OmniAICreator/Qiita-1.07M huggingface dataset:
AI-900(Azure AI Fundamentals)概要と試験対策

# AI-900 の概要
|項目|内容|
|---|---|
|試験概要|機械学習 (ML) 、人工知能 (AI) の概念と、関連する Microsoft Azure サービスの基礎知識を問う試験です。|
|試験方法|コンピュータ上で実施するCBT（Computer Based Testing）形式。|
|受験料|12,500円（税別）|
|難易度|初級(Fundamentals)|
|試験時間|45分|
|問題数|50問前後|
|合格点|700点/1000|

・[Microsoft Virtual Training Days](https://www.microsoft.com/ja-jp/events/top/training-days)で「AIの基礎」のトレーニングを受けると、無料でAI-900認定試験を受験できるバウチャーを貰えます（2022年2月現在）。
・IT系の認定試験の中では難易度の低い試験です。標準学習時間としては20～30時間程度でしょうか。

# 試験対策
### マイクロソフト・ラーニングパス
https://docs.microsoft.com/ja-jp/learn/certifications/azure-ai-fundamentals/
試験範囲を網羅しているので、こちらのドキュメントを一通り目を通して概要をつかむのが良いと思います。ただし、機械翻訳をしているのか、頭にスッと入ってこない文面が多々あるのが難点です。
### Udemy
日本語版の模擬試験問題集が販売されています。購入者のコメントを読むと、問題の的中率は高そうですが、マイクロソフトの規約に違反している可能性もあるので避けたほうが無難でしょう。
[絶対合格！Microsoft AI-900　模擬試験問題　※日本語対応](https://www.udemy.com/course/microsoft-ai-900-l/)
### 公式ドキュメント
マイクロソフト公式ドキュメントにAI関連サービスの情報があります。こちらは、ラーニングパスで理解が不十分な箇所の補足資料として参照すると良いでしょう。
[Azure Cognitive Services のドキュメント](https://docs.microsoft.com/ja-jp/azure/cognitive-services/)
### 個人のWebサイト
参考になったサイトを紹介します。
[・アラフォー2児の母がMicrosoft Azure AI Fundamentals(AI-900)をサクッと取得](https://qiita.com/mofu_mother/items/a90dd793b7ba7bb6d02e)
　「マイクロソフトのAI基本原則」がよく整理されています。
[・[覚書・カンペ]AI-900合格に必要な知識まとめ](https://pickerlab.net/2021/06/12/test-preparation-for-ai-900/)
　模擬試験があり有益なサイトです。

# 試験前の覚書メモ
試験前に私が整理した情報です。

### 回帰・分類・クラスタリング
回帰：株価の予測など、「数値」を予測するときに用いる。教師あり学習。
分類：晴れ、曇り、雨など、カテゴリーを予測するときに用いる。教師あり学習。
クラスタリング：似たものをグルーピングする。教師なし学習。

### コンピュータービジョン
・Form Recognizer
領収書などのドキュメントから、取引時間や合計金額などの重要な情報を抽出します。
・光学式文字認識(OCR)
画像から、「文字や数字」を認識することが出来ます。
・カスタムビジョン
ユーザーが学習用の画像データを用意します。

# 受験前の注意点
・本試験を受験される方は、必ず最新のマイクロソフト公式ドキュメントを参照ください。
　[試験 AI-900: Microsoft Azure AI Fundamentals](https://docs.microsoft.com/ja-jp/learn/certifications/exams/ai-900)
【JavaScript】reduce()で配列から指定した値の近似値を取得する

海外のブログで、配列から指定した値の近似値を取得する方法が紹介されていたのでメモ。いったん配列をソートしてから近似値を求めるより、reduce() を使った方が早いらしい。

参考: [JFind the closest number in an array JavaScript](https://www.gavsblog.com/blog/find-closest-number-in-array-javascript)


#配列内で "8" に一番近い値を取得する

```javascript:
const needle = 8;

const closest = [1, 10, 7, 2, 4, 9].reduce((a, b) => {
    return Math.abs(b - needle) < Math.abs(a - needle) ? b : a;
});

console.log(closest); // 出力値: 7
```

この方法だと結果は "7" になる。配列に "9" があったとしても、先に比較された "7" が最近似値となる。

これだと問題となるケースがあるため、「大きい方 vs 小さいほう (> vs <)」を指定して、どちらを近似値とするかを決められるようにする。

```javascript:
const needle = 8;

const closest = [1, 10, 7, 2, 4, 9].reduce((a, b) => {
    let aDiff = Math.abs(a - needle);
    let bDiff = Math.abs(b - needle);

    if (aDiff == bDiff) {
        // 大きい方 vs 小さいほう (> vs <) を指定する
        return a > b ? a : b;
    } else {
        return bDiff < aDiff ? b : a;
    }
});

console.log(closest); // 出力値: 9
```

# 使い回しができるよう関数化する

```javascript:
function getClosestNum(needle, haystack) {
    return haystack.reduce((a, b) => {
        let aDiff = Math.abs(a - needle);
        let bDiff = Math.abs(b - needle);

        if (aDiff == bDiff) {
            // 大きい方 vs 小さいほう (> vs <) を指定する
            return a > b ? a : b;
        } else {
            return bDiff < aDiff ? b : a;
        }
    });
}
```

ざっと動作確認してみる。

```javascript:
// 数値のみの配列
const needle = 8;
const numbers = [1, 52, 0, -25, 10, 7, 2, -128, 4, 9, 99, 256];

let closetnum = getClosestNum(needle, numbers);
console.log(closetnum);  // 出力値: 9
```

```javascript:
// いろいろごちゃまぜの配列
const needle = 0.5940;
const numbers = [1, 10, NaN, 7, -5, null, "テスト", 2, 4, 9, "Test", 0.5267, 0.5877, NaN, 0.6534, NaN];
let closetnum = getClosestNum(needle, numbers);
console.log(closetnum);// 出力値: 0.5877
```

いろいろごちゃまぜの配列にしても、近似値を取得できているが、あまり無茶をするとバグりそう（汗

#参考：
[JFind the closest number in an array JavaScript](https://www.gavsblog.com/blog/find-closest-number-in-array-javascript)
[JavaScript　配列から指定した値の近似値を取得](https://qiita.com/PianoScoreJP/items/755e7d638e4381b5de24)
[【javascript】reduce](https://qiita.com/chihiro/items/1047e40514a778c08baa)
geopandasとpandasのデータフレームを結合してシェープファイルにする


# モジュールimport
```
import geopandas as gpd
import pandas as pd
from os import path
import os
```

# 適当に用意した四次メッシュshapeファイル読み込み
```
path_shp = "../MESH4.shp"
gdf = gpd.read_file(path_shp)
print(gdf.head())
```

# 結合対象のデータ読み込み
```
path_m = "../cleansed.csv"
df = pd.read_csv(path_m, index_col=0)
print(df.head())
df["mesh4code"] = df["mesh4code"].astype(str)
```

# 出発地のメッシュコードをキーにinner join
```
merged_data = pd.merge(df, gdf, left_on='mesh4code', right_on='MESH4_ID')

gdf_out = gpd.GeoDataFrame(merged_data)
print(gdf_out.head())
```
print reverse<>;

引数に指定したファイルの内容をすべて表示するperlスクリプトを書け、と言われたら、私なら以下のように書く。

```perl
open IN,"<".$ARGV[0];
while(){
    print;
}
```

そしてperlって簡単だなァ・・・とニタニタする。しかし、実は以下のように書けばいいのである。

```perl
while(<>){
    print;
}
```

そしてもっと恐ろしいことには、

```perl
print <>;
```

でよい。そして、このときの引数は複数あってもよい。指定されただけのファイルについて、内容を表示する。そして、以下のようにすると、ファイル内容を逆順に、つまり最後の行から順に先頭の行まで表示する・・・

```perl
print reverse<>;
```

・・・・・。これは、実は一番最後のスクリプトを見たのである。そして、これでこうならもしかして、と、今書いたのと逆にさかのぼっていったのである。

これは、「初めてのPerl」からのネタです。「初P」では「ダイヤモンド演算子」ということでその使い方が説明してあるのでそれを読んでいればわかることですが、私はここを飛ばしていたのです。そして5章のハッシュのところを読み、最後の問題の答えを見ていたら、6章の答えである

```perl
print reverse<>;
```

が目に入ったわけです。今日は仕事がちょっとヒマだったので「初P」を読んでいたのですが、何度か吹き出しました。こういう冗談って、なかなか書けないですよね。絵文字も、（笑）ともかかずに、マジメな顔してあきらかに冗談であることがわかる文章を書くのって、難しいものです。
公開鍵暗号方式における暗号化とデジタル署名の双方向性に関する考察


公開鍵暗号方式において、暗号化は公開鍵を用いて行われ、受信者は秘密鍵を用いて暗号化されたデータを復号する。

このとき公開鍵と秘密鍵はペアであり、データを暗号化して送信する者をA、データを受信して復号する者をBとすると、公開鍵はBが作成して公開した鍵であり、秘密鍵はBが作成して自分で保持している鍵である。

公開鍵を公開しないと暗号化することができないし、
秘密鍵を公開してしまうと誰でも復号化できてしまう。

公開鍵暗号方式では署名と検証ということも行われる。

署名と検証においては送信者が秘密鍵を用いて署名し、
受信者が公開鍵を用いて検証する。

この話を聞くと、
『要するに暗号化は公開鍵で暗号化して、署名は秘密鍵で暗号化するってことだね？』
と言いたくなってしまうのだが、そうではない。

とりあえず、「署名は秘密鍵で暗号化するということではない」と覚えておけば、
会話して笑われたり怒られたりすることはない。

が、そこで『じゃあいったい署名ってどんな処理なの？そしてそれを検証するってどういう処理なの？』
と考えてほしい。

というか、私はそれを考えて軽く調べてみたのだがよくわからないのである。

公開鍵暗号方式は、ある程度大きな数の素因数分解が困難であることを利用している。
ある程度大きな桁数の素数を掛けることは容易であるが、
結果からもとの二つの素数を求めることはコンピュータを使っても事実上不可能である。

d1をもとのデータ、d2を暗号化したデータ、k1を公開鍵、Eを暗号化する演算とすると、

```
d1 E k1 = d2
```

k2を秘密鍵、Dを復号する演算とすると

```
d2 D k2 = d1
```

となればよい。

このとき、Eが単なる掛け算であったら、k1は公開されているので、
d1を求めるにはd2を k1で割ればよいことになってしまう。 

だから、Eはk2を使わないと復号できないような演算でなければならない。

それはどういう方法だろうか？
 
RSA暗号のwikipediaを見る

>鍵のペア（公開鍵と秘密鍵）を作成して公開鍵を公開する。
>まず、適当な正整数 e を選択する。
>また、大きな2つの素数の組み{p,q}を生成し、
>それらの積 n=pq を求めて、
>組み{e,n}を平文の暗号化に使用する鍵（公開鍵）とする。
>2つの素数{p,q} は秘密に保管し、
>暗号文の復号に使用する鍵（秘密鍵）d の生成にも使用する
>d=e^-1 mod Φ
>ここで
>Φ=lcm(p-1,q-1)
>※lcmは最小公倍数
>暗号化（平文 m から暗号文 c を作成する）：
>c=m^e mod n
>復号（暗号文 c から元の平文 m を得る）：
>m=c^d mod n
>暗号化（e 乗）は公開鍵 {e,n} があれば容易に計算でき、
>復号（d 乗）も容易に計算できる。
>しかし、秘密鍵 d を知らずに解読（法 n の下で e 乗根を計算）するのは、
>「n の素因数を知らないと難しい（大きい合成数の素因数分解も難しい）」
>と考えられている。
>つまり、「秘密鍵を用いずに暗号文から平文を得ることは難しい」と信じられている。
>これがRSA暗号の安全性の根拠である。
>
>鍵生成
>
>k をセキュリティパラメータとする。
>p,q（ただしp≠q）をk/2ビットの素数とし、
>n=pqとする。
>eをΦ(n)未満の正の整数で、
>Φ(n)と互いに素な数とし、
>dを、Φ(n)を法としたeの逆数 ( deΞ1 (mod Φ(n)) )とする。
>ただしここでΦはオイラーのφ関数で、
>この場合は
>Φ(n)=(p-1)(q-1)
>である。
>dは、e,Φ(n)が既知の時には拡張されたユークリッドの互除法を使えば容易に求まる。
>deをΦ(n)で割った整数商をxとした場合、
>de+(-x)Φ(n)=1
>が成り立ち、
>かつ
>eの取り方から
>gcd(e,Φ(n)) = 1
>であるのでこれを解けばよい、
>dを秘密鍵とし
>n, eを公開鍵とする
>pとqが漏れるとdが計算で求まるため、pとqは安全に破棄すること
>
>暗号化
>
>aを平文空間Znの元とする。
>b=a^e mod n を計算し、bを出力する。
>
>
>復号化
>
>bを暗号文とする。
>a' = b^d mod n を計算し、a'を出力する。
>ここでa'=aとなり、復号できる。


ちなみに公開鍵暗号方式は最初RSA暗号方式なしに考案されて、
それを実現するためにRSA暗号方式が考えられたらしい。

さて。

では署名と検証である。

だいたい、以下のように説明されている。

 
>送信者がデータのハッシュ値を計算して秘密鍵で暗号化し添付（これが署名）
>受信者が暗号化されたハッシュ値を公開鍵で復号
>受信者が自分でデータのハッシュ値を計算して、復号したハッシュ値と等しいかどうかを確認

wikipediaに書いてある通り、暗号化も復号化もおこなっている演算はある数について
ある数の累乗を求めそれをある数で割った余りを計算している。

同じ計算を違うパラメータでおこなうことによって暗号化になり復号化になるのである。

デジタル署名においては先に秘密鍵による演算がなされてその結果に対して公開鍵による演算がなされる。

これを、『秘密鍵により暗号化し公開鍵により復号化する』と言ってはいけないのだ。

そう言うと怒る人がいる。

怒る理由は、私が調べて理解したところでは以下の2点である。

1. それはRSA暗号方式にしかあてはまらない
2. 署名で「暗号化」するのはデータではなくデータのハッシュである

以下はRSA暗号方式を使うこと前提にした話である。

私が調べて理解した知識によれば、「秘密鍵でも暗号化できる」。
ただし、デジタル署名で暗号化するのはデータそのものではなくデータのハッシュである。
秘密鍵で暗号化されたデータのハッシュを公開鍵で復号化し、
自分でデータのハッシュを計算してその結果を復号化したハッシュと比較する、
これが「署名の検証」である。

では、データのハッシュを公開鍵で暗号化して秘密鍵の保持者に送信したら「署名」になるか？

ならない。

なぜなら公開鍵は公開されているので誰でもそれを使ってハッシュを暗号化することはできるからだ。


では、ハッシュではなくデータそのものを秘密鍵で暗号化して公開鍵で復号化させたらどうか？
暗号化というのは、「鍵を生成した人」ではなく、「鍵を生成した人に暗号化したデータを送信する人」が行う。
では、逆の場合は？「鍵を生成した人」が、誰かに暗号化したデータを送りたいときにはどうすればいいのか？

その場合は、データを送りたい相手に鍵ペアを生成してもらうのか。

秘密鍵でハッシュを暗号化し復号できるなら、秘密鍵でデータそのものも暗号化できるはずだが、
そういう話は聞かない。

それをしないひとつの理由として、秘密鍵は公開鍵より鍵長が長くて演算に時間がかかる、ということが説明されていたが、

時間がかかるからやらない、ということなら不可能ではないということだ。
（未完）
40 代おっさん GASのプロジェクトとスクリプトを学んでみた！！

## 本記事ついて

本記事は プログラミング初学者の私が学習していく中でわからない単語や概要をなるべくわかりやすい様にまとめたものです。
もし誤りなどありましたらコメントにてお知らせいただけるとありがたいです。

## プロジェクトとファイル

スクリプトはプロジェクトと言う単位で作成
プロジェクト内にHTMLファイルを作成することも可能

## スタンドアロンスクリプトとコンテナバインドスクリプト

GASのスクリプトには2種類ある
作成方法、保存法補が異なる

### スタンドアロンスクリプト

Googleドライブにプロジェクトファイル自体に保存
プロジェクトファイル1つに対して、１つのプロジェクトしか持つことできない

Apps Scriptダッシュボードの新しいプロジェクトをクリックすると便利
作成されたプロジェクトはApps Scriptダッシュボードの一覧に追加される。
Googleドライブ上のマイドライブに作成されている。

### コンテナバインドスクリプト

スプレッドシート、ドキュメント、フォーム、スライドと言った、親ファイルに紐づく形で保存できる。
カスタム関数の作成ができる。
紐づいたファイルを参照するgetActiveSpreadsheet,getActiveDocument,getUiなどのいくつかのメソッドが使用できる。

### Apps Script

Apps Scriptダッシュボードは、GASのプロジェクトを管理およびモニタリングするためのツール

プロジェクトの閲覧および検索、操作
スタンドアロンスクリプトの作成
スクリプトの使用状況のモニタリング
ログの表示と保管
インストーラブルトリガーの作成、管理
ができる

Apps Scriptダッシュボードはスクリプトエディタの左上のアイコン
<font color="Red">Apps Script</font>からアクセスできる。
またURL
<https://script.google.com/>
開くこともできる。

## 参考資料

<https://www.amazon.co.jp/s?k=google+apps+script+%E5%AE%8C%E5%85%A8%E5%85%A5%E9%96%80&adgrpid=110264232688&gclid=CjwKCAiA9aKQBhBREiwAyGP5lSl7AJJLCvOEHb4wQgMlyqW1fll5X8GDTT_Rkd1_soUAyIPMXQr26hoClHEQAvD_BwE&hvadid=553833563682&hvdev=c&hvlocphy=1009076&hvnetw=g&hvqmt=b&hvrand=4378489642044417389&hvtargid=kwd-594191211348&hydadcr=4106_13159878&jp-ad-ap=0&tag=googhydr-22&ref=pd_sl_2x1owglv0s_b_p52>
create-react-app できない！

# 事象

create-react-app しようとしたところ以下のように表示されます。
一見エラーっぽくないですがReactアプリは作られません。

```sh
$ npx create-react-app appsample_YYYYMMDD --template typescript
Need to install the following packages:
  create-react-app
Ok to proceed? (y) y

You are running `create-react-app` 4.0.3, which is behind the latest release (5.0.0).

We no longer support global installation of Create React App.

Please remove any global installs with one of the following commands:
- npm uninstall -g create-react-app
- yarn global remove create-react-app

The latest instructions for creating a new app can be found here:
https://create-react-app.dev/docs/getting-started/
```

以下のコマンドを実行するように書いてありますが、これらを実行してもうまくいきません。


```sh
- npm uninstall -g create-react-app
- yarn global remove create-react-app
```

# 解決策

この方の記事が非常に参考になりました。

https://qiita.com/kurab/items/6c6056d06d053631b596

キャッシュが悪さをしているようです。

```sh
$ npx clear-npx-cache
```
ショートカットキーを使おう！


---
 
この記事は[リンク情報システム](https://www.lis.co.jp/)の「TechConnect！2022年2月」のリレー記事です。
engineer.hanzomon のグループメンバによってリレーされます。
（リンク情報システムのFacebookは[こちら](https://ja-jp.facebook.com/lis.co.jp/)から）

 

TechConnect！2022年2月のインデックスは[こちら](https://qiita.com/hs-lis/items/69eee14fd7bec92a854f)
 


---


#はじめに
こんにちは、吉田です。
今回は、エクスプローラと仮想デスクトップで使えるショートカットキーについてのお話です。
入社1~2年目などでPC操作にまだ慣れていないよといった方に向けて、少し便利なショートカットキーをご紹介します。

コピペなどの基本的なショートカットキーについては、<a href=https://qiita.com/13-nonono/items/1ee1442789b0e90128b3>私の同期が執筆した去年のアドベントカレンダーの記事</a>をご参照ください。
また、「こんな便利なショートカットもあるぞ！」などありましたら、コメントでご教示いただけますと幸いです。

#目次
[はじめに](#はじめに)
[1.エクスプローラ編](#エクスプローラ編)
[2.仮想デスクトップ編](#仮想デスクトップ編)
[3.その他](#その他)
[おわりに](#おわりに)

#1.エクスプローラ編
仕事で必要な資料を探したり、作成した文書を共有したりなど、エクスプローラを使う機会は多いと思います。
そんなエクスプローラの操作をキーボードだけできたら、とても楽ちんですよね。
これだけ覚えていれば、エクスプローラをキーボードだけで操作できるかも！？

|No.|できること|キー|
|---|---|---|
|1|エクスプローラを起動する|Win + E|
|2|前のフォルダに戻る|Alt + ←|
|3|戻る前のフォルダに進む|Alt + →|
|4|親フォルダに移動する|Alt + ↑|
|5|アドレスバーを選択する|Alt + D|
|6|選択中のフォルダ/ファイルのプロパティを表示する|Alt + Enter|
|7|フォルダ/ファイルを検索する|Ctrl + F|
|8|現在のアドレスで新しいウィンドウを開く|Ctrl + N|
|9|選択中のフォルダ/ファイルを削除する|Ctrl + D|
|10|新しいフォルダを作成する|Shift + Ctrl + N|
|11|選択中のフォルダ/ファイルの名前を変更する|F2|

#2.仮想デスクトップ編
仕事中、作業を同時並行して行わなければいけないことってありますよね。
1つの画面で2つの作業をしようとすると、開いているウィンドウが多くなって訳がわからなくなりがちです。
そんな時に仮想デスクトップを利用すれば、1つの作業ごとに1つの画面を使うことができます。
これを覚えていれば、2つの作業がごちゃ混ぜにならずに、快適になるかも！？

|No.|できること|キー|
|---|---|---|
|1|新しい仮想デスクトップを起動する|Win + Ctrl + D|
|2|左隣の仮想デスクトップに移動する|Win + Ctrl + ←|
|3|右隣の仮想デスクトップに移動する|Win + Ctrl + →|
|4|仮想デスクトップを閉じる|Win + Ctrl + F4|

#3.その他
ここでは、先輩方に教えてもらったとても便利なショートカットキーを紹介します。
このあたりを覚えるとマウスを握る時間がグッと減り、効率よく作業を進めることができるかも！？

|No.|できること|キー|
|---|---|---|
|1|「ファイル名を指定して実行」を起動する|Win + R|
|2|起動中のウィンドウを切り替える|Alt + Tab|
|3|起動中のウィンドウを切り替える（2と逆回り）|Shift + Alt + Tab|
|4|選択中のウィンドウを閉じる|Alt + F4|
|5|タスクマネージャを起動する|Shift + Ctrl + Esc|


>No.1について補足
Win + Rを押すと添付画像のようなウィンドウが開きます。
ここでは、コマンドを入力することで、アプリケーションを起動できます。
![ファイル名を指定して実行.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/751559/ced681ed-be36-0eb4-a133-7fe71e23fa8c.jpeg)
私は以下の表の内容をよく利用しています。

>|No.|起動するアプリ|コマンド|
|---|---|---|
|1|ペイント|mspaint|
|2|計算機|calc|
|3|メモ帳|notepad|
|4|コマンドプロンプト|cmd|
|5|コントロールパネル|control|
|6|Excel|excel|

#おわりに
今回は、ショートカットキーの紹介をさせていただきました。
この記事で、みなさんのパソコン作業が少しでも捗れば幸いです。
拙い箇所も多々あったとは思いますが、最後まで読んでいただきありがとうございました。
BGPのベストパス選択の実際

![bgp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379353/75d69dd7-b25d-13ef-10e9-6a6c1f9dd0e1.png)

R1はR2, R3, R5とneighborになっている。
R1でshow ip bgpを実行すると

```
R1#sho ip bgp
     Network          Next Hop            Metric LocPrf Weight Path
 *>  192.168.102.0    192.168.101.2            0         32768 64513 i　※1
 *                    192.168.101.18          80             0 64517 i　※2
 * i                  192.168.101.14          80     80      0 64516 i　※3
```

192.168.102.0/24 のprefixはBGPテーブルに３つあるが、
ベストパスは※１である。

この時、192.168.101.2のルータ（図でいうRT5）がダウンしたら、 ベストパスはどれになるか？

現在のベストパスはweightが設定されている。
weightはciscoルータがBGPのベストパスを選択するときに比較する最初の条件である。

この経路以外はWeightは設定されていない。

Weightの次に比較するのはlocal preference である。

残りの2経路のLocPrfを見ると、一つは空欄、もう一つは80である。

この時、どちらの経路が採用されるか？

そもそも、※２のlocPrfはなぜ空欄なのか？
それは、※２の経路はeBGPのネイバーから受信したprefixだからである。
逆に言うと、BGPテーブルを表示したときにLocPrfが空欄のprefixは、
eBGPから受信したものだとわかる。

eBGPから受信した経路にはlocPrfは「ない」のである。

では、ベストパスの2番目の比較が行われるときに、※２と※３の比較はどうなるのか？
locPrfがない経路より、80が設定されている※３の方が強いのか？

これは考えてもわからない。

こういう場合、LocPrfがないeBGPネイバーから受信したprefixはLocPrfがデフォルト値の100であるとして比較をおこなうことになっている。

https://www.cisco.com/c/en/us/support/docs/ip/border-gateway-protocol-bgp/13753-25.html


だから、RT5がダウンしたらベストパスは ※２になる。



実際にやってみた。

```
R1#sho ip bgp

     Network          Next Hop            Metric LocPrf Weight Path
 *>  192.168.102.0    192.168.101.2            0         32768 64513 i
 *                    192.168.101.18          80             0 64517 i
 * i                  192.168.101.14          80     80      0 64516 i
```

※RT5を落とす

```
*Mar 29 04:29:31.095: %BGP-3-NOTIFICATION: sent to neighbor 192.168.101.2 4/0 (hold time expired) 0 bytes
*Mar 29 04:29:31.095: %BGP-5-NBR_RESET: Neighbor 192.168.101.2 reset (BGP Notification sent)
*Mar 29 04:29:31.095: %BGP-5-ADJCHANGE: neighbor 192.168.101.2 Down BGP Notification sent
*Mar 29 04:29:31.095: %BGP_SESSION-5-ADJCHANGE: neighbor 192.168.101.2 IPv4 Unicast topology base removed from session  BGP Notification sent

R1#sh ip bgp summary

Neighbor        V           AS MsgRcvd MsgSent   TblVer  InQ OutQ Up/Down  State/PfxRcd
192.168.101.2   4        64513       0       0        1    0    0 00:00:07 Idle
192.168.101.14  4        64512      10      11        3    0    0 00:05:09        1
192.168.101.18  4        64517      10      11        3    0    0 00:05:09        1
```


※新しいベストパスが選択される

```
R1#sh ip bgp
     Network          Next Hop            Metric LocPrf Weight Path
 *>  192.168.102.0    192.168.101.18          80             0 64517 i
 * i                  192.168.101.14          80     80      0 64516 i
 ```
古いASAにASDMでアクセスできないのはTLSバージョンのせい

私はCisco ASA5505を持っている。
ヤフオクで入手した中古品だ。

ASAはASDMというJavaで動く管理用のGUIツールを使って設定する。
CLIでも設定できるが見やすかったり設定しやすかったりするのでだいたいASDMを使う。

久しぶりに引っ張り出してASDMでアクセスしたら、こんなエラーになった。

![asdm error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379353/3006391b-e05d-5c70-e5d7-8eb41e4f1b72.png)


ログインダイアログ右下にあるJavaコンソール（コーヒーカップのアイコン）を開いてアクセスすると、以下のようなエラーが記録されている。

```java
javax.net.ssl.SSLHandshakeException: The server selected protocol version TLS10 is not accepted by client preferences [TLS12]
```

Javaのバージョンは 1.8.0_301-b09
ASAは9.2(4)33

コントロールパネルの「プログラム」にあるJavaコントロールパネルを起動し、
詳細タブを見ると、「高度なセキュリティ設定」のところの「TLS1.0を使用する」のチェックがはずれている。


ASAにconsoleかsshでログインしてみると

```
# show ssl
Accept connections using SSLv2, SSLv3 or TLSv1 and negotiate to SSLv3 or TLSv1
Start connections using TLSv1 and negotiate to TLSv1
Enabled cipher order: dhe-aes256-sha1 dhe-aes128-sha1 aes256-sha1 aes128-sha1
Disabled ciphers: 3des-sha1 des-sha1 rc4-md5 rc4-sha1 null-sha1
SSL trust-points:
  outside VPNLB interface: ASDM_Launcher_Access_TrustPoint_0
  outside interface: ASDM_Launcher_Access_TrustPoint_0
Certificate authentication is not enabled
```

TLS1しかサポートしていない。
ASAはTLS1、JavaはTLS1.1以上だったため、接続できないのだ。

接続できるようにするには、ASAがTLS1.1以上を使うか、JavaがTLS1.0を使うようにすればよい。

が、結論から言うとどっちもできなかった。
ASAには ssl server-versionというコマンドがあるのだがtlsv1より上を設定できない。

そしてJavaコンソールでTLS1.0をチェックしても、上記のエラーは変わらない。
ここの設定を変えてもTLS1.2で接続しようとするようなのだ。

家にJavaがインストールされていない古いパソコンがあったので、
そこに 1.7.0_80-b15 を入れてみた。

Javaコンソールを開くと「TLS1.0を使用する」がチェックされており、1.1と1.2はチェックされていない。
この状態だとASDMで接続できた。

OSをあげれば、と思ったが、
5505は販売終了製品で、9.2(4)33が2018年にリリースされた後新しいバージョンはリリースされていない。

JavaコンソールでTLS1.0をチェックしてもダメな理由がわからず、
どこか別の設定を変えればいけるのかもしれないが使用が推奨されない古いプロトコルを使うことをあまり深追いするのもアレなので。
予定表が縦になってしまった場合の解決方法

[Outlookで予定表を上下に並べて表示する方法 | できるネット](https://dekiru.net/article/20860/)

記載のように
表示＞グループスケジュール
で行けるっぽいです……

なんか困っていたのでメモっていたので表記失礼します。
hashの値の降順でソート

「数えてハッシュに登録し件数が多い順に表示」というのを最近おぼえてよく使うようになったのだが、

ハッシュの値でのソート方法をいつも検索して某所からコピーしていたのだが
メンドクサイのでここに書いておく。

```perl
foreach my $name (sort { $hash{$b} <=> $hash{$a} } keys %hash) {
    print "$name,$hash{$name}\n";
}
```
LaTeXで空白ページを作るときに全角スペースを入れるのはよせ

LaTeX で空白ページを作るときに

```
\documentclass[uplatex,a4paper]{jsarticle}
\begin{document}
\section{何某}
なんたらかんたら
\newpage
　%←ここに全角スペースが入っている
\newpage
\section{何某}
どうたらこうたら
\end{document}
```

でおｋ、みたいな話がちょいちょい検索で引っかかるんですけど、この考え方を使うと、例えばこんな虚無なpdfを作ろうとしちゃうわけじゃないですか。

```
\documentclass[uplatex,a4paper]{jsarticle}
\begin{document}
\thispagestyle{empty}
　%←ここに全角スペースが入っている
\end{document}
```

実際虚無ってほどでもなくて、複数のpdfファイルを結合するときに稀に使うんですよね、空白pdfページ。

でもこれあんまり嬉しくないんですよ。何故ならこんな悲しいことになるから。

```
$ pdffonts blankzw.pdf
name                                 type              encoding         emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
VNMPFH+HaranoAjiMincho-Regular-Identity-H CID Type 0C       Identity-H       yes yes no       4  0
```

わざわざフォント埋め込むんです。全角スペースのために。マジか。あとエディタによっては何が入っているのかだいぶ分かりにくい。空行なのかなんなのか。

そこでまあ、LaTeXの空白制御にはいくつか種類がありますので、ここではレポートなどでverbatim使わずにPC-UNIXの実行結果とか貼って酷い目に遭うことでおなじみ ```~``` に御登場いただきましょう。

```
\documentclass[uplatex,a4paper]{jsarticle}
\begin{document}
\thispagestyle{empty} ~
\end{document}
```

改行禁止も`\end{document}`には勝てぬよ。そりゃそうだ。
するとどうでしょう、フォントなんてないわけですよ。

```
$ pdffonts blankpage.pdf
name                                 type              encoding         emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------

```

ファイルサイズもすっきり。

```
$ ls -l blankzw.pdf blankpage.pdf
-rw-r--r-- 1 tarai 197121 2350  2月 14 08:49 blankzw.pdf
-rw-r--r-- 1 tarai 197121  712  2月 14 08:55 blankpage.pdf
```


そもそもの「空白ページを文書中に作る」のだって、

```
\documentclass[uplatex,a4paper]{jsarticle}
\begin{document}
\section{何某}
なんたらかんたら
\newpage
~
\newpage
\section{何某}
どうたらこうたら
\end{document}
```

これでいいわけですよ。改行禁止も`\newpage`には勝てぬよ。そりゃそうだ。
まあ本来は「既になんらかの文書を書いていてたまたま空ページがほしかった」ってところから来ている発想だと思うので、フォントの埋め込みがーとか言うのはお門違いなのだろうと思いますけど、全角スペースが単独で混ざり込むの、つらくないですか？　やめませんか？　という話でした。
pythonでexcelファイルの正規表現置換をする


excelの内容を正規表現で置換したかった。
ある列に、数字をカンマで区切った内容を入れてあるのだが、
最後がカンマで終わっている場合、カンマを取りたい。

たとえば、

```
123, 124, 222, 234
333, 444, 555, 666,
111, 222, 333
```
みたいな場合、2行目の666, のカンマをとって

```
333, 444, 555, 666
```
としたい。

pythonの正規表現は使ったことがあり、
最初は

```python
resut = pattern.match(",$",s1)
```

という風にしたのだが、なぜかマッチしない。
findallを使ったらマッチした。

置換はもっとスマートな方法があるかもしれないが、
最後の一文字を落とす、という風にした。

```python:rep.py
import glob
import os
import openpyxl
import re
import sys

pattern = re.compile('.*,')
bookname = sys.argv[1]
newbook = sys.argv[2]
wb = openpyxl.load_workbook(bookname,data_only=True)
ws = wb[u"Sheet1"]

for row in range(1000):
	c1 = ws.cell(row=row+1, column=9)
	if c1.value is None:
		pass
	else:
		s1 = str(c1.value)
		result = re.findall(r",$",s1)
		if result:
			print(str(s1[:len(s1)-1]))
			s2 = str(s1[:len(s1)-1])
			c1.value = s2

wb.save(newbook)
wb.close
```

列は9列目（「I列」）を固定で指定。
ファイル名と保存ファイル名は引数で指定

```
python rep.py filename1 filename2
```
Renovateでライブラリの更新を自動化する

![whitesource_renovate_660_220.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335670/97dd2df5-5a58-fbdf-df38-630fd4b8243f.jpeg)

## Renovateとは

時間の経過とともに古くなっていくライブラリの更新を自動化してくれるツール

具体的には以下のようなことをしてくれます。

- リポジトリをスキャンして依存関係を検出する
- 依存関係の更新があるかどうかを確認する
- 依存関係を更新するためのコミットとマージ/プルリクエストの作成

様々なプラットフォーム、マネージャーに対応しています。

## Renovate良いポイント

- renovateを適用したいリポジトリを選択できる
- プルリクを受けるスケジュールを作成できる
- issueに可視化できるダッシュボードが追加される
- リリースノートを表示してくれるので変更点が一目でわかる
- 似たようなパッケージをグループ化してプルリクしてくれる
    - babel関連のパッケージなどはデフォルトでまとめてくれる
    - まとめたいパッケージは自分でも指定できる
- Node.jsのバージョンにも対応
    - volta（package.jsonのvoltaフィールドに対応）
    - LTSのリリースのアップグレードを提供してくれる

## インストール

公式を参照しながらやればすぐ終わる

https://docs.renovatebot.com/getting-started/installing-onboarding/

## 共有プリセットを作る

全てのリポジトリで同じ設定が重複しないように共有プリセットを作ることができます。

renovateの設定を変更したいときに、個々のリポジトリにある`renovate.json`を変更することなく、一つのファイルで設定を管理することができます。

### GitHubで共有プリセットを作成する

1. 新しいリポジトリを作成する（例: `renovate-config`）
    1. リポジトリ名はなんでもOK。公式を参考に`renovate-config` を作成する
2. `renovate-config`リポジトリに`default.json`を作成する
    1. デフォルトでは`default.json`を確認します。名前付きプリセットを使用することもできますが、今回は割愛します
    2. 共有可能なプリセットはJSON形式のみ使用可能です
3. `default.json`にrenovateの設定を書いてデフォルトブランチ（例: main）に適用する
    1. renovateはデフォルトブランチにある`default.json`ファイルを探します

これで共有プリセットの完成です（簡単！）

### 共有プリセットを使用する

renovateを適用したリポジトリにある`renovate.json`を以下に書き換えます。

「github>ユーザー名/リポジトリ名」のようにextends配列で参照するだけ。

```json
{
  "extends": ["github>yukiji/renovate-config"]
}
```

今後renovateの設定を変更したいときは`renovate-config/default.json`を変更するだけなので管理が楽になります。

## 色々設定してこうなった

一旦個人開発はこちらで運用してみようと思います。

下記の参考資料にある各記事も参考にしてみました。

renovateはデフォルトの`config:base`に既に色々と設定されています。

基本的に`config:base`をオーバーライドしていく形で設定していきます。

```json
{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json", //設定項目の補完
  "extends": [
    "config:base"
  ],
  "timezone": "Asia/Tokyo", // タイムゾーンを日本仕様に
  "schedule": [
    "every weekend" // プルリクは週末（土日）だけ
  ], 
  "prConcurrentLimit": 10, // プルリクの上限は10まで
  "packageRules": [
    {
      "groupName": "webpack family", // webpack関連はまとめて1つのプルリクにする
      "matchPackagePatterns": [
        "webpack",
        "-loader$"
      ]
    }
  ]
}
```

renovateは設定項目数がめっちゃあります。（一応全部見ました）

実際に運用してみて課題点などがあればその都度、公式ドキュメントを参考にしながら改善を加えていけばいいかなぁと個人的には思います。

## まとめ

まだ運用して間もないですが、週末にプルリクが作成され、平日にリリースノートを見ながら適用していくスタイルが個人的にはフィットしてます。

ライブラリに対しての情報感度が高くなるものいいですね。

テストを書いて自動マージなんかも今後はやっていきたい〜。

## Tips

### renovate configをチェックする

renovateのconfigが正しいかチェックするツールがあります。

renovateパッケージに含まれる`renovate-config-validator`を設定ファイルがある場所で実行します。タイポしているとエラーで怒ってくれます。

ファイル名が`default.json`だと反応してくれないところが気になる。

```
$ npm i -g renovate
$ renovate-config-validator
INFO: Validating renovate.json
INFO: Config validated successfully　
```

### 後から適用したいリポジトリを選択する

- GitHubの`Settings` -> `Applications` -> `Renovate`の`Configure`を選択
- 初回インストールの手順と同じで、Renovateを適用したいリポジトリを全て選択するか個別に選択する

## 気になるconfigメモ

- enabledManagers
- prCreation
- Monorepo Presets

## 公式ドキュメント

https://docs.renovatebot.com/

## 参考資料

https://zenn.dev/kyoncy/articles/27dce2a0174347

https://tech.recruit-mp.co.jp/front-end/post-21350/

https://developer.hatenastaff.com/entry/2020/06/19/113030
ラズベリーパイでwindowsの共有ドライブをマウントする

ラズベリーパイで、windowsのドライブをマウントする。

```
sudo mkdir /mnt/DATA
sudo mount -t cifs //172.16.x.x/DATA/subdir /mnt/DATA -o user=fugafuga,password=hogehoge,iocharset=utf8
```

つねにマウントするには /etc/fstabに追記

```
//172.16.x.x/DATA/subdir /mnt/DATA cifs username=fugafuga,password=hogehoge,iocharset=utf8,rw,uid=1000,gid=1000,defaults 0 0
```

uidおよびgidは id コマンドで確認
Windows側からVisualStudioでMacにペアリングすると、「Xcodeが見つからない」と出る

# WindowsのVisualStudioで、Macにペアリングできない！

何度か試したのですが、
Windows機側から、Macにペアリングしようとすると、
「Xcodeが既定の場所に見つかりません」的なメッセージが。

調べた。。
デフォルト、「/Application/XCode」にあるのに、
なぜか、Mac側の環境変数で、そこじゃないところに、AppleSDKはあるといっているのが原因の様子。

事前にMac側にインストールしていた、
VisualStudio for Macを開いて、
以下の手順をしたら、無事接続できたので、備忘録！

# 手順  

1. Mac側で、任意のVisualStudioを開く(任意のプロジェクト作ってないと駄目かも）
1. [Visual Studio] > [ユーザー設定]を開く
1. メニューから、[プロジェクト] > [SDKの場所] > [Apple]を選択
1. [Apple SDK]の項がエラーになっていれば、[参照(B)...]をクリックして、「/Application/XCode」を選択
1. この後、Windows側のVisualStudioから、Macとペアリングすると・・・


## うまくいった～！！！！

このあたり、説明がしっかり書かれていないので、ぜひぜひ皆様ご確認してみてください。

See you next!
grep はマッチ文字列がないとエラー終了する

## 概要
`grep` は，検索がヒットしないとエラー終了します．その仕様を知らず，微妙にハマったときの話です．

## 詳細
### 状況の再現
たとえば，以下のようなスクリプトがあったとします．

```sapmle-grep.sh
#!/bin/bash
set -exo pipefail
lines="$(echo foo | grep bar | wc -l)"
echo "$lines"
```

`echo foo` がなにか動的な処理をするコマンドと想定しましょう．その出力の中から， `bar` を含む行を絞り込み，その行数をカウントして表示するスクリプトです．

直感的には， `echo foo` の出力内に `bar` なる文字列が存在しない場合，最後には `0` と出力されて終了するだろうと予想できます．しかし，現実にはそうならず，以下のような表示で終了します． [^xtrace]

[^xtrace]: `+` から始まる行は，実行されたコマンドの内容です． `set -x` の働きです．

```
$ ./sample-grep.sh
++ grep bar
++ echo foo
++ wc -l
+ lines=0
```

**最後の `echo` が実行されていません**．一見，なぜかスクリプトが途中で停止する怪奇現象に思えます．

### 原因の調査
遭遇時，不思議に思いながら原因を絞り込んだところ，どうやら `$()` の中のコマンド時点で停止していることがわかりました．そして， `grep` が終了コード `1` を出していることもわかりました．そこまで判明すると，スクリプト全体が停止するのは `set -e` および `set -o pipefail` の効果によると予想できます．

肝心の「**なぜ `grep` がエラー終了しているのか**」(= なぜ終了コードが `1` なのか) というところです． `man grep` を見て `exit status` で検索すると，以下の内容がヒットします．

```
EXIT STATUS
       Normally the exit status is 0 if a line is selected, 1 if no lines were
       selected, and 2 if an error occurred.  However, if the -q or --quiet or
       --silent  is  used and a line is selected, the exit status is 0 even if
       an error occurred.
```

(抜粋・雑訳)
**検索対象が見つからなければ，ステータス 1 で終了します．**

### grep はマッチ文字列がないとエラー終了する
タイトル回収です．

`man` の通り，マッチする対象が見つからなかったために終了コード `1` を出しており，そこに `set -eo pipefail` が合わさって怪奇現象が起きていました．この挙動は， `wc -l` との組み合わせではなく `grep` の `--count` オプションを使っても同じです．

```sample-grep-n.sh
$ echo foo | grep --count bar || echo fail
0
fail
```

`set -eo pipefail` も特にエラー文を出力しなかったので，怪奇現象となっていました．

完全にやられました．

### 回避策
これだけのために `set -eo pipefail` を外したくはありません．別の方法で回避したい気持ちになります．

`grep` 自体は「マッチしなくても `0` で終了する」的なオプションは持たないようです．エラー終了を回避するには，以下のようにする必要があるでしょう． [^true]

[^true]: `true` コマンドは，何も出力せず終了コード `0` を出します．

```
grep bar || true
```

これだと通常のエラー (コード `2`) も握り潰してしまうため好ましくないですが， `1` だけをうまく躱すためにはこの [Stack Overflow の回答](https://unix.stackexchange.com/a/427598) のように `$?` や `[[` 等を組み合わせるしかなさそうです．

```
echo something | grep x || [[ $? == 1 ]]
```

少し冗長になってしまうので，ケースバイケースで使い分けることになるでしょう．今回は使い捨てのスクリプトだったため，簡潔な前者を採用しました．

より堅牢性 (?) が求められる場合は，後者のようにマッチしなかった場合のみをハンドルするようなやり方が求められるでしょう．

## まとめ
grep の「マッチ文字列がないとエラー終了する」仕様を知らずに苦しめられた話でした．

筆者としては非直感的に思える挙動ですが，何か深い意図があるのでしょうか……．それにしたって，コマンドラインでオプトアウトできても良さそうなものですが，

この記事を読んだ方は，この挙動を頭においておくか，任意の `grep` に `|| true` をつける習慣を持ちましょう [^or-true]．

[^or-true]: 冗談です．
40 代おっさん GASをとりあえず動かしてみた‼

## 本記事ついて

本記事は プログラミング初学者の私が学習していく中でわからない単語や概要をなるべくわかりやすい様にまとめたものです。
もし誤りなどありましたらコメントにてお知らせいただけるとありがたいです。

## 動かしてみる

### スプレッドシートからスクリプトエディタを開く

まずはGoogleのスプレッドシートを開いてください。

次はサイドバーから拡張機能、APPS Scrigtを開く。

### エディタを編集

エディタに

```javascript
function myFunction() {
  
}
```

書かれているので
下のコードを追記

```javascript
Browser.msgBox('利樹大好きだよ～～ん');
```

コード.gsが黄色くなっているので
Ctrl+sで保存をしてください。

上が無題のプロジェクトになっていますので、そこをクリックするとプロジェクトタイトルを変更できます。

### スクリプトを実行

ツールバーにmyFunctionを確認
実行を押すか、Ctrl+Rを押す。

初回実行時だけ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641940/a437db19-bc1b-d954-18fc-aa9965594160.png)

権限を確認をクリック
アカウントの選択画面になるので自分のアカウントを選んでください。

![GAS確認画面.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641940/f40d5dab-44a3-c248-58cc-79a268998b6d.png)

と出ますので
詳細をクリック（赤枠）

自分のプロジェクト名（安全でないページ）に移動とでるのでそれをクリック

「アクセスをリクエストしています」と出るので許可をクリック

スプレッドシートを見るとメッセージボックスが出ていると思います。

## 参考資料

<https://www.amazon.co.jp/s?k=google+apps+script+%E5%AE%8C%E5%85%A8%E5%85%A5%E9%96%80&adgrpid=110264232688&gclid=CjwKCAiA9aKQBhBREiwAyGP5lSl7AJJLCvOEHb4wQgMlyqW1fll5X8GDTT_Rkd1_soUAyIPMXQr26hoClHEQAvD_BwE&hvadid=553833563682&hvdev=c&hvlocphy=1009076&hvnetw=g&hvqmt=b&hvrand=4378489642044417389&hvtargid=kwd-594191211348&hydadcr=4106_13159878&jp-ad-ap=0&tag=googhydr-22&ref=pd_sl_2x1owglv0s_b_p52>
babelのプラグイン

# プラグインの使用

babel.config.jsonにplugins項目を追加するだけ。
またパスには絶対、相対どちらも使える。

```json
{
  "plugins": ["babel-plugin-myPlugin", "@babel/plugin-transform-runtime"]
}
```

#　構文プラグイン
JSXやFlowなどのシンタックス変換をするためのプラグインも存在する。
使い方は下記のようになる。

```json
{
  "parserOpts": {
    "plugins": ["jsx", "flow"]
  }
}
```

# プラグインの実行順序

プラグイン(初めから最後まで) > プリセット(最後のプリセットから最初のプリセットまで)

# プラグインオプション
名前とオプションオブジェクトを構成内の配列にラップすることでオプションを指定できます。

```json
{
  "plugins": [
    [
      "plg-A",
      {
        "module": "bluebird1",
        "method": "coroutine1"
      }
    ],
    [
      "plg-B",
      {
        "module": "bluebird2",
        "method": "coroutine2"
      }
    ],
    [
      "plg-C",
      {
        "module": "bluebird3",
        "method": "coroutine3"
      }
    ]
  ]
}
```
Node.jsのESmodule設定でcloudinary機能が使いたとき import cloudinary from 'cloudinary' 思った通りに機能しない。

##  結論


Node.jsでESmodule設定でもCloudinaryを使用するなら下記のようにCommonjsを使う。
v2がないと駄目っぽい？

```php:app.js
import { createRequire } from 'module';
const require = createRequire(import.meta.url);

...

const cloudinary = require('cloudinary').v2; // ok
// import cloudinary from 'cloudinary' // No

```


使用方法をちゃんと読みましょう（教訓）

https://www.npmjs.com/package/multer-storage-cloudinary

##  import cloudinary from 'cloudinary' だと機能しない？
機能しないと思います。（私は機能しませんでした。）


### やりたいこと
ReactからformDataを使って送ってきた画像をCloudinaryに保存して、画像のURL（path）のみMongoDBに保存。

multer-storage-cloudinaryを使用することで、Cloudinaryに保存することができる。

### 起きたエラー

下記のupload.array('file')の部分で、Cloudinaryに保存するまでは大丈夫でした。
しかし、upload.array('file')のミドルウェアの後、CreatePostの処理にいってくれませんでした...


```php:route.js

router.post('/', auth, upload.array('file'), createPost);

```

## まとめ
解決策としては、最初に記述したようにV2をrequireするだけでした。
このエラーでかなりの時間を消費したので、誰かの助けになればと思います。
【Go】GitHub上の「特定の１ファイル」を取得する

<!-- wp:paragraph -->
<p>Go言語でAPIを使う練習のため、タイトルにある「GitHubのリポジトリにある特定の１ファイルの内容を取得する」プログラムを書いてみました。</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":1} -->
<h1 id="取得するファイル-githubリポジトリ側">取得するファイル（GitHubリポジトリ側）</h1>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>今回は<a href="https://github.com/fugithora812/git-tutorial">チュートリアル用のリポジトリ</a>から、以下のようなREADME.mdのコンテンツを取ってきてみたいと思います。</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code class="">This is a script for API-tutorial

- feature-A
- fix-B
- feature-C
</code></pre>
<!-- /wp:code -->

<!-- wp:heading {"level":1} -->
<h1 id="プログラム全文">プログラム全文</h1>
<!-- /wp:heading -->

```go
package main

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	blobUrl := "https://api.github.com/repos/fugithora812/git-tutorial/contents/README.md"
	req, err := http.NewRequest("GET", blobUrl, nil)
	if err != nil {
		fmt.Println("failed: NewRequest")
	}
	req.Header.Set("Accept", "application/vnd.github.v3+json")

	client := new(http.Client)

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("failed: DoReq")
	}
	defer resp.Body.Close()

	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("failed: ReadAll")
	}

	var blob interface{}
	err = json.Unmarshal(contents, &amp;blob)
	if err != nil {
		fmt.Println("failed: Unmarshal")
	}
	src := blob.(map[string]interface{})["content"]
	dec, err := base64.StdEncoding.DecodeString(src.(string))

	fmt.Println(string(dec))
}
```

<!-- wp:heading -->
<h2 id="実行結果">実行結果</h2>
<!-- /wp:heading -->

<!-- wp:code -->
<pre class="wp-block-code"><code class="">$ go run main.go
This is a script for API-tutorial

- feature-A
- fix-B
- feature-C
</code></pre>
<!-- /wp:code -->

<!-- wp:heading {"level":1} -->
<h1 id="解説">解説</h1>
<!-- /wp:heading -->

解説は[こちら](https://tubuyaki-tech.com/tubu-go-get-blob/)をクリックして読めます。（私の個人ブログに遷移します）
STM32G031のI2Cでマスターから送られた来た文字をシリアルに出力する。(STM32G031J6M6)(Arduino)(I2C-USART)


目的
I2Cのテスト


![o_con230.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/b02f1424-1d22-a614-c85c-c68746a565c9.jpeg)



```c++


//i2c_s_LCD_031_c1_1
//9600bps

#include <Arduino.h>
#include <Wire.h> //I2Cのヘッダー

//文字列の表示 nana_seg
int ns_printf(char *str1)
{

  //文字の中身がゼロか
  while (*str1) {

    digitalWrite(PB7, LOW);//Start
    delayMicroseconds(102);

    for (int ii = 0; ii < 8; ii++) { //Data x 8
      digitalWrite(PB7, ( (*str1) >> ii) & 1  );
      delayMicroseconds(102);
    }//for

    digitalWrite(PB7, HIGH);//Stop
    delayMicroseconds(102);

    str1++;//ポインターをカウントアップ

  } //while

  //戻り値
  return (0);

}//ns_printf


//初期化
void setup() {

  //仮想シリアルの出力ポートの初期化
  pinMode(PB7, OUTPUT);
  digitalWrite(PB7, HIGH);

  //I2Cの初期化
  Wire.begin(PA12,PA11); //stm32g031

  Wire.begin(0x40);  //I2Cスレーブアドレスの設定
  Wire.onReceive(receiveEvent); //データが来ると呼ばれる関数


}//setup


//無限ループ
void loop() {
}//loop



//レシーブイベント
void receiveEvent(int howMany) {

  int x = Wire.read(); //I2C受信データの読み込み

  char data_i[] = { x,0  };
  ns_printf(data_i); //受信した数値の表示



}//receiveEvent



```
githubで初pushをした時に、fatal: protocol 'https' is not supportedのエラー発生

Githubを初めて使ったときに起きた不具合です。
progateを学んだ直後の初学者の方であれば、同じような不具合に出くわすかもしれません。

##環境

□OS:Windows10 home　64bit

##不具合に至る経緯

progateで紹介された下記記事に従って、Gitのインストール＆Githubの登録を実施しました。
https://prog-8.com/docs/git-env-win

しかし、記事内の「④Githubにプッシュする」の工程を行った際に不具合が発生。

##不具合の詳細

記事に従って、下記の順番でコマンドを実行。

```
$ mkdir mysite
$ cd mysite
$ git init
$ git remote add origin <URL>
$ touch index.html
$ git add index.html
$ git commit -m "Create index.html"
```

↑ここまで上手くいった


```
$ git push origin master
```
↑最後に、このコマンドを実行する際に不具合が発生。
以下のようなエラーメッセージが表示されてしまった。

```
fatal: protocol 'https' is not supported
```

#原因、および解決方法

「$ git remote add origin <URL>」を実行した際に、制御文字が入ってしまったとのことです。
そのため、まずは以下のコマンドを実行。

```
git remote set-url origin <URL>
```

その後に、「$ git push origin master」をやり直したらうまくいきました。
解決のために、下記ページを参考にしました。
https://teratail.com/questions/253312

この不具合を通じて、プログラミング初学者にとって「ググる能力」が大切だと学びました:sweat_smile:
検索キーワード：emoji Font Cheatsheet

1. emoji Font Cheatsheet
1. icon Font Awesome Cheatsheet
1. icon Font nerd Cheatsheet

この検索キーワードを使ってグーグルで複合検索すれば一覧表へのリンクがいっぱい出て便利

* 絵文字フォント
* アイコンフォント

チートシートというのは、一覧表を作って壁に貼ったり、デスクのマウスパッドにしたり。早見表とか言うアレのこと。

海外でも emoji て呼ぶらしい。グリフだと昔と混同して検索にヒットしにくいからだろうか？
Pytorchを理解したい。足し算をするだけのPytorchモデルをつくる。

#足し算をするPytorchモデルを作ります

![baron007.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/098c72f2-b060-bd2b-63bd-722115451031.jpeg)

#Pytorchを理解したい
機械学習モデルの多くはPytorchやTensorFlowで書かれています。
機械学習モデルに触れてみたいけど、Pytorchコードの部分がなんか「むにゃむにゃむにゃ。。。」という感じ。

#シンプルなもので理解してみる
小学校の算数も、数を数えたり足し算をすることから始めた気がするので、
とりあえず、入力に１を足すモデルを作って理解してみます。

```python
import torch.nn as nn 

device = "cuda" if torch.cuda.is_available() else "cpu"

class AdditionModel(nn.Module):
    def __init__(self):
        super(AdditionModel, self).__init__()
        self.y = 1

    def forward(self, x):
        x = torch.add(x,self.y)
        return x

model = AdditionModel().to(device)
```

init　でモデルクラス自体を定義し、
forwardで入力を処理します。

モデルに入力してみます。

```python
x = torch.Tensor([1])
x = model(x)
x
```
>tensor([2.])

無事に入力の１とモデルの１が足されて2が出力されました。

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLやARKitを使ったアプリを作っています。
機械学習／AR関連の情報を発信しています。
GCP Cloud Funtions + Firebase

Cloud function develop

# GCP Cloud Function & Firebase 開発環境整備

ちょっとした縁でFirebaseを使ったプロジェクトのBackend構築を
お手伝いすることになりました。開発環境構築内容をまとめます。

## Firebase:Firestore 一般内容Study
Firestoreの基本は collection -> document -> collenction -> document .. という構造でdocumentに複数のField(Json)を保存することができるものです。このDocumentをCollectionにまとめて階層的に管理していくというのが基本的な使い方です。

SQLDBのように最初にTable定義をする必要はなく、上記の階層を指定して、データを書き込めば途中のcollection, documentは動的に生成されます。

* 注意点としてはcollectionは直接collectionを持つことができない。
    - 参考：https://firebase.google.com/docs/firestore/manage-data/structure-data

* collectionの最大深度は100, 1documentあたりの容量は1MBまでという制約がある。
    - 参考：https://firebase.google.com/docs/firestore/quotas

## FirebaseのBackend処理パターン
Firestoreに変更が加わったことに応じて処理をBackendで行いたいということが今回実現したいことです。

* Firebase自体にCloudFunctionという機能がリリースされた。こちらは2022/2月現在だとNodejsしかサポートされていない。また使用するには、Firebaseの有料（Blaze）契約が必要になります。
    - https://firebase.google.com/docs/functions
    - 料金プラン：https://firebase.google.com/pricing?authuser=0

Backend処理を行うときに下記の３パターンが想定されます
1. GCP Scheduler にて定期的に GCP CloudFucntion(python/Node)を呼び出す
2. Firebase firestore 変更Trigger にて Firebase Cloud Function(Node)を呼び出し処理を行う
3. Firebase firestore 変更Trigger にて Firebase Cloud Function(Node)が、GCP CloudFunction(python)　を呼び出し処理を行う

無料な状態ではとれるのは1のみ。　有料にしたときは処理のメイン内容により　2 or 3 を選んでいくのが良いと思います。

一般的に、画像処理、機械学習等はPythonで記述したほうがライブラリが豊富なので有利。
それ以外は実装担当者のスキルにより選んでいけば良いと思います。

### 参考
* Firebase/GCP の連携方法
    * https://firebase.google.com/docs/storage/gcp-integration?hl=ja
* FirestoreからGCP Cloudfunctionをtriggerする
    * https://cloud.google.com/functions/docs/calling/cloud-firestore#limitations
* FirestoreからFireabase cloud functionをTriggerする
    * https://firebase.google.com/docs/functions/firestore-events?hl=ja


## GCP CloudFUnctions (python) + Firebase SDK
GCP CloudFuntionから対象のFirebaseにアクセスするために FirebaseAdminSDK用の接続設定jsonが必要である。

1. 対象のFirebaseをひらき→プロジェクトの設定→サービスアカウントタブ　を開く
2. 新しい秘密鍵を生成する（安全に管理しましょう）
3. 下記のPythonの例を参考に必要なLibをInstall、生成した秘密鍵を渡して　読み書きできるようにする
  * Firebase Admin SDK : https://firebase.google.com/docs/storage/admin/start?hl=ja

Let's enjoy firestore programming!
Gitコンフリクト解消手順（マージ先のゴミ差分を取り込みたくない場合）

## はじめに

今回はGitのコンフリクトの解消法について備忘録を書いていこうと思います。<br>
記事を移転させました。<br>
[【投稿】Gitコンフリクト解消手順（マージ先の差分を取り込む場合と差分を取り込みたくない場合）](https://pick-up-tech.com/blog/git%E3%82%B3%E3%83%B3%E3%83%95%E3%83%AA%E3%82%AF%E3%83%88%E8%A7%A3%E6%B6%88%E6%89%8B%E9%A0%86%EF%BC%88%E3%83%9E%E3%83%BC%E3%82%B8%E5%85%88%E3%81%AE%E5%B7%AE%E5%88%86%E3%82%92%E5%8F%96%E3%82%8A%E8%BE%BC%E3%82%80%E5%A0%B4%E5%90%88%E3%81%A8%E5%B7%AE%E5%88%86%E3%82%92%E5%8F%96%E3%82%8A%E8%BE%BC%E3%81%BF%E3%81%9F%E3%81%8F%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%EF%BC%89)

![git-conflict.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267720/19c88e8a-3dde-d945-dcfd-78ab9b51bbaa.png)
2022/2/14主にITとかセキュリティの記事

サイバーセキュリティにとって厳しかった2021年は関連スタートアップには記録的な年に(2/11)
https://jp.techcrunch.com/2022/02/11/2022-02-09-vc-cybersecurity-startups-record-year/

Windows Defender(Microsoft Defender)とは？ 最大限に有効活用する方法と組み合わせるべき対策について(2/11)
https://japan.zdnet.com/release/30644375/

県内ぴりぴり、ウイルスメール テレワーク浸透、セキュリティーと社員教育強化(2/12)
https://www.yamagata-np.jp/news/202202/12/kj_2022021200369.php

AWSを触らずに「AWS認定ソリューションアーキテクト アソシエイト」に合格した話(2/11)
https://qiita.com/shoshohehe/items/6862bf0363d62d5e3344

【イギリスの元スパイが説く】
どんな状況の予測にも使える考え方とは？(2/12)
https://diamond.jp/articles/-/294526

仮想通貨採掘業者が保有ビットコインを削減、業界再編の兆しか(2/12)
https://www.bloomberg.co.jp/news/articles/2022-02-11/R75JNYT0G1KW01

意外とわかっていないテクノロジー用語解説
ビジネスの世界で頻出しはじめた『DAO』とは？　インターネットネイティブな組織を作る仕組みへの期待と課題(2/12)
https://realsound.jp/tech/2022/02/post-966298.html

ロシア政府、暗号資産を通貨の一形態として認める方針(2/12)
https://hedge.guide/news/russia-crypto-regulation-bc202202.html

NTTドコモを装ったフィッシングSMSが報告、注意を呼びかけ(2/12)
https://iphone-mania.jp/news-437528/

Slackで生産性を最大限に。知らなかった4つのカスタマイズ機能(2/11)
https://www.gizmodo.jp/2022/02/productivity-tips-for-working-in-slack.html

欧米の対ロ制裁、銀行のＳＷＩＦＴ排除は含まれず＝関係筋(2/12)
https://jp.reuters.com/article/ukraine-crisis-sanctions-idJPKBN2KG24I

富士通、メインフレームの販売を2030年で終了へ(2/12)
https://www.zaikei.co.jp/article/20220212/659996.html

【重要ニュースまとめ（2/5~2/11）】国内財閥グループ2社が暗号資産業界に本格参入、ロシア政府は暗号資産を通貨と認定へ(2/12)
https://hedge.guide/feature/blockchain-weekly-report-0212-bc202202.html

北朝鮮にハックされて頭にきたセキュリティ研究員がしかえし→北朝鮮全土ネット遮断 | ギズモード・ジャパン(2/10)
https://newstopics.jp/url/19359614

「メールは危ない」と何度でも伝え続ければいけない理由と、正しい伝え方(2/12)
https://techtarget.itmedia.co.jp/tt/spv/2202/12/news01.html

長野県機関を装った「なりすましメール」にご注意ください(2/10)
https://www.pref.nagano.lg.jp/dx-infra/20220210.html
VSCode拡張機能のオフラインインストール用vsixファイルのダウンロード

# 概要
* VSCodeの拡張機能はオフラインインストールできます。流れとしては、VSCodeのMarketPlaceのWebページからオフラインインストール用のvsixファイルをダウンロードし、GUI操作でオフラインインストールします。非常に簡単です。
* ただし、拡張機能によっては、比較的新しいバージョンのvsxiファイルのダウンロードリンクしかないことがあります。VSCodeのバージョンに依存して、拡張機能の過去バージョンが必要なことがあります。
* 私は、適切なバージョンを確認するのと、そのバージョンをダウンロードする手順を見つけるのに困ったため、そのTipsをまとめます。



# 手順
## 1.適切なバージョンの確認
* インターネットに繋がる環境で、拡張機能をオンラインインストールして、バージョンを確認。
* 例）Jupyter
    * v2021.5.745244803
    * <img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100414/fc86bab8-4c6a-06b3-1524-b71479994b13.png">


## 2.ダウンロードURLの確認
* MarketPlaceの該当拡張機能のページにアクセスし、Version Historyのタブで、ダウンロードURLを確認。
* バージョン部分を自分が欲しいバージョンに置き換えて、ブラウザでアクセスすれば、vsixファイルがダウンロードできます。
* 例）Jupyter
    * 最新バージョンのURLは、「https://marketplace.visualstudio.com/_apis/public/gallery/publishers/ms-toolsai/vsextensions/jupyter/2022.2.1001828435/vspackage」。
    * この「2022.2.1001828435」を「2021.5.745244803」に置き換えればOK。
    * <img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100414/73d63fca-ff20-4b76-fba3-a5af16bc0d61.png">

# 参考
* [VSCode拡張機能をオフライン環境でインストールする方法](https://qiita.com/ss_tom_jp/items/5977e4f16d78b8ca7cc8)
* [VSCodeにオフラインでExtensionを追加する](https://qiita.com/ss_tom_jp/items/5977e4f16d78b8ca7cc8)
オプションで色を指定してターミナルに出力するやつ


探してもあんまり見つからんかったからいっそ作った

# 概要
数人で共有するサーバでログイン時に注意書きを出したりいしたい．
でも，全部同じ色だと非常に見づらい．
かと言って， `echo` のエスケープシーケンスを全部自前で書く気力はない．

というわけで，そのへんをうまいことやってくれるコマンドがあるはずだ，探そう…

あれ？ぜんぜん見つからんが…

探すのめんどくさいし，作るか．

Pythonは簡単だけど，コマンドとしては使いづらい．そうだRustを使おう．

という経緯


# 使い方
基本的には公開しているGithub
[echooo](https://github.com/customtea/echoo/)
を参照していただきたい．

ちゃんと，relase機能を使って，win用のexeとLinux用のバイナリをそれぞれ用意しておいた．（というか，Linuxのサーバで使うのに，開発をWindowsでしちゃったからクロスコンパイルが必要だっただけである）

![screenshot](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356619/3f2a123e-b574-38d8-ec3c-c4ad7dae1a90.png)



## ネーミング
`echo`に追加機能をつけただけなので，既存の表示に使ってる `echo`に `oo` をつけるだけで使えるんじゃないかと思ってやった．

（最近この手のの最後の文字ダブらせる，独自コマンドを作ってたからそれに引っ張られた… `cdd` とか（`cd` に`fzf` を合体したやつ））
LinuxとPython3でsubprocess.Popenを使って"OSError: [Errno 12] Cannot allocate memory"が出たとき


# 原因
* 単純にメモリーが足りない
* subprocess.Popenを実行するプロセスのメモリが元々多い

# メモリが元々多い？？とは？

subprocess.Popenを実行するプロセスのメモリが元々多いとは？
subprocess.Popenはシステムコールのsys_cloneが使われていて、メモリがコピーされて使用量もコピーされるようです・・・
そんなの知らないよ・・・:sob:
tensorflowで大き目のモデルを読み込んだプロセスとかだと大き目になりがち。
その状態でsubprocess.Popenを使って非同期実行するとメモリがコピーされるのか？メモリ空間がコピーされるのかよくわからないがsubprocess.Popenコール時点の容量が消費されるみたいです。

単純にメモリーが足りないパターンの場合はどうしようもない。:frowning2:

# 対策

キュー化するとか??大げさになっちゃうなぁ～～:thermometer_face:。今回は、REST APIを作って小さいプロセスからsubprocess.Popenで非同期実行してみた。
(Oracle)SQL*Loaderで大量データを投入する方法

## (Oracle)SQL\*Loaderで大量データを投入する方法

テスト環境などに大量データを仕込むときに行う方法。
数百、数千件であればObject BrowserやDMLを使用したほうが楽ですが、
UNDO表領域を使用するため百万件のような大量データを仕込む場合はSQL\*Loaderを使用したほうがお勧め。

SQL\*LoaderではUNDO表領域を使用しないで直接データを書き込むため、
何百万件のデータも数分で登録することができる。

## DB環境
Oracle

## 準備に必要なもの
  - CTLファイル
  - DATファイル(CSVファイルも可)

## CTLファイル
テーブルの情報を記載したファイル。
大量データを登録するテーブルの情報。
※"INFILE"で登録対象のDATファイルを指定。

```
LOAD DATA
INFILE 'MY_TABLE.DAT'
APPEND
INTO TABLE MY_SCHEMA.MY_TABLE
FILEDS TERMINATED BY ","
TRAILING NULLCOLS
(
  "COLUMN1",
  "COLUMN2",
  "COLUMN3",
  "COLUMN4" DATE "yyyy/mm/dd hh24:mi:ss"
)

```

## DATファイル
DATファイルには実際に登録するデータを記載する。
データはカンマ区切りのためCSVファイルでも可能。

```
DATA1-1,DATA1-2,DATA1-3,2021/12/11 09:11:54
DATA2-1,DATA2-2,DATA2-3,2021/12/11 09:11:54
DATA3-1,DATA3-2,DATA3-3,2021/12/11 09:11:54
```

## 実行方法

CTLファイルとDATファイルを用意したら
以下コマンドを実行する。
※今回はCTLファイルとDATファイルをカレントディレクトリに用意しています。

```
sqlldr userid=SchemaID/schemaPW@10.11.11.11:1020/schema control=MY_TABLE.CTL log=MY_TABLE.LOG
```

- userid=SchemaID/schemaPW@10.11.11.11:1020/schema<br>
DBの接続情報
- control=MY_TABLE.CTL<br>
事前に準備したCTLファイル
- log=MY_TABLE.LOG<br>
実行結果
Laravel8系でログイン機能を実装する方法


#laravel8系でログイン機能を実装する方法

#####筆者は、laravelのログイン機能をインストールする際にかなり手こずりました。そのため、今回記事にして参考にしていただければ幸いです。きっと、laravel初学者の方の参考になると思います。

##概要

- larave8系のインストール
- Bootstrapのインストール

##①laravel8系をインストールしよう
まず、下記のコードをターミナルにコピペしてください。
その際、<アプリネーム>の部分を任意の名前に変更して下さい。
例えば、sampleとかsimple、極論Appleでも大丈夫です。
今回は、Appleにしたいと思います。

↓（下記のコード）
```composer create-project --prefer-dist laravel/laravel <アプリネーム> "8.*" ```

↓

インストールが済んだら下記のコードを入力して下さい
cdコマンドでAppleのディレクトリに移動します。

↓（下記のコード）
```cd Apple```

ターミナルで下記のコード（php artisan serve）を入力して下さい。
そしたら、```http://127.0.0.1:8000```と表示されて、簡易サーバが立ち上がると思います。
↓（下記のコード）
```php artisan serve```

##➁Bootstrapのインストールしよう

下記のコード、laravel uiをインストールしていきます。
↓（下記のコード）
```composer require laravel/ui```

その次にLOGIN機能とテーブル作成していきますので、下記コードを入力して下さい。
↓（下記のコード）LOGIN機能
```php artisan ui bootstrap --auth```
↓（下記のコード）テーブル作成
```php artisan migrate```

↓

そしたら、```npm install && npm run dev```をターミナルに入力して下さい。

↓

下記文章のように詳細については `npm　fund`を実行してくださいと文章が表示されると思うので、バコバコ`npm　fund`など入力して行きましょう！！！！
↓（下記文章）
84 packages are looking for funding
  run `npm fund` for details


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1788291/9f86f18d-c275-789d-e124-d7c7efd4534b.png)


バコバコ入力し終わったら、`npm install`を入力し、その次に`npm run dev`を入力すれば、無事に終了になると思います！！！
このような画面が出たら、OKです！！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1788291/67138b54-0c24-9b06-5f87-a25095f1616b.png)

それでは、`php artisan serve`を入力し、簡易サーバーを立ち上げます。
そして、画面を見ると完成している!!!



今回はここで終了です。ありがとうございました。
Makefileで全探索

# 背景

Makefileをタスクランナーとして使用する記事が色々あります。

- [タスク・ランナーとしてのMake](https://qiita.com/shakiyam/items/cdd3c11eba978202a628)
- [MakeをPythonのタスクランナーとして使う](https://www.honai.me/blog/post/makefile-python-task-runner/)

そうすると、パラメータチューニングなどで、全探索をしたくなります。  
本記事では、Makefileの並列処理の能力を生かせるようにターゲットを構成してみます。

# 方法
Makefileのワイルドカードや関数を用いて、テストケースの通し番号に紐づくパラメータの組み合わせを求めます。

```makefile
LIST_OF_VAR_A = $(shell seq -f "%03.1f" 0 0.1 0.2)
LIST_OF_VAR_B = $(shell seq -f "%01.0f" 2)
LIST_OF_VAR_C = $(shell seq -f "%02.0f" 10 12)

LEN_A = $(words $(LIST_OF_VAR_A))
LEN_B = $(words $(LIST_OF_VAR_B))
LEN_C = $(words $(LIST_OF_VAR_C))

LAST_INDEX := 1
LAST_INDEX := $(shell echo "$(LEN_A) * $(LAST_INDEX)" | bc)
LAST_INDEX := $(shell echo "$(LEN_B) * $(LAST_INDEX)" | bc)
LAST_INDEX := $(shell echo "$(LEN_C) * $(LAST_INDEX)" | bc)
LAST_INDEX := $(shell echo "$(LAST_INDEX) - 1" | bc)

OUTPUTS = $(foreach INDEX, $(shell seq -f "%02.0f" 0 $(LAST_INDEX)), test_$(INDEX))

all: $(OUTPUTS)

test_%:
	$(eval INDEX:=$(subst test_,,$@))
	$(eval VAR_A = $(word $(shell echo "$(INDEX) % $(LEN_A) / 1 + 1" | bc), $(LIST_OF_VAR_A)))
	$(eval VAR_B = $(word $(shell echo "$(INDEX) % ($(LEN_A)*$(LEN_B)) / $(LEN_A) + 1" | bc), $(LIST_OF_VAR_B)))
	$(eval VAR_C = $(word $(shell echo "$(INDEX) % ($(LEN_A)*$(LEN_B)*$(LEN_C)) / ($(LEN_A)*$(LEN_B)) +1 " | bc), $(LIST_OF_VAR_C)))
	@echo Check $@ with VAR_A: $(VAR_A), VAR_B: $(VAR_B), VAR_C: $(VAR_C)

```

# 結果
```bash
$ make all
Check test_00 with VAR_A: 0.0, VAR_B: 1, VAR_C: 10
Check test_01 with VAR_A: 0.1, VAR_B: 1, VAR_C: 10
Check test_02 with VAR_A: 0.2, VAR_B: 1, VAR_C: 10
Check test_03 with VAR_A: 0.0, VAR_B: 2, VAR_C: 10
Check test_04 with VAR_A: 0.1, VAR_B: 2, VAR_C: 10
Check test_05 with VAR_A: 0.2, VAR_B: 2, VAR_C: 10
Check test_06 with VAR_A: 0.0, VAR_B: 1, VAR_C: 11
Check test_07 with VAR_A: 0.1, VAR_B: 1, VAR_C: 11
Check test_08 with VAR_A: 0.2, VAR_B: 1, VAR_C: 11
Check test_09 with VAR_A: 0.0, VAR_B: 2, VAR_C: 11
Check test_10 with VAR_A: 0.1, VAR_B: 2, VAR_C: 11
Check test_11 with VAR_A: 0.2, VAR_B: 2, VAR_C: 11
Check test_12 with VAR_A: 0.0, VAR_B: 1, VAR_C: 12
Check test_13 with VAR_A: 0.1, VAR_B: 1, VAR_C: 12
Check test_14 with VAR_A: 0.2, VAR_B: 1, VAR_C: 12
Check test_15 with VAR_A: 0.0, VAR_B: 2, VAR_C: 12
Check test_16 with VAR_A: 0.1, VAR_B: 2, VAR_C: 12
Check test_17 with VAR_A: 0.2, VAR_B: 2, VAR_C: 12
```

# 解説
3通りの値を取るVAR_A、2通りの値を取るVAR_B、3通りの値を取るVAR_Cの全探索なので、3x2x3=18(通り)あります。
そこで、00から18までのインデックスを各場合に割り当て、生成すべきターゲット名をtest_00などのように名付けます。

ターゲット名から、インデックス$I$を取得するのが以下の行です。

```Makefile
$(eval INDEX:=$(subst test_,,$@))
```

インデックス$I$に基づいて、パラメータを決定します。
VAR_A, VAR_B, VAR_Cのインデックス$I_A$, $I_B$, $I_C$は以下で決定します。

$$ I_A = (I \% 3) // 1$$
$$ I_B = (I \% (3*2)) //3 $$
$$ I_C = (I \% (3*2*3)) //(3*2) $$

ここで、//は商を、%は「あまり」を求める演算子です。この計算で以下の数列を得ます。
ただし、Makefileの関数である`word`は、最初の要素のインデックスがゼロではなく１であるので、上記の計算で求めたI_A, I_B, I_Cに1を足して、パラメータを取得しています。

|I  |I_A|I_B|I_C|
|--:|-:|-:|-:|
| 0|0|0|0|
| 1|1|0|0|
| 2|2|0|0|
| 3|0|1|0|
| 4|1|1|0|
| 5|2|1|0|
| 6|0|0|1|
| 7|1|0|1|
| 8|2|0|1|
| 9|0|1|1|
|10|1|1|1|
|11|2|1|1|
|12|0|0|2|
|13|1|0|2|
|14|2|0|2|
|15|0|1|2|
|16|1|1|2|
|17|2|1|2|