OmniAICreator/Qiita-1.07M huggingface dataset:
【初学者】CLIとは？をざっくり覚える

CLIという言葉をよく耳にするのですが、人に説明できるくらいの理解ができていなかったため、改めて学習しました。

# CLIとは？

- CLIは （Command Line Interface：コマンドラインインターフェース）の略称である。
- MacのターミナルやWindowsのコマンドプロントなどがCLIの例である。
- キーボードを利用し、文字を入力してコンピュータに指示をするというものである。
- `pwd`とか`ls`とか`cd`などはCLIコマンドとしてよく使われるコマンドである。
- 昔の例でいうと、Microsoft社がWindows発売前に開発・販売していたのがMS-DOSというコンピュータが、CLIを用いた機械として有名である。

#### 【補足】ターミナルのコマンド例
```
pwd　　　：カレントディレクトリの場所を表示する
ls　　　　：ディレクトリとファイルの一覧を表示する（隠しファイルは除く）
ls -a　　　　：隠しファイルを含むディレクトリ・ファイル一覧を表示
cd 　：ルートディレクトリに移動する
cd [ディレクトリ名]　　　：カレンとディレクトリから指定したディレクトリに移動する
```

> ※pwdについて
print working directoryを略したコマンドで、カレントディレクトリの絶対パスを表示します。絶対パスはシステムの最上位階層（ルートと言います）から対象とするディレクトリやファイルまでの経路を示したものです。

引用：<a href="https://www.sejuku.net/blog/124853#index_id4">ターミナルの使い方・基本的なコマンドについて詳しく解説！</a>


# CLIとCUIの違いは？
- CLIの同義語としてCUI（キャラクターユーザーインターフェース）がある。
- CLIはCUIどちらでも同じで、英語圏ではCLIで使われることが多いらしい。


# CLIとGUIの違いは？
- CLIと対をなすインターフェースとして、よく挙げられるのがGUIである。
- マウスを使って画面上で直感的な操作を実現する技術をGUI（Graphical User Interface：グラフィカルユーザーインターフェース）と呼ぶ。


# 参考サイト

https://e-words.jp/w/CLI.html

https://wa3.i-3-i.info/word16524.html

https://www.sejuku.net/blog/124853
【Python】UnicodeDecodeError: 'cp932' codec can't decode byte 0x81...エラーの原因と解決方法

# 概要
`pandas`で`encoding`を`cp932`に指定してCSVファイルを読み込むコードを実装していたら、以下のエラーが返されました。本記事ではこのエラーの原因と解決方法を記載します。

```
UnicodeDecodeError: 'cp932' codec can't decode byte 0x81 in position 2407: illegal multibyte sequence
```
上記は、文字列をデコードしようとした際に、`'cp932'`（Shift-JIS）というエンコーディング方式を使用した際に発生しています。

# 原因
`UnicodeDecodeError`は、指定されたエンコーディングに基づいてバイト列を文字列にデコードしようとしたときに、不正なマルチバイトシーケンスが見つかったことを意味するエラー。実際のファイルの文字コードと読み込み時に指定した文字コードが異なっているときに表示される変換エラーです。

`0x81`というバイト列は`Shift-JIS`エンコーディングにおいて特定の文字を表すために使用されていますが、`Shift-JIS`のルールに従わない場合、デコードエラーが発生するのです。

以下のどちらかの場合が多いとのこと。
・テキストファイルや文字列が正しいエンコーディングで保存されていない
・ファイル内の特定のバイト列がエンコーディングに合致しない

エンコーディングについてややこしい点は、
・Mac環境でCSVファイルを作成する際のデフォルトのエンコーディングは、一般的に`UTF-8`
ですが、
・Windows環境でCSVファイルを作成する際のデフォルトのエンコーディングは、一般的に`cp932`（Shift-JIS）エンコーディングが多い
ということ。

なのでCSVデータが出力された環境によって適切に指定してあげる必要があります。

# 解決方法
・CSVファイル内の文字列データがUTF-8エンコードされている可能性が高いです。
　`encoding`を`utf-8`にしてあげると解決しました。

```py
csv_encoding = "utf-8"  # エンコーディングを指定
data = pd.read_csv(csv_file_path, encoding=csv_encoding)
```

ということで、Windows環境で作成されたCSVファイルをUNIX系環境やMac環境で扱う際には、エンコーディングの違いに注意する必要があるでしょう。

