OmniAICreator/Qiita-1.07M huggingface dataset:
【ChatGPT】カスタムGPTに会話内容を保持させる

こんにちは!
前回作成したキャリアアップ用のカスタムGPTの続きとなります。

https://qiita.com/shikamayuya777/items/21198d57004e95f2bf03

### カスタムGPTに会話内容を保持させる

前回、キャリアアップのための学習計画をGPTと一緒に考え、初めにG資格とE資格の取得を目標に掲げました。

![https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_3920265_fb7c076f-2a12-14b3-7bdd-4703f5eacc32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/352b2393-4968-920f-6f76-c07ea449328a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/361da0d7-52f8-0890-a5ff-132592249e25.png)

今後はこの内容に従ってキャリアアップのための活動を行っていこうと思っていましたが、ChatGPTは会話の内容を長期的に保持する機能がなく、別の会話を開くと前回の会話内容がリセットされてしまうようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/131d73e9-22ea-a297-bd00-4606bdcc6bc2.png)

記憶を保持するようカスタムGPT作成画面で指示してもそのような機能はありませんと回答が返ってきます。

![https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_3920265_19e3d1b7-32be-aedc-6243-2395debe3ea0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/11bf5dc5-b484-dda0-7514-41166fee888f.png)


これでは今月の目標を再度聞いても前回の会話内容が保持されていないため、同じ回答を得ることができないようですね。

chatGPTでは前回の会話内容を長期的に保持することができないで別の会話を開くと内容がリセットされまた一から始まってしまうようです。

そこで、カスタムGPTの「知識アップロード」機能を使って会話内容を保持させることにしました。以下はその手順になります。

まずは、ChatGPTからやり取りの内容を出力してもらいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/05a28776-7ba7-c857-4446-7cd2317e50f8.png)

まとめてもらった内容をテキストファイルにコピーします。

![SnapCrab_NoName_2024-10-28_22-34-58_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/bf31b400-7f4e-d9bf-7aa3-d48b94a2877d.png)

それを作成したGPTの知識にアップロード。

![SnapCrab_NoName_2024-10-27_11-46-34_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/87f74e42-3f30-b033-c313-7601eab79b71.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/a5422712-9a48-1764-ffe7-061d27687390.png)

![あああ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/0c342439-b3f7-2542-415e-ad85771358bb.png)

あとは知識の内容を参照するようGPTに指示してあげましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/66cca639-0aaf-998b-07c5-c41df42d448d.png)

知識をアップロード後に今月の目標を再度聞いてみると、前回の会話内容が反映されているため、今度は正確な回答が返ってきました!

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/d54dfa1a-652a-96f5-7af1-aad2132fc8cf.png)

以上、chatGPTに会話内容を記憶させる方法でした

自分のプロフィール情報や現在の資格取得状況をアップロードしておけば、それらを考慮した回答が得られるようになります。

知識にはPDFやExcelもアップロードできるようです。
アップロードするファイル次第、例えば説明書やシステムのマニュアルを知識としてカスタムGPTに入れておけば、自動でお問い合わせに対応するチャットボットとしても利用できそうですね。
`link_to`をブロックで囲った際に適用範囲がおかしい

# 問題
* `<div>` の範囲をリンクにしたくて以下のように実装していたが何故か `link_to` が反応しない
* デベロッパツールで確認してみると `div` が `<a>` に囲われていないという想定外の表示となっていた
    * 当然 `<div>` を押下しても無反応
```html:実装内容
<%= link_to XXX_url do %>
    <div>
    <!-- 中略 -->
    </div>
<% end %>
```

```html:デベロッパツールの表示結果
<a href="XXX"></a>
<div>
<!-- 中略 -->
</div>
```

# 修正
* よくよく確認した所 `link_to` ではない `<a>` が存在しており、これを削除したら想定の実装が出来た

```html:修正前
<%= link_to do %>
    <div>
    <!-- 中略 -->
        <a href="XXX"> XXXXX </a> 
    </div>
<% end %>
```

```html:修正後
<%= link_to do %>
    <div>
    <!-- 中略 -->
    </div>
<% end %>
```
[エラー対応]Reactに入門した人のためのもっとReactが楽しくなるステップアップコース完全版：基本的なページ遷移

## 状況
* Udemyの「Reactに入門した人のためのもっとReactが楽しくなるステップアップコース完全版」のセクション5: ルーティングの基礎(React Router)の基本的なページ遷移のレクチャーで`react-router-dom`のバージョンの違いによるエラーが起きた
* 具体的には`react-router-dom`のSwitchコンポーネントをimportしたときに画面が真っ白になった
* 環境はStackBlitzを使用
* `"react": "17.0.2"`,
    `"react-dom": "17.0.2"`,
    `"react-router-dom": "5.2.0"`　を使用

## 参考記事
https://qiita.com/Mai_HB/items/91c6660179b904684d75

## エラー対応
* 初めに参考記事を見ながら`react-router-dom`のバージョン5にインストールし直した
* Udemyの動画の冒頭でreactとreact-domのバージョンを17にするよう指示があったのでインストールし直した
* しかし状況は変わらずエラーは解消しなかった（結局エラーの原因はわからず）
* 仕方なく再度StackBlitzの環境構築をやり直し、バージョンダウンを行わず進めた
* `"react": "^18.3.1"`,
    `"react-dom": "^18.3.1"`,
    `"react-router-dom": "^6.27.0"`　を使用
* `import { BrowserRouter, Link, Routes, Route } from 'react-router-dom';`
としてSwitchではなくRoutesコンポーネントを使用

* ```React
    <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/page1" element={<Page1 />} />
        <Route path="/page2" element={<Page2 />} />
    </Routes>

　　Routeはelementを使用する
* Udemy内で解説していたexactはRoutesコンポーネントでは不要

## まとめ
Udemyの動画内では`react-router-dom`のバージョンを5にするのをおすすめしていたが、なぜか上手くいかなかったためバージョン6で進める方法を取りました。

バージョン6ではSwitchではなくRoutesコンポーネントをつかわないといけないのとRouteコンポーネント内の記述法がバージョン5と違いがありました。

多分`react-router-dom`のバージョンを5のまま進める方法があると思うのですが、一旦この先のレクチャーもバージョン6で進めていこうと思います。
Formオブジェクトについて　【備忘録】

この議題は沢山の人が書いていますが、理解の為に自分の言葉で説明したいと思います。

１つのフォームから複数テーブルにデータを送信したいとき、この`Formオブジェクト`を使う。
（ほとんどが１つのフォームから２つのテーブルのケース）

一緒にする他モデルがあるモデルファイルにformオブジェクトファイルを作る。
名前は１つにしたいそれぞれのモデル名をつなげたもの。例）memo_form.rb、address_order.rb
この中にバリデーションやsave機能を記述することでまとめて複数のテーブルに送信する事が出来る。

最初聞いた時、多対多の中間モデルみたいなものかな？と思いました。
（あれは複数のidを１つのレコードで管理するテーブルでしたね。）
UnionFindの勉強【鉄則本A66】


筆者はレート700前後の茶色コーダ

今日は鉄則本のUnionFind問題を解いてみたので
記録としてまとめておく

https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_bn

# 実装コード

UnionFindはグラフをグループ分けするときに使う木構造

親がマイナス１のときに根とみなす

最初は何も繋がっていないので
大きさ１ですべて親を-1にする

繋げる度にサイズが大きい方を根にする
(そうしたほうが計算量少ないらしい)

根のノードが一緒なら同じグループとみなす

```python:main.py
import sys
def rI(): return int(sys.stdin.readline().rstrip())
def rLI(): return list(map(int,sys.stdin.readline().rstrip().split()))
def rI1(): return (int(sys.stdin.readline().rstrip())-1)
def rLI1(): return list(map(lambda a:int(a)-1,sys.stdin.readline().rstrip().split()))
def rS(): return sys.stdin.readline().rstrip()
def rLS(): return list(sys.stdin.readline().rstrip().split())
def err(*args): print(*args, file=sys.stderr)

class UnionFind:
    def __init__(self, n):
        self.parent = [-1] * -~n
        self.rank = [1] * -~n
    def root(self, x):
        while (p:=self.parent[x]) != -1:
            x = p
        return x
    def union(self, x, y):
        xr = self.root(x)
        yr = self.root(y)
        if xr == yr: return
        elif (rx:=self.rank[xr]) < (ry:=self.rank[yr]):
            self.parent[xr] = yr
            self.rank[yr] += rx
        else:
            self.parent[yr] = xr
            self.rank[xr] += ry
    def same(self,x,y):
        # err(self.root(x), self.root(y))
        return self.root(x) == self.root(y)
        

