OmniAICreator/Qiita-1.07M huggingface dataset:
laravel middleware ルーティングで管理者だけを通したい

## やりたい事
web.phpの以下のコードででログインしていないアカウントを弾いてくれる。
```php
->middleware('auth')
```
同じようにルーティング時点で管理者以外も弾きたい。

## userテーブルにis_adminを追加
```php:マイグレーション
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->boolean('is_admin')->after('remember_token')->nullable()->comment('管理者');
        });
    }

    public function down(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('is_admin');
        });
    }
};

```


## middleware作成

```php:
 php artisan make:middleware AdminOnly
```

```php:app/Http/Middleware/AdminOnly.php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use App\Models\User;

class AdminOnly
{
    public function handle(Request $request, Closure $next): Response
    {
        $is_admin = auth()->user()->is_admin;
        if($is_admin != 1){
            return redirect()->route('top');
        }

        return $next($request);
    }
}


```

## Kernelに追加
```php:app/Http/Kernel.php
    protected $routeMiddleware = [
        'adminOnly' => \App\Http\Middleware\AdminOnly::class,
    ];

```

## やりたい事
これでis_adminフラグが立ってないユーザーを弾いてくれます。
```php: web.php
->middleware(['auth', 'adminOnly'])
```
斜方投射(空気抵抗あり)の飛距離を求めたい

斜方投射はきっと多くの方が通る道でしょう。スポーツをしている人々も大学生も斜方投射したことがない人の方が少ないのではないでしょうか。
ですが、空気抵抗ありの斜方投射で飛距離を求めるのはかなりの難易度です。その方法をここに記します。
# まずは式から
https://mathmaru.hatenablog.com/entry/2021/04/14/162901

このページより、$x$を飛距離、$y$を初期条件の高さ、$k$を空気抵抗係数、$m$を質量、$g$を重力加速度として
``` math
X=\frac{kx}{mv_0\cos θ}
```
``` math
Y=-\frac{k^2y}{m^2g}
```
``` math
Z=1+\frac{kv_0\sin θ}{mg}
```
``` math
Y=XZ+\log(1−X)
```
ということがわかります。指数をとると
``` math
e^Y=(1−X)e^{XZ}
```
正負を反転させて
``` math
-e^Y=(X-1)e^{XZ}
```
$e^{-Z}$倍して
``` math
-e^{Y-Z}=(X-1)e^{Z(X-1)}
```
$Z$倍して
``` math
-Ze^{Y-Z}=Z(X-1)e^{Z(X-1)}
```
ここでランバート(ランベルト)の$W$関数という$xe^x$の逆関数(初等関数ではない)を使い
``` math
W(-Ze^{Y-Z})=Z(X-1)
```
$X$についてとくと
``` math
X=1+\frac{W(-Ze^{Y-Z})}{Z}
```
$X=\frac{kx}{mv_0\cos θ}$より
``` math
x=\frac{mv_0\cos θ(W(-Ze^{Y-Z})+Z)}{kZ}
```
``` math
Y=-\frac{k^2y}{m^2g}
```
``` math
Z=1+\frac{kv_0\sin θ}{mg}
```
$Y$と$Z$に代入するのは式が長くなるのでやめます
# いざプログラム
言語はJavaScriptにします

```js
function Lambert_W_0(x) { //ランバート(ランベルト)のW関数(0の方)
	var ret = 0;
	for (var i = 0;i < 100;i++) {
		var power = Math.pow(Math.E,ret);
		var little_error = ret*power-x;
		ret = ret-little_error/(power*(ret+1)-(ret+2)*little_error/2/(ret+1));
		if (ret < -1) {
			ret = -1;
		}
	}
	return ret;
}

function compute_x(rad,m,v,g,k,y) {
	if (k == 0) { //空気抵抗なしの時
		var A = g/(v*v*Math.cos(rad)*Math.cos(rad));
		var B = Math.tan(rad);
		return (B+Math.sqrt(B*B+2*A*y))/A;
	}
	if (m == 0) { //NaNが出ないように
		return 0;
	}
	var Y = -k*k*y/(m*m*g);
	var Z = 1+k*v*Math.sin(rad)/(m*g);
	var T = Lambert_W_0(-Z*Math.pow(Math.E,Y-Z))+Z;
	return m*v*Math.cos(rad)*T/(Z*k);
}
```
シミュレーションでおそらく正しく動作することを確認済み
プログラミングスクール卒業後のあれこれ④


約4ヶ月ほど空いてしまいました。
前回の投稿が2023/09/26ということなので、だいぶ記憶も薄れてしまいました。
良くないですねー。
前回の記事では、Webアプリケーション開発にどんな立場でどんな業務に従事していたかなど書きました。
別業務でRPAの導入から実際にRPAを触ってシナリオ作成を行いました。
そのことについて書きたいと思います。

## RPAツールを使って
勤めていた会社は、学習支援を行う事業を行っていました。
RPAの使用用途としては、お客様がツールを通して学んだ学習記録のデータ取得をするというものです。
ツールは（たしか）8~10種類ほどありました。

ちょうど入社したときは、導入検討途中の段階でした。
前担当者から引き継ぎ、見積書の作成依頼やこちらの使用用途に沿った提案をしていただくための打ち合わせの段取りを組んだりしました。
ちなみにRPAはWinactorを使用しました。

## RPAとは
簡単にRPAの説明を書きます。
Robotic Process Automation　の略語です。
PCで行う事務作業を自動化するソフトウェアロボット技術のことを指します。
人が日常的に「このサイトを開く」「エクセルを開く」「このボタンをクリックする」「マウスホイール操作を行う」「ダウンロードする」「ダウンロードしたものをエクセルに貼り付ける」といった動作をロボットに指示を送って作業効率UPができます。
「シナリオ」と呼ばれるものを作成し、ロボットに指示を送ります。

## 実際に行ったこと
Winactorを導入し、いざシナリオを作成し始めることに。
わたしは学習記録のデータ取得方法をどうやっておこなっているのか、というところから教えてもらい、実際に業務に取り掛かりました。
メンバーは自分を含め3人。
先輩2人が各ツールのデータ取得を手で行っていたことから、シナリオが単純になるであろうものから作成に取り掛かりました。

ちなみに、本契約前にトライアルを行いました。
そのときに実際にエンジニアのかたから講習を受けることで理解を深めていきました。
わたしの場合、実際につくりはじめても、一歩理解が遅いなーと落ち込むことも。。
先輩にこの部分が上手くいかない、とか他のツールでの取得の時にこうだった、とかアドバイスをいただきながらなんとか進めていきました。
シナリオを作成する上で「部品」がたくさんあります。
サイトによっては動作するものと、上手く動作してくれないものがありました。
クリックするにしてもXpathを指定してクリックさせたり、タグをつかって指定したり、様々なパターンを試しました。
1つひとつトライアンドエラーを繰り返してシナリオを完成させていくことに達成感を感じたことも。

このシナリオ作成業務にかかわったのは4ヶ月ほどでしたね。
こちらもとてもいい経験だったと思います。



<br><br><br>

今日はこのあたりで終わりたいと思います。
読んでいただきありがとうございました。
STUDIOのCMSで地図を埋め込む方法

# はじめに
STUDIOのCMSで地点をマッピングした地図を埋め込みたいと思ったので、その方法を解説します。
複数個所の情報をWEBに掲載したいと思ったのですが、位置をマッピングされた地図があったほうが直感的に場所が分かりやすいと思い、地図表示が出来ないかと考えました。WEBサイトの情報はCMSで管理しており、CMSの機能の制限があるので、地図が埋め込めるかどうかが気になったので、こちらでまとめておきます。
結論としては、GoogleMapの「マイマップ」をiframe機能を使うことで簡単に実現できました。


# まずは

### STUDIOとは

https://studio.design/ja

STUDIOは、ノーコーデでWEB制作を行えるサービスです。テンプレートも数多く揃っているので、それらしく制作したい場合にも簡単に作ることが出来ます。小さなプロジェクトであれば、無料で作成することもできます。

### GoogleMapのマイマップとは

https://www.google.co.jp/intl/ja/maps/about/mymaps/

GoogleMapのマイマップは、自分だけのオリジナルの地図を作成、編集、共有できる機能で、マーカーを設置することが可能です。また、マイマップを一般公開して、WEBサイトに埋め込むことなどが可能です。今回は、こちらの機能を使用します。



# 方法
1. GoogleMapのマイマップを作成する　※詳細は割愛
1. GoogleMapのマイマップのメニューから、「自分のサイトに埋め込む」を選択します
1. HTMLのiframeタグが表示されるのでコピーします
1. STUDIOのCMSで、「埋め込みコード」を使用します（iframeが使用できます）
1. コピーしたHTMLのiframeタグをペーストします
1. これで、GoogleMapのマイマップがCMSで埋め込むことができます


# まとめ
STUDIOのCMSを使用した場合は、デザインのレイアウトなどは多少制限を受ける印象がありますが、埋め込みタグを上手く使用することである程度自由度は上がります。
今回は、最初は上手く地図が埋め込めるかがちょっと不安でしたが、STUDIOのCMSで埋め込みコードが使用できたこと、GoogleMapのマイマップでiframeタグを使って埋め込みできたこと。これらの組み合わせがばっちりだったので、簡単にCMSを使いながらも地図の埋め込みを実現することができました。


<br>
最終的にはこのように埋め込むことが出来ました。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475457/dc62fb3f-053a-38e0-4085-176b793320f7.png)


GoogleMapのマイマップを埋め込んだサイトはこちらになります。
STUDIOのCMSを利用してします。

https://nouenlabo.com/posts/20240203
LinuxでPythonのGUI(tkinter)のWindows実行ファイルをクロスコンパイルする

LinuxでPythonコーディングしてWindowsにexeファイルを提供する方法についてまとめる

# Wineのインストール

インストール手順
https://wiki.winehq.org/Ubuntu

```
$ sudo dpkg --add-architecture i386
$ sudo mkdir -pm755 /etc/apt/keyrings
$ sudo wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key
$ sudo wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/jammy/winehq-jammy.sources
$ sudo apt update
$ sudo apt install --install-recommends winehq-stable
```

# PythonをWineにインストール

ここでinstallerをダウンロード
https://www.python.org/downloads/windows/

インストールする。
ダウンロードディレクトリとinstallerファイル名は各自調整
```
$ wine ~/Downloads/python-3.12.1-amd64.exe
```

# Python環境の整備
tkinterのインストール
```
$ wine ~/.wine/drive_c/users/`users`/Local\ Settings/Application\ Data/Programs/Python/Python312/python.exe -m pip install pytk
```
PyInstallerのインストール
```
$ wine ~/.wine/drive_c/users/`users`/Local\ Settings/Application\ Data/Programs/Python/Python312/python.exe -m pip install PyInstaller
```
# GUIサンプル
gui.py
```python
import tkinter

root = tkinter.Tk()
root.title("Sample")
root.geometry("400x400")
root.mainloop()
```


# Windwos向けのexeファイル作成
```
$ wine ~/.wine/drive_c/users/`users`/Local\ Settings/Application\ Data/Programs/Python/Python312/python.exe -m PyInstaller gui.py --onefile --noconsole
```
exeファイル生成の確認
```
$ ls -l dist/
合計 10040
-rwxrwxr-x 1 noxon noxon 10277031  2月  3 20:01 gui.exe
```
Wineで実行
```
$ wine dist/gui.exe
```
【02】Next.js app routerのチュートリアルやってみる(CSSスタイル)

# はじめに

Next.js app routerのチュートリアルの第２章のアウトプットします。

https://nextjs.org/learn/dashboard-app/css-styling

<details><summary>前の記事</summary>

【01】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/af58da3d20cbc790e767

</details>


# 第２章 CSSスタイル

この章では下記を学習しました。

- グローバルＣＳＳをインポートする
- `Tailwind`
- `CSSモジュール`
- `clsx`でクラス名を柔軟に変更する

# グローバルCSSのインポート

グローバルCSSファイルはアプリケーション全体で使用できる必要がある。

その場合は`layout.tsx`でインポートする。

`layout.tsx`は`app router`におけるルートレイアウトと呼ばれるファイルみたいです。

ここに書いたコードはすべてのページで共有されるため、`header`や`footer`といったものはおそらくここに書くのでしょう。

# Tailwind

`Next.js`は`create-next-app`で新しいプロジェクトを作成した場合に`Tailwind`を使うか尋ねられます。

その時に`Yes`を選択しておけば、すぐに`Tailwind`が使える状態になっています。

# CSSモジュール

> 一意のクラス名を自動的に作成することで CSS のスコープをコンポーネントに設定できるため、スタイルの衝突についても心配する必要がなくなります。

だそうです。

私は、`Tailwind`が結構好きですし、この後のコースも`Tailwind`でスタイリングをするみたいなので適当に読み飛ばしました。

# `clsx`でクラス名を柔軟に変更する

条件に基づいて要素のスタイルを設定するしたいという場合があります。

その時に使えるライブラリが`clsx`です。

https://www.npmjs.com/package/clsx

https://github.com/lukeed/clsx

例えば以下のコードでは、`status`で`red`or`blue`を受け取ります。

そして、`div`の`className`の中で条件式を書くことができます。

```jsx
import clsx from 'clsx';

type Status = 'red' | 'blue';

type Props {
  status: Status;
}

export default function Test({ status }: Props) {
  return (
    <div
      className={clsx({
        'bg-red-100': status === 'red',
        'bg-blue-100': status === 'blue',
      })}
    >
      test
    </div>
  );
}

```

`status`が`red`の場合

```jsx:app/page.tsx
<Test status="red" />
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582046/72e45750-923d-d7e9-be11-2d4ddc51a2a0.png)

`status`が`blue`の場合

```jsx:app/page.tsx
<Test status="blue" />
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582046/58293160-f647-9071-1996-494adbf09d3f.png)

# おわりに

まだまだ楽勝ですね！

# 次の記事

https://qiita.com/naoyuki2/items/612221eac233aa9cbb74
中学二年生がAtCoder通知Botを作った話

始めまして、Kangpingです。
最近 AtCoder通知Bot という DiscordBotを作成させていただきました。
[Jikky1618](htpps://atcoder.jp/users/jikky1618) さんが大体の仕様を考えてくれました。ありがたい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2971874/c6fc7eff-8978-40a9-c14c-38de78467d65.png)
↑こういう画像を自動で投稿したりするBotです。当日通知と一時間前通知もあります。(あと精進ポイント通知も)
# 経歴
中学二年生の一般中学生。プログラミングに触れたのは小学一年生の時に始めたプログラミンという文部科学省が作っていたビジュアルプログラミングサイト。そのあとに小学二年生のころにScratchを始めて小学四年生のころに AtCoder を Python ではじめた。現在は Typescript を主に普段使い、AtCoder などの競技プログラミングでは Python を使用している。
# なぜ DiscordBot を作り始めたのか
私が中学一年生のころに Discord を始めて、友達に「DiscordBot作ってみたら」と言われたのがきっかけ。なお、それ以前に SlackBot 作成で CoffeeScript につまずいたことがあったので少し心配だったのが、その当時大量に書いていた Node.js 出かけることがわかり、やってみようと思ったら結構楽しかったのでいろいろな機能を付けていって技術力を上げていった。
# AtCoder通知Bot の作成
AtCoder通知Bot の作成はなんか友達にやれとか言われずに自分でやったので楽しかったです。開発言語は Typescript、Discord.jsを使用しています。一番最初に開発したバージョンは 2023年8月11日にリリースしました。その後、2024年1月23日にすべてのコードを書き直した大規模なアップデートをして今に至ります。
# 使用 API など
## AtCoder
### コンテスト一覧ページ
コンテスト一覧ページを直接 Node.js からたたき [libxmljs](https://www.npmjs.com/package/libxmljs) を使用して解析しています。コンテスト名、URL、レーティングタイプ、コンテスト時間、レーティング範囲などを取得しています
### コンテストランキング
このページは AtCoder アカウントでログインした人しか開けなくなったため、一定時間ごとに AtCoder のアカウントにログインしています。
## AtCoder Problems
### コンテストの diff など
コンテストの diff を取得します。ADL に対応するために [これ](https://kenkoooo.com/atcoder/resources/problem-models.json)だけではなくいろいろ取得しています。一分ごとに diff の変更がないかどうか監視しています
### ユーザーの提出情報
このようなリンクから取得しています。これは精進ランキングを作成するために作成しています。すべての登録されたユーザーに対して行っています。5分ごとにすべてのユーザーのデータを取得しています。
## ac-predictor
### APerf
ランキング昨日のパフォーマンスとレーティングを計算するために使用しています。
# 結論
中学二年生でもがんばれば DiscordBot は作れる。
# リンク
Botの参加リンク:https://discord.com/api/oauth2/authorize?client_id=1140221377174044722&permissions=165888&scope=bot
AtCoder:https://atcoder.jp/
ac-predictor:https://ac-predictor.com/
AtCoderProblems:https://kenkoooo.com/atcoder/
## 最初の画像にいる人たち
maspyさん:https://atcoder.jp/users/maspy/
yukkkuさん:https://atcoder.jp/users/yukkku/
blueberry1001さん:https://atcoder.jp/users/blueberry1001/
kangpingさん:https://atcoder.jp/users/kangping/
Jikky1618さん:https://atcoder.jp/users/jikky1618/
yaakiyuさん:https://atcoder.jp/users/yaakiyu/
ujex256さん:https://atcoder.jp/users/ujex256/
So_teACさん:https://atcoder.jp/users/So_teAC/

# サンプル画像たち
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2971874/2a0b8b0c-2880-a688-b328-949acd9569e4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2971874/693a4269-947f-d8c9-5995-d7a9d8d4a5ba.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2971874/606c917f-092d-d0d6-85cd-5fc323d5dfad.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2971874/910706e5-4c39-11fd-9f66-d32990094861.png)
google_artifact_registry_repositoryにはcleanup_policiesをつけよう!

## 問題

artifact registryにdocker imageをPushしていると開発環境などの古いimageがたまり続けてしまう

## cleanup_policies

> Keep policies work with delete policies to keep artifacts that would be deleted according to the specifications of your delete policy, but that you want to keep. When an artifact matches the criteria for both a delete policy and a keep policy, the artifact is kept.

- keepとdeleteのpoliciesをつける
- keepとdelete両頬うにmatchしたらkeepされる

Ref: https://cloud.google.com/artifact-registry/docs/repositories/cleanup-policy


## terraform例

:::note info
terraform-provider-googleの[v4.80.0](https://github.com/hashicorp/terraform-provider-google/releases/tag/v4.80.0)以降を使う必要がある
:::

```hcl
resource "google_artifact_registry_repository" "my-repo" {
  location      = "us-central1"
  repository_id = "my-repository"
  description   = "example docker repository with cleanup policies"
  format        = "DOCKER"
  cleanup_policy_dry_run = false
  cleanup_policies {
    id     = "delete"
    action = "DELETE"
    condition {
      tag_state  = "ANY"      # default: ANY
      older_than = "2592000s" # 30 days
    }
  }
  cleanup_policies {
    id     = "keep-minimum-versions"
    action = "KEEP"
    most_recent_versions {
      keep_count = 5
    }
  }
}
```

Prefixなどで対象を絞ることも可能

## 既存の repositoryの場合

### 既存のRepoの確認

```
gcloud artifacts repositories list --project $PROJECT --location $REGION
```

### option1: terraform import

`terraform import` でterraform管理に変更することができる。

上のtfファイルを記載してから

```
terraform import google_artifact_registry_repository.my-repo projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}
```

という風に実行する

### option2: import blockを使う

terraform 1.5.0 移行であればhttps://developer.hashicorp.com/terraform/language/import blockが使えるので

```hcl
import {
  id = "projects/${var.project}/locations/${var.region}/repositories/cloud-run-source-deploy"
  to = google_artifact_registry_repository.cloud-run-source-deploy
}
```

などと書いて`terraform plan`するとimportするものと変更を確認できる。

```
Plan: 1 to import, 0 to add, 1 to change, 0 to destroy.
```

## apply

plan結果が、cleanup_policies部分のみの差分になっていることを確認してから`terraform apply`を実行

## Ref
1. https://cloud.google.com/artifact-registry/docs/repositories/cleanup-policy
1. https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/artifact_registry_repository#most_recent_versions
1. https://github.com/hashicorp/terraform-provider-google/issues/13824
1. https://github.com/GoogleCloudPlatform/magic-modules/pull/8671
1. https://github.com/hashicorp/terraform-provider-google/releases/tag/v4.80.0
【SwiftUI】GIFを表示したい

# はじめに
SwiftUIでGIFを使いたかったので使えるようにGIFViewを作ってみました。

# サンプルアプリ
![Simulator Screen Recording - iPhone 15 - 2024-02-03 at 22.40.41.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/c6e49a95-ffc6-857f-7af8-981e43525741.gif)

# 今回使用するGIF
![heart.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/c5cc430a-6af6-986c-afc6-d102f4fd8991.gif)

<a href="https://pixabay.com/ja/users/supergsatb-32809140/?utm_source=link-attribution&utm_medium=referral&utm_campaign=animation&utm_content=10539">SuperGSATB</a>による<a href="https://pixabay.com/ja//?utm_source=link-attribution&utm_medium=referral&utm_campaign=animation&utm_content=10539">Pixabay</a>のGIF

# 実装
```swift
import SwiftUI

struct GIFView: View {
    @State private var images: [Image] = []
    @State private var gifCount: Int = 0
    @State private var currentIndex: Int = 0

    var gifName: String
    var minimumInterval: Double
    
    var body: some View {
        TimelineView(.animation(minimumInterval: minimumInterval)) { context in
            Group {
                if images.isEmpty {
                    Text("エラー")
                } else {
                    images[currentIndex]
                        .resizable()
                        .scaledToFit()
                }
            }
            .onChange(of: context.date) {
                if currentIndex == (gifCount - 1) {
                    currentIndex = 0
                } else {
                    currentIndex += 1
                }
            }
        }
        .onAppear {
            guard let bundleURL = Bundle.main.url(forResource: gifName, withExtension: "gif"),
                  let gifData = try? Data(contentsOf: bundleURL),
                  let source = CGImageSourceCreateWithData(gifData as CFData, nil)
            else {
                return
            }
            gifCount = CGImageSourceGetCount(source)
            var cgImages: [CGImage?] = []
            for i in 0..<gifCount {
                cgImages.append(CGImageSourceCreateImageAtIndex(source, i, nil))
            }
            let uiImages = cgImages.compactMap({ $0 }).map({ UIImage(cgImage: $0) })
            images = uiImages.map({ Image(uiImage: $0) })
        }
    }
}
```

# 使い方
使用したいGIFをXcodeにドラッグします。
![スクリーンショット 2024-02-03 22.42.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/1b675f03-9545-aa11-af47-0439d27cbf59.png)

以下の設定で「Finish」を押します。
![スクリーンショット 2024-02-03 22.43.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/e3e35a45-e713-6839-3d34-61db48b6d7d7.png)

使用側では、
`gifName`はGIFのファイル名、
`minimumInterval`はGIFの1枚の画像にかける秒数
を渡します。
```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        GIFView(gifName: "Heart", minimumInterval: 0.03)
            .frame(width: 300, height: 300)
    }
}
```

# おわり
ロジック部分はもうちょいいい感じにできそうです。
`currentIndex`で表示画像を管理しているのをもうちょい改善したいです。

改善案があれば編集リクエストがコメントください！

# 追記(2024/2/8)
コメントで教えてもらったもっと表示方法です！！

https://qiita.com/SNQ-2001/items/331133f5a8eb92761c03

# 参考コード
https://github.com/kiritmodi2702/GIF-Swift/blob/master/GIF-Swift/iOSDevCenters%2BGIF.swift
Gitコマンド早見表

# はじめに
個人的によく使うGitコマンドをまとめました。
Gitを既に使用している人向けの記事になります。

# 早見表
##### ローカルの変更内容を全てリモートに反映する際に使用するコマンド
```
git add --all
git commit -m “コメント”
git push
```

##### ローカルの変更内容を一部リモートに反映する際に使用するコマンド
```
git add -p
git commit -m “コメント”
git push
```

##### ローカルのステータスを確認する際に使用するコマンド
```
git status
```

##### ローカルの変更内容を確認する際に使用するコマンド
```
git diff
```

##### 現在選択中のブランチを確認する際に使用するコマンド
※--allを追加することにより、リモートのブランチを併せて確認できる。
```
git branch
git branch —all
```

##### ローカルのブランチを切り替える際に使用するコマンド
※-bを追加することにより、ブランチの追加と切替を併せて行うことができる。
```
git checkout develop
git checkout -b develop origin/develop
```

##### ローカルのブランチの変更内容を削除する際に使用するコマンド
```
git checkout .
```

# 最後に
間違いなどありましたら、ご指摘頂けますと幸いです。
【01】Next.js app routerのチュートリアルやってみる(プロジェクトのセットアップ)

# はじめに

今までなんとなく`Next.js`のコードを書いてきましたが、このままではいけないと思い、公式のチュートリアルをやることにしました。

ちゃんと理解しているのかアウトプットするために記事を書かせていただきます。

全部で16章あるので、16この記事を書きます

# チュートリアルについて

https://nextjs.org/learn/dashboard-app

どうやら`ダッシュボードアプリ`を作成しながら`Next.js`を学ぼうという感じみたいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582046/4456eafc-39aa-3e2b-02c3-7f320bba542b.png)

- ホームページ
- ログインページ
- ログイン後にアクセスできるダッシュボードページ
- CRUD操作

以上の機能を備えたダッシュボードみたいです。

`データベース`もあるフルスタック`Next.jsアプリ`ということですね。

# 第１章 はじめる

https://nextjs.org/learn/dashboard-app/getting-started

ひな形が用意されているらしくそれを`npm`経由でインストールするみたいです。

ひな形の時点で結構コーディングされているみたいですね。

# おわりに

次の章から実際にコーディングを進めていきましょう！

# 次の記事

https://qiita.com/naoyuki2/items/edf450b3ee135e83d1e8
C#のnull許容型を処理する方法メモ

#### はじめに
C#でNull許容型の変数をNull非許容に変換し、エラーや警告を回避する方法として認識しているもののメモを残したいと思います。
この記事内ではC#12.0を使用しています。

+ #### [Nullableを処理する](#nullableを処理する-1)
    + [isで変換する](#isで変換する)
    + [switch式で処理する](#switch式で処理する)
    + [null合体演算子で別の値を入れる](#null合体演算子で別の値を入れる)
    + [ロジックで除く](#ロジックで除く)
+ #### [Nullableのプロパティ、メソッドにアクセスする](#nullableのプロパティメソッドにアクセスする-1)

## Nullableを処理する
##### isで変換する
```csharp:isで変換する
void TestMethod(ClassA? nullableValue){
    if(nullableValue is ClassA value){
        //valueにnullableValueの値が入る
        value.MethodA();
    }
    else{
        //nullableValue = nullの時の処理
        throw new Exception("nullableValue is null");
    }
}
```
変数(null許容) is 型(null非許容)とするとで値が入っている場合trueを返せます。後ろに変数名を付けると値が代入された状態のnull非許容の変数を宣言することができます。


##### switch式で処理する
```csharp:switch式で処理する
void TestMethod(Int? number){
     var text = number switch
     {
         1 => "one", //case 1
         2 => "two", //case 2
         null => throw new Exception("is null") , //nullの場合も普通の値と同様に書ける
         _ => throw new Exception("out of range") //default
     };
}
```
switch式(パターンマッチング)でnullのパターンを記述できるのでnullの時にnullを返さないようにすればnull非許容に変換できます。


##### null合体演算子で別の値を入れる

```csharp:null合体演算子??
void TestMethod(string? nullableText){
    string textValue = nullableText ?? "";//nullの場合右辺を代入する
    nullableText ??= "";//=をつけて同じ変数に代入することもできる
}
```
null合体演算子??を使うとnullの場合は別の値を代入することができます。
??=は変数の型が変わらないので個人的にあまり好みではありませんが…

#### ロジックで除く
```csharp:ロジックで除く
private void TestMethod(ClassA? nullableValue){
    nullableValue.MethodA();  //こちらは警告,エラーが発生する

    if(nullableValue is null)throw new Exception("nallableValue is null");
    nullableValue.MethodA();  //こちらは警告,エラーは発生しない
}
```
ロジックでnullをである可能性を排除すればnull許容型のプロパティにアクセスしてもエラーが発生しません。
多分コンパイラがうまく読み取ってくれているんだと思います便利ですね。個人的には同じ書き方でも文脈で状態が変わるのが気持ち悪くてあまり使いません。

## Nullableのプロパティ、メソッドにアクセスする
```csharp:null条件演算子?.
void TestMethod(ClassA? nullableValue){
    //Nullableな変数のプロパティにアクセスする
    var nullableProperty = nullableValue?.Property; //nullableValue=nullの時はnullが入る
    
    //Nullableな変数のメソッドにアクセスする
    nullableValue?.Method(); //nullableValue = nullの時は実行されない
}
```
null条件演算子?.を使うとプロパティ、メソッドにアクセスするときのNull例外を防ぐことができます。
プロパティの場合は後ろにさらにnull合体演算子をつけてnullの場合の値を記述することもできます。
メソッドの方はnullの時は何もしないということが少ないのであまり使わない気がします。

#### おわりに
Null許容型はすごく便利ですが何もわからずに適当に使おうとすると今まで使えていたコードがエラーになって嫌いになってしまいやすい文法でもあります。しっかり使い方を学んでNull例外を駆逐していきましょう。

そんな書き方しねーよ、なんでこの記法書いてねーんだよ等ありましたらぜひ教えてください。
ネットワークモデルと対応するプロトコル

|OSI 7層モデル|TCP/IP 5層モデル|対応するプロトコル|
|---|---|---|
|アプリケーション層|アプリケーション層|HTTP, TFTP, FTP, NFS, WAIS, SMTP, Telnet, DNS, SNMP|
|プレゼンテーション層|アプリケーション層|TIFF, GIF, JPEG, PICT|
|セッション層|アプリケーション層|RPC, SQL, NFS, NetBIOS, names, AppleTalk|
|トランスポート層|トランスポート層|TCP, UDP, QUIC|
|ネットワーク層|インターネット層|IP, ICMP, ARP, RARP, RIP, IPX|
|データリンク層|データリンク層|FDDI, Frame Relay, HDLC, SLIP, PPP|
|物理層|物理層|EIA/TIA-232, EIA/TIA-499, V.35, 802.3|
Bitnami WordPress のインスタンスバージョンアップ手順

基本公式ドキュメントに従えばいい。
https://docs.bitnami.com/aws/how-to/migrate-wordpress/#migrate-data-from-one-wordpress-instance-to-another

:::note warn
警告
All in one wp migration の無料版はローカルファイルのアップロードしか対応していない
:::

# おおまかな手順

1. All in one wp migraiton にてバックアップを作成、ローカルにダウンロードしておく（数GBになることもあるので注意）
1. Lightsail のインスタンスを新しく作成し WordPress を選択する（この時点で最新版になる）
1. PHP や WordPress の設定を書き換えてアップロード上限に抵触しないようにしておく
1. 新しいインスタンスにバックアップをリストアする。ダウンロードしたファイルをアップロードする
1. lets encrypt を利用している場合は crontab あるいは systemd timer が設定されていることを確認する
1. 動作確認用のサブドメインを用意(DNS)し、最終確認する（DNSのレコードTTLは短くしておく）
1. 問題なければ DNS の設定を書き換える


## PHP や WordPress の設定を書き換えてアップロード上限に抵触しないようにしておく

- `sudo apt install silversearcher-ag` で ag をインストール
- post_max_size などで検索。 `/home/bitnami/stack/php/etc/php.ini` を編集
- post_max_size, upload_max_filesize, memory_limit, max_execution_time, max_input_time を同じように見つけ編集
- 最後に `sudo systemctl restart bitnami`
ITILv4から始めるITマネジメント

# はじめに
マネジメント系の資格を取る機会ができたので最初のステップとしてITIL(v4)について勉強していきます。

# 目次
1. [ITILファンデーション(v4)とは](#Chapter1)
2. [マネジメント系の資格](#Chapter2)

# ITILファンデーション(v4)とは
<a id="Chapter1"></a>
ITIL（Information Technology Infrastructure Library) V4は主にITサービスマネジメントの価値といったマネジメント系の資格になります。サービスマネジメントはサービスの改善やコストの削減があたります。
v4とつくだけに従来ではv3でしたが最新バージョンのv4へと変更になります。

# マネジメント系の資格
<a id="Chapter2"></a>
ITIL(v4)の上位資格としてプロジェクトマネージャ資格、ITサービスマネージャ資格があります。
プロジェクトマネージャ資格はIPA（独立行政法人情報処理推進機構）が実施する国家試験である「情報処理技術者試験」の一つです。	
プロジェクトマネジメントの知識・スキルを主に扱う資格です。予算、工程、品質などを管理し、プロジェクトを円滑に進める役割を担います。

ITサービスマネージャ資格はIPA（独立行政法人情報処理推進機構）が実施する国家試験である「情報処理技術者試験」の一つです。	
サービスマネージャ資格ではシステムの導入や維持・拡張のほか、システムの管理方法、情報セキュリティといった安全性と信頼性の高いサービス提供を行います。

### 二つの資格の違い
プロジェクトマネージャ資格とITサービスマネージャ資格の違いとしてプロジェクトマネージャ資格はシステムを新規に作り上げる際や保守開発業務のプロジェクトマネジメント。
ITサービスマネージャは本番稼働した後のシステム運用保守業務があたります。
	
# 最後に
プロジェクトマネージャ資格とITサービスマネージャ資格はどちらもマネジメント系の資格ですが内容が異なるため自分が今後どういったマネジメントをしたいかによって変わってくるので先に進路を決めておくことでぶれることがなくなると思います。
LightSail や VPS でいろいろやるときに便利なツール

LightSail などのメンテナンスで活躍しているツールやサービスたちをまとめる。

* piping server: ファイルの受け渡しで使う。僕はよく https://ppng.io を使う。拡張子までしっかりつけてあげると便利。あと他人が待ち受けているとやばいので `uuid/name.{ext}` のような感じで UUID 使うといい
* cloudflared: なんらかの理由でサーバーにトンネルして tcp 接続したいときに使う。実はアカウントなくても使える(そういう意味で ngrok よりも便利)
* ag(silver searcher): ファイルの中身を探索するときに使う。upload_max_filesizeとか探す
* caddy file-server: サーバーの中にある画像や動画ファイルをみるときにつかう
* rclone: データの受け渡しで使う。しばらくおいておく必要があるときにつかう。rclone config で設定できるが rclone config はインタラクティブすぎるので ~/.config/rclone/rclone.conf を piping server で送受信すると快適
* goofys: rclone よりも頻繁にデータやりとりが必要なときに使う。オペレーションに課金が走らない Wasabi がおすすめ。
* screen/tmux: ssh 接続が切断されたときにもプロセスがしなないのでおすすめ。nohup で頑張るよりもはるかにらく。
SpringBoot Mybatis 起動時に factoryBeanObjectType エラー

# 起動時に以下のエラーが発生
java.lang.IllegalArgumentException: Invalid value type for attribute 'factoryBeanObjectType': java.lang.String

# 原因
たぶん、Mybatisのバージョンが環境に合わないのが原因
（バグなのか？）

# 対処
バージョンを変えてみる
~~~エラーになったバージョン.
		<dependency>
		    <groupId>org.mybatis.spring.boot</groupId>
		    <artifactId>mybatis-spring-boot-starter</artifactId>
		    <version>3.0.2</version>
		</dependency>
~~~
~~~解決したバージョン.
		<dependency>
		    <groupId>org.mybatis.spring.boot</groupId>
		    <artifactId>mybatis-spring-boot-starter</artifactId>
		    <version>3.0.3</version>
		</dependency>
~~~
お試しあれ
Jetpack Compose + HiltでViewModel生成時にパラメータを渡す

# 概要

HiltはAndroidで公式に推奨されているDIライブラリです。[Dagger 2.49](https://github.com/google/dagger/releases/tag/dagger-2.49)で可能になった、ViewModel生成時に引数を動的に渡す方法（Assisted Injection）と、Jetpack Composeでの使用方法をまとめます。

# Hiltの基本的な使い方

Hiltを使うと、依存関係はHiltが解決して生成してくれるので、ViewModelを生成する時に引数を渡す必要がありません。

```kotlin
@HiltViewModel
class MyViewModel @Inject constructor(
    private val repository: MyRepository// 依存オブジェクト
): ViewModel() {
    ...
}

@Composable
fun MyView(
    viewModel: MyViewModel = hiltViewModel()//引数を指定しなくていい
) {
    ...
}
```

しかし、ViewModelに追加のパラメータを渡したいとき、このような書き方はできません。

```kotlin
@HiltViewModel
class MyViewModel @Inject constructor(
    private val id: String,//　画面ごとに異なるID
    private val repository: MyRepository
): ViewModel() {
    ...
}

@Composable
fun MyView(
    viewModel: MyViewModel = hiltViewModel("id")// NG!
) {
    ...
}
```
そのため、SavedHandleStateを経由してパラメータを渡す方法などがありました。その場合、パラメータの受け渡しが散らばり、見通しが悪くなるという問題がありました。

# Assisted　Injection

Assisted InjectionはDIコンテナが管理していないパラメータを生成時に渡す方法です。ViewModelでAssisted Injectionを使うには問題がありましたが、[Dagger 2.49](https://github.com/google/dagger/releases/tag/dagger-2.49)で使えるようになりました。Jetpack Composeのための拡張は[1.2.0-alpha01](https://developer.android.com/jetpack/androidx/releases/hilt#1.2.0-alpha01)以降で対応しています。

```kotlin:build.gradle.kts
dependencies {
    ...
    implementation("androidx.hilt:hilt-navigation-compose:1.2.0-beta01")
    implementation("com.google.dagger:hilt-android:2.50")
    kapt("com.google.dagger:hilt-android-compiler:2.50")
    ...
}
```

ViewModelでAssisted Injectionを使うには、`@Inject`のかわりに`@AssistedInject`を使い、追加で渡したい引数に`@Assisted`を付けます。

```kotlin
@HiltViewModel(assistedFactory = MyViewModelFactory::class)
class MyViewModel @AssistedInject constructor(
    @Assisted private val id: String,
    private val repository: MyRepository
): ViewModel() {
    ...
}
```
次にFactoryを定義します。Assistedなパラメータを引数に取る関数を定義するだけです。

```kotlin
@AssistedFactory
interface MyViewModelFactory {
    fun create(id: String) : MyViewModel
}
```

こうして、引数を渡してViewModelを生成することができます。`hiltViewModel()`に生成時コールバックが追加されています。

```kotlin
@Composable
fun Screen() {
    val viewModel = hiltViewModel(
        creationCallback = { factory: MyViewModelFactory ->
            factory.create("id")
        }
    )
    MyView(viewModel)
}
```

# まとめ

SavedStateHandleに比べて、ViewModelにパラメータを渡すのが簡単になりました。
画面ごとに異なるパラメータを動的にViewModelに渡したい時は使えそうです。

# 参考
- https://qiita.com/Horie1024/items/d2c4e8c79e40ea88fcfc
- https://medium.com/@alexander.michaud/hiltviewmodel-assisted-injection-with-compose-a800723165bf
- https://dagger.dev/dev-guide/assisted-injection
- https://dagger.dev/hilt/view-model.html
資格の勉強のフレームワーク

# 前置き
最近資格勉強をすることが多いので
これするとよかったなー　とかを方法論としてまとめておきます。

# 目次
1. 参考書付き問題集と過去問を用意する
1. 過去問を解く
1. 参考書付き問題集を進める
1. 過去問を解く

## 参考書と過去問付き問題集を用意する
当然ですが勉強するためのツールが必要です。
参考書付き問題集を用意します。
参考書付き問題集:勉強のインプットとアウトプットとして使います
過去問:適宜の確認として使います。
いつから：テスト勉強開始時

## 過去問を解く
過去問を解きます。
たいてい合格点をとれませんが、
1. 実際の試験の雰囲気を把握する
1. 問題傾向を把握する
ことが目的です。
いつから：テスト勉強開始から１週間後

## 参考書付き問題集を進める
参考書付き問題集を進めていきます。
詰まることもあると思いますが、軽い気持ちで飛ばしてしまいましょう。
参考書ぶぶんを読んで学んだところを問題集部分で解いていきます。
3週くらいしてます。
浅い勉強を何回も繰り返すイメージ。
いつから：テスト勉強開始から２週間後

## 過去問を解く
最後の仕上げとして過去問を解きましょう。
３年分くらいかな
いつから：テスト前１週間
特定のPCでVisual StudioのC++ファイルをShift-JISとして読み取ってくれない

## 事象

Visual StudioでShift-JISとして保存されたC++ソースコードがShift-JISとして開かれず文字化けする。

## 解決方法（結論）

コントロールパネル→時計と地域→地域→管理→システムロケールの変更　で「日本語（日本）」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067155/c7c67bae-7560-ccda-6aec-56b0d7617f30.png)

## 背景・経緯

TwinCAT/C++の開発を行うのにVisual Studio 2019を使用していますが、Visual StudioではデフォルトのままC++ファイルを作成し、日本語のコメントなどを含んで保存するとShif-JISとして保存されます。

このShift-JISで保存されたファイルについて、普段開発しているPCでは問題なくShift-JISとして開かれるのですが、Beckhoff製IPCで開くと自動で文字コードを認識してくれず、文字化けしてしまう事象がありました。

ソースファイルを右クリックしてOpen with→C++ Source Code Editor (with encoding)でShift-JISを指定すれば文字化けせずに開けるのですが、毎回この操作でソースファイルを開くことはかなり効率が悪いです。

該当PCはWindowsの初期設定が英語だったため、Windowsの表示言語を日本語にしたり、Visual Studioの表示言語を日本語にしても変わりません。

いっそのこと[BlueSilverCatさんの記事など](https://qiita.com/BlueSilverCat/items/1e5af7fdaeaf8fd2289d)を参考にC++のデフォルトエンコーディングをUTF-8にしてしまおうかと思いましたが、設定が面倒で、またPC毎に設定する必要があるのもミスが起きそうで避けたかったです。

色々試行錯誤した結果、上記の解決方法の方法で解決できました。数時間格闘していました。。
システムロケールの設定の存在を初めて知り、Windowsについて少しだけ詳しく慣れた気がします。
というかWindowsは脱コントロールパネルしようとしているはずですが、未だにこの設定などはコントロールパネルからしかできない？

この問題が解決するまではコメントを英語で書いていたりしましたが、GitHubで公開するわけでもないソースは、パッと読んで理解するためにも、コメントを書く時間を節約するためにも（英文を書こうと思うと時間がかかる）、やっぱり日本語でコメントは書きたいです。
Java21で正式リリースの Virtual Thread を使ってみた(その1)

Java19でプレビュー、Java21で正式リリースとなった Virtual Thread（仮想スレッド）を使ってみた。ラムダ式とやらは使ったことないので、理解の複雑化回避のためあえて使わずに。

```java: ThreadExecutor.java
package pkg;

public class ThreadExecutor {
	
	public static void main(String[] args) throws InterruptedException {

		MyRunnable runnable = new MyRunnable();
		
		// プラットフォームスレッドとして実行する場合(従来からのスレッド)
		Thread pthread = Thread.ofPlatform().start(runnable);
		System.out.println("pthread is Virtual ? : " + pthread.isVirtual());
		// なんとなく、スレッドが終了するまで待つ
		pthread.join();
		
		// 仮想スレッドとして実行する場合（新しいスレッド）
		Thread vthread = Thread.ofVirtual().start(runnable);
		System.out.println("vthread is Virthal ? : " + vthread.isVirtual());
		// なんとなく、スレッドが終了するまで待つ
		vthread.join();
	}
}

/**
 * スレッドで実行したい処理
 */
class MyRunnable implements Runnable {

	@Override
	public void run() {
		System.out.println("--> I am Thread. I am Virtual ? : "
			+ Thread.currentThread().isVirtual());
	}
}
```

```shell: 実行結果
C:\>java -version
java version "21" 2023-09-19 LTS
Java(TM) SE Runtime Environment (build 21+35-LTS-2513)
Java HotSpot(TM) 64-Bit Server VM (build 21+35-LTS-2513, mixed mode, sharing)

C:\>java pkg\ThreadExecutor.java
pthread is Virtual ? : false
--> I am Thread. I am Virtual ? : false
vthread is Virthal ? : true
--> I am Thread. I am Virtual ? : true

```

なるほど。
辞書式ソート

https://paiza.jp/works/mondai/c_rank_level_up_problems/c_rank_sort_step3

うんつまりどういう意味じゃ？
と思ったのですが、
結局のところ降順に並べ替えるとこの問題の条件通りのソートになるということです。
ソートの仕様がそうなっている、という話ですね。
念のためソートの仕様を確認しておきます。

仕様がわからんかったら、やっぱり知ってる関数を試してちゃんと条件通りになっているか
確認してみるのがよいですね。

```py
n = int(input())
ab = [None] * n
for i in range(n):
    [a, b] = map(int,input().split())
    ab[i] = [a, b]
ab.sort(reverse=True)
for i in range(n):
    print(*ab[i])
```
【KMP】Android Gradle plugin requires Java 17 to run. You are currently using Java 11.

## はじめに

 Kotlin Multiplatform の[チュートリアル](https://www.jetbrains.com/help/kotlin-multiplatform-dev/multiplatform-update-ui.html)をやっている際、iosApp.xcodeproj を Xcode で開いて **Xcode 上でビルドを実行する** と以下のエラーが発生した。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494458/b766fd26-da89-069a-2866-b0b6a53a65f4.png" alt="" width="500">

エラーの詳細を見てみる。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494458/fa4defd2-4c3a-ce99-0c76-29aba7fc34f0.png" alt="" width="500">

エラーの通り Java 11 でビルドしているようだ
Android Studio の JDK のパス設定を確認すると Java 17 になっているのだが、なぜ？

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494458/165f2d85-64f2-f5ca-125a-c8219c98ec69.png" alt="" width="700">


因みに、 Android Studio でビルドすると成功する。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494458/6e9e33a8-f3fc-ce3f-ef47-7cd4257fdf6b.png" alt="" width="400">  

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494458/aeb3360a-826f-f8fa-2af3-41c328eb8963.png" alt="" width="400">

また、JDK のパス設定は Java 17 になっている。

```shell
$ echo $JAVA_HOME 
/Applications/Android Studio.app/Contents/jbr/Contents/Home
$ java -version
openjdk version "17.0.7" 2023-04-18
OpenJDK Runtime Environment (build 17.0.7+0-17.0.7b1000.6-10550314)
OpenJDK 64-Bit Server VM (build 17.0.7+0-17.0.7b1000.6-10550314, mixed mode)
```


Android Studio のバージョンは `Hedgehog | 2023.1.1 Patch 1`。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494458/eda40eb0-927d-f4dd-88ee-cde7cc47213f.png" alt="" width="400">


## Xcode に JDK のパスを設定することで解決

Xcode の `Settings - Locations` に `JAVA_HOME` のパスを設定するとビルドに成功し、エラーが解決した。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494458/2f66181f-bc35-f36a-8ce5-ea7b23419784.png" alt="" width="500">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494458/5d2b64b8-5084-a9aa-3de5-4c11c559dc1f.png" alt="" width="500">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494458/95a2d2e6-5e1d-f9c1-bce1-7e18bf9e7bca.png" alt="" width="250">

## 補足

本記事は以下の Slack チャネルを参考にしている。

https://slack-chats.kotlinlang.org/t/10376978/hi-i-am-using-kotlin-multiplatform-to-build-ios-android-app-
【2024年版】Qiitaのはじめかた【アカウント登録~記事投稿】

# 目次
- 概要
- アカウント登録
- 記事作成
- 記事作成~公開時にみるメモ
- まとめ
# 概要
Qiitaを始める際にこれをみればアカウント登録から記事の投稿までできるという記事を丁寧かつ簡潔にまとめます。

自分が今後記事を作成する際の備忘録的なメモにもしたい。

# アカウント登録
特に難しいことはないですが、Qiitaにアクセスし右上の新規登録ボタンをクリック。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691448/b241f793-0d30-b213-3a62-160fe2ca73b5.png)

任意の方法でアカウント登録をします。
私は右欄からメールアドレスで登録しました。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691448/d5250942-4d8e-21bb-17ba-512520253c83.png)

メールアドレスで登録すると認証用のメールが来るのでリンクを踏んで登録完了！
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691448/83624c44-368f-b293-2189-70f3d3e60dcb.png)

# 記事作成
Qiitaログイン後右上の投稿するボタンから記事を新規作成を選択します。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691448/f5d55428-6ef2-c44e-c508-ff918f91e784.png)
すると以下の画面に遷移するので好きに書いて投稿！
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691448/a86aa1e3-6464-1335-a1dd-58494e9140ab.png)

# 記事作成~公開時にみるメモ
## はじめに読んでおくもの
とはいえ何をどう書けばいいの？という感じだと思うので、とりあえず以下を読みましょう。
[良い記事を書くためのガイドライン](https://help.qiita.com/ja/articles/qiita-article-guideline)

## 記法について
QiitaはMarkDown記法が使用できます。
MarkDownとは
>Markdown（マークダウン）は、文書を記述するための軽量マークアップ言語のひとつである。本来はプレーンテキスト形式で手軽に書いた文書からHTMLを生成するために開発されたものである。しかし、現在ではHTMLのほかパワーポイント形式やLATEX形式のファイルへ変換するソフトウェア（コンバータ）も開発されている。各コンバータの開発者によって多様な拡張が施されるため、各種の方言が存在する。

MarkDown記法を全く使用したことがない、ﾅﾆｿﾚｵｲｼｲﾉという人は以下等を読みましょう。
[Markdown記法 サンプル集](https://qiita.com/tbpgr/items/989c6badefff69377da7)

ざっと目を通したらよく分かっていなくても一度使ってみるとよいと思います。

ちなみにこの記事はこんな感じで書いています。
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691448/e38ff5fb-3e62-682b-fceb-bbe15cbb9a69.png)

## 気をつけること
まめに下書き保存！
長文書いたあと消えると萎えます。
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691448/f30a557a-eaa8-3364-198a-114cb5ffdd32.png)

## 記事ができたら
公開設定ボタンをクリック。
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691448/da11cb49-a1cf-867a-e6a9-1f7ab6691ae7.png)

利用規約とプライバシーポリシーを熟読し、問題なければチェック。
公開範囲を設定して、右上のボタンから記事を公開！
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691448/1e1e53ac-9e58-2aeb-d13a-7234508acd1c.png)

# まとめ
上記をみればアカウント登録から記事を公開するまでの流れがイメージできたかと思います。

私自身も記事の投稿方法が分かったので続けて投稿していきたいと思います。
[Palworld] SteamCMD（Windows）版パルワールドサーバーにおけるセーブデータの移行方法

:::note alert
「キャラIDによるデータ管理」が理解できない人はブラウザバックでお願いします。
尚、ご理解いただけているとは思いますが、**at your own risk**です。
当方は一切の責任を負いません。

「理解はできないけれど、どうしてもセーブデータの移行がしたい」という方は、有志の方が公開されている下記スクリプトで行うとよいでしょう。
https://github.com/xNul/palworld-host-save-fix
:::

# なぜ書こうと思ったのか？
ネットを検索すれば数多くのセーブデータ移行方法が見つかるが、WindowsのSteamCMD版Palworldサーバーにおけるセーブデータの移行については記事が無い。
また専用サーバーやレンタルサーバーでの方法では移行出来なかったので、私が実際に行い移行に成功した方法を書いておくことにした。

# 下準備
1. 移行先のWindowsマシンにSteamCMDをインストール
1. SteamCMDからPalworldのサーバーをインストール
    ```cmd
    login anonymous
    force_install_dir "d:\pal-server"
    app_update 2394010
    ```
1. サーバーを起動し、クライアントから接続＋新規キャラを作成する
1. サーバーを停止する

    :::note
    この時に作成した新規キャラのファイル名をメモしておく。

# 移行元のセーブデータ修正
1. 有志が作ったセーブデータ変換ツールをダウンロード（要Python実行環境）
    https://github.com/cheahjs/palworld-save-tools
1. 移行元のLevel.savとキャラクターのsavファイルを上記ツールでjsonに変換する
   
   :::note
   不慮の事故を防ぐため、ファイルをどこかに一度退避して、退避先のファイルで変換しましょう
   :::
   
1. 変換後のLevel.sav.jsonを開き、移行元のキャラデータのファイル名頭8文字の16進数を、上記下準備で作成した新規キャラの同8文字に置換する

   :::note
   この時、英字は小文字にしておくこと（9D5E2D92 -> 9d5e2d92）
   :::
   :::note warn
   jsonファイルが数百MBとなっているので、メモリ展開型テキストエディタで開かないとこの置換作業で詰む。
   SubLime Textなら可能。VSCodeは「置換できません」となるので注意。
   :::
   :::note alert
   キャラで生産したテクノロジーやパルの所有権にキャラIDが記述されているため、この置換は1000個以上になる。
   さらに複数人でサーバーを使っていた場合、この作業をキャラクターの人数分繰り返す必要がある。
   コーヒーでも飲みながら気長にやりましょう。
   :::

1. 同様にキャラデータのjsonファイル内のキャラIDも置換する（2か所）
1. 再度変換ツールを使いjsonファイルをsavファイルに変換する

# 移行作業
1. 移行元の```PalWorldSettings.ini```を移行先にコピーする
1. 移行先の```GameUserSettings.ini```を開き、```DedicatedServerName```を移行元のIDに置き換える
1. 移行元のSaveGamesフォルダを移行先にコピーする
1. 移行先のLevel.savを上記で編集したLevel.savに置き換える
1. 編集したキャラクターファイルを移行先にコピーする。移行先にある移行元のキャラクターファイルは消しておく
1. サーバーを起動、接続しキャラ＆環境が移行出来ていることを確認する


以上になります。お疲れさまでした。



<details><summary>余談</summary>
おそらく、WindowsのSteamCMD版サーバーのバグか、Windows固有の問題かと推測される。
Linux版だとキャラデータを見て、既にある場合はそのIDを使用するが、Windows版は問答無用で新IDの取得からワールドを読み込んでいるようだ。
なのでそのままコピーでは既存IDが使えず、どうやっても新IDのキャラクター作成になってしまっているのだろう。
新IDなのでLevel.sav内に記述してあるワールド内の物（建物や捕獲済みのパル）は使用することができない。
</details>
npm install —save-devオプションの意味

npmを使用してマークダウンを使って職務経歴書を作成している
そこで、参考にさせて頂いている下記の記事中でtextlintを使用すると良いと学んだ

https://zenn.dev/ryo_kawamata/articles/resume-on-github

installのコマンドを見た時に、疑問が湧いた

```
$ npm install --save-dev textlint
```


--save-devってなんだっけ？

前にも調べたことがあった気がしたが、完全に忘れていた。
なので、もう一度調べてみた。


## どういうときに—save-devするのか?

このオプションの有無で何が変わるのか？

を考えるとその存在意義が分かりやすかった。

このオプションは、
package.jsonに記載される依存関係が、
devDependenciesになるか？Dependenciesになるか？の違いを生み出す。


開発用のパッケージか、実行用のパッケージか分けられる。

当然開発していれば、これらを分離したいと思うのは当たり前だ。

特にLinterなんて、アプリケーションを動かす実行環境には必要ない。

こうした機能が存在するのは、ごく当たり前で自然な事だろう。

これでもう忘れないはず。

## 参考記事
https://zenn.dev/ryo_kawamata/articles/resume-on-github

https://qiita.com/kohecchi/items/092fcbc490a249a2d05c
STM32C011でPA8ハードウェアシリアルで遊ぶ。(STM32C011J4M7)


目的
シリアルのテスト


![o_cop921.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/49c08d78-b292-da4c-fee7-fe46c30946ad.jpeg)



```c++


//GPIO_PC14_C011_1




//初期化
void setup() {

  //シリアルの初期化
  //Serial.setTx(PA2_ALT1);
  //  Serial.setTx(PB7_ALT1);
  //  Serial.setRx(PB7_ALT1);
  Serial.setTx(PA8);
  Serial.setHalfDuplex();
  Serial.begin(9600);


  //ピンの初期化 PB8
  pinMode(PB7, OUTPUT);

} //setup


//メインループ
void loop() {

  //文字を出力
  Serial.print("A");

  //PB7をオン
  digitalWrite(PB7, HIGH);

  delay(1000); //1秒待つ

  //PB7をオフ
  digitalWrite(PB7, LOW);

  delay(1000); //1秒待つ

} //loop

```
電子工作で使う圧着端子の種類

コネクタ　ピッチ　容量
ZH 1.5mm 50V1A
PH 2.0mm 100V2A
PA 2.0mm 250V3A
EH 2.5mm 250V3A
XH 2.5mm 250V3A
NH 2.5mm 250V3A
VH 3.96mm 250V10A

詳しくはここ↓
参考　https://xn--p8jqu4215bemxd.com/archives/397#i-vh
[画像処理]画像の補間について図を用いて説明する(最近傍補間、バイリニア補間)

# はじめに
Pillowで画像の拡大縮小や回転を行う際、resampleという引数を指定することができる。例えば、以下のようなコードである。

```python
image = Image.open("hogehoge")
rotated_image = image.rotate(angle=45, resample=Image.BICUBIC)
```

resampleは、画像の補間方法を指定することができる引数である。今回は画像の補間とは何なのか、補間の方法にはどんなものがあるのかをまとめたいと思う。

# 画像の補間とは
画像の補間とは、既存の画像を基にして新しい画像を生成するプロセスである。例えば、画像の拡大は元の画像を基にしてサイズの大きい新しい画像を生成している。画像を拡大する際、元の画像になかった画素が生成される。そのため新たに生成された画素にどのような画素値を入れるか考える必要がある。(添付画像のA, Bは拡大することで新たに生まれた画素)
![スクリーンショット 2024-01-28 224554.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324032/a8abcd42-dd14-3e00-f1d2-e90cea2990d7.png)

画像を縮小する場合は、画素が減少するが既存の画素からどのような画素値を入れるか検討する必要がある。
![スクリーンショット 2024-01-28 230619.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324032/688cdb64-a0cf-523d-28f3-d4b104341844.png)

このように既存の画像から新しい画像を生成するプロセスが補間であり、補間にはいくつかの方法が存在する。以降は補間の方法について説明する。

# 補間のアルゴリズム詳細
本記事では補間方法の中でも、最近傍補間、バイリニア補間について解説する。

## 最近傍補間
画像を拡大、縮小、回転した時に元画像の最近傍にある画素値をそのまま使用する方法である。単純なアルゴリズムなので処理が早いが画質が劣化しやすいという特徴がある。

### 拡大、縮小する場合
元画像のある座標における画素値を $I$ ,補間後の画像の画素値を$I'$、拡大率を$α$とすると補間は下式で実施される。

$$
I'(x', y') = I([\frac{x}{α}], [\frac{y}{α}])
$$

[]は四捨五入を意味する。
拡大の具体例を示す。例えば、ある画像を1.5倍に拡大する場合、補間された画像の(2, 3)の座標に当たる画素値は、元の画像の$([\frac{2}{1.5}], [\frac{3}{1.5}])=(1,2)$の座標の画素値を使用することになる。

### 回転する場合
$(x', y')$が回転後の座標とすると、回転元の座標$(x, y)$から下式で参照される。

$$
\begin{equation}
    \begin{bmatrix}
    x' \\\ y'
    \end{bmatrix}
    = \begin{bmatrix} cos\theta & -sin\theta \\\ sin\theta & cos\theta \end{bmatrix} \begin{bmatrix} x \\\ y \end{bmatrix}
\end{equation}
$$

$\begin{bmatrix} cos\theta & -sin\theta \\\ sin\theta & cos\theta \end{bmatrix}$は回転行列であり、任意の点を$\theta$だけ回転した位置に移動させる。回転行列がなぜこのような形になるのかについては、こちらの動画がわかりやすかったので、詳しく知りたい方はこちらの動画をご覧ください。

https://youtu.be/qyviaCFxg_Q?si=m79sWozMS58IgH6p

## バイリニア補間
バイリニア補間は、4つの画素値を用いて補間する画素の画素値を求める方法である。手順は下記の通り。

### 拡大縮小の場合

1. 変換後の座標$(x', y')$を拡大率$α$で割り、$(\frac{x'}{α}, \frac{y'}{α})$を求める
2. $(\frac{x'}{α}, \frac{y'}{α})$の小数部を切り捨てることで、$(x,y)$を得る
3. $(x,y), (x+1,y), (x,y+1), (x+1,y+1)$とすることで、周囲4画素を得る
4. $(\frac{x'}{α}, \frac{y'}{α})$との距離が大きくなるほど値が小さくなるように加重平均を算出し、変換後の画素値とする(下式)


```math
\begin{align}
\displaylines{
I(x',y') =& (1-dx)(1-dy)I(x,y) + dx(1-dy)I(x+1, y) \\ 
&+ (1-dx)dyI(x,y+1) + dxdyI(x+1,y+1)
}
\end{align}
```


![スクリーンショット 2024-02-03 160736.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324032/aa62cf7e-c00d-2a1e-ce05-4e0089e3610e.png)

### 回転の場合
回転の場合も、拡大縮小の場合とほぼ同じ手順である。拡大縮小の場合は、拡大率$α$を用いて、周囲4点の画素を求めたが、回転の場合は回転行列を用いる点が異なる。

# 終わりに
代表的な画像の補間方法について解説した。画像の補間方法によって変換のスピードや画質に影響が出るため、それぞれの補間方法の特性を把握しておきたいと思った。本記事が皆さんの理解の一助になると嬉しく思う。


# 参考

https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=1409828
Packet Tracer で使える CLI のショートカット

公式な内容ではありません。自分で試してわかった内容です。

■削除系
Ctrl + n    すべてを消す
Ctrl + w    カーソルの左側をスペースまで消す
Ctrl + k    カーソルの右側を一気に消す
Ctrl + x    カーソルの左側を一気に消す
Ctrl + u    カーソルの左側を一気に消す
Ctrl + d    カーソルの右側を一個ずつ消す
Ctrl + h    カーソルの左側を一個ずつ消す

■移動系
Ctrl + a    行頭に移動
Ctrl + f    カーソルを右に一個ずつ移動
Ctrl + b    カーソルを左に一個ずつ移動
SpringBoot データベーステーブルの列名（カラム名）がスネークケースだった場合の対処

# 前提（テーブルの列名がスネークケース）
SpringDataJPAを使用
エンティティにf_testというテーブルを設定
~~~Entitiytest.java
package com.example.demo.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "f_test" , schema = "main")
public class Entitiytest {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long kojin_no;

    //getter, setter
}
~~~
リポジトリに指定のkojin_noを抽出するよう記述
~~~RepositoryTest.java
package com.example.demo.repositry;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import com.example.demo.entity.EntityTest;

public interface RepositoryTest extends JpaRepository<EntityTest, Long> {
	List<EntityTest> findByKojinNo(String kojin_no);
}
~~~
findByKojinNoの「findBy」は固定値で、
KojinNoは抽出したい列名と同じスペルで記述する必要があるが、
スネークケースの場合は、キャメルケースに変換する必要がある。
そして、列名の先頭は大文字で始める必要あり。

ゆえに、kojin_no → KojinNo → findByKojinNo

ここまでは問題ないはずだが、
実行させるとkojinNoなんて列は指定のテーブルにないと怒られる

# どうしたらいいか
いきなり答え
~~~Entitiytest.java
package com.example.demo.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "f_test" , schema = "main")
public class Entitiytest {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    //private Long kojin_no;
    @Column(name = "kojin_no")   //←こうする
    private Long kojinNo;        //←こうする

    //getter, setter
}
~~~
エンティティ側もキャメルケースにする必要がある
ただし、それだけだと実際にテーブルを見に行く際も「kojinNo」として見に行くため、
それを回避するために実際の列名は「kojin_no」だよという
@Column(name = "kojin_no")が必要ということらしい
【C#のポイント】Deconstructの解体

コンストラクタは、オブジェクトの初期化時にデータをオブジェクトに渡すものです。その逆であるDeconstructは、オブジェクトから必要なデータを返すものです。

以下に使用シナリオを見てみましょう。Orderをrecordとして定義し、OrderオブジェクトからnoとorderTimeをメタデータ方式で取り出す例です。これはどのように実現されているのでしょうか？

```csharp
// Orderをrecordで定義
record Order(string No, DateTime OrderTime, string Address);
// Orderを使用
var (no, orderTime, _) = new Order("T000001", DateTime.Now, "北京市海淀区");
Console.WriteLine(no);
Console.WriteLine(orderTime);
```
実際には、クラス内部にDeconstructメソッドを定義するだけで簡単に実現できます。以下に、Orderをclassとして例示します。基本的なプロパティの他に、2つのoutパラメータを持つDeconstructを実装しています。このメソッドはNoとGoodsのIDのコレクションのみを返します。ここでは一例を示していますが、どのようなデータをどのような形式で解構するかは、ニーズに応じて自由に定義できます。また、Deconstructにはオーバーロードが可能ですが、パラメータが同じ場合は関数に二重の意味が生じます。【ただし、（string no,List<int> goodsIds）を使用することで二重の意味を解消できると思いますが、現時点では使用できません】

```csharp
class Order
{
    public Order(string no, DateTime orderTime, string address)
    {
        No = no;
        OrderTime = orderTime;
        Address = address;
    }
    public string No { get; set; }
    public DateTime OrderTime { get; set; }
    public string Address { get; set; }
    public List<Goods> Goodses { get; set; } = new List<Goods>();

    public void Deconstruct(out string no, out List<int> goodsIds)
    {
        no = No;
        goodsIds = Goodses.Select(a => a.ID).ToList();
    }
    public void Deconstruct(out string no, out DateTime orderTime)
    {
        no = No;
        orderTime = OrderTime;
    }   
}
var (no, goodsIds) = new Order("T000001", DateTime.Now, "北京市海淀区")
{
    Goodses = new List<Goods>
    {
        new Goods { ID = 1, Name = "商品A", Price = 10m },
        new Goods { ID = 2, Name = "商品B", Price = 15m },
    }
};
Console.WriteLine($"OrderNo：{no}");
foreach (var goodsId in goodsIds)
{
    Console.WriteLine($"    GoodsId：{goodsId}");
}
```
さらに、Deconstructは拡張機能を通じて、いくつかの型に解構機能を追加することができます。以下はExceptionに対する解構で、MessageとInnerExceptionを取り出す例です。これは単なるデモであり、具体的な応用は柔軟に定義できます。

```csharp
static class ExceptionExtensions
{
    public static void Deconstruct(this Exception? exception, out string? message, out Exception? innerException)
    {
        message = exception?.Message;
        innerException = exception?.InnerException;
    }
    public static void Deconstruct(this Exception? exception, out string? message, out string? innerMessage, out Exception? innerInnerException)
    {
        message = exception?.Message;
        innerMessage = exception?.InnerException?.Message;
        innerInnerException = exception?.InnerException?.InnerException;
    }    
}

try
{
    throw new Exception("1級エラー", new Exception("2級エラー"));
}
catch (Exception exc)
{
    var (msg, (innerMsg, _)) = exc;
    Console.WriteLine(msg);
    Console.WriteLine(innerMsg);
}
```
不思議なC#の知識がまた少し増えました。