OmniAICreator/Qiita-1.07M huggingface dataset:
リンクタグでページに遷移してもreloadしないとJavaScriptのイベントが発火しない

##解決したい問題
###``<link_to>や<a>タグ``でページに遷移してもreloadしないとJavaScriptのイベントが発火しない

##エラーの仮説
turbolinksが邪魔してそう...

##turbolinksってなんだっけ？
turbolinksとは、ページ遷移をAjaxに置き換え、JavaScriptやCSSのパースを省略することで高速化するgem。Rails4からはデフォルト。

##原因
###data-turbolinkが働いて遷移したページではイベントが発火しない事があるらしい.

##解決策

###``link_to``には``data: {"turbolinks"=>false}``を追加
###``<a>タグ``には ``data-turbolinks="false"``を追加

####data-turbolinkをオフにするために、遷移元のリンクタグにdata属性を追加！
GPUサーバーにおけるPython環境構築

GPUサーバーでPytorchとfaiss-gpuを使うコードを実行する際に、マシンによって環境を使い分ける必要が生じたので、備忘録として方法をまとめました。

https://qiita.com/supersaiakujin/items/50def6f33b79f9a61b18
を参考に、pyenv+anacondaで環境構築しました[^1]。

[^1]: pyenv+virtualenvでやりたかったのですが、faissのインストールが上手くいかず挫折しました。

やる前に使いたいマシンのcudaバージョンを確認する必要があります。これは、

```
$ nvcc -V
```

等で確認できます。そして、

```
$ pyenv install -l
```

で表示される一覧の中から、インストールするanacondaのバージョンを決定します(以下anaconda3-5.1.0とします)。
その上で以下を順に実行します。

```
$ pyenv install anaconda3-5.1.0

$ pyenv local anaconda3-5.1.0

$ conda create -n 環境名

$ conda activate 環境名

# faiss-gpuのインストール
$　conda install -c pytorch faiss-gpu cudatoolkit="cudaのバージョン"

# pytorchのインストール(CUDA 11.0の場合)
$ conda install pytorch==1.7.1 torchvision==0.8.2 torchaudio==0.7.2 cudatoolkit=11.0 -c pytorch
```

pytorchのインストールは https://pytorch.org/get-started/previous-versions/ を見てcudaのバージョンに合わせて行います。その他、必要なライブラリをconda installします。

ここまでできたらあとはコード実行するときに

```
$ pyenv local anacondaバージョン名
$ conda activate 環境名
```

で環境を立ち上げるだけです。

```
(環境名) $
```

みたいになってくれます。環境から抜けたい時は

```
$ conda deactivate
```
以上をマシンやディレクトリごとに行えばOK！、なのですが、筆者の環境ではこのままだとscreen環境内でconda activateができないという問題があったので、対処法を書いておきます。screenを使わない方は無視してください。

この解決策は、https://stackoverflow.com/questions/50591901/screen-inside-the-conda-environment-doesnt-work/53535739 を参考にしました。

まず、

```
$ pyenv local anacondaバージョン名
$ which conda
```

でcondaコマンドのパスを調べます。これをコピーして、

```
. コピーしたパス/etc/profile.d/conda.sh
```

を~/.bash_profileに追記し、

```
$ source ~/.bash_profile
```

を実行します。こうすると、screen環境内で

```
$ conda activate 環境名
```

が使えるようになるはずです！
numpyでFFTを使う

# 1次元FFT
numpy.fft.fftを使う。
※FFTの結果の格納の順番に注意
最初に周波数プラスのものを昇順に、次に周波数マイナスのものを昇順に、という順番で格納されている。なのでそのままプロットしても結果を把握しづらい。

格納順への対応方法
1. numpy.fft.fftfreqで上記の格納順に対応する周波数の配列を作成
2. numpy.fft.fftshiftでFFTの結果を周波数マイナスのもの〜周波数プラスのものの順に並び替える

以下numpy.fft.fftの使用例

```python:1次元FFT使用例
import numpy as np
import numpy.fft as fft
import matplotlib.pyplot as plt


y = []
N = 10000
step = 0.001
# 周波数の配列を作成
freq = fft.fftfreq(N, d=step)
# 周波数、振幅その1
f1 = 2
amp1 =1
# 周波数、振幅その2
f2 = 5
amp2 = 3

for i in range(N):
    x = i*step
    # 周波数、振幅その1、その2の波の重ね合わせ
    y_i = amp1*np.sin(f1*2*np.pi*x) + amp2*np.sin(f2*2*np.pi*x)
    y.append(y_i)

fy = fft.fft(y)
# 絶対値を規格化してプロット
plt.scatter(freq, np.abs(fy)/np.linalg.norm(fy))
plt.xlim([0, 7])
plt.grid()
plt.show()
```

* 結果  
それぞれの周波数のピークが表れている。絶対値の比もそれぞれの振幅の比と一致する。
<img width="450" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1566923/463a22f2-c2d5-8ec1-6ba9-6b27d85918a0.png">

# 2次元FFT
numpy.fft.fft2を使う。
2次元の場合、x、y方向両方とも上記のように周波数プラスのもの〜周波数マイナスのものの順で格納されている。
numpy.fft.fftshiftを使用すればx、y方向両方とも周波数マイナス〜プラスの順に並べ替えてくれる。

```python:2次元FFT使用例
mport numpy as np
import numpy.fft as fft
import matplotlib.pyplot as plt


z_ij = []
N = 1000
mid = N/2
step = 0.001
freq = fft.fftfreq(N, d=step)
freq = freq.tolist()
freq.sort()
freq_x = []
freq_y = []
for i in range(N):
    freq_x.append(freq)
for i in range(N):
    freq_y.append([freq[i]]*N)

# x方向、y方向周波数
fx1 = 4
fy1 = 6

for i in range(N):
    z_j = []
    for j in range(N):
        x = j*step
        y = i*step
        z = 2*np.sin(fx1*2*np.pi*x + fy1*2*np.pi*y)
        z_j.append(z)
    z_ij.append(z_j)

fz_ij = fft.fft2(z_ij)
# fftshiftでFFTの結果を並び替え
shift_fz_ij = fft.fftshift(fz_ij)

plt.contourf(freq_x, freq_y, np.log(np.abs(shift_fz_ij)), cmap='coolwarm')
delta = 10
plt.xlim([0, delta])
plt.ylim([0, delta])
plt.grid()
plt.show()
```

* 結果  
x方向周波数4、y方向周波数6の場所にピークがある
<img width="450" alt="ファイル名2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1566923/29b58ff0-5709-0200-8c15-160d45edf4dc.png">
マーケティングオートメーション入門（自分用）

# はじめに
Salesforceの「Marketing Cloud」を触る機会があるため、学習を始める。
Marketing Cloudとは、Salesforceが提供するマーケティングオートメーション（MA）ツールである。
Marketing Cloudを学習する前に、そもそもマーケティングについて全く知識がないため前提知識や背景について、自分用にまとめる。

# マーケティングとは？

> 商品の販売を行い利益を増やすためには、多くの顧客に商品を知ってもらい、購買行動を起こしてもらう必要があり、そのような企業活動を総じてマーケティングといいます。マーケティングでは以下のプロセスが必要となってきます。
1. 見込み客を集める⇒Lead Generation（リードジェネレーション）
2. 見込み客を育てる⇒Lead Nurturing（リードナーチャリング）
3. 見込み客を選別する⇒Lead Qualification（リードクオリフィケーション)

