OmniAICreator/Qiita-1.07M huggingface dataset:
[Python]【補足】04章-08 いろいろなデータ構造（セットの作成と操作）

#[Python]【補足】04章-08 セットの作成と操作
この節ではセットについて取り扱います。セットもデータ構造の分野の1つになります。ただし、この節については補足事項として説明しますので、セットについては割愛しても構いません。

ただし、基本情報技術者試験を受験しようと考えている人は、集合理論や集合演算で出題される内容とっています。午後問題でPythonを選択する人も見ておいたほうが良いでしょう。

なお、**「セット」**は書籍によっては**「集合」**ということもありますので把握しておいてください。

##セットの作成
では早速セットを作成してみましょう。**Python console**に以下のコードを入力してください。

```.py
>>> S = {1, 2, 3, 4}
>>> S
{1, 2, 3, 4}
```
セットは**{  }**で囲んで表現します。なお、ディクショナリでは**{  }**内に**「:」**（コロン）で区切ってキーと値を記載していましたが、コロンがなくなるとセットとなります。

##セットの要素の追加

ではセットに要素を追加します。セットの場合は、appendではなく、**add**メソッドを使用します。
**Python console**に以下のコードを入力してください。一度変数**S**の内容を表示してから実行します。

```.py
>>> S
{1, 2, 3, 4}
>>> S.add(5)
>>> S
{1, 2, 3, 4, 5}
```
セットの最後に要素が追加されたことを確認できたかと思います。

では、この状態で、もう一度**add(5)**を実行して出力してみましょう。

```.py
>>> S.add(5)
>>> S
{1, 2, 3, 4, 5}
```
結果を見てわかるように、セットを利用すると重複のない要素を作成することができます。

##セットの要素の削除

セットの要素から削除するには、**removeメソッド**を使用します。**Python console**に以下のコードを入力してください。一度変数**S**の内容を表示してから実行します。

```.py
>>> S
{1, 2, 3, 4, 5}
>>> S.remove(2)
>>> S
{1, 3, 4, 5}
```
直接セットの要素を指定して削除できます。

なお、セットの全要素を削除するには**clearメソッド**を利用します。

```.py
>>> S.clear()
>>> S
set()
```
Sの中身を確認すると、**set()**と出力されます。この**set()**は空のセットを意味します。

##セットの要素の探索
セットに指定した要素が含まれているかも確認ができます。リストやディクショナリと一緒で**in演算子**を使います。

```.py
>>> S = {1, 2, 3, 4}
>>> S
{1, 2, 3, 4}
>>> 2 in S
True
>>> 10 in S
False
```

##最後に
今回はセットについて触れました。セットは重複せずに要素が保管されることがわかればよいでしょう。
次回は集合演算について触れ、それを実際にPython上で実装していきます。

###[【目次リンク】へ戻る](https://qiita.com/ko0821/items/379e8bd9e6ea01089419)
Windows 環境で Wolfram Engine を Jupyter Notebook で使うときにハマったこと

# 概要
詳しくはわかりませんが，以下の２つを導入することによって Jupyter Notebook で Mathematica の機能が無料で使えるようになるそうです．

* Free Wolfram Engine for Developers
* Wolfram Language kernel for Jupyter notebooks

導入の手順に関しては詳しく説明されているページがあるため省略します．
この記事では，私が実際に環境を作るときに発生したエラーの対処について取り上げます．

# 環境
* Windows 10 Pro
* Anaconda3-2020.02
* WolframEngine_12.1.0
* WolframLanguageForJupyter-master (Commits on Feb 7, 2020)

# 発生したエラー
`Wolfram Language kernel for Jupyter notebooks` をクローンして `$ configure-jupyter.wls add` を実行したときに，うろ覚えですが次の二つのエラーが発生しました．

* configure-jupyter.wls: Jupyter installation on Environment["PATH"] not found
* jupyter kernelspec list なんとやら

# 対処
Anaconda を一度アンインストールして，もう一度インストールする時に `Add Anaconda3 to my PATH environment variable` にチェックを入れる．
※結局エラーの原因はわかっていません．
![anaconda.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324504/0ed6228a-4628-41b1-18d5-0d0d6deb594f.png)

# 手順
## 1. Wolfram Engine のアンインストール
影響があるかわかりませんが一応アンインストールしておきます．
普通にコントロールパネルからアンインストールします．

## 2. Anaconda のアンインストール
1. `$ conda install anaconda-clean` で Anaconda-Clean パッケージをインストール
2. '$ anaconda-clean' で anaconda-clean を実行
3. コントロールパネルから Anaconda をアンインストール

