OmniAICreator/Qiita-1.07M huggingface dataset:
Visualforceページを新規タブで表示させつつパラメータを渡したい時にハマった

Visualforceページを実装している時にハマったことがあったので記事化

## やりたいこと
あるVFページからボタンを押したら、ブラウザの新規タブで別のVFページを表示させつつ、
新規表示するページにパラメータを渡したい

## ハマったこと
Visualforce の`target="_blank"`と`reRender`を併用したら、うまくいかずにハマった
ハマったソースは以下のような感じ

あるコマンドボタンを押すと、対応するアクションでパラメータを受け取って
受け取ったパラメータを次のページのパラメータとして渡す

```html:ハマったvisualforce
<apex:form id="form-id" target="_blank">
    <!-- コマンドボタン 新規タブで開くがパラメータが渡らない -->
    <apex:commandButton value="ボタン" action="{!openNewPage}">
        <apex:param name="param" value="hoge"/>
    </apex:commandButton>
 
    <!-- コマンドボタン 新規タブで開かないがパラメータが渡る -->
    <apex:commandButton value="ボタン" action="{!openNewPage}" reRender="form-id">
        <apex:param name="param" value="hoge"/>
    </apex:commandButton>
</apex:form>
```

```java:ハマったApex
public with sharing class Controller {
 
    // 直接パラメータを受けてそれを遷移先に渡そうとしていた
    // commandLinkとcommandButtonから新規タブを開きながらアクションを呼ぼうとしたら、新規タブは開くがパラメータが渡らない
    // target="_blank" と reRender を併用すると、新規タブで開かない代わりにパラメータが渡らない
    public PageReference openNewPage() {
        String param = System.currentPageReference().getParameters().get('param');
        PageReference newPage = Page.NewPage;
        newPage.getParameters().put('param', param);
        return newPage;
    }
}
```

## 原因
どうやらreRenderとtarget=_blankの併用だとよろしくないらしい
この辺の挙動の詳細がわかってないので、要調査
おそらく、reRenderをすると同一ページの再描画になるので、新規タブ表示が行われなくなる？
reRenderを使う時にその詳細な挙動まで意識したことがないので、反省

## 解決
いろいろと調べた挙句、`ActionFunction`でパラメータをコントローラに登録する処理だけを別で呼ぶことにした。
ベストプラクティスかどうかはわからないが、実現したい挙動はできたのでとりあえずよしとする

```html
<apex:form id="form-id" target="_blank">
  <!-- パラメータをコントローラに持たせるための処理 -->
  <apex:actionFunction name="setParams" action="{!setParams}" reRender="form-id">
    <apex:param name="param" value="{!param}"/>
  </apex:actionFunction>

  <!-- 出力ボタン, onclickでsetParamsを呼ぶ -->
  <apex:commandButton value="ボタン" action="{!openNewPage}" onclick="setParams()"/>

</apex:form>
```

```java
public with sharing class Controller {
    // パラメータを保持する変数
    String param {get; set;}
 
    // ActionFunctionで呼んで、パラメータをコントローラに保持させる関数
    public void setParams() {
        this.param = System.currentPageReference().getParameters().get('homesNo')
    }

    public PageReference openNewPage() {
        PageReference newPage = Page.NewPage;
        newPage.getParameters().put('param', param);
        return newPage;
    }
}
```

これで無事にパラメータを渡しつつ、別タブでの表示ができた
とはいえゴリ押し感が強いが、目をつむる
php-master-changes 2019-03-27

今日はドキュメント内で --enable-maintainer-zts とまだ書いてあった最後の生き残りを --enable-zts にする修正、run-tests.php の最低動作バージョンの言及追記、pbpdbg で条件ブレークポイント設定時に SEGV が起きる場合がある問題やビルド問題等の修正、argon2 のデフォルトのタイムコストを 2 から 3 にする修正、sodium が argon2 のパスワードハッシュと組み合わせて使えることのテスト追加、継承時のエラーでの行番号表示を正確にする修正があった！

# 2019-03-27
## krakjoe: remove last enable-maintainer-zts mention from source
- https://github.com/php/php-src/commit/f43ce705fe277d12e25109548ad2e69be886b3a4
- ドキュメント内で --enable-maintainer-zts とまだ書いてあった最後の生き残りを --enable-zts に修正

## petk: Add minimum required PHP version to run-tests.php
- https://github.com/php/php-src/commit/434388a61006e958dabddef1c6477e6fd3e75c63
- [7.4~]
- run-tests.php で、最低動作バージョン（7.0.0）の言及を追記