>参考：[MAとは？活用メリットとツール5選](https://sth.bell-face.com/sales-knowledge/what-is-ma/)

※リード：見込み客

とりあえずイメージはこんな感じかな程度に認識しておく。


# マーケティングオートメーション（MA）とは？
> マーケティングオートメーション(MA)とは、簡潔にいえば、新規顧客の獲得や見込み顧客の育成なども含めたマーケティング施策をサポートするためのツールやソフトウェアを指します。
参考:[いまさら聞けない「マーケティングオートメーション」。できることから事例、導入のポイントまでまとめて解説！](https://promote.list-finder.jp/article/marketing_automation/what-is-ma/)

また、***国内のMA市場規模としては、2020年で447億3500万円***となっている。
コロナ禍で顧客行動のオンライン化が急激に進み、オンライン上での顧客行動の把握や顧客接点の創出に向けたデジタルマーケティングツールの重要性が高まっている。

参考：[矢野経済研究所　DMP / MA市場に関する調査を実施（2020年）](https://www.yano.co.jp/press-release/show/press_id/2542)

## MA需要の高まりの理由
先ほど記載した通り、コロナ禍で顧客行動のオンライン化が急激に進んだことが市場拡大に影響しているのはもちろんだが、そもそも***営業手法の変化***が大きく影響している。

・インターネット普及前
市場や商品に関する情報の多くは、ベンダー側（販売提供元）が持っていた。そのため、顧客はベンダーに相談、依頼することが一般的。

・インターネット普及後
市場や商品に関する情報は、顧客たちが自ら集めることが出来るようになった。自分たちで調べ、ある程度絞ったうえでベンダーに声をかける。

上記のような変化から、マーケティング機能を強化し、積極的にリード（見込み客）を引き込む必要が出てきて、MAの需要が高まってきた。

参考：[MA（マーケティングオートメーション）とは？基礎知識と導入のポイント](https://www.salesforce.com/jp/hub/marketing/what-is-ma/#why-ma)


## MAツールでできること
細かい機能の違いはあれど、以下のようにマーケティングで必要な各プロセスへのサポートができる。

### 見込み顧客情報の統合・一元管理
問い合わせフォームや、セミナー参加者、名刺交換などなど見込み顧客情報を得る方法はさまざまである。
※このような、見込み顧客を獲得することを「リードジェネレーション」という。

これらの情報を手作業で管理するのは困難である。MAツールを使うことで、主にメールアドレスを軸に見込み顧客の情報を統合・一元管理することが出来る。
例）過去のセミナー参加の有無、自社サイト閲覧情報などなど

一元管理し、行動を分析していくことで優先すべき顧客を判断することが出来るようになる。

### 見込み顧客の育成（リードナーチャリング）
見込み顧客の育成とは、見込み顧客に対して、段階的かつ効果的にアプローチし購入意欲を高めていくこと。MAツールを用いることで、一斉メール送信やステップメールなど、顧客の興味対象に合わせたメールマーケティングなどを行うことができる。

### 見込み顧客の選別（リードクオリフィケーション）
見込み顧客の選別は、見込み顧客の育成（リードナーチャリング）を行っている見込み顧客に対して、メールの開封率や行動に応じて分析し、意欲の高い顧客を選別する。
選別することで、優先順位を明らかにし、営業の効率化を図ることが出来る。


参考
[リードナーチャリングとは？方法やプロセス、役立つツールを解説](https://jp.marketo.com/content/leadnurturing.html)
[【2020年12月更新】マーケティングオートメーション(MA)とは？　効果、特長...基礎知識を解説！](https://www.innovation.co.jp/urumo/marketingautomation/#i-2)


# 用語まとめ
|用語 |意味  |詳細 |
|---|---|---|
|リード  |見込み顧客  |自社製品に関心を示しており、将来的には顧客になる可能性がある人 |
|リードジェネレーション  | リードの獲得 |セミナーや名刺交換、アンケートなどを通じたリード情報の取得|
|リードナーチャリング  |リードの育成  |獲得したリードに対して、段階的なアプローチを行い、見込み度合いを上げる活動|
| リードクオリフィケーション |リードの選別  |リードナーチャリングしたリードに対して、分析し見込み度合いの高いリードを明確化|
Windowsとエクスプローラーのショートカット集

マウスを操作するのが面倒くさくなってきたので、
もっとキーボードで色々出来ないかなと思い調べ、
定番のもの・気に入ったものをまとめました。

一応、役立つ順に並べたつもりです。

他にも「これ便利！」なものがあったら、教えてください。


## Windowsの便利なショートカット集

### Ctrl+C：選択した項目をコピー<br>Ctrl+X：選択した項目をカット<br>Ctrl+V：クリップボードから貼り付け

1にして全。


### Win+V：クリップボードを開く

めっちゃコピーできるようになります。
初回の操作ではクリップボード機能を有効化する必要があります。


### Win+Shift+S：スクショ撮影

そのまま「切り取り＆スケッチ」で簡単に編集もできる。
大抵のアプリはCtrl+Vでそのまま画像を貼り付けられる。

### Win+T / Win+Shift+T：タスクバー上のアプリを順番に切り替える・逆順

マルチディスプレイの場合、マルチ側にも飛んでいきます。


### Win+E：エクスプローラーを開く

タスクバーにピン留めしておく必要がなくなります。

### Alt+Tab：アクティブなアプリの切り替え

ノートだと三つ指スクロールでも大体同じことが出来ると思いますが、
敏感すぎるのでこちらが楽な場合も。


### Win+D：デスクトップの表示・非表示

最小化よりこっちを使いがちです。


### Win+M：すべてのウィンドウを最小化<br>Win+Shift+M：最小化したウィンドウを復帰

戻す方法は始めて知りました。


### Win+0～9：タスクバー上の数字で示す位置にピン留めされているアプリを開始する

知りませんでしたが、**めっちゃ便利**だと思います。
Ctrl、Shift、Alt、各派生コマンドがあるので是非[Microsoft](https://support.microsoft.com/ja-jp/windows/windows-%E3%81%AE%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89-%E3%82%B7%E3%83%A7%E3%83%BC%E3%83%88%E3%82%AB%E3%83%83%E3%83%88-dcc61a57-8ff0-cffe-9796-cb9706c75eec)で見てください。


### Win+L：PCをロック

最近ノートPC買ったので、覚えておこうと思いました。


### Win+R：ファイル名を指定して実行、を開く。

ゲームのためにスペックを調べるときは"dxdiag"。

#### .を入力して実行するとユーザーフォルダが開ける。

エクスプローラー使いの足しにしてください。


## エクスプローラーの便利なショートカット集

### Ctrl+Shift+N：新規フォルダの作成

そのままフォルダ名の編集もできます。


### F2：ファイル・フォルダ名を編集

エクセルやスプレッドシート等でもセルの編集が行えるので、
お馴染みかと思います。


### Alt+↑ or ← or →：上位・前の・次のディレクトリに移動

とても便利です。
ブラウザでも使えます。


### Ctrl+N：現在のディレクトリを新しいウィンドウで開く<br>Ctrl+Enter：選択中のディレクトリを新しいウィンドウで開く

コピペ作業の時など便利だと思います。


### 英数字：英数字で始まるファイルorフォルダに移動

ファイルでは基本的に1文字目までしか入力を受け付けてくれませんが、
フォルダの場合は繰り返し入力するたび、カーソルを操作することが出来ます。

性質上、日本語ファイル名には対応していません。


### Alt+D / Ctrl+l：アドレスバーを選択<br>F4：アドレスバーのドロップダウンリストを表示

Alt+D/Ctrl+Lはアドレスバーをそのまま操作しやすいです。
ブラウザでも使えます。

#### アドレスバーに"cmd"でそのディレクトリでコマンドプロントを開く

地味に便利です。


### F6 / Shift+F6：選択要素を切り替え・逆順切り替え

Tabよりローテーションが短いのでツリーに移動したりするのに便利です。
ブラウザでも使えます。


### Alt+Enter：プロパティを表示

タイムスタンプの確認に使えると思います。


### Shift+F10：Shift+右クリック

ノートや右クリックキーがない場合は便利かなと思いました。


## おわりに

私はまだWinキーとAltキーの本当の力を知らないと思いました。
脱マウスに向けて頑張りたいと思います。


## 参考にしたページ

いつもありがとうございます。

Microsoft - Windows のキーボード ショートカット
https://support.microsoft.com/ja-jp/windows/windows-%E3%81%AE%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89-%E3%82%B7%E3%83%A7%E3%83%BC%E3%83%88%E3%82%AB%E3%83%83%E3%83%88-dcc61a57-8ff0-cffe-9796-cb9706c75eec

ショートカットキー一覧［完全版］- パソコン仕事が爆速になるWindows、Office、Googleのキー操作 286選 | できるネット
https://dekiru.net/article/18619/
enebularのデバックのやり方

enebularのデバックのやり方について一ついい方法を見つけたので記載していく。
今後見つけ次第追記

##デバックする準備前のコード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1269684/0b43e802-4b75-ed48-cfda-9727e40b6842.png)

インプットに数値を入れて料金判断でどの拠点まで行けるかを判断するコードでした。
最終的にwebhookで他のiPaaSに接続するものでした。

料金判断でどこにも行けないに通ると

```
{"value1":"行きません","value2":"行けません","value3":"行けません"}
```
と出力されるようにしていた。
しかし結果は
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1269684/b339d63e-6350-88a7-16e8-2826b65c52bb.png)

失敗。。。

##デバック方法①
今後増えるかもしれないので①とする。
失敗からみてテンプレート生成かjson変換でこけていると判断。
このように変更
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1269684/7165adfb-353b-934d-1eba-3dc3e1453507.png)
調べたいところでデバックを追加。

実行したところ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1269684/2a3ce58e-edba-ddd8-fab6-c983a2044789.png)
テンプレート生成時に余計な「;]が入っていることに気づけた。
「;」削除後、実行ができました。

ブレイクポイント等があるかもしれませんがデバックを入れることでバグ解消につながりました。
【JavaScript】functionとアロー関数のthisの違い



ダメな例

```
document.addEventListener("turbolinks:load", () => {
    $('#post_image').on('change', () => {
      var size_in_megabytes = this.files[0].size/1024/1024;
      if (size_in_megabytes > 5){
        alert("アップロード可能なファイルサイズは5MBまでです。より小さいサイズのファイルを選んでください。");
        $('#post_image').val("");
      }
    });
  });
```
  
このエラーになる

```
image_size.js:4 Uncaught TypeError: Cannot read property '0' of undefined
at HTMLInputElement.<anonymous> (image_size.js:4)
```

###``() => {}``内のthisはaddEventListnerメソッド実行時のスコープであるグローバルスコープ(document)を指す。
this.filesは定義されていない(undefinedだ)から'0'は読み込めません！とのこと

```
document.addEventListener("turbolinks:load", () => {
    $('#post_image').on('change', () => {
      var size_in_megabytes = this.files.size/1024/1024;
      if (size_in_megabytes > 5){
        alert("アップロード可能なファイルサイズは5MBまでです。より小さいサイズのファイルを選んでください。");
        $('#post_image').val("");
      }
    });
  });
```
```
image_size.js:4 Uncaught TypeError: Cannot read property 'size' of undefined
at HTMLInputElement.<anonymous> (image_size.js:4)
```

this.filesは定義されていない(undefinedだ)から'size'は読み込めません！とのこと
  
うまくいく例

```
  document.addEventListener("turbolinks:load", () => {
    $('#post_image').on('change', function(){
      var size_in_megabytes = this.files[0].size/1024/1024;
      if (size_in_megabytes > 5){
        alert("アップロード可能なファイルサイズは5MBまでです。より小さいサイズのファイルを選んでください。");
        $('#post_image').val("");
      }
    });
  });
```
  
###``function(){}``内のthisはaddEventListnerメソッドを保持する``$('#post_image')``オブジェクト(DOM)を指す
最低限覚えておきたいWindows 10ショートカットキー

# 最低限覚えておきたいWindows 10ショートカットキー
## 知らなければ最早恥。～一般教養編～

|キー|何が起こる？|
|:-:|:-|
|Ctrl + a|全選択|
|Ctrl + c|コピー|
|Ctrl + x|切り取り|
|Ctrl + v|ペースト|
|Ctrl + z|元に戻る|

## 覚えておいて損はない！～アプリ操作編～

|キー|何が起こる？|
|:-:|:-|
|Win + D|デスクトップを表示|
|Win + 1～9|タスクバーの1～9番目のアプリを起動|
|Alt + Tab|別のアプリに切り替え|
|Alt + F4|アプリを閉じる|

## 画面を分けてみよう！～仮想デスクトップ編～

|キー|何が起こる？|
|:-:|:-|
|Ctrl + Win + D|仮想デスクトップを追加|
|Ctrl + Win + F4|現在の仮想デスクトップを削除|
|Ctrl + Win + →|右の仮想デスクトップに移動|
|Ctrl + Win + ←|左の仮想デスクトップに移動|
|Win + Tab|タスクビュー|

## 全人類覚えよ！！～最速シャットダウン編～

|キー|何が起こる？|
|:-:|:-|
|Win + D|デスクトップを表示|
|Alt + F4|Windowsのシャットダウンメニュー表示|
|Enter|シャットダウンOK|

# 後書き

いかがだったでしょうか？
僕が覚えているショートカットの中で厳選したものを紹介しました。
さらに詳しく知りたい方は調べるなり、試してみたりしてはいかがでしょうか。
僕もまだ約30個程のショートカットしか知らないのでまだまだもっと覚えるには時間がかかりそうです。
Windowsユーザーの皆さん。良いショートカットライフを！
Macは何1つ知ららないただの無知なので、機会があれば覚えたいと思います。
grbl_ESP32 ファームの書き込み方法変更

ワケあって最新のgrbl_ESP32をいじっているのですが、
最新のファームはArduino IDEではうまくファームの書き込みができません。
（ライブラリインクルードができない）

VS codeのPLatformIOを使って書き込むと問題なく書き込みが出来ます。
https://github.com/bdring/Grbl_Esp32/wiki/Compiling-with-PlatformIO
AKS で Node に接続する (kubectl debug / Azure Portal)

AKS (Azure Kubernetes Service) のお勉強がてら Kubernetes 関連の記事を眺めていたところ、「[Kubernetes: kubectl debug node でノードをデバッグする](https://qiita.com/tkusumi/items/c689440ae5b90710e462)」という記事があり、やってみました。

本記事では AKS でやってみた情報を記載していますが、内側の詳細などは上記の記事のほうが詳しいため、ぜひ併せて読んでみてください。

# 環境

* AKS (v1.20.5)
* kubectl (v1.21.1)

# kubectl debug コマンドを試す

## 接続用 Pod の作成

下記のコマンドを実行し、接続用の Pod を作成します。

```
> kubectl debug node/<NODE_NAME> -it --image=busybox
```

### ※debug オプションが見つからない場合

恐らく、kubectl のバージョンが古いです。アップデートしましょう。

ちなみに Windows 環境では [Chocolatey](https://chocolatey.org/) 経由でもインストール可能です。パッケージ名は [kubernetes-cli](https://community.chocolatey.org/packages/kubernetes-cli) でした。

```
> choco install kubernetes-cli
```

## Node のファイルシステムのマウント領域を見る

接続した Pod 内の `/host` 配下に Node のルートディレクトリがマウントされています。

```
/ # ls /host
NOTICE.txt   dev          lib          lost+found   opt          run          
srv          usr          vmlinuz.old
<略>
```

## chroot する

`/host` に chroot することで、パス等の影響があるコマンド等も実行することができるようになります。

```
# chroot /host
```

# Azure portal から Node に繋ぐには

と。ここで Azure Portal から AKS の個々の Node につなぐ方法も記載しておこうと思います。

AKS を作成した際、「Kubernetes サービス」が作成されたリソースグループには Node の実体のリソースは見つかりません。

ではどこにあるのかというと、同時に作成される別のリソースグループ (※) の配下に VM スケールセットが作成されており、そのインスタンスが Node のリソースになっています。

(※) このリソースグループ名は `MC_<AKSリソースグループ名>_<AKSサービス名>_<AKSのリージョン> `となっています。

「仮想マシンのスケールセット」のリソースをクリックし…

![aks_vmss_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218221/d341960b-cef5-8e79-3010-1dd002b9ae00.png)

左ペインで [設計] - [インスタンス] をクリックすると、Node の一覧が表示されます。これらは VM インスタンスですね。

![aks_vmss_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218221/e632438a-0ea2-6001-2723-542143728a45.png)

接続したい Node をクリックし、次の画面ではおなじみ VM (IaaS) の画面になるので、あとは [接続] をクリックして SSH で接続してやれば OK です。

![aks_vmss_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218221/9e3ac53e-24e6-d170-d653-e946ee53bc6c.png)
Pandasのto_sqlで行が多すぎて時間がかかる or エラーになった時に...

# 0. はじめに

SQLiteの記事を過去に書いてきました。
その中で実際に株のデータをSQLに入れるという記事があるのですが、実際にPandasで読み出した株価＊年分のDataframeをそのまま`to_sql`でSQLに挿入しようとすると、無茶苦茶時間がかかります。

(過去記事と記載した該当部分は以下)

https://qiita.com/ku_a_i/items/ab395c1cf4493517a1dd

```Python:
"""
実際に動かしてみるとわかるが、これ無茶苦茶時間かかります。
"""

#dfをto_sqlでデータベースに変換する。DBのテーブル名はpriceとする
df.to_sql('price', db, if_exists='append', index=None)
```

そこで本日はそんなときの対処方法を書いておきます。

# 1. 対処方法

実は簡単で`method='multi'`を入れるだけでいいのです。

```Python:
"""
重い操作。内部的には1行1行insertしているので遅くなっている。
"""
df.to_sql('price', db, if_exists='append', index=None)

"""
一瞬。内部的には一括でinsertさせている
"""
df.to_sql('price', db, if_exists='append', index=None, method='multi')
```

たったこれだけです。
`method='multi'`を入れるだけですぐに終わるので試してみてください。

# 2. too many SQL variablesの対処法

## 2-1.エラーの確認

しかし、実はこの`method='multi'`は行数が大きすぎるとエラーで実行できない。
以下は実際の私の株データの例です。
**まずはDataframeの大きさをprintさせてますが、見るとわかるように1500万行もあります。
これを1行1行SQLに入れてたら1日で終わるかどうかも怪しいです。**

かといって、`method='multi'`だと以下のように`too many SQL variables`というエラーがでてしまいます

```Python:
print(df.shape)
df.to_sql('price', db, if_exists='append', index=None, method='multi')
```

```:実行結果
(15462514, 7)

(途中略)
   1558         data_list = list(data_iter)
   1559         flattened_data = [x for row in data_list for x in row]
-> 1560         conn.execute(self.insert_statement(num_rows=len(data_list)), flattened_data)
   1561 
   1562     def _create_table_setup(self):

OperationalError: too many SQL variables
```

## 2-2.対処法

実はPandasでは`chunksize`というパラメータがあって、**メモリに乗り切らないような大容量データを用いるときに一回に読み込む量を指定することが出来る。**
これと`to_sql、method='multi'`を組み合わせればいいだけである。

```Python:
"""
chunksize=5000で5千行ずつ書き込みさせている。
too many SQL variablesにならない程度に数字を大きくすればいいと思います。
"""
df.to_sql('price', con, if_exists='append', index=None, method='multi', chunksize=5000)
```

実際に私の環境で本命令時間を計測した結果、1分でSQLに挿入が出来ました。

# 3.chunksizeは読み出しにも使えます

to_sqlで保存した大量のdfを再度SQLからdfに戻す方法も書いておきます。
※これもchunksize使わないと無茶苦茶時間かかります！

```Python:
# データベースの接続
dbname = ('***.db')
db = sqlite3.connect(dbname, isolation_level=None)

# 同じくchunksizeを使用してdfで読み出す
dfs = []
for chunk in pd.read_sql_query('SELECT * FROM price', con=db, chunksize=1000):
	dfs.append(chunk)
df = pd.concat(dfs)
```

# 4.おわりに

実はこれ`to_sql`や`read_sql_query`以外に`pd.read_csv`等でも使用できます。(ただし読み込みがテキストになるが)
Pnadasでメモリに乗らないような大きな読み書きをする際には、`chunksize`を指定して快適に操作しましょう！

参考：https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_sql.html

# 5.追記
書き込むときの方法はわかったとして、逆に読み出す時に遅くてイライラしちゃってる方は以下記事も参考にしてみてください。結構早く読み出せますよ

https://qiita.com/ku_a_i/items/e326902e67a99594a6e4
ムームードメインで新規ドメイン取得後、ロリポップで独自ドメイン設定できない時は「10日間無料でお試し」の方に紐づいている可能性も疑う

ムームドメインで新規ドメインを取得後、自分のロリポの管理画面で独自ドメイン設定をしようとしたら以下のようなエラーが出て設定ができない。
> 「入力されたドメインはすでに他のアカウントにて設定されているか、ロリポップのドメインのため設定をすることができません。また、ムームーメールでご利用中の独自ドメインは、設定をすることができません。」

こちらとしては「あれ？まだ設定なんかしてないけど？」という状態なのだが、ヘルプをみても以下の内容しか出てこない。
>以下いずれかの状態になっている可能性がございます。
>1. 対象ドメインが当サービスの別アカウントに設定されている
>2. 対象ドメインがムームーメールに設定されている

以前まではドメイン取得したらすぐにロリポップの管理画面で独自ドメインしてもなんの問題もなかったのに。まだ反映されてないのかな？とか疑って何時間か放置したり、ムームードメイン側の設定が違うのかと思ってネームサーバーの設定やムームーDNSの過去に設定済みのデータをひっくり返してもなんの差異もない。

もう設定が終わってるとか？
![スクリーンショット 2021-05-30 16.40.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216609/b9594388-217f-8576-020c-33f9df755c40.png)

んなわけないか。

あれー？
ヘルプをもう一度読むとこんな記述を見つけた。
> **ムームードメインでのドメイン取得時、もしくはドメイン取得後にコントロールパネルより申込んだ当サービスのアカウントから対象ドメインを解除する場合**
> 1. ムームードメインにご登録のメールアドレス宛にお送りしている『ロリポップ！レンタルサーバーを10日間無料でお試し【ムームードメイン】』というタイトルのメールに記載されているログイン情報をご確認ください。
> 2. 対象アカウントのユーザー専用ページにログインしてください。
> 3. ユーザー専用ページにログイン後、独自ドメイン設定の解除方法を参考に対象ドメインを解除してください。

**ドメイン取得時に申し込んだアカウント**から解除？**10日間無料お試し**？確かにそんなメール届いてた気がする。
これってひょっとしてドメイン取得と同時に10日間の無料ロリポアカウントが発行されて、取得したドメインがそっちに紐づいているとかいうそういうオチ？
と思って、「10日間無料お試し」メールで案内されているアカウントでログインしてみたら....。（※既存のロリポアカウントにログイン済みの場合は一度ログアウトしてくださいね。）
**イターーー！**
![スクリーンショット 2021-05-30 16.37.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216609/701f65ab-25e9-698a-18a2-e6303896c3b1.png)

と思って申し込みのとこから見直してみたらしっかり書いてありましたわ。こんなのができてたのか。「あーいつもの作業ね」って思って、ちゃっちゃか作業しすぎて見落としてたんですね。しっかり読まなきゃダメですね。ということであとはこっちのアカウントから取得したドメインを解除するだけですね。
![スクリーンショット 2021-05-30 16.44.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216609/08a3236a-e132-9db9-f73f-65262c955408.png)
MacにVerilog環境を構築する(Big Sur対応版)

LSIメーカーに就職した友人とVerilogを用いたディジタル回路設計の勉強をすることになりました。macOS BigSurに対応した環境構築方法を備忘録として残しておこうと思います。

# 今回構築した環境
* macOS 11.3.1 Big Sur
* Icarus Verilog 11.0
* GTKWave 3.3.107
* XQuartz 2.8.1

# Icarus Verilogのインストール
Verilogの実行環境としてフリーのIcarus Verilogをインストールします。インストールにはHomebrewを用いることとします。

```bash
brew install icarus-verilog
```

<details><summary>動作確認</summary><div>

`iverilog`コマンドを実行して、以下の様に表示されればインストール成功です。

```bash
$ iverilog 
iverilog: no source files.

Usage: iverilog [-EiSuvV] [-B base] [-c cmdfile|-f cmdfile]
                [-g1995|-g2001|-g2005|-g2005-sv|-g2009|-g2012] [-g<feature>]
                [-D macro[=defn]] [-I includedir] [-L moduledir]
                [-M [mode=]depfile] [-m module]
                [-N file] [-o filename] [-p flag=value]
                [-s topmodule] [-t target] [-T min|typ|max]
                [-W class] [-y dir] [-Y suf] [-l file] source_file(s)

See the man page for details.
```

</div></details>

# GTKWaveのインストール
ディジタル回路設計ではHigh/Lowの信号波形を扱います。そこで、波形描画ソフトのGTKWaveをインストールします。GTKWaveは単独でインストール出来ず、XQuartzを同時にインストールします。

```bash
brew install --cask xquartz gtkwave
```

# GTKWaveの起動
LauncherからGTKWaveを起動します。初回起動時は以下の画面が表示され、起動出来ません。ここでは`キャンセル`をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469079/b5dbaf06-991f-ac76-1742-bb6fbbefba33.png)

`システム環境設定`を起動し、更にセキュリティとプライバシーを起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469079/a7ccba50-9735-7a7c-289f-0656a4cef81b.png)

`ダウンロードしたアプリケーションの実行許可:`に「<font color="RED">"gtkwave.app"は開発元を確認出来ないため、仕様がブロックされました。</font>」と表示されます。その右隣の`このまま開く`をクリックします。以下のウィンドウが表示されます。`開く`をクリックします。
:warning: **rootパスワードの入力を求められた場合は、入力します。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469079/42173a5a-03fc-73b7-ca54-35423460a429.png)


無事起動すると、以下のウィンドウが起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469079/a6de60c2-107c-faed-5e81-9b71976446b5.png)

# まとめ
最新のmacOSにVerilogHDL環境を構築する方法の備忘録メモをまとめました。今後ディジタル回路設計の勉強に活用して行こうと思います。

# Reference
* [MacOSでのverilogHDL開発備忘録(icarus verilog編)](https://qiita.com/RotaryKer/items/d8f6d218962c213b0577)
pythonである文字数以上だったら省略、...にする

#やりたいこと

例えば、

```text
山田　一郎
鈴木　次郎
佐藤　ゴンザレスモリモリマッスル花子
```

という名前データを扱うとき、


```text
山田　一郎
鈴木　次郎
佐藤　ゴンザレ...
```

のように、10文字を超えそうなときは、...で省略する、といった処理を行いたいときは、以下のようにすればよい。


```python
student_name_list = ["山田　一郎", "鈴木　次郎", "佐藤　ゴンザレスモリモリマッスル花子"]
name_len_max = 10 # プリントできる最大の文字列
syouryaku_str = "..."
for student_name in student_name_list:
    if len(student_name) > name_len_max:
        name_print = student_name[:name_len_max-len(syouryaku_str)] + syouryaku_str
    else:
        name_print = student_name
    print(name_print)
```


```text:実行結果
山田　一郎
鈴木　次郎
佐藤　ゴンザレ...
```

注意点として、省略文字...も含めて10文字にしているので、もし省略文字を含めずに10文字にしたい場合は適宜修正して使用してください。
【enebular】switchから結果をjson変換する方法

enebularのswitch機能を使った後に結果をjson変換する方法

enebularのswitch機能をネットで検索すると下のような条件分岐した後に終わりというものが多かった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1269684/83752d1a-7216-ccdc-3c13-2929f1eba00b.png)

なので今回は条件分岐した後特定の値を設定しjsonに変換する方法を書く。

まずswitch後に値を設定するため、テンプレートを使用。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1269684/1500274c-c298-0bc5-6725-264e78d00a48.png)

