OmniAICreator/Qiita-1.07M huggingface dataset:
【クラウド初心者向け】Amazon Connectのルーティングプロファイル作成

# 概要
- この中から割り当てるユーザー（エージェント）が選択されます。
- ユーザー（エージェント）を束ねられます。
- ルーティングプロファイルには複数のキューを割り当てる事ができます。

## 使用ユーザー
-  IAMユーザー

## 手順
1. AWSにサインインします。
    1. アカウント、ユーザー名、パスワードを入力してサインインします。  
     [アカウント内（IAM）で作成したユーザーを使用してコンソールにサインインする](https://qiita.com/echolimitless/items/129495c920217916a14f#%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E5%86%85iam%E3%81%A7%E4%BD%9C%E6%88%90%E3%81%97%E3%81%9F%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E3%82%B3%E3%83%B3%E3%82%BD%E3%83%BC%E3%83%AB%E3%81%AB%E3%82%B5%E3%82%A4%E3%83%B3%E3%82%A4%E3%83%B3%E3%81%99%E3%82%8B)

1. 『AWSマネジメントコンソール』画面の右上にある《リージョン名》をクリックし、ドロップダウンます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/02487090-54eb-e851-6d7a-674e88da61c9.png)

1. 『AWSマネジメントコンソール』画面にある「サービスを検索」にConnectと入力し、検索結果から《Amazon Connect》をクリックし、Amazon Connect コンソール[（https://console.aws.amazon.com/connect/）](https://console.aws.amazon.com/connect/)を開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/28aff404-d3ae-b201-9ebb-b9839bde6ebf.png)

1. Amazon Connectのインスタンス一覧が表示されるので、該当のインスタンスをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/5846170a-bf01-6560-6687-9f970722c1bb.png)

1. インスタンスの概要が表示されるので《管理者としてログイン》をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/46c1f25e-b2e2-65ce-7972-1aa73f8441cb.png)

1. ダッシュボードの左側のメニューから《ルーティングプロファイル》をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/ca3a32f7-2da9-dd50-15d0-a0c19bc5be33.png)

1. 《新しいプロファイルを追加》をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/2d9833e2-a2fc-f2a9-56db-8428809175f3.png)

1. 以下の項目を入力、選択し、《新しいプロファイルを追加》をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/ccd6c6f4-92da-f08c-ad22-af3f9c3e8789.png)
    1. 名前：適当な名前を入力します。
    1. 説明：適当な説明を入力します。
    1. Set channels and concurrency：Voiceを選択します。
    1. ルーティングプロファイルのキュー：[【クラウド初心者向け】Amazon Connectのキュー作成](https://qiita.com/echolimitless/items/87bd5c69d771c77bdb73)で作成したキューを選択します。
    1. デフォルトのアウトバウンドキュー：[【クラウド初心者向け】Amazon Connectのキュー作成](https://qiita.com/echolimitless/items/87bd5c69d771c77bdb73)で作成したキューを選択します。

1. 登録が完了し、ルーティングプロファイルが一覧に表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/1e87995d-54b6-80f4-5bb9-f1eaacd5cfec.png)

# 目次に戻る
- [【クラウド初心者向け】Amazon Connectでコールセンターを作る](https://qiita.com/echolimitless/items/e5044c73656f8ae29f93#%E7%9B%AE%E6%AC%A1)
pytestの超基本の使い方

# pytestの使い方ノート

pytestを触ってみたので、そのノート。

## pytestとは

Pythonのテストフレームワーク
[pytest: helps you write better programs ? pytest documentation](https://docs.pytest.org/en/latest/)

## pytestをインストールする

普通にpipからインストールすればOK

```bash:pytestのインストール
pip install pytest
```



## pytest用のテストを書く

基本的な書き方は下記。

- Pythonのプログラムとして書く
- テストとして実行する部分を下記のいずれかで書く
  - 先頭が`test_`で始まる関数にする
  - 先頭が`Test`で始まるクラスの`test_`で始まるメソッドにする
- 結果がOKかNGかは、`assert 条件式`の結果がTrueかFalseかで判定される
  - `return`じゃないよ、`assert`だよ



### テストする側とされる側のサンプル

テストする側（pytestから実行するプログラム）

```python:test_program.py
from my_funcs import add, sub


def test_add():
    assert add(1, 2) == 3


def test_sub():
    assert sub(3, 1) == 2


class TestCase:
    def test_true(self):
        assert True

    def test_add_zero(self):
        assert add(1, 0) == 1
```

テストされる側

```python:my_funcs.py
def add(a, b):
    return a + b

def sub(a, b):
    return a - b
```



## pytestを実行する

普通に`pytest`を実行すると、カレントディレクトリの中で
ファイル名が`test_`で始まるファイルか、`_test`で終わるファイルを自動で実行する。

```bash:pytestを実行する
pytest
```



### テストプログラムを指定する場合

`pytest テストする側のプログラム名`で指定したテストのみが実行される。

```bash:ファイルを指定してpytestを実行する
pytest test_program.py
```



## 実行結果の見方

### テストにパスした例

- 最初にヘッダーがあって、その後に結果が`ファイル名 ..`の書式で続く
- この`.`の一つ一つがテスト関数での`結果＝OK`に対応する
- 末尾にパスした個数が表示されて終了

```text:実行結果
==================================== test session starts ====================================
platform linux -- Python 3.6.3, pytest-5.3.0, py-1.8.0, pluggy-0.13.1
rootdir: /mnt/c/Users/nab391/pytest
collected 2 items

test_example1-1.py ..                                                                 [100%]

===================================== 2 passed in 0.02s =====================================
```

### テストでこけた例

- 最初にヘッダーがあって、その後に結果が`ファイル名 ..`の書式で続くのは同じ
- パスしなかったテストは`F`が表示される
- その後、`FAILURES`にパスしなかった箇所が表示される
- 末尾にOKとNGの個数とが表示されて終了

```text:テストNG
==================================== test session starts ====================================
platform linux -- Python 3.6.3, pytest-5.3.0, py-1.8.0, pluggy-0.13.1
rootdir: /mnt/c/Users/nab391/pytest
collected 3 items

test_example1-1.py ..F                                                                [100%]

========================================= FAILURES ==========================================
________________________________________ test_false _________________________________________

    def test_false():
>       assert False
E       assert False

test_example1-1.py:14: AssertionError
================================ 1 failed, 2 passed in 0.08s ================================
```


## 実行オプション

- `-s`：標準出力を出力する（デフォルト：しない）
- `-v`：結果の詳細を出力する（デフォルト：しない）

```text:詳細出力の例
test_example1-1.py::test_add PASSED                                                   [ 50%]
test_example1-1.py::test_sub PASSED                                                   [100%]
### 実行結果の見方
```
【クラウド初心者向け】Amazon Connectのキュー作成

# 概要
- お客様の電話がユーザー（エージェント）に接続されるまで待機している場所になります。
- キュー内の優先順位はキューに入ってきた順です。
- ルーティングプロファイルを割り当て、空いているユーザー（エージェント）に電話を転送します。

## 使用ユーザー
-  IAMユーザー

## 手順
1. AWSにサインインします。
    1. アカウント、ユーザー名、パスワードを入力してサインインします。  
     [アカウント内（IAM）で作成したユーザーを使用してコンソールにサインインする](https://qiita.com/echolimitless/items/129495c920217916a14f#%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E5%86%85iam%E3%81%A7%E4%BD%9C%E6%88%90%E3%81%97%E3%81%9F%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E3%82%B3%E3%83%B3%E3%82%BD%E3%83%BC%E3%83%AB%E3%81%AB%E3%82%B5%E3%82%A4%E3%83%B3%E3%82%A4%E3%83%B3%E3%81%99%E3%82%8B)

1. 『AWSマネジメントコンソール』画面の右上にある《リージョン名》をクリックし、ドロップダウンます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/02487090-54eb-e851-6d7a-674e88da61c9.png)

1. 『AWSマネジメントコンソール』画面にある「サービスを検索」にConnectと入力し、検索結果から《Amazon Connect》をクリックし、Amazon Connect コンソール[（https://console.aws.amazon.com/connect/）](https://console.aws.amazon.com/connect/)を開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/28aff404-d3ae-b201-9ebb-b9839bde6ebf.png)

1. Amazon Connectのインスタンス一覧が表示されるので、該当のインスタンスをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/5846170a-bf01-6560-6687-9f970722c1bb.png)

1. インスタンスの概要が表示されるので《管理者としてログイン》をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/46c1f25e-b2e2-65ce-7972-1aa73f8441cb.png)

1. ダッシュボードの左側のメニューから《キュー》をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/9b5d96d2-bd59-0a3d-7aa0-fa995052bb0c.png)

1. 《新しいキューの追加》をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/f65a6141-0d39-01c5-28eb-71ec5b6c0b4f.png)

