OmniAICreator/Qiita-1.07M huggingface dataset:
MDbootstrapを使ってみよう

まずMDBootstrapというフレームワークの使うための事前準備をします。

MDBootstrapは、CSSフレームワークであるBootstrap4のマテリアルデザイン版です。
MDBootstrapを使用することで、美しいマテリアルデザインの画面のコンポーネント(部品)が簡単に利用できます。

ビューファイルは、`resources/views`ディレクトリに作成していきます。

まず、`resources/views`ディレクトリに`app.blade.php`という名前のBladeを作成します。
`app.blade.php`は全画面で共有するビューになります。

以下のよう編集します。

```
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  <title>
    @yield('title')
  </title>
  <!-- Font Awesome -->
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css">
  <!-- Bootstrap core CSS -->
  <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
  <!-- Material Design Bootstrap -->
  <link href="https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.8.11/css/mdb.min.css" rel="stylesheet">
</head>

<body>

  @yield('content')

  <!-- JQuery -->
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <!-- Bootstrap tooltips -->
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.4/umd/popper.min.js"></script>
  <!-- Bootstrap core JavaScript -->
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
  <!-- MDB core JavaScript -->
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.8.11/js/mdb.min.js"></script>
</body>

</html>
```

この内容は、MDBootstrap公式サイトの導入方法に記載されているコードをそのまま流用しています。

