OmniAICreator/Qiita-1.07M huggingface dataset:
DockerでVMへのリバースプロキシ

前回：[VMサーバーをコンテナに移行する計画](https://qiita.com/F_clef/items/0bd119f6f954e056c05b)
これは**そろそろDockerを使えるようになりたい**筆者の試行錯誤の軌跡です。

# あらすじ
VMサーバー群をコンテナに置き換えるために、一旦コンテナからVMへリバースプロキシしたい。
> ![Untitled(3) (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227222/8ad9e6ae-c7c3-6f5e-83e0-185d389dca6f.png)
> 画像のようにnginxのコンテナを起動し、VMにリバースプロキシするよう設定し、http系のアクセスがVMからコンテナに向くよう変更しました。
が、つながりませんでした。
> ブラウザにはERR_SSL_PROTOCOL_ERRORと表示されており、コンテナのnginxは文字化けしていて解読できませんでした。

とりあえず進展があったので記事にしますが、正しい理屈はまだ理解しておらず、うまく動いたケースの分析を根拠にしています。

# 原因①SSL証明書のインストール場所
SSL証明書が*Deploy*にしかないためにエラーになったのだと思います。
コンテナのリバースプロキシを挟む前は*Deploy*がWANからの窓口になっていたので、*Deploy*に全サービスのSSL証明書がインストールされています。
また、常時SSLにしており、HTTPで*Deploy*にアクセスすると、HSTSを設定した上でHTTPSのアクセスへリダイレクトします。
だからブラウザはHTTPSで通信しますが、リバースプロキシサーバーにSSL証明書がないので、認証できないですね。

* HTTPSでアクセスしなければならない
* 認証できない

の板挟みでエラーになっていたと推測できます。

# 原因②凡ミス
SSL証明書を*Deploy*からコンテナのリバースプロキシに移動しましたが、エラーは解消されませんでした。
このとき、コンテナのリバースプロキシは以下のような設定をしていました。

```
server {
    listen       80;
    listen [::]:80;
    server_name  [ドメイン名];

    include /etc/nginx/params/hsts_params;
    return 301 https://$host$request_uri;
}

server {
    listen       443 ssl;
    listen [::]:443 ssl;
    server_name  [ドメイン名];
    root         /var/www/html;

    ssl_protocols              TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers  on;
    ssl_ciphers                'ECDHE+RSAGCM:ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!aNULL!eNull:!EXPORT:!DES:!3DES:!MD5:!DSS';
    ssl_dhparam                /etc/nginx/ssl/dhparam.pem;
    ssl_certificate            /etc/letsencrypt/live/[ドメイン]/fullchain.pem;
    ssl_certificate_key        /etc/letsencrypt/live/[ドメイン]/privkey.pem;

    location / {
    	include /etc/nginx/params/proxy_params;
        proxy_pass http://[DeployのローカルIP];
    }

}
```

おわかりいただけたでしょうか。

ブラウザからHTTPでアクセスしたとしましょう。

1. 1つめのserverセクションにより、HTTPSにリダイレクトされます。
2. HTTPSでのアクセスになり、2つめのserverセクションに処理され、*Deploy*へ**HTTPで**転送します。
3. HTTPを受けた*Deploy*も常時SSL設定のため、HTTPSでのリダイレクト指示を出します。
 
この3ステップで無限ループができていました。
上記設定ファイルの*Deploy*への転送をHTTPSにしてあげる、もしくは*Deploy*でHTTPも受け入れるようにすれば問題解決です。
(どっちがベターなのかわかりません。教えていただけると幸いです。)
(前者だとリバースプロキシサーバーにも転送先にもSSL証明書が必要になってしまうので、後者のほうがいいのかなと思っています。)

# 今後の展望
これでとりあえず、コンテナのリバースプロキシを介して、VMサーバー群をこれまでどおり使えるようになりました。
あとはサービスを一つずつコンテナにして、リバースプロキシの向きを変えるという作業の繰り返しになります。
大きく分類して、

* PHP製のアプリケーション(owncloud)
* Ruby制のアプリケーション(gitlab)
* Python制のアプリケーション
* Node.js制のアプリケーション
* 静的コンテンツ

の5種類コンテンツがあります。
順に取り上げて作業していきます。

次回：[VMのgitlabをコンテナへ（ついでにバージョンアップ 12.0.3→13.2.4）（ついでにdocker-compose）](https://qiita.com/F_clef/items/5855a5eb8090f96fdd99)
Nuxtでbuildした静的ファイルをnetlifyやfirebase hostingしたら一部画面が表示されない問題

Nuxt便利！
Neflify便利！
Firebase便利！

そう思って使っていたら一部画面が表示されないではありませんか・・・
デバッグバーで見てみると自分の場合
`_nuxt/commons/.b5d8c04.js`
で404となっていた。

なぜだろうか・・・
ローカルでビルドしてみた`dist` 内をみると確かにファイルが存在する。
でもデプロイすると404・・・
これはNeflifyやFirebaseがドットファイルをデプロイしないように設定しているに違いない！

# 対処法
考えられる対処法は２つ
 1. NetlifyやFirebaseでドットファイルをデプロイして認識されるようにさせる
 2. Nuxtのビルドでドットファイルを生成しないようにする

1.は調べきれていないが、仕様で無理な可能性も高い。
なので2のほうが確実に対処できるので今回はこちらの方法を使う。

`nuxt.config.js`の`build`部分を

```js
build: {
 filenames: {
     app: ({ isDev }) => isDev ? '[name].js' : '[chunkhash].js',
     chunk: ({ isDev }) => isDev ? '[name].js' : '[chunkhash].js',
     css: ({ isDev }) => isDev ? '[name].css' : '[contenthash].css',
     img: ({ isDev }) => isDev ? '[path][name].[ext]' : 'img/[hash:7].[ext]',
     font: ({ isDev }) => isDev ? '[path][name].[ext]' : 'fonts/[hash:7].[ext]',
     video: ({ isDev }) => isDev ? '[path][name].[ext]' : 'videos/[hash:7].[ext]'
   }
}
```

こうしておくとOKです。
Nuxtのソースは見てないですが、バージョンによってビルドの仕方が若干違うのかな？
僕の場合は Nuxt 2.13 で `npm run build` `npm run export` した場合にこうなりました。
`npm run generate` がなくなってたし、このあたりなにかかわったのかもですね。（全然調べてない）

同じようにハマった人がいたら参考になれば幸いです。
取得するレコードを最新順表示にする方法

#取得するレコードの順番を変える
ツイートを並び替える方法は、表示の時に順番を変えるのではなく、情報を取得するタイミングで先に並び替えておきます。
##order メソッドを使用する
【例】

```
インスタンス = モデル名.all.order("並び替えの基準となるカラム名 並び順")
```
並び順にはそれぞれAscending/Descendingの略でASC(昇順)とDESC(降順)の2種類があり、値が「小さいものから大きいものになる」または「古いものから新しいのものになる」場合は昇順、その逆は降順を使います。

##tweets_controller.rbを以下のように編集
レコードが作成された日時情報を持つcreated_atカラムを基準に並び替えます。

```tweets_controller.rb
 def index
   @tweets = Tweet.includes(:user).order("created_at DESC")
 end
```
orderメソッドの引数として("created_at DESC")とすれば、レコードは逆順に並び替えられます。
オープンイノベーション事例

平成31年春期 午前問題70

オープンイノベーションに関する事例として，適切なものはどれか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/f5d86d92-07b3-161f-d393-5028233ece67.png)


１、オープンイノベーションは、
**企業組織を超えて、外部から**の新たな技術やアイデア・ノウハウなどを組み合わせ、革新的な製品、サービス、ビジネスモデルを開発することである。

キーワードがOpenですね。

２、プロダクトイノベーション
社内の製造部と企画部で共同プロジェクトを設置し，新規製品を開発した。

３、プロセスイノベーション
物流システムを変更し，効率的な販売を行えるようにした。

４、コーポレートブランディングの事例
ブランド向上を図るために，自社製品の革新性についてWebに掲載した。


参照：
http://fast-macro.com/Johosyori/h31HaruOuyou/h31HaruOuyou-70.html

https://www.ap-siken.com/kakomon/31_haru/q70.html
知識創造プロセス(SECIモデル)　共同化、表出化、連結化、内面化

平成31年春期 午前問題69


知識創造プロセス(SECIモデル)における"表出化"はどれか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/1062dd4a-d5fc-a15d-cb4f-1c8e6340c34a.png)

知識創造プロセス（SECI モデル）とは，個人が保有する知識を組織内で共 有・活用し，より高度な知識を創造するためのプロセスモデルであり，以下の 4 つのプロセスの頭文字をとったものである。

・共同化（Socialization）とは、組織内の個人、または小グループでの暗黙知共有、およびそれを基にした新たな暗黙知の創造である。
・表出化（Externalization）とは、各個人、小グループが有する暗黙知を形式知として洗い出すこと。
・結合化（Combination）とは、洗い出された形式知を組み合わせ、それを基に新たな知識を創造することである。
・内面化（Internalization）とは、新たに創造された知識を組織に広め、新たな暗黙知として習得することである。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/fd346835-1b68-f668-83d0-32969699641a.png)


参照：

https://kanauka.com/kakomon/st/h22a/016.html

https://www.ap-siken.com/kakomon/31_haru/q69.html

https://www.chusho.meti.go.jp/pamflet/hakusyo/h18/H18_hakusyo/h18/html/i7327000.html
Microsoft Teamsのチーム作成を自動化する (申請→承認→作成→通知)