テンプレートの中身の値は今回json形式に変換するため以下のように設定。

```
{"value1":"値1","value2":"値2","value3":"値3"}
```

その後これらの値をjson変換する機能を用いて変換
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1269684/123b44e9-5148-9fca-1e4b-3741bdf8a73c.png)


全体像
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1269684/2cc36021-1295-52f6-3e0b-d9f6f8f2acc4.png)


変換機能はほかにもあるのでそれにあった形にテンプレートを使用すれば条件ごとに出力を変換出来る。
Flutter + Firestore 同じドキュメントIDが存在するかチェックしてから保存

#ドキュメントIDを指定して保存する時、ダブってないか確認したい
FirestoreでドキュメントIDを指定して保存するときってありますよね？

例えば映画情報を取得できるAPIを使ってた場合、**APIの中で既に映画に対して割り振られているIDをそのままドキュメントIDとして使いたい**、といったパターンがあるかと思います。

そういった時に「ドキュメントIDが既に存在するかチェックしてから保存」という処理にしたいと思い、調べてみました:wink:

#前提
FlutterとFirebaseの連携部分は省きます。

環境は下記の通り

```yaml:pubspec.yaml
environment:
  sdk: ">=2.7.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  firebase_core: "0.7.0"
  firebase_auth: "^0.20.1"
  cloud_firestore: "^0.16.0+1"
  firebase_storage: "^7.0.0"
  cloud_functions: ^0.9.0
```

