OmniAICreator/Qiita-1.07M huggingface dataset:
Pythonの便利技と注意点:PyCharm編

[目次に戻る](https://qiita.com/yuta-sanjyo/items/416b05f8498df1ed3f49)

# Windowsにて日本語を扱う時の技

```Py:subprocessでWindowsのコマンドを使うと文字化けする
import subprocess

subprocess.run('dir', shell=True)
=================================
# 出力結果 ※パス・ファイル名・日付・バイト数などは脚色してあります
 �h���C�u C �̃{�����[�� ���x��������܂���B
 �{�����[�� �V���A���ԍ��� 5882-3E25 �ł�

 C:\Users\<username>\PycharmProjects\pj �̃f�B���N�g��

2024/05/14  00:48    <DIR>          .
2024/05/14  00:48    <DIR>          ..
2024/05/11  00:31             2,147 main.py
2024/05/12  15:43             1,139 test.py
2024/05/14  00:48                 4 test.txt
               3 �̃t�@�C��              24,937 �o�C�g
               2 �̃f�B���N�g��  776,319,602,688 �o�C�g�̋󂫗̈�
```

これは、PyCharmにおけるコーディングの文字コードが「UTF-8」、Windowsの文字コードが「Shift-JIS」に設定されていることで、Windows側でUTF-8により書かれた文字列を変換できないことで発生する、と推測される。

したがって、この箇所を「UTF-8」から「ShiftJIS」に変更することで解消する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588352/5537d5af-b36c-3568-ddb6-1e28ef18629c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588352/fa401456-9d81-68f4-efcd-7ec88ab34e58.png)

※「ShiftJIS」はプルダウンの「その他」から選ぶことができる


```Py:ShiftJISでエンコーディングすれば文字化けが解消する
import subprocess

subprocess.run('dir', shell=True)
=================================
# 出力結果 ※パス・ファイル名・日付・バイト数などは脚色してあります
 ドライブ C のボリューム ラベルがありません。
 ボリューム シリアル番号は XXXX-XXXX です

 C:\Users\<username>\PycharmProjects\pj のディレクトリ

2024/05/14  00:48    <DIR>          .
2024/05/14  00:48    <DIR>          ..
2024/05/11  00:31             2,147 main.py
2024/05/12  15:43             1,139 test.py
2024/05/14  00:48                 4 test.txt
               3 個のファイル              24,941 バイト
               2 個のディレクトリ  776,316,506,112 バイトの空き領域
```

ところがこの状態で、新たにpyファイルを作成して日本語出力しようとするとエラーを出力する

```Py:ShiftJIS設定のまま日本語を出力しようとするとエラーとなる
print("日本語")
==============
# 出力結果
SyntaxError: Non-UTF-8 code starting with '\x93' in file C:\Users\<Username>\PycharmProjects\pj\test.py on line 1, but no encoding declared; see https://peps.python.org/pep-0263/ for details
```

`# -*- coding: utf-8 -*-`を冒頭に宣言すると解消する

```Py:utf-8でコーディングする、という宣言を加えるとエラーが出なくなる
# -*- coding: utf-8 -*-
print("日本語")
=======================
# 出力結果
日本語
```



