OmniAICreator/Qiita-1.07M huggingface dataset:
【AWS/RDS】MySQL 5.5をAurora MySQLへ移行

現在、運用中のサービスのデータベースの移行を行ったので、その記録と、事前に行った検証についてまとめてみます。

以前は、MySQL5.6以降であれば、ほぼダウンタイムなしでAuroraへの移行が可能でしたが、MySQL5.5でもいくつか手順を踏めばほぼダウンタイムなしで移行が行えるようになったようです。（以前は、気づかなかっただけかもしれませんが、確かスナップショットからAuroraを立ち上げるしか方法がなかったような気がします）

データベースの移行なんて、昔はかなりの大仕事だったのですが、AWSのおかげでだいぶ楽になりましたね。

まずは、移行前の構成です。インスタンスサイズやリージョンは特に関係ないので省きます。

|名前（仮）|ロール|エンジン|アプリケーションからの参照|
|:--:|:---:|:--:|:---:|
|MySQLマスター|マスター|MySQL5.5|参照中|
|MySQLスレーブ|レプリカ|MySQL5.5|参照中|

##手順1 新しくレプリカを作成します。

AWSのコンソールで、MySQLマスターを選択して、リードレプリカの作成を行います。
新しく作成するレプリカは、稼働中のアプリケーションでは利用しないので、サイズは小さめで問題ありません。
逆に、新しく追加したレプリカを稼働中のアプリケーションから参照しないように注意してください。

作成後の構成

|名前（仮）|ロール|エンジン|アプリケーションからの参照|
|:--:|:---:|:--:|:--:|
|MySQLマスター|マスター|MySQL5.5|参照中|
|MySQLスレーブ|レプリカ|MySQL5.5|参照中|
|MySQLスレーブNEW|レプリカ|MySQL5.5||

##手順2 新しく作成したレプリカのMySQLを5.6にアップグレードします。

新しく作成したMySQLスレーブNEWは、アプリケーションから参照されていない状態なので、稼働中のアプリケーションに影響はないので、AWSコンソールでMySQLのバージョンを5.6にアップグレードしてしまいます。すぐに適用で問題ないかと思います。

MySQLのアップグレード後の構成

|名前（仮）|ロール|エンジン|アプリケーションからの参照|
|:--:|:---:|:--:|:--:|
|MySQLマスター|マスター|MySQL5.5|参照中|
|MySQLスレーブ|レプリカ|MySQL5.5|参照中|
|MySQLスレーブNEW|レプリカ|MySQL5.6||

※ MySQLが5.6にアップグレードしたことによるアプリケーションへの影響は別途確認しておいてください。

##手順3 Auroraリードレプリカの作成

MySQL5.6にアップグレードしたレプリカBは、Auroraリードレプリカの作成が可能になるので、AWSのコンソールで、Auroraリードレプリカの作成を行います。

Auroraのリードレプリカの作成時に設定する値は、適宜ご自身の環境に合わせたものをご検討ください。
また、Auroraでデータベースを作成時にマルチAZを選択すると、MySQLとは違って、コールドスタンバイ状態ではなく、実際に利用できるレプリカとして機能しますので、この辺も移行するためのメリットにもなっているのではないかなと思います。

Aurora リードレプリカの作成後の構成

|名前（仮）|ロール|エンジン|アプリケーションからの参照|
|:--:|:---:|:--:|:--:|
|MySQLマスター|マスター|MySQL5.5|参照中|
|MySQLスレーブ|レプリカ|MySQL5.5|参照中|
|MySQLスレーブNEW|マスター,レプリカ|MySQL5.6||
|Auroraマスター|書き込み|Auroa MySQL5.6||
|Auroraスレーブ|読み込み|Auroa MySQL5.6||

##手順4 アプリケーションからの参照DBの切り替え

ここまでで、新しく移行するためのAuroraの構築はできました。もちろんステータスが利用可能になっていることは確認ください。
あとは、どういったタイミングで切り替えを行うかになります。

こっからは、何度か私の方で検証したことに基づいて記載しますので、間違え等あれば、ご指摘いただけると助かります。

####検証1 Auroraのリードレプリカは、構築後もレプリケーションされ続けるのか

これは、もちろん大丈夫でした。MySQLマスターに書き込まれたデータが、継続してAuroraにも反映されていました。

####検証2 Auroraマスターにデータの書き込みが行えるのか

MySQLのリードレプリカの場合、書き込みが行えないのですが、Auroraのリードレプリカとして作成した、Auroraマスターには書き込みができるのか、検証してみました。結果は、書き込みが可能でした。

####検証3 書き込まれた Auroraマスターのレプリケーションはどうなるのか

一度、書き込まれたAuroraマスターへのレプリケーションは、テーブル毎に停止するようです。
例えば、テーブルAにAuroraマスターから書き込みを行った場合、それ以降のデータはMySQLマスターへ書き込みされたデータが反映されない。ただし、書き込まれていないテーブルBへは、MySQLマスターへ書き込みされたデータが反映されました。

####検証4 Auroraクラスターを昇格した後、レプリケーションはどうなるのか

これも、もちろんデータベース全体でレプリケーションが停止します。

以上の検証結果を元に参照DBの切り替えを行います。取りうる選択肢としては2つぐらいあるかなと思います。

###A案 ほぼダウンタイムなしでの参照DBの切り替え

対象のデータベースへ参照しているアプリケーションが少ない場合など。

1.DB接続部分をAuroraに書き換えて、一気にアプリケーションをデプロイする。
2.AWSコンソールでAuroraクラスターの昇格を実行して完了

私は、なるべくアクセスが少ない時間を狙って深夜に対応しました。

##B案 少しだけダウンタイムがあっても良いので慎重に切り替えたい場合

1.稼働中のアプリケーションをメンテナンス中に切り替え。もしくは書き込みのみ停止。
2.AWSコンソールでAuroraクラスターの昇格
3.アプリケーションのDB接続部分をAuroraに書き換えてデプロイ
4.アプリケーションを稼働中に戻す


DB切り替え後

|名前（仮）|ロール|エンジン|アプリケーションからの参照|
|:--:|:---:|:--:|:--:|
|MySQLマスター|マスター|MySQL5.5||
|MySQLスレーブ|レプリカ|MySQL5.5||
|MySQLスレーブNEW|レプリカ|MySQL5.6||
|Auroraマスター|書き込み|Auroa MySQL5.6|参照中|
|Auroraスレーブ|読み込み|Auroa MySQL5.6|参照中|
Visual Studio CodeでGitの履歴を素敵に表示する