1. 以下の項目を入力、選択し、《新しいキューの追加》をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/5c8cf1cd-643c-7233-6258-f77b170732d7.png)
    1. 名前：適当な名前を入力します。
    1. 説明：適当な説明を入力します。
    1. オペレーション時間：デフォルトで用意されているBasic Hoursを選択します。  
      （利用しませんが何か指定しないといけないため指定する）
    1. アウトバウンド発信者ID番号：[【クラウド初心者向け】Amazon Connectの電話番号取得](https://qiita.com/echolimitless/items/8005138dfd337cf6b34e)で取得した電話番号を選択します。  
     （外線転送した場合にこの番号が外線転送先に通知されます）

1. 登録が完了し、キューが一覧に表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/e184f608-8101-7e82-222d-cb124df4c040.png)

# 目次に戻る
- [【クラウド初心者向け】Amazon Connectでコールセンターを作る](https://qiita.com/echolimitless/items/e5044c73656f8ae29f93#%E7%9B%AE%E6%AC%A1)
Rails server(Rails s)が再起動できない！　問題内容と解決法について

Rails server（以下、Rails s)に関する、バグが発生しましたので、内容と解決法を以下に纏めます。
皆様の参考になれば、幸いです。

#問題内容
-内容:
Rails sを再起動しようとしたところ、既にサーバーがあり起動できないという問題
-背景/詳細:
binding.pry使用中、exit！・ctrl+c等をコマンドしてもなぜかループから抜けられない。
=>ターミナルを消してrails sを再起動して使用を試みる。
=>既にサーバーがあるとの文言があり、起動できないとのこと。

以下のような状況でした。

```:terminal
rails s
=> Rails 5.0.7.2 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
A server is already running. 
```

#解決方法
結論、lsofコマンドを使用し、該当のPIDをキルして解消しました。
詳細を以下に記載していきます。

##lsofコマンドを使用して状況を確認
今回はlocalhost:3000使用していたので、$ lsof -i:3000と記載してチェックします。
以下のように「34139」が既に存在していることがわかります。
このタスクが切れてないのが問題の原因であることが、明白になりました。

```:terminal
$ lsof -i:3000
COMMAND    PID    USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
ruby      34139  
ruby      34139 
```

##該当のPID番号をキルして解消
それでは上記で確認できたタスクを削除します。

```:terminal
$ kill 34139
```
*念のため、再度状況を確認。何も動いていない状況であることが確認できました。
 これで、再度「rails s」を使用することができます。
*上記でまだプロセスを終了できていない場合は、以下のように「−９」を追記して試してみてください。

```:terminal
$ kill -9 34139
```

```:terminal
$ lsof -i:3000
```

###因みに。。lsofコマンドについて
今回使用したlsofコマンドについて、調べてみましたので、以下に記載しておきます。
詳細は参照ページを確認頂けますと幸いです。

オプション|意味
---|---
-a|複数のオプションを指定した際に、AND（かつ）の意味で機能させる
-P|ポート番号をサービス名に変換しない
-c|プロセス名を指定する
-i|ネットワークソケットファイルを指定する
-n|IPアドレスを表示する（名前解決しない）
-p|プロセスIDを指定する
-u|ユーザー名を指定する

