OmniAICreator/Qiita-1.07M huggingface dataset:
OpenCVのSIFTで特徴抽出してみた


#SIFTとは

- SIFT(Scale-Invariant Feature Transform)
- 特徴点の検出と特徴量の記述を行います。
- 特徴: 拡大縮小に強い、回転に強い、照明変化に強い。



###SIFTのアルゴリズム

#####【特徴点の検出】
1-1. 特徴点となる候補点の探索
1-2. 候補点の絞り込み
#####【特徴量の記述】
2-1. 各特徴点の勾配を検出
2-2. 各特徴点の勾配方向ヒストグラム計算






####1-1. 特徴点となる候補点の探索

スケール方向の差分画像(DoG画像)において、極値を取る点を特徴点とする。簡単にまとめると、２次元(x,y)である画像に、**スケール**という次元を加えて３次元にする。スケールはどうやって決めるかというと画像(x,y)を、ある量σだけ**平滑化**した(x,y,σ)を考える。平滑化には**ガウシアンフィルタ**を使う。このデータを使って、特徴点となる候補を洗い出す。変化量が大きいってことは、情報量が多い。

####1-2. 候補点の絞り込み

DoG画像の出力値は、(x,y,σ)を変数とする関数なので、それを特徴点周りで近似してやり、その近似式の導関数とかを使って、極値をとる点を算出し直すってこと。エッジ上の点は除外。DoG出力値が小さいものを除外。


####2-1. 各特徴点の勾配を検出

- 特徴点の周りで輝度勾配ヒストグラムを作成
- 方向・強度の計算はHoGとほぼ同じ
- 方向は36方向

ポイント
強度は、特徴点のスケールのガウシアンフィルタで重み付け。
⇒スケール変化に強くなる。

- 求めたヒストグラムにて、強度が最大値の８０％を超える方向を、この特徴点の方向と定める。


####2-2. 各特徴点の勾配方向ヒストグラム計算

- 特徴点の方向を基準の方向として、再度、輝度勾配ヒストグラムを作成する（回転に強い）
- 方向は８方向(45度ずつ)
- 4x4x8 = 128次元の特徴量
- 正規化もする（これにより照明変化に強くなる）



#SIFTのコード

サンプルコードです。

```.py

import cv2
import numpy as np

img = cv2.imread('dog.jpg')
sift = cv2.xfeatures2d.SIFT_create()
keypoints, descriptors = sift.detectAndCompute(img, None)
img_sift = cv2.drawKeypoints(img, keypoints, None, flags=4)
cv2.imwrite("sift_img.jpg",img_sift)

```

- image : 入力画像
- keypoints : 入力画像から得られたキーポイント
- flags : 図形描画機能の識別設定

入力画像
![dog.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223559/1f2687f4-fb0d-c104-41f0-eca5ea492406.jpeg)




出力画像

![sift_img.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223559/31b90657-1df8-6df2-8c60-cff30f326033.jpeg)




#参考文献