def main():
    N, Q = rLI()
    
    UF = UnionFind(N)
    
    for _ in range(Q):
        q, u, v = rLI()
        # err(q,u,v)
        if q == 1:
            UF.union(u,v)
        if q == 2:
            print("YNeos"[1-UF.same(u,v)::2])
    
    
if __name__ == '__main__':
    main()

```



# まとめ

鉄則本のUnionFind問題を解いた
実装は意外と単純だった

今度はこれを使うABCの過去問とか解いてみたい

# おまけ

今回のUnionFind実装をVSCodeスニペットにしたので
使いたい人どうぞ

<details><summary>折りたたみ</summary>

```json:python.json
{
    "Union-Find": {
        "prefix": "unionfind",
        "body": [
            "class UnionFind:",
            "    def __init__(self, n):",
            "        self.parent = [-1] * -~n",
            "        self.rank = [1] * -~n",
            "    def root(self, x):",
            "        while (p:=self.parent[x]) != -1:",
            "            x = p",
            "        return x",
            "    def union(self, x, y):",
            "        xr = self.root(x)",
            "        yr = self.root(y)",
            "        if xr == yr: return",
            "        elif (rx:=self.rank[xr]) < (ry:=self.rank[yr]):",
            "            self.parent[xr] = yr",
            "            self.rank[yr] += rx",
            "        else:",
            "            self.parent[yr] = xr",
            "            self.rank[xr] += ry",
            "    def same(self,x,y):",
            "        # err(self.root(x), self.root(y))",
            "        return self.root(x) == self.root(y)"
        ],
        "description": "Union-Findアルゴリズムを実装"
    }
}
```

</details>
SIGNATE CLIとGoogleColabで簡単にコンペに参加してみる

# はじめに

　本記事では、SIGNATEというAIコンペティションサイトに簡単操作でGoogleColab上からコンペに参加するまでの備忘録です。

以下のサイトからコマンドなど引用しておりますので是非ご覧ください！

https://pypi.org/project/signate/

> - Python3.6 以降の環境が対称
> - Mac OSおよびLinuxをサポート


# 実行手順

前置きが長くなりましたがここからコンペに参加するまでの手順を一気に説明していきます！

## 1. SIGNATEにログイン
公式サイトから情報を入力してアカウントを作成してください
ここの操作については皆さん慣れていると思うので操作を割愛させていただきます！

https://signate.jp/

### ログイン後の手順

画面右上のプロフィールからアカウント設定を開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818832/f0ee8861-f50d-a305-4866-22642ba8ef7f.png)

サービス利用管理項目より、API Tokenの作成をクリックして`signate.json`をダウンロードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818832/744c1a18-6493-0bbb-9e6a-4c3501f4bcca.png)

ダウンロードしたファイルをGoogleDriveのマイドライブ上のどこかにアップロードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818832/a7c010cb-c903-9ae6-6b7a-b5ba41bf9c3a.png)

これで下準備は完了です！

## 2.APIキーをColabインスタンス上に保存

任意のフォルダにノートブックを作成し、セルで以下のコードを実行します。

```python
!pip install signate
from google.colab import drive
import shutil
import os

# Googleドライブをマウント
drive.mount('/content/drive')

# コピー元とコピー先のパスを指定
source_path = '/content/drive/MyDrive/signate/signate.json'  # 実際のファイルパスに変更
destination_path = '/root/.signate/signate.json'

# 保存先ディレクトリがない場合は作成
os.makedirs(os.path.dirname(destination_path), exist_ok=True)

# ファイルをコピー
shutil.copy(source_path, destination_path)

print("signate.json copied successfully.")
```

> ここでエラーが出てもゴールはすぐそこです！
おそらくパス名が間違っているだけなのでエラーが出てもめげずに頑張りましょう！

## 3. いざ、コンペ選択

別のセルで以下のコードを入力し、開催しているコンペの一覧を出力します。

```python
! signate list
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818832/2570c089-8be9-f154-eeef-45e40cfc4a5f.png)

### 必要なデータのダウンロード

参加したいコンペを決めたら次にダウンロード可能なファイルの確認です。
コンペリストに表示してあるコンペIDを以下のコードの最後に入力し実行してください。

```python
! signate files --competition-id=<competitionId>
```

次のコードで一式ダウンロードします。

```python
! signate download --competition-id=<competitionId>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818832/b2845f92-2765-6724-c897-2e7cf341fb8e.png)


# 準備完了！

これで戦闘準備は完璧なはずです！
最後にデータの一部を覗いてください！

```python
import pandas as pd

df_train = pd.read_csv('/content/train.csv')
df_test = pd.read_csv('/content/test.csv')

df_train.head()
```

# さいごに

　本記事ではコンペの始め方について解説しましたが、リファレンスによるとデータの提出までコマンドからできるようです。私はまだ操作に慣れてなく、画面上からしか提出したことしかありませんが賢い面倒くさがり屋さんはぜひ試してみてください！
insert文作成エクセルマクロ

```
Sub CreateInsertSQL()
    Dim ws As Worksheet
    Dim tableName As String
    Dim colNames As String
    Dim rowCount As Long
    Dim colCount As Long
    Dim i As Long, j As Long
    Dim insertSQL As String
    Dim fileName As String
    Dim fileNum As Integer
    Dim filePath As String
    Dim nn As Integer
    Dim fileExists As Boolean

    Set ws = ThisWorkbook.Sheets("Sheet1") ' シート名を適宜変更してください

    ' テーブル名を取得
    tableName = ws.Range("B1").Value

    ' カラム名を取得
    colCount = ws.Cells(3, ws.Columns.Count).End(xlToLeft).Column
    colNames = ""
    For j = 1 To colCount
        colNames = colNames & ws.Cells(3, j).Value
        If j <> colCount Then
            colNames = colNames & ", "
        End If
    Next j

    ' 行数を取得
    rowCount = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row

    ' INSERT文を作成
    insertSQL = ""
    For i = 4 To rowCount
        insertSQL = insertSQL & "INSERT INTO " & tableName & " (" & colNames & ") VALUES ("
        For j = 1 To colCount
            ' 値が数値の場合
            If IsNumeric(ws.Cells(i, j).Value) And Not IsEmpty(ws.Cells(i, j).Value) Then
                insertSQL = insertSQL & ws.Cells(i, j).Value
            ' 値が日付の場合
            'ElseIf IsDate(ws.Cells(i, j).Value) Then
            '    insertSQL = insertSQL & "'" & Format(ws.Cells(i, j).Value, "yyyy-mm-dd") & "'"
            ' 値が文字列の場合
            Else
                insertSQL = insertSQL & "'" & Replace(ws.Cells(i, j).Value, "'", "''") & "'"
            End If
            If j <> colCount Then
                insertSQL = insertSQL & ", "
            End If
        Next j
        insertSQL = insertSQL & ");" & vbCrLf
    Next i

    ' ファイル名を作成
    nn = 1
    Do
        fileName = "insert_" & tableName & "_" & Format(nn, "00") & ".sql"
        filePath = ThisWorkbook.Path & Application.PathSeparator & fileName
        If Dir(filePath) <> "" Then
            nn = nn + 1
        Else
            Exit Do
        End If
    Loop

    ' ファイルに書き込み
    fileNum = FreeFile
    Open filePath For Output As #fileNum
    Print #fileNum, insertSQL
    Close #fileNum

    MsgBox "INSERT文をファイルに出力しました: " & fileName

