OmniAICreator/Qiita-1.07M huggingface dataset:
【ImageView】ScaleTypeと表示画像の対応表

# ScaleTypeと表示画像の対応表
`ScaleType`と表示画像の対応は以下のようになります。なお、ImageViewの幅・高さはともに固定しています。

|ScaleType|画像の表示方法|ImageViewのサイズ > 画像サイズ|ImageViewのサイズ < 画像サイズ|
|---|---|---|---|
|CENTER|・ImageViewの中央に表示される<br>・拡大縮小されない|![bugdroid_center.jpg](https://qiita-image-store.s3.amazonaws.com/0/302946/556a7cb7-98b3-f7fc-3f91-610127bea825.jpeg)|![kotlin_center.jpg](https://qiita-image-store.s3.amazonaws.com/0/302946/b4489b44-0b95-1758-1f41-fc601221743d.jpeg)|
|CENTER_CROP|・ImageViewの中央に表示される<br>・ImageView全体を覆う閾値になるまで拡大縮小される|![bugdroid_center_crop.jpg](https://qiita-image-store.s3.amazonaws.com/0/302946/b7cbf9a5-7fc7-99a7-1eb8-24b18669453a.jpeg)|![kotlin_center_crop.jpg](https://qiita-image-store.s3.amazonaws.com/0/302946/a8e56ccc-8b74-b358-8e9d-f81e9467a889.jpeg)|
|CENTER_INSIDE|・ImageViewの中央に表示される<br>・ImageView内部に画像全体が含まれるように拡大縮小される<br>・ImageView内部に画像全体が元々含まれている場合、**拡大縮小しない**|![bugdroid_center_inside.jpg](https://qiita-image-store.s3.amazonaws.com/0/302946/4ee6780f-ee5c-25c9-8720-0a1c2d7ad2e9.jpeg)|![kotlin_center_inside.jpg](https://qiita-image-store.s3.amazonaws.com/0/302946/becd3b19-54b8-d49b-5df5-bc5a774d7658.jpeg)|
|FIT_CENTER<br>(デフォルト値)|・ImageViewの中央に表示される<br>・幅・高さのいずれかがImageViewのサイズと一致し、かつImageView内部に画像全体が含まれるように拡大縮小される|![bugdroid_fit_center.jpg](https://qiita-image-store.s3.amazonaws.com/0/302946/c1a97017-b5dc-8099-89c8-cef5bbd27417.jpeg)|![kotlin_fit_center.jpg](https://qiita-image-store.s3.amazonaws.com/0/302946/4c24e2d8-c3be-9bf5-6b03-64deff254193.jpeg)|
|FIT_END|・ImageViewの**右下**に表示される<br>・幅・高さのいずれかがImageViewのサイズと一致し、かつImageView内部に画像全体が含まれるように拡大縮小される|![bugdroid_fit_end.jpg](https://qiita-image-store.s3.amazonaws.com/0/302946/3d78d885-ac79-739c-f09b-48642627bf21.jpeg)|![kotlin_fit_end.jpg](https://qiita-image-store.s3.amazonaws.com/0/302946/ae2ee492-959e-da95-97dc-02ee8249fa5e.jpeg)|
|FIT_START|・ImageViewの**左上**に表示される<br>・幅・高さのいずれかがImageViewのサイズと一致し、かつImageView内部に画像全体が含まれるように拡大縮小される|![bugdroid_fit_start.jpg](https://qiita-image-store.s3.amazonaws.com/0/302946/66b4f74b-3a84-a161-3b48-fb2731df748d.jpeg)|![kotlin_fit_start.jpg](https://qiita-image-store.s3.amazonaws.com/0/302946/e15c7849-3ea5-0075-c133-605ef20f2f7c.jpeg)|
|FIT_XY|・幅・高さがImageViewのサイズと一致するように**それぞれ独立して拡大縮小される**<br>|![bugdroid_fit_xy.jpg](https://qiita-image-store.s3.amazonaws.com/0/302946/2ea56335-5ff3-65bc-110b-5373bd3c2d8d.jpeg)|![kotlin_fit_xy.jpg](https://qiita-image-store.s3.amazonaws.com/0/302946/f074fdf5-701c-7a60-493b-d18c219760c5.jpeg)|
|MATRIX|・`Matrix`に指定された条件にしたがって表示される<br>・条件指定がない場合、ImageViewの左上に拡大縮小されずに表示される|![bugdroid_matrix.jpg](https://qiita-image-store.s3.amazonaws.com/0/302946/63a99d25-12b3-c8d6-8e85-058dcf0bd909.jpeg)|![kotlin_matrix.jpg](https://qiita-image-store.s3.amazonaws.com/0/302946/94867006-f56f-efeb-d393-851a707f01a3.jpeg)|

表の最後にある`Matrix`は行列のことで、きちんと検証できていませんが、拡大縮小(Scale)・移動(Translate)・回転(Rotate)・ずれ[^1](Skew)などの条件を指定できるクラスのようです。

[^1]: 「ひずみ」が正しい言葉ですが、分かりやすく「ずれ」と表記しました。

# サンプルアプリ
上記に記載した画像の`ScaleType`を切り替えて表示を実際に確認できるアプリです。
追々、各自で画像をアップロードしてその表示確認をできるものにしようと思います。
[GitHub - ImageViewScaleTypeChecker](https://github.com/tkhs0604/ImageViewScaleTypeChecker)
cron の使い方（pythonスクリプト）

# はじめに

cron とは、macOS/Linuxで使える、ジョブ（スクリプト）を自動実行するためのデーモンプロセスです。定期的に実行したいジョブを自動的に実行するよう管理することができます。

python で株価のスクレイピングを毎日実行しているのですが、手動でやるのめんどくさいなぁと思ってた時に見つけて使い始めましたが便利です。今のところ高頻度でいじるものでもないので、備忘として残します。

macOS Mojave 10.14.3

# cronの設定

ターミナルで、下記を実行。

```terminal:
$ crontab -e
```

するとVimが立ち上がる。Vimの使い方は下記を参考にしてくだい。
初めて使うときは焦ります。
[Vim初心者に捧ぐ実践的入門](https://qiita.com/okamos/items/c97970ab34ff55ff3167)

cron の設定は、実行時間とコマンドを半角スペース開けて記述する。保存して閉じると、`installing new crontab`とメッセージがTerminalに表示される。

```vim:crontab
*  *  *  *  * command
分 時 日 月 曜日
```

|  | 分  | 時  | 日  | 月  | 曜 |
|:--|:--|:--|:--|:--|:--|
| 範囲  | 0-59  | 0-23  | 1-31  | 1-12  | 0-7（0と7はSunday） |

全てワイルドカード[*]にすると、毎分実行。
また、[ , ]でand、[ / ]でステップ数、[ - ]で範囲を指定できる。

```vim:実行例
32 02 * * * 　　         02:32に実行
*/10 * * * * 　　　　　　 10分おきに実行
0-10 20 * * *           20:00から20:10まで 1分毎に実行
0,30 20 * * 2,4         毎週,火,木曜の 20:00と 20:30に実行
* 20 * * *　　　　　　　　 20:00から 20:59まで 1分おきに実行
0 1 * * *　　　　　　　　  1:00に実行
0 * * * *　　　　　　　　  毎時 0分に 1時間おきに実行
2 8-20/3 * * *　　　　　　8:02,11:02,14:02,17:02,20:02に実行
```

### 文字コード
出力に日本語が入っていると、下記のようなエラーが発生する。
対応するには、cronに`LANG=ja_JP.UTF-8`と記述する。

```terminal:
'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
```


### 環境変数
コマンドは、設定ファイルでパスを通していないものに関してはフルパスで指定するかカレントディレクトリからの相対パスで指定しないといけない。

### ディレクトリ
cron実行時のカレントディレクトリはホームディレクトリにされるので、絶対パスを指定する。


## 実行例

上記の注意点を考慮して、デスクトップに置いた`hello.py`をcronで実行してみる。

```python:hello.py
print('hello')
```
```terminal:crontab(2時に"hello.py"を実行)
LANG=ja_JP.UTF-8

0 2 * * * cd /Users/{ユーザ名}/Desktop/; bash -l -c 'python3 /User/{ユーザ名}/Desktop/hello.py'
```

指定した時間を過ぎると、terminalに下記のようなメッセージが現れる。これは、`/var/mail/{ユーザ名}`として出力結果がメール保存されていることを示している。

```terminal:
You have mail in /var/mail/{ユーザ名}
```
```terminal:中身を確認する
$ cat /var/mail/{ユーザ名}
　# => hello
```

## おまけ

### crontab コマンド

|コマンド||
|:--|:--:|
|crontab -e|cronを設定する|
|crontab -l|設定されてるcronを表示する|
|crontab -r|cronは削除する|
|crontab -u|ユーザを指定する|

### MAILTO

出力結果をメールして欲しくないとき、もしくは指定のメールアドレスで受け取りたい時。

```Terminal:メール受け取らない(MAILTOをブランクに)
MAILTO = ''
LANG=ja_JP.UTF-8

0 2 * * * cd /Users/{ユーザ名}/Desktop/; bash -l -c 'python3 /User/{ユーザ名}/Desktop/hello.py'
```

```Terminal:メール受け取る
MAILTO = 'sample@gmail.com'
LANG=ja_JP.UTF-8

0 2 * * * cd /Users/{ユーザ名}/Desktop/; bash -l -c 'python3 /User/{ユーザ名}/Desktop/hello.py'
```
データサイエンスや機械学習のチートシートを最も効率的に収集する方法

機械学習・データサイエンスのチートシート集、便利なものがたくさん出回っていますが、ちまちまブラウザからダウンロードしていたりしませんか？そんな貴方にお勧めなのがこちらのレポジトリ。

FavioVazquez/ds-cheatsheets
https://github.com/FavioVazquez/ds-cheatsheets

はい、クリックあるいはコマンド一つで100を超えるチートシートが一括でダウンロードできちゃいますね。以上、釣りタイトル失礼しました。

と、これだけではなんなので、個人的に有用性が高いと感じたものを、大きなサムネイル付きでまとめてみました。ソースとして、DataCamp及びRStudio公式ページの情報量は圧倒的なので、一読をお勧めします。

# 科学計算・データ操作・可視化

## Python (NumPy/SciPy/Pandas/matplotlib/bokeh)

Pythonに関しては、[DataCamp Cheat Sheets](https://www.datacamp.com/community/data-science-cheatsheets)にまとまっています。下記サムネイルはその一部です。

### [Python For Data Science - A Cheat Sheet For Beginners](https://www.datacamp.com/community/tutorials/python-data-science-cheat-sheet-basics)  
![](https://cdn-images-1.medium.com/max/1600/1*KHzoQS80C80_KLzNa9L_Mw.png)

### [NumPy Cheat Sheet: Data Analysis in Python](https://www.datacamp.com/community/blog/python-numpy-cheat-sheet)
![](https://cdn-images-1.medium.com/max/2000/1*o_CO_8Plpi2Ac3s-Gs5IQg.png)

### [SciPy Cheat Sheet: Linear Algebra in Python](https://www.datacamp.com/community/blog/python-scipy-cheat-sheet)
![](https://cdn-images-1.medium.com/max/2000/1*9gFze6fk9EHcm1bgJsmgFA.png)

### [Pandas Cheat Sheet for Data Science in Python](https://www.datacamp.com/community/blog/python-pandas-cheat-sheet)]
![](https://cdn-images-1.medium.com/max/2000/1*2RJpJMci8ysUbrFOCzPKAw.png)

### [Pandas Cheat Sheet: Data Wrangling in Python](https://www.datacamp.com/community/blog/pandas-cheat-sheet-python)
![](https://cdn-images-1.medium.com/max/2000/1*YhTbz8b8Svi22wNVvqzneg.jpeg)
![](https://cdn-images-1.medium.com/max/2000/1*3-mTHM3ejorJwLnjuIpVNQ.jpeg)

### [Matplotlib Cheat Sheet: Plotting in Python](https://www.datacamp.com/community/blog/python-matplotlib-cheat-sheet)
![](https://cdn-images-1.medium.com/max/2000/1*ykxp7OpgBXbRRHgjzSkeCA.png)

### [Python Data Visualization: Bokeh Cheat Sheet](https://www.datacamp.com/community/blog/bokeh-cheat-sheet-python)
![](https://cdn-images-1.medium.com/max/2000/1*v826QDZmnp68ZPHbVeggPg.png)

## R(lubridate/stringr/purrr/dplyr/ggplot2)

Rに関しては、[RStudio Cheat Sheets](https://www.rstudio.com/resources/cheatsheets/)にまとまっています。下記サムネイルはその一部です。

![](https://www.rstudio.com/wp-content/uploads/2018/11/tidyeval.png)
![](https://www.rstudio.com/wp-content/uploads/2018/08/lubridate.png)
![](https://www.rstudio.com/wp-content/uploads/2018/08/strings.png)
![](https://www.rstudio.com/wp-content/uploads/2018/08/purrr.png)
![](https://www.rstudio.com/wp-content/uploads/2018/08/data-transformation.png)
![](https://www.rstudio.com/wp-content/uploads/2018/08/data-visualization-2.1.png)
CUTRのgtfs-realtime-validatorを起動する(時に必要なリンク集)

[CUTRのgtfs-realtime-validator](https://github.com/CUTR-at-USF/gtfs-realtime-validator)をとりあえず使えるところまで

dockerを作ってくれている神がいらっしゃったので、ただのまとめ記事です。

1. dockerが使える環境を持ってくる。CentOSでもCoreOSでもmacでも (筆者は `CentOS 7.6` で試しました)
2. dockerやgitが入ってなければ入れる
3. [gtfs-realtime-validator-docker](https://github.com/scrudden/gtfs-realtime-validator-docker)にあるDockerfileから起こす。コマンドは←のリンク先参照
4. bulidは数分かかる
5. 起動したら `http://{address}:8080` へ

![screencapture-47-245-1-254-8080-2019-02-23-03_15_43.png](https://qiita-image-store.s3.amazonaws.com/0/159912/ebc4c3f4-d184-f969-bc71-ec3a28cd8c03.png)

**その他**

公式オススメのMBTA(マサチューセッツ湾交通局)の静的GTFSとGTFS-RTで試してみるのがいいかと思います。(とはいえボストンが夜中だとダメですね。)
https://github.com/CUTR-at-USF/gtfs-realtime-validator#quick-start---run-it-yourself

GUIだけでなくAPIからバリデーションの結果を呼び出せるっぽいけどなんかうまくいかない:rolling_eyes:
→ https://github.com/CUTR-at-USF/gtfs-realtime-validator/wiki/RESTful-API

**参考記事**
[CentOS7にDockerをインストールする](https://qiita.com/inakadegaebal/items/be9fecce813cebec5986)
Python: 離散フーリエ変換（実装コードとテスト）


# 離散フーリエ変換
参考 ⇒ [wiki](https://ja.wikipedia.org/wiki/%E9%9B%A2%E6%95%A3%E3%83%95%E3%83%BC%E3%83%AA%E3%82%A8%E5%A4%89%E6%8F%9B)


離散フーリエ変換の式

${\displaystyle F(t)= \sum_{x=0}^{N-1} f(x) e^{-i\frac{2 \pi t x}{N}} \quad \quad }$

逆離散フーリエ変換の式

${f(x)={\displaystyle \frac  {1}{N}}\sum _{{t=0}}^{{N-1}}F(t)e^{{i{\frac  {2\pi xt}{N}}}}\quad \quad}$

# 実装したdftのコード

```dft.py
import cmath

import numpy as np


def dft(f):
    N = len(f)
    A = np.arange(N)
    T = A.reshape(1, -1)
    X = A.reshape(-1, 1)
    # 行列演算形式になっているがwikiの数式そのまま
    M = f * cmath.e**(-1j * 2 * cmath.pi * T * X  / N)
    return np.sum(M, axis=1)


def idft(f):
    N = len(f)
    A = np.arange(N)
    X = A.reshape(1, -1)
    T = A.reshape(-1, 1)
    # 同上
    M = f * cmath.e**(1j * 2 * cmath.pi * X * T  / N)
    return np.sum(M, axis=1) / N


def dft_matrix(f):
    N = len(f)
    A = np.arange(N)
    T = A.reshape(1, -1)
    X = A.reshape(-1, 1)
    return cmath.e**(-1j * 2 * cmath.pi * T * X  / N)
```

# テスト
実装コードをimportしてテスト.

```python
%matplotlib inline

import dft
import numpy as np
import cmath
import matplotlib.pyplot as plt

# ステップ
s = 0.1
# 横軸(0~2πまで)
x = np.arange(0, 2 * cmath.pi, s)
y = np.sin(x) + 2 * np.sin(2 * x + cmath.pi)
fy = dft.dft(y)
yd = dft.idft(fy)
print('元波形')
plt.plot(x, y)
plt.show()
print('変換後:実部')
plt.plot(fy.real)
plt.show()
print('変換後:虚部')
plt.plot(fy.imag)
plt.show()
print('逆変換後')
plt.plot(yd.real)
plt.show()
```

変換と逆変換ができていることを確認. 
![実行結果.png](https://qiita-image-store.s3.amazonaws.com/0/365961/2188f16b-5a70-e609-1dc8-b2735adbc68c.png)


# 追記
x,tの積部分はNxNパターンあるので, 以下のような行列演算で一気にやることができる.

```
A = np.arange(4)
A.reshape(1, -1) * A.reshape(-1, 1)
```

実行結果

```
array([[0, 0, 0, 0],
       [0, 1, 2, 3],
       [0, 2, 4, 6],
       [0, 3, 6, 9]])
```

# 追追記
よく見るとよくある行列用いた空間系の変換みたいにできそうなのでやってみた.
逆変換行列の作成方法が変なのと, 最後Nで割っているところは調整がいる.
 ⇒できたら今後「変換行列による離散フーリエ変換」みたいな記事書きたい.+.(ﾉ*･ω･)ﾉ*.

```python
%matplotlib inline

import dft
import numpy as np
import cmath
import matplotlib.pyplot as plt

# ステップ
s = 0.1
# 横軸(0~2πまで)
x = np.arange(0, 2 * cmath.pi, s)
y = np.sin(x) + 2 * np.sin(2 * x + cmath.pi)
# 変換行列
M = dft_matrix(y)
# 波形 ⇒　M　⇒ 周波数表現
fy = np.dot(M, y)
# 周波数表現 ⇒　-M　⇒ 波形
yd = np.dot(-M, fy) / len(fy)
print('元波形')
plt.plot(x, y)
plt.show()
print('変換後:実部')
plt.plot(fy.real)
plt.show()
print('変換後:虚部')
plt.plot(fy.imag)
plt.show()
print('逆変換後')
plt.plot(yd.real)
plt.show()
```

![実行結果.png](https://qiita-image-store.s3.amazonaws.com/0/365961/2188f16b-5a70-e609-1dc8-b2735adbc68c.png)
Go+AWS LambdaでSlackのSlash Commandsを作る

## はじめに

SlackのSlash Commandsはこういうやつです。

![slash.gif](https://qiita-image-store.s3.amazonaws.com/0/220908/11e244c5-f372-f8fb-0d9d-e2494097bdbf.gif)

Slackに`/commandName`を入力すると、あらかじめ設定したURLにリクエストが送信されます。


これをGo+AWS Lambdaで作ってみます。

* SAMでデプロイ
* Valification tokenを検証する
* ビジネスロジックは書かない

といった感じです。

## 前提条件

以下がインストールされていること。

* [Docker](https://www.docker.com/community-edition)
* [AWS SAM CLI](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)
* [Go](https://golang.org/doc/install)

ローカルにAWS認証情報がセットアップされていること。

## とりあえずサンプルをデプロイ

### 準備

#### Slack Appを登録

[こちら](https://api.slack.com/apps)からSlack Appを登録します。

<img width="857" alt="スクリーンショット 2019-02-23 1.24.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/220908/978de230-5d2b-7ade-ea15-09c3569f20b3.png">

登録後、App Credentialsに表示されるVerification Tokenの値をメモしておきます。

#### アプリケーションの準備

1. [こちら](https://github.com/inabajunmr/slack-slash-lambda-go-sample)をclone
2. [template.yaml](https://github.com/inabajunmr/slack-slash-lambda-go-sample/blob/master/template.yaml#L29)のVERIFICATION_TOKENの値を取得した値に書き換えます
3. デプロイに使うS3バケットを作成

### デプロイ
以下のコマンドでデプロイを実行します。

```
make deploy BUCKET="your S3 bucket name" PROFILE="your aws profile"
STACK_NAME="your stack name"
```

BUCKETには事前に用意したS3バケットを、PROFILEにはデプロイに使うAWSのprofileを、STACK_NAMEには任意の値を指定します。
バケットはprofileで指定されているものと同じリージョンに配置されている必要があります。

### Slackに設定

デプロイが完了するとAPI Gatewayのエンドポイントが払い出されるので、Slackに設定します。

Valification Tokenを取得したページからSlash Commandsを選択し、

<img width="531" alt="スクリーンショット 2019-02-23 1.27.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/220908/22d8756b-156d-cc5e-09c1-4cb2d03edb2b.png">

<img width="618" alt="スクリーンショット 2019-02-23 1.27.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/220908/c12b949b-ba03-0d2d-b7d9-440542351f20.png">

URLを登録します。

<img width="564" alt="スクリーンショット 2019-02-23 1.27.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/220908/e47656ee-157f-e741-1945-33a5258680e4.png">


## コードについて

[このへん](https://github.com/inabajunmr/slack-slash-lambda-go-sample/blob/master/app/main.go#L45)で環境変数に埋め込んだVERIFICATION_TOKENと、Slackが送信したRequestのtokenを比較しています。

```go
// valification token
token := os.Getenv("VERIFICATION_TOKEN")
vals, _ := url.ParseQuery(request.Body)
req := slackRequest{
vals.Get("token"),
vals.Get("team_id"),
vals.Get("team_domain"),
vals.Get("channel_id"),
vals.Get("channel_name"),
vals.Get("user_id"),
vals.Get("user_name"),
vals.Get("command"),
vals.Get("text"),
vals.Get("response_url"),
vals.Get("trigger_id"),
}

if req.token != token {
  // invalid token
  return events.APIGatewayProxyResponse{
    Body:       fmt.Sprintf("Invalid token."),
    StatusCode: 200,
  }, nil
}
```

環境変数は[template.yaml](https://github.com/inabajunmr/slack-slash-lambda-go-sample/blob/master/template.yaml)で埋め込んでいます。

```yaml
      Environment: # More info about Env Vars:
        Variables:
          VERIFICATION_TOKEN: xxxxx
```

## 参考
SAMのデプロイについては以下の記事を参考にさせていただきました。

https://qiita.com/shunp/items/ded0da8b29dae7aa9196
Swift：CALayerや画像に射影変換を適用する

# はじめに
CAlayerや画像に射影変換を適用する時のTipsを残す．
併せて[こちらの記事](https://qiita.com/Kyomesuke3/items/b56f6d43d68a175e6327)も参照するといいかもしれない．

## CALayer編

```swift
let layer = CALayer()
self.view.wantsLayer = true //macOSだと必要
self.view.layer?.addSublayer(layer) //親のビューは状況による
layer.frame = self.view.bounds

//layerに何かしらコンテンツを入れる

let rect = CGRect(x: 0, y: 0, width: W, height: H) // コンテンツの大きさ
let filter = CIFilter(name: "CIPerspectiveTransformWithExtent")!
filter.setValue(CIVector(cgRect: rect, forKey: "inputExtent")
filter.setValue(CIVector(x: X1, y: Y1), forKey: "inputTopLeft") //射影変換後のコンテンツ左上頂点の座標
filter.setValue(CIVector(x: X2, y: Y2), forKey: "inputTopRight") //射影変換後のコンテンツ右上頂点の座標
filter.setValue(CIVector(x: X3, y: Y3), forKey: "inputBottomRight") //射影変換後のコンテンツ右下頂点の座標
filter.setValue(CIVector(x: X4, y: Y4), forKey: "inputBottomLeft") //射影変換後のコンテンツ左下頂点の座標

layer.filters = [filter]
```

## 画像編

```swift
var nsImage = NSImage(name: "hoge")!
let imageData = nsImage.tiffRepresentation!
var ciImage = CIImage(data: imageData)!

let filter = CIFilter(name: "CIPerspectiveTransformWithExtent")!
filter.setValue(ciImage, forKey: "inputImage")
filter.setValue(CIVector(cgRect: ciImage.extent), forKey: "inputExtent")
filter.setValue(CIVector(x: X1, y: Y1), forKey: "inputTopLeft") //射影変換後のコンテンツ左上頂点の座標
filter.setValue(CIVector(x: X2, y: Y2), forKey: "inputTopRight") //射影変換後のコンテンツ右上頂点の座標
filter.setValue(CIVector(x: X3, y: Y3), forKey: "inputBottomRight") //射影変換後のコンテンツ右下頂点の座標
filter.setValue(CIVector(x: X4, y: Y4), forKey: "inputBottomLeft") //射影変換後のコンテンツ左下頂点の座標

ciImage = filter.outputImage!
let rep = NSCIImageRep(ciImage: ciImage)
nsImage = NSImage(size: rep.size)
nsImage.addRepresentation(rep)
```

## 補足
[CIPerspectiveTransformWithExtent](https://developer.apple.com/library/archive/documentation/GraphicsImaging/Reference/CoreImageFilterReference/index.html#//apple_ref/doc/filter/ci/CIPerspectiveTransformWithExtent)が射影変換用のフィルタなのかは不明ですが，射影変換を手軽に達成できるのでいいですね．しかし，このCIPerspectiveTransformWithExtentは各頂点のパラメータ次第で結果がちゃんと出力されないので要注意です．色々試した感じだと，元のコンテンツより大き過ぎたり，どこかの辺が水平or垂直だとダメ(？)っぽい．引き伸ばしの限界があるのか，ゼロで割っちゃうのかよくわかりません．出力できる時はできる．
SymfowareでのSQL問い合わせに関する備忘録

SymfowareでのSQL問い合わせに関する考慮事項等を自分用メモも兼ねて記載します。比較する場合は基本的にはOracleとの比較になります。

# INSERT SELECT
挿入先のテーブルをSELECT句で指定できない（ビューを指定し、ビューから参照されている場合も同様）。
同一テーブル内でのコピーができないので、一旦一時表に入れるとか、JDBC接続等であれば、一旦取得してINSERTかけるしかない。

```Oracle.sql
-- Oracleでは可能
INSERT INTO hoge_tbl
    (SELECT hoge_seq.nextval, hoge_col FROM hoge_tbl);
```

# UPDATE FROM
更新時に別テーブルの値を利用することができない。

```SQLServer.sql
-- SQLServerでは可能
UPDATE hoge_tbl SET
    hoge_tbl.hoge_col1 = fuga_tbl.fuga_col1
FROM fuga_tbl
WHERE hoge_tbl.key_col = fuga_tbl.key_col;
```

```Oracle.sql
-- Oracleでは副問合せで可能
UPDATE hoge_tbl SET
    (hoge_col1, hoge_col2) =
    (SELECT fuga_col1, fuga_col2
        FROM fuga_tbl
        WHERE hoge_tbl.key_col = fuga_tbl.key_col);
```

# リテラル指定
Symfowareでは日付型をリテラルで指定する際、型名の指定が必要。

```Symfoware.sql
SELECT *
FROM hoge_tbl
WHERE date_col = DATE'2000-01-01'
AND timestamp_col = TIMESTAMP'2000-01-01 00:00:00';
```

# システム表
https://software.fujitsu.com/jp/manual/manualfiles/M060002/J2X02265/01Z2/usaplac/usapl131.html

## カラム定義情報取得
``` sql
SELECT rc.*
FROM RDBII_SYSTEM.RDBII_TABLE rt
LEFT OUTER JOIN RDBII_SYSTEM.RDBII_COLUMN rc
ON (rt.DB_CODE = rc.DB_CODE AND rt.SCHEMA_CODE = rc.SCHEMA_CODE AND rt.TABLE_CODE = rc.TABLE_CODE)
WHERE rt.TABLE_NAME = 'hoge_table'
```

## インデックス情報取得

``` sql
SELECT
    TABLE_NAME
  , INDEX_DSO_NAME
  , rcu.ORDINAL_POSITION
  , rc.COLUMN_NAME
FROM
  RDBII_SYSTEM.RDBII_TABLE rt 
  INNER JOIN RDBII_SYSTEM.RDBII_INDEX ri 
    ON ( 
      rt.DB_CODE = ri.DB_CODE 
      AND rt.SCHEMA_CODE = ri.SCHEMA_CODE 
      AND rt.TABLE_CODE = ri.TABLE_CODE
    )
  INNER JOIN RDBII_SYSTEM.RDBII_COLUMN_USAGE rcu 
    ON ( 
      ri.DB_CODE = rcu.DB_CODE 
      AND ri.SCHEMA_CODE = rcu.OBJ_SCHEMA_CODE 
      AND ri.INDEX_DSO_CODE = rcu.OBJECT_CODE
    )
  INNER JOIN RDBII_SYSTEM.RDBII_COLUMN rc 
    ON ( 
      ri.DB_CODE = rc.DB_CODE 
      AND ri.SCHEMA_CODE = rc.SCHEMA_CODE 
      AND ri.TABLE_CODE = rc.TABLE_CODE
      AND rcu.COLUMN_CODE = rc.COLUMN_CODE
    )
WHERE DB_NAME = 'TEST_DB' AND TABLE_NAME = 'TEST_TBL'
ORDER BY rt.TABLE_NAME, ri.INDEX_DSO_CODE, rcu.ORDINAL_POSITION;
```

## 表のDSI名取得

``` sql
SELECT NAME
FROM RDBII_SYSTEM.RDBII_DSI_STATUS
WHERE TYPE = 'T' AND TABLE_NAME = 'TEST_TBL'
```

参考：[A.3.26 DSI情報](https://software.fujitsu.com/jp/manual/manualfiles/M100005/J2X17495/02Z200/J7495-a-03-26.html)
logue SDK の初期設定(minilogue xd)

Mac OSX (Mojave) で logue SDK の minilogue xd 用デモプロジェクトをコンパイルするまでの手順メモ。

## プロジェクトクローン

```
git clone https://github.com/korginc/logue-sdk.git
cd logue-sdk
git submodule update --init --recursive
```

ここでsubmoduleのupdateを忘れるとコンパイルエラーでハマる（ハマった :sob: )

## toolの準備

```
cd logue-sdk/tools/gcc
./get_gcc_osx.sh
cd ../logue-cli
./get_logue_cli_osx.sh
```

## プロジェクトのビルド

```
cd logue-sdk/platform/minilogue-xd/demos/waves
make
```
mysql でwarningログを自動的に表示する


これでwarningログが自動的に表示される。

```
mysql> \W
Show warnings enabled.
```

```
mysql> create table if not exists a(id int primary key);
Query OK, 0 rows affected (0.01 sec)

mysql> create table if not exists a(id int primary key);
Query OK, 0 rows affected, 1 warning (0.00 sec)

Note (Code 1050): Table 'b' already exists
```
ロボ作り01

#Qiitaとは
geekの溜まり場って認識。
[ココ](https://www.google.com/amp/ferret-plus.com/amp/1856)を参考に登録。エンジニア版ヤフチエみたいなツールもあったような。それもいつか調べてみましょ

#Markdown記法
Qiitaの投稿には_Markdown記法_というものを使うらしい。これを使うときっと綺麗なレイアウトになるんでしょう。[ココ](https://qiita.com/tbpgr/items/989c6badefff69377da7)とか参考にしてみました。デザインの勉強とかも楽しそう

#とりあえず
勉強のためにQiitaで製作記録を録ってみることにしました。早速次回から具体的な内容を投稿してみましょ
Micronaut入門1〜導入〜

# 目的
SIerではSpring系FWが採用されるケースが多いが、Micronautは既存の有名FWに影響を受けていることもあり導入障壁はそれほど高くなさそうで既存FWの欠点を克服しているということで技術調査がてらメモ。

# Micronautとは
マイクロサービスアプリケーションを構築するために設計された、最新のJVMベースのフルスタックマイクロサービスフレームワーク。
Micronautはマイクロサービスを構築するすべての機能の提供する。
それと同時に、Spring、Spring Boot、Grailsのようなフレームワークの欠点を回避するため以下を提供する。

- Fast startup time
- Reduced memory footprint
- Minimal use of reflection
- Minimal use of proxies
- Easy unit testing

SI業界ではビジネスモデル上あまり向かないと思われるが、マイクロサービスをターゲットに設計されている。

# 環境構築
- Java8以上のSDKがはいっていること
- SDKMANにてMicronaut CLIをインストールする

###### SDKMANのインストール
```bash
$ curl -s "https://get.sdkman.io" | bash
$ source "$HOME/.sdkman/bin/sdkman-init.sh"
$ sdk update
$ sdk install micronaut 1.1.0.M1
```

# サーバーアプリの作成
###### テンプレートプロジェクトの作成
--features file-watchでオートリロード機能がつく

```bash
$ mn create-app my-app --features file-watch
$ cd my-app
$ ./gradlew run --continuous
```

###### コントローラーの作成
```java:HelloController.java
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;

@Controller("/hello")
public class HelloController {
    @Get(produces = MediaType.TEXT_PLAIN)
    public String index() {
        return "hello world!!";
    }
}
```

http://localhost:8080/hello
にアクセスでhello world!!が表示される。
ファイルの変更を検知し、再起動してくれる。
起動もとてもはやく、もっさり感は感じない。

# 参考
https://docs.micronaut.io/1.1.0.M1/guide/index.html
【いまさらCSS】flexbox + max-width = IE11崩れ

##はじめに
いまさら感が否めないのですが、もう二度とこんな過ちを繰り返さないために書きます。

##やりたかったこと
- flexboxで横並びにした各要素の中に、サイズの違うロゴを配置

余談ですが、クライアントにwordpressからアップロードしてもらった画像を表示させるので、縦横比どんなサイズの画像が来てもうまく収まることを目指します。
![1.jpg](https://qiita-image-store.s3.amazonaws.com/0/91928/a23eb463-2889-ba11-c9c7-dad0d2eec882.jpeg)

##イメージ
ちょっと分かりづらいですが、タグにするとこんなイメージです。
![2.jpg](https://qiita-image-store.s3.amazonaws.com/0/91928/75daffd9-dba7-3f4f-7661-d089f6f0809a.jpeg)


##詰まったところ
- flexで包含される`img`タグに`max-width:100%`を指定するとIE11でみたときに盛大に崩れる
- `img`は下記のようにしました。`max-width`がきかないので、`width: auto;`のみ適用され幅が枠から盛大にはみ出す

```css
img {
 width:auto;
 height:auto;
 max-width:100%;
 max-height:100%;
}
```

##結果
- `img`を包含している要素に`position: relative`を設定（仮に`a`）

```css
a {
 position: relative;
}
```

- `img`を下記のように`position: absolute;`に

```css
img {
 width:auto;
 height:auto;
 max-width:100%;
 max-height:100%;
 /* 以下追加 */
 position: absolute;
 top: 50%;
 left: 50%;
 transform: translate(-50%,-50%);
}
```

こんな感じです。＊上の絵をつくるより早かった。
[DEMO](https://codepen.io/hamayoo/pen/xMozOM)

##まとめ
面倒ですがIE11対応はサポートの切れる2025年まで続きそうです。ということで、とりあえず制作はじめたらIE11は早期に確認するようにしたほうがいいなということです。
今回は以上です。ありがとうございました。

##参考・引用
>[「Flexbox」を使って大きい画像を並べたら、IEでだけ画像がはみ出してしまった時の対処法](https://takuo4649design.com/weblog/note/archives/14159)
>[flexboxのバグに立ち向かう（flexboxバグまとめ）](https://qiita.com/hashrock/items/189db03021b0f565ae27)
1日1投稿を2週間やってみた雑感

## ポエムだ
そうさ、ポエムさ。技術ネタはないぞ。

## アウトプットはいいぞ
って皆様が仰る理由がちょっとはわかった気がする。
転職活動の一環としてやり始めた投稿ですが、なかなかいいのでは！？と思っております。

## 毎日Qiitaを覗くことになる
毎日Qiitaを覗くということは、トップにならぶすげーエンジニアの皆様によるすげー記事を見ることになるので、自分の興味ある分野はもとより興味がない分野の記事も目に留まり、色々と発見があります。
特にWebのフロントエンドの記事を楽しく読んでおり、次はVue.jsあたりに手を出そうかなぁと思い始めてます。

## 毎日投稿するネタを探すようになる
これがほんとにすごい。
クソ記事書くなって言われたらごめんちゃいって感じなんですが、毎日ネタを探すため色々やるようになります。
しょーもない細かい仕様をじっくり眺めたり、トライアンドエラーした結果をまとめるだけでノルマになるじゃんと打算的になりつつも試すキッカケになったりと、得るものが多いです。

## これからも続けよう
そうしようそうしよう。
うちの職場、技術ブログとかねーしな。

## なんで今日の記事ポエムなの？
ちょっと「YOU ARE THE CHAMPION」って言われたくて忙しい
手軽に出来る定期実行の手段まとめ

スクレイピングやボットなど、長い間定期的に実行したいプログラムがある時には、クラウドサーバーを使うのが良い選択です。

そういうわけで、僕が知っている定期実行の手段をまとめてみました。サーバーレスが中心です。
「他にこんなのもあるよ」という方は、ぜひ編集リクエストで追加をお願いします！
## 1 AWS Lambda とAmazon CloudWatch 
[公式チュートリアルはこちら。](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/events/RunLambdaSchedule.html)
### メリット
安定のAWS。Lambdaの対応言語も多い。
### デメリット
クレカ登録が必要。初心者には少し敷居が高い。

## 2 Firebase Functionsとcron-job.org
### メリット
Firebase最高！とても簡単に出来る。
### デメリット
ログがみにくい。Nodeしか使えない。


## 3 Heroku Scheduler
個人的に、Raiilsプロジェクトで定期実行を行うために重宝しているので載せておきます。
## 終わりに
私は現在、Web3のサービスの開発をしています。詳しくはこちらの記事をご覧下さい。
        [無料でイーサリアムが当たる、Web3時代の寄付サイトを作った話](https://note.com/kenroda/n/n814347fbdcd7)
wgetの使い方メモ - basic認証、robots.txt無視

Macユーザーなら、サイトをまるごとバックアップするにはwgetが便利です。
よく使うオプションのメモ。

## コマンド例

wget -r -l 0 -e robots=off --http-user=hoge_user --http-passwd=fugapwd https://xyz.jp/

## 全階層を取得する

-r -l 0 

## robots.txtの無視
デフォルトでは、robots.txtに忠実に従うので、disallowされていると、ダウンロードできません。

-e robots=off

# Basic認証

--http-user=hoge_user --http-passwd=fugapwd
Jupyter Notebookでデフォルトで行番号を表示する

# 環境
- Windows 10 Home Edition

# Jupyter Notebookでデフォルトで行番号を表示する
Google検索すると、いくつか方法がある。
`C:\Users\ユーザー名\.jupyter`に`custom`ディレクトリを作りcustom.jsを作り以下の記述を付け足すらしいです

```javascript
define([
    'base/js/namespace',
    'base/js/events'
    ], 
    function(IPython, events) {
        events.on("app_initialized.NotebookApp", 
            function () {
                require("notebook/js/cell").Cell.options_default.cm_config.lineNumbers = true;
            }
        );
    }
);
```

自分もそのとおりに試してこれで表示されるだろうと期待したのですが、表示されません


# 解決方法

`C:\Users\ユーザー名\.jupyter\nbconfig\notebook.json`
とりあえず以上のファイルを開き、以下のように変える

```json
{
  "CodeCell": {
    "cm_config": {
      "lineNumbers": true
    }
  }
}
```
もしも元々`"lineNumbers": true`の箇所を同じなら、
一度`"lineNumbers": false`にしてから、もう一度trueに戻してください

正直自分でもなぜ動いたかよく分からない。
Excel経由でWin32APIのURLDownloadToFileを使ってファイルをダウンロードするVBScript

# 概要
Excelがあれば、Win32APIのURLDownloadToFile()を呼び出して、web上のファイルをダウンロードします。
ExcelのApplication.ExecuteExcel4Macro()メソッドを利用しています。

# 使用方法
- InputBoxからURLを入力
- 「名前を付けて保存」ダイアログから、保存先のファイル名を入力
- キャンセルするまで繰り返す


```vb:URLDownloadToFile.vbs
Option Explicit
Dim Application
Dim CD
Dim URL
Dim Path
Dim RC

Set Application=CreateObject("Excel.Application")
CD=CreateObject("Scripting.FileSystemObject").GetAbsolutePathName("")
Call Application.ExecuteExcel4Macro("CALL(""kernel32"",""SetCurrentDirectoryA"",""JC"","""&CD&"¥..¥"")")
Do
  URL=InputBox("URLを入力してください。")
  If URL="" Then Exit Do
  Path=Application.GetSaveAsFileName("*.*","すべてのファイル,*.*")
  If Path=False Then Exit Do
  RC=Application.ExecuteExcel4Macro("CALL(""urlmon"",""URLDownloadToFileA"",""JJCCJJ"",0,"""&URL&""","""&Path&""",0,0)")
  If RC Then
    MsgBox Join(Array(URL,Path,Hex(RC)),vbLf),vbCritical,"失敗"
    Err.Raise &H80070000 Or (&HFFFF& And RC)
  Else
    MsgBox Join(Array(URL,Path,RC),vbLf),vbInformation,"成功"
  End If
Loop
```
herokuでデプロイをロールバックする

## 一世代前にロールバック

```
$ heroku rollback
```

## ロールバックするバージョンを指定

heroku releaseでバージョン一覧を表示し、バージョン番号(v1..)をrollbackの引数に指定。

```
$ heroku release

MacBook-Pro-3:sample_app inutty$ heroku releases
=== sample181023 Releases - Current: v9
v9  Rollback to v7                                   aaa@gmail.com  2018/10/26 17:18:48 +0900 (~ 1m ago)
v8  Deploy f447c4b7                                  aaa@gmail.com  2018/10/26 16:57:51 +0900 (~ 22m ago)
v7  Deploy 523a26c5                                  aaa@gmail.com  2018/10/25 12:47:08 +0900
v6  Deploy 6203c079                                  aaa@gmail.com  2018/10/23 12:31:55 +0900
v5  @ref:postgresql-symmetrical-80169 completed pr…  aaa@gmail.com  2018/10/23 12:31:54 +0900
v4  Attach DATABASE (@ref:postgresql-symmetrical-8…  aaa@gmail.com  2018/10/23 12:31:54 +0900
v3  Set LANG, RACK_ENV, RAILS_ENV, RAILS_LOG_TO_ST…  aaa@gmail.com  2018/10/23 12:31:52 +0900
v2  Enable Logplex                                   aaa@gmail.com  2018/10/23 12:22:04 +0900
v1  Initial release                                  aaa@gmail.com  2018/10/23 12:22:03 +0900
```
Rails on Dockerでcredentialsをeditしたい

# Introduction
Rails 5.2.2から登場したcredentialsさん。
通常、`rails credentials:edit EDITOR="vim"`のような感じで編集ができるのですが、Rails on Dockerの場合で躓いちゃったのでメモを残しておきます。

# 1. Dockerでvimをインストール
`vim`でなくても良いですが、Dockerイメージにお好きなエディタをインストールします。
例えばRubyの公式イメージをベースにする場合は、Debianをベースに作られているはずなので、`apt-get install`でインストールできます。（alpineベースだと`apk add`だったり。この辺りはお使いのベースイメージに合わせて）

```dockerfile:/Dockerfile
apt-get install -y vim
```
追記したら`vim`がインストールされたDockerイメージを作成するためにビルドします。

```
$ docker-compose build
```

# 2. EDITORを環境変数として指定
あとは`run`するときに起動コンテナに環境変数を渡す形で`EDITOR=vim`を指定してあげます。

```
$ docker-compose run -e EDITOR=vim web rails credentials:edit
```
※Railsが動くコンテナのサービス名が`web`の前提です。

# 別解. `docker-compose.yml`に環境変数を定義しておく
上の手順からわかる通り、環境変数`EDITOR`をコンテナに渡しているだけなので、`2`は以下の対処にすることも可能です。

```yaml:docker-compose.yml
# ...
services:
  web:
    # ...
    environment:
      - EDITOR=vim
    # ...
```

```
$ docker-compose run web rails credentials:edit
```
credentialsを何回も編集する場合はこちらの方が効率よさそう。

# Conclusion
同じように躓いちゃった人の参考になれば嬉しいです！
No.039【Python】辞書の値の取得・追加：setdefault

![python-logo-master-v3-TM-flattened.png](https://qiita-image-store.s3.amazonaws.com/0/336067/8fb9f6aa-57f7-dc4b-b4bf-a648969d315c.png)

####今回は、辞書の値を取得・追加する「setdefault()」について書いていきます。
I'll write about acquiring and adding the value of a dictionary：setdefault().

###■ 辞書への要素追加・更新
&emsp;Add and update elements to a dictionary

```
>>> # 要素の追加・更新の仕方
>>> # 辞書オブジェクト[キー] = 値
```

``` 
>>> d = {"key1": 1, "key2": 2}
>>> 
>>> d["key3"] = 3
>>> 
>>> print(d)
{'key1': 1, 'key2': 2, 'key3': 3}
>>> 
>>> d["key1"] = 50
>>> 
>>> print(d)
{'key1': 50, 'key2': 2, 'key3': 3}
```
###■ setdefault()メソッドの使用方法
&emsp;How to use setdefault()method

``` 
>>> #第一引数：key
>>> #第二引数：value
>>> 
>>> #第一引数に指定のキーがない場合、新たな要素が追加される
>>> 
>>> d = {"key1": 1, "key2": 2}
>>> 
>>> d.setdefault("key3", 3)
3
>>> print(d)
{'key1': 1, 'key2': 2, 'key3': 3}
``` 

``` 
>>> # valueを省略するとNoneが追加される
>>> 
>>> d.setdefault("key4")
>>> 
>>> print(d)
{'key1': 1, 'key2': 2, 'key3': 3, 'key4': None}
``` 

```   
>>> #第一引数がすでに存在する場合、第二引数へ値を指定しても変更されない
>>> 
>>> d.setdefault("key1", 50)
1
>>> print(d)
{'key1': 1, 'key2': 2, 'key3': 3, 'key4': None}
>>> 

``` 

###■ setdefault()メソッドの返り値
&emsp;Return value of setdefault()method

```
>>> # 第一引数に指定したキーが存在しない場合:
>>> # 第二引数に指定した値で要素追加後、値が返される
>>> 
>>> d = {"key1": 1, "key2": 2,"key3": 3, "key4": 4}
>>> 
>>> d.setdefault("key5", 5)
5
>>> 
>>> print(d)
{'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5}
```

``` 
>>> # 第二引数省略の場合：
>>> # Noneを追加し、Noneを返す
>>> 
>>> print(d.setdefault("key6"))
None
>>> print(d)
{'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5, 'key6': None}
```

```
>>> #第一引数に指定のキーが存在する場合：
>>> #第二引数へどんな値を指定しても既存のキーへは影響はない
>>> 
>>> print(d.setdefault("key1", 25))
1
>>> 
>>> print(d.setdefault("key1", -25))
1
>>> 
>>> print(d.setdefault("key1"))
1
>>> 
>>> print(d)
{'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5, 'key6': None}
```

随時に更新していきますので、<br>定期的な購読をよろしくお願いします。
I'll update my article at all times.
So, please subscribe my articles from now on.

本記事について、<br>何か要望等ありましたら、気軽にメッセージをください！
If you have some requests, please leave some messages! by You-Tarin
Pythonの~xって何？

Pythonのソースコードを見ていたとき、謎の一文を見つけてしまったのでメモ

## ~を使うとどうなるの
簡単な式で表せます。

```py
~x
```
は
$$-(x+1)$$
です。

### 例
```py
~1  # -2
~100 # -101
```

## ~の正体
どうやらビット演算子の一つらしいです。

## 最後に
Googleで「Python ~」で検索しても~は無視されちゃって大変でした…

記号を無視しない設定を用意してほしいです。（すでに用意されてる可能性大ですが）
F9で再計算されないExcelのセルを更新する


計算方法の設定「自動」で、セルの数式が更新されない場合の対処法を見つけたのでメモ。

# 問題
セルの数式の更新がされず、「再計算実行」も効かない。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/277734/f300e34c-0e54-735d-7e97-0eb006baa6fd.png)
対象のセルを選択し、Enterで更新できるが複数の数式を一括で更新できない。

# 解決
**Ctrl+Alt+F9**
※「開いているすべてのブックのツリーの再構築と計算の強制」を行うので、再計算のコストに注意する

# 補足
VBAの場合
**Application.CalculateFull**

Excel の再計算
https://docs.microsoft.com/ja-jp/office/client-developer/excel/excel-recalculation
Jupyter notebookの初期ディレクトリ、ホームディレクトリを変える誤った方法

# Jupyter notebookの初期ディレクトリを変える方法
Googleで検索すると、一般に以下の方法が見つかります。

1) Anaconda Promptを開き以下のコマンドを実行して設定ファイルを生成する。

```bash
jupyter notebook --generate-config
```
2) `C:\Users\username\.jupyter\jupyter_notebook_config.py`を開き、以下の箇所を検索して
コメントを意味する文頭のシャープ(#)を削除して、自分の好みのディレクトリを指定する。
一例として以下のように

```python
## The directory to use for notebooks and kernels.
c.NotebookApp.notebook_dir = 'C:\\Users\'
```
これで他の人は解決していたようですが、自分の場合は動かない……
なぜか同じディレクトリしか開かない。

## 解決法
自分はスタートメニューにJupyter notebookのショートカットをピン留めしていたのですが、
問題はそこに余計な引数が渡されていたが原因でした。

自分の解決法は、まず起動用のJupyter notebookのショートカットアイコンを右クリック。
その他 > ファイルの場所を開く
を選択し、Jupyterのショートカットを右クリック。コンテキストメニューからプロパティを選択。
リンク先のフォームの最後についている「%USERPROFILE%」を削除します。

これで指定したディレクトリを開けます。
プログラミング学習記録6〜シンタックスハイライトに手を出す〜

##今日やったこと
- Progate Ruby1~3 そのまま復習
- Progate Ruby4,5 リセット復習
- Progate Command Line リセット復習
- initializedメソッド、クラスの継承の意味と便利さに気づく笑

明らかにやり過ぎなくらい、ProgateのRubyをやりました。

流石にやり過ぎたので、Progate Rubyの復習はしばらくやめます。

忘れたところがあったらたまにスライドを見るくらいにします。
そうじゃないと先に進めないので。

##initializedメソッド
いまいちこのinitializedメソッドが何のために使うのかがよくわかっていなかったが、今日ようやくわかった気がします。

Initializedを使うと、インスタンス変数の記述を減らすことができ、全体的にコードをスッキリできる。

具体的に言うと、

```rb
menu1.name=“寿司”
menu1.price=500
menu1.calorie=300
```

と書いていたものを

```rb
def initialized(name:,price:,calorie:)
  self.name=name
  self.price=price
  self.calorie=calorie
end
```
とすることでインスタンスを作るときに

```rb
menu1=Menu.new(name:”寿司”,price:500,calorie:300)
```

というように１行でまとめることができる。

インスタンスが１種類だとあまりメリットを感じないですが、インスタンスが何種類もあったとき(menu2,menu3,menu4,,,,,,)にかなり省略でき、とても便利だと思いました。


##クラスの継承、オーバーライド、super
これもinitializedメソッド同様にコードの記述を少なくするものです。

異なるクラスを作るときに他のクラスとの共通部分を利用できルカらです。

例えば、Aというクラスが1,2,3という情報を持っていたとして、1,2,3,4という情報を持つBクラスを作りたくなった時に、Aクラスの内容を継承することで、新しく書くのは4だけでよくなるって感じですね。

##Qiitaのシンタックスハイライト
100DaysOfCode 6日目にして初めてコードを見やすく表示する「シンタックスハイライト」というやつを使って、コードを書いてみました。

ようやく学習記録という感じになりました。

シンタックスハイライトについてはこちらの記事に使い方がわかりやすく書かれています↓
https://qiita.com/Qiita/items/c686397e4a0f4f11683d

明日からも引き続きプログラミングの勉強を頑張りたいと思います。

おわり
[C++] unorder_set custom hash function

When we use `set` we can override operator `<` for the custom class. Because it is implemented by Red-Black tree. But it does not work for `unordered_set`, because `unordered_set` is based on hash. If we want to use `unordered_set` for our custom class. We must tell `unordered_set` the hash value for a object.

What we need to do.

- override == operator
- implement hash function

Here is a example

```c++
struct Point {
    int x, y;

    Point(int x, int y) : x(x), y(y) { }
    // override == operator
    bool operator == (const Point& other) const {
        return x == other.x && y == other.y;
    }
};

// implement hash function
namespace std {
    template<>
    struct hash<Point> {
        size_t operator () (const Point& point) {
            // just a simple way to hash a point range between 0..100
            return point.x * 100 + point.y;
        }
    };
}
```

Test our custom class `Point`

```c++
int main() {
    unordered_set<Point> point_set;
    point_set.insert(Point(0,0));
    point_set.insert(Point(0,1));
    point_set.insert(Point(0,1));

    for (auto& point : point_set) {
        cout << point.x << " " << point.y << endl;
    }
    return 0;
}
```

Output

```
0 1
0 0
```
Macでpython3の仮想環境構築

<h2>Macでpython3の仮想環境を構築した際のメモ。</h2>
<p>仮想環境を作成する。</p><code>$ python3 -m venv env-py3</code>
<br>
<p>作成した環境を有効にする。</p><code>$ source env-py3/bin/activate</code>
<br>
<p>環境を終了</p><code>$ deactivate</code>
AWSバーチャル彼女から毎朝モーニングコールで起こしてもらう1つのアーキテクト

###目覚ましが鳴らなくて会社に遅刻、、、なんて経験ありませんか？

私も先日、起床したら11時…　派手に遅刻し、上司から

###「再発防止を考えるように！」
　とお叱りを受けました。

というわけで、

###バーチャル彼女モーニングコールを設計します

AWS Cloudwatch Event, Lambdaに加え、
コールセンター革命とも呼ばれたクラウド電話サービス「Amazon Connect」を使用し、
完全なるサーバーレスで設計します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276897/097dc4e1-d0b6-c7b7-52ac-06037bbdc8e1.png)
【要件】
・平日の朝7時にAmazon Connectのコールフローが発動し、
　自分のスマホの電話番号に発信して女性の声でコールスクリプトが読み上げられること

##コールフローを作成する
AWS公式のAmazon Connectハンズオンスライド資料の15〜70を参照し、
インスタンス、およびコールフローを作成する。（約15分）
https://www.slideshare.net/AmazonWebServicesJapan/amazon-connect-85894458

「プロンプトの再生」でテキスト読み上げにし、
適当に言ってほしいことを入力する。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/276897/9fbf2d2e-5439-110a-6a49-0ffc2432a5e7.png)
問い合わせフローエディタにある
コンタクトIDとコールフローIDは後で使うので控えておくこと。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276897/82ad1117-179f-1436-a4ed-052c02320e1e.png)

##Lambdaを作成する
Node.js 8.10でLambda関数を作成する。

以下を自分の環境に置き換える
 　- ContactFlowId
 　- InstanceId
 　- SourcePhoneNumber (Amazon Connectから発行された発信用番号)

```Node.js:
exports.handler = async (event) => {

    // import entire SDK
    var AWS = require('aws-sdk');

    var connect;
    // create amazon connect object
    connect = new AWS.Connect({apiVersion: '2017-08-08', region:"ap-southeast-2"});

    // create API request parameter
    var params = {
      ContactFlowId: "*************************",
      DestinationPhoneNumber: process.env.PHONENUMBER,
      InstanceId: "***************************",
      SourcePhoneNumber: "+81**********"
    };
  // call API with parameter
  console.log("start!");
  var calling = connect.startOutboundVoiceContact(params, function(err, data) {
    if (err) {
      console.log(err);
    } else {
      console.log(data);
    }
  });
  return calling;
};
```

環境変数に自分のスマホの番号を入力する
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276897/6eeaad8a-7e65-8311-a40f-00adc4309a06.png)

Lambdaの実行権限に
AmazonConnectFullAccess
を付与すること。



##Cloud Watch Eventを作成する
時刻はUTC基準なので気をつける。
UTC + 9時間 = JST

Cron式を設定し、作成したLambda関数名を指定する。

```
0 22 ? * MON-FRI *
```
（平日の朝7時に起動）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276897/342f3235-9f25-a243-8d71-37f3711c1f22.png)


名前と説明を付けて完成
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276897/fd4f595c-7fa2-8728-d18d-edb3ce0c53c2.png)

##おわりに
・Amazon Connectの音声設定をTakumiさんにすればバーチャル彼氏にも対応可能
・「プロンプトの再生」ではwavファイル再生可能。現実の彼女の声を録音すればバーチャルから脱出できる
・コールフローの途中でLambda関数も呼び出せるので、簡単な計算式をプッシュ通知で解かせる事も可能


**遅刻は根性論ではなく、仕組みで防げる。
しかし、今回、そもそも早く寝た方が良いという結論に至った。**

ありがとうございました。
少しでもお役にたちましたら「いいね」をよろしくお願いします。
【Laravel5.7】belongsToのリレーション先の型がintになって死んだ

idがstring型で定義されたテーブルA、およびA.idにリレーションを張ってるテーブルBがあるとします。


# テーブル

## テーブルA

```sql
CREATE TABLE table_a (
 `id` varchar(16) NOT NULL COMMENT '主キー',
 `name` varchar(16) NOT NULL COMMENT '名前',
 PRIMARY KEY (`id`)
)
```

## テーブルB

```sql
CREATE TABLE table_b (
 `id` int NOT NULL COMMENT '主キー',
 `a_id` varchar(16) NOT NULL COMMENT 'table_a.id',
 PRIMARY KEY (`id`),
 CONSTRAINT `a` FOREIGN KEY (`a_id`) REFERENCES `table_a` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
)
```


# モデル

## モデルA

```php
class A extends Model
{
    protected $table = 'table_a';

    // IDは文字列型
    protected $casts = [
        'id' => 'string',
    ];
}
```

## モデルB

```php
class B extends Model
{
    protected $table = 'table_b';

    // a_idは文字列型
    protected $casts = [
        'a_id' => 'string',
    ];

    // Aへのリレーション
    public function table_a()
    {
        return $this->belongsTo('Path/To/Model/A', 'a_id', 'id');
    }
}
```

# コントローラ

```php
public function hogeAction(Request $request){
	// BとAを取得
    $BwithA = B::where('id', 1)->with(['table_a'])->get();
}
```

# 発行されたSQL

[DB::getQueryLog]()で確認できます。

```php
array:2 [
  0 => array:3 [
    "query" => "select * from `b` where `id` = ?"
    "bindings" => array:1 [
      0 => 1
    ]
  ]
  1 => array:3 [
    "query" => "select * from `a` where `a`.`id` in (999)"
    "bindings" => []
  ]
]
```

おい`"`どこ行った。

# 現象

`b.a_id`がどのような形であろうが、数値として扱われてしまいます。
`a_id`に"hoge"とか文字列が入っていたとしても気にせず数値にするので`where a.id IN (0)`になってしまいます。
結果として正常にリレーションを持って来れません。


# 調査

## Illuminate\Database\Eloquent\Relations\BelongsTo

BelongsToクラス内のaddEagerConstraintsでWHERE IN句を生成しているようだ。

```php:BelongsTo.php
public function addEagerConstraints(array $models){
    $whereIn = $this->whereInMethod($this->related, $this->ownerKey);
    $this->query->{$whereIn}($key, $this->getEagerModelKeys($models));
}
```

この`$whereIn`に、`whereIntegerInRaw`とかいういかにもintを返すっぽい値が入っていた。

## Illuminate\Database\Eloquent\Relations\Relation

Relationクラス内のwhereInMethodメソッドが、`whereIntegerInRaw`もしくは`whereIn`という値を返している。


```php:Relation.php
    protected function whereInMethod(Model $model, $key)
    {
        return $model->getKeyName() === last(explode('.', $key))
                    && $model->getIncrementing()
                    && in_array($model->getKeyType(), ['int', 'integer'])
                        ? 'whereIntegerInRaw'
                        : 'whereIn';
    }
```

こういう書き方やめてくれよ。

さて`$model->getKeyType()`が悪さをしているようだ。
コントローラでちょっと確認してみる。

```php
public function hogeAction(Request $request){
    $a = new A();
    var_dump($a->getKeyType());
}
```

`$a`は`int`になった。
なんで？


# 解決

主キーの型指定は`$casts`ではなく`$keyType`の[設定が必要だった](https://readouble.com/laravel/5.7/ja/eloquent.html#contentContainer)とかいう落ち。

> 主キーが整数でない場合は、モデルのprotectedの$keyTypeプロパティへstring値を設定してください。


# 感想

最初から主キーの型という方向で調べればすぐわかったと思うのだが、`with`や`belongsTo`から調べ始めてしまったために無駄に時間がかかった。

ところでこれ、今回は外部キーの向き先がテーブルAの主キーだったから`$keyType`で解決できたけど、主キーではなく他のカラムだった場合はどうなるんだろう？
Automaterを使ってchromeでDropbox Paperを開くアプリケーションを作成する

# 2020/02/09 追記
DropboxがDropbox Paperのデスクトップアプリをリリースしました。
(追記ここまで)

---



# はじめに

Dropboxはファイル共有とクラウド保存を行うことができるサービスで、2015年からチームの情報共有を目的とした[Dropbox Paper](https://paper.dropbox.com/)と呼ばれるサービスを始めました。Dropbox Paperは一枚のドキュメントをチームメンバーで共有しリアルタイムで共同編集できるのが特徴です。

Dropbox PaperはiOSやAndroidアプリなどはあるので気軽に使うことができるのですが、公式のmacアプリケーションはまだありません。

そこでmacに標準でインストールされているAutomatorを使ってDropbox Paperのためのアプリケーションを作成します。正確にはAutomatorによって指定したURLをChromeで開くスクリプトを作成します。今回はDropbox Paperを題材にしていますがこのURL部分を自分の好きなサイトに変更すれば、そのサイト専用のアプリケーションを作成することも可能です。

# 必要なもの
* Google Chrome

# 手順

1. Automater を開き「アプリケーション」を選択
   ![1](https://d2mxuefqeaa7sj.cloudfront.net/s_7D64D42BA042DF8B0B5EB7965B5273A67F9A1F14AEA47D25C78E5826C8647C86_1530950773261_+2018-07-07+17.05.38.png)

2. 検索で「シェルスクリプトを実行」を検索して選択
   ![2](https://d2mxuefqeaa7sj.cloudfront.net/s_7D64D42BA042DF8B0B5EB7965B5273A67F9A1F14AEA47D25C78E5826C8647C86_1530950850007_+2018-07-07+17.07.23.png)

3. シェルのプルダウンを `/usr/local/bin/bash/`から`/bin/bash`に変更する。他の Terminal を使用している場合はお好みで。

4. コマンドを記述するテキストボックス内に次のコマンドを入力する。

   ```bash
   open -n -a /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --args '--app=https://paper.dropbox.com/'
   ```
 ![1](https://d2mxuefqeaa7sj.cloudfront.net/s_7D64D42BA042DF8B0B5EB7965B5273A67F9A1F14AEA47D25C78E5826C8647C86_1530950982818_+2018-07-07+17.09.35.png)
5. 保存して実行

<img width="1281" alt="スクリーンショット 2019-02-22 21.51.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/13590/c917cc85-8612-d0e6-bc79-c79f9e8cffc6.png">
Class not found: "<class name>"Empty test suite.　解決メモ

Androidのライブラリを書いていて、新しいmoduleを追加したのでkotlinのユニットテスト書いた。

```kotlin
class MessageTest {
    @Test
    fun testGet() {
        assertEquals(2, 1 + 1)
    }
}
```

実行すると以下のようなテストが見つからないというエラーが発生。

```
Process finished with exit code 1
Class not found: "com.github.bassaer.travismylib.MessageTest"Empty test suite.
```

試しにjavaのテストを追加してみる

```java
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class FooTest {
    @Test
    public void fooTest() {
        assertEquals(2, 1+1);
    }
}
```

javaだと問題なし。

```
Process finished with exit code 0
```

## 結論

新しく追加したモジュールのgradleに以下を追加するのを忘れていた。

```gradle
apply plugin: 'kotlin-android'
```
laravel5 チェックボックスで「オフの時は0、オンの時は1をpost」はどう書くのが気持ちいいか

チェックボックスはオフの時に値をpostしません。
登録のみなら構わないのですが、編集時はオフの時に値をpostされないと、チェック状態が外せなくなります。

#hiddenを埋め込む

いくつか方法はある（プログラム側でなんとかするとか、jsでなんとかするとか）のですが、
今回はhiddenを埋め込む方法でやってみます。

```html
<input name="cb1" type="hidden" value="0">
<input name="cb1" type="checkbox" value="1">
```

このようにチェックボックスの前にhiddenで0を埋め込んでおくと

- チェックボックスがオンの時はvalueの1がpostされる
- チェックボックスがオフの時はhiddenの0がpostされる

のです。

#formヘルパーで実装

ネットで検索すると
formヘルパーを使った

```php
{{ Form::hidden('cb1', 0) }}
{{ Form::checkbox('cb1', 1, $data['cb1'] ?? '') }}
```

のような書き方が散見されます。
確かにhiddenもcheckboxもこれで配置されますが、
**この方法はひとつ落とし穴があります。**
**Form::hiddenはoldの影響を受けるのです。**

#検証

![qiita20190222_1.png](https://qiita-image-store.s3.amazonaws.com/0/108345/cd69054c-3068-4c0a-970d-35d7f278f2aa.png)

このようなフォームがあって
チェックボックスには先ほどの

```php
{{ Form::hidden('cb1', 0) }}
{{ Form::checkbox('cb1', 1, $data['cb1'] ?? '') }}
```

という記述をしているとします。
テキストにはフォームリクエストバリデーションで必須を指定しています。

この時点では
![qiita20190222_2.png](https://qiita-image-store.s3.amazonaws.com/0/108345/b2ee05e8-0538-ecf8-b4a6-61a123a3213c.png)
期待した通りの状態になっています。

では、チェックボックスをオンにして、テキストには何も入力せずにpostしてみましょう。

![qiita20190222_3.png](https://qiita-image-store.s3.amazonaws.com/0/108345/6df4dae5-59ed-ac35-e1f2-32b71f628e4e.png)

テキストのバリデーションエラーで入力画面に戻りました。
この状況でhiddenの値がどうなっているかというと…

![qiita20190222_4.png](https://qiita-image-store.s3.amazonaws.com/0/108345/57612491-30a8-1012-7a50-bf7eb8c7efc2.png)
**hiddenのvalueが1になってしまいました。**

チェックボックスをオンにしたため、cb1=1としてpostされ、
old('cb1')は1になります。
バリデーションエラーで戻ってきた入力画面では、Form::hiddenはこの値を使用して
valueの値を変更します。

というわけで、formヘルパーでhiddenを埋め込むと
valueを0に固定できません。
まぁ、

```php
<input name="cb1" type="hidden" value="0">
{{ Form::checkbox('cb1', 1, $data['cb1'] ?? '') }}
```

と書けば解決するんですが、
あまりテンションの上がらない書き方です。

「チェックしたままpostしてバリデーションエラーで戻されてからチェックを外す」
という状況でしか問題にならないから別にええやないか、とも言えますが、
やっぱりあまりテンションは上がらない感じになります。

#ないなら作る

LaravelのFormヘルパーはマクロを自作できます。

というわけで
チェックボックスの前に自動でhiddenの値を埋め込んでくれる
Form::booleanboxを自作します。

```
$ php artisan make:provider FormMacroServiceProvider
```

```php:app/Providers/FormMacroServiceProvider.php
class FormMacroServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        require app_path().'/Libs/FormMacro.php';
    }
}

```

```php:config/app.php
    'providers' => [
        App\Providers\FormMacroServiceProvider::class,
    ],
```

```php:app/Libs/FormMacro.php
\Form::macro("booleanbox", function($name, $value = 1, $checked = null, $options = array()){
    return $this->toHtmlString("<input type=\"hidden\" name=\"{$name}\" value=\"0\">". \Form::checkbox($name, $value, $checked, $options));
});
```

あとは

```php
{{ Form::booleanbox('cb1', 1, $data['cb1'] ?? '') }}
```

と書けば
Form::checkboxと
全く同じように使えるようになります。

#とはいえ

新規案件でしたら
vue / react なんかで
ページ遷移とかoldとかを気にしない作りにしてしまうのが
一番気持ちいいとは思います。

古いプロジェクトの修正をする必要がある場合なんかにどうぞ。
これならForm::checkboxを一括置換するだけで済むので。
JupyterNotebookで行番号を常に表示

# はじめに
JupyterNotebookは、デフォルトで行番号が表示されてません。
行番号が表示されていないと、どの行でエラーが発生したかわかりづらいです。
そこてデフォルトで、行番号を設定する方法をご紹介いたします。
ショートカットキー等で表示させることは可能ですが、後々面倒になってくると思います。

#設定方法
①custom.jsの配置箇所
②custom.jsの配置
③JupyteNotebookの起動

①custom.jsの変更に関して
Windowsではデフォルト設定ではC\Users\(PCのアカウント名)\.jupyterが存在します。
その配下にcustomディレクトリがない場合は、新規作成する必要があります。
もしあれば、その中にcustom.jsといったjavascriptファイルを配置する必要があります。
Windows以外でも.jupyterディレクトリは存在しているので、その配下のcustomディレクトリに配置する必要があります。

②custom.jsの配置
custom.jsの中身は以下をコピーしてjsファイルを作成してください。

```custom.js
// custom.js
//--------------------------------------------------------------------------------
// Display line numbers in code cell by default
//--------------------------------------------------------------------------------

var cell = Jupyter.notebook.get_selected_cell();
var config = cell.config;
var patch = {
  CodeCell:{
    cm_config:{lineNumbers:true}
  }
}
config.update(patch)
```

③JupyteNotebookの起動
実際にJupyterNotebookを起動して、行番号が表示されているかご確認ください。
表示されていれば、下図のようになるはずです。
表示されていなければ、JupyterNotebookを再起動してください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/277025/4c27cfc9-f6f8-7022-2b39-2f05749f4ab4.png)
Firefoxでの印刷時、2ページ目以降のレイアウトが崩れる

###現象
A4の帳票が印刷できるHTMLを作っていて、Firefoxの印刷バグに泣かされました。
同じレイアウトを並べても、2ページ目以降、*position: absolute*で指定している要素の、y方向の指定が無視され、ページ上部に詰まったような形になってしまっていました。

　　↓　ブラウザ上で普通に見る分には普通
![img1.png](https://qiita-image-store.s3.amazonaws.com/0/82885/65402c6c-b490-664e-ff42-62056c03cc3c.png)
　　↓　しかし印刷プレビューや印刷結果では、ひょえ～
![img2.png](https://qiita-image-store.s3.amazonaws.com/0/82885/23c0e597-20a8-5912-7934-d4c9239d41cd.png)

###原因
調べてみると、根本的な原因は、Firefoxの印刷バグで、*position: relative*を指定したA4サイズのdivの中に、*position: absolute*で要素を配置していくと、このようになるとのこと。ただ、解決方法を見ても、*position: relative*を使わなければ大丈夫、としか書いてなく途方に暮れます。

###解決方法
*position: relative*を指定したA4サイズのdiv内の冒頭に、*position: relative*指定をした画像を敷くと解決しました。
これは透明なPNGでもよく、サイズも1pxで大丈夫です。
このダミー画像の後に、*absolute*でいろんな要素を配置していけばOK。
印刷時に*relative*な画像を描画しようとする際、ちゃんとy方向も計算されるのかもしれません。

###おまけバグ
これで解決した～、と思っていたのもつかの間、まだ微妙にカスいバグがありました。
最上段に*height*を指定した*th*が並んでいる、ありがちな*table*を作ったら、その*th*の高さ指定が無視されてしまいます。
しかも、その下のセル文字等は、*th*が正しい高さで描画されている前提で描画されるので、上下がズレます。
この現象は、*th*の高さと、*th*の*lineheight*を同じにすることで回避できました（厳密には*border*や*padding*のサイズを考慮して*lineheight*を調整します）。
![img3.png](https://qiita-image-store.s3.amazonaws.com/0/82885/8efca90f-6add-7d23-40bd-06a2c9f9a81f.png)　これが、こう→　![img4.png](https://qiita-image-store.s3.amazonaws.com/0/82885/120587fa-e886-6f11-a5b1-da182ab00d15.png)



###感想
モダンブラウザの印刷環境は近年非常に使えるようになってきましたが、時々びっくりバグやクセがあって困りますね。