## 参考
[【Python】UnicodeDecodeError: 'cp932' codec can't decodeの原因と解決方法](https://office54.net/python/error/unicode-decode-cp932)
【Xcode】シュミレーターのダークモード切り替え

# はじめに
[@shota_appdev](https://twitter.com/shota_appdev)と画面共有をしながら開発してたらいいことを教えてもらったので記録しておきます。

# こんな感じ
簡単にライトモードとダークモードの切り替えができます！
![Simulator Screen Recording - iPhone 14 - 2023-08-09 at 22.10.55.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/bf9bc74d-5924-eae3-81d0-33e286860a7d.gif)

# やりかた
Command + Shift + A

# おわり
他の人にコーディングを見てもらうと学びがありますね！
json-rpcのAPIをASP.NET Coreで作る

## 目的
ASP.NET Coreでjson-rpcを用いたAPIを作りたい

## 方法
既存のライブラリ[edjCase/JsonRPC](https://github.com/edjCase/JsonRpc/)を使う

## 作ってみる
ドキュメントをもとに作成

```C#:Program.cs
using EdjCase.JsonRpc.Router.Defaults;
using EdjCase.JsonRpc.Router;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddJsonRpc(config =>
{
    config.BatchRequestLimit = 10;
    config.ShowServerExceptions = true;
    
    config.JsonSerializerSettings = new System.Text.Json.JsonSerializerOptions
    {
        WriteIndented = true
    };

    config.OnInvokeException = (context) =>
    {
        if (context.Exception is InvalidOperationException)
        {
            int customErrorCode = 1;
            var customData = new
            {
                Field = "Value"
            };
            var response = new RpcMethodErrorResult(customErrorCode, "Custom message", customData);
            return OnExceptionResult.UseObjectResponse(response);
        }

        //Continue to throw the exception
        return OnExceptionResult.DontHandle();
    };

}).AddAuthorization().AddAuthentication();


var app = builder.Build();
app.UseJsonRpc();


app.Run();
```

```c#:TestController.cs
using EdjCase.JsonRpc.Router;
using EdjCase.JsonRpc.Router.Abstractions;

namespace jsonrpctest.Controllers
{
    [RpcRoute("/api/test")]
    public class TestController: RpcController
    {
        public async Task<string> HelloWorld()
        {
            
            await Task.Delay(1000); // 非同期実行の確認のため1秒ウエイト
            return "Hello World!";
        }

        public async Task<int> Add(int a, int b)
        {
            await Task.Delay(1000); // 非同期実行の確認のため1秒ウエイト
            return a + b;
        }
    }
}
```

## 試してみる
Azure(AppService)に公開してアクセスしてみた。
→普通に動いた。メソッドを3回コールしたが、1秒ちょっとでレスポンスが帰ってきているので、3回のコールが非同期で並列に実行されることがわかる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77403/6b4ff7cd-bc40-9f6e-a550-13dac35b047c.png)

## わかったこと
* クラス名/メソッド名で自動でマッピングし、対応するメソッドをコールしてくれる
* バッチリクエストも非同期で実行してくれる

## このライブラリの懸念点
* セッションやサーバ変数をとれるような作りになってなさそうなので、これらを使用する必要がある場合はこのライブラリが使えないかもしれない
* 入力値のバリデーションを自分でやらないといけない(REST APIの場合は[モデル検証]((https://learn.microsoft.com/ja-jp/aspnet/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api))でやれそう)→[FluentValidation](https://github.com/FluentValidation/FluentValidation)などを使用すれば可能
* 冪等性を担保する方法としてIdempotencyKeyを設定することがあるが、バッチで処理を行う場合にIdempotencyKeyを各メソッドにつける運用ではうまくいかなさそう(1つ目に実行されるメソッドと2つ目に実行されるメソッドで別の値にする？)
* バッチ全体に対してトランザクションをかけることができなさそう
* 外から拡張してやることを考慮されていないので機能追加が難しい→folkして改造すればいいが保守性が。。

## ほか
[vs-StreamJsonRpc](https://github.com/microsoft/vs-streamjsonrpc)を使うか
Dockerでシリアルコンソールサーバーを作る

Docker上でSSHによるアクセスが可能なシリアルコンソールサーバーを作成します。ネットワーク機器等を操作するためにシリアルコンソールサーバーがあると便利ですが、安価ではないため手作りしたいと思います。

# シリアルコンソールへのアクセス

今回はUSBシリアルコンソールを使います。ベースイメージはalpineです。ホストはUbuntu 22.04を使用しています。
```
docker run -d -p 2001:22 --device=/dev/ttyUSB0:/dev/ttyUSB alpine:3.18
```
とりあえずコンテナを立ち上げます。`--device`でホスト上の`/dev/ttyUSB0`をコンテナ上の`/dev/ttyUSB`にマウントさせます。ポートも開放しておきます。

```
microcom -s 9600 /dev/ttyUSB0
```
busyboxのmicrocomを使用してシリアルコンソールを操作します。`ctrl + x`で終了できます。

# SSHサーバーの設定
SSHサーバーをインストールします。
```
apk add openssh-server
```

コンソールサーバーとして使用するため、`/etc/ssh/sshd_config`を編集してSFTPやポートフォワード機能等は無効化しておきます。
```config:/etc/ssh/sshd_config
Port 22
PasswordAuthentication yes
PermitRootLogin no
AllowAgentForwarding no
AllowTcpForwarding no
GatewayPorts no
X11Forwarding no
#Subsystem	sftp	internal-sftp
```

SSHログイン時に`/etc/motd`の内容が表示されるため、コンソールサーバーらしい文面に書き換えます。
```:/etc/motd
#-----------------------
# Serial Console Server
#-----------------------
```

`ssh-keygen -A`で事前にホスト鍵を生成しおく必要があります。`sshd`は`-D`オプションによりデーモン化せずに起動可能です。`-e`はログを標準出力に出力をするオプションです。
```
/usr/bin/ssh-keygen -A
/usr/sbin/sshd -D -e
```

# ログインシェルの作成

コンソールサーバーとしてのみ使用可能とするため、SSHでログインするとシリアルコンソールターミナルが直接表示されるようにし、Linuxコマンドを実行できないようにします。アクセス用のユーザーを作成し、ログインシェルをmicrocomにすることで実現します。

```sh:/usr/local/bin/console.sh
#!/bin/sh

BUSY=`ps | grep microcom | wc -l`
if [ ! $BUSY -eq 1 ]; then
    echo "This console is occupied."
    exit 1
fi

/bin/busybox microcom -s 9600 /dev/ttyUSB
```
microcomを起動するためのスクリプトを作成します。シリアルコンソールは同時利用できないため、同時起動しようとすると終了する処理を入れています。（かなり適当です…）

```
chmod a+x /usr/local/bin/console.sh
echo "/usr/local/bin/console.sh" >> /etc/shells
```
実行権限を付与を忘れずに行います。`/etc/shells`にパスを記載することで、ログインシェルとして使用可能になります。

# ユーザーの作成
ログイン用のユーザーを作成します。
```
adduser -S user -s /usr/local/bin/console.sh -G dialout
echo user:user | chpasswd
```
`adduser`コマンドでユーザーを追加できます。`-S`でユーザー名を指定します。`-s`でログインシェルに先ほど作成したスクリプトを指定します。/dev/ttyUSBにアクセスするために`-G`で`dialout`グループに所属させます。
`echo <ユーザー名>:<パスワード> | chpasswd`でパスワードを設定します。

# 動作テスト
試しにホストからコンテナにSSHでアクセスしてみます。
```
$ ssh user@localhost -p 2001
user@localhost's password:
#-----------------------
# Serial Console Server
#-----------------------

(コンソールの内容)
```
上手くいけば、ログインするとそのままシリアルコンソールを使えるはずです。

# Dockerfile

さきほどの内容をDockerfileに書き起こしました。
https://github.com/caribouHY/docker-serial-console-server/
```dockerfile:Dockerfile
FROM alpine:3.18

ENV USER="user"
ENV PASSWORD="password"
ENV SPEED="9600"
ENV TTY_DEVICE_PATH="/dev/ttyUSB"

RUN apk add --no-cache openssh-server

COPY ./login_text.txt /etc/motd
COPY ./entrypoint.sh /entrypoint.sh
COPY ./console.sh /usr/local/bin/console.sh
COPY ./sshd_config /etc/ssh/sshd_config

RUN chmod u+x /entrypoint.sh && \
    echo /bin/busybox microcom -s $SPEED $TTY_DEVICE_PATH >> /usr/local/bin/console.sh && \
    chmod a+x /usr/local/bin/console.sh && \
    echo "/usr/local/bin/console.sh" >> /etc/shells

EXPOSE 22/tcp
ENTRYPOINT [ "/entrypoint.sh" ]
```

環境変数でユーザー名/パスワードやシリアルの速度を設定できるようにしてあります。
```
docker build -t console-server .
docker run -d -p 2001:22 --device=/dev/ttyUSB0:/dev/ttyUSB \
    -e USER:user -e PASSWORD:user console-server
```
とりあえず動作はしていますが、そのうちもう少し作り込みたいなと考えています。
【Winの開発者へ...】Win11インサイダープレビュー版で極端に動作が重たくなる場合の緊急対処法

先日Windows11の新機能をいろいろ試してみたくインサイダープレビュー(Devチャンネル)に切り替えたのですが、例のごとく不具合が生じたため備忘録として対処法を書いておきます。

## SSD搭載PCにおいて極端に動作が遅くなる

https://gigazine.net/news/20230417-windows-11-kb5025239-slowing-system/

この不具合は前々から指摘されていたらしいんですが、まさか自分が遭遇するとは...

どうやらいつものアップデートによる不具合っぽいです; ; ;

## 対処法

自分としては3つくらい試しました

## 1. Explorer再起動
``Curl`` + ``Shit`` + ``Esc``でタスクマネージャーを立ち上げる

下にスクロール、もしくは検索欄でexplorer.exeと検索(すごいもっさりですが頑張って💦)

右クリックでタスクの再起動を実行


## 2. cmdから強制再起動
``Curl`` + ``Shit`` + ``Esc``でタスクマネージャーを立ち上げる

タスクの実行でcmd.exeを実行(Powershellでも行けますが多分動かないです)

以下のコマンドで再起動(電源ボタンでもいいんですがこっちのほうが安全なので)

```powershell
shutdown /s /t 0
```

## 3. アップデートしたバージョンのアンインストール

これは詳しい方法は割愛しますが、設定のWindows Updateから以前のバージョンの削除を行うと改善するかもです。


いずれにせよインサイダープレビューだと数時間ごにょごにょしないと厳しいです（　＾ω＾）・・・
GASでBacklogを操作したい！【Vol.2 ユーザ一覧取得編】

※まだまだ投稿が不慣れなので、温かい気持ちで読んでいただけると幸いです。

# 背景
Backlogが全社的に利用されるようになり登録ユーザが増えてきました。
そうなってくると出てくる問題が、一時的に利用したユーザや退職に伴うユーザの削除ですね（決めつけww）

便利に管理できて、一覧で見やすく管理できないかな〜
ないなら、どうする？ そう！ **作っちゃおう！**

:::note info
**目次**
* 全ユーザの取得
* 取得したユーザの細かい設定値の書き出し
:::

# 前提
アクセスに必要なAPIキーの取得の仕方は[こちら](https://support-ja.backlog.com/hc/ja/articles/360035641754-API%E3%81%AE%E8%A8%AD%E5%AE%9A)

# プロジェクトの取得
```javascript:getBacklogUsers()
  //エンドポイント
  var endPoint = '/users';
  //最終的なURL
  url = 'https://{ワークスペースのドメイン}/api/v2' + endPoint + '?apiKey=' + apiKey + '&all=true';
  //取得＆整形
  var resUsers = UrlFetchApp.fetch(url);
  var jsonUsers = JSON.parse(resUsers.getContentText());
```
※取得可能なユーザの情報は[こちら](https://developer.nulab.com/ja/docs/backlog/api/2/get-user/#url-%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%83%BC)

# 最後に
GASでめんどくさいを自動化してハッピーライフ

# 参考
[GASとは](https://developers.google.com/apps-script)
[BacklogのAPIキー作成手順](https://support-ja.backlog.com/hc/ja/articles/360035641754-API%E3%81%AE%E8%A8%AD%E5%AE%9A)
[ユーザー情報の取得](https://developer.nulab.com/ja/docs/backlog/api/2/get-user/#url-%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%83%BC)
メモ：dokuwiki の表を markdown に変換する

個人的なメモです。

## 要件の検討

* dokuwiki ではセルは結合できるけれど、それは変換できなくても仕方がないものとする
* dokuwikiでは行毎にセルの左右寄せを変えることができるけれど、markdownでは列単位でしかできないので、２行目の中寄せ・右寄せが後続の行でも使われるものとする

## 入出力の形式

### 入力

* 見出し行は `/^(\^[^^]*)+\^$/`
* 後続行は `/^(\|[^\|]*)+\|$/`
  * 繰り返しの回数は見出し行と同じでなければならない（はずなのだが簡単のためテストはしない）
* 最初の後続行（表の第２行）について各セル（`|`で分割した各要素）が：
  * `/^␣␣.*␣␣$/` ならば当該列は中寄せに
  * そうではなく、`/^␣␣/` ならば当該列は右寄せに
  * そうではなければ当該列は左寄せに

（ここでスペースはわかりにくいので ␣ `&#x2423;` で代えました）

### 出力

* 見出し行は `|` を `\|` に置換してから `^` を `|` に置換して出力（以下、見出し変換と呼ぶ）
* 後続行はそのまま出力
  * ただし、最初の後続行を出力する前に、左右中寄せ指定を出力

## 分析
### 状態遷移図

種類の違う行を受け取ったときにプログラムの挙動が違うので、抜けがないように考えてみます。

```mermaid
stateDiagram-v2
  [*] --> 初期状態
  初期状態 --> 見出し認識状態: 見出し行
  初期状態 --> 初期状態: 見出し行 以外
  見出し認識状態 --> 後続行認識状態: 後続行（左右中寄せ指定を出力）
  見出し認識状態 --> 初期状態: 後続行 以外
  後続行認識状態 --> 後続行認識状態: 後続行
  後続行認識状態 --> 初期状態: 後続行 以外
```

こういうのを有限状態オートマトンといいます。

### 状態遷移表

慣れれば状態遷移図を見ながらコーディングできますが、ねんのため状態×入力の表にしてみましょう。

|   |見出し行|後続行|その他の行|
|:--|:--|:--|:--|
|初期状態|見出し変換出力; 見出し認識状態へ|そのまま出力|そのまま出力|
|見出し認識状態|そのまま出力; 初期状態へ|左右中寄せ指定出力; そのまま出力; 後続行認識状態へ|そのまま出力; 初期状態へ|
|後続行認識状態|そのまま出力; 初期状態へ|そのまま出力|そのまま出力; 初期状態へ|

## あとはガリガリコーディング

たとえば JavaScript ならなんかこんな感じで動く。

```javascript
 function convert(){
 let val = document.getElementById("text-area").value;
 let lines = val.split(/\r\n|\n/);
 let text = [];
 let state = 0;
 for (var line of lines) {
  if (state === 0) {
    if (/^(\^[^^]*)+\^$/.test(line)) {
      line = line.replace(/\|/g, "\\|");
      line = line.replace(/\^/g, "|");
      state = 1;
    }
  } else if (state === 1) {
    if (/^(\|[^\|]*)+\|$/.test(line)) {
      let cols = line.split(/\|/);
      cols.shift();
      cols.pop();
      let colspec = cols.map(function (col){
        if (/^  \.*  $/.test(col)) {
          return ':---:';
        } else if (/^  /.test(col)) {
          return '---:';
        } else {
          return ':---';
        }
      });
      colspec.unshift('');
      colspec.push('');
      text.push(colspec.join('|'));
      state = 1;
    } else {
      state = 0;
    }
  } else if (state === 2) {
    if (!(/^(\|[^\|]*)+\|$/.test(line))) {
      state = 0;
    }
  }
  line = line.replace(/^======\s*(.*)\s*======$/, "# $1");
  line = line.replace(/^=====\s*(.*)\s*=====$/, "## $1");
  line = line.replace(/^====\s*(.*)\s*====$/, "### $1");
  line = line.replace(/^===\s*(.*)\s*===$/, "#### $1");
  line = line.replace(/^==\s*(.*)\s*==$/, "##### $1");
  // 一行に複数リンクがあるときのバグは直したよ
  line = line.replace(/\[\[([^[\|]*)\|([^[]*)\]\]/g, "[$2]($1)");
  text.push(line);
 }
 let txt = document.getElementById("output");
 txt.innerHTML = text.join("\r\n");
}
```
Vueの勉強④

今回は、v-forについて
リストレンダリングに使われるディレクティブ。
複数の要素をリスト形式でHTML上に描画する際に使うと便利。

要するに配列を使い表示させるときに使うものってことでいいのかな？

```
v-for="(app, i) in apps" v-bind:key="i">{{ app }}
```

リストを追加する処理の一部を抜粋

v-forを使うときはkey属性を忘れずにつけないといけないみたいです。

確かに配列を使うときにキーがないと、、
Pythonのlistとtupleの違い

# listとtupleの違いまとめ
- listは可変なデータ型で、値の操作が自由にできる。
- tupleは不変なデータ型で、値の操作ができない。
- tupleはlistよりもメモリ使用量や処理速度が優れている。
- listとtupleは、それぞれ適切な場面で使い分けることが重要である。

# listのコード例
```python
# listの作成
my_list = [1, 2, 3, "apple", "banana"]

# listの要素にアクセス
print(my_list[0]) # 1
print(my_list[-1]) # banana

# listの要素を変更
my_list[3] = "orange"
print(my_list) # [1, 2, 3, 'orange', 'banana']

# listに要素を追加
my_list.append(4)
print(my_list) # [1, 2, 3, 'orange', 'banana', 4]

# listから要素を削除
my_list.pop()
print(my_list) # [1, 2, 3, 'orange', 'banana']
```

# tupleのコード例
```python
# tupleの作成
my_tuple = (1, 2, 3, "apple", "banana")

# tupleの要素にアクセス
print(my_tuple[0]) # 1
print(my_tuple[-1]) # banana

# tupleの要素を変更（エラー）
my_tuple[3] = "orange" # TypeError: 'tuple' object does not support item assignment

# tupleに要素を追加（エラー）
my_tuple.append(4) # AttributeError: 'tuple' object has no attribute 'append'

# tupleから要素を削除（エラー）
my_tuple.pop() # AttributeError: 'tuple' object has no attribute 'pop'
```

##
簡単なスクリプト、登録・削除が必要な機能はlist、
変更予定はないが、ある程度まとまった数の値を管理する場合はtupleみたいなイメージで使い分けるとよいかも
Java Switchのアロー構文について

## アロー構文 
JavaのSwitch文で使えるアロー構文というものを初めて知ったのでメモに残しておく。
### 結論
アロー構文「->」を使うことでswitch文の「：」と[break;]を省略することができる。
{}でブロックを作れば複数行の処理も書ける。
String　str = "2";
switch(str){
case "1" -> System.out.println("1です");
case "2" -> System.out.println("2です");
case "3" -> {System.out.println("3です①");
　　　　　  System.out.println("3です②");
　　　　   　System.out.println("3です③");
　　　　　 }
}



### 普通の書き方

String　str = "2";
switch(str){
case "1": System.out.println("1です");
　　　　break;
case "2": System.out.println("2です");
　　　　break;
case "3": System.out.println("3です");
　　　　break;
}

### 何がいいのか
breakの書き忘れを防止したい場合に有効なのだとか。
あとは見た目もすっきりする。
半角英数のみのエンコードとデコードを basic32 パッケージで実現する

こんにちは、皆さん！今回は Go 言語で半角英数のみの文字列をエンコードし、後にデコードする方法を紹介します。そのために、`basic32` パッケージを使用します。

### basic32 パッケージとは？

`basic32` パッケージは、バイト列を base32 エンコーディングでエンコードおよびデコードするためのパッケージです。base32 エンコーディングは、半角英数のみの文字セットを使用してデータをエンコードする手法であり、主に文字列の安全な転送や保存に使用されます。

### インストール

まず最初に、`basic32` パッケージをインストールします。

```bash
go get github.com/savaki/basic32
```

### エンコードとデコードの例

以下は、半角英数のみの文字列をエンコードし、後にデコードする Go のコード例です。

```go
package main

import (
	"fmt"
	"github.com/savaki/basic32"
)

func main() {
	// エンコードする文字列
	input := "Hello123"

	// エンコード
	encoded := basic32.EncodeToString([]byte(input))
	fmt.Printf("Encoded: %s\n", encoded)

	// デコード
	decodedBytes, err := basic32.DecodeString(encoded)
	if err != nil {
		fmt.Printf("Error decoding: %v\n", err)
		return
	}
	decoded := string(decodedBytes)
	fmt.Printf("Decoded: %s\n", decoded)
}
```

このコードでは、まず `basic32` パッケージをインポートし、指定された文字列をバイト列に変換してからエンコードとデコードを行っています。実行すると、元の文字列がエンコードされ、再びデコードされて元に戻ることが確認できます。

### まとめ

今回は、半角英数のみの文字列を `basic32` パッケージを使用してエンコードし、デコードする方法を紹介しました。この手法は、データの安全な転送や保存などのシナリオで役立つことがあります。ぜひ、お試しいただき、ご自身のプロジェクトに活用してみてください！

それでは、次回の記事でお会いしましょう！お楽しみに！
クラウドシステム

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/6b46610b-ef58-0252-1ce4-e6c13ac9a064.png)
　クラウドシステムとは、データセンタに設置されているサーバを利用することにより、インターネットを介して、いつでもどこからでもデータにアクセスできるようにしたシステムです。いつでもデータにアクセスできることをアベイラビリティが高いと言えます。また、必要な時に必要な分のデータ格納領域やサーバ機を使えます。このように、必要に応じて性能を変えられることをスケーラビリティが高いと言えます。
　クラウドシステムを利用したサービス形態として、SaaS、PaaS、IaaSがあります。

試験の出題例：クラウドとは、「コンピュータ資源をネットワークを介して、提供」し、「利用者がスケーラビリティやアベイラビリティの高いサービス」を受けられる。
JAVA基礎復習

本日はJAVAの基礎を復習しました。

使用ソフト：　eclipse
本日の気付き：==とequals()の違い

~~~~java
public class CSSample1 {

	public static void main(String[] args) {
		String CS1 =new String("ABC");
		String CS2 =new String("ABC");
		System.out.println(CS1.equals(CS2));
		System.out.println(CS1 == CS2);
	}

}
~~~~

結果

~~~
true
fales
~~~~~

同じような内容であるが結果は違う
なぜか？

本日の学び：　equals()は「同じ内容」
　　　　　　　==は「完全に同一の内容
Sphinxを導入してドキュメントを自動生成する

# Sphinxとは

`Python`のクラスや関数のドキュメントを自動生成するツールです。正しく、`docstring`を書いている場合自動的に整形して`html`を生成してくれます。これを導入する際にいくつかトラップがあるので、それを解説します。参考にした記事は以下の通りです。

- [Sphinxの使い方．docstringを読み込んで仕様書を生成 - Qiita](https://qiita.com/futakuchi0117/items/4d3997c1ca1323259844)
- [sphinx でドキュメント作成からWeb公開までをやってみた - Qiita](https://qiita.com/kinpira/items/505bccacb2fba89c0ff0)

# 導入

`Python`の仮想環境に入ります。

- `venv`の場合

```sh
$ source venv/bin/activate
```

- `conda`の場合

```sh
$ conda activate <env_name>
```

# Sphinxのインストール

```sh
$ pip install sphinx # Sphinx
$ pip install sphinx-book-theme # Sphinxで用いるテーマ
```

# テストプロジェクトの作成

```sh
~$ mkdir test
~/test$ cd test
~/test$ touch main.py
# ディレクトリ構造は以下の通り
.
└── main.py
```

# Sphinxの初期設定

インタラクティブシェルが起動するので、以下のように入力します。

```sh
~/test$ sphinx-quickstart docs
> Separate source and build directories (y/n) [n]: y
> Project name: hoge
> Author name(s): hoge
> Project release []: 1.0.0
> Project language [en]: 
```

すると、以下のようなディレクトリ構造ができます。重要なものだけ抜粋しています。

```sh
.
├── docs
│   ├── build
│   ├── source
│   │   ├── conf.py
│   │   └── index.rst
│   ├── make.bat
│   └── Makefile
└── main.py
```

# 設定ファイルの編集

`docs/source/conf.py`に以下の内容を追加します。

```python
import os
import sys  
sys.path.insert(0, os.path.abspath('../../'))
# 中略
extensions = [
    'sphinx.ext.autodoc', 
    'sphinx.ext.napoleon', 
]
# 中略
html_theme = 'sphinx_book_theme'
```

`extensions`が非常に重要で、これがないと何も表示されません。

- `sphinx.ext.autodoc`は、`docstring`を読み込んでドキュメントを生成するための拡張機能です。
- `sphinx.ext.napoleon`は、`Numpy`スタイルか`Google`スタイルの`docstring`を読み込むための拡張機能です。

`docs/source/index.rst`を以下のように編集します。
`glob`を追加することで、`*`が使えるようになります。
そして、`*`を指定することですべての`.rst`ファイルを選択することができます。

```rst
Welcome to hoge's documentation!
================================

.. toctree::
   :glob:
   :maxdepth: 2
   :caption: Contents:

   *

Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
```

```sh
~/test$ cd docs
~/test/docs$ sphinx-apidoc -f -o source ../
~/test/docs$ make html
```

最終的なディレクトリ構成は以下のようになります。重要なものだけ抜粋しています。

```sh
.
├── docs
│   ├── build
│   │   ├── html
│   │       ├── index.html # これがドキュメントのトップページ
│   ├── source
│   │   ├── conf.py
│   │   └── index.rst
│   ├── make.bat
│   └── Makefile
└── main.py
```

# ドキュメントの確認

`VSCode`における`html`の確認方法を説明します。自分で`Web`サーバーを建てられる人はそうしても構いません。

- ローカル環境の場合、特別な設定は必要なく、`html`をブラウザに貼り付ければ多分表示されます。自分はやったことがないのでうまくいかない場合は次に示す方法を参考にしてください。

- サーバー上などの場合、`VSCode`の`Live Server`という拡張機能を利用します。`index.html`が存在するフォルダを`VSCode`で開き、右下の`Go live`というボタンを押すとそのサーバーの何らかのポートで`html`が表示されます。

# 参考サイト

- [Sphinx Themes Gallery](https://sphinx-themes.org/)  
  - Sphinx のテーマがまとまっているサイトです。
経営者のための情報セキュリティQ&A45

https://www.amazon.co.jp/%E7%B5%8C%E5%96%B6%E8%80%85%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE-%E6%83%85%E5%A0%B1%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3Q-A45-%E5%8C%97%E6%A2%9D-%E5%AD%9D%E4%BD%B3/dp/4532323045

本書を手に取った背景
CISSPの勉強するにあたり、読んでおきたいと思い手に取った。
経営者がセキュリティを考えるとき、いろいろな観点から説明がなされているようだったので読みたいと思いました。

本書のテーマ
セキュリティに関する組織づくり、データのセキュリティ、内部不正、責任、法令や法制度についてQA形式で書かれている。
「こんなときどうしたらいい？」という具体例にもなっているのでとっつきやすい。

個人的なポイント
１，BCMというのもある
BCPはよく聞いてたが、2012年にISO22301としてBCMが国際規格化されてる。事業継続管理という。

２，CSIRTだけじゃない
PSIRT、FSIRTというのもある。P＝組織が提供する製品やサービスに特化したセキュリティチーム。F=工場内のセキュリティ。CSIRT＝組織全体で考える、サービスのインフラなどを対象としてる。

３，最低限の対策で必要なものは？
「避難訓練」。全社で取り組むものや他社セミナーに参加するのもいい。

４，GDPRに違反したとき
過去の事例では、６１億、２５０億の罰金になった例がある。

５，サイバー攻撃にあった場合の対応
被害の最小化、詳細調査、初動対応、報告、相談、届け出、公表、責任追及、再発防止などやることがいっぱいあって、やっぱりセキュリティ対策は大事。

６，サイバー保険
https://www.cybereason.co.jp/blog/ransomware/8355/
少し聞くようになってきた。
サイバー攻撃により企業に生じた第三者に対する「損害賠償責任」「費用」「喪失利益」を保証するもの

７，セキュリティ対策推進のロードマップ
コントロールが実装、整備されてる→コントロールが自動化されてる→効果測定されサイクルが回ってる
これが流れ。

８，摘発事例
最近では不正アクセス禁止法違反が断然多い。他人のアカウントで不正にアクセスすること。

今後やれること
・お客様と話すときのねたになりそう
・コンサル的なことによってくる
・犯罪という視点をもつ

まとめ
警察の方が書いている内容もあり面白かった。
警視庁の方が登壇しているセミナーもあるので、見方が変わりそう。
セキュリティは技術ではなく、犯罪に関係しているという視点をもっともったほうがいいかもしれない。
ブラウザバック直前の遷移元のurlを取得したい

# はじめに

`ページA → ページB → ページC → ブラウザバックしてページB`
のような画面遷移を行ったと想定します。

![ページ遷移.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536974/ae022f00-f051-adbb-5fa1-89981d54b427.png)


この時に、ページBでブラウザバック直前のページであるCのurlを取得したいです。

# document.referrerでは取得出来ない？

遷移元のurlを取得するには`document.referrer`を使用すれば取得可能です。

https://developer.mozilla.org/ja/docs/Web/API/Document/referrer

しかし、**ブラウザバック直後では想定しているurlは取得出来ません。**

`ページA → ページB → ページC → ブラウザバックしてページB`において。
ページBで`document.referrer`からリファラを取得すると、**ページAのurl**が取得されてしまいます。

# 【解決】 sessionStorageに保存する

ページCで現在のurlをsessionStorageへセットし、ページBでそれを取得します

```page-C.js
sessionStorage.setItem('url', window.location.href);
```

```page-B.js
let url = sessionStorage.getItem('url');
```

以上です
Sysdig SecureのTeam Zones機能（Tech Preview版）

Sysdig SecureのTeam Zones機能がTech Preview版としてリリースされました。これにより、Teamのメンバーは、TeamにアサインされたZoneのComplianceスキャン結果のみが見えるようになります。Team Zones機能をテストしたので、その手順をご紹介します。

1. アカウントメニュー（左下の自分の名前）から __Settings__ 画面に移動します。
1. __Sysdig Labs__ で`Team Zones`が有効になっていることを確認します。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/f4b62da2-2544-d938-a1b4-1da9613d34bd.png)

3. __Policies > Posture > Zones__ に移動して任意の新しいzoneを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/2581ebc8-21b9-124c-c922-89e5f5c7394e.png)

4. アカウントメニュー（左下の自分の名前）から __Teams__ 画面に移動します。
5. 任意の新しいteamを作成し、__Zones__ として先ほど作成したzone (例：test zone)を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/655bd3c1-2c68-76fa-e666-c80220842aa3.png)

6. __Posture > Compliance__ に移動します。
7. アカウントメニュー（左下の自分の名前）からチームを切り替えて、表示されるComplianceスキャン結果の対象が異なっていることを確認します。
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/92c32266-77ba-3f76-a726-f1310f785b92.png width=50%>

* `Secure Operations` Teamの場合は、Team内でのZones設定が`All Zones`となっているため、すべてのZoneのComplianceスキャン結果が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/0947b907-16f0-387b-74f4-fb214d999b23.png)

* `test team`の場合は、Team内でのZones設定が`test zone`となっているため、test zoneのComplianceスキャン結果のみが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/43752aa0-5b40-d1ba-3d87-e49c2f37dde2.png)

# まとめ
Sysdig SecureのTeam Zones機能（Tech Preview版）によって、Complianceスキャン結果とそれを確認できるTeamを簡単に紐づけることができるようになりました。
Go言語でAPIを叩く時、パスパラメータが渡せない不具合について


## はじめに
Go言語を使用してAPIを呼び出す際、パスパラメータを渡す際に初期化が必要な不具合に遭遇したことはありませんか？この記事では、そのような問題についての理解を深め、適切な方法でパスパラメータを渡す方法について解説します。

## パスパラメータとは
APIはしばしばURL内の特定の部分にデータを埋め込むためにパスパラメータを使用します。例えば、`/users/{id}`というエンドポイントでは、`{id}`の部分がパスパラメータを表します。これにより、異なるユーザーの情報を取得する際に、異なる値を指定することができます。

## 不具合の原因
Go言語でAPIリクエストを処理する際に、パスパラメータを渡す際に初期化を行わないといけないいう問題が発生することがあります。例えば、以下のようなコードを考えてみましょう。

```go
package main

import (
	"fmt"
	"net/http"
)

type PathParam struct {
	ID int
}

func main() {
	http.HandleFunc("/users/", func(w http.ResponseWriter, r *http.Request) {
		// パスパラメータの取得
		param := new(PathParam)
		// ここで初期化を行わないとparam.IDに値を代入できない
		// これが問題の根本的な原因です
		// 以下、省略
	})
	http.ListenAndServe(":8080", nil)
}
```

このコードの問題点は、`param`変数を初期化しないと、`param.ID`に値を代入できないことです。これにより、パスパラメータの値が正しく取得できず、APIリクエストが正しく処理されない可能性があります。

## 正しいパスパラメータの扱い方
正しい方法は、パスパラメータを取得する前に`param`変数を初期化することです。以下に、正しいコード例を示します。

```go
package main

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"
)

type PathParam struct {
	ID int
}

func main() {
	http.HandleFunc("/users/", func(w http.ResponseWriter, r *http.Request) {
		// パスパラメータの取得
		urlParts := strings.Split(r.URL.Path, "/")
		id, err := strconv.Atoi(urlParts[len(urlParts)-1])
		if err != nil {
			http.Error(w, "Invalid ID", http.StatusBadRequest)
			return
		}

		param := &PathParam{
			ID: id,
		}

		// paramを使ったAPI処理
		// 以下、省略
	})
	http.ListenAndServe(":8080", nil)
}
```

このコードでは、リクエストのURLをスラッシュで分割し、最後の部分を数値に変換して`param.ID`に代入しています。これにより、パスパラメータを正しく取得できるようになります。

## まとめ
Go言語でAPIを呼び出す際に、パスパラメータを渡す際には適切な初期化を行うことが重要です。不具合を避けるために、パスパラメータの値を紐付ける前に`param`変数を適切に初期化する方法を確実に理解しましょう。これにより、正しく動作するAPIリクエスト処理を実装することができます。
Click (Python) でオプション名と仮引数名を別にする

PythonのCLIツールを作るためのライブラリ Click で割と忘れがちなノウハウ (忘れるたびに調べてる) を紹介します.

## オプション名と仮引数名を別のものにしたい

複数の値をとれるオプションを定義する場合, 次のように書きます (他にもあったと思いますが).

```python
@click.command()
@click.option("--keyword", "-k", type=str, multiple=True)
def main(keyword: tuple[str]):
    click.echo(keyword)
```

実行例.

```
$ sample -k sapporo -k hokkaido
('sapporo', 'hokkaido')
```

これでいいといえばそうなのですが, 仮引数名「keyword」は「keywords」にしたくなるのが人情ではないでしょうか. しかし, 単純にはいきません. 仮引数名だけを任意の名前にすると, 次のエラーが出てしまいます.

```
TypeError: main() got an unexpected keyword argument 'keyword'
```

オプション名から仮引数名を類推してマッピングしにいくようになっているためです.

この場合, オプション名のあとに, 次のように引数を加えることで解決できます.

```python
@click.command()
@click.option("--keyword", "-k", "keywords", type=str, multiple=True)
def main(keywords: tuple[str]):
    click.echo(keywords)
```

## 参考

このへんに書かれてます. オプション名がPythonの予約語 (fromとか) のときには, この指定が必須になりそうです.

https://click.palletsprojects.com/en/8.1.x/options/#basic-value-options
Go言語向けNCMB SDKの使い方（会員管理の使い方）

NCMBはモバイル向けのBaaS（mobile Backend as a Service）ですが、サーバー側のデータとNCMB上のデータを連係させたいというニーズは良くあります。

そんなときには各言語向けのSDKがあると便利です。サーバー向けにはRuby、Python、PHP、Java、C#のSDKがあります（すべて公式サポート対象外の、コミュニティSDKという位置づけです）。

今回はGo言語向けのSDK開発をはじめたので、その使い方を紹介します。今回はログインやユーザー登録といった会員管理周りの使い方です。

## ソースコード

ソースコードはGitHubにて公開しています。ライセンスはMIT Licenseになります。

[NCMBMania/ncmb\_go](https://github.com/NCMBMania/ncmb_go)

## インストール

SDKのインストールは下記コマンドで行います。

```bash
go get -u github.com/NCMBMania/ncmb_go
```

## インポート

続けてSDKをインポートします。

```go
import (
    "github.com/NCMBMania/ncmb_go"
)
```

## 初期化

NCMBより取得したアプリケーションキー、クライアントキーを使って初期化します。

```go
ncmb := NCMB.Initialize("YOUR_APPLICATION_KEY", "YOUR_CLIENT_KEY")
```

## ユーザー登録

ユーザー登録はユーザー名とパスワードを使います。

```go
user, err := ncmb.SignUpByAccount(userName, password)
```

メールアドレスの場合は、まず会員登録メールを該当メールアドレス宛に送信する必要があります。

```go
bol, err := ncmb.RequestSignUpEmail(mailAddress)
```

## パスワードリマインダー

パスワードをリセットする場合です。メールアドレス認証でしか使えないので注意してください。

```go
bol, err := ncmb.RequestPasswordReset(mailAddress)
```

## ログイン

ログインはユーザー名とパスワード、またはメールアドレスとパスワードに対応しています。

```go
// ユーザー名とパスワードによるログイン
user, err := ncmb.Login(userName, password)

// メールアドレスとパスワードによるログイン
user, err := ncmb.LoginWithMailAddress(mailAddress, password)
```

返却値はユーザーオブジェクトです。ユーザーオブジェクトは、データストアのアイテムオブジェクトと似た形になっています。

```go
type User struct {
	ncmb *NCMB
	Item
}
```

そのため、 `Set` や `Get〜` 、 `Save` 、 `Delete` などが使えます。詳細は下の各記事を参照してください。

[Go言語向けNCMB SDKの使い方（データストアの保存） \- Qiita](https://qiita.com/goofmint/items/ceabf6fbf6c429a39261)

[Go言語向けNCMB SDKの使い方（データストアの取り出し方） \- Qiita](https://qiita.com/goofmint/items/81974227a67719b2fb3a)

[Go言語向けNCMB SDKの使い方（データストアの更新と削除） \- Qiita](https://qiita.com/goofmint/items/45f88c92c4b94c27ec85)

## 会員の検索

検索する場合には、 `users` を対象としてください。後は[データストアの検索](https://qiita.com/goofmint/items/bc580474552564084ae3)と変わらず利用できます。

```go
query := ncmb.Query("users")
```

## ログアウト

ログアウトは `Logout` メソッドになります。もしセッションの有効期限が切れていた場合、API呼び出しが失敗します。そのため、エラー判定は無視した方が良いでしょう。

```go
bol, err := ncmb.Logout()
```

## まとめ

まだ基本的な機能しかありませんが、徐々にバージョンアップしていきます。

Go言語を使ってWebアプリケーションを開発している方は、そのデータ保存先としてNCMBを利用してみてください。

[mBaaSでサーバー開発不要！ \| ニフクラ mobile backend](https://mbaas.nifcloud.com/)
スプレッドシートでセル内に改行を含むデータを行毎のデータに変換したい

この記事は移行しました！[最新の内容はこちら](https://naoqoo2.github.io/blog/%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E3%82%B7%E3%83%BC%E3%83%88%E3%81%A7%E3%82%BB%E3%83%AB%E5%86%85%E3%81%AB%E6%94%B9%E8%A1%8C%E3%82%92%E5%90%AB%E3%82%80%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E8%A1%8C%E6%AF%8E%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%97%E3%81%9F%E3%81%84/)をご覧ください😀


## やりたいこと

シートA のA,B列に下記3行があります。

| 商品 | サイズと値段 |
|:-:|:-:|
ジュース | S:100円<br>M:150円<br>L:200円
ポテト | M:150円<br>L:200円
バーガー | 通常:200円<br>パティ倍:300円

これを シートB のA列に下記のように7行になるように出力したい。

| 商品とサイズと値段 |
|:-:|
ジュース_S:100円
ジュース_M:150円
ジュース_L:200円
ポテト_M:150円
ポテト_L:200円
バーガー_通常:200円
バーガー_パティ倍:300円


## 関数では難しそうだった

関数一発で実現したかったのですが、[ChatGPTさん的にも難しそうだった](https://twitter.com/naoqoo2/status/1689086403500728321?s=20)ので諦めました。

## GASで実現

[GPTさんがGASを提案してきた](https://twitter.com/naoqoo2/status/1689089962879369217?s=20)ので書いてもらいました。


```js
function copySheetAToB() {
  var sheetA = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('シートA');
  var sheetB = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('シートB');

  var dataRange = sheetA.getDataRange();
  var data = dataRange.getValues();

  var outputData = [];
  for (var i = 0; i < data.length; i++) {
    var item = data[i][0];
    var prices = data[i][1].split("\n");
    for (var j = 0; j < prices.length; j++) {
      var parts = prices[j].split(':');
      var size = parts[0];
      var price = parts[1];
      var outputRow = item + '_' + size + ':' + price;
      outputData.push([outputRow]);
    }
  }

  sheetB.getRange(1, 1, outputData.length, 1).setValues(outputData);
}
```

## おわりに

区切り文字が改行ではなく、カンマとかでも対応できますね！
`.split(',')`　とかにすればOK！

## ところで

GPTさんのこと「じぷとさん」と呼んでるのですが、みなさんどうですか？
OpenAI APIの利用方法の調べ方をまとめた

# 概要

業務でOpenAI APIを利用しました。
公式ドキュメントは用意されてますが、必要な情報が分散していて調べるのが手間だったので、自分用メモも兼ねてまとめます。
あくまでも必要最低限なので、この文書だけで全てわかるわけではないです。

# 基本的な情報
https://platform.openai.com/docs/api-reference

APIリファレンスがまとめられている。
例えば、標準的なチャットでのやり取りについて調べたければChatの項目を確認する。
リクエスト、レスポンスの構造などが確認できる。

# 料金
https://openai.com/pricing
通信にかかる費用は、どの「モデル」を利用し、送信したリクエストの「トークン」がいくつか次第で変動する。

# モデル
https://platform.openai.com/docs/models
自然言語やコードの処理などの機能をまとめたセットである。
高性能、新しいモデルであるほど高価になる。

# トークン
https://platform.openai.com/docs/introduction/tokens
OpenAIとのチャットでは、文字列をトークンという文字列をそれ以上分けることのできない最小単位に分けたものに格納してやり取りを行う。
1トークンに何文字入るかは下記サイトで動作確認できる。
（ただしモデルはGPT-3となっている）

https://platform.openai.com/tokenizer

英語の場合は1単語で1トークンになるケースが多かった。
日本語の場合はかな漢字問わず1文字で1トークンとなった。

ちなみに、モデルごとにトークンの最大値が設けられている。
各モデルの最大値は下記リンクにて記載あり。

https://platform.openai.com/docs/models/models

# 最後に
自分が開発してる最中に新モデルのGPT-4も出ましたし、続々新情報が追加されていくと思いますので、あくまでも2023/08/09現在の情報ということでご承知おきください。
君たちはどうCSRF対策をするか

## はじめに
おはこんばんにちは。キティちゃんです。徐々に暑さが増していき、外へ出ると汗でべとべとになってしまう時期が来ましたね。そんな時期ですが、私は好きです。ですが、暑さで食欲が落ちるのは悩みですね。そんなことはさておき、今回はCSRFのことについて書いてみようと思います。

## CSRFって？
CSRFとはクロス・サイト・リクエスト・フォージェリ(以降、CSRF(シーサーフ))の略で、あるサイト(例：ECサイトなど)にログインしているユーザAに対して、攻撃者Bが用意したページに何らかの方法で誘導し、ユーザAに強制的にサイト内でリクエストを送信させ処理を実行させる攻撃となります。もっと簡単に言ってしまえば、ユーザAに意図していない操作をさせることですね。

## CSRFの何が問題なのか
例えばですが昔、掲示板にユーザが意図していない犯行予告の投稿がされてしまうといった事件がありました。このサイトはCSRFの対策を施していなかったことがきっかけで意図しない投稿が成功してしまうというものでした。
このように、CSRFの対策が取れていない場合、意図しない掲示板への投稿であったり、ECサイトなどであれば、ユーザの個人情報（パスワードやメールアドレスなど）が書き換えられてしまい、アカウントを乗っ取られる可能性が高まります。

## どのように対策をすれば良いのか
大きく分けて2つのパターンがあります。

1つ目、CSRFトークン(以降、トークン)を用いる方法です。掲示板であれば、投稿前の確認画面、ECサイトなどであれば購入確認画面にてサーバ側でトークンを発行し、ユーザーは投稿または購入のボタンを押した際に、発行されたトークンを一つのパラメータとして入力したパラメータと一緒にリクエストを送信します。このトークンは画面上では分かりませんし、攻撃者もどんな値が発行されたかを知る方法がありません。なので、有効な対策方法の1つとして挙げられます。
ただし、トークンの値が攻撃者が推測しやすい値（極端な例ですが、今日の日付など）が発行される場合はあまり意味をなさないこともあります。なので、トークンを利用する場合は攻撃者が推測しにくい値を発行する必要があります。PHPであればopenssl_random_pseudo_bytes関数やrandom_bytes関数を使うのが無難だと思います。

2つ目、ヘッダにトークンの役割を果たすものを設定することです。X-CSRF-TOKENヘッダにトークンの値を付けるパターンとX-Requested-Withヘッダを付与するパターン(最近知ったので、まだ色々調べ中、、)があります。
・・・
他にも、Refererヘッダをチェックしたり、パスワード変更機能であれば、旧パスワード(=現在使用しているパスワード)を入力させることで、トークンのような役割を果たさせる方法もあります。ただ、Refererヘッダで対策しているところはあまり見ないですね。

## 実装時の注意点
2パターンの対策方法を記載しましたが、いずれもサーバ側にて値を検証する必要があります。サーバ側にて検証していない場合、トークンがあってないようなものとなってしまうので、攻撃者の餌食になります。ですので、トークンを発行する処理を実装するだけではなく、サーバ側で発行されたトークンなのかを検証する処理も併せて実装しましょう。
・・・
口で説明するのは簡単ですが、じゃあトークンが役割を果たしているかどうかというのはどうやって検証すればいいの？と思うかもしれません。診断企業では専用のツールを使用できるので比較的楽に検証ができるのですが、開発チームだと診断企業が利用しているようなツールは会社的にダウンロード対象ではないと思うので、検証は容易ではないと思われます。なので、申し訳ないのですが設計の段階からセキュア開発を心がけ、コードレビューをしっかりしましょうとしか言えません。予算があれば、脆弱性診断を依頼するのもありです(宣伝じゃありません)。

## 診断ではどういう観点でトークンをみるのか（小話もあるよ）
よくあるのが、トークンの値を削除、トークンの値を一部改ざん、過去に発行されたトークンが使用できないようになっているか、他のユーザで発行されたトークンが使用できないかですかね。重要視しているのは、サーバで発行された値がちゃんと検証されているのか、また、発行されたトークンは発行したユーザのセッションと紐づいているかという点を見ていたりします。
・・・
私もWeb診断をしている企業を何社か経験したのですが、トークンの評価の仕方は、全社異なっていました。一番厳しく見ていたところは、確定処理の二つ前の画面からワンタイムのトークンを発行していて、なおかつサーバ側でトークンの値をチェックしていることがCSRFの問題がないと評価していました。ECサイトで言えば、商品選択画面→カート画面→購入確認画面→商品購入確定画面という処理がある場合、カート画面に遷移した時点でサーバ側でトークンを発行し、商品購入確定画面までに2回のトークンチェックの処理が必要ということになります。1回しかトークンのチェックをしていない場合は危険度のレベルを変えて指摘していたと記憶しています(何年も前の話なので許してください)。
・・・
なので、診断を依頼した会社によって指摘の度合いも変わるので、アプリケーションのセキュリティ対策も診断会社に依存しそうだなぁっていつも思います。

## まとめ
CSRF対策を怠ると意外と面倒なことになったりします。掲示板の事件も誤認逮捕に至っているのでね。。
まとめを書いててふと思ったのが、CSRF対策ってどういうサイトでするのって話を書くのを忘れていたなと。まとめに書くなよ感は否めませんが、基本的にログイン機能を持ち、更新処理があるようなサイトは対策が必須かなと思います。また、ログインしなくても投稿ができてしまうような掲示板も対策しとく方がいいと思います。
最後に私から言えることはコードレビューをしっかりしましょうですかね、今回はこれにて終わります。最後までありがとうございました。

## 参考
・『体系的に学ぶ 安全なWebアプリケーションの作り方 第2版』　著者：徳丸浩様
SOQLで選択リストの表示ラベルを取得する

# SOQLで選択リストの表示ラベルを取得する

作業中の別問題の調査で引っかかり、忘れないようにメモっておきます。

## 問題：選択リスト値が翻訳されない。
翻訳設定を利用して、ユーザー言語に合わせて日本語と英語で表示していたけど、
あるカスタムLWC作成で、Datatableに詰め込んだデータの選択リストが翻訳されなくなっている。

## 原因：PickListのAPI参照名を取得していた。
SOQLで普通に選択リスト項目を取得すると、API参照名が取得されること。

```SQL
[Select PickList__c From SomeCustomObject__c ];
```

上記だとAPI参照名が取得されるが、あいにく、設計が悪く、
ラベルとAPI参照名が同じになっていて、API参照名を取得したのを画面から気付かなかった。
ちなみに、API参照名だと翻訳が適用されないようだ。

## 対処：toLabel()で選択リスト項目のラベルを取得する。
そして、選択リスト項目にtoLabelメソッドを利用することで、選択リスト項目のラベルが取得でき、翻訳も正しく行えるようになる。
```SQL
[Select toLabel(PickList__c) From SomeCustomObject__c ];
```

ちなみに、ラベルとAPI参照名の両方を取得したい場合は、
下記のように別名つける方法で対応できる。
```SQL
[Select PickList__c, toLabel(PickList__c) picklistLabel From SomeCustomObject__c ];
```

※：SOQLで通常は項目に別名つけられません。集計関数など利用時のみ別名つけ可能


## SOQL および SOSL リファレンス
[toLabel()：SOQL](https://developer.salesforce.com/docs/atlas.ja-jp.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_tolabel.htm?q=toLabel)
[toLabel()：SOSL](https://developer.salesforce.com/docs/atlas.ja-jp.soql_sosl.meta/soql_sosl/sforce_api_calls_sosl_tolabel.htm)
日本で人気なAIツール一覧！簡単に使えるAIツールとは？

本ページでは、日本で大人気の最新AIツールを一覧で解説しています。AIツールについて詳しい人も詳しくない人にも読みやすい記事となっています。「AIツール一覧」を検索された方にピッタりの記事です。簡単に使えるAIツールもご紹介します。

[AIツール一覧（日本で人気)のまとめ](https://www.marke-media.net/whitepaper/ai-tool/)

## Pictory
Pictoryは、高品質なビデオを簡単に作成および編集できるAIビデオジェネレータです。このツールの最大の特徴の1つは、ビデオ編集やデザインの経験が必要ないことで、簡単に使えるAIツールです。

```
記事やスクリプトを基にしたビデオ作成テキストを使用したビデオ編集シェア可能なビデオハイライトリールの作成ビデオの自動キャプションと要約
Pictoryは、クラウドベースで動作するため、どのコンピュータでも利用できます。テキストを使用してビデオを編集したり、自動キャプションや要約を追加することで、プロフェッショナルな結果を簡単に得ることができます。
```

## Jasper
Jasperは、優れた機能と品質で最も優れたAIライティングアシスタントとして市場をリードしています。このツールは、与えられたキーワードを分析し、その内容と声のトーンに基づいてフレーズ、段落、または文章を生成します。たった15分で1,500語の記事を作成できる能力があります。

特徴：

11,000以上の無料フォントと2,500以上のライティングスタイルカテゴリのサポート25以上の言語のサポート直感的なインターフェース長文の執筆アシスタント（1,000語以上）テキスト内のキーポイント要素の識別（代名詞、動詞、名前など）
Jasperには50以上のAIコンテンツ生成テンプレートがあり、ブログ投稿、メール、マーケティングコピー、広告生成、プレスリリースなど幅広いニーズに対応しています。

## Murf
ビジネス向けの最高のAIテキストスピーチジェネレータであるMurfは、市場で最も人気のある印象的なAI音声ジェネレータの1つです。Murfは、テキストを音声、ボイスオーバー、口述に変換できるため、製品開発者、ポッドキャスター、教育者、ビジネスリーダーなど、さまざまなプロフェッショナルが利用しています。

特徴：

100以上のAI音声を15言語で提供表現豊かな感情スタイルオーディオとテキスト入力のサポートAI音声オーバースタジオ音程、速度、音量でカスタマイズ可能
Murfの音声合成は、声の変更、一時停止と強調の追加、発音の変更など、さまざまなカスタマイズオプションを提供します。声の変更も可能で、ピッチや速度、音量を調整できます。


## HitPaw Photo Enhancer
HitPaw Photo Enhancerは、最高のAI画像拡大ツールの1つです。このツールは、画像をぼやけさせずに拡大することができ、写真の品質を向上させます。

特徴：

WindowsとMacで利用可能な最高のAI画像拡大ツール画像の品質と解像度を自動的に向上させるためのワンクリック操作画像のぼやけを簡単に修正し、ノイズを取り除く高品質の拡大と解像度向上
HitPaw Photo Enhancerは、ぼやけた写真を完璧に修正し、AIノイズリダクションテクノロジーを使用して高ISOと低照明の画像からノイズを自動的に除去します。また、白黒画像をカラー化する技術も提供します。

## Synthesys
Synthesysは、AIテキストから音声への変換と商用利用向けのビデオ生成アルゴリズムを開発するリーディングカンパニーです。Synthesysは、スクリプトをダイナミックなメディアプレゼンテーションに変換するためにSynthesysテキストtoビデオ（TTV）技術を活用しています。

特徴：

69の実在する"Humatars"140以上の言語と254のユニークなスタイル説明ビデオ、eLearning、ソーシャルメディア、製品説明に最適なツールシンプルな使いやすいインターフェース
Synthesysを使用すると、アバターを選択し、140以上の言語でスクリプトを入力するだけで、高品質のビデオを生成できます。また、編集とレンダリングのための使いやすいインターフェースと高解像度の出力も提供します。

## Lovo.ai
Lovo.aiは、AIベースの音声ジェネレータとテキストtoスピーチプラットフォームで、最も強力で使いやすいプラットフォームの1つです。さまざまな業界にサービスを提供する広範な声を提供しており、音声合成モデルを継続的に改善しています。

特徴：

500以上のAI音声プロフェッショナルな音声グレードエモーショナルな話し方スタイル同時にビデオを編集できるビデオ編集機能音声の音程、強調、速度、ピッチのコントロール
Lovo.aiは、音声合成セクターで革新的な存在として、世界中の優れた組織から注目を浴びています。最新のGenny AI音声ジェネレータは、テキストtoスピーチとビデオ編集の機能を備えており、高品質で人間らしい声を生成します。

## AIツールのまとめ

日本では、簡単に使いやすいAIツールが注目を集めています。中でも、初心者に使いやすいAIツールが人気となっているので、開発される方は、初心者にとって使いやすいUIUXを目指しましょう。

参考サイト
250+ Best AI Tools - Complete AI Tools Directory (2023)

https://aitoolsdirectory.com/

https://www.synthesia.io/post/ai-tools


https://www.edureka.co/blog/top-12-artificial-intelligence-tools/


AIツール一覧まとめ（JAPAN）


https://bootcamp.uxdesign.cc/the-ultimate-list-top-100-ai-tools-in-2023-65c5ea1ccbd9

https://www.futurepedia.io/

https://topai.tools/

https://geekflare.com/most-powerful-ai-tools-list/


https://intellipaat.com/blog/top-artificial-intelligence-tools/?US

https://clickup.com/blog/ai-tools/
Azure Application Gateway用のプライベート証明書作成手順メモ

:::note warn
技術的に新しい内容が含まれている訳ではなく、初歩的な内容です
:::

# はじめに

Azure Application Gateway用のプライベート証明書を作成した手順をメモする

・証明書はSAN付きで発行
・PKCS12形式に変換する際にパスワードを付与


# 証明書作成手順

1. ルートCA作成（プライベートCA作成）
2. サーバ証明書作成


# 1. ルートCA作成（プライベートCA作成）

```console: 1.CA秘密鍵の作成
openssl ecparam -out test2023.key -name prime256v1 -genkey
```

```console: 2.自己証明(CSRの作成)
openssl req -new -sha256 -key test2023.key -out test2023.csr
```

```console: 3.ルートCA証明書の作成
openssl x509 -req -sha256 -days 365 -in test2023.csr -signkey test2023.key -out test2023.crt
```
上記は有効期限を365日、SHA256の設定例（要件に応じて変更する）


# 2. サーバ証明書作成


```console: 0. SANファイルの作成(viコマンドでsan.txtを作成)
vi san.txt
subjectAltName = DNS:agw.test-2023011.local, IP:10.1.1.1
```

```console: 1. サーバ秘密鍵の作成
openssl ecparam -out agw-svr.key -name prime256v1 -genkey
```

```console: 2.自己証明(CSRの作成)
openssl req -new -sha256 -key agw-svr.key -out agw-svr.csr
```

```console: 3.サーバ証明書の作成
openssl x509 -req -in agw-svr.csr -CA test2023.crt -CAkey test2023.key -CAcreateserial -out agw-svr.crt -days 365 -sha256 -extfile san.txt
```

```console: 4.証明書の検証
openssl x509 -in agw-svr.crt -text -noout
```

```console: 5. PKCS12への変換
openssl pkcs12 -export -in agw-svr.crt -inkey agw-svr.key -out agw-svr.pfx
パスワードを入力
```
Application Gatewayに上記PKCS12形式(pfx)の証明書をインポートする際にパスワードの入力が必須
（上記の「パスワードを入力」で空エンターをするとApplication Gatewayにインポートできない）


# 参考URL

Application Gateway の証明書
https://learn.microsoft.com/ja-jp/azure/application-gateway/renew-certificates#certificates-on-an-application-gateway
【24歳/未経験/完全独学】Webアプリケーションのポートフォリオ

# はじめに
はじめまして、Qiita記事初投稿です。

表題の通り、未経験からWeb系エンジニアへ転職するためにポートフォリオを制作しました！
初心者レベルですが簡単にご紹介します。

もし参考にして頂ければとても嬉しいです！

参考:
[本ポートフォリオでの環境構築についてまとめました](https://qiita.com/Takthustra/items/136e37f1da48d11f4445)
[ポートフォリオ第二弾](https://qiita.com/Takthustra/items/c651636b874e2602841b)

# 経歴
自己紹介
* 24歳
* 専門学校卒業(事務・経理科)
* カスタマーサービス(2年)→IT系職業訓練校(半年)→一般事務(半年)→現在

IT系職業訓練校に通っていましたがVBAに力を注いでいて、
授業を受けただけなのでほとんど0からのスタートです。

# ポートフォリオ
サービス名：「茶の湯随想」

* [サイトURL](http://tea-assay.ddo.jp/)
* [Githubリポジトリ](https://github.com/Takthustra/TeaAssay)

「茶の湯随想」は茶道について掲載しているWebサイトです。
私が茶道をしているので茶道の情報をまとめるために作成しました。

# 製作期間
2023/6-2023/7の2カ月間です。

4月に退職、5月に基本情報を取得して、
6月からプログラミング言語の勉強を本格的にはじめました。

上記期間は平均で6-8時間程度取り組みました。

# 技術面
### 使用技術
**フロントエンド**
HTML,CSS

**バックエンド**
JavaEE(JSP/サーブレット)

**開発環境**
Eclipse IDE(4.28.0)

**インフラ関連**
Google Cloud Platform(VPC:CentOS7)
Tomcat(10.1.10)
Mariadb(10.11.4)

# 技術選定理由

「よく使われている技術」「学びやすい」技術を必要に応じて学習しました。
* **Java**
    *  案件数が最も多い開発言語のため
* **Google Cloud Platform**
    * クラウドでのインフラ構築が流行っているため
* **Eclipse IDE**
    * スッキリわかるの参考書を応用して作成しているため
* **Tomcat**
    * スッキリわかるの参考書を応用して作成しているため
* **Mariadb**
    * Linuxで使用できる主要なデータベースのため
# 実装機能
* アクセスカウント機能
    * 一日のアクセス数を表示
* お問い合わせ機能
    * データベースにお問い合わせ内容を保存する機能
* 年齢、茶道歴自動計算機能
    * 自己紹介ページの年齢、茶道歴を現在の年月日から計算する機能
* ドメインからトップページにアクセス
* 独自のエラーページ

# 制作の感想
いくつか気づいたことがあったので参考までに載せておきます。
## まずは作り始める
参考書で学びながら、自分の制作物に実装していくことが大切だと思いました。
しばしば参考書をやり終えることが目的になってましたが、
**制作物に参考書の技術が活かせるか**が最も大切だと思います。

## 休むことも大切
開発を進めていると行き詰ったり、上手くいかないこともありました。
そういう時は一度手を止めて休むことも必要だと思います。
休むと「**これで解決できるのでは**」と発想が生まれることが度々ありました。

# 参考教材
ポートフォリオを作成にあたって参考にした教材を紹介します。
|参考書| コメント |
|:-:|:-:|
|[スッキリわかるJava入門](https://store.shopping.yahoo.co.jp/bookfan/bk-4295007803.html?sc_i=shp_pc_search_itemlist_shsrg_title) |Javaの基本構文からオブジェクト指向まで丁寧に教えてくれます。Javaを学び始めにオススメです。|
|[スッキリわかるJava入門 実践編](https://store.shopping.yahoo.co.jp/bookfan/bk-429501124x.html?sc_i=shp_pc_search_itemlist_shsrg_title)  |入門からより開発に踏み込んだ内容ですがわかりやすいです。外部アクセスや開発・設計について学べます。|
|[スッキリわかるサーブレット&JSP入門](https://store.shopping.yahoo.co.jp/bookfan/bk-429501124x.html?sc_i=shp_pc_search_itemlist_shsrg_title)|JavaによるWebアプリケーションの作り方を学べます。ポートフォリオのフロント・バックエンドの部分はこちらを参考にしました。|

# おわりに
随時ポートフォリオを発展させつつ、転職活動に励みます。
未経験なので厳しいとは思いますが引き続き技術を磨きます！
最後までご覧いただき、ありがとうございました。
djangoで、複数のアプリに共通して使用する「staticファイル」の配置について

# 結論
プロジェクトの直下などに共通して使用する「staticファイル」をまとめたフォルダを作成すればいいと思います。
作成後は、プロジェクトの`settings.py`ファイルに`STATICFILES_DIRS`変数を追加します。その変数に作成したフォルダのパスを配列の形で格納します。

# 解説
djangoでは、staticファイルを扱う場合、基本は任意アプリのフォルダ内に「static」という名前のフォルダを作成します。そしてそのフォルダに「staticファイル」を配置します。この時、複数のアプリに共通して使用する「staticファイル」を、どこかのアプリの「static」フォルダに入れるのは個人的に違和感を感じました。複数のアプリに共通して使用する「staticファイル」はプロジェクトのどこに配置すればいいか、調査をしてまとめた結果を記事にします。

# 調査した結果
djangoプロジェクトの`settings.py`は、アプリフォルダ以外で「staticファイル」をどこにまとめているパスを指定できるようです。それを使用すれば、プロジェクト直下などに「staticファイル」をまとめられそうです。

# 手順
1. プロジェクトの直下などに「static」という名前のフォルダを作成します。(「共通staticフォルダ」ということにします。)
1. プロジェクトの`settings.py`に下記のコードを追加します。
    ```settings.py
    # ...
    STATICFILES_DIRS = [
        # 「共通staticフォルダ」の配置パスに合わせて適宜調整する
        os.path.join(BASE_DIR, "static")
    ]
    # ...
    ```
1. これで、「共通staticフォルダ」内に作成したstaticファイルを使用することができます。
    ```テンプレート.html
    {# staticファイル読み込み #}
    {% load static %}
    {# 「共通staticフォルダ」内にhoge.jpgを配置した場合 #}
    <img src="{% static "hoge.jpg" %}"/>
    {# 「共通staticフォルダ」内にフォルダがあってもパスを指定すればOK #}
    <img src="{% static "pngs/hoge.png" %}"/>
    ```

これで、複数のアプリに共通して使用する「staticファイル」を違和感なく配置できそうです。
以上です。

# 参考

https://qiita.com/okoppe8/items/38688fa9259f261c9440

https://yu-nix.com/archives/django-collectstatic/#Django%E3%81%AEcollectstatic%E3%81%A7%E9%9D%99%E7%9A%84%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E9%9B%86%E3%82%81%E3%82%8B

https://qiita.com/saira/items/a1c565c4a2eace268a07
Electronでpostする

　これもてっきり簡単にできるものだと思ってたら、以外とそうではなくて、ログイン認証だったり、クライアント証明書を使おうとしたら、axiosを使う記事が見つかって、それでいったん書きました。
　そうじゃなくBrowserWindowではできないのかと思ったら出来て、書き直しました。

# 手順
1. BrowserWindow.loadURLでpostする
1. 結果をpreload.js の window.addEventListener("DOMContentLoaded" で受け取ってipcRenderer.send する
1. ログインは BrowserWindow.webContents.on('login' で処理できる
1. クライアント証明書は、システムの証明書が使用される
Javaで「ファイルを作成する(Files.createFile)」の動作を確認してみた

# 概要
Javaで「ファイルを作成する(Files.createFile)」の動作を確認してみました。以下のページを参考にしました。

https://www.javadrive.jp/start/file/index4.html

# 実装
以下のファイルを作成しました。
```JSample4_1.java
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.Files;
import java.io.IOException;

class JSample4_1{
  public static void main(String[] args){
    Path p = Paths.get("/code/java/file/report2.txt");

    try{
      Files.createFile(p);
    }catch(IOException e){
      System.out.println(e);
    }
  }
}
```
以下のコマンドを実行しました。
```
$ javac JSample4_1.java 
$ java JSample4_1 
$ java JSample4_1 
java.nio.file.FileAlreadyExistsException: /code/java/file/report2.txt
```
# まとめ
何かの役に立てばと。
Minecraft modding Mixinの使い方

# Mixinとは
MixinはSpongePoweredによって開発された既存のソースコードを動的に変更することができるものである。
@[Mixinについて](https://mcmodding.jp/modding/index.php/Mixin)

1.20になってforgeに追加された。

## 簡単な使い方

```java:LocalPlayerMixin.java
package examplemod;

import net.minecraft.client.player.LocalPlayer;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Mixin(LocalPlayer.class)
public class LocalPlayerMixin {
    @Shadow @Final public static Logger LOGGER;

    @Inject(method = "getPermissionLevel", at = @At(value = "HEAD"))
    public void getPermissionLevelMixin(CallbackInfoReturnable<Integer> cir) {
        LOGGER.info("INJECT TO HEAD @ `getPermissionLevel`");
    }
}

```

### @Mixin
`＠Mixin(ターゲットクラス.class)`

挿入したいメソッドのあるクラス(この記事では`ターゲットクラス`とする)を`value`に置く

### @Shadow
`@Shadow` : ターゲットクラスのフィールド(同じ名前である必要がある)

`LocalPlayer`クラスでは1行目に 
```java
public static final Logger LOGGER = LogUtils.getLogger();
```
と既に定義されているため、それを使うためにShadowアノテーションを置く

### @Final
`@Final` : フィールドにfinalがついていた時のみつける

先ほどの`LOGGER`フィールドには`final`がついているため、ターゲットクラスではfinalがついているということを記す。

### @Inject
`@Inject(method = "メソッド名", at = @At(value = "挿入場所"))` : このmixinの醍醐味

ただし、指定が少し難しい

メソッド名：挿入したいメソッド名の名前。今回は`LocalPlayer#getPermissionLevel()`

挿入場所：(空白部分は自分はよくわかっていない)
|value|自分の認識|
|-|-|
|[HEAD](https://github.com/SpongePowered/Mixin/wiki/Injection-Point-Reference#methodhead) |メソッドの一番初めに実行|
|[RETURN](https://github.com/SpongePowered/Mixin/wiki/Injection-Point-Reference#beforereturn)||
|[TAIL](https://github.com/SpongePowered/Mixin/wiki/Injection-Point-Reference#beforefinalreturn)| 指定したメソッドの最後の`return`の直前で実行
|[INVOKE](https://github.com/SpongePowered/Mixin/wiki/Injection-Point-Reference#beforeinvoke)
|[INVOKE_ASSIGN](https://github.com/SpongePowered/Mixin/wiki/Injection-Point-Reference#afterinvoke)
[FIELD](https://github.com/SpongePowered/Mixin/wiki/Injection-Point-Reference#beforefieldaccess)
[NEW](https://github.com/SpongePowered/Mixin/wiki/Injection-Point-Reference#beforenew)
[INVOKE_STRING](https://github.com/SpongePowered/Mixin/wiki/Injection-Point-Reference#beforestringinvoke) |`INVOKE` とほぼ同じ|
[CONSTANT](https://github.com/SpongePowered/Mixin/wiki/Injection-Point-Reference#beforeconstant)||

### 最後に
忘れないようにメモの感覚で残しています。間違っていたところがあれば指摘していただけると助かります。

参考
---
[Spongepowered wiki](https://github.com/SpongePowered/Mixin/wiki)