[MD Bootstrap 5 min quick start - Material Design for Bootstrap](https://mdbootstrap.com/education/bootstrap/quick-start/)

これで完了です。
VirtualBoxスマートカードリーダーへのアクセス-「ハウツー」ガイド


###目次

1. VirtualBoxでスマートカードリーダーを使用するためのガイド
2. USBスマートカードリーダーを仮想マシンに転送するソフトウェアソリューション
3. VRDPを介してスマートカードリーダーにリモートアクセスする
VirtualBoxでスマートカードリーダーを使用するためのガイド

[VirtualBox 5.0](https://www.virtualbox.org/)にはスマートカードリーダーのパススルーサポートが付属していることをご存じかもしれません。ここでは、VirtualBoxでスマートカードリーダーを接続する簡単な手順をいくつか紹介します。

VirtualBoxでスマートカードリーダーを使用する
USB 3.0の速度を利用するには、オプションで無料のVirtualBox Extension Packをインストールできます。
ソフトウェアをインストールしたら、Windows、Linux、またはその他のサポートされているゲストOSで仮想マシンを起動します。
目的のUSBデバイスをホストマシンのUSBポートに接続します。
次に、[デバイス]-> [USB]に移動し、[共有するUSB​​デバイス]を選択します。
![ыьфке сфкв.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695639/f1c4a62c-1152-11f8-2226-a6a569139da8.jpeg)

接続が有効な場合、VirtualBoxを介してスマートカードリーダーにアクセスできます。共有USBデバイスが仮想マシンによって検出され、ゲストOSからそのフル機能にアクセスできるようになります。これにより、離れた場所からUSBスマートカードリーダーに接続できます。

一度に1台のコンピュータのみがUSBデバイスにアクセスできることに注意してください。

##USBスマートカードリーダーを仮想マシンに転送するソフトウェアソリューション

Electronic Team、Inc.による[USB Network Gate](https://www.usb-over-ethernet.org/)
多くの一般的な仮想化アプリは、ローカルUSBデバイスを完全にはサポートしていません。 USBネットワークゲートは、この問題に対するソフトウェアソリューションです。

この専用ツールを使用すると、USBリダイレクトテクノロジーを使用して、USB接続のスマートカードリーダーからインターネットまたはLAN経由でデータを転送できます。ゲストOSを使用して、ホストOSに接続されておらず、リモートPCにローカルに接続されているUSBデバイスにアクセスできます。

USB Network Gate
これを実現するために必要な3つの手順を次に示します。

USBスマートカードリーダーが接続されているコンピューターにUSB Network Gateアプリケーションをダウンロードしてインストールします。
ソフトウェアインターフェイスでデバイスを共有します。
アプリを仮想マシンにインストールして起動すると、共有USB周辺機器に接続できます。
USB Network Gateは、Windows、Linux、およびMacオペレーティングシステムと互換性があります。
![UNG smart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695639/4e0306b4-9503-dfae-85c1-a23780e3b946.png)

###VRDP経由でスマートカードリーダーにリモートアクセス

VirtualBoxを使用すると、仮想マシンをリモートで表示できます。つまり、あるマシンで起動したゲストOSを別のPCから表示および制御できるということです。 VirtualBoxは、VirtualBox Remote Display Protocol（VRDP）によってこれを実現します。このプロトコルはMicrosoft RDPプロトコルと下位互換性があるため、RDP接続を介して仮想マシンにアクセスする必要がある場合に最適なソリューションになります。

VirtualBoxのリモートスマートカードリーダーへのアクセスについてはどうですか？ゲストOSがリモートでVRDPデータとして表示されている場合、リモートコンピューター上のUSBデバイスに接続して、VMの実際のホストにローカルに接続されているかのようにアクセスできます。このように、VRDPはVirtualBoxを使用してUSBデバイスにリモートアクセスすることを簡単にします。
Ruby on Rails navbar-brandにリンクを付けたい

#初めに
Railsを学習中の際、タイトルの部分を押せばトップページに戻るようにしたかったのですが、少し手間取ったので記事にする事にしました。なので、メモ程度だと思って見て頂ければ幸いです。

# 本題
###何をしたかったのか？
以下の画像にある、この赤い部分を押せばサイトのトップに戻るようにしたかった。「app/views/layouts/application.html.slim」を利用してこの部分は作成していたので、このファイルのコードを添付しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455271/be829759-41a2-7983-85c0-5717209de29a.png)

```:application.html.slim
doctype html
html
  head
    meta charset = "utf-8"
    title TaskTest
    = csrf_meta_tags
    = csp_meta_tag
    = stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload'
    = javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
  body
    .app-title.navbar.navbar-expand-md.navbar-light.bg-light
      .navbar-brand TaskTest
      .container
        - if flash.notice.present?
          .alert.alert-success= flash.notice
    = yield

```
変更した要所のみを載せます。navbar-brandの横にhrefでトップページに飛ばそうとしても上手くいきませんでした。しかし、以下のように下にaタグを設定することによってタイトルを押すとトップページに戻れるようになりました。

```:application.html.slim
  body
    .app-title.navbar.navbar-expand-md.navbar-light.bg-light
      .navbar-brand
        a class="title" href="/"  TaskTest
      .container
        - if flash.notice.present?
          .alert.alert-success= flash.notice
    = yield
```

# 最後に
slim形式で書くことに慣れていないのでこれが最適解なのかは分かりませんが、これからの勉強に役立てていきたいと思います。
【MacOS】Laravel環境構築時のcomposerがbinに移動できなかったけど解決した


▼概要
・狙い：composerをターミナルで簡単に実行したい
・不具合現象：composer.pharがbinに移動しない
・解決方法：binを正しい場所に移動させたら解決した


composerをターミナルで実行するためにbinフォルダにcomposer.pharを移動させなければならないのだが移動できない。

ターミナルにて
実行「sudo mv composer.phar /usr/local/bin/composer」（composerをbinに移動させて）
結果：「mv: rename composer.phar to /usr/local/bin/composer: No such file or directory」（そこにそんなフォルダないよ）

どうやらOSを入れ直したMacには
/usr/local/の直下にbinフォルダが存在せず、usr/直下にあるらしい。

ということで、usr直下にあるbinをlocalにカット＆ペーストして再度実行→・・・反応はないけどOKみたい。

「composer -V」でインストールされてるか確認
→結果：Composer version 1.10.10 2020-08-03 11:35:19

やったーーーー

※間違ってたらごめん
Splunk 住所マスターデータを取り込む

https://geolonia.github.io/japanese-addresses/
こちらのデータをsplunkに取り込んでみた。

#データについて

列

- 都道府県コード
- 都道府県名
- 都道府県名カナ
- 都道府県名ローマ字
- 市区町村コード
- 市区町村名
- 市区町村名カナ
- 市区町村名ローマ字
- 大字町丁目コード
- 大字町丁目名
- 緯度（代表点）
- 経度（代表点）

データ数：189539(R2.8.21)

#props.conf
日本語の列名は`INDEXED_EXTRACTIONS`の場合上手くいかなかった。

```config:props.conf
[jyusho_csv]
DATETIME_CONFIG = CURRENT
FIELD_DELIMITER = ,
INDEXED_EXTRACTIONS = csv
LINE_BREAKER = ([\r\n]+)
NO_BINARY_CHECK = true
SHOULD_LINEMERGE = false
category = Custom
disabled = false
pulldown_type = true
FIELD_NAMES = todofuken_code,todofukenmei,todofukenmei_kana,todofukenmei_roman,shikuchouson_code,shikuchousonmei,shikuchousonmei_kana,shikuchousonmei_roman,oazamachichoumoku_code,oazamachichoumokumei,ido,keido
CHARSET = AUTO
PREAMBLE_REGEX = 都道府県名
```

`FIELD_NAMES`はとりあえずローマ字ベタ内のフィールドにしてみた。

これで保存して、いったんＳｐｌｕｎｋを再起動
そして`CSV`自体も_zip_で圧縮してアップロード

#結果

![qiita_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130729/ed887628-d85f-92e5-d2c3-78e310b96a1b.png)

#いろいろトップ１０
|市区町村名|カウント|	 
|:-:|:-:|
旭川市|2,270
岐阜市|2,143
帯広市|1,578	
富山市|1,279
豊田市|1,206
札幌市東区|1,105
札幌市北区|1,057
札幌市中央区|990
長岡市|940
金沢市|900

都道府県名|カウント
|:-:|:-:|	 
北海道|	25,914
愛知県|	14,507
兵庫県|	8,967
大阪府|	8,603
京都府|	7,631
新潟県|	7,217
岐阜県|	6,699
福岡県|	6,174
千葉県|	5,716
東京都|	5,358

```sql:yokosuka.spl
| tstats count where source="address.zip:*"  shikuchousonmei="横須賀市"  by oazamachichoumokumei
| rex field=oazamachichoumokumei "(?<machi>.*)(?<choume>.丁目)"
| eval machi=coalesce(machi,oazamachichoumokumei)
| stats count by machi
```
町が多かった。
`INDEXED_EXTRACTIONS`の利点は`tstats`がそのまま使えるところ。

#まとめ
日本語のヘッダーは`transforms.conf`でやると上手くいくけど、正規表現で書かなきゃいけないのがかなりめんどいです。

日本語フィールド名は一応対応していないことになっていますし。

最後出力するときに`rename`使って変更しましょう
WebComponents の constructor で getAttribute が属性があるのに null を返す時がある件。

# はじめに

よく`Javascript`は`body`の閉じタグの前に書くか、それより前で書くなら別ファイルにして`defer`をつけろと言われる。最近この言葉を守らないではまった事例があるのでご紹介。

# 事例

以下のように`WebComponents`を定義する。

```main.js
customElements.define(
	'constructor-attribute'
,	class extends HTMLElement {
		constructor() {
			super()
			this.textContent = this.getAttribute( 'replace' )
		}
	}
)
```

`replace`という名前の属性の値を`textContent`にセットするだけの`webComponents`である。

```index.html
<constructor-attribute replace =REPLACED>INITIAL</constructor-attribute>
<script src="main.js"></script>
```

とやると、期待通りブラウザに**REPLACED**と表示される。

```index.html
<script src=main.js defer></script>
<constructor-attribute replace=REPLACED>INITIAL</constructor-attribute>
```

でも期待通りブラウザに**REPLACED**と表示される。
ところが`script`の`defer`をはずして、

```index.html
<script src=main.js></script>
<constructor-attribute replace=REPLACED>INITIAL</constructor-attribute>
```

とやると、`constructor`の中の`getAttribute`で`null`が帰ってくるので、ブラウザには**INITIAL**と表示される。

# 対処

`body`の閉じタグの前に書いてやるか、それより前に書くのなら別ファイルにして`defer`をつける

でもどうしても head で書きたいときとかは、別解？を参照。


# 別解？

どこにでもおけるようなものを作りたいと思い、次のようにしてみたらちょいハマりした。

```main.js
customElements.define(
	'constructor-attribute'
,	class extends HTMLElement {
		static get
		observedAttributes() {
			return [ 'replace' ]
		}
		attributeChangedCallback() {
			this.textContent = this.getAttribute( 'replace' )
		}
	}
)
```

`observedAttributes`でウォッチしたい属性を登録しておけば、`constructor`直後に`attributeChangedCallback`が呼ばれるのでここで処理しておけばいい気がしたのでやってみた。


```index.html
<constructor-attribute replace=REPLACED>INITIAL</constructor-attribute>
<script src=main.js></script>
```

```index.html
<script src=main.js defer></script>
<constructor-attribute replace=REPLACED>INITIAL</constructor-attribute>
```

上の二つは期待どおり**REPLACED**と表示される。

```index.html
<script src=main.js></script>
<constructor-attribute replace=REPLACED>INITIAL</constructor-attribute>
```

これもうまくいくと思っていたのだが、実際は**REPLACEDINITIAL**と表示される

`constructor`と`attributeChangedCallback`は同一のランループで処理されて、そのあと、タグ中の文字列がアペンドされるようだ。`chrome`,`safari`,`firefox`,`opera`で確認。
Dockerで使うコマンドメモ

あとでもう少しまとめる。

自分：Docker全然知らないけど、Webのコーディングする人（タスクランナー動かせるけどプログラム分かりません）
やりたいこと：PHPとかのサーバー環境をまるっと再現して、ローカルで開発したい。

### ▼ Docker for Mac をインストール
https://docs.docker.com/docker-for-mac/install/

### ▼ イメージを探して、ローカルにインストール
https://hub.docker.com/

公式のイメージで古いバージョンは、`tag`で探す。
https://hub.docker.com/_/php?tab=tags&page=174
今回探してたのが、phpの5.2だったけど、公式にはもうなかった。

一旦、PHP5.4 + apacheを入れる。

```shell
docker pull php:5.4.34-apache
```

#### ▼ イメージ一覧 をみる
```shell
docker images
```
```shell
docker image ls
```

#### ▼ コンテナ作成
```shell
docker run
```

http://www.tohoho-web.com/docker/docker_run.html#run
> -v (--volume) オプションは、ホストのボリュームまたはディレクトリをコンテナに割り当てます。複数指定可能です。-v ホスト側:コンテナ側 で指定しますが、ホスト側が / で始まる名前の場合はディレクトリを指定します。

Web開発（ページ作成）においては、
`-v ＜開発フォルダのドキュメントルートフォルダ＞:＜コンテナのドキュメントルート＞` という理解。

##### ▼ ホスト？とコンテナ？マウント？
概念的なものが分からなかったのでここ結構つまづきつつ。
参考サイトに分かりやすい図があったので引用。
> ![docker-v01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85559/72377872-2564-b837-bc98-887e48087ba3.png)
> → [Dockerのバインド・マウントを利用する[-v]](https://noumenon-th.net/programming/2019/03/30/docker-v/)

？ コンテナのルートってどうやって知る？？
→ 適当にimage 作って作成したコンテナに bash で入ってルートを確認して ↑ボリュームオプションを設定したコンテナを作り直した。これは正しく無い気がする…。


#### ▼ 作成したコンテナに bash で入る

```bash
docker container exec -ti "NAME" bash
```

#### ▼ 作成したコンテナから抜ける
https://qiita.com/Statham/items/c204e85067ea4dca2724

#### ▼ コンテナの停止

```bash
docker stop
```

#### ▼ コンテナの再起動

```bash
docker restart "NAME"
```

#### ▼ ハマった点
古い php を動かそうとしたら、 mb系の関数が使えない。
→ [Dockerの公式PHPコンテナでmb系関数を使うにはmbstringモジュールをインストールします
](https://unskilled.site/docker%E3%81%AE%E5%85%AC%E5%BC%8Fphp%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%81%A7mb%E7%B3%BB%E9%96%A2%E6%95%B0%E3%82%92%E4%BD%BF%E3%81%86%E3%81%AB%E3%81%AFmbstring%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC/)

#### ▼ いろいろ
動かすまで行けた。
php5.2は、他の人がアップしているイメージが結構ありそうではあるんだけど。動かないことが多い。と言うかドキュメントがないものが多くて、ちょっと何していいかわかんなかった。
BugCをまっすぐ走らせてみた

前回投稿した[BugCとJoyCで遊んでみた](https://qiita.com/moritakuya/items/6ac95099812f3b46f4ba)、でうまくまっすぐ走らなかったので、素人なりに頑張ってまっすぐ走らせてみた記録です。

# まっすぐ走らない
4つすべてのモーターを同じスピードにしても、なぜか左斜め前に走ったり、たまにまっすぐ走ったりと、よくわからない動きをしてました。
パワーをモーターごとにオフセットを入れるようにしてもうまくいかず、、、。

# なぜまっすぐ走らないのか
![https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_504156_3f7462ac-dfe4-3241-9cc6-095178859906.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504156/8e194e97-7c4e-1277-84a7-5ca050a2d5ab.png)
足の接地面が小さく空回りしやすいのでは？と考えました。それならでかい車輪をつけたらいけんじゃね、という安易な発想で改造してみました。

# 改造計画
車輪を取り付けたいのですが、モーターが斜めについているうえに回転軸が縦向きじゃないのでこのまま車輪を付けられません。
てことはギヤをかませて回転軸を変えて、ついでにギヤ比を変えてスピードを落としてトルクを出すようにすれば空回りしにくくなるのでは、と考えました。

ちなみにギヤとか詳しくなく、子供のころミニ四駆で遊んでいた程度。工作もプラモデルを作ったことがある程度の知識と技量しかなく、不安でいっぱいです。

設計図です。
![設計図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504156/22d7ba15-25e9-5854-0acb-c3ee2b91431c.png)

# いざ改造
足にピニオンギヤを取り付けたいのですが、径が合わずガバガバだったので、足に熱収縮チューブを付けて径を太くしてみました。
![DSC_0367.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504156/a1ad6c34-9dc9-0b4e-9a26-98ea5ee60c84.jpeg)
![DSC_0368.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504156/05238b5f-6d16-5833-db71-96f1a48b9159.jpeg)
それでも径がうまく合わなかったので真鍮パイプを買ってきてピニオンギヤと熱収縮チューブの間を埋めてみました。
![DSC_0382.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504156/1b9a30f9-316c-aad8-89e9-cf79d60c35cf.jpeg)
土台の方はクラウンギヤとそれを支えるシャフトとベアリング、そしてプラ板で構成。クラウンギヤ、シャフト、ベアリングはネットで見つけたミニ四駆改造部材っぽいものを買ってみました。
土台は家にあった何に使ったかわからないプラ板の切れ端を使用しました。プラ板の上に乗っかっているボール紙はBugCを支えるためのものです。家にあったコアラのマーチの箱を切って作りました。
![DSC_0384.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504156/4f289eac-0d9e-c1b9-38a2-3f2d0be0a713.jpeg)
いざ、合体！！
![DSC_0381.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504156/bb72df11-74ad-9a44-9c18-12e513c98eea.jpeg)

# 走らせてみた
なんと、まっすぐ走ることに成功しました。以下の動画参照。
[youtube動画(https://youtu.be/qT29zwokJnI)](https://youtu.be/qT29zwokJnI)

まっすぐ走るのを見たらちょっと感動しました。
こんな雑な工作でも案外なんとかなるもんですね。
Pythonで自身のIPアドレスを取得

表題の通りです。 windowsとmacでは動作確認しました。
配列で取得出来ます。

## パッケージインストール

```bash
pip install psutil
pip install netifaces
```

## スクリプト

```python
import netifaces as ni
import psutil
import os
import socket


def get_ip() -> list:
    if os.name == "nt":
        # Windows
        return socket.gethostbyname_ex(socket.gethostname())[2]
        pass
    else:
        # それ以外
        result = []
        address_list = psutil.net_if_addrs()
        for nic in address_list.keys():
            ni.ifaddresses(nic)
            try:
                ip = ni.ifaddresses(nic)[ni.AF_INET][0]['addr']
                if ip not in ["127.0.0.1"]:
                    result.append(ip)
            except KeyError as err:
                pass
        return result


print(get_ip())
```

## 結果

```bash
['192.168.XXX.XXX', '10.211.XX.X', '10.37.XXX.X']
```

## 参考サイト
> https://stackoverflow.com/questions/24196932/how-can-i-get-the-ip-address-from-nic-in-python
> https://stackoverflow.com/questions/3837069/how-to-get-network-interface-card-names-in-python
> https://edosha.hatenablog.jp/entry/2017/08/09/150636
【niv】package.jsonのscripts一覧をターミナルから確認できるCLIを作ってみた

# 作ったもの

[![ReadMe Card](https://github-readme-stats.vercel.app/api/pin/?username=hota1024&repo=niv)](https://github.com/anuraghazra/github-readme-stats)

`package.json` に登録されている `npm-scripts` をターミナルから確認、実行できるCLIを作ってみました。

# 説明

`package.json` があるフォルダで

```
$ niv
```

と実行すると
![スクリーンショット 2020-08-21 18.03.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154299/a60b9143-1239-54ca-5269-178bed86f597.png)
こんな感じで `npm-scripts` 一覧が表示されます。
`hjkl` または `矢印キー` で `❯` を動かし、スクリプトを選択できます。
`エンターキー` で選択しているスクリプトを実行します。
`ctrl + c` でキャンセルできます。

# インストール

`npm` または `yarn` でインストールできます。

```bash
npm install -g niv
# or
yarn global add niv
```

# モチベーションとか技術のお話

いろんなプロジェクトに参加しててそれぞれ `npm-scripts` がバラバラなので一覧にしてさらに実行もできるCLIがほしかったので作りました。

使った技術セットはこんなかんじです。

| 技術 | 説明 |
|:----|:----|
| TypeScript | 型システムがついたJavaScript。最近V4が出たらしい...？ |
| oclif | Node.jsのCLIフレームワーク。TypeScriptにも対応してて簡単にCLIが作れちゃう。 |

# さいごに

ちょい実行速度が遅いところもありますが、よければ使ってみてください〜
最後まで読んでいただきありがとうございました〜
databricks公式ドキュメントをやってみた~Get EC2 instance information~

#はじめに
公式ドキュメントに沿ってdatabricks on AWSを動かしてみたいと思います。
今回のテーマは
「Get EC2 instance information」です。
その名の通り、databricks上でコードを実行してEC2インスタンスの情報を表示させるという内容です。



#本題
今回行う作業としては、

- 作業ページまでのログイン

- クラスターの作成

- Notebookの作成

- スクリプトの実行

の4ステップです。
早速初めて行きましょう。

###作業ページにログインする
1.以下URLからdatabricksにログインします。
https://accounts.cloud.databricks.com/registration.html#login

2.「Deploy Databricks」を選択し、水色文字になっているURLをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593135/9c8f1a22-6d7d-dc2e-125b-a77de3a234dd.png)

3.1でログイン時に使用したメールアドレスとパスワードを使用してログインします。
　この画面に辿りついたらOKです。
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593135/a35ecbb0-75d7-dbfd-33f4-45f34732eeaf.png)

###クラスターの作成
1.先ほどの画面Common Tasks欄のNew Clusterをクリック。
　※左のメニューバーからClustersを選択してもOKです。

2.ここではクラスターの詳細設定ができますが、とりあえずデフォルトのもので構いません。
　(コストが気になるという方は
　Worker Typeのところをm4.largeなどの変更しても大丈夫です。)
　Cluster Nameを記入したらCreate Clusterをクリックします。
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593135/6dc72d86-18a0-3091-30e8-dd6fd33648d6.png)

3.左のメニューバーからClusterページにいき
　このようにStateがRunningになったらクラスターの設定が完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593135/26380046-5f24-f001-cf2d-9d9448066202.png)

###Notebook作成
左上のメニューバーからHome画面に戻ったら
画面右のCreate a Blank Notebookをクリックします。
Name : 任意
Default Language : Python
Cluster : 先ほど作成したもの
を記入してCreateをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593135/0db57442-61a3-c470-3269-92a0c1adb385.png)

###スクリプトの実行
以下のスクリプトを実行していきましょう。
基本的な動作はjupyter notebookと同じです。

1.今回使うモジュールのimport

```
import urllib.request
import json
```


2.インスタンス情報取得

```
instance = json.loads(urllib.request.urlopen('http://169.254.169.254/latest/dynamic/instance-identity/document').read())
instance
```

3.マスター/ドライバーのパブリックホスト名を取得

```
public_hostname = urllib.request.urlopen('http://169.254.169.254/latest/meta-data/public-hostname').read()
public_hostname
```

4.全てのワーカーのパブリックホスト名とIP情報を取得
numWorkersはClusterページから確認して各自変更してください。

```
numWorkers = ***

worker_instance_ids = sc.parallelize(range(numWorkers)).map(lambda x: 
  (urllib.request.urlopen('http://169.254.169.254/latest/meta-data/public-hostname').read(), urllib.request.urlopen('http://169.254.169.254/latest/meta-data/public-ipv4').read())
)

print ​worker_instance_ids.distinct().collect()
```


※今回の内容は以下公式サイトを参考に作成しました。
ドキュメント内のスクリプトはPython2のモジュールになっているので、本記事ではPython3用に修正しております。
https://docs.databricks.com/administration-guide/cloud-configurations/aws/describe-my-ec2.html


#さいごに
公式ドキュメントに基づいて実際にNotebookを動かしてみました。
非常に簡単でしたが、databricksとAWSが連携していることが確認できたと思います。

最後までお読みいただきありがとうございました。
USDをDockerで動かす

USD([Universal Scene Description](https://graphics.pixar.com/usd/docs/index.html))のコマンド叩いてみようと思ったら少しめんどくさかった。
MacなのでAppleが提供するUSDPython最新版を試そうとするとエラー吐くし[Reality Converter](https://developer.apple.com/news/?id=01132020a)はGUIなのでサーバーサイドで使えないしでUSDを試すことにしました。

そんなわけでDockerでの導入備忘録を残しておきます。

## Dockerfileをビルドする

Dockerの初期設定の1.9GBだとメモリ不足でエラーになるので6GBまで増やしました。(重要)
ビルド中眺めていると最大で4GB届かない程度で推移してました。

```bash

$ docker build -t usd .
```

```dockerfile:Dockerfile
FROM ubuntu:20.04

ENV TZ=Asia
ENV PYTHONPATH="$PYTHONPATH:/usr/local/USD/lib/python"
ENV PATH="$PATH:/usr/local/USD/bin"
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

RUN apt update
RUN apt install -y build-essential cmake git libglew-dev libglib2.0-0 libx11-dev
RUN apt install -y python python3 python3-pip
RUN pip3 install PySide2 PyOpenGL jinja2
RUN git clone https://github.com/PixarAnimationStudios/USD
RUN python3 USD/build_scripts/build_usd.py /usr/local/USD

WORKDIR /opt/
```

## 使ってみる
デーモン立ち上げて、マウントしたフォルダにファイルを置いてコマンドを叩く

```bash
$ docker run -d -it --name usd \
-w /opt/volume \
-v $HOME/usd:/opt/volume \
usd
```


コマンドは[USD Toolset](https://graphics.pixar.com/usd/docs/USD-Toolset.html)を参照

```bash
# usdaをusdcに変換
$ docker exec usd usdcat -o hoge.usdc hoge.usda
# usdzを作成
$ docker exec usd usdzip hoge.usdz hoge.usda 
```


# 手書きでUSDAを作成

処理を書いて出力結果を見ながら他の言語で実装するといったことが出来そうです。

- 参考サイト
  - [Meshを作成](https://github.com/ft-lab/Documents_USD/blob/master/doc/usd_create_mesh.md)
  - [Materialの作成](https://github.com/ft-lab/Documents_USD/blob/master/doc/usd_create_material.md)

# Docker Hub

Docker Hubにあげておきました。
https://hub.docker.com/r/otmb/usd

```
$ docker pull otmb/usd
```

Docker Hubは半年したら削除する方針になったので暫くしたら消えます(T_T)
[Docker Hubに保存したコンテナイメージ、無料プランでは6カ月間使われないと削除へ](https://www.itmedia.co.jp/news/articles/2008/20/news079.html)
YouTubeのURLのみ登録を許可する正規表現を設定してみた【Ruby】

#環境
ruby 2.6.5
rails 6.0.3

#前置き

今回実装したかった仕様はYouTubeの動画をユーザーが登録すること
その際にYouTube以外の動画サイトのURLを登録されると色々不都合が出てくるので
ユーザーが登録する動画URLはYouTubeのURLだけに限定したい

YouTubeのURLの特徴としては以下の２点

+ PC版とスマホ版でURLの始まり方が異なる
 + PC https://www.youtube.com/watch?v=
 + スマホ https://youtu.be/
+ URLの最後に１１桁の動画識別番号？が割り振られている

なので今回はこの２点を考慮してYouTubeのURLを判定する正規表現を作成していく


#正規表現
そして完成したのがこちらのvalidation

```app/models/exercise.rb
validates :url, presence: true,
                  format: { with: /\A(https\:\/\/)?(www\.)?(youtube\.com\/watch\?v=|youtu\.be\/)+[\S]{11}\z/ }

```

正規表現だけ抜き出すとこんな感じ

```
/\A(https\:\/\/)?(www\.)?(youtube\.com\/watch\?v=|youtu\.be\/)+[\S]{11}\z/
```

これでYouTubeのURLのみデータベースに保存することが可能です。
rubyの場合は[Rubular](https://rubular.com/)というサイトで正規表現のチェックを行えます。


#ブラウザでの表示

ちなみに以下のようにすることでブラウザで動画を表示させる事が可能です。


```app/views/exercise/exercise.html.erb
<iframe width="560" height="315" src="https://www.youtube.com/embed/<%= @exercise.url.last(11) %>"
        frameborder="0" allow="accelerometer; autoplay; encrypted-media;
        gyroscope; picture-in-picture" allowfullscreen>
</iframe>
```

```app/controllers/exercise_controller.rb
@exercise = Exercise.find(params[:id])
```

#最後に

もうすこしうまく正規表現を書けば、最後の１１文字だけを抽出して登録した方がいいかもです。
そうするとブラウザに表示するときに`.last(11)`が不要になるので。
私はここまでかなり苦戦したので余力がありませんでした・・・笑
時間がある時にまた考えてみようと思います。

あと実は他にもYouTubeのURLの形式って色々あります。
下記のように再生リストのURLだと全然形式違ったり・・・
https://www.youtube.com/watch?v=APdS9YQUWro&list=RDVFdLm6gEEE4&start_radio=1
検証段階で他にも確か全然違うURLがあったりとしましたが大変なので今回はメイン２種類に絞りました。
RubyOnRailsを用いたデータベースの作り方

復習を兼ねてRubyOnRailsを用いたデータベースの作成方法について記載。

#モデルの作成方法
```
rails g model User name:string age:integer
```
上記コマンドでモデルを作成することができる。モデル名のUserだが、最初だけ大文字の単数形になることに注意。
（テーブル名はusersという小文字の複数形になる）
カラムにはstringなどデータの形式も指定する。

string:文字
text : 長い文字列（２５５文字以上のデータを格納する際）
integer : 整数
float : 浮動小数
decimal : 精度の高い小数
datetime : 日時
timestamp : タイムスタンプ
time : 時間
date : 日付
binary : バイナリデータ
boolean : Boolean

#マイグレーションファイルを実行する
```
rails db:migrate
```
このコマンドを実行することによりデータベースが作成される。

#データベースの中を見る

```
rails dbconsole
```
このコマンドを実行するとSQLiteが立ち上がる。コマンドを実行することでデータベースの中を参照可能。

```
.tables
#テーブル一覧を確認　ちゃんとテーブルが作成されたかを確認する際などに使用

.exit
#参照モードを解除
```

#データベースにデータを入れる

```
rails c
#rails consoleの略
```
このコマンドにより、コンソール上でRubyを簡単に実行することができる様になる。Rubyを用いてデータを入れていく。

```
User.create(name:"A君",age:22)
#nameがA君、ageが２２歳のデータを追加
```

#データを参照する
```
User.find(1)
#ユーザーIDが１のデータを参照する

User.find_by(name:"A君")
#nameがA君のデータを参照する
```
IDを指定するときはfind、その他のデータを指定する場合はfind_byを使用する。
ただしfind_byはデータを検索して、IDが一番若い人のデータのみしか見つけてくれない。
（例：年齢が２９歳の人が５人いても、最初の1人目しかデータを持ってこない）

```
User.where(age:29)
#複数のデータを持ってきたいときに入力
```
上記のコマンドを入力することによって、合致するデータを配列で抽出することができる。

ちなみに、下記コマンドで全てのユーザーを確認することが可能。

```
User.all
```
#ユーザーの情報を変更する
まずは変更の対象とするユーザーを決める

```
change_user = User.find(1)
#ユーザーID１のデータを変更することを宣言　ちなみにchange_userは変数なので、何でもOK

change_user.age = 35
#ID１のageを３５に変更

change_user.save
#変更した内容を記録する　こちらを実行しないとデータベースには反映されないので注意
```

#データの削除方法
```
user = User.find(1)
#まずは削除対象のデータを決める userは変数なので、別の名前でもOK　この場合はIDが１を指定

user.destroy
#データを削除する
```


#カラムの追加方法
```
rails g migration add_mail_users mail:string
#マイグレーションファイルのみを作る　mailカラムをusersテーブルに作る

rails db:migrate
#追加したカラムを反映させるために、コマンドを実施
```
DockerのWordpressでアップロードできるファイルサイズを変更する

Dockerで作成したWordpressでは、デフォルトのアップロードファイルサイズが2MB。
少し大きめのテーマファイルをアップロードしようとするとエラーになります。

変更手順のメモ書きです。

# ターミナルからDockerコンテナに入る。

docker psでコンテナID確認

```
$ docker ps
CONTAINER ID        IMAGE                          COMMAND                  CREATED             STATUS              PORTS                  NAMES
58f9b5e5f3ad        wordpress:latest               "docker-entrypoint.s…"   4 hours ago         Up 51 minutes       0.0.0.0:8087->80/tcp   sample_wordpress12_1
d85068445ebb        mysql:5.7                      "docker-entrypoint.s…"   2 months ago        Up 51 minutes       3306/tcp, 33060/tcp    sample_db_1
cc924f86373f        phpmyadmin/phpmyadmin:latest   "/docker-entrypoint.…"   2 months ago        Up 51 minutes       0.0.0.0:8888->80/tcp   sample_phpmyadmin_1
```
docker exec -it  コンテナID /bin/bashで該当するコンテナに入る。

```
$ docker exec -it 58f9b5e5f3ad /bin/bash
```
# uploads.iniファイル作成
/usr/local/etc/php/conf.d に移動する

```
$ cd /usr/local/etc/php/conf.d
```

uploads.iniファイルを作成し、upload_max_filesize と post_max_size をファイルに記述する。

```
$ cat > uploads.ini
upload_max_filesize = 50M;
post_max_size = 50M;
```

ここまで完了したら　Control-D で終了し、dockerを起動

```
$ docker-compose up -d 
```

wordpressを立ち上げて確認すると、サイズの大きいファイルもちゃんとアップロードできるようになっています。
配列


#　配列

配列とは
配列とは、変数が1つの値を保持するのに対して、配列は1から複数の値を保持することが出来ます。配列の使用用途として代表的なものは、データを纏めて管理することが出来ることと、ソースコードを効率よく記述することが挙げられます。またソースコードを効率よく記述出来るだけでなく、値の修正なども簡単に行える為、メンテナンス性にも優れています。
特にPythonの配列は他プログラミング言語に比べて、配列操作がしやすく、Pythonを使用するメリットの1つです。配列の使用例としては学生の名前を全て出力する場合などがあります。
ExcelのVBAなどで出来ることをを簡潔に行うことができます。


リスト配列の記述方法。
リスト配列を作成する記述方法は、下記になります。

配列名 = []


空のリストを初期化
空のリストを初期化したい場合は下記のよう記載します。

>listA = []


リストの初期化＜数値＞
リストへは数値を直接入力することができます。

>listB = [1, 2, 3]

リストの初期化＜文字列＞
数値と同様に文字列もリストへ入力できます。

>listC = ["c", "d", "e"]

リストの初期化＜数値と文字列＞
数値と文字列を混在した形でリストを作成することができます。
>listD = [3, 4, "d", "e"]


リストのて初期化＜リスト＞
リストの中に、リストを挿入して形でリストを作成できます。 Pythonのリスト柔軟性が高いです。

>listB = [1, 2, 3]
>listC = ["c", "d", "e"]
>listD = [3, 4, "d", "e", listB, listC]

リストの中に変数の設定
リストの中には変数も入力することができます。

>str = “AAA”
>num = 5

>listA = [3, 4, "d", "e", list4, num, str]

指定サイズ分(要素数)だけ0埋めをして初期化
0埋めも用途によっては使うと思います、 下記は、3要素数だけ0埋めしてリストを作成しています。

>listA = [0] * 3

連想配列について
連想配列は通常の配列に加えて、キーを含んで管理することにより、配列を効率よく管理することができます。
連想配列の使用例としては、名簿の配列があったとします。
その名簿の配列に、連想配列のキーとして年齢を指定することで、名簿配列の年齢でまとめて利用することができます。
使用方法としても、SQLのSELECT文の使用方法をイメージするとわかりやすいと思います。Pythonの連想配列とは、ディクショナリを使用します。リストとは異なり、連想配列としてディクショナリを使用することで、キーとバリューで要素を格納します。Pythonで「辞書のリスト」は表データ（テーブル）を表すのに有効です。表データを1行1行処理するときに扱いやすいデータです。 また、表データは日常の業務でもよく使われるので、活用の幅はとても広いでしょう。ここから発展して、Pythonの「辞書のリスト」を「辞書の辞書」のデータに変換することもあります。


ディクショナリを作成する記述方法
ディクショナリを作成する記述方法は、下記になります。

>ディクショナリ名 = {}
【Laravel】storageにある画像が読みだせない

###要約
1. php artisan storage:link
2. storeAs('public', ファイル名)
3. {{ asset('/storage/ファイル名') }}で読み出す


###画像をアップロードするフォームを作成していたら、画像が読みだせない
```php5:＊＊＊Controller.php
public function (Request $request){
  $uploaded_image = $request->file('image');
  if($request->hasFile('image') && $uploaded_image->isValid(){
    $file_name = $uploaded_image->getClientOriginalName();
    $uploaded_image->storeAs('characters', $file_name); // ここが原因でassetで読み込めなくなる
  }
}
```
#####storeAs('characters', $filename)
`storage/app/characters`の中に`$filename`という名前で保存する
という意味になる。
つまり、`storage/app/public`には入っていないということ！！ここが肝心！！

###シンボリックリンクを作成しないとstorageディレクトリにアクセスできない
そもそもLaravelのルートディレクトリは`css`,`js`などを入れるディレクトリになっていて、実際公開されているのはこのディレクトリだけ。

ということはstorageディレクトリに入っている画像はアクセスできないから読みだせないじゃん！どうしよ・・・

###シンボリックリンクで参照されるディレクトリはstorage/app/public
とうことでルートのpublicディレクトリに、storageにアクセスするシンボリックリンクを作成する。

`Windowsでいうショートカット`に当たる。
（もともとWindowsしか使ったことないから、この考え方超わかりやすい）

```terminal:ターミナル
// publicにstorageにアクセスするためのシンボリックリンクを作成する
$ php artisan storage:link
```
これで
`public/storage(←ショートカット)`ディレクトリが作成される。

Windowsでいうと、publicの中のstorageリンクをクリックすると`storage/app/public`フォルダに飛ぶということ。


###画像の保存先をstorage/app/publicにしてassetヘルパを使う
assetヘルパはルートディレクトリのパスを生成してくれるもの？（言葉は変かも知れません。）

asset('panda.jpg')ならpublic/panda.jpgというパスを生成してくれる。

ということは

```php5:画像の読み出し
<img src="{{ asset('panda.img') }}">
// public/panda.imgを参照することになる！そこには画像がないにも関わらず！
// 逆にpublicに直接画像を入れれば読み出せる。
```

```php5
{{ asset('/storage/panda.img') }}
// publicの中のシンボリックリンクstorageの中のpanda.imgを参照
// シンボリックリンクstorageはstorage/app/publicに飛ぶ
// 結局,public/storage→storage/app/publicの中のpanda.imgにアクセス
```
ということは

```php5:
// php artisan storage:linkを実行した後なら
<img src="{{ asset('storage/panda.img') }}">
```

これで画像が読み出せる！！


###シンボリックリンクの参照先の変更もできるらしい

これは勉強不足で良く理解できていません。


###storeAsの使い方
```php5
$uploaded_image->storeAs('characters', $file_name);
// storage/app/charactersディレクトリに$file_nameというファイル名で保存
```
これだとstorage/app/publicとちゃうんやんってなってassetで読みだせない

```php
$uploaded_image->storeAs('public', $file_name);
// storage/app/public
```
これでasset('storage/ファイル名')で読み出せる！

###storeだとフォルダ名とファイル名が思わぬことに

```php
$uploaded_image->store($file_name);
```

これだと
storage/appの中に$file_nameのディレクトリを作成してそのなかに謎の文字列が並んだファイル名で保存される。


###感想
少しずつLaravelのディレクトリ構成が分かってきた。
でもまだまだ分かっていないのが分かった。無知の知的な。

これからデータベースにPathを保存して、データベースから画像を取得する流れと勉強します。
ハードディスクの構造と記憶方法、フラグメンテーションとデフラグメンテーション、RAIDとは、ハードディスク以外の補助記憶装置

#ハードディスクの構造と記憶方法
**構造**
 ディスク(プラッタ)
 金属やガラスでできている硬い円盤。表面に磁性体が塗布されていて、磁化することで情報を記録ができる。

 アクセスアーム
 先端に磁気ヘッドがついてるアーム。ディスク上の目的地まで磁気ヘッドを運ぶ。

 磁気ヘッド
 アクセスアームの先端についている電磁コイル。ディスク表面の磁性体を磁化させたり読み取ったりする。

**領域単位**
 セクタ
  領域（プラッタ）の扇状に分かれた最小範囲。

 トラック
   セクタを複数集めた1周分の領域。

 シリンダ
  複数の同心円状のトラック。

 クラスタ
  OSがファイルを読み書きする際に、複数のセクタを1ブロックとみなしたもの。

**ハードディスクの記憶容量算出**
 以下の仕様のハードディスクの場合の総容量の算出方法は次の通り
　![図68.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686519/5ac99533-cc50-ffc0-3dbc-4ed17f098b84.png)
　![図69.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686519/43373137-ca55-2961-87d8-ef208928499c.png)


**データへのアクセスにかかる時間**
以下の仕様のハードディスクの場合の5,000バイトのデータを読みだす場合のアクセス時間は次の通り

![図70.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686519/e216d23d-84e2-bf57-970e-c25e23e26492.png)
![図71.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686519/c0a4c6d6-6e9a-7620-5d35-2f3d7608f97c.png)

#フラグメンテーション
　ハードディスクに書き込みや消去を繰り返していくと、連続した空き容量が減り、ファイルが断片化してしまうこと
#デフラグメンテーション
　断片化したファイルのデータを連続した領域に並べなおして、フラグメンテーションを解消する。

#RAIDとは
RAIDは複数のハードディスクを組み合わせることで、ハードディスクの速度や信用性を向上させる。

**RAIDの代表的な種類とその特徴**
 ・RAID0(ストライピング)
　　ひとつのデータを2台以上のディスクに分散させて書き込む
 ・RAID1(ミラーリング)
　　2台以上のディスクに対して常に同じデータを書き込む
 ・RAID5
　　3台以上のディスクを使って、データと同時にパリティと呼ばれる誤り訂正符号も分散させて書き込む
#ハードディスク以外の補助記憶装置

　**光ディスク**
　レーザ光線によってデータの読み書きを行う

　**CD(Compact Disc)**
   　直径12cmの光ディスクで、記憶容量は650MBと700MBの2種類
　　種類
　　　・CD-ROM：再生専用型のCD(書き込みができない読み込み専用）
　　　・CD-R：追記型のCD(一度だけ書き込める)
　　　・CD-RW：書き換え可能型のCD(何度も書き換えができる)
　
**DVD(Digital Versatile Disc)**
 CDよりも波長の短い赤色レーザで記録するため、ピットの高密度化が可能になってより、大容量を実現している。
 　種類
 　　　・DVD-ROM：再選専用型のDVD
 　　　・DVD-R：追記型のDVD
 　　　・DVD-RW:書き換え可能型のDVD
 　　　・DVD-RAM：書き換え可能型のDVD

**光磁気ディスク(MO：Magneto Optical disk)**
　レーザ光線と磁気によってデータの読み書きを行う。
 
**磁気テープ**
　磁性体が塗布された「テープ状のフィルムに、時期を使って読み書きを行う」カセット型の記憶媒体

**フラッシュメモリ**
　EEPROMの一種を補助記憶媒体に転用したもの。これを代表したものにメモリーカードやUSBメモリがある

#以上
MySQLで「Column cannot be null.」 timestampとdatetimeに振り回された話

データベースサーバの移行に際して起こったトラブル．

MySQLにて，データ挿入時に自動でタイムスタンプを付与したい…

```sql
> CREATE TABLE `my_table` (
> `insert_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP PRIMARY KEY,
> `my_column1` VARCHAR(4) NOT NULL,
> `my_column2` VARCHAR(4) NOT NULL,
> `my_column3` VARCHAR(4) NOT NULL);
```

こんなテーブルを作った．
`insert_time`はNULLを許容しないが，もしNULLを入れても自動で現在時刻に差し替えてくれるはず…！

データを挿入してみる．

```sql
> INSERT INTO my_table VALUES (null, "aaaa", "iiii", "uuuu");
```

しかし…

```sql
Column 'insert_time' cannot be null.
```
移行前のサーバではこれで動いてたはずなのに…

## 解決策
### その１：`insert_time`を指定しないようにする

```sql
> INSERT INTO my_table (my_column1, my_column2, my_column3) VALUES ("aaaa", "iiii", "uuuu");
```

めんどい…

### その２：`null`ではなく`default`を指定する

```sql
> INSERT INTO my_table VALUES (default, "aaaa", "iiii", "uuuu");
```

なるほど，`null`で指定してしまってたからいけなかったのか．
`null`は`default`に置き換わるわけではなかったのね！

デフォルト値を使いたいなら

- 何も指定しない
- `default`を指定する

のいずれかが必要だということだ．

しかし，移行前のサーバではなぜエラーを吐かなかったのか？

##　勘違いの原因
移行前のサーバを調べ直したところ，`insert_time`の型が`datetime`じゃなくて`timestamp`だったのだ！

`timestamp`型なら，

```sql
> INSERT INTO my_table VALUES (null, "aaaa", "iiii", "uuuu");
```
も問題なく通る．

## Q. じゃあ`timestamp`型を使うべきか？
### A. `datetime`を使うべき

`timestamp`の方が`datetime`よりも使い勝手が悪いみたい．
一番分かりやすいのは，`datetime`は「9999年」まで指定できるのに対して，
`timestamp`は「2038年」までしか指定できないということ．

2038年なんてそんなに遠い未来じゃないから，どうしても`timestamp`を使わざるをえないような人以外は，`datetime`使えばいいよね．

他にもいろいろ違うっぽい．
（参考：[MySQLのDATETIME型とTIMESTAMP型の違いを検証してみた](https://qiita.com/ykawakami/items/2449a24e3b82ff0cbab6)）

## 結論
原因も知れたしスッキリした！
Vue.js のテンプレートで複数行にまたがる table の tr を表示する

## 課題

- Vue.js で複数行にまたがる`<tr rowspan="x">`を表示したい

![スクリーンショット 2020-08-21 17.28.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2022/e0ddd8c0-e675-6161-d199-1053846cc50a.png)

## 失敗例      

- `<template>`には1つの要素しか許可されていないため`<tr>`が複数記述できない

```html:Table.vue
<template>
  <table>
    <tbody>
      <table-row v-for="row in rows" />
    </tbody>
  </table>
</tepmlate>
```
```html:TableRow.vue
<template>
  <tr>
    <td rowspan="2">A</td>
    <td>1</td>
    <td>2</td>
    <td>3</td>
  </tr>
  <tr>
    <td>1</td>
    <td>2</td>
    <td>3</td>
  </tr>
</template>
```

## 成功例

- 複数の`<tr>`を`<tbody>`で囲うことで表示できるようになる

```html:Table.vue
<template>
  <table>
    <table-row v-for="row in rows" />
  </table>
</tepmlate>
```
```html:TableRow.vue
<template>
  <tbody> <!-- これで囲う -->
    <tr>
      <td rowspan="2">A</td>
      <td>1</td>
      <td>2</td>
      <td>3</td>
    </tr>
    <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
    </tr>
  </tbody> <!-- これで囲う -->
</template>
```

知ってる人からしたら当たり前のことかもしれないけど、初心者の私には目からウロコでした
wslコマンドの--updateオプションが使えない

# 概要
Windows Subsystem forL Linux 2 (WSL2) を利用してWindows上でDocker + TensorFlow(GPU)の環境を作成しようとした際に起きた躓きと解決方法をまとめておきます。

# 問題
Windows Subsystem forL Linux 2 (WSL2) でGPUを利用するにはLinuxカーネルが古い場合、これを更新を行う必要があります。Linuxカーネルが`4.19.104`の場合、WSL2からGPU(あるいはCUDA)の利用ができません。

```
# wsl uname -r
4.19.104-microsoft-standard     # *.104ではGPUは利用できない
```

そこで他記事を参考に`wsl --update`を実行してカーネルのバージョンを更新しようとすると、`wsl`のコマンド引数に`--update`がなく、実行してもそんな引数はないと引数リスト(`wsl --help`に相当するもの)が表示される場合があります。

# 解決方法
2020/08/21(金)時点において、`wsl`コマンドの`--update`オプションはまだ公開(リリース)されておらず、Windows Insider PreviewのDev チャンネルから入手する必要があります。
2020/06/17(米国時間)に公開された「Windows 10 Insider Preview Build 20150」に含まれる`wsl`コマンドのエンハンスを適用することで`wsl --update`のコマンドが実行可能になります。

Windowsの設定メニューから`更新とセキュリティ`画面を表示し、`Windows Insider Program`から下図の様に設定を変えてください。Dev チャンネルに接続することでWindows Updateに「Windows 10 Insider Preview Build 20150」が現れインストールできます。
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146699/23a069ae-b51e-8cf3-dbaf-536a4d7e71c9.png">
GoogleSpreadsheetが更新されたらSlackに通知を送る、基本の形

## やりたいこと
GoogleSpreadsheetで作った管理表を何人かで共有していて、
ステータス列が変更された時、すぐ通知が欲しいという事ありませんか。

今回、GoogleSpreadsheetの特定の列が更新されたらSlackに通知が飛ぶように、
GoogleAppsScriptを使って実現してみます。

![Sheet -_ GAS -_ Slack.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649785/652ec684-b97b-e8d1-962a-f65fd7288ce9.png)

## 手順
1. SlackのIncoming Webhookの設定をする
2. 対象のSpreadsheetにて、スクリプトを書く
3. トリガーの設定をする

### 1. SlackのIncoming Webhookの設定をする

Slackの画面左上の組織名をクリックし、設定と管理→アプリを管理する へ進む。
カスタムインテグレーションからIncoming Webhookをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649785/84f70d65-55ea-8cb5-ea87-b6e5d402bd1e.png)

(注意書きにもあるように、カスタムインテグレーションは2020/08時点で非推奨となっていますので、そのうち書き換えます)

Slackに追加をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649785/b733cda9-ef93-a1ac-bc6d-8bfb61bbc8cc.png)

どのチャンネルに投稿させるかを選んで、追加ボタンを押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649785/47fd9c75-ba34-4cab-c5af-815fa4d5ae25.png)

次の画面に出てくるWebhook URLをメモして、画面下部の「設定を保存する」ボタンを押す。
いったんSlackから離れます。

### 2. 対象のSpreadsheetにて、スクリプトを書く
Slackに通知を送りたいSpreadsheetを開き、
ツール→スクリプトエディタを開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649785/dcf7a0a0-0b81-9610-e037-b177c3ca7a13.png)

開いたら以下のコードをコピペ。（後で少し書き換えます）

#### コード

```javascript:コード.gs
/**
 新しく値が追加されたときに、Slackにお知らせする関数
*/
function onEdit(e) {
  // 対象のシート名
  const TARGET_SHEET = "list";
  // 対象の列番号 (A=1, B=2,...)
  const TARGET_COLUMN = 5;
  // 対象のSlack webhook URL
  const SLACK_URL = "https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX";

  // 更新したシートとセル
  let sheet = SpreadsheetApp.getActiveSheet();
  let cell = sheet.getActiveCell(); 

  // 対象のシート・列でなければ何もしない
  if (!e || (sheet.getName() != TARGET_SHEET) || (cell.getColumn() != TARGET_COLUMN )) {
    return;
  }
 
  // Slackに送るテキストメッセージ
  let message = e.user + " さんが " + cell.getA1Notation() + "を更新しました。\n" + e.oldValue + "\n↓\n" + e.value;
 
  const OPTIONS = {
    "method": "post",
    "contentType" : "application/json",
    "payload" : JSON.stringify({
      "text" : message
    })
  };
  UrlFetchApp.fetch(SLACK_URL, OPTIONS);
}

```

↑のコードを、利用状況に合わせて書き換えます。
まずは、TARGET_SHEET, TARGET_COLUMN, SLACK_URLを書き換えてください。
TARGET_COLUMNは、E列の更新を通知したい場合、5、と書きます。
SLACK_URLには、手順1でメモしたURLを書きます。

終わったら保存します。(Ctrl+s または、💾ボタンをクリック)

### 3. トリガーの設定をする
現時点では、このプログラムは保存されただけで起動するきっかけがありません。
次にするのはトリガーの設定です。

編集→現在のプロジェクトのトリガー、を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649785/fa385927-056c-eca9-1857-8e0cfb7bcce6.png)

トリガーを追加、をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649785/d21d7631-c58c-0550-fe3b-26d7c584b132.png)

イベントの種類を「編集時」に変更します。
その他は変更不要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649785/60e50488-d663-850d-5996-79ff81dbe78e.png)

保存を押したら完了です。
Spreadsheetを変更してSlackに通知がいくかどうか、テストしてみてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649785/418ead01-c521-d901-e268-ec0d762cff32.png)


## おわりに

手順を大幅にすっ飛ばして、動作させるための「基本」のやり方だけ説明しました。
エラーチェックをしたり、メッセージを変えてみたり
カスタマイズを色々と試してくださいね。
FizzBuzz問題(Ruby)(「each文」編)

:pray_tone1:コメントいただいております通り、
訂正予定記事ですご注意くださいませ。
私の理解不足でございます。申し訳ございません。

#この記事でわかること
FizzBuzz問題をRubyで解く方法
:thinking:Ruby以外での回答はないのでご注意下さい。

###前提
解答方法：Ruby、each文
  
　　
#FizzBuzz問題の問題文
>1から100までの数をプリントするプログラムを書け。ただし3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、3と5両方の倍数の場合には「FizzBuzz」とプリントすること。

###＜ヒント＞
:speaking_head:問題を読んで何をしていいのか思いつかなかった人は先ずToDoリストができればオッケー
<details><summary>問題文を分かりやすく分解したもの</summary>
・３で割り切れる数値　　　　を引数に渡すと、「Fizz」を返す。
・５で割り切れる数値　　　　を引数に渡すと、「Buzz」を返す。
・３と５両方で割り切れる数値を引数に渡すと、「FizzBuzz」を返す。
さらに、
・それ以外の数値は、数値を文字列にして返す。
　※これらを条件文に直していくことがポイントになる。＞＞[「if文についてに」戻る](https://qiita.com/kusaharajiji/items/eaca7b35b0ef07a5164f#if%E6%96%87%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)
</details>
　　
　　
　　

　　
#解答コード

####each文での解答

```ruby:Ruby
(1..30).each do |i|

    if i%15==0
        puts "FizzBuzz!"
    elsif i%3==0
        puts "Fizz!"
    elsif i%5==0 
        puts "Buzz!"
    else
        puts i
    end

end
```
正直、私は初学者なので複数解答がある中でこれがRubyで一番分かりやすいのではないかと思う。

　　
　　
　　

##解釈
####＜ポイント＞

- eachメソッド
- if文
- 1..30というソースコード。ピリオドを２つ連続で付ける（..）と、数字の範囲を指定することができる。
　　

これらが理解できていると解けなくとも問題が分かってくる。
　　
　　
　　
###eachメソッドについて
```ruby:eachメソッド
(1..30).each do |i|
  //ここに処理を記述
end
```

「(1..30)」には繰り返したい範囲のものをかく。
iはiである理由は無いがeach do |i|からendの間で使える変数として命名されたもの他の文字でも良い。
今回の場合iは(1..30)の記述通り1から30の間の数字をいれる箱になっている。
each doなので1から30までの数字を繰り返しiに入れながら処理の部分を繰り返している。
今回は「//ここに処理を記述」の中にiという変数（箱）が使われる。
　　
　　
###if文について
```ruby:if文

if 条件文１
  puts "出力したい文字列a"
elsif 条件文２
  puts "出力したい文字列b"
elsif 条件文３
  puts "出力したい文字列c"
else
  puts each文で繰り返し処理されている数字iを出力
end
```

冒頭にある[ヒント](https://qiita.com/kusaharajiji/items/eaca7b35b0ef07a5164f#%E3%83%92%E3%83%B3%E3%83%88)であげた３項目が条件になる。
また、条件をどの順番からif文の中に書いてくかも課題。
というのも「３と５両方で割り切れる数値（i%15==0）」という条件を先に記述せず、
条件の「３で割り切れる数値（i%3==0）」を先に持ってきてしまうと「３と５両方で割り切れる数値（i%15==0）」が意味の無いものになる。

<details><summary>条件文を実際に入れ替えて成立しない時の例は左の▶︎をクリック</summary><div>

```ruby:＜例＞間違い

#「３で割り切れる数値（i%3==0）」を先にし、引数iが30の時

(1..30).each do |i|
    #条件１に30が当てはまるので puts "FizzBuzz!"が処理される。
    if  i%3==0
        puts "FizzBuzz!"
    #ここにも当てはまるが条件１で処理されてしまうので、この処理が行われることが無い。
    elsif i%15==0
        puts "Fizz!"
    elsif i%5==0 
        puts "Buzz!"
    else
        puts i
    end

end
```
条件の並びは十分に考えて、
実際に数字を入れて確認するのがベスト！
</div></details>
　　
　　
　　
##ひとことMemo
正直、初見は問題みて分からなかった。
でも、繰り返しやってみたりこうして自分で解説してみると理解しやすい。
初学者からすれば不明点が重なるので余計に挫折してしまう。
もっと解説できるところを増やして編集するので懲りずに記事を読んでやってほしい。
特に問題の場合使用できる言語がRubyだけではなくで他にもある。
ということは解答は複数ある。
また、Rubyだけでも複数ある。
今回みたいにeach文ではなくfor文での解答もあるようだ。
それもまた勉強して記事にしたい。
　　
　　


最後まで読んでくださって、ありがとうございます:blush:
そして、お疲れ様です✨
頭を使ったら甘いもの食べちゃいましょう！
ではまた:yum:

  
  

##参考リンク
[Ruby 2.3.1でFizzBuzz問題を解く。]
URL(https://qiita.com/Fendo181/items/425293e8e638d7fd7cea)
CDP 7.1でAtlasをインストール

Cloudera Data Platform（CDP）7.1.1をインストールし、Atlasを追加する際に必要な作業をメモしておきます。

CDP 7.1.1は２０２０年５月末にGAになりました。CDH6/HDP3系の進化版となっています。
インストール後の画面は以下です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110403/a594f865-73f3-1713-472c-872a84d40230.png)

Atlasをインストールするにはいくつかコンポーネントを先にインストールしないといけません。

大まかな手順

* Zookeeper, HBase, Kafka, Solr(CDP-infra-solr)を「サービスの追加」からインストール 
* Solrの起動に以下のエラーで失敗した場合、「Solrの初期化」と「HDFSホームディレクトリの作成」を実施

```
Unable to set the cluster property due to following error : Error setting cluster property
Error: Unable to set the cluster property in ZK
ERROR: Failed to configure urlScheme property for Solr cluster in Zookeeper
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110403/033dc4da-44ec-f8be-8924-73a2156c20fb.png)

* Atlasのアクションで「Create HBase tables for Atlas」を実行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110403/6f1c3df9-ea25-910e-0389-1dc7c2e492a6.png)


* 続いてAtlasの初期化を実施。Atlasプロセスを停止してからやらないと、「Initialize Atlas」はグレーになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110403/1b702790-9bea-2e53-7ddf-6ed8b94d7538.png)

初期化のログ。Solrにvertex_index, edge_index, fulltext_indexが作成される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110403/f6461082-105e-f34e-4ef6-0b83e771c72d.png)

これでAtlasのUIにアクセスできるようになります。
AWS API GatewayにおけるIP制限

AWS API GatewayにおけるIP制限
============
AWS Security Groupsのように簡単にInbound rules設定ができなかったので備忘録。
ホワイトリストの設定の仕方。
API Gatewayのコンソール上から設定
------------
１．Amazon API Gateway > APIs > 該当のAPI > Resource Policy
２．下記ソースを参照。aws:SourceIpに許可したいIPを入れる。複数のIPを同時に設定できる。
３．Save。保存したとたんにAWSが自分の気に入る形にjsonを書き換えることがある。たぶん問題はない。

```rb
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": "execute-api:/*/*/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "0.0.0.0/0"
                }
            }
        }
    ]
}

```
![APIG_IP制限.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453255/cc8b3c86-b4e6-06bf-2e34-1c0a8191686c.png)

設定後は忘れずにデプロイ
------------
ホワイトリストを設定したら、APIをデプロイしないと反映されない。
１．Amazon API Gateway > APIs > 該当のAPI > Resources
２．Actionsプルダウンから、Deploy APIを選択する。
３．Deployment stageを選択し、任意で説明も記載してDeploy。
４．Amazon API Gateway > APIs > 該当のAPI > Stages > 該当のStage
５．Deployment Historyタブで、デプロイが成功していたら完了。

動作確認
------------
ホワイトリストで許可したIPでアクセスしてみて、200が返ってくれば成功。
許可していないIPでアクセスしてみて、403が返ってくれば成功。

その他
------------
Resource Policyを修正したら、設定を壊してしまった…
→デプロイ履歴から、成功していた時のデプロイに戻る。
　１．Amazon API Gateway > APIs > 該当のAPI > Stages > 該当のStage
　２．Deployment Historyタブで、設定を壊す前のデプロイを選択してChange Deployment。
　３．Current stageで選択したデプロイ履歴にチェックついていればOK。
　　※デプロイ履歴をわかりやすくするため、デプロイ時にはDescriptionを記載しておいた方が良い。
　　※※この作業で、いつでもどのデプロイ（設定）へも戻れる。
AWSにデプロイしたら、ログイン機能が使えなかった話

AWSにrailsアプリをデプロイ後に、サインアップしようとしたら、メールが送れない。
We're sorry, but something went wrong.が表示される。
こんな事象を治す過程を記します。

今回はログイン機能にDeviceを用いて実装しています。

環境
rails 6.0.3.2
ruby ruby 2.6.3p62
AWS amazonlinux
Nginx,unicornを使用


#エラー
log/prodution.logに以下のようなエラーがでていました。

```config/log/prodution.log
ActionView::Template::Error (Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true):
 2:
 3: <p>You can confirm your account email through the link below:</p>
 4:
 5: <p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>
```

#やったこと

本番環境でメール送信するため、
以下を参考に設定しました。
https://qiita.com/cigalecigales/items/16ce0a9a7e79b9c3974e#comments
今回は本番環境なので、

```config/environments/production.rb
 config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
```

```config/environmets/production.rb
config.action_mailer.default_url_options = { host: 'IPアドレスに変更'} 
```
AWSで設定したIPアドレスに変更しました。


```app/views/devise/confirmation_instructions.html.erb
 ５：<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>


 5: <p><%= link_to 'Confirm my account', user_confirmation_url(confirmation_token: @token) %></p>
```

エラーにPlease provide the :host parameter, set default_url_options[:host]
とあるので:hostが送られてきてないよということなので、
エラー文のでている５行目を変えました。

rails routesで〇〇_confirmationを調べて、変更しました。
今回は〇〇がuserになっています。

以下を参照しました。
http://renkaze.seesaa.net/article/374977746.html

おっと！！
こののままではダメで、
このcondig変更後に、
unicornを再起動させる必要があります。

```サーバー環境
ps aux | grep rails
```

で右側に出たunicornのプロセスIDのマスターになっているもの

```サーバー環境
kill プロセスID
```

unicorn起動

```サーバー環境
$ bundle exec unicorn_rails -c /var/www/rails/アプリ名/config/unicorn.conf.rb -D -E production
```

これをしてなかったが為に結構な時間を取られたのご注意ください。
初心者が忘れやすいミスなのかもですが、、

Deviceは便利ですが、エラーがでてしまうと
わりと困惑しますよね。

AWSのデプロイはこちらを参考にしました。
https://qiita.com/Yuki_Nagaoka/items/975b7598806d6ae0c0b2
JupyterLabの拡張機能を一斉アップデートしたらjupyterlab-gitが消えた

JupyterLabをアップデートしたところ、拡張機能のアップデートを求められたので言われるままそうしたところjupyterlab-gitが左のメニューバーから消えた。

[jupyterlab-gitのGitHub](https://github.com/jupyterlab/jupyterlab-git)のTroubleshootingに書いてある通りに

```
$ jupyter serverextension list
$ jupyter labextension list
```

を実行すると、[こちらの記事](https://qiita.com/Koooichiiii/items/40988653260574efd332)と同じエラーが発生していたため、バグの元になっているjsonファイルを消去。

さらに、serverextensionとlabextensionのversionは同じでないといけないのですが、現在labextensionのv0.21.0が出ているようで、JupyterLab上でlabextensionをインストールするとserverextensionの最新版v0.20.0とバージョンが異なる状況になってしまいます。

そこで

```
$ jupyter labextension uninstall @jupyterlab/git
$ jupyter labextension install @jupyterlab/git@0.20.0
```

としてバージョンを揃えてあげて再ビルドしたところ直りました。
疲れた……
Let's Encrypt の自動更新

Let's Encrypt の自動更新の設定方法です。

<ol>
<li>クローンが動いているかの確認</li>

Ubuntu

```text
$ sudo systemctl status cron
● cron.service - Regular background program processing daemon
     Loaded: loaded (/lib/systemd/system/cron.service; enabled; preset: enabled)
     Active: active (running) since Sat 2023-06-10 14:38:23 JST; 1h 1min ago
       Docs: man:cron(8)
   Main PID: 937 (cron)
      Tasks: 1 (limit: 966)
     Memory: 872.0K
        CPU: 164ms
     CGroup: /system.slice/cron.service
             └─937 /usr/sbin/cron -f -P
```

Arch Linux

```text
$ sudo systemctl status cronie
● cronie.service - Periodic Command Scheduler
     Loaded: loaded (/usr/lib/systemd/system/cronie.service; enabled; preset: d>
     Active: active (running) since Wed 2023-06-07 07:47:57 JST; 3 days ago
   Main PID: 288 (crond)
      Tasks: 1 (limit: 629145)
     Memory: 3.1M
        CPU: 4.254s
     CGroup: /system.slice/cronie.service
             └─288 /usr/bin/crond -n
```

<li>簡単なクローンを設定してみる</li>

クローンの設定

```bash
crontab -e
```

クローンの確認

```text
$ crontab -l
#
14 * * * * date > /tmp/t208.txt
#
15 16 * * * date > /tmp/t209.txt
#
16 16 21 * * date > /tmp/t210.txt
```

上記の意味は、
毎時　14　分に実行
毎日　16時15分に実行
毎月　21日16時16分に実行

<li>ドライランでコマンドを走らせてみる</li>

```bash
$ sudo certbot renew --dry-run
```

<li>ドライランをクローンに設定する</li>

```bash
sudo crontab -e
```

```text
$ sudo crontab -l
#
PATH=/usr/sbin:/usr/bin:/bin
#
45 18 20 * * /usr/bin/certbot renew --dry-run >> /tmp/test_dry.log 2>&1
#
```

クローンが動くことを確認

<li>更新コマンドをクローンに設定</li>

```bash
sudo crontab -e
```

```text
$ sudo crontab -l
#
PATH=/usr/sbin:/usr/bin:/bin
#
45 19 20 * * /usr/bin/certbot renew --post-hook "systemctl restart nginx" >> /tmp/certbot.log 2>&1
```

上記は、月に１回ですが、同じコマンドを３つ程書いて、月に３回程動かす方が良い。
たまたま，ネットワークなりが不調の時に実行されると、更新がされないので。

PATH=/usr/sbin:/usr/bin:/bin を入れないと次のようなエラーが出ます。

```text
Could not choose appropriate plugin: The nginx plugin is not working; there may 
be problems with your existing configuration.
The error was: NoInstallationError("Could not find a usable 'nginx' binary. Ensu
re nginx exists, the binary is executable, and your PATH is set correctly.",)
```

次のようにしてうまく行くこともあります。

```text
$ sudo crontab -l
#
PATH=/usr/sbin:/usr/bin:/bin
#
45 19 20 * * /usr/bin/certbot renew --webroot -w /var/www/html --post-hook "systemctl restart nginx" >> /tmp/certbot.log 2>&1
```

</ol>