OmniAICreator/Qiita-1.07M huggingface dataset:
ターミナルからVSCodeを起動するコマンド

# はじめに
プログラミング学習中の[@kat_log](https://twitter.com/kat__log "Twitter")と申します。

ターミナルからVSCodeを起動するコマンドの共有です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1455073/e6bb1b7a-8490-5013-62e2-2b85ce13ffb7.png)

# 最初に設定
1. ⇧+⌘+Pキーにてコマンドパレットを開く
1. `>Shell Command`と入力する（`>`はコマンドパレットを開いた時点で入力されています）
1. `Shell Command: Install 'code' command in PATH`を選択し、エンター
1. 以上で、ターミナルから`code .`コマンドにてカレントディレクトリをVSCodeで開けるようになります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1455073/bb216932-521a-6422-5d3b-d12dc3f382d9.png)

# ターミナルから使用
## カレントディレクトリをVSCodeで開く
`code .`

## VSCodeの拡張機能を全てオフにして開く
`code --disable-extensions`

:::note info
VSCodeの挙動がおかしい時に、拡張機能の影響か切り分ける際の確認に便利です
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1455073/8c78cbcf-4832-33c3-8661-0c2d84101b2f.png)

（右下に、一時的に拡張機能がオフになっているメッセージが表示されます）

# おわりに
お読みいただきありがとうございました。
どなたかの参考になれば嬉しいです。

# 参考

https://zenn.dev/link/comments/50da7d585cb6be

https://motamemo.com/vscode/vscode-tips/disable-extensions/#:~:text=%E6%8B%A1%E5%BC%B5%E6%A9%9F%E8%83%BD%E3%82%92%E3%81%99%E3%81%B9%E3%81%A6%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%97%E3%81%A6%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8B%E3%81%AB,%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%97%E3%81%BE%E3%81%99%E3%80%82
1001: Genesis64 押し釦とランプ

# 概要
簡単なラダー回路(GX-Works3+GX-Simulator3)とGenesis64(GraphWorX64)を接続してみます

# PLC側の準備
![01_GX_ラダー.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361877/c02b9feb-39d6-d9c3-f09d-2e5b3c5c2f28.png)

# Workbench Tag設定
[データ接続] - [Mitsubishi Electric] - [+ MELSECの追加]でPLCを追加し
[タググループ]からタグ設定を行います
![02_Tag設定.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361877/d3b64152-64d8-5e25-6bf5-70c65b33703d.png)
PLCが[グレー]になっている場合は、[機器の有効化]を行います
![03_機器の有効化.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361877/89b94939-736e-3c78-551e-60f53926d184.png)
GX-Simulator3を起動し
![04_モニタ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361877/a5572809-41ef-61cd-c97a-023abc376007.png)
ビット情報は、[スタート]-[ICONICS Tools]-[Data Explorer]から確認できます
![05_DataEｘ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361877/97c1ab9f-6db3-a3a1-de9e-a17f06495fed.png)
# GraphWorX64の設定
GraphWorX64を起動し、[ダイナミック]-[ボタン]を選択
M0,M1の押し釦を配置します
![06_PB.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361877/5d4fd957-54bf-cb01-44c7-d897233ef05f.png)![07_PB.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361877/fe0d96d3-0b5c-a3bf-05a1-a5e1a9fb41b9.png)
ボタン　[プロパティ]-[Context]-[Text] を"ボタン" から　”運転”に変更します
ボタン　[ダイナミック]-[Command]を"値の書込み"に変更し![PB_Set.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361877/d73fdeef-08ae-2423-2f52-820a74dbab77.png)
設定可能なパラメータは、[OnUpValue]のみなので、通常の押し釦動作のように
[OnDownValue]=1  [OnUpValue]=0 が可能になる設定を追加します![PB_Set2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361877/908a7a32-7f05-86cd-a532-0916535553c2.png)
[DataSource]を設定してPLCタグと連携します![PB_Set3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361877/65b24b1d-d973-ec49-a8b6-6264fd06bf80.png)
# 動作確認
　右上の[ランタイム]を実行します![PB_Set4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361877/4c74fd70-a9dc-d1a2-4531-7bb0e79defcd.png)
![PB_Set5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361877/81be2e87-305c-947a-3f6e-136bea7d0a13.png)
# 外観の設定
押し釦の機能や動作は、[ダイナミック]で設定しますが外観は[プロパティ]設定となります
![PB_Set6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361877/5a78403f-2d78-d5ac-dca1-9e0f99a19470.png)
同様に[停止]ボタンも作成
![PB_Set7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361877/c8569b8e-c1ac-2904-d7db-73806dbf043c.png)
押し釦[起動]に運転中ランプを付加します
![PB_Set8.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361877/00552d36-f27b-7cda-f890-4aa4cd9380c2.png)
ランプ[色]機能の設定![PB_Set9.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361877/303a6780-eedf-7fde-03ba-8848f49a9ea2.png)
# まとめ
タッチパネルでの一般的な[押し釦]と[ランプ]を実装してみました
GOTのように[オブジェクト]-[スイッチ]で画面に配置するのとは少し違い、必要な機能は付加していく感じでしょうか

Genesis64 10.97.2 では、[GENESIS64 Converter-GOT]が ICONICS Tools にインストールされています
コンバートすると押し釦やランプがどのように変換されるのか･･･機会があれば試してみたいところです
springで共通のエラーハンドラを実装する【Exception Handler】

今日も備忘録です。

## このドキュメントについて
下記について記載していきます。
・springの@ExceptionHandler,@ControllerAdviceを利用したExceptionのハンドリング


## 実行環境

・Java17
・springboot 3.0.2

## 実装

```java

@RestControllerAdvice
@Slf4j
public class OriginalExceptionHandler {

    @ExceptionHandler(ExampleException.class)
    public ResponseEntity<Object> exampleExceptionHandler(ExampleException e) {
        log.error(e.getMessage(), e);
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new CommonErrorResponse(e.getMessage()));
    }

```
説明：
1. @RestControllerAdviceを利用することで、共通のエラーハンドラを作成できる。
また、json形式のレスポンスを返却できる。
json形式ではないレスポンスを返却したい場合は@ControllerAdviceを利用する

2.@ExceptionHandlerを利用し、引数にハンドリングしたいexceptionクラスを記載することで、該当exceptionが投げられた時に動作するようになる。
,(カンマ)続きで複数のexceptionを記載することもできる。

上記実装は、ExampleExceptionがthrowされた時に、
ログレベルエラーのログを出力後、404エラーを返却する。


### 良きせぬエラーが発生した場合の共通化も可能
```java
@ExceptionHandler(Exception.class)
```
exceptionクラスを設定しておくことで、ヌルポ等想定外のエラーが起こった場合にも共通した処理ができる。


## まとめ
エラーハンドラをちゃんと実装しておくことで、想定外のエラーの場合でも共通したレスポンスを返却できたり、HTTPステータスを統一、変更したい場合にも柔軟に対応できるので、今後の実装に役立てていこうと思います。
Blazor チュートリアル - 画像を表示する

# はじめに

チュートリアルを進めて、Blazorアプリ上で画像ファイルを表示させる方法について学びます。（詳細は一番下の参考ページにあります。）
簡単な画像Viewerを作成します。

完成イメージ：ボタンを押すと画像が切り替わります。画像は３種類です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/897cc320-36f1-ccea-abb3-baf069675897.png)



# 準備

Blazorアプリを新規作成して、編集していきます。
本記事では`index.razor`に追記していきます。

https://qiita.com/firesign2023/items/7165f0977b6fb45bdd70

表示させる画像を用意して`Images`フォルダを新規作成してその中に入れます。

[Image Creator from Microsoft Bing](https://www.bing.com/create)で画像を作ってみました。

①image1.jpg
②image2.jpg
③image3.jpg

見た目を変えるために`index.razor.css`ファイルを作成します。

下記のようになっていればOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/14beee96-7517-4033-d494-f0a57a1a93ba.png)

# 画像を表示させる


ボタンを押した時に画像が切り替わるようにします。
`ShowImage`メソッドに`画像id`を渡すことで`image1.jpg` , `image2.jpg` , `image3.jpg`を切り替えます。
~~~
@code {
    private string? imageSource;

    private void ShowImage(int id)
    {
        imageSource = $"images/image{id}.jpg";
    }
}
~~~

ボタンを配置します。ボタンを押した時の動作は`@onclick="() => ShowImage(imageId)"`です。

~~~
@for (var i = 1; i <= 3; i++)
{
    var imageId = i;
    <button class="btn" @onclick="() => ShowImage(imageId)">
        Image @imageId
    </button>
}
~~~


画像を表示するために`img`タグを使用します。`src`には表示させたい画像の場所を指定します。
アプリ起動時は画像が未選択なので`<p>Please Select Image.</p>`を表示するようにしています。
~~~
@if (imageSource is not null)
{
    <p class="card">
        <img src="@imageSource" />
    </p>
}
else
{
    <p>Please Select Image.</p>
}
~~~

# 完成形

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/897cc320-36f1-ccea-abb3-baf069675897.png)


~~~index.razor
@page "/"