#はじめに

オンラインコミュニケーションの中心として導入が進んでいる Microsoft Teams ですが、企業によってはセキュリティ・ガバナンスの観点から、チームの作成権限が一部のユーザーに限定されているケースがあります。
この場合、最もアナログには、メールで作成依頼をして上長やITチームなどの担当者が承認、手動でチームを作成して管理者に引き渡しという流れになるかと思います。

もう少しシステム化されていると、何らかのチケットシステム・申請システムでチーム作成を依頼して上長等が承認、チーム作成をIT担当者が行うというケースもあります。

今回はそのような、**チーム作成が集中管理されているケース** を対象として、Power Automate と Microsoft Formsを活用して、チームの申請、承認、チーム作成、結果通知までを自動化してみたいと思います。

なお、簡単化のためにチームメンバーは追加されたチームの管理者によって行われると仮定します。

# 申請受付部分 (Microsoft Forms)

チーム作成の申請は企業内で共有されたFormsの申請フォームを利用します。
全て必須入力で、チームの管理者は代理申請であることを考慮して申請者に入力させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/032cee9e-46ec-3ada-8df2-785e3cdb8cc5.png)

申請部分はこれだけの簡単なものです。

申請後は申請者の上長、セキュリティ担当者の承認を経て、チームが作成され、申請者に結果が通知されるようにフローを作成します。

# 承認・作成フロー

フローの全体像は以下の通りです。

1. 申請受信から申請内容を取得 (フォームの回答が作成されたトリガー)
2. 上長への承認依頼
3. セキュリティチームへの承認依頼
4. チーム作成および結果通知

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/bc9f1d2d-2a75-b7bb-509e-3496b011281e.png)

## 1. 申請受信から申請内容を取得
申請フォームから回答が送信されたことをトリガーにフローが開始されます。
まずは応答のIDから回答の詳細を取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/7e7ffea3-4f16-2315-83f0-10a98f6a9f7d.png)

回答内容と申請者情報がこの2つのステップで取得できます。

## 2. 上長への承認依頼
※わかりやすさのために処理ブロックは「スコープ」でまとめています
**Office 365ユーザーコネクターの「上長の取得 (V2)」アクション** で申請者の上長を取得し、承認依頼を送信します。

承認結果が "Approve" の場合には特に処理をせず、後続のブロックに移行します。
却下の場合には、申請者に却下された旨のメッセージを送り、「終了」アクションでフローを正常終了させます。

これにより、後続の処理ブロックは実行されません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/b84e8792-708c-19c5-4b21-0797c2fd976e.png)

## 3. セキュリティチームへの承認依頼
セキュリティチームでなくてもよいのですが、特定の担当者に承認依頼を送信しています。
処理内容は上長の場合と同様で、承認結果がApproveであれば後続処理に、それ以外では却下の旨の通知を送り、フローを終了させます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/b8de288a-e439-45e0-4cd2-0d43c66f8f1e.png)

## 4. チーム作成および結果通知
最後の処理ブロックまで到達するのは2回の承認をパスしてきた後です。
最終ブロックでは、依頼内容のチーム名でチームを作成し、指定の管理者をチームに管理者として追加、最後に申請者に通知を送っています。

注意するべきは**チームメンバーの追加にAAD IDが必要**ということです。AAD IDを取得するために、Office 365ユーザーコネクターで「ユーザープロフィールの取得」を行っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/fb633994-83a4-7c4d-51b9-e74e23153048.png)

# まとめ
今回はPower Automateに追加された、「チームの作成」「チームにメンバーを追加する」アクションを利用して、申請から承認、チーム作成までを自動化してみました。

応用として、例えばログを残しておきたい場合などはExcelファイルやSharePointリストに申請内容と処理結果を記載するステップを追加してください。
今回はセキュリティ担当者に承認依頼を送りましたが、これは組織のポリシーに依存するところですので、複数の承認者を割り当てたり、回答内容を工夫してみてください。
バランススコアカード(BSC:Balanced Score Card)

平成31年春期 午前問題68

バランススコアカードの四つの視点とは，財務，学習と成長，内部ビジネスプロセスと，もう一つはどれか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/97c54640-6131-eaa8-b629-879d4bd34702.png)

バランススコアカード(BSC:Balanced Score Card)は、**企業のビジョン(=未来像)と戦略を実現するため**に、「財務」「顧客」「内部ビジネスプロセス」「学習と成果」という4つの視点から業績を評価・分析する手法です。

・**財務の視点**
株主や従業員などの利害関係者の期待にこたえるため、企業業績として財務的に成功するためにどのように行動すべきかの指標を設定する。

・**顧客の視点**
企業のビジョンを達成するために、顧客に対してどのように行動すべきかの指標を設定する。

・**内部ビジネスプロセスの視点**
財務的目標の達成や顧客満足度を向上させるために、優れた業務プロセスを構築するための指標を設定する。

・**学習と成長の視点**
企業のビジョンを達成するために組織や個人として、どのように変化（改善）し能力向上を図るかの指標を設定する。



参照：

https://www.itpassportsiken.com/kakomon/22_aki/q16.html
すべてのIoT家電をボタン1つだけで制御する(我が家のSmartHouse化計画Lv4)


# はじめに
* 今までは、ボタンを単一の機能に割り当てていたのですが、一つのボタンでまとめていろいろなことをしようと思い立ったので、実装してみました。
* 個々の制御などは、関連記事を御覧ください
* 結果、これは楽にはならない（笑）


## 関連する記事

