OmniAICreator/Qiita-1.07M huggingface dataset:
Dockerでwheneverを扱う時No such file or directory - crontabとなる

簡単に定時処理が書ける便利なgem「whenever」

dockerでアプリ作成時、wheneverを使った処理をしようとしたが、つまづいてしまったので忘備録として記述しておきます。

#環境
Ruby 2.5.1
Rails 5.2.4.3

#やりたいこと
今回はpostというモデルを用意し、wheneverを使って1分ごとにpostを作成してみる。
dockerの環境構築は終わっているものとしてスタート。


##modelとcontrollerを作成
docker上で

```
root@6181bdf78fa7:/myapp# bundle exec rails g model post name:string 
root@6181bdf78fa7:/myapp# bundle exec db:migrate
root@6181bdf78fa7:/myapp# bundle exec rails g controller posts
```

##wheneverの設定
まずはgemをインストール

```ruby:Gemfile
gem 'whenever', require: false
```

buildし直してgemをインストールしたらコマンドを実行してファイルを作成

```
root@6181bdf78fa7:/myapp# bundle exec wheneverize .
[add] writing `./config/schedule.rb'
[done] wheneverized!
```

作成されたschedule.rbに処理をかいていきます。

```ruby:schedule.rb
require File.expand_path(File.dirname(__FILE__) + "/environment")
set :environment, :development
set :output, 'log/cron.log'
ENV.each { |k, v| env(k, v) }

every 1.minutes do
  runner "Post.create"
end
```

ここまできたら、cronに設定を反映させる

```
root@6181bdf78fa7:/myapp# bundle exec whenever --update-crontab
bundler: failed to load command: whenever (/usr/local/bundle/bin/whenever)
Errno::ENOENT: No such file or directory - crontab
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:77:in `popen'
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:77:in `write_crontab'
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:38:in `run'
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:6:in `execute'
  /usr/local/bundle/gems/whenever-1.0.0/bin/whenever:44:in `<top (required)>'
  /usr/local/bundle/bin/whenever:23:in `load'
  /usr/local/bundle/bin/whenever:23:in `<top (required)>'
```

エラーが出ましたね。
cron初心者の自分はここでつまづいてしまいました。

##cronをインストール
どうやらdocker環境にcronをインストールしないといけないので、インストールに必要な処理をdockerfileに記述。
今回はこんな感じで１行追記しました。

```dockerfile
FROM ruby:2.5.1
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN apt-get install -y cron　 #この行を追記
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp
```


```
root@6710f08a3504:/myapp# bundle exec whenever --update-crontab
[write] crontab file updated
```

無事updateされてcronに反映されました。
これで自動処理が始まってると思い、しばらく待ってみます…

…どうやら動いてないですね。
wheneverが作動していればclog/cron.logが作成されるはずなので。

## cronを起動させる
cronが動いていないので状態を確認します。

```
root@827fe138767f:/myapp# service cron status
[FAIL] cron is not running ... failed!
```

やはり動いていませんでした。
起動しましょう。

```
root@827fe138767f:/myapp# service cron start 
[ ok ] Starting periodic command scheduler: cron.
```

１分後…

```ruby:cron.log
Running via Spring preloader in process 122
```

ついにcron.logが生成されlogが書かれました。
rails consoleで確認します。

```
root@827fe138767f:/myapp# bundle exec rails c
Running via Spring preloader in process 135
Loading development environment (Rails 5.2.4.3)
irb(main):001:0> Post.all.count
   (4.5ms)  SELECT COUNT(*) FROM "posts"
=> 1
```

データが生成されたのがわかりますね！

##課題
しかしcronの起動は手動で毎回行うのは面倒なので、できればdockerfileに記述して自動で起動されるようにしたいところです。
今後その方法も追記していきたと思います。
遺伝的アルゴリズムをブラウザで実行できるフレームワークの実装

遺伝的アルゴリズムをブラウザで実行するためのJavaScript用フレームワークを実装しました。

GA Framework
https://github.com/technote-space/ga-framework

テンプレートリポジトリ
https://github.com/technote-space/ga-framework-template