#ドキュメントIDが既に存在するかどうかをチェックして、存在しなければ新たにデータを保存する

ここではAPIから取得した`movieId`という値を、そのままドキュメントIDとして使用します。

**「映画をマイリストに保存する」みたいな処理をイメージして頂けるとわかりやすいかと！**

```dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';

class AddMovieButton extends StatelessWidget {

final int movieId;
final title;
AddMovieButton(this.movieId, this.title);

  final FirebaseFirestore firestore = FirebaseFirestore.instance;
  final FirebaseAuth auth = FirebaseAuth.instance;

void _addMovie(BuildContext ctx) async {
    final uid = auth.currentUser.uid;
    final _userRef = firestore.collection('users/${uid}/movies');
    final _movieRef =
        firestore.collection('users/${uid}/movies').doc(movieId.toString());
    await _movieRef.get().then((docSnapshot) => {
          if (docSnapshot.exists)
            {
              // 既に登録されているドキュメントの場合
              print('追加しない')
            }
          else
            {
              // 登録されてない新しいドキュメントの場合
              _userRef
                  .doc(movieId.toString())
                  .set({'id': movieId, 'title': title})
                  .then(
                    (value) => print('追加しました'),
                  )
                  .catchError((error) {
                    print('追加失敗！')
                  }),
            }
        });
  }

// 省略

}
```