[目次に戻る](https://qiita.com/yuta-sanjyo/items/416b05f8498df1ed3f49)
PHPのfilter_var関数で検証を行う

## はじめに
最近ChatGPTでPHPコードを生成した際Filterの存在を知った。
スクラッチ開発でメールアドレスなどの検証を行うのに正規表現を利用していたが標準機能が存在するなら利用しようと思いまとめてみた。
今回はfilter_var関数を使った検証フィルタをいくつかまとめた。他にもさまざまなFilterの機能が存在する。詳しくはPHPマニュアルを確認して欲しい。

※対応バージョンはPHP 5 >= 5.2.0, PHP 7, PHP 8
※一部機能は対応していないバージョンがあるのでマニュアルを確認すること

## Boolean
- "1"、"true"、"on" および "yes"の時trueを返す

| フィルタの型                  |                      |
|:------------------------|:---------------------|
| FILTER_VALIDATE_BOOLEAN | FILTER_VALIDATE_BOOL |

### 検証例
- POST送信された値が真(1, true, on, yes)とみなせる値か検証する
````index.php
if (isset($_POST['test']) && filter_var($_POST['test'] ,FILTER_VALIDATE_BOOLEAN)) {
    //何らかの処理
}
````
- FILTER_NULL_ON_FAILUREフラグを追加することでfalseを返すのは"0"、"false"、"off"、"no"のみになる。真とfalse以外の値はnullを返す
````index.php
//NULLを返す
$failure_value = 'test';
var_dump(filter_var($failure_value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)); //NULL

//falseを返す
$falsy_value = 'no';
var_dump(filter_var($falsy_value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)); //bool(false)
````
### その他
- 文字列を検証する際、先頭および末尾にあるホワイトスペースはtrim関数で除去される

## URL
- 値が URL 形式である (» http://www.faqs.org/rfcs/rfc2396 に準拠している) かどうかを検証する
- ASCIIのURLのみ正しいとみなす
- プロトコルの検証は別途行う必要がある

| フィルタの型              |
|:--------------------|
| FILTER_VALIDATE_URL | 

### 検証例
````index.php
//RFC2396に準拠したURL
$compliant_url = 'https://www.google.com/';
var_dump(filter_var($compliant_url, FILTER_VALIDATE_URL)); //string(23) "https://www.google.com/"

//RFC2396に準拠していないURL
$not_compliant_url = 'http://example.com/あいうえお';
var_dump(filter_var($not_compliant_url, FILTER_VALIDATE_URL)); //bool(false)

//ただのパス
$path = '/test/0124/';
var_dump(filter_var($path, FILTER_VALIDATE_URL)); //bool(false)
````
### その他
- ここでは詳しく説明しないがフラグを設定することでパスやクエリを必須にできる

## e-mail
- e-mail アドレスが [» RFC 822](http://www.faqs.org/rfcs/rfc822.html) の addr-spec 形式 に沿ったものであるかどうかを確かめる

| フィルタの型                |
|:----------------------|
| FILTER_VALIDATE_EMAIL |

### 検証例
````index.php
//RFC822に準拠したe-mail アドレス
$compliant_email = 'test@example.com';
var_dump(filter_var($compliant_email, FILTER_VALIDATE_EMAIL)); //string(16) "test@example.com"

//RFC822に準拠していないe-mail アドレス
$not_compliant_email = 'john@doe@example.com';
var_dump(filter_var($not_compliant_email, FILTER_VALIDATE_EMAIL)); //bool(false)
````

## 参考
- [データのフィルタリング](https://www.php.net/manual/ja/book.filter.php)
- [検証フィルタ](https://www.php.net/manual/ja/filter.filters.validate.php)
- [filter_var](https://www.php.net/manual/ja/function.filter-var.php)
Factorybotのtransient属性とは何か

## はじめに
Factorybotのコード内に `transient` という定義を見かけました。 初めて見かけた属性だったので調べてみました。

## transient属性とは？
factory_bot gemの[GETTING_STARTEDドキュメント](https://github.com/thoughtbot/factory_bot/blob/main/GETTING_STARTED.md#transient-attributes)には以下のように定義されていた。

> Transient attributes are attributes only available within the factory definition, and not set on the object being built. This allows for more complex logic inside factories.

> 「一時的属性」とは、ファクトリーの定義内でのみ利用可能な属性であり、構築されるオブジェクトには設定されません。これにより、ファクトリー内でより複雑なロジックを実装できます。

とのことで、モデルに定義された属性とは別にファクトリー内の一時的な変数のように利用できる属性のようです。

## transient属性を使ったよくありそうな実装例

### フラグの定義

`transient` 属性にフラグを定義し、他の属性からそのフラグを参照することで挙動を変えるパターン。ファクトリーでcreateするときに、フラグの値を渡すことで任意のデータを登録するようにできるようになる。

```ruby
factory :item do
  transient do
    secret { false }
  end

  name { "#{"[secret] "if secret}Item Name" }
end
```

```ruby
[3] pry(#<RSpec::ExampleGroups::Items::GETItems>)> create(:item).name
=> "Item Name"

[4] pry(#<RSpec::ExampleGroups::Items::GETItems>)> create(:item, secret: true).name
=> "[secret] Item Name"
```

### 回数の定義

`transient` 属性で回数を定義し、複数データを作成する際の初期値として利用します。回数を初期値として設定しつつ、状況に応じて変えたい場合には有効です。

```ruby
factory :category do
  transient do
    article_count { 5 }
  end

  trait :with_articles do
    after(:create) do |category, evaluator|
      create_list(:article, evaluator.article_count, category: category)
    end
  end
end
```

```ruby
# カテゴリー作成時に5個の記事も合わせて作成される
create(:category, :with_articles)

# カテゴリー作成時に10個の記事も合わせて作成される
create(:category, :with_articles, article_count: 10)
```

## まとめ

ファクトリー内だけで利用できる一時的な属性の `trasient` というのを知りました。この`transient` 属性をtraitや他属性と組み合わせることで、細かい条件でデータ作成ができるようになり便利そうです。

## 参考
* [factory_bot/GETTING_STARTED.md at main · thoughtbot/factory_bot](https://github.com/thoughtbot/factory_bot/blob/main/GETTING_STARTED.md#transient-attributes)
【aws】lambda layerを使ってlambdaにモジュールをインポートする

## はじめに
AWS Lambdaではawsが提供しているもの以外のライブラリを使いたい場合、事前にライブラリをアップロードする必要があります。
（私はそれを知らずに`luxon is not defined`エラーを出しました😅）
今回はその方法を記録したいと思います。

## 事前準備
- npmのインストール
- awsコマンドのインストール（[こちらのAWS公式サイト](https://repost.aws/ja/knowledge-center/lambda-import-module-error-nodejs)が参考になりました。）

## layerのアップロード
以下の手順はお使いのPCのCLIで実行してください。
#### 1.nodejsフォルダーを作成
```shell
$ mkdir nodejs
```

#### 2.利用したいライブラリをnodejsフォルダーにインストール
```shell
$ cd nodejs
$ npm init
$ npm install --save ライブラリ名
```

#### 3.nodejsフォルダを圧縮
```shell
$ zip -r layer.zip nodejs .
```

#### 4.Lambda layerを公開
`luxon`, `node.js18.x`には各自、**利用するライブラリ名**と**互換性のあるnodeのバージョン**を指定してください。
`互換性のあるnodeのバージョン`は`lambda/ランタイム設定` より、確認して指定しました。
```shell
$ aws lambda publish-layer-version --layer-name luxon --zip-file fileb://layer.zip --compatible-runtimes node.js18.x --region us-east-1
```

lambdaのレイヤーを確認したところ、luxonが無事に作成されていました 🎉

![５.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/31a05036-91de-511b-e1db-2a0eef3d6815.png)

## lambdaにlayerを追加する
お使いのlambda関数のコンソールに移動してください。スクロールしてレイヤーを追加を押してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/d1313270-572b-780a-27e5-5889e32287f1.png)

次に、カスタムレイヤーを選択し、作成したレイヤーを追加します。
![スクリーンショット 2024-05-14 0.22.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/e94d9839-c088-e23b-76a2-e35049a3acf0.png)

## プログラムの作成
これでモジュールを使う準備は整ったので、実際にコードを書いて実行しましょう！
※以下は私のコードの一部を抜粋したものです。
```javascript
import { DateTime } from 'luxon';

const dynamo = DynamoDBDocument.from(new DynamoDB());
const tableName = "feeds";

export const handler = async (event) => {

    let body;
    const date = DateTime.now().setZone('Asia/Tokyo');

    try {
        switch (event.httpMethod) {
            case 'GET':
                const queryParams = event.queryStringParameters || {};
                const interval = queryParams.interval;
                switch (interval) {
                    case 'daily':
                        console.log('dailyが呼ばれた');
                        let startOfDay = date.startOf('day').toMillis();
                        console.log(startOfDay);
```

ログを確認すると、luxonを用いて正確な時刻情報を取得できていることが確認できました 🥳
![６.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/5c225d24-25d4-b33c-6332-da806dc3b931.png)
Nodemonを用いたExpress起動

# Express 毎回再起動するの面倒くさくない??

Node.jsでExpressを用いてWebサーバーを作成する記事を今まで記載してきました。
今後も学んだことを記事にしていきますがExpressで機能を追加した際に動作検証をするとき、
何度も再起動するのめんどくさいな、と思ったときに`Nodemon`を知って便利！となったので記事にします。

## Nodemon
`Nodemon`はnpmに公開されているパッケージの一つです。
私が把握している機能は
`指定したディレクトリ内のファイルが変更された場合、自動的にnodeアプリケーションを再起動する`
⇒`Expressでファイルを変更した場合、サーバの再起動をNodemonが自動で行ってくれる`
です。
毎回コマンドで再起動しなくていいのは便利じゃないですか！？笑
※他にも機能があれば教えていただきたいです。

## Nodemon　設定
下記記事で記載したフォルダ構成を元に説明します。
[ExpressでWebサーバーを立ててみる](https://qiita.com/moody_engineer/items/f5773380ffc964cf10f3)
※自分で読み替えられる人は自分のプロジェクトに読み替えてください。
 私が最初の頃は`npm install パッケージ`ってどこでしたらいいの??ってなってたので
 基準となるフォルダ構成を用いて説明します。

 コマンドプロンプト or ターミナルで`src`ディレクトリに移動してください。
 `src`ディレクトリに移動した後に以下のコマンドを実行してください。
 ```
 npm install --save-dev nodemon
 ```
 ※npm installで`--save-dev`を用いるかどうかについては別記事でまとめます。

 インストール後、`package.json`の`scripts`に`devStart`の1行を追加してください。
 ```json
 "scripts": {
     "devStart": "nodemon app.js"
 }
 ```
 設定は以上になります。
 ※なぜ`package.json`に設定をしているかは下記記事を見てください。
 [Expressの起動方法](https://qiita.com/moody_engineer/items/2859b647f0f978f93e4c)

 ## Nodemonを用いてExpressを起動してみる

 コマンドプロンプト or ターミナルで`src`ディレクトリに移動して下記コマンドを実行してください。
 ```
 npm run devStart
 ```
 下記結果が表示されWebサーバー(Express)が起動します。
 ```
 > mock-server@1.0.0 devStart
> nodemon app.js

[nodemon] 3.1.0
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,cjs,json
[nodemon] starting `node app.js`
listen on port... 8000
```
何かファイル内を変更し保存してみてください(コメントの追加だけでも大丈夫です)。
以下のように再起動したログが表示されます
```
[nodemon] restarting due to changes...
[nodemon] starting `node app.js`
listen on port... 8000
```

毎回コマンドで再起動しなくて良くなりました!!

### 余談
npmのパッケージをインストールしてるのにソースコードで利用しないのは初めてだったため
少し違和感がありましたが、こうゆう使い方もあるのかと知ることができました。
【Dependabot】レビュアーを設定する方法

`dependabot.yml` に `reviewers` を記述することでレビュアーを設定できます。

```yml:dependabot.yml
version: 2
updates:
  # Keep npm dependencies up to date
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    reviewers:
      - "my-org/team-name"
      - "user-name"

```

https://docs.github.com/ja/code-security/dependabot/dependabot-version-updates/customizing-dependency-updates#setting-reviewers-and-assignees

https://docs.github.com/ja/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#reviewers
WindowsPCでJupyterLabを始める（Miniconda利用）

# 概要
Minicondaを利用して、WindowsPCでJupyterLabを使えるようにする手順です。

JupyterLabはPythonの統合開発環境（IDE）で、データ解析や機械学習のためのコード作成、実行、共有を簡単に行うことができます。
 
# ゴール
JupyterLabでNotebookを新規作成し、動作確認までを行います。

# 手順

### 1. Minicondaのインストール
- [Minicondaのダウンロードページ](https://docs.conda.io/en/latest/miniconda.html)からWindows用のインストーラをダウンロードする
- インストーラをダブルクリックして起動し、指示に従ってMinicondaをインストールを進める

### 2. Minicondaのパスを環境変数に追加
- インストールが完了したら、コマンドプロンプトを開く
- 以下のコマンドを実行して、Minicondaのパスを環境変数に追加する
  ※ `u-data` の部分は、自分のユーザーネームに置き換えてください。

  ```
  setx PATH "%PATH%;C:\Users\u-data\miniconda3\Scripts;C:Users\u-data\miniconda3"
  ```
<br>

- 環境変数の追加が完了したら、コマンドプロンプトを一度閉じる

### 3. JupyterLabのインストール
- コマンドプロンプトを開き直し、以下のコマンドを実行してJupyterLabをインストールする
    ※途中で「Proceed?」 と聞かれた場合は、「y」を入力して続行します。

  ```
  conda install -c conda-forge jupyterlab
  ```

### 4. JupyterLabの起動
- インストールが完了したら、コマンドプロンプトで以下コマンドを実行してJupyterLabを起動する

  ```
  jupyter lab
  ```
    ⇒ 自動でブラウザが開き、JupyterLabのダッシュボードが表示されます。


### 5. Notebookでこんにちは
- ダッシュボード画面でNotebookのPython3を選択して、Notebookを開く

![jupyterlab_maru.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3357979/76015ea5-0420-7d92-8e44-19a10020528a.png)

- Notebookのセルに以下を入力して実行する

  ```
  print('Hello World!')
  ```

<br>

無事、「Hello World!」と出力されました。

![jupyterlab_hello.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3357979/1c33bd49-e31e-a4e6-2037-c1e0d6e60d9a.png)


# おわり

以上で、JupyterLabを使えるようになりました。
ハードウェアについて簡単にまとめ

## アジェンダ
コンピューターのハードウェアについて簡単にまとめます。ハードウェアとは、コンピューターシステムを構成する物理的な部品のことを指し、これには私たちが日常的に使用するデバイスや内部の構成要素が含まれます。本記事では、ハードウェアの基本的な概念、歴史、種類、そして主要な構成要素について記述します。

文字だけだとイメージしずらければ、以下のサイトでイメージ図を見ながら読み進めてください。
[コンピュータの「５大構成要素」を理解する | HINODE ICT lab](https://lab.hinode.or.jp/blog/web/archive/2734)

## ハードウェアについて
ハードウェアはコンピューターおよびそれにまつわる機器全般のことを言います。ソフトウェアが直接触ることができないものと考えれば、対照的に直接触ることができるものと考えるとイメージしやすいかもしれません。

### コンピューターの歴史
[コンピューターの歴史](https://www.komazawa-u.ac.jp/~kobamasa/reference/nenpyo/computerHis_UeyamaS/computerHis_UeyamaS.htm)は、技術の進化とともに大きく変化してきました。

#### 第一世代: 1940年代（第二次世界大戦前後）
1940年代に登場した最初のコンピューターの一つが`ENIAC`（Electronic Numerical Integrator and Computer）です。ENIACはアメリカで開発され、主に弾道計算を目的としていました。`真空管`を使った電子計算機で、部屋全体を占めるほどの大きさでした。

#### ノイマン型コンピューター
同じ時期に、ジョン・フォン・ノイマンは現在のコンピューターの基本構造となるノイマン型アーキテクチャを提唱しました。このアーキテクチャの主な特徴は、`ストアドプログラム方式（プログラム内蔵方式）`と`逐次制御方式`です。プログラムとデータが同じメモリ内に格納され、命令を順次実行する仕組みです。初期の代表的なノイマン型コンピューターには`EDSAC`（Electronic Delay Storage Automatic Calculator）があります。

ストアドプログラム方式（プログラム内蔵方式）: `プログラムを実行するタイミングでデータを主記憶装置に読み込ませる。`
逐次制御方式: `CPUが主記憶装置から命令を前から一つづつ取り出し、順番に実行していく。`

#### 第二世代以降
1950年代以降、トランジスタが導入され、コンピューターはさらに小型化・高速化しました。その後、集積回路（IC）や大規模集積回路（LSI）の登場により、コンピューターの性能は飛躍的に向上し、現在のパーソナルコンピューターやスマートフォンの原型が形成されました。

### コンピューターの種類
#### パーソナルコンピューター
パーソナルコンピューター（PC）は、個人が日常的に使用するためのコンピューターです。デスクトップ型とノート型があり、オフィス作業や家庭での利用が一般的です。

#### サーバー
サーバーは、ネットワークを通じて他のコンピューターにサービスを提供するためのコンピューターです。データの保存やウェブサイトのホスティング、アプリケーションの実行など、多岐にわたる用途があります。

#### 携帯端末
携帯端末にはスマートフォンやタブレットが含まれます。これらのデバイスは、持ち運びが容易で、インターネットの閲覧、メールの送受信、アプリの使用など、多様な機能を備えています。

#### マイクロコンピューター
マイクロコンピューターは、組み込みシステムや制御システムで使用される小型のコンピューターです。家電製品や自動車、工業用機器などに組み込まれています。

### コンピューターの五大装置
コンピューターのハードウェアは5つの装置に分けることができ、それらを`五大装置`と言います。

#### 制御装置
制御装置は、`命令を解釈してコンピューターの動作制御`する装置です。

#### 演算装置
演算装置は、`データの計算や演算処理を実行`する装置です。`論理回路`や`2進数の計算`はここで行われます。

ここまで出てきた制御装置と演算装置を合わせて`CPU`と言います。CPUはコンピューターの脳みそのようなものです。

#### 記憶装置
記憶装置はさらに`主記憶装置`と`補助記憶装置`に別れます。

主記憶装置: `データを一時的に保存する装置`であり、`メモリ`が主記憶装置に該当します。主記憶装置は容量が小さいが、読み書きが速いのが特徴です。

補助記憶装置: `データを長期間保存する装置`であり、`HDD`や`SSD`が補助記憶装置に該当します。補助記憶装置は容量が大きいが、読み書きが遅いのが特徴です。

#### 入力装置
入力装置は文字通り、`データを入力する機器`を指します。`マウス`や`キーボード`、`タッチスクリーン`などが該当します。

#### 出力装置
出力装置は文字通り、`データを出力する機器`を指します。`モニター`や`プリンター`、`スピーカー`などが該当します。

### プロセッサ
プロセッサは、データを処理する装置のこと。

#### CPU(Centeral Processing Unit)
制御装置と演算装置をまとめた呼称。
多数のトランジスタやICチップの組み合わせ。

#### GPU(Graphics Processing Unit)
コンピュータゲームに代表されるリアルタイム画像処理に特化した演算装置。

#### MPU(Micro Processing Unit)
CPUとほぼ違いはない。多数のトランジスタやICチップの組み合わせで構成されていたCPUを一枚のIC（LSI）で実現したもの（CPUとして用いられる）。

#### SoC(System on a Chip)
CPU機能 ＋ メモリなど必要とされる全ての機能をIC（LSI）に搭載した半導体チップ。

#### ワンチップマイコン(シングルチップマイコン)
SoCに似ているが、メモリ機能以外にも入出力機能もIC（LSI）に搭載。

## 参考
[ハードウェア - 用語集|EdTechZine（エドテックジン）](https://edtechzine.jp/glossary/detail/%E3%83%8F%E3%83%BC%E3%83%89%E3%82%A6%E3%82%A7%E3%82%A2)  
[【A試験_ハードウェア】01. 五大装置とノイマン型コンピューター | 基本情報技術者試験 - YouTube](https://youtu.be/dyDRuPZkjcw?si=FmQpkmNvAtMNDIJW)
メールサーバーの仕組みとプロトコル（SMTP、POP、IMAP）

近頃、ネットワークの知識をよく使うことがあるため、メールサーバーの仕組みとプロトコルについてまとめたいと思います。

個人的にはSMTPとIMAPの違いが良くわからないと思うので、その違いについても記載します。

## メールサーバーのしくみ

メールサーバーの仕組みについて簡単にまとめます。

### メールサーバーの種類
メールサーバーでは、メールの受信と送信の２種類から成り立っています。

| 種別　| 説明 | プロトコル 　|
|:-----------|:------------|:------------|
| 受信       |メールを受け取り、PCからダウンロードして閲覧できるようにすることができるもの|POP, IMAP|
| 送信     | PCなどから送信されたメールを、相手に届けるために相手先のサーバーに送るもの| SMTP |


### メールの受信プロセス
箇条書きになりますが、メールの受信プロセスは以下のような手順で実施されます。
1. メールクライアントはユーザーの受信サーバー（POP3/IMAPサーバー※1）に接続
2. 受信サーバーからメールをダウンロードまたは同期
3. ユーザーはメールクライアントを通じてメールを閲覧

※1 POP3/IMAPサーバー：「POP3：メールを受信するためのサーバー。メールをローカルデバイスにダウンロードし、通常はサーバーから削除するサーバー」、「IMAPサーバー：メールを受信するためのサーバー。メールをサーバー上で管理し、複数のデバイスで同じメールボックスにアクセス・同期するサーバー」


### メールの送信プロセス
一方のメールの送信プロセスは以下のような手順です。
1. メールクライアント（Outlook、Gmailなど）はユーザーからメールを受け取る
2. メールクライアントはSMTPサーバー(※2)に接続し、メールを送信
3. SMTPサーバーは、送信先のドメインを解析し、相手のSMTPサーバーにメールを転送
4. 相手のSMTPサーバーはメールを受け取り、相手の受信サーバー（POP3/IMAPサーバー※1）にメールを保存

※2 SMTPサーバー：メールを受信するためのサーバー。メールをサーバー上で管理し、複数のデバイスで同じメールボックスにアクセス・同期するサーバー

### メールで使用されるプロトコルの種類
先ほどもメールサーバーごとに対応プロトコルを記載しましたが、プロトコルに焦点を当てて、説明したいと思います。

従来のメールサーバーはPOP3で受信し、SMTPで送信するという単純なものでした。
|種別　　 　|プロトコル　　 　|ポート　　 　| 特徴　
|:-----------|:------------ |:------------|:------------
| 受信       |POP3 |110| メールをダウンロードして端末で管理
| 受信       |IMAP |143| メールはダウンロードせずサーバーで管理
| 送信       |SMTP |25| メール送信（サーバーと端末、サーバー同士）に使われる

これらのプロトコルの問題点として「通信の暗号化が実施されない」という欠点もあるため、安全性の高いプロトコルが存在しています。


|種別　|プロトコル　　　　 |ポート　　| 暗号化の種類　| 備考　　|
|:-----------|:------------ |:------------|:------------|:------------|
| 受信       |POP3s |995|SSL(TLS)|
| 受信       |IMAP4s |993| SSL(TLS)|
| 送信       |SMTP |465 or 587| SSL(TLS)|いずれのポートでも利用可能

最近は、メールの受信側・送信側のいずれもSSL（TLS）での暗号化を行なった上で通信を行うことが必須となっています。

# メールサーバーの安全性を高める方法

### メールサーバーの設定
ここまでの話を簡単にまとめると、以下のようになります。
+ メールの送受信は、SMTPサーバーとPOP3/IMAPサーバーを使って行われる。
+ 送信側はSMTPサーバーを使ってメールを相手のSMTPサーバーに転送し、受信側はPOP3/IMAPサーバーを使ってメールをダウンロードまたは同期する。

上記の内容に基づいて、全性の高いおすすめの設定は、暗号化が施された以下の組み合わせです。

+ 受信：POP3s or IMAP4s
+ 送信：SMTPs

最近はメールの送信でOP25B(※1)を設定するケースが増えている見たいです。

OP25B：Outbound Port 25 Blockingのことであり、25番ポートを使用したSMTPによる送信をブロックする仕組み

OP25B を設定することで、ウィルスメールなどを防ぐことができるので、利用することが推奨されます。

### まとめ
色々と書いてましたましたが、まとめているとかなり奥が深いです。（自分でまとめてみて、理解できたところもありました。）

何か皆様の参考になりましたら、幸いです。
Cypress から Playwright への変更

## 環境
Next React
## Playwright 導入の経緯
E2Eテストで品質を担保すべく Cypress を導入したが、テストが長くなるにつれて動作が遅くなった。
また、ブラウザが落ちることも多々あったので、違うE2Eテストの方法を考える必要があった。

Cypress の改善しましたが、期待するほどのパフォーマンス改善が見られなかったです。

[公式ドキュメント](https://playwright.dev/docs/intro)

## Install

```bash
npm init playwright@latest
```

github Actions を使うのか？などを聞かれますので状況に応じて選択してください。

## 書き方

### ページ遷移
```typescript
await page.goto('https://playwright.dev/');
```
### クリック
```typescript
// Role の場合
const getStarted = page.getByRole('link', { name: 'Get started' });
await getStarted.click();

await page.getByTestId("login-button").click(); // data 属性
await page.locator("css=button").click(); // css の場合
await page.locator(".className").click(); // class の場合
await page.locator("#id").click(); // id の場合
```

### テキストの取得
```jsx
<div>
  Hello
  <span>world</span>
</div>
<div>Hello</div>

// Matches <span>
page.getByText('world')
// Matches first <div>
page.getByText('Hello world')
// Matches second <div>
page.getByText('Hello', { exact: true })
```

### 実際のテスト

```typescript
import { test, expect } from '@playwright/test';

test('has title', async ({ page }) => {
  await page.goto('https://playwright.dev/');

  // Expect a title "to contain" a substring.
  await expect(page).toHaveTitle(/Playwright/);
});
```

## テストの実行
https://playwright.dev/docs/running-tests
```bash
npx playwright test
```
```bash
npx playwright test --ui
```
特定のテストを実行
```bash
npx playwright test -g "add a todo item"
```
Slack次世代プラットフォームにおけるトリガーの変更を反映させる方法

## はじめに: 問題
Denoを用いてSlack次世代プラットフォームの開発をしている際に、トリガーの変更内容が反映されない事象が発生しました。(ちなみにワークフローやファンクションは変更内容が逐一反映されます。)


## 解決方法

https://github.com/slack-samples/deno-code-snippets/issues/9

上記Issueの通りなのですが、トリガーをローカルで変更してもSlackサーバー側で変更が反映されません。
したがって一度既存のトリガーを削除し、再作成すればトリガーの変更が反映されます。

```bash
% slack trigger delete
% slack trigger create
```

## おわりに
いかがだったでしょうか。

Slack次世代プラットフォームに関する日本語の記事等が少ないので、これからもTips的な内容を投稿していきます。
LeetCode入門してみた①

# はじめに

最近、業務で実装する時間よりも資料作成やレビューをする時間が多くなってきました。
このままでは自身のコーディング能力が落ちそうで怖いので、LeetCodeを始めてみました。

自身の学習の記録 & LeetCodeに興味のある人が挑戦しやすいように、記事に残していきます。
このような競技プログラミングをした経験がないので、ひよってEasyからやっていきます...

## 1768. Merge Strings Alternately

### 初版

ひとまず、シンプルにやってみた。
Runtimeが遅すぎる...

#### コード

```typescript
function mergeAlternately(word1: string, word2: string): string {
    const word1Letters = word1.split("");
    const word2Letters = word2.split("");
    const length = (word1Letters.length < word2Letters.length) ? word2Letters.length: word1Letters.length;

    const letters = [];
    for (let i=0; i<length; i++) {
        if (i < word1Letters.length) { letters.push(word1Letters[i]); }
        if (i < word2Letters.length) { letters.push(word2Letters[i]); }
    }

    return letters.join("");
};
```

#### 結果

Runtime：68ms
Beats 12.06% of users with TypeScript

Memory：51.56MB
Beats 76.99% of users with TypeScript

### ループ回数削減

不要なループや条件を削除してみた。
一気にRuntimeが短くなった。

#### コード

```typescript
function mergeAlternately(word1: string, word2: string): string {
    const word1Letters = word1.split("");
    const word2Letters = word2.split("");
    const word1Length = word1Letters.length;
    const word2Length = word2Letters.length;

    const letters = [];
    if (word1Length === word2Length) {
        for (let i = 0; i < word1Length; i++) {
            letters.push(`${word1Letters[i]}${word2Letters[i]}`);
        }
    } else if (word1Length < word2Length) {
        for (let i = 0; i < word1Length; i++) {
            letters.push(`${word1Letters[i]}${word2Letters[i]}`);
        }
        letters.push(word2.slice(word1Length));
    } else /*if (word1Length > word2Length)*/ {
        for (let i = 0; i < word2Length; i++) {
            letters.push(`${word1Letters[i]}${word2Letters[i]}`);
        }
        letters.push(word1.slice(word2Length));
    }

    return letters.join("");
};
```

#### 結果

Runtime：48ms
Beats 95.30% of users with TypeScript

Memory：51.57MB
Beats 76.99% of users with TypeScript
【初心者向け】基本的なGitのコマンド

こんにちは！
新卒1年目の小川です。
ご覧いただきありがとうございます。

今回は、Gitのコマンドについてまとめたいと思います。

# こんな人に読んでほしい
* Gitを使い始めた方
* Gitに苦戦している方

# 使用環境
* Macのターミナル

# 用語解説
ここでは、Gitを使う上で、さまざまな用語が出てくるので、最初に用語の解説をしたいと思います。

## Gitとは?
Gitとは、プログラミングのソースコードの変更履歴を記録、追跡できる**分散型バージョン管理システム**のことを言います。
分散型バージョン管理システムといってもわかりにくいと思うので、もう少しわかりやすくいうと、ファイルのバージョン管理やプロジェクト内での共有がスムーズかつ簡単にできるものです。

## ローカルリポジトリ
**ローカルリポジトリ**とは、自分のパソコン上で操作・作業するときに使うリポジトリのことです。

## リモートリポジトリ
**リモートリポジトリ**とは、サーバ上に配置され、複数人で共有することができるリポジトリのことです。

## branch
**branch**とは、1つのプロジェクトから分岐させることで、プロジェクト本体に影響を与えることなく、開発をすることができるもののことです。

## トピックブランチ
**トピックブランチ**とは、短期間で行う場合や特定の課題やバグ、機能の追加などを行いたいときにメインで使うブランチとは別で作成できるブランチのことです。
後にメインのブランチに統合することもできます。

# pushの流れ
**push**とは、ローカル環境で作業していた内容を、保存し、指定のbranchにアップロードしていくことです。

## git add
まず最初に、ステージングという作業をします。
これは、作業内容を保存するための準備をする段階です。
この作業を行わないと、これ以降のコマンドが機能しないので、必ず行うようにしてください。
また、git add には、複数指定して行うことができます。
以下でコマンドと一緒に紹介するので、自分が使うシーンに合わせて活用してください。

```:
 git add .         　#これまで作業してきた全ての内容をステージングする
 git add ファイル名　　#指定したファイルの作業内容をステージングする
 ```
 
## git commit -m
git commitは、addで準備したものを実際に保存するものです。
コミット名を記載することで、以前登録したときから何を変更したのかがわかリヤすくなります。
そのため、コミット名は自分が理解できていることもそうですが、あとで紹介するpullを誰かがするときに、他の人でもわかるようにしておくと、認識の違いが起こりにくくなります。
以下が実際に入力するコマンドです。

```:
git commit -m "コミット名"　#保存する
```

## git push origin branch名
git pushは、記録したものを実際に保存したいbranchにアップロードするコマンドです。
pushをすることで、変更内容をアップロードすることができます。
以下が実際のコマンドです。
```:
git push origin ブランチ名　#指定したブランチに保存する
```

# pull
**pull**とは、リモートリポジトリの最新の情報を自分のローカルリポジトリに取り込むことです。
以下がコマンドになります。

```:
git pull ブランチ名
```

# mergeの流れ
**merge**とは、トピックブランチなど、別のbranchで作業をしていた場合、そのトピックbranchをメインのbranchに統合したいときに使います。

## pushの流れのcommitまで実行
まずは、上記のpushで紹介したcommitまでの流れを進めて、保存していきます。
以下でも改めてコマンドを紹介します。
```:
git add . 
git commit -m "コミット名"
```

## branchの切り替え
別のブランチから移したい先のブランチに切り替える必要があります。
もし、別のブランチではなく、メインのブランチで作業をしている場合は、この作業は必要ありませんので、pushをしてください。
以下は保存したい先のbranchに切り替えるコマンドです。
```:
git switch ブランチ名　#切り替えたい先のブランチを指定して切り替える
```

## merge
上記の作業が終わったら、mergeをしてメインのブランチに別のブランチの内容を統合します。
以下が実際のコマンドです。
```:
git marge ブランチ名 　#メインではなく、トピックブランチ名を入力して統合する。
```

## push 
そして、最後にpushをして、mergeの作業は終了です。
```:
git push origin ブランチ名
```

* git merge --abort    　　　　マージの中止
* git branch —no-merged    　mergeできていないものを表示する

# その他の便利なコマンド
上記で紹介した以外にもよく使うコマンドがあるので、以下で紹介したいと思います。

* git status               
    * addやcommitのし忘れなどがないかを確認する
* git log                  
    * logの確認
* git branch               
    * branchの一覧を表示する
* git switch -c 新規ブランチ名
    * 新しいトピックブランチを作成する

# 最後に
今回はよく使うgitのコマンドにつyいてまとめてきました。
gitは慣れるまでに時間がかかったり、分からなくなったりすることがあるかもしれませんが、繰り返し行うことで、わかってくるようになります。
この記事が少しでも参考になれば嬉しいです。
ここまで読んでいただきありがとうございました！
知られていないF13(ファンクションキー)以降のキー

実は、 ファンクションキー (F1~F12) 以降にも存在しF24まで存在する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802707/9caab1c4-7e71-c2f9-4969-5f29b5118584.png)

多くのキーボードには、F12までしかないが マクロキーボードの設定や一部のキーボード(PC122 keyboard)にはF13からF24まで存在します。

これらのファンクションキーは通常のキーボード同様に認識されます。マクロキーと違い特定のアプリケーションや設定に依存せず使えます。

キーボードショートカットを設定していると次のようなことが起きます。

- 一つのキーボードでショートカットを設定したい
- 大概のキーボードは固有の役割を持っている
- 結局複数の複雑なボタンを押す組み合わせをショートカットに割り当てる

この問題を解決するのが F13からF24のキーボードです。

https://www.youtube.com/watch?v=EhZ23dGujhA
Go言語でパッケージ呼び出し

### プログラムの構成

helloパッケージ
　｜＿　hello.go
main.go

### helloパッケージ内の処理をmain.goで呼び出す

```
package main

import "Fyne01/Lesson1/hello"

func main() {
	hello.Hello()
}
```
Goで宣言できるパッケージは1つだけなので、他言語のようにいくつもパッケージで呼び出すことはできない。
代わりにimportを使って呼び出す。
ソフトウェアキーボード「jQuery Keypad」を使用してみる

# はじめに
お仕事にて`Classic asp`で作成された既存アプリケーションを`Blazor Server`に作り替える作業をしています。
このアプリケーションには、ガラケーの文字入力を模したソフトウェアキーボード(1キーで3文字割り当て)が作成されておりました。
これを`Blazor`で一から作成し直すのは面倒だしコストも掛かります。現在の使用状況を調べたら、3年前を最後に使用されていないようでした。
実質オマケ的な感じでもあればいい状況です。

そこで見つけたのが、ソフトウェアキーボード「jQuery Keypad」でキーのカスタマイズ可能です。

http://keith-wood.name/keypad.html

# 環境
|ライブラリー|バージョン|
|:--|:--|
|jQuery.min.js|3.7.1|
|jquery.plugin.min.js|-|
|jquery.keypad.min.js|2.1.1|

https://github.com/kbwood/keypad

## 準備 
jQuery Keypad 2.1.1のCDNが見当たらなかったため、暫定的に下記サイトを参考に rawgithub.com を使用しています。

https://kanasys.com/tech/99

# CodePen
インライン向けの英大文字と数字とハイフン入力、数値入力の2パターンを作成しました。

:::note warn
余分な記号がないのは、仕様です。
:::

キーボードが表示されない場合、この記事をリロードしてください。

<p class="codepen" data-height="640" data-default-tab="html,result" data-slug-hash="rNgyzEO" data-pen-title="jQuery Keypad Input Demo" data-user="yaju-the-encoder" style="height: 640px; 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/yaju-the-encoder/pen/rNgyzEO">
  jQuery Keypad CharacterInput</a> by やじゅ (<a href="https://codepen.io/yaju-the-encoder">@yaju-the-encoder</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

BlazorでもBoostrapフレームワークを使用しているため、下記サイトのCSSを参考にさせていただきました。

https://kuttsun.blogspot.com/2021/03/jquery-keypad.html

## 工夫点
数値入力で、`+/-`のところを工夫しました。
何も入力がなければ、`-`を表示、負数の場合に`+/-`を押すと正数に、正数の場合に`+/-`を押すと負数に切り替わります。

```js
$.keypad.addKeyDef('MINUS', 'minus', function (inst) {
  let val = Number(this.val())
  if (val != 0 && !isNaN(val))
    this.val(val * -1).focus();
  else if (this.val().length == 0)
    this.val('-').focus();
});
```

# 最後に
`jQuery Keypad`の日本の記事は少ないですね。
カスタマイズ可能なソフトウェアキーボードを作成するには便利ですよ。

次回の記事では、これを`Blazor`で使用できるようにしていきます。

# 参照サイト
https://qiita.com/solabito331/items/f06d613c166e2bed2839

https://qiita.com/kawasima/items/d052d0f4565c7f0a7492
iOS / macOSの構造体をUserDefaultsに保存する

データやパラメータをひとかたまりにした構造体(struct)を丸ごとUserDefaultsに保存し、アプリ起動時に読み出す必要が出てきました。
そのためには構造体の定義時、`Codable`に対応させる必要があります。
```swift
struct CEngineParameter: Codable {
    private var _parameterType = EngineType.water
    public var isEngineEnable = true
    public var differenceHeight = Float(5)
    public var differenceWidth = 32
    ...
    ...
}
```
このように構造体を定義すると、`Codable`に対応したイニシャライザの実装が求められます。
下記のように、対応したイニシャライザを記述します。
```swift
init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
        
    self._parameterType = try container.decode(EngineType.self, forKey: ._parameterType)
    self.isEngineEnable = try container.decode(Bool.self, forKey: .isEngineEnable)
    self.differenceHeight = try container.decode(Float.self, forKey: .differenceHeight)
    self.differenceWidth = try container.decode(Int.self, forKey: .differenceWidth)
    ...
    ...
}
```
_parameterTypeというプロパティはenum型です。
enum型も下記のようにCodableに対応させれば保存可能です。
```swift
enum EngineType: Codable {
    case water
    case air
}
```
この構造体の読み出し・保存がちょっと複雑です。
そこで、構造体に読み出し・保存のメソッドを実装し、使いやすくします。
```swift
public static func load(forKey: String) -> CEngineParameter? {
    if let loadValue = UserDefaults.standard.data(forKey: forKey) {
        let decoder = JSONDecoder()
            
        if let value = try? decoder.decode(CEngineParameter.self, from: loadValue) {
            return value
        } else {
            return nil
        }
    } else {
        return nil
    }
}
```
```swift
public func save(forKey: String) {
    let encoder = JSONEncoder()
        
    if let encodedValue = try? encoder.encode(self) {
        UserDefaults.standard.set(encodedValue, forKey: forKey)
        UserDefaults.standard.synchronize()
    }
}
```
構造体のオブジェクトが複数あっても、UserDefaultsで保存するためのキーを複数用意しておけば対応できます。
【MySQL】起動、ログイン、ログアウト、停止

## 概要
MySQLの管理に必要なコマンドを紹介しています。

<br>

## MySQL一連の手順


#### MySQL起動
macOSまたはLinuxでHomebrew がインストールされている場合にのみ機能
```bash:コマンド
brew services start mysql@5.7
```

#### MySQLログイン
```bash:コマンド
mysql --user=root --password
```

#### MySQLログアウト
```bash:コマンド
exit;
```

#### MySQL停止
```bash:コマンド
brew services stop mysql@5.7
```


## brewとは

Homebrew（通称 "`brew`"）のことで、macOSおよびLinux用のパッケージ管理ソフトウェアです。
Homebrewを利用することで `brew` コマンドが使えるようになり、ソフトウェアのインストール、アップデート、管理がコマンドラインから簡単に行えます。
iOSデバイスが実機かシミュレータかを判断する方法

iOSアプリでBluetoothを使ったアプリを開発しています。
macOSのシミュレータではBluetooth接続ができません。
シミュレータでデバッグするときは、`擬似的にBluetoothからデータが来たように見せかけるテストモード`を用意しました。
そのため、実機かシミュレータかを判断する必要があります。
```swift
#if targetEnvironment(simulator)
    private let isDemoMode = true
#else
    private let isDemoMode = false
#endif
```
これで実機を使わなくてもデバッグができるようになりました。
iOS / macOSアプリでAssets内の音声ファイルを再生する

開発中のiOSアプリで、Bluetoothから送られてくるデータで異常を検出したとき、「音」と「振動」で知らせる必要に迫られました。

まずはAVFoundationをインポートします。
```swift
import AVFoundation
```

音声ファイルを用意します。今回はシンセサイザーのバーチャルアナログ音源を使って簡単なビープ音を作り、それをWAVファイルにエクスポートしました。
そのファイルAssetsへ入れます。
Assetsに音声ファイルをドラッグ&ドロップします。
ソースコード内で参照する名前をつけます。今回は「Sending Sound」という名前にしました。
![スクリーンショット 2024-06-02 21.52.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202602/a95d563b-6dff-f8d8-acc1-9f1592a73b0c.png)

AVAudioPlayerのプロパティを宣言します。
```swift
private var sendingSound: AVAudioPlayer!
```
Assetsからオーディオファイルのオブジェクトを取得します。
オーディオファイルは確実に存在するので、今回はエラー処理は省略しています。
```swift
let soundFile = NSDataAsset(name: "Sending Sound")!
```
AVAudioPlayerのオブジェクトを生成します。
```swift
sendingSound = try? AVAudioPlayer(data: soundFile.data, fileTypeHint: "wav")
```
あとは再生、ポーズ、音量変更などのメソッドを呼び出せば簡単に使えます。
```swift
sendingSound.play()  //再生
sendingSound.play()  //停止
sendingSound.pause() //ポーズ(綺麗に再生解除ができる)
sendingSound.setVolume(volume: Float, fadeDuration: TimeInterval)
sendingSound.currentTime = 0 //再生位置を先頭に戻す
sendingSound.numberOfLoops = -1 //ループ回数して、-1で無限ループ
```
このほかにもいろんなメソッド、プロパティが用意されています。
ひとまず、これらを利用すれば簡単に音声ファイルの再生をできることがわかりました。
iOS、macOSどちらも同じソースコードで動作します。
登録セキスペ オンライン講習 2023 参考資料備忘録 #1

# 情報セキュリティ10大脅威 2023
毎年IPAから発表される情報セキュリティ10大脅威はランキング形式でセキュリティが発表されます。昨年は「個人」では「ワンクリック請求等の不当請求による金銭被害」、「組織」では「犯罪のビジネス化」が初めて10位にノミネートしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469079/a059dc37-da33-4dc9-6ec7-a26e10f458cf.png)

* 参考

https://www.ipa.go.jp/security/10threats/10threats2023.html

# サイバー空間における脅威の概況 2022
公安調査庁によって発表されている資料です。ここ数年で世界的なニュースとなったサイバー犯罪についてまとめられています。国内の事例も具体的な企業名などは伏せられてはいますが、掲載されています。

* 参考

https://www.moj.go.jp/content/001371280.pdf

# サイバーセキュリティ戦略の概要
内閣サイバーセキュリティセンターが作成している資料です。概要と本体と2種類のファイルに分かれていますが、本体は長い長い文章にまとめられているファイルなので概要の方を掲載しましたが、それでも読むのが大変です。これが所謂「霞ヶ関曼荼羅」という物なのでしょうか。。。

* 参考

https://www.nisc.go.jp/pdf/policy/kihon-s/cs-senryaku2021-gaiyou.pdf

# 映像コンテンツ
動画で学ぶをコンセプトとしたセキュリティ事例の紹介、対策の紹介動画です。「華麗なるセキュリティ対策」という動画は個人的に扱っている内容は至極真面目な内容ながらアニメの内容が笑ってしまう内容だと思います。面白く？学ぶのには良いのかもしれません。友人に早速共有しました。

* 参考

https://www.ipa.go.jp/security/videos/list.html

# Reference
* 登録セキスペオンライン講習 2023OL1_情報処理安全確保支援士に期待される役割と知識
Javascript　map　配列を新しく作るとは

## map　配列を新しく作るとは
記事を書いたきっかけ

Javascriptでmapを使ったループをさせる方法の書き方を勉強しているときに新しく配列を
作るという言葉の意味がしっくりとイメージをつかめていなかったので記事を作ることにしました！

## 挙動を確かめるためのコード
```
const numbers = [1,2,3,4];
const double = numbers.map(( (value) =>{
   return (value * 2);
 }))
 console.log(numbers);
 console.log(double);
 ```

 ## 実行したコード結果
 ```
 (4) [1, 2, 3, 4]0: 11: 22: 33: 4length: 4
 (4) [2, 4, 6, 8]0: 21: 42: 63: 8length: 4
```
## ここから分かったこと
* mapで配列を生成したときにはmapを使う際のもとになった配列とは参照している先が違うこと
* mapで配列を新しく生成したときに(ここではdouble)元の配列（ここではnumbers）の配列の中身に影響を及ぼさないこと
⇒今回は配列をループするのに使用したnumbersの値に×２をしたものを新しく生成した配列doubleで出力するというコードを書いた。

* numbersの配列の中身は[1,2,3,4,]のままでdoubleの配列の中身は[2,4,6,8]になって上書きされていないことが分かる。
⇒このことから新しく生成した配列と元の定義した配列とはまったく別の配列であることが分かった。

* 参考にした記事
mapメソッドについての基礎
⇒https://qiita.com/NNNiNiNNN/items/3743ce6db31a421d88d0

## JISOUのメンバー募集中！
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。

興味のある方は、ぜひホームページからお気軽にカウンセリングをお申し込みください！
▼▼▼
https://projisou.jp/
python django 書籍管理システム開発備忘録 #１（開発環境構築）

python djangoを使用したwebアプリ開発備忘録
家にある本を管理するシステムを作成してみようと思います。

次の記事
・[python django 書籍管理システム開発備忘録 #２（マイグレーション）](https://qiita.com/syakesoba/items/6dc5cc6e7dbb7c881c83)

## 開発環境構築
まずは環境構築から。
### １．pythonインストール
#### 下記記事を参考にインストール

https://qiita.com/Obataskill/items/4cfe0d4d8cec8a140b8e

インストーラのオプション機能（Optional Features）、高度オプション(Advanced Options)に関しては下記記事を参照

https://3rdplanetblog.com/pg/python-custom-install

### ２．仮想環境作成、djangoインストール、アプリの起動
#### １．下記記事を参考

https://qiita.com/smiler5617/items/92564143097643751027

補足_ディレクトリ構成は以下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806365/c353366f-9781-171e-ccb1-7ff2128dd087.png)

### ３．DB接続設定
#### １．下記記事を参考

https://tech-lab.sios.jp/archives/39339

### その他
#### １．github連携

https://qiita.com/hayaharu3220/items/b7eb57a3689fb8050856

gitの初期設定をしてないとできないかも

https://qiita.com/ucan-lab/items/aadbedcacbc2ac86a2b3

最低でも以下のの設定必要
※git bash上で以下コマンド入力
```
$ git config --global user.name "任意の名前"
$ git config --global user.email "自身のメアド"
```


以上で環境構築は完了です。
次回は実装を始めていこうと思います。

ここで作成したソースはgithubにて公開しております。
興味があればどうぞ。

https://github.com/syakesoba/django_project

次の記事
・[python django 書籍管理システム開発備忘録 #２（マイグレーション）](https://qiita.com/syakesoba/items/6dc5cc6e7dbb7c881c83)
GPT-4oで簡単なWebアプリを作成

# はじめに
GPT-4はプロンプトの応答が遅かったのですが、GPT-4oになってだいぶ早くなったというのを目にしていました。出力の精度も確認したかったので、簡単なWebアプリを作成してみようと思いました。

# アプリケーションの概要
- Node.jsでTodo管理するWebアプリケーション
- ユーザ登録、ログイン、トークン認証あり
- プロジェクトと、プロジェクトごとのTodoの追加

　※あくまでサンプル的なものなのであまり期待せずでお願いします。

# GPT-4o　プロンプト入力
プロンプトは以下で入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468278/a543ddfb-4ae1-3593-02bf-f0fcf6cc4490.png)

# GPT-4o　プロンプト応答

出力されたプロジェクト構造
```
my-todo-app/
│
├── node_modules/
├── app.js
├── config.js
├── database.js
├── routes/
│   ├── auth.js
│   ├── projects.js
│   └── todos.js
└── models/
    ├── user.js
    ├── project.js
    └── todo.js
```

その後にそれぞれのソースを出力してくれます。全てのソースを出力しますが、一部のみ記載します。
```app.js
const express = require('express');
const bodyParser = require('body-parser');
const authRoutes = require('./routes/auth');
const projectRoutes = require('./routes/projects');
const todoRoutes = require('./routes/todos');

const app = express();
const PORT = process.env.PORT || 3000;

// ミドルウェア設定
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
.
.
.
(省略)
```

最後にプロジェクトの起動コマンドを出力して終わります。
```sh
npm install
npm start
```

# アプリケーションの起動
```
npm start

Server is running on port 3000
```
起動してみたはよいのですが、画面がありません。追加してもらいましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468278/68a6af4a-6981-c150-adb0-d9933383675d.png)

publicフォルダ下の3ファイルが追加されました。
```フォルダ構成
my-todo-app/
│
├── node_modules/
├── public/
│   ├── index.html ・・・追加
│   ├── style.css  ・・・追加
│   └── app.js     ・・・追加
├── app.js
├── config.js
├── database.js
├── package.json
├── routes/
│   ├── auth.js
│   ├── projects.js
│   └── todos.js
└── models/
    ├── user.js
    ├── project.js
    └── todo.js
```

動かしてみましょう。
localhost:3000

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468278/2cbe2fa2-86f0-8bc0-41df-f6fce9d0e6d2.png" width="400px">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468278/bdcfb531-602a-42c7-b337-293bd9f6c96e.png" width="400px">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468278/05e07bb8-6f04-b251-acf0-0394c58b9449.png" width="400px">

プロジェクトを選択します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468278/a77aed55-3896-c29d-8328-608106d74c98.png" width="400px">

Todoを追加します。表示されたTodoを削除します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468278/e12b2ad6-5e8f-247d-4779-40113726e046.png" width="400px">


# まとめ
GPT-4oを使ってみて、GPT-4と比べてプロンプトの応答が体感でもかなり早くなっていることが分かりました。出力されたファイルの精度は高く、いくつか不足しているソース、処理がありましたが、9割くらいはそのまま動かせるものでした。プログラムの初期作成はAIが中心になっていくでしょう。
CloudFrontでのBasic認証

## はじめに
Basic認証は、HTTPプロトコルを使用してWebサーバーとクライアント間でユーザー認証を行うためのシンプルな方法です。
本記事では、CloudFrontでのBasic認証について解説します。

## 実装について

CloudFrontでBasic認証を実装するにはいくつかの方法があります。

・Lambda@Edgeの利用
・CloudFront Functionsの利用
・Amazon CloudFront KeyValueStore＋CloudFront Functionsの利用

本記事では3つ目の「Amazon CloudFront KeyValueStore＋CloudFront Functionsの利用」について説明します。
この実装方法では、複数のユーザ名/パスワードを管理し、Basic認証を実装することが可能です。

## CloudFront Functions

CloudFront FunctionsはCloudFrontのコンテンツ配信ネットワークで、シンプルな処理をより高速に、素早く、安価に実行できるサービスです。

◆CloudFront FunctionsとLambda@Edge

|                        | CloudFront Functions | Lambda@Edge           |
|------------------------|----------------------|-----------------------|
| プログラミング言語      | JavaScript           | Node.js,Python         |
| イベントソース          | Viewer request, Viewer response | Viewer request, Viewer response,<br> Origin request, Origin response|
|Scale                   |リクエスト数: 毎秒 10,000,000 件以上|リクエスト数: 1 リージョンあたり毎秒 10,000 件まで|
|最大実行時間             |1ms未満|5s (Viewer request, Viewer response),<br>30s (Origin request, Origin response)|
|最大メモリ               |2MB|128 ～ 3,008MB|
|最大サイズ               |10KB|1MB (Viewer request, Viewer response),<br>50MB (Origin request, Origin response)|

上表の通り、CloudFront FunctionsはLambda@Edgeに比べ制限が厳しくなっています。
また、ネットワークやファイルシステムへのアクセスなどもできないため、DynamoDBや外部のAPIを叩くような処理についてはCloudFront Functionsではできません。

◆料金
・100 万件の呼び出しあたり 0.10USD (1 回の呼び出しごとに 0.0000001 USD)

https://aws.amazon.com/jp/cloudfront/pricing/?nc1=h_ls

## Amazon CloudFront KeyValueStore

CloudFront KeyValueStore は、CloudFront Functions 内からの読み取りアクセスを許可する、安全でグローバルな低レイテンシーのキーバリューストアです。

◆ユースケース
・**URL の書き換えまたはリダイレクト**：キーと値のペアには、書き換えられた URL またはリダイレクト URL を含めることができます。

・**A/B テストと機能フラグ**：ウェブサイトの特定のバージョンにトラフィックの割合を割り当てることで、テストを実行する関数を作成できます。

・**アクセスの許可**：独自に定義した条件とキー値ストアに保存したデータに基づいて、リクエストを許可または拒否するアクセスコントロールを実装できます。

◆サポートされている値の形式
キーと値のペアの値は、以下のいずれかの形式で保存できます。

・文字列
・バイトでエンコードされた文字列
・JSON

## まとめ
KeyValueStore で認証情報を管理することにより、アプリケーションコードのデプロイを行うこと無く、認証情報の追加や変更を行うことができるようになります。
ただし、マネジメントコンソールにアクセスさえできればユーザー名とパスワードが平文で見えてしまうという点には注意が必要です。

## 参考
https://qiita.com/Haruki-N/items/37cb6745d1837328268b
【UE5】ゼロから極めるゲーム開発　その1

ゲーム開発開始

早速かなり放置してしまいました。
更新早めに努力します。

# プロジェクトの作成
「起動」ボタンからUEを起動する。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779049/d3d55bb0-ea7d-cc77-e5db-881266bcc475.png
">

プロジェクトの初期設定はこんな感じ
![プロジェクト所きせてい.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779049/0a10c48a-97c9-bbd1-3d98-21934cff0dbf.png)
上から
1. 「ブループリント」か「C++」のどちらを使用するかを選択。今回はブループリントを使用
1. PC向け開発なのでデスクトップを選択
1. 品質プリセットには「Maximum」(最高品質)と「Scalable」(可変品質)がある。今回はとりあえずScalableで
1. スターターコンテンツ。初期素材として使用できるアセットの詰め合わせ
1. レイトレーシング。よくわからない。

設定が終わったら「Blank」でプロジェクトを作成。

出来ました。
![スクリーンショット 2024-05-08 224239.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779049/030af1c3-ccbb-8281-2700-a62c6bd08c1f.png)


デスクトップにショートカットを作成するためにいったん閉じてEpic Games Launcherに移動する。
作成したプロジェクトを右クリックでショートカット作成。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779049/f8f1db0f-88a1-c5eb-7cec-f6dd936bf5e0.png)

# レイアウトの設定

初期のレイアウトがこんな感じ。使いづらそうなので変更する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779049/11c5cac6-9083-b4f0-e662-afb1b3a48888.png)

[ウィンドウ]メニュー > コンテンツブラウザ > コンテンツブラウザ2 を選択するとコンテンツブラウザが画面に現れる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779049/2eb42859-ad6f-6b43-97c3-70fc3b03c1e5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779049/a4a88652-e2a7-a2b0-4e43-438186b2854b.png)


これをドラッグして好きなところに配置する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779049/087e3449-816a-10c5-949f-574b3655c96d.png)


次にアクタの配置パネルを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779049/aacec072-cef1-5c94-714f-913b6dc36e4d.png)

こういうのが画面左側に出てくるので、右クリックしてサイドバーにドックを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779049/702f78b4-5f31-b520-133e-c64c402be224.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779049/4d41c01f-b336-9589-e422-f4099377dbed.png)


最終的な画面はこんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779049/db9364ac-510a-ac2f-68db-4576e194ce79.png)

レイアウトの保存もできる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779049/262f0f57-c1af-1a78-db78-eb9336a62ec7.png)

# プロジェクトの基本設定

プロジェクト立ち上げ時の画像を変更できる

画面右端の設定からプロジェクト設定を選択する。
なかなかわかりずらいところにある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779049/9e1c0dec-d246-c33e-5622-1745ba9ea58f.png)

プラットフォーム > windowsを選択する
エディタスプラッシュとゲームスプラッシュを変更する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779049/586c958c-b292-2112-3a22-f2c59e758ef9.png)

こんな感じで変わる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779049/e8263c8a-f198-f362-e45e-a67fd2e12b37.png)
Python学習で僕がやったことを公開

# Pythonプログラミングチュートリアル

こんにちは！
私はPython未経験から案件に入ったのですが、同じ体験をする人がいるかもしれないので僕が案件参画までにやったことをまとめました。

以下にチュートリアル的な感じで作成しているのでやってみて下さい。

https://github.com/masakiShito/python-tutorial

この記事では、私が作ったチュートリアルの概要を説明します。

## 対象読者

このチュートリアルは、以下のような読者を対象としています。

- Pythonプログラミングを初めて学ぶ初心者
- 基礎的なPythonスキルを磨きたい中級者
- 実際のプロジェクトでPythonを活用したいと考えている方
- Pythonの標準ライブラリや応用例を学びたい方

## チュートリアルの意図

このチュートリアルを作成した意図は、以下の通りです。

1. **基礎から応用まで一貫した学習**:
    - Pythonの基礎から始めて、オブジェクト指向プログラミングや例外処理、標準ライブラリの使い方まで体系的に学べるように構成しています。

2. **実践的なスキルの習得**:
    - 基礎的な知識を学ぶだけでなく、実際に手を動かしてコーディングすることで、実践的なスキルを身につけることを目指しています。

3. **豊富な練習問題**:
    - 各セクションに練習問題を設け、学んだ内容を確認し、実践する機会を提供しています。

4. **応用例**:
    - 基礎を固めた後には、実際の応用例を通じて、Pythonを使った具体的なアプリケーションの開発方法を学びます。

## 各セクションの概要

### 1. はじめに

このセクションでは、Pythonとは何か、Pythonを学ぶ理由、Pythonのインストール方法について説明します。Pythonの基本的な構文や簡単なプログラムの書き方も紹介します。

### 2. Pythonの基本

ここでは、変数、データ型、基本的な演算子など、Pythonの基本的な要素について学びます。また、基本的な入出力やコメントの書き方についても触れます。

### 3. データ型とデータ構造

このセクションでは、リスト、タプル、セット、辞書などのデータ構造について詳しく学びます。各データ構造の使い方や特徴、適切な使用場面についても説明します。

### 4. 制御構文

条件分岐、ループ、リスト内包表記などの制御構文について学びます。効率的なコードを書くためのテクニックも紹介します。

### 5. 関数とモジュール

関数の定義と呼び出し方法、引数と戻り値、ラムダ関数、モジュールのインポートと使用方法について学びます。

### 6. オブジェクト指向プログラミング

クラスとオブジェクト、継承、ポリモーフィズムなど、オブジェクト指向プログラミングの基本概念を学びます。Pythonでの実装方法についても詳しく説明します。

### 7. 例外処理

例外の発生とキャッチ、独自の例外クラスの作成方法について学びます。エラーが発生した際の対処方法についても説明します。

### 8. 標準ライブラリ

Pythonの標準ライブラリについて学びます。よく使うモジュールとその使い方、便利な機能について紹介します。

### 9. 応用例

ここでは、実際のプロジェクトで使える応用的なテクニックやコード例を紹介します。実践的なスキルを身に付けることができます。

---

このチュートリアルを通じて、Pythonの基礎から応用までしっかりと学び、実践的なスキルを身につけることができます。
皆さんのPython学習が充実したものになりますように！

https://github.com/masakiShito/python-tutorial
機械学習における、ファインチューニング、転移学習、蒸留

## 目的
各手法がいまいちピンとこなかったため、生成AIにて学習


## 一覧表

| 手法 | 説明 | 特徴 | 利点 | 欠点 | サンプル |
|------|------|------|------|------|---------|
| ファインチューニング | 事前学習済みモデルのパラメータを、新しいタスク用のデータで再学習すること。 | - 事前学習済みモデルの一部または全部のパラメータを更新する。<br>- タスク固有のデータを用いて学習する。 | - 少量のデータでも高い性能を発揮できる。<br>- タスクに特化したモデルを得られる。 | - 事前学習済みモデルの知識が上書きされる可能性がある。<br>- タスクごとにモデルを保存する必要がある。 | スマートフォンで撮影した料理の画像を分類するために、ImageNetで事前学習したVGG16をファインチューニングする。 |
| 転移学習 | 事前学習済みモデルの知識を、関連するタスクに活用すること。 | - 事前学習済みモデルの一部または全部のパラメータを固定または更新する。<br>- 関連するタスクのデータを用いて学習する。 | - 事前学習済みモデルの知識を活用できる。<br>- 少量のデータでも高い性能を発揮できる。 | - タスク間の関連性が低い場合、転移がうまくいかない可能性がある。<br>- 事前学習済みモデルの選択が重要となる。 | Wikipediaで事前学習したWord2Vecを、映画レビューの感情分析タスクに転移する。 |
| 蒸留 | 大規模な教師モデルの知識を、小規模な生徒モデルに転移すること。 | - 教師モデルの出力を疑似ラベルとして使用する。<br>- 生徒モデルを教師モデルの出力に近づけるように学習する。 | - 小規模なモデルでも高い性能を発揮できる。<br>- 推論時の計算コストを削減できる。 | - 教師モデルの選択が重要となる。<br>- 蒸留による性能低下が起こる可能性がある。 | BERT-largeの知識を、モバイルデバイスで動作可能な小規模なBERT-tinyに蒸留する。 |

### 知識定着のための問題：

1. 問題：大量の猫と犬の画像データを用いて、猫と犬を分類するモデルを構築したい。しかし、手元にあるデータは1,000枚程度と少ない。どの手法を用いるべきか？


2. 問題：大規模な言語モデルを用いて、文法誤り訂正システムを構築したい。しかし、推論時の計算コストを抑えるために、モデルのサイズを縮小する必要がある。どの手法を用いるべきか？


3. 問題：ある企業では、従業員の職務満足度を予測するモデルを構築したい。しかし、職務満足度に関するデータが少ない。一方で、過去に実施した従業員アンケートのテキストデータが大量にある。どの手法を用いるべきか？


4. 問題：オンライン学習プラットフォームで、生徒の成績を予測するモデルを構築したい。しかし、プラットフォームごとに学習履歴データの形式が異なるため、モデルを各プラットフォームに適応させる必要がある。どの手法を用いるべきか？


5. 問題：自然言語処理のベンチマークタスクで高い性能を示すモデルを構築したい。大規模な事前学習済みモデルを利用できるが、タスク固有のデータも十分にある。どの手法を用いるべきか？


### 回答：

1. ファインチューニングを用いるべきです。ImageNetなどの大規模なデータセットで事前学習したモデル（例：VGG16, ResNet）を、猫と犬の分類タスクにファインチューニングすることで、少ないデータでも高い性能を発揮できます。事前学習によって獲得された画像の特徴抽出能力を活用しつつ、タスクに特化したモデルを得ることができます。

2. 蒸留を用いるべきです。大規模な言語モデルの知識を、小規模なモデルに蒸留することで、推論時の計算コストを抑えつつ、高い性能を維持することができます。例えば、BERT-largeの知識をBERT-tinyに蒸留することで、モバイルデバイスでも動作可能な文法誤り訂正システムを構築できます。

3. 転移学習を用いるべきです。過去の従業員アンケートデータで事前学習した言語モデル（例：Word2Vec, BERT）を、職務満足度予測タスクに転移することで、少ないデータでも高い性能を発揮できます。事前学習によって獲得された言語の理解力を活用しつつ、タスク固有の知識を取り入れることができます。

4. ファインチューニングを用いるべきです。ある学習プラットフォームで事前学習したモデルを、他のプラットフォームのデータでファインチューニングすることで、各プラットフォームに適応したモデルを構築できます。これにより、プラットフォームごとのデータの違いを吸収しつつ、生徒の成績予測の精度を高めることができます。

5. ファインチューニングを用いるべきです。大規模な事前学習済みモデルを、タスク固有のデータでファインチューニングすることで、事前学習の知識とタスク固有の知識を組み合わせた高性能なモデルを構築できます。十分なタスク固有のデータがある場合、ファインチューニングによってモデルをタスクに特化させることが効果的です。

これらの回答は、与えられた問題設定に基づいた一般的な推奨です。実際のモデル構築では、データの性質、タスクの要件、利用可能なリソースなどを総合的に考慮して、最適な手法を選択する必要があります。また、複数の手法を組み合わせることで、さらなる性能向上が期待できる場合もあります。
Next.jsとSupabase AuthでgetUserがnullになる

# はじめに

Next.jsでsupabaseのAuthを使っている中で沼った箇所を書いていきます

# 問題

https://supabase.com/docs/guides/auth/server-side/nextjs

ドキュメント通りに設定をして、アプリケーション開発を行っていたところとあるタイミングで以下の認可のコードでユーザーが取得できなくなりました

```ts

  const { data, error } = await supabase.auth.getUser();
  if (error || !data?.user) {
    redirect("/login");
  }

```

さっきまでユーザーが取れていたのにとナゾになっていました

# 解決方法

middleware.tsのimportがNextResponseよりも手前になっていたのが原因でした

これは動かない
```
import { updateSession } from "@/utils/supabase/middleware";
import { type NextRequest } from "next/server";
```

これならうごく
```
import { type NextRequest } from "next/server";
import { updateSession } from "@/utils/supabase/middleware";
```

最初に検証のときにはうまく設定しており、次にアプリケーション設定をしたときにミスをしていました
最初成功していたのでセッションがずっと効いていたようでログアウトをしたあとから、middleware.tsの位置がおかしいのでセッションをセットすることができなくなっていました

# おわりに

突然起きてしまい数時間を使ってしまいましたがmiddlewareについて理解をふかめられましｔ
普通に開くと文字化けするzipを解凍する(unar -e Shift-JIS aru.zip)

# 概要
配布されたzipが、普通にダブルクリックで開くとファイル名が文字化けしてしまった。

# 環境
Mac Montery 12.6.2
zip作成環境：不明

# したこと
`unar` を活用することにした。

## `unar`のインストール
```bash
brew install unar
```

## `unar`の実行
おそらくshift-jisだろうと思ってまずはそれでチャレンジ
```bash
unar -e Shift-JIS haihu.zip
```

すると、日本語ファイル名がきれいに解凍された。

# 蛇足
なお、haihu.zipを解凍したところ、今度はnakami.zipが出てきた。
なので、`unar -e Shift-JIS nakami.zip`を再度実行してうまく解凍できた。
(二重にzipされていたからうまく解凍できなかった側面もあるのか？)

# 結語
なんとかなってよかった


https://github.com/ashang/unar
https://theunarchiver.com/command-line