OmniAICreator/Qiita-1.07M huggingface dataset:
DatabricksのIdentity列を試してみる

こちらで紹介されている新機能、Identity列を試してみました。

https://qiita.com/taka_yayoi/items/f4076d1be4ffe017564f

[Databricks SQL](https://www.databricks.com/jp/product/databricks-sql)でテーブルを作成して、データをインサートしていきます。

# Databricks SQLにアクセス

Databricksワークスペースにログインし、サイドメニューのペルソナスイッチャーで**SQL**を選択します。
![Screen Shot 2022-08-16 at 8.15.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/7c4e8e7e-473c-240f-96b8-6aebd6c766fa.png)

# テーブルの作成

1. サイドメニューから**クエリ**を選択します。
![Screen Shot 2022-08-16 at 8.16.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/cdd89491-050a-1cc0-3b3e-2817bf6a8c55.png)
1. 画面右上の**クエリーを作成**をクリックします。
![Screen Shot 2022-08-16 at 8.17.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/74b55483-4cf9-5441-21bf-afa3c1510c16.png)
1. クエリーエディタが表示されます。
![Screen Shot 2022-08-16 at 8.21.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/52719fef-a6f5-92fc-00d2-75e3e7152173.png)
1. 以下のクエリーを入力します。`USE`で指定するデータベースは適宜変更してください。

    ```sql:SQL
    USE `20210826_workshop_takaakiyayoidatabrickscom`;
    
    CREATE OR REPLACE TABLE demo (
      id BIGINT GENERATED ALWAYS AS IDENTITY,
      product_type STRING,
      sales BIGINT
    );
    ```

1. **すべてを実行**をクリックしてテーブルを作成します。クエリーが成功すると`demo`テーブルが作成されます。
![Screen Shot 2022-08-16 at 8.23.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/f3861a7e-9c6b-f4d5-7a94-192855dd36b1.png)
1. この時点ではテーブルは空です。
![Screen Shot 2022-08-16 at 8.27.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/b32bd5dc-56d0-e724-83c1-1be18fa17f6f.png)

# 行のインサート

1. ダミーの行をインサートします。

    ```sql:SQL
    USE `20210826_workshop_takaakiyayoidatabrickscom`;
    INSERT INTO demo (product_type, sales)
    VALUES ("Batteries", 150000);
    INSERT INTO demo (product_type, sales)
    VALUES ("Chargers", 200000);
    ```

1. テーブルを確認します。

    ```sql:SQL
    SELECT * FROM `20210826_workshop_takaakiyayoidatabrickscom`.demo ORDER BY id ASC;
    ```
    `id`列にインサートされた順の連番が振られていることがわかります。
![Screen Shot 2022-08-16 at 8.28.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/336da2e8-da10-4212-7be9-2b369b189c89.png)

1. さらにダミーの行をインサートします。

    ```sql:SQL
    USE `20210826_workshop_takaakiyayoidatabrickscom`;
    INSERT INTO demo (product_type, sales)
    VALUES ("Papers", 50000);
    INSERT INTO demo (product_type, sales)
    VALUES ("Repair", 1200000);
    ```

1. テーブルを確認します。

    ```sql:SQL
    SELECT * FROM `20210826_workshop_takaakiyayoidatabrickscom`.demo ORDER BY id ASC;
    ```
    ![Screen Shot 2022-08-16 at 8.30.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/c6868fbc-8159-d09c-3b11-04f4d6e40c72.png)

クリーンアップするにはテーブルをドロップしてください。

```sql:SQL
DROP TABLE `20210826_workshop_takaakiyayoidatabrickscom`.demo
```

このようにIdentity列を使うことで、データベースでは当たり前の主キー・外部キーによるテーブル結合がデータレイク上のデータでも容易に行えるようになります。

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
MUI

# MUIとは
- React用デザインライブラリ
- 画面全体からではなくコンポーネント単位からデザインするのが特徴

# インストール
パッケージ名自体が変わることが多く、パッケージ名とReactバージョンの依存関係に注意
```bash
npm install @mui/material @emotion/react @emotion/styled
```

# サンプル
https://github.com/mui/material-ui/tree/master/examples/nextjs
```python
import * as React from 'react';
import Button from '@mui/material/Button';

function App() {
  return <Button variant="contained">Hello World</Button>;
}
```

# コンポーネント
https://v4.mui.com/components/

## ボタン
```python
import Button from '@mui/material/Button'
```

## チェックマーク


## アイコン
```bash
npm install @material-ui/icons # React17まで
npm install @mui/icons-material # React18から
```

```python
<Icon color="primary">add_circle</Icon>
```
## ヘッダー
```python
<Typography variant="h1" component="h2">
  h1. Heading
</Typography>
```

## リスト

```python
<List component="nav" className={classes.root} aria-label="contacts">
  <ListItem button>
    <ListItemIcon>
      <StarIcon />
    </ListItemIcon>
    <ListItemText primary="Chelsea Otakan" />
  </ListItem>
  <ListItem button>
    <ListItemText inset primary="Eric Hoffman" />
  </ListItem>
</List>
```
列名を変更する/不要な列を削除する(SPSS Modeler データ加工逆引き7-7)

# 列名を変更する/不要な列を削除（フィルター）

![スクリーンショット 2022-08-03 9.19.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/d13bba35-c143-4fc9-5e9e-ce67824f7de0.png)

## 1.想定される利用目的

・列展開や集計によって便宜的に付与された列名の接尾語の変更
・特徴量を作成する過程で不要になった列の整理

## 2.サンプルストリームのダウンロード

https://github.com/yoichiro0903n/blue/blob/main/filter.str?raw=true

## 3.サンプルストリームの説明

![スクリーンショット 2022-08-03 9.50.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/3e4f5181-25f0-d08b-2aaf-74a12a245fdc.png)

a.入力するデータは以下の通りです。後続のプロセスにはクラスタ番号のみが必要で、それを作成する列は不要という想定です。
![スクリーンショット 2022-08-03 9.52.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/2b729832-dea7-4b61-9871-621ffbf5a38d.png)

b.[フィルター]ノードを編集します。右のフィールド名列で列名をリネームでき、矢印をオフにすると列をフィルターできます。
![スクリーンショット 2022-08-03 9.52.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/d35e7783-d35e-9483-7d37-dadacd99be18.png)

[テーブル]を実行します。
![スクリーンショット 2022-08-03 9.52.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/bb73fe15-cc24-4a7a-da8e-a4eb41dde21b.png)

#### 注意事項

後続でSPSS Stats連携させる場合には、フィールド名として扱えない文字を自動で処理する機能を利用してください。
![スクリーンショット 2022-08-03 9.53.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/8dd5b5f3-df68-1c5c-66d2-43d4809ef2d3.png)

## 4.参考情報

#### [フィルター]ノードで列名を一括変換

https://www.ibm.com/blogs/solutions/jp-ja/modeler-tips-11/

#### [フィルター]ノードを扱った記事

https://qiita.com/kawada2017/items/7e10618edd5e1f3d6ebd

https://qiita.com/416nishimaki/items/52f857c98036d2f44839

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/private/4bf813e6cba84b2a1008
[Unity]それまでのコンポーネントを維持したままfbxだけを差し替える

# きっかけ

セットアップ済みのVRChat用モデルのコンポーネント再セットアップはさすがに厳しいので、どうにかfbxだけを差し替える方法を知りたかった。多分また必要になりそうなので自分用メモです。

# 流れ

前提条件として、「書き出したfbxのボーンの構造と順番が同じ」ならば、既存のfbx書き換えでそのままできる可能性があります。

1. Blenderへのインポート時に、"Ignore Leaf Bones"にチェックボックスを入れた状態にしておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306146/19a0504d-08b2-6be7-b3e5-e2c4224c0673.png)

1. 満足いくまでいじり倒す
1. エクスポート時に、"FBX All"を選んだ状態にする。(Apply Unitはどうしてたっけな...多分そのままでよかった気がする。。。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306146/001a8be5-c6e0-6eaf-dbd8-3a916357de2c.png)

1. プロジェクトを開く(Unityを起動する) **前に** エクスプローラーから既存の改変前のFBXを上書きする形でエクスポートした物を配置する。
から
以上です。
Python,JavaScript,PHP,Ruby,Perlの入門の比較 | プログラミング言語比較

<a href="https://qiita.com/yuki_kimoto/items/f9c2454e7f9130ddb003">Qiita > プログラミング言語の比較</a>

プログラミング言語Python,JavaScript,PHP,Ruby,Perlの入門の比較

# Python

https://qiita.com/ponnhide/items/870f0e6b1ae50f201f07

# JavaScript

https://qiita.com/ab-boy_ringo/items/23f60e051e3022f2a599

# PHP

https://qiita.com/mackeyTA/items/069900b5c2366fb30e3a

# Ruby

https://qiita.com/oekazuma/items/6daa19248353c6a81146

# Perl

https://perlzemi.com/
mac で lalavel /sail のビルドができないときは docker のバージョンを下げる

タイトルそのまま

何度ビルドしても

```
ERROR [ 4/11] RUN apt-get update 
```

となるときは Docker Desktop 4.9.0　(docker engine　20.10.6)　にしましょう。


https://github.com/laravel/sail/issues/159#issuecomment-863079097
【夏休み企画】#IT用語一問一答【毎朝投稿8日目】CSRF