あとは`print`の部分を好みに合わせて、アラートやSnackBarにすると良いかと:grinning:

https://qiita.com/kokogento/items/54d6695844edc9415324


#参考
https://stackoverflow.com/questions/46880323/how-to-check-if-a-cloud-firestore-document-exists-when-using-realtime-updates
Windowsでpyenv（pyenv-win）とvenvを使ってPythonの仮想環境を構築

Windows上で複数のバージョンのPythonをもつ必要があったので調べて、構築した手順をメモします。
初めて環境構築する方にお役に立てれば幸いです。

# pyenv とは

pyenv は、Python バージョン管理ツールです。
Python の複数のバージョンを簡単に切り替えることができます。
pyenv は、WSL 以外の Windows 環境では利用できないため、代わりに pyenv-win を利用します。

# pyenv（pyenv-win）をインストールする

https://github.com/pyenv-win/pyenv-win


公式を見ますと、いくつかの方法がありました

- pipでインストールする方法
- zip形式で更新サイトからダウンロードし、指定の場所にファイルを展開する方法
- git cloneする方法
- Chocolateyからインストールする方法(Windows版のパッケージ管理）

Powershellでpipをつかってインストールしたのですが、`ERROR: Can not combine '--user' and '--target'` でエラーになってしまいました。

```powershell
> pip install pyenv-win --target $HOME\\.pyenv
```

エラーになった場合、後ろに`--no-user` をつけると上手くいきました。

```powershell
> pip install pyenv-win --target $HOME\\.pyenv --no-user
```

# 環境変数の追加

PowerShell から次のコマンドを実行して、環境変数 PYENV を設定する。

```powershell
> [System.Environment]::SetEnvironmentVariable('PYENV',$env:USERPROFILE + "\.pyenv\pyenv-win\","User")
```

PowerShell から次のコマンドを実行して、PATH に pyenv の実行パスを追加する。

```powershell
> [System.Environment]::SetEnvironmentVariable('path', $env:USERPROFILE + "\.pyenv\pyenv-win\bin;" + $env:USERPROFILE + "\.pyenv\pyenv-win\shims;" + [System.Environment]::GetEnvironmentVariable('path', "User"),"User")

```

環境変数の確認は、PCのアイコンからプロパティを参照、詳細情報を表示し、「システムの詳細設定> 環境変数」から確認できます

今設定した環境変数を読み込ませるために、既存で開いてるコマンドプロンプトは閉じて、新たにコマンドプロンプトを起動します。

PowerShell で pyenv コマンドがインストールされたことを確認します

```powershell
> pyenv --version
The system cannot find the file specified.
pyenv 2.64.7.4
```

# サポートしてる Python のバージョンの一覧を見る

```powershell
> pyenv install -l
```

# 指定のバージョンをインストールする

```powershell
> pyenv install 3.8.2
```

# 環境に設定できるバージョンの一覧を確認する

```powershell
> pyenv versions
  3.8.2
  3.9.2
```

# 環境の設定を行う
バージョンの切り替えをしてみます。localの場合は現在のディレクトリにしたpythonを実行します。
globalの場合は全体に反映されます。

```powershell
> pyenv local 3.8.2
> pyenv versions   
* 3.8.2 (set by C:\web-test\.python-version)
  3.9.2
```

```powershell
> pyenv global 3.8.2
```

# 仮想環境の作成

```powershell
> python -m venv env
```

# 作成した仮想環境をアクティベートする
作成した仮想環境にてpipを使いインストールができます。

```powershell
PS C:\web-test > env\Scripts\activate
(env) PS C:\web-test > 
```

# ディアクティベートする場合は以下のコマンドを実行する

```powershell
> deactivate
```
GitHubランキング

Github使い始めるのに参考させてもらった記事

#第1位
https://qiita.com/nenohi/items/9afbc15033580d10d6d7

#第2位
https://qiita.com/nanoneko/items/bdb079d29a211902470f

#第3位
https://qiita.com/narimiya/items/af28df4386c3c4619f99

わかりやすい記事をいつもありがとうございます
【Java】LocalDateTimeの使い方

# LocalDateTimeとは
Java8からjava.timeパッケージに追加されたクラスで、日付」と「時刻」の両方を扱うことが出来ます。
タイムゾーンのない日時を取得できます。
`ex.2021-05-30T15:47:13.395703`

# 現在日時を取得する方法

```java
import java.time.LocalDateTime;  
import java.time.format.DateTimeFormatter;

public class Main {   
    public static void  main(String [] args){  
  
        LocalDateTime now = LocalDateTime.now();  
        System.out.println(now);
    }  
} 
```

###出力結果

```
2021-05-30T15:47:13.395703
```

# フォーマットを指定する方法
取得した日時のフォーマットを指定するには、`DateTimeFormatter`クラスを使用します。

```java
public class Main {   
    public static void  main(String [] args){  
        //現在日時を取得
	    LocalDateTime now = LocalDateTime.now();  
        System.out.println(now); 
        
        //フォーマットを指定
        DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        System.out.println(now.format(f));
    }  
} 
```

###出力結果

```java
//フォーマットを指定していない出力
2021-05-30T16:11:25.778861

//指定したフォーマットで出力
2021/05/30 16:11:25
```

#参照
[Java Platform SE8 #LocalDateTime](https://docs.oracle.com/javase/jp/8/docs/api/java/time/LocalDateTime.html)
カスタムセルのidentifierを管理しやすくする


# はじめに
カスタムセルを登録するとき、こんなかんじで***nibName***や***identifier***を入力するの、面倒ですよね。

```swift:ViewController.swift
override func viewDidLoad() {
    super.viewDidLoad()
    videoListCollectionView.register(UINib(nibName: "VideoListCell", bundle: nil), forCellWithReuseIdentifier: "VideoListCellId")
}
```
手打ちで入力すると予測変換もできないし、エラーの温床となるので良くないです。

# 対策

カスタムセルを登録するときは、カスタムセル側に次のような記述を書くようにするのが良いです。


```swift:ViewListCell.swift
    static let identifier = "VideoListCellId"
    static func nib() -> UINib {
        return UINib(nibName: "VideoListCell", bundle: nil)
```
identifierの文字列とUINibのプロパティを定義して、それをstaticでクラスに紐付けています。（identifierの文字列はxibファイルのidentifierと一致させましょう。）
こうすると、viewcontroller側での呼び出し方は次のようになります。

```swift:ViewController.swift
override func viewDidLoad() {
    super.viewDidLoad()
    videoListCollectionView.register(VideoListCell.nib(), forCellWithReuseIdentifier: VideoListCell.identifier)
}
```

このように予測変換で打つことができるので、バグの温床がなくなります。

# さいごに
今回の例に限らず、apiキーやadUnitIDなどの長い文字列は、一度どこかの変数に定義してあげてると、とても開発しやすくなります。
Databricksクラスターポリシーを特定のユーザーにのみ適用する手順

特定の構成でのクラスター作成を許可するクラスターポリシーを、特定ユーザーにのみ適用する手順を説明します。

クラスターの作成権限を持っているユーザーは、制限のないクラスターポリシー「Unrestricted」を利用できます。Unrestrictedポリシーでは任意の構成でクラスターを作成できるため、大幅にコストが増加するリスクがあります。このため、Unrestrictedポリシーを使わせたくないユーザーの利用権限を削除します。

Admin ConsoleのUsersを開き、Unrestrictedポリシーを与えたくないユーザーの「Allow cluster creation」チェックボックスが外れていることを確認します。チェックがついている場合には解除します。以下の例では二行目のユーザーのチェックが外れている状態を示しています。この状態では、ユーザーTakaaki Yayoiはクラスターを作成することができません。
![Screen Shot 2021-05-30 at 15.30.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/0205c70d-08ba-5d6b-8697-9ccde2101213.png)

次に、上記ユーザーが利用できるクラスターポリシーを作成します。クラスターポリシーの設定方法に関しては以下のマニュアルを参照ください。

- [Create a cluster policy](https://docs.databricks.com/administration-guide/clusters/policies.html#create-a-cluster-policy)
- [Cluster policy definitions](https://docs.databricks.com/administration-guide/clusters/policies.html#cluster-policy-definitions)

**Name**にクラスターポリシー名、**Definitions**にポリシー定義を入力します。
![Screen Shot 2021-05-30 at 15.29.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/61f5fad2-70ff-a19a-5fea-2b264b73dd52.png)

**Permissions**でクラスターポリシーに対するアクセス権を設定します。アクセス権を割り当てることで、当該ユーザーはアクセス権が割り当てられたクラスターポリシーのみを使用できるようになります。
![Screen Shot 2021-05-30 at 15.29.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/93a97a65-b636-67cd-c0ea-485d6a94596c.png)

クラスターポリシーが一つしか割り当てられていない場合には、クラスター作成画面ではデフォルト値としてクラスターポリシーが適用されます。複数割り当てられている場合にはドロップダウンリストからクラスターポリシーを
選択します。
![Screen Shot 2021-05-30 at 15.29.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/b5a16977-2d1e-fdd6-9e32-8585c8197c74.png)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
Java Gold SE 8（1ZO-809）に合格しました

## はじめに
Java Gold SE8(Programmer Ⅱ）試験に合格しました。
勉強期間が長すぎて記憶が曖昧だったり、『いまさら8かよ』という気もしますが、お約束なのでメモを残しておきます。

## 自分のレベル
元々は組み込み系の業界でC/C++を20年くらい使っていて（コーディングしていたとは言っていない）、Javaは1行も書いたことなかったのですが、Web系の仕事をするようになって『WebならJava取るよね』という流れで受験することにしました。
ちなみに実業務では、C#/Kotlin/TypeScriptを使いながらのJava学習だったので、頭が混乱して地味に辛かったです。

Silverの方は2020年の2月に取ったのですが、その後のコロナ騒ぎを言い訳にサボっていたら思いのほか時間が空いてしまいました。Silverの勉強で覚えたこともかなり忘れてしまい、これは失敗だったと思います。続き物の試験はさっさと受けるべきですね。

## 合格までの勉強期間
Silverを取った後、勉強を始めてから約14か月。
うち、真面目に勉強していたのは3か月くらい、実働は50～100h程度でしょうか。

## 対策本
以下の2冊を買って学習しました。

#### 紫本
Silverの時は黒本のみで合格できたのですが、黒本は問題集なので基本的な説明が少なく、Goldの内容だとちょっと厳しい予感がしたので、先に教科書的な本で学習しようと考えてこれを買ってみました。

https://www.amazon.co.jp/gp/product/479814682X/ref=ppx_yo_dt_b_asin_title_o09_s00?ie=UTF8&psc=1

ちなみにAmazonの購入履歴によるとSilver合格直後の2020年2月に買っていて、当時はやる気があったようです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15083/b21010c6-b9f4-68ad-861d-723acae13d46.png" width=300 />

内容は、教科書だけあって読んでいると超眠くなり遅々として進みませんでしたが、半年くらいかけて2周ほど読みました。


#### 黒本
Silverで読んで良かった安心感＆試験の形式に慣れるためにこちらも購入。

https://www.amazon.co.jp/dp/4295000035/ref=cm_sw_em_r_mt_dp_SBY9WRCXW715REXZBNHB?_encoding=UTF8&psc=1

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15083/a866d2bd-97ab-5dce-e788-e095a0692b0d.png" width=300 />

各章の練習問題をひたすら解きつつ、疑問に思ったところは解説を読んだり紫本に戻ったりしながら進めていきます。
2冊を見比べたり、両方で説明の厚い所は重要ポイントだと認識できたりで、結果的に両方買って正解だったと思いました。

こちらも2周したところで付録の模擬試験をやります。

模擬試験①（1回目）52/85  `不合格`
模擬試験①（2回目）84/85  `合格`
模擬試験②（1回目）52/85  `不合格`
模擬試験②（2回目）82/85  `合格`
模擬試験③（1回目）53/85  `不合格`
模擬試験③（2回目）80/85  `合格`
模擬試験①（3回目）82/85  `合格`
模擬試験②（3回目）74/85  `合格`
模擬試験③（3回目）82/85  `合格`

後半は安定して合格点を取れるようになってきたので、『そろそろ行けるかな』と思って本番を受験します。


しかし実はこれが結構失敗で、同じ試験をやると2回目以降は理解したというより問題の答えを覚えてしまって回答できることが多く（本人にその自覚はない）、実力以上の得点だったことを後で思い知ります。

## 本番試験
ピアソンVUEを利用して自宅から受験しました。

タイミング良く「1回目の受験が不合格でも、2回目の再受験が無料になります」の特典が使えたので、精神的には少し余裕をもって望めました。
¥29,400の再課金は自腹勢にとってはかなりの恐怖です。

試験開始前に部屋の環境確認など色々と手順があるので、初めて受験する際には余裕をもってチェックイン開始時間になったらすぐに始めたほうが良いと思います。
（ちなみに自分は、ちょっとしたトラブルが発生して割と大変な目に遭いました。）

問題の傾向としては、Silverの様に重箱の隅をつついたり変なひっかけ問題は少なく、純粋に知識を問われる系の物が多かったように思います。
そのため変なストレスは無かったのですが、単純にGoldで要求される知識の範囲とレベルが高くて、制限時間をギリギリまで使ってなんとか最後まで行きました。
後で見直すチェックを付けた自信のない回答も多く、『これは落ちたかもしれんな。。』と思いながら終了しましたが、ギリギリで合格！
これはマジでうれしかったです。ギリギリだけど。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15083/534d600f-a2d6-b6b6-e52d-83ff041e49ec.png" width=800 />


## まとめ
今回の受験で学んだこと

- 続き物の試験は忘れる前に受ける
- さっさと試験を申し込んでしまう
- 資格は資格と割り切って取り組む

OracleのJava認定は期限切れがないので、これで一生Java Goldです。
でもこの先、Java使う事あるかなあ。
【OCI】新しいバージョンのDRGを試す① - DRG作成、VCNアタッチ -

###概要
新しいバージョンのDRGを試していきます。
最初にDRGの作成とVCNアタッチ方法について検証を通じて確認してみます。


###検証構成
・同じリージョンの中に2つのVCNを作成し各VCNにpublic subnetを1つずつ作成します
・上記で作成した2つのpublic subnetのルート・ルール及びセキュリティ・リストを
　相手subnetと通信が行えるように設定します
・各VCNにVCN間疎通テストに利用するインスタンスを1つずつ作成します
・DRGを作成後、仮想クラウド・ネットワーク・アタッチメントを作成して上記で作成した
　2つのVCNを関連づけます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/fc11f1f8-51ac-0e08-ae9d-a2f620366c39.png)

###設定

①DRGの設定
設定方法は既存のDRGと基本的に同じです。

コンソール画面にて
[ネットワーキング] ⇒ [動的ルーティング・ゲートウェイ]を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/e6e9703d-f55a-3aa1-1114-dc5b79c0bf7c.png)
[動的ルーティング・ゲートウェイの作成]をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/7a6b4640-16d7-8dcc-d136-3a4d2a84fafb.png)
DRGの名前を入力後、[動的ルーティング・ゲートウェイの作成]をクリックすると
作成完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/39ace91e-d2ea-cb11-3d31-686843ad5e12.png)

②VCNをアタッチ
DRGの詳細画面を表示させると画面左のリソースに[仮想クラウド・ネットワーク・アタッチメント]
という項目があるのでそちらを選択
その後[仮想クラウド・ネットワーク・アタッチメントの作成]をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/844cec8d-bb11-a616-8bb2-cd818cd25f5b.png)
[仮想クラウド・ネットワーク・アタッチメントの作成]画面において
添付名(オプション)入力後、アタッチするVCNを選択して
[仮想クラウド・ネットワーク・アタッチメントの作成]をクリックすると
作成完了です。
※同じ手順でVCN1とVCN2のアタッチメントを作成します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/ca45d489-11f3-6c33-d65b-95e9a8760d8a.png)

