OmniAICreator/Qiita-1.07M huggingface dataset:
Attentionの復習

# モチベーション
Transformerを学習するにあたりAttentionの知識が必要になったため。

# Attentionの種類
①Sorce-Target型
順序の異なる２つの系列を組み合わせる時に使用する。翻訳など。
入力側（日本語）からKeyとValueを出力側（英語）からQueryを作成する。

②Self-Attention型
1つの系列の特徴を抽出するために使用する。
ある単語の特徴をほかの単語によって特徴づけたい時など。
自分自身からQueryとKey（Q=K)、Valueを作成

# ①Sorce-Target型
翻訳する際にどの単語に注目して翻訳すべきかを判断する。

KeyとValue：翻訳元の特徴をKeyとValueに分けたもの
	Key:着目する単語を決めるために使われるベクトル
	Value：最終的に利用されるベクトル
Query：どのような特徴を持つ単語に着目すべきか決定するベクトル

QueryとKeyの内積をとることでどのデータに着目すべきかを決定する。
算出した重要度はSoftMaxによりSum＝1になるように変換される。

例）日本語を英語に翻訳する場合
Theという単語のQueryと日本語単語のKeyとの内積をとることで、重要度を算出する。
この場合は「ハンバーガー」の重要度が高くなる。
重要度とValueを加算することで、重要度に従った特徴量（ハンバーガーの特徴量）を取り出すことができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/f41e0957-fa2a-546d-c72c-4e038e300d52.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/bbb135ee-a8d1-ef5e-1988-9b8693b01c0a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/5c8eb448-3700-6c39-07d8-c361fde34593.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/cfd84506-59b4-ad7e-4e7b-252e70ca937c.png)


問い合わせ（Query)に最も類似するKeyに対応するValueを取得している
Queryの特徴量とベクトルの方向が同じ特徴量の値が大きくなる。そして、対応するValueを取り出している。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/2d37e0d3-938b-30cd-c866-bdc961e20aec.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/31623d62-01be-9d96-f910-863c9d6ae82b.png)


# ②Self-Attention型
自分自身を特徴づける。
自分自身からQueryとKey（Q=K)、Valueを作成

「嫌い」という単語は「ない」という単語によって意味合いが変わる単語であるため、「ない」によって特徴づけられる必要がある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/e8f28c4c-e00b-72b9-6fc1-882ffa134479.png)


嫌いのQueryと各単語のKeyとの内積->softmaxで重要度を算出
「嫌い」のQueryを各Keyと内積をとると「ない」の重要度が大きくなり「ない」によって特徴づけられるようになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/4276d71d-6380-560d-f1f1-b93dbb56a067.png)


# Multi-Head Attention 
Headごとに着目する点を変えることで偏った観点で着目しないようにする。
次元数が512次元あった時にヘッドの数がh=8であれば各ヘッドが担当する次元数は512/h=64次元となる
各ヘッドでAttentionをすることで、異なる位置の部分空間を処理することになる。
あるヘッドではある観点で着目、別のヘッドでは別の観点で注目という風にしている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/a02b2797-82a1-042a-0e33-91aa3adee07b.png)

各ヘッドで求めた特徴量を最終的に足して最終出力にする。

# 画像の場合
画像のどの特徴に注目するかを決定している
Query（左上の画素は）どこの画素に注目すべきかをKeyと内積-＞Softmaxで重要度を算出しValueにけることでどこに注目すべきかを算出する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/6e726562-9d71-ac6b-2943-79d2cc593c25.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/c7e386dd-7dbd-f746-7693-8370bff1e63b.png)