End Sub
```

以下のようなシートを作成しマクロを実行
![スクリーンショット 2024-10-28 午後10.31.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241513/0ae1f992-5240-78e4-33c8-27908780ebab.png)
Difyを使用してMicrosoft Teamsに通知を送る方法

## ■概要

タイトルの通り、簡単な内容ですが書き残したいと思います。

# ■やること

今回Webhookを使用します。
まず、最初にteams側でWebhookを設定し、その後Dify側ではブロックを設定するという所です。

詳細なこと、後述していきます。

# ■TeamsでWebhookの設定をする

まず、Teamsで通知を受け取るためのWebhook URLを取得していきましょう。
手順は以下の通りです。

1. **Teamsを開く**: 
   - 通知を送りたいチャンネルを選択します。
2. **コネクタの追加**:
   - チャンネル名の横にある「...」（その他のオプション）をクリックします。
   - 「チャネルを管理」を押下
   - 「**コネクタ**」を選択します。
3. **Incoming Webhookの設定**:
   - コネクタ一覧から「**Incoming Webhook**」を見つけ、「**追加**」または「**構成**」をクリックします。
   - Webhookに名前を付け、必要に応じてアイコンを設定します。
   - 「**作成**」をクリックすると、Webhook URLが生成されます。
   - **Webhook URLをコピー**しておきましょう。

:::note info
以下の公式ページにて、画象付きで紹介されていました。
こちらが画象付きで分かりやすいかもしれません！
:::

受信 Webhook を作成する
https://learn.microsoft.com/ja-jp/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook?tabs=newteams%2Cdotnet

# ■Difyでブロックを追加する（Webhook URLを設定）

次に、DifyでTeamsに通知を送信するための設定を行います。
（現在作成中のワークフローがある前提で進めます！）

1. **Difyのワークフローを開きましょう**
2. **ブロック（ステップ）の追加**:
   - ワークフローエディターの空いてる所で右クリック「**+ ブロックを追加**」をクリックします。
   - 「**HTTPリクエスト**」アクションを選択します。
3. **HTTPリクエストの設定**:
   - **メソッド**: `POST`
   - **URL**: 先ほど取得したTeamsのWebhook URLを入力します。
   - **ボディ**:
     - 送信したいメッセージをJSON形式で入力します。

![フロー1_20241028220535.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954355/bf938340-5038-b2d5-2882-aaab92330da0.png)

![フロー2_20241028220553.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954355/56000b50-3825-3b58-7b5a-116a7dde788b.png)

JSONの所は任意で変更してください！
今回テスト的に以下に設定しました。

   **例**:

   ```json
   {
     "text": "Difyからの自動通知メッセージです。"
   }
   ```

設定を保存して完了です！

## ■動作テスト

作成したフローの右上「...」から「このステップを実行」を選ぶことでこの通知部分だけをテスト可能です。

![テスト実行_20241028221110.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954355/c026690d-ac57-34d4-096d-ef2433258fa9.png)

問題なく、実行できていれば対象のチャンネルにメッセージが投稿されているかと思います。

![テスト実行2_20241028221313.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954355/0f3f6fa9-cc22-7c47-534e-a355bfb2ceea.png)

以上です！
【メモ】CSSを始めて1週間で学習したこと

# 概要
普段はTypeScriptとNodeでバックエンドの勉強をしているが、そろそろフロント側の技術も学習すべきと思ったためCSSを勉強し始めた
YoutubeやMDN・Webサイトを覗き、CSSにおける汎用的な記法や考え方が少しつかめてきたため、備忘録としてまとめる

# ボックスモデル
ブラウザに表示される文字やボタン、その他全ての要素は箱(ボックス)のような領域に囲われているという概念。[ボックスモデル(MDN 2024/10/28参照)](https://developer.mozilla.org/ja/docs/Learn/CSS/Building_blocks/The_box_model)

以下のことをイメージしやすくなった
- 要素はコンテンツ・パティング・ボーダー・マージンの4つのレイヤーを持つ
- 子要素が参照する親要素の位置や大きさ
    - `top: 0`や`width: 100%`など
- positonの`relative`と`absolute`の参照/被参照の関係性
    - `absolute`をもつ要素は最も近い`relative`をもつ親を基準にする？
- position`fix`と`sticky`の基準
    - 最も外側のタグ(`<html>`)を基準にする？

# リセットCSS
ブラウザの規定のCSSを消すためのCSSファイル
ブラウザ間の表示を統一するために使用する

# レスポンシブ対応
利用者の端末の画面幅によって表示を変えること
`@media`で表示幅が規定以下・以上の時に適応するCSSを変えることができる

# 汎用性のある記法
### 横並び
このcssを持つ親の子要素を横並びにする
```css
.x {
    display: flex;
    flex-wrap: wrap;
}
```

等間隔で左右に配置
```css
.x {
    display: flex;
    justify-conteint: space-between;
    flex-wrap: wrap;
}
```

### 中央揃え
左揃えのときは`margin-right`, 右揃えのときは`margin-left`を使用する
```css
.x {
    width: 90%; 
    margin: 0 auto; /*上下0 左右をwidthが親要素の幅に対して90%になるように自動調整*/
}
```

### px数をある数の倍数にする
px数を指定する場合、特定の数の倍数に揃えるとレイアウトにメリハリが出るらしい

# 終わりに
現在はこの程度しかわからないが、年末には適当に開いたウェブページの見た目を再現できるようにしたい
【備忘録】Spring Securityの導入

# Spring Security
Spring Security実装のメモ書き
## 開発環境
javaのバージョン : 21  
springbootのバージョン : 3.3.5  
依存関係の管理 : gradle  

## Spring Security の追加
gladleに依存関係を追加します。
```gradle:build.gradle
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-security'
}
```
プロジェクトを再ロードすることでSpring Securityがプロジェクトに追加されます。

## ログイン画面の表示
Spring securityの追加が完了すれば、ログイン画面が使えるようになります。  
プロジェクトを実行し、http://localhost:8080 にアクセスするとログイン画面が表示されます。  
![ログイン画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600926/3889ee59-7124-635d-1b6e-1f2fd81a34f4.png)

## ログイン後にHTMLファイルを表示する
ログイン完了後に、HTMLファイルが表示されるようにするため、各ファイルを作成します。
### LoginController.java
java/com/example/demo/controller/LoginController.java
```java:LoginController.java
package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class LoginController {
  @GetMapping("/")
  public String index() {
    return "redirect:index.html";
  }
}
```
### index.html
resources/static/index.html  
```html:index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>ログイン成功</title>
</head>
<body>
  <h1>ログイン成功</h1>
