OmniAICreator/Qiita-1.07M huggingface dataset:
【Sajya】Laravel Sajyaの簡単な使い方まとめ

# Laravel Sajyaの導入から基本的な使い方まで
使い方を簡単にまとめたものになります。
英語が得意な方は公式をご覧ください。

## Laravel Sajyaとは
Laravelフレームワーク向けにJSON-RPC 2.0サーバーの仕様を簡単に実装することを目指したオープンソースプロジェクトだそうです。API作成に便利かも？

### 導入
まずは、Laravel Sajyaをプロジェクトに導入します。以下のコマンドを実行して、Sajyaをインストールします
```terminal:ターミナル
composer require sajya/server
```
### Procedureファイル作成
以下のコマンドでファイルを作成します
```terminal:ターミナル
php artisan make:procedure TestProcedure
```
作成したファイルにテスト用のコードを入力します（メソッド以外ほぼ自動生成されます）
```php
declare(strict_types=1);

namespace App\Http\Procedures;

use Sajya\Server\Procedure;


class TestProcedure extends Procedure 
{
    /** 
     * The name of the procedure that will be 
     * displayed and taken into account in the search 
     */ 
    public static string $name = 'test';

    /**
     * Execute the procedure.
     *
     * @return string
     */
    public function ping()
    {
        return 'pong';
    }
}
```


### ルートの設定(エンドポンイント)
次に、Sajyaのルートを設定します。routeファイルに以下のコードを追加します
```php
use Illuminate\Support\Facades\Route;
use App\Http\Procedures\TestProcedure;

Route::rpc('/v1', [TestProcedure::class])->name('rpc.endpoint');
```

上記のコードでは、/v1というエンドポイントに対して、TestProcedureクラスを割り当てています。

### APIテスト
まずは、ローカル環境のサーバーを立ち上げます。

次にcurlを用いてリクエストを送信します。（私はGitBashを使用していますが、自分の環境に合わせてください） 

```terminal:ターミナル
curl --location --request POST 'http://127.0.0.1:8000/api/v1'
--header 'Content-Type: application/json'
--data-raw '{ 
        "jsonrpc":"2.0",
        "method":"test.ping",
        "id":1
}'
```

※Postmanのようなツールを使えばもっと簡単ですし、毎回コマンド打たなくても良くなります。

成功すれば下記のようなレスポンスが返ってきます。
```json
{
    "id": "1",
    "result": "pong",
    "jsonrpc": "2.0"
}
```

### エラーハンドリングについて
Exceptionファイルを作成し、throwします

### Excepotionファイル作成
以下のコマンドでファイルを作成します
```terminal:ターミナル
php artisan make:exception ErrorTest
```

次に、テスト用にコードを入力します（ほとんど自動生成されます）
```php
namespace App\Exceptions;

use Sajya\Server\Exceptions\RpcException;

class ErrorTest extends RpcException
{
    /**
     * Get the default error message for the exception.
     * @return string 
     */ 
    protected function getDefaultMessage(): string
    {
        return 'Error Message Daze'; 
    }
    
    /**
     * Get the default error code for the exception.
     * @return int
     */
    protected function getDefaultCode(): int
    {
        return -13000;
    }
}
```
### Procedureファイル編集
先ほど作成したProcedureファイルを以下のように編集します
```php
namespace App\Http\Procedures;

use App\Exceptions\ErrorTest; 
use Sajya\Server\Procedure;

class TennisProcedure extends Procedure
{
    public static string $name = 'test';
    
    public function ping()
    {
        throw new ErrorTest();
    }
}
```
直接throwしていますが、条件を付けることももちろん可能です。
これでリクエストを送信すると以下のようなエラーレスポンスが返ってきます。
```json
{ 
    "id": "1",
    "error": {
        "code": -13000,
        "message": "Error Message Daze."
        ....
    },
    "jsonrpc": "2.0"
}
```

### 参考サイト 

https://sajya.github.io/

---
記事を読んでくださった方は、是非弊社開発課のXもフォローしてね:pray:
毎日エンジニアに向けた情報発信を行っています:muscle:

https://twitter.com/tech_cin
【VBA】DAOとADOの違い

# はじめに
ExcelやAccessからVBAでデータベース接続をする方法を調べていると、
よく目にするのが __DAO__ と __ADO__ ですよね。

接続方法がちがう？みたいなことは知っていましたが、
今まであまり違いを意識せずに使用していたのでそれぞれの違いをまとめてみました！

# DAOとADOって？
>#### DAO（Data Access Objects）
>Accessで使用されるデータベースを操作するためのアクセス方法

>#### ADO（ActiveX Data Objects）
>外部のデータベースやファイルに接続して操作するためのアクセス方法

# DAOは処理がはやい？
DAOはAccessに特化しているのでADOよりも処理が速いそうです。
どれくらい処理速度に差があるのか検証をしてみました。

## ■ 検証方法
DAOとADOでCSVファイルを取り込むコードを作成します。

同じAccessとCSVファイルを使用し、検証ごとにデータは削除・最適化します。
取り込むCSVファイルは100万行（78MB）のサンプルデータです。

### 参照設定
DAOとADOを使用するにはそれぞれ事前に「参照設定」を行う必要があります。
参照設定はVBE（Visual Basic Editor）から下記の画像の通りに開くことができます。
それぞれのライブラリファイルにチェックを付けてOKをクリックしてください。

DAO：Microsoft Office x.x Access databese engine Object Library
ADO：Microsoft ActiveX Data Objects x.x Library
（x.xはバージョン番号、数字が大きいものを選択します）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576431/33f6d80c-7963-bfb0-14bb-18cda7076b3f.png)



### 各コード
#### DAO

```vb:DAO
Sub DAOインポート_Click()

    ' 処理時間測定用
    Dim stTime As Double
    Dim edTime As Double
    
    Dim db As DAO.database
    Dim Path As String
    Dim File As String
    Dim sql As String

    ' ACCESSに接続
    Set db = CurrentDb

    ' CSVファイル情報取得
    Path = CurrentProject.Path
    File = "test.csv"

    ' SQLを実行し、CSVファイルをインポート
    sql = "SELECT * INTO T_DAO FROM [" & File & "] IN '" & Path & "' 'Text;HDR=YES'"
    db.Execute sql

    ' 処理時間測定
    edTime = Timer
    t = edTime - stTime
    MsgBox "DAO処理時間：" & t
    
End Sub
```
***
#### ADO

```vb:ADO
Sub ADOインポート_Click()

    ' 処理時間測定用
    Dim stTime As Double
    Dim edTime As Double
    Dim t As String 
    stTime = Timer
    
    Dim cn As ADODB.Connection
    Dim Path As String
    Dim File As String
    Dim sql As String

    ' ACCESSに接続
    Set cn = CurrentProject.Connection

    ' CSVファイル情報取得
    Path = CurrentProject.Path
    File = "test.csv"

    ' SQLを実行し、CSVファイルをインポート
    sql = "SELECT * INTO T_ADO FROM [" & File & "] IN '" & Path & "' 'Text;HDR=YES'"
    cn.Execute sql

    ' 処理時間測定
    edTime = Timer
    t = edTime - stTime
    MsgBox "ADO処理時間：" & t
    
End Sub
```

## ■ 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576431/06f799eb-a631-ba7d-d4b8-336c6c32f5c0.png)

若干の差ではありますが、DAOの方が処理速度は速くなりました！

## ■処理速度に差が出る理由は？
__DAO__ では「Jetデータベースエンジン」というAccess固有のデータベースエンジンを使用して接続しています。
__ADO__ では「OLE DB」という複数のデータベースへのアクセスを統一化した方法を使用しており、Accessやデータベースに接続しています。

DAOは初期からAccessで使われていたアクセス方法であり、ADOはAccess2000から採用されたアクセス方法です。
DAOはADOよりも古いアクセス方法ではありますが、 __DAOはAccessに特化した機能__ であるため処理が速くなっています

# まとめ（個人的な感想）
結果としてはDAOの処理速度が速かったですが、個人的にそこまで大きな差ではないかなと思いました。（もちろんデータ量にもよりますが）

もっと大きなデータを操作するのであれば処理速度の差が大きくなるかと思いますが、
Access自体の容量の上限が2GBなので、Access内で大きいデータを使用するよりも別の方法を考えた方がいいかなと個人的には思います。

使用するのがAccessのみと決まっている場合はDAO、それ以外にも接続する場合はADOと覚えておくと良いかと思います！

# ご案内
株式会社ジールでは、「ITリテラシーがない」「初期費用がかけられない」「親切・丁寧な支援がほしい」「ノーコード・ローコードがよい」「運用・保守の手間をかけられない」などのお客様の声を受けて、オールインワン型データ活用プラットフォーム「ZEUSCloud」を月額利用料にてご提供しております。
ご興味がある方は是非下記のリンクをご覧ください：
https://www.zdh.co.jp/products-services/cloud-data/zeuscloud/?utm_source=qiita&utm_medium=referral&utm_campaign=qiita_zeuscloud_content-area
Nuxt3で、複数の同一コンポーネント内でほぼ同時にAPIを叩くと結果が同期？された