- [Sift特徴量について](https://www.slideshare.net/la_flance/sift-20150311)
 
- [SIFT(Scale-Invariant Feature Transfrom)の導入](http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_feature2d/py_sift_intro/py_sift_intro.html)
pythonで隣接行列から２点間の全てのパスを見つける

# はじめに
2頂点対最短経路問題を解いている時に、最短ではないが条件を満たすパスの見つけ方を調べたので、メモとして残しておきます。

# 手順
#### 1. 隣接行列の作成
今回のデータは.csv fileに保存されているのでpandasを使って読み取り、numpy arrayに変換します。

```
file = pd.read_csv('Data1.csv', header=None, delimiter=',')  
data = np.array(file)
```  
#### 2. NetworkXでグラフを作成する。  
NetworkXは、グラフ/ネットワーク理論系の計算を行うためのPythonのパッケージです。

```
G=nx.from_numpy_matrix(data)
```

#### 3. 指定した２点間をつなぐ全てのパスを探し、プリントする。
使用した関数はnx.all_simple_paths()。この関数は先ほど作成したグラフGにおいて、スタート地点(= source)とゴール地点（= target）を指定することで、指定した２点間をつなぐ全てのパスを探し出します。ただし、有向グラフでない場合、特に巨大なグラフの場合は何万通りものパスを見つけてしまうので、cutoffでパスの深さを限定する必要があります。

```
for path in nx.all_simple_paths(G,source=1,target=100, cutoff=13): 
	print(path)
```
結果はこの通りです、
読み込んだデータは8000ノードある巨大なものなので、パスの深さを13に限定しました。

```
[1, 2587, 808, 211, 188, 6510, 6216, 3057, 5276, 1512, 3826, 5203, 100]
[1, 2587, 808, 4675, 1671, 5411, 3983, 3714, 202, 3064, 644, 2182, 100]
[1, 2587, 808, 4675, 1671, 5411, 3983, 6512, 3590, 7915, 2182, 100]
[1, 2587, 808, 4675, 5958, 4521, 6562, 7430, 4083, 6189, 3089, 3826, 5203, 100]
[1, 2587, 6562, 4521, 5958, 4675, 1671, 5411, 3983, 6512, 3590, 7915, 2182, 100]
[1, 2587, 6562, 6046, 4846, 324, 7374, 1141, 3651, 1963, 888, 5203, 100]
[1, 2587, 6562, 7430, 4083, 6189, 3089, 3826, 5203, 100]
[1, 3346, 4986, 4968, 2652, 1750, 5373, 6453, 6667, 5505, 7572, 7915, 2182, 100]
[1, 3346, 4986, 4968, 2652, 2154, 5437, 656, 3987, 2058, 6764, 6790, 2182, 100]
[1, 3346, 4986, 4968, 2652, 2800, 2448, 3575, 1141, 3651, 1963, 888, 5203, 100]
[1, 3346, 4986, 4968, 4197, 7116, 6733, 869, 4783, 6468, 7620, 6790, 2182, 100]
[1, 3346, 4986, 4968, 5331, 1379, 6246, 6214, 40, 2579, 3590, 7915, 2182, 100]
[1, 3346, 4986, 4968, 5331, 7417, 7969, 6865, 2863, 868, 6764, 6790, 2182, 100]
```

# 最後に
コード自体はとてもシンプルですが、一度引っかかったポイントとしてはパスの深さを限定しないでいるとプログラムが終わらないという点です。同じような問題に取り組んでいる方の参考になればと思います。
RxJS: map, concatMap, mergeMap, switchMap, exhaustMap の動作を理解する

サンプルコード書いたら大体理解できた。

利用シーンのイメージ:

* map: 値の変換操作
* concatMap: 同期処理など、キューイングして直列実行したい処理。
* mergeMap: TODOのDone操作など、並列実行したい処理。
* switchMap: リアルタイム検索のキーボード入力から検索する処理など、後続の処理のみ優先させたい場合。
* exhaustMap: フォームのサブミットなど、多重実行されたくない処理。


```typescript
import { of } from 'rxjs';
import {
  concatMap,
  exhaustMap,
  map,
  mergeMap,
  switchMap,
} from 'rxjs/operators';

const sleep = (ms: number) => {
  return new Promise(resolve => {
    console.log('sleep: start');
    setTimeout(() => {
      console.log('sleep: end');
      resolve();
    }, ms);
  });
};

const array = [1, 2, 3];

/**
 * map
 * * Promiseは展開されない
 * * 配列操作と同じ
 */
const mapExample = () => {
  of(...array)
    .pipe(
      map(i => {
        return sleep(1000).then(() => i * 2);
      }),
    )
    .subscribe(i => console.log(i));
};

// 出力:
// Promise { <pending> }
// Promise { <pending> }
// Promise { <pending> }

/**
 * concatMap
 * * Promiseが展開される
 * * 連続で値が流れてきた場合は直列で実行される。
 */
const concatMapExample = () => {
  of(...array)
    .pipe(
      concatMap(i => {
        return sleep(1000).then(() => i * 2);
      }),
    )
    .subscribe(i => console.log(i));
};

// 出力:
// sleep: start
// sleep: end
// 2
// sleep: start
// sleep: end
// 4
// sleep: start
// sleep: end
// 6

/**
 * mergeMap
 * * Promiseが展開される
 * * 連続で値が流れてきた場合は並列で実行される。
 */
const mergeMapExample = () => {
  of(...array)
    .pipe(
      mergeMap(i => {
        return sleep(1000).then(() => i * 2);
      }),
    )
    .subscribe(i => console.log(i));
};

// 出力:
// sleep: start
// sleep: start
// sleep: start
// sleep: end
// 2
// sleep: end
// sleep: end
// 4
// 6

/**
 * switchMap
 * * Promiseが展開される
 * * 連続で値が流れてきた場合は並列で実行され、ストリームには最後の結果しか流れない。
 */
const switchMapExample = () => {
  of(...array)
    .pipe(
      switchMap(i => {
        return sleep(1000).then(() => i * 2);
      }),
    )
    .subscribe(i => console.log(i));
};

// 出力:
// sleep: start
// sleep: start
// sleep: start
// sleep: end
// sleep: end
// sleep: end
// 6

/**
 * exhaustMap
 * * Promiseが展開される
 * * 連続で値が流れてきた場合は最初のPromiseのみ実行され、実行中は後続の値を切り捨てる。
 */
const exhaustMapExample = () => {
  of(...array)
    .pipe(
      exhaustMap(i => {
        return sleep(1000).then(() => i * 2);
      }),
    )
    .subscribe(i => console.log(i));
};

// 出力:
// sleep: start
// sleep: end
// 2

(async () => {
  // 動作確認はコメントを切り替える
  mapExample();
  // switchMapExample();
  // mergeMapExample();
  // concatMapExample();
  // exhaustMapExample();
})();

```
padStart で日付・時刻を二桁表示する書き方

Date オブジェクトで月日、時間や分を取得することは多いですね。
例えば `分` を取得したいとき、 14:05 などの場合 getMinutes() を使いますが、結果は `5` となってしまいます。
こと時刻の分の表示に関しては、二桁じゃないと時刻っぽくないですね。

二桁記述にする際によくある実装方法と、別の実装方法と合わせて紹介します。

## よくある記述

```javascript

const date = date = new Date('2020-01-01 14:05:30')
// Wed Jan 01 2020 14:05:30 GMT+0900 (日本標準時)

('0' + date.getMinutes()).slice(-2)
// "05"
```

これで実装は問題ないんですが、 `slice` でやってるあたりが「上手い !!」と思いつつもあまり美しいコードではないなと常々思っていました。

それを解消できたコードが以下です。とはいえまだ課題はあるかなと思ってます。

## padStart を使った記述

```javascript

const date = date = new Date('2020-01-01 14:05:30')
// Wed Jan 01 2020 14:05:30 GMT+0900 (日本標準時)

date.getMinutes().toString().padStart(2, '0')
// "05"
```

[String.prototype.padStart()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/padStart) は、文字列を任意の長さに変えるのに使えるメソッドなのでこちらを使ってみました。

>padStart() メソッドは、結果の文字列が指定した長さになるように、現在の文字列を他の文字列で (必要に応じて繰り返して) 延長します。延長は、現在の文字列の先頭から適用されます。

残っている課題としては getMinites の結果が Number で返ってくるため、 `toString()` で文字列化してあげないといけないことですかね。それでもだいぶモヤモヤは抜けました。

## ただし IE は非対応

なのでご注意を。
Windowsや IIS や .NET などのバージョン対応メモ

#Windows にプリンストールされている IIS のバージョン対応表

|Windows OS | IIS バージョン |
|:----------|--------------:|
|Windows XP Pro |5.1|
|Windows Server 2003 |6.0|
|Windows Vista / Windows Server 2008 |7.0|
|Windows 7 / Windows Server 2008 R2 |7.5|
|Windows 8 / Windows Server 2012 |8.0|
|Windows 8.1 / Windows Server 2012 R2 |8.5|
|Windows 10 / Windows Server 2016 以降 |10.0|

#Windows にプリインストールされている .NET Framework バージョン対応表
機能の有効化は必要なものもあります。

|Windows OS |プリインストール .NET Framework バージョン|
|:----------|:------------------|
|Windows 7|.NET Framework 3.5|
|Windows 8|.NET Framework 4.5|
|Windows 8.1|.NET Framework 4.5.1|
|Windows 10|.NET Framework 4.6|
|Windows 10 (11月のUpdate)|.NET Framework 4.6.1|
|Windows 10 (Anniversary Update)|.NET Framework 4.6.2|
|Windows 10 (Creators Update)|.NET Framework 4.7|
|Windows 10 (Fall Creators Update)|.NET Framework 4.7.1|
|Windows 10 (April 2018 Update / October 2018 Update)|.NET Framework 4.7.2|
|Windows 10 May 2019 Update|.NET Framework 4.8|

|Windows Server OS |プリインストール .NET Framework バージョン|
|:-----------------|:------------------|
|Windows Server 2008 / 2008 R2 |.NET Framework 3.5|
|Windows Server 2012 |.NET Framework 4.5|
|Windows Server 2012 R2 |.NET Framework 4.5.1|
|Windows Server 2016|.NET Framework 4.6.2|
|Windows Server 2019|.NET Framework 4.7.2|

#.NET Standard と .NET Framework または .NET Core のバージョン対応表
|.NET Standard|.NET Framework|.NET Core|
|:-----------------|:------------------|:--|
|1.0|4.5|1|
|1.1|4.5|1|
|1.2|4.5.1|1|
|1.3|4.6|1|
|1.4|4.6.1|1|
|1.5|4.6.1|1|
|1.6|4.6.1|1|
|2.0|4.6.1|2.0|
|2.1|※1|3.0|

※1
.NET Framework 4.8 は .NET Standard 2.1 に対応するものは発表されていない。
.NET Framework は互換性維持のため、発表が遅れるとのこと。
参考: https://devblogs.microsoft.com/dotnet/announcing-net-standard-2-1/

#参考
https://ja.wikipedia.org/wiki/Internet_Information_Services
https://support.microsoft.com/ja-jp/help/224609/how-to-obtain-versions-of-internet-information-server-iis
https://docs.microsoft.com/ja-jp/dotnet/framework/get-started/system-requirements
https://docs.microsoft.com/ja-jp/dotnet/standard/net-standard
自分メモ：バリデーションを行うのはサーバー側？クライアント側？両方？？

##結論：サーバー側、クライアント側の両方行います。
(twitter引用：https://twitter.com/saya1001kirinn/status/1191950370328715264)

例えばLaravelで最小値0を指定するバリデーションの場合、Controllerのバリデーションにmin:0って書くのか、viewでinputタグ内にmin="0"を書くのか。

####例：サーバー側対応

```php:Controller.php
$request->validate([
    'total' => ['required', 'min:0'],
]);
```

####例：クライアント側対応
```php:create.blade.php
<input type="number" min="1" value="{{ old('total') }}">
```

サーバー側はデータの整合性を担保するため、クライアント側はUXを向上するためと考えます。
サーバー側の対応は必須です。

時間がない場合はサーバー側のみの対応でもいいかと思いますが、
可能であれば両方対応が良さそうです。
クライアント側はHTMLバリデーションまたはjsでバリデーションを行います。
windows10のコマンドプロンプトで、linuxのコマンドを使う。

#環境
windows10

#準備
設定 > アプリ (アプリと機能) > プログラムと機能 > Windows機能の有効化または無効化 

に移動する。

その後、

Windows Subsystem for Linux

の項目にチェックを入れて、OKをクリックする。

スタートメニューの「Microsoft Store」で「Linux」を検索して好きな Linux のディストリビューションをインストールする。（この場合はUbuntu）

#本番
C:\Users\xxx
などに

linuxcmd.bat というファイルを、以下の内容で保存する。

```linuxcmd.bat
@echo off
doskey /MACROFILE=%~dp0.doskeys
```

そして、同じディレクトリに
.doskeys
という名前のファイルを、以下の内容で作成する。

```.doskeys
alias=if "$1"=="" (doskey /macros) else for /f "delims== tokens=1,*" %i in ("$*") do @if "%j" neq "" (  doskey $* ) else (  doskey /macros $b findstr /b /c:"%i=" )

pwd=cd
traceroute=tracert
ifconfig=ipconfig
awk=wsl awk $*
cat=wsl cat $*
clear=wsl clear $*
cp=wsl cp $*
cut=wsl cut $*
df=wsl df $*
diff=wsl diff $*
dig=wsl dig $*
du=wsl du $*
find=wsl find $*
grep=wsl grep $*
gzip=wsl gzip $*
head=wsl head $*
ip=wsl ip $*
join=wsl join $*
kill=wsl kill $*
less=wsl less $*
ls=wsl ls $*
man=wsl man $*
more=wsl more $*
mv=wsl mv $*
ps=wsl ps $*
rm=wsl rm $*
sed=wsl sed $*
sort=wsl sort $*
sudo=wsl sudo $*
tail=wsl tail $*
touch=wsl touch $*
tr=wsl tr $*
uniq=wsl uniq $*
whoami=wsl whoami $*
wc=wsl wc $*
wget=wsl wget $*
```

これで準備は完了しました。

#実行
コマンドプロンプト上で、```linuxcmd.bat```を実行し、好きなlinuxコマンドを実行します。

#コマンドプロンプト起動時にlinuxcmd.batを実行するようにする。
linuxcmd.batと同じディレクトリに、linuxcmdreg.bat という名前で、以下のファイルを作成する。

```linuxcmdreg.bat
@echo off

reg add   "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v AutoRun /d %~dp0linuxcmd.bat
reg query "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v AutoRun

pause
```

#制限
パイプが使えない。
日本語のファイルが文字化けする。

対処法：アプリケーションのubuntuのコマンドプロンプトを使用する。

#コマンドの追加

.doskeysに、以下のようにすることでコマンドを追加できる。

Linuxの方で、sudo apt installなどを用いてImagemagickなどをインストールしてから、

```
<追加したいコマンド>=wsl <追加したいコマンド> $*
```
と追記することで、コマンドを追加できる。

例

Linuxの方で、
```
sudo apt install tree
```

.doskeys に、
```
tree = wsl tree $*
```

と追記すると、Windowsのコマンドプロンプトでも、treeコマンドがつかえる。
sqlのミニTips

#はじめに
業務で見かけたsqlについて、「こんなのあるんだ」と感じた点、2つまとめてみました。

##1,Selectでしぼったデータを利用してjoinする

以下のテーブルを利用します

**userテーブル**

| user_id      |       user_name | 
|:-----------------|------------------:|
| 1            |              Aさん | 
| 2         |            Bさん | 
| 3           |              Cさん | 

**postテーブル**

| post_id     |post_user_id |    post_name    |
|:-----------------|:------------------|:------------------:|
| 1            |1  |      日記1      |
| 2           |2 |         日記2     |
| 3           |3|        日記3        |
| 4             | 1 |         日記4         |
| 5            |  |         日記5         |
| 6            | 1 |         日記6        |


上記のテーブルでAさんが投稿した数の合計値をだしたい場合以下のように書けます。
ここでは簡単な例でjoin後にcount関数を使うこともできますが、より複雑な条件で
データを取得したい場合には効果を発揮しそうな書き方だと思いました。

```
select *
from sample_user
 INNER JOIN (
			select post_user_id ,count(post_user_id ) as post_user_count
			from  sample_post
			where post_user_id = 1
			GROUP BY post_user_id 
		)post_one
		ON post_one.post_user_id = sample_user.user_id
```

**結果**

| user_id      |       user_name | post_user_id |post_user_count|
|:-----------------|------------------:|:------------------|:------------------|
| 1            |              Aさん |              1| 3| 


##2,Left Joinをすると重複する(ように見える)

以下のテーブルを利用します

**adminテーブル**

| admin_id|       name_sei|   name_mei| 
|:-----------------|------------------:|------------------:|
| 1            |              田中 | hoge|
| 2         |            山田 | huge|


**admin_categoryテーブル**

| admin_category_id   |admin_id | 
|:-----------------|:------------------|
| 1         |1  | 
| 2           |1 |
| 3           |1|


以下のsqlを流します。

```
SELECT	 ad.admin_id
		,ad.name_sei
		,ad.name_mei
		
FROM	admin ad
	LEFT JOIN admin_category adc
	ON adc.admin_id = ad.admin_id
```
**結果**

| admin_id|       name_sei|   name_mei| 
|:-----------------|------------------:|------------------:|
| 1            |              田中 | hoge|
| 1            |              田中 | hoge|
| 1            |              田中 | hoge|

紐づいたadmin_idでjoinすると重複してるように見えます。
admin_categoryのデータをselectしていないのが原因です。
重複して表示されるのが正しいシステムの場合は、そのままで大丈夫ですが
この情報をひとまとめにしたい場合は、以下のようにDISTINCTを付け足して書くと１つのデータとなります。

```
SELECT DISTINCT ad.admin_id
        ,ad.name_sei
        ,ad.name_mei

FROM    admin ad
    LEFT JOIN admin_category adc
    ON adc.admin_id = ad.admin_id
```




#終わりに
2つ紹介させていただきましたが、訂正点などあればご指摘いただけると幸いです。
left joinで複数なるケースがほかにもあった気がするのですが忘れました・・・ｗ
Siemens#S7-300 Block_DB使え方

まずF1でHelpを見てみます。

>You can only assign this data type for variables which you declare as Formal Parameters.
Using BLOCK_DB, you determine that a Data Block (DB) is to be transferred to the declared formal parameter as an Actual Parameter when the logic block is called.


Data Type Length Format (n = Block Number) Information Provided

BLOCK_DB 16 bits DB n Number of the data block

あなたがこのData Typeを使うには、変数をパラメータとして定義する必要があります。
つまりこのBLOCK_DBを使うことは、あなたがFunction Blockが呼び出すとき、DataBlock(DB)をそのままパラメータとして渡して於けば大丈夫です。

データタイプ：BLOCK_DB
長さ：16Bit

#バージョン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/21d6e537-5aa0-5635-ce7f-425fdd715f0f.png)
#実装
##DB1
これはパラメータとして渡すの”Datablock”です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/42171cd1-e3fe-43ca-5c42-9675bb18ce20.png)
##FB1
このFBはBlock_DBをInputパラメータとして定義し、そして間接的にDBのデバイスをアクセスします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/58987392-d0f4-613e-2e1b-eb5638f6b6a2.png)
##プログラム
OPN命令使ってパラメータとして渡された”BLOCK_DB”を開きます。
L DBNOでいま開いてるDB番号をもらってoutDBに出力します。
DBも開いてたから、そのままDBX1.0をアクセスすれば、開いたDBのDBX1.0を間接的アクセスすることが可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/7df720f5-6398-1173-70cd-dfdb96d6afea.png)
##OB1
先は間接的アクセスっていいましたね？もしここでinDBはここで別のDBを入れれば、たとえ（DB2）だったら、アクセスするものはDB2.DBX1.0になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/f57b3ff7-711d-8cef-d4fd-d3c8ee20b630.png)
それでお疲れ様ですー
Pyinstallerを使ってPythonコードから生成した実行ファイルについて、実行時エラーModuleNotFoundErrorを回避