# この記事を読むと、、
- 「関連用語」を使って「CSRF」を説明できるようになる

# 関連用語
CORS / login CSRF / stored CSRF flaw / CSRF token / SameSite

[**復習用**] 記事の内容を見る前に上記の言葉でCSRFを説明してみよう！

# 企画説明
- クラウドって何？って人に聞かれて説明してるけど俺もよく知らないや、、
- ドキュメント読んでみてるけど半分くらい何言ってるか分かんない、、
- 今日の夕飯はナスの炒めものにしよっかな〜、あれ、NASってなんだっけ？

みたいなことが結構あったので、知ったかしていたIT用語を毎日一個ずつちゃんと学んでいこうっていう企画です！

昨日の記事はこちら↓

https://qiita.com/acta/items/cac0b99bbd5006c78603

# CSRFとは
CSRF = Cross-Site Request Forgery = あるサイトにログインしている状態のユーザーが攻撃者のサイトを訪問した際に、攻撃者がその認証情報を使って不正な操作をリクエストする攻撃

## CSRFの流れ
1. 被害者がCSRF脆弱性のあるサイトにログイン(例えば銀行のサイトだとする)
1. Social Engineeringなどで被害者が攻撃者のサイトを訪問する
1. 悪意のあるスクリプトによって銀行にリクエストを投げる
    - ブラウザはリクエストにsession cookieやIPアドレスを自動で含める
    - ユーザーはこれに気づかない
    - レスポンスは**CORS** = Cross-Origin Resource Sharingによって弾かれるが攻撃は達成されている
    - リクエストはGETならaタグやimgタグなど、POSTならformタグなどから送信される
1. 銀行のwebサーバーはユーザーの意図したリクエストとの見分けがつかずリクエストに応じて処理を実行
    - 攻撃者への送金やパスワードの変更などが行われる
    - ユーザーの個人情報を入手するリクエストはレスポンスが攻撃者に渡らないため行われない

## いろんなCSRF

**login CSRF** = 被害者が偽のformに誤って認証情報などを入力し、攻撃者がそれをもちいて被害者のアカウントにログインする手法
- 先述の流れとは違うけどこれ↑もCSRFの一種

**stored CSRF flaw** = HTMLを注入可能なサイトにおいてimgタグやiframeタグなどから、あるいはXSSをもちいて脆弱なサイトに仕掛けられるCSRFの罠

## CSRFへの対策
**CSRF token** = サーバーから返却するHTMLページのform上のhidden fieldとして埋め込まれるtoken
- このページからのリクエストにはtokenが含まれるため、サーバーはCSRFとの見分けがつけられる
- CSRFでは標的サイトのHTMLを読めないが、XSSでは盗まれる可能性があることに注意
- このtokenをcookieに保存してもCSRF対策にはならない

**SameSite** = HTTPレスポンスヘッダに含まれる属性で、リクエストの発行元のオリジンなどによってCookieを送るか決めることができる
- Strict, Lax, Noneの3種類が用意されている
- デフォルト値はLax

# 参考資料
- https://owasp.org/www-community/attacks/csrf
- https://blog.vnaik.com/posts/web-attacks.html
- https://owasp.org/www-community/SameSite
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
2022/8/16主にITとかセキュリティの記事

従業員を標的にした認証サービスに対するスミッシングについてまとめてみた(8/13)
https://piyolog.hatenadiary.jp/entry/2022/08/13/023034

従業員を標的にした認証サービスに対するスミッシングについてまとめてみた - piyolog
https://b.hatena.ne.jp/entry/s/piyolog.hatenadiary.jp/entry/2022/08/13/023034

新学期に向けた学生が準備すべき5つの簡単なセキュリティ対策(8/14)
https://news.mynavi.jp/techplus/article/20220814-2423684/

iPhoneから削除しよう！ 人気1位だったPDFアプリにマルウェアが潜んでいた(8/14)
https://gunosy.com/articles/eyvoA

「あなたの名前をネット検索したら、あなたの情報が出てきますか？」１０人にひとりがネット上に消したい情報があると判明！　実は身近なデジタルタトゥーの恐怖(8/14)
https://news.nicovideo.jp/watch/nw11296627

Acala Networkがハッキングを受け、aUSD12.67億ドルが不正Mintされる(8/14)
https://crypto-times.jp/ausd-hack-minted/

ロシア、SNS戦巻き返し　対ウクライナで民主主義劣勢(8/14)
https://www.nikkei.com/article/DGXZQOUC013H00R00C22A8000000/

凸版など、ICカードに新暗号技術　25年の実用化狙う(8/14)
https://www.nikkei.com/article/DGXZQOUC027FH0S2A800C2000000/

【9割の人が知らないGoogleの使い方】
古いPCをタダで最新OS搭載PCとして復活させる方法(8/14)
https://diamond.jp/articles/-/307725

「なぜOSをバージョンアップするだけなのに、なんでこんなに費用がかかるんですか？」という質問(8/13)
https://www.orangeitems.com/entry/2022/08/13/183204

DXリテラシー標準（DX Literacy Standards）(8/15)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/020600009/080300121/

年8000件の契約を電子化　紙と印紙なくし年1億円削減へ(8/15)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/020600004/080200110/

「全社員デジタル人材化」でEUCの悪夢再来、やばすぎるDX戦略の成否(8/15)
https://xtech.nikkei.com/atcl/nxt/column/18/00148/080100237/

3割超が個人間送金の利用経験あり　使用ツールは「PayPay」が首位(8/15)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/020600010/080100121/

巨額制裁金が現実に　「AI倫理」待ったなし(8/15)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/020600014/080300123/
raspberry piでSMTPリレーサーバーを立ち上げた時の備忘録

## postfixのインストール
```c
csudo apt install -y postfix libsasl2-2 libsasl2-modules bsd-mailx
```

## main.cfの編集
main.cfを開く
```c
sudo nano /etc/postfix/main.cf
```
mynetworks= にメールの送信元になる機器のIPアドレスを記述する。
```c
mynetworks =127.0.0.0/8, <IPアドレス>, <IPアドレス>・・・
```
SMTPリレーサーバーの設定を追記
```c
#mail Settings
relayhost = <SMTPサーバーアドレス>:<ポート>
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/passwd
smtp_sasl_security_options = noanonymous
smtp_sasl_mechanism_filter = plain
smtp_use_tls = yes
```

パスワードファイルの作成
```c
sudo nano /etc/postfix/passwd
```
記述
```c
<SMTPサーバーアドレス>:<ポート> <ログインID>:<パスワード>
```
## ハッシュ化
```c
sudo postmap /etc/postfix/passwd
```
削除
```c
sudo rm /etc/postfix/passwd
```
再起動
```c
sudo postfix reload
```
【OWASP ZAP】 SSL通信のインジェクション用のルート証明書を自前の証明書をZAP用に変換・インポートする手順

# 背景
OWASP ZAPに対して、事前に所有しているルート証明書をインストールし、SSL通信をインジェクションする必要があった。

# 環境
Windows 10
OpenSSL 3.0.5 5 Jul 2022 (Library: OpenSSL 3.0.5 5 Jul 2022)

# 手順の流れ
手元に、OWASP ZAPへインポートして、TLS通信時のインジェクション時署名するためのpem形式の公開鍵と秘密鍵を別々に保持している。(前提)
ZAPのマニュアルを見ると、平文でpem形式1ファイルにまとめる必要があるので、必要に応じて変換を実施して取り込む。
https://www.zaproxy.org/docs/desktop/ui/dialogs/options/dynsslcert/#import
> You can also import certificates stored in pem files as long as they include both the certificate and the unencrypted private key in the following format:

* 1,秘密鍵について変換を行う(手元にあった証明書が暗号化済みだったため、pkcs8形式に変換)
```
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private\cakey.pem -out private\pkcs8_cakey.pem
```
→生成されたファイルが、-----BEGIN PRIVATE KEY-----から始まっていればOK

(公開鍵は、-----BEGIN CERTIFICATE-----で始まっていたため割愛)

* 2,結合、メモ帳などで、上記ZAPのマニュアルで例示されている通り、公開鍵+秘密鍵を1ファイルにまとめる(GUIでもCUIでも好みでOK)
```
-----BEGIN CERTIFICATE-----
XXXX
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
XXXX
-----END PRIVATE KEY-----
```
の順番になっていたらOK

* 3,OWASP ZAPへインポートする
GUI(ツール>オプション>ダイナミックSSL証明書>インポート)
ないし、
CUI(zap.bat -cmd -certload )　https://www.zaproxy.org/docs/desktop/cmdline/

# 余談
`zap.bat -cmd -certfulldump` で秘密鍵まで含めた状態でOWASP ZAPで使用されているルート証明書をダンプすることができた。

以上。
【RSpec】have_xpathの使い方｜テキストフィールドの中身をテストする

# have_xpathの使い方
have_xpathを使うとタグの有無を確認することができます。

```ruby
#ページ内に指定した属性が'hoge'である指定したタグがあるかテストする
expect(page).to have_xpath "//タグ名[@属性名='hoge']"

#ページ内にvalue属性が'サンプルデータ'であるinputタグがあるかテストする(テキストフィールドの中身が'サンプルデータ'かどうかテストする)
expect(page).to have_xpath "//input[@value='サンプルデータ']"
```

