OmniAICreator/Qiita-1.07M huggingface dataset:
【Swift】NavigationControllerへの画面遷移で値を渡す

## 概要
あるViewControllerから、NavigationControllerの階層下にある次の画面へShowで遷移する際に値を渡す方法です。

ここで、現在のViewControllerはNavigationControllerの階層下にはなく、値の渡し先はNavigationControllerのroot view controllerであるという前提です。

## 準備
storyboardでNavigationControllerに`Identifier`をつけてください。

今回は例のため`"NavigationController"`としました。

<img width="456" alt="スクリーンショット 2019-02-21 15.05.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/163599/319c8c39-306f-436c-20f0-034506a44867.png">

## 値渡し
```.swift
let storyboard: UIStoryboard = self.storyboard!
let nc: UINavigationController = storyboard.instantiateViewController(withIdentifier: "NavigationController") as! UINavigationController
let followingVC = nc.viewControllers[0] as! FollowingViewController
followingVC.variable = self.variable  //ここで値渡し

self.present(nc, animated: true, completion: nil)  //画面遷移
```

ちなみに、`nc.viewControllers[0]`の部分は`nc.topViewController`でも大丈夫だと思います。（root view controllerを指定するという点においては前者の方が分かりやすくていいですが）
Ruby 学習　基本　（メソッド）




#はじめに
  Rubyの学習を始めました。学んだことを忘れないように備忘録として残しています。


##メソッド定義
  ※def メソッド名　endの間にまとめたい処理を書く
  ※メソッドを定義する時に用意した引数はそのメソッドの中でしか使うことが出来ない。 メソッド内で定義した変数も同様。

```Ruby

 def introduce(name,age)  # メソッド名(引数名1,引数名2)

   message = "My name is #{name}."
   puts message  # 　メソッド内では使える
   puts "I am #{age} years old."


 end

 introduce(Ken,30)   #メソッドの呼び出し My name is Ken.

```


 ```Ruby
  def add(a,b)
    return a + b   # aとbを足した値が戻り値として呼び出し元に帰る
  end

  sum = add(2,4)  # 呼び出し部分
  puts sum # 6

```  
真偽値を返すメソッドはメソッド名の末に？をつける習慣がある。

```Ruby
 def negative ? (number)  #  True or False を返す。
                          
   return number < 0
 end

 puts negative?(8)
```
returnは戻り値の返すだけではなく、メソッドの処理を終了させる性質ももっている。
よって、returnの後にあるメソッドの処理は実行されない。



キーワード引数を持つメソッドの書き方
  1 定義側で引数の後にコロン(:)をつける
  2 呼び出し側で、値の前に引数名を書く
  
```Ruby

 def introduce(name:,age:,place:)
   put "My name is #{name}"
   put "#{age}years old"
   put "I am from #{place}"
 end

 introduce(name:"John",age:24,place:"Canada")

 ```
nc と ping をつかってサーバリストから接続確認をするシェルスクリプト

excelおじさん貼り付けようですぐに作る必要があったので雑ですが


server_list
```
domain.jp:www.domain.jp
```


nc_to_csv.sh

```nc_to_csv.sh
#!/bin/bash

#set -x
SERVER_LIST="./server_list"
CMD="nc -w 0.1 -i 0.01 -vz"
PORT=(22 25 80 443)
CMD02="ping -w 0.1 -c 1 -t 1"
RESULT_FILE="/tmp/nc.csv"

if [ -f ${RESULT_FILE} ]; then
  rm ${RESULT_FILE}
fi

for LIST in $(cat ${SERVER_LIST}); do
  for i in "${PORT[@]}"; do
    RECORD=$(echo ${LIST} | awk -F":" '{print $1}')
    SERVER=$(echo ${LIST} | awk -F":" '{print $2}')
    ${CMD} ${SERVER} ${i} 2>/dev/null
    if [ $? = 0 ]; then
     RESULT+=("YES")
    elif [ $? = 1 ]; then
     RESULT+=("NO")
    else
     RESULT+=("fail")
    fi
  done

  ${CMD02} ${SERVER} 1>/dev/null
  if [ $? = 0 ]; then
   RESULT+=("YES")
  elif [ $? = 1 ]; then
   RESULT+=("NO")
  else
   RESULT+=("fail")
  fi
  #echo "${SERVER} ${RESULT[@]}"

  RESULT_COMMA=$(echo "${RESULT[@]}"  | sed -e 's/\ /\,/g')
  echo "${LIST},${RESULT_COMMA}" >> ${RESULT_FILE}
  RESULT=()
done

```


実行

```console
$ ./portcheck.sh
13.115.109.xx NO YES NO NO NO
54.64.135.xx NO  NO  NO NO NO
```
マネージャとリーダーを誤魔化さずに白黒つける

## なに？

**マネージャー** とか **リーダー** とか違いがよくわからないという話が多いのでちゃんと整理してみる。

## 前提

それなりに説明を書きますが、なんだかんだ言って厳密な定義があるわけではないので、結論「わたしはこう思う」という内容になっています。とはいっても、なるべくそうならないように世の中で平等な視点で書いたつもりです。

## マネージャーとリーダーに関する誤解

さっそくですがいくつかの誤解が混乱のもとになっていると思うので説明してみます。

### 混乱の原因１：役割と人がごっちゃになってる

まず言葉の整理。

- マネージャー
- リーダー

これはロール、役割、役職、つまり人を指してます。

- マネジメント
- リード

これは具体的な行動、機能を指す言葉です。

つまり、

- 主に **マネジメント** を行う人が **マネージャー** と呼ばれて、
- 主に **リード** を行う(リーダーシップを発揮する)人が **リーダー** と呼ばれます。

１つ注意はこれらは排他的なものではなくてマネジメントをしつつリーダーシップを発揮する人もいるのでマネージャーかつリーダーという人もいます。現場のエンジニアやデザイナーの方でリーダーシップを発揮している人もいます。デザイナーでマネージャーという人ももちろんいます。


### 混乱の原因２：なり方が違う。気持ち次第でリーダーにはなれるがマネージャーにはなれない

最初にリーダーについてです。

物事をリードする、リーダーシップを発揮するのがリーダーです。
その人の普段の心がけや行動によっていくらでも**好きなだけリーダーシップは発揮できます**。
チーム全員リーダーというのもありえます。Scrumの自己組織化されたチーム等はそれに近いです。
逆に「リーダーになってくれ」と言われて仕事としてリーダーシップを発揮し続ける人もいます。

次にマネージャーについてです。

マネジメントを行うのがマネージャーです。
マネジメントととは簡単に言うと目標を達成する責任を持つことで、目標達成のために経営資源を使う権限を持っています。
権限が必要ということは、**任命(権限委譲)される必要があります**。
なので自分からマネージャーになる！と言ってもダメで、誰かから（通常は上の人間から）任命されてなるものです。
自分から「わたし部長です」と言ってもダメで、会社から「あなたを部長に任命します」と言われて初めてなれるものです。

つまり、リーダーは権限が不要で自分の行動によってなれるもので、マネージャーは権限が必要で任命されてなるものです。

＊＊＊

まずは、ここの誤解さえはっきりしていればそんなに混乱することはありません！！

## 具体的な説明

### そもそもリーダーシップとは何か？

*「リーダーたる者は目的を一致させ，組織の方向づけを確立する」*

この言葉にあるようにリーダーがやるべきこと、つまりリーダーシップとは、チーム（や組織や個人）を目標に向かって推し進めていくことです。引っ張っていくことです。

チームを実際に動かし目標に向かって推進していくのがリーダーの仕事です。

> とはいえ力強く引っ張るだけがリーダーシップではなく、サーバントリーダーシップのようにみんなを支えるような手法もあります。どちらにせよ目標達成のために具体的にチームを動かすのがリーダーです。

その人がリーダーかどうかの判断は簡単で、フォロワーがいるかどうかです。その人のことを信頼してついてきてくれる人（フォロワー）がいたらその人はリーダーです。そのフォロワーに対して何かしらのリーダーシップを発揮してます。

繰り返しですが、目標に向かって自分をみんなを推し進める活動、がリーダーシップです。

### ではマネジメントとは？

マネジメントは、目標を達成することに対して責任を持っています。何としても目標を達成するのが仕事です。

目標の達成のための環境を作ること、手段を定めること、定めた手段が問題なく動いているかを管理（チェック）することです。そのための権限を持っています。

何を言っているかと言うと、例えば予算であったり人であったりを調達してチームやプロジェクトを作り、そのチームやプロジェクトが目標達成に向かって活動しやすいな環境を構築し維持することです。例えば組織を作る、ルールを作る、人を集める、ソフトウェアを購入するなどです。

> 平たく言うと、働く環境を作る、働きやすい環境を作る、のがマネジメントのやることです

自分の権限で使ったお金や人の結果がどうだったかを確認・是正する責任があるため、多くの場合は活動のレポート先になります。
そして自分の権限を維持するため（つまりチームやプロジェクトを維持するため）に上位の組織やスポンサーへの説明責任も持っています。
そのため現場に実際の活動についての詳細なレポートを求める傾向があります。

> 株主に正しい説明をしないと株主からお金がもらえないのと一緒です。関係者に正しい説明ができないとプロジェクトを維持するための経営資源を守ることができないのです。

マネジメントは基本的にはある組織の中での役職です。

### もう少しだけ違いを補足すると。。