</body>
</html>
```

## ログイン
実際にログインをしてみる。  

Username : user  
Password : プロジェクト実行時すると、コンソールに表示される。  
![パスワード](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600926/fef8c607-72d7-e624-001f-6e4990cf5daf.png)

UsernameとPasswordを入力
![ログイン画面(入力)](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600926/a497e3c5-4eff-49c6-d53d-24b299adc8ce.png)

ログインに成功し、HTMLファイルが表示された。
![ログイン成功](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600926/a8ed998e-db36-a697-ee82-3a8fc7e61b93.png)

## まとめ
Spring Security導入の基礎の基礎を実装した。
次はユーザーごとにアクセス制御の設定を追加してみる。
作業煮詰まった時...どうしていますか？Vol.2

こんにちは。東です。
前回に引き続き技術的な内容を置いておいて、雑談のような内容になっております。
今回のテーマは
__「煮詰まった時の対処法」__ についてです。
前回の記事も良ければご覧ください。
[作業煮詰まった時...どうしていますか？Vol.1](https://qiita.com/pesysyon/items/ef747a72f8d9c00e31d2)
是非最後までお付き合いください。

## 間食
こちらも働いている方々の環境によってできるか微妙なですが...
できるのであれば1種の手段になってくれると思います。
嚙むようなものが食べることが許可されていましたら、ラムネやグミなどがいいですね。嚙んだりしていると眠気に対しても対処できそうですね。
そういうのがちょっと憚られるという場合はチョコレートがおすすめです。
サッととけるのでかまなくてもよかったり、糖分もそれなりにとれるので個人的に気にいっています。
<img width="150" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/b0bbddfc-5cc6-ce59-5374-77280c0d9b4d.png">
虫歯とカロリー過多にご注意！

## 香りによる刺激を加えてみる
こちらは比較的様々な方もできるので、結構おすすめです。
個人的に重宝していた方法は
・アロマストーンを持ち歩く
・ネックレスに入れて持ち歩く([こんな感じ](https://www.creema.jp/item/3574955/detail?ibi_action=send&ibi_category=ad_offsite&ibi_media=google&ibi_campaign=gpm_cr&gclid=Cj0KCQjw7Py4BhCbARIsAMMx-_I3uQskCU3Ggv6fAhIluPKWC8u9FfOmGH7b6ONC9FfntoHcx3B9rnIaApfDEALw_wcB))
というものでした。
嫌なことがあったり、気持ちの余裕がなくなったりするときも
お気に入りの香りを持っておくと、出先でも冷静な気持ちになることができます。
<img width="150" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/ae735e6e-74d2-2d7c-0336-a68652dfa7c8.png">
香りって重要！

## 思い切ってボーっとする時間を作る
最終手段です。
一旦、思考回路を開放しましょう。
5分間考えるのをやめてみましょう。
天井、空、壁、アスファルト、木などできるだけ刺激が少ないものにしましょう。
これが結構難しいことで、未だに上手くできることの方が少ないですが...
ただその分、帰ってきた際の閃きが戻ってきたりすることもあります。
是非お試しを！
<img width="150" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/ed6357ab-fa8f-86d8-e70d-b670c5a933b7.png">
こうなってしまったら、休みましょう...

## まとめ
いかがでしょうか？
前回に引き続き煮詰まった際の対応アレコレをまとめさせていただきました。
自分の管理も大切ですね。
ご覧いただきありがとうございました！
Chatterの「〇人が参照」「再生回数〇回」についての設定方法

本橋孝昭です

Chatterには
「〇人が参照」
や
「再生回数〇回」
の表示がされていますがこれはどのような設定で可能か検証します


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/2de360a7-26bb-5ff5-df7e-f31809960a01.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/ee6cce3a-87c9-3cdd-5e01-33a01965c1eb.png)





今回の内容は
・ユーザーの付与権限

により変更されます


ユーザーの付与権限は
・「[表示先] リストを非表示」チェックの有無
を確認します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/334d9374-1374-faa7-3346-6d19852c8e64.png)




## パターン1 「[表示先] リストを非表示」チェックが無い場合

「〇人が参照」が表示

※なお「〇人が参照」を表示する場合「すべてのデータの参照」権限が必要となります


## パターン2 「[表示先] リストを非表示」チェックが有る場合

「再生回数〇回」が表示
【Java】Springで利用可能なコンテンツがないときのエラー対応

## はじめに
今回はEclipseで`新規Springスターター・プロジェクト(Spring Initializr)`を選択したときに発生したエラーの対処内容を記載します。

## エラー内容
今回発生したエラーは下記になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3855381/8de65a71-37b2-5fcd-a613-d9b75d9cb6aa.png)

まずエラーの分析をします。上記画像のエラー原因をChatGPTに尋ねると下記の回答を得られました。

>この画像に表示されているエラーは、「SocketException: Connection reset」です。これは、Spring Initializr の新規プロジェクト作成画面での接続エラーです。具体的には、指定されたサービス URL（https://start.spring.io）に接続を試みた際に、接続がリセットされたことを示しています。
>
>このエラーが発生する原因としては以下のようなものが考えられます：
>
>ネットワークの問題: インターネット接続が不安定、または一時的なネットワーク障害が発生している可能性があります。
>
>ファイアウォールまたはプロキシの設定: 使用しているネットワーク環境のファイアウォールやプロキシが、この接続をブロックしている場合があります。
>
>サービスの一時的なダウン: Spring Initializr のサービスが一時的にダウンしている可能性があります。
>
>URLのタイプミス: 設定されている URL に誤りがあるか、スペルミスがある可能性があります。
>
>解決方法
>インターネット接続の確認: 他のウェブサイトにアクセスして、インターネットが正常に機能しているか確認します。
>
>ファイアウォール・プロキシの設定確認:
>
>使用しているファイアウォールやプロキシの設定を確認し、https://start.spring.io への接続が許可されているかを確認します。
必要に応じて、システム管理者に問い合わせて設定を変更してもらいます。
サービスの状況確認:
>
>しばらく待ってから再度試すか、サービスのステータスページ（もしあれば）を確認します。
URLの再確認:
>
>設定されている URL に誤りがないか確認し、必要に応じて訂正します。
上記のステップを試しても解決しない場合は、詳しい情報を元にさらに調査・対応する必要があります。

ChatGPTの回答によるとネットの設定やスペルミスが原因と指摘しています。
作業の直前にブラウザのキャッシュを削除していたため、プロキシあたりに問題がありそうです。

## 対処内容
ChatGPTによって大まかなエラー原因を特定できました。今回は下記の記事を参考に対処します。

https://qiita.com/sasaki_hir/items/72d309681a8215523cca

1. 記事を参考に[https://start.spring.io](https://start.spring.io)の証明書を取得する。
1. 取得した証明書をキーストアに登録する。
私の環境では下記のコマンドを実行しました。
```
%JAVA_HOME%\bin\keytool -importcert -keystore "%JAVA_HOME%\lib\security\cacerts" -storepass changeit -file "C:\Users\User\Downloads\_.spring.io.crt"
```

♯♯ 動作確認
証明書を追加したら、下記の画面に変わりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3855381/b38bf640-8bed-98e2-5fb8-22ffb9f3d7a6.png)

## おわりに
証明書を追加することで、無事`SocketException: Connection reset`を解決することができました。


## (column) ChatGPTを利用してみて
今回はエラーの分析にChatGPTを利用しましたが、画像認識能力と回答の精度の良さに非常に驚かされました。その反面、この精度の良さは情報漏洩のリスクも伴うことを再認識しました。業務でAIを利用するなら、利用する前にマスク処理などの工夫が必要だと感じました。適切に利用すれば、開発の補佐として非常に有用なツールとなると思います。
【Flutter】go_routerで前画面に戻ったことの検知&前画面に値を返却

タイトルの通りで、Flutterアプリにてよく利用されるクライアントサイドルーティングライブラリの 「go_router」で、前画面に戻ったことを検知し、それを契機に前画面側で処理をキックしたいというシーンに出くわしたが、意外とやり方が分からなかったので自分用メモ。

ついでに遷移先画面から遷移元画面に値を渡す方法も。

## 結論
こう。

```dart
final res = await context.push('/second_page');
```

このように書くと、second_pageから自身のpageに戻ってきた時にawaitの行以降が動き出すので、そのまま処理を書いていけば前画面に戻ったことを契機に自身のpage側の処理をキックすることが出来る。

resとして値を受け取っているが、呼び出された側の画面(遷移先の画面)でpop時に何某かの値を設定していれば、それをresとして受け取ることが出来る。

```dart
context.pop('SecondPage Button A Pressed!!');
```

なお、次画面側からヘッダーナビゲーションの戻るボタン等で前画面に戻ってきた場合は、await context.push~の値は`null`となる。

「なんかぱっとググっても(海外含)全然情報無いなあ...」と思っていたが、[go_router公式](https://pub.dev/documentation/go_router/latest/topics/Navigation-topic.html)の`Returning values`の項に普通に書いてあって泣いた。

まずは公式を熟読せよ、そういうことである。

## 参考ソース

```my_home_page.dart
// 遷移元画面
import 'package:flutter/material.dart';
import 'package:flutter_application_1/router/router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

class MyHomePage extends HookConsumerWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  Widget build(BuildContext context, WidgetRef ref) {

    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(title),
      ),
      body: Center(
        child: 
            ElevatedButton(
              onPressed: () async {
                final res = await context.push('/second_page');
                print('response from next page=$res');
              },
              child: const Text('Move2NextPage'),
            ),
        ),
      ),
    );
  }
}
```

```second_page.dart
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:go_router/go_router.dart';

class SecondPage extends HookConsumerWidget {
  const SecondPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        children: [
          const Text('This is SecondPage!!'),
          ElevatedButton(
              onPressed: () {
                context.pop('SecondPage Button A Pressed!!');
              },
              child: const Text('Back2FirstPage Button A'),
            ),
          ElevatedButton(
              onPressed: () {
                context.pop('SecondPage Button B Pressed!!');
              },
              child: const Text('Back2FirstPage Button B'),
            ),
        ],
      ),
    );
  }
}