# はじめに
Nuxt3で、以下をやろうとしていました。
- 親コンポーネントで`id`の配列を持っている
- それを`v-for`して子コンポーネントに`id`を渡しつつ子コンポーネントを複数表示する
- 子コンポーネントの中で`id`を引数に取るAPIをコールし、返り値を表示する

このとき`id`ごとにAPIの返り値は異なるはずなのですが、表示される結果がすべて同じになってしまいました。
一応解決まで行けたので共有します。

# 環境
```json:package.json
{
  "name": "nuxt-app",
  "private": true,
  "type": "module",
  "scripts": 省略,
  "dependencies": {
    "nuxt": "^3.10.3",
    "vue": "^3.4.21",
    "vue-router": "^4.3.0"
  }
}

```

# 再現するソースコード
```vue:./pages/index.vue(親コンポーネント)
<template>
  <div>
    <ChildComponent v-for="id in [1, 2, 3, 4]" :key="id" :id="id" />
  </div>
</template>
```

```vue:./components/ChildComponent.vue(子コンポーネント)
<template>
  <span>{{ userName }}</span>
</template>

<script setup lang="ts">
const { id } = defineProps<{ id: number }>();

const userName = ref<string | null>(null);
useFetch<string>('/api/fetchName', {
  method: 'POST',
  body: { id }
}).then((res) => {
  userName.value = res.data.value || null;
});
</script>
```

```typescript:./server/api/fetchName.ts
export default defineEventHandler(async (event): Promise<string> => {
  const { id } = await readBody(event);

  if (id === 1) return 'a';
  if (id === 2) return 'b';
  if (id === 3) return 'c';
  return 'd';
});
```

上記コードで表示される期待値は以下だが、
```
abcd
```

実際は以下になる
```
dddd
```

# 解決方法
理由は分からないですが、以下2点を修正することで解消しました。
- APIコールを`onMounted`内で行う
- それに伴い、`useFetch`ではなく`$fetch`を使う

# 修正後のソースコード
```diff_vue:./components/ChildComponent.vue(子コンポーネント)
<template>
  <span>{{ userName }}</span>
</template>

<script setup lang="ts">
  const { id } = defineProps<{ id: number }>();

  const userName = ref<string | null>(null);
+ onMounted(() => {
-   useFetch<string>('/api/fetchName', {
+   $fetch<string>('/api/fetchName', {
      method: 'POST',
      body: {id}
    }).then((res) => {
-     userName.value = res.data.value || null;
+     userName.value = res || null;
    });
+ });
</script>
```

# おわりに
解決はしましたが、原因が全く分かっていないので分かるいらっしゃれば教えて頂きたいです。
ライフサイクルの問題か、useFetchの内部処理(キャッシュ等)の問題かと思っていますが...
モバイルアプリをストアからダウンロードできない



