OmniAICreator/Qiita-1.07M huggingface dataset:
ちょっとずつ読むドメイン駆動設計 第三部 より深い洞察へ向かうリファクタリング 第十章 しなやかな設計5 概念の輪郭

> 2017/11/27　修正
> ドメインについての自分の直感に頻繁に立ち返り、技術的思考を抑えること。(第三部第十章より)
>↓
> ドメインについての自分の直観に頻繁に立ち返り、技術的思考を抑えること。(第三部第十章より)
> 
> **直感**ではなく**直観**の誤りでした。以下[Wikipedia](https://ja.wikipedia.org/wiki/%E7%9B%B4%E8%A6%B3)より直感と直観の違いについて
> **直観**・・・知識の持ち主が熟知している知の領域で持つ、推論など論理操作を差し挾まない直接的かつ即時的な認識の形式である。
> **直感**・・・勘で答えるなど、感覚的に物事を感じとること
> 
> 全く別の言葉ですね。
> 推論しないで、経験や理解から得たドメインの知識に立ち返る「直観」という言葉。絶妙な日本語訳ですね。

# これまでの第十章

- [序章](https://qiita.com/YasuhiroKimesawa/items/c240451e6746497fd446)
- [意図の明白なインターフェース](https://qiita.com/YasuhiroKimesawa/items/988ed817de9aac785633)
- [副作用のない関数](https://qiita.com/YasuhiroKimesawa/items/a035d872d630eadeaffb#)
- [表明](https://qiita.com/YasuhiroKimesawa/items/bc2c417c30ec79efce15)

# 概念の輪郭

## 高凝集と疎結合　大事だけれど

オブジェクト指向の原則でよく言われる高凝集と疎結合。
モジュール間の関係をできるだけ、凝縮して、不要な関連はなくしていく。基本的なオブジェクト指向の原則。

ただ、この原則を技術的な側面だけで適用すると、その価値は半減します。

高凝集と疎結合の原則を概念的にも適用すること。概念的に意味のある機能の単位を見つけること。それが、**概念の輪郭**を見つけるということですね。

## やり方

高凝集と疎結合の原則をコードに適用する際に、

> ドメインについての自分の~~直感~~直観に頻繁に立ち返り、技術的思考を抑えること。(第三部第十章より)

リファクタリングやオブジェクト指向の原則を適用する際に、いつも考慮すべきことですね。技術的観点だけで適用せず、一回立ち止まって、ドメインの知識が表現されているかを考えてみること。

ソースコードを書く上での意識・考え方・スタイルを技術的思考から切り替える必要があります。人によって、それはある種のブレイクスルーを必要とするものかもしれませんね。
Logical Replicationを使ってみた。

## はじめに
PostgreSQL 10の目玉機能にLogical Replicationというのがあったので、さっそく使ってみました。

## Logical Replicationの仕組み
Logical Replicationとは、データベースに対する操作のログをネットワークを通じて他のデータベースに送信することで、データの複製を行う仕組みです。[Publish/Subscribeモデル](https://ja.wikipedia.org/wiki/%E5%87%BA%E7%89%88-%E8%B3%BC%E8%AA%AD%E5%9E%8B%E3%83%A2%E3%83%87%E3%83%AB)を利用して、複製元のデータベースのログを複製先のデータベースへ送信します。複製元のデータベースはPublisher、複製先のデータベースはSubscriberと呼びます。
Publisherは複製したいテーブルを選択して、そのテーブルに対する操作のログをすべてPublishします。Subscriberは、そのログをSubscribeして、Publisherと同じ操作をテーブルに実行することでデータを複製します。
1対1のLogical Replicationは、Publisherがテーブルに対する操作のログをキューに詰め込み、Subscriberがそのキューからログを取り出して、テーブルを複製していると考えてもよいでしょう。

## 用意した環境
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201287/24ff5de2-0ecc-bbdc-c8c8-dcc2a58f9a8f.png)

今回はデスクトップPCとMacBookAirを用意しました。デスクトップPC上のPostgreデータベースから、MBA上のデータベースにデータを複製します。デスクトップPCがPublisherで、MBAがSubscriberです。

## Logical Replicationの設定手順
以下の2つの前準備をしてから、PublicationとSubscriptionを作成します。
1. Publisherのネットワークの設定
2. wal_levelの設定

### Publisherのネットワークの設定
SubscriberがPublisherのデータベースにアクセスできるように設定をします。Publisherのpg_hba.confを開き、一番下の方にある
`# IPv4 local connections:`の下に、
`host all all 192.168.0.5/32 md5`
を挿入します。これによってSubscriberがPublisherに接続できるようになります。IPアドレスは適宜変更してください。

### wal_levelの設定
Publisherのpostgresql.confを開き、
`# - Settings -`の下にある`wal_level`を、
`wal_level = logical`
に変更してください。これをしないと、Logical Replicationは使えません。

## Publicationの作成
まず、Publisherのデータベースに複製したいテーブルを作成しましょう。ここでは、newtableというテーブルを作成しました。
`create table newtable(name varchar(100), id varchar(20) primary key);`
primary key制約をつけることを忘れないでください。primary keyがないと、複製対象のテーブルに対してUpdate,Deleteした際に怒られます。
次に、Publicationを作成します。ここで、複製したいテーブルを選択します。
`create publication pubtest for all tables;`
上の例ではすべてのテーブルを複製対象にしています。

## Subscriptionの作成
Publisherと同じく、Sublisherのデータベースにも複製したいテーブルを作成します。
`create table newtable(name varchar(100), id varchar(20) primary key);`
次に、Subscriptionを作成します。ここで、どのPublicationをSubscribeするかを設定します。`connection`の中身は適宜変更してください。
`create subscription subtest connection 'host=192.168.0.8 port=5432 password=xxxxxxxx' publication pubtest;`

## 動作確認
Publisherでnewtableに対してデータを挿入、更新、削除し、Subscriberでselectします。たしかに、PublisherのテーブルがSubscriberに複製されています。

1. Publisher:データの挿入
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201287/71e4bf20-e738-b848-5ea2-570f17cd0438.png)

2. Subscriber:Select
![スクリーンショット 2017-11-27 1.27.26.png](https://qiita-image-store.s3.amazonaws.com/0/201287/dd902ce1-575f-364d-e2e6-837860ecbcca.png)

3. Publisher:データの更新
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201287/8078d731-4f90-1ead-e0a3-3c531f850d02.png)

4. Subscriber:Select
![スクリーンショット 2017-11-27 1.29.59.png](https://qiita-image-store.s3.amazonaws.com/0/201287/f446f475-2ccc-7607-13ca-217a0fd8f33f.png)

5. Publisher:データの削除
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201287/04791003-3979-1fda-2391-e30914d9167a.png)

6. Subscriber:Select
![スクリーンショット 2017-11-27 1.31.49.png](https://qiita-image-store.s3.amazonaws.com/0/201287/7e9df0bc-5513-3bf2-2083-1a52bfa6794b.png)

## おわりに
Subscriberが複製対象のテーブルに対してInsertなどの操作を行うとPublisherのテーブルにも反映されるという情報をいくつか見かけましたが、私の環境ではそのようなことはできませんでした。(そもそもPublish/Subscribeモデルでそのようなことはできないと思います。)
UITextFieldに下線を引く（縦向き、横向き切替対応）

TextFieldに下線を引く方法はググると直ぐ出てきて、`draw(_:)`に記述すれば対応出来ます。
ただ、これで行うとPortrait (縦向き) モードからLandscape (横向き) モードにしても下線が短いままです。
（TextFieldをAutoLayoutで画面の横幅一杯にしている場合など）
ちなみに、フォーカスすると再度draw(_:)が呼び出されるので下線が横幅一杯になります。

Portrait (縦向き) モードと Landscape (横向き) モードでの切替に対応するには切り替えた事を検知して横幅を変更してあげればいいのでプロパティ監視の機能を使って`bounds`が変更されたときにborderを更新するようにすると上手くいきます。


```swift:CustomTextField.swift

import UIKit

class CustomTextField: UITextField {
    override open var bounds: CGRect {
        didSet {
            updateBorder()
        }
    }
    
    private let borderLayer = CALayer()

    override func draw(_ rect: CGRect) {
        updateBorder()
        self.layer.addSublayer(borderLayer)
    }
    
    func updateBorder () {
        borderLayer.backgroundColor = UIColor.borderColor.cgColor
        borderLayer.frame = CGRect(x: 0, y: self.frame.height, width: self.frame.width, height: 0.5)
    }
}
```
slackの便利なスラッシュコマンド

初投稿なので、練習も兼ねて最近学んだSlackの便利なスラッシュコマンド機能を紹介

# スラッシュコマンドとは
メッセージ入力で / から始まるコマンドを入力する事をスラッシュコマンドと言います。

# /remind
リマインダーを設定することができます。

```
/remind [@メンバ or #チャンネル] [何を(日本語可)] [いつ(英語で指定)]
```
##[@メンバ or #チャンネル]
| 用途 | コマンド |
|:-:|:-:|
| 自分へのリマインド | me |
| 特定のメンバへのリマインド | @メンバ |
| 特定のチャンネルへのリマインド | #チャンネル |

## 何を
リマインドしたい内容を設定します。
内容には、特定のメンバへのメンション（@メンバ）も含めることができます。

## いつ
**経過時間指定(in)**

|  |指定方法（例）|
|:--|:--|
| 10秒後  | in 10 secs |
| 1分後  | in 1 min |
| 2時間後 | in 2 hours |
| 10日後 | in 10 days |
| 1ヶ月後 | in 1 month |

**時刻指定（at)**


| | 指定方法(例)　|
|:--|:--|
| 午前10時（12時間制）  | at 10:00am |
| 午後５時（24時間制）  | at 17:00 |
| 午前0時 | at midnight |
| 午後8時 | at evening |
| 午前9時 | at morning |

**日付指定(on)**

| | 指定方法(例)　|
|:--|:--|
| 1月1日 | on January 1 |
| 2月8日 | on 8 Feb |
| 2018年11月30日 | on 11/30/2018 |

**繰り返し設定(every)**
注意 : 他のメンバーに対して繰り返しのリマインダーを設定することはできません

| | 指定方法(例)　|
|:--|:--|
| 平日に毎日 | every weekday |
| 毎週の月曜日 | every Monday |
| 毎週の火曜、水曜、金曜 | every Tuesday, Wednesday, and Friday |
| 隔週木曜日 | every other Thursday |

#/feed
SlackにRSSフィードを追加することができます。

```
/feed [list, subscribe or remove]
```

## list
そのチャンネル追加された全てのRSSフィードとその固有のIDナンバーを確認できます。

## subscribe
フィードを追加できます。
任意のチャンネルにて、メッセージボックスに下記コマンドを入力すると追加します。

```
/feed list [フィードのアドレス]
```

## remove
追加したフィードの受信を停止できます。

```
/feed remove [フィードのIDナンバー]
```
暗号化とか、証明書とか

暗号化とか、証明書とか個人的なメモ

# 暗号化通信の基本的な仕組み
1. Aは秘密鍵を作る。
2. Aは作った秘密鍵とペアになるような公開鍵を作る。
3. Aはその公開鍵をBに渡す。
4. 通信するときは、その秘密鍵と公開鍵のペアで通信する。


一見これで問題ないように見えるのですが、これには大きな問題が含まれています。
3.の公開鍵を渡すというポイントです。
その受け渡しをどうやってセキュアに実施しますか？
これって鶏と卵ですよね。
つまり、セキュアに通信するために鍵交換をしたいのに、
その鍵交換には、セキュアな通信が必要・・・という。

これを解決する方法はひとつしかありません。
OSのインストール時にインストールディスクとかに埋め込んでおくんです。
※インストールディスクは改ざんされない前提ですけどね。
これについては、製品を買ってきて手に入れるのが大半だと思うので、問題ないです。

じゃあ、全部のサイトの公開鍵を埋め込んでおくんですか？という話です。
そんなん無理な話ですよね。どんどん新しいサイトもできますし、ほぼ無限大に存在します。
結論から言うと、OSインストール時に埋め込む鍵は限られています。

そうすると、鍵をあらかじめ持っていないサイトとは通信できない気がします。
その場合はどうするのか。その場合は、「すでに信頼している人から、保証してもらう」ことが有効になります。

次に、その、「既に信頼している人から、保証してもらう」仕組みを考えてみる。


# 暗号化通信と証明書

## Aが証明書を作るプロセス
1. Aは秘密鍵を作る。
2. Aは作った秘密鍵とペアになるような公開鍵を作る。
3. Aはその公開鍵に署名してもらう書類を作る。(CSR=Certificate Signature Rrequire)
4. AはCSRをKに渡す。
5. Kは受け取ったCSRに対して、Kの秘密鍵で暗号化して、証明書を作る。
6. Kは作った証明書をAに返す。

## AがBと通信するプロセス。
1. BはAにアクセスする。
2. AはBに証明書をかえす。
3. Bはその証明書をKに問い合わせて本物かどうか確認する。
4. 確認の結果問題なければAと通信する。

さて、ここで重要になってくるのは、Kの存在です。
これはKがいるからこそ、成り立つ仕組みなのです。
このKのことをKPIとよんでいます。

## もう少し勉強したい人へ。
この、”Kに問い合わせて検証する”部分を詳しく見ていきましょう。

1.BはAから証明書をもらう。
2.BはKから公開鍵をもらう。
3.Aの証明書はKの秘密鍵で暗号化されているので、Kの公開鍵で復号化できる。
4.そのようにして、BはAの証明書が正しいことが検証できる。
5.ちなみに、証明書にはAの公開鍵が含まれているので、このようにしてBはAの正しい公開鍵を手に入れることができる。



# 認証局

ここで、OSに最初からインストールしている証明書のことを”ルート証明書”と呼び、
そのルート証明書で認証できるサーバーのことをルート認証局と呼んでいます。
そして、そのルート認証局に認証してもらう必要のあるサーバーを中間認証局と呼び、区別します。
中間認証局はルート認証局に証明してもらうことにより、その正当性を確保することができます。
こうして、信頼がどんどん連鎖していくことを、「信頼の連鎖」と呼ぶこともあります。
友達の友達は友達！見たいな感じですかね。違いますかね。


# 要約
ごちゃごちゃいってきましたが、要約すると以下のポイントとなります。
1.通信をするときには、鍵交換を行う必要がある。
→でもどうやってその鍵交換を行うの？
2.もともと埋め込まれている鍵でやり取りする相手をルート認証局と呼ぶ
→じゃあそれ以外とどうやって通信するの？
3.ルート認証局に認証してもらうことによって中間認証局ができ、信頼できる相手となる。

# さいごに
なんかまとまりのない文章となってしまいました
嘘とか言ってたら指摘していただけると幸いです
Google Compute Engine上でお手軽にRStudio Serverを立ち上げる方法のメモ

# はじめに

Google Cloudを使っていて、自分が感動したことの一つは、少しのコマンドでものすごく簡単にサーバーを立ち上げることが出来ることです。その中でも、データ解析系の仕事に従事する人はRstudioを使っていることが多いと思いますが、ブラウザでアクセスできる、Rstudio ServerをGoogle Cloud上で簡単に立ち上げる方法を記載します。他の記事では通常通りにサーバーをインストールする方法は載ってましたが、dockerを組み合わせれば本当にものすごく簡単立ち上げることが出来るので、紹介します。
＊Google Cloud SDKはインストールされている前提です。

# FIREWALLの設定

Rstudio Serverはポート8787を利用するので、まずこちらの開放する準備をします。

```
> gcloud compute firewall-rules create allow-rstudio --allow tcp:8787 --target-tags allow-rstudio --source-ranges 0.0.0.0/0
```

これで、allow-rstudioというfirewallのルールが生成されました。以下のコマンドで確認できます。

```
> gcloud compute firewall-rules list
```

# VMインスタンスを立ち上げる

とりあえず、コンテナ用に最適化されたイメージが用意してあり、こちらを利用すれば最初からdockerがインストールされております（他のイメージを利用すると、dockerをわざわざインストールする必要があります）。ちょっとメモリを15GBほど利用できる設定にしましょう。また、この際に、ポート8787を開放する設定にします。

```
> gcloud compute instances create rstudio-server --machine-type n1-standard-4 --image-family cos-stable --image-project cos-cloud --tags allow-rstudio
```

しばらくするとインスタンスが立ち上がり、次のコマンドでインスタンスの確認ができます。

```
> gcloud compute instances list
```

# インスタンスに接続して、RSTUDIO SERVERを立ち上げる。

まずは、作成したインスタンスにssh接続します。

```
> gcloud compute ssh rstudio-server
```

接続したインスタンス上で、サーバーを立ち上げますが、Rstudio Serverを立ち上げるdockerイメージが準備されており（[https://hub.docker.com/r/rocker/rstudio/]([https://hub.docker.com/r/rocker/rstudio/])）、こちらを利用するとものすごくお手軽にできます。

```
> sudo docker run -d -p 8787:8787 rocker/rstudio
```

# ブラウザ上で接続

http://\<EXTERNAL_IP\>:8787 とブラウザで入力して、Rstudio Serverに接続する。初期ユーザーとパスワードはともにrstudio、rstudio。
Unity2017.2でC#6.0を使う

monodevelopで試行錯誤して時間をとられてしまったのでメモ

## 環境情報
* Unity2017.2.0f3
* macOS Sierra 10.12.6

## 手順
1. [ここ](https://www.visualstudio.com/ja/vs/community/)からVisualStudioをダウンロード
2. Unityの[ Preferences > External Tools > External Sctipt Editor ]をVisual Studioに変更
3. Unityの[ Build Settings > Player Setings > Other Settings > Scripting Runtime Version ]をExperimental(.NET 4.6 Equivalent)に変更
Raspbianの初期設定をおこなう

Raspberry Pi Zero WにインストールしたRaspbianの各種設定です。

# パッケージの更新

パッケージ取得元の更新
`$ sudo vi /etc/apt/sources.list`

変更前

```
deb http://mirrordirector.raspbian.org/raspbian/ stretch main contrib non-free rpi
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
#deb-src http://archive.raspbian.org/raspbian/ stretch main contrib non-free rpi
```

変更後

```
deb http://ftp.jaist.ac.jp/raspbian/ stretch main contrib non-free rpi

#deb http://mirrordirector.raspbian.org/raspbian/ stretch main contrib non-free rpi
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
#deb-src http://archive.raspbian.org/raspbian/ stretch main contrib non-free rpi
```

パッケージインデックスファイルの再同期
`$ sudo apt-get update`

インストールされている全パッケージを更新
`$ sudo apt-get dist-upgrade`

念のため再起動しておく
`$ sudo reboot`

# piユーザーの無効化とユーザーの追加

```
SSH is enabled and the default password for the 'pi' user has not been changed.
This is a security risk - please login as the 'pi' user and type 'passwd' to set a new password.
```
SSHが有効になっているとpiユーザーはセキュリティリスクになるのでパスワードを変更しろと警告されます。よってpiユーザーは無効にし新たなユーザーを作成します。

## piユーザーが所属しているグループの確認
新しく追加するユーザーはpiユーザーと同じグループに所属させるため、予め調べておきます。

```
$ groups pi
pi : pi adm dialout cdrom sudo audio video plugdev games users input netdev spi i2c gpio
```

## ユーザーの追加
`$ sudo adduser --gid 100 <username>`

## グループへの追加
`$ sudo usermod -G pi,adm,dialout,cdrom,sudo,audio,video,plugdev,games,users,input,netdev,spi,i2c,gpio <username>`

## 追加したユーザーがsudoできることを確認する
先ほど作成したユーザーでsshして(Raspberry Piにログインして)sudoできることを確認する。piユーザーの権限を剥奪する前に確認しておく。これ以降の作業は追加したユーザーで行う。

```
$ sudo whoami
root
```

## piユーザーの無効化
念のためパスワードを変更しておきます。
現在のパスワードを聞かれますが初期状態であれば`raspberry`です。
`$ sudo -u pi passwd`

## piユーザーをsudoグループから削除
`$ sudo gpasswd -d pi sudo`

## piユーザーからsudo権限を剥奪

### vimのインストール
この後の作業にてvimを使いたいのでインストールしておく
`$ sudo apt-get install vim`

### /etc/sudoers.d/010_pi-nopasswdを編集する
`$ sudo vim /etc/sudoers.d/010_pi-nopasswd`

変更前
`pi ALL=(ALL) NOPASSWD: ALL`

変更後
`#pi ALL=(ALL) NOPASSWD: ALL`

※`/etc/sudoers`を編集してコメントアウトする、または`sudo visudo`で編集すると書かれたドキュメントはすでに情報が古くなっています。

### piユーザーでsudo出来ないことを確認しておく

```
$ sudo -u pi sudo pwd
[sudo] pi のパスワード:
pi は sudoers ファイル内にありません。この事象は記録・報告されます。
```
Istio入門 その1 -Istioとは?-

## はじめに
Istioの全体像がわかるよう、数回に分けて入門してみます。今回はコンセプトやざっくりとしたアーキテクチャの話、次回からはサンプルのbookinfoアプリケーションを元に各機能を深掘りしていく予定です。

> **Istio入門シリーズ**
> * [その1 -Istioとは?-][istio1]
> * [その2 -Istio構築とサンプルアプリのデプロイ-][istio2]
> * [その3 -Blue/Greenデプロイメントによるカナリアリリース-][istio3]
> * [その4 -基礎から振り返る-][istio4]
[istio4]: https://qiita.com/Ladicle/items/4ba57078128d6affadd5
[istio1]: https://qiita.com/Ladicle/items/979d59ef0303425752c8
[istio2]: https://qiita.com/Ladicle/items/e949b0f68ac18b7a95d8
[istio3]: https://qiita.com/Ladicle/items/5a68ff85e15e86781453


## Istioとは?
[Istio](https://istio.io)[^0]とはマイクロサービスをセキュアにマネージメントするためのOSSで、Kubernetes同様CNCFの一員です。

マイクロサービス化が進むにつれてA/Bテストやカナリーリリースに20%のアクセスのだけ割り当てたいなどの要望により、サービスメッシュ[^1]はより大きく、より複雑になりました。Istioは、このような「複雑なサービスメッシュの管理が追いつかない」という課題を解決するため開発されています。主な機能としては、サービス間の認証やモニタリング、L7での柔軟なロードバランシングが提供されています。現在はKubernetesにのみ対応していますが、将来的には他のプラットフォームにも対応するようです。(現在の0.2系でも鍵管理などの一部機能はベアメタルに対応しています)

また、Istioのコンポーネントは、サービスのサイドカーとしてPodにデプロイされるためサービスコードを修正する必要がありません。これによって、アプリケーション開発者に負担をかけることなく、運用者がシステムを柔軟にマネージメントできるという利点があります。

## システム構成

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/1932a175-171c-ab34-1fb3-695c8a6cc131.png)

Istioのサービスメッシュは上記の図のように**データプレーン**と**コントロールプレーン**の2つに分けることができます。
データプレーンはプロキシサーバによるマイクロサービス間の通信の管理、コントロールプレーンではポリシーやプロキシ設定の管理を行なっています。

### Istioを構成するコンポーネント

* **Envoy**: サービスメッシュのイン/アウトバウントの全てのトラフィックを管理するプロキシサーバで、KubernetesではPodのサイドカーとしてデプロイします。ちなみに、Envoy[^2]は素のままではなく、Istio用に拡張されたものを使用しています。
* **Mixer**: Envoyを通して各サービスのデータを収集し、その情報を元にアクセスコントロールを行うコンポーネントです。プラグインモデルを取っており、柔軟なカスタマイズが可能になっています。
* **Pilot**: サービスディスカバリやトラフィック管理などを担当しています。Kubernetesの場合、サービスディスカバリはWatch APIによるEnvoyのステータス変更を検知することで実現しています。
* **Istio-Auth**: KubernetesのService Accountを利用したユーザ認証や、サービス間のTLS相互認証を行います。この認証を利用することで、ポリシーベースでサービスメッシュを管理することができます。また、将来的にはFGAC[^3]に対応するようです。

## 参考リンク集
* [Istio](https://istio.io): オフィシャルウェブサイト
* [Github - Istio org](https://github.com/istio): GithubのIstioページ
* [Istio - A modern service mesh](https://istio.io/talks/istio_talk_gluecon_2017.pdf): Gluecon 2017の講演資料(PDF)

## おわりに
今回はIstioのコンセプトとアーキテクチャの概要をご紹介しました。最後に登場したIstio-Authは**SPIFFE**を利用しているのですが、こちらの詳細については@hiyosiさんが解説されます。それでは、ひき続き[Z Labアドベントカレンダー](https://qiita.com/advent-calendar/2017/zlab)をお楽しみください。

[^0]: Istioはギリシャ語で`帆`を意味する
[^1]: マイクロサービスが互いに通信するネットワークのこと
[^2]: これまたCNCFのプロジェクトの一つで、C++で書かれた[Envoy](https://www.envoyproxy.io)というOSSのプロキシ
[^3]: Fine-Granted Access Controlの略。詳細な権限コントロールができる機能で、サービスに対して誰がどのデータにアクセスでき、どのようなアクション(read/write)を実行するかを指定できる
Selenium ChromeDriver & PythonをMacで動かす準備メモ

# はじめに
* Webアプリの受け入れ"簡易"試験を実施することになりまして
* "簡易"なのでMac上に環境を構築しました。
* 備忘のために手順をメモしておきます。

# 前提
| ソフト | バージョン |
|:-:|:-:|
| Mac | Sierra 10.12.6 |
| Python | 3.6.3 |
| Selenium | 3.7.0 |
| ChromeDriver | 2.33 |
|  Chrome | 61.0.3163.100 |

# Seleniumインストール
`pip install selenium`

「そもそもpipが入っていない！」という方は
`curl -kL https://bootstrap.pypa.io/get-pip.py | python`
を実行してください。

# ChromeDriverインストール
`brew install chromedriver`

「そもそもbrewが入っていない！」という方は
`/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"`
を実行してください。

brewを使わない or Mac以外の方は以下サイトの「Latest Release」のバージョンのダウンロード画面から
環境に合うものをダウンロード・インストールします。
https://sites.google.com/a/chromium.org/chromedriver/downloads

# テストプログラムの実行
「Chromeを起動して"Selenium"とGoogle検索して、Seleniumの公式サイトを開く。」
というテストプログラムを実行してみます。

```py3:selenium-test.py
# coding:utf-8
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from time import sleep

# ブラウザを開く。
driver = webdriver.Chrome()
# Googleの検索TOP画面を開く。
driver.get("https://www.google.co.jp/")
# 検索語として「selenium」と入力し、Enterキーを押す。
driver.find_element_by_id("lst-ib").send_keys("selenium")
driver.find_element_by_id("lst-ib").send_keys(Keys.ENTER)
# タイトルに「Selenium - Web Browser Automation」と一致するリンクをクリックする。
driver.find_element_by_link_text("Selenium - Web Browser Automation").click()
# 5秒間待機してみる。
sleep(5)
# ブラウザを終了する。
driver.close()
```

# 参考サイト
* [PythonでSeleniumを使ってスクレイピング (基礎)](https://qiita.com/kinpira/items/383b0fbee6bf229ea03d)
* [SeleniumからHeadless Chromeを使ってみた](https://qiita.com/orangain/items/db4594113c04e8801aad)
xonshのタブ補完でなんかエラーになる件

# 環境
* Windows 10 64bit
* Python 3.6.3
* xonsh: `xonsh/0.6.0`

# 事象
サブプロセスモードの何かしらで`<TAB>`で補完を試みると、下記のエラー

```py3tb
Exception in thread Thread-25:
Traceback (most recent call last):
  File "C:\Python36\lib\threading.py", line 916, in _bootstrap_inner
    self.run()
  File "C:\Python36\lib\threading.py", line 864, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Python36\lib\subprocess.py", line 1063, in _readerthread
    buffer.append(fh.read())
UnicodeDecodeError: 'cp932' codec can't decode byte 0x83 in position 14: illegal multibyte sequence

Exception in thread Thread-24:
Traceback (most recent call last):
  File "C:\Python36\lib\threading.py", line 916, in _bootstrap_inner
    self.run()
  File "C:\Python36\lib\threading.py", line 864, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Python36\lib\site-packages\prompt_toolkit\interface.py", line 865, in run
    completions = list(buffer.completer.get_completions(document, complete_event))
  File "C:\Python36\lib\site-packages\xonsh\ptk\completer.py", line 49, in get_completions
    self.ctx)
  File "C:\Python36\lib\site-packages\xontrib\free_cwd.py", line 82, in wrapper
    out = func(*args, **kwargs)
  File "C:\Python36\lib\site-packages\xonsh\completer.py", line 35, in complete
    out = func(prefix, line, begidx, endidx, ctx)
  File "C:\Python36\lib\site-packages\xonsh\completers\bash.py", line 13, in complete_from_bash
    command = xp.bash_command()
  File "C:\Python36\lib\site-packages\xonsh\platform.py", line 432, in bash_command
    bc = windows_bash_command()
  File "C:\Python36\lib\site-packages\xonsh\platform.py", line 340, in windows_bash_command
    universal_newlines=True)
  File "C:\Python36\lib\subprocess.py", line 336, in check_output
    **kwargs).stdout
  File "C:\Python36\lib\subprocess.py", line 405, in run
    stdout, stderr = process.communicate(input, timeout=timeout)
  File "C:\Python36\lib\subprocess.py", line 843, in communicate
    stdout, stderr = self._communicate(input, endtime, timeout)
  File "C:\Python36\lib\subprocess.py", line 1113, in _communicate
    stdout = stdout[0]
IndexError: list index out of range
```

# 原因
`locale.getpreferredencoding()`が`cp932`になっているので、Unicodeの文字を`cp932`で`decode`しようとしてる。(多分)

```py3
import locale

locale.getpreferredencoding()
\# => 'cp932'
```

# 対策
## 無理やり`locale.getpreferredencoding()`を変更する
`~/.xonshrc`に以下を追記 ([参考@stackoverflow](https://stackoverflow.com/questions/31469707/changing-the-locale-preferred-encoding-in-python-3-in-windows/34345136#34345136))。

```py3
import _locale
_locale._getdefaultlocale = (lambda *args: ['ja_JP', 'utf_8'])
```
shebang (#!) 以下の内容（コンテンツ）を読み出す方法

# はじめに
シェルスクリプトはもとより、lua などのシェルじゃないスクリプト言語なども、\#! を使って

```lua:exec-by-shebang.lua
#!/usr/bin/env lua
print("HEELO")
print(1+2)
```

などと記述することができます。このように書かれたファイルに実行属性を与えて実行すれば、\#! の直後に書かれたプログラムにより（この例では lua により）、2 行目以降に書かれた lua プログラムが実行されます。

ちなみに、\#! のことを、shebang - シバンとかシェバンとか呼ぶそうです。

これは、一体どのように実現されているのでしょうか？　例えば、自作のプログラムで、

```sh:test
#!./my-great-program
parameter / my great program
command-for-my-great-program
  :
```

などという書き方を実現するためには、どのようにすれば良いのでしょうか？

ベテラン Unix プログラマの方からみたら、非常に基本的な事柄なのだろうと思いますが、検索してもそのものズバリの答えを見つけることができなかったので、ここに記しておきます（多分、私の調べ方が悪いのだと思いますが、シェルスクリプトの書きかたに関する情報が大量に出てきてしまって、答えにたどり着くまでに随分時間がかかってしまいました…）。

#いきなり結論
\#! で起動されると、呼び出したスクリプトファイルのファイル名が引数として渡されます。

つまり、shebang-test に、

```sh:sheebang-test
#!./read-shebang-contents
shebang contents string
alpha
beta
```

などと書かれていたとすると、このファイルから呼び出される read-shebang-contents プログラムは、コマンドライン的に書くと、

```sh:exec-by-cli
%./read-shebang-contents ./shebang-test
```

となります。つまり、第 1 引数にシェルスクリプトのファイル名である shebang-test を付けた状態で起動されます。

# サンプルプログラム
検証するためのプログラムを以下に示します。単に、argv を表示し、かつ、argv[1] に渡されたファイルの中身を表示する簡単なプログラムです。

```C:read-shebang-contents.c
#include <stdio.h>
#include <unistd.h>

int main(int argc,char *argv[]) {
    int i;
    for(i=0; i<argc; i++) {
        printf("argv[%d]=%s\n",i,argv[i]);
    }
    if(argc<2) {
        printf("NO SCRIPT FILES.\n");
        return 0;
    }

    char buf[1024];
    FILE *fp=fopen(argv[1],"r");
    puts("===shell script contents===");
    while(fgets(buf,sizeof(buf),fp)!=NULL) {
        fputs(buf,stdout);
    }
    puts("=== END ===");
    fclose(fp);

    return 0;
}
```

シェルスクリプト shebang-test を実行した結果は以下のとおりです。

```text:resut-of-shebang-test
argv[0]=./read-shebang-contents
argv[1]=./shebang-test
===shell script contents===
#!./read-shebang-contents
shebang contents string
alpha
beta
=== END ===
```

# まとめ
shebang により起動されるプログラムには、起動するスクリプトファイルのファイル名が引数として渡されます。ただそれだけ。非常に簡単です。

冒頭に挙げた lua のスクリプトも、引数として渡されたファイル名をたよりに、ファイルをオープンしているようです。lua 言語でのコメントは \# ではありませんので、ファイルを読み込む時になにか特別な処理をしているのではないかと思われます（どうやら最初の行の \#! だけは無視するように処理をしているっぽいですが…）。

# 余談
本件は、分かってしまえば何も難しいところはない仕組みですが、分かるまでに少し時間がかかってしまいました。

当初は、シェルがプログラムを起動する際に exec 系のシステムコールを使うから、オープンされているファイルディスクリプタが引き渡されるのではないのか！？などとも思ったりしておりました。Unix について、あまり詳しくないとこんな風に思ってしまうという例です（他山の石にしていただければ幸いです）。

最終的なヒントとなったのは、lua のソースコードでした。lua は冒頭で示したように、\#! で起動するファイルにプログラムを書いておけば、それを読み込み実行してくれます。検索してもなかなか分からない状況でしたので、最終的には lua のソースコード（lua.c）を読み、printf を所々に挿入して、make macosx しつつ、その挙動を調べていきました。21 世紀になっても、検索能力が低いと、結局「ソースを読め！」ということなんだなぁ、としみじみ思いつつ、また、トホホな気分になった日曜日でした。

おわり。
ラズパイで複数のネットワーク設定をする

#きっかけ
基本は寮に住んでるけど、ラズパイを持って帰省することもある。家のLANと寮のLANでDNSサーバとかのアドレスが違ったりして、IPアドレスが変わったりして手間。
#ってことで
複数のネットワーク情報を保存して、接続するネットが変わっても、自動で切り替わってくれるようにする。意外と単純だった。
#バージョンとか
- RaspberryPi Zero W

```console:
pi@raspberrypi:~$ cat /etc/debian_version
9.1
```
OSはRaspbianでバージョンは9.1でした。
#手順
wpa_supplicant.confを設定する。

```console:
pi@raspberrypi:~$ sudo nano /etc/wpa_supplicant/wpa_supplicant.conf
```
ここで、以下の感じでどんどん追加してく。

- ssidはそのままの意味でSSIDをダブルクォーテーションでくくって入力します。
- pskはパスワードで、ダブルクォーテーションでくくります。
- priorityは接続できるネットが複数あった時の接続する優先度で、大きい値のssidに優先して接続します。
- id_strは設定しておくと、dhcpcd.confのssid名のところをこれに置き換えることが可能になります。しなくてもいい。

```console:wpa_supplicant.conf(一部抜粋)
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
        ssid="AirPortXXXX"
        psk="XXXXXX"
        priority=0
        id_str="home"
}

network={
        ssid="iPhone6"
        psk="XXXXXXX"
        priority=3
        id_str="iPhone"
}

network={
        ssid="WARPSTAR-XXXXX"
        psk="XXXXXXXXXX"
        priority=2
        id_str="dormitory"
}
```
次にdhcpcd.confを設定する。

```console:
pi@raspberrypi:~$ sudo nano /etc/dhcpcd.conf
```
ここで、以下のように設定する。全部Wi-Fi接続です。

```console:dhcpcd.conf(一部抜粋)
# static IP configuration:

interface wlan0
ssid AirPortXXXXX
static ip_address=192.168.1.151/24
static routers=192.168.1.1
static domain_name_servers=192.168.1.1

ssid XXXXXXXXXXXXX
static ip_address=192.168.3.151/24
static routers=192.168.3.1
static domain_name_servers=192.168.3.1

ssid WARPSTAR-XXXXXXX
static ip_address=192.168.0.151/24
static routers=192.168.0.1
static domain_name_servers=192.168.0.1
```
設定後再起動すると、反映されてる。
お疲れ様でした。
【Termux】Android上にPython環境を作成する


Android端末上でLinux環境が作れるtermuxが面白くて弄ってみたのでそのメモ。
結局numpyがインストールできず若干止まっているのですが、軽いpythonスクリプトくらいなら動かせるので面白いですね。
あとはTaskerと連携可能なようなので可能性を感じます。


下記は実際に使ったログです。
\# 端末のストレージにシンボリックリンクを作成
\# 内部ストレージやsdカードの利用はここで作ったシンボリックリンクから行う
\# 実パスからでは権限不足となってしまう模様
termux-setup-storage

\#Git
apt install git

\#Vim
apt install vim

\# 設定
set fileencodings=utf-8,sjis
set fileencodings=utf-8
set encoding=utf-8
\# 参考
https://sites.google.com/site/fudist/Home/qfixhowm/other-service/howm-android\#TOC-Termux
\# ソフトウェアキーボード利用時でもHacker's Keyboardを使えばEscキーが使えるのでなんとかなる


\#Python3
\#内部的にはCythonをインポートしている模様
apt install python

\# ライブラリのインポートはpipが使える
pip install xxx



\# Python mysql-connectorのインポート
\# 下記サイトと同じくpipでインストールできない..
https://qiita.com/a_t_a/items/680ed657c4dbeab40a28
\# zipをブラウザでDLし、解凍してインストールすればOK
python setup.py install


\# numpy
\# 結局インストールできず...
\# 下記サイトなどを参考
https://github.com/termux/termux-packages/issues/1737
https://plus.google.com/+NaganumaTatsumi/posts/inz3nrEau2b
http://hibagon.sblo.jp/s/article/181186800.html

\# 必要と思われるライブラリ
apt install python-dev fftw
pip install wheel
apt install clang libc++
pip install numpy==1.9.1
\# 自分ではこれではインストール出来ず...
LDFLAGS=" -lm -lcompiler_rt" pip install numpy

\# matplotlib
apt install freetype-dev libpng-dev
apt install pkg-config
【Google Apps Script】その14　SEO用にタイトルとディスクリプションを収集する

この記事は[Google Apps Scriptを実例交えて基礎からざっくり学ぶ Advent Calendar 2017](https://qiita.com/advent-calendar/2017/gas_beginner)　14日目の記事です。

本アドベントカレンダーは@rt_pの個人プロジェクトですが、筆者は[Ateam Brides Inc. Advent Calendar 2017](https://qiita.com/advent-calendar/2017/a-t-brides)にも参加しています。そちらでも出張版記事を書いているので、覗いていただけると嬉しいです。

# はじめに

SEOで重要なタイトルやdescription、URLの一覧を元に自動的に取得したいですよね。
まぁ正直、無料で同じようなツールはあったりするわけですが、今回はGASの勉強も兼ねてスプレッドシート上で作成してみたいと思います。

![meta2.png](https://qiita-image-store.s3.amazonaws.com/0/199678/991ffc5d-9b60-9203-9fb3-c0d724a9511b.png)

# 収集したいURLのスプレッドシートを作成する

1行目は説明行としてURL　タイトル　description　h1と入力。

1列目に、調べたいURLを入力していきましょう。
サンプルは動画サイトのURLですが、特に深い意味はないです。
最初はFacebookやYahoo、Google、Amazon等をサンプルに使う予定でしたが、どこも地味に取得しづらい形に加工されておりうまく取得ができませんでした…

![meta1.png](https://qiita-image-store.s3.amazonaws.com/0/199678/48b70c53-1bfd-cf33-468f-603bd829b3aa.png)

スクリプトエディタを開き、以下コードに置き換えて実行します。
スクリプトエディタの開き方や*承認が必要です*メッセージが出た際の対処法が分からない場合は
[アドベントカレンダー1日目のHello, world!記事](https://qiita.com/rf_p/items/0535ec495df8f9d2b894)をご参照ください。

```javascript:get_meta.gs
function myFunction() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var values = sheet.getDataRange().getValues();

  try {
    for (var i = 1; i < values.length; i++) { // 1行目は説明行なので2行目であるkey1から開始
      checkTitleDescription(sheet, values[i], i);
    }
  } catch (e) {
    Browser.msgBox(e);
  }
}

function checkTitleDescription(sheet, value, i) {
  var response = UrlFetchApp.fetch(value[0]); // 一番左のセルにURLの値が入っている
  var text = response.getContentText();
  var titleMatch  = text.match(/<title>([\s\S]*)<\/title>/i);
  var title       = getFirstValue(titleMatch);
  var descMatch   = text.match(/meta\s+name=['"]description['"]\s+content=['"](.+)['"]/i);
  var description = getFirstValue(descMatch);
  var h1Match     = text.match(/<h1.+?>([\s\S]*)<\/h1>/i);
  var h1          = getFirstValue(h1Match);
  sheet.getRange(i + 1, 2, 1, 3).setValues([[title, description, h1]]);
}

// マッチする最初の要素を返す
function getFirstValue(values) {
  return values && values.length > 1 ? values[1] : '';
}
```

実行すると以下結果になるはずです。

![meta2.png](https://qiita-image-store.s3.amazonaws.com/0/199678/991ffc5d-9b60-9203-9fb3-c0d724a9511b.png)

特に今までと違う目新しいことはしていないはずです。
正規表現でマッチする文字列を抽出し、setValuesしているだけです。

もし対象URLが大量の場合は処理に時間がかかるので、1行ずつsetValuesする方式ではなく配列を返し、最後に1回でsetValuesするのがスマートな気がしますね。

# おわりに

応用すれば競合のTDを監視して変わった時に通知したり、特定の文字列がある／ないでアラートを出す等の仕組みが考えられそうですね。

# 明日

[【Google Apps Script】その15　Execution APIを使い、外部からAPIとして叩く](https://qiita.com/rf_p/items/2eeb5e5e863fb3f42860)
となります。
今回のアドベントカレンダーで最も肝になる機能を、遂に実装します！！お楽しみに。

前の記事
[【Google Apps Script】その13　スプレッドシート上のグラフを画像として保存やメール送信する](https://qiita.com/rf_p/items/0480d85325811017b715)
次の記事
[【Google Apps Script】その15　Execution APIを使い、外部からAPIとして叩く](https://qiita.com/rf_p/items/2eeb5e5e863fb3f42860)
VivadoをUbuntuの仮想環境に導入する

#はじめに
新しいバージョンのVivadoを試してみたいけどPCの環境を汚したくないなぁ・・・という時，仮想環境を作成してそれにインストールしたいことがあるかもしれません．
LinuxにVivadoをインストールするのは少し手間がかかるので，その手順を共有したいと思います．

#環境
OS : Windows 10 Pro Version 1903
CPU : Intel Core i5 8500 (6コア6スレッド 3.0GHz)
メモリ : 16GB DDR4
ストレージ : 500GB SSD + 2TB HDD

開発ツール : Vivado Design Suite - HL Web PACK

##仮想環境の構築
###VMWare Workstation Playerのダウンロード
まずは以下のURLからVMWare Workstation Playerのインストーラをダウンロードします．
商用利用しない場合無償で，ユーザ登録などは不要です．
https://www.vmware.com/jp/products/workstation-player/workstation-player-evaluation.html



###VMWare Workstation Playerのインストール
次に，ダウンロードしたインストーラを起動し，普通にインストールします．
途中，拡張キーボードドライバをインストールするかどうかのチェックボックスがありますが，無視して大丈夫です．

###BIOSの設定を変更する
インストールが完了したら，PCのBIOSの設定画面を開き「Intel Virtualication Technology」を[Enable]にします．
これをしないと仮想環境がロードされず，エラーが発生します．

###Ubuntu 16.04 LTSのISOイメージのダウンロード
以下のURLからUbuntu 16.04 LTSのISOイメージをダウンロードします．
http://www.ubuntulinux.jp/News/ubuntu1604-ja-remix

※最新のUbuntuを試したい場合はこちら．Vivadoがサポートしているか要確認．
https://www.ubuntulinux.jp/download/ja-remix

###VMWare Workstation PlayerにUbuntuをインストール
- VMWare Workstation Playerを起動し，「ホーム」→「新規仮想マシンの作成」を選択します．
- ウィザードが始まるので，「**後でOSをインストール**」を選択し，次へ進みます．
- ゲストOSの選択画面に入るので，「Linux」，「Ubuntu **64 ビット**」を選択し，次へ進みます．
- 仮想マシンの名前を自由に変更して，次へ進みます．
- **ディスクの最大サイズを100GB以上の値に設定し**，次へ進みます．Vivadoインストール時に60GB近くの容量を食うのでデフォルトの容量ではインストールできません．**Vitisを試したい場合は150GB以上です．**
- 「ハードウェアをカスタマイズ」を選択します．
- 仮想マシンのメモリを2048MB~, プロセッサのコア数を2~4程度に変更します．この値はPCのスペックに応じて変更してください．デフォルト値のままだと動作がもっさりするので注意です．
- 続けて，「新規 CD/DVD(SATA)」→「ISOイメージファイルを使用する」を選択し，ファイルとして先ほどダウンロードしたUbuntuのISOイメージを指定し，「閉じる」をクリックします．![2017-12-17 (4).png](https://qiita-image-store.s3.amazonaws.com/0/217478/c4ffda67-846a-3420-02a7-0e5c5a78ca0d.png)
- 最後に「完了」をクリックします．

###Ubuntuの起動とセットアップ
- VMWareのホーム画面に作成した仮想環境があるので，それをクリックしてから「仮想マシンの再生」をクリックし，仮想環境を起動します．
- Ubuntuのインストールが始まるので，普通にインストールを行います．当然ですが，パスワードはしっかり控えておきましょう．

###パッケージの更新とアップグレード
Ubuntuのインストールが完了したら，パッケージの更新とアップグレードをしておきます．Ubuntuの「端末」を開き，`sudo apt update`と`sudo apt upgrade -y`を実行し，終わったら再起動します．


#UbuntuにVivadoをインストールする
これについてはすでに詳しい記事を書いてる方がいらっしゃったので，[この記事](http://marsee101.blog19.fc2.com/blog-entry-3740.html)を参考にVivadoのインストールを行います．

#まとめ
この手順で仮想環境のUbuntuにVivadoを導入できます．新しいバージョンを試してみたいときに手軽にできるためおすすめです。
Windowsアップデートによってリモートデスクトップできなくなった場合の対処

# 追加修正 (2019.04.19updated)
2018年4月の Windows Update (April 2018 Update 1803) によってまたしても RDP Wrapper でリモートデスクトップが封じられてしまったので対策方法を修正

# 前提
Windows 10 の Windows Update すると時々リモートデスクトップで他PCから入れなくなることが度々ある。特に Windows10 HOME はリモートデスクトップ(RDP)サービスが元々入っていないので RDP Wrapper をインストールして対応するが、これも封じられてしまう。


# 対策
対策としては、termsrv.dll を入手してインストールする方法と rdpwrap.ini に設定を追加する方法があるがここでは後者を説明する（検索すると前者は沢山出てくるので割愛）

1. rfxvmt.dll をコピーする
2. RDP Wrapper をインストールする（2019年4月時点では v1.6.2）
3. rdpwrap.ini に設定を追加

基本的にこれで大丈夫。

## rfxvmt.dll をコピー

もともと C:\Windows\system32 の下にあるリモートデスクトップ／リモートアシスト用のDLLがWindows Update で消されてしまうらしいのでコピーする

手元の rfxvmt.dll が無い場合には下記よりダウンロードしてコピーする。

64-bit Windows 10用: https://github.com/stascorp/rdpwrap/files/1236856/rfxvmt.zip
32-bit Windows 10用: https://github.com/stascorp/rdpwrap/files/1238499/rfxvmt.zip

## RDP Wrapper 最新版をインストール

RDP Wrapper を [Release](https://github.com/stascorp/rdpwrap/releases) よりダウンロード
あとは install.bat -> update.bat する

## rdpwrap.ini に設定を~~追加~~上書き

**2019.07.15追加**
rdpwrap.ini を修正するのが面倒な人は、下記の github （注意：本家から foked されたもの）からダウンロードして使うと良いだろう。
https://github.com/DrDrrae/rdpwrap/blob/master/res/rdpwrap.ini

**以下は古い情報 (2019.07.10まで)**
C:\Program Files\RDP Wrapper\rdpwrap.ini に下記サイトの設定を追加する
rdpwrap.ini は管理者権限でないと修正保存できないのでプロパティ情報を変えるなり管理者権限で修正追加を行う

[Add support for build 10.0.17763.292 #645] (https://github.com/stascorp/rdpwrap/issues/645)

追加する設定

```
;----------------------snip part1
[10.0.17763.292]
; Patch CEnforcementCore::GetInstanceOfTSLicense
LocalOnlyPatch.x86=1
LocalOnlyOffset.x86=AFAD4
LocalOnlyCode.x86=jmpshort
LocalOnlyPatch.x64=1
LocalOnlyOffset.x64=77A11
LocalOnlyCode.x64=jmpshort
; Patch CSessionArbitrationHelper::IsSingleSessionPerUserEnabled
SingleUserPatch.x86=1
SingleUserOffset.x86=4D665
SingleUserCode.x86=nop
SingleUserPatch.x64=1
SingleUserOffset.x64=1322C
SingleUserCode.x64=Zero
; Patch CDefPolicy::Query
DefPolicyPatch.x86=1
DefPolicyOffset.x86=4BE69
DefPolicyCode.x86=CDefPolicy_Query_eax_ecx
DefPolicyPatch.x64=1
DefPolicyOffset.x64=17F45
DefPolicyCode.x64=CDefPolicy_Query_eax_rcx
; Hook CSLQuery::Initialize
SLInitHook.x86=1
SLInitOffset.x86=5B18A
SLInitFunc.x86=New_CSLQuery_Initialize
SLInitHook.x64=1
SLInitOffset.x64=1ABFC
SLInitFunc.x64=New_CSLQuery_Initialize
;.------------------------------------
;

;
;.--------------------------snip part2
[10.0.17763.292-SLInit]
bInitialized.x86 =CD798
bServerSku.x86 =CD79C
lMaxUserSessions.x86 =CD7A0
bAppServerAllowed.x86 =CD7A8
bRemoteConnAllowed.x86=CD7AC
bMultimonAllowed.x86 =CD7B0
ulMaxDebugSessions.x86=CD7B4
bFUSEnabled.x86 =CD7B8

bInitialized.x64 =ECAB0
bServerSku.x64 =ECAB4
lMaxUserSessions.x64 =ECAB8
bAppServerAllowed.x64 =ECAC0
bRemoteConnAllowed.x64=ECAC4
bMultimonAllowed.x64 =ECAC8
ulMaxDebugSessions.x64=ECACC
bFUSEnabled.x64 =ECAD0
;.---------------------------
```

RDP Wrapper を再起動して RDPCheck なり RDPConf でポートが listen 状態か確認

# 参考サイト

https://github.com/stascorp/rdpwrap/issues/645
https://www.rootlinks.net/2019/02/14/rdp-wrapperのtermsrv-dll-ver-10-0-17763-292での対応/
https://qiita.com/aoi70/items/47e521c6a310e3959b35
https://wanderism.net/archives/686
https://github.com/stascorp/rdpwrap/issues/194
組合せ最適化でナンバーリンクを解く

Advent Calendar 16日目の記事 [組合せ最適化で美術館を解く](https://qiita.com/SaitoTsutomu/items/ffccc24e5b6173e8f0a4)
Advent Calendar 18日目の記事 [組合せ最適化で四角に切れを解く](https://qiita.com/SaitoTsutomu/items/7c37ab147c390a1de0a9)

## これなに

**ナンバーリンク**を、Pythonで[組合せ最適化](https://qiita.com/SaitoTsutomu/items/bfbf4c185ed7004b5721)モデルを作って解きます。
解く楽しみは、モデル化を工夫することになります。

自分でも試してみたい人は、下記を参考にしてください。

- [数独を通して組合せ最適化を学ぼう](https://qiita.com/SaitoTsutomu/items/bd09190d8a02432b3f16)

## 問題
* 各マスには2つ以上の線が入ってはいけません
* 異なる線同士が交わってはいけません

下記は、問題と答えです。

![](https://raw.githubusercontent.com/SaitoTsutomu/opt4puzzle/master/pic/numberlink.png)

### 入力パラメータ

`data`に始点と終点が入っているとします。

```py3:python
import numpy as np
from itertools import product
from pulp import LpProblem, lpSum, value
from ortoolpy import addvars, addbinvar, addbinvars
data = np.array([list(s) for s in """\
1.4....
2....3.
...2...
.......
.......
..5.4..
1.3...5""".splitlines()])
data[data == '.'] = '0'
data = data.astype(int)
```

## Pythonで解く

数理モデルを作成し、解きましょう。

### 変数
* vr:どのタイプのラインに含まれるか (1)
* vh:水平に出るかどうか (2)
* vv:垂直に出るかどうか (3)

### 制約
* 始点と終点が指定のラインに含まれること (4)
* 始点と終点は、1本だけ出ること (5)
* 始点終点以外の各マスに接続されるのは、0本か2本 (6)
* 接続したら、両端のタイプは同じになること (7)

```py3:python
mx = data.max()
m = LpProblem()
vr = addvars(*data.shape) # (1)
vh = addbinvars(data.shape[0], data.shape[1]-1) # (2)
vv = addbinvars(data.shape[0]-1, data.shape[1]) # (3)
def dirs(i, j):
    return ([vh[i][j - k] for k in range(2) if 0 <= j-k < data.shape[1] - 1]
          + [vv[i - k][j] for k in range(2) if 0 <= i-k < data.shape[0] - 1])
for i, j in product(range(data.shape[0]), range(data.shape[1])):
    s = dirs(i, j)
    if data[i][j]:
        m += vr[i][j] == data[i][j] # (4)
        m += lpSum(s) == 1 # (5)
    else:
        m += lpSum(s) == 2 * addbinvar() # (6)
    if i < data.shape[0] - 1:
        m += vr[i][j] <= vr[i + 1][j] + mx * (1 - vv[i][j]) # (7)
        m += vr[i + 1][j] <= vr[i][j] + mx * (1 - vv[i][j]) # (7)
    if j < data.shape[1] - 1:
        m += vr[i][j] <= vr[i][j + 1] + mx * (1 - vh[i][j]) # (7)
        m += vr[i][j + 1] <= vr[i][j] + mx * (1 - vh[i][j]) # (7)
m.solve()
```

### 結果の表示

```py3:python
print(np.vectorize(value)(vr).astype(int))
>>>
[[1 1 4 4 4 4 4]
 [2 1 1 1 1 3 4]
 [2 2 2 2 1 3 4]
 [1 1 1 1 1 3 4]
 [1 3 3 3 3 3 4]
 [1 3 5 5 4 4 4]
 [1 3 3 5 5 5 5]]
```

解けていることが確認できます。

以上
絶対に作業できない作業用BGMサイト

[クソアプリ Advent Calendar 2017](https://qiita.com/advent-calendar/2017/kuso-app2017) 17日目の記事です.
[10日目にも投稿しました](https://qiita.com/de_teiu_tkg/items/c938fbb52218185659e7)が、カレンダー上でこの日だけ空いていたので、もう一本書きました。

#前置き
コーディングをする時は何かしらの作業用BGMを聞きながらやる、という人は結構多いと思います。好きなアーティストの曲だったり、雨の音などの環境音を聞きながら作業すると捗りますよね。


ということで今回は、開くだけで作業用BGMが流れるWebアプリを作成してみました。

#成果物
ひたすらブーイングを受ける作業用BGMサイトです。

デモは以下
(**注意：わりと大きめの音が鳴ります**)
[Booooooo](https://de-teiu.github.io/booing/)

<img width="813" alt="キャプチャ.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/173272/59b625e4-4a48-c3de-7ed2-644146cd3fa6.png">



#これ聞きながらコーディングできる？
つらそうです。

#解説(mp3再生について)
今回も[p5.js](https://p5js.org/)を使用して作りました。
mp3ファイルの再生にはp5.jsの拡張ライブラリである[p5.sound.js](https://p5js.org/reference/#/libraries/p5.sound)を使用しています。

ソースは[こちら(GitHub)](https://github.com/de-teiu/booing)にあります。



## mp3を再生するオブジェクトの定義
まず用意するfunctionはこんな感じ

```js:bgm.js
/** ブーイング再生用オブジェクト定義 */
function Booing() {
    var FILE_PATH = 'https://raw.githubusercontent.com/de-teiu/booing/master/js/sound/81191__payattention__booooooo.mp3';


    //1つの音をうまいこと途切れないようにループ再生するため、mp3を読み込んだオブジェクトを2つ用意
    this.startDate = new Date();
    this.bgm1 = loadSound(FILE_PATH);
    this.bgm2 = loadSound(FILE_PATH);
};
```

GitHub Pagesを使用して動かす場合、読み込みたいmp3ファイルのパスは絶対パスにする必要があるようです。
(相対パスで指定したら読み込みに失敗しました。もしかしたら何かしらの手順が必要？)
というわけで、ひとまずFILE_PATHには読み込むmp3ファイルを絶対パスで指定しています。

また、mp3ファイルを読み込んだオブジェクトを２つ用意しています(理由は後述)。

## ループ再生処理

以下の処理をmain.jsから毎フレーム呼び出しています。

```js:bgm.js
/** ループ再生 */
Booing.prototype.loopPlay = function () {

    //BGMが鳴ってなかったら再生
    if (!this.bgm1.isPlaying() && !this.bgm2.isPlaying()) {
        this.bgm1.play();
    }

    //再生が終了するあたりのタイミングでもう片方のBGMを再生開始
    var now = new Date();
    if ((now.getTime() - this.startDate.getTime()) / 1000 >= 22) {
        this.bgm1.isPlaying() ? this.bgm2.play() : this.bgm1.play();
        this.startDate = now;
    }
};
```

曲の再生時間を常に計っておき、再生が終わる直前にもう片方の音声オブジェクトの再生を行っています。
これを繰り返すことで、途切れることなくBGMが流れます。

p5.soundの機能で再生位置とか取得したりすればもう少しスマートに書けそうです(調査中)。
Rust と C++17 のソースコードを混ぜてビルドする

# Rust と C++17 のソースコードを混ぜてビルドする
## 動機
* C や C++ で書かれたライブラリを利用しつつ、 Rust を書きたい
* https://crates.io/crates/cc というライブラリを使う
* cargo による rust のコンパイル時に C++ のコンパイルもいっしょにできる
* これで C や C++ のライブラリの FFI をいちから手書きするのではなく、 C や C++ のライブラリを呼ぶ部分は C++ で書いておいて Rust から呼ぶということができる

## 導入
* Cargo.toml に cc を追加する

```rs:Cargo.toml
[package]
name = "hello-rs"
version = "0.1.0"
links = "hello"
build = "build.rs"

[build-dependencies]
cc = { version = "1.0", features = ["parallel"] }

[dependencies]
libc = "0.2"
```

* parallel は make -jN 相当の並列コンパイル
* libc は char や int などの C API の型が定義されている - https://crates.io/crates/libc
* links - は依存ライブラリを記述するもの - http://doc.crates.io/build-script.html#the-links-manifest-key

## C++ のコードを書く
```c:src/cpp/include/hello.h
#pragma once

#ifdef __cplusplus
extern "C" {
#endif

  void hello();
#ifdef __cplusplus

}
#endif
```

```cpp:src/cpp/src/hello.cpp
#include <iostream>
#include <string>

void hello(){
  std::cout << "hello cpp" << std::endl;
}
```

* 基本的には C API で書くので Rust から呼び出す関数は C の型を使う

## Rust で C の FFI を書く

```rs:src/main.rs
extern crate libc;

use libc::{ c_void, c_char, size_t };
use std::ffi::{ CStr, CString };

#[link(name = "hello", kind = "static")]
extern "C" {
  fn hello();
}

fn main() {
  unsafe{
    hello();
  }
}
```

* ffi の書き方は公式ドキュメントを参考に - https://rust-lang-ja.github.io/the-rust-programming-language-ja/1.6/book/ffi.html


## build.rs に C++ コードのビルド方法を記述する

```rs:build.rs
extern crate cc;

fn main(){
    println!("cargo:rustc-link-search=native=/usr/local/lib");
    cc::Build::new()
        .cpp(true)
        .warnings(true)
        .flag("-std=c++17")
        .flag("-Wall")
        .flag("-Wextra")
        .flag("-v")
        .flag("-g")
        .file("src/cpp/src/hello.cpp")
        .include("src/cpp/include")
        .compile("libhello.a");
}
```

* flag はひとつづつ書く
* 任意のバージョンの c コンパイラを使いたい場合は環境変数に指定する
    * `env CXX=/usr/bin/g++-7 cargo build`
    * `env CXX=/usr/bin/g++-7 cargo run`


## 参考
* http://mmi.hatenablog.com/entry/2017/02/28/213656
コンソールゲーム制作 第1章 描画(2)

## 前回
[コンソールゲーム制作 第1章 描画(1)](https://qiita.com/selector828/items/1e7463f3363875651e8b)
前回はコンソール用の出力関数の一覧を確認できたので、コンソールの構造を考えながら適切な関数を選んでいきます。

# コンソールの構造
実際に使ってみた自分なりの解釈ですが、コンソールの構造はこんな感じです（必要な情報のみ)

**コンソール**

|要素|備考|
|:-----------------|:------------------|
|スクリーンバッファ|画面に表示される情報の格納庫|
|カーソル|入力用の情報の格納庫|

**スクリーンバッファ**

|要素|備考|
|:-----------------|:------------------|
|セル[文字数分]|1マスに格納されている情報|
|フォント|画面に文字を書き込む際のフォント情報|

**カーソル**

|要素|備考|
|:-----------------|:------------------|
|色|書き込む際の文字色とその背景色|
|座標|書き込み位置|

**セル**

|要素|備考|
|:-----------------|:------------------|
|文字|セルに表示される文字|
|色|セルに表示される文字色とその背景色|

# 出力関数の仕様
上記のコンソールの仕様を基にそれぞれの出力関数の仕様を解説していきます。

画面サイズを横40, 縦10だとします。
`x >= 0 && x < 40 ( x = 0 ~ 39 )
y >= 0 && x < 10 ( y = 0 ~ 9 )`

まずは、

- **SetConsoleTextAttribute**：カーソルの色（文字、背景）を設定します。

`色(赤, 青)`を設定すると

`コンソール->カーソル->色 = 赤 | 赤`

- **SetConsoleCursorPosition**：カーソル位置を設定します。

`位置(6, 3)`を設定すると

`コンソール->カーソル->位置 = (6, 3)`

- **FillConsoleOutputAttribute**：指定位置から指定したセル分の色（文字・背景）を再設定する。

`位置(x=5, y=5)、セル数(3)、文字色(青)、 背景色(赤)`を指定すると、

`コンソール->スクリーンバッファ->セル[5][5]->色 = 青 | 赤
コンソール->スクリーンバッファ->セル[6][5]->色 = 青 | 赤
コンソール->スクリーンバッファ->セル[7][5]->色 = 青 | 赤`

の３マスが一気に塗りつぶされます。

xは39までなのでもし、`位置(x=38, y=5)、セル数(3)、文字色(青)、 背景色(赤)`を指定すると、

`コンソール->スクリーンバッファ->セル[38][5]->色 = 青 | 赤
コンソール->スクリーンバッファ->セル[39][5]->色 = 青 | 赤
コンソール->スクリーンバッファ->セル[0][6]->色 = 青 | 赤`

という風に次の行にずれます。

- **FillConsoleOutputCharacter**：指定位置から指定したせる分の文字を再設定する。

`位置(x=5, y=5)、セル数(3)、文字色('A')`を指定すると、

`コンソール->スクリーンバッファ->セル[5][5]->文字 = 'A'
コンソール->スクリーンバッファ->セル[6][5]->文字 = 'A'
コンソール->スクリーンバッファ->セル[7][5]->文字 = 'A'`

今度はその範囲を文字で埋めます。

- **WriteConsole**：指定した位置から指定した文字列を書きこむ。

WriteConsoleの場合は位置を指定して文字列をその位置から書き込むだけです。

`位置(x=5, y=5)、文字列("abc")`を指定すると、

`コンソール->スクリーンバッファ->セル[5][5]->文字 = 'a'　色 = カーソルの色
コンソール->スクリーンバッファ->セル[6][5]->文字 = 'b'　色 = カーソルの色
コンソール->スクリーンバッファ->セル[7][5]->文字 = 'c'　色 = カーソルの色`

になります。色に関してはSetConsoleTextAttributeで指定した色になります。

標準出力関数のprintfの中でもこれが使われています。

- **WriteConsoleOutputAttribute**：指定した長方形ブロックに含まれる文字セルに、色（文字・背景）の再設定します。

FillConsoleOutputAttributeとほとんど同じですが、書き込む際の画面内の範囲が決められます。

- **WriteConsoleOutputCharacter**：指定した長方形ブロックに含まれる文字セルに、色（文字・背景）の再設定します。

FillConsoleOutputCharacterとほとんど同じですが、書き込む際の画面内の範囲が決められます。

- **WriteConsoleOutput**：指定した長方形ブロックに含まれる文字セルに、文字と色(文字、背景)。

WriteConsoleOutputAttributeとWriteConsoleOutputCharacterを混ぜたものです、
唯一色と文字が同時に変えられるので優秀です。

# 結論
**WriteConsoleOutput**を使いましょう。

理由としては、一瞬で画面全体を書き直せるからです。
少しずつ画面を書き換えると、書き終わった場所と終っていない場所の差が見えてしまって、画面がチラついてゲームになりません。

色を変えるだけでしたら、FillConsoleOutputAttributeまたはWriteConsoleOutputAttributeでもいいですが、ゲームとはいえ意外と文字も活躍します。（いつか文字の応用の仕方の記事を書きます）

# 次回
適切な関数はWriteConsoleOutputでした、次は実際の例をあげて使い方を説明します。
テスト駆動開発による組み込みプログラミングをgoogletestでやる

# はじめに

[Amazon.co.jp: テスト駆動開発による組み込みプログラミング ―C言語とオブジェクト指向で学ぶアジャイルな設計](https://www.amazon.co.jp/%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9%96%8B%E7%99%BA%E3%81%AB%E3%82%88%E3%82%8B%E7%B5%84%E3%81%BF%E8%BE%BC%E3%81%BF%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E2%80%95C%E8%A8%80%E8%AA%9E%E3%81%A8%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%81%A7%E5%AD%A6%E3%81%B6%E3%82%A2%E3%82%B8%E3%83%A3%E3%82%A4%E3%83%AB%E3%81%AA%E8%A8%AD%E8%A8%88-James-W-Grenning/dp/4873116147)

本記事は、上記書籍を使って学習を始める人が、環境構築で躓かないようにしたい、という主旨のシリーズ第1弾です。

私は組込みシステム開発をしており、C言語をメインに使っています。
この本に出合う前は、コードを修正するたび、クロスビルドして、ターゲットボードにバイナリをコピーして動作確認をしていました。ハードウェアはチーム人員に対して十分な量がないため、他のメンバーがハードウェアを使っているときは、動作確認できず、開発が滞ることも多かったです。

今年の2月に、この本に出会い、書かれていることを業務でも実践するようになりました。
結果として、私の開発スタイルがガラっと変わりました。デュアルターゲットのビルド環境を整え、ハードウェアがなくても、ホスト上でユニットテストベースの開発を行えるようになり、自動ユニットテストにより、ちょっとしたミスがすぐに見つかるようになりました。
自分の書いたコードの品質にも少しだけ自身が持てるようになってきました。

今や、新しく追加する機能は、全てTDDで開発し、既存箇所にも時間を見つけてテストを書き、容赦ないリファクタリングを続けています。
コードは改修を重ねるたびに、より読みやすく、良い設計に進化していると感じています。

本書では、テスティングフレームワークとして、UnityとCppUnitが紹介されています。
そのままやるのも芸がないと考えたのと、本書を勉強する上で後述する躓きがあったため、今回、googletestを使ってすぐに本書の勉強が始められるソースコードを公開することにしました。

ビルドツールにはAutotoolsを使っています。そのため、公開しているソースコードは、クロスコンパイラでそのままクロスビルドすることが可能です。
googletestは、インストールなしで動作するので、クロスビルドしたバイナリをターゲットボードにポンっと置けば、ターゲットボード上でユニットテストが動きます。

# 学習する上で躓いたこと

本書を読み進めながら、Unity, CppUnitを使って写経しようとしましたが、恥かしながら、環境構築で躓きました…。（何で躓いたか、もう忘れてしまったのですが、なんだかんだで1日くらい格闘していたと思います）
また、公開されているサンプルコードでは、ビルドスクリプトが（自分にとっては）複雑で、自分でちょっと拡張したい、ということが簡単にはできませんでした。
ちょっとしたことなのですが、学びたいこと以外のところで躓くと、学習意欲が削がれやすいです。

組込み業界入りたての人でも、自分でファイル追加して、写経できるような環境を考えて、作ってみました。

# ソースコード

ソースコードは以下です。
https://github.com/tomoyuki-nakabayashi/TDDforEmbeddedC

4章終了時点のプロダクトコードとテストコードを公開しています。
git, gcc, autotoolsがインストールされていれば、1分以内にテストが実行できます。

本書を最初から写経したい方は、src/LedDriver.c, src/LedDriver.h, test/LedDriverTest.cppの中身を削除して下さい。


# ソースファイルの追加

自分でソースファイルを追加して、色々試してみたい場合には、下記ファイルの該当箇所にファイル名を追加して下さい。
TDDforEmbeddedC/test/Makefile.am

```
test_sources = \
  TestMain.cpp \
  LedDriverTest.cpp
target_sources = \
  $(top_srcdir)/src/LedDriver.c
gtest_SOURCES = $(test_sources) $(target_sources)
```

# テストダブルとmock

本書の7章以降では、テストダブルとmockの話が掲載されています。
残りの内容に関しても、写経を簡単に始められる環境を整備しました。

[テスト駆動開発による組み込みプログラミングをgoogletestでやる8章](https://qiita.com/tomoyuki-nakabayashi/items/19014f5904cfe2d860f8)
[テスト駆動開発による組み込みプログラミング～モック＆フラッシュドライバ編～](https://qiita.com/tomoyuki-nakabayashi/items/859f1ca077332d4197f6)
[テスト駆動開発による組み込みプログラミングをgoogletestでやる～SOLIDな設計編～](https://qiita.com/tomoyuki-nakabayashi/items/751cdb12157228367c79)

## 追記

CMakeに対応しました。
オープンソース MAツール Mautic と外部サービスを AWS Lambda を使用してデータ連携

オープンソース MAツールの Mautic と外部サービス（自社で運営している Webサービス）のデータを、AWS Lambda を使用して連携したので記事にします。

## 連携の目的
- 自社サービスのデータの一部を Mautic のコンタクトと連携（Mautic 側に保持）させて、Mautic で作成するキャンペーンのシナリオ等で利用。

## 連携概要図
Mautic と自社サービスのデータをそれぞれ同期するために、Mautic と自社サービスのトリガーごとに Lambdaファンクションを作成してデータ連携

<img width="1419" alt="スクリーンショット 2017-12-16 22.16.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/22986/653c7f23-03b7-0fdd-c340-fa859bbd0790.png">

## 作業概要
### 1. カスタムフィールドの作成
- Mautic のコンタクトに保持したい自社サービスのデータ用のカスタムフィールドを作成

### 2. Webhook の作成
- API Gateway のエンドポイントを「ウェブフック POST URL」に設定
- 「ウェブフックイベント」は「新規のコンタクトイベント」を選択

### 3. Lambdaファンクションの実装
#### Mauticトリガーファンクション
- Mautic に新規コンタクトが作成された時、自社サービスのデータを参照して紐づくデータが見つかった場合、コンタクト情報に自社サービス情報を取り込むファンクション
- 連携フロー
    - ①：新規コンタクト追加イベントにより Webhook を送信
    - ②：コンタクトと紐づくデータが自社サービスにあるか検索
    - ③：もしあれば自社サービスの情報を返却
    - ④：Mautic API でコンタクト情報を更新

#### 自社サービストリガーファンクション
- 自社サービスのデータが新規追加、更新、削除された時、Mautic のコンタクト情報の自社サービスのカスタムフィールドを更新するファンクション
- 連携フロー
    - ①：自社サービスデータが新規追加、更新、削除を検知
    - ②：Fluentd で Lambdaファンクションを実行
    - ③：新規追加、更新、削除が行われた自社サービスデータと紐づくデータが Mautic側にあるか検索
    - ④：もしあれば Mautic のコンタクト情報を返却
    - ⑤：返却されたコンタクト情報を元に、自社サービスのデータを検索
    - ⑥：コンタクトに保持したい自社サービスのデータを返却
    - ⑦：Mautic API でコンタクト情報を更新

## 苦労した点
- Mautic の画面からコンタクトを作成したときと、CSVインポートでコンタクトを作成したときの Webhook のペイロードが異なること
    - 画面からコンタクトを作成するとコンタクト情報がペイロードとして送られてくるが、CSVインポートした場合、コンタクト情報が送られてこない（送られてくるのは、コンタクトID といくつかのタイムスタンプくらい）
- コンタクト情報を取得する Mautic API で contact_id 以外での検索ができない
    - contact_id がわかっていれば `GET /contacts/ID` でいいが、メールアドレスなどからコンタクト情報を取得したい場合は、`GET /contacts` の `search` パラメータの利用しかできず、前方一致のみになってしまい、不完全な検索になる
    - コンタクト情報の取得は、Matuic API を利用せず、Mautic の DB を Lambdaファンクションから直接参照して回避

## 総評
- 多少苦労したものの、わりと低コストで外部データ連携が実現可能
- AWS等のクラウドサービスをうまく組み合わせれば、アイデアしだいで Mautic の可能性が広がることを実感
PythonのoepnpyxlでテンプレートファイルからExcel帳票を作成する

## 1. はじめに

以前にxlsxwriterを利用したExcelの作成について記事にしましたが、xlsxwriterではExcelの読み込みができないことが分かりました。そこで今回は[oepnpyxl](https://openpyxl.readthedocs.io/en/default/)を利用して、事前に用意したExcelテンプレートファイルからExcel帳票を作成する方法について説明したいと思います。

**（以前の記事）**

* [PythonでGitBucketのIssueをExcel出力する（Excel出力編）](https://qiita.com/5zm/items/282956dbc1b4f6813108)
* [PythonでGitBucketのIssueをExcel出力する（その後）](https://qiita.com/5zm/items/b0b620cdeb9596108418)

## 2. ソースコード

```python:excelReportWithOpenpyxl.py
# -*- coding: utf-8 -*-
import openpyxl
import datetime

# report excel using template file
def write():
    # ★ポイント1
    # テンプレートファイルを読み込む
    workbook = openpyxl.load_workbook('reservationTemplate.xlsx')
    # ゼロからExcelファイルを作る場合
    #  workbook = openpyxl.Workbook()

    # ★ポイント2
    worksheet = workbook.get_sheet_by_name(u'予約')

    # ★ポイント3
    # 行、列は1開始のインデックス
    worksheet.cell(row=5, column=6).value = unicode('12345678', 'utf-8')

    # ★ポイント4
    # 書式フォーマットは再設定が必要
    currentFormat = worksheet['AA5'].number_format
    worksheet['AA5'].value = datetime.date.today()
    worksheet['AA5'].number_format = currentFormat

    # ★ポイント5
    workbook.save('reservation.xlsx')

if __name__=='__main__':
    write()
```

**★ポイント1**

最初に`openpyxl.load_workbook()`でExcelのワークブックのインスタンスを生成します。
引数には読み込むExcelテンプレートファイルのファイル名を指定します。

ちなみに、ゼロからExcelファイルを作成する場合は`openpyxl.Workbook()`でワークブックのインスタンスを生成します。

**★ポイント2**

次に`workbook.get_sheet_by_name()`でワークシートを選択します。
引数にはワークシート名を指定します。unicodeで指定すれば日本語のシート名でも動作します。

**★ポイント3**

セルの選択方法はR1C1形式（行と列を個別に指定）とA1形式の２つがあります。
R1C1形式の場合、`worksheet.cell(row=行番号, column=列番号)`でセルを選択します。
**行番号と列番号は0ではなく1から開始するので注意してください。**
`value`属性でセルの値にアクセスできるので、これで値の読み取りや変更を行います。

**★ポイント4**

A1形式の場合、`worksheet['A1']`でセルを選択します。値の参照、変更はR1C1形式と同様に`value`属性を利用します。

**(書式フォーマットに関する注意)**

テンプレートファイルで書式フォーマットを設定している場合、`number_format`で値を設定する前にフォーマットを取得して、値を設定した後、事前に取得したフォーマットを`number_format`で再設定してください。
**自分の環境では再設定しないとテンプレートで設定したフォーマットが反映されませんでした。**

**★ポイント5**

最後に`workbook.save()`でファイルに書き込みます。
引数には保存する際のファイル名を指定します。

## 3. さいごに

今回はoepnpyxlを利用して、事前に用意したExcelテンプレートファイルからExcel帳票を作成する方法について説明しました。
もともとxlsxwriterだとExcelファイルの読み込みができないことが今回の記事の始まりでした。xlsxwriterの機能をしっかりと調査していれば、読み込みも書き込みも可能なoepnpyxlを最初から利用していたと思います。
今後ライブラリを選定する際は、利用可能な機能を事前にしっかりと調査していきたいと思います。