```
(2024年度版) ocaml-lsp / Merlin で MetaOCaml を開発するためのメモ

MetaOCaml を触ってみようと思い開発環境をセットアップしようとしたところハマったのでとりあえず雑にメモ。時間があったら手直しますが期待しないでください。

基本的には2019年のこちらの記事に従えばOK: [[OCaml] MetaOCaml で IDE (Merlin) を使う方法と簡単な紹介](https://qiita.com/keigoi/items/c9f43309312978acf05a)

2019年と今で違う点
* 今は Merlin ではなく ocaml-lsp を使うのが主流になっているらしい。ocaml-lsp は内部的には Merlin を使っているのであまり大きな違いはない
* よってインストールするべきパッケージは以下のようになる
   ```
   opam install ocaml-lsp-server dot-merlin-reader
   ```
   * `dot-merlin-reader` は後述の理由で必要
* 元記事では `.merlin` ファイルに設定を記述しているが、ocaml-lsp はデフォルトでは `.merlin` を読まない設定になっているのでそのままで動かない。`ocaml-lsp` の起動オプションに `--fallback-read-dot-merlin` を付けることで`.merlin`を読ませることができる(dot-merlin-readerはこのために必要)
    * 起動オプションの変更はEmacsだったら `(setq lsp-ocaml-lsp-server-command '("ocamllsp" "--fallback-read-dot-merlin"))` などで変更できる。

わざわざMetaOCamlを触ろうという人だったらここまで書いたら後は自力でなんとかなると思います。がんばってください！

(追記) ocamlfmt は MetaOCaml をサポートしていないらしいです。諦めてください → https://github.com/ocaml-ppx/ocamlformat/issues/1211
【Chat GPT】キャリアコンサルタントとしての役割を持たせたカスタムGPTの開発

こんにちは！

現在システムエンジニアとして5年間働いている私ですが、そろそろキャリアアップを考え始める時期になりました。

なので今回はchatgptの有料版機能である「カスタムGPT」にキャリアコーチとしての役割を持たせてキャリアアップについていろいろアドバイスをもらってみよと思います。

### GPTの作成

まず、私のキャリアコーチとなる「カスタムGPT」を作成してみましょう!

プロフィール→マイGPT

![SnapCrab_NoName_2024-10-27_11-46-34_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/c4c80fd9-c1e4-dc0a-b788-d2ea37d301fc.png)

GPTを作成する

![SnapCrab_NoName_2024-10-27_11-57-23_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/dbcd509e-9352-1c86-2836-51f15846c535.png)

![SnapCrab_NoName_2024-10-27_11-59-48_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/7051e5b3-c512-9fd7-15e1-418d7e152e8f.png)

これがカスタムGPTの作成画面になります!

左側に指示を入力していくようですね

では早速プロンプトを入力していきましょう!

```
### GPTの役割
私のキャリアに関して、現状の分析や次のステップについてのアドバイスを求めます。
キャリアアドバイザーとして、以下の情報を元に、私のスキルや希望に合った具体的なキャリアプランを提案してください。

### 要件
1. **現在の状況**  
   - 現在の職種: システムエンジニア 
   - 勤務年数: 5年  
   - 主要スキル: プログラミング（Java, Python, HTML）
   - 興味のある分野: AIエンジニア  

2. **今後のキャリアについて**  
     AIエンジニアとして活躍できる人材となり、将来はフリーランスとして独立を目指す。

3. **制約条件**  
   - 学習にかけられる時間: 週に10時間
   - 地域やその他の制限: 日本国内で東日本で活動したい

### 期待する出力
- 私の現在の状況と目標に基づいて、次に取るべき具体的なステップの提案（例: 学習すべきスキル、転職に向けての準備、成長を加速させるためのアクション）
- 選択肢の長所と短所、リスクとチャンス
- 短期・中期・長期的な目標設定のアドバイス
- 必要なリソースや参考になる教材・資格のリスト
```

今回はこのようなプロンプトを使用します。
現状と目標、転職時期等を詳細に示すことで、GPTが的確なキャリアプランを提案できるようにしました。

![SnapCrab_NoName_2024-10-28_18-19-25_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/324b174f-9221-9659-c549-42609feff0ad.png)

プロンプトを打ち込むとAIがGPTの名前を提案してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/6866bbf6-f8dd-32be-cc96-ebd97e0896de.png)

GPT名やプロフィール画像はこんな感じに会話ベースで指定することができます。
専門的な知識がなくても、アプリを作成できるのは本当に驚きですね。

あとは流れに従って会話を進め右上の作成ボタンを押せば完成になります

![SnapCrab_NoName_2024-10-28_18-33-9_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/158230b8-6f49-ea7d-84d3-d0aa2aa4fa1e.png)
![SnapCrab_NoName_2024-10-28_18-33-28_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/05eac59c-5458-6dde-f531-53602f7eda6f.png)

早速アドバイスを求めてみましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/fb7c076f-2a12-14b3-7bdd-4703f5eacc32.png)

どうですかね?
個人的にはかなり具体的でとてもいいプランと思いました。

あとは学習スケジュールや勉強法なども聞けば答えてくれました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920265/506bded0-ef5a-930e-d943-76bdcae7c2d0.png)

このGPTを使用してこれからキャリアアップのための学習進めていこうと思います。

自分流のチャットボットを簡単に作成できるカスタムGPT、アイデア次第でいろんなことができそうで面白そうですよね！
これからも、他にどんなことができるか、いろいろ試してみようと思います。
個人PCでVScode+AzureDevOps環境準備したメモ

# 1. ソースコード管理ツール
ソースコード管理ツールにはどのようなものがあるのかを一表にしてみました。


| ツール | 特徴 | 長所 | 短所 | 適用シーン | 有料/無償 |
|:-:|:-:|:-:|:-:|:-:|:-:|
| GitHub | 世界最大のGitホスティング | オープンソース、CI/CD、自動化が強力 | エンタープライズ機能は有料 | オープンソース、企業内のコラボレーション開発 | 無償（基本機能） / 有料（エンタープライズ機能） |
| Azure DevOps | 開発ライフサイクル全体を管理 | CI/CD、Azure統合 | 一部機能はAzureサブスクリプションが必要 | Azureを使ったエンタープライズ向け開発 | 無償（基本機能） / 有料（高度な機能） |
| GitLab | 自社サーバーにホスティング可能 | DevSecOps対応、CI/CD標準搭載 | 高機能プランのコストが高め | セキュリティやプライバシーを重視したプロジェクト | 無償（基本機能） / 有料（プレミアム機能） |
| Bitbucket | Atlassian製品と連携 | Jiraとの統合、小規模チームに最適 | プラグインの選択肢が少ない |  Atlassian利用企業や小規模チーム| 無償（5ユーザーまで） / 有料（6ユーザー以上） |
| Gitea | 軽量で設定が簡単 | 自社サーバーにホスティング可能 | 機能が少ない | リソースが限られた環境でのシンプルなGit管理 | 無償（オープンソース） |

ChatGPTによると、
>**Azure DevOps**はMicrosoftが提供する統合された開発ツールスイートで、AzureリポジトリとしてGitリポジトリを提供します。CI/CDやプロジェクト管理、テスト管理など開発ライフサイクル全体をサポートします。

無料で使うことができるとのこと。

# 2. 手順

マイクロソフトのサイトに飛び、サインイン
https://azure.microsoft.com/ja-jp/products/devops/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452338/faf96f23-80f0-2261-54b8-aa9b9a2f8e39.png)

検索バーで「Azure DevOps」を検索
※筆者はすでに登録してあったので直接Azureのポータルに入れたが、必要に応じて登録する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452338/36ccde1c-faa5-683e-3bd6-d8635c0e533f.png)

「My Azure DevOps Organizations」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452338/5742af89-ec7f-1d97-4c07-50b477254e0b.png)

「Create new organization」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452338/dca8ae9a-7a55-de78-2955-3627ab367084.png)

作成が完了すると以下の画面のようになる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452338/1409b9f9-3e91-8870-2d77-bae4457702cd.png)

プロジェクトを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452338/c7d869fa-9ef6-3102-c405-86a1551d730b.png)

作成が完了するとこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452338/b733affc-afb9-2ff7-3cb6-b62666c3139f.png)

「Repos」タブを選択→「Generate Git Credentials」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452338/a1dfbfdc-b42b-21b6-024d-a9780c64f37b.png)

「Clone in VS Code」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452338/4793053a-e7e9-614b-c906-ec97c8ee2e19.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452338/53aa0572-71c0-8669-66d9-7ddcd1c5d8bd.png)

準備完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452338/5578e031-6fbd-d19a-4af6-30d407b2111b.png)

PowerShellの拡張機能も必要そうな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452338/e371b660-a17e-83ac-aa99-1708f9e79727.png)

なぜか「Commit」を押してもCommitが終わらない・・・。
なにか設定不足だったのか・・・。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452338/ebc6a80e-864b-614f-3aed-f45a6d3864fb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452338/5a99d433-22f9-221f-9041-a1a83d8e729b.png)


# 3. 参考文献

https://qiita.com/yamazaki3104/items/8aef0c1aad99895a6097
異なるサーバー間でのデータベースのコピーにハマった話(SQLServer)

# はじめに
以前、同じサーバー(同一のSQL Serverインスタンス)間でデータベースの複製を行いました。
その際に バックアップ(コピー元) → 復元(コピー先) という手順で非常に簡単に複製することができました。
しかし、今回異なるサーバー間で複製しようとしたらハマったので備忘録として残しておきます。

# 環境
`サーバーA`：コピー元のデータベース(データベースAとします)がある
`サーバーB`：ここにデータベースAを複製したい
※サーバーA,BともにSQL Server Management Studio (SSMS) がインストールされている前提です

# 試したこと

### コピー元サーバーでの操作
コピー元サーバーのSSMSからデータベースAで右クリック　⇒　`タスク`　⇒　`バックアップ`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726673/3df4e321-6832-d6eb-13b3-14f4c490028c.png)

コピーしたい `データベース` を選択　⇒　`バックアップの種類` を `完全` とする
`バックアップ先` を選択し `OK`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726673/81475734-ed8d-27d3-b982-a7ef18bd5046.png)

指定のバックアップ先のフォルダに.bakファイルが作成されるためバックアップは完了

### コピー先サーバーでの操作
コピー先サーバーのSSMSからコピー先としたいデータベースを右クリック　⇒　`タスク`　⇒　`復元`　⇒　`Fileおよびファイルグループ`
![復元メニュー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726673/7ab79941-be0a-d449-014c-1e7084bb6bff.jpeg)