ある集まりがあったときに自然発生的に「リーダー」が生まれることはあります。集まりの中で特に強いリーダーシップを発揮している人がいたときに「あの人がリーダーだな」となることはあります。リーダーはその活動の延長にいる存在だからです。

逆に、自然発生的に「マネージャー」が生まれることはありません。マネージャーは外から連れてこられるか、基本的に任命されてなるものだからです。マネージャーはその集まりの普段の活動の延長にはいないからです。

現場ですぐれた担当者・リーダーだった人がすぐれたマネージャーにならないのも同じ理由で、マネージャーは現場の延長にはいない存在なのです。

> まあ、なのでマネージャーは一般的に現場から嫌われることが多いという悲しい定めなのです。。。


## まとめ

ということで **マネージャー** と **リーダー** はごっちゃになります。

なぜかというと、**マネジメント** と **リーダーシップ** という活動は両方同時に発揮されることがあって、それは大抵の場合において一人の人間が同時に発揮することが多いからです。

「マネジメント活動の成果」と「リーダー活動の成果」と「現場活動の成果は」はまったく別物なのですが、それが場合によっては一人の人間が同時に行っていることが多いのが混乱の元です。

> なので成果を見るなら「わたしがやったこと」という大きなくくりにせずん、「わたしはマネジメントとして〇〇をしました」「リーダーとして〇〇をしました」という風に分けて考えればよいです。

マネージャーは目標達成のため働きやすい環境を作りリーダー（チーム）がプロジェクトを遂行する。
リーダー（チーム）は環境が正しく機能しているおかげで進捗がでていることをマネージャーに報告する。

基本はこれだけのことでなのす。

あ、これが一番端的でわかりやすい説明かも。

**Good leaders do the right things, good managers do the things right**

以上
PHP: どのエラーハンドラが使われているか調べる方法

フレームワークを使っていたり、`set_error_handler`を使ってエラーハンドリングまわりを拡張したりしていると、エラーハンドラが複数あっていったいどのエラーハンドラが使われているのか分からなくなることがある。

そうしたときに現在アクティブなエラーハンドラを調べたくなるが、PHPにはそれをストレートにやる方法が無いので、自前でデバッグロジックを実装する必要がある。(`get_error_handler`とか`get_error_handlers`とかあってもよさそうなのに)

このような処理を書くと、現在アクティブなエラーハンドラがどこに定義されているものなのか調べることができる:

```php
// 仮エラーハンドラをセットすることで、現在のハンドラを取り出す
$currentHandler = set_error_handler(function(){});

// 仮エラーハンドラを取り消して、現在のハンドラに戻す
restore_error_handler();

// リフレクションで現在のハンドラの情報を取る
$handlerInfo = new \ReflectionFunction($currentHandler);

var_dump(
	// 現在のハンドラが定義されているファイル名を調べる
	$handlerInfo->getFileName(), 
	// 現在のハンドラが定義されている行数を調べる
	$handlerInfo->getStartLine()
);
```

これをエラーが発生している箇所の手前に置くなりしてデバッグに活用する。

```php
$currentHandler = set_error_handler(function(){});
restore_error_handler();
$handlerInfo = new \ReflectionFunction($currentHandler);
var_dump(
	$handlerInfo->getFileName(), 
	$handlerInfo->getStartLine()
);

@unlink('/hoge'); // エラーハンドラにて処理されているエラー発生箇所
```
Laravel チートシート ルーティング 編

#ルート一覧
    php artisan route:list

#ルートパラメータ
リクエストパラメータとの混同注意

### 強制  
```php5
    Route::get('/book/detail/{id}', 'Admin\BookController@getBookDetail')
        ->name('book.detail')
        ->middleware('https');
```  
    
### 任意
```php5
    Route::get('/book/detail/{id?}', 'Admin\BookController@getBookDetail')
        ->name('book.detail')
        ->middleware('https');
```
### コントローラ例
```php5
    public function getBookDetail($id = null)
    {
    
    	$book = Book::find($id)
    	
    	return view('book.detail', compact('book'))
    
    }
```
### リンク例
```html
    <a href="{{route('book.detail', $book->id)}}" >
```
Laravelのartisan serveでポート80を指定したらエラーが出た

#背景
Laravelのphp artisan serveを使用すると自動的にポート8000が割り当てられます。
$ php artisan serve
Laravel development server started on http://127.0.0.1:8000/

ポート80を指定した場合に、エラーが出てしまいました。
$ php artisan serve --port=80
Laravel development server started on http://127.0.0.1:80/
[Thu Apr 13 21:08:44 2017] Failed to listen on 127.0.0.1:80 (reason: Permission denied)

#対応
sudoを付けて、artisan serveコマンドを実行する。
$ sudo php artisan serve --port=80
Password:入力してね
Laravel development server started on http://127.0.0.1:80/
【Swift】前の画面への値の受け渡し方

## 概要
アプリを作っているときに次の画面への値渡しは遷移先のViewControllerのインスタンスを取得したり、`prepare(for segue: UIStoryboardSegue, sender: Any?)`を用いることで行えます。

今回はその逆で、遷移した先の画面から **遷移元の画面へ値を渡す** 方法についてです。

## NavigationControllerなし
画面の遷移にNavigationControllerが関係していない状態での値の受け渡し方法です。多くの場合はこの方法を用いると思います。

```.swift
 let preVC = self.presentingViewController as! PreviousViewController
 preVC.variable = self.variable  //ここで値渡し
```

UIViewControllerのプロパティである`presentingViewController`には遷移元のViewControllerのインスタンスが格納されているので、それを取得してやれば値を受け渡せます。

## NavigationControllerあり
上記のように`presentingViewController`を取得するところまでは同じ流れですが、プロパティにNavigationControllerが格納されるので以降の処理が少し変わります。

### Showではない遷移をしてきたとき
```.swift
let preNC = self.presentingViewController as! UINavigationController
// let preNC = self.navigationController as! UINavigationController でも可能かと思います
let preVC = preNC.viewControllers[preNC.viewControllers.count - 1] as! PreviousViewController
preVC.variable = self.variable  //ここで値渡し
```

### Showで遷移してきたとき
```.swift
let preNC = self.presentingViewController as! UINavigationController
// let preNC = self.navigationController as! UINavigationController
let preVC = preNC.viewControllers[preNC.viewControllers.count - 2] as! PreviousViewController
preVC.variable = self.variable  //ここで値渡し
```

### 補足説明のようなもの
UINavigationControllerのプロパティである`viewControllers`は、公式ドキュメントを参照すると

>
The root view controller is at index 0 in the array, the back view controller is at index n-2, and the top controller is at index n-1, where n is the number of items in the array.

のように記述されています。つまり`viewControllers`の0番目にはroot view controller、n-1番目には表示されているViewController、n-2番目には一つ前のViewControllerが格納されているようです。
MySQL8.0新機能 (caching_sha2_password 認証プラグイン)を回避したい。

#MySQL8.0の新機能追加のおしらせ。

MySQL8.0で新規追加された認証プラグイン(caching_sha2_password)について確認します。

MySQL5.7までの認証プラグインには mysql_native_password がデフォルトで使用されていましたが、
MySQL8.0より新たに追加された caching_sha2_password に変更されました。
SHA-256を使用した、より安全なパスワードの暗号化を提供するとともに、キャッシュを使用して同一ユーザの認証処理を高速化しようという、MySQL推奨の認証プラグインです。

MySQL8.0を導入して最初につまずくのがこれです。



#環境確認
caching_sha2_password 認証プラグインの確認方法
デフォルトに設定されている認証プラグインを確認します。

```Bash
mysql> show variables like 'default_authentication_plugin';
+-------------------------------+-----------------------+
| Variable_name                 | Value                 |
+-------------------------------+-----------------------+
| default_authentication_plugin | caching_sha2_password |
+-------------------------------+-----------------------+
1 row in set (0.00 sec)
```
この設定があると、Mysql8.0未満のMySQLクライアントからの接続に失敗したりします。

#回避方法
１．デフォルト「mysql_native_password」に書き換える。
２．MySQLクライアントを8.0以上にする。
このあたりになりますが、プログラムの接続の場合、そもそも「caching_sha2_password」に対応してなかったりします。
Python3.6とかそうでした。(2019/02現在)

今回は「デフォルト「mysql_native_password」に書き換える。」についての手順を書きます。

###my.cnfを設定する。ただしどこにあるかは環境によって異なるかもしれないため、下記を実行して設置候補から探す。
```Bash
$ mysql --help | grep my.cnf
                      order of preference, my.cnf, $MYSQL_TCP_PORT,
/etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf 
```

###llコマンドでファイルを探していく
```Bash
$ ll /etc/my.cnf
-rw-r--r-- 1 root root 1297 Nov 29 10:12 /etc/my.cnf
$ ll /etc/mysql/my.cnf
ls: cannot access /etc/mysql/my.conf: No such file or directory
$ ll /usr/etc/my.cnf
ls: cannot access /usr/etc/my.cnf: No such file or directory
```

###みつかった、my.cnfを修正
```Bash
$ sudo vi /etc/mysql/my.cnf
default_authentication_plugin= mysql_native_password
#上記を追加する。コメントアウトされている可能性大。
```


###MySQLを再起動する。
```Bash
$ sudo systemctl restart mysqld
```
これで設定は完了。

