OmniAICreator/Qiita-1.07M huggingface dataset:
H2 をデータベースに指定した場合、spring.jpa.hibernate.ddl-auto を create にしてもテーブルが作成されない現象

#概要
Spring Boot にて AuditorAware の機能を使用して作成日、更新日を設定していましたが、通常の SQL 実行時においてもデフォルト値として現在日時を設定するために columnDefinition にて既定値を設定するよう設定した結果、H2 データベースにテーブルが作成されなくなる現象が発生しました。
なお、MYSQL をデータベースに指定した場合、正常にテーブルが作成される動作になりました。

```Audit.java
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@Getter
public class Audit implements Serializable {
    @CreatedBy
    private String createdBy;

    @CreatedDate
    @Column(nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
    private LocalDateTime createdDate;

    @LastModifiedBy
    private String modifiedBy;

    @LastModifiedDate
    @Column(nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
    private LocalDateTime modifiedDate;
}
```

#原因と解決策
どうやら、2017/10/20 現在の H2 データベースの動作においては、ON UPDATE が指定できないようです。
columnDefinition を変更した結果、正常に動作するようになりました。
update については、@EnableJpaAuditing にて自動的に更新日時が設定され、通常の SQL にて UPDATE を打つ可能性は低いですが、どこで更新が行われているかわからなくなるかもしれないと考え指定しました。
テストを H2 データベースにて正常に行う方が、更新日時の更新のタイミングを追いかける必然性より高いと判断したので、下記のように変更しました。


```Audit.java
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@Getter
public class Audit implements Serializable {
    @CreatedBy
    private String createdBy;

    @CreatedDate
    @Column(nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
    private LocalDateTime createdDate;

    @LastModifiedBy
    private String modifiedBy;

    @LastModifiedDate
    @Column(nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
    private LocalDateTime modifiedDate;
}
```
##補足
上記のエンティティを継承したクラスは、テスト時においては、下記 AuditorAware が動作いたしますので、CreatedBy, LastModifiedBy については、TEST_AUDITOR が設定されます。


```MockAuditAware.java
@Component
public class MockAuditorAware implements AuditorAware<String> {

    private String auditor;

    public static final String TEST_AUDITOR = "TEST_AUDITOR";

    @Override
    public String getCurrentAuditor() { return TEST_AUDITOR; }

    public void setCurrentAuditor(String auditor) {
        this.auditor = auditor;
    }

}
```

MockAuditAware クラスについては、テスト用の Configuration クラスに、@EnableJpaAuditing(auditorAwareRef = "mockAuditorAware") を設定してテスト時に起動するよう設定しております。

```TestConfig.java
@Profile("test")
@TestConfiguration
@ComponentScan(basePackageClasses = {TestRoot.class})
@Configuration
@TestPropertySource("classpath:application-test.properties")
@EnableJpaAuditing(auditorAwareRef = "mockAuditorAware")
public class TestConfig {
}
```
rspecを並列で動かすgemを使って実行時間を短くする（mongodb使用時の暫定対策も）


# 結論
* test-queueのgemを導入し満足のいく結果になりました
 * 2コアのマシンで約1900ケースを流した結果の比較
 
| Rspecのみ | test-queue併用 |
|----|--------------|
| 37 minutes | 15 minutes |

* マシン非力すぎ。。

* 課題が二点残りました
    * mongodbを使用するspecはコア数に応じた名前のdbをspecの度に作成する方法がわからなかったため、test-queueを使用しないようにする為spec/serial_onlyディレクトリを新規作成してそちらに移設し、コマンドでtest-queueを適宜使用するように運用していく
    * 進捗が表示されなくなってしまった（--format progressオプションが効かない）


# 選定候補と特徴
## test-queue（今回採用）
* 導入が容易
* CPUのコア毎にプロセスを立ち上げて処理を分散させ並列で動かす
    * その際にそれぞれのプロセスが独立したDBを使用する必要がある為、test1などの名前のDBがコア数分作成される
    * プロセスに割り当てる単位はspecファイル単位
    * 実行時の各specファイル毎の処理時間をrails_app/.test_queue_statsファイルに記録する
    * 次回実行時はrails_app/.test_queue_statsに記録した各specファイル毎の処理時間を参照し、各プロセスに対して負荷が均等になるようにspecファイルを割り当てる