先ほど作成した.bakファイルを `復元元デバイス` として選択し、 `OK`

同じサーバー(同一のSQL Serverインスタンス)間のコピーではこれで問題なく復元ができるはずです。
しかし異なるサーバー間だとエラーとなりました。

# エラー内容
以下発生したエラー内容です。
```
サーバー '{コピー先サーバ名}' の復元に失敗しました。  (Microsoft.SqlServer.SmoExtended)
Transact-SQL ステートメントまたはバッチの実行中に例外が発生しました。 (Microsoft.SqlServer.ConnectionInfo)
バックアップ セットは、既存のデータベース '{コピー先データベース名}' 以外のデータベースのバックアップを保持しています。
RESTORE DATABASE が異常終了しています。 (Microsoft SQL Server、エラー: 3154)
```

どうやら.bakファイル内には既存のデータベース (コピー先データベース)とは異なるバックアップを保持している(当たり前といえば当たり前だが。)とのことです。

試しにコピー先データベース名を、コピー元データベース名と同一にして再度実行してみましたが、同じエラーが発生しました。

# 原因
調べてみるとどうやら、**バックアップ機能**では様々な制約があり、異なるサーバー間ではうまくいかないことがあるそうです。

まあそもそも”バックアップ”という名のついている機能なので、基本的には同じデータベースが障害などでクラッシュしたときの復元に使用する前提の機能だからだと考えています。

# 解決策
いろいろな方法があると思いますが、以下の方法が簡単でした。
まずコピー作業を、 `テーブル定義` のコピーと中身の `データ` のコピーの２段階に分けます。
`テーブル定義` は**スクリプト機能**を使用
`データ` は**エクスポート機能**を使用

一つずつ解説します。

### テーブル定義のコピー
コピー元のデータベースを右クリック　⇒　`タスク`　⇒　`スクリプトの生成`

![スクリプト生成5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726673/56ec2448-d877-67ef-63d9-dc4ed67540d5.jpeg)


スクリプトの生成ウィザードが表示されるため、`特定のデータベースオブジェクトを選択`　を押下するとオブジェクトが選択できるようになるので、`すべて選択`　を押下しチェックを入れる

![スクリプト生成2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726673/7bcf63b5-d765-c2c4-9944-21426c1c463c.jpeg)

次にスクリプトの保存方法を決めます。
これはお好みの方法でどうぞ。
ここでは `スクリプトファイルとして保存` を選択しています。

![スクリプト生成3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726673/f4808cd7-5347-9372-b38e-0ab57a8633db.jpeg)

次に、`詳細`　ボタンを押下し詳細オプションを表示させます。
ここで、`インデックスのスクリプトを作成`　をTrueにしておきます。
ほとんどのテーブルでは検索速度を高めるためのインデックスが設定されていると思いますので、それも一緒に作成するようにしておきます。

![スクリプト生成4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726673/aaf7da3d-05e6-5612-5fca-8c037c8d0a5d.jpeg)


そして生成されたスクリプトをコピー先のデータベースで実行すると
コピー元のテーブルやストアドなどが新たに作成されます。

ただし、このままではテーブル定義のみのコピーであり、中身のデータは空っぽのため次に解説する**エクスポート機能**でデータのコピーを実施します。

### データのコピー
コピー元のデータベースを右クリック　⇒　`タスク`　⇒　`エクスポート`

![スクリプト生成.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726673/0fccf9c6-71bb-f407-3670-d91baa5ef136.jpeg)

エクスポートウィザードが表示されるため、コピー元とコピー先の情報を入力し指示通りにエクスポートを実施します。
以上の操作でデータベースそのもののコピーが完了します。

# まとめ：
異なるサーバー間でのデータベース移行では**バックアップ機能**は制約があり使えない。
**スクリプト機能**と**エクスポート機能**を使用すると簡単にデータベースのコピーができることがわかりました。
初めてのHTML #1

# 1 VSCodeの導入
まず初めにVSCodeの公式サイトにアクセスする。
https://code.visualstudio.com/
ダウンロードしたファイルを解凍して
解凍してでてきたファイルをアプリケーションフォルダに移す
そしてVScodeを開いたらこのような画面になります。
![スクリーンショット 2024-10-28 21.30.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919171/bc81d26f-12ce-4647-3d01-32b2c76cd366.png)
# 2 VSCodeの日本語化
VSCodeを日本語化するためには、左のバーのExtensionsをクリックするそうして検索バーにJapaneseと入力するとJapanese Language Pack for VS Codeが出てくると思うのでそれをインストールしてVSCodeを再起動すれば日本語化完了です。
これでVSCodeですることは完了です。
# 3 VSCodeとは
VSCodeとは、Microsoftが開発・公開しているコードエディタです。コードエディタは他にもSublime Text,Atom,CotEditorなどがあるので自分に合うものを使うといいと思います。
（本番環境）Rails における `devise + Omniauth` の Google 認証の導入メモ

# はじめに
* こちらの記事の通りにローカルで試験的に Google 認証が出来たことを確認済みな状態が前提となっております

https://qiita.com/nakad119/items/9caa1ce803185b93fe85

* 「本番環境」 = 「デプロイ済みの Web アプリがある」という前提となっております
    * 私は Render に web アプリをデプロイしております

---
# 本番の URI を追加するだけ
* やることは単純で<font color="Red"> Google Cloud コンソールで公開した Web アプリの URI を追加するだけ</font>
    * Google Cloud コンソールでは `http://localhost:XXXX/` のようにローカルだけでの利用を許可している状況だとデプロイした Web アプリでは利用許可が降りていません

## 現状
* 現状はローカルホストだけでの利用を許可されているためデプロイしたアプリで Google 認証を利用しようとすると以下のような画面が表示されるかと思います

（図1 : ローカル環境ではログイン認証が利用できていたはずがブロックされる）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3518714/219c316e-7720-edfc-42df-390f04255e8d.png)

# 手順
## 1. デプロイしたアプリの URI を追加
* デプロイした Web アプリの URI を二箇所にコピペする
　
* 【上】 承認済みの JavaScript 生成元
    * こちらはそのままコピペ
* 【下】承認済みのリダイレクト URI
    * コピペした URI にコールバック先のアクションのパスを追記
        * この例だと "URI 1" の `http://localhost:3000/` をデプロイした Web アプリの URI に書き換えるだけ


（図2 : デプロイした Web アプリの URL を二箇所にコピペする）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3518714/7d88410d-81ec-3b74-a6cc-ab552ec5da2f.png)


## 2. 公開ステータスの変更
* 公開ステータスは特に触っていなければデフォルトの "テスト" のままだと思いますのでこれを変更
* 公開ステータスが "テスト" のままだと図 3 の通り「検証での利用を許可しているだけだから利用可能なユーザーの数は制限しているよ」という状態なので変更が必要


（図3 : 公開ステータスの説明）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3518714/d530a99a-72a7-3f06-c1d9-69aee5fe84cf.png)


（図4 : 公開ステータス）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3518714/6a499549-c4d0-0671-ea63-21585a8ca622.png)

以上です

---
### 不明点
* 検証として新たに Google アカウントを作成して公開ステータスは"テスト"のままテストユーザーに追加していないユーザーとしてログインをしてみたところ、想定ではログインをブロックされるかと思ったがログインできてしまった


---
### 参考資料

https://zenn.dev/tteaoocl/articles/5601b28fa8045d
PowerShellで角括弧ファイル名を変更する方法

# PowerShellで角括弧ファイル名を扱う際の注意点

下記のようなcmdletを実行した際に見つからないというエラーが出た。
```
Rename-Item -Path "C:\Temp\[test].txt" "C:\Temp\[test].txt" -NewName "test.txt"
>> Rename-Item : 引数 'C:\Temp\[test].txt' を受け入れる位置指定パラメーターが見つかりません。
```


どうやら原因は角括弧([])はPowerShellでワイルドカードとして使用されているからだそう。
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_wildcards?view=powershell-7.4


対策として、-LiteralPathオプションを指定してファイル名変更を実行
```
Rename-Item -LiteralPath "C:\Temp\[test].txt" -NewName "C:\Temp\test.txt"
```
.NET「Rider」非商用で無償

# .NET 「Rider」　非商用利用ならば無償

IntelliJ IDEAなどの統合開発ツールやKotlin言語の開発などで知られるJetBrainsは、JavaScript/TypeScriptのためのIDE「WebStorm」と.NETおよびゲーム開発のためのIDE「Rider」を、非商用利用ならば無償で利用可能にすることを発表しました。

