OmniAICreator/Qiita-1.07M huggingface dataset:
T-SQL で Azure SQL MI のストレージ容量を確認する

# はじめに

Azure SQL MI インスタンスの予約ストレージの容量、使用済み容量、空き容量は、Azure ポータルでカンタンに確認できます。

- SQL マネージド インスタンス > 概要
    - 記憶域使用率

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230264/b0412580-6d49-e4de-b884-72d7e57f7a19.png)

- SQL マネージド インスタンス > [監視] メトリック
    - reserved_storage_mb ... 予約ストレージの容量
    - storage_space_used_mb ... 使用済み容量

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230264/ca6e9d50-bd06-1ffc-3b1a-7a963f462423.png)

https://learn.microsoft.com/ja-jp/azure/azure-monitor/reference/supported-metrics/microsoft-sql-managedinstances-metrics?wt.mc_id=AZ-MVP-5003113

これを PowerShell スクリプトなどでも確認したいです。

たとえば、空き容量が気になる以下のような機会でしょうか。

- DB をインポートする時
- DB をリストアする時

いずれも、十分な空き容量がない場合、「マネージド インスタンスはストレージ制限に達しました。...」というようなエラーメッセージが出力されます。

> Invoke-Sqlcmd : The managed instance has reached its storage limit.The storage usage for the managed instance cannot exceed 98304 MBs. Target database size 76936, current database size 24, used storage space 77056

また、DB をドロップした後、実際のコマンド (たとえば ```DROP DATABASE``` とか) が完了していても、Azure 内部では DB 削除時点のバックアップ取得などの処理が実施されているため、その DB が使用していた領域が解放されるまでにしばらく時間がかかる場合があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230264/0b25db9e-f277-daad-0544-02a6dd5f4e4f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230264/9608e755-fe25-f663-d24c-3a4a9b3a7397.png)

このようなことがあるため、事前に Azure SQL MI インスタンスの予約ストレージ容量、使用済み容量、空き容量を把握しておきたいのです。


# どこから情報を入手するか

```sys.server_resource_stats``` ビューから入手できます。このビューは、15 秒ごとに 1 行のレポートが作成され、5 ～ 10 分以内に収集、集計、更新されます。
よって、このビューから最新の行を参照すれば、直近の情報が得られると考えられます。

https://learn.microsoft.com/ja-jp/sql/relational-databases/system-catalog-views/sys-server-resource-stats-azure-sql-database?wt.mc_id=AZ-MVP-5003113&view=azuresqldb-mi-current

注目すべきは、以下のカラム。
```reserved_storage_mb``` から ```storage_space_used_mb``` を減算することで、空き容量が確認できますね。

| カラム | データ型 | 説明 |
|:-|:-|:-|
| reserved_storage_mb | bigint | Azure SQL MI インスタンスの予約ストレージ容量 (MB) |
| storage_space_used_mb | decimal(18,2) | 使用済み容量 (MB) |
| end_time | datetime | 15 秒ごとのレポート間隔の終了を示す日時 (UTC) |


# ストレージ容量を確認するクエリ

以下のクエリで、Azure SQL MI インスタンスの予約ストレージ容量、使用済み容量、空き容量を確認します。

```sql:Check Storage Space
SELECT TOP 1
  reserved_storage_mb        -- 予約ストレージ容量
  ,storage_space_used_mb     -- 使用済み容量
  ,CAST((reserved_storage_mb - storage_space_used_mb) AS decimal(18,2))
   AS storage_space_free_mb  -- 空き容量
FROM
  sys.server_resource_stats
ORDER BY
  end_time DESC
```

以下は、筆者の環境で上記クエリを実行すると、以下のような結果が得られました。:heart_eyes:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230264/e033053f-3643-7e24-e51e-a198561be468.png)


# 参考文献

https://techcommunity.microsoft.com/t5/azure-sql-blog/how-to-find-out-reserved-and-available-disk-space-on-sql-mi/ba-p/2636930?wt.mc_id=AZ-MVP-5003113

https://techcommunity.microsoft.com/t5/azure-sql-blog/sql-managed-instance-how-tos-series/ba-p/2644958?wt.mc_id=AZ-MVP-5003113
プライバシーマーク クイズ アプリ


## 「PMarkクイズ」アプリがリリース🎉

https://qiita.com/chihiro1020/items/4a85c453d4b88b181a7b

https://qiita.com/chihiro1020/items/7a306f037950ffab5102

こちらの記事を書きながら作成していたアプリが
2023年10月5日10:00にリリースされました！！！

２つの記事からさらに改良を重ね、
プライバシーマークに関する4択クイズを開発しました。

こちらは新人エンジニア🔰が社内の方と協力して、
個人の学習にも、企業の研修にも使えるようなアプリを作成しました。
SwiftUIが初挑戦だったのでかなり苦戦しました...

クイズを作成していると、意外と答えを選ぶのに迷うような問題もあり
改めて、個人情報保護について継続的に学習する事の大切さを認識しました。
この記事を見てくださった方、一度試しにプレイしてみて欲しいです。

また、弊社では他にも多くのアプリケーションを提供しています。
ぜひそちらもご確認ください！




またさらに色々なアプリの開発に挑戦してみようと思います！

次の記事を楽しみにお待ちください♪
Deno で環境変数を設定する方法

# はじめに

Deno で開発している際に、環境変数を設定する方法がわからなかったので記事にまとめてみました。主に以下について記述します。

- `Deno.env` で環境変数を設定する方法
- 標準ライブラリで `.env` ファイルから環境変数を設定する方法
- Deno Deploy で環境変数を設定する方法

また、Denoを触るのは約1年ぶりだったので、その時に新しく学んだ Deno の関連情報も記載しています。

# `Deno.env` で環境変数を設定する方法

Deno には、`Deno.env` という組み込みのオブジェクトが存在します。
`Deno.env.set()` で環境変数を設定し、`Deno.env.get()` で環境変数を取得できます。

```ts:例
Deno.env.set("API_KEY", "examplekey123");

console.log(Deno.env.get("API_KEY")); // examplekey123
```

注意点として、パーミッションが必要なため、`deno run` コマンド実行の際に `--allow-env` オプションが必要です。

https://docs.deno.com/runtime/manual/basics/env_variables

# 標準ライブラリで `.env` ファイルから環境変数を設定する方法

Deno には標準ライブラリがあります。

https://deno.land/std@0.203.0

標準ライブラリ `std` には、様々なモジュールが用意されており、その中に `.env` ファイルで環境変数を設定するためのモジュール `dotenv` があります。

https://deno.land/std@0.203.0/dotenv/mod.ts

dev.ts に以下のように `dotenv/mod.ts` を import すると、 `.env` ファイルを読み込んで、環境変数が設定されます。

```ts:例
import { load } from "https://deno.land/std@0.203.0/dotenv/mod.ts"

await load({export: true}))
console.log(Deno.env.get("API_KEY")) // examplekey123
```

`.env` は以下のように記述します。

```:.env
API_KEY=examplekey123
```

また、 `dotenv/load.ts` を import すると、それだけで `.env` ファイルを読み込んで、環境変数が設定されます。

```ts:例
import "https://deno.land/std@0.203.0/dotenv/load.ts"

console.log(Deno.env.get("API_KEY")); // examplekey123
```

注意点として、パーミッションが必要なため、`deno run` コマンド実行の際に `--allow-read --allow-env` オプションが必要です。

その他、オプションで詳細な設定が可能です。詳しくは公式ドキュメントを参照してください。

https://deno.land/std@0.203.0/dotenv/mod.ts

## Deno Deploy で環境変数を設定する方法

Deno Deploy にデプロイしている場合は、Deno Deploy の Web サイト上で設定ができます。

# Deno Deploy で環境変数を設定する方法

Deno Deploy は、Deno公式のホスティングサービスです。

https://deno.com/deploy

Deno のアプリケーションを Deno Deployにデプロイしている場合は、Deno Deployのプロジェクトの設定ページから、環境変数ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325392/3c895ff9-bd66-051d-41df-1afb52057c11.png)

一度設定した値は再び確認できないので、注意が必要です。

また、設定した環境変数を削除する際に、別の値を設定できます。これにより、既存の変数の値の更新が可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325392/76424f2f-2451-0937-fbd0-5ff82ca4d775.png)

詳細はドキュメントを参照してください。

https://docs.deno.com/deploy/manual/environment-variables

# おわりに

約1年前(2022年夏ごろ)に Deno が個人的ブームだったので、そのときの個人開発で Deno Fresh を使用して作った Webサイトを時々更新する機会があり、今回この記事を書きました。

https://fresh.deno.dev/

最終的に、開発環境では `.env` を参照し、本番環境では Deno Deploy で設定した値を使う形に落ち着きました。

最近では Deno KV という組み込みの key-value データベース の登場など、Denoの開発環境がますます充実してきていることを感じています。今後のDenoの進化と共に、新たな機能やツールが登場することを楽しみにしています。

また、 Bun の v1.0 が先日リリースされて話題になったり、Node.js 以外の JavaScript ランタイムの動きが活発ですね。今後もこれらの動向を注視していきたいと思います。
MySQLのLOAD DATAを許可する

my.cnf（環境によってファイル名が違うかも）にroot権限で下記を追加。ubuntu22は/etc/mysql/mysql.conf.d/mysqld.cnfでした。

```
[mysqld]
local-infile=1
```

さらに、mysqlログイン時にオプションを追加

```
mysql -u username -p --local-infile=1
```

で、インポートしたいテーブルがあるデータベースを選択

```
use this-database;
```

```
LOAD DATA LOCAL INFILE '/home/username/foldername/file.csv' INTO TABLE table-name FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\r\n' (id, company_name, phone, address1, address2, website, email, fax);
```
オーケストレーション



