OmniAICreator/Qiita-1.07M huggingface dataset:
javascript/ajaxでIncoming WebhookにPOSTするまでにつまづいた箇所

## Incoming Webhookをslackに追加する
![スクリーンショット 2019-03-16 14.39.17.png](https://qiita-image-store.s3.amazonaws.com/0/199554/44a8b805-f50d-b923-8f04-e26226990b19.png)

## 実装
とりあえず最終形態。

```.javascript
function submit() {
  const url = "https://hooks.slack.com/services/xxxxxxxxxx";
  const data = {
    text: "testです"
  };

  const xml = new XMLHttpRequest();
  xml.open("POST", url, false);
  xml.setRequestHeader("content-type", "application/x-www-form-urlencoded;charset=UTF-8");
  xml.send(`payload=${JSON.stringify(data)}`)
}
```

<img width="1190" alt="スクリーンショット 2019-03-17 0.46.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/199554/a7c8f96a-49aa-7011-6b9e-fc03dd755e3c.png">


## 詰まったところ

**エラー**  
`Access to fetch at 'https://hooks.slack.com/services/・・・' from origin 'null' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.`

**該当箇所**  
`"Content-Type": "application/json; charset=utf-8"`

**理由**  
https://stackoverflow.com/questions/45752537/slack-incoming-webhook-request-header-field-content-type-is-not-allowed-by-acce

>フロントエンドのJavaScriptからJSONを想定しているAPIエンドポイントに投稿するときは、そのContent-Type: application/jsonヘッダーをリクエストに追加することが、まさにあなたがする必要があり、すべきことです。しかし、この場合ではありません - その特定のAPIエンドポイントはそれを適切に処理しないからです。

`'Content-type': 'application/json'`
を削除しろとのこと。

なので削除して見たら、400が返ってくる。

`Ajax (XMLHttpRequest)` を使用していたが、jQueryの`$.ajax`で送信している人がいたので参考に`$.ajax`で試したら、送信できた。

差異を確認すると、どうやら`contentType`が違っているようだ。
$.ajaxの初期値は'application/x-www-form-urlencoded; charset=UTF-8'
http://js.studio-kingdom.com/jquery/ajax/ajax

しかし、`Ajax (XMLHttpRequest)` の初期値は`'text/plain;charset=UTF-8'`

```
xml.setRequestHeader("content-type", "application/x-www-form-urlencoded;charset=UTF-8");
```

を追記することで解決できた。  
ただのテキストだよって送ってたからエラーになってたんですね。
コード見直しの為のrubocop-airbnbの導入方法

#記事を書くに当たって
rubocop-airbnbを導入したのですが、自動修正までまとまっている記事がなかったのでまとめました。

#rubocopとは
rubocopはrubyコードがコーディング規約に乗っ取って書かれているかどうかをチェックするコード解析ツールです。

rubocopは色んな設定を自分でしなければいけないので、ここではairbnbの開発で使用されているrubocopの設定が反映されているrubocop-airbnbを使います。

#rubocop-airbnbの導入方法

Gemfileにgemを追加して、ターミナルでbundle installします。

```Gemfile.
group :development, :test do
  gem 'rubocop-airbnb'
```

#ファイルの作成

アプリフォルダに``.rubocup.yml``と``.rubocop_airbnb.yml``を追加し、以下の内容を記入します。
（Gemfileと同じ階層のフォルダ）
ここでファイル名を間違えると、呼び出した際にエラーが出るので注意しましょう。
（.のつけ忘れや、_（アンダーバー）を-（ハイフン）にしていたなど）

```．rubocop.yml
inherit_from:
  - .rubocop_airbnb.yml

#以下にはrubocopで検証したくないフォルダを指定する
AllCops:
  Exclude:
    - 'db/**/*'
    - 'bin/*'
    - 'config/environments/*'
    - 'config/application.rb'
    - 'config/initializers/*'
    - 'config/spring.rb'
    - 'lib/tasks/*'
    - 'vendor/**/*'
    - 'path/ruby'

```

```．rubocop_airbnb.yml
require:
  - rubocop-airbnb
```

#実行
ターミナルで以下のコマンドを入力します。エラーが出ていなければOK

```
bundle exec rubocop --require rubocop-airbnb
```

#実行結果(例）

```
20 files inspected, 1 offense detected
```
20のファイルを読み込み、1ファイル間違いがあります。という意味です。

#エラーの例
私は、``．rubocop_airbnb.yml``を``．rubocop-airbnb.yml``と記載しており、以下のエラーが出ていました。参考までに。

```
Errors are usually caused by RuboCop bugs.
Please, report your problems to RuboCop's issue tracker.
https://github.com/rubocop-hq/rubocop/issues

Mention the following information in the issue report:
0.58.2 (using Parser 2.6.0.0, running on ruby 2.5.1 x86_64-darwin17)
```

#コードの自動修正
ターミナルで実行時に、``-a``をつけると自動で間違いを修正してくれます。
ソース：https://docs.rubocop.org/en/latest/auto_correct/

```
bundle exec rubocop --require rubocop-airbnb -a
```




以上です。コードの自動修正がすごく便利なので使ってみてください。
複数のGitHubアカウントを使い分ける

# 概要

複数のGitHubアカウントを使い分ける方法です。

# 手順

## SSH鍵の作成

まず秘密鍵/公開鍵のペアを作成します。
RSAより強固でパフォーマンスも優れているEd25519でSSH鍵を作成します。
(すでに鍵を作成済みならそれを使用しても構いませんが、RSA 1024bitを使っている場合やパスフレーズ設定していない場合は良い機会なので、よりセキュリティの強固なEd25519に変えてみてはどうでしょう)

```bash
$ ssh-keygen -t ed25519 -C XXXX@gmail.com
```

※パスフレーズはちゃんと設定しましょう。(秘密鍵が漏洩してしまった際の対策です)
パスフレーズは10〜30文字で、推測されやすい文は避け、大文字・小文字・数字・記号を混ぜられると良いです。
ssh-keygenのマニュアルには
> Good passphrases are 10-30 characters long, are not simple sentences or otherwise easily guessable
     (English prose has only 1-2 bits of entropy per character, and provides very bad passphrases), and contain a mix of upper and lowercase letters, numbers, and
     non-alphanumeric characters.

とあります。

## SSH鍵の指定

### direnvの設定

使用しているgitのバージョンが2.3以上であれば、 `GIT_SSH_COMMAND` が有効なので、gitで使用する秘密鍵を環境変数で指定することができます。
[direnv](https://github.com/direnv/direnv)と組み合わせれば、特定のディレクトリ配下でgitが使用する秘密鍵を自動で切り替えることができます。

```:.envrc
export GIT_SSH_COMMAND='ssh -i ~/.ssh/id_ed25519_xxx'
```

### ssh_configの編集

gitのバージョンが2.3未満の場合は `GIT_SSH` を使うか、ssh_configを変更する必要があります。

```bash
$ vi ~/.ssh/config

Host xxx.github.com
  User git
  Port 22
  IdentityFile ~/.ssh/id_ed25519_xxx
  Host github.com
```

## 公開鍵をGitHubへ登録

作成した公開鍵をGithubに登録します。

「Settings」-「SSH and GPG keys」で「New SSH key」から登録します。

## 動作確認

プライベートリポジトリをクローンしてみる。

```bash
$ git clone git@github.com:xxx/xxxx.git
Cloning into 'xxxx'...
Enter passphrase for key '/Users/xxx/.ssh/id_ed25519_xxx': パスフレーズを入力
remote: Enumerating objects: 26, done.
remote: Counting objects: 100% (26/26), done.
remote: Compressing objects: 100% (22/22), done.
remote: Total 26 (delta 1), reused 20 (delta 0), pack-reused 0
Receiving objects: 100% (26/26), 4.45 KiB | 505.00 KiB/s, done.
Resolving deltas: 100% (1/1), done.
```

無事クローンすることできました。
4日目: RMDL: Random Multimodel Deep Learning for Classification

# RMDL: Random Multimodel Deep Learning for Classification 要約
## 読んだ論文
RMDL: Random Multimodel Deep Learning for Classification
Kamran Kowsari • Mojtaba Heidarysafa • Donald E. Brown • Kiana Jafari Meimandi • Laura E. Barnes 
https://arxiv.org/abs/1805.01890
上記の論文を読んだので簡単にまとめます．Best Paper award ACM ICISDMらしいです．現在のMNISTのState-of-the-artな手法らしいので読むことにしました．

## 3行でまとめる
- 画像とテキスト分類に適用可能なRMDL（Random Multimodel Deep Learning）の手法を提案した．
- DNN，RNN，CNNを並列使用する手法である．
- 様々なBaseline手法と公開データセットで性能評価を行った．

## 余談
関連研究の末尾で紹介されていた，複数の深層構造の組み合わせとしてRCNN（Recurrent Convolutional Neural Network）が挙げられていた．[紹介記事](https://qiita.com/suckgeun/items/bb2c42b1970479a7da2a)もあるので，時系列分類問題に実際に適用してみたい．もちろん本稿のRMDLも使えそうなのでやってみたい．

## 提案手法
### 使用モデル
![20190316_001.png](https://qiita-image-store.s3.amazonaws.com/0/376859/e0c65ce9-11e7-f9dd-b1b5-b0083b4d88f7.png)
![20190316_002.png](https://qiita-image-store.s3.amazonaws.com/0/376859/71c57294-5bd3-3673-8e29-f4f59f220787.png)

- 提案手法の概要はFig.1とFig.2が全てを示している．
- Fig.1のように入力に対してランダムに複数のDLモデルを構築し，多数決をとる．
- 各モデルの層数やユニット数等はランダムに生成され，各モデルでユニークになる．
- 恐らく，特徴抽出に関する記述があったので，DNNとRNNはHand-craftedな特徴量を使用している．
- Random Forestのようにブートストラップな感じかと思ったが，モデルだけがアンサンブルな様子．
- 以上．．．従来手法やDNN，RNN，CNN，最適化などについて詳細に説明してくれているので紙面を使っているが，教科書に書いてある話なので提案手法自体はシンプル．

## 評価実験
### 実験設定
- テキスト分類
 - 評価用のデータセットは4種類でWOS，Reuters，IMDB，20newsgroups．
 - Baseline手法はDNN，CNN，RNN，NBC，SVM，SVM(TF-IDF)，Stacking-SVM，HDLTex．
- 画像分類
 - 評価用のデータセットは2種類でMNIST，CIFAR
 - Baseline手法はDeep L2-SVM，Maxout Network，Binary Connect，PCANet-1，gcForest 
- 実験環境
 - CPU: Xeon E5-2540
 - 64GB Memory (DDR3)
 - 3 GPU: GTX 1080Ti*2, Tesla K20c
- ライブラリ
 - TensorFlow + Kearsらしい．

### 実験結果
- 上記全てのデータセットにおいて提案手法の推定精度の方が高かった（すごい）．
- 特にMNISTのErrorRateが0.18（精度99.82%）．

## まとめ
- DLモデルをランダムにアンサンブルするだけで高い精度が出るという不思議な論文である．
- CNNにはどこまでのテクニックを導入しているのかが気になる．
- 簡単に実装できそうではあるが，ランダムの範囲等が不明なので結構チューニングが大変かもという印象を受けた．
- あと，学習に時間がかかりそうだがその辺の評価が気になるところではある．

## 所管
手法は簡単だったが色々読んでると結局論文の選定含めて2時間くらいかかっている．全然時間節約ができていない．．．60GPUの論文を読んだ後だったので，3GPUが意外としょぼかったが，色々な検証を行っていて素晴らしいと思います．
Node.js/YARN 環境構築めも

# Node.js/YARN 環境構築めも
めも記事が多くて、「良い記事を書くには」の文字がイタい。

## 前提
OS:CentOS7.6

## インストール
```bash
# Nodejs (8系)
curl -sL https://rpm.nodesource.com/setup_8.x | sudo bash -
sudo yum install nodejs
node -v

## yarn
# 通常は↓
curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
sudo yum install yarn

# NOT yummy.
なんかyum用のrepoだけかもだけど
上記のrepoだと1.13.0-1が入ってしまう。しょうがないから

# 直接rpm (vは公式みて安定板を指定する)
sudo wget https://github.com/yarnpkg/yarn/releases/download/v1.15.2/yarn-1.15.2-1.noarch.rpm
sudo yum localinstall yarn-1.15.2-1.noarch.rpm
rm -f yarn-1.15.2-1.noarch.rpm
```
Justinmind

# Justinmind

* Webページなどのワイヤーフレーム作成ツール
* ドラッグ&ドロップで配置、テキストの編集が可能
* イベントを追加することで画面遷移を再現できる
* 無料(有料機能もあるが)

## ダウンロード

1. [Justinmind](https://www.justinmind.com/?utm_medium=cpc&utm_source=google&utm_campaign=1063145459&utm_term=justinmind_e&gclid=CjwKCAjwvbLkBRBbEiwAChbckZehYIEoleE-_cxrOAHNCc9kab-pDf-17anTV3OnhRA1_y7mu5uXDxoCGcAQAvD_BwE)のURLへアクセスする
2. [DOWNLOAD FREE]クリック
3. [Create a Justinmind FREE ACCOUNT]で「メールアドレス」と「パスワード」を入力し[GET STARTED]をクリック
4. アプリを起動して3.で入力した「メールアドレス」と「パスワード」を入力
Windows7を起動すると黒画面になりマウスのカーソルだけが表示される。

　リモートデスクトップでWindows7のパソコンにログインしたら、黒い画面になって何も操作ができない。
　という状況があったので、対処方法のメモを残します。

状態：
　リモートデスクトップを起動して、ログイン情報を入力して接続すると、黒い画面とマウスポインタだけが表示されて他の何も表示されません。
　マウスポインタは動くけど、メニューは何も出ないそうです。
　お問い合わせをくれたユーザーは、実は別件（商用サービス）で障害が発生中だったみたいで、そのリモート先のコンピューターは緊急で使いたいということでした。
　そんなわけで、僕はリモート先のコンピューターは、即座に使用可能な状態にする必要がありました。

　ちょっと試しに僕もリモートしてみると、ご申告のとおりの状況でした。
　現象が手元で再現したわけですから、対処しましょう。

1.Ctrl+Alt+Delete(リモートデスクトップなので実際に押すのは'End')が機能せず、メニュー画面が開かない。

2.Ctrl+Shift+Escを押下してタスクマネージャーを開く。
　タスクマネージャーが動作していたので、ここからオペ開始です。

3.タスクマネージャーの「ファイル」メニューの「新しいタスクの実行」を押下します。
　ここで、cmdと打てば、コマンドプロンプトが開きます。
　修復が目的なら、ここから修復開始なのですが、今回はすぐにでも使いたい人がいるので、別のことをします。

　症状から、きっとユーザープロファイルの何かが壊れている状態だと思われるんですが、完全に破損しているなら、そもそもログインができずに即座にログアウトされるはずですので、ユーザプロファイルが不完全な状態にあるんだと思われました。
（NTUSER.DATがない。とかじゃなくて、Desktop.iniが壊れてるとか参照できないとかじゃないでしょうか？）
　ちなみにこういう症状の時のMicrosoftがおすすめする対処方法はここのURLを見ると書いてあります。
　https://support.microsoft.com/ja-jp/help/14039

　これが通用する人としない人がいると思うので、僕はコマンドプロンプトを開いて、"rstrui"を入力して、システムの復元を試すことをお勧めします。
　再起動が必要になるのでリモート操作だとドキドキが止まらない方法ですが、うまくいく可能性が一番高いと思います。

4.「新しいタスクの実行」でexplorer.exeを指定して実行する。
　エクスプローラーが開くかどうかを試す、というより、本来動いていなきゃいけないWindowsのバックグラウンドのプロセスとかに刺激を与えるのが目的です。
　今回は、これがうまく働き、タスクバーやデスクトップに配置されていたはずのアイコンが復元されました。

5.ログオフせずにセッションを切断した状態でユーザーに引き渡す。
　ログオフしてしまうと、4.までの操作の状態が残らないので、リモートデスクトップを終了して、ユーザーにログインを試してもらいます。
　僕の操作した状態がそのままユーザーに引き継がれるので、ユーザープロファイルはきっと壊れたままですが、そのまま操作をしてもらいました。

　時間がない、ちょっとコンピューターの再起動はしたくない。みたいなときにはこの方法が使えると思います。

　働き方改革で在宅勤務が一般的になると、どんな構成なのかは別として仮想デスクトップの利用が増えるとユーザプロファイル破損はいろいろ致命打がありそうですよね。
　そういえば、去年あたりに耳にしたAzureのWVDはもう詳細が発表されたんでしょうか？

※便利なショートカットキーの一覧。
https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%A7%E3%83%BC%E3%83%88%E3%82%AB%E3%83%83%E3%83%88%E3%82%AD%E3%83%BC%E4%B8%80%E8%A6%A7

　WindowsOSとMacOSのショートカットはいくつか覚えておくとぱっと使えて便利です。
WordPress 脆弱性情報 情報源のまとめ

[@koshi_life](https://twitter.com/koshi_life) です。

[こちら](https://qiita.com/koshilife/items/2829d7606627172ce066) の投稿で WordPress Plugin(duplicator)の脆弱性を突かれインシデント対応をしたことを書きました。

WordPress関連の脆弱性情報を早くキャッチアップできていれば未然に防げたと考えているので情報源として、良さそうなサイトをまとめます。

表の参考列に上記duplicator事象の詳細情報、注意喚起が投稿されたていたかどうかも付記してます。

おすすめのサイト、キャッチアップ方法があれば是非コメントで教えてもらえたら嬉しいです。

## まとめ

|ジャンル|言語|サイト|RSS/ATOM|参考「duplicator 1.2.40 脆弱性情報」|
|:--|:--|:--|:--|:--|:--|
|国内主要レンタルサーバ事業|JP|[エックスサーバー お知らせ](https://www.xserver.ne.jp/support/news.php)|?|[有り](https://www.xserver.ne.jp/news_detail.php?view_id=4751)|
|国内主要レンサバ事業|JP|[エックスサーバー Twitter](https://twitter.com/xserverjp)|[RSS](http://twitrss.me/twitter_user_to_rss/?user=xserverjp)[^1]|[有り](https://twitter.com/xserverjp/status/1038389206140108800)|
|国内主要レンサバ事業|JP|[さくらインターネット お知らせ](https://www.sakura.ad.jp/information/announcements/)|[RSS](https://www.sakura.ad.jp/information/feed/?post_type=announcements)|[有り](https://www.sakura.ad.jp/information/announcements/2018/09/20/1968198178/)|
|国内主要レンタルサーバ事業|JP|[さくらインターネット Twitter](https://twitter.com/sakura_pr)|[RSS](http://twitrss.me/twitter_user_to_rss/?user=sakura_pr)[^1]|[有り](https://twitter.com/sakura_pr/status/1042665714321022978)|
|国内主要レンタルサーバ事業|JP|[ロリポップ！ お知らせ](https://lolipop.jp/info/news/)|?|[有り](https://lolipop.jp/info/news/6085/)|
|国内主要レンタルサーバ事業|JP|[ロリポップ！ Twitter](https://twitter.com/lolipopjp)|[RSS](http://twitrss.me/twitter_user_to_rss/?user=lolipopjp)[^1]|?|
|はてブ|JP|[はてブ「WordPress 脆弱性」を検索(新着 3ブクマ以上)](http://b.hatena.ne.jp/search/text?q=WordPress+%E8%84%86%E5%BC%B1%E6%80%A7&sort=recent&users=3&safe=on)|[RSS](http://b.hatena.ne.jp/search/text?q=WordPress+%E8%84%86%E5%BC%B1%E6%80%A7&sort=recent&users=3&safe=on&mode=rss) ※[参考](https://qiita.com/suesan/items/a02c893b5d391cee1a86)|?|
|徳丸先生|JP|[徳丸浩の日記](https://blog.tokumaru.org/)|[RSS](https://blog.tokumaru.org/feeds/posts/default?alt=rss)|[有り](https://blog.tokumaru.org/2018/09/wordpress-duplicator-plugin-vulnerabilty.html)|
|本家|En|[WordPress.ORG - news](https://wordpress.org/news/)|[RSS](https://wordpress.org/news/feed/), [ATOM](https://wordpress.org/news/feed/atom/)|?|
|脆弱性DB|En|[CVE Details - WordPress](https://www.cvedetails.com/vulnerability-list/vendor_id-2337/product_id-4096/)|?|?|
|脆弱性DB|En|[WPScan Vulnerability Database](https://wpvulndb.com/)|?|[有り](//wpvulndb.com/vulnerabilities/9123)|
|脆弱性DB|En|[ThreatPress](https://db.threatpress.com/)|?|[有り](https://db.threatpress.com/vulnerability/duplicator/wordpress-duplicator-plugin-1-2-40-arbitrary-code-execution-vulnerability)|

[^1]: TwitterタイムラインのRSS化は [こちら](https://yokonoji.work/twitter-rss) を参考にしました。

### 参考

- [セキュリティサイトまとめ](https://qiita.com/Brutus/items/6559cc1b2cfaf4fe48ec)
- [【随時更新】セキュリティに関する情報源を整理してみた](http://security.nekotricolor.com/entry/my-news-source-about-information-security)
UiPathの開発に実際のところ必要なスペック

## 公式ハードウェア要件

UiPathの実行に必要なPC環境とはどの程度でしょうか。
公式には以下のような最小／推奨ハードウェア要件が設定されています。



### **◆UiPath Studio**
**【最小要件】CPU：1.4GHz 32-bit (x86)／RAM：4GB**
**【推奨要件】CPU：デュアルコア 1.8 GHz、64 ビット／RAM：4GB**



### **◆UiPath Robot**
**【最小要件】CPU：2 x 1.8GHz 32-bit (x86)／RAM：4GB**
**【推奨要件】CPU：4 x 2.4GHz 64-bit (x64)／RAM：8GB**



参考リンク：
https://studio.uipath.com/lang-ja/docs/hardware-requirements
https://robot.uipath.com/lang-ja/docs/hardware-requirements


## 筆者の考える推奨ハードウェア要件
しかし、これを鵜呑みしてはいけません。

実際にインストールしてみれば分かることではありますが、
上記のスペックでは、**特にStudioは推奨スペックでも動作が厳しい**でしょう。

UiPathはことのほかハイスペックパソコンを要するソフトウェアです。


筆者の考える推奨スペックは下記の通りです。

※Studio/Robotともに
**CPU：2Core/4Thread 動作周波数：2.0GHz／RAM：8GB／ストレージ：SSD**



RAM8GB以上推奨のため、CPUは必然的に64bitになります。
**Intelであれば第8世代以降**ならi3／i5／i7／i9のいずれでも問題なく、**AMDであればRyzenシリーズ**を選んでおけばどれでも問題ないでしょう。

StudioとRobotがともに同じ推奨スペックなのは、そもそもRPAでは環境差異による動作不全がしばしば起こるため、
**開発環境・実行環境ともに同一スペックとすることを推奨する**ことに起因します。



また、ストレージについては、RPAの性質上、ストレージI/O（入出力）が頻繁に発生しますので、**SSDであるとベター**です。

SSDの中でもSATAではなく**PCIe**という規格のものだと尚良いでしょう。
最近はSSDもかなり安くなって来たため、RPAをやるならSSDにしない手はありません。

## 重要度
いずれもRPA稼働に重要な3要素ですが、この中で特に重要度を順番にするなら**「RAM＞CPU＞SSD」**となるでしょう。

ゲームをするわけではないので、GPUなどはインテルのオンボードですら問題ありません。

## 参考リンク
その他、実際に組んでみたUiPath用ノートパソコンの実例などは下記を参照してください。

RPAコンサルティング合同会社 - UiPathの動作に必要なスペック
https://www.rpacons.com/blog/tech/UiPath_Spec
ethereumjs-util を使用した ECDSA 署名と署名検証

[ethereumjs-util](https://github.com/ethereumjs/ethereumjs-util) を使用した ECDSA 署名および署名検証の手順です。

# 署名の手順
1. 署名するメッセージの Keccak ハッシュを得ます。
2. メッセージのハッシュに署名をします。

# 署名検証の手順
1. 検証したいメッセージと署名を入手します。
2. メッセージの Keccak ハッシュを得ます。
3. ecrecover を使用して、署名者の公開鍵を得ます。
4. 公開鍵から Ethereum アドレスを計算し、実際の署名者のアドレスと比較します。

# サンプルコード
```js
const EthUtil = require('ethereumjs-util')

// 署名者のアドレス
const SIGNER_ADDRESS_STRING = '0x89c24a88bad4abe0a4f5b2eb5a86db1fb323832c'

// 署名者の秘密鍵文字列
const PRIVATE_KEY_STRING = '0x61ce8b95ca5fd6f55cd97ac60817777bdf64f1670e903758ce53efc32c3dffeb'

// メッセージ
const MESSAGE = 'piyopiyo!'

// 秘密鍵の文字列からバッファを取得  
const privateKey = EthUtil.toBuffer(PRIVATE_KEY_STRING)


// 与えられたメッセージと秘密鍵から署名を返すメソッドです。
function sign(message, privateKey) {
	 
	// メッセージ の Keccak ハッシュを得ます。
	const hashedMessage = EthUtil.keccak(message)
	
	// ecsign を使用してメッセージのハッシュに署名します。
	const signature = EthUtil.ecsign(hashedMessage, privateKey)

	return signature
}


// 与えられたメッセージと署名から署名者の Ethereum アドレスを導出し、
// 署名者が正しいかどうかを返すメソッドです。	
function verify(message, signature, address) {

	// メッセージ の Keccak ハッシュを得ます。
	const hashedMessage = EthUtil.keccak(message)

	// ecrecover を使用して、署名から公開鍵を導出します。
	const publicKey = EthUtil.ecrecover(hashedMessage, 
                                    	signature.v, 
                                    	EthUtil.toBuffer(signature.r), 
                                    	EthUtil.toBuffer(signature.s))
	
	// 公開鍵から署名者のアドレスを計算します。
	const recoverdAddress = EthUtil.bufferToHex(EthUtil.pubToAddress(publicKey))

	// アドレスを比較します。
	if (EthUtil.toChecksumAddress(address)
		== EthUtil.toChecksumAddress(recoverdAddress)) {
		return true
	} else {
		return false
	}

}


// 署名
const signature = sign(MESSAGE, privateKey)
console.log('signature:\n', signature)


// 署名検証
const isVerified = verify(MESSAGE, signature, SIGNER_ADDRESS_STRING)
console.log('isVerified:', isVerified)
```

# Ref.
- https://github.com/ethereumjs/ethereumjs-util/blob/master/docs/README.md#const-ecsign
- https://github.com/ethereumjs/ethereumjs-util/blob/master/docs/README.md#const-ecrecover
- https://scrapbox.io/a42/ethereumjs-util_を使用した_ECDSA_署名と署名検証
【Unity2D】0からのローグライク作成記録その3～パラメータ・セーブ・UI～

![1.gif](https://qiita-image-store.s3.amazonaws.com/0/370076/f95a7c1e-5a23-5a14-ee70-fbeb1a32f677.gif)
タイトル画面。

![2.gif](https://qiita-image-store.s3.amazonaws.com/0/370076/eaa2d9e2-6c54-e15e-38b1-0c2ccb96747c.gif)
ゲーム最序盤プレイ画面。オリジナル要素が欲しくて、ミスタードリラー的な穴掘りローグライクゲームにしました。

下に実装に苦労したものを軽く書いておきます。
ド初心者向けです。

#プレイヤーと敵のパラメータ管理
[Unity-Excel-Importer-Maker](http://tsubakit1.hateblo.jp/entry/20131010/1381411760)を使いEXCELで管理している。HPなどのパラメータはプレイヤーや敵にアタッチしているスクリプトで取得するようにする。パラメータは管理する場所が分散しすぎないように。
EXCELからデータを抜き出す時にエラーが頻出していたが、int変数の場所に文字列が入っていた為だった。
#セーブデータの管理
[【Unity】オブジェクトをJsonにシリアライズしてテキストに保存・読み込みする](https://qiita.com/2dgames_jp/items/3c232b37d20ce12edb07)
この記事を参考に作成。シーン切替時にオートセーブするようにした。保存項目はプレイヤーのステータスとセーブ時にいたシーン名。これによりロード時にそのシーンの最初からやり直す様に出来る。
またゲームオーバー時にはセーブだけして、拠点扱いのシーンに飛ばすようにした。
#UI右上のメッセージダイアログ
「プレイヤーは10のダメージを与えた」「宝箱を開けた」などのメッセージ表示箇所です。空オブジェクトにスクリプトを貼っつけて管理しています。実装はキューを使っています。

```ruby:qiita.rb
using UnityEngine.UI;　//必須

public class UIControl : MonoBehaviour
{
    Text MessageDialog1; //メッセージダイアログの表示
    Text MessageDialog2; //メッセージダイアログの表示
    Text MessageDialog3; //メッセージダイアログの表示
    Text MessageDialog4; //メッセージダイアログの表示
    Text MessageDialog5; //メッセージダイアログの表示
    Queue<String> Message = new Queue<String>(); //メッセージダイアログの入れ物（キュー）
    int MaxMessegeCount = 30; //メッセージの最大ログ数
    string MessegeOut;

    //各クラスから受けとったメッセージを入れるメソッド
    public void MessageDialogIn(string InMessege)
    {
        //受け取ったメッセージを格納
        Message.Enqueue(InMessege);
        //メッセージログが最大になったら一つ消す
        if (Message.Count >= MaxMessegeCount)
        {
            Message.Dequeue();
        }
        MessageDialogOut();
    }

    //メッセージ表示用
    void MessageDialogOut()
    {
        //メッセージダイアログのテキストを取得（表示用）
        MessageDialog1 = GameObject.Find("MessageText (1)").GetComponent<Text>();
        MessageDialog2 = GameObject.Find("MessageText (2)").GetComponent<Text>();
        MessageDialog3 = GameObject.Find("MessageText (3)").GetComponent<Text>();
        MessageDialog4 = GameObject.Find("MessageText (4)").GetComponent<Text>();
        MessageDialog5 = GameObject.Find("MessageText (5)").GetComponent<Text>();

        //メッセージログを下から上にコピーしていき、最後に最下段はDequeueしたものを入れる
        MessageDialog1.text = MessageDialog2.text;
        MessageDialog2.text = MessageDialog3.text;
        MessageDialog3.text = MessageDialog4.text;
        MessageDialog4.text = MessageDialog5.text;
        MessageDialog5.text = Message.Dequeue(); ;
    }
}
```

プレイヤーの攻撃など、メッセージが出たら外部より「MessageDialogIn」を実行して飛ばしています。Enqueueで入力しDequeueで出力できる。UIはテキストボックスを縦に5つ並べてそこに表示している。
配列などを使えばスムーズに書けるのですが力技で実装しています。持っているチンケなカードで勝負している感が凄い。
#今後実装すべきもの
- ゲームボリューム：敵や攻略フロアの追加
- アイテム：インベントリとアイテムの実装。拠点では倉庫と商人も欲しい。
- トラップ：ダメージ床やワープ等

アイテム要素が入れられたらローグライクとしての基本がほぼ完成する。
床に置いてあるアイテムに接触→プレイヤーのインベントリに追加→メニューより使用→アイテム消失・効果発生→ターン経過としたいが、実装の難易度は高そう。良いアセットとか参考になるものがあったら誰か教えてください…。
RaspberryPiに入れたk3sをRancherサーバーから見えるようにした

Qiita初投稿です。
よろしくお願いします。

k3sをラズパイに入れてRancherでマルチクラスタ管理したらかなり強力だと思って、家のRaspberryPiで実験してみました。
色々ハマったので時系列に動くまでのメモ。

### まず最初に何も考えずにやった（2月の終わり）

k3sのインストールは超簡単

```
$curl -sfL https://get.k3s.io | sh -
$k3s server
```

- k3sは問題なく動いた
- rancher-agentがarmでは動かない

うん。そらそうか。

### dockerhubにarm版のrancher-agentがでた（3/14）

rancher-agentのimageを変更して試してみた

rancherの画面からクラスタのimportを選び、表示されたURLのYAMLを一旦保存

```
$curl --insecure -sfL https://35.200.55.75/v3/import/XXXXX.yaml  > rancher.yaml
```

imageを変更(２箇所)

```
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: cattle-cluster-agent
  namespace: cattle-system
      ...
      containers:
          ...
          - name: CATTLE_K8S_MANAGED
            value: "true"
          image: rancher/rancher-agent:v2.2.0-rc4-arm64
...
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
    name: cattle-node-agent
      ...
      containers:
      - name: agent
        image: rancher/rancher-agent:v2.2.0-rc4-arm64
```

前回とは違うエラーだけど、やっぱり動かない。
よくよく考えたら、rasbianは32bitだってことに気づく。。。

### ラズパイのOSから書き換えてみる（3/15）

####2020/3/21追記 rasbianOSを64bitにする。

まだ安定版ではないですが、k3sが動作することは確認できました。こっちの方が簡単です。

```
sudo rpi-update
```

```
sudo vi /boot/config.txt

arm_64bit=1
```

####以前の手順

OSはOpenSUSEのLeap15.0を使用  
https://en.opensuse.org/HCL:Raspberry_Pi3  
（うちの環境だと、Tumbleweedはwifiモジュールを認識しなかった。ラズパイ用のUbuntuもwifiがうまく動かなかった。）

OS作成（macから）  
注）ddで書き込む先はよく確認して行ってください。

```
$xzcat openSUSE-Leap15.0-ARM-JeOS-raspberrypi3.aarch64-2018.07.02-Buildlp150.1.1.raw.xz  | dd bs=4m of=/dev/rdisk2 ;sync
```

最初と同様にk3sを導入後、起動

```
$k3s server
...
INFO[2019-03-16T14:41:03.713645166Z] Waiting for containerd startup: rpc error: code = Unavailable desc = all SubConns are in TransientFailure, latest connection error: connection error: desc = "transport: Error while dialing dial unix /run/k3s/containerd/containerd.sock: connect: connection refused"
```

なんか、rasbianでは見なかったエラーが出た。。。

原因は調べられてないけど、opensuseの場合、serverとagentを別々に起動したらうまくいった
（resolv.confとかネットワーク周りだろうと勝手に想像）

```
$k3s server --disable-agent
$cat /var/lib/rancher/k3s/server/node-token
→表示されるtokenをメモ
$k3s agent -node-name raspberrypi3 --token <token> --server https://<ラズパイのIP>:6443
```

あとは、3/7と同じようにrancher-agentをインポート（3/15時点でrc6）

### 無事起動！
<img width="1270" alt="スクリーンショット 2019-03-16 21.32.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/306826/c3c7446d-4a81-ecdb-dc2e-681c2fc05309.png">

podの状態

```
$kubectl get po -n cattle-system
B8-27-EB-98-2F-9B:~/kubernetes # kubectl get po -n cattle-system
NAME                                   READY   STATUS    RESTARTS   AGE
cattle-cluster-agent-686954759-z7xjn   1/1     Running   0          2m13s
cattle-node-agent-jzl8n                1/1     Running   0          2m9s
```

いろいろ組み合わせのマジックがあるみたいで、またバージョン上がると動かないとかいろいろありそうだけど、とりあえずやれそうな気はしてきた。
ドメイン代を圧倒的に節約する方法(個人開発者向け)

今回はドメイン代を圧倒的に節約する方法を解説します。
## ドメイン代を圧倒的に節約する方法(個人開発者向け)
ドメインをいくつも取っていると意外と出費になりますよね。
しかし、**サブドメイン**を活用することで取得するドメインは１つで良くなります。

僕の例で行くと、
メインブログのドメインは
https://toshioakaneya.com/
ですが、
自作したオンラインゲームは
https://boundbattle.toshioakaneya.com/
で配信しています。

サブドメインはそれぞれがSEO的にも独立しているのでとても便利です。(はてなブログは各ユーザーにサブドメインが割り当てられますよね。)

ぜひ活用して下さい。
## 終わりに
私は現在、Web3のサービスの開発をしています。詳しくはこちらの記事をご覧下さい。
        [無料でイーサリアムが当たる、Web3時代の寄付サイトを作った話](https://note.com/kenroda/n/n814347fbdcd7)
SMS 受信、Google Drive と Amazon での２段階認証ができなかった原因

# この記事のきっかけと動機
Google Drive ログインの際に、スマフォ画面をロックし、パスワードを入力させるようにする２段階認証を使っていた。
ところがある日から、Google Drive ログインしようとしてもスマフォ画面がロックされなくなり、（おそらく同時に）SMS も届かなくなった。試してわかったことを記録に残しておくので、同じトラブルで困った場合の参考にしていただければ、と思う。

何かしたのが原因なんだけれど、寝ぼけながら操作していた。そのため、何をしたせいでトラブル発生したのかは、残念ながら特定できていない。

# 最終的にわかったこと
Wi-fi 通信だけでなるべく済ませようとして、あちこちのアプリでバックグラウンド通信の ON/OFF を OFF に切り替えていた。それを ON に戻したことで最終的にすべて解決した。
およびメモリ消費を抑えようとして、使っていないアプリの更新はほったらかしにしたり、デフォルトで入っている状態に戻したりしていた。とにかくすべてのアプリを最新状態に更新した。一部のアプリでの SMS のみがこれで復活した。

# 試してもダメだったこと
SIM カードが原因の場合がある、と Web サイトで見て、某大手通信会社のショップに行って、SIM カード変えてもらってもダメだった。これは機種変更しないといけないのか？　でもまだ支払いがＸか月残ってるのに。

すべてのアプリを最新状態に更新することで、LINE からの SMS のみ復活、Amazon へのログイン２段階認証に必要な SMS はダメなままだった。自分自身が出品するために使う Amazon アカウントへログインするためには２段階認証が必須なのであせった。休止状態への変更すらできない。

SMS 受信ができなくなったり、２段階認証ができなくなったりする前にインストールしたアプリをいくつかアンインストール。無関係だった。

メッセージアプリのリセット、SMS 受信のデフォルトをメッセージアプリから、Facebook のメッセンジャーへ切り替え

# おまけ
結果的に機種変更せずに、SMS 受信も Google Drive と Amazon での２段階認証もできるようになった。
機種変更に備えて料金プランの説明見ていたら、前回機種変更した時にはなかったピタットプランがあった。これを使うと安く済むことに気づいて、プラン変更した。トラブルに遭遇していなかったら料金プラン変更していなかったので、これは不幸中の幸いだったかもしれない
Webフォント(Google Font)で必要な文字だけ読み込んで、少し読み込み速度を上げる

例えば、サイトのタイトルだけにWebフォント(Google Font)を使用している場合など、
パラメータの「?family=<フォント名>」の後に「&text=<使用する文字>」をつけることで、
最小限のフォントだけを読み込むようになります。

```
<!-- Google Font -->
<link href="https://fonts.googleapis.com/css?family=Play&text=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" rel="stylesheet">
```
RaspberryPi Zero W(H)で固定IPアドレスを設定する

# はじめに

- RaspberryPi3 B+と同じ方法では固定IPがふられなかった。

#### ヘッドレスでRaspberryPi Zero W(H)に接続する

- microSDにOSを焼く
- 焼いたmicroSDのbootフォルダをパソコンで開く
- 空のsshファイルを新規作成する
- wpa_supplicant.confファイルを新規作成する

```txt:wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=JP

network={
        ssid="My-SSID"
        scan_ssid=1
        psk=暗号化したパスフレーズ
}
```

- microSDをRaspberryPi Zero W(H)に挿して、電源ON
- 無線LANルータの管理画面でRaspberryPi Zero W(H)のIPを調べる
- 調べたIPアドレスにSSH接続する

#### 初期設定をする

- raspi-configを起動して設定する 
 - VNCをEnable
- VNCで接続して初期設定をする

#### 固定IPアドレスの設定

##### NGだった方法

- /etc/network/interfaces.d/wlan0に設定を書く

```sh:/etc/network/interfaces.d/wlan0
auto wlan0
allow-hotplug wlan0
iface wlan0 inet static
  address 192.168.0.xxx
  netmask 255.255.255.0
  gateway 192.168.0.1
  wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
```

##### OKだった方法

- /etc/dhcpcd.confに設定を書く

```sh:/etc/dhcpcd.conf
:
(略)
:
interface wlan0
static ip_address=192.168.0.xxx/24
static routers=192.168.0.1
static domain_name_servers=192.168.0.1
```

# おわりに

- RaspberryPiのネットワーク設定周りは面倒だな。
laravel mysql 距離 geo lat lng 検索

# mysql で 位置情報検索してみようぜ

・geometry 型を使おうぜ
・検索で使うから SPATIAL INDEX も貼る。
・ライブラリとか使わない。使ったけどバグってたんで。
・距離はkmで取得しない

# まずは位置情報テーブルを作る

```

CREATE TABLE `geos` (
`name` VARCHAR(30) NOT NULL,
`location` GEOMETRY NOT NULL
) ENGINE = InnoDB;

```


# インデックスを貼る

```

ALTER TABLE `geos` ADD SPATIAL `location` (`location`);

```

なぜかインデックスを貼れない場合は以下をやる。
#1416 - Cannot get geometry object from data you send to the GEOMETRY field
```
UPDATE `geos` SET `location` = POINT(0,0)
```


# 位置情報を挿入

経度、緯度 の順番

```

INSERT INTO `geos` (`name`, `location`)
VALUES ('札幌駅', GeomFromText('POINT(141.350857 43.067656)')),
('上野駅', GeomFromText('POINT(139.776381 35.712297)')),
('名古屋駅', GeomFromText('POINT(136.881537 35.170915)')),
('アメリカ', GeomFromText('POINT(37.77493 -122.419416)')),
('品川駅', GeomFromText('POINT(139.73876 35.628471)'));

```
(laravel で挿入する場合は)

```

        //use DBしとく
        $model = Geo::firstOrNew(['id' => 3]);
        $model->name = 'テスト保存';
        $model->location = \DB::raw("GeomFromText('POINT(139.776381 35.712297)')");
        $model->save();

```


# 直接SQL実行

```

SELECT
id,name,
ROUND(
GLENGTH(
GEOMFROMTEXT( CONCAT( 'LineString( 136.8735744 35.168256 , ', X( location ) ,  ' ', Y( location ) ,  ')' )
)
) * 111000 ) AS distance
FROM
geos
ORDER BY
distance

```




# 速度は？
インデックス使えないみたいだけど、上記のSQLがいろいろ試した中で最速。
(合計 11103, Query took 0.0298 seconds.)


# laravel

ユーザーモデルにjoinして使おう。

```

        $lat = '136.8735744';
        $lng = '33.590599';

//        ユーザーの name と geo の name がかぶると取得できんので、 as 句使っておく
        $res = User::with('geos')
            ->join('geos', 'users.id', '=', 'geos.id')
            ->selectRaw(
                "users.name as user_name,geos.id,geos.name,ROUND(
GLENGTH(
GEOMFROMTEXT( CONCAT( 'LineString( ".$lat." ".$lng." , ', X( location ) ,  ' ', Y( location ) ,  ')' )
)
) * 111000 ) AS distance"
            )
            ->orderBy('distance', 'ASC')//遠い順、近い順
            ->limit(10)
            ->get();

        foreach ($res as $v) {
            echo $v->id. ' : ' .$v->user_name.'さん 住所 '.$v['geos'][0]['name'].' 距離: '.$v->distance.'<br>';
        }


```
php-master-changes 2019-03-15

この日は bcpow() の不具合修正、不要コードの削除、弱参照の実装が master の修正と噛み合ってなかった部分の修正、ビルドシステムのリファクタリング、テストこけの修正、PHPTestfest2017 のテストの取り込み、phar のビッグアンディアン環境での不具合修正、構文定義ファイルのリファクタリングがあった！

# 2019-03-15
## nikic: Fixed bug [#77742](https://bugs.php.net/bug.php?id=77742)
- https://github.com/php/php-src/commit/e7d40afb7a7984174eb132a14b7a6621c8e76258
- [7.2~]
- ext/bcmath で、bcpow() の実装を修正
- s390x 用に gcc の -O2 でビルドすると、鼻から悪魔効果によりオーバーフローチェックコードが消えてテストこけしてたらしい
- メインフレーム事情は全く知らんけど s390 とか言われるとワクワクする

## c9s: ext/session: remove the redundant convert_to_long
- https://github.com/php/php-src/commit/a59881fa04f0ce0054675de907401d28b2b205f2
- [7.4~]
- ext/session で、不要な convert_to_long() 呼び出しがあったのを削除

## nikic: Fix weakref object handlers for master
- https://github.com/php/php-src/commit/273aa37b8396f4e57791df979dcba899b1328e70
- 弱参照の実装で、オブジェクトハンドラが [master では zval でなく zend_object と zend_string をとるようになっている](https://qiita.com/sj-i/items/a5690a083b5754c30dc7#dstogov-refactor-zend_object_handlers-api-to-pass-zend_object-and-zend_string-insted-of-zvals)のを反映して修正

## petk: Remove HAVE_STRFTIME
- https://github.com/php/php-src/commit/3a857852a8dada5e60ba6d028878ecd6224b9c5d
- [7.4~]
- HAVE_STRFTIME の条件コンパイルを削除
- strftime() は c89 標準に入ってる

## petk: Clean build system
- https://github.com/php/php-src/commit/97d25c87d2f875426aa27495896f419412de7ab2
- [7.4~]
- ビルドシステムのリファクタリング
- 不要な記述/チェックを削ってる

## petk: Fix failing test
- https://github.com/php/php-src/commit/c02a03b49bd1ac365d5fe84282f005689c26b47e
- テストこけの修正

## thiagooak: Add tests to XMLReader
- https://github.com/php/php-src/commit/4cfa01bfb8c95b094e104a70e877cfe5aae04104
- [7.4~]
- ext/xmlreader で、テストの追加
- PHPTestfest2017

## laruence: Fixed bug [#77697](https://bugs.php.net/bug.php?id=77697) (Crash on Big_Endian platform)
- https://github.com/php/php-src/commit/b41959089313d7397c936a885e9d1ca84e0f93f8
- [7.3~]
- ext/phar で、ビッグエンディアンな環境でクラッシュする場合がある問題の修正
- size_t のアドレスを unsigned int のポインタにキャストしてとってるので、環境によっては持ってくる部分違ってしまうのでだめですねという奴だった

## nikic: Remove unnecessary precedence/associativity annotations
- https://github.com/php/php-src/commit/2a04efe0e42c9d7ac150bc918e16edb96cf4f219
- [7.4~]
- 構文定義の不要な結合方向の記述を潰した
Python手遊び(OpenCV,機械学習向けの教師データ用意)

#この記事、何?
機械学習でGridSearchCV近辺触ってて、精度を悩んでみたくなった。
ただ、アヤメやタイタニックと向き合うのはいまいち気が乗らない・・・
だって、スコアが良すぎたら過学習を疑ってしまうし、低くても理解や努力が足らないのか、そもそもそのくらいなものなのかがよくわからない。

というわけで、音ゲーのスクリーンショット(スクショ)で何かしてみようと。
まずは、初めて画像がらみをどうにかする初心者向けの課題として、数値分類をしようかと。
で、やったことというと・・・教師データとして数字1文字ずつの画像ファイルを作った。
スクショを94枚用意して、1枚当たり31個の数字があったので94*31=2914個の画像ファイルを作った。

#全体的な方針
今回の投稿は2914個の画像ファイルに細切れにしたまでだけど、長期的には目的はこんな感じ。

Lv.1 ： 決まったドット位置にでる数字を読み取る
Lv.2 ： 何種類かのスクリーンパターンごとにパターンを判別したうえで数字を読み取る
Lv.3 ： 決まったドット位置に出る曲名を読み取る
Lv.4 ： 何種類かのスクリーンパターンごとにパターンを判別したうえで文字を読み取る
Lv.5 ： 未知のパターンに対しても文字・数字を読み取る

まあ・・・キャライラストからアイドルの子を判別できたり、スマホのスクショではなく、アーケードゲームのレザルトを撮影した写真からスコアとか曲名とか取れるようになるといいなぁ・・・始めたばかりの自分には想像もつかない感じですが。

#使ったもの
Windows 8 Pro
Python 3.7.1 (Anaconda)
OpenCV 3.4.1

(参考：デレステ)
■アイドルマスター シンデレラガールズ スターライトステージ
https://cinderella.idolmaster.jp/sl-stage/

#方針
今回は上記でいうといわばLv.0。Lv.1の解析を目的にした準備。
Lv.1で解析させたい数字がいっぱい出る画面として、プレー後のスコア画面。
スコアとして7桁の数字が出る。
それ以外に、タイミングピッタリ(PERFECT)～駄目(MISS)までの5種類の数と、つながった数(COMBO)が出る画面。(それぞれ4桁)
それらがスクショで固定的な位置に出るから初心者向けとしてピッタリ。

Pythonで処理する前に、画像の何ドット目から何桁なのかということの位置合わせのために画像を表示してポイントしたら位置を数えてくれるツールをC#で別途作ってみた。
で、そこから得た情報がこんな。

| Name | FromX | FromY | SizeX | SizeY | Digits |
|:-:|:-:|:-:|:-:|:-:|:-:|
| PERFECT | 772 | 344 | 132 | 44 | 4 |
| GREAT  | 772 | 403 | 132 | 44 | 4 |
| NICE  | 772 | 462 | 132 | 44 | 4 |
| BAD  | 772 | 521 | 132 | 44 | 4 |
| MISS  | 772 | 580 | 132 | 44 | 4 |
| COMBO  | 759 | 669 | 144 | 52 | 4 |
| SCORE  | 653 | 827 | 252 | 49 | 7 |

*1行目、PerfectはX=772,Y=344の位置から、132x44サイズで4桁という意味

あとはC#でこれを一つのjsonとして出力しておいて、pythonで読んでOpevCVでバラバラにしようと。
で、あとで学習させようと。

※あくまで本記事の目的はOpenCVでの分割までです。
ホントは・・・C#ももっといい感じのコードにしてアップしようかと思ったけどやっつけ感が半端ないものになったので上げられない。。。


#できあがり
これで2914個の「0」とか、「3」とか書いたちっちゃいファイルができた。

```python
import os
import json
import cv2

jfile = 'score.json'
jdata = open(jfile)
dict = json.load(jdata)

#7種類の数ごとに繰り返す
for f in range(7):
    #位置とか桁とかの読み取り
    header = dict[f]['Name'] 
    x = int(dict[f]['FromX'])
    y = int(dict[f]['FromY'])
    width = int(dict[f]['SizeX'])
    height = int(dict[f]['SizeY'])
    digits = int(dict[f]['Digits'])

    #ファイルごとに繰り返す
    for dirpath, dirs, files in os.walk('C:/projects/qiita_data/20190303/score'):
        for name in files:
            #各桁ごとに1文字ずつ切り出す
            for d in range(digits):
                src = cv2.imread(dirpath + '/' + name, 1)
                dst = src[y:y+height, x+int(width/digits)*d:x+int(width/digits)*(d+1)]
                #別フォルダに個別のファイルとして出力
                cv2.imwrite('output/' + header + '_' + str(d) + '_' + name, dst)

```

#感想
初めてOpenCV使ってみた。
画像ってそんなに簡単なコマンドで何とかなるものなのね・・・やっぱPythonすごいな。
あっ、教師デーったってことは94ファイル・・・2914個の数字を読んで書き留めないといけないのね。めんどい。。。

あと、松尾先生がしばらく前のAI関連の番組で「レシートをOCRして家計簿に落としてくれるAI」がでてた。
それ、レシートに出てくる、商品名・価格だけじゃなく、それらが「食費」なのか、「交際費」なのかとかのジャンル分けとか、
店舗名とか、スルーしてよい特売のお知らせとかの意味まで理解してカテゴライズしてた気がする。
すごいな。Lv.100?
discord.py(Rewrite版)のCogを使ってみる

# はじめに
こんにちは。
しゅみでdiscordのbotをつくったりしているものです。

discord.py（rewrite版）の **Cog** を触ってみたので備忘として残しておこうと思います。

# 前提
Discord向けのbotを実装するにはいくつか選択肢がありますが、pythonで実装する場合は **[Rapptz/discord.py](https://github.com/Rapptz/discord.py)** を使う人が多いと思います。

disocord.pyには「async版」と「rewrite版」という2つのバージョンが存在します。
2つのバージョンの違いについては以下の記事にあるとおりです。

- [discord.pyのasync/rewriteとは何なのか](https://qiita.com/1ntegrale9/items/f4c47a6a69ecf23fc5db)

現在おもに開発が続いているのは「rewrite版」のほうです。

- [discord.py 1.0.0a ドキュメント](https://discordpy.readthedocs.io/ja/latest/)

# Cogとは
Cogという単語をググった結果、

> Cog
主な意味　(歯車の)歯、(企業・事業などで)必要だがつまらぬ仕事をしている人、「歯車」

らしいです。

ではdiscord.pyのCogはどういうものかというと、

[Cogs](https://discordpy.readthedocs.io/ja/latest/ext/commands/cogs.html#cogs)
>
There comes a point in your bot's development when you want to organize a collection of commands, listeners, and some state into one class. Cogs allow you to do just that.

**複数のコマンドやリスナーをまとめたり、様々なステータスをクラス化したい時に使えるフレームワーク**
と説明されています。
コマンドやリスナーなどをbotを構成する歯車として機能単位で分割するイメージでしょうか。
これまでは冗長になってくると都度モジュール化したりしてましたが、Cogを使えばもっとシンプルに実装できそうです。

# 実装
絵文字を揃えて遊ぶ「slot」というコマンドをCogとして切り出してみようと思います。
（コマンドの処理ロジックはここでは割愛します）
Cogとして実装する為には以下の要件を満たす必要があります。

- `commands.Cog`のサブクラスであること
- コマンドは`commands.command()`で修飾されること
- リスナーは`commands.Cog.listener()`で修飾されること
- Cogは`Bot.add_cog()`を呼んでbotに登録する
- 登録したCogを削除する場合は`Bot.remove_cog()`を呼ぶ

上記を踏まえて以下のように実装してみました。

```game.py
import configparser
import random
from discord.ext import commands

class Game(commands.Cog):

    def __init__(self, bot, config):
        self.bot = bot
        self.config = config
        self.slot_game_counter = 0
        self.bingo_game_counter = 0

    @commands.command()
    async def slot(self, ctx):
        # 内部処理
        await ctx.send(message)

def setup(bot, config):
    bot.add_cog(Game(bot, config))
```

`commands.Cog`のサブクラスとして`Game`というクラスを定義しました。
`__init__`で必要なパラメータを引数で受け取りプロパティとして保持しています。
コマンドは`@commands.command()`アノテーションを付与しています。

これを`cogs`というフォルダに置きました。

次はこのCogをbotに登録します。
botの本体を以下のように実装します。

```botcore.py
import os
import configparser
import discord
import random
import cogs.game as game

from discord.ext import commands

config = configparser.ConfigParser()
config.read('src/config.ini')

bot = commands.Bot(command_prefix='!')

async def send2developer(text):
    developer = bot.get_user(config.getint('BOT', 'developer'))
    dm = await developer.create_dm()
    await dm.send(text)

@bot.event
async def on_ready():
    print('------')
    print('Logged in as')
    print(bot.user.name)
    print(bot.user.id)
    print('------')
    text = f'Logged on as {bot.user}!'
    game.setup(bot, config)
    await send2developer(text)

bot.run(os.environ['BOT_TOKEN'])

```

`cogs.game`をimportし、`on_ready`関数内で`Game`クラスの`setup`関数を呼び出しています。
`setup`関数内で引数に渡ってきたbotに対して`add_cog`で登録するというフローです。

# おわり
この記事ではCogの基本的な使い方を試してみました。
（この記事を下書きしている間に有志の方がドキュメントを日本語訳されていました）
・[コグ](https://discordpy.readthedocs.io/ja/latest/ext/commands/cogs.html#using-cogs)

discord.pyは使いやすいフレームワークです。
開発や有志の方によるドキュメント翻訳など活発に活動しているようなので、またなにか学んだら記事を書こうと思います。
最後まで読んでいただきありがとうございました！
pipenvでpipが壊れる場合のやつ

# pipenvでpipが壊れる場合のやつ
俺は新しくパソコン買ったからpipenvを入れようとしたわけだが、
ubuntu上でpipが変になって動かなくなった。
pipenvを入れたらpipが変になる人はこうしたら良いよという記事です。

# TLDR;

管理者

```bash
sudo apt install python3 python3-pip
```

おまえら

```bash
python -m pip install --user pipenv
echo "alias pip=\"python3 -m pip\"" >> .bashrc
echo "alias pipenv=\"python3 -m pipenv\"" >> .bashrc
```

これにて一件落着。解散。
以下、駄文。
# ダメ！ゼッタイ！
以下をやった人は再インストール。流石にこれをやる人はいないと信じたい。

```
sudo pip install pipenv
```

# -mってなんだよ
モジュールとして動かしちゃうpythonのオプション。
詳しくは以下を参照

```
man python
```
mainがねえよと怒られるわけですから、当然っちゃ当然かもです。
> mainがないならモジュールとして動かせばいいじゃない。　マリーアントワネット

# コマンド長いのが嫌な初心者へ
シェル芸をおすすめする。シェル芸は便利だぞ！
aliasコマンドでどんな長いコマンドも呼び出せるんだ！

# 感想
こういうのを公式に書いてほしくね？
Visual Studio CodeでNo source control providers registerd

## 事象

Visual Studio CodeでGit連携するぞ！！
意気揚々とSource Controlを開いたところ
![image.png](https://qiita-image-store.s3.amazonaws.com/0/341017/aaab8976-858e-4914-84bf-27146db928d3.png)
"No source control providers registerd."と出る。
(有効なソース管理プロバイダーがありません)

切り分け面倒だからGit Bashでcommit pushするか…と思ったけど
たぶん単純なことだと思いググって直したので投稿。

## 対処:環境変数にパスを通す

- 環境変数設定ウィンドウを開く。
（Win10ならスタートメニューにて"環境変数"で検索）
- ユーザ環境変数のPathを選択して編集押下。
- `C:\Program Files\Git\cmd` を新規追加。（パスはインストールした場所による）
- VSCodeを立ち上げなおすと変更が反映されてる！コミットできるぞ！！
 
![image.png](https://qiita-image-store.s3.amazonaws.com/0/341017/d5726fa6-37d9-9007-cf91-83970204b1d3.png)
Xcode10でSlideMenuControllerSwiftを使用する

#Xcode10でSlideMenuControllerSwiftが動かない
横からメニューをスライドしたいときに便利なライブラリのSlideMenuControllerSwiftですが、Xcode10で使用しようとするとコンパイルがエラーになります。これはswift4.2への対応がなされてないためのようです。

#解決策
grizzlyという人がswift4.2に対応したコードを作成してくれているのでそちらを利用しましょう。PodFileに以下のように指定すればOKです。

`pod 'SlideMenuControllerSwift', :git => 'https://github.com/grizzly/SlideMenuControllerSwift.git'`
Shellscript if,function, for, array まとめ

#ShellでのTips

しばらく書かないと忘れてしまうのでよく使うif、 for, array, functionをまとめました。
関数の引数に配列があります（かなりトリッキーなコードになり可読性が悪くなるので基本的にはおすすめしません）

##
```shell

yasai=('carrot' 'onion')

function getdetail(){
  name=$1
  shift
  array=$@
  for detail in ${array[@]}
  do
    if [ $detail = "onion" ]; then
      echo "I don't like onion!!"
    else
      echo "I like ${detail}!!!"
    fi
  done
}
getdetail "yasai"   ${yasai[@]}

```
注意）実際にはたまねぎ好きです。
コマンドいらず！VisualStudioでASP.NET Coreと Angularのひな形を作る

地味だけどボタンをポチポチするだけでいろいろ生成してくれるVisualStudioを使って、バックエンドをC#のASP.NET Core、フロントエンドをAngularで開発をするためのひな形を作ります。

コマンド不要なので、初心者エンジニアの方でもできます。環境構築の参考に。

## 開発環境
- Windows10 Home
- VisualStudio v15.9.9
- Node.js v10.15.3
- .NET Core v2.2.105
## 環境構築

## 1. プロジェクトの作成
ファイル→新規作成→プロジェクト

![1.png](https://qiita-image-store.s3.amazonaws.com/0/256853/800f5e60-9bcf-4526-1dce-3b5362201be0.png)

Visual C#→Web→.NET Core→ASP.NET Core Webアプリケーションを選択
プロジェクト名もここで決めます。

## 2. SPAのテンプレートを選択
今回はAngularを使うのでAngularを選択してOKを押す。
Reactを使いたい方はReactを選んでもOKです。

![2.png](https://qiita-image-store.s3.amazonaws.com/0/256853/4ee17ab8-0cd9-cf3e-511b-3ac7c873d541.png)

## BuildしてServe！

IIS Expressを押してBuildします。
この時、`npm install`、`ng serve`も一緒に行ってくれてます。なので、フロント側で編集があれば即座にブラウザに反映されます。便利！

![4.png](https://qiita-image-store.s3.amazonaws.com/0/256853/206a2c86-f228-2ad3-76a8-621b7ee83f34.png)

Buildが終わると、テンプレのHelloWorldが表示されます。

![3.png](https://qiita-image-store.s3.amazonaws.com/0/256853/da7c2f43-e001-5a8b-d33d-e1886db17e4f.png)

ボタンをポチポチするだけで、簡単にひな形が作れました。
あとは、APIを作るなり、画面を作るなり、自由に開発してみてください。



## 参考
> \[ASP.NET Core 2.0でSPAテンプレートを使おう【前編】 (1/2)：CodeZine（コードジン）\](https://codezine.jp/article/detail/10599)
railsのキホンvol.3(データベース操作、投稿保存)

##find_byメソッド
データベースにある、特定のidのデータを取り出すことができる。
例：

```
$ rails console
>post = Post.find_by(id:3)
>post.content
```
とすることで、postsテーブルにある、id:3のcontentデータを取得することができる。

##params変数
コントローラのアクション内でidの値を取得することができる。
例：

```posts_controller.rb
def show
  @post = Post.find_by(id: params[:id])
end
```

また、

 ```
<input type="" name="">
```
のようなフォームの情報を受け取ることもできる。

##投稿を保存
フォームの投稿ボタンを押すとcreateアクションに進み、投稿を保存するような処理を用意する。

```routes.rb
post "posts/create" => "posts#create"
```
ルートは通常は「get」、フォームの値を受け取る時は「post」とする。

###form_tagメソッド
フォームに入力された情報を指定のURLに送ることができる。
例：

```new.html.erb
<%= form_tag("/posts/create") do %>
 <textarea name="content"></textarea>
 <input type="submit" value="送信">
<% end %>
```
とすることで、/posts/createにcontentのデータを送ることができる。


###redirect_toメソッド
今回のcreateアクションは投稿を保存するためのアクションなので、redirectが必要。

```posts_controller.rb
def create
  redirect_to("/posts/index")
end
```
とすることで、/posts/indexに転送することができる。
###受け取った情報をテーブルに保存
@post = Post.new(content: params[:content])

```posts_controller.rb
def create
  @post = Post.new(content: params[:content])
  @post.save
end
```

##orderメソッド

投稿一覧を時系列順に表示したい場合はorderメソッドを使う。
高順の場合は desc を用いる。

 ```posts_controller.rb

def index 
  @post = Post.all.order(created_at: :desc)
end
```
続き
https://qiita.com/jonnyjonnyj1397/items/7f9013d384708d282329
whileの基本

# while
ある条件が満たされるまで同じ動作を繰り返したい場合の処理**（繰り返し処理）**の一つとしてwhileがあります。
	- [基本形]
	- [無限ループ]
		- [無限ループを抜けたいとき]
		
## 基本形
```rb

while 動作を繰り返す条件 do
  繰り返して欲しい処理
end
```
**example1**<br>

入力

```rb
i = 0
while i <= 10
  puts(i)
  i = i + 1
end
```
出力

```rb
0
1
2
3
4
5
6
7
8
9
10
```
**example2**<br>

入力

```rb
i = 10
while i >= 0
  puts(i)
  i = i - 1
end
```
出力

```rb
10
9
8
7
6
5
4
3
2
1
0
```
## 無限ループ
while文の条件設定を誤ると処理が止まらない無限ループに陥ってしまいます。<br>

**example**

入力

```rb
i = 1
while i > 0 do
  puts(i)
  i = i + 1
end
```
実行すると処理が止まらないので、macでしたら`Ctrl+C`で強制的に止めて下さい。<br>

出力（最後の方だけ）

```rb
277645
277646
277647
277648
277649
277650
277651
277652
277653
277654
277655
277656
277657
277658
277659
```
### 無限ループを抜けたいとき
わざと無限ループ処理を行い、途中でループを抜けたい場合<br>
`if ~ break`<br>
を使用しましょう。<br>

**example**

入力

```rb
i = 1
while i > 0 do
  puts(i)
  i = i + 1
  if i > 21
    break
  end
end
```
出力

```rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
```
ちなみにi > 21でbreakですが、i = 21の時は、まず21がputsされます。その後、(i=)21に1が足され22になります。そこでi>21となりifの条件を満たしbreakが実行されます。なので、21は出力されます。
WordPressのJSが改竄された話。その３「再発防止編」(終)

[@koshi_life](https://twitter.com/koshi_life) です。

「WordPressのJSが改竄された話」の３本目です。（この話はこれで終わりです。）
このインシデント対応について振り返り、教訓として再発防止方針をまとめてみました。

- 過去記事
  - [その1 事象編](https://qiita.com/koshilife/items/2829d7606627172ce066)
  - [その2 攻撃手法編](https://qiita.com/koshilife/items/c3fe21dee22f58ddb0b6)

# 対応経緯と対策の図

<img alt="20190316-再発防止まとめ.png" src="https://qiita-image-store.s3.amazonaws.com/0/51734/16c84501-db33-40cd-6165-ca479308ef7d.png" width="800px"/>

## ①＜未然防止＞コンテンツ提供に不要な資材は全て削除しよう

当たり前レベルなので、お恥ずかしいですが、できていなかったので反省点です。
セットアップ用のスクリプト類、未使用のプラグイン、テーマ等を削除しました。

以下、徳丸先生の記事から引用。

>[WordPressのプラグインDuplicator 1.2.40以前にリモートコード実行の脆弱性](https://blog.tokumaru.org/2018/09/wordpress-duplicator-plugin-vulnerabilty.html)
>一般論としても、このようなセットアップ用のスクリプト類は、セットアップ完了後はただちに削除すべきですし、セットアップ中も外部からアクセスできないように、アクセス制御すべきです。


## ②＜未然防止＞脆弱性情報をウォッチして早めに穴を塞ごう

プロダクトで利用中のソフトウェアの脆弱性情報をウォッチして
早めにセキュリティホールを塞げるような仕組みを作りましょうって話です。

具体的な仕組み化は検討中ですが、今考えているのは、Slackのチャンネルに関連性の高い脆弱性情報が流れてくるような仕組み化を検討しています。

※「情報源の選定」と「フィルターの仕組み」がまとまれば後日、記事を書くかもです。

<2019/03/19 更新>
[WordPress 脆弱性情報 情報源のまとめ](https://qiita.com/koshilife/items/b4075f747e2bec981524) 書きました。


## ③＜影響極小化＞異常検知の仕組みを整えて、対応の初速を早めよう

この③以降は、事後いかにして影響を極小化することを焦点にした対策です。

今回はHTML内に不正なJSが埋め込まれる形のコンテンツ改竄だったので、
ポートの死活監視、URL監視では検知が難しく、それ以上の改竄を検知する高度な監視設定を行う必要があります。例えば、HTML差分で検知する方式など。

※以下サイトが改竄検知の概要がまとまっていて理解が進みました。
[参考-Webサイト改ざんの検知の仕組みとは？](https://www.shadan-kun.com/blog/measure/2848/)

サービスレベルによって Too Much にならないようバランスを意識して監視内容を決めれば良いと思っています。ちなみに今回被害にあったこのサービスではサービスレベルがそこまで高く求められないため、改ざん検知の仕組みは導入しない予定です。


## ④＜影響極小化＞改竄箇所から最短でリカバリ・対策をしよう

異常検知後は、できるだけ早いリカバリ・同じ攻撃をされないような対策に迫られると思います。
主に、以下２つの手がかり情報を明らかにしたり、推測するなりして、インシデント対応を進める形になると思います。

手がかり１．どのファイルがどんな変更をされたのか？
手がかり２．どのような攻撃手法で変更されたのか？

手がかり１については、
[その1](https://qiita.com/koshilife/items/2829d7606627172ce066#%E8%AA%BF%E6%9F%BB%E3%82%B9%E3%83%86%E3%83%83%E3%83%97%E3%81%AE%E6%8C%AF%E3%82%8A%E8%BF%94%E3%82%8A) にも書きましたが、手軽に改ざん箇所を知る手段として、リリース後に資材をgit管理化にする対策を予定しています。

手がかり２については、
サーバログ、持ちうる脆弱性情報を元に、仮説検証する形で攻撃手法を推測する進め方なので
特定できるか難しいかもしれません。(私はさっぱりで周囲にセキュリティに明るい方がいないのもあり Qiita に情報提供を求めました。)

※ Linux ログ種別のインデックスとして参考になった記事を張っておきます。
[/var/log以下のログ一覧](https://qiita.com/okiami123/items/32f7a775463443f3dfe9)


## ⑤＜影響極小化＞権限設定は必要最小限に

今回サーバ側で任意のPHPコードが実行される状態になりましたが、
AWS EC2 Roleに与えていた権限をある程度絞っていた、セキュアな情報にアクセスできないサーバだったので、情報漏えい、過剰な請求被害、AWS内のリソース破壊等はされずに済みました。

基本的な話ですが、必要最小限のアクセス権限に絞った権限設計をすることで、
もし、侵入・コードインジェクトされた時の影響範囲を最小限に留めることができます。


# 教訓

インシデント対応は突然やってくる。
サービスレベルに見合った防衛策を。ノーガードはダメ。
よく使うRails基本コマンドたち

#はじめに
全てのrailsコマンドは-h (or -help)オプションでヘルプが見れる

```bash:command
$ rails -h
$ rails generate -h
$ rails generate scaffold -h
```
自分が普段、勉強や開発等でよく使うRailsの基本コマンドについて、忘れないうちにまとめてみました。
##開発を始めるには（新しいアプリを作成）
```bash:command
$ rails new アプリケーション名　-d mysql 
```
好きなアプリケーション名を入力し、`-d　データベース名`でデータベースを選択できるフォーマットでは`mysql`ではなく`sqlite`が使われている。
##サーバーの起動
```bash:command
$ rails server 
```
これでローカルサーバーを立ち上げられ、`http://localhost:3000`にアクセス出来る。

##主要generateコマンドで生成できるファイル

デフォルトでは（オプションを与えなければ）、以下のようにファイルが生成される

###controller
コントローラとビューを生成する

```bash:command
$ rails generate controller name action
# name:	コントローラ名（単数系か複数系かは用途に合わせて ）
# action: アクション名
# 例
$ rails generate controller home top
```

###model（モデルとマイグレーションを生成する）

```bash:command
$ rails generate model Name カラム名:データ型 カラム名:データ型 
# Name: モデル名 （単数系）
# 例
$ rails generate model User name:string mail:string
```

###migration（マイグレーションを生成する）

```bash:command
$ rails g migration マイグレーション名
# 例
$ rails generate migration add_users_column
```
#### マイグレーション実行＆ロールバック＆確認

このままだと、実際のDBには反映されないので、`db:migrate`コマンドを実行する。

```bash:command
# 実行
$ rails db:migrate
```

```bash:command
# ロールバック
$ rails db:rollback
```

```bash:command
# 確認
$ rails db:migrate:status

database: hoge_development

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20190316055128  Create users
   up     20190316055128  Create posts
   up     20190316055128  Create user posts
   up     20190316055128  Change options to user post
```

### テーブルを削除する。

```bash:command
$ rails g migration DropUser
```

```ruby
class DropUser < ActiveRecord::Migration[5.0]
  def change
   #drop_table :テーブル名　で削除
    drop_table :users
  end
end
```

### テーブル名を変更する

すでに存在しているテーブルの名前を変更したくなった場合。

```bash:command
$ rails g migration Rename_issue_to_task
```

```ruby:/db/migrate/20190316055128_Rename_issue_to_task.rb
class RenameIssueToTask < ActiveRecord::Migration
  def change
    #rename_table :変更前のテーブル名, :新しいテーブル名
    rename_table :issues, :tasks
  end
end
```

### 既存カラムを変更する

すでに存在しているテーブルのカラムを変更したくなった場合。

```bash:command
$ rails g migration ChangeColumnToUser
```

```ruby:/db/migrate/20140909095843_change_column_to_user.rb
class ChangeColumnToUser< ActiveRecord::Migration

  # 変更内容
  def up
    change_column :users, :uuid, :string, null: false, default: 0
  end

  # 変更前の状態
  def down
    change_column :users, :uuid, :string, null: true, default: 0
  end
end
```

<strong>以上です！！！</strong>
pydubを使ったステレオ音声の分離

# チャンネル分離の方法
AudioSegmentでロードしたデータに対して、下記でステレオを分離できる。

```python
from pydub import AudioSegment
sound = AudioSegment.from_file('fileName.mp4')
samples = np.array(sound.get_array_of_samples())

left = samples[0:len(samples):2]
right = samples[1:len(samples):2]
```

# 詳細説明
今回は単なるTipsですが、一応説明。
pydubを使うと、簡単に音声を読み込むことができます。

```python
sound = AudioSegment.from_file('fileName.mp4')
```

音声のメタデータは下記のような感じで読み出せます。
よく使うのは全体長のdurationと、フレームレート、チャンネルなどでしょうか。
pydub便利。

```python
channel_count = sound.channels
frames_per_second = sound.frame_rate
duration = sound.duration_seconds

print('channel==>', channel_count)
print('frame rate==>', frames_per_second)
print('duration==>', duration)
```
```
channel==> 2
frame rate==> 48000
duration==> 22.464000
```
例えばこの例だと、チャンネルが2つあることがわかります。
平たく言えばステレオ。もちろん、2つマイクを置いてモノクロ録音したものでもいいんだけど、とにかくチャンネルが2つある。
音声解析する際には、2つの時系列データとして扱いたくなるわけです。チャンネル同士の相関とか見たくなる。だから分離しないと。というモチベーション。
では、どうやって格納されているか、が問題。
とりあえず音声だけを抜き出して、その長さを調べてみると、、

```python
samples = np.array(sound.get_array_of_samples())
print('length of samples', len(samples))
```
```
length of samples==> 2156544
```
2156544ってことは、22.464秒 x 48000Hz x 2ch=2156544と推測される。
チャンネルってシリアルに入ってんのね。（というかシリアルに読み出してるのかなぁ。音声はズブの素人なので詳しい人教えてください。）

さて、じゃあどうやってシリアルになってるか。
波形を見て見たところ、交互に入っているようでした。
なので、奇数と偶数のインデックスでスライスすれば左右のデータを取り出せます。

```python
left = samples[0:len(samples):2]
right = samples[1:len(samples):2]
```
僕自身が初めて音声を扱ってみようと思って、最初にぶつかった壁でした。
全てのステレオがこうやって格納されているか、は正直知りません。
違うケースもあるよ、という場合は教えてください。