https://www.publickey1.jp/blog/24/jetbrainsjavascripttypescriptidewebstormnetideriderrustroveraqua.html

非商用　無償

https://www.jetbrains.com/ja-jp/rider/buy/?section=personal&billing=yearly
iPhone ミラーリング 

iPhoneのミラーリング機能の説明です。

環境：iMac M1デスクトップ、iPhone iOS 18 機種は結構前。

MacOS 15をインストールした後、iPhoneのマークのようなアイコンがDeckに表示されています。
これがiPhoneのミラーリング機能です。

１、有効化
iPhoneのパスコードを入力。
MacOSのログインパスワードを入力。

２、iPhone画面が表示！
結構綺麗に映ります。自分のiPhoneのサイズと同じ大きさのウィンドウが表示されている。横表示マークをクリックすると、横が長い画面になりました。とても読みやすいです。

３、音声
iPhoneの音声がiMacのスピーカーから流れて、自然に聞こえます。

４、所感
iPhone画面を普通のMacOSアプリと同様に、位置を移動できます。
何がいいの？と聞かれると、なんかいいと言います。
やはり、iPhone上によく使うアプリがあります。iMacで勉強、資料を読む時に、iPhoneのアプリを使うと、なんか新鮮です。

また、改めて、iMacの画面の大きさとiPhoneのとの違いが感じました。こんな小さい画面を毎日見ているんだと思いました。
解像度はiPhoneのほうが高いらしいです。気にせいかもしれません。

そのあたり、使う人の近い方次第かと思います。人それぞれの感触があります。個人的には使える機能と思います。

以前のiPodがそのままiPhoneの1アプリになったと同じように、iPhoneはiMacの1アプリになるとか。

まあ、試してみてください。

以上
github pagesの404ページを変更する方法。(メモ)

## 早速やっていく
まず、404.mdを作成し、

```
---
permalink: /404.html
---
```
と入れ、404.htmlを下の画像のように作って

![404 test page](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569677/7482b1ba-4c59-893b-0867-8ccc71a3b8f5.png)
やったら完成です。
【React × react-testing-library × Jest】error: uncaught [typeerror: cannot read properties of undefined (reading 'sanitize')]の解決方法

# はじめに
React Testing LibraryとJestを用いたテスト実装中に、DOMPurifyに関連するエラーが発生したので、解決方法をまとめました。エラーの原因と解決方法を解説します。

:::note warn
***この記事は<font color="Red">個人的なアウトプット</font>を目的として作成したものです。そのため、誤った情報や不足している内容が含まれている可能性があります。もし間違いや気になる点がございましたら、ぜひご指摘いただけますと幸いです***。
:::

# 問題
以下のようなエラーが発生しました。
```
error: uncaught [typeerror: cannot read properties of undefined (reading 'sanitize')]
```

エラーの原因は、DOMPurifyの設定やモジュールのインポート方法に問題があったようです。コンポーネントのコードは以下の通りです。

```react
import { useEffect, useState } from "react";
import { getAllUsersData } from "../utils/supabaseFunction";
import { User } from "../domain/User";

import { Box, Button, Link, Text } from "@chakra-ui/react";
import { useParams } from "react-router-dom";
import { ExternalLinkIcon } from "@chakra-ui/icons";
import * as DOMPurify from "isomorphic-dompurify";

import parse from "html-react-parser";

const Card = () => {
  const { id } = useParams();
  const [userData, setuserData] = useState<User[]>([]);
  const [loading, setLoading] = useState(true);

  const ParserSanitized = ({ html }: { html: string }) => {
    const sanitizedHtml = DOMPurify.sanitize(html);
    return parse(sanitizedHtml);
  };
  return (
  //省力
  );
};

export default Card;

```
# 原因と解決方法
`DOMPurify`を使用する際に、`sanitize`が定義されていないというエラーが発生しました。このエラーの原因と解決方法は以下の通りです。

以下のように、`DOMPurify`のインポートを変更します。

```react
import * as DOMPurify from "isomorphic-dompurify";
```
この修正でエラーが解消されましたが、次に以下のエラーが発生しました。

```
Cannot find module 'isomorphic-dompurify' or its corresponding type declarations.
```

このエラーは、isomorphic-dompurifyがインストールされていないために発生します。以下のコマンドでモジュールをインストールすることで解消しました。

```
 npm i isomorphic-dompurify 
```

# 終わりに
今回は`DOMPurify`に関するエラーの解消でした。今後もテストやエラーを通じてさらに学びを深めていきたいと思います。

# 参考
『【React Jest】DOMPurifyを自動テスト中に使った際のimportエラー』
https://qiita.com/yuuki4135/items/17eef9ca5992cf9fac53
「llama.cpp」メカニズムと推論プロセス詳解ガイド

`llama.cpp` は、Meta の LLaMA モデルの推論とデプロイに特化した軽量な C++ 実装です。このプロジェクトは、大規模なディープラーニングフレームワーク（PyTorch や TensorFlow など）に依存せずに LLaMA モデルを効率的に動作させることを目的とし、特に個人PCやモバイル端末といったリソースの限られた環境での実行を可能にしています。以下では `llama.cpp` の主な動作原理について、モデルの表現方法や推論手法を解説します。

### 1. モデルの表現

`llama.cpp` では、LLaMA モデルのデータ構造とストレージ形式がメモリ効率を重視して設計されており、特に量子化によってメモリや計算量の削減を図っています。モデルの主な構造には、重み（weights）、埋め込み（embeddings）、Transformer 層のマルチヘッドアテンション、前方フィードネットワーク（FFN）などが含まれます。

#### モデルファイルの読み込み
LLaMA モデルの重みファイルは `.bin` 形式のカスタムバイナリファイルとして保存されており、このファイルにはモデルの層数、各層のパラメータサイズ、埋め込み行列、層ごとの正規化パラメータなどが含まれています。`llama.cpp` では、メモリを節約するためにモデルの重みを 4bit または 8bit の整数に量子化します。

```cpp
struct llama_model {
    int n_vocab;             // ボキャブラリサイズ
    int n_ctx;               // コンテキストサイズ
    int n_embd;              // 埋め込みの次元数
    int n_layer;             // 層数
    int n_head;              // アテンションヘッド数
    std::vector<layer> layers; // Transformer 層
    ggml_tensor *embeddings; // 埋め込み行列
    ggml_tensor *norm;       // 最終層の正規化
    // 他の必要なパラメータ
};
```

読み込み時に、`llama.cpp` は `.bin` ファイルを解析してこの構造にデータをロードし、メモリ効率を確保するために量子化します。量子化された各層のパラメータ（マルチヘッドアテンションや前方フィードネットワークなど）は整数として表現されるため、計算コストとメモリ使用量が抑えられます。

### 2. 推論プロセス

`llama.cpp` における推論は、入力を埋め込み、アテンションメカニズム、フィードフォワード計算、活性化といった手順で処理し、最終的に出力予測を生成する流れです。以下に推論の主なステップを示します。

#### 埋め込み層
入力テキストはトークン化され、それぞれのトークンのインデックスが埋め込み行列で参照され、埋め込みベクトルが取得されます。

```cpp
ggml_tensor* embedded_tokens = ggml_get_tensor(model.embeddings, input_token_ids);
```

この生成された埋め込みベクトルが、次の Transformer 層で利用されます。

#### Transformer 層
LLaMA モデル内の各 Transformer 層はアテンション機構とフィードフォワードネットワークで構成されています。以下の2つのステップで推論が進みます。

##### 1. マルチヘッドアテンション
マルチヘッドアテンション層では、入力に対して各トークンのアテンション重みを計算します。`llama.cpp` では、重みのデータを異なる量子化レベルで保持することで効率化を図っています。

```cpp
// QKV 計算
auto query = ggml_linear(model.query, x);
auto key = ggml_linear(model.key, x);
auto value = ggml_linear(model.value, x);

// アテンション重みの計算
auto scores = ggml_softmax(query * ggml_transpose(key));
auto context = ggml_matmul(scores, value);
```

##### 2. フィードフォワードネットワーク（FFN）
FFN では、アテンションの出力に対して線形変換-活性化-線形変換を行い、非線形マッピングを実行します。

```cpp
auto hidden = ggml_relu(ggml_linear(model.ffn_1, context));
auto output = ggml_linear(model.ffn_2, hidden);
```

##### 残差接続と層の正規化
各層の出力は残差接続と正規化が行われ、安定性が確保されます。各層の結果は入力特徴量に加算されます。

```cpp
x = x + context + output;
```

#### 推論フローの概要
最終的に、`llama.cpp` は全層の結果を集約し、モデルの予測値を出力します。

