OmniAICreator/Qiita-1.07M huggingface dataset:
【rails】gem 「devise」の使い方

今回は一番railsを利用しているとよく見かける「devise」というgemについて学習したため、
アウトプットいたします。

わかる内容としては
●　そもそもdeviseとは？
●　deviseの使い方とは？

です。

#deviseとは？

railsで作ったウェブアプリケーションに、簡単にログイン、ログアウト機能を追加するgemです。
deviseはgemの中で一番使用されており、工数がかかるログイン機能の実装を簡素化してくれます。

ではどのようにdeviseを使っていけばいいでしょうか？


#deviseの使い方

１、　gem install
まずはgemをインストール。gemfileにdeviseを記述しましょう

```
gem 'devise'
```

2, rails g devise:install
deviseの設定ファイルをrailsにインストールするのがこのコマンドです。

3, rails g devise:views
deviseのファイル（サインアップ、ログイン等）を作成します。
※もしデフォルトで備わっているサインアップやログインのページで良ければこれをする必要はない

4,　railsでログイン機能を実装したいモデルを作成する
deviseで認証する（ログインする）ためのモデルを作成します。

```
rails g devise モデル名
```


5, migrationファイルを読み込む
最後はおなじみ。マイグレーションファイルが変更されたので、それを読み込んでください

```
rake db:migrate
```

以上で実装は完了です。
Tencent CloudのTWebLiveを使ってWebでライブ配信をやってみた。