# 参考
[Attention](https://www.youtube.com/watch?v=g5DSLeJozdw)
趣味で宇宙開発するのに必要な〇〇駆動開発

この記事は趣味で宇宙開発をしている団体「[リーマンサット・プロジェクト](https://www.rymansat.com/)」がお送りする[新春アドベントカレンダー](https://qiita.com/rsp-dgkz/private/a6ff573c07dbe2c6166f)です。
トップバッターを務めます私は人事部に所属していて、この組織で`やっていること`とメンバーが`やりたいこと`をつなげるべく活動をしています。
というわけで、技術的な話しはこの後のメンバーに任せて、私からはこの組織の人について話したいと思います。
ワークライフバランスが唱えられている社会に、特にエンジニアにとっては技術と人と組織との取り組み方を考えるヒントになればと思います。

##「趣味」とは
リーマンサットは確かに人工衛星やローバーをつくっている団体ですが、その大前提に`趣味で`というものがあります。この`趣味`というのは、人によりその解釈が様々です。仕事から解放される時間、休憩、適当に楽しむ時間、勝手な研究、人生の醍醐味、夢、周囲の人々を見渡しても「趣味」の定義にはかなり差があるように感じます。これはリーマンサット内部でも共通していて、私はメンバーと接する中で様々な活動形態を目の当たりにしてきました。
今回はその観測を、`趣味というモチベーションでメンバーがリーマンサット内で如何に宇宙開発をしているか`を、紹介したいと思います。

#TeDD (Teach each other Driven Development)
`教え合いながら開発`。この形態を一番よく見かけます。
宇宙対応するための開発では、どんな技術者でも見かけることのない要件によく出会います。ひとつの分野に特化している技術者でも決まった解を見つけることが難しかったり、それぞれの得意分野を持ち寄って相談することで開発が進んでいきます。
そしてメンバーには学生も多くいます。
学生は時間の自由が効きやすいこともあり、知見・経験のあるメンバーが学生や初心者に教えながら一緒に開発をする場面はとても多いです。

#DDD (Deadline Driven Development)
`締め切り駆動開発`。
これはこの団体に限りませんね。私も今この原稿をまさにこのDDDで書いています。
人はなぜこの業を繰り返すのでしょうか。

#IDD (Involved Driven Development)
`巻き込まれ駆動開発`。
まだオフでみんなで集まれた頃、懇親会や飲み会の場でよく見かけました。
自分が好きな技術を知る仲間を見つけて楽しく話し込んでいると、いつの間にか相手のプロジェクトに参加している人。
自分に何が出来るのか分からないけど、とりあえずメンバーと飲んでいたらいつのまにか酒以外のものに飲まれていた人。
この形態をとる方々はご自身で選択しているようにはなかなか見えませんでしたが、意外と皆さん幸せそうでした。ホントですヨ。

#MDD (Muchaburi Driven Development)
`無茶振り駆動開発`。
この形態は私自身も何度か経験があります。大概この方式はある限界(主に時間)をむかえて採用されることが多く~~それはもうとてもたちが悪く~~、自分も限界を突破するためのいい経験になります。
この形態に出くわした瞬間~~相手を怨みそうになりますが~~こそが、自分が成長するチャンスなのです。
この形態が採用される確率は、自分のスキルやポテンシャルをメンバーに共有している量に比例します。
~~趣味とか軽いノリで宇宙開発なんていう難解なことに取り組んでいるから~~
リーマンサットは`相手を尊重すること`を大事にしているからこそ成り立つ形態だと思います。

#SDD (Stranger Driven Development)
それは未知との遭遇。
いつから同じ輪にいたのか、不意に現れたかと思えば、メンバーの問題を解決に導き、見たことのないマテリアルを置いていき、他の銀河系から遣いを呼び、杯を交わし共に熱狂し・・・
何もしていないように見えたが、目の前でロケットで打ち上がっている景色はその方のおかげでもあったのだ。

#HDD (Human Driven Development)
`人駆動開発`。
この形態は私です。自分ひとりでは出来そうにないことを、同じ方向を向いた誰かと一緒にやりたかったのです。
どんな組織であれその組織にいる人が何を感じ・思い・考え・行動するかが大事だと考えているメンバーは特に人事部に多いです。
リーマンサットは2020年も`200名`あまりの人が新規メンバーとして加わりました。
宇宙関係の開発だけでも6つプロジェクトがあります。
広報系の活動も7つに分かれて行っています。
それとは別に、約30つものサークル活動があります。
例えばこの記事をお読みになられているあなたが加わると、リーマンサットプロジェクトはよりいっそうドライブします。

#DDD (Dream Driven Development)
`夢駆動開発`。
先程のDDDとは全く違う方式です。比べてはいけません。
リーマンサット・プロジェクトを始めたメンバーは`『この組織が宇宙(夢)を通して自分を見つめ、大切な何かを見つけていける場所になってほしい』`と話していました。
ローバーを開発しているプロマネは言います。`『夢から醒めてはいけない』`。
私がリーマンサットのメンバーであり続けている理由も、同じ夢をみながら活動する仲間が居るからで間違いありません。


##終わりに
今更ですが、衛星開発にはNASAでもとられていた[PPP(Phased Project Planning)](https://ntrs.nasa.gov/citations/19720064044)を採用しています。

趣味って結局、人にとってどういうものなのでしょうか？

私達の活動にご興味ありましたらお気軽にご参加ください。
https://www.rymansat.com/join
私達の活動を応援したいという方がいらっしゃいましたら、ご支援お願い致します。
https://www.rymansat.com/donate

次回は@manabu042001 さんによる「基板設計初心者がカメラモジュールプロトタイプを作ってみた」です！
お楽しみに！！
Pardot Engagement Studio (Pardot Lightning アプリケーション) ⇒ アクション、トリガー、ルールについて

１．ルールで何を定義できますか?
２．トリガーは何に反応しますか?
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634241/4f37ddc1-7d81-c6ab-ba8d-c41eeff9f55f.png)
LINE ログイン連携(Webアプリ) メモ

* WebアプリがLINEログイン連携する際の事前作業や主要な連携処理(ログイン、ログアウト、ユーザー情報取得)フローに関する備忘録記事。


## 開発事前作業

* LINEログインチャネル(WebアプリとLINEプラットフォームを接続するための通信路。連携したいWebアプリごとに作成する。)を作成する。
  * リダイレクトURI(コールバックURL)を設定する。
  * メールアドレス取得権限申請(ログインしたユーザーのメールアドレスを取得する)を行う。
  * ※その他、アイコンやプライバシーポリシーURLなどを設定する。

## ログイン処理
* [シーケンス図](https://developers.line.biz/assets/img/web-login-flow.2af66354.svg)

**1. ユーザーは、Webアプリに設置されたLINEログインボタンを押下する。**

   * ボタンデザインは、以下のガイドラインに従うこと。
     * [LINEログインボタン デザインガイドライン](https://developers.line.biz/ja/docs/line-login/login-button/)
   * ログインボタンを設置せず、認可URLへの直接リンクもOK。
   
**2. Webアプリは、LINE Platform 認可URLへアクセスする(リダイレクトURIとstateを指定する)。**
   
* URL及びパラメータは以下を参照。
     * [ユーザーに認証と認可を要求する](https://developers.line.biz/ja/docs/line-login/integrate-line-login/#making-an-authorization-request)

**3. LINE Platformは、ログイン画面・認可同意画面をユーザーに返却する。**
**4. ユーザーは、ログイン画面・認可同意画面でユーザー認証・認可同意を行う。**
   
* ユーザーは、4つの認証方法のいずれかでログインを行う。詳細は以下を参照のこと。
     * [ユーザーがユーザー認証を行う](https://developers.line.biz/ja/docs/line-login/integrate-line-login/#authentication-process)
* ユーザーは、開発者が`scope`パラメータで指定した情報へのアクセス権を認可する。
     * scopeの定義域については、以下を参照のこと。
        * [スコープ](https://developers.line.biz/ja/docs/line-login/integrate-line-login/#scopes)

**5.LINE Platformは、リダイレクトURIにアクセスする(認可コードとstateをクエリパラメータに指定する)。**

* 正常/異常パラメータの仕様については、以下を参照のこと。
    * [認可コードを受け取る](https://developers.line.biz/ja/docs/line-login/integrate-line-login/#receiving-the-authorization-code)
    * [エラーレスポンスを受け取る](https://developers.line.biz/ja/docs/line-login/integrate-line-login/#%E3%82%A8%E3%83%A9%E3%83%BC%E3%83%AC%E3%82%B9%E3%83%9B%E3%82%9A%E3%83%B3%E3%82%B9%E3%82%92%E5%8F%97%E3%81%91%E5%8F%96%E3%82%8B)

**6.Webアプリは、受け取ったstateを検証する。**
**7.Webアプリは、LINE Platformトークンエンドポイントからアクセストークンを取得する(認可コードをクエリパラメータに指定する)。**

* リクエスト/レスポンス仕様については、以下を参照のこと。
     * [ウェブアプリでアクセストークンを取得する](https://developers.line.biz/ja/docs/line-login/integrate-line-login/#get-access-token)
     * [アクセストークンを発行する](https://developers.line.biz/ja/reference/line-login/#issue-access-token)

**8.LINE Platformは、Webアプリにアクセストークンを返却する。**

**9.Webアプリは、LINE Platformにユーザー情報をリクエストする(IDトークンを指定する)。**

   *  [IDトークンからプロフィール情報とメールアドレスを取得する](https://developers.line.biz/ja/docs/line-login/integrate-line-login/#verify-id-token)

**10.LINE Platform はWebアプリにユーザー情報を返却する。**

**11.ログイン成功**



## ログアウト処理

1. ユーザーは、Webアプリのログアウトボタンを押下する。
2. Webアプリは、該当ユーザーのセッション情報を削除し、アクセストークンを無効化する。
   * [ユーザーをログアウトする](https://developers.line.biz/ja/docs/line-login/managing-users/#logout)
   * [アクセストークンを取り消す](https://developers.line.biz/ja/reference/line-login/#revoke-access-token)



## ユーザー情報取得処理

1. Webアプリは、ログインフローで取得したアクセストークンを指定してプロフィールを取得する。
   * API詳細仕様については、以下を参照のこと。
     * [ユーザープロフィールを取得する](https://developers.line.biz/ja/docs/line-login/managing-users/#get-profile)
     * 指定するアクセストークンに`profile`スコープが付与されている必要がある。



## 参考情報

* [ウェブアプリにLINEログインを組み込むLINE開発者ガイド](https://developers.line.biz/ja/docs/line-login/integrate-line-login/)
[Rails] link_toでページ遷移する際、ページの指定した場所に移動する

一生懸命調べていても中々解決できずにいましたが、実はとても簡単でした。（自分の調べ方が悪かった）

#1. 移動させたい場所にidを指定する
```html
<div id="target">目的地</div> 
```

#2. link_toの遷移先のパスにアンカーを設定
```Ruby
<%= link_to '目的地へ遷移', 遷移先のパス(anchor: 'target') %>
```
これだけでできました！


ただ今回のような「パッ」と移動するものではなく、
アニメーションをつけて自動スクロールさせた方が動的で憧れますし、その場合JSを使っての実装が必要になると思うので、今後それも身につけていきたいです。

**参考にさせていただいた記事**
[Rails アンカーリンクを使い遷移先ページの場所(位置)を指定する](https://qiita.com/hellhellmymy/items/37ce7197c8f206715af2)
[Rails link_toでアンカーを設定する](https://qiita.com/tatsuya1156/items/595fe0df912c6c89f991)
CentOS7.9でDPDK22(LTS) SDKを試す ①インストール

### はじめに
VirtualBoxで作成した、CentOS7.9 VMにDPDK SDKの最新LTS(22.11.2)を入れてみました。そのときのメモです。

注：本記事記載の操作はrootアカウントで行っています。十分ご注意ください。

### まず、python3.8のインストール
DPDK22はpython3.6ではビルドできず、python3.7以降にする必要があります。

```
# yum install -y centos-release-scl
# yum install -y rh-python38
# scl enable rh-python38 bash
# python3 -V
Python 3.8.13
# pip3 -V
pip 19.3.1 from /opt/rh/rh-python38/root/usr/lib/python3.8/site-packages/pip (python 3.8)
```

### つづいてMeson/Ninjaのインストール

```
# pip3 install pyelftools
# pip3 install meson ninja
# meson --version
1.2.1
# ninja --version
1.11.1.git.kitware.jobserver-1
```

### DPDK22のソースをダウンロードしてビルド/インストール

LTS（long term support）バージョンを入れないと余計な苦労をするハメになるので、ちゃんと[ここ](https://core.dpdk.org/download/)から最新LTSバージョンをダウンロードします。

なお、2023/9/1時点のLTSは22.11.2となっています

```
# cd /home
# wget https://fast.dpdk.org/rel/dpdk-22.11.2.tar.xz
# tar xJvf dpdk-22.11.2.tar.xz
```

Meson/Ninjaでビルド/インストールします。

```
# cd dpdk-stable-22.11.2/
# meson build
# cd build
# ninja
# ninja install
```
以上でビルドとインストールは完了。恐ろしく簡単でした(時間はかかります)。/usr/local/binや
/usr/local/includeにSDKの各種ファイルがちゃんとインストールされています。

```
# modprobe vfio-pci
# modprobe uio_pci_generic
# /usr/local/bin/dpdk-devbind.py -s

Network devices using kernel driver
===================================
0000:00:03.0 '82540EM Gigabit Ethernet Controller 100e' if=enp0s3 drv=e1000 unused=vfio-pci,uio_pci_generic *Active*
（後略）
```

DPDK対応ドライバuio_pci_genericやvfio-pciも使えそうです。

### 今後

dpdk-devbindとかDPDK22の各種ツールを試してみたいと思います。
2021年版　ImageMagick のインストール

# ImageMagick のインストール

Macでのインストール方法です。個人的なメモです。

## brewを使用してインストール

```
brew cask install xquartz
brew install tlk/imagemagick-x11/imagemagick 
```

## 参考

[macos - How to use ImageMagick with XQuartz - Stack Overflow](https://stackoverflow.com/questions/44624479/how-to-use-imagemagick-with-xquartz)
dockerまずなにしたらいいの？（なんとなくshellはわかるが…ってレベルの初学者向け）

<h1>・ことの発端</h1>
当方、情シスやってます(2年目のペーペー)。
pythonによるテキスト解析を行ったところ、
pipやらcondaやらでのライブラリインストールしすぎによるよく分からん不具合に見舞われまくった。
元々ML界隈の情報収集は積極的に行っておりdockerという単語をちょくちょく見ていたが、
ここでようやくコンテナを活用することの重要性を理解する。

<h1>・結論</h1>
よくわからなくても取り合えず先にコンテナの技術を学ぼう

<h1>・コンテナとは？</h1>
ざっくりとPCの中にPCを起動するイメージです（仮想化とジャンルとしては一緒）。
幼いころ：「PCの中にPC立てたらファイルとかどこにあるかわからなくなるやろ・・・」
今：「わけわからんことして悪影響でてもすぐ切り捨てられるようにしたい」

というわけで、
コンテナ使う＝皿洗うのが面倒な人が皿にラップをひいて食べ終わったら捨てるのと同じ感じですね。
それ以外にもホストOSをそのまま使える（仮想化技術との違い）など、
色々とメリットはあるみたいですが、仮想化全盛期の時代を知らないので、
正直どうよくなってるのかはわかりません（爆）。


で、そもそもどういう時代背景で仮想化・コンテナ化が活用されるようになっているのかというところですが、
ユーザー間の開発環境の差を均一化するためにできたものとされています。

ここでようやくことの発端に戻るのですが、pythonもバージョンによって
使えるライブラリ（=excel関数のようなもの）が異なるようなのです。
個人で使うPCを自分用にカスタマイズしてあるのは当然ですが、
他人と共有する場合や、開発環境⇒本番環境への移行など、を踏まえるとマストなわけです。
近年のゲームで例えるならばPS4,PS5で同じセーブデータを使ってゲームするようなものですね。
これはありがたい。

当初はチーム間でのシステムテストのためだけに役立つのだからバリバリコードを書く立場ではない情シスには
必要のないものだと思っていました。しかし、上に記載した通り、自分だけの場合でも役に立つものですね。
サーバー側のCI/CDみたいな概念ですかね（適当言ってたらすみません）。

<h1>・で、何をハンズオンすればいいの</h1>
とりあえず⇓に従って、dockerコンテナの起動・停止を学びましょう。
https://tech-lab.sios.jp/archives/19073

個人的にハマったポイントとしては、
・imageとrunは違う。imageはデスクトップにあるだけ。runはソフトを立ち上げている状態。
・sudoは実行できなかった。管理者アカウントではないからだからと想定。
・imageIDとコンテナIDは異なるので混同しないように。


<h1>・終わりに</h1>
こんなところです。
あまり大した量進んでないので相当初学者向けのペースですが、
継続的にアウトプットする目的でやってきますのでコメントとか自由に投げてください。
[Python] 動的計画法　ABC015D

#[ABC015D](https://atcoder.jp/contests/abc015/tasks/abc015_4)

個数制限付きのナップサック問題です。ちなみに全探索で考えると、N 個の中から K 個選んで入れる・入れないを全て試すと $O(2^N)$ となり、間に合いません。動的計画法であれば、計算量は $O(NKW)$ で間に合います。

動的計画法は部分問題を意識して、次のように設計します。

$dp[n][k][w]$の定義：
n 番目以下のスクリーンショットから k 枚以下のものを選び、幅が w を超えないように荷物を選んだ時の重要度の最大値

dpの漸化式：
$\mathrm {\rm dp}(n, k, w)$

```math
=
\left \{
    \begin{array}{l}
        \mathrm {\rm max}\{ {\rm dp}( n - 1, k, w ), \:{\rm dp}( n - 1, k - 1, w - A_{n-1} ) + B_{k-1} \}&( k \geq A_{n-1} )\\
        \mathrm {\rm dp}( n - 1, k, w )　&(otherwise)\\
    \end{array}
\right.
```

dp初期条件：
$dp[0][0][*]=0$

求めるもの：
$dp[N][K][W]$


実装は、ボトムアップ方式の貰うDPで行います。Python では TLE ですが、PyPy では間に合いました。

```python:サンプルコード
W = int(input())
N, K = map(int, input().split())
AB = [list(map(int, input().split())) for _ in range(N)]
dp = [[[0]*(W+1) for _ in range(K+1)] for _ in range(N+1)]
for n in range(N):
    for k in range(K+1):
        for w in range(W+1):
            a = AB[n][0] # 幅
            b = AB[n][1] # 重要度
            if w-a>=0 and k-1>=0:
                dp[n+1][k][w] = max(dp[n][k][w], dp[n][k-1][w-a]+b)
            else:
                dp[n+1][k][w] = dp[n][k][w]
print(dp[N][K][W])
```
Node.jsを勉強する - nodemonを使う

##はじめに
nodemonの使い方を備忘録として、まとめておきます。
##教材
Udemy
The Complete Node.js Developer Course (3rd Edition)
https://www.udemy.com/course/the-complete-nodejs-developer-course-2/

##インストール
npmのウェブサイトの[nodemonのページ](https://www.npmjs.com/package/nodemon)からインストールコマンドをコピーし、ターミナルで実行。

```terminal:ターミナル
//ローカルインストールする場合
npm install nodemon
/グローバルインストールする場合
npm install -g nodemon
```

##jsファイルの実行
node ファイル名の代わりに、nodemon ファイル名でファイルを実行します。
今回は、app.jsという名前のファイルを作り、実行します。

```javascript:app.js
consol.log("Hello World!")
```

```terminal:ターミナル
nodemon app.js

Hello World!
[nodemon] clean exit - waiting for changes before restart
```

この状態で、app.jsの変更を保存すると、自動でそのファイルが実行されます。

```javascript:app.js
console.log(chalk.green.bold('Hello Node.js!'));
```
変更を保存すると、ターミナル上でapp.jsが実行され、以下のように表示されます。

```terminal:ターミナル
nodemon app.js
Hello World!
[nodemon] clean exit - waiting for changes before restart

//ここで変更を保存
[nodemon] restarting due to changes...
[nodemon] starting `node app.js`
Hello Node.js!
```

nodemonの実行を止めるには、Ctrl + c をターミナル上で押します。すると通常の状態に戻ります。
機械学習pythonコードまとめ(随時更新)

#機械学習pythonコードまとめ


##データの分割
```
#ホールドアウト法
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

#k-分割交差検証(クロスバリデーション)
from sklearn.model_selection import cross_val_score
cores = cross_val_score(svc, X, y, cv=5)
```
##Scikit-learnを用いたモデル(分類)
### Random Forest
```
from sklearn.ensemble import RandomForestClassifier

rfc= RandomForestClassifier(max_depth=100)
rfc.fit(X_train, y_train)
predicted= rfc.predict(X_test)

```

### ロジスティック回帰
```
from sklearn.linear_model import LogisticRegression

lr = LogisticRegression(random_state=42)
lr.fit(X_train, y_train)
predicted= lr.predict(X_test)
```
###サポートベクターマシン

```
from sklearn.svm import SVC

svc = SVC()
svc.fit(X_train,y_train)
predicted= svc.predict(X_test)
```

### モデルの評価
```
model.score(X_train, y_train)
model.score(X_test, y_test)

#混同行列
from sklearn.metrics import  confusion_matrix
confmat = confusion_matrix(y_test,predicted)

#正解率
from sklearn import metrics
accuracy = metrics.accuracy_score(y_test, predicted)

#精度
from sklearn.metrics import precision_score
precision = metrics.precision_score(y_test, predicted)

#再現率
from sklearn.metrics import recall_score
recall = metrics.recall_score(y_test, predicted)

#F値
from sklearn.metrics import f1_score
f1 = metrics.f1_score(y_test, predicted)
```

他クラス分類の評価をする際、引数にマイクロ平均か、マクロ平均を指定する場合がある。

```
f1 = metrics.f1_score(y_test, predicted, average='micro')
```
## モデルの保存
```
# モデルを保存
import pickle
name = 'test.sav'
pickle.dump(model, open(name, 'wb'))

# モデルをロード
loaded_model = pickle.load(open(name, 'rb'))
result = loaded_model.score(X_test, y_test)
```

## 参考にさせていただいたサイト
- svmのコード<br>
https://qiita.com/sotetsuk/items/3a5718bb1f945a383ceb
- モデルの評価<br>
https://aidemy.net/courses/2010
- モデルの保存<br>
https://localab.jp/blog/save-and-load-machine-learning-models-in-python-with-scikit-learn/
じゃんけんゲームを作ってみる

# 近所に富士そばができるらしいです

その前、そこには何があったっけ？ 
と思い出そうとしても全く思い出せませんでした

何十回（何百回？）と通り過ぎたり、向かいのマクドナルドから
窓越しに見ていたはずなのに、まったく思い出せませんでした

家に戻り、ストリートビューで確認すると、
去年一昨年は工事中の幕が張られていました。
それを見ても、出てきた感想は「そうだったかな〜...？」でした

人の記憶はあやふやなものであることを、あらためて経験しました

```
意識しないと記憶には残りませんが、
意識すれば記憶に残すことはできそうなので、
勉強というのは意識して記憶に残す行為で、
記憶に残るというのは、自分の頭の中に玩具を格納していくようで、
のちのちまで、遊ぶ（=考える）楽しみにつながるのかもしれませんね
```

# 最近はもっぱら`エンジニアVtuber凛`さんのチャンネルで勉強しています。
https://youtu.be/JpcWUuG_5S0
こういう方がたくさん出てくると楽しく学べそうです
*自分でやってみても良いかも？*

# じゃんけんゲームを作ってみる
```python
from random import randint
import time

hands = ["Goo", "Choki", "Paa"]
rules = ["Draw ", "Lose... ", "Win!!! "]
draw = 0
lose = 0
win = 0

print("----------------------------------------------")
print("　　　　　　Let's JAN-KEN Start!!!!")
print("----------------------------------------------")

while True:
  # Player
  print("【 0 : Goo 】", "【 1 : Choki 】", "【 2 : Paa 】")

  while True:
    try:
        p = int(input("You choose ==========> "))
        if p in [0, 1, 2]:
          print("Yes!")
          break
        else:
          print("0か1か2て言うたやん！お願いしますわ！") 
    except:
        print("数字ですらないですやん！せめて！せめて数字でお願いしますわ！") 
  
  print("----------------------------------------------")
  print("■ You 【 " + hands[p] + " 】 play")
  time.sleep(0.9)
  #CPU
  m = randint(0, 2)
  print("● CPU 【 " + hands[m] + " 】 play")
  print("----------------------------------------------")
  time.sleep(0.9)
  #gameset
  i = (p - m) % 3
  print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■")
  print(rules[i])
  print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■")
  if i == 0:
      draw = draw + 1
  elif i == 1:
      lose = lose + 1
  else:
      win == win + 1
  time.sleep(0.9)
  #result
  print("{}...Win / {}...Lose / {}...Draw".format(win, lose, draw))
  print("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■")
  if win == 3:
      print("▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼")
      time.sleep(3)
      print("3wins!!!! You win!!!!")
      print("▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲")
      break
  if lose == 3:
      print("▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼")
      time.sleep(3)
      print("3loses... You lose...")
      print("▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲")
      break
  time.sleep(1)
```

上記は動画の内容と若干違っていまして、
1. 出力内容を少し派手にしたかった
2. 日本語変換が面倒だったので、コメントも英語にした
3. 0,1,2**以外**を入力したときのエラー処理を加えたかった

# 0,1,2以外を入力したときのエラー処理について、まずはフロー図を描いてみた

![janken_flow.drawio_PNG.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528622/3af4c78d-36d2-4d08-983c-b605ebd38019.png)

フロー図を作るにあたって、こちらのサイトの使いやすさを実感しました
https://app.diagrams.net/

# そして、追記したwhile文がこちら

```python
while True:
    try:
        p = int(input("You choose ==========> "))
        if p in [0, 1, 2]:
          print("Yes!")
          break
        else:
          print("0か1か2て言うたやん！お願いしますわ！") 
    except:
        print("数字ですらないですやん！せめて！せめて数字でお願いしますわ！") 
```

意図した結果になりました
もっとスマートな書き方があるかもしれませんが、今のところはこんな感じです

# 勉強結果に寄せて

上記は去年の勉強の一部ですが、
1. フロー図を書く
2. 例外処理を書く
3. 自分でwhile文を書く

ということができたのが嬉しく、記憶に残っていましたので
ここにも記述した次第です

## 新年の抱負（？）
周りの方々がハイレベルな処理をしているなか、
わたしはまだこの辺か、と思ったりもしますが、自分のペースで進めていこうと思います

あと、最近は食べるとすぐ眠くなってしまいますし、
また太りだしたので食事を見直していきます
ScrollViewで横スクロールする方法

インターンで横スクロールを使う場面があったのでやり方をメモっときます！

#ScrollViewを配置
scrollViewを選択し、適当に配置しましょう！
![スクリーンショット 2021-01-04 15.07.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684645/45a50800-1073-b5da-d7ca-246489d00e77.png)
AutoLayoutを上下左右につけます。
しかしエラーが出ます⚠️
![スクリーンショット 2021-01-04 15.10.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684645/e10a3fca-932f-b762-cb7b-25f03219cdc9.png)
居場所が曖昧と怒られてしまいます。
![スクリーンショット 2021-01-04 15.11.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684645/d73df68d-1703-af50-fd5d-806a254c1ebc.png)
これを解決するためにScrollViewの上にViewを置きます。
![スクリーンショット 2021-01-04 15.13.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684645/a63b0830-b3ff-be88-5464-8ead3d20f826.png)
Viewは横スクロールさせたい範囲まで横に伸ばします！
![スクリーンショット 2021-01-04 15.14.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684645/1a79e5ee-48fd-7c1d-5241-831ba66c49e9.png)
ここまでがステップ１です。

#特殊なAutoLayout
ScrollViewのAutoLayoutは特殊でこんな感じでやります。
![スクリーンショット 2021-01-04 15.18.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684645/1a7c5984-c8be-d931-f4c4-6a6e8ed92d04.png)
commandキーを押しながら、`Content Layout Guide`と`View`を選択し、画像のようにAutoLayoutを付けていきます。
![スクリーンショット 2021-01-04 15.18.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684645/14744a47-e1b9-3ef9-cf7b-7ee10ae8558e.png)
controlキーを押しながら、`View`から`Frame Layout Guide`に引っ張っていきEqual Widthsを選択します。
![スクリーンショット 2021-01-04 15.18.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684645/c92769cb-7573-6f77-8def-62bdfed129c1.png)
最後に`View`のHeightを設定すれば、横スクロールが完了です！

#完成(わかりやすく)
Viewにボタンを入れてみました！
![スクリーンショット 2021-01-04 15.22.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684645/cf7caa3f-2eae-f5fc-d827-631d6b701ae3.png)

![スクリーンショット 2021-01-04 15.23.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684645/40d1c746-0e7c-fcc4-bcea-aa901efcc18d.png)
ちなみに`ContentLayoutGuide`の範囲がこれです![スクリーンショット 2021-01-04 15.49.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684645/b26083f8-c7e2-6b5f-b287-f9eb89e5a441.png)
`FrameLayout`がこちら
![スクリーンショット 2021-01-04 15.50.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684645/5ed26c2a-830a-8c21-3bbf-65bf863435d4.png)
`ContentLayoutGuide`がスクロールする範囲で、`FrameLayout`が表示させる範囲です！！
以上横スクロールする方法でした。
Lookahead Optimizerについて

#はじめに

TensorFlow Addonsでも提供されている、Lookahead Optimizerについて簡単に記事にする。

#Lookahead Optimizerとは

論文はこちら。
[Lookahead Optimizer: k steps forward, 1 step back](https://arxiv.org/abs/1907.08610)(19 Jul 2019)

日本語による解説記事はこちら。
[論文解説「Lookahead Optimizer: k steps forward, 1 step back」 ](https://cyberagent.ai/blog/research/11410/)


以下の図が動作を示したもの。

![accuracy_surface.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/824193/31732433-a0cd-a355-c3cc-74ad539d981c.png)

簡単に動作を説明すると次のとおり。

1. 重みを記憶
1. 所定のステップ数だけOptimizeを実行して重みを更新(これはSGDでもAdamでもなんでもよい)
1. 所定のステップに達したら、最初に覚えた重みと現在の重みの間のどこかに重みを更新(つまり戻る)
1. 以下繰り返し

ハイパーパラメータとしては、上記のステップ数(sync_period)と、戻る際の重みの割合(slow_step_size)となる。
TensorFlow Addonsの実装では、sync_period=6、slow_step_size=0.5になっており、この場合は戻る際にちょうど中間の値になる。

戻るので速度が遅くなるような気がするが、論文では収束が速くなったとしている。「いそがば回れ」、ということらしいが、他のOptimizerと組みわせることも含めて、最近(2020/12)発表された[SAM](https://qiita.com/omiita/items/f24e4f06ae89115d248e)と似ている気がする。
その他にも、汎化性能向上や、学習率の変化にたいしてもロバストになったと主張されている。

#tf.kerasでの利用法

これはTensorFlowAddonsをつかえば割と簡単で、こんな感じで最初にOptimizerを渡せばよい。その後は学習率の設定も内部で受け渡ししてくれるので、Schedulerでも普通のOptimizerとして扱える。

```Python
import tensorflow as tf
import tensorflow_addons as tfa
optimizer = tfa.optimizers.Lookahead(tf.keras.optimizers.Adam(0.001))
```
#実際の動作
単純な最適化を実施した場合の比較はこちら。
![LookAhead.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/824193/e6f3e789-d560-7ac8-bb8c-9981746b46c8.png)
Lookaheadでは'step back'していることがわかる。

一方、ResNet50でCIFAR10を学習させた結果がこちら。CosineDecayで学習率は0.2から0.002になるように設定。

![LookAheadResNet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/824193/6c0ee23b-53f9-3584-fb16-7bb451a1a414.png)


あまり明確な違いは出ないが、Lookaheadを使用したほうが認識率が低く収束した(SGDでは96.46、Lookaheadでは95.91)。何度か設定を変えたりしたが一貫してLookaheadを使用したほうが性能が悪化した、という残念な結果だった。
特に学習が速いわけでもないが、遅くなってもいないようだ。

以下の論文では効果があったというので、条件次第では効果があるようだ。
[Lookahead optimizer improves the performance of Convolutional Autoencoders for reconstruction of natural images](https://arxiv.org/abs/2012.05694)
CURLコマンド

# 概要

よく使うCURLコマンドですが、よく忘れるのでまとめです。

# curlコマンドとは

こちらによると[さまざまなプロトコルに対応したデータを転送するためのコマンド](https://www.atmarkit.co.jp/ait/articles/1606/22/news030.html)です。

難しいことが書いてあって「？？？」なのですが、私の理解は、コマンドラインからインターネットに通信することができるコマンドです。

# サーバーでよく使うオプション

`-X <request method(POST/GET)>`: メソッドの指定。これを指定しない場合はデフォルトで`GET`になるので、`GET`のときは指定しなくてOK。

`-H <header>`: ヘッダを追加する。

`-s`: 実行中のメッセージを表示しない。コマンドの実行結果の詳細が不要の時につける。

`-v`: `-s`とは逆に詳細を出力する。

`-o`: ファイルに保存。`-o index.html`など。

`-w`: statusの結果を表示する。`-w  "%{time_starttransfer}"`とするとかかった時間を表示できる。

`-d "id=01234"`: パラメーターを付与したい時に。複数のパラメーターを`-d`を指定したい場合は、複数使用することが可能。もしくは`-d "id=01234"&password=abcd`

# その他でよく使うオプション

`-O　<URL>`: ファイルのダウンロード。

# よく一緒に使うコマンド

`jq`: jsonをきれいに整形してくれるコマンド

`jq --sort-keys`で、ソートしてくれるので、`curl <url> | jq --sort-keys > <savename.json>`をつかって出力します。

# 参考文献
- https://www.atmarkit.co.jp/ait/articles/1606/22/news030.html
- https://www.karakaram.com/notes-on-curl-options/
- https://hogem.hatenablog.com/entry/20091122/1258863440
Google Analytics4ではページビューは5秒以上見た場合に限定される件

Universal Analytics(UA)からGoogle Analytics4(GA4)ではページビューという概念が結構変わっています。

## 同じページにUAとGA4と設置
同じ発火タイミングでやっています。また、特にクロスドメイン設定などは行っていません。

![Screenshot from 2021-01-04 10-48-27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293892/765efcbb-7d07-4fc5-e91c-c0ed298f87ad.png)


## GA4では最大5秒程度のページ閲覧が必要
UAの場合、ページが呼び出されてタグが動いた瞬間にページビューがカウントされます。一方でGA4ではUAのタグ発火から5秒程度遅れてから発動するようです。

![Screenshot from 2020-12-16 19-05-27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293892/b70d790d-8433-b7f6-8959-8955105dc37a.png)

UAのタグ発火は1.93秒
![Screenshot from 2021-01-04 15-37-41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293892/42025504-e59d-b003-4f89-2ee9d0558775.png)
GA4のタグ発火は6.94秒
![Screenshot from 2021-01-04 15-39-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293892/82301f48-0901-0f3e-1e43-fe954766f5ff.png)

多分Googleがページビューという概念を、少なくとも5秒閲覧した状態と定義したのだと思われます。
今まで解析する際に、PV数が2以上や3以上といったセグメントを切って「真面目に回遊しているセッション」だけを洗い出す技が有りましたが、GA4からは特に意識する必要もなくなったように思えます。

ただ副作用として、Google BigQueryのRAWデータを見た際に、セッションは開始されているのに、ページビューがカウントされないという状態が発生したり、UAとGA4でページビューの数が違うという事が発生しそうです。特にBigQueryでRAWデータ解析する際には、意識してデータを扱う必要はあるのかも、と思った次第でした。

## 補足：各種検証

#### UAとGA4を同時に貼った場合に起こる現象では？GTM固有の現象では？クロスドメイン設定とかの問題では？
特にクロスドメイン設定をせず、デフォルトのgtagをヘッダー内に貼るという、Google公式の一番シンプルなページ構成でも同様に5秒以上かかることを確認しています。

#### タグのプライオリティがLowestになっているから、画像やらなんやら呼び出されて、結果一番最後に呼び出されただけでは？
テキストだけの超軽いサイトでも5秒以上かかっている様子です。

参考：https://twitter.com/kazkida/status/1346634217875099648
コンポーネントからサービス経由してAPIを呼んでる場合の単体テスト　備忘録

コンポーネントでサービス経由でAPI呼んで初期値取得したり値取ったりしてる場合、
どうやってサービスをモック化するか備忘録 (Karma + Jasmin)

```java
〇〇.spec.ts
let service: testService;
// サービスのモックを作る
const testServiceMock = {
  setService() {
    service.id = "1";
  }
};

beforeEach(async(() => {
    // テストモジュールの準備
    TestBed.configureTestingModule({
        declarations: [TestComponent]
         省略
    })
    // テストモジュール内のコンポーネントで呼び出すサービスをオーバーライド
    .overrideComponent(TestComponent,{
        set: {
            providers: [{provide: testService, useValue: testServiceMock}]
        }
    })
    // テストモジュールのコンパイル
    .compileComponents();
});

beforeEach(() => {
  // テストクラス内で上記で設定したサービスを呼び出す場合に記載
    service = fixture.debugElement.injector.get(testService);
});

it('t', () => {
  // こうやって呼び出すとモックのサービスをテスト内からも任意で実行できる
  // 悪魔でもオーバーライドである点に注意（本来無いreturnを追加するとかは無理）
  service.setService();
}
```
【全エンジニア向け】Alfredで超シンプルgoogle英語検索

## 結論

以下を追加Aflredのcustom searchに追加

```
https://www.google.com/search?q={query}&hl=en
```

Titleはお好きにどうぞ(筆者はenにしています)

## みんな大好きAlfred

とりあえず入れましょう。
https://www.alfredapp.com/

## googleは英語検索が面倒くさい

情報量が日本語と段違いなのでエンジニアにとって必須です。

しかし、googleでは英語優先の検索がいかんせん面倒が多い。
英語検索の度に、わざわざ英語に変更して終わったら日本語に戻す、なんてやってられませんよね。

## 対処法

ということで、Alfred使って簡略化します。

Alfredを起動してキーワード入力画面になったら

```
command + ,
```

で設定画面を開きます。

以下のようにweb search画面に行きます。
[![Image from Gyazo](https://i.gyazo.com/2d09c3834397931f37452751be5fb994.jpg)](https://gyazo.com/2d09c3834397931f37452751be5fb994)

右下のAdd Custom Searchをクリックして、以下のように入力する。

[![Image from Gyazo](https://i.gyazo.com/e4cfaea5afac9abd659a5b5208fa3eee.png)](https://gyazo.com/e4cfaea5afac9abd659a5b5208fa3eee)
SearchURLには以下を入力

```
https://www.google.com/search?q={query}&hl=en
```
Titleは自身が識別できれば何でもok。
keywordは利便性のために短くしましょう。
Validationは触らなくてok。

これで完了です。

## 使い方

こんな感じ。今回は英語でalfredを検索しました。
[![Image from Gyazo](https://i.gyazo.com/5570df4a5e8cb2efb2344518551d37dd.png)](https://gyazo.com/5570df4a5e8cb2efb2344518551d37dd)
[custom searchで設定したkeyword] + 検索したいキーワード
でgoogle英語検索できます。
【TypeScript】型アサーション

## 型アサーションとは
- TypeScriptによって推論・分析された型を上書きする
- 記述方法: `value as Type`

## どの様な時に使うか
- JavaScriptからTypeScriptへコードを移植する場合

```typescript
interface Foo {
    bar: number;
    baz: string;
}

const foo = {} as Foo;
foo.bar = 123;
foo.baz = 'hello';
```

## 注意点
- 型アサーションでは、必要なプロパティの追加を忘れた時もコンパイラは指摘しない

```typescript
interface Foo {
  bar: number
}

const foo: Foo = {};  // コンパイルエラー
```
```typescript
interface Foo {
  bar: number
}

// 型アサーション
const foo = {} as Foo // コンパイルエラーは出ない
```

- any型: 下記の様なコードはコンパイルは成功するが実行時にエラーとなる

```typescript
// any型に上書きする
const foo = 123 as any;

// StringオブジェクトのメソッドであるtoUpperCase()を呼び出す
foo.toUpperCase();  // 実行時エラー
```
Client Hintをwebサーバで取得してみる

#Client Hintって何？
httpリクエストヘッダに載ってくるUserAgentの情報が、Chromeのとあるバージョンからマイナーバージョンが0.0.0に固定されるというアップデートが2021年前期に発生するとのこと。詳細は[こちらを参照](https://qiita.com/paddy-oti/items/fae9ecca9facc9797035)

端的にいうと下記のようになる。
【現行】User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/**85.0.4183.121** Safari/537.36
【改修後】Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/**85.0.0.0** Safari/537.36

メジャーバージョンは引き続き更新されていく予定で、一見些細な改修のように感じるがその傍ら[Clinet Hint](https://wicg.github.io/ua-client-hints/)というものが既に実装されている。

新規に下記のようなリクエストヘッダー情報が追加されるのだ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541083/1b926603-bcdf-0237-1a19-b203593f49b9.png)


上記を利用することでマイナーバージョンもしっかりと取得することができる。
またこの実装背景として、真偽は定かではないが、意味不明な文字列であるUserAgentを今後無くして、ClientHintに絞ろうという意向を感じている。

現状UserAgentを利用して判定し、クライアントサイドに返すコンテンツをコントロールしているものがあまりにも多いのですぐには起こらないだろうが、UserAgentではなく、**Client Hintを利用していくのが今後推奨されていく**のではないか。

そのためにもClient Hintをしっかり取得する方法を学んでおいて損はないだろう。

#Client Hint取得方法
例えばphpでは、``$_SERVER``などを利用してhttpの一部ヘッダ情報を取得可能だが現時点(2020年12月現在)では不可能である。php等のアプリケーション側でも取得する方法は存在するが本記事ではwebサーバレイヤーのみ（apacheとnginx）で、それぞれapacheのaccess_logとnginxのaccess_logにClient Hintを含める方法を記載していく。

##ApacheのlogにClientHintを含める
具体的には/var/log/httpd/acc_XXXXXXXXXX.logにClientHintを含める方法だ。
特にカスタムのconfファイルを追加していない場合、2か所修正が必要となる。
**【修正1】**下記のheader set 追加

```/etc/httpd/conf/httpd.conf
Header set Accept-CH "UA-Full-Version, UA-Arch, UA-Model, UA-Platform, UA-Platform-Version, UA-Mobile"
```

**【修正2】**Logformatに``\"%{sec-ch-ua}i\"``追加

```/etc/httpd/conf/httpd.conf

<IfModule log_config_module>
    #
    # The following directives define some format nicknames for use with
    # a CustomLog directive (see below).
    #
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{sec-ch-ua}i\"" combined
```

が必要である。
``\"%{sec-ch-ua}i\"``の部分は適宜必要なヘッダー要素の名前をhttpリクエストヘッダを参照すると良い。

###解説
修正1ではまず、apacheがクライアントに対して、以降のhttpリクエストヘッダにClientHintを含めるように指定をしている内容である。(デフォルトではClientHintは取得できない)
修正2では生成されるapachelogはhttpd.conf内でフォーマットを持っており、そのフォーマットを修正してログにも出力されるようにしている。
もしカスタムのログフォーマットを持っている場合、そのパス``/var/log/XXXX(カスタムのフォーマット名)/acc_XXXXXXXXXX.log``に置かれているものが編集が必要なのでそれに応じたLogformatをいじらなければいけない。

##NginxのlogにClientHintを含める
nginx_confを下記のように修正する必要がある。

```/etc/nginx/conf.d/nginx.conf
http{
    log_format formatA #ここに'"$http_sec_ch_ua"'を追加
    access_log /var/log/nginx/access_log formatA
}
```

###解説
こちらも同様にlogのformatにClientHintを追加してやる必要がある。
ClientHintの形式は``$http_``と開発者ツールで見れる属性(「-」を「\_」に変える必要あり)の結合文字列によって取得可能になる。($https_sec_ch_ua_full_versionなど)

#まとめ
ClientHintを取得可能にするメリットは下記の3つ
★UserAgent文字列が凍結されてもマイナーバージョンまで取得可能
★UserAgentを利用するよりはるかに判定がしやすくなる
★UserAgentが今後無くなる可能性があり、クライアント情報を得る次世代方式

デメリットは
★ログにカラムが追加されるため、以降のフロー(集計処理など)がおかしくなる可能性
★多少ログデータが重くなる
などがある。

少なくともクライアント情報をUserAgentから取得している処理がある場合は今後の各種ブラウザのClientHintの実装状況にしっかりアンテナを張っておくべきだろう。
Oriental motorのブラシレスモーターを動かす

# はじめに
今まで、DCブラシ付きモーターか、ステッピングモーターぐらいしか使ったことがなかったのですが、安定した高速回転を求めてブラシレスモーターを購入しました。あまり情報がなかったので、オリエンタルモーター社製のブラシレスモーターを購入してRaspberry Piで動かしたのを書いておきます。
<img width="400px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197729/07b10856-ff4b-b50f-a55d-3469cba28820.png">
# やったこと
* ブラシレスモーターとは（調査）
* Oriental motor社製のブラシレスモーターを購入
* Raspberry PiからPWM制御でブラシレスモーターの回転を制御

# ブラシレスモーターとは
ブラシレスモーターの特徴はこちらのサイトに詳しく書かれています。→[サーボライクな性能をインバータ並みの価格で？第３の選択肢、ブラシレスモーターとは](https://www.orientalmotor.co.jp/om/knowledge/uroko_bl/bl01.html)
CDプレーヤーの回転軸などに使われているようです。

#### 特徴
* ステッピングモーターと基本原理は同じ
* DCブラシ付きモーターとトルクは同じ
* 応答性が高い（ステッピングモーターはすぐ高速に動かすとかできない）
* 色んな速度で動かせる
* サーボモーターより安価(←重要)
* 制御基板(駆動回路)が必要

# Oriental motor社製のブラシレスモーターを購入

ブラシレスモーターは制御基板が必要で、他の種類のモーターほど流通していないため、Oriental motorのサイトから購入します。もちろん１台から購入可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197729/ece8a061-d4d4-db8d-be44-8f3bf7e11a45.png)

スペックで絞り込むことで、オススメのモーターを教えてくれます。
今回は、[BLHM450KC](https://www.orientalmotor-shop.jp/shop/product_details_ec.action?hinmei=BLHM450KC-5)を選びました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197729/ec331bcb-ec13-2000-657e-508f36d0ad22.png)

ここで最低限必要なのは、ブラシレスモーター、ドライバ、電源/入出力信号ケーブルです。接続ケーブルは1.5mの延長ケーブルなのでなくても大丈夫です。
他に、DC24Vを供給するためのACアダプタ→[参考までにamazonで選んだACアダプタ]
(https://www.amazon.co.jp/gp/product/B08CDBW8HY/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&th=1)
PWM入力をするためのRaspberry Pi (PWM波形が出せるものであれば Arduino などでも可)
も用意してください。


# Raspberry PiからPWM制御でブラシレスモーターの回転を制御

デジタル制御基板の使い方はこちらにユーザーマニュアルが置いてあります。→[オリエンタルモーター社サイトのマニュアル](https://www.orientalmotor.co.jp/download/dialog.action?serviceTypeNo=18&senimotoId=1&senimotoUrl=%2fproducts%2fdetail.action%3fhinmei%3dBLH2D50-KD&hinmei=BLH2D50-KD&gengo=JP&documentType=5&fileName=%2ffile_addon_auth%2fproducts%2fsc%2fmanual%2fHP-5071J.pdf&gengoId=1)


<img width="400px" alt="制御基板の接続PIN一覧" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197729/705e6921-76d2-bfdd-57f6-b02ab31bdf9a.png">

13,14のピンをONにして、6,7にPWM入力を与えればモーターが回転します。

**注意点は１ポイントだけ。**
 こちらの制御基板の入力信号は、ON:0〜0.5V(Lレベル)、OFF4〜5V(Hレベル)となっています。

<img width="400px" alt="制御基板の入力信号" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197729/c2120c77-6c12-6d1e-977b-8085ee670f0c.png">

そうすると0V指定で電源投入してしまうとすぐに動き出してしまって危ないのでは？と思うともちろんそうはなっておらず、0Vの状態で電源を入れると、制御基板上のアラートランプが11回赤点滅します。電源投入時には、Hレベルの状態（つまりOFF）になっていないと、動き出しません。一度OFFにしてから電源を投入し、そのあとONにすれば動作状態となります。

<img width="400px" alt="制御基板のアラート" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197729/a4d3f318-2266-1ed9-c777-0aa1343708c4.png">

制御基板の6,7PINをRaspberry Piの出力PINに接続し、PWM波形を生成すると簡単に速度をコントロールできます。

* 6PIN : GND
* 7PIN : PWM (GPIO.PWM Out)


```python:参考コード
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)

pin_id = 4
GPIO.setup(pin_id, GPIO.OUT)

pin = GPIO.PWM(pin_id, 100) #100Hz
pin.start(0)

pin.ChangeDutyCycle(30)
time.sleep(3)
pin.ChangeDutyCycle(50)
time.sleep(3)
pin.ChangeDutyCycle(100)
time.sleep(3)

pin.stop()
GPIO.cleanup()
```

あまり情報がなかったのですが、ユーザーマニュアル通りに繋げばPWM制御で比較的簡単にコントロールできますのでお試しください。
SwiftでHTML/XMLジェネレータを作成する(dynamicMemberLookup)

# 概要

`@dynamicMemberLookup` を使ってSwiftでHTML/XMLを生成するDSLを作ります。（作りました）

#SwiftPM

SwiftPMの形で配布しています。

https://github.com/coe/MarkUpDynamic

#コード例

## HTML

以下のような形でSwiftを記述します。

```swift
MarkUp()
    .html[MarkUp()
            .body[MarkUp()
                    .table[MarkUp()
                            .tr[MarkUp()
                                    .td[character: "one"]
                                    .td[character: "two"]
                            ]
                    ]
            ]
    ].generate()
```

上記のような構造でSwiftのコードを書くと、以下のような形でHTMLなテキストを生成します。

```html
<html>
<body>
  <table>
    <tr>
      <td>one</td>
      <td>two</td>
    </tr>
  </table>
</body>
</html>
```

## XML
同様にXMLも生成できます。
`レシピ` と `手順` をドットアクセスでつないでいきます。

```swift
MarkUp(doctype: #"<?xml version="1.0" encoding="UTF-8"?>"#)
    .レシピ[MarkUp()
                .手順[character: "全ての材料を一緒にして混ぜます。"]
                .手順[character: "オーブンに入れて温度を180℃にして30分間焼きます。"]
    ]
    .generate()
```

こうすると以下のような形でXMLを生成します。

```xml
<?xml version="1.0" encoding="UTF-8"?>
<レシピ>
    <手順>全ての材料を一緒にして混ぜます。</手順>
    <手順>オーブンに入れて温度を180℃にして30分間焼きます。</手順>
</レシピ>
```

#仕組み

これらのタグの生成には、 `@dynamicMemberLookup`を使っています。

## dynamicMemberLookup

dynamicMemberLookupは、Swift 4.2より追加された機能です。
`@dynamicMemberLookup`が付与されると、まるでプロパディが実装されているかのようにドットでアクセスできて、内部では`subscript(dynamicMember:)`の部分でドットアクセスに対する処理を書いていきます。

上記コードの場合、`.html`や`.body`、`.レシピ` などのアクセスで `subscript(dynamicMember:)` が動き、タグを生成する処理を行っています。

```swift
    public subscript(dynamicMember member: String) -> MarkUp {
        tagName(member)
    }
    
    public func tagName(_ tagName: String) -> MarkUp {
        queue.append(self)
        return MarkUp(tag: tagName,queue: queue)
    }
```
Pardot Engagement Studio (Pardot Lightning アプリケーション) ⇒ Engagement Studio プログラムの作成 (Pardot Lightning アプリケーション)

１．分岐ロジックを設定する Engagement プログラムのステップはどれですか?
２．稼働開始後に Engagement プログラムにステップを追加する場合、何を行う必要がありますか?
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634241/69c58822-43e7-6b14-67a6-b65b33d32f39.png)
特定プロジェクトのDerivedDataの削除

`find ${HOME}/Library/Developer/Xcode/DerivedData/ -maxdepth 1 -name "MyProject*" -type d -exec rm -rf {} \;`

`${HOME}/Library/Developer/Xcode/DerivedData`フォルダ内の、`MyProject`から始まるフォルダを非再帰的に検索し、削除している。

CI/CDを使っている場合は、何か問題が発生した際、DerivedDataの削除をボタン一つで手動でできるようにしておくと便利かもしれない。以下は、gitlab CI/CDでそのような設定をした時の一例。

```:.gitlab-ci.yml
stages:
  - refresh
  - test
  - archive

.job_template: &before_script_definition
  before_script:
    - export LANG=en_US.UTF-8
    - security unlock-keychain -p $PATH_PHRASE "${HOME}/Library/Keychains/login.keychain-db"
    - export DEVELOPER_DIR=/Applications/Xcode11.4.1.app/Contents/Developer

refresh_build_machine:
  <<: *before_script_definition
  tags:
    - ios
  stage: refresh
  when: manual
  script:
    - find ${HOME}/Library/Developer/Xcode/DerivedData/ -maxdepth 1 -name "MyProject*" -type d -exec rm -rf {} \; # DerivedData 中間データ（キャッシュ） 削除

# 後略
```

### 参考

[[Xcode][小ネタ] DerivedDataの削除についての備忘録](https://dev.classmethod.jp/articles/remove-xcode-derived-data/)
[[Sy] Linuxでファイル名で検索したファイルを一括削除するコマンド（ワイルドカードも使えるよ）](https://utano.jp/entry/2016/07/linux-search-file-name-delete/)
[【find】Linuxでファイル・ディレクトリ検索をするコマンド](https://uxmilk.jp/8583)
[再帰なしで見つける](https://www.it-swarm-ja.tech/ja/unix/再帰なしで見つける/970672085/)
[GitLab CI/CD pipeline configuration reference](https://docs.gitlab.com/ee/ci/yaml/#allow_failure)
SalesforceからAzure DBへの引っ越しをPythonで行う

![Screen Shot 2021-01-04 at 13.59.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142638/bc3fbc63-c41b-def9-ed05-df71afe22aa5.png)

#概要
あえてSFDCをDataframeにしてAzure DBに入れるのをPythonでやります。

#SFDCのdf化
こちらの記事をご覧ください。
https://qiita.com/tetsuyaimagawa/items/26e3ceeb56e92e40d0d9#salesforce%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92dataframe%E3%81%A7%E6%8A%9C%E3%81%84%E3%81%A6%E3%81%8F%E3%82%8B
👇のような感じです。

```Python
import cdata.salesforce as mod
import pandas as pd
from sqlalchemy import create_engine

engine = create_engine("salesforce:///?User=a@b.com;Password=xxx;SecurityToken=yyy;")
df = pd.read_sql("SELECT * FROM Object1;", engine)
```

#Azure DBにテーブルを作る

```Python
import pyodbc
server = 'aaa.database.windows.net'
database = 'bbb'
username = 'xxx'
password = 'yyy'   
driver= '{ODBC Driver 17 for SQL Server}'

with pyodbc.connect('DRIVER='+driver+';SERVER='+server+';PORT=1433;DATABASE='+database+';UID='+username+';PWD='+ password) as conn:
    with conn.cursor() as cursor:
        cursor.execute("
         CREATE TABLE [dbo].[Object1](
         [id] [int] IDENTITY(1,1) NOT NULL,
         [name] [nchar](128) NULL,
         [str] [nchar](64) NULL,
         [num] [decimal](18, 0) NULL
         ) ON [PRIMARY]
         ")
```

公式はwithで書かれていましたが、👇のような感じで大丈夫です。

```Python
conn = pyodbc.connect('DRIVER='+driver+';SERVER='+server+';PORT=1433;DATABASE='+database+';UID='+username+';PWD='+ password)
cursor = conn.cursor()

#作業

conn.commit()
cursor.close()
```

#dfをAzure DBにINSETする
SFDCから落としたdfがものすごい簡易化して👇のようなものだとします。

||col1  |col2  |col3  |
|---|---|---|---|
|1|name1  |str1  |1  |
|2|name2  |str2  |2  |

```Python
for index, row in df.iterrows():
    cursor.execute("INSERT INTO [dbo].[Object1] (name, str, num) values(?,?,?)", row.col1, 
    row.col2, row.col3)
```
これでテーブル一つ引っ越し完了です。

#Azure DBのデータをdfで取得する
確認も兼ねて、INSETしたものをSELECTしてdfにします。

```Python
query = "SELECT * FROM [dbo].[Object1]"
df = pd.read_sql(query, conn)
```

#まとめ
csvを落とした方が速いことがわかりました。
（私のような）SQL Server未経験者は文法に発狂するので、やめておいたほうがよいと思いました。
iOS SDK備忘録

以下を読んだ際の備忘録
UIKit＆Swiftプログラミング　優れたiPhoneアプリ開発のためのUI実装ガイド Kindle版
https://www.amazon.co.jp/dp/B00ZF44J8K/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

■iOS SDK
xCodeに同梱されている。フレームワークやiOSの実行環境なども含む

■Application Bundle
→アプリの実体。これがメモリの上に乗る

■アプリの状態
・Active（以下の順で遷移した後、Background状態になる）
	appplicationWillResignActive(_:)
	applicationDidEnterBackground(_:)
	application(_:shouldSaveApplicationState:)
	application(_:didDecodeRestorableStateWithCoder:)
・Background（裏で動いている）
	通常5秒、延長して180秒
・Suspended（現在動作はしていないが、再開できるようにメモリ上に残っている）=sleep？
	メモリが圧迫されたらKillされる
・Not Running（メモリにいない）

■アプリの構成
・Deviceに関する部分
→iPhoneの、何インチなのかとか
・Application共通部分
→Framework部分。ホームボタンを押した時にホームを表示したり、着信が来た時に着信画面を出したり
・アプリ毎に実装が異なる部分
→デザインパターンに基づいて実装する

■イベントループ(Main Run Loop)
イベントが発生するまで待ち続け、イベントが来た際に1つずつ処理する仕組み
イベントは、ユーザー操作、端末が振られた、Notificationを受信した、着信が来たなど
イベントは、イベントキューに積まれる(	Queuing)
その後、渡し先にディスパッチ（割り振り）される

■UIApplicationオブジェクト
イベントループを管理し、適所にディスパッチする。
=アプリの動作全体を管理する。全てのアプリは、UIApplicationのインスタンスを持つ

■フレームワーク
以下を含んだパッケージ（ディレクトリ）
・システムAPI
・ダイナミック共有ライブラリ
・ヘッダファイル
・画像
・補助アプリなど
・その他ライブラリのサポートに必要なリソース

■MVCパターン
・モデル=アプリが扱うデータを保持、操作
・ビュー=モデルが持つデータをユーザに表示することと、UIを提供すること
・コントローラ=両者の橋渡しと、Notificationなど、端末からの通知を受け付ける

■Delegateパターン
プロトコルを継承させ、呼び出し元はプロトコルのメソッドを呼ぶだけ。
プロトコルを実装するクラスに実装を委譲するのが目的

■Observerパターン
NSNotificationCenterで呼び出すこと。
このパターンは、Broadcastのように、複数機能に処理タイミングを通知することが目的
アプリがバックグラウンドになったタイミングをViewControllerで知りたいときはAppDelegateからNSNotificationCenterで呼べばいい

■シングルトンパターン
オブジェクトをたった一つにすることで、処理の漏れを防ぐ

■InterfaceBuilder
デザインのツール。
Storyboardを作るキャンパスを提供

Auto Layout
Size Class

■Storyboard
設計図
場面＝画面（View Controller Scene = ViewController + View)
キャラクター＝部品
シナリオ=画面遷移(Segue)
ルール1=Viewの大きさや位置(Auto Layout)
ルール2=表示可否、Constraintの利用有無の取り決め（Size Class）

■コンポーネントの役割
コンテンツViewController
	通常のViewController
コンテナViewController
	ViewControllerを管理するViewController
Scene
	StoryBoard上の一画面

■ライフサイクル
アプリが起動
UIApplicationオブジェクトがUIWindowインスタンスを生成する
メインのStoryBoardをインスタンス化
Initial ViewControllerをインスタンス化
UIWindowオブジェクトのrootViewControllerプロパティに設定

Viewの木構造
rootViewControllerのrootViewをロード
rootViewのsuperviewプロパティにWindowオブジェクトが入る
rootViewの子Viewをロードし、subviewsプロパティに入れる

ViewControllerの木構造
ViewControllerも木構造になっている
parentViewController、childVoiewControllersプロパティそれぞれに格納されている


■モーダルビューについて
モーダルビューは、画面いっぱいに表示するか、一回り小さく表示するか指定できる
モーダルビューを閉じるのは、呼び出し元のViewControllerの役目。
でも一時的にモーダルビューに制御が移っているので、Delegateで移譲する
MySQLモニタを使用してデータベースを操作する

MySQLモニタを使用してデータベースの操作をする機会があったので、今回はMySQLモニタを使ってコマンドラインベースでデータベースの操作をする方法についてまとめようと思います。
今回使用したサーバーに元々mySQLモニタがインストールされていた為、MySQLモニタのインストールについては書いておりませんのでご了承下さい。
また、今回が初の投稿なので適宜アップデートさせていただく事がありますのでご了承下さい。

#やりたい事

MySQLモニタを使ってデータベースの操作をする。

##MySQLモニタとは
>MySQL モニタはコマンドラインベースで MySQL を操作するためのプログラムです。コマンドプロンプトなどから MySQL モニタを起動することで、コマンドを使ってデータベースやテーブルを作成したり、テーブルに追加したデータを取得したりすることができます。ここでは MySQL モニタの使い方について解説します。
https://www.dbonline.jp/mysql/connect/ より引用

#コマンドラインとは
ざっくりと説明すると
`操作する為の命令をキーボードで文字を入力する事で行う物`

#データベースに接続する方法
コマンドプロンプトに mysql -u ユーザー名 -pパスワード を入力する。
```mysql -u ユーザー名 -pパスワード```

ただしこれだとパスワードを入力するとパスワードが見えてしまうので
```mysql -u ユーザー名 -p```
mysql -u ユーザー名 -p　と入力すると下の画像のようなパスワード確認画面が出てきてパスワードを入力しても表示がされなくなる為他の人にパスワードを見られる可能性が低くなる。
![スクリーンショット 2021-01-04 14.05.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933264/93e95136-76d6-4c51-259c-c1815907ac99.png)

無事に表示されるとこのような文言が出る![スクリーンショット 2021-01-04 14.08.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933264/86089555-eabd-e6f4-3e66-fc2805e4c5d2.png)

#MySQLでよく使うコマンド
```show databases;```
存在するデータベースの一覧を表示する。下の画像のような形で存在するデータベースがテーブル形式で表示される。
![スクリーンショット 2021-01-04 14.10.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933264/34956538-e046-39dd-de2a-f5819a503636.png)

```use データベース名;```
使用するデータベースを選ぶ。下の画像のようなメッセージが出てくればOK。
![スクリーンショット 2021-01-04 14.13.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933264/5d33e0b9-2e0c-1143-8bf4-bdef83c4fdad.png)

```show tables;```
データベースの中にあるテーブルを表示する。
(show databasesのテーブル版みたいな物)
![スクリーンショット 2021-01-04 14.15.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933264/f4f841a4-0343-44d6-a2fa-2522d490a1ee.png)

使用するデータベースをuse データベース名　で選択した後は各SQL文（CRUD処理に使用するSQL文やcreate tableなど)も使用する事が出来る。

#MySQLモニタや他のツール(phpMyAdmin等)のツールを使用してデータベースの操作をする時に理解しておくといい事
(phpを使用している場合、phpMyAdminが多く使われるそうなので今回の記事投稿ではphpMyAdminを例に書いていこうと思います)
それはどんな事かと言うと**「phpMyAdminというデータベースがあるわけではなく、phpMyAdminはあくまでデータベースの操作をする為のツールの一つ」**と言う事です。

食事を例えにして説明すると

「データベースに入っているデータ」を、ご飯
「MySQLモニタを使用してデータを操作」というのを、手づかみで丼に入ったご飯を食べるという事に例えたとして
手づかみでもご飯は食べる事は出来るけど、手にくっつくしおかゆみたいにベタベタした物だと掴みづらい時ってありますよね。

MySQLモニタでSELECT文を実行した時等も、以下のように入っているデータが長くなったりした時に表示がぐちゃぐちゃになり見づらくなる時があります。
![スクリーンショット 2021-01-04 14.27.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933264/4b47b24b-159c-6f2c-d688-f7c527ce1992.png)
上の画像で実行したのと同じ、usersテーブルから全カラムの値を取得するSELECT文を実行した場合でもphpMyAdminを使ってデータベースを使用するとデータがきれいに整形されているので、データベースの操作をした時にデータが見やすいという利点があります。
(先ほどの例え話でいうとお箸やスプーン(phpMyAdmin)を使ってご飯を食べる(データベースの操作をする)と食べにくそうな形状のご飯でも食べやすいみたいな感じです)

![スクリーンショット 2021-01-04 23.23.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933264/f91925f4-b08c-e9a7-d367-f390569111ed.png)


なので、今回qiitaに書いたMySQLモニタもよく使われるphpMyAdminもデータベースそのものではなく、あくまで**「データベースを操作する為のツールの一つ」**という事を理解しておくといいかもしれません。

以上になります！LGTMを押していただけると励みになります。
ここまで読んで頂き誠にありがとうございます！
クラウド破産じゃないけどS3の設定ミスで高級なランチ代飛んだ話

最近は余り聞かないのですが、クラウド破産という言葉がありましたが、
そこじゃないけど、高級なランチ代分余計にかかった話。

個人開発のサービスでS3は画像サーバーとして使っていたのですが、最近一寸コストが増えてきてて、「大量の画像があるし基本的に消せないけどめったにアクセスしない画像と頻繁にアクセスする画像」のが混在しててどうしようかと思ってたときに見つけたのが[intelligent-tiering]([https://aws.amazon.com/jp/blogs/news/new-automatic-cost-optimization-for-amazon-s3-via-intelligent-tiering/ )（以下IT）なるサービス。

>高頻度と低頻度という2つのアクセス階層が組み込まれています。両方の階層とも、Standard(標準)ストレージクラスと同等の低レイテンシーを提供します。モニタリングと自動化の料金を抑えつつ、S3 Intelligent-Tiering はアクセスパターンをモニタし、連続30日間アクセスされていないデータを低頻度のアクセス階層に移動します。もしそのデータがのちにアクセスされた場合は、高頻度アクセス階層に自動的に戻されます。すなわち、アクセスパターンが変化するような状況でも、性能の影響なく、運用のオーバーヘッドもなく、データ取り出しのための料金もなく、利用料金を節約することができるのです。」

と一見おあつらえ向きに見えるサービスだったためにコンソールから標準からITに設定してみましたがそれが落とし穴でした。

# 落とし穴1　えっ、移行にコストかかるの？
　一番最初の落とし穴はこれでした。IT移行させるには1000オブジェクト/0.037ドル分PUTがかかるのです。これでホテルのバイキング代一人前が飛びます。

# 落とし穴2　えっ、監視コストが結構重い
　ITに設定したオブジェクト1,000あたり/0.0025ドル監視コストがかかりますが、私の使っている環境では結構馬鹿にならないコストがかかっています。もちろん、その分安くなれば投資と見なせるのですが･･･。

# 落とし穴3　結局割高。
　監視コストが重なって結局2～3割ほど割高になりました。しばらく様子を見ようかとも思いましたが、損切り万両ということで元通りの設定に戻すことに。結局移行コスト×2でホテルのバイキング代二回分が飛ぶ（飛ぶ見通し）です。払えなくはない額ですがかなり痛い。

## コスト計算
>Intelligent-Tiering はどんなサイズのオブジェクトにも使用できますが、
128 KB 未満のオブジェクトは高頻度アクセス階層に保持されます

とあるので、まず128 KB以下のデータはとられ損ですが、東京リージョンは50TBまでは0.025ドル/GB、低頻度アクセスは0.019ドル/GBなので、差し引き0.006ドル/GB。監視コストは1000オブジェクトあたり0.0025ドルなので3000オブジェクトを越えると0.0075ドル。

すなわち3000オブジェクトを越えると0.019+0.0075=0.0265ドル/GBとなって割高となりますが、1,048,576Kb/2999=1オブジェクト平均349.64Kb未満でなければ割高のサービスです。

# まとめ
　やはり、こうしたサービスは適材適所というしかありませんが、オブジェクトの数が少なくて一つ当たりの容量が多いと予算の節約にはなると思うのですが、最適化にはかなり気を遣っていた上に、サムネイルも格納しているのでオブジェクトの数が多くて一つ当たりの容量が少ないので、監視コストが多めにかかってしまって結局コスト効果もなくただただ移行コスト2回分余計にかかる結果となりました。すぐに飛びつかずに事前の検証は本当に重要なのだと痛感しました。

　正直払えない額でもないし、ゲームに使う額を思えば･･･ってくらいなんで大人しく払いますが、本当に損をした気分です。