# 確認
```Bash
mysql> show variables like 'default_authentication_plugin';
+-------------------------------+-----------------------+
| Variable_name                 | Value                 |
+-------------------------------+-----------------------+
| default_authentication_plugin | mysql_native_password |
+-------------------------------+-----------------------+
1 row in set (0.00 sec)

```
無事、caching_sha2_password 認証をすることができました。


# おまけ
### Python3での接続確認コード。
```connect_to_DB.py
import mysql.connector as db

def connect_to_DB():
    try:
        mydb = db.connect(
        host = "ec2-52-11-217-26.us-west-2.compute.amazonaws.com",
        user = "seifuen",
        passwd = "ibs3050",
        database = "seifuen",
        port = 3306,
        auth_plugin = 'mysql_native_password')
        
        print('DBへの通信に成功しました。')
        
    except Exception as e:
        print('[ERROR: catch_loop_video] DBへの通信に失敗しました {}'.format(e))
        return
    return mydb


connect_to_DB()
```
LightGBMのパラメータ(引数)

LightGBMにはsklearnを利用したパッケージとオリジナルが存在する．これらのパッケージはパラメータ名が異なるので備忘として記録．

# インストール方法
以下の記事を参考にした．
https://qiita.com/tackey/items/fa3e4ca37beecb1c7842

# 実行方法

```py
import lightgbm as lgbm

lgb_params = {"objective":"binary", 
              "metric":"binary_logloss", 
              "verbosity": -1}

lgb_train = lgbm.Dataset(
                 x_train, 
                 y_train)

lgb = lgbm.train(lgb_params, lgb_train)

lgb.predict(x_test)
```