# TWebLiveの紹介
TWebLiveはTencent Cloud Webライブ配信SDKです。TWebLiveがTencent CloudのTRTC、IM、Super Video Player(TCPlayer)を統合して、Webライブ配信のよく使う機能（Stream push,Stream pull, マイクのオンオフ、カメラ、コメント、いいねなどの機能）をカバーして、簡単に使えるAPIです。[Github](https://github.com/tencentyun/TWebLive)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633185/70171dd8-6a44-1838-bffc-754ab7c328bc.png)

# 前提条件
[Tencent Cloud](https://intl.cloud.tencent.com/)のアカウントを持っていること。

# 手順
### 1.コンソールでTRTCのアプリを作成
[TRTCコンソール](https://console.cloud.tencent.com/trtc)でTRTCのアプリを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633185/ab468ce7-386a-415b-1a1c-c9525a5c97e3.png)
https://main.qcloudimg.com/raw/a65b6631553159ce553620e40f9c2040.png

### 2.SDKAppIDと秘密鍵を取得
【Application Management】をクリックして、先に作成したアプリに入ると、SDKAppIDと秘密鍵を確認できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633185/4ce2a413-56e9-a10b-3921-10232ec4439e.png)
https://main.qcloudimg.com/raw/a65b6631553159ce553620e40f9c2040.png
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633185/b6d3c42d-114e-e023-b012-0ef3dc122bd7.png)
https://main.qcloudimg.com/raw/99f03c367c43416bd7c7e8c6d6ff5002.png

### 3.Webライブ配信のDemoをダウンロード
- Githubに公開された[Webライブ配信デモ](https://github.com/tencentyun/TWebLive)をダウンロードする
- ```TWebLive/dist/debug/GenerateTestUserSig.js```で、手順2で取得したSDK App IDと秘密鍵を```SDKAppID```と```SECRETKEY ```に設定する。

### demo実行
Chrome/Safariで```dist```フォルダーの```index.html```を開ければ、Demoが動き始める。
下記はデモの実行した様子です。実行するときに、カメラとマイクのテスト必要です。テストが完了したら、Webライブ配信が可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633185/72a37b12-e44a-6fb6-4c2f-dd1b03783058.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633185/f9ac909b-5003-df00-bd7f-538902c08c1d.png)

# まとめ
以上で、TWebLive SDKでライブ配信のデモを動いてみました。2行のソースコードをいじるだけで、Webライブ配信アプリをできた。
VagrantにHerokuを入れる際に起きたエラーと解決方法と参考記事

#はじめに
ドットインストールで構築したローカル環境でアプリを開発し、公開するため、いざherokuを入れようとしたらエラーが起きまくりました。
[【初心者向け】railsアプリをherokuを使って確実にデプロイする方法【決定版】](https://qiita.com/kazukimatsumoto/items/a0daa7281a3948701c39#%E8%87%AA%E5%88%86%E3%81%AE%E7%92%B0%E5%A2%83)
この記事を参考にしていました。
しかし、herokuを入れる際に、この記事の開発環境が全く違うため、その先に進めずエラーと戦うことになりました。


#パスがない問題
エラー解決に必死だったため、エラーのコピーは取っていませんが、このようなエラーがでたと思います。

```
↓エラーの最後の文
Your path is missing /usr/local/bin, you need to add this to use this installer.
```
`/usr/local/bin`のパスが無いと言われているため、パスを作る必要があるみたいです。

パスの確認

```
$ echo $PATH
```
パスを確認してみますが`/usr/local/bin:`はあっても`/usr/local/bin`がないと駄目みたいです。
##解決方法の前に、解決する中で知った知識
`sudo`とは、僕の解釈では権限の高いコマンド。
`$`と`#`で違いもあり、`#`のほうが権限が高い。（`$`の方で実行できないことが`#`で実行できたから）

##解決方法：偉い権限を使ったり、`vi`エディタで書き換えたりする。
パスの設定に必要な`.bash_profile`の設定と`sudo`の設定は以下を参考にしました。
[仮想環境構築後に設定しておきたいこと -メモ-](https://qiita.com/Ma-ishii/items/bf0e43fd859a1826dd9f)

`sudo`の設定はこちらの方が親切です。
[CentOS で sudo 時に実行ユーザーのPATHを引き継ぐ](https://qiita.com/ogwmtnr/items/3ec2fab50d069a3cf335)

```
$ sudo visudo
```
の実行後に、viエディタの操作が必要だったため以下を参考にしました。
[viエディタの使い方](https://www.youtube.com/watch?v=FY3K8rAznFk&t=174s)

#パスが通ったと思ったら、シンタックスエラー問題

```
$ heroku --version
```
herokuのバージョン確認をすると、以下のエラーが...

```
/usr/local/lib/heroku/node_modules/@oclif/command/lib/index.js:3
const path = require("path");
^^^^^
SyntaxError: Use of const in strict mode.
    at Module._compile (module.js:439:25)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.require (module.js:364:17)
    at require (module.js:380:17)
    at Object.<anonymous> (/usr/local/lib/heroku/bin/run:5:1)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
```
Node.jsのバージョンが古すぎたみたいです。

```
$ node -v
```
確認してみたところ`v0.10.48`でした。
##解決方法：キャッシュを消して、新しいバージョンを入れる。
いろいろと試したため、ダイレクトな解決方法にならない場合はすみません。

`npm`がインストールされていなかったので、インストールしました。ついでに`node`もインストール。
`Heroku`を入れるために`npm`が必要かどうかはわかりませんが、とりあえずインストールしました。

```
$ sudo yum install nodejs npm
```


偉い権限の方に行く。

```
$ sudo -s
```
左のやつが`$`から`#`に変わる。

インストールするために必要なやつ（正直、よくわかってないですが`setup_11.x`の数字の部分でインストールするバージョンを指定。）

```
# curl --silent --location https://rpm.nodesource.com/setup_11.x | bash 
```

ここから、インストールとアンインストールを繰り返したため、手順が間違っていたらすみません。
以下を参考にしました。先の読んでおいて欲しいです。
[yumでのnodejsのバージョンアップにはまった話と解決方法](https://qiita.com/robitan/items/a684a81214767c21a560)

古い方のrpmを削除。

```
# rm /etc/yum.repos.d/nodesource-el.repo
```
アンインストールする。

```
# yum -y remove nodejs
```
キャッシュを削除。

```
# yum clean all
```
インストールする。

```
# yum -y install nodejs
```
バージョンを確認。

```
# node -v
v11.15.0
```
成功です！
そして、偉い権限のところから出る。

```
# su vagrant
```

herokuのバージョンも確認

```
$ heroku -v
heroku/7.44.0 linux-x64 node-v11.15.0
```

他の参考記事です。
https://qiita.com/daskepon/items/16a77868d38f8e585840
https://inaba.hatenablog.com/entry/2018/11/13/023933

ほぼ同じエラーが出ていた記事
https://teratail.com/questions/256490

#感謝
参考にさせていただいたサイト管理人の皆様、誠にありがとうございました。
Docker（Windows）のUbuntuコンテナでNordVPNを動かす

# こんな人向け

+ 複数コンテナで別々のIPを取得したい
+ 格安で

# 手順

1. Dockerインストール
2. コンテナ立ち上げ
3. 起動イメージ作成
4. NordVPN接続
5. その他コマンド

## 1.Dockerインストール
ダウンロード（dockerhub）：
https://hub.docker.com/editions/community/docker-ce-desktop-windows/
参考手順サイト：
https://ops.jig-saw.com/tech-cate/docker-for-windows-install

## 2.コンテナ立ち上げ

```
docker pull ubuntu
docker run -it --name ubuntu1 ubuntu bash
```

## 3.起動イメージ作成

### NordVPNインストール

```
apt-get update
apt-get install wget
wget -qnc https://repo.nordvpn.com/deb/nordvpn/debian/pool/main/nordvpn-release_1.0.0_all.deb
apt install -y nordvpn-release_1.0.0_all.deb
```

エラーが出るので、

```:ERROR
E: Unable to locate package nordvpn
```

apt installとupdateとupgradeを何回か繰り返してると通る。

```
apt update
apt upgrade
apt install -y nordvpn
```

エラーで進めなかったら必要に応じて、

```
apt --fix-broken install
```

も混ぜて叩いてみる。

この時点では、以下の追加設定が必要なため、一時イメージを作成する。

+ nordvpndがsystemdにより実行されていること（bash等から起動していないこと）
+ コンテナにネットワークデバイスの使用権限を付与すること

###一時イメージ作成
コンテナからexitしておく。

```
docker commit ubuntu1 ubuntu-nordvpn
```

###Dockerfile作成

コンテナ立ち上げ時に、nordvpnが起動するようにする。
公式：[NordVPN Dockerイメージを構築する方法は？](https://support.nordvpn.com/Connectivity/Linux/1507838432/How-to-build-the-NordVPN-Docker-image.htm)


```:Dockerfile
FROM ubuntu-nordvpn

ENTRYPOINT ["/usr/sbin/nordvpnd", "&"]
```

###ビルドする
Dockerfileがあるディレクトリで、以下のコマンドを実行する。
最後にカレントディレクトリのDockerfileを参照する「．（ピリオド）」を付ける。

```
docker build -t ubuntu-nordvpn-entrypoint .
```

###新イメージからコンテナ立ち上げ
コンテナにネットワークデバイスの使用権限を付与するオプションを付けて起動する。

```
docker run -it --cap-add=NET_ADMIN --cap-add=SYS_MODULE --device /dev/net/tun --name ubuntu-nordvpn-entrypoint1 --sysctl net.ipv4.conf.all.rp_filter=2 ubuntu-nordvpn-entrypoint
```

シェルの反応が返ってこなかったら、Ctrl+p Ctrl+q で一度、コンテナから抜ける。再度、bashで入る。

```
docker exec -it ubuntu-nordvpn_entrypoint1 bash
```

## 4.NordVPN接続

```
nordvpn login
# Username : NordVPNアカウント登録時のメールアドレス
# Password : NordVPNアカウント登録時のログインパスワード
nordvpn set protocol tcp
nordvpn set killswitch on     #エラーが出てもon登録される
nordvpn connect Japan
```

## 5.その他コマンド

###IPチェック用
```
wget -O - http://inet-ip.info/ 
```

# リンク

+ [stackoverflow : Run nordvpn in a docker container](https://stackoverflow.com/questions/59708051/run-nordvpn-in-a-docker-container)
+ [youtube : Run All Your Dockers through a VPN](https://www.youtube.com/watch?v=BZ1LOMJqEkM)
PyCryptodomeがnot found

以下は確認した

- パスが通っている
- バージョンも正しい

なぜだろう..と思ったが意外な方法で解決した。
site-packagesにあるライブラリのインストールフォルダ名が**crypto**になっていた場合、それを**Crypto**に変更する。過去にcryptoという別のライブラリをインストールしていたのが原因らしい。

```python
>>> import Crypto
>>> 
```
OK
Vue CLIの導入方法




どうも　最近Vuejsを始めたので
アウトプットしていこうと思います



#Vue CLIとは

VueCliはVue.jsで開発するための便利ツールであります
私の解釈で話しますと、
VueCLIはVueを使うときに最初にうつコマンドのところであり
プロジェクト生成するときに使います。
CLIはコマンドインターフェースであります。

なぜこんな説明をしたかと言いますと、
なんと私

####Vue.jsと　Vue CLIって違うものなの？
とかなんかあたかも対等な関係的な感じで考えていました。
当たり前に違いました。


#導入方法


１　Vue CLIをグローバルにインストール

```
 % npm install -g @vue/cli
```

2.これでバージョンを確認

```
 vue --version
```



3.プロジェクトを作成(hoge-appのところは自分の作りたいプロジェクトの名前）

```
 vue create hoge-app
```


4.プロジェクトを作るとこのようなものが出てきます
とりあえず初めてのかたであれば設定をカスタマイズできるManually select featuresを選択します

```
Default ([Vue 2] babel, eslint) 
  Default (Vue 3 Preview) ([Vue 3] babel, eslint) 
  Manually select features 
```

5. これに関しては用途に合わせて選んでください
　　初めての方の場合は私と同じCSS Pre-processorsとbabelを選んどきましょう

```
Vue CLI v4.5.6
? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯◉ Choose Vue version
 ◉ Babel
 ◯ TypeScript
 ◯ Progressive Web App (PWA) Support
 ◯ Router
 ◯ Vuex
 ◯ CSS Pre-processors
 ◉ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

```
おそらくこの後に私と同じCSS Pre-processorsを選んだ方は
CSS Pre-processorsの具体的になんのライブラリを使用するか選ぶこととなるでしょう

その後。。。。



６.babelやESLintの記述をどのファイルに記述するか選びます
　専用の設定ファイルを使用する場合はIn dedicated config filesを選びます
私はIn dedicated config files選びます。

```
Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
❯ In dedicated config files 
  In package.json 

```

７.今回の設定をプリセットするか選択します
yを選択すると今後今までの作業を省略することができます。
```
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? (y/N) 
```



これでエンターキーを押したらおしまいです:sunny:
お疲れ様でした:shamrock:
M5StickV と M5StickC Plus  買ってみた

# Qiita 始めてみた

初めまして。 cpx といいます。

自身の理解を深めるためにも勉強したことを少しずつまとめて投稿してみようかなと考え、Qiitaを始めてみました。
不束者ではございますが、何卒よろしくお願いいたします。

# M5StickV と M5StickC Plus 買ってみた

職場の先輩に感化され、[スイッチサイエンス](https://www.switch-science.com)の小型マイコンモジュール[M5Stack](https://m5stack.com)シリーズのAIチップK210を搭載したM5StickVとIoT開発基盤のM5StickC Plusを購入しました。

<!---
![m5stick_v_c.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765592/cfe83a07-5dc2-b8f3-d107-542ca3716fc1.jpeg)
-->

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765592/cfe83a07-5dc2-b8f3-d107-542ca3716fc1.jpeg" width=50% height=50% alt="m5stick_v_c.jpg">

※ 左水色：M5StickV，右橙色：M5StickC Plus
本当に小さいです。小型マイコンの名は伊達ではないですね。

## M5StickV

AIチップのK210が載っています。（本当はK510搭載版が発売されてから購入するつもりでしたが、マイク搭載版が発売され我慢できず買ってしまいました笑）（K510搭載版は結局M5Stackでは製品化していないようですね、、、；2023年2月9日追記）

カメラ付きです。レンズの締め具合がよくわからなかったです。ピント調整をいい感じのところで止めても少しの振動で緩んじゃいます。

<!---
![face_detection.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765592/29eb9358-9cfb-698b-f211-044fbf636324.jpeg)
-->

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765592/29eb9358-9cfb-698b-f211-044fbf636324.jpeg" width=50% height=50% alt="face_detection.jpg">

- 購入時デフォルト顔検出

## M5StickC Plus

M5StickVにBluetoothやWiFiなどの通信機能がないので、M5StickCにつないでIoT化しようと思い購入しました。

<!---
![imu.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765592/4475b2c9-f365-da85-3fef-62325c387e4f.jpeg)
-->

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765592/4475b2c9-f365-da85-3fef-62325c387e4f.jpeg" width=50% height=50% alt="imu.jpg">

- 6軸IMU（加速度センサ＋ジャイロセンサ）

<!---
![bmp_rtc_time.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765592/7443196a-8948-06f1-61f6-4d9c773d417f.jpeg)
-->

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765592/7443196a-8948-06f1-61f6-4d9c773d417f.jpeg" width=50% height=50% alt="bmp_rtc_time.jpg">

- RTC : リアルタイムクロック

<!---
![microphone.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765592/a8954544-29a8-bd0d-6803-a6d563f3286f.jpeg)
-->

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765592/a8954544-29a8-bd0d-6803-a6d563f3286f.jpeg" width=50% height=50% alt="microphone.jpg">

- マイクロフォン

<!---
![bluetooth.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765592/3ee6ffbf-179f-f704-e326-f782272e8fad.jpeg)
-->

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765592/3ee6ffbf-179f-f704-e326-f782272e8fad.jpeg" width=50% height=50% alt="bluetooth.jpg">

- Bluetooth

# あとがき

とりあえず購入時の製品状態を確認できました。
これから色々いじってなんらかのシステムを構築できたらいいなぁと考えています。

今後、M5Stack以外にも以下のキーワードに関連することを投稿していきたいです。
\#CNN \#ComputerVision \#DeepLearning \#MachineLearning \#ImageProcessing \#GPU \#CUDA \#Python \#C++ \#GoogleColaboratory \#Git \#GitHub \#Linux \#Ubuntu \#ROS \#Docker \#Camera \#LiDAR \#IMU \#SLAM \#Microcontroller \#M5Stack \#M5StickV \#M5StickC etc.

# 参考文献

- [Wi-FiがないM5StickVを、M5StickCと繋ぎLINEに投稿してみるまでの手順](https://qiita.com/nnn112358/items/5efd926fea20cd6c2c43)
Passenger 6.0.5 で ActiveRecord 使った Sinatra アプリが死んだ

# 何の話？

CentOS 8 + Apache 2.4 + Phusion Passenger 6.0 で，ActiveRecord を使った Sinatra アプリを動かしていた。
Ruby のバージョンは 2.7.1 だが，たぶんこのバージョンはあまり関係無い。

Passenger 6.0.4 では動いていたのに 6.0.6 では，本番（production）環境で起動すらしなくなった。
手許（ローカル）ではちゃんと動作している。

Apache のエラーログ（/var/log/httpd/error_log）には以下のように出ていた。

```
'production' database is not configured. Available: [] (ActiveRecord::AdapterNotSpecified)
```

# 原因

どうも Passenger 6.0.5 で導入された変更が原因のようだ。
ここに issue が上がっている。
https://github.com/phusion/passenger/issues/2281

同様の問題は Sinatra 以外でも起こりうるが，Rails では起こらない（たぶん）。

# 死んだコード

件の Sinatra アプリは，SQLite3 データベースにあらかじめ入れておいたデータを検索して表示するだけのごく簡単なもの。
データベースファイルは，とくに production 用とか development 用とか分けていない。

接続のところは

```rb
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: db_file)
```

てな感じに書いていた。
ローカル変数 `db_file` には，SQLite3 ファイルのパスが代入されている。

# 修正

どうも，`ActiveRecord::Base.configurations` をセットしてやらなければならないようなので，上記を

```rb
ActiveRecord::Base.configurations = {
  "production" => {"adapter" => "sqlite3", "database" => db_file },
  "development" => {"adapter" => "sqlite3", "database" => db_file },
}
ActiveRecord::Base.establish_connection
```

のように変えた。

これで本番環境でも動くようになった。
python スクレイピング時における　UnicodeEncodeError: 'cp932'

#概要
[goToEat](https://premium-gift.jp/eatosaka/use_store?events=page&id=2&store=&addr=&industry)の店名一覧から店名のみを抽出し、CSVに出力したい。

Beautifulsoup
requests
python3
windows10

を利用している。

#エラー内容と理由
以下のコードでhtmlタグを指定してタグを含めた店名をリストの形で抽出できた

```python

        urlName = "https://premium-gift.jp/eatosaka/use_store?events=page&id={}&store=&addr=&industry=".format(PageNumber)
        dataHTML = requests.get(urlName)
        soup = BeautifulSoup(dataHTML.content, "html.parser")
        elems = soup.select('h3.store-card__title')
```

余分な情報をreplaceし削除してCSVに出力する。i.textでテキスト情報を取得できると教えていただきました。

```python
    with open(r'C:\Users\daisuke\Desktop\python\eat.csv', 'w') as f:
        writer = csv.writer(f)
        for i in elems:
            """
            i = str(i)
            i = i.replace('<h3 class="store-card__title">', '')
            i = i.replace('</h3>', '')
            i = i.replace('  ', '  ')
            i = i.replace(' ', ' ')
            """
            print(i.text)

            try:
                writer.writerow([i.text])
            except:
                writer.writerow(['error'])
```
以下のエラーが発生

```
活伊勢海老料理中納言  大阪駅前第三ビル店
Traceback (most recent call last):
  File "C:\Users\daisuke\Desktop\python\go_to_eat.py", line 24, in <module>
    writer.writerow(i)
UnicodeEncodeError: 'cp932' codec can't encode character '\xa0' in position 20: illegal multibyte sequence
```

[参考1](https://ja.stackoverflow.com/questions/34431/python-%E3%82%A8%E3%83%A9%E3%83%BCcp932-codec-cant-encode-character)、[参考2](https://naruport.com/blog/2019/10/10/python-unicode-decode-error-todo/)によると

1. スクレイピング対象となるページは様々な文字コードで作られているため、スクレイピング時に自動で任意の文字コードでデコードされる
2. 対象となる文字コードはOS依存で、windowsではCP932(shift_jis)が選択される
3. これは日本語用の文字コードで、**\xa0(ノーブレークスペース)**には対応していない

#解決方法

そこで以下のようにノーブレークスペースを半角スペースに置き換えて対応しました。
いわば対症療法的やりかたでよくないですね

```python

        for i in elems:
            i = str(i)
            i = i.replace('<h3 class="store-card__title">', '')
            i = i.replace('</h3>', '')
            i = i.replace('  ', '  ')
            i = i.replace(' ', ' ')
            print(i)

            try:
                writer.writerow([i])
            except:
                writer.writerow(['error'])
```


恐らく一番良いのは問題の文字をきちんと表現できる文字コードを指定してやることではないでしょうか。次のように、 open()関数に encoding キーワード引数を与えてやると、自動変換で使用される文字コードを直接指定することができますから、これを Unicode 文字が表現できる UTF-8 等にしてやればいいわけです。

CSVファイルを開いた際に文字化けしてしまいますが、文字コードを変更すれば大丈夫です。

```python

with open(r'C:\Users\daisuke\Desktop\python\eat.csv', 'w', encoding='utf-8') as f:

```

しかし、CSVからreadした際に以下のように不要な空白列が追加されてしまいました。
~~これはまだなぜかわかっていません。~~詳しい方がコメントで教えてくださり解決しました！
ありがとうございます

```
['ウルフギャング・ステーキハウス by ウルフギャング・ズウィナー 大阪店']
[]
['ぶどう畑']
[]
['墨国回転鶏料理  ルクア店']
```
Ubuntu on GCP にリモートデスクトップ接続

## はじめに
GCP上にUbuntuのOSを入れてWebサーバーなどを構築していると、ブラウザを利用して確認をしたくなる時がある。
デフォルトはSSH接続によるCUIがベースなため、今回GCP上のUbuntuにリモートデスクトップを構築して接続を試してみる。

## 実行環境
【ローカルPC環境】
　　Windows 10 Pro　

【サーバー環境】
　　Ubuntu20.04 LTS（GCP上）
　　※既にVMインスタンス作成済み。

## 手順
・コンソールから必要パッケージのインストール
・GCP上でネットワーク設定
・ローカルPCからの接続確認


### コンソールから必要パッケージのインストール

まずは、恒例のパッケージ管理ツールの更新。

```shell:
$ sudo apt update
$ sudo apt -y upgrade
```

リモートデスクトップで接続するためのユーザー作成。

```shell:
# ユーザー作成。　※パスワードの設定も求められる。
$ sudo adduser 【ユーザー名】

# 上記作成のユーザーがsudoコマンドが実行できる様にしておく。
$ sudo gpasswd -a 【ユーザー名】 sudo
```

リモートデスクトップに必要なパッケージをインストール。

```shell:
$ sudo apt -y install ubuntu-desktop xrdp
```
サービスの有効化・起動・確認

```shell:
$ sudo systemctl enable xrdp
$ sudo systemctl start xrdp
$ sudo systemctl status xrdp
```


### GCP上でネットワーク設定
リモートデスクトップ接続元のグローバルIPアドレスを調べる。　https://www.cman.jp/network/support/go_access.cgi
`ナビゲーションメニュー ＞ VPCネットワーク ＞ ファイアウォール` より、そのIPアドレスに対して[3389] のポートを開放する。
![Qiita-no012_img01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/0a508a4e-1299-b816-abf3-0598d97fd8a7.jpeg)


### ローカルPCからの接続確認
ローカルPCからリモートデスクトップ接続。
![Qiita-no012_img02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/956c03a7-0a30-7546-79bf-5cfe6e1f6e87.jpeg)

GCPのVMインスタンス画面の [外部IP] を入力して『接続』をクリック。
![Qiita-no012_img03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/5b6f1bfd-5ff8-f1bc-8975-55b7a8cca348.jpeg)
※何か聞かれるけどOKで問題なし。

以下の画面が立ち上がれば、ひとまず起動は成功している。
先程作成した [ユーザー/PASS] を入力して接続する。
![Qiita-no012_img04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/a4a0b89c-b009-f099-f410-b18c45b548ad.jpeg)


**この後、UbuntuのGUI画面に遷移すれば、リモートデスクトップ接続はひとまず完了！**

恐らくデフォルトでは`Firefox`が入っているので、Activitiesより起動させることが可能。
![Qiita-no012_img05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/a3408598-14f6-c5e6-28b8-46f4454a233d.jpeg)


※Chromeをインストールしたい場合、こちらのサイトが参考になる。
https://linuxfan.info/google-chrome-on-ubuntu
複数ユーザーで使うMacのzplug loadで"insecure directories..."エラーが出ないようにする

# 概要
zshでcompinitした際に、下記のようなエラーが出ることがあります

```shell-session
# compinit
zsh compinit: insecure directories and files, run compaudit for list.
Ignore insecure directories and files and continue [y] or abort compinit [n]?
```

これは検索すると、`compaudit`で出てくるディレクトリのオーナーやパーミッションを設定し直すことで解消できる、といった例を多く見かけます。

シングルユーザーの場合はこれで問題ないのですが、同じシステムを複数ユーザーで使っている場合は
誰か一人しかディレクトリのオーナーになれないので、毎回`y`を入力するか、`chown`をする必要があります。

※chownをする方法は[こちら](https://qiita.com/suin/items/7b49abadc387801e8d6f)でも紹介されていました。

※そもそも`compinit -u`とすれば無視することもできますが、 `zplug`を使っている場合はこれがラップされているので修正が困難です。

Macの場合 `/usr/local/share/zsh/` がこの問題として上がる例が多いみたいです。
このディレクトリはHomebrewで入れたパッケージの補完スクリプトなどが入る場所ですね。

今回は、`chown`せずに、補完を効かせつつこのエラーを出なくする方法を紹介します。

# 今の結論
`zplug load`の前に↓をやる

```zsh
rsync -a /usr/local/share/zsh/ ~/.zsh # sync auto completion scripts
fpath=("${(@)fpath:#/usr/local/share/zsh/site-functions}") # remove from $fpath
fpath=($fpath ~/.zsh)
```

# 何をやっているか

## `/usr/local/share/zsh/`を`~/.zsh`にコピー

```zsh
rsync -a /usr/local/share/zsh/ ~/.zsh
```

毎回`rsync`してるのは、Homebrewで新しいパッケージ入れた後でも反映できるようにするためです
重くなる懸念があれば、一度だけ`cp -R /usr/local/share/zsh/ ~/.zsh`としたり、`rehash`みたいなaliasにしてもいいかもしれません。

## fpathの更新
デフォルトでzshのモジュールとして読み込まれるパスは`$fpath`に一覧が入っています。

```shell-session
# echo $fpath
/usr/local/share/zsh/site-functions /usr/share/zsh/site-functions /usr/share/zsh/5.7.1/functions ...
```

なので

```zsh
fpath=("${(@)fpath:#/usr/local/share/zsh/site-functions}") # remove from $fpath
fpath=(~/.zsh $fpath)
```

として、`/usr/local/share/zsh/site-functions`を`$fpath`から削除し、rsyncした`~/.zsh`を追加しています。

ひとまずこれで、複数ユーザーでもHomebrewで入れたパッケージの補完を効かせつつ `insecure directories...` エラーが出ないようになりました。

# 参考
https://qiita.com/suin/items/7b49abadc387801e8d6f
https://stackoverflow.com/questions/3435355/remove-entry-from-array
Git config設定(global)

global:プロジェクトをまたいだ全体の設定のこと。
# 現在の状態を確認
```
$ git config -l
```

# ユーザ名の設定
```
$ git config --global user.name "ユーザ名"
```

# メールアドレスの設定
```
$ git config --global user.email メールアドレス
```

# 参考
- https://note.nkmk.me/git-config-setting/
JavaScript 配列の中の重複を省く簡単な方法

# 配列の重複を省く簡単な方法
## プリミティブ値

- 数字
- 文字列
- 真偽値

```javascript
//重複を省きたい配列
const old_array = [1,1,1,2,2,2,3,4];
const new_array = [...new Set(old_array)]

console.log(new_array);
// [1, 2, 3, 4]
```
##
Set
<https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Set>

## Object

### やりかた
1. ソートします。
2. 隣接するObjectと比較して重複しているなら省く。

以上

### 実践


```javascript
const old_array = [{k:3},{k:1},{k:2},{k:3},{k:1},{k:2},{k:3},{k:3}];

//ソート
old_array.sort((o1,o2)=> o1.k - o2.k);

//何を重複とするか決める。
//今回だとkの値が一緒だと重複と見なします。
function compare(o1,o2){
  return o1.k === o2.k
}

//あとは、隣と比較して同じだったら省くだけ！
const new_array = old_array.filter(function(element,index,array){
  if(index === 0) return true;
  return !compare(element,array[index-1])
})
console.log(new_array)
// [{"k":1},{"k":2},{"k":3}]

```
Jupyter Notebook / Labを立ち上げてパスワードを設定するシンプルな方法

# はじめに

QiitaでもJupyterにパスワードを設定する方法は既出ですが、「この方法でやっておけば間違いない。簡単、しかも安全」というものがシンプルに書かれていたらなぁと思いました。
Jupyter Notebookサーバーを一から立てる人の参考になれば嬉しいです。

一応、Jupyterサーバーのインストールから。

# 前提

- `pip` が利用できること

# Jupyter Notebook サーバーを立ち上げる

```terminal:terminal
$ pip install jupyter
$ jupyter notebook --port=8888 # ポートを指定したい場合
```

# Jupyter Lab サーバーを立ち上げる

```terminal:terminal
$ pip install jupyterlab
$ jupyter labextension install jupyterlab-plotly # Jupyter LabでPlotlyを使う場合（詳細は後述）
$ jupyter lab --port=8888 # ポートを指定したい場合
```

# パスワードを設定する

自分でハッシュ化したり、パスワードを平文で書いたりする必要がなく、キーボード入力で自動で暗号化して保存してくれます。楽ちんですね。
参照: [公式ドキュメント](https://jupyter-notebook.readthedocs.io/en/stable/public_server.html#automatic-password-setup)

```terminal:terminal
$ jupyter notebook password
Enter password: 
Verify password:
[NotebookPasswordApp] Wrote hashed password to $HOME/.jupyter/jupyter_notebook_config.json
```

# 余談

## 設定ファイルを生成する

サーバー起動時にブラウザを立ち上げたくないなどの設定は、このファイルを直接編集すればOKです。
やり方は Jupyter Notebook / Lab 共通です。

```terminal:terminal
$ jupyter notebook --generate-config
Writing default config to: $HOME/.jupyter/jupyter_notebook_config.py

# 実際には$HOMEとは表示されません。ご使用の環境のホームディレクトリが表示されます。
```

## Jupyter LabでPlotlyを使うなら必要な設定

Jupyter LabでPlotlyのグラフを描写しようとすると、表示されないことがあります。`jupyter` コマンドでプラグインをインストールしましょう。グローバルで `node` コマンドが使えること前提です。

[Plotly 公式ドキュメント](https://plotly.com/python/getting-started/) の *JupyterLab Support (Python 3.5+)* に書かれているとおりインストールを行います。

```terminal:terminal
$ brew install node # macOSの場合
$ node --version
v14.13.0
$ jupyter labextension install jupyterlab-plotly
```
VScode上でubuntuを操作する(windows10)

python3(django)の開発環境構築時にubuntuを使用したが、
コーディングする際に使うVScode上でコマンド打てないか調べたところあったの備忘録


#事前準備
VScodeがダウンロードされていること
ubuntuがダウンロードされていて、ユーザ名とパスワード設定が終わっていること

# VScodeとubuntuの連携
VScodeの左下の設定(歯車)⇒設定

[shell]と検索すると以下の文章が中段辺りにある
`Terminal › Integrated › Shell Args: Windows`

その下にある以下をクリック
`settings.jsonで編集`

settings.jsonが開かれるので{}内にbash.exeのパスを追加で完了

```json:settings.json
{
    "editor.formatOnPaste": true,
    "editor.suggestSelection": "first",
    "vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue",
    "emmet.triggerExpansionOnTab": true,
    "window.zoomLevel": 0,
    "[html]": {
        "editor.defaultFormatter": "mohd-akram.vscode-html-format"
    },
    "files.associations": {
        "*.html": "html"
    },
    "terminal.integrated.shell.windows": "C:\\Windows\\System32\\bash.exe",
　　　↑これを追加
}
```

VScode上で[Ctrl + @]でターミナルが開かれる。
ubuntuで開いた時と同じユーザ名になっていれば終了。
[SharePoint]CSOMでログインにパスワード以外を使う

## 経緯

もうすぐ全ての.NETが.NET5(旧Core)に集約されることになりますが、この.NET5にはCSOMのパスワード認証で標準的に使われている`SharePointOnlineCredentials`が使えなくなるそうです。

それ以前に、パスワードレス認証でログインしている人が困ってしまうのでそれに対応したいというのが動機です。

## .NET5以前

.NET5以前の場合は、NuGetで「SharePointPnPCoreOnline」を入れたあと、

```C#
var authenticationManager = new OfficeDevPnP.Core.AuthenticationManager();
ClientContext context = authenticationManager.GetWebLoginClientContext("<Site URL>", null);
```

で出来る様です。（.NET5以前では試してはいません）

2020/10/4現在では.NET5環境ではうまく動作しませんでした。
ビルド時に.NET5に対応していない旨の警告が出るのが関係していると思います。

## 今回行なった方法

[PnP Core](https://github.com/pnp/pnpcore)の認証ライブラリを使用した後、アクセストークンを取り出してCSOMの`ClientContext`を初期化します。

ただ、そもそもPnPにはCSOMと同様なSharePointアクセスだけでなくMicrosoftGraphも扱えるので、CSOMで実装済みの資源をなるべく修正したくない場合を除けば、CSOMをあえて使う必要は無いです。

## サンプル

サンプルは以下に置いておきます。
https://github.com/RYO-4947123/CSOM_Sample

※あらかじめAADにアプリ登録をしておく必要があります。
https://github.com/pnp/pnpcore/tree/dev/src/samples/Demo.Console

## 要点

PnP.Core.Authのヘルパーを駆使してログインを行なった後、アクセストークンを取り出します。

```C#
var accessToken =  await context.AuthenticationProvider.GetAccessTokenAsync(context.Uri);
```

その後、CSOMの`ClientContext`作成時にリクエストヘッダにトークンを加える様に初期化します。

```C#
context.ExecutingWebRequest += (sender, e) =>
{
    // Insert the access token in the request
    e.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + accessToken;
};
```

あとは今まで通り`ClientContext`を使ってSharePointにアクセスすることができます。

### ※注意点

コンソールアプリの場合、一度接続を切る（`Host.Dispose()`）と再接続しても`GetAccessTokenAsync`メソッドがデッドロックして帰ってこなくなります。

## 参考にしたサイト

[.NET Standard に対応した CSOM で注意するべき点について](https://blog.karamem0.jp/entry/2020/07/21/120000)
[.NET Framework で CSOM ではなく、.NET Standard に対して CSOM を使用する](https://docs.microsoft.com/ja-jp/sharepoint/dev/sp-add-ins/using-csom-for-dotnet-standard?WT.mc_id=M365-MVP-5002941)
[PnP Core SDK](https://github.com/pnp/pnpcore)
[独自のAzureADアプリケーションを構成したい](https://pnp.github.io/pnpcore/articles/consumer/configuring%20authentication.html)
Google Cloud Vision APIを使ってみた

## Google Cloud Visionとは
Google Cloud VisionはGoogleが提供しているが提供している画像の分析サービスです。
今回は、画像内の文章を読み込むために使ってみました。

## 手順１ Google Cloud Platformに登録する
以下のリンク先からGoogle Cloud Platformに登録しましょう。
なお、登録にはクレジットカードが必要となります。
https://console.cloud.google.com/getting-started?hl=ja

## Cloud Vision APIを有効にする
画面上部の検索窓に「Cloud Vision API」を入力ましょう。
![スクリーンショット 2020-10-02 17.34.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/9f22ead6-02a0-a9b0-118c-e4dd23da9c77.png)

遷移後の画面でCloud Vision APIを有効にすれば完了です。
![スクリーンショット 2020-10-02 17.35.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/ac0d725c-117c-301b-b9a4-06d10cdf8673.png)

## サービスアカウントの作成
サービスアカウントとは？
ここから引用→https://cloud.google.com/iam/docs/service-accounts?hl=ja

サービスアカウントは、ユーザーではなく、アプリケーションや仮想マシン（VM）インスタンスで使用される特別なアカウントです。アプリケーションはサービスアカウントを使用して、承認されたAPI呼び出しを行います。

それではサービスアカウントを作ってみましょう。
「IAMと管理」からサービスアカウントをクリック。
![スクリーンショット 2020-10-02 17.57.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/533d26a9-986e-7c76-a69a-8f910e37e030.png)

遷移後の画面で「サービスアカウントを作成」をクリックしましょう。
![スクリーンショット 2020-10-02 18.00.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/a1e00636-2bf6-2bbe-4bef-e01b375a5db3.png)

適当なサービスアカウント名を入力して「作成」をクリック
![スクリーンショット 2020-10-02 18.02.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/2584b417-6e98-5695-2ee8-77683504a599.png)

「続行」をクリック
![スクリーンショット 2020-10-02 18.08.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/8d88d625-6e35-526f-2ad8-0bd09b067f17.png)

「完了」をクリック
![スクリーンショット 2020-10-02 19.44.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/711d261c-b41e-dca5-8f95-a0e6536b0cc3.png)

続いて認証用の秘密鍵の作成です。上記の操作を行った後、以下のような画面になっていると思うので「操作」をクリックしてキーの作成を行います
![qVGSMdCDldLGqek1601635670_1601635725.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/2a8e9986-50da-033c-7718-868d0ddbe6dc.png)

ダイアログが表示されるのでJSONを選択してキーを作成します。
キーは任意のフォルダに配置し、後述の環境変数(GOOGLE_APPLICATION_CREDENTIALS)にキーのパスを指定してください。
![ti0oDmp7fe6mIxY1601636143_1601636179.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/58661cab-17df-e42a-7e21-7ac439d0a3c4.png)

gemをインストール。

```
gem 'google-cloud-vision'
```

秘密鍵のパスを環境変数に設定して、準備は完了です。

```
export GOOGLE_APPLICATION_CREDENTIALS="/hoge/fuga.json"
```

## 実装
公式のドキュメントを参考にし、以下のようになりました。
・公式ドキュメント
https://cloud.google.com/vision/docs/libraries?hl=ja#client-libraries-usage-ruby

公式の例と最も異なる点はlabel_detectionではなくtext_detectionを使用していることです。
label_detectionを使用すると、どのようなものが画像内に含まれているか検出することが出来ます。
例えば、駅内を撮った写真ですと改札や線路、券売機といった物が検出されるわけです。
今回は画像内の文字を検出したかったため、text_detectionを使用しました。

```
@image = Image.new

require "google/cloud/vision"
image_annotator = Google::Cloud::Vision.image_annotator

# 読み込む画像を指定
file_name = "~/hoge.jpg"

# file_nameを引数にしてCloud Visionで解析する
response = image_annotator.text_detection image: file_name

response.responses.each do |res|
  @image.OCR = res.text_annotations[0].description
end
```

## まとめ
Google Cloud Vision APIは、今回の例以外にもPDFファイルの分析や画像内の顔検出などにも使えます。
月に1000件の読み込みまでは無料で行えますので、色々と試して自作アプリに組み込んでみましょう！
コードレビュー時に意識するべき観点

コードレビュー時に意識するべき観点を、最下部の資料からまとめました。
自分への戒めとして、記しておきます。

## 考慮に入れるべきこと

### レビューの目的はなにか、チーム内でコンセンサスを取る

-  「コードレビューが完了したときに、どういう状態になっていれば成功なのか」を意識する。
- 指摘を受けて修正する場合、優先順位を検討する。
  - 自分の指摘にはどれくらい実現可能性があるか
  - 指摘を反映した場合に、プロジェクト全体にどんなメリットがもたらされるか
- ソースコードの基本は、「将来的に必要になる修正・対応コストを削減する」こと。
- メンバー同士の知識がチームに共有されることで、技術レベルが向上する

### 「どんな勉強をすれば、コードレビューで受けた指摘を改善しやすくなるか」もセットで教える

初学者は、どういう勉強をすればいいかそもそもわからない場合があるので、学習方法についても案内する。
また、パブリックな場で教えることで、知識を共有し合う文化の形成につながる。

### ソースコードのいい部分には「いいね！」という

良いコードやいい指摘を目にしたら、積極的に「いいね」とコメントする。
フィードバックとは、悪い部分を改善するためだけではなく、いい部分を伸ばすためにでもある。

### 「最悪を最初に」

影響範囲が広い、手戻りコストが高くつく、失敗するようなリスクがないか確認する。

残りを適切な順序でみる。


## 資料

- コードレビューを成功させるためにCTOが考えるべき7つのことー監修：高遠和也（株式会社LIG CTO） | FLEXY（フレキシー）
https://flxy.jp/article/4298

- コードレビューのイロハをまとめました（レビュイー/レビュアー両者の心得や実践的なテクニックなど） - Qiita
https://qiita.com/hariNEzuMI928/items/5e3d96a069e075e37720
SAP ABAPのエディターの設定

SAP GUIをインストールしてから、プログラムを開発・照会する前、通常にエディターの設定を行う必要があります。常用設定をメモします。まずはT-Code: SE38でエディターを起動してください。
#新旧エディター切り替え
メニュー：「ユーティリティ」=>「設定」　タブ：[ABAP Editor]
![SE38_ABAP_EDITOR_SETTING_01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/760424/5e5be7ca-3aed-cf33-16ac-8d0a15ea21b9.jpeg)

![SE38_ABAP_EDITOR_SETTING_02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/760424/0b7b0f9d-5d60-3910-fce3-1ce22281a689.jpeg)

#キーワードと変数、名称などの大文字・小文字表示方法
![SE38_ABAP_EDITOR_SETTING_03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/760424/31976144-7a5c-6702-55f7-4dc4a5843f96.jpeg)

#エディターの行番号を表示する
エディターの右下
![SE38_ABAP_EDITOR_SETTING_04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/760424/350e02d4-b238-75f3-5c4a-306e4fe7f3bd.jpeg)
![SE38_ABAP_EDITOR_SETTING_05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/760424/86ba4740-af62-8ab9-2368-3c871160d1e1.jpeg)

#フォント変更（コメントに漢字・英文字が混在した場合も整列表示するため）
![SE38_ABAP_EDITOR_SETTING_06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/760424/8a69fbbf-d7a2-1a60-f159-eff671568ada.jpeg)

#その他の設定（GUIのオプション）
例：ドロップダウンリストにキーを表示
![SE38_ABAP_EDITOR_SETTING_07.jp
g](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/760424/6b8b38e9-46b3-dcdb-9441-8de016bfe0b4.jpeg)
【複数のグラフを描画とラベル】plotlyで動的な可視化をする【python3,make subplot, xlabel, ylabel】




python==3.8
plotly==4.10.0


plotlyの設定てきなもので
よく使うものを追加していくつもり


#図面を割り振る(subplot)


```python
from plotly.subplots import make_subplots
import plotly.graph_objects as go

fig = make_subplots(rows=1, cols=2)
fig.add_trace(go.Scatter(y=[4, 2, 1], mode="lines"), row=1, col=1)
fig.add_trace(go.Bar(y=[2, 1, 3]), row=1, col=2)
fig.show()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/5358faf4-80ce-ec01-c2bd-99fc9456bebe.png)



#背景色

```python
from plotly.subplots import make_subplots
import plotly.graph_objects as go

fig = make_subplots(rows=1, cols=2)
fig.add_trace(go.Scatter(y=[4, 2, 1], mode="lines"), row=1, col=1)
fig.add_trace(go.Bar(y=[2, 1, 3]), row=1, col=2)

fig.update_layout(
    margin=dict(l=20, r=20, t=20, b=20),
    paper_bgcolor="LightSteelBlue",
)

fig.show()
```



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/8b46ae5f-308e-a3f8-e900-b764599352ff.png)




##x,yラベルのタイトル


```python
from plotly.subplots import make_subplots
import plotly.graph_objects as go

fig = make_subplots(rows=1, cols=2)
fig.add_trace(go.Scatter(y=[4, 2, 1], mode="lines"), row=1, col=1)
fig.add_trace(go.Bar(y=[2, 1, 3]), row=1, col=2)

fig.update_layout(
    margin=dict(l=20, r=20, t=20, b=20),
    paper_bgcolor="LightSteelBlue",
)


fig.update_xaxes(title_text="xlabel")
fig.update_yaxes(title_text="ylabel", hoverformat=".3f")

fig.show()
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/6c7b0090-65d8-9649-313e-cd7aa6998d61.png)



#特殊なplotの割り振り

barやscattorはmake_subplotsのままで指定できるが、
pieやscatter3Dはこのままでは指定できない
make_subplotsに何を指定したいかを指示しておく

##specsで指定


```python
from plotly.subplots import make_subplots
import plotly.graph_objects as go

fig = make_subplots(
    rows=2, cols=2,
    specs=[[{"type": "bar"}, {"type": "barpolar"}],
           [{"type": "pie"}, {"type": "scatter3d"}]],
)

fig.add_trace(go.Bar(y=[2, 3, 1]),row=1, col=1)
fig.add_trace(go.Barpolar(theta=[0, 45, 90], r=[2, 3, 1]),row=1, col=2)
fig.add_trace(go.Pie(values=[2, 3, 1]),row=2, col=1)
fig.add_trace(go.Scatter3d(x=[2, 3, 1], y=[0, 0, 0], z=[0.5, 1, 2], mode="lines"),row=2, col=2)

fig.update_layout(height=700, showlegend=False)

fig.show()
```




![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/db57bc5c-bae9-eb18-ce82-fd4b1136dfdb.png)




#以上

追記記録

2020-09-27 作成
Dokcer環境等で発生するSelenium::WebDriver::Error::UnknownErrorの対処法

Dokcer環境などのCUI環境でcapybara/selenium/chromedriverを利用する際は `no-sandbox/disable-dev-shm-usage`オプションが必要

```shell
Selenium::WebDriver::Error::UnknownError:
                unknown error: Chrome failed to start: exited abnormally.
                  (unknown error: DevToolsActivePort file doesn't exist)
                  (The process started from chrome location /usr/bin/google-chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.)
```

```capybara.rb
...
Capybara.register_driver :selenium_chrome_headless do |app|
  options = ::Selenium::WebDriver::Chrome::Options.new
  options.add_argument('--headless') 
  options.add_argument('--no-sandbox') # chrootで隔離された環境(Sandbox)での動作を無効
  options.add_argument('--disable-dev-shm-usage') # 共有メモリファイルの場所を/dev/shmから/tmpに移動
  options.add_argument('--disable-gpu')
  options.add_argument('--window-size=2500,2500')
  Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
end

Capybara.javascript_driver = :selenium_chrome_headless
```
Lorenz96をJuliaで解く　その２

# 前回まで
https://qiita.com/ishigaki/items/a61be370961eee36d297

ではグローバル変数を使ったJuliaのコードを書いて，実行時間0.7s程度でした。

今回はグローバル変数を使わないように，引数渡しでパラメータ設定するコードにしました。

# 計算時間
結果からいうと，40ms程度まで早くになりました。Fortranで計算したのと同程度の速さになりました。

# コード
前回との違いは，F, N, dt, nstepをmain関数で定義して，引数で渡してるだけです。内容的には同じ計算です。

引数をそのまま書いたのでかっこわるいです。黒木さんのコードはparameter使って，かっこいいかんじになってます。https://gist.github.com/genkuroki/f0426a7f3772c804ace0e6875445ea49

```julia
function main()
    ##パラメータ
    ##Fの大きさで挙動が変わる
    F = 8
    N = 40
    dt = 0.01
    tend = 146
    nstep = Int64(tend/dt)

    xn, t =  progress(dt, F, N, nstep)
    
end

# dx/dt=f(x) 
# Lorentz96の方程式
function f(x, F, N)
    g = fill(0.0, N)
    for i=3:N-1
        g[i] = (x[i+1]-x[i-2])x[i-1] - x[i] + F
    end
    
    # 周期境界
    g[1] = (x[2]-x[N-1])x[N] - x[1] + F
    g[2] = (x[3]-x[N])x[1] - x[2] + F
    g[N] = (x[1]-x[N-2])x[N-1] - x[N] + F
    
    return g
end

# L96をRK4で解く
function RK4(xold, dt, F, N)
    k1 = f(xold, F, N)
    k2 = f(xold + k1*dt/2., F, N)
    k3 = f(xold + k2*dt/2., F, N)
    k4 = f(xold + k3*dt, F, N)
    
    xnew = xold + dt/6.0*(k1 + 2.0k2 + 2.0k3 + k4)
end

# 真値を全ステップ計算
function progress(deltat, F, N, nstep)
    xn = zeros(Float64, N, nstep)
    t = zeros(Float64, nstep)
    
    #X = fill(F,N)+randn(N)
    X = fill(Float64(F), N)
    # 初期擾乱はj=20の点にFの値の0.1%の値を与える。
    X[20] = 1.001*F
    
    for j=1:nstep
        X = RK4(X, deltat, F, N)
        for i=1:N
            xn[i, j] = X[i]
        end
        t[j] = deltat*j
    end
    
    return xn, t
end
```
ObjectをInstantiateするときに親Objectを指定する

ObjectをInstantiateするときに親Objectを指定することで、親オブジェクトにつけたアニメーションと同じ動きを、新たに生成した子Objectにもつけることができます。

第四引数に親オブジェクトを指定することで、新たに生成するオブジェクトを子オブジェクトとして生成できます。

Instantiate(生成したいオブジェクト, transform, rote,親オブジェクト);

<注意>
親オブジェクトを宣言するときは
 public GameObject 親オブジェクト;   ではなく
 public Transform 親オブジェクト;　　になります。

<参考>
https://qiita.com/A-Kouki/items/9b79e6eb7e78d93af8c7
[K8s] マニフェストからポッドを起動

## 概要

本投稿はminikubeを使用し、マニフェストからポッドのみを起動させる内容をまとめた個人メモです。
本番運用ではポッドのみを起動させることはないので要注意。

## マニフェストについて

`マニフェスト`とは、K8sのオブジェクトを生成するために、そのオブジェクトに対応するAPIバージョン、メタ情報、使用などをyamlやjsonで定義したファイルのことです。
今回はポッドのみを起動させる最小単位でオブジェクトの生成を行います。

### マニフェストの適応

今回使用するマニフェストは以下の通りです。
ポッドで動かすコンテナとして`nginx`の最新バージョンを使用します。

```yml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
```

マニフェスト定義後、以下コマンドを使用しデプロイを行います。

```
$ kubectl apply -f nginx-pod.yml
pod/nginx created
```

以下コマンドで状態を確認します。

```
$ kubectl get pod nginx -o wide
NAME      READY     STATUS    RESTARTS   AGE       IP           NODE       NOMINATED NODE
nginx     1/1       Running   0          2m        172.17.0.4   minikube   <none>
```

### ポッドの疎通確認

表示されているIPアドレスはクラスタネットワークのノード間でのみ通信可能な内部のIPのため、ホストからアクセスすることはできません。

```
$ curl 172.17.0.4
curl: (7) Failed to connect to 172.17.0.4 port 80: Network is unreachable
```

ポッド間の通信を確認するため、`busybox`コンテナを立ち上げ疎通確認を行います。
nginxに正常にアクセスできることが確認できます。

```
$ kubectl run busybox --image=busybox --restart=Never --rm -it sh
If you don't see a command prompt, try pressing enter.
/ # wget 172.17.0.4
Connecting to 172.17.0.4 (172.17.0.4:80)
saving to 'index.html'
index.html           100% |*****************************************************************************************************************************|   612  0:00:00 ETA
'index.html' saved
/ #
```

```
$ kubectl get pod -o wide
NAME      READY     STATUS    RESTARTS   AGE       IP           NODE       NOMINATED NODE
busybox   1/1       Running   0          1m        172.17.0.5   minikube   <none>
nginx     1/1       Running   0          15m       172.17.0.4   minikube   <none>
```

マニフェストで作成した環境は`delete`を使用し削除してください。

```
$ kubectl delete -f nginx-pod.yml
```

---
以上
iosのinputやselectタグなどで画面が拡大されるのを防ぐ

# 課題
iosで input,select,textareaなどの要素をクリックすると下の画像のように拡大表示されてしまう
![IMG_3112.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223280/3df12996-dd6e-3b73-9a62-2dd770c745f4.jpeg)

## 解決方法
それぞれのタグに下記のcssを追加する

```
input, select, textarea {
 font-size: initial !important;
}
```

## 結果
![IMG_3113.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223280/e36c4fa0-361e-777b-3747-3909313e8753.jpeg)

iosではフォントサイズが16px以下のinputやselectタグをクリックすると拡大されてしまう仕様があるため、こちらでフォントサイズを初期化するよう明示してあげます

お疲れ様でした！
FreeRTOS を Raspberry Pi 4B へ移植する

# はじめに

Unikernelを組込みシステムへいい具合に統合してやろうと思ったらRTOSとLinuxが同時に動く機材が必要となったので、タイトルの通り移植してみました。

Raspberry Pi向けのポーティングだとFreeRTOS単独起動構成が多い気がしていますが、今回のFreeRTOSはu-bootからキックさせた後にLinuxと同時起動出来るようにしています。

既にRTOSとLinuxが同時に動く実装が存在するi.MX8MやZynqMP SoCなどを持ってくればとても簡単なのですが、ラズパイにしておけばお金の節約と知識習得に繋がるはずなのです。

# リポジトリ

[ここ](https://github.com/TImada/raspi4_freertos)にあります。ビルドや使い方は`README.md`を参照してください。

ベースの実装は[@eggman](https://qiita.com/eggman)さんのRaspberry Pi 3向け[FreeRTOS](https://qiita.com/eggman/items/2b6eb18b297673bab6c0)です。先人のご尽力に感謝ですm(_ _)m。

# 移植について

### ベースの実装から変えたところ

1. 「u-bootからの起動」および「Linuxとの同時起動」を前提にしているため、EL2からスタートアップルーチンが動くように変更
2.  FreeRTOSのバイナリがCPUコア#3で動作するように変更 (CPUコア#0-2はLinux用)
3.  Raspberry Pi 4Bでは割込みコントローラとしてGICを使えるようになったので、それを使うように変更
4.  UARTはUART2(by PL011)を使用するように変更 (UART1はLinux用)
5.  Linuxと同時起動できるように、LinuxによるGIC構成変更に上手く対処するためのルーチンを追加
6.  MMUを有効化 (ただし仮想アドレス=物理アドレス、2MBページサイズ)
7.  FreeRTOS kernelのバージョンをv10.3.0にアップデート

### 実装tips

#### CPUコア#3でのバイナリキック

[Raspberry Piのstubコード解説記事](https://leiradel.github.io/2019/01/20/Raspberry-Pi-Stubs.html)に詳しく書いてある通り、0xD8 - 0xF7までのメモリ領域は8byte毎に`spin_cpuX : X=0,1,2,3`とラベルがつけられていています。CPUコア#3でバイナリをキックさせたければ、`spin_cpu3 (=アドレス0xF0)`にリセットハンドラの先頭アドレスを書き込んでSEV命令を発行すればCPUコア#3が適切に動き出します。

今回のポーティングではアドレス0xF0へのリセットハンドラアドレス書き込みをu-bootの`mw`コマンドにお任せしたのですが、同コマンドをCPUコア#0で実行するとその書き込み結果がキャッシュに留まって物理メモリに反映されないという事態が起こりました(アレェェ...)。CPUコア#3はアドレス0xF0の値を見てプログラムカウンタを設定しますが、物理メモリに値が反映されていないとアドレス0xF0の値は0x0のままとなります。このとき、CPUコア#3は`WFE`命令を発効してお昼寝するようにstubコードが実装されています。

この問題を解消しようとするとu-bootの`dcache flush`コマンドを利用できればいいのですが、Raspberry Pi 4B向けUbuntu 20.04 LTSに収録されているu-bootには同コマンドがなかったのでu-bootを再コンパイルする羽目に...。

#### Linuxとの同時起動

u-bootプロンプトからFreeRTOSサンプルをキックさせた後にLinuxをキックさせると、LinuxがGICをLinux用に設定してくるので先にFreeRTOSで設定したGIC構成がオーバーライトされてしまいます(特に問題なのがLinuxによるGIC Distributor設定の書き換えでした)。そうなってしまうと、tick用タイマとUARTの割込みが入ってこなくなってしまいます。

なので今回はLinuxがGICのDistributor設定を終えるタイミングを検知するための機構をFreeRTOS側に実装し、LinuxがGIC設定を終えた後にFreeRTOSが改めてGIC設定し直すようにしました。[検知機構](https://github.com/TImada/raspi4_freertos/blob/master/FreeRTOS/Demo/CORTEX_A72_64-bit_Raspberrypi4/uart/src/interrupt.c#L71)はビジーループx2という地球に優しくない処理なので、そのうち方法を見直さなければなりません。

#### MMU有効化

[remoteproc/rpmsg](https://github.com/OpenAMP/open-amp)の移植をしていたら、MMUが有効になっていないと使えない排他アクセス命令を使うコードになっていたので泣く泣くMMU周りのコードを書く羽目に...。ということで、ベースとなるUARTサンプルにまず適用。

めんどいので「仮想アドレス=物理アドレス」なアドレス無変換のページテーブルを作成するように実装。2-levelのページテーブルで、1st levelが1GBブロックサイズ、2nd levelが2MBページサイズです。

#### UART2(PL011)用のコード実装

勘のよい方は既に気付いているかと思います。実はUART1(mini UART)をFreeRTOS側で利用するようにすれば、UART1は既にベース実装にあったのでわざわざUART2の箇所を実装する必要は無いのです。

ええ、もちろん知っていましたがあえてやりました。ニッコリ。

# 次のマイルストーン

LinuxとFreeRTOSが通信できるように、[remoteproc/rpmsg](https://github.com/OpenAMP/open-amp)を移植。
【C#】enumのシリアライズをカッコよくしたい!


# はじめに

C#の`System.Xml.Serialization.XmlSerializer`を使って列挙型のシリアライズを行うと，識別子の名前がそのまま出力されてしまっていい感じ(?)ではありません。
そこで，列挙型をシリアライズしたときに出力される文字列をカスタマイズできるようにしてみました。

# コード

```CSharp

using System;
using System.Reflection;
using System.Xml.Serialization;

namespace Qiita
{
  // 列挙体に任意の文字列を割り当てるための属性
  public class CustomTextAttribute : Attrubute
  {
    public string StringValue { get; protected set; }

    public CustomTextAttribute(string value)
    {
      this.StringValue = value;
    }
  }

  // 列挙体
  public enum Wochentage
  {
    [CustomText("mo")]
    Montag,

    [CustomText("di")]
    Dienstag,

    [CustomText("mi")]
    Mittwoch,

    [CustomText("do")]
    Donnerstag,

    [CustomText("fr")]
    Freitag,

    [CustomText("sa")]
    Samstag,

    [CustomText("so")]
    Sonntag
  }

  // シリアライズのためのラッパー
  [Serializable]
  public class EnumWrapper<T> where T : Enum
  {
    protected T value;

    [XmlText]
    public string Value
    {
      get
      {
        // リフレクションで属性を取得
        var type = this.value.GetType();
        var fieldInfo = type.GetField(this.value.ToString());
        if (fieldInfo == null) return this.value.ToString();

        var attrs = fieldInfo.GetCustomAttributes<CustomTextAttribute>() as CustomTextAttribute[];
        return attrs.Length > 0 ? attrs[0].StringValue : this.value.ToString();
      } // get
      set
      {
        // 効率的な方法がわからなかったので強引に頑張る
        foreach (T val in Enum.GetValues(typeof(T)))
        {
          if (val.ToString<CustomTextAttribute>() == value)
            this.value = val;
            return;
        }
      } // set
    }

    public EnumWrapper() { }

    public EnumWrapper(T val)
    {
      this.value = val;
    }

    // 列挙体との暗黙の型変換を定義
    public static implicit operator EnumWrapper<T>(T val)
      => new EnumWrapper<T>(val);

    public static implicit operator T(EnumWrapper<T> val)
      => val.value;
  } // public class EnumWrapper<T> where T : Enum
} // namespace Qiita

```

## 使い方

シリアライズする型の中の列挙体(`Wochentage`とします)の型を`EnumWrapper<Wochentage>`に変更するだけで，`CustomText`属性で指定した値を使用してシリアライズされるようになります。
変更前の型(`Wochentage`)と暗黙的に変換できるため，その他のコードに変更を加える必要はありません。

# その他

今回はプロパティの中でゴリゴリ書きましたが，`CustomTextAttribute`に相当するようなクラスを複数作り，拡張メソッド`ToString<T>`を定義してあげて文字列に変換する，と言ったこともできます(UIに表示する用とか)。

# 参考文献

- [C# > enumに文字列を割り当てる。](https://qiita.com/sugasaki/items/ea5eec093ad7934abd5c)
AzureADでDeviceCodeFlow

# 概要

- AzureADでDeviceCodeFlowを使った認証をします。
- RedirectURIを用いない認証が可能です

# アプリの登録

- まず実験用のアプリを登録します
- Azure Portalに入る  
  https://portal.azure.com/
- AzureActiveDirectoryを選ぶ
- アプリの登録を選ぶ
- 新規登録を選ぶ
- 名前は適当、アカウントの種類は「マルチテナント+個人アカウント」
- リダイレクトURIは省略（後で設定する）

# アプリの設定

- 認証を開く
- プラットフォームを追加
- 「モバイルアプリとデスクトップアプリ」を選ぶ
- 「https://login.microsoftonline.com/common/oauth2/nativeclient 」にチェックを入れて「構成」を押す
- 「既定のクライアントの種類」で「はい」を選ぶ
- 最後に「保存」を押す
- 概要ページに移動して「アプリケーション (クライアント) ID」をメモっておく

# Tokenの取得

- curlでTokenを取得します。

```text
$ curl -X POST -d 'client_id=クライアントID&scope=user.read%20openid%20profile%20offline_access' https://login.microsoftonline.com/common/oauth2/v2.0/devicecode
```

- レスポンスが表示されたら、verification_uri、user_code、device_codeをメモっておく
- verification_uriをブラウザで開いて、user_codeを入力する
- 入力しおわったら、トークンを取得する

```text
curl -X POST -d 'client_id=クライアントID&grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=デバイスコード' https://login.microsoftonline.com/common/oauth2/v2.0/token
```

- これでaccess_token, id_token, refresh_tokenが取得できているはずです

# 自分のプロファイルの取得

- GraphAPIで自分のプロファイルを読んでみます

```text
$ curl -H "Authorization: Bearer アクセストークン" https://graph.microsoft.com/v1.0/me
```

# 参考URL

- [RFC 8628 - OAuth 2.0 Device Authorization Grant](https://tools.ietf.org/html/rfc8628)
    - [上記の日本語訳](https://tex2e.github.io/rfc-translater/html/rfc8628.html)
- [図解デバイスフロー（RFC 8628）](https://qiita.com/TakahikoKawasaki/items/78eff94cef92741131f0)
- [Azure公式 Microsoft identity platform and the OAuth 2.0 device authorization grant flow](https://docs.microsoft.com/ja-jp/azure/active-directory/develop/v2-oauth2-device-code)
- [.Net用のAzure AD Device Code Flowサンプル](https://github.com/Azure-Samples/active-directory-dotnetcore-devicecodeflow-v2)
- [Java用のAzure AD Device Code Flowサンプル](https://github.com/Azure-Samples/ms-identity-java-devicecodeflow)
- [Python用のAzure AD Device Code Flowサンプル](https://github.com/Azure-Samples/ms-identity-python-devicecodeflow)
document.formsが便利だった

# はじめに
久しぶりにフレームワークを使わずにJavaScriptを扱いました。
その際、formの内容を操作をするのに**document.forms**を利用しました。
忘れない内にまとめておきます。

# document.formsとは
HTML文書内に含まれる全てのformのHTMLCollectionを返します。
読み取り専用です。

# 便利な事
* 記述が短くてすみます。
* `document.forms`なので、何を表しているのか直感でわかります。
* `document.forms`の`elements`プロパティはフォームコントロールのみにアクセスできます。
  この為、他の要素の事を気にせずに（例：要素を判定）、フォームの操作のみ書くことができます。

読む側にとっては、何を検索しているのかをすぐに把握できる事がメリットだと思います。
また、書く側にとっても直感的に書けるのではないでしょうか。

# 使い方
下記でアクセスできます。

```HTML
<!--対象のform-->
<form action="hoge" name="hoge" id="hoge1">
```
```javascript
console.info(document.forms['myform'])
console.info(document.forms['hoge'])

// .でもアクセスできます。
```

# 注意
## 配列ではないです
`document.forms`が返すのは`HTMLCollection`で、配列ではありません。
なので、`forEach`などはこのままでは使えません。
特に、操作したいコントロールが大量にある場合は、`Array.from()`などで配列にするのが手っ取り早いと思います。

＊アクセスしたいものが1つ2つであれば、`namedItem()`の方が便利だと思います。

## 特定formの存在をチェックしたい場合
特定のformが取得できているかどうかは、返り値が`undefined`かを判定すれば対応できます。

```javascript
document.forms['myform'] === undefined
```

# サンプル
フォームのチェックボックスを一括でチェックしたり外したりするものです。

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="js,result" data-user="H_Naito" data-slug-hash="WNwVJRE" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Form manipulation">
  <span>See the Pen <a href="https://codepen.io/H_Naito/pen/WNwVJRE">
  Form manipulation</a> by H.N (<a href="https://codepen.io/H_Naito">@H_Naito</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

# 参考
[Document.forms](https://developer.mozilla.org/ja/docs/Web/API/Document/forms)
[HTMLFormElement.elements](https://developer.mozilla.org/ja/docs/Web/API/HTMLFormElement/elements)
[HTMLCollection](https://developer.mozilla.org/ja/docs/Web/API/HTMLCollection)
[2.7.2.2 The HTMLFormControlsCollection interface](https://dom.spec.whatwg.org/#interface-htmlcollection)