OmniAICreator/Qiita-1.07M huggingface dataset:
コンフュージョンマトリックスって、行合計に対する各要素の比率も必要なんじゃ？

# はじめに
[Pythonデータサイエンスハンドブック](
https://www.oreilly.co.jp/books/9784873118413/)の勉強中に思ったこと。

seabornでヒートマップ作って誤分類を可視化しているけど、これって全体の中で数字が大きい値に色がつくのでは？
（全分類でサンプル数が同じであればよいが、データ不均衡は往々にして発生するため）

行の合計（＝各分類）に対する、各要素の割合が分かるヒートマップもあった方がよいのでは。
ということで作った。

# データの読み込みと分類アルゴリズムの適用
```Python:load_and_modelfitting.py
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix

# サンプルとして今回は手書き文字の画像を分類タスクとしてロード
digits = load_digits()
X = digits.data
y = digits.target

# 訓練用と評価用に分割
Xtrain, Xtest, ytrain, ytest = train_test_split(X, y, random_state=0)

# 分類アルゴリズムも適当にガウシアンナイーブベイズを適用
model = GaussianNB()
model.fit(Xtrain, ytrain)
y_model = model.predict(Xtest)
accuracy_score(ytest, y_model)
```

# ここから本題
いつもの混同行列と、行に対する比率の配列をヒートマップにする

```Python:create_confmrx.py
# 普通のコンフュージョンマトリックスの2次元配列
mat = confusion_matrix(ytest, y_model)
# 各行合計に対する割合を計算し、小数点第3位を四捨五入した2次元配列
mat_dec = np.round(mat / np.sum(mat, axis=1), decimals=2)

fig, axes = plt.subplots(1, 2, figsize=(10, 10))
kwargs = dict(square=True, annot=True, cbar=False, cmap='RdPu')

# 2つのヒートマップを描画
for i, dat in enumerate([mat, mat_dec]):
    sns.heatmap(dat, **kwargs, ax=axes[i])

# グラフタイトル、x軸とy軸のラベルを設定
for ax, t in zip(axes, ['Real number', 'Percentage(per row)']):
    plt.axes(ax)
    plt.title(t)
    plt.xlabel('predicted value')
    plt.ylabel('true value')
```
![heatmap.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172589/ddcc2fda-ffb6-8d73-fd60-a56310bf1a65.png)

# 描画したヒートマップ情報の解釈案
- 全体を俯瞰する
    - 左側（普通のヒートマップ）の対角線上で色が薄い要素に注目し、「全体の中でハズレが多かった行」を特定
    - 分類2,9,4,0が該当
- 右側ヒートマップを見て「行単位の中でもハズレが多い要素」を確認する
    - 分類2,9が該当しそうなので、サンプル数増やすとかチューニングを優先的に行う
    - 逆に分類4,0は、左側だけを見ると色が薄いが、右側を見ると色が濃いのでチューニングの優先順位低

# おわりに
コンフュージョンマトリックス、見方がムズい…。
フーリエ変換に関するメモ

- 授業で習ったことをまとめるメモ

## 線形代数のおさらい

#### 1. n次元の空間は、n個の基底ベクトルで表される

下の図の場合、2次元平面上の任意の点P$(\vec{r})$は、２つの基底ベクトル　$\vec{a}, \vec{b}$　の線型結合で表される
$$\vec{r} = c_1 \vec{a} + c_2 \vec{b}$$
![](https://web1.kcg.edu/~k_emi/math/LA/chap1/LA112.files/image061.jpg)
(http://web1.kcg.edu/~k_emi/math/LA/chap1/LA112.htm )
一般には、
$$\vec{e_1}, \vec{e_2}, \cdots, \vec{e_n}$$ を基底ベクトルとすると、
$$\vec{r} = c_1 \vec{e_1} + c_2 \vec{e_2} + \cdots + c_n \vec{e_n}$$
と表される.　ここで、$$c_1, c_2, \cdots, c_n$$は、各基底ベクトルの**”重み付け”**と考えることができる.
#### 2. ベクトルの内積

２つの複素n次元ベクトル
$$\vec{a} = (a_1, a_2, \cdots, a_n), \vec{b} = (b_1, b_2, \cdots, b_n)\in \mathbb{C}$$ の内積は、

```math
\begin{align}
\vec{a}\cdot\vec{b} &= |a|\, |b|\cos\theta \\
      &= a_1b_1^{*} + a_2b_2^{*}+ \cdots+a_nb_n^{*}
\end{align}
```
特に、
$$\vec{a}\cdot\vec{b} =0 \ \Leftrightarrow \ \vec{a} \perp \vec{b}$$
#### 3. 連続関数 f(x), g(x) の内積
連続関数 $f(x), g(x)$ の内積は、
$$\int^{\infty}_{-\infty}f(x)\ g(x)^{*}\  dx$$
#### 4. 正規直交基底

基底のとり方のうち、”大きさが１”　かつ　”互いに直交”しているものを**正規直交基底**という  
例）デカルト座標系
![](https://imagingsolution.net/wordpress/wp-content/uploads/2012/02/Orthonormal_basis_1.png)
(https://imagingsolution.net/math/orthonormal_basis/ ）

上図では、

```math
e_1 =
\left(
    \begin{array}{c}
      1 \\
      0 \\
    
    \end{array}
  \right),\ \  e_2 =
\left(
    \begin{array}{c}
      0 \\
      1 \\
    
    \end{array}
  \right)
  
```
が正規直交基底ベクトルである.
#### 5. 正規直交基底に対する基底変換
$$\vec{r} = c_1 \vec{e_1} + c_2 \vec{e_2}$$
において、”重み付け”　$c_1, c_2$　は、
$$\vec{r}\cdot\vec{e_1}=c_1\ \vec{e_1}\cdot\vec{e_1}+c_2\ \vec{e_2}\cdot\vec{e_1} = c_1$$$$\vec{r}\cdot\vec{e_2}=c_1\ \vec{e_1}\cdot\vec{e_2}+c_2\ \vec{e_2}\cdot\vec{e_2} = c_2$$
で求められる.

## フーリエ変換とは？

一般の関数  $f(t)$  について、$f(t)$  を、
$$”重み付け”をF(\omega)、基底を\frac{1}{\sqrt{2\pi}}e^{i\omega t}$$
の無限次元の線型結合として表すと、$$f(t)=\int^{\infty}_{-\infty}F(\omega)\left(\frac{1}{\sqrt{2\pi}}e^{i\omega t}\right)^{*} d\omega$$と表せる.

**この”重み付け”$F(\omega)$を求める操作のことをフーリエ変換という.**

ここで、上記の　**5. 正規直交基底に対する基底変換**　を利用すると、

$F(\omega)$（重み付け）を求めるには、$f(t)$と基底の内積をとれば良いので、

```math
\begin{align}
F(\omega) = \int^{\infty}_{-\infty}f(t)\left(\frac{1}{\sqrt{2\pi}}e^{i\omega t}\right)^{*} dt
\end{align}
```
これを**フーリエ変換**という.

## まとめ

$$フーリエ変換：　F(\omega) = \int^{\infty}_{-\infty}f(t)\left(\frac{1}{\sqrt{2\pi}}e^{i\omega t}\right)^{*} dt$$

$$逆フーリエ変換：　f(t) = \int^{\infty}_{-\infty}F(\omega)\left(\frac{1}{\sqrt{2\pi}}e^{i\omega t}\right) d\omega$$
初期EC2のTeratermログインマクロ

# 内容
AWSで作成したサーバへログインするTeratermマクロ(コピペで可能)

# 何故作ったか
AWSでサーバ作成した後に初めてSSH接続を行う際
IPアドレス⇒ユーザ(ec2-user...)⇒キーペア(鍵)選択⇒接続
上記をしているんですが、面倒になってきたので作りました。
コピペ用なので詳しい事は調べて頂くか、よければ以下を見てみてください。
[Teratermマクロ初心者入門](https://qiita.com/Inon/items/f7b71e44ae6313a7c01c)

# 前提条件
・SSH接続可能なサーバが存在していること
・Teratermマクロとキーペア(鍵)が同ディレクトリ配下に存在していること

### ユーザ情報
初期状態のユーザ情報を記載しておきます。
[Linux インスタンスでのユーザーアカウントの管理](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/managing-users.html)

| AMI       |       ユーザ名　 |
|:-----------------|---------------------:|
| Amazon Linux 2           |              ec2-user |
| Amazon Linux            |            ec2-user |
| CentOS                  |              centos |
| Debian                  |  　　admin,root |
| Fedora                  |ec2-user,fedora  |
| RHEL                 |  　　admin,root |
| SUSE                  |ec2-user,root  |
| Ubuntu                  |ubuntu  |

### IP固定してないEC2用(毎回IPだけ入力する)
```
;========================================================== 
; <マクロ名>
; <用途>
;========================================================== 
; ディレクトリ取得
getdir DIR

; IPアドレスの入力
inputbox 'IPアドレスの入力' '接続情報'

; 鍵ファイルを指定
KEY = '使用するキーペア(鍵)のファイル名'
makepath KEYFILE DIR KEY

; ログディレクトリの指定
LOGSDIR = DIR
strconcat LOGSDIR '\LOGS\'

; ログディレクトリの作成
foldersearch LOGSDIR
if result = 0 then
foldercreate LOGSDIR
endif

; 接続情報
HOSTNAME = '<任意のホスト名>'
HOSTADDR = inputstr
USERNAME = '<接続ユーザ>'

; 接続オプション
COMMAND = HOSTADDR
strconcat COMMAND ':22 /ssh /2 /auth=publickey /user='
strconcat COMMAND USERNAME
strconcat COMMAND ' /keyfile='
strconcat COMMAND KEYFILE

; 接続
connect COMMAND

; ログファイル情報作成
getdate LOGDATE '%Y%m%d_%H%M%S'
strconcat LOGNAME LOGSDIR
strconcat LOGNAME HOSTNAME
strconcat LOGNAME '_'
strconcat LOGNAME LOGDATE
strconcat LOGNAME '.log'

; ログファイル作成
logopen LOGNAME 0 0

end
```

### IP固定しているEC2用
```
;========================================================== 
; <マクロ名>
; <用途>
;========================================================== 
; ディレクトリ取得
getdir DIR

; 鍵ファイルを指定
KEY = '使用するキーペア(鍵)のファイル名'
makepath KEYFILE DIR KEY

; ログディレクトリの指定
LOGSDIR = DIR
strconcat LOGSDIR '\LOGS\'

; ログディレクトリの作成
foldersearch LOGSDIR
if result = 0 then
foldercreate LOGSDIR
endif

; 接続情報
HOSTNAME = '<任意のホスト名>'
HOSTADDR = '<接続先IPアドレス>'
USERNAME = '<接続ユーザ>'

; 接続オプション
COMMAND = HOSTADDR
strconcat COMMAND ':22 /ssh /2 /auth=publickey /user='
strconcat COMMAND USERNAME
strconcat COMMAND ' /keyfile='
strconcat COMMAND KEYFILE

; 接続
connect COMMAND

; ログファイル情報作成
getdate LOGDATE '%Y%m%d_%H%M%S'
strconcat LOGNAME LOGSDIR
strconcat LOGNAME HOSTNAME
strconcat LOGNAME '_'
strconcat LOGNAME LOGDATE
strconcat LOGNAME '.log'

; ログファイル作成
logopen LOGNAME 0 0

end
```
〇ユーザにPWが設定されていて入力する必要がある場合は、
・;接続オプションのstrconcat COMMAND USERNAMEの下に以下を追記
strconcat COMMAND ' /passwd='
strconcat COMMAND PASSWORD

〇認証方式が鍵ではなくPWの場合は以下を修正してください。
・; 鍵ファイルを指定を削除
・; 接続オプションの以下を削除
strconcat COMMAND ' /keyfile='
strconcat COMMAND KEYFILE
・; 接続オプションの/auth=publickeyを/auth=passwordへ変更
・;接続オプションのstrconcat COMMAND USERNAMEの下に以下を追記
strconcat COMMAND ' /passwd='
strconcat COMMAND PASSWORD

# これで
最初の接続がほんのすこ～～～～～～～～～～～～しだけ楽になった気がします。
部分一致でgit checkoutしたい

## 前置き
gitのブランチ移動は**エディタと連携**したり**Sourcetree**のようなリッチなツールを試してみたりしている
[gitのtab補完機能](https://github.com/git/git/tree/master/contrib/completion)は勿論導入している

だがしかし、時にはコマンドラインでの作業中**他のツールを開くのもめんどくさくて**CLIで`git checkout`したくなる時がある
というかしている

そして仕事で使うgitリポジトリは**featureとかissue番号とかがprefixに含まれてる**ので、
tab補完が活かせるほどブランチ名覚えてないんですよね...
**検索機能だからsearchとかブランチ名に入れた気がする...**みたいなノリで移動したい

## 忙しい人向け
~/.bashrcに下記のbash関数を書く
`gc {ブランチ名}`で過去にcheckoutしたブランチに部分一致で移動できます
例えば`gc dev`でdevelopブランチに移動
一致したブランチが複数ある場合はヒットしたブランチ名を全て表示します
リモートにしか存在しないブランチは部分一致で移動できません(頑張ってカスタマイズすればできると思いますが)
よくわからない人は`bash alias 設定`でググってください

```.bash:.bashrc
checkout_to_found_branch() {
  if [ $# = 1 ] ; then
    COUNT=`git branch | grep -c $1`
    if [ "$COUNT" = "1" ] ; then
      BRANCH=`git branch | grep $1`
      git checkout ${BRANCH##* }
    else
      git branch | grep $1
    fi
  fi
}
gc() {
  git checkout ${@:1} 2>/dev/null || checkout_to_found_branch ${@:1}
}
```

tab補完のアレに追記すればtab補完機能も有効にできます

```bash:/Library/Developer/CommandLineTools/usr/share/git-core/git-completion.bash
# __git_complete git __git_mainとか書いてあるあたりに
__git_complete gc _git_checkout
```

## 解説
うろ覚えのシェルスクリプトです、普段シェル書かないので...**改善案は大歓迎です**

1. bash関数を作成する

```.bash
gc() {
  git checkout ${@:1} 2>/dev/null || checkout_to_found_branch ${@:1}
}
```
自作関数gc **(git checkoutのaliasのつもり)** に渡した引数を`git checkout`に渡します
`${@:1}`はシェルスクリプトにおける可変長引数なので、-bとかのオプションとかをどんな順番で渡しても問題なく動きます
`2>/dev/null`は完全一致でブランチにヒットしなかった場合にエラーがターミナルに出力されないように殺しています

制御演算子`||`を用いて通常の`git checkout`に失敗した場合自作の関数`checkout_to_found_branch ${@:1}`を走らせます
つまり完全一致するブランチを指定したり -b オプションで新規にブランチを作成したりする分には、
純粋な`git checkout`のaliasとして機能します

自作の関数はその名の通り見つかったブランチにcheckout

```.bash
checkout_to_found_branch() {
  if [ $# == 1 ] ; then # オプション引数込みで何かして死んだときに動かないように、引数がブランチ名単一の時だけ動かす
　　　　　　　　　　　　  # こんな保険は必要無いという豪の者は削除してif文のネストを減らそう 
    COUNT=`git branch | grep -c $1` # 部分一致するブランチ名をカウント
    
　　if [ "$COUNT" = "1" ] ; then　　 # カウント結果が一つの場合
      BRANCH=`git branch | grep $1`
      git checkout ${BRANCH##* }   # ヒットしたブランチにcheckout、
　　　　　　　　　　　　　　　　　　   # 現在のブランチと同じブランチに無駄にcheckoutしても死なないように
                                    # 検索結果の先頭に*があった場合は除外
    else
      git branch | grep $1 # カウント結果が複数ある場合一致したブランチ名を表示
    fi
  fi
}
```

意外と**git checkout 部分一致**でググってもこれといった手法が出てこないので需要無いのだろうか...
取り敢えず自分が使う分にはこれで充分です、ブランチ切り替えでそんなに特殊な事しないので
Chromebookでドキュメントを書くために使ってるツール群

# 概要
Chromebookいいよ。

# はじめに
Chromebookで使ってるツールを一度まとめておこうと思う。時間たって忘れたときに見返すために。Chromebookを普及したい気持ちもあるし。

# ハード
## Chromebook
まず、マシンのこと。Chromebook使ってる。
acerのCB3-431ってやつ。スペック低いけど、気に入ってる。
2年前にAmazon.comで3万円くらいで買った。安かった。
スペックはこんな感じ。

- 14 inches
- 1.7kg

![Screenshot 2020-02-19 at 3.11.33 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/9efb38c2-05d8-d1ad-d6dc-2e4b49284c27.png)

# ソフト
## スクリーンショット
### デフォルトのスクリーンショット
スクリーンショットのショートカットはこんな感じ。普通のことができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/8dae5de2-8bda-cfc7-9c63-0e343a17fab4.png)

### Awesome Screenshot
デフォルトのだけやと物足りないので、これ使ってる。
ちょっとした画像編集にも使ってる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/dac13caf-cffe-07e6-ec86-844b2e5681a0.png)

[Awesome Screenshot: Screen Video Recorder - Chrome Web Store](https://chrome.google.com/webstore/detail/awesome-screenshot-screen/nlipoenfbbikpbjkfpfillcgkoblgpmj?hl=en)

立ち上げると、こんなアイコンでてくる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/072db6e0-52bb-ee29-35b0-235a681b585b.png)

気に入ってる機能と理由はこんな感じ。

- トリミング
- 文字追加
- 四角とかで選択して強調
- 見せたくない部分をぼかせる
- 色とか線の太さのデフォルトが好み
- ローカルの画像とかクリップボードの画像も編集できる
- サイトの全画面（スクロールしてったところも）もキャプチャできる
- 動画もキャプチャできる（らしい）

## Copy as Markdown
URLをMarkdownの文法でコピーしてくれるやつ。
似たようなのいろいろあったけど、シンプルやったからこれ使ってる。
`Ctrl+Shift-D`で開いてるページのURLコピーできる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/a0f98c95-a8d1-b78d-e108-d864e0ad27ca.png)
[Copy as Markdown - Chrome ウェブストア](https://chrome.google.com/webstore/detail/copy-as-markdown/fkeaekngjflipcockcnpobkpbbfbhmdn)

## 図を書くツール
Google 図形描画使ってる。Google Drawings。なんで図形描画って名前に訳したんやろ。
必要な機能、だいたい入ってる。
[Google 図形描画 - Chrome ウェブストア](https://chrome.google.com/webstore/detail/google-drawings/mkaakpdehdafacodkgkpghoibnmamcme)

こんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/e7e07b28-4653-bd5b-47b3-69a9f00fe4d2.png)

## エディタ
Chromebook上のLinux環境（Crostini）にインストールされたVisual Studio Codeを使ってる。ちゃんとコピペできる。Linux環境立ち上げなくてもアイコンクリックで起動する。ファイルは、`Linux files`ってところに保存される。Linux環境で少し隔離されてる感じ。それ以外には保存できないけれど、Chromebookのメインの環境からは、ファイルブラウザでアクセスできる。

こんな感じで見える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/9645e1c6-0890-8993-2c72-119ced7b63d4.png)

# ショートカット
Chromebookのショートカットは、`Ctrl+Alt+/`で確認できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/e2ea2487-de35-b456-6db9-f9bd0a52722e.png)

Extensionsのショートカットは、ここらへんを見たら確認できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/ebca2fdd-5a32-2675-187b-4b8aaa43d12c.png)

# できてないこと

- 動画キャプチャ（Awesome Screenshotでできるはず。）
- 動画うめこみ（gifとかyoutubeとか？）

必要になったら試してみたい。

# 改善したいこと

- スマホでとった画像をコピペするところ（Google Photo経由でやってるけど微妙）

# おわりに
Chromebookいいよ。
【jQuery】要素をn個ずつ表示するtoggleボタン【ぬるっと】

##経緯
###なが〜〜いリストをn個ずつ段階的に表示させたかった

クリックすると要素をぬるっと表示する「もっと見る」ボタンは
toggle系メソッドで簡単に出来るのですが、
そのまま使うと表示/非表示の切り替えだけだったのでアレンジ。

※今回は、要素をすべて表示しきったら「もっと見る」ボタンを消すようにしています。

間違っているところがあればご指摘下さい。

##参考にさせていただいた記事
大変参考になりました。神です。

[n件ずつ表示する「もっと見る」ボタンのシンプル実装](https://qiita.com/auko55736370/items/62a3a6b715b9fcb5e3f0)

##デモ
こんな感じです。

https://codepen.io/kotottt/pen/vYOKqxm

##HTML/CSS
最初にいくつか表示した状態からスタートします。

HTMLはこちら
細かいところは、伝家の宝刀『割愛』です。

```html:qiita.html
<body>
  <div class="container">
    <div class="p-tags">
      <a class="p-tag">初期表示</a>
      <a class="p-tag">初期表示</a>
      <a class="p-tag none">ぬるっと後から表示</a>
      <a class="p-tag none">ぬるっと後から表示</a>
      <a class="p-tag none">ぬるっと後から表示</a>
      <a class="p-tag none">ぬるっと後から表示</a>
      <a class="p-tag none">ぬるっと後から表示</a>
      <a class="p-tag none">ぬるっと後から表示</a>
    </div>
    <div class="p-more__tags"><a href="#">もっと見る</a></div>
  </div>
</body>

```

CSSはこちら

```css:style.css

.p-tags{
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
  width: 100%;
  margin:10px 0;
}

.p-tag{
  display: block;
  width: 100%;
  background: #333;
  color: #fff;
  padding: 3px;
  margin-bottom: 3px; 
}

.p-more__tags{
  width: 100%;
  background: #ff69b4;
  text-align: center;
  color: #fff;
  padding: 5px 0;
}

.p-more__tags a{
  display: block;
  color: #fff;
}

.none{
  display:none; /* 見せたくない要素は見えないように */
}
```

##jQuery
```javascript:nurutto.js

var num = 2;//何個ずつ表示させていくか指定

$('.p-more__tags').on('click', function() { 
  const hiddenTags = $('.p-tags a.none');
  //noneクラスがついてる要素を指定

  var hiddenTagsNum = hiddenTags.length; 
  //noneクラスがついてる要素の個数を取得 

    if(num > hiddenTagsNum){
    //noneクラスがついてる要素の個数より最初に指定した表示させる数が多かった時
      num = hiddenTagsNum;
      //表示させる数を残りの要素数に変更
    }

  hiddenTags.slice(0, num).slideToggle();
  //noneクラスがついている要素のうち、最初からnum個目まで表示
  hiddenTags.slice(0, num).removeClass('none');
  //表示させた要素はnoneクラスを削除

  if (num == hiddenTagsNum) {
  //表示させるものがなくなったら、ボタンをフェードアウト
      $('.p-more__tags').fadeOut();
  }
});
```

###解説

順番前後しますが、まずToggle部分から


```nurruto.js
hiddenTags.slice(0, num).slideToggle();
//noneクラスがついている要素のうち、最初からnum個目まで表示

hiddenTags.slice(0, num).removeClass('none');
//表示させた要素はnoneクラスを削除
```

イメージで言うと、工場のベルトコンベアですね。

流れてくる非表示状態の要素を前から2個取って、slideToggleで表示。
取った要素はnoneクラスを外してあげて、ベルトコンベアから降ろす。

そうすると、さっきは３、４番目でベルトコンベアから降ろされなかった要素が前に流れてきて事実上１、２個目に。

これを取って・表示して・降ろしてを要素が無くなるまで繰り返します。

```nurruto.js
if(num > hiddenTagsNum){
//noneクラスがついてる要素の個数より最初に指定した表示させる数が多かった時
  num = hiddenTagsNum;
  //表示させる数を残りの要素数に変更
}
```

この処理を挟んでいるのは、上の処理をして最後に残った非表示の要素が
必ずしも２個とは限らないからですね。(割り切れない可能性がある)

もし余りが１の時、numをそのまま2にすると`.slice(0, num)`がエラーになってしまいます。


##懸念点
`display: none;`を最初に見せたくない要素に指定していると、
グーグル先生いわく要素が隠しコンテンツ的な扱いになるとかならないとか。

SEOへの影響を考えると、`opacity: 0;`から`opacity: 1;`への変化がいいのかなぁ。

知見のある方いらっしゃいましたらコメント下さい。。

##まとめ
ざっくりまとめると、
`display: none;`が指定されているクラスを付けたり外したりしてるだけです。
それならaddClassやremoveClassでいいじゃないか、
と最初は思ったのですが、
それだと、ぬるっと表示できなかったのと、
cssでアニメーションをつけるにしても`display: none;`と相性が悪い。
そしてめんどくさい(本音)

なのでjQuery頼みでtoggle系メソッドを使いました。
インストール、初期設定(Git,GitHub資料2)

#GitHubのアカウント登録

まず、[GitHub](https://github.co.jp)にアクセスします。

その後、GitHubに登録するを選択し、Username、Email、Passwordを入力してサインアップします。進めていくと入力フォームが表示されますが何も入力しなくても大丈夫です。

その後、登録したメールアドレスにメールが届くので、「Verify email address」をクリックしてアカウントが登録されます。

#Gitをインストール

GitHubに登録したら次はパソコンにGitをインストールします。ここでは、Linuxのインストール方法を紹介します。

まずはターミナルを開いて以下のコマンドを入力します。
```$ sudo apt-get install git``` 
インストールされたか確認をします。
以下のコマンドを入力してバージョンが表示されていれば大丈夫です。
```$ dpkg -l git```

次にGitの初期設定を行います。
以下のコマンドを入力して初期設定を行います。
```$ git config --global user.name "[設定したユーザーネーム]"```
```$ git config --global user.email "[設定したメールアドレス]"```

次にエディタをVimに設定します。
コミットログを書くときにUbuntuのデフォルトだとnanoに設定されてしまうのでこれをVimに修正します。
```$ git config --global core.editor 'vim -c "set fenc=utf-8"'```

これで完了です。

#GitHubでSSH接続をする

これを行うと、pushやpullの時に**パスワード入力する手間が省けます**。
必ずやることではないですが、やっておくと便利です。

まずは秘密鍵、公開鍵を作成します。
鍵を入れるフォルダに移動します。
```$ cd ~/.ssh```
次のコマンドで鍵を生成します。
```$ ssh-keygen -t rsa```
何か聞かれたら**エンターを三回押せばid_rsaとid_rsa.pubの２つの鍵が生成**されます。

次に公開鍵をGitHubにアップします。
https://github.com/settings/ssh
から公開鍵の設定ができます。
開いたら画面右上の「New SSH key」を押します。
「title」に公開鍵名(自分の名前とかなんでも)、「key」に公開鍵の中身を入れます。
公開鍵の中身については、以下の操作をします。
```$ cat id_rsa.pub```
これを実行すると公開鍵の中身が出力されるので、マウスで全て選択して、Shift + Ctrl + c でコピー(ターミナルではコピー等のショートカットキーが少し違うので注意)します。コピーが完了したら「key」の欄にCtrl + v で貼り付けし、「Add key」を押すとパスワードを求められるので入力します。

接続が完了したか確かめます。以下のコマンドを入力します。
```$ ssh -T git@github.com```
そして「Hi (account名)! You've successfully authenticated, but GitHub does not provide shell access.」と返ってきたら接続完了です。


###続き
[使い方その1(Git,GitHub資料3)](https://qiita.com/proken/private/c457084b4acbcd7ec34e)
趣味プロジェクトの進め方とドキュメント化について

# 概要
趣味プロジェクトの進め方とそのドキュメント化（Qiitaやブログへの投稿）について考えたことをまとめてみた。

# はじめに
2年前くらいから趣味プロジェクトをQiitaに投稿するようにしている。

理由は、こんな感じ。

- アウトプットしたほうが勉強になる（気がする）
- 人のためになる（かもしれない）
- アピールできる（かもしれない）
- 反応あるとうれしい

デメリットは、こんな感じ。

- 時間かかる
- 公開しちゃいけないことを公開しちゃう可能性がある
- 「いいね」の数が気になりすぎる

効率化のためにも、誰かに訴えられないためにも、目的を見失わないためにも、一度手順を見直してフレームワーク化しようと思う。

# 趣味プロジェクト？
趣味でやってるプロジェクトを勝手にそう呼んでる。大体、ひとりでやってる。
それなりに時間がかかるので、他のことにも役立つことをしがち。仕事と関係するとか、育児・家事に関係するとか。
面白いものできたら、家族とか友人とか同僚に見せて自慢することで、モチベーションをキープしてる。

# 心構え
- うまく行かなかった場合でも、ドキュメントを公開する。
- うまく行く方法だけじゃなくて、つまづいたところも公開する。
- うまくまとまらなくても公開する。
- 他の人がやってるのと同じことでも、環境が違ったら公開する。

誰かが困って検索したときに、役立てることを気にかけたい。
時間とれなかったりして、あまりできてないけど・・・。明日からちゃんとする。

# 進め方案
こんな感じで進める。
時間とれなかったりして、あまりできてないけど・・・。明日からちゃんとする。
順番は、適当に変えて実行する。

1. やりたいことを決める
2. プロジェクトに名前をつける
6. スケジュールを立てる
3. 技術を調査する
4. 作り方を決める
5. 作るものの仕様と評価方法を決める
7. スケジュールを見直す
8. ドキュメントで書くことを決める
9. ノートを取りながら作る
10. ノートを整理して公開する
11. フィードバックもらって更新


# 気をつけること
ここらを気をつけたい。

- 気に入った名前をつけること
- スケジュールをちょいちょい見直すこと
- 大きな変更があるときは、とりあえず、やったことをまとめて公開すること
- キャプチャ画面とか写真とか図を作業しながら残すこと

悩ましいのは、取ったノートの不要になった部分をどうするか。捨てるか、どこかに公開せずに保存しておくか、悩ましい。趣味なら捨ててもいいかも。まじめに保存するのは管理がめんどい。


# 書くこと
ここらへんは書きたいなと思ってる。

### 概要
やったことの概要を書く。できるだけ完結に。

### はじめに
背景とか課題とか書く。

### 環境
再現性キープするために、環境を書く。サボりがち。

### おわりに
結果と感想と次のアクションと他への応用の可能性について書く。

### 更新履歴
サボりがち。更新そのものもサボりがち。

### 参考文献
最近は、最後に書くより、文中に書いちゃったらいいかと思ってる。
最後に書くと文章中の引用箇所とリンクをつなぐのめんどいから。
ただ、文章途中で出てくると、文章の流れが途切れるかもしれなくて、悩ましいところやけども。

# おわりに
そこそこ、頭整理できた。
ソースコードと同じようにドキュメントのアウトプットもレビューしてほしいところやけど、誰にしてもらうのがいいんやろ。悩ましい。

また、書き忘れたり、考え方かわったら、そのうち更新したい。
Elm で FizzBuzz やったよー

# はじめに
[ココ](https://ellie-app.com/85BJkkJrQsta1)をクリック！Ellie だから、怖いサイトじゃないから！

# おわりに
褒めて！やっと、Elm でソレっぽいアプリ作れたの！

# コメントくれた人、ありがとー！
[試してみた](https://ellie-app.com/863DCxTnMP5a1)
本格的なTwitterクローンを作る

#Twitterのクローンアプリを10日間で作った話
今回、Web上で「**CloudDiary**」という交流サイトを作りました。
デモは以下をご覧ください。

**スマホ版**（GIF画像）
![スマホ用](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/471258/3291a06e-0166-9bb5-a87b-7389b03f6521.gif)

**PC版**
<img width="700" alt="PC用" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/471258/0094fa76-7a80-042b-9e9a-6a5ee8154249.png">


#このアプリについて
主な機能はTwitterに似ており、デザインはGoogleが推奨する**マテリアルUI**を採用しました。言語はHTML，CSS，JavaScript，PHP，Ajax（非同期でいいね）です。メインページはSPAで、フッターのナビゲーションで画面遷移しても、ページバックした際は、前のページに戻ります。

#機能一覧
- ログイン/ログアウト
- パスワードの不可逆暗号化（解読不可能な暗号としてDBに登録）
- 文章投稿
- 画像投稿
- いいね（Ajaxで非同期処理）
- コメント機能
- Twitter共有
- フォロー/フォロワー
- アイコン画像
- プロフィール変更

#主な機能の仕組み
データベースは、**usersテーブル**，**postsテーブル**，**likesテーブル**，**repliesテーブル**，**followsテーブル**の5つから成り立っております。例えば何か投稿したら、usersテーブルのpost数が更新され、postsテーブルに詳細カラムが追加されます。このようにデータベースが連携し合っています。

#PHP
基礎土台はこんな感じです。これを応用すれば、ユーザーごとのいいね数，コメント内容等を取り出して表示できます。

```php:index.php
<!--postsテーブルのnameを取り出す-->
<?= foreach($posts as $row): ?>
<?= echo $row['name']; ?>
<?= endforeach; ?>

<!--セッションがあればユーザーの名前を表示-->
<?= if(isset($_SESSION['user'])): ?>
<div class= "user-name"><?php echo $_SESSION['user']['name']; ?></div>
<?= else: ?>
<div class= "user-name">User name</div>
<?= endif; ?>

```

#Ajax
いいねボタンが押された場合、Ajaxで非同期でlikesテーブルに新情報を挿入します。メリットとしては、例えば下にスクロールしている際にいいねボタンを押した場合、**ページがリロードされてトップに戻ることがなくなります**。また、感覚としては瞬時にいいねボタンを押せるため、**UXが向上します**。

#JavaScript
特定のボタンが押されたら、ポップアップ表示を出したり、部品をクリックしたときに波紋を出したりしています。

#おわりに
今回はPHPを使ってこのような交流サイトを作ってみました。
何かアドバイス等あれば教えていただければと思います。
そして、この記事が皆様にお役に立てれば幸いです。
Git,GitHubってなに？(Git,GitHub資料1)

#はじめに
プロ研216はGitHubを使っています。しかし、Git, GitHubとはそもそも何なのかを知らない人もいると思うので、資料にまとめます。
#Git, GitHubとは？

###Git
Gitとはプログラムのソースコードなどの**変更内容を記録・追跡するための分散型バージョン管理システム**です。

Gitでは各ユーザーのワーキングディレクトリに、全履歴を含んだリポジトリ(作業場)の完全な複製が作られるので、ネットワークにアクセスできないなどの理由で中心リポジトリにアクセスできない環境でも、履歴の調査や変更の記録といったほとんどの作業を行うことができます。

例えば、プログラミングをしていると日々ファイルの中身は変わっていきます。この変遷の履歴を管理し、必要に応じて前のものに戻したり、途中で枝分かれして別の変更を加えたりするためのシステムです。

かんたんに言うと、オフラインでもプログラムの編集などができ、その変更履歴も管理できるシステムです。

###GitHub
GitHubとは、この**Gitの仕組みを利用して、世界中の人たちがプログラムコードやデザインデータなどを保存できるウェブサービス**です。

GitHubは様々なプロジェクトのためにGitのリポジトリをホスティングできるサービスです。Gitは基本的にコマンドラインツールですが、
GitHubはWeb上で扱うことができます。
#なぜGitHubを使うのか？

GitHubにはたくさんの便利な機能があります。プロジェクトのバグ管理に使えるIssuesや、コードレビューを効率化できるPull Requestなどの**チーム開発に役立つ機能がWeb上から使える**ようになります。
その他にも、チーム開発で一番大変なコード統合をGitの機能を使うことによって自動的にしてくれるので、開発効率が上がります。

コードレビューでは、指摘と対象のコードがひと目で分かるようになり、バグ修正や機能追加がどの時点のバージョンで実装されたのかも一目瞭然になります。

要するにチーム開発やコード管理などにおいて便利なので入れたほうがいいよ、ということです。
#P.S.

Git, GitHubは使えば使うほどわかっていくと思うので、今はよくわからなくても全然大丈夫です。
たくさんコードを書いて使っていきましょう。
#予備知識

これから記事を読み進める時に必要な情報を書いておきます。
分からないときはここを見ましょう。

###SSH
SSH(secure shell)とはネットワークを経由してマシンを遠隔操作する仕組みのことで、通信が暗号化されているのが特徴的です。
主にクライアント(ローカル)からサーバー(リモート)に接続する時に使われます。

仕組みを見ていく上で重要になるのが秘密鍵と公開鍵です。
まずはクライアントのマシンで秘密鍵と公開鍵を作り公開鍵をサーバーに渡します。サーバー側はその公開鍵を使ってユーザーを特定し紐付けを行っていきます。
ちなみに、秘密鍵は自分で管理して必ず見せてはいけません。

SSH接続を行うことによって**安全にサーバーへ接続し、操作する**ことができます。
###ブランチ
ブランチとは、**1つのプロジェクトから分岐させることにより、プロジェクト本体に影響を与えずに開発を行える機能**のことを言います。
イメージとしてはパラレルワールドを作成して、のちに元の世界に収束させることもできる、という感じです。
リポジトリを作るとmasterというブランチが作成されます。
個人開発でも使うことはありますが、**チーム開発ではほぼ確実に使う**と思うので知っておきましょう。
###リポジトリ
リポジトリ(repository)は**保管場所のようなもの**で、中身はドキュメントファイルだったり、設定ファイルだったり、プログラムそのものだったり、いろいろです。
リポジトリは以下の2種類があります。
####リモートリポジトリ
リモートリポジトリはパブリックな場所でみんなで共有するものです。
これ自体は樹木に例えられることが多く(実際にツリー構造をしている)、masterと呼ばれる幹に安定したコードを置いておき、そこからブランチを生やしていきます。
####ローカルリポジトリ
ローカルリポジトリはプライベートな場所で、ユーザ一人ひとりが利用するために自分の手元のマシン上に管理するリポジトリのことです。
ローカルリポジトリで編集した内容をリモートリポジトリにアップロードすることができます。

##続き
[インストール、初期設定(Git, GitHub資料2)](https://qiita.com/proken/private/fc051e414f62d4fbb600)
「スマートスピーカーを遊びたおす会 vol.9」に参加してきた

# はじめに
[スマートスピーカーを遊びたおす会 vol.9](https://kotodama.connpass.com/event/163156/)の内容についてまとめます。今回はコロナウイルスの流行を考慮して、オンラインでの開催となりました。

# 湊川さん「マンガでわかるLINE Clova開発入門！」
[わかばちゃんと学ぶシリーズ](https://webdesign-manga.com/books/)の方の登壇でした。実際のマンガは[ここのTECH PLAYのサイト](https://techplay.jp/column/354)で公開されてます。基本はこのマンガの内容に即したセッションだったので、リンク先のマンガを読んでもらう方がいいと思います。かなりわかりやすいです。
こういった開発にはサーバーを用意する必要があるのですが、サーバーレス（FaaS）を用いればアプリケーションを書くことだけで開発できてしまうのが素晴らしいですね。ここでは[Azure Functions](https://azure.microsoft.com/ja-jp/services/functions/)が紹介されました。

一応わたしも[入門記事](https://qiita.com/ufoo68/items/67e90f46aae2782932f9)を書いてます（しょうもない宣伝ですが）。まあ、これ見るよりマンガを見てもらう方が１００億倍いいです。

# もっちーさん「好きなもの×VUI」
[デニーズ](https://www.dennys.jp/)とスマホアプリとVUIを組み合わせたものを作った、という内容でした。
作ったものとしては、デニーズで食べたものをスマホアプリを介して記録してスマートスピーカーからオススメのメニューを紹介するという内容のスキルのようです。
スマホアプリ側では[AirTable](https://airtable.com/)というクラウドのデータベースを使用し、スマートスピーカー側ではスキルの開発に[Voiceflow](https://www.voiceflow.com/)を使用していました。内容の一部は[ここの記事](https://qiita.com/Motchy_1204/items/21c24a05280b05e0fac8)で公開されているようです。

Voiceflowを用いればコードを書くことなくスキルの開発ができるのがいいです！難点としてはこのVoiceflowはUIの更新の頻度が高く、ググって出てくる記事とUIが違ったりして、参考文献を探すのが難しいという点だそうです。

# 小城さん「スマスピを怠惰に使うスマスピ」
このセッションでは、スマートスピーカーの課題として、質問の意図を解釈してくれない、スマート家電をうまくコントロールできないといったことを解消するスキルを開発したという内容でした。
その課題の解決方法として、**スマートスピーカーに適切な指示を出すスマートスピーカー**を開発したそうです。

指示機（スマートスピーカーに指令送るVUI）はスマホアプリとして、開発環境にはAndroidを用いて行ったようです。VUIアプリの開発にはアプリを呼び出すためのウェイクとインテントの理解が必要になりますが、今回は[pocketsphinx](https://github.com/cmusphinx/pocketsphinx)というライブラリを用いて音声認識を行い、[Daialogflow](https://dialogflow.com/)を用いて自然言語処理を行って、合成音声にはAndroidの標準のAPIを用いて行ったそうです。

Androidでもライブラリを駆使すれば機械学習の技術がなくてもVUIの開発ができそうですね！

# さいごに
最近VUIの開発（特にClova）に飽きがちだったのですが、今回の話（特に最後のセッション）を聞いてまだまだスマートスピーカーの開発には可能性があるなと感じました。
RSpecを導入した時、詰まったこと(NameError:   uninitialized constant FactoryBot)

#エラー内容
Rspecを使ったテストを実行する際、以下のようなエラーが発生。

```
An error occurred while loading ./spec/models/board_spec.rb.
Failure/Error: config.include FactoryBot::Syntax::Methods

NameError:
  uninitialized constant FactoryBot
```


#行ったこと
参考
http://yurafuca.hatenablog.com/entry/2018/06/28/190842
https://qiita.com/Sa2Knight/items/90d32c9b8493d6bf94b3
・gemにrspec-railsを導入済み
・rspecの初期ファイルを作成済み

#エラー原因
spec/rails_helper.rbの一番最初の行にいきなり`config.include FactoryBot::Syntax::Methods`を記入してしまった。
下記が正しい書き方。

```
RSpec.configure do |config|
  # 中略
  config.include FactoryBot::Syntax::Methods
end
```
OAuth 2.0 認可コードグラント+PKCE 概要

パブリッククライアント(特にネイティブアプリ)向けグラントタイプとして推奨されているグラントタイプの認可コードグラント+PKCEについて説明する。PKCEは、「Proof Key for Code Exchange」の略でピクシーと読む。

## OAuth2.0の概要とその必要性について
「[OAuth 2.0 認可コードグラント概要](https://qiita.com/KWS68810828/items/f5282d1056f8582d31ad)」を参照のこと。

## OAuth2.0のロールと関係性
![OAuth2_関係.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/d73bb52b-99a6-50d3-d392-2811c610bcd0.png)

|ロール  |説明  |
|---|---|
|リソースオーナー  |サービスで管理しているリソースの所有者。3rdパーティアプリにアクセス権を委譲して、リソースにアクセスする。  |
|クライアント  |リソースサーバーを利用するアプリケーション。ユーザーによって委譲されたアクセス権の範囲で、リソースにアクセスする。  |
|リソースサーバー |データや機能を提供するサービス。リソースオーナーのリソースを管理し、リソースオーナーが許可したアクセスのみを受け入れる。アクセス権の確認には、アクセストークンを利用する。|
|認可サーバー  |以下の機能を持つサーバー。<br>・リソースオーナーを認証(リソースオーナーであることを確認)する。<br/>・クライアントのリソースへのアクセスについて、リソースオーナーの同意を得る。<br>・アクセストークンを発行する。|

## 認可コードグラント+PKCE

認可コードグラント+PKCEとは、認可コードグラントのリクエストに、検証パラメータを追加し、認可コード横取り攻撃を防ぐ手法である。

### 認可コード横取り攻撃

認可コード横取り攻撃とは、リソースオーナーが所持するデバイスが以下の条件を満たす場合、
1. デバイスには、3rdパーティアプリ(クライアント)と悪意あるアプリがインストールされている。
2. 悪意あるアプリは、クライアントと同じカスタムスキームが設定されている。
3. 悪意あるアプリは、クライアントのクライアントIDを知っている。
悪意あるアプリによって、認可サーバーが発行した認可コードを奪い、その認可コードを使って、アクセストークンを取得されてしまうことを指す。

#### 認可コード横取り攻撃シーケンス
![OAuth2_ACG+PKCE_Bad.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/5fac700f-1d9e-2459-5659-31c00ce17b4c.png)

### 認可コードグラント+PKCE パラメータ
認可コードグラント+PKCEでは、以下の検証用パラメータを認可コードグラントのリクエストに追加する。

| パラメータ            | 説明                                                         |
| --------------------- | ------------------------------------------------------------ |
| code_verifier         | 長さが４３文字、最大１２８文字までの間の[A-Z]/[a-z]/[0-9]/"-"/"."/"_"/"~"からなるランダムな文字列。 |
| code_challenge        | code_verifierに対して、code_challenge_methodの計算を施して算出された値 |
| code_challenge_method | plainまたは、S256。基本はS256を利用する。<br>plain:code_challenge=code_verifier<br>S256:code_challenge=BASE64_URL_ENCODE(SHA256(ASCII(code_verifier))) |

### 認可コードグランド+PKCE シーケンス

![OAuth2_ACG+PKCE.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/69b9dde5-9e0c-5f6d-a3d2-af740c897040.png)

上記のようにリクエスト送付元を`code_verifier`パラメータから検証することで、悪意あるアプリによる認可コードの横取りを防ぐことができる。

## 参考書籍
* [雰囲気で使わずきちんと理解する！整理してOAuth2.0を使うためのチュートリアルガイド](https://www.amazon.co.jp/%E9%9B%B0%E5%9B%B2%E6%B0%97%E3%81%A7%E4%BD%BF%E3%82%8F%E3%81%9A%E3%81%8D%E3%81%A1%E3%82%93%E3%81%A8%E7%90%86%E8%A7%A3%E3%81%99%E3%82%8B%EF%BC%81%E6%95%B4%E7%90%86%E3%81%97%E3%81%A6OAuth2-0%E3%82%92%E4%BD%BF%E3%81%86%E3%81%9F%E3%82%81%E3%81%AE%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB%E3%82%AC%E3%82%A4%E3%83%89-%E6%8A%80%E8%A1%93%E3%81%AE%E6%B3%89%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA%EF%BC%88NextPublishing%EF%BC%89-Auth%E5%B1%8B-ebook/dp/B07XT8H2YG)
shopify theme kitでよく使うコマンド

shopify theme kitでよく使うコマンドについて記載


```

#configファイルを設定する
$theme configure --password=[your-api-password] --store=[your-store.myshopify.com] --themeid=[your-theme-id]

#テーマIDの一覧を取得
$theme get --list -p=[your-api-password] -s=[your-store.com]

#テーマをダウンロード（テーマIDを指定）
$theme get -p=[your-api-password] -s=[your-store.com] -t=[your-theme-id]

#デプロイ
$theme deploy

#デプロイ（指定ファイルのみ）
$theme deploy [filepath]

#修正ファイルを随時アップ
$theme watch

#ブラウザでプレビューを確認する
$theme open

#ブラウザでプレビューを確認する
$theme open

#コマンドを特定の環境で実行したい場合の引数（configに複数環境記載の場合）
$ 〜　--env=production

```


以上


参考

https://shopify.github.io/themekit/
Qiita記事のタイトルを変更したら、OGPも更新しよう



[QiitaのOGPイメージが新しくなってから、早くも2ヶ月が経過しました](https://blog.qiita.com/qiita-article-ogp-renewal/)。筆者はQiita公式をフォローしているので、よくうん百いいねの記事がTLに飛んでくるのですが、最近になって「ん？」という現象を発見しました。
こちらの投稿をご覧ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411269/fdf3a9fc-30a4-6e25-ed45-492d22d2f911.png)
ツイートとOGPでタイトルは同じですね。

この記事は最初「__【Qiita】タイトル変更してもTwitterで出るOGPが変わらない__」というタイトルで投稿しました。
「__Qiita記事のタイトルを変更したら、OGPも更新しよう__」というタイトルに変更してみます。

## 再投稿したら変わるんじゃないの？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411269/b2454795-d2b7-d290-27f2-b937a0c9d895.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411269/6e67e80b-3464-c98b-5691-ef36f2523c5e.png)
Twitterに再投稿してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411269/f5f228e8-861b-7579-25d9-fa69d6268b06.png)
ずれてますね。

困ったので「 _ogp タイトル変更_ 」で検索をかけてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411269/872311ed-dbde-3398-734b-e0356437b904.png)
https://twitter.com/bosyu_me/status/1189368855208038400

出た。というわけで、https://cards-dev.twitter.com/validator に行ってみましょう。




![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411269/d7c62bb0-c8b6-ee10-eede-d6e42faf7931.png)
打った。
反映されるまで少しかかるので待ちます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411269/fbcf9e7a-b98f-8529-c8e4-84769b4856f8.png)


ちょっと待つと、OGPが更新されます。やったね。


# まとめ

__タイトルを変更したらOGPを更新しよう。__

# 蛇足


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411269/de706fa1-092e-033c-5545-067db6fd3621.png)
OGP画像が中華フォントになってるのは直してほしい。
参照: [__Qiita記事の新しいOGP画像が中華フォントな件__](https://qiita.com/FlameArche/items/61ffeb8350725e7f95ce)
2/19 第一回テスト対策ノート<あやふや>

あやふやな部分。

#HTML分野
・インライン要素
　→テキストデータや画像、a要素(<a></a>)など横並びでマークアップするテキストレベルの要素(＝テキストデータとして扱われる)
・ブロック要素
　→見出し、段落、箇条書き、表組みなど文書構造の骨組みを構成する要素
　※ブロックレベルの要素はマークアップすると自動改行される
→概念的にはブロック要素は入れ物、インライン要素は中身
　つまり…ブロック要素の中にインライン要素/ブロック要素(入れ物に中身)は入るが、
　インライン要素の中にブロック要素(中身に入れ物)は入れられない！
　☆もっとも手軽な見分け方→要素を記述した時に自動改行するかどうかで判断
section要素について
　→開始タグと終了タグで囲まれた範囲を一つのまとまりと指定する要素
リンクの種類
　①ページ内リンクはid属性(要素に固有の識別名を指定する属性)を使って設定する
　ex:)```<section id=”aaa”>…<a href=”#aaa”></section>```
　　 →1. section要素にid属性を使って固有の識別名”aaa”を与える
　　 →2. a要素のhref属性に「#+リンク先id」を記述
　②内部リンクはhref属性内に目的ファイルまでのパスを記述する
　ex:)```<a href=”../profile.html”>aaa</a>```
 　　 →同じタブ内でリンク先ファイルを開く
　③別のサーバにある外部Webページ(外部リンク)
　ex:)```<a href=”http://www.yahoo.co.jp ”target=”_brank”>yahoo!トップページへ</a>```
 　　 →新規ウィンドウ/タブでリンク先ファイルを開く(target=”_brank”)

#CSS分野
・text-align:centerとmargin:0 autoの違い
　text...は文字や画像をBoxに対して中央揃えにすること
　marginは横幅のあるブロック要素が親Boxに対して中央揃えにする
・ボーダーまたは背景色が設定された要素に対して設定するもの
　padding(見やすくするため)
・marginとpaddingの認識について

・ショートハンドとは：関連プロパティはプロパティ毎に一括指定することができる
　ex::)
　　①margin/paddingプロパティ
　　　margin: A;：上下左右すべてAの値だけ余白を指定
　　　margin: AB;：上下(A)左右(B)の値だけ余白を指定
　　　margin: ABC;：上(A)左右(B)下(C)だけ余白を指定
　　　margin: ABCD;：上(A)下(B)左(C)右(D)だけ余白を指定
　　②borderプロパティ
　　　border-width: 1px;
　　　borderstyle: solod;-
　　　border-color: #fff;
　　　→**border: 1px solid #fff;(順不同)**
　　③backgroundプロパティ
　　　background-image:url(original/header_herbkitchen.jpg);
　　　background-position: left top;
　　　background-repeat: no-repeat;
　　　→background:url(../original/header_herbkitchen.jpg) left top no-repeat;(順不同)
リテラルに親を殺されたPython解説

@Raclett3さんの
[文字列と数値と真理値のリテラルに親を殺されたPythonプログラミング](https://qiita.com/Raclett3/items/9e0fec83800e62dd631d)
がめっちゃ面白いな:raised_hands:と思うと同時に、何が起きているのか理解できなかったので調べてみました。
解説というか、自分のお勉強です。

おもに「小さな数値」の項目をつらつら書きます。
間違ってたらマサカリ投げてください。

# 0
```python
int()  # 0
```
これは@Raclett3さんの[リンク](https://docs.python.org/ja/3/library/functions.html#int)にもある通りです。

> or return 0 if no arguments are given

引数が指定されていない場合は0を返す、そうです。
これは簡単。

# 1
```python
len([()])  # 1
```
これはリストがその要素にタプルを1つ持っているので、lenで長さ1が返されるだけですね。
つまり下のような例だと何が起きているか分かりやすいでしょうか。

```python
len([(), ()])  # 2
len([1, 2, 3])  # 3
```

# 2
```python
len(((),()))  # 2
```
いやらしく全てタプルになっていますが、やっていることは1の外側のリストがタプルになっているだけです。
ちょっと空白を入れてやると分かりやすい。

```python
len( ( () , () ) )  # 2
len( ( () , () , () ) )  # 3
```

# 3
```python
len(hex(not()))  # 3
```
not()は元記事の@Raclett3さんの解説がめっちゃ分かりやすいのでそちらを。
少しずつ変形してみます。

```python
len(hex(not()))

# ↓ not() == True

len(hex(True))

# ↓ True == 1

len(hex(1))

# ↓ hex()は引数を16進数の　文字列　に変換する。

len('0x1')  # つまり3!!
```

# 4
```python
len(str(not()))  # 4
```
これは3が理解できると簡単ですね！
4文字のTrueをstr型にし、lenで長さを取得しています。

```python
len(str(not()))

# ↓ not() == True

len(str(True))

# ↓ Trueが文字列に変換される。

len('True')  # 4!!
```

# 5
```python
len(str(not[()]))  # 5
```
これは4のFalse版。

```python
len(str(not[()]))

# ↓ not[()] == False

len(str(False))

# ↓ Falseが文字列に変換される。

len('False')  # 5
```

# 6
```python
len(str(complex(not(),int())))  # 6
```
この辺から頭痛くなりますね:scream_cat:
complexは第一引数に実部、第二引数に虚部を取り、complex型の複素数を返します。
こちらも細かく見ていった方が分かりやすいと思います。

```python
len(str(complex(not(),int())))

# ↓ not()はTrue、int()は0

len(str(complex(True, 0)))

# ↓ Trueは1

len(str(complex(1, 0)))

# ↓ 実部1、虚部1のcomplex型の複素数、(1+0j)が返る。

len(str((1+0j)))  # len( str( (1+0j) ) )

# ↓ (1+0j)をstr型にする。

len('(1+0j)')  # ()を含んだ6文字なので6が返る。
```

# 7
```python
len(str(bytes(len(((),)))))  # 7
```
(((( ；ﾟДﾟ)))
一瞬震えますが、よく見ると1をbytes型にしているだけ。
bytes型の文字列変換については、@Raclett3さんの記事にある通り[こちら](https://docs.python.org/3/library/stdtypes.html#str)にサンプルコードもあります。

```python
len(str(bytes(len(((),)))))  # bytesの中身は、len( ( (), ) )

# ↓ つまり要素数1のタプルの長さがbytesの引数になる。

len(str(bytes(1)))

# ↓ 1をbytes型にする。

len(str(b'\\x00')  # \\ はエスケープシーケンスなので1文字。

# ↓ b'\\x00'を文字列にしてその長さを得る。

len("b'\\x00'")  # 7!
```

# 8
```python
len(str(((),())))  # 8
```
後半戦は()が多く見た目が複雑ですね...

```python
len(str(((),())))  # len( str( ((),()) ) )

# ↓ 「空のタプルを2つ要素に持つタプル」がstr()の引数。

len('((),())')  # 要素数2のタプルがそのまま文字列に変換され、文字列の長さ8が返る。
```

# 9
```python
len(str(([int()],[])))  # 9
len(str(((int()),())))  # 全部タプルにしたらやばい見辛い
```
ようやく最後です。
これは8と同じですね:honeybee:

```python
len(str(([int()],[])))

# ↓ int() == 0

len(str(([0],[])))

# ↓ 8と同じくstrの引数は、([0],[])なので...

len('([0],[])')  # 9!!!
```

めちゃくちゃ長くなりましたが需要あったのだろうか。
こういう基本的なやつは普段ドキュメントを読んだりすることないので勉強するいい機会になりました。
@Raclett3さんに感謝。
整形済みJSON文字列を１行JSONに変換（圧縮）する

JSON文字列を１行JSONに変換（圧縮）する際に方法を確認したのでメモ。

## 方法

以下の２通りの方法を紹介する。

- Python
- jqコマンド

ファイルに記載された以下のようなJSON文字列を前提にする。

```file.py
{
    "Records": [
        {
            "database": {
                "NewImage": {
                    "eventId": {
                        "S": "a4207f7a-5f04-471b-a338-1175182eaa6d"
                    },
                    "isCompleted": {
                        "BOOL": True
                    }
                },
                "OldImage": {
                    "eventId": {
                        "S": "a4207f7a-5f04-471b-a338-1175182eaa6d"
                    },
                    "isCompleted": {
                        "BOOL": False
                    }
                }
            }
        }
    ]
}
```

### 方法その１：Pythonを利用

```shell
$ python
>>> import json
>>> f = open("file.json")
>>> json.dumps(f.read()).replace("\\n","").replace("\\","").replace("    ", "")
'"{"Records": [{"database": {"NewImage": {"eventId": {"S": "a4207f7a-5f04-471b-a338-1175182eaa6d"},"isCompleted": {"BOOL": True}},"OldImage": {"eventId": {"S": "a4207f7a-5f04-471b-a338-1175182eaa6d"},"isCompleted": {"BOOL": False}}}}]}"'
```

`.replace("    ", "")`ではインデント（スペース` `4つ）を置換して削除している。JSON文字列中で異なる文字列をインデントとしている場合は本部分の置換元を変更すれば良い。

### 方法その２：jqコマンドを利用

基本的には`cat <ファイル名> | jq -c`で対処可能である。

しかし、jqは`True`や`False`をbooleanとして扱えないため、今回のfile.jsonに対してそのまま実行しようとすると下記のようなエラーとなる。

```shell
$ cat file.json | jq -c
parse error: Invalid numeric literal at line 11, column 0
```

よって、`True`を`true`へ、`False`を`false`へ事前に変更する必要がある。事前にfile.jsonを手直しした場合は以下のように実行可能である。

```shell
$ cat file.json | jq -c
{"Records":[{"database":{"NewImage":{"eventId":{"S":"a4207f7a-5f04-471b-a338-1175182eaa6d"},"isCompleted":{"BOOL":true}},"OldImage":{"eventId":{"S":"a4207f7a-5f04-471b-a338-1175182eaa6d"},"isCompleted":{"BOOL":false}}}}]}
```

以上
nodemailer envelope設定サンプル

#テスト環境
- node.js v12
- nodemailer v6.3


[公式ドキュメント](https://nodemailer.com/smtp/envelope/)

#サンプルコード
```send-mail.js
var Mailer = require('nodemailer')

//
// ローカルsmtpサーバ
//
const smtp = Mailer.createTransport({
  host: 'localhost',
  port: 25
})

const message = {
// メッセージヘッダとかの設定
// ＝＞　メール受け取る側から見える情報
  from: 'from@example.com',
  to: ['to@example.com'],
  cc: ['cc@example.com'],
  bcc: ['bcc@example.com'],
  subject: 'HELLO! nodemailer!!',
  text: 'this is a test mail',
  html: '<p>this is a test mail</p>',

// envelope: SMTPサーバー用の設定
//  FROM: (バウンスメールが届くアドレス)
//    envelope.from
//  と
//  RCPT TO: (実際に送信する宛先)
//    envelope.to, envelope.cc, envelope.bcc

// envelopeは "省略可能"
// 省略した場合は以下のように自動付与されると思っていい
  envelope: {
    from: 'from@example.com',
    to: ['to@example.com'],// RCPT TO: に突っ込まれる
    cc: ['cc@example.com'],// RCPT TO: に突っ込まれる
    bcc: ['bcc@example.com'],// RCPT TO: に突っ込まれる
  }
}

smtp.sendMail(message)
```

## メッセージヘッダのfromとバウンスメールの受け取りアドレスを変えたい場合
例えば、MAILER-DAEMONが返ってきてしまった該当メールアドレスは無効化したいので、バウンスメール用のメールアドレスを用意して監視したい時などが利用場面です。

この場合は、envelopeを明示的に設定する必要あります。

```envelopeを明示的に設定する場合、message.to, message.cc, message.bccに宛先を書くだけでは、メールは届かないので注意。
envelope.to, envelope.cc, envelope.bcc に宛先を書く必要がある。
```

```.js
const message = {
  from: 'from@example.com',
  to: ['to@example.com'],
  cc: ['cc@example.com'],
  bcc: ['bcc@example.com'],
  subject: 'HELLO! nodemailer!!',
  text: 'bounce-mails are sent to for-bounce@example.com ',
  html: '<p>bounce-mails are sent to for-bounce@example.com</p>',
  envelope: {
    from: 'for-bounce@example.com',
    to: ['to@example.com'],
    cc: ['cc@example.com'],
    bcc: ['bcc@example.com'],
  }
}
```
[Swift5.1] Dynamic Member Lookup（KeyPath）によるProxyパターンの実装（プロパティのみ）

### じょ
某Twitter上で「CGRectはCGFloatが面倒くさい」という旨の話が流れてきたので、いろいろ考えていたらピコーンときたので。

#### Proxyパターン
GoFのあれです。今回はインターフェースを変えてしまうパターンの奴です。

#### Dynamic Member Lookup（KeyPath）
Dynamic Member LookupはSwift4.2で実装されましたが、この時はKeyをStringでとるようになっていたため、Typoをしてもコンパイル時には検出できないという致命的な欠陥がありました。
しかし、Swift5.1でKeyPathをKeyにとる方式が実装されこれが克服されました。

### やり方
目的はCGFloat型のプロパティをFloat型で扱えるようにすることです。
#### CGPoint
CGRectにはCGPoint型のプロパティもありますので、まずこちらを実装しちゃいます。

```swift
@dynamicMemberLookup
struct Point {
    var cgPoint: CGPoint
    
    subscript(dynamicMember keyPath: WritableKeyPath<CGPoint, CGFloat>) -> Float {
        get { Float(cgPoint[keyPath: keyPath]) }
        set { cgPoint[keyPath: keyPath] = CGFloat(newValue) }
    }
}
```

以上です。
CGPointにはプロパティが2つしかないので直接コンピューテッドプロパティとしてもいいのですが、Dynamic Member Lookup（KeyPath）を使った型変換Proxyが簡単にできるという例です。

ポイントはKeyPath（ここではWritableKeyPath）の型パラメータを明示してあげるというところです。
こうすることでこのsubscriptはCGPoint型のプロパティのうちCGFloatを返すKeyPath以外を受け付けなくなります。

これでCGPoint型であればFloatへのキャスト（あるいはFloatをCGFloatへ）する必要があったものが、そのままFloatとして利用可能になります。

```swift
var point = Point(cgPoint: .zero)
print(point.x)
// prints 0.0

point.x = Float(10)  // 例のためFloatを明示
print(point.cgPoint.x)
// prints 10.0
```

#### CGSize
CGPointと同じです！


```swift
@dynamicMemberLookup
struct Size {
    var cgSize: CGSize
    
    subscript(dynamicMember keyPath: WritableKeyPath<CGSize, CGFloat>) -> Float {
        get { Float(cgSize[keyPath: keyPath]) }
        set { cgSize[keyPath: keyPath] = CGFloat(newValue) }
    }
}
```

#### CGRect

最後にCGRectです。
これも同じといえば同じです。


```swift
@dynamicMemberLookup
struct Rect {
    var cgRect: CGRect
    
    subscript(dynamicMember keyPath: WritableKeyPath<CGRect, CGFloat>) -> Float {
        get { Float(cgRect[keyPath: keyPath]) }
        set { cgRect[keyPath: keyPath] = CGFloat(newValue) }
    }
    
    subscript(dynamicMember keyPath: WritableKeyPath<CGRect, CGPoint>) -> Point {
        get { Point(cgPoint: cgRect[keyPath: keyPath]) }
        set { cgRect[keyPath: keyPath] = newValue.cgPoint }
    }

    subscript(dynamicMember keyPath: WritableKeyPath<CGRect, CGSize>) -> Size {
        get { Size(cgSize: cgRect[keyPath: keyPath]) }
        set { cgRect[keyPath: keyPath] = newValue.cgSize }
    }
}
```

こちらはCGPointをPoint、CGSizeをSizeとして扱えるようにするインターフェイスの書き換えを追加しています。

多段のドットアクセスも可能です。

```swift
var rect = Rect(cgRect: CGRect(x: 0, y: 0, width: 100, height: 23))
rect.size.width = Float(120)  // 例のためFloatを明示
print(rect.cgRect)
// prints (0.0, 0.0, 120.0, 23.0)
```

### 問題点

####変なエラー
readonlyなプロパティに代入を行おうとすると、ちょっと意味不明なエラーが出てしまいます。

```swift

var rect = Rect(cgRect: CGRect(x: 0, y: 0, width: 100, height: 23))

rect.height = 30  // ambiguous reference to member 'height'
```
これは「mutableなキーパスheightを探したけどよく分からない」的な意味合いだと思うのだが、突然これを出されると「heightプロパティ以外の何？？　ほかにheightってあったっけ？？」となること請け合いです。

#### メソッドどこ行った？
メソッドは頑張って書くしかないです。

## まとめ
「CGRectのCGFloatをFloatにしたRectを作る」と見たときは一瞬簡単だと思ったんですけど、プロパティの数が無駄に多いことが簡単さレベルを大幅に下げてることに気づいた。
これがDynamic Member Lookup（KeyPath）でいとも簡単に解決して、これはほかでも使えるのではないだろうか、と感じこの記事を書いた次第です。
僕は思いついてないのですが、これを見た人がこれをヒントにすごい使い方を編み出してくれることを期待しています。
コミュニケーションぐらい円滑にしたい初心者のためのgithubアサインのタイミング

##PRできたばかり。作業中でまだ本格的なものでは無い場合
### 作業者にアサイン
質問は相手にメンションするけれど、アサインは作業者のまま（質疑していても作業は自分で継続しているはず。大抵は相手を待って作業が止まったりしないので。仕様がまったく違うとか大きな場合は例外です。）

##一回作業者の中で完了。ちゃんとレビューを求めたい。
### レビュアーにアサイン
レビュアーがレビューした後、作業者にアサイン
作業者が修正した後、レビュアーにアサイン（この動きがキャッチボール）
「会話」という単位ではなくて、作業の主体がどちらかか、というイメージ。レビューはレビュアーと、レビュイーが交互に作業するので、キャッチボールになります。
Flutter Daemonツールを利用したアプリ操作方法

# はじめに

[`Flutter Daemon`](https://github.com/flutter/flutter/blob/master/packages/flutter_tools/doc/daemon.md)という機能 (ツール) がありましたので、紹介したいと思います。

# Flutter Daemonとは？

Flutter は通常 Flutter SDK で提供されるコマンド群でビルドや各デバイスへのインストールなどが行われます。

一番よく使うのはアプリ実行のために利用する`$ flutter run`コマンドですね。この flutter コマンドからターゲットデバイスの Android や iOS などに対して、adb や Xcodeのプロトコルで繋がった通信経路の中で Flutter Engine と Host PC の Flutter SDK との間でやり取りを行っています (ここのプロトコルも後々調べたい) 。

Flutter SDK は外部から操作可能なツール (I/F) を`Flutter Daemon`としてユーザ (開発者) に提供しています。`Flutter Daemon`を利用すると、ユーザの操作でホットリロードやアプリの終了、開始、インストール等が行えます。複数デバイスを同時に操作するときには便利そうです。

VSCodeのFlutterプラグインはこの機能を利用している？

# ソースコード

ソースコードは[packages/flutter_tools/lib/src/commands/daemon.dart](https://github.com/flutter/flutter/blob/master/packages/flutter_tools/lib/src/commands/daemon.dart)です。

# プロトコル

提供される入出力は`stdin/stdout`のみで、フォーマットは`JSON-RPC`です。httpとかは無さそうなので、必要なら自分でブリッジを作る必要がありそうです。

# 使い方

`Flutter Daemon`を立ち上げるには以下のコマンドを実行します。

```shell:
$ flutter daemon
Starting device daemon...
[{"event":"daemon.connected","params":{"version":"0.5.3","pid":4365}}]
```

操作方法は、JSON-RPCをターミナルに直接入力するか、Linux環境であれば`stdin ( /proc/${pid}/fd/0 )`に入力でも出来ます。

まずは`daemon.version`でFlutter Daemonのバージョン情報を取得してみます。
`id`はクライアント側が自由に決められる番号です。サーバー側はクラアントへその`id`を添えてリプライを返してきます。

```shell:
$ [{"method":"daemon.version","id":2}]
[{"id":2,"result":"0.5.3"}]
```

アプリの実行や各種操作するには`appId`が必要なので、認識しているデバイスを取得してみると

```shell:
$ [{"method":"device.getDevices","id":2}]
[{"id":2,"result":[]}]
```

？？？？

何も返してくれません。`appId`が必要なのですが…。

仕方がないので適当な`appId`で試してみます。

```shell:
$ [{"event":"app.start","params":{"appId":"53ee146d-ca2a-4886-ad3a-1291cb52e25c","deviceId":"macOS","directory":"/Users/kurun/workspace/flutter-app","supportsRestart":true,"launchMode":"run"},"id":2}]
[{"id":2,"error":"unexpected response with id: 2","trace":"#0      Daemon._handleRequest (package:flutter_tools/src/commands/daemon.dart:168:11)\n#1      _rootRunUnary
　〜　略
```

うまくいきません。

諦めます。

その他の使い方は[`Flutter Daemon`](https://github.com/flutter/flutter/blob/master/packages/flutter_tools/doc/daemon.md)を参照してください。

## 他の方法

アプリ実行後にそのままデーモンを立ち上げ続ける方法があるので、こちらを利用します。

```shell:
% flutter run --machine
```

この状態からソースコードを変更して、ホットリロードするには以下のように`app.restart`を実行します。
`appId`は上記コマンド実行時のログに表示されている`appId`を指定します。

```shell:
[{"method":"app.restart", "id":2, "params":{"appId":"189f0050-4f0a-4357-b0d8-72653cdbe698", "fullRestart":true}}]
```

ホットリロード出来ました！

参考↓

```shell:上記コマンド実行後のログ
[{"event":"app.progress","params":{"appId":"189f0050-4f0a-4357-b0d8-72653cdbe698","id":"2","progressId":"hot.restart","message":"Performing hot restart..."}}]
[{"event":"app.progress","params":{"appId":"189f0050-4f0a-4357-b0d8-72653cdbe698","id":"3","progressId":null,"message":"Syncing files to device macOS..."}}]
[{"event":"app.progress","params":{"appId":"189f0050-4f0a-4357-b0d8-72653cdbe698","id":"3","progressId":null,"finished":true}}]
[{"event":"app.progress","params":{"appId":"189f0050-4f0a-4357-b0d8-72653cdbe698","id":"2","progressId":"hot.restart","finished":true}}]
Restarted application in 852ms.
[{"id":2,"result":{"code":0,"message":""}}
```
欲しかったデザイン用ツールを見つけたので２つ紹介

最近[product hunt] (https://www.producthunt.com/)でほしかったツールを２つ見つけたので紹介したいと思います。

## Lunacy - Windowsでsketchが開けるフリーソフト

`windows` `sketch` `free`

|  product hunt紹介ページ  |  https://www.producthunt.com/posts/lunacy-designer-5-0  |
| ---- | ---- |
|  website  |  https://icons8.jp/lunacy  |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273096/fe1e152f-7c10-e4a3-acd4-2aa110b4daff.png)

windowでsketchが開けます。*1

Microsoft Storeでインストール可能です。

試してみましたが、かなり軽量です。

## Devsync - ブラウザ上でcssを編集してエディタに反映可能なChrome拡張機能

`chrome extension` `css` `editor`

|  product hunt紹介ページ  |  https://www.producthunt.com/posts/devsync  |
| ---- | ---- |
|  website  |  https://devsync.co/  |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273096/7bd5ff07-73f7-4495-3f3a-17b9eeac5da4.png)

欲しかった（というか作ろうとしてた）Chrome拡張機能です
Developper toolでグラフィカルにCSSを編集でき、その結果がコードに自動で反映されるというものです。

**（注意：まだリリースされていません）**

cssのsoucre-mapが出力されていればあらゆるスタイルシート言語（scssとか）に適用可能だそう。

見た目もおしゃれなのでライセンスの早期予約しました。

**（追記: 2020/02/21）リリース日が延期されるとのメールが届きました。まだ使えないっぽいです。**

現在(2020/02/19)の情報によると、"Pay once"とあるので一回買い切りなのだと思います。

## まとめ

cross platformが謳われる今、
Mac OSじゃなくてもデザイナーになれる未来も遠くないと思います。

*1 これまでなかったというわけでは無いです (Lunacy前バージョンなど)
systemdユニットの ExecStop はsystemctl stopで実行されるわけではない（らしい）

ハマったーーーーーーーーーーー

こちらの記事に助けられました↓
https://chienomi.org/archives/livewithlinux/1811


とりあえず自分用の記録として残しておく。
余力があったらハマった経緯とか諸々まとめていきたい。
【swift】Mapkitに表示されているpinの画像を一律すべて変える

Mapkitのpinの画像をデフォルトのpin画像から、自分で選んだpinの画像に変更をするメモです。

##1.storyboardにMapKitを貼る
storyboardにMapKitを貼ります。

##2.Mapkitとコードを接続し、Mapkitの宣言をする。
weakで今回は名前を「pinChangeMap」にします。

```swift
@IBOutlet weak var pinChangeMap: MKMapView!
```

##3.画像を登録する
左メニューにある「Assets.xassets」にpinの画像にしたい画像をドラッグし登録する。
今回名前は「mark1」にしました。

##3.viewControllerにコードを書く
下記の通りコードを書きます。

```swift

import UIKit
import MapKit

 class ViewController: UIViewController ,MKMapViewDelegate{
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        // MapViewのdelegate通知先を設定
        sentouMap.delegate = self

        //MKPointAnnotationを宣言
        let annotation = MKPointAnnotation()
        // ピン（アノテーション）の緯度経度を指定
        annotation.coordinate = CLLocationCoordinate2DMake(35.681236, 139.767125)
        // アノテーションのタイトルを指定
        annotation.title = "東京駅"
        // アノテーションのサブタイトルを指定
        annotation.subtitle = "Tokyo Station"
        // mapにアノテーションを追加
        self.pinChangeMap.addAnnotation(annotation)
    }
    
    
    @IBOutlet weak var sentouMap: MKMapView!
    
    // mapViewのデリゲート
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        
        // MKPinAnnotationViewを宣言
        let annoView = MKPinAnnotationView()
        // MKPinAnnotationViewのannotationにMKAnnotationのAnnotationを追加
        annoView.annotation = annotation
        // ピンの画像を変更
        annoView.image = UIImage(named: "mark1")
        // 吹き出しを使用
        annoView.canShowCallout = true
        // 吹き出しにinfoボタンを表示
        annoView.rightCalloutAccessoryView = UIButton(type: UIButton.ButtonType.detailDisclosure)
        
        return annoView   
    }
}

```

mapViewのデリゲートメソッドに宣言をするMKPinAnnotationViewで、imageの中に登録をした画像の名前を記載します。

```swift
let annoView = MKPinAnnotationView()
annoView.image = UIImage(named: "mark1")
```

これで選択した画像でPinを作成することができました。


##最後に
これで任意の画像をPinにすることができました。
ただ、上記コードだとMapkitで表示しているPinすべてを一律で変更してしまうため、Pinごとに異なった画像にすることができません。
（mapViewのデリゲートメソッドで画像を変えているため）

pinごとに異なった画像で表示するのは別記事で説明したいと思います。