OmniAICreator/Qiita-1.07M huggingface dataset:
gitlab ce をdockerコンテナでMac上に構築してみる

# gitlab ceをダウンロードして構築する。

自分のmacを無職になったのを機に開発用として、OSをクリーンインストールしたので、いろいろ遊んでみる。
最新版のGitlabをMac上に、dockerコンテナで構築して、自分のコードとかを保管しておく環境を作ってみる。

まず、情報収集から、検索ワード的には、「gitlab docker mac 構築」とかで検索しました。

- Dockerのimageは、docker hubにありそう。
 - EEは、エンタープライズエディションらしいので、有償です。
 - CEは、コミニュティエディションらしいので、無料で使えます。
検索ワード： gitlab ee ce 違い

```
dev@devPC ~ % sudo docker pull gitlab/gitlab-ce:latest
latest: Pulling from gitlab/gitlab-ce
fe703b657a32: Pull complete 
f9df1fafd224: Pull complete 
a645a4b887f9: Pull complete 
57db7fe0b522: Pull complete 
51f2452df587: Pull complete 
ca20bb0d0d35: Pull complete 
03b677c603dc: Pull complete 
a5cc90bd1eae: Pull complete 
fb67a436809a: Pull complete 
1295d3cf7f16: Pull complete 
Digest: sha256:fb97fba1e925dce93750bea9d51695c369250a99534793775c2c4fcb0a83bc3b
Status: Downloaded newer image for gitlab/gitlab-ce:latest
docker.io/gitlab/gitlab-ce:latest
dev@devPC ~ % 

```

docker imageのダウンロードをしてみた。起動コマンドはこんな感じです。

```
dev@devPC ~ % sudo docker run \                      
--hostname gitlab.example.com \
--publish 443:443 --publish 10080:80 --publish 22:22 \
--name gitlab_kun \
--restart always \
--volume /Users/dev/gitlab:/etc/gitlab \
--volume /Users/dev/gitlab:/var/log/gitlab \
--volume /Users/dev/gitlab:/var/opt/gitlab \
gitlab/gitlab-ce:latest
```
このコマンドをうって、PCからlocalhost:10080にアクセスすると、接続することができました。

- オプションの説明です。
 - --publish (いつも -p って書いてるから、portの略かとおもったら、publishだったのか・・・・)
     - ホスト側のポート：コンテナ側のポート
     - 例えば、上のコマンドだとホストの10080にアクセスすると、コンテナの80ポートにアクセスすると言う意味です。そのため、gitlabのwebにアクセスすることができます。

 - --volumeについては、ホストとコンテナのデータをバインドするための設定です。
     - コンテナの中のデータは、コンテナが消えたときに一緒に破棄されてしまうので、バインドしておくことでホスト側にデータを保存しておくことができます。


gitlab-ctlコマンドで、いろいろできます。
設定を変えて変更したければ、gitlab-ctl reconfigure
ステータスをログをみたい場合には、gitlab-ctl status

```
root@gitlab:/# gitlab-ctl status
run: alertmanager: (pid 1489) 827s; run: log: (pid 610) 1228s
run: gitaly: (pid 251) 1296s; run: log: (pid 278) 1294s
run: gitlab-exporter: (pid 546) 1247s; run: log: (pid 548) 1246s
run: gitlab-workhorse: (pid 1461) 828s; run: log: (pid 513) 1264s
run: grafana: (pid 1511) 826s; run: log: (pid 1328) 886s
run: logrotate: (pid 533) 1253s; run: log: (pid 539) 1252s
run: nginx: (pid 523) 1260s; run: log: (pid 529) 1258s
run: postgres-exporter: (pid 1502) 826s; run: log: (pid 625) 1222s
run: postgresql: (pid 288) 1289s; run: log: (pid 373) 1287s
run: prometheus: (pid 1477) 827s; run: log: (pid 587) 1234s
run: redis: (pid 238) 1298s; run: log: (pid 248) 1297s
run: redis-exporter: (pid 1469) 828s; run: log: (pid 564) 1240s
run: sidekiq: (pid 491) 1272s; run: log: (pid 497) 1270s
run: sshd: (pid 22) 1318s; run: log: (pid 21) 1318s
run: unicorn: (pid 468) 1278s; run: log: (pid 485) 1276s
root@gitlab:/# 
```
Pythonでウェブスクレイピング

# ウェブスクレイピングをしよう

自分用メモ。
yahoojapanのニューストピック(https://news.yahoo.co.jp/topics)
ここでは題名をスクレイピング->テキストファイルに保存まで。

### ライブラリインポート
```Python
import requests
from bs4 import BeautifulSoup
```

### GETリクエスト
```Python
##プロキシ下の環境だったためプロキシ設定
proxies = {
 "http":"プロキシURL"
 "https":"プロキシURL"
}
##オプションにプロキシ設定し、GETリクエストを投げる
req = request.get('https://news.yahoo.co.jp/topics',proxies=proxies)
```

### BeautifulSoupでスクレイピング実行->リスト化

BeautifulSoup().find_allのオプション引数は"class"でなく"class_"であることに注意
classだとPythonの予約語になってしまう。

```Python
yahoo = BeautifulSoup(req.content,"html.parser")
topics_list_items = yahoo.find_all("li" ,class_="topicsListItem")#yahoojapanHPの仕様でこのclass。
### 文字列のみ抜き出してリスト化
topics_list_text = []
for topics_list_item in topics_list_items:
    topics_list_text.append(topics_list_item.text)
```

### テキストファイルに保存する
```Python
f = open('topiclist.txt','w')#ファイルは自動的に生成
for topic in topics_list_text:
    f.write(str(topic)+'\n')#一行に一トピックという加工
f.close()
```

# 所感
BeautifulSoupを初めて使ったがとても明瞭で簡単。逆に言えばブラックボックス。
ただfind_allだとget_textのメソッドはなく、for文で取り出さないといけないみたい。
いずれにせよとても簡単にできた。時代は進んでいる…
以上っす。
Qiskitで任意のユニタリー行列から量子ゲート(量子回路)を作る

ここ数ヶ月何度か同じコードが必要になる(聞かれる)ケースがあったので、コードサンプルを載せておきます。
何かしようとすると意外と使いたい機能な気がします。  
コードは2020/3/13現在のものです。
もし間違いがあったら教えてください。  

```
from qiskit import QuantumCircuit
from qiskit.quantum_info.operators.operator import Operator
import numpy as np

# 任意の数の量子ビットと古典ビットを持つ量子回路を用意(今回は適当に2qubit)
qc = QuantumCircuit(2,2)

# ユニタリー行列を用意(今回は適当に単位行列)
unitary = np.array([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]])

# ユニタリー行列からオペレーターを作成
operator = Operator(unitary)

# 量子回路(qubit0番と1番)にオペレーターを作用(ユニタリーでなかった場合はエラーが出る)
qc.append(operator, [0,1])

# 実行する部分は省略
```
NPOIを使ってセル内の文字列の細かい書式を取得する方法

## 実現したいこと

1つのセル内の文字の細かい書式情報(太字、斜体、色、などなど)を取得したい。 
例えば、こんな文字列。
![コメント 2020-03-13 121546.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592672/d9d8487f-6972-a9f1-8918-69062c1f170d.png)

記事が見つからなかったので、公式ドキュメント読んで頑張ってみました。

## 環境

.NET 4.8
NPOI 2.4.1

※対象となるファイル形式は、.xlsx のみ。.xls では動作しません。

## 結果

いい感じに取得できました。
![コメント 2020-03-13 120925.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592672/bbae58e2-4691-3a3d-dd25-24172fe72096.png)


ソースは[こちら](https://github.com/TRyota-lab/NPOI-Examples/tree/master/RichStringSample)

## 解説

ポイントは `ICell.RichStringCellValue` を `IRichTextString` から `XSSFRichTextString` へキャストしてあげることです。

```csharp
var xssfStr = (XSSFRichTextString)cell.RichStringCellValue;
```

`IRichTextString` のままではExcelの旧フォーマット(.xls)との抽象化のため、用意されたプロパティやメソッドが少なく、取得できる情報がほとんどありません。`XSSFRichTextString` であれば、細かい書式情報のプロパティが公開されているため出来ることが多くなります。

また、各文字ごとの書式は `Run` と呼ばれる単位で取得します。`Run` は1つ以上の文字の塊で、何らかの書式が変わった区切りで生成されます。この `Run` をループで処理しすべての文字の書式を取得します。取得する際には、先ほどと同様に `IFont` を `XSSFFont` へキャストしてから行います。

```csharp
for (int runNo = 0; runNo < xssfStr.NumFormattingRuns; runNo++)
{
  var xssfFont = (XSSFFont)xssfStr.GetFontOfFormattingRun(runNo);
```

サンプルでは、以下の情報を取得します。
それぞれの詳しい説明は [公式ドキュメント](https://poi.apache.org/apidocs/dev/org/apache/poi/xssf/usermodel/XSSFFont.html "Class XSSFFont") を確認してください。

```csharp
// フォント名
$"Font:{xssfFont.FontName}, " +
// フォント色(16進)
$"Color:{xssfFont.GetXSSFColor()?.GetARGBHex()}, " +
// フォントサイズ(ポイント)
$"Size:{xssfFont.FontHeightInPoints}, " +
// 太字
$"Bold:{string.Format("{0, 5}", xssfFont.IsBold)}, " +
// 斜体(イタリック)
$"Italic:{string.Format("{0, 5}", xssfFont.IsItalic)}, " +
// 下線
$"Underline:{string.Format("{0, 6}", xssfFont.Underline)}, " +
// 取り消し線
$"Strikeout:{string.Format("{0, 5}", xssfFont.IsStrikeout)}, " +
// 上付き(Super)/下付き(Sub)
$"TypeOffset:{string.Format("{0, 5}", xssfFont.TypeOffset)}");
```

下線については以下の種類が取得できるようです。

```csharp
public enum FontUnderlineType : byte
{
  None = 0, // 無し
  Single = 1, // 下線
  Double = 2, // 二重下線
  SingleAccounting = 33, // 下線(会計)
  DoubleAccounting = 34 // 二重下線(会計)
}
```

![コメント 2020-03-13 124241.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592672/42ec2b77-64ab-298f-a33b-d157e2223203.png)

## 終わりに

旧形式(.xls)は無事死亡。
MAMPでtimezoneを変更する手順

# はじめに
mampを使って現在時刻を表示させたら、実際の時刻と違いました。
調べたところphp.iniのtimezoneで変更が可能とのことでした。
試したところ簡単にはうまくいかなかったので備忘録としてメモします。
MAMPは導入済みとします。

# phpのバージョンの確認
デスクトップ上部左の「MAMP」をクリック(下図)して「preferences」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580653/54da6c85-859a-253a-5b12-037cd5aeaf8f.png)

phpのバージョンを確認。下記画像だとバージョン7.4.2になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580653/9644fdd7-fb83-fc27-b987-5ff4fba3cd1d.png)
# php.iniの編集
下記場所のphp.iniを開きます。

/Applications/MAMP/bin/php/php7.4.2/conf

- phpフォルダの中では先ほど確認したバージョンと同じバージョンのフォルダを選択します。
- 下記のようにコードを変更します。
- 標準設定ではtimezoneが"Europe/Berlin"に設定されているので"Asia/Tokyo"に変更します。
- 初心者は見落としがちですが、コメントアウト「；」されているので解除します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580653/d14b4993-caa0-e1c9-52cd-848e577de5a5.png)
　　　　　　　　　　　　　　　↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580653/ac497779-e4ad-1839-87a5-7c276b058dba.png)