## 技術・特徴
### Web Worker
遺伝的アルゴリズムの計算を同じプロセスで行うとブラウザの動作が固まってしまうので [Web Woker](https://developer.mozilla.org/ja/docs/Web/API/Web_Workers_API/Using_web_workers) を使用して別プロセスで計算します。

### 欠失・挿入
遺伝子長の変化を伴う突然変異を考慮しています。

### 島モデル
多様性の保持のための島モデルを標準でサポートしています。
またテンプレートリポジトリには異文化型島モデルの考えを採用した世代交代モデルも実装しており、島のいくつかに混ぜることでより多様性が必要なネットワーク構造を持つモデルなどで有効な可能性があります（未検証）。

### Minimal Generation Gap
テンプレートリポジトリには世代交代として MGG が実装されています。
淘汰圧の強い SGA は普段使わないので用意してないですが、実装して使用することはできます。

## デモ
### Hello,World! 文字列の作成
- 遺伝子型：整数列
- 表現型：文字列

[HSP3で遺伝的アルゴリズムをした話 〜遺伝的アルゴリズムの概略と「ムダにクリエイティブ」な"Hello,World!"〜](https://qiita.com/AmefuriTell/items/74f4e7049994e26096cd)

こちらの記事の例と似たものをこのフレームワークで実装したものです。
「Hello,World!」 という文字列を作成します。

デモ
https://technote-space.github.io/ga-framework/samples/hello-genetic-algorithm/

実装
https://github.com/technote-space/hello-genetic-algorithm

![hello.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264159/dcb33007-9991-8d19-f265-66c1c1ca6979.gif)

### 離れていても心は一つ
- 遺伝子型：実数列
- 表現型：画像

[遺伝的アルゴリズムを使って「離れていても心は一つ」を自動化してみた in Python](https://qiita.com/tancematrix/items/81f059112806f1c9cd33)

こちらの記事の例と似たものをこのフレームワークで実装したものです。
いくつかの円で入力画像に近い画像を作成します。

デモ
https://technote-space.github.io/ga-framework/samples/auto-figure-ground/

![figure-out.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264159/0bea3f39-359e-cf33-e4ec-8d1418f73c64.gif)

### アルゴリズム自動生成
- 遺伝子型：整数列
- 表現型：グラフ構造

研究中のアルゴリズム生成自動化技術をこのフレームワークで実装したものです。
階乗、フィボナッチなどを求めるプログラムを自動生成します。

デモ
https://technote-space.github.io/ga-framework/samples/automatic-programming/

![auto.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264159/b37e1e66-f4be-0ff7-9eec-b031251348f0.gif)

## 利用方法の詳細
:construction: Under Construction...
Kotlin/JSプロジェクトでkotlinx-serializationを使う設定

kotlinx-serializationというは、オブジェクトをJsonなどに変換したりするライブラリ。
Kotlin/JSプロジェクトの設定方法は公式サイトを見ても分かりづらかったのでメモ。

build.gradle.ktsに以下を記述する。

```gradle
plugins {
    kotlin("plugin.serialization") version Versions.kotlin
}

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-stdlib-js:1.3.72")
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:0.20.0")
}
```

ライブラリ名に"-js"が付いているのが肝。
Elasticプロダクトの定期アップグレードをElastic Cloudで安全に行った話

# はじめに
後回しにしがちなアップグレード対応ですが、[Elasticプロダクトのサポート期間はメジャーリリースのGA/一般公開日から18か月](https://www.elastic.co/jp/support/eol)と決まっているため、定期的なアップグレードが必要です。Elastic Cloudは、無停止でアップグレードが可能ですが、より安全に実施するため今回の手順で対応しました。
Elastic Cloudのアップグレードを実施したいけど、本番影響を懸念して躊躇している方の参考になれば幸いです。

##Elasticsearchとは
オープンソースの RESTful 分散検索/分析エンジンで、Apache Lucene を基盤として構築されています。ログ分析、フルテキスト検索、セキュリティインテリジェンス、ビジネス分析、およびオペレーショナルインテリジェンスのユースケースに広く使用されています。

##Elastic Cloudとは
Elastic社が公式に運営するマネージドサービスです。

## 補足
* ver6.6.1->v6.8.10のマイナーバージョンのアップグレード
* 開発用のクラスタで事前にアップグレード後のテストは確認済み

# アップグレードの手順
1. クラスタを新規にデプロイする
2. インデックスを複製する
3. 新規クラスタに接続を切り替える
4. 既存クラスタは削除する

###1. クラスタを新規にデプロイする
アップグレードするVersionのクラスタを新規にデプロイします。
Versionは④の「Set up your deployment」の「Elastic Stack version」で選択可能です。
また、「Select a deployment to restore from one of its snapshots」を選択すればインデックスの複製が可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/470184/db50703d-f065-ac59-b15e-35e223c79b02.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/470184/63f4cb94-c068-466f-ed87-e6c93250bdd6.png)

###2. インデックスを複製する
新規デプロイした環境にスナップショットでインデックスを複製します。
デプロイ時にインデックスを複製している場合は割愛して頂いて問題ありません。
※注意) Restore snapshots時、snapshots先のクラスタは完了するまでリクエストを受け付けることが出来なくなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/470184/7f19fc09-b110-878a-42c1-fe342b8e2ca2.png)

###3. 新規クラスタに接続を切り替える
client の接続を新しいクラスタに切り替えて問題が発生しないことを確認します。
###4. 既存クラスタは削除する
正常動作確認後、既存のクラスタは不要のため削除する。

#最後に
Elastic Cloudはアップグレードで問題が発生した場合にダウングレードすることができませんが、今回の手順で、もし問題が発生した場合は既存のクラスタが存在するため、容易に切り戻しすることが可能なため、より安全にアップグレードを行うことが出来ました。

#参考
[Best practices for major version upgrades](https://www.elastic.co/guide/en/cloud/current/ec-upgrading-major.html)
Sixel試行錯誤記録

# はじめに
Sixelのエンコードを行うライブラリを自作した記録です.

Sixelそのものについては, 別の記事に譲りましょう.
仕様は, [All about sixels](https://www.digiater.nl/openvms/decus/vax90b1/krypton-nasa/all-about-sixels.text) を参照しています.

目的は, 簡単に自分のアプリケーションに取りこめ, 24ビットカラーと遜色ない品質で, リアルタイムの速度で描画できることです.

目標は,

- 400x300解像度で17msのパフォーマンスを出すこと, マルチスレッドは必須にしない
- ディザリング込みで, 視覚に対して24ビットカラー相当の品質にすること
  - 自己満足のためPSNRなどでの明確な数値目標はありません

ライブラリの設計は,

- 必要最低限のインターフェイス
    - ライブラリ用コンテキストの初期化と終了
    - 色の量子化とSixel書き出し
- カスタマイズは犠牲にする
    - 256色固定, 透過処理はしない
    - ディザリング必須
    - 動的色パレット生成のみ

処理の流れは, デバッグのし易さもあって２つに分けています.

1. 色の量子化と色パレット作成, 画像の色を色パレットのインデックスにマッピング, ディザリングとマッピング修正
2. 色パレットとインデックス化された画像をSixelエンコード, 出力

エンコードは特筆すべきことがないため, `1.`の部分を記録します.

# 色の量子化, 画像を色パレットへマッピング
この２つが切り離せません. 試行錯誤の結果をだらだらと書きます.
数値化はしていないので感覚です.

## 色の量子化

- Median-cutが品質と速度のバランスがよい
- k-meansに代表されるクラスタリング手法は, 計算コストがかかり過ぎる
    - 軽い方法で初期値を求めて, 精度を上げることも考えられるが, 全体では遅くなりそう
    - ただし, 初期値が良ければ品質の改善具合は一考に値する
  - 量子化後のマッピングに時間がかかりそう
- Octreeの基にした方法は, 量子化速度は速いが, メモリコストが高い
    - 使用メモリを事前に確保しようとするとメモリコストが高い
    - パレットへのマッピングを行う際, 8分木を再利用しようとすると計算が複雑

## 画像を色パレットへマッピング
画像のピクセル色がパレット内のどの色に対応するか決定することです.
問題としては最近傍探索になるため, 真向から挑むと難しい問題になります.
最大で256x256x256の３次元から探索するだけなので, 比較的には簡単な問題, 17ms縛りがなければ

- Kd-Tree
    - 感覚的にクイックソートに近く, 最悪の場合に全探索に近づく
    - 木の構築は少々複雑な分割基準にしたところで誤差程度の時間
    - 品質を犠牲にして計算打ち切りする指標があれば, 一考の価値あり
        - 単純に木をたどって葉を見つけただけでは, 品質に不満がある
- 荒いグリッド, 局所性鋭敏型ハッシュ
    - 悪くない. 色が対象なのでハッシュはやりすぎ

## 実装
次の論文の手法をベースにしています.
`Kanjanawanishkul, Kiattisin & Uyyanonvara, Bunyarit, "Novel fast color reduction algorithm for time-constrained applications", Journal of Visual Communication and Image Representation. 16. 311-332. 10.1016/j.jvcir.2004.07.002.`

論文からもらったアイデア,
- ３次元プレフィックスサム
- 軸毎の分散の近似

逆に採用しなかったアイデア, 
- ヒストグラムサンプルを間引く

ヒストグラムサンプルを間引かないとすると, **画像の色は３次元グリッド内のひとつに必ずマッピングされます** . 論文では32x32x32のグリッドにしています, 数個の画像で試したところ, グリッドのサイズを増やしても品質にそれほど差がない印象です.
この３次元グリッドでMedian-cutを行うことで処理負荷を軽減します.

**画像の色は３次元グリッド内のひとつに必ずマッピングされる** ことを利用すると, 色パレットへのマッピングは`O(1)`になります.

※Median-cutで空の領域を省いたりしなければ, 品質を保ってサンプル数を削減することができるかも

## ディザリング
拡散誤差法を使用します. しかし, 単純なビット数減少で量子化した場合と違い, 誤差を拡散した結果がパレット内の別の色に近づくかは保証されていないことが問題です.

単純に, 誤差を合算した値でパレットに近い色がなければ, 誤差なしの色で対応するパレット色を採用しています. それなりに効果があります.

細かいですが, 画像の外郭に拡散範囲のサイズだけ余分に確保して分岐を削減します, 処理は左から右, 右から左を１行ごとに入れ替えます.

# まとめ
簡単に美しく速くを目的に, Sixelエンコードライブラリを作成しました.
色の量子化について知見が貯まったことはいいことでしょう. 拡散誤差法の処理順入れ替えのような, ちょっとした実装における知見です.

SIMD高速化については, 測定して有効かどうか確かめながら実装しますが, 揺れ幅が大きく確信が持てないことが多いため難しいです. 書くほどのことでもないため書いていません.

RLoginからChocolate Doomを起動する.

```
$ export DISPLAY=:1
$ Xvfb :1 -screen 0 400x300x24 &
```
![sixel_doom00.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27065/64ccce67-0f90-e0ab-2afb-9936fac219a5.gif)
年齢の commit graph 作成スクリプト（git merge --no-ff の説明用）

先日投稿した記事（ [Gitで急いで戻したいならmerge --no-ffを使う](https://qiita.com/mrk461/items/81c286491546c17e9a75) ）でご紹介した、年齢のcommit graphを作成するスクリプトです

## スクリプト

```c.sh
#!/bin/sh

git init
echo '0歳' > a.txt
git add a.txt
git commit -a -m '0歳'
git tag -a age0 -m '0歳'

# 0歳に戻ります

git checkout master
git reset --hard age0
#git log --oneline --graph

# non fast-forward のcommit graphを作ります

git checkout -b youjiki master
echo '1歳' > a.txt; git commit -a -m '1歳'
echo '2歳' > a.txt; git commit -a -m '2歳'
echo '3歳' > a.txt; git commit -a -m '3歳'

git checkout master
git merge --no-ff youjiki -m '幼児期のおわり'
#git log --oneline --graph

git checkout -b youchien master
echo '4歳' > a.txt; git commit -a -m '4歳'
echo '5歳' > a.txt; git commit -a -m '5歳'
echo '6歳' > a.txt; git commit -a -m '6歳'

git checkout master
git merge --no-ff youchien -m '幼稚園卒園'
git log --oneline --graph

# 0歳に戻ります

git checkout master
git reset --hard age0
git branch -D youjiki
git branch -D youchien
#git log --oneline --graph

# fast-forward のcommit graphを作ります

git checkout -b youjiki2 master
echo '1歳' > a.txt; git commit -a -m '1歳'
echo '2歳' > a.txt; git commit -a -m '2歳'
echo '3歳' > a.txt; git commit -a -m '3歳'

git checkout master
git merge --ff youjiki2 -m '幼児期のおわり'
#git log --oneline --graph

git checkout -b youchien2 master
echo '4歳' > a.txt; git commit -a -m '4歳'
echo '5歳' > a.txt; git commit -a -m '5歳'
echo '6歳' > a.txt; git commit -a -m '6歳'

git checkout master
git merge --ff youchien2 -m '幼稚園卒園'
git log --oneline --graph

git branch -D youjiki2
git branch -D youchien2
```

## 実行結果

git merge --no-ff のグラフ

```
*   fa6cf7c (HEAD -> master) 幼稚園卒園
|\
| * 0b9ffb0 (youchien) 6歳
| * 74a3283 5歳
| * 9dfb758 4歳
|/
*   aace58b 幼児期のおわり
|\
| * 6e848f8 (youjiki) 3歳
| * 0edd54f 2歳
| * d979b3a 1歳
|/
* 798a893 (tag: age0) 0歳
```

git merge --ff のグラフ

```
* d35dd2e (HEAD -> master, youchien2) 6歳
* f758c86 5歳
* ceddede 4歳
* 88e1396 (youjiki2) 3歳
* be9c037 2歳
* 6b0691a 1歳
* 798a893 (tag: age0) 0歳
```

## 使い方
* 適当なディレクトリに設置して
* 下記スクリプトをコピペして
* 保存し
* 実行してください

```
% mkdir agegraph
% cd agegraph
% vim c.sh
% sh c.sh
```

毎回手動で作るとけっこう大変だったので、もしよかったらご利用くださいませ。
元の記事は（ [Gitで急いで戻したいならmerge --no-ffを使う](https://qiita.com/mrk461/items/81c286491546c17e9a75) ）です。
EXCEL VBAでワークシートにCREATE TABLE（ADO）

#挙動
・コネクションは普通に

```vb
    Dim cn As ADODB.Connection
    Set cn = New ADODB.Connection
    cn.Execute "Provider=Microsoft.ACE.OLEDB.12.0;" & _
               "Data Source=[fullpath];" & _
               "Extended Properties=""Excel 12.0;HDR=Yes;"""
```

・存在しないシートにテーブルは作成できない（シートは自動挿入されない。後ろに`$`を付けても同じ）

```vb
'「オブジェクト 'Sheet2' が見つかりませんでした...」エラーが返る
    cn.Execute "CREATE TABLE [Sheet2] (fieldname datatype)"   
```

・存在するシートでも、後ろに`$`を付けないとシートとして認識しない

```vb
'「オブジェクト 'Sheet1' が見つかりませんでした...」エラーが返る
    cn.Execute "CREATE TABLE [Sheet1] (fieldname datatype)" 
```

・シート名に`$`を付けたのみの場合、A1セルからフィールドが作成される

```vb
    cn.Execute "CREATE TABLE [Sheet1$] (test LONG)"
```
![test1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637201/7b90c0ef-9ea9-acc5-50bd-f5514614a2f3.png)

・新規のシートの場合、SQL文からはフィールドを1つしか定義できない

```vb
'「定義されているフィールドが多過ぎます」エラーが返る
    cn.Execute "CREATE TABLE [Sheet1$] (foo LONG, bar VARCHAR)"
```

・これは、`$`の後にレンジを指定しても回避できない

```vb
'やはり「定義されているフィールドが多過ぎます」エラーが返る
    cn.Execute "CREATE TABLE [Sheet1$A1:B1] (foo LONG, bar VARCHAR)"
```

・フィールド名をシートに予め入力しておくと、SQL文で複数フィールドを定義しても通る
![test2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637201/284d34e1-0f63-16ce-be9f-d2c1329aec5e.png)

```vb
'通る
    cn.Execute "CREATE TABLE [Sheet1$A1:C1] (foo LONG, bar VARCHAR, hoge DATETIME)"
```

・フィールド名を事前入力すれば、テーブルの場所は自由

```vb
'通る
    cn.Execute "CREATE TABLE [Sheet1$C5:D5] (poyo LONG, peyo VARCHAR)"
```
![test3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637201/ab21694b-9bdb-b43f-09b7-d94d4d88c4f2.png)

・一旦定義されたフィールド領域は記憶され、全ての領域の "上下の端" と "左右の端" を含むレンジ全ての範囲（上の例ではA1:D5）で、フィールド名の事前入力なしにSQL文からフィールド定義できるようになる（というか、定義できてしまうので混乱する）

```vb
'通る
    cn.Execute "CREATE TABLE [Sheet1$B3:D3] (a LONG, b VARCHAR, c VARCHAR)"
```

##補足
1. SQL文に記述するシートのストリングは、シートのオブジェクト名ではなく`Name`プロパティ。

2. 上の例では全てレンジを1行（＝フィールド名の行のみ）としたが、レコード領域を想定した複数行を設定することも可能。ただしその場合でも、記憶される領域（正確には、記憶される領域の基準点となり得るセル範囲）はフィールド名のセルのみ。

3. 記憶されるのは`UsedRange`的な四角い領域だが、ワークシート上の入力をクリアしても領域が変わることはない。

4. Microsoft Office Professional 2016 Excelバージョン2006での動作。
DeepRunning　～Level4.7～

#Level４．機械学習講座（理論と実践）
##4-7.サポートベクターマシン（SVM）
###4-7-1.サポートベクターマシンとは
　　●２クラス分類のための機械学習手法

　　●線形判別関数と最も近いデータ点の距離を“マージン”と呼ぶ。
　　　マージンが最大となる線形判別関数を求める。

　　●サポートベクター
　　　分離超平面を構成する学習データは、サポートベクターだけで残りのデータは不要である。

　　●ソフトマージンSVM
　　　サンプルを分離できない時、誤差を許容し、誤差に対してペナルティを与える。
　　　線形分離できない場合でも対応し、パラメータCの大小で決定境界が変化する。

　　●非線形分離
　　　線形分離できない時、特徴空間に写像し、その空間で線形分離する。

　　●カーネルトリック
　　　高次元ベクトルの内積をスカラーで表現する。
　　　特徴区間が高次元でも計算コストを抑えられる。

　　※目的関数の導出などは、別途、復習して知識を養っておく必要がある。（今後の目標）

###4-7-2.ハンズオン
　　サンプルコードをもとにして、実行して確認してみる。

![SVM0001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/c6fee4bb-c5e4-6296-980e-7d7a5729cd89.png)
![SVM0002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/5acfd358-fadf-51be-4a69-83120bc5d650.png)
![SVM0003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/e4bdd715-2665-0dff-c685-0037bf779d21.png)
![SVM0004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/dc65955a-e68c-9b28-53b2-f8a45c41d17c.png)
![SVM0005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/6ac286d3-e6b1-b71b-ea0b-ab5f71c5a5d2.png)
![SVM0006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/883de0d5-79a3-a15d-102a-4e1786b59374.png)
![SVM0007.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/d6d50a5e-5afd-43bc-f291-316cba001dd2.png)
![SVM0008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/7fd8a59f-6baa-1205-a87d-68c6365e3d64.png)
![SVM0009.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/53990468-75e1-a981-3666-437505da7b72.png)
![SVM0010.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/ba0fbf8a-a13f-0595-8a05-17d1758530f4.png)
![SVM0011.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/48435b49-efb6-d130-9a58-ed9b927b83b7.png)
![SVM0012.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/53bc4243-7694-9e02-f9ff-481b5a3aa1dd.png)
![SVM0013.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/0f7b7367-df0f-5896-5880-61da0dc537ec.png)
![SVM0014.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/b51d2fb4-2245-ca5b-e7f3-2a456075bca4.png)
![SVM0015.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/d186e2eb-cac4-5bb3-23cb-52d54a19fe88.png)
![SVM0016.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/a6c83887-6918-d8e1-ed5b-76d45e355e93.png)
![SVM0017.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640632/8d16f7ba-10b8-5d62-c2e4-95f3db3bbf3d.png)

###4-7-3.考察
　　マージンの考え方や、決定境界を可視化するやり方は、
　　誰かに説明をする時に理解してもらい易いだろうなと感じた。
　　サポートベクターマシンの・・・と言うと良く分からない人には難しく感じる。
　　誤分類の許容や、マージンとペナルティを与える適切な関係性など、
　　お試しでやってみようと思う。
Xamarin.Forms Tips - SetBackButtonTitleの使い方

#概要
NavigationPageで戻るボタンのキャプション（タイトル）が変わらない現象が起きて、
2時間くらいハマってしまった・・・
自戒の念を込めた備忘録。

#結論
SetBackButtonTitleは、
遷移前の画面で使いなさい。
以上。

#経緯
画面A→画面B→画面Cと遷移するアプリを作っていて、
画面Bと画面CでSetBackButtonTitleを呼び出していました。

画面Bの戻るボタンのキャプションが変わらない・・・
画面Cでは変わっている。

どちらもコンストラクタでSetBackButtonTitleを呼び出している・・・。
使い方に差異はないのに・・・

って悩んでました。

何のことはない。
画面AでSetBackButtonTitleを呼び出してから、
画面Bに遷移する必要があったのね・・・。
通常関数とアロー関数でのthisの違い【JavaScript】

最近JavaScriptを勉強し始めた中で`this`の使い方がイマイチぴんと来ていないので、今回は、

- **`function(){・・・}`（通常関数）**
- **`()=>{・・・}`（アロー関数）**

**の`this`の使い方の違いについてまとめます。**

# 何が違うのか？
私自身、調べる前は「`this`の範囲が違うらしい」ということくらいしか分かっていませんでした。

違いを一言で言うと、

- 通常関数の`this`は、**`function` を呼んだ時の `.` の前についているオブジェクト**
- アロー関数の`this`は、**関数の外の`this`**

を指してます。

通常関数を先に説明をします。

# 通常関数の`this`

```JavaScript
function test() {
    console.log(this)
}
var obj = {}
obj.test = test
obj.test() // => {test: ƒ}
```
`this`は`function`を呼んだ時の`.`の前についている`obj`オブジェクトとなります。

```JavaScript
function test() {
    console.log(this)
}
test() // => Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
```
オブジェクトを指定しない場合は、グローバルオブジェクトになります (non-strict モード時)。 strict モードでは `undefined` になります。

とまあ、**通常関数の場合は関数の呼び出し方に応じて`this`の中身が変わります。**下の記事に呼び出し方による違いが書いてあります。

[JavaScript の this を理解する多分一番分かりやすい説明 - Qiita](https://qiita.com/takkyun/items/c6e2f2cf25327299cf03)

記事は非常に分かりやすく書いてあります。が、実行の仕方によって`this`が変わってしまい、分かりにくくないですか？　私は読んでいて嫌になってきました。

その複雑さを改善したのが**アロー関数**のようです。

# アロー関数の`this`

アロー関数の`this`は、**関数の外側の`this`**に固定されます。

```JavaScript
const test = () => {
    return this
}
// 関数の外側のthis
const lexicalThis = this

// 関数定義したタイミングで、関数の外側のthisを参照する
console.log(test() === lexicalThis) //=> true

// メソッドとして実行しても、thisはメソッドが属するオブジェクトを指さない
const obj = { method: test }
console.log(obj.method() === obj) //=> false
console.log(obj.method() === lexicalThis) //=> true
```
先ほどの通常関数の`obj.test()`は`this`=`obj`として扱っていたのに対して、アロー関数の`obj.test()`は`this`=`lexicalThis`（関数の外側の`this`）として扱っていることが分かります。
**アロー関数の`this`は、`.`前のオブジェクトは指さず、必ず関数の外側の`this`を指します。**

また、強制的にあるオブジェクトと結びつける`bind`等も無視するようです。通常関数では有効です。

```JavaScript:通常関数のbindの例
function test() {
    console.log(this)
}
var obj = { name: "obj" }
var check = test.bind(obj)
check() // => {name: "obj"}
```

# まとめ
通常関数は、さまざまな参照の仕方があるため汎用性があるが、`this`の対象が実行の仕方によって変動してしまう。
一方、アロー関数は、参照するオブジェクトに制約があるものの、オブジェクトが決まっているため分かりやすい。

使用上の注意としては、

- アロー関数を使うときは、間違ってオブジェクトのメソッドとして使わないようにする。
- 通常関数を使うときは、`this`が使い方によって変わることに気を付ける。

以上の２点でしょうか。

アロー関数で書くと格好よく書けるなー、としか思っていませんでした。
思った以上に様々な制約があり、他の違いもしっかり知っておく必要があると感じました。

# 最後に
通常関数とアロー関数の違いは`this`の使い方だけではありません。
その他の違いについてはこちらをご覧ください。
[JavaScript: 通常の関数とアロー関数の違いは「書き方だけ」ではない。異なる性質が10個ほどある。 - Qiita](https://qiita.com/suin/items/a44825d253d023e31e4d)


初投稿で拙い文章となってしまいましたが、最後までお読みいただきありがとうございました。
何か誤り等ありましたらご指摘ください。
PythonのURL結合にはos.path.joinではなくurlparse.urljoinを使う

PythonでcsvファイルからURL一覧を取得して、そのURLを結合させたいときに躓いたのでメモ

### うまくいかなかった方（os.path.join）

```py3
import os.path

channel_urls = ['/channel/UCVrJcoR8hUN9Rn7uPI4z6NQ']

for i in channel_urls:
    root_url = 'https://www.youtube.com'
    channel_url = ('%s' % i)
    channel_about_url = urlparse.urljoin(youtube_url, channel_url, 'about')
    print(self.open_channel_url)

# /channel/UCVrJcoR8hUN9Rn7uPI4z6NQ/about           // 「https://www.youtube.com」が入らない
```

### うまくいった方（urlparse.urljoin）

まずはモジュールをインストール
（以下のコマンドたちは`$ histroy`の出力結果から拾ったので、全部必要だとは限りません）

```tamenal.
$ pip3 install urllib3
$ pip install git+https://github.com/mitsuhiko/flask-oauth
$ pip install urlparse3
```

ソース

```py3:sample.py
try:
    import urlparse
except ImportError:
    import urllib.parse as urlparse

channel_urls = ['/channel/UCVrJcoR8hUN9Rn7uPI4z6NQ']

for i in channel_urls:
    root_url = 'https://www.youtube.com'
    channel_url = ('%s' % i)
    channel_about_url = urlparse.urljoin(youtube_url, channel_url, 'about')
    print(self.open_channel_url)
# https://www.youtube.com/channel/UCVrJcoR8hUN9Rn7uPI4z6NQ/about
```


参考
https://qiita.com/Go-zen-chu/items/d7e6b9af0bd90c7aabca
https://www.it-swarm.dev/ja/python/python%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%ABurlparse%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%9B%E3%82%93/961197002/
https://github.com/heroku/kafka-helper/issues/6
[rails]redirect_toとrenderの違い

#redirect_toとrenderの違い
初めの頃は違いなんて理解せずに使ってました。
処理の流れが違ったんですね。

##redirect_toの場合

```
①controller（redirect_to）　→ ②HTTPリクエスト　→　③ルーティング　→　④controller　→　⑤view
```

##renderの場合

```
①controller　→　②view
```

僕の感覚ではあるんですが、基本的にrenderは部分テンプレート以外であまり使わない気がします。
elasticsearchのコンテナが137エラーで立ち上がらない

### はじめに

elasticsearchでdockerコンテナを立ち上げても下記のエラーで立ち上がらないので、原因＆解消方法を探る

```
elasticsearch exited with code 137
```

```yml:dockerfile
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.1.1
    expose:
      - 9200
    ports:
      - "9200:9200"
      - "9300:9300"
    tty: true
    environment:
      discovery.type: single-node
```

### エラーコード137とは

OOM（メモリが足りない）が原因で、コンテナがSIGKILLされているようだ
https://success.docker.com/article/what-causes-a-container-to-exit-with-code-137

OOM状態の処理に関しては、ノードのカーネルログを確認してみる

```bash
journalctl -k | grep -i -e memory -e oom
# 実行結果
Out of memory: Kill process 19824 (java) score 116 or sacrifice child
```

もしくは落ちてしまったコンテナの詳細をみることもできる

```
docker inspect <container ID>
```


### メモリの上限を設定する

公式のリファレンスに書いてある
https://www.elastic.co/guide/en/elasticsearch/reference/current/heap-size.html

起動時のヒープサイズと最大ヒープサイズは物理メモリによって決める
起動時のヒープサイズと最大ヒープサイズは物理メモリの50%以下に設定するといいみたい
Xmx設定で構成された制限よりも多くのメモリを使用してElasticsearchプロセスを監視する必要がある


では、自分の環境で物理メモリはどれくらいあるか見てみると

```bash
free -m
# 実行結果
              total        used        free      shared  buff/cache   available
Mem:           7803        5325         536         163        1940        1816
Swap:          4095        2221        1874
```

１GBまでならelasticsearchのコンテナに当てられそう

では、実際に起動時のヒープサイズと最大ヒープサイズを設定する
ES_JAVA_OPTSの環境変数に値をセットすればいい

### と、その前にヒープ領域に関して簡単に復習

#### ヒープメモリ

大きくつの領域がある

- new領域（短命なオブジェクト）
- old領域（長生きオブジェクト）
- permanent領域（クラスを保持する）
 
さらに、new領域にはeden、from、toの3つの領域があり、edenがいっぱいになったら、fromもしくはto領域にオブジェクトを移動する
そしてさらに、移動回数が多いオブジェクトはold領域へ移動する

#### GC

ヒープ領域を掃除するGCについても大きく2つタイプがある

- Scavenge GC（NEW領域のみを対象とした短時間で終了するガベージ・コレクションであり、頻繁に実施）
- Full GC（NEWとOLD両方の領域を対象とした大がかりなガベージ・コレクションであり、比較的低い頻度で実施）

（参考： https://www.atmarkit.co.jp/ait/articles/0504/02/news005_2.html）


### 本題に戻ってヒープ領域を制限する

ES_JAVA_OPTSでXmsとXmxをそれぞれ500MBで設定する

```yml:dockerfile
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.1.1
    expose:
      - 9200
    ports:
      - "9200:9200"
      - "9300:9300"
    tty: true
    environment:
      discovery.type: single-node
      ES_JAVA_OPTS: -Xms500m -Xmx500m
```

そして、実際にメモリ使用量が減ったか見てみると

```bash:変更前
ps aux | grep elastic
# 実行結果
1000     115726  1.2 16.6 4803048 1329072 pts/0 Ssl+ 13:51   7:01 /usr/share/elasticsearch/jdk/bin/java -Xms1g -Xmx1g ・・・ override=/ -Xms1g -Xmx1g ・・・
```

```bash:変更後
ps aux | grep elastic
# 実行結果
1000      27147  231  9.4 3789796 753308 pts/0  Ssl+ 23:41   0:23 /usr/share/elasticsearch/jdk/bin/java -Xms1g -Xmx1g ・・・ override=/ -Xm500m -Xmx500m ・・・
```

変更後の方は、XmsとXmxの値がoverrideされて、
変更前はメモリ使用率が16.6%だったのが、9.4%まで落ちているのがわかる！
これでOOMで落ちることはない！

Let's start programming elasticsearch!!
Unsupervised Learning of Visual Features by Contrasting Cluster Assignments のメモ


Mathilde Caron, Ishan Misra, Julien Mairal, Priya Goyal, Piotr Bojanowski, Armand Joulin

- https://arxiv.org/pdf/2006.09882.pdf
- facebook AI とInriaのチーム

## 概要
- SwAV という手法を提案 - 教師なし学習の一種
- Swapping Assignments between multiple Views of the same image の略
- pairwise の比較を用いないContrastive learning
- 同じ絵の異なるaugmentationがクラスタになるようにする
- 大規模データでもうまくうごく
- メモリバンクやモメンタムエンコーダを使わない
- 関係ないけどmulti-cropというaugmentation手法も提案、複数の解像度の画像を使う

## 手法
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412142/62bd49d1-c03b-bc82-2fa9-a201eaeb7a7b.png)

- latent $z_t$ と $z_s$ から code $q_t$と$q_s$を作る。$q_t$と$q_s$ をクラスタのプロトタイプ{$c_1$ .. $c_k$}とマッチさせる。

- ロスは下記。つまり、$z_t$から$q_s$を予測、$z_s$から$q_t$を予測する。
   $L(z_t, z_s) = l(z_t, q_s)+l(z_s, q_t)$
  

ここで$l(z, q)$ は下のように定義される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412142/34f67251-5b72-5833-bede-7ed55c279be4.png)

$p_t^{(k)}$ は個々のクラスタプロトタイプと$z$の内積のsoftmaxになっている。

### コードのクラスタリング
zからqをつくるところで、クラスタプロトタイプにマッチさせるのだが、そのときに、偏りがないようにすべてのクラスタタイプにバッチ内のデータを均等に割り当てる。こうすることで、collaptがおきないようにしている。

## 所感
まったくよくわかっていないのだけど、方向性としてはBOYLとよく似ている。BYOLがモメンタムエンコーダを使うことで、Collaptを防ごうとしているのに対して、こちらはクラスタ割当に制約を与えることで回避している、ということなのだろうか。
構造は簡単だが、クラスタリングのところでかなり凝ったことをしているようだ。計算量が見当つかないが、GPUで高速に計算できる、と書いてあるので問題ないのか。
pythonのrequestsでAPIGateWayをAPIKeyを使って呼び出す

## 概要

ローカルのpythonのプログラムからリクエストを送信してAPI Gateway を呼び出せるかを試してみました。
APIKeyを設定することで呼び出しを制限できるので呼び出しを制限することができます。
処理呼び出し用の画面でも作ってそこのアクセス制限をしてしまう方が楽な方が気もしますが・・・


## APIGateWayの設定
* Lambda関数を作成し、トリガーにAPIGateWayを設定するときに↓のように `REST API` を指定してセキュリティを `API Key` にします
![コメント 2020-08-02 235214.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657697/eaaac17a-b09a-3f84-0570-f858bc40d54a.png)

* APIGateWayの方では `メソッドリクエスト` から `APIキーの必要性` を `true` に変更します。
![コメント 2020-08-02 235424.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657697/96015048-6c59-02f6-8ff8-4467329a96bf.png)

* アクションからAPIのデプロイを行う

## 呼び出すPythonのプログラム

* ↓のようにrequestsを使ってheadersにAPIKeyを設定すれば呼び出すことができます。

```python
import requests
import traceback

if  __name__ == "__main__":
    try:
        
        # APIKeyはAPIGatewayで確認したAPIKey
        headers = {'x-api-key': 'APIKey'}
        # xxxxxxxx の部分は各APIの値 /test2 の部分はリソース名を指定ここでは greet
        url='https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/default/test2'
        # 成功のパターン
        rSucess = requests.get(url, headers=headers)
        print(rSucess.status_code)
        print(rSucess.content)

        # 失敗のパターン
        rFail = requests.get(url)
        print(rFail.status_code)
        print(rFail.content)

    except :
        print(traceback.format_exc())
```

* 呼び出した結果は↓のように1つ目はapikeyがあるため結果が返ってきますが、2つ目はapikeyがないため失敗となります。

```
200
b'"Hello from Lambda!"'
403
b'{"message":"Forbidden"}'
```
bashでYouTubeライブのコメント(チャットのリプレイ)をサクッと取得する

# 事前の準備
- ライブ配信アーカイブの`/live_chat_replay?continuation=XXX` XXX部分の値を取得する

![ScreenShot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18613/27aa4932-55be-b8a5-106d-8577ed4e21a4.png)


# Script

```bash

#/bin/bash

NEXT_URL=${1}

readonly API='https://www.youtube.com/live_chat_replay?continuation='

readonly UA='User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'

readonly TS=$(date +%s)

function get_comment_json(){
  curl -s -H "${UA}" ${1} | \
  grep 'responseContext'| \
  sed -e 's/window\["ytInitialData"\]\ =\ //' -e 's/;$//' \
  > /tmp/out.json
}

function output_comment(){
  cat /tmp/out.json |jq -r '.continuationContents[].actions[].replayChatItemAction.actions[].addChatItemAction.item.liveChatTextMessageRenderer| [.timestampText.simpleText , .authorName.simpleText , .message.runs[0].text , .message.runs[1].text]|@tsv' 2>/dev/null| \
  awk -F '\t' '{print $1 "\t" $2 "\t" $3 $4 }' \
  >> ./comment_${TS}.tsv 
}

while [ "${NEXT_URL}" != 'null' ]
do
  get_comment_json ${API}${NEXT_URL}
  output_comment
  NEXT_URL=$(cat /tmp/out.json |jq -r .continuationContents.liveChatContinuation.continuations[0].liveChatReplayContinuationData.continuation 2>/dev/null)
  sleep 1
done

rm /tmp/out.json

exit 0
```

# 実行
- 事前準備で取得したXXXを第一引数で実行する

```
% bash ./run.sh XXX
```

# 実行結果
```
% head -n 20 ./comment_*.tsv
		
-0:04	M M	来ました！笑
-0:01	寒色系ブルー	おつ
-0:01	しゅーへー	あ
0:00	アルカディア	おお！
0:06	私はダメです	！
0:07	Rena	こんばんは
0:07	REX	えいやっさ！
0:10	。 a	楽しみ〜
0:10	y t	きた！
0:10	ずんだ	はよ
0:11	ルビリアルビィ	こんばんは！
0:12	天下の大泥棒石川五右衛門	おお
0:12	しゅんちゃん!	！
0:12	。くろ	やべぇ！
0:13	きなこきなこ	いぇい
0:13	黒崎嶺二	こんにちは
0:15	渡邉りさちゃん	あああああ
0:16	ふにゃっしー	こんばんはわ
0:17	しゅーへー	にコメ
```
link_toの下線を消す

#プログラミングの勉強日記
2020年8月3日　Progate Lv.226
aタグと同じようにlink_toの下線を消す。（メモ）
HTMLのリンクについては[こちらの記事](https://qiita.com/mzmz__02/items/2ac88037d8f99bee5ac8)で扱っている

#方法
　1.`link_to`にクラスを付ける。

```erb:layouts/application.html.erb
<li>
  <%= link_to("User List", "/users/index", class:"userList") %>
</li>
```

　2. scssファイルまたはcssファイルで下線を消す処理をする

```css:stylesheets/application.css
.userList{
  text-decoration: none;
}
```
[rails]バリデーションを設定

#バリデーションとは
パラメーターを受け取った時に該当カラムにデータが入っているか確認する機能です。

以下の例の場合、nameカラムがnil(データがない)であるかどうかを確認します。
nilだと保存されません。

```app/models/user.rb
class User < ApplicationRecord
 
  validates :name, presence: true
  
end
```
RAIDとは

#RAIDとは

- **R**edundant **A**rrays of **I**nexpensive **D**isksの略で、サーバーに用いられる技術で、ハードディスクを複数台用意し1台が故障してもサーバーの稼働を止めないようにする技術のこと。

- 昨今のRAIDは主に「安全性の向上(故障対策)」として用いられているが、**「容量の向上(大容量化)」**、**「速度の向上(高速化)」**というメリットもある。

- RAIDを実現するには、「RAIDコントローラ」と呼ばれる専用のカードを用いる。このカードを通じてハードディスクの読み書きを制御する。
この制御にはいくつかの種類があり、それぞれ「RAID X(Xには数字が入る)」のように分類される。
Amazon Sagemakerで作成したモデルによる推論処理をREST APIとして公開する

#やったこと
SageMakerで作成したモデルを使った推論処理をREST APIとして公開してみた。

#構成
API Gatewayで公開されるAPIにアクセスし、Lambdaを実行。LambdaからSageMakerで作成したModelをエンドポントから呼び出し、推論処理を実施、リクエスト側に結果を返す、という感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187747/a5ab192f-be98-4b22-cfe6-43a9c3371cf0.png)

#構築手順
1. SageMakerで学習モデルを作成
2. モデルをデプロイ＆エンドポント作成
3. LambdaからSageMakerのエンドポイントを呼び出すためのロールを作成する
4. Lambda関数実装
5. Amazon API Gateway設定
6. CurlでREST APIの動作確認

1,2だけでかなりの量になるので別で執筆中。
以下、3以降について記載。

## 3. LambdaからSageMakerのエンドポイントを呼び出すためのロールを作成する
LambdaからSageMakerのエンドポイントにアクセスするためにロールを作成します。ここの記載がない記事が多かったので、あえて設定手順記載。

1. サービスから「IAM」を選択
2. ナビゲーションから「ロール」を選択し「ロールを作成」をクリック
3. ユースケースの選択でLambdaを選択して「次のステップ」  
ここではどのサービスにロールを割り当てるか、を考えます。今回、Lambdaにロールを割り当てるのでLambdaを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187747/9eaafaab-717f-0e0d-4a66-13f996f8a722.png)
4. ポリシーのフィルタで[sagemaker]と入力。「AmazonSageMakerFullAccess」を選択して「次のステップ」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187747/85aecc82-bab8-ffeb-d105-47264cfd3f73.png)  
ちなみに、ポリシー名をクリックするとこのポリシーのアクセス権限を確認することができます。"Statement"の中をみると、
`"Effect": "Allow","Action": ["sagemaker:*"],"`の記載があり、これはsagemakerに対するあらゆるアクションを許可するという意味です。これによりLambdaからモデルのエンドポントを呼び出すことができるようになります。
5. ロール名を指定して、ロールの作成をクリック


## 4. Lambda関数実装
Lambdaでは推論処理を実装します。下記のような感じで、言語は今回pythonで記載しました。

```
import boto3

ENDPONT_NAME = "YOUR_ENDPOINT_NAME" #ここにはエンドポイントの名前を指定する


def lambda_handler(event, context):
    runtime_client = boto3.client('runtime.sagemaker', region_name="ap-northeast-1")
    values = list(event.values())
    
    try:
        response = runtime_client.invoke_endpoint(EndpointName=ENDPONT_NAME, 
                                   ContentType='text/csv', 
                                   #Body=value_single)
                                   Body='{0},{1},{2},{3}'.format(values[0], values[1], values[2], values[3]))
                                   
        result = response['Body'].read()
        result = result.decode("utf-8")
        return result
        
    except:
        return {
            'statusCode': 400,
            'body': 'Exception Occur'
        }

```


## 5. Amazon API Gateway設定
[ここ](https://dev.classmethod.jp/articles/getting-start-api-gateway/)を参考に設定を済ませました。

## 6. CurlでREST APIの動作確認
さくっと確認

```
> curl --request POST --header 'Content-Type: application/json' --data '{\"key1\":0.25,\"key2\":0.666,\"key3\":1,\"key4\":1}' 'https://your-api'
curl: (6) Could not resolve host: application
curl: (1) Protocol "'https" not supported or disabled in libcurl
```
あれ、なんで。
調べてみると、windowsターミナルではシングルクオーテーションが使えないみたい。
[Windows 環境における curl コマンド利用のまとめ (平成最終版)](https://qiita.com/yamachan360/items/8c928738289cd518eec8)がわかりやすかった。

修正して、もう一度実行。

```
> curl --request POST --header "Content-Type: application/json" --data "{\"key1\":0.25,\"key2\":0.666,\"key3\":1,\"key4\":1}" "https://your-api"
"106.2766342163086"
```

ふぅ。OK。
Atcoder ABC176 (A,B,C,E)をPythonで解く

テスト中解けたのはA,B,Cの3問。D,Eはコンテスト中はTLEでした。

# A - Takoyaki

コメント：特になし

```python
N, X, T = map(int, input().split())

if N % X == 0:
    print(N // X * T)
else:
    print((N // X + 1) * T)
```

# B - Multiple of 9

コメント：特になし（Aより簡単・・？）

```python
N = int(input())

if N % 9 == 0:
    print("Yes")
else:
    print("No")
```

# C - Step

コメント：特になし

```python
N = int(input())
A_L = [int(x) for x in input().split()]

ans = 0
_a = A_L[0]
for i in range(1, N):
    _ca = A_L[i]
    ans += max(_a - _ca, 0)
    _a = max(_ca, _a)

print(ans)
```

# D - Wizard in Maze

コメント：幅優先探索か深さ優先探索かどちらを使えばいいかがわからず、
とりあえず実装が楽な深さ優先探索を使ってみたがTLE。
解説を見たところ、幅優先探索で解くみたいなので、時間があるときに
幅優先探索で解きなおす。

```python
# TLE
import sys

sys.setrecursionlimit(10**9)

H, W = map(int, input().split())
C_L = [int(_)-1 for _ in input().split()]
D_L = [int(_)-1 for _ in input().split()]
S_L = [[x for x in input()] for y in range(H)]


ans = 0
c_l = [[float("Inf")] * W for _ in range(H)]


def dfs(x, y, c):
    if not(0 <= x < W) or not(0 <= y < H) or S_L[y][x] == "#":
        return
    if c_l[y][x] > c:
        c_l[y][x] = c

        # no magic
        dfs(x+1, y, c)
        dfs(x-1, y, c)
        dfs(x, y+1, c)
        dfs(x, y-1, c)

        # use magic
        for _x in range(-2, 3):
            for _y in range(-2, 3):
                if (_x == -1 and _y == 0) or (_x == 1 and _y == 0)\
                        or (_x == 0 and _y == -1) or (_x == 0 and _y == 1)\
                        or (_x == 0 and _y == 0):
                    continue
                dfs(x+_x, y+_y, c+1)


dfs(C_L[1], C_L[0], 0)

if c_l[D_L[0]][D_L[1]] == float("Inf"):
    print("-1")
else:
    print(c_l[D_L[0]][D_L[1]])
```

# E - Bomber

コメント：解き方は単純だったが、コンテスト中はlistで実装していたため、TLEになった。
listとset,tupleの速度面での使い分けをこれまで意識していなかったので、今後は気を付ける。

## TLEとACの違い
### TLE
```python
HW_L = [[int(x)-1 for x in input().split()] for y in range(M)]
```

### AC
```python
HW_L = set(tuple(int(x)-1 for x in input().split()) for y in range(M))
```

## 全体コード

```python
H, W, M = map(int, input().split())
HW_L = set(tuple(int(x)-1 for x in input().split()) for y in range(M))

w_l = [0] * W
h_l = [0] * H

for _hi, _wi in HW_L:
    w_l[_wi] += 1
    h_l[_hi] += 1

max_h = max(h_l)
max_w = max(w_l)

h_idx = [i for i, x in enumerate(h_l) if x == max_h]
w_idx = [i for i, x in enumerate(w_l) if x == max_w]

ans = max_h + max_w - 1

for hi in h_idx:
    for wj in w_idx:
        if (hi, wj) not in HW_L:
            ans = max_h + max_w
            break
    else:
        continue
    break

print(ans)
```
fusion360で滑車のモデルを作って見よう！！-その１:輪を作る

#この記事の対象者
・fusion360を入れたけど何をして良いのか分からない人
・3Dプリンターを買った人、買いたい人
#fustion360を入手する
この**fustion**はインストールするのが信じられないくらい、難しいのでこちらの[サイト](https://cad-kenkyujo.com/fusion360/install/)を参照して下さい。
※ただしこれで上手く行かない可能性も有ります。これで上手く行かなかったら自力でやって頑張って下さい。いずれダウンロード方法を記事にします。

#fustionの画面を自由自在に動かそう
インストール出来たら、実際に起動して見ましょう。起動するとこんな感じの画面が表示されるはずです。
![スクリーンショット 2020-08-22 22.58.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581846/ebdc0b53-2c0f-0973-7ed1-ef739ec12f69.png)
そしたら始めに操作について軽く説明します。まずは右上にある四角いキューブについて説明します。これは簡単に視点移動が出る物で例えは上と書いてある所をクリックすると上の視点に切り替わります。視点が変になってしまった時はこれを使って視点を戻すと便利です。次にオービットについてです。左下にある矢印が二つ重なっているアイコンをクリックしてからボタンを押したままカーソルを移動させると視点を立体的に動かせます。最後に左下から3番目にある画面移動です。これは名前の通りボタンを押したままかーするを移動させると視点を水平に動かす事が出来ます。これで視点を切り替える時に使うツールの紹介は終わりです。
#スケッチを使って見よう！！
次はスケッチと言う機能を使っていよいよモデルを作って行きます。始めに右端のスケッチを追加をクリックしてモテ下さい。そうするどの視点で編集するか選べるのでカーソルで視点を決めてクリックします。![スクリーンショット 2020-08-22 23.14.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581846/77adef2c-21ab-182b-94d3-4dd831f57215.png)
これでスケッチの準備は出来ました。早速スケッチを書いて行きましょう。まずは滑車の円をスケッチして行きます。なのでまずは右端の線分をクリックして、中心に点をカースルを合わせてクリックです。(間違った所でクリックした時はコマンド+Zで操作を取り消す事が出来ます。)今回の円は直径4戦地の物を作るので始めに半径の20ミリをX軸と並行に引きます。指定の場所に来たと思ったらそこでクリックです。そしてこれを続けて図形を作って行きます。今回の円の高さは4ミリです。写真を参考にやって見て下さい。
![スクリーンショット 2020-08-22 23.24.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581846/80bd3a6c-6961-e69c-da1d-842910f0b8e9.png)
ここまで出来たら、スケッチを終了のボタンを押して元に戻りましょう。次に左端から3つ目の回転を押し緑の線を選んでOKを押して下さい(ここで、操作が新規コンポーネントになっている事を確認して下さい。)
![スクリーンショット 2020-08-22 23.30.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581846/6c75cd94-d3f2-d994-82d6-a536547e0d5a.png)
次はこの円に穴を開けます。先ほどと同じようにスケッチを押して下さい※今回はキューブの前の視点で作業するので必ず前をクリックして視点を切り替えて下さい。スケッチを軽くして行きます。今度は右から3番目の円のようなアイコンを押して中心にカーソルを移動させて10mmと入力が出来たらenterを押してスケッチを終了させてくだいさい。
![スクリーンショット 2020-08-22 23.35.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581846/730959c9-b94d-efcf-1133-85d154ce62ae.png)
戻ったら左から2番目の押し出しをクリックして下さい。操作を切り取りにして距離を4mmと入力してOKを押すと滑車の円が出来ました。
![スクリーンショット 2020-08-22 23.40.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581846/25eb262d-08f1-1f9d-33fd-eac1c0c5d6d5.png)
これで今回の目標は達成です。
#終わりに
初めての3Dモデルについての解説だったので、間違いを指摘してくれると嬉しいです。
AtCoder 生活　94日目

[前回](https://qiita.com/flandrescarlet237/items/7e61c3da3bf0c659f72f)

#94日目
ABC176に参加しました。

![スクリーンショット 2020-08-22 22.46.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606053/ba158d09-045a-52ae-873d-5bdd59751f39.png)

##[ABC176](https://atcoder.jp/contests/abc176)

###A

```c++

#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0;i < (n);i++)
using namespace std;
using ll = long long;
using pii = pair<int,int>;

const int INF = 2e9;

int main(){
    int n,x,t;
    cin >> n >> x >> t;
    int ans = (n/x)*t;
    if(n%x != 0) ans += t;
    cout << ans << endl;
}

```

###B

```c++

#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0;i < (n);i++)
using namespace std;
using ll = long long;
using pii = pair<int,int>;

const int INF = 2e9;

int main(){
    string n;
    cin >> n;
    ll h = 0;
    rep(i,n.size()){
        int a = n[i];
        a -= 48;
        h += a;
    }
    if(h%9 == 0)cout << "Yes" << endl;
    else cout << "No" << endl; 
}

```

###C

```c++

#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0;i < (n);i++)
using namespace std;
using ll = long long;
using pii = pair<int,int>;

const int INF = 2e9;

int main(){
    int n;
    cin >> n;
    vector<int> a(n);
    rep(i,n) cin >> a[i];
    ll ans = 0;
    ll b = 0;
    rep(i,n){
        if(b > a[i]){
            ans += (b - a[i]);
            a[i] = b;
        }
        else b = a[i];
    }
    cout << ans << endl;
}

```

###最後に
Bで少し時間がかかってしまった。
saveとsave!の違い

備忘録です！！

saveとsave!,destroyとdestroy!の違いを説明していきます。

saveとsave!の違いは「処理が失敗した時の挙動」です。

saveの場合・・・falseを返す

saveの場合・・・例外が発生する。

簡単に説明すると

『処理が失敗する可能性が想定されて、失敗した場合に何かハンドリングしたい場合』はsaveを使う

『処理が必ず成功すると想定されていて、万が一失敗したらそこで処理を中断したい場合』はsave!を使う

例えば、userを登録するときは、バリデーションに引っかかることがあり、失敗する可能性があるので、saveを使います。

destroyでユーザーを削除するときは、必ず成功する、失敗することが考えられないので、destroy!を用います。
掲示板の削除と編集

備忘録です！

#boardコントローラーの追加

```ruby:boards_controller.rb
def edit
  @board = current_user.boards.find(params[:id])

def update
  @board = current_user.boards.find(params[:id])
  if @board.update(board_params)
      redirect_to board_path(params[:id]), success: t('defaults.message.edited', item: Board.model_name.human)
  else
      flash.now['danger'] = t('defaults.message.not_edited', item: Board.model_name.human)
      render :edit
  end
end

def delete
  @board = current_user.boards.find(params[:id])
  @board.destroy!
  redirect_to boards_path, success: t('defaults.message.deleted', item: Board.model_name.human)

```

今回は、他人の作成した掲示板の編集ページにアクセスした場合は404エラー(ActiveRecord::RecordNotFound)となるように実装したい.

```
@board = Board.find(params[:id])
```
とすると、全てのboardのから情報を取得できてしまう。
なので、

```
@board = current_user.boards.find(params[:id])
```
current_userを用いることで、現在ログインしているユーザーが所有しているboardのみからしか情報を取得できないため、自分の投稿でない場合、ページに転移することも、編集することも、削除することもできない。

##HTMLのdata属性

データを削除するときに、「本当に削除してよろしいですか？」質問され、「はい」というボタンを押したら削除できるように実装していきます。

```
<%= link_to 'リンク', ○○_path, data: { confirm: 'ダイアログで表示させるメッセージ' } %>
```

こちらでダイアログを出せるので、今回は、

```
<%= link_to board_path(board.id), id: "button-delete-#{board.id}", method: :delete, data: {confirm: '本当に削除してもよろしいです'} do %>
  <%= icon 'fas', 'trash' %>
<% end %>
```

とします。
RDSのテーブル確認方法

## 手順
- EC2インスタンスにSSHで入る。

```
$ ssh -i [鍵ファイルへのパス] ec2-user@[EC2のパブリックIP]
```
- AWSのRDSから、対象のDBインスタンスのエンドポイント・使用ポートを確認。

- MYSQLに接続。(MYSQLの場合)

```
[ec2-user@ip... ~]$ mysql -h [エンドポイント] -P [ポート番号] -u [ユーザ名] -p
```
[scala] 乱数でグループ分け

乱数でトラフィックを２つのグループに分ける実装を行なった。

## 実現したいこと

新ロジックの既存コードに適応させたい。
しかし一気に総トラフィック100%に新ロジックを適応させると、売上毀損のリスクがある。
総トラフィックの10% ~> 100%といった、ランプアップ方式で新ロジックを効果測定しながら、適応していきたい。


以下のように総トラフィックを分けたい。

```
新ロジック　  -> 総トラフィックの10%
既存ロジック  -> 総トラフィックの90%
```


## ソリューション

0 ~ 99の整数をランダムに作成し、0 ~ 9の時は新ロジック。10 ~ 99の時は既存ロジックに、トラフィックが流れるようにする。

## 実装

```scala

val trafficRatio = 10  // 100%中、何%で新ロジックに振り分けるのか
val random = new Random()

val randomNum = random.nextInt(100)

if(randomNum < trafficRatio) {
  // 新ロジック
} else {
  // 既存ロジック
}

```

## 他の方法
トラフィックを振り分ける手段は、ELBを使ったり、[VWO](https://vwo.com/)といったツール使ったりなど、様々な手段があるが一番工数がかからない手法！！
【vi】Tera Termから仮想マシンへの接続方法

##【viコマンド入門】viコマンド入門

##Tera Termから仮想マシンへの接続方法
①　centos8 にipアドレスを設定して、teratermから接続。
　　ネットワークアダプタを「ホストオンリーアダプター」に設定にしておく。
②　centos8でコマンドプロンプトで、ip addrでipアドレス確認。
③　インタフェースenp0s3に、IPアドレス10.0.*.*（192.168.*.*）が振られているのを確認。
④　Windows10のコマンドプロンプトから、pingを打ち接続されている確認。
　　※タイムアウトにならなければ次へ
⑦　ip aを入力し、IP アドレスが設定されていることを確認。
⑤　ホスト名はIPアドレス、TCPポートは22番を設定。OK。
⑥　ユーザ名とパスワードを入力。oK。

##コマンド一覧
viエディタ使用するためのコマンド

vi　存在しないファイル名を指定した場合、新規作成される。
i　　挿入モード。左下に INSERT の表示が出て、編集可能になる。
ESC　押下すると編集状態を解除。
:wq　編集内容を保存し、viエディタを終了する。
ls　　ファイルの表示。

※「./ファイル名」を実行すると、ファイルに記載されたコマンドの実行。
　　シェルスクリプト = ファイル名

##事前設定
・virtualboxにCentOS8をインストールしていること
・teraterm をインストールしてあること

##参考文献
この記事は以下の情報を参考にして執筆しました。
[NetworkManager 使用方法（nmtui編）](https://www.server-memo.net/centos-settings/network/nmtui.html)
[Tera Termから仮想マシンへログインする](http://free-money.hatenablog.com/entry/2017/12/10/224424)
Android Studio 4.1 RC1で公式日本語パックの導入と文字化けを解消する

# はじめに

Android Studio 4.1系からIntelliJ IDEAのベースバージョンが2020.2に上がったので公式の日本語パックを導入できるようになりました。ですがランタイムが古く文字化けしてしまうので解消します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8995/7e6e1a7a-b13f-ae6f-8db0-145470c8bcf3.png)

手順とランタイムの最新バージョンは以下のリンクで確認できます。

- [JetBrainsデスクトップ製品の日本語化](https://samuraism.com/jetbrains/localization)
- [Android Studio 4.1 Beta 1で文字化けが発生する](https://youtrack.jetbrains.com/issue/IDEA-244137)
- [JetBrains Runtime](https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime)

# ランタイムを変更する

1. PluginsのMarketplaceタブからChoose Runtimeをインストールする。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8995/0a620a85-50e4-723f-1339-1eab25f6d3d3.png)
1. Ctrl + Shift + AでFind Actionを開いてchooseを入力して絞り込む。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8995/9f6af2af-1537-cc49-b209-afe6cfcafc49.png)
1. Choose Runtimeを開いて最新版のJetBrains Runtimeを選択する。
    - 現時点で1035.1が最新でした。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8995/ef548d32-0dfd-67db-1351-0e5d3715bff1.png)
1. Android Studioを再起動する。

# 日本語パックをインストールする

- PluginsのMarketplaceタブからJapanese Language Packをインストールする。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8995/d4f3fb56-7546-b3c4-b1f1-8396637d5878.png)
- Android Studioを再起動する。

以上で日本語パックを導入できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8995/553999fb-83b6-9d4a-1232-ebb2653daef6.png)
AtCoder Beginner Contest 176 A問題「Takoyaki」解説(Python3,C++,Java)

Ruteです！皆さんAtCoder Beginner Contest 176 お疲れ様でしたー！！
今回は、A問題・B問題・C問題早解きという、<b><font color = "red">ABC164</font></b>以来のABC早解きコンテストとなりました。
おそらく、「ABCを3完して撤退」という方も多かったと思います。

今回は、A問題・B問題・C問題の解説を3言語で解説していきたいと思います！！

##各問題・解説へのリンク

|A|B|C|
|---|---|---|
|この記事です！！|[ABC 176 B] (https://qiita.com/rute_not_route/items/d22bafa86bdf1140b217)|[ABC 176 C](https://qiita.com/rute_not_route/items/5f9c1f899cc4b10c23ce)|

それでは、<b>A問題</b>の解説から始めます！！

#問題概要

たこ焼き機は、一度に最大で$X$個のたこ焼きを作ることができる。作るのにかかる時間は個数によらず$T$分である。

$N$個のたこ焼きを作るためには何分必要かを出力せよ。

##制約
・$1 \leq N,X,T \leq 1000$
・入力は全て整数

#解説
##解法1(天井関数の利用)
$N$個のたこ焼きを作るために必要なたこ焼き機の使用回数は$\lceil{\frac{N}{X}}\rceil$です。

(ここで、$\lceil{A}\rceil$は、Aの<b>天井関数</b>といい、具体的には$A$以上の<b>最小の整数</b>という意味を持ちます。)
よってそれに$T$を掛けたものが$N$個のたこ焼きを作るために必要な時間なので、これを出力すればよいです！！
##解法2 (条件分岐の利用)
または、以下の様な条件分岐を考えても良さそうです。
・もし $N$を$X$で割った余りが0なら `N/X*T`を出力し、そうでなければ`(N/X+1)*T`を出力する。
以下、Python3,C++,Javaでの解答例を示します。
(Python3は<b>解法1</b>で、C++は<b>解法2</b>で解いたコードを解答例としています。)

##各言語解答例

<details><summary>Python3での解答例</summary><div>

```{ABC176A.py}
import math
n,x,t = map(int,input().split())
A = math.ceil(n/x)
print(A*t)
```
※`math`というライブラリにある`ceil`という関数を用いて天井関数を求めています。

</div></details>

<details><summary>C++での解答例</summary><div>

```{ABC176A.cpp}
#include<bits/stdc++.h>
using namespace std;
int main(){
  int n,x,t;
  cin >> n >> x >> t;
  if (n%x == 0){
    cout << n/x * t << endl;
  }else{
    cout << (n/x + 1) * t << endl;
  }
}

```

</div></details>

<details><summary>Javaでの解答例</summary><div>

```{ABC176A.java}
import java.util.Scanner;
public class Main{
  public static void main(String[] args){
    Scanner scan = new Scanner(System.in);
    int n = scan.nextInt();
    int x = scan.nextInt();
    int t = scan.nextInt();
    if (n%x == 0){
      System.out.println(n/x*t);
    }else{
      System.out.println((n/x+1)*t);
    }
  }
}

```

</div></details>
【jQuery】jQueryで、クリックされた【Laravel】の画像ファイルのデータを取得する方法

###パスの最後の/の後が画像のファイル名

```php:画像出力のHTML
<img src="/storage/anpanman.png" alt="anpanman" >
```

```javascript:画像のsrcを取得→ファイル名を取得
$('img').click(function() {
     $object = this;
     filename = $object.getAttribute("src").split("/").pop(); // ファイル名を取得         
});
```

`split("/")`で/ごとに配列に分ける
`pop()`で配列の最後の要素だけ取り出す（つまりファイル名）

意外に調べても出てこなかった。。。あんまり苦労するところじゃないのかもしれん。。。

初心者はつまづく気がするので、参考になれば幸いです。
VSCodeでmarkdown上に数式を書いてPDFで出力する

# 概要

データエンジニア(≠データサイエンティスト)のキャリアを歩みたいと思っていますが、
ちょっと数式を書けると格好良いのでちょっと調べてみた。


# VSCodeでmarkdownに数式を書く
VSCodeでmarkdown上で数式を書くときは、[Markdown+Math](https://marketplace.visualstudio.com/items?itemName=goessner.mdmath)を使う

数式で1行使いたいとき

```plaintext
$$ f(x)=e^{x} $$ 式1
```
$$ f(x)=e^{x} $$ 式1

数式の前後で改行したくないとき

```
$ x_{ij} $ の前後で改行しない
```
$ x_{ij} $ の前後で改行しない

数式の記法は、[KATEX](https://katex.org/docs/supported.html)の公式ドキュメント参照。



# VSCodeでmarkdownをPDFに変換

おまじないとして、ファイルの最初に下記を埋め込む

```html
<script type="text/x-mathjax-config">MathJax.Hub.Config({tex2jax:{inlineMath:[['\$','\$'],['\\(','\\)']],processEscapes:true},CommonHTML: {matchFontHeight:false}});</script>
<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML"></script>
```



markdownからPDFを出力は、[markdown-pdf](https://marketplace.visualstudio.com/items?itemName=yzane.markdown-pdf)を使う

⌘ + Shift + p でコマンドパレットを開いて、
```Markdown PDF Export (pdf) ```を入力して選択するとPDFで出力される