# 記事の内容

Mac及びWindows10で、Pyinstallerを使ってPythonコードから生成した実行ファイルを動かしたら、ModuleNotFoundErrorが発生しました。それを回避した時の記録です。

## 手順

以下のように、Pyinstallerを使ってPythonコードから実行ファイルを生成しました。pipenvを使用しています。

```bash

pipenv run pyinstaller foo.py --onefile
```

実行ファイルがdistディレクトリ配下に生成されましたので、以下のように動かしました。

```bash

./dist/foo
```

実行時エラーが発生しました。
Macでのエラーメッセージ：

```
Traceback (most recent call last):
  File "site-packages/PyInstaller/loader/rthooks/pyi_rth_pkgres.py", line 13, in <module>
  File "/Users/username/.local/share/virtualenvs/foo_project-dA2KfCBr/lib/python3.7/site-packages/PyInstaller/loader/pyimod03_importers.py", line 623, in exec_module
    exec(bytecode, module.__dict__)
  File "site-packages/pkg_resources/__init__.py", line 86, in <module>
ModuleNotFoundError: No module named 'pkg_resources.py2_warn'
[5125] Failed to execute script pyi_rth_pkgres
```

Windowsでのエラーメッセージ：

```
Traceback (most recent call last):
  File "site-packages\PyInstaller\loader\rthooks\pyi_rth_pkgres.py", line 13, in <module>
  File "c:\users\username\.virtualenvs\foo_project-uuzswlzx\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 623, in exec_module
    exec(bytecode, module.__dict__)
  File "site-packages\pkg_resources\__init__.py", line 86, in <module>
ModuleNotFoundError: No module named 'pkg_resources.py2_warn'
[14256] Failed to execute script pyi_rth_pkgres
```

対処方法です。
まず、最初にpyinstallerを動かしたときに.specファイルも生成されていますので、それをテキストエディタで編集します。
ModuleNotFoundErrorと言われてしまったモジュールを、以下のようにhiddenimportsに書き加えます。

```foo.spec

# -*- mode: python ; coding: utf-8 -*-

block_cipher = None


a = Analysis(['foo.py'],
             pathex=['/Users/username/PycharmProjects/n/foo_project'],
             binaries=[],
             datas=[],
-              hiddenimports=[],
+              hiddenimports=['pkg_resources.py2_warn'],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='foo',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True )
```

以下のように、編集した.specファイルを使用して再びpyinstallerを起動します。

```
pipenv run pyinstaller foo.spec --onefile
```

実行ファイルが生成されましたので、以下のように動かしたら、うまく動きました。

```
./dist/foo
```

## エラーメッセージの意味（想像）

エラーメッセージ内に、以下の内容が含まれていました。

```
exec(bytecode, module.__dict__)
```

私の想像ですが、pyinstallerが生成した実行ファイルでは、人がpipenv installでインストールしたモジュールが、exec関数が動かすコードに引き継がれないのだと思います。
exec関数が動かすコード用に、モジュールを.specファイルのhiddenimportsに指定しておく必要があるのでしょう。
クリーンアーキテクチャの『依存関係逆転の原則』は、『モジュール依存関係逆転の原則』と表現したほうが自分には理解できたんだけどどうでしょうかという話

これはオピニオンであり私がクリーンアーキテクチャ本にあることを正しく理解できてないかもしれませんが書いておきます。もしかしたら私のように勘違いしている人が他にもいるかも知れないし、現時点でも私がまだ勘違いしているかもしれないです。

勉強会用のスライドとして作成していたので、一部画像があります。

# 言いたいこと

書籍「Clean Architecture 達人に学ぶソフトウェアの構造と設計」（以下CA本）が私にはわかりづらい

- 実際に強制力のあるモジュール分割していないのであれば、それは『依存関係逆転の原則(DIP)』じゃなくて『抽象に対してプログラミング』しているだけじゃない？
- 『モジュール依存関係逆転の原則』とか『コンポーネント依存関係逆転の原則』とかそういう表現であれば自分はしっくりくる
  - しっくりくるんだけど、クリーンアーキテクチャ本第5章図5-2はInteraface使ってるだけなのに『依存関係逆転』と表現している
      - この図が『DIP』なのか『DIPのための単なる手法』のことなのか紛らわしい
- CA本8章にはインタフェース使ってるけどDIPじゃない例がある（後述）

# 最初に私の中での結論

- 『抽象に対してプログラミングせよ』
  - 一般的な手法
      - Swiftならプロトコル
      - Javaならインタフェース
  - 内部実装を知らないようにプログラミングするだけ
- 『依存関係逆転の原則(DIP)』
  - モジュールの依存関係を逆転する手法
      - 一般的な手法 を利用する
      - 相互依存していれば単方向の依存にもできる

# 本題

## まず最初に、モジュールというものがない世界で、Swiftのプロトコルを使った例