[git-hub - test-queue](https://github.com/tmm1/test-queue)

## parallel_tests
* 開発が活発
* スター数が多い（2000ちょっと）
* CPUのコア毎にプロセスを立ち上げて処理を分散させ並列で動かす
    * その際にそれぞれのプロセスが独立したDBを使用する必要がある為、test1などの名前のDBがコア数分作成される
    * プロセスに割り当てる単位はspecファイル単位
    * specファイルのサイズを見て均等になるように割り振っているようだが、サイズでは処理の分散をきめ細かく行うことが出来ない（同じ一行のレコード生成処理でも、一件だけの生成とeachでの大量の生成では当然実行時間は異なり、片方が遊んでしまう可能性がある）
* トラブルが多い（ネットの評判）
* 試したが実際動かすことが出来なかった


[git-hub - parallel_tests](https://github.com/grosser/parallel_tests)

## rrrspec
* 複数マシンで並列で処理することを想定している
* コア数に応じて処理速度が上がるのかが不明なので、1台での運用時にメリットがあるのか不明
* 試していない

[git-hub - rrrspec](https://github.com/cookpad/rrrspec)


# test-queue導入方法
* ①gemのインストールと②DBをコア数分動的に作成しプロセスと紐付けする為のファイルを置く、の2点が必要でした。とにかく簡単
* ②は下記のサイトを参考にしました。そちらをご参考ください


[shimar's blog - test-queueでRailsアプリのRSpecの実行時間を短縮する](http://blog.shimar.me/2017/02/14/rails-rspec-test-queue.html)

# spec実行方法
## 非mongodb系（test-queueを使用したい）のspecの実行

```
bin/rspec-test-queue.rb --exclude-pattern "spec/serial_only/**/*_spec.rb" spec/
```
## mongodb系（test-queueを使用したくない）のspecの実行

```
rspec spec/serial_only
```



# 参考にしたWebページ
* [Qiita - RSpecを並列実行するgemを作っている話](https://qiita.com/yuku_t/items/ebe9a1d6e648f5c76041)
* [Qiita - RSpecの速度を並列実行で3倍速に〜3行書き換えて〜](https://qiita.com/sumyapp/items/ec457d023bbce832f999)
* [ユニファ開発者ブログ - テストコード(RSpec)の高速化事例](http://tech.unifa-e.com/entry/2017/01/25/105653)
* [Hatena Blog - Thanks Driven Life - parallel_tests ではなく test-queue に乗り換えようと思う](http://gongo.hatenablog.com/entry/2014/08/26/221311)
* [shimar's blog - test-queueでRailsアプリのRSpecの実行時間を短縮する](http://blog.shimar.me/2017/02/14/rails-rspec-test-queue.html)
Setting up local postgresql database server for WSL/Ubuntu

The [offical Ubuntu guide](https://help.ubuntu.com/community/PostgreSQL) can be a little confusing.

Here are the correct steps in order to set up a local postgresql database server.

1. `sudo apt install postgresql`
2. `sudo service postgresql start`
3. `sudo su - postgres`
4. `createuser --superuser $USER` where $USER is your username
5. `psql`
6. `\password $USER` is typed into the psql console to set up your account.
7. `\q` to exit
8. `createdb $USER` by convention
9. `exit` and now you can run `psql` in your own console with your username.
postmanによるdevise_token_authのログイン

# postmanをダウンロード

Chrome ExtensionでもApp版でもいいのでpostmanを落としてきて入れる。

Chrome Extension
https://chrome.google.com/webstore/detail/postman-interceptor/aicmkgpgakddgnaphhhpliifpcfhicfo?hl=ja

App版
https://www.getpostman.com/

# ログイン

## URLを設定する

- localhost/api/v1/sign_in
- POSTメソッド

## headerを設定する

- Content-Type application/json

![スクリーンショット 2017-10-20 13.23.12.png](https://qiita-image-store.s3.amazonaws.com/0/29737/403f73b3-2547-e5a1-f1c4-a02fd9ae5291.png)

## bodyを設定する

- email
- password

![スクリーンショット 2017-10-20 13.23.30.png](https://qiita-image-store.s3.amazonaws.com/0/29737/2f404577-e2d3-ea7e-0aa3-a375a74318df.png)

## レスポンスを確認する

- json側。指定したユーザーの情報が返ってくる

![スクリーンショット 2017-10-20 13.24.01.png](https://qiita-image-store.s3.amazonaws.com/0/29737/2ff317f5-deeb-f5d0-c1e9-8b89a0e0c5ef.png)

### ここ重要！

- header側。各種必要な情報になるので、メモっておく。
 - access-token
 - client
 - uid

![スクリーンショット 2017-10-20 13.24.15.png](https://qiita-image-store.s3.amazonaws.com/0/29737/e847ea3d-0f49-135c-3623-2117cc94d6a4.png)

## 試しにtokenが正しいか確認してみる

- URLを設定する
 - localhost/api/v1/validate_token
 - GETメソッドに変更するのを忘れずに

- header側にこの内容を入力してgetしてみる
 - Content-Type application/json
 - access-token
 - client
 - uid

- successが返ってくることを確認

![スクリーンショット 2017-10-20 13.30.57.png](https://qiita-image-store.s3.amazonaws.com/0/29737/cbc6e92b-11c0-8d3c-5764-ed4ffc35aa43.png)
擬似クラス nth-childとnth-of-type

# 擬似クラス nth-childとnth-of-typeの特徴と違い
 擬似クラスであるnth-child等の挙動が分かりづらい。
また、nth-childとnth-of-typeの違いについて正確に記載されているものが少なかったので、投稿いたします。
## 特徴
まずは、nth-childで挙動を確認します。

 - 両者とも、<font color="red">親要素（１つ上）</font>内の<font color="red">子要素（１つ下）</font>が検索範囲であることを知っておく必要があります。

```html

<ul class="list">
	<li class="item"><a class="link">1</a></li>
	<li class="item"><a class="link">2</a></li>
	<li class="item"><a class="link">3</a></li>
</ul>
```
```css
.item:nth-child(even) {	/* ulタグ内の偶数番目の要素がitemクラスか判定 */
	border-right: solid 1px #dcdcdc;
}

.link:nth-child(even) {		/* liタグ内の偶数番目の要素がitemクラスか判定 */
	border-bottom: solid 1px #dcdcdc;
}
```

[昔は、クラスに適用できなかった説あり](https://stackoverflow.com/questions/6447045/css3-selector-first-of-type-with-class-name)
## nth-childとnth-of-typeの違い
それでは、本題に入ります。
ズバリ、検索範囲の中で、要素（p, a, liなど）を判別して数えるかどうかが違います。

 - item:nth-child(n)         //n番目がitemクラスなら適用
 - item:nth-of-type(n)     //<font color="red">要素ごとの</font>n番目がitemクラスなら適用

```css
.item:nth-child(1) {		
	border-bottom: blue;
}

.item:nth-of-type(1) {	
	color: red;
}
```

```html
<div class="list">
	<a class="item">1</a>  //.item:nth-of-type(1)
	<p class="item"><a class="link">2</a></p> //.item:nth-child(1), .item:nth-of-type(1)
	<p class="item"><a class="link">3</a></p>
	<p class="item"><a class="link">4</a></p>
	<p class="item"><a class="link">5</a></p>
</div>
```

擬似クラスには、他にもfirst~~, last~~などありますが、~~上記の特徴を理解していれば問題ないかと思います。~~
かなり便利な使用方法は[擬似クラスのカラムレイアウトでの便利な使用方法](https://qiita.com/kudo_kk/items/8eec05f10ba11bfdd454)をご覧ください。
[concrete 8.2+] Expressオブジェクトとセレクトボックス属性をパッケージインストールで追加する


## この記事で書かれていること
* concrete Ver.8 から実装されたExpressオブジェクトをパッケージからインストールするサンプルコード
* Expressオブジェクトにセレクトボックス属性をコードで追加する方法

## この記事で割愛されていること
* Expressオブジェクトの操作、説明
* concreteでパッケージインストールの操作、説明

## サンプルコードの前に

concreteでは、独自に実装したコードをパッケージという単位でまとめてインストールできます。

GUIで同じ操作は可能なのですが、初期値の設定や大量の属性などは一括でインストールしたいですし、一元管理して保守性を高めたいところ。

Ver.8 から追加されたExpressオブジェクトは、O/RマッパーのためのデータモデルをGUIで作成できるものです。

Expressオブジェクトの基本操作はこちらにまとまっています。
http://c5blog.xross-cube.com/express%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A8%E3%81%AF/

ただデータインポート機能はまだないので、データ移行でCSVなどから一括インポートしたいのであれば自前での実装が必要です。
https://concrete5-japan.org/community/forums/chat/post-14882

まだドキュメントが整備中のため、コメント欄などに実装例があったりする状況です。

ここではパッケージインストールからExpressオブジェクトを作成し、セレクトボックスの属性を追加する実装を例示します。
以下、コメント欄での内容を参考にしています。
https://documentation.concrete5.org/developers/attributes/working-with-attribute-keys/creating-attribute-keys-in-a-package

## サンプルコード


```packages/my/controller.php
use \Concrete\Core\Package\Package;
use \Concrete\Core\Block\BlockType\BlockType;
use \Concrete\Core\Entity\Attribute\Key\Settings\SelectSettings;
use Concrete\Core\Entity\Attribute\Value\Value\SelectValue;
use Concrete\Core\Entity\Attribute\Value\Value\SelectValueOptionList;
use Concrete\Core\Entity\Attribute\Value\Value\SelectValueOption;
use Express;

class Controller extends Package
{

...

	public function install()
    {
        $pkg = parent::install();
        $this->installExpressObjects();
    }

    private function installExpressObjects()
    {
        $object = Express::buildObject('object', 'objects', 'Expressオブジェクト', $pkg);

        $object->addAttribute('select', '性別', 'object_sex', $this->selectSettings(['男', '女']));
        $object->save();
    }

    private function selectSettings($options, $isMultiple=false)
    {
        $settings = new SelectSettings();
        $list = new SelectValueOptionList();
        $list->setOptions($this->selectOptions($options, $list));
        $settings->setOptionList($list);
        if($isMultiple)
        {
            $settings->setAllowMultipleValues(true);
        }
        return $settings;
    }

    private function selectOptions($optionArray, $list)
    {
        $options = [];
        $displayOrder = 0;
        foreach($optionArray as $option)
        {
            $o = new SelectValueOption();
            $o->setSelectAttributeOptionValue($option);
            $o->setDisplayOrder($displayOrder);
            $o->setOptionList($list);
            if(is_object($o))
            {
                $options[] = $o;
                ++$displayOrder;
            }
        }

        return $options;
    }
    
...

}

```
Gradleでcompile(implementation)する時に常に最新バージョンを指定する

「ええい！毎回値を変更するの面倒なんじゃい！常に最新バージョンを勝手に見ててくれよう！」
という場合に有効な手段です。

大元はここからです。
[java.lang.IllegalStateException: Could not initialize plugin](https://github.com/mockito/mockito/issues/910)

# 指定方法
build.gradleで下記のように記載します。
今回はMockitoを例にします。


```build.gradle
dependencies {
def mockito_version = 'latest.release'
testImplementation "org.mockito:mockito-core:$mockito_version"
androidTestImplementation "org.mockito:mockito-android:$mockito_version"
}
```

重要なのは2行目の `latest.release` です。
Gradleでは動的にバージョンを指定でき、そのうちのひとつです。
https://docs.gradle.org/current/userguide/dependency_management.html#sub:dynamic_versions_and_changing_modules

他にも `latest.someStatus` 、 `latest.integration` などがありますが、リリース状態のものを指定するのがよいでしょう。

## ただし
この方法を使っていると、実際に今自分が使っているバージョンがわからなかったり、気づかぬうちにバージョンアップしてたりするので、
この方法は個人開発の時だけにするのが吉かと個人的には思います。

簡単でしたが以上です。
api blueprint でData Structuresを用いてIFを定義する

#aglioを用いたhtmlの生成
api blueprintで記述したAPI定義をaglioというレンダラーを用いて静的なHTMLとして出力することができます。その際にData Structuresというデータ型定義の方法があるのでポイントがあるのでまとめてみます。

##Data Structuresを用いたデータ型の定義
APIごとに戻りの形を記述するのではなく、共通の形はDetaStructuresを用いてスキーマ定義することが可能です。XMLにおけるxsdですね。
インターフェース定義と同一のファイルに定義しても良いですし、別ファイルに定義してもOKです。別ファイルに定義した場合のマージ方法は[こちら](https://qiita.com/haseshin42/items/2a03f14bd429f6cf44b5)を参照してください。型を外出しにして定義しておくことでデータ型が変更になった際にはここだけ修正すれば良い事になります。

```datastructure.apib
# Data Structures

## Person(object)
+ name: haseshin (string,required) - 名前
+ age:18  (string,required) - 年齢
```

##DataStructuresを用いた場合のIF定義
DataStructuresをもちいた場合にAPIの戻りの形を指定するには以下のように行います。

```interface.apib
+ Response 200 (application/json)
    + Attributes
      + person(Person)
```

##arrayを使う場合の注意点
配列の場合には以下のように定義します。

```interface.apib
+ Response 200 (application/json)
    + Attributes
      + persons(array[Person])
```
このままaglioで出力した場合、DataStructures側で定義した戻りのSchema情報に説明が含まれません。
この定義だとオブジェクトの配列であることを示していることに過ぎず、Personはそのサンプル･データという扱いになるためと思われます。

戻りのSchemaに説明を含めるには以下のように、Person型の配列であるということを明示的に定義します。

```interface.apib
+ Response 200 (application/json)
    + Attributes
      + persons(array[Person],fixed-type)
```

##まとめ
Data Structuresに型定義をすることで、APIを効率的に定義することが可能になります。
また、配列で固定の型を戻す際にはfixed-typeを使用することでschemaにプロパティの説明を含めることが可能になります。
プロットした時の表示を要素ごとに切り替える

例えばインデックスの偶奇で色を変えるなら

```r
> v <- c(1,0,1,0,1,0)
> v
[1] 1 0 1 0 1 0
> plot(v, col = ifelse(1:length(v) %% 2 == 1, "red", "blue"))
```

![alt.png](https://qiita-image-store.s3.amazonaws.com/0/44208/f93797bc-3c09-4a08-8ff2-714615762d0a.png)

ちなみに`col`として与えた値はベクトルで

```
> ifelse(1:length(v) %% 2 == 1, "red", "blue")
[1] "red"  "blue" "red"  "blue" "red"  "blue"
```
次のようにより短く書いてもよい。

```r
> plot(v, col = c("red","blue"))
```
iPhoneXかどうか

iPhoneX と その他の識別のコード。備忘録ですね。

```Objective-C

NSMutableDictionary *options;
struct utsname systemInfo;
uname(&systemInfo);
NSString* code = [NSString stringWithCString:systemInfo.machine
                                        encoding:NSUTF8StringEncoding];
BOOL sim_iPhoneX = ([code isEqualToString:@"x86_64"] && MAX([[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height) == 812);
if ([code isEqualToString:@"iPhone10,3"] || [code isEqualToString:@"iPhone10,6"] || sim_iPhoneX ) {
} else {
};
```

```Swift
var size : Int = 0
sysctlbyname("hw.machine", nil, &size, nil, 0)
var machine = [CChar](repeating: 0, count: Int(size))
sysctlbyname("hw.machine", &machine, &size, nil, 0)
let code:String = String(cString:machine)
let sim_iPhoneX = (code == "x86_64" && max(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height) == 812)
if (code == "iPhone10,3" || code == "iPhone10,6" && sim_iPhoneX) {
} else {
}
```

な、感じかなー。どっちも sys/utsname.h あたりはインポートする必要あるかもだけど。
iPad > GoodReader 3 > ブックマークは移行されない (ソフト、プラットフォーム独自機能)

```txt:動作環境
iPad mini4
GoodReader 3
```

iOSがv11になる時、32ビットアプリケーションは動作しなくなるとのこと。

GoodReader 3で資料を読んできたが、後継ソフトに移行しないといけない。

PDF Viewer(by PSPDFKit)が後継ソフト候補である。

GoodReader 3のブックマークは移行できないようだ。ハイライトや図形マーキングが移行できるだけましかもしれない。

ソフト（プラットフォーム）独自の機能を使うと、データ移行時に情報が消失する。
独自機能は使わないようにしようと最近は思っている。

- <details><summary>この機能はプラットフォーム独自の機能です。</summary>別のプラットフォームに移行する時は、マークダウンで書き直してください。</details>
よく使うXpath

私が最近よく使うXpathについて話す。
Xpathを理解するとプログラミング言語並みに色々できることがわかったので知見を共有します。
サンプルのXpathのデモに使うページは[ここ](https://www.itandi.co.jp/)

---

# 集合操作・検索

---

### ()

xpathの結果をそのまま変数として扱う

```
//a[text() = (//*[@id="service-index"]/div[4]/div/div/div/div[2]/div[1]/a/text())]/text()
```

---

### contains(arg1, arg2)

arg2の文字列を含むarg1の集合を返す

```
//*[contains(@class, 'is-text')]
```

---

### following-sibiling::

現ノードに対し兄弟関係にあるノードの弟を返す

```
//*[@id="news-index"]/div[1]/div[1]/ul/li[2]/a/span/i/following-sibling::node()
```

---

### position()

現ノードの集合における、親ノードからみた順番で範囲選択する

```
(//*[@id="news_all"]//div[contains(@class, 'title')]/a)[position() >= 2]
```

---

## 文字列操作

---

### concat(arg1, arg2, ..., argn, ...)

引数の文字列を連結する

```
concat(//*[@class = 'nav-item'][1]/text(), //*[@class = 'nav-item'][2]/text())
```

---

### normalize-space(arg)

文字列引数の前後に含まれる空白文字をトリムする

```
normalize-space(concat(//*[@class = 'nav-item'][1]/text(), //*[@class = 'nav-item'][2]/text()))
```

---

### translate(arg1, arg2, arg3)

arg2に渡された文字をarg3に変換されたarg1を返す

```
translate(normalize-space((//*[@id="news_all"]//div[contains(@class, 'title')]/a)[position() = 1]), 'CTO', 'CEO')
```

---

### substring-before(arg1, arg2) substring-after(arg1, arg2)

arg2で分割された前後のarg1を返す

```
substring-before(normalize-space((//*[@id="news_all"]//div[contains(@class, 'title')]/a)[position() = 2]), '、')
```

```
substring-after(normalize-space((//*[@id="news_all"]//div[contains(@class, 'title')]/a)[position() = 2]), '、')
```

---

## 論理演算

---

### and

論理積の条件にあったノードの集合を返す

```
//*[@class = 'nav-item' and contains(text(), 'ニュース')]
```

---

### or

論理和の条件にあったノードの集合を返す

```
//*[contains(@class, 'is-text') or contains(@class, 'nav-item')]
```

---

### not()

条件式の否定に沿ったノードの集合を返す

```
//*[@class = 'nav-item' and not(contains(text(), 'ニュース'))]
```

---

## appendix

[ここ見れば大体載ってる](https://sites.google.com/site/shin1ogawa/xsl/xpath)
【R】ファイルの読み込み

##はじめに
「Rがデータファイルを読み込んでくれません」という相談を受けたので覚書き。

##ファイル種類別の読み込み方
###tsv（tab区切りテキスト）

```R:
x <- read.table("hoge.tsv",sep="\t")  
```
###csv（カンマ区切りテキスト）

```R:
x <- read.csv("hoge.csv")  
```
または

```R:
x <- read.table("hoge.csv",sep=",")  
```

###Excelで作ったデータの読み込み
ファイル >別名で保存 > カンマ区切り形式（.csv）

```R:
x <- read.csv("hoge.csv")  
```
または

```R:
x <- read.table("hoge.csv",sep=",")  
```

MacだとExcelで保存すると改行コードがCRになるけど、改行コードとか気にせず読み込んでくれるようです。

###rtf（リッチテキストフォーマット）
[unrtfパッケージ](https://cran.r-project.org/web/packages/unrtf/index.html)を使うらしい。(要確認)  

```R:read_rtf.r
library(unrtf)
x <- unrtf("hoge.rtf",format="text")
```
標準テキストに変換したほうが早いんじゃないか…というのはちょっとおいといて。

##おわりにひとこと
要確認のところはたぶん追記する。
数値は数値として、文字列は文字列として、読み込んでもらうことってはじめはわりと苦労する。逆に、希望通りに読み込ませてしまえばあとは楽なのよねー。
DataGridViewでチェックチェックボックスにチェックが付けられた（あるいはチェックが外された）ことを知ろうと思ったら例外が出たお話し

#発端→解決
DataGridViewでチェックが変更されたのを知りたい。
↓
ググって発見。
DataGridViewの列にチェックボックスを表示する  .NET Tips  C#, VB.NET
・チェックボックスにチェックが付けられた（あるいはチェックが外された）ことを知る
https://dobon.net/vb/dotnet/datagridview/datagridviewcheckboxcolumn.html#section3
↓
スペースキーでチェックボックスの値を変えると例外が出る。
↓
ググって発見。デリゲートでCommitEditを遅延させる必要があるらしい。
https://connect.microsoft.com/VisualStudio/feedback/details/780347/nullreferenceexception-in-notifymassclient-after-checking-unchecking-a-checkbox-in-datagridview-with-spacebar
↓
C#だったのでVB.NETへ変換。

```
Delegate Sub InvokeDelegate()

Private Sub MyDelegate()
    Me.DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)
End Sub

Private Sub DataGridView1_CurrentCellDirtyStateChanged(ByVal _sender As Object, ByVal _e As EventArgs)
    If Me.DataGridView1.CurrentCellAddress.X = 0 AndAlso
       Me.DataGridView1.IsCurrentCellDirty Then
        'コミットする
        BeginInvoke(New InvokeDelegate(AddressOf MyDelegate))
    End If
End Sub
```
MAXscriptでテキストにprintの内容を書き出す



※バージョンは2015を使用しています。

# テキストにprintの内容を書き出す

```
createFileName = maxFilePath + "text.txt" --<filename_string>

if (doesFileExist createFileName) == true then (print "同名のファイルがあります")
else(
	print "同名のファイルが無いのでファイル作成及び出力をします"
	createFileStream = createFile createFileName --<filestream>
	print "aaa" to:createFileStream
	close createFileStream
)
```

分かりにくかった点として、
`<filename_string>`と`<filestream>`は別モノだということ。
`print "aaa" to:<filename_string>` にするとエラーになってしまう。
あと、ファイルを扱う時の基本として、
`close`でちゃんとファイルを閉じてやらないと、3DSMAXがずっとファイルを握っていてコントロールできなくなるので注意です。

***
WordpressプラグインBuddyPressのメールがSMTP経由で届かなかった時の対処法

## やりたかったこと

WordpressプラグインBuddyPressを使って会員制サイトを構築しているサイトで、XserverからAWSへサーバー移行を行い、メールサーバはそのままxserverのメールサーバを使用したかった。

要約するとWordpressで外部のメールサーバを使ってメールを送りたかった。
しかし、SMTPの設定をしてもBuddyPressでユーザー登録を行なったメールが送られてこなかったので、調査した。

## 目次

1. WordpressプラグインのWP MAIL SMTPをインストール
2. WP MAIL SMTPの設定
3. BuddyPressでメールが届かない


## 1. WordpressプラグインのWP MAIL SMTPをインストール

外部のメールサーバを使うため、SMTPの設定を行う必要があるので[WP MAIL SMTP](https://ja.wordpress.org/plugins/wp-mail-smtp/)をインストールする。

インストール方法はふた通りあって、以下の方法。私の環境では前者がエラーで出来なかったので、後者の方法でインストールした。

* 管理画面からプラグインの追加で、「WP MAIL SMTP」でインストールする。
* プラグインのページよりダウンロードして、サーバー内の`plugins`フォルダにアップロードする

後者の方法をもう少し詳しく解説すると、[WP MAIL SMTP](https://ja.wordpress.org/plugins/wp-mail-smtp/)こちらのページより「Download」をクリックして、フォルダ一式ダウンロードしたら、`wp-content/plugins`ディレクトリ内に配置する。

上記を行ったらあとは同様の方法でインストール済みプラグインより該当プラグインを有効化する。

## 2. WP MAIL SMTPの設定

上記でプラグインを有効化したら、SMTPの設定を行う。
Wordpressの管理画面より、「設定」→「メール」にてSMTPの設定を行う。
SMTPの設定に関しては、xserverの管理画面よりメールアカウント設定の情報と[こちら](https://www.xserver.ne.jp/manual/man_mail_setting.php)を照らし合わせて設定する。

設定例：

項目 | 値
---- | ---
From Email | xserverで設定したメールアドレス
From Name | テストユーザー
メーラー | WordPressの全てのメールをSMTP経由で送信する。
SMTP Host | hoge.xserver.jp
SMTP Port | 465
Encryption | SSLを使用する（適宜環境に合わせてください）
Authentication | はい: SMTP認証を使用します。
Username | xserverで設定したメールアドレス
Password | xserverで設定したパスワード

最後に「メール詳細設定」ページ下部のテストメール送信でメールが送信できていれば、設定は完了。
もしメールが来なければ、設定がどこか間違っているので、再度見直してみてください。

## 3. BuddyPressでメールが届かない

3章でやっと本題なのだけれど、上記でSMTPの設定も終えているので、Wordpressから送信されてくるメールは全てSMTP経由でメールが送られてくるはず...だった。
だけど、メールが来なかった。

解決方法は以下
管理画面より、
1. 「ツール」メニュークリック
2. 「BuddyPress」メニュークリック
3. 「Reinstall emails (delete and restore from defaults).
」の項目にチェックをいれる
4. 「項目を修復」ボタンを押す
以上ので出来た。
設計 > SDKありとSDKなしでの実装

```txt:動作環境
RS-232Cが使える環境
```

### 関連

[組込みプログラミング > エミュレータを作る利点と欠点](https://qiita.com/7of9/items/39dc4fa39a860dbaf2d1)

### 背景

- とある装置がある
- とある通信interface(例: RS-232C)で通信する
- その装置との通信用SDKが提供されている
    - 対応OSは決まっている

とある装置のエミュレータを作ったのは2年くらい前だった。
その後、PC上でSDKを使った通信ソフトのデバッグにそのエミュレータが活躍してきた(数百時間くらい)。

### 変更 > SDKを使わない

「SDKなしで通信できたらXXXできるのに」という一言から始まった。

エミュレータがあったので、エミュレータと通信しながら、SDKなしの通信ソフトを実装した。
装置の実機もあるので、その後に実機を使って動作確認も終わった。

### SDKを使わない

SDKを使った場合、以下の事項が気になる。

- OSのバージョンアップ時にSDKはそのまま使えるか
    - XPから7になったので対応できません、という実例は、とある会社の製品であった
        - それを残念がるユーザの言葉が強く印象に残った
    - ソフトのEOL (End of Life)を規定する
- SDKを使えるOS上でしか動かない
    - ESP8266やRaspberry Piでは使えない
- 付随情報の通信を行うことにより、処理時間がかかる
    - 例:20秒(SDKあり), 1秒(SDKなし)
- 一度に1対1通信しかできない (1対N同時通信ができない)
    - SDKでインスタンス変数ではなく、static変数を使っているようだ


アスキー通信の場合は通信内容から推測ができるかもしれない。
バイナリ通信では解析が成功しないとSDKを使うことになる。

状況に合わせてSDKあり、SDKなしを検討するのはいいかもしれない。

独自機能に依存した通信の場合はSDKなしでの利点は少ないかもしれない。
Android Studioで別のOpenJDKプロバイダーによるJDKを使用する

### Android Studioのプロジェクトビルドに用いられるJDKについて
Android Studio 2.2以降には、**OpenJDK**と呼ばれるJava開発環境が同梱されています。デフォルトでは、作成したAndroidアプリケーションプロジェクトは、このOpenJDKによってビルドされます。しかし、このOpenJDKでなければビルドが通らないような特別な仕組みが存在するわけではありません。**[Oracle JDK](https://www.oracle.com/technetwork/java/index.html)**はもちろんのこと、**[AdoptOpenJDK](https://adoptopenjdk.net/)**、**[Azul Zulu](https://www.azul.com/products/zulu-enterprise/)**、**[Amazon Corretto](https://aws.amazon.com/jp/corretto/)**などの別のOpenJDKプロバイダーによるJDKを用いることも可能です。

### 設定方法
自分でインストールしたJDKをビルドに使用するには、次のように操作します。

- スタート画面の右下にある`Configure`→`Project Defaults`→`Project Structure`と選択して、設定画面を出します。
- `Use embedded JDK`のチェックを外して、その下のテキストボックスにJDKの場所を入力します。右側の`…`ボタンでダイアログから選択することもできます。

Azul ZuluのOpenJDK 8u202ビルド（64bit版）のzipファイルをダウンロードし、`C:\opt`の下に展開すると、`C:\opt\zulu8.36.0.1-ca-jdk8.0.202-win_x64`というフォルダーが作成されます。このフォルダーを上記の操作で指定すると、**図1**のようになります。

|![図1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53988/37761a0c-8f85-a965-d3e7-ee695f168282.png)|
|:--|
|**図1**|

#### Windowsならばジャンクションを活用しよう
**図1**のような設定だと、JDKがアップデートされる度に設定を変更しなくてはなりませんが、WindowsならばOSが標準で備えている**ジャンクション**という機能を活用することで、Android Studio側の設定を操作することなく、JDKのバージョンを改めることができます。

先のAzul Zuluの例で展開されたフォルダーへのジャンクションを作成するには、コマンドプロンプトで次のように操作します。

```
C:\opt>mklink /j jdk8 C:\opt\zulu8.36.0.1-ca-jdk8.0.202-win_x64
```

これで、`C:\opt\jdk8`というジャンクションが、`C:\opt\zulu8.36.0.1-ca-jdk8.0.202-win_x64`と同じ場所を示すようになります。この後、Android StudioのJDK locationとして`C:\opt\jdk8`を設定することで、先の設定例と同様に動作させることができます。

#### ジャンクションの貼り替え
JDKを更新したら、ジャンクションのみを貼り替えます。上書きはできないので、rmdirコマンド（エクスプローラーで削除しても良い）で削除してから、新しいジャンクションを作成します。

```
C:\opt>rmdir jdk8
C:\opt>mklink /j jdk8 <新しいJDKへのパス>
```

これで貼り替えは完了です。

### JDK 11を利用することは可能？
同じ方法でJDK 11へのパスを設定して新規プロジェクトを作成すると、**図2**のようにエラーが発生します。

|![図2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53988/429ec03b-59e2-ed51-5dd4-81a176531dee.png)|
|:--|
|**図2**|

これは、スタート画面右下の`Configure`→`Settings`で設定画面を開き、左ペインのツリーから`Experimental`を選択して、`Only sync the active variant`のチェックを外すことで回避できるようです（**図3**）。ただ、Experimental（実験的）であることは踏まえておく必要がありそうです。

|![図3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53988/17b172eb-2888-ac28-6331-3c85feac4e87.png)|
|:--|
|**図3**|
SmartGit > リポジトリ > Removeできる条件 > 非アクティブ or Closed

```txt:動作環境
Windows 7 Pro (32bit)
SmartGit Version 17.0.4 #10132
```

ローカルのリポジトリ削除方法が分からなかった。

### Reporitoesペイン

こちらのペインに表示されているリポジトリ上にて右クリックしても「Remove」が選択できない。

該当のリポジトリはボールド表示になっている。

### Removeの使用可能条件

以下のいずれかの条件でRemoveが使えるようだ。

- 該当のリポジトリがアクティブでない
- 該当のリポジトリをCloseした状態
    - リポジトリ上で右クリック、Close選択

アクティブ状態でも削除できるようにするツールもある。
UIとしてはどちらが分かりやすいだろうか。

アクティブ状態でもRenameはできるので、UI設計としてはアンバランスに感じる。
Office 365 サインインページの「サインインしたままにする」チェックボックスの表示/非表示を切り替える

#概要
Office365 のサインイン画面に表示される「サインインしたままにする」のチェックボックスは、AzureActiveDirectory の管理画面から表示/非表示の切替が可能です。
本記事では、既定では表示されている「サインインしたままにする」のチェックボックスを非表示にする手順をご紹介します。

＜既定のサインインページ＞
![image.png](https://qiita-image-store.s3.amazonaws.com/0/208403/c56f8ff8-f883-03c5-7827-a39dde38690f.png)


※なお、この手順により「サインインしたままにする」以外のサインインページの表示オプションについても変更することが可能です。変更可能なオプションは以下です。
- バナーロゴ
- サインインページ テキスト
- ユーザー名のヒント
- サインインページ の画像
- サインインしたままにする表示オプション
➡それぞれの詳細については必要に応じて公開情報を参照ください。
https://docs.microsoft.com/ja-jp/azure/active-directory/customize-branding

#用意するもの
- Office 365 テナント
- 全体管理者権限を持ったユーザー

#変更手順
１．Office365 に全体管理者のアカウントでサインインします。 

２．Office365のアプリランチャーから[管理者]を開きます。

３．[管理センター]から[Azure AD]を開きます。
　　　![image.png](https://qiita-image-store.s3.amazonaws.com/0/208403/117ef5d5-ffe7-cf6a-4366-b657047f2740.png)

４．画面左のメニューから[Azure Active Directory]をクリックします。
　　　![image.png](https://qiita-image-store.s3.amazonaws.com/0/208403/fac77984-58d3-e8ba-eef7-1d9394843a46.png)

５． [管理]メニューから[会社のブランド]を選択し[編集]クリックします。
　　　![image.png](https://qiita-image-store.s3.amazonaws.com/0/208403/15b5266c-6623-a3d1-c16f-5591a90cacf0.png)

６． 編集画面下部の[サインインしたままにするオプションを表示する]で[いいえ]を選択して[保存]をクリックします。
※チェックボックスを表示する場合は「はい」を選択します。
　　　![image.png](https://qiita-image-store.s3.amazonaws.com/0/208403/c4c3fb8e-9b21-9eab-0870-ab77faf877c3.png)


手順は以上となります。
一度Office 365 からサインアウトし、再度サインインすると以下のようにチェックボックスが非表示になります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/208403/73677573-91d5-b5c2-d279-7943996c0018.png)


#補足
これらのオプションはOffice 365 テナント上に存在する”ドメイン毎”での設定が可能です。
※ユーザー単位での設定は出来ませんのでご注意ください。
過去のiOS beta版の配信スケジュール

社内の新OS対応にあたり、過去のiOSリリーススケジュールを整理したので共有します。

# 過去のOSリリース日[^1] (iOS 8〜15)

| iOS | beta1 | beta2 | beta3 | beta4 | beta5 | beta6 | beta7 | beta8 | beta9 | beta10 | beta11 | beta12 | GM, RC | 正式リリース |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| __8__ | 6/2 | 6/17 | 7/7 | 7/21 | 8/4 | 8/19 | - | - | - | - | - | - |  9/9 | __2014/9/17__ |
| __9__ | 6/8 | 6/23 | 7/9 | 7/22 | 8/6 | - | - | - | - | - | - | - | 9/9 | __2015/9/16__ | 
| __10__ | 6/13 | 7/5 | 7/18 | 8/1 | 8/9 | 8/15 | 8/19 | 8/26 | - | - | - | - | 9/7 | __2016/9/13__ | 
| __11__ | 6/5 | 6/21 | 7/10 | 7/24 | 8/7 | 8/14 | 8/21 | 8/28 | 8/31 | 9/6 | - | - | 9/12 | __2017/9/19__ | 
| __12__ | 6/4 | 6/19 | 7/4 | 7/18 | 7/30 | 8/6 | 8/13 | 8/15 | 8/20 | 8/23 | 8/27 | 8/31 | 9/12 | __2018/9/17__ | 
| __13__ | 6/3 | 6/17 | 7/8 | 7/18 | 7/29 | 8/7 | 8/15 | 8/21 | - | - | - | - | 9/10 | __2019/9/24__ |
| __14__ | 6/22 | 7/7 | 7/22 | 8/4 | 8/19 | 8/25 | 9/4 | 9/10 | - | - | - | - | 9/16 | __2020/9/17__ |
| __15__ | 6/7 | 6/24 (beta 2.1: 6/30) | 7/14 | 7/27 | 8/10 | 8/17 | 8/25 | 8/31 | - | - | - | - | 9/14 | __2021/9/20__ |
| __16__ | 6/6 | 6/22 | 7/6 | 7/27 | 8/8 | 8/15 | 8/23 | 8/29 | - | - | - | - | 9/7 | __2022/9/12__ |
| __17__ | 6/5 | 6/21 | 7/5 | 7/25 | 8/8 | 8/16 | 8/22 | 8/29 | - | - | - | - | 9/12 | __2023/9/18__ |

通例、新OSのbeta 1はWWDCの開催時に配信開始される。

## ソース
https://en.wikipedia.org/wiki/IOS_version_history
https://betawiki.net/wiki/Main_Page
https://www.theiphonewiki.com/wiki/Timeline
https://github.com/uupaa/WebKitChangeLog/wiki/VersionTable
https://apple.fandom.com/wiki/
https://9to5mac.com/
など

[^1]: 日付は現地時間です
PHPで有効期限判定

# PHPで有効期限判定

## DateTimeの場合

```
$datetime = new DateTime('2017-10-20 00:00:00');// 登録・更新日時等
$datetime->add(new DateInterval('P10D'));// 10日後まで有効
$current_datetime = new DateTime(date('Y-m-d H:i:s'));// 現在時刻

$expired_flag = $datetime < $current_datetime;// 期限切れか
$expire_datetime_string = $datetime->format('Y-m-d H:i:s');// 期限が切れる日（'2017-10-30 00:00:00'）
```

## DateTimeImmutableの場合

```
$datetime = new DateTimeImmutable('2017-10-20 00:00:00');// 登録・更新日時等
$expire_datetime = $datetime->add(new DateInterval('P10D'));// 10日後まで有効
$current_datetime = new DateTimeImmutable(date('Y-m-d H:i:s'));// 現在時刻

$expired_flag = $expire_datetime < $current_datetime;// 期限切れか
$expire_datetime_string = $expire_datetime->format('Y-m-d H:i:s');// 期限が切れる日（'2017-10-30 00:00:00'）
```

`$datetime`は操作されないので`$expire_datetime`という変数を使用して比較している。（別のオブジェクトを返しているので変数に保持）

**DateTimeImmutableの方がそれ自体は操作しないで別のオブジェクトを返すので変数名に困らなくなるので良いかもしれません。**

例)

```
$today_datetime = new DateTime('2017-10-20 00:00:00');
$today_datetime->add(new DateInterval('P10D'));
```

これだと

$today_datetimeが10日後になっているのでtodayではなくなってしまう。

### 補足

パース出来る文字列かどうか判定するには`date_create()`か`strtotime()`を使って判定できます。共に失敗時にfalseを返します。

http://php.net/manual/ja/datetime.formats.php

### 参考

http://php.net/manual/ja/datetime.construct.php
http://php.net/manual/ja/class.dateinterval.php
http://php.net/manual/ja/dateinterval.construct.php
https://en.wikipedia.org/wiki/ISO_8601#Durations

http://php.net/manual/ja/class.datetimeimmutable.php
MacBook Pro (2017)でnvidia eGPUディープラーニングを始めるまでの道のり


深層学習用PCの発注手続きを進めているが、納品まで数ヶ月かかるという。まってられないのでなんとか手持ちの戦力でGPUディープラーニングができないかと試行錯誤した結果を記しておく。

#用意したもの
##Sonnet Breakaway box
thunderbolt 3で外付けGPU(eGPU)を実現する。
##nvidia　gtx1080ti
上述のbreakaway box では8pin+6pinまでしか対応していないので該当するモデルを探すのに少し苦労した（8pin+8pinのものが多い）。最終的に[玄人志向](http://www.kuroutoshikou.com/product/graphics_bord/nvidia/gk-gtx1080ti-e11gb_white/)のものを購入した。
##MacBook Pro(2017)
2017年10月中旬購入。幸いにもhigh sierraが入っていなかった。後述する理由でsierraでなければ駄目。
##macOS Sierra 10.12.6
間違ってもhigh sierraにしないこと。2017年10月20日時点で
>CUDA Application Support:
In order to run macOS Applications that leverage the CUDA architecture of certain NVIDIA graphics cards, users will need to download and install a compatible CUDA driver. A CUDA driver which supports macOS High Sierra 10.13 will be available at a later date.
[nvidia](http://www.nvidia.com/download/driverResults.aspx/125379/en-us)

cudaドライバがhigh sierraに対応していないので接続できても使えませんとのこと。

#使いたいディープラーニングフレームワーク
##tensorflow(+ Keras)
macがnvidia gpuを公式にサポートしていないのでtensorflowが対応を打ち切ってしまった。
pip install tensorflow-gpuでインストール可能な最新版はver1.1.0

#接続云々
breakaway boxの[マニュアル](http://www.sonnettech.com/support/kb/kb.php?cat=524&expand=_a1&action=b919#b919)を見ながら接続、ドライバインストールを行う。

*マニュアルにしたがってセットアップを進めていくと、最新版のcuda(+cuDNN)のインストールを指示される。フレームワークが要求するバージョンを入れる必要がある。

tensorflow-gpu(v1.1.0)はCUDA8.0を要求する。現時点での最新版は9.0なので、brew cask install cudaとかすると後者がインストールされるので駄目。cuda toolkit8.0をホームページから探してきて入れる。今回は8.0.61(v5.0)をインストールした。対応するcuDNNはcuDNN-8.0 v5.0。v5.1もあるが、対応をとらないとtensorflowの実行でエラーをはく。


ワンダフルgpuディープラーニング環境！
![IMG_1442.JPG](https://qiita-image-store.s3.amazonaws.com/0/156483/0b7a3fd7-fda0-65ce-ae58-d2503dbb3423.jpeg "IMG_1442.JPG")

![IMG_8052.JPG](https://qiita-image-store.s3.amazonaws.com/0/156483/653d5b89-d7bc-f919-c0d2-749a8a06a617.jpeg "IMG_8052.JPG")
java9のお勉強(dropWhileとtakeWhileとStream.ofNullable）

ということで件名の内容を書こうと思うのですが
[こちらの素晴らしい投稿](https://qiita.com/k--kato/items/64967d2555f39aace608)がとてもわかり易いので、何か今更投稿することもない気がしてきました。

とりあえず軽くやってみました。

```
		List<String> list = Arrays.asList("AA", "BB", "C", "DD", "E", "FGH");
		List<String> list2 = Arrays.asList("A", "B", "C", "DD", "E", "FGH");

		System.out.println("とりあえず何も考えずに出す");
		list.stream().forEach(System.out::print);


		System.out.println("\n2文字以上のものはスキップしてから出す");
		list.stream().dropWhile(str -> str.length() >= 2).forEach(System.out::print);

		System.out.println("\nlist2は最初が1文字から始まってからこいつに適用しても結果として何も変わらない");
		list2.stream().dropWhile(str -> str.length() >= 2).forEach(System.out::print);
```

実行結果

```
とりあえず何も考えずに出す
AABBCDDEFGH
2文字以上のものはスキップしてから出す
CDDEFGH
list2は最初が1文字から始まってからこいつに適用しても結果として何も変わらない
ABCDDEFGH
```

ポイントはdropWhileであってフィルターではないってところですかね。
自分で書いてみるまでは一番最後の

```
list2.stream().dropWhile(str -> str.length() >= 2).forEach(System.out::print);
```
は2文字以上の要素を全部除去してくれるのでABCEって出るものと思い込んでいたのですが、結果が違ったので何だろって思ったけど
list2を最初から読み込んでいって2文字以上のやつが出ている間は読み飛ばすぜっていうメソッドなので、最初の要素Aの段階ですでに2文字以上ではないから何もdropされなかったのは今思うと自然。

使い方は似た感じですがtakeWhileもやってみました。

```
		System.out.println("\ntakeWhileも似たような感じ");
		list.stream().takeWhile(str -> str.length() >= 2).forEach(System.out::print);
```

実行結果

```
takeWhileも似たような感じ
AABB
```

今回のラストはStream.ofNullable。

```
		/* Stream.ofNullableやるよ */
		List<String> list3 = Arrays.asList("A", "B", null, "DD", "E", "FGH");
		System.out.println("\n文字サイズ出します");
		// Stream.ofNullableしない例
		try {
			list3.stream().forEach(str -> System.out.println(str.length()));
		} catch (NullPointerException nullpo) {
			System.out.println("想定通りぬるぽ！");
		}

		// Stream.ofNullableする例（なお、Stream.ofNullable(str)をStream.ofNullable(str.length())とかやったら
		// ぬるぽで落ちます。あくまでofNullableの引数がNULLだったら飛ばすってだけなので。
		list3.stream().flatMap(str -> Stream.ofNullable(str)).forEach(str -> System.out.println(str.length()));

```

実行結果

```
文字サイズ出します
1
1
想定通りぬるぽ！
1
1
2
1
3
```


forEachのところで使いたい変数がNULLだったら飛ばすぜみたいに出来るので便利そうに見えるけど
いちいちflatMapとか書くの面倒だしそんなに使い勝手いいかって言うと・・・。
あと今回かなり適当な例ですが、実際は冒頭に書いた参考記事の例のようにMapから値が取れなかった場合に使ったりするほうがおそらく実際に使われると思います。
MySQLのUsingを雑に調べた

# TL;DR

たまたまみかけたSQLで`USING(hoge_id)`という記述をみて「そういえば`USING`使ったことないな？」と思ったので雑に調べてみた。

# 結論

`USING`は`FROM [テーブル名A] JOIN　[テーブル名B] ON [テーブル名A].id = [テーブル名B].id`とだいたい等価。
違いがあるとするなら`USING`を使うときは両方のテーブルに同じ名前のカラム(上の例だと`id`)が存在している必要があるということだろうか？

なので`[テーブル名A].id=[テーブル名B].a_id`とかだと`USING`は使えない…ということでいいのかな。

# 参考

- [MySQLのJOIN構文で、USINGを利用した場合のメリット、デメリットはなんでしょうか](http://q.hatena.ne.jp/1296183535)
    - 質問自体が古いが最近増えたものでも変更があったものでもないという認識なので問題ないだろう。

# あとがき

JOIN ONで書くのに比べて簡単に表現できるのでメリットはありつつもUSINGとONが混在すると妙な気持ち悪さを感じる。
そもそも入り混じって気持ち悪いSQLになってるのは設計が悪いというだけの話しなのかもしれないが。

ぼくがUSINGを使うとしたら中間テーブルを経由して多対多の関係性を解消するときに限定するかな…という気持ちになった。
冗長だけどなにやってるかわかりにくいSQLを書くよりはマシなのかなと考えている。
Firebase Cloud Messaging(FCM)でブラウザにWebPush通知

# はじめに
https://firebase.google.com/docs/cloud-messaging/js/client?hl=ja
まず全部見て、同じ様にやってみよう。

# できない
メッセージが届かない。

Unauthorized

Error 401

Invalid (legacy) Server-key delivered or Sender is not authorized to perform request.

# これじゃない
原因はこれ。
![222.png](https://qiita-image-store.s3.amazonaws.com/0/116531/738074bb-0e15-feee-6d48-8fc7ce88d6e1.png)

動画だとapikeyってこれだと思うじゃないですか。

本当は・・・
![111.png](https://qiita-image-store.s3.amazonaws.com/0/116531/e673cd8a-862d-6c6d-60b6-1454edb5f771.png)

プロジェクトの設定>クラウドメッセージング>

![333.png](https://qiita-image-store.s3.amazonaws.com/0/116531/258bf204-a246-9b11-fd35-5b61663c9f00.png)

もうちょっと親切に教えてください。


↓ここ参考
https://stackoverflow.com/questions/37633188/firebase-401-unauthorized-error-fcm
OpenCVで連番付き静止画をビデオリソースとして扱う

[Visual Tracker Benchmark](http://cvlab.hanyang.ac.kr/tracker_benchmark/datasets.html)に物体追跡用のベンチマークデータがあるが、このデータの実体は連番付きの静止画である。

openCVの VideoCapture メソッドは多機能で、カメラデバイスがあるならカメラから、引数に動画ファイルを与えればその動画ファイルから、そして、連番静止画であれば、次のようにして一連の静止画が動画であるかのように振舞ってくれる。

とても便利

```python
import cv2
import numpy as np
from PIL import Image
import sys

# 4桁連番の jpeg 画像をビデオであるかのように読み込み表示
cap = cv2.VideoCapture('Coupon/img/%04d.jpg')

while True:
    try:
        ok, frame = cap.read()
        cv2.imshow("src",frame)
        if cv2.waitKey(10) == ord('q'):break
    except:
        break
cv2.destroyAllWindows()
cv2.waitKey(1)
```
F5 BIG-IPのiRule LXでnode.jsが使えるらしいので、まずはHello Worldから(ぱーと１)

# iRule LXについて
[iRule LX](https://cloud.watch.impress.co.jp/docs/news/758823.html)
> BIG-IP 12.1では、iRules LXのプログラマビリティを強化。Node.js経由でサービスを操作して、選択的に展開することを可能にするとともに、コミュニティからの25万件を超えるNode.jsパッケージに容易にアクセスする能力を提供する。また、CA、Google、IBM、Oracle、Red Hat、SAPなど、他のエンタープライズテクノロジーベンダーが一般にサポートするEclipse Integrated Development Environment（IDE）向けの新しいプラグインにより、高度な機能を担う再利用可能なコードを、迅速に調達できるとしている。

# とりあえず環境準備！BIG-IPを用意から
と思ったのですが、どうしたらよいのか、、、、、
調べてみるとAWS上で簡単に動かせるらしいので、今回はそれで環境準備しみることにしました。

GitHubでBIG-IP用のAWS CloudFormationテンプレートを公開されているので、それを利用していきます。

https://github.com/F5Networks/f5-aws-cloudformation
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131001/7532a17e-2c51-114e-a1cb-9deddd3b1ea6.png)
個人でやるのでライセンス買うお金はもちろんないので、「Standalone .... Single NIC」の「Hourly」を選択
※ 1台で、1(EIP)で、従量課金みたいな感じらしいです。
※ BYOLはライセンス持ってないので、また今度(F5のホームページで1カ月フリーライセンスが発行できるみたい)


クリックすると、AWSのCloudFormationに飛んでくるので、そのまま「次へ」
リージョンがバージニア北部に勝手になってたけど無視して次へ。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131001/410bb7c9-3282-9d83-0ad8-634a04bdd72c.png)


パラメータ入れないといけないのね、、


![image.png](https://qiita-image-store.s3.amazonaws.com/0/131001/7de177ec-07f9-55a3-797c-2b11fa4b9c2b.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131001/867ef286-d8d9-6005-327c-946067ed1946.png)

| 項目                     |                                                内容 | 
|:-------------------------|:----------------------------------------------------|
| VPC                      | 事前に作ったVPCを選択 |
| Subnet1 in AZ1           | BIG-IP用サブネットも作っといたのでそれを選択 |
|BIG-IP Image Name         | 一番安そうな Good25Mbpsを選択　 <br> (Good/Better/Bestで使える機能が違う)<br>(25Mbps/200Mbs/1Gbps/これはスループット制限みたい)  |
| SSH Key                  | これは自分のキーペアを選択 |
| Source Address for Management Access | 0.0.0.0/0 <br>(管理画面のアクセス制限みたい。とりあえず制限なし)|
| Source Address for Application Access| 0.0.0.0/0 <br>(サービス用かな、アプリケーション用アクセス制限みたい。とりあえず制限なし) |


AWS Marketplaceで調べると対応表があったので見てみると、だいたいこれくらいなら今月のお小遣いでいける！
[AWS Marketplace F5 BIG-IP Good25Mbps](https://aws.amazon.com/marketplace/pp/B00JL3UASY?qid=1508462727264&sr=0-6&ref_=srh_res_product_title)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131001/05f47021-f8b4-4556-ef4f-ba1e0c886322.png)

あとは「次へ」で「作成」やっ！！　

15分くらいしたら、、、「CREATE_COMPLETE」や！

![image.png](https://qiita-image-store.s3.amazonaws.com/0/131001/f3f19c77-0958-637f-3917-d58e34a55de4.png)

さっそく「BIG-IP Management GUI」とやらにアクセスしてみます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131001/2a891214-b681-aa96-5da2-565fd32fec05.png)

とりあえずOKそう。。。。。
一旦休憩して、次はやっとnode.jsできるぞー！
[F5 BIG-IPのiRule LXでnode.jsが使えるらしいので、まずはHello Worldから(ぱーと２)](https://qiita.com/Mi-wa/private/9b157f5ea6167696dc12)
java9のお勉強(jShell)

少しはjava9もやるかってことで簡単そうなjShellから

以下、windows上でdosプロンプトを上げてJAVA_HOMEの下のbinフォルダに移動(cd)してから実行。
（環境変数でPATH通してれば移動するまでもないけど）

```
C:\Program Files\Java\jdk-9\bin>jshell.exe
|  JShellへようこそ -- バージョン9
|  概要については、次を入力してください: /help intro

jshell> String regex = "^Hello";
regex ==> "^Hello"

jshell> Pattern p = Pattern.compile(regex);
p ==> ^Hello

jshell> p.matcher("Hello World").find();
$3 ==> true

jshell> p.matcher("hello World").find();
$4 ==> false

jshell>

```

なお、終了させたい時は/exitって打つらしい。

Eclipse等のIDE入れてれば簡易な検証ってすぐできちゃうからありがたみは微妙だけど、
Java初めてやりますちょっと動かしてみたいですとか
Eclipse入れれてない環境ですとか
サーバ上で動くシェルとかでシェルだけでゴリゴリ書くよりJavaのAPI呼ぶと楽なケースがあるんだけどなあ
とかそういう時にいいのかなって思いました。
変数定義しただけでなんか出力されたのは「おおっ」って思いました。
chrootされたSFTP専用ユーザのFTP転送logを簡単に/var/log/sftp.logへはきだす

Socketを使って出す　とか色々あるみたいだけど、
タイトル通り、簡単に実現したい方向け。


環境
CentOS6.5
Filezilla3.28（最新版）



# １．sshd_config設定ファイルの変更

vim /etc/ssh/sshd_config を以下に変更↓

```vim:sshd_config
#Subsystem sftp /usr/libexec/openssh/sftp-server -f LOCAL5 -l VERBOSE`
Subsystem sftp internal-sftp```
Match Group sftp_group
ChrootDirectory /data/sftp/%u
ForceCommand internal-sftp -f AUTH -l INFO
#PasswordAuthentication yes
# X11Forwarding no
# AllowTcpForwarding no
# ForceCommand cvs server
```

# ２．ssh_config再起動

`service sshd restart`



_解説：_
_・chroot化　→/data/sftp/クライアント名　以下みられない
・SSHログイン不可　→SFTP送受信専用ユーザ完成。セキュリティ上SSHでTeraTermとかで入れないように。_



# ３．rsyslog.conf設定ファイルの変更

`vim /etc/rsyslog.conf`

↓以下を追加↓

```vim:rsyslog.conf
if $syslogfacility-text == 'authpriv' and $msg contains 'flags WRITE,CREATE,TRUNCATE mode 0666' then /var/log/sftp.log
```

# ４．rsyslog.conf再起動

`service rsyslog restart`



_解説：
/var/log/secure より出力したいlogの一部を上記のように記載
例１）ファイルのダウンロードだけsftp/logに書き込みたい　→上記を追加
例２）/var/log/secureの全てをsftp.logに書き込みたい　→if $syslogfacility-text == 'authpriv' then /var/log/sftp.log_



とりあえず上記１．~４．を実施することでタイトル通りのことはできます。

あとはお好みでローテーション設定も追加すればよいと思います。

# ５．logrotate.d/syslogファイルの編集

`vim /etc/logrotate.d/syslog`

↓以下を追加↓

`/var/log/sftp.log`

**詳しくは以下のサイトで情報があるので参考にしてください。
http://fanblogs.jp/kumon/archive/18/0**


以上
ローディングコンポーネントのラップ


よくあるパターンとして、3項間演算子を使った以下のようなパターンがあります。

```js
this.state.isLoading ? <Loading /> : (
  <div>
    <div>
      <MyComponent1 />
    </div>
    <div>
      <MyComponent2 />
    </div>
    <div>
      <MyComponent3 />
    </div>
    <div>
      <MyComponent4 />
    </div>
  </div>
)
```

しかし、どちらを先に書くか？等の不要な判断が入るスキマが残っています。
例えば、以下の場合はローディング中にMyCompコンポーネントが表示されてしまうでしょう。

```js
this.state.isLoading ? <MyComp /> : <Loading />
```

このような場合、ローディングを抽象したコンポーネントを用意してあげると便利です。
MyComponentは必ずローディング後にレンダリングされることが保証されます。

```js
<SwitchLoading isLoading={this.state.isLoading}>
	<MyComponent />
</SwitchLoading>
```

やり方は色々ありますが、シンプルにこんな感じで用意して上げればいいと思います。
ここでは、更にMaybeコンポーネントを用意しています。
もちろん、flowを使わない理由はないですから、flowで型付けを行います。

```js
// @flow
import * as React from 'react'

class Maybe extends React.Component<{
  flag: boolean,
  children?: React.Node,
  else: React.Node,
}> {
  render() {
    const { props } = this

    return props.flag ? props.children : props.else
  }
}

const Loading = () => <div>Loading...</div>

class SwitchLoading extends React.Component<{
  isLoading: boolean,
  children?: React.Node,
}> {
  render() {
    const { props } = this

    return (
      <Maybe flag={props.isLoading} else={<Loading />}>
        {props.children}
      </Maybe>
    )
  }
}

const MyComponent = () => <h2>Hello World</h2>

class App extends React.Component<{}, { isLoading: boolean }> {
  state = { isLoading: false }

  componentDidMount() {
    setTimeout(() => {
      this.finishLoading()
    }, 2000)
  }

  finishLoading = () => {
    this.setState({ isLoading: true })
  }

  render() {
    const { state } = this

    return (
      <div className="App">
        <SwitchLoading isLoading={state.isLoading}>
          <MyComponent />
        </SwitchLoading>
      </div>
    )
  }
}

export default App
```

## 🤔
### VS HoC
withLoadingのようなHoCを用意してあげてもいいです。
が、しかし、HoCは便利な反面、複雑で厄介です。
個人的にはパフォーマンス上の理由がない限り、自分でHoCを作成するのは避けます。
どちらかと言えば、コントロール可能なコンポーネントを作る場合、Comp as Funcスタイル(react-motion等)か、レンダラーpropスタイルを使う方が単純で便利だと思います。
ブラウザ上でもCVしたい！ (jsモジュール？知らない子ですね）

本記事はOpenCV Advent Calendar 2017　‭FFFFFFFFFFFFFFD6‬ h 日目の記事です。

#目的：
HTMLブラウザをbackendにしたOpenCVアプリケーションが開発できるっぽいので試してみましょうかね！
今年はjsモジュール（JavaScript Binding）をネタにする人がいると思いますので、あえて対抗心をメラメラ燃やしまして！
「またまたやらせていただきましたァン！！」

# 実行結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/89434/5d449c25-d6d8-289a-25a5-800784aad015.png)

#システム概要
1. broadway daemonを起動し、ブラウザで接続しておく（☆）
1. OpenCV applicationは、何も考えずにhighguiを叩くだけ！
1. highguiは、gtk3を使って描画をする。
1. gtk3/gdkがbroadway clientとして、broadway daemonに描画を転送！
1. broadway daemonがブラウザにWebsocketで転送、ブラウザ上は表示・操作可能に！ 

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89434/dd608020-d701-e51a-22a0-0969fc531a3a.png)

# 手順
1. Ubuntu Serverをインストール。
1. OpenCVをgdk3付きでコンパイル。
2. $ broadwayd で、broadway daemonを立ち上げる
3. Windows上のChromeで、Ubuntu Serverの8080ポートに接続。専用のデスクトップが表示。
3. OpenCV application起動。

# メリット
1. OpenCV applicationには一切手を加えずに、サーバークライアント環境が構築できる。
2. X11, Wayland, RDPと違い、専用のViewerを用意する必要がなく、対応システムが広範囲である。
3. SSH接続サポートしているっぽい（コマンドラインヘルプより）。
 
# デメリット
1. 同時接続数は1限定っぽい？

# まとめ
- gtk3でサポートされているbroadway daemonを使う事で、ブラウザ上で動くOpenCVアプリケーション構築も簡単にできる。
- 2017/10/21 明日のOpenCV Advent Calenderは(nil)さんの(nil)です！！ 

# 履歴
## 2017/10/17(1日目)
資格試験勉強も終わり、今年のOpenCV Advent Calendar何しようかなー、と悩む。

「そういえば、LinuxのOpenCV GUIって、Qtに依存しまくりだなあ…　あれ、directfbとか使ってもっと軽量にできるようにしようかなー」と思い立つ。

対応したい機能

1. 画像表示
1. マルチウィンドウ表示
1. キー入力対応
1. マウス対応１
1. ボタン対応
1. マウス対応２
1. トラックバー対応

まあ、昔、N88BASICで自前Window Systemとか作ってたし、いけるっしょ！と気楽に考える。

## 2017/10/18(2日目)
なん・・・だと・・・ DirectFBの公式サイトがつぶれてる。
https://bcopy.github.io/DirectFB/ を見ると、
こんな感じで、いけそう。

1. 画像表示 → IDirectFBSurface
1. マルチウィンドウ表示 → IDirectFBWindow
1. キー入力対応 → IDirectFBInputDevice
1. マウス対応１ → IDirectFBInputDevice
1. ボタン対応 → IDirectFBInputDevice
1. マウス対応２ → IDirectFBInputDevice
1. トラックバー対応

しかも、設定ファイルでsystem=x11といれれば、GUI上で動作確認しつつ進められるですって？こりゃもう勝ったな、ガハハハハ。

あれ？GTKがbackendをDirectFBでできる？んじゃ、ぷよぐやみんぐもいらないな、これ設定だけでいけるな！！勝ったな、ガハハハハ！！

## 2017/10/19(3日目)
勝てなかったよ……

GTK3はbackendとしてDirectFB使えません、と。悲しみ……　さて、どうしたものかなあ。

| Module           | Windows | Linux | MacOS |
|:-----------------|---------|-------|-------|
| Qt | 〇 | 〇 | 〇 |
| Carbon | × | × | 〇 |
| Cocoa | × | × | ◎ |
| GTK | 〇 | 〇 | 〇 |
| W32 | 〇 | × | × |
| WinRT | ◎ | × | × |

| GTK2 | Windows | Linux | MacOS |
|-----|---------|-------|-------|
| X11 | △      | ◎    | △    |
| Win32 | ◎ | × | × |
| MacOSX |  × | × | ◎ (Quarz API) |
| DirectFB | 〇 | 〇 | 〇 |

| GTK3 | Windows | Linux | MacOS | HTML |
|-----|---------|-------|-------|-------|
| X11 | △      | ◎    | △    | × |
| Win32 | ◎ | × | × | × |
| MacOSX |  × | × | ◎(Quarz API) | × |
| Broadway | × | × | × | ◎ | 
| Wayland | × | 〇 | △ |　×　|
| Mir | × | 〇 | △ |　×　|

## 2017/10/20(最終日)
いっそbroadwayでHTMLブラウザ表示をネタにしよう、と思い立つ。
Vueでnpmから起動するブラウザを変更する

# 結論
build\dev-server.jsの`opn`の呼び出しで第2引数に呼び出したいブラウザを渡す。

```
opn(uri, {app: 'chrome' })
```

ChromeはWindows系とMac系とLinux系でそれぞれ名前が異なるみたいなので注意。
当環境はWindowsです。本文では、ChromeとChorme Canaryの呼び分けの話とかを書きます。

# 本文
## 背景
最近、Chrome Canaryを使い始めました。Chrome Canary(以下、Canary)はChromeの開発版であり、まだ一般公開用のChrome(以下、Chrome)に入っていない機能などを使うことができます。
Chromeと別に入れることができるので、私はChromeはブラジング、Canaryは開発用に使っています。
なので、デフォルトブラウザはChromeにしているんですが、それだと`npm run dev`コマンドなどで開くときにChromeで開かれてしまいます。
そこで、Canaryで開くように設定を変えます。
環境はWindows 10、webpackテンプレートで作ったVueプロジェクト(vue init webpack)を想定しています。

## 本文
### package.json
`npm run`で実行されるコマンドは`package.json`の`script`プロパティに記述されるので、そこを見てみると以下のようになっています。

```
"dev": "node build/dev-server.js",
```

どうやら、`build/dev-server.js`というファイルを実行しているだけっぽい。

### build/dev-server.js
中身を見ていくと、なんとなく怪しいのが`opn(uri)`です。
おそらく渡したuriでブラウザを開く処理ではないかと推測できます。
そこで、`opn`について調べていきます。
js上部でrequireで持ってきているので外部のライブラリということもわかるので、[npmのopnの情報](https://www.npmjs.com/package/opn)から、[opnのGitHubのリポジトリ](https://www.npmjs.com/package/opn)を見に行きます。

### opn
`opn`のサイトを見てみると第2引数のオブジェクトの`app`プロパティで指定したブラウザで開くようです。
Chromeの場合、Windowsは`chrome`、Macは`google chrome`、Linuxは`google-chrome`と全部異なるようです。
とりあえず、Chromeで起動する設定にしてみます。

```
opn(uri, {app: 'chrome' })
```

これに変更した後に`npm run dev`するとCanaryが開きました。
あれれ～？

### opnの動作
opnのコードを追ってみると、プログラムを起動させるためのコマンドを呼び出しているだけのようです。
Windowsであれば、`start chrome`コマンドで呼び出されるブラウザが`opn(uri, {app: 'chrome' })`によって呼び出されます。
そこで、`start chrome`を実行してみると確かにCanaryが開きます。
おそらく、Canaryを後からインストールしたせいでしょうか。
一応、Canaryを削除して試してみたら今度はChromeが起動しました。`chrome`という名前でChromeとCanaryが衝突を起こしるようですね。

### 呼び分ける
Canaryが呼び出せたので一応目的を達成したのですが、衝突しているのがイヤなので呼び分けを考えてみます。
startコマンドから呼び出す方法を調べてみると、名前を変えたショートカットを置いたフォルダを作り、環境変数Pathにそのフォルダのパスを指定するとよい良いようなので、ChromeとCanaryのショートカットをそれぞれ`chromeo`、`chromec`という名前で作成しました。
これによって、ChromeとCanaryの呼び分けができるようになりました。

Chrome
```
opn(uri, {app: 'chromeo' })
```
Canary
```
opn(uri, {app: 'chromec' })
```

#### 余談
パスを変えたとき、普通に起動したWindows Power Shellなら即時反映されたんだけど、atom-terminalで起動したWindows Power Shellではパスが再起動するまで有効にならなかった…。


# 参考
[「ファイル名を指定して実行」から任意のアプリを実行](https://qiita.com/kaishero/items/f73f60e1ad00d52f3740)
etherpad-liteで議事録をつくる

## 目的
* ひとりが議事録を担当するのは大変なので他の参加者もフォローしたい
* 打ち合わせの場で議事録の訂正をして、よい議事録を残したい
* クラウドサービスは使えない立場

## 前置き
etherpadとはオンラインテキストエディタです。
自前のサーバー上で構築が可能です。
ここでは、構築手順を記載します。

### 環境
* Windows10

## インストールするもの
etherpad-lite

## 環境構築手順

### etherpad-liteのダウンロード

ここからダウンロード
[etherpad-Download](http://etherpad.org/#download)

### settings.jsonの修正

users 要素のコメントアウトを外す`Line126~137`

```json
/*
  "users": {
    "admin": {
      "password": "changeme1",
      "is_admin": true
    },
    "user": {
      "password": "changeme1",
      "is_admin": false
    }
  },
*/
```

### etherpad-liteの起動

`start.bat`を実行したら、webブラウザ上で`http://localhost:9001`

![image.png](https://qiita-image-store.s3.amazonaws.com/0/129204/ac0a70b7-abca-1dd3-c875-c202fae65d49.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/129204/c18235ba-8957-1b21-8750-4ca128cbc56f.png)

## （さいごに）etherpad-liteの利活用

こんなことができればよいのでは？

#### 準備
* chatbotに、どの会議体を始めるのか伝える
* chatbotが、その会議体にあったテンプレを書いたetherpadのページURLを展開する  
(前回のアクションアイテムなんかも出してくれるとより良い)

#### 作成
* 基本は一人が記録する
* 参加者は、記録内容に指摘があればチャットで指摘する
* 資料の格納先やキーワードの説明など、補足情報があれば参加者も議事録に追記する

#### 事後
* エクスポートしたテキストをchatbotに渡す
* chatbotがGitHub Issueに追加してそのURLを展開してくれる
* Issueに対して、承認権限を持つ人がコメントすれば記録に残る