OmniAICreator/Qiita-1.07M huggingface dataset:
サブのMacでDiscordの音声収録をする

サブのMacとサブアカウントでDiscord にログインし、音声収録をする設定のメモです。
録音直前にうまくいかなくて慌てる日々に。

####ご注意：この手法で収録をしたら温泉エコー状態になりました。失敗！

① サブのMacにBlackhole 16chを導入する

② サブのMacの「システム環境設定」→「サウンド」で
	・出力：「Blackhole 16ch」を選択
	・入力：「Blackhole 16ch」を選択

③ サブのMacとサブアカウントで収録したいDiscordのチャンネルにログインする

④ サブのMacのDiscordアプリの左下の歯車マークに入り「Voice&Video」を開く。
	・INPUT DEVICE ：「Built-in Line Input」等を選択（基本的にマイクは無効にする）
	・OUTPUT DEVICE：「Blackhole 16ch」を選択

⑤ サブのMacのDiscordアプリの左下のアイコンにて以下に設定する。
	・マイク：オフ
	・ヘッドフォン；オン

⑥ サブのMacのQuickTimeにて「ファイル」→「新規オーディオ収録」を選択
	・オーディオ収録のウィンドウの設定ボタン（赤いボタンの隣のv印）をクリックし、
		・「Blackhole16ch: Blackhole16ch」を選択

⑦ Discordからの音声がおり設定がうまくできていれば、この時点でQuickTimeのレベルメーターに反応が出る。

⑧ QuickTimeの収録ボタンを押す。

⑨ メインアカウントでDiscordの会話を開始する。

⑩ QuickTimeの収録を停止する。ファイルはパネルを閉じる際に保存されるので注意。
省略形だとfind_elementできないXpathをfindしたい(Selenium)

Seleniumにおいて、idなどがない要素を選ぶ時、Xpathを使うことが多いと思います。
Xpathは省略しない絶対パス(/html/body/div[2]/div[2]/...とつらつら書いてく書き方)で書けば、一意的に要素を指定できますが、[推奨されていません](https://kurozumi.github.io/selenium-python/locating-elements.html)(web製作者が少しでも階層の変更をしてしまうと、機能しなくなるためだそうです。)

classやnameなど、複数の属性の組合せで要素を特定できればいいのですが、例えば[Googleトレンド](https://trends.google.co.jp/trends/explore?q=%E3%81%AD%E3%81%93&geo=JP)のcsvダウンロードボタンのように、**class属性しかなく、かつ同名のclassが何回も使われているような要素はどうやって省略形のXpathで指定すればいいんだろう**と迷ったのでメモしておきます。

```HTML:GoogleトレンドのCSVダウンロードボタンの要素
<i class="material-icons-extended gray">file_download</i>
<!-- "material-icons-extended gray"というクラスはこの後も何回も使われています。-->
```
こういうときは、find_element_by_xpathではなく、find_element”s”_by_xpath
というように、一旦全ての要素をリストで取得します(↓pythonのコード)。

```python:Seleniumで要素を取得するコード。find_element_by_xpathではなく、find_element"s"_by_xpath
dl_button=driver.find_elements_by_xpath('//i[@class="material-icons-extended gray"]') 
```
そのあと、リストから番号を指定して、欲しい要素を取り出せばOK。

```python
dl_button[6].click()
```
この例の"6"という数字はどうわかったかといいますと、次の画像にまとめています。

![配列番号の確認：スクリーンショット 2021-07-09 12.40.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1605263/68852e27-8ba1-215a-8a35-c83104adb9ab.png)

リスト(配列)は0スタートなので、コマンドFで調べた「出現順番」から-1することを忘れずに。
様々なタイムトラッキングツールを実際に使って比較した結果、Toggl Trackが最高！となった話

# TL;DR
「どうも、効率的な仕事ぶり、充実した私生活。キャリアウーマンです。」ではなく、エンジニアです。
効率的な仕事をするに当たって、自分が何にどれだけ時間を使っているのかを把握することは重要です。
この記事では、3つのツールを実際に使ってみて、**Toggl Trackが最高だよ**ということをお伝えします。

# 前提
工数管理はプロジェクトを成功させる重要な要素です。工数見積もりの精度を上げるためには、そのタスクがどれぐらいの工数で実現できるのかを把握する必要があります。タイムトラッキングツールを活用して、実際に自分がどれぐらいの時間でタスクを完了できるかを可視化したいとなったのがきっかけです。
また進捗が悪いと感じた際に、想定以上の時間がかかっているのか、それとも他のタスクが時間を圧迫しているのかを確認することで改善策を考えることができます。

そこで、以下のポイントを意識してツールを試しました。

1. **作業をしながら、簡単な操作でタイムトラッキングができる（＝デスクトップアプリ、ブラウザの拡張機能）**
1. **後から振り返りができる（＝1日単位、タスク単位での集計が可能）**
1. **デバイスを切り替えながら利用できる（＝デバイス間同期）**
1. **（長く使い続けるものだから無料だと嬉しい）**

# 比較結果
||***[Toggl Track](https://toggl.com/track/)***  |[Focus To-Do](https://www.focustodo.cn/)  |[TimeCrowd](https://timecrowd.net/) |
|---|---|---|---|
|利点|- トラッキング忘れをリマインドしてくれる　<br> - 様々な切り口で分析ができる <br> - UIがかっこいい <br> - ブラウザの拡張機能サクサク <br> - デスクトップアプリ、拡張機能、モバイルアプリなど多様　<br> - 時給を決めておけば稼働時間を金額に換算できる <br> - PCの操作を詳細に記録する機能もある <br> - 作業レポートをメールで送ってくれる |- ポモドーロツールなのでそれらの機能が充実（通知音の自由度が高い、ポモドーロ中にホワイトノイズを流せる） <br>- デスクトップアプリ、拡張機能、モバイルアプリなど多様  |- 拡張機能、モバイルアプリが使える　<br> - 時給を決めておけば稼働時間を金額に換算できる  <br> - 作業レポートをメールで送ってくれる  |
|欠点|- ポモドーロの機能が少し弱い（自動でタイマーが起動しないなど）  |- 無料版では同期機能が使いにくい <br> - （無料版が原因かもしれませんが）データ同期の際に一部のデータが欠落 |- タスクごとの集計が2週間しか遡れない（機能追加の要望を送っておきました）<br> - ブラウザの拡張機能が致命的に遅い  |
|まとめ|最高！  |ポモドーロの開始と終了で音を変えられたり、タスク中にホワイトノイズを流せるのがとても良いです。  |拡張機能で導入しやすく、レポートのメールなどが見やすいです。  |

今回はタイムトラッキングという切り口ですので、Toggl Trackを全面的に押し出しています。しかし、ポモドーロテクニックのツールとしてはFocus To-Doもかなり使いやすかったです。

# 経緯
試した順番や、その際に感じたことをまとめます。

1. [Focus To-Do](https://www.focustodo.cn/) を3ヶ月程度使っていました。しかしデバイス間同期の際に、データが欠落してしまうことを発見し乗り換えを決意。
1. 運営会社が日本で、拡張機能で使えるという手頃さから[TimeCrowd](https://timecrowd.net/)を試しに使ってみる。1ヶ月程度利用する中で、前述のタスクごとの時間の集計が見れないことに気づき再度乗り換えを決意。（今から考えると、拡張機能の致命的な遅さにも不満が募っていたのかも）
1. 様々なツールを探すもこれというものを見つけられず、モバイルアプリで妥協しかけていました。（PCで作業するに当たって、スマホでの操作はかなり面倒だと考えていたので）しかしそのタイミングで[Toggl Track](https://toggl.com/track/)を見つけ、2週間程度利用し現在に至ります。無料試用期間は1ヶ月ですが、その後も個人利用では問題ないレベルで無料で継続して利用できそうなので使っています。~~（もし、かなり機能が制限されるなら追記してお知らせします。）~~→問題なく、使い続けています！

# Toggl Trackの便利なポイントを紹介
- Timer
    - リストビューとカレンダビューが選べる
    - 週間のカレンダービューが参照できるので、日ごとの比較や週間の大枠を把握するのに便利
- Reports
    - タスクのプロジェクトやタグ、Billableかどうかなど様々な切り口での統計情報を確認できる
- Insights
    - 上記に基づいて、1週間における曜日ごとの傾向などを把握できる

https://toggl.com/track/features/ 

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">こちらのタイムトラッキングツールがめちゃめちゃオススメなので、ご紹介いたします！<br><br>Toggl Track Explainer Video <a href="https://t.co/pJPKs5TxMW">https://t.co/pJPKs5TxMW</a> <a href="https://twitter.com/YouTube?ref_src=twsrc%5Etfw">@YouTube</a>より</p>&mdash; 一昨日まで、知らなかった。 (@i_kinopee) <a href="https://twitter.com/i_kinopee/status/1413342445572562954?ref_src=twsrc%5Etfw">July 9, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 感想
結構色々と探したのですが、Toggl Trackを見つけるまでに時間がかかりました。最高なツールなので、少しでも多くの方に知っていただきたいなと思い、今回の記事を作成しました。

今回比較をする中で気づいたことなのですが、UIやパフォーマンスってUXや印象に大きく関わってくるということです。（当然ですが）
また、そもそもUIが今風でないものは試用するまでもなく比較対象から外しました。結構印象って大切だよなということも実感しました。
今回おすすめしたToggl Trackを運営会社はエストニアにあるようですが、こうした優れた日本製のツールを見つけられなかったのは残念だなと思いました。
この記事を書くに当たって[調べてみた](https://toggl.com/jobs/)のですが、フルリモートで働きやすそうな環境でした。興味ある方はぜひ！（誰）
hubspotブログ


## ブログは何個も作成することが可能
例：ニュースブログ
例：事例ブログ
例：テックブログ

## 適応テンプレート
ブログ毎にテンプレートを変更することができる。
個別のテンプレートを適応可能。
ただし同一ブログの記事ごとではテンプレートを変えることができない。

例：ニュースブログ　記事A　（テンプレート：A）
例：ニュースブログ　記事B　（テンプレート：A）
例：事例ブログ　（テンプレート：B）
例：テックブログ　（テンプレート：C）

## コンテンツの追加方法
2021.7.9 現在では個別に作ったモジュールをドラッグ・アンド・ドロップで追加することはできない。テンプレート内にモジュールを組み込んでおくか、リッチテキストで入力するしかない。
生産現場IoTへの挑戦 #06.5　～QIコネクタ　2 x 20pinソケットの威力～

#1.はじめに

<img width="500" alt="2x20pin.JPG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496179/4df83c72-338e-288b-0e5a-1a4cf0166f01.jpeg">
生産現場IoTへの挑戦ではRaspberry Pi 4Bを使っています。使えば使うほど、RPiの便利さを痛感しますが、その便利さを支える要因は大きく2点、様々なOSSやライブラリが公開されている点と、多くのGPIOを持ち多様なphysicalへのインターフェイスを持っている点かと思います。

カッコつけた言い方をしましたが、GPIOを通じてセンサーやアクチュエーター、ディスプレイ、他端末との通信など多岐にわたる機能を追加でき、それらを制御するアプリやライブラリも簡単に手に入るということですね。

RPiを使いこなすには、ソフト、ハードの両面の知識が必要ともいえる訳ですが、今回はハード面の最大の特徴である、GPIOを便利に使う2x20PinのQIコネクタハウジングを紹介します。


#2.閑話休題

「作りたいものがある」から作るのか、はたまた「作ることができる」から作るのか。。。
なぜ山を登るのか問われて「そこにあるから」と答えたのはジョージ・マロリーですが、私がRPiで工作するのは、まさに「こうすれば実現できる」と思えるから作ってみたくなるパターンが多いように思います。
という訳で？、私物3台、仕事用4台のRPiを使っていろいろな動作をさせて遊んでいるのですが、面倒なのが環境の組み換えです。
ソフト面はdockerを使うと簡単に環境構築及び切り替えができるそうですが、まだ使い方を習熟していないのでプロジェクトごとにmicroSDを焼いて、入れ替えながらつかっています。
一方ハード面もブレッドボードやユニバーサル基板でテスト回路を作っているのですが、GPIOを接続しなおすのが面倒だったりします。
面倒なだけならいいのですが、ピンの位置を間違えて動作せず、ピン間違いに気づかずにコードのエラーを探したりモジュールの再インストールをしてみたりと、大きなロスをすることもしばしばありました。
そこで大きな威力を発揮したのが、QIコネクタの 2×20pin ハウジングです。

#3.本題
QIコネクタ（別名dupont connector）自体は珍しいものではなくて、2.54㎜ピッチのピンヘッダやピンソケットにケーブルを接続するために用いられるコネクタです。
ケーブルの本数や用途によって、1pin、2pin、3pin、2x3pinなど、複数の線をまとめられるのも便利です。
汎用的に使えるため、この様なセット販売品を持っている方も多いと思います。

<img width="500" alt="71hLt8vjNeL._AC_SL1500_.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496179/05af3cac-3a54-4296-785e-22d29def394f.jpeg">

しかし、上でも述べた通りRPiのGPIOは2×40pinもあり、差し替えの都度ピン番号を確認する手間や、差し間違いのトラブルが頻発していました。そこでaliexpressで見かけた2×20pinを採用したところ、想像通りものすごく便利でした。
<img width="500" alt="DSC_3365.JPG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496179/4a53743f-965b-01dc-1fa1-a5b7afd1eaa1.jpeg">

実際に使っているのが上の写真です。
RPiの用途を変えるときには、コネクタごと差し替えればOKなのでとても簡単です。

ただそれだけの話なんですが、なぜか国内で販売しているショップを見たことがありません。
なぜーーーーーーー？

2021/7/9現在、[aliexpress](https://ja.aliexpress.com/item/32717622351.html?spm=a2g0o.productlist.0.0.558357f96RIg8U&aem_p4p_detail=2021070820340217343405038789200004544855)では1,576円/100本。これだけあれば一生分ありそうですね。

https://ja.aliexpress.com/item/32717622351.html?spm=a2g0o.productlist.0.0.558357f96RIg8U&aem_p4p_detail=2021070820340217343405038789200004544855
[Colab] Google Driveをマウントする関数

#1.はじめに
Google Colabでプログラム開発をする際に、Google Driveをマウントすることがよくあります。
例えば、マウントしたGoogle Driveをデータセットのアップロード先、あるいは学習済みのモデルの保存先として使うことを考えてみてください。
Colabユーザとして、Google Drive関連のコードは、比較的に使用頻度が高いので、関連する関数をまとめました。

#2.やりたいこと

1.Google Driveをマウントする。
2.特定のパスをCurrent Pathにする。

#3.プログラムコード

マウントする関数とパスを変更する関数です。

```Python:
def connectDrive():
    from google.colab import drive
    drive.mount('/content/drive', force_remount=True)

def changeDirectory(path):
    import os
    original_path = os.getcwd()
    os.chdir(path)
    new_path = os.getcwd()
    print("Original path: ",original_path)
    print("New path: ",new_path)
```

#3. 実行結果

例えば、Google Driveに/Datasets/Cats_and_dogsというデータセット保存パスがあり、ここをCurrent Pathにしたい場合の操作です。

###1.Google Driveをマウントする。

```Python:
# Connect to Google Drive
connectDrive()
```

```
Mounted at /content/drive
```

###2.特定のパスをCurrent Pathにする。

```Python:
#Change Path
changeDirectory('/content/drive/MyDrive/datasets/cats_and_dogs')
```

```
Original path:  /content
New path:  /content/drive/MyDrive/datasets/cats_and_dogs
```

#4. 確認

```Python:
import os
current_path = os.getcwd()
print(current_path)
```

```
/content/drive/My Drive/datasets/cats_and_dogs
```

#5. まとめ
大変便利です。皆さんもぜひお使いください。

#6. 参考文献
1. Kaggle's Cats and Dogs Datasets : [リンク](https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition/data)
Dockerでコンテナが削除できなくなった

## 経緯
ローカル環境に使ってないコンテナとイメージが溜まってきたので掃除をしようとしたところエラーが起きたので備忘録として残しておきます。


## やったこと
まず、VSCodeのプラグインからDockerのコンテナ、イメージを削除していたところ一つだけ削除が完了しないものがあったのでターミナルから調査をする必要が出てきました。

まずは、コンテナを確認してみます。

```
CONTAINER ID   IMAGE          COMMAND                  CREATED      STATUS      PORTS                               NAMES
cca3269a13aa   09361feeb475   "docker-entrypoint.s…"   3 days ago   Up 3 days   33060/tcp, 0.0.0.0:3308->3306/tcp   database
```

↑このdatabaseのコンテナが削除できなくなりました。


まずは稼働中になっているので`docker stop`をして停止を試みます。

````
$ docker stop cca3269a13aa

```

いくら待っても返答が返ってきません。仕方なく`command + C`で処理を中止します。
次にコンテナを強制削除することを検討します。

```
$ docker rm --force cca3269a13aa
Error response from daemon: removal of container cca3269a13aa is already in progress
```

こちらもダメですね。。
「削除は進行中です」みたいなエラーが返ってきていますが、この処理が終わりそうな気配は全くないです。
プロセス周りでエラーしてるのかなということでMacを再起動します。（プロセスをkillして他のエラーに遭遇するのも嫌だったのでこうしています）
再起動後、再度プロセスを確認するとStatusがDeadに変わっています。

```
$ docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED      STATUS    PORTS                               NAMES
cca3269a13aa   09361feeb475   "docker-entrypoint.s…"   3 days ago   Dead      33060/tcp, 0.0.0.0:3308->3306/tcp   database
```

なんか、今なら削除できる気がします。

```
$ docker rm cca3269a13aa
cca3269a13aa
```

おぉ、無事削除することができました。

## 最後に
対応に慣れていればプロセスのkillでも対応できそうなので次同じことがあれば調べてみようと思います。

GUIで操作するのは、かなり楽をできますが何を実行してるか分からないのでなんか怖い、、、
どんなに便利になっても、基礎の学習は必要だなと感じました
提言：パスワードロック機能は誤入力の“回数”ではなく“種類数”で

ごく当たり前の提言をします。
パスワード総当たり攻撃への対抗策として誤入力連発によるパスワードロック機能を導入する際、やってしまいがちですが以下のような仕様には**しないでください**。

```
最後に認証成功またはパスワードを変更して以降かつ直近○○分以内の
パスワード誤りが○○回に達したら
それから○○分間はパスワード認証を拒否する
```

そうではなく以下のような仕様にしてください。

```
最後に認証成功またはパスワードを変更して以降かつ直近○○分以内の
パスワード誤りが○○ **種類** に達したら
それから○○分間はパスワード認証を拒否する
```

正当なユーザーの多くはパスワード認証を拒否されたらまず自分のミスタイプを疑い、再入力を試します。再々入力、再々々入力を試すことも大いにありえます。別のパスワードを試すこともありますが、それも拒否された場合はやはりその別パスワードのミスタイプを疑ってそれも再入力します。正当なユーザーは、**自分のミスタイプを疑っての再入力で容易に試行回数を使い切ってしまう**のです。

それに対して、総当たり攻撃をする攻撃者の目的は**より多くの種類のパスワード候補を試すこと**です。

誤ったパスワードの種類数でなく回数を条件にすることは、防御力にまったく寄与することなく正規ユーザーの利便性だけを下げているのです。利便性ということは当然、カスタマーサポート工数とユーザー離脱率を高める利益削減要因だということです。回数を条件にする意義はまったくありません。
kintoneのポータルのファビコンを無理やり変えるカスタマイズ

今回はkintoneポータルのファビコンを変えてみたいと思います。

複数のkintoneポータルを使用するという状況にある場合、一体どれがどのポータルなのか分からなくなってしまうこともあるかもしれません。そんな時に便利かもしれないカスタマイズです。

※DOM操作するのでkintoneのアップデートなどで使えなくなる可能性があり、あまりオススメできないカスタマイズです。

# ファビコンにしたい画像の準備

**画像保管用のアプリを作成しておきます。**

添付ファイルフィールドと、文字列(1行)フィールド等でメモを設置して
好きな画像を保存しておきます。

※↓こちらでアイコン作りました。

https://icone.unique-work.com/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/2bff519a-2012-0bc6-f707-cce5c0e0ba03.png)

**画像のURLを取得します。**

画像アドレスをコピーします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/509363b2-fb26-dc79-d825-916c501145f3.png)

# ポータルのJavaScript
portal.showイベントに↓を追加します。

```js
const obj = document.querySelectorAll("link");
obj.forEach((o) => {
  if (o.attributes.rel.nodeValue === "shortcut icon") {
    o.href = "コピーした画像アドレス";
  }
});
```


以下のようにポータルのファビコンを変えることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/e2bdcea7-fbac-ecd6-6926-7043cff65b46.png)
大変だ！JavaScriptでspliceの罠にかかってしまった！

# はじめに
お久しぶりです。業務が忙しかったりして、全然書けなかったです。
ネタがなかったわけではない

# わなにかかってしまった！

```vue:trap.vue
<script>
    let arr = ['1', '2', '3', '4', '5']

    arr.forEach((num, i) => {
        if (num >= 3) {
            arr.splice(i, 1) //３以上のものを消すで
        }
    })
    console.log(arr)
</script>

```

```log
(3)["1", "2", "4"]
```

なんでやねん！
って思ったら単純だった。
消したらlengthは1個減り、iは前に進み続ける。結果、ズレが生じる

# わなから抜け出した！

```vue:out.vue
<script>
    let arr = ['1', '2', '3', '4', '5']
    let i = 0
    while (i <= arr.length-1) {
        const data = arr[i]
        if (data >= 3) {
            arr.splice(i, 1)
            i--
        }
        i++
    }
    console.log(arr)
</script>

```

```log
(2)["1", "2"]
```

whileでループすれば簡単に解決した。
あとちょっとforEach嫌いになりました。

# まとめ
他にやり方あるのなら是非教えてください！
また暇になったら書きます〜
【Rails】Rails consoleを使ってコードを実行する方法

####My Profile
プログラミング学習歴②ヶ月目のアカウントです！
プログラミングスクールで学んだ内容や自分が躓いた箇所等のアウトプットの為に発信しています。
また、プログラミング初学者の方にわかりやすく、簡潔にまとめて情報共有できればと考えています。
もし、投稿した記事の中に誤り等ございましたら、コメント欄でご教授いただけると幸いです。　



#対象者

・サーバー起動せずにコードを実行したい方
・簡単に動作確認を行いたい方

#目的

・実装前に実装を考えてるメソッドの動きを確認する
・テーブルでどんなデータが格納されているか確認する


#実際の手順と実例
###1.rails cをターミナルで起動

`````
vocstartsoft:~/environment/sample_app $ rails c
``````
終了する場合は**exit**と入力し終了する

````
Running via Spring preloader in process 15364
Loading development environment (Rails 5.2.6)
[1] pry(main)> exit
````

###2.コマンドを入力
前提：Bookモデル、Books　Controllerでcreateを例にします。カラムにはtitleとbodyを用意してます。

````
pry(main)> Book.create(title:"Railsを楽しく学ぼう",body:"happy cording")
`````
と入力しEnterを押すと

`````
   (0.1ms)  begin transaction
   (0.1ms)  rollback transaction
=> #<Book:0x00000000069967a8
 id: nil,
 title: "Railsを楽しく学ぼう",
 image_id: nil,
 body: "happy cording",
 user_id: nil,
 created_at: nil,
 updated_at: nil>
[2] pry(main)> 
`````
上記のように表示されれば、保存が正常に動作しているということになります。

他にも、削除、取得の他にレコードの取得や保存、エラー箇所の発見ができるので便利です！


#補足
標準のconsoleのツールであるirbからpryに変更をおすすめします！pryはirbの「強化版」です。

導入方法は以下の通り。Gemfileに以下コードを追加します。

````
Gemfile
:
:

group :development, :test do
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  gem 'pry-rails'end

:
:

`````
追記できたら、**bundle install** を必ず実行する。

rails cをすると、下記のような表示が出力されます。

`````
username:~/environment/sample_app $ rails c
Running via Spring preloader in process 2885
Loading development environment (Rails 5.2.5)
[1] pry(main)>

`````
VSCode拡張 Rest ClientでInvalidParams: Json deserialize error: trailing characters at line

## 状況
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152020/d5086aa2-cf50-3658-c03d-8ecb845eadae.png)

## 結論
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152020/fbabc51b-bb08-908e-4584-f6b7b77a0390.png)

 ### が抜けていたorz
WindowsTerminalで複数タブを一気に開きたい

## やりたいこと

Windowsターミナルのタブを毎回開き直すのが大変なので簡単に開きたい。

## ショートカットを作る

右クリックからショートカットを作っていく。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290072/d6354389-be20-2a8e-3dc6-86cbcf30534e.png" width="50%">

```
wt ; new-tab -p "Command Prompt" -d "C:\Program Files" ; new-tab -p "Command Prompt" -d "C:\Program Files (x86)" ;
```

コマンドラインの引数についてはこちらを参照

https://docs.microsoft.com/en-us/windows/terminal/command-line-arguments?tabs=windows

## 他のタブも立ち上がってしまったがとりあえずOK

startingDirectoryとかそこらへんが初期値で設定されているから、そのあたりだろうか。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290072/863defa9-e30c-418c-e862-922a43da67b1.png" width="50%">

### 追伸

コマンドの最後に`;`があるともう１ウィンドウ立ち上がってしまう

## 知らなかったこと

これでターミナルが立ち上がること。

!<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290072/5a9a8e09-8574-5268-f2ad-19716fd734e3.png" width="50%">
CSSの::beforeと:beforeの違い、分かりますか？

## これは何

- CSSで装飾をスタイリングするときに`before`などを使う機会は多いですよね
    - 記事の分かりやすさとして`before`だけを例に挙げていますが、`after`や`first-line`でも全く同じことが当てはまります
- `::before`でも`:before`でも同じ動きをするんですが、それらがどう違うのかをまとめまた記事です

## 正しさで言えば`::before`の方が正しい

CSSには`疑似要素`と`疑似クラス`という概念があります。
それぞれの詳細な説明は省きますが、特定の要素や状態に対してのみスタイリングを施せて便利ですね。

```css:疑似要素（例としてbefore）
.class::before {
  /* スタイルを書く */
}
```

`css:疑似クラス（例としてhover）
.class:hover {
  /* スタイルを書く */
}
`

記事タイトルに挙げた`before`は疑似要素なので、コロン2つの`::before`が正しいです。

## なんで`:before`でも動くのか？

昔のCSSでは疑似要素と疑似クラスはどちらもコロン1つの記法でした。
しかしCSS3になってからは両者を区別しやすくするために、疑似要素はコロン2つの記法が導入されました。

後方互換性を保つために、コロン1つの記法が今でもサポートされていて問題なく動きます。
ただしあくまでサポートされているだけなので、あえてコロン1つの`:before`を使う理由はありません。

## 参考

https://developer.mozilla.org/ja/docs/Web/CSS/Pseudo-elements

https://developer.mozilla.org/ja/docs/Web/CSS/Pseudo-classes

https://developer.mozilla.org/ja/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements
Grafana の admin パスワードのリセット

こちらのページと同様のことを Arch Linux で行いました。
[Reset lost admin password of Grafana server (CentOS 7)](https://ahelpme.com/software/grafana/reset-lost-admin-password-of-grafana-server-centos-7/)

sqlite3 のデータベースを更新します。

```text
$ sudo sqlite3 /var/lib/grafana/grafana.db
SQLite version 3.36.0 2021-06-18 18:36:39
Enter ".help" for usage hints.
sqlite> select login,salt from user;
admin|F3FAxVm33R
sqlite> update user set password = '59acf18b94d7eb0694c61e60ce44c110c7a683ac6a8f09580d626f90f4a242000746579358d77dd9e570e83fa24faa88a8a6', salt = 'F3FAxVm33R' where login = 'admin';
sqlite> .exit
```

この操作をすると
user: admin
password: admin
になります。

Grafana のバージョンは次の通り

```text
$ grafana-cli --version
Grafana CLI version 8.0.4
```
【SASE】「真のゼロトラストを実現する現実的な導入ステップとは？」を視聴して

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/67f2e2a1-9691-64f4-a508-544cb914adcc.png)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/c5aa8f9b-7455-f046-5cdf-75b0bb7db1e0.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/e870f70d-1b2d-7e00-ab3c-b30726ef3fc2.png)
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/1ab3052d-1e61-b9fa-e3d8-df548410ead4.png)
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/cd9ef469-ccb8-31a2-7137-2e9d75fc0e84.png)
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/cd6dc12b-d278-5fc8-da1f-c06e4789730b.png)
[Rails]リロードしないとJavaScript(jQuery)が動かない問題

今回はRails初心者によくありがちな、リロードしないとjQueryが動かない問題について、記事にしていきます。

ぼく自身この問題には何度も直面していまして、対応策をあまり理解せずに、呪文のようにコードにコピペしていました。。
Turbolinksについて調べて理解が深まりましたので、初心者の方にもわかりやすく解説したので、最後まで読んでいただき理解してコードを書いていきましょう！

#開発環境

> ruby 2.6.3
> Rails 5.2.6

#何が原因？

まず結論から書いていきます。
リロードしないとjQueryが動かない問題の原因の９割は`Turbolinks`が関係しています。

たぶん何度か同じ経験をされた方は「またか」となるはずです。
なので`Turbolinks`を削除したり、無効にすることで解決します。

#対応策

対応策は3パターン。

####①Turbolinksを削除する

Turbolinksが原因なら削除すればいいのではという記事もよく見かけますが、この方法はおすすめしません。
あとで解説しますが、Turbolinksはページ遷移時の表示の高速化に一役買ってるのでそのままにしている方が、便利です。

####②jsファイルでTurbolinksを無効化する

この方法がおすすめです。
たとえば、.alert_btnをクリックしたら[Hello World!]とアラートを表示する処理があるとします。

```assets/javascript/application.js
$(function () {
  $('.alert_btn').click(function(){
    alert('Hello World!')
  });
});
```

この処理の記述自体は正しいのですが、Turbolinksのせいでリロードしないと発火しません。
なのでTurbolinksを無効化する処理を追加します。

```assets/javascript/application.js
// 以下１行を追加
$(document).on('turbolinks:load', function() {
  $(function () {
    $('.alert_btn').click(function(){
      alert('Hello World!')
    });
  });
// 閉じタグも忘れず追加
});
```

これで、画面遷移後、リロード無しで動作するはずです。

####③link_toでTurbolinksを無効化する

②の方法はjsファイルに記述しましたが、link_toに記述する方法もあります。
link_toに`data: {"turbolinks" => false}`を追加することで、リンク先のTurbolinksを無効化できます。

```erb:
<%= link_to 'Top', root_path, data: {"turbolinks" => false} %>
```

#そもそもTurbolinksとは

ここまででTurbolinksは無効化できて動作自体は問題なくできているはずですが、Turbolinksについてはわからないままだと思います。
ぼくも今までは「Turbolinksようわからんけど、②のコード追加したらちゃんとなるしええか」と思っていました。

なのでそもそものTurbolinksに触れていきます。

先程もちらっと触れましたが、`Turbolinksは画面遷移を高速化してくれるJavaScriptのライブラリ`で、RailsではGemによって管理され、デフォルトで入っています。(対応策①の削除するを実行したければGemfileから削除すればいい）

```Gemfile
:
gem 'turbolinks', '~> 5'
:
```

#Turbolinksの仕組み

画面遷移を高速化してくれる便利なやつとわかったので、仕組みを確認します。

- Turbolinksはaタグへのクリックイベントを起点として動作
- 遷移元のheadタグ内と遷移先のheadタグ内の情報に差分があれば差分を取り込む
- 遷移元のbodyタグの中身を遷移先のbodyタグの中身へと置き換える
- 遷移先のページを一から新たに読み込んでいるわけではない

つまり、aタグをクリックしたときに、headタグ内の差分を取り込んで、bodyタグを変更するだけで、一からページのファイルを読み込む必要がないので、表示が高速化されます。

#なぜ動かなかったのか

仕組みが分かったので、`リロードしないとJavaScript(jQuery)が動かない問題`の原因を整理していきます。

Turbolinks発動時、遷移先のページを一から新たに読み込んでいるわけではないので、jsファイルが読み込まれていないという状況が発生し動作しないのです。

つまり、aタグのクリックを使用しない、リロードやURLの直打ちのページ遷移だとTurbolinksは発動しないので、jQueryは問題なく動く。

やっと、根本的な原因が見えてきました。

だから、対応策としてTurbolinksを無効化するのが有効だったわけです。

#まとめ

####対応策としては３パターン
>①Turbolinksを削除する
>②jsファイルでTurbolinksを無効化する
>③link_toでTurbolinksを無効化する

####Turbolinksの仕組み
>- Turbolinksはaタグへのクリックイベントを起点として動作
>- 遷移元のheadタグ内と遷移先のheadタグ内の情報に差分があれば差分を取り込む
>- 遷移元のbodyタグの中身を遷移先のbodyタグの中身へと置き換える
>- 遷移先のページを一から新たに読み込んでいるわけではない


今までなにも考えずに呪文コードを使っていましたが、Turbolinksの仕組みを知ることで、深い理解が得られました。

この記事を読んで、エラーを改善するだけでなくTurbolinksを理解していただければ幸いです。
Boolean.valueOfのNPE

# Boolean.valueOfにBoolean型のnullを渡すとNPE
```java
Boolean.valueOf(null); // false

Boolean hoge = null;
Boolean.valueOf(hoge); // NullPointerException
```

## 理由
答えは簡単で、`hoge`はBoolean型だが、これを引数にとる`valueOf`は存在しない。

`valueOf`のメソッドシグネチャは、
* valueOf(String)
* valueOf(boolean)

である。

Boolean型を渡すと、対応する型が無いため、booleanへオートボクシングを試みる。
booleanはプリミティブ型であるため、NullだとNPEが発生する。
配列,集合,辞書型（Swift)

Swiftにはデータのコレクション型には配列型と辞書型と、集合型の３種類がある

1配列型
--
同じ値が異なるインデックスに複数回現れる。インデックスでアクセスできる
他の言語でもおなじみのやつ。

```swift:array.swift
let array: Array<Element> = ["値","値"] //一番丁寧な書き方
let array:[String] = ["値","値"] //:で型宣言する書き方
let array = ["値","値"]　 //型推論パターン
let array:[String] = [] //空白の配列は型推論できないのでしっかり宣言
let array = [String]()　 //空白の配列は型推論できないのでしっかり宣言(イニシャライザ使用）


```
配列型の操作基礎
append→末尾に要素を入れる
insert(要素, at　インデックス）→　任意の場所に挿入
remove(at インデックス)→指定の場所の要素を削除
removeFirst→先頭を削除
removeLast→末尾を削除
removeAll→全削除
count→要素の数を調べる
isEmpty→空かどうかを調べる


２辞書型
--
キーとペアで値を入れている順序を持たないデータ型。そのまんま辞書のイメージ

```swift:辞書.swift
let a: Dictionary<String, Int> = ["key": 1, "key2": 2]//丁寧な書き方
let a: [String: Int] = ["key": 1, "key2": 2]//：で簡単に書く
let a = ["key": 1, "key2": 2]//型推論
let a: [String: Int] = [:]//型推論は空白では使えないので宣言
let a = [String: Int]()//イニシャライザ使用
```

辞書型はキーがかぶってはいけない。順序関係も保証されていない。→for (key ,vakue) in 辞書型で回してみると順序が保証されていなことがわかる
そのため、アクセスするには。キーが必要になる。
要素を削除するにはnilを代入してあげるか```removeValue```で削除できる

３集合型
----
順序を持たないコレクションで、重複したデータを許容しない。

```swift:集合.swift
let a: Set<Int> = [1,2,3]　//丁寧な書き方
let a: Set = [1,2,3]//型推論
let a: Set<Int> = []//空集合の場合は型明示
let a = Set<Int>()//イニシャライザ使用
```

順序関係は保証されない。
contains→値があるか調べる
description→集合の情報を全てとれる
count→数を調べる
isEmpty→空か調べる
insert→追加する。順序がないのでインデックス指定はない。
remove→削除。上記同様、インデックス指定なし
union→和集合を出力
subtracting→差集合を出力
intersection→積集合を出力


よく使われるプロトコル
--
first→最初の要素をオプショナル型として返す
last→最後の要素をオプショナル型として返す
for in→繰り返し処理
forEach　→繰り返し処理
map→すべての要素にアクセスして新しいシーケンスを作る
reduce→要素にアクセスして全て一つの値（シーケンスではない）を生成
flatMap→すべての要素にアクセスして１つのシーケンスを生成する
filter→指定した条件飲みの要素を出力してシーケンスを生成
comactMap→nilを無視できるmap処理
Laravel eloquent の覚え書き

##この記事はLaravelを使っていて「これ便利だな」と思ったEloquentを記していきます。

覚え書きみたいなものなので、随時更新していきます。

####1. 先月のデータを取得する(Carbon使用)
```php
$query = \DB::table('users')
         ->wheremonth('created_at', '=', Carbon::now()->subMonth()->month)
         ->get();
```
users テーブルからレコードの作成日(created_at)が先月のものを取得します。
between を書かなくっていいので便利。


####2. left join 1
```php
$query = \DB::table('users')
         ->select(
              'users.name as name',
              'users.email as email',
              'books.name as book'
          )
         ->leftjoin('books', 'users.id', '=', 'books.user_id')
         ->where('books.id', '=', $id)
         ->wherenull('books.deleted_at')
         ->get();
```
普通に left join します。

####3. left join 2
```php
$query = DB::table('users')
         ->join('books', function($join) use($id){
            $join->on('books.user_id', '=', DB::Raw($id));
            ～～～
         });
$query->get();
```

####4. substring
```php
$query->on(DB::Raw('SUBSTRING(usres.id,5,6)'), '=', 'books.user_id');
```
OAuth2.0 VB.NET アクセストークンの更新


ロジレス(LOGILESS)のWEB-APIでアクセストークンを更新する手続きを記録します。

```vb:VB.NET
Imports Newtonsoft.Json
Imports System.Net
Imports System.IO
Imports System.Text

'アクセストークン再取得
url = "https://app2.logiless.com/oauth2/token?client_id=" & client_id & "&client_secret=" & client_secret & "&refresh_token=" & refresh_token & "&grant_type=refresh_token"

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12'TLS 1.2 を有効にする
Using wc As New WebClient
    wc.Headers.Add("ContentType", "application/json")

    Using st As Stream = wc.OpenRead(url)
        Using sr As StreamReader = New StreamReader(st, Encoding.UTF8)
            jsonStr = sr.ReadToEnd()
        End Using
    End Using
End Using

jsonObj = JsonConvert.DeserializeObject(jsonStr) 'Json文字列をJson形式データに復元する

'新しい情報
accessToken = jsonObj("access_token").ToString.Replace("{", "").Replace("}", "")
expires_in = jsonObj("expires_in").ToString.Replace("{", "").Replace("}", "")
refresh_token = jsonObj("refresh_token").ToString.Replace("{", "").Replace("}", "")

```
ReactにおけるCSSの書き方4種類

#はじめに
インラインスタイルとかCSSモジュールとかなにが違うんだっけと毎回調べていたのでいい加減まとめる。

#className属性によるCSS
普通のやつ。外部のcssファイルに書いてimportすることで適用。classNameを書くのがめんどくさいのと、1つのファイルで書くには量が膨大すぎる。分けようとするとどういう規則で分けるのかも考えなければならず、Reactのコンポーネント指向に従うならコンポーネントごとに作るべき。でもそれならCSS in JSでよくない？ってなる。

#インラインスタイルによるCSS
styled属性にcssを埋め込むことで適用。Reactで書く場合CSSがキャメルケースになったりしてめんどくさいのと、単純に見た目が汚くなるので好きじゃない。そもそも全部これでスタイルすることは想定してないだろうし、1行だけ適用させたい時以外はいらない。

#CSS Modules
className属性によるCSSと似ているが、違うのはCSSファイルの影響範囲を以下のReactコンポーネントを定義したJSXの中に限定することが出来る。classNameを一意なものにwebpackのツール？で変換しているっぽい。そのままのCSS使うよりはこちらの方がいいだろうが、コンポーネントごとに作るのならJSXファイルにまとめたいなあと個人的には思うので嫌。

#CSS in JS
JS上でCSSを書く。個人的には1つのコンポーネントにHTML/CSS/JS全部まとまるので一番好き。あんまり大きくなると分割しないといけないのかもしれないが、その時はスタイルコンポーネントだけ別ファイルにすれば一応できる（いいのかは置いておいて）。いろいろあるが一番人気なのはstyled-componentsじゃないかなと思っているので使っている。CSSもそのままの記法で書けるし、SASS記法も使える。

#おまけ
Material-UIなどのUIコンポーネントライブラリも便利。これだけですべて書くのはちょっと厳しいんじゃないかと思うが、１から実装するよりはこちらを使った方が早いことが多い。しかしデザインが似通ったものになるので、デザインを気にしないもの以外には使えない気もする。


#おわりに
とりあえず最初はReact + typescript + styled-components +material-UIとかで書いとけば、ある程度簡単に安全でそこそこの見栄えのwebサイト、webサービスが作れるんじゃないかと思ってる。

#参考文献
[1]:https://www.i-ryo.com/entry/2020/12/09/073749#CSS-Modulescss-loader
[2]:https://qiita.com/_likr/items/c335dec5221024ad56bc
[3]:https://morishitter.hatenablog.com/entry/2015/09/28/103334

[[1]]:ReactのCSS設定方法について調べたこと（className属性、style属性、CSS Modules、CSS in JS、CSSフレームワーク）
[[2]]:webpackのcss-loaderでCSS Modulesをやる
[[3]]:CSS Modules 所感
JAR,WAR,EARの違い

いずれもJava仕様に準拠して定義されたZIP形式のパッケージ(複数のファイルをまとめたアーカイブ)。
Javaで実装したプログラムを実行・配布しやすくするための形式。
ファイルの規模感としては、`EAR > WAR > JAR`となる。

###JAR
Java プログラムの実行に必要なクラスファイルや設定ファイルがまとめられているアーカイブ。 Javaで作成したソフトウェアを配布する際に関連するファイルを1つにパッケージングする際に利用され、実際に多くのクラスライブラリはこの形式で配布されている。

###WAR
Java 製のWebアプリで利用されるクラスファイル(servlet)、設定ファイル、JSPやHTMLファイル、JAR形式のライブラリなどがまとめられているアーカイブ。 また、web.xmlが含まれ、TomcatなどのアプリケーションサーバにWARファイルを配布すると、これを元にデプロイされる。
MVCモデルでいえば、MVCすべてまとめてひとつにした感じだと思う。

###EAR
Java EEアプリーケーションのパッケージ形式。 任意の数のWARファイルやEJBファイル、またこれらのアプリケーションで必要とするJARファイルを含めることができる。
herokuのPostgreSQL/MySQLへ接続

#はじめに
herokuにて作成したDBへ、ターミナルから接続したい時の備忘録

##PostgreSQL

以下のコマンドでデータベースへ接続可能

```bash
$ heroku pg:psql -a <herokuアプリ名>  #https://<herokuアプリ名> .herokuapp.com/
```

また、以下のコマンドで詳細情報確認可能。

```
$ heroku pg:info -a <heroku アプリ名>
```

##MySQL

以下のコマンドで`CLEARDB_DATABASE_URL`を確認

```
$heroku config -a <heroku アプリ名>

CLEARDB_DATABASE_URL:　mysql://"Username":"Pssword"@us-cdbr-east-02.cleardb.net/heroku_"Database"?reconnect=true

```
以下のコマンドでデータベースへ接続

```
mysql -u Username -p -h us-cdbr-east-02.cleardb.net heroku_Database
Enter password: Password
```
Expo(ReactNative)でiOSアプリ配信


何度リリースしても忘れてしまうのでざっくりと個人用メモを残しておく

【概要】
A. develop周り
B. connect
C. expo

---
https://developer.apple.com/account
A-1. Certificatesの作成（証明書）
A-2. Identifiersの作成（識別子）
A-3. Profilesの作成（プロファイル）

---
https://appstoreconnect.apple.com/
B-1. 新規App作成
B-2. App Store > 一般（プロモーション用テキスト、概要、キーワード、サポートURLの作成、Appプレビュー、、、その他入力）
B-3. App Store > App情報（名前、サブタイトル、カテゴリ選択、コンテンツ配信権、年齢制限指定、使用許諾契約）
B-4. App Store > 価格および配信状況（価格表、予約注文、配信可否、Appleシリコン向け配信、Appの配信方法）
B-5. App Store > Appのプライバシー（プライバシーポリシー、、、データタイプ以降を入力）
B-6. 機能 > Game Center
B-7. 機能 > 暗号化（輸出コンプライアンス）
B-8. 機能 > プロモーションコード

---
https://docs.expo.io/distribution/building-standalone-apps/
C-1. app.json周りを修正
C-2. expo build:ios
C-3. 2完了後、ipaファイルを保存
C-4. アップロード（Transporter）
C-5. アップロード完了メールが届いたらconnectにてビルドを選択

---
細かな設定などは全て除いて概要だけとなってます。
修正・追加などリクエストあればぜひお声がけください🙇‍♂️

2021版リリースフローでいい感じの記事あれば共有いただければ幸いです。
それでは良いアプリ開発の日々を!
PythonでWindowsアプリを自動化する【プログラム】

 [環境構築](https://qiita.com/daizou33/items/4cb5d7336421d85b0c82 "PythonでWindowsアプリを自動化する【開発環境構築】")が整ったらプログラミングを行います。

```python:Python
# 必要なライブラリのインポート
from appium import webdriver
from selenium.webdriver.common.keys import Keys

# 起動されているWindows Application Driverへ接続する
# この例では、アプリケーション全体(App=Root)を対象として4999番ポートで起動されたWADへ接続している。
# 特定のアプリを起点としたい場合は、desired_caps["app"] = "C:\\hoge.exe" とする。

desired_caps = {}
desired_caps["app"] = "Root"
driver = webdriver.Remote(command_executor='http://127.0.0.1:4999', desired_capabilities= desired_caps)
	
# 要素の指定
xpath_str = \
   　　"/".join(['ここにWinAppDriverUiRecorderで調査したxpathを書く'])

# キー入力
driver.find_element_by_xpath(xpath_str).send_keys(キーを書く)

# クリック
driver.find_element_by_xpath(xpath_str).click()

# 文字を取得
driver.find_element_by_xpath(xpath_str).text

```
番外編！Pythonコードをexeファイル化する
１.pyinstallerをインストールする
  pip install pyinstaller
    
２.pyinstallerコマンドで.pyファイルをexeファイルにする
　pyinstaller [ファイル名].py --onefile

３.成功すると実行したフォルダ下にdistフォルダが作られておりその中にexeファイルが出来る
プログラムの引数とVM引数って何？

Eclipseの実行構成画面でコマンドライン引数の設定やってみた。
`プログラムの引数`にコマンドライン引数にしたいものを記入。
`VM引数`はJava 仮想マシン (JVM) の振る舞いを変更する値。例えば以下の様な設定値が入る。

```
-classpath(あるいは-cp):クラスパスの指定
-D:プロパティの定義
-Xmx:ヒープ領域の最大サイズの指定
```

適当に入力してみる・・・
![スクリーンショット 2021-07-09 9.54.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207205/9de13dd3-2850-e738-d1ee-d6c5e3df993c.png)

コンソールにarg[0]〜arg[3]で出力

```
arg[0]:山田
arg[1]:太郎
arg[2]:伊藤
arg[3]:佐藤
```
デリゲート、プロトコルを理解する

プロトコルってなんだ？
----
protocol 日本語訳すると「議定書」
swiftのドキュメントの説明　「型のインターフェースを定義するものです。インターフェースを定義し、抽象化することによって、複数の型で共通の機能を実装することができます。プロトコルはクラス、構造体、列挙型などで使われ、プロトコルのインターフェースを満たす型は、プロトコルに準拠している と言われています。」

　頭で？？？
が出てきますね。。

要は、用意されたデータ型のオブジェクトを使用する際のルールのまとめ集（仕様書のようなもの）である。ルールであるため、プロトコルに沿った変数やメソッドを実装しないとエラーになります.


プロトコルの定義方法

```swift
protocol プロトコル名 {
    var プロパティ名: 型 { get set }
    func メソッド名() -> 返り値の型
}

class Sample: プロトコル名 {
    var プロパティ名: 型
    func メソッド名() { ... }
}
```

プロパティ名でget,setを指定することで読み書き可能になります。getのみだと読み込み専用。setのみは記述不可
プロトコルはあくまで仕様書なので実際の処理内容は準拠したクラス側で記述しなくてはならない。


プロトコルの準拠の話
--
よくプロトコルに準拠しているという記述を目にする。
難しく聞こえるが、要はプロトコルに書かれた仕様書（ルール）通りにかかれているという意味。
そもそも、ルール通りに書かなければコンパイルエラーになってしまう。
クラスにおいてプロトコルの準拠は継承の書き方とおなじだが、クラスは１つしか継承できないのに対して、準拠はいくつでも可能。
また、構造体は継承はできないが、準拠ならいくつでも可能。




プロトコルはわかったけどデリゲートってなんだ？
---
そもそもデリゲートと和訳すると「任せる」という意味。
要はプロトコルでルール（仕様書）を作成し、あるクラスから細かいデータの処理は他のクラスに任せるというデリゲートデザインパターンのこと。
デザインパターンだったのか！！早くそれを言ってくれよ！！

つまり、プロトコルはSwiftの公式な文法だが、デリゲートは文法ではなくてデザインパターンである。
そして、デリゲートはAppleが用意してくれたプロトコルを使用して情報を受け取って使用することで実装している


なんでデリゲートって必要なの？
---
処理を任せることでファイルの依存性を解消できるため変更に強くなる。
クラス間の依存性をなくす重要性はプログラミングを学んでいれば一度は聞いたことあるはず。
また、プロトコルに実際の処理が書かれていないのでどのクラスなのか、どんな処理なのかをあまり意識しなくてもかける。

delegatemethodの実装方法
--
①デリゲートを実装する
②自身を受取先に指定する
③デリゲートメソッドを定義して情報を受け取る
④任意のタイミングで発動
open sshのダウングレード

## 概要
open sshのダウングレードの記事が少なく, 苦労したので書き残しておきます.

## やっていく
ubuntu 20.04ではデフォルトで`openssh-client==1:8.xxx` のopen sshが入ってると思います. このバージョンだと

```
$ ssh-keygen -t rsa
```

した時に, 古いバージョンの時に比べて長い鍵が生成されます. この鍵の長さが20.04より古いバージョンのubuntu間の通信を阻害します. なので, client側のopen sshのバージョンを強制的に下げて, 鍵の長さを合わせます.

`penssh-client==1:7.6p1-4ubuntu0.3`まで下げればいけるとのこと
具体的には`/etc/apt/souce.list`のファイルに下記の1行を追加します.

```
deb http://security.ubuntu.com/ubuntu bionic-security main
```

そして, 下記のコマンドで古いバージョンをインストールします.

```
$ sudo apt update
$ sudo apt-get install openssh-client=1:7.6p1-4ubuntu0.3
```

これで短い鍵が生成される. 


### 参考にした記事
https://packages.ubuntu.com/bionic/openssh-client
PythonでWindowsアプリを自動化する【開発環境構築】

【開発環境構築】
１．Pythonをインストールする
　　pip(Pythonパッケージ管理ツール)もインストールされます。
　　
２．Python用のAppiumライブラリのインストール
　　　pip install robotframework-appiumlibrary

　　　以下のライブラリも含まれています。
　　　Appium-Python-Client
　　　　pip install Appium-Python-Client
　　　selenium
　　　　pip install selenium

３．WinAppDriverUiRecorderをダウンロードする
　　https://github.com/microsoft/WinAppDriver/releases/tag/UIR-v1.1
　　操作したい画面等の要素のxpathを知るためのツールです。
　　exe直起動して使うアプリです。
　　inspect.exeでは、xpathが取れない？ので、WinAppDriverUiRecorderは必須と言えよう。
　　なお、inspect.exeは私のPCでは以下にありました。　　
　　C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x86
　　
４．Windows Application Driverをダウンロードして起動する
　　https://github.com/microsoft/WinAppDriver
　　exe直起動アプリです。
　　このコンソールアプリを事前に起動しておいて、PGからセッションを接続する使い方です。
　　ただしこれを起動するには、<font color= red>Windows10を開発者モード(developer mode)にしておく必要があります。</font>

　　こんなbatファイルを作ると便利！
　　cd C:\Program Files (x86)\Windows Application Driver
　　WinAppDriver.exe 4999
Nuxt.js+axiosでCORSを回避する方法(本番環境, proxyを使わない方法)

## したいこと

 - フロント(Nuxt.js)からAPIを呼ぶ際に、普通に呼ぶとCORSのエラーになるので回避したい

## 試したこと(ローカル環境)

https://axios.nuxtjs.org/options/

にもあるように、proxyを設定していた。

nuxt.config.ts:

```
  axios: {
    proxy: true
  },

  proxy: {
    '/api/': {
      target: 'https://hoge.co.jp/v1/',
      changeOrigin: true
    },
  }
```

APIの呼び出し:

```
await axios.get(
'/api/xxx
)
```

これで、`yarn dev`してlocalhostで確認していた際は、うまく行っていた。

## 問題点

 - 上記の設定で`yarn generate` したものをサーバー上(AWS)にデプロイしたら、再びCORSエラーになった。

## 解決方法

 - axiosのヘッダーにCORSの設定を追加した

設定例:

plugin/axios.ts

```
import { Context } from '@nuxt/types'
import axios from 'axios'

export default function ({ $axios }: Context) {
  $axios.onRequest((config: any) => {
    axios.defaults.headers.common.Authorization = localStorage.getItem(
      'auth._token.local'
    )
    axios.defaults.headers.post['Content-Type'] = 'application/json;charset=utf-8'
    axios.defaults.headers.post['Access-Control-Allow-Origin'] = '*'
    return config
  })
}
```

## 所感

 - proxyの設定ができたほうが、APIを呼び出す際に、/apiとかで呼び出せるので、URLがnuxt.config.ts内で完結するのが良さそうだと感じたが、その恩恵を受けられないのが少し残念。

 - 改善に期待
Nuxt generateで TypeError: _vm._ssrNode is not a functionってエラーがでた

`nuxt generate`したら、こんなエラーがでた。

```
TypeError: _vm._ssrNode is not a function
```

## どんな環境でおきたの？
[Nuxt (v2.15.7)](https://nuxtjs.org/)で、Universal(SSR/SSG) ＋ Static (Static/Jamstack hosting) 

## 原因
functional component（以下参考） を利用するとでることがあるっぽい。

## エラーがでたコンポーネントの内容

layout/default.vue

```vue
<template>
  <div class="l-wrapper">
    <LayoutHeader />
    <Nuxt />
  </div>
</template>
```

components/LayoutHeader.vue

```vue
<template functional>
  <HogeFunctional>こいつはfunctional component</HogeFunctional>
</template>
```

components/HogeFunctional.vue

```vue
<template functional>
  <div>Hoge!</div>
</template>
```

## どうやってエラー解決したか

`components/LayoutHeader.vue` の　functional を削除。
（根本的な解決になってないけど。。）

```diff
- <template functional>
+ <template>
  <HogeFunctional>こいつはfunctional component</HogeFunctional>
</template>
```

## 補足

ちなみに、以下のケースではエラーがでませんでした。

components/LayoutHeader.vue

```vue
<template functional>
  <div>LayoutHeaderでは、vueコンポーネント使わないもん</div>
</template>
```

## 参考にしたサイト

- https://github.com/vuejs/vue-loader/issues/1170
- https://github.com/gridsome/gridsome/issues/443
- https://bleepcoder.com/nuxt-js/747345602/functional-components-not-worked-if-import-dynamically-with


間違い、その他良い方法等あったらコメントください。
SQL 一覧シート3（ビュー、サブクエリ、相関サブクエリ）

#### 関連記事
- [SQL 一覧シート1（テーブル作成からSELECT文）](https://qiita.com/mitsuooo/items/e58eb0317f8dedb32247)
- [SQL 一覧シート2（INSERT, DELETE, UPDATE）](https://qiita.com/mitsuooo/items/a7355d2a284df55e3b9d)

# ビュー

## テーブルとの違い

- ビュー
    - 実際のデータではなく、**SELECT文が保存**されている
        - SELECT文を保存しており、実行した際に一時的に仮想のテーブルを作る
    - SELECT文で、ORDER BY句が使えない
          - テーブル同様、ビューにも**行には順序がない**から
    - ビューに対する更新(INSERT, DELETE, UPDATE)は制限があり、以下の項目を守る必要がある。ビューとテーブルの更新は連動して行われるため。
        - DISTINCTが含まれていない
        - FROM句に含まれるテーブルは1つだけ
        - GROUP BY句を使用していない
            - 元のテーブルを集約しているため、ある1つのレコードを追加するときに、整合性がとれない（1つの定まらない）から
        - HAVING句を使用していない
       

＊DBのデータは、実際にはコンピュータ内の**記憶装置（ハードディスク）に保存**されている。

## ビューのメリット

- データを保存しないことで、記憶装置の容量を節約できる
- 頻繁に使うSELECT文を、ビューとして保存しておくことで使い回しが効く
    - **ビューが含むデータは、元のテーブルと連動しているため、自動的に最新の状態に更新されている**
        - **ビューを参照する = そのSELECT文を実行する** ため最新状態のデータを選択できる

## CREATE

```sql
CREATE VIEW ビュー名　(ビュー列名1, ..)
AS
SELECT文 ..
```

## SELECT

テーブル同様に使用可能

```sql
SELECT ビュー列名1, ..
  FROM ビュー名；
```

### ビューへの検索の実行順序

1. ビューに定義されたSELECT文実行
２. その結果に対して、ビューをFROM句に指定したSELECT文が実行される

**ビューに対する検索は2つ以上のSELECT文が実行される**

＊3つ以上、ビューの上にビューを重ねる**多段ビュー**は**パフォーマンスの低下**を招くため避ける

## DROP

```sql
DROP VIEW ビュー名;

-- 多段ビューの作成元となっているビューを削除する場合、それに依存するビューが存在するとエラーになる。
```

依存するビューごと削除するCASCADEオプション

```sql
DROP VIEW ビュー名 CASCADE;
```

# サブクエリ

- 使い捨てのビュー（SELECT文の実行終了後に消去される）
- ビュー定義のSELECT文をそのままFROM句に持ち込んだもの

## 基本の形

```sql
SELECT ビュー列1, ..
  FROM ( SELECT 列名1, ..
           FROM テーブル名
          GROUP BY ... ) AS ビュー名;

-- カッコ()内がサブクエリ
-- この「ビュー名」は使い捨てであり、ビューのように記憶装置（ハードディスク）には保存されない
-- サブ : 下位、 クエリ : 問い合わせ
-- = 一段レベルが下がったSELECT文
```

まずFROM句の中のSELECT文が実行され、その後に外側のSELECT文が実行される。

＊サブクエリの中にサブクエリ..のように深い階層になると、多段ビューの時同様、パフォーマンスに悪影響

# スカラサブクエリ

- 必ず1行1列だけの結果を返すサブクエリ
    - つまりただ1つの値

## 使用される状況（例）
    - 全体の平均値より大きい値を持ったレコードのみを取得したいが、集約関数(AVG)をWHERE句に書くことはできないため、SELECT文が書けない

```sql
SELECT name, age 
  FROM User
 WHERE age > AVG(age)
-- エラーになる
```

ここで、スカラ・サブクエリを使用する

```sql
SELECT name, age
  FROM User
 WHERE age > (SELECT AVG(age)
                FROM User);

-- SELECT AVG(age) FROM User は、全ユーザー対象の平均年齢が、1つの値として出力されている
```

サブクエリ同様、スカラ・サブクエリから先に実行され、その後外側のSELECT文が実行される

## スカラ・サブクエリが書ける箇所

- 定数や列名を書くことのできる場所はどこでも記述可能
    - SELECT
    - GROUP BY
    - HAVING
    - ORDER BY

# 相関サブクエリ

## サブクエリとの違い

- （例）全体の平均年齢ではなく、国ごとの平均年齢より高いユーザーを出力する、のようにグループごとに比較する。

## スカラ・サブクエリとの違い

- 結果が2行以上で返されるため、対応関係を示す必要がある

## 基本の形

```sql
SELECT name, age
  FROM User AS U1
 WHERE age > (SELECT AVG(age)
                FROM User AS U2
               WHERE U1.age = U2.age
               GROUP BY nation);

-- 各ユーザーの年齢と平均年齢の比較を、同じ国籍の中で比較する
-- 相関サブクエリ内のWHERE句で対応関係を示すことで、結果的に実行される各クエリでは、
  -- 1つの値が返されており、エラーにならない
```
**テーブル全体ではなく、テーブルの一部のレコードの集合に限定した比較をしたい時に用いる**

## 気をつけること

### 結合条件は、サブクエリ内に書く

- スコープに関して考えると、外側のSELECT文でのWHERE句にテーブルの別名を定義すると、サブクエリが先に実行されて実行結果が残った状態になると、サブクエリ内で使用してテーブルの別名が使用できないため

```sql
SELECT name, age
  FROM User AS U1
 WHERE U1.age = U2.age
   AND age > (SELECT AVG(age)
                FROM User AS U2
               GROUP BY nation);

-- サブクエリが実行終了した際、U2はもう存在しなくなるので、外側のSELECT文時にエラーが起きる
```

#### 参考

「SQL ゼロから始めるデータベース操作」
window.onloadが効かない。そんな時はoverflow:auto;を探そう

ほぼタイトルで完結していますが、一応どこでoverflow:auto;を探せばよいかほんの少しだけ書きます。

```CSS:CSS
body{
     overflow:auto;
}
/* もしくは */
html{
     overflow:auto;
}
```
上記の記載がCSSに存在するとwindow.onloadが反応しないことがあります。
window.onloadが効かないと悩んでいる方に参考となれば幸いです。
ckanバックエンド側テスト環境構築時に発生したエラーまとめ

ckanのプラグインの開発時、バックエンドのテスト実行時にエラーになった個所について記載します。

# 環境

Windows上でDockerのコンテナ上にckanを構築しています。

|ソフトウェアなど|バージョン|
|---|---|
|Windows|10|
|Docker|v20.10.7|
|Docker Compose |v2.0.0-beta.4|
|Debian GNU/Linux|v9|
|python|v2.7.13|
|pytest|v4.6.5|
|ckan|v2.9.3|
|PostgreSQL|v11.2|
|Solr|v6.6.5|
|Redis|v6.2.4|

# 発生したエラー

## 設定ファイル(who.ini)読み込み時にエラーになる

### エラー内容

```
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR>   File "/usr/lib/ckan/venv/local/lib/python2.7/site-packages/_pytest/main.py", line 204, in wrap_session
...(略)...
INTERNALERROR> MissingSectionHeaderError: File contains no section headers.
INTERNALERROR> file: /usr/lib/ckan/venv/src/ckan/who.ini, line: 1
INTERNALERROR> 'ckan/config/who.ini'
```

### 原因

Linuxのシムリンクの`who.ini`がWindows上でサポートされないためです。

### 解決方法

シムリンク先の`who.ini`を直接参照するようにテスト用設定ファイルを修正します。

```ini:{プラグインのルートディレクトリ}/test.ini
who.config_file = {who.iniのリンク先}
```

※`who.ini`のリンク先の確認方法

[ckanのGitHub](https://github.com/ckan/ckan/blob/master/who.ini)上から確認し、リンク先のパスを探してください。

### 参考

* https://github.com/ckan/ckan/issues/4604

## DBの操作を行う実装個所でエラーになる

テスト用DBのクリーンを行うために以下のようなテストコードを実装しました。

```python
@pytest.mark.usefixtures('clean_db')
def test_plugin():
    pass
```

### エラー内容

```
self = <sqlalchemy.dialects.postgresql.psycopg2.PGDialect_psycopg2 object at 0x7f3e6e7cb7d0>, cursor = <cursor object at 0x7f3e6e7bac50; closed: -1>, statement = '\nDROP TABLE spatial_ref_sys', parameters = {}                                                                                                                                                                                                   rs = {}
context = <sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7f3e6af4bdd0>

    def do_execute(self, cursor, statement, parameters, context=None):
>       cursor.execute(statement, parameters)
E       InternalError: (psycopg2.errors.DependentObjectsStillExist) cannot drop table spatial_ref_sys because extension postgis requires it
E       HINT:  You can drop extension postgis instead.
E
E       [SQL:
E       DROP TABLE spatial_ref_sys]
E       (Background on this error at: http://sqlalche.me/e/2j85)

../../local/lib/python2.7/site-packages/sqlalchemy/engine/default.py:550: InternalError
```

### 原因

テスト用DBが初期化されていない可能性があります（参照しているDB情報が異なる）。

### 解決方法

ckanをホストするサーバーのシェルスクリプトで以下を実行します。

```bash
CKAN_SQLALCHEMY_URL={テスト用DBの接続情報}
# 例としてプラグイン「sample」のテストを行う
cd /usr/lib/ckan/venv/src/ckanext-sample
# テスト実行
pytest --ckan-ini={テスト用の設定ファイル} ckanext/sample/tests
```

### 解説

大切な個所は以下1点です。PostgresSQLの拡張機能「Postgis」は関係ありません。

1. `CKAN_SQLALCHEMY_URL={テスト用DBの接続情報}`

    環境変数「CKAN_SQLALCHEMY_URL」を使用していなければ、設定ファイル内のDB情報が正しく参照されるためエラーは発生しません。もし環境変数「CKAN_SQLALCHEMY_URL」にすでに本番用DBの接続情報が設定されている場合、テスト用の設定ファイルに`sqlalchemy.url`を指定していても環境変数側の値が優先されます。
EC2 マウントポイント追加方法

# EBSボリューム追加

[![Image from Gyazo](https://i.gyazo.com/a6181514acf5a0a20f6afe4d5219ba4f.png)](https://gyazo.com/a6181514acf5a0a20f6afe4d5219ba4f)

# マウント設定

### デバイスフォーマット
```
$ sudo mkfs -t ext4 /dev/sdf
sudo file -s /dev/sdf   // 確認
```

### マウントポイント作成
```
$ sudo mkdir -pm 755 /mnt/
$ sudo mkdir -pm 755 /mnt/test_dir
```

### fstab設定
```
$ sudo vi /etc/fstab
/dev/sdf                                      /mnt/test_dir     ext4    defaults 0   2
```

### マウント
```
$ sudo mount -a
```

### 手動マウント
```
$ sudo mount /dev/sdf /mnt/test_dir
```

### アンマウント
```
umount /mnt/test_dir
```

### ディスク確認コマンド
```
$ sudo fdisk -l
$ lsblk
```



# 参考文献
 - [EC2インスタンスに追加でEBSボリュームをアタッチする。](https://qiita.com/kooohei/items/d692931cbebf97006f96)
【RPA】RPAブログの投稿傾向

# はじめに

この投稿は、QiitaとNoteのRPA製品に関する投稿データから、その傾向を見てみる 記事です。

RPAツールUiPathのコミュニティ「UiPath Friends」が企画する「**UiPathブログ発信チャレンジ2021サマー**」の 9日目の投稿になります。

企画の内容は [**こちら**](https://note.com/shumpei_w/n/n651cbdbec4e8) 。カレンダーのURLは [**こちら**](http://u0u1.net/sUwZ) です。

https://twitter.com/ShumpeiWatanabe/status/1405168150736359427?s=20


# データ取得方法

Qiita・NoteともにAPIでデータを取得できます。今回はUiPathを使って、APIからデータを取得してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/06ab4d83-e37d-e032-0d6a-685e1417eb8a.png)
データ取得方法についての記事はこちら。

https://qiita.com/miya_gis/items/742874b43699266f2d6e

https://qiita.com/miya_gis/items/2872e34ebafbbd59c722


# データ傾向）年度別の投稿数

投稿データの最初は2017年度でした。以降から現在（2021年上期まで）のデータを見ると、各製品ともに増えています。2021年上期はPAD登場で賑わいました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/e15ca020-11b9-a0da-763d-fd0baea02957.png)

# データ傾向）投稿している人

製品別の投稿者数、投稿数を見てみると、特定の人が牽引している状況も見えました。
ただし継続して投稿するのは難しく、休眠期間や他の製品への移動などの傾向も見えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/43b73b5b-fa6e-5bf1-0a41-d855eb1422da.png)

※ アカウントの情報は、アスタリスクで半分伏せてあります。

# データ傾向）投稿時期

直近12ヶ月の投稿を見てみると、PAD登場による投稿数増加などの傾向が見えます。
製品によってはブログ投稿イベントを開催していたり（UiPath）そのタイミングでも投稿数が増えています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/b745ccdb-fba8-c1d3-deef-10727d996e72.png)

# データ傾向）投稿内容（コンテンツ）

投稿数の安定している「UiPath」の直近12ヶ月の投稿内容を分類しました。
やってみた系が少し少ないですが、程よく分散されていると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/58f176de-6720-d74c-5813-42142e3f304b.png)


# 終わりに

いかがでしたでしょうか。
今後も各社ともに製品のブログ投稿記事が増えていけば、RPA業界ももっと盛り上がります。

次回はこのデータを参考に、ブログ投稿のネタ作り、コツについて紹介したいと思います。

この記事が参考になったら、 LGTMをお願いします。閲覧ありがとうございました。
GoでTestifyでテストする際のassertとrequireの違い

### `assert`か`require`か。

どちらも同じに見えるが、動きが少し異なる。

結論から言うと、
* **`assert`は途中でFailしてもテストは続行する**が、
* **`require`は途中でFailしたらそこでテスト関数を抜ける**。

`require`は、テストに必要な前提条件などの確認で使い、
`assert`は目的のテストのために使うとよさそう。

#### 使い分けの例:
`Foo()`をテストしたいが、`Foo()`を実行するためにフォルダが必要な場合。

```go
func TestFoo(t *testing.T) {
  err := mkFooDir()
  require.NoError(t, err)

  actual := Foo()
  assert.Equal(t, fooExpected(), actual) 
}
```

### サンプルコード
https://play.golang.org/p/EAbcXAenWI3

```go
package main

import (
    "testing"

    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/require"
)

func TestFoo(t *testing.T) {
    assert.Equal(t, 123, 123) // pass
    assert.Equal(t, 123, 321) // fail
    assert.Fail(t, "failed")  // fail

}

func TestBar(t *testing.T) {
    require.Equal(t, 123, 123) // pass
    require.Equal(t, 123, 321) // fail, and finish testing
    require.Fail(t, "failed")  // will be skipped.

}
```

Output:

```shell
=== RUN   TestFoo
    prog.go:12: 
            Error Trace:    prog.go:12
            Error:          Not equal: 
                            expected: 123
                            actual  : 321
            Test:           TestFoo
    prog.go:13: 
            Error Trace:    prog.go:13
            Error:          failed
            Test:           TestFoo
--- FAIL: TestFoo (0.00s)
=== RUN   TestBar
    prog.go:19: 
            Error Trace:    prog.go:19
            Error:          Not equal: 
                            expected: 123
                            actual  : 321
            Test:           TestBar
--- FAIL: TestBar (0.00s)
FAIL
```

参考URL：
https://www.yellowduck.be/posts/assert-vs-require-in-testify/
ASP .NET Core Identity External Login の外部認証側からASP .NET CoreへのClaim引き継ぎについて

自分用の備忘録。

外部認証External Loginを使った時の話。

GoogleやFacebook、ADなど、外部認証を行うと、基本的にはメールとユーザIDのみ引き継ぎ。
外部認証側の属性を使いたいときは、Claimを使う。
外部認証側のClaimにユーザの情報が入っているので、初回ログイン時にユーザ作成をした際に、ASP .NET Core側のユーザー情報としてClaimを追加する。
ClaimはAspNetUserRolesテーブルに保存される。
https://docs.microsoft.com/ja-jp/aspnet/core/security/authentication/social/additional-claims?view=aspnetcore-5.0

だいたい載っているユーザの属性情報を引き渡す方法としては上記だが、このログイン方法だと、「初回ログイン時にユーザ作成をした際に」しかClaimを渡さない。
今回、自分がつかったのは、社内システムのADと連携する際に利用したため、組織変更に対応する、という観点ではつらいところがある。
やりたいのは、ログインのたびに、外部認証側のClaimを使えること。

似たような課題を持った人がいたので、以下を参照。以下要約。
https://haacked.com/archive/2019/07/16/external-claims/
やりたいこと：
・ログインのたびに、外部認証側のClaimを使いたい
・AspNetUserRolesにClaimを保存したくない
ポイント：
（実際に検証してみたら本当だった内容。ほかの記事で、この内容でいける、みたいな情報があっても、このポイントの内容のため実施できなかった。）
・IClaimsTransformationつかって、外部認証側のClaimをいれればイケる、という情報があったら、IClaimsTransformationの中で外部認証側のClaimを参照すると、無限ループが起きるため、使えない。
・外部認証をする際に外部認証のCookiesを消すため、ログイン処理以外の場所では、外部認証のClaimを参照できない。
この記事での対応：
・SignInManagerをOverWriteして、外部認証のClaimを埋め込む処理を入れる
（
しかし、上記記事の対応は、実際にやってみたらうまくいかず。
SignInManagerのソースがverupなどで挙動が変わったら…と思うと、この方法は怖い。
が、永続化なし＆外部認証Claim使用したい場合、仕方ないようにも思える。
https://github.com/aspnet/Identity/blob/master/src/Identity/SignInManager.cs
）

永続化はしてもいいので、ログイン時にASP .NET Core側のユーザー情報としてClaimを追加する、をやりたい。
しかし、ログイン時のClaim追加の方法がいまいち見つからず。
以下で発見。
https://github.com/dotnet/AspNetCore.Docs/blob/main/aspnetcore/security/authentication/social/additional-claims.md#add-and-update-user-claims
上記ソースの中で、ポイントとなる箇所をピックアップ

```
//以下でユーザの情報を取得
var user = await _userManager.FindByLoginAsync(info.LoginProvider, 
                info.ProviderKey);
//以下でClaim追加
await _userManager.AddClaimAsync(user, new Claim(addedClaim.Key, externalClaim.Value));
//以下でClaim更新
await _userManager.ReplaceClaimAsync(user, userClaim, externalClaim);
//以下で、更新したClaimをDBに反映。
 await _signInManager.RefreshSignInAsync(user);
```
Next.jsにressを導入する


## ressとは？
リセットCSSの一つでブラウザがデフォルトで持っているスタイルを打ち消すCSSです。
https://github.com/filipelinhares/ress


## パッケージを追加する

```
yarn add ress
```

## _app.tsxでressを読み込む
`import 'ress'`を追加してressを読み込む

_app.tsx

```
import '../styles/globals.scss'
+ import 'ress'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default MyApp

```

## 完了
手元の環境でリセットCSSが効いているか確認してみてください。
【Docker】コードの変更が自動的に反映されない時 Windowsユーザー向け no.33

![パンプキン カフェ (11).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/18e5827c-bb31-79c9-9b07-34ebada92cb6.png)


こんにちは、まゆみです。

Dockerについての記事をシリーズで書いています。

『Containerからリモートにあるプロジェクトフォルダーをバインドマウントしているのに、コードの変更が自動的に反映されない』

今回の記事では、そのような時どうしたら解決するのかを書いていきたいと思います

Windowsユーザー向けの記事になります。

#Dockerfileの時

```
env CHOKIDAR_USEPOLLING=true
```
![2021-07-28_9-55-42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/1a53d75b-1a3e-c1de-6712-fa07a8862c55.png)

#docker-composeの場合

```
environment:
   - CHOKIDAR_USEPOLLING=true
```

以上をつけ足して書いてくだされば、解決します