IT用語では、システムやソフトウェア、サービスなどの構築、運用管理を自動化することを指す。 

+ [オーケストレーションのマイルストーンについて](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007HMT9l)

以下のヘルプを見ると静的にステータスを変換できるような組み合わせが定義されているような感じがします。

 

Orchestration Statuses and Milestones
https://help.salesforce.com/s/articleView?id=sf.orchestrator_manage_orchestration_statuses.htm&type=5
LOAD DATA時にフィールドを指定してインポート

LOAD DATAの最後にフィールド名を入れるだけ。

```
LOAD DATA LOCAL INFILE '/home/username/importfile.csv' INTO TABLE table_name FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\r\n' (id, company_name, phone, address1, address2, website, email, fax);
```
クイックヒント: あまり知られていない Pardot と Salesforce の制限事項



+ [Quick Tip: Some lesser known Pardot and Salesforce limitations](https://optimalbusinessconsulting.com/quick-tip-some-lesser-known-pardot-salesforce-limitations/)

**Pardot の制限**

# Pardot カスタム項目の制限

+ 許可される Pardot カスタム項目の最大数は Salesforce によって制限されており、フィールドのエディションやソースに関係なく、組織は 800 個を超えるカスタム項目を持つことはできません…ただし、Summer '23 の時点では、推奨される「実用的な」制限があります。 Salesforce にマッピングできるフィールドの数。
+ 「実用的」という用語を使用しているのは、これが厳しい制限ではなく、Pardot と Salesforce 間の同期の問題を回避するために Salesforce オプティマイザーによって作成された推奨事項であるためです。
+ Pardot から Salesforce にマッピングできるフィールド数の実質的な制限は、Salesforce のリードと取引先責任者全体でマッピングされるプロスペクト フィールド 150 個、および Pardot アカウントと Pardot 商談間で結合されるフィールド 125 個です。これらの制限には、標準フィールドとカスタム フィールドの合計が含まれます。
+ 推奨される制限の理由は、項目数が多い組織は Pardot 同期キューでスタックし、プロスペクトが Salesforce に同期できなくなるためです。
+ 推奨されるフィールド制限を確認するには、[アカウントエンゲージメント設定] > [オプティマイザー] で Salesforce オプティマイザーを実行できます。


# Pardot ジャーニー/育成/エンゲージメント プログラムの制限

+ 移動で許可される最大歩数は 300 歩に制限されています。
+ いくつかのかなり複雑な旅で、この制限に本当にぶつかる寸前になったとき、私たちは驚きました。300 歩以上ある場合は出発できないという警告が表示されました。したがって、この制限に遭遇した場合は、ジャーニーを小さなジャーニーに分割するか、自動化を分けて特定の部分をサブルーチンとして区切ることが最善です。

# Pardot Automation ルールの制限

+ アクティブなオートメーション ルールの最大数は、ご使用のエディションに基づきます: MCAE Growth = 50、MCAE Plus = 100、MCAE Advanced = 150、MCAE Premium = 150。
+ 多くの場合、Engagement Studio プログラムと動的リストを使用してオートメーション ルールの必要性を減らすことができるため、上記のハード制限はそれほど重要ではない可能性があります。
+ オートメーション ルールには、オートメーション ルールごとに 10 個の完了アクションの制限があります。

# Pardot 外部アクティビティ拡張機能の制限

+ アクティブな外部アクティビティ拡張機能の最大数は、エディションに基づきます: MCAE Growth = 0、MCAE Plus = 10、MCAE Advanced = 20、MCAE Premium = 30。

# Pardot インポートの制限

+ Pardot インポートの CSV ファイルの最大サイズは 100MB です。
+ この制限に何度か遭遇しました。簡単な解決策は、インポートする前に CSV ファイル内の不要な列と行を削除して、ファイル サイズを小さくすることです。多くの場合、インポートする必要があるのはいくつかのフィールドのみです。これが現実的でない場合は、単一のファイルをインポート用に複数の小さなファイル (import1of3、import2of3、import3of3) に分割する必要があるかもしれません。

# Pardot プラットフォームとコネクタの制限

+ 複数の Pardot 組織 (または「インスタンス」) を 1 つの Salesforce 組織に接続できますが、複数の Salesforce 組織を 1 つの Pardot 組織に接続することはできません。実際、Pardot を Salesforce サンドボックスに接続する場合、再接続するまで、Pardot は SF 本番組織から切断されます (再接続する前に、サンドボックスのテストデータを手動でクリーンアップする必要があります)。

# Pardot ビジネスユニットの制限

+ 含まれるビジネス ユニットの最大数* は、ご使用のエディションに基づきます: MCAE Growth = 0、MCAE Plus = 0、MCAE Advanced = 2、MCAE Premium = 5。
+ 上記の数値は各エディション層に含まれる数値であり、プランによっては追加のビジネス ユニットを購入できる場合があります。

# Pardot メールテンプレートビルダーの制限

+ 言うまでもなく、クラシック Pardot メール テンプレート ビルダーには、ドラッグ アンド ドロップができないなど、多くの制限があります (「HubSpot と Pardot の比較…どちらが優れていますか?」に関するブログ投稿を参照してください)。
+ Lightning Email Template Builder の API サポートはなく、API を使用して Lightning Email Template Builder メールテンプレートを作成することはできません。たとえば、API を使用して HTML 値フィールドを更新すると、電子メール テンプレート ビルダーの値は同期されなくなります。

+ Lightning メールテンプレートビルダーとメールコンテンツビルダーには、次の制限があります。

   + 電子メール テンプレートまたは電子メール コンテンツ レコードごとに 250 コンポーネント
   + リージョンあたり 100 コンポーネント (コンポーネント コンテナー)
   + 各コンポーネントのプロパティ値に 10,000 文字

HTML コンポーネントの [HTML 値] フィールドで [形式]をクリックすると、 文字数制限を超える場合があります。その場合、テンプレートを保存することはできません。書式設定を元に戻すか、HTML を短くして、コンテンツの残りの部分に別の HTML ブロックを追加します。
Crystal本体にタイポフィックスでコントリビュートする話

## はじめに

> Crystal言語が好きです。（使いこなしているとは言ってない）
> Crystal言語本体にコミットして、コミット履歴に名前を残したいです。
>
> でもCrystal本体に貢献するぐらいのスキルはありません。
> どうすればいいですか？

https://github.com/crystal-lang/crystal

というお便りが、届いておりません。しかし、届いたつもりで回答します！

## タイポフィックスなら誰でもできる

そこで、タイポフィックスを狙います。タイポフィックスとは、単語のスペルミスなどを修正することです。

世の中には便利なツールが公開されています。typo検出コマンドラインツールとかちゃんとあるんですね。

https://github.com/crate-ci/typos

これを利用して、Crystalのコードからタイポを探します。

## プルリクエストを送る

実際に typos を用いてタイポを発見したのでプルリクエストを送りました。

https://github.com/crystal-lang/crystal/pull/13850

こちらは、Crystalの利用中に気がついたエラーメッセージ中のtypoです。

https://github.com/crystal-lang/crystal/pull/13764

これらのタイポ修正のプルリクエストはすでに本体にマージされます。

## 気をつけること

`lib` ディレクトリの中にもタイポは見られますが、これらは外部のライブラリなので、Crystalのリポジトリの中では修正できません。これに気がつかずにホイホイプルリクエストを出しましたがクローズされました。

https://github.com/crystal-lang/crystal/pull/13851

## まとめ

こんな感じで、スキルがなくてもCrystalのリポジトリにはコミットできます！

Crystalは非英語圏の人たちが中心になって開発していることもあり、まだPRが送られていないタイポも複数残っているとみています。
コントリビューション・チャンスです。

みんなCrystalにプルリクエストを送って、コミット履歴に名前を残そう。

この記事は以上です。
AZ-104試験対策のまとめ「Storage Account編④」

## はじめに
Microsoft Azure Administrator(AZ-104)合格に向けた勉強でまとめた内容を本記事では投稿しています。
試験範囲の内容を私が勉強していく中で、
・忘れてしまっていた内容
・他の知識と絡めて理解した方が良い内容
・Microsoft Learnの読解に苦戦した内容
などをできるだけ分かりやすく簡潔にまとめることを意識しています。
Azureの勉強を一から始め、AZ-104取得を目指している方の参考になれば幸いです。
※本記事の内容が必ず試験に出るわけではないこと、ご注意ください

## 試験対策のまとめ
### **共有アクセス署名(SAS：Shared Access Signatures)**
Storage Account内のリソースへのセキュリティで保護された委任アクセスが可能になる  
* SASによる制御の例
    - クライアントがアクセスできるリソース
    - アクセス先のリソースに対するアクセス許可
    - SASの有効期間
* SASの形式
    - アドホックSAS
        - 開始時刻/有効期限/アクセス許可をSAS URIで指定可能
    - 保存されているアクセスポリシー
        - リソースコンテナ(BLOBコンテナ/テーブル/キュー/ファイル共有など)で定義
        - 1つ以上のSASの制約を管理可能
        - 定義されている制約(開始時刻/有効期限/アクセス許可)を関連付けたSASが継承

#### SASの種類
|  | ユーザー委任SAS | サービスSAS | アカウントSAS |
| --- | :---: | :---: | :---: |
| SASトークンへの署名 | ・Azure AD資格情報 <br>・SASに指定されたアクセス許可 | Storage Accountキー | Storage Accountキー |
| 委任対象のリソース | BLOBストレージ | 1つだけのストレージサービス | 1つ以上のストレージサービス |
| アドホックSAS | ○ | ○ | ○ |
| 保存されているアクセスポリシー | × | ○ | × |

#### アカウントSASにおけるSASトークン必須パラメーター
* SignedVersion(sv)：承認に使用する署名付きストレージサービスのバージョンを指定
* SignedServices(ss)：アクセスできる署名付きサービスを指定
    - BLOB = b
    - キュー = q
    - テーブル = t
    - ファイル = f
* SignedResourceTypes(srt)：アクセスできる署名付きリソースのタイプを指定
    - サービス = s
    - コンテナ = c
    - オブジェクト = o
* SignedPermissions(sp)：アクセスできる署名付きアクセス許可を指定
    - 読み取り = r
    - 書き込み = w
    - 削除 = d
    - 永久削除(BLOBオブジェクトリソースタイプのみ) = y など
* SignedExpiry(se)：SASが無効になる時刻
* signature(sig)：アクセスを承認するための署名部分

<br>

* 参考
    - https://learn.microsoft.com/ja-jp/azure/storage/common/storage-sas-overview
    - https://learn.microsoft.com/ja-jp/rest/api/storageservices/create-account-sas

## 次の試験対策のまとめ
* **AZ-104試験対策のまとめ「データ転送編」**

https://qiita.com/fsd-jume/items/6308435c4672a9c2992f

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/6eda24728c9c03c36bc3
Set Up Salesforce Payments


+ [Setting up Digital Experiences](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007KZNwN)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/513a9f62-58bc-2a75-0441-5b5d74e1ad41.png)