![CA勉強会_クリーンアーキテクチャと iOSアプリ開発のためのVIPERと.008.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16400/31abce17-5710-9b64-13c9-c4d94d4dc33a.jpeg)


上の図単体ではモジュールもないのでDIPとは言い切れないと思う。

これはクリーンアーキテクチャ本第5章図5-2と同じで、「ソースコードの依存関係」と「制御の方向」は逆転している。でもこれや第5章図5-2のそれはDIPなのかな？違うんじゃないのかなーという話です。

## モジュールを用意して境界線をはっきりさせる

モジュールによって分割するものの、まずはプロトコルを使わずに次のように表現する

![CA勉強会_クリーンアーキテクチャと iOSアプリ開発のためのVIPERと.013.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16400/ac90742f-1197-655a-87ba-2caef2294a03.jpeg)

これはなんのこっちゃない、ただのモジュールA->Bの依存。
それをプロトコルをモジュールAに用意して表現すると次のようになる

![CA勉強会_クリーンアーキテクチャと iOSアプリ開発のためのVIPERと.014.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16400/7f02ec7c-1d5d-8aa9-e810-ededefe86d93.jpeg)

プロトコルを使わずに表現した図から逆転していることがはっきりわかる。つまり、これがDIPであって単に『抽象に対してプログラミングせよ』という手法とは区別したほうがスッキリする。

繰り返しになるけども、モジュールAにプロトコルがあるのであってBにはプロトコルはない。Bにプロトコルを用意してしまうと依存関係は逆転できない。

## 書籍から引用

### Interfaceを使ってるがDIPじゃない例

CA本の8章から引用する。
まず図8-2のControllerモジュール、Interactorモジュールに注目してほしい。

![f0802.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16400/e369432b-e678-749c-d254-37fb18534a8e.jpeg)

引用

> FinancialReportRequesterインターフェイスは、依存関係の逆転とは別の役割を担っている。このインターフェイスの役割は、FinancialReportControllerがInteractorの内部を知りすぎないように保護することである。このインターフェイスがなければ、Controllerは推移的にFinancialEntitiesに依存してしまう。

整理すると

- FinancialReportRequesterインタフェースはInteractor側にインタフェースがある
    - Controller側にない
        - ControllerはInteractorに依存している（つまり逆転させていない）
            - DIPしたいわけじゃなくInteractorの内部を知らないように保護しているだけ
                - データのFinancialEntitiesに依存しないようにしている
                    - データのFinancialReportResponseには依存して良しのスタンス

つまりこれはインタフェースを使った一般的な手法でありDIPではない。内部を保護して知らないようにするのは『依存関係逆転の原則（DIP）』にはあたらないんじゃないかな。

# 使わない言葉

説明が必要なので下記の言葉を使っていません

- 安定した具象
    - 何をもって安定というかはチームによる
- 上位のモジュール/下位のモジュール
    - 何が上で下かっていうのは物理的なモノではないので、その説明と納得が必要
Cordova+Xcode11対応でハマったこと

