OmniAICreator/Qiita-1.07M huggingface dataset:
古い余っていたPCに無償版ESXiをインストールした備忘録

個人的な備忘録の側面もあるので雑です。
なんなら終わった後に記事を書くことを思いついてうろ覚えで書いてたりするので画像もない。
少し詰まったポイントがあったので同じようなことしようとしている人の助けになったらうれしいなぐらい。

# 経緯
* 旧メインPCが余っている
* サーバー用にしようかな
* そうだ、どうせならESXi入れてみよう

## 旧メインPCのスペック
* マザーボード
    * [ECS Z77H2-A3 with DVI](https://www.ecs.com.tw/en/Product/Motherboard/Z77H2-A3/specification)
    * **内臓NICがRealtek** 、後々苦労する
* CPU
    * Core i7 3770
* メモリ
    * 寄せ集めで合計24GB

# 準備
* ESXiのイメージとライセンスキーをもらってくる
    * DLにはユーザー登録が必要
    * 詳しい方法などはほかの記事があるので割愛
* SSDを購入
    * USBブートで悲しいことになった話を周りで聞いたのでちゃんとSSDにインストールする
    * 今回はAmazonでKingston SSD Q500 480GBを購入
        * https://www.amazon.co.jp/gp/product/B07KCP5NT9

# いざ導入
* [こちら](https://soji256.hatenablog.jp/entry/2020/04/28/090814)のブログを参考に導入作業を進めていく
* [Rufus](https://rufus.ie/)を使って起動用USBを作成
    * なんか `menu.c32` が古いよ！新しくする？と聞かれる
    * 新しくせず作成したところ見事にそれ起因で起動しなかったのでおとなしく指示通り新しくする
* USBから起動、インストールを試みる・・・が
* [これ](https://protectli.com/kb/esxi-7-bios-workaround/)と同じような症状が発生、同じように設定を変更することで先に進めた
* NICが認識しない・・・これは上でも書いたが内臓NICがRealtek製のせい
    * [IntelのNIC](https://www.amazon.co.jp/gp/product/B01LYSK23E/)を買い足した
    * 選定理由は安かったのと同じコントローラーがコンパチありそうだったため、結構賭けだった
* NICを追加したところ無事認識、インストールできた
* インストールはできたが次はブートしない（BIOS直通になる）
    * これはブート設定を初期化したら治った
* 無事インストール完了！

# 設定
* IPがDHCPだと嫌なのでルーターの設定を覗いて振り分け対象外のアドレスを静的に設定した
* ブラウザからのアクセス確認
    * 特に異常もなし
* ライセンス割り当て
* サクッと差しておいたSSDをデータストアとして構成して完成
* もうあとは遊び放題（無償版の範囲内で）

# 所感
* 思いついて完成まで3日ぐらい（機材の買い足しがなければ1日で終わった）
* 想定よりはうまくいった感
    * なんなら失敗すると思っていた
    * NIC問題は少し焦った
* 偉大なる先人の知恵に大きな感謝を
* ちゃんとした構成で遊んでみたい欲がわいてきたのでVMUGとか考え始めた
deviseとdevise_token_authとomniauthの使い分けがわからなかったので調べてみた

はじめに
--
自分の備忘録として、わからなかったことや詰まった部分をアウトプットしています。
同じ部分で悩んでいる方の力になったら幸いです。

何に詰まったのか
---
現在ポートフォリオを作成しており、バックエンドをrails apiで開発をしています。
その中でアカウントを作成しなくてもTwitterのアカウントでログインができる機能を実装したいと考えました。

この機能を実現するためには、ログイン機能のgemとして有名なdevise以外に何が必要なのかな？と思い調べたところ、
・devise_token_auth
・omniauth
のgemが検索でヒットしました。

実装方法についてはたくさんの記事があったので、おそらく理解していなくてもなんとなくで作成できる気がします。
「それぞれ何の役割があるのか/何をしたいときにどのgemが必要なのかが分かっていない」まま開発をしてもエラーの際にとても時間がかかったり、目的からずれた使い方をしてしまうと思ったので実装前にそれぞれの役割を簡単に整理しようと思いました。

色々な記事を参考にして自分なりに整理をしてみましたが、ポートフォリオ作成中の初学者なので間違った理解があるかもしれません。
もし間違った内容や補足内容があればご指摘を頂けますと幸いです。

devise_token_auth
--
deviseのログイン機能ではsession認証を使用しており、devise_token_authは、railsをapiモードで使用する際にログイン機能でトークン認証を行うためのgemのようです。(セッション認証、トークン認証については色々と記事がヒットするので是非調べてみてください)

また、deviseがGemfileに入っていないと、devise_token_authでエラーが起きてしまうことがあるようなので、セットでGemfileに書く必要がありそうです。

session認証では、cookieを使用して状態を維持（ECサイトで買い物リストに入れる等)します。
もしrailsをapiモードでデータを提供する立場の場合、そのデータを使う先がネイティブアプリ（app storeとかでインストールするアプリのこと)の可能性があり、その場合はcookieを使用できないので、その代わりにトークンを使って認証をする必要があります。
>railsをapiモードでデータを提供する立場の場合、そのデータを使う先がネイティブアプリ（app storeとかでインストールするアプリのこと)の可能性があり

※この箇所はrails+react Nativeを使ってアプリを作成した場合（スマホアプリのバックエンドをrailsが担う）のような場面のことなのではないかと解釈しております。


この箇所は下記の方の記事を参考にさせて頂きました。

https://qiita.com/tomokazu0112/items/5fdd6a51a84c520c45b5

omniAuth
--
こちらはすごくシンプルです。
一言で言うと外部のアカウントを使用してログインやユーザー登録ができるようになるgemです。
使用する際には、omniauthのgemとomniauth-twitterのようにomniauth-[使用したいサービス名]のgemをGemfileに記載する必要があります。

例
~~~
  gem 'omniauth'
  gem 'omniauth-twitter' #Twitterを使用したい場合
~~~


終わりに
--
最初はdevise+omniauthのgemだけ使っている記事があったり、devise+devise_token_authを使用した記事があったりと何を使ったらいいのか頭がこんがらがってしまいましたが、調べてみると役割が全然違いました。
理解が浅い箇所がまだ大量にありますが、使用するものを調べて自分の理解を深めていきたいです！

ここでつまづく人もそんなにいないかもしれませんが、僕が実際詰まったので誰かの助けになったら幸いです！
【JavaScript】クラス関連の用語

・オブジェクトとは
　→複数の値をプロパティという名前をつけて管理できるもの
　(例)const user = {name: "シンチ", age:24};
　　　この{}の部分のこと

・書いてて思ったけどやっていくうちに覚えていく気がするから、
さくさく勉強進めちゃおう。
基本情報技術者試験_CPU

CPU
CPUはコンピュータの頭脳に当たり、プロセッサと呼ばれています。CPUの性能は、主にフロック周波数とバス幅で表されます。 

クロック周波数
コンピュータの内部では、一定の間隔で電圧が規則的に「高」「低」を繰り返す信号が生成されています。これがコンピュータの動作の基準となるクロック信号(クロックパルス)です。クロック信号の高低の搔い繰るが１秒間に繰り返される回数をクロック周波数といいます。単位としてＨzヘルツが使われます。
例えば、クロック周波数２GＨzとは、１秒間に２x10⁹回の信号を生成していることを示しています。この信号に合わせて、コンピュータが動作しています。これは人に例えると、脈拍のようなイメージです。
CPU内部のクロック周波数は内部クロック、cpuの主記憶などの周辺回路を結ぶ伝送路のクロック周波数は外部クロック(システムクロック)といいます。内部クロックは、外部クロックの数倍の速度で動作しますが、PCのカタログなどにあるクロック数は内部クロックのことです。
一般的に、同一種類のCPUであれば、クロック周蓮は高いほど処理能力は高くなります。但し、主記憶やハードディスクなどの性能も関係してくるため、CPUのクロック数を2倍にすれば、システム全体も2倍になるわけではありません。
また、CPUの発熱量も増加するので、防熱処理が問題となり限界があるためＭ様々なCPUの高速化の方法が考えられています。

バス
CPUのや錦億、キャッシュメモリなどで、お互いがデータの送受信をするための伝送路をバスといいます。これは人に例えると、血管のようなイメージです。
一般的に、バス幅は広く、クロック周波数が大きいほど、高速にデータを送受信することができます。
STM32L010とDS1307で時計プログラム(ソフトウェアシリアル出力)


x リビジョンの変え方がわかる人よう
x Mbed2リビジョン125

x 時間合わせは、別

目的
RTCのテスト
時間合わせが人気があったから

調査目的で引用
原文を確認の事

![o_con625.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/b511ba74-36c6-6e3a-5191-f170ee9e67ed.jpeg)



![o_con627.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/3b4fcd65-4453-043b-5354-ed584aef001c.jpeg)



```c++

//i2c_ds1307_S_SER_010_1

#include "mbed.h"

//仮想シリアルへの一文字出力 9600bps
DigitalOut TX(PA_2);
#define UART_DELAY 101 //  1/9600 98-105
int pc_putc(char ch)
{
    TX=1;
    TX=0;//Start
    wait_us(UART_DELAY);

    for(int ii=0; ii<8; ii++) { //Data x 8
        TX=(ch>>ii)&1;
        wait_us(UART_DELAY);
    }; //for

    TX=1;//Stop
    wait_us(UART_DELAY);

    return(0);
} //pc_putc

//メイン関数
int main()
{
    I2C i2c(PA_10, PA_9); //010

    char data_read[7]; //リードバッファー
    while(1) {

        //時間の読み込み
        i2c.write( (0xD0), "\000", 1);
        i2c.read(  (0xD0) | 1, data_read, 7);

        //時間の表示
        pc_putc( '0'+(data_read[2] >> 4)   );
        pc_putc( '0'+(data_read[2] & 0xf)  );
        pc_putc( '.' );
        pc_putc( '0'+(data_read[1] >> 4)   );
        pc_putc( '0'+(data_read[1] & 0xf)  );
        pc_putc( '.' );
        pc_putc( '0'+(data_read[0] >> 4)   );
        pc_putc( '0'+(data_read[0] & 0xf)  );
        pc_putc( '\r');
        pc_putc( '\n' );

        //1秒待つ
        wait_ms(1000);
    }//while
}//main

//容量削減
void error(const char* format, ...) {}





```
Web3でビジネスはどう変わる？

# はじめに
IT×ビジネスという視点で週1本記事を投稿しています。
もし興味のある方は下のリンクから他の記事も見ていただければ幸いです。
 [@7_inai_](https://qiita.com/7_inai_)

# Web3とは
Web3はイーサリアムの共同創業者であるGavin Wood氏によって提唱された、インターネットの新たな概念のことで、__次世代の分散型インターネット__ の総称です。
`特定の企業に依存しない、分散型のインターネットというのが大きな特徴`です。

Web3があるということはWeb1やWeb2も存在します。はっきりとした定義があるわけではありませんが、一般的な定義としては以下のようになっています。
- Web1(1995〜2000年頃)：WWW(World Wide Web)が普及し、個人が自由にホームページを制作に発信できるようになった時代。__静的コンテンツ、読み取り専用が大半。__
- Web2(2000〜2020年頃)：SNSの普及。__情報発信者と閲覧者の双方向的な通信。__ 見るだけから参加できるインターネット。
Web2ではGAFAMに代表されるプラットフォーマーが開発したプラットフォームを使用するため一部の企業が市場を独占していました。しかしWeb3では管理者を必要としないため、そういった意味で特定の企業に依存しません。

# Web3でビジネスがどう変わる？
Web3では主に以下の3つのメリットがあります。
- 仲介組織を介さない
Web3では、ブロックチェーンの仕組みによりP2Pという接続方法で接速できるため、__データの通信にサーバーを管理する中間組織を介しません。__ そのため、企業とユーザーが直接かつ自由に通信ができるようになります。


- セキュリティの向上
ブロックチェーンによる分散型ネットワークでは、個人の情報を集約して管理するのではなく、__全員で情報を分散して管理するためセキュリティが向上__ します。

- クリプトエコノミー
Web3では __クリプトエコノミーという新しい経済圏__　が形成されています。クリプトエコノミーでは、円・ドル・ユーロのような法定通貨(法で定められた通貨)ではなく、暗号試算が流通しています。また、現金を預けておく銀行が必要ないため、アメリカの若者の間ではBANKLESSという考え方も増えていきています。

他にも、Web3を代表する用語として次のようなモノがありますが、詳細はそれぞれのリンクからご確認お願いします。
・[DAO](https://qiita.com/7_inai_/items/eb78bdc13b7c2f1d631d)
・[NFT](https://qiita.com/7_inai_/items/847b070db694276eae4c)
・[DeFi](https://qiita.com/7_inai_/items/0c13c35f55dab796b930)
・[DApps](https://qiita.com/7_inai_/items/9b859520d31bff2cf1c8)


# 終わりに
前述した通りWeb3では特定のプラットフォームを必要としません。これにより、今まで固有のプラットフォームで市場を独占していたGAFAMの今後はどうなるのでしょうか？GAFAMによってWeb3に向けた新しいサービスが生まれるのでしょうか？それとも新たな強みを持った企業が生まれるのでしょうか？今後の動向が楽しみです。
最後までお付き合いくださりありがとうございました。
チーム開発時、どのようにして品質を担保したか

### はじめに
チーム開発時に品質を担保するために行っていたことを書いていきます。

### 品質を担保するために行っていたこと
プルリクエストを上げる前にエラーが発生しないかを確認しました。
具体的には確認時にローカル環境でデータを入れ直してエラーが発生していないかを確認したり、
画面を表示・動作するかの確認を行いました。
【トリビアのDelta Lake】#7 Pysparkでカラム内のjsonデータを取り出す

Sparkはさまざまなフォーマットのデータに対応しており、jsonデータも勿論readし、Databframeにすることができます。
```
{"a": 123,"b":"hello"},
{"a": 789,"b":"world"}
```
こんなjsonファイルがあったとして、こんな感じで読める。
```Python:read_json.py
df_from_json = (
    spark
    .read
    .format("json")
    .load("<file_name>.json")
)
```

https://spark.apache.org/docs/latest/sql-data-sources-json.html

# 値の中身にjsonがある場合

ここまでは「そりゃそうじゃん」って内容なのですが、じゃあ、カラム内の値がjsonだとしたら？
```
+---+------------------------------+
|no |value                         |
+---+------------------------------+
|1  |{"year": 2021,"rank":"junior"}|
|2  |{"year": 2022,"rank":"senior"}|
+---+------------------------------+
```

# get_json_object
sparkは優秀なので、おあつらえむきなfunctionがあります。

https://spark.apache.org/docs/3.1.1/api/python/reference/api/pyspark.sql.functions.get_json_object.html

こんな感じで書けます。
```Python:get_json_in_dataframe.py
from pyspark.sql.functions import get_json_object,col
df_get_json = (
    df_include_json
    .withColumn("year", get_json_object(col("value"), "$.year").cast("string"))
    .withColumn("rank", get_json_object(col("value"), "$.rank").cast("string"))
)
df_get_json.show()

>>>
+---+------------------------------+----+------+
|no |value                         |year|rank  |
+---+------------------------------+----+------+
|1  |{"year": 2021,"rank":"junior"}|2021|junior|
|2  |{"year": 2022,"rank":"senior"}|2022|senior|
+---+------------------------------+----+------+
```

もちろん、select文を使うことで、value列を消して、見たい値だけ残すってことも可能です。
```Python:get_json_with_select.py
from pyspark.sql.functions import get_json_object,col
df_get_json = (
    df_include_json
    .withColumn("year", get_json_object(col("value"), "$.year").cast("string"))
    .withColumn("rank", get_json_object(col("value"), "$.rank").cast("string"))
    .select(
        "no",
        "year",
        "rank"
    )
)
df_get_json.show()
>>>
+---+----+------+
|no |year|rank  |
+---+----+------+
|1  |2021|junior|
|2  |2022|senior|
+---+----+------+
```
これで美しくなりましたね。

# どんなときに使う？
APIのGetメソッドを使って返ってきたレスポンス（json）は、とあるvalueの中身がまたjsonで…など、多階層にネストされていることもしばしば。
そんなときも根気よく掘って値を表示していきたい、っていうときに使えそうですね。

久しぶりにQiitaを書きました。
今後ともよろしくお願いします。

# このシリーズの目的
クラウドストレージに蓄積された生データ（CSV,JSON等）を加工するのに必要なPysparkの知識を溜めていく、まさにPysparkに関するトリビアのDalta Lakeを目指しています。
Pysparkに関する記事はまだ海外のものが多く、このシリーズが私のような国内の駆け出しデータエンジニアの一助になることを願っています。
ubuntuにcomposerをインストール

参考
https://mebee.info/2020/06/02/post-10844/

```
sudo apt install -y php libapache2-mod-php php-gd php-xml php-cli php-mbstring php-soap php-xmlrpc php-zip
```

```
curl -sS https://getcomposer.org/installer | php
```

```
sudo mv composer.phar /usr/local/bin/composer
sudo chmod +x /usr/local/bin/composer
source ~/.bashrc
```
確認
```
composer -v
```
Kubernetesの作成済みPodのspecをjqコマンドで吐き出す。

spec とは、オブジェクト定義の親階層的な感じです。

https://kubernetes.io/ja/docs/concepts/overview/working-with-objects/kubernetes-objects/

では、まずPodの確認から。

```
yusuke@mbp kubernetes % kubectl get pod                                  
NAME         READY   STATUS    RESTARTS   AGE
nginx-yaml   1/1     Running   0          18m
```
次に、specの内容をjqコマンドで吐き出します。
```
yusuke@mbp kubernetes % kubectl get pod nginx-yaml -o jsonpath="{.spec}" | jq
{
  "containers": [
    {
      "image": "nginx",
      "imagePullPolicy": "Always",
      "name": "nginx",
      "resources": {},
      "terminationMessagePath": "/dev/termination-log",
      "terminationMessagePolicy": "File",
      "volumeMounts": [
        {
          "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
          "name": "default-token-9lsqm",
          "readOnly": true
        }
      ]
    }
  ],
  "dnsPolicy": "ClusterFirst",
  "enableServiceLinks": true,
  "nodeName": "docker-desktop",
  "preemptionPolicy": "PreemptLowerPriority",
  "priority": 0,
  "restartPolicy": "Always",
  "schedulerName": "default-scheduler",
  "securityContext": {},
  "serviceAccount": "default",
  "serviceAccountName": "default",
  "terminationGracePeriodSeconds": 30,
  "tolerations": [
    {
      "effect": "NoExecute",
      "key": "node.kubernetes.io/not-ready",
      "operator": "Exists",
      "tolerationSeconds": 300
    },
    {
      "effect": "NoExecute",
      "key": "node.kubernetes.io/unreachable",
      "operator": "Exists",
      "tolerationSeconds": 300
    }
  ],
  "volumes": [
    {
      "name": "default-token-9lsqm",
      "secret": {
        "defaultMode": 420,
        "secretName": "default-token-9lsqm"
      }
    }
  ]
}
```
細かく定義したものではないのでs、
ほとんどがデフォルト値です。
以上。
API Gatewayで公開したアプリをCloudFront経由でアクセスする

# 前提

[Amazon FargateのアプリケーションをAPI Gateway経由で公開する](https://qiita.com/ykdevs/items/fa84ec68491d2e1273e7)
で公開したAPI GatewayにCloudFrontを設定する。

# CloudFrontでディストリビューションを作成する

オリジンにAPI Gatewayのパスを設定する。

![スクリーンショット 2022-08-08 22.10.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81113/05f3c151-d313-790f-3667-0efdee35a27a.png)

![スクリーンショット 2022-08-08 22.10.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81113/12600a9e-b750-0ad6-aa1e-8f00740a2e18.png)

![スクリーンショット 2022-08-08 22.11.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81113/94f8dbd9-de33-aac7-da21-77b1a9d6a406.png)

# 確認

ディストリビューションドメイン名にアクセスしてみる。

![スクリーンショット 2022-08-08 22.16.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81113/b37f39d4-8fe4-c35a-b36e-e85f0e470136.png)

![スクリーンショット 2022-08-08 22.16.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81113/b5412c0a-1d71-f488-64db-b3d35ebcc83d.png)
Firestoreへのアクセス(アプリ、フロントエンド、バックエンド)

すでに同じような内容の記事もありますが、自分の中で整理したときのメモ。
相変わらず、公式ドキュメントを読んでもわかりづらい。。

■アプリから
・REST APIを使う。OAuthによる制御が必要。[API](https://firebase.google.com/docs/firestore/reference/rest/v1beta1/projects.databases.documents/patch)
・Firestoreへのアクセス制限は、Firestoreのセキュリティルールとユーザ認証とをセットで
・ユーザに認証操作をさせたくないケースのときは、Firebaseの匿名認証を使うのが楽

■フロントエンドから
・firebase/firestoreライブラリを使う
・Firestoreへのアクセス制限は、Firestoreのセキュリティルールとユーザ認証とをセットで
・ユーザに認証操作をさせたくないケースのときは、Firebaseの匿名認証を使うのが楽

■バックエンド(Cloud Functionsなど)から
・firebase-adminライブラリ(Admin SDK)を使う
・Firestoreへのアクセス制限はバックエンドがする
・バックエンドへのアクセス制限は、フロントエンドにてユーザ認証で入手したトークンをバックエンドが検証する方法で。[サンプルソース](https://github.com/firebase/functions-samples/tree/main/authorized-https-endpoint)
・Firestoreのセキュリティルールは全部拒否(それでもバックエンドはadmin権限なので全アクセス可能)

![3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726391/a5bbf5be-6003-aabb-4064-5f7a594f6bde.jpeg)


注意事項としては、Firebaseプロジェクトの情報(api keyなど)は、秘密情報ではなく普通に他人に見れてしまいます。なので、バックエンドなしでデータを守る場合は、Firestoreのセキュリティルールに完全に頼ることになります([参考](https://firebase.google.com/docs/projects/api-keys))。
これが心配な場合は、バックエンドを導入してバックエンドでFirestoreへのアクセス制限をかけつつ、さらにバックエンドへのアクセスについては、フロントエンドとバックエンド間の認証で守ることにしたほうが良さそう(フロントエンドでユーザ認証→トークン取得→バックエンドへトークン渡す→バックエンドでトークン検証。それでも不安なら追加の仕組みを入れる)。

間違っていたら指摘お願いします。。

# 参考
[https://zenn.dev/phi/articles/firebase-auth-be-sign-in-anonymously](https://zenn.dev/phi/articles/firebase-auth-be-sign-in-anonymously)
[https://blog.flatt.tech/entry/firebase_authentication_security](https://blog.flatt.tech/entry/firebase_authentication_security)
KubernetesでPodを作成してみた

KubernetesのPodを作成する方法です。
まず、vi でyamlファイルを作成します。

```
yusuke@mbp kubernetes % vi pod1.yaml
```

```
apiVersion: v1
kind: Pod
metadata:
  name: nginx-yaml
spec:
  containers:
    - image: nginx
      name: nginx
```

上記の記載が終わったら、kubectl createコマンドで実行します。
```
yusuke@mbp kubernetes % kubectl create -f pod1.yaml
pod/nginx-yaml created
```

createと出たので、成功ですね。
getコマンドで、podが作成されたことを確認します。
```
yusuke@mbp kubernetes % kubectl get pod            
NAME         READY   STATUS    RESTARTS   AGE
nginx-yaml   1/1     Running   0          5m34s
```

また、下記のコマンドで一発作成する方法もあります。
```
yusuke@mbp kubernetes % kubectl run ngnx --image=nginx
```
こっちの方が一般的なのかな。
以上。
【zsh-abbr】alias もいいけど abbr も使ってみませんか？

# 初めに
みなさん、alias 張ってますか？便利ですよね。
今回はその強化版と言っても良い、 `abbr` の紹介をしたいと思います。

# ３行まとめ
* abbr は コマンドを展開してくれる alias のようなもの
* fishに実装されてる
* zshの人は https://github.com/olets/zsh-abbr を入れよう

# abbr とは
実行時に元のコマンドに展開される alias のようなものです。
abbr という名前は、 `略語` の意味を持つ `abbreviation` からきています。
この機能は fish shell に実装されています。

例えば、alias を使って、`git`コマンドに対して以下のような設定をしている方は多いと思いますが、

```bash
alias g='git'
```

abbrでも同じように設定できます。

```bash
abbr -a -g g git
```

aliasと同じじゃん？と思われるかもしれませんが、少し挙動が違います。
試しに `g` と打ってエンターを押すと、`git`と同じ動作をするのはもちろんのこと、ログには展開後の `git` として記録されます。

![output-abbr1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263988/9456bbb0-b070-a583-eb35-7be257923a82.gif)


`gis status` のような、引数やサブコマンドを取るコマンドにも使えます。

![output-abbr2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263988/02933a03-b234-2751-8116-c6d96325fbc5.gif)

このような abbr の挙動には、以下の３つのメリットがあると言えます。

* alias と同様、タイプ数の削減ができる
* 他の人に画面を見せるときに、何のコマンドを打っているのか正確に伝えられる
* 自分が打っているコマンドは何なのか、正確に把握できる

fish shellの機能である abbr ですが、外部のパッケージをインストールすることで、bash　や zsh などの別のシェルでも使うことができます。

# zsh-abbr とは
fish shellに実装されている abbr を、zshでも使用できるようにしたものです。

https://github.com/olets/zsh-abbr


# zsh-abbrのインストール
homebrewでインストールできます。それ以外の方法はREADME.mdを参照してください。

```zsh
brew install olets/tap/zsh-abbr
```


# abbr を使ってみよう
今回はzsh-abbrをインストールした状態で、 `~/.zshrc` に設定を書き込み、 alias と同じように abbr の設定をしてみましょう。

一例として、私の abbr の設定の一部を載せておきます。


```~/.zshrc
abbr -S l='exa -F'
abbr -S ll='exa -Fl'
abbr -S la='exa -Fa'
abbr -S lla='exa -Fla'
abbr -S v='vim'
abbr -S g='git'
abbr -S b='bat'
abbr -S venv='source venv/bin/activate'
abbr -S ra='rails'
abbr -S gr='grep'
abbr -S k='kubectl'
abbr -S t='tmux'

# docker
abbr -S d='docker'
abbr -S dps='docker container ls'
abbr -S dimgs='docker image ls'
abbr -S drun='docker container run'
abbr -S dcd='docker compose -d'

# git
abbr -S ga='git add'
abbr -S gacm='git add -A && git commit'
abbr -S gst='git status'
abbr -S gbr='git branch'
abbr -S gcm='git commit'
abbr -S gco='git checkout'
abbr -S gdf='git diff'
abbr -S gl='git log'
abbr -S ggr='git grep'
abbr -S gul='git pull'
abbr -S gsw='git switch'
abbr -S gush='git push'
abbr -S gget='ghq get'
```

どうですか？うまく動かせましたか？

## 補足
zsh-abbrでは、-S オプションを使うと alias と似たような形で abbr の設定ができます。

> Use the --session or -S scope flag to create session abbreviations. Otherwise, or if the --user or -U scope flag is used, the Git abbreviations will be user.

https://github.com/olets/zsh-abbr#:~:text=To%20add%20a%20session%20abbreviation%2C%20use%20the%20%2D%2Dsession%20or%20%2DS%20scope%20flag.%20Otherwise%2C%20or%20if%20the%20%2D%2Duser%20or%20%2DU%20scope%20flag%20is%20used%2C%20the%20new%20abbreviation%20will%20be%20available%20to%20all%20sessions.

# 参考
https://girigiribauer.com/tech/20200420/

https://fishshell.com/docs/current/cmds/abbr.html
James Cloosとは何か【jhcloos】

https://github.com/jhcloos/

jhcloosさんがみなさんのレポジトリを見守ってくれているようです。GitHub公式のアカウントだと思います。

jhcloosさんが開発中のプロジェクトを紹介します。

# flashrom

https://www.flashrom.org/Flashrom

flashromはオンボードじゃないプログラマーではSPI,パラレル,LPC,FWHの焼き方に対応しているが、SPIのサポートがもっとも多いデバイスです。

# xpdf

http://www.xpdfreader.com/

Xpdf は、無料の PDF ビューアおよびツールキットで、テキスト エクストラクタ、画像コンバータ、HTML コンバータなどを備えています。ほとんどのツールはオープン ソースとして利用できます。

# Little-CMS

https://www.littlecms.com/

WordPressのような商用ではなくオープンソースなCMSで軽量です。LxQTでなじみLubuntuでも使うLxQtが使用されています。


# resiprocate

http://www.resiprocate.org/

reSIProcate コンポーネント、特に SIP スタックは、商用製品とオープンソース製品の両方で使用されています。このプロジェクトは、SIP といくつかの関連プロトコルの完全で正確な商用利用可能な実装を維持することに専念しています。

## reSIProcate を選ぶ理由
* 広範なトランスポート: UDP、TCP、TLS、DTLS、そして現在 [[ WebRTC-and-SIP-Over-WebSockets | WebRTC 用の WebSocket (WS/WSS) ]]
* 柔軟性: reSIProcate を低レベルの SIP 解析 API、ダイアログ管理用の中レベル API、または会話管理用の高レベル API として使用/ソフトフォン、PBX、および B2BUA を迅速に開発 - [[プラグイン| C++ と Python を使用したプラグインのサポートも]]
* 深さ: OUTBOUND、Identity などの機能を含む、多くの SIP 関連の RFC を幅広くカバー
* Linux、Windows、FreeBSD、Mac OS、Android、iPhone などの複数のプラットフォーム
* 主流の x86 チップセット、Itanium、PowerPC、MIPS、ARM、S/390 などを含む複数の CPU をサポート ([ここ](https://buildd.debian.org/status/package.php?p=resiprocate) を参照)
* 寛大な BSD ライクなライセンス条項
* 複数のプラットフォームのすべてのリリースで検証された数千のテスト ケース
* 一流の C++: OO-design を使用してニーズに合わせて理解しやすく拡張可能
* Debian、Fedora、Ubuntu、その他のプラットフォームで利用できる便利なパッケージ
バージョン管理についてのあれこれ

# はじめに
私たちの身の回りにはたくさんのバージョンが存在します。
例えば次のようなものです。
- Windows11
- iOS 15.6
- GitHub API v4

「数字が上がれば最新バージョンだろう」くらいにしか知りませんでした。
この記事では、**これらの数字がどんな意味を持つのか**まとめていきたいと思います！



# セマンティックバージョニング
**セマンティックバージョニング**とは、バージョンの割り当て方の一つです。
参考：https://semver.org/lang/ja/

セマンティックバージョニングでは、例えば**1.2.3**のように、3つの数値をドットで繋いでバージョンを表します。
1.2.3の数字の部分をそれぞれ**X.Y.Z**と表すとするとそれぞれの数字の意味は以下の表のように分けられます。

| 位置 | 名前 | 用途 |
|:-|:-|:-|
| X  | メジャーバージョン  | 後方互換性のない変更が行われた際に増える  |
| Y  | マイナーバージョン  | 後方互換性のある機能変更、あるいは特定の機能が今後廃止されることが決まった場合に増える  |
| Z  | パッチバージョン  | 後方互換性を保ったバグ修正を行ったときに増える  |

※後方互換性：新しいバージョンにしたときに古いバージョンで使えていた機能が利用できるということ

この表のように意味を振り分けてバージョン管理していく方法をセマンティックバージョン管理といいます。

# バージョン管理の例を見ていく
それでは、セマンティックバージョニングを基にして、「はじめに」で例にあげた3種類のバージョンについてそれぞれどんな意味を持っているか見ていきましょう。

## Windows
WindowsにはWindows10やWindows11などがありますが、これらはWindowsのバージョン情報の一部を表しています。
正しくは、**"バージョン番号：10.0（バージョン21H2）　ビルド番号：22000"** のように表します。

バージョン番号がセマンティックバージョニングで言う、メジャーバージョン、ビルド番号がマイナーバージョンorパッチバージョンを表します。

実は、Windows 10 November 2021 Update	とWindows11のバージョン番号は変わっていないので、大きな変化は少ないと考えられます！

## iOS
iOSではiOS15.6やiOS15.5.3といったバージョン表記があります。iOSでは、**セマンティックバージョニングを基に**バージョン管理がなされています。
例えば、iOS15.5.3であれば、15がメジャーバージョン、5がマイナーバージョン、3がパッチバージョンを表します。
iOS15.6であれば、15がメジャーバージョン、6がマイナーバージョンを表します。


## API
Githubなど多くのAPIでは、**v3**や**v4**のようにバージョンを表します。

このvの後に来る数字がメジャーバージョンを表しています。また、APIではマイナーバージョン以下は表さないものが多いです。

APIでは基本的に、**後方互換性のある変更ではバージョンを上げません**。これは、複数のAPIのバージョンをメンテナンスするのはコストがかかりますし、利用者側から見ても分かりにくいからです。
そのため、後方互換性を失っても良いと判断できるほどの本当に大きな変更を行いたい時にのみ、バージョンを上げます。


# まとめ
この記事では、セマンティックバージョニングを基に、バージョン管理についてまとめました。
基本的な考え方を理解できれば、バージョン管理の数字の意味がわかってくるかと思います！

**これで君もバージョン強者！**
GASでGmailをLINEに自動転送する


## 直近１時間に受信したGmailをLINEに自動転送するスクリプト(GAS)
関数mainを1時間おきのトリガーで設定すればok :ok_hand:

```
const LINEToken = "xxxxxxxx"; //LINE notify token

function main() {
  try {
    const messageList = getMessageListLastOneHour();
    for(let i = 0; i < messageList.length; i++) {
      sendToLINE(messageList[i]);
    }
  } catch(error) {
    Logger.log(error);
  } 
}


//検索対象にしたい送信元メールアドレスリスト(任意)
function getTargetFromEmailList() {
  return [
    'xxx@xxx',
  ];
}  

//直近１時間に受信したメールを検索して取得する
function getMessageListLastOneHour() {
  //検索条件
  let searchString = '(newer_than:1h';
  const fromEmailList = getTargetFromEmailList();
  if (fromEmailList.length > 0) {
    searchString += 'from:' + fromEmailList.join(' OR from:');
  }
  searchString += ')';
 
  //取得
  const myThreads = GmailApp.search(searchString);
  const myMsgs = GmailApp.getMessagesForThreads(myThreads);
  let targetMsgs = [];
  for(let i = 0; i < myMsgs.length;i++){
    const message = myMsgs[i].slice(-1)[0];
    targetMsgs[i] = " " + (message.getDate().getMonth()+1) + "/"+ message.getDate().getDate()
    + " " + message.getDate().getHours() + ":" + message.getDate().getMinutes()
    + "\n[from]" + message.getFrom()
    + "\n\n[subject]" + message.getSubject()
    + "\n\n[body]" + message.getBody(); 
  }

  return targetMsgs;
}

// LINEに転送する
function sendToLINE(message) {
  const payload = {'message' : message};
  const options ={
    "method"  : "post",
    "payload" : payload,
    "headers" : {"Authorization" : "Bearer "+ LINEToken}  
  };
  UrlFetchApp.fetch("https://notify-api.line.me/api/notify", options);
}

```

## こんな感じ
![IMG_6F68821DC7D9-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83896/56a214fb-4cb6-064e-8379-102cc2ead7b6.jpeg)




## 参考
[メールをラインに転送する方法! iPhone/AndroidのGmailを自動でLINEに通知しよう](https://sp7pc.com/gadget/line/23926)
【Rails6】Initialization autoloaded the constants ApplicationHelper を解消する

# 初めに

Rails6 で Rspec を稼働させると`DEPRECATION WARNING`が出るので、それを解決します。

# 解決方法

## エラー内容

以下のエラーが発生しました。

```console
DEPRECATION WARNING: Initialization autoloaded the constants ApplicationHelper,DeviseHelper、ApplicationController、
DeviseController、Devise::SessionsController、Devise::PasswordsController、Devise::UnlocksController、Devise::RegistrationsController、
Devise::ConfirmationsController.

Being able to do this is deprecated. Autoloading during initialization is going
to be an error condition in future versions of Rails.

Reloading does not reboot the application, and therefore code executed during
initialization does not run again. So, if you reload CustomErrors, for example,
the expected changes wont be reflected in that stale Module object.

These autoloaded constants have been unloaded.

In order to autoload safely at boot time, please wrap your code in a reloader
callback this way:

    Rails.application.reloader.to_prepare do
      # Autoload classes and modules needed at boot time here.
    end

That block runs when the application boots, and every time there is a reload.
For historical reasons, it may run twice, so it has to be idempotent.

Check the "Autoloading and Reloading Constants" guide to learn more about how
Rails autoloads and reloads
(called from <top (required)> at /coffee-oma/config/environment.rb:5)

```

config/initializers から`Controllerクラス`などを呼び出しでエラーが発生します。

## 解決例

まずは、どのファイルから呼び出されているかを確認する必要があります。

今回は`ApplicationHelper`に`pp caller_locations`を使い、どのファイルで呼び出されているかをコンソールに出力させます。

```ruby:application_helper.rb
module ApplicationHelper
  pp caller_locations.select { |l| l.to_s.index("config/initializers") }
  # 以下省略
end
```

これでコンソールに呼び出されたファイル名が出力されるので、そのクラスを`Rails.application.reloader.to_prepare`でラップさせると解決できます。

```ruby:config/initializers/devise.rb
Rails.application.reloader.to_prepare do
  ActiveAdmin::Devise::SessionsController.class_eval do
    def after_sign_in_path_for(resource)
      if resource.is_a?(AdminUser)
        admin_root_path
      else
        root_path
      end
    end
  end
end
```

# 参考

- [Rails 6 に上げると”DEPRECATION WARNING: Initialization autoloaded the constants”のような警告が出る - Qiita](https://qiita.com/jnchito/items/b8f40e7fe82b07bc3de8)
- [定数の自動読み込みと再読み込み (Zeitwerk) - Rails ガイド](https://railsguides.jp/autoloading_and_reloading_constants.html)
.env などにある環境変数を[一括で|まとめて] パラメーターストアに登録するスクリプトを書いたよ

## 環境変数を追加するのが面倒

パラメーターストアに環境変数をぽちぽち登録するのが苦行で仕方がありませんでした。
12個ぐらい一気に追加されると、それをポチポチすると5-10分かかってしまいます。
そこで、慣れないシェルスクリプトをつかって一括登録できるようにスクリプトを書きました。
慣れないので2時間ぐらいかかりました。笑

## 前提

AWS CLI が必要です。

## シェルスクリプト


``` put_env.sh
#!/bin/bash

## Default値
profile='default'
data_type='String'
desc='from post_envs.sh'
prefix=''
##

function usage {
  cat <<EOM
Usage: $(basename "$0") [OPTION]... filename
  -h Help    	  Display usage.
  -a Prefix       Prefix of parameter store's key.
  -d Description  Parameter Description.
  -t Data Type    Data type of parameter store. Default value is "String".
  -p Aws Pofile   Default value is "default". 
EOM

  exit 2
}

echo $@
while getopts ":a:d:p:t:" optKey; do
  case "$optKey" in
    a)
      prefix=${OPTARG}
      ;;
    d)
      desc=${OPTARG}
      ;;
    p)
      profile=${OPTARG}
      ;;
    t)
      data_type=${OPTARG}
      ;;
    '-h'|'--help'|* )
			usage
      ;;
  esac
done

# オプションとその値のかずだけ引数配列からshiftさせる
shift $(($# - 1))

if [ "$1" != "" ]; then
  filename=$1
fi

if [ "$filename" = "" ]; then
	echo "\n[missing argv error] missing argv filename.\n"
  usage
fi

cat ${filename} | while read line
do
  key=`echo ${line} | cut -d '=' -f 1 | grep -v '^\s*#'`
  val=`echo ${line} | cut -d '=' -f 2`
	if [ "$key" != "" ]; then
		echo "[sending...] ${prefix}${key}=${val}"
		aws ssm --profile ${profile} put-parameter --name "${prefix}${key}" --value "${val}" --type ${data_type} --description "${desc}"
	fi
done

```

## 使用例

例えば、環境変数をまとめて以下のようなファイルがあったとします。

``` .env-to-post
# hogeにつかう
HOGE=hoge
# fugaにつかう
FUGA=fuga

```

その場合は、

```
sh put_env.sh .env-to-post 
```
で登録できます。

## オプション

| オプション | 備考 |
| --- | --- |
|-a|パラメータのキーにプレフィックスをつけることができます。|
|-d|パラメータの説明分を指定できます。一括で同じものになります。|
|-p|AWS CLI のプロファイル名です。|
|-t|パラメータのタイプです。String以外にもSecureStringなどがあります。|

## コメント

せっかく作ったので、どなたかの参考になったら **幸甚の至り** です。
シェルスクリプト筋がか細いので、シェルスクリプトつよつよの方がいたら改善案等お待ちしております :bow:
Mac上でpipで入れたパッケージが何をしても動かなかったのを解決した話

# 誰向け？
MacでHomebrewを使っていて、pipで入れたパッケージがうまく動かない人向け。

# 状況
pip3で入れたはずのパッケージがどうしてもcommand not foundになる。

`python3 -m pip install <パッケージ名> —user`
とかやってもダメ。

```
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: chalice in ./Library/Python/3.8/lib/python/site-packages (1.27.1)
…
```
と出るし、インストールはされているがMac側がうまく参照できていないっぽい。

# 結論

__homebrewをインストール後にpython3やpip3をインストールしなおしていなかった__

(brewでアレコレと入れていたもののpython3やpip3はデフォルトのものを使っていたことになり、PATHがおかしなことになっていたらしい)

# 回復方法
## 今使っているpythonはどこのもの？

おそらくデフォルトのpython3やpip3をつかっていた人はwhichコマンドを使うと

`which python3` →　`/usr/bin/python3`
`which pip3` → `/usr/bin/pip3`

となっていると思う。これは __MacデフォルトのPythonのPATH__。

`brew install python3`

とターミナルに打ち込み、完了すると

- 新しくインストールし直されたpython
- 新しくインストールし直されたpip
- 今後pipでインストールするものの場所

のPATHが表示されるので、メモしておく。

## PATHを書き換えるには
最近のMacではデフォルトのシェルがzshになっている。

そこでホームディレクトリ(Finder→移動タブ→ホーム で表示されるディレクトリ)で[command]+[shift]+[.(ドット)]キーを押すことで隠しファイルを表示する。
.zshrcファイルがPATHの設定ファイルなのだが、存在しないこともある。

その場合はターミナル上でホームディレクトリに移動した上で

`touch .zshrc`

をしてサクッとつくっておこう。

エディタでもvimでもいいのでとりあえず.zshrcファイルを開き、
```.zshrc
# Python3
export PATH="$PATH:/usr/local/bin/python3"
# installed by pip3
export PATH="$PATH:/usr/local/lib/python3.9/site-packages"
```
と追記し、保存。ここは筆者の環境で表示されたPATHを記載しているが、これはそれぞれの環境に合わせて変更してほしい。

その後ターミナルで
`source ~/.zshrc`
と打ち込んで状態を更新しておく。

# 脱線 - コマンドがpythonだったりpython3だったりややこしい

python実行コマンドが環境によってpythonだったりpython3だったりする。本当になんで？
pythonと打ってpython3を実行できるようにできないものか。

これも.zshrcファイルに設定を追加しておくことでなんとかできる。

.zshrcファイルを開き、
```.zshrc
alias python="python3"
alias pip="pip3"
```
と書き込み、保存。

ターミナルで
`source ~/.zshrc`
として更新しておく。

# PATHが変更できたか確認
ターミナルを再起動し、
`which python3`
を実行して変更した通りのPATHになっているかを確認する。

変更が確認できれば、
`pip install <パッケージ名>`
を実行する。

# 完了
上記の方法で筆者はchalice(AWSのフレームワーク)のインストールを完了できました。

Mac環境でPATHを通し間違えたときは[こちら](https://qiita.com/1plus1is3/items/0f04b76fb3f011610fa0)
VBAで定数配列もどきを作る

## VBAでは定数の配列は宣言できない

VBAでは定数の配列は宣言できない（エラーになる）のですが、代わりに定数配列もどきを作る方法を思いついたので、書き留めたいと思います。
はじめに、定数配列の代わりとして一般的に使われている方法を2つ紹介して、最後に定数配列もどきの作り方を紹介します。

結論を言うと、いずれも一長一短があり、ベストな方法はなさそうです。

## 方法①：Split関数を使う方法

「VBA 定数 配列」などで検索すると出てくる方法です（※他の方の記事を参考にしました）。

__コード__

``` vb
Const CONST_STR_ARRAY As String = "HELLO,HI,HEY"

'main
Public Sub main()
    Dim i As Long
    Dim STR_ARRAY As Variant

    STR_ARRAY = Split(CONST_STR_ARRAY, ",")

    For i = 0 To 2
        Debug.Print STR_ARRAY(i) & " WORLD!"
    Next i
End Sub
```

__出力__

``` sh
HELLO WORLD!
HI WORLD!
HEY WORLD!
```

> __短所：再代入できる__
> 
> 実体は配列なので再代入できてしまいます。
> これでは、定数配列とは言えません。
> 
> ``` vb
> STR_ARRAY(2) = "NEW"
> ```

## 方法②：Array関数を使う方法

こちらも「VBA 定数 配列」などで検索すると出てくる方法です（※他の方の記事を参考にしました）。

__コード__

``` vb
'main
Public Sub main()
    Dim i As Long
    Dim STR_ARRAY As Variant

    STR_ARRAY = Array("HELLO","HI","HEY")

    For i = 0 To 2
        Debug.Print STR_ARRAY(i) & " WORLD!"
    Next i
End Sub
```

__出力__ （※前回と同じ）

``` sh
HELLO WORLD!
HI WORLD!
HEY WORLD!
```

> __短所：再代入できる__
> 
> 実体は配列なので再代入できてしまいます。
> これでは、定数配列とは言えません。
> 
> ``` vb
> STR_ARRAY(2) = "NEW"
> ```

## 方法③：Functionプロシージャを使う方法

定数配列もどきを紹介します。
これは、配列と`Function`の書き方が似ている（どちらも丸括弧を使う）を利用した方法です。
実体は`Function`なのに、まるで配列のように見えます。

__コード__

``` vb
'定数配列もどき
Private Function STR_ARRAY(index) As String
    Select Case index
        Case 0
            STR_ARRAY = "HELLO"
        Case 1
            STR_ARRAY = "HI"
        Case 2
            STR_ARRAY = "HEY"
        Case Else
            Error 9 'インデックスが有効範囲にありません。
    End Select
End Function

'main
Public Sub main()
    Dim i As Long

    For i = 0 To 2
        Debug.Print STR_ARRAY(i) & " WORLD!" '定数配列のように見える
    Next i
End Sub
```

__出力__ （※前回と同じ）

``` sh
HELLO WORLD!
HI WORLD!
HEY WORLD!
```

> __短所：配列関連の関数が使えない__
> 
> - 配列だと使える関数が使えません（※かなり不便）
>     - `LBound`
>     - `UBound`
>     - `IsArray`
> 
> __短所：［ウォッチ式の追加］が利用できない__
> 
> - 追加までは出来るのですが、値欄には`<ウォッチ式が不正です。>`と表示されます。

## 番外編：Evaluateメソッドを使う方法

コメント欄で、`Evaluate`メソッドを使う方法を紹介して頂きました。（勝手に紹介してスミマセン...）。
この方法は配列の添字（インデックス）が1から始まる点に注意が必要です。

ちなみに`Evaluate`メソッドとは、ワークシートの数式をVBAで実行する場合に用いるものです。
`Evaluate`メソッドには、`[]`で囲む簡略化した書き方も用意されていて、どちらで書いても同じ意味です。

__コード__

``` vb
'main
Public Sub main()
    Dim i As Long
    Dim STR_ARRAY As Variant

    STR_ARRAY = [{"HELLO","HI","HEY"}]
    'Evaluateメソッドを使った書き方（同じ意味）
    'STR_ARRAY = Evaluate("{""HELLO"",""HI"",""HEY""}")

    For i = 1 To 3
        Debug.Print STR_ARRAY(i) & " WORLD!"
    Next i
End Sub
```

__出力__ （※前回と同じ）

``` sh
HELLO WORLD!
HI WORLD!
HEY WORLD!
```

> __注意：配列の添字（インデックス）は1から始まる__
> 
> `For`ループを`0`から始めると、`Debug.Print STR_ARRAY(0) & " WORLD!"`を表示するタイミングで、エラーが出ます。
> 
> ``` vb
>     For i = 0 To 2
>         '実行時エラー'9': インデックスが有効範囲にありません。
>         Debug.Print STR_ARRAY(i) & " WORLD!"
>     Next i
> ```
[C#]ForEach(System.Collections.Generic.List)はどうしてbreak・continueを使えないんだろう？

## はじめに

C#(.Net)でforeachを回す方法として、素直にforeachを使用する方法とSystem.Collections.Generic.ListのForEachを使う方法の2通りがあります。<br>

```cs
var hogeList = new List<int>();
//書き方1
foreach (var hoge in hogeList) {
    //処理
}

//書き方2
hogeList.ForEach(hoge => {
    //処理
});
```

書き方2の方はbreak・continueが使えず、returnを使うことでcontinue相当の処理をすることができます。
というのを人に説明しながら、**そもそも何でbreak・continueが使えないんだ？何でreturnを使うんだ？** ということが気になったので、このようになっている理由を確認します。

## ForEachの実装を確認
MicrosoftがSystem.Collections.Generic.Listのコードを公開しているので、以下からForEachの実装を確認します。

https://github.com/microsoft/referencesource/blob/master/mscorlib/system/collections/generic/list.cs

ForEachの実装部分を引用します。
```cs
public void ForEach(Action<T> action) {
    //略
    for(int i = 0 ; i < _size; i++) {
        //略
        action(_items[i]);
    }
    //略
}
```
引数部分を見てみると、Actionを渡していることがわかります。そしてそのActionをListの各要素に対して実行しています。つまり、書き方2の処理部分はforeachのループの中身ではなく、メソッドの一部を記述していることになります。
以上より、最初の問題を納得いく形で理解できるようになりました。
* 書き方2の処理部分はメソッドの一部であり、foreachの一部ではないため、break・continueを使用できない
* 書き方2の処理部分はメソッドの一部であるため、returnすることで処理を終了できる。この際、ForEachの実装としてはメソッドを各要素に対して実行しているだけなので、returnすることはその要素への実行の終了=continue相当となり、break相当のことができるような実装はない
サーバーサイドでKtor初学時に困ったこと

:::note warn
サーバーサイドでKtorを使って学習しましたので、
クライアントサイド使用の場合は別記事を参照した方がよいかと思います。
:::

Ktorをこの度はじめて学習したのですが、
参考にしているソースコード通りに書いてるのにうまく動かない・・・ということがいくつかあったので記事にまとめます。
(2022/08/08の情報なので、最新の情報とは限りませんのでご注意を！)

※ 自分は、Ktorのバージョンが1系と2系の違いで詰まったのがほとんどです。
以下にまとまっていました(あとで見つけた)

https://ktor.io/docs/migrating-2.html

## IntelliJでKtorのプラグインが見つからない

安心してください。同梱されてます。

## Ktorの新規プロジェクトの作成ができない

有料版でないとIDEからはできません。
Spring Initializrの要領で以下から作成できます。

https://start.ktor.io/

## なんかmain関数の雰囲気が違う

以下を参考に書きました。

https://jp.ktor.work/quickstart/index.html

## Locationsがうまくインストールできない

以下のように変更してうまく動きました

```build.gradle
dependencies{
  io.ktor:ktor-locations:$ktor_version // before
  io.ktor:ktor-server-locations:$ktor_version // after
}
```

## jacksonがうまくインストールできない

以下のように変更してうまく動きました

```build.gradle
dependencies{
  io.ktor:ktor-jackson:$ktor_version // before
  io.ktor:ktor-server-content-negotiation:$ktor_version // after
  io.ktor:ktor-serialization-jackson:$ktor_version // after
}
```

## authがうまくインストールできない

以下のように変更してうまく動きました

```build.gradle
dependencies{
  io.ktor:ktor-auth:$ktor_version // before
  io.ktor:ktor-server-auth:$ktor_version // after
}
```
データ前処理ってどうしてます？

## はじめに
データ分析の最初のステップは、データ準備 → 可視化 → データ概観 です。
現実データは乱れていたり、整っていないことが多いので、このステップの前に前処理を行わなければならない場合があります。
この前処理は、かなり手間を要します。乱れたデータを見を見た瞬間にあきらめている方も多いかもしれません。
 　
例えば、
- データに欠損値がある：通常 欠損値は「空白」ですが、わざわざある記号（"---"等）で識別している場合もある
- 異常データが混在している：数値データの中に文字データが混在している、通常はあり得ない数値や文字のデータがある
- 16進数の値のデータがある：16進数は数値ですがPythonは数値なのに文字と認識します。10進数に変換しないといけない。
- 「/区切り」で複数データが入力されたデータ：Excelのひとつのセルに”/”区切りで、複数データがインプットされていると表現するとわかっていただけると思います。


 　
これらへの対処は、順序も意識しないといけません。

- 16進数データがある場合、先に「文字データ」を除去すると（文字と認識される）16進数データはすべて除去されてしまいます。
- あるデータ列のみ欠損値がとても多い場合、「欠損値」を削除＝多くのデータを削除することになります。
　
　
（初心者なので）Pythonで前処理を実施するだけでも大変なのに、処理する順序にも気を配らないといけませんので、なかなか大変です。
確実かつ丁寧にやるならPythonではなくてEXCELで対応すればいいんじゃないか・・・　これもカラム数が多いとやってられませんので、なんとか効率よくやりたいんですよね。
「すべての欠損データや異常データは捨てる」と割り切れば、すこしは楽になれるのですが。。。諦めたら負けです。
　
　
  　
そこで、以下3パターンの前処理をPythonで実行してみることにしました。

- ① すべてのデータを生かすため、異常データを-99、Nanを-1に置換
- ② すべてのデータのうち、異常データだけを-99に置換、Nanはそのまま
- ③ 異常データ、Nanデータをすべて削除

***

※Pythonでの前処理は、以下記事でも触れています。

https://qiita.com/hima2b4/items/6a490f6d9527221da6f1

## 実行条件など
>- **Google colab**で実行
>- 任意のデータUploadだけではなく、機械学習データセット Boston_housing :regression / Diabetes :regression / Breast_cancer :binary / Titanic :binary / Iris :classification / Loan_prediction :binary も実行できるようにしています。
>- 実行コードは以下

https://colab.research.google.com/github/hima2b4/Auto_Profiling/blob/master/Data_Preprosessing_V3.ipynb



## 実施したデータ前処理の内容と順序
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1275001/bbf5d0ac-62f6-2e97-dd9d-4eed28c5479f.png)


## データ前処理における悩み

### 1. **異常データと欠損値は消したくない**

例えば、検査データの場合、検査NGデータには必ず欠損値があります。
NGとなった時点で検査は停止し、停止以降の検査は実行されないからです。
「欠損値があるデータ行は除く」ということを行うと、検査NGデータの多くを捨ててしまうことになります。
また、異常データも同様です。「数値カラムに文字が混在している」等のデータを異常データと認識していますが、これに傾向があれば検査NGの原因に近づけるかもしれません。データを消してしまえば この可能性も消してしまうことになります。

では、「異常データと欠損値は残せばいいじゃん」ということなのですが、異常データは数値カラムに混在した文字、欠損値も「---」等で識別されている場合があり、数値に置換するなど適切に処理しないと、該当カラムは数値として扱うことができません。


### 2. **カラムには数値しか入力されていないのに文字認識されることがある**

intとfloatが混在しているとobject（文字）として認識されるようです。
先の異常データや欠損値の処理を行っただけでは安心できません。各カラムのデータ型を確認し、状態に応じ、データを適切な型に変える必要があります。


### 3. **カラム数が膨大である場合、データ前処理をカラム毎に行うのは面倒**

1カラムづつ処理を行うならば、EXCELで十分です。
Pythonで実行するなら、データセット全体に1アクションで処理を行えるようにした方が効率的です。
例えば以下のような処理です。

- 異常値やN.A.を指定数値に置換
- ラベルエンコードしない文字列は一気にカラムごと削除
- 分析で文字化けしないよう、カラムを英字に翻訳

objectラベルは、一気にラベルエンコードするか否かで迷いましたが、エンコードするカラムを個別に指定、指定しなかったカラムはまとめて削除としました。

## 最後に

データ前処理は単純なようで、単純ではないところがあります。
データセットが「欠損なし、すべて数値」という場合は可視化に直行できますが、現実は甘くありませんね。


## 参考

https://stackoverflow.com/questions/54444260/labelencoder-that-keeps-missing-values-as-nan
【#48 エンジニア転職学習】VirtualBoxを使用したLinux開発環境

# はじめに
富山県に住んでいるChikaといいます。
毎日投稿を目標に、バックエンドエンジニア転職に向けた学習内容をアウトプットします。

簡単なアプリケーション開発を続けていきますが、
その前にLinuxの開発環境を整えようと思います。

バックエンドエンジニアになるまでの学習内容は以前投稿した以下の記事を基にしています。


https://qiita.com/Chika110/items/ef54dddd565a0193ef44

# 本日の学習内容
VirtualBoxを使用したLinuxの開発環境を作成しました。
* **VirtualBoxを使用したLinuxの開発環境　参考記事まとめ　←Topics!!**


# VirtualBoxを使用したLinuxの開発環境　参考記事まとめ
ベースはLinux基礎学習のときに使用した「VirtualBox」上でのCentOS7になります。
現状PCで使用しているツールを使えるようになることを目標にしました。
* VMwear　：Oracle VirtualBox 6.1.36
* Linuxディストリビューション　：CentOS7
* IDE　：VSCode
* 他インストールしたツール等：
    * Go言語
    * MySQL8.0
    * Git最新版
    * Google Chrome
#### VirtualBoxの高速化
この設定で一気に処理等軽くなりました。
****[VirtualBoxの動作を高速化させるための設定](https://www.orzs.tech/virtualbox-acceleration/)****
#### GoogleChromeのインストール
****[CentOS7・CentOS8 Google Chromeをインストールする](https://rin-ka.net/centos-google-chrome-install/)****
#### Go言語のインストール
****[Centos7 go言語をインストールして実行する](https://mebee.info/2020/08/04/post-15855/)****
#### VSCodeのインストール
****[VSCodeのインストール](https://www.xlsoft.com/jp/blog/blog/2021/06/18/post-19929/)****
#### Git最新版のインストール
デフォルトでGitは入っていますが、最新版に更新します。
****[Git – CentOS7への最新版のインストール](http://taustation.com/git-installing-latest-version-to-centos7/)****
#### MySQL8.0のインストール
****[CentOS7にMySQL8.0をインストール](https://qiita.com/zaburo/items/7518a432d915c061983f)****

****[[MySQL] アップデート時にGPGキーのエラーで停止してしまう場合](https://blog.katsubemakito.net/mysql/mysql-update-error-gpg)****

##### 使用している教材はこちら↓


https://go.dev/doc/tutorial/web-service-gin


# おわりに
最後までお読みいただきありがとうございました。
アドバイス・応援コメント等いただけますと幸いです。
ゲストのアクセス制限

## はじめに

ポートフォリオ製作で作成したゲストログイン機能に閲覧制限をかける際に悩んだのでメモとして残そうと思いました。

## ゲストログイン機能


```ruby
class Menber < ApplicationRecord
# ゲストユーザー
  def self.guest_user
    find_or_create_by!(email: 'guest_user@example.com') do |guest|
      guest.password = SecureRandom.urlsafe_base64
    end
  end
end
```

```ruby
class Admin::SessionsController < Devise::SessionsController
　def guest_log_in
    guest = Menber.guest_user
    sign_in guest   # ユーザーをログインさせる
    redirect_to root_path, notice: 'ゲストユーザーとしてログインしました。'
  end
end
```

## やりたいこと

本会員とゲストでアクセス制限を分けたい。

## やったこと

ヘルパーメソッドであるauthenticate_userメソッドを使用したいと考えましたが、使用しているゲストログイン機能だと内部的には本会員と同じ扱いを受けてしまっているので、区別するため新たに作成することにしました。

```ruby
#補足:作成時、既にゲストユーザーにはMenber id:１を渡してあります。
def guest_check
    if current_menber == Menber.find(1)
      redirect_to root_path,notice: "このページを見るには会員登録が必要です。"
    end
  end
```

制限をかけたいコントローラーに記述。

```ruby
# ゲストユーザーとしてログインした場合は閲覧を制限する
  before_action :guest_check
```

以上で終了です。

初学者のため、沢山の方にご教授いただきたいと思っております。

読んでいただきありがとうございました！

---
### authenticate_userについての参考文献

[https://qiita.com/gogotakataka1234/items/c7d5c0b3d8953216259e](https://qiita.com/gogotakataka1234/items/c7d5c0b3d8953216259e)
無駄な会議を減らす基本的・具体的な手順

# はじめに
会議が多すぎ・長すぎると、個人の作業時間が確保できず、業務スピード・品質に悪影響を及ぼす。
無駄な会議は可能な限り削減すべきであり、会議時間は必要最小限にとどめるべきである。

本ページでは、そのための具体的な方策を記述する。
※実現可能性を重視して、情報量を最小限にとどめている


# 前提(環境)
- Microsoft365を導入している
- MyAnalyticsが使える

# 1. 現状の定量化
何よりも最初にやるべきは「定量化」。
どれだけ自分が会議に時間を費やしているかについて、定量的に把握することが何よりも重要。
Microsoft365導入企業であれば、MyAnalyticsで簡単に定量化できる。

例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684495/1b1358f9-9cf0-de81-c845-e964b8b8edc6.png)

引用元

https://docs.microsoft.com/ja-jp/viva/insights/personal/use/collaboration


経験則では、コラボレーションの比率が30%以内に収まっていることが理想的。
※もちろん職種・役職によって会議時間比率の理想は変動すると考えられ、一義的に決めるのは難しい。


# 2. 原因分析
なぜ会議時間が長いのか？その原因を以下2つの観点から分析する。

## どんな種類の会議が多いのか？
一般的に、会議には以下4種類あると考えられる。
- ブレスト
- 意思決定
- 情報共有
- チームビルディング

任意の2～3週間を対象にして、どの会議に時間がかかっているのかを特定する。
「情報共有」に多くの時間がかかっていると、会議時間削減の可能性が高いと考えられる。


## 事前準備は十分か？
アジェンダが準備されている会議はどの程度あるか？
十分に準備されていない会議が過半数だと、会議時間削減の可能性が高いと考えられる。


# 3. 改善策立案
## 原因分析結果に応じて改善策を立案する
原因は人・組織でばらつきが大きく生じると考えられるので、画一的に改善策を提示すべきではない。
しかしながら、一定の例示があるとイメージしやすいと思うので、以下に例示する。


## 例：「情報共有」目的の会議時間を削減する
特に無駄な会議になりやすいのは「情報共有」。
「全社会議」「全体会議」として、ただ資料を棒読みするだけの会議は必要ない。
わざわざ全員同じ時間に集まることをせずに、わかりやすいドキュメントを作って配布すれば十分である。

※もちろん感情的納得感を醸成するために行う情報共有には一定の価値があるので、「情報共有目的の会議＝すべて不要」とは考えていない。

## 例：会議のタイトルに必ず会議の種類を記載する
タイトルの冒頭に会議の種類が記載されていることで、会議のゴール認識が統一しやすくなる。
例えば以下のようなイメージ。
- 【情報共有】●●●について、詳細情報を共有する
- 【意思決定】A事業の人員計画を決定する
- 【ブレスト】新規事業Bのアイデアを出す


## 例：アジェンダ準備を徹底する
事前に文書化されていることで、主に以下のようなメリットがある。
- 会議前に参加要否を判断可能
- 会議が必要なく、チャットで完結できるような用件のときに、それを事前に検知できる
- 深度ある議論が可能になる

なお、アジェンダは編集作業コストの小さいツールで作成すべきである。
具体的には、PowerPointやGoogleスライドのようなスライド作成ツールを避けて、OneNoteやNotionを使用すべきである。


# おわりに
会議の生産性向上に関する情報は、現代であれば簡単にキャッチアップ可能。
しかしながら、いまだに無駄な会議に苦しんでいる企業・従業員はまだまだ多いと想像する。




# 参考文献
https://www.amazon.co.jp/dp/4799326082

https://www.amazon.co.jp/dp/4413231112

https://toyokeizai.net/articles/-/460955

https://learn.gitlab.com/c/gitlab-presentation-developers-summit?x=JBqxmQ

https://xtrend.nikkei.com/atcl/contents/18/00447/00007/
heapを使ったダイクストラ法の計算量について考える


# はじめに
タイトルにもある通り、heapを使用したダイクストラ法の計算量について考えてみます。
ダイクストラ法について知らない方は[こちら](https://products.sint.co.jp/topsic/blog/dijkstras-algorithm)などが分かりやすいです。
heapについて知らない方は[こちら](https://medium.com/@yasufumy/data-structure-heap-ecfd0989e5be)などが分かりやすいです。


# 結論

計算量は以下のようになります。

- 頂点の数V、辺の数Eとすると
```math
O((V+E)log(V))
```
- V≒E(頂点と辺の数がほぼ同じ)の場合
```math
O(Vlog(V))
```
- 各頂点から全ての頂点に辺があるような場合
```math
O(V^2 log(V))
```

# なぜ(V+E)log(V)になるのか

ダイクストラ法で、値を更新していくコードの主要部分は以下のようになります。

```python
# 既にその頂点までの最低コストが確定している場合、頂点番号のindex要素をTrueとします。
seen = [False for _ in range(V)]

# その頂点までのコストを管理します。
C = float("Inf")
cost = [C for _ in range(V)]
cost[0] = 0

# (コスト, 頂点番号)
heap = [(0, 0)]

# Gは辞書型で、頂点0→頂点1のコストが10の場合、G[0][1] = 10としています。
while heap:
    s = heappop(heap)[1]
    seen[s] = True
    for i in G[s].keys():
        if cost[i] > cost[s] + G[s][i] and not seen[i]:
            cost[i] = cost[s] + G[s][i]
            heappush(heap, (cost[i], i))
```

ある時点で始点から最小のコストで行ける頂点の取得は`heappop`で行います。`heappop`の計算量は
```math
O(log(V))
```
です。(後述)
この計算は外側のwhileのループ数の分だけ行いますが、頂点の取り出しは多くてもV回(頂点数)になります。
したがって、上記コードのheappop関連の計算量は
```math
O(Vlog(V)) ・・・(1)
```
です。

ある時点での各頂点への最小コストが更新された場合、`heappush`を行います。`heappush`の計算量は
```math
O(log(V))
```
です。(後述)
この計算は(`while`のループ数)×(`for i in G[s].keys()`)のループ分行いますが、どんなに多くてもE(辺の数)を超えることはありません。
`if`の条件文が毎回trueだとしても、辺の数の回数しか更新は走らないはずだからです。したがってheappush関連の計算量は
```math
O(Elog(V))・・・(2)
```
です。

(1)と(2)を合計すると、heapを使用したダイクストラ法の計算量は
```math
(V+E)log(V)
```
になることが分かります。


# heappopの計算量はなぜO(log(V))になるのか

heappopは実際には以下の操作をこの順番で行っています。
1. heapの先頭と末尾を交換(以後、先頭に来た要素を「追加した要素」と表現する)
2. heapの末尾を削除
3. 追加した要素が子要素より大きければ交換
4. (3)の操作を葉の要素まで繰り返す。

(3)の処理を繰り返すとき、最大でルート要素から葉要素まで行います。
heapを構成する完全二分木の高さをhとすると、最大でh回繰り返すことになります。
要素数がVの完全二分木の高さは`log(V)`(後述)なので、`heappop`の計算量は`O(log(V))`で見積もることができます。

# heappushの計算量はなぜO(log(V))になるのか

heappushは実際には以下の操作を行っています。

1. 末尾に要素を追加
2. 追加した要素が親要素より小さければ交換
3. (2)の操作をルートの要素まで繰り返す。

(2)の処理を繰り返すとき、最大で葉要素からルート要素まで行います。
heapを構成する完全二分木の高さをhとすると、最大でh回繰り返すことになります。
要素数がVの完全二分木の高さは`log(V)`(後述)なので、`heappop`の計算量は`O(log(V))`で見積もることができます。


# 要素数Vの完全二分木の高さ

完全二分木は、高さがhのとき、要素数は最大で
```math
2^{h+1} - 1
```
になります。

これは、[等比数列の和](https://www.kwansei.ac.jp/hs/z90010/sugakua/suuretu/touhisum/touhisum.htm)を使うと、簡単に求めることができます。

高さがh-1のとき、要素数は最大で
```math
2^{h} - 1
```
になります。

つまり高さがhのとき、要素数Vは以下の条件を満たします。
```math
2^{h} - 1 < 2^{h} <= V <= 2^{h+1} - 1 < 2^{h+1}
```
```math
2^{h} <= V < 2^{h+1}
```
両辺logを取ると
```math
h <= log(V) < log(h+1)
```
となり、hは正の整数なので、高さhは`log(V)`と分かります。(高さを0~で考えた場合)


# まとめ

- heapを使ったダイクストラ法の計算量は`O((V+E)log(V))`
- heappopの計算量は`O(log(V))` (Vは要素数)
- heappushの計算量は`O(log(V))` (Vは要素数)
- 要素数Vの完全二分木の高さはlog(V)

# 参考

- [ヒープをわかりやすく解説してみた](https://medium.com/@yasufumy/data-structure-heap-ecfd0989e5be)
- [完全二分木の根の高さがO(logn)となる理由](https://qiita.com/kamikennn/items/1c8f657779a9998af2df)
- [等比数列の和](https://www.kwansei.ac.jp/hs/z90010/sugakua/suuretu/touhisum/touhisum.htm)
- [ダイクストラ法とは?]()
CalicoのPodをFargateにデプロイしない方法

CalicoをEKS上で使うとこうなる。
```
$ kubectl get pod -n calico-system
NAME                                      READY   STATUS    RESTARTS   AGE
calico-node-smmgx                         0/1     Pending   0          14m
calico-node-th9f7                         1/1     Running   0          14m
```
FargateにデプロイされたDaemonSetのPodがPendingとなる。\
これを回避する。

ポイントとしては、以下のPRがMergeされた以降のバージョンを使う点となる。
https://github.com/tigera/operator/pull/1725

現状、以下のAWSのCalicoはメンテされていない。
https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/calico.html
よって、この手順でインストールしても、上述のPRがMergeされていないバージョンを使うことになる。\
そのため、[Calicoオフィシャルの手順](https://projectcalico.docs.tigera.io/getting-started/kubernetes/managed-public-cloud/eks)を少し改変して適用する。

最初に、Calicoの最新版をインストールする。
```
kubectl create -f https://projectcalico.docs.tigera.io/manifests/tigera-operator.yaml
```
配布元がCalicoになっているものを使う。

次に、`kind: Installation`を作成する。このカスタムリソースはCalicoのインストール方法を定義したものとなる。Calicoオフィシャルの手順だと上手く行かなかったので、AWSで配布されていたInstallationを元に、PRの修正を反映させるための設定である`kubernetesProvider: EKS`を追加する。
```yaml
kubectl create -f - <<EOF
kind: Installation
apiVersion: operator.tigera.io/v1
metadata:
  name: default
spec:
  kubernetesProvider: EKS
  cni:
    type: AmazonVPC
EOF
```
この結果、Fargateにデプロイされなくなる。
```
$ kubectl get pod -n calico-system
NAME                                       READY   STATUS    RESTARTS   AGE
calico-node-4vmm7                          1/1     Running   0          35m
calico-node-54cwl                          1/1     Running   0          35m
```
なお、calicoのDaemonSetの中身を見ると、以下のnodeAffinityが追加設定されていることがわかる。

```yaml
$ kubectl get ds -o yaml -n calico-system calico-node
：（省略）
      spec:
        affinity:
          nodeAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
              nodeSelectorTerms:
              - matchExpressions:
                - key: eks.amazonaws.com/compute-type
                  operator: NotIn
                  values:
                  - fargate
：（省略）
```

## おまけ：動作確認

Calicoの導入理由はEKS上でNetworkPolicyを使いたかったからであり、NetworkPolicyが動作するかを確認する。\
以下の動作確認用のPodとNetworkPolicyを作成する。
```yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: centos
  name: centos
  namespace: default
spec:
  containers:
  - command:
    - sleep
    - 365d
    image: centos
    name: centos
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-netpol
  namespace: default
spec:
  podSelector:
    matchLabels:
      run: centos
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 10.10.0.0/16
```

実際に外部への通信が遮断されることを確認する。
```
$ kubectl exec -it centos -n default -- ping www.google.com
ping: www.google.com: Name or service not known
command terminated with exit code 2
```
NetworkPolicyを削除すると通信できることも確認する。
```
$ kubectl delete netpol test-netpol -n default
networkpolicy.networking.k8s.io "test-netpol" deleted
```
```
$ kubectl exec -it centos -n default -- ping www.google.com
PING www.google.com (172.253.115.103) 56(84) bytes of data.
64 bytes from bg-in-f103.1e100.net (172.253.115.103): icmp_seq=1 ttl=95 time=2.18 ms
64 bytes from bg-in-f103.1e100.net (172.253.115.103): icmp_seq=2 ttl=95 time=2.12 ms
```
正常にCalicoが動作しているようだ。