③設定結果確認
アタッチメントが作成され、各仮想クラウド・ネットワークと
関連づけられたことが確認できます。
またアタッチメント関連のパケットがDRGに入ってきた際に使われるルート表として
[Autogenerated DRG Route Table for VCN attachments]が指定されていることが
確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/6ed3c479-1471-a959-27bd-e6189a7ed820.png)


④ルーティング確認
作成したアタッチメントで使うルート表の中身を確認してみたいですね。
[Autogenerated Drg Route Table for VCN attachments]をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/0930b140-3f8d-cc74-98f7-4042fb9c5365.png)
[すべてのルート・ルールの取得]をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/cae191e5-1bc1-4a39-c469-097f357e5bb7.png)
VCN1のpublic subnet(10.0.1.0/24)とVCN2のPublic subnet(10.1.1.0/24)の
ネットワーク情報が動的に学習されていることが確認できます。
各VCNからDRGに入ってきたパケットはこのルーティング情報を使って制御されるわけですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/0810e47c-0264-718d-b803-bfd76570db37.png)

###動作確認
VCN1のpublic subnetに作成したインスタンス(10.0.1.100)と
VCN2のpublic subnetに作成したインスタンス(10.1.1.11)間でpingによる
疎通確認を行います。

①VCN1のインスタンス(10.0.1.100)からVCN2のインスタンス(10.1.1.11)に
pingを実施し応答が返ってくることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/9b862e21-14fd-df1d-2b9a-fb408e8b1516.png)
②VCN2のインスタンス(10.1.1.11)からVCN1のインスタンス(10.0.1.100)に
pingを実施し応答が返ってくることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411653/34befb21-100b-4fc9-f660-3f949773c5d1.png)