※フォルダ内検索でphp.iniを検索するとたくさん出てきますが、上記ディレクトリ内のファイルであること、phpのバージョンが合っているこで変更は反映されます。
Apacheのサーバーを再起動します。(下図)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580653/766786a4-2d15-207f-db6a-6459147f3a91.png)
これでプラウザを更新すれば日本時間に変更されます。
【ECS】 【Fargate】TASK実行container内でTask ID を取得するスクリプト

調べてもあまりいい方法がなかったので、ゴリゴリですがとりあえず作ってました。

# TD;DR

* curlとpython -cを使ってやりました。 
* [タスクメタデータエンドポイントバージョン 3](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task-metadata-endpoint-v3.html)を使用
    * サポートバージョンは以下の通り
        * EC2：1.21.0以降のバージョン
        * Fargate ： v1.3.0以降のバージョン

* curlで`${ECS_CONTAINER_METADATA_URI}/task`を取得、pythonでparseしてTaskARNから取得

```bash
#!/bin/bash

METADATA=$(curl ${ECS_CONTAINER_METADATA_URI}/task)
python3 -c "import json; meta=json.loads('$METADATA'); task_id=meta['TaskARN'].split('/')[-1]; print(task_id)" > ./task_id
TASK_ID=$(cat ./task_id)
```

# TASK IDが取りたい

* TASK実行container内でTask IDをもとに処理したいときがあった
* けど、環境変数は用意されてない
* METADATAはとれるので、そこからparseした


# まとめ

* 一応取ることはできた
* けど、本当はTASK実行container内でやることではない気がする
* 普通に環境変数用意してほしい


# 参考

* [ECSにおけるタスクメタエンドポイント(Task Metadata Endpoint)について整理しました](https://dev.classmethod.jp/tool/docker/ecs_task-metadata-endpoint/)
dockerで簡単にnginxを動かす

## tl; dr
+ 例えば、nginxの設定ファイルを変更したい時にローカルでサクッと確認できると楽だわーって思うことないですか？それをできるようにします

+ 今回はその辺りの設定ことと、若干原始的な方法で、インストールなどもやって、ワンポチにはしないようにします


まず、dockerを立てます<>は任意の文字でOKです

```
$docker run --name <ubuntu-nginx> -d -p 8080:80 nginx
```

これでnginxはできました。が今回は、logのフォーマットを変更してみます。
docker内に入ります。nginxのdockerはubuntuで作られているので、
まず `nginx.conf` の設定を変更できるように最低限必要なファイルを設定します 

```
$docker exec -it <ubuntu-nginx> /bin/bash
//以下コンソール内
apt update && apt install -y procps && apt install -y vim
apt install -y curl
```
nginxの設定を書き換えます
元々

```/etc/nginx/nginx.conf
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}
```

変更後)

```
cat /etc/nginx/nginx.conf

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    log_format json escape=json '{'
      '"time": "$time_local",'
      '"remote_addr": "$remote_addr",'
      '"host": "$host",'
      '"remote_user": "$remote_user",'
      '"status": "$status",'
      '"server_protocol": "$server_protocol",'
      '"request_method": "$request_method",'
      '"request_uri": "$request_uri",'
      '"request": "$request",'
      '"body_bytes_sent": "$body_bytes_sent",'
      '"request_time": "$request_time",'
      '"upstream_response_time": "$upstream_response_time",'
      '"http_referer": "$http_referer", '
      '"http_user_agent": "$http_user_agent",'
      '"http_x_forwarded_for": "$http_x_forwarded_for",'
      '"http_x_forwarded_proto": "$http_x_forwarded_proto"'
    '}';


    access_log  /var/log/nginx/access.log main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}
```

※ただし、ローカルから変更するのであれば、以下のファイルから変更が必要です

```default.conf
:
access_log  /var/log/nginx/host.access.log  json;
:
```


configのテストをして、リロードします
再起動すればlogが、jsonになっています

```
nginx -t
nginx -s reload
```
Android OS のバージョンシェア 2020年2月版

```
2020-02
+------+-----+--------------+------------+----------+------------+----------+
|  OS  | API |  CODE_NAME   | WW SHARE % | WW SUM % | JP SHARE % | JP SUM % |
+======+=====+==============+============+==========+============+==========+
|  4.4 |  19 | KITKAT       |       2.08 |    99.22 |       2.38 |    98.96 |
+------+-----+--------------+------------+----------+------------+----------+
|  5.0 |  21 | LOLLIPOP     |       1.35 |    97.14 |       2.13 |    96.58 |
+------+-----+--------------+------------+----------+------------+----------+
|  5.1 |  22 | LOLLIPOP_MR1 |       5.39 |    95.79 |       3.60 |    94.45 |
+------+-----+--------------+------------+----------+------------+----------+
|  6.0 |  23 | M            |      10.00 |    90.40 |       7.40 |    90.85 |
+------+-----+--------------+------------+----------+------------+----------+
|  7.0 |  24 | N            |       6.67 |    80.40 |       8.12 |    83.45 |
+------+-----+--------------+------------+----------+------------+----------+
|  7.1 |  25 | N_MR1        |       4.58 |    73.73 |       3.54 |    75.33 |
+------+-----+--------------+------------+----------+------------+----------+
|  8.0 |  26 | O            |       7.94 |    69.15 |      13.43 |    71.79 |
+------+-----+--------------+------------+----------+------------+----------+
|  8.1 |  27 | O_MR1        |      12.15 |    61.21 |       4.05 |    58.36 |
+------+-----+--------------+------------+----------+------------+----------+
|  9.0 |  28 | P            |      41.22 |    49.06 |      44.54 |    54.31 |
+------+-----+--------------+------------+----------+------------+----------+
| 10.0 |  29 | 10           |       7.84 |     7.84 |       9.77 |     9.77 |
+------+-----+--------------+------------+----------+------------+----------+
```