* [我が家のSmartHouse化計画](https://qiita.com/kazutxt/items/f56f8eb339fc7da952ea)
* [我が家のSmartHouse化計画Lv2](https://qiita.com/kazutxt/items/df5daa363652368e6bdc)
* [我が家のSmartHouse化計画Lv3](https://qiita.com/kazutxt/items/71271ef35e84331f701d)
* [Nature RemoとNode-REDでテレビを操作する](https://qiita.com/kazutxt/items/e7ca6c062eff0f279455)
* [Node-RED系の記事のまとめ](https://qiita.com/kazutxt/items/8c72448eefcba56dabef)

# 実現方法
## 方針
* ボタンには3種類のイベントがあります。
    * クリック、ダブルクリック、ホールド
* 単純にどれかの機器に割り当てると3つしか割り当てられないので、シーケンスを作ります。
    * 7個の機器の状態をクリック/ホールドでON/OFFで制御し、ダブルクリックで実行とします

## 具体的な操作方法
* クリック：1に対応させ、ON/切り替えを割り当てます
* ホールド：0に対応させ、OFF/そのままを割り当てます
* ダブルクリック：実行

### 具体的な割当
|  操作 | 照明  | ライト  | テレビ | エアコン | 壁スイッチ | 空気清浄機 | 玄関鍵 |
|:------|:------|:-------|:-------|:--------|:-----------|:----------|:-------|
| クリック| ON    |  ON    |切り替える|切り替える|  ON    |  ON        | UNLOCK  | 
| ホールド| OFF   |  OFF   |そのまま  |そのまま  |  OFF   |  OFF       | LOCK | 

* 左から順番に対応させていきます
* 7個に満たなかった場合は、後ろに0(ホールドを補います)
* 8個以上でもその部分は無視されます(やり直し不可w)

### 例
1. クリック　⇛　照明をつける
2. ホールド　⇛　ライトを消す
3. クリック　⇛　テレビを切り替える(ついていたら消す、消えていたらつける)
4. ホールド　⇛　エアコンは何もしない
5. ホールド　⇛　壁スイッチはオフ
6. ダブルクリック　⇛　実行

※空気清浄機と玄関鍵はホールド扱いでOFF/LOCK

## 例題
* 下記の初期状態ときに、各問に答えよ(笑)

| 照明  | ライト  | テレビ | エアコン | 壁スイッチ | 空気清浄機 | 玄関鍵 |
|:------|:-------|:-------|:--------|:-----------|:----------|:-------|
| ON    |  OFF    |  ON    |  OFF    |  ON        |  ON       |  CLOSE | 


### 例題1
* 夜ベッドに入って寝る準備をします。ライトだけを付けてください。

### 解答1
|   | 照明  | ライト  | テレビ | エアコン | 壁スイッチ | 空気清浄機 | 玄関鍵 |
|:--|:------|:-------|:-------|:--------|:-----------|:----------|:-------|
|元の状態| ON    |  OFF    |  ON    |  OFF    |  ON        |  ON       |  CLOSE | 
|操作|ホールド | クリック|  クリック | ホールド    |  ホールド    |  ホールド  | ホールド| 
|結果| OFF    |  ON  |  OFF   |  OFF    |  OFF        |  OFF       |  CLOSE | 

* テレビをOFFにするために、切り替えの3番目のクリックを忘れないでください
* クリック、ホールド、クリック、ダブルクリックでも可

### 例題2
* 熱くなってきたので、エアコンをONにして他の状態を変えないでください

### 解答2
|   | 照明  | ライト  | テレビ | エアコン | 壁スイッチ | 空気清浄機 | 玄関鍵 |
|:--|:------|:-------|:-------|:--------|:-----------|:----------|:-------|
|元の状態| ON    |  OFF    |  ON    |  OFF    |  ON        |  ON       |  CLOSE | 
|操作|クリック | ホールド|  ホールド | クリック    |  ホールド    |  ホールド  | ホールド| 
|結果| ON    |  OFF  |  ON   |  ON    |  OFF        |  OFF       |  CLOSE | 

* エアコンの後はダブルクリックでも可
* 別解として「alexa,エアコンを付けて」でも可
 
# まとめ
* 結論。難しい。脳トレやっている気分になる

#　その他
* その他面白いIoT家電があれば、教えて下さい。
コアコンピタンス(Core Competence)

平成31年春期 午前問題67

コアコンピタンスに該当するものはどれか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/5556410d-372d-5882-2ff0-5ebfd2e5299a.png)


１、コアコンピタンス(Core Competence)とは、
長年の企業活動により蓄積された他社と差別化できる、または競争力の中核となる企業独自のノウハウや技術のことです。コアコンピタンスに該当する技術には、「様々な市場に展開可能」「競合他社による模倣が困難」「顧客価値の向上に大きく寄与する」などの共通性質があります。
コアコンピタンスの例としては「ホンダのエンジン技術」「ソニーの小型化技術」「トヨタの生産管理方式」などがよく挙げられます。

基本は、他社より技術高い、効率速い、効果よいなどのて点ですね。


参照：

https://www.ap-siken.com/kakomon/27_haru/q67.html
Prototypeを理解する

>JavaScriptはprototypeをベースにした言語である

こちらがあるので、ES６ではクラスが使われてますが、きちんと基礎のprototypeを理解していきます。

###基本
- prototypeプロパティを使って、どんなオブジェクトも継承可能
- コンストラクタをもとに、いくらでもインスタンスを作れる
- インスタンスとは、実態／実際に作ったもの

###基本的な記述方法
`オブジェクト名.prototype.メソッド名= function() {メソッドの処理内容} `

コードで書いていきます。
ここでは一つの会社を想定し、どこの部署に、何年くらい働いているのかを出してみます。


```script.js
//コンストラクタ(設計図)を作成　
var Person = function(name, yearOfJoin, department) {
  this.name = name; //引数nameを渡してる
  this.yearOfJoin = yearOfJoin; //引数yearOfJoinを渡してる
  this.department = department; //引数departmentを渡してる
} //この時点ではオブジェクトは空

Person.prototype.calculateYears = function() {
  console.log(2020 - this.yearOfJoin);
};//prototypeでPersonのコンストラクタを継承

//設計図にプロパティを入れる
var mike = new Person('John', 2005, 'sales');
var jessie = new Person('Jessie', 2010, 'Accounting');
var mary = new Person('Mary', 2019, 'Planning');

mike.calculateYears(); //結果：15
jessie.calculateYears();//結果：10
mary.calculateYears();//結果：1
```

functionだけでなく、プロパティも追加できる（でも上記の方が一般的）

```script.js
Person.prototype.lastName = 'Williams';

console.log(mike.lastName); //結果：Williams
console.log(jessie.lastName); //結果：Williams
console.log(mary.lastName); //結果：Williams
//全員同じラストネーム
```

###補足
コンストラクタfunctionの外側でprototypeを定義することで、
毎回同じ内容が、インスタンスが作成される度にコピーされずに済みます。
＝参照として利用することで、メモリーを最低限に抑えられる。
ソフトウェア調達　サブスクリプション方式、買い取り形式(=永続ライセンス?)、受託開発(or 自社開発)、

平成31年春期 午前問題66

サブスクリプション方式のソフトウェア調達はどれか。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/f2f8a80b-1c4b-ccf0-fb58-43d821964765.png)


１、サブスクリプション(Subscription)とは、
ソフトウェアやサービスの料金形態の一種で、従来のようにソフトウェア自体を一括して買い取るのではなく、ソフトウェアの使用権を借り、その利用期間に応じて使用料が発生する方式です。一般的には1年単位や1カ月単位の課金となっていることが多くなっています。利用者にとっては初期費用が掛からず、不要になったらいつでも契約解除できる利点があります。サブスクリプションは英語で「購読」の意味があります。

月額固定料金で音楽や動画が利用し放題のサービスや、月額課金で購読できる新聞社のWebサイト、月額課金のオンラインストレージ、PhotoShopで有名なAdobe社のCreative Cloudなどが代表的な事例です。

２、買い取り形式(=永続ライセンス)
CD-ROMといった記録媒体によって販売され、購入したエンドユーザーは、ソフトウェアのバージョンアップやサポートに追加料金を支払うこともあるが、永続的に使用することができるの形式です。

３、受託開発(or 自社開発)
受託開発は、クライアントのシステムの開発において、クライアントのコンサルティングから設計、開発、運用・保守・管理までを一括請負うことです。
自社開発は、全ての階段は自社でやるのことですね。

参照：
https://www.ap-siken.com/kakomon/31_haru/q66.html

サブスクリプション方式、買い取り形式
https://ja.wikipedia.org/wiki/%E3%82%B5%E3%83%96%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3%E6%96%B9%E5%BC%8F
【Go】ルーティングライブラリgo-chiの使い方

# go-chi
- net/http
- go-chi
- gorilla
- echo

とかがあると思います(他にもあるけど省略)が、go-chiやgorillaはその中でもフレームワークとして使いやすいながらにハンドラでは標準パッケージのnet/httpをそのまま使用できたり導入しやすい部類に入ると思います。実際に見ていきましょう。

```
 $ go get github.com/go-chi/chi 
```

## 使っていきます

まずはハンドラを定義します。ハンドラ自体はnet/httpを使うので、ライブラリを消したくなった場合はルーティングの記述だけを変更すれば良いです。

```go:handler.go
package handler

func Get(w http.ResponseWriter, req *http.Request) {
  // ハンドラを記述
  fmt.Println("呼ばれた")
  return
} 
```

ルーティングでハンドラを呼び出します。

```go:router.go
package router

type Router struct {
  chi.Router
}

func Init() *Router {
r := chi.NewRouter()
return &Router{r}
}

func (r *Router) Routes() {
  r.Get("/", handler.Get)
}

func (r *Router) Run() {
	port := "8080"
	log.Printf("ポート番号 %s で待ち受けています。", port)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), r))
}


```

これをmainで呼び出します。

```go:main.go
func main() {
	r := router.Init()
	r.Routes()
	r.Run()

```

これでlocalhost:8080/hogeにアクセスすると、「呼ばれた」がコンソール上に表示されるはずです。

必要最低限の実装は終わりですが、さらに下のようにmiddlewareをかましたり、Group化させることもできます。


```go:router.go
func (r *Router) Routes() {
	r.Route("/api", func(r chi.Router) {
		r.Route("/v1", func(r chi.Router) { 
			r.Group(func(r chi.Router) {  // Group
				r.Use(middleware1)  // このGroup内のみmiddleware適用
				r.Route("/me", func(r chi.Router) {
					r.Get("/", handler1) // ルーティング: /api/v1/me
				})
			})
			r.Route("/review", func(r chi.Router) {
				r.Get("/{ID}", handler2) //ルーティング: /api/v1/review/{ID}
			})
		})
	})
}

```

以上です。質問・訂正あればお願いいたします。ありがとうございました。
写真から住所を特定する方法 (Mac OSX)

結構ベタなネタなので需要ないかもだけど、一応自分用のメモもかねて。

まず、terminal でいろんな画像のメタ情報を抽出するために、下記をインストール:

```
brew install ImageMagick
```

その後

```
identity -verbose [画像ファイルパス]
```

で画像ファイルの詳細情報が手に入る。
注意すべきは、 geometry とか記載されているところはあくまでも画像のサイズ　px * px を示している
のであって地理情報ではない。GPS情報だけ抽出したければ

```
identity -verbose SAMPLE.jpg | grep GPS
```

とかすると詳細情報を手に入れられる。

<img width="523" alt="picture 2020-08-13 at 9.26.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62181/ec7b8fee-c38d-d2d0-e40c-1002e1146cdf.png">


例えば上記に記載されている緯度と経度をGoogle Mapとかで入力すれば、どこにいるかがわかる。

<img width="344" alt="picture 2020-08-13 at 9.26.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62181/636a07ad-ee4b-da75-61f8-95c3f2646318.png">


あとはどんなデバイスで写真撮ったかもわかる。

スマホ用の詳細情報を入手できるアプリも提供してあって、

```
exif viewer
```

とかで検索すると手に入る。

搾取のシナリオとしては、例えばターゲットが個人ブログその他にあげたりした写真をこれで調べ、
どこにいたか、自宅とかであればどこに住んでいるかまで特定が可能。

ただし、大手SNS（もしくはたぶんgoogleまわりのサービスも）はここらへん全部トリミングしてしまう
（してくれる）ので、仮にDLしても場所の追跡は難しい。

以上。
Ruby on Rails 基礎　覚書

<h2>Ruby on Rails覚書</h2>
Ruby on Rails の基礎を勉強中なので、自分自身で覚えるためにも覚書として残しておきます。

<h2>そもそもRuby on Railsとは</h2>
Rubyで書かれた、Webアプリケーションフレームワーク。MVC(Model, View, Controller)モデルを採用している。プログラマーの負担を軽減するために、必要なものを事前にフレームワークに用意してある。
基本理念として、「Don't Repeat Yourself」, 「Convention over Cofiguration」の二つがある。

<h2>アプリケーションの新規作成</h2>

```
rails new アプリケーション名
```

アプリケーション名のフォルダが作成される

<h2>サーバを立ち上げる</h2>

```
rails server
```

<h2>トップページの自動作成</h2>

```
rails generate controller home(コントローラ名) top(アクション名)
```

トップページの自動作成をすると３つの要素が作成される

・ビュー(View）
見てくれの部分。Webのhtml
viewsフォルダの中に格納される。ファイル拡張子はerb

・コントローラ（Controller）
Rubyの中で"アクション"を起こし、ブラウザにhtmlを返す。
コントローラの同じ名前のviewフォルダから、アクションと同じ名前のhtmlを返す。
いうなれば、はがきを受け取り、そのハガキを受取人に渡す郵便配達員。

・ルーティング（routing）
いわば、ブラウザとコントローラの間に入って交通整備をしてくれる。
このurlはこちらのコントローラへどうぞの仕分けを書く場所。
ルーティングは、 `url => コントローラ名#アクション名`で記載する。

自動作成では、トップページのビュー＋コントローラを作成し、
コントローラ名#アクション名のルーティングを追加する。


<h2>ビューファイル（拡張子.erb）</h2>
erbの意味は、Embedded Ruby（埋め込みRuby）
ファイル内で、rubyのコードを埋め込む時は、<% %>を使う。

```ruby:例
<% posts.each do |post|  %>
:
<% end %>
```

また、コードをブラウザに表示したい場合は、<%= %>を使う。

つづく・・・
Wifiアクセスポイントの接続優先度を設定する (Linux, NetworkManager)

# 何がしたいか

自宅のWifiアクセスポイントは5GHz, 2.4GHzの両方が見えています。
極力、5GHzのほうに接続したいと思っています。

アクセスポイントは XXXXXXXXXXXX-a, XXXXXXXXXXXX-g と記載していますので、適宜読み替えてください。前者が5GHz, 後者が2.4GHzです。

# 何をしたか

コネクションの優先度を設定しました。
まずは優先度を確認します。

```bash
$ nmcli -f NAME,TYPE,DEVICE,AUTOCONNECT,AUTOCONNECT-PRIORITY c
NAME             TYPE      DEVICE     AUTOCONNECT  AUTOCONNECT-PRIORITY 
XXXXXXXXXXXX-a   wifi      wlp0s20f3  はい         0
XXXXXXXXXXXX-g   wifi      --         はい         0
```

XXXXXXXXXXXX-a のコネクション優先度を上げます。大きい値の方が優先度が高いです。

```bash
$ nmcli connection modify XXXXXXXXXXXX-a connection.autoconnect-priority 10
```

ちゃんと変更されたか確認します。

```bash
$ nmcli -f NAME,TYPE,DEVICE,AUTOCONNECT,AUTOCONNECT-PRIORITY c
NAME             TYPE      DEVICE     AUTOCONNECT  AUTOCONNECT-PRIORITY 
XXXXXXXXXXXX-a   wifi      wlp0s20f3  はい         10
XXXXXXXXXXXX-g   wifi      --         はい         0
```

優先度が0から10に変更されました。
きっとこれで5GHzの方を優先して接続されるようになったはずです。

# お願い

コメントありましたらお願いします。
もっと良い方法とか、上の方法のデメリットとか、修正リクエストとか、ぜひお願いします。

- 環境
    - Debian bullseye
    - network-manager 1.26.0-1 amd64
- 参考文献
    - <[qastack.jp](https://qastack.jp/ubuntu/165679/how-to-manage-available-wireless-network-priority)> 利用可能なワイヤレスネットワークの優先度を管理する方法 

おわり
BadMethodCallException Method Illuminate\Routing\Route::get does not exist. のエラー

「PHPフレームワーク Laravel入門 第二版」を使ってlaravelの勉強をしていたが、ｐ33の
helloルートにアクセスできず、「BadMethodCallException Method Illuminate\Routing\Route::get does not exist. 」と表示される。

#解決法
routes/Route.phpの```use Illuminate\Routing\Route;```を```use vendor\laravel\framework\src\Illuminate\Routing;```に書き換える。
ユースケース図、アクティビティ図、クラス図、オブジェクト図、状態遷移図

平成31年春期 午前問題65

要件定義において，ユーザや外部システムと，業務の機能を分離して表現することで，ユーザを含めた業務全体の範囲を明らかにするために使用される図はどれか。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/317ca7ab-d8cf-030f-81ca-d221b4cfaea4.png)


１、ユースケース図は、
UMLの中でもシステムの振る舞いを表現する図で、システムに要求される機能を、ユーザの視点から示した図です。ユースケース図を有効に活用することにより、システムの全体像を開発者とユーザが一緒に評価しやすくなる利点があります。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/04dfdcf3-c861-6755-3319-b1dd4ccdb237.png)

２、アクティビティ図とは、
連続する「実行」の遷移、つまり一連の｢手続き｣を表現するための図です。ある事象の開始から終了までの機能を実行される順序にしたがって記述します。 状態マシン図が実体の状態遷移を表すのに対し、アクティビティ図では実体の制御の流れを描写します。

アクティビティ図は、上流行程のビジネスプロセスの流れや下流行程のプログラムの制御フローなどシステムの流れを表せるフローチャートのUML版図法です。

記述例
アクティビティ図は必ず開始状態から何らかの終了状態へ、矢印で示された手順に従って実行を行います。 下の図はある会社社員が起床して出社するまでの手続きを示した例です。


【要件定義】

まず朝起きて顔を洗います。健康ならば新聞を読みながら朝食を食べ、歯を磨き、そのあと服を着替えて出社します。もし体調が悪ければ｢病気である｣と会社に連絡して処理終了です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/3bec8457-c1f7-687b-f29c-7fb2a56c32dc.png)


３、クラス図は
UMLの中でも最もよく使用される図の1つです。オブジェクト指向のプログラミング言語においては、クラス図から実装（ソースコード）に変換することができます。このためシステム開発においては他のUMLダイアグラムを作成しようとも、それは最終的にはクラス図の作成に結びつけられることが多く、このような性質からもクラス図はシステム開発において中心となる図であると言えます。

クラス、属性、クラス間の関係からシステムの構造を記述する静的な構造図です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/1c873ce1-5538-432d-5755-e992aa1c2fc2.png)


４、オブジェクト図には「インスタンス指定（インスタンス仕様）」と「リンク」と呼ばれる2つの要素しか登場しません。「インスタンス指定」の中には「スロット」が記述されます。

オブジェクト図は、システムが動作しているある時点でのオブジェクトとオブジェクト間の関係を表現するためのダイアグラムです。

オブジェクト図は、ある特定の時点でのオブジェクトのインスタンス間の静的な構造を記述する図です。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/2167af9a-8316-6357-7e30-2167e3914ebd.png)