###まとめ
・新しいバージョンのDRGはアタッチメントという概念さえ理解すれば
簡単に設定できる気がしました。
・様々なタイプの複数のアタッチメントを1つのDRGに作成する場合、
キャパシティ、パフォーマンスはどのに考えるべきか把握しておくべきだと思いました。
(これから確認します)
スイフト勉強_データ型変換

前文に続いてデータの型変換について調べてみようと思う。

### IntとDoubleの型変換
まず、Int と Double は共に演算されないため、二つのうち一つを変換しなければならない。
Int が自動的に Double に変換されないことである。

```swift
var intValue:Int = Int(123.45) // error
print(intValue)
var price:Int = 100
var totalPrice = Double(price) * 1.1  //
print(Int(totalPrice))
```
ここで見られるように変換するタイプを記載し、括弧を生成してその中に変換する変数を入れればよい。

### 数字を文字列に変換
文字+文字に文字ではない他の資料型を入れる場合、エラーが発生するため、型変換を行う必要がある。
やはりやり方の上のようだ。

```swift
var maskCount:Int = 100
var message:String = "mask " + String(maskCount) + " remains"	
print(message)

print("maks " + String(maskCount) +  " remains")	
print("maks \(maskCount)" + " remains")
print("maks \(maskCount) remains")
```
### 文字を数字で
やはり上記の通りだ。

但し、注意すべき点は、変換しようとする文字に数字以外の値が入るとエラーが発生する。

```swift
var str = "3.1"

var intOtherValue : Int = Int(str) //nil
var doubleValue : Double = Double(str) //3.1

var intValue : Int = NSString(string: str).integerValue //3
var floatValue : Float = NSString(string: str).floatValue //3.09999
var doubleValue : Double = NSString(string: str).doubleValue //3.1
```

###is
isとasに区別され、isはインスタンスのタイプを確認(チェック)に使用する。
そしてas はインスタンスの型変換作業に用いられる。
isはBoolタイプをReturnし、指定されたインスタンスが特定のClassであるかを判別。

###as, as!, as?
「as」は「as, as?, as!」の3つに使われるんですが、

as は上位に変換(Upcast)するときにのみ使用され、下位に変換(Downcast)するときは？あるいは！のように使用される。

as？は文字通り選択的で、Optional ValueをReturnする。 Downcastが可能でなければ、nilが返される。 したがって、Downcastが不確実ならばas？を選択した方が良い。 as？によって型変換されたインスタンスをそのまま出力するとOptional() Valueが表示されるのが分かる。

as!は強制的にDowncastする。 そのため、Downcast が成功でない場合エラーを起こす。 また、as! によってDowncast されたインスタンスを出力するとき、Optional 値が強制的にunwrap されたことが分かる。

Upcastの場合には「as, as!, as?」が全部使われますが、

Upcastが失敗した場合、as、as!はエラーが発生する反面、as?はnil値として処理される。
SPEEDTEST CLIの結果をMuninで記録

# はじめに