<h1>Dynamic Image Source Example</h1>

@for (var i = 1; i <= 3; i++)
{
    var imageId = i;
    <button class="btn" @onclick="() => ShowImage(imageId)">
        Image @imageId
    </button>
}

@if (imageSource is not null)
{
    <p class="card">
        <img src="@imageSource" />
    </p>
}
else
{
    <p>Please Select Image.</p>
}

@code {
    private string? imageSource;

    private void ShowImage(int id)
    {
        imageSource = $"images/image{id}.jpg";
    }
}
~~~

~~~index.razor.css
.card {
    border: 1px solid #ccc;
    border-radius: 4px;
    padding: 10px;
    margin-bottom: 10px;
    background-color: #f7f7f7;
}

    .card img {
        max-width: 100%;
        height: auto;
    }

.btn {
    display: inline-block;
    padding: 10px 20px;
    margin:10px 10px;
    font-size: 16px;
    font-weight: bold;
    text-align: center;
    text-decoration: none;
    background-color: #007bff;
    color: #fff;
    border-radius: 4px;
    border: none;
    cursor: pointer;
    transition: background-color 0.3s ease;
}

.btn {
    background-color: #0056b3;
}

~~~

# 参考ページ

https://learn.microsoft.com/ja-jp/aspnet/core/blazor/images?view=aspnetcore-6.0#preview-an-image-provided-by-the-inputfile-component

https://qiita.com/nobu17/items/7465006ce24a4490183b#1css%E3%81%AE%E5%88%86%E9%9B%A2
技術記事を書いてフォロワー数を15,000人にする方法

# 2018年、35歳無職ワイ

Qiitaで記事を書き始めたころ、私は無職のおじさんでした。
Twitterのフォロワー数は**50人**ほどでした。

でも、Qiitaで技術記事を書き始めてから
フォロワーさんがものすごく増えました。

1つ記事を書くごとに100人以上フォロワーさんが増えた時期もありました。

現在はありがたいことに**15,000人**の方にフォローいただいています。
なんと当初の**300倍**です。

# 正直、プログラマーとしては三流

私自身は、どこにでもいるレベルのポンコツ気味なプログラマーです。
メンタルも技術力も弱い感じです。

当然、皆さんより技術的にレベルの高い記事は書けていません。

皆さんより分かりやすい説明文も書けません。

誰よりも笑える記事も書けていません。

でも、2020年の年間いいね数で1位になることができました。

Qiitaアカウントのフォロワー数でも1位になることができました[^1]。

大した才能もない割には、すごく上手くいった例だと思います。
その要因を自分なりに分析した結果を、この記事に書いていきたいと思います。

# 【要因1】 理解力が低かった

私はプログラミングの記事を読むのが苦手でした。

たぶん、理解力が低いんだと思います。

でも、それがあったからこそ逆に「読みやすい記事を書くこと」に異常に執着することができました。

# 【要因2】 文章が苦手だった

子供の頃から文章を書くのが苦手で、作文の宿題などは親に代筆してもらっていました。

そのため、普通の技術記事は書く気になれず、会話形式の記事しか書けませんでした。

会話形式といっても、小説も書いたことがないので、
2ちゃんねる風の関西弁の文体で書くことにしました。

「2ちゃんねるの人たちが書けるんだから、これなら私でも書けるだろう」
そんな感じです。

でも、それが逆に個性となり、覚えてもらいやすかったんだと思います。

具体的に言うと───

### 普通の文体で書かれた記事の場合

> 読者「この記事、ためになるな〜」
> 読書「いいねボタン、ポチ！」
> 
> 〜1ヶ月経過〜
> 
> 読者「この記事、ためになるな〜」
> 読書「いいねボタン、ポチ！」

このとき、

> 読者「あ、1ヶ月前に読んだ記事の、あの人だ！」

と気づかないこと、多いと思います。

### ワイ記法で書かれた記事の場合

> 読者「なんだこの関西弁のコントみたいな記事」
読者「まあ読みやすくていいじゃん」
読書「いいねボタン、ポチ！」
> 
> 〜1ヶ月経過〜
> 
> 読者「お、またあの関西弁の人の記事だ」

↑このように、
記事だけでなく「人」を覚えてもらえる、というメリットがありました。

アカウント名も「会社やめ太郎（本名）」という珍妙なものだったので、余計に記憶に残りやすかったのだと思います。

# 【要因3】 Twitterもそのキャラでやっていた

もともと私は標準語の文章でTwitterをしていたのですが、
この頃から、なんとなくTwitterも関西弁で投稿するようになりました。

そのおかげで───

> 読者「Qiitaのあのキャラ、Twitterに実在してんのかい！」

───という感じで少し面白い感じになり、
それもあってTwitterのフォロワー数が増えていったのかもしれません。

# 【要因4】 自分の存在価値のなさを理解していた

当時は無職だったので、

> 「記事を書いて有名になって、再就職をしないといけない」
> 「そうしないと、妻子ともに路頭に迷ってしまう」

そんな風に考えていました。

ですが、技術力もキャリアも知名度も無かったため───

「誰も自分に興味などない」
「自分の記事など、読む**理由**がない」
「そんな中で、どうやって自分の記事をクリックさせるか」
「どうやって最初の一文で興味を持たせるか」
「どうやって最後まで読ませるか」
「どうやって、いいねボタンを押させるか」
「どうやって自分のことを覚えてもらうか」
「一生忘れられないようなアウトプットをしてやる」

───そんなことを無意識に考えていました。
自分の発信を手に取ってもらう「理由」を探していました。
そんな想いが、何かしら効いていたのかもしれません。

# 【要因5】 ディスられてもやめなかった

本人としては至って真面目に書いている記事なのですが、
文体がコント臭かったり、たまに内容が間違ってたりして、色々と批判されました。

- 2ちゃんねるに「やめ太郎しね」と書かれる
- 有名なエンジニアさんからも批判される

でも、死ねと言われようが、尊敬している人から否定されようが

> 「それでも、俺が面白いと思うことをやめる理由にはならねぇなぁ！？」

と、なんとか続けられたこと。

メンタル弱くてすぐ凹むくせに「なんだかんだで、やめない才能」があったことが
私の強みだったと思います。

でも、誰もいいねをしてくれなかったらここまで書き続けられなかったと思います。
私の記事に初めていいねをしてくれた@uhyoさんには感謝しています。

# 【要因6】 自分の力を過信し、嫉妬に燃えていた

35歳まで、技術記事どころか作文もあまり書いたことがなかったのに、

「世の中の技術記事、全部つまんねーな！」
「なんでこんなもんが評価されてんだ！」

そう思うことで、何もない自分を守っていました。

今思うと嫉妬まみれでダサ過ぎますが、その嫉妬のおかげで頑張れた部分もあると思います。

35歳で妻子もいるのに無職で、技術力もキャリアもなく、
どうしようもなくポンコツな状態でしたが、

「俺の方が面白い記事を書ける！」

そう自分の力を過信することで、半ば強引にモチベーションを保っていました。

現実を受け入れて「俺なんて、もうダメですわ...」と思うのではなく、
どんなポンコツな自分でも見捨てずに───

「俺、やってやっかんな！」

───そう思えたことが、後から考えると大事だったんだと思います。


# まとめ

いろいろ書きましたが、大前提としては───

- 学びの深い記事
- できるだけ正確な記事
- 分かりやすい記事
- 旬のテーマを扱った記事
- 笑える記事

───みたいな、読む人にとって価値のある記事を書くことが大事だと思います。
笑いながら、分かりやすく旬の技術について学べるなんて、最高ですもんね。

**〜おしまい〜**

# 記事の書き方についての具体的な方法はこちらやで

