OmniAICreator/Qiita-1.07M huggingface dataset:
ROS2の共有ライブラリを使用したプログラムの作成

【[ROS2関係トップページへ](https://qiita.com/NeK/items/7ac0f4ec10d51dbca084)】

【前:[ROS2における共有ライブラリ]】
【次:[ROS2におけるコンポーネント]】

[ROS2における共有ライブラリ]:https://qiita.com/NeK/items/48c55bd473091d41cc75
[ROS2におけるコンポーネント]:https://qiita.com/NeK/items/775c0ddb4e10ed091068

[ROS2における共有ライブラリ]で作成した共有ライブラリを使用する方法について．
他のROS2プログラムとの違いは，CMakeLists.txtでtarget_include_directoriesを使うことのみ．

# 準備

```bash:terminal
$ cd ~/ros2_studies_ws/
$ ros2 pkg create minimal_comp_user --build-type ament_cmake --dependencies rclcpp minimal_comp
```

[ROS2における共有ライブラリ]で作成したパッケージ:minimal_compを使用するため，dependenciesに追加．

# 共有ライブラリを使用したプログラム

- src/minimal_comp_user_main.cpp

## プログラム

```c++:minimal_comp_user_main.cpp
#include <rclcpp/rclcpp.hpp>
#include "minimal_comp/minimal_comp_node2.hpp"

int main(int argc, char * argv[]){
  rclcpp::init(argc,argv);
  rclcpp::spin(std::make_shared<minimal_comp::MinimalCompNode2>());
  rclcpp::shutdown();
  return 0;
}
```

### 概要
共有ライブラリのMinimalCompNode2を呼び出している．
パッケージ名をnamespaceにしていたので呼び出しは6行目のようにminimal_comp::MinimalCompNode2となる．

# package.xmlとCMakeLists.txt
関係する部分のみ抜粋．

## package.xml

```xml:package.xml
<package format="3">
  <depend>rclcpp</depend>
  <depend>minimal_comp</depend>
```

### 説明
rclcppパッケージとともに共有ライブラリのパッケージ(minimal_comp)を記述．

## CMakeLists.txt

```CMakeLists.txt
find_package(rclcpp REQUIRED)
find_package(minimal_comp REQUIRED)

add_executable(minimal_comp_user
  src/minimal_comp_user_main.cpp
)
ament_target_dependencies(minimal_comp_user
  rclcpp
  minimal_comp
)

target_include_directories(minimal_comp_user
  PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
)

install(TARGETS
  minimal_comp_user
  DESTINATION lib/${PROJECT_NAME}
)
```

### 概要
他のROS2と基本的に同じで，パッケージを見つけるfind_packageやターゲットと必要となるソースファイルの指定，インストール先などを記述．
共有ライブラリを使用する上で必要となるものがtarget_include_directoriesとなる．

### 説明
共有ライブラリなど自分のパッケージディレクトリにない外部のヘッダファイルにアクセスするために12～16行目が必要となる．
12行目に今回作成するターゲット名を書く．13～16行目は他でも同じ書き方になるのでコピペ．

# ビルド・実行

## ビルド
```bash:terminal
$ cd ~/ros2_studies_ws/
$ colcon build --symlink-install --packages-up-to minimal_comp_user
$ . install/setup.bash
```

共有ライブラリがビルドしてあるものとする．まだしていなければ，--packages-up-toに共有ライブラリのパッケージも一緒にしていしてやる．

## 実行

```bash:terminal
$ cd ~/ros2_studies_ws/
$ . install/setup.bash
$ ros2 run minimal_comp_user minimal_comp_user
```

# 共有ライブラリと作成プログラムが同一パッケージの場合
ここでは共有ライブラリとROS2プログラムが異なるパッケージの場合を作成した．
この時，共有ライブラリのパッケージ(minimal_comp)をfind_packageで指定し，ament_target_dependenciesでminimal_compを指定した．


共有ライブラリとROS2プログラムが同一パッケージの場合は，find_packageを書く必要がなく(自身のパッケージ名だから書けない)，~~ament_target_dependenciesではライブラリ名(add_libraryの名前)を指定すればよい．~~ 共有ライブラリ分だけtarget_link_librariesに書く(その他のrclcppなどはament_target_dependenciesに書く)．例えば以下の通り．

```CMakeList.txt
target_link_libraries(hoge
  fuge # 同一パッケージの共有ライブラリ名(add_libraryの名前)
)
ament_target_dependencies(hoge
  rclcpp
)
```


[公式githubの共有ライブラリにかかわるexmaple](https://github.com/ros2/examples/tree/master/rclcpp/minimal_composition)のCMakeLists.txtが参考になる．
LDAP設定されたJenkinsでユーザ全員がログインできなくなった場合の対処法

# はじめに
Jenkinsにて、LDAP認証設定中に、LDAPの設定を誤るとユーザがログインできなくなることがあります。本記事では、そのような事態に陥った際の対処法について具体的な手順を説明します。

# 事象
LDAPを用いた認証設定が行われたJenkinsで、全ユーザがログインできなくなった。

# 対策
以下の手順を実施することで、LDAP認証を再設定し、ユーザがログインできるようにします。

## 手順
**(1) config.xmlファイルのバックアップを取る**
   - `E:\Jenkins\.jenkins\config.xml` のバックアップを取ります。バックアップは、設定の誤りやデータの損失を防ぐために重要です。

**(2) config.xmlファイルをデスクトップにコピー**
   - `E:\Jenkins\.jenkins\config.xml` をデスクトップにコピーします。

**(3) config.xmlファイルを編集**
   - デスクトップにコピーしたファイルを開きます。
   - `hudson/authorizationStrategy/roleMap type="globalRoles"/role name="Admin"/assignedSIDs/sid` タグ内のIDをLDAP認証でログイン可能な管理者のIDに変更します。

```xml:config.xml
<roleMap type="globalRoles">
  <role name="Admin">
    <assignedSIDs>
      <sid>admin_user_id</sid>
    </assignedSIDs>
  </role>
</roleMap>
```

**(4) 編集したconfig.xmlファイルを上書き**
デスクトップにある編集済みのconfig.xmlファイルを E:\Jenkins\.jenkins にコピーして上書きします。

**(5) Jenkinsのサービスを再起動**
Jenkinsのサービスを再起動します。サービスの再起動は、設定変更を反映させるために必要です。

# まとめ
LDAP設定されたJenkinsにおいて、全ユーザがログインできなくなった場合の対処法について説明しました。主な原因はLDAP認証における設定ミスやLDAPサーバーとの接続問題であり、config.xmlファイルを適切に編集することで解決可能です。定期的なバックアップと設定ファイルの確認を行うことで、障害発生時の迅速な対応が可能となります。

困ったときは、この記事の手順を参考に対応してみてください。設定変更が反映され、ユーザが再びログインできるようになることを願っています。
TinyGo Keeb の活動 2024

2024年08月24日に行われた屋形船での IoTLT vol.114 で飛び入り LT をさせていただきました！

https://x.com/n0bisuke/status/1827284321629311459

[TinyGo](https://tinygo.org/) という Go 言語のサブセットであり組み込みと Wasm 用途に使用されています。

IoTLT で LT させてもらった TinyGo Keeb の会は、@sago35 さんが設計したキーボードを題材に、前半ははんだ付け、後半はそのキーボードとともに TinyGo で遊ぶというイベントです。

![](https://cdn-ak.f.st-hatena.com/images/fotolife/s/sago35/20241029/20241029083603.png)

こんなキーボードができるよ

https://x.com/sago35tk/status/1812817785573232674

2024年は、神戸、関東、仙台、福岡で開催しました。


はんだ付けが初めてのヒトや、Go/TinyGo に初めて触れるヒト、いろいろなヒトに参加いただいて、ワイワイしました！


神戸開催の様子

https://x.com/taku_ting/status/1819986841254461926


関東開催の様子
nanbuworks さんのはんだごて、ステーション型の AVTOKYO をお借りしています。

https://x.com/mikkegt/status/1827570363586507013


わいわい

https://x.com/ysaito8015/status/1827699931475558506


仙台開催の様子

https://x.com/micchiebear/status/1844920215051829758



工具や、パーツなどはスタッフが用意するので、みなさん、PCのみ持ってきていただいて、出来上がった自作キーボード持ってかえってもらえます。

はんだ付けが、初めてでも、失敗しても、熟練のヒトたちが、よってたかってリワークします。


福岡でのリワークの様子

https://x.com/ysaito8015/status/1850026223176696257


## グッズ

全国ツアーグッズも展開しています。

[uji さんデザインの long gopher T シャツ](https://suzuri.jp/uji_rb/16366029/t-shirt/s/white)


https://x.com/ysaito8015/status/1844909548689293610


参加するともらえるかもしれない senoue さん作ツアータオル

https://x.com/micchiebear/status/1845018762350563375


## ゲームもできちゃう

https://x.com/sago35tk/status/1841091471786852685


## アドカレ

[TinyGo Advent calandar 2024](https://qiita.com/advent-calendar/2024/tinygo) も爆誕しました

個人的には、conejo 氏にアドカレ記事を書いてもらったのがとても感動でした。むちゃぶりに応えてくれてとても嬉しい！

https://x.com/_CONEJO/status/1868781795753574746



## そして 2025 年...

2025年は、高松を始まりの地として、いろいろな街で開催予定です！


[TinyGo Keeb Tour](https://tinygo-keeb.connpass.com/) よろしくねー！

![TinyGo Keeb Banner.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23206/73b60f93-407b-2470-d33a-aa81c50a3e64.png)
自分用メモ#5

数値加工の奴


``` java
public class DecimalFormatter {

    public static String formatDecimal(String number, int integerPartLength) {
        // 入力のバリデーション
        if (number == null || number.isEmpty()) {
            throw new IllegalArgumentException("Number string cannot be null or empty");
        }
        if (integerPartLength < 1 || integerPartLength > 8) {
            throw new IllegalArgumentException("Integer part length must be between 1 and 8");
        }

        // 入力が8桁未満の場合、ゼロ埋め
        while (number.length() < 8) {
            number = "0" + number;
        }

        // 小数点を挿入
        String integerPart = number.substring(0, integerPartLength).replaceFirst("^0+", ""); // 整数部の先頭のゼロを除去
        if (integerPart.isEmpty()) {
            integerPart = "0";
        }
        String fractionalPart = number.substring(integerPartLength); // 小数部

        // 整数部と小数部を結合して返す
        return integerPart + "." + fractionalPart;
    }

    public static void main(String[] args) {
        // サンプル入力
        String number = "1";
        int integerPartLength = 5;

        // 結果を表示
        try {
            String result = formatDecimal(number, integerPartLength);
            System.out.println("Formatted number: " + result);
        } catch (IllegalArgumentException e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}
```
Cursor(VSCode) で tfenv を使うと楽ちんですよ for Windows

# はじめに
ITエンジニアが業務に集中できないくらいに世間は賑わっています。
自分もその影響を多分に受けている [@\_\_\_nix___](https://twitter.com/___nix___) です。

# 背景
Terraform は皆さんお使いの方お多いかと思います。
しかしながら、terraform のバージョンをまだ手で切り替えながら作業している方も見受けられます。
tfenv を使って環境依存が発生しないよう環境を整えておきましょう。

:::note info
今更感の方はここでそっとブラウザを閉じて頂いても大丈夫です。
:::


# 概要
Terraform ではバージョンを切り替える為に [tfenv](https://github.com/tfutils/tfenv) というツールがあるのは皆さんもご存知かと思います。
この Terraform のバージョンを一度決めてしまえば気にせず使え、バージョンの異なる環境やワークスペースであっても意識する必要が無くなります。

今回、このツールを Cursor に導入し、Terraform 環境を最適化します。

# 何が嬉しいのか
1. tfenv の利用がルール化されていれば、以下のような記述は不要です。（書いても良いけど管理箇所が増える）
    ```
    terraform {
      required_version = "1.x.x"
    ```
    　
2. tfenv コマンドは覚えなくて良いし、意識する必要が無い。
    ```
    tfenv install ...
    tfenv use ...
    tfenv list
    ```
    　
3. ワークスペースで terraform バージョンを意識しなくて良い。
    「このワークスペースでは x.x.x で動いてるから tfenv use x.x.x を実行しないと」が不要

# 導入

## ダウンロード

まずは [tfenv](https://github.com/tfutils/tfenv) から zip でも git clone でも良いので、 `C:\Users\{user}\.tfenv` 以下に展開しましょう。

`C:\Users\{user}\.tfenv` 配下が以下のようになるように配置してください。
```
.github/
bin/
lib/
...
README.md
```

## 環境変数の設定

1. Windowsの「スタートメニュー」を右クリックし、「システム」を選択します。
2. 左側のメニューから「システムの詳細設定」を選び、「環境変数」をクリックします。
3. 「ユーザー環境変数」セクションで Path を選択し、「編集」をクリックします。
4. 「新規」をクリックし、C:\Users\{user}\.tfenv\bin を追加します。

## 確認

念の為 Cursor(VSCode) を再起動してターミナルで確認してみます。

```
$ tfenv --version
tfenv 3.0.0
```

# 実践

1. Terraform のコードを準備します。
    ```backend.tf
    terraform {
      backend "local" {}
    }
    
    provider "aws" {
      region = "ap-northeast-1"
    }
    ```
    　
2. バージョンを決めます。
    ここは安全に 1.10.3 にします。（ここは心に決めるだけでOK）
    ```
    $ tfenv list-remote | head
    1.11.0-alpha20241218
    1.11.0-alpha20241211
    1.11.0-alpha20241106
    1.10.3
    1.10.2
    1.10.1
    1.10.0
    1.10.0-rc3
    1.10.0-rc2
    1.10.0-rc1
    ```
    　
3. バージョンを固定します。
    決めたバージョンを `.terraform-version` に記載します。
    ```.terraform-version
    1.10.3
    ```
    　
4. terraform init を実行します。
    これでこの環境は勝手に terraform 1.10.3 で動くことになります。
    別のワークスペースに移動して terraform コマンドを実行する時も `.terraform-version` のファイルを読み込み、自動でそのバージョンを取得して利用してくれます。

5. バージョンを上げた場合は？
    `.terraform-version` に変更があった場合は terraform init を実行すれば指定したバージョンに変更されます。（`-upgrade` オプションが必要なケースもあります）

# 終わりに
意外と色々な企業さんで仕事をしていると、この辺りの環境設定はマチマチで tfenv を利用していないケースも少なくありません。
少しでもルール化することで環境差異を無くし、楽が出来る環境を整えておくことをお勧めします。

HCP Terraform(Terraform Cloud) を併用しているケースだと、terraform バージョンを指定するので `.terraform-version` に記載したバージョンと合わせておきましょう。

# 一言
年の瀬に、基本的な環境設定の内容でしたが、少しでも参考になれば幸いです。

この記事良かったと少しでも思って頂けたら是非 [@\_\_\_nix___](https://twitter.com/___nix___) をフォローしてあげてください。或いは記事に対してリアクションをお願い致します。
dbt incrementalでキーにnullは利用できない

[ちゅらデータアドベントカレンダー](https://qiita.com/advent-calendar/2024/churadata) 17日目の記事です。（投稿12/27 大遅刻です。ごめんなさい。）

最近寒くなってきました。
きたっぴ@ちゅらデータです。気が付くともう12月。今年はPJにてdbtを利用してETL処理をガリガリ書く事が多かった1年でした。

この1年で何度もdbtの挙動に悩んだことがありましたが1つかなり長時間ハマったことがありましたので
ここで供養の意味も込めて記事にしたいと思います。


# 対象読者
- dbt について触ったことがある
- DB (primary key)について基礎知識がある

# 複合キーが一致していても更新されずに新規で追加される場合がある

dbtにて作成したincrementalのモデルに対してデータ挿入を行っていたところ、複合キーが一致していてもデータが更新されず、新規レコードとして追加される現象が発生しました。

:::note info
dbt incremental modelの挙動について
dbt incremental modelとは、毎回モデル起動時にデータを洗い替えを行うのではなく新しいデータや変更されたデータのみを追加/更新するモデル。モデル起動の時間を短縮できたり過去データを保持することができるのがメリット。
:::

# 環境

dbt core 1.7.6
dbt - snowflake 1.7.1
DWHはsnowflake利用

# 対象モデル詳細

``` test.sql
{{
  config(
      materialized = 'incremental',
      unique_key = [
            'id' ,
            'name'
        ]
    )
　
}}

select
    id,
    name,
    quantity
from base
```

# 初回dbt run時

初回実行時ソースとなるテーブルには以下のデータが格納されているものとします。

baseテーブル
| id | name | quantity |
| ---- | ---- | ---- |
| 1 | taro | 100 |
| 2 | null | 200 |

上記、testモデルを初回実行した場合には、以下のテーブルが作成されます。
ソースとなるbaseテーブルと同一のものが出来上がります。
| id | name | quantity |
| ---- | ---- | ---- |
| 1 | taro | 100 |
| 2 | null | 200 |

# 二回目dbt run時

初回実行時より、id 1,2のquantityを変更、3をbaseテーブルに追加したうえでtestモデルを実行します。

baseテーブル
| id | name | quantity |
| ---- | ---- | ---- |
| 1 | taro | 300 |
| 2 | null | 400 |
| 3 | hanako | 500 |

私の予想では、id 1,2が更新 3が追加されbaseテーブルと同一のものが出来上がると思っていましたが
実際は以下の状態となりました。

| id | name | quantity |
| ---- | ---- | ---- |
| 1 | taro | 300 |
| 2 | null | 200 |
| 2 | null | 400 |
| 3 | hanako | 500 |

# 調査

勿論、主キー制約にて主キーに指定されたフィールドがNULL値を取ることができないことは承知しておりますが、dbt にてテーブルを作成する場合
- モデル内configにてunique_keyを指定していてもテーブル自体に主キー制約が付与されるわけではない
- モデル内configにて指定されたunique_keyはデータの更新or新規追加の判断に利用される

ため、主キーの一部がnullであっても問題なく動作すると予想して吐いたのですが作成されたモデルを確認するとどうも関係がありそうなため調査を行いました。

結果、upsert/merge判断の為のキー同一チェックにはnull値が入力されている場合の処理が組み込まれていないことが分かりました。

複合キーの一部にnullが入力される場合は新規に全複合キーをタネとしたサロゲートキーを利用することで行いたかった動作は実現できそうですが、自身の予想が外れたためかなり調査に手間どりましたのでここに調査結果を残しておきたいと思います。

# 追記情報

:::note warn
2024/12/27現在
本問題を解決するためのPRがマージされていそうです。
今回は時間が無く、テストが行えませんでしたが時間に余裕出来たタイミングで試してみたいですね！
:::

https://github.com/dbt-labs/dbt-adapters/pull/383
Gitで削除したブランチがVisual Studioに表示される問題の解決法

# はじめに
Gitを利用している開発者の中には、リモート上で削除したブランチがVisual Studio上に残ってしまうという現象を経験したことがある方もいるでしょう。この問題は、特に複数のブランチを扱う大規模プロジェクトでは見逃しがちな場合があり、影響を受けることが多いです。今回は、この問題の事象、原因、および解決策を詳しく説明します。

# 事象
Git上で削除したブランチがVisual Studioに表示され続ける。

# 原因
Visual Studio上の設定により、フェッチ中にリモートブランチが自動的に取り除かれないためです。

# 対策
Visual Studioの設定を変更し、「フェッチ中にリモートブランチを取り除く」オプションを有効にすることで、この問題を解決できます。

# 手順
(1) Visual Studioを起動し、メニューから「項目 > Git > 設定」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3963503/635fc27a-f334-5bfe-3eff-778e1588b57b.png)

(2)「リソース管理 > Gitグローバル設定」に移動し、「フェッチ中にリモートブランチを取り除く」プルダウンリストを「True」に変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3963503/7339014b-cc2d-c057-279d-d0185d45b89c.png)

# まとめ
Git上で削除したブランチがVisual Studioに表示される問題を解決するためには、Visual Studioの「フェッチ中にリモートブランチを取り除く」設定を有効にすることが重要です。この設定を行うことで、リモートブランチが正しく管理され、開発作業の効率が向上します。今回の手順を参考にし、適切に設定を変更してみてください。

# 参考記事:
https://learn.microsoft.com/ja-jp/visualstudio/version-control/git-settings?view=vs-2019
[SwiftUI]IgnoreSafeAreaとScaleToFillを使用すると、画像が右にズレる問題

# はじめに
以下のようなコードを書くと、画像が右にズレる現象が起きたので、その解決策を調べます。

```swift
content
    .background(
        image
            .resizable()
            .scaledToFill()
            .ignoresSafeArea(.container, edges: [.top])
    )
```

# 実装
```diff_swift
content
    .background(
        image
            .resizable()
            .scaledToFill()
+            .frame(minWidth: 0, maxWidth: .infinity)
            .ignoresSafeArea(.container, edges: [.top])
    )
```

# おわりに
frameを明示的に指定してあげることで、中心点がずれないようになりました。

# 参考
https://ix76y.medium.com/space-travel-app-part-1-creating-a-fullscreen-background-image-in-swiftui-beginner-tutorial-ca6f950b3b8
Could not install workload 'ios'. Response status code does not indicate success: 401 (Unauthorized). 

備忘録

## TL;DR
- 認証が必要な NuGet Private feed を無効化してペアリングする

## 事象
- Visual Studio から Mac にペアリングすると、タイトルのエラーが出てペアリングできない

## 詳細
- Visual Studio から Mac にペアリングを行った際に、ワークロードのインストールが行われる
- 一部のワークロードのインストールには内部的にNuGetを利用しているらしく、
認証が必要な Nuget Private feed が設定されている場合にインストール処理がブロックされてしまう場合がある
自分は、PrismLibraryの有料版を利用していてひっかかった
- 認証が必要な NuGet Private feed を設定している場合に、一度設定から外するとペアリングが可能となる
- ペアリングが完了した後に、再度有効化すれば問題なく動作する
beマッチャー

# true,falseまたはnilならばパスする　同一のインスタンスであるか？

true,falseまたはnilを与えられると、実際の値がtrue,falseまたはnil(それぞれ）であればパスする。引数なしは、呼び出し元がif条件（beかnot to be）を満たす必要があることを意味する。
>Given true, false, or nil, will pass if actual value is true, false or nil (respectively). Given no args means the caller should satisfy an if condition (to be or not to be).

述語はルビーの"?"で終わるメソッドそしてtrueまたはfalseを返すものです。`be_`に続く任意の述語("?"なし)が与えられると、RSpecはそれをマッチして対象のオブジェクトに対するクエリに変換するだろう
>Predicates are any Ruby method that ends in a "?" and returns true or false. Given be_ followed by arbitrary_predicate (without the "?"), RSpec will match convert that into a query against the target object.

arbitraryhpredicate機能は"be_an"、"be_a"または"be"の接頭辞となるいくつかの述語を扱い、あなたは最善のスイートの述語の先頭辞を選ぶことができます。
>The arbitraryhpredicate feature will handle any predicate prefixed with "be_an" (e.g. bean_instance_of), "be_a" (e.g. bea_kind_of) or "be" (e.g. be_empty), letting you choose the prefix that best suits the predicate.

Examples:
```rb
expect(actual).to     be_truthy
expect(actual).to     be_falsey
expect(actual).to     be_nil
expect(actual).to     be_[arbitrary_predicate](*args)
expect(actual).not_to be_nil
expect(actual).not_to be_[arbitrary_predicate](*args)
[]
```

https://rspec.info/documentation/3.6/rspec-expectations/RSpec/Matchers.html#be-instance_method:~:text=known%20as%3A%20a_value-,Given%20true%2C%20false%2C%20or%20nil%2C%20will%20pass%20if%20actual%20value%20is,%5B%5D,-%2D%20(Object)

オブジェクトがtrueならばパスする
```rb
 expect(obj).to be         # passes if obj is truthy (not nil or false)
```
https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/be/#:~:text=expect(obj).to%20be%20%20%20%20%20%20%20%20%20%23%20passes%20if%20obj%20is%20truthy%20(not%20nil%20or%20false)


# 同じ値だけだと失敗する
`subject!`と名前を使ったロードはexampleの前に定義されたブロックと名付ける。

オブジェクトの同一性を比べるequal?を使って比べました、しかし期待と実際は同じオブジェクトではありません。あなたがこのexampleでオブジェクトの同一性を気にしなければ、`expect(actual).to eq(expected)`を使え
```
eager loading using a named subject! calls the definition block before the example
     Failure/Error: expect(updated_list).to be([1, 2, 3, 99, 5])

       expected #<Array:13180> => [1, 2, 3, 99, 5]
            got #<Array:13200> => [1, 2, 3, 99, 5]

       Compared using equal?, which compares object identity,
       but expected and actual are not the same object. Use
       `expect(actual).to eq(expected)` if you don't care about
       object identity in this example.
```

実際と同じであればパスする
```rb
  expect(actual).to be(expected) # passes if actual.equal?(expected)
```

オブジェクト同一性　aとbは同じオブジェクトを指す
```rb
a.equal?(b) # object identity - a and b refer to the same object
```
https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/equality/#:~:text=a.equal%3F(b)%20%23%20object%20identity%20%2D%20a%20and%20b%20refer%20to%20the%20same%20object

>同じ値でもインスタンスが異なる場合はテストは失敗します。

https://qiita.com/jnchito/items/2e79a1abe7cd8214caa5#:~:text=%E5%90%8C%E3%81%98%E5%80%A4%E3%81%A7%E3%82%82%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%81%8C%E7%95%B0%E3%81%AA%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AF%E3%83%86%E3%82%B9%E3%83%88%E3%81%AF%E5%A4%B1%E6%95%97%E3%81%97%E3%81%BE%E3%81%99%E3%80%82

* 同一性とはそういうことだったのか。
Mongo DBのダンプ・リストア

# はじめに
[フレームワーク：Rails (6.1.7.2) ,  データベース：Mongo DB　(mongosh 2.2.10)]

業務システムを開発している中で、リリース後の本番環境のデータを手元（ローカル環境）で扱う必要があった時、本番DBのダンプファイルを取得してローカルにリストアしました。ダンプファイル入手後の手順を以下に記します。

<br>

<img width=20% ><img width=60%　 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3690695/3b8c10e5-bc10-f0c8-68d2-55685bb665cd.png">

# 現在のDBのバックアップ
まず、コンテナ内で現在のDBをダンプ（バックアップ）し、それをコンテナ外へも反映させるためにコンテナ内からコンテナ外へファイルをコピーします。（コンテナ内だけの出来事だと、コンテナを落とした時に消えてしまうため。）

### コンテナ内の操作

コマンドラインにて、
①コンテナを起動
➁コマンドでdb操作（exitで退出可能）

```
docker compose up d    
docker compose exec mongo bash
```

③現在のDBのダンプ

```
mongodump <認証情報> --db <現在のデータベース名> --out <バックアップを保存するディレクトリ>
```
上記が現在のDBのダンプ（バックアップ）を行う基本的なコマンドです。
今回は、backups/dumpというディレクトリを作成し、その中に現db(sample)を入れます。
認証情報の○○部分は伏せていますが、認証情報が設定されている場合は環境に応じて記載してください。

```
mkdir backups
cd backups/
mkdir dump
cd ../　
mongodump --authenticationDatabase=○○ --username ○○ --password ○○ --db sample --out ./backups/dump/
```
ダンプできていれば、/backups/dump/sampleに入っているはずです。

### コンテナ外の操作
```
docker compose cp <コンテナ内の移動元パス> <コンテナ外の移動先パス>
```
上記は基本的なコピーのコマンドです。

コンテナ内から外へファイルをコピーするために、コンテナ外から操作します。あらかじめ、バックアップファイルを移動する先のフォルダを作成しておきます。（今回はbackupsフォルダを「docker compose up -d」を行っているディレクトリの一つ上に作成）

④db操作から退出します。
⑤コンテナ内からコンテナ外へバックアップファイルをコピーします。
```
exit
docker compose cp mongo:/backups/dump/sample ../backups
```

移動先フォルダにバックアップファイルが入っていれば成功です。

# 本番環境ファイルの配置
⑥本番環境のダンプファイル（当記事では入手方法までは記載していません。）を配置します。
今回はバックアップファイルと同じ場所、/backups/dumpに配置します。これはコマンド等ではなく、普通のコピペでいけます。
⑦コンテナ内へコピー
先ほど配置した本番ダンプファイルを、以下のようにコマンドでコピーします。cp等で行わないとymlファイルが自動で書き換えられず、自力で書き換えないといけなくなります。
「../backups/dump/sample2」が移動前で、sample2が本番環境のダンプファイルです。
「mongo:/backups/dump」が移動先です。
```
docker compose cp ../backups/dump/sample2 mongo:/backups/dump
```

# リストア
dbの参照先を、もってきた本番環境のDBにします。
次のコマンドが基本的なリストアコマンドです。--dropをつけると、現在のdbが削除されます。削除しない場合、キー重複エラーが起きる可能性があります。<データベース名>はリストアするDB名です。存在しないdb名にすると、新規作成されます。<パス>はダンプしたファイルが配置されているパスです。
```
mongorestore --drop <認証> --db <データベース名> <パス>
```

⑧コマンドでdb操作
⑨リストア

```
docker compose exec mongo bash
mongorestore --drop --authenticationDatabase=○○ --username ○○ --password ○○ --db sample2 /backups/dump/sample2
```

# `config/mongoid.yml`の編集
参照するデータベースを変更し、再起動。

database: sample →　database: sample2 

# あとがき
元々のdbに戻す場合は、リストア以降の操作のみでdbを変更できます。
ChatGPTで効率化する卒論作成

## はじめに

卒業論文の作成には膨大な手間と時間がかかります。しかし、ChatGPTを活用することでその負担を大きく軽減することができました。先行研究の調査から解析コードの作成、論文執筆に至るまで、幅広い場面で助けられた経験をこの記事で共有します。
学生の方やChatGPTの実用的な活用法を知りたい方にとって、参考になるポイントがあれば幸いです！

## 1. 先行研究の調査

卒論の基盤を作る上で、先行研究の調査は避けて通れません。しかし、膨大な文献量に圧倒されることも少なくありません。そこで、ChatGPTのGPTs機能を活用しました。

#### **論文の要約生成**

Google Scholar等で見つけてきた論文のPDFを自作の「論文要約GPT」に読み込ませ、"落合陽一式論文要約フォーマット"に則り要約を生成させます。このフォーマットは、以下の6つの項目で構成されています。

1. **どんなもの？**: 論文の概要や背景、目的。
2. **先行研究と比べてどこがすごい？**: 研究の新規性や独自性。
3. **技術や手法のキモはどこ？**: 使用された技術や方法の要点。
4. **どうやって有効だと検証した？**: 実験や評価方法、結果の簡潔な説明。
5. **議論はある？**: 結果に基づく考察や課題、限界点。
6. **次に読むべき論文は？**: 関連文献や次のステップとして参照すべき論文。

「論文要約GPT」に要約を生成させた後、詳細を知りたい箇所については本文を参照するという形で調査を進めました。結果として、膨大な文献を効率的に扱うことができ、調査効率が格段に向上しました。

落合陽一式論文要約フォーマットの詳細については、こちらの記事をご参照ください。

https://qiita.com/lotushk95/items/e2f5489ed51a7dd6a1af

## 2. 研究方針の策定

研究テーマを具体化し、方向性を明確にするプロセスでもとても役に立ちました。ここからはo1モデルを利用しました。

- **テーマのブラッシュアップ**: o1モデルには現時点でPDFアップロード機能がないため、1.で生成した先行研究の要約文を投げ、先行研究との差別化ポイントを考えながらテーマを具体的かつ実現可能な形に洗練しました。

- **実験計画の立案**: 実験計画の具体的なプロセスや手法を整理しました。先行研究で使用された手法を分析し、それを改良する方法や、自分の研究テーマに適用する方法を検討しました。


## 3. 実験（解析コードの実装）

今回の私の研究ではPythonを用いたデータ解析が主軸です。以下のプロセスで実験を進めました。具体的な内容は載せられないので雰囲気だけ共有します。

#### **プロセスの概要**

1. **画像解析**: データセットの前処理や解析アルゴリズムの設計。
2. **解析を元に3Dモデルを出力**: 画像データを基にした3Dモデルの生成。
3. **3Dモデルの読み込み**: 作成したモデルを視覚的に検証し、さらなる分析に活用。

#### **具体的な実装の進め方**

ChatGPTデスクトップアプリのVSCode連携機能(beta)を利用してPythonコードを作成。画像処理ライブラリや3Dモデリングツールを統合。期待通りに動作しない場合はプロンプトを調整して改良。

![スクリーンショット 2024-12-26 18.48.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3934417/57550f62-4ffe-396a-3304-8e6831d07906.png)

#### **GitHub Copilotの併用**

ChatGPTに加えてGitHub Copilotも利用しました。特に`/explain`コマンドはAIが生成したコードを理解するのにとても役立ちました。学生なら無料で様々な機能が使えるのでおすすめです。

https://zenn.dev/iput_app/articles/77809fa7dd59be

## 4. 論文執筆

論文執筆についてもChatGPTの力を借りて効率化しました。以下のような手順で進めました。

1. **卒論フォーマットの用意**: 教授からLaTeX形式のテンプレートを受け取り、基本フォーマットを確認。
2. **LaTeX環境の構築**: VSCodeでLaTeX環境を整備。
3. **執筆**: これまでのプロセスで行ったやりとりの情報を踏まえた上でo1 + VSCode連携で卒論テキスト（texファイル）を生成。
4. **修正作業**: 卒論ドラフトを見せた段階で教授から受けた指摘をChatGPTに投げ、3.と同様に修正。

## おわりに

研究から卒論の執筆まで、体感ですが約9割の作業はChatGPTがやってくれている印象です。
この記事が少しでも参考になれば幸いです。利用する際は機密情報の取り扱いに十分ご注意ください！
Ubuntu Server LTS インストール後の作業（特に全てのディスク領域を割り当てたい）

# Ubuntu Server LTS のインストール
たまに Ubuntu Server をインストールする機会があり、いつもどうやったかな？と思い出せないので自分メモです。

ISOは、下記からダウンロードする

https://jp.ubuntu.com/download

インストール方法はここが参考になります

https://qiita.com/yui10/items/79ed7a97e909d2b83550

# シリアルポートを追加
Proxmox で使用する場合、コンソールが noVNC だとコピペができなくなにげに不便なので、シリアルポートを追加する。ただこのままだと Linux でサービスが上がってなく使えないのでサービスを起動する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44540/2235fef3-671d-0830-bb22-0f2ac2bed2eb.png)

```bash
$ sudo systemctl enable serial-getty@ttyS0.service
$ sudo systemctl start serial-getty@ttyS0.service
```

# swapを無効化
ディスク容量を圧迫しているswapを無効化しておく。個人的趣味です。

https://qiita.com/HirumaT/items/2a492f4c56ec557417f2

# 全てのディスク領域を割り当てたい
インストール画面でパーティションの割り当てがあります。ここで FREE となっている未使用領域をすべて割り振るのが正しいのですが、あまり気にせずそのまま先に進んでインストールを完了すると全てのディスク領域が使用されていないことがわかります。

全体で 32G あるのに・・・

```cmd
Filesystem                        1K-blocks    Used Available Use% Mounted on
tmpfs                                400928    1224    399704   1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv  15371208 5670768   8897832  39% /
tmpfs                               2004632       0   2004632   0% /dev/shm
tmpfs                                  5120       0      5120   0% /run/lock
/dev/sda2                           1992552   96644   1774668   6% /boot
tmpfs                                400924      12    400912   1% /run/user/1000
```

そこで、FREE を `/dev/mapper/ubuntu--vg-ubuntu--lv` に全て振り分ける

```cmd
sudo lvextend -l +100%FREE /dev/mapper/ubuntu--vg-ubuntu--lv
sudo resize2fs /dev/mapper/ubuntu--vg-ubuntu--lv
```

すると。。。。！。おお！

```cmd
Filesystem                        1K-blocks    Used Available Use% Mounted on
tmpfs                                400928    1224    399704   1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv  30849020 5670784  23746664  20% /
tmpfs                               2004632       0   2004632   0% /dev/shm
tmpfs                                  5120       0      5120   0% /run/lock
/dev/sda2                           1992552   96644   1774668   6% /boot
tmpfs                                400924      12    400912   1% /run/user/1000
```

# あとの作業
ロケールを修正したりと。しましょう。

https://linuc.spa-miz.com/2020/08/30/ubuntu-to-ja/#google_vignette
第4章 はりのたわみと不静定はり 基本事項3 p94「材料力学演習(20221021)」符号の決め方

 # オリジナル
[基本事項3(せん断力と曲げモーメント) p94 (pdf)](http://zairikiweb.starfree.jp/zai_enshuh/zai_enshuh_ver.3.3.pdf#page=99)＜[「材料力学演習(20221021)一括(ver.3.3)」を勉強したい。#sympy](https://qiita.com/mrrclb48z/items/c3274daf5f7a99cfe027#%E4%BD%9C%E6%A5%AD%E4%B8%AD%E7%A7%81%E3%81%AE%E8%A7%A3%E7%AD%94sympy)
り
# 基本事項３（せん断力と曲げモーメント）
#### 1 .(省略)
#### 2 .(おすすめです。) 私は、理解？覚えるのに苦労しました。
>この表現は第１章の基本例題1.29...
#### 3 .(おすすめです。) 私は、理解？覚えるのに苦労しました。
#### 本書では使わないが，次のような表現もある．
#### 2'.(おすすめです。) 　
#### 3'.(おすすめです。) 
#### 4 .(抜粋) ＞憶えておくと便利な関係式として，
(2025/03/10 移動してきました。)
```math
F=\dfrac{dM}{dx}
```
(2023/12/26追加)
[基本事項３ ４.関係式P94](https://qiita.com/mrrclb48z/items/09b7cc73f0a22bf651b8)より
```math
\begin{array}{ll}
\dfrac{dQ}{dx}=q\\
\dfrac{dM}{dx}=Q\\
\end{array}
```
(2023/12/22追加)
・左端を揃えたいです。
・左端のスペースを削除したいです。
```math
F = \left\{
\begin{array}{ll}
R_A & (0 \leq x \leq a)\\
R_A-q(x-a) & (a \leq x \leq l)
\end{array}
\right.
```
　　　　　　　Fを積分
　　　　　　　Mを微分
```math
M = \left\{
\begin{array}{ll}
R_Ax & (0 \leq x \leq a)\\
R_Ax-1/2q(x-a)^2 & (a \leq x \leq l)
\end{array}
\right.
```
# いつもの? sympyの実行環境と 参考のおすすめです。
[(テンプレート)](https://qiita.com/mrrclb48z/items/00dd08b0317069be9342) 

# いつもと違うおすすめです。
#### wikipedia

### 参考文献
~~＞一部に等分布荷重を受ける単純支持はり~~
~~＞JSME p89~~
　
~~＞単純支持ばり 7)~~
~~＞構造力学公式集 p136~~


- 村上敬宜. (2023). *材料力学* (新装版). 森北出版.　
5.3 せん断力図と曲げモーメント図 p78 **符号の決め方**
＞私は上記で理解???しました。ありがとうございました。
Windowsで仮想デスクトップを活用しよう

Windowsの仮想デスクトップ機能は使ってみますか？
同時にいろんなことをやる人にはぜひ活用してほしい機能です。

# 仮想デスクトップとは
仮想のデスクトップ環境を複数作り、自由に切り替えることのできる機能です。
作業内容ごとに分けることで、ウィンドウが開きまくってごちゃごちゃするのを防ぐことができます。

# 仮想デスクトップの作り方

Windowsのここにある白と黒の四角形のアイコンを押してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124670/88147a81-6e6b-9ff6-2ceb-7434375ea64b.png)

すると今開いているウィンドウが一覧になって表示されていると思います。

その下のところに並んでいるのが仮想デスクトップです。
ここで新しいデスクトップをクリックすると新しいデスクトップを追加することができます。
また、デスクトップごとに名前を付けることもできます。

仮想デスクトップを選択すると画面が切り替わり、別の仮想デスクトップ環境へと移動できます。

# ショートカット

## 仮想デスクトップの作成
``Win`` +``Ctrl``+``D`` 

## 仮想デスクトップの移動
``Win``+``Ctrl``+``←``または``→``
もしくはタッチパッド上で4本指で左右になぞる

## 仮想デスクトップ一覧画面の表示
``Win``+``Tab``
もしくはタッチパッド上で4本指で上になぞる

## 仮想デスクトップの削除
``Win``+``Ctrl``+``F4``
Enumeratorクラスにできるメソッド

# Enumeratorを介することでeach と同様に Enumerable の機能を利用できる
>例えば Array#map は Array#each の繰り返しを元にして定義されます。 Enumerator を介することにより String#each_byte のような異なる名前のイテレータについても each と同様に Enumerable の機能を利用できます。

# map,each,each_byteによってEnumeratorクラスになりイテレータをすることができる
### each
>each -> Enumerator
各要素に対してブロックを評価します。

>ブロックが与えられなかった場合は、自身と each から生成した Enumerator オブジェクトを返します。

例
```rb
irb(main):002* [1, 2, 3].each do |i|
irb(main):003*   puts i, i.class
irb(main):004> end
1
Integer
2
Integer
3
Integer
=> [1, 2, 3]
irb(main):005> [1, 2, 3].class
=> Array
irb(main):006> [1, 2, 3].each.class
=> Enumerator
```
https://docs.ruby-lang.org/ja/latest/class/Array.html#I_COLLECT:~:text=each%20%7B%7Citem%7C%20....%20%7D%20%2D%3E%20self,2%0A%23%20%20%203

### map
>map -> Enumerator
collect {|item| ... } -> [object]
map {|item| ... } -> [object]
各要素に対してブロックを評価した結果を全て含む配列を返します。

>ブロックを省略した場合は Enumerator を返します。

例
```rb
irb(main):007> p [1, 2, 3].map {|n| n * 3 }
[3, 6, 9]
=> [3, 6, 9]
irb(main):008> p [1, 2, 3].map.class
Enumerator
=> Enumerator
```

https://docs.ruby-lang.org/ja/latest/class/Array.html#I_COLLECT:~:text=map%20%2D%3E%20Enumerator,3%2C%206%2C%209%5D

### each_byte
```rb
irb(main):019* "str".each_byte do |byte|
irb(main):020*   p byte
irb(main):021> end
115
116
114
=> "str"

irb(main):023> "str".each_byte.class
=> Enumerator
```
https://docs.ruby-lang.org/ja/latest/method/String/i/each_byte.html

### 感想
EnumeratorはStirng,Arrayの親ではないのに使えるのだろうか？
調べることができなかった。
GitLabリポジトリのクローン時に発生する403エラーの解決方法

# はじめに
社内でGitLabを利用中のユーザーから、リポジトリのクローン作業が失敗する報告があがりました。
本記事では、その際に報告された事象、原因の特定プロセス、そして実施した解決方法について詳述します。

# 事象
特定のユーザーが、GitLabリポジトリを自身のPCにクローンしようとした際、以下のエラーが発生しました。

> Git failed with a fatal error: unable to access '[GitLab URL]': The requested URL returned error: 403


このエラーはVisual Studioを使用してクローン操作を実行した場合だけでなく、Git Bashでのコマンド操作でも再現しました。一方で、他のユーザーは同じリポジトリを問題なくクローンできており、リポジトリ自体やサーバー側の設定には問題がないことが示唆されました。

# 原因
調査の結果、以下の2つの主要な原因が考えられました。

### 1. Git Credential Managerの問題
Git Credential Managerが正常に動作しておらず、認証情報が正しく提供されていない可能性がありました。これにより、GitLabサーバーへのアクセスが拒否される状況が発生していました。

### 2. Proxy環境の問題
ユーザーのシステムに設定された`http_proxy`環境変数が、リポジトリへの接続経路を妨害していた可能性があります。この場合、プロキシ設定が誤っているために、GitLabサーバーへのアクセスが阻害されていました。

# 解決方法

### 1. Git Credential Managerの問題の対策
**Git Clientの再インストール**:
現在使用しているGit Clientを一度削除し、最新バージョンのGitを公式サイトから再インストールしました。
**再インストール後の動作確認**:
Gitを再インストール後、`git clone`操作を再試行し、認証情報が正しく提供されることを確認しました。

### 2. Proxy問題の対策
**no_proxyの設定**:
GitLabサーバーのホスト名をno_proxy環境変数に追加することで、プロキシを通さずに直接接続できるようにしました。
```bash
 export no_proxy="your.gitlab.server"
```

**設定反映後の動作確認**:
上記の設定変更を反映後、再度git cloneを実行し、クローンが成功することを確認しました。


# まとめ
本事例では、Git Credential Managerの不具合とProxy設定の影響が原因となり、リポジトリのクローン操作が失敗していました。これらの問題に対して、Git Clientの再インストールや環境変数の修正といった具体的な対応を実施することで、無事問題を解決することができました。

問題解決のプロセスでは、事象の正確な把握、原因の特定、そして適切な解決方法の実施が重要です。
このようなトラブルが再発した場合でも迅速に対応できるよう、本記事が参考になれば幸いです。
Asset StoreからUnityのAssetをインポートする

AssetをWebブラウザからインポートの仕方について紹介します。

# 環境
- Unity6 6000.0.32f1
- Windows11
- Google Chrome
# やり方
Asset StoreにUnityのアカウントでログインします。
ほしいAssetを検索します。
無料なものや2D素材など条件を絞って検索することができます。

ほしいAssetを見つけたら、Add to My Assetというボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124670/305b1089-1d84-584d-85ab-da2e5050e7a1.png)

利用規約に同意しますかみたいなのが表示されたら内容を確認してAcceptを押しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124670/c7a4798a-e5ec-73d3-9536-742f026e9746.png)

このようにバナーが出るので、Open in Unityを開きます。この時、インポートしたいプロジェクトを開いておいてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124670/7a5f0afa-efa5-6962-9652-9aa7a5ebd5f4.png)

するとこのようにPackage Managerが開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124670/9e02b1b8-21ca-6165-b958-6fb53724a42d.png)

``Download``を押してください。
ダウンロードできたら``Import x.x.x to Project``という表示に変わるので、それを押します。

するとこのようにどれをインポートするかの選択画面が出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124670/6070a597-272e-6a94-194b-15bf36045ddd.png)

必要なものにチェックを入れ、Importしてください。

これでAssetsフォルダ内にAssetがインポートされます。

以上！
Entity Framework CoreでSQL Serverに接続する【実践編①】

こんにちは。藤原です。

この記事では、.NET Webアプリケーション開発でDBフレームワークである EntityFrameWorkCore(以下、EFCoreと記載)について取り上げています。

今回はEFCoreを介して、実践編①ということでEFCoreをプロジェクトに導入。コンテキストクラスの作成までやってしまいましょう🗒

:::note warn
注意
本記事はDB接続のための前準備が完了している前提で記載しています。
準備がまだの方は↓の【準備編】をご参照ください。
https://qiita.com/pesysyon/items/54b51c70a31a41eef035
:::

# 今回の目標
・接続先テーブルの作成
・EFCore の導入
・DBコンテキストクラスの作成

# 接続先テーブルの作成

それではさっそくソースコードでテーブルのデータを取得！
...といきたいところですが、テーブルが無いですね。

まずはSSMS(SQL Server Management Studio)上からさくっと検証用のテーブルを
作成してしまいましょう！

SSMSで前回の記事で作成しておいたDBを開きます。
開けたらテーブルで「新規作成 > テーブル」を選択しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/9a923513-1661-9285-060f-0576b8137d42.png)

すると「列名」「データ型」「NULL許容」等のテーブルへ作成カラムの
設定UIが表示されるかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/afca4fdf-fb04-65ad-0052-b252060c3b93.png)

今回は MemberId(会員ID)、MemberName(会員名)、MemberAddress(会員住所)という3つのカラムを設定しました。
  ※主キーは MemberId(会員ID)で3つともNULL非許容に設定。

カラムが設定出来たら、Ctrl + S (保存ボタンでも可)を押して、テーブル名を設定します。
テーブル名は「Member」としました。

入力できたら「OK」を押して、テーブルの作成を完了しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/47461404-0e3a-0af6-79f1-fd35d5e765de.png)

無事にテーブルが作成できました！検証用としてはこれで十分です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/ba2f5e97-d89b-8800-f185-fcb3c53f01a7.png)

:::note warn
注意
実際の開発の際にはテーブル定義はシステム根幹を担うため、
きちんとした設計が重要です。
:::

# EFCore の導入

さあ、それでは本丸のEFCoreをPJに導入しましょう～！
VisualStudioでの作業に戻ります。
ソースが書きたくてウズウズしている方、もう少しです。。

Nugetパッケージ管理にて「参照」タブを選択し、「EntityFrameWorkCore」で検索すると「Microsoft.EntityFrameworkCore.SqlServer」がヒットします。
対象PJ確認のうえ、インストールを実行しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/9188a2a8-bc89-9e40-5dda-89dd2152d156.png)

:::note info
バージョンはご自身の作成されたソリューションのバージョンに合わせましょう。
互換性がないバージョンインストールを試みるとインストールに失敗します。
:::

インストールが完了したらソリューションエクスプローラー上から、対象のPJ -> 依存関係 -> パッケージを開いてPJにPkgが追加されていることを確認しましょう！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/77b5326b-b6d2-94fe-f4f8-9fee9be58551.png)