この記事は[cloudpack あら便利カレンダー 2019](https://benri2019.cloudpack.jp/) の2日目です。

[誕生秘話](https://qiita.com/shinichi-takahashi/items/cea235795f904ccea207#%E3%81%82%E3%82%89%E4%BE%BF%E5%88%A9%E3%82%AB%E3%83%AC%E3%83%B3%E3%83%80%E3%83%BC%E8%AA%95%E7%94%9F%E7%A7%98%E8%A9%B1) はこちらです。
私は今年からの参戦になります。

この記事では、あら便利な拡張機能の紹介をしたいと思います。

Gitのコミット履歴が複雑になってしまった場合に、コミットグラフが絡み合ってしまい履歴が追いづらい状態になってしまうことありますよね？
そこまで酷くはないけれど、ぱっと見で履歴がちゃんと終えるかというと微妙かも...という時はまあ普通にあります

そこで、最近、Visual Studio Codeの[Git Graph](https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph) というあら便利な拡張機能を見つけまして、これがなかなか綺麗にgitgraphを出してくれるので紹介したいと思います


# 使い方

## インストール

```console
$ code --install-extension mhutchie.git-graph
```

あるいは、GUIからインストール

![gitgraph_extension](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330514/d92b4639-f7c6-3f9c-e70c-29d1cea5b38a.png)

## 起動

インストールが完了すると、VCSのパネルにボタンが追加されるので、これを押すだけです。

![gitgraph_button](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330514/0f4c6270-5dd0-a24f-38ba-925cee58047f.png)


ボタン押下で新たなタブが立ち上がり、ギットグラフが表示されます。

以下、公式にあるキャプチャそのままです。この時点でオッとなり使ってみました。
まだ全然使いきれていないですが、なかなか良い感じです。
あと、起動はかなり軽いです。[Git History](https://marketplace.visualstudio.com/items?itemName=donjayamanne.githistory) なんかも使ったことはあるんですが、起動時のタメが気になって使わなくなりました。
この拡張はサクっと起動します。

![](https://github.com/mhutchie/vscode-git-graph/raw/master/resources/demo.gif)


# 複雑なグラフの表示

gitのコミットグラフはシンプルな例ならいいんですが、mergeが入り組むと途端に崩壊します。
ということで、複雑な状態のグラフでどうなるかをみてみました。

特に理由はないのですが、そこそこ大きいリポジトリ+自分のgithubのレコメンドに出てきたということで[pipenv](https://github.com/pypa/pipenv) のリポジトリのグラフを表示してみました。

一番めんどくさそうなところを表示した例がこちらです。

![pipenv_gitgraph](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330514/dcc13a07-ea68-fca8-415c-6d70f5ad0217.png)

なかなか綺麗に表示できているんじゃないでしょうか

# 別のツールで表示した場合

他のツールでも表示してみました。

## git cli

コマンドラインでのグラフ表示を試してみました。

```
$ git log -a --graph --oneline --decorate=full
```

![pipenv_git_cli](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330514/b5af7178-aa28-4196-ee60-5ee3266ac8a7.png)

ちょっと何言ってるかわかんないですね


## tig

コマンドラインツールの[Tig](https://jonas.github.io/tig/) の場合です

![pipenv_tig](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330514/26fa3877-af4d-f321-5aa9-f0c371d35c56.png)


ちょっと何言ってるかわかんないですね

まあ、CLIツールのこの辺求めるのは難しいですね 

## Git DAG

GUIツールということで、[Git Cola](https://git-cola.github.io/index.html) についてくるGit DAG というグラフで試してみました。
このグラフ表示が結構好きでメインで使っています。
このツールの場合は以下のようになりました

![pipenv_git_dag](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330514/3ffff57e-188a-07f5-1b8f-3e9764108e37.png)

この表示の方が正しい気がするとも思ったんですが、パッと見だと頭がついていかない感じがありますね。
まあでもこれはこれでいい感じ！


# まとめ

他のツールと比較しても、かなり見やすいツールじゃないでしょうか。
エディタと統合できるというのも嬉しいのでこれからも使っていこうかなと思います。
CentOSファイアーウォールのfirewalldをiptablesに変更する。

#あらすじ
先輩に教えてもらったキーワードを元にサーバーを構築する備忘録。
[前回](https://qiita.com/drafts/b3a937f751f113e6230f)でcentOSをサーバーに入れることに成功したので、初期設定を行う。
今回はファイアーウォールを変更する。

##firewalld・iptables
CentOSで使われているファイアーウォールです、前身はiptableだそうな。今回は練習ということでiptablesに変更します。

##firewalldを停止しよう
前身のiptableに変更しますがfirewalldは特に削除する必要はありません。止めるだけでOK。

```
# systemctl status firewalld
```
これで状態を確認できます。activeであれば緑色のランプがついてるはずです。
動作しているのがわかれば、停止しちゃいましょう。

```
//止めます
# systemctl stop firewalld
//自動起動も止めます
# systemctl disable firewalld

//確認して、inactiveであればOK
# systemctl status firewalld
```
おやすみFirewalld。

##iptablesのインストール

```
# yum -y install iptables-services
//バージョン確認
# iptables --version
//起動、自動起動を開始
# systemctl start iptables
# systemctl enable iptables
//activeか確認してください。
# systemctl status iptables
```

##ポートの開放
設定ファイルが作成されているので編集してポートを開放しましょう。
viで編集します。


```
# vi /etc/sysconfig/iptables


//vi----------------------------------------------

# sample configuration for iptables service
# you can edit this manually or use system-config-firewall
# please do not ask us to add additional ports/services to this default configuration
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
#-A チェイン -s どこから -d どこに -p どうやって --dport どこに(port) -j どうする
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
#TCP
COMMIT


＃　dport 22の上に追加する（どちらかでok）
#1.特定のIPアドレスのみ全ポート開放(使用頻度の高いもので)------
-A INPUT -p tcp -m state -s 111.222.3.4/24 --state NEW -j ACCEPT

#2.80番ポート開放------
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
```

iptablesをサービス登録

```
# systemctl enable iptables.service

# systemctl list-unit-files | grep iptables iptables.service                            

# systemctl start iptables.service
```

設定が反映されてるか見てみましょう。

```
# iptables -nL

//追加した設定があればOK
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
ACCEPT     tcp  --  111.222.3.4/24       0.0.0.0/0            state NEW
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            state NEW tcp dpt:22
REJECT     all  --  0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
REJECT     all  --  0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited
Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
```

nmapで空いてるポートを確認できます。

```
# yum -y install nmap

# nmap  111.222.3.4　＃（サーバのIPアドレスを指定すること）
```

これでファイアーウォールの変更と、ポートの開放ができました。次回もどんどん他のをいれていきます。


##参考文献
[CentOS7でfirewalldの代わりにiptablesを使用する](http://toriaezu-engineer.hatenablog.com/entry/2017/01/15/122642)
[CentOS にポートスキャンツール Nmap をインストールして使ってみる](https://www.websec-room.com/2014/02/09/1812)
GitHub GraphQLにcurlでqueryを投げる

curlでGitHubのGraphQLサーバーにqueryでデータを取得できたのでメモ。

## コマンド
```bash
curl -i -H "Authorization: bearer GITHUB_TOKEN" \
   -X POST -d "{ \"query\": \"query { viewer { login }}\"}" https://api.github.com/graphql
```

`GITHUB_TOKEN`は以下のページから自分で作成すること。

https://github.com/settings/tokens

レスポンスはこんなjsonが返ってくる

```json
{"data":{"viewer":{"login":"GitHubのユーザー名"}}}
```

## 注意点

[GitHub v4](https://developer.github.com/v4/guides/forming-calls/#communicating-with-graphql)のドキュメントを見ると、queryをjson化する必要があるようだ。


> To query GraphQL using cURL, make a POST request with a JSON payload. The payload must contain a string called query:

> cURLを使用してGraphQLをクエリするにはPOST、JSONペイロードを使用してリクエストを行います。ペイロードには、次の文字列が含まれている必要がありますquery。

これを見落としていたため、何度も通信できず大変だった。

## 教訓
ドキュメントはしっかり読もう！
ゴルーチン利用時に使用するCPUを制限する[失敗編]

ゴルーチンを利用するときに、使用するCPUの数が指定できるらしく少し試してみました。


#CPU数を1つに指定

`runtime.GOMAXPROCS`を利用することで、利用するCPUが制限できるらしい。
以下のソースだと、CPUを1つしか使わないはず。
ちなみに、`runtime.GOMAXPROCS`を指定しないと全てのCPUを利用するらしい。

##ソース
```go:main.go
package main

import (
	"fmt"
	"runtime"
	"sync"
	"time"
)

func main() {
	DATE_TIME_FORMAT := "15:04:05"
	start := time.Now().Format(DATE_TIME_FORMAT)
	fmt.Println("処理開始", start)

	var wg sync.WaitGroup
	runtime.GOMAXPROCS(1) // <---- CPU数を指定できる

	for i := 0; i < 10; i++ {
		wg.Add(1) // WaitGroupに、ゴルーチンを1つずつ追加
		go goroutine(i, &wg)
		PrintMemory()
	}

	wg.Wait() // すべての並列処理が終わるのをまつ

	end := time.Now().Format(DATE_TIME_FORMAT)
	fmt.Println("処理終了", end)
}

func goroutine(i int, wg *sync.WaitGroup) {
	defer wg.Done()              // 並列処理が終わったよ
	time.Sleep(10 * time.Second) // 10秒待つ
}

// PrintMemory メモリ調査
func PrintMemory() {
	var mem runtime.MemStats

	runtime.ReadMemStats(&mem)
	fmt.Println(mem.Alloc, mem.TotalAlloc, mem.HeapAlloc, mem.HeapSys)
}
```

##結果

実行した結果が、こちら
10秒待機する処理を、10回まわしているが
並行処理を行っているため、10秒で完了している。

```
処理開始 23:46:23
200144 200144 200144 4096000
201056 201056 201056 4096000
201536 201536 201536 4096000
202144 202144 202144 4063232
202624 202624 202624 4063232
203104 203104 203104 4063232
203584 203584 203584 4063232
204064 204064 204064 4030464
204544 204544 204544 4030464
205024 205024 205024 4030464
処理終了 23:46:33
```

#CPU数を4つに指定

変更箇所は以下

```go:
	max_cpu := runtime.NumCPU() // 搭載CPUの数が分かる
	fmt.Println("cpu数", max_cpu)
	runtime.GOMAXPROCS(max_cpu) // <---- CPU数を指定できる
```

`runtime.NumCPU()`で搭載CPU数が分かるらしい。

## ソース
```go:main.go
package main

import (
	"fmt"
	"runtime"
	"sync"
	"time"
)

func main() {
	DATE_TIME_FORMAT := "15:04:05"
	start := time.Now().Format(DATE_TIME_FORMAT)
	fmt.Println("処理開始", start)

	var wg sync.WaitGroup
	max_cpu := runtime.NumCPU() // 搭載CPUの数が分かる
	fmt.Println("cpu数", max_cpu)
	runtime.GOMAXPROCS(max_cpu) // <---- CPU数を指定できる

	for i := 0; i < 10; i++ {
		wg.Add(1) // WaitGroupに、ゴルーチンを1つずつ追加
		go goroutine(i, &wg)
		PrintMemory()
	}

	wg.Wait() // すべての並列処理が終わるのをまつ

	end := time.Now().Format(DATE_TIME_FORMAT)
	fmt.Println("処理終了", end)
}

func goroutine(i int, wg *sync.WaitGroup) {
	defer wg.Done()              // 並列処理が終わったよ
	time.Sleep(10 * time.Second) // 10秒待つ
}

// PrintMemory メモリ調査
func PrintMemory() {
	var mem runtime.MemStats

	runtime.ReadMemStats(&mem)
	fmt.Println(mem.Alloc, mem.TotalAlloc, mem.HeapAlloc, mem.HeapSys)
}
```

##結果

時間もメモリともにほとんど変化なし。
ただ、搭載CPU数は正しく取得できている。

簡単な処理内容のため差が出ていないのか、
自分の利用方法が間違っているのか不明。

```
処理開始 23:54:12
cpu数 4
199968 199968 199968 4096000
200968 200968 200968 4063232
201720 201720 201720 4063232
202360 202360 202360 4063232
202968 202968 202968 4063232
203640 203640 203640 4063232
204248 204248 204248 4030464
204856 204856 204856 4030464
205464 205464 205464 4030464
206200 206200 206200 4030464
処理終了 23:54:22
```

#結論
ネット上から情報を集めてテキトーに試したため、想定通り動作しなかった。
キチンと勉強しないとダメですね。
Ruby:  `raise` の書き方 - against Provide an exception class and message as arguments to `raise`.Style/RaiseArgs `

# raise 処理でRubocopに叱られる

Rubyでraise処理を書いた時に以下のようにしたらRubocopに叱られた。

```ruby
raise OriginError.new('これは問題です！!')
```

```console
Provide an exception class and message as arguments to `raise`.Style/RaiseArgs
```

# 修正された書き方

以下のように変更したら解決します。

```ruby
raise OriginError, 'これは問題です!!'
```

ドキュメントによると、例外クラスのインスタンスを作るより例外クラスとエラーメッセージを `raise` に渡す方が良い、とのこと。  

> This cop checks the args passed to `fail` and `raise`. For exploded style (default), it recommends passing the exception class and message to `raise`, rather than construct an instance of the error. It will still allow passing just a message, or the construction of an error with more than one argument.
>
>The exploded style works identically, but with the addition that it will also suggest constructing error objects when the exception is passed multiple arguments.

[Class: RuboCop::Cop::Style::RaiseArgs](https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/RaiseArgs)

 
# Rubocopでサポートしているスタイルは2つある

Rubocop では2種類の `raise` の書き方をサポートしています。


## Exploded - デフォルトの設定

冒頭のエラーはこの設定で発生するもので、例外クラスが複数の引数を取る時にインスタンスを作ることを推奨します。
なので以下のように書きましょう。

```ruby
# ⭕ 
raise OriginError
raise OriginError, 'これはいかん！！'
raise OriginError.new('これはいかん！！', '@masayuki14')
raise OriginError.new('これはいかん！！', user: '@masayuki14', action: :save)
raise OriginError, 'これはいかん', caller

# ❌
raise OriginError.new
raise OriginError.new('これはいかん!!')
```

## Compact

こちらは引数があれば、例外クラスのインスタンスを作ることを推奨します。

```ruby
# ⭕ 
raise OriginError
raise OriginError.new('これはいかん!!')
raise OriginError.new('これはいかん！！', '@masayuki14')
raise OriginError.new('これはいかん！！', user: '@masayuki14', action: :save)

# ❌
raise OriginError, 'これはいかん！！'
raise OriginError, 'これはいかん！！', caller
```

# 設定ファイルの書き方

`.rubocop.yml` にはこのように書きます。好みに合わせて設定しましょう。

```.rubocop.yml
RaiseArgs:
  EnforcedStyle: exploded
```

```.rubocop.yml
RaiseArgs:
  EnforcedStyle: compact
```



# そもそも `raise` はKernel Module に定義されたインスタンスメソッド

そもそも `raise` はメソッドで `for` や `if` などの制御構文と違って引数を取ることができるので、上記のような書き方ができるわけです。

```ruby
# （）をつけると急にメソッドに見えてくる
raise(OriginError, 'やっちまったな')
raise(OriginError.new('やっちまったな', user: user, action: :save))
```

https://docs.ruby-lang.org/ja/latest/method/Kernel/m/fail.html

`raise()` がとる引数についてはこちらでご確認ください。
hrefにすべきか、xlink:hrefにすべきか、それが問題だ（SVG）

SVGをHTMLに埋め込んで、動的な画像操作を行おうとしていたのですが、その過程で引っかかる場所が出てきました。

## `<image>`要素

SVGの中に他の画像を埋め込むための要素として、`<image>`という要素があります。もちろんHTML内ならHTML側の`<img>`を使っても処理ができるのですが、SVGの枠内に他の画像も取り込める、ということで、場面によっては便利です。

## 画像URIの指定は…どうする？

で、当然ながら画像を埋め込む以上は、画像URIを指定する仕組みがあります。そして、これはバージョンの変遷により2つの流儀があります。

* `xlink:href`…SVG 1.1時代の表記。XLinkという、別な名前空間（名前空間URIは`http://www.w3.org/1999/xlink`[^1]）を使う必要があります。
* `href`…SVG 2からの記法。SVGの名前空間の一部となっています。

別な名前空間の属性を使うのは（後述しますが）煩雑になりますし、SVG 2では`xlink:href`が非推奨となりますので、`href`で書きたくなるかと思います。

## 待ったをかけるiOS

ところが、ここで問題になるのがiOS Safariで、iOSでSVGの`href`属性に対応したのがiOS 12からと、（2019年7月時点から見て）かなり最近のことなのです。iOS 11以前では、`xlink:href`を使うしかありません（なお、よく互換性が問題となるIE 11でも、`href`には対応しています）。

もちろん、`xlink:href`の廃止に備えて、`href`と`xlink:href`に同じ値を指定しておくという方法もあります。この場合、`href`を認識できる環境では`href`の値が優先される、とのことです。

## JavaScriptとSVG

ちょっと本題から外れる部分もありますが、SVGをJavaScriptで操作したい場合、注意点がいろいろとあります。

### ノードやアトリビュートと名前空間

SVGのエレメントはHTMLとは別の名前空間にあるので、`document.createElement`で生成するとSVGのエレメントだと正しく認識されません。`document.createElementNS('http://www.w3.org/2000/svg', 'image')`のように`document.createElementNS`へ名前空間も指定して生成する必要があります。

また、SVG要素に付ける通常のアトリビュート[^2]はSVG名前空間で処理されるので単なる`setAttribute`で処理して問題ないのですが、`xlink:href`は別な名前空間になるので、`.setAttribureNS('http://www.w3.org/1999/xlink', 'xlink:href', 値)`と`setAttributeNS`が必要になります。

### SVGプロパティの処理

SVGはアニメーションさせることを前提として作られていますので、多くのプロパティ[^2]が`element.propertyName`で直接アクセスできず、`element.propertyName.baseVal`が指定としての値、`element.propertyName.animVal`がアニメーション中の値（読み取り専用）となっています。

`href`をアニメーションさせる場面も考えづらいのではありますが、やはり`baseVal`と`animVal`のある構造となっていまして、`element.href = 'https://...'`ではなく`element.href.baseVal = 'https://...'`のように指定する必要があります（なお、この構造はSVG 1.1とSVG 2.0で特に変わっていません）。

## 外部リンク

* [On xlink:href being deprecated in SVG](https://css-tricks.com/on-xlinkhref-being-deprecated-in-svg/)

[^1]: 名前空間URIは、（この例では説明の文書が置いてありますが）URIを使った**一意な識別子**ですので、`https://`に書き換えてはいけません。
[^2]: DOM操作を考える際に、[AttributeとPropertyは区分して考える必要があります](https://qiita.com/jkr_2255/items/66a16bd969454ee8b114)ので、「属性」とせずに「アトリビュート」「プロパティ」としています。
【Swift】 WWDC2019のWhat's New in CoreLocationについて

### 前置き
今在籍している会社でCoreLocation機能を使ったアプリ(backgroundでも位置情報を取り続けるいわゆる”足あと”機能が載っている)をサービスの一部として提供しているのですが、WWDC2019のあと、「今度のアップデートから、位置情報サービスの「常に許可」がなくなります！やばいです！」みたいな情報が社内で展開されていました。
しかし、(いまさらですが)自分でプレゼンの動画やらスライドやらを確認してみると、CoreLocationの仕様が変わるのは確からしいけど、『「常に許可」がなくなる』ってだけでは要約としてあまりに乱暴だなぁと感じたので、自分の認識をまとめます。
（社内で展開されたメールも、ソースは他人の要約記事(WWDC2019行ってきたよ～、的なノリのヤツ)で、「こういう調査・展開のしかたする(一次情報を直接確認しない)から、伝言ゲームしてるうちに不正確な情報になるんだろうなぁ」と思った次第。）

### 資料
Apple社が掲載しているWWDC2019 - [What's new in CoreLocation]のページ
https://developer.apple.com/videos/play/wwdc2019/705/

※Resourcesのところからプレゼン動画、スライドがダウンロードできます。

### 何が変わるのか
で、結局何が変わるのか。

１．**そもそも、(位置情報の利用を)「常に許可」(する状態)そのものがなくなるわけではない**
２．アプリ起動時の位置情報サービスの利用許可を求めるダイアログ(↓の画像参照)から「常に許可」(Always Allow)という選択肢がなくなる
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126315/b83d355b-a4d0-e8ed-c784-13c5e0b4788f.png" width="200">
３．位置情報サービスを「常に許可」でbackgroundでも使いたければ、今までどおりソースに`locationManager.requestAlwaysAuthorization`を書けばよい。
　→すると、以下の手順で従来の「常に許可」と同じステータスにすることは可能。
　①アプリ起動時の位置情報サービスの利用許可を求めるダイアログでは「このAppの使用中のみ許可」を選択させる
　②アプリでイベント(位置情報サービスを利用するイベント？)発生時、改めて以下のようなダイアログ(↓の画像参照)が表示されるようになるため、「Change to Always Allow(常に許可に変更)」を選択させる
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126315/3f6e4c33-a5c9-4e78-eb1d-5bb4a577a3cd.png" width="200">

### 不明点
１．新しく表示されるようになるダイアログの表示タイミング
　→スライドにある「An event occurs」って具体的にいつなのか。
　　→`startLocationUpdate()`が呼ばれたら？
　　　もしくは`locationManager(_:didUpdateLocations:)`？
２．「設定」アプリの位置情報サービスの画面イメージ
　→アプリ起動時のダイアログだけでなく、
　「設定」アプリの位置情報サービスの設定画面からも「常に許可」は消えるのか。

### まとめ
とにかく、「常に許可」に設定するまでのフローは少し変わるものの、状態そのものがなくなるわけではなさそうなことが分かった。
もし認識に間違い・補足等があればご指摘頂きたいです。

情報展開してきたヤツには、Appleから簡単にプレゼン資料なり動画なりが入手できるんだし、自分で中身読まないにしてもリンク貼るなりファイル貼るなりしろよと言いたい。
なるべく一次情報に近いものを根拠資料として示すのは情報展開の基本だと思う。

・実際試して仕様を確認した
　＞公式のマニュアルにそう書いてある
　　＞公式に問い合わせた結果、回答がこうだった
　　　＞他の人の問合せ履歴を見るに、回答がこうだった
　　　　＞他の人が実際にためした結果、こういう仕様らしい　、、、みたいな。

枯れた言語を、社内独自のフレームワークで開発してるせいで、
あんまり技術とか仕様とかを調べることに慣れてないんですよね、ウチの会社。。
mark.jsを使ってみた

webページを作っている時、ページ上の任意の文字列をCSS等でハイライトしたい時がある。

そのような時、愚直にタグで囲んでCSSで装飾を施してもいいが、特定の文字列あるいは文字列の位置を指定することで、ハイライトできると便利。

そんな時に使えるのが、`mark.js`。

## mark.jsとは

公式ページは[こちら](https://markjs.io/)

mark.jsはJavaScriptで書かれたtext highlighter（蛍光ペンとかの意味がある）。


## 例

とりあえず、どんなコードでどういう出力がされるのかみてみる。

```html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<meta charset="utf-8">
<meta name="description" content="">
<meta name="author" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="">
<script src="https://cdnjs.cloudflare.com/ajax/libs/mark.js/8.11.1/mark.min.js"></script>
</head>
<body>
<div id="hoge">今日はいい天気。天気がいいと体調もいい</div>
</body>
</html>
<style>
mark{
    background: orange;
    color: black;
}
</style>
<script>

var hoge = document.querySelector("#hoge");
var instance = new Mark(hoge);

instance.markRegExp(/天気/gmi);

instance.markRanges([{
    start: 0,
    length: 2
}])
</script>
```

上記ではcdnで提供されたファイルを利用している。

出力は以下。（web pageのscreenshotである）


|<img width="320" alt="スクリーンショット 2019-07-12 9.15.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88357/dbfcd883-feae-a726-dcf8-8f27e0b4afc4.png">|
|:-:|

「天気」文字列のハイライトは、正規表現により実現されている。

```js
instance.markRegExp(/天気/gmi);
```

「今日」文字列のハイライトは、開始位置（start）とハイライト対象文字列の長さ（length）を指定することで実現されている。

```js
instance.markRanges([{
    start: 0,
    length: 2
}])

```

css部分を変更することで、ハイライトの色やサイズ等が変更できる。
これは、実際に動的に生成されるHTML部分が以下のようになっているからである。

|<img width="259" alt="スクリーンショット 2019-07-12 9.21.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88357/3ab44ec4-ef43-0cb5-b4c5-57286cad838f.png">|
|:-:|

ここから、同一タグ内の文字列に対して別々のCSSを当てることができないことがわかる。

### mark()

`mark`関数を利用することで、`mark`タグを任意のタグに変えることができる。
以下のように、`mark`関数でオプション指定することで、`mark`タグだった部分が指定されたタグに変更されている。

```js
instance.mark("天気", {"element": "span"});
```

|<img width="257" alt="スクリーンショット 2019-07-12 9.27.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88357/78e8f077-b4fd-b0d0-33ba-0b42fb932d63.png">|
|:-:|

詳しいオプションについては、[公式ドキュメント](https://markjs.io/)の4.2のmark()を読んでほしい。

`filter`オプションを利用することで、特定の文字列のハイライト数の制限も可能だ。

## ブラウザ互換性について

この記事の執筆時点では以下のモダンブラウザに対応しているとのこと。

- Firefox (30+)
- Chrome (30+)
- Safari (7+)
- Edge (13+)
- IE (9+)
Homestead - Laravel を使っててなんか RuntimeException とかで壊れた時にとりあえず試すこと

# Key作り直し

```
vagrant ssh
cd <code directory>
php artisan key generate
```

# migrate

```
vagrant ssh
cd <code diresctory>
php artisan migrate
```

# composer install

```
vagrant ssh
cd <code directory>
composer install
```

# キャッシュ削除

```
vagrant ssh
cd <code directory>
php artisan cache:clear 
php artisan config:clear 
php artisan route:clear 
php artisan view:clear 
```

# storage 以下とかのいらなさそうなファイル消す

```
rm -rf storage
git checkout HEAD storage
```

# git で出てる変な差分消す

※差分消えるので注意

```
git stash
git clean -fd
```

# .envの設定ちゃんとできているか確認

確認する

```
edit .env
```

# 環境作り直し

```
vagrant destroy
vagrant up
```

# ボックスダウンロードし直し

```
vagrant box list
vagrant box remove <box>
```

# .vagrant を消す

```
rm -rf .vagrant
```

これ消すとVirtualBoxにゴミができる可能性があるので、VirtualBoxのアプリケーション（GUI）を開いてBoxを削除した後 `vagrant up` するといい。

# Virtualboxのバージョンアップ

https://www.virtualbox.org/

# Vagrantバージョンアップ

https://www.vagrantup.com/
Ubuntuで画面リソースを節約して作業効率爆上げ

###13.3型ノートPCはハンドリングが良いが、画面が小さい。。。

ノートパソコンを使ってるエンジニアの皆さんは多いですよね。
でも、２ND画面がないとなかなか、画面がしんどい。。。。

そこで今回は画面リソースを節約して、作業効率を上げる、僕のセッティングをまとめてみます！

こういうのもいいよ！とか、これ間違ってる！とかあったらどんどんコメントしていってください！

#### 環境
<hr>
ubuntu19.04
libinput
tmux
guake
<hr>

### libinputでタッチパッドジェスチャーの設定をする
概要導入は以下記事がわかりやすいデス！
https://qiita.com/onokatio/items/c386da501d11a9735915


##### ~/.config/libinput-gesture.confを編集
ここはお好みですが
僕の設定は以下の通り

```
gesture swipe left 3 xdotool key super+Left
切り替え
gesture swipe right 3 xdotool key super+Right
#三本指左右スワイプで、画面分割

gesture swipe up 3 xdotool key alt+Tab

gesture swipe down 3 xdotool key alt+shift+Tab
#三本指上下スワイプで、ウィンドウ切り替え

gesture swipe up 4 xdotool key super+Page_Down

gesture swipe down 4 xdotool key super+Page_Up
#４本指上下スワイプでワークスペース切り替え

gesture swipe left 4 xdotool key control+Tab

gesture swipe right 4 xdotool key control+shift+Tab
#４本指左右スワイプでタブの切り替え

gesture pinch in xdotool key F12
gesture pinch out xdotool key F12！
#ピンチアップ、ダウンでターミナル呼び出し（指の動きは拡大みたいなかんじ、後述のguakeと連携）

```

これで例えば、クローム開きながら、Vscode打ちながら、気が向いたらターミナル打ってみたいなことができます。

### guakeの設定
guakeの導入↓
https://qiita.com/puttyo_bubu/items/6cab623f377a282e3635

MACでいうItermみたいな感じ
端末を開かなくても、F１２キーを押すとぬるっと出てくる。

さっきの設定でF１２キーにタッチパッドのキーバインドを当てたので、ラクラク開ける！

![Screenshot from 2019-07-12 09-25-48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307982/d9b2b53f-1fda-9fb7-b3bb-0d69ae3acef2.png)

これで、クローム見ながらコマンドやコードがガシガシ書ける。
もう、マウスなんて必要ない！
90年代～とある中小ICT企業の社内システム

90年代～当社社内システム開発の経歴です。
こういう例は当社だけかも知れませんが・・・

個人的には本当に楽しかったです。

##そもそも兼自己紹介
- 自分が中学生の頃に、父親が中央システムを起業、兄がいます
- 文系大学を卒業し、食品流通系の営業職へ
- 1998年に中央システムに入社、経営に参画しました

##中央システム入社時
- ICTスキルゼロ、ICT関連の経験は、前職での売上入力くらいでした
- 技術職ではないが商品（ICT）知識は必要、以降全て独学しました

##社内ポータルが無かった
・勤務報告も経費精算も、メールでExcelファイルなどをやりとりしていました
・事務担当の目検に完全依存していました

##なので自力で社内ポータルを開発
技術職では無いし、経営などの実務や勉強を優先するべきなので、孤独な非公式プロジェクトでした。

###IIS ＋ Perl（CGI） ＋ OLEオートメーション
- Webからサーバー内のExcelファイルへデータを送り、Excelが計算 、データを返す、という仕組み
- サーバーのスペックがダメだった事もあり、非現実的なレスポンス、全然ダメでした、笑ってしまうくらい

###IIS ＋ Perl（CGI）
- 何となくIISに限界を感じ始めました、自分のスキルが低かっただけです
- DBも必要です

###Apache（Windowsクライアント内） ＋ Perl（CGI） ＋ PostgreSQL
- だいぶそれらしくなってきました
- 実装するのはLinuxサーバーが良いと判断し勉強、研修用ノートPC１台を密かに拝借、サーバー構築（RedHat）
- PHPというものを知りました、Perlよりイケてると感じ、導入を決めました

###Linux（CentOS） ＋ Apache ＋ PostgreSQL ＋ PHP 本格構築へ
- サーバー機が必要、前述の研修用ノートPCはいくら何でもなスペックでした（W98世代）
- 個人でPCを自作していて、ケースや電源は余っていました
- マザーボードは、アキバで箱潰れ見切り品を購入しました（非公式プロジェクトなので全て自費）
- 勤務報告、経費精算機能等々
- 2006年くらいから実運用

###止めました
- 2008年に社長になりました
- 保守と開発をしているのは社長、直近で継承の見込みも無さそう、管理部門に人がいませんでした
- 順次、外部WEBサービスへ移行して運用を停止しました

###新ポータルサイト開発~現行
- 管理部門要員も増えたし、ICT企業だし、もう一度開発・運用しよう
- 2014年あたりから開発に着手しました
- Linux（CentOS） ＋ Apache ＋ MariaDB ＋ PHP
- これはさすがに公式プロジェクトでした

##今後は
オンプレミス、スクラッチな手作り、な時代では無いので、クラウドの便利なものに移行します。
個人の趣味プラスアルファでは無くて・・・でも、繰り返しになりますが、本当に楽しかったです。

[二代目社長 社内システム開発のもっと内実](https://qiita.com/k_iwamoto/items/356688ef329ad0558704)
Kibana の 日本語化

1. 日本語ファイルを取得
====================== 

```:ja-JP.json配置
cd /usr/share/kibana/node_modules/x-pack/plugins/translations/translations
wget https://raw.githubusercontent.com/elastic/kibana/master/x-pack/plugins/translations/translations/ja-JP.json
```

2. 設定ファイル変更
==================

```:/etc/kibana/kibana.yml
# Specifies locale to be used for all localizable strings, dates and number formats.
i18n.locale: "ja-JP"
```

3. 再起動
=========

```
# systemctl restart kibana
```
【SQL Server】ストアドプロシージャ実行権限を付ける

# 概要
SQL Serverでユーザーに検索や書込みの権限を与える場合、定義済みのロール`data_reader`や`data_writer`を割り当てれば良い。しかし、これだけではストアドプロシージャの実行権限は付かない。実行権限が付くロールは用意されていないので、自分で作成する必要がある。

# サンプル
```sql
-- ロールを作成
CREATE ROLE db_execute
-- 作成したロールに「実行」権限を与える
GRANT EXECUTE TO db_execute
-- 作成したロールをユーザーに割り当てる
ALTER ROLE db_execute ADD MEMBER [ユーザー名]
```
apacheとphpの環境をkubernetesで構築する

# Docker for Macでkubernetesを起動
dockerアプリからpreferencesを開き、kubernetesの「Enable Kubernetes」にチェックを入れて、kubernetesを有効にする。

```
kubectl config get-contexts
```
を実行して、CURRENTが”docker-for-desktop”になっていることを確認

仮に”docker-for-desktop”になっていない場合には、下記コマンドでCURRENTを変更

```
kubectl config use-context docker-for-desktop
```

下記コマンドにて起動しているMaster Nodeを確認

```
$ kubectl get nodes
NAME                 STATUS    ROLES     AGE       VERSION
docker-for-desktop   Ready     master    203d      v1.10.11
```

# dockerを準備
## ディレクトリ構成
```
workspace .
├── app
    ├── phpinfo.php
    └── index.php
└── docker
    ├── apache-php
    │   ├── vhost.conf
    │   └── Dockerfile
    └── templates
        └── main.yaml
```

```php:phpinfo.php
<?php
  phpinfo();
?>
```

```php:index.php
<?php
  echo "現在の時間は".date("Y/m/d H:i:s")."です。";
?>
```

```conf:vhost.conf
<VirtualHost *:80>
    DocumentRoot /var/www/html
    ServerName localhost
    ServerAdmin root@example.com
    LogFormat "[%V] %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" custom
    ErrorLog /etc/httpd/logs/error_log
    CustomLog /etc/httpd/logs/access_log custom
    <Directory "/var/www/html">
        AllowOverride All
        Options Indexes FollowSymLinks SymLinksIfOwnerMatch
    </Directory>
</VirtualHost>
```

```Dockerfile
FROM php:7.2.6-apache

ADD vhost.conf /etc/apache2/sites-available/vhost.conf
```
下記コマンドでdocke imageを作成

```
$ docker build -t k8sdemo/php-apache:1.0.0 docker/apache-php
```

# クラスタ上にコンテナを起動するためのyamlを準備
```yaml:main.yaml
apiVersion: v1
kind: Service
metadata:
  name: ssdemo-service
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: ssdemo-apache-php
---
apiVersion: extensions/v1beta1
kind: Deployment # リソースの種類
metadata:
  name: ssdemo-deployment # Deploymentの名前
spec:
  replicas: 2 # 起動するpod数
  template:
    metadata:
      labels:
        app: ssdemo-apache-php # podの名前
    spec:
      containers:
      - name: ssdemo-apache-php # コンテナ名
        image: k8sdemo/php-apache:1.0.4 # コンテナイメージ
        imagePullPolicy: IfNotPresent # ローカルのdocker imageを使用
        ports:
        - containerPort: 80 # コンテナのポート
        volumeMounts:
        - mountPath: /var/www/html/
          name: demo-volume
      volumes:
      - name: demo-volume
        hostPath:
          # directory location on host
          path: /Users/ytada/Documents/k8sdemo/app
          # this field is optional
          type: Directory
```
# 各yamlをクラスタにデプロイ
下記コマンドよりクラスタにデプロイ

```
$ kubectl apply -f main.yaml
```

# クラスタの状況を確認
```
$ kubectl get all
```

# サービスを確認

```
http://localhost/
http://localhost/phpinfo.php
```
Lesson Test Automation

# Outline
team members（マニュアルテストの知識はある）にテスト自動化に関して教える機会があった。
一部の人は、いまだに銀の弾丸的に思っている人がいます。
その人たちに、正しいテスト自動化を理解してもらい、かつ自動化の簡単な実装できるようにするためのコンテンツを作成した

コンテンツとして４つに絞った

- Purpose of Test Automation
- Test automation tool 
- Test automation process (End to End test)
- Test automation pyramid

本来、テスト自動化には上記以外にも以下の項目も学ぶべきではある。

- Metrics
- Pilot Project / deployment
- Generic Automation Architecture

ただ、まずは自動化の基本を学び、実際に実装フェーズに進めたいため、それに関連性の薄いものは除いた

尚、英語で説明したのでコンテンツは英語ですｗ

<A HREF="https://www.slideshare.net/SadaakiEmura/test-automation-lesson"><IMG SRC="//image.slidesharecdn.com/test-automation-lesson-190710003031/95/slide-1-1024.jpg" WIDTH=80%></A>

# Purpose of Test Automation

まず、テスト自動化を学ぶ人にとって、どれだけギャップがあるかを知ることから始めた
そのためにテスト自動化の目的やメリットデメリットを解説する

# Test automation tool 

自動化といってもシステムテスト実行だけではないことを知ってもらう。
自動化をV字モデルの各工程に導入することで、それぞれで効率化など図れることを知ってもらう

# Test automation process (End to End test)

テスト自動化の設計から開発、運用までの一連のプロセスの解説。
各工程でどのようなことをやるのかなどを知ることで、さらに自動化に関して正しい認識をしてもらう

# Test automation pyramid

余談的に入れました。
システムテストの自動化バンザイにならないように全体的なバランスの必要性を知ってもらう
[ZF3]  エスケープ取り扱いについて


# Zend Escaper

> zend-escaper は、1 つのクラスである Zend\Escaper\Escaper を提供し、出力をエスケープするための 5 つのメソッドを提供します。どの方法を使用するかは、出力が使用されるコンテキストによって異なります。

>escapeHtml: HTML 
本文コンテキストの文字列をエスケープします。

>escapeHtmlAttr:
HTML 属性コンテキストの文字列をエスケープします。

>escapeJs: Javascript 
コンテキストの文字列をエスケープします。

>escapeCss: 
CSS コンテキストの文字列をエスケープします。

>escapeURL: 
URI または URI パラメーター コンテキストの文字列をエスケープします。

*

> zend-escaper は、出力用のデータをエスケープする場合にのみ使用されることを目的としており、入力データのフィルタリングに誤用してはなりません。このようなタスクでは、zend-filter、HTMLPurifier、PHP のフィルタ機能を使用する必要があります。

```vim
$escaper = new Zend\Escaper\Escaper('utf-8');


$escaper-> escapeHtml('<script>alert("zf2")</script>');

$escaper->escapeHtmlAttr('<script>alert("zf2")</script>');

$escaper->escapeJs('<script>alert("zf2")</script>');

$escaper-> escapeCss('<script>alert("zf2")</script>');

$escaper-> escapeUrl('<script>alert("zf2")</script>');

```

# 参考
[https://docs.zendframework.com/zend-escaper/intro/](https://docs.zendframework.com/zend-escaper/intro/)
Tableauで日付型のディメンションのヘッダ名を変更する方法

Tableau Desktopで日付型ディメンションのヘッダ名の変更ができなくて詰まったのでメモ。
日付型ディメンションの機能を使って「年/月/日」を生成するとヘッダ名が自動的に`日（ディメンション名称）`で固定されます。
ヘッダ名を制御したい場合は、日付型ディメンションの機能である`正確な日付`を選択した上で書式設定を使います。

#環境
- Tableau 2019.2.1
- スーパーストア(データソース)

#日付型ディメンションの機能だと名称を変えられない
日付型ディメンションのピルを列/行にドロップすると、自動的に日付型ディメンションの機能が適用されて、日付型がTRUNCされます。
<img width="976" alt="スクリーンショット 2019-07-12 7.49.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337794/c202bab7-2464-b6e2-f345-706842dcae68.png">
いったん日付型ディメンションがTRUNCされるとヘッダ名を変えられなくなります。
（正確に言うと、「`日(ディメンション名)`」のうち`ディメンション名`は変えられますが、`日()`は変更できません。）

#日付型ディメンションの名称を変える方法
ヘッダ名から`日()`の表示をなくすためには、`正確な日付`を選択してディメンション本来がもつ生データを表示させます。
（つまりDBやCSVファイルなどに取り込まれているローデータということ）
<img width="893" alt="スクリーンショット 2019-07-12 7.50.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337794/33ebc6d6-ccd6-f0f8-45d0-b6eca0e0a79b.png">
これでヘッダ名から`日()`の表示がなくなり、ディメンション名のママになりました。
デフォルトは`yyyy/mm/dd`型で表示されますが、書式設定によって変更も可能です。
<img width="723" alt="スクリーンショット 2019-07-12 7.50.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337794/9a536d12-1120-d2ad-e101-72ae7bbf7b07.png">

#まとめ
ヘッダ名などの細かい表示は自分用に分析するだけであれば別にどうでもいいことなのですが、Tableau ServerにPublishしてクライアントに共有する場合などはそうも言ってられません。。。
Tableauはアドホック分析に関しては操作性がいいですが、細かい表示の修正などは結構小ネタがあったりして面倒な印象です。
Makefileを使って、Pods と Carthage の待ち時間を短縮した話🌞

## 対象者
・Pods と Carthage の両方を管理ツールとして使っているあなた。


## Pods と Carthage をどっちも入力するのはもう飽きた。

そうだ。エンジニアなんだから効率化しなきゃ。
一つのコマンドでどっちも実行できるようにすれば良いではないか！！！
何やら、「Makefile」なるものがあるらしい。

詳しくはここ↓↓↓↓↓↓↓↓
[GNU makeについて](https://www.mlab.im.dendai.ac.jp/~tobe/xp-2/gmake.html)
[Makefileの書き方](http://shin.hateblo.jp/entry/2012/05/26/231036)




## Makefileの作成

以下のファイルを作成します。 
Podfile と Cartfileと同じ場所に作りましょう。

```Makefile:Makefile

## CocoaPods Carthage をどっちも実行するぞ！！！
Pod_Carthage: Podfile Cartfile
	pod install
	carthage bootstrap --platform iOS --no-use-binaries
```



## あとは実行するだけ
ターミナルで Podfile と Cartfile がある場所に行き、

`make` を入力して、***エンターを勢いよく押せば、***

`pod install`
`carthage bootstrap --platform iOS --no-use-binaries`

が一気に走ります。

これで、待ち時間を短縮できますね！！！
pods が終わるのを待たずとも、 Carthageも始まるので良いです！


**Makefile便利ですね！！！**


## こっちも読んでもらいたい☺️
[〜拝啓〜 アプリ開発を始める半年前の自分へ。アプリ公開初日に300ユーザーを獲得できるぞ!!!](https://qiita.com/yamatatsu10969/items/96a1462997b4478f9aea)


### 間違っていることがあればご教授ください🙇‍♂️
NodeJSでShift-JISのDB2からデータを取得

Visual Studio CodeでNodeJSのアプリを開発中に発生した文字化けに関する記事です。
NodeJSにて文字コードがShift-JISのDB2データベースのテーブルから、日本語を含むデータをSELECTすると文字化けが発生しました。
NodeJSはUTF8ですが、その情報がドライバに伝わらずコード変換が正しく行われていないようです。
そんな時はクライアント側の文字コードをprocess.env.DB2CODEPAGEに設定しましょう。

```Javascript
let ibm_db = require('ibm_db');
let settings = require('./settings');

// クライアント側の文字コード（UTF8）を明示しドライバにコードを変換させる
process.env.DB2CODEPAGE = 1208;

var db_str = "DATABASE=" + settings.db_name
+ ";HOSTNAME=" + settings.db_host
+ ";UID=" + settings.db_username
+ ";PWD=" + settings.db_password
+ ";PORT=" + settings.db_port
+ ";PROTOCOL=TCPIP;";
var sql = "select name from test";

ibm_db.open(db_str, function(err, conn) {
  if(err) return console.log(err);

  conn.query(sql, function(err, data) {
    if(err) {
       console.log(err);
    } else {
      for (let index = 0, max = data.length; index < max; index++) {
        console.log(data[index].name);
      }
    }

    conn.close(function() {
      console.log('done.');
    });
  });
});
```

以上です。
TECH　DAY　−２　Ruby

勉強した項目：　Ruby概要　
時間： 2:００
内容：
＊学習アウトプットです。なにぶん間違いなんかもあります。気をつけますがその際はご指摘いただけますと幸いです＊

###【Rubyの基礎、ディレクトリ】　

　•**ルートディレクトリ**：階層構造の一番上にあるディレクトリがルートディレクトリ
　•**カレントディレクトリ**：ターミナルで現在作業中となるディレクトリ
　•**ホームディレクトリ**：新規にターミナルを立ち上げた場合に作業中となるディレクトリ、`〜`で表される

###【linuxコマンド】

　`lsコマンド`：lsコマンドはlistの略で、フォルダやファイルの一覧を表示するコマンド
　　　　　　カレントディレクトリの直下にあるファイルやフォルダの名前が一覧で表示

　`cdコマンド`：カレントディレクトリを移動するときに使う

###【パスの指定方法】

　`絶対パス`：絶対パスはルートディレクトリから指定するパス。
　　　　　　絶対パスで指定するときにはパスの一番最初に　/　を指定する

　`相対パス`：現在いるディレクトリ(カレントディレクトリ)から指定するパス。
　　　　　　相対パスで指定するときにはパスの一番最初に　/　を書かない

###【Rubyの拡張子】
　Rubyの拡張子は     `.rb`

###【オブジェクト】
　Rubyで扱える全てのデータは、「オブジェクト」


|   オブジェクト名	   |     扱うもの   |
|-----------------:|:-------------|
|   文字列オブジェクト  |     文字      |
|   数値オブジェクト    |      数       |
|   時刻オブジェクト    |     時間      |
|  日付オブジェクト	   |     日付      |
|  配列オブジェクト	   |   複数のデータ  |


###【文字列】
　文字列は文字を`""`**(ダブルクォテーション)**、または`''`**(シングルクォテーション)**で囲むことで定義

###【メソッド】
　`メソッド`とはプログラミングにおける何らかの処理をする命令群

###【putsメソッド】
　`putsメソッド`はターミナル上に文字を出力するためのメソッド

###【rubyコマンド】
　rubyコマンドはRubyに関する様々な操作をターミナルで行うために必要なコマンド、`ターミナル`に打ち込む


###【起こりやすいエラー】
　・全角スペース
　・スペル間違い
　・閉じタグがない
【メモ】xml関連の覚書（書きかけメモ）

#PythonでのXML処理を高速化したい
初心者として、とりあえずElementTreeを使ってきたわけだが、どうにも処理速度に満足できない。

ひとまず、lxmlというものを勉強し始めようかと思う。
https://www.ibm.com/developerworks/jp/xml/library/x-hiperfparse/index.html
https://www.haya-programming.com/entry/2018/02/21/005902
https://techacademy.jp/magazine/19063
https://python.keicode.com/advanced/xml-lxml-1.php

http://myuon-myon.hatenablog.com/entry/2013/08/12/111351
PythonとBeautifulSoupで初スクレイピング

機械学習をコツコツと勉強して居て、その上での必須スキルであるスクレイピングをそろそろ身につけたいなと。で、トライしてみました。
環境は敢えてWindowsでやりました。画像とか扱うこと多いだろうし、それだったらWindows上の方が何かと便利かと思いまして。言語は未だに不慣れなPythonの修行も兼ねるのでもちPython。
Pythonでのスクレイピングにはseleniumを使うという選択肢もあるようで試してみたのですが圧倒的にBeautifulSoupの方がよさそう。
何を採ろうかと迷ったのですが、日頃からお世話になっているqiita様に実験台になって貰いました。トレンドの一覧を抜いてみました。
そして初のスクレイピングのコードはこんな感じになりました。

```
from bs4 import BeautifulSoup
import urllib.request as req
import json

url = 'https://qiita.com/'
res = req.urlopen(url)

soup = BeautifulSoup(res,"html.parser")

#二つ目の配列にトレンドの本体のJSONがある
items = json.loads(soup.select('div[data-hyperapp-app]')[1].get('data-hyperapp-props'))

#投稿者の画像を入れる配列
images = []
for item in items['trend']['edges']: #
    #個々の投稿はnode配下
    print(item['node']['title']) #トレンドに表示されている文字列
    auth = item['node']['author'] #投稿者の情報
    images.append(auth['profileImageUrl']) #投稿者のアイコンへのURLを配列に格納
    print('---s---')

#格納した投稿者のアイコンへのURLを一覧表示
print('-----img-----')
for url in images:
    print(url)
```
Chromeのディベロッパーツールで取りたい情報の位置を探りながら。またVisual Studioで開発したので充実したデバッグ機能にも助けられました。
試していくと色々面白そうですね。機械学習用データ収集と言うより単純にスクレイピングそのものにはまりそうな感じすらしますw
【初心者】Pythonでデータ連携フォームを作成してみた。

[未来電子テクノロジー](https://www.miraidenshi-tech.jp/)でインターンをしている**to-fu16**です。
Pythonを用いてデータ連携フォームを作成したので、概要を簡単に解説したいと思います。

#全体の構成
今回は、データ連携フォームを作るに当たって、input.py、confirm.py、complete.py、index.pyという４つのファイルを用意しました。
ここからはそれぞれのファイルで行った処理について解説します。

##input.py
input.pyではデータを入力するためのフォームを表示しました。
htmlのformタグのPOSTメソッドを利用してデータの送信を行いました。
htmlのバリデーション機能を使って、データの入力形式を制限しました。

##confirm.py
confirm.pyではinput.pyで得たデータを取得し、データベースに値を入れました。
その処理と同時に確認画面を表示し、入力したデータを確認できるようにしました。
もし、入力されたデータが求めている形式のものでなかった場合、警告文を表示し、input.pyに戻ることが出来るようにしました。

##complete.py
complete.pyでは登録完了の表示を行いました。
また、index.pyに接続することが出来るボタンも付けました。

##index.py
index.pyではデータベースに保存された値を表で表示しました。
データベースの値をhtmlで表示する際は、データの型に注意する必要があります。

#おわりに
今回はデータ連携フォームの流れを簡単に解説しました。
プログラミング初心者の方はてこずってしまうかと思いますが、エラーが出た箇所を直すという作業を繰り返すことで完成に近づいていきます。
どうしても分からないときは先輩プログラマーの力を借りて、頑張って完成させましょう。
自己流の新しい言語、フレームワークの勉強方法

#はじめに
色々な勉強法があると思う
従業員を見ているとほとんどが、書籍だったり公式ドキュメントを見て勉強をしている
が、私の勉強法が全く市民権を得てないので
紹介したい

#Githubからサーチする

Githubサーチが便利
https://github.com/search
![SnapCrab_NoName_2019-7-12_4-4-59_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13916/8e93d04f-3f43-02f3-b7a8-7c57560292e3.png)

たとえば、Goのechoを勉強したいとする

Advanced optionから LanguageをGoにする
検索欄には 
language:go
になっている
そこに echoを足し
echo language:go
にして検索すると、プロジェクトがいっぱい出てくる
あとはMostStarなりMostForks、RecentlyUpdated
などで検索する
最もStarがついているコードは良いコードのはずだ！
と思っている

![SnapCrab_NoName_2019-7-12_4-4-45_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13916/dd5ce4e2-423c-0b1d-9ac9-a360743241e4.png)


たいていトップには、フレームワークの実装が現れる
フレームワークの実装コードを読むことは大事！だし
そこにあるサンプルは非常に有用だ。

ここから色々なプロジェクトを見ていけばいい

そして別の事で困ったら
例えば echoでmysql使いたくなったら検索ワードを変えて試せばいい


これらのコードを読んで分からない事が出たら
改めて、公式のドキュメントを読んだりWebで検索


以上、私の勉強法でした
Windows 7でセキュリティエラーが出たら、SSLが有効なコンポーネントが残っていた

~~Windows 7 なんて化石っぽいOS使ってるなんて石を投げないでください。~~
もしかしたら同じ人いる可能性もある(かもしれない)ので一応メモ残します。

## 発生した問題

Windows 7の環境でRuby系整理したいと思ってrbenvをインストールしたところ、`rbenv install` で以下のエラーが。

```
PS > rbenv install 2.6.0
download 2.6.0 ...
セキュリティで保護されたチャネル サポートでエラーが発生しました
```

## 対処

Googleに直接エラーメッセージ打ち込んでGitHubで見かけたパッチ [MicrosoftEasyFix51044](http://download.microsoft.com/download/0/6/5/0658B1A7-6D2E-474F-BC2C-D69E5B9E9A68/MicrosoftEasyFix51044.msi) をポチりと適用して直りました。
他のサイトで見たところ、旧SSL系やら古いTLSを止める対処みたいなので、どうも旧SSL系が有効になっているコンポーネントがあったみたい。


## 原因(ぽいもの？)

rbenvの中身見たところ、vbsからのHTTPアクセスで `Msxml2.ServerXMLHTTP` という懐かしい記述が。。。
最近めっきり見ないコンポーネントであまり触らないからちゃんとセキュリティパッチとか個別当てサボってたみたいで\_(:3」∠)_


## 関連で確認した外部リンク

- [Windowsのコマンドラインからrbenvを使いたい](https://qiita.com/nak1114/items/0cbf4797d95422b04569)
- 該当のパッチ見つけたのは某githubリポジトリのコミットログより。
    - archived だったのでリンクは貼りません。
pythonなど初めての人向けの文献案内

# For beginner

## Editor

- VSCode: https://code.visualstudio.com/
- emacs or vim（GUIなしの環境でもいいように最低限どちらかが使えるように）

## Python

- Python Tutorial: https://docs.python.jp/3/tutorial/index.html

## Git

- とにかくGitHubに登録しよう: https://github.com
- Learning Git Branching: https://learngitbranching.js.org/
- Learn git in Y minutes https://learnxinyminutes.com/docs/git/
- gitbook: https://git-scm.com/book/ja/v2

## Linux

- Linux標準教科書: http://www.lpi.or.jp/linuxtext/text.shtml
- Basic Linux Commands for Beginners https://maker.pro/linux/tutorial/basic-linux-commands-for-beginners

## Bash

- Learn bash in Y minutes https://learnxinyminutes.com/docs/bash/

## Markdown

- Mastering Markdown https://guides.github.com/features/mastering-markdown/

## Computer Vision

- opencv-python tutorial
- 画像処理百本ノック: https://github.com/yoyoyo-yo/Gasyori100knock

## Deep Learning

- pytorch samples: https://github.com/pytorch/examples
Ubuntuでgoofysがメモリを大量に掴みっぱなしになる場合の対策

AWS S3(及びその互換オブジェクトストレージ)をLinuxのファイルシステムとしてマウントできるgoofysはなかなか重宝します。
goofysのインストール、設定についてはqiita内にいい記事がいくつもあるのでそれを参照してください。
しかし、気がつくとgoofysがこんな風に結構なメモリを掴みっぱなしになることがあります。

```
 8960 *******   20   0  872988 378244  11384 S  0.0 18.5   0:35.59 goofys
```

上記は自分の使っているサーバーでの実例ですが、goofysが400MB弱のメモリを掴んでいました。umount/mountすると一度20MB程度まで減るのですが、暫く経つとまたこうなります。

# 犯人はupdatedb
Ubuntuを普通にインストールすると、ファイル検索を高速化するためのupdatedbが日に一回実行されるように設定されます。これがgoofysでマウントされたディレクトリツリーについても探索するため、ディレクトリ構造によっては大量のメモリを消費してしまいます(そして残念なことに開放されない)。
そこで、updatedbの探索範囲からgoofysでマウントしている部分を除外する設定を行います。

```/etc/updatedb.conf
PRUNE_BIND_MOUNTS="yes"
# PRUNENAMES=".git .bzr .hg .svn"
PRUNEPATHS="/tmp /var/spool /media /home/.ecryptfs /var/lib/schroot"
PRUNEFS="NFS nfs nfs4 rpc_pipefs afs binfmt_misc proc smbfs autofs iso9660 ncpfs coda devpts ftpfs devfs mfs shfs sysfs cifs lustre tmpfs usbfs udf fuse.glusterfs f#use.sshfs curlftpfs ecryptfs fusesmb devtmpfs fuse fuse.goofys"
```

PRUNEFSで探索から除外するファイルシステムを指定するので、この末尾に"fuse fuse.goofys"を追記しています(fuseだけでいけると思いますが念の為)。
もしくは、goofysのマウントポイントをPRUNEPATHSに追記します。
(ファイル探しにlocateコマンドを使わないなら、`/etc/cron.daily/mlocate`を削除してupdatedbの実行自体を止めるのもありです)
これで何日経ってもgoofysのメモリ消費はほぼ増えなくなります。

# そもそも、
goofysでのmount時にallow_otherを指定せず単一のユーザーからだけ見えるようにしておけば、rootでマウントを実行していない限りupdatedbから見えないんですけどね。そこは諸般の事情で。
私が勉強・開発時に使っている効率化ツール＆Webサービス

とある投稿には、Qiitaの利用者にMacが圧倒的に多いとかかれていました。　　
が、Macは高額で、スペックを少し上げるぐらいでバカなお金が必要で、援助なく自力で買おうとすると、やや辛いです。

一方、世の中にはすごい開発者がたくさんおられて、Windowsでも効率性をアップするツールや、便利なツールがあり、今使っているのを簡単紹介したいと思います。詳細は各自にHPを確認してください。（後日設定方法も更新するかも）

##  Terminal
cmderを使っています。[Homepageはここをクリック](https://cmder.net/)

## Search file
* Everything [詳細←](https://www.voidtools.com/)
* listary　[詳細←](https://www.listary.com/)

コメント：2つのソフトそれぞれ自分のメリデメがあり、サーチスピードや使用方法なども若干違います。個人はノートPCでlistaryと、デスクトップにはEverythingを入れています。

## Google extension
### [Diigo](https://www.diigo.com) <- 詳細ここクリック
普段よくノートPCとデスクを交換で勉強しているため、ネットで見ていたすごい言葉、要注意な点など、記録するには苦労しました。Diigoはまさにこの問題を解決してくれるサービスです。ログインすれば、ページに文やSentencesをHighlightすることができ、同期もできちゃいます。　　また、タグ付けや、ReadAfterの機能も付き、すごく便利です。

### [Vimium](http://vimium.github.io/) <- 詳細ここクリック
主にノートPCで効果を発揮してもらっていますが、Chromeで閲覧する際に、ほとんど全操作をキーボードででき、Mouseを要らなくする便利なツールです。
例えば、xを押せば、今のページをcloseするとか、u,d,j,kによりページのスローができます。


---
とりあえず、今日はここまで。おやすみ
【初心者向け】Google Apps Script 導入


#はじめに
とある会社に入社して間も無く、
業務においてgoogleスプレッドシートやGmailを利用する中で、
人力で行なっている作業が多く、自動化したらとてつもなく効率化が図れると感じました。

同じような状況で悩んでいて、もっと効率的に仕事をしたい！という方向けに
自分のノウハウを少しでも共有したいと思い文字に起こすことにしました。


# 目次
1. GoogleAppsScript(gas)とは
2. GoogleAppsScriptでできること
3. 導入の方法
4. 次回の投稿について



# 1.GoogleAppsScript(gas)とは
> [Google Apps Script](https://developers.google.com/apps-script/)（通称GAS）は、Googleが提供する11のサービスをクラウド上でスクリプトを実行することで操作できるサービスです。スクリプトの言語は、JavaScriptをベースとしています。
「Excelのマクロと同じ」と言われることもありますが、これは正しくありません。スプレッドシートだけを操作する場合は、Excelのマクロと似ていますが、Google Apps Scriptはより幅広い用途に使用できます。

*注意：JavaScriptをベースとしておりますが、JavaScriptの全ての組み込み関数を使えるわけではありませんのでご注意下さい。

*from UXmilk*

# 2.GoogleAppsScriptでできること
[JavaScript](https://ja.wikipedia.org/wiki/JavaScript)ベースの言語を利用して、[スプレッドシート](https://www.google.com/intl/ja_jp/sheets/about/)やGoogleカレンダー、GmailなどのGoogleの他のアプリケーションとの連携に加え、[slack](https://slack.com/intl/ja-jp/)や[freee](https://www.freee.co.jp/)などの外部サービスとも連携ができる優れものです。

例えば、
「Googleフォームのリンクを含むメールを毎週月曜日に自動で送信する」
「目標の売上を達成したら、slackの特定のチャンネルで自動的におめでとうメッセージが届くようにする」
というようなことが可能です。

# 3.導入の方法
Googleアカウントを保有している方であれば、１分程度で導入は終わってしまうので、
ぱぱっとやってしまいましょう！！

## 準備するもの
- Googleアカウント
- ネットワーク環境
- ブラウザ
    - Chromeの拡張機能でより効率的にgasを利用できるので、Chromeがおすすめです。

## 導入
ブラウザはChromeを利用する前提で話を進めて行きますね。

[GoogleAppsScript](https://chrome.google.com/webstore/detail/google-apps-script/eoieeedlomnegifmaghhjnghhmcldobl?hl=ja)より、Chromeの拡張機能にgasを追加して下さい！

この作業により、GoogleDriveや[GoogleApps](chrome://apps/)から、GoogleApsScriptを利用することができるようになります。


以下の写真のように、[GoogleDrive](https://www.google.com/intl/ja_ALL/drive/)ページから、GoogleAppsScriptを新規で作成できるようになります。
<img width="1360" alt="スクリーンショット 2019-07-12 1.34.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432245/e0afaf4d-87cb-ae15-40c2-d13bf156c331.png">

# 4.次回の投稿について
次回の投稿では、実際にGoogleAppsScriptを使ってサンプルコードを書いていきます。

→[Google Apps Scriptを使ったメールマガジン無料配信 メール送信編](https://qiita.com/higahigashiu/items/fddb95959f0969048e97)

### 参考サイト
- [Google Apps Script公式HP](https://developers.google.com/apps-script/)
- [UXmilk](https://uxmilk.jp/25775)
- [GoogleAppScript入門](https://qiita.com/t_imagawa/items/47fc130a419b9be0b447#%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%81%A7class%E5%8C%96%E3%81%A8%E8%A3%9C%E5%AE%8C)
SQLアンチパターン-10章 31のフレーバー-まとめ

## 列に入る値を限定する
列に入る値を限定するとき、テーブル設計時にCHECK制約を利用することで定義が可能になります。

また、MySQLでは`ENUM`というデータ型をサポートしています。


```sql
CREATE TABLE Books (
 author VARCHAR(100)
 category ENUM('human','social','history')
);
```
しかし、上記のようにテーブルを設計したとして、
category列でソートをかけるとどうなるでしょうか。
答えは、アルファベット順にソートされるのではなく
値のリストの定義順でソートされることになります。

## デメリット
`ENUM`や`CHECK制約`を使う際には、その中の値が今後変更されうることが起きないか、新しい値が追加される可能性があるのか、よく考えましょう。


### 列定義を変更する
列定義をもし追加するとしたら、元々の列定義の内容を知っておく必要があります。
また、定義されている値を変更する場合は既存のデータを編集した上で更新する必要が出てきます。
それはとてもコストのかかる作業となります。

### データの移植が難しい
例えば`ENUM`型はMySQLでしか対応しておらず、他のDBに移植しようとなった場合には設計を見直す必要があります。



## 解決策 
### 限定する値は別テーブルで定義しましょう
今回の場合、外部キーで`category`テーブルを扱えば問題は簡単になるでしょう。
`category`の値を変更することもできるし、
新しく`cateogry`を増やすことも容易になります。
データの属性が増えた場合も変更は容易です。
例えば`category`を扱う際に、親子関係を考える必要が出てきたとします。
その際は`category`テーブルでその親子関係を表せば良いです。(Closure tableなどを使いましょう)
`ENUM`や`CHECK制約`で設計していては実現できないことです。

値の制限を、テーブルを増やして表しただけなので
他のDBへの移植も容易です。
ブラウザのクソみたいなレンダリングを解決したクソみたいな方法 (Firefox70/Chrome79)

_追記(19/07/13):コメントにてアドバイスを頂き、フォント側を直接改造してヒンティングを消すことでどんなソフトでも解決できるようになりました。コメントをくださったscivolaさんにお礼申し上げます。_
_これが続編→[【Fontforge】ブラウザやElectron系ソフトで表示される文字がガビガビになってる時の解決法と、ヒンティングについて感じたこと](https://qiita.com/mmns/items/7d268134f5915f222599)_
_この記事の方法も使えるといえば使えるので、読んでおいてマイナスにはならないはず。:追記終わり_
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411269/8aa77c04-6f95-1fa0-8b04-9f71ad0c1a0d.png)
FirefoxやChromeを使っているならば、このような酷たらしい惨状を一度は見たことがあるだろう。
上がUbuntu Medium 40px, 下がM+ Type-1 C 20pxだが、下の文章が__ささくれだったようなガビガビ状態に__なっている。[^3]

このような許しがたいレンダリングを解決する、わりかし信じがたい方法がこちら。

# <font color="#ff0000">元・最強の解決法:ほんの少しだけ回転させろ</font>
とりあえずこのHTMLをコピペして開いてほしい。

```html:hoge.html
<!DOCTYPE html>
<title>てすと</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<style>
    body{
        background-color: hsl(0,0%,15%);
        color: #fafafa;
        font-size: 20px;
        text-align: center;
        font-family: 'Ubuntu', 'M+ 1c', serif;
    }
    h1 {
        font-weight: 500;
    }
    .rotate * {
        transform: rotate(0.3deg);
    }
</style>
<h1 class="ub">The quick brown fox jumps over the lazy dog.</h1>
<p class="mp">適当な文章が思いつかないという文章が、こういう用途に一番適当ではないか。</p>
<div class="rotate">
    <h1 class="ub">The quick brown fox jumps over the lazy dog.</h1>
    <p class="mp">適当な文章が思いつかないという文章が、こういう用途に一番適当ではないか。</p>
</div>
```

ポイントはここ。

```css:ここ.css
.rotate * {
    transform:rotate(0.3deg);
}
```

__ほんの少しだけ、人間の目にはとうてい区別できないぐらいほんの少しだけ__回転させている[^1]。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411269/c235490f-3867-3d06-b68d-111930621090.png)
__ほんの少しどころではないくらい見た目が改善された。__スーパーマッカーが見ている景色ってこんななんでしょうかね。
下の日本語だけではなくUbuntu側も、特に「m」「n」の形は__お前誰だレベルで変わっている__。
~~回転によってレンダリングモード的なのが変わっているのだろうか？~~
_追記:**ヒンティングが裏目に出ている**とのコメントをいただきました。続編の記事の通り**ヒンティングが悪さをしている**ことでほぼ間違いないかと思われます。_

# 問題点

いかにも問題点だらけそうな力技だが、案の定問題点だらけであるようだ。

- M+系、源真ゴシック系などが崩れている場合はきれいになるが、もとからきれいな場合(Noto Sans CJK JP/源ノ角ゴシックとか)は__逆にぼやけて見づらくなる__。
- なんとかかんとかフレームワークで作ったSPA(ﾄﾞﾔｧ)とかの場合、表示が全部消えたりする。Qiitaとか。
- しきい値があり、`0.027976454235613339deg`未満では改善されない。このしきい値が環境依存の可能性。
    - ちなみに、モニタの解像度は1920x1080で試している。
    - ~~CSSの`font-size`は多分関係ない。~~

## 追記:サイズについて

> CSSの`font-size`は多分関係ない。

などと抜かしていたが、**拡大を続けると違いがほとんどなくなるようだ。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411269/cb7713a1-1c06-8ab2-9ca2-a115a8fb7063.png)
上のページでブラウザの開発者ツール(F12)を使うと、簡単にサイズを調整できる。


# 参考

[Windowsも含めブラウザでフォントをきれいに表示する - なないろ研究所](https://www.7-16.co.jp/laboratory/2378)

# さいごに
回転しなくていい方法があったらぜひご教授ください。__すべてのM+ユーザーが救われます。__

_続編はこっち→
[【Fontforge】ブラウザやElectron系ソフトで表示される文字がガビガビになってる時の解決法と、ヒンティングについて感じたこと](https://qiita.com/mmns/items/7d268134f5915f222599)_

[^1]: `html`とかで回してもいいんだが、要素が縦長だとさすがに`0.2deg`とかでも傾きが目立つので、`h2`とか`p`とかできるだけ小さい範囲で回したほうがよろしい。
[^2]: ブラウザの開発者ツールとかでパッと調整できる。
[^3]: じつはUbuntuも字形が変わっている。mやnで顕著。