* 「[Debian 10 busterでMunin - Qiita](https://qiita.com/mktlab/items/309b75421c0f25596988)」の続き

# SPEEDTEST CLI

* 「[Speedtest CLI - Internet connection measurement for developers](https://www.speedtest.net/apps/cli)」の「Install Options」で「Ubuntu/Debian」をクリック
* 表示された以下を実行

```console
$ curl -s https://install.speedtest.net/app/cli/install.deb.sh | sudo bash
$ sudo apt-get install speedtest
```

* 定期実行

```console
$ sudo crontab -e
...
18,38,58 * * * * /usr/bin/speedtest --server-id=7139 --format=csv > /usr/share/munin/plugins/speedtest.out 2>&1
...
```

# Munin

* プラグイン作成

```console
$ cd /usr/share/munin/plugins
$ sudo nano speedtest
```

```shell:speedtest
#!/bin/bash
case $1 in
    config)
    echo "graph_category network"
    echo "graph_title Speedtest"
    echo "graph_args -l 0 -u 1000000000 -r"
    echo "graph_vlabel download / upload (bps)"
    echo "down.label download"
    echo "down.type GAUGE"
    echo "down.draw LINE1"
    echo "up.label upload"
    echo "up.type GAUGE"
    echo "up.draw LINE1"
    echo "graph_info Graph of Internet Connection Speed"
    exit 0;;
    esac
OUTPUT=`/usr/bin/cat /usr/share/munin/plugins/speedtest.out`
DOWNLOAD=`echo "$OUTPUT" | /usr/bin/cut -d ',' -f 6 | /usr/bin/sed 's/"//g'`
DOWNLOAD=`echo $((DOWNLOAD*8))`
UPLOAD=`echo "$OUTPUT" | /usr/bin/cut -d ',' -f 7 | /usr/bin/sed 's/"//g'`
UPLOAD=`echo $((UPLOAD*8))`
echo "down.value $DOWNLOAD"
echo "up.value $UPLOAD"
```

* プラグイン有効化

```console
$ sudo chmod 755 speedtest
$ sudo ln -s /usr/share/munin/plugins/speedtest /etc/munin/plugins/speedtest
$ sudo /etc/init.d/munin-node restart
```

* Webブラウザで http://debian/munin/localdomain/localhost.localdomain/speedtest.html  を表示
    ![Screenshot_20210530-153130.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240188/f8ae20a8-9985-a7f0-3043-4cece92d817d.jpeg)
* 土日と平日夕方～夜の落ち込みが激しい・・・

# 参考

* [GitHub - giovino/munin-speedtest-plugin: A Munin plugin to graph the results from speedtest-cli](https://github.com/giovino/munin-speedtest-plugin)
Intel CPU F シリーズ + Nvidia GPU でUbuntu Desktopを 動かす

#背景
Intel CPU Fシリーズにはグラフィックボードがありません。
そのため、普通にUbuntu Desktopをインストールできるのか心配になり、Intel CPU F + Nvidia GPUの購入に踏み切れない人がいるかもしれません。
そこで、**Intel CPU F シリーズ + Nvidia GPUでもUbuntu Desktopが動かせたよ**という記事を残しておきます(同様の記事を探してもなかなか見つからなかったので)。

#設定方法
## Ubuntu Server のインストール
* Ubuntu Server (>=18)のブート可能なインストールメディアをUSBに入れます（USBの作り方は他の記事を参照してください）。
* インストールして再起動します。(他の記事を参照してください)。

## グラフィックドライバの設定
グラフィックに限らず諸々のドライバを入れます。

```
sudo apt update
sudo apt upgrade
sudo apt install ubuntu-drivers-common
sudo ubuntu-drivers autoinstall
sudo reboot
```
もしデスクトップ画面が表示されてしまったら、`Ctrl+Alt+(F1-F6)`を押してCUIに切り替えてログインしてください。
## Ubuntu Desktopのインストール


```
sudo apt -y install ubuntu-desktop
sudo reboot
```
以上で終了です。
[Swift][Combine]ON/OFF切り替えありのTimer の実装方法（暫定）

Swift　でON/OFF切り替えありのTimer実装に関して、既存の書き方とCombine利用時の書き方の比較。
＊本当にこれで良いのかあまり自信はありません。より良い方法ありましたらコメントいただけますと幸いです。


###非Combine

```
class ViewController: UIViewController {
    private var timer: Timer?

    func startTimer() {
        timer = Timer.scheduledTimer(
            timeInterval: 1.0,
            target: self,
            selector: #selector(self.periodicalFunction),
            userInfo: nil,
            repeats: true)
    }
    
    func stopTimer() {
        timer?.invalidate()
    }
    
    @objc func periodicalFunction() {
         print("update")
    }
}
```

###Combine

```
class ViewController: UIViewController {
    private var timerCancelable: AnyCancellable?

    func startTimer() {
        timerCancelable = Timer.publish(every: 1.0, on: .main, in: .common)
            .autoconnect()
            .sink(receiveValue: { _ in
                self.periodicalFunction()
            })
    }
    
    func stopTimer() {
        timerCancelable?.cancel()
    }
    
    func periodicalFunction() {
         print("update")
    }
}
```

Combine の場合、キャンセルのため保持するのは `AnyCancellable` クラスのようです。

参考: 
https://developer.apple.com/documentation/combine/replacing-foundation-timers-with-timer-publishers
anaconda python仮想環境を一瞬で作成するスクリプト(JupyterLabも一緒に)

# 作成理由
- windows にて anaconda + Jupyterlabの仮想環境を新規作成するのが大変
- 作成してある仮想環境を起動するのに毎回コマンドを打つのが大変
※アナコンダのインストール前提のため、こちら( https://www.javadrive.jp/python/install/index5.html )参考にインストールするとよいかと思います。

# バッチを実行するとできること
- anaconda仮想環境の作成
- jupyterlabのインストールと起動　まで行います。
※すでに同名の仮想環境が存在する場合は、
　その仮想環境のjupyterlabを起動するのですぐに作業に取り掛かれる

# コード（バッチファイル）
[createCondaEnv.bat]
※パス部分などは変更が必要です。

``` 
@echo off

set /P IN_STR="作りたい仮想環境名を入力してください。すでに存在する仮想環境名の場合jupyterlabを起動します。"

rem 適宜ユーザー名設定してください。
set USER=""

rem アナコンダを起動する(anacondaフォルダにactivate.batファイルが存在するので適宜パスを変更してください。)
call C:\Users\%USER%\anaconda3\Scripts\activate.bat

rem もしすでに同名の仮想環境が存在する場合
set FOLDER1=C:\Users\%USER%\anaconda3\envs\%IN_STR%
if exist "%FOLDER1%" (
	echo すでに同じフォルダ名が存在するのでjupyterlabを起動します。
	cd C:\Users\%USER%\anaconda3\envs\%IN_STR%
	call activate %IN_STR%
	jupyter lab
	exit
)

rem 仮想環境作成
echo Y|call conda create -n %IN_STR% python=3.7

rem 作成した仮想環境へ移動し、有効化、jupyterlabをインストール
cd C:\Users\%USER%\anaconda3\envs\%IN_STR%
call activate %IN_STR%
pip install jupyterlab
jupyter lab

pause

``` 

# 実行してみる
上記のバッチファイルを作成し実行すると
コマンドプロンプトが開くのでtestと入力し、エンターを押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703168/5de65e6f-0de4-1bd5-3beb-d0c208510027.png)
少し待つとアナコンダの仮想環境が作成され、ブラウザでJupyterLabも自動で開くはず
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703168/4e8876bb-6492-760a-3b30-3ced8aa37383.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703168/a9f99a55-696c-1479-5edb-e80523068e1c.png)

一度コマンドプロンプトを閉じ、仮想環境を停止させ、
再度バッチファイルを実行して再び「test」と入力すると
すでに仮想環境【test】が存在するのでjupyterLabが立ち上がる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703168/be9cad18-f442-2a77-43a1-68f43b73d3e2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703168/0f60f322-3eec-aa8e-a0dc-d717ec9af5fa.png)
【AndroidStudio】assetsフォルダにローカルのファイルを追加する

aseetsフォルダにファイルを追加する際、普通にドラッグ＆ドロップで追加できると思ったら、追加できなかったので少しハマってしまいました。

# 環境
- macOS10.15.7
- AndroidStudio3.6.3

# 方法1
AndroidStudio左上の「Android」を「Project」に変更し、`app/src/main`を開きます。
assetsフォルダに追加したいファイルをドラッグ＆ドロップするとダイアログが表示され、assetsフォルダにファイルを追加できます。
ただし、この方法だとファイルがassetsフォルダに移動してしまいます。

# 方法2
assetsフォルダにファイルをコピーしたい場合は、Finderで直接aseetsフォルダを開いてファイルをコピーします。

もし上記より良い方法があればコメントお願いします🙇‍♂️
SpringBoot 2.5からschema/dataの指定方法が変わった

# 概要

SpringBootのversion 2.5が最近リリースされたようです。
劇的な変化があるのかはまだわかりませんが、application.ymlの`spring.datasource.schema`や`spring.datasource.data`、`spring.datasource.initialization-mode`に該当する設定部分に警告が出ていたので、その対応（警告が出ないように対応）をしたのでメモとして残します。

# 警告の内容

以下のような警告が出ています。
内容を見ると、いずれも`*** is Deprecated`となっているので、従来の設定が非推奨となったようです。
代わりに`spring.sql.init.***`を使ってね。と丁寧に教えてくれているので、設定を変更してみます。

```
説明	リソース	パス	ロケーション	タイプ
Property 'spring.datasource.data' is Deprecated: Use 'spring.sql.init.data-locations' instead.	application-local.yml	/restcontroller-sample/src/main/resources	行 32	言語サーバー
Property 'spring.datasource.initialization-mode' is Deprecated: Use 'spring.sql.init.enabled' instead.	application-local.yml	/restcontroller-sample/src/main/resources	行 33	言語サーバー
Property 'spring.datasource.schema' is Deprecated: Use 'spring.sql.init.schema-locations' instead.	application-local.yml	/restcontroller-sample/src/main/resources	行 31	言語サーバー
```

# application.ymlの修正

以下のように修正することで、警告表示は消えました。
今まで`spring.datasource`にまとめて定義していたものを、分割するようになったんですね。

```yaml:修正前
spring:
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=1;DB_CLOSE_ON_EXIT=FALSE;MODE=DB2
    username: sa
    password: ''
    schema: classpath:develop-resources/schema.sql
    data: classpath:develop-resources/data.sql
    initialization-mode: always
```

```yaml:修正後
spring:
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=1;DB_CLOSE_ON_EXIT=FALSE;MODE=DB2
    username: sa
    password: ''
  sql:
    init:
      enabled: true
      schema-locations: classpath:develop-resources/schema.sql
      data-locations: classpath:develop-resources/data.sql
```
IAMアカウント

# IAM (Identity and Access Management)

IAMは, AWSリソースへ安全に管理するためのサービスである [1].
IAMを使うことで, 「誰がサインイン可能か」, および「アクセス権限を持つか」をユーザは管理する.
[1]https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html

# MFA (Multi-Factor Authentication)

MFAは, 他のデバイスを使用した認証のことである [2].
MFA用のデバイスには, 認証用のアプリをインストールする必要がある.
そのアプリは, 6桁のTime-based One-Time Passwordを認証コードとして生成する.
[1] https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html
npmのwebpack-devserverでhttpsを有効にする


## /webpack.config.js

```javascript
(略)
const fs = require('fs'); // 追加しておく
(略)

module.exports = {
  
  (略)

  devServer: {
    https: {
      key: fs.readFileSync('./letsencrypt/privkey.pem'),
      cert: fs.readFileSync('./letsencrypt/cert.pem'),
    },

    (他の設定を書く)

  }
```

### 補足
- letsencryptで作った証明書を設定する場合はこんな感じです。
- なんでこんなの作ったの？とかいうツッコミはなしで。

### 愚痴
- ネット検索してるといろんな設定見つかるんで苦労した

### 参考
- リファレンスが一番正解に近かったですね
  - https://webpack.js.org/configuration/dev-server/#devserverhttps
  - 英語の方が正確
[AtCoder] 競プロ典型 90問 044 - Shift and Swapping

https://atcoder.jp/contests/typical90/tasks/typical90_ar

制約がたくさんあって面倒です。
どこに時間がかかりそうか考えたところ、$T_{i} = 2$ のときの右シフトを配列で愚直にやってしまうと時間がかかってしまいそうです。
右シフトですが、配列の開始位置の添字を$-1$ずらすだけでいけることがわかります。
添字が$0$より小さくなってしまう場合が出てきてしまうので、$N$の剰余を求めて配列開始位置の添字とします。
配列の開始位置の添字を`start`とすると、`i`番目の要素にアクセスするためには、`A[(i + start - 1) % N]` で出来ます。
その計算をソースコードに落とし込んだのが以下です。
言語はC++(GCC 9.2.1)でAtCoderのコードテストで確認しています。

```c++
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int main() {
  ll N, Q;
  cin >> N >> Q;
  vector<int> A(N), T(Q), X(Q), Y(Q);
  for (int i = 0; i <N; i++) {
    cin >> A[i];
  }
  for (int i = 0; i < Q; i++) {
    cin >> T[i] >> X[i] >> Y[i];
    X[i]--;
    Y[i]--;
  }
  int start = 0;
  for (int i = 0; i < Q; i++) {
    if (T[i] == 1) {
      swap(A[(X[i] + start) % N], A[(Y[i] + start) % N]);
    } else if (T[i] == 2) {
      start = (start - 1 + N) % N;
    } else if (T[i] == 3) {
      cout << A[(X[i] + start) % N] << endl;
    }
  }
}
```