項目|意味
---|---
COMMAND|実行されているコマンド名
PID|プロセスID
USER|ユーザー名
FD|ファイルディスクリプタ
TYPE|種類
DEVICE|デバイス
SIZE/OFF|ファイルサイズ
NODE|iノード番号(プロトコル）
NAME|ファイル

以上となります。最後までご覧いただき、ありがとうございました！
今後も学習した事項に関してQiitaに投稿していきますので、よろしくお願いします！
記述に何か誤りなどございましたら、お手数ですが、ご連絡いただけますと幸いです。

####参照
Linux基本コマンドTips一覧
https://www.atmarkit.co.jp/ait/articles/1904/18/news033.html
【記事散乱から卒業】目的別に記事をリスト化できるサービスを開発してみた

**「散らばった情報を自分の切り口でリスト化して、みんなにシェアできるサービス」** をリリースしました！

毎日新しい情報が、莫大に発信されていて、自分の求めている情報はすぐに埋もれてしまいます。また、自分と同じような情報を求めている人も他にいるのに、その人たちも、良質な情報を求めて、同じように莫大な情報を掻き分けて、宝探しをしています。

このような作業の重複を改善するために、[Ownlist](https://ownlist.me)というサービスを作りました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185039/a2004092-ddce-6d7d-e399-cb39c1ffb8e8.png)

(このサービスの特徴となる機能を作る上で参考にした情報を添付しておいたので、興味のある方は、ご覧ください。)

## こんな人に使って欲しい
- エラー対応で使った記事を再び探すことがある人
- 勉強の参考にした記事をストックしておきたい人
- 「後で読む」とブックマークしたが、それらが散乱してしまっている人
- インプットに使った記事を他の人にシェアしたい人

## 開発言語
- フロント
    - JavaScript(Vue.js)
- バックエンド
    - Python(Flask)

## 特徴①時系列でまとめたリストが表示される
作成したリストは時系列順に並びます。

1ヶ月前、1年前に「勉強のため」「エラー解決のため」などにまとめたリストが見返しやすい状態で表示されます。
自分の振り返りに使っても良いでしょうし、後輩や同僚に過去の参考になった記事を目的ごとにまとめてシェアできます。

![04b0f7dc17873de63f206e5032739759.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185039/2c1df47b-07bd-634b-ccc1-1e8618863e78.gif)

[時系列で表示するために参考にした記事リスト](https://ownlist.me/list/gQTl5uyveLLZ)


## 特徴②まとめる目的をタイトルに付ける必要がある
「後で読むからとりあえずブックマーク！」「良さそうな記事だからとりあえずslackでシェア！」など、なんとなく良さそうだからとか、何かのランキング上位の記事だから、という理由で、ストックしたりシェアしたりする人もいると思います。

ただ、それらをシェアされた側の人や後から見返した自分は、 **なぜ、これらが重要だと感じたのか** がわからなくなってしまうことは、少なくありません。

なので、ブックマークする前、シェアする前に、 **どんな目的でこの記事が役立つのか** を明記してまとめておくことで、読むべき理由を知らせることができ、より有益な情報になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185039/b900c68b-2ffc-3553-b27a-4fb7bf55dab0.png)

[Vue.jsを勉強するために参考にしたページ](https://jp.vuejs.org/v2/guide/index.html)

## まとめ
流れてきた記事をなんとなくブックマークしてしまっていた人、過去見た記事と同じ内容の記事を求めてネットの世界で迷子になっていた人、勉強の記録をつていなかった人などの、情報集積をないがしろにしてきた方に **自分のため** と **仲間のため** に使っていただきたいサービスです。


[ownlistはこちら](https://ownlist.me)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185039/6c4651d1-eeb0-7c3e-f0fa-d1c6f697258b.png)
qpdfを使って、pdfファイルのパスワードを削除する方法

#前提条件
homebrewで、qpdfをインストールする。
```brew install qpdf```

パスワードを解除したいpdfファイルのパスワードがわかっている。

#コマンド
ターミナル上で、以下を実行する。
```qpdf --password=<pdfファイルのパスワード> --decrypt <original_name>.pdf <decrypt_name>.pdf```

これで、元のpdfファイルが、パスワードを削除された状態で複製される。
ubuntu上のapache2で公開するディレクトリを変更する方法

### 背景
/var/www/html内の作業していましたがサイトの内容をリセットすることにしました。リセットするにあたってついでに作業ディレクトリも変更しようと思い立ち解決策を探しました。

###環境
1. Windows Subsystem for Linux (ubuntu18.04LTS)

### 解決方法
以下のファイルを編集(170行目くらい）

```/etc/apache2/apache2.conf
#デフォルトで定義されていたディレクトリ
#<Directory /var/www/html>
 #Options Indexes FollowSymLinks
 #Allow Override None
 #Require all granted
 #EnableSendfile off
#</Directory>

#新たに定義したいディレクトリ
<Directory /home/"user"/html>
 Options Indexes FollowSymLinks
 Allow Override None
 Require all granted
 EnableSendfile off
</Directory>
```

以下のファイルも編集

```/etc/apache2/sites-enabled/000-default.conf
#DocumentRoot /var/www/html
DocumentRoot /home/"user"/html
```

以下のコマンドでapacheを再起動
service apache2 restart

###蛇足
ネットで調べるとhttpd.confに関するものが多くて「そんなファイルないぞ！」と途方に暮れていました。
今は WSL → Windows10 間での通信しかしていないのでセキュリティに関する設定はまったく気にしていませんが、今後AWS上で公開するときにはapache2.conf内のオプションについて勉強する必要がありますね。
isoをマウントする

##isoをマウントするには？
###mountコマンドの利用
Linuxではmountコマンドを使用します。
しかし、サーバにcdromやmediaを搭載するディレクトリがあるとは限りません。
存在しない場合はディレクトリから作成し、作成したディレクトリへisoをテラタームなどを用いて転送します。
サーバにisoを持ってきた後、isoマウントする方法をここでは説明します。

①まず、現在のディレクトリ内にisoファイルが存在することを確認します。

```
# ls -l /media
-rw-r--r--. 1 root root 531628032  4月 17  2019 CentOS-7-x86_64-NetInstall-1810.iso
```

②次に対象のisoをマウントします。

```
[定型文]
# mount -t iso9660 <isoイメージファイル> <マウント場所>

# mount -t iso9660 /dev/cdrom /media
```
③マウントされたのか、dfコマンドにて確認します。

```
# df -T
```


##アンマウントされるには？
###umountコマンドの利用

```
[定型文]
# umount <アンマウントするディレクトリ>

[使用例]
# umount /media
```

##引用
DVD-ROMイメージファイルをマウントしてデータを参照
>http://ossfan.net/setup/linux-17.html

isoイメージをマウントする方法
>https://www.server-memo.net/memo/iso-mount.html

以上がisoのマウント方法でした。
最後までお読みいただきありがとうございました！
JavaScriptで連想配列をつくる方法

##連想配列
連想配列は普通の配列と違い、数字だけでなく文字列も添字にして使うことができます。連想配列の添字は、keyと言います。
JavaScriptでは、Mapオブジェクトを提供しているので、それを使います。


```JS
const myMap = new Map();

let keyString = "文字列",
    keyObj = {},
    keyFunc = function() {};

// 値を設定（追加）する
myMap.set(keyString, "'文字列' と関連付けられた値");
myMap.set(keyObj, "keyObj と関連付けられた値");
myMap.set(keyFunc, "keyFunc と関連付けられた値");

myMap.size; // 3

// 値を取得する（取り出す）
myMap.get(keyString);    // "'文字列' と関連付けられた値"
myMap.get(keyObj);       // "keyObj と関連付けられた値"
myMap.get(keyFunc);      // "keyFunc と関連付けられた値"
```
また、for...of...ループを使用して反復処理を行うこともできます。 

```JS
const myMap = new Map();
myMap.set(0, 'zero');
myMap.set(1, 'one');
for (let [key, value] of myMap) {
  console.log(key + ' = ' + value);
}
// 0 = zero
// 1 = one
```
また、Array.fromを使えば、連想配列を普通の配列にすることもできます。
ただし、配列の中に配列があるようになります。

```JS
const myMap = new Map();
myMap.set(0, 'zero');
myMap.set(1, 'one');
let mapArray = Array.from(myMap);
console.log(mapArray);
//[['0', 'Zero'], ['1', 'one']]

console.log(mapArray[0]);
//[ 0, 'zero' ]

//キーを取り出す。
let mapKey = Array.from(myMap.keys());
console.log(mapKey);
// ['0', '1'];

//値を取り出す。
let mapValue = Array.from(myMap.values());
console.log(mapValue);
// ['Zero', 'one'];
```

参考・引用：[MDN Mapの説明](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Map)
Node.jsでプロファイリングをする方法

##node --prof index.js
--profはプロファイリングと呼ばれる、処理に時間がかかっている様子やどれ位メモリを使っているのかを調べる方法を提供するオプションです。

```console:console
$ node --prof index.js
```
とすると、index.jsが入っているディレクトリに、

```index.jsが入っているディレクトリ
isolate-0x103002a00-v8.log
```
以上のようなログファイルが生成されます。
しかし、このログファイルは人間が見てもよくわかりません。
そこで、このログファイルを以下のように人間が見やすいファイルにします。

```console:console
$ node --prof-process isolate-0x103002a00-v8.log
```
すると、コンソールに以下の表示が出ます。

```console:console
>
Statistical profiling result from isolate-0x103002a00-v8.log, (382 ticks, 37 unaccounted, 0 excluded).

 [Shared libraries]:
   ticks  total  nonlib   name
     15    3.9%          /usr/lib/system/libsystem_platform.dylib
      3    0.8%          /usr/lib/system/libdyld.dylib
      2    0.5%          /usr/lib/system/libsystem_pthread.dylib
      1    0.3%          /usr/lib/system/libsystem_malloc.dylib
      1    0.3%          /usr/lib/system/libsystem_kernel.dylib

 [JavaScript]:
   ticks  total  nonlib   name
      1    0.3%    0.3%  Script: ~bootstrapInternalLoaders internal/bootstrap/loaders.js:42:35
      1    0.3%    0.3%  LazyCompile: ~realpathSync fs.js:1380:22
      1    0.3%    0.3%  LazyCompile: ~getOptionValue internal/options.js:6:24
      1    0.3%    0.3%  LazyCompile: ~binding internal/bootstrap/loaders.js:77:39
      1    0.3%    0.3%  LazyCompile: ~QuickSort native array.js:530:19
      1    0.3%    0.3%  Builtin: LoadIC_Uninitialized
      1    0.3%    0.3%  Builtin: Construct {1}

 [C++]:
   ticks  total  nonlib   name
(中略)
[Summary]:
   ticks  total  nonlib   name
      7    1.8%    1.9%  JavaScript
    316   82.7%   87.8%  C++
      7    1.8%    1.9%  GC
     22    5.8%          Shared libraries
     37    9.7%          Unaccounted
```
この[Summary]という部分に注目すると、どの処理に一番時間がかかっているのか調べることができます。
今回の処理では、C++の処理が全体の87.8%なので、C++の処理を改善すれば良いことがわかります。
その他にも[Bottom up (heavy) profile]という部分には時間のかかった処理が書かれています。
Node.jsで簡易テストをできるassert.equal()

##assert.equal()
assert.equalは、アサーションというnode.jsが提供する簡易テストのモジュールです。

```JS
const assert = require('assert');
assert.equal(50, 50); //OK
assert.equal(50, "50"); //OK
assert.equal(50, 70); /*AssertionError: 50 == 70 */

//関数と答えの比較もできます
function addition(n) {
  let result = n + 1;
  return result;
}
//第三引数に、エラーが出た場合のエラー表示の設定をできる。
assert.equal(addition(1), 3, `1 + 2の答えは3ですが、計算は${additon(1)}でした`)
//AssertionError: 1 + 2の答えは3ですが、計算は${additon(1)}でした`
```

##assert.deepEqual()
assert.deepEqualは配列オブジェクトの深い比較まで行ってくれます。
例えば、assert.deepEqual([50], [50]);はOKなのに対して、
assert.equal([50], [50]); ではエラーが出てしまいます。
これは、JavaScriptでは配列やオブジェクトを == 演算子で比較した際、同じオブジェクト同士でないとfalseになってしまうからです。

```JS
const assert = require('assert');
assert.deepEqual(50, 50); //OK
assert.deepEqual(50, "50"); //OK
assert.deepEqual(50, 70); /*AssertionError: 50 == 70 */
assert.deepEqual([50], [50]); //OK
assert.equal([50], [50]); /*AssertionError: [ 50 ] == [ 50 ] */
```
DataCore vFilO Anvilを冗長化（HA化）してみる

今回は本番環境で使えるようにAnvil（メタデータサーバー）を冗長化（クラスター化、HA化）してみます。[前回はこちら](https://qiita.com/tsurun/items/a3ca42759cef7a224e88)。

HAの場合はNICは2つ以上割り当てる必要があります。
- 1つはData, Management
- 1つはHigh Availability（別名HA Interconnect）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/9b7875a4-8f98-cf76-66a5-f72dc19868cd.png)

NICにHigh Availabilityを割り当てて初めてInstallation TypeでHA clusterを選択できるようになります。
見ての通り1台目の時点で2台分の設定を入力してしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/46c3535d-8c97-2b68-f9eb-ea8ec96f8485.png)

1台目が終わるとこのような画面になり、2台目を待っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/4916a8f1-492e-f09b-a7bb-daf42b76e636.png)

Peer IP AddressでEnterキーを押すと1台目を見つけてきます。あとはINSTALLを選べば自動で設定してクラスターを構成してくれます。簡単ですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/bb2a4029-11c1-b078-8564-8fac309d5ddc.png)

インストールが完了しGUIにログインするとこんな感じです。
（実はこのスクリーンショットは別のクラスターです）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/06ebb166-ed50-e747-d5d6-1c3b8af587b6.png)

仮想化基盤上に作る時は仮想マシンを作成した時点でクローンしておくと少し手間が省けます。
Node.jsのprocess.argv[i]とは

Node.jsのファイルで以下のような記述がありました。

```JS:index.js
'use strict';
const number = process.argv[2] || 0;
let sum = 0;
for (let i = 1; i <= number; i++) {
  sum = sum + i;
}
console.log(sum);
```
それに対して、いかのような記述をすると、

```console:console
$ node index.js 3
> 7
```
となります。
つまり、node index.js 3の3の部分が、process.argv[2]に当てはまるということです。
process.argv[0]だったら、node
process.argv[1]だったら、index.js
を意味します。
midPointで構築するシステムの構成例

# はじめに
midPointアドベントカレンダー3日目はmidPointを利用する場合のID管理システムの構成例をご紹介します。

midPointはDBとしてH2 Databaseを内包しており、単体でも利用可能です。今回のmidPointアドベントカレンダーの中で紹介していくmidPointの機能群を試す程度であれば、フルフィルメント(プロビジョニング)を行う場合は連携するRDBやLDAP等を用意する必要はありますが、基本的に[2日目](https://qiita.com/yoshimi0227/private/0cdc010d02150386619c)の記事を参考にインストールしたもので十分です。

しかし、実際に運用していくうえでは性能や可用性を考慮する必要があります。本記事では、midPointを実際に運用する上での基本的な構成をご紹介します。また、midPointとアクセス管理プロダクトを組み合わせた統合的な認証基盤として運用するような構成もご紹介します。

# 単体利用
上述の通り、midPointは単体でもIDライフサイクル管理やポリシー管理、プロビジョニングといった[アドベントカレンダー1日目](https://qiita.com/naokiiiii/private/0535139fb45e50cb1180)で触れているような機能が一通り利用可能です。プロビジョニングする周辺システムも含めた簡単な図は以下のとおりです。

![単体利用.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13224/6ffe1123-0e31-9f6e-edd8-50dc2db3936d.png "midPoint単体利用時の構成")

単体では、IDを保管するIDリポジトリとして、内包しているH2 Databaseを利用しています。

# 実運用を想定した構成
## データベース
実際にmidPointを運用していく場合、H2 Databaseでは性能的に不利であったり、可用性向上のためにDBの冗長構成を取りたいといった目的で、基本的にH2 Database以外のDBを利用することになるかと思います。外部のDBを使う場合の構成例は以下のとおりです。

![データベース.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13224/1c915cfa-81bf-a94b-75cb-2f1c9af6cfd7.png "外部DBを利用する場合の構成")

上図ではPostgreSQLとしていますが、midPointでは様々なDBプロダクトに対応しています。公式に対応がうたわれているDBプロダクトは以下の表のとおりです。

|DB|備考|
|:--|:--|
|H2 Database|midPointに内包しているデフォルトで利用するDB|
|PostgreSQL||
|MariaDB|公式にテストされているのはVer 10.0.28|
|MySQL|Ver 5.6.4以降に対応|
|Oracle Database 12c||
|SQL Server 2008, 2014, 2016||

PostgreSQLやMariaDB、MySQLに対応しているため、Amazon RDSなどのマネージドサービスも利用可能です。

## 冗長構成
midPointは冗長構成を取ることもできます。

![冗長構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13224/fe0ad3e0-8564-9d6b-5ddb-5bd17a99312c.png "midPoint冗長構成")

冗長構成とした場合は、タスク(プロビジョニング等のジョブ実行)も分散実行されます。また、万が一タスク実行中のノードがダウンしたような場合でも、残りのノードでそのタスクを実行するといった動作をすることで可用性が確保されています。タスク定義はDBに格納されており、このタスク実行機能は内部的にはJavaのジョブスケジューリングライブラリのQuartzが利用されています。

![冗長構成-障害時.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13224/b17d4a6d-915d-1d98-efcd-70335ccaabc8.png "冗長構成の障害時の動作")

なお、冗長構成時のDBとしてH2 Databaseも利用することは可能ですが、非推奨とされています。

# 統合認証基盤
最後にmidPointにアクセス管理プロダクトを組み合わせることで統合認証基盤として活用する構成をご紹介します。ここでは、アクセス管理プロダクトはNRI [OpenStandia](https://openstandia.jp/)として採用事例の多いKeycloakを例にしています。

![統合認証基盤.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13224/41014a1f-b33d-6237-9613-d436fa3962dc.png "統合認証基盤構成")

Keycloakを組み合わせることでID管理だけでなく、SSOも実現することができます。midPoint自体も、Spring Securityによるリクエストヘッダ情報での認証に対応しているので、Keycloak GatekeeperやApache HTTP Server+mod_auth_openidcなどのリバプロ型のOIDC/SAMLのクライアントプロキシを利用することによりSSOに対応することができます。

Keycloakについては、[OpenStandia](https://openstandia.jp/)の過去のアドベントカレンダーの[Keycloak by OpenStandia Advent Calendar 2017](https://qiita.com/advent-calendar/2017/keycloak-by-openstandia)などをご参照ください。

# おわりに
以上、midPointを利用したID管理システムの構成のご紹介でした。

midPointは各種DBプロダクトに対応しており、冗長構成も取れ、非機能面でもID管理システムとしての採用に足るプロダクトです。また、Keycloakなどのアクセス管理プロダクトと組み合わせることで統合認証基盤として活用することができます。

# 参考

- [Repository Configuration - midPoint - Evolveum Confluence](https://wiki.evolveum.com/display/midPoint/Repository+Configuration)
- [Clustering / high availability setup - midPoint - Evolveum Confluence](https://wiki.evolveum.com/pages/viewpage.action?pageId=11075783)
リモートのLinuxを手元のWindowsで操作する（GUI編）

# リモートのLinuxを手元のWindowsで操作する（GUI編）

知識をアップデートしたのでメモ。

## 概要

リモートのLinux機を自分の手元のWindowsで操作する。
SSH経由でX11に接続し、GUI操作できるようにする。



## 設定の流れ

- Linux機のSSHサーバーの設定を行う
- WindowsにX server（VcXsrv)をインストールする
- WindowsのputtyからLinux機にssh接続する
- 動作テストをする



## Linux機のSSHサーバーの設定を行う

設定ファイルを修正する。

```sh
$ sudo vi /etc/ssh/sshd_config
```

書き換える内容（抜粋）。もとから設定されているならそのままでOK。

```text:sshd_config
X11Forwarding yes
```

書き換えたらサービスを起動。

```sh
# systemctl start sshd.service
```



## WindowsにX server（VcXsrv)をインストールする

下記からVcXsrvをダウンロードする。

[VcXsrv Windows X Server download \| SourceForge\.net](https://sourceforge.net/projects/vcxsrv/)

インストーラーを起動してインストールする。
設定は全部初期値。


![vcxsrv-installer.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170209/bbc3a622-6639-769b-8670-621271cdefd9.jpeg)


スタートメニューから起動する。
初回は設定を色々きかれるが、全部デフォルトでOK。

![xlaunch.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170209/106ff9b4-2fa5-3eba-93c5-140e8f350b9e.jpeg)



## WindowsのputtyからLinux機にssh接続する

puttyを起動して、下記の項目にチェックする。

Connection -> SSH -> X11 -> Enable X11 forwarding

![putt-x11.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170209/396f2c9e-cb48-4ebf-991d-cbf6f34f0b41.jpeg)

Linux機にログインする。

![putty-success.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170209/922095e0-1d28-179d-9bf9-7243c028aa53.jpeg)



## 動作テストをする

ターミナルから下記コマンドを実行する。
（X11のアプリならどれでもOK）

```bash:動作テスト
$ nautilus
```

LinuxのGUIアプリがWindows上で表示される。

![x11-windows.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170209/3064a7f8-6db5-44c1-8da3-0b6cc40bd3bb.jpeg)


ファイルをダブルクリックするとLinux機内のアプリで表示される。
リモートのLinuxを手元のWindowsで操作する（CUI編）

# リモートのLinuxを手元のWindowsで操作する（CUI編）

## 概要

リモートのLinux機を自分の手元のWindowsで操作する。
操作はCUIのみとし、SSH経由で接続する。

## 設定の流れ

- Linux機でSSH接続用のサーバー設定を行う
- ファイアウォールを設定する
- Windows機にSSH接続用のクライアントソフトをインストールする
- SSH接続を実際に行う



## Linux機でSSH接続用のサーバー設定を行う

### SSHサーバーの設定を行う

設定ファイルを修正する。

```sh
$ sudo vi /etc/ssh/sshd_config
```

書き換える内容（抜粋）。もとから設定されているならそのままでOK。
`X11Forwading yes`は今後GUIのリモート接続をするための設定。

```
Port 22
HostKey /etc/ssh/ssh_host_rsa_key
PermitRootLogin no
PasswordAuthentication yes
X11Forwarding yes
```

書き換えたらサービスを起動。

```sh
# systemctl start sshd.service
```


### ファイアウォールを設定する

ssh接続を許可する。（既に設定済みなら不要）

```sh
# firewall-cmd --permanent --add-service=ssh
```



### Windows機にSSH接続用のクライアントソフトをインストールする

下記から「putty-gdi-年月日.zip」をダウンロードする

[iceiv\+putty](https://ice.hotmint.com/putty/)

zipを解凍する。場所はどこでもよい。
これでインストールは完了。


## SSH接続を実際に行う

インストールしたフォルダの中は下記のようになっている。
putty.exeをWクリックして起動する。

![putty-exe.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170209/0177441f-7384-461a-e7c7-7421520137f9.jpeg)


下記のような画面が表示される。  
`＜LinuxのIPアドレス＞`の箇所に実際のIPアドレスを入力して
`Open`ボタンをクリックする。

![putty-connect.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170209/08306e0a-f036-8551-8f9f-192969f062d8.jpeg)

ログイン名とパスワードを聞かれるので入力する。  
パスワードは画面に何も表示されないが入力は受け付けられている。

![putty-login.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170209/c94fb3ce-3014-dcd2-3e73-4fc6d3460096.jpeg)

Linux機にログインが成功する。  
後はLinux機に直接ログインした時と同様に操作ができる。

![putty-success.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170209/18165409-7ea2-d82b-58b0-ce691707092c.jpeg)
プリメイドai用WiFiブリッジを作ったよ　組み立てキット組み立てガイド

プリメイドai用WiFiブリッジの製作マニュアルになります。

内容はこちらをご覧ください。
プリメイドai用WiFiブリッジを作ったよ
https://qiita.com/usashirou/items/622cb3d7ab2e46ecf5e8

部品表
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/add66b07-b549-a62c-be38-ad5e7c597ae0.png)
＊8番の抵抗は1~1.2KΩにしています。

回路図
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/4400266d-f9a3-2e06-d146-cb928e4e3371.png" alt="" width="10000"height="" border="0" />

![DSC_0004 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/9a1704b6-c829-dba9-0cea-8010c3f74ea9.jpeg)

組み立ては
表面実装部品
ZHコネクタ
4ピンコネクタ
の順番で組み立てるのが良いと思います。

なお、コンデンサやスイッチは厚みが厚いので最後に取り付けることをお勧めします。
ESP-32はある程度平らなので、表面の抵抗やLEDの後に取り付けるのが良いようです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/e07d6037-b7d9-d0c2-dadd-13525c2b14bf.jpeg" alt="" width="500" height="" border="0" />
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/ca180698-3b09-e7a4-e30d-4dfd95b5e4f4.jpeg" alt="" width="500" height="" border="0" />

製作後は、LEDの点灯を確認しましょう。
これは、極性の間違え等のミスをすぐに確認できます。
（ちなみに、今回の試作品はZH-4Pコネクタのシルクが逆になっています）
広告の文章作成

広告の文章の作成方法
（twitterのプロフィールとか）

まず、
https://www.related-keywords.com/
類似キーワード検索をして、どのような言葉と￥一緒に検索されているか調べる。

いくつか集客に使えそうなキーワードをピックアップする。

文章にまとめる。数字を使うことによりより効果的。
AndroidのChrome 78のPreload問題



問題になっているサービスは多いのではないかと思いつつも、あまり騒ぎになっていないので不思議だなと思っているkumanomiです。

# どんな問題なの？
AndroidのChrome78.0.3904.108にて、Preloadの機能が有効になりページ内のリンクを勝手に踏んでしまい予期せぬ挙動をしてしまう問題が発生しています。

## たとえば・・・
- ログインをしようとした際にプリロード機能によって勝手にログアウトのリンクが踏まれてしまいログアウトしてしまう

- 商品の購入や予約ができない

- 強制的にトップページに戻されてしまう

- 選択したものと異なる振込先が選択された状態となる

**結構致命的なものも多いと思うんですよね 。**

## 同現象が起きているサービスなど一部抜粋
- [無印良品](https://www.muji.net/mt/media/archives/2019/11/24_121500.html)
- [高速バスネット](https://www.kousokubus.net/BusRsv/ja/information?key=HG5jn-PE6Aw)
- [三井住友銀行](https://qa.smbc.co.jp/faq/show/3318?category_id=1&site_domain=default)
- [あおぞら銀行](https://www.aozorabank.co.jp/info_article/kojin/post-173.html)
- [福井銀行](https://www.fukuibank.co.jp/news/ib_android_preload.html)
- [中央労働金庫](http://chuo.rokin.com/attention/__icsFiles/afieldfile/2019/11/25/20191125kojinnib.pdf)
- [きらぼし銀行](https://www.kiraboshibank.co.jp/oshirase/20191122.html)
- [mixi](https://mixi.jp/release_info.pl?mode=item&id=3619)


##　お知らせのサンプル

```
現在、AndroidスマートフォンでChromeの最新バージョン 78.0.3904.108 をお使いの一部のお客さまにおいて
エラーメッセージが表示され、なにがしが
完了できない事象が発生しております。

Google Chromeの設定を変更していただくことで、
事象が解消されることがございますので、以下をお試しください。

＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝

【表示されるエラーメッセージ】
hogehoge

【対処方法：Chromeの設定の変更（プリロード機能のオフ）】
①ブラウザを開いた状態で右上のメニューボタン（・・・が縦に並んだボタン）を押す
②「設定」を選択する
③「プライバシー」を選択する
④「ページをプリロードして、閲覧と検索をすばやく行えるようにします」のチェックをはずす

事象が解決しない場合には、恐れ入りますが別のブラウザアプリまたはパソコンからのご利用をお試しください。
```

## issueは上がっていて・・・
https://bugs.chromium.org/p/chromium/issues/detail?id=1027991

## issue内では解決されていそうだ
```
The server-side config has been disabled. It should roll out to users over the next couple of hours
(サーバー側の設定は無効になっています。今後数時間でユーザーに展開されるはずです)
```

しばらく待ってれば良いんですかね・・・？
(詳しい人教えてください)

## 暫定対応された方の記事はこちら
[preload問題とその暫定的対応](https://qiita.com/Nakaz/items/617bcdace4fbd6f298cd#_reference-732c6583034051b2827a)
ドメインの取得方法

#ムームードメインで検索
　
ほしいドメインを検索にかける。
※２年目から更新料が違うのでチェック

https://web.archive.org/
過去にドメインが使われていないかチェック
使われていたら、twitterAPIに通らなかったりするので要確認。

購入をクリック
おさいぽを使う。
ドメインを取得完了


DNSの設定方法

ムームードメインにログイン
設定したいドメインを開く。

#ネームサーバー設定変更
→GMOペパポ以外のネームサーバーを使用する
設定して、確定。

DNSが繋がっているかチェック
https://mgt.jp/t/dns#
ここにドメインを入れる。

nameseverかIPアドレスをチェックする。
GitHubでPull RequestでMergeされたブランチを自動で削除する設定

# 概要
タイトルの通りです。
削除し忘れることがまれによくあるMerge後のブランチの削除し忘れを防ぐ設定です。

# 方法
1. リポジトリの設定画面（https://github.com/[Team]/[Repository]/settings） を開きます
<img width="1025" alt="スクリーンショット_2019-11-26_11_52_44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207645/57d1a2ed-197f-e4a7-6027-3d40b6e757e8.png">

2. 下にスクロールしていくとMerge buttonという見出しがあり、その中の[Automatically delete head branches]というのが本記事タイトルの設定となります。
<img width="768" alt="スクリーンショット_2019-11-26_11_38_44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207645/5ab71077-ea9e-a392-23da-ab79cb724d4c.png">

3.Checkをいれて有効にすることで設定完了です。

# さいごに
とっても簡単ですね
Node.jsでのリクエストIDのログ出力（express, log4js, request-context）

##概要
Node.jsのexpressベースのWebアプリで、リクエストIDをログ出力します。
今回、log4js、request-contextを使用しました。

request-contextで、リクエスト毎にリクエストIDを保持します。
log4jsのtokensに、リクエストIDをセットして、patternでリクエストIDを出力するようにしています。
 
##参照情報
参考にさせていただいたページは下記です。

* 参照先1: [Node.jsでログにRequestIdを入れる](https://qiita.com/ippei_ukai/items/adea86744777cbef5eba)

* 参照先2: [Node.js で Log に userId を自動で出力する方法](https://qiita.com/waterada/items/3b3cedc86e1a4eb47d91)

##注意点
request-contextは、下記の通り、Node.jsのdeprecatedになっているdomainに依存しています。参照先2でも指摘されており、より詳しく記載されています。
[request-context](https://www.npmjs.com/package/request-context)
>See the Domain Docs for further information on error handling for domains. Note that the domain module is pending deprecation!

##サンプルコード
今回は、リクエスト毎に、uuidでリクエストを発行するようにしています。
contextService.setのところでリクエストIDを保持させています。

```javascript:app.js
const express = require('express');
const app = express();
const contextService = require('request-context');
const uuid = require('uuid/v4');
const logger = require("./logger").logger();

app.use(contextService.middleware('request'));
app.use((req, res, next) => {
  const requestId = uuid();
  contextService.set('request:requestId', requestId);
  logger.info("Start API.", req.method, req.originalUrl);
  next();
});

app.get('/', function (req, res) {
  res.send('hello world');
  logger.info("End API.");
})

app.listen(3000)

```

getRequestIdで、保持しているリクエストIDを取得しています。
layoutのpatternの%x{requestId}がリクエストIDです。

```javascript:logger.js
const log4js = require("log4js");
const contextService = require('request-context');
const getRequestId = function() {
  return contextService.get('request:requestId');
};

log4js.configure({
  appenders: {
    console:{
      type:'console',
      layout:{
        type:'pattern',
        pattern:'[%d] [%x{requestId}] %[[%p]%] [%c] %m',
        tokens: {
          requestId: getRequestId
        }
      }
    }
  },
  categories:{
    default:{appenders:['console'], level:'info'}
  }
});

exports.logger = function(){
  const logger = log4js.getLogger('default');
  return logger;
};

```

##ログ出力結果
下記のようにリクエスト毎に、リクエストIDが出力されます。

```
[2019-11-26T11:24:46.451] [ef9b0c23-53f2-4c7b-bce3-0def665fbc08] [INFO] [default] Start API. GET /
[2019-11-26T11:24:46.460] [ef9b0c23-53f2-4c7b-bce3-0def665fbc08] [INFO] [default] End API.
[2019-11-26T11:24:49.588] [4af4ffed-a22f-4b81-806a-1cdcff4b7c22] [INFO] [default] Start API. GET /
[2019-11-26T11:24:49.590] [4af4ffed-a22f-4b81-806a-1cdcff4b7c22] [INFO] [default] End API.
[2019-11-26T11:24:51.226] [360033c9-e6eb-405c-b3a7-6ac9e20b3fa4] [INFO] [default] Start API. GET /
[2019-11-26T11:24:51.227] [360033c9-e6eb-405c-b3a7-6ac9e20b3fa4] [INFO] [default] End API.
[2019-11-26T11:24:53.371] [048a8ce6-1bd8-4514-89df-aa467419e0ce] [INFO] [default] Start API. GET /
[2019-11-26T11:24:53.372] [048a8ce6-1bd8-4514-89df-aa467419e0ce] [INFO] [default] End API.
```
新人にRPAを教えるときにやったことまとめ

# 概要
今年入社した文系大学出身の新卒後輩ちゃんに、RPAについて教えることになったためその際に意識したことをまとめました。
RPAを推進していくにあたり、ノンテク部門の方への **教育/指導は避けては通れない道** だと思うので、少しでも参考になれば幸いです。

# 経緯
今年度入社の新人ちゃん:woman:(新卒、演劇学科卒)が弊社RPAグループに配属されてきました。
話を聞くと「これまでプログラミングはやったことないです:woman:」とのこと。
そんな彼女にRPAとプログラミングの基礎の基礎を教えるための試行錯誤が始まりました…

# 教えるときに意識したこと
## 1.処理の組み立て方から教える
一番最初に、 **フローチャート(流れ図)** について教えました。
「どんな処理を」「どんな流れで」「どうやって処理するか」を視覚的に表現できるので、教える側としても伝えやすいです。
また、実際にロボットを作る前に一度流れ図を作成してもらうことで、処理について互いに把握しやすくなります。

## 2.極力身近なものに例える
身近なものに例えることで、「プログラミング=なんだか難しい…」というイメージを持たれないように気を付けました。

### たとえば…  
- 変数は **値を保存する箱**
- 眼鏡は眼鏡ケース、名刺は名刺入れのように **入れるものによって箱(変数)の形は変わる**
- 配列は **薬ケース**  

などなど
## 3.聞ける環境を作る
分からないことがあれば迷わずに聞ける環境づくりを意識しました。
聞くための **手段(メール、Slack、口頭…etc)** は社内で既に構築済なので、
疑問点をざっくばらんに聞ける **関係性** の構築に力を入れました。

## 4.調べ方を教える
四六時中後輩について指導ができるわけではないので、自力で解決できる力を身につけられるよう意識しました。
困っている内容をうまく言語化して、その対処方法をさらにRPAツールに絞り込んで調べるって案外慣れないと難しいので、
最初のうちは「このワードで調べれば出てくるんじゃないかな？」とアドバイスしてました。

| 知りたい内容 | 難易度 | 対処 |
|:-:|:-:|:-:|
| 調べれば解決できる | 易 |  調べ方を教える |
| 調べるのにコツがいる | 中 | 参考になるサイトを教える |
| 調べても出てこない | 高 | やり方を教える |
※質問できるコミュニティがある場合はそちらへ誘導してもよかったかもと反省してます:thinking:

## 5.聞かれても答えられる知識を身につける
あらかじめ後輩に解かせる問題は自分で作成/検証しておくのは大前提として、自分自身としても様々な方法を試してみたり、学習コンテンツが充実しているツールであればその学習コンテンツに目を通すことで知識を蓄えてました。(UiPath 〇cademyなど…)
質問してくれた後輩を「分からないから〇〇さんに聞いて！」とたらい回しにしないで済むように、極力自分が回答できるように意識しました。

## 6.それでも分からないことは周囲を巻き込んで解決
そうはいっても限界は来ます(無慈悲)
その場合はグループメンバーで解決方法を探りました。
メンバー全員が見れるSlackで解決方法を探ることで後輩と私だけでなく、グループメンバー全員で成長できたように思います。

# 結果
後輩だけでなく自身もとても成長できました:cherry_blossom:
[上司、後輩、私の3人でLT登壇もしました](https://www.slideshare.net/maiodamura/20191108-rpai)
なんと、後輩ちゃんは12月に **[内定者向けのハンズオンまで実施](https://qiita.com/sakumo_o/items/99a79e278ef1431b9ec7)** しました！

## 人に教えるメリット
- 相手を納得させられる説明のため、自分が納得できるほどの情報をインプットする必要がある
- 相手に分かりやすく伝える方法を考えたり、実践できる（分かりやすかったかどうかのフィードバックも得やすい）
- 相手からの異なる視点からの疑問を知ることでさらに知識を深められる
- **頼ってもらえると嬉しい**（個人の感想です）

と、教える側のスキルやモチベーション向上にもつながります！

# 終わりに(2024/06/25追記)
当時(2019年)に比べて、プログラミングが義務教育の必修科目になったため、今後は流れ図や変数の概念といった部分の説明は不要になっていくかと思います。
ですが、「分からないことの解決方法」「分からないままで終わらせないための関係構築」は普遍的な必須スキルと思うため、新人に限らず少しでも質問できない・してくれないという悲しい悪循環が減ってくれることを願っています。
iOS アプリ公開 スクリーンショットでハマった


![s.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182971/a7882722-de33-d992-17a1-50b92f36b2dd.png)

以下のようなエラーができてた

**無効なGeoJSON：ルーティング App カバレッジファイルが無効です。詳細については、次のガイド「Location and Maps Programming Guide」を参照してください。**

原因：　Choromeを使っているせい
解決策：safariを利用する


**イメージにアルファチャンネルや透過を含めることはできません。**

Photoshopでpngを普通に保存したら出てきた、どうしよう？？
メニュー
⇨　ファイル
⇨　書き出し
⇨　書き出し方式
⇨　透明部ボタンチェックボックスを外す
⇨　書き出し
![スクリーンショット 2019-10-16 14.13.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182971/f77e97aa-ee4b-5c81-ca78-934d9eed2925.png)

メニュー
⇨　ファイル
⇨　クイック書き出し形式　の部分で 透明部分のチェックを外すでも可
![スクリーンショット 2019-10-16 14.13.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182971/3ad3d996-ad14-df86-7403-5c737862c12f.png)
iOS申請→拒否られApple Connectへ修正バージョンを再アップしたが反映されない

# 拒否られたあと、Apple Connectへ新しいバージョンのAppをアップロードするが反映されない時

いつまで経っても反映されないと、バージョンを変えてみたりして再度アップロードするが、反映されない。。。

今回の場合、拒否られたバージョンが、ビルドに赤く拒否られた状態で残っていたので、反映されなかったようです。

拒否られたバージョンをビルドから取り外し（削除）したら、**やっと反映されました**。

なぜ、反映されないのか、教えてくれてもよさそうなのに、と思ってしまいます。
TypeScript2.3.2でmoment-duration-formatを使う

注意
====

moment-duration-formatでは、バージョン２でTypeScript対応がアナウンスされているようです。より新しいバージョンのmoment-duration-formatを使用している場合、アップデートで対応できる可能性がありますのでGitHubを確認してください。
https://github.com/jsmreese/moment-duration-format

環境
====

Vue.jsを使ったJavaScript（ES6）のコードをWebPackで固めてクライアントサイドで実行している。
エディタはVSCode

背景
====

前の記事 https://qiita.com/a-yonenaga/items/18c9aaf67abf1f897e72 では、ES6で開発中のプロジェクトのTypeScriptの移行に着手した。この移行作業中に、moment-duration-formatを使用しているクラスでコンパイルエラーが発生した。

moment-duration-formatは、時間を扱うライブラリmoment.js( https://momentjs.com )内の、期間を表現するクラスdurationにフォーマット出力の機能を追加するライブラリ。

https://github.com/jsmreese/moment-duration-format

エラーメッセージ
====

`Property 'format' does not exist `

![EditableProgram_ts_—_gachi-taite-designer-web.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99567/a900fe70-7e9d-abd1-c1dc-2bcf60215830.png)

TypeScriptではうまくmoment.Durationに機能をうまく追加してくれない（というより、存在するはずだが呼ぶことができない？）らしい。

解決策
====

StackOverflowにあった。
https://stackoverflow.com/questions/43058807/how-to-use-moment-duration-format-in-typescript

使っている.tsファイル内で、moment.Durationを拡張したDurationを作ってやる。

```typescript:moment-duration-formatを使用するファイル内でのinterface宣言
interface Duration extends moment.Duration {
    format: (template?: string, precision?: number, settings?: DurationSettings) => String
}

interface DurationSettings {
    forceLength:boolean
    precision: number
    template: string
    trim: boolean | 'left' | 'right'
}
```

```javascript:変更前
const programLengthHHmm = moment.duration(program.lengthMinute, 'minutes').format('HH:mm', {trim: false})
```

moment.durationをDuration型にキャストすることで、format()関数が呼べるようになった。
precisionやtrim:falseの渡し方が変わったので、その部分の対応も加えている。

```typescript:変更後
const durationSettings = {trim: false} as DurationSettings

const programLengthDuration = (moment.duration(program.lengthMinute, 'minutes') as Duration)
const programLengthHHmm = programLengthDuration.format('HH:mm', null, durationSettings) as string
```
Windowsにてp "日本語"で"日本語"を表示させる方法

# Ruby on WindowsのFAQシリーズ
初学者からよく聞く

```ruby:nihongo.rb
p "日本語"
p ["日本語"]
p "日本語": :"日本語"
```

が

```
"\u65E5\u672C\u8A9E"
["\u65E5\u672C\u8A9E"]
{:"\u65E5\u672C\u8A9E"=>:"\u65E5\u672C\u8A9E"}
```

となる問題です。

## ちなみに脳筋回答
コンソールに日本語表示させる必要なんて無いんじゃない？
(割と真面目に、Rubyの`p`による日本語表示をwindowsでやる必要は無いと思ってます)

## 真面目回答
出力が**真の意味で文字化けする危険性がある**が
スクリプトの頭に

```rb
Encoding.default_internal = __ENCODING__
```

付けとけ

## p "日本語"とは?

[Kernel.#p](https://docs.ruby-lang.org/ja/latest/method/Kernel/m/p.html)
> 引数を人間に読みやすい形に整形して改行と順番に標準出力 $stdout に出力します。主にデバッグに使用します。

> 引数の inspect メソッドの返り値と改行を順番に出力します。つまり以下のコードと同じです。

> print arg[0].inspect, "\n", arg[1].inspect, "\n", ...

つまり、`p("日本語")`は`puts "日本語".inspect`となります。

```rb
p "日本語".encoding         # => #<Encoding:UTF-8>
p "日本語".inspect          # => "\"\\u65E5\\u672C\\u8A9E\""
p "日本語".inspect.encoding # => #<Encoding:Windows-31J>
```

なので、`"日本語".inspect`の時点で`\u`表記への変換が行われている事
および、その理由が文字コードを変換しつつ元の情報を損なわないための措置という事がわかります。

`"日本語".encoding`は[るりま: 多言語化](https://docs.ruby-lang.org/ja/latest/doc/spec=2fm17n.html)に
> リテラルのエンコーディング
> 文字列リテラル、正規表現リテラルそしてシンボルリテラルから生成されるオブジェクトのエンコーディングは スクリプトエンコーディングになります。

> 現在のスクリプトエンコーディングは \_\_ENCODING\_\_ により取得することができます。

とある通り、スクリプトエンコーディング(`__ENCODING__`)によって取得できます。
また、[Ruby2.0以降のスクリプトエンコーディングの既定はUTF-8](https://docs.ruby-lang.org/ja/latest/doc/news=2f2_0_0.html)です


では、`"日本語".inspect`は？というと
[るびマ Ruby M17N の設計と実装](https://magazine.rubyist.net/articles/0025/0025-Ruby19_m17n.html#default_external-と-default_internal)
> Encoding.default_internal が設定されている場合は、全ての入力された String のエンコーディングは Encoding.default_internal の返すエンコーディングと等しいと仮定することが可能になります。この場合、ライブラリが返す文字列も Encoding.default_internal になっているべきです。

ライブラリが返す文字列は、`Encoding.default_internal`になっているべき　という事なので`Encoding.default_internal`によって指定できる事がわかります。


# 結論

```rb
Encoding.default_internal = __ENCODING__
```

を行うことによって、`String#inspect`が返す文字列を文字列リテラルと同じエンコーディングにできる。

## 問題点

Windowsではlocaleが`cp932`なので
文字列内に絵文字などのcp932に変換できない文字を含むと文字化けします。
この問題のために`default_internal`が`nil`の場合は`default_external`を代替エンコーディングとして使っていると推測できます。
トピックブランチの作成

トピックブランチ：機能追加やバグ修正といったある課題に関する作業を行うために作成するブランチのこと。複数の課題に関する作業を同時に行う場合、その数だけトピックブランチを作成する。
トピックブランチの分岐元を統合ブランチという。

1. `git branch`：現在のブランチの確認

2. `git branch 作成するブランチ名`：新しいブランチの作成

3. `git checkout 使用したいブランチ名`：ブランチの変更
   (`git checkout -b 作成したいブランチ名`：新しいブランチの作成とそのブランチへの切り替えを同時に行う)
日数分ループして、１ヶ月分の日付を上から順番に表示させたい

## 動作環境
Google Apps Script
Chrome

# まえがき
Googleのスプレッドシートで、勤怠管理表を作った際に、日付１ヶ月分を新しいシートにマクロで表示したい場合などに、このページのコードが役に立つと思います。

# 感想
VBAに馴染んでいる自分には、GasのDate型の扱いがピンとこないです。

# コード
```javascript
function setDaysInAManth() {
  var strDate = "201902"   // ←この年月の数値をシート名にすること
  var strYear = strDate.slice(0,4);
  var strMonth = strDate.slice(4,6);
  
  Logger.log(strYear);
  Logger.log(strDate);
  Logger.log(strMonth);
  if (strMonth.slice(0,1) == "0") {
     strMonth = strMonth.slice(1,2);
  }
  Logger.log(strMonth);
  
  Logger.log(new Date(strYear, strMonth, 0));
  
  var DaysInAMonth = getLastDate(strYear, strMonth)
  Logger.log(DaysInAMonth);
    
  var ssTo = SpreadsheetApp.openById(スプレッドシートのナンバー)
  var shTo = ssTo.getSheetByName(strDate)
  
  // 日数分ループして、セルに１ヶ月分の日付を上から順番に表示させる
  var top_row = 5 
  for(var i=1;i<=31;i++){
    if (DaysInAMonth < i){
      shTo.getRange(i + top_row, AbcToNumber("A")).setValue("");
      continue
    }
    var memoDate = strYear + "/" + strMonth + "/" + (i)
    Logger.log(memoDate);
    shTo.getRange(i + top_row, AbcToNumber("A")).setValue(memoDate);
  }
}

// アルファベットを数値に変更する関数
// aのときに1を返したい
function AbcToNumber(strColumn) {
  var iNum = 0;
  var temp = 0;
  
  strColumn = strColumn.toUpperCase();
  for (i = strColumn.length - 1; i >= 0; i--) {
    temp = strColumn.charCodeAt(i) - 65; // 現在の文字番号;
    if(i != strColumn.length - 1) {
      temp = (temp + 1) * Math.pow(26,(i + 1));
    }
    iNum = iNum + temp
  }
  return iNum + 1;
}

// 月末の日付を取得する
function getLastDate (year_, month_) {
  var strDate = new Date(year_, month_, 0);
  return strDate.getDate()
}
```

# あとがき
とりあえずコピペすれば動作はします。
アルファベットを数値に変更する関数と、月末の日付を取得する関数は、役に立ちます。(Excel VBAでアルファベットを数値に変換しないコード多いですよね)
JavaScriptの引数の数チェックについて

#JavaScriptの引数の性質（備忘録）

JavaScriptでは呼び出し側の引数の数が呼び出し元と一致しなくてもエラーとならず、下記の結果となる。

```javascript
console.log(message);
}

displayMessage(); //undefind
displayMessage('hoge'); //hoge
displayMessage('hoge', 'foo');//hoge

```

####参考文献
改定新版JavaScript本格入門　~モダンスタイルによる基礎から現場での応用まで
９日目

htmlとcssがわかっていきたところで、
rubyのレビューコードを実装します。

読み方としては

コードを上から読んでいきますが

約束事はスキップして
実際に表示されるコードまで行きます。

そこで実際に呼ばれるアクションのメソッドを実装していくことで、ミスを防げると思いました。

実際に作成していく過程を
やればいいと思いました。
#wordpressを知らないPHPエンジニアあるある

## 「PHPエンジニア」を名乗っていても、WordPressはあまり知らない、という方もいらっしゃるのではないでしょうか。

そういった方向けに、ツイッターで [#wordpressを知らないPHPエンジニアあるある](https://twitter.com/hashtag/wordpress%E3%82%92%E7%9F%A5%E3%82%89%E3%81%AA%E3%81%84PHP%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%82%E3%82%8B%E3%81%82%E3%82%8B?src=hashtag_click) を書いているのですが、ツイッターだと流れてしまうので纏めています。

### javascriptなどをheader.phpで呼び出している
→ wp_enqueue_script を使いましょう

### cURL や file_get_contents でHTTPリクエストを処理している
→[wp_remote_get](https://php4wordpress.calculator.jp/wordpress/wp_remote_get/)を使いましょう

### CSRF 対策に自分でnonceを実装している
→settings_apiを使いましょう

### sql文を書いて、データベースに直接アクセスしている
→ WP_Queryを使いましょう

### キャッシュ機能を独自実装している
→ [transient API](https://php4wordpress.calculator.jp/wordpress/transient/)を使いましょう

### 1時間を3600、1日を86400と書いている
→ HOUR_IN_SECONDS や DAY_IN_SECONDS を使いましょう。#wordpressjp #php

## どうすれば防げたか？
公式ドキュメントに目を通していれば、防げた可能性は高いと思います。

## 情報募集中
皆さんも、ご自身の体験などを、ハッシュタグ [#wordpressを知らないPHPエンジニアあるある](https://twitter.com/hashtag/wordpress%E3%82%92%E7%9F%A5%E3%82%89%E3%81%AA%E3%81%84PHP%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%82%E3%82%8B%E3%81%82%E3%82%8B?src=hashtag_click) で共有いただければと思います。
ホーム画面に追加したspaサイトで遷移すると上部にバーが出るのを消す

iPadでspaで簡単なサイトを作って「ホームに画面に追加」をして疑似アプリケーション化して使っていたのですが、いつのまにか遷移すると「上部にバー」が出るようになってしまいました。「完了」を押すとバー自体は消えるのですが、せっかくの専用端末化が台無しです。ということで調査しました。

![IMG_0002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14768/ab66cd69-6d0f-38ff-b459-abcf6e41f299.jpeg)
※縮めています＆ダークモードなので灰色。


# 環境
- iPadOS 13.1.3

たぶん、どこかのバージョンで治る気がしますが...。

# 方法

結論から書くとmanifestファイルを追加します。

```index.html
<!-- タイトルバーを消す設定 -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">

<!-- 追加 -->
<link rel="manifest" href="manifest.json">
```

```manifest.json
{  
  "name": "サンプルアプリ",  
  "short_name": "サンプル",  
  "display": "standalone",  
  "scope": "/",  
  "start_url": "/"  
}
```

## nuxtの場合

- manifest.jsonをstaticに入れます
- nuxt.config.jsに以下を追加します。

```nuxt.config.js
  head: {
    ...
    meta: [
      ...
      { name: 'apple-mobile-web-app-capable', content: 'yes' },  
      { name: 'apple-mobile-web-app-status-bar-style', content: 'black-translucent' }
      ...
    ]
    ...
    link: [
      { rel: 'manifest', href: '/manifest.json'},
    ]
  }
  ...
```

# メモ

前はmanifest無くてもできていたと思うのですが...。ハマったのでメモしておきます。
yupで複合 validation 〜春のeslint-disable-next-lineを添えて〜

## TL;DR

「2つののフィールドを切り替え可能で、いずれか一つが必須」みたいなやつをyupでやりたかったけど、地味にハマった。
結論としては

 - `test` を使う
 - thisが必要なのでarrow functionをあきらめる
    - eslint の[このrule](https://eslint.org/docs/rules/func-names) をdisableする

## 実装例

フィールド `id` / `email` のどちらかが必須というのをやりたい場合


```tsx
// イメージが湧く程度の適当なjsx

/*
Props
  loginWithId: boolean        ... IDとメールアドレスのどちらを表示するかを保持するProps
  toggleLoginKey: () => void  ... IDとメールアドレスのどちらを表示するかを切り替える関数
*/

{loginWithId && <p><input type="text" name="id" value="" /></p>}
{loginWithId && <p><input type="text" name="email" value="" /></p>}
<button onClick={toggleLoginKey}>

```

```typescript
yup.object().shape({
  id: yup
    .string()
    // eslint-disable-next-line func-names
    .test('email', 'ログインIDを入力してください', function(value) {
      return this.parent.email || value
    }),
  email: yup
    .string()
    .email('メールアドレス形式で入力してください')
    // eslint-disable-next-line func-names
    .test('email', 'メールアドレスを入力してください', function(value) {
      return this.parent.id || value
    }),
})
```

見えなくなったFiledの値はToggleする関数内でemptyにしておく。
PEP8の警告が出たときの対応

## 動作環境
python3
PyCharm(無料版)

# PEP8に準拠したコーディングをしたい場合の設定
PyCharm左上のメニュー欄から
File -> Settings -> Editor -> Inspections -> Python -> PEP8 coding style violation から week warning を warning に上げる。
また、その下の PEP8 naming convention violation の設定も warningに変更する。


# エラーの表示文と直し方
以下、具体的なエラーの対応方法です。
これらのエラーは、静的解析といい、PyCharmでは無料版においても即時にチェックしてくれます。この結果、バグの防止や可読性が上がります。

## PEP8 do not use bare except
と警告が出たら
except:
↓
except FileNotFoundError:
というように、エラーのパターンを記載する。
一度エラーを出して確認すれば、何のエラーかわかります。

## Function name should be lowercase
ReadFile
↓
read_file

## Remove redundant parentheses
余計なカッコを削除すればよい
class ClassA():
↓
class ClassA:

## PEP8: expected 2 blank lines, found 1
１行の空白を２行に変更すればよい

## PEP8: expected 2 black lines after class or function definition, found 1
１行の空白を２行に変更すればよい

## PEP8: block comment should start with '# '
 #のあとに半角のスペースを入れる

## PEP8: identation contains mixed spaces and tabs
インデンテーションでスペースとタブが混在している

## Method "xxx" may be 'static'
メソッドの一行前に@staticmethodを付ける

## Shadows built-in name 'xx'
既存の（組込みの）名前 'xx' とかぶっている（shadow 覆い隠す）。
バグの温床になるので無くすようにする

## continuation line under-indented for visual indent
(視覚的なインデントのために継続行がインデントされていません)
引数を最初の行におかずに二行目から列挙していく。ちょっと複雑

## simplify chained comparison
（連鎖している比較を簡素化しなさい）
PyCharmの場合、Alt + Shift + Enterを押すと、自動で修正してくれる