## krakjoe: Fix [#77800](https://bugs.php.net/bug.php?id=77800) phpdbg segfaults on conditional breakpoints
- https://github.com/php/php-src/commit/7df8e4fc0abc105cd5d7b933499bdd275459f7ee
- [7.2~]
- sapi/pbpdbg で、条件ブレークポイント設定時に内容によって SEGV が起きる問題の修正
- [PR:3992](https://github.com/php/php-src/pull/3992)

## krakjoe: more work on phpdbg conditional breaks
- https://github.com/php/php-src/commit/6d3a2b46930057524c1eebfa574a4869e3f9dd28
- [7.2~]
- ↑の修正で直ってない部分があったのを修正

## sgolemon: Increase default time cost for argon2 password hashing
- https://github.com/php/php-src/commit/d12464070460086329e93f632aed2f16daa52600
- argon2 の[デフォルトのタイムコスト](https://www.php.net/manual/ja/password.constants.php#constant.password-argon2-default-time-cost)を 2 から 3 に増加

## sgolemon: Validate interoperability between libsodium and libargon for argon2i(d) hashing
- https://github.com/php/php-src/commit/7e7fa77a2ec084c6720d0ce7e8fef5868786899a
- [7.4~]
- ext/sodium のテストで、argon2 のパスワードハッシュと組み合わせて使えることのテストを追加

## krakjoe: Fix [#77805](https://bugs.php.net/bug.php?id=77805) phpdbg build fails when readline is shared
- https://github.com/php/php-src/commit/7af270eb284c3bd00f6e5d80fbb0a2de9f89b693
- [7.2~]
- sapi/phpdbg で、readline が共有オブジェクトで組み込まれているとビルドできない問題の修正

## kaplun: Consider phpdbg as cli
- https://github.com/php/php-src/commit/79f046f89e187312cec3715bffc1a8b101f57531
- [7.2~]
- ビルドシステムで、phpdbg が configure で cli 扱いとなるよう修正
- これで例えば pcntl が phpdbg で使えるようになる

## nikic: Make line numbers for inheritance errors more precise
- https://github.com/php/php-src/commit/251f293cb7e6fa603885e912e455725efe4cd94e
- [7.4~]
- 親と互換性がないシグネチャでメソッドをオーバーライドしようとした時、エラーメッセージの行表示がクラスの先頭 or 末尾だったのを子のメソッドの開始行で出すよう修正

## nikic: Fix lineno for more inheritance errors
- https://github.com/php/php-src/commit/d1e5006c1487c0df1333564c3fdcc0528e1da394
- [7.4~]
- final メソッドをオーバーライドしようとしたとか、その他の継承時のエラーについても行表示がより正確になるよう修正
S3アクセスログに追加された項目(署名バージョンなど)をAthenaでクエリできるようにする

# S3において署名バージョン2(SigV2)が廃止される（廃止されない）

~~AWS署名バージョン２が2019年6月24日に廃止されることになりました~~
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/UsingAWSSDK.html#UsingAWSSDK-sig2-deprecation

> 2019/07/10更新
SigV2は廃止されないことになったみたいです
今後SigV2は移行を強く推奨するといったスタンスみたいです


そこで、社内のプロダクトにおいてS3のアクセスに使用しているライブラリおよび署名バージョンの調査が必要になりました

# S3のアクセスログに項目が追加

それにともなってか、S3のアクセスログに項目が追加されました
https://docs.aws.amazon.com/AmazonS3/latest/dev/LogFormat.html

# Athenaでテーブルを作る

以下を参考にアクセスログの分析をしました
https://docs.aws.amazon.com/AmazonS3/latest/dev/LogFormat.html

上記のドキュメントでは、まだS3に追加された以下の項目に対応できていませんので
CRATE TABLEは少し追記する必要があります
参考： https://dev.classmethod.jp/cloud/aws/s3-accesslog-new-fields/

| 項目 | 例 | 内容 |
|:--|:--|:--|
| Host Id | s9lzHYxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | リクエストID |
| Signature Version | SigV2 | 署名バージョン |
| Cipher Suite | ECDHE-RSA-AES128-GCM-SHA256 | 暗号スイート |
| Authentication Type | AuthHeader | 認証タイプ |
| Host Header | s3-us-west-2.amazonaws.com | 接続先S3エンドポイント |
| Ssl Protocol | TLSv1.2 | 暗号化プロトコル |

以下のようにテーブルを作成しました

```sql
 CREATE EXTERNAL TABLE IF NOT EXISTS database.hogehoge(
   bucketowner STRING,
   bucket STRING,
   requestdatetime STRING,
   remoteip STRING,
   requester STRING,
   requestid STRING,
   operation STRING,
   key STRING,
   request STRING,
   httpstatus STRING,
   errorcode STRING,
   bytessent BIGINT,
   objectsize BIGINT,
   totaltime STRING,
   turnaroundtime STRING,
   referrer STRING,
   useragent STRING,
   versionid STRING,
   hostid STRING,
   signatureversion STRING,
   ciphersuite STRING,
   authenticationtype STRING,
   hostheader STRING,
   sslprotocol STRING)
 ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'
 WITH SERDEPROPERTIES (
 'serialization.format' = '1',
   'input.regex' = '([^ ]*) ([^ ]*) \\[(.*?)\\] ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) \\"(.*?)\\" (- |[^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) \\"(.*?)\\" \\"(.*?)\\" ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*)$'
 )LOCATION 's3://bucket/accesslog/'
```

~~正規表現があまり理解できてないのですが~~ とりあえず動きそうです


以上
MySQLクライアントに Can't read dir of '/usr/local/etc/my.cnf.d' と言われた。

Docker Container の MySQL に接続しようとしたところ、
MySQLクライアントに `Can't read dir of '/usr/local/etc/my.cnf.d'` と言われてしまった。

```sh
$ docker run --name local-db -itd -p 3306:3306\
   -e MYSQL_ROOT_PASSWORD=root \
   -e MYSQL_USER=t_horikoshi\
   -e MYSQL_PASSWORD=t_horikoshi \
   -d mysql:5.6 \
   --character-set-server=utf8mb4 \
   --collation-server=utf8mb4_unicode_ci \
   --innodb-large-prefix=true \
   --innodb-file-format=Barracuda \
   --innodb-file-per-table=true
298fa19aa73229c5d4c3902ac6578e880d8741ac324a9f56de7f3e5163138ad0

$ docker start local_db
local_db

$ mysql -h 127.0.0.1 -u root -p
mysql: Can't read dir of '/usr/local/etc/my.cnf.d' (OS errno 2 - No such file or directory)
mysql: [ERROR] Fatal error in defaults handling. Program aborted!
```

なんか `my.cnf.d` が無いらしい 😵

# /usr/local/etc/ の中身を確認

```sh
$ cd /usr/local/etc/

$ ls
bash_completion   dnsroots.global   gitconfig         mongod.conf       openssl           sbtopts
bash_completion.d fish              init.d            my.cnf            pkcs11            unbound
brew-wrap         fonts             logrotate.d       my.cnf.default    profile.d
```

確かに `my.cnf.d` は見当たらない。

# my.cnf.d を作ってみる

無いんだから作ればいいんでしょ？

```sh
$ mkdir my.cnf.d
```

# 動作確認

```sh
$ mysql -h 127.0.0.1 -u root -p
Enter password: # root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 991
Server version: 5.6.40 MySQL Community Server (GPL)

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
```

無事解決しました。
※`my.cnf.d` はディレクトリじゃないとダメっぽい。

# おしまい
type hinting で複数の Protocol を実装したクラスの型を表現する

# Protocol / Interface
作っているプログラムが複雑になってくると、 Interface (python の世界では Protocol) を使って複数のクラスが同じインターフェースを持つことを保証したくなります。
特に mypy など type hinting の仕組みを使い始めるとそのようなものが欲しくなります。

このようなインターフェースは python では `Protocol` というものを使うことで実装できます。
例えばあるクラスの情報を DB に書き出すために、 `serialize` というメソッドを実装したクラス群があるとしましょう。この serialize というインターフェースを Serializable と呼ぶことにします。

```py3
from typing import Dict, Any
from typing_extensions import Protocol

class Serializable(Protocol):
    def serialize(self) -> Dict[str, Any]:
        ...

class A:
    def __init__(self) -> None:
        self.data = None

    def serialize(self) -> Dict[str, Any]:
        return {'data': self.data}

    def run(self) -> None:
        self.data = 'run result'


def print_serialized(instance: Serializable) -> None:
    print(instance.serialize())


a = A()
print_serialized(a)
```

print_serialized は何らか serialize メソッドを持ったクラスを受け取り、そのシリアライズ結果をプリントします。
いったいそのインスタンスがどんなクラスなのか、何をシリアライズするのかとかは知らなくてすみます。


# 複数の Protocol を実装したクラスを作りたい
さて、先程のクラス A には run というメソッドがありました。
このように、何らか run というメソッドをもっているというインターフェースを Runnable と呼ぶことにしましょう。
そして、 Runnable と Serializable の両方を持っているクラスのインスタンスを受け取ってなにか処理を行うことを考えます。


```py3
from typing import Dict, Any
from typing_extensions import Protocol


class Serializable(Protocol):
    def serialize(self) -> Dict[str, Any]:
        ...


class Runnable(Protocol):
    def run(self) -> None:
        ...


class A:
    def __init__(self) -> None:
        self.data = None

    def serialize(self) -> Dict[str, Any]:
        return {'data': self.data}

    def run(self) -> None:
        self.data = 'run result'


# ダサいぞ！！！
class RunAndSerializable(Serializable, Runnable, Protocol):
    ...


def print_result(instance: RunAndSerializable) -> None:
    instance.run()
    print(instance.serialize())
```
こういう書き方をすることになります。

`print_result` ですが以下のように書きたいですね。。

```py3
def print_result(instance: Intersection[Serializable, Runnable]) -> None:  # Serializable/Runnable 両方のインターフェースを実装しているクラス
    instance.run()
    print(instance.serialize())
```
このような Intersection 型ですが、2019/03現在検討はされているようですが、まだ実装には入っていないようです。
https://github.com/python/typing/issues/213

書かれていることを見ると

- Intersection は型一般に対応しようと思うと、 Generic などへの対応が非常に複雑になる
- Protocol のみに対応なら簡単だけど、それだと Union との対称性が無かったり、ニッチすぎる
- よって今はまだやる時期じゃない

個人的には Protocol ベースなプログラミングをする上では非常に重要な機能なのでぜひ実装してもらいたい気持ちです。
ruby本勉強して得た知識(アクセサメソッド)

# ruby本を勉強して得た知識
ruby本勉強して得た知識を頭に入れとくだけだと多分忘れるので
実際に使えそうだったり、よく見るものとかを書いてみてメモに残そうと思いました。
(定期的にやっていきたい..)

## 今回の内容
### アクセサメソッド
アクセサメソッドとは、ゲッターメソッド、セッターメソッドを自動で定義してくれるメソッドの総称です。
以下がアクセサメソッド。

- attr_accessor # ゲッターとセッターが自動的に定義される
- attr_reader # ゲッターメソッドが自動的に定義される
- attr_writer # セッターメソッドが自動的に定義される

### ゲッターメソッド？？
ゲッターメソッドとは以下のようなメソッドでインスタンス変数から値を取得できる。
外部インスタンスから値を参照する時に使用します。

```ruby
class User
  def initialize(name)
    @name = name
  end

  def name # このメソッドにアクセスすることで@nameの値を参照できる
    @name
  end
end

user = User.new('三郎')
p user.name # ターミナルで確認すると"三郎"と出る。
```




### セッターメソッド？？
セッターメソッドは以下のようにインスタンス変数に値を設定できるメソッドです。
外部インスタンスから値を更新するときなどに使用します。

```ruby
class User
  def initialize(name)
    @name = name
  end

  def name=(value) # このメソッドにアクセスすると@nameの値がvalueの値になる
    @name = value
  end
end

user = User.new('三郎')
user.name = '一郎'
p user.name # こうすると三郎ではなく一郎に変わっているのがわかる。
```

## コード

```ruby
attr_accessor :name
attr_reader :age
attr_writer :gender

def initialize(name, age, gender)
  @name = name
  @age = age
  @gender = gender
end

user = User.new('三郎', 40, '男性')
p user.name
user.name = '一郎'
p user.name

p user.age
# user.age = 20 # ageはセッターが用意されていないのでエラーになる

user.gender = '女性'
# p user.gender # genderはゲッターが用意されていないのでエラーになる

```

### attr_reader
attr_readerは

```ruby
def name
  @name
end
```
(ゲッターメソッド)を自動で定義してくれます。


### attr_writer
attr_writerは

```ruby
def name=(value)
  @name = value
end
```
(セッターメソッド)を自動で定義してくれます。

### attr_accessor
attr_accessorはゲッターメソッドとセッターメソッドを自動で定義してくれます。
[Arduino]あらゆるデバイスをI2C化する

#初めに
Arduinoに複数のデバイスやセンサーを繋いで使用したい際に、ピン数が足りない、またはバッティングする、といったことはないでしょうか？
また、使用中のI2Cセンサーを、プログラムを書き換えることなく別のセンサーに置き換えたい、といったことはないでしょうか？

今回は、
・複数のI2Cデバイス
・ソフトウェアシリアル
・電磁リレー
等で複数ピンが使用されているArduinoに対して、さらに液晶モジュールを取り付けたいという要望のために液晶モジュールをI2C化しました。
![IMG_6440.jpg](https://qiita-image-store.s3.amazonaws.com/0/59911/4108494a-0114-4dd1-2a2b-1967a494c529.jpeg)

#経緯
はじめは[I2C 16x2文字モノクロ液晶](http://akizukidenshi.com/catalog/g/gP-11916/)を使っていたのですが、
・もう少し大きく表示したい
・プログラムを変えずに液晶だけ置き換えたい
という要望があり、[SPI接続の1.8インチTFT液晶モジュール](http://www.aitendo.com/product/16367)を[I2C 16x2文字モノクロ液晶](http://akizukidenshi.com/catalog/g/gP-11916/)とコマンド互換でArduinoとI2Cで接続できるようにすることにしました。

#しくみ
[SPI接続の1.8インチTFT液晶モジュール](http://www.aitendo.com/product/16367)をI2Cモジュール化するために、
・TFT液晶を別のArduinoで制御
・メインのArduinoとI2Cで接続（TFT液晶側をスレーブにする）
・メインのArduinoからI2Cでコマンドを送り、スレーブ側のArduinoで表示
としました。
![2019-03-28_130554.png](https://qiita-image-store.s3.amazonaws.com/0/59911/6cf73584-4b17-2e10-ad1b-e1f57e8855fc.png)
こうすることでArduinoのピンを新たに消費することなく液晶を追加することができます。

#Arduino同士のI2C
Arduino同士をI2Cで接続する方法は
[Arduino同士でI2C通信する方法](https://qiita.com/hikoalpha/items/7bf563ee286a59bfd2f4)
で詳しく解説されていますが非常に簡単です。
今回は、それまで使っていた[I2C 16x2文字モノクロ液晶](http://akizukidenshi.com/catalog/g/gP-11916/)とアドレス互換、コマンド互換となるようにしました。

モノクロ液晶ではコマンド(文字出力、カーソル位置変更等)とデータ(位置、文字等)を0x40の符号で判断していたので、

```
  Wire.beginTransmission(m_addr);
  Wire.write(_isData ? 0x40 : 0x00);
  Wire.write(_command[i]);
  Wire.endTransmission();
```

スレーブ側のArduinoでもそれに合わせた仕様で受け取るようにしました。

```
  if(isData==0){ // !0x40
    if((v_data&0x80)==0x80){ // 0x80はカーソルセットコマンド
      int x = (v_data&0x3f);
      int y = ((v_data>>6)&0x1);
      emu->SetCursor(x,y); // 16x2行を8x4行に 
    }
  }else if(isData==0x40){ // 0x40は文字表示コマンド
      emu->WriteCharReq(v_data);
  }
  else if(isData==0x10){ // 0x10は色変えコマンド（拡張）
    emu->SetPalette(v_data); // 0xfront|back
  }
```

#まとめ
既存のデバイスをI2C化して動作させることができました。
グラフィック液晶を高速表示するような用途には向いていませんが、
・I2C接続されていたセンサー/デバイスを、仕様を変えることなく別のものに置き換えたい
・デバイスをなるべくモジュール化したい
といった用途には向いているのではないかと思います。
SSL設定リダイレクト方法

# SSL設定リダイレクト方法
http通信をhttpsにリダイレクトさせる方法の1つ。
(他の方法は。default.confにRewriteを書くなどがある)
.htaccessを対象のアプリケーションのpublic/以下に作成しリダイレクトさせる。

```sh:.htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /

# httpからの通信を、httpsにリダイレクト（www有り無し）
RewriteCond %{HTTPS} off
RewriteRule ^(.*$) https://~~~(ドメイン名)/$1 [R=301,L]

# httpsからの通信でwww有りの場合、www無しにリダイレクト
RewriteCond %{HTTPS} on
RewriteCond %{HTTP_HOST} ^www.~~~(ドメイン名)$
RewriteRule ^(.*)$ https://~~~(ドメイン名)/$1 [R=301,L]
</IfModule>
```
Pythonのプロキシ設定

##はじめに
社内環境でプロキシを突破できずハマったので自分用メモ

##プロトコルの違いだった

Pythonのプログラム内で定義

これで突破できなかった

```php
import os
os.environ["http_proxy"] = "http://user:pass@server:port"
```

こっちで突破できた

```php

import os
os.environ["https_proxy"] = "http://user:pass@server:port"
```

社内環境がhttpsプロトコルだけだったという話

下記を参照させていただきました。
[pythonのrequestsモジュールで認証プロキシを超えたい](https://qiita.com/shnchr/items/bbecc7cf984bf80aee27)
Bye-bye anaconda

anacondaをuninstallする際のmemo.

```shell-session
cat /etc/debian_version 
9.8
```

```shell-session
$ conda install anaconda-clean

Collecting package metadata: done
Solving environment: done

## Package Plan ##

  environment location: /home/*username*/.pyenv/versions/anaconda3-4.3.1

  added / updated specs:
    - anaconda-clean


The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    anaconda-clean-1.1.0       |           py36_1           7 KB
####(略)####
    ------------------------------------------------------------
                                           Total:       146.5 MB

The following NEW packages will be INSTALLED:

  anaconda-clean     pkgs/main/linux-64::anaconda-clean-1.1.0-py36_1
####(略)####

The following packages will be UPDATED:

####(略)####

Proceed ([y]/n)? y  #入力


Downloading and Extracting Packages
fontconfig-2.13.0    | 291 KB    | ##################################### | 100% 
####(略)####

Preparing transaction: done
Verifying transaction: done
Executing transaction: done
```

```shell-session
$ anaconda-clean --yes
Backup directory: /home/*username*/.anaconda_backup/2019-03-28T124457
```

bashプロファイルからanacondaパスを削除

```shell-session
$ vi ~/.bashrc
```
下記の行を削除

```~/.bashrc
export PATH="$PYENV_ROOT/versions/anaconda3-4.3.1/bin/:$PATH"  #<-削除
```

anacondaディレクトリを削除

```shell-session
$ cd $PYENV_ROOT/versions/
$ ~/.pyenv/versions$ ls
anaconda3-4.3.1
$ rm -r anaconda3-4.3.1
$ python3 -V
pyenv: version `anaconda3-4.3.1' is not installed (set by /home/*username*/.pyenv/version)
$ source ~/.bashrc #設定再読込
$ python3 -V
Python 3.5.3
```
アンインストール完了。

source listへ追記

```shell-session
# su
# echo 'deb http://ftp.jp.debian.org/debian experimental main' >> /etc/apt/sources.list
# echo 'deb http://ftp.jp.debian.org/debian unstable main' >> /etc/apt/sources.list
# vi /etc/apt/apt.conf.d/00local
```

```/etc/apt/apt.conf.d/00local
APT::Default-Release "stable"; #追加
```shell-session
# apt update
(略)
# apt install python3.7

```

```
Androidの署名付きapk(debug用)を作成する方法

# 環境
- macOS Mojave
- Android Studio 3.3.2

# 署名付きapk(debug用)作成手順

1. debug.keystore を作る。

```
$ keytool -genkey -v -keystore debug.keystore -alias androiddebugkey -keyalg RSA -validity 10000 -dname "CN=Android Debug,O=Android,C=US"
> キーストアのパスワードを入力してください: android
> 新規パスワードを再入力してください: android
...
(キーストアのパスワードと同じ場合はRETURNを押してください): RETURN押下
```

2 . Android Studio > Build > Generate Signed Bundle / APK
3 . チェックボックスで「APK」を選択して「Next」
4 . 以下の情報を入力して、「Next」

- key store path: 1 で作成した debug.keystore の path
- Key store password: android
- key alias: androiddebugkey
- key password: android

5 . 以下の情報を入力して、「Finish」

- BuildType: devDebug
- Signature Versions: V1 と V2 にチェック

6 . 署名済みの apk が ./dev/debug/app-dev-debug.apk に作成される

# 参考

- https://qiita.com/taka0125/items/c408df4061a0af49c9b3
RPLIDAR A3 laser filterによる障害物検出

# 開発背景
産業用ドローン等を活用した業務用ロボティクスソリューションの開発をしています。
自動車の自動運転、ドローンの自律飛行等のロボット開発には、障害物を検出する必要があります。

# RPLIDAR A3による障害物検出
今回は、RPLIDAR A3を使用してROSのlaser_filtersで障害物検出を検証します。

## 環境
- RPLIDAR A3
- Ubuntu 16.04
- ROS Kinetic

## RPLIDAR A3
https://www.slamtec.com/en/Lidar/A3
![RPLIDAR_A3M1.jpg](https://qiita-image-store.s3.amazonaws.com/0/386259/c4f07ee6-9218-c1e6-0156-dc3d1b5718e0.jpeg)

### インストール
https://github.com/Slamtec/rplidar_ros
Githubからrplidar_rosをcatkin workspace srcフォルダーにcloneします。
catkin_makeコマンドでrplidar_rosをビルドします。

```
catkin_make
```

### Lidar起動
```
roslaunch rplidar_ros view_rplidar_a3.launch
```
![laser_collision_zone_filter_rviz_scan.png](https://qiita-image-store.s3.amazonaws.com/0/386259/6310088e-a8a2-24b0-8ed9-396221b52397.png)

## laser_filters
http://wiki.ros.org/laser_filters
ROSのlaser_filtersには、いくつfilterのPluginがあります。
今回は、LaserScanRangeFilterで検証します。

### laser_filtersのLaserScanRangeFilterの設定ファイル
0.6 m 〜 1.0 m 範囲内の障害物を検出します。
0.6 m 〜 1.0 m 範囲外のPoint Cloudをerror caseとして「-.inf」「.inf」で置換します。
laser_collision_zone_filter.yaml

```yaml

scan_filter_chain:
- name: range
  type: laser_filters/LaserScanRangeFilter
  params:
    use_message_range_limits: false
    lower_threshold: 0.6
    upper_threshold: 1.0
    lower_replacement_value: -.inf
    upper_replacement_value: .inf

```

### laser_filtersのros launch ファイル
drone_filter.launch

```ros
<?xml version="1.0" encoding="UTF-8"?>
<launch>
  <arg name="laser_filter_file" default="laser_collision_zone_filter.yaml"/>

  <!-- laser_filter -->
  <node pkg="laser_filters" type="scan_to_scan_filter_chain" name="laser_filter">
    <rosparam command="load" file="$(find obstacle_detection)/config/$(arg laser_filter_file)" />
  </node>
</launch>
```

### Lidar filter起動
```
roslaunch obstacle_detection drone_filter.launch
```

![laser_collision_zone_filter_rviz_scan_filtered.png](https://qiita-image-store.s3.amazonaws.com/0/386259/264587c8-9f91-1956-ae5e-7a0919090237.png)

### ROS Lidar filterのrqt_graph
```
rqt_graph
```
![laser_collision_zone_filter_rqt_graph.png](https://qiita-image-store.s3.amazonaws.com/0/386259/81d4fbfb-8698-0f9c-4923-a4667d4f2dae.png)

### lidar scan topicのfilter結果
0.6 m 〜 1.0 m 範囲内の障害物が検出されます。
0.6 m 〜 1.0 m 範囲外のPoint Cloudがerror caseとして「-inf」「inf」で置換されます。
![laser_collision_zone_filter_rostopic.png](https://qiita-image-store.s3.amazonaws.com/0/386259/68cc9c80-e6de-412c-3082-61d050c1ca60.png)
Unity Scriptを編集するといちいちinconsistent line endingsっていうWarningが出る

いちいちwarning が出るので検索し、以下のページが出てきた

https://forum.unity.com/threads/inconsistent-line-endings.40671/

つまりVS Codeの改行コードの設定を修正すれば直るってことかな？

まだやってないけど
UILabel 行間を空ける

## ストーリーボードの設定でうまくいかないことがあるときはこうする

```swift
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 6
paragraphStyle.lineBreakMode = .byTruncatingTail
let stringAttributes: [NSAttributedString.Key : Any] = [
      NSAttributedString.Key.paragraphStyle : paragraphStyle,
      NSAttributedString.Key.font : UIFont.systemFont(ofSize: 15.0)]
let string = NSAttributedString(string: "表示するテキスト", attributes:stringAttributes)
label.attributedText = string
```
lodashのメソッド全部分類してみた

# lodashメソッド分類シート
[lodash 4.17.11 ドキュメント](https://lodash.com/docs/4.17.11) から作成
使い方は[参考文献](#参考文献)をご参照ください

[Googleスプレッドシート版](https://drive.google.com/open?id=14sQhCK-2m7e2F4JQtiDvaVpKWcHdkNd9tQwdASD3rP8)
[Microsoft Office Excelシート版](https://drive.google.com/open?id=17QQJ5djSQC9MuGa7KCEe1GEBUH70rWCy)
![lodash-1.png](https://qiita-image-store.s3.amazonaws.com/0/76595/8a90a0db-d032-86c8-de39-1f3977ee41ea.png)
![lodash-2.png](https://qiita-image-store.s3.amazonaws.com/0/76595/13394adf-d00c-583c-ee80-0042eb188d77.png)

# 参考文献
- [細かすぎるけど伝わって欲しいlodash.jsの話](https://techblog.kayac.com/2017-12-2_lodash)
- [逆引きlodash Array/Collection/Object編](https://blog.mamansoft.net/2019/02/14/lodash-by-usecase-array-collection-object/)
- [lodash ちょっとマニアックだけど便利な関数](https://qiita.com/waterada/items/63eb186e2150d38bb6ed)
- [lodashでよく使う関数まとめ](http://matsukaz.hatenablog.com/entry/2014/04/09/082410)
- [Lodash cheatsheet](https://devhints.io/lodash)
Log Analytics のクエリー結果を定期的に収集する

#概要
　本記事では [Azure Logic Apps](https://docs.microsoft.com/ja-jp/azure/logic-apps/) の Log Analytics コネクタを使用して、指定したクエリ構文に従ってログ収集を定期的に実行するワークフローを構築しています。

#手順
1. リンク先の手順に従い [**Logic Apps をデプロイ**](https://docs.microsoft.com/ja-jp/azure/logic-apps/quickstart-create-first-logic-app-workflow#create-your-logic-app) します。
2. 上記手順で [空のロジック アプリ] を選択した後に、[スケジュール] を追加します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/51221d8e-2534-bfca-7d0b-50914d8c3cdc.png)

3. 繰り返し間隔を 1 分に設定し、次の [新しいステップ] を追加します。 
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/53f76bcd-e2c4-c231-dbab-14d8e7183b9a.png)

4. [すべて] のカテゴリから Azure Log Analytics で検索して、[Run quey and list results] を追加します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/7111708b-8688-313b-4665-6751c74ec3b6.png)

5. Azure サブスクリプションを管理している Azure AD テナントへサインインします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/4c703a72-f581-f1c0-0c87-87f0d20f8d09.png)

6. 対象となる Log Analytics の Workspace を選択します。Query には、Log Analytics のサンプルから、各 DataType のログ数を列挙するクエリー例を利用しています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/8968049b-ff8f-defb-afd6-6b4d03ccbb81.png)


7. 続けてクエリー結果の CSV への変換と BLOB ストレージへの出力を以下のように設定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/e3a0cae7-5f9d-fcb6-2584-8b7ae3bc9528.png)

#出力結果
　以下は、BLOB ストレージへのログ収集結果となります。ワークフローが動き出すと毎分、UTC 時刻名でログファイルが生成されていきます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/b3beb33c-230a-2543-907a-1488c0d5dbed.png)

ログの中身は、次のような CSV フォーマットで格納されています。

```
DataType,count_per_type
UpdateSummary,23
ProtectionStatus,168
Heartbeat,168
Operation,168
ConfigurationData,36
Update,5
ConfigurationChange,8
SecurityBaselineSummary,7
SecurityBaseline,7
```
ABC - 063- A&B&C

#AtCoder ABC 063 A&B&C
[AtCoder - 063](https://atcoder.jp/contests/abc063)

#A問題

 - $A + B \geqq 10$　を判定

```java
	private void solveA() {
		int numA = nextInt();
		int numB = nextInt();

		if (numA + numB >= 10) {
			out.println("error");
		} else {
			out.println(numA + numB);
		}

	}
```

#B問題

 - 文字列を全て分解して出現回数を調べる
    - Mapを使っても良かったのだけど配列で実装してみたかった
    - $(cahr)'XXX' - (char)'a'$　で`int[26]`の場所を決めるというのをやってみたかったので

```java
	private void solveB() {
		char[] wkC = next().toCharArray();
		int[] wk = new int[26];

		for (int i = 0; i < wkC.length; i++) {
			int index = wkC[i] - (char) 'a';
			wk[index] += 1;
		}
		Arrays.sort(wk);
		out.println(wk[25] > 1 ? "no" : "yes");
	}
```


#C問題

 - 先ず全部足してしまう
 - 足した結果が10の倍数でない場合**(sum % 10 != 0)**
    - それが回答

 - 足した結果が10の倍数の場合**(sum % 10 == 0)**
    - （合計-テストの点数) % 10 != 0 になる最小値を探す
    - テストの配点配列を元に、一番点数が低い配点から順に探す

```java
private void solveC() {
		int numN = nextInt();
		int[] wkC = IntStream.range(0, numN).map(i -> nextInt()).toArray();

		int cnt = Arrays.stream(wkC).sum();

		/*
		 * 配点の合計点数が10の倍数でない場合はそれが答え
		 */
		if (cnt % 10 != 0) {
			out.println(cnt);
			return;
		}

		/*
		 * 配点配列を配点が少ない順にソート
		 */
		Arrays.sort(wkC);

		/*
		 * wkC[i]%10 != 0で判定をするとNG
		 * 　13の時、-3したら10になってしまう。
		 *  (cnt-wkC[i]) %10 != 0で判定をする
		 *  　13-3=10を除外するため
		 *  何故か気づかずはまった　orz
		 *
		 */
		for (int i = 0; i < wkC.length; i++) {
			int wkCnt = cnt - wkC[i];
			if (wkCnt % 10 != 0) {
				out.println(wkCnt);
				return;
			}
		}
		out.println(0);

		//		out.println(chkC(wkC, 0, 0, numN));
	}
```

#C問題のTLEになるような実装

 - 再帰使って全部走査することをやってみたら、、、TLEになった。
 - 時間気にしない場合これでも動作はする。

```java
	private long chkC(int[] wkC, int currentI, long total, int max) {

		if (currentI >= max) {
			if (total % 10 == 0) {
				return 0;
			} else {
				return total;
			}
		}
		long res = 0;

		//自分を足して次に進む場合
		long val1 = chkC(wkC, currentI + 1, total + wkC[currentI], max);
		//自分を足さないで次に進む場合
		long val2 = chkC(wkC, currentI + 1, total, max);

		res = Math.max(val1, val2);
		//		out.println(currentI + " : " + total);
		return res;
	}
```
gaphql-rubyで不親切なエラーメッセージに立ち向かう

rails (5.2.2.1)
graphql (1.9.3)

## 見慣れぬエラーメッセージ

[rmosolgo/graphql-ruby](https://github.com/rmosolgo/graphql-ruby)を使っていると、まれに以下のようなエラーメッセージに遭遇することがあります。

```shell

LoadError - Unable to autoload constant Types::MutationType, expected .../app/graphql/types/mutation_type.rb to define it:
```

こちらのエラー、特にMutationを使用していないプロジェクトでも発生することがあり、かつ内容やトレースからは原因が追いづらいものになってます。どうして怒られたのでしょうか。

## 対処

そこで真の原因究明のため、いったん以下の変更を加えてみます。

```ruby
# config/application.rb
config.paths.add 'app/graphql/types', eager_load: true`
```

あまりスマートな方法ではありませんが、「 `Types::MutationType` が無い」と怒られたので明示的にautoloadさせてみた感じですね。
これで一旦冒頭のような奇妙なメッセージは消え去り、下記の通りより本当のエラーに近い内容がトレースされるようになりました。

```shell
/myapp/app/graphql/queries/select_query.rb:26: syntax error, unexpected ':', expecting '}' result: row, ^ 
```

ご覧の通りで、今回の場合原因は単なるrubyのシンタックスエラーだったことが分かったのですが、最初の表示はトレースを追っても全然到達できず、これには中々ハマりました。

## 本家issueの状況

[Trying to use a union, getting "Unable to autoload constant Types::MutationType" #1245](https://github.com/rmosolgo/graphql-ruby/issues/1245)

本家にも似たようなissueがありますが、2019/3/28現在はfixのないままcloseされてる状態のようです。
それにしてもこの挙動には何人も苦しんでるようで、スキを見てPR投げてみようかなという気持ちになりますね ^^;
[Rails5] Railsデバッグ時にサーバーを毎回再起動している方へ。

# サーバー再起動不要なRailsのデバッグに関する話
**Railsのデバッグで毎回Railsサーバーを再起動している方へ！**
**実はそんな事する必要はありません！**

なんの話かというと、先日からRails5の学習を下記環境で行ってます。

* CentOS7(VirtualBox上にRailsサーバーを立ち上げる。)
* WindowsでVSCodeからリモートデバッグ
* 私が以前書いた[Railsの環境構築の仕方](https://qiita.com/takmt/items/0858dbd3c53cabaa4395)が主な環境
* RailsVerは5.2.1.1
* RubyVerは2.5.5

で、私のデバッグのやり方としては下記のやり方を繰り返しておりました。

1. ソースコードを更新する。
* RailsサーバーをCTRL+Cで止める。
* Railsサーバーを起動する為に`bundle exec rdebug-ide ....省略` というコマンドを打つ。
* VSCodeからデバッグ開始(F5キー)を行う。
* 約10秒後サーバーが起動するのでブラウザから動作確認
* ステップ実行の結果うまく動かなかったら 1に戻る。

この方法を行っていた理由は、
Railsサーバーの再起動をしないとソースコードを変更してもブラウザ上に表示される結果やブレークポイントの値がソースコード変更前の値のままだったからです。

皆さんの中でこんな方法でデバッグしている方はいませんか？
**実はこの方法非常に非効率です。**

-------------

## サーバーを再起動せずデバッグを効率よく行う方法

何か効率のよいやり方はないか？と思って調べてみると、実はサーバーを毎回止めなくてもよい事がわかりました。。。
(私が知らなかっただけです。。。)

という事で現在のデバッグの形はこんな感じです。

1. 予め`bundle exec rdebug-ide ...省略`コマンドでRailsサーバーが立ち上がっている。
* ソースコードを更新する。
* ステップ実行の結果うまく動かなかったら 2に戻る。

すごく簡略化できました。

やり方は非常に簡単。

Railsアプリケーションのファイル
`config/environment/development.rb`の

```
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
```

の箇所を

```
config.file_watcher = ActiveSupport::FileUpdateChecker
```

に変更するだけです。

これはソースコードの更新をサーバー起動中もチェックしてくれる機能のようです。

これでControllerの処理などを変更したときでも、
* Railsサーバーを再起動しなくてもよい。
* ブラウザ上では更新後の結果が表示される。
* ブレイクポイントでも更新後の値が表示される。
というような事が出来ます。

ただし `db:migrate`などコマンドを伴うような更新はRailsサーバーの再起動が必要と思います。

# 読んでいただきありがとうございます。
一人でも同様の問題を解決出来れば幸いです。
これで無駄な時間を減らし遊ぶ時間を増やすことができますね。

もし誤っている点などありましたら御指摘の程お願いします。
npm install request してもnpm install -g requestしてもCannot find module 'request'

# 問題
npm install requestしてもnpm install -g requestしても、~/.bash_profileにグローバルなパスを追加してもCannot find module 'request'になるという事象が起きた。

```
$ node app.js 
module.js:57
    throw err;
    ^
Error: Cannot find module 'request'
```
# 解決策

```
npm install request --save
```

# 原因
npm install requestしたのに関わらず、package.jsonのdependenciesにはrequestモジュールが含まれていなかった。その原因は謎。なので--saveオプションを指定して、package.jsonのdependenciesにバージョン付きで書き込んであげた。

# 学んだこと
Error: Cannot find module ~ ってエラーが出力されたら、npm installを既に叩いていても、
package.jsonの中身を確認する。確認して存在していれば~/.bash_profile辺りを確認してみる。

# 参考記事
[node.js: cannot find module 'request'
](https://stackoverflow.com/questions/16482600/node-js-cannot-find-module-request)[npm install -gでグローバルインストールしたのに見つけてくれない](https://qiita.com/chkk525@github/items/ea1c2a110bf74efd843c)
Dockerでcronを回す時ハマったこと


# タイムゾーンの設定

`Dockerfile` や `docker-compose.yml` のどっかに下記環境変数を設置しましょう

```
TZ=Asia/Tokyo
```
環境変数だけでは、システムが`Asia/Tokyo`になったが、cronが`UTC`のままになっているケースがあるため、`/etc/timezone`も更新しなければいけません。

```
$ ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
```

設定が終わったら、cronを再起動します。

```
$ service cron restart
```

# `crontab -e` でエラーが発生した

おそらくエディター入れてないのが原因なので、 `vim` などを入れましょう

# cronが効かない

大まか２つ可能性がある
## 1. cronが起動されてない

こんな現象が見れるはずです。

```
$ service cron status
[FAIL] cron is not running ... failed!
```

そこで `service cron start` を打てば、OKです。

```
$ service cron status
[ ok ] cron is running.
```

## 2. cronがエラーになった

まず、動いているcronのdaemonを終了します。

```
$ service cron stop
```

そして、下記コマンドでcronをフロントで回して、様子をみます

```
$ cron -f
```

Sessonをもう一つ立ち上げて、すぐ実行しそうなjobを入れます

```
* * * * * /bin/bash -l -c 'echo `date` >> /var/log/cron.log'
```

上記コマンドであれば、`/var/log/cron.log`　を監視してみましょう。

```
$ tail -f /var/log/cron.log
```

もし、cron自身がエラーになった場合、先ほど `cron -f` を回したセッションに、エラーログが吐くと思います。

```
$ cron -f

Cannot make/remove an entry for the specified session
```

対策としては、 `/etc/pam.d/cron` または `/etc/pam.d/crond` の下記の一行をコメントアウトします。

```
# session    required   pam_loginuid.so
```

そしてcronを再起動すれば、動くはずです。

Dockerfileの場合はこんな書き方：

```
RUN sed -i '/session    required     pam_loginuid.so/c\#session    required   pam_loginuid.so' /etc/pam.d/cron
```

# 参考
https://yoru9zine.hatenablog.com/entry/2017/01/12/224637
https://qiita.com/mokemokechicken/items/60bebaabb9acd012ea03
https://stackoverflow.com/a/43473861
PureDataでの日付変換

PureDataで任意の文字列をTimeStamp型に変換する
```TO_TIMESTAMP('2019/03/20 00:00:00','YYYY/MM/DD HH24:MI:SS')```

任意の文字列をDate型に変換する
```TO_DATE('2019/03/20','YYYY/MM/DD')```

PureDataの中身はほぼPostgre SQLのため、書き方は同じ。
FactoryGirlからFactoryBotにバージョンあげたらundefined methodになる

##背景

FactoryGirlからFactoryBotにバージョンアップした時
RSpecテスト時、Undefined Methodエラーでちょっとつまづきました。

##使用環境
- MacBook Pro (15-inch, 2018)
- macOS Mojave 10.14.3
- VSCode 1.31.1
- factory_bot 5.0.2

##起こったこと
factoryは下の通りです。

```ruby:spec/factories/medicine.rb
  factory :medicine do
    name {generate :seq_medicine_name}
    title {generate :seq_medicine_title}
    reported_at "2019/12/31"
    request_staff {generate :seq_medicine_request_staff}
    detail {generate :seq_medicine_detail}
    source {generate :seq_medicine_source}
    report_staff {generate :seq_medicine_report_staff}
  end 
```

これでRSpecにてテストすると
以下のエラーとなる。

```
An error occurred while loading ./spec/requests/medicines_spec.rb.
Failure/Error: reported_at "2019/12/31"

NoMethodError:
  undefined method 'reported_at' in 'medicine' factory
```

##解決方法
{}　←これが必要みたいですね。
5.0.0からは中括弧｛｝をつけないと動かないみたいです。

```ruby:spec/factories/medicine.rb
  factory :medicine do
    name {generate :seq_medicine_name}
    title {generate :seq_medicine_title}
    reported_at {"2019/12/31"}
    request_staff {generate :seq_medicine_request_staff}
    detail {generate :seq_medicine_detail}
    source {generate :seq_medicine_source}
    report_staff {generate :seq_medicine_report_staff}
  end 
```
[メモ] ラズパイ: Tor proxyで、.onionドメインにアクセス

- *.onion にアクセスするメモ

# 概要

- Dockerをつかって、ラズパイを Tor proxyにします。
- https://github.com/PeterDaveHello/tor-socks-proxy をそのままつかってます。


# 環境
- Raspberry Pi 3B
- Raspbian: `2018-11-13-raspbian-stretch.zip`
- パッケージ更新: 2018/3/27 (apt update && apt upgrade)
    - Chromiumが、72.0.になった

		```shell-session
		pi@raspberrypi:~ $ chromium-browser --version
		 --disable-quic --enable-tcp-fast-open --disable-gpu-compositing --ppapi-flash-path=/usr/lib/chromium-browser/libpepflashplayer.so --ppapi-flash-args=enable_stagevideo_auto=0 --ppapi-flash-version=
		Chromium 72.0.3626.121 Built on Raspbian , running on Raspbian 9.8
		pi@raspberrypi:~y $ 
		```
- Docker 導入しておく。 <br>`curl -sSL https:/get.docker.com | sh && sudo usermod -aG docker $USER`


# 手順
1. Torコンテナの準備

	```bash
	DOCKER_NAME=tor-socks-proxy

	# git クローン : ${DOCKER_CONTAINER_NAME} フォルダへ
	git clone https://github.com/PeterDaveHello/tor-socks-proxy ${DOCKER_NAME}
	cd ${DOCKER_NAME}

	# ビルド
	docker build . -t ${DOCKER_NAME}
	```

2. コンテナ起動<br>`-p`オプションにて、ローカルのみか、誰でも接続できるか、指定できる

	```bash:起動
	# ローカルのみ接続許可
	docker run -d --name ${DOCKER_NAME} -p 127.0.0.1:9150:9150 ${DOCKER_NAME}

	# 誰でも接続できる
	# docker run -d --name ${DOCKER_NAME} -p 9150:9150 ${DOCKER_NAME}

	# 様子を見る
	docker logs ${DOCKER_NAME}
	
	# > ...
	# > Mar 28 01:34:19.000 [notice] Bootstrapped 100%: Done
	# こんな感じのが出てたら、起動OK
	```

3. 接続テスト

	1. `curl -x socks5h://localhost:9150 https://ipinfo.io/ip`

		```shell-session
		pi@raspberrypi:~ $ curl -x socks5h://localhost:9150 https://ipinfo.io/ip
		185.220.101.27
		pi@raspberrypi:~ $ 
		```

	2. chromiumにて<br>`https://3g2upl4pq6kufc4m.onion/` は DuckDuckGoへ行きます。
	

		```bash
		chromium-browser --proxy-server="socks5://127.0.0.1:9150" \
				https://ipinfo.io/ip \
				https://3g2upl4pq6kufc4m.onion/ &
		```
		
4. テスト終了

	```bash:コンテナ動作停止、削除
	# DOCKER_NAME=tor-socks-proxy
	docker stop ${DOCKER_NAME}
	docker rm ${DOCKER_NAME}
	```


5. (お好みで) Dockerコンテナをサービスに登録して、自動起動

	```bash:こぴぺ
	DOCKER_NAME=tor-socks-proxy
	DOCKER_CONTAINER_NAME=tor-socks-proxy

	# とりあえず起動させる
	docker run -d --name ${DOCKER_CONTAINER_NAME} -p 9150:9150 ${DOCKER_NAME}


	# systemdのファイル作成
	sudo sh -c "cat <<EOF > /lib/systemd/system/${DOCKER_CONTAINER_NAME}.service
	[Unit]
	Description=${DOCKER_CONTAINER_NAME} container
	Requires=docker.service
	After=docker.service

	[Service]
	Restart=always
	ExecStart=/usr/bin/docker start -a ${DOCKER_CONTAINER_NAME}
	ExecStop=/usr/bin/docker stop ${DOCKER_CONTAINER_NAME}

	[Install]
	WantedBy=multi-user.target
	EOF"


	# systemdの設定
	sudo systemctl daemon-reload
	sudo systemctl enable ${DOCKER_CONTAINER_NAME}.service
	sudo systemctl restart ${DOCKER_CONTAINER_NAME}.service

	# サービスが起動しているか?
	#sudo systemctl status ${DOCKER_CONTAINER_NAME}.service
	# なんちゃら、100%になっているか?
	#docker logs ${DOCKER_NAME}
	```

# おまけ
- ほかからも、接続できるようにした場合(`-p 9150:9150`)、<br>
"~~\chrome.exe" --proxy-server="socks5://rpi_ip:9150" というかんじで、ショートカットを作れば、WindowsのChromeをTor経由で使える。
<br>![image.png](https://qiita-image-store.s3.amazonaws.com/0/75594/ff35d970-c7f6-7e42-8db0-4d86a40f9e81.png)
[個人メモ] おすすめの3本を2行でまとめ

# リーダブルコード
　**読みやすいコードに必要なメソッドが複数詰まっている。
　実際のコードのbefore afterなど見ながら学べた。**

　（例）Getは伝わらない。FetchPageやDownloadPage。
　（例）Stopではなく、キャンセルできないならKill、ResumeできるならPause。

# Team Geek
　**ミッションステートメントを設定し、沿わない機能はどんなに素晴らしくても実装しない。
　チームマネジメント/開発への心得を数多く学べた。**

　（例）Chromeなら4つのS以外は実装しない。
　（例）目標を設定したら自律性にまかせる（マイクロマネジメントをしない）
　
# 世界最高のチーム
　**心理的安全性を確保しなければ何をしても”成果の高い”チームにはなれない
　チームで開発を行う上で重要と思われる心得を学べた。**

　（例）愚痴はチーム改善に。建設的に
　（例）自分らしさを発揮しながらチームに参画できる環境を作る
GASの通知用関数の簡易メモ

GAS（Google Apps Script）で通知したい時用の簡易メモ。

``` js
function myFunction() {
  var msg = "test";

  mail(msg);
  slack(msg);
  line(msg);
  chatwork(msg);
  hangout(msg);
}
```

## Mail

``` js
function mail(message) {
  var to = "***@gmail.com";
  var subject = "test";
  MailApp.sendEmail({
    to: to,
    subject: subject,
    body: message,
  });
}
```

## Slack
- Incoming WebHooksを設定。
  - https://slack.com/apps/A0F7XDUAZ--web-
  - 設定を追加　＞　「Webhook URL」をメモ。

``` js
function slack(message) {
  var postUrl = 'https://hooks.slack.com/services/******************'; // Incoming WebHooksで発行したURL
  var jsonData =
  {
     "text" : message
  };
  var payload = JSON.stringify(jsonData);
  var options =
  {
    "method" : "post",
    "contentType" : "application/json",
    "payload" : payload
  };
  UrlFetchApp.fetch(postUrl, options);
}
```

## LINE
- LINE Notify
  - https://notify-bot.line.me/ja/
- マイページ　＞　トークンを発行する
  - トークン名
    - LINEで通知を受け取る際に一番上に表示される名前。「自動通知」などに。
  - 通知を送信するトークルーム
    - 送信したいLINEグループを選ぶ。但し、最初は「1:1でLINE Notifyから通知を受け取る」でテストを。
- トークンをメモする
  - 一度しか表示されないので必ずメモを。
  - 忘れてしまったら再度トークン発行で対応。


``` js
function line(message){
  var token = "******************"; // LINENotifyで発行したトークン
  var api = "https://notify-api.line.me/api/notify";
  var options =
   {
     "method"  : "post",
     "payload" : {"message": message, }, 
     "headers" : {"Authorization" : "Bearer "+ token}
   };
   UrlFetchApp.fetch(api,options);
}
```

## Chatwork
- Chatwork　＞　「API設定」　＞　API Tokenを取得　＞　API Tokenをメモ
- Chatworkのライブラリを追加
  - GAS　＞　「リソース」 ＞　「ライブラリ」　＞　M6TcEyniCs1xb3sdXFF_FhI-MNonZQ_sT　＞　一番新しい番号のバージョンを選択
- ChatworkのルームID
  - $!ridXXXXX の数字がルームID

``` js
function chatwork(message){
  var client = ChatWorkClient.factory({token: "****************"}); // Chatwork API トークンを記載
  client.sendMessage({
    room_id: **********, // チャットを通知したいグループチャットのIDを記載。#!ridはいらない。
    body: message
  }); 
}
```

## Hangout
- チャットルーム名　＞　Webhookを設定

``` js
function hangout(message) {
  var url = 'https://chat.googleapis.com/**********************'; //　WebhookのURLを記載
  var msg = { 'text' : message }
  var options = {
    'method': 'POST',
    'headers' : {
      'Content-Type': 'application/json; charset=UTF-8'
    },
    'payload':JSON.stringify(msg)
  };
  UrlFetchApp.fetch(url, options);
}
```
kintoneに存在しないデータをkrewDataで抽出する

# やること
顧客マスターと訪問履歴の2つのkintoneアプリがある場合を考えます。

顧客マスターには全顧客が登録されています。
訪問履歴には訪問した顧客のデータしか存在しません。

kintoneの標準機能では訪問していない顧客を抽出することはできません。
そこでkrewDataを使って訪問していない顧客を抽出してみます。

# krewDataとは
[krewData](https://krew.grapecity.com/products/krewdata.htm)とはスケジュール実行でアプリ間のデータを自在に集計できるkintoneプラグインです。
[30日間の無料お試し](https://krew.grapecity.com/trial/)があります。

# 存在しないデータの抽出方法1
それでは早速試してみます。
## kintoneアプリの構成とデータ
顧客マスターアプリの構成は以下の通りで、5件登録されています。
![顧客マスター.jpg](https://qiita-image-store.s3.amazonaws.com/0/102790/c9f65eed-d2ee-5213-8244-54e203be1f0e.jpeg)


訪問履歴アプリの構成とデータは以下の通りで、2件登録されています。
![訪問履歴.jpg](https://qiita-image-store.s3.amazonaws.com/0/102790/1aef2b6d-d424-b6a5-0ced-385a2bee9c79.jpeg)


## krewDataの設定
全体のフローは以下の通りです。
![krewData2.jpg](https://qiita-image-store.s3.amazonaws.com/0/102790/59fdf32a-9749-aa5e-432b-e87dd58f957b.jpeg)


- ポイント1
「レコード結合」パーツで顧客マスターの顧客名と訪問履歴の顧客名とを結合します。
顧客マスターの5件と訪問履歴の2件を合わせて7件になります。
![krewData3.jpg](https://qiita-image-store.s3.amazonaws.com/0/102790/e846d011-4c5e-5a08-2e34-560e6ee7bab7.jpeg)


- ポイント2
「グループ化」パーツで顧客名でグループ化し、件数をカウントします。
![krewData4.jpg](https://qiita-image-store.s3.amazonaws.com/0/102790/78e5826a-1b78-3722-08d6-96da8a634d0f.jpeg)


- ポイント3
「フィルタ」パーツで件数が1件のみに絞り込みます。
![krewData5.jpg](https://qiita-image-store.s3.amazonaws.com/0/102790/1b53da78-ea58-3551-fb6c-bbba3ffa3764.jpeg)


- ポイント4
ポイント3の時点で未訪問の顧客を抽出できていますが、顧客担当も同時に取得できたほうが便利です。
そこで、「アプリ結合」パーツで顧客マスターと結合して顧客担当を紐づけます。
![krewData6.jpg](https://qiita-image-store.s3.amazonaws.com/0/102790/84bb78a1-28c4-7d50-130a-5a3e079c60d6.jpeg)

# 存在しないデータの抽出方法2
書いていて外部結合＋フィルタでも実現できることに気が付きました。
こっちのほうがフローが短いです！

全体のフローは以下の通りです。
![krewData11.jpg](https://qiita-image-store.s3.amazonaws.com/0/102790/01a7e783-c8e7-d005-acff-c52602e5fdff.jpeg)


- ポイント1
「アプリ結合」パーツで結合します。
![krewData8.jpg](https://qiita-image-store.s3.amazonaws.com/0/102790/440f8415-cd02-7584-abb8-aa912f2642d0.jpeg)

そうするとこんな感じのデータができあがります。
![krewData9.jpg](https://qiita-image-store.s3.amazonaws.com/0/102790/eebbc697-9695-fe6d-9221-931c0717f8dc.jpeg)

- ポイント2
「フィルタ」パーツで絞り込みます。
![krewData10.jpg](https://qiita-image-store.s3.amazonaws.com/0/102790/8eef025b-c4df-60e5-d617-54fabfed2598.jpeg)


# krewDataの実行
krewDataを実行すると以下のデータが登録されます。ばっちり！
![krewData1.jpg](https://qiita-image-store.s3.amazonaws.com/0/102790/766ed1fe-9b3f-eb73-20da-e809c9d53524.jpeg)

# その他
krewDataにはスケジュール実行機能があるのでそれを使って毎日実行できます。

アプリの対象レコードに条件を設定することも可能です。
例えば訪問履歴アプリの対象を日付で絞り込むことで**今年**未訪問の顧客リストなどにすることも可能です。
![krewData7.jpg](https://qiita-image-store.s3.amazonaws.com/0/102790/8a0aefc7-8d9a-97b7-b2c1-c05730a5d646.jpeg)

krewDataが扱うレコード数には上限があるのでそこは注意が必要です。
https://docs.krew.grapecity.com/krewdata/#krewdata_limitations.html
Dropbox デバイス数制限への対策

# 3台まで？？
先日、Dropbox の無料アカウントでのリンク数が3台までに制限されることが発表された([本家ページ](https://help.dropbox.com/ja-jp/account/computer-limit))。自分の場合は明らかに制限数を超えるデバイスで使用しているため、今後デバイスの入れ替えなどを行う場合に3台[^1]までに減らす必要がある。

幸いにも過去にリンクしたデバイスは維持されるようなので[^2]、今のうちに徐々に手を打つ（手を引く）のがよさそうである。

結論を先に書いておくと、

+ 共有サーバに Dropbox のリンクを1台分充て、同一ネットワーク内ではそのマシンを介してファイルを共有する
+ Windows / Mac はメインを OneDrive に乗り換え

という方法を取ることにした。全面的に OneDrive に移行しないのは、Dropbox 上で何人かとシェアフォルダを運用していることが原因。

# Dropbox の削減方法
## Before
まずは本当に必要なデバイスを洗い出す必要がある。自分の場合2カ所の拠点があり、加えてモバイル環境もあるので、総数は10台程度。

#### 拠点A
+ Mac mini (1)
+ Windows note (1)
+ Android Tablet (1)

#### 拠点B
+ Linux (2)
+ Windows note (3)

#### モバイル
+ Android Phone (1)
+ Macbook (1)

これら全てでファイルを共有する必要があるのか？という問題があるが、一部のファイルは全てで共有したい前提で考える。最終的には2拠点とモバイルそれぞれ1個のリンク（計3台）で済むようにしたい。

#After
結果、下記のようにした。まだ5台までしか減っていない。この間に OneDrive で済むものは移行を進めていく。モバイルについても Dropbox への依存度を減らしていく予定。

#### 拠点A
+ Mac mini (1) [ **Dropbox**,  OneDrive,  iCloud ]
+ Windows note (1) [ OneDrive, **Dropbox** ]
+ Android Tablet (1) [ 廃止予定 ]

#### 拠点B
+ NAS(Linux) (1) [ **Dropbox** ( on NAS ) ]
+ Linux (1) [ NAS, OneDrive ( Free Client for OneDrive on Linux ) ]
+ Windows note (3) [ NAS, OneDrive ]

#### モバイル
+ Android Phone (1) [ **Dropbox** ]
+ Macbook (1)  [ NAS, **Dropbox**, OneDrive, iCloud ]

### 説明
Windows 同士 については OneDrive をメインに切り替えることで対処することにする。オンデマンド機能が実装されてから、ノートPCでも使いやすくなった。Mac 同士については iCloud である程度共有できるが OneDrive に統一することにした[^3]。Mojave ではオンデマンドも使える。

拠点Bでは Linux 1台を NAS(NFS/Samba) にしているため、このネットワーク内では全てのマシンでファイルを共有できる。従って、Dropbox の同期フォルダのシンボリックリンクをNASの公開フォルダに作成することで難なく解決した。

Dropbox の同期フォルダをNASの公開用フォルダの階層下へ移動することを考えたが、下記の記事を参照すると LinuxのCUI環境では面倒かもしれないのでやめた[^4]。

- [Dropbox フォルダの場所 - Dropbox ヘルプセンター](https://www.dropboxforum.com/t5/%E8%B3%AA%E5%95%8F%E3%81%99%E3%82%8B/Dropbox-%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E3%81%AE%E5%A0%B4%E6%89%80/td-p/253378)

#その後
SynologyのNASを導入して、クラウドへの依存度を減らそうとしている最中。SynologyのDSMでCloudSyncを利用するとDropboxのクライアント数にカウントされないことが分かった。下記の強調表示は台数カウントされるデバイス。3台まで絞り込んだ。NASは全デバイスで使用するので省略。また、NASを入れなければデバイスは8台まで減少。

####拠点A
+ Synology NAS [ CloudSync (Dropbox, OneDrive, GoogleDrive, ...) ]
+ Macbook (1) [ OneDrive, iCloud ] モバイル->A
+ Windows note (1) [ OneDrive ] B->A

####拠点B
+ Synology NAS [ CloudSync (Dropbox, OneDrive, GoogleDrive, ...) ]
+ Mac mini (1) [ **Dropbox**, OneDrive, iCloud ] A->B
+ Windows note (1) [ OneDrive ]
+ Linux (1) [ OneDrive ]

####モバイル
+ MacBook Pro (1) [ **Dropbox**, OneDrive, iCloud ]
+ iPad (1) [ OneDrive, iCloud ]
+ Android Phone (1) [ **Dropbox** ]

他に GoogleDrive, Box などを適宜倉庫代わりや共有に使用。コロナ騒ぎで G Suite を契約した結果GoogleDriveの容量制限が無くなり、活用法を検討中。

特に最近、[[Mac OS] OneDriveの暴走対策](https://qiita.com/rpscrw/items/a5fc3b017ac8a3328d42)で取り上げた問題もあり、OneDriveも万能では無いのが気になるところ。

[^1]: 新デバイスを含む
[^2]: 過去にEvernoteで2台に制限された時よりはマシな状況
[^3]: CPU使用率が異状に高くなるバグがあり、iCloud Drive は使いたくない
[^4]: GUIだと簡単に設定できる模様: [Ubuntu Dropbox その4 - Dropboxの設定を行う・Dropboxの全般設定を行う・Dropboxフォルダーの場所を変更する](https://kledgeb.blogspot.com/2014/06/ubuntu-dropbox-4-dropboxdropboxdropbox.html)
debian(jessie)のdocker imageでapt-getのエラー→要らないエントリを消しましょう

[こちらの投稿](https://qiita.com/rh_taro/items/40373a30ead444ae9ca7)について、間違いがあるのでメモを（最初は編集提案しようと思ったのですが、ガッツリ書き換えで大変すぎたのでエントリ立ててみました）。

詳細な背景と対処を[blogに書いておいた](https://henrich.github.io/blog/2019/03/26/%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88%E7%B5%82%E4%BA%86%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AE%E3%82%A2%E3%83%BC%E3%82%AB%E3%82%A4%E3%83%96%E5%89%8A%E9%99%A4%E3%81%AB%E5%AF%84%E3%81%9B%E3%81%A6/)のでそちら見てください。件の投稿ではセキュリティアップデートの設定も消してしまってるので良くないです。
【Git】2つのGitリポジトリを履歴を保持して統合したい



### 初めに


基本は以下のリンク先の記事を参考にさせていただいています。
 [Git 別のリポジトリを履歴を残したまま取り込みたい](https://chaika.hatenablog.com/entry/2015/06/04/173401)


### 環境
  *  ubuntu18.04
  *  git version 2.17.1


### 今回やること


現状`repo_a`と`repo_B`リポジトリが別々に存在し、以下のような構成になっています。

```
~/repo_A
   |--- .git
~/repo_b
   |--- .git
```

これを`repo_A`内に`repo_B`をディレクトリとして統合し、**repo_Bの履歴も保持したまま**以下のような構成にします。

```
~/repo_A
   |--- .git
   |---repo_B
```


Treeは下記のようになる想定です。

```
*       <name>    <commitID> marge repo_B in repo_A
|\     
| *     <name>    <commitID> repo_B HEAD
| *     <name>    <commitID> commit3
| *     <name>    <commitID> commit2
| *     <name>    <commitID> commit1
| *     <name>    <commitID> repo_B init
*       <name>    <commitID> repo_A HEAD
*　　　　<name>    <commitID> repo_A commit1
```



### 手順

#### Homeディレクトリに`repo_A`、`repo_B`リポジトリをcloneする

```
$ cd ~　#hemeディレクトリで作業します
$ git clone <repo_Aのurl>
$ git clone <repo_Bのurl>
```

#### `repo_B`を入れるディレクトリを作成
今回は`repo_A`の中に統合するため`repo_A`の中にあらかじめ`repo_B`を入れるディレクトリを作成しておきます。
今回はそのままではありますが、ディレクトリ名を`repo_B`にします。

```
$ cd repo_A/ 
$ mkdir repo_B
#repo_BディレクトリをGit管理できるよう.gitkeepを作成します
$ touch repo_B/.gitkeep 
$ git add -A repo_B
$ git commit -m "create repo_B dir" #ディレクトリをgitに追加します
```

#### `repo_B`リポジトリをリモートリポジトリとして追加する
取り込みたい`repo_B`リポジトリを`repo_A`のリモートリポジトリに追加します。

ただし自分は`fetch`が必要でしたので、以下の記事を参考にさせていただきました。
[Git で複数のリポジトリをまとめたり、逆に切り出したりする](https://qiita.com/uasi/items/77d41698630fef012f82#repo1subdir-%E3%81%AB-repo2-%E3%82%92%E5%85%A5%E3%82%8C%E3%82%8B)

```
$ git remote add repo_B ~/repo_B
$ git fetch repo_B
```

#### subtreeとしてマージ
普通にマージしようとしますと以下のエラーが出ました。

```
$ git merge -X subtree=repo_B repo_B/master
fatal: refusing to merge unrelated histories
```

エラーメッセージから検索し、以下の記事を参考にさせていただきました。
[初めてGitHubリポジトリにpushしたらrejectedエラーになったときの対応メモ](https://qiita.com/takanatsu/items/fc89de9bd11148da1438#%E3%82%B0%E3%82%B0%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F%E3%82%89git-fetch--git-merge-originmaster%E3%81%97%E3%81%A6%E3%81%8B%E3%82%89push%E3%81%99%E3%82%8C%E3%81%B0ok%E3%81%A8%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%82%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%A7%E8%A9%A6%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B--merge%E3%82%A8%E3%83%A9%E3%83%BC)


```
git merge --allow-unrelated-histories -X subtree=repo_B repo_B/master
```
`--allow-unrelated-histories`を付けないと関係のないツリーはマージできない仕様らしいです。

あとは要らなくなった`.gitkeep`と`~/repo_B`を消して完了です。

```
$ cd ~/repo_A/repo_B
$ rm .gitkeep
$ cd ~
$ rm -r repo_B #-rはディレクトリも削除するオプションです
```


---
### 参考にさせていただきました！
ありがとうございます！

* [Git 別のリポジトリを履歴を残したまま取り込みたい](https://chaika.hatenablog.com/entry/2015/06/04/173401)
* [Git で複数のリポジトリをまとめたり、逆に切り出したりする](https://qiita.com/uasi/items/77d41698630fef012f82#repo1subdir-%E3%81%AB-repo2-%E3%82%92%E5%85%A5%E3%82%8C%E3%82%8B)
* [初めてGitHubリポジトリにpushしたらrejectedエラーになったときの対応メモ]( https://qiita.com/takanatsu/items/fc89de9bd11148da1438)