+ [my customer in China found some models of mobile phones are restricted from download SF1 from GooglePlay, because these models are domestic version, so they don't connect to the world of app marketplace(googleplay). ](https://trailhead.salesforce.com/trailblazer-community/feed/0D53A00003FN6oQSAT)
+ [FSL app is not available in the local chinese playstore. The only option is to either use something like Citrix vpn or use iOS.](https://trailhead.salesforce.com/trailblazer-community/feed/0D53A00003i36axSAA)
+ [China AppStore - Can't download Salesforce Mobile App](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007YwQRXSA3)
Rails + Vue.js：ドキュメントのロード完了後にVueアプリをマウントする方法

RailsとVue.jsを組み合わせたアプリケーション開発では、ページのDOMが完全にロードされてからVueインスタンスをマウントすることが重要です。特にRailsのビューで`javascript_pack_tag`や`vite_javascript_tag`を使う際にこの問題は顕著になります。この記事では、DOMのロード完了を待ってからVueアプリケーションをマウントする方法と、そうしない場合の違いについて解説します。

## `DOMContentLoaded` を使用する理由

```javascript
document.addEventListener('DOMContentLoaded', () => {
  const calendarEl = document.getElementById('weekly-calendar');
  if (calendarEl) {
    createApp(WeeklyCalendar).mount(calendarEl);
  }
});
```

上記のコードでは、`DOMContentLoaded` イベントリスナーを使用しています。このイベントは、HTMLドキュメントが完全に読み込まれ、解析された後に発生しますが、画像やスタイルシートなどは待ちません。このイベントを待つことで、Vueコンポーネントをマウントする際に、必要なDOM要素が確実に存在することを保証します。

## 即時マウントとの違い

```javascript
const app = createApp(WeeklyCalendar);
app.mount('#weekly-calendar');
```

こちらは即座にVueアプリケーションをマウントしようとするコードです。これが正常に機能するためには、このスクリプトが実行される時点でDOM要素`#weekly-calendar`が存在している必要があります。通常、これを保証するためにはスクリプトを`</body>`タグの直前に配置することが一般的です。

## 実際にはどちらの方法を使うべき？

ViteやWebpackなどのモダンなフロントエンドツールを使用している場合、`type="module"`を使用したモジュールスクリプトは、デフォルトで`defer`属性が適用されるため、DOMが準備できるまでスクリプトの実行が遅延されます。このため、`DOMContentLoaded` イベントを待つ必要はなく、上記の即時マウントコードで十分です。

しかし、スクリプトが早期に実行される可能性がある場合や、スクリプトのロードと実行のタイミングを明示的に制御したい場合は、`DOMContentLoaded`イベントリスナーを使用した方が安全です。

## まとめ

RailsとVue.jsを組み合わせて開発する際は、Vueインスタンスをマウントするタイミングに注意が必要です。DOMが完全にロードされたことを確認してからマウント処理を行うことで、予期せぬエラーを避け、アプリケーションの安定性を高めることができます。


## [補足]コード解説
```javascript
document.addEventListener('DOMContentLoaded', () => {
  const calendarEl = document.getElementById('weekly-calendar');
  if (calendarEl) {
    createApp(WeeklyCalendar).mount(calendarEl);
  }
});
```

1. **`document`**: これはHTMLドキュメント全体を指します。ブラウザ内で表示されるページをJavaScriptが操作するときのエントリーポイントです。

2. **`addEventListener`**: これは、特定のイベントが発生したときに実行される関数をドキュメントに追加するメソッドです。これを使って、イベントリスナーを設定します。

3. **`DOMContentLoaded`**: このイベントは、ページ全体のHTMLが完全に読み込まれ、DOMツリーが構築された後に発生しますが、スタイルシート、画像、サブフレームの読み込みは待ちません。このイベントは、ページのロードが完了してDOM操作が安全に行えることを示すために使用されます。

4. **`() => {}`**: これはアロー関数と呼ばれ、短い関数を定義するためのJavaScriptの構文です。`addEventListener`の第二引数に渡され、`DOMContentLoaded` イベントが発生したときに実行されます。

5. **`const calendarEl = document.getElementById('weekly-calendar');`**: この行では、`id`が`'weekly-calendar'`であるHTML要素をドキュメントから取得し、その要素への参照を`calendarEl`という定数に代入しています。

6. **`if (calendarEl) {...}`**: ここで、`calendarEl`が実際に存在するかどうかをチェックしています。つまり、`getElementById`が`null`を返さなかった場合（要素が見つかった場合）、カッコ内のコードが実行されます。

7. **`createApp(WeeklyCalendar).mount(calendarEl);`**: これはVue 3の構文で、`WeeklyCalendar`というVueコンポーネントを初期化しています。`createApp`はVueアプリケーションインスタンスを作成し、`mount`メソッドはそのアプリケーションを指定されたDOM要素（この場合は`calendarEl`）にマウント（つまり、描画やDOMに反映）します。

簡単にいうと、このコードはページのHTMLが完全にロードされたら実行され、`id`が`'weekly-calendar'`のHTML要素を見つけ、その要素に`WeeklyCalendar`コンポーネントをマウントします。これにより、コンポーネントが表示されるべき場所にVueアプリケーションが表示されることが保証されます。
【Swift】専門家に処理を依頼するDelegate

# 目次
[1.Delegateとは？](#Delegateとは？)
[2.実例](#2-実例)
[3.おわりに](#3-おわりに)

# 1. Delegateとは？
Swiftを勉強していると、初期段階でつまずくのが`Delegate`。
日本語で言うと`委譲`、`委ねる`です。
近年の、オブジェクト指向プログラミングでは、１クラス１機能に特化したクラス設計を行うことが多いです。いわば***その機能の専門家***クラスを作って、使いたいところで呼べば良いよね？という思想です。
Swiftも同様に、他のクラスへ処理を委譲(専門家に処理を任せる)して実装させることが多いです。
そんな時に便利なのが`Delegate`です。

# 2. 実例
コードを見ていきます。
## コード
~~~swift: MainClass.swift
protocol mainDelegate {
    func printIntro()
}

class MainClass {
    var delegate: mainDelegate?
    
    func introduce() {
        delegate?.printIntro()
    }
}
~~~

~~~swift: Name.swift
class Name: mainDelegate {
    let name = "田中圭"
    func printIntro() {
        print("名前は\(name)です。")
    }
}
~~~
~~~swift: Job.swift
class Job: mainDelegate {
    let job = "俳優"
    func printIntro() {
        print("職業は\(job)です。")
    }
}
~~~
~~~swift: Hobby.swift
class Hobby: mainDelegate {
    let hobby = "スキューバダイビング"
    func printIntro() {
        print("趣味は\(hobby)です。月に１回はいきます。")
    }
}
~~~
`Delegate`を使用してそれぞれの専門家に処理をお願いしています。
名前を言いたい時は名前を出力する専門家である、Nameクラス、
趣味を言いたい時はその専門家であるHobbyクラスといった具合です。
もしこれらの機能を一気にメインクラスに持たせたいのであれば、***クラスの継承***を行います。
:::note info
Delegateを使うと、「呼び出し元の関数がスッキリ書ける」、「処理の記述を分散させることができる」というメリットを教授できます！
:::
playground用にまとめました。
~~~swift:ForPlayground.swift
protocol mainDelegate {
    func printIntro()
}

class MainClass {
    var delegate: mainDelegate?
    // 外部からdelegateを渡し忘れないようにコンストラクタインジェクションを使用
    // https://mama-lifestyle.jp/swift-dev-jp/di/
    init (delegate: mainDelegate) {
        self.delegate = delegate
    }

    func introduce() {
        delegate?.printIntro()
    }
}
class Name: mainDelegate {
    let name = "田中圭"
    func printIntro() {
        print("名前は\(name)です。")
    }
}
class Job: mainDelegate {
    let job = "俳優"
    func printIntro() {
        print("職業は\(job)です。")
    }
}
class Hobby: mainDelegate {
    let hobby = "スキューバダイビング"
    func printIntro() {
        print("趣味は\(hobby)です。月に１回はいきます。")
    }
}


// 名前の自己紹介
let mainName: MainClass = .init(delegate: Name())
mainName.printIntro()
// 職業
let mainJob: MainClass = .init(delegate: Job())
mainName.printIntro()
// 趣味
let mainHobby: MainClass = .init(delegate: Hobby())
mainName.printIntro()
~~~
~~~swift:実行結果
名前は田中圭です。
職業は俳優です。
趣味はダイビングです。月に１回はいきます。
~~~

# 3. おわりに
いかがでしたでしょうか？
`Delegate`を使用することで、メインのクラスのコードがdelegateの型をプロトコルに決めてあげるだけで、そのデリゲートを変えてあげるだけでさまざまな処理ができるようになります！便利！

※外部から値を渡すプロパティは忘れやすいのでコンストラクタインジェクションを使用
https://mama-lifestyle.jp/swift-dev-jp/di/
SwiftのThrowsとthrow

## SwiftのThrowsとthrowとは？

Swiftでエラー処理をするときに、提供されている機能でthrowとThrowがある。

throwキーワードは、エラーをスローするために使用され、Throwsキーワードはメソッド宣言で指定されます。

## エラー処理の作り方

Enumを使用して、Error型の列挙型を作ります。ただの定数ですね。errorのcaseに対して必要なだけ書きます。

```swift
// throwing errors
enum Errors: Error {
    case OutOfStock
}
```

if文でエラーチェックする処理を書きます。メソッドに、`throws`キーワードをつけると、Enumで定義したエラーを使うことができます。

throwを使うには、do catchの中で使う必要があります。

```swift
import UIKit

// throwing errors
enum Errors: Error {
    case OutOfStock
}

struct Stock {
    var totalLamps = 5
    mutating func sold(amount: Int) throws {
        if amount > totalLamps {
            throw Errors.OutOfStock
        } else {
            totalLamps = totalLamps - amount
        }
    }
}

var myStock = Stock()

do {
    try myStock.sold(amount: 8)
} catch {
    print(error)// OutOfStock
}
```

しかし、エラーを気にしない場合は、`try`キーワードが強制的に結果を返すようにすることができます。メソッドがエラーをthrowした場合は、nilを返すため`catch`ステートメントを実行する。do catchを削除して、`try?`に修正してみましょう。

```swift
import UIKit

// throwing errors
enum Errors: Error {
    case OutOfStock
}

struct Stock {
    var totalLamps = 5
    mutating func sold(amount: Int) throws {
        if amount > totalLamps {
            throw Errors.OutOfStock
        } else {
            totalLamps = totalLamps - amount
        }
    }
}

var myStock = Stock()

try? myStock.sold(amount: 8)// nil
```

場合によっては、throwメソッドがerrorをthrowしないことが事前にわかっているため不要なコードの記述を避けたいことがあります。この場合は`try?`を使用できます。



購入したランプの合計をチェックして大きいかどうかを確認してみます。

```swift
import UIKit

// throwing errors
enum Errors: Error {
    case OutOfStock
}

struct Stock {
    var totalLamps = 5
    mutating func sold(amount: Int) throws {
        if amount > totalLamps {
            throw Errors.OutOfStock
        } else {
            totalLamps = totalLamps - amount
        }
    }
}

var myStock = Stock()
// 在庫を３個超えているか?
if myStock.totalLamps > 3 {
    try! myStock.sold(amount: 3)
}
print("ランプの在庫は: \(myStock.totalLamps)")// ランプの在庫は: 2

```

## まとめ

SwiftのthrowとThrowsについて学習してみました。違いはなんだと混乱してしまいますよね。Throwsの方は、メソッドにつけて、throwはエラーを返す処理の中に書くものでした。
【JavaScript】オプショナルチェーン(?.)について

## オプショナルチェーン(?.)ってなに？
参照が nullish (null または undefined) の場合にエラーとなるのではなく、式が短絡され undefined が返されるところが異なります。関数呼び出しで使用すると、与えられた関数が存在しない場合、 undefined を返します。

## 例①
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673845/4c031a11-a010-a7ca-af74-d6b6134bda23.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673845/a4cd854f-8b90-2865-2572-6bd14d12f88b.png)
このコードは、studentsという配列に学生の情報が入っており、それぞれの学生がテニスをしているかどうかをチェックしています。forEachメソッドを使って配列をループし、includesメソッドを使ってtennisが含まれているかどうかを確認しています。最後に、学生の名前とテニスをしているかどうかをコンソールに出力しています。
①の場合、鈴木太郎さんはtennisが含まれていない為、falseが返ってきます。


## 例②![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673845/704db3d3-ef67-08b1-2f91-23dfc6ade7b4.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673845/3ca2fa83-8573-9c80-aee9-8122f53770b9.png)
②の場合、鈴木太郎さんはsportsプロパティがそもそも存在しない為、エラーが返ってきます。


## オプショナルチェーンを使用した場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673845/8d80c30c-a3be-f3cd-fbbe-df74df2cc09f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673845/4fcbb217-2e34-0de4-f54f-41abdbbc7e0d.png)
上記のように、オプショナルチェーンをsports?.includes('tennis')の部分で使用することで、sportsプロパティが存在しない場合でもエラーが発生せず、undefinedが返されます。



## まとめ
例えば、フォームを作成する際に任意項目を作りたい時に、空配列返すという方法もあるがそういった対処法が使えない場合に、JS側で任意項目のプロパティに対してオプショナルチェーンを使用すれば、とりあえずエラーを回避することができるのでこの演算子はとても便利だなと思いました！
Amplify接続先をAWS環境ごと変えたい

開発用のAWS環境で、CLIからinitして作成したAmplifyに接続済みのアプリ……
を、<strong>本番用のAWS環境に別のメンバーが用意したAmplifyに繋ぎかえたい</strong>

「新しいAWS環境にCLIからログインして、接続先を変えて、pullしたりinitしたりpushしたりすれば自動生成のamplifyconfiguration.jsonとかも作成されてうまいこといくだろう」という想定だった

### はまった内容
・`aws amplify list-apps`は新環境のAmplify一覧が表示されるが、`amplify env list`しても旧環境のものしか表示されない(新しいAmplifyが見えていないので繋ぎ変えられない)
・appid等を指定してpullすると`Amplify appid mismatch.`となり失敗する
***
### 解決
1. プロジェクトの中のamplifyフォルダを削除(は怖かったので`amplify-old`にrename)
2. `amplify pull --appId <appID> --envName　<envname>`

成功

***
### 参照
Resolutionとして表示されたメッセージ`You are currently working in the amplify project`でggって見つけた以下のやりとり
https://github.com/aws-amplify/amplify-hosting/issues/2912

>The fix was deleting the entire amplify folder, then pulling again with amplify pull --appId <app Id> --envName <env name>
SWRの楽観的更新ができない

SWRを扱う上で躓いたところを共有し誰かの参考になればと思い、記事にしました。  
SWRの使い方の記事ではなく、SWRを知っている前提の内容です。  
公式　https://swr.vercel.app/ja

## やりたいこと
### 楽観的UI更新（optimistic update）
楽観的更新とは、ユーザーが行った操作をサーバーからのレスポンスを待たずにUIに反映する手法のことです。    
公式のソースコードはこのようになっています。  

[optimistic-updates](https://swr.vercel.app/ja/docs/mutation#optimistic-updates)
```react
import useSWR, { useSWRConfig } from 'swr'  

function Profile () {
  const { mutate } = useSWRConfig()
  const { data } = useSWR('/api/user', fetcher)  

  return (
    <div>
      <h1>My name is {data.name}.</h1>
      <button onClick={async () => {
        const newName = data.name.toUpperCase()
        const user = { ...data, name: newName }
        const options = {
          optimisticData: user,
          rollbackOnError(error) {
            // タイムアウトの AbortError だった場合はロールバックしません
            return error.name !== 'AbortError'
          },
        }  

        // ローカルのデータを即座に更新します
        // データを更新するためにリクエストを送信します
        // ローカルデータが正しいことを保証するために再検証 (再フェッチ) を発行します
        mutate('/api/user', updateFn(user), options);
      }}>Uppercase my name!</button>
    </div>
  )
}
```  

ソースコード下部`mutate('/api/user', updateFn(user), options)`の` updateFn(user)`は  
このソースコードにはないですがPromiseか非同期関数であり、更新後のデータを返します。  
サーバからのレスポンスを待たずに`<h1>My name is {data.name}.</h1>`のdataを`optimisticData`の値で更新しています。  

## 躓いたところ
optimisticDataの値でUIが更新されない。

## 結論
`updateFn(user)`の戻り値は、「指定されたキーのデータの型」と一致している必要があるようです。   
この場合mutateのkeyは'/api/user'で、` const { data } = useSWR('/api/user', fetcher)`のdataの型と一致している必要があります。  
※私の場合はいいね機能を実装していて、dataはユーザ情報を持つ型でした。いいね更新APIの戻り値は`Promise<boolean>`としていたためうまくいきませんでした。
Pythonで1ヶ月前を求める時

標記でネットを調べると、みんなdateutil　を使うってなっているけど、わざわざutility使うことないのではと思って、下の関数を作成しました

これは、YYYYMMのフォーマットで文字列6桁の年月を受け取り、1ヶ月前を返すものです

今の所、問題ない感じですね

```get_pre_month.py
def get_pre_month(year_month: str) -> str:
    y = int(year_month[0:4])
    m = int(year_month[4:6])

    if m == 1:
        y -= 1
        return f"{y}12"

    m -= 1
    # 0 padding
    return f"{y}{m:02}"
```

```test_app.py
def test_get_pre_month():
    assert app.get_pre_month("202403") == "202402" 
    assert app.get_pre_month("202401") == "202312"
    assert app.get_pre_month("202312") == "202311"
```
【TypeScript】case文の予期せぬ値を型エラーとして実行前に検出する

株式会社学びと成長しくみデザイン研究所の藤澤です。

TypeScript において、「型で定義していない値が switch 文などに渡された際に、それをエラーとして検出する」という挙動を、例えば以下のように実装したとします。

```ts
type Element = 'rhythm' | 'melody' | 'harmony'
const element: Element = 'rhythm'

switch (element) {
  case 'rhythm':
    rhythmFunction()
    break
  case 'melody':
    melodyFunction()
    break
  case 'harmony':
    harmonyFunction()
    break
  default:
    throw new Error(`不正な値： ${element}`)
}
```

このコードでは、switch に型 `Element` で定義されていない値が来た場合にエラーを出してくれます。
しかしエラーのタイミングは実行時なので、例えば型 `Element` に新しい値を追加した際、それに対応した実装を忘れていても**実行時エラーが出るまで気が付かない**可能性もあります。


なので、型に新しい値を追加した際などに、実行前に型エラーを出してもらえるように改修します。
```ts
type Element = 'rhythm' | 'melody' | 'harmony' | 'timbre' // 新しい値 'timbre' を追加
const element: Element = 'rhythm'

// 明示的に引数に値が入らないことが分かる関数を作成
const assertUnreachable = (element: never): never => {
  throw new Error(`不正な値： ${element}`);
};

switch (element) {
  case 'rhythm':
    rhythmFunction()
    break
  case 'melody':
    melodyFunction()
    break
  case 'harmony':
    harmonyFunction()
    break
  default:
    assertUnreachable(element)
}
```

関数 `assertUnreachable` の引数の型は `never` なので値が入らない想定ですが、このコード上では少なくとも `timbre` がこの関数に到達する可能性があり、実行前にその点を型エラーとして教えてくれます。
念の為に実行時エラーを出す挙動も残しています。
エンジニアを目指す人が最初に見る記事（用語）

# はじめに
エンジニアになると色んな言葉がでてきます。
しかし、最低限の言葉は知っている前提で説明がされるため、意味は記載されません。

今回はそのエンジニアの最低限を取り上げてみようと思います。

# まずは
エンジニアになると、沢山のソフトをパソコンにインストール（導入）します。

Excelも表計算のソフトですし、ChromeやSafariはウェブ検索できるソフトですが、
特にエンジニアの開発では、プログラミングを書いて実行するための「統合開発環境（IDE）」と呼ばれるソフトをインストールして使います。

また、様々なソフトをインストールして、開発のできる状態に整えることを「環境構築」と呼びます。
エンジニアの基礎として、ソフトインストールの流れや、環境構築する際によく出てくる言葉を紹介します。


# ソフトインストールの流れ
ソフトをインストールして使えるようにするまでの大体の流れは以下です。

1. インストールしたいソフトを検索する
↓
2. ダウンロードページから、**ソフトのバージョンなどを選び**、ダウンロードする。
↓
3. ダウンロードしたソフトを、パソコンにインストールする。

:::note warn
ダウンロードはソフトのデータをPCに持ってくること。インストールはPCに適用して使えるようにすることです。スマホなどでは言葉の区別がされていないことが多いです。
:::

# ダウンロードページからソフトを選ぶ
ダウンロードできるページには、公式サイトや第三者が用意したダウンロードページなどがあります。
そしてその中には、色んなバージョンや選択肢があります。ここでは、よくある選択肢を紹介します。

* **バージョンを選ぶ**：ソフトは絶えずアップデートがされていています（例えば年ごとに2022年版、2023年版など）。適当なバージョンを選んでダウンロードします

* **エディションを選ぶ**：エディション=版です。無料版と有料版、普通版や拡張版などがソフトによって存在します

* **自身のPC対応版を選ぶ**：Windows版やMac版と記載があります

* **「32bit版」か「64bit版」を選ぶ**：選択肢がある場合は、64bit版を選んでおけば問題ないです。（64bit版の方が高性能）

実際の開発現場のメンバーは、開発に使用するソフトのバージョンやエディションを揃えます。これは、バージョンの違いによって、予期せぬ不具合がでることを避けるためです。

ダウンロードするバージョンの指示がある場合は、それに従います。

# よく出てくる用語


<dl>
  <dt>実行ファイル（.exe）</dt>
  <dd>ファイル名の末尾が.exeで終わるものを実行ファイルと呼びます（Executable file）。ファイル名の末尾の例でいうとExcelでは.xlsxだったり、写真は.pngだったりします。.exeのファイルはダブルクリックすると、中の処理が開始されます。環境構築では、ソフトをPCにインストールするための実行ファイルをダウンロードします。これらは特にインストーラーと呼ばれます。
</dd>
  
  <dt>圧縮する・解凍する</dt>
  <dd>データのサイズを小さくすること、またそれを元に戻すことです。PCでは様々なファイルやソフトがやりとりされますが、通信するデータ量はそのファイルやソフトの大きさで決まります。できるだけ小さい方がデータ通信量は少なくなるので、一定のルールでデータを小さく圧縮する技術が使われます。
  <br>流れとしては「データを圧縮」→「データが移動（ダウンロードなど）」→「データの解凍」です。データ圧縮の解除は「解凍」と呼ばれます</dd>  
  
  <dt>Zip形式、Zipファイル</dt>
  <dd>Zipはデータを圧縮・解凍する技術のことです。zipファイルやzip形式と言われたら圧縮されたファイルのことを指します。7-Zipというソフトを使うことで、ファイルをzip形式へ圧縮や、解凍ができます
</dd>  
  
  <dt>パッケージ</dt>
  <dd>色んなソフトや要素を一まとまりにしたものをパッケージと呼んでいます</dd>  
  
  <dt>プラグイン・アドイン</dt>
  <dd>ソフトに入れる追加機能をプラグインやアドインと呼びます。ソフトをインストールした後に、プラグインを追加することがよくあります。（英語スペルチェックなどのプラグインもあります）</dd>  
  
  <dt></dt>
  <dd></dd>  
  
  <dt></dt>
  <dd></dd>
  
</dl>

# おわりに
エンジニア界隈では、環境構築こそが最難関と言われることがあります。
実際には環境構築手順のようなマニュアルが用意されて、それ通りに進めていくことが多いです。

あまり考えず、手順通りに進めるのも一つですが、この記事を呼んで、少しでも自分が今していることの理解が進み、楽しさを感じてもらえれば嬉しいです。
生成型AIの旅

![alt 图片](https://mmbiz.qpic.cn/sz_mmbiz_png/4CAA63nvHRAqWZc5jyQibpQzTIGSNQoDy95aibfoMOy7zXKk4f8tJMnMasJicEM8ibWFzIicfBrAR9TFCCttDUyalFg/640?wx_fmt=png&from=appmsg)
ChatGPTが登場したばかりの時の体験をまだ覚えていますか？知識が豊富で、何でも知っており、賢さがオンラインで、論理が明確で、「高級で、大気で、上品」と形容できるけど、「控えめで、豪華で、深みがある」とも言える感じでした。

GPTを使ってみて、いくつかの段階を経験しました。最初は娯楽の段階で、チャットや詩を書くなどが主でした。その後、長い検索エンジンの段階を経て、知識点、技術点や文案のアウトラインを検索するようになりました。そして今、生産ツールの段階にあります：自分の代理人を開発して、仕事の製品に導入し、新しい生産力について考えています。これからもっと複雑で高度なアプリケーションが出てくると信じています。

娯楽
小冰、小娜、AppleのSiriなどは、一言で返答するチャットボットで、上下文の記憶がありません。話したことをすぐ忘れます。詩を読んだり、歌を歌ったりすることは問題ありません。しかし、ChatGPTは違います。1つのセッションで話したことをすべて覚えており、とても人間らしい体験ができます。これにより、私は一時期、人間が出力しているのではないかと疑いました。

検索エンジン
新鮮味はすぐに消えます。その後、ChatGPTを検索エンジンとして使い続けました。わからない技術点や知識点があれば、質問してみるためです。出力の精度を上げるために、いくつかのPromptの学習リソースも見ました。質問を明確にするか、ケースを提供するなどの方法が基本です。この過程で、GPTもそういうものだと感じるようになりました。GPT4がリリースされても、結果が少し良くなるだけでした。そうして、GPTを水のように、空気のように、当たり前のものとして扱うようになり、「高級感」もなくなりました。

生産力
23年の年末になると、中国に戻って.NETコミュニティの大会に参加したとき、多くの人が生成型AIに注目していました。その熱意と自信に感染されました。彼らの交流から、私の無知を知りました。GPTを「検索エンジン」と見なしたり、「大規模なデータストレージ、ランダムテキストリレー」と考えるのは、実に単純なことでした。わからなければ学ぶ、基本的なアルゴリズムのアイデアから、Promptの進化、GPT API、アプリケーションのSDK-SemanticKernelへの接続など、一つ一つ見て、一つ一つ試して、生成型AIを長く使ってみると、水のように、平凡で味がないと感じますが、基礎資源であることがわかります。私たちの生活における水や電気のように、普段はほとんど感じないものですが、基本中の基本です。

ある人が言ったように、GPTは私たちに電力から知力へのパラダイムシフトを感じさせてくれました。この知力は多くの人にとってはまだ基本的で単純なものですが、初めての蒸気機関もそんなに完璧ではありませんでした。

一方で、生成型AIの知識を学ぶことで、自分のエネルギーが満ち溢れ、遅ればせながら出会ったような急ぎ足の感覚もあります。友人や同僚からは、これが熱狂だと言われますが、笑、別の角度から見れば、確かにそうです。何であれ、それが私を幸せにしてくれるなら、それが最も重要です。
![alt 图片](https://mmbiz.qpic.cn/sz_mmbiz_png/4CAA63nvHRDcUzbn51GKNNOCiacSXZ5XSicLNbWsPYY0nTWiayibYLERkKVJbltnUicAfxh2gibjlcHibCFazfYmNictlA/640?wx_fmt=png&from=appmsg)
(Translated by GPT)

元のリンク：https://mp.weixin.qq.com/s?__biz=MzA3NDM1MzIyMQ==&mid=2247487916&idx=1&sn=827ded9a15c1c33b84be47e78f72bf7f&chksm=9f004e86a877c790c90f2dbd3fc67f518ae1b52310182d9fe5aedf5abf13ba2e2dd5acd6643a&token=408560405&lang=zh_CN#rd
Proxmox8で最初にやる apt update エラー対応（no subcription時）

Proxmox8のインストール直後いきなり`apt update`エラーが出ました。有料のサブスク登録していない場合に出るエラーのようです。
2024年の2月から利用するようになり、まだまだ慣れていないので備忘録として残します。

Qiitaの記事、「[Proxmox 8の注意事項](https://qiita.com/Bacalhau/items/6a56752b05fe75364c87)」を参考にしました。

下記3つのファイルを修正すれば`apt update`のエラーが解消されます。

1. `/etc/apt/sources.list`
2. `/etc/apt/sources.list.d/pve-enterprise.list`
3. `/etc/apt/sources.list.d/ceph.list`

## 1. `nano /etc/apt/sources.list`

```conf:/etc/apt/sources.list
deb http://ftp.debian.org/debian bookworm main contrib
deb http://ftp.debian.org/debian bookworm-updates main contrib

# Proxmox VE pve-no-subscription repository provided by proxmox.com,
# NOT recommended for production use
deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription

# security updates
deb http://security.debian.org/debian-security bookworm-security main contrib
```

## 2. `nano /etc/apt/sources.list.d/pve-enterprise.list`

```conf:/etc/apt/sources.list.d/pve-enterprise.list
# deb https://enterprise.proxmox.com/debian/pve bookworm pve-enterprise
```

## 3. `nano /etc/apt/sources.list.d/ceph.list`

```conf:/etc/apt/sources.list.d/ceph.list
# deb https://enterprise.proxmox.com/debian/ceph-quincy bookworm enterprise
deb http://download.proxmox.com/debian/ceph-quincy bookworm no-subscription
```

公式からの説明はこちら

https://pve.proxmox.com/wiki/Package_Repositories
Swiftのself keywordとは?

## selfとは?
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/methods/

公式によると...

**self プロパティ**
ある型のすべてのインスタンスは、selfと呼ばれる暗黙のプロパティを持つ。selfプロパティは、インスタンスメソッド内で現在のインスタンスを参照するために使用します。

上の例のincrement()メソッドは、次のように書くことができる：
```swift
func increment() {
    self.count += 1
}
```

実際には、コードに self を書く必要はあまりありません。明示的に self を書かない場合、Swift は、メソッド内で既知のプロパティまたはメソッド名を使用するときはいつでも、現在のインスタンスのプロパティまたはメソッドを参照していると仮定します。この仮定は、Counterの3つのインスタンスメソッド内で（self.countではなく）countを使用することで実証されています。

このルールの主な例外は、インスタンス・メソッドのパラメータ名がそのインスタンスのプロパティと同じ名前の場合に発生する。この状況では、パラメータ名が優先され、より修飾された方法でプロパティを参照する必要が生じます。パラメータ名とプロパティ名を区別するには、selfプロパティを使用します。

ここでは、selfがxというメソッド・パラメータと、同じくxというインスタンス・プロパティを区別している：

```swift
struct Point {
    var x = 0.0, y = 0.0
    func isToTheRightOf(x: Double) -> Bool {
        return self.x > x
    }
}
let somePoint = Point(x: 4.0, y: 5.0)
if somePoint.isToTheRightOf(x: 1.0) {
    print("This point is to the right of the line where x == 1.0")
}
let p = Point()
// 実行結果:
// This point is to the right of the line where x == 1.0
```

テキストを参照して表示する例だとこんな感じですね。
```swift
import UIKit

// selfキーワードは、コードが属するインスタンスを参照するのと同じように機能します。
class Employee {
    var name = "Undefined"
    
    func changedeName(name: String) {
        self.name = name
    }
}
let employee1 = Employee()
// この例のselfキーワードは、employee1変数に格納されているオブジェクトへの参照です。
employee1.changedeName(name: "Monica")

print("Name: \(employee1.name)")// Name: Monica
```

## まとめ
self keywordの役割は、クラスと構造体の中で定義しているプロパティを参照する目的で使用するキーワードです。他の言語だったら`this`ですかね。
Tailwind CSS – テーブル1行目のヘッダ行を固定しつつ部分スクロールさせる

# HTML例

- テーブルの外側の要素に高さを指定する
- テーブルヘッダのセルに `top-0` `sticky` を指定する


```html
<div class="h-52 overflow-scroll text-5xl">
  <table class="bg-gray-100">
    <thead>
      <tr>
        <th class="sticky top-0 bg-yellow-200">HEAD A</th>
        <th class="sticky top-0 bg-green-200">HEAD B</th>
        <th class="sticky top-0 bg-blue-200">HEAD C</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>BODY A 1</td>
        <td>BODY B 1</td>
        <td>BODY C 1</td>
      </tr>
      <tr>
        <td>BODY A 2</td>
        <td>BODY B 2</td>
        <td>BODY C 2</td>
      </tr>
      <tr>
        <td>BODY A 3</td>
        <td>BODY B 3</td>
        <td>BODY C 3</td>
      </tr>
      <tr>
        <td>BODY A 4</td>
        <td>BODY B 4</td>
        <td>BODY C 4</td>
      </tr>
      <tr>
        <td>BODY A 5</td>
        <td>BODY B 5</td>
        <td>BODY C 5</td>
      </tr>
      <tr>
        <td>BODY A 6</td>
        <td>BODY B 6</td>
        <td>BODY C 6</td>
      </tr>
      <tr>
        <td>BODY A 7</td>
        <td>BODY B 7</td>
        <td>BODY C 7</td>
      </tr>
      <tr>
        <td>BODY A 8</td>
        <td>BODY B 8</td>
        <td>BODY C 8</td>
      </tr>
      <tr>
        <td>BODY A 9</td>
        <td>BODY B 9</td>
        <td>BODY C 9</td>
      </tr>
      <tr>
        <td>BODY A 10</td>
        <td>BODY B 10</td>
        <td>BODY C 10</td>
      </tr>
    </tbody>
  </table>
</div>

```

# 動作例

https://play.tailwindcss.com/D2teDEGTfT

<img width="939" alt="image" src="https://github.com/YumaInaura/YumaInaura/assets/13635059/7527b4e7-debc-4a70-a11b-0eefe10177cd">
# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# プロフィール・経歴

https://github.com/YumaInaura/YumaInaura
【Docker】基礎コマンド

# はじめに

[Amazon.co.jp: Docker&仮想サーバー完全入門　Webクリエイター＆エンジニアの作業がはかどる開発環境構築ガイド eBook : リブロワークス: 本](https://amzn.asia/d/fKzpBH5)

こちらの本を参考に、素人の経験談を交えつつ、Dockerの基礎的なコマンドをまとめます。

# ☆`container`

Dockerの基本的な流れを説明すると

```mermaid
graph TD;
  a(image（設計図）)-->|設計図をもとに作成| b(container（新しいPC）)
```
（わかりやすさ重視で説明）

です。

自分のPC①の中にPC②を作り、そのPC②の中でいろいろと動かすわけですね。
使い終わったPC②はデータごと捨てます。そうすると、PC①にデータが残りません。
（よくある、「このアプリなんだっけ・・・いつ使ったっけ・・・」を防ぐことができます）

また、他人に設計図を配ることで、同じ環境を再現できます。
自分がMacbookで、友人がWindowsだとしても、その中に作られるPC②は同じものなので。
（正確には少し違いがあることがあります）

- docker
  - container
    - ls
    - run
    - start
    - stop
    - rm

## `docker container ls`

現在稼働中のコンテナの一覧を表示します。
`-a`オプションで、稼働していないコンテナも表示します。

【経験談】
`bash`を開きたいけど、コンテナ名なんだっけ？って時に使いました。

## `docker container run / start / stop / rm`

それぞれ
- `run`：コンテナを作成し起動
- `start`：作成されているが、停止しているコンテナを再起動
- `stop`：停止
- `rm`：削除

ですね。

【経験談】
どれも使ったことないです。どの操作も、後述する`docker compose`でまとめて行います。

# ☆`compose`

`container`コマンドには複数の欠点があります。
- コンテナを複数動かす際、ひとつひとつ起動させるしかありません
- 起動の順番を意識する必要があります
  例えば、`db`と`web`は多くの場合、`db`を先に起動させなければいけません
- 実際には、起動のたびにまあまあに長い文を打つ必要があります
  `docker container run -d --name ngrok -e NGROK_AUTHTOKEN=${NGROK_AUTH} -p 4040:4040 ngrok/ngrok http rails:3000`など

一回のコマンドで済ませたい！毎回同じこと書くなら自動化したい！
そこで使用するのが`compose`です。

```mermaid
graph TD;
  subgraph compose
    c('db' image)-->|作成| d('db' container)
    a('web' image)-->|作成| b('web' container)
  end
```

  - compose
    - ls
    - up
    - run
    - build
    - start
    - stop
    - down

## `docker compose ls`

【経験談】
`container`と同じく、`-a`オプションをつけて使用。
後述する`down`の前に、どんな`compose`がどのディレクトリに存在するかを確認するために使用しました。

## `docker compose up`

Dockerで最も使用されるコマンドかもしれません。
`compose.yaml`に基づき、Docker composeを起動します。

【経験談】
私も例に漏れず使用しています。

## `docker compose run`

`compose.yaml`の中の指定したコンテナを作成し実行します。

`--rm`オプションをつけると、実行後にコンテナが削除されます。
というか、`--rm`を使用しないと、コンテナが残り続けます。
`docker compose`を使用している場合、`compose run`するときは`--rm`をつけることがほとんどでしょう。おそらく。

【経験談】
`rails new`してローカルにプロジェクトディレクトリを作成する際使用しました。
（`docker compose --rm web rails new .`）
## `docker compose build`

`compose.yaml`の中のイメージをビルド・再ビルドします。
`--no-cache`オプションをつけると、中間イメージを再使用せずに再ビルドします。

【経験談】
`volume`を使用しない（知らなかった）時、`gem`のインストール後使用していました。

## `docker compose start / stop`

- `start`：コンテナを起動
- `stop`：コンテナを停止

【経験談】
使ったことがないです。
`stop`に関しては、いつも`ctrl + c`使いがち。
## `docker compose down`

コンテナを削除します。
`--rmi all`オプションで、イメージも削除します。
`-v`オプションでボリュームも削除します。

【経験談】
使い終わったコンテナの削除に使用しています。
コンテナを削除しても、ボリュームだけは残せたり、`compose.yaml`があれば同じ環境に戻せるのがDockerのよいところですね。

# ☆`image` / `network` / `volume`

  - image
    - build
    - ls
    - pull
    - push
    - rm
  - network
    - create
    - ls
    - rm
  - volume
    - create
    - ls
    - rm

どれも使用したことがないです。`compose.yaml`に書けば事足りるので。

特徴的なのは`docker image push`でしょうか。
Docker hubや、その他リモートレジストリに`push`するもので、「共有」「公開」「本番環境でのデプロイ」で使用するようです。

# おわりに

気になることです。
「（環境に依らない）共有」の目的の場合、イメージを共有する方法だけでなく、単に`compose.yaml`の共有でも為しえますよね・・・？（Githubなど）
どっちが主流とかあるんでしょうか。
個人的には、公式のイメージに安心感があるので後者派なのですが。
【React・Supabase】duplicate key value violates unique constraint がでた

# はじめに
Reactとsupabaseを使ってアプリを開発していた時に躓いたエラーを共有します。

# 問題
supabaseにデータの追加ができない(ちなみにデータ追加はアプリケーション側で行う機能がある)。

# 解決策
Primary columnを変更する。

こんな感じで、鍵マークがついているのがPrimaryに設定されている。これをデータの識別子(つまり一意なもの)として扱っているらしい。なので、このPrimaryが同じ値になってしまっていないかを確認する。同じ値にしたければPrimaryを変更する。
![スクリーンショット 2024-03-15 093634.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3554025/49ca445f-6505-6188-c8df-579744675ed2.png)

# 最後に
supabaseのGUI上でデータ追加しようとするとすぐに気づくかもしれないけど、アプリケーション自体に追加機能を実装すると気づきにくいなと思いました。ついコードの方にばっかり目が行ってしまうのでしっかりおおもとも確認するのが吉。

# About Me
お友達になってください～
- X(Twitter)

https://twitter.com/shunii_hack
AWS勉強備忘録8 - AMIについて

## AMI (Amazon Machine Image) とは
### ざっくりした概要
AMIは、Amazon EC2インスタンスを起動するためのテンプレートであり、OS、アプリケーションサーバー、アプリケーション、設定情報など、インスタンスを実行するために必要なすべての情報を含んでいます。AMIはインスタンスの作成における「型金」のようなものであり、インスタンスの作成時に基盤となるOSや設定を定義します（（サーバのディスクの中身が丸ごと入っている）。

### OSとの関係性と提供されるOS

AMIは特定のOSを含んでおり、インスタンス作成時にそのOSがインスタンスにインストールされます。提供されるOSには、Amazon Linux, Ubuntu, Red Hat Enterprise Linux, Windows Serverなどがあります。これにより、開発者やシステム管理者は、必要なOS上で独自のアプリケーションや環境を迅速にデプロイできます。

### AMIの料金

基本的にAMI自体に料金はかかりません。しかし、AMIを使用してEC2インスタンスを起動する場合、インスタンスの使用料金が発生します。また、特定のソフトウェアを含むAMI（たとえば、ライセンスが必要なソフトウェア（Windows Serverなど）をプリインストールしたAMI）を使用する場合、追加の料金が発生することがあります。これらの料金はAMIの提供者によって設定されます。

### AMIの自作

カスタムOS設定、アプリケーション、設定ファイルなどを含む独自のAMIを作成し、それを使用してEC2インスタンスを起動することを意味します。このプロセスにより、ユーザーは完全にカスタマイズされた環境を迅速に複製してデプロイできるようになります。AMIを自作することで、特定のプロジェクトやアプリケーション要件に合わせた環境を一貫して提供することが可能になります。

### AWSマーケットプレイス

AWS Marketplaceは、AWS上で動作するソフトウェアやサービスを販売・購入できるオンラインストアです。開発者は自作したAMIをマーケットプレイスに登録して販売することができ、他のユーザーはそれを購入して利用することができます。マーケットプレイスを利用することで、ソフトウェアの配布や販売が簡単になり、広い顧客層にリーチすることが可能です。

### メリットとデメリット、危険性

**メリット**:
- カスタマイズされたAMIを迅速にデプロイできる。
- AWS Marketplaceを通じてソフトウェアを販売することで収益を上げる機会がある。
- 独自のAMIを通じて、特定の要件に合わせた環境を簡単に複製・共有できる（AMIがないと1台ずつ設定が必要で非常に手間がかかる）。

**デメリットと危険性**:
- セキュリティベストプラクティスに従っていないAMIを使用すると、脆弱性が発生する可能性がある。
- カスタムAMIの維持管理には時間と労力がかかる場合がある。
- マーケットプレイスでの販売には、品質管理や顧客サポートなどの追加的な責任が伴う。

自作AMIやAWS Marketplaceの利用には多くの機会がありますが、セキュリティや管理の面で慎重に検討する必要があります。適切な準備と知識をもって進めることで、これらのツールを効果的に利用できます。
AWS勉強備忘録7 - インスタンス作成における各設定項目と料金について

## AWSインスタンス作成の設定項目

1. **AMI (Amazon Machine Image)**: インスタンスにインストールするOSやアプリケーションの設定が含まれたテンプレートです。Amazon Linux 2, Ubuntu, Windows ServerなどのさまざまなOSから選択できます。

2. **インスタンスタイプ**: CPU、メモリ、ストレージ、ネットワーキングキャパシティによって異なります。一般的なタイプにはt2.micro, m5.largeなどがあります。

3. **リージョンとアベイラビリティゾーン**: AWSの物理的なデータセンターの位置です。リージョンには米国西部（オレゴン）、アジアパシフィック（東京）などがあります。インスタンスの遅延と料金に影響します。

4. **インスタンス数**: 起動するインスタンスの数です。

5. **購入オプション**: オンデマンド、リザーブドインスタンス、スポットインスタンス、専用ホストなどがあり、それぞれ料金と使用条件が異なります。なしも可能。

6. **ネットワークとサブネット**: インスタンスを配置するVPC（Virtual Private Cloud）とサブネットを指定します。

7. **配置グループ**: 物理的に近接したハードウェア上にインスタンスを配置する設定です。性能やネットワークの遅延を最適化したい場合に使用します。なしも可能。

8. **IAMロール**: インスタンスに割り当てるAWS Identity and Access Management（IAM）ロール。AWSリソースへのアクセス権をインスタンスに与えます。なしも可能。

9. **シャットダウン動作**: インスタンスのシャットダウン時の動作を選択します（停止または終了）。

10. **削除保護の有効化**: インスタンスが誤って削除されるのを防ぐための設定です。なしも可能。

11. **モニタリング**: CloudWatchを使用してインスタンスのモニタリングを有効にするかどうか。なしも可能。

12. **テナンシー**: インスタンスが物理的なホストを他のAWSアカウントと共有するか（デフォルト）、専用ホストを使用するかを選択します。

13. **T2/T3無制限**: T2/T3インスタンスでCPUクレジットのバランスに関係なくCPU性能を最大限に活用できるオプションです。
⇒負荷が高まったときのバースト（一時的に高いパフォーマンスを出す機能）を無制限にすることが可能です。ただし、通常のバーストを超えた利用については別途料金がかかるため、常にサーバに負荷がかかる使い方の場合、コストが想定以上にかさんでしまうおそれがあります。
⇒なしも可能。

14. **ストレージ**: EBS（Elastic Block Store）やインスタンスストアといったストレージオプション、その容量と種類（SSD, HDD）を選択します。

15. **タグ**: インスタンスや他のAWSリソースを識別するためのユーザー定義のタグ（キーと値のペア）キーはName、値はYellow Serverなどのサーバーの名称。

16. **セキュリティグループ**: インスタンスへのアクセスを制御するための仮想ファイアウォールルールのセット。例えば、SSH（ポート22）、HTTP（ポート80）、HTTP（ポート443）など

## 料金の計算

AWSの料金計算は複雑で、使用したサービスの種類と量に基づいています。基本的には以下のコンポーネントに分けられます：

- **インスタンスの使用量**: 選択したインスタンスタイプと購入オプション（オンデマンド、リザーブド、スポット）に基づく料金。
- **EBSの料金**: 使用したEBSボリュームのタイプ（SSD, HDD）と容量、およびIOPSに基づく料金。
- **データ転送料金**: インターネットやAWS内でのデータ転送にかかる料金。
- **追加サービスのオプション**: 詳細モニタリング、専用ホスト、その他の追加サービスに関する料金。

支払い方法には、クレジットカード、デビットカード、AWSの請求書支払いなどがあります。

### AWS加入の特典

- AWS Free Tier: 新規顧客には、12ヶ月間無料で利用できる特定のサービスがあります。例えば、毎月750時間のAmazon EC2 t2.microインスタンス使用が含まれます。
- 広範囲のサービスとリソース: コンピューティング、ストレージ、データベースなど、さまざまなニーズに応える豊富なサービスが利用可能です。
- 柔軟性と拡張性: リソースをリアルタイムで追加または削除することで、ビジネスの成長や需要の変動に合わせて簡単にスケールアップまたはダウンが可能です。

### EC2の得手不得手

**得手**:

- 柔軟性: 多様なインスタンスタイプと設定オプションにより、ほとんどのコンピューティングニーズに対応できます。
- スケーラビリティ: 需要に応じてリソースを瞬時に追加または削除できるため、効率的にスケールアップまたはダウンが可能です。
- セキュリティ: VPC、セキュリティグループ、IAMロールなど、強力なセキュリティ機能と柔軟な設定が可能です。

**不得手**:

- 複雑性: 多岐にわたるオプションと設定が初心者にとっては複雑に感じられることがあります。
- コスト管理: リソースの使用状況によっては、想定外の高額な料金が発生する可能性があります。適切なコスト管理と監視が必要です。

この概要から、AWSのEC2を効率的に使用するためには、利用するサービスと設定オプションを理解し、コスト管理に注意することが重要です。


EC2はマネージドサービスではないので、素のEC2を使用するだけではクラウドのメリットを活かしきれているとはいいがたく、最近ではECSやEKSなどのコンテナサービスを組み合わせる例が多くなってきています。
squidでプロキシサーバ

- サーバはdebian, ubuntu系のOSで、
- user : foobar
- pass : e8eb23ddf9245b6dbb309903e50f67c0
- port : 3128
```
#!/bin/sh
sudo apt-get update
sudo apt-get -y install squid apache2-utils
sudo cp /etc/squid/squid.conf /etc/squid/squid.conf.org
sudo sh -c "echo ''                                                                              > /etc/squid/squid.conf"
sudo sh -c "echo 'auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/.htpasswd' >> /etc/squid/squid.conf"
sudo sh -c "echo 'auth_param basic realm proxy'                                                 >> /etc/squid/squid.conf"
sudo sh -c "echo 'acl authenticated proxy_auth REQUIRED'                                        >> /etc/squid/squid.conf"
sudo sh -c "echo 'http_access allow authenticated'                                              >> /etc/squid/squid.conf"
sudo sh -c "echo 'http_port 3128'                                                               >> /etc/squid/squid.conf"
sudo sh -c "echo 'request_header_access X-Forwarded-For deny all'                               >> /etc/squid/squid.conf"
sudo sh -c "echo 'request_header_access Via deny all'                                           >> /etc/squid/squid.conf"
sudo sh -c "echo 'request_header_access Cache-Control deny all'                                 >> /etc/squid/squid.conf"
sudo sh -c "echo 'reply_header_access X-Forwarded-For deny all'                                 >> /etc/squid/squid.conf"
sudo sh -c "echo 'reply_header_access Via deny all'                                             >> /etc/squid/squid.conf"
sudo sh -c "echo 'reply_header_access Cache-Control deny all'                                   >> /etc/squid/squid.conf"
sudo cat /etc/squid/squid.conf
sudo htpasswd -bc /etc/squid/.htpasswd foobar e8eb23ddf9245b6dbb309903e50f67c0
sudo systemctl reload squid
```
(QA) IBM i IWSでREST APIからRPG/COBOLをキックする際の関連ジョブは？

先週頂いたお題です。

## Q.  IBM i IWSでREST APIからRPG/COBOLをキックする際の関連ジョブは？

### 統合Webサービスサーバー（IWS）とは？
IWSはIBM i OSの標準導入されるアプリケーションサーバー（以下APサーバー）の名称です。かつてはWebSphere Application Serve Base版やExpress版をベースにIBM i にポーティングしたものでした（プロファイルやConfigファイルなどが他OSと共通フォーマットです、ただしディレクトリなどは各OS固有なのは共通）。近年のIWSはWebSphere Libertyベースになっています。

IWSには別名がいくつかあります。統合APサーバー、統合Webアプリケーションサーバー、LWI（Light Weight Integration Server)などです。サーバー機能名ではありませんがWebサービスゲートウェイ、もIWSを使用してSOAPリクエストを処理する機能名です。いずれも実態はWebSphere Application ServerベースのAPサーバー上で動作するJavaアプリケーションが外部からhttp/httpsでSOAP/RESTのリクエストを受け取り、Toolbox for JavaのPCMLクラスを使用してIBM i 上の機能・プログラム・データベースを呼び出し・処理するものです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/01deec51-6e57-91b6-f992-adee7731e148.png)

※上図ではRESTしか記載がありませんが、SOAPも使用できます。

## A. IBM i が受信したREST API の処理フローは下図のとおりです。

上記で説明した通り、IBM i 標準機能のRESTインターフェースはIWSにデプロイされたJavaアプリケーションが実態です。このAPサーバーと関連のジョブログを調べることで問題判別が進みます。

大まかな構成は以下の①～④ようになります。※認証系などは記載していません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/3c7b3308-ed67-480c-a94b-7d94bd02bcd9.png)

上記の①～④についてログを確認することで状態が分かります。

実は、同時に
## エラー等のログ確認はどこでできますか？

というご質問もいただいたのですが、書き始めたらとても長くなってしまったため、別記事でこちらにまとめました。

**iWorld 「統合WebサービスサーバーIWSの構造とログ確認方法について」**
https://www.i-cafe.info/column/serials/ibmonko_6
react-hook-formのresetを使ってステートを初期化する

# はじめに
**ステートを初期化する際に、react-hook-formのresetを使用しました。**
公式ドキュメントに使用方法が載っています。

https://react-hook-form.com/docs/useform/reset
# 問題
現在、学習記録アプリを作成しています。

今回実装する処理の流れとしては下記のとおりです。
**登録ボタンの押下後、モーダルを閉じる→ステートの初期化を行う→再度モーダルを開くと、入力フォームが初期化された状態になっていればOK**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3675500/1917f406-1682-44a9-c2f9-a164dbfd1e4a.png)

# 解決方法
react-hook-formのresetを使って、**学習内容と学習時間を初期化**しました。
なお今回は`studyTime`をnumber型で扱っているため、初期値を0としています。

```tsx:tsx
const onSubmit: SubmitHandler<IFormInputs> = async data => {
    console.log(data); 
    try {
     //データ追加(supabase)
    const addedData = await addAllRecords(data.studyContent, data.studyTime);
    const newRecord = { id: addedData.id, studyContent: data.studyContent, studyTime: data.studyTime, createDate: addedData.created_at };
    setRecords([...records, newRecord]);
    //ここでリセット
    reset({ studyContent: '' })
    reset({ studyTime: 0 })
    //モーダルを閉じる
    onClose(); 
    } catch (error) {
      console.error('Failed to submit form data:', error);
    }
  };
  ```
# おわりに
**「どこでresetを使うか」に注意が必要です。**

例えば今回の場合だと、モーダルを閉じてからresetすると、再度モーダルを開いたときに前回入力した値が残ってしまいます。
従って、モーダルを閉じる前にresetを使ったほうが**確実に初期化できる**ということです。

**×NG例**
```tsx:tsx
const onSubmit: SubmitHandler<IFormInputs> = async data => {
    console.log(data); 
    try {
     //データ追加(supabase)
    const addedData = await addAllRecords(data.studyContent, data.studyTime);
    const newRecord = { id: addedData.id, studyContent: data.studyContent, studyTime: data.studyTime, createDate: addedData.created_at };
    setRecords([...records, newRecord]);
    //モーダルを閉じる
    onClose();
    //モーダルを閉じてからリセットすると、挙動がおかしくなる
    reset({ studyContent: '' })
    reset({ studyTime: 0 }) 
    } catch (error) {
      console.error('Failed to submit form data:', error);
    }
  };
  ```
# 参考
https://qiita.com/nakamo-03/items/dad3f9e68bbfb5bbb6ab
ローカルに作成した DB（PostgreSQL）にDbeaverからアクセスする（備忘録）

## 目的
- ローカルにダウンロードした DB（PostgreSQL）にDbeaverを利用してアクセスしたい


## 環境
1. MacBook Air M1
2. macOS Sonoma 14.2.1
3. homebrewからPostgreSQL14をインストール


## Postgres側での準備
1. 早速PostgreSQLでテーブル作成します。
    （HomebrewからPostgreSQLをインストールする方法は他の方の記事を参照してください）
    
    terminalでバージョン確認して、下記のようになっていたらインストール済みです。
    ```terminal
    username@pcname~% psql --version
    psql (PostgreSQL) 14.10 (Homebrew)
    ```

    続いて、PostgreSQLに接続します。（ローカルであれば下記で行けるはず..）
    ```terminal
    username@pcname~% psql postgres
    psql (14.10 (Homebrew))
    Type "help" for help.
    
    postgres=# 
    ```

    早速、データベース作成をします。
    既存で、postgres/template0/template1のデータベースが存在しているので、そちらを使ってもOKです。（私は練習も兼ねて作成しました）
    ```terminal
    postgres=# create database practice;
    CREATE DATABASE

    postgres-# \l
                                    List of databases
       Name    |     Owner     | Encoding | Collate | Ctype |        Access privileges        
    -----------+---------------+----------+---------+-------+---------------------------------
     postgres  |      name     | UTF8     | C       | C     | 
     practice  |      name     | UTF8     | C       | C     | 
     
    ```

    続いて、ユーザーを作成し、ログイン権限を与えます。
    1. user1という名前のユーザーを作成したので、下記user1になっています。適宜変更ください
    1. 'password'には設定したいものを入れてください。（しなくても作成できるそうです）
    ```terminal
    postgres=# CREATE USER user1 WITH PASSWORD 'password';
    CREATE ROLE
    
    postgres=# ALTER ROLE user1 LOGIN;
    ALTER ROLE
    
    postgres=# \du
                                         List of roles
       Role name   |                    Attributes                         | Member of 
    ---------------+-------------------------------------------------------+-----------
     user1(新規)    |                                                       | {}
     name1(既存)    | Superuser, Create role, Create DB, etc...             | {}
     
    ```

    以上で、（Localの）PostgreSQL側の設定は完了

## Dbeaver側での設定
1. Dbeaver起動後、左上の下記画押下
![Screenshot 0006-01-13 at 18.49.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2510209/591e2db9-a8aa-800f-6bed-6f21ba43c20d.png)
2. 下記ダイアログが出るので、PostgreSQLを選択し「Next>」を押下
![Screenshot 0006-01-13 at 18.51.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2510209/fcdf851b-cf94-5e93-88fb-e8293ad060a8.png)
3. 次ページにて、Databaseの名前とUsername・Passwordを入力します。
![Screenshot 0006-01-13 at 18.53.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2510209/1da0fed0-2b0b-e9f0-7a02-2a6a9bc4850f.png)
![Screenshot 0006-01-13 at 18.53.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2510209/d89bd176-9f34-7b94-3ae8-8dc7a4717d4d.png)
4. ダイアログ左下のテスト接続（or Test Connection）を押下後、下記ダイアログのような接続完了が出ればOK
![Screenshot 0006-01-13 at 18.55.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2510209/551fe80d-c281-fbd3-b010-7bb6005b9114.png)
5. OK押下後、ダイアログ右下の終了（or Finish）を押下し完了
Git Flowとは

# Git Flowとは
Git Flowは、Vincent Driessenによって提案され、広く採用されているGitのブランチ管理戦略です。Git Flowは、Gitリポジトリ内での機能開発、リリース、およびバージョン管理を容易にするために、主に複数のブランチを使用します。

Git Flowの主要なブランチは次のとおりです：

1. **master**: 安定したプロダクションリリースが保持されます。
2. **develop**: 開発中の最新の開発状態が保持されます。
3. **feature**: 新しい機能の開発に使用されるブランチです。各機能は独立したブランチで開発され、開発が完了したらdevelopブランチにマージされます。
4. **release**: 次のリリースの準備中に使用されるブランチです。リリース準備が完了すると、このブランチはmasterブランチにマージされ、新しいバージョンがリリースされます。
5. **hotfix**: プロダクション環境で発生した緊急の修正を行うためのブランチです。修正が完了すると、このブランチはmasterブランチとdevelopブランチの両方にマージされます。

これらのブランチングモデルに従うことで、チームは効果的に機能の開発、テスト、リリースを管理できます。これにより、コードの安定性が向上し、コラボレーションが容易になります。
機械学習リンク集2024



https://qiita.com/tech-Mira/items/67dec9c5a5f025d2727a

https://arxiv.org/html/2402.17764v1

chrome-extension://efaidnbmnnnibpcajpcglclefindmkaj/https://www-mcs.c.oka-pu.ac.jp/pdf/abstract/2011_Nagashi_BachelorAbstract.pdf