単に有効化できてないだけ？
三項演算子

# 三項演算子について

この前初めて三項演算子というものを知りました。(恥ずかしながら。。)

簡単に書いておきます。
```条件式?真の式:偽の式``` 
というのがベース
例
```
$num1 = 100;
$num2 = 200;

$ans = $num1 < $num2 ? 'num1はnum2より小さい' : 'num1はnum2より大きい';
```
という書き方になります。

この場合はnum1の方がnum2よりも小さいという条件式が真になるので画面には
「num1はnum2より小さい」と表示されます。
Brain で家族計画を動かす

Brain で えろげー する。

![kazoku.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821068/c65c413a-77d7-324d-1114-90746b7ea461.png)

## 動作しない原因
- ディレクトリ名に日本語を含むことが原因でした (日本語版 WindowsCE が必要)
  なので、いつものように アプリ ディレクトリにはコピーせず、CeOpener から手動で呼び出します

## 動作させるために必要なもの
- [CeOpener （改造版）](https://ho.ie-t.net/it/brain/ceopener_mod/)
- [偽gx.dll](https://qiita.com/nekopro2/items/9a44e8f28e52c1eb5b02)
- akirappc130.lzh (当時の物)
- Windows版 家族計画 のCD-ROM

## 動かし方
1. CeOpener をダウンロードして Brain に転送する
1. Brain の本体ルートに xkazoku フォルダを作成、Akira.exe と gx.dll、変換済データをそのまま入れる
   ![dir.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821068/9aa0d043-0c94-52f5-db23-476663e140c8.png)
1. CeOpener を起動する
1. スタートから[実行...] を選択する
   ![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821068/3f8635b8-5aba-53e4-c05e-e37624ca0a06.png)
1. ファイル名を指定して実行で [参照(B)...] を選択
   ![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821068/de82da72-5d51-510e-0a9d-fb0244fbc110.png)
1. \NAND3\XKAZOKU\Arika.exe を指定して [OK] を選択
   ![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821068/0b6a6101-66a3-414e-ad57-6fb8ea214802.png)
1. [OK] を選択して起動する
   ![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821068/d0cf3d71-613a-fa1c-7c1a-a8eb2d83b51b.png)

## さいごに
- これ作ったの20年前かー(超遠い目
hotstring を利用して、今日の日付を「年月日＋曜日」の形式で素早く入力する - AutoHotkey v2

# はじめに

この記事では、AutoHotkey v2 で hotstring を利用して、今日の日付を「年月日＋曜日」の形式で素早く入力するプログラムを学習します。
エディタで今日の日付を手動で入力するとき、カレンダーを確認せずに素早く入力できるようになります。

## AutoHotkey v1.1 利用者が詰まる要所

v2 では後方互換性は犠牲となっており、v1.1 のために書かれたスクリプトは基本的に動作せず、改修の必要があります。

# 必要な前提知識

AutoHotkey v2 は Windows で動作する、自動化に役立つツールです。

## インストール

### AutoHotkey

[AutoHotkey](https://www.autohotkey.com/) をダウンロードします。このプログラムは v2.0 で書かれているので、ダウンロードページで「Download v2.0」の方をダウンロードし、動作させる Windows 機にインストールします。

### AutoHotkey Plus Plus

VSCode をご利用の方は、「[AutoHotkey Plus Plus](https://marketplace.visualstudio.com/items?itemName=mark-wiemer.vscode-autohotkey-plus-plus)」をインストールしましょう。コーディングが快適になります。

#### コマンド

AHK++を使用すると、キーボードショートカットを使用してスクリプトをコンパイル、デバッグ、および実行できます。選択範囲をスタンドアロン スクリプトとして実行することもできます。

- デバッグ：Ctrl + Alt + F9
- ヘルプを開く:Ctrl + F1
- 実行：Ctrl + F9
- 選択範囲の実行:Ctrl + F8

# 手順

## 実装する内容

「w[[」と順番に入力すると、例として「2023 年 10 月 4 日(水)」と入力されるようにします。

## コード

```:info-v2.ahk
;w[[ → 年月日＋曜日を入力する Hotstring  本体
::w[[::
{
    TimeString := FormatTime(,"LongDate")
    downum := FormatTime(,"WDay")
    dowstr := get_dowstr(downum)
    A_Clipboard := TimeString . dowstr
    Send "+{INSERT}"
}
;曜日をカッコつきで返す関数
get_dowstr(theNum)
{
    dowtable := "日月火水木金土"
    ; Wday は日曜日が 1、
    dowstr := SubStr(dowtable, theNum, 1)
    return "(" . dowstr . ")"
}
```

```
::w[[::
{コード}
```

- Hotstring は、連続して入力する文字を、「::」で囲います。実行する内容が複数行にわたる場合、中括弧{} で囲います。これがないと、「Error: Hotkey or hotstring is missing its opening brace.」が表示されます。

`TimeString := FormatTime(,"LongDate")`

- 変数「TimeString」に、今日の日付を"LongDate"のオプションを使って"yyyy 年 MM 月 dd 日"の形式で代入します。

`downum := FormatTime(,"WDay")`

- 変数「downum」に、今日の曜日を代入します。形式は 1 ～ 7 で、1 が「日曜日」、数字が上がるごとに火水木と続いて 7 が「土曜日」になります。

`dowstr := get_dowstr(downum)`

- 変数「dowstr」に、get_dowstr() 関数を使って引数の「downum」で曜日を指定し、「(曜日)」の形式で曜日を取得します。

```
A_Clipboard := TimeString . dowstr
Send "+{INSERT}"
```

- クリップボードに「年月日＋曜日」を代入して、「(クリップボードを)貼り付け」を実行します。

`get_dowstr(theNum){}`

- 曜日を WDay の形式で受け取り、「(曜日)」の形式で曜日を返す関数です。

```
dowtable := "日月火水木金土"
dowstr := SubStr(dowtable, theNum, 1)
```

- 変数「dowtable」に、日本語の曜日を日曜日から一文字ずつ並べて代入します。
- 変数「dowstr」に、指定された曜日を日本語で代入します。SubStr() は指定された文字列から、開始位置「theNum」を 1 文字だけ抜き取って値を返します。

`return "(" . dowstr . ")"`

- 指定された曜日を日本語化して、小カッコでくくったものを返します。

# 注意点

- 曜日の取得に`FormatTime(,"ddd")`を使えば曜日を数値ではなく単語で取得できるので、コードをもっと短く記述できます。ただし、オプション「ddd」は、利用しているパソコンの言語設定に依存するため、例えば英語を選択している場合は英語の曜日が出力されるので結果が変わってしまいます。
- 自作関数は「get_dowstr(theNum){}」のように、実行内容を中カッコでくくります。

# 結論

- この Hotstring を使えば、今日の年月日を知らなくても、「w[[」と入力することで今日を指す年月日＋曜日を入力することができます。
- AutoHotkey をインストールした後に付属する「Ahk2Exe」を使えば、AutoHotkey のプログラムを.exe 化できます。それを利用すれば、AutoHotkey をインストールしていない Windows 機でも hotstring が使えるようになります。
- また、作成した.exe ファイルを「Windows 10 の起動時に自動的に実行するアプリ」として登録しておけば、起動時に自動的に立ち上がり、hotstring が利用可能になります。
GASを使ってプリザンターにGoogleスプレッドシートの内容を登録する

# はじめに
GAS(Google Apps Script)を使って、Googleスプレッドシートの内容を [プリザンター](https://pleasanter.org) に登録することができます。

## 事前準備
1. プリザンターの [デモ環境](https://pleasanter.org/demo) に登録します。
1. テーブルを作成してURLに含まれるサイトIDを控えます。
1. [APIキーを作成](https://pleasanter.org/manual/api-key) します。
1. Googleスプレッドシートを作成します。
1. A1セルにAPIキーを入力します。
1. A2～A4セルにテストデータを入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78230/d9e0f2a2-d5c6-8bd3-812c-9038c6cb00fe.png)

## サンプルコード
プリザンターの [デモ環境](https://pleasanter.org/demo) で動作するGASのコードです。
```
function apiCreate(i) {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getActiveSheet();
  var apiKeyRange = sheet.getRange(1, 1);
  var titleRange =  sheet.getRange(i, 1);
  var data =
  {
    "ApiKey": apiKeyRange.getValue(),
    "Title": titleRange.getValue()
  };
  var options =
  {
    "method" : "post",
    "contentType": "application/json",
    "payload" : JSON.stringify(data)
  };
  var response = UrlFetchApp.fetch("https://demo.pleasanter.org/api/items/1234567/create", options);
}

function myFunction() {
  for (let i=2; i<5; i++) {
    apiCreate(i);
  }
}
```

## 補足情報
- 事前準備で作成したテーブルのURLに含まれるサイトIDを指定しています。
- テストレコード1～3をループして1件ずつレコードを作成しています。

## 動作結果
GASを動作させると、テストレコード1～3がプリザンターのテーブルに登録されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78230/da6a1bf4-d3d6-cb52-a15e-6b2ecfe19854.png)
Pipenvの使い方

# Pipenvとは
プロジェクトごとに自動で仮想環境を作成し、仮想環境ごとにパッケージ管理を行うことが出来るライブラリ。
他のプロジェクトに影響させることなく、そのプロジェクト専用の環境を作ることが出来る。

# 実行環境
- windows10
- python 3.8.7

# 事前準備
- pythonのインストール
[公式サイト](https://www.python.org/downloads/windows/)から必要なバージョンを選択してダウンロードする。
ダウンロードファイルを実行し、セットアップウィザードに沿ってインストールする。

- pipのインストール
ターミナルでpip --versionとコマンド実行し、バージョン番号が表示されればOK。（Python3.4以降は標準搭載）
```:ターミナル
pip --version
実行結果：pip 20.2.3 from c:\users\***\.pyenv\pyenv-win\versions\3.8.7\lib\site-packages\pip (python 3.8)
```


# Pipenvをインストール
以下コマンドを実行してバージョン表示されることを確認。

```:ターミナル
pip install pipenv  
pipenv --vesion

実行結果：pipenv, version 2023.9.1
```

# 仮想環境を作成
- プロジェクト用のフォルダを適当な場所に作成し、その中に移動する。
- 以下コマンドを実行する。

```:ターミナル
pipenv --python 3.8　（※事前準備でインストールしたPythonバージョン）
```

上記移動先フォルダいかにPython3.8で動く専用の仮想環境が用意される。
同時にPipfileとPipfile.lockという名前の2つのバージョン管理ファイルが自動生成される。

# 仮想環境に入る
- 以下コマンドを実行
```:ターミナル
pipenv shell

----実行結果----
Launching subshell in virtual environment...
Microsoft Windows [Version 10.0.22621.2283]
(c) Microsoft Corporation. All rights reserved.
```
プロジェクト専用の仮想環境が動作する。

# パッケージインストール
- 以下コマンドを実行
```:ターミナル
pipenv install <パッケージの名前>
```

仮想環境で使用するためのパッケージがインストールされる。
インストールしたパッケージは、仮想環境作成時に自動生成された「Pipfile」に記述され、このファイルでバージョン管理されていく。
コマンドプロンプト(bat)のコマンドの由来一覧

覚えやすくするための自分用メモです。 ※推測を含みます。
プログラミングの組み込み関数名の由来一覧とかそういう記事もっと増えて欲しいなあ。

# rem (コメント)
remark 意見

# echo (文字出力)
echo 反響
コマンドラインにおいて入力した文字がそのまま返ってくることから

# 変数からの読み取り
`%~f` full path フルパス
`%~d` drive letter ドライブ文字
`%~p` path name パス名(ファイル名なし)
`%~n` name ファイル名(拡張子なし)
`%~x` extension 拡張子
`%~t` time 更新日時
`%~z` si(z)e? ファイルサイズ
動いているEC2を全部問答無用で停止するLambda

## さくっとコピペでどうぞ

```python:python
import json
import boto3

client = boto3.client('ec2')

def lambda_handler(event, context):
    response = client.describe_instances(
        Filters=[
            {
                'Name': 'instance-state-code',
                'Values': [
                    '16',
                ]
            },
        ]
    )
    targetInstances = []
    for i in response['Reservations']:
        targetInstances.append(i['Instances'][0]['InstanceId'])
    
    if not targetInstances:
        return "nothing target instances"
    else:
        response = client.stop_instances(
            InstanceIds=targetInstances,
            Force=True
        )
        return response
```

## 解説

desclibe_instancesで動作状態（Statuscode:16）のEC2インスタンスを全部取得して、そこからinstanceIDのみを配列にして、stop_instancesに渡して終わり。

環境に左右されない作りだと思うのでどこでも使えると思います。
強いて言うならEC2の台数が多くなると正常に動かないかも。（X>50？わかんない）
その場合はpagenatorとかで取得動作自体がループするAPIに差し替えれば行けるはず。

あと、LambdaからEC2のAPIを叩けるようなIAMの権限設定だけはお忘れなく。

EventBridgeでスケジューラ作って動かしたら幸せになれるかも。
AWSの最新アップデートを楽しく追いかける方法

クラウドサービスのAWS、毎日のように多数の機能アップデートがあり、追いかけるの大変ですよね！

https://aws.amazon.com/jp/new/


# そもそも最新情報なんてずっと追わなくてよくない？

そんなことないんです！ アップデートを毎週追っているとメリットも多数。

- 常に最新機能に詳しくなれる。業務にも生きる
- 最新情報をきっかけに普段触れていないサービスにも詳しくなってくる
- 同僚やコミュニティの仲間と毎日ワイワイ盛り上がれる。大きなアプデ時はお祭り！

昨日まで案件で悩んでいた技術制約が、今朝のアップデートでめでたく解消…みたいなサプライズもあったりするのがクラウドの面白いところでもありますよね。


# アップデートってどこを見ればいいの？

### What's New at AWS

https://aws.amazon.com/new/

日本語環境でアクセスすると日本語ページにリダイレクトされると思います。
残念ながら本当に最新のアップデートは英語でしか出ておらず、2週間ほど経ってから日本語版になっています。なので最新の英語What's Newを見たい場合、ページ内の言語切り替えを「English」にしてから確認しましょう！

また、有志が運営している非公式のTwitter版もあります。

https://twitter.com/awswhatsnew


### AWS News Blog

https://aws.amazon.com/blogs/aws/

大きめのアップデートなど、長文＋画像やコード付きで補足解説がされるのがこちらです。
数日で日本語化されるものが多いですが、最速は英語版となります。

日本語版は以下。

https://aws.amazon.com/jp/blogs/news/



# オススメの咀嚼情報

上記は公式情報なので「もっと噛み砕いた言葉で優しく教えてよ！」って方におすすめの情報源も。

### 週刊AWS

公式寄りではありますが、AWS JapanのSA（ソリューションアーキテクト）さんが大きめのアプデを中心に毎週、日本語でまとめてくださっています。

https://aws.amazon.com/jp/blogs/news/tag/%E9%80%B1%E5%88%8Aaws/


### DevelopersIO

言わずと知れたクラスメソッドさんのエンジニアブログです。特に大きめのアップデートは超速で記事を出してくれていることが多いです。

https://dev.classmethod.jp/tags/aws/


### しまがじ！

SimStaさんの個人ブログですが、AWSのアップデートを分かりやすく随時まとめてくださっています。元ネタをつぶやいてくれているTwitterの方も注目！

https://alta-whitechip.name/category/aws/

https://twitter.com/shimagaji



# アップデートの種類

### 大型アップデート

出たらみんなTwitterでわちゃわちゃするやつです。AWS Blogも同時に出されることが多し


### ちょっとした機能改善など

そのサービスを使い慣れてないと「何が嬉しいの…？」と分かりづらいものも多いですね


### 既出機能の対応リージョン追加

これも地味に数が多いです。

- ローンチされたばかりのリージョンへの追いつきアプデ（最近だとイスラエルのテルアビブリージョンなど）
- 各地域の第二都市的なポジションのリージョン軍への機能拡充（日本だと大阪リージョン）


# キャッチアップ会をやってみよう！

### 既存のイベントに参加してみる

以前はAWSのSAさんを中心にアップデートを毎週ラジオ風に解説するTwitterスペース「オハヨーAWS」がありましたが、少し前に休止してしまいました。

代わりに最近、AWSコミュニティのJAWS-UGで有志がキャッチアップ会を開催しています。

https://jaws-ug.doorkeeper.jp/events/164381


### 自分で会を企画してみる

また、ご自身の職場やコミュニティなどでWhat's New会を開いてみるのもすごく面白いですよ！

私も自分の職場で月に数回、3名程度でラジオ風にZoom雑談するキャッチアップ会を部署横断のクラウドコミュニティ内で配信しています。パーソナリティは色んな部署の仲間から毎回変えてみています。（以下は @yoshii0110 @sandshiP とやった回です🙌）
![お昼のクラウドニュース会 4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/e336eb2a-d31d-05b7-0857-d064659e77c6.png)

### What's New会を企画するときのコツ

- なるべく事前準備しない会にする（重いと続かない。その場でWhat's Newを開いて雑談する）
- 初歩的なところから素直に質問しあう（そもそもこのサービス何だっけ？ xxと何が違うの？ 等）
- AWS以外のアップデートも扱ってみる（例：はてなブックマーク等のITニュース、Azure等の他クラウド、生成AIなど）

「素朴な疑問をぶつけ合う」ことが出来れば学びを得られるので、AWSに詳しくなくても会としてちゃんと成立するのがポイントです。恥ずかしがらずに思い切ってやってみましょう！ めちゃくちゃ勉強になりますよ。
JSON を最も簡単にブラウザで表示する方法

API から返ってきた JSON をブラウザに表示して確認したいこと、ごくまれにありますよね。

```tsx
import { useJson } from "@/api";

export function Page() {
  const { data } = useJson();

  return (
    <>
      <div>data:</div>
      <pre>{JSON.stringify(data, null, "\t")}</pre>  {/* ← これだけ */}
    </>
  );
}

```
【Python】sounddeviceモジュールを用いたwavファイルの再生

# 概要
Python でwavファイルを再生する方法をメモしておきます。
PyAudio などを使用する方法もありますが、今回は sounddevice モジュールを使用します。

# ファイルの読み込み・再生
今回は wave モジュールではなく、 ```scipy.io.wavfile``` を使用し、ファイルを読み込みます。
```sd.play(data, sampling_rate)``` でファイルを再生します。

```python: test.ipynb
import scipy.io.wavfile as wav # 今回はwaveモジュールではなくこれを用いる
import sounddevice as sd

wav_file_path = "./wav/test_sound.wav" # ファイルのPath
fs, data = wav.read(wav_file_path) # サンプリング周波数(fs)とデータを取得
sd.play(data, fs)
```

```sd.play(data, fs)``` 中の ```fs``` は省略できるっぽいんですが、音声が速すぎたり遅すぎたりして再生される場合があるらしいので、実装ではこの通りに記述しておきましょう。（参考：[sounddeviceドキュメント](https://python-sounddevice.readthedocs.io/en/0.4.6/api/convenience-functions.html#sounddevice.play)）

# 再生を停止
再生中に以下を実行すると、再生を停止することができます。
```python:test.ipynb
sd.stop() # 再生を停止
```
MacのSafariのブックマークが同期しない件

### 新しいMacBook Proを購入しました。

元のMacBook Proはほとんど素のまま使っており、移行は手作業ですぐに済む想定。
ただし、Safariのブックマークがなぜか半分ほどしか同期しない。

システム設定のiCloudで、Safariの項目のオンオフを何度か繰り返し、
Macの再起動も行うが改善せず。

諦めかけたのですが、ダメもとでApple IDを一度サインアウト、サインインすることで
同期されました。
なぜChatGPTが会話できるのか？誰でもわかるように説明します！

# 背景
ChatGPTがなぜ0から会話できるようになった流れを細かくわかりやすく説明したいと思います。
ネットで調べてみると、意外とChatGPTに関するシンプルな説明が少なく、一番最初から詳しく解説する記事も少いような気がします。
ですので、私が理解しているChatGPT（他の言語モデルも同じく）の全体的な中身を0から1まで説明してみたいと思います。
*認識が間違っているところもあると思いますが、ぜひコメントで教えていただきたいです。

# 1.まず最初の最初、「モデル」から話ししたいと思います。
モデルは一番最初の段階では、ただのランダムな数字で構成されています。（ウェイト(Weights)という概念をわかればより簡単に理解できると思いますが、実は正規分布でランダムに初期化されたWeightsで構成されています。でも数字として理解しても特に問題ないかと思います）
なので、この時点のモデルは何にも知らず、何も理解できないです。例えば、「How are you？」をinputすると、「1?<L+L#&」のような何でもないoutputが出てくると思います。
![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/0e6c4b28-00c1-2fda-af03-9e3dbe984c84.jpeg)

# 2.プレトレーニング（Pre-training）
ここからモデルは、インターネットから収集されたものすごい膨大なデータを使って学習をスタートします。学習よりはデータを全部自分の中に入れるようなイメージです。（ここで入れるデータはunlabeledと呼ばれます。なぜかというと、わざと準備されたデータではないからです。）
*GPT-3の場合は、学習データは約3,000億の単語で、31億のサイトの内容を含んでいました。メインとなっている言語は英語で、全体の約46%を占めています。一方、日本語は約5%でした。なので、今ChatGPT4になっても英語は一番性能が強いです。

次のステップは自己教師あり学習(Self-supervised learning)です。これは自然言語処理のベースとなっている、非常に有名なTransformerのSelf-attention（単語と単語の間の関係性を理解する）アーキテクチャに基づいてます。
自己教師あり学習で行う作業は、非常に単純で、「一つの単語（token）につなぐ次の単語を予測する」ことだけです。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/0ae71b43-28b8-66b0-2292-3d37d854e7a9.png)


この単純すぎる作業を数百億回以上自己訓練後、How の後はare、areの後はyou,モデルはHow are youのようなフレーズを予測できるようになりました。どちらかというと、いきなり言語力をできたような感じです。（ですので、モデルが言語力を身につけることは本当に偶然なことです。こんな単純作業を繰り返すだけで会話能力を持つAIが現れるとは想像できませんでした。不思議ですね）
*ちなみに、OpenAIは0からGPT3.5まで約5年ほど学習しました。

この時点のモデル（Base model）はものすごいデータを学習しましたが、まだ会話する能力はないです。「How are you」をinputすると、「How are you?what’s your name?where are you from?.....」みたいな関係ないoutputが出てきます。なぜかというと、モデルは「How are you」を見たことありますが、それが質問としての回答を求められていることを理解していないためです。そのため、outputは文字化けにはならないですが、適当に学習データで見た内容をoutputするような状態です。

# ③ファインチューニング(fine-tuning)
会話できるChatbotになるために、fine-tuningが必要です。つまり、GPT3.5からChatGPT3.5に進化することです。
fine-tuningによって実現できることは主に2つがあります。
一つはモデルの行動をコントロールし、明確な指示や条件をモデルに与えることです。例えばChatGPTなら、人間と会話してほしいという指示を覚えさせます。
もう一つは、モデルの性能アップで、プレトレーニングで学んだ間違ってる内容を直すとか、新たな知識を得ることです。

ファインチューニングには必要なデータ量が非常に少なくなります。（まだまだ多いですが、プレトレーニングと比べるとわずかくらいなレベルです。）
モデルを特別な指示に対応できるようになりたいために、特化したデータセットを使って学習します。（例えば画像系ならよく使われるImageNetを学習させて、画像系のタスク対応できるようなLLMになるとか）
![3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/141ecaff-b2be-e55e-bf69-aaafd988b370.jpeg)


この時にやる作業はプレトレーニングの際と変わらず「一つの単語につなぐ次の単語を予測する」ことだけです。
ただ、変わったことはweightsに対しての調整で、一部を調整するではなく、全体的なweightsを一括で調整することです。こうすると、モデルのoutputはなってほしいストラクチャー（この問に対してはこの回答してほしいとか）に少しずつ近づきます。

fine-tuningができた時点で、やっとモデルが「How are you」に対して「I am fine」を回答することをわかって、GPTが会話できるChatGPTになりました。

END
![4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/136ba26f-f5ad-ecaf-c325-76596508c3aa.jpeg)
【TailwindCSS】親要素や兄弟要素の状態に基づいてスタイルを設定する

## 親要素の状態に基づいてスタイルを設定する

以下のように`group`を使用すると親要素に基づいてスタイルを設定できます。

```html
<!-- 親要素にgroupを記述して子要素にgroup-hoverなどを記述する -->

<a href="#" class="group block max-w-xs mx-auto rounded-lg p-6 bg-white ring-1 ring-slate-900/5 shadow-lg space-y-3 hover:bg-sky-500 hover:ring-sky-500">
  <div class="flex items-center space-x-3">
    <svg class="h-6 w-6 stroke-sky-500 group-hover:stroke-white" fill="none" viewBox="0 0 24 24"><!-- ... --></svg>
    <h3 class="text-slate-900 group-hover:text-white text-sm font-semibold">New project</h3>
  </div>
  <p class="text-slate-500 group-hover:text-white text-sm">Create a new project from a variety of starting templates.</p>
</a>

```

## 兄弟要素の状態に基づいてスタイルを設定する

以下のように`peer`を使用すると兄弟要素の状態に基づいてスタイルを設定できます。

```html
<form>
  <label class="block">
    <span class="block text-sm font-medium text-slate-700">Email</span>
    <input type="email" class="peer ..."/>
    <p class="mt-2 invisible peer-invalid:visible text-pink-600 text-sm">
      Please provide a valid email address.
    </p>
  </label>
</form>
```

`peer`を先に記述している要素に記述しなければ適用されません。
以下のように記述した場合には適用されません。

```html
<!-- spanとinputの順番を入れ替えなければ適用されない -->

<label>
  <span class="peer-invalid:text-red-500 ...">Email</span>
  <input type="email" class="peer ..."/>
</label>
```
Vercelのデプロイをwebhookで簡単に定時実行する

## 前提

VercelでWebサイトをホスティングしているが、deployを毎時一回以上行わなければならない。

> **🤔状況:**
> NotionAPIを使用してブログを作ったが、NotionAPIの画像リンクは1時間で切れる（セキュリティーの都合上）ため、一時間以上開けて誰かがアクセスした時に画像が表示されない問題が発生する。その場で再度リロードするとvalidateのおかげで問題なく表示されるようになるけど、ユーザー体験としてはよくない。

↓作ったブログ

https://tanorobo.shirokuma89.dev

## 🔧解決法

### vercel CLI

Tokenを発行してやる方法。知識不足すぎて理解できず泣きながらブラウザバックした。

https://zenn.dev/nikaera/articles/vercel-github-actions

### GitHub Actionsでコミットプッシュを繰り返す方法

こちらの記事に書いてあって面白いなって思ったけど、コミット履歴はクリーンにしたいので今回は用途に合わず見送った。

https://qiita.com/centerfield77/items/a5a47f0004a93d3ffa04

### webhookを使う方法（これ）

一番簡単な気がする。この記事で説明。

## 🔥やり方

まずProject Settingsからdeploy hookを作成する。コピっておく。

![スクリーンショット 2023-10-04 23.53.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628782/0023a697-1e10-c503-0ddc-ee07f618cc24.png)

次にGitHubの該当リポジトリのsecretに`API_URL`（などの任意の名前）で保存する。

最後に、yamlを書いて以下の内容でGitHub Actionsを生成する。nameは適当に好きなのにしてOK。実行間隔はcronの行をいじる。

```yml:internet.yml
name: internet yamelo

on:
  push:
    branches:
      - main
  schedule:
    - cron: "0 * * * *"
  workflow_dispatch:
  repository_dispatch:

jobs:
  build:
    name: build
    
    runs-on: ubuntu-latest
    
    steps:
    - name: Call the web hook
      run: curl -X POST ${{ secrets.API_URL }}
```
【Python】waveモジュールを用いたステレオwavファイルの作成と出力

# 概要
Python でステレオwavファイルを作成し、出力する方法をメモしておきます。

今回は、
* サンプリング周波数: 44100 Hz
* ビット深度: 16bit
* チャンネル数: 2 （ステレオなので当然）

のデータを作成します。

# ファイルの作成
例として、左からAのサイン波、右から2オクターブ下のAの矩形波が聞こえるようなデータを作成します。

**インポート**

```python
import numpy as np
import wave
```

**データ作成にあたり、便利な関数を定義**
```python
# sec を時間軸に変換する関数
def frac_t(sec, samplerate):
    return np.arange(int(sec * samplerate)) / samplerate


# サイン波を定義 （A:振幅, f:周波数, t:時間）
def sin_wave(A, f, t):
    return A * np.sin(2 * np.pi * f * t)


# 矩形波を生成
def sq_wave(A, f, t):
    return A * np.sign(sin_wave(A, f, t))


# のこぎり波を生成 （今回使いません。オマケです）
def saw_wave(A, f, t):
    return 2 * A * (f * t - np.floor(f * t) - 1 / 2)
```

**設定**
```python
# 設定
fs = 44100  # サンプリング周波数 [Hz]
sec = 1  # 信号を生成する秒数 [s]
A = 0.5  # 振幅
f = 440  # 信号の周波数 [Hz]
t = frac_t(sec, fs)  # 秒数を時間軸に変換
```

## データの作成
まず、440Hzのサイン波を ```data_L``` に、 110Hz （440Hz の 2オクターブ下）の矩形波を ```data_R``` に格納します。
```python
# Left/Right Channel のデータを生成
data_L = sin_wave(A, f, t)  # 440Hz のサイン波
data_R = sq_wave(A / 10, f / 4, t)  # 110Hz の矩形波
```

ステレオデータは、Left/Rightのデータを交互に格納する必要があるので、そのようなデータを ```data_stereo``` に格納します。また、扱いやすいよう、そのリスト型を np.array 型に変換しておきます。
```python
# ステレオデータを格納するリスト
data_stereo = []

# ステレオデータは [LRLRLRLRLR...] の形式にしなきゃいけない
for i in range(len(data_L)):
    data_stereo.append(data_L[i])
    data_stereo.append(data_R[i])

# リストを np.array に変換
data_stereo = np.array(data_stereo)
```

これでステレオのデータを格納することができました。あとは、これを 16bit のデータに変換します。
```python
# 16bit のデータとして書き込むためにスケールを調整 (※1)
data_stereo = data_stereo * np.iinfo(np.int16).max  # (データ)×(16bitで表現できる最大値)

# # (※1) にて音割れする場合… 代わりにこれを用いる
# data_stereo = data_stereo / max(data_stereo) * 0.7 * np.iinfo(np.int16).max # (データ)/(データの最大値)×0.7×(16bitで表現できる最大値)

# 16bit のデータに変換
data_stereo = data_stereo.astype(np.int16)
```
<font color="silver">

**補足**
ここで、(※1) で音割れする場合は、対症療法的ですが
$$
\frac{y_i}{\max(y_i)}\times (割合)
$$
として音割れを防ぎました。
また、ここで割合は -3dB として、
$$
(-3 \\,[\mathrm{dB}] の減衰比) \simeq \frac{1}{\sqrt{2}} \simeq 0.7
$$
をとりました。（-3dB は音楽業界でマスタリング前の2MIXデータの上限値の目安として選ばれることの多い値です。（ほんとか？？？））</font>



## データをファイルに出力
これで下準備は完了したので、最後に ```data_stereo``` を ```test_01.wav``` というファイル名で出力するだけです。
wave モジュールでは出力する際に、チャンネル数やサンプル幅などのメタデータを設定する必要があるため、それも行っています。
```python
# データをファイルとして出力
output_file = "./wav/test_01.wav"
with wave.open(output_file, "w") as wf:
    wf.setnchannels(2)  # チャンネル数の設定 (1:mono, 2:stereo)
    wf.setsampwidth(2)  # サンプル幅の設定 (2bytes = 16bit)
    wf.setframerate(fs)  # サンプリングレートの設定
    wf.writeframes(data_stereo)  # ステレオデータを書き込み
```

これで出力が完了しました！

# 余談
```with``` 構文を使わずにコードを書こうとすると、
```python
wf = wave.open(outputfile, "w")
wf.setnchannels(2)  # チャンネル数の設定 (1:mono, 2:stereo)
wf.setsampwidth(2)  # サンプル幅の設定 (2bytes = 16bit)
wf.setframerate(fs)  # サンプリングレートの設定
wf.writeframes(data_stereo)  # ステレオデータを書き込み
wf.close() # close
```
と少し冗長で見づらいコードになります。（なるほど～これが ```with``` 構文のメリットかぁ）
```wf.close()``` をわざわざ書かなくても、書き忘れても、勝手に閉じてくれるわけですね。
Javaとは？初心者向けに解説

# Javaとは？初心者向けに解説

こんにちは！今回はプログラミング言語の一つである「Java」について、初心者向けに解説していきます。

## 1. Javaの歴史

Javaは、1995年にSun Microsystems (現在はOracle Corporationの一部) によって公開されました。当初は家電製品の制御用のプログラム言語として開発されましたが、その後、ウェブアプリケーションやエンタープライズシステムの開発にも広く利用されるようになりました。

## 2. Javaの特徴

### 2.1. プラットフォーム独立

「一度書けば、どこでも動く」という思想の下、Javaは開発されました。Javaで書かれたプログラムは、異なるハードウェアやOS上で動作するJVM (Java Virtual Machine) 上で実行されるため、プラットフォームに依存することなく動作します。

### 2.2. オブジェクト指向

Javaは完全なオブジェクト指向プログラミング言語です。これにより、再利用性、拡張性、保守性が向上します。

### 2.3. 豊富なライブラリ

Javaには標準で多くのライブラリが含まれており、ネットワーク通信、データベース操作、GUI作成など、様々なタスクを容易に行えます。

## 3. Javaでできること

- ウェブアプリケーションの開発
- Androidアプリの開発
- サーバーサイドアプリケーションの開発
- デスクトップアプリケーションの開発
- IoTデバイスの制御

## 4. まとめ

Javaは、幅広い分野で使用される強力なプログラミング言語です。プラットフォーム独立性や豊富なライブラリにより、様々なアプリケーションの開発が可能となっています。
Ubuntu　名前解決不可時用の備忘メモ

# Ubuntu　名前解決不可時用の備忘メモ
Let's encryptの証明書取得時にエラーが勃発しレート制限に引掛り、
時間を無駄にしたためメモしておく。
※OSはUbuntuだがLinux系共通と想定

# エラー内容
```
ping: yahoo.co.jp: Temporary failure in name resolution"
```

# 解決方法
1.念のためresolvedサービス停止
```
sudo systemctl stop systemd-resolved.service
```

2./etc/resolv.confの書き換え
```
nano /etc/resolv.conf
````

3.DNS修正
```
nameserver XXX.XXX.XXX.XXX
````

4.ping確認

# 反省
Let's encrypt証明書取得に失敗した際、すぐに確認するべきだった。
初心に返り反省・・・・
2023: Week 39 - Tennis 200 Club / Preppin' Data / Tableau Prep

# Challenge Preppin'Data 2023:Week 39

## 概要

アンディ マレーのグランド スラム 200 勝を祝うダッシュボードを作成するため、他の 3 人のメンバー (ナダル、フェデラー、ジョコビッチ) と比較できるデータセットを作成したいと考えました。
各年 (2000 年から 2023 年) のファイルに、その年に行われた各試合の行が含まれています。 
各プレイヤーが勝った最初の 200 試合のみを比較し、200 勝目までの敗戦を合わせて確認します。また、勝利ごとに、前回の勝利から経過した日数を算出します。

Requirement

1. すべてのファイルを 1 つのデータセットにまとめる
2. グランドスラムの試合のみにフィルターをかける
3. マレー、ナダル、フェデラー、ジョコビッチがプレーした試合のみを対象としてする
  勝者のフィールドにも敗者のフィールドにも名前が入っている可能性があるため注意
4. 各プレイヤーが勝った最初の 200 試合のみを抽出に、200 勝目までの損失データと比較できるデータセットを作成する
5. 前回の勝利から経過した日数を算出する

## 問題のページ（英語）※ここからデータをダウンロード
https://preppindata.blogspot.com/2023/09/2023-week-39-tennis-200-club.html

## 出題者の回答のページ（英語）※動画あり
https://preppindata.blogspot.com/2023/10/2023-week-39-solution.html

## 自分の解決法
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/946c253f-55ce-ad0b-46e6-d9e7b952c78c.png)

1. 複数のファイルをワールドカードでユニオンする。この際にグランドスリムにフィルターをかける
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/d7b2f92a-7d70-1088-ec30-e6e305f0a9d0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/ad65af05-1104-20ae-44cb-0b53b882c580.png)

2. Winnerのデータを先に作る
2. ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/632fb3fe-8f19-4d75-95b5-383d424fd27e.png)

Winnerのフィールドを複製して、フィールド名をPlayer of Interestに変更する
Player of Interestを4選手にフィルターする

3. 次に同様にしてLoserのデータを作る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/2bb2a693-ebb6-d9cc-6169-2914f7123b0a.png)

Loserのフィールドを複製して、フィールド名をPlayer of Interestに変更する
Player of Interestを4選手にフィルターする

4. 2と3をユニオンする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/e8758abf-78f8-465a-fced-20cf65427e54.png)

この際に、TableNameを使って、Win/Lossというフィールド名に変更し、それぞれ値をWinとLossに書き換える

5. 各選手ごとに200勝目の試合を特定し、200週目以前のデータに絞り込む
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/cd8e9663-3e4d-5c47-9c68-b515536bad6e.png)

* 最初は、各選手ごと、WIN/LOSSごとに古い日付ごとに行番号をふる
* 次に、各選手ごと、WIN/LOSSごとに前回との試合の経過日数を計算する
* WINでかつ200勝までは、上記の2ステップで作成した行番号と経過日数を残し、それ以外をクリアする
* 200勝目の日付を抽出し、それ以前のデータのみにフィルターをかける

6. 出力
最後に、出力先やファイル名を指定したら完成です。

## 今回の感想
今回は計算式がもりもりでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/9698bf3f-9243-b022-7993-a86c0f7c36a1.png)
FIXED関数で200勝目の日付を簡単に参照できました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/2ed87807-87d8-8587-3b9f-af0bd9a34385.png)
〇〇ごとに行番号を指定したい場合、PARTITIONで〇〇をしたいして、データを並べ替えるとできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/b6fb0ee7-fcae-95ae-e3ff-89effad92c1a.png)
前回の試合日は、Lookup関数で1つ前のデータを参照します。
【Rails 7】Bootstrapのインストール

# 開発環境
Rails 7.0.8
Ruby 3.1.3
Bootstrap 5.3.0
# 導入手順

## 1.Gem導入

Gemgileに以下２つのgemを追加
```ruby:Gemfile
gem 'bootstrap', '~> 5.3.0'
gem 'jquery-rails'

gem "sassc-rails" #コメントアウトをなくす
```
ターミナルにて、インストール
```:terminal
bundle install
```

## 2.CSS編集
app\assets\stylesheets\application.cssを".scss"に変更
中身を全て消して以下のコードに変更
```scss:application.scss
@import "bootstrap";
```

## 3.javascriptの設定
### a) Configファイルの編集
config\importmap.rb
以下のコードを追記(位置はどこでも良い）

```ruby:importmap.rb
pin "bootstrap", to: "bootstrap.min.js", preload: true
pin "@popperjs/core", to: "popper.js", preload: true
```
※バージョンによっては、"bootstap.min.js"ではなく、"bootsrap.js"と書く

### b) assets.rbファイルの編集
config\initializers\assets.rb
以下のコードを追記(位置はどこでも良い）

```ruby:assets.rb
Rails.application.config.assets.precompile += %w(bootstrap.min.js popper.js)

# a)で"bootstap.min.js"ではなく、"bootsrap.js"と書いた場合は、こちらも同じに直す
```
### c) application.jsファイルの編集
app\javascript\application.jsに以下のコードを追記（import "@hotwired/turbo-rails"の上に書く）
```javascript:application.js
//= require jquery3
//= require popper
//= require bootstrap
```
バージョンによっては以下のコードにする
```javascript:application.js
//= require jquery3
//= require popper
//= require bootstrap
```

## Javascriptがページをリロードしないと読み込まないとき
application.jsを修正する
```javascript:app\javascript\application.js

//下記をコメントアウト又は削除
// import "@hotwired/turbo-rails"

//下記に書き換える
import { Turbo } from "@hotwired/turbo-rails"
Turbo.session.drive = false
```
Turboの無効化した場合、リンクからコントローラーのPOSTメソッドに飛ばすには、turbo: trueオプションを追加する。
```html:HTML
<%= link_to "Logout", logout_path, data: {turbo: true,"turbo-method": :post} %>
```


# 参考
https://github.com/twbs/bootstrap-rubygem/blob/main/README.md
Time.atとTime.zone.atの違いについて

## Time.at
* Rubyの組み込みメソッド。
* 指定した時刻のTimeオブジェクトを返す。
* キーワード引数inでタイムゾーンを指定できる。
* タイムゾーンの指定がなく引数が数値の場合、生成されたTimeオブジェクトは地方時になる。

```ruby
# Timeオブジェクト、もしくは起算時からの経過秒数を表す数値を指定する
Time.at(0) #=> 1970-01-01 00:00:00 +0000

# "+HH:MM" や "-HH:MM" のような形式の文字列か,"UTC"などでタイムゾーンを指定する
Time.at(1582721899, in: "UTC")　 #=> 2020-02-26 12:58:19 UTC
```


## Time.zone.at
* Ruby on Railsのフレームワークにおいてタイムゾーンを取り扱うためのクラス。
* TZInfoというRubyのタイムゾーン情報を扱うためのライブラリを利用していて、`TZInfo::Timezone` インスタンスをラップして、Railsでの使用に適したインターフェースを提供する。
* 実際のタイムゾーンの数は非常に多いが、TimeZoneはそれを134の意味のあるゾーンに制限することで、一般的なタイムゾーンの選択を容易にする。
* そしてより人間が読みやすい形式にタイムゾーンを表現してくれる。
* タイムゾーン情報は、必要になったときだけロードされるので、メモリ使用量の削減や起動時間の短縮に寄与する。
* Railsアプリケーションの `config.time_zone` 設定を通じて、デフォルトのタイムゾーンを設定できる。Time.zoneを通じてアクセスが容易になる。

```ruby
Time.zone       # => #<ActiveSupport::TimeZone:0x514834...>
Time.zone.name  # => "Eastern Time (US & Canada)"
Time.zone.now   # => Wed, 04 Oct 2023 23:04:18.669175338 JST +09:00
Time.zone.at(0) # => Thu, 01 Jan 1970 09:00:00.000000000 JST +09:00
```

```ruby
# タイムゾーンを東京に設定
config.time_zone = 'Tokyo'
```

## 両者の違い

* `Time.at`はシステムのローカルタイムゾーンに基づくオブジェクトを生成する。
* `Time.zone.at`はRailsのタイムゾーン設定に基づくオブジェクトを生成する。
    * タイムゾーンの一貫性を保つためには、`Time.zone.at`の使用が推奨される。


---
参考リンク

https://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html


https://railsdoc.com/page/config_time_zone


https://docs.ruby-lang.org/ja/latest/method/Time/s/at.html
テキストエディタ 秀丸エディタ のインストール

「秀丸エディタ」は、Windows 向けの有料のテキストエディタです。秀丸エディタは基本的なテキスト編集機能から高度な編集機能まで幅広くカバーしています。日本のプログラマや文章作成者に根強い人気があります。ここでは 18 歳の新入社員向けに秀丸エディタのインストール手順を説明します。

## 秀丸エディタを使う目的
秀丸エディタをメモ帳と比較すると以下の特徴があります。

### プログラムやスクリプトのコーディング
シンタックスハイライト機能を活用して、ソースコードの読みやすさを向上させることができます。

### 大容量テキストの閲覧・編集
秀丸エディタは1000万行のCSVファイルをスムーズに開き、編集することができます。また正規表現を使用した強力な検索・置換機能や、マクロ機能を使用して大量のデータを高速に加工することができます。

## 秀丸エディタを使う目的 その2
秀丸エディタを無料のテキストエディタと比較すると以下の特徴があります。

### Windows と親和性が高い初心者向け UI
秀丸エディタはメニュー、タブ、ウィンドウといった、Windows のマウス操作に慣れているユーザに使いやすい操作体系を提供します。

### サポート体制がありスピーディな対応
Windows がバージョンアップして新しい機能が増えた場合の対応も早いです。

https://forest.watch.impress.co.jp/docs/news/1043227.html

https://forest.watch.impress.co.jp/docs/news/1071830.html

## 秀丸エディタの利用条件
### 価格
秀丸エディタはシェアウェアです。無料でダウンロードし、試用することができます。2週間以上利用する場合はライセンスを購入する必要があります。

https://hide.maruo.co.jp/software/hidemaru.html

秀丸エディタの価格は1ライセンス4000円（税抜）です。学校や企業で10ライセンス以上を同時に購入する場合、割引制度があります。

https://hide.maruo.co.jp/swreg/price.html

### 使用条件
購入したライセンスは、以下の２つの使用条件のうちの１つを選択して使用することができます。
- (a) １ライセンスにつき、１人の使用者のみが、複数のコンピュータにインストールして使用できる
- (b) １ライセンスにつき、１台のコンピュータにのみインストールし、複数の使用者が使用できる

https://hide.maruo.co.jp/swreg/license.html

### バージョンアップ
秀丸エディタはバージョンアップが無料です。エンジニアが個人で購入し使用条件（a） を選択すると、パソコンを入れ替えたりパソコンの台数が増えても引き続き最新版を使うことができます。

## 秀丸エディタのシステム要件
秀丸エディタは、WindowsXP/Vista/7/8/8.1/10/11 上で動作します。

ここでは 秀丸エディタ（32bit版）version 9.24 を例にして、Windows 11 へのインストール方法を紹介します。

## 秀丸エディタ のインストール手順
### ダウンロード
窓の杜の秀丸エディタの紹介ページにアクセスし、「窓の杜からダウンロード」をクリックします。<br>
[https://forest.watch.impress.co.jp/library/software/hidemaru/](https://forest.watch.impress.co.jp/library/software/hidemaru/)

![03_officialSite.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/00abd684-1792-766c-c4db-b0a2bdb03904.png)

### インストーラの起動
ダウンロードが完了したら、ファイルをダブルクリックし、インストーラを実行します。

![12_Installer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/f66c4901-b42e-5b97-8267-8f565538aa7d.png)

### インストールの確認
インストールの確認画面が表示されたら、「はい」をクリックします。

![22_Installer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/b5af570b-8f76-9fb5-b8ce-d311537507c5.png)

### セットアップ画面の確認
セットアップ画面が表示されたら、「次へ」をクリックします。

![23_Installer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/f3f6bd0f-3003-f071-1978-4f014903d273.png)

### インストール方法の選択
インストール方法の選択画面が表示されたら、「次へ」をクリックします。

![24_Installer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/12035d1e-5be4-f258-7cf6-fe65dac917b5.png)

### 関連付けの選択
関連付けの登録画面が表示されたら、「次へ」をクリックします。

![25_Installer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/2d9e041b-8296-bb10-b3e3-1b456e2af035.png)

### 拡張子の選択
拡張子の指定画面が表示されたら、「次へ」をクリックします。

![26_Installer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/36086779-0459-6640-69e0-9f9729bb4884.png)

### インストールの確認
コピーの開始画面が表示されたら、「次へ」をクリックします。

![27_Installer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/4fc80133-83f6-2123-9363-8cf4734e054d.png)

### インストール終了
インストールの完了画面が表示されたら、「OK」をクリックします。

![28_Installer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/830df513-b013-aadc-47bd-53f4135c255a.png)
shell scriptでログを出力

## はじめに
掲題の通り、ログをファイルに出力するshellを作成しました。
また、定期実行するためにcronにも登録してみました。

## shell

```shell:test.sh
#!/bin/bash

LOG_OUT=./stdout.log
LOG_ERR=./stderr.log

exec 1> >(tee -a $LOG_OUT)
exec 2> >(tee -a $LOG_ERR)

# 標準出力
echo foo1
echo foo2
echo foo3
# 標準エラー出力
ls /foo
rm /foo
```
簡単に説明していきます。
「echo」：コンソールに出力します。
「ls /foo」：fooのディレクトリに移動。※今回はエラーにするために、わざとディレクトリを作成しません。
「rm /foo」：fooのディレクトリを削除。※今回はエラーにするために、わざとディレクトリを作成しません。
「LOG_OUT=./stdout.log」：変数にファイルの場所を格納しています。
「LOG_ERR=./stderr.log」：変数にファイルの場所を格納しています。
「exec 1> >(tee -a $LOG_OUT)」：shellを実行時に標準出力をコンソールとファイルの両方に出力します。
「exec 2> >(tee -a $LOG_ERR)」：shellを実行時に標準エラーをコンソールとファイルの両方に出力します。

## crontab
①「chmod 755 test.sh」で実行権限をshellに付与します。
②「crontab -e」でcronを登録するためにファイルを開きます。
③「`*/1**** cd /home && ./test.sh`」を入力して「:wq」で保存します。
　※1分間隔でshellを実行します。cdで移動していますが、各々のパスに合わせてください。

## 補足
shが実行されるたびに、cronからメールがくる場合があります。
もし、メールを停止させたい場合は以下の対応を行ってください。
①メールを消すshellを作成する。
```shell:deletemail.sh
#!/bin/bash

cat /dev/null > /var/spool/mail/root

sleep 2

cat /dev/null > /var/spool/mail/root

sleep 2

cat /dev/null > /var/spool/mail/root

sleep 2

cat /dev/null > /var/spool/mail/root

sleep 2

cat /dev/null > /var/spool/mail/root

sleep 2

cat /dev/null > /var/spool/mail/root
```

②作成したshellをcrontabに登録する。
　┗「chmod 755 deletemail.sh」
　┗「crontab -e」
　┗「`*/1**** cd /home && ./deletemail.sh`」

※deletemail.shの説明ですが、メールのファイルの内容を２秒間隔でクリアしています。（計6回）
　sleepは指定した時間分、処理を止めてくれます。
　これをcrontabに登録することでメールは飛びますが、即座に消してくれるので、
　メールの通知がコンソール上に表示されなくなります。
VPNとは

# はじめに
毎週1本様々な技術に関する記事を投稿しています。
もし興味のある方は下のリンクから他の記事も見ていただければ幸いです。
 [@7_inai_](https://qiita.com/7_inai_)

# VPNとは
VPN（Virtual Private Network）は、仮想プライベートネットワークの略称です。これは、`特定の個人のみが利用できる専用ネットワーク`のことです。

# VPNの仕組み
### ①データの暗号化
VPNは、__データを暗号化することでセキュリティを向上__ させます。通常、インターネットを介してデータは平文で送信されるため、盗聴者がデータを傍受できます。しかし、VPNを使用すると、データは強力な暗号化アルゴリズムを使用して変換されます。これにより、データが傍受されても理解不能な形になり、セキュリティが確保されます。

### ②トンネルの確立
VPNは、__ユーザーのデバイスとVPNサーバー間で仮想的な「トンネル」を確立__ します。このトンネルを通じてデータが送受信され、外部からのアクセスが制限されます。トンネルは、通信データが安全に転送される要となり、不正アクセスから保護します。

### ③VPNプロトコル
VPNの種類にはさまざまなプロトコルがあります。一般的なプロトコルには、OpenVPN、L2TP/IPsec、PPTP、IKEv2などがあります。各プロトコルには異なる特性があり、セキュリティレベルや速度に影響を与えます。ユーザーは使用目的に応じて最適なプロトコルを選択できます。

### ④ロケーションの選択
VPNユーザーは、VPNサーバーのロケーションを選択できます。これにより、__ユーザーは自身の物理的な場所を隠し、特定の地域にあるウェブコンテンツやサービスにアクセス__ できます。例えば、米国にいるユーザーがヨーロッパにあるVPNサーバーを選択すれば、ヨーロッパのIPアドレスを使用できます。

以上がVPNの基本的な仕組みです。VPNは、これらの要素を組み合わせて、セキュアでプライベートなオンライン環境を提供します。プライバシーとセキュリティを重要視するユーザーにとって、VPNは不可欠なツールとなっています。

# VPNのメリット
- セキュリティ向上
VPNはデータを暗号化するため、公共のWi-Fiネットワークなどでのデータの盗聴を防ぎます。
- プライバシー保護
VPNを使用すると、ISPやウェブサイトがユーザーのオンラインアクティビティを追跡できなくなります。
- 地理的制限の回避
VPNを使用することで、特定の国や地域でコンテンツにアクセスする制限を回避できます。
- 匿名性
VPNはユーザーのIPアドレスを隠すため、オンラインでの匿名性を提供します。

# 終わりに

VPNは、現代のデジタル環境でプライバシーとセキュリティを強化するための強力なツールです。正しく設定し、使用することで、オンラインでのリスクを最小限に抑えることができます。プライバシーとセキュリティを重視する場合、VPNの活用は非常に有用です。

最後までお付き合いくださりありがとうございました。
コマンドラインでTestNGを動かす[Windows 11]

# 動機
- mavenやant、EclipseやIntelij IDEAがない環境でもTestNGを使いたい。

# 環境
- OS : Windows 11 Home
- JDK
```
>java -version
openjdk version "1.8.0_382"
OpenJDK Runtime Environment (Temurin)(build 1.8.0_382-b05)
OpenJDK 64-Bit Server VM (Temurin)(build 25.382-b05, mixed mode)
```

# 手法
## 1. ライブラリのダウンロード
[mvnrepository](https://mvnrepository.com)からダウンロードする。
必要なのは以下の2つ。

- TestNG 6.11 - [リンク](https://mvnrepository.com/artifact/org.testng/testng/6.11)
- JCommander 1.72 - [リンク](https://mvnrepository.com/artifact/com.beust/jcommander/1.72)

より新しいバージョンがあるが、JDK8をサポートしていない場合がある。
詳しくは調査していないがこのバージョンの組み合わせで動作した。
**TestNGは多くのバージョンで脆弱性が報告されているので注意（[CVE-2022-4065](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-4065)）。**

## 2. 環境変数の設定
毎回引数に`-cp [classpath]`を記述しても良いが面倒なので設定する。
環境変数名は`CLASSPATH`を、値は上でダウンロードしたJARファイルを配備したディレクトを設定する。

例：`C:\Users\{ユーザ名}\Java\classpath\*`
`classpath`配下のファイルがすべてクラスパスに読み込まれる。

## 3. テストケース
非常に簡易なサンプルを用意。
```java:SampleTest.java
import org.testng.annotations.Test;

public class SampleTest {

    @Test
    public final void fooTest() throws Exception {
        System.out.println("foo");
    }
    
}
```

## 4. テスト起動用xml
非常に簡易なサンプルを用意。
なお、最近のTestNGは1行目で`http`ではなく`https`を用いる。
```xml:testng.xml
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
  
<suite name="Suite" verbose="1" >
  <test name="Test" >
    <classes>
       <class name="SampleTest" />
    </classes>
  </test>
</suite>
```

## 5. テスト実行
ここでディレクトリ構成を確認しておく。

    -｛任意のディレクトリ｝
        - src
            - SampleTest.java
            - testng.xml

コマンドプロンプトで以下を実行。
```
# ソースのあるフォルダに移動
>cd {任意のディレクトリ}\src

# テストケースをコンパイル
>javac SampleTest.java

# テスト実行
>java -cp %CLASSPATH%;.\ org.testng.TestNG testng.xml
foo

===============================================
Suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
```