OmniAICreator/Qiita-1.07M huggingface dataset:
READMEに画像やGifを【最速で!!】追加する

# はじめに
プログラミングスクールのカリキュラムで作成した個人開発アプリのREADMEにアプリケーションのタイトルとなる画像やデモンストレーション用のGifファイルを埋め込みたいと思って方法を探しました。

# 達成したいこと
以下の画像のようにREADMEにサイトのイメージ画像やGifを挿入していきます。タイトルにもありますが、一番早く入れられると思われる方法を紹介します。
<img width="1027" alt="スクリーンショット 2020-06-14 20.07.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614723/38cb473d-e572-27a6-dbc8-f853ac80916b.png">

# 前提

- アプリケーションがGithubに紐付け済みである
- macを使用している

# 手順
今回の方法では、画像もGifも同じ手順でOKです。

- 画像を用意する
- GitHubからissueを作成する
- issueの本文に画像をドラッグ＆ドロップする
- アップロードした画像のリンクをREADMEにコピーする

# 画像を用意する
画像の用意方法は何でも構わないのですが、macであれば、[shift]+[command]+[4]でスクリーンショットを撮影することができます。
Apple公式より[Macでスクリーンショットを撮る](https://support.apple.com/ja-jp/HT201361#:~:text=Mac%20%E3%81%A7%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%E3%82%92%E6%92%AE%E3%82%8B%E6%96%B9%E6%B3%95,%E5%90%8C%E6%99%82%E3%81%AB%E9%95%B7%E6%8A%BC%E3%81%97%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)

# GitHubからissueを作成する
まずは、GitHubにアクセスし、READMEを編集したいアプリケーションのページにアクセスします。すると、「Issues」という項目があるので、こちらをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614723/e71659e7-11f1-6108-9c44-87beb66d6378.png)

次に「New Issue」をクリックして、新しくIssueを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614723/5678703e-d119-a637-8321-25cec9b5c2d8.png)

# issueの本文に画像をドラッグ＆ドロップする
表示されている本文用のテキストボックスに登録したい画像またはGifファイルをドラッグ・アンド・ドロップします。しばらく「Uploading」と表示されていますが、程なくしてアップが完了すると画像のリンクが以下のように表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614723/2d49c15d-e4af-3088-b1b1-de94ed97e0a6.png)

ちなみに「Preview」タグをクリックするとアップされた画像を確認することができます。「White」をクリックすると元のテキストボックスに切り替わります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614723/6f69c15f-ddcb-667f-0232-f78f9929d423.png)

# 画像のリンクをREADMEにコピーする
アップロードされた画像のリンクをコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614723/2d49c15d-e4af-3088-b1b1-de94ed97e0a6.png)

エディタでREADMEを開き、画像を表示させたい箇所に貼り付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614723/1685e113-39b7-e8af-a432-97be2fc894b6.png)

あとは、変更したREADMEファイルを保存し、commit&pushを行えば、GutHub上で画像が表示されていることが確認できます。
また、今回Issueは、画像アップロードのために使用したので、「Submit new issue」は押さずに編集途中でブラウザを閉じて大丈夫です。

# Gifも入りました
![29788b17bd7f3dcb242e63dd61d79229.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614723/aab4ee1c-f206-2583-1d3d-3b948f754d3a.gif)

# 別の方法でのアップロード
GitHubのWikiを使用した方法もあります。恐らくこっちのほうが確実かつ王道であるように感じます。今回は【最速】というタイトルにしたかったので、詳しくは紹介しませんが、参考記事を以下に載せたいと思います。こちらの方法も実践できました。

[GithubのREADMEにGif画像を埋め込む](https://qiita.com/yamataku29/items/fb14fb99f5024e01b4b8) @yamataku29様
(結論抜粋)現代のニューラルネットワークは奇妙な現象を示します。。。　論文 『On Calibration of Modern Neural Networks』（Chuan Guoら)を読む

#概要
**ディープラーイングによる物体検出等で、0.99とかの率が良く出る。ただ、それで、平気で誤検出だったりする**。そこには、**違和感**あり。
また、softmaxの通常の処理も合理的かもしれないが、**違和感**あり。

あたらずとも遠からずの**正しい率**が知りたいですよね。

それの解決につながるか不明であるが、**入り口**として、以下の論文に注目した。

https://arxiv.org/pdf/1706.04599.pdf
『On Calibration of Modern Neural Networks』
（Chuan Guo  Geoff Pleiss  Yu Sun  Kilian Q. Weinberger)
arXiv:1706.04599v2 [cs.LG] 3 Aug 2017

#内容紹介
以下、Google翻訳をべたべたはる。

概要：
>信頼度キャリブレーション（真の正確性の可能性を表す確率推定値を予測する問題）は、多くのアプリケーションの分類モデルにとって重要です。 10年前のニューラルネットワークとは異なり、最新のニューラルネットワークはキャリブレーションが不十分であることがわかります。 広範な実験を通じて、深度、幅、重量減衰、およびバッチ正規化がキャリブレーションに影響する重要な要素であることがわかります。 画像とドキュメントの分類データセットを使用して、最先端のアーキテクチャでさまざまな後処理校正方法のパフォーマンスを評価します。 私たちの分析と実験は、ニューラルネットワーク学習への洞察を提供するだけでなく、実用的な設定のためのシンプルで簡単なレシピも提供します。ほとんどのデータセットでは、温度スケーリング（プラットスケーリングの単一パラメーターバリアント）が予測のキャリブレーションに驚くほど効果的です。

温度スケーリング：
>Plattスケーリングの最も単純な拡張である温度スケーリングは、すべてのクラスに対して単一のスカラーパラメーターT> 0を使用します。ロジットベクトルziを指定すると、新しい信頼度予測は次のようになります。

<img width="677" alt="shiki.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/8d6475d0-a45c-ebf1-fed1-f502bb341d3c.png">

>Tは温度と呼ばれ、T> 1でsoftmaxを「柔らかく」します（つまり、出力エントロピーを上げます）。T→∞の場合、確率qˆiは1 / Kに近づき、これは最大の不確実性を表します。 T = 1の場合、元の確率pˆiを回復します。 T→0になると、確率は点質量に崩壊します（つまり、qˆi = 1）。 Tは、検証セットのNLLに関して最適化されています。パラメーターTはsoftmax関数の最大値を変更しないため、クラス予測は、変更されません。つまり、温度スケーリングはモデルの精度に影響を与えません。温度スケーリングは、知識蒸留（Hinton et al。、2015）や統計力学（Jaynes、1957）などの設定で一般的に使用されます。私たちの知る限り、確率モデルのキャリブレーションのコンテキストでこれまでに使用されたことはありません。3このモデルは、ロジットの特定の制約のもとで出力確率分布のエントロピーを最大化することと同等です。

結論：
>現代のニューラルネットワークは奇妙な現象を示します。確率的エラーと誤校正は、分類エラーが減少しても悪化します。 ニューラルネットワークアーキテクチャとトレーニングにおける最近の進歩（モデルの容量、正規化、正則化）がネットワークキャリブレーションに大きな影響を与えることを実証しました。 これらのトレンドがキャリブレーションに影響を与えながら精度を向上させる理由を理解することは、今後の課題です。 それにもかかわらず、シンプルな手法は、ニューラルネットワークのミスキャリブレーション現象を効果的に改善できます。 温度スケーリングは、最も単純で、最も速く、最も単純な方法であり、驚くべきことに、多くの場合、最も効果的です。

#今後
上記、Google翻訳のみなので、もう少し、中味を。
関連する内容をあまり見かけていないので、この取り組みは、あまり有効でないのかもしれません。
コメントなどあれば、お願いします。
[Swift] KeyPath


Swift5 のKeyPath キーワードについて勉強しましたので、メモします。