これでEFCoreの導入も完了です！

# DBコンテキストクラスの作成

それでは必要なクラス作成へと移りましょう。

### DBコンテキストの作成

DBコンテキストクラスとは、一言でいうと「データベースとのやり取りを管理する中心的な役割を果たすクラス」と言えます。
このクラスでデータベース接続を管理するので、EFCoreにおいて欠かせない重要な役割を担っているわけです。
その他にも「エンティティとDBのマッピング」「クエリの実行と追跡」「トランザクションの管理」など大切な幾つかの役割を担います。

より詳しく知りたい方は公式ページを読んでみることが良いと思います。
[Entity Framework Core Microsoft公式ページ](https://learn.microsoft.com/ja-jp/dotnet/api/microsoft.entityframeworkcore.dbcontext?view=efcore-9.0)

まずはフォルダを1つ追加してDBコンテキスト用のファイルを新規作成します。
名前は「DB名+Context」とするのがおススメです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/5c0c127f-8351-f6c8-7613-e61e25d9e775.png)

クラスが作成できたら、usingで「EntityFrameworkCore」と「SqlClient」を追加しましょう！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/5bc994b6-8321-2448-17fc-caecb1a203fd.png)

これでEFCoreの恩恵を受けられます:muscle_tone1:

# 最後に
今回はDBコンテキストクラスの作成まで完了しました。
ここからはDBコンテキストの必要処理、Modelクラスの作成、実際のデータ取得と進んでいきます。