### 3. 量子化による最適化

`llama.cpp` の大きな特徴として量子化が挙げられます。浮動小数点の重みを 4bit や 8bit の整数に変換することで、モデルのメモリ使用量を大幅に削減し、計算速度を向上させています。この量子化は、カスタムの `ggml` テンソルライブラリを使用して行われ、低精度計算をサポートするため、推論時に整数演算へ変換され、計算速度とリソース効率が向上します。

```cpp
// 例：重みの 4bit 量子化
auto quantized_weight = ggml_quantize_4bit(original_weight);
```

### 4. 推論の実行

ユーザーは `llama.cpp` を使用する際、モデルファイルと入力テキストを指定して推論関数を呼び出すだけで結果を得られます。

```cpp
std::string input_text = "What is the capital of France?";
auto result = llama_infer(model, input_text);
std::cout << result << std::endl;
```

推論関数は `forward` 関数を呼び出して入力を処理し、予測結果を出力します。このフローは効率化されており、リソースの限られた環境での実行に適しています。

### まとめ

`llama.cpp` の中心原理には、モデル構造の軽量化表現、量子化による最適化、および簡潔で効率的な推論フローが含まれています。C++ と `ggml` テンソルライブラリを利用することで、リソースの少ないデバイスでも複雑な Transformer の推論が実現されており、簡潔かつ効率的に LLaMA モデルが実行できる設計となっています。
桁dpの初歩【競技プログラミング】

# はじめに
- 過去、[桁dpを取り上げたこと](https://qiita.com/kei_tnk/items/7627c77d19d980774091)があったけど、頭に全く残ってなかったし、今読み返しても、頭にスッと入ってこない。
- やっぱり、初歩を飛ばしてやるからこんなことになるんだよね。
- ということで、一番基本的な問題を解いてみることとした。
- というか、基本的な問題に出会って、過去にやったことを全く覚えてなかったことに驚愕して、慌てて初歩に手を付けた、と言うのが正確な表現だね。

# 桁dpの一番基本的と思われる問題
- [コレ](https://atcoder.jp/contests/dp/tasks/dp_s)です。
    - 数字、KとDが与えられて、1〜K(＜$10^{10000}$)の数字のうち、各桁数字の合計がDの倍数となる数字はいくつあるか？(mod 1000000007)
- 問題だけ見ると簡単よね。計算量を考えなければ、簡単に実現できそう。

# 解き方
- うろ覚えだけど、[以前解いたとき](https://qiita.com/kei_tnk/items/7627c77d19d980774091)は、各桁の数字として0〜9の全ての数字が使えるわけではなく、例えば、[0,3,5,7,8]しか使えない制約ががあったなぁ。
- 今回は、その制約がないことが大きな違い。制約がないから、簡単なはず！
- そして、前回は、「その整数自身がBの倍数か」で判断したけど、今回は「各桁の数値の合計がBの倍数か」だから、かなり違うね。
- で、前回は、桁dpとして、dp[i][k]とは、(下位)i桁以下の数字で(mod D)がkになる「場合の数」としていたね。
- だから最終的な答えとしては、dp[N][0]を求めれば良いよね。よし、頑張って思い出しながら、コードを書いてみよう
- あれ？以前解いたときの元の数値は、N桁の数字（例：5桁の場合、10000〜99999）ってだけの指定だったけど、今回の問題は、K=54321（この場合、1〜54321の範囲）のように、各桁毎で9まで使えるとは限らない！
    - 例えば、K=54321のときにdpを行う場合、頭の3桁が543の場合、4桁目は2以下にする必要があるけど、頭の3桁が542以下であれば、4桁目は0〜9の好きな数字が使える。
- よって、今回の桁dpでは、dp[i][d][0/1]として3次元dpにします
    - 元のインデックスがkだった2次元目部分は今回の条件で使われる大文字のＫと紛らわしいので倍数Dから連想されるdに変更。
    - 最後の箱(3次元目部分)は、K=54321の例であれば、上位3桁が543の時は0、542以下の時は1とするフラグです。初歩なのに、dpが3次元になったよ！
- あと、Kを分解して頭からの各桁に格納される数値をK[i]としておくのが良いみたい。ん？dp[i][d][0/1]のiって、前回解いたときは下の桁からの数だったけど、今回は上からの桁数にした方が良いのか...。まぁ、前回（その数自身）と今回（その数の各桁の合計）では、Bの倍数かどうかの判定対象が違うから、今回はiを桁の上位から数えるのは当然かな。
- なんだか、全然別物になっちゃってるね。とりあえず、コードを書いてみるよ。
- 改めて説明するけど、dp[i][d][0/1]については、N桁の数値の上位「i-1」までの数値を使ったときの余剰がdとなる組み合わせの数だよ。[0/1]については、さっきの説明の通り。
- だから、dpは0で初期化した後、初期値として、dp[0][0][0] = 1として、それを育てていくイメージだね。
```swift
extension Array { // 3次元配列初期化を短縮表記するためののエクステンション
    init(_ cnt: Int, _ v: Element) {
        self = [Element](repeating: v, count: cnt)
    }
    init<T>(_ cnt2:Int, _ cnt1:Int, _ v:T) where Element == [T] {
        self = [[T]](cnt2,[T](cnt1,v))
    }
    init<T>(_ cnt2:Int, _ cnt1:Int , _ cnt0:Int, _ v:T) where Element == [[T]] {
        self = [[[T]]](cnt2,[[T]](cnt1,[T](cnt0,v)))
    }
}

let K = Array(readLine()!).map{Int(String($0))!}
let D = Int(readLine()!)!
let N = K.count

let mod = 1000000007
// print(K)

var dp = [[[Int]]](N+1,D,2,0) // 短縮表記
dp[0][0][0] = 1 

for i in 0..<N {
    let k = K[i]
    for d in 0..<D{
        for t in 0..<10 {
            if t == k {
                dp[i+1][(d+t)%D][0] += dp[i][d][0] % mod
            }

            if t < k {
                dp[i+1][(d+t)%D][1] += dp[i][d][0] % mod
            } 
            
            dp[i+1][(d+t)%D][1] += dp[i][d][1] % mod
            
        }
    }
}

print((dp[N][0][0] + dp[N][0][1] - 1) % mod)
```
- 出来た!提出したら、300ms程度でACでした。
- まぁ、この問題のキモは、dpの3次元目の[0/1]の設定を閃くかどうかだけだから、その部分をコッソリ見ておけば、コードは書けるよね。
- ただし、提出前検証まで、気づかない点がありました。
- 最後の行の「dp[N][0][0] + dp[N][0][1] - 1」を見てください。1を引いてるよね？
- これは、K=54321の例であれば、各桁合計がBの倍数となるパターンの中に「00000」が入っちゃうから、除く必要があるため。

# おわりに
- 桁dpの初心者版を解いたけど、三次元dp[i][d][0/1]の最後の[0/1]は、普通は閃かないって。これが閃かなくても、他に無理矢理解く方法はあるのかもだけど、天才じゃない人には厳しいね。
- 初心者向けだけど、暗記問題だね、これ。
- まぁ、とりあえず、こっちの桁dpの方は覚えられたと思うよ。[前回の桁dp](https://qiita.com/kei_tnk/items/7627c77d19d980774091)は、また忘れそうだけどね。
構造体の作成 (paizaランク C 相当)

https://paiza.jp/works/mondai/class_primer/class_primer__make/

解答は見てくれを表示するだけで、全然構造体を作成してませんでした。

```python3
N=int(input())
ulist=[]
for i in range(N):
    n,o,b,s=input().split()
    #入力を元に辞書を作成
    u = {
        "nickname":n,
        "old":o,
        "birth":b,
        "state":s,
    }
    #辞書をリストに追加
    ulist.append(u)

for u in ulist:
    print("User{")
    for key, value in u.items():
        #キーと値を出力
        print(f"{key} : {value}")
    print("}")
```

構造体ならばulist[0].nicknameのような感じで使いたいので、調べたところ、namedtapleやdataclassを使用すればいいとのこと

```python3
from dataclasses import dataclass

# dataclassの定義
@dataclass
class User:
    nickname:str
    old:str
    birth:str
    state:str
    
N = int(input())
ulist = []

# 入力を取得し、インスタンスをリストに追加
for i in range(N):
    n, o, b, s = input().split()
    u = User(nickname=n, old=o, birth=b, state=s)
    ulist.append(u)
# リストの内容を出力
for u in ulist:
    print("User{")
    for key, value in u.__dict__.items():
        print(f"{key} : {value}")
    print("}")
```

結果表示の関係で辞書型に変換して出力してますが、
print(ulist[0].nickname)
といった感じに取り扱えます。