# 引数の種類
参照は[Microsoftのドキュメント](https://lightgbm.readthedocs.io/en/latest/Parameters.html)と[LightGBM's documentation](https://testlightgbm.readthedocs.io/en/latest/Parameters-tuning.html)．
以下の詳細では利用頻度の高い変数を取り上げパラメータ名と値の対応関係を与える．

## objective（目的関数） 
### regression
回帰を解く．
metric(誤差関数の測定方法)としては，
絶対値誤差関数(L1)ならばmae, 
2乗誤差関数(L2)ならばmseと指定．

### binary
二値分類．ラベルは 0 or 1．
metricとしては，
binary_logloss(クロスエントロピー)とbinary_error(正答率)の2つ．

### multiclass
多クラス分類．
metricとしては，
multi_logloss(softmax関数)とmulti_error(正答率)の2つ．
また，クラスの数をnum_classとして設定することが推奨されている．

## learning_rate
学習率．デフォルトは0.1．大きなnum_iterationsを取るときは小さなlearning_rateを取ると精度が上がる．

## num_iterations
木の数．他に num_iteration, n_iter, num_tree, num_trees, num_round, num_rounds, num_boost_round, n_estimators という名前で呼び出すことも可能．デフォルトは100．

## num_leaves
木にある分岐の個数．${\bf sklearnのmax\\_depth}$との関係は
$num\\_leaves = 2^{max\\_depth}$
デフォルトは31．大きくすると精度は上がるが過学習が進む．

## max_depth
木構造の深さを限定するための変数．データが少ないときに過学習を防ぐために設定する．デフォルト値は-1で0以下の値は制限なしを意味する．

## verbosity
学習途中の中継的な情報を表示するかしないか．
デフォルトでは表示になっており，-1を指定すると表示しなくなる．

# マニアックな引数

## max_bin
一つの分岐に入るデータ数の最大値を指定．小さい数を指定することで強制的なデータ間の分離を可能にして精度を上げることができるが，大きな数を指定することにより一般性を強めることができる．結果として過学習抑制につながる．

## min_data_in_bin, min_data_in_leaf
正直，違いがわからないが設定されている値のオーダーが異なるので別物．
大きくすることでデータと分岐が1対1対応することを防ぎ，結果として過学習を抑制する．

## feature_fraction
学習の高速化と過学習の抑制に使用される．データの特徴量のfeature_fraction * 100 % だけ使用する．

## weight_column
各列に対して，評価時の重要度を変更可能

[data0, data1, data2,..., dataN]に対して，
[1.0, 0.5, 0.7, ..., 0.4]というような重みをつけることが可能．
WagbyのCSVダウンロード機能で出力内容をカスタマイズする

# 動機
標準のCSVダウンロード機能を利用しつつ、出力するCSVの内容を編集したかった。

サポートのページになかったので調べた内容を記載する。

# Wagbyのバージョン
8.2.0

# やりたいこと
- CSVのヘッダー行を出力しないようにしたい。
- 出力する各カラムの内容を修正(整形)したい。

# CSVのヘッダー行を出力しないようにする
## 前段
Wagbyで作成するアプリケーション上で行うことはあまり推奨されていないらしい。
別途ETLツールとかを使って加工できるならそっちのほうが楽かもしれない。

## Wagbyで作成するアプリケーション上で行う場合
自動生成されるJavaを継承したクラスを作成し、CSV出力メソッドの内容を変更する必要がある。

継承するクラス：_Downloadモデル名ProcessBean_

```DownloadTestProcessBean.java
public Object outputAllData(DbDownloadProcessor out, Map paramMap, boolean getallmodelitem) {
    ...
    // Output header line
    Collection<String> targetitems =
        (Collection<String>) getParameter("targetitems");
    String[] _data = ((jp.jasminesoft.wagby.app.test.TestPCSVHelper)p.appctx.getBean("TestPCSVHelper")).toCsvDataHeader(null, colMap, (ActionParameter)p, getallmodelitem, targetitems);
    out.write(_data);
    ...
}

```

上記メソッドをオーバーライドして記述してあるヘッダー出力処理を削除したメソッドを作成することでヘッダーなしのCSVが作成できる。

この処理はWagbyバージョンアップ時に変更される可能性があるため、バージョンアップしたときは継承元の処理が変わっていないか確認したほうが良い。

# 出力する各カラムの内容を修正(整形)する
サポートページで紹介されていないため、標準のカスタムポイントではないようだが、各行を読み込んで出力するタイミングで呼ばれるjavascriptがあり、そこで内容を編集することが可能。

javascript名：モデル名 ＋ Helper_beforeShowInDownload.js

```TestHelper_beforeShowInDownload.js
/**
 * Javaから呼ばれるメソッド
 */
function process() {
    // ストアモデルの内容を書き換えられる
    test.id = "hoge";
}
```
なおこの時CSVに出力するカラムだけでなく、ストアモデルにはモデルの1レコードすべてが格納されている。
dockerで自分のデータをコンテナ内に反映させるためのmemo

# 自分のデータをコンテナ内に反映させる

docker 使う必要が出てきたので見よう見まねで使ってみた。
イメージを引っ張って、run したら、いきなりrootになってて戸惑った。それから、自分のデータが見えないので、ちょっと焦った。

どうやら
**-v 反映させたいdirectory:コンテナ内でのdirectory**　
で自分のデータをコンテナ内に反映できそう。

*-v /Users/MyName/OneDirectory/:/data* とか
*-v /Users/MyName/OneDirectory/:/home/daresore/data* とか。
適宜。

**複数のdirectoryの指定も可能**

docker run --rm -it -v /Users/MyName/OneDirectory/:/in -v /Users/MyName/AnotherDirectory/:/out docker-image-name
とか。

私の用途だと、
docker run -it --name container-name docker-image-name
docker attach container-name
の組み合わせより使いやすい気がする。
A4のファイルPDFファイルに綴じしろをつける

# やりたいこと
- A4のPDFファイルに綴じしろをつける
    - 例えば1ページ目が表紙だとする
    - 左開きの場合
        - 2ページ目からの偶数ページには右側に余白を付ける
        - 3ページ目からの奇数ページには左側に余白をつける

# 持ってるもの
- 様々な種類のファイルを結合したPDFファイル
    - 例：パワポ，ワードなどをPDF化し結合した200ページの論文集
    - つまり，ワードで一括の余白設定ができないもの
    
- Adobe Acrobat Pro DC
    - Pro版でないとできない可能性が高いです

# 手順

## 概要

A4ファイルをA3の紙に貼り付けて，そこから綴じしろが残るように余白を削っていく．

## Step by step

### 変換前

こんなPDFを持っているとします．
右側の「印刷工程」をクリックします．
![スクリーンショット 2019-02-21 13.11.30.png](https://qiita-image-store.s3.amazonaws.com/0/186209/f5976436-d3b5-b83d-4dc8-0b26868e665e.png)

そして，「ページボックスを設定」をクリック
![スクリーンショット 2019-02-21 13.13.02.png](https://qiita-image-store.s3.amazonaws.com/0/186209/c7dd62e7-ccb3-11b6-b5ce-a109bd019acb.png)

- 「ページサイズを変更」から`ページサイズ：A3`を指定
- 表紙を無視する場合は，ページ範囲から該当ページを消す
- 「OK」をクリック
![スクリーンショット 2019-02-21 13.14.27.png](https://qiita-image-store.s3.amazonaws.com/0/186209/99d125d4-6b07-409b-bfe8-77691c8db1a9.png)

### A3に変換後

![スクリーンショット 2019-02-21 13.18.41.png](https://qiita-image-store.s3.amazonaws.com/0/186209/45fc3524-8e36-7146-7954-abd4bf3de1ba.png)

こんなかんじで余白が大きくできたファイルができます．（この例では表紙が他にあるものと仮定し，今見えているページは冊子の2ページ目とします．）
`トリミング後のページサイズ：209.91 x 297.04`から`拡張後のページサイズ：297.04 x 420.17`になっているので，以下の分だけ余白を削ることができます．

横幅：$87.13mm$ (297.04 → 209.91)
縦幅：$123.13mm$ (420.17 → 297.04)

### 余白を削る

再び「ページボックスを設定」から余白を削ります．
![スクリーンショット 2019-02-21 13.23.42.png](https://qiita-image-store.s3.amazonaws.com/0/186209/3a1bb774-eac1-091b-bf21-88a89927be3d.png)
各枠線の色については[Adobeのページ](https://helpx.adobe.com/jp/acrobat/using/crop-pdf-pages.html)を参照ください．


`余白の制御`から，以下の方針で余白を削っていきます．

- 上下（縦幅）：綴じ代とは関係ないため，上下対称に削っていきます．
    - 上：$61.565mm$ $(= 123.13 \div 2)$
    - 下：$61.565mm$
        - （小数点以下の数字について，ここまでの精度をサポートしているかはわかりませんがとりあえず）
- 左右（横幅）：左開きの場合，2ページ目の綴じしろは右側になるため，右側の余白をあまり削らないようにします．
- 左側は右で削った分に合わせて調整します．
    - 左：$50mm$ $(= 87.13 - 37.13)$
    - 右：$37.13mm$
- ページ範囲
    - 奇数ページにのみ行う場合は`適用先：奇数ページのみ`とします．
   
こんな感じに見えます
![スクリーンショット 2019-02-21 13.40.32.png](https://qiita-image-store.s3.amazonaws.com/0/186209/07646330-4034-fce0-7d17-e1a9bb81f004.png)

- 青：<font color="blue">修正前のA3領域</font>
- 緑：<font color="green">コンテンツがある領域（余白を含む）</font>
- 黒：<font color="black">今回調整した，**印刷・表示される領域**</font>

黒と緑の領域が若干ずれていることがわかります．

# 結果

![スクリーンショット 2019-02-21 13.44.22.png](https://qiita-image-store.s3.amazonaws.com/0/186209/d7752168-58f5-4cfc-d63e-7b53e1f79e71.png)

綴じしろ用の余白をつくることができました．

もう片方（最初に奇数ページの綴じしろ調整をしたのなら，偶数ページのこと）に余白を作りたいのなら同じことを左右入れ替えて行います．`適用先`を変更するのを忘れずに
player.datをデータベースにすることについて 考えてみる[PMMPプラグイン]

#はじめに
この記事では、プラグイン導入における
ユーザーのデータ管理の手段を考察していきます。

PocketMine-MP(以下PMMP)利用者に向けた記事です。

ちなみに今回書く**例**は、
**API4.0.0以降のPMMPでは使用できない**のでご注意ください。

4.0.0でも恐らく書き方を変えれば(恐らく)使えますので
(気が向いたら)API4.0.0向けも書こうと思います。

私は**Steadfast2**を推します。
 

# 目的の説明
タイトルの player.datとは、
``players/{プレイヤー名}.dat``を指すこととします。

PMMPを触ったことがある方ならわかると思いますが、
プレイヤーデータを保存しているファイルとなります。

一般的には リスポーン地点, ログアウト時の座標, インベントリ, 体力...等
を保存しています。
　

ではここでプラグインの話に移ります。

あなたのプラグインでは、データはどのように管理しているでしょう。

恐らくほとんどは、``plugin_data/プラグイン名/○○.yml``や``.json``, ``.db``等で保存し、
管理をしていることだと思います。
レガシーを有効にしてるのであれば``plugins/プラグイン名/○○``にありますね。
　

では、タイトル通り、**player.datにプラグインのデータ**をぶち込み、
データ管理をすることと、その考察をしていきます。
　
#書き方
先程さらっと player.datに保存することについて触れましたが、
どんな感じなコードになるのか分からない方もいると思います。

簡単な例を使って書いてみます。

### 例1：プレイヤーに数字のデータを付けてみる
よくプラグインの保存で使われるyaml形式だと
``MyDeacy: 53 ``
のようになります。
こういう保存ファイルはよく見ると思います。

で、player.datに保存する方法はこちら。

```php
//$playerはPlayerオブジェクトとする
$nbt = $player->namedtag;
$nbt->setTag(new CompoundTag("Sample",
	[
		new IntTag("num", 53)
	]
));
```

一つ一つ解説していきます。

**``$player->namedtag``**
で プレイヤーに紐づけられているNBTデータを取得します。
ここではplayer.datの中身が入っています。

**``$nbt->setTag(new CompoundTag("Sample"``**
先ほど取得したNBTデータの中には gamemode や health などの項目があります。
目的の説明で述べたようなものが入っています。
そこに、Sample という項目を作成します。
フォルダを作成するイメージです。

**``[new IntTag("num", 53)]``**
Int型のデータを入れます。
"num" と書いてあるのはキーです。
Configからデータを読むとき、``get("num")`` とするイメージです。

このデータは、player.datが保存されるとき
勝手に書き込まれます。

また、CompoundTagの中身は配列で複数入れることができます。
次の例で簡単に解説します。


### 例2：複数のデータを入れてみる
先程はInt型の1つのデータのみでしたが、前述の通り
配列で複数データを入れることができます。

そして、データ型ごとにTagがあり、
様々な型のデータを扱うことができます。

詳しくは
https://github.com/pmmp/NBT/tree/master/src/tag

では例

```php
$nbt->setTag(new CompoundTag("Sample",
    [
        new IntTag("num", 53),
        new StringTag("brain", "odabutsu")
    ]
));
```
このように配列で複数入れることができます。
簡単ですね。

### 例3：取得する
いくら保存方法が分かっても取得する方法が分からないと
意味がありません。

getter/setterの概念に慣れている方ならなんとなくわかりますよね。

例えば例2のデータを取得するとなるとこのようになります。

```php
$nbt = $player->namedtag->getCompoundTag("Sample");

$num = $nbt->getInt("num");
$brain = $nbt->getString("brain");
```
簡単ですね。
例1,2が分かればなんてことないと思います。
よって解説は省きます。
　
#メリットとデメリットについて
まず、この手段を用いる利点としては、プレイヤーデータに直接紐づけられるので
ファイルが多く生成されたり、
一つのファイルにプレイヤーごとのデータが大量に入ることが少なくなり、
見かけ上 楽になることです。

いつものプレイヤーデータのセーブに少し+αされるのみなので
IOの非同期云々を考慮する必要が(そこまで)出てくることはないです。
Playerオブジェクトさえあれば 簡単にデータを取ることができ、
プラグインでの利用としては扱いやすいのではないかなと思います。
　

デメリットは、プレイヤー個別にデータを持つことになるので
集計などでデータをリスト化することが困難になるのが不利な部分だと思います。

また、例を見てもらった通り、データを編集するたびにインスタンスを生成しています。
滅多にないとは思いますが一度に扱うデータが**極端に膨大**になりすぎると 
処理が適切に追えるようになるのか 少し心配な面もあります。

###まとめるとこんな感じ
#### メリット
・プレイヤーオブジェクトがあれば直接データを取得、編集ができ便利
・複数のプラグインで同時に使えるので 上手く使うとファイルが大量に生成されることがなくなる
・保存はPMMPの処理が勝手に行ってくれるため配慮は最小限で済む

#### デメリット
・データのリスト化が困難
・超膨大なデータを扱うときの配慮が必要
・オフラインプレイヤーへの配慮も必要

これ以上にもメリットデメリット双方挙げられますが
代表的なのはこんなものだと思います。
　
# 私がたどり着いた結論
**"リスト化する必要のなく、頻繁に読み書きを行わないデータ"**ならば
player.datへの保存を採用する機会は十分にあるのではないかなと考えます。

リスト化すると便利な所持金やレベルのようなデータに関しては
素直にJSON, SQLite等を使うべきですね。
　

ということをおよそ1か月前に考え、
サンプルとしてログインプラグインを作りました。

宜しければ評価をお願いします。
https://github.com/MyDeacy/PMLogin
　

#おわりに
拙い文章でしたが最後まで読んでいただきありがとうございます。
結論で述べた通り、デメリットはあるもののきちんとした使用価値を見出せました。

このような使い方も悪くはないと思います。
あなたはどうお考えでしょうか。
jupyter notebook/pythonで時間のかかる処理が終わったときにslackに通知する

# 概要
jupyter notebookで時間がかかる作業をする場合、終わるまで別の作業をすると思いますが、
そちらの作業に没頭してしまい、元の作業が終わっていたことに気づかないことがよくあります

対処法として通知を飛ばしたくなると思います。現時点で僕が一番いいと思った方法をまとめます

# 通知の要件
同じ悩みを持つ人はたくさんいるので様々なpipのpluginが公開されています。いろいろpipを漁ったのですが、結論を先にいうとslackのwebhook apiをそのまま叩くのが一番シンプルでよさそうということになりました

通知の要件としてはデスクトップ通知で画面に割り込んでくれたり、スマホが振動したりするのが分かりやすくて良いです。slackであれば自分にメンションを飛ばせば通知が飛ぶのでシンプルに実現できます
(notify_runというweb pushを使うライブラリがあるのですが、PCとスマホの両方に通知を飛ばすのはslackを使ったほうが楽です)
(slackのアカウントが無い人は自分用に適当に作ってください。無料アカウントが使えます)

# slackのwebhookの有効化
下記の公式ページに従って有効化してください
https://api.slack.com/incoming-webhooks

# jupyterでの準備
jupyterの上の方のセルで関数を定義しておきます
webhook urlはPOST通信で叩きます。HTTPアクセスを行うのに、デフォルトで入っていることの多いrequestsプラグインを使うのでインポートします
(aws sagemakerのjupyter環境にはデフォルトで入っていました)
(もしrequestsプラグインが入っていなければpip install requestsしてください)

```
import requests
def slack_notify(msg = 'おわったよ'):
    slack_user_id = '＜あなたのアカウントのuser_id＞'
    slack_webhook_url = '＜先程設定したwebhookのurl＞'
    requests.post(slack_webhook_url, json={"text":f"<@{slack_user_id}> {msg}"})
```
(slackwebというラッパーライブラリがあるのですが、上記を書くのと変わんないのと、pip installをする手間が面倒なので使いません)

user_idの調べ方は下記記事を参照してください
https://qiita.com/ryo-yamaoka/items/7677ee4486cf395ce9bc

# 通知を送りたい処理で関数を呼び出す
重い処理の最後で先程定義した関数を呼べば通知されます

```
なんか重い処理

slack_notify()
```

いちおう文字列を与えるとメンション内容が変わるようになっています

```
なんか重い処理

slack_notify('データのダウンロードが終わった')
```

当然ですが、関数定義のjupyterのセルを実行しておくのを忘れると、関数が未定義でエラーになります
それが嫌な人は上記のセルの中身をまとめて各呼び出し側に書くことになると思います
PHPの基本

[未来電子テクノロジー](https://www.miraidenshi-tech.jp/intern-content/program/)でインターンをしている**西尾芽衣**です。

最近HTML、CSSの基本を終えたので、PHPを勉強していこうと思っています！

PHPを学ぶことで、ユーザーからのデータを表示できたり、実際のWebサービスで必要な機能をつくることができます。

今回は、PHPの基本的な知識をアウトプットします。

#PHPの文法
文末にセミコロン；を付けます。
文字列を出力させる場合、echoで表示させます。

```php
<?php 
echo ’HELLO!!’;
?>
```

文字列を出力する際はシングルクオーテーションマークですが、代入や計算結果などを出したい場合はダブルクオーテーションマークを使います。

#PHPで計算する
足し算は+
引き算は-
掛け算は*
割り算は/
割り算の余りは%
で表されます。

#変数
変数とは、データの入れ物の事であり、頭に＄を付けて表します。
＄変数名＝値；でさまざまな値を変数に入れられます。
変数の役割は、主に2つあります。

- データに名前を付けてそのデーターが何を表しているのかを分かりやすくする
- 複数回使うデータを1つの入れ物に入れておくことで変更があっても一カ所の修正で済む

変数名は、英単語で表し、2語以上の場合は大文字で区切らなければいけません。

#変数に数字を足す
`＄x=＄x+10;`
`＄x=＄x/3;`
などの計算を、
`＄+=10;`
`＄x/=3;`
のように省略することができます。

#文字列の連結
`.`を用いて文字をつなげることができます。

```php
$name=’mei’;

echo $name.’です。’;

//meiです。
```
と表されます。


#最期に
今回は、PHPの基本中の基本をお伝えしました。
次回もPHPの学びを発信します。
AssumeRoleに一時認証情報をリクエストして環境変数に適応するコマンド

# はじめに

SQSにメッセージするEC2で動く既存プロダクトをローカルで動作確認しようとしたら、怒られた。

```sh
Error in custom provider,
com.amazonaws.services.sqs.model.AmazonSQSException: The security token included in the request is invalid.
(Service: AmazonSQS; Status Code: 403; Error Code: InvalidClientTokenId; Request ID: xxx)
```

# なぜ怒られた？

調査してみると、EC2への認証情報は Instance Profile で提供しているらしいことがわかった。

# どうする？

ということで、一時認証情報をリクエストしてローカルに適用することにした。
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_temp_use-resources.html

# 一発で環境変数を適応するコマンド

## 前提

+ AWS CLI インストール済
+ jq コマンドインストール済
+ 私は fish ユーザーなので bash、zsh の方は良しなに。

## 実際のコマンド

```sh
set aws_secrets (aws sts assume-role \
--role-arn <arn of assume-role> \
--role-session-name "local_session" \
--profile <your profile> \
| jq .Credentials | jq '.AccessKeyId, .SecretAccessKey, .SessionToken' | sed "s/\"//g") \
;and set -x AWS_ACCESS_KEY_ID $aws_secrets[1] \
;and set -x AWS_SECRET_ACCESS_KEY $aws_secrets[2] \
;and set -x AWS_SESSION_TOKEN $aws_secrets[3]
```

おしまい。
Interface Builderでの指定色とコードでの指定色の違い

### Q. `Interface Builder` で設定した色と、コードから設定した色が微妙に違う？
A. `Interafce Builder` で設定した色の **Color Profile** を確認しましょう。

OSのカラーピッカーで何も考えず色を選択すると、Color Profileが `Generic RGB` が指定された状態になっています。

<img width="595" alt="スクリーンショット 2019-02-21 12.38.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/25727/9aa4586c-948c-469f-5b08-78340669b3c7.png">

このときのStoryboardファイルを見ると、`colorSpace` 属性が `calibrateRGB` になっています。

```Main.storyboard
<color key="backgroundColor" red="0.5" green="0.6" blue="0.7" alpha="1" colorSpace="calibratedRGB"/>
```

そしてこの色のRGB値を `UIColor#getRed(_:green:blue:alpha:)` で取得すると、 **指定値 `rgb(0.5, 0.6, 0.7)` とは異なる値** が返ってきます。
一方、コード上で同じ値を指定して `UIColor` を生成すると、Interface Builder上で指定した色と色味が微妙に異なることがわかります。

<img width="50%" src="https://qiita-image-store.s3.amazonaws.com/0/25727/f217ba8f-05a2-d690-cccc-08cde587d474.png">

同じ色味に揃えたい場合は、Color Profileを `sRGB` に変更しましょう。

<img width="80%" src="https://qiita-image-store.s3.amazonaws.com/0/25727/e02633c8-4c01-ec92-7ee5-b59b8ec24976.png">

コードで指定した色と合わないときや、デザイナーさんから「なんか色が違う...」と突っ込まれたら、一度確認してみるとよいと思います。
eslint( standard + prettier + typescript )

暫定

## Node.js用

```
yarn add --dev eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-prettier eslint-config-standard eslint-plugin-import eslint-plugin-node eslint-plugin-prettier eslint-plugin-promise eslint-plugin-standard prettier
```

```json:.eslintrc.json
{
  "extends": [
    "standard",
    "plugin:prettier/recommended"
  ],
  "plugins": [
    "@typescript-eslint"
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
      "sourceType": "module"
  },
  "rules": {
    "@typescript-eslint/adjacent-overload-signatures": "error",
    "prettier/prettier": [
      "error",
      {
        "singleQuote": true,
        "semi": false
      }
    ],
    "yoda": "off",
    "no-unused-vars": "off",
    "@typescript-eslint/no-unused-vars": "error",
    "no-dupe-class-members": "off"
  },
  "globals": {
    "fetch": false
  }
}
```

## React用

```
yarn add --dev @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-prettier eslint-config-standard eslint-plugin-import eslint-plugin-node eslint-plugin-prettier eslint-plugin-promise eslint-plugin-react eslint-plugin-standard prettier @typescript-eslint/parser
```

create-react-app後

```
yarn add eslint-config-prettier eslint-config-standard eslint-plugin-node eslint-plugin-prettier eslint-plugin-promise eslint-plugin-standard prettier
```

```json:.eslintrc.json
{
  "extends": [
    "standard",
    "plugin:prettier/recommended",
    "plugin:react/recommended"
  ],
  "plugins": [
    "@typescript-eslint"
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "rules": {
    "@typescript-eslint/adjacent-overload-signatures": "error",
    "prettier/prettier": [
      "error",
      {
        "singleQuote": true,
        "semi": false
      }
    ],
    "yoda": "off",
    "react/prop-types": "off",
    "import/first": "off",
    "no-unused-vars": "off",
    "@typescript-eslint/no-unused-vars": "error",
    "no-dupe-class-members": "off"

  },
  "globals": {
    "fetch": false
  }
}


```
unity5.2の作法 その4 IlluminanceSensor

#概要

unity5.2の作法、調べてみた。


#写真

![20190221_124508.gif](https://qiita-image-store.s3.amazonaws.com/0/18104/cf74b588-d57e-cc65-2da0-6521ccb91041.gif)

#参考にしたページ

http://ftvoid.com/blog/post/1379

#センサーでモーターを動かす。


```
public class ba2 : MonoBehaviour {
    [SerializeField]
    private HingeJoint WL;
    [SerializeField]
    private HingeJoint WR;
    [SerializeField]
    private IlluminanceSensor LS;
    [SerializeField]
    private float speed = 200;
    [SerializeField]
    private float threshold = 0.5f;
    [SerializeField]
    private float kp = 1;
    [SerializeField]
    private float ki = 1;
    [SerializeField]
    private float kd = 1;
    private float errorInt = 0;
    private float errorPrev = 0;
    private void Update() 
    {
    }
    void FixedUpdate()
    {
        var error = threshold - LS.illuminance;
        errorInt = (error + errorPrev) * Time.deltaTime / 2;
        var errorDiff = (error - errorPrev) / Time.deltaTime;
        var output = kp * error + ki * errorInt + kd * errorDiff;
        var motor = WL.motor;
        motor.targetVelocity = speed - output;
        WL.motor = motor;
        motor = WR.motor;
        motor.targetVelocity = speed + output;
        WR.motor = motor;
        errorPrev = error;
    }
}
```

#カメラでセンサーを作る。


```
public class IlluminanceSensor : MonoBehaviour 
{
    [SerializeField]
    private Camera dispCamera;
    public float illuminance;
    private Texture2D targetTexture1;
    private IEnumerator Start() 
	{
        var tex = dispCamera.targetTexture;
        Debug.Log(tex.width);
        targetTexture1 = new Texture2D(tex.width, tex.height, TextureFormat.ARGB32, false);
        while(true)
        {
            yield return new WaitForEndOfFrame();
            RenderTexture.active = dispCamera.targetTexture;
            targetTexture1.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);
            targetTexture1.Apply();
            illuminance = GetLightValue(targetTexture1);
        }
    }
    private float GetLightValue(Texture2D tex)
    {
        var cols = tex.GetPixels();
        var avg = new Color(0, 0, 0);
        foreach(var col in cols)
        {
            avg += col;
        }
        avg /= cols.Length;
        return avg.grayscale;
    }
}
```

#playerを追いかけるカメラ

```
public class camo : MonoBehaviour 
{
    public GameObject player; 
    private Vector3 offset;
    void Start() 
    {
        offset = transform.position - player.transform.position;
    }
    void LateUpdate() 
    {
        transform.position = player.transform.position + offset;
    }
}
```

以上。
非線形カーネル主成分

```{r}

#kernel component analysis


library(mlbench)

library(kernlab)

n=200

k=10

dat=mlbench.spirals(n,cycles=1.2,sd=0.16)

X=dat$x;Y=dat$classes

data=data.frame(x1=X[,1],x2=X[,2],class=Y)

plot(data$x1[data$class==1],data$x2[data$class==1],type="p",col=2,xlab="x1",ylab="x2",xlim=c(min(data$x1),max(data$x1)),ylim=c(min(data$x2),max(data$x2)))

par(new=T)

plot(data$x1[data$class==2],data$x2[data$class==2],type="p",col=3,xlab="x1",ylab="x2",xlim=c(min(data$x1),max(data$x1)),ylim=c(min(data$x2),max(data$x2)))

kernel=function(x,y){
  
return(exp(-sum((x-y)^2)))  
  
}

K=array(0,dim=c(nrow(X),nrow(X)))

N=nrow(K)

val=0

for(j in 1:nrow(K)){
for(i in 1:ncol(K)){  
 
val=val+kernel(X[i,],X[j,])   
  
}
}  

val=val/(N^2)

for(j in 1:nrow(K)){
for(i in 1:ncol(K)){  
  
  value=kernel(X[j,],X[i,])+kernel(X,X[j,])/N+kernel(X,X[i,])/N+val
  
  K[j,i]=value
  
}
}

eigen_values=eigen(K)$values

eigen_vectors=eigen(K)$vectors

propotion=eigen_values/sum(eigen_values)

comp_principles=eigen_vectors

for(j in 1:length(eigen_values)){
  
comp_principles[,j]=sqrt(eigen_values[j])*comp_principles[,j]  
  
}

comp_principles=comp_principles[,1:2]

plot(comp_principles[,1],comp_principles[,2])

comp_principles=data.frame(comp_principles) %>% mutate(class=kmeans(comp_principles,2)$cluster,y=Y) 

plot(comp_principles$X1[comp_principles$class==1],comp_principles$X2[comp_principles$class==1],type="p",col=1,xlab="x1",ylab="x2",xlim=c(min(comp_principles$X1),max(comp_principles$X1)),ylim=c(min(comp_principles$X2),max(comp_principles$X2)))

par(new=T)

plot(comp_principles$X1[comp_principles$class==2],comp_principles$X2[comp_principles$class==2],type="p",col=2,xlab="x1",ylab="x2",xlim=c(min(comp_principles$X1),max(comp_principles$X1)),ylim=c(min(comp_principles$X2),max(comp_principles$X2)))


```
句読点の色を変えたら読むのが楽になった

[Highlight This!](http://www.deboel.eu/HighlightThis2.html) を使うととても文章が読みやすくなった。

* [chrome用](https://chrome.google.com/webstore/detail/highlight-this/fgmbnmjmbjenlhbefngfibmjkpbcljaj?hl=en-US)
    * Vivaldiで動かすととても軽快に動作した。
* [firefox用](https://addons.mozilla.org/ja/firefox/addon/highlightthis/)
    * firefoxだとプライベートブラウジング中もハイライト表示してくれる。

### 設定

![setting.png](https://qiita-image-store.s3.amazonaws.com/0/25728/00813c12-cc6f-c60a-7992-41cb25ac0a7e.png)

同じものを複数指定する場合は1行に１つ書く

![a.png](https://qiita-image-store.s3.amazonaws.com/0/25728/d1102768-4535-dfbc-e1b6-73b49a9ac104.png)


### これまで

![before.png](https://qiita-image-store.s3.amazonaws.com/0/25728/19f89372-2d52-0817-db96-511a716a952c.png)

###  適用後

![dot.png](https://qiita-image-store.s3.amazonaws.com/0/25728/808647de-b19a-46fc-6cb0-1dc1f3494a31.png)
MySQLに外部から接続したい

# MySQLに外部から接続したい

Laravelを使ってWebアプリを作成していました。

## 環境
- Ubuntu 19.04 (daily build, 4.19.0-13-generic #14-Ubuntu SMP, Host)
- Ubuntu 18.04 (LXC)
  - mysql 5.7.25-0ubuntu0.18.04.2

## 下準備
Laravelでは簡単に認証を実装できるということで以下のコマンドを打とうとした。

```
php artisan make:auth
```

おっと、その前にDBの設定をしないと。そう思い私は、LXCを建てそこにMySQLをインストールした。

```
# lxc launch ubuntu:18.04 mysql
# lxc exec mysql bash
mysql # apt install mysql-server
mysql # mysql -u root
mysql> create database homestead;
mysql> grant all on homestead.* to homestead@'%' identified by 'secret';
mysql> exit
mysql # exit 
```

さて、`.env`で設定されているデータベース名やユーザ名、パスワードに合わせて設定したので`DB_HOST`だけコンテナのIPアドレスにしてあげればよいだろう。

    # lxc list
    +-------+---------+---------------------+------+------------+-----------+
    | NAME  |  STATE  |        IPV4         | IPV6 |    TYPE    | SNAPSHOTS |
    +-------+---------+---------------------+------+------------+-----------+
    | mysql | RUNNING | 10.55.37.202 (eth0) |      | PERSISTENT |           |
    +-------+---------+---------------------+------+------------+-----------+

`10.55.37.202`が今回のMySQLサーバのアドレスとなることがわかる。
したがって、`.env`に設定するDBの設定は以下のようになった。

    DB_CONNECTION=mysql
    DB_HOST=10.55.37.202
    DB_PORT=3306
    DB_DATABASE=homestead
    DB_USERNAME=homestead
    DB_PASSWORD=secret

## 認証の実装
準備が終わったので認証の実装をする。「実装をする」と言っても最初に紹介したコマンドを１行打つだけだ。

    # php artisan make:auth
    Authentication scaffolding generated successfully.

successfullyを出力され、ディレクトリを見るとコントローラやビューなど必要なものが生成される。次にマイグレートの実行だ。

    # php artisan migrate
     Illuminate\Database\QueryException  : SQLSTATE[HY000] [2002] Connection refused (SQL: select * from information_schema.tables where table_schema = homestead and table_name = migrations)

`Connection refused`

## 原因
今回の構成の場合、MySQLはコンテナ上で実行されているのでホストOSからのアクセスは外部からのアクセスとなる。そのため、`grant`では`homestead@'%'`のようにしてどこからでもアクセスできるようにしていた。実際に、外部から接続したい系記事ではこれで接続できていた。なぜだ。

### `/etc/mysql/mysql.conf.d/mysqld.cnf`
`/etc/mysql/mysql.conf.d/mysqld.cnf`に以下のような設定があった。

    bind-address          = 127.0.0.1
    
この設定によって、`127.0.0.1`でLISTENしているため外部からの接続は拒否されるらしい。
この設定をコメントアウトするとどこからでも接続できるようできる。また、IPアドレスを変更して特定のIPアドレスでLISTENするなどするらしい。

したがって、以下のように設定することでマイグレートできるようになった。

    # bind-address          = 127.0.0.1

## さいごに
MySQLに外部から接続するには`grant`でIPアドレスを指定するだけなく、`/etc/mysql/mysql.conf.d/mysqld.cnf`の`bind-address`でIPアドレスを指定、またはコメントアウトする必要がある。

この情報を得るまでに多くの時間を費やしたのだけど、`bind-address`で調べると案外記事が出てきたので、自分の検索スキルが低かったのかな。

<a href="http://xyk.hatenablog.com/entry/2013/11/08/142548">MySQLにリモートホストから接続できるようにする</a>
<a href="https://gist.github.com/koudaiii/10696132">外部からMySQLの接続する際のチェックポイント</a>
PHP phalconメモ用

臨時更新して適当に

# !issetとか否定(NOT)
は 「is」の後に「not」を入れて演算子を書く

```hoge.volt
#php
#if(!isset(hoge)){
#  pirnt("実行されます")
#}

#phalconでやる時
 {% if hoge is not defind %}
    {{ "実行されます" }}
 {% endif %}
```

情報少ないし、公式の英語大変やし疲れる。
Cactiのインストール中にtimezoneにつまずく


[この](https://knowledge.sakura.ad.jp/618/)あたりを参考にしながらcactiをインストールした際のトラブル。
Cacti Versionは1.1.38。

Cactiの初期設定ウィザードに「Pre-installation Checks」というものが追加されている。チェック項目に「MySQL Timezone Support」というものがあり、ここで下記のコメントが出て先に進めなくなった。

`Your Cacti database login account does not have access to the MySQL TimeZone database.`

MySQL（実際はMariaDB）にTimezoneを設定する必要があるとのこと。

[こちら](https://www.ipentec.com/document/mariadb-set-time-zone)の「Linuxの場合」を参考に設定。

### Timezone table作成
```
# mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
```

### 自身のTimezoneの設定
``` /etc/my.cnf
[mysqld]
default-time-zone = 'Asia/Tokyo'   ←この行を追加
```

### DB再起動
```
# systemctl restart mariadb.service`
```

### MySQL cactiユーザにTimezone tableのアクセス権付与
```
# mysql -u root -p
# Enter password:    ←MySQLのrootユーザのパスワードを入力
MariaDB [(none)]> grant select on mysql.time_zone_name to 'cactiuser'@'localhost' identified by '<password for cactiuser>';
MariaDB [(none)]> quit
Bye
#
```
micro:bitで名札をつくってみた

#名札をつくってみた
##2019.3.14 少し更新してみました(ver1.0)．
<img width="812" alt="スクリーンショット 2019-03-14 9.38.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/237044/30f805ad-fa15-85cc-2495-d72640fb260a.png">

- [公開コード](https://makecode.microbit.org/_gv2LE5TTuCzs)
- アクションを加えてみました．
- Aボタンで表示，Bボタンで非表示の切り替えができるようにしました．
- 机の上などにおいたときに非表示にするようにした（ロゴが上向きのとき（首にぶら下げたとき）に表示）．
- （裏コマンド？）水平にした状態で「ゆさぶる」とハートマークを３回表示．
- 文字の定義等については，以下を参考にしてください．

##Ver0.9
![スクリーンショット 2019-02-21 12.34.57.png](https://qiita-image-store.s3.amazonaws.com/0/237044/bf82a16f-f6bc-f266-5a10-367f190550f8.png)


- [公開コード](https://makecode.microbit.org/_9UpcET79j94x)
- 名前が表示されていないときにBボタンを押すと明るさの数値を表示する。

#考察。メモ

- ひっくり返ったら表示しないようにしてみた。

#関連サイト
-[フォントの参考サイト:5x5フォント](https://sanuki-tech.net/micro-bit/appendix/japanese-katakana-font/)
-[フォントの参考サイト]:5x4フォント(https://sanuki-tech.net/micro-bit/appendix/japanese-katakana-5x4-font/)
Ruby 学習　基本　（ハッシュ）

#はじめに
  Rubyの学習を始めました。学んだことを忘れないように備忘録として残しています。


# ハッシュ
  配列は複数値を並べて管理するのに対し、ハッシュはそれぞれの値にキーと呼ばれる名前をつけて管理する。

  ※書き方
  　ハッシュは{}で囲みキーと値は=>で繋ぎ、要素と要素はコンマ(,)区切る

```


 #配列
　[値1値2]　　#[]で囲む

 #ハッシュ
 　{キー1 => 値1, キー2 => 値2}  #{}で囲む

 ```

 ```ruby

 user = {"name"=>"Ken","age"=>30}  # 変数userに代入
 puts user                         # {"name"=>"Ken","age"=>30}

 ```

## ハッシュの要素を用いる

```Ruby

 user = {"name"=>"Ken", "age"=> 30}
 puts user["name"] #Ken  キーnameに対する値”Ken”が出力される

```

## ハッシュの要素を更新する

```Ruby
  user = {"name"=>"Ken", "age"=> 30}
  puts user      #  {"name"=>"Ken", "age"=> 30}

  user["age"] = 33  #　ハッシュ[キー] = 値　と書く。
  puts user         # {"name"=>"Ken", "age"=> 33}

```

## ハッシュに要素を追加する

```Ruby
 user = {"name"=>"Ken", "age"=> 30}
 puts user      # {"name"=>"Ken", "age"=> 30}

 user["gender"] = "male"  # ハッシュ[新しいキー] = 値と書くことで新しい要素を追加することができる。
 puts user      # {"name"=>"Ken", "age"=> 30 , "gender"=>"male"}

```

## ハッシュのキーにシンボルを用いる
  :name この書き方をシンボルという

```Ruby

 user = {:name=>"Ken", :age=> 30}  # :コロンで始める
 puts user[:name]   # Ken
```

   ※省略した書き方

```Ruby

  user =  {name:"Ken", age:30}  # 「:key =>」を「key:」というように省略することができる。
  puts user[:name]

```

## 配列要素にハッシュを入れる

```Ruby

  users = [
    {name: "Ken", age: 30}, # (,)で繋ぐ=
    {name: "John", age: 24}
  ]

  puts users[1] # {name: "John", age: 24}
  puts users[1][:name]  # John

  users.each do |user|

    puts user[:name] # Ken
                     # John
  end
  

```
右クリックメニューに「環境変数PATHに追加」（永続化）

#gitコマンドが無いってどういう事やねん
これ書いてて思い出したけど、そうだよmasterにマージしようとしてキレてたんだったよ。ちょっとマージしてくる。してきた。
毎回ストレスなのが「あーパスが通ってねえや」って奴。いつもフォルダを右クリックで追加できたら楽なのにな、とか思いながら何もしてなかったわけだが。

そっかQiitaに記事として乗っけりゃ再利用性が高いじゃん、いいじゃん**Qiitaなんか俺のブログだよ**みたいなノリでね、うん。
#四の五の言わずにPowerShell
毎回余計な前振りが長いよね。そうだね。ほい、これで多分大体行けるはず。

```setenv.ps1
$path1 = "HKLM:\SOFTWARE\Classes\Folder\shell\環境変数PATHに追加"
$path2 = "HKLM:\SOFTWARE\Classes\Folder\shell\環境変数PATHに追加\command"

$value = "`"%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell`" -Command [System.Environment]::SetEnvironmentVariable(`\`"Path`\`", `\`"`$Env:Path;%1`\`", `\`"Machine`\`")"

New-Item $path1
New-Item $path2 
New-ItemProperty -Path $path2 -name "(default)" -Value $value -propertyType ExpandString
```

いや、PowerShellのexeの場所とかってなんか無いのかとか思ったけど、ちょっと分かんなかったんだよね。

unregist的なモノは面倒くさいから書かない。追加するだけ。環境変数を消すのも手作業。
レジストリいじるのとシリアへの取材は自己責任なんだけど、なんか変な事が起こったらごめんね。

俺は知らん。強いて言えば社会が悪い。政府に言ってくれ。

**追記**
ユーザー環境変数だとなんかトランジェントな感じだったんでシステム環境変数にぶっこんだ。ま、どーせQiitaなんか見てんは技術者なんだから使うも使わないも自分で判断してやってくれるでございましょう。
「定期的にユーザのパスワードを更新している」の欄にチェックを入れるためだけの有害な自動化

# 注意
セキュリティ的に有害な方法を紹介します。商用サービスでそのまま利用してはいけません。

# はじめに
サービスのセキュリティ担保のためにチェックシートを使う企業は多いと思います。このチェックシートで頻出するのが次の項目です。

> 特権アカウントのパスワードを定期的に更新している

この項目を埋めるためには、文字通りパスワードの定期的な入れ替えが必要となります。たとえばLinuxユーザの場合、`chage` コマンドでパスワードの有効期限が設定できます。運用対象のサーバが複数台ある場合は、ADを設定することが一般的かと思います。ただ、いずれの場合でも運用メンバーごとにユーザ管理をするか、もしくはパスワードを共有する必要があるため、パスワード更新のための運用負荷が発生します。

この項目にチェックを入れるためだけに、パスワードを自動更新する仕組みを作ってみました。セキュリティを度外視しているので商用環境では使えません。いないとは思いますが利用する際には注意してください。

# 想定環境
Amazon Web Service 上でEC2インスタンスを複数台起動しています。インスタンスのOSはすべてAmazon Linux 2 であり、Systems Managerが利用可能な設定になっています。

Systems ManagerでEC2インスタンスを操作する場合、EC2インスタンスに付与するためのIAMロールを作成し、 `AmazonEC2RoleForSSM`ポリシーを付与する必要があります。
- [Systems Manager のインスタンスプロファイルの作成](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/sysman-configuring-access-role.html)

# 構成
構成は次のとおりです。
![update_passwd.png](https://qiita-image-store.s3.amazonaws.com/0/236562/821cd065-332e-9b05-f3ff-350e7c7e5cf2.png)

CloudWatch Events + LambdaでSSM Run Commandを定期実行します。
SSMは主にEC2インスタンス向けの構成管理サービスです。SSMには複数のインスタンスを指定してLinuxコマンドを実行するRun Commandという機能があります。これを使ってLambdaからLinuxコマンドをまとめて実行します。
パスワードはSSM ParameterStore(SecureString)に保存します。SecureStringはKMSの鍵を利用して値を暗号化します。これを使ってLinuxユーザのパスワードを秘匿情報として保管/更新します。

# 実装
以下、実装手順を説明します。
## KMS CMK
適当な名前のCMKを作成し、キーIDを控えます。
キーポリシーで、対象のEC2インスタンスに付与したIAMロールに利用権限を付与します。

## Parameter Store (SecureString)
先の手順で作成したKMS CMKを使ってSecureStringとしてパラメータを作成します。値はあとでLambdaがランダムな文字列を入れるので適当で構いません。

## CW Events + Lambda

- [GitHub](https://github.com/Hikosaburou/update_linux_user_passwd)

[Serveless Framework](https://serverless.com/)でデプロイします。env-xxx.ymlにKMSのキーIDとアカウント情報を記載し、以下コマンドを実行します。

``` shell
$ sls deploy --aws-profile={{ Your Profile }} --stage=xxx
```

Lambda上でSSM Parameter Storeの更新とSSM Run Commandを実行し、各EC2インスタンス内のec2-userのパスワードを更新します。このLambdaをCloudWatch Eventで定期実行します。

すぐにLambdaを実行したい場合は、以下の `sls` コマンドを実行します。

``` shell
$ sls invoke --aws-profile={{ Your Profile }} --stage=xxx --function=runner
```

# パスワードの取得方法
KMS鍵を使えるIAMユーザのShared Credentialsを使って、以下コマンドで取得します。

``` shell
$ aws ssm get-parameters --name {{ Parameter Name }} --with-decryption --query 'Parameters[*].Value' --output text
```

# なぜ有害なのか
EC2に紐づくIAMロール単位でKMS鍵の利用許可を与えているため、EC2インスタンスに入ればユーザに関係なくParameter Storeにアクセスできてしまいます。つまり、サーバにSSH接続できたら誰でもユーザのパスワードが入手できてしまいます。

# おわりに
セキュリティチェックシートを埋めるためにセキュリティ強度を下げるという本末転倒な結果になりました。
(改善案としては、KMSのキーポリシーをLambdaで操作するという方法があるかと思います。)
Rails の binary型 を MySQL で使用した際のトラブルシューティング

#概要
PDFや画像をアップロード・ダウンロードする機能を実装し、開発環境（SQLite）では動作しているものを本番環境（MySQL）にデプロイした際のトラブルシューティングです。

トラブルとしては以下の２つのトラブルに遭遇しました。

- MySQL でクライアントからサーバに送出できるパケットの制限を超えた
- Railsのbinaly型はMySQLではBLOB型となるが、容量不足だった



#環境（開発・本番）
```
# 開発環境
$ ruby -v
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux]
$ rails -v
Rails 5.1.6
$ gem list sqlite
sqlite3 (1.4.0, 1.3.13)

#本番環境
$ ruby -v
ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-linux]
$ rails -v
Rails 5.1.6
$ mysql --version
mysql  Ver 14.14 Distrib 5.7.25, for Linux (x86_64) using  EditLine wrapper
```

#max_allowed_packetを変更する

本番環境にデプロイしてファイルをアップロードしてみると例外が発生してしまいました。ログを見てみると以下のようなエラーメッセージでした。

```
Mysql2::Error: MySQL client is not connected: ROLLBACK
```

[Mysql2::Error: MySQL client is not connected: ROLLBACKを解消した話](http://mr-itaya-magic.hatenablog.com/entry/2017/02/03/104344)
[mysql max_allowed_packetを変更する](https://qiita.com/_am_/items/91824da643256d46b847)


この辺の情報を参考にしましたが、私の場合はconfファイルを変更してMySQLの再起動で解消しました。

```shell
$ sudo vi /etc/my.cnf
```

```my.cnf
[mysqld]
max_allowed_packet=16MB
```

```
$ sudo systemctl restart mysqld.service
```




#該当フィールドをmediumblobに変更する

次に遭遇したエラーメッセージは以下になります。

```
Data too long for column 'upload_file'
```


[【Rails×MySQL】保存できる画像ファイルの容量を変更する]
(https://qiita.com/residenti/items/d791533423d3f4999a61)
[【Rails・MySQL】MySQLのデータ型とRailsのマイグレーションファイルのデータ定義の対応まとめ](https://qiita.com/vermilionfog/items/816fa7de1d0213979929)

こちらを参考に、カラム修正のマイグレーションを行う事で解消しました。

```ruby:migration.rb
class ChangeUploadFileToDocument < ActiveRecord::Migration[5.1]
  def change
    change_column :documents, :upload_file, :binary, :limit => 5.megabyte
  end
end
```
snapでインストールしたコマンドがzshでPATH通ってない

## 概要

snapでインストールしたherokuコマンドがzshから使えなかったので、PATHを通した。
それだけ。

### 経緯

herokuコマンドが無いと言われた。

```
% sudo snap install --classic heroku
heroku v7.21.0 from Heroku✓ installed

% heroku help
zsh: command not found: heroku
```

調べたら原因は `/snap/bin` にPATHが通ってないことがわかった。
bashだとPATH通っている。

 - 再現した環境

```
% snap version
snap    2.37.2
snapd   2.37.2
series  16
ubuntu  18.04
kernel  4.15.0-1019-aws
```

## 対応

`/etc/zsh/zprofile` の末尾に以下を追記した。

```zsh
# Expand $PATH to include the directory where snappy applications go.
snap_bin_path="/snap/bin"
if [ -n "${PATH##*${snap_bin_path}}" -a -n "${PATH##*${snap_bin_path}:*}" ]; then
    export PATH=$PATH:${snap_bin_path}
fi
```

※ `/etc/profile.d/apps-bin-path.sh` から抜粋した。


## まとめ

snapでインストールしたコマンドがzshでPATH通ってなかったので、PATHを通した。
が、果たしてこの対応が本当に正しいのだろうか。

正しい方法知ってたら誰か教えてほしい。

## 補足

こういうバグレポートを見つけた。
https://bugs.launchpad.net/ubuntu/+source/snapd/+bug/1640514
29歳未経験新人プログラマがSES業界に飛び込んで最初の(約)2週間を過ごして思ったこと　その2

https://qiita.com/ginger_t/items/77231691baed07080e22
上記の続きです。


■2週目
・月
祝日だったので休み。
土日含めて、勉強や復習は一切していない。

　
・火
単体テスト実施→完了
先週自習した内容を半分くらい忘れてる。
正確には「なんとなくこんなんだったかな」程度の知識まで落ちている。
帰宅後や休日は一切何もしていないので、
まあ、そうなるな　といった感じ。
単体テスト自体は完了。
内容は6~7割くらい理解。

 
・水~金
MYSQLを使い､SQLの学習を開始する。
使用ツールはphpMyAdmin(よく調べずに単体テスト時のものをそのまま使用)
例によって「SQLって何？」という所からのスタート。
初日はひたすらSQLについてググることから始め、
以降は例題を解く作業を続ける。
INSERTやSELECT等の簡単な命令ならある程度理解できるようになる。
しかし、構文が全く憶えられていない。
数こなすしかないのかなーと思いつつ、
特に意識的に覚える作業とかはしてなかった。

<hr>

以上が最初の2週間の内容です。
三行でまとめると
・研修内容はテストとSQLの基礎中の基礎
・自習自習自習アンド自習
・現場レベルには到底たどり着いてない(と思う)

現在(3週目)ですが、まだSQLを触っています。
今日明日くらいで一旦区切りをつけて、次はJAVAに入る予定です。
またこれも1から調べる所からのスタート。
「自分で調べる」事の大切さはすごくよくわかるんだけど、
誰かに何かを教わるでもなく、ただひたすら2週間黙々と自習し続けるのもなぁ･･･と思ってきています。
じゃあ何するのって言われると結局自主学習くらいしかできることないんですけどね！

以上、
「29歳未経験新人プログラマがSES業界に飛び込んで最初の(約)2週間を過ごして思ったこと」でした。
(～思ったことというかただの日記だコレ)
【android9.0】DNS66でchromeの広告が消せない問題について

結論としてはChrome内部のデフォルトフラグ設定が問題だった。

私の場合は以下の手順で解消された。


1.Chromeアプリを起動。 

2.アドレスバーにURL
「chrome://flags」を入力。

3.検索ボックスで“dns”を検索して
 [Async DNS resolver]オプションを[Disabled]に設定してChromeを再起動。

![How-to-fix-Adhell-2-not-working-issue-on-Chrome.jpg](https://qiita-image-store.s3.amazonaws.com/0/155354/3173ed41-40ff-3df5-be19-ff0ec60ba276.jpeg)

---
私は上記だけで改善されたのだが
DNSキャッシュも削除しておいた方が
いいそうなので以下に手順を記載する。

1.アドレスバーに 「chrome://net-internals」を入力。

2. DNSタブを選択し、「Clear Cache」をタップ後、 Chromeを再起動。


---
【引用元】
https://github.com/julian-klode/dns66/issues/289

https://www.androidsage.com/2018/01/25/how-to-fix-adhell-2-not-working-chrome/

https://www.androidjungles.com/download-adhell-3-samsung-galaxy-devices-apk/