５、状態遷移図
現在状況の状態と発生する事象だけによって、状態が変化していくようなシステムを記述するときに用いられる図式化手法です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/bd87b977-774e-c7ba-ebed-c28099e25ced.png)


参考：
https://www.ap-siken.com/kakomon/27_aki/q64.html

ユースケース図
https://thinkit.co.jp/article/40/2/

アクティビティ図
https://www.itsenka.com/contents/development/uml/activity.html

クラス図
https://thinkit.co.jp/article/40/3/

オブジェクト図
https://thinkit.co.jp/article/40/3/3.html

状態図
https://www.bcm.co.jp/site/2002/uml/uml8.htm
SwiftでArrayの中の全ての要素が、特定の条件を満たすかどうか判定する方法

Swift4.2からは `allSatisfy` メソッドが提供されています

ドキュメント: https://developer.apple.com/documentation/swift/array/2994715-allsatisfy

例:

```swift
struct Item {
    var id: String
    var hasStock: Bool
}

let category1 = [
    Item(id: "1", hasStock: true),
    Item(id: "2", hasStock: false),
    Item(id: "3", hasStock: true)
]

let category2 = [
    Item(id: "1", hasStock: false),
    Item(id: "2", hasStock: false),
    Item(id: "3", hasStock: false)
]

print(category1.allSatisfy { $0.hasStock == false }) // -> false
print(category2.allSatisfy { $0.hasStock == false }) // -> true

// 上2つは次の2つと同じ意味だが、allSatisfyメソッドの方がわかりやすい
print(!category1.contains(where: { $0.hasStock == true })) // -> false
print(!category2.contains(where: { $0.hasStock == true })) // -> true
```
ポート番号指定で、Railsサーバーを停止したい

デタッチモードでサーバーを起動する(`$rails s -d`)と便利なのだが、
よく停止するのを忘れてどのプロジェクトファイルがそのポート番号を使っているのかわからなくなり、tmp/pids/server.rbのファイルを消去して停止するという方法がとれない時がある。



そういう時は、

`$ Sudo kill -9 $(lsof -i :任意のポート番号 -t)`

で消す事ができる。