ここまで読んでいただき、ありがとうございました:writing_hand_tone1:

以上、藤原でした。
[OutSystems] フロントエンドアクションにSplitが無いだと…

## はじめに
株式会社メディアテック所属の @mt-h2 です。
普段は OutSystems を利用したローコードでシステム開発を行っています。

今回は実装時に発覚した「マジか」事項になります。

:::note info
対象バージョンは OutSystems 11 となります。
:::

## 何があった
URLの末尾部分の文字列を抽出したいという事がありました。
※ `http://www.example.com/hoge?args1=123` の `hoge?args1=123` の部分

言語関係なしによくある処理、よく使う処理。フロントエンドで処理しようとしました。
文字列を Split してサクッと取得できると考え、公式の [ビルトイン関数](https://success.outsystems.com/ja-jp/documentation/11/reference/outsystems_language/logic/built_in_functions/text/) を探すも…

あれ？
**Split がない**

Text 以外のディレクトリを探すも存在せず。
どんな言語でも必ず存在すると言っても過言ではない Split 処理。
名前を Split にしていないだけなのか、自分が何か勘違いしているだけだろうと思い調査。

https://www.outsystems.com/forums/discussion/68875/how-to-split-the-column-sell-with-in-outsystems-reactive-app/

https://www.outsystems.com/forums/discussion/90492/string-split-in-reactive/

一言で説明すると、「フロントエンドでやるなら Substr や Replace を使う、または JavaScript で Split を使用するアクションを作成する。もしくは Forge を導入しよう」との事。
マジか。Split 無いのか。マジか…。
バックエンドには [String_Split](https://success.outsystems.com/ja-jp/documentation/11/reference/outsystems_apis/text_api/#String_Split) が用意されているのに！
特にこだわりは無いので [Substr](https://success.outsystems.com/ja-jp/documentation/11/reference/outsystems_language/logic/built_in_functions/text/#Substr) で取得するよう実装しました。

何故フロントには Split が無いのか気になったので調べてみましたがこれと言った情報は見つからず。理由がすごく気になるので、教えて OutSystems の中の人！

## あとがき
今までフロントエンドにデフォルトで用意されているアクションに対して特段不足や不満はありませんでしたが、Split が無い事については「マジか」と思いました。

諸々実装するのに手間がかかりそうなら贅沢は言わないので [AWK](https://ja.wikipedia.org/wiki/AWK) の実装お願いします！
業務では経験上あまり好まれないのは分かっていますが、[AWK](https://ja.wikipedia.org/wiki/AWK) は本当に便利なんですよ。これだけあれば他の文字列処理の大半使えなくても文句言わないくらいに。

https://ja.wikipedia.org/wiki/AWK

## さいごに
株式会社メディアテックでは絶賛 [開発メンバを募集中](https://www.mediatech.jp/recruit) です。
ローコード開発だけではなく、RPAやBIエンジニア諸々多数の募集をしておりますので、みなさまのご応募をお待ちしております。
遅延セグ木の王、遅延セグキングのチートシート

　アルメリアさんが、遅延セグ木（遅延セグメントツリー）について、とても便利な [チートシート](https://betrue12.hateblo.jp/entry/2020/09/23/005940) を公開してくださっています。

　しかし、慣れていない人にとっては、いつ何を使えばいいかがわかりづらいです。

　そこで、本記事では、持てる情報をなるべく持った遅延セグ木の王、遅延セグキングのチートシートを紹介したいと思います。

　これがその最強のチートシートだ！

```c++
const long long INF = 8e18;
struct S{
    long long sum;     // 区間の合計値
    long long min_val; // 区間の最小値
    long long max_val; // 区間の最大値
    int size;          // 区間のサイズ
};
using F = long long;
const F ID = INF;
S op(S a, S b){
    return S{
        a.sum + b.sum,
        std::min(a.min_val, b.min_val),
        std::max(a.max_val, b.max_val),
        a.size + b.size
    };
}
S e(){
    return S{
        0,
        INF,
        -INF,
        0,
    };
}
S mapping(F f, S x){
    if(f != ID){
        x.sum = f * x.size;
        x.min_val = f;
        x.max_val = f;
    }
    return x;
}
F composition(F f, F g){
    return (f == ID ? g : f);
}
F id(){
    return ID;
}
long long target;
bool f_sum(S prod){
    return prod.sum <= target;
}
bool f_increase(S prod){
    return prod.max_val <= target;
}
bool f_decrease(S prod){
    return prod.min_val >= target;
}
bool f_same(S prod){
    return prod.max_val <= target && prod.min_val >= target;
}
```

# 嬉しいところ

1. 何をコピペすればいいか迷わなくてよい
1. 複数の用途にひとつのデータ構造で対応できる
1. 同一値連続区間が求められる

　「1.」については特に説明はいらないと思うので、「2.」と「3.」について、使用例を添えて説明していきます。

# 複数の用途にひとつのデータ構造で対応できる

　二分探索は最大値を基準に行いたいけど、クエリの結果は区間和が欲しい、みたいな時でも、どちらの情報も持っているので対応できます。

https://atcoder.jp/contests/abc359/tasks/abc359_e

## 使用例

```c++
int main(){
    int n;
    cin >> n;
    vector<int> h(n);
    cin >> h;
    lazy_segtree<S,op,e,F,mapping,composition,id> seg(n);
    rep(i,n){
        seg.set(i,{0,INF,-INF,1});
    }
    vector<ll> ans;
    rep(i,n){
        target = h[i];
        int idx = seg.min_left<f_increase>(i+1);
        seg.apply(idx,i+1,target);
        ans.push_back(seg.all_prod().sum+1);
    }
    cout << ans << endl;
}
```

# 同一値連続区間が求められる

　「最小値が $x$ 以上であるような区間」と「最大値が $x$ 以下であるような区間」の共通部分を取ると、「値が $x$ であるような区間」となります。最小値と最大値をふたつ持つことによって、この探索が可能になります。

https://atcoder.jp/contests/abc380/tasks/abc380_e

## 使用例

```c++
int main(){
    int n,q;
    cin >> n >> q;
    lazy_segtree<S,op,e,F,mapping,composition,id> seg(n);
    rep(i,n){
        seg.set(i,{i+1,i+1,i+1,1});
    }
    vector<int> ans(n+1,1);
    while(q--){
        int t;
        cin >> t;
        if(t == 1){
            int x,c;
            cin >> x >> c;
            x--;
            target = seg.get(x).sum;
            int left = seg.min_left<f_same>(x);
            int right = seg.max_right<f_same>(x);
            ans[target] -= right-left;
            ans[c] += right-left;
            seg.apply(left,right,c);
        }
        if(t == 2){
            int c;
            cin >> c;
            cout << ans[c] << endl;
        }
    }
}
```

# 嬉しくないところ

## 区間加算ができない

　上のチートシートは区間変更限定です。区間加算を扱うためには、新たな遅延セグキングを生み出してください。

## 区間最小値（最大値）更新ができない

　これは遅延セグ木では不可能で、Beats という更にハイレベルなデータ構造が必要なようです。
RaspberryPi Zero Wでumap2を使ってUSBホストスキャンする方法

# 概要
 umap2はFacedancerが推奨されていますが、高額で手に入りにくいのでRaspberryPi Zero Wを使用してumap2を動かす方法を紹介します。
# 環境構築
古いバージョンのものが必要なのでOSのインストールから解説していきます。

## OSインストール  

[公式サイト](https://www.raspberrypi.com/software/)からRaspberry Pi ImagerをダウンロードしてPCにインストールする。
umap2はpython2で動くため、[OSアーカイブ](https://downloads.raspberrypi.com/raspios_full_armhf/images/raspios_full_armhf-2022-09-26/)から2022-09-22-raspios-bullseye-armhf-full.img.xzをダウンロードする。 
Raspberry Pi Imagerを使って書き込む(ユーザー名・パスワードを設定しておく)  
シリアル通信を行うためconfig.txtに下記の内容を追記する。

```text
[pm0]
dtoverlay=dwc2
enable_uart=1
```

## Wi-Fi設定

LANポートが無いのでWi-Fiの設定を行う。  
`sudo nano /etc/wpa_supplicant/wpa_supplicant.conf`の中にあるSSIDとパスワードを設定する。  

## python2利用設定
python2で開発されたものなので、python2の環境を設定する。
```bash
sudo apt-get -y install python-dev
 ```

python2をメイン環境に設定する。

```bash
sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
sudo update-alternatives --config python
```

下記画面で、python2を選択する。

```text
There are 2 choices for the alternative python (providing /usr/bin/python).
 
  Selection    Path                Priority   Status
------------------------------------------------------------
* 0            /usr/bin/python3.9   2         auto mode
  1            /usr/bin/python2.7   1         manual mode
  2            /usr/bin/python3.9   2         manual mode
Press <enter> to keep the current choice[*], or type selection number:1　
```

バージョンが変更されたか確認する。

```bash
python -V
Python 2.7.18
```

環境変数を設定する。

```bash
sudo nano ~/.bashrc
PATH=/home/pi/.local/bin:$PATH
source ~/.bashrc

```

## ツールインストール

pip2をインストールする。

```bash
wget https://bootstrap.pypa.io/pip/2.7/get-pip.py
sudo python2 get-pip.py
```

必要なモジュールをインストールする。

```bash
sudo apt install python-setuptools
sudo pip2 install requests
sudo pip2 install bitstring
```

追加モジュールインストールする。

```bash
git clone https://github.com/BinyaminSharet/Mtp.git
cd Mtp
sudo python2 setup.py install
```

## umap2インストール

umap2をダウンロードする。

```bash
git clone https://github.com/nccgroup/umap2.git
```

umap2をインストールする。

```bash
cd umap
sudo python2 setup.py install
```

テスト用のファイル・ディレクトリを作成する。

```bash
cd umap/data
tar xvf fat32.3M.stick.img.tar
mkdir mtp_fs
```

# 実行方法

## ログイン

teratarmのシリアルポートで接続。スピードを115200に変更する。

## umap2実行

`gadget`ディレクトリに移動し、ラズパイ用のシェルスクリプトを実行する。

```bash
cd umap/gadget
sudo sh start_gadgetfs_RaspiZeroW.sh
```  

その後`umap/data`に移動して実行する。

```bash
cd
cd umap/data
sudo umap2scan -P gadgetfs
```

:::note
出力結果を保存したい場合はteratarmのログ機能を利用してください。
:::
WordPressで記事ページに前の記事・次の記事を出力する方法

# はじめに
HP制作をしている駆け出しエンジニアです。

ブログの記事ページに見られる、「前の記事」「次の記事」に遷移するリンクを作成する方法をまとめました。

# リンクを表示するコード
下記のコードをHTMLファイルに記載することで、「前の記事」「次の記事」に遷移するaタグを実装できます。

```PHP:HTML
<?php previous_post_link(); ?>
<?php next_post_link(); ?>
```

実際のHTMLは下記のようになります。
```HTML:HTML
<a href="前の記事のリンク" rel="prev">前の記事のタイトル</a>
<a href="次の記事のリンク" rel="next">次の記事のタイトル</a>
```

# 表示したいテキストを指定する場合
下記のように、第2引数に表示したいテキストを渡すことで実装できます。
```PHP:HTML
<?php previous_post_link('%link', '前の記事へ'); ?>
<?php next_post_link('%link', '次の記事へ'); ?>
```

# 同じカテゴリーの前後の記事を表示する場合
下記のように、第3引数に「TURE」を渡すことで実装できます。
```PHP:HTML
<?php previous_post_link('%link','%title', TURE); ?>
<?php next_post_link('%link','%title', TURE); ?>
```

# 前後の記事が無い場合にボタンのCSSを無効化にする場合
前後の記事がない場合に、クラスに`hidden`を追加することで実現可能になります。
今回は、前後の記事がない時は、ボタンを見えなくする仕様にするため、`visibility: hidden;`をCSSで指定します。

```HTML:HTML
<button class="button-before <?php echo get_previous_post() ? '' : 'hidden'; ?>">
    <?php previous_post_link('%link', '前のページへ'); ?>
</button>
```
```CSS:CSS
/* ボタン */
.button-before {
  border-radius: 40px;
  border: solid 1px #757575;
  color: #757575;
  font-size: 15px;
  height: 62px;
}

/* ボタンが非表示でもスペースを保持 */
.button-before.hidden {
  visibility: hidden;
}
```

以上、参考になれば幸いです!
Pandas: 漢字をひらがなに変換してソート

## プログラム

```py:hiragana_sort.py
#! /usr/bin/python

import pandas as pd
from pykakasi import kakasi

# ------------------------------------------------------------------
def kanji_to_hiragana(kanji):
	kks = kakasi()
	result = kks.convert(kanji)
	hiragana = ""
	for converted_word in result:
		hiragana += converted_word['hira']
	return hiragana

# ------------------------------------------------------------------
data = {
    'name': ['山田','佐藤','山内','鈴木','伊藤','田中','高橋','野田','相川'],
    'age': [25,30,22,35,28,31,27,21,32]
}

df = pd.DataFrame(data)

df['name_hiragana'] = df['name'].apply(kanji_to_hiragana)

sorted_df = df.sort_values(by='name_hiragana')

print(sorted_df[['name', 'name_hiragana']])

# ------------------------------------------------------------------
```

## 実行結果

```text
$ ./hiragana_sort.py 
  name name_hiragana
8   相川          あいかわ
4   伊藤           いとう
1   佐藤           さとう
3   鈴木           すずき
6   高橋          たかはし
5   田中           たなか
7   野田            のだ
2   山内          やまうち
0   山田           やまだ
```
プロを目指す人のための例外処理（再）入門 をTypeScript版でまとめてみた 後編

# はじめに
この記事では[プロを目指す人のための例外処理（再）入門 / #rubykansai 2018-01-13](https://speakerdeck.com/jnchito/number-rubykansai-2018-01-13)で学習した内容を備忘録としてTypescript版にしつつまとめたものになります。
前編はこちらです
[プロを目指す人のための例外処理（再）入門 をTypeScript版でまとめてみた 前編](https://qiita.com/Atkiyama/items/123254aab9b8dfde1e6c)
後編では例外処理（主に設計）に関する高度なトピックとして紹介されている箇所をとりあげますので是非ご覧ください！


# 業務エラーとシステムエラーの違い
エラーには概ね以下の二種流があります
- 業務エラー（ビジネス例外）
    - ユーザー操作が原因となるエラー
    - 入力フォームにおけるユーザーの入力ミスや権限違反（権限のないページへのアクセス等）等
- システムエラー（技術的例外）
    - システム側の都合によるエラー
    - プログラムのミス（いわゆるバグ）、ネットワークエラー、データベースのダウン等
これらの区別をすることで、適切なエラーへの対処をすることができます

## 業務エラーへの対処
業務エラーが起きた場合は、以下のような対応が求められます
### ユーザー側にやりなおしをさせる
ユーザー側に原因がある場合、ユーザーの挙動に問題があります。例えば数値を入力する部分に文字列を入力した場合など、、、ですのでエラーをユーザーに伝えてユーザーに操作をやり直してもらうしかないのです
### 例外処理を極力使わずに対応する
業務エラーは基本的にシステム側で想定できたり、検知できるものばかりです。ですので例外処理を使うケースはあまりありません。
```ts
export const createEvent = async (req: Request, res: Response) => {
  const event = new Event(req.body); // リクエストから新しいイベントを作成

  // 保存メソッドの戻り値をチェック
  const savedEvent = await event.save().catch(() => null);

  if (savedEvent) {
    // 保存成功時
    res.redirect(`/events/${savedEvent.id}`, {
      notice: 'Event was successfully created.',
    });
  } else {
    // 保存失敗時
    res.render('new', { event, error: 'Event creation failed.' });
  }
};
```
このコードのように**成功or失敗を例外を使わずともメソッドの戻り値で表現できます**。この戻り値を検証してエラーハンドリングすれば十分エラーに対処できます。逆に例外処理をなくしても業務エラーに対処でない場合、処理フローの制御に例外処理を使っています。その場合には例外処理を使わない業務フローを検討しましょう。(もちろん使わなくてはどうにもならな場合もありますが！)
## システムエラーへの対処
主に以下の対応になります
- 画面には500エラーを出し、ユーザーにこちらで対処する旨を伝える
- エラーログを出す
- 処理を中止するorやむを得ない場合のみcatchして続行する

基本的には処理をそのまま停止させてOKです。ただしやむを得ない場合はcatch等をして続行しましょう。ここでいうやむを得ない場合とは、前編で紹介した[例外処理を使っても許されるケース](https://qiita.com/Atkiyama/private/123254aab9b8dfde1e6c#%E4%BE%8B%E5%A4%96%E5%87%A6%E7%90%86%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%82%82%E8%A8%B1%E3%81%95%E3%82%8C%E3%82%8B%E3%82%B1%E3%83%BC%E3%82%B9)で紹介した場合やそのまま停止した場合にデータの整合性が合わなくなってしまうときです
# 例外処理とロールバックの関係
## アトミック操作
アトミック操作(不可分操作)とは以下の性質を持つ操作です
- 全ての変更が成功したときのみ、変更を確定する
- 1つでも失敗すればロールバックして、変更前の状態に戻す

スライドでは例として複数のレコードを同時に更新する場合やデータベース更新後に課金決済APIを呼び出す場合が紹介されています。

**アトミック操作はデータの整合性を担保するのに必要不可欠**です。トランザクションを用いたり、手動によるロールバックを用いて、エラーが起きた時にもデータの整合性を担保できるようにしましょう。
# 攻めの例外（意図的に例外を発生させる）
## 予期せぬ条件分岐を防ぐ
以下のコードのように、分岐した先でありえない分岐をした場合には例外を投げてエラーを発生させて処理を停止しましょう。これを放置していると予期せぬ動作につながります。例えば変なところでエラーが出たり、矛盾した動作を起こしたりするので気をつけましょう。

```ts
function currencyOf(country: string): string {
  switch (country) {
    case 'japan':
      return 'yen';
    case 'us':
      return 'dollar';
    case 'india':
      return 'rupee';
    default:
      throw new Error(`無効な国名です。${country}`);
  }
}

// 使用例
try {
  console.log(currencyOf('italy')); //=> Error: 無効な国名です。italy
} catch (error) {
  console.error(error.message); // エラー処理
}
```

# まとめ
以上、プロを目指す人のための例外処理（再）入門 をTypeScript版でまとめてみた 後編でした！
自分もまだ例外処理については学習中ですが、同じ学習を進めている方の参考になればと思います！
情報処理技術者試験の４区分(FE,AP,SC,NW)に1年半くらいで合格した話（Part3_情報処理安全確保支援士、本試験編）

## 前回までのあらすじ

3行で

* 妻が臨月間近なのに
* 文系大学出身の国家公務員(FE取得ほやほや)が
* 情報処理安全確保支援士に挑戦するよ

プロフィールとか　→　[Part1へのリンク](https://qiita.com/nelly7k/items/1feed6405f67e0e75990)

前回の記事　　　　→　[Part2へのリンク](https://qiita.com/nelly7k/items/13cacf062834ab373694)

何番煎じかわかりませんが...


## 試験当日

試験会場は新横浜でした。
住居地からは公共交通機関で1時間半かかる場所であったため、かなり早めに起床しました。
とりあえずこの時点で0次の起床試験は突破できました。
この0次試験で落ちる人が一定数いるのは、この試験の面白いところかなと思います。

さて、ここから本試験の話をしていきます。

#### 午前Ⅰ

ここでかなり出鼻をくじかれました。

というか甘く見ていました。
あの方の言葉を借りるなら

「そして何よりも ―― 時 間 が 足 り な い !」

過去問道場をしていた時は、あまり意識していなかったのですが、本試験では1問あたり1分40秒で解く必要があります。
単純な択一問題は脊髄反射くらいで解いてください。マジで。
私は、計算問題は飛ばして、択一問題をすべて終わらせてから、最後に計算問題をまとめて解きました。
それでもむちゃくちゃ短かった気がします。


#### 午前Ⅱ

これもむちゃくちゃ短いですが、計算問題は少なめなので若干余裕があります。
1問あたり1分36秒で解く必要があります。


#### 魔のお昼休み

午前Ⅱが終わるとお昼休憩です。
情報処理技術者試験で個人的に一番大事なことをお伝えしておきます。


<font color="Red">$\huge{答え合わせはやめときな}$</font>



マジでいいことありません。(3戦1勝2敗)

SC、NW、AP、それぞれの試験で気になるところだけ答え合わせをしてしまったのですが、結果SCとNWの午後の戦い前に少しダメージを負うことになりました。

特に午前Ⅰは解けてそうな問題で間違えていることが判明したりして絶望しました。(2か月ぶり、2回目)


#### 午後

さて、難関の午後です。

この年の過去問を知っていれば、あぁあれね。となる方が大半かと思います。

試験では解答用紙が先に配られて、裏向きにしておきます。

すると、裏面に印字されている問3と問4の回答欄が自然と目に入るのですが...

ん？

ん？？

$\huge{なにこの回答欄？？？}$

通常であれば、文字制限であることを表すために、記述問題の回答欄は1文字ごとに区切られます。

ですが、問4にはそのような回答欄がなく、3行ほどの記述欄が見受けられました。

何じゃこりゃと思いながら、試験開始を迎えました。

選択したのは問２(無線LANセキュリティ)、問４(リスクアセスメント)でした。

問2はオーソドックスな問題かと思いますので、特に触れません。

問3と問4で迷ったのですが、答えやすそうな問4を選択しました。

回答の内容には触れませんが、どちらの問題でも作問者が問題文にちりばめた伏線を回収しておくことが重要なのかなと思います。


## 試験後のむちゃくちゃ余談

試験終了後、友人から電話がかかってきて、「RADIUS書けた？」とか「この問題こうじゃない？」とか話している間に午後の問2は多分こけたなぁと絶望しました。（3時間ぶり3回目）
試験後ラーメン博物館に寄りました。
休日であることを忘却していたため、むちゃくちゃ並んでいて絶望しました。(20分ぶり4回目)
列に並びながら春にまた受けるかぁと思っていた記憶だけが残っています。笑

帰宅して、20時くらいには公式から午前問題の回答が発表されており、友人と答え合わせをしました。
正答率的に午前を突破していたことが判明して少し安堵したことを覚えています。


## 結果
そういや結果発表されてるなぁと思いながら発表から二日後くらいに確認した覚えがあります。
というのも、里帰り出産していた妻を迎えに行ったりとバタバタしていたので結果発表の日にちを正確に覚えていませんでした。笑


午前Ⅰ　68.00点
午前Ⅱ　76.00点
午後　　78点

で合格でした。
いや合格してるんかい！と思いました。笑

## 完走した感想
問4の自由記述欄の問題はちょっとどうなのかなとも思いましたが、受かったのでよしとするご都合主義な自分もいるわけで。笑


## 余談
   結果発表までは沈んでいる時が多かったので、妻には迷惑をかけたなぁとこの記事を書きながらしみじみと思っています。
   試験の次の日は、妻と出かけたのですが、むちゃくちゃため息ついてた気がします。
   合格を報告したときには、妻から「合格してるんかい(ﾟДﾟ)ﾉ」「お主が落ち込んでいるので次の日の外出が楽しくなかったんや」「埋め合わせ~~しやがれ~~をきちんとするように」と言われました。笑
   $\tiny{きちんと妻孝行をしようと思います。切実に。}\$

## さて、

ここまで読んでくれてありがとうございます。
特に書きたかったのはここまでの話だったのですが、最後まで完走しようと思います。
もう少しだけ続きます。

~~抹殺の~~[Part4_ネットワークスペシャリスト編へ](https://qiita.com/nelly7k/items/a51e748f803bf2c9ed62)