<a href="https://android.benigumo.com/20200313/android-os-versions-2/" target="_blank">👉 Android OS バージョン マーケットシェア はどうなってるのか&nbsp;<img src="http://b.hatena.ne.jp/entry/image/https://android.benigumo.com/20200313/android-os-versions-2/"></a>
【Webアクセシビリティ奮闘メモ】マークアップ編（超基礎）

勉強しないといけないと思いつつも、なかなか手を出せていなかったWebアクセシビリティ。
去年、[Accessibility Step Vol.6](https://a11ystep.connpass.com/event/156645/)に参加して、色んな方たちのお話聞いて、「あぁこれはちゃんと勉強しないと駄目なやつだわ」と実感。
だけど、いきなりやれと言われても難しい…そんなしっかり知識があるわけでもないし。。。

ということで。
ちまちまと調べたことをメモとして残していきます。

## セマンティックなマークアップはSEOに効果があるだけじゃないよ
まずはマークアップです、基礎の基礎。
SEO内部施策で「セマンティックなマークアップを！」みたいなことを言うけど、セマンティックなマークアップはSEOだけでなく、アクセシビリティにもよいのですな。

## HTMLで定義された要素を利用したマークアップ

- `<header>` / `<footer>` 
- `<main>` / `<aside>`
- `<aritcle>` / `<section>`
- `<h1>` / `<h2>`などの見出し
- `<p>` / `<a>` / `<img>`
- `<ul>` / `<ol>` / `<dt>`などリスト系

などを利用して、文書構造を意識しながら、よりセマンティックなマークアップしていくことが大事。
例えば、`<nav>`を使うと、VoiceOverなどの読みあげ機能で「ナビゲーション」って感じで読みあげてくれる。

あと、Webアクセシビリティのイベントで、「これ今後に期待！」みたいな要素もありました。
知らなかったのでメモ。

### ダイアログ要素（`<dialog>`）
その名の通り、モーダルやダイアログ的意味合いのものに利用する。
一部のブラウザ（ChromeやEdge）しか利用できない。

```html
<dialog>
    ダイアログメッセージが入ります
    <button type="button">閉じる</button>
</dialog>
```

### 詳細折りたたみ要素（`<datails>`）／概要明示要素（`<summary>`）
この2つの要素は一緒に利用する。

```html
<details>
    <summary>質問が入ります</summary>
    <p>質問の答えが入ります</p>
</details>
```
`<summary>`要素をクリックすると、`<details>`要素の開閉状態を切り替える。
つまりは、JSとか使わずとも、トグルボックスみたいな実装ができる。
ただし、これも一部のブラウザ（ChromeやEdge）しか利用できない。

## WAI-ARIAを利用したマークアップ
W3Cによって定められた仕様で、大きく3つある。

- 【Role】ランドマーク（目印。それがどういう役割なのか）を定義
- 【Property】性質を定義
- 【State】状態を定義

これを利用することで、よりセマンティックなマークアップを行うことが可能。
たとえば、`<h1>`をWAI-ARIAのルールに則って書くとこうなる。

```html
 <div role="heading" aria-level="1">h1見出し</div>
```

### WAI-ARIAロールについて
改めて、WAI-ARIAロールってのは、ランドマーク（目印）のこと。
「これは、このページ（サイト）ではこういう役割なんですよー」ってのを示すことができる。
role属性を指定することで、その要素が何の役割なのかが分かるが、HTML5には、このrole属性の意味合いが含まれているものがある。

| HTML5要素 | 要素の説明 |
|----|----|
| `<header> ` | ロゴ、会社名、検索アイコン、スローガンなどを含めた要素群。<br>`role="banner"`と同じ意味を持つ。 |
| `<footer>` | 著作権情報、ナビゲーションリンク、個人情報保護方針など、サイトの最後に繰り返される情報。<br>`role="contentsinfo"`と同じ意味を持つ。 |
| `<nav>` | ウェブサイトまたはページをナビゲートするために使用されるリンクの集まり。<br>`role="navigation"`と同じ意味を持つ。 |
| `<main>` | メインコンテンツ。<br>`role="main"`と同じ意味を持つ。 |
| `<aside>` | メインコンテンツに関連する補足情報。<br>`role="complementary"`と同じ意味を持つ。 |

### WAI-ARIAを利用するにあたっての注意
WAI-ARIAを利用すれば、よりセマンティックなマークアップが可能だが、これは補助的に利用するものであり、ブラウザによっては未サポートなaria属性が存在する [^1] ため、**既にネイティブなHTML要素・属性が存在している場合は、積極的にそれを利用することが推奨**されている。

```html
<!-- この書き方は非推奨 -->
<div role="banner">
    <div role="heading" aria-level="1">h1見出し</div>
</div>

<!-- 上記は、header要素／h1要素に置き換えることができるので、下記のように書くことができる -->
<header>
    <h1>h1見出し</h1>
</header>
```
[^1]: 例として、[aria-labelledbyはIEでは未サポート](https://www.html5accessibility.com/tests/aria-labelledby-input.html)。
BigQueryでテーブルの更新時間を取得する方法

テーブルの更新時間を取得するには下記の方法がある

### SQLで取得する方法

``` sql
SELECT
  table_id,
  FORMAT_TIMESTAMP('%Y-%m-%d %H:%M:%S', TIMESTAMP_MILLIS(last_modified_time), 'Asia/Tokyo')
FROM
  `データセット名.__TABLES__`
WHERE
  table_id = 'テーブル名'
```

### CLIで取得する方法
(unixtime)

``` bash
bq show \
--schema \
--format=prettyjson \
プロジェクト名:データセット名.テーブル名 | grep lastModifiedTime
```

[INFORMATION_SCHEMA](https://cloud.google.com/bigquery/docs/information-schema-tables?hl=ja)で取りたいけど、作成日しか取れない(2020/3 現在)
Slackで引用タグ（>）は内部的にはどのように認識されているか？

# 結論
**`&gt;`**という特殊文字コードで認識されている

# `>`だと反応しない
```
if (receivedMessage.indexOf('>') === 0) {
  var message = '```' + receivedMessage + '```\n\nこの行の文頭に「>」を感知しました！';
} else {
  var message = '```' + receivedMessage + '```\n\nこの行の文頭に「>」を感知しませんでした…';
}
postMessage(message)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253818/8e4213d6-c195-2109-ce1e-50eb3677e818.png)

# `&gt;`で反応する
```
if (receivedMessage.indexOf('&gt;') === 0) {
  var message = '```' + receivedMessage + '```\n\nこの行の文頭に「>」を感知しました！';
} else {
  var message = '```' + receivedMessage + '```\n\nこの行の文頭に「>」を感知しませんでした…';
}
postMessage(message)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253818/4742ca37-1905-6a95-f095-a048d1ea6b8b.png)

# `&gt;`ってなに？
[HTML特殊文字コード表](http://www.shurey.com/js/labo/character.html)
> | `>` | `&gt;` | 大なりの記号。タグを表記したいときにも必要 |
> |:--|:--|:--|

HTML特殊文字として内部的には処理されているようでした。
React Contextと再レンダリング、shouldComponentUpdate, memoとかの関係

# 目的
ReactでContextを利用している子コンポーネントと再レンダリングのトリガの関連が不明だったので自分で動かして調べる。

# 不明点
Reactにはコンポーネントの不要な再レンダリングを防ぐ手段がある。
1. shouldComponentでfalseを返す
2. React.memo使う
3. PureComponent使う

一方でContextはpropsのバトンリレーをスキップすることが可能。

疑問なのはContext Provider（親） -> 中間コンポーネント -> Context Consumer（子）のような構造になっているときに中間コンポーネントがshouldComponentとかを使って再レンダリングされなかったときでもContextが変更されたときにはConsumerが再レンダリングされるかどうか。
Contextの目的からすれば再レンダリングされないとおかしいが、公式ドキュメントでははっきりしないので動かして試してみた。

# 結論
Contextをconsumeしている子コンポーネントは途中のコンポーネントが再レンダリングをスキップしていても再レンダリングされる。

# 検証Code
https://github.com/ftanuma/react-context-test

```react
import React, { useContext } from "react";
import "./App.css";

const ThemeContext = React.createContext({
  mode: "light",
  changeMode: () => {}
});

function Toolbar() {
  return (
    <>
      <ContextConsumingClass />
      <ContextConsumingFuncMemo />
    </>
  );
}

const ToolbarMemo = React.memo(Toolbar, (prevProps, nextProps) => {
  return true; // Always avoid re-render
});

class ContextConsumingClass extends React.Component {
  static contextType = ThemeContext;

  shouldComponentUpdate() {
    return false;
  }

  render() {
    console.log("ContextConsumingClass:render()");
    return <p>ContextConsumingClass: I'm actually not using context :)</p>;
  }
}

function ContextConsumingFunc() {
  const context = useContext(ThemeContext);

  console.log("ContextConsumingFunc:render()");
  return <p>ContextConsumingFunc: I'm actually not using context :)</p>;
}

const ContextConsumingFuncMemo = React.memo(ContextConsumingFunc, (prevProps, nextProps) => {
  return true; // Always avoid re-render
});

class App extends React.Component {
  state = {
    mode: "dark"
  };
  changeMode = () => {
    this.setState(prevState => {
      if (this.state.mode === "dark") {
        return { mode: "light" };
      } else {
        return { mode: "dark" };
      }
    });
  };

  render() {
    return (
      <ThemeContext.Provider
        value={{ mode: this.state.mode, changeMode: this.changeMode }}
      >
        <div className="App">
          <ToolbarMemo></ToolbarMemo>
          <button onClick={this.changeMode}>change mode</button>
          <p>{this.state.mode}</p>
        </div>
      </ThemeContext.Provider>
    );
  }
}

export default App;


```

ブラウザでReact DevToolsを使ってフレームキャプチャしつつ、ボタンを押してContextにかかわるstateを変更してみたときの状態。中間のToolbar（Memo）と ContextConsumingFuncMemoが再レンダリングされていない（灰色）にも関わらずContextConsumingClassとContextConsumingFuncコンポーネントはちゃんと再レンダリングされている。ContextConsumingClassについては自身のshouldComponentUpdate()で毎回falseを返していてもContextに変更があるとrender()が呼び出されている。

![Screen Shot 2020-03-12 at 8.10.24 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101092/c4c553d7-128c-be72-d4f3-aadeb67509ca.png)
Homebrew + pyenvでPython 3.4.3をインストールしたかった話

# はじめに

pyenv + Python 3.4.3を構築するにあたって半日くらい費やしてしまったので、その備忘録です。

# 前提

- macOS Catalina 10.15.3
- Homebrew 2.2.10 
- fish 3.1.0
- pyenv 1.2.16

```shell
pyenv install 3.8.1
pyenv global 3.8.1
```

は成功。

# Python 3.4.3のインストール

同様にインストールを試みるもエラー発生。

```shell
pyenv install 3.4.3
```

↓

```shell
〜〜略〜〜
ERROR: The Python ssl extension was not compiled. Missing the OpenSSL lib?
〜〜略〜〜
```

## 失敗: OpenSSLに関するコンパイルオプションの指定

公式Wiki[^1]によると、「コンパイルオプションを指定すると良い」とのことだが、同様エラーにより撃沈。

> If you have homebrew openssl and pyenv installed, you may need to tell the compiler where the openssl package is located:

試したコマンド（※fish用です。）

```shell
set -gx CPPFLAGS "-I/usr/local/opt/openssl/include"
set -gx LDFLAGS "-L/usr/local/opt/openssl/lib" 
pyenv install 3.4.3
```

↓

```shell
〜〜略〜〜
ERROR: The Python ssl extension was not compiled. Missing the OpenSSL lib?
〜〜略〜〜
```

## 成功: HomebrewからのOpenSSLパッケージの削除

同公式Wiki[^1]によると、「（Ubuntuでは）OpenSSLのバージョン変更により解決するかも？」とのこと。

> If you're having trouble to get it to compile older python versions(<3.5) even after installing the recommended packages on ubuntu, changing the openssl lib might help:

そこで、とりあえずHomebrewに入っているOpenSSLをアンインストールしてみた。ただし、同パッケージはpyenvが依存関係にあるため、`--ignore-dependencies`オプションを指定。

```shell
brew uninstall --ignore-dependencies openssl@1.1
pyenv install 3.4.3
```

その後、ログを眺めていると冒頭でPython 3.4.3のインストールの前にOpenSSL 1.0.2kをビルドし始めて成功の予感が。
↓

```shell
Downloading openssl-1.0.2k.tar.gz...
-> https://pyenv.github.io/pythons/6b3977c61f2aedf0f96367dcfb5c6e578cf37e7b8d913b4ecb6643c3cb88d8c0
Installing openssl-1.0.2k...
〜〜略〜〜
Installed Python-3.4.3 to /Users/yaumu3/.pyenv/versions/3.4.3
```

無事成功です。

## 後片付け

Python 3.4.3インストール時にインストールされたOpenSSLを削除し、HomebrewにOpenSSLを再インストールする。

```
rm -rf /usr/local/opt/openssl
brew reinstall openssl@1.1
```

# さいごに

1. HomebrewからOpenSSLのアンインストール
2. 古いバージョンのOpenSSLをHomebrewにインストール[^2]
3. PATHを通す
4. コンパイルオプションを指定して`pyenv install 3.4.3`

でも成功しますが、この方法が一番シンプルだと思います。

[^1]: [pyenv/Wiki/Common build Problems](https://github.com/pyenv/pyenv/wiki/common-build-problems#error-the-python-ssl-extension-was-not-compiled-missing-the-openssl-lib)
[^2]: [Qiita - homebrew で openssl 1.0 がインストールできなくなっています](https://qiita.com/kunit/items/0aef44d5e522abde1f9c)
【AWS】CloudFormationでsts:AssumeRoleのPrincipalに指定するサービス名の一覧(xxx.amazonaws.com)

## 一覧の場所

以下に掲載されています。

- [List of AWS Service Principals - GitHub Gist](https://gist.github.com/shortjared/4c1e3fe52bdfa47522cfe5b41e5d6f22)

CloudFormationのテンプレートファイルを書いているときに便利です。

## AssumeRoleに関する参考ページ

- [IAMロール徹底理解 〜 AssumeRoleの正体 ｜ Developers.IO](https://dev.classmethod.jp/cloud/aws/iam-role-and-assumerole/)

- [[AssumeRole] アクセスキーが流出しても被害が最小限になるIAMユーザでCloudFormationにデプロイする方法 ｜ Developers.IO](https://dev.classmethod.jp/cloud/aws/assume-role-deploy-iam-user-and-role/#assumerole%E3%81%A8%E3%81%AF)
【UE4】NavMeshで障害物をよける／第13回UE4ぷちコン進捗 - 2020/03/13

[1]:http://historia.co.jp/ue4petitcon13
[2]:https://docs.unrealengine.com/en-US/API/Runtime/NavigationSystem/UNavigationSystemV1/FindPathAsync/index.html


[株式会社ヒストリアさん主催の第13回UE4ぷちコン][1]の作業進捗。

グラボが死んでからずいぶん間をあけてしまった。
あの後、１週間後に(※)PCのサポートセンターから交換用のグラボが届いて、そこから作業を再開したのだが、結構な時間を浪費したので、かなりテンパり気味に作業した結果、進捗記事を書くのをさぼってしまった。

> ※最近のご時世のアレで、メーカーさんもグラボの調達に予想外に時間がかかったようである。

# さて、現状はこんな感じ

![20200313_1055.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/24d3b8ae-2bc7-4a77-00ea-2ab944bc9be6.gif)

ここしばらくは、恐竜の仲間たちが障害物を避けられるようにアレコレ実験していた。
水色の柱が目的地、白いのが壁。
ここまで作ってきたぷちコン本体のプロジェクトを汚したくなかったので、別のプロジェクトで実験している。

- ご存じ NavMesh を使用している。
- もともと、恐竜たちは物理で動いているので、pathfinding の結果(=経路情報：`TArray<FVector>`)を愚直にたどる方法との親和性が低い。
- 現在位置と pathfinding で得られた移動経路から恐竜たちに与える force を**なんとなく**求め、最終的には物理として処理するようにした。（ここが難しかった！）

## NavMesh でハマったこと

### コリジョン設定

私は通常、UE4 標準のコリジョンプロファイル(BlockAllやOverlapAllなど)は使っていない。基本的に関係ないものはすべて Ignore にしたいからだ。
地面のコリジョンプロファイルも、自作の Ground というものを使っている。そうすると、地形を作って、壁などを配置した後、Landscape の Collision Preset (=Collision Profile※)を自作の Ground に切り替えたとたん、NavMesh がなくなってしまった。

> ※UE4 内でも Collision Profile と Collision Preset が混同して使われている様子。とりあえず私は Collision Profile と言うことにしている。

色々試行錯誤した結果、どうやら <font color="red">Pawn を Block する設定をした地面でないと NavMesh は生成されない</font>…ではないか、と思われる。

### RecastNavMesh-Default とプロジェクト設定

NavMesh のビルド後に自動生成される「RecastNavMesh-Default」について。
RecastNavMesh-Default のパラメータをいじると NavMesh が更新されるが、レベルをオープンしなおしたり、次回 uproject を起動したときなどにデフォルト値に戻っている。

調べた結果、Project Settings > Engine > Navigation Mesh の設定をいじるのが正解のようだ。
設定のテスト自体は RecastNavMesh-Default で行い、最終的には Project Settings にその値を書く、という感じでやればよかろう。

ところが。
主に設定した値は Agent Radius, Agent Height, Agent Max Slope なのだが、結局 Agent Max Slope しか反映されていない様子。何かほかに設定しなくてはいけないものがあるのだろうか？

これについては現在放置中。最悪このままでいく。


## Pathfinding は重い

※pathfinding = 障害物を避けて目的地に至るまでの経路を検索する方法

当たり前といえば当たり前なのだが、個々の Pawn が毎フレーム pathfinding を呼び出すと、テキメンにフレーム落ちする。なので今回は：

- pathfinding のマネージャ的なものを用意する。
- 各々の Pawn は、そのマネージャに「リクエスト」を投げる。
- マネージャは１フレーム当たり１回しかリクエストを処理しない。（この回数は変更可能）
- 各々の Pawn は、マネージャから返ってきたパス(`TArray<FVector>`)の最終点に到達するまで、リクエストは投げない。

という形でやってみた。
結果は良好。50体を動かして、冒頭の .gif アニメのように、一応 120fps を(ギリギリ)保っている。

> 注意：ゲーミングPCなので、CPUはまあまあ強い。
> だが、ファンは回りっぱなしだった。

### おまけ： FindPathAsync()

Blueprint に Find Path to Location Synchronously というノードがある。
これが pathfinding をやってくれるノードである。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/6d95b7c1-200f-e007-f907-2926feee5f7c.png)

単なる好奇心で C++ の実装を覗いてみたのだが、そのついでに FindPathAsync() なる関数を発見した。非同期で pathfinding をやってくれるのはありがたい。今回はこちらの関数を使っている。

[UNavigationSystemV1::FindPathAsync() - Unreal Engine 4 Documentation][2]

困ったことに、Web検索をしても、エンジンソース内を覗いても、この FindPathAsync() を使っている例が見つけられなかったが、最終的には上記 Blueprint ノードの元関数、UNavigationSystemV1::FindPathToLocationSynchronously() を参照して意図通り動作するように使うことができた。

> なお、いくら非同期とはいえ、多数のリクエストを同時に、かつ高フレームレートを維持したまま処理できるわけではないので、ご注意ください。


では、作業に戻ります。
[備忘録]~/.sshの作り方とconfigの設定

## 目的

- 人生で何度か設定するけどその都度調べて時間を浪費してしまうので、そうしないための備忘録。

## 必要な事

```shell
# 空ディレクトリ作成
$ mkdir ~/.ssh

# 空ファイル作成
$ touch ~/.ssh/config

# パーミッション変更
$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/*

# configファイルの編集
$ vim ~/.ssh/config

Host *
    StrictHostKeyChecking no
    UserKnownHostsFile=/dev/null
    ServerAliveInterval 15
    ServerAliveCountMax 30
    AddKeysToAgent yes
    UseKeychain yes
    IdentitiesOnly yes
```

> - `Host *` 全ホストの共通設定
> - OpenSSHの警告メッセージを非表示
>   - `StrictHostKeyChecking no`
>   - `UserKnownHostsFile=/dev/null`
> - SSH接続のタイムアウト設定
>   - `ServerAliveInterval 15`
>   - `ServerAliveCountMax 30`
> - 入力したパスワード/鍵の省略設定
>   - `AddKeysToAgent yes`
>   - `UseKeychain yes`
> - 認証の際に、ssh_config ファイルで指定された秘密鍵のみを使用するよう指定
>   - `IdentitiesOnly yes`
>   - [configを書くことでsshを便利で簡単にしよう！](https://koejima.com/archives/583)

引用元：[Mac Git 初期設定](https://qiita.com/ucan-lab/items/aadbedcacbc2ac86a2b3)
Docker for Windowsでproxy設定


Docker for Windowsをインストールしてdocker runしたらproxy関係でエラーが出たのでメモ。

## 環境

- Windows 10 Enterprise 1903
- Docker for Windows v19.03.5

## 発生したエラー

```
> docker run -it -d --name centos7 centos:centos7
Unable to find image 'centos:centos7' locally
C:\Program Files\Docker\Docker\resources\bin\docker.exe: Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers).
See 'C:\Program Files\Docker\Docker\resources\bin\docker.exe run --help'.
```

## 対処

- マシンが認証付きプロキシ環境下のため環境変数にプロキシを入れたが同じエラーとなった。
- タスクトレイのDockerアイコンから`settiongs`をクリックし、`PROXIES`の画面を確認。
- 以下のプロキシ設定を入力し、`Apply & Restart`をクリック。

`http://<user>:<password>@<your-proxy>:<proxy-port>/`
※認証付きでない場合は`<user>:<password>@`を外す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418880/54d18883-2c64-ebc0-017e-f7df5f1846d2.png)

これで無事に実行できた。

```
> docker run -it -d --name centos7 centos:centos7
Unable to find image 'centos:centos7' locally
centos7: Pulling from library/centos
ab5ef0e58194: Pull complete
Digest: sha256:4a701376d03f6b39b8c2a8f4a8e499441b0d567f9ab9d58e4991de4472fb813c
Status: Downloaded newer image for centos:centos7
f2c8f2188ba3260e6ef96f1d73bf0c3fa3ce42eda71cdf1e5dd79df19eac713b
```
こんなQiitaの「いいね」がいいな

# この記事について

件のアイコン変更を受けて、記事を書こうかと思いました。
https://blog.qiita.com/like-to-lgtm/

いいね実装者のブログも読みました。
https://mizchi.hatenablog.com/entry/2020/03/13/015359

# 提案

こんなQiitaがいいな

* ストックを先頭に
* LGTMを末尾に
* 開発者レベルごとのランキング設定

# 理由

## ストックを先頭に

いいね実装者のブログのような「ストック機能自体要らない」という意見はあります。また自分も、Qiitaでストックしたうえで記事のブックマークするときはあります。
>個人のブックマークやソーシャルブックマークなどによって、それらは別途個々人がもっていたはずです。

ただブックマークのフォルダ選ぶのって、ちょっと手間あるんですよね。特に、仕事で急いでるときは。
必要なとこだけ読んでコピペする、ってよくあるじゃないですか。

なので、仕事中にザッとみて、とりあえずストックしておいて、後で精査する、みたいな使い方ができればいいなと思ってます。

## LGTMを末尾に

* あとで読む→ストック
* ちゃんと読んだ→LGTM

でいいと思います。
いいね廃止案としてのLGTMは、ベストエフォートだと思ってます。

## ランキングの開発者レベル設定

上記２つは既出のアイデアですが、こちらは独自のものです。  

大雑把でいいと思うんですよね、

* 初心者向け
* 経験者向け
* 上級者向け

みたいな。

LGTMにしたとしても、「ちゃんと読む」の精度って人によって違うと思うんですよね。ポエムであっても初心者にとっては有益になると思うので、読者レベルをあらかじめ設定するのがいいかと思ってます。

# その他

LGTMはまだしも、ストックのフォルダアイコンを変えた意味がわからない・・・
そっちだけ戻してほしい。
AWS RDS Auroraを自動スナップショットから復元をCLIで実現する(AWS RDSと比較)

## 経緯
今まではAuroraではないAWS RDSをCDで作成していました。
今回Auroraに変更することになり、CLIで作るのに戸惑ったのでメモとして残しておきます。

## 前提
- 毎日Auroraが自動スナップショットを作成している
- 復元元のDBクラスター名(RDSの場合はインスタンス名)は`test-rds`とする

## リポジトリ
- [こちら](https://github.com/koyama-naoto-uhuru/aws-rds-restore-rds-from-snapshot)にサンプルを作成してます。

## スナップショット名の取得
- 1行目で自動スナップショットから最新日付のスナップショット名は取得できます
- `describe-db-cluster-snapshots`ではダブルクウォテーションを含んでしまうのでsedで削除しています

### Aurora
```
SNAPSHOT_NAME=`aws rds describe-db-cluster-snapshots --query "reverse(sort_by(DBClusterSnapshots[?DBClusterIdentifier=='test-rds'],&SnapshotCreateTime))[0].DBClusterSnapshotIdentifier"`
SNAPSHOT_NAME=`echo $SNAPSHOT_NAME | sed "s/\"//g"`
```

### RDS
```
SNAPSHOT_NAME=`aws rds describe-db-snapshots --query "reverse(sort_by(DBSnapshots[?DBInstanceIdentifier=='test-rds'],&SnapshotCreateTime))[0].DBSnapshotIdentifier"`
SNAPSHOT_NAME=`echo $SNAPSHOT_NAME | sed "s/\"//g"`
```

## スナップショットから復元
- `$SNAPSHOT_NAME`はスナップショット名の取得から持ってきています。単純にスナップショットから復元したい場合はここをベタ書きすればOKです。
- インスタンスの存在チェックも行っています
- AuroraはClusterとインスタンス両方する必要があります

### Aurora
```
rds_cluster_exists=`aws rds restore-db-cluster-from-snapshot --snapshot-identifier $SNAPSHOT_NAME --db-cluster-identifier "作りたいcluster名" --engine "aurora-postgresql" --engine-version "11.6" --db-subnet-group-name "xxxx" --vpc-security-group-ids "xxxx" --db-cluster-parameter-group-name "xxxx"` || true
echo "rds_cluster_exists='$rds_cluster_exists'"
if [[ $rds_cluster_exists =~ 'DBClusterAlreadyExistsFault' ]] ;
then
  echo 'DBClusterAlreadyExistsFault !!'
fi
rds_instance_exists=`aws rds create-db-instance --db-cluster-identifier "上記で指定したcluster名" --db-instance-identifier "作りたいインスタンス名" --db-instance-class db.t2.small --engine aurora-postgresql --publicly-accessible 2>&1` || true
echo "rds_instance_exists='$rds_instance_exists'"
if [[ $rds_instance_exists =~ 'DBInstanceAlreadyExists' ]] ;
then
  echo 'DBInstanceAlreadyExists !!'
fi
```

### RDS
```
rds_instance_exists=`aws rds restore-db-instance-from-db-snapshot --db-snapshot-identifier $SNAPSHOT_NAME --db-instance-identifier "作りたいインスタンス名" --db-subnet-group-name "xxxx" --db-instance-class db.t2.small --vpc-security-group-ids "xxxx" --db-parameter-group-name "xxxx" --publicly-accessible 2>&1` || true
echo "rds_instance_exists='$rds_instance_exists'"
if [[ $rds_instance_exists =~ 'DBInstanceAlreadyExists' ]] ;
then
  echo 'DBInstanceAlreadyExists !!'
fi
```

## おまけ：復元完了を待つ
- 例えば復元した後でマイグレーションをかけたいなどCDでやりたいこともあると思います
- その場合には復元完了を待つ必要がありますのでそのやり方です

### Aurora
- `aws rds wait`コマンドを実行しますが、これは何分か（正確な数値は忘れましたw）待ってまだできていない場合は処理が終了してしまいます。
- そこでループで終わるまで待つようにしています
- Auroraの作成って1時間弱かかるイメージなので、`aws rds wait`だけだと不十分なんですよね

```
rds_wait="1"
while [ $rds_wait != "0" ]
do
  rds_wait=`aws rds wait db-instance-available --db-instance-identifier "上記で作成したインスタンス名"; echo $?`
  rds_wait=`echo $rds_wait | tail -n1`
  echo "waiting..."
  sleep 1
done
```

### RDS
- RDSはすぐに作成されるので、以下のみでOKです

```
aws rds wait db-instance-available --db-instance-identifier "上記で作成したインスタンス名"
```
CSVHelper で Shift-JIS のCSV書き込みをした際、改行が入らなかったときの対応

## 状況
C#でCSVHelperを使ってCSVファイルの読み書きをしている既存プログラムの改修（元は別の人がコーディング）をしています。
元々合ったコードとしては、以下のような感じで、inputCSVを読み込んだ後、1レコードずつ読み込んでいくつか処理をした（中略部分）あと、別のCSVファイル（outputCsv）に書き込むというものでした。

~~~C#
using (var inputCsv = new CsvReader(new StreamReader(inputCsvFilePath, Encoding.GetEncoding(932)), CultureInfo.InvariantCulture))
{
    inputCsv.Configuration.AllowComments = true;
    inputCsv.Configuration.Comment = '#';
    inputCsv.Configuration.HasHeaderRecord = true;

    using (var outputCsv = new CsvWriter(new StreamWriter(outputCsvFilePath, false, Encoding.GetEncoding(932)), CultureInfo.InvariantCulture))
    {
        outputCsv.WriteHeader<inputCsv>();
        var records = inputCsv.GetRecords<inputCsv>();
        foreach( var record in records ){
            //（中略）
            outputCsv.WriteRecord(record);
        }
    }
}
~~~

## 発生した不具合
元々のプログラムでは正常に動いていたのですが、改修の作業を始めてから動作確認をしていたところ、outputCsvの中に書き出されたデータが、改行がされておらず、全てのデータが連続して1行に書き込まれてしまうという事象が発生しました。

## 解決策
WriteRecordメソッドの下でNextRecordメソッドを実行して、明示的に次のレコードに移行させることで、無事、改行してくれるようになりました。
### (追記2020-03-13 13:20)
WriteHeaderの下にもNextRecordは必要でした。

~~~C#
using (var inputCsv = new CsvReader(new StreamReader(inputCsvFilePath, Encoding.GetEncoding(932)), CultureInfo.InvariantCulture))
{
    inputCsv.Configuration.AllowComments = true;
    inputCsv.Configuration.Comment = '#';
    inputCsv.Configuration.HasHeaderRecord = true;

    using (var outputCsv = new CsvWriter(new StreamWriter(outputCsvFilePath, false, Encoding.GetEncoding(932)), CultureInfo.InvariantCulture))
    {
        outputCsv.WriteHeader<inputCsv>();
        outputCsv.NextRecord();
        var records = inputCsv.GetRecords<inputCsv>();
        foreach( var record in records ){
            //（中略）
            outputCsv.WriteRecord(record);
            outputCsv.NextRecord();
        }
    }
}
~~~

## 原因
正直、私がC#は不慣れ（ほとんど初めて触ってる…）なこともあって、詳しい原因はわかっていません…。
ただ、

* 元のプログラムが数年前に作成された少し古いモノであること。
* 元々ビルドされたプログラムは問題なく動いていた。
* 開発環境は引き継いだものではなく、新しく構築しなおしたもの。（Nugetパッケージも新しいものをインストールしていた）

という状況から、推測としては

* CSVHelperのバージョンが上がった（新しい環境で動いていたのは、最新版の1.5.1。旧環境でのバージョンは、古い環境がすでになく不明）ことによる仕様変更で、NextRecordのコールが必須になった。
* CSVHelperのバージョンが上がったことでShift-JISでは改行ができなくなるバグが発生している。（UTF-8ではNextRecordをコールしなくても問題にならないかは未確認）

のどちらかかな、と思っていますが、どなたか詳しい方がいましたら、ご教示いただければと思います。

以上、大した情報ではないかと思いますが、ここだけに注目したトピックというのは見当たらず、最初に公式ドキュメントにあたっていなかったらドツボにはまっていたかもな～。と思いましたので、どなたかの参考になればと考えてまとめさせていただきました。
[Rails5]Twitter認証で悩んだことまとめ

## 概要
TwitterAPIを利用してすでにある認証機構に後付けでTwitterログインをつける際につまづいたことをまとめます。
自己流の解決方法なので最適ではない可能性が高いです。ご意見いただたら嬉しいです。
developerアカウントとか外部キーの取得に関しては記事がたくさんあるので省きます。

**※Deviceなどの認証系のgemは使っていません。**

記事を参考にして作ったモデルのメソッドはこんな感じ↓

```ruby:/app/models/user.rb
def self.find_or_create_from_auth(auth)
  provider = auth[:provider]
  uid = auth[:uid]
  name = auth[:info][:name]
  image = auth[:info][:image]

  self.find_or_create_by(provider: provider, uid: uid) do |user|
    user.name = name
    user.email = User.dummy_email(auth)
    user.password = User.new_token
    user.remote_image_url = image
  end
end
```
## 既存のsessions#createと機能が被る
アクションとルーティングを分離することで解決した。

```ruby:/app/contorollers/sessions_controller.rb
def twitter_create
  @user = User.find_or_create_from_auth(request.env['omniauth.auth'])
  log_in @user
  flash[:success] = "Twitter認証に成功しました"
  redirect_back_or root_url
end
```
```ruby:/config/routes.rb
get "/login", to: "sessions#new"
post "/login", to: "sessions#create"
get "/auth/:provider/callback", to: 'sessions#twitter_create'
delete "/logout", to: "sessions#destroy"
```

## 既存のUserテーブルはemailとpasswordが入力必須
ダミーEmailとパスワード用のトークンを発行することで代用した。

```ruby:/app/modles/user.rb
self.find_or_create_by(provider: provider, uid: uid) do |user|
  user.name = name
  user.email = User.dummy_email(auth)
  user.password = User.new_token
  user.remote_image_url = image
end

#API用ダミーemail生成
def self.dummy_email(auth)
  "#{auth.uid}-#{auth.provider}@example.com"
end

#ランダムなトークンを生成
def new_token
  SecureRandom.urlsafe_base64
end
```

その代わり、**twitterログインするユーザーはtwitterAPI経由でしかログインできなくなる。**
このデメリットを解決する手法は見つからなかった。もしくはそれが当たり前なのかも。
併せてusers/edit.html.erbでuser.providerに値が入っていたらEmailとパスワードを変更できる項目として表示しないようにした。

## carrierwaveを利用している場合のimageカラムの取り扱い
carrierwaveを利用している場合アップローダーを経由する必要があるため
`user.image = image #TwitterAPIから取得したプロフィール画像のパス`
では通らず
`user.remote_image_url = image #TwitterAPIから取得したプロフィール画像のパス`
とする必要があった

## まとめ
twitterAPIから情報を取得するまでは難しくないが、それを既存のアプリにどう組み込むかは頭を悩ませた。
同じように悩む方の救いになることを祈ります。
multiple-value in single-value context

```go:main.go
package main

import "fmt"
import "strconv"

func main() {
    str := "12"
    num, _ := strconv.Atoi(str) + 1 
    fmt.Println(num)
}
```

##本日のエラー
<font color="Red">multiple-value strconv.Atoi() in single-value context</font>
(一つの値が来るべきコンテキストに複数の値があるよ)

strconv.Atoi()は複数の戻り値を返すので、その実行結果に同文内で直接演算しようとしても当然できない。
戻り値を複数返せない言語を主に扱ってきた人は案外引っかかってしまうかも。(はい、私です。)

##対処
```go
num, _ := strconv.Atoi(str)
num++
```

##ちなみに

```go
num := getNum() + 1

func getNum() int {
    return 12
}
```
これはgetNum()が一つの戻り値しか返さないので問題ない。
これだけ知っておけばQiitaに投稿できるMarkdown記法一覧

Qiitaに記事を投稿するにあたって、
これだけ知っておけば記事の体裁が整えられる最低限のものを集めました。


詳しくはこちら。[Markdown記法 チートシート](https://qiita.com/Qiita/items/c686397e4a0f4f11683d)


## Headers - 見出し
\# H1タグ
\## H2タグ
\###### H6タグ


## Emphasis - 強調・強勢
*イタリック体*: _ か * で囲む（HTMLのemタグ）
**太字**: __ か ** で囲む（HTMLのstrongタグ）


## Lists - リスト
文頭に「*」「+」「-」のいずれかを入れる


## Code - コードの挿入
> (空行)
> \`\`\`言語:ファイル名（なくてもよい）
> ここにコードを書く
> \`\`\`
> (空行)


## Blockquotes - 引用
\> 文頭に>を置く


## Links - リンク
\[リンクテキスト](URL)
\[リンクテキスト](URL "タイトル")


## Images - 画像埋め込み
\![代替テキスト]\(画像のURL)
\![代替テキスト]\(画像のURL "画像タイトル")


## Horizontal rules - 水平線
\* * *
\***
\*****
\- - -
\---------------------------------------
python上でのファイルやフォルダ情報を参照

よく使うけど毎回調べてしまうpythonのファイル操作関連のまとめ

#フォルダ内のファイル一覧を取得
指定したフォルダ内のファイルの一覧をリストとして取得する

```python
import glob

folder = "./tmp/" 
img_path_list = glob.glob(folder)
```

ワイルドカードを使用すれば特定のファイルの一覧も取得可能
下記はpngファイルのみをリストとして獲得

```python
img_path_list = glob.glob(folder + "*.png")
```

#ファイル名の取得
指定したパスからファイル名を文字列として取得する

```python
import os

filepath = './tmp/hogehoge.ext'

filename = os.path.basename(filepath)
print(filename) # hogehoge.ext
```

拡張子なしで取得する場合

```python
filename_only = os.path.splitext(os.path.basename(filepath))[0]
print(filename_only) # hogehoge 
```

#存在しない場合にフォルダ作成
ファイルを保存するときになどに保存先フォルダが存在するかを確認し、
存在しない場合は新規に作成する


```python
import os

filepath = "./hogehoge2/" 
if not os.path.exists(filepath):
        os.makedirs(filepath)
```
【macで短縮コマンド】シェル、エイリアス機能を使う


#macで短縮キーの作成

最近、laradockを使い始めて長いコマンドを打つことが多くなり、短縮できないかとリサーチしました。結果として、シェル、エイリアスという機能を使う事で達成できました。

##この記事を読んで達成できること

laradockコマンドで
git clone https\://github.com/Laradock/laradock.gitの実行

laraworkコマンドで
docker-compose exec --user=laradock workspace /bin/bashの実行

##macのバージョン

macOS catalina 10.15.3


#どのシェルを使っているか確認してください。

最新のmacバージョンではzshを使っているようです。

```
% echo $SHELL
/bin/zsh
```

###使えるシェルの一覧を確認できます。

```
% cat /etc/shells
# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.

/bin/bash
/bin/csh
/bin/dash
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
```

##エイリアスへの登録

##.zshrcを開きます

```
% vim ~/.zshrc
```

##エイリアスを登録

alias 短縮キー="短縮キーとして登録したい内容"の形で記載します。

```:.zshrc
alias laradock='git clone https://github.com/Laradock/laradock.git'
alias larawork='docker-compose exec --user=laradock workspace /bin/bash'

```

##反映します。

```
% source ~/.zshrc
```

###終了です、お疲れ様でした。
nokogiriのエラーでbundle installが出来ない。libxsltのインストールで解決

# nokogiriのインストールでエラー

`bundle install --path vendor/bundle/` するとnokogiriのインストールでエラー。


```
An error occurred while installing nokogiri (1.6.7.1), and Bundler cannot continue.
Make sure that `gem install nokogiri -v '1.6.7.1' --source 'https://rubygems.org/'` succeeds before bundling.
```
指示通りに`gem install nokogiri -v '1.6.7.1' --source 'https://rubygems.org/'`してみても状況は変わらず。


# gem_make.out確認
`gem_make.out`にResultがあると書かれてあるので見てみる。↓

```
$ cat ./vendor/bundle/ruby/2.2.0/extensions/x86_64-linux/2.2.0-static/nokogiri-1.6.7.2/gem_make.out
/usr/local/rbenv/versions/2.2.2/bin/ruby -r ./siteconf20200313-12822-1iyzulw.rb extconf.rb --use-system-libraries
checking if the C compiler accepts ... yes
Building nokogiri using system libraries.
libxml2 version 2.6.21 or later is required!
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=/usr/local/rbenv/versions/2.2.2/bin/$(RUBY_BASE_NAME)
        --help
        --clean
        --use-system-libraries
        --with-zlib-dir
        --without-zlib-dir
        --with-zlib-include
        --without-zlib-include=${zlib-dir}/include
        --with-zlib-lib
        --without-zlib-lib=${zlib-dir}/lib
        --with-xml2-dir
        --without-xml2-dir
        --with-xml2-include
        --without-xml2-include=${xml2-dir}/include
        --with-xml2-lib
        --without-xml2-lib=${xml2-dir}/lib
        --with-libxml-2.0-config
        --without-libxml-2.0-config
        --with-pkg-config
        --without-pkg-config
        --with-xslt-dir
        --without-xslt-dir
        --with-xslt-include
        --without-xslt-include=${xslt-dir}/include
        --with-xslt-lib
        --without-xslt-lib=${xslt-dir}/lib
        --with-libxslt-config
        --without-libxslt-config
        --with-exslt-dir
        --without-exslt-dir
        --with-exslt-include
        --without-exslt-include=${exslt-dir}/include
        --with-exslt-lib
        --without-exslt-lib=${exslt-dir}/lib
        --with-libexslt-config
        --without-libexslt-config

extconf failed, exit code 1
```

`libxml2 version 2.6.21 or later is required!` と書かれてるので、ここら辺があやしい。
`Check the mkmf.log file for more details.` とあるので見てみる。


# mkmf.log　確認

```
$ cat ./vendor/bundle/ruby/2.2.0/extensions/x86_64-linux/2.2.0-static/nokogiri-1.6.7.2/mkmf.log

〜〜省略〜〜
package configuration for libxml-2.0 is not found
package configuration for libxslt is not found
package configuration for libexslt is not found
```

どうやらlibxml系のパッケージが見つからないみたいなことが書かれていた。

# libxsltインストール
libxsltをインストールする。

```
yum install libxslt-devel
```

libxsltインストール完了後、無事bundle installができるようになった。
OpenStreetMapのタイルマップサーバーをDockerで構築する

OpenStreetMapのタイルマップサーバーをDockerで構築します。

環境
\- Debian 10.3
\- PostgreSQl 12.2

まず、PostgreSQL12のインストールを行います。

```
$ wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
$ echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" |sudo tee  /etc/apt/sources.list.d/pgdg.list
$ sudo apt-get update
$ sudo apt-get -y install postgresql-12 postgresql-client-12
```



次にタイルマップサーバーの構築を行います。
必要な場所のPBFファイルを取得します。
[世界全体](https://planet.openstreetmap.org/pbf/planet-latest.osm.pbf)
今回は、九州のみの地図が必要だったので、
[地域別PBFのサイト](http://download.geofabrik.de/)から
[九州のPBF](http://download.geofabrik.de/asia/japan/kyushu-latest.osm.pbf)を取得してきます。

```
$ wget -c http://download.geofabrik.de/asia/japan/kyushu-latest.osm.pbf
```


Dockerのタイルマップサーバー用のボリュームの作成

```
$ docker volume create openstreetmap-data
```

PBFデータのインポート

```
$ docker run –v /home/baba/kyushu-latest.osm.pbf:/data.osm.pbf -v openstreetmap-data:/var/lib/postgresql/12/main overv/openstreetmap-tile-server import
```

タイルマップサーバーのDockerの起動

```
$ docker run -p 8080:80 -v openstreetmap-data:/var/lib/postgresql/12/main -d overv/openstreetmap-tile-server run
```


http://<サーバーアドレス>:8080/
にアクセスすることで、サンプルのleaflet画面を見ることができます。
![tilemap.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189046/1a6b247f-2ef5-1540-fb6b-1486a08524de.png)



http://<サーバーアドレス>:8080/{z}/{x}/{y}.png
で、それぞれのタイル画像にアクセスできます。
macOS catalinaでbitbucketからsshでリポジトリをclone出来なかったときの解決策

# 起きた問題
　今、所属組織の関係上Bitbucketのアカウントを２つ持っていて、使っている。久しぶりに、自分のPCに組織AのBitbucketにあるリポジトリのソースをcloneしようとしたところ

```
Forbidden
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
```

というエラーが出た。要は使った秘密鍵にはこのリポジトリに対するアクセス権がありませんよということである。

# 解決方法
　よく見ると、このアカウントに使っている秘密鍵とcloneするときに参照されている秘密鍵が異なっていた。
　普通は「じゃあ、今参照されている秘密鍵に対応する公開鍵をBitbucketに登録すればいいのでは？」と思いますよね。で、それをしたのですが、すると「この秘密鍵は、違うアカウントで使用されています」とエラーが出るんですね。はい、組織Bで使ってました。
　本当にアカウントをそろそろ統合せねばと思いながら、面倒だなーと思い、色々とした結果、普通にssh-agentに登録しなおせば解決しました。

```
% eval "$(ssh-agent -s)"
Agent pid 42643
% ssh-add ~/.ssh/[組織Aの秘密鍵]
```

　備忘録として。
　他にいい方法知っている方いらっしゃったら教えて下さい。
Jqueryで動的に全角改行2文字 半角1文字で文字数カウント

Jqueryで動的に文字数カウントをしたかったので作成
着火イベントは onInputでやってました
(IE9以前ではonInputが動かないので注意)

---
条件
1. 全角2文字
2. 半角1文字
3. 改行は2文字(CRLF CR LFすべて２文字）

---

以下、コード

```javascript
// 引数について
// text カウントしたい文字列
// field カウントした文字数を挿入するid属性

function getLen(text, field){
    var result = 0;
    // ここで すべての改行コードを \nへ 変換し、文字数を取得
    var textLength = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n').length;

    for (var i = 0; i < textLength ; i++){
        var chr = text.charCodeAt(i);
        if (chr === "\n".charCodeAt(0)) {
        // 改行の場合は2を加算
            result += 2;
        }
        else if ((chr >= 0x00 && chr < 0x81) ||
            (chr === 0xf8f0) ||
            (chr >= 0xff61 && chr < 0xffa0) ||
            (chr >= 0xf8f1 && chr < 0xf8f4)) {
            // 半角文字の場合は1を加算
            result += 1;
        } else {
            // それ以外の文字の場合は2を加算
            result += 2;
        }
    }
    //結果を返す
    document.getElementById(field).innerHTML = textLength;
};
```
Mac Visual Studio Code のターミナルのShellをbashに変更する

# 目的

- Visual Studio CodeのターミナルShellをZshに変更する方法のメモを書く  
※本作業はPCにすでにZshが入っており、terminalでは使用できていることを条件とする。

# ご注意

- **現在、この記事に記載されている方法だとターミナルのデフォルトshellをbashに設定できない模様**
- **2021-09-08時点の設定方法は下記を参照して頂きたい**
    - [https://qiita.com/miriwo/items/afffd94c2c50b65d0e56](https://qiita.com/miriwo/items/afffd94c2c50b65d0e56)

# 実施方法

1. Visual Studio Code(以降、VScode)のエディタ画面の左上の「Code」をクリックする。
1. 「基本設定」→「設定」と進む。
1. 「設定の検索」に`terminal.integrated.shell.osx`と入力する。
1. 「settings.jsonで編集」をクリックする。
1. 開いたファイルに下記の内容を追記する。場所はどこでもOK

    ```
    "terminal.integrated.shell.osx": "/bin/bash"
    ```

1. PCを再起動させてからVScodeのターミナルを開く
1. 下記コマンドを実行してshellがZshになっているか確認する。

    ```terminal
    echo $SHELL
    >/bin/bash
    ```
ショートカット一発でXcodeプロジェクトのGitリポジトリをChromeで開く

# はじめに
OSSのコード読んでいる時に、時々Readmeファイルを読みたくなります。

毎回手動でChromeを開いていたのですが、面倒なので、ショートカットにより一発でChromeを開けるようにしました。

かなり快適になりました。煩雑な手順が必要なものはコンピュータにお願いしたいです。


# 手順

## スクリプトをローカルに保存

今回登録するスクリプト

```
#!/bin/bash
pwd | git remote -v | grep fetch | awk '{print $2}' | xargs open -a '/Applications/Google Chrome.app'
```


https://github.com/masa7351/XcodeSupportScripts/blob/master/README.md
に同じものを配置しました。

便利に使えたら(・∀・)ｲｲﾈ!!押してもらったら励みになります。


## Behaviorsを開く

Xcode > Preference > Behaviors Tab

でこのウィンドウを開きます。

<img width="912" alt="open_repository_behaviors.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45426/bcb97b67-7075-98e5-b914-a4bea3b4cf04.png">



## スクリプトを登録＆ショートカット割当

画面左下の「＋」をクリックします

上のキャプチャーの "Custom"セクションを見てもらうと、 `Open Terminal` と `Open Repository`が表示されていますが、わかりやすい名前をつけてください。

（現在は自分はこの2つのスクリプトを登録しています）


作成したスクリプトの右側に　`Run` ところのチェックボックスをチェックしてください。

スクリプトは上の手順でローカルの任意の場所に保存したものを登録してください。


ショートカットを任意のもので割り当てて下さい。すでに登録されているショートカットを上書きすることも可能です。

# その他

Xcodeを使っていて、面倒なものはどんどんショートカットで対応していきたいと思います。
他、現在開いているPJをターミナルとして開くスクリプトも用意していますのでご活用してください。


# 参考

```
git remote -v | grep fetch
```

の出力結果の

```
origin	https://github.com/folio-sec/ImagePipeline.git (fetch)
```

から、どうやってURLを抜き出そうかと調べた時に、 awkを使うと簡単に実装できそうなので参考にさせてもらいました。

> 例2: スペース区切りのsample2.logファイル内で左から3番目の文字列を抽出
> $ awk '{print $3}' sample2.log> 区切り文字を-Fで指定(指定しないとスペース区切りになる)

[【備忘録】javascriptで空白区切りのデータから情報を取得する正規表現](https://qiita.com/shuntaro_tamura/items/e4e942e7186934fae5e7)