[参考記事①](https://bit.ly/30OpaID)、[参考記事②](https://bit.ly/3fTrz90)
Roomba980をRaspberry Pi4経由でROSで動かす

（親が）ジャパネット高田で購入したRoomba980が家にやってきました。お掃除もできるお手軽ハッキング用ロボットということで、私もRaspberry Pi 4を購入してハッキングしてみました。
- ハード: Raspberry Pi 4
- OS: Raspbian Buster
- ROS: melodic


# Roomba980
Roombaには400, 500, ... , 900やCreate 1, 2などのシリーズがありまして、980は900シリーズの最新版ということのようです。車体上部にはiAdaptと説明書で呼ばれているカメラがついており、おそらくこれでvSLAMをしているのではないかと思います。見た目はこんな感じ。ちなみに結構うるさいです。我が家の犬は怯えています。
![roomba.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272738/96fe8ceb-2d2a-ac7a-f129-f057d877a37e.jpeg)


# Roomba900シリーズのROI
Roombaは共通してROI(Roomba Open Interface)と呼ばれるものが存在し、これを使って人々は数多くのRoombaをハッキングしてきました。通常、Roombaはその上部に存在するシリアルポートからRaspberry Piなどで通信し、ハッキングを行うようです。しかし900シリーズはその上部に存在するシリアルポートが取り除かれており、他のシリーズのように通信することができません。

いろいろと探してみたところ、車体右下上面にある細い円弧状のフレームを取り外すと、microUSBのポートがあることがわかりました[^1][^2]。特に写真については[^2]をご覧ください。

ここにRaspberry Pi 4をつないでみると、 `/dev/ttyACM0` としてRoombaが認識されました。https://github.com/martinschaef/roomba で試してみるとちゃんと動きました。

ちなみに、microUSBのケーブルによっては認識されない場合もありました（そもそもmicroUSBに違いがあることを知りませんでした）。「つないでも/dev/*が出てこないんだけど！」という人はケーブルを変えてみると良いかもしれません。

# Roomba980をROSで動かす
ここではROS(1)のインストール方法は省きます。今回はCreate Autonomy[^3]のパッケージに含まれるドライバーを使いました。ちなみに使う前にちゃんとRoombaポートの権限追加を行いましょう。ttyACM0の部分は適当にご自分のに変えてください。その後のROSドライバーでも同様です。

```terminal
$ sudo chmod a+rw /dev/ttyACM0
```

これができたら、あとはドライバーを立ち上げるだけです。ちなみにCreate Autonomy[^3]のページには「900シリーズは対応未確認」とあるように、公式にはRoomba900シリーズをサポートしていないようです。いろいろ試してみたところ、create_1のドライバーを立ち上げると接続に成功しました。（なぜ？）

```terminal
$ roslaunch ca_driver create_1.launch
```

ちなみに `rostopic list` の結果はこんな感じ。

```
$ rostopic list
/battery/capacity
/battery/charge
/battery/charge_ratio
/battery/charging_state
/battery/current
/battery/temperature
/battery/voltage
/bumper
/check_led
/clean_button
/cmd_vel
/day_button
/debris_led
/define_song
/diagnostics
/dock
/dock_button
/dock_led
/hour_button
/ir_omni
/joint_states
/minute_button
/mode
/odom
/play_song
/power_led
/rosout
/rosout_agg
/set_ascii
/spot_button
/spot_led
/tf
/tf_static
/undock
/wheeldrop
```

Roomba980はせっかくカメラ（？）がついているというハード面でのアドバンテージがあるにもかかわらず、現状だとそれがrosで使えないのがもどかしい、、、。そもそも[^3]は900シリーズを公式に対応しているわけではないと思うので、現状ですらうまく通信できない部分があるのかもしれません。さらっと確認したところだと`/cmd_vel`や`/battery/*`, `/ir_omni`などのセンサー系はとりあえずちゃんと動いていそうでした。

# Conclusion
Roomba900シリーズもROSで動かすことができるようですね。ただ現状ではまだ全て正常かを確認できていないのと、機能をフルで活かすことはできない感じがします。新しくハッキング用Roombaを購入する場合は900はあまりお勧めしないかもです。

# Future Work
- ちゃんと全てのrostopicが正常に動作しているか確認する。
- ROS2で試してみる。
- 何とかしてカメラを使う（Roombaのが無理なら別でカメラ買うしかないかな）

秒で作った記事なので何か不備や質問などがあればよろしくお願いします。

[^1]: Roomba 980をraspberry piで動かしてみた, http://mementomorisince2013.blogspot.com/2019/01/roomba-980raspberry-pi.html
[^2]: 実はルンバ900シリーズはROI対応している, https://qiita.com/ozwk/items/7ed89479cf4931970edd
[^3]: github create_autonomy, https://github.com/AutonomyLab/create_autonomy
CentOS(RHEL) 8 で python , pip コマンドが利用できない

# はじめに

CenoOS で python , pip コマンドが利用できないと思ったらインストールされていないし、インストールしてもデフォルトでインストールしたものを利用してくれないので設定する必要があった

https://dev.classmethod.jp/articles/in-search-of-lost-python-at-rhel-8/#toc-3


# python のインストール
とりあえず、全ての python モジュールをインストールしておく


```bash
dnf install python36*
```

または

```bash
yum -y install python36*
```

pipコマンドをインストールするのであれば、以下のパッケージをインストールしていいと思う。

* python36-3.6.8-2.module_el8.1.0+245+c39af44f.x86_64
* python3-pip-9.0.3-16.el8.noarch

```bash
rpm -qf /bin/pip3
python36-3.6.8-2.module_el8.1.0+245+c39af44f.x86_64

rpm -qf /bin/pip3.6
python3-pip-9.0.3-16.el8.noarch

```

# python コマンド単体で実行する環境に設定

インストールしただけでは、インストールした python をシステムデフォルトとして利用してくれないので、以下のコマンドを実行して、インストールした python のバージョンを選択する。以下では「2」を選択してエンターを押している。

```bash
alternatives --config python

2 プログラムがあり 'python' を提供します。

  選択       コマンド
-----------------------------------------------
*+ 1           /usr/libexec/no-python
   2           /usr/bin/python3

Enter を押して現在の選択 [+] を保持するか、選択番号を入力します:2


python --version
Python 3.6.8
```

# pip コマンド単体で実行する環境に設定

こちらも、インストールした pip3 のコマンドを実行できる環境にするため以下のコマンドを実行

```bash
update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1

pip --version
pip 9.0.3 from /usr/lib/python3.6/site-packages (python 3.6)


```
時刻１５分刻みの２４時までをJS８行で書いてみた

# ソースコード
```
const minute = ['00','15','30','45'];
const test = () => {
  [...Array(24)].forEach((_,hour) => {
  minute.forEach((minute_data) => {
  console.log(hour + ':' + minute_data);
});
});
}
```
SQL SELECTによる検索結果と絞り込み①

####SQLのSELECT文の時に使える検索の絞り込みについての簡単なまとめ(前半)となります。

##今回取り上げるワード

|キーワード　　| 詳細 |
|:---------   |:--------------------|
| DISTINCT     |重複を除外                |
|ORDER BY 列名 (ASC or DESC)| 順序の並び替え  ASCで昇順 DESCで降順   　|
|OFFSET- FETCH | 件数を限定して取得　  　　　　　　  |



## DISTINCT

重複を除外することのできるキーワードなので、

```SQL:
SELECT DISTINCT 列名1
FROM テーブル名
```

SELECT DISTINCT 列名と指定する事でその列の値で重複するものを除外して結果を検出してくれる。


## ORDER BY

列名 ASC or DESCで順番を指定して並び替え。

メッセージの投稿順や売れ筋ランキングなどの並び替えの際に使用することが多い。

ひとつ目の絞り込みで同じ値がある場合、その中からさらに順番を並び替えすることができる。

その場合は

```SQL:
SELECT *
FROM テーブル名
ORDER BY 列名1 DESC, 列名2 DESC
```
のように「,」で区切ればOK。

列名は列番号(SELECTした列に対し順に割り当てた番号)にすることもできるが、
この場合*で全選択せずに列名で指定すると指定した列名の順序に気をつけないとSELECT文の選択列リストを修正した時に結果が変わってしまうので注意が必要。

基本的には列名を指定した方が安全である。


## OFFSET - FETCH

必要に応じて並び替えした結果を限定したい時はOFFSETとFETCHで行うことができる。

```SQL:
SELECT 列名A, 列名B FROM テーブル名
<!-- まずは並び替え -->
ORDER BY 列名B DESC
<!-- 結果の上から何番目から取得するかを指定 -->
OFFSET 0 ROWS
<!-- OFFSETの結果から何番目までを取得するかを指定 -->
FETCH NEXT 5 ROWS ONLY
```

この様に書けば５番目までのランキングを取得できる。


ランキングでなくても特定の番数のみ取得したい場合はこの様に書く。↓

```SQL:
SELECT 列名A, 列名B FROM テーブル名
<!-- まずは並び替え -->
ORDER BY 列名B DESC
<!-- 結果の上から何番目から取得するかを指定 -->
OFFSET 4 ROWS
<!-- OFFSETの結果から何番目までを取得するかを指定 -->
FETCH NEXT 1 ROWS ONLY
```
これで5番目のみ取得できる。

OFFSET - FETCH に対応していないDBMSもあるようで、その場合に取得方法には別の方法もある。

私の使っているPostgreSQLの場合

```SQL:
SELECT 列名1, 列名2 FROM テーブル名
ORDER BY 列名2 DESC LIMIT 5
```

とすればOK!

続く
firebase perf plugin使用時のビルドでワーニング

# Android 向け Performance Monitoringを取り入れてビルドするとエラーが、、、
設定では、Java1.8準拠としているので、Java 6でJSR/RETバイトコードペアが廃止されたやつが出る

```
> Task :app:checkProdReleaseDuplicateClasses
 Can't instrument: org/apache/commons/digester/plugins/strategies/FinderFromFile.class
 java.lang.IllegalArgumentException: JSR/RET are not supported with computeFrames option
 	at org.objectweb.asm.Frame.execute(Frame.java:1009)
 	at org.objectweb.asm.MethodWriter.visitJumpInsn(MethodWriter.java:1156)
 	at org.objectweb.asm.MethodVisitor.visitJumpInsn(MethodVisitor.java:473)
 	at org.objectweb.asm.commons.AdviceAdapter.visitJumpInsn(AdviceAdapter.java:517)
 	at org.objectweb.asm.ClassReader.readCode(ClassReader.java:2040)> Task :app:transformClassesWithFirebasePerformancePluginForProdRelease
 	at org.objectweb.asm.ClassReader.readMethod(ClassReader.java:1275)
 	at org.objectweb.asm.ClassReader.accept(ClassReader.java:679)
 	at com.google.firebase.perf.plugin.instrumentation.Instrument.instrument(Instrument.java:170)
 	at com.google.firebase.perf.plugin.instrumentation.Instrument.instrumentClassesInJar(Instrument.java:117)
 	at com.google.firebase.perf.plugin.FirebasePerfTransform.performTransformationFor(FirebasePerfTransform.java:563)
 	at com.google.firebase.perf.plugin.FirebasePerfTransform.transformJarInputs(FirebasePerfTransform.java:445)
 	at com.google.firebase.perf.plugin.FirebasePerfTransform.transform(FirebasePerfTransform.java:416)
```

# 原因
Android Studioで外部ライブラリの参照を確認すると
「commons-digester:1.8」となっていた、1.8とはだいぶお古い。。。
これは、自分でimplementationしたライブラリではないので

# 対応
確か、3.xぐらいまで出てたよなと、リポジトリには2.1があったので
自分で、implementationで追加してみた
「commons-digester:2.1」

    implementation 'commons-digester:commons-digester:2.1'

もう一度、外部ライブラリの参照を確認すると
今度は、2.1になって、1.8は参照されなくなっている

この状態でもう一度ビルドしてみると
見事エラーは出なくなりました。
Laravel バリエーションによるエラーメッセージが出た際に文字が消えなくする方法（oldヘルパーを使用します）

こんにちはショウです。初投稿となりますが、間違った箇所がございましたらご指摘よろしくお願いいたします。

今回はバリエーションによるエラーメッセージが出た際に文字が消えなくする方法を例を用いて解説します。


バリエーションの一例です

使用環境： Laravel framework 6.18.24

```php:○○○controller.php
public function store(Request $request)
    {

        
       $request->validate([
            'status' => 'required|max:10',
            'content' => 'required|max:255',
        ]);
    

```
statusが10文字までしか保存できない＆10文字以上書いている状態でセーブするとエラーメッセージが表示される状態を例にして説明します
<img width="656" alt="スクリーンショット 2020-08-13 8.03.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613591/094b092e-2f35-c1d3-bf47-c2c1021b0962.png">

10文字以上入力して投稿すると<img width="740" alt="スクリーンショット 2020-08-13 8.06.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613591/5a374c74-089a-6372-a854-697e447e64f5.png">

このようにエラーメッセージが表示されますが、これまで書いた文字が消えてしまいました。

文字を消えないようにするにはoldヘルパーを入れます。

```php:create.blade.php

//status
<input type="text" value="{{ old('status') }}" id="status">

//content           
<input type="text" value="{{ old('content') }}" id="content">

    

```

<img width="921" alt="スクリーンショット 2020-08-13 8.30.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613591/f5e53dc0-f2bd-60ac-548a-b6936d874c24.png">

エラーメッセージが出ても文字が消えなくなりました！

説明は以上となります

僕のポートフォリオであるメモアプリのソースコードは公開しているので良かったらご覧ください
https://github.com/shou-github/memo.App/

以下のURLからご使用頂けます。
https://memoapps.herokuapp.com/
buttonタグ選択時のoutlineを無効にする



**警告** コメントにいただいたように`outline: none;`の指定は非推奨となります

`:focus`擬似クラスで効果を上書きして対応します。

```style.css
button:focus {
    outline: none;
}
```


ただ、outlineを無効にすることはユーザーのフォーカス位置の手がかりを奪ってしまうことになるので、
マウスや指をボタンの上に乗せたときに表示するアニメーション（いわゆる「ホバーアニメーション」）を，ボタン押下時にも適用するなどの対処は行った方がいいです。

```style.css
button:focus, button:hover {
    outline: none;
    background: green;
}
```

ちなみに`:focus`はBasic Selectorであり，一般的に利用可能です。

[Can I use ":focus"](https://caniuse.com/#search=%3Afocus)
を見ると，
`:focus-visible`は，FirefoxとChromeにおいて，かろうじて利用可であり，
`:focus-within`は，IEを除いた一般的なブラウザで利用可能となっていますが，
`:focus`は，最下段の「CSS 2.1 selectors」に含まれており，全てのブラウザで利用可能となっています。
Raspberry Pi でOpenCVやらTensorFlowやらをやろうとしたときのエラーと対処


ここを参考にしながらTensorFlowをインストールすると、
https://qiita.com/taisuke3/items/3f8690137672174ac8d0

動作確認プログラムでエラーが出た。

```
numpy/core/_multiarray_umath.cpython-35m-arm-linux-gnueabihf.so: undefined symbol: cblas_sgemm – Raspberry Pi
```

調べてみるとどうやらnumpy関連のようで、対処は色々あったが、どれもうまくいかず。

参考にしたページの一つ
https://jaredrhodes.com/2019/07/22/numpy-core-_multiarray_umath-cpython-35m-arm-linux-gnueabihf-so-undefined-symbol-cblas_sgemm-raspberry-pi/

numpyをuninstallしてinstallするを繰り返しているうちに、元々入れていたOpenCVからのnumpyインポートでエラーが起こるように。

```
ImportError: numpy.core.multiarray failed to import
```

そしてここを参考にしながら、
https://qiita.com/kai0706/items/8169d01a83f63fc4a0bd

これをやってみると、

```
$ python3
>>>import sys
>>>sys.path
```

このように出た。

```
['', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-arm-linux-gnueabihf', '/usr/lib/python3.5/lib-dynload', '/home/pi/.local/lib/python3.5/site-packages', '/usr/local/lib/python3.5/dist-packages', '/usr/lib/python3/dist-packages']
```

当たり前だが、Pythonにもライブラリロード順があるということが分かったので、'/home/pi/.local/lib/python3.5/site-packages', '/usr/local/lib/python3.5/dist-packages'といったあたりが'/usr/lib/python3/dist-packages'よりも前にあることが怪しいと思い、この一文を.bashrcに追記したらOpenCVのエラーもTensorFlowの動作確認プログラムもうまくいった！

```
export PYTHONPATH="/usr/lib/python3/dist-packages"
```
100種類以上のターミナルのカスタムテーマをサクッと導入

こんにちわ
最近メインPCがThinkpadになって、メインOSがUbuntuになったゴリラです

普段ターミナルで作業する方はカスタムテーマを使っていますか？
割とカスタムテーマをダウンロードして適用したりするの面倒と感じている方もいると思いますが、
今日はサクッとテーマを適用する方法を紹介します

## やり方
こちらを使います。MacとLinux対応しています。
https://github.com/Mayccoll/Gogh

ぼくはLinuxなので、次のコマンドを実行します。

```sh
bash -c  "$(wget -qO- https://git.io/vQgMr)"
```

100種類以上のテーマがあるので、[こちら](https://mayccoll.github.io/Gogh/)を見て使ってみたいものの番号を選択して下さい
もしくは`ALL`で全テーマを入れてもOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66178/7aa499a5-9e6f-c63d-60bf-1bd40b24bc2e.png)


入れたあと、デフォルト設定にしてターミナルを再起動すれば適用されます(gnome-terminalの場合)
あとはフォントを変えるなりして見てください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66178/ddf36f95-5650-2792-c106-82ebbf9130b4.png)

## さいごに
100種類以上のテーマをサクッと導入できるのは便利ですね
formでの情報の受け取り

#成果物
htmlのフォームに入力した内容を受け取って,
コンソールに返すjavascriptを作りたいと思います。
<img width="252" alt="スクリーンショット 2020-08-13 7.17.16.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663834/4c5d0faa-fcc8-e99f-e4aa-acacf522f169.jpeg">
<img width="194" alt="スクリーンショット 2020-08-13 7.43.22.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663834/cb9f1c34-8d89-7111-5535-556168e2348e.jpeg">
<img width="320" alt="スクリーンショット 2020-08-13 7.45.34.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663834/9b732731-d444-9fcc-1b35-7c957674326d.jpeg">



#前提知識
- 変数（javascript）
- 関数(javascript)


#仕組み
<img width="409" alt="スクリーンショット 2020-08-13 7.29.20.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663834/9d3ddf7c-3ac3-9c20-77c1-388381fa7aa0.jpeg">

#コード
###html側
formタグで、１行入力用のテキストエリアと、送信ボタンを作成します。
送信ボタンにはクリックするとnamePost()という関数が始まるようにしておきます。

```.html
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>無題ドキュメント</title>
<script type="text/javascript"	src="./main.js" defer></script>
</head>
<body>
	<form action="" >
	 	<input type="text"  id="yourName">
		<input type="button" onClick="namePost()" value="送信">
	</form>
</body>
</html>
```

###javascript側
namePost()という関数を作ります。

```.js
const namePost = () =>{
	const getName = document.getElementById("yourName").value;
	console.log(getName);
} 
```
javascript側から、htmlを参照するときに使う、`document.getElementById（"id名"）`の後ろに`.value`をつけると、htmlで入力したものをjavascript
で受け取ることができます。
最後に、定義したgetNameをコンソールで表示させれば完了です。

##参考サイト
https://techacademy.jp/magazine/21069
https://qiita.com/Teach/items/4b0104847be9f2960665?fbclid=IwAR0EoMAiMs5sBbQFMbUIEHWwBnpM4j26Ad_wUvhfybHuDtd-Gc6mfgg4Czc
wolfSSLの相互認証API

wolfTips: IoTデバイスのセキュリティライブラリ wolfSSL を使いこなすためのヒント集
　　　　　　　　　　　　　　--- 鍵、証明書編 ---

###概要
[wolfSSL](https://www.wolfssl.jp/wolfssl/products)はIoTデバイス、組み込み向け小型、軽量のSSL/TLSライブラリーです。ここでは、wolfSSLでサーバ認証、クライアント認証、あるいは相互認証を実現するためのAPIをまとめます。

TLSでは、ハンドシェーク実行時に通信の相手方のなりすましなどがないことを確認するために公開鍵証明書を使ったサーバ認証、クライアント認証、あるは両方を認証する相互認証を行うことができます。パソコンのブラウザからのWebサーバへのアクセスでは通常サーバ認証のみを行うケースが多いですが、IoTデバイスではデバイス側のなりすましを防ぐためにクライアント認証を行うケースも多々あります。

上の図に示すように、例えばサーバ認証のためにはにTLS通信の前にサーバ認証を実行したいクライアント側に信頼するルートCAの証明書をおき、サーバ側にはCAの署名したサーバ証明書と対応する秘密鍵を置いておきます。クライアント認証はちょうどその逆で、サーバ側にCA証明書をおき、クライアント側が自分を証明するための証明書と秘密鍵を置いておきます。両方の認証を行うことを相互認証と呼びます。

![MutualVerification.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263939/d4737f92-d894-dcfb-330c-f678e1a33177.jpeg)


wolfSSLではプログラム上でこれれを実現するためのAPIとして、表２のようにそれぞれの証明書や鍵をロードするためのAPIが提供されています。サーバ認証とクライアント認証はお互い対称なので、APIとしては３つのAPIがひと組だけ提供されていて、認証の方向によってサーバ、クライアントのどちらか適当なほうで利用します。ここでロードされた証明書、鍵がハンドシェーク時に参照され通信相手方の認証が行われます。これらの指定は、認証される側のAPIでは、一つのコンテクスト全体で共通のファイルを指定するためのAPI("wolfSSL_CTX_xxx")とセッションごとに異なるファイルを指定できるAPI("wolfSSL_xxx")の二種類が用意されています。

また、IoTデバイス、組込み系のシステムではファイルシステムが無いケースもあります。wolfSSLではそのような利用環境のために、ファイルイメージと同じものをメモリーバッファー上に置き、そのポインタとサイズを渡すようなインタフェースも提供されています。例えば、wolfSSL_load_verify_locationsに対してはwolfSSL_load_verify_bufferのように、wolfSSL_xxxに対してwolfSSL_xxx_bufferのようなネーミング規則となっています。

![API-List.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263939/16c749bc-6457-b094-5deb-71381a891db5.jpeg)


###まとめ
以上、wolfSSLのサーバ認証、クライアント認証のためのAPIについてまとめてみました。個々のAPI仕様については[wolfSSL APPIレファレンス](https://www.wolfssl.com/doxygen/group__CertsKeys.html)を参照してください。

ドキュメント：https://www.wolfssl.jp/docs/
英語サイト：https://www.wolfssl.com
日本語サイト：https://www.wolfssl.jp
Twitter: https://twitter.com/wolfSSL_Japan
グループ署名方式を実装する（libgroupsig）

# グループ署名方式とは

グループ署名方式とは署名者がグループに含まれることを証明する署名方式です。
グループ署名についての説明は[こちら](https://www.atmarkit.co.jp/ait/articles/1510/20/news007.html) にあります。

# 想定する環境

- Ubuntu 20.04

# インストール
## 1. 必要なパッケージをインストール

以下のコマンドで事前に必要なプログラムをインストールしておきます。

```sh
$ sudo apt update
$ sudo apt install git build-essential cmake libssl-dev
```

## 2. libgroupsigのインストール

以下のコマンドでlibgroupsigをインストールします。

```sh
$ git clone https://github.com/IBM/libgroupsig
$ cd libgroupsig
$ mkdir build
$ cd build
$ cmake ..
$ make
$ sudo make install
```

# プログラムの作成
## 1. プログラムの記述

以下のようなプログラムを書き、`sign_gl19.c`という名前で保存します。

```c
#include <groupsig/groupsig.h>

int main (int argc, char *argv[]) {

  groupsig_config_t *cfg;
  groupsig_key_t *grpkey, *isskey, *cnvkey, *memkey;
  groupsig_signature_t *sig;
  message_t *msg, *m1, *m2, *m3, *m4;
  uint8_t b;

  /* Initialize environment for GL19 */
  cfg = groupsig_init(GROUPSIG_GL19_CODE, 0);

  /** Create the group **/

  /* Initialize the group and manager keys */
  grpkey = groupsig_grp_key_init(GROUPSIG_GL19_CODE);
  isskey = groupsig_mgr_key_init(GROUPSIG_GL19_CODE);
  cnvkey = groupsig_mgr_key_init(GROUPSIG_GL19_CODE);

  /* Run the Issuer part of the setup */
  groupsig_setup(GROUPSIG_GL19_CODE, grpkey, isskey, NULL, cfg);
  
  /* Run the Converter part of the setup */
  groupsig_setup(GROUPSIG_GL19_CODE, grpkey, cnvkey, NULL, cfg);

  /** Add a member to the group **/

  /* Initialize the member key */
  memkey = groupsig_mem_key_init(GROUPSIG_GL19_CODE);
    
  /* Simulate the issue-join interactive process */
  m1 = m2 = m3 = m4 = NULL;
  groupsig_join_mgr(&m1, NULL, isskey, 0, NULL, grpkey);
  groupsig_join_mem(&m2, memkey, 1, m1, grpkey);
  groupsig_join_mgr(&m3, NULL, isskey, 2, m2, grpkey);
  groupsig_join_mem(&m4, memkey, 3, m3, grpkey);

  /** Sign a message **/

  /* Prepare the message */
  msg = message_from_string("Hello, World!");
  
  /* Initialize the signature object */
  sig = groupsig_signature_init(GROUPSIG_GL19_CODE); 
  groupsig_sign(sig, msg, memkey, grpkey, 0);

  /** Verify the signature **/
  groupsig_verify(&b, sig, msg, grpkey);

  if (b) {
    fprintf(stdout, "VALID signature.\n");
  } else {
    fprintf(stdout, "WRONG signature.\n");
  }

  /* Free memory */
  groupsig_clear(GROUPSIG_GL19_CODE, cfg); cfg = NULL;
  groupsig_grp_key_free(grpkey); grpkey = NULL;
  groupsig_mgr_key_free(isskey); isskey = NULL;
  groupsig_mgr_key_free(cnvkey); cnvkey = NULL;
  groupsig_mem_key_free(memkey); memkey = NULL;
  groupsig_signature_free(sig); sig = NULL;
  message_free(msg); msg = NULL;
  message_free(m1); m1 = NULL;
  message_free(m2); m2 = NULL;
  message_free(m3); m3 = NULL;
  message_free(m4); m4 = NULL;
  
  return 0;

}
```

## 2. コンパイル＆実行

以下のコマンドで、コンパイルと実行を行います。

```sh
$ gcc sign_gl19.c -o sign_gl19 -lgroupsig -lmcl -Wl,-rpath=/usr/local/lib
$ ./sign_gl19
```

`VALID signature` と表示されれば成功です。

# 参考

- https://www.atmarkit.co.jp/ait/articles/1510/20/news007.html
- https://github.com/IBM/libgroupsig/wiki/Building-libgroupsig
- https://github.com/IBM/libgroupsig/wiki/Using-libgroupsig
7zで作成された自己展開形式のexeをcliから展開する

「～.7z.exe」な自己展開形式のファイルをスクリプトから利用したいときなどに、展開先をGUIから指定させられるのが地味にこまります。

つぎのように実行することでCLIから展開先を指定して実行することができます。GUIのプログレスダイアログが表示されますが。

```powershell
.\PortableGit-2.28.0-64-bit.7z.exe -o"Git" -y
```

-oの後に空白がないのは間違いではありません。連続して指定してください。
DynamodbをLambdaからSQLっぽく操作する

# 説明の前に

pipのモジュールを利用する方法は、下記の記事を参考にさせていただきました。
ありがとうございました。

【Python】AWS Lambdaで外部モジュールを使用する
https://qiita.com/SHASE03/items/16fd31d3698f207b42c9

# 1.準備
LambdaにPipのモジュールを持ってくる必要があるため、ローカルにDQLモジュールをインストールする。

プロジェクトフォルダ内で、下記

```sh
$pip install dql -t ./
```

# 2. ソースコード
ファイル名は`lambda_function.py`

```python
import dql
def lambda_handler(event, context): 
    engine = dql.Engine()
    engine.connect(region="us-west-2")
    results = engine.execute("DELETE FROM tablename WHERE tm >= 1420071600 AND tm <= 1420705200;")
    print(results)
    return "hi world"