参考
[[Python]Anacondaをアンインストールしてから「All Users」設定で再インストールしてみた](https://note.com/hotta3216/n/n9a12faf675f9)

## 3. Anaconda の再インストール
`Add Anaconda3 to my PATH environment variable` にチェックを入れ忘れないようにする．

## 4. 以降は通常の手順
1. Wolfram Engine をインストール
2. 'Wolfram Language kernel for Jupyter notebooks' をクローンして `$ configure-jupyter.wls add` を実行

# 参考
* [wolfram engineをjupyterで使う方法（windows版）](https://note.com/yusuke_higuchi/n/n3d4c0a3700a7)
* [Wolfram Engine を導入して Jupyter-notebook で動かすまで](https://qiita.com/Mizuto_Kadowaki/items/0f8ac51c7c00303f456e)
MS AccessファイルのデータをPowerShellに取り込む


OSが64bitの場合は手当が必要だったので出力は必ずCSVになるようにした。

```powershell:export-accdb.ps1
<#
64bit OS の場合はインストールされている office に合わせたアーキテクチャのpowershellで実行すること

x32 office
C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe

x64 office
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
#> 
Param(
    [Parameter(Mandatory=$True)]
    [string]$Path,

    [Parameter(Mandatory=$True)]
    [string]$Table
)
$con = New-Object -ComObject ADODB.Connection

if(-not (Test-Path $Path)) { throw 1 }

if (([System.IO.Path]::GetExtension($path)) -eq ".mdb") {
    $connectionString = "Provider = Microsoft.Jet.OLEDB.4.0; Data Source = $path"
} elseif(([System.IO.Path]::GetExtension($path)) -eq ".accdb") {
    $connectionString = "Provider = Microsoft.ACE.OLEDB.12.0; Data Source = $path"
} else {
    throw 1
}

$con.Open($connectionString)

$sql ="SELECT * FROM $Table;" 
$rs = New-Object -ComObject ADODB.Recordset 

$adOpenStatic = 3
$adLockOptimistic = 3
$rs.Open($sql, $con, $adOpenStatic, $adLockOptimistic)
$rs.MoveFirst()
& {
    while($rs.EOF -eq $False)  {
        $o = new-object psobject
        $rs.Fields | ForEach-Object {
            $o | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.value
        }
        Write-Output $o
        $rs.MoveNext()
    }
} | ConvertTo-Csv -NTI

$rs.Close()
$con.Close()
$rs = $null
$con = $null
```


```console:使い方
$ps = "C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe"
$Path = ".\hoge.accdb"
$csv = & $ps -ExecutionPolicy bypass -File .\export-accdb.ps1 -Path $Path -Table table1
```
繰り返し

# 繰り返し
Rustで繰り返しを実装する手段は以下の３つがあります。

|キーワード|説明|
|:-:|:-:|
|loop|無限ループ|
|while|条件がtrueならループ|
|for|イテレータを使ったループ|

#loop
`loop`は無限ループです。
以下のコードは無限に「無限ループです。」と表示し続けます。
実行したら`Ctrl + C`で止めましょう。

~~~rust
fn main() {
    loop{
        println!("無限ループです。");
    }
}
~~~

#while
`while`は指定した条件式によって繰り返しを制御します。以下のように書きます。
`while` `繰り返し条件` `{` `繰り返す処理` `}`
繰り返し条件は`bool`型を返す式です。条件の真理値によって以下のように動作します。

- `true`の場合　→　カッコ内の処理を実行する。その後、再び条件式を評価する（繰り返し）。
- `false`の場合　→　処理を実行せず、次の処理に移る。

条件が`true`の間ループし続けます。

~~~rust
fn main() {
    let mut count = 1;

    //条件式(count < 10)を評価し、trueならカッコの中身を実行する。
    while count < 10 {
        println!("count = {}",count);
        count += 1;
        //ここまで実行したら再び条件式を判定する。
    }
}
~~~

実行結果

~~~
count = 1
count = 2
count = 3
count = 4
count = 5
count = 6
count = 7
count = 8
count = 9
~~~

#for
`for`はイテレータを用いる繰り返しです。イテレータとはチェーンのように連なるデータで、データを順番に生成することが出来ます。`for`は対象となるデータをイテレータに変換し、イテレータからデータを一つずつ取り出して変数に束縛して何らかの処理をします。
`for`ループの書き方は以下の通りです。
`for` `変数` `in` `イテレータに変換可能なデータ` `{` `繰り返す処理` `}`
以下のように使うことが出来ます。

~~~rust
fn main() {
    //決まった回数の繰り返し。
    //1..10は1から9までの数値を順番に生成する。
    for count in 1..10 {
        println!("count = {}",count);
    }

    //Vecの各要素に対して１回ずつ処理を行う。
    //Vecはイテレータに変換可能。
    let name_list = vec!["太郎","花子","一郎","清"];
    for name in name_list {
        println!("私の名前は{}です。",name);
    }
}
~~~
上記の例では2つの`for`ループがあります。
一つは決まった回数の繰り返しです。繰り返しの回数を`1..10`と指定しています。これで1から9までの数値を順番に生成することが出来、9回の繰り返しとなります。
もう一つはベクタの各要素に対して処理を繰り返し行うために`for`を使用しています。`name_list`は4つの要素を持つベクタであり、これをイテレータにすると要素を4回生成するイテレータになります。繰り返しの各過程では、nameにname_listの各要素が順番に束縛されます。

実行結果

~~~
count = 1
count = 2
count = 3
count = 4
count = 5
count = 6
count = 7
count = 8
count = 9
私の名前は太郎です。
私の名前は花子です。
私の名前は一郎です。
私の名前は清です。
~~~


[目次](https://qiita.com/tonesuke/items/52e469f18e747c794376)
[Rでデータ分析]効いているラインはどこなの？線形回帰でやってみる。

次の仮想データで考えてみる。

```R:バスケのデータ
per <- c(43,75,60,44,61,77,65,51,44,71)
time <- c(50,70,70,40,50,60,60,40,40,60)
```
`per`がシュート成功率 [%]、`time`が自主練の平均時間 [分]を表す。
このとき、自主練の時間が何分くらいから練習の効果に差が出てくる？って興味。
セグメントを分けて**2標本t検定**繰り返してみてってのもこの問題なら出来るが、他の説明変数も含めた上で何分くらいが境界になるかを明らかにしたい（興味の対象が狭すぎてすみませんｗ）。
なので回帰分析します(t検定も回帰の一種だが)。非線形でも同じようにできるので線形でやってみる。

データを見ると自主練の時間は40分から10分刻みで70分までの4段階（段階多いと計算に時間かかるね）。
出来るだけ汎用性高いように作りたいかなと。
今回は出来たモデルの良し悪しを「決定係数（Coefficient of determination）」を使ってみる。統計学では記号として「$R^2$」を使うことが多いのでRの実行結果では`Multiple R-Squared`と表示される。決定係数は 0から1の間の値を取り、1に近いほどモデルの当てはまりがいいとされる。1に近い値が出るモデルが作れたらそれが一番いいってことだね！(言い過ぎ)
ただし、決定係数は説明変数の数を増やすと値が大きくなりやすいって弱点もあってそれを補うために提案されたのが「自由度調整済み決定係数（Adjusted R-squared）」である（誰が提案したかは知らない。誰なんだろ）。
ちなみになんで決定係数は説明変数の個数を増やすと値が大きくなりやすいのかは問題として面白いので考えてみてもいいね。ちゃんと式で説明できるから。（多重共線性の問題とかも式で説明できる。）
とりあえず今回試してみるのは自由度調整済み決定係数で一番当てはまりのよさそうなモデルを作れる閾値を決めてみようと思う。総当たりやな。。

```R:時間を区切ってモデリングしたときの比較コード
rep <- c(50,60,70) #for文で回す範囲をここで作る。40を外してるのはソース見て。
Rsq <- numeric() #最終的にこの値が高いモデルを採用するために箱を用意
time2 <- time #timeの中身を変えたくないから用意したが、いらないかも。
for(i in rep){
  time2[time < i] <- 1
  time2[time >= i] <- 0
  result <- lm(per ~ time2)
  Rsq[rep == i] <- summary(result)$adj.r.squared
}
which.max(Rsq) #考えられるすべてのモデルで一番いいものを出力
```
こんな感じで出来る。一応汎用性は高いよね？（高くねぇよ）`for`文の間の部分は`if`文でも書けるけど`TRUE` or `FALSE`使ってみた。すっきり書けるから。
出力結果を確認してみると、

```R:
> Rsq
[1] 0.386977281 0.683073816 0.004291811
> which.max(Rsq)
[1] 2
```
となるので2番目のパターン、つまり`rep`の2番目だから**60分**より多いか少ないかで差が出るってことやね。
こんなに差出んのかよって結果になったね。
（細かい部分気にすると進まないのでとりあえずこれで）

もちろん他の評価指標でモデルの良し悪しを判断してやることも出来る。
回帰分析の結果`summary()`のあとに`$`つけて必要な情報を引き出すのは`R`ではよく使うことなので知っておくと便利よ。何が出力できるのかは、実行する関数名をそのまま実行すると中のソースが見れるのでそれで大体わかる。

あと、実務で一番大事なのはこうやって解析して基準がわかったとして、その基準がなんなの？ってのはちゃんと説明できないといけないってこと。
今回の結果の60分って何？まぁ自主練の時間だから最低でも60分はやったほうがいいよって言えるけど。長ければ長いほどいいのか？とかはわかんないしね。データ解析は深いよ。
numpy Loadtxtについて

numpyのLoadtxtを利用する際に、海外OS(Spanish)のせいか文字変換のエラーが発生

ValueError: could not convert string to float: '235.00 ;591.00 '

元のコード　train = np.loadtxt("XXXXXXXXXX", delimiter=',', skiprows=1)

色々と調べたところ、file Pathの前にrの追加とdelimiterを;に変更することで解決

修正後のコード　train = np.loadtxt(r'XXXXXXXXX', delimiter=';', skiprows=1)

海外OSでは、地味にcsvファイルを扱う際に色々と気を付けないといけないことを実感しました
Kitematic 初回アプリ起動で「開発元が検証できないため開ません」と出て開けない

# 目的

- Kitematicをダウンロード直後の初回起動時にポップアップが出てアプリの起動ができなかったため解決策をまとめる

# 実施環境

- ハードウェア環境

| 項目 | 情報 |
| --- | --- |
| OS | macOS Catalina(10.15.3) |
| ハードウェア | MacBook Pro (16-inch ,2019) |
| プロセッサ | 2.6 GHz 6コアIntel Core i7 |
| メモリ | 16 GB 2667 MHz DDR4 |
| グラフィックス | AMD Radeon Pro 5300M 4 GB Intel UHD Graphics 630 1536 MB |

- ソフトウェア環境

| 項目 | 情報 | 備考 |
| --- | --- | --- |
| Docker バージョン | 19.03.8 | こちらの方法で導入→[Docker Desktop for Mac をインストールする](https://qiita.com/miriwo/items/b4d41c45a12b1ae7f91e) |

# 発生した問題

- ダウンロード直後にzipを解凍し、アプリを起動しようとしたところ「“Kitematic”は、開発元を検証できないため開けません。」と言う警告ウインドウが開き、起動することができない。

    <img width="532" alt="スクリーンショット 2020-05-29 11.05.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/7a35565d-92ee-c8e1-6e24-a76a3b3ed606.png">

# 解決策

1. 解凍し、アプリをクリックして起動するタイミングでKitematicの上にカーソルを持ってゆき、Controlキーを押しながらアプリケーションアイコンをクリックする。
1. 「開く」を選択してクリックする。

    <img width="820" alt="スクリーンショット 2020-05-29 11.08.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/c97d2083-79ef-ee4e-6906-8c95158efa23.png">

1. 下記のウインドウが出たら「開く」をクリックする。

    ![スクリーンショット 2020-05-29 11.09.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/07e82dd1-3927-2033-d214-ba470adf6326.png)

1. 無事にアプリを起動することができた。

    <img width="1192" alt="スクリーンショット 2020-05-29 11.09.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/60936852-41b5-2330-c950-38c9656acc8c.png">
Pythonで簡単なブラックジャックを作ってみた

#はじめに

この記事はプログラミング歴1ヶ月半の初心者が書いているコードなので温かい目でご覧ください。

環境
・Windows10(Macでも全然できる)

使用言語
・Python3

使用エディタ
・VScode

#サンプルコード

```python:blackjack.py

import random


deck = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] * 4


def deal():
    hand = []
    for i in range(2):
        random.shuffle(deck)
        card = deck.pop()
        if card == 11:
            card = "J"
        if card == 12:
            card = "Q"
        if card == 13:
            card = "K"
        if card == 1:
            card = "A"
        hand.append(card)
    return hand


def hit(hand):
    random.shuffle(deck)
    card = deck.pop()
    if card == 11:
        card = "J"
    if card == 12:
        card = "Q"
    if card == 13:
        card = "K"
    if card == 1:
        card = "A"
    hand.append(card)
    return hand


def total(hand):
    score = 0
    for card in hand:
        if card == "J" or card == "Q" or card == "K":
            score = score + 10
        elif card == "A":
            if score >= 11:
                score = score + 1
            else:
                score += 11
        else:
            score += card
    return score


def play_again():
    again = input("もう１度プレイしますか？ (Y/N): ")
    if again == "y" or again == "Y":
        # game()
        return
    else:
        print("お疲れ様でした！")
        exit()


def result(dealer_hand, player_hand):
    if total(player_hand) > total(dealer_hand):
        print(
            f"\nディーラーの合計は {total(dealer_hand)} あなたの合計は {total(player_hand)} です。\033[32mYOU WIN!\033[0m")
    elif total(dealer_hand) > total(player_hand):
        print(
            f"\nディーラーの合計は {total(dealer_hand)} あなたの合計は {total(player_hand)} です。\033[91mYOU LOSE...\033[0m")


def game():
    dealer_hand = deal()
    player_hand = deal()
    print(f"ディーラーのカードは {dealer_hand[0]} です。")
    print(f"プレイヤーのカードは {player_hand} 合計が {total(player_hand)} です。")

    choice = 0

    while choice != quit:
        choice = input("ヒットしますか？ スタンドしますか？ (HIT/STAND): ").lower()
        if choice == "hit":
            hit(player_hand)
            print(
                f"\nあなたに {player_hand[-1]} が配られ、カードは {player_hand} 合計は {total(player_hand)} です。")
            if total(player_hand) > 21:
                print("あなたは 21 を超えてしまいました。\033[91mYOU LOSE...\033[0m")
                choice = quit

        elif choice == "stand":
            print(
                f"\nディーラーの２枚めのカードは {dealer_hand[1]} 合計は {total(dealer_hand)} です。")
            while total(dealer_hand) < 17:
                hit(dealer_hand)
                print(
                    f"ディーラーに {dealer_hand[-1]} が配られ、カードは {dealer_hand} 合計は {total(dealer_hand)} です。")
                if total(dealer_hand) > 21:
                    print("ディーラーは 21 を超えてしまいました。\033[32mYOU WIN!\033[0m")
                    choice = quit

            if total(dealer_hand) <= 21:
                result(dealer_hand, player_hand)
                choice = quit


game()
```

ターミナルでぽちっと押せばゲームがスタートします。
Anaconda環境でGraphvizを使う

#概要
`Graphviz`をAnaconda環境下で使用する分には、condaプロンプトでインストールするだけで良さそうだったので、手順をまとめました。

※その他の環境で使用したい場合は、以下を参照してください。
[【Windows10】Graphvizのインストール](https://qiita.com/BARANCE_TW/items/c3f7816d38cc9e746bbd)

#パッケージのインストール

```
conda install python-graphviz
```
#環境変数をセットする
binまでのパスを環境変数にセットします。

```
...\Anaconda3\pkgs\graphviz-2.38-hfd603c8_2\Library\bin
```
※環境変数の追加の仕方がわからない場合は、[こちら](https://qiita.com/BARANCE_TW/items/c3f7816d38cc9e746bbd)を参照してください。

注：[OK]を押して環境変数の画面をちゃんと閉じること。パスが通らず1時間くらい悩んだ:confounded:

#確認

####DOTコマンドが使えるか確認する

コマンドプロンプトで、以下を実行します。

```
dot -V

// 以下が出力されればOK
dot - graphviz version 2.38.0 (20140413.2041)
```
####DOT言語を使って確認する
メモ帳などでdotファイルを作成します。

```sample.dot
digraph g{
1 [label="x0", color=orange, style=filled]
2 [label="x1", color=orange, style=filled]
3 [label="Add", color=lightblue, style=filled, shape=box]
4 [label="y", color=orange, style=filled]
1 -> 3 [label="2"]
2 -> 3 [label="3"]
3 -> 4 [label="5"]
}
```
コマンドプロンプトで以下を実行します。

```
dot sample.dot -T png -o sample.png
```
sample.dot：ソースとなるdotファイル
-T png：レンダリングする拡張子の指定（pdfやsvgなどにもできる）
-o sample.png：出力ファイル
![aaa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358498/511733bf-0d9b-5b13-0918-237ecef340fb.png)
`sample.png`

####Pythonスクリプトで確認する

```test\test.py
from graphviz import Digraph

G = Digraph(format="png")
G.attr("node", shape="square", style="filled")
G.edge("start","state1",label="0.8")
G.edge("start","state2",label="0.2")
G.edge("state1","state1",label="0.5")
G.edge("state2","state2", label="0.8")
G.edge("state1","state2",label="0.5")
G.edge("state2","end",label="0.2")
G.edge("end","count",label="1.0")
G.edge("count","start",label="1.0")
G.node("start", shape="circle", color="pink")
G.render("graphs") #png/直下
```

![graphs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358498/a84efaac-b7c0-462e-4d19-4b4bac9fcbca.png)
`graphs.png`

正しく環境変数が設定されていないと、renderをするときに以下のエラーがでます。

```.py
graphviz.backend.ExecutableNotFound: failed to execute ['dot.bat', '-Tpng', '-O', 'graphs'], make sure the Graphviz executables are on your systems' PATH
```
【PostgreSQL】psqlのCOPYコマンドによるCSVインポートで重複エラーを回避する

# はじめに
サーバーリプレース作業にて、データベースを Oracle 11g から PostgreSQL 9.6 に移行作業をしています。
[OracleからPostgreSQL移行について](https://qiita.com/yaju/items/7cf5ab6987ecd1d83b13)

Oracle 用に作成していたバッチにSQL*Loader コマンドを使用してCSVファイルをテーブルにインポートする処理があり、psqlの¥COPYコマンドに置き換えて運用していました。

# 現象
先日、対象テーブルに該当データが存在していないという報告がありました。

# 原因
ログを確認したら一意制約違反エラーによりロールバックされていました。
どうも運用的に既に登録済みの一部のデータがCSVファイルに入ることがあるようで、運用開始から１週間くらい問題が発生しなかったのはたまたまだったようです。
では、Oracle の時に問題にならなかったのはどういうことなのか調べると、Oracle 用のSQL*Loader コマンドには、ERRORS(エラーの許容最大数)というオプションがあり、無制限(-1)に指定されていました。これにより一意制約違反エラーがあった場合でも許容されていたのです。

# 対応
psqlの¥COPYコマンドには、残念ながらERRORS(エラーの許容最大数)というオプションがありません。
今回に関しては、一意制約違反エラーのみ無視して登録してくれればいいわけです。

PostgreSQL 向けの高速データロードユーティリティ「[pg_bulkload](http://ossc-db.github.io/pg_bulkload/pg_bulkload-ja.html)」には、制御オプションにDUPLICATE_ERRORS(一意制約違反の許容件数)があり、無制限(-1)に指定することが出来ます。これだと思ったんですが、Windows版は長いこと更新がストップしているということで採用するのをやめました。

PostgreSQL9.5以降から、INSERTにオプションのON CONFLICT句を追加され、主キー制約などに反するINSERTを無視する(DO NOTHING)ことが出来るようになりました。
[第21回　PostgreSQL 9.5について（前編） （2）INSERTでUPSERT機能の追加](https://oss-db.jp/dojo/dojo_21)

よって、下記の手順で登録すれば良さそうです。

1. 一時テーブルを用意する。
2. ¥COPYコマンドで一時テーブルにインポートする。
3. 一時テーブルから対象テーブルにINSERTのON CONFLICT DO NOTHINGを使用して登録する。

一時テーブルですが当初は対象テーブルの名前を変更した実テーブルを作成しましたが、今後同じようなことを考えると汎用性を持たせたい。テーブル定義の複製が出来れば、どのテーブルでも可能になる。

テーブルの複製は下記の方法で出来ます。likeオプションは状況に応じたものを指定(空白区切りで複数指定可能)すればいいです。

```
CREATE TABLE table_name (LIKE source_table [like_option...]);
```

|likeオプション|内容|
|:--|:--|
|INCLUDING DEFAULTS|DEFAULT 制約をコピーします。|
|INCLUDING IDENTITY|カラムへの IDENTITY の指定がコピーされます。カラムに割り当てられるシーケンスはコピー元とコピー先で異なります。|
|INCLUDING CONSTRAINTS|CHECK 制約がコピーされます。|
|INCLUDING INDEXES|PRIMARY KEY 、 UNIQUE 、 EXCLUDE の各制約がコピーされます。|
|INCLUDING COMMENTS|カラム、制約、インデックスに関するコメントがコピーされます。|
|INCLUDING STATISTICS|拡張統計情報がコピーされます。|
|INCLUDING STORAG|カラム定義に関する STORAGE 設定がコピーされます。|
|INCLUDING ALL|全てのオプションを指定したのと同じです。|

もう一工夫として、一時テーブルをTEMPORARY TABLEとして作成することで接続したセッションの間にしか生存できないテーブルとなります。
CREATEの後にTEMPORARY又はTEMPを付けてテーブルを作成し、コミットしたら自動的に削除(DROP)するようにします。

```
CREATE TEMP TABLE table_name (LIKE source_table [like_option...]) ON COMMIT DROP;
```

最終的には下記のようになりました。

```sql:import.sql
BEGIN;
CREATE TEMP TABLE test_temp (LIKE test INCLUDING DEFAULTS) ON COMMIT DROP;
¥COPY test_temp FROM 'C:\Work\test.csv' csv;
INSERT INTO test SELECT * FROM test_temp ON CONFLICT DO NOTHING;
COMMIT;
```

# 最後に
これで無事に一意制約違反エラーでロールバックされずに登録出来るようになりました。

ちなみに登録するデータが重複していたら、更新に切り替えることも出来ます。
ON CONFLICT DO NOTHING から ON CONFLICT DO UPDATE SET にして列名と更新値を指定します。

# 参照
* [How Postgresql COPY TO STDIN With CSV do on conflic do update?](https://stackoverflow.com/questions/48019381/how-postgresql-copy-to-stdin-with-csv-do-on-conflic-do-update)
* [テーブル構造をコピーして新しいテーブルを作成する(CREATE TABLE ... LIKE)](https://www.dbonline.jp/postgresql/table/index14.html)
* [TEMPORARY TABLE（一時テーブル）を探る](https://qiita.com/noborus/items/16ea90339a637d0f40f7)
* [一時テーブルを使用する場合の注意事項](https://software.fujitsu.com/jp/manual/manualfiles/m150013/j2ul1738/10z200/j1738-a-02-00.html)
* [UPSERT（ON CONFLICT句）とGROUPING SETS句/CUBE句/ROLLUP句の実装](https://thinkit.co.jp/article/9586)
Github Actionsのactions/setup-pythonをv1からv2に上げたらエラーになった。

# 前置き
個人的なメモです。

Github ActionsでDjangoのテストをpytestで実行しています。
先日下記のように`actions/setup-python@v1`でエラーが発生しました。

``` main.yml
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v1
        with:
          python-version: 3.8.2
      - run: python -m pip install --upgrade pip
      - run: pip install pipenv
      - run: pipenv install -d
      - run: pipenv run pytest -n auto --cov
```

エラーの内容はこちらです。

``` console.log
##[error]Version 3.8.2 with arch x64 not found
Available versions:

2.7.18 (x64)
3.5.9 (x64)
3.6.10 (x64)
3.7.7 (x64)
3.8.3 (x64)
```

# 本題
`actions/setup-python@v2`では`3.8.2`が使用できそうだったので、
とりあえずバージョンを変更して実行してみました。

その結果、pytestのテストでエラーが発生しました。
エラーの内容はこんな感じです。

``` console.log
==================================== ERRORS ====================================
_ ERROR collecting 6e684b56-631b-4b6c-932f-7229ff10dace/lib/python3.8/ctypes/test/test_anon.py _
import file mismatch:
imported module 'ctypes.test.test_anon' has this __file__ attribute:
  /opt/hostedtoolcache/Python/3.8.2/x64/lib/python3.8/ctypes/test/test_anon.py
which is not the same as the test file we want to collect:
  /home/runner/work/xxxx/xxxx/6e684b56-631b-4b6c-932f-7229ff10dace/lib/python3.8/ctypes/test/test_anon.py
HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules
(省略)
```

# 原因
調べた所、ワークディレクトリにライブラリがダウンロードされており、
そのディレクトリがテスト対象に含めているのが原因でした。

https://github.com/actions/setup-python/blob/4dda7a3aa16ec239b7b1302e7e95a4e886a81796/src/install-python.ts

# 解決方法
とりあえず、pytestの設定(pytest.ini)でuuidっぽいディレクトリはテスト対象外にして解決しました。

``` pytest.ini
[pytest]
norecursedirs = *-*-*-*-*
```

もっと良い方法もありそうです。。
[Java] Date 関連用語メモ

久々に　サーバー側プロジェクトを担当することになりました。
しかも環境がdb & windows & Java　など （Ｔ、Ｔ）
ですので、用語など勉強絡みでメモします。

#用語
##１。 ISO-8601暦体系
日付と時刻の表記に関するISOの国際規格

基本形式: YYYYMMDDThhmmss+0900
 例）20200531T115959+0900

##２。 GMT（グリニッジ平均時：Greenwich mean solar time）
英国のグリニッジ（経度0度）の地方平均太陽時
（平均太陽が南中する時を正午とする）
<img width="100" height="200" alt="Greenwich.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101832/2c8efd2e-44ae-bc0b-f8ab-143ec9475560.png">| <img width="304" alt="経度0度0分0秒の基準子午線.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101832/110a8752-c3c6-5eb2-0bc8-c8fe799c8b4d.png">

グリニッジ天文台旧本館

##３。 UTC（協定世界時：Universal time coordinated）
セシウム原子を利用したセシウム原子時計を基本

 JST(日本標準時,Japan Standard Time) 
 UTC + 9時間（東経135度分の時差）

 UNIX時間（POSIX ）
UTCでのUNIXエポックから形式的な経過秒数
※UNIXエポック(epoch)：　1970年1月1日午前0時0分0秒

##4。グレゴリオ暦（新暦）
1582年10月15日（グレゴリオ暦）から行用されている暦法である。
(第226代ローマ教皇グレゴリウス13世がその前までの旧暦であるユリウス暦の改良を命じたである)

##参照
[・Wiki-ISO-8601]
(https://ja.wikipedia.org/wiki/ISO_8601)
[・Wiki-GMT(グリニッジ平均時)](https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%AA%E3%83%8B%E3%83%83%E3%82%B8%E6%A8%99%E6%BA%96%E6%99%82)
[・Wiki-UTC（協定世界時](https://ja.wikipedia.org/wiki/%E5%8D%94%E5%AE%9A%E4%B8%96%E7%95%8C%E6%99%82)
[・Wiki-UNIX時間](https://ja.wikipedia.org/wiki/UNIX%E6%99%82%E9%96%93)

#JAVA
 (バージョン:　1.8)

##１。OffsetDateTime
オフセットを使った日付/時間の不変の表現です。
UTC/グリニッジからのオフセットの他に、すべての日付と時間のフィールドをナノ秒の精度まで格納します。
例１）「2nd October 2007 at 13:45.30.123456789 +02:00」
例２）インスタンス生成
of(LocalDateTime date,ZoneOffset zone)
of(LocalDate date, LocalTime time, ZoneOffset zone)

##２。LocalDateTime
日付/時間(年-月-日-時-分-秒として表示されることが多い)を表す不変の日付/時間オブジェクトです。
他の日付と時間フィールド(「年の日」、曜日、「年の週番号」など)にもアクセスできます。時間は、ナノ秒の精度まで表されます。
例１）「2007年10月2日の13:45.30.123456789」
例２）インスタンス生成
of(LocalDate date, LocalTime time)

##３。Timestamp
java.util.Dateの薄いラッパーであり、JDBC APIはこれをSQL TIMESTAMP値として識別できます。

例１）インスタンス生成
valueOf(LocalDateTime date)


#参照
[https://docs.oracle.com/javase/jp/8/docs/api/java/time/OffsetDateTime.html](https://docs.oracle.com/javase/jp/8/docs/api/java/time/OffsetDateTime.html)
[https://docs.oracle.com/javase/jp/8/docs/api/java/time/LocalDateTime.html](
https://docs.oracle.com/javase/jp/8/docs/api/java/time/LocalDateTime.html)
[https://docs.oracle.com/javase/jp/8/docs/api/java/sql/Timestamp.html](https://docs.oracle.com/javase/jp/8/docs/api/java/sql/Timestamp.html)
#おまけ

[【Java】日付時刻API]
(https://www.ne.jp/asahi/hishidama/home/tech/java/datetime.html)
[【Swift】Dateの王道 (日付)](
https://qiita.com/rinov/items/bff12e9ea1251e895306)
[【kotlin】 Date日時計算をする方法](
http://android.techblog.jp/archives/8116670.html)
Ruby で嵌る AtCoder ABC 169 C 浮動小数点

# はじめに
*[「AtCoderは、世界最高峰の競技プログラミングサイトです。
リアルタイムのオンラインコンテストで競い合うことや、
3,000以上の過去問にいつでもチャレンジすることができます。」](https://atcoder.jp/)*
を利用して、プログラミングの勉強をしています。
AtCoder さん、ありがとうございます。
# 今回のお題
*[AtCoder Beginner Contets C - Multiplication 3](https://atcoder.jp/contests/abc169/tasks/abc169_c)*
<font color="brown">Difficulty: 536</font>

今回のテーマ、浮動小数点による誤差

*[浮動小数点数 -WikiPedia](https://ja.wikipedia.org/wiki/%E6%B5%AE%E5%8B%95%E5%B0%8F%E6%95%B0%E7%82%B9%E6%95%B0)*
# Ruby
## WA1
```wa1.rb
a, b = gets.split.map(&:to_f)
puts (a * b).floor
```
切り捨てなので`floor`を使用するも`WA`。
## WA2
```wa2.rb
a, b = gets.split.map(&:to_f)
puts ((a.to_i * (b * 100)) / 100).floor
```
`100倍`してから`100`で割る作戦、失敗。
## WA3
```wa3.rb
a, b = gets.split.map(&:to_f)
puts ((a.to_i * (b * 100)) / 100).to_i
```
神頼みで`floor`を`to_i`にしてみる。
## WA4
```wa4.rb
a, b = gets.chomp.split
puts ((a.to_i * (b.to_f * 100).to_i) / 100)
```
標準入力からの受け取りを文字列にする作戦。
## AC
```ac.rb
a, b = gets.chomp.split
puts ((a.to_i * (b.gsub!('.', '').to_i).to_i) / 100)
```
`to_f`を`100倍`するのを諦め、小数点`.`の文字を削除する作戦。
<font color="green">$\huge{成功}$</font>

何が良くて、何が拙かったよく分かっていないのですが、とにかく疲れました。
# まとめ
+ ABC 169 C を解いた
+ Ruby に詳しくなっていない

**追記**
いい記事が投稿されています
*[浮動小数点数オタクが AtCoder Beginner Contest 169 のC問題をガチで解説してみる](https://qiita.com/mod_poppo/items/910b5fb9303baf864bf7)*
【Rails5.2】credentials.yml.encの編集方法[AWSのaccess_keyについて]

#はじめに
この記事は学習の備忘録として作成しました。
いろいろと抜けている部分がございますが、ご了承ください。

##credentials.yml.enにaccess_keyなどを編集するには

ターミナルで下記のように打つと、入力画面へ飛ぶことができます。
そこで初めにiを打ち、入力します。

```ruby:ターミナル
$ EDITOR=vim bin/rails credentials:edit
```
```ruby:credentials.yml.enc
aws:
   access_key_id: 123 #ここにご自身のアクセスキーを入力
   secret_access_key: 123　#ここにご自身のシークレットアクセスキーを入力

# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.
secret_key_base: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
```
※デフォルトだと、access_key、secret_access_keyの部分がコメントアウトされているので、外しましょう。

### ※carrierwaveを使ってS3に画像をアップロードする場合
この場合は、他にもgemを入れなくてはいけないのですが、今回はaccess_key、secret_access_keyを読み込むためにはどのような記述が必要かだけ上げておきます。

```ruby:carrierwave.rb
require 'carrierwave/storage/abstract'
require 'carrierwave/storage/file'
require 'carrierwave/storage/fog'

CarrierWave.configure do |config|
    config.storage = :fog
    config.fog_provider = 'fog/aws'
    config.fog_directory  = 'freemarket-sample-67d'
    config.fog_credentials = {
      provider: 'AWS',
      aws_access_key_id: Rails.application.credentials.dig(:aws, :access_key_id),
      aws_secret_access_key: Rails.application.credentials.dig(:aws, :secret_access_key), #ここの部分が重要になります。[]、（）で閉じるかは上手くいく方で試してみて下さい。
      region: 'ap-northeast-1'
    }

  config.fog_directory  = 'freemarket-sample-67d'
  config.asset_host = 'https://s3-ap-northeast-1.amazonaws.com/freemarket-sample-67d'
end
```

こんな感じでkeyを読み込むことができます。
これでは少し説明が足りないと思うので、わからない部分がありましたら、コメントください！！
OpenCVでzero-paddingを1行でする方法

しがない地方院生のsotaです。
初心者なので間違いが多々あると思いますが、その時はコメントで教えていただけると幸いです。

研究やバイトでたびたびパディングを実装するのですが、毎回pillowやらopencvやらでどうするか調べて、一時間近く実装に使っていたのですが、タイトルにもあるようにopencvで1行で実装できることが分かったので、備忘録として残します。

## cv2.copyMakeBorder()

具体的には`cv2.copyMakeBorder()`を使います。
使い方は

```python
output = cv2.copyMakeBorder(src, top, bottom, left, right, borderType, value)
```
です。
- `src`は入力画像
- `top, bottom, left, right`はそれぞれ画像の上下左右に何ピクセル空白を加えるか
- `borderType` は追加する境界の種類を指定するためのフラグで、いわゆるpaddingをしたいなら、`cv2.BORDER_CONSTANT`を選択してください。
- 他にも`cv2.BORDER_REFLECT, cv2.BORDER_DEFAULT, cv2.BORDER_REPLICATE, cv2.BORDER_WRAP`などがありますが、少しパディングとは異なってくるので、これらは公式ドキュメントを参考にしてください。
http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_core/py_basic_ops/py_basic_ops.html
- `value`はpaddingした箇所の色を指定します。`(0,0,0)`なら黒、`(255,255,255)`なら白といった具合です。

## 実装例

```python

import cv2

img = cv2.imread('./fig.png')

img_pad = cv2.copyMakeBorder(img, 50, 50, 50, 50, cv2.BORDER_CONSTANT, (0,0,0))

cv2.imwrite('./fig_pad.png', img_pad)
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406479/ecf05561-25b9-f732-7799-a231787e2b3b.png" > <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406479/ddf5384c-05c1-edce-3aef-9e4d5c4ff98b.png">

無事パディングできています。
今まで黒い画像を作ってスライスで場所を毎回考えながら貼り付けた手間を考えると、驚くほど簡単にできました。
私は今後、opencvではこの方法でパディングします。
mac (catalina10.15)にhomebrewでpython3をインストールする際、出たエラーと解決法

しがない地方院生のsotaです。
初心者のため間違いや改善策、指摘・質問などがありましたらコメントお願いします。

macをクリーンインストールしてhomebrewでpython3を入れ直した際の備忘録です。
具体的に出たエラーは
1.

```bash

brew install python3
...
error: could not delete '/usr/local/lib/python3.7/site-packages/pip/_internal/configuration.py': Permission denied
...

```
2.
brewでpython3(/usr/local/bin)をインストールした後もデフォルトで入ってるpython3 (/usr/bin)を呼び出される問題です。

## 1. error: could not delete '/usr/local/lib/python3.7/site-packages/pip/_internal/configuration.py': Permission denied
`brew install python3`でpythonを更新しようと思っても上記のエラーでうまく中途半端にしかインストールできませんでした。
これは
`/usr/local/lib/python3.7/site-packages/`
のユーザーがrootのため発生していました。

そのため、
`sudo chown -R [あなたのユーザー名(your user name)] /usr/local/lib/python3.7/site-packages `
でユーザーを変更することで解決しました。

## 2. brewでpython3(/usr/local/bin)をインストールした後もデフォルトで入ってるpython3 (/usr/bin)を呼び出される問題
1.のエラーを解決してpython3.7.7をインストールできた後も

```bash
% python3
Python 3.7.3 (default, Apr 24 2020, 18:51:23)
```  
と3.7.7が起動しません。
pip3も動作が怪しかったです。
pathを見ると

```bash
 % which python3
/usr/bin/python3
```
となってます。
brewでインストールしたpythonは`/usr/local/bin`に来るので、これが原因です。
しかし、

```bash
echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
```
`/usr/local/bin`が$PATHの先頭に来ており、問題はないはずです。
これはよく分かっていませんが、

.bashrc もしくは.zshrc (最近macのデフォルトのshellがzshに変更されています。)

```bash
export PATH=/usr/local/bin:$PATH
```
を追記し、`source .bashrc`もしくは`source .zshrc`を行います。
これで

```bash
% echo $PATH
/usr/local/bin:/usr/local/bin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
```
となり、

```bash
% which python3
/usr/local/bin/python3

% python3
Python 3.7.7 (default, Mar 10 2020, 15:43:33)
```

と無事解決できました。pip3も同様に解決しました。
`/usr/local/bin:/usr/local/bin:`

となっているのが不可解で気持ち悪いですが動作できたので、私の力ではここで妥協にしました..
これの原因や意味を知っている方がいましたら、是非コメントで教えてください。
普段使っているBluetoothイヤホンとAndroidスマートフォンを、そのままOpen Homeでレシーバーにしてしまう横着

# 概要
普段屋外では、AndroidスマートフォンとBluetoothイヤホンで音楽を聴いている。
しかし、Bluetoothイヤホン側の切り替えは容易では無いため、
家では同じBluetoothイヤホンをそのまま使うのが難しい。
と言うかほんとBluetoothの切り替えは **クソ面倒くさい**。
(そのせいでDAPを使わなくなったと言っても過言ではない)

なので、そのままスマートフォンをOpenHomeのRendererにして、
Bluetoothイヤホンとスマートフォンの接続を変えないまま、
Bluetoothイヤホンでお家メディアを聴く、
と言うただのOpenHomeの活用例です。


## 概要図 (トポロジー)
![art_01_01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72257/639e48bf-c3df-9f30-fbcc-5749bdd19e17.jpeg)

## 個人的な前提
私は元々デスクトップPCで作業中に聴くBGMの再生にデスクトップPCを使いたく無いという思いがあり、
タブレットをアームで固定化して、据え置きにしている。
理由は、PCの起動に関わらずネットラジオを聴ける環境がほしかったり、
動画再生時の表示領域がモニター上にあると作業の邪魔だったり、
ウィンドウ切り替えに鑑賞してほしくないなどで、
”鑑賞”の部分をデスクトップPCから切り離している。

# 環境 (構成例)

* Server
  * DLNA Server
     * Raspberry Pi
     * CentOS 7
  * ReadyMedia
* Controller
  * Android タブレット
     * Amazon Fire HD 10
  * Bubble UPnP
* Renderer
  * Android スマートフォン
     * ARROWS M03 PREMIUM
  * Bubble UPnP
* Bluetooth Audio Reciever

# 利点/欠点
## 利点
  1. **Bluetoothの接続切り替えが不要。**
  2. ControllerとRendererが別れている。
  3. Controllerを据え置きにして再生画面やアルバム アートが見やすく出来る。
  4. 沢山の曲を垂れ流している時に、すぐ再生画面が見れるので、曲名などを確認しやすい。<br /> ⇒ 曲名を覚えるのに助かる。
  5. Rendererのスマートフォンは画面を見る必要がないので、適当に放って置ける。<br />⇒ 適当な場所で充電しておける。
  6. このための設定変更が少ないので、スマートフォンの日常使いに干渉しづらい。

## 欠点
  1. ControllerとRendererの両方の電池を消費する。<br />据え置きでない方には電池残量の注意も必要。
  2. 曲選時の遅延は時間がでかめ。
  3. Bubble UPnPの操作性が悪い。<br /> 連続して曲送りすると、再生情報と実際の再生が食い違うことがある。
  4. 動画では使えない。


# 余談
## 余談①
OpenHomeは概要はわかるものの、自分のライフサイクルに合った活用方と見つけるのが難しいのかなと思う。
今回Bluetoothのための活用法が見つかったのは、少しよかった。

## 余談②
スマートフォンのイヤホンジャックはどうしても日常の抜き差しは避けられないので、
Bluetoothは端末を大事に使う上でも非常によいのだけど。
Bluetooth自体は複数機器同士を相互に的に切り替えることを全く加味されていないので、
どうしても再生デバイスと出力機が固定化してまいやすいと言う苦さがある。
電池がスマートフォンの電池が切れそうだからDAPにしようとか、
Bluetoothイヤホンの電池が切れそうだから、予備のレシーバーに切り替えようとか。
普通の人はそういうこと無いんスかね・・・・？
複数オーディオの同時再生とか、管理機構とかBluetoothはその辺りがもう少し便利になって欲しい。
Spek（Android）入門

# はじめに
AndroidのUnitTestで[Spek](https://www.spekframework.org/)が流行しているので(今更ですが)、導入からはじめてみました。

この記事では、公式ドキュメントを元にAndroidプロジェクトのセットアップから
UnitTestの実行までを記載します。

そもそも、Spekとは？何が便利か？についてはこのあたりの記事やDroidKaigiでもよく紹介されているので、
そちらを閲覧してみてください。
https://qiita.com/k_keisuke/items/815ced486e8cdff8670d
https://qiita.com/sadashi/items/a5b93c9fc06e084456d2

# 導入

1.JUnit5を実行するため、サードパーティのライブラリを導入。 
--

プロジェクト自体はAndroidStudio標準のFragment + ViewModel で作成しました。

https://github.com/mannodermaus/android-junit5 のページに記載されている
gradleの設定をします。

２.Android modules の設定
--
[setup](android https://www.spekframework.org/setup-android/)

spek_version の変数やその他の設定はgradle.propertiesに記載します。
(うまく行かない部分は [公式のandroid sample](https://github.com/spekframework/spek/tree/2.x/samples/android)を参考にしました。 )

ここまで行けばSpekのビルドが通ります。

3.SpekのUnitTest
--
最終形はこのように書いてみました。

```kotlin
object ExampleSpekUnitTest: Spek({

    describe("A Calculator") {
        val calculator by memoized { Calculator() }

        it("should return 4") {
            assertEquals(4, calculator.add(2, 2))
        }

        it("should return 10") {
            assertEquals(10, calculator.add(5, 5))
        }

        it("should return 12") {
            assertEquals(12, calculator.add(6, 6))
        }
    }

    describe("view model verify") {
        val viewModel by memoized { MainViewModel() }

        it("should return text MainViewModel") {
            assertEquals("MainViewModel", viewModel.getText())
        }
    }
})
```

Spekは `gradlew test` でも実行できますが、
https://www.spekframework.org/running/ に記載されているPluginを導入すると
JUnitと同様に右クリックで実行できるので便利です。
<img width="50%" alt="スクリーンショット 2020-05-31 22.44.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384422/dcb781eb-8019-1be3-4da2-f9331d4dcaa9.png">

実行後
--
<img width="414" alt="スクリーンショット 2020-05-31 23.54.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384422/e8d7c53c-3b70-3f67-8ed2-fb3377d0990f.png">

実行が階層形式で表現されたり、実行順序が維持されることが見えていい感じです！

# まとめ
一度Spekの導入を行ったときに導入に手間取ったので、復習や今後を含めて記載してみました。
仕様のように記載できるテストはよりテストの価値が生まれるので、今後はどんどん使ってみます！
ゼロから始めるLeetCode Day42「2. Add Two Numbers」

#概要
海外ではエンジニアの面接においてコーディングテストというものが行われるらしく、多くの場合、特定の関数やクラスをお題に沿って実装するという物がメインである。

その対策としてLeetCodeなるサイトで対策を行うようだ。

早い話が本場でも行われているようなコーディングテストに耐えうるようなアルゴリズム力を鍛えるサイト。

せっかくだし人並みのアルゴリズム力くらいは持っておいた方がいいだろうということで不定期に問題を解いてその時に考えたやり方をメモ的に書いていこうかと思います。

[Leetcode](https://leetcode.com/)

[ゼロから始めるLeetCode 目次](https://qiita.com/KueharX/items/6ee2502c3b620c795b70)

前回
[ゼロから始めるLeetCode Day41「394. Decode String」](https://qiita.com/KueharX/items/4228d2a815922b1631be)

今はTop 100 Liked QuestionsのMediumを解いています。
Easyは全て解いたので気になる方は目次の方へどうぞ。

[Twitter](https://twitter.com/kueharx)やってます。

# 問題
[2. Add Two Numbers](https://leetcode.com/problems/add-two-numbers/)

難易度はMedium。
Top 100 Liked Questionsからの抜粋です。

空ではない連結リストを与えられるので与えられた数字をそれぞれ桁ごとに足していき、反転させて返すようなアルゴリズムを設計してください、というものです。


>Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.


# 解法

```Python
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        tempsum = 0
        root = cur = ListNode(0)
        while l1 or l2 or tempsum:
            if l1: tempsum += l1.val; l1 = l1.next
            if l2: tempsum += l2.val; l2 = l2.next
            cur.next = cur = ListNode(tempsum % 10)
            tempsum //= 10
        return root.next
# Runtime: 64 ms, faster than 95.04% of Python3 online submissions for Add Two Numbers.
# Memory Usage: 13.9 MB, less than 5.67% of Python3 online submissions for Add Two Numbers.
```

シンプルなものにはなりましたが、良さげですね。
問題番号でも最初の方のものは良問揃いな気がしますね。
今回のようにしっかりとした数学的な知識というよりは頭を使ってしっかりとフローチャートを考えれば解けるような問題が多い気がします。

※2021/11/1 追記

Javaで解きました。

このアルゴリズムを考える時には

- 桁上げが起こった時の処理
- 連結リストの走査方法
- 連結リストの長さが異なる時の処理
- 走査が終わった後にcarryがある場合の処理


などなど色んなことを考えなくてはならないので良い問題だなあと思いました。

それこそSolutionの↓はいい回答だと思います。

```java
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    // dummyHeadを作っておくことで余分なチェックが必要なくなる
    ListNode dummyHead = new ListNode(0);
    ListNode p = l1, q = l2, curr = dummyHead;
    int carry = 0;
    // p,qのいずれかが存在する限り続ける
    while (p != null || q != null) {
        // nullでない場合に値を代入する。nullの場合は0を返す。
        int x = (p != null) ? p.val : 0;
        int y = (q != null) ? q.val : 0;
        // carry(前の値の足し算の桁上がり)とそれぞれの値の足し算
        int sum = carry + x + y;
        // sumを10で割った値が桁上がり値となる 
        carry = sum / 10;
        // curr.nextにsumを10で割った時の余りを値を入れる
        curr.next = new ListNode(sum % 10);
        curr = curr.next;
        if (p != null) p = p.next;
        if (q != null) q = q.next;
    }
    // ループ終了後に桁上がりがあった場合に引き継ぐことで桁上がりをカバー
    if (carry > 0) {
        curr.next = new ListNode(carry);
    }
    return dummyHead.next;
}
```


今回はこの辺で。お疲れ様でした。
【python selenium】Google検索結果をスクレイピング後 タイトルとURLをcsv出力

#環境
macOS Catalina 10.15.3
Python 3.6.5 

#概要
任意のワードでGoogle検索し、その検索結果の一覧を任意のページ数まで取得
タイトルとurlをcsv出力する

#方法（コピペOK）
※コピペOKですがコード内のディレクトリや検索ワードは任意で書き換えてください

```
# !python3
# google検索結果のタイトルとURLを取得してcsv出力

import time, chromedriver_binary, os, csv
from selenium import webdriver

output_path = "/最終的なcsv出力ディレクトリ
os.chdir(putput_path)                        

driver = webdriver.Chrome()                 # Chromeを準備

#htmlを開く
driver.get("https://www.google.com/")       # Googleを開く
search = driver.find_element_by_name("q")   # 検索ボックス"q"を指定する
search.send_keys(“xxx yyy zzz“)  # 検索ワードを送信
search.submit()                             # 検索を実行
time.sleep(3)                               # 3秒待機

def ranking(driver):
    i = 1 # 1で固定
    i_max = 10 # 何ページ目まで検索するか？
    title_list = []
    link_list = []

    #現在のページが指定した最大分析ページを超えるまでループする(i_max)
    while i <= i_max:
        # タイトルとリンクはclass="r"に入っている
        class_group = driver.find_elements_by_class_name("r")
        # class="r" からタイトルとリンクを抽出し,リストに追加するforループ
        for elem in class_group:
            title_list.append(elem.find_element_by_class_name('LC20lb').text)           # タイトル(class="LC20lb")
            link_list.append(elem.find_element_by_tag_name('a').get_attribute('href'))  # リンク(aタグのhref)

        #「次へ」のボタンはひとつしかないがあえてelementsで複数検索. 空のリストであれば最終ページという意味.
        if driver.find_elements_by_id("pnnext") == []:
            i = i_max + 1   # 次のページがなければ,最大ページ数を強制的に越してループ終了
        else:
            # 次ページのURLはid="pnnext"のhref属性
            next_page = driver.find_element_by_id("pnnext").get_attribute("href")
            driver.get(next_page)
            i = i + 1       # ページを進む
            time.sleep(3)   # 3秒休憩, これを指定の最大ページ数まで繰り返す
    return title_list, link_list 

# 上記で定義したranking関数を実行してタイトルとURLリストを取得する
title, link = ranking(driver)

# csvで吐き出すために[[a,1],[b,2]]みたいなリストを作成
result = [list(row) for row in zip(title, link)]

# resultを使ってcsv出力
with open("result.csv", mode="w", encoding="utf-8") as f:
    writer = csv.writer(f, lineterminator="\n")
    writer.writerows(result)

# ブラウザを閉じる
driver.quit()
```
Amazon Linux 2 に AWS CloudFormation ヘルパースクリプトがプレインストールされていなかった話

# 事の起こり
AWS上にWordPressサーバを建てていたときに、CloudFormationのサンプル[^1]をもとにyamlを書いていた。
PHPのバージョン引き上げるのにamazon-linux-extrasを使いたかったこともあり、Amazon LinuxからAmazon Linux 2に変更したところCloudFormationが通らなくなった。

# 問題のコード
AutoScalingのインスタンス起動時にこけていることはわかっていたので、コードを消したり戻したりを繰り返した結果以下のコードが原因と判明。
```yum update -y aws-cfn-bootstrap```
aws-cfn-bootstrapが何者かよくわからずに使っていたので公式のドキュメント[^2]を改めてよく読むと以下の記述があった。

> Amazon Linux AMI イメージ
AWS CloudFormation ヘルパースクリプトは Amazon Linux AMI イメージにプレインストールされています。
Amazon Linux AMI の最新バージョンでは、スクリプトは /opt/aws/bin にプレインストールされています。
以前の Amazon Linux AMI バージョンでは、スクリプトを含む aws-cfn-bootstrap パッケージは、Yum リポジトリにあります。

>その他のプラットフォーム用パッケージのダウンロード
Amazon Linux AMI イメージと Microsoft Windows (2008 以降) を除く Linux/Unix ディストリビューション用に、aws-cfn-bootstrap パッケージをダウンロードできます。 

Amazon LinuxにプレインストールされているならAmazon Linux 2にもあると勝手に思っていたけど、そんなことどこにも書いてないんですね。
updateをinstallに変えたら無事通りました。

# 結論
いい加減WordPressやめてAmplifyでReactとかVue.jsを使ったページ作れって話なんですが、そこまでの気力がなかったので妥協した結果がこれでした。
いろいろ勉強にはなったんですがやっぱり楽するための苦労は妥協すべきではないですね。

# 

[^1]: https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/sample-templates-applications-eu-west-1.html
[^2]: https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/cfn-helper-scripts-reference.html
モーダルウインドウを背景固定にしてスクロールバー分のガタつき問題を解決しつつ、iOS Safariにも対応してしかもjQuery非依存にしたいワガママなアナタへ捧ぐ愛のコード

![modal_optional_article.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593842/dce29f6d-3eab-511a-bdfa-a4e9a0f33d80.png)

記事はこちら
https://myscreate.com/optional-modal/
TC358743XBG を使った HDMI to CSI-2 アダプタを使ってみる(接続編)

もうちょい色々試してから投げようかと思ったけど、業務の方が多忙でこのまま埋もれそうだったので忘れる前にメモ。

## TC358743XBG HDMI to CSI-2 について

https://mzyy94.com/blog/2020/04/10/raspberrypi-hdmi-input/

こちらを読んで試そうと思ったのがきっかけ。

[東芝東芝デバイス＆ストレージ TC358743XBG](https://toshiba.semicon-storage.com/jp/semiconductor/product/interface-bridge-ics-for-mobile-peripheral-devices/hdmir-interface-bridge-ics.html)は HDMIの信号入力をCSI-2に変換するブリッジチップです。

よく映像配信とかでつかってる、HDMI入力をWebカメラに見せかける(UVCにブリッジする)やつではなく、こちらはRaspberry Pi や Jetson Nanoで同じものカメラ接続IFであるCSI-2に変換できます。

で、ＨＤＭIの映像ソースをRaspberry Piとかに入力できるとプログラマブルな配信機材っぽく使えたり、あわよくばそのままmobilenetとかで判定とかかけれたらおもしろいなと思ったわけです。
HDMIさえでればOKなら、スペック的には古くてもレンズはちゃんとしてる古いカメラとかも流量できるしね。(ここが後に悲劇を生むとは誰も思わなかった)

## 購入

Aliexpressで 「TC358743XBG」で検索すると山ほど出てくる。値段はだいたい 5000jpy前後

![D32EDB3E-4C7B-4788-83C3-8E67D47AA3A2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52410/30afe4df-a1ba-63c0-dc1f-d6dac597f01c.png)

というわけで、さっそく買った。ぱっと見、基板レイアウト的にこの２種類がスタンダードっぽかったので、両方買ってみた。

![8A6960D1-0226-4889-913F-6C6DE5061DDD_1_105_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52410/7e8a92e9-287a-41c6-79af-113bdc11723f.jpeg)

ちなみに、オーダーしたのが 2020/04/11、届いたのは 2020/05/18 ごろなので、約１ヶ月かかった…まぁ触る時間無かったから良いんだけど。


## セットアップ

1. Raspberry Pi 4 の カメラコネクタ(CSI-2)に TC358743XBG を接続
2. `vcgencmd get_camera` コマンドで `supported=1 detected=1` とかえってくる事を確認(認識OK)
3. TC358743XBG にHDMIソースを接続(今回は Cannon EOS M3のHDMI出力)


## 問題

![31CC3302-FB82-429B-B53F-DB73247B9268_1_105_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52410/040cb93c-2de1-4a07-a4a1-d395f12ac0c6.jpeg)

さっそく `raspistill -o img.jpg` とか試して見たが、以下のエラーが出る。

```
mmal: mmal_vc_component_enable: failed to enable component: ENOSPC
mmal: camera component couldn't be enabled
mmal: main: Failed to create camera component
mmal: Failed to run camera app. Please check for firmware updates
```

firmwareあげろと言う話なので `sudo apt upgrade` も試したが、一向に改善なし。  
途方にくれていたところ、何の気なしにHDMIソースをiPhoneに変えてみたらなんと写るではないか。

## 検証

ＨＤＭＩの入力ソースにより挙動が変わる事が分かったので、とりあえず身の回りにあるデバイスで試す。
入力ソースの種類の他に、キャプチャデバイス側も比較対象が欲しいので、Amazonで売ってる比較的安価なHDMI to UVCキャプチャを使う。 [TreasLin とか BasiColor とか ShuOneとかいろんなブランドで出てるけど多分中身は同じやつ。](https://amzn.to/2XjZ52i) ソフト的には MiraBox って名前になってる。

それぞれの入力ソースと、２つのキャプチャデバイスが映像を取得できたかどうかの結果は以下の通り。

| HDMIソース | TC358743XBG + RasPi4 | MiraBox |
|:---|:----:|:---:|
| Nvidia Shield TV | OK | OK |
| iPhone XR + HDMIアダプタ | OK | OK |
| 秋葉原で適当に買った激安ムービーカム | OK | OK |
| FireTV Stick | NG(※) | OK |
| EOS M3 | NG | OK |
| GoPro HERO 6 | NG | OK |

※上記エラーが発生する前にraspistillコマンドがハングアップしてしまう。再現率は 3/3。

## 結果

HDMI 詳しくないのでよく分からない。
EOS M3 と iPhone、ムービーカムの、ディスプレイ側の信号の認識は以下の通りで、特に変わらないように見える。

- iPhone : 1080p@60.0Hz, H: 67.5KHz, PCLK: 148.4MHz, HDCP 1.4 Enabled Sink
- EOS M3 : 1080p@60.0Hz, H: 67.5KHz, PCLK: 148.4MHz, HDCP Disabled
- ムービーカム: 1280x720, H: 67.5KHz, PCLK: 148.4MHz, HDCP Disabled

よく分からないし、僕自身は調べる術をもたないので、とりあえず記録として残すだけ。
動くには動くので、動作するデバイスでもって本来やりたかったことを今後試そうと。
手っ取り早くGPUの使用状況を確認する

`nvidia-smi -l 5`でGPUの使用状況を継続的に確認することができますが、これだと1ステップあたりの行数が多くて時系列での傾向を把握するのが難しいです。
その際に`--query-gpu`オプションを使うことで結果が見やすくなります。

```
$ nvidia-smi --query-gpu=timestamp,memory.used --format=csv -l 5
timestamp, memory.used [MiB]
2020/05/31 14:20:46.035, 0 MiB
2020/05/31 14:20:51.036, 0 MiB
2020/05/31 14:20:56.037, 0 MiB
2020/05/31 14:21:01.038, 0 MiB
2020/05/31 14:21:06.038, 1472 MiB
2020/05/31 14:21:11.039, 1472 MiB
2020/05/31 14:21:16.040, 2270 MiB
2020/05/31 14:21:21.040, 2270 MiB
2020/05/31 14:21:26.041, 2270 MiB
2020/05/31 14:21:31.042, 2270 MiB
2020/05/31 14:21:36.042, 2270 MiB
2020/05/31 14:21:41.043, 2270 MiB
2020/05/31 14:21:46.044, 2270 MiB
2020/05/31 14:21:51.044, 2270 MiB
2020/05/31 14:21:56.045, 2270 MiB
2020/05/31 14:22:01.046, 0 MiB
2020/05/31 14:22:06.046, 0 MiB
```

タイムスタンプが付けられるのは地味に便利。どのタイミングでGPUメモリが使われているのかわかりやすいです。
【Day75】積み上げ日記

##学習内容
■ネコ泣いちゃったアプリ
■数字当てゲーム

##学習ポイント
■createElement(“生成したい要素”);
■document.body.appendChild(生成した要素が入った変数名);
■querySelectorAll(“セレクタ名”);
■入力された数字を保持するコード
let 変数名 = Number(TFのID名.value);



##参考記事
https://developer.mozilla.org/ja/docs/Learn/JavaScript/First_steps/What_is_JavaScript
Ktormに実装されていないSQL関数を自分で作成する

# Ktormについて

最近の仕事ではSpring Batchを使ったバッチ処理をKotlinで書いています。
mysqlのDBにSQLを投げる際にORマッパーをどうするか調査した結果、Kotlin製のOR
マッパーである[Ktorm](https://ktorm.liuwj.me/)を使用しています。

KtormはSQL部分をDSLで見通しよく書けるので、結構満足して使っています。

例)

```sql:SQL

select
  user_id,
  sum(amount)
from
  reports
where
  created_at >= '2020/05/01'
group by
  user_id
```

上記のようなSQLだと全てDSLで書くことができ、テーブルのカラム名もクラスに定義され(今回の例ではReportDef)
カラムの内容の変更があればエンティティ部分とその使用箇所を修正すればいいし、修正漏れがあればコンパイルエラーになってくれます。

```kotlin:sql部分
database.from(ReportDef)
.select(
    ReportDef.userId,
    sum(ReportDef.amount)
).where {
    ReportDef.createdAt greaterEq date
}.groupBy(ReportDef.userId)
```

```kotlin:Report.kt
interface Report : Entity<Report> {
    companion object : Entity.Factory<Report>()

   var id: Long
   var userId: Long
   var amount: Int
   var purchaseType: String

}
object ReportDef : Table<Report>("reports") {
   val id by long("id").primaryKey().bindTo { it.id }
   val userId by long("user_id").bindTo { it.userId }
   val amount by long("amount").bindTo { it.amount }
   val purchaseType by varchar("purchase_type").bindTo { it.purchaseType }
}

```

# ハマったケース


今回 購入方法がCASHとかCARDのように複数存在し、'CASH'のみの使用回数を知る必要がありました。
SQLだとselect部分に``count(purchase_type='CASH')``を追加する必要がありました。

``count(purchase_type)``だとKtormでは``count(ReportDef.purchaseMethod)``で書けるのですが、
``count(purchase_type='CASH')``はさすがに素のKtormでは書けません。

基本的にORマッパーが提供している機能で必要なSQLを書ければ良いのですが、
未提供の場合は最悪のケースで文字列の中に素のSQLを書くことになり、
なんとか避けたいなぁと思っていました。

# 調査結果


色々調べたところ、Ktorm自体も[mysqlで使用するSQL関数を拡張しているロジック](https://github.com/vincentlauvlwj/Ktorm/blob/master/ktorm-support-mysql/src/main/kotlin/me/liuwj/ktorm/support/mysql/Functions.kt)
があり、これを参考に拡張関数のcountifメソッドを実装することでKtormのDSLで書くことができました。


```kotlin:sql部分
database.from(ReportDef)
.select(
    ReportDef.userId,
    sum(ReportDef.amount),
    ReportDef.purchaseMethod.countif('CASH') // 追加部分
).where {
    ReportDef.createdAt greaterEq date
}.groupBy(ReportDef.userId)
```


```kotlin:DatabaseMethodExtension.kt

fun <T : Any> ColumnDeclaring<T>.countIf(right: String): FunctionExpression<T> {
    val rightExpression = ArgumentExpression(right, VarcharSqlType)
    val equal = BinaryExpression(BinaryExpressionType.EQUAL, asExpression(), rightExpression.asExpression(), BooleanSqlType)
    return FunctionExpression(
            functionName = "sum",
            arguments = listOf(equal),
            sqlType = sqlType)
}
```

やっていることをざっくり説明すると以下になります。

- SQLでのsum関数を使用するFunctionExpressionを返す拡張メソッドを用意する
- 引数から渡された文字列を表すArgumentExpressionを用意する
- ``=``を表すBinaryExpressionを用意し、右辺側に先ほどのArgumentExpressionを渡す
- ``=``を表すBinaryExpressionをFunctionExpressionのarguments引数に渡す

# まとめ
- KtormのDSLはSQL関数をどうしても使う必要があるケースでもメソッドを実装することで対応可能。
- Kotlinの拡張関数は便利

# 参考URL
- [Ktorm](https://ktorm.liuwj.me/)
- [拡張(extension)](https://dogwood008.github.io/kotlin-web-site-ja/docs/reference/extensions.html)
- mysqlで使用するSQL関数を拡張しているロジック](https://github.com/vincentlauvlwj/Ktorm/blob/master/ktorm-support-mysql/src/main/kotlin/me/liuwj/ktorm/support/mysql/Functions.kt)
自己証明書自動作成

HTTPS通信のテストのため、自己証明書（オレオレ証明書）を使うケースがあるが、
自己証明書を自動的に作成する方法を説明する。

検証環境：Amazon Linux, Amazon Linux2（CentOSやRedHat系もOK）
事前インストールパッケージ：opnessl

#### openssl確認
```
[root@localhost tmp]# openssl version
OpenSSL 1.0.1k-fips 8 Jan 2015
```
opensslのバージョンが表示されたら、OK


#### 証明書作成
```
[root@localhost tmp]# secretFileName=secret
[root@localhost tmp]# domainName=www.hoge.com
[root@localhost tmp]# email=root@hoge.com

[root@localhost tmp]# openssl genrsa 2048 > ${secretFileName}.key
[root@localhost tmp]# openssl req -new -key ${secretFileName}.key << EOF > ${secretFileName}.csr
JP
Tokyo
Tokyo
hogeCompany
development
${domainName}
${email}


EOF
[root@localhost tmp]# openssl x509 -days 3650 -req -signkey ${secretFileName}.key < ${secretFileName}.csr > ${secretFileName}.crt
```
opensslで証明書作成時に色々入力を求められるが、EOF入力で自動化している。
**気を付けるところは上記の${email}とEOFの間に改行が2行入ること**
secretFileNameやdomainName、emailを外部からパラメータとして受け入れるようにすれば、
shellscriptとして使えるので、試してみよう！