- [文章が下手なワイが、技術記事を書くときにやっていること](https://qiita.com/Yametaro/items/21b8772e6c0d1d77e176)
- [会話形式で技術記事を書くメリット](https://qiita.com/Yametaro/items/a40ffcd65d77ed8b29a0)

# 新しい記事もよろしくやで

- **[【Vue】reactive()って要らなくね？ref()だけでよくね？](https://qiita.com/Yametaro/items/2a37f18fb52f7565b2cb)**

[^1]: [参考記事：Qiitaのいろいろランキング2020](https://qiita.com/rana_kualu/items/307d461ad2d59a1d6008)
KubernetesでPgpoolを動かすと設定が単純になるということ

# はじめに

PgpoolをKubernetesで動かすとそうでない場合と比較して設定が単純になります。
それはKubernetesの機能で賄えるものがあるためです。最近、Pgpoolを学んだこともありこの記事ではその部分について説明したいと思います。

# 前提：PostgreSQL Operatorを使用する

前提として、以下のような構成のPostgreSQL Operatorを使うものとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1474054/3b6e425f-2328-b4e0-fae8-1221d8f7d630.png)

引用元：https://www.pgpool.net/docs/pgpool-II-4.3.0/ja/html/example-kubernetes.html

# PostgreSQLのレプリケーションはOperatorが行う

PgpoolにはPostgreSQLクラスタを監視して、レプリケーションやフェイルオーバーを行う機能があります。
Kubernetesでは代わりにOperatorが監視してくれます。

PostgreSQL OperatorのPostgreSQLで使用するコンテナイメージはspiloというものが使われており、PostgreSQLとPatroniがバンドルされています。

https://github.com/zalando/spilo

Patroniがクラスタを監視してフェイルオーバーを自動で行ってくれます。
別の構成ですが、日本語で解説されているページを載せておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1474054/a5af004f-9a1f-1883-c4f9-1c8cd930b99e.png)

引用元：https://recruit.gmo.jp/engineer/jisedai/blog/postgresql12-patroni-cluster/

# ServiceがPostgreSQLの負荷分散を補助してくれる

PgpoolにはバックエンドとなるPostgreSQLを1台ずつ定義してどの比重で分散させるか設定します。

KubernetesのServiceを使うと、PostgreSQLのレプリカへのアクセスの負荷分散を行ってくれます。

↓のようなイメージです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1474054/63a5085b-2db7-f64c-36d3-95d9c3b18a11.png)

マスターとレプリカでは役割が違うため、それぞれServiceが分かれています。
Pgpoolは2つのServiceのDNSだけ把握すればよいため、レプリカの台数が増えても設定変更する必要がなくなります。
ServiceはPODについているラベルでバックエンドのターゲットを特定します。

https://kubernetes.io/ja/docs/concepts/services-networking/service/

KubernetesでのDNSは以下のように決まります。

https://kubernetes.io/ja/docs/concepts/services-networking/dns-pod-service/

ただし、完全に互換になるわけではないと思っています。
クライアントによってはマスターかレプリカの片方に処理が偏るかもしれません。クエリによってどのように分散するか設定したい場合はPgpoolにて設定を行う必要があります。

https://www.pgpool.net/docs/latest/ja/html/runtime-config-load-balancing.html

# Pgpool間のハートビートは不要となる

上記の内容から、PgpoolではPostgreSQLのフェイルオーバーを行わないため、Pgpool間のPostgreSQLクラスタの状況共有は不要となります。
PgpoolにはWatchdogという状況共有を行うための仕組みがありますが、Kubernetesで動かす場合にはOFFにします。

代わりにPgpoolをリスタートする機能が必要となりますが、KubernetesのDeploymentやStatefulSetを使うことができます。

https://kubernetes.io/ja/docs/concepts/workloads/controllers/deployment/

https://kubernetes.io/ja/docs/concepts/workloads/controllers/statefulset/

Watchdogの動作の説明は以下のページが参考になります。

https://www.fujitsu.com/jp/products/software/resources/feature-stories/postgres/article-index/pgpool2/

Watchdogを使用する場合、PgpoolとPostgreSQLそれぞれのスプリットブレインを考慮する必要があります。
WatchdogをOFFにできれば、Pgpool側のスプリットブレインの心配がなくなるメリットがあると思います。

# 具体的な設定例

以下のページではKubernetesでPgpoolを動かす最低限の設定が以下のように紹介されています。
https://www.pgpool.net/docs/pgpool-II-4.3.0/ja/html/example-kubernetes.html

```config
backend_hostname0 = '<プライマリService名>'
backend_hostname1 = '<レプリカService名>'
backend_port0 = '5432'
backend_port1 = '5432'
backend_flag0 = 'ALWAYS_PRIMARY|DISALLOW_TO_FAILOVER'
backend_flag1 = 'DISALLOW_TO_FAILOVER'

failover_on_backend_error = off

sr_check_period = 10                        (ストリーミングレプリケーションチェック機能を利用する場合のみ)
sr_check_user='username of PostgreSQL user' (ストリーミングレプリケーションチェック機能を利用する場合のみ)

load_balance_mode = on
connection_cache = on
listen_addresses = '*'
```

フェイルオーバーの設定が無効になっていますね。
あとは必要に応じて接続数やメモリなどの設定を加えていくことになります。

# おわりに

今回は最近触っているPgpoolの設定について触れました。基盤が変わると設定も変わるということを思い知りました。
これからも勉強します！
心理学生からFlutterのエンジニアへ  文系大学生が切り開くエンジニアの道


![スクリーンショット 2023-06-20 14.16.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/7563cb71-4943-0bc3-97f3-e890825aa84b.png)


こんにちわ。　いせりゅーです。

今回はこちらのイベントで話せそうな内容を記載していこうと思います。
景品が欲しいので、頑張りたいです（笑）

https://qiita.com/official-events/0d4c7ac216324bd6a3b9


:::note warn
注意
- この通りした結果、絶対にうまくいくとは限りません。
- 正直なところ、運が良かったなと思っていたりしています。
:::



# プロフィール

![スクリーンショット 2023-06-19 18.57.56（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/f24c9a8d-2d41-8ab8-af70-23bb6b0c2eb0.png)


# 大学1年生

- 心理学部に入学する。
- 児童福祉に興味を持ち、海外ボランティアに行く決意をする
- ベトナムで児童福祉を一ヶ月間滞在する中で死にかけた
- 死にかけたことによって、気持ちが180°変わった
- 図書館の友達にプログラミングに誘われる
- HTML・CSSをやってみる
- HTML・CSS・JavaScriptで案件を受注してみた
- 案件をこなせることができずに挫折


# 大学2年生
- ポートフォリオサイトを作りまくる。
- HTML・CSS・JavaScriptに完全に挫折をして、模索する
- 模索した結果、PHPに手を染めてみる→環境構築で挫折する
- 模索した結果、Pythonに手を染めてみる→環境構築で挫折する
- 従姉妹のお父さんにMacBookをもらった。
- MacBookでしかできない開発はないのかを探した結果「Swift」をやってみた
- Swiftが結構面白くて、その魅力に取り憑かれる。
- ここから個人開発を始める。

# 大学3年生
- インターンシップに参加したいと思い、[TechTrainのミッション](https://techtrain.dev/missions)に挑戦した
- メンターの方とたくさんの面談を重ね、なんとかクリアした
- Missionを作成した [エキサイト株式会社](https://info.excite.co.jp/)とカジュアル面談をした
- Swiftを志望していたが、「Flutterをやらないか？」と言われ、「やらせてください」と打診する。
- エキサイト株式会社とのインターンを開始する。
- GitのCommit・Push・Mergeの概念をあまり知らなかったため、悪戦苦闘
- Flutterの状態管理あたりで悪戦苦闘
- インターンで少しずつ任せてもらえる領域が広がり、モチベーションがMaxの時に謎の吐き気に見舞われる。
- その影響でご飯が食べられなくなり、１６キロ体重が減少する。
- エキサイトでのインターンが終了→、就職活動をする。
- 逆求人などの参加するが、最初はボコボコにされて心が折れる

# 大学4年生
- 個人開発やインターンでの経験をしっかり持った上で面接に挑む
- ２５社受けて、３社から内定をもらえる。
- 現在の職場（[株式会社ゆめみ](https://www.yumemi.co.jp/)）から内定をもらえる。
- 個人開発に熱中し、アプリを作り続ける。
- 卒論を締め切り2日前で提出し、卒業する。


# 振り返ってみて
いや〜〜色々とありすぎて振り返るのがとても大変でしたね。。笑
個人的には本当に運が良かったと思います。エキサイトのインターンもたまたまうまくいきましたし、ゆめみの内定も特殊なルートで受かったので、本当に偶然の重なりだと思います。

# 最後に
色々と人生は変わったりするので、皆さんも色々な視野を持ってみると面白く生きれると思います！！僕は現在はとても幸せに生活できています👍
これからも楽しい人生を送れるようにもりもり頑張っていきます。
今さらGitHub Copilotを使ってみた！ コード入力補完がめちゃ便利‼︎

# GitHub Copilotとは？

ソースコードリポジトリで有名なGitHubが提供しているプログラミング支援AIツールです。
2021年ごろから提供開始されていたため、ChatGPTなどの生成AIがブームになる前から話題になっていましたね。

https://docs.github.com/ja/copilot/getting-started-with-github-copilot

技術としてはOpenAIのプログラミング専用モデルCodexが利用されています。

主な利用方法としては、Visual Studio Codeなど開発者が実際にプログラミングするツール（開発環境）にプラグインとしてこのGitHub Copilotを有効にし、コード入力の補完などを実現します。


### 最近聞くGitHub Copilot Xって何？

2023年3月、生成AIブームの勢いが止まらないなかでGitHub Copilot Xが発表されました。
これはGPTモデルの新バージョン導入に加え、チャットや音声入力などコード補完に限らない様々なプログラミング支援を行えるCopilotの機能拡張の総称としてのアナウンスでした。

https://github.blog/jp/2023-03-23-github-copilot-x-the-ai-powered-developer-experience/

現在は申請した人のみWaitlistに登録され、段階的にテクニカルプレビューの利用が承認される形になっています。



# GitHub Copilotの利用方法

### GitHubアカウントでCopilotを有効化

最初にCopilotのプランを選んでサインアップする必要があります。
個人用（for Indivisuals）とビジネス用（for Business）があり、個人用で月額1,400円ほど。30日の無料トライアルもあります。また、学生は無料で利用できるようです。

https://github.com/github-copilot/signup

私の場合はGitHub Copilot for Businessに登録しているOrganization所属のアカウントを今回利用しました。

![スクリーン ショット 2023-06-17 に 21.11.29 午後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/635f3673-33cd-6e87-6953-d50e4af507ce.png)




### VS CodeにCopilot拡張機能をインストール

Copilotを有効にしたGitHubアカウントVS Codeにサインインし、GitHub Copilot拡張機能をインストールします。
![スクリーン ショット 2023-06-17 に 21.17.38 午後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/6ee2227e-017c-ee2e-5347-70043cf585f1.png)

VS CodeのステータスバーにCopilotちゃんアイコンが表示されたら、無事に有効化できているはずです。
![スクリーン ショット 2023-06-17 に 21.21.16 午後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/d955b00d-d74a-83f5-f9b7-bcc8a64b5830.png)


### 実際にコードを書いてみよう！

適当に `test.py` ファイルを作成し空のPythonコードを書き始めてみます。
![スクリーン ショット 2023-06-17 に 21.23.26 午後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/17103b29-fd25-594a-839b-2ceb32fcfa74.png)

いきなりコメントで「ランダムな数字を表示する」と書いてみます。
![スクリーン ショット 2023-06-17 に 21.25.34 午後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/0097bf10-04f8-10b7-7ed0-973d5152c877.png)

改行すると、薄い文字で `import` 句がサジェストされてきました。
![スクリーン ショット 2023-06-17 に 21.26.20 午後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/24cd0f8e-b79c-f920-40e5-71686b9d28bc.png)

Tabキーでサジェストを承諾し、さらに改行すると続きのサジェストが出現します。
![スクリーン ショット 2023-06-17 に 21.27.24 午後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/4a17fc53-70fc-0c76-cbd7-b0624a2b32b4.png)

Tabキーでサジェスト承諾し、また改行すると次のサジェストはなぜかバッククォート3つ。
ただ、コレすでに動きそうです。試しにデバッグ実行してみましょう。
![スクリーン ショット 2023-06-17 に 21.29.16 午後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/490996a4-59b6-354a-8836-75ba4b53715a.png)

右上のデバッグボタンを押すと、ターミナル上に整数がプリントされました！
2回押してみましたがちゃんとランダムに出力されています。
![スクリーン ショット 2023-06-17 に 21.33.35 午後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/6f904929-51b5-6c76-92a3-0f0f43d08beb.png)


# 最後に

これは便利ですね。
ChatGPTとうまく組み合わせて、最初にゼロからサンプルコードをまとめて生成する部分はChatGPTに頼み、細かいコード修正や追記にGitHub Copilotをガッツリ活用する、というスタイルも効果的かも知れません。
Netlify の使い方

Netlify で次のページをデプロイします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/3f06c8b9-0906-3714-46ed-50228cff16c3.png)

## データの用意

フォルダー構造

```text
$ tree hello
hello
└── index.html
```

```bash
mkdir hello
cd hello
touch index.html
```

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Hello</title>
</head>
<body>
<blockquote>
<h2>Hello</h2>
	<blockquote>
	<p>こんにちは</p>
	</blockquote>
</blockquote>
<hr />
Jun/21/2023 AM 07:00<br />
</body>
</html>
```

注意
>シンボリックリンクは使えません。
>フォルダー名は何でも構いません。


## Netlify へアップロード

hello というフォルダーを　'deploy manualy' へドラッグします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/858a2c18-3534-ae85-e19e-75c3b1685b6c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/102e88d9-be4a-0810-497a-aa0708a02a61.png)

## ブラウザーでアクセス

URL が表示されるので、ブラウザーでアクセス

https://lighthearted-semifreddo-893a86.netlify.app

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/3aff8507-51b6-3c29-9514-bb20d38efc47.png)

## ページの更新

Deploys で、フォルダー毎、ドラッグアンドドロップをします。

```text
     Need to update your site?
Drag and drop your site output folder here

       Or, browse to upload
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/0832035c-c8f4-62cc-3059-87a4572d3d58.png)
Serverless FrameworkでAPIキーとなるリソースIDをSSM Parameter Storeに保存する

# やりたいこと
Serverless FrameworkでAPIをデプロイしますが、その際に生成される `a1bcdef2gh` みたいなAPIキーはURLとして利用されていたり、APIを利用する際に必要になる場合があります。

この情報をServerless Frameworkで `sls deploy` した際に自動でSSM Parameter Storeに保存する方法です。


# 対応
以下のServerless Frameworkの定義の通り、生成されたリソースIDを `resources` の部分に記載したCloudformationでSSM Parameter Storeに保存すると Serverless Frameworkで完結します。

一度デプロイしてみて、論理コンポーネント名を確認して `Value` のところで参照するとスムーズです。 (
`!Ref ApiGatewayRestApi` の部分）

```yaml
frameworkVersion: '3'

# --- 
# 省略
# --- 

functions:
  api:
    handler: app/api.handler
    events:
      - http:
          path: /
          method: ANY
      - http:
          path: /{proxy+}
          method: ANY

resources:
  Resources:
    ApiKeyParameter:
      Type: AWS::SSM::Parameter
      Properties:
        Name: "/api/${self:custom.stage}/api-key"
        Type: String
        Value: !Ref ApiGatewayRestApi
        Description: "API Key"
```
【React】Reactのバージョンをダウングレードさせる方法【簡単】

## はじめに
ここ最近、React18の新機能について学習及び記事にまとめており
その際に毎回React17以前にダウングレードさせる手順を記述するのは手間のため
こちらにまとめさせて頂きます！

実際にReact18と17の差分を確認したりする際に、
この記事を参考にしてみてください！

## バージョンダウンの手順

今回はReactのバージョンを18から17に落とします

### 1.Reactプロジェクト作成

```terminal
$ npx create-react-app react-app --template typescript
```

上記のコマンドで`typescript`ベースのreactのプロジェクトが作成できます。

### 2.コマンドを実行

```package.json
 "react": "^18.2.0",
 "react-dom": "^18.2.0",
```

何も指定でせずプロジェクトを作成すると、上記のようなバージョン(実行日時によって変動します)が作成されるかなと思います。

ですので、以下のコマンドを実行してください。

```terminal
$ npm install --save react@17.0.2 react-dom@17.0.2
OR
$ yarn add react@17.0.2 react-dom@17.0.2
```
そうすると...

```package.json
 "react": "17.0.2",
 "react-dom": "^17.0.2",
```
Reactがバージョン18から17に変更されたのが確認できると思います。

## 最後に
今回は、Reactのバージョンダウンの方法を備忘録形式でまとめさせて頂きました！

React18の変更点について、今後記事にまとめていく予定ですのでよかった見ていってください！

https://qiita.com/kim_t0814/items/ce95b6b92e7994d4fdac
multipart form-data と boundary 

サンプル: 
https://developer.mozilla.org/ja/docs/Web/HTTP/Methods/POST#:~:text=multipart/form%2Ddata%20%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84%E3%82%BF%E3%82%A4%E3%83%97%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%9F%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%A7%E3%81%99%E3%80%82

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/14243772-3981-1359-52f7-2a4a026e59aa.png)

```
POST https://httpbin.org/post
Content-Type: multipart/form-data;boundary="HOGEHOGE"

--HOGEHOGE
Content-Disposition: form-data; name="field1"

value1
--HOGEHOGE
Content-Disposition: form-data; name="field2"; filename="example.txt"

value2
--HOGEHOGE--
```


結果:
```
HTTP/1.1 200 OK
Date: Tue, 20 Jun 2023 21:29:00 GMT
Content-Type: application/json
Content-Length: 493
Connection: close
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

{
  "args": {},
  "data": "",
  "files": {
    "field2": "value2"
  },
  "form": {
    "field1": "value1"
  },
  "headers": {
    "Accept-Encoding": "gzip, deflate",
    "Content-Length": "174",
    "Content-Type": "multipart/form-data;boundary=\"HOGEHOGE\"",
    "Host": "httpbin.org",
    "User-Agent": "vscode-restclient",
    "X-Amzn-Trace-Id": "Root=1-64921a1c-3d90ffc007917d634b21b54d"
  },
  "json": null,
  "origin": "106.72.201.193",
  "url": "https://httpbin.org/post"
}
```

テストはここでできる。

https://httpbin.org/#/HTTP_Methods/post_post
Unreal Engine4 UCharacterMovementComponentについて

# UCharacterMovementComponentとは

https://www.main-function.com/entry/2017/11/25/225805
こちらの記事にて詳しく解説されています。


つまり、キャラクターを動かしたり、その時のパラメータを取得することができるよ～というコンポーネントであるのですが、まだ全然理解はできていない。


現在はこのように使用しており、書かれたものを見せられると「はいはい、なるほどね」とわかるが、実際に「この処理書いてね」と言われて書けるかといわれると怪しい。

* TryGetPawnOwnerでPawnを取得
* Pawnを取得した変数->GetCharacterMovementコンポーネント->関数であったり、プロパティ
で覚えておけばいいのかな

```php
if (ShooterCharacter == nullptr)
	{
		ShooterCharacter = Cast<AShooterCharacter>(TryGetPawnOwner());
	}
	if (ShooterCharacter)
	{
		//キャラクターが空中にいるかどうか
		bIsInAir = ShooterCharacter->GetCharacterMovement()->IsFalling();

		//キャラクターが走っているか
		if (ShooterCharacter->GetCharacterMovement()->GetCurrentAcceleration().Size() > 0.f)
		{
			bIsAccelerating = true;
		}
		else
		{
			bIsAccelerating = false;
		}
	}

```

# おわりに
BPでUnreal Engine開発を始めて調子に乗ってC++で始めましたが、痛い目にあってます...
頑張っていきます....
[Python]拡大表示のウィンドウを追加する

# キャプチャした画像の拡大

[OpenCVでマウス操作する (2)](https://wonderfuru.com/opencv%E3%81%A7%E3%83%9E%E3%82%A6%E3%82%B9%E6%93%8D%E4%BD%9C%E3%81%99%E3%82%8B-2/) でズームするとあったので、
これかと思ったけど違ったので作り直し

マウスで場所取って、その部分を切り抜いて拡大する。
画面が遠いので、ちょっと拡大したいと思って作成。

```python
mouse_x = 0
mouse_y = 0
def set_mouse_pos(event, x, y, flags, param):
    global mouse_x, mouse_y
    if (event == cv2.EVENT_LBUTTONDOWN or
        event == cv2.EVENT_MOUSEMOVE and (flags & cv2.EVENT_FLAG_LBUTTON) > 0):
        # print(event, x, y, flags, param)
        mouse_x = x
        mouse_y = y
        

cv2.namedWindow('cap')
cv2.setMouseCallback('cap', set_mouse_pos)

zoom_size = 100 # halfサイズ
zoom_scale = 5

while True:
    img = WindowCapture('MonsterX U3.0R')

    h, w = img.shape[:2]
    x = max(zoom_size, min(w - zoom_size, mouse_x))
    y = max(zoom_size, min(h - zoom_size, mouse_y))
    l, r = x - zoom_size, x + zoom_size
    d, u = y - zoom_size, y + zoom_size
    
    cv2.rectangle(img, (l, d), (r, u), color=(255, 255, 255))
    cv2.imshow("cap", img)
    
    
    zoom_img = img[d:u, l:r, :]
    zoom_img = cv2.resize(zoom_img, None, fx=zoom_scale, fy=zoom_scale)
    
    cv2.imshow("zoom", zoom_img)
    
    key = cv2.waitKey(100)
    if key == ord('q'):
        break
    

cv2.destroyAllWindows()
```

```WindowCapture```は、[[Python]マルチモニター環境でのウィンドウキャプチャ](https://qiita.com/danupo/items/e196e0e07e704796cd42) のものを流用。

直接キャプチャしたかったけど、MonsterXをOpenCVで直接キャプチャすると
古いせいかよく止まる。純正アプリだと止まらないので、画面キャプチャする方針へ。
（WindowCaptureはいじって枠と書けしてるけど、数値ハードコーディングなので、非公開ｗ）
Dockerを用いたRailsの基本的なコマンド

現在のRoute設定を表示
```
$docker-compose exec web rails routes
Prefix Verb    URI Pattern    Controller#Action
pages_about GET    /pages/about(.:format)    pages#about
...以下ルーティング設定の表示が続く
```

コントローラーの作成
```
docker-compose exec web rails generate controller pages
```

コントローラーの削除
```
docker-compose exec web rails destroy controller pages
```
Git使い方

リポジトリをGitHub上で作成する。

初回コミット時
```.sh
echo "# test" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:y-nagayoshi/test.git
git push -u origin main
```

二回目以降コミット時
```.sh
git status
git add -A
git commit -m "変更内容"
git remote add origin git@github.com:y-nagayoshi/test.git
git branch -M main
git push -u origin main
```
LambdaのLayerをCloud9で作る

# はじめに
Cloud9を使用してLambdaで使用するLayerを作るときのzipの作成手順をまとめておく

作成時につまづいた部分も残しておくことで、未来の自分のためになることを期待

# Cloud9の準備

マネコンから Cloud9 > [関数の作成] > 名前を入力して [作成] 

Cloud9 IDEの「開く」からエディタの画面へ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116677/fe67d7ac-a82e-6dca-2b08-eaf3dc88a99b.png)

右下のターミナルで操作していく
![FireShot Capture 413 - lambda_layer - AWS Cloud9 - ap-northeast-1.console.aws.amazon.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116677/b0e1aaac-4c0d-2387-891a-00823be3d7b9.png)


# 環境構築

pyenvのインストール

```sh
curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash
```

bashrc
```sh
vi ~/.bashrc
```
```
export PATH="/home/ec2-user/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
```
```
source ~/.bashrc
```

入れたいpythonのバージョンを指定してインストール
```sh
pyenv install 3.9.16
pyenv global 3.9.16
```

バージョン確認
```sh
python3 -V
```

モジュールを入れるディレクトリ
```sh
mkdir python && cd $_
```

Layer化したいものを詰めてzip化
```sh
pip3 install requests -t .
cd ../
zip -r requests.zip python/
aws s3 cp requests.zip s3://<backet_name>/requests.zip　　　　# S3に上げる場合はaws cliから可能
```

作成したファイルを右クリックでダウンロードも可能
![FireShot Capture 414 - lambda_layer - AWS Cloud9 - ap-northeast-1.console.aws.amazon.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116677/0cd45b87-8852-65fb-4d75-2030f95c7f6c.png)


あとはLayerに画面で作成するだけです。

必要なくなったらインスタンスの削除を忘れずに。


# memo

個人的メモ書き。

## requestsとboto3

(2023.06.21)
python3.9のLambdaに対して、何も考えず上記の方法でrequestsのLayerを作って適用したら、import時にエラーが発生した。

```
boto3 requests cannot import name 'DEFAULT_CIPHERS' from 'urllib3.util.ssl_'
```

requestsを外してboto3だけにするとimportは成功するし、boto3を入れずにrequestsのLayerだけにしたらその場合も成功する...


（原因）
両方とも依存関係の中に `urllib3` があり、違うバージョンの2つが共存する状態になっていた。

- boto3は urllib3-1.26.16
- requestsは urllib3-2.0.3 （バージョン指定しなかったせいで最新の2.31.0を入れようとしていた）

requestsのバージョンを下げていき、urllib3のバージョンを揃えて解決。
Livewireで動的にバリデーションルールを変更する


Livewireでは$rulesプロパティを定義することで、バリデーションルールを設定することができます。

```php
protected $rules = [
    'name' => 'required',
    'email' => 'required|email'
];

public function submit()
{
    // バリデーション実行
    $this->validate();

    // バリデーションで問題なければ続く処理が実行
}
```

上はあらかじめ決められたルールを適用するケースですが、このルールを動的に変更したい場合(選択肢によって表示される項目が変わるなど)があるかと思います。
その際に思いつくことしては、以下のようにmount時に$rulesを書き換えることかと思いますが、これではバリデーションルールを変更することはできません。

```php
protected $rules = [
    'name' => 'required',
    'email' => 'required|email'
];

public function mount ()
{
    // mount上部で定義したバリデーションルールのままで以下に書き変わらない
    $this->rules = [
        'name' => 'required',
        'email' => 'required|email',
        'postcode' => 'required'
    ];
}
```

そこで別な方法としては、$rulesプロパティの代わりにメソッドを定義し、mount時に呼び出すことで動的にバリデーションルールを書き換えることができます。

```php
public function mount ()
{
    $this->rules();
}

protected function rules()
{
    //$this->conditionは何かしらのフラグ
    if ($this->condition) {
        return [
            'name' => 'required',
            'email' => 'required|email',
            'postcode' => 'required'
        ];
    } else {
        return [
            'name' => 'required',
            'email' => 'required|email'
        ];
    }
}
```


[参考]
https://readouble.com/livewire/2.x/ja/input-validation.html
jwt（json web token）とjwt認証について

# jwtとは
json形式で表現された認証情報などをurl文字列として送受信できるよう、符号化やデジタル署名の仕組みを規定した標準規格。
jwtにデジタル署名の仕組みがあるのではなく、jwsの署名の仕組みを利用し作成された、トークンの構造をjwtと呼ぶ。(jwt認証のところで説明）

※ 補足
符号化 ・・・ エンコードすること
デジタル署名 ・・・ 暗号化を利用して、データの信頼性を保つ仕組み。公開鍵方式や共通鍵方式などを使って、データが改竄されていないことや、作成者の証明を行うこと。


# jwtの仕組み
・json形式のデータをURLセーフにする
→ httpヘッダーやクエリパラメータにはスペースや/などの特殊文字を入れることができないため、json形式のデータをbase64URLエンコードし、httpヘッダーやクエリパラメータに埋め込めるようにする。

・jsonをコンパクトにする
→ よく使われるjsonのキー名を省略形にすることで、データをコンパクトにする。このようなjwtのjsonをクレームと言う。
省略形の例は以下画像
![スクリーンショット 2023-06-21 1.44.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484861/21ec7bcb-7394-152a-66b5-0f6130a5a31e.png)
※ 上記は主な登録クレーム（jwtのjsonの項目)であるが、全て必須ではない。また、登録クレーム以外にも任意のクレームを追加することも可能。（例えばメールアドレスをクレームとして追加するなど。）


# jwt認証とは
1. jwtのトークン構造について
ヘッダ、ペイロード、シグネチャの3つからなる。上記のjwtの仕組みで説明したjsonはペイロードにあたる。ヘッダーには何が含まれているかというと、署名のアルゴリズムとトークンの種別が含まれる。シグネチャはヘッダとペイロードを暗号化したものとなる。
ヘッダ、ペイロード、シグネチャをそれぞれbase64URLエンコードし、ヘッダ.ペイロード.シグネチャという形でドットで繋いだものが、jwt形式のトークンとなる。

2. jwsについて
jwt自体はhttpヘッダーやクエリパラメータによるデータの送受信のためにjsonを都合いいように加工する仕組みであり、認証とは全く関係ない。つまり、base64URLデコードすれば、誰でも内容の閲覧や改竄できてしまうセキュリティガバガバな仕組みである。
上記を解決するための仕組みとしてjws(json web signature)がある。具体的には、　公開鍵方式などを用いて、ヘッダとペイロードを暗号化（署名）し、シグネチャに含めるという仕組みである。（ヘッダ+ペイロード ＝ シグネチャ)
![スクリーンショット 2023-06-21 2.26.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484861/b9591c77-9fc8-41b0-8c21-8c17dc27e5a2.png)
上記を検証するとき、仮にヘッダやペイロードが改竄されていた場合、復号化したシグネチャの内容と、ヘッダとペイロードが異なるため、改竄されたことを検知することができる。

3. jwt認証の仕組み
・iDとパスワードの認証に成功したら、アプリケーション（バックエンド）はjwtトークンを発行し、ユーザー（フロント）に送信。（ここの処理は、IDプロバイダーと呼ばれる外部アプリに委託することがよくあるらしい。）
・受け取ったユーザー（フロント）はjwtトークンをクッキーに保存し、その後のアプリケーション(バックエンド）との通信時にはhttpヘッダーにjwtトークンを含める。
・jwtトークンを受け取ったアプリケーション（バックエンド）は秘密鍵を使用し、シグネチャを復号化。シグネチャとヘッダ+ペイロードを比較し、差異がないかチェック。なければ認証OK。
韓国語の形態素解析パッケージSoynlp (pure Python)

# はじめに
韓国語の形態素解析では[koNLPy](https://konlpy.org/en/latest/)を利用することができますが、辞書に未登録の単語の認識がうまくできないという点があります。これにうまく対処するためにPythonのみで作られたパッケージがSoynlpということのようです。（MeCabに対するJanomeのようなもののようです）

https://github.com/lovit/soynlp

紹介の内容は以下の記事をもとにしています。

https://datascienceschool.net/03%20machine%20learning/03.01.04%20soynlp.html

# インポート&コーパス

```bash
!pip install soynlp
```

コーパスのダウンロード
```bash
!wget https://raw.githubusercontent.com/lovit/soynlp/master/tutorials/2016-10-20.txt -O 2016-10-20.txt
```

こんな感じのファイル
![スクリーンショット 2023-06-21 1.26.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638747/995e88eb-f46f-ffca-53b5-2dca16380b95.png)

# コーパスの読み込み
行、または2つのスペースで文が区切られているとして、`DoublespaceLineCorpus`で読み込むとコーパスのオブジェクトが生成される。
なぜ2つのスペース区切りなのかは不明。
```python
from soynlp import DoublespaceLineCorpus

# iter_sent=Trueだと1行に複数文を許容する
corpus = DoublespaceLineCorpus("2016-10-20.txt", iter_sent=True)
```

オブジェクトの中身はこのような感じ。
![スクリーンショット 2023-06-21 1.29.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638747/3a543bf6-01f2-813c-4e1e-73dea8608739.png)

# 単語抽出
先ほどのコーパスをもとに単語抽出を行う。なお、koNLPyのように辞書ベースでの分析ではないため、与えられたコーパスでの学習を行う。

```python
from soynlp.word import WordExtractor

word_extractor = WordExtractor()
word_extractor.train(corpus) # 50秒くらいかかる
```

分割の学習がされた単語ごとに、cohesion, branching entropy, accessor varietyというパラメータが算出され、単語ごとに諸々確認できるらしい

https://datascienceschool.net/03%20machine%20learning/03.01.04%20soynlp.html#cohesion

```python
# 各単語でのスコアを算出
word_score = word_extractor.extract()

# cohesion: P(연합|연)で表される生起確率
word_score["연합"].cohesion_forward
#=>0.1943363253634125

# branching entropy: 次に出てくる文字のエントロピー（例えば確実に一文字しかない場合は0になる）
word_score["연합"].right_branching_entropy
#=>0.42721236711742844

# accessor variety: 次に出てくる文字の種類の数
word_score["연합"].right_accessor_variety
#=>42
```

# L-トークン化
韓国語は分かち書きされるものの、その分かち書きにおいては、助詞やサ変動詞における「する」の部分のようなものはくっつけて書きます。そのため、左側のトークンと右側のトークンに分ける機能がsoynlpにあります。

```python
from soynlp.tokenizer import LTokenizer

scores = {word:score.cohesion_forward for word, score in word_score.items()}
l_tokenizer = LTokenizer(scores=scores)

l_tokenizer.tokenize("안전성에 문제있는 스마트폰을 휴대하고 탑승할 경우에 압수한다", flatten=False)

#=>
[('안전', '성에'), # 安全/上に
 ('문제', '있는'), # 問題/がある
 ('스마트폰', '을'), # スマートフォン/を
 ('휴대', '하고'), # 携帯/して　
 ('탑승', '할'), # 搭乗/する
 ('경우', '에'), # 場合/に
 ('압수', '한다')] # 押収/する
```

# 最大スコアでの分かち書き
分かち書きすることが韓国語の正書法ではありますが、ネットの書き込みなどで分かち書きを全くしていない文などが存在しています。このような文に対する前処理として使える分かち書きの手法です。

```python
from soynlp.tokenizer import MaxScoreTokenizer

maxscore_tokenizer = MaxScoreTokenizer(scores=scores)
maxscore_tokenizer.tokenize("안전성에문제있는스마트폰을휴대하고탑승할경우에압수한다")

#=>
['안전',
 '성에',
 '문제',
 '있는',
 '스마트폰',
 '을',
 '휴대',
 '하고',
 '탑승',
 '할',
 '경우',
 '에',
 '압수',
 '한다']
```

# おわりに
これを使う日本人、いるのか...?
[Unity] Debug.Logの呼び出しをリリースビルドから除外 & GC低減ラッパークラスを作る

# 1. Debug.Logの問題点
Unityでコンソールに情報を出力する関数としては以下のようなものがある。
~~~c#
Debug.Log();
print();
~~~
これらはリリースビルド時に除外される....ということはなく、普通に呼ばれている。
`Debug.logger.logEnabled = false` でログを無効にすることができるが、メソッド呼び出しコストの発生は避けられない。呼び出し時に条件付きコンパイルで囲えば回避できるが、あまり現実的ではない。
~~~c#:条件付きコンパイルで囲う
#if UNITY_EDITOR
    Debug.Log("test");    //疲れる...
#endif
~~~


# 2. メソッド呼び出しコストの回避

この問題に対しては、Debugクラスのラッパークラスを作成しそこからログを出力することで回避することができる。

~~~c#
public static class MyDebug {
    [Conditional("EDITOR_MODE")]
    public static void Log(string msg) => Debug.Log(msg);
}
~~~

[Conditional属性](https://learn.microsoft.com/ja-jp/dotnet/api/system.diagnostics.conditionalattribute?view=net-7.0)
> 指定した条件付きコンパイル シンボルが定義されていない場合、メソッド呼び出しまたは属性を無視するようコンパイラに指示します。

※メソッド呼び出しを無視するのであって、メソッド本体を除外する訳では無い

あとは`LogWarning`, `LogError`, `Assert`, `DrawRay` などの呼ぶ予定のあるDebugクラスメソッドをラップしていくだけだ。

どうせラッパークラスを作るなら少し改良してみる。

# 3. GC低減

`Debug.Log`で複数のデータを文字列にする場合、文字列結合によるアロケーションが発生。
~~~c#:allocation
int score = 71, clearTime = 61;
Debug.Log($"score : {score} clearTime : {clearTime}");
//"score : 71 clearTime : 61"
~~~
そもそも引数の型が`object`型なので、`int`や`float`などの値型は**boxing**が発生する。これも同様にアロケーションが発生。
~~~c#:allocation
int num = 5;
Debug.Log(num);
~~~
そこで今回使用するのが[ZString](https://tech.cygames.co.jp/archives/3383/)という文字列生成ライブラリ。

[ZString](https://tech.cygames.co.jp/archives/3383/)
> 文字列生成におけるメモリアロケーションをゼロにする「ZString」というライブラリを公開しました。
![Image](https://tech.cygames.co.jp/wp-content/uploads/2020/02/zstring_01_table.png)

これをラッパークラスから呼び出すようにジェネリックメソッドを定義していく... (一部抜粋)

~~~c#
public static class MyDebug {
    public const string DEBUG_CONDITIONAL_TEXT = "UNITY_EDITOR";

    [Conditional(DEBUG_CONDITIONAL_TEXT)]
    public static void Log(string msg) => UnityEngine.Debug.Log(msg);

    [Conditional(DEBUG_CONDITIONAL_TEXT)]
    public static void Log<T1>(T1 arg1) => UnityEngine.Debug.Log(ZString.Concat(arg1));

    [Conditional(DEBUG_CONDITIONAL_TEXT)]
    public static void Log<T1, T2>(T1 arg1, T2 arg2) => UnityEngine.Debug.Log(ZString.Concat(arg1, arg2));

    [Conditional(DEBUG_CONDITIONAL_TEXT)]
    public static void Log<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3) => UnityEngine.Debug.Log(ZString.Concat(arg1, arg2, arg3));

    [Conditional(DEBUG_CONDITIONAL_TEXT)]
    public static void Log<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4)
        => UnityEngine.Debug.Log(ZString.Concat(arg1, arg2, arg3, arg4));
    //省略
    //ZString.Concatは16引数まで定義されている
}
~~~



呼び出すときはデータを引数で渡していけばいい（便利）

~~~c#
int score = 71, clearTime = 61;
MyDebug.Log("score : ", score, " clearTime : ", clearTime);    
//"score : 71 clearTime : 61"
~~~

# 4. Debugラッパークラスのデメリット
コンソールに出力されたログをクリックするとラッパークラスのDebugメソッドの場所に飛ばされる。スタックトレースからジャンプするのは少し面倒。

# 参考
https://tech.cygames.co.jp/archives/3383/
https://creator.game.cyberagent.co.jp/?p=8645
https://shikaku-sh.hatenablog.com/entry/unity-debug-log-optimization
【Blazor】Visual Studioでデバッグ中に応答なし後に開けなくなった場合の対応

# はじめに
Visual Studioで、Blazor Serverのデバッグをしていると急に応答なしになり、Visual Studio ごと落ちてしまうことがありました。
更に対象のプロジェクトを開き直そうとしても、Visual Studio ごと落ちてしまうのです。

# 原因
対象プロジェクトは.NET 7で作成しています。
bin\Debugフォルダを見ると「...」フォルダが出来ており、その「...」フォルダを開くと、また「...」フォルダと「net7.0」フォルダがあり、また「...」フォルダ開くと「...」フォルダと「net7.0」フォルダと無限状態になっていました。

![スクリーンショット 2023-06-21 0.00.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/dac23108-9208-477b-8613-1876d80e1950.png)

デバッグ中に「...」フォルダが作り続けられて最終的に落ちてしまうようです。

# 対応
ファイルエクスプローラーで削除しようとしましたが、エラーで削除出来ませんでした。
コマンドプロンプトで対象のbinフォルダに移動して、「rd /s /q debug」とします。

rd / rmdir は、ディレクトリを削除するコマンドです。

|オプション|説明|
|:--|:--|
|/s|ファイルやサブディレクトリも含めて削除する|
|/q|/sで削除する際に確認メッセージを表示しない|

# 最後に
こんな現象あるんですね。
【Unity】【Shader】【SpriteStudio6】影を落とす方法

## はじめに
個人ゲーム制作などでスプライトアニメーションをさせたいときなどは、条件はあるが無料で使うことのできる [SpriteStudio6](https://www.webtech.co.jp/spritestudio/index.html) がおすすめだ。

ただ、このツールを使って作られたスプライトアニメ素材を、ただ単に3D世界に配置しただけだと影が落ちない。

どうにか影を落としたいと思うとShaderをいじる必要があるが、Shaderはかなりとっつきにくい。
初心者が特にShaderの勉強をせずに、今回の目標を達成しようとすると結構ハードルが高い。

なので、そのクリティカルパスをメモっておこうと思う。


## 環境
今回の環境は以下の通り
・Unity (2020.3.43f1)
・SpriteStudio6 (OPTPiX SpriteStudio Ver.6 Professional)

UnityにSpriteStudio6のスプライトアニメをあてがう方法はSpriteStudioの公式サイトから読み解いて下さい。


## 実装方法
その後、↓のShaderファイルを開いて、編集してください。

``` shader:Assets/SpriteStudio6/Sprite_SpriteStudio6.shader
Shader "Custom/SpriteStudio6/SS6PU/Sprite"
{
	Properties
	{
		/*省略*/
	}

	SubShader
	{
		Tags
		{
			"Queue" = "Transparent"
			"IgnoreProjector" = "True"
			"RenderType" = "Transparent"
		}

		Pass
		{
			Cull Off
			ZTest LEqual
			ZWRITE [_ZWrite]
			Stencil
			{
				Ref 0
				Comp [_CompareStencil]
				Pass Keep
			}
			BlendOp [_BlendOperation]
			Blend [_BlendSource] [_BlendDestination]

			CGPROGRAM
			#pragma vertex VS_main
			#pragma fragment PS_main

			#pragma multi_compile _ ETC1_EXTERNAL_ALPHA
			#include "UnityCG.cginc"

//			#define RESTRICT_SHADER_MODEL_3
			#pragma multi_compile _ PS_NOT_DISCARD
			#pragma multi_compile _ PS_OUTPUT_PMA
			#include "Base/Shader_Lib_SpriteStudio6.cginc"
			#include "Base/Shader_Data_SpriteStudio6.cginc"
			#include "Base/ShaderVertex_Sprite_SpriteStudio6.cginc"
			#include "Base/ShaderPixel_Sprite_SpriteStudio6.cginc"
			ENDCG
		}

		// ここから下が今回追記した影を落とす処理(半分は↑の基本描画のコピペ)
		Pass
		{
			Tags{ "LightMode"="ShadowCaster" }

			CGPROGRAM
			#pragma vertex VS_main
			#pragma fragment PS_main

			#pragma multi_compile_shadowcaster _ ETC1_EXTERNAL_ALPHA
			#include "UnityCG.cginc"

//			#define RESTRICT_SHADER_MODEL_3
			#pragma multi_compile _ PS_NOT_DISCARD
			#pragma multi_compile _ PS_OUTPUT_PMA
			#include "Base/Shader_Lib_SpriteStudio6.cginc"
			#include "Base/Shader_Data_SpriteStudio6.cginc"
			#include "Base/ShaderVertex_Sprite_SpriteStudio6.cginc"
			#include "Base/ShaderPixel_Sprite_SpriteStudio6.cginc"
			ENDCG
		}
	}
	FallBack Off
}
```

別ファイルにコピーを取って、コピー先のShaderファイルに実装する方法は今回は避けています。
(どうやら実行時にこのShaderをあてがう処理が自動で走っていて、コピー先のShaderをあてがっても上書き参照されちゃいます。その辺の処理を追いきれていないので今回の記事では触れません。)

↑のShaderが適応された状態が↓の動画です

https://twitter.com/avmiya_game/status/1671183066294005760


## 残りの課題
とりあえず、影を落としたいだけでしたらこれで十分ですが、まだ問題はあります。
・裏面だと影が落ちない(単にY軸180度回転で左右反転した場合など)
・このスプライトアニメ側に別の何かの影を投影できない

↑の問題も今回手を加えたShaderファイルに追加の処理を書けばなんとかなるような気がしますが、僕はShader専門家ではないので、調べようとすると結構気合入れないとですね。

頼られると嬉しくなっちゃうので、いい感じにおだてて下さればもうちょっと調査頑張ってみます(苦笑)
何かあれば、↑のツイートにリプなどあれば対応するかも
6.ランダムエンカウント実装

**6.ランダムエンカウント実装**

マップを2種類作成し、ランダムエンカウントにて切り替える手順をまとめていきます。

・目次
1.ランダムエンカウント実装


<br>
<br>
<br>
<br>

**1.ランダムエンカウント実装**

概要
以下関数実装　（今回関係ない部分は省略しています。）
　・checkEncounter
　・rand

```main.c
void main(){

	while (TRUE) {
		joy = joypad();
		
		if (joy & J_UP)         checkEncounter();
		else if (joy & J_DOWN)  checkEncounter();
		if (joy & J_LEFT)       checkEncounter();
		else if (joy & J_RIGHT) checkEncounter();
}
	

void checkEncounter() {
	int encounterChance = 80;
	int randomValue = rand();

	if (randomValue % encounterChance == 0) {
		SCX_REG = 0;
		SCY_REG = 0;
	
		set_bkg_data(0, 1, vstile); 
		set_bkg_tiles(160, 160, 40, 50, vsmap);
		
		while(TRUE){
			joy = joypad();
			
			if (joy & J_UP || joy & J_DOWN || joy & J_LEFT || joy & J_RIGHT){
			} else if (joy & J_A)  {
				set_bkg_data(0, 241u, AllTaile);
				set_bkg_submap(map_pos_x, map_pos_y, 20, 18, AllMap, AllMapWidth);
				return;
			}
		}
    }
}


int rand() {
    seed = (seed * 1103515245 + 12345) & 0x7FFFFFFF;
    return seed;
}


```
◇解説
>if (joy & J_UP)         checkEncounter();
　else if (joy & J_DOWN)  checkEncounter();
　if (joy & J_LEFT)       checkEncounter();
　else if (joy & J_RIGHT) checkEncounter();
→checkEncounterを呼び出し
	

>void checkEncounter() {
→checkEncounter関数を定義

>int encounterChance = 80;
→エンカウントの確率を設定

>int randomValue = rand();
→rand関数を呼び出し、ランダム値を格納

>if (randomValue % encounterChance == 0) {
→エンカウント率とランダム値を比較し、エンカウント時の処理に入る

>SCX_REG = 0;
　SCY_REG = 0;
→スクロール状態初期化
		
>set_bkg_data(0, 1, vstile);
　set_bkg_tiles(160, 160, 40, 50, vsmap);
→エンカウント時の背景を設定
		
>while(TRUE){
→エンカウント時のキー操作するまでループ

>joy = joypad();
　if (joy & J_UP || joy & J_DOWN || joy & J_LEFT || joy & J_RIGHT){
→方向キー入力を無効化

>} else if (joy & J_A)  {
→エンカウント終了条件として一旦Aボタン押下時の条件追加

>set_bkg_data(0, 241u, AllTaile);
　set_bkg_submap(map_pos_x, map_pos_y, 20, 18, AllMap, AllMapWidth);
→通常マップの背景を設定し、エンカウント前の位置に戻る

>return;
→戦闘終了

>int rand() {
→rand関数定義

>seed = (seed * 1103515245 + 12345) & 0x7FFFFFFF;
　return seed;
→ランダムアルゴリズムにてランダム値生成し、値を返す

		



コンパイル結果
![ダウンロード.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476538/d917f820-36f4-c069-20f9-d1d34b049936.gif)


<br>
<br>
<br>

以上！
次回はランダムエンカウント時のバトルシーンでの操作を作成しよう！
Java マルチスレッド処理～Runnable編～

Javaでマルチスレッド処理を実装する。
１章：Runnable編です。
今後、２章：Thread編、３章：Executor編を投稿予定です。

昨今のコンピューターが搭載しているCPUは「マルチコア」と呼ばれ、１つのCPUが複数のコアの持っています。
そのため、従来のシングルコアの並行処理のように切り替えることなく同時に複数の処理を進めることができます。
※「並行処理」．．．シングルコアで処理対象を切り替えながら実行すること
※「並列処理」．．．マルチコアで同時に処理を実行すること

### ・対象者
細かい理屈は抜きにとりあえずマルチスレッド処理を体感したい人

### ・Runnableインターフェースを使用したマルチスレッド処理
手順①：Runnableインタフェースを実装したクラスを作成
実装したクラス内でrunメソッドをオーバーライドします。
runメソッド内に別スレッドで実行したい処理を実装します。
```java
class RunnableThread implements Runnable {
	//startメソッドが呼ばれた際に実行される処理
	public void run() {
		for (int i = 0; i < 3; i++) {
			System.out.println("Runnableクラスのrun:" + i);
			//処理ごとに１秒間スリープ
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
```
### 手順②：スレッドの呼び出し
①で実装したrunメソッドを呼び出すには、①のクラスのインスタンスを作成し、startメソッドを呼び出します。
```java
//スレッド処理を呼び出すクラス
class Main {
	public static void main(String[] args) {
		//Runnbleインタフェースを実装したクラス（RunnableThread）を指定してインスタンスを生成
		Thread thread1 = new Thread(new RunnableThread());
		//スレッド処理を開始（別スレッドで実行される）
		thread1.start();
		//メインスレッドで実行
		for( int i = 0;i<3;i++) {
			System.out.println("Mainクラス:" + i);
			
			//実行ごとに１秒間スリープ
			try {
				Thread.sleep(1000);				
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
```
### ・実行結果
MainクラスとRunnbaleクラスでそれぞれのスレッドが実行されているのが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484672/73ecb6b1-2aab-db60-c8ac-a3fa2bcdfff0.png)



次回は２章：Thread編です！（１章：Runnable編と似ているので理解しやすいと思います。）
お楽しみに！
VS Codeで拡張機能なしでMarkdownに画像を貼り付けられるようになった

Visual Studio Code v1.79で、拡張機能を使わずにMarkdownに画像を貼り付ける機能が実装されました！今までクリップボードの画像を貼り付けるには[Paste Image](https://marketplace.visualstudio.com/items?itemName=mushan.vscode-paste-image)などの拡張機能が必要でしたが、これからは拡張機能なしで同様のことができるようになります。

また、Shiftキーを押しながらMarkdownエディターにメディアファイルをドラッグアンドドロップした場合、ワークスペースにファイルがコピーされるようになりました。

<blockquote class="twitter-tweet" data-dnt="true" data-theme="dark"><p lang="en" dir="ltr">🎉 The May release of <a href="https://twitter.com/code?ref_src=twsrc%5Etfw">@code</a> is here! Check out what&#39;s new:<br><br>🔒 Read-only mode for files and folders<br>💡 Automatic copy of dragged/pasted files to Markdown<br>🔎 Notebook rich content search<br>... &amp; much more!<br><br>Release notes: <a href="https://t.co/CqbeScHiOW">https://t.co/CqbeScHiOW</a><br>Download: <a href="https://t.co/1CSkQpMJlL">https://t.co/1CSkQpMJlL</a> <a href="https://t.co/EVlrfZZ8K2">pic.twitter.com/EVlrfZZ8K2</a></p>&mdash; Visual Studio Code (@code) <a href="https://twitter.com/code/status/1666868920404570112?ref_src=twsrc%5Etfw">June 8, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

以下のスクリーンキャプチャーのように、画像や動画をMarkdownの編集画面に貼り付けるか、Shiftキーを押しながらドラッグアンドドロップすると、ワークスペースにファイルがコピーされます。そして、Markdownには相対パスでリンクが挿入されます。

![スクリーンキャプチャー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420120/04bb12b6-9a13-1394-aef0-c3a1b3c3f3ec.gif)

この機能は、ワークスペースの外にあるメディアファイルを現在編集中のMarkdownファイルで使う場合や、クリップボードに保存されているスクリーンショットを貼り付けたい場合に便利です。

ファイルのコピー先や、既存のメディアファイルを上書きするかどうかなど、詳しい設定は[公式ドキュメント](https://code.visualstudio.com/updates/v1_79#_copy-external-media-files-into-workspace-on-drop-or-paste-for-markdown)を参照してください。

## 参考

- [Visual Studio Code May 2023](https://code.visualstudio.com/updates/v1_79)
jpackageで削除できないフォルダを作ってしまったら...

# はじめに
「やってしまった...。jpackageでiフラグを./まで書いたところでエンターキーを押してしまった...。」
ってことありますよね？

https://stackoverflow.com/questions/69412663/jpackage-doesnt-generate-working-exe-and-bugs-folders

> You have set --i and --temp such that input folder is current directory and therefore contains the temp folder - so jpackage is copying the current directory into temp every time.

上のstackoverflowの記事にも書かれているように、iフラグで指定した入力フォルダの中に出力先フォルダが含まれていると、大変なことになってしまいます。
つまり、出力したフォルダ構造そのものが入力されてしまうので、無限ループになります。これによって、`C:\project\fuga\app\fuga\app\fuga\app\fuga\app...`というような無限（実際は、文字数等の関係で、どこかで止まります）に続く、フォルダ構造が生成されてしまうのです。

こうなってしまうと、Windowsのエクスプローラーでは消すことが出来なくなります。実は、Windowsが扱うことが出来るパスの長さは決まっているものの、jpackageはそんなことお構いなしにフォルダ構造を生成し、扱える文字数を余裕で突破してしまうので、ゴミ箱に移動することが出来なくなるのです。

https://atmarkit.itmedia.co.jp/ait/articles/2106/02/news024.html

同様に、コマンドプロンプトの`rd`コマンドの`/s`も、実行途中でエラーを吐いて落ちてしまいます。一般的なエンジニアはUbuntu等が入ったboot USBを常備しているでしょうが、たまたま無かった場合はどうやって消せばよいのでしょうか？


# 解決法
「Javaによって生成されたのなら、Javaによって消せばいいじゃないか。」という発想です。以下のコードを適当なJavaファイルに書き込み、パスの部分を適当に書き換えます。実行すると、見事、フォルダが削除されました。

```java:zettai_ni_kesu.java
import java.nio.file.*;
import java.io.*;
import java.util.*;

class zettai_ni_kesu{
    public static void main(String[] args) {
        try {
            var dir=Paths.get("C:\\Users\\osane\\hogehoge\\keshitai");
            var walk=Files.walk(dir);
            walk.sorted(Comparator.reverseOrder())
                .map(Path::toFile)
                .forEach(File::delete);
        } catch (IOException ioErr) {}
    }
}
```
　
こちらのページを参考に作成しました。

https://devlights.hatenablog.com/entry/2022/07/12/073000


# おわりに
コマンドの引数はよくよく確認してから実行しましょう。

以上。