```
`region`や`tablename`、クエリなどは任意の設定に修正してください。

# 3. zip化してアップロード

```sh
zip -r dpl.zip ./*
```

完成したZIPをLambdaにアップロードすれば完成です。
【Vim】起動時と保存時に自動で行末の空白を削除する設定

- vimでの編集の際に以下の点で気になったため、解消できるかを調査。
  - 「**癖や不意**」で行末に空白が入ってしまうため、毎回手動やコマンドで削除している。
  - 時々削除忘れを起こすことがあるため、自動で削除したい。
  - 削除防止を徹底するため、**保存時だけでなく起動時**も自動削除を行いたい。
- そこでautocmd機能を利用して、自動削除設定を記述していく。

## 手順
- vimrc(設定ファイル)を開く。

```bash
vim ~/.vimrc
```

- 下記の内容を`.vimrc`へ書き込む。

```vim:~/.vimrc
augroup vimrc
autocmd BufRead,BufWrite * if ! &bin | silent! %s/\s\+$//ge | endif
augroup END
```

- vim内で設定読み込み。

```vim
:source ~/.vimrc
```

- 試しにファイル内の行末へ空白を入力して、「起動・保存」時に自動削除がされていたら完了。

## 参考
- [Vim 空白削除コマンド](https://www.mk-mode.com/blog/2012/06/20/20002049/)
- [autocmdドキュメント](https://vim-jp.org/vimdoc-ja/autocmd.html)
競プロ備忘録 - AGC047 A問題でWAがとれずに苦労した。

これもたぶんRust特有のはまり方

#結論
Rustの減算には要注意。

#問題
今回WAがとれずにハマった問題はこちら。

[AGC047-A Integer Product](https://atcoder.jp/contests/agc047/tasks/agc047_a)
要約すると、長さ$N$の実数列$A$から2個を取り出す時、積が整数になる組み合わせの数を求める問題。
$A_i$の制約は $0<A_i<10^4$ であり、小数第9位まで与えられる。

#提出

いつものようにRustで解いて下記のように提出したのだけれど、5つのケースで`WA`になった。
入力値の範囲などを何度チェックしなおしても原因がわからず、何時間も時間を浪費してしまった。

```Rust
#![allow(non_snake_case, unused_mut, unused_assignments)]
use proconio::input;
use std::cmp::*;

fn main() {
  input! {
    N:usize, A:[String;N]
  }
  let N: usize = N;
  let A: Vec<String> = A;
  let mut cnt = vec![vec![0; 50]; 50];
  let mut p2 = vec![0; N];
  let mut p5 = vec![0; N];
  for i in 0..N {
    let s = A[i].clone();
    let mut ip = 0usize;
    let mut dp = 0usize;
    if let Some(i) = s.find('.') {
      // 入力値が小数の場合
      ip = s[0..i].parse().unwrap();
      let ss = s[(i + 1)..].to_string() + "0000000000";
      dp = ss[0..9].parse::<usize>().unwrap()
    } else {
      // 入力値が整数の場合
      ip = s.parse::<usize>().unwrap();
    }
    let mut x = ip * 1_000_000_000 + dp;
    while x % 2 == 0 {
      x /= 2;
      p2[i] += 1;
    }
    while x % 5 == 0 {
      x /= 5;
      p5[i] += 1;
    }
    cnt[p2[i]][p5[i]] += 1;
  }

  let mut ans = 0usize;
  for i in 0..N {
    let remain2 = max(18 - p2[i], 0);
    let remain5 = max(18 - p5[i], 0);
    for j in remain2..50 {
      for k in remain5..50 {
        ans += cnt[j][k];
      }
    }
    if p2[i] >= remain2 && p5[i] >= remain5 {
      ans -= 1;
    }
  }
  println!("{}", ans / 2);
}
```

#原因
結論から言うと、今回の原因は計算途中で値が負になってしまったこと。
`cnt`のindexとして使用するため、`p2[i]`,`p5[i]`の型は`usize`にしている。それを踏まえて下記の行を見てみる。

```Rust
    let remain2 = max(18 - p2[i], 0);
    let remain5 = max(18 - p5[i], 0);
```

`remain2`と`remain5`が$0$以上になるよう、`std::cmp::max`を使っている。……のだけれども、`p2[i]`が`usize`であることから`18 - p2[i]` も`usize`と型推論されるため、`18 - p2[i]`が$0$未満になった時点で`panic`が発生する。つまり`max`自体が無意味だったというオチ。
例えば入力値として`1 0.000524288`($2^{19} / 10^9$)を与えると`p2[0]`が$19$になるため、下記のように`attempt to subtract with overflow`が発生する。

```
runtime error: exit code: 101

stderr:
     1 | thread 'main' panicked at 'attempt to subtract with overflow', src\bin\a.rs:41:23      
     2 | note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```

このコードを活かすなら、下記のように、いったん符号付整数型に変換する必要がある。[^1]

```Rust
    let remain2 = max(18 - p2[i] as i64, 0) as usize;
    let remain5 = max(18 - p5[i] as i64, 0) as usize;
```



[^1]: ちなみに実行時間などを考えると、`cnt`のサイズを$19 \times 19にして、$`p2[i]`,`p5[i]`を値を18以下にしたほうが良い。というか、[そちらのコード](https://atcoder.jp/contests/agc047/submissions/15855480)で`AC`することに気づいてからも、原因に気付くまでかなり悩んだ。

#おまけ
`std::cmp::max`ではなく、`if`文で同じことをすると、無意味な比較だと教えてくれる。

```Rust
    let remain2 = if 18 - p2[i] >= 0 { 18 - p2[i] } else { 0 };
```
のように書くと、下記のようになる。

```
warning: comparison is useless due to type limits
  --> src\bin\a.rs:41:22
   |
41 |     let remain2 = if 18 - p2[i] >= 0 { 18 - p2[i] } else { 0 };
   |                      ^^^^^^^^^^^^^^^
   |
   = note: `#[warn(unused_comparisons)]` on by default
```



#愚痴
というかこれ、`WA`じゃなくて`RE`ちゃうんか？
いろんな実行時エラーを試して、`WA`と`RE`のどちらにジャッジされるか、見分けるケース一覧作ったら便利そう。
C# エラーメッセージ

`Split`の引数を`"`で囲ってしまった時に出たエラー。使用するときは、`data.Split(',')`のようにシングルクォーテーションで指定する。

```C#
Main.cs(8,31): error CS1502: The best overloaded method match for `string.Split(params char[])' has some invalid arguments
/usr/lib/mono/4.5/mscorlib.dll (Location of the symbol related to previous error)
Main.cs(8,37): error CS1503: Argument `#1' cannot convert `string' expression to type `char[]'
```

`implicitly convert type`とは、「暗黙の型変換」の意味。int型の変数に、string型の文字列を代入しようとしたときに出たエラー。

```C#
Main.cs(8,25): error CS0029: Cannot implicitly convert type `string[]' to `int'
```
VSCodeとDockerで快適なSphinx(reStructuredText, rst)編集環境を作る

弊社のプロジェクトではドキュメントをSphinx(rst)で書くことになっているのですがあまり普段rstを書くことがないので、なにかの手助けがないとスラスラドキュメントが書けません。
今回はVSCodeとDockerを使っていい感じに補完、lint, previewができる環境を構築します。
rst用のVSCodeプラグインとして[reStructuredText - Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=lextudio.restructuredtext)があるので、それをインストールすれば出来上がりかと思ったのですが、ちょっと面倒な設定が必要だったのでまとめた次第です。

## Dockerなしで使う

ドキュメントは[reStructuredText Extension for Visual Studio Code — restructuredtext 1.0 documentation](https://docs.restructuredtext.net/)にあり、書かれているとおりに環境を作ってあげれば動くようになります。ただ、pip moduleをglobalにインストールさせようとしているあたりが自分のPythonプロジェクトの開発手法と相容れないところがあり、この方法は取りませんでした。

普段自分はpyenv + pipenvでproject毎にPython環境を切り替えています。上記のマニュアルによるとvirtualenvも対応しているようなので、正しく設定すれば僕の普段の環境でも使えるようになるはずですが、困ったことに設定が複雑になるとの理由でドキュメントから説明が省かれてしまっています。


## Dockerを使う

Dockerで環境を固めて、コンテナにVSCodeでアタッチする形で使えば環境がポータブルにできるので、今回はそちらの方法で環境構築します。
Sphinxの公式Docker imageは[Sphinxdoc/sphinx](https://hub.docker.com/r/sphinxdoc/sphinx)にあるので、このimageをベースにします。

このimageに[Prerequisites — restructuredtext 1.0 documentation](https://docs.restructuredtext.net/articles/prerequisites.html#)で定義されている依存モジュールを入れてあげればよいことになるので、下記のように定義しました。

```docker:Dockerfile
FROM sphinxdoc/sphinx:3.2.0

RUN mkdir /workspace
WORKDIR /workspace

RUN python3 -m pip install --no-cache-dir \
    docutils sphinx-autobuild doc8 rstcheck \
    sphinx_rtd_theme sphinxcontrib-httpdomain
```

`docutils`は`sphinx`を使うのであれば必要なく、`doc8`と`rstcheck`はどちらか好きな方で良いですが面倒なので全部入れています。`sphinx_rtd_theme`と`sphinxcontrib-httpdomain`はプロジェクトで必要だったので入れています。

あとは、imageをbuildしてコンテナを作って、VSCodeからコンテナ起動、中に入ってドキュメントを編集します。
[reStructuredText - Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=lextudio.restructuredtext)はremote containerにもインストールする必要があるので注意が必要です。