#KeyPathの定義
KeyPathの公式ドキュメントですが、理解できない。。。
[https://developer.apple.com/documentation/swift/swift_standard_library/key-path_expressions](https://developer.apple.com/documentation/swift/swift_standard_library/key-path_expressions)

## 下記のリンクを参照しました。
[https://qiita.com/BlueEventHorizon/items/dee0eb27fbba83ed8ea9](https://qiita.com/BlueEventHorizon/items/dee0eb27fbba83ed8ea9)

## コード
### 1.struct

```swift:StudentModel.swift
struct StudentModel {
    var studentId = "0"
    var name = "new"
    var age = "0"
}
```

### 2. keyPath確認

```swift:sample.swift(type)

public func confirmKeyPathType() {
   var studentModel = StudentModel()
   //keyPath 設定
   let nameKeyPath = \StudentModel.name
        
   print(" \(#function) keyPath type: \(String(describing: type(of: nameKeyPath)))")
}

```

上記の結果ログは下記の通り__WritableKeyPath__です。
<pre>
confirmKeyPathType() keyPath type: WritableKeyPath<StudentModel, String>
</pre>

理由は下記の通りの属性のため

・KeyPath ：　ReadOnly 
・WritableKeyPath ：　Read&Update 


### 3. KeyPath 値更新

```swift:sample.swift(update)
   var studentModel = StudentModel()
   let nameKeyPath = \StudentModel.name
   //keyPath 値更新
   studentModel[keyPath: nameKeyPath ] = "updated"
```

### 4. Sort 


```swift:sample.swift(array)
        
   let array =  [StudentModel(studentId: "003", name: "3", age: "10"),
   StudentModel(studentId: "002", name: "1", age: "15"),
   StudentModel(studentId: "001", name: "2", age: "20")]
```

 KeyPathを利用し、ソート

```swift:sample.swift(Sort2)
        
   let ageKeyPath = \StudentModel.age
   let results = array.sorted {
            $0[keyPath: ageKeyPath] > $1[keyPath: ageKeyPath]
   }
   print(" \(#function) 2.sorted result: \(results) ")
```
一般的なソート

```swift:sample.swift(Sort)
        
   let results = array.sorted{ $0.age > $1.age } 
   print(" \(#function) 2.sorted result: \(results) ")
```

## Github

[https://github.com/mario7/studyForiOS/blob/realmJsonSample/realmAndJsonSample/message/SampleStudentModel.swift](https://github.com/mario7/studyForiOS/blob/realmJsonSample/realmAndJsonSample/message/SampleStudentModel.swift)

## おまけ
### Sort と　Sorted 差

ソートされたリストが返却される。
<img width="461" alt="sorted-help.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101832/15924af0-304c-4a71-bfc3-c884af7c9c5b.png">

対象リストがソートされるため、返却値なし。
<img width="457" alt="sort-help.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101832/61c97d6a-dab6-56bc-4d58-00d1ba36d1c4.png">

### KVO 

<img width="941" alt="kvo.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101832/f0dbc295-892f-13d3-ec80-4736dc51121b.png">

observeがあれば、ごんな感じですかな？　
ごめんなさい。次回調査します。

```swift:sample.swift(kvo)
    let webview = UIWebView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
    webview.observe(\UIWebView.pageLength, options: .new) {_,_ in
            //handler
        }
```

以上です。
CloudFormationで作るECSとAutoScalingの3分クッキング

# 前提

- gitがインストールされている
- dockerがインストールされている
- aws-cliがインストールされている


# クッキング開始

まず、以下のリポジトリをクローンしてください。
https://github.com/yutaro1204/ecs-autoscaling-demo

そして、付属の`ecrRepository.yaml`を利用してAWSにスタックを作成します。
parameterに指定するRepositoryNameは以降で作成するイメージと合わせる必要があります。

```shell
$ aws cloudformation create-stack --stack-name sampleECRRepository --template-body file://ecrRepository.yaml --no-disable-rollback --parameters ParameterKey=RepositoryName,ParameterValue=php_demo_image
```

このスタックにはECRのリポジトリが含まれ、ここに自作したイメージをプッシュします。

自分でイメージを作るのがめんどくさい方は、

```shell
git clone https://github.com/aws-samples/ecs-demo-php-simple-app.git
cd ecs-demo-php-simple-app
```

でPHPのデモアプリをクローンして中に入り、

`src`内に以下の内容のhealthcheck.phpを配置して(`src/healthcheck.php`をヘルスチェックの対象としてます)、

```php
<?php echo "HealthCheck TEST";
```

```shell
$ docker build -t php_demo_image .
```

でこのイメージを作成します。
最初にECRリポジトリを作成した時に指定したRepositoryNameと同じ名前でbuildしています。

次にこの作成したイメージをECRのリポジトリにプッシュします。

```shell
$ aws ecr get-login --no-include-email --region ${AWS.Region}
```

でログインコマンドを取得し、これをそのまま実行します（以下は例）。

```shell
$ docker login -u AWS -p XXXXXX.......
```

で、先ほど作ったイメージにタグづけをして、

```shell
$ docker tag php_demo_image:latest ${AWS.AccountId}.dkr.ecr.${AWS.Region}.amazonaws.com/php_demo_image:latest
```

タグづけされたイメージをECRへプッシュします。

```shell
$ docker push ${AWS.AccountId}.dkr.ecr.${AWS.Region}.amazonaws.com/php_demo_image:latest
```

AWSコンソールなどでイメージがちゃんとプッシュされているか確認してみて下さい。

あとは`microservices.yaml`の`ECSTaskDefinition`の`ContainerDefinitions`を以下のように修正して、

```yaml
ECSTaskDefinition:
  Type: AWS::ECS::TaskDefinition
  Properties:
    ContainerDefinitions:
      - Image: '${さっきイメージをプッシュしたECRのARN}:latest'
```

以下のコマンドでCloudFormationのスタックを作成します。

```
$ aws cloudformation create-stack --stack-name sampleECSClusterWithAutoScaling --template-body file://microservices.yaml --no-disable-rollback --capabilities CAPABILITY_NAMED_IAM
```

数分でロードバランサーのDNSNameからPHPのデモページへと飛ぶことができるようになっているかと思います！

![Screenshot 0002-06-14 at 22.46.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245704/763dbb96-6cd4-ca41-1256-e2c10c7c936d.png)


# クッキング終了

リソースの設定値を色々といじってみて自分にあった構成を試してみてください。
たとえば、タスクやAutoScalingGroupに含まれるEC2インスタンスを意図的に削除してみたりとか。

タスクはECSのServiceが自動復旧してくれるし、EC2インスタンスもALBが認識してAutoScalingが立て直してくれると思います。
Splunk 過去と最近を比較する

小ネタ
https://community.splunk.com/t5/Splunk-Search/How-to-count-data-from-different-time-and-use-it-in-the-same/m-p/504308/highlight/false#M140775

で回答したので。

#ある期間と、今日の値を時系列で比較したい場合のやり方
```sql:timechart.spl
| tstats count where index=_internal earliest=1 by _time span=30min
| eval status="OverTime"
| append [|tstats count where index=_internal earliest=-1d@d by _time span=30min | eval status="Today"]
| eval _time=strftime(_time,"%T")
| stats avg(count)  as count by _time status
| xyseries _time status count
| fillnull OverTime Today
```

##結果
| _time | OverTime | Today |
|:--|--:|--:|
| 00:00:00 | 3147.4166666666665 | 0 |
| 00:30:00 | 2295.235294117647 | 0 |
| 01:00:00 | 2218.2 | 290.5 |
| 01:30:00 | 3621 | 818 |
| 02:00:00 | 6259.8 | 6103 |
| 02:30:00 | 4775.7 | 8777 |
| 03:00:00 | 3919.470588235294 | 145 |
| 03:30:00 | 4572 | 218 |
| 04:00:00 | 6751.25 | 4705 |
#解説
- `tstats`は検索期間を複数設定できないので`append`でくっつけています。
- その際`eval`で区分を作成
- 結合するために、時間だけのデータにしています。
- 二番目の引数のフィールドの値が列名となる`xyseries`を使ってみました。
- `xyseries`だと値がないところを補完してくれないので`fillnull`を使いました。

#まとめ

|列１|列２|列３|
|:-:|:-:|:-:|
|時間|あとで値を列名にしたいフィールド|集計値|

という形を作ると`xyseries`がいい感じで使えます。
`bin`して`stats count by _time field`を`append`でくっつけるとこの形が作れますね。

Splunk>Answersの質問者は`appendcols`を使ってますけど、単純に横に列をくっつけるだけなので、だったら`join`のほうがいいですよね。

このごろは`xyseries`をよく使っているような気がしています。
[Splunkのtableの縦横を変換する](https://qiita.com/toshikawa/items/5bb9315507078cc5c88c)
の頃はあんまり使ってなかったのに、慣れでしょうかね。

:sweat:逆に`timechart`が使い辛くなってきた。
アジャイル開発にてチーム内でのデータベースの齟齬が発生した

#はじめに
アジャイル開発にて、migrateファイルが消えてしまう事態が発生したので解決までに行った事をまとめます。

##原因
原因は、本番環境でのエラーを修正中に誤って消してしまったためである。
はっきりとした原因は、明確ではない。

##行った作業
チーム内で、一人がデータベースを修正。その後、マージ。最後に各自でgit pullし、データベースを最新に修正。

##手順

### 代表がmodelの作成
```
rails g model モデル名
```
もし、もともとのモデルが存在していた場合、”オーバーライト”が起きる。その際は、ターミナルで "n"（Noを意味する）を選択する。
そうすれば、migrateファイルだけが生成される。

###データベースを削除する
```
rake db:drop
```

###再度データベースを生成
```
rails db:create
rails db:migrate
```

##補足

もし、scheme.rbファイルが正しい内容になっていた場合は、以下のコマンドだけでもできる様です。

```
rake db:reset
```
参考記事：https://qiita.com/Atsushi_/items/a230fb7f624d1eebf2f3


以上.
Tiny-YOLOv3でチャンネル数を変更する方法

# Tiny-YOLOv3 でチャンネル数を変更する方法

Tiny-YOLOv3 の cfg ファイルでは、Classes が 80 で固定されているのでそれを変更する。

~~~yolov3-tiny.cfg
@@ -132,7 +132,7 @@ activation=linear
 [yolo]
 mask = 3,4,5
 anchors = 10,14,  23,27,  37,58,  81,82,  135,169,  344,319
-classes=80
+classes=10
 num=6
 jitter=.3
 ignore_thresh = .7

[yolo]
 mask = 0,1,2
 anchors = 10,14,  23,27,  37,58,  81,82,  135,169,  344,319
-classes=80
+classes=10
 num=6
 jitter=.3
 ignore_thresh = .7
~~~

単純に、yolov3-tiny.cfgのclasses を 変更するだけでは、以下のエラーが出てしまう。
darknet: ./src/parser.c:318: parse_yolo: Assertion `l.outputs == params.inputs' failed.

Filter数も修正しないといけない。

filters は 3x(検出したいmodel数 + 5) で決まっている。
よって、検出したいmodel数が80の場合は、3 x (80 + 5) = 255 になるので、
検出したいmodel数を10にする場合は、3 x (10 + 5) = 45 にする必要がある。

~~~yolov3-tiny.cfg
@@ -124,7 +124,7 @@ activation=leaky
 size=1
 stride=1
 pad=1
-filters=255
+filters=45
 activation=linear


@@ -168,13 +168,13 @@ activation=leaky
 size=1
 stride=1
 pad=1
-filters=255
+filters=45
 activation=linear
~~~
【Flutter】ColumnやRowのtextDirectionで起きたエラー

# ColumnやRowのtextDirectionでエラーが起きる

## 出会った時
RowのtextDirectionで

```dart
TextDirection.rtl
```
を書こうとすると
```The getter 'rtl' isn't defined for the type 'TextDirection'.```
と怒られる。
代わりに変換で出てくるのは
TextDirection.RTL
大文字だったっけ？と思いながら書いてもエラー。。

## 原因
```dart
TextDirection.rtl
```
エラー文は

```
The argument type 'TextDirection (where TextDirection is defined in /Users/xxxx/flutter/.pub-cache/hosted/pub.dartlang.org/intl-
0.16.1/lib/src/intl/bidi_utils.dart)' can't be assigned to the parameter type 'TextDirection (where TextDirection is defined in /Users/xxxx/flutter/bin/cache/pkg/sky_engine/lib/ui/text.dart)'.dartargument_type_not_assignable
bidi_utils.dart(26, 7): TextDirection is defined in /Users/xxxx/flutter/.pub-cache/hosted/pub.dartlang.org/intl-0.16.1/lib/src/intl/bidi_utils.dart
text.dart(1287, 6): TextDirection is defined in /Users/xxxx/flutter/bin/cache/pkg/sky_engine/lib/ui/text.dart
```
うーん、TextDirectionが二つ定義されてるらしい？
そのbidi_utils.dart

```dart
class TextDirection {
  static const LTR = TextDirection._('LTR', 'ltr');
  static const RTL = TextDirection._('RTL', 'rtl');
```
がある。これが原因か。そしてこのファイルは

```dart
import 'package:intl/intl.dart'
```
このパッケージによるファイルと判明。

## 解決方法
1.パッケージを消す
```import 'package:intl/intl.dart'```
を消せば問題は解決する
しかし僕はDateFormatを使っていたため、これを消すわけにはいかず。

2.インポート接頭辞
importには接頭辞を指定することができます。

```dart
import 'package:intl/intl.dart' as hoge
```

とすると

```dart
(old) DateFormat('HH:mm').format(date);

(new) format.DateFormat('HH:mm').format(date);
```

で使用できるようになる。すると他には影響せず、

```dart
TextDirection.rtl
```

が使えるようになりました。
第5回Flutterもくもく会@Zoom 実施レポート

# はじめに 

2020年6月14日にZoomにて[Flutterもくもく会](https://flutter-okurayama.connpass.com/event/178885/)を実施したので、
そのレポートになります。個人的所感メインです。
何かご意見などありましたらよろしくお願いします。
話題になった内容をトピックとして記載します。


もし良ければ過去のものもご覧ください。

* [第1回](https://qiita.com/glassmonkey/items/7dd8cf2037e17c5131f8)
* [第2回](https://qiita.com/glassmonkey/items/9ed36f0e8f27952c7c6d)
* [第3回](https://qiita.com/glassmonkey/items/95d470bc780e35d079fa)
* [第4回](https://qiita.com/glassmonkey/items/75f6df813d0458e9cf5b)


# トピック
今回のもくもく会で出た話題の一部をピックアップ。

# 画面レイアウトについて
画面の組み方をどうしてます？という話題が出ました。

最初は愚直にレイアウトを組むのが良いのかと思うと、listviewとの組み合わせが難しいなと改めて思っております。
https://flutter.dev/showcase
を参考にして素振りしてくしかないのですかね。

デザインパターンみたいなのが出来てくるのに期待はしたいです。

プロダクションでFlutterを採用しているアプリも増えてきているので、
参考にしていきたいですね。show caseでのアプリ数は日々充実している印象があります。

# テストについて
テストについて、個人的に悩んでる点があったので話題にしました。
現在タイマーアプリを作っていてそのテスト方法でお悩み中です。
[fake_async](https://github.com/dart-lang/fake_async)を使ってみましたが、
async/awaitと相性がわるく諦め中だったりはします。

最近、[StateNotifierに関するテスト](https://qiita.com/glassmonkey/items/0a406898cd28152c24ff)について記載したので宣伝もさせていただきましたｗ


# Dartのスレッド周り
Dartの勉強の話からスレッドの話になりました。
現状作ってるタイマーアプリではそこまで意識する必要はなさそうな感じですが、Apiとのやりとり増えると意識しないといけないなとは思いました。
[FlutterでIsolateを用いた並列処理をするべきシーンとそのやり方](https://medium.com/flutter-jp/isolate-a3f6eab488b5)にまとまってました。mono先生いつも助かってます。

# おわりに次回開催と宣伝
こちらで定期的にもくもく会を隔週の頻度で実施予定です。次回は6月28日を予定しています。
https://flutter-okurayama.connpass.com/event/179680/

LTなど発表したい方いましたら [@glassmonekey](https://twitter.com/glassmonekey)にご連絡いただけますと嬉しいです。LTの練習とかも大歓迎です。

下記のコンパスも良ければ登録お願いします。これを機に一緒に始めましょう
https://flutter-okurayama.connpass.com/


# 感想というかメモ
今日はネイティブ開発経験してる方が多めだったので思いましたが、
Swift, Kotlin開発との比較はもっと知りたいなーとは思いました。
WSL2にUbuntu20.04LTSをインストール



# WSLのインストール
WSLがまだインストールされていない場合、インストールが必要です。

管理者として PowerShell を開き、以下を実行。

```powershell
PS > dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
```

# WSL2 に更新

##  「仮想マシン プラットフォーム」のオプション コンポーネントの有効化
WSL2 に必要な、「仮想マシン プラットフォーム」オプション機能を有効にする必要があります。

管理者として PowerShell を開き、以下を実行。

```powershell
PS > dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
```

## WSL2 を既定のバージョンとして設定
新しい Linux ディストリビューションをインストールするときに、WSL2 を既定のバージョンとして設定します。

管理者として PowerShell を開き、以下を実行。

```powershell
PS > wsl --set-default-version 2
```

# Ubuntu 20.04 LTS のインストール
WSL2にUbuntu20.04LTSをインストールします。
MIcrosoftStoreから「ubuntu」で検索し、「入手」（または「インストール」）ボタンを押してインストール。

# WSLのバージョン確認
PowerShell を開き、以下を実行。

```powershell
PS > wsl --list -v
  NAME              STATE           VERSION
* Ubuntu-20.04      Running         2
```
Ubuntu-20.04が、VERSION 2 （WSL2）で動作しているのを確認できます。


以上。
入力した文字列から、指定した文字列より右の文字列をとりだす

### 要望

```
入力した文字列："abcTESTTEST123defghi"
から、指定した文字列(TESTTEST)より右の文字列(123defghi)を取り出したい
```

### 解決方法

以下のようにsedを使うと、指定した文字列(TESTTEST)より右を取り出せる

```
$ echo abcTESTTEST123defghi | sed -e 's/.*TESTTEST//'
123defghi
```

# 参考
[sedコマンドを使って、特定の文字列以降を削除〜ソースコードのコメントを削除したかったの〜](https://karoten512.hatenablog.com/entry/2018/03/14/120202)
[文字列から特定の文字を抽出する - Linux シェルスクリプト プログラミング](https://ez-net.jp/article/7A/9qV1-XpJ/6o8QiIwz08um/)
[sedでこういう時はどう書く?](https://qiita.com/hirohiro77/items/7fe2f68781c41777e507)
【Java】標準入力を使いこなせないとpaizaのスキルチェックはDで詰む

##概要
Progateを軽くやったくらいでJavaの経験がないため、研修でpaizaのスキルチェック問題を解いているのですが、初日に予想外の所で詰まったのでメモします。

スキルチェックを始めると早々に
>文字Nが入力されるのでNを出力せよ

的な内容を指示されます。

System.out.print～で出力して終わりじゃん！と思うのですが
そのまま書くのは間違いとなります。

色々フォローされるProgateと違い
スキルチェックでは入力される値もこちらで読んであげる必要があります。
ここで「入力値を読み込む」方法を知らないと、paizaはDランクすら取れません。
##方法
簡単なのでyoutubeに投稿されている[Java標準入力解説](https://www.youtube.com/watch?v=nxd4CLklcfY)を見るか
[paizaラーニング](https://www.youtube.com/watch?v=nxd4CLklcfY)を見る事で理解できますが、せっかくなので使い方を書いてみます。

冒頭のような問題の場合、文字なので

```Java
//変数を定義
Scanner sc = new Scanner(System.in);
//文字列を取得
String t = sc.nextLine();
```
これで読み込んであげれば、出力する事ができます。

###数字が入力される場合
数字の場合もほぼ変わりません。

```Java
//数字を取得
int t = sc.nextInt();
```

「nextInt」となっている事に注意しましょう。

###一つずつ読み込む
例えばN Bという1行の形で文字が与えられ、N + Bにする必要があったとします。
>N B

この場合、nextLine();にするとNもBもまとめて読み込まれてしまうので
next();を使うと良さそうです。

```Java
//Nを読み込む
String x = sc.next();
//Bを読み込む
String y = sc.next();
```
next()は半角スペースまでを読むので、splitを使わずとも疑似分割できます。
数字の場合でも同じように使う事ができます。
※ただし「文字」として読み込むので、当然Stringの型指定が必要

###複数行を読み込む
1行目に1という数字、2行目にNという文字が与えられるとします。
>1
>N

この場合、nextInt();,nextLine();でそれぞれ取得すれば良さそうですが
このまま書くとエラーになります。

```Java
//間違い例
int t = sc.nextInt();
String a = sc.nextLine();
```

nextInt()は整数を読むので、実は改行文字が残ったままになります。
この処理だと2行目が読めていません。
なので、nextLine();を追加して読み飛ばす必要があります。

```Java
//1行目の整数を読む
int t = sc.nextInt();
//改行文字を読み飛ばす
sc.nextLine();
//2行目の文字を読む
String a = sc.nextLine();
```

paizaは結構このタイプの問題があるので、覚えておいて損はありません。
自分は何故上手く行かないのか分からなくて、かなり詰まってました...。


他にもListとして取得したりもできますが、値や文字を適切に取得できれば
後はロジックの処理に集中できます。
nextLine();とnext();とnextInt();がそれぞれどういう動きをしているのか、イメージするのが大事です。
##まとめ
知っている人からすると単純な話ですが。Progateや書籍に頼った学習をしていたせいか、予想外の部分で躓いたので参考になればと思います。
先輩の話によると、どうやら実際の現場ではあまり使われないとの事ですが、paizaのスキルチェックを攻略する上では重要な知識です。
【Django】独自の403、404、500 エラーページを作成する

# 概要
404 Not Foundなどのエラーページを作成する方法を調べたのでまとめます。

# 今回調べたエラー
以下のエラーコードについて触れていきます。

* 403 Forbidden
* 404 Not Found
* 500 Internal Server Error

# やり方
 任意のtemplatesディレクトリの下に、

* 403.html
* 404.html
* 500.html

を置きます。  
すると、対象のエラーが吐かれるときに自動でテンプレートを読み取ってくれます。  

## 例
```
myproject
  - myapp
    - urls.py
    - views.py
    - models.py
    - app.py
    - forms.py
    - templates
      - 403.html
      - 404.html
      - 500.html
```

以下のように、独自の404ページなどを実装します。

```404.html
{% extends "base.html" %}
{% block content %}
<section>
    <div>
        <label>404 Not Found<br>お探しのページが見つかりませんでした。<br><a class="hover-under" href="{% url 'top' %}">トップページへ戻る</a></label>
    </div>
</section>
{% endblock %}
```

## 各エラーコードが吐き出される例外
これらのページは、それぞれのステータスコードが返されるべき例外を呼んであげると、返されます。

### 404 Not Found
`django.http`パッケージの中にある`Http404`クラスをraiseします。

```views.py
from django.http import Http404


class MyView(View):
    def index(self):
        raise Http404
```

### 403 Forbidden
`django.core.exceptions`に`PermissionDenied`クラスがあります。

```views.py
from django.core.exceptions import PermissionDenied


class MyView(View):
    def index(self):
        if not self.request.user.is_authenticated:
            raise PermissionDenied
```

### 500 Internal Server Error
構文エラーなど、通常のInternalServerErrorとなるものをキャッチしない、もしくは明示的に返した通常のエラーを使います。

```views.py
from .models import Example


class MyView(View):
    def index(self):
        try:
            _instance = Example.objects.get(id=1)
        except Example.DoesNotExists:
            # 例外を投げる（普通はあまりやらない）
            raise Exception
```
異なるシートの同性質テーブルを結合させる

# 処理内容
position-Aの処理までを割愛します。

処理対象となるシートをループ処理する
シートのA列の情報を二次元配列で取得する
取得した二次元配列を一次元へ変換する
変換した配列の中で、キーワードが位置している要素番号を検索し、＋１することで行数と対応させる
キーワードの行数を基準に、DataRegion()で四方向がNullになるまで選択範囲を延長する
１行目はタイトル、２行目がヘッダなので、取得した二次元配列の０番目と、１番目の要素をsplice()メソッドで削除する
まとめ用の配列に格納する

＝＞ループ処理終了後
配列の階層を削除し、表形式に対応する形に変換する（flat()メソッドの部分）
まとめ用配列の要素内容と、要素数をログ出力する

```
function getDataRange() {
  const IndexSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Index');
  let data_range = IndexSheet.getDataRange().getValues();
  data_range.shift();
  let original_list = data_range.map(function (record){return record[0]});  
  let total_data_range = [];
  for(let sheet of original_list){
    let targetSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheet);
    let column_A_values = targetSheet.getRange('A:A').getValues();
    let convert_list = column_A_values.map(function(element){return element[0]})
    let keyword_OptionId_position = convert_list.indexOf('OptionId') + 1;
    let extention_range = targetSheet.getRange(keyword_OptionId_position, 1).getDataRegion().getValues();
    // delete two element
    extention_range.splice(0, 2);
    total_data_range.push(extention_range);
  }
  let flat_array = total_data_range.flat();
  console.log(flat_array);
  console.log(flat_array.length);
}

```
Dockerを使ったMacでのGolang開発環境

こちらの記事を参考にMacでDockerを使ったGolang開発環境を整えてみる。
https://dev.classmethod.jp/articles/vscode-remote-containers-golang/

## 環境
mac OS : Catallina 10.15.4
VS Code : 1.45.1

# VS Codeの機能拡張

Remote-Containers : インストール済みだった

どう動作するかは以下の最初の図がわかりやすい
https://code.visualstudio.com/docs/remote/containers
【VSCode】VSCodeでハイフン区切りの単語をダブルクリックを使い一発選択する方法

## 手順
### 設定画面を開く
command + ,を押して設定画面を開く。
![2020-06-14 19.30.32.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431639/8edd86d8-f9ce-4728-a8cf-4755ead5b0c3.gif)

### editor.separatorの編集
editor.separator（ダブルクリックで単語を一発選択するときの文字の区切り）
から-を消す。
![2020-06-14 19.37.51.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431639/e7450e2b-4434-f457-f49f-4f613469b02c.gif)

### 確認
ダブルクリックで-区切りの単語を一発選択できる事を確認する。
![2020-06-14 19.38.45.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431639/c40c387b-3cc4-318e-bb79-70d2fcb5bccc.gif)

## 投稿した経緯
みんな設定しているもんだと思ってましたが、
ツイッターでケバブケースの選択が面倒...という話題を見たので。
【Git】リモートブランチを強制的にローカルにチェックアウトする

リモートのとあるブランチがローカルに存在するかどうかに関わらず、そのブランチを強制的にローカルに落とす（存在する場合は上書き）方法です。
なお、fetchでリモートの情報を取り込めていることが前提です。



## リモートブランチを強制的にローカルに落とす
```
$ git branch --force branch1 origin/branch1
```

とすると、ローカルにbranch1が存在していなかった場合は、リモートのbranch1をローカルに落とします。
ローカルにbranch1が存在する場合は、ローカルのbranch1をリモートのbranch1で上書きします。

## リモートブランチを強制的に切ってチェックアウト
```
$ git checkout -B branch1 origin/branch1
```
とすると、ローカルにリモートのbranch1を強制的に落として（上書きして）チェックアウトまで行います。
AtCoder Beginner Contest159 D - Banned K (ABC159D) をpythonで解く (countが遅すぎる！)

普通にpythonのcountメソッドを使ったらTLEしたので、Counterを使ってみたところAC出来ました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655616/82bcb1d4-9455-a675-0ec4-7f86a28564f3.png)

以下がCounterを使った回答です。

```code.py
import sys
from collections import Counter
N=int(sys.stdin.readline())
L=list(map(int,sys.stdin.readline().split()))
C=Counter(L)           #Lに含まれる{文字:出現回数}の辞書型で帰ってきます
x=0
for a in C.values():   #値（出現回数）のみを取り出します
  x += int(a*(a-1)/2)  
for K in range(N):
  print(x-C[L[K]]+1)   #すべての同じ数の組み合わせからKを含む組み合わせを引きます
```

以下がTLEした回答です。ちょっといじれば速くなるのでしょうか？

```code.py
import sys
N=int(sys.stdin.readline())
L=list(map(int,sys.stdin.readline().split()))
C=list(set(L))
x=0
for i in range(len(C)):
  a = L.count(C[i])
  x += int(a*(a-1)/2)  
for K in range(N):
  print(x-L.count(L[K])+1)
```
MaixCubeで音声認識を試してみる

# はじめに

MaixCubeを含むMaixシリーズの特徴が画像認識と音声認識のAIです。K210に搭載されたKPU、APU、FFTなどのハードウェアがサポートしてくれます。

サウンドデバイスが使えるようになったので、音声認識を試してみましょう。

# Maixduino

Sipeed社から提供されているMaixduinoの開発環境にSpeech Recognitionのサンプルのコードとモデルが含まれています。

サンプルのコードでは、音声入力をMFCC（メル周波数ケプストラム係数）分析した後、DTW（動的時間伸縮法）で類似度を求めているようです。MFCCでK210のFFTが使われています。

場所

.platformio/packages/framework-maixduino/libraries/Maix_Speech_Recognition/examples

# サンプル

サンプルのモデルをそのまま使ってMaixCubeで試したソースは[こちら](https://github.com/fukuen/maixcube-speech-recognition-demo)

起動すると、まずモデルを読み込みます

init model...
init model ok!

次に、周囲の雑音が小さくなるのを待ちます

get noise again...

音声入力待ちになります

speaking...

ここで、「レッド」あるいは「グリーン」あるいは「ブルー」と話しかけます。

うまくいけば、

res : red

と、表示されて赤のLEDが表示されます。

うまく認識されない時は、

recognize failed.

と表示されます。





# 結果

あまり認識率がいいとは言えませんが、サンプルに自分のモデルを作るコードもあるので、自分の声でモデルを作ると少し認識率が上がりそうです。

Maixduinoの開発環境が提供されているので、簡単に音声認識（AI）を試すことができました。
最近 Pythonを勉強し始めたので……

初投稿です。
独学でpythonを勉強し始めたので、アウトプットのための投稿です。


## 型とか色々
始めたばかりなので、初歩的な部分を色々とやっています。

#### 型について
ご指摘いただいたので修正。
- int=integre型
 - ~~主に数字を扱う。~~
 - 整数、少数、指数表記などを表現することができる。クォートで囲めば文字列に変換可能。
Python3だとかなり膨大な桁数を扱うことができる。
~~文字~~ 英字・記号を入れるとエラーをはく。(ture,falseを除く)

``` py
>>> int(20)
 20
```

- float型
 - 小数点を専門に表現する。float型で整数を入力すると、必ず1.0のように小数点以下第一位が表示される。クォートで囲むことで文字列に変換可能。
文字を入れるとエラーをはく。(ture,falseを除く)
 
```py
>>> float(3.0)
3.0

>>> float(4)
4.0
```

- str=string型
 - 文字列を専門に扱う型。数字でも文字として変換できる。ただし、計算などはできない。
 
```py
>>> str(abc)
'abc'
```


#### クォートについて
シングルクォート、ダブルクォートで囲むことで、文字列として表現することができる。
また、長文を改行付きで表示させるためには、初めと終わりにクォートを三連続で表記する。
printで表示すると、改行なども入力時と同じ表示となる。

## おまけ
```py

>>> int(1.0e4)
10000
```

というテキストが出てきたときに、この**e**ってなあに？　となった。
調べてみると、指数表記というものだった。
上記の（）内は、1.0×10の４乗という意味。
つまり**e**=１０で、後ろにくっついている４は乗数ということ。

こういう表も見つけたので、参考までに。
[指数表記の早見表]
(https://qiita.com/rev84/items/68f9c5bf7aa7e8e8e13f#%E5%8F%82%E8%80%83)

---
少しづつでもしっかり勉強していきたいと思います。
ECS＆FARGATEでEFSをマウント

# はじめに
FARGATEがEFSをサポートしたので、試してみました


## やりたいこと

NginxのコンテナをECSにデプロイ
index.htmlをEFSに配置し、それをNginxコンテナでマウントして
動的にコンテンツを更新する

## 今回の構成
![efsとECSの連携.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626780/a976d176-9933-069b-75d6-921e267c068c.jpeg)



## 大まかな流れ

(1)EFS作成＆コンテンツ配置

(2)ローカル環境でnginxのイメージを作成＆ECRへプッシュ
nginxの公式イメージを使用してコンフィグだけADDしてプッシュ

(3)タスク定義作成

## 実際にやってみる

### (1)EFS作成＆コンテンツ配置

1.EFSはデフォルトでサクッと作成
写すことができない箇所はマスクしてます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626780/d7969710-a476-5ad2-40da-20fb024b3203.png)

2.EFSマウント

今回はEC2インスタンスにてマウントしますので以下の手順を実施

Amazon Linux EC2 インスタンスを使用している場合は、次のコマンドを使用して EFS マウントヘルパーをインストールします。

```
$ sudo yum install -y amazon-efs-utils
```

EC2 インスタンスで「efs」などの新しいディレクトリを作成します。

```
sudo mkdir efs
```

EFS マウントヘルパーの使用

```
sudo mount -t efs fs-xxxxxxx:/ efs
```

3.コンテンツをEFSへ配置

```
$ cp -p xxx /efs/
```

### (2)ローカル環境でnginxのイメージを作成＆ECRへプッシュ

1.適当にnginxのDockerFileを作成

```
FROM nginx:latest
RUN echo "start"
```

2.イメージ作成

```
$ docker build -t hogehoge .
```

3.ECRへプッシュ
ここの手順は割愛

### (3)タスク定義作成
ECRにプッシュした定義を使用してタスク作成

ボリュームに事前に作成しておいたEFSを指定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626780/53a09ff8-8c24-e818-a02a-7bfaeb13821d.png)


コンテナの設定のマウントポイントに作成したボリュームをマウント
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626780/c2dbc6bd-5bf7-0757-1e73-fd55706f5919.png)

後は作成したタスクを使用して実行すればEFSのコンテンツが見えてくるはずです
【Flutter】StatefulWidget に引数(Parameter)を渡すには


####結論
コンストラクタによって引数を渡さず、
`State`オブジェクトに用意されている**`widget`プロパティを利用して引数を取得**する。


⭕️　`State`のbuildメソッド内部で`widget`変数から値を受け取る
❌　`StatefulWidget`の`createState()`メソッド内で、`State`のコンストラクタに渡す（
####実装

```main.dart
import 'package:flutter/material.dart';

class Page extends StatefulWidget {

  final String param; //上位Widgetから受け取りたいデータ
  Page({this.param}); //コンストラクタ

  @override
  _PageState createState() => _PageState();
}

class _PageState extends State<Page> {
  @override
  Widget build(BuildContext context) {
    return Text(widget.param); // widget 変数からデータ取得可能
  }
}


```

####理由
Flutter公式のドキュメントにStateオブジェクトのライフサイクルについての記載があります。

	Stateオブジェクトの作成
	BuildContextへの関連付け（マウント完了,BuildContextにアクセス可能となる）
	initStateの呼び出し（呼び出された親のStatefulWidgetをwidgetプロパティに格納する）
	→初期化完了(以後、Stateの変更によるWidgetツリーの再構築が可能になる。）

「コンストラクタを用いてはいけない」などの記載はありませんが、下記の理由からwidgetプロパティを使用すべきと考えます

	・Flutterの機能としてwidgetプロパティが用意され、使用が想定されている（公式ドキュメントやTutorial動画全てこの方式）
	・二重にParameterの記載をすると実装ミス・修正影響が増えるという設計上のリスクがある。

####参照
[How Stateful Widgets Are Used Best - Flutter Widgets 101 Ep. 2](https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html)
[State class - flutter.dev](https://api.flutter.dev/flutter/widgets/State-class.html)
[Stack Overflow - Passing data to StatefulWidget and accessing it in it's state in Flutter](https://stackoverflow.com/questions/50287995/passing-data-to-statefulwidget-and-accessing-it-in-its-state-in-flutter)
同一要素を含む複数のシートについて、シートごとの要素位置を検索する（同一要素の位置は不一致）

# 処理内容

処理対象となるIndexシートをインスタンス化
Indexシートの全データを二次元配列（getVlalues()）で取得する getDataRange()
１行目（ヘッダ）を削除する
ヘッダなしの二次元配列を一次元に変換する＝＞処理対象となるシート名を配列で保持することが目的
処理対象となるシート名について、各シート名ごとにループ処理を実行する
シートをインスタンス化する
A列の値を二次元配列で取得する(getValue()では一つの情報しか取得できないため、指定した範囲のデータをまとめて取得する際は、getValues()メソッドを使うことになる。ただ、ほしい値が１列分だけだとしても二次元配列となるため、１行分の情報として扱いたい場合は、二次元配列を一次元配列へmapメソッドを使って変換してやる必要がある）
取得した二次元配列を一次元に変換する
indexOf(キーワード)メソッドを使って、配列内の検索したい文字列の要素番号を検索する。この時、配列のインデックスと行のインデックス差分１を考慮して、＋１することで配列の要素番号を行数と見做すこととする。
上記結果をログ出力する

```
function getDataRange() {
  const IndexSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Index');
  let data_range = IndexSheet.getDataRange().getValues();
  data_range.shift();
  let original_list = data_range.map(function (record){return record[0]});  
  for(let sheet of original_list){
    let targetSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheet);
    let column_A_values = targetSheet.getRange('A:A').getValues();
    let convert_list = column_A_values.map(function(element){return element[0]})
    let keyword_OptionId_position = convert_list.indexOf('OptionId') + 1;
    console.log(keyword_OptionId_position);
  }
}
```
【Rails】enumの使い方　

##はじめに
RubyやRailsで、Enumの使い方を
忘れない為のメモ。

##enumとは？
「Enum」は「列挙型」のこと。
・DBにはint型やboolean型で登録され、数値に紐付く任意のキー名を付けることができる。
・ソースコードでは、紐付くキー名を用いれる。

利点
・データ型をintegerにするとDBに数字で登録されるが、数字だけだと数字が持つ意味が共有出来ない。
・文字列として定義していたらタイポする可能性が多くなるが、enumを使うとその心配がない。
・修正の際に楽。

##定義方法
モデルに対してenumを定義する必要があります。
定義方法は、２通りあります。
**1.定義のみ**
**2.定義に数値を指定**
#定義のみ指定
配列で定義をします。定義順に0から順に紐付けされます。
下記の例では昨日→0、今日→1、明日→2と自動的に振り分けされる。
enum カラム名:[:付けたいキー名]でenumを指定していきます。

**※[　]なのと　:　の位置に注意**

```ruby:モデルのファイル
  enum カラム名:    [ :昨日, :今日, :明日 ]
　　　　　　　　　　　↑定義するもの
```
##定義に数値を指定
enum カラム名:{付けたいキー名:対応する数値}でenumを指定していきます。
**※{　}なのと　:　の位置に注意**

```ruby:モデルのファイル
  enum カラム名:    { 昨日: 0, 今日: 1, 明日: 2 }
　　　　　　　　　　　↑定義するもの
```

##viewでの使用
下の記述でselectボックス作成ができます。
**カラム名,カラム複数型は同じカラムでenumの後に記述したカラム**
**モデル名は定義の際に記述したモデル**

```ruby:viewファイル
 <%= select :カラム名, :name, モデル名.カラム名複数形.keys.to_a, include_blank: true %>
```
##終わりに
・私はステータスの変更や連動してステータスが変更される時に、使いました。
・コントローラーで、ifなどで比較する場合は数字ではなく定義した文字で比較できると思います
例) if 比較したい情報　== "昨日"
例） 探したい情報.where(カラム名: "今日").count　など
ポエム：女の子が物故割れる話

#何を書くか。
ホラーです。リアルにあるめちゃくちゃ怖いホラーです。

#何をしたか。
生来100年程度の余白があってその余白を生きるための才能等を与えられます。
それは何によってでしょうか。

#MY Answer
仕組みは色々ありますが、生を受けた時、その人の構造にはいろんな法則や仕組み使うための術をビルトインされます。
それがですね、何によって壊されるかというと、実は「コンピュータ」によってなのです。
どういうことかというと、そのビルトインされている術にはある程度の割り切り等が入っていてその割り切りが物故割れることはその術にまつわるすべてが物故割れるということです。
コンピュータ上では、アルゴリズムが正しければ答えは正しいです。
それによって、個々にビルトインされている割り切りのすべてを正されるのです。
私も書きましたが「ABC予想」は死にました。それだけでいろんなものが物故割れる程度の威力があったそうです。
そのABC予想にまつわるすべての成否が壊れたのです。解けない問題はありません。
C++には多倍長浮動小数点数が使える環境があり、すべての数式をメモリ資源のある限り演算しつくすポテンシャルがあるのです。
生半可な割り切りはその前には無力なのです。

#光明
一つの光明としては、物事は成長するということです。
意識や体もただそこにあるわけでは無いのです。
いろんなものの末に、意識のフローを愚直に書いても間に合う程度のリソースが備わっている可能性があります。
そのフローを書くに値しない確立論等を使わなくてもある程度目標を達することが可能でしょう。
そこに賭けて、愚直にフローを書くことが結果的に長寿を生むでしょう。

#危ない話。
C++では、危ないことが二つあって、一つが「メモリスマッシュ」一つが「0で割り算をする」です。
やばいのがメモリスマッシュで、ダングリングポインタ等をキッチリデストラクションしないで放置してしまうとそこに触って構造が飛びます。
これは簡単な事なのに危険度がVeryHighなのです。
0で割り算をするは、まぁ、基本的には数値計算の話なのでハードよりもアルゴリズムの問題ですが、0で割るとエラーを起こしてフローが飛びます。
ハードが物故割れるよりはマシですが、人理にとっては悪い話です。
C++にとって算術とは、スタック上で行われる演算でしかないです。その中で行われる以上コンパイラが壊れてなければハードを破壊しにいくリスクはほぼ無いです。とにかく、メモリスマッシュだけはやめてください。

#計算限界
数値Nが数で表現される以上数学の範疇ですが、その数学を「多倍長浮動小数点数」数百万オペレーターで計算してそれを乗り越えた程度のモノを運用しなければ、100年生きることは不可能でしょう。
巨数計算はもう手のひらに載っているのです。
なのであえて言いますが、

「お前のちんけな割り切りなど数学の前では無力。フハハハハハ。」

お後がよろしいようで。

#無限
とある観点では、「無限」とは640Bitで表される数字の事だそうです。たった80バイトです。簡単ですね。

#終わりに
最後に残るものは正しいモノですが、筆者にとって正義は「アリスマティック」つまり算数です。
私には、割り算がビルトインされていません。なので遅いのですが、しかし、アリスマティックの固さによっていろんなものを支えてもらっています。アリスマティックが壊れると世界の根幹が壊れるのでほんと怖い話ですよ。

半端な割り切りを入れたらあなたの娘は狂います。

よろしくお願いいたします。

#最後に
```C++:CrashABCProblem.Cpp
#include <iostream>
#include <cstdint>
#include <vector>
#include <algorithm>
#include <limits>
#include <numeric>

typedef std::vector<std::uintmax_t> DType;

DType PrimeFacterlizer(std::uintmax_t N) {

	DType R;
	for (std::uintmax_t i = 2; i <= N; i++) {
		if (N % i == 0) {
			R.push_back(i);
			N /= i;
			i--;
		}
	}

	return R;
}

std::uintmax_t Radical(std::uintmax_t N) {
	auto R = PrimeFacterlizer(N);

	std::sort(R.begin(), R.end());

	R.erase(std::unique(R.begin(), R.end()), R.end());

	std::uintmax_t V = 1;
	for (auto& o : R) {
		V *= o;
	}
	
	return N;

}

bool CrashABCProblem(double Epsilon) {//not debug complete

	for (std::uintmax_t C = 1; C <= std::numeric_limits<std::uintmax_t>::max(); C++) {
		for (std::uintmax_t B = 1; B < C / 2; B++) {
			std::uintmax_t A = C - B;
			if (std::gcd(A, B) != 1) { continue; }
			if (std::gcd(A, C) != 1) { continue; }
			if (std::gcd(B, C) != 1) { continue; }
			auto R = Radical(A * B * C);
			double X = std::pow(R, 1 + Epsilon);
			if (X < C) {
				std::cout << "A:" << A << ",B:" << B << ",C:" << C << ",Rad:" << R << std::endl;
			}
		}
	}
	return true;
}

int main() {
	std::uintmax_t N = 2 * 2 * 3 * 3 * 5 * 7;
	auto R = PrimeFacterlizer(N);

	for (auto& o : R) {
		std::cout << o << ',';
	}
	std::cout << std::endl;

	std::cout<<Radical(N) << std::endl;

	CrashABCProblem(0);
	return 0;
}
```
KivyアプリをBuildozerを使ってapkファイルにする（Ubuntu）

# はじめに
機械学習を使ったAndroidアプリを作ろうと思っていて、
Pythonでアプリが作れるKivyが便利なので使っていたが、
Kivyアプリをapkファイルにするときにいろいろハマったのでうまくいった手順をメモ。

# 環境
- Ubuntu Server 20.04　※AWSの無料枠で使用できるEC2インスタンスを使ったが、デフォルトの設定だとストレージが足りなくなるので、ストレージの容量を16GBにする
- Kivy 11.1
- Buildozer 1.2.0

# 手順
## 必要なパッケージをインストール

```terminal
sudo apt update
sudo apt upgrade
sudo apt install -y git zip unzip openjdk-8-jdk python3-pip autoconf libtool pkg-config zlib1g-dev libncurses5-dev libncursesw5-dev libtinfo5 cmake libffi-dev libssl-dev
pip3 install --user --upgrade Cython==0.29.19 virtualenv

export PATH=$PATH:~/.local/bin/

# buildozerのインストール
pip3 install --user --upgrade buildozer
```

## apkファイルの作成
Kivyアプリが入っているプロジェクトフォルダに移動して、以下のコマンドを実行する。
成功すると、プロジェクトフォルダのbinフォルダ内に、apkファイルが作成される。

```terminal
# buildozer.spec（設定ファイル）を作成
buildozer init

# デバッグモードのアプリを生成
buildozer android debug
```

# 参考
- https://buildozer.readthedocs.io/en/latest/installation.html#android-on-ubuntu-20-04-64bit
Network エミュレーション

# Netem
Network の検証でたまーに遅延による影響を評価したくなることがある。いわゆる Network エミュレーション。遅延とかパケロスとかを発生させて上位レイヤがどう動くかを評価する。

データセンター内だとこの辺りはあまり問題にならない。でも、WAN 部分だと結構な影響が出てくる。音声通信の品質とか、End-End での死活監視タイマとか。当然こういった検証をするための遅延エミュレータもあるんだけれど、買うとなるとそれなりのお値段がする。

このあたり、お家で遊べないかなと調べてみたら、Linux では Netem というツールで実現できる様子ことが分かった。この手の装置はL2で使いたい。遅延装置にアドレス振ってしまうと Network の論理トポロジが崩れてしまうから。なので、Linux の Interfaceをブリッジで動作させ、そこを通過するパケットに対して遅延を発生させてみた。

# 検証条件
* Ubuntu 20.04 on GNS3 2.2.9

遅延を起こすこと自体に必要な Netem 自体はUbuntu 18.04でも20.04でも最初から入っていた。そんな大事ではなさそう。微量のトラフィック印加であれば特にCPU高騰などといったことはなかった。

## 検証構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409463/2277507e-cda1-0ff3-bcda-6ddd4d302b9b.png)

遅延サーバには Interface を3つ持たせた。遅延サーバ自体にアクセスするためのInterfaceが一つと、L2で透過させるための2 Interface が必要になる。ens4/5をブリッジとして動作させる。

### ブリッジで動作させる
```console
sudo apt install bridge-utils
sudo ip link set ens4 promisc on
sudo ip link set ens5 promisc on
sudo brctl addbr br0
sudo brctl addif br0 ens4
sudo brctl addif br0 ens5
sudo ip link set br0 up
```
### 遅延設定
例えばこんな感じ。

```console
sudo tc qdisc add dev ens4 root netem delay 100ms #ENS4から入るパケットに100msの遅延を印加
sudo tc qdisc del dev ens4 root #遅延設定を削除
```
TCの使い方は、[tcコマンドの使い方](https://qiita.com/hana_shin/items/d9ba818b49aca87b2314)など、 多くの方がドキュメントを残して下さっているのでそちらを参照。

#### 見え方
```console
vyos@EoR1a:~$ ping 10.0.0.2
PING 10.0.1.1 (10.0.1.1) 56(84) bytes of data.
(snip)
64 bytes from 10.0.0.1: icmp_seq=135 ttl=64 time=0.869 ms
64 bytes from 10.0.0.1: icmp_seq=136 ttl=64 time=0.961 ms
64 bytes from 10.0.0.1: icmp_seq=137 ttl=64 time=1.19 ms
64 bytes from 10.0.0.1: icmp_seq=138 ttl=64 time=1.26 ms
64 bytes from 10.0.0.1: icmp_seq=139 ttl=64 time=100 ms    # ここから遅延が乗ってきた
64 bytes from 10.0.0.1: icmp_seq=140 ttl=64 time=101 ms
64 bytes from 10.0.0.1: icmp_seq=141 ttl=64 time=101 ms
```
基準となるセルから、縦横に延長（空白セルまで）する

# コードの処理内容

スプレッドシートをインスタンス化する
操作したいシートであるIndexをインスタンス化する
※対象シートに存在する情報全件を取得するメソッドはgetDataRangeとなる
基準となるセルをインスタンス化する
基準となるセルから、縦横に延長したデータ範囲を選択し、かつその範囲の情報を二次元配列で取得する
取得した二次元配列の要素をログ出力する
取得した二次元配列の要素数（これは行数と対応関係にあります、各要素内の要素は列数と対応関係です）をログ出力する

```
function myFunction() {
  const Spread = SpreadsheetApp.getActiveSpreadsheet();
  const IndexSheet = Spread.getSheetByName('Index');
  //let range_values = IndexSheet.getDataRange().getValues();
  const index_range = IndexSheet.getRange(1,1);
  let range_values = index_range.getDataRegion().getValues();
  console.log(range_values);
  console.log(range_values.length);
}
```
Firestoreでimportする際、権限エラーでハマった

# 経緯
Firestoreのデータを別のプロジェクトに移すため、下記を参考に作業したがimportコマンドで権限エラーが出てハマった。そのときの対処メモ。

データのエクスポートとインポート
https://firebase.google.com/docs/firestore/manage-data/export-import?hl=ja

Cloud Firestore の import / export やってみた
https://qiita.com/star__hoshi/items/b500e6350f2ff8e991db

# 事象
gcloudコマンドでimportを打つとこんな感じのエラーが出る。
([BUCKET_NAME],[EXPORT_PREFIX],[firestore-projectid]は読み替えてください)

```
C:\Program Files (x86)\Google\Cloud SDK>gcloud firestore import gs://[BUCKET_NAME]/[EXPORT_PREFIX]/
ERROR: (gcloud.firestore.import) PERMISSION_DENIED: Service account does not have access to Google Cloud Storage file: [BUCKET_NAME]/[EXPORT_PREFIX]/[EXPORT_PREFIX].overall_export_metadata. See https://cloud.google.com/datastore/docs/export-import-entities#permissions for a list of permissions needed. Error details: [firebase-projectid]@appspot.gserviceaccount.com does not have storage.buckets.get access to the Google Cloud Storage bucket.
```

# 対処
こちらに書いてあるとおり、移行先の[firebase-projectid]に権限付与が必要でした。

プロジェクト間でデータを移動する
https://firebase.google.com/docs/firestore/manage-data/move-data?hl=ja#give_the_destination_project_access_to_your_data_files

```
gsutil iam ch serviceAccount:[firebase-projectid]@appspot.gserviceaccount.com:admin gs://[SOURCE_BUCKET]
```

このコマンド実行後にimportを打つとデータ移行できました。
最初からこの記事を見ていれば問題なかったですね。。

## コマンド例
パラメータが下記の場合。

- [firebase-projectid]：firebase-test
- [SOURCE_BUCKET]：gcpstrage-test

```
gsutil iam ch serviceAccount:firebase-test@appspot.gserviceaccount.com:admin gs://gcpstrage-test
```

# その他
Firebaseプロジェクトを有料プランに移行する、FirebaseプロジェクトとGCP Strage Bucketのリージョンは一致させる、作業用アカウントにも権限つけるなど注意することが色々あり、予想以上に大変でした。。
[メモ]体系的に学ぶ 安全なWebアプリケーションの作り方

[体系的に学ぶ 安全なWebアプリケーションの作り方](https://www.amazon.co.jp/%E4%BD%93%E7%B3%BB%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B6-%E5%AE%89%E5%85%A8%E3%81%AAWeb%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9-%E8%84%86%E5%BC%B1%E6%80%A7%E3%81%8C%E7%94%9F%E3%81%BE%E3%82%8C%E3%82%8B%E5%8E%9F%E7%90%86%E3%81%A8%E5%AF%BE%E7%AD%96%E3%81%AE%E5%AE%9F%E8%B7%B5-%E5%BE%B3%E4%B8%B8-%E6%B5%A9/dp/4797361190)を読んだメモ

# XSS
- 悪意のあるサイトにリダイレクトして重要情報を入力させる
- スクリプトを埋め込んで重要情報をURLに引き継いで悪意のあるサイトに遷移する

対策

- エスケープする
- JSで文字列を動的に生成するときも注意。JSでエスケープするか、hidden要素などでHTML側でエスケープしておいた要素を使用する

# SQLインジェクション

対策

- プレースホルダーを使用する
- Like検索ではワイルドカードをエスケープする
- 攻撃者に情報を与えないためにエラーメッセージを抑制する
- 攻撃の被害を抑えるためにデータベースの権限を最低限にする

# CSRF
- 悪意のあるサイトにアクセス → ifameから正規のサイトへPOST → ログイン状態の場合セッションIDがつくのでPOSTできてしまう
- 確認画面があるようなサイトでもifameの数を増やし、時差でアクセスすることで攻撃可能
- 内部ネットワークでもルーターなどを管理者情報を持った端末が罠サイトを踏むとパスワードなど変更される恐れがある

対策

- 購入、変更など重要ページでは再度パスワードを入力してもらう
-実行直前のページに攻撃者が予測できないトークを入れて実行画面で確かめる
- リファラーのチェック（自サイトからになっているか）

# セッションハイジャック
- セッション情報をURLに埋め込んでいるとサイトから別サイトに遷移した時にリファラーで漏洩する

# オープンリダイレクタ脆弱性
実装でリダイレクト先のURLを外部から指定できる場合に発生
- 罠サイトにリダイレクトされる
- 配布サイトでマルウェアを配布されるなど

対策

- リダイレクト先のドメインチェックをする
- クッションページを挟む(あなたは...にアクセスしようとしています)

# メールヘッダーインジェクション
- webサイトのフォームなどから意図しない相手にメール送付される
- 本文を改ざんされる

対策

- 改行を含まないようにする
- 外部からのパラメーターを含ませない

# ファイルダウンロードによるxss
- jsファイルをhtmlと認識させユーザーのブラウザーで実行させる

対策 

- content typeを設定するなど
[初級者向け]SwiftUIでrootViewをContentViewから任意のViewに変更しよう

## ContentViewから任意のViewに変更しよう
### 環境
- Xcode11.5
- Swift5
- SwiftUI

### この記事で何をしようとしているか
Xcodeから新規プロジェクトを作成後、デフォルトで設定されているContentViewを自分の好きなViewに変更したい。
例えば, ContentView -> RootView, LoginView等

<img width="1437" alt="Screen Shot 2020-06-14 at 18.12.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195876/e356de4c-2273-0349-2380-1e8272a80d03.png">


### 1. 任意ファイルを作成
File > New > FileからSwiftUIを選択して、新しいファイルを作成します。今回はファイル名を"RootView"とします。

<img width="1432" alt="Screen Shot 2020-06-14 at 18.14.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195876/37f3cb3c-d489-6504-b6cc-34a1ebcbb4d6.png">

下図のようにRootView.swiftファイルが作成できたことが確認できます。
<img width="264" alt="Screen Shot 2020-06-14 at 18.25.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195876/ab4bf2fe-2a61-48b8-bd34-8f5c3257698b.png">



以下、作成したRootView.swiftのコード

``` RootView.swift
import SwiftUI

struct RootView: View {
    var body: some View {
        Text("Root View なんだぜ〜")
    }
}

struct RootView_Previews: PreviewProvider {
    static var previews: some View {
        RootView()
    }
}
```

### 2. SceneDelegate.swiftを編集
``` SceneDelegate.swift
import UIKit
import SwiftUI

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).

        // Create the SwiftUI view that provides the window contents.
        // 以下、作成したViewを指定
        // let contentView = ContentView()
        let rootView = RootView()

        // Use a UIHostingController as window root view controller.
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            // contentView -> rootView
            window.rootViewController = UIHostingController(rootView: rootView)
            self.window = window
            window.makeKeyAndVisible()
        }
    }

 // ...  以下、不要なので省略

}

```

### 3. シュミレータまたは実機で実行
下図のように、RootViewに変更できていることがわかります。
<img width="338" alt="Screen Shot 2020-06-14 at 18.22.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195876/2cac334f-371b-0f39-e462-9ecf9472ff73.png">


## ついでに
本記事のように、新規ファイルを作成せず、ContentView.swiftファイルを編集することもできます。
A列の中から特定の文字列がある行数を検索する

# 目的
スプレッドシートを編集する際に、列内に特定の文字がある前提で、その文字がある行数を検索したいと思い、考えました。

# 処理の流れ
処理対象としたいスプレッドシートオブジェクトのシートをインスタンス化する
A列の値を二次元配列で取得する
取得した二次元配列を一次元に変換する
位置を検索したい文字列が配列の何番目の要素であるかをindexOfを使って検索する
※配列のインデックスが０であり、かつシート列のインデックスが１であるため、シートの行数を求める時は要素数に＋１することで、行数と要素数を一致させます。

```
function searchInColumn() {
  const TargetSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('A-1');
  let A_column_values = TargetSheet.getRange('A:A').getValues();
  let convert_list = A_column_values.map(function (element) {return element[0]});
  // console.log(convert_list);
  let keyword_position = convert_list.indexOf('# Option') + 1;
  console.log(keyword_position);
}
```
An error occurred while installing json (2.3.0), and Bundler cannot continue

#初めに
これが本当に正しい修正方法かは疑問ですが、
少し戸惑ってしまったり悩んでしまったのでここに記述します。

対応としては、使用Rubyのバージョン変更です。
色々言われた通りコマンド打ってもうまくいかなかったので、、、

#エラー

`$ bundle install`として出るエラー

```
Gem files will remain installed in /Users/***/sample/vendor/bundle/ruby/2.6.0/gems/json-2.3.0 for inspection.
Results logged to /Users/***/sample/vendor/bundle/ruby/2.6.0/extensions/universal-darwin-19/2.6.0/json-2.3.0/gem_make.out

An error occurred while installing json (2.3.0), and Bundler cannot continue.
Make sure that `gem install json -v '2.3.0' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  cocoapods was resolved to 1.9.3, which depends on
    cocoapods-core was resolved to 1.9.3, which depends on
      algoliasearch was resolved to 1.27.3, which depends on
        json
```

#対応
言われたコマンドを色々打って見てもダメだったので使用するRubyのバージョンを変更しようと思いました！
結果通りました！

以下参考にさせていただきました！
[犬でもわかるRuby on Rails 環境構築 for MacOS](https://qiita.com/kyaneism/items/9750b41530b034c43495)

ですが、パスを通してもダメでした、、
結論通すパスが間違っていました。
変わったのでしょうか？
私の場合は以下を通すべきでした。

`$ echo 'export PATH="$HOME/.rbenv/versions/2.7.1/bin:$PATH"' >> ~/.bash_profile`

なのでbash_profileに記述されるはずのものは以下。
`export PATH="$HOME/.rbenv/versions/2.7.1/bin:$PATH"`

`$ source ~/.bash_profile`
の反映処理も忘れずに。

`$ open $HOME/.rbenv`で開いたらbinフォルダがないことで発覚。

っというかPATH指定しないと変えられないってこれからその都度パス指定しなおさないといけないの？？？

と言ってもこれRubyのバージョンあるところ指定しているだけのような気も、、、


ちなみに、

~/.bash_profileに

```
eval "$(rbenv init -)"
export PATH="$HOME/.rbenv/shims:$PATH"
```

って書かないと

`$ rbenv local 2.7.1`
`$ rbenv versions`

の切り替えはうまく行きませんでした、、、

ただこれ、

`$ rbenv global 2.6.0`
しても
`$ ruby -v `
グローバル変わらない、、、

`$ which ruby `の出力もOKそう。あ、最終的にこれではあれなのでここも変わりますが以下操作で、、、
/Users/***/.rbenv/shims/ruby

以下みたいに直接指定なら変わる、、、

~/.bash_profileに

```
export PATH="$HOME/.rbenv/versions/2.7.1/bin:$PATH"
```

`$ rbenv global 2.6.0`
的なので変わらないのなんでだろう、、、
直に指定しないと、新しい　→　古い　出来ないのでしょうか?

また何か分かったら追記します🙇‍♀️
pythonでbigqueryのデータセットとテーブル一覧を抜き出してCSV出力する

A列にデータセット名、B列にテーブル名が記載されたCSVを出力します。
対象のprojectはターミナルで以下を打ち込んだ際に表示されるプロジェクトとなります。

```
gcloud config list
```

コード

```.py
import datetime
import pandas as pd
from google.cloud import bigquery

bigquery_data = pd.DataFrame(
    index   = [] ,
    columns = ['dataset','table']
)

client = bigquery.Client()
datasets = list(client.list_datasets())
project = client.project

for dataset in datasets:
    dataset_id = '{}.{}'.format(project , dataset.dataset_id)
    dataset = client.get_dataset(dataset_id)
    tables = list(client.list_tables(dataset))
    for table in tables:
        dataset_table = pd.Series({'dataset' : dataset.dataset_id ,'table' : table.table_id})
        bigquery_data = bigquery_data.append(dataset_table , ignore_index = True)
make_day = datetime.datetime.today().strftime('%Y-%m-%d')
bigquery_data.to_csv('bigquery_data_{}.csv'.format(make_day) , index = False)

```
Windows 10にZIP版Pythonとpipをインストール

# 初めに
WindowsでPythonを使いたいけど余計なものは入れてくれるなという私向けの記事です。
多分普通にインストーラでもそんなに入るものは変わらないと思う。

# PythonのZIP版をダウンロード
公式よりWindows用Pythonをダウンロードする。
https://www.python.org/downloads/windows/

私はPython3.7の64bit版が欲しかったので以下をダウンロードしました。
> Note that Python 3.7.6 cannot be used on Windows XP or earlier.
> ・Download Windows x86-64 embeddable zip file

# 好きな場所に展開
私は `%USERPROFILE%\bin` にアプリケーションをインストールするという運用をしているので`%USERPROFILE%\bin\python3` に展開しました。

# Pythonのパスを通す
環境変数のPATHに展開したPythonの展開パスを追加する。

```:例
%USERPROFILE%\bin\python3
```

Windows 10の場合はpythonコマンドでMicrosoft Storeが起動してしまう場合があるので
Pythonのパスを `%USERPROFILE%\AppData\Local\Microsoft\WindowsApps` より前に設定する必要があります。


# pipをインストール
インストーラ版を使えばpipを楽に入れられるようですがZIP版にはpipが入っていません。
公式ドキュメントにインストール方法が書いてありました。
https://pip.pypa.io/en/stable/installing/
https://bootstrap.pypa.io/get-pip.py をダウンロードして実行すればいいみたいです。

```
python get-pip.py
```

# pipのパスを通す
環境変数のPATHにpipのパスを追加する。

```
[Pythonの展開パス]\Scripts
```

# import siteを有効化
そのままだとpipが正しく起動しないので`[pythonの展開パス]\python37._pth` を編集して `import site` の行を有効化する。

```diff:python37._pth
python37.zip
.

# Uncomment to run site.main() automatically
- #import site
+ import site

```

# 最後に
私はvimのプラグインが使いたくてPythonとpipをインストールしたので以下のようなコマンドを実行して動作確認しました。

```
pip install pynvim
```