※XPathとはなんぞや？という人は以下のサイトを参考にしてください。
[【図解】XPathとは？基本概念から書き方までわかりやすく解説！](https://www.octoparse.jp/blog/xpath-introduction/)

# 参考
- [Capybara RSpecでのマッチャ、セレクタ 「こんなときどうするの」その1](https://qiita.com/kenzan100/items/9642615badc3e1cf160a)
- [【図解】XPathとは？基本概念から書き方までわかりやすく解説！](https://www.octoparse.jp/blog/xpath-introduction/)
【Dart・Flutter】日付の1ヶ月前、1ヶ月後

# はじめに
- プロジェクトにおいて1ヶ月前、1ヶ月後の定義はバラバラなので本記事が正解とは限りません。
- 個人的に結果が綺麗だと思う定義での取得方法です。

## 結論
リンクのDartPadで色々試せます。
https://dartpad.dev/?id=d22e226e0854357340cf24ec0a6f2707
```
  final baseDate = DateTime(2022, 1, 29); // 任意の日付
  final prevMonthLastDay = DateTime(baseDate.year, baseDate.month, 0);
  final thisMonthLastDay = DateTime(baseDate.year, baseDate.month + 1, 0);
  final prevDiff =
      baseDate.day < prevMonthLastDay.day ? prevMonthLastDay.day : baseDate.day;
  final prevMonth = baseDate.subtract(Duration(days: prevDiff)); // 1ヶ月前

  final nextMonthLastDay = DateTime(baseDate.year, baseDate.month + 2, 0);
  final nextDiff = baseDate.day < nextMonthLastDay.day
      ? thisMonthLastDay.day
      : nextMonthLastDay.difference(baseDate).inDays;
  final nextMonth = baseDate.add(Duration(days: nextDiff)); // 1ヶ月後
```

## 1ヶ月前
### 定義
1. 基本的に基準となる年月日の月を-1する。（例：2023/02/14→2023/01/14）
2. 月が1月の場合、年を-1して、月は12になる（例：2023/01/14→2022/12/14）
3. 基準日の1ヶ月前の月の日数より基準日の日付が大きい場合、1ヶ月前の月末になる（例：2023/05/31→2023/04/30）

### コード
```
  final baseDate = DateTime(2022, 3, 30); // 任意の日付
  final prevMonthLastDay = DateTime(baseDate.year, baseDate.month, 0);
  final prevDiff =
      baseDate.day < prevMonthLastDay.day ? prevMonthLastDay.day : baseDate.day;
  // 基準日と1ヶ月前の日付の間隔。
  // 基本的に1ヶ月前は基準日から前月の月の日数分引けば求められる。
  // 基準日の1ヶ月前の月の日数より基準日の日付が大きい場合は前月の月末にするために基準日の日付を引く。
  final prevMonth = baseDate.subtract(Duration(days: prevDiff)); // 1ヶ月前
  // subtract()は引数のDuration分時間を戻す関数
```

## 1ヶ月後
### 定義
1. 基本的に基準となる年月日の月を+1する。 （例：2023/02/14→2023/03/14）
2. 月が1月の場合、年を+1して、月は1にする。（例：2022/12/14→2023/01/14）
3. 基準日の1ヶ月後の月の日数より基準となる年月日の日が大きい場合、1ヶ月後の月末になる。　（例：2023/05/31→2023/06/30）

### コード

```
  final baseDate = DateTime(2022, 1, 31); // 任意の日付
  final thisMonthLastDay = DateTime(baseDate.year, baseDate.month + 1, 0);
  final nextMonthLastDay = DateTime(baseDate.year, baseDate.month + 2, 0);
  final nextDiff =
      baseDate.day < nextMonthLastDay.day ? nextMonthLastDay.difference(baseDate).inDays;
  // 基準日と1ヶ月後の日付の間隔。
  // 基本的に1ヶ月後は基準日から今月の月の日数分足せば求められる。
  // 基準日の1ヶ月後の月の日数より基準日の日付が大きい場合は翌月の月末にするために基準日から翌月末までの日数分を足す。
  final nextMonth = baseDate.add(Duration(days: nextDiff));　// 1ヶ月後
　　　　// add()は引数のDuration分時間を進める関数
```

## さいごに
上記コードを参考にDateTimeにextensionしてgetterでも関数でも定義すれば使えば使い易くなります。
久しぶりに記事を書いて文章をまとめる能力が低いと思い知らされました。
少しでも誰かの参考になれば嬉しいです。
なんで二分探索の計算量はO(log2N)になるの？

二分探索の計算量がなんでO(log2 N)になるのか、
FEの勉強などで出てきても適当に飛ばしていましたが、
最近アルゴリズムを改めて書くようになり、触れる機会があったので
計算してみました。


図にするとこのようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418980/4947a1ce-e66d-f870-dd90-d56e4333b3ec.png)



最大の探索回数で考えるので、
N個のデータからある値を二分探索する場合
計算回数をx回とすると、N/(2^x)が１となるまで繰り返します。
N/(2^x)=1
2^x=N
log2(2^x)=log2N
x=log2N
となり
二分探索の計算量は
O(log2N)
となることがわかります。

対数って感覚的に掴みずらくて、今までサラッと通り過ぎていましたが
図にすることで理解しやすくなりました。
Amazon Linux2での環境構築メモ（Git、Node.js、MySQL）

## はじめに
よくわからなくなってググるので超個人的備忘録として書き記しておきます。

### 動作環境
OS：Amazon Linux2

## gitのインストール
コマンドラインで以下のコマンドを入力
```bash
sudo yum install git
```

インストール確認。
```bash
git --version
```

これでgitのインストールは完了。
あとは任意のリポジトリを`git clone`してやればOK

## Node.jsのインストール
まずはnvm（Node.jsのバージョン管理ツール）をインストールします。
[公式サイトの手順](https://github.com/nvm-sh/nvm/tree/v0.37.2#installing-and-updating)に従うだけで大丈夫。コピペで簡単。
```bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash
```

bashを開き直すよう言われるので開き直してからインストール確認。
```bash
nvm --version
```

次にnvmを使ってNode.jsをインストールする。
```bash
# バージョン指定でインストール
nvm install 【インストールしたいNode.jsのバージョン】
# 最新のLTSをインストール
nvm install --lts
# 最新版をインストール
nvm install node 
```

毎度恒例のインストール確認。
```bash
node --version
npm --version
```

Node.jsとnpmが利用可能になっていればNode.jsのインストール作業はOKです。

#### おまけ）nvmでのNode.jsバージョン切り替え方法
間違ったバージョンをインストールした、複数のバージョンを切り替えたいetc...といった場合は以下のコマンドで使用するNode.jsのバージョンを切り替えられます。
```bash
# 使用するバージョン自体を変更
nvm use 【version】
# 指定したバージョンのNode.jsを使用してjsファイルを実行
nvm run 【version】 temp.js
```
その他nvmの便利コマンドは[nvm チートシート](https://qiita.com/guai3/items/4d38dcb8a877951b718a)に分かりやすくまとめてあるので気になる場合は是非。

## MySQLのインストール
みんな大好きMySQLをインストールする手順。

```bash
sudo yum localinstall https://dev.mysql.com/get/mysql80-community-release-el7-6.noarch.rpm
```

インストール確認

```bash
# 関連パッケージ全体を確認
sudo yum repolist all | grep mysql
# 有効化されているパッケージを確認
sudo yum repolist enabled | grep mysql
```

現在はデフォルトだとMySQL8.0をインストールする設定になっているので以前のバージョンをインストールしたい場合はインストール対象のバージョン変更処理を行います。
今回はMySQL5.7をインストールするように変更。

```bash
# MySQL8.0のコミュニティを無効化
sudo yum-config-manager --disable mysql80-community
# MySQL5.7のコミュニティを有効化
sudo yum-config-manager --enable mysql57-community
```

ちゃんと有効化されているか確認。

```bash
sudo yum repolist enabled | grep mysql
```

`mysql57-community/×86_64`が有効化リストに表示されていればOK！
次はMySQL本体のインストールです。

```bash
sudo yum install mysql-community-server
```

最後にMySQLを起動します。
```bash
# MySQLの起動
systemctl start mysqld
# 起動確認
systemctl status mysqld
```

`Active: active(running)`と表示されていればMySQLが起動されています。

#### おまけ）初回ログイン
MySQLをダウンロードした時点でルートユーザが生成されているのでまずはルートユーザでログインします。
初回のログインパスワードは以下のコマンドで確認できます。
```bash
sudo grep 'temporary password' /var/log/mysqld.log
```
出力された`A temporary password is generated for root@localhost: ○○○`の○○○の部分が初期パスワードです。

ルートユーザのパスワードが分かったところでログインしてパスワードを変更します。

```bash
# ログイン
mysql -uroot -p
```

```sql
-- ルートユーザのパスワード変更
ALTER USER 'root'@'localhost' IDENTIFIED BY '任意のパスワード';
```

## おわりに
ざっと自分がよく使うもののインストール手順をまとめてみたのですが、いざまとめてみると意外と単純なのでは？という気がするのが不思議ですね。まとめてみるの大事！
とは言ってもサーバ上での環境構築は面倒なのでDockerとか使ったほうが楽なのかなぁ・・・とも思っております。（Dockerは全く分からないので誰か教えてください。）
仏教での「慈悲の瞑想」を[for文を使った関数]で処理する

仏教には「慈悲の瞑想」と呼ばれる、生きとし生けるものの幸せを祈る瞑想があります。

https://ja.wikipedia.org/wiki/%E6%85%88%E6%82%B2%E3%81%AE%E7%9E%91%E6%83%B3

https://j-theravada.net/world/metta/

ここでは日本テーラワーダ仏教協会の言葉を引用します。

:::note info
私は幸せでありますように
私の悩み苦しみがなくなりますように
私の願いごとが叶えられますように
私に悟りの光が現れますように
私は幸せでありますように（３回）

私の親しい生命が幸せでありますように
私の親しい生命の悩み苦しみがなくなりますように
私の親しい生命の願いごとが叶えられますように
私の親しい生命に悟りの光が現れますように
私の親しい生命が幸せでありますように（３回）

生きとし生けるものが幸せでありますように
生きとし生けるものの悩み苦しみがなくなりますように
生きとし生けるものの願いごとが叶えられますように
生きとし生けるものに悟りの光が現れますように
生きとし生けるものが幸せでありますように（３回）

私の嫌いな生命が幸せでありますように
私の嫌いな生命の悩み苦しみがなくなりますように
私の嫌いな生命の願いごとが叶えられますように
私の嫌いな生命に悟りの光が現れますように

私を嫌っている生命が幸せでありますように
私を嫌っている生命の悩み苦しみがなくなりますように
私を嫌っている生命の願いごとが叶えられますように
私を嫌っている生命に悟りの光が現れますように

生きとし生けるものが幸せでありますように（３回）
:::

ただ、私はこれをみたとき、似たような言い回しに対して祈りの対象が違っているだけなので、定型句を関数にして、祈りの対象をリスト化して、for文で呼び出せば一発で祈れるのではないかと思ったので、pythonで慈悲の瞑想を処理するコードを書いてみました。

```python:cultivation-of-loving-kindness.ipynb
def cultivation_of_loving_kindness(name):
    print(name+'は幸せでありますように')
    print(name+'の悩み苦しみがなくなりますように')
    print(name+'の願いごとが叶えられますように')
    print(name+'に悟りの光が現れますように')
    print(name+'は幸せでありますように')
    print(name+'は幸せでありますように')
    print(name+'は幸せでありますように')

target=['私', '私の親しい生命', '生きとし生けるもの', '私の嫌いな生命', '私を嫌っている生命']
    
for i in range(5):
    name=target[i]
    cultivation_of_loving_kindness(name)
```

出力結果はこちらです。

![スクリーンショット 2022-08-15 23.49.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210818/e5e05e73-4536-26e3-0ea6-31f9cdce08b8.png)

このコードを実行すれば、すべての生命の幸せを一発で祈ることができ、プログラミングで穏やかな境地にたどり着けそうです！
攻めの品質、守りの品質

## 1. はじめに
攻めの品質、守りの品質と言ったときの「攻め」には意味がいくつかあるようです。

## 2. 攻めの品質、守りの品質
「[基礎から学ぶQMSの本質　第5回　品質の捉え方その２(2016-2-22)](https://www.tqm9000.com/news/2016/02/22/qms_iso9001_quality-what2/)」によると「利益＝売り上げ－原価」において

- 守りの品質：品質コストの総費用を極力抑える品質管理活動
- 攻めの品質：売り上げを増加させるための活動

と呼んでいます。

「[基礎から学ぶQMSの本質　第6回　品質を経営の中心に据える(2016-2-29)](https://www.tqm9000.com/news/2016/02/29/qmsiso9001_quality-center/)」では攻めの品質を以下2つ取り上げ、

> 1. （コンビニエンスストアのコーヒーが100円なのに対して）スターバックスは“ひとりでホッとできる空間”という顧客価値を提供することによって，通常の3倍以上の値段もするコーヒーが売れている
> 2. 美容電化製品としてのドライヤーは，街中の電気量販店の最安値で2千円弱で買えますが，それが“家で気楽にエステができる”という顧客価値を訴えてそれに適した商品にすることで，その10倍の2万弱の値段での販売に成功

次のようにまとめています。
> いずれの例も，これまで顧客自身でさえも気が付かなかったようなニーズを満たす商品（＝品質の良い商品）を市場に送り出すことによって，市場価格よりずっと高値で売ることができます．
これは，“売り上げ”に大きく貢献します．


なお、この記事ではこれまで顧客自身でさえも気が付かなかったようなニーズを満たす「市場開拓型の商品」をどうやって実現するかは触れていません。ただ、少なくとも品質管理（後工程に欠陥を流出させない取り組み）のやり方で潜在ニーズを具現化するのは難しそうです。潜在ニーズの具現化も品証部門の役割とすると品質エンジニアは品質管理だけでなくマーケティングやプロダクトマネジメント、価値工学[^1]といった分野も手を出すことになるのではと思います。

## 3. 営業における「攻めの品質」
品証部門の外に目を向けるとこういった説明もあります。

> むしろ、お客様の不満・不安を積極的に収集すること、それを解決する商品を提案することで新しい市場を開拓するのです。
これを「不」のマーケティングと呼んでいます。
これこそが営業における「品質でもうけなさい」のコンセプトです。
（[『品質でもうけなさい』9-6.守りから攻めの品質管理 | Apérza News（アペルザニュース） | ものづくり産業向けニュースサイト](https://news.aperza.jp/%E3%80%8E%E5%93%81%E8%B3%AA%E3%81%A7%E3%82%82%E3%81%86%E3%81%91%E3%81%AA%E3%81%95%E3%81%84%E3%80%8F9-6-%E5%AE%88%E3%82%8A%E3%81%8B%E3%82%89%E6%94%BB%E3%82%81%E3%81%AE%E5%93%81%E8%B3%AA%E7%AE%A1/)より）

「不」のマーケティングといえば「[リクルート「創刊男」の大ヒット発想術（くらた まなぶ 著）](https://bookplus.nikkei.com/atcl/catalog/2006/9784532193539/)」が思い出されるトコロですね。

## 4. 攻めのQA
「[「受身から攻めのQA」に至るまでの道のり | BLOG - DeNA Engineering](https://engineering.dena.com/blog/2022/05/road_to_aggressive_qa/)」では「QA担当も事業の中に入り、開発初期からのメンバーとして一緒に担当していくこと」を攻めのQAと呼んでいます。また、「[マネーフォワードのQAらしさ〜プロダクト開発のパフォーマンスを最大化する攻めのQA〜｜Morita Masami @MoneyForward｜note](https://note.com/morita_masami/n/ne28e8982bdb3)」では修正コストを削減して「プロダクトチームのパフォーマンスを最大化する」ことを攻めのQAと呼んでいます。

品質コストを下げる取り組みは「守りの品質」ですが、「手戻りを減らす→デリバリが短縮する→顧客のニーズをいち早く満たす→前倒しで売り上げを立てられるようになる」と解釈すると「攻めの品質」と言えるかもしれません。

## 5. 切っても切れないQAとお金の話
「[「受身から攻めのQA」に至るまでの道のり | BLOG - DeNA Engineering](https://engineering.dena.com/blog/2022/05/road_to_aggressive_qa/)」に

> 成果の可視化を色々な視点で実施してきましたが、やっぱりコストで示すのが一番有効でした！

とあり、QAはお金の話から逃れられないのだなと思いました。実際、QAは技術部門に限らず様々な部門と協働する機会が多い[^2]こともあり成果をお金で表すことがしばしば求められます。

## 6. 品証部門に期待される攻めの品質
「[基礎から学ぶQMSの本質　第5回　品質の捉え方その２(2016-2-22)](https://www.tqm9000.com/news/2016/02/22/qms_iso9001_quality-what2/)」は
> 品質保証，品質管理部門が品質を追求することの社内の旗振り役であるならば，守りの品質に留まらず，攻めの品質に力点を置くことが期待されているのです．

と締めくくられています。

ここで攻めの品質に力点を置くことを仮に

- 潜在ニーズまで深掘りして具現化する
  - マーケティング、プロダクトマネジメント、価値工学
- 不満、不安を解決する
  - 「不」のマーケティング
- 手戻りを減らしてデリバリを加速し早く売り上げを立てられるようにする
  - シフトレフト

とすると品質エンジニアはやることがたくさんありますね。また、経営層や品証部門のマネジメント層は攻めの品質の期待に応えられる部門運営を求められるものと思います。

## 7. おわりに
QAは攻めの品質まで役割を広げると商品企画や事業企画までスコープが広がって品証部門に閉じこもっていたらできない仕事ですね。品質に関して利益に貢献することは何でも開き直って攻めてみたいと思いました。

[^1]: 品質管理は基本的にはマイナスを減らす取り組みでありプラスを生むのは管理技術で言えば価値工学です。「[品質エンジニアにオススメする三大管理技術(IE, QC, VE)](https://qiita.com/pbjpkas/items/e9a40e45c18d48152eef)」も併せてどうぞ。
[^2]: 「[DXとQAの交点](https://qiita.com/pbjpkas/items/c0965ff17163b07ff4ab)」ではQAをグルーロジックに例えています。
コマンドライン引数をリストに格納し、出力してみた。

コマンドライン引数をリストに格納し、出力するプログラムを作りました。
使用例:
```
yusuke@mbp 20220815 % python main.py "apple" "orange"
['apple', 'orange']
```
* 解説
引数がない場合は、「引数を入力してください」と返されるようにしました。
コマンドライン引数は、文字列なので、リスト型に型変換しています。

* ソースコード
```Python
import sys


def main():
    args = list(sys.argv[1:])
    if not args:
        print("引数を入力してください")
        sys.exit(1)


    ex_lists = []
    ex_lists.append(args)


    for ex_list in ex_lists:
        print(ex_list)


    sys.exit(0)


if __name__ == '__main__':
    main()
```
[SwiftUI]外観モードを変更する際の注意点

# 外観モードの変更

SwiftUIでは外観モードを


```swift
.preferredColorScheme(.light)
```

で変更できますが少し癖があるので紹介します。

# 1. 宣言に一番近いpresentationまでが変更される

これはドキュメントにも書いてあるのですが、preferredColorSchemeを呼ぶとその直近のpresentationよりも下のビューの外観モードが変わります。
**アプリ全体が変更されるわけでは無いので注意**

https://developer.apple.com/documentation/swiftui/path/preferredcolorscheme(_:)

つまり、次のようなView構造の場合、Buttonは外観モードが変わらずListは動的に変更されることになります。

```swift
@State private var isPresented = false
@State private var isDarkMode = true

var body: some View {
    Button("Show Sheet") {
        isPresented = true
    }
    .sheet(isPresented: $isPresented) {
        List {
            Toggle("Dark Mode", isOn: $isDarkMode)
        }
        .preferredColorScheme(isDarkMode ? .dark : .light)
    }
}
```

# 2. システム設定に準拠する場合はnilを渡す

`ColorScheme`には`.dark`,`.light`があるのですが、システムの設定を使いたい場合はnilを指定します。
`.auto`とか`.system`ありそうで無いので注意しましょう。

# 3. sheetでシステム設定準拠をセットすると動作しない

これはバグな気がしますが、`preferredColorScheme(nil)`を呼ぶとコントロールセンターからダークモードの切り替えをしても切り替わらなくなります。
この問題はiOS14.5で修正されていますが、sheet内で呼ぶ場合はiOS14.5以降でも発生します。

ワークアラウンドとしては、UIKitのUIWindowのoverrideUserInterfaceStyleを直接呼ぶことで変更することができます。
SwiftUIWorkaroundというライブラリを作ったのでささっと対応したい方は使ってみてください。
preferredColorSchemeと違い、アプリ全体のカラースキームが変更される点に注意してください。

https://github.com/noppefoxwolf/SwiftUIWorkaround

```swift
struct ColorSchemeView: View {
    @State var colorScheme: ColorScheme? = nil
    
    var body: some View {
        contentView
            .workaround.preferredColorScheme($colorScheme)
    }
}
```
rails sがうまくいかなかった

背景
railsのバージョンを6.1.6.1　→　6.1.4.4に変更。
変更前はエラーが多発していた
1.
Running via Spring preloader in process ~
2.
gemでgemfile.lockにインストールされていない
3.
rails s
rails db:migrate
rails db:seed

バージョンによる問題、バージョンが理由ではない問題に
切り離して考えてみた。


問題が起こる前の挙動
gemfile
gem 'activeadmin'
gem 'devise'
gem 'net-smtp'
を追加して、
bundle install —path  vendor/bundle


実行
❯ rails s

=> Booting Puma
=> Rails 6.1.6.1 application starting in development 
=> Run `bin/rails server --help` for more startup options
Exiting
/Users/~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/webpacker-5.4.3/lib/webpacker/configuration.rb:103:in `rescue in load': Webpacker configuration file not found /Users/~/active_admin_sample/config/webpacker.yml. Please run rails webpacker:install Error: No such file or directory @ rb_sysopen - /Users/~/Desktop/program/active_admin_sample/config/webpacker.yml (RuntimeError)
がかえってくる。


エラー内容の特定:
どこ）configuration.rb:103:in `rescue in load': Webpacker configuration file not found 
何）Please run rails webpacker

よって、
以下を実行
rails webpacker:install
bundle install
yarn install

実行結果、なんとか無事にパス
yarn installの意味もパッケージ関係としておさえておきます
【Git】git commit 後に commit message を変更したい

# やりたいこと
`git commit`で間違って設定してしまったコミットメッセージを変更したい！

# どうやってやるか
`git commit --amend` を使えば、コミットメッセージを後から変更可能です。

# ユースケース
## 直前のCommitメッセージの変更
「GitHubのテンプレート作ったからコミットしよーっと :smiley:  」
```zsh
git commit -m 'GitHubのテンプレートwo追加'
```
「うお！コメントミスってしまった！」
「落ち着け。。。コミットメッセージは --amend で変更出来る。変更しよう。」
```zsh
git commit --amend -m 'GitHubのテンプレートを追加'
```
「`--amend`を使って、まともなCommitメッセージに出来てよかった :sweat_smile: 」


# 参考
- https://www.granfairs.com/blog/staff/git-commit-fix
Go で Stack と FIFO


# はじめに

[Go 強化月間](https://qiita.com/official-events/ae80b010f51f7018891a) と聞いたので Go の記事を書きます。

Go で Stack や FIFO を実装する時には `container/list` を使います。この `container/list` は Stack と FIFO に必要となるベースのみ提供されます。なぜなら Stack も FIFO も仕組みは同じで、取り出す時に先頭か最後かの違いしかないからです。

# Stack

`container/list` をフィールドに持ち、末端に追加、末端から取り出すのが Stack ですね。

```go
package main

import (
	"container/list"
	"fmt"
)

type Stack struct {
	v *list.List
}

func NewStack() *Stack {
	return &Stack{v: list.New()}
}

func (s *Stack) Push(v interface{}) {
	s.v.PushBack(v)
}

func (s *Stack) Pop() interface{} {
	b := s.v.Back()
	if b == nil {
		return nil
	}
	return s.v.Remove(b)
}


func main() {
	s := NewStack()
	s.Push(1)
	s.Push(2)
	s.Push(3)
	fmt.Println(s.Pop())
	fmt.Println(s.Pop())
	fmt.Println(s.Pop())
}
```
https://go.dev/play/p/E7eEVkcQ1m_T

# FIFO

同じく `container/list` をフィールドに持ち、末端に追加、先頭から取り出すのが FIFO ですね。

```go
package main

import (
	"container/list"
	"fmt"
)

type FIFO struct {
	v *list.List
}

func NewFIFO() *FIFO {
	return &FIFO{v: list.New()}
}

func (s *FIFO) Push(v interface{}) {
	s.v.PushBack(v)
}

func (s *FIFO) Pop() interface{} {
	b := s.v.Front()
	if b == nil {
		return nil
	}
	return s.v.Remove(b)
}

func main() {
	f := NewFIFO()
	f.Push(1)
	f.Push(2)
	f.Push(3)
	fmt.Println(f.Pop())
	fmt.Println(f.Pop())
	fmt.Println(f.Pop())
}
```
https://go.dev/play/p/8GGLJXk7kCg

int に限定したい場合は [こんな](https://go.dev/play/p/bDPPOrHaKQr) 感じ。

# まとめ

Go には Stack や FIFO が無い様に見えて実はある、というお話でした。ちなみに FIFO は chan を使っても実現できます。chan は通常、goroutine でデータを通信する為に使われますが、バッファがあれば同一のメイン goroutine 内で FIFO としても使えます。

```go
package main

import "fmt"

func main() {
    fifo := make(chan int, 5)
    fifo <- 1
    fifo <- 2
    fifo <- 3
    fmt.Println(<-fifo)
    fmt.Println(<-fifo)
    fmt.Println(<-fifo)
}
```
https://go.dev/play/p/lY91lVWlm1S
[Splunk] Splunk Enterprise（シングルインスタンス）構築

# 背景
どこでも見られて自身の知識をアウトプットとして残せる場所が欲しいな～と思ったため
手始めにSplunk Enterpriseの構築を行います。

# 目標
windows10上のVM（Virutal Box）上にUbuntuを建て、そこにSplunk Enterpriseを構築する。
Webインターフェースでのアクセスが確認できればOK

# 環境
ホストOS: windows10
VMソフト: virtualbox 6.1
ゲストOS: ubuntu-18.04.6

# 前提条件
- VM上にUbuntu構築済み

# 手順
- deb ファイルをダウンロードしたら、下記のコマンドでインストール。
 ` sudo dpkg -i splunk-8.2.7-amd64.deb `

すると、`/opt`配下に`splunk`というフォルダが作成されています。
環境変数設定 **※任意です※**
`SPLUNK_HOME=/opt/splunk` 

- 以下コマンドを実行して使⽤許諾契約に同意（初回起動時のみ）。
`$SPLUNK_HOME/bin/splunk start --accept-license`
管理者のユーザ名とパスワードが求められるので設定

- 起動しているはずなので、`targetIP:8080`でアクセス **※targetIPはゲストOSのIPです**

- 成功していたら以下のような画面が出ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783871/8cc80c4f-c13f-2462-63b6-5a0c30dc115c.png)

- 設定したIDとPassでログイン
- ログイン成功！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783871/5c35e070-d20d-264d-a988-4ed2cf9fbca0.png)

# まとめ
VM上のUbuntuにSplunk Enterprise（シングルインスタンス）を構築しました。
シングルインスタンスの構築はとても簡単です。（クラスターになると面倒ですが・・・）
【Azure】API Managementの設定ミスで課金した話【予算は大切】

# この記事は

Azure初学者がリソースの設定を間違えて、**想定していなかった課金**をした話です

同じAzure初学者の方がこの記事をみて、**予算の大切さ**を感じ取っていただけたら幸いです

あと、いろいろAzureポータルのキャプチャを載せているので、Azure認定資格初級レベルを受験される方にも少しは役に立つかもです

# 朝起きたらAzureからメールあり

隊員はAzureポータルへ急行せよ！（脳内イメージ）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/6537ca4e-da03-17c7-06b0-2ecb768085f7.png)

# Azureポータルへアクセスして実態を確認

**171円**の利用料発生！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/cb9f9853-81c7-5e02-0837-c6cbaae69441.png)

## 料金が発生しているのはどのリソースだ！？

[API Manegement service](https://docs.microsoft.com/ja-jp/azure/api-management/api-management-key-concepts)でした

これは、[AZ-204資格勉強](https://zenn.dev/t13801206/scraps/591b5824f29687
)のために、お試しでつくったリソース

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/0df9e209-9c6a-387c-c770-316761a41505.png)

## なぜ料金が発生しているのだ？

当該リソースは毎月ワンミリオンの無料枠があるはず・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/5158b93d-429e-9ad4-0582-139d419a841e.png)

### 不正アクセスか！？

メトリクスは凪でした

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/732dc80d-301d-b897-e0c6-81ce9733b22b.png)

#### ワンポイント

API Managementはインターネットに公開せず、仮想ネットワーク内に閉じ込めることが推奨されているようです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/1dfa6167-edcb-7e3a-9b01-2b9214d761b2.png)

# 答え：設定ミス

前述のとおり、AZ-204の勉強をしていて、そのとき参照した[ラーニングパス](https://docs.microsoft.com/ja-jp/learn/modules/explore-api-management/8-import-api)にならってリソースを作ったわけだけど

Azureポータルから手動でリソースを作ったときに、１番下のSKUを`Consumption`ではなく`Developer`にしていた模様

```bash
az apim create -n $myApiName \
    --location $myLocation \
    --publisher-email $myEmail  \
    --resource-group az204-apim-rg \
    --publisher-name AZ204-APIM-Exercise \
    --sku-name Consumption # <<<--- ここ！！
```

## API Managementの価格

- `Consumption`は呼び出しごとに課金、ただし毎月百万回までは無料
- `Developer`は１時間あたり9円の課金　（※為替変動があると思います）

https://azure.microsoft.com/ja-jp/pricing/details/api-management/#pricing

### [料金計算ツール](https://azure.microsoft.com/ja-jp/pricing/calculator/)

`Consumption`の場合、たくさん呼ぶと、あるところからお金がかかる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/255536c8-ab1e-5536-e30d-eacd1298ae15.png)

`Developer`の場合、立ち上げているだけでお金がかかる

36時間立ち上げたときの料金は325円

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/f76a24e4-28bf-5cc2-1912-b00c0f28259a.png)

# リソースを削除したあとの様子

8/13夜にリソース作成、8/15朝にリソース削除

8/14は**24時間分の216円**が課金された

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/5d25fdf3-edd8-a582-5866-dc4d63b77b0c.png)

料金計算ツールでも、たしかに**24時間**でかかる料金は**216円**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/eeb0d832-0f46-c564-d47e-01c510e98ba0.png)

今回の授業料は、しめて**315円**になりました

## 実際の請求書

315円にプラス消費税10%で**346円**になりました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/185d5d83-f9aa-3540-e49c-345d31168214.png)

# おわりに

予算の設定は大切です

プレビュー版ですが、**コスト分析**にアクセスしたらすぐにどのリソースが原因かわかったので、安心しました
ターミナルの＄より左側の長ったらしい部分を消したい～WSL2編

自分用の備忘録。
Mac用の記事は結構あったけど、WSL2ではあまり見なかったので。

WSL2側のOSはUbuntu 20.04.4 LTS。
そのほかに境界条件がわからないので再現性の有無は分からない。
自分はこれでうまく行ったという話。

## 解決すべき課題
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680862/3a60fc51-5c4b-4338-3d77-d9e85bf019ca.png)
本当に長ったらしい……。
これをスッキリさせたい。

## 解決
`bash_profile`をいじったら行けました。
VSCodeで編集したかったので、`code  ~/.bash_profile`でファイルを開く。

```bash:bash_profile
export PS1="\W$"
```
上記を追加すると、現在のディレクトリ名のみが表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680862/a25ae6d6-4d7e-df94-cfdd-b5870355ccf5.png)
超すっきり。

## 応用
```bash:bash_profile
export PS1="\W$"
```
なお。
上記の``\W$``部分を変更することで、$の左側に何を表示するか変えれるらしい。
- ``\w$``だと、現在のディレクトリがホームディレクトリからの絶対パスで表示。
- ``\u$``だと、ユーザー名を表示。
- ``\t$``だと、時刻を表示

などなど。
表示色を変えたりする方法もあるらしいけど、
そこまでする気もなかったので省略。

## 参考
[bashのプロンプトを変更するには](https://atmarkit.itmedia.co.jp/flinux/rensai/linuxtips/002cngprmpt.html)
Excel ファイルを Google スプレッドシートに変換する

Excel ファイル (xlsx形式)を Google Drive にアップロードすると、勝手に Google SpreadSheet に変換されるもんだと思っていたのですが、設定に依るという事を知りました。

https://support.google.com/docs/answer/9331167?hl=ja#2.4:~:text=2.5-,Excel%20%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%20Google%20%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E3%82%B7%E3%83%BC%E3%83%88%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B,-%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%82%80
ユークリッド距離以外でKMeansクラスタリング

## 環境
- Python 3.7.13
- scikit-learn 1.0.2
- nltk 3.7

## scikit-learn で KMeans
PythonでKMeansクラスタリングしたいとき、**scikit-learn** を使うのがポピュラーなのではないかと思います。

https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html

```python
import numpy
from sklearn.cluster import KMeans

data = numpy.array([1,2,3,10,11,21,22,23])
KMeans(n_clusters=3).fit_predict(data.reshape(len(data), 1))
```

```:出力
array([2, 2, 2, 0, 0, 1, 1, 1], dtype=int32)
```

scikit-learnのKMeansはユークリッド距離（euclidean distance、2点間の直線距離）に基づいているようです。[scikit-learnのソースコードを眺めてみると`_euclidean_distances`というメソッドに依存している](https://github.com/scikit-learn/scikit-learn/blob/b90348633605ef22de16c4c274bc62e7f5ab9ff9/sklearn/cluster/_kmeans.py)のが分かります。


## NLTK で KMeans
**NLTK** でも KMeansクラスタリングができます。

https://www.nltk.org/api/nltk.cluster.kmeans.html?highlight=kmeans#module-nltk.cluster.kmeans

```python
from nltk.cluster import KMeansClusterer, euclidean_distance

data = numpy.array([1,2,3,10,11,21,22,23])

clusterer = KMeansClusterer(3, distance=euclidean_distance, repeats=10)
clusterer.cluster(data.reshape(len(data), 1), assign_clusters=True)
```

```:出力
[0, 0, 0, 1, 1, 2, 2, 2]
```

見ての通り、`euclidean_distance`というユークリッド距離算出メソッドを渡しています。ここに別の関数を渡せば、別の距離に基づくクラスタリングができます。


```python
data = numpy.array([(1,1), (0,1), (100,100)])
clusterer = KMeansClusterer(2, distance=euclidean_distance, repeats=10, avoid_empty_clusters=True)
clusterer.cluster(data, assign_clusters=True)
```

```:出力
[0, 0, 1]
```

このように、ユークリッド距離だと例えば`(1,1)`と`(100,100)`は遠いので別のクラスタになりましたが

```python
from nltk.cluster import cosine_distance

data = numpy.array([(1,1), (0,1), (100,100)])
clusterer = KMeansClusterer(2, distance=cosine_distance, repeats=10, avoid_empty_clusters=True)
clusterer.cluster(data, assign_clusters=True)
```

```:出力
[1, 0, 1]
```

`(1,1)`と`(100,100)`のコサイン類似度は1.0で一致する（コサイン距離はコサインから1を引いた値なので、ゼロ距離になる）ため、同じクラスタに属するようになります。

もちろん自前で定義した関数を距離として使うこともできます。

```python
# コサイン距離を自前で定義
def cos_dis(i1, i2):
    return 1 - (numpy.dot(i1, i2) / (numpy.linalg.norm(i1) * numpy.linalg.norm(i2)))

data = numpy.array([(1,1), (0,1), (100,100)])
clusterer = KMeansClusterer(2, distance=cos_dis, repeats=10, avoid_empty_clusters=True)
clusterer.cluster(data, assign_clusters=True)
```

## 参考
- [python \- Is it possible to specify your own distance function using scikit\-learn K\-Means Clustering? \- Stack Overflow](https://stackoverflow.com/questions/5529625/is-it-possible-to-specify-your-own-distance-function-using-scikit-learn-k-means/39442355#39442355)
【初心者向け】Linuxコマンド　とりあえずこれ知ってたらなんとかなる！！

# Linuxでよく使うコマンド

Linuxのセットアップ時やプログラム作成時に用いるコマンドを以下にまとめてみた。
- ### **cd：カレントディレクトリの変更**
カレントディレクトリとは・・・
カレントとは日本語で今。ディレクトリとはフォルダ。
つまり今対象となっているフォルダのこと。
```
目的フォルダへの移動：cd フォルダパス
前の階層へ移動：cd ../
```

- ### **ls：ファイル・フォルダ一覧の表示**
プログラムが実行できないってときはこのコマンドでファイルの権限を要確認
```
ls フォルダパス
よく使うオプション
-a：すべてのファイルを表示
-l：ファイルの詳細がわかる
例
admin@DESKTOP-0V2V6K1:~$ ls -al
-rw------- 1 admin admin  138 Aug  7 22:02 .bash_history
-rw-r--r-- 1 admin admin  220 Jul 27 22:11 .bash_logout
-rw-r--r-- 1 admin admin 3526 Jul 27 22:11 .bashrc
drwxr-xr-x 2 admin admin 4096 Aug  7 22:01 IoT
-rw-r--r-- 1 admin admin  807 Jul 27 22:11 .profile
d：ディレクトリ r:読み取り w:書き込み x:実行
``` 
- ### **chown：ファイル、フォルダの所有者/グループを変更する**
Linuxには様々なユーザーがログインすることを前提にグループとユーザーという概念があり、
chownは指定したファイルの所有者や所有グループを変更することができる。
現在の所有者情報はlsコマンドで確認でき、上記を例にするとadminが所有者ということになる。

``` 
chown 所有者名 ファイルパス
``` 
- ### **chmod：ファイル、フォルダのアクセス権限を変更する**
プログラムが実行できないときにあれ？？って思ったらこれのことが多い。
Linuxのファイルは上記lsコマンドでの説明の通り権限が設定されており、
「所有者」「グループ」「その他ユーザ」という順で権限がrxwで記述されている。
変更方法は下記
``` 
chmod 777(3桁の数字)
r:4 w:2 x:1 の足し算
``` 
- ### **mv：ファイルの移動・リネーム**
ファイル移動は複数ファイルを指定する場合もあるので移動先フォルダの後は"./"が無難
``` 
ファイルの移動：mv 変更前のファイルパス 移動先のフォルダ./
ファイル名リネーム：mv 変更前のファイル名 変更後のファイル名
```
- ### **su -：ユーザーをスーパーユーザー(root)に変更**
ファイル権限の変更時やrootでないと編集できない設定ファイルをいじるときにログイン
```  
su -
sudo：rootにログインせずともroot権限を使えちゃうコマンド
``` 

- ### **apt：debian系のパッケージ管理に用いるコマンド**
```  
よく使うコマンド
更新できるパッケージがあるか確認：apt update
実際に更新：apt upgrade
パッケージを削除：apt remove
``` 
- ### **mkdir：フォルダ作成**
``` 
mkdir　フォルダ名を含むパス
``` 
- ### **touch：ファイル作成**
``` 
touch ファイル名
``` 
- ### **rm：ファイル削除**
``` 
rm　ファイル名
``` 
- ### **tar：アーカイブファイルを作成、展開するコマンド**

``` 
ファイルの圧縮：tar -czvf アーカイブ名.tgz 対象ファイル
ファイルの展開：tar -xzvf アーカイブ名.tgz
``` 
- ### **nano：ファイルを編集する便利なテキストエディタ**
```
nano　ファイルパス
``` 
- ### **systemctl：様々なシステムの停止・起動ができるコマンド**
``` 
サービスの停止：systemctl stop サービス名
サービスの起動：systemctl start サービス名
サービスの再起動：systemctl restart サービス名
```
BufferとTextDecoderの微妙な差

Node.jsの標準で存在する`Buffer`と、WHATWG発祥の`TextDecoder`でそれぞれバイト列をUTF-8として解釈できますが、微妙に結果が違うことに気づきました。

## TL; DR

* 正当なUTF-8となるバイト列であれば、`Buffer`と`TextDecoder`の結果に差は出ない
* 途切れたマルチバイト文字の解釈で、生成される`�`（U+FFFD）の数が違う
* この挙動差に依存するコード自体に嫌な雰囲気を感じる一方、`Buffer`の挙動のほうが一貫している印象を受けた

## 気づいたきっかけ

`Buffer`で書かれたコードを`TextDecoder`に直したところ、テストがコケてしまいました。テストの状況を確認してみたところ、正常系では特に問題がなかったのですが、正しくUTF-8として解釈できないコードで、`�`（U+FFFD）の個数が違っていました。

## UTF-8の構造

正しくないコードについて語るために、ここでUTF-8の構造について整理しておきます。日本語用のシフトJISやEUCでは、1バイト目と2バイト目で同じバイトを使っているために、最悪の場合先頭から読まないと文字の区切りが把握できない、という事態となってしまいます。これに対して、UTF-8では「1バイト目」と「2バイト目以降」で使うビットパターンを区別することで、最悪の場合でも次の文字に行けば同期できるようになっています。

| 16進 | ビットパターン | 役割 |
|:-:|:-:|:-:|
| 0x00 - 0x7F  |  0xxxxxxx | 1バイト文字  |
| 0x80 - 0xBF  |  10xxxxxx | マルチバイト文字の2バイト目以降  |
| 0xC2[^1] - 0xDF  | 110xxxxx  | 2バイト文字の1バイト目  |
| 0xE0 - 0xEF  |  1110xxxx | 3バイト文字の1バイト目  |
| 0xF0 - 0xF4[^2]  |  11110xxx | 4バイト文字の1バイト目  |

なお、0xF8 - 0xFCは、かつてISO 10646が31ビットコードとして定義されていた時代に、5バイト文字や6バイト文字の1バイト目に使われていましたが、のちにISO 10646もUnicodeの範囲まで縮小したため、もはや使われることはありません。また、0xFEと0xFFはBOMの識別用に空けてあります。

### 不正なコード

上の基本ルールに従わない、たとえば「いきなり2バイト目以降が現れた」なども不正なコードですが、それ以外にも不正なものが存在します。

#### 冗長なエンコード

たとえば0xC0 0x80を機械的に解釈するとU+0000に当たるのですが、これは0x00と書けば済みます。セキュリティ上の理由により、このような「必要以上に多くのバイトでエンコードする」ことは禁止されています。

* 2バイト…0xC0 0x80 - 0xC1 0xBF
* 3バイト…0xE0 0x80 0x80 - 0xE0 0x8F 0xBF
* 4バイト…0xF0 0x80 0x80 0x80 - 0xF0 0x8F 0xBF 0xBF

#### サロゲートペア

UTF-16で追加面を表すためにサロゲートペア（前半がU+D800 - U+DBFF、後半がU+DC00 - U+DFFF）が導入されていますが、UTF-16以外の符号化方式でサロゲートペアを使うのは禁止されています[^3]。

* 前半…0xED 0xA0 0x80 - 0xED 0xAF 0xBF
* 後半…0xED 0xB0 0x80 - 0xED 0xBF 0xBF

#### 大きすぎる文字

Unicodeの規格上、最後のコードポイントはU+10FFFF（0xF4 0x8F 0xBF 0xBF）です。これ以降のコードポイントは存在しません。

## 動作検証

実際に規格外のコードを作って動作検証を行ってみました。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="ExEdMbK" data-user="jkr_2255" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/jkr_2255/pen/ExEdMbK">
  Untitled</a> by jkr_2255(すんぶ) (<a href="https://codepen.io/jkr_2255">@jkr_2255</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

ご覧のように、3バイト文字・4バイト文字が2バイト目以降で途切れた場合の結果が違ってきています。

## 考察

[Unicodeの規格書（PDF）](https://www.unicode.org/versions/Unicode14.0.0/ch03.pdf)では、「不正なコードの処理に正当なコードは巻き込まない」ということは決まっていますが、途切れた文字に対していくつの`�`を入れればいいかは規定されていません。

[TextDecoderの仕様](https://encoding.spec.whatwg.org/#utf-8-decoder)を確認してみたところ、変換不能な文字は「気づいた箇所の直前」で`�`に置き換えるような処理となっていました。各種の不正な文字については2バイト目で判定できるので1バイト目だけ`�`として次に進みますが、途切れたパターンでは途切れるまでのシーケンスをまとめて`�`にする、という流れでした。

不正なコードの処理の形に依存するコード自体、筋が悪そうな感じしかしないので、どうでもいい部類の差ではあるのですが、`Buffer`の「不正なコードポイント1つに対して1つ`�`を生成する」と一貫しているのも悪くないなと思いました。

## 脚注

[^1]: 0xC0や0xC1もこの範囲には入りますが、後述するようにこれらのバイトから始まる文字は「冗長なエンコード」となって、正当なUTF-8とはなりません。
[^2]: 0xF5 - 0xF7もこのビットパターンですが、後述のようにUnicodeの範囲からはみ出すので、正当なUTF-8で使われることはありません。
[^3]: 「CESU-8」と称してこのような、UTF-8でサロゲートペアを使うエンコードがなされる例もあります。
【Google App Script】条件分岐（if文）の記載方法

GoogleAppScriptにおける、条件分岐（if文）の書き方について記載します。

## 基本構文
以下の通りです。Javaと同じですね。
~~~if.gs
if(条件式1）{
    // 処理を記載
} else if (条件式2) {
    // 処理を記載
} else {
    // 処理を記載
}
~~~

## 参考
https://auto-worker.com/blog/?p=5631
AWS周りのツール一覧

## はじめに
こんなツールあったのかっていう発見をたまにするので一覧化しておきたかった
使ってて便利そうなものは適宜追加予定

## 一覧

### AWS公式

| ツール名 | 概要 | 言語 | リンク |
|:-:|:-:|:-:|:-:|
| AWS-SDK | ソースコード上からAWSの各サービスのAPIを簡単に呼び出せるようにしたもの。<br>環境変数などから認証情報を取得してトークンを発行してAPIをコールしている。<br>Goはv2、Javascriptはv3が出ている | Go<br>Typescript<br>Javascript<br>Java<br>.NET<br>PHP<br>Python | [リポジトリリンク](https://github.com/aws/aws-sdk) |
| AWS-CDK | プログラミング言語よりCloudformationのテンプレートを生成してデプロイできるようにしたツール | Go<br>Typescript<br>Java<br>.NET<br>Python | [リポジトリリンク](https://github.com/aws/aws-cdk) |
| AWS-CLI | コマンドラインからAWSのリソースを操作できるようにしたもの | shell | [リポジトリリンク](https://github.com/aws/aws-cli) |
| amplify-cli | Amplifyというサービスをコマンドラインから操作するためのツール <br> amplifyを使うとAPIやCI/CD、DB、認証などバックエンド周りをすべて自動で構築してくれて、開発者はフロントエンドの開発に集中できる<br>※万能というわけではない | shell | [リポジトリリンク](https://github.com/aws-amplify/amplify-cli) |
| AWS-Copilot-CLI | アプリとDockerfileさえあればVPCやインスタンス、ロードバランサーを作ってくれるツールで、Manifestファイルを弄ることである程度のカスタマイズ可能 <br> amazon-ecs-cliの後継 | shell | [リポジトリリンク](https://github.com/aws/copilot-cli) <br> [ECSのオペレーションを劇的に簡略化するAWS Copilotが発表されました！](https://dev.classmethod.jp/articles/aws-copilot/) |
| aws-sam-cli | Dockerを使ってAPIGatewayやLambdaをローカルで実行し、動作確認やデプロイを管理するツール | shell | [リポジトリリンク](https://github.com/aws/aws-sam-cli) |
| aws-elastic-beanstalk-cli | AWS Elastic Beanstalkのデプロイと管理を行うためのツール | shell | [リポジトリリンク](https://github.com/aws/aws-elastic-beanstalk-cli) |
| aws-lambda-powertools | Lambdaにおけるコールドスタートのメトリクス取得や、メトリクスをCloudWatch Embedded Metric Formatという仕組みを使ってパフォーマンス影響無しでメトリクスを出力できるなどの機能がある | Typescript<br>Java<br>Python | [リポジトリリンク](https://github.com/awslabs/aws-lambda-powertools)<br>[AWS Lambda Powertools TypeScript がbeta releaseされたので触ってみた。](https://dev.classmethod.jp/articles/aws-lambda-powertools-typescript/) |
| git-remote-codecommit | GRC形式でCodecommitにアクセスするためのツール。AWSアカウントを分けており、スイッチロールしてアクセスしたい場合はこのツールが必須 | - | [リポジトリリンク](https://github.com/aws/git-remote-codecommit) |
| aws-toolkit-vscode | VSCodeからCloudwatchのログを確認したり、S3のファイルをダウンロードしたりできるツール | - | [リポジトリリンク](https://github.com/aws/aws-toolkit-vscode) |
|  aws-shell | AWS-CLIをより便利に利用できるように、コマンドを自動補完できるようにしたもの。例えばEC2のコマンド実行時はオプションやインスタンスIDが候補に現れる。 | shell | [リポジトリリンク](https://github.com/awslabs/aws-shell) |

### 非公式

| ツール名 | 概要 | 言語 | リンク |
|:-:|:-:|:-:|:-:|
| Terraform | AWSだけでなくGCPやAzureをまとめてIaCツールとして管理できるツール | terraform独自 | [リポジトリリンク](https://github.com/hashicorp/terraform) |
| Former2 | 既存のリソースからCloudformationのテンプレートを起こすツールで、手作業で構築したけど複製したり環境を移すときに便利 | GUI | [参考記事](https://dev.classmethod.jp/articles/former2/) |
【#51 エンジニア転職学習】goqueryを使用したスクレイピング

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

本日よりスクレイピングのプロジェクトをつくっていきます。

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


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

# 本日の学習内容
本日はプロジェクトのタスク決め、goqueryの操作をやってみました。
* **プロジェクトのタスク決め　←Topics!!**


# スクレイピングプロジェクトのタスク決め
今回参考にするメイン教材は以下の動画です。
動画はLaravelとgoutteを使用していますが、**Go・goquery・GORM**に置き換えて作成していきたいと思います。

https://www.youtube.com/watch?v=tYbVl6N8oxI&list=PLv6F1QYhG31S-sDkutIQjCnKjFTvjuUus&index=1&t=2049s

### タスク
動画内仕様策定の内容実装することを段階的に設定しました。
1. プロジェクトの構成整理
1. goqueryでURL一覧取得をするハンドラー作成
1. goqueryで各求人情報を取得するハンドラー作成
1. スクレピングしてきた情報をDBに保存
1. MySQLのテーブル2つをCSVに出力
1. データを毎回削除して新規保存する機能追加


ファイル構成は以下で作成していこうと思います。

```
job_offer_scraping/
├── db
│   ├── base.go      -->DBコネクタ、イニシャライザー作成
│   └── dbmodels.go  -->テーブルモデルの作成
├── main.go　　　　　 -->scrapeとDB接続の実行
└── scrape
    └── scrape.go　　-->URLと求人情報スクレイピング
```


# おわりに
最後までお読みいただきありがとうございました。
アドバイス・応援コメント等いただけますと幸いです。
Rubyで可変長配列を実装する

# はじめに

Rubyの[配列](https://docs.ruby-lang.org/ja/latest/class/Array.html)は可変長配列であり、両端キューです。それは `shift`, `unshift`, `push`, `pop` のメソッドを持っている点から明らかです。
ではRubyで可変長配列を実装するとは何を言っているのでしょうか？
それはもしRubyが配列の要素数が増減したときに言語側でメモリの動的確保を行なってくれない言語だったらを仮定して、可変長配列を実装してみました。
両端キューには対応していませんが、C++の[vector](https://cpprefjp.github.io/reference/vector/vector.html)を参考にスタック構造を実装しました。
劣化車輪の再発明でしかありませんが、勉強として作成したためアウトプットします。

# 実装

```rb
class MyVector
  def initialize(*arr)
    @heap = arr
    @size = arr.size
    @max_size = arr.size
    keep_memory(arr)
  end

  attr_reader :heap
  attr_reader :size

  def [](idx)
    @heap[idx]
  end

  def []=(idx, val)
    @heap[idx] = val
  end

  def push(val)
    if @size + 1 >= @max_size then
      keep_memory(@heap)
    end
    @heap[@size] = val
    @size += 1
  end

  alias << push

  def pop
    if @size.zero? then
      raise 'failed'
    end
    @size -= 1
    res = @heap[@size]
    @heap[@size] = nil
    return res
  end

  private
  
  def keep_memory(a)
    arr = a.dup
    @max_size += 1
    @heap = arr.concat(Array.new(@max_size, nil))
    @max_size *= 2
  end
end
```

# usage

```rb
# 初期値が存在する場合
v = MyVector.new(1,2)
p [v.heap, v.size]  # [[1, 2, nil, nil, nil], 2]
v.push 3
p [v.heap, v.size]  # [[1, 2, 3, nil, nil], 3]
v << 4
v << 5
p [v.heap, v.size]  # [[1, 2, 3, 4, 5], 5]
v << 6
p [v.heap, v.size]  # [[1, 2, 3, 4, 5, 6, nil, nil, nil, nil, nil, nil], 6]
p v.pop             # 6
p [v.heap, v.size]  # [[1, 2, 3, 4, 5, nil, nil, nil, nil, nil, nil, nil], 5]

# 初期値が空の場合
v2 = MyVector.new
p [v2.heap, v2.size]  # [[nil], 0]
v2.push 11
p [v2.heap, v2.size]  # [[11], 1]
v2 << 12
v2 << 13
p [v2.heap, v2.size]  # [[11, 12, 13, nil], 3]
```

# おわり

確保している配列の要素数がいっぱいになったタイミングで現在の要素数+1の2倍確保するような実装にしました。
C++の[vector::push_back](https://cpprefjp.github.io/reference/vector/vector/push_back.html)の、

> vectorの実装で行われるメモリ確保戦略では、再確保の際にそれら要素がぴったり収まるサイズを確保するのではなく、少し多めの1.5倍や2倍といったサイズのメモリを確保し、再確保の回数を減らしている。

を参考にしています。
現在の要素数+1なのは、初期値が存在しない場合を考慮してです。

元々の要素を拡張後の配列にコピーするのにC言語ならポインタのポインタを使うかループで新しく作成した配列に詰め直すかしますが、面倒だしconcatがあるのでconcatで実装しました。

C/C++で実装しなかった理由はRubyで書いたほうが処理を理解してもらいやすいと考えたからです。
でも `def [](idx)` や `def []=(idx, val)` の処理って普段見かけない処理なのでイマイチピンとこないですよね。[Ruby 3.1 リファレンスマニュアル 演算子式](https://docs.ruby-lang.org/ja/latest/doc/spec=2foperator.html)を参考にして、コードを読み解いてください。
C++のvectorを見るだけでもまだまだ実装できそうなものはありますが、今回はここで終わります。
読んでいただきありがとうございました。