OmniAICreator/Qiita-1.07M huggingface dataset:
Garminを狙ったランサムウェア（WastedLocker）の話

# Garminのアップロード情報が閲覧できない（2020年7月25日時点）
私の日常生活において非常に困った事件が発生してしまいました…
それがスポーツおよびフィットネステック大手のGarmin（ガーミン）社のシステムダウンです。

私はCOVID-19の影響を受け2020年4月より在宅ワーク中心の勤務形態に変わったことを契機に、学生の頃達成したフルマラソンのサブ4をもう一度達成したいというモチベーションで月間最低150kmを目標にランニング継続中であり、この全記録をランニングウォッチからGarminに蓄積しております。

![つなぐ場用.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640480/f781f6ac-5e20-fd1d-8f09-0cde852092a2.png)

7/23のお昼ごろから専用アプリにてサーバメンテナンス中の表示が…
珍しい時間にメンテナンスするんだな～程度に思ってましたが、夜になっても翌朝になってもメンテナンス中のまま…
何かおかしいぞ？と思い、Web検索してみると、なんとランサムウェアによるサイバー攻撃を受けてる！！

![つなぐば2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640480/bd2b68df-8cdf-7638-8a35-1212cab81806.jpeg)

直近[EDRに関する記事](https://qiita.com/itoumke/items/ae5e452075a9ce997891)も書いている通り、セキュリティに対するアンテナが高めだったこともあり、今回Garmin社が標的となったWastedLockerというランサムウェアについて簡単に整理してみます。

# なぜGarminが標的に？
2020年7月23日が何の日だったか、皆さんご存知でしょうか？

そう！
COVID-19が猛威を振るっていなければ_東京オリンピック_の開会式の日です！

仮に現在東京オリンピックが開催中だった場合、Garminが使用不能になることによるアスリートへの影響は甚大なものがあったことが予測され、Garmin社は解読鍵を入手するために必要な大金を支払わざるをえない状況に追い込まれるだろう、というハッカー側の目論見があったのでは？という憶測もあるようです。

# WastedLockerの話
### 攻撃者は？
Evil Corpと名乗っているサイバー犯罪集団。
現在も猛威を振るっている「Dridex」や「Bitpaymer」といったランサムウェアを利用して、様々な国の銀行や金融機関から1億ドル以上を身代金として盗んだと言われている。

### どんなウイルス？
2020年4月頃に攻撃が報告されているランサムウェアで感染時に企業データを暗号化し（WastedLockerという名前は暗号化時に「wasted」の文字列が付与されることに起因する）、暗号化されたファイルごとに下記のようなファイル名に「_info」が追加されたファイルが作成され、身代金が要求される。
![safe_wasted_ransom_note.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640480/c9a70619-10df-ea1c-b825-eba378bfaccc.jpeg)

[WastedLocker Ransomware: Abusing ADS and NTFS File Attributes](https://labs.sentinelone.com/wastedlocker-ransomware-abusing-ads-and-ntfs-file-attributes/)
[Evil Corp’s WastedLocker Demanding Millions of Dollars for Decryption](https://securityboulevard.com/2020/07/evil-corps-wastedlocker-demanding-millions-of-dollars-for-decryption/)


### 侵入の仕方は？
WastedLockerのマルウェアプログラムの実行における初動は標的型メールといった原始的な手段のようである。
キーとなる攻撃技術要素としてはSocGholishとCobaltStrikeが挙げられる。

* SocGholish：JavaScriptベースのフレームワークで、システムまたはソフトウェアの更新を装い、不正プログラムの実行する
* CobaltStrike:Lateral Movement Framework（水平移動フレームワーク）の一種。NW内の接続端末にマルウェア感染を拡げる

### 防ぎ方は？
標的型攻撃に対する対策としては以下のようなことが挙げられる。

* 疑わしいメールに対するNW境界防御
* OSやアプリケーションの脆弱性対策
* ウイルス対策ソフトの最新化
* 社員に対する訓練

だが、近年高度化している標的型攻撃に対して完全な対策を講じることは難しい。
そこで感染することを前提として、早期に検知/対処するソリューションとして、EDR製品が有効となる。

また、基本的なことではなるが、万が一攻撃を受けデータが暗号化されてしまったとした際に、別NWにデータバックアップを取得することもサービス復旧の観点で重要である。

# まとめ
DX化が進む中、高度化したサイバー攻撃に対して、なんとなくのセキュリティ対策ではなく、どのような攻撃があるのかを知っておくことは重要である。必要に応じたセキュリティ対策を提案できるよう最低限の知識を身に付けておきたい。

今月の月間走行距離が分かるよう、Garminが早く復旧しますように…
[初心者向け]KotlinのRecyclerViewのテンプレート

# Kotlinで一覧機能を作りたい方向け
RecyclerViewの鋳型（ボイラープレート）です。
一覧機能を作りたい場合に、Adapterとか0から作らなくてもこちらのソースをお使いいただければ楽かなと思い作成しました。

2020/7/25時点でローカルで検証し正常に動作することを確認済みです。(Android Studio 4.0)

ソースコードはこちらからダウンロードいただけます。
https://github.com/kzytech/recyclerViewBoilerplate

## recyclerView デモ
![Diagram](https://res.cloudinary.com/dyrbzxv2c/image/upload/v1595655758/demo.gif)

※MainActivity.ktの20行のcreateUsersList()内の数値を変えると生成されるアイテムの数を変更できます。

## recyclerView フロー図
![Diagram](https://res.cloudinary.com/dyrbzxv2c/image/upload/v1595654759/Untitled_Diagram.png)
Gitに管理されたファイルを削除したい

.gitignoreに書き忘れてcommitしてしまった時に、
「.gitignoreに追記すれば大丈夫...」
と誤解していませんか？
僕のように..汗

後から.gitignoreに追記するだけではすでにGitに管理されたファイルは除去されないので、そんな時の対処方法を書いておきます。


# Gitに管理されたファイルを残して除外したい場合
```
$ git rm --cached [除外したいファイル名]
```
その後は必ず`.gitignore`に除外したいファイルを追記する。
注意箇所：
`--cached`を必ずつける！！
つけないとファイルごと削除してしまいます。


# ファイルごと削除したい場合
```
$ git rm [削除したいファイル名]
```

# ディレクトリごと削除したい場合
```
$ git rm -r [削除したいディレクトリ]
```


# 最後に
Gitを使い始めた時に何回か忘れてcommitして、都度調べていたので備忘録として残しておきます。

同じ境遇になった方のお役に立てば嬉しいです。
キャッシュサーバーとコンテンツサーバーの違い

この記事では2種類のDSNサーバーについて解説しています。

#DNSサーバーとは？

**D**omain **N**ames **S**ystemの略で、インターネット上に存在するホストのIPアドレスを教えてくれるサーバーのこと。


#DNSサーバーには2種類ある
あまり意識することがないかもしれないが、DNSサーバーには大きく以下の２種類がある。

・ **キャッシュサーバー（別名：フルサービスリゾルバ）**

・ **コンテンツサーバー（別名：権威DNSサーバー）**

#キャッシュサーバーとは？

- クライアントPC(正確にはブラウザによって呼び出されたスタブリゾルバという検索プログラム)からの質問を受け付けるDNSサーバーである。
- PCからの質問（名前解決要求）に基づき、結果が得られるまでひたすら名前解決処理をやり続ける

- 名前解決を行う「リゾルバ(フルサービスリゾルバ)」が、何度も同じ名前解決の処理をしないで済むように結果をキャッシュしているため「キャッシュサーバー」と呼ばれる。

- 我々が普段アクセスしているのは、キャッシュサーバーとしての役割を付与されたDNSサーバーということになる。

- キャッシュサーバーは後述するコンテンツサーバーに対して問い合わせをして、IPアドレス情報の回答を得るようにしている。

#コンテンツサーバーとは？

- 名前解決要求に対する回答に責任を持つDNSサーバーである。

- 権威サーバーと呼ばれることもある。

- コンテンツサーバーは、常に自身の管理するホスト名とIPアドレスについて、最新の情報を保持していなければならない。これは人間が手作業でやる必要があり、コンテンツサーバーの管理者は、ホスト名とIPアドレスの対応表を作成してコンテンツサーバーに登録しておく必要がある。
Pythonのエラー 'shift_jis' codec can't encode character '\u6c2e' の解決方法 

#はじめに
　備忘録のために書くので、余計なことは書きません。Pythonでテキストファイルにある文字を別のテキストファイルに移す処理を書いていたら

```
'shift_jis' codec can't encode character '\u6c2e' 
```
というエラーが返されました。どうやら文字のエンコードのエラーらしいです（勉強不足です）
特定の文字だけをreplaceして消す方法もあるようなのですが、種類が多すぎて面倒です。

#解決法
　対象のPythonコードの初めにこれを記述してください。

```
import codecs
codecs.register_error('none', lambda e: ('?hoge?', e.end))
```

そして、ファイルを開く処理のopen関数を以下の様に変更してください。

```
f = open('file.txt', 'w', encoding='cp932', errors='none')
```

そうすれば、エンコードできない文字だけ?hoge?と置き換わります。消したい場合は'?hoge?'を''にすればOKです。

#参考サイト
　まじで助かりました。ベストアンサーのkatsukoさん、ありがとうございます。

・(python3でshift_jisのテキストファイル保存でUnicodeEncodeError)[https://teratail.com/questions/38949]
DCL The Game のレース結果を自動的に Slack に投稿する

こんにちわ。ドローンおじさんです。[Drone Champions League (DCL)](https://dcl.aero/) というヨーロッパ各地でドローンレースを開催しているプロリーグがあります。その DCL から発売されているドローンレースシミュレーター、[DCL The Game](https://www.google.com/search?q=DCL+The+Game)（Steam、PS4、Xbox 版あり〼）のレース結果を自動的に取得して Slack に投稿するっていう、スーパーニッチなプログラムの解説を書いておきます。

# どういうこと？　

↓こういうのがレース後に出る。
![file.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2595/f5e2326e-1459-99e4-ccc7-f0a945c837b9.jpeg)
それが↓みたいに投稿される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2595/571fd2ea-8311-2ec1-43e4-e9c86d5560e4.png)

# どうやってんの？

1. 定期的に画面キャプチャする。
2. レース結果画面かどうかを判定する。
3. タイムとかパイロット名とかを取得する。
4. Slack に投稿する。

## 1. 定期的に画面キャプチャする。

プログラム全体は Python で書いてるので、画面キャプチャは PIL の ImageGrab で。DirectX フルスクリーンのでも普通にちゃんと取れる。PIL の Image オブジェクトになってるので後処理もやりやすい。

>[Python][Windows] Pythonでスクリーンキャプチャを行う
>https://qiita.com/koara-local/items/6a98298d793f22cf2e36

## 2. レース結果画面かどうかを判定する。

ちまちまピクセル解析すんのはダルいので、[AutoML Vision](https://cloud.google.com/vision) の Single-Label Classification で機械学習。

ゲーム内容をビデオキャプチャしたあとに 1 秒ごとにフレーム書き出し小さめにリサイズ。

```
ffmpeg -i capture.mp4 -vf scale=256:-1 -vcodec png -r 1 images/%05d.png
```

手動で分類、ラベル付け → Cloud Storage にアップロード → トレーニング、、てかチュートリアル↓まんま。
https://cloud.google.com/vision/automl/docs/edge-quickstart

必要なのは `flow-result-complete` ラベルだけなんだけど、他のシーンにもラベルつけてみた。数がだいぶ偏ってる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2595/e8aa57af-348e-e629-3287-1095ecbca5d4.png)

トレーニング後。過学習っぽい気がしないでもない🤔（実際のところ問題なし）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2595/bb794fa7-0fa4-a5ee-1ac6-0750cab7dde3.png)

モデルをダウンロードして Docker 上で動かす。REST API で画像送れば推論結果が JSON で返ってくる。
https://cloud.google.com/vision/automl/docs/containers-gcs-tutorial

内部的には TensorFlow が動いてるんだけど、ここまでまったく TensorFlow 絡みのコード書いてない。PIL でイメージ読んで HTTP リクエストしてるだけ。精度問題なし。学習時間 2 時間ぐらい。API 利用料 600 円ぐらい。ラクチン！

## 3. タイムとかパイロット名とかを取得する。

結果画面が取得できたら、あとはそこから必要な情報を抜き出す。画像から文字情報を抜き出すには OCR。Python で OCR なら pytesseract が定番？ [Vision API には OCR もあって](https://cloud.google.com/vision/docs/ocr)そっちのが精度はいいんだけど今回は読み出す内容がすごくシンプルなので pytesseract で事足りた。

ふつうに全画面を pytesseract に食わせるとわけわからんデータが返ってくるので、必要なとこだけ切り出した画像を食わせる。あと背景白で文字黒のほうが精度高いっぽいので白黒反転させる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2595/b2f28cdd-cea3-17da-7967-a9851e7a1ca6.png)
英数字だけならほぼ間違わずに読み取れる。たまにパイロット名に英数字以外つかってる人いると間違う。（しらん人なので無視😅）

### ステータスアイコンも読み取る。

人間が足りないときは過去の人間のリプレイがゴーストとして登場。どれがゴーストかは結果画面のアイコンでわかる。これを読み取るのには、アイコン表示位置を切り取ったあと [scikit-image の structural_similarity](https://scikit-image.org/docs/stable/auto_examples/transform/plot_ssim.html) で比較して判定。接続が切れたときのアイコンも判定。


## 4. Slack に投稿する。

必要な情報が取得できたらあとは整形して投稿。画像つきで投稿するときは [chat.postMessage](https://api.slack.com/methods/chat.postMessage) じゃなくて [files.upload](https://api.slack.com/methods/files.upload) ね。

# 何につかうん？

Slack に投稿するだけだとまだイマイチなんだけど、Spreadsheet とかにつっこんでいくようにするといろいろ集計できて、チーム練習が捗るんですよ😉
クリックイベントを取り消す処理について

クリックしたらドロップダウンでメニューが出てくるのをjQueryで実装していたのですが、それを消すためのイベントについての話です。

https://gyazo.com/32762b0a4613e5b455de93f3db394050

右の▼または画像をクリックするとドロップダウンメニューが出てきて、その後どこかをクリックすると消える、という物です。

# blurではできなかった。
ドロップダウンメニューが消えずにずっと残っていた。邪魔。

```erb:navbar.html.erb
          <li class="nav-item dropdown" id="nav-bar__dropdown">
            <%= link_to '#',class: "ml-2 tip-accoount",id:'nav-bar__account' do %>
              <%= image_tag 'sample-account.png',class: "navbar__profile-icon" %>
              <span class="caret">
                <%= icon('fas','caret-down') %>
              </span>
            <% end %>
            <div class="dropdown-menu dropdown-menu-right">
              <%= link_to '管理ページ','#' ,class:"dropdown-item ajax-link" %>
              <%= link_to 'ログアウト','#' ,class:"dropdown-item ajax-link" %>
            </div>
          </li>
```

```js:navbar.js
  $("#nav-bar__dropdown").click(function(){
    $("#nav-bar__dropdown").children(".dropdown-menu").toggleClass("show");
  });
  $("#nav-bar__dropdown").blur(function(){
    $("#nav-bar__dropdown").children(".dropdown-menu").removeClass("show");
  });
```

#結論：blurではなくfocusoutを使う

blurではその要素自体にしか適用されないので、子要素に適用するにはfocusoutを使わないといけない、とのことです。

```js:navbar.js
  $("#nav-bar__dropdown").click(function(){
    $("#nav-bar__dropdown").children(".dropdown-menu").toggleClass("show");
  });
  $("#nav-bar__dropdown").focusout(function(){
    $("#nav-bar__dropdown").children(".dropdown-menu").removeClass("show");
  });
```

#参考にした記事
https://developer.mozilla.org/ja/docs/Web/API/Element/blur_event
ライブ配信の仕組み

### ライブ配信
今盛り上がりを見せている「ライブコマース 」をご存知でしょうか？タレントやインフルエンサーがライブ動画を配信し、視聴者はリアルタイムに質問やコメントをしながら商品を購入できるという新しいEコマースの形。先行する中国では既に2時間で3億円を売り上げるようなインフルエンサーの実績も出てきており、日本でも関連するアプリが続々とリリースされています。

### ライブ配信の仕組み
ライブ配信は、一体どのような仕組みで行われるのだろうか。マイク／ビデオ・カメラで取り込まれた音声と映像は、エンコーダーによって符号化された後、ネットワークでライブ配信プラットホームのWebサーバーに送られる。そこからネットワークを通じて世界中に配信され、視聴者側のデバイスで音声と映像に復号化（デコード）されるという仕組みだ。
![図１](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633185/62dff6fd-270d-ce77-99d0-575aaf7cee19.png)

#### 通信プロトコル
- RTMP
- hls
- HTTP
- RTSP+RTP

#### 処理の流れ
- ビデオと音声をエンコードして、ライブ配信データをサーバに送るまでの処理(push streamという)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633185/e5d5f594-3df4-a584-2a14-581e97c4ba3c.png)

- サーバからライブ配信データを取得し、デコードをして視聴するまでの処理（pull streamとう）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633185/bfe1768c-4898-8806-c5c7-5ecc6a3227c5.png)



### クラウドのライブ配信ソリューション[Tencent Cloud LVB](https://intl.cloud.tencent.com/jp/product/LVB)

Live Video Broadcasting（LVB）はTencentの長年に渡るオーディオとビデオ技術プラットフォーム、およびグロバール・大規模な加速ノードとトップのオーディオとビデオ AI 技術により、開発者にプロフェッショナル、安定なライブブロードキャスト プッシュ、トランスコーディング、配信および再生サービスを提供し、低ディレー、超高画質、大規模な並列処理アクセス量のニーズを全面的に満たします。

以下の大きな特徴があります。

- iOS/Android/WebSDKを提供しているので、簡単にライブアプリを開発できる
- LVBは配信サーバCDN、トランスコードなど製品をまとめる製品で、サーバに簡単に構築できる。
- 低コスト

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633185/0dc9dd74-4103-d584-c229-bfba02a90473.png)



###  参考
- (强烈推荐)移动端音视频从零到上手 https://juejin.im/post/5d29d884f265da1b971aa220
- ライブ配信を支える技術と知識 https://engineer.dena.com/posts/2018.12/knowledge-for-livestreaming/
やらかしJS先生がみたMapをObject的に扱ってハマった話⭕❌

#Overview

過去にバグになってしまったものを忘れないよう書き留めておくシリーズです。
今回の題材はMapです。以下は私が最初にさらりと書いたコードです。
これを基に❌な部分を修正していきます。

```javascript

const map = new Map();

if (!map["1"]) {
  map["1"] = "⭕";
}

for(const {key, value} of map) {
  console.log(`key:${key}, value:${value}`);
}

```

#Target reader

- この結果がわからない方

#Prerequisite

- JavaScriptを一通り理解している
- 今回はChromeで実行したが、Node.js等、環境によって出力結果が異なることがあることに注意。

#Body

## 少しだけ言い訳をしたい:sweat_smile:

いつもはJSONでファイル出力することが多いため、どうしてもそのまま出力できるObjectを利用することが多い。
そんな折、ファイル出力ないものがあったので、久しぶりにMapを使ったらずいぶん忘れていただけ。
今はもう大丈夫なんで:rolling_eyes:

##答え合わせ

正解はこうなる。

```text:terminal
```

何も出ないが正解:joy:

そもそも、MapはMapにあるメソッドを使って値を扱い必要がある。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Map

>Map オブジェクトに対してオブジェクトプロパティを設定すると正しく動作しますが、混乱を催すことが考えられます。

要するに、Object的な扱いもできる故に、Mapにデータ入れたと思ったらハマりますよってことで。
詳しくは上記URL参照のこと。

ということで、Object的な扱いを一つ一つ是正していく。

```javascript

const map = new Map();

if (!map.has("1")) { // ❌ !map["1"]
  map.set("1", "⭕"); // ❌ map["1"] = "⭕";
}

for(const {key, value} of map.entries()) {
  console.log(`key:${key}, value:${value}`);
}

```

これで正しくMapのデータ構造にデータを入れれたはず…答えはこうだ。

```text:terminal
```

何も出ない:joy:

よく見ると、`of map`ではなく`of map.entries()`で`key-value`のペアを受け取らないといけなかった！

```javascript

const map = new Map();

if (!map.has("1")) { // ❌ !map["1"]
  map.set("1", "⭕"); // ❌ map["1"] = "⭕";
}

for(const {key, value} of map.entries()) { // ❌ map
  console.log(`key:${key}, value:${value}`);
}

```

これで正しくMapのデータ構造にデータを入れれたはず…答えはこうだ。

```text:terminal
> "key:undefined, value:undefined"
```

値がない:joy:

そういえば、`map.entries()`って`key-value`のペアだからオブジェクトから取り出しではない！

```javascript

const map = new Map();

if (!map.has("1")) { // ❌ !map["1"]
  map.set("1", "⭕"); // ❌ map["1"] = "⭕";
}

for(const [key, value] of map.entries()) { // ❌ map, ❌ {key, value}
  console.log(`key:${key}, value:${value}`);
}

```

これで正しくMapのデータ構造にデータを入れれたはず…答えはこうだ。

```text:terminal
> "key:1, value:⭕"
```

動いた:sob:


ちなみに、以下のように、値のセットをObjectとして処理し、存在チェックをMapで処理すると…

```javascript
const map = new Map();

map["1"] = "❌";

if (!map.has("1")) {
  map.set("1", "⭕");
}

for(const [key, value] of map.entries()) {
  console.log(`key:${key}, value:${value}`);
}

```

```text:terminal
> "key:1, value:⭕"
```

本来なら❌が出力され、⭕での上書きを防止するはずがそれを防げないという厄介なバグに発展するので要注意。

#Conclusion

**`Map`は`Object`と似ているように見えるが、使い方が異なるのでうろ覚えでの使用には注意！**
特に存在チェックとセットメソッドを混在して利用する等すると泥沼。
Dartのhttp_interceptorライブラリを使うと配列のクエリパラメータが消えてしまう件の応急処置

# tl; dr

- 2020年7月時点、dart:coreのUriクラスを使うとクエリパラメータで配列末尾以外の値が失われることがある

- [http_interceptor](https://pub.dev/packages/http_interceptor) ライブラリで発生することを確認

<!-- https://github.com/CodingAleCR/http_interceptor/blob/a88887a/lib/models/request_data.dart#L30 で `Request.url.queryParameters` を参照して、配列の末尾以外の値が抜けてしまっている。。 -->

- APIまわりのコードを[OpenAPI Generator (for Dart)](https://openapi-generator.tech/docs/generators/dart/)で生成していたので、Workaroundとして[QueryParameterのスタイル](https://swagger.io/docs/specification/serialization/#query)に `explode: false` 指定を追加  
※ QueryParameterの配列スタイルを `https://example.com/foo?ids=1&ids=2&ids=3` から `https://example.com/foo?ids=1,2,3` に変更


# 確認環境
- dart : 2.8.4
- http_interceptor : 0.3.2
- openapi-generator : 4.3.1


# 原因

dart:coreのUriクラスをStringから生成すると、配列として持っていたQueryParameterが末尾のみに変換されてしまう

```dart
final url = Uri.parse('https://example.com/foo?ids=1&ids=2&ids=3');

// https://example.com/foo?ids=1&ids=2&ids=3
print(url);

// {ids: 3}
print(url.queryParameters);
```

# 解決方法

## OpenAPI Generatorでコード生成している場合

#### 方針
dart:coreのUriクラス依存の問題のため修正を諦め、QueryParameterの形式を修正する。（クライアント/サーバそれぞれ問題なければ）

Before|After
---|---
`https://example.com/foo?ids=1&ids=2&ids=3`|`https://example.com/foo?ids=1,2,3`

OpenAPI/Swaggerの形式でQueryParameterの形式を修正するために、`parameters:` 以下に `explode: false` を追加する。

**Before**

```yaml
paths:
  "/foo":
    get:
      parameters:
        - name: ids
          in: query
          required: true
          schema:
            type: array
            items:
              type: integer
```

**After**

```yaml
paths:
  "/foo":
    get:
      parameters:
        - name: ids
          in: query
          required: true
          explode: false
          schema:
            type: array
            items:
              type: integer
```

OpenAPI/Swaggerを上記のように修正してコード生成するとQueryParameterで配列を `?ids=1,2,3` 形式で扱うようになり、Uriクラスで値が失われることを避けることができます。
動作確認リポジトリ：https://github.com/gyamoto/dart-http-query-param-trial

#### 補足

他にも `style` と `explode` の組み合わせで下記パターンの形式に変えることができます。

style | explode | Array id = [3, 4, 5]
---|---|---
form * | true * | /users?id=3&id=4&id=5
form | false | /users?id=3,4,5
spaceDelimited | true | /users?id=3&id=4&id=5
spaceDelimited | false |/users?id=3%204%205
pipeDelimited | true | /users?id=3&id=4&id=5
pipeDelimited | false | /users?id=3|4|5
deepObject | true | n/a


#### 参考
- Describing Query Parameters https://swagger.io/docs/specification/describing-parameters/#query-parameters
- Query Parameter Serialization https://swagger.io/docs/specification/serialization/#query

## その他の場合
_TODO: 解決法が見つかれば、いつか書くかも_
Buildroot の環境セットアップ

Buildrootのドキュメントだと、以下にMandatoryのPackageが書いてあるだけで、どうしたら良いか分からなかったので、メモです。

https://buildroot.org/downloads/manual/manual.html#requirement-mandatory

AWS環境で、AWSのコミュニティAMIの[Ubuntu Server 18.04](https://aws.amazon.com/marketplace/pp/Canonical-Group-Limited-Ubuntu-1804-LTS-Bionic/B07CQ33QKV) からセットアップしています

```shell-session
$ sudo apt-get update
$ sudo apt-get install build-essential ncurses-dev flex bison unzip python gperf
```
FreeRTOSスケジューリング性能測定

# 概要
FreeRTOSのスケジューリングレスポンス性能を測ってみる
# 事前知識
[FreeRTOSスケジューリング機能まとめ](https://qiita.com/azuki_bar/items/91e12949737f460dbc11)
[ARM Cortex-R5(Armv7-R) PMU使い方（パフォーマンス測定方法）](https://qiita.com/azuki_bar/items/1dd0a57a292ac1a074e4)
[FreeRTOS Debug, Utility系のTips](https://qiita.com/azuki_bar/items/9516066ce30b020d45d6)
#測定
以下、いくつかのパターンを測定します。
## 共通環境
#### FreeRTOSConhig.h

|Config|設定値|
|:--|:--|
|configUSE_PREEMPTION  |1|
|configUSE_TIME_SLICING|1|
|configUSE_PORT_OPTIMISED_TASK_SELECTION|1|
|configIDLE_SHOULD_YIELD|1|

この設定で行う。変更する場合は、各項目に記載する。
Configの意味は [FreeRTOSスケジューリング機能まとめ](https://qiita.com/azuki_bar/items/91e12949737f460dbc11) 参照。
### 評価ボード
Ultra96
https://www.96boards.org/product/ultra96/
http://zedboard.org/product/ultra96

CortexR5のsingle coreで測定
### ちゃんと測定できているか確認
タスク1つで1秒delayさせた前後で測定してみる。プリエンプトされるこないのでほぼ1秒が測定できるはず。
#### コード（測定部分のみ）
```c:main.c
unsigned long start, end;
static TaskHandle_t TaskHdlPri01;
static void TaskPri01( void *pvParameters ) {
	while(1) {
		start = pmon_start_cycle_counter();
		vTaskDelay(pdMS_TO_TICKS(1000));
		end = pmon_read_cycle_counter();
		xil_printf("time = %ld\r\n", end - start);
	}
}

int main( void )
{
    ...
    xTaskCreate(TaskPri00,"TaskPri00", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, &TaskHdlPri00 );
    ...
```
#### 結果

>time = 499993470
time = 499992880
time = 499996332
time = 499996662

あれ、スペックではR5は600MHzのはずだが、、
xparameters.hで↓な記述があった。測定は大丈夫そう。

```c:xparameters.h
/* Canonical definitions for peripheral PSU_CORTEXR5_0 */
#define XPAR_CPU_CORTEXR5_0_CPU_CLK_FREQ_HZ 500000000
```

## 単純なプリエンプト性能
TaskPri00 優先度0
TaskPri01 優先度1
として
1. TaskPri01がSuspend
2. TaskPri02がResume
3. TaskPri01がRunnning状態
2-3を測定する。
### 環境
#### コード(測定用の部分のみ)
```c
unsigned long start, end;
static TaskHandle_t TaskHdlPri00;
static TaskHandle_t TaskHdlPri01;
static void TaskPri00( void *pvParameters ) {
	while(1) {
		//xil_printf("%s\r\n", GetTaskName(xTaskGetCurrentTaskHandle()));
		vTaskDelay(pdMS_TO_TICKS(1000));
		start = pmon_start_cycle_counter();
		vTaskResume(TaskHdlPri01);
	}
}
static void TaskPri01( void *pvParameters ) {
	while(1) {
		//xil_printf("%s\r\n", GetTaskName(xTaskGetCurrentTaskHandle()));
		vTaskSuspend(NULL);
		end = pmon_read_cycle_counter();
		xil_printf("time = %ld\r\n", end - start);
	}
}

int main( void )
{
	xTaskCreate(TaskPri00,"TaskPri00", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, &TaskHdlPri00 );
	xTaskCreate(TaskPri01,"TaskPri01", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+1, &TaskHdlPri01 );

```
### 結果
>time = 1424  (/500MHz = 2.848[us])
time = 463  (/500MHz = 0.926[us])
time = 456  (/500MHz = 0.912[us])
time = 456  (/500MHz = 0.912[us])
あとは456がずっと続く

## 割り込み性能
ReactNavigationによる画面遷移(BottomTabNavigation)

### ①公式ドキュメントに沿って、インストールする。

```jsx
npm install @react-navigation/bottom-tabs
```

### ②表示させる画面ファイルをインポートする。

```jsx
import HomeScreen from './screens/HomeScreen';
import FavoriteScreen from './screens/FavoriteScreen';
import MypageScreen from './screens/MypageScreen';
```

### ③createBottomTabNavigatorを変数化する。

```jsx
const Tab = createBottomTabNavigator()
```

### ④メソッド化する。

```jsx
const TabNavigation = () => {
  return (
    <Tab.Navigator>
      <Tab.Screen name="ホーム" component={HomeScreen} />
      <Tab.Screen name="お気に入り" component={FavoriteScreen} />
      <Tab.Screen name="マイページ" component={MypageScreen} />
    </Tab.Navigator>
  );
};
```

### ⑤画面に表示するため、renderにかける。

```jsx
export default class App extends React.Component {
  render() {
    return (
      <NavigationContainer>
        <TabNavigation />
      </NavigationContainer>
    );
  }
}
```
Dronecode - QGroundControlの使い方（ユーザーガイド）

ドローンの自律飛行を実現するには、DronecodeとMAVSDKを試してみます。

# 目次
1. [PX4環境構築](https://qiita.com/k-koh/items/77af5422b3857e68ad9a)
2. [uORB Messaging](https://qiita.com/k-koh/items/c57c02df772785816c14)
3. [QGroundControlの使い方（ユーザーガイド）](https://qiita.com/k-koh/items/eedc303cb0b72d1272ee)
4. [MAVLinkの入門](https://qiita.com/k-koh/items/9e9c1694dbb5a2a4117a)
5. [QGroundControlのカスタマイズ開発](https://qiita.com/k-koh/items/36c34f0e3e18b2e055ac)


## 動作環境
- Ubuntu 18.04
- ROS Melodic

## QGroundControl

QGroundControlとは、PX4、ArduPilotを搭載したドローンと車両のフライトコントロールと設定を提供するアプリです。

### QGroundControlの起動

```
./QGroundControl.AppImage  (or double click)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/2e4fbfb1-f5a9-8b73-c9d2-b30b63caaeb0.png)

### Analyze View - MAVLink Inspector

1. Analyze | MAVLink Inspector | 表示したいmessages（複数選択可）を選択
2. Pilot1, Pilot2でリアルタイム表示したい項目のチェックを選択
3. グラフにアルタイム値を確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/9a1346c4-a3d5-aed3-21fd-49c2b21931d7.png)

### Analyze View - MAVLink Console

Mavlink Consoleは、 PX4 nsh shellに接続、コマンド発行することができます。

注：PX4 flight stackが稼働した実機のみ対応（PX4 SITLとArduPilotは対応しない）

1. Analyze | MAVLink Console を選択
2. 入力バーに「?」を入力してEnterキーを押す
3. コマンド一覧と実行可能なアプリ一覧を表示

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/e445a968-5444-f7c4-c4f0-b2ce14740f61.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/81015245-1b1d-501e-ac9d-6b2654dcffb8.png)
kubernetes the hard way on PC (８．Encryption Config and Key)

#初めに
「[kubernetes the hard way](https://github.com/kelseyhightower/kubernetes-the-hard-way) を PC でやってみる」の8回目、「Generating the Data Encryption Config and Key」についてです。（ [目次](https://qiita.com/shimauma_Zzzzz/items/84ecf5c748ceafd05380#%E8%AA%AC%E6%98%8E%E8%A8%98%E4%BA%8B%E7%9B%AE%E6%AC%A1) ）
今回は短いのでちょっと気が楽ですね。　とはいえ、ここまででようやく準備が終わり、次回からはもう...（涙）

ここでは、　etcd に情報を格納する際の暗号化の設定を作成します。

やることは以下の通りです。
- 暗号化のキーとなる文字列の生成 (The Encryption Key)
- 暗号化設定ファイル作成 (The Encryption Config File)
- 各マスターノードへの配布

#暗号化のキーとなる文字列の生成 (The Encryption Key)

暗号のシードとなる文字列は何でもよいので、 Linux のランダム文字列を出してくれる urandom デバイスを使います。
文字列なんですね。　私はずっとランダムな数値を出してくれると思っていました。。。
それだけでは利用できない文字などが含まれるのでしょうね。 base64 エンコードしています。

```shell-session
root@k8smaster0:/data/assam/k8s/ca# ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)
root@k8smaster0:/data/assam/k8s/ca# echo $ENCRYPTION_KEY
77ditR6J(略)pKZL+AQj0=
```

変数に格納しているのは、次に cat コマンドを使って設定ファイルを出力する際にその変数を使うからです。
このぐらいであればわざわざコマンドを使って出力しなくてもファイルにコピー＆ペーストでもよいですが。。

#暗号化設定ファイル作成 (The Encryption Config File)

cat コマンドでファイルを出力します。

```shell-session
root@k8smaster0:/data/assam/k8s/ca# cat > encryption-config.yaml <<EOF
> kind: EncryptionConfig
> apiVersion: v1
> resources:
>   - resources:
>       - secrets
>     providers:
>       - aescbc:
>           keys:
>             - name: key1
>               secret: ${ENCRYPTION_KEY}
>       - identity: {}
> EOF
```

上記のコマンドを実行すると、下記の内容のファイルができます。

```shell-session
root@k8smaster0:/data/assam/k8s/ca# cat encryption-config.yaml
kind: EncryptionConfig
apiVersion: v1
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: 77ditR6J（略）pKZL+AQj0=
      - identity: {}
```


#各マスターノードへの配布

作成したファイルを 3台の master に配布します。　
（別途各サーバー上で適切な場所に配置しなおすため、ここでは rootのホームディレクトリに配置しました）

配置方法は…お任せで。 
( scp 等でどうぞ。私はたまたま暇そうにしていた NFS サーバー経由で受け渡しました。。。）


---
今回はここまでとして、次回は Bootstrapping the etcd Cluster の部分を実施します。
いよいよ本格的になってきますね！


← [７．k8sConfig](https://qiita.com/shimauma_Zzzzz/items/e90710402e76b50322c4)
↑ [目次](https://qiita.com/shimauma_Zzzzz/items/84ecf5c748ceafd05380#%E8%AA%AC%E6%98%8E%E8%A8%98%E4%BA%8B%E7%9B%AE%E6%AC%A1)
→ [９．Bootstrapping the etcd Cluster](https://qiita.com/shimauma_Zzzzz/items/3c61ec5aa869b6a333c2)

----
FreeRTOS Debug, Utility系のTips

# 概要
FreeRTOSのDebug, Utility系のTipsのまとめ
逐次追記、、予定
# タスク情報関連
## Task名の取得
```c
void GetTaskStatus( const TaskHandle_t xHandle, TaskStatus_t* xTaskDetails )
{
    //TaskHandle_t xHandle;
    //TaskStatus_t xTaskDetails;

    /* Obtain the handle of a task from its name. */
    //xHandle = xTaskGetHandle( "Task_Name" );

    /* Check the handle is not NULL. */
    configASSERT( xHandle );

    /* Use the handle to obtain further information about the task. */
    vTaskGetTaskInfo( /* The handle of the task being queried. */
                      xHandle,
                      /* The TaskStatus_t structure to complete with information on xHandle. */
                      xTaskDetails,
                      /* Include the stack high water mark value in the TaskStatus_t
                      structure. */
                      pdTRUE,
                      /* Include the task state in the TaskStatus_t structure. */
                      eInvalid );
}
const char* GetTaskName( const TaskHandle_t xHandle)
{
	TaskStatus_t xTaskDetails;
	GetTaskStatus(xHandle, &xTaskDetails);
	return xTaskDetails.pcTaskName;
}

// 使いたい場所で
// ex. printf("%s", GetTaskName(handle));
```

# Tracealyzer
AGC 001 B Mysterious Light

##問題
https://atcoder.jp/contests/agc001/tasks/agc001_b
##見た感じ
Nがめちゃくちゃでかくなるので、1手ずつ数えていくのでは間に合わない。
だから、手元で図を描いたりして見ると、おんなじ長さの辺を一気に書いていって、書けなくなったら、次の長さに移っていくという書かれ方をしていて、かつ平行四辺形がたくさん出てくるのに気づいた。
ここから、$n\times m(n>m)$の平行四辺形に注目してその中でできるだけ大きな正三角形をできるだけ多く書くとき、最初の点に戻るとしたらそれまでに

```math
2*(\lfloor n/m\rfloor -1)*m
```

書き加えているし最初の点に戻らないときは

```math
2*\lfloor n/m\rfloor *m
```
書きくわえて、$m\times n\%m$の平行四辺形に移るを繰り返す。
これを実装すればおk

##解法
上の再帰的な操作を繰り返す。
##ソースコード

```c++
ll n,x;

void Main(){
    int y=INF10,z=1;
    //入力
    cin>>n>>x;
    //処理
    ll res=0,a,b,c;

    a=max(n-x,x);
    b=min(x,n-x);
    res=n;
    while(b!=0){
        if(a%b==0){
            res+=((a/b)-1)*2*b+b;
        }else{
            res+=(a/b)*2*b;
        }
        c=b;
        b=a%b;
        a=c;
    }
    
    //出力
    cout << res <<endl;
}

int main(){
    cin.tie(nullptr);
    cout<<fixed<<setprecision(12);
    Main();
}
```
基本的なREST-APIをAWSのAPI GatewayとLambdaとDynamoDBで作るための参考サイトまとめ


ゼロからAWSでREST-APIを一気通貫で実装してみましたが、それなりの苦労があったため、次はもっと効率よく作りたいので、参考サイトをまとめておきたいと思います。

# やってみたこと
超シンプルなREST-APIを作ってみました。シンプルですがいろいろ知る必要がありました。

+ 一覧は、GETでパスパラメータがあり、パーテーションキーだけ渡す、レスポンスはJSONでBODYが配列
+ 追加は、POSTでパスパラメータがあり、パーテーションキーだけ渡す、リクエスト本文はJSON、レスポンスもJSONでBODYが１件、ソートキーが採番される
+ 更新は、PATCHでパスパラメータがある、パーテーションキー、ソートキーを渡す、リクエスト本文はJSON、レスポンスもJSONでBODYが１件
+ 検索は、GETでパスパラメータがある、パーテーションキー、ソートキーを渡す、リクエスト本文はなし、レスポンスはJSONでBODYが１件
+ 削除は、DELETEでパスパラメータがある、パーテーションキー、ソートキーを渡す、リクエスト本文はなし、レスポンスはJSONでBODYが０件

# 参考サイトまとめ
知る必要があった情報を使う順番に書いておきたいと思います。API GatewayとLambdaとの繋がりを確認することと、REST-APIを作るためにLambdaを使ってDynamoDBで必要な処理を実装すること、をそれぞれ行うこととなります。

## API GatewayとLambdaとの繋がりを確認する
+ APIGatewayとLambdaを使う場合、まずプロキシ統合が気になりますので確認しました
 - https://rso.hateblo.jp/entry/2019/02/17/232229
 - https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html
 - https://qiita.com/takeh/items/3915e47f58939a6fab88

+ APIGatewayとLambdaでの値の受け渡し方を理解するために、プロキシ統合を使わず、マッピングテンプレートを活用する方法を確認しました
 - https://dev.classmethod.jp/articles/sugano-009-api-gateway/
 - https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/set-up-lambda-custom-integrations.html
 - https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-override-request-response-parameters.html
 - https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#input-variable-reference

## REST-APIを作るためにLambdaを使ってDynamoDBで必要な処理を実装する

+ REST-APIを作るために、リソースとかメソッドの設定のあるべき姿を確認しました
 - https://qiita.com/kawasukeeee/items/70403129f5a5338cd4ad

+ APIGatewayだけをとにかく動かして、REST-APIはどういうものかを実装したかったので、Mockを活用しました
 - https://qiita.com/Keisuke69/items/0852d536110b2fa6e087
 - https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-getting-started-mock.html

+ 実際にコードを書いていくために、PythonとAPIGatewayとLambdaとDynamoDBを一気通貫で動かすために必要な処理を確認しました
 - https://business.ntt-east.co.jp/content/cloudsolution/column-try-20.html#section-03-02
 - http://blog.livedoor.jp/sce_info3-craft/archives/9288509.html

+ ソートキーは自動採番したいのでDynamoDBのアトミックカウンターを利用する方法を理解しました
 - https://dev.classmethod.jp/articles/python-dynamodb-atomic-counter-by-python/

+ Lambdaにて、リクエスト本文の値をそのまま利用する作りにしたため、最後に、パスパラメータとリクエスト本文をマッピングテンプレートで合体してリクエスト本文にする方法を確認しました
 - https://qiita.com/minsu/items/c9e983f109b1cf5a516e
 - https://qiita.com/keitakn/items/a409b1722956cb1d9487

# まとめ
これくらい参考にすれば、基本的なREST-APIをAWSのAPI GatewayとLambdaとDynamoDBで一気通貫で作れました。参考サイトを一気に読んで、だいたいの作りをイメージしたものを、まとめてコードにできるようになれれば効率が良さそうです。

以上
正答率・再現率・特異度・適合率・偽陽性率・偽陰性率・F値まとめ

#はじめに
題名にある通り正答率(正解率)、再現率、特異度、適合率、偽陽性率、偽陰性率、F値について、算出方法に焦点を絞って備忘録を兼ねたまとめを書きたいと思います。
機械学習や物体検出手法、診断などの世界では精度の評価指標としてよく用いられると思うので、よかったら算出方法の備忘録として覗いてください。

#全体像
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678596/2cac2a0a-3a46-8996-274a-0026b80bffbc.png)

全体像を図にするとこんな感じです。

##上の図の説明
- とあるクラスにサンプルたちが入るか入らないかという分類問題をした状況を想定する。
- 分類したサンプルたちをすべて含めた集合をUとしている。
    - ①：「このサンプルはとあるクラスに入っている」と判断された、かつその判断は正しかった
    - ②：「このサンプルはとあるクラスに入っている」と判断された、かつその判断は間違っていた
    - ③：「このサンプルはとあるクラスに入っていない」と判断された、かつその判断は間違っていた
    - ④：「このサンプルはとあるクラスに入っていない」と判断された、かつその判断は正しかった

##蛇足
「陽性や陰性って何？」といった内容を具体例と混ぜて説明します。不要な方は読み飛ばしてください。

- 病気にかかっているかを診断する状況を具体例として考える。
    - この場合は「病気にかかっている人たち」というのが「とあるクラス」に該当する。
    - ①：「この人は病気にかかっている」(このサンプルはとあるクラスに入っている)と判断された、かつその判断は正しかった
    - ②：「この人は病気にかかっている」(このサンプルはとあるクラスに入っている)と判断された、かつその判断は間違っていた
    - ③：「この人は病気にかかっていない」(このサンプルはとあるクラスに入っていない)と判断された、かつその判断は間違っていた
    - ④：「この人は病気にかかっていない」(このサンプルはとあるクラスに入っていない)と判断された、かつその判断は正しかった
- 陽性とは：「この人は病気にかかっている」(このサンプルはとあるクラスに入っている)と判断することを陽性と言う
- 陰性とは：「この人は病気にかかっていない」(このサンプルはとあるクラスに入っていない)と判断することを陰性と言う
    - でも陽性や陰性と判断してもやっぱり間違いがあるため、それが正解とか不正解になる
        - 「この人は病気にかかっている」と判断しても「実はかかっていなかった」(このサンプルはとあるクラスに入っていなかった)などの状況が該当
- 正解とは：陽性、もしくは陰性の判断が正しかったこと
- 不正解とは：陽性、もしくは陰性の判断が間違っていたこと
- 実際に「病気にかかっている人たち」は①+③
- 実際には「病気にかかっていない人たち」は②+④

#算出方法
##正答率(正解率)
全サンプルの中で、診断が正しかったサンプル数

```math
正答率 = \frac{①+④}{①+②+③+④} 
```

##再現率
実際は陽性だったサンプルの中で、陽性という判断が正しかかった数

```math
再現率 = \frac{①}{③+①} 
```

##特異度
陰性と判断したサンプルの中で、陰性という判断が正しかった数

```math
特異度 = \frac{④}{③+④} 
```

##適合率
陽性と判断したサンプルの中で、陽性という判断が正しかった数

```math
適合率 = \frac{①}{②+①} 
```

##偽陽性率
陽性と判断したサンプルたちの中で、判断が間違っていたサンプル数

```math
偽陽性率 = \frac{②}{①+②} 
```

##偽陰性率
陰性と判断したサンプルたちの中で、判断が間違っていたサンプル数

```math
偽陰性率 = \frac{③}{③+④} 
```

##F値
再現率と適合率の調和平均

```math
F値 = 2 \times \frac{再現率 \times 適合率}{再現率+適合率} 
```
キャラクターに便利！ちょっと足したい時のためのCSS animation

サイトやLPを作っていて、ちょっとインパクトが足りない！何か足したい！って場合は、
CSSアニメーションを追加しましょう！
キャラクターを使っているLPなどに使ってる時に効果的です！

## せっかちなあなたのために
こちらに一覧が載っています。ご活用ください。
<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="css,result" data-user="seahorse-design" data-slug-hash="zYrLGPV" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="キャラクターに便利なCSS animation">
  <span>See the Pen <a href="https://codepen.io/seahorse-design/pen/zYrLGPV">
  キャラクターに便利なCSS animation</a> by saki matsushita (<a href="https://codepen.io/seahorse-design">@seahorse-design</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## 一覧
### ふわふわ
![fuwafuwa.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165868/9b9737a1-035b-0ca2-b408-044623500bb3.gif)
くもやおばけのキャラクターなどに。

### ぴょんぴょん
ボールやなんか跳ねてるキャラクターなどに。

### びっくり
![bikkuri.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165868/d5d5c58b-8ec6-5dd7-debc-d1ae808557f3.gif)
びっくりしている表情や「激安！」大きいフォントなどに。

### ぶるぶる
![buruburu.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165868/dd3b922f-9747-6ad0-0390-151190d84458.gif)
凍えている時、怯えている時など。

### ステップ
![step.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165868/01de079a-9166-5218-1f51-e3fdd1c3978d.gif)
楽しい時。割と汎用的。

### ゆらゆら
![yurayura2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165868/2d45e3ae-d6dc-3fe9-fbc7-eafec46b63c6.gif)
横揺れ

### どーん！
![burn.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165868/2d1a9743-df64-a162-236a-163d0d7f21c7.gif)
価格の大きいフォントなど。
これは1回きりなので、スクロールと同時に現れるとインパクトになるかも。

---

ぜひ良きCSS Animationライフを！
基本的なDockerコマンドメモ

##Dockerイメージ関係

###イメージを取得する
タグを指定しなかった場合、デフォルトではlatestタグのイメージが取得されます。

```
$ docker pull [イメージ名]
```

###Dockerfileからイメージをビルドする

キャッシュを無効化する場合は、`--no-chache`オプションを追加

```
$ docker build -t [生成するイメージ名]:[タグ名を指定] [ビルドコンテキストを指定]
```

Dockerfileという名前のファイルがビルドコンテキストに入っていない場合は、以下のように`-f`オプションを追加してパスを指定

```
$ docker build -f [Dockerfile名(パスを指定)] [ビルドコンテキストを指定]
```

###ダウンロード済みのイメージ一覧を表示する

```
$ docker images　

　// もしくは、

$ docker image list
```

###イメージの詳細情報を表示する

```
$ docker inspect [イメージ名]
```

###イメージを削除する

もし既に、削除対象のイメージからコンテナが作成されている場合は、そのコンテナの削除後でないとイメージを削除できません。
（`-f` オプションを付けると強制削除が可能）

```
$ docker rmi [イメージ名 or イメージID]

  // もしくは、

$ docker image rm [イメージ名 or イメージID]
```

###イメージを一括削除する

イメージを作成し過ぎてしまって、不要なものをまとめて削除したい時に便利なコマンドです。

```
$ docker image prune
```


##コンテナ関係


###DockerHubからイメージを取得して、コンテナを起動する

```
$ docker run [イメージ名]:[タグ名]
```
→タグ名は、主にイメージのバージョン

docker runコマンドは、以下の３つのコマンドを１度にまとめて実行するコマンドです。

　`①docker pull:イメージの取得`
　`②docker create:コンテナの作成`
　`③docker start:コンテナの起動`

**オプション：**

`-d` ：プロセスをバックグラウンドで実行
`-it`：コンテナのシェルに接続する時に必要なオプション
`--name [コンテナ名]`：コンテナ名を付ける
`--rm`：コンテナを停止すると、そのままコンテナが削除されるようにする


###コンテナを再起動する

```
$ docker restart [コンテナ名 or コンテナID]
```

###コンテナを一時停止/再開する

```
  //コンテナの一時停止
$ docker pause [コンテナ名 or コンテナID]

  //コンテナの再開
$ docker unpause [コンテナ名 or コンテナID]
```

###コンテナを停止する

```
$ docker stop [コンテナ名 or コンテナID]
```

###コンテナを削除する
コンテナを削除するには、`docker stop`でコンテナを停止する必要があります。
もしくは、下記コマンドに`-f`オプションを加えることで強制削除することも可能です。

```
$ docker rm [コンテナ名 or コンテナID]
```

オプション：
`-f`：コンテナが停止していなくても強制削除する

###コンテナを一括削除する

コンテナを作成し過ぎてしまって、不要なものをまとめて削除したい時に便利なコマンドです。

```
$ docker container prune
```


###コンテナ一覧を表示する

現在実行しているコンテナを一覧表示します。


```
$ docker ps
```
オプション：
`-a`：現在実行されていないコンテナも表示



##DockerHubへのプッシュ

###DockerHubにログイン

```
$ docker login
```

###DockerHubにおけるタグ付けのルール

```
[Docker ID]/[イメージ名]:[タグ名]
```

####DockerHubにプッシュ

```
$ docker　push [Docker ID]/[イメージ名 ]:[タグ名]
```

##コンテナのシェルに接続

###イメージからコンテナを作成・起動してコンテナに接続

```
$ docker run -it [イメージ名 or イメージID] bash
  // ※シェルがbashの場合
```

ホストのファイルシステムをコンテナにマウントする時は、`-v`オプションを使用します。

```
$ docker run -it -v [ホストのマウント元のパス]:[コンテナのマウント先のパス] [イメージ名 or イメージID] bash
```

更に、コンテナに接続するユーザを指定する時は`-u`オプションを使用します。

例）ホストユーザーでコンテナに接続する場合

```
$ docker run -it -u $(id -u):$(id -g) -v [ホストのマウント元のパス]:[コンテナのマウント先のパス] [イメージ名 or イメージID] bash
```

###既にあるコンテナに接続

```
$ docker exec -it [コンテナ名 or コンテナID] bash
  // ※シェルがbashの場合
```

コンテナから抜ける時は、以下のいずれかを実行
（よく利用されるのはexit)

`①exit`コマンド
　　　　→ コンテナを動かしているプロセスを**切って**コンテナから出る

`②Control + q + p`(detach)
　　　　→ コンテナを動かしているプロセスを**残して**コンテナから出る


##ホストマシン⇆コンテナ間でのコピー

###ホストマシンのファイルをコンテナ内にコピー
ホストマシン→コンテナ

```
$ docker cp [ホスト上のコピーしたいファイルのパス]  [コンテナ名 or コンテナID]：[コピー先のパス]
```

###コンテナ内のファイルをホストマシンにコピー
コンテナ→ホストマシン


```
$ docker cp [コンテナ名 or コンテナID ]：[コンテナ上のコピーしたいファイルのパス]  [コピー先のパス]
```
ゲーム理論から学ぶチームビルディング

# ゲーム理論から学ぶチームビルディング

## 目的

ゲーム理論からチームビルディングの難しさを学ぶ


## ゴール
- 相手のこと、未来のことを考えられるようになりチームビルディングの際に考えないといけない要素を学ぶ
- ※数学的な部分は深く突っ込まない



## ゲーム理論とは？

ゲーム理論とは、「２人以上のプレイヤーの意思決定・行動を分析する理論」です。  
ここでいう「プレイヤー」とは、人間だけではありません。  
企業、国家などさまざまな「意思決定を行なう主体」を指し、幅広い応用が可能です。

→相手がいるときの問題の意思決定の学問

→数学的な見方、経済学的な見方、心理学的な見方いろいろあるけどマネージメント観点で見てみる。





----

# 第一章

## 囚人のジレンマ

> 共同で犯罪を行ったと思われる囚人A、Bを自白させるため、警官は2人に以下の条件を伝えた。  
> 「もし、お前らが2人とも黙秘したら、2人とも懲役2年だ。  
> だが、お前らのうち1人だけが自白したらそいつは懲役1年に減刑してやろう。  
> この場合自白しなかった方は懲役5年だ。  
> ただし、お前らが2人とも自白したら、2人とも懲役4年だ。」  
> この時、2人の囚人は共犯者と協調して黙秘すべきか、  
> それとも共犯者を裏切って自白すべきか、というのが問題である。  
> なお彼ら2人は別室に隔離される等しており、2人の間で強制力のある合意を形成できない 状況におかれているとする。

----
## この問題の肝
囚人2人にとって、互いに裏切り合って4年の刑を受けるよりは互いに協調し合って2年の刑を受ける方が得である。  
しかし囚人達が自分の利益のみを追求している限り、互いに裏切り合うという結末を迎える。  
これがジレンマと言われる所以である。

----

## 各人思考に関して

このようなジレンマが起こるのは以下の理由による。  
まずAの立場で考えると、Aは次のように考えるだろう。  
Bが「黙秘」を選んだ場合、自分 (=A) の懲役は2年（「黙秘」を選んだ場合）か5年（「自白」を選んだ場合）だ。だから「自白」を選んで2年の懲役になる方が得だ。  
Bが「自白」を選んだ場合、自分 (=A) の懲役は5年（「黙秘」を選んだ場合）か4年（「自白」を選んだ場合）だ。だからやはり「自白」を選んで4年の懲役になる方が得だ。  

以上の議論により、AにとってはBがどのような行動をとるかによらず、Bを裏切るのが最適な選択ということになる。よってAはBを裏切ることになる。  

----

## 囚人のジレンマが面白いところ

現代でも似たような状態がたくさんある
- 牛丼の値段の値下げ競争
- ↑デフレ構造

----

## 囚人のジレンマから学ぶべき部分

- 各個人の最適化を選んでも全体でみて最適化になるということではない
- チームビルディングをする際に各個人の最適化を選んでも全体としていい結果にはならない可能性がある。

----

## では（現実問題）どうすればいいか
ぱっと考えられる対応方法
- 善意に訴える
 - 基本的にうまくいかない。うまくいく条件は以下である
  - 囚人のジレンマのような状況が同じ人々の間で繰り返される（毎回同じ問題が起きてる
  - お互いの行動が観察できる（監視できる。注意できる)  
  それ以外はうまくいかない  
（↑ただ上は注意しないといけないという工数がかかるのであまりいい答えとはいえないと思う）

----

囚人のジレンマには前提の条件がある
- お互いに話せない状況

現実世界ではここまで厳しいことはそこまでない  
答えとしてはルールを変えてしまう。
- デフレ問題
 - 一定のクオリティ以下なら罰則をつける
 - 国の間で話し合う。
- （囚人なら話し合ってもいいにする？

----

## コーディネーション・ゲーム

- 電気自動車のが環境的に明らかにエコなのに一般的に化石燃料自動車を選んでしまう
 - スタンドが少ないから
- キーボード配列は確実に覚えにくい
 - そっちのほうが普及している
- エスカレーターの右左
----

## コーディネーション・ゲーム

ゲームに参加するプレイヤーが同調することで互いが利益を得るという構造をもつゲーム。  
特別な理由はないが、みんなが同じ選択をすることによって、お互いの利益が守られる。  

複数のナッシュ均衡から人々にとって望ましくない均衡に陥ることもある。
これを「コーディネーションの失敗」と呼ぶ。  
コーディネーションゲームは「良いコーディネーション」、「コーディネーションの失敗」のいづれかに落ち着く。  
コーディネーションゲームには、「安定すると変えにくい」という性質があるため、気を付けないと時代の変化に取り残される危険性がある。  
逆に、ひとたび良い均衡に落ち着くと、ルールを強制しなくても自然とうまくいく利点もある。  

----

### チームでの「コーディネーションの失敗」例
- 某バッチの保守は大変である
- 作り変えるのはもっと大変である
 - 某バッチの保守をしてしまう。
上記は
- 長期的にみて損しているのは明らかに前者である
- 安定すると変えにくい

チームでもよくある事例である

----

## コーディネーションゲームから学ぶべき部分
- 自然な流れに沿っていても良いものが選ばれるわけではない
- 現場で古くから行っていることが最適だとは思わないこと

----

## では（現実問題）どうすればいいか

- 一斉にスタートを切ることである。（こうすると決めること）
そうすることで損を選ぶ人はいなくなり良い方の結果を選ぶようになる。

----

# 第3章
## 応用編：上記話はあくまで序章、現実的には他にも考えないといけない問題もある
- 時間的な視点
 - 時間が立ってみるとメリットがなくなるという場合がある。
 - 未来を予測する必要がある。

 例：値下げ競争とかは特に他社も値下げするという見込みを立てておかないといけないので
 先を予測する力が必要になってくる。

先を予測する力について：
----

- その人の価値観的な視点
 - みんなそんな論理的に動くとは限らない
 - MTよりATのが優れているのにMT好きとか

ここらへんは相手のことを考える必要性がでてくる

## 終わりに

なるべく簡潔にゲーム理論からチームビルディングの際に考えないといけないということを伝えられたらなと思い勉強会で話した内容を記載します。
なにか指摘などありましたら教えて下さい。



#　引用
マンガでやさしくわかるゲーム理論
C/C++ developer からみた uCRT のメモ


uCRT とは?

https://devblogs.microsoft.com/cppblog/introducing-the-universal-crt/

C/C++ developer からしたら glibc 相当かしらん.
header とソースコードは実は公開されている. 実装としては Win32 API or より低レベルの Windows 関数を呼んでいる感じである. C++ で書かれている.


uCRT ランタイムは Windows 10 から標準付属となった.
古いシステムでは, vcredist あたり入れればいけるっぽい.


## 再配布性

https://docs.microsoft.com/en-us/cpp/porting/upgrade-your-code-to-the-universal-crt?view=vs-2019

Retail(Release) の DLL は再配布可能.
Debug 版は不可(もともと昔も Visual Studio の debug DLL 関連は再配布不可でした. 開発者用なので本来は再配布向けではないですが, シンボル周りとか, デバッグ DLL で変に動かないエラーが出るのを避けるために再配布不可にしているでしょうか)

## Static link

static link が可能である(もしくは uCRT のソースコードを自身のプロジェクトに取り込んで static build も可能).

バイナリとしての再配布は, 

https://devblogs.microsoft.com/cppblog/introducing-the-universal-crt/

の blog を見る限り OK そう. app-local deployment に該当.
(Debug 版はどうなのかな?)

ときどき `api-ms-win-***.dll` を含んだアプリを見ますが, これが app-local deployment.


### Wine 

Wine で動かしてデバッグしたいときは, app-local depolyment or static link ですかね.
SSHのパスワード認証を停止して完全に鍵認証に切り換える

前回の記事ではSSH接続に必要な公開鍵と秘密鍵の生成方法を書きました。

最後に、パスワード認証を停止する方法を紹介します。
これにより、誰もパスワード認証でSSH接続を開始できなくなり、代わりに公開鍵・秘密鍵の認証のみでSSH接続を開始できるようになります。

```ruby:MainPC
$ sudo vi /etc/ssh/sshd_config
```

上記を打つと、sshについていの設定ファイルをvimで編集します。
vimで以下を検索します。

```ruby:MainPC
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication no
```

上記の部分のyesとnoをいじるだけなんですけども....
意外な落とし穴で、デフォルト状態では上から2つのコマンドはコメントアウト(#~)でなっています。
これだといくらyesやnoに変えても設定項目として反映されません笑
必ず、#を外して値を変更・保存してください。

さ、あとはsshシステムを再起動します。

```ruby:MainPC
$ sudo systemctl restart sshd
```

これで、以前の記事をもう一度試してください。
おそらくパスワード認証はオフになっています。
[Go言語] 初心者必見シリーズ その１:配列とスライス

# 配列（Arrays）

配列は **連続したメモリ領域** を確保するデータ構造です。

<img width="438" alt="golang-array.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170309/350120f7-d2e6-b66c-dd0a-03396dbeb4d2.png">

## 定義方法

### 方法1

構文: 

```go
  var 配列名 [サイズ]型
```

例:

```go
  var a [2]string
```

### 方法2

構文: 

```go
    var  配列名  [サイズ]型
        = [サイズ]型{初期値1, ..., 初期値n} 
```

例:

```go
    var a [2]string
        = [2]string{"Hello", "Go"}
```

> NOTE:  宣言と同時に代入する。

### 方法3

構文: 

```go
    配列名 := [サイズ]型{初期値1, ..., 初期値n} 
```

例:

```go
    a := [2]string{"Hello", "Go"}
```

> NOTE:  宣言と同時に代入するなら、方法2よりもこちらが簡潔でおすすめ。

### 方法4

構文:

```go
    配列名 := [...]型{初期値1, ..., 初期値n}
```

例:

```go
    a := [...]string{"Hello", "Go"}
```

> NOTE: 配列のサイズを "..." にすると、コンパイラーが自動的に要素数を数えてくれる。  

### 多次元配列  (Multiple Dimension) 

多次元配列  (Multiple Dimension) は、 
**[]の数** を増やせば1次元配列と同じように定義することができる。


例:

```go
    a := [][]string{
        {"Hello", "Go"},
        {"Hello", "Python"},
    }
```



## 要素の走査 (iteration) 

### 方法1： len関数を利用することで配列のサイズを取得。

```go
for i := 0; i < len(array); i++ {
  fmt.Println(array[i])
}
```

### 方法2 : rangeを使って配列を走査。

```go
for index, value := range array{   
    fmt.Println(index, value)
}
```



## まとめ

* 配列は、宣言後にサイズを変更できません。（**固定長**）

  あらかじめデータサイズの確定しないデータには向いてません。

* 配列は、基本同じ型をもつ要素を格納しますが、

  いろんな型を混在させたい場合は `interface` 型で初期化します。

  ```go
  array := []interface{}{“hello", 10, 2.5}
  ```

# スライス（Slices）

スライスは**可変長の配列**の様な動きをするデータ構造です。

## 定義方法

定義方法は配列と似ていて、**サイズを指定せず**に宣言します。

### 方法1

構文：

```go
var 名前 []型
```

例：

```go
var a []string
```

### 方法2

構文：

```go
var 名前 []型 = []型{初期値1, ..., 初期値n} 
```

例：

```go
var a []string = []string{"Hello", "Go"}
```



### 方法3

構文：

```go
名前 := []型{初期値1, ..., 初期値n}
```

例：

```go
a := []string{"Hello", "Go"}
```

### 方法4

構文：

```go
名前 := make([]型, 初期長さ ,初期容量)
```

例：

```go
a := make([]string, 2, 10)
```

> 方法4は、配列にはないような宣言方法。
>
> **初期容量**はオプション引数。



## スライスの構成

![golang-slice.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170309/3679422f-7ffd-922d-35ad-dc40b1669c36.png)


> スライスは配列への参照のようなもの。


## 要素の走査 (iteration) 


走査方法は、配列と同様です。



## 要素の追加 (append)

スライスへ新しい要素を追加するには、Goの組み込みの **append関数** を使います。

要素追加時の動きは、こちらの[動画](https://youtu.be/4IoXc5x6FjA?t=280)が分かりやすくご覧いただければと思います。

# 動画（YouTube）

この記事を動画で見たければ、こちらでお願いします。

https://www.youtube.com/watch?v=4IoXc5x6FjA

# 元記事

https://aifan.jp/2020/07/26/Go%E8%A8%80%E8%AA%9E-%E5%88%9D%E5%BF%83%E8%80%85%E5%BF%85%E8%A6%8B%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E3%81%9D%E3%81%AE%EF%BC%91-%E9%85%8D%E5%88%97%E3%81%A8%E3%82%B9%E3%83%A9%E3%82%A4%E3%82%B9/
【Python】データサイエンス100本ノック（構造化データ加工編） 014 解説

- データサイエンス100本ノックをやりきる会を作りました🎉
- こちらの[Slack招待URL](https://join.slack.com/t/data-science-100nocks/shared_invite/zt-gfncg9vm-8W8b3UrDg8R~TKaqUkQpgw)からご参加ください！！
- ぜひ一緒に励まし合いながら、データサイエンス100本ノックをやり切りたいと思っています！

##Youtube
[動画解説](https://youtu.be/ceMOn5IjJL0)もしています。

##問題
P-014: 顧客データフレーム（df_customer）から、ステータスコード（status_cd）の末尾が数字の1〜9で終わるデータを全項目抽出し、10件だけ表示せよ。

##解答
```:コード
df_customer.query("status_cd.str.contains('1$|2$|3$|4$|5$|6$|7$|8$|9$')", engine='python').head(10)
```

##出力
|  | customer_id | customer_name | gender_cd | gender | birth_day | age | postal_cd | address | application_store_cd | application_date | status_cd |
|--:|:--|:--|--:|:--|:--|--:|:--|:--|:--|--:|:--|
| 4 | CS001215000145 | 田崎 美紀 | 1 | 女性 | 1995-03-29 | 24 | 144-0055 | 東京都大田区仲六郷********** | S13001 | 20170605 | 6-20090929-2 |
| 9 | CS033513000180 | 安斎 遥 | 1 | 女性 | 1962-07-11 | 56 | 241-0823 | 神奈川県横浜市旭区善部町********** | S14033 | 20150728 | 6-20080506-5 |
| 12 | CS011215000048 | 芦田 沙耶 | 1 | 女性 | 1992-02-01 | 27 | 223-0062 | 神奈川県横浜市港北区日吉本町********** | S14011 | 20150228 | C-20100421-9 |
| 14 | CS040412000191 | 川井 郁恵 | 1 | 女性 | 1977-01-05 | 42 | 226-0021 | 神奈川県横浜市緑区北八朔町********** | S14040 | 20151101 | 1-20091025-4 |
| 16 | CS009315000023 | 皆川 文世 | 1 | 女性 | 1980-04-15 | 38 | 154-0012 | 東京都世田谷区駒沢********** | S13009 | 20150319 | 5-20080322-1 |
| 22 | CS015315000033 | 福士 璃奈子 | 1 | 女性 | 1983-03-17 | 36 | 135-0043 | 東京都江東区塩浜********** | S13015 | 20141024 | 4-20080219-3 |
| 23 | CS023513000066 | 神戸 そら | 1 | 女性 | 1961-12-17 | 57 | 210-0005 | 神奈川県川崎市川崎区東田町********** | S14023 | 20150915 | 5-20100524-9 |
| 24 | CS035513000134 | 市川 美帆 | 1 | 女性 | 1960-03-27 | 59 | 156-0053 | 東京都世田谷区桜********** | S13035 | 20150227 | 8-20100711-9 |
| 27 | CS001515000263 | 高松 夏空 | 1 | 女性 | 1962-11-09 | 56 | 144-0051 | 東京都大田区西蒲田********** | S13001 | 20160812 | 1-20100804-1 |
| 28 | CS040314000027 | 鶴田 きみまろ | 9 | 不明 | 1986-03-26 | 33 | 226-0027 | 神奈川県横浜市緑区長津田********** | S14040 | 20150122 | 2-20080426-4 |

##解説
・PandasのDataFrame/Seriesにて、条件に当てはまる先頭データを確認する方法です。
・条件に当てはまる情報を確認したい時に使用します。
・**'contains(<文字列>)'は、指定した文字列が含まれているどうかを判定する関数**であり、含まれる場合はTrue、含まれない場合はFalseを返します。
・ただし、**'.query('---.str.contains(<文字列>))'は、指定した文字列が含まれることを条件として指定します**。
・今回の場合、status_cd を文字列に置換するために'status_cd.str'とし、'.contains('[1-9]$')'を続けることで、「1-9」が末尾にある status_cd を指定しています。
**・'$'は末尾文字であることを表す正規表現**です。正規表現とは、「複数の文字列を1つの記号で表す方法」のことを指します。
・'engine = 'python''について、query の引数である engine には'python'か、'numexpr'かを選択することができますが、strを用いる場合は、'python'を指定してあげないとエラーが発生してしまいます。

**※正解を見ると、以下のようなコードになっています。確かに'[1-9]$'については、**
**末尾を表す正規表現'$'と、範囲を表す'[1-9]'で表した方が、より簡単に表現することができます。**
**・'regex=True'は、正規表現を扱う際に必要とされていました。以下の解答例では'$''-'が正規表現として扱われています。現在は、書かなくても正規表現として扱われるようになっているので、なくても問題ないです。**  

```:コード
df_customer.query("status_cd.str.contains('[1-9]$', regex=True)", engine='python').head(10)
```

※末尾文字なんだから'str.endswith'を使うんじゃないか、と思われた方もいるかもしれませんが、以下のコードを実行しても何も抽出できません。なぜなら、'str.endswith'は正規表現を処理することができず、'|'を読み取ることができないためです。

```:コード
df_customer.query("status_cd.str.endswith('1$|2$|3$|4$|5$|6$|7$|8$|9$')", engine='python').head(10)
```

※正規表現については、[こちら](https://qiita.com/hiroyuki_mrp/items/29e87bf5fe46de62983c)の記事が参考になります。
セキュリティリスクを回避しながらSSH接続する

[前回の記事](https://qiita.com/kitarow0309/items/b7c4880bd19d7cce34fe)では、パスワードを使った最も簡単な接続を紹介しました。
次はもう少しセキュリティを高めた方法を紹介します。
前回同様、会社のデスクトップパソコン(Main PC)を社内のどこからでも自分のノートPC(My PC)で接続できるようにします。

サーバー:Main PC
クライアント:My PC

open-sshと付属のパッケージをインストールします。こちらは以前の記事を御覧ください。

まず、セキュリティを高めるために、SSH接続では「秘密鍵」と「公開鍵」ファイルを理解しましょう。
これら~~「鍵」はSSH接続を開始し、~~~通信内容を暗号化・復号化するためにつかわれるものです。
例えば、自分のノートPC(My PC)から会社のデスクトップPC(Main PC)をSSH接続で操作するときにパスワードを使ってログインしていると、自分以外の誰かが操作できる可能性がでてきます。また、SSH接続の内容を他人が読み取る可能性もあります。
そこで、通信接続をはじめる際にパスワードを用いないで2台のPCを接続し、更に2台のPC間の通信内容を暗号化し、2台のPC間でしか復号化できないようにする事を実現したものが上記の2つの「鍵」です。

実際のSSH接続では、My PCで2つの鍵を生成し、そのうちの「公開鍵」をMain PCに登録します。My PCでは「秘密鍵」を使って通信を暗号化します。この暗号化した通信をMain PCは受け取り、公開鍵で復号化します。

では、「秘密鍵」と「公開鍵」を作成しましょう。こちらからはMy PC(自分のノートPC)で操作します。

```ruby:MyPC
$ ssh-keygen -b 2048
```

上記を打つと、どこに２つの鍵を生成するか聞かれます。デフォルトの~/.sshで良いと思います。
次に上記の鍵を実際に鍵として使うためのパスワードを求められます。
このパスワードは忘れないでください。
(簡単にいうと、2つの鍵のうち秘密鍵はパスワードでしか開かない封筒に入れられてる状態で生成されるためです。実際に接続するときにはこのパスワードを一度いれて封筒から秘密鍵を取り出さないと使えません。)

次に、鍵が生成されたか確認しましょう

```ruby:MyPC
$ ls ~/.ssh
id_rsa id_rsa.pub
```

鍵の生成場所は今回、~/.ssh (/home/user/.ssh)ですので、そこのファイルをlsで表示させます。
すると2つのファイルがあると思います。

id_rsa＝秘密鍵
id_rsa.pub=公開鍵(pub=publication)

できました!!!!

それでは、この公開鍵をMain PCに持ってけばいいんですが、どこに置くか、どうやって持っていけばいいのか....面倒な人は以下を実行すれば勝手に公開鍵をMain PCに登録してくれます。

```ruby:MyPC
$ cd ~/.ssh #1
$ ssh-copy-id -i id_rsa.pub user@192.168.1.1 #2
  (ssh-copy-id -i 公開鍵名(パスの指定もできます) Main PC(サーバー)のユーザー名@Main PCのIP)
```
 #1で公開鍵の保存場所に移動します。
 #2で~/.sshのid_rsa.pubを公開鍵に指定して、サーバー(Main PC)に送信しています。
サーバー(Main PC)のユーザー名やIPアドレスの調べ方は、[以前の記事](https://qiita.com/kitarow0309/items/b7c4880bd19d7cce34fe)でお書きしていますので、そちらを参照ください。
実行するとMain PCのログインパスワードを聞かれますので入力してください

これで、My PCの公開鍵がMain PCに登録されました。

さて、後は接続です。
これまた結構簡単です。

```MyPC
$ cd ~/.ssh
$ ssh -I id_rsa(パスの指定でもOK:~/.ssh/id_rsa) user@192.168.1.1
```

あれ？パスワード聞かれる....意味ないんじゃ？
そうです。このパスワード認証をオフにしましょう。
次回の記事で書きます！！
Java SE11 silver に受かった話



#経歴

地方公務員（向いてないなあ）→SESに転職→1ヶ月の研修後、運用・保守の現場

研修ではjavaをやってました。その前に空白があったので、[すっきりわかるJava入門](https://www.amazon.co.jp/スッキリわかるJava入門-第3版-スッキリシリーズ-中山清喬/dp/4295007803)と[paiza](https://paiza.jp) を1ヶ月ほどやってました。Bランクまではなんとか解けました。

研修最終日にsilver受けて、53％でした。。。

再受験で89％！合格！

トータル学習期間：3ヶ月くらい

#気をつけたこと

1回目は勉強不足！が確実にあったので

2回目は[黒本](https://www.amazon.co.jp/徹底攻略Java-SE-11-Silver問題集-1Z0-815/dp/4295007625/ref=pd_lpo_14_t_0/355-2169576-6249117?_encoding=UTF8&pd_rd_i=4295007625&pd_rd_r=fbcae4b0-48fd-4bf8-bcc1-ebdb9fa90b30&pd_rd_w=7JXDG&pd_rd_wg=329ry&pf_rd_p=4b55d259-ebf0-4306-905a-7762d1b93740&pf_rd_r=YZTBQMR58WS3SB177MWK&psc=1&refRID=YZTBQMR58WS3SB177MWK)を解きまくって、終盤は満点しか出さないくらいのレベルでした。

Javaのことでいえば
・オーバーライドの仕様をよく確認する
・アクセス修飾子をよく確認する
・ローカル変数とフィールドの優先度とか
・コンストラクタの仕様
・例外処理、ラムダ式、モジュールシステムに関しては出題されるパターンが黒本と似ているので、それで覚える。（あんまりよくないですけど…）

・あんまり参考にならんかもですけど、モジュールに関しては、役割とか、基本的なAPIがまとめられているのはbaseか、とかがよくでた印象でした。知識を問うような問題が多かった。

#先人たちの記事

とても参考になりますので、ぜひ！

[Java Silver 試験対策メモ](https://qiita.com/leonis_sk/items/6a147f70ae326494cc03)
[[java] Java SE 8 Silver メモ](https://qiita.com/kharigai/items/6cdcb9e66b327669703b)

#さいごに

ほんとに認定教科書シリーズやりまくれば、受かります！

次は基本情報かLPIC受けたいし、なんか作りたいですね
あと、技術的な記事も書きたいですね