[2020年4月のXcode11必須化](https://developer.apple.com/news/?id=09102019a&1568158483)が迫ってきました。
[MonacaもXcode11に対応したので](https://press.monaca.io/takuya/4648)、いよいよ対応を進めているのですが、ハマって点をまとめます。
他に何かあったら随時追記します！

**2020/3/27追記**
4/30から対応が必要でしたが、既存アプリの更新は6/30に延期するとのことです。
https://developer.apple.com/news/?id=03262020b

## Bluetoothの権限対応

iBeaconなどでBluetoothを使用している場合、ユーザーにBluetoothのアクセス許可を得る必要がある。
NSBluetoothAlwaysUsageDescriptionを追加する。

config.xmlに以下を追加。

```xml
<edit-config target="NSBluetoothAlwaysUsageDescription" file="*-Info.plist" mode="merge">
    <string>Bluetoothの利用目的</string>
</edit-config>
```

## ダークモード仮対応

何もしないと、ダークモード時に自動で一部のスタイルが変わってしまう（例えば、ダークモード時にステータスバーのテキストが白になる、など）
とりあえず、Lightモードに固定する方法で回避する。

config.xmlに以下を追加。

```xml
<edit-config file="*-Info.plist" mode="merge" target="UIUserInterfaceStyle">
    <string>Light</string>
</edit-config>
<edit-config file="*-Info.plist" mode="merge" target="UIViewControllerBasedStatusBarAppearance">
    <true/>
</edit-config>
```

ちなみに、本格的に対応する場合は、以下の記事が参考になります。
https://qiita.com/kishisuke/items/e1fecb20d35693680421

## デバイストークンの取得方法変更
https://qiita.com/naofumi_okano/items/6c983959ec2b3a4c8af5

phonegap-plugin-pushで同様の問題があり、2.3.0で修正された。
2.3.0にバージョンアップする。

## モーダルの仕様変更
https://qiita.com/yh_genephia/items/b82d4df36b4ef1fdcdd8

モーダルで表示する画面によって対応するかしないか決める。
とりあえず現状通りであれば、`modalPresentationStyle`に`UIModalPresentationFullScreen`を設定する。

個人的には、以下の基準が良いかと。

- `UIModalPresentationAutomatic`(デフォルト): 参照のみや簡単な入力画面
- `UIModalPresentationFullScreen`: 複雑な入力画面やユーザーが没頭して操作する画面
Qiitaに25記事ぐらい投稿してわかったこと

この記事はこのアカウントでQiitaに投稿する26個目の記事です。

25記事ぐらい投稿してわかったことがあるのでまとめておきます。

- どんな記事でも100回は見られる。
- タイトルに人気の言語とかだと200回は見られる。
- qiita.comのSEOはめちゃくちゃ強いので、どんなクソ記事でもすぐにGoogle検索で上位になる。
- タグをつけることは重要。
ProtoPieでFigmaのフレームをインポートしたら崩れてしまった

FigmaからProtoPieにデータをインポートした際に、一部崩れてしまった部分があったので
どうにかこうにかしたメモ。

## 崩れるとは
<img width="1436" alt="スクリーンショット 2020-01-18 18.41.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325419/4440de48-23f7-8ee8-93a9-73f3e92414ae.png">
こんな感じの円グラフのようなものをFigmaで作ったとする。
（下に三つ並んでいるのは円グラフを構成しているパーツをバラしたもの）
これをProtoPieでインポートすると、
<img width="1440" alt="スクリーンショット 2020-01-18 18.43.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325419/ff8166af-d01f-93f6-f95a-7b999eb01ea4.png">
こんな感じになってしまった。

ここでは例示のために単純な円グラフだけにしているが、実際はFigmaで綺麗に出来上がっているプロトタイプをProtoPieに移している作業中に、一部の円グラフだけが崩れていた。

## 解決方法
なんで崩れるの？？と思っていたら、ちゃんとヘルプに書いてあった。
https://www.protopie.io/support/#figma-layers-imported-incorrectly
回転させたレイヤーがある場合、FigmaのAPIの都合で、正常にインポートできない場合がありますよ、と。
心当たりがありすぎる。
↑のリンクに書いてあることは概ねやっていたが、唯一Exportにチェックをつけていなかったと思って試しにやってみた。
<img width="232" alt="スクリーンショット 2020-01-20 13.20.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325419/7ba6e113-e6ac-653a-e242-f9a6300a179b.png">
Exportにチェックをつけるって、書き出したいレイヤーを選択して、左下のExportの+ボタンをクリックするということでいいのかしら。

そして、ProtoPieでインポートするときに
<img width="388" alt="スクリーンショット 2020-01-20 13.15.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325419/4d915772-f04e-c446-1462-e92b095fd09b.png">
「書き出しとしてマークされたレイヤーだけ」を選択する。
そしたら
<img width="242" alt="スクリーンショット 2020-01-20 13.22.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325419/b817241d-fe72-1f61-32a6-d0f252ca4789.png">
できた。

## 邪道（？）なやり方
上のやり方に気付く前に、崩れるなら画像にしてしまえばいいのでは？と思ってやった方法。

<img width="228" alt="スクリーンショット 2020-01-18 18.45.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325419/c5d1c283-8d23-665c-1bfa-26e1fc31593b.png">
崩れてしまう図形を画像として書き出す。
そしてそれをFigmaのフレームに載せてProtoPieでインポートする。
画像なので、当然だが崩れない。
上ではpngで書き出しているが、svgの方が綺麗に仕上がる。
<img width="326" alt="スクリーンショット 2020-01-18 18.47.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325419/c981a328-6e28-e889-d6d6-2ec82617da72.png">

Figmaのレイヤーが整理されていていれば上のやり方がベストだと思う。
が、レイヤーがカオスなことになっている、とりあえず急いでいるので欲しいフレームだけとにかくインポートできればいい、程度なら画像にしてしまうのも一つの方法なのかな・・・
Amplifyとは何者なのか


## AWS Amplify とは
> セキュアでスケーラブルなモバイルアプリケーションとウェブアプリケーションを構築するための開発プラットフォーム
https://aws.amazon.com/jp/amplify/?nc2=h_ql_prod_mo_awsa

AWS Amplifyを使うことで、モバイル／Webアプリが利用する、AWS上のサーバーレスなバックエンドリソースを簡単に構築できます。


例えば以下のような機能を持つサーバーレスアプリケーションを簡単に構築することができます。

- データストア
- 認証
- 分析
- API
- ストレージ

などなど ( [詳細](https://aws.amazon.com/jp/amplify/features/) )

イメージ図としてはこうなると思います。
![amplify.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45528/68e6fbe0-c359-afcb-6b8c-f2a38109c0e1.png)



## AWS Amplify を構成するサービス
AWS Amplifyには、ライブラリ、CLI、コンソール、などといったさまざまなサービスが含まれています。

- [Amplify Framework](https://aws-amplify.github.io/)
    - ライブラリ
        - ライブラリを使用して、AWSの機能を活用するモバイル、Webアプリを構築できる
    - CLI
        - コマンドラインから、アプリが使用するAWS上のサーバーレスなバックエンドを構築することができる
        - `$ amplify add api` などのコマンドを利用してやりたいこと(apiの追加)を対話的に構築できる
- [Amplify Console](https://aws.amazon.com/jp/amplify/console/)
    - Webアプリケーションのホスティングを行える
    - 静的サイトのホスティングだけであればGithubを連携するだけ
    - サーバーレスなバックエンドもデプロイできる

 
### 参考

- https://aws.amazon.com/jp/amplify/?nc2=h_ql_prod_mo_awsa
- https://aws-amplify.github.io/ 
- https://qiita.com/kimyan/items/2d364c66abfdb751781a
nodeのバージョンが古く、npmがアップデートできない(バージョン管理:nodebrewとanyenv)

# はじめに
### 概要
Webサイト作るお仕事をしている方向けの内容です。

- gulpを使用してフロントエンドの環境構築
- バージョン管理はnodebrewとanyenv
- 既にgulpを使用している

(nodebrewとanyenvに関しては後々記事を書いていこうと思います。)

# 出来事

gulpを使用したかったので、他の記事にもあるように

① Node.js
② npm
③ gulp

の順番で確認しました。
今回は私が普段からgulpを使用しているので、ダウンロードではなく**バージョンを確認してgulpを導入**する。という方向から進めました。
(もしバージョンが古ければ適宜アップデートする必要がある)

### nodeバージョン確認

まず、ターミナルから、Node.jsのバージョンを確認します。

```node.js
node -v
```
結果

```node.js
v9.2.0
```

nodeのバージョンが、9.2.0であることがわかりました。
(当時の最新バージョンは13.6.0、推奨バージョンは12.14.1なので若干古いことが分かります。)

### npmのバージョンの確認
```
npm -v
```
結果

```npm
EROOR: npm is known not to run on Node.js v9.2.0
Node.js is 9 is supported but the specific version you're running has
a bug known to break npm.Please update to at least 9.0.0 to use this version of npm.You can find the latest release of Node.js at https://node.js.org/
```

はい、エラーが出ました。

##エラー内容

なんとなくの翻訳
→npmはNode.jsの9.2.0で実行されない
→Node.jsは9がサポートされているが、実行している特定のバージョンにはnpmを壊すバグがあるよ(?)
→最低9.0.0のバージョンにアップデートしてください

先程調べたように、現在のnodeのバージョンは9.2.0
けど、このエラーは最低9.0.0のバージョンにアップデートして欲しいらしい。謎。



### 試した事

色々コマンドを試しました。

(例)

```
nodebrew ls-remote  ・・・nodebrewで使用可能なnodeのバージョンの確認
nodebrew install-binary {バージョン}  ・・・nodebrewを使用してnodeのアップデート
sudo npm install -g npm   ・・・npmのアップデート
```

他にも沢山。
どれもダメでした。


そして最終的に行き着いた、解決できそうな方法が2つ。

#### 選択肢

- 選択肢 1
    - このまましつこくトライする(nodeのアップデートを続けてみる)
- 選択肢 2
    - 一度nodeを消して、再ダウンロード


↓

選んだのは、**選択肢 1** の、しつこくトライ。

####理由

node.jsのバージョン管理をnodebrewとanyenvで行なっており、まだ詳しく理解していないので、更なるエラーが出るのが怖かったから。


# 解決した方法

```
nodenv install -l  ・・・インストール可能なバージョンのリストを確認
```

結果

```
12.8.1
12.9.0
12.9.1
12.10.0
12.11.0
12.11.1
12.12.0
12.13.0
12.13.1
13.0.0
13.0.1
13.1.0
13.2.0
chakracore-dev
chakracore-nightly
chakracore-8.1.2
chakracore-8.1.4
chakracore-8.2.1
chakracore-8.3.0　　・・・・・・
```

たくさん出てきます。

自分が今欲しいと思っているバージョンをインストールしよう。

```
nodenv install {バージョン}
```

↓ 私は当時の推奨版をインストールしました。

```
nodenv install 12.13.0
```

過去に複数のバージョンをインストールしてきていると思うので、
以下のコマンドでインストール済みのバージョンを確認してみます。

```
nodenv whence npm
```

結果

```
8.10.0
9.2.0
10.9.0
12.13.0
```

コンピュータのデフォルトのバージョンを指定します。
指定できるのはインストールしたバージョンなので、

```
nodenv global 12.13.0
```

再度、nodeのバージョンを確認してみました。

```
node -v
v12.13.0
```

nodeのアップデートが終わったところで、npmのエラーがどうなったのか確認しました。
なんと消えていました。

nodeとnpmのアップデートが無事終わったと言う事で一件落着。
# さいごに

"自分のPCの開発環境を知ってるのは自分だけだからね"
と、エンジニア歴十数年のベテランインフラエンジニアの友人に言われた事を思い出しました。
ひとつひとつの原理原則を、きちんと理解して進めないといけないなぁと思うばかり。


# 参考サイト
・MacにNode.jsをインストール（anyenv + nodenv編）
https://qiita.com/kyosuke5_20/items/eece817eb283fc9d214f
ReduxにおけるImmutableの概念についてまとめてみた

### はじめに
ReactやReduxを触っていると、多くの人は、Immutable、mutableというワードを耳にするのではないでしょうか。もちろんこれらは他の言語やフレームワークを使用するにあたっても重要とは思いますが、React、Reduxで開発するにあたってはとりわけ重要な概念です。実際、Reduxのstyleガイドで挙げられているReduxによるコーディングの原則の一番初めにデカデカと書かれているのが、mutableにデータを変更してはならないという指摘です。それくらい重要な概念であるImmutableですが、ちょっと理解が難しく、また理解しなくても一通り開発が進めらてしまうため（もちろんそのうち壁にぶち当たりますが）、言われてもあまりピンとこないのではないでしょうか？（筆者自身もそうでした）。この記事では、その概念について、利点や、実際のコーディング例も交えながらわかりやすく解説していきたいと思います。これを最後まで読めば、あなたもImmutableについての理解が深まると思います。

### Immutableコーディングの利点
Immutableなコーディングには複数のメリットがあります。
1. シンプルで可読性の高いコーディングが可能になる
2. デバックしやすい
3. **React等のDOM動作のフレームワークが正確に動作する**

### なぜReduxにおいてImmutableなコーディングが必要なのか
- **Redux、React-Reduxはともにshallow equality checkingを採用しています。ReduxのcombineReducersでは、そのcombineReducersが呼び出したreducerの変化をshallow checkingしている。React-Reduxのconnectメソッドでは、RootStateの変化をshallow checkingして、コンポーネントが再renderされるかを判別しています。**
- Immutableなコーディングでは、より安全にデータを扱うことができるようになります。
- 副作用のない関数によってreducerが定義されることにより、デバックの際、別個のstate間を正しく追跡することが可能になります。

### そもそもshallow equality checkingとは？deep equality checkingとの違い
**shallow equality checking** => ２つの異なる変数が同じ参照元（データの保存先のメモリの番地）かどうかをみているのみです。そのため、実際のデータの中身のみが変化しても、そのデータの参照元が同じである場合、変更が検知されません。
**deep equality checking** => 2つの異なる変数の実際のデータの値が同一のものであるかどうかをみています。

Reduxでは、そのパフォーマンスの向上の理由上から**shallow equality checking**が採用されています。 

#### 具体例1
Reduxのstateを変更する際。
悪いコード例）

```javascript
const exampleReducer = reducerWithInitailState(initialState)
    .case(actions.exampleAction, (state, payload) => (
        state.push(payload)
    ))

```
良いコード例)

```javascript
const exampleReducer = reducerWithInitailState(initialState)
    .case(actions.exampleAction, (state, payload) => (
        state.concat(payload)
    ))

```

上記の2つの例の違いは、元のstate（ここでは配列を想定）にどのように引数を追加しているかという点です。1つ目の例で使われているpushメソッドは、配列に対して要素を追加する際、元の配列を直接書き換えて、変更します。そのため、その配列の参照元（データの保存先のメモリの番地）が変わることはありません。
一方で、2つ目の例にあるconcatメソッドは、元の配列に影響を与えず、結合された新たなオブジェクトを生み出します。そのため、元の配列を複製した上で新たな配列（結合された新しい配列）を生成するため、元のstateの配列と新しい配列ではその参照元が異なります。
​
#### 具体例2
悪いコード例)

```typescript
const initialstate = {
    name: "Rui",
    age: 22,
    address: "多摩"
}
const exampleReducer = reducerWithInitialState(initialState)
    .case(action.exampleAction, (state, payload) => (
      state.address = "六本木"
    ))
```
良いコード例)

```typescript
const initialstate = {
    name: "Rui",
    age: 22,
    address: "多摩"
}
const exampleReducer = reducerWithInitialState(initialState)
    .case(action.exampleAction, (state, payload) => (
       ...state,
       address: "六本木"
    ))

```
悪いコード例では、stateのaddressを直接書き換えていますが、良いコード例では、stateを一度複製し、複製したstateに対して変更を加えているため変更前のstateが書き換わっていません。

### おわりに
ReduxおよびReact-Reduxにおいては、shallow equality checkingが採用されているためstate等のデータを直接書き換えるようなImmutableでないコーディングを行ってしまうと、その変更が検知されず、stateの変更があったにも関わらず、componentが正しく再renderされないなどの事態が生じる恐れがあります。また、はじめの方でも書いたように、Immutableなコーディングはデバックの際にもたいへん有効ですし、コード全体の可読性も上がるため、チーム開発の際にもとてもメリットがあります。気にかけていないと、ついうっかりmutableなコーディングをしてしまいがちなので、ぜひ注意してくださいね！ Reduxの公式FAQ（下にもリンクを貼っておきます）はかなり詳細にこの概念について書かれていて、とても勉強ななるので、ぜひ一読してみてください。

###### 参考にしたサイト
- [Redux公式FAQ](https://redux.js.org/faq/immutable-data)
特定のS3 バケットだけにアクセスするポリシーを30秒で書く

# 色々調べたのだけど、とにかくパターンが多すぎて怖い

ので、一番簡素で強力と思えたパターンだけ書きます。
(違ってたらぜひご指摘ください！)

hogehoge.comを置き換えてご利用下さい。
(ここではcloudfrontでスタティックページを配信してるユースケースを想定しています)


```s3-singlebucket-policy.json
# テンプレ
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::hogehoge.com",
                "arn:aws:s3:::hogehoge.com/*"
            ]
        },
        {
            "Effect": "Deny",
            "NotAction": "s3:*",
            "NotResource": [
                "arn:aws:s3:::hogehoge.com",
                "arn:aws:s3:::hogehoge.com/*"
            ]
        }
    ]
}
```

# 使うのは「iamユーザー」
いろんな設定の仕方があるかと思いますが、僕は上記ポリシーを作成後、
そのポリシーを適用したユーザーをバケットごとに作成しています。
（プラグマティックアクセスを有効に・ManagementコンソールはOFF）




# Cyderduck や Transmit で使う時
「指定バケットをデフォルトパス」に指定しないとエラーになります。(デフォルトはバケット全体をListしようとするため)
CyberDuckだと「QuickConnect」にそのオプションが無いのだけ軽くハマりました。
普通に「新規作成」から詳細設定を指定してあげればOK！

Transmit:
<img width="1233" alt="screeenshot 2020-01-20 at 13.09.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255842/977a6c2e-bbd0-5400-d6fd-c2ab1adb3e48.png">

CyberDuck:
<img width="522" alt="screeenshot 2020-01-20 at 13.08.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255842/aff27c91-9f14-8622-0e77-10205ec813c4.png">



# より詳しくは
https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_s3_deny-except-bucket.html

# セキュリティ的なベストプラクティスなのか？
これで僕が求めていた事は実現(作業者ごとに個別のバケットアクセスを管理 - 管理者のみ複数バケットにアクセス可)出来ているのですが、
AWS勉強中の身ですのでこれで完全かはわかりません。
具体的には「ポリシー・Deny」を上回る権限設定が出来るか、これから調べたいと思います。

「S3全員見えちゃう運用」からのステップアップとしては上記でも充分有効、程度にお読み頂ければ。
【どのように成長すれば良いのか、ヒントを貰えた】一生成長し続けられるエンジニアになる方法 参加ふりかえり #teambox

「成長」は、すべてのエンジニアにとって大事なテーマだと思います。
参加の振り返りをしていきます。

イベント情報、発表資料はこちらから確認できます↓
https://teambox.connpass.com/event/160981/

## 良かったこと
### 成長するための具体的な方法論を提示してもらえたこと

具体的には、以下の２つです。

- 「アウトプットして、ふりかえって、改善計画をして、行動を変化させる」を繰り返す。
- 時々、全体を見直してより良い仕組みに変化させる。

言葉にすると単純ですが、改めて「なるほど」と思います。
スクラム開発も同じプロセスになりますね。

### マネジメントの具体的な知見を得られたこと
冒頭、「なぜリーダーになると人は成長するのか」について、中竹さんが「**人前で自分の考えを喋る機会が増えるからだ**」と言いました。

なぜなら、考えを言葉にすることは、要するに決断をするということだからです。

決断力が鍛えられれば、行動の質が向上するでしょう。アウトプットが大事な理由も、ここにある気がしました。

また、中竹さんは怒らないマネジメントを大事にされているそうです。

しかし、選手がコーチにただ反発して自分の指示に従わない場合、怒らないといけないときもあります。そんなときどうしたのでしょう？

「たしかに俺はダメなコーチだ。ただ、お前の態度はどうだった？ただ愚痴るだけだったよな。他責だよな。それが世界で勝とうとする者のやることか？」と言ったそうです。

自分の意見を押し付けるのではなく、事実を指摘して相手に考えさせたのです。見事だと思いました。

### テクノロジーで成長を支援するための仕組みがわかった
本イベントの主催である株式会社チームボックスでは、ヒトの成長を支援するサービスを展開しています。

実際の1on1の様子を動画に撮り、サービスの履歴データと連携して、その人のモチベーションがどう変化したかを計測する取り組みを行っています。

具体的には、モチベーションが低下するような行動をしたら、システムがアラートを出して行動改善を呼びかける仕組みを作っているそうです。

しかし、システムが機械的に出したアラートをヒトが素直に受け取れないことが課題のようです。

たとえば、「いや、私はモチベーションなんて下がってない。機械が故障してるんだ！」といった感じです。

## 思ったこと
スポーツの選手育成が、エンジニアの成長にどう関わるのか懸念でしたが、払拭されました。

スポーツは人がやること。個人的なパフォーマンスに大きく依存します。仕事も同じだし、エンジニアリングだって、個人のパフォーマンスが悪かったら機能しないですよね。

私はずっと現場で働いてきたので、現場が機能することの大切さも分かりますし、個人のパフォーマンスを発揮できるように支援をしないと仕事の満足度も上がらないと思います。

人間的な活動に目を向けるのは勉強になりました。

また、この勉強会は発表者から頻繁に質問がされ、参加者同士でディスカッションする形で終始進められました。当事者意識が高まるので、この形式の勉強会はとても有意義ですね。

## 改善行動

- 勉強会に行くときは、ワークショップ形式の勉強会に行く、または登壇する
- フィードバックを与えるときは、相手の行動をフィードバックする。
- ポモドーロテクニックを使ってふりかえりを行う。ポモドーロが終了した単位で振り返りを行う
何でも言うことを聞いてくれるアカネチャン

# 聞いてよアカネチャン！
[俺] 良いこと思いつきました！
[ア] なんや？
[俺] 俺， アカネチャンの列挙型をつくります！
[ア] あ ほ く さ
[俺] ...
[俺] ええええええええええええええええええ(ry

※[元ネタはこちら](https://www.youtube.com/watch?v=OVuYIMa5XBw) - 何でも言うことを聞いてくれるアカネチャン

# キッカケは友人との会話
その場のノリで話してただけなので，詳しい経緯なんてものは覚えていません．

とりあえず『何でも言うことを聞いてくれるアカネチャンの返事はboolean型みたい』みたいな話をしたんだと思います．

理想は

```java
if (Seyana) {
    System.out.println("True!!")
}
```

ですが，Seyanaをboolean型の代わりとして直接使うことはできないので，できる範囲でやってみました．お遊びです，何のメリットもありません．

# 作るよアカネチャン！
## アカネチャンのセリフ
アカネチャンのセリフは採用したもの以外は受け付けたくないので，列挙型(enum)にしてします．また，各セリフにboolean型を紐づけたいので，それも決めます．結果以下のようになりました．

- あほくさ(false)
- あれな(true)
- ええで(true)
- ええんちゃう?(true)
- ほんま(true)
- 知らんがな(false)
- 知らんけど(false)
- それな(true)
- そやな(true)
- わかる(true)

無理やりtrue/falseを決めた部分もありますが，まぁ良いでしょう．

## 実装
AkaneChan列挙型をつくります．この中に先ほどのセリフを入れ込みます．このとき，列挙型にもprivateなコンストラクタを持たせることで，インスタンスに固有の値を持たせることができるので，それを使いboolean型を紐付けます．また，せっかくなので日本語と英語それぞれの文章も紐づけておきます．

例として「あほくさ」と「あれな」を実装すると以下のようになります．

```java
public enum AkaneChan {
    Ahokusa(false, "Sounds stupid.", "あほくさ"),
    Arena(true, "Exactly...", "あれな"),
    ;

    private boolean agree;
    private String meaning_en;
    private String meaning_jp;

    private AkaneChan(boolean agree, String meaning_en, String meaning_jp) {
    this.agree = agree;
    this.meaning_en = meaning_en;
    this.meaning_jp = meaning_jp;
}
}
```

あとは，

- `isAgree()` -- agreeをreturnするメソッド
- `getMeaning_en()` -- meaning_en(英語の意味)をreturnするメソッド
- `getMeaning_jp()` -- meaning_jp(日本語の意味)をreturnするメソッド

を作ってあげれば完成です．

# 使うよアカネチャン！

とてもシンプルです．理想は〜の部分に書いたif文を再現します．

```java
if (AkaneChan.Seyana.isAgree()) {
    System.out.println("True!!");
} else {
    // 呼ばれることはない
    System.out.println("False!!");
}
```

# 結論

[俺] **いらねぇよ！アカネチャン！！**
[ア] せやなーそやなー知らんけどー(棒)

# あとがき
先ほど実装したメソッドに加えて，`ListenUpAkaneChan`メソッドを追加したAkaneChan列挙型と，いくつかの無駄なものをセットにしてGithubに公開しています．
<div id="dummy"></div>
~~[Github - YabPaseri/AKANE-CHAN](#dummy)~~
2021/08/01更新: GitのPublicリポジトリ整理に伴い、削除しました。
<br/>

Java8環境で作ってますが，固有の何かを使っているわけではないので，問題なく使えるかと思います．

/build のなかに，jarファイル化したアカネチャンや，実際にアカネチャンを使っているプログラム`SampleAkaneChan.java`も入っているので，よろしければ...使わないか(笑)
[Rust/Python] 周期境界条件

実数 $\mathbb{R}$ に周期 $b > 0$ の周期境界条件を課す ($\mathbb{R} / b \mathbb{R}$) ことを考えます. つまり, ふたつの数 $x$ と $x+b$ を同一視します. このとき任意の数 $x \in \mathbb{R}$ に対応する座標の一意的な表現として
* $0 \leq x < b$
* $-\frac{b}{2} \leq x < \frac{b}{2}$
という二通りの表現方法が可能です. 本記事では任意の実数 $x$ が与えられたときにこれらの制約を満足する値へと変換するコードを確認します. 


# Rust 実装

コード全体と動作確認はこちら: [PlayGround](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=extern%20crate%20rand%3B%20%2F%2F%200.7.3%0Ause%20rand%3A%3A%7BRng%2C%20thread_rng%7D%3B%0A%0Afn%20main()%20%7B%0A%20%20%20%20let%20mut%20rng%20%3D%20thread_rng()%3B%0A%20%20%20%20let%20b%20%3D%201.57%3B%0A%20%20%20%20%0A%20%20%20%20for%20_%20in%200..128%20%7B%0A%20%20%20%20%20%20%20%20let%20x%20%3D%20rng.gen_range(-6.%2C%206.)%3B%0A%20%20%20%20%20%20%20%20if%20!check1(x%2C%20b)%20%7B%20println!(%221%3A%20pbc(%7B%3A.03%7D)%20%3D%20%7B%7D%22%2C%20x%2C%20pbc1(x%2C%20b))%3B%20%7D%3B%0A%20%20%20%20%20%20%20%20if%20!check2(x%2C%20b)%20%7B%20println!(%222%3A%20pbc(%7B%3A.03%7D)%20%3D%20%7B%7D%22%2C%20x%2C%20pbc2(x%2C%20b))%3B%20%7D%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%0A%23%5Binline%5D%0Afn%20pbc1(x%3A%20f64%2C%20b%3A%20f64)%20-%3E%20f64%20%7B%0A%20%20%20%20let%20dx%20%3D%20x%25b%3B%0A%20%20%20%20if%20dx%20%3E%3D%200.%20%7B%20dx%20%7D%20else%20%7B%20dx%20%2B%20b%20%7D%0A%7D%0A%0A%23%5Binline%5D%0Afn%20pbc2(x%3A%20f64%2C%20b%3A%20f64)%20-%3E%20f64%20%7B%0A%20%20%20%20x%20-%20(x%2Fb%20%2B%200.5).floor()*b%0A%7D%0A%0A%0A%23%5Binline%5D%0Afn%20check1(x%3A%20f64%2C%20b%3A%20f64)%20-%3E%20bool%20%7B%0A%20%20%20%20let%20x%20%3D%20pbc1(x%2C%20b)%3B%0A%20%20%20%20%0A%20%20%20%20(%20x%20%3E%3D%200.%20)%26(%20x%20%3C%20b%20)%0A%7D%0A%0A%23%5Binline%5D%0Afn%20check2(x%3A%20f64%2C%20b%3A%20f64)%20-%3E%20bool%20%7B%0A%20%20%20%20let%20x%20%3D%20pbc2(x%2C%20b)%3B%0A%20%20%20%20%0A%20%20%20%20(%20x%20%3E%3D%20-b%2F2.%20)%26(%20x%20%3C%20b%2F2.%20)%0A%7D%0A%0A)

## 0 ≦ x < b

Rust では剰余 `x%b` は `x` と同符号になります. 従って `x` が正ならば `x%b` でよいのですが, そうでなければ `b` を足す必要があります.

```rust
#[inline]
fn pbc1(x: f64, b: f64) -> f64 {
    let dx = x%b;
    if dx >= 0. { dx } else { dx + b }
}
```

最初 `f64::is_sign_negative` を使っていたのですが, `-0.0` の扱いで困った結果, 不等号を使うべきだという結論に到達しました. 

## -b/2 ≦ x < b/2

この場合 `(x/b + 0.5).floor()` を計算すると `x` を欲しい区間に移動するために何回 `b` で動かせばよいのかがわかります.

```rust
#[inline]
fn pbc2(x: f64, b: f64) -> f64 {
    x - (x/b + 0.5).floor()*b
}
```


# Python 実装

以下のコードは入力 `x` が float でも `np.ndarray` でも使えます. 動作確認はこちら: [Paiza](https://paiza.io/projects/-e-prSzVswvC81hxFEM5cA?locale=ja-jp)

## 0 ≦ x < b

Python では剰余は $0 \leq x\%b < b$ を満たすようになっている (いま $b > 0$ としています) ので一発です.

```python
def pbc1(x, b):
    return x%b
```

## -b/2 ≦ x < b/2

これは上の Rust 実装をそのまま Python に書き換えるだけです.

```python
def pbc2(x, b):
    return x - np.floor(x/b + 0.5)*b
```
Swift で 画像 (UIImage ) の リサイズ と トリミング (切り抜き) を一度の処理で行う。

# ０．はじめに

Swift で画像の切り抜きとリサイズを一度の処理で行いたかったので、やってみました。

以下の記事を参考にさせて頂きました。

* [UIImageのリサイズ方法と注意点 \- Qiita](https://qiita.com/ruwatana/items/473c1fb6fc889215fca3)
* [【Swift4】UIImageで画像のサイズ変更、指定した倍率で拡大/縮小 \- Qiita](https://qiita.com/zlq4863947/items/4b016824cf152bc2a769)
* [Swift3\.0で画像の切り抜き \- Qiita](https://qiita.com/takabosoft/items/391b7593f0b9ef7d77a5)
* [\[Swift\] 画像のサムネイル生成（縮小＆切り抜き） \- Qiita](https://qiita.com/taku/items/fb44d0bf10509d977bc0)

感謝 ♪♪♪

🙇‍♂️🙇‍♂️🙇‍♂️

# １．コード

今回は、画像を 0.5 倍にリサイズしつつ、中心部分を正方形に切り抜いてみました。

```swift
    var _image: UIImage = image
    var compress: CGFloat = 0.5
    var oneside: CGFloat = _image.size.width < _image.size.height ? _image.size.width : _image.size.height
    let origin: CGPoint = _image.size.width < _image.size.height
        ? CGPoint(x: 0.0, y: (_image.size.width - _image.size.height) * 0.5 * compress)
        : CGPoint(x: (_image.size.height - _image.size.width) * 0.5 * compress, y: 0.0)
    UIGraphicsBeginImageContextWithOptions(CGSize(width: oneside * compress, height: oneside * compress), false, 0.0)
    _image.draw(in: CGRect(origin: origin, size: CGSize(width: _image.size.width * compress, height: _image.size.height * compress)))
    _image = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
```

##### ■ リサイズ

まず、以下の処理で、出力先のサイズを指定します。

```swift
    var oneside: CGFloat = _image.size.width < _image.size.height ? _image.size.width : _image.size.height
    UIGraphicsBeginImageContextWithOptions(CGSize(width: oneside * compress, height: oneside * compress), false, 0.0)
```

##### ■ トリミング (切り抜き)

そして、以下の処理で、画像をトリミング (切り抜き) します。

```swift
    let origin: CGPoint = _image.size.width < _image.size.height
        ? CGPoint(x: 0.0, y: (_image.size.width - _image.size.height) * 0.5 * compress)
        : CGPoint(x: (_image.size.height - _image.size.width) * 0.5 * compress, y: 0.0)
    _image.draw(in: CGRect(origin: origin, size: CGSize(width: _image.size.width * compress, height: _image.size.height * compress)))
```

重要なポイントは、

<b><font color="red"> draw 関数の引数に指定する CGRect の値 (origin も、size も) を出力後の値で設定する</font></b>

こと。

# ９９．ハマりポイント

* 上述しましたが、draw 関数の引数に指定に結構手間取りました…。

😭😭😭

# ＸＸ．まとめ

以上、ご参考になれば ♪♪♪

👋👋👋
TypeScriptでthree.jsのexampleを使う(2年ぶり2回目)

[こちら(TypeScriptとwebpackとthree.jsでexamplesを使う)](https://qiita.com/kojiro_ueda/items/28c96ed0536c7469765b)の記事をたまにみていただいているのですが、最近試したら、もっと簡単になっていたので、おしらせします。

TypeScriptでthree.jsのexampleに入っているモジュールを利用したいという話です。
型補完が効き、しかもわかりやすくなっていました。

# やりかた

```typescript
import THREE from "three";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";

const loader = new OBJLoader();
```

`examples`の下に`js`と`jsm`というフォルダが生えていて、いい感じにjsのモジュールとして実装されているのが`jsm`フォルダのほうになります。

以上です。よろしくお願いいたします。
Excelマクロでプリンタのプロパティを変更するには

オフィスで使われるプリンタは、ランニングコスト削減を理由に、白黒印刷がデフォルトに設定されていることが多い。（白黒とカラーでは料金がざっくり言って10倍違うので）
Excelマクロ（VBA）を使って、**白黒印刷がデフォルトのプリンタ**でカラー印刷できるか？と後輩君に聞かれたので、ちょっと調べてみた。

なお、**カラー印刷がデフォルトのプリンタ**に白黒で印刷したいなら、Excelのページ設定にあるので、当然マクロから制御可能だ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236222/ae6e47df-99d3-ac41-9280-4106346508e9.png)

```vb
object.PageSetup.BlackAndWhite = True
```

という具合。でもこれってExcel側で色を落としているだけなので、カウンター料金の契約だとしっかりカラー単価で請求されそうな気がするのだが実際どうなのだろう・・・？

# 方法
やり方は色々あるので、ひとつずつ解説していこう。

なお、プリンタのプロパティが変更できないポリシー設定の現場では、当たり前だが、以下に述べる方法は実現できない。システム管理者に相談しよう。

## WindowsAPI を使う方法
**Win32API**を使ってプリンタドライバの情報をDEVMODE構造体で取得し、`dmColor`に`DMCOLOR_COLOR`、`dmFields`に`DM_COLOR`をセットする方法。
でも、今どきVBAからWin32APIを直で叩くのは時代錯誤も甚だしいし、コード量が増えて面倒くさいだけなので試してもいない。

## PowerShell の Set-PrintConfiguration を使う方法
かつてWin32APIに頼っていた機能の殆どは**WMI**に抽象化され簡単に実現できるようになった。そしてWMIは**WSH**というスクリプト言語で扱うことが多かったが、今のWindowsスクリプティング環境は、より洗練された**PowerShell**へと移行している。PowerShellからWMIの`Win32_Printer`／`Win32_PrinterConfiguration`クラスを呼び出すとプリンタのプロパティを変更できそうだが、PowerShellの`Set-PrintConfiguration`コマンドレットなら、さらにシンプルに書けそうなので、そちらを試してみた。

VBAからPowerShellのコードを実行するには`WScript.Shell`を経由する。

```vb
CreateObject("WScript.Shell").Run "PowerShell -ExecutionPolicy RemoteSigned -Command Set-PrintConfiguration -PrinterName 'プリンタ名' -Color $True", 0
```

一応、期待する動きになったが、マクロウイルスと判定されてしまった。
[マイクロソフトサポートサイトの手順](https://support.office.com/ja-jp/article/%E4%BF%A1%E9%A0%BC%E3%81%A7%E3%81%8D%E3%82%8B%E5%A0%B4%E6%89%80%E3%82%92%E8%BF%BD%E5%8A%A0%E3%80%81%E5%89%8A%E9%99%A4%E3%80%81%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B-7ee1cdc2-483e-4cbb-bcb3-4e7c67147fb4)に沿って、信頼できる場所から起動しなければならない。

## SendKeysメソッドを使う方法
逃げ道として大概でてくるSendKeysメソッド。
プリンタのプロパティ画面を表示してユーザに変えてもらう方法。運用負担軽減策としてはアリ。

```vb
SendKeys "%R"
Application.Dialogs(xlDialogPrint).Show
```

Office2007以降ならCommandBarsオブジェクトでも可。

```vb
Application.CommandBars.ExecuteMso "PrintPreviewAndPrint"
```

## 【本命】カラー印刷用のプリンタを追加する方法
最後に本命を載せる。
同じプリンタドライバで、カラー印刷用のプリンタを【Windowsの設定】から追加し、

```vb
object.PrintOut ActivePrinter:="プリンタ名"
```

とする方法。これが素直かつ、もっとも問題が起こりにくい簡単なやり方だろう。
二段階認証のGitアカウントでのAWS SageMakerとのリポジトリ連携

# これはなに？
- セキュリティ観点でGitアカウントに二段階認証を入れている
- SageMakerで更新するJupyter Notebook、他ファイルをGit管理したい

以上のような状態を達成するために少しハマったので備忘録。

# 作業環境
AWS SageMakerのJupyter notebook上
二段階認証を行ったGitアカウント

# どうやる
AWSのドキュメント通り。
[このページ](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/nbi-git-repo.html)のAmazon SageMaker アカウントに Git リポジトリを追加する (コンソール)という項目内の、
<img width="773" alt="スクリーンショット 2020-01-20 11.49.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160142/760dfc50-b073-1453-8028-96b0df8cb678.png">

この部分に従う。
（SageMaker上でGithubのユーザー名・パスワードでSageMaker-リポジトリ間の連携を行うと、JupyterNotebookインスタンスをGitリポジトリと連携した状態で立ち上げると認証エラーが発生し、起動失敗してしまう）

二段階認証を行っている場合はSageMakerとGitリポジトリを連携する際にパスワード部分に上画像にある個人用アクセストークンを利用する。

[パーソナルアクセストークン設定方法はこちら](https://help.github.com/ja/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line)

こちらで手順通りに設定すると最後にアクセストークンが発行される。
ここで発行されるアクセストークンがSageMakerとリポジトリを紐付ける時にパスワードの部分に入力する文字列になる。

AWSコンソール内のSageMaker > Githubリポジトリ > リポジトリの追加で下画像の項目を入力する。
ユーザー名：Githubアカウント名
パスワード：アクセストークン
<img width="605" alt="スクリーンショット 2020-01-20 12.05.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160142/bc32489f-f036-e62d-de70-e0ddc8d96134.png">

入力した後はシークレットを作成し、Jupyter Notebookにこのリポジトリを紐付ける。

紐付けが終わった後はJupyter Notebook内でのヘッダー部分に「Git」という項目があるので選択する。
Git > Git Command in Terminalで通常通りGitコマンドを入力。

```
git add hogehoge.ipynb
git commit "first commit"
git push origin master
```

Jupyter Notebook上の管理したいファイルに対して、いつものように`git push`してやれば連携したリポジトリ側にJupyterNotebookの管理ファイルが追加されています！！

DONE!!
AuroraRDSの証明書更新メンテナンス

https://aws.amazon.com/jp/blogs/aws/urgent-important-rotate-your-amazon-rds-aurora-and-documentdb-certificates/

cliはバージョンアップ済み（リスタートしないオプションが古いcliだと無い）

```
# pip install -U awscli
# aws --version
aws-cli/1.17.3 Python/2.7.5 Linux/3.10.0-693.el7.x86_64 botocore/1.14.3
```
SSLを使用せずrestartしない場合のオプションをつけたコマンドは以下。

```
myprofile=xxxx
rdsinstance1=xxxx
aws rds modify-db-instance --db-instance-identifier ${rdsinstance1} \
 --ca-certificate-identifier rds-ca-2019 \
 --no-certificate-rotation-restart \
 --apply-immediately --profile ${myprofile}
```
マネコンで対象インスタンスを確認できる。

stgから準繰り対応で作業後にログで再起動生じていない確認をするなど。
datadogでrdsのrestartイベントは補足される設定してて作業時にアラートは特になかったしマネコンのイベントログからもrestartは特にしてなさそうだった。

`--apply-immediately`を指定しないと週一のメンテナンスウィンドウの時間帯に実行タイミングが設定される挙動になっていた。
マネコンの手順に載ってる「直ちに実行」に相当するオプションを`aws rds modify-db-instance help`で探したところ上記が該当した。

確認

```
# aws rds describe-db-instances --profile ${myprofile} |jq -r '.DBInstances[] |{DBInstanceIdentifier,CACertificateIdentifier}|@text "\(.DBInstanceIdentifier)\t\(.CACertificateIdentifier)"'
```

3/6追記

3/5でca-2015の証明書期限が切れてから、監視スクリプトでエラーが。
mysqlコマンドの--ssl-modeオプションのデフォルトが少し古いバージョンだと
PREFERRED（証明書が利用できる場合は利用する）になってるせい。
回避するには、mysqlやmysqladminコマンドに`--ssl-mode DISABLED`をつけるとよいようです。
https://dev.mysql.com/doc/refman/5.7/en/connection-options.html
独自例外の作成

```py:
class UppercaseError(Exception):
    pass

def check():
    words = ['APPLE', 'orange', 'banana']
    for word in words:
        if word.isupper():
            raise UppercaseError

try:
    check()
except UppercaseError as e:
    print('独自に作成したエラーです。')
```

```:実行結果
独自に作成したエラーです。
```

Exceptionをスーパークラスとして継承した
サブクラスUppercaseErrorを作成。

UppercaseErrorの中身はpass即ち、
Exceptionと同じ。

check関数を作成。
check関数の中身はwordsリストの中身を1つ1つ
大文字で記載したものがないかチェックし、
あった場合はraise UppercaseError
つまり、UppercaseErrorとする　というもの。

try以下は、
check関数を実行して、
UppercaseErrorが発生した場合は、
except UppercaseErrorブロックが実行されるというもの。

なので、
実行結果に、
独自に作成したエラーです。と出力される。