OmniAICreator/Qiita-1.07M huggingface dataset:
脆弱性のあるサイトを作成してSQLインジェクションを体験してみる

# 目次
[#1.はじめに](#1はじめに)
[#2.前提環境](#2前提環境)
[#3.作成したサイト](#3作成したサイト)
[#4.実際に攻撃してみる](#4実際に攻撃してみる)
[#5.あとがき](#5あとがき)
[#6.参考サイト](#6参考サイト)

# 1.はじめに
情報処理試験の勉強をしているといろんな攻撃方法を学ぶことになります。
今回は数ある攻撃方法の中でも有名なSQLインジェクションを実際に体験してみました。

# 2.前提環境
python:3.12.2
django:5.0.4
postgresql:16.2

# 3.作成したサイト
SQLインジェクションの検証ができればいいので、ユーザIDを入力してPOSTするとユーザ名をテキストエリアに出力する簡易サイトを作成しました。

①ユーザIDを入力して送信するボタンを押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324575/926c73fa-83dc-df31-27b3-6373c0943c4f.png)


②テキストエリアに対象のユーザ名が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324575/c6cadc7a-08bd-e9fb-6b38-311f66e14979.png)

DBの状態は以下のようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324575/0acc6e01-7d84-1846-7dfc-4cb8c0f05ad8.png)

# 4.実際に攻撃してみる
内部的に実行されているSQLは以下の実装になっています。
※本来djangoではあまり生のSQL文を実行することはありませんが、
　検証のためにあえて生SQLを発行する実装にしています。

```views.py
        cursor = connection.cursor()
        cursor.execute(f'SELECT username FROM m_attack WHERE userid={userid}')
```

SQLインジェクション攻撃ではSQLのWHERE句を強制的にTRUEにすることで、任意のSQL文を発行する攻撃です。
今回の場合はユーザIDに「0001 OR 1=1」を入力してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324575/a17dda19-d6ae-244e-0348-e7455817bbed.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324575/25822747-f874-ab7d-aa13-5409c558c162.png)

m_attackテーブルに登録されているユーザ情報を取得することができてしまいました。
今度はUPDATE文でテーブルを更新するために「0001 OR 1=1;UPDATE m_attack set username='SQLインジェクション' WHERE userid=0001」を入力してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324575/be86f04a-dd60-7c63-5c23-b9339a9a6595.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324575/2fcd7e89-0286-b1e9-4a02-31792ea492e4.png)

リクエストが通ってしまいました。
実際にDBを確認してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324575/31556bbe-f9f1-42c6-af5e-e8abdbba415a.png)

userid 0001のユーザの名前が「SQLインジェクション」に書き換えられています。

# 5.あとがき
簡易的に脆弱性のあるサイトを作成し、SQLインジェクションを体験してみました。
最近ではフレームワークを利用することで開発者が意識せず対策が可能な場合も多いですが、理解しておくことは重要だと思います。
また、SQLインジェクションに限った話ではありませんが、ウェブサイトのセキュリティ対策としてIPAが公開している「安全なウェブサイトの作り方」はかなり有用なので一読をお勧めします。(個人的には以前受験した情報処理安全確保支援士試験の勉強にもなりました)

[安全なウェブサイトの作り方 - 1.1 SQLインジェクション](https://www.ipa.go.jp/security/vuln/websecurity/sql.html)

# 6.参考サイト

[djangoで素のSQLを実行する](https://qiita.com/shota0616/items/74716fd7a019da48540a)

[Django#3（フォームの値を受け取る）](https://qiita.com/nab/items/e32cde1643a010dfacb9)
TypeScriptにおける型ガードの役割と使い方

# はじめに
「型ガード」という単語、聞いたことあるけど使ったことない状態でした。しかし使う必要があったので使ってみたところ結構便利だったので、簡単に忘備録も踏まえて記述していきます。

# そもそも型ガードとは
型ガードは、特定のスコープ内で変数の型をより狭い範囲に絞り込むTypeScriptの機能です。
「もしもこの変数がこのタイプならば」という条件を設定し、それに応じてTypeScriptが変数の扱い方を変えることができます。型ガードを使うと、安全に変数を特定の型として扱うことができるため、誤った型の使用によるバグを減らすことができます。

# 型ガードの種類
型ガードにはいくつか種類があります。

#### 1. `typeof`
`typeof`ガードは、プリミティブ型をチェックする際に使用します（`string`、`number`、`bigint`、`boolean`、`symbol`、`undefined`、`object`、`function`）。

```typescript
if (typeof variable === 'string') {
  // 変数が文字列の場合の処理
}
```

#### 2. `instanceof`
`instanceof`ガードは、オブジェクトが特定のクラスのインスタンスであるかをチェックします。
```typescript
class Hoge {}

const myInstance = new Hoge();

if (myInstance instanceof Hoge) {
  // `myInstance`が`Hoge`のインスタンスである場合の処理
}
```

#### 3. `ユーザー定義型`
`ユーザー定義型`　特定の条件を満たす関数を定義し、その関数がtrueを返すことで型を絞り込みます。
```typescript
interface Dog {
  type: 'dog';
  bark: () => void;
}

interface Cat {
  type: 'cat';
  meow: () => void;
}

type Pet = Dog | Cat;

function isDog(pet: Pet): pet is Dog {
  return pet.type === 'dog';
}

function isCat(pet: Pet): pet is Cat {
  return pet.type === 'cat';
}

const myDog: Pet = { type: 'dog', bark: () => console.log("Woof!") };
const myCat: Pet = { type: 'cat', meow: () => console.log("Meow!") };

if (isDog(myDog)) {
  myDog.bark(); // 安全に`bark`メソッドを呼び出せる
}

if (isCat(myCat)) {
  myCat.meow(); // 安全に`meow`メソッドを呼び出せる
}

```

#### 4. `in`
`in`　オブジェクトが特定のプロパティを持つかどうかをチェックするのに使用します。
```typescript
interface Fish {
  swim: () => void;
}

interface Bird {
  fly: () => void;
}

function move(pet: Fish | Bird) {
  if ('swim' in pet) {
    pet.swim();
  } else {
    pet.fly();
  }
}
```

# 実際いつ使う
一例として、外部APIから様々な形状のデータを受け取ることがあります。このデータを扱う際、型ガードを使用して、データが期待する型を持っていることを確認することができます。

```typescript
interface AdminUser {
  id: number;
  username: string;
  admin: true;
}

interface NormalUser {
  id: number;
  username: string;
  admin: false;
}

type User = AdminUser | NormalUser;

function isAdmin(user: User): user is AdminUser {
  return user.admin;
}

// 外部APIから取得したユーザーデータ(graphQLでもrest APIでもなんでも良い)
const usersFromApi: User[] = [
  { id: 1, username: "adminUser", admin: true },
  { id: 2, username: "normalUser", admin: false },
];

usersFromApi.forEach(user => {
  if (isAdmin(user)) {
    console.log(`${user.username} is an admin.`);
  } else {
    console.log(`${user.username} is not an admin.`);
  }
});

```
こんな感じで使用することができます。

# 最後に
APIから来た予測不可能なデータも、型ガードでしっかりとチェックできれば、安心してコードを書いていけます。
型は安全にしましょう。わからないものはガードしましょう。
Java silver向け 例題 継承 コンストラクタ

次のコードはコンパイルエラーになりますか？

```java
class sampleSuper {
	sampleSuper(int a) {
	}
}

class sampleSub extends sampleSuper{
	sampleSub(int i){
	}
}
```
答え

<br>↓<br>↓<br>↓<br>↓<br>↓<br>↓<br>↓<br>↓<br>↓<br>↓<br>↓<br>↓
サブクラスのコンストラクタ
sampleSub(int i){}でコンパイルエラーになる。

サブクラスのコンストラクタの引数の有無に関わらず、コンストラクタの1番目に暗黙的にsuper();が追加される。

```java
class sampleSub extends sampleSuper{
	sampleSub(int i){
	//super();
     }
}
```

スーパークラスのコンストラクターsampleSuper(){}が呼び出されるが、スーパークラスのコンストラクタに引数が合致するものがないためコンパイルエラーになる。

スーパークラスにコンストラクタが一つもない場合は暗黙的にsampleSuper(){}が追加される。（その場合コンパイルエラーが解決される）
```java
class sampleSuper {
	//sampleSuper(){}
}
```
スーパークラスにコンストラクタが明記的に記述される場合は暗黙的にsampleSuper(){}が追加されない（問題文)。

下記のようにサブクラスのコンストラクタに引数ありのスーパークラスのコンストラクタを明記すると、暗黙的に引数なしのコンストラクタは追加されない。（その場合もコンパイルエラーが解決される）

```java
class sampleSuper {
	sampleSuper(int a) {
	}
}

class sampleSub extends sampleSuper{
	sampleSub(int i){
    	super(100);
     }
}
```
コンストラクタの呼び出しはコンストラクタの1番上に書かなければいけない。
例えばサブクラスのコンストラクタでsuper()とthis()を併用するとsuper()が2回呼び出されることになるためコンパイルエラーになる。

```java
class sampleSuper {
    //sampleSuper(){}
}
class sampleSub extends sampleSuper{
    sampleSub(){
        //super();
    }
	sampleSub(int i){
    	super();
         this();
     }
}
```
独習PHP学習メモ（Chapter2-変数）


[PHP8技術者認定初級試験](https://www.phpexam.jp/summary/novice8, 'PHP8技術者認定初級試験')取得を目指しています🔰

公式の認定教材である[独習PHP第4版](https://www.amazon.co.jp/dp/4798168491/)での学習のアウトプット用の記事です。


## 命名規則

#### 「$名前」の形式であること

```php:例
// 良い例
$name
$address

// 悪い例
name
address
```

:::note warn
「$名前」のように変数名には日本語を含むこともできますが、慣例的に
 **英数字、アンダースコアに限定**するのが良い。
:::

#### 先頭は任意の文字かアンダースコアであること（数字はNG）

```php:例
// 良い例
$_name
$data

// 悪い例
$123
$1data
```

#### 名前の2文字目以降は数値を使用しても良い

```php:例
// 良い例
$name1
$val1

// 悪い例
$name-1
```

#### 大文字と小文字は区別される

```php:例
// 下記2つは別の扱いになる
$val
$Val
```

## 記法ルール

#### キャメルケース

小文字から始まり単語の区切りを大文字にする。
PHPでは **変数** や **関数** に用いることが一般的である。

```php:例
$userName
```

:::note info
キャメルはラクダ🐪
大文字の部分がラクダのコブと似てることが由来
:::

#### パスカルケース

先頭も含め、全ての単語の区切りを大文字にする。
PHPでは **クラス名** に用いることが一般的である。

```php:例
$UserName
```

:::note info
アッパーキャメルケースとも呼ばれる🐪
プログラミング言語のPascal（パスカル）がこの記法を標準としていることが由来
:::

#### スネークケース

全て小文字 or 大文字で表し単語の区切りをアンダースコアでつなぐ。
PHPでは全て大文字にして **定数** に用いることが一般的である。

```php:例
const USER_NAME = 'hogehoge';
```

:::note info
スネークはヘビ🐍
ヘビの姿が由来（こういうの考えられるセンスを持ちたかった）
:::

## 予約語

予約語とは言語であらかじめ決められた単語（キーワード）のこと。
定数、関数、クラスでは使用禁止である。
変数のみ例外的に認められているが使わないほうが良い。

予約語にも強さがあり、定数名で利用しても良いものもあるが、将来的に使えなくなる可能性や混乱、バグを招く原因であるため、あえて使う理由もないことから使わないことが一般的である。

```PHP:例
and
array
class
if
else
elseif
true

など
```

https://www.php.net/manual/ja/reserved.php
Pythonで「ファイルの作成と削除」の動作を確認してみた

# 概要

Pythonで「ファイルの作成と削除」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/python/file/index9.html

# 実装

以下のファイルを作成しました。
```sample1.py
import os
f = open('./test/user.txt', 'w')
f.close()
```
```sample2.py
import os
os.remove('./test/user.txt')
```

以下のコマンドを実行しました。
```
$ mkdir test
$ python3 sample1.py 
$ ls test/
user.txt
$ python3 sample2.py 
$ ls test/
```

# まとめ

何かの役に立てばと。
【解決】Node.js20系にホットリロード導入しようとしたらめちゃくちゃハマった

# 起こったこと
Node.js(Express)環境でtypescriptを使ったAPIの開発環境でホットリロードを実装しようとしたところ、めちゃくちゃ詰まった。  
最初に試したことはts-nodeとnodemonの組み合わせ。ts-nodeがtsファイルを読み込めず、ずっとエラーを吐いていた。。。

以下、解決した方法と環境

## 実行環境
- Node.js 20.0.0
- express 4.19.2
- typescript 5.3.3
- nodemon 3.1.0
- tsx 4.7.2

## 解決方法
結論、ts-nodeではなく、tsxをnodemonと一緒に利用することで解決した。
package.jsonのstartコマンドを記載するだけ。tsconfig.jsonなど他のファイルの変更は不要。

```
yarn add -D tsx
```

```
  "scripts": {
    "test": "echo \"Error: no tes@t specified\" && exit 1",
    "start": "nodemon --exec tsx './app.ts'",
    "up": "yarn install && yarn start"
  },
```
この状態でdocker-compose up時にstartコマンドも実行するようにすればコンテナの起動と同時にホットリロードが走るようになった。  
※`tsx './app.ts'`の部分はファイルのパスをシングルクォーテーションで囲む必要があります。


## 原因
ts-nodeとNode.js20系とESMの組み合わせの相性が悪いっぽかった。（ts-nodeの実行時にesmオプションを付けたり、package.jsonに`type: module`を記載してみたりしたが以下のエラーが直らなかった。）
原因は不明。。。

```
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /home/watanabejin/workspace/business_card/batch/index.ts
    at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:160:9)
    at defaultGetFormat (node:internal/modules/esm/get_format:203:36)
    at defaultLoad (node:internal/modules/esm/load:143:22)
    at async nextLoad (node:internal/modules/esm/hooks:750:22)
    at async nextLoad (node:internal/modules/esm/hooks:750:22)
    at async Hooks.load (node:internal/modules/esm/hooks:383:20)
    at async handleMessage (node:internal/modules/esm/worker:199:18) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
}
```

## 他の学び
はじめ、windows × WSLの構成でdockerコンテナを起動し、プロジェクト自体はWSL上ではなくWindowsのローカルに置いていたため、コンテナのパフォーマンスが著しく低かった。
これはWindows上のファイルシステムがWSL Ubuntu自身のファイルシステムとは違うことによって起こるらしい。
下記の記事がとても勉強になりました。
[参考](https://qiita.com/atomyah/items/3a361cecfa62e12e1d86)

最終的にHyperVを利用してコンテナ起動するように修正したらパフォーマンスの問題は改善されました。

## 20240418 追記
メンバーの環境によってはdocker起動時に「System」タスクがCPUを食い尽す事象が発生した。（タスクマネージャから確認）

最終的には下記のような形で落ち着いた。

``` package.json
  "scripts": {
    "start": "nodemon ./dist/index.js",
    "build": "npx tsc",
    "build:watch": "npx tsc -w",
    "dev": "yarn install & yarn run build:watch & yarn start",
    "up": "yarn install && yarn start"
  },
  ```

  jsファイルを直接実行した方が安全かもしれないという結論に。
20240409 日記 開発環境構築、RR-automate開発

### 環境構築
#### コマンドでWindowsをスリープさせる方法
キーボードからなるべく指を離したくないという気持ちから探してみた

```
> RUNDLL32.exe POWRPROF.DLL SetSuspendState Sleep.
```
これでできる

参考： [Windows 11 PCをスリープさせる方法 - TheFastCode](https://www.thefastcode.com/ja-jpy/article/how-to-put-a-windows-11-pc-to-sleep)

#### lazygitをいれた
が、Neovimのtoggletermから開くと`<esc>`がnvimの`<esc>`とぶつかってしまう
タブもぶつかる
いろいろキーマップを変えないと

#### Oil.nvim
Windowsで使えない？と思ったがそこにwslで作ったシンポリックリンクがあったのが原因だった
簡単にファイルを作ったり名前変更できるのはいいけどディレクトリをまたいだ操作はできないのがちょっと残念

### RR-automate開発

だいぶきれいになったのでそろそろデッキの集計機能を作ろうと思う

デッキをさくっと作るために、テストデッキのYMLファイルを作る
そして、デッキが正しく読み込まれるかのテスト
デッキ集計をできるかのテスト

そんな感じに進めていこう

今できたのはこんなの
```yaml:deck.yml
decks:
  -
    hero:
      name: Zeus
      level: 20
    units:
      -
        name: Riding Hood
        level: 15
        talents:
          -
            rank: 1
            name: Alpha Wolf
          -
            rank: 2
            name: Wound Licking
          -
            rank: 3
            name: Neutralization
          -
            rank: 4
            name: Treats for Grandma
      -
        name: Knight Status
        level: 15
        talents:
          -
            rank: 1
            Name: Sharpened Spear
          -
            rank: 2
            name: Barrier
          -
            rank: 3
            name: Stone Legion
          -
            rank: 4
            name: Soul of a Warrior
      -
        name: Dryad
        level: 15
        talents:
          -
            rank: 1
            name: Fairy of Rage
          -
            rank: 2
            name: Gift of Nature
          -
            rank: 3
            name: Poisonous Fruit
          -
            rank: 4
            name: Spirits of the Forest
      -
        name: Witch
        level: 15
      -
        name: Trapper
        level: 15
```

Witchのタレントは省略
才能によって、Toxic＝True/Falseあるし、なかなか面白そう
【Zod】maxやminで文字列を正確に数える方法

Zodの `max` や `min` を使用すると「𩸽」などのサロゲートペアの文字は2文字としてカウントされます。

以下のように `min` を記述してフォームバリデーションをします。

```js
const schema = z.object({
  name: z
    .string()
    .min(2, "2文字以上で入力してください")
})

```

![スクリーンショット 2024-04-10 0.23.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/3e813128-d4d5-387b-ddb8-50163b128dbf.png)

ユーザー名の入力欄には「𩸽」1文字しか入力されていないにも関わらず、「2文字以上で入力してください」というメッセージが表示されていません。

`refine`を使用して以下のように書き換えます。

```js
const schema = z.object({
  name: z
    .string()
    .refine((value) => [...value].length > 2, {
      message: '2文字以上で入力してください。',
    }),
})

```

すると「𩸽」も1文字としてカウントされるようになり、「2文字以上で入力してください。」というエラーメッセージが表示されるようになります。

![スクリーンショット 2024-04-10 0.27.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/d06426d9-edc1-f879-d7da-cc24c66f2c2d.png)
【備忘録】Next.jsでクライアントコンポーネントから呼び出せない関数を作成する

# はじめに
この記事は **server-only** の **挙動理解** と **使い方** の備忘録です。

## インストール
```
npm install server-only
```
## server-only とは
**サーバコンポーネントからのみ呼び出したい関数** を **クライアントコンポーネント** から
**呼び出せなくするライブラリ** です。

```
import "server-only"
```
と記述することで **適用** 出来ます。

## 挙動理解
**クライアントコンポーネント** から **server-onlyを使った関数** を呼び出すが
**エラーがスロー** されて呼び出せない **実装例** を下記に示します。
```tsx:app/page.tsx
"use client";

import { serverSideExecution } from "@/datas/serverSideExecution";

export default function Home() {
  const temp = serverSideExecution();

  return (
    <div>{temp}</div>
  );
}
```
```ts:datas/serverSideExecution.ts
import "server-only"

export const serverSideExecution = () => {
    return "サーバ側でのみ実行されます。"
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/6fb2229b-c7b9-1a6e-528a-f6d9747fd7b0.png)

このような **エラーをスロー** します。

## さいごに
学習させていただいた先・ライブラリの公式ドキュメント・リンクです。

https://www.npmjs.com/package/server-only
mix ecto.setupってなに？ってお話

背景
ecto.setupの情報があまり落ちていない

mix ecto.setupとは？
mix.exsのエイリアスを定義してくれる
mix.exsで記述できるので予め設定しておくと便利かも？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330568/91d68762-7cce-e782-97d8-d2e3c16d4605.png)


その他
mix helpで簡易的な情報について知れる。
実行可能なmix taskではあるが公式でも明確に説明されていないためやや注意が必要です。
https://hexdocs.pm/phoenix/mix_tasks.html#ecto-tasks
@sidebase/nuxt-auth + prisma で Unknown argument provider_providerAccountId エラー

### 環境
- prisma 5.12.0
- @sidebase/nuxt-auth 0.7.0
- @next-auth/prisma-adapter 1.0.7

### エラー

https://next-auth.js.org/v3/adapters/prisma

上記サイトの設定に従ってスキームを作成したところ、ログイン時にこのエラーが発生した。

### 解決

https://authjs.dev/reference/adapter/prisma

最新の情報はAuth.jsに記載されているようで、こちらのスキームに変更したところ解消された。
意外とみんな低気圧に困っている

# はじめに
「低気圧」による不調を受け入れる方法について考えてみました。

## 低気圧で影響を受けていると気づくまで
小学生の頃から、雨の日にはよく腹痛になっていました。
社会人になってからも雨の日にの腹痛や身体の怠さ、頭痛が続いていましたが、
ある時、ニュースで「気象病」というものを知りました。

そして「気象病」を調べていくうちに
低気圧で影響を受ける場合があるとわかりました。

## 低気圧による影響
私の場合ですが、低気圧で以下の影響を受けることが多いです。

* 身体のだるさ
* 腹痛
* 頭がボーッとする
* ちょっとネガティブになる
* 頭痛（激しい低気圧の場合）

## 低気圧を受け入れるポイント
**お薬を飲んでみる**
頭痛や腹痛が起こる方はお薬を事前に準備したり、常備しておいて、
予兆が現れそうな時は服用してみましょう。

身体的な負担が軽くなると、
すこし気が楽になります。

**アプリを見て、低気圧を確認する**
気圧の変化を表示できるアプリを入れてみましょう。

自分の不調の要因の一つが
「気圧にある」ということを認識できるだけで、
すこし気が楽になります。

**低気圧のせいにしてみる**

悪いことが起きた時の気持ちを、
ちょっとだけ低気圧のせいにしてみましょう。

低気圧はいわば`dev/null`と同じなので、何も言い返したりしません。
つらい気持ちはちょっとだけ低気圧のせいにしてみましょう。
すこし気が楽になります。

（※ただし、自分でやらかしたことや失敗の反省はきちんとしましょう）

**話のネタにしてみる**

「今日、低気圧ヤバイ」みたいなネタを社内で話してみると、
メンバーから共感のリアクションを得られることも多く、意外と話のタネになります。
日々のMTGのアイスブレイクとして話のネタにしてみましょう。

話してみて「自分だけじゃないんだ」と思えることで、
すこし気が楽になります。

# まとめ
低気圧による「影響を受ける・受けない」「どれだけ影響がある」「どんな不調がある」は体質によって全然違います。影響を受けやすい方は、最小限の負担で受け入れられるように意識してみるといいかもしれませんね。

# 告知
最後にお知らせとなりますが、イーディーエーでは一緒に働くエンジニアを
募集しております。詳しくは採用情報ページをご確認ください。

https://eda-inc.jp/recruit/

みなさまからのご応募をお待ちしております。
プログラマーの仕事道具、キーボードの種類を簡単に解説してみた

## 誰向けの記事？

- 駆け出しプログラマー
- 在宅勤務増えた人
- 最近キーボード買おうと考えている人
- HHKBとか聞いたことあるけどなにそれ？美味しいの？な人

パソコンを使って仕事をする人が最も触るデバイスは？

そう、キーボードです。

でも、キーボードってなんか色々種類あるっぽいけど、

「良くわかんねぇぜ！」って言っちゃうそこのアナタに捧ぐ。

ちょっと(自作)キーボード沼にハマった人が、

今回はキーボードの軸の種類で分類してみた概要を囁いてみようと思います。

## TL;DL

ざっくりな種類分けはこんな感じ

- メンブレン
- パンタグラフ
- メカニカル
- 静電容量無接点

はい、そこ！

ブラウザバックしようとしたでしょ？

テストに出るからちょっと沼を覗き込みなさい(あ、優しくするから帰らないでー)

## グループ分けの概要図

キーボードの心臓部分はもちろん、ペコペコ押すスイッチの部分になります。

今回は、スイッチの種類でキーボードをグループ分けしてみようと思います。

概要図は下記の通り。

```mermaid
graph LR;
    A[キーボードたち] --> B[接点あり]
    A --> C[接点なし]
    B --> D[メンブレン]
    D --> E[安いキーボードに多い]
    B --> F[パンタグラフ]
    F --> G[ノートPCのキーボードのように薄いもの]
    B --> H[メカニカル]
    H --> I[通常タイプ]
    I --> J[赤軸・茶軸・青軸などと言われる物がついてる]
    H --> K[ロープロファイル]
    K --> L[薄いメカニカルスイッチがついているタイプ]
    C --> M[静電容量無接点]
    M --> N[REALFORCE、HHKB、Nizぐらいにしかない特殊なタイプ]

```

物によって価格差はあるので全てがこのような形にはなりませんが、

おおよそ価格の関係性はこんな感じになります。

`メンブレン < パンタグラフ < メカニカル < 静電容量無接点` 

今自分が使っているキーボードはどこにグルーピングされているかなんとなくわかりましたでしょうか？

ハッキリ言ってキーボードの入力に関しては好みなので、

ノートPCのような薄いペチペチとした打鍵感が好きな人もいるし、

静電容量無接点こそ至高！という流派も存在するのも事実です。

多様性の世の中だよ？好きなの使えばいいと思うの🐭

## タイプ別の代表機

キーボードのタイプ別で見たときにどれがどのキーボードか？のイメージが付くと良いかな？と思ったので、

有名なものを何個かあげたいと思います。

<メンブレン>

数が多いので略！(おい！)

<パンタグラフ>

- magic keyboard(macの薄い外付けキーボード)
- MX KEYS(Logicool製品)

<メカニカル>

- ゲーミングPC用のキーボードで赤軸、茶軸、青軸など◯軸と選ぶもの
- Keychronのキーボード(薄型も通常サイズもラインナップあり)
- 自作キーボードの大体(ここは沼なので要注意です。おいでよ。)

<静電容量無接点>

- REALFORCE(機体がずっしり。安定感◯)
- HHKB(プログラマーがハッピーになる持ち運びもしやすいキーボード)
- Niz(中華製で一番バネが軽いので柔らかい打鍵感が他とは違うところ)

これ以外の選択肢を自分は知らない。

キーボードの写真も貼り付けようか悩みましたが、

自分で色々探す楽しみがあってもいいかな？と思いましたので割愛します笑

## 最後に

ちょっとだけキーボードってどんな仲間がいるかという理解の一助になれば幸いです。

グルーピングはスイッチの部分だけではなくて、

- 配列(US配列、JIS配列など)
- キーの数によるサイズ(フルサイズ、テンキーレス、60%…など)
- 一体型、分割式(分割式はキーボードが半分に分割されていて左右に分かれます)

なんていう分け方もあります💦

この辺は、他のブログ記事でも色々情報があるので、

見てもらえれば大体同じことが書いてあると思います笑

唯一体験談としてあれこれ書けるのは分割式はキーボードって実際どうなん？ってことだと思いますが、

そのへんは需要があるようでしたらそのうち記事に残そうと思います。

長くなりましたが、皆様良きキーボードに出会えますように！

では！
チームでスキルアップするためのAWS Team Jamの活用

# 概要
## Jamとは？  
AWS JamはAWSより提供されるスキルアップのためのトレーニングです。  
Jamでは実際の案件でありがちな構築作業やトラブルシューティングがラボ環境で再現されますので、実際に手を動かしながらこれらの課題(チャレンジ)を解決していくことになります。

https://aws.amazon.com/jp/training/digital/aws-jam/  

https://beta.jam.aws.com/v2/  

Jamを実施する方法として個人で行うパターン、チームで行うパターンの2パターンがあり、どちらのパターンにおいても、AWS Skill Builderのポータルから利用することが出来ます。(Subscriptionが必要です)  
また、AWS Summitやre:inventなどでも、Jamのイベントが開催されることがあります。 (以下は2023年のAWS Summit Tokyoでの実施案内)


https://aws.amazon.com/jp/blogs/news/aws-summit-tokyo-2023-aws-jam-intro/

## Team Jamとは？ 
Jamの参加者を3~4人毎のチームに分け、チーム単位で課題に取り組むトレーニングです。  
弊社ではこのTeam Jamを2023年後半から2024年3月にかけて社内向けに複数回実施しましたので、本記事では**社内で純粋な学習目的に利用した際の知見**を記載します。
Team Jamはこういった学習目的以外に、各チームでスコアを争うことでレクリエーションイベントとしても活用出来ますので、この場合の考慮事項についてはAWS公式等の情報をご確認ください。

## 実施方法
Skill Builder・Jamのコンソールにログインすることで詳細なドキュメントを確認できますので、こちらでの紹介は割愛します。  
ファシリテーター向けのガイドだけでなく、参加者向けのガイドも存在します。  

# イベント開催時のポイント  
## イベントの意義を説明する
このあたりはJamに限らずイベント毎全てで同じだと思いますが、必ずイベントの開催意義を説明するようにしていました。  
Team Jamに参加してくれたメンバーは若手がほとんどでしたので、以下の内容を特に伝えるようにしていました。  

・Jamは(模擬的な)実戦経験を獲得する場である  
若手だとアサインされる現場によって身につく技術分野がかなり左右されるため、”よくあるシチュエーション”の模擬戦であるということを認識してもらいました。

・横のつながりを深める    
チームで実施することになるため、チーム内で積極的にコミュニケーションしてもらうこと・お互いのスキルレベルを認識してもらうことを心がけていました。(スキルアップのための学習は、ともすれば孤独な戦いになりがちなので、お互いの立ち位置を把握・教え合うことを期待)  


・縦のつながりを見つける    
AWS案件で困ったときに”頼り先”として、ファシリテーターの方ともコミュニケーションを深めてもらうこともイベントの目的の一つです。リモートワーク中心だと誰が詳しい人なのか分からない・気軽に連絡出来ない、というのはよくあると思うので、そういった際の頼り先を見つけてもらうようにしました。
  

## ラボ環境の用意には時間がかかることを理解しておく
いきなりシステム的な話になりますが、Jamはラボ環境が常に用意されているわけではなく、ラボ環境作成のボタンをポチッとしてはじめてラボ環境作成が開始されます。(数分～十数分はかかります)  
そのため、集合したら何よりもはじめにラボ環境の作成を開始するのが重要です。(ゲーム形式で行う場合はラボ環境の作成時間は持ち時間に直結しますので、より一層の考慮が必要と思われます。)  

## ググってもOK
Team Jamはテストではないので、ググってもOKとしていました。  
むしろ実際に案件で色々なタスクをこなしていく際にはググりながら・生成AI等も活用しながら実施していくと思いますので、学校の試験さながらのテストを行うのでなければこれを禁止する意味はないと思います。(むしろ、ここでググる際の勘所を見つけ方を身につけてくれることを期待)

## (極力)答えは教えない
ググってもOKということもあり、答えを伝えるのは最後の手段とし、質問されたときの対応はだいたい以下のパターンにしていました。  

・見当違いの箇所で詰まっている際はそれを伝える    
課題を解決するためのポイントと全く異なるポイントを頑張って設定しようとしている場合は、”そこは今回の課題では関係ないよ”と伝えるようにしていました。また、振り返りの中でどういったシチュエーションならその設定を行う必要があるか、というのも合わせて伝えていました。

・キーワードを伝える  
何から手を付けていいか分からない状態になっているチームには、ググる際のキーワードを伝えていました。AWS Docsがヒットするようなキーワードであればチュートリアルや設定のサンプルが記載されていますので、それを参考に進めることが出来ます。(そのDocsが課題の内容に即しているかどうかは参加者に考えてもらいます)

・類似例を持ち出す  
"微妙にjsonの書き方が違う。。"であったり、"見ている箇所は正しいけど設定値が正しくない。。。”というときは、"同じ種類の別のリソースの設定値を見たらどうかな？"とコメントするようにしていました。例えば、IAM Policyなど公式が用意しているものがあるリソースがあるときはその記述と比較してもらうことで単純なミスに気づくことが出来たりします。  

## 振り返りを行う
チャレンジ終了後には必ず15～30分ほど時間を設けてチームで振り返りを行う時間を設けてもらい、以下の内容について話し合ってもらうようにしていました。  

・チャレンジ内容に対する理解  
・出来たこと  
・出来なかったこと  
・技術的にもやもやしている箇所  

また、ファシリテーターから出題されたシステムのアーキテクチャや実案件での使われ方を説明することもありました。

## 上記を踏まえた時間配分をする
Jamイベントを企画する際には、イベントの意義を説明したり・振り返りをする時間を考慮しておく必要があります。2つ合わせて最低でも30分・多ければ60分は見ておく必要があるでしょう。  
そのため、2時間程度で完結する場合、実際にチャレンジへの取り組みに当てられる時間は1時間～1時間半程度と考えてください。

# まとめ
AWSに関する勉強・スキルアップの記事を見ていると、資格試験に関するものが圧倒的に多く、資格を取得した後どうするか・(資格のような座学ではなく)ハンズオン形式の学習はどのように行うか、という記事は少ないという印象です。  
本記事ではTeam Jamをトピックとしてスキルアップイベントを行う際のポイントをまとめましたが、個人でJamを行う際にもいくつか参考になる点があれば幸いです。  
AWSからはこのJamだけでなく、Cloud QuestやCard Clashのような楽しみながらスキルアップできるコンテンツが提供されていますので、是非これらも合わせて学習の効率化につなげていただければと思います。
JavaSilverの試験を受けて学んだことの振り返り

先日、JavaSilverの試験(Java SE 11 Programmer I (1Z0-815-JPN))を受験し、合格しました。
私は大学時代に合わせて一年ほどJavaを勉強した後、業務で数年ほどJavaを使っていたので、試験勉強は基本的には知っている内容の復習がメインだったのですが、一部、知らなかったり全く覚えていなかった内容がありましたので復習を兼ねて以下に纏めさせて頂きます。


#### コンパイルについて
Javaプログラムを実行する場合、以下①、②の手順でコンパイルを行った後に実行を行いますが、Java11では「Launch Single-File Source-Code Programs」が導入され、コンパイルを行わずに実行することができるようになりました。
コンパイルを行わずに実行する場合、以下③で実施します。


```
javac Sample.java     ---①
java Sample           ---②

java Sample.java      ---③
```


#### 例外処理：try-catch-finalyブロック
Javaでtry-catch-finalyブロックを使用して例外処理を行う場合、try-catch-finalyおよびtry-catchの記載が行えますが、それ以外に以下のようにtry-finalでの記載もできます。

```
try{
    //tryブロックでの処理
}finaly{
    //finalyブロックでの処理
}
```

#### モジュールについて
モジュール・システムとは、Java9から導入された、パッケージをグループ化する仕組みのことです。
モジュールを定義する際には以下のようなmojule-info.javaという名前のファイルを作成します。


```
//mojule-info.java
module モジュール名 {              ---①
    requires 依存するモジュール名;  ---②
    exports 公開するパッケージ名;   ---③
}
```

module-info.javaでは①でモジュール名を記述し、波カッコ内にモジュール本体を記述します。
②のrequiresディレクティブではモジュール間の依存関係を表しており、②で記載したモジュールに①で記載したモジュール名が依存します。
③のexportsディレクティブでは他のモジュールに公開するパッケージを表しています。
依存関係のある他モジュールで、②で記載したパッケージのpublicなクラスを使用することができるようになります

#### モジュールシステムのコンパイル
モジュール化されたプログラムをコンパイルする場合は、以下のコマンドを実施します。
コンパイルが成功するとmodule-info.classがされます。生成されたクラスファイルは、モジュールのルートディレクトリに配置する必要があります。
```
javac -d クラスファイル生成先　コンパイル対象
```

#### モジュール実行
コンパイルしたモジュール化されたプログラムを実行する場合は、以下のコマンドを実行します。
```
java --module-path モジュールのルートディレクトリ -m 実行するモジュールのクラス
```

### 最後に
普段の業務で使用する際はわからないことがある場合もその時に必要な内容のみを調べて進めており、全体を通して確認することはなかったので、大学でJavaを学んで以来数年ぶりにjavaについて全体的に勉強し直しました。
ですので上記の内容含め、忘れていた部分や理解が不十分だった箇所を振り返る良い機会となりました。
また、自分が知らなかった内容は主にJava9以降に追加された機能に関わる部分でしたので、今回を機会に知識をアップデートする必要性を感じました。
【Vercel】いつもどおりデプロイしたらErrorになった話。

Vercelにアプリケーションをデプロイしたところ、エラーが発生しました。

![スクリーンショット 2024-04-09 22.53.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116193/ff3a0ba7-1a6e-f2fc-18d8-98948ac3a808.png)

公式のインシデント履歴を確認したところ関係しそうなものが。
> Some Builds with Edge Functions and Middleware Failing
Resolved - This incident has been resolved.
Apr 9, 04:27 UTC
Monitoring - A fix has been implemented and we are currently monitoring.
Apr 9, 04:06 UTC
Identified - Some new builds experienced build failure due to an issue with edge functions and middleware. This issue was identified by one of our upstream providers, and they internally investigated and fixed the issue. 
This relates to the previous incident linked below:
https://www.vercel-status.com/incidents/9pyk5640w5r7
Apr 9, 03:26 UTC

自分の備忘録として。
次からは何かあればここをチェックする。

https://www.vercel-status.com/

※翌日デプロイすると、問題なく成功しました。

## 参考記事

https://github.com/vercel/vercel/issues/10793
Helm

# Helm の目的
Helm は、チャート と呼ばれる Kubernetes パッケージを管理するためのツールです

* 最初から新しいチャートを作成する
* チャートをチャートアーカイブ (tgz) ファイルにパッケージ化する
* チャートが保存されているチャートリポジトリを操作する
* チャートを既存の Kubernetes クラスターにインストールおよびアンインストールする
* Helm でインストールされたチャートのリリースサイクルを管理する

# Helm の概念
* Chart
    * Kubernetesアプリケーションを構築するための一種のパッケージで、パッケージをインストールすることで、Kubernetesクラスターにアプリケーションを簡単にデプロイできる
* Config
    * コンフィグは、チャート内にある設定情報をまとめたもので、デプロイ時に必要な設定やパラメータが含まれ、環境に合わせたデプロイができる
* リリースは、特定のコンフィグを適用してデプロイされたチャートが、Kubernetesクラスター上で実行されている状態

# コンポーネント
Helm は、2つの異なる部分に実装される実行可能ファイルのこと

１．Helm クライアント
* ローカルチャート開発
    * ローカル上でアプリケーションやサービスをKubernetesにデプロイするための準備作業をする
* リポジトリの管理
    * チャートを公開したり、検索したり、取得したりするための場所を整理する
* リリースの管理
    * チャートを使って新しいバージョンのアプリケーションをデプロイし、古いバージョンをアップグレードまたは削除する
* Helm ライブラリとのインターフェース
    * HelmクライアントがHelmライブラリを介してKubernetesクラスターとやり取りし、アプリケーションのデプロイや管理をする
* インストールするチャートを送信する
    * ユーザーが指定したチャートをKubernetesクラスターに送り、アプリケーションを展開する


２．Helmライブラリ
すべてのHelm操作を実行するためのロジックを提供し、Kubernetes APIサーバーと、以下の機能を提供する

* Helmはチャートと構成情報を組み合わせて、アプリケーションのリリースを構築し、Kubernetesクラスターにデプロイする
* Helmはユーザーが指定したチャートをKubernetesにデプロイし、その結果として生成されるリリースオブジェクトを提供する
* Kubernetes APIを利用し、チャートのアップグレードとアンインストールをする

Helmクライアントとは独立したHelmライブラリは、Helmのロジックを包括しているため、異なる種類のアプリケーションやツールがHelmの機能を利用できる

# 実装
Helmクライアントとライブラリは、Go言語で記載されている

# ポストレンダリング
マニフェストが生成された後に、ユーザーが必要に応じてその内容を変更したり、検証したりできる仕組み

続きはまたあとで、まとめようと思います
統計検定準1級合格体験記

# 初めに
　筆者が統計検定準1級に合格するまでに行った「勉強方法」・「合格に必要なこと」・「合格して思うこと」を書いています。
 
　成績は74点で、ありがたいことに優秀成績賞を頂けました！せっかく優秀賞を頂いたので、体験記を書いてみました。

# 筆者の勉強方法
　やったことは統計学実践ワークブック本文の行間埋めです。ひたすら載っている数式や定理の導出をしていました。例題の方は、一周目は理解の助けになるものだけにざっと目を通すだけでした。例題も全て解いていると、ワークブックのあのスカスカな行間を埋めながらでは時間がかかり過ぎると思ったからです。
 
　ですが、行間埋めにも非常に時間がかかりました…。一週間の勉強時間が平均10時間くらいで7、8ヶ月かかりました。その間、何度も心が折れそうになってました…。後述もしますが、正直、合格にはそこまで丁寧にワークブックを読み込む必要はなかったのですが、統計学の知識を網羅的にきちんと身につけておきたいという思いで準1級の勉強を始めたので、この方針を続けていました。
 
　行間埋めには、久保川先生の「現代数理統計学の基礎」や小西先生の「多変量解析入門」などの他の書籍や、統計学をまとめたブログ記事、YouTubeの動画も参考にしていました。昨今、ネットで検索すれば、わかりやすく解説して下さっている方々がたくさんいらっしゃるので、独学でも学習に困ることが少なくなっています。発信されている方々には感謝しかありません。

# 合格に必要なこと
　ワークブックは必携ですが、私のように本文の数式全てを導出する必要はありません。それらを丸暗記できて、なおかつ問題に応じて使えるならそれでも問題ないと思います。私は、学生の頃からそうだったのですが、暗記は苦手で、数式は導出したり何回も使っていく過程で覚えていくタイプだったのでそうしていました。何を暗記して何を導出まで追うかは、自身で取捨選択するのがいいと思います。
 
　ワークブックの例題に関しては、これは全て一回は解いておいた方が良いです。難易度がほぼ本番の問題と同程度なためです。また、半分くらいの問題が、過去問の類題なので、出題傾向を知るにもワークブックで十分だと思います。例題は、解くだけではなく、ワークブックの解答がどうしてこのような解き方なのか、それをある程度、説明できるくらいにその分野の理解を深めておく必要はあるかなと思います。

　最短で合格を目指すなら、次のような勉強方法をおすすめします。
①ワークブックの例題一通り解いてみる
②本文や他の書籍・ネットブログなどで出来なかった分野の理解を深める
③もう一度、例題を一通り解く
ワークブックの例題だけでは不安がある場合は、過去問や2級の問題を解いても良いと思います。感触として、2級の問題を完璧に解けるくらいであれば、準1級でも50点は取れると思います。
 
# 合格して思うこと
　ここからの話は、これから統計検定準1級を受けようとする方の参考にはならないと思いますが、合格した後、私自身も想定していなかった思いが湧いてきたので、一つの体験として記しておきます。

　当初、準1級に合格すれば、ある程度、自信を持って「統計学を使って仕事ができます！」と言えると思っていました。ですが、準1級は統計学の各分野をある程度は網羅しているものの、合格してしばらくすると「それぞれの分野の表面的なことしかまだ知れていないのでは…」という思いが沸いてきました。
 
　ワークブックには載っていない手法も数多くあります。また、試験の問題は正解がありますが、実務ではそもそも問題設定の方が重要です。そのため、準1級レベルの問題を解けるからといって、仕事で統計学を駆使できるレベルまで達してはいないことを実感してしまいました。
 
　合格後、私の中では準1級合格はまだ統計学の序の口レベル、といった印象に変わりました。まだまだ色んなことを学んでいかなければならないと感じています。
llamafileでお手軽♪ローカル生成AI

# :goat: llamafileとは

`llamafile`とは大規模言語モデル（LLM）をマルチプラットフォームで実行可能なようにパッケージ化するもの、あるいはパッケージ化されたファイル。  

> [Github](https://github.com/Mozilla-Ocho/llamafile)より．
> > 私たちの目標は、オープンなLLMを開発者とエンドユーザーの両方にとって、よりアクセスしやすくすることです。私たちは、llama.cppとCosmopolitan Libcを一つのフレームワークに統合することで、LLMのすべての複雑さを、インストールすることなく、ほとんどのコンピュータでローカルに動作する単一ファイルの実行ファイル（"llamafile "と呼ばれます）に集約しています。

要は、いろんなOS上で簡単にLLMを実行可能にする素敵なツール、ということです。  
ローカル上でとても簡単に生成AIを稼働させることが出来、しかも`llama.cpp`を利用しているのでCPUで動作します。  


# :rocket: 実行

`llamafile`を実行するのはとても簡単です。  
まずは[huggingface](https://huggingface.co/)から`llamafile`をダウンロードします。  
いくつかのLLMのllamafileが見つかると思いますので、お好みのモデルのものを取得しましょう。  
> ここの例では`mistral-7b-instruct-v0.2.Q3_K_M.llamafile`を使用します。

Windowsの場合は、DLした`llamafile`のファイル名を変更し最後に`.exe`を追加します。  
（`mistral-7b-instruct-v0.2.Q3_K_M.llamafile.exe`）  

あとはこのファイルを実行するだけです。  
ターミナルが立ち上がり処理が走り出します。  
しばらくするとブラウザが起動し以下のような画面が表示されます。  
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479194/c4d4d4d1-c5f6-faa4-7bf6-8071025f37f5.png)

これで生成AI利用の準備はOKです。  
下部の"Say something..."の欄に文章を入力し`Send`ボタンを押下すれば会話が始まります。  
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479194/53047207-984e-9af5-571e-6dfe246714bd.png)

### 注意

Windowsでは4GB以上の実行ファイルを実行することが出来ません。  
llamafileのサイズに注意してください。

## LLMを指定してllamafileを実行

現時点ではllamafile化されたLLMはまだ選択肢が多くありません。  
またWindowsでは4GBの制限があるため、性能のよいLLM（llamafile）を実行することができません。  

そのような場合は、お好みのLLMを指定してllamafileを実行することができます。  

まずは以下をダウンロードします。
- [Github](https://github.com/Mozilla-Ocho/llamafile)より`llamafile-*.*`
- [huggingface](https://huggingface.co/)より利用したいLLMの`gguf`ファイル
    > 例では`ELYZA-japanese-Llama-2-7b-instruct-q3_K_M.gguf`を利用しています。

Windowsの場合は、ダウンロードした`llamafile-*.*`を`llamafile.exe`にファイル名変更しておきます。  
次にターミナルを開き、以下コマンドを実行します。  
```
llamafile.exe -m ELYZA-japanese-Llama-2-7b-instruct-q3_K_M.gguf --host 0.0.0.0
※上記はカレントディレクトリ内にllamafileとggufファイルがある場合です。
  異なるディレクトリにある場合はパスを指定してください。
```

すると先ほどと同様にターミナル内で処理が走り出します。  
しばらくするとブラウザが起動し先ほどと同様の画面が表示されます。
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479194/dcd61ac5-0369-d374-d3ae-a75c3351f0ac.png)

あとの使い方は同じです。
文章を入力し`Send`をクリックしましょう。
![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479194/146e6dc1-a435-3b5e-008d-dbb4c04e7cac.png)

# :bulb: あとがき

上記利用手順を見てもわかるように、極めて簡単にLLMを利用することができます。  
ある程度の性能のLLMを利用するにはそれなりのスペックの端末が必要ですが、強力なGPUも必須というわけではなく（コマンド実行時にオプションでGPUに処理させることも可）、また、ファイルさえ用意すればインターネット接続も不要と、使い勝手も良いです。  

いろんなLLMの比較検証や、クローズドな環境での生成AIシステムの構築などに適しているのでは、と感じます。  
OSSのLLMも、`llama-2`のようなメジャーなものから最新で強力な`Command-R+`まで、いろいろ利用することが可能です。  
みなさんもお気軽に試してみてはいかがでしょうか。

それでは、よいLLMライフを:sunny:
Railsアプリケーションを立ち上げる

プログラミング学習を始めて約２か月。
理解しているのか謎なので自分なりにまとめてみようと思います。

### アプリの内容
タイトル、名前、内容を投稿するアプリです。
(初心者なので細かな設定はしていません。基本の動作を理解するためのものです。)

#### 手順
1.新規アプリの立ち上げ
2.一覧機能実装
3.投稿機能実装
4.保存機能実装

#### アクション
・index　　一覧表示
・new　　　新規投稿
・create 　 保存    


#### 1.新規アプリ雛形作成
今回は「practice_app」という名前でアプリを作ります。
```ruby
%rails _7.0.0_ new practice_app -d mysql
%rails db:create #データベース作成
```

モデルの作成。命名規則は「単数形」
```ruby
%rails g model post
```

カラムの追加。項目は「タイトル」・「内容」・「名前」、型はタイトルと名前は１行以上になることはないので「string」、内容は長い文章を想定して「text」としました。
```ruby:_create_posts.rb
t.string :title
t.text :content
t.string :name
```
マイグレート実行
```ruby
% rails db:migrate
```

#### 2.一覧機能(index)
コントローラーを作成。命名規則は「複数形」
```ruby
% rails g controller posts 
```
コントローラーの設定。(アクションを定義)
```ruby:app/controller/posts_controller
def index
  @posts = Post.all
end
#すべての投稿を@postsに格納
```
ビューの作成。一覧表示なのでファイル名はindex.html.erb
```ruby:index.html.erb
<% @posts.each do |post| %>
  タイトル：<%= post.title %><br>
  内容：<%= post.content %><br>
  投稿者：<%= post.name %><br>
<% end %>
```

ルーティングの設定
```ruby:routes
root to: 'posts#index'　　#postsコントローラーのindexアクション
resources :posts, only: [:index]
```

#### 3.投稿機能
コントローラーの設定。
```ruby:posts_controller
def index
  @posts = Post.all
end
def new
  @post = Post.new
end
```
ルーティングの設定
```ruby:routes
root to: 'posts#index'
resources :posts, only: [:index, :new]
```
ビューの設定　new.html.erb作成。
```ruby:new.html.erb
<%= form_with model: @post, local: true do |form| %>
  <%= form.text_field :title, placeholder: "タイトル" %><br>
  <%= form.text_area :content, placeholder: "投稿内容" %><br>
  <%= form.text_field :name, placeholder: "投稿者" %><br>
  <%= form.submit 'POST' %>
<% end %>
```

#### 4.保存機能
コントローラーの設定
```ruby:posts_controller
def index
  @posts = Post.all
end
def new
  @post = Post.new
end
def create
  Post.create(post_params)
  redirect_to action: :index
end

private
def post_params
  params.require(:post).permit(:title, :content, :name)
end
```

ルーティングの設定
```ruby:routes
root to: 'posts#index'
resources :posts, only: [:index, :new, :create]
```

実際に作ってみたところ一応形になりました！
今回の気付き
・ルーティング、コントローラーのアクションは初めから使うアクションが分かっていたので一度にindex,new,createを記述したほうが良いのか？

これから機能やレイアウトを追加していきながらさらに理解を深めていきます！
RailsでURLからidを取得する方法

## はじめに
RailsのCRUDを学習し直すために、簡易的な勤怠管理アプリを作成したため、自分用の備忘録としてまとめてみました。基本的なものだけを紹介しているので、より詳しく知りたいものについては適宜ご自身で調べながら読み進めて頂けると幸いです。

また、こちらはプログラミング初学者がまとめた記事となりますので間違っていることがあるかもしれません。その際はご指摘等頂けると幸いです。宜しくお願いします。

## 本記事の内容
Railsでよく使われる文法の解説。

## 対象者
Railsのparamsについての基礎が抜けていたので備忘録としてメモです<br>
もしかしたら間違っているところもあるかもしれないので、その際は優しく指摘頂けると幸いです🙇🏼‍♂️
# ``` find_by ```メソッドの使い方
特定のidの投稿を取得するために``` find_by ```を使う
```ruby
post = Post.find_by(id:3)
```
のような感じ<br>

こうすることによってデータベースから特定のidを持った値を取得できる

# ``` URLにidを含める 方法```
ルーティングをいじっていく
```ruby
get "posts/:id" => "post#show"
```
こうすることで特定のidを持った投稿の詳細ページに飛べる

# ``` params ``` の使い方
viewファイルのアクション内で```@id```のような形でインスタンス変数を作ってあげる
そこに```params[:id]```を代入する
``` ruby
@id = params[:id]

```
のような感じ<br>
viewファイルに``` <%= @id %> ```とすれば、idを表示できる
この考え方を応用して、
``` ruby
@post = Post.find_by(id: params[:id])

```





のように``` find_by ```と``` params ```
の合わせ技でURLに含まれるidを持った値を取得できる<br>
例えば```@post```を用いて``` <%= @post.content %> ```とすれば指定したidの内容を表示できる（contentカラムが存在する場合）

# ``` link_to ```について
``` link_to(リンクテキスト, リンク先URL) ```

# フォームの入力内容を受け取る方法
フォームから入力内容を受け取る際も``` params ```を用いて、

``` ruby
@post = Post.new(content:params[:content])

```
と取得できる<br>
paramsの後に指定する名前は``` <textarea>```などのフォームについている```name=" "```と紐づく

# ``` form_tag ```
Railsで投稿フォームを作成する場合に``` form_tag ```を用いると楽ができる<br>
全体を``` form_tag ```で囲み、その中に投稿用のHTMLを書く
``` ruby
<%= form_tag('/posts/create') do %>
   (中身)
<textarea></textarea>
<input type="submit" value="投稿する">
<% end %>
```
議事録は自分を守るための強力なツールなので、率先して書きましょう！

みなさん議事録書いてますか？
若手に雑に丸投げしてないですか？

私は社会人歴10年超えてますが、必ず自分で書いてます。
誰かが議事録を書いてたとしても書いてます。


# 理由：自分を守るため

議事録というのは<strong>自分を守るための盾</strong>です。

言った言わない問題というのは業界に関係なく良くあることだと思います。
言った本人は忘れて後日全く逆のことを言いだしたりして、余計な対応が発生したりすることもしばしば。。。

そんな時に、「あの時こう言いましたよね？ほら、ここ見てください！」って自信を持って反論できます！
  
まぁこれでも折れてくれないことも良くあるんですけどね。。。
ただ、「対応しても良いですけど、別工数ください」といった交渉はしやすくなるかと思います。
  


# 書くべきこと

何でもかんでも書いてると結局なにを話したんだっけ？ってなるので要点をしっかりとまとめましょう。
以下の項目は絶対に書かないとダメなことです。

- やると決まったこと
  - 担当者
  - 期限
- 要件等事項
- <font color="red">やらないと決まったこと</font>
  - その理由も書いておく
  - ※なんでやらないってなったんだっけ？ってなるので書いておいた方が良い



# 書いた後にやること

参加者に必ず議事録を展開すること！
そして、過不足・誤りあれば連絡もらうようにしてください。

せっかく議事録を書いても展開してみてもらわないと意味がないです。

また、ちゃんと内容確認したよね？という、無言の圧をかけておくことで後々議事録への文句を言われないようにしましょう！


# 私の議事録の書き方

- 会議の前
  - 議事録のひな型を作成
    - 日時
    - 場所
    - 参加者
  - 議題と要確認項目などを先に記載
  - 自分からの報告があればそれも記載しておく
    - 定例とかであれば、参加者にも事前に展開して書いてもらうのもあり
- 会議中
  - 議事録を画面共有しながら議題について話し合う
  - その場で要約して記載
    - 口語で殴り書き
- 会議後
  - すぐに参加者へ展開 
    - リアルタイムで画面共有してるので清書とかしない


# 最後に

議事録の書き方ってあまり教えてくれないので、数こなして慣れていきましょう。
上司の方は議事録のポイントとかもしっかり教えてあげて、書いてくれた議事録はちゃんとチェックしてポイントを指摘しましょう。


最近ではAIが議事録作成してくれるサービスもあるので、それを導入してしまうのもありだと思います。
ただ、作成された議事録はちゃんと見直しましょう。
FactoryBotでhas_oneの関連付けを表現する。traitの基本的な使い方。

FactoryBotでhas_oneの関連付けを表現するのってどうやるんだっけ？ってなったので自分用に備忘録を残しました。

traitという機能を使用しました。
今回はtraitの基本的な使い方➕作業の全体像を記しています。

参考にした記事

https://qiita.com/ShotaroHirose59/items/7c64be350676120de9bd


 ## 前提条件

CustomerがProfileをhas_oneしています。

```customer.rb
class Customer < ApplicationRecord
  has_one :profile, dependent: :destroy
end

```


```profile.rb
class Profile < ApplicationRecord
  belongs_to :customer
end

```

<br>

<br>

## 本題のコード

customerの方のFactoryBot

```spec/factories/customers.rb
FactoryBot.define do
  factory :customer do #各テストからcreate(:customer)で生成できるようになる

    trait :profile do #traitで条件を付与したものを生成できるようになる。create(:customer, :profile)の形で生成できる
      after(:build) do |customer|
        customer.build_profile
      end
    end
  end
end
```

after(:build)は、オブジェクトがメモリ上にビルドされた直後に、特定のアクションを実行するためのコールバックです。

つまり、この場合はブロック変数のcustomerがbuildされたもので、それがデータベースに保存される前にcustomer.build_profileをして、customerインスタンスに新しくprofileを紐づけています。


<br>

profileの方のFactoryBot
```spec/factories/profile.rb
FactoryBot.define do
  factory :profile do
    customer
  end
end

```

上記については
だいぶ省略されていて、
```
factory :profile do
  association :customer
end
```

このassociationメソッドが省略されています。
これによってProfileモデルがCustomerモデルに対してbelongs_toの関係を持つことをしめされています。


## テスト上での使い方

とてもシンプルな例。
自分で定義した「profile!」というインスタンスメソッドの挙動をテストしています。
CustomerがProfileを持っていないか確認してからprofileを作成するという内容のものです。
テストしたいインスタンスメソッドは以下の通り

```customer.rb
class Customer < ApplicationRecord
  has_one :profile, dependent: :destroy
end

def profile!
  return if profile?
  create_profile!
end
```

<br>

実際のテスト

```customer_spec.rb
require 'rails_helper'

RSpec.describe Customer do

describe 'profile!' do
    it 'profileを追加できる' do
      customer = create(:customer) #profileを持っていないので、profile!を実行したら追加できるはず
      expect { customer.profile! }.to change(Profile, :count).by(1) #count自体が増えることでそれを証明している
    end

    it 'customerが既にProfileを持っている場合は追加できない' do
      customer = create(:customer, :profile) #先ほどのtraitを使用して、既にprofileを持ったcustomerを生成している。
      target_id = customer.profile.id #has_oneのものは新しく生成されると更新されてしまうので、現在のprofileのidを比較するために変数に格納しておく
      customer.profile!
      expect(Profile.exists?(id: target_id)).to be true #既にprofileがあるなら生成されずに同じidのインスタンスを保持しているはず
    end
  end
end
```

has_oneの挙動についても理解が浅く実装に少し苦戦しました。
次回はこの記事読んでささっと実装できたら良いな〜と思っています。

間違い、こうするともっと良いなどがあったらぜひご指摘していただけると幸いです。
【UE4】【UE5】プロジェクトランチャーのLaunchingUATでのエラー

ここではプロジェクトランチャーでパッケージ化しようとしてエラーが発生した際にエラーの原因が少しわかりずらく検索してもヒットしなかったのでメモがてら記載します。

## 通常のパッケージ化
- UE4ならエディタのメインメニューで [File] > [Package Project] > [プラットフォーム名] の順にクリックをしてパッケージ化を行います。
- UE5ならエディタ上の[プラットフォーム] > [プラットフォーム名] > [プロジェクトをパッケージ化]でパッケージ化を行います。

ただこれだとプロジェクト設定でDevelopment・Shippingを切り替えて配布用のチェックを外してといった変更を行わないといけません。
コマンドラインを使ってパッケージ化を行ってもいいですがエディタを開いたままだとエラーしてパッケージ化出来ないといった問題もあります。

そこでプロジェクトランチャーを使う事で開発用・本番用といった状況に合わせた設定を別々に用意する事でパッケージ化のたびに設定を変える手間を無くす事が出来ます。

またプロジェクト設定のiniファイルを変更せずにパッケージ化を行えるので、svn・gitといったバージョン管理ツールを使ってプロジェクトを管理しているとiniファイルに差分が生まれてしまいます。それをアップしてしまうと他の方の環境で競合が発生してしまうといった事を起こります。

プロジェクトランチャーで用意したパッケージ化の設定はプロジェクトフォルダ内に生成されずローカル環境のPC内で管理されているので差分が発生する事もありません。(設定ファイル自体を受け渡しすれば別のPCに設定を持っていく事も出来ますがここでは割愛)

プロジェクトランチャーの設定については公式や有志の方がブログ等で情報を書いてくれていのでここでは書きません。

## 私が出会ったエラー

**バージョン管理外のビルドはインクリメント出来ません。と言われてプロファイルの起動が出来ない**
厳密にはエラーではないですが。。
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2723177/42d80622-eff6-18ea-5362-780bbfe5c8bf.png)
 -> パッケージ > このビルドは一般配布用ですかのチェックボックスにチェックを入れる
 ![タイトルなし3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2723177/d07c62d0-7ce6-e5e6-42b5-fa5cace8effe.png)
もしくはクック > バージョン情報なしでパッケージを保存するのチェックを外す
![タイトルなし4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2723177/d320dc8d-4d4a-0e34-4dae-151f795b4ad8.png)
どちらかの対応を行うとプロファイルの起動が出来るようになるはずです。

**LaunchingUATでエラーが発生**
Can't use iterative cooking / deploy on dlc or patching or creating a release
![タイトルなし5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2723177/9bee4ece-0a5a-d179-9c9d-795ec8b8ab7d.png)

- ディストリビューション用にゲームのリリースバージョンを作成にチェックを入れる
- これが基づくリリースバージョンです。の項目にバージョンを入れる
![タイトルなし6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2723177/63eef9a3-e49c-b205-01a4-c256b3aa1181.png)
このような設定でパッケージ化を行うとLaunchingUATでエラーが発生してしまいます。
リリースバージョンの項目はパッチ・DLCを作成する際の差分チェックの為に使用される為の物のようなのでパッチの作成もしくはDLCをビルドにチェックが入っていない状態でリリースバージョンを入力するとエラーしてしまうみたいです。
なのでパッチとDLCにチェックを入れていない場合はリリースバージョンの項目は空にしておく必要があります。
Unity 2022 Navmesh マップチップ

# Unity 2022ではNavigation AIの作成方法が変わった。
これにより、各オブジェクトにコンポーネントとしてNavigation Surfaceを追加し、Bakeすることになった。

自分は3Dのマップの一部ををPrefab化し、Resoucesから読み込み、
マップチップとして自動生成していたのだが、Prefab内でBakeしてもうまくいかない。(Bakeの範囲が見えない)

現状SceneのHierarchy内でBakeするとうまくつながった。動的生成でBakeする方法もしらべなきゃな...。


# 追記
親オブジェクト1つにNavigation Surfaceを設定し、Bakeするだけで出来ました...！！
Datadog ログ・パース規則の書き方を忘れた時つかう機能

# Datadog ログ・パース規則を自動で生成してくれるメニューってどこにあるの？
Datadog Logs Pipeline でテキストログから特定のキーワードを検出してその時の値をメトリック化できます。テキストログから値を抽出するためのパース規則［Define parsing rules］の設定を覚えきれず、ログサンプルを[MATCH]させるまでにあれこれと試して無駄な時間を費やしてしまうことがあります（私だけ？）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/d73e6480-8883-d34d-a7b4-a139b64d77a2.png)


[パース規則のサンプルはこちらの公式で紹介されています](https://docs.datadoghq.com/ja/logs/log_configuration/parsing/)

## [Show Parsing rule]
こんなときに便利なのが、パース規則を自動で生成してくれる［Show Parsing Rule］機能です。ではこの機能はDatadogポータルのどこにあるのでしょうか？　いつも使っていればともかく、いつも探し回って見つからないとここでも時間を費やしてしまいます。

自分のためにもここにパース規則を自動で生成してくれる［Show Parsing Rule］への道のりを残します。将来、GUIが変わっていたら申し訳ないです。

## パース規則を定義したい
ログ・パイプラインでサンプルのテキストログをコピペで貼り付けて、パース規則を書いて合致したら［MATCH］と表示されます。このパース規則を書きたい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/7a172229-7eea-74b3-bfac-f069d80f3698.png)

## 対象のログを見つけます
Datadogポータルのメニュー [Logs] > [Search] でログ・エクスプローラーに表示される対象ログを探します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/a76fb876-b2e9-8762-a61d-771f2736bb98.png)

対象ログが見つかったら、そのログをクリックして詳細が表示されます。この画面では[Show Parsing rule]メニューが見つからないのです。ここにはないので［X］をクリックして戻ります.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/bb3c8183-36a8-5cb3-ee3c-0db41d30e1cc.png)

## ログをパターン形式で表示
グループの[Patterns]を選んでパターン形式でログを表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/24fd222a-ee83-65b4-373c-adc72ad8aa5b.png)

そしてログをクリックします...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/a2105eff-fba0-9000-cdbe-2bc36400df40.png)

すると右上に探していた[Show Parsing Rule]が見つかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/d0949989-cfac-b850-9bd5-edabcbea4b5d.png)

クリックするとテキストログに対応したパース規則が表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/2747f8c7-d2c8-f0da-9650-e41cd81238de.png)

自動生成されたパース規則をコピーして、ログ・パイプラインで続きを設定します。
どうせなら Grok Parser の画面にあるといいなと願いつつ。

以上、備忘録でした。
AppleScriptプログラムを定時に自動実行する方法[Macのみ]

最近Qiitaの記事投稿のやる気が出てきたので投稿。

筆者は現在、AppleScriptとJavaScriptを使って、国内上場企業の株式情報を自動取得する自作プログラムを運用しており、現在は手作業で実行しているのだが、実行まで自動化したいと思い方法を再確認。

# 手順1 ：AutomatorでAppleScriptファイルを実行出来る状態にする
Automatorアプリを開き、"アプリケーション"で新規書類を作成します。

![スクリーンショット 2024-04-09 20.38.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982162/b4ec3968-8f68-ae1b-39d0-053e520a3c82.png)

新規書類を作成しますと、以下のような画面になりますので、こちらの"AppleScriptを実行"を選択。

![スクリーンショット 2024-04-09 20.42.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982162/87ae3467-61b0-965e-5cb2-9395b0b6c586.png)

すると下記画面が出てきます。

![スクリーンショット 2024-04-09 20.43.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982162/ac87bd61-8630-35d4-df87-839248417b90.png)

こちらのボックスの中にある記述を全て削除し、下記のように修正します。
モザイクがかかっている部分は、自分が作成したAppleScriptファイルの絶対パスを入力してください。

![スクリーンショット 2024-04-09 21.06.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982162/94d40ba9-f75d-25d3-462b-1fb331210a37.png)


ここまで完了しましたら、書類を保存します。


![スクリーンショット 2024-04-09 21.10.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982162/f10cc6f2-2590-384f-8a4f-e62c0644786c.png)

# 手順2： カレンダーより自動実行の設定をする

カレンダーアプリを開いてください。以下のような画面になります。

![スクリーンショット 2024-04-09 21.20.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982162/38a8fc97-1d45-4586-f262-c2801dab6a2b.png)

お好きな日付をクリックすると、以下のメニューが出てきます。開始時刻に実行したい日時を入力してください。

![スクリーンショット 2024-04-09 21.22.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982162/974a41f7-c048-c289-215d-29ef9f235979.png)

次が本番です。メニュー内に、「通知」という項目があります。こちらを選択し、各プルダウンごとに、次を選択してください。
1番上・・・ファイルを開く
2番目・・・先ほど作成した書類(Automatorファイル)
3番目・・・イベントの開始時刻

この状態でOKを押下してください。

![スクリーンショット 2024-04-09 21.23.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982162/5e0b4901-fffd-cd34-f7c1-9388cbb6de9c.png)

以上で、AppleScriptプログラムの自動実行手順は終了です。
こちらを毎日実行したい場合は、カレンダーアプリ内で該当イベントの繰り返しを、「毎日」に設定すればOKです。
該当日時になれば指定のAppleScriptプログラムが実行されるはずです。


以上となります。
Xでも有益な情報を呟いているつもりですので、フォローよろしくお願いいたします。

https://twitter.com/DB_sirro_SE
ZED SDK をDocker環境の中でインストールする

画像認識の環境構築にdocker を使うことがある。（たとえばJetson 用のcudaを使ったpytorchの環境構築）
そういう場合にもZED SDK を使いたいと思う。

## 想定する読者
- docker 環境を起動したことがある人
- stereoLabs のカメラ　zed2iなどを利用している人

## 実施したこと
- Dockerfileの中でZED SDK のインストールを記述。
- docker build の実行
- docker run の実行
- docker runの実行後の環境内で、zed sdk を利用するプログラムの実行。

## ベースとなるDockerImage
Jetpack5.1では
L4T 35.2.1 です。
それによって、CuDNN, CUDA, TensorRTのバージョンは固定されます。
それに対応するpytorch のバージョンが固定されます。
以下の例では、次のDockerImageをベースとしています。

```
FROM nvcr.io/nvidia/l4t-pytorch:r35.2.1-pth2.0-py3
```
## Dockerfile の中に追記したこと
- StereoLabs で提供しているインストーラーをダウンロードする。
- zstd: Zstandard - Fast real-time compression algorithm
    - https://github.com/facebook/zstd
- ZED SDK のインストーラーは zstd がインストール済みであることを前提とする。

```
(追加分だけを記入してます。これだけでは動作しません)
RUN wget -O ZED_SDK_Tegra_L4T35.3_v4.1.0.zstd.run https://download.stereolabs.com/zedsdk/4.1/l4t35.2/jetsons
RUN chmod +x ZED_SDK_Tegra_L4T35.3_v4.1.0.zstd.run
RUN apt install zstd
RUN ./ZED_SDK_Tegra_L4T35.3_v4.1.0.zstd.run -- silent
```

#### 改善を要する点
- wget で指定しているURLが、いつまでそのバージョンに*.run ファイルになっていてくれるかがわからない。

## 確認方法
- 以下の方法でzed sdk のインストールができたことを確認できる。

```
python3
import pyzed.sl as sl
zed = sl.Camera()
print(zed.get_sdk_version())
```

## うれしいこと
#### Dockerなしの環境では
- Jetson のホスト環境自体を意図しない改変を引き起こしかねない。
- 新しいバージョンのライブラリを安全に試すことができない。
#### Dockerの環境では
- Jetson のホスト環境自体を破壊することなく、ソフトウェアのインストールができる。
- apt install するライブラリを記述できるので、環境構築が楽になる。
#### ZED SDK をもDockerfile に記述できる利点
- ZED SDK のインストール手順も docker build で実行できる。
- ホスト環境のライブラリにアクセスするために、ホスト環境のライブラリをマウントするなどという変則的なことをしなくて良い。
Azure Static Web Apps CLI で Node.js バージョンエラーが出た場合の回避策

# 発生環境

- Windows11/MacOS Sonoma
- Node.js 20系全て
- SWA CLI バージョン問わず

# 回避策

急いでいる人向けです。原因は Azure SWA CLI のバグなので、強引に直す必要があります。func-core-tools.js ファイルをエディタで開きます。

Windowsの場合(youraccountは自分のものに修正してください)
- C:\Users\youraccount\AppData\Roaming\npm\node_modules\@azure\static-web-apps-cli\dist\core\func-core-tools.js

MacOS の場合はどんなツールでどこに Node.js をインストールしたのか次第でパスが異なります。私の場合は Homebrew で Node.js をインストールしていたので、次の場所でした。
- /opt/homebrew/lib/node_modules/@azure/static-web-apps-cli/dist/core/func-core-tools.js

次の箇所を直します。41行目ぐらいです。

```diff_javascript:func-core-tools.js一部抜粋
function isCoreToolsVersionCompatible(coreToolsVersion, nodeVersion) {
    // Runtime support reference: https://docs.microsoft.com/azure/azure-functions/functions-versions?pivots=programming-language-javascript#languages
    switch (coreToolsVersion) {
        case 4:
-           return nodeVersion >= 14 && nodeVersion <= 18;
+           return nodeVersion >= 14 && nodeVersion <= 20;
        case 3:
            return nodeVersion >= 10 && nodeVersion <= 14;
        case 2:
            return nodeVersion >= 8 && nodeVersion <= 10;
        default:
            return false;
    }
}
```

保存すれば問題なく動作するようになります。SWA CLI をアップデートすると、このファイルは元に戻ってしまいますので、また同じ修正をしてください。

# エラー発生

久しぶりに Azure Static Web Apps CLI 使って React + Azure Functions アプリをローカルで動かそうとしたらこんなエラーが出るようになって焦りました。

```bash
✖ Found Azure Functions Core Tools v4 which is incompatible with your current Node.js v20.10.0.
✖ See https://aka.ms/functions-node-versions for more information.
```

何やら非対応のバージョンでも使っているかのようなエラーです。確認すると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/58a097de-8e34-98f0-b9c2-95441c18de97.png)

Node.js 20.x はサポートされていますね。変ですね。

https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-reference-node?tabs=javascript%2Cwindows%2Cazure-cli&pivots=nodejs-model-v4#supported-versions

自力で色々やっても解決できず、検索していたら回避策の記載を見つけましたので共有します。こちらのスレッドがこの件についての issue と回避策が書いてあります。

https://github.com/Azure/static-web-apps-cli/issues/756

SWA CLI 実行時に Azure Functions Core Tools を使用する場合はインストールしてある Node.js とのバージョンチェックをかける箇所があり、そこで Node.js のバージョンは 18 以下ではないとダメ、となっているのです。

func-core-tools.js ファイルの中に次のように実装されています。

```javascript:func-core-tools.jsの一部抜粋
function isCoreToolsVersionCompatible(coreToolsVersion, nodeVersion) {
    // Runtime support reference: https://docs.microsoft.com/azure/azure-functions/functions-versions?pivots=programming-language-javascript#languages
    switch (coreToolsVersion) {
        case 4:
            return nodeVersion >= 14 && nodeVersion <= 18;
        case 3:
            return nodeVersion >= 10 && nodeVersion <= 14;
        case 2:
            return nodeVersion >= 8 && nodeVersion <= 10;
        default:
            return false;
    }
}
```

case 4 の時、つまりAzure Functions Core Tools のバージョンが4の時の Node.js のバージョンは 14 以上18 以下、と実装されています。この 18 を 20 に変更して保存すれば良いのです。

このファイルの場所については上に記載しておいたのでそちらをご確認ください。

# いつ直るのか

こちらの issue は 2023 年 10 月にオープンして、半年ほど経過した 2024 年 4 月の現在もまだ修正バージョンがリリースされていません。

https://github.com/Azure/static-web-apps-cli/issues/756

いつ直るのか全く見込みが立っていないので、しばらくはこの方法で回避するしかなさそうです。
global命令, static命令

## はじめに
PHPのglobal命令, static命令に関して整理する。

### global命令

ローカル変数を強制的にグローバル変数に割り当てる。

```php:global.php
$x = 10;

function checkScope() {
    global $x;
    return ++$x;
}

print checkScope(); // 11
print $x; // 11 
```
### static命令

静的変数を定義する。

```php:static.php
function checkStatic() {
    Static $x = 0;
    return ++$x;
}

print checkStatic(); // 1
print checkStatic(); // 2
print $x; // null
```
【Rails】erbからslimへ変換したい方へ

## はじめに

みなさん`slim`はお好きでしょうか？

`erb`から`slim`への変換をしてくれる便利な`html2slim`というgemがあるのですが、非推奨のメソッドが使用されている関係で警告が出ていました。

それだけでなく、一部のファイルが変換できない現象があったため解決しようと試みました💡

:::note warn
ご覧いただきありがとうございます!
この記事の投稿者は主にRuby on Railsを学習している初学者です。
理解不足な点や内容に誤りがございましたらご指摘いただけますと幸いです。
:::

## 問題
```
NoMethodError: undefined method `exists?' for class File
```
exists?メソッドが非推奨（そして最終的に削除された）ために発生しているようです。
現在は`File.exists?`の代わりに`File.exist?`を使用するのだそうです。

詳しいことまではわからないのですが、ライブラリの記述で起きている問題のため、本家のgemの更新を待つ他にはないようです。

## 解決方法
有志の方がgemを修正して公開してくださっています。
使用できるコマンドは本家と同じようです。
(使用される際はドキュメントをご一読ください)

https://rubygems.org/gems/html2slim-ruby3


## 終わりに
あまり頻繁に更新されていないのが残念なのですが・・・この箇所は`slim`で記述したらどうなるんだろう？と思った時にコマンド1つで変換してくれる便利なgemです。

1箇所だけなら直接ライブラリの編集を試みようかとも思ったのですが、また次の機会にトライしてみたいと思います💡

最後までお読みいただき、ありがとうございました🙇
## 参考

https://github.com/slim-template/html2slim

https://rubygems.org/gems/html2slim-ruby3