OmniAICreator/Qiita-1.07M huggingface dataset:
とあるサイトでのみ%HTTPoison.Error{id: nil, reason: :closed}が発生 (Elixir)

[Elixir その2 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/elixir2) 4日目です。
前日は、[Surfaceをつかってみる(Elixir/Phoenix)](https://qiita.com/torifukukaiou/items/b5ae9eac42bd304b7aa3)でした。

# 2021-09-04追記
- ようやく会話が成立しました :tada::tada::tada: 
- 下記の記事をご参照ください
- [とあるサイトでのみ%HTTPoison.Error{id: nil, reason: :closed}が発生 解決編 (Elixir)](https://qiita.com/torifukukaiou/items/fd7971bb5dd7788c55d5)

# はじめに
- そういうことがあるのですねえ
- この記事で使用したバージョンは以下の通りです

|  | バージョン | 
|:-----------|------------:|
|[Elixir](https://elixir-lang.org/)|1.10.4-otp-23|
|[Erlang](https://www.erlang.org/)|23.0.1|
|[httpoison](https://hex.pm/packages/httpoison)|1.7.0|
|[hackney](https://hex.pm/packages/hackney)|1.16.0|

- 大丈夫なサイトもあります
- たいてい大丈夫です

```elixir
iex> HTTPoison.get "https://www.google.com" 
{:ok,
 %HTTPoison.Response{
   body: "<!doctype html><html...
}
```

- エラーがでるサイトの例
    - 少数派です

```elixir
iex> HTTPoison.get "https://xxx.jp/"    
{:error, %HTTPoison.Error{id: nil, reason: :closed}}
```

- なにがなんだかわからず焦った :sweat: ので、調べたことを書いておきます 

----

# 結論
- **[hackney](https://hex.pm/packages/hackney)のアップデートを待ちましょう**

----

# [{:error, %HTTPoison.Error{id: nil, reason: "closed"}} #326](https://github.com/edgurgel/httpoison/issues/326)
- [hackney](https://hex.pm/packages/hackney)を更新したら直ったという人もいれば、駄目だという人もいろいろいます
- どうも[httpoison](https://hex.pm/packages/httpoison)が依存している[hackney](https://hex.pm/packages/hackney)になにかがありそうです

# 回避策(非推奨)
- 必ずしも解決できるとは限りません
- [hackney](https://hex.pm/packages/hackney)のバージョンを落としてみました
- 私がアクセスしたかったサイトは以下の方法でアクセスできましたよ! ということのご紹介です

```elixir:mix.exs
  defp deps do
    [
      {:httpoison, "~> 1.6"},
      {:jason, "~> 1.2"},
      {:hackney, "1.15.2", override: true}
    ]
  end
```

```
$ mix deps.update --all
```

```elixir
$ iex -S mix

iex> HTTPoison.get "https://xxx.jp", [], ssl: [{:versions, [:'tlsv1.2']}]
{:ok,
 %HTTPoison.Response{
   body: "<!doctype html><html...
}
```

- こんなことをしなくてもアクセスできていた気がするので、[httpoison](https://hex.pm/packages/httpoison)と[hackney](https://hex.pm/packages/hackney)の組み合わせでなにかありそうです
    - さらにほると、[hackney](https://hex.pm/packages/hackney)が依存している[certifi](https://hex.pm/packages/certifi)というHexのバージョンを落とせば第3引数の指定で動くことを確認しました
    - `{:certifi, "2.5.1"},`


# Wrapping Up :lgtm: :qiita-fabicon: :lgtm: 
- すっきりしませんが、日本語の記事は見つからなかったので書き留めておきます
- Enjoy [Elixir](https://elixir-lang.org/)!!! :rocket::rocket::rocket:
cloud9にdein.vim導入

失敗した場合のリスクを考えてcloud9でdein.vim導入してみた

1回目
失敗


```
"dein Scripts-----------------------------
```
↑コメントアウトが意図しない書き方で入ってしまい失敗

##以下をコピペする


```
$ mkdir -p ~/.cache/dein
$ cd ~/.cache/dein
$ curl https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.sh > installer.sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2243  100  2243    0     0   6796      0 --:--:-- --:--:-- --:--:--  6796
$ sh ./installer.sh ~/.cache/dein

〜〜省略〜〜

"End dein Scripts-------------------------

Done.
Complete setup dein!
$
```
```
"dein Scripts-----------------------------
if &compatible
  set nocompatible               " Be iMproved
endif

" Required:
set runtimepath+=/home/ec2-user/.cache/dein/repos/github.com/Shougo/dein.vim

" Required:
if dein#load_state('/home/ec2-user/.cache/dein')
  call dein#begin('/home/ec2-user/.cache/dein')

  " Let dein manage dein
  " Required:
  call dein#add('/home/ec2-user/.cache/dein/repos/github.com/Shougo/dein.vim')

  " Add or remove your plugins here like this:
  "call dein#add('Shougo/neosnippet.vim')
  "call dein#add('Shougo/neosnippet-snippets')

  " Required:
  call dein#end()
  call dein#save_state()
endif

" Required:
filetype plugin indent on
syntax enable

" If you want to install not installed plugins on startup.
if dein#check_install()
  call dein#install()
endif

"End dein Scripts-------------------------

```

参考資料（いつもありがとうございます）
---
[dein.vimのインストール自体にハマってしまったメモ
](https://qiita.com/Coolucky/items/0a96910f13586d635dc0)

[設定ファイル (.vimrc) を開く、リロードする
](https://maku77.github.io/vim/settings/reload-vimrc.html)

[deinを真面目に設定してみる(TOML)](http://grainrigi.hatenablog.com/entry/2017/08/28/013114)
C216 Audio ControllerをArch Linux上で使う方法

最近マザーボードを`Z77M-D3H`に変えた。Arch LinuxのSSDを繋げてみると音が出ない。
調べてみたところどうやらカーネルモジュールの設定を追記してやればいいらしい。
Root権限で設定ファイルを作成後にinitrdを再作成すればおｋ

```bash
echo "options snd-hda-intel model=generic"  > "/etc/modprobe.d/alsa-base.conf"
mkinitcpio -P
reboot
```
「レガシーコードからの脱却」読書メモ その2

レガシーコードからの脱却
ソフトウェアの寿命を延ばし価値を高める9つのプラクティス

David Scott Bernstein 著
吉羽 龍太郎、永瀬 美穂、原田 騎郎、有野 雅士 訳
オライリー・ジャパン 2019年
https://www.oreilly.co.jp/books/9784873118864/

---
第Ⅱ部　ソフトウェアの寿命を延ばし価値を高める9つのプラクティス
　4章　9つのプラクティス
　5章　プラクティス1 やり方より先に、目的、理由、誰のためかを伝える
　6章　プラクティス2 小さなバッチで作る
を読んだメモ

---
# プラクティスの話の前に

---
# ソフトウェア開発における「原則」

単一責務の原則
「クラスを変更する理由は1つ以上存在してはならない」
オープン・クローズドの原則
「ソフトウェアの構成要素は拡張のために開いていて、修正のために閉じていなければならない」
etc.

では原則をどうやって実践するのか？
→その手助けとなるのが**プラクティス**

---
例えば..
原則: 安く買って、高く売れ
プラクティス: ドルコスト平均法

---
# 9つのプラクティスの背景

ソフトウェアは必ず変化する(それ自身は良いこと)
変化を完全に予測することは不可能
ゆえに「後から対応可能」にする方がコストが安い

---
> それらのプラクティスの焦点は開発者を速く働かせることではない。保守、開発がやりやすいコードを開発することに重点を置く。

---
# プラクティス1
---
# やり方より先に、目的、理由、誰のためかを伝える

---
# ストーリーから進める
「何が　なんのために　誰のために存在する」= **ストーリー**

ストーリーの例: 映画ファンとして、チケットをオンラインで購入したい。そうすれば劇場で列に並んで待つ必要がない。

---
# ゴールを決めておく
ストーリーからゴール=**受け入れテスト**を作っておく
→どこまでやれば終わりかがわかる
→エッジケースを受け入れテストに入れておく

**どこまでやれば終わりか**を明示し、作りすぎを防ぐ

---
# プロダクトオーナー

プロダクトに対して責任を負う役割(映画で言えば監督)
プロダクトに精通し**「これが次に作るいちばん重要な機能だ」**と言う人
→ストーリーを書き、その優先順位を決定する

---
> 私は長年IBMで働き、合議によって設計されたプロジェクトやプロダクトに従事してきたので言える。絶対にそれはうまくいかない。

---
# やり方は開発者の領分

> そこでもし建築家に屋根の角度をどうするか尋ねられたり、請負業者がどの釘を使うか指示するよう求めたり、配管工が仕入れるパイプの長さを私の指示を待ったりしたらどうだろうか？

---
# プラクティス2

---
# 小さなバッチで作る

---
# 小さいことは良いこと

「小さい」=計測可能な結果が得やすいこと

理解しやすい、見積もりやすい、実装しやすい、テストしやすい

---

# 小さければ不確実性が少ない

ソフトウェア開発は創造的なプロセス
→常に不確実性が付きまとう
→小さい単位なら不確実性も少ない

---
# 「小さくする」ための指針

大きいことはたいてい**複数のことが入り混じっている**か**複雑**のいずれか

複数のことが入り混じっている
→コンポーネントに分割する
複雑
→既知のことと未知のことを分離する
　→未知のことを既知のことにする、カプセル化する

---
> 小さな問題は大きな問題に比べて解決が容易だ。したがって、分割は本当に重要だ。そしてこのスキルは、ソフトウェア開発を単なる仕事からプロとしての仕事にする上で獲得しておかなければならない重要なスキルの1つだ(決して唯一のスキルではない)。

---
# 小さくリリースする

一度に取り掛かる作業が多すぎると、仕掛り中の作業が増えてたくさんの無駄が生まれる

・最初にすべての要求事項を出す
・結合やテストは最後
→従来の手法だと仕掛りが多い状態が維持される

---
# フィードバックサイクルを短くする

最初から正しくやるのは難しい
→間違いを減らすためにはフィードバックが必要

ビルド(=最初のフィードバック)を高速化する
→結合レベルを適切にする

---
# 計測のための7つの戦略(1)

**生産性は計測できない**

**・価値実現までの時間を計測する**
　→全体像に着目し部分最適化を避ける
**・コーディングに使った時間を計測する**
　→役に立たないことに時間を取られていないか？
**・欠陥密度を計測する**
　→コード量に対するバグ数はチームや時間をまたいで比較可能
**・欠陥検出までの時間を計測する**
　→欠陥修正のコストを下げる

---
# 計測のための7つの戦略(2)

**・機能ごとの顧客価値を計測する**
　→価値の高い項目に時間を割けるようにする
**・機能を使用しない場合のコストを計測する**
　→それが機能の価値になる
**・フィードバックループの効率を計測する**
　→いかに早く失敗し、そこから学ぶか

---
# つづく
AAE2019 Bot実行時エラー対策Tips（随時追加中）


#はじめに

AutomationAnywhere A2019で発生するエラーと対策について、知っている限り記載します。
※まだ数は少ないですが、随時内容追加予定です。
※バージョンが上がったら日本語化される（かもしれない）

#Webブラウザ操作系
##ハイパーリンクが見つからないエラー
> There was a problem at line 10
> This may be due to the following reason:
> LINK が見つかりません。検索条件が一致しませんでした。

> To continue, edit the bot and fix the error. Then, try again.
> If you continue to see this message, please contact your system administrator.
> コード: bot.execution.error

####直接原因
Webブラウザ操作で、対象のハイパーリンクが見つからない。

####対応案
Web画面の操作の再キャプチャを行う　他？
（画面上にリンクがあるのにこれが出るケースもある。原因究明中）

---
##ブラウザの対象Windowが見つからない
>There was a problem at line 11
>This may be due to the following reason:

>Cannot find window or application titled '[Webページのタイトル]' that was open during recording
>To continue, edit the bot and fix the error. Then, try again.
>If you continue to see this message, please contact your system administrator.
>コード: bot.execution.error

####直接原因
対象のWebページが開いていない。

####対応案
当ステップ実行前に、対象Webページが開けているか確認する。


---
#テーブル操作時エラー
>There was a problem at line 13
>This may be due to the following reason:
>
>Invalid argument supplied to 'table', index '8' is invalid or out of bound.
>
>To continue, edit the bot and fix the error. Then, try again.
>If you continue to see this message, please contact your system administrator.
>コード: bot.execution.error

####直接原因
テーブルの列・表のインデックス指定が範囲外。
javaでいうならば、ArreyIndexOutOfBoundsException。

####対応案
表の内容を確認し、取得対象行列のインデックスとして指定した値を見直す。
★indexはjavaなどと同じく、0からの指定になる点に注意。
　（このあたり、一般ユーザーにはわかりにくいかなぁ）

---
#メール送信
##メール送信失敗（接続情報が不正）
>This may be due to the following reason:
>E メールメッセージの送信中にエラーが発生しました。提供された接続の詳細を確認して、もう一度お試しください。
>
>To continue, edit the bot and fix the error. Then, try again.
>
>If you continue to see this message, please contact your system administrator.
>コード: bot.execution.error

####直接原因
メール送信失敗。メール送信の設定がおかしい？

####対応案
設定内容と同じ内容で、メーラーで送信可能か確認する
【Rails】note記事をrssで取得するrakeタスクを作る


### やりたいこと
Rails 環境で、note 記事を rss で取得してDBに保存、自動表示させたい！✨
今回は、note 記事を取得するための rake タスクを作成します。

### 準備
- HTTP クライアントライブラリを`gemfile`に追加

本記事では`httparty`を使用していますが、`faraday`でも動作します。

参考: [Awesome Ruby - Faraday VS httparty](https://ruby.libhunt.com/compare-faraday-vs-httparty)

- RSSフィード解析ライブラリ`feedjira`を`gemfile`に追加

```ruby:Gemfile
gem 'httparty'
gem 'feedjira'
```
```console
$ bundle install
```

### モデルの用意
今回は、特定のマガジンの記事の取得&タイトルと日付の表示が目的なので、シンプルに１つのモデルを作成します。
（複数のマガジンを取得するなら、もう１つモデルが必要そうです）

```console
$ rails g model notice note_id:string title:string article_date:date

$ rails db:migrate
```

### rakeタスク
タスクファイルを作成します📝

```
$ rails g task rss
```
`Httparty.get`の後には取得したいページの`"URL/rss"`を入れてください。

```ruby:lib/tasks/rss.rake
namespace :rss do
  desc "note記事を更新"
  task note_update: [:environment] do
    xml = Httparty.get("https://note.com/○○/rss").body
    rss = Feedjira.parse(xml)
    rss.entries.each do |item|
      id = item.url.split(File::SEPARATOR).last
      date = item.published.strftime("%Y/%m/%d")
      local_item = Notice.where(note_id: id).first_or_initialize
      local_item.update!(title: item.title, article_date: date)
    end
  end
end
```
`File::SEPARATOR`はファイルパスのセパレータです。
参考: [constant File::SEPARATOR](https://docs.ruby-lang.org/ja/latest/method/File/c/SEPARATOR.html)

`rake rss:note_update`コマンドで、最新の25件（デフォルト値）の記事をDBに保存します。`rails c`で保存されているか確認してみます。

```ruby
pry(main)> Notice.count
=> 25
pry(main)> Notice.all
# ここに記事一覧がでます
```
`first_or_initialize`で`note_id`がなければレコードを作成し、既にあれば更新するので、タイトルや記事が更新されても重複保存されません。

### 表示
記事のタイトルや内容を更新すると、表示順が一番後ろに変更されるので、`article_date`の`"DESC"`などで表示すると、間違いなく最新順に並ぶと思います。

```erb
<% articles = Notice.order(article_date: "DESC").take(8) %>
<% articles.each do |item| %>
  <li><a href="https://note.com/○○/n/<%= item.note_id %>?magazine_key=○○">
    <p><%= item.title %></p>
    <span><%= item.article_date %></span></a>
  </li>
<% end %>
```

### その他
`note_id`の一意性のテストなどを追加しました👍
Go 言語で湯婆婆を実装してみる

[Javaで湯婆婆を実装してみる](https://qiita.com/Nemesis/items/c7192a7c510788d2cba2)（@Nemesis 様）というのがバズっていたので、
完全に便乗ですが、せっかくだし面白そうなので Go言語で Go婆婆 を実装してみます。

# 実装
```main.go
package main

import (
	"bufio"
	"fmt"
	"math/rand"
	"os"
	"strings"
	"time"
)

func main() {
	fmt.Println("契約書だよ。そこに名前を書きな。")

	stdin := bufio.NewScanner(os.Stdin)
	stdin.Scan()
	name := stdin.Text()
	fmt.Printf("フン。%sというのかい。贅沢な名だねぇ。\n", name)

	nameArray := strings.Split(name, "")
	rand.Seed(time.Now().UnixNano())
	newname := nameArray[rand.Intn(len(nameArray))]

	fmt.Printf("今からお前の名前は%sだ。いいかい、%sだよ。分かったら返事をするんだ、%s！！\n", newname, newname, newname)
}

```

Go のランタイムがあれば main.go を実行すればそのまま動きます。

```sh
$ go run main.go
契約書だよ。そこに名前を書きな。
山田太郎
フン。山田太郎というのかい。贅沢な名だねぇ。
今からお前の名前は山だ。いいかい、山だよ。分かったら返事をするんだ、山！！
```


# コード解説
解説するほど難しいコードではないような気がしますが一応。

### 標準出力
組み込みの [fmt](https://golang.org/pkg/fmt/) パッケージを使うだけです。

```go
fmt.Println("契約書だよ。そこに名前を書きな。")
```

### 標準入力
[bufio](https://golang.org/pkg/bufio/) パッケージを使ってます。
Go での標準入力のやり方は複数あって、[fmt.Scan](https://golang.org/pkg/fmt/#Scan) を使うのが一番コード量が少ないんですが、
未入力のリターンを受け付けないので不採用(未入力でのクラッシュを再現したかったので)。

```go
stdin := bufio.NewScanner(os.Stdin)
stdin.Scan()
name := stdin.Text()
```

### 名前を奪う
標準入力から受け取った文字列を split で配列に変換して、乱数を利用してインデックス指定で1文字だけ抽出します。
乱数の作成には [math/rand](https://golang.org/pkg/math/rand/) を利用しています。

```go
nameArray := strings.Split(name, "")
rand.Seed(time.Now().UnixNano())
newname := nameArray[rand.Intn(len(nameArray))]
```

# クラッシュ
標準入力で何も入力しないと panic します。
本家でもクラッシュさせてたので再現させてみました。
`rand.Intn` の引数に 0 を指定するなというエラーですね。

```
panic: invalid argument to Intn

goroutine 1 [running]:
math/rand.(*Rand).Intn(0xc000058180, 0x0, 0x1188ce0)
        /usr/local/opt/go/libexec/src/math/rand/rand.go:169 +0x9c
math/rand.Intn(...)
        /usr/local/opt/go/libexec/src/math/rand/rand.go:337
main.main()
        /Users/nakaya/go/src/yubaba/main.go:22 +0x2ad
exit status 2
```

ちなみに、クラッシュさせないかつ空文字のみの入力を受け付けないようにするには以下のようにします。

```main.go
package main

import (
	"bufio"
	"fmt"
	"math/rand"
	"os"
	"strings"
	"time"
)

func main() {
	var name string
	for len(strings.TrimSpace(name)) == 0 {
		fmt.Println("契約書だよ。そこに名前を書きな。")
		stdin := bufio.NewScanner(os.Stdin)
		stdin.Scan()
		name = stdin.Text()
	}
	fmt.Printf("フン。%sというのかい。贅沢な名だねぇ。\n", name)

	nameArray := strings.Split(name, "")
	rand.Seed(time.Now().UnixNano())
	newname := nameArray[rand.Intn(len(nameArray))]

	fmt.Printf("今からお前の名前は%sだ。いいかい、%sだよ。分かったら返事をするんだ、%s！！\n", newname, newname, newname)
}
```

何かしらの文字入力があるまで湯婆婆が延々ループします。

```sh
$ go run main.go
契約書だよ。そこに名前を書きな。

契約書だよ。そこに名前を書きな。

契約書だよ。そこに名前を書きな。

契約書だよ。そこに名前を書きな。

契約書だよ。そこに名前を書きな。
```
fish環境で、nodeをnvmで入れる




```
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.0/install.sh | bash

# fish-nvmのインストール
$ fisher add jorgebucaran/fish-nvm

$ nvm -v

# nodeバージョン確認
$ nvm ls

# ltsバージョンをダウンロードしてpathを貼る
$ nvm use lts
$ node -v
````

参考：
- https://dev.classmethod.jp/articles/fish-nvm/
データフレームに含まれる2値データの頻度をPythonを用いて1つの棒グラフで表してみる 

データの中身を確認するにあたり、
2値データ等がどれだけ含まれるかを一つの棒グラフで表現したい時があるはずです。

探し方が悪かったのか、
一つの棒グラフで表す簡潔な方法が出てこなかったのでアウトプットも含めて記載します。

今回は、2値データだけでなく6値のデータも含めた棒グラフを作成しています。

# 環境

Google Colabを使用しました。
使用したライブラリのバージョンは以下になります。

|ライブラリ|バージョン|
|---|---|
|python|3.6.9|
|pandas|1.1.4|
|seaborn|0.11.0|
|matplotlib|3.2.2|

# ライブラリのインポート

上記のモジュールを使用するにあたり、インポートしておきます。

```python
%matplotlib inline
import pandas as pd
import seaborn as sns
from matplotlib import pyplot as plt
```

# データセットのインポート

今回は、seabornに含まれる学習用データセットの[tips](https://www.kaggle.com/ranjeetjain3/seaborn-tips-dataset)を利用します。
このデータセットには、
ディナーとランチの総支払額と含まれるチップの額や支払った人の性別などが含まれます。

```python
# データフレームのインポート
tips = sns.load_dataset('tips')

# 先頭5行を確認
display(tips.head())
```
||total_bill|tip|sex|smoker|day|time|size|
|---|---|---|---|---|---|---|---|
|0|16.99|1.01|Female|No|Sun|Dinner|2|
|1|10.34|1.66|Male|No|Sun|Dinner|3|
|2|21.01|3.50|Male|No|Sun|Dinner|3|
|3|23.68|3.31|Male|No|Sun|Dinner|2|
|4|24.59|3.61|Female|No|Sun|Dinner|4|

上記のような出力があればインポートは成功です。

# データの加工

以下の4つのカラムを用いて棒グラフを作成します。
グラフの作成にあたり、定性的な値を定量的な値に変換する必要があります。

|カラム名|概要|方針|
|---|---|---|
|sex|性別 (Male/Female)|Male -> 0, Female -> 1|
|smoker|喫煙 (No/Yes)|No -> 0, Yes -> 1|
|time|食事の時間 (Lunch/Dinner)|Lunch -> 0, Dinner -> 1|
|size|人数 (1 ~ 6)|そのまま利用|

これを実現するには色々な方法があると思いますが、
以下のように実施しました。

```python
# sexを定量化 (Male1 -> 0, Female -> 1)
tips.sex = tips.sex.replace("Male", 0).replace("Female", 1)

# smokerを定量化 (No -> 0, Yes -> 1)
tips.smoker = tips.smoker.replace("No", 0).replace("Yes", 1)

# timeを定量化 (Lunch -> 0, Dinner -> 1)
tips.time = tips.time.replace("Lunch", 0).replace("Dinner", 1)

# 先頭5行を確認
display(tips.head())
```

||total_bill|tip|sex|smoker|day|time|size|
|---|---|---|---|---|---|---|---|
|0|16.99|1.01|1|0|Sun|1|2|
|1|10.34|1.66|0|0|Sun|1|3|
|2|21.01|3.50|0|0|Sun|1|3|
|3|23.68|3.31|0|0|Sun|1|2|
|4|24.59|3.61|1|0|Sun|1|4|

このように、0と1に置き換えられたことが確認できます。

# 頻度のグラフ化

さて、本題になります。
棒グラフに含めるカラム名をリスト形式でlabelに定義します。
次に各カラムに対してユニークな値とその個数を取得します。
このままではindexがカラム名、カラム名が値の状態なので入れ替えを実行しています。

```python
# 棒グラフに収めるラベル一覧の定義
label = ["sex", "smoker", "time", "size"]

# 各ラベルに対してユニークな値の取得
tips_ = [tips[l].value_counts() for l in label]

# データフレームに変換してindexとカラムを入れ替え
tips_ = pd.DataFrame(tips_).transpose()

# グラフの表示
tips_.plot.bar()
plt.grid()
plt.title("Frequency of values in each label")
plt.ylabel("counts")
plt.xlabel("value")
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/861505/97cf0b9f-1d5f-f94a-e269-b2efd19fe81d.png)

このように求めたかったグラフを作成することができました。

# まとめ

value_countsを使用してデータフレームを新たに作成し、頻度の棒グラフを出力しました。

# 参考にしたもの

* [BioTech ラボ・ノート: 学習用データセット – seaborn【Python】](https://biotech-lab.org/articles/1408)
* [note.nkmk.me: pandasのplotメソッドでグラフを作成しデータを可視化](https://note.nkmk.me/python-pandas-plot/)
VS Codeをリフレッシュする方法

[VSCode で最高の LaTeX 環境を作る](https://qiita.com/Gandats/items/d7718f12d71e688f3573)通りに作業していたのですが、ビルドをするときに「Tasks are only available on a workspace folder.」というエラーが出てダルかったので、いっそのことVS Codeを一度削除して新たにインストールしました。

macOSです。必要なコマンドを`~/refresh_vscode.sh`などとして保存しておけば、

```bash
source ~/refresh_vscode.sh
```

で何度でも簡単に削除とインストールができるようになります。

# 消したくないファイル

- 削除をする前に、消したくないファイル、ディレクトリは取っておいた。
    - `~/Library/Application\ Support/Code/User/`というディレクトリに`settings.json`や`snippets/`があるので、このディレクトリごといったんデスクトップに置いておく。
    - `~/.vscode/extensions/`に拡張機能があるので、これもデスクトップに避難させておく。
    - `settings.json`, `snippets/`, `extensions/`の3つ以外に消したくないようなファイルはないとに思います。まぁ消してしまったら再度設定していけばいいでしょう。

```bash
# settings や extensionsをデスクトップに写しておく
mv -v ~/Library/Application\ Support/Code/User/ ~/Desktop/
mv -v ~/.vscode/extensions ~/Desktop/
```

# 削除

これで完全削除できるらしいです。

```bash
# アプリの削除
rm -rf /Applications/Visual\ Studio\ Code.app
rm -fr ~/Library/Preferences/com.microsoft.VSCode.helper.plist
rm -fr ~/Library/Preferences/com.microsoft.VSCode.plist
rm -fr ~/Library/Caches/com.microsoft.VSCode
rm -fr ~/Library/Caches/com.microsoft.VSCode.ShipIt/
rm -fr ~/Library/Application\ Support/Code/
rm -fr ~/Library/Saved\ Application\ State/com.microsoft.VSCode.savedState/
rm -fr ~/.vscode/
rm -fr ~/.vscode*
rm -rf /usr/local/bin/code
```

# 再インストール

```bash
brew update
brew cask install visual-studio-code
brew reinstall visual-studio-code # 上のコマンドで「Already exists」と出た場合
```

# 「消したくないファイル」をもとに戻す


```bash
mkdir -p ~/Library/Application\ Support/Code
mkdir -p ~/.vscode
mv -v ~/Desktop/User ~/Library/Application\ Support/Code/
mv -v ~/Desktop/extensions ~/.vscode/
```

# 最後に

すべて連結したようなファイル`~/refresh_vscode.sh`を作っておけば、

```bash
source ~/refresh_vscode.sh
```

のコマンド一発でVS Codeをリフレッシュできるでしょう。

```shell:~/refresh_vscode.sh
mv -v ~/Library/Application\ Support/Code/User/ ~/Desktop/
mv -v ~/.vscode/extensions ~/Desktop/
rm -rf /Applications/Visual\ Studio\ Code.app
rm -fr ~/Library/Preferences/com.microsoft.VSCode.helper.plist
rm -fr ~/Library/Preferences/com.microsoft.VSCode.plist
rm -fr ~/Library/Caches/com.microsoft.VSCode
rm -fr ~/Library/Caches/com.microsoft.VSCode.ShipIt/
rm -fr ~/Library/Application\ Support/Code/
rm -fr ~/Library/Saved\ Application\ State/com.microsoft.VSCode.savedState/
rm -fr ~/.vscode/
rm -fr ~/.vscode*
rm -rf /usr/local/bin/code
brew update
brew cask install visual-studio-code
brew reinstall visual-studio-code
mkdir -p ~/Library/Application\ Support/Code
mkdir -p ~/.vscode
mv -v ~/Desktop/User ~/Library/Application\ Support/Code/
mv -v ~/Desktop/extensions ~/.vscode/
```
Prophetで簡単に時系列予測をする





#1.はじめに
最近簡単に時系列予測をするために、Prophetを使ってみた。
せっかくなので導入から動かすところまでを共有しようと思い、記事にしました。


* 動作環境
 * OS : Windows10
 * Python : 3.8.3 // Miniconda 4.9.1
 * Visual Studio Community : 2019
 
#2.Prophetって何？
Prophetはfacebook社がOSS(MITライセンス)として公開している時系列の予測パッケージ。
細かい理論に関してはここで触れないが、一般化加法モデルを用いて予測が行われている。

[公式ページ](https://facebook.github.io/prophet/)
[github](https://github.com/facebook/prophet)

#3.検証用に仮想環境を作成、仮想環境に切り替え

```Python:
#prophet_envという仮想環境をpython3.7系で作成(3.8系だとfbprophet 0.6に非対応)
conda create -n prophet_env python=3.7

#base環境から作成したprophet_env仮想環境に切り替える
conda activate prophet_env
```

#4.導入～動作確認
まずは、Visual Stuido Communityをインストールしておく。
※C++ Compilerが必要になる
[Visual Studio Code のサイト](https://code.visualstudio.com/)

その上で以下ライブラリを導入する

```Python:
#ProphetはPyStanに依存している為に導入
conda install plotly -y

#fbprophetを導入(2020/11/1時点のバージョンは0.7.1だったがエラーが出たので0.6)
conda install -c conda-forge fbprophet==0.6

#環境がminicondaなので・・(numpyやpandasは↑でたまたま一緒に導入されたので個別には入れなかった)
conda install matplotlib
```

下記コマンドでエラーが出なければ導入成功

```Python:
from fbprophet import Prophet
```

#5.実際に使ってみる

今回はサンプルデータセットとしてシンプルな「AirPassengers」というデータセットを使用する
Monthカラムに時系列部分、Passengersカラムに飛行機乗客数の推移が入っている。
[データセットのリンク](https://www.analyticsvidhya.com/wp-content/uploads/2016/02/AirPassengers.csv)

| Month |#Passengers  |
|---|---|
|1949/1/1  |112  |
|1949/2/1 |118  |
|1949/3/1 |132  |

### 5-1:ファイル読み込みまで

```Python:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from fbprophet import Prophet

#AirPassengersのcsvを読み取る
df = pd.read_csv('AirPassengers.csv')
```
### 5-2:Prophetを学習

```Python:
#Prophetではカラム名をdsとyに変更する必要があるので変更する
df.columns = ['ds', 'y']

#今回はProphetにデータフレーム後ろから10番目までを学習(fit)させる
m = Prophet()
m.fit(df[:-10])
```

### 5-3:Prophetで予測

```Python:
'''
periods=10：10マス分予測させる
freq='M'：単位は「Month」
　→つまり10か月分予測させるという意味
'''
future = m.make_future_dataframe(periods=10, freq='M')

forecast = m.predict(future)

#forecastの結果を図示する
fig = m.plot(forecast)
```
↓のように表示されるはず。
※黒い点は学習データ
<img width="600" alt="追加されたkernel" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373060/2909b4df-1274-ec58-01f1-168a451a67f6.png">


#6.最後に
どうだっただろうか？
プログラム自体は簡単に動作するので、むしろ導入のほうが手こずるかもしれない。
バージョンが違ったりするとどこかでエラーになるかもしれないし、実際私も最初はそこで躓いた。
(PyStan、libpython等はfbprophet==0.6で一緒に導入されたので最終的には個別では導入しなかった)
お手軽なのでぜひ試してみてほしい。
E45: 'readonly' option is set (add ! to override) が出た場合に保存する方法

## E45: 'readonly' option is set (add ! to override)が出たら
パニックになったのでメモ。

- 入力モードをescで抜ける


- コマンドモードで下記を実行

```
:w !sudo tee %
```

- 強制脱出

```
:q!
```

上書き完了
Airpodsの充電残量をMacでわかりやすく表示する。

　最近はオンラインでの働きからも増えてきて、AirPodsを常につけながら働いている人も多いのではないでしょうか。
　そこで、Macにペアリングしている時のAirPodsの充電残量をわかりやすく表示してくれるアプリの紹介をします。

このような形で表示されます。アイコンが可愛いです。

![スクリーンショット 2020-11-07 19.08.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663044/46d5adff-e76c-a26b-2ea9-51d0b29f843c.png)

インストールはこちらからお願いします。
[Battery Stats for AirPods](https://apps.apple.com/jp/app/battery-stats-for-airpods/id1405763798?mt=12)

他のアプリだと、
[AirPods Battery Monitor For MAC OS](https://github.com/mohamed-arradi/AirpodsBattery-Monitor-For-Mac)
も個人的にアイコンが可愛くて良いなと思いました。
Azure Storageへのファイルアップロード（Python）

## Azure Storageへのファイルアップロードの手順
Azure Storageへのファイルアップロード方法を以下に記載します。

# 前提条件
以下の環境にて、構築しております。

OS: Windows10
言語：Python 3.8.6

Azure環境があること
Azureの"ストレージアカウント"サービスにて、新規アカウントを作成していること

# アップロード手順
①Python用のAzure Storageパッケージをインストールする。
 $ py -m pip install azure-storage-blob == 12.5.0

② Azure ポータルにて、"ストレージアカウント"サービスから、Blob service → コンテナーを選択する。
  その後、接続文字列を確認する。

③ 以下のプログラムが記載された"sample_upload.py"を実行する。
  なお、実行位置に"Hello World.txt"(中身は自由)を配置しておくこと。

  $ py sample_upload.py

  ※ファイル内の以下の箇所を自身の環境に合わせて変更してください。
　　<接続文字列>, <コンテナ名称>, <アップロード先のフォルダ名称>
  
```
from azure.storage.blob import BlobServiceClient, BlobClient, ContainerClient, __version__

# Azure Storage上にて、接続文字列を確認する。
connect_str = <接続文字列>

# Create a file in local data directory to upload and download
container_name = "<コンテナ名称>"

# Azure Storage内は厳密には、フォルダという構成ではない。
# 一応 "\"区切りをすることで、疑似的にフォルダ構造を実現することは可能
upload_path = "<アップロード先のフォルダ名称>\"

# アップロードするファイル名(実行位置によって、相対ファイルパスを記載すること)
local_file_name = "HelloWorld.txt"

# アップロード先
upload_file_path = os.path.join(upload_path, local_file_name)

# 自身のAzure Storageに接続するためのインスタンスを作成する。
blob_service_client = BlobServiceClient.from_connection_string(connect_str)

# Azure Storageの指定コンテナに接続するブロブ（ファイル）のクライアントインスタンスを作成する。
blob_client = blob_service_client.get_blob_client(container=container_name, blob=local_file_name)

print("\nUploading to Azure Storage as blob:\n\t" + local_file_name)

# Azure Storageへのアップロード
with open(upload_file_path, "rb") as data:
    blob_client.upload_blob(data)
```

## 参考文献
Azure公式ドキュメント Pythonリファレンス BlobServiceClientClass
<https://docs.microsoft.com/en-us/python/api/azure-storage-blob/azure.storage.blob.blobserviceclient?view=azure-python>
JavaScript: 順列 / 組み合わせ / 重複順列 / 重複組み合わせ を まとめて関数にしてみた。

[前にも同じような記事](https://qiita.com/ttatsf/items/200fe1ba765108ba502f)を書いたけど、考えてみれば 重複順列 / 重複組み合わせ も一緒だなあと思い、まとめてみました。
## 関数版

```js
// 共通の内部再帰関数
const innerPC = filterFunc => selecteds => k => options =>  
  (k === 0)? [selecteds]
  : options.flatMap(
      (e, i) =>
        innerPC( filterFunc )( [...selecteds, e] )( k-1 )( filterFunc(i)(options) ) 
    )

// 順列
const permFilter = i => options =>
  [...options.slice(0, i), ...options.slice(i + 1)]
const perm =  
  innerPC( permFilter )( [] )

// 組み合わせ
const combiFilter = i => options =>
  options.slice(i + 1)
const combi = 
  innerPC( combiFilter )( [] )

// 重複順列
const repPermFilter = i => options =>
  options
const repPerm = 
  innerPC( repPermFilter )( [] )

// 重複組み合わせ
const repCombiFilter = i => options =>
  options.slice(i)
const repCombi = 
  innerPC( repCombiFilter )( [] )

// 使用例：
perm(2)([0, 1, 2])  
/*
[ [ 0, 1 ], [ 0, 2 ], [ 1, 0 ], [ 1, 2 ], [ 2, 0 ], [ 2, 1 ] ]
*/
combi(2)([0, 1, 2])  
/* 
[ [ 0, 1 ], [ 0, 2 ], [ 1, 2 ] ]
*/
repPerm(3)([0, 1])  
/*
[ [ 0, 0, 0 ],
  [ 0, 0, 1 ],
  [ 0, 1, 0 ],
  [ 0, 1, 1 ],
  [ 1, 0, 0 ],
  [ 1, 0, 1 ],
  [ 1, 1, 0 ],
  [ 1, 1, 1 ] ]
*/
repCombi(3)([0, 1]) 
/*  
[ [ 0, 0, 0 ], [ 0, 0, 1 ], [ 0, 1, 1 ], [ 1, 1, 1 ] ]
*/
```
## ジェネレータ版

```js
const innerPCG = filterFunc => selecteds => k => options => function*(){
  if(k===0){ 
    yield  selecteds
    return
  }
  for(const i of options.keys()) {
    yield* innerPCG( filterFunc )( 
      [...selecteds, options[i]] )( k-1 )( filterFunc(i)(options) )
  }
}()

// 順列
const permFilter = i => options =>
  [...options.slice(0, i), ...options.slice(i + 1)]
const permG =  innerPCG( permFilter )( [] )

// 組み合わせ
const combiFilter = i => options =>
  options.slice(i + 1)
const combiG = innerPCG( combiFilter )( [] )

// 重複順列
const repPermFilter = i => options =>
  options
const repPermG = 
  innerPCG( repPermFilter )( [] )

// 重複組み合わせ
const repCombiFilter = i => options =>
  options.slice(i)
const repCombiG = 
  innerPCG( repCombiFilter )( [] )

// 使用例：
;
[...permG(2)([0,1,2])];  
[...combiG(2)([0,1,2])];
[...repPermG(3)([0,1])];
[...repCombiG(3)([0,1])];
// 結果はそれぞれ関数版に同じ
```

おかしなところがあれば、コメントよろしくです。
python3で　import cv2   ModuleNotFoundError: No module named 'cv2'

##概要
ちょっと動かしたいopencvを使ったpyhtonのプログラムがあったので、
以下の様に実行した。

```
python3 "動かしたいプログラム.py"
```
そうすると、次のようなエラーが出た

```
Traceback (most recent call last):
  File "動かしたいプログラム.py", line 21, in <module>
    import cv2
ModuleNotFoundError: No module named 'cv2'
```

##環境
- Ubuntu 18.04 64bit
- opencv 4.2.0
- python 3.6.9

## Solution

[Qiitaのこのページ](https://qiita.com/fiftystorm36/items/1a285b5fbf99f8ac82eb)を参考に、以下のコマンドを実行した。

```
pip install opencv-python
```

で、もう一度importできるかどうか確認

```
>>> import cv2
>>> print( cv2.__version__ )
4.4.0
>>> 

```
できた。

昨日寒かったなあ
2020年11月7日
obnizってフロントエンド側からどうつなぐのか？メモ(ml5.js)

#やろうとしてたこと
ml5.jsのImageClassifierで画像を分類→読み取った値が「酔っ払い」だったらobnizでライトをつける。

分類するJSはhtml内に記載されている。

#結果
フロントエンドからの呼び出し自体はnode.jsの時とほぼ同じ。
srcの指定を入れる必要があった。（最新のバージョンだとなぜかコンソール上に404のエラーが。。。これも原因だったのかも。）

```javascript
<script src="https://unpkg.com/obniz@2.0.0/obniz.js"></script>
```

vue.js内で関数Aから関数Bを呼び出すのがうまくいっていなかった。

vue.js内で、obniz.onconnect = async function () {}みたいな感じで呼び出そうとしていたが、
そこに処理が入っていなかった。

そもそも、vue.jsの外側でobnizを接続状態にしておいたらうまくいった。
なぜ。。。
AndroidでJNetHackをプレイしたいのです！！

# はじめに
Qiitaに投稿してよいのかどうか迷いましたが、
毎回お世話になっておりますので、投稿することにしました。
初めての投稿になりますので、色々と見づらいとかおかしな所があったりするかもしれませんが指摘くだされば訂正していきたいと思います。

今回、手持ちのスマートフォンを新しい機種へ変更したので、
内部ストレージに余裕が出来ました。
で、度々訪れるJNetHackをプレイしたい欲求が湧いてきました。
5年位前にもアンドロイドにインストールしましたが、その時よりすごく簡単に
インストールする事が出来て幸せです。

補足ですが、AndroidでJNetHackをプレイするのにルート化は不要です。
2025/01/17
JNetHack367をコンパイルするための追記
## 準備

[Termux](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwiE2tre-O_sAhXa62EKHSj5AnwQFjAAegQIBxAC&url=https%3A%2F%2Fplay.google.com%2Fstore%2Fapps%2Fdetails%3Fid%3Dcom.termux%26hl%3Dja%26gl%3DUS&usg=AOvVaw22ol9j76oz9viV-gLCv8bI)をインストールした後、下記コマンドを実行
テキストエディタは好きなもので構いません。

```
$ pkg upgrade
$ pkg install clang make bison flex gzip wget vim ncurses-ui-libs
```
lexコマンドが無いのでリンクを張っておく※ファイルを編集すればリンク不要(後述します)

```
$ ln -s /data/data/com.termux/files/usr/bin/flex /data/data/com.termux/files/usr/bin/lex
```
nkfをコンパイルしてインストール
※osdnからダウンロード出来なかったからiijへ変更
```
$ wget https://ftp.iij.ad.jp/pub/sourceforge.jp/nkf/70406//nkf-2.1.5.tar.gz
$ tar zxvf nkf-2.1.5.tar.gz
$ cd nkf-2.1.5
```
vimで**Makefile**と**config.h**を編集
テキストが編集出来たら何を使っても良いです。

**Makefile**
プリフィックスを変更

```
prefix = /data/data/com.termux/files/usr
```
**config.h**
デフォルトコードUTF8のコメントをはずす

```
#define DEFAULT_CODE_UTF8
```
make installしてルートに戻る

```
$ make
$ make install
$ cd ../
```
これで、準備は完了しました。

### NetHackとJNetHackパッチファイルをダウンロード
ダウンロードして展開し、パッチを当てます。

```
$ wget https://ftp.jaist.ac.jp/pub/sourceforge.jp/jnethack/78334/jnethack-3.6.7-0.1.diff.gz
$ wget https://www.nethack.org/download/3.6.7/nethack-367-src.tgz
$ tar zxvf nethack-367-src.tgz
$ cd NetHack-NetHack-3.6.7/
$ zcat ../jnethack-3.6.7-0.1.diff.gz | patch -p1
```

ファイルの編集

```
$ vim sys/unix/hints/linux
```
libiconvを追加します。
```
WINTTYLIB=-lncurses -ltinfo -liconv
```

下記フォルダが間違っていたので訂正しました。
```
$ vim sys/unix/Makefile.utl
```
flexとbisonを検索しコメントとアンコメントします。※lexコマンドをリンクしていたら不要
```
#YACC     = yacc
#LEX      = lex
YACC     = bison -y
#YACC     = byacc
LEX      = flex
```

```
$ vim util/recover.c
```
configureしてもインストール時にエラー出るのでエラー出る行（209行目）コメント
```
/*    fd = creat(savename, FCMASK);*/
```
configureしてインストール

```
$ sh ./configure
$ make install
```
起動します。

```
$ cd ../
$ nh/install/games/jnethack
```
無事に起動しました。
気になるのが、ステータスが変換されていない事ですが、
普通にプレイできるのでよしとします。
![Screenshot_20201106-222845.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211553/f9bfe8c9-d3d5-62e5-263e-251567b3e1d2.png)
#### まとめ
今回の記事を書くときに以前使用していたスマホでも確認しながら編集しました。検証環境を記載しておきます。

【検証環境】
Xperia10VI(SO-52E)/android15
Xperia10ii(SO-41A)/android10
nova lite(PRA-LX2)/android8
順次セル選択して文字列変換してCBに格納

## 概要
- UI都合で改行を含む文字列の編集が難しいアプリケーションを使う際の効率化マクロ。
- Excelを下書きとして使ったり、既存の文書があってそれをコピペしたい時に使う。
- アプリケーション独自の改行コードがある場合、それに合わせて改行コードを変換してCBに格納できる。
- ペーストはCtrl+Vでも良いが1つずつウインドウを往復するのが面倒なのでWin+Vがおすすめ。

## 使い方
1. InputBoxが出てくるのでセルを選択し実行
2. Win+VでCBに格納された変換後の文字列を順に貼り付ける

## コード
``` vb
Option Explicit
  '適宜変更
    Const 変換対象文字 As String = vbLf
    Const 変換文字 As String = "\"
    Const 待ち時間 = 300 'ミリ秒
    

Sub 順次セル選択して文字列変換してCB格納()
    Const 分母 = 86400000 '待ち時間のミリ秒変換分母

  'InputBox用の説明文
    Dim Cmt(8)
    Cmt(0) = "「" & 変換対象文字 & "」を「" & 変換文字 & "」に変換してクリップボードに格納します。"
    Cmt(1) = ""
    Cmt(2) = "セルを選択してください。"
    Cmt(3) = "（Ctrlで複数選択可能。ドラッグで範囲選択可能）"
    Cmt(4) = ""
    Cmt(5) = "実行後、Win+Vで順番にペーストできます。"
    Cmt(6) = ""
    Cmt(7) = "※待ち時間が短いとクリップボードに格納できない場合があります。"
    Cmt(8) = "  その際はVBEから待ち時間を調整してください。"
    Dim Prompt: Prompt = Join(Cmt, vbCrLf)
    Const Title = "順次セル選択→文字列変換→クリップボードに格納"
  
  
  'メイン
    On Error GoTo Err
    Dim rng As Range
    Set rng = Application.InputBox(Prompt, Title, Type:=8)
    rng.Select
  
  'いったん配列に格納
    ReDim Arr(rng.Cells.Count - 1)
    Dim c As Range, i As Long
    For Each c In rng.Cells
      Arr(i) = c.Value
      i = i + 1
    Next
    
  '仕上げ：CBに格納
    Dim ub
    ub = UBound(Arr)
    For i = ub To 0 Step -1 'CB順を選択順にするため逆順でループ
      Call CB格納(Arr(i), 変換対象文字, 変換文字)
      Application.Wait [Now()] + 待ち時間 / 分母
    Next
      
Exit Sub
Err:
  Select Case Err.Number
    Case 424
      Err.Clear
  End Select
End Sub

Private Sub CB格納(Target, 変換対象文字, 変換文字)
  Dim buf
  buf = Replace(Target, 変換対象文字, 変換文字)
  
  With New MSForms.DataObject
    .SetText buf      '変数の値をDataObjectに格納する
    .PutInClipboard   'DataObjectのデータをクリップボードに格納する
  End With

End Sub

```
シングルサインオン(Single Sign On, SSO) 概要

シングルサインオン(Single-Sign-On,SSO)の概要情報をまとめる。学習目的記事。

## シングルサインオン(Single-Sign-On)とは

* 1つのアプリケーションにログインした際に、そのアプリケーションに関連する他のアプリケーションを追加のログインなしで利用可能にする仕組み。
  * 1つの認証情報で複数のアプリケーションにログインできるようになる。
![SSO.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/8cbd5761-e4cc-6d72-4ba6-60ded07d4b70.png)


## シングルサインオンのメリット

* **ユーザビリティの向上**
  * ユーザーが管理する認証情報の数が少なくなる。
  * アプリ利用時に都度認証情報を入力する手間を省略できる。
* **認証情報管理リソースやコストの削減**
  * アプリ別に認証情報を管理するためのシステム構築する必要が無い。

## シングルサインオンのデメリット

* **SSOシステムに強固なセキュリティ対策が要求される**
  * SSOシステム自体に不正アクセスが行われた場合、システムの先にあるアプリ全てに不正アクセスできてしまう懸念があるため。

* **ユーザーが認証情報を漏洩させてしまった場合、重大なセキュリティリスクにつながる**
  

## シングルサインオンの概シーケンス(OAuth2.0)

* **用語**
    * **サービスプロバイダー(SP)**：ユーザーが利用するアプリケーション。
    * **IDプロバイダー(IdP)**:アプリケーションに代わり、認証処理を担うシステム。

![SSO_OAuth_sequence.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/f18e2b4e-02df-e534-fe65-872e5e6cb96d.png)



## 参考情報

* [シングルサインオン(SSO)とは](https://trustlogin.com/sso/)
* [シングルサインオン(Single Sign On)の仕組みとSSOサーバの役割](https://ruby-hankan.hatenadiary.org/entry/20081215/1229356404)
【Java SE 11 Silver】Arraysクラスのメソッドまとめ【Java初心者】

# はじめに
Java学習歴約3ヶ月です。
未経験からSESに入社し、Javaの研修を受けながら、
土日にちまちまと Java SE 11 Silver の勉強をしています。

会社の研修ではJava7までの内容だったので、初めての内容も多く、
今回は黒本第9章APIのArraysクラスのうち3つのメソッドについてまとめてみます。


#目次
[1.asListメソッド](#1asListメソッド)
[2.compareメソッド](#2compareメソッド)
[3.mismatchメソッド](#3mismatchメソッド)


# 1.asListメソッド
配列→リストに変換。
指定された配列に連動する固定サイズのリストを返す。
そのため追加（add）や削除（remove）ができない。
（追加や削除をしようとすると「UnsupportedOperationException」という例外がスローされる）

## List.of（Listインタフェースのofメソッド）との違い
どちらも固定長のリストを生成する。
asListは要素の変更（set）はできるミュータブル（可変）に対し、
List.ofは変更できないイミュータブル（不変）。


# 2.compareメソッド
2つの配列を辞書順（アルファベット順）に並べた時の並び順を比較する。
引数に渡した2つの配列が等しければ0を、
第1引数が第2引数よりも辞書順で先ならば負の値を、
第2引数の方が先ならば正の値を戻す。

### equalsメソッド
2つの配列が等しいかどうかを調べるメソッドで等しければtrueを戻す。


# 3.mismatchメソッド
引数で渡された2つの配列の要素を先頭から順番に比較。
最初に一致しなかった要素の添字（インデックス）を戻す。
全ての要素が一致する場合は-1を戻す。


##最後に
いずれもJava9で導入されたメソッドになります。
サンプルコードも載せられたらよかったと思いますが、
頭の中が整理できたのでよかったです。


## 参考
[Java SE 11 & JDK 11 Arrays](https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Arrays.html)
[徹底攻略Java SE 11 Silver問題集](https://www.amazon.co.jp/%E5%BE%B9%E5%BA%95%E6%94%BB%E7%95%A5Java-SE-11-Silver%E5%95%8F%E9%A1%8C%E9%9B%86-1Z0-815/dp/4295007625/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=292UROQ3DD33J&dchild=1&keywords=java+silver&qid=1604741554&sprefix=Java%2Caps%2C260&sr=8-1)
WSL2でスタートアップスクリプトを実行するHack

## 序論

WSL2 では起動時に systemd を自動スタートさせたり、`/etc/rc.local` によるスタートアップスクリプトの実行ができません。

Windowsスケジューラにスクリプトを登録するなど、回避策はありますが、筆者はなるべく Linux 環境内で設定を完結させたいと考えていました。

そのような訳で、WSL2 で Docker を使いたい場合、起動時にいちいち以下のようなコマンドを打っていました。

```bash
# dockerデーモン起動
$ sudo service docker start

# WSL2 には cgroup 用ディレクトリがデフォルトで作られていないため作成しておく
## これをしておかないと Docker でプロセスのグループ化が必要になったときにエラーが起きる
$ sudo mkdir -p /sys/fs/cgroup/systemd
$ sudo mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd
```

・・・面倒くさい。

ああ、面倒くさい。

そんな事を考えながらネットを彷徨っていると、[WSL2 が起動時に /sbin/mount -a を呼び出すことを利用した Hack](https://linux.srad.jp/story/20/06/25/1855205/) を発見し、感動したので共有します。

## Environment

- WSL2:
    - Guest OS: `Ubuntu 20.04 LTS`
    - Linuxカーネルバージョン: `4.19.121-microsoft-standard`

## WSL2用スタートアップスクリプト作成

仕組みとしては、WSL2 では起動時に `/sbin/mount -a` コマンドが呼び出されるため、これをフックすることで `/sbin/mount.rc` をスタートアップスクリプトとして使うことができる、ということのようです

WSL2内のLinuxターミナルで以下のように設定します

```bash
# /sbin/mount -a 実行時に rc ファイルシステムをマウントするように設定
$ echo 'none none rc defaults 0 0' | sudo tee -a /etc/fstab

# => これにより起動時に /sbin/mount.rc ファイルが呼び出されるようになる

# /sbin/mount.rc ファイルを実行可能スクリプトとして作成
$ echo '#!/bin/bash' | sudo tee /sbin/mount.rc
$ sudo chmod +x /sbin/mount.rc

# /sbin/mount.rc に実行権限が付与されているか確認
$ ll /sbin/mount.rc
-rwxr-xr-x 1 root root 12 11月  7 18:27 /sbin/mount.rc*
```

### 起動時に Docker サービスを開始するように設定
```bash
# service docker start を /sbin/mount.rc に追記
$ echo 'service docker start' | sudo tee -a /sbin/mount.rc

# WSL2 には cgroup 用ディレクトリがデフォルトで作られていないため、以下もスタートアップスクリプトに登録しておく
## これをしておかないと Docker でプロセスのグループ化が必要になったときにエラーが起きる
$ echo 'mkdir -p /sys/fs/cgroup/systemd && mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd' | sudo tee -a /sbin/mount.rc

# スタートアップスクリプト確認
$ sudo cat /sbin/mount.rc
#!/bin/bash
service docker start
mkdir -p /sys/fs/cgroup/systemd && mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd
```

### WSL2 を再起動して動作確認
WSL2 を再起動して動作確認してみます。

`Win + X` |> `A` キーで管理者権限 PowerShell を起動し、以下のようにコマンドを実行します。

```powershell
# WSL2 シャットダウン
> wsl --shutdown

# WSL2 起動
> wsl
```

```bash
# -- user@wsl2

# Docker サービスが起動しているか確認
$ sudo service docker start
 * Starting Docker: docker

# /sys/fs/cgroup/systemd に cgroup がマウントされているか確認
$ ll /sys/fs/cgroup/systemd
合計 0
dr-xr-xr-x  3 root root   0 11月  7 17:54 ./
drwxr-xr-x 17 root root 340 11月  7 17:54 ../
-rw-r--r--  1 root root   0 11月  7 17:54 cgroup.clone_children
-rw-r--r--  1 root root   0 11月  7 17:54 cgroup.procs
-r--r--r--  1 root root   0 11月  7 17:54 cgroup.sane_behavior
drwxr-xr-x  4 root root   0 11月  7 17:54 docker/
-rw-r--r--  1 root root   0 11月  7 17:54 notify_on_release
-rw-r--r--  1 root root   0 11月  7 17:54 release_agent
-rw-r--r--  1 root root   0 11月  7 17:54 tasks
```
〇〇インフォマティクス勉強のためのおすすめHPメモ

#はじめに
マテリアルインフォマティクスを進めるための情報収集・勉強のためのHPのまとめ
(2020/11/7 更新）

## ケモインフォマティクス関連
- [明治大学金子研究室HP](https://datachemeng.com/)  
一般的なデータ解析の流れ、予測モデルの紹介から、データ解析での化合物の取り扱い、解析のノウハウなど幅広い情報が網羅されている。オンラインサロンへ参加（無料）することで金子先生に直接質問することも可能。
- [Instruction of chemoinformatics](https://funatsu-lab.github.io/open-course-ware/)  
どちらかというと基礎的な内容で、環境構築・機械学習手法・評価指標などについて勉強できる。説明がかなり丁寧で分かりやすい。東京大学船津研究室によって運用されている。
- [化学の新しいカタチ](https://future-chem.com/)  
化学構造の取り扱いに関する記事や、pythonで量子化学計算が可能なライブラリ "Psi4" に関する記事が他HPと比べて多く、かなり化学よりの内容
- [計算化学.com](https://computational-chemistry.com/top/)  
量子化学計算に関する記事が主だが、機械学習を絡めた解析の紹介もある。月に2回注目論文BEST3の紹介があり、マテリアルズインフォマティクスの最新の技術動向を知ることができる。
- [PC CHEM BASICS.COM](http://pc-chem-basics.blog.jp/?p=13)  
量子化学計算に関する記事が充実
- [magattacaのブログ](https://magattaca.hatenablog.com/)
- [ぷんたむの悟りの書](http://punhundon-lifeshift.com/)
- [ご注文はリード化合物ですか？（〜医薬化学録にわ〜）](https://aimedchem.hatenablog.com/)

## データ解析関連
- [DATA SCIENCE LIFE](https://datawokagaku.com/)  
データサイエンス、GitHub、Docker に関する記事が充実
- [大学教授のブログ（データ分析相談所）](http://univprof.com/archives/16-07-19-4830239.html)  
データ解析手法や研究生活に関するブログ。データ解析手法のプログラムや教科書もnoteで公開。
ポップアップメッセージ

```css

body {
  padding: 64px;
}

.message {
  width: 300px;
  padding: 8px 16px;
  background: #2c2c2c;
  color: #ddd;
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, .2);
  position: fixed;
  right: 32px;
  bottom: 32px;

  animation: popup 2s forwards;
}

@keyframes popup {
  0% {
    transform: translateY(20px);
    opacity: 0;
    animation-timing-function: ease-out;
  }
  20%, 80% {
    transform: none;
    opacity: 1;
  }
  100% {
    transform: translateY(20px);
    opacity: 0;
    pointer-events: none;
  }
}

button {
  width: 300px;
  padding: 8px 16px;
  position: fixed;
  right: 32px;
  bottom: 32px;
}
```

```html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>My CSS Animation</title>
  <link rel="stylesheet" href="css/styles.css">
</head>
<body>
  <button>Click me!</button>
  <div class="message">Hello!</div>
  
  <script> </script>
</body>
</html>
```

デモ
http://samples.dotinstall.com/s/basic_css_animation_v2/51820/MyCSSAnimation/index.html
外部データベースのまとめ（ケモインフォマティクス ）

主にケモインフォマティイクスで活用できそうな外部データベースのまとめ。
### API利用などで一括取得が可能

- [Pubchem](https://pubchem.ncbi.nlm.nih.gov/)
 化合物のデータベース。(APIを使った自動取得が可能）
 (参考：[pubchem から化合物情報を一気に取得する](https://chemoinformatics.hatenablog.com/?_ga=2.245990092.912412993.1606735825-11600955.1508149107))

- [ChemSpider](http://www.chemspider.com/)
化合物のデータベース。(APIを使った自動取得が可能）

- [GDB-17,13,11](https://gdb.unibe.ch/downloads/)
GDB-11:C,H,N,O,F から構成される原子数（水素は除く)が11個の化合物のデータベース
GDB-13:C,H,N.O,D,Cl から構成される原子数（水素は除く)が13個の化合物のデータベース  

- [MoleculeNet](http://moleculenet.ai/datasets-1)
 機械学習による分子特性予測をテストするために設計されたベンチマーク用データセット。化学構造と量子化学計算出力値をまとめたデータセット(QM7, QM8, QM9）や
水溶解度（logP）のデータなどが収容。


### （おそらく）一括取得が不可
- [Polyinfo](https://polymer.nims.go.jp/)
高分子の物性に関するデータベース。利用するには登録が必要。スクレイピングなどのデータの一括取得は基本的には禁止されている。

- [Bordwell pKa Table](Bordwell pKa Table)
  pKa のデータベース。構造化データではないため解析に使用するにはデータの整形が必要。

### 調べる

- [CAS](https://www.cas.org/ja)
 アメリカ化学会が運営しているデータベース

- [PubChemQC](http://pubchemqc.riken.jp/)
 量子化学計算のデータベース

- [ZINC15](https://zinc15.docking.org/)
 バーチャルスクリーニング用途に市販化合物を集めたデータベース

- [ChEMBL](https://www.ebi.ac.uk/chembl/)
  化学構造と生物活性データを集めた、医薬品・医薬品候補化合物データベース

- [PDB](https://www.wwpdb.org/)
 タンパク質の立体構造データベース
- [CCDC](https://www.ccdc.cam.ac.uk/)
低分子や結晶構造のデータベース
- [SDBS](https://sdbs.db.aist.go.jp/sdbs/cgi-bin/cre_index.cgi?lang=jp)
 有機化合物のスペクトルデータベース

#参考
以下のHPの情報を使わせてもらいました。

-  [化合物データベースPubChemをpythonで使いこなす(化学の新しいカタチ)](https://future-chem.com/pub-chem-py/)
- [化合物のデータセット一覧(NoteBook)](https://insilico-notebook.com/db-ml-chem/)
DesignSPHysicsとは？

この投稿記事は、GitHub上の[DualSPHysics](https://github.com/DualSPHysics/DesignSPHysics#installation-instructions)にあるREADME.mdファイルを訳したものです。

DesignSPHysicsは、[FreeCAD](http://www.freecadweb.org/)に組み込まれたソフトウェアモジュールで、[DualSPHysics](http://dual.sphysics.org/)のグラフィカルユーザーインターフェイスを提供します。2016年9月から開発中で、ベータ版の段階です。

ダウンロードや詳細については、[公式Webページ](http://design.sphysics.org) を確認してください。

![Screenshot](https://design.sphysics.org/img/github-shot-21112019.png)

## 説明
DesignSPHysicsでは、固体と流体を使ったケースを作成し、DualSPHysicsに対応したフォーマットをエクスポートできます。さらに、ケースデータの自動生成、シミュレーション、ポスト処理など、ユーザーのためのハードワークをすべてFreeCAD内で行います。

GenCaseによる前処理、DualSPHysicsによるシミュレーション、DualSPHysicsパッケージのいくつかのツールによるポスト処理をサポートしています。

将来的には、コードはモジュール化され、異なるSPHソルバーとの統合が可能になります。今のところ、DualSPHysicsで使用するように最適化されています。

これは、PySide経由でQTライブラリを使用して、Python3.5以降でマクロブートストラッパー付きのFreeCADモジュールとして開発されています。

## インストール手順
DesignSPHysicsをインストールするには、2つの方法があります：安定版のFree CAD Addonマネージャーを使うか、gitから好きなバージョンを手動でインストールするかです。

### リリースバージョンのインストール
リリースバージョンをインストールするには、FreeCAD 0.18以降を開いて、メニューの*Macro -> Macros...*に進みます。そこから右下の*Addons...*ボタンを押し、DesignSPHysics を検索し、*Install / Update*をクリックします。FreeCADはアプリケーションを再起動するようにアドバイスし、そして、設定されます。

このパッケージにはDualSPHHysicsが含まれているため、ダウンロードに時間がかかる場合があることを注意してください。

DesignSPHysicsを実行するには、同じマクロダイアログを開き、DualSPHysicsをダブルクリックするだけです。

### 開発ビルドのインストール
このリポジトリから好きなブランチをクローンして、フォルダー名を「DesignSPHysics」に変更します。次に、そのフォルダーをFreeCADインストールディレクトリのModフォルダーにコピーします。

デフォルトでは、たとえば、Windowsでは、`%appdata%/FreeCAD/Mod`に、Linuxでは、`~/.FreeCAD/Mod`にあります

そして、このリポジトリのファイル`DesignSPHysics.FCMacro`をFreeCADマクロディレクトリ（Windowsでは、`DesignSPHysics.FCMacro`、GNU/Linuxでは、`~/.FreeCAD/Macro`）にコピーします。

## ヘルプを求める場所
[DesignSPHysics Wiki](http://design.sphysics.org/wiki)で調べてみるとよいでしょう。また、[issue here on GitHub](https://github.com/DualSPHysics/DesignSPHysics/issues)に投稿したり、[CONTRIBUTINGファイル](CONTRIBUTING.md)で見つけた人にメールを送信したりすることもできます。

## DesignSPHysicsへの貢献と開発
ご希望の方は自由に投稿していただいて構いません！ここではGitHub上で行うことができます。

プロジェクトへの貢献方法についての情報を表示するには、[CONTRIButeファイル](CONTRIBUTING.md) を確認してください。

## 著作権とライセンス
著作権 (C) 2019
EPHYSLAB Environmental Physics Laboratory（環境物理研究所）, Universidade de Vigo（ビーゴ大学）
EPHYTECH Environmental Physics Technologies（環境物理技術）

このファイルはDesignSPHysicsの一部です。

DesignSPHysicsはフリーソフトウェアです:フリーソフトウェア財団が公開しているGNU一般公衆利用許諾書のバージョン3、もしくはそれ以降のバージョンのいずれか（任意で）のGNU一般公衆ライセンスの条件のもとで、それを再配布および/または変更したりできます。

DesignSPHysicsは、お役に立てればと思って配布しています。ただし、いかなる保証もなく、商品性や特定目的への適合性についての暗黙の保証もありません。詳細はGNU一般公衆利用許諾書を参照してください。

GNU一般公衆ライセンスのコピーをDesignSPHysicsとともに受領したはずです。そうでない場合は、<http://www.gnu.org/licenses/>を参照してください。
Python 3で湯婆婆を実装してみる

# はじめに

原作者様: [Javaで湯婆婆を実装してみる - Qiita](https://qiita.com/Nemesis/items/c7192a7c510788d2cba2)

- [JavaScriptで湯婆婆を実装してみる - Qiita](https://qiita.com/hato-poppo/items/670d5186c2807a5f51b4)
- [バッチファイルで湯婆婆を実装してみる - Qiita](https://qiita.com/kshibamo/items/2e698a37d95652b22940)
- [monaca(JS)でAndroid版湯婆婆を実装してみる - Qiita](https://qiita.com/nakano1120/items/cbd34837ad8b18207637)
- [Discord Botで湯婆婆を実装してみる - Qiita](https://qiita.com/nekozuki_dev/items/485d47a459a63f59400f)

**令和のHello World!と呼びたい。**

このビッグウェーブに乗ってやる！
n番煎じ疑惑が否めないが。。。


# コード

f-string を使っているのでPython 3.6以降でお願いします。

```python3:yubaba.py
import sys
import random

print("契約書だよ。そこに名前を書きな。")
name = sys.stdin.readline().rstrip()
print(f"フン。{name}というのかい。贅沢な名だねぇ。")

newName = random.choice(name)

print(f"今からお前の名前は{newName}だ。いいかい、{newName}だよ。分かったら返事をするんだ、{newName}!!")
```

## 実行例

```
$ python3 yubaba.py
契約書だよ。そこに名前を書きな。
山田太郎
フン。山田太郎というのかい。贅沢な名だねぇ。
今からお前の名前は山だ。いいかい、山だよ。分かったら返事をするんだ、山!!
```

## クラッシュ湯婆婆

今のままでは名前が空白だと落ちます。
原作リスペクト


```
$ python3 yubaba.py
契約書だよ。そこに名前を書きな。

フン。というのかい。贅沢な名だねぇ。
Traceback (most recent call last):
  File "yubaba.py", line 8, in <module>
    newName = random.choice(name)
  File "/usr/lib/python3.6/random.py", line 260, in choice
    raise IndexError('Cannot choose from an empty sequence') from None
IndexError: Cannot choose from an empty sequence
```

# 今後の展望

Twitter Botとか作ってみたらいいんじゃないですかね。（コード書くよりアカウントの準備が面倒そう）
jetson nano上のDockerfileで、karaage0703さんのinstall-ros-melodic.shをRUNする際は事前にgnupg gnupg2 gnupg1のインストールが必要でした

jetson nano上のDockerfileで、karaage0703さんのinstall-ros-melodic.shをRUNする際は事前にgnupg gnupg2 gnupg1のインストールが必要でした

gnupg gnupg2 gnupg1なし版のDockerfile→これだとdocker build時にエラーになりました

```Dockerfile:Dockerfile
FROM nvcr.io/nvidia/l4t-ml:r32.4.4-py3
LABEL maintainer="seigot<s.takada.3o3@gmail.com>"

ENV DEBIAN_FRONTEND=noninteractive

# install basic package
RUN apt-get update && \
    apt-get install -yq wget curl git build-essential vim sudo lsb-release locales bash-completion tzdata \
    emacs \
    gosu \
    unzip \
    less

# install ROS
RUN git clone https://github.com/karaage0703/jetson-nano-tools /tmp/jetson-nano-tools && \
    gosu jetson /tmp/jetson-nano-tools/install-ros-melodic.sh
```

gnupg gnupg2 gnupg1あり版のDockerfile→インストール成功しました


```Dockerfile:Dockerfile
FROM nvcr.io/nvidia/l4t-ml:r32.4.4-py3
LABEL maintainer="seigot<s.takada.3o3@gmail.com>"

ENV DEBIAN_FRONTEND=noninteractive

# install basic package
RUN apt-get update && \
    apt-get install -yq wget curl git build-essential vim sudo lsb-release locales bash-completion tzdata \
    emacs \
    gnupg gnupg2 gnupg1 \
    gosu \
    unzip \
    less

# install ROS
RUN git clone https://github.com/karaage0703/jetson-nano-tools /tmp/jetson-nano-tools && \
    gosu jetson /tmp/jetson-nano-tools/install-ros-melodic.sh
```

# 参考
[Jetson NanoにROSをインストールする方法](https://qiita.com/karaage0703/items/aa54e086f0a2f165d3e9)
制限対象の非SDKインターフェースの使用をLogcatで調査する

## はじめに
2020年11月2日以降、 AndroidアプリのアップデートはAndroid10（APIレベル29）以上を対象にしなければなりません。
Android10にはアプリに影響を与える可能性のある動作変更点あると[公式ドキュメント](https://developer.android.com/about/versions/10/behavior-changes-10?hl=ja#non-sdk-restrictions)に書かれています。
その動作変更点のひとつに、**非SDKインターフェースに対する制限の更新**があります。
開発しているアプリが、制限されている非SDKインターフェースを使用していないか調査する必要があります。
そこで、この記事では制限対象の非SDKインターフェースの使用をLogcatで調査する方法について紹介します。

## 前提
### 開発環境
- Language：React Native
- PC OS：Mac OS Catarina 10.15.7
- Android OS：9, 10
- Java：Oracle Java 12

### 非SDKインターフェースのテスト方法は複数ある
- 非SDKインターフェースの使用を調べる方法は、[公式ドキュメント](https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces?hl=ja#test-for-non-sdk)で複数紹介されています。
    - デバッグ可能なアプリを使用したテスト
    - StrictMode APIを使用したテスト
    - veridexツールを使用したテスト
    - Android Studioのlintツールを使用したテスト
    - Play Consoleを使用したテスト
- この記事では**デバッグ可能なアプリを使用したテスト**について補足しながら紹介します。

## 調査方法
- 1. アプリをデバッグビルドする
- 2. 調査したいアプリのPIDを特定する

```
adb shell ps | grep <app name>
```

- 3. 特定したPIDでフィルターをかけてログ出力する

```
adb logcat --pid=<pid> | grep "Accessing hidden field"
```

- 4. アプリを操作し、以下のようなログが表示されなければ、制限対象の非SDKインターフェースは使用していないとのこと

```
Accessing hidden field Landroid/os/Message;->flags:I (light greylist, JNI)Accessing hidden field Landroid/os/Message;->flags:I (light greylist, JNI)
```

## 補足情報
### adbとは
adbとはAndroid Debug Bridgeの略で、Androidデバイスを通信するための多用途コマンドラインツールです。
adbコマンドを使用することで、さまざまなデバイス操作をコマンドラインから実行できます。
この記事では非SDKインターフェースの使用を調べるためにadbコマンドを使用します。

参考：https://developer.android.com/studio/command-line/adb?hl=ja

### shellコマンドとは
shellコマンドは、adbを介してデバイスコマンドを発行したり、対話型シェルを起動できます。
`adb shell ps`を使用すると、デバイスで実行中のプロセスを一覧で表示することができます。
今回は調査したいアプリのPID（プロセスID）を特定するために、アプリ名でgrepします。

参考：https://developer.android.com/studio/command-line/adb?hl=ja#shellcommands

### logcatコマンドとは
logcatコマンドは、デバイスが出力したシステムメッセージのログをダンプするコマンドラインツールです。
`adb logcat`で実行することができます。
logcatコマンドにはオプションが用意されていて、今回は特定のPIDでフィルターをかけるオプションを使用します。

参考：https://developer.android.com/studio/command-line/logcat?hl=ja

###
ローディングアニメーション

```html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>My CSS Animation</title>
  <link rel="stylesheet" href="css/styles.css">
</head>
<body>
  <div class="loading"></div>
  
  <script> </script>
</body>
</html>
```

```css
.loading {
  width: 40px;
  height: 40px;
  border: 8px solid #ccc;
  border-right-color: transparent;
  border-radius: 50%;
  
  animation: spin .8s infinite linear;
}

@keyframes spin {
  /* 0% { */
  from {
    transform: none;
  }
  /* 100% { */
  to {
    transform: rotate(360deg);
  }
}
```

デモ
http://samples.dotinstall.com/s/basic_css_animation_v2/51817/MyCSSAnimation/index.html