OmniAICreator/Qiita-1.07M huggingface dataset:
令和６年春期　応用情報技術者試験　完走した感想

## 初めに

令和6年の応用情報技術者試験を受けた感想を忘れないうちに書いておく。

## なぜ受験したのか

- 資格手当がもらえる
- 転職したい
- ITパスポート、基本情報、セキュリティマネジメントを順調に取得してからのステップアップ


## 勉強法

1．「キタミ式ITイラスト塾　応用情報技術者」をさらっと二周して頭にだいたい入れておく。（20~30時間ぐらい?）
毎年新しいものが出るようなのでこれから買う人は下記リンクじゃなくて令和6年版を買ったほうがよい。
https://www.amazon.co.jp/gp/product/B0BMFQMQJY/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1
2.  「応用情報技術者試験ドットコム」で午前過去問を解く。
期間は令和5年秋～平成29年秋。（1300回程度。20~30時間程度?　時間きっちり測っておけばよかったな）
https://www.ap-siken.com/
3.　前項で間違えた問題をテキストで再度復習する。
4.　午後の過去問を一通り解いて、選択科目を決める。
最初は日頃仕事で使っているSQL文を使うつもりだったが、普段使っているDBとなんかちょっと違って変なところで点を落とすのでやめた。
最終的には経営戦略・サービスマネジメント・システム監査を軸に、後の一つは情報システム開発・システムアーキテクチャ・データベースからアドリブで一問選ぶことにした。
5．　午後の過去問を解く。これは応用情報技術者試験ドットコムにかけた時間が残っている。11.3時間らしい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3565403/45267b96-842c-f4bb-6bf5-5c09dbe93d4b.png)
6.　午後の過去問であやふやだったところをテキストに戻って復習。
7． 午前の過去問で不正解だったところを、応用情報技術者試験ドットコムの「復習を開始」から復習して全問正解しておく。

多分トータルで100時間は超えないと思う。
「キタミ式ITイラスト塾　応用情報技術者」を購入したのが昨年11月3日だったので、期間としては5カ月ということになるが、そんなにずっと勉強漬けだったわけでもない。

## 前日
風邪気味だったし、既に合格するという確信を持っていたので、早めに寝た。
（そもそも、午前試験を合格できないようであれば午後試験の問題など解けるわけもないので、ギリギリまで知識を詰め込むよりも午後試験のために早めに寝たほうがよいと判断した）

## 当日
早めに寝たおかげで頭すっきり。
予定通りの時刻に起床し、試験会場へ。
なお、朝食のことを忘れていたのでモンスターエナジーを飲んですませたが、これはよくなかった。
試験の日には朝食を食べるべきだった。

### 午前試験
とりあえず計算問題は飛ばして知識問題を解いてから、時間に余裕のある状態でゆっくり計算問題を解いた。
90分ほどで解き終わり、15分程度見直しとマークミスと試験番号と生年月日の確認を二回やってから、11時15分ごろに退出した。

### 休憩
時間が余ったら（見直しはする前提で）早めに退出したほうがよかった。
12時まで試験して12時40分に入場では、40分しか食事と休憩とトイレにかけられない。
試験会場の立地にもよるが、これではかなり忙しくなる。
見直しはしたうえで、早めに退出して、混む前に食事とトイレをのんびり済ませる。
これが王道かと思う。
ちなみに行きつけのラーメン屋が混んでいたのでSubwayで軽くすませた。
なお応用情報技術者試験のサイトで自己採点したら8.5割だった。
そういえば大学受験の時は「自己採点を試験会場でやるやつは落ちる」と教師が口を酸っぱくして言っていたなと思いだした。要はギリギリまで単語一つ、公式一個を詰め込めと言う話だが、私は会場でそんなことやってる時点で負けだと思う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3565403/c7c47a23-eaed-e8a6-b52e-ea658005564b.png)

### 午後試験
問1（セキュリティ・必須）を完答した時点で20分経過。
そのあと問11（システム監査）問2(経営戦略)問10（サービスマネジメント）を順調に解いていき、あと大問1つというところで残り60分。
…………ここで手が止まる。
情報システム開発は……クラスとか日常の開発で触ってないから苦手だし、システムアーキテクチャは今回難しそう……データベースは解けないこともないけど……
…………組込みシステムのほうが、簡単そうに見えるなあ。
（5分程度悩む）
悩んでる時間が無駄！ここで一番避けるべきは「大問4つをほぼ完答したけど悩んで大問一個丸ごと解けない状態になる」こと！それよりは問１問２は確実に解けそうな問7（組み込みシステム）を解く！（オリチャー発動）
問7を30分かけて完答し、15分かけて見直ししてエンド。なんとなく退出せずに最後まで残りました。

## 手ごたえ
午前は間違いなく受かってるし午後も99%受かってると思います。
キタミ式と応用情報ドットコムに感謝したい。

## 追記（2024-07-05)
合格しました。
並列化したプログラム全体のプログレスバーを表示させる

# 並列化したプログラム全体のプログラスバーを表示させる

以前，Pythonのプログラムを並列化による高速化を実装した際に，全体の進捗状況が確認出来たら便利だな～と思って調べたのですが，ググっても日本語記事は出てきませんでした．

出てきても並列処理それぞれの進捗を表示させるみたいなのしかなかった…（なお，並列化した関数から値を返すとなったらなおさら）

なので，自分で実装したコードの例を備忘録として記事にしておこうと思いました．

ここでの並列化は multiprocessing を想定しており，全体としては主に三段構造になっています．
今回は例として0から10までのリストを作って，それらの二乗の値を返すプログラムにしています．
状況によって適宜変更して下さい．

## 使用するライブラリ
~~~python:
from multiprocessing import Pool #並列処理
from tqdm import tqdm
~~~

## 並列化させる関数
~~~python:
def func(param_list):
    param_list = [x**2 for x in param_list]
    return param_list
~~~

## 並列処理を実行する関数
~~~python:
def parallel_processing(param_list):
	with Pool(processes=10) as pool:
		results = []
		with tqdm(total=len(param_list)) as pbar:
			for result in pool.imap(func, param_list):
				results.append(result)
				pbar.update(1)
		return results
~~~

## プログラム本体
~~~python:
param_list = [n for n in range(10)]
square_list = parallel_processing(param_list):

# 確認する
print(param_list)
print(square_list)
~~~

ここでは，processes で並列処理の数を10に設定しています．

pool の imap で関数 func とパラメータ param_list を渡して，それらと同じ順番で二乗した値を返します．


もしうまく動作しなかった場合はコメントしていただければ嬉しいです．
応用情報技術者試験を受けてきた

## はじめに
自己採点して午前不合格が確定したので半年後の自分のために書きます。
受かるとも思ってなかったけどもう少しいいラインまでいけるんじゃないかと期待していました...

# 申し込み〜当日
### 良かったこと
#### 申し込みは早めに
申し込み開始時はまだまだ合格できそうになく、高いお金を出しても意味ないかなぁと思って躊躇しがちです。
でも早く申し込めば会場は近くなる（はず）ので当日の早起きチャレンジに成功する確率が上がります。
申し込み開始翌日あたりに申し込みましたが、近くの会場が取れたので現実的な時間に起きて会場にたどり着くことができました。

#### 1時間前に会場到着
8時半頃到着するようにスケジュールを立て、実際は8時20分頃に到着しました。
8時半から部屋に入れると案内を受けたのでロビーで少し待機。
9時10分には着席していないといけないので、会場に着いてから筆記用具の準備をしたり、お手洗いに行ったり、気持ちを落ち着けたり、復習したりする時間を確保するならこれくらい必要そうです。
今回は涼しい日だったので汗をかいて落ち着かないなんてことはありませんでしたが、10月だとまだ暑いかも？
尚更余裕持って準備できるようにした方がいいかもしれません。

#### 休憩場所を探しておく
基本情報を受けたときは午前が早めに終わって余裕があったのでファミレス等でご飯を食べていましたが、応用情報はギリギリの時間に途中退室したのでそんな余裕はありませんでした。
今回は近くにお店もなかったのでコンビニでご飯を買っていて正解でした。
受験した部屋の近くにベンチがあるのは開始前に確認していたので、退室後はそのベンチに行き、試験終了後に部屋へ戻ってご飯を食べました。


### 良くなかったこと/改善したいこと
#### 解答速報は信じない
解答速報2サイトで確認しました。
その時点で合格点には届いてませんでしたが、ポジティブに「まぁ受かってる可能性だってあるし？」と思って午後も受けました。
午後を諦めないなら確認してもいいと思います。
サイトによりますが、解答速報と公式解答例で5点差がありました。（下がった）
次回は絶対確認しない。怖い。

#### 早起きが辛い
早起きしようと意気込んで準備しておけば起きられるくらいにはなりましたが、早起きが当たり前の生活にはできませんでした。
やっぱり午後になると眠くなりました（ご飯減らせばよかったかも）。

#### 午後問題をちゃんと紙で解く
普段iPadで勉強していたため、午後問題の過去問を模擬試験のような形で解く際もiPadで解いていました。
（紙でやろうとしたけどコンビニで印刷できなかった）
ページが跨ぐことの見づらさはあまり変わらないだろうと思っていましたが、実際は紙を捲る動作の有無が個人的には大きな違いでした。
ちゃんと紙で解いていたらわかっていたことなので反省です。
また、問題用紙と解答用紙に書き込むことで普段よりも時間がかかったのでここも注意が必要です。
自己採点は諦めて解答用紙だけに書くか、前もって両方書いても時間に余裕があることを確認しましょう。



# 一応勉強のことも少しだけ書く
### 使用した参考書
- キタミ式イラストIT塾 応用情報技術者
- 応用情報技術者 合格教本
- 応用情報技術者 午後問題の重点対策

キタミ式はよく言われていますが、初心者向けの参考書でした。
初めは読みやすかったので活用していましたが、ある程度勉強すると情報が少なすぎて学べなくなったため合格教本に切り替えました。

合格教本は情報が多いです。
初めての参考書としては多すぎて何から覚えればいいかわからなくなりそうです。
過去問を解いていてわからないことはほとんど載っているので合格するためにはマストだと思います。

重点対策はあまり活用できませんでした。
午後より午前の方ができなくて対策もままならない状態で当日を迎えました。
解説はわかりやすいですし、午後の対策としてはいい参考書だと思います。
これから活用しようと思います。
【Flutter】WidgetBindingを使ってbuild実行中のページ遷移を防ぐ

## はじめに
ページ遷移を実装したところ、`navigator.dart':Failed assertion: line 5295 pos 12: '!_debugLocked':is not true.`というエラーが出ました。解決したので記事にしようと思います。
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/171246a7-23e1-b12e-1efd-9b8cf947f09f.png', width = 150>

## エラー内容
以下のコードを実行したところ、`navigator.dart':Failed assertion: line 5295 pos 12: '!_debugLocked':is not true.`というエラーが出ました。
```dart
Widget build(BuildContext context) {
		/*--省略--*/
    if (isAccountBanned) {
      Navigator.push(context, AccountBannedPage.route());
      return const SizedBox.shrink();
    } 
```

このコードにおける問題は`build`メソッド内で直接`Navigator.push()`を呼び出していることにありました。`build`メソッドはウィジェットの描画に関わるため、このメソッド内で直接ページ遷移を行うと、フレームの描画が完了する前に遷移が始まることで状態が不整合になり、エラー（ロック状態）になってしまいます。

## 解決
以下のように`Navigator.push`を`WidgetsBinding.instance.addPostFrameCallback`で囲むと解決しました。これにより、フレームワークの描画が完了した後に遷移を実行することができます。WidgetBindingとは公式にも書かれている通り、FlutterEnginとFlutterFrameworkを通信できるようにする役割があります。他にも色々種類があるそうなので後に調べてみようと思います。

```dart
Widget build(BuildContext context) {
		/*--省略--*/
  WidgetsBinding.instance.addPostFrameCallback((_) {
    if (isAccountBanned) {
      Navigator.push(context, AccountBannedPage.route());
    }
  });

```

## 最後に
このエラーに出会ったことでFlutter自身のロジックについて興味を持つきっかけになりました。これから色々と調べて、確信を持ってコーディングやデバッグのできるエンジニアになりたいと思いました。
Apple SiliconのMacとUTMで「ゼロからのOS自作入門」の環境を構築する

# 概要
「ゼロからのOS自作入門」を進める中で、Apple SiliconのMac + UTM + [Ubuntu 22.04 arm64](https://cdimage.ubuntu.com/jammy/daily-live/current/)という組み合わせで、詰まってしまった箇所のメモです。


## 2章

### `target.txt`の`TOOL_CHAIN_TAG`を変更する
```
TOOL_CHAIN_TAG = CLANGPDB
```

### edk2のブランチを変更する
```
git checkout edk2-stable202102
```

## 参考
https://www.czu.jp/blog/20210327
[4]Next.jsチュートリアルを進められたのでやってみる(4)レイアウトとページの作成

# はじめに

今回の記事では、Next.jsチュートリアル第4章「レイアウトとページの作成」を進めていきます。

https://nextjs.org/learn/dashboard-app/creating-layouts-and-pages

#### 前回の記事

https://qiita.com/2201009-kikukawa/items/5e5f5d98b04cdfdab81b

## chapter4:レイアウトとページの作成

この章では以下の内容について学ぶことができます。
- ファイル システム ルーティングを使用してルートを作成する
- 新しいルート セグメントを作成するときのフォルダーとファイルの役割を理解する
- 複数のダッシュボード ページ間で共有できるネストされたレイアウトを作成する
- コロケーション、部分レンダリング、ルート レイアウトとは何かを理解する

## ネストされたルーティング
Next.js はファイルシステムルーティングが使用されており、フォルダーを使用してネストされたルートを作成します。各フォルダーは、URLセグメントにマップされるルートセグメントを表します。
つまり以下の画像のようにフォルダー名がそのままURLになります。
![スクリーンショット 2024-04-21 154308.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619847/4a0ff96e-1e99-3eda-275d-28c6ccae1566.png)
ただし、ただフォルダーを作るだけではルートはできません。下の画像のようにフォルダーの中にpage.tsxというファイルを作成することによってルートが作成されます。
![スクリーンショット 2024-04-21 154512.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619847/89cab038-79a7-70f1-185b-da42fd468c81.png)

### ダッシュボードページの作成
`dashboardinside`という名前の新しいフォルダーを`/app`直下に作成します。次に、`dashboard`フォルダーの`page.tsx`に以下の内容を貼り付けます。
```/app/dashboard/page.tsx
export default function Page() {
  return <p>Dashboard Page</p>;
}
```
貼り付けが終わったらターミナルで`npm run dev`を実行し、下記のローカルホストにアクセスし`Dashboard Page`というテキストが表示されればOKです。

http://localhost:3000/dashboard

### ダッシュボードレイアウトの作成
先ほど作成したダッシュボードフォルダに含まれるファイルには共通レイアウトとしてサイドバーを用意する必要があります。
そこで第2章でも使った`layout.tsx`を`dashbord`内に追加すると、
 - /dashboard/page.tsx
 - /dashboard/customers/page.tsx
 - /dashboard/invoices/page.tsx
 の`dashboard`直下のファイルすべてに共有され、`dashbord`以外の`page`に対し影響を与えません。

```/app/dashboard/layout.tsx
import SideNav from '@/app/ui/dashboard/sidenav';
 
export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <div className="flex h-screen flex-col md:flex-row md:overflow-hidden">
      <div className="w-full flex-none md:w-64">
        <SideNav />
      </div>
      <div className="flex-grow p-6 md:overflow-y-auto md:p-12">{children}</div>
    </div>
  );
}
```
こうすることで先ほど3つのページ全てにサイドバーが共有されました。ちなみにページごとのレイアウトは`{children}`に含まれています。
ローカルホストへアクセスし下の画像のようになっていればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619847/c6afbb5d-2067-5066-4c28-93933b90ff0c.png)



また`layout.tsx`を使う利点として`page.tsx`が更新された時に`再レンダリング`が起こらないといったものがあります。このことを`部分レンダリング`といいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619847/73cc705c-0fc1-6f89-aa39-7bc4804bb15c.png)
この画像のように、`layout.tsx`部分は共有の物を利用しているためレンダリングが起こらず、各ページの固有の部分にのみレンダリングが発生します。

### ルートレイアウト
第3章では`Inter`フォントを別ファイルにインポートしました。
```/app/layout.tsx
import '@/app/ui/global.css';
import { inter } from '@/app/ui/fonts';
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={`${inter.className} antialiased`}>{children}</body>
    </html>
  );
}
```
これは`ルートレイアウト`と呼ばれ、ルートレイアウトに追加したUIは、アプリケーション内の`すべての`ページで共有されます。
今回、新しく作成したレイアウト`/app/dashboard/layout.tsx`はダッシュボードページ固有のものであるため、上記のルートレイアウトにUIを追加する必要はありませんが、前回のフォントのような`全ページ`に共有させたいレイアウトは必ず記述しなければいけません。

## 終わりに
今回の記事では新しくページ、ルート、レイアウトの作成をおこないました。
やっとコーディングの作業が本格化してきて楽しくなってきました、次の章も楽しみです。

## 次の記事
リモート接続でSQL ServerのtableをExcelのpower queryでインポートする方法

かなり時間がかかったが接続方法が分かったので備忘として残したい。
同じLAN内のPC1からPC2に接続してPC2のSQL Serverのデータベースのテーブルを確認できるようにしたい。
通信系の設定とユーザー権限系の設定が必要。
SQL Server Express,SSMS 20.1, SQL 構成マネージャーをPC2にインストールしている。

## 通信系の設定
### セキュリティ設定
windows DfenderでPC2のSQL Serverの受信を許可する。
受信の規則→新しい規則→名前、SQL_Server(tcp/1433) ポート1433
受信の規則→新しい規則→名前、SQL ServerBrowser (udp/1434) ポート1434
上記二つの規則を有効にする。

### SQL Server構成プロトコル
SQL Server ネットワークの構成　SQLEXPRESSのプロトコルでTCP/IPを有効にする。
TCP/IPのプロパティのプロトコルですべて受信待ち：はい
TCP/IPのプロパティのIPアドレスでIPALL > TCPポート：1433
上記を設定してSQL Serverを再起動

SQL ServerのサービスのSQL Server Browserのプロパティのサービスの開始モードを自動に変更
その後実行

## ユーザー権限系の設定
### SSMSでの設定
ログイン を右クリックして新しいログイン
ログイン名を SQL server認証として任意のユーザー名とパスワード名を入力
パスワードポリシーは外す。

データベースのプロパティーから設定したユーザーにselect権限を付与する。

## Excel Power Queryでの接続
PC1のExcelでパワーQueryを立ち上げ
サーバ名：「PC2のIP\SQLEXPRESS」
SQL Server認証で設定したユーザ名・パスワードを入力



参考記事
https://tex2e.github.io/blog/database/sqlserver-setup
https://www.movabletype.jp/documentation/mt7/installation/database/sqlserver2016/create-user/sqlserver-authentication.html
Pythonでテキストマイニング【概要】（自然言語処理/MeCab/nlplot）

# 準備・環境構築
## Pythonまわり
* ローカルでPythonを動かす場合：**自由度高い、煩雑**
    * **Python**：必須
    * **Jupyter Notebook/Lab**：Pythonスクリプトを動かすソフト、(ほぼ)必須
    * **Anaconda**：Pythonを動かすためのツールが色々入っているパッケージ（なくても可、あると便利）
    * 必要に応じてNode.jsのインストール（Jupyter Labを動かすのに必要だったような）

<br>

* クラウドでPythonを動かす場合（Google Colaboratory）：**簡単・手軽、自由度低い**
    * Google Colaboratoryを使うための設定（ほんの少し）
    * Googleドライブの接続

:::note info 
**ここでのゴール**
* JupyterかColabを用いてPythonのコードを動かすことができる
* ライブラリをインストールすることができる
* ある程度適切に環境が構築されている
（場合によってはPC内がごちゃごちゃになる。。）
:::



## MeCabまわり
* MeCab（Windows版）のインストール
* ユーザー辞書の[追加](https://qiita.com/kujira_0120/items/de46f7db2e24d0af6142)
* 動作確認

:::note info
**ここでのゴール**
* 任意の単語を追加できている
* それに基づいて形態素解析を行えることが確認できている
:::


## テキストの取得
* 解析したいテキストを、csvかxlsxファイルで準備（pandasで読み込むことを想定）
* （APIを用いてテキスト取得の自動化も可能）
* テキストの整形



# 実際に動かす
## ライブラリのインストール
* 必要なライブラリーを`pip install`する
* pandas, mecab, nlplot, matplotlib, seaborn, plotyなど

## 実装
* ライブラリのインポート
* テキストの読み込み
* 形態素解析
* nlplotで解析、可視化
archlinux(hyprland) で huawei のイヤホンを使ったらオーディオファイル(コーダー)で困った

# 問題
archlinux(hyprland)の hyprdots で HUAWEI FREEBUDS 5 を接続したときに、音が途切れる、勝手に接続が切れるということが発生していました。
接続し直しても変わらず、再起動でも変化ありません。

# 原因
オーディオプロファイルの設定が間違っていたようです。
コーデックという音声ファイルを圧縮変換する技術があり、データの形式が違うようです。

今回はLDAC対応のイヤホンなのでFLAC/ALAC/A2DPのコーデックを利用することができます。
また、SBCよりAACのほうが「低遅延・高音質」らしいので、ACCを利用します。

(私は、音声ファイルについて詳しいわけではないので間違っていたらコメント等よろしくお願いします。)
# 解決
Bluetooth から接続している機器を右クリックすることでオーディオプロファイルの設定ができます。
以下のように A2DP ACC を選択しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3769595/7f1b053b-1d6b-41a7-fa0d-f6ed01b5dabe.png)

音質直ってよかった！！
archlinuxライフむずすぎ！
Golang_study_1


## 本日やったこと
- GO言語を学ぶための環境構築
    - [参考にさせていただいた記事](https://qiita.com/melty_go/items/c977ba594efcffc8b567)
    - goのインストール
    - vscodeをGO開発向けにカスタマイズ
        - 静的チェック
        - デバッグ
    - goのプロジェクト作成
- GO言語の基礎学習
    - [A Tour of Go](https://go-tour-jp.appspot.com/list)
- Git環境の構築
    - gitのインストール
    - GitLabアカウント作成
    - ローカルマシンの既存プロジェクトフォルダをgitリポジトリ化
    - GitLabの空プロジェクトと上記ローカルリポジトリの同期

## 詰まった点
### GO関連
- Goのプロジェクトを作成するときに実行する```go mod init <モジュール名?>```がよくわからなかった
- 変数の宣言時に、型を変数名のあとにつける感じが慣れない
    - vscodeをGO向けにカスタマイズした結果、静的なミスを拾ってくれるようになったから、それはすごく楽だった
### Git関連
- ローカルマシンの既存プロジェクトフォルダをリポジトリ化して、それをGitLab上のからプロジェクトに```push```する際、いきなり```push```はできなかった。```add```と```commit```をする必要があった
    - プロジェクトをgitで管理するときは一般的にはどうやってはじめるのだろう(ほんとのほんとの始まりの部分)
        - gitlabなどで空プロジェクトを作成してから、それをクローンとかして、ローカルに持ってきて作業してpushして～みたいな流れなのか
        - ローカルマシンのプロジェクトをリポジトリ化して、gitlabなどの空プロジェクト(リモートディレクトリ)にpush～みたいな流れか
        
## 今後の学習
- ```go mod```について理解する必要あり
- ```git push```のオプションなどについて理解する必要あり
Visual Stdio Codeキーバインド

最近何度も設定しているので、備忘録です。
設定内容だけでなく、設定手順自体も忘れちゃうので、ちょっと丁寧めに。

キーボードショートカットリストを表示する 
　macの場合、⌘＋K ⌘＋S

![スクリーンショット 2024-04-21 21.12.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16828/eaeb667b-b40a-6d77-367c-9edaedabf70c.png)

　そして、↑の赤枠にあるアイコンをクリック

 ```json:keybindings.json
 // 既定値を上書きするには、このファイル内にキー バインドを挿入します
[
    {
        "key": "ctrl+t j",
        "command": "workbench.action.terminal.focus",
        "when": "editorFocus"
    },
    {
        "key": "ctrl+t k",
        "command": "workbench.action.terminal.focus",
        "when": "editorFocus"
    },
    {
        "key": "ctrl+t k",
        "command": "workbench.action.focusActiveEditorGroup",
        "when": "terminalFocus"
    },
    {
        "key": "ctrl+t j",
        "command": "workbench.action.focusActiveEditorGroup",
        "when": "terminalFocus"
    },
    {
        "key": "ctrl+t h",
        "command": "workbench.action.focusSideBar",
        "when": "editorFocus"
    },
    {
        "key": "ctrl+t l",
        "command": "workbench.action.focusSideBar",
        "when": "editorFocus"
    },
    {
        "key": "ctrl+t l",
        "command": "workbench.action.focusActiveEditorGroup",
        "when": "focusSideBar"
    },
    }
]
 ```

 一応tmuxでpane移動するようなキーバインドを想定
 tmuxのprefixはCtl+tとしているので。
[Python]Google Colab上でMeCabを動かす

# はじめに
Google ColaboratoryでMeCabを動かす。ポイントとしては、ライブラリーのインストール先をGoogleドライブ上のフォルダに指定することで、ランタイムを更新する度に新たにインストールする手間を省けるようにした。

## Googleドライブのマウント
```python
from google.colab import drive
drive.mount('/content/drive')
```

## ドライブ上にライブラリをインストール
任意のフォルダを指定して**Googleドライブ上にインストール**。
ここでは、`mecab-python3`と`ipadic`をインストールしている。
```
!pip install --target /content/drive/MyDrive/Colab\ Notebooks/site-packages/mecab mecab-python3 ipadic
```

## ドライブからインポート
**準備**
```python
package_path_str = '/content/drive/MyDrive/Colab Notebooks/site-packages/mecab'

import sys
sys.path.append(package_path_str)
```
インポート自体は通常と同じコード。
```python
import MeCab
```
これで**ドライブ上からインポート**できる。

## 形態素解析の実装

```python
tagger = MeCab.Tagger('-d /content/drive/MyDrive/Colab\ Notebooks/packages/mecab/ipadic/dicdir')
text = 'メカブ（和布蕪）は、ワカメの付着器の上にある、葉状部の中で厚く折り重なってひだ状になった部分である。'
print(tagger.parse(text))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3655949/3a021697-36e5-88f1-008f-c943a2abccf0.png)
CSVファイルの読み書きサンプル

``` python
import csv
import os


base_folder_path = os.getcwd()

list_path = os.path.join(base_folder_path, "list")

# ディレクトリ名と絶対パスの対応を格納する辞書を初期化
path_dict = {}

# 指定したディレクトリ内のディレクトリのリストを取得し、辞書に追加
for item in os.listdir(list_path):
    full_path = os.path.join(list_path, item)
    if os.path.isdir(full_path):
        path_dict[item] = full_path


# 新しいCSVファイルのパス
output_csv_path = "./output.csv"

# csvの読み込みと書き込み
with open("./data_list.csv", "r", encoding="utf-8-sig") as read_file, open(
    output_csv_path, "w", encoding="utf-8-sig", newline=""
) as write_file:

    reader = csv.reader(read_file, delimiter=",")
    writer = csv.writer(write_file, delimiter=",")

    for row in reader:
        directory_name = row[0].strip()
        if directory_name in path_dict:
            directory_path = path_dict[directory_name]
            row.append(directory_path)  # 対応するディレクトリのパスを追加
        writer.writerow(row)  # 書きこみ


```

修正後↓

```python
import csv
import os
import argparse


def main() -> None:

    parser = argparse.ArgumentParser()
    parser.add_argument("-l", "--list_path", default="./list")
    parser.add_argument("-i", "--input_path", default="./data_list.csv")
    parser.add_argument("-o", "--output_path", default="./output.csv")
    args = parser.parse_args()

    list_path = args.list_path
    input_csv_path = args.input_path
    output_csv_path = args.output_path

    # ディレクトリ名と絶対パスの対応を格納する辞書を初期化
    path_dict = {}

    # 指定したディレクトリ内のディレクトリのリストを取得し、辞書に追加
    for item in os.listdir(list_path):
        full_path = os.path.join(list_path, item)
        if os.path.isdir(full_path):
            path_dict[item] = full_path

    itemlist_with_added_path = []

    # csvの読み込み
    with open(input_csv_path, "r", encoding="utf-8-sig") as read_file:
        reader = csv.reader(read_file, delimiter=",")

        for data in reader:
            directory_name = data[0].strip()
            if directory_name in path_dict:
                directory_path = path_dict[directory_name]
                data.append(directory_path)  # 対応するディレクトリのパスを追加
            itemlist_with_added_path.append(data)

    with open(output_csv_path, "w", encoding="utf-8-sig", newline="") as write_file:
        writer = csv.writer(write_file, delimiter=",")

        for data in itemlist_with_added_path:
            writer.writerow(data)  # 書きこみ


if __name__ == "__main__":
    main()
```
追加↓ 
```python
from openpyxl import Workbook


output_data = {"hoge1": [["1", "a"], ["2", "b"]], "hoge2": [["3", "c"], ["4", "d"]]}

wb = Workbook()
ws = wb.active

row = 0
for path, error_data_list in output_data.items():
    for error_data in error_data_list:
        for column, data in enumerate([path] + error_data):
            ws.cell(row + 1, column + 1, data)
        row += 1


wb.save("sample.xlsx")
```
Rubrikについてまとめてみた！vol.2

# Rubrikについて vol.2

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494465/f1728ca5-a018-17c4-ca04-2d25a20af82f.png)


vol.1に引き続き、Rubrikについて書いていきます。
実際に構築した経験があるのは、物理筐体(Brik)だけなのでEdgeやCloud Cluster ESについては出てこないです。(このあたりもそのうち経験したい)

前回の記事はこちらです。

https://qiita.com/konyakun/items/dc0df3329f804ba014f3

# 構築前に検討しないといけない事項
ここでは、「これからRubrikの構築をする！」という方に向けて書いていきます。
実際に僕が構築した際、次回構築時は気を付けないといけないなと思った部分です。


:::note warn
注意
本記事はRubrikのCDMバージョンは9.0の前提で書いています
:::


### 1. ネットワーク回りの検討 (使用するbondの決定)
Rubrik社の担当者と話した時にも、NW回りを詰めていないことから、構築に影響が出ることが多いと言っていました。
(というよりも構築がうまくいかないのは、ほぼNWの検討不足で起きるとのこと)
ここだけでも書きたいこと盛りだくさんです。

まず、Rubrikの筐体(Brik)に搭載されているノードのうち、どのポートを使用するかを決める必要があります。

ノードの画像です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494465/92090f28-9f2a-4bb7-f883-9bdb6f6bb80a.png)

①と②はbond0とよばれ、Rubrikを使用する上で必ず結線する必要があります。デフォルトではデータ/管理ポートとして使用されます。

※1 管理：インターネットへの通信や、SNMP、Syslogなどに使用されるポートになります。
※2 データ：バックアップデータの通信に使用されるポートになります。

③と④はbond1とよばれ、「管理」と「データ」の通信を物理的に分離したい場合にのみ使用します。

bond0だけでも論理的な分離は可能なので、使用するbondの決定は接続先スイッチの空きポートにも依るところが多いかなと思います。

以下、必要ポート数を計算してみました。

**1Brikでbond0、IPMIを使用する場合**
1ノードあたり3ポート(bond0で2ポート、IPMIで1ポート)なので、**12ポート**必要

**1Brikでbond0、bond1、IPMIを使用する場合**
1ノードあたり5ポート(bond0、bond1で4ポート、IPMIで1ポート)なので、**20ポート**必要

**3Brikでbond0、IPMIを使用する場合**
1ノードあたり3ポート(bond0で2ポート、IPMIで1ポート)なので、**36ポート**必要

**3Brikでbond0、bond1、IPMIを使用する場合**
1ノードあたり5ポート(bond0、bond1で4ポート、IPMIで1ポート)なので、**60ポート**必要

### 2. IPMIの使用有無

さっきのノードの画像です。⑤がIPMIと呼ばれるポートです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494465/92090f28-9f2a-4bb7-f883-9bdb6f6bb80a.png)

DellのiDRACやHPEのiLO、FujitsuのiRMCと同じように、遠隔から機器の電源操作ができます。
使用しないと、電源をつけるのに現地に行かないといけないので、使用するかどうかは運用担当者の判断次第となります。(Rubrikクラスターのシャットダウンはsshで実行可能です。)
また、先ほど同様、Rubrik接続先であるスイッチの空きポートにも依ります。


### 3. インターネットへの接続に関して
**CDMのver.9.0以降は、基本的にインターネット接続が必須となります。**
以前はRubrik筐体側での各種設定管理が主流でしたが、現在はRSCでの管理がほぼ必須となっています。
なので、**CDMクラスタからインターネットに抜ける経路の中で、FWやProxyがあれば、事前に通信を許可する設定を入れておく必要があります**。
※初期セットアップ時にRSCへ登録する必要があります。

記事の作成時点では、CDM クラスタからインターネット経由で以下へ接続する必要があります。
・accounts.google.com
・storage.googleapis.com
・www.googleapis.com
・oauth2.googleapis.com
・rubrik-support-download.s3.amazonaws.com
・xxx.my.rubrik.com　※これは割り当てられたRSCの接続先URLに依ります。
・1e100.net
・proxy.rubrik.com
・apollo-ingest.s3.amazonaws.com
・rubrikstats.s3.amazonaws.com
・apollo-ingest.s3.dualstack.us-east-1.amazonaws.com
・rubrikstats.s3.dualstack.us-east-1.amazonaws.com


### 4.初期構築時におけるNTP、DNSの設定
インターネットに出られる環境で初期セットアップを行う場合は、以下の設定値で初期セットアップをできるため、問題ありません。

NTP：time.google.com
DNS：8.8.8.8

インターネットに接続できない環境での初期セットアップが**厄介**です。

NTPに関しては、4ノードのうち任意の1ノードを時刻同期の参照先として指定する必要があります。
(たしかRubrikのkbに書いてたはず...)

DNSに関しては、「**接続するL2スイッチ側でIPv6のmDNS(マルチキャストDNS)機能を持っていること！**」が初期セットアップ時の条件になっていたはずです。
なのでリピーターハブ(バカハブ)では初期セットアップを完了できないことに注意が必要です。(僕はここで1度詰まったことがあります。)

### 権限に関して(Web UI SSH RSC)
特に気を付けるべき点はないですが、Rubrikのコンポーネントにログインする際は2種類のユーザがあります。
RSCとRubrik筐体側のログインユーザは別物と知っておけばよいと思います。

・RSCのログインユーザ
・SSHやWebコンソールのログインユーザ

それぞれにMFAを設定が必須のため、注意が必要です。

# さいごに
今回は構築時に検討が必要な箇所や事前準備が必要な箇所に関して記事を書いてみました。
vol.3ではさらに細かい仕様を書いていく予定です。
(vol.4では実際の構築の流れを書くかも...)

誰かの参考になれば幸いです。
それではまたどこかで。
ファミコンをつくりてぇんだPart3

どうも、GAIです。

この記事も第3回ですね。
そろそろなんでこんなことをやることになったか説明しないといけません。
あ、先に伝えておくと、アセンブラの解説は（ほぼ）お仕舞です。だって、難しいからね。
なんでかの詳しい理由は後で話します。

まず経緯からお話します。

始まりは、ファラオDAO。
ファラオDAOって何かというと、無駄は最高の贅沢をモットーにいろんな無駄なことをしていくDAOです。
DAOって何？っていうのは、説明しても説明しきれない上に正しく説明できる自信もないのでここではしないですが、とりあえず、無駄で楽しいことだけを追い求めて、いい歳こいた大人がはしゃいで楽しもうねっていう感じです。

そのファラオDAOのファウンダー（立ち上げた人）がSHOWGOさんというのですが、その人とWeb3界のなんかすごい人ことパジさんという方がですね。voicyというラジオアプリで音声配信をしてまして、そこで交換日記ならぬ交換音声で、なにか無駄なことを大がかりでやりたいね、ということをお話して、何をやろうかというのを募集したんです。

無駄なことに関しては理解度が高いと自負しているGAIなので、DAO設計士のtomyさんとやっているムダプラスの中で何をやりたいかお話したんです。
その中で、ファミコンソフトをつくるのいいんじゃね？というのがでましてね。

あらかじめ言っておくと、ほかにもあったんですよ。
僕らだけでなく、いろんな方がアイデアを出して、それをお二方のvoicyでなにがいいか、みたいな話を展開していて。
もちろん、GAIも無駄について本気で検討したうえで出したアイデアですし、実際今の時代にファミコンつくっている人もいることは知ってましたから、まあなんとかなるだろうと。

まあそのファミコンをつくろうっていうアイデアがですね、うまーく遊び心と無駄感とおじさんの子供心を刺激して、やろう、という感じになったわけです。

何故ファミコンなのかという話ですが、ファラオDAOでは「ファ」という音を大事にしていまして、ファミリーマートとか、ファーファとか。なので、ファミコンはぴったりマッチしているんです。
ゲームボーイでなくファミコンなのはそこが理由です。
もちろんそこだけではなく、どれだけ無駄か、という点も重要です。
なんせ今の時代のゲームは、カセットという媒体どころかDVDもありません。基本ほぼすべてインターネット上からダウンロードしてくるものです。
その時代において、本体が無いと遊べないカセット。しかも、ファミコン本体が無いといけない。
さらに、AVケーブルという歴史上の遺物を引っ張り出さないといけないし、それをつなげられるテレビも必要。
作るのにアセンブラという古代の言語を使用し、容量は脅威の最大512KB。
初期は40KBという容量。今だと画像１枚すら保存できません。
そのカセット１本を世の中に生み出すために開発環境を構築し、言語を習得し、カセットをつくり、基盤をつくり、データを焼きこみ、説明書をつくり、パッケージをつくりと、なんかいろいろやる。
その結果できるものがカセット１本。
これを無駄といわずしてなんといえばいいでしょうか。

AIが大躍進を遂げている令和の時代に、昭和のゲームの新作を出す。
ああ、よだれがでますね。
こんな無駄を求めていたのです。私は。（倒置法）

とまあ、経緯はこんなところです。

もちろん言い出しっぺのGAIがやらない、なんてことにはならないですし、無駄なことが大好きなGAIとしてもやらない理由はないということで、ファラオDAO内で、今後使うことは二度とないであろう技術を習得してまでファミコンを作りたい人はいるか？という条件で募集をし、数人の命知らずが集まったのでファミコンソフト制作を実行に移すことになった、ということです。

この記事の１，２を読んでいただいた方は、なんで急にこんなことを？と思った方もいるかもしれませんが、こういった理由です。

というわけで、これからこのファミコン製作をしていく上での日記というか、進捗とか技術的課題とか問題とか食べたいものとか、そういうことを記事として残していこうと思いますので、よろしくお願いします。

さて、先ほど書いたとおり、これからはアセンブラをメインで使って０からつくろう、なんて無謀なことをしているとガチで年単位でかかってしまうことが想定できたので、海外の有志がつくってくれた、ファミコンソフト作成ツール、『nes maker』を使っていきます。
ノーコード（ノーコードとは言ってない）の開発ツールで、アセンブラを手でうつより、はるかに開発しやすい環境です。

チュートリアルも充実しているので、これを活用すればきっとあっという間にファミコンソフトが作れると思います。
是非、ファラオDAOから出る最新作ファミコンソフトをご期待ください。

クラファンも実施していきます。
無駄なクラファン、無駄クラファンです。
「無駄遣い税」という、無駄なことをするためにお金を集めるぞ！という感じなので、無駄なこと大好き！という人と、「他人がファミコンつくって苦労している様を見るのはたまんねえぜ！じゅるり！」というドSな方はぜひご支援くださるとうれしいです。まあ、税金なので徴収するのは当然なんですけどね。

あと、これは伝えておかないといけないですね。
ファラオDAOに密入国したい人は、Xで「ファラオDAOに密入国したいです #ファラオDAO」ってつぶやけば、SHOWGOさんが見つけてくれます。
僕と一緒に無駄なことをしていきましょう。
これからよろしくお願いします。

GAI
AIに指示されるだけの人間になりたい

https://qiita.com/EasyCording/items/0a817ec1100041a6af78

やや前回の続きであるが・・・

# 内容
要するに毎日を考えながら、生きていくのが邪魔くさい
・将来のこと
・仕事のこと
・家族のこと
・家事のこと

いろいろ、毎日何かを考えて生きていくのが、やや辛くなってきた。

# あるべき姿
目標をセットしたら、ＡＩが全部のプロセスを考えてくれて、自分はひたすらＡＩに指示されて生きていきたい。

# 先ずはタスクから

一人暮らしなので、食事の買い出しで頭をひねるのが嫌になる。
だいだい生活なんてのは一度決めたことは、そんなに大きく変わらないし、やっていることも実に単調。
大した結果も無いのに、そもそも考えるのがバカらしくなってくる。
（世の中の専業主婦も、死ぬのを待っているだけの高齢者も、蓋を開ければそんな感じだと思う）

なので、ここを生成ＡＩで改善したい。

## 段階的導入とカスタマイズ
まずは特定の領域(例:食事)から導入し、徐々に他の領域(掃除、シフト管理、レジャーなど)に広げていきましょう。あなたの要望に合わせて、柔軟にカスタマイズできます。

こうした提案を実現すれば、日常生活の多くの決定や手続きをAIにゆだねられるようになり、あなたは気楽に生活に専念できるはずです。

同時に、重要な決定や精神的な部分はあなた自身が関与し続けられます。徐々にAIの関与を増やしつつ、バランスを取ることが肝心です。プライバシーなども細心の注意を払います。一緒に作り上げていきましょう。

# 提案内容

提案した手順をPlantUMLのシーケンス図で可視化します。


* ユーザーが初期設定としてパーソナルAIに生活パターン、好み、目標を入力する
* 日常的に、ユーザーの生活行動がスマートホームデバイスに記録され、AIに送信される
* AIはユーザーのデータとオープンデータを組み合わせて分析し、日課、買い物リスト、メニューなどを提案する
* ユーザーはAIの提案に対してフィードバックを返す
* AIはフィードバックを学習して提案を改善する
* 順次、ユーザーの要望に応じて新しい生活領域をAIに追加していく
* AIは提案の精度を高め、新機能を追加し、ユーザーの変化に適応していく


```plantuml
actor User
participant "パーソナルAI" as AI
participant "スマートホーム" as IoT
participant "オープンデータ" as OpenData

== 初期設定 ==
User -> AI: 生活パターン、好み、目標を入力
AI -> User: 初期設定を確認

== 日常生活 ==
loop 毎日
    User -> IoT: 生活行動をIoTデバイスに記録
    IoT -> AI: センサーデータを送信
    OpenData -> AI: オープンデータを収集
    AI -> User: 日課、買い物リスト、メニュー案を提案
    User -> AI: 提案に対するフィードバック

    AI -> AI: 提案を学習して改善
end

== 領域拡大 ==
User -> AI: 新しい生活領域を追加
AI -> User: 新領域の提案を開始

== 成長・変化 ==
note left
  - AIは提案の精度を高める
  - 新しい機能を追加
  - ユーザーの変化に合わせて適応
end note
```

# 質疑
>　パーソナルＡＩは、話しかけてくれて、ヒアリングしてくれるような会話ロボットにしてください

はい、分かりました。日記機能を持つ会話ロボットのイメージですね。そうすれば、ユーザーはロボットに日常の出来事を話すことで、自然な形でヒアリングされ、ロボットがユーザーの生活パターンや好みを学習できます。

会話ロボットの要件を以下のように定義できるでしょう。

## 機能要件

### 日記機能
* ユーザーが自由形式で1日の出来事を話すことができる
* 話された内容を日記としてテキストデータで記録する
* 音声入力に対応している

### 会話機能
* ユーザーの発言内容を適切に理解し、関連する質問や応答ができる
* 自然な会話の流れを維持する
* ユーモアや感情表現にも対応できる

### パターン分析・学習機能
* 蓄積された日記データからユーザーの生活パターン、嗜好、関心事項を分析する
* 分析結果を基に、レコメンデーションやリマインダーなどの機能を提供する

### マルチモーダルインターフェース
* 音声のほか、タッチスクリーンやジェスチャーなども入力に対応する

### アカウント管理・同期機能
* ユーザーごとにアカウントを作成し、データを管理する
* クラウドとの同期で、複数デバイス間でデータを共有できる

# GPTs
コアエンジンはやはり､GPTsに尽きる・・・
課題感は、パターン分析・学習機能　のところ　→　何故かと言うと、データ蓄積部分は外部に出さなくてはいけない
外部のオープンデータは、ＳＮＳやブログの自動スクレイピングにより、ベクトル化させて、最終的な人の情報として特徴化する必要かある。

>この場合は、ブロガーやＳＮＳのパーソンになるので、ある程度のプライベート情報にアクセスすることになる。
オープンデータの取得については、以下のようなアプローチが考えられます。

### 公開済みデータの活用
* 完全に公開済みのブログ記事やSNS投稿などを活用する
* スクレイピングではなく、APIやデータ公開サービスを利用する

### 匿名化・一般化されたデータの購入
* データプロバイダーから、匿名化・一般化された生活データセットを購入する
* 直接的な個人情報は含まれないが、生活パターンが参照可能

### オプトインによるデータ収集
ユーザーに同意を得た上で、ブログやSNSのデータを収集する
プライバシーポリシーと厳格な規約の下で実施する

### 連携サービスからのデータ取得
食事記録アプリや買い物リストアプリなど、連携可能なサービスから匿名データを取得する
プライバシーに配慮しつつ、十分なデータを確保するには、上記のようなマルチソースアプローチが現実的だと思われます。透明性の高い手法を採用し、ユーザーの理解と同意を得ることが何より重要でしょう。

また、収集したデータの分析と学習の際も、データの非可逆的な匿名化や、オンプレミスあるいは信頼できるクラウド環境でのデータ処理など、プライバシーを保護する対策が求められます。AIシステムの構築においては、機能の実現とプライバシー保護のバランスを常に意識する必要がありますね。


# こう考えると

世の中の家計簿アプリや、レシピアプリが実はバックで大量の個人データを扱っているのかもしれない。


# つづき

https://qiita.com/EasyCording/items/fceef0255168852a1b7a
統合テストのエラー解決

## 問題
統合テストを実行したら以下のエラーが生じた。
```
ERROR SiteLayoutTest#test_layout_links (0.22s)
Minitest::UnexpectedError:NoMethodError: undefined method `body' for nil:NilClass

response.body

^^^^^
test/integration/site_layout_test.rb:7:in `block in <class:SiteLayoutTest>'
```

`test/integration/site_layout_test.rb:7`が指摘されている。

```ruby:
require "test_helper"

class SiteLayoutTest < ActionDispatch::IntegrationTest

  test "layout links" do
    assert root_path
    assert_template 'articles/index' # ここでエラーが発生 
  end

end
```
articlesコントローラのindexアクションのビューを描画しようとしてエラーが出ている。

responseオブジェクトのbodyプロパティを呼び出そうとするとnilが返ってきている。

実際の画面ではindex.htmlが問題なく表示されているのに、なぜテストだとnilになるのか？


試しにエラーが出ている箇所だけコメントアウトして、`assert root_path`だけでもエラーが生じるか確認してみた。
その結果、`assert root_path`ではエラーが生じなかった。

~~このことから、`root_path`にHTTPリクエストを送るところでは問題が出ていないが、正しくビューが返されていないのが問題だとわかった。~~

## 原因
responseがnilになっている原因は？
→ そもそもHTTPリクエスト（GET）が送られていなかったから

## 試したこと
`/articles`にアクセスした場合はエラーにならなかった。どっちも同じ`articles#index`を指定しているのになんでだ？

```ruby
require "test_helper"

class SiteLayoutTest < ActionDispatch::IntegrationTest

  test "layout links" do
    get '/articles'
    assert_response :success
  end

end
```

```ruby
Rails.application.routes.draw do
  root "articles#index"
  get "/signup", to: "users#new"
  get "/login", to: "sessions#new"
  post "/login", to: "sessions#create"
  delete "/logout", to: "sessions#destroy"
  resources :users
  resources :articles
  get '/articles', to: 'articles#index'
end
```

## 解決した方法

```ruby
require "test_helper"

class SiteLayoutTest < ActionDispatch::IntegrationTest

  test "layout links" do
    assert root_path
    get root_path # これを追加
    assert_template 'articles/index'
  end

end
```

`assert root_path`はroot_pathが存在することを確認しているだけで、root_pathにリクエストを送っているわけではなかった。

`assert root_path`でリクエストを送ったつもりになっていた。`assert`をちゃんとわかっていなかったのが誤りの原因だった。

`get root_path`でGETリクエストを送ったら`response`にデータが入っていることが`binding.pry`で確認できた。
Claudeの賢さ検証

# はじめに
本日応用情報技術者試験を受験してきました。そこで午後の解答が気になったので速報を見ていましたが自分の解答が合っているのか（文章力が低いせい。。。）不安だったので、AIを使って確認してみました。（答えが長いので、今回は一問だけ出力を見てみたいと思います。）


画像を入力すると枚数制限がありちょっとイマイチなので、ある程度文章を入力&自分の言葉が合っているかを確認します。

# 情報セキュリティ設問1
```

Q: この中でfwによって防御できるものを教えてください。

ア：システム管理者による内部犯行

イ：パケットフィルタリングのポリシーで許可していない通信による内部ネットワークへの侵入

ウ：標的型メール攻撃での添付ファイル開封にっよる未知のマルウェア感染

エ：ルータの脆弱性を利用したインターネット接続の切断
```

正解はイだと思います。

以下出力結果
```
ファイアウォール(fw)は、ネットワークの境界線上で通信パケットを監視し、あらかじめ定義したポリシーに基づいてパケットの通過を許可または拒否する役割を果たします。

このため、fwによって防御できるものは以下の通りです。

イ: パケットフィルタリングのポリシーで許可していない通信による内部ネットワークへの侵入

fwのポリシーで許可されていない通信は遮断されます。
エ: ルータの脆弱性を利用したインターネット接続の切断

fwはルータの脆弱性を悪用した不正な通信を検知し、遮断することができます。
一方、以下は防御が困難です。

ア: システム管理者による内部犯行

内部からの不正行為はfwでは防げません。
ウ: 標的型メール攻撃での添付ファイル開封による未知のマルウェア感染

メールの添付ファイルの実行は、fwの機能外です。
総じて、fwは外部からの不正な通信を遮断する役割を果たしますが、内部の脅威や人的要因による危険に対しては別の対策が必要となります。
```

おお！！かなり賢そうですねえええ！！
React公式ページで学んでみた14（備忘録）

# はじめに
初めまして！
エンジニアになって数年、今まで本を読むだけでしたが、もっとプライベートで楽しみながら成長したい！自分が学んだ足跡を残していきたい！と思い記事を書きました！
最終的には自在に開発できるようになりたいと思っています。:triumph:
いろいろな記事を参考にさせてもらっています。:bow_tone2:
その中でもこれってどういう意味？とかつまづいたところを念入りに書いていこうかと思います。:fist:

# 今回の目的
前回の続きです。今回は「リデューサとコンテクストでスケールアップ」。被る部分もあると思いますが、後で振りかえって深掘りするきっかけになるのが理想です。細かく書くと大変なのであっさりめ。

https://qiita.com/mr_noppo/items/049fd3ad53f5356fc35c

# 使用したものや事前準備
・Macbook Pro
・Visual Studio Code

# 主に参考にさせていただいた記事
https://ja.react.dev/learn/scaling-up-with-reducer-and-context

# ReducerとContext
Reducerを使えばstate更新ロジックを集約することができ、Contextと組み合わせれば深い階層への情報連携が可能になる。

## Reducerによるバケツリレーの困難さ
stateでも言えることだが、stateやイベントハンドラ関数が増えて深い階層への受け渡しが発生するほど、製造の困難さが上がる。
回避策としては、contextを使う、カスタムフックを利用する手法が考えられる。

```react
export default function TaskApp() {
  const [tasks, dispatch] = useReducer(
    tasksReducer,
    initialTasks
  );
...
// トップレベルでのpropsの受け渡しのみならいいが、孫にまで伝播するとpropsの数が増える
<TaskList
tasks={tasks}
onChangeTask={handleChangeTask}
onDeleteTask={handleDeleteTask}
/>
```

# ReducerとContextを組み合わせる方法
手順は下記の通り
1.コンテクストを作成する。
2.state と dispatch をコンテクストに入れる。
3.ツリー内の任意の場所でコンテクストを使用する。

## コンテクストを作成する
Reducerのtasksとdispatch関数をcontextで定義する
```react
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
```
別ファイルでcontextを定義する。
```react
import { createContext } from 'react';

export const TasksContext = createContext(null);
export const TasksDispatchContext = createContext(null);
```

## state と dispatch をコンテクストに入れる
最上階のコンポーネントでcontextをインポートして初期化し、providerを設定
```react
import { TasksContext, TasksDispatchContext } from './TasksContext.js';

export default function TaskApp() {
  const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
  // ...
  return (
    <TasksContext.Provider value={tasks}>
      <TasksDispatchContext.Provider value={dispatch}>
```

さらに上記の部分をcontextを定義したファイルで設定し、childrenをラップするコンポーネントを作成することで処理を簡潔に記述できる
```react
export function TasksProvider({ children }) {
  const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);

  return (
    <TasksContext.Provider value={tasks}>
      <TasksDispatchContext.Provider value={dispatch}>
        {children}
      </TasksDispatchContext.Provider>
    </TasksContext.Provider>
  );
}
```
他にもcontextを定義したファイルに読み込みのためのuseContextを記述しエクスポートすることで関連ある操作などをまとめることができる
```react
export function useTasks() {
  return useContext(TasksContext);
}

export function useTasksDispatch() {
  return useContext(TasksDispatchContext);
}
```

## ツリー内の任意の場所でコンテクストを使う
下記の通りpropsが不要になる。
読み込み
```react
export default function TaskList() {
  const tasks = useContext(TasksContext);
```

更新
```react
export default function AddTask() {
  const [text, setText] = useState('');
  const dispatch = useContext(TasksDispatchContext);
  // ...
  return (
    // ...
    <button onClick={() => {
      setText('');
      dispatch({
        type: 'added',
        id: nextId++,
        text: text,
      });
    }}>Add</button>
```

## 最後に
ツリー内で管理したいstate群にはとても有効だと思いました。

# 次
https://qiita.com/mr_noppo/items/50ad5175fc3882b9d704
コマンドプロンプトで開く 「ユーザー名とパスワードが必要な共有フォルダ」編

## 経緯
所属先のプロジェクトにて「共有フォルダ」(クラウドではありません)でドキュメントなどの管理をしており、出社後に即バッチ起動できないかと思い試したことを備忘のため記載しました。

## コマンドサンプル
「net use フォルダのパス名 /user:ユーザー名 パスワード」がポイント

```@echo off
set folderPath_1=フォルダのパス
net use %folderPath_1% /user:ユーザー名 パスワード
start %folderPath_1%
[Python/Jupyter]venv仮想環境の操作等(自分用)

## 仮想環境の操作
起動する
```
cd C:\Users\sakur\Documents\env_py

.\*******\Scripts\activate

pip list

pip install *******
```
閉じる
```
deactivate
```
追加
```
python -m venv *****
```

## Jupyterのカーネル操作
追加する
```
ipython kernel install --user --name=******
```
削除する
```
jupyter kernelspec uninstall ****
```
一覧の出力
```
jupyter kernelspec list
```

Jupyter Lab のインストール
```
pip install jupyterlab
```

ipykernel のインストール
```
pip install ipykernel
```
Azure前提知識（クラウドの登場で変わったこと）

# データセンターからクラウドへ
これまでー＞データセンターでサーバースペースを借りて管理
電気代、場所代等使用料がかかる。

今ー＞大企業が自社データセンターに大量のサーバーを置いてサブスクのように貸し出している

クラウドー＞サーバー環境をサブスクで借りるみたいな感じ
オンプレミスー＞物理サーバー

イメージはカーシェアのようなもの




引用：
https://az-start.com/cloud-vs-onpremise-usage-pattern/
firebase deploy したのにwelcome画面(Firebase Hosting Setup Complete)が表示する

## はじめに

こんにちは！[@nyakako13](https://qiita.com/nyakako13 "Qiita ページ") です。

Reactアプリをfirebaseにデプロイする過程で困ったので対処法をまとめます。


## 問題
```shell
$ firebase deploy
```
して、Hosting URLにアクセスすると・・・

![スクリーンショット 2024-04-21 18.54.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2539365/7ba74df6-54ec-7fe5-6a6a-b07c9e84f765.png)

welcomeて！！！

作ったアプリは一体どこに？？

## 解決方法
```shell
$ firebase init
```

の後の質問事項で、public directoryに"dist"を選択して、

再度

```shell
$ firebase deploy
```
することで改善しました。


## 原因
firebase init の後の質問に罠がいくつかあります。

![スクリーンショット 2024-04-21 19.11.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2539365/67cb8269-88ec-d6c0-5b2b-fa6bc415a479.png)


### ①public directoryの罠

公開ルート ディレクトリのデフォルトはpublicなので
深く考えずにそのまま選択してました。

<br>

ただ今回は

```shell
$ npm run build
```

でbuildしたので、デプロイしたいファイルはdistディレクトリにありました。

公開したいファイルがある場所を指定しておかないともちろんアプリは表示しません。

これはしょうがない。

<br>

ちなみにfirabase initを一度した後だったら
init時に作成される、firebase.jsonで後から変更もできました。

```json:firebase.json
{
  "hosting": {
    "public": "dist",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}
```

### ③Overwrite?の罠
①で指定したディレクトリにindex.htmlがあると上書きするかと最後に聞いてきます。

ここはNです！

yを選ぶとwelcomeページのindex.htmlに上書きされます。（index.htmlを何で上書きするのかちゃんと教えてほしい・・・）

<br>

firebase init の後にbuildするなら、
そもそも上書きしないので問題ないですが、

今回はbuildした後に、
(再設定のため)さらに firebase init した時にindex.htmlを上書きしてしまったので
公開ディレクトリをdistにしたのにまたwelcomeページが！？となりました。



## 感想
2重の罠で少し混乱しましたが、それでもfirebaseのデプロイ楽すぎるー！

ターミナルの英語の選択肢も今後はちゃんと読んでから選びます！！


## おわりに
よかったら[X(@nyakako13)](https://twitter.com/nyakako13 "Xプロフィール")もフォローしてもらえると嬉しいです。

[Qiita100投稿](https://qiita.com/nyakako13/items/03ad61cfb82a1582b5d1)まで残り95！

未経験や浅経験、厳しいと言われている年代でエンジニアへの転職活動されている方、負けずにがんばりましょう！！

## 参考
https://firebase.google.com/docs/hosting/quickstart?hl=ja

https://maitakeramen.hatenablog.com/entry/2019/04/15/180416
raspberry pi3 で、コマンド入力なしで電源ぶちっ

![shutdown.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166811/77713570-9a0f-4386-5886-674df437abda.jpeg)
# 目的
Raspberry pi3 を家のステレオとして使っているけど、いちいちログインしないで電源を切りたい！！
（自分以外の家族にも使って欲しくて、、、）

# どうやって切る？
GPIOの2つのpinにタクトスイッチをつけて、1秒間長押しして、少し待ったら、、、、

電源ON時、赤のledが常にheartbeat( どどっ、どどっ、どどっ、どどっ、）で光りますが、少し待ったら、常時点灯に変わります。そして、緑のアクセスランプが完全に消灯したら、電源ぶちっ。

# 設定方法

/boot/config.txt の中に

~~~vim:/boot/config.txt
dtoverlay=gpio-shutdown,debounce=1000
dtparam=pwr_led_trigger=heartbeat
~~~

を入れる。

raspberry piの挙動を起動時に設定するしくみとして、/boot/config.txt での設定ができますが、色々な設定についての説明は、[/boot/overlays/README](https://www.google.com/url?[sa=t&source=web&rct=j&opi=89978449&url=https://github.com/raspberrypi/firmware/blob/master/boot/overlays/README&ved=2ahUKEwjrga2QhtiFAxVjk1YBHXujA1AQFnoECA4QAQ&usg=AOvVaw1EZGXBpmI5UCEOsGpHPiVl)に色々書いてありますね。

## スイッチでshutdown
dtoverlay に gpio-shutdown を指定すると、GPIOピンの状態の変化でshutwown 処理を始めます。デフォルトでは、GPIO 3を 100mmsec(0.1秒間)、0vにすることで、shutdown処理が始まります。今回の設定では、debounce=1000としており、1秒間0vにすることで、shutdown処理が始まります。つまり、私の構成では、１秒間タクトスイッチを押すことで、shutdown処理が始まります。

### 配線
GPIO3と、gndの2本の間にスイッチをいれてつなぎます。スイッチが切れた状態の時は、GPIO3は、プルアップされていて、3v(?)になっていますが、スイッチをつなぐと、gndにつながるので0vになります。

私は、タクトスイッチとケーブルをとってもいい加減につないでいるので、タクトスイッチが時々外れます。恥ずかしいかぎりです。せめてハンダでスイッチ外れないようにしないとね。

## 赤ledの挙動変更
赤ledは、通常、常時点灯ですが、shutdown処理が行われたかどうかの判断が良く分かるように、上記のようにheartbeatに設定します。赤ledは、pwr_ledなんですね。

### (^_^;)
※写真のシステム、埃っぽくて、すみません。一杯ホコリかぶっていて、これでも少し掃除しました。
Vercel FunctionsでGoのAPIサーバをデプロイする！

# はじめに
こんにちは、H×Hのセンリツ大好きエンジニアです。（同担OKです😉）

今回は、運用にお金を使いたくない人向けの味方「Vercel Functions」にステートレスなGoのAPIサーバをデプロイする方法をまとめました。

前提として、Vercel Functionsのデプロイに向いているものは以下の条件にクリアしたものになると思います😇
- ステートレス（セッション管理などをしない）
- 小規模なAPIサーバ
- 一回のデータ取得に時間が掛からない

# セットアップ
1. Vercelのアカウント登録
1. Vercel CLIのインストール
    - npmの場合、`npm i -g vercel`
3. Vercelにログイン
``` npm
vercel login
```

# APIエンドポイント作成
### ディレクトリ構成
これを元に、ご自身で構成を変えていただければと思います🫣
```
.
├── api # エンドポイント用
│   ├── articles # APIの例
│   │   └── index.go
│   └── index.go # 接続確認用
├── APIエンドポイントから実行される関数
│   ├── 様々
│   └── 色々
├── go.mod
├── go.sum
└── vercel.json # 設定ファイル
```

### APIエンドポイント
まずは、Vercel Functionsが正しく動作するかの確認用に、`/api/index.go`を作成します。
``` api/index.go
package api

import (
	"fmt"
	"net/http"
)

func Handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "<h1>Hello Vercel Functions!</h1>")
}
```

そして、各種エンドポイントを作成します。
動かす関数は用意しておいてください。

今回は、ルーティングと同じようにディレクトリを分けてます🥹

``` api/article/index.go
package articles

import (
	"net/http"
)

func Handler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodGet:
		ArticlesPerPage(w, r) // 実行する関数はあらかじめ用意しておく
	default:
		w.WriteHeader(http.StatusMethodNotAllowed)
	}
}

```

### 設定ファイル作成
基本的に、デプロイするディレクトリのルートに設置します。
``` vercel.json
{
  "build": {
    "env": {
      "GO_BUILD_FLAGS": "-ldflags '-s -w'"
    }
  },
  "rewrites": [
    { "source": "/api", "destination": "/api" },
    { "source": "/api/articles", "destination": "/api/articles" }
  ],
  "headers": [
    {
      "source": "/api/(.*)",
      "headers": [
        { "key": "Access-Control-Allow-Origin", "value": "CORSを許可するURLを載せる" },
        { "key": "Access-Control-Allow-Methods", "value": "GET, OPTIONS" },
        { "key": "Access-Control-Allow-Headers", "value": "Content-Type, Authorization" }
      ]
    }
  ]
}
```

ここで注意して欲しいのですが、リファレンスにある`routes`は既に非推奨なので、`rewrites`を使用してルーティングを行います。🤯
(クエリパラメータを受け取るエンドポイントでも、特に意識せず上記のようにパスだけルーティングしても大丈夫です)

また、このAPIサーバのCORS設定は`headers`で設定します。
（`headers`を使用しないとCORSエラーになるので要注意！）

# デプロイ
本番環境にデプロイをする場合、以下のコマンドを入力します。
```
vercel --prod
```

`Error: queryA EREFUSED api.vercel.com`が発生する場合、DNS設定を見直したり、接続しているWi-Fiを変更してみてください。

デプロイ後、アクセスすると正しい挙動になっているか確認します。
`api/articles`を入力してみます。
![スクリーンショット 2024-04-21 12.46.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653241/0a981534-91d8-5256-ef2c-ce102904ee25.png)

きちんと返ってきました。。。嬉しすぎて言葉が出ません。。。😮

### 注意点
POSTメソッドを行う場合、ブラウザによるCORSポリシーの一環であるプリフライトリクエスト（OPTIONSメソッド）が送信されてしまいます🥶

そのため、以下のように適切なCORSヘッダーを返すことで、POSTリクエストが正しく行われるようにします。

``` index.go
package articles

import (
	"net/http"
)

func Handler(w http.ResponseWriter, r *http.Request) {
	// OPTIONSリクエストへの対応
	if r.Method == http.MethodOptions {
		w.WriteHeader(http.StatusOK)
		return
	}

	switch r.Method {
	case http.MethodPost:
        // 何かしらのPOSTメソッド関数
	default:
		w.WriteHeader(http.StatusMethodNotAllowed)
	}
}

```

# おわりに
今回は、節約したいエンジニアにとって素晴らしいツールである、Vercel Functionsの使用法を紹介しました。🥸

ですが、無料枠だと一回の関数が10秒以内に完了しないと`time out`エラーになってしまうので、使用前に関数を分解する or 別のデプロイ先（AWS Lambdaなど）を検討する方が良いかと思います🥹
【画像あり】AppIconの表示数を変更

# AppIconの表示数の変更の仕方
①Assetsを開く

![スクリーンショット 2024-04-21 19.50.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760972/1ffc5170-fb8d-469e-5b33-6f958230f741.png)

②AppIconを開く

![スクリーンショット 2024-04-21 19.50.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760972/da1cc053-9a1d-9dd0-6fbd-e01d9fc745a1.png)

③右側の欄（インスペクタ）を開く

![スクリーンショット 2024-04-21 19.51.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760972/3d4d0eae-908b-3821-977c-1675408ab030.png)

④IOS or macOS or watchOS 任意のタブ→ALL Sizesに変更
備忘録(Python)

# 辞書型を１つの文字列として返す関数
~~~screen_dict.py
def screen_menu(dict):
  txt = ""
  for key,value in dict.items():
    txt +=value+" : "+str(key)+"\n"
  return txt
  ~~~
# これをtkinterのtextに利用！
tkinterのlabelのテキストに辞書型を入れたかったから作った。
~~~
import tkinter as tk
import tkinter.messagebox as tmsg

def screen_menu(menu):
  txt = ""
  for key,value in menu.items():
    txt +=key+" : "+str(value)+"\n"
  return txt

main = {"ラーメン":600,"餃子":400,"チャーハン":500}
root = tk.Tk()
root.geometry = ("800x400+500+300")
root.title("ラーメン屋")
screen_b = tk.Frame(root,width=800,height=600)


label_b = tk.Label(screen_b,text = "メニュー")
label_b.pack()

label_b_2 = tk.Label(screen_b,text=screen_menu(main),font=("Times",12))
label_b_2.pack()
screen_b.pack()

root.mainloop()

 
~~~

実行すると

![スクリーンショット 2024-04-21 195325.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724119/026562be-f7fb-3e1a-065e-19620b693602.png)

こんな感じ^^
WSLを使ってWindowsに適したRicty Nerdフォントを作る

## いろんなソースコード向けフォントが出ても

シェルスクリプトの作者が前時代的とおっしゃっていても、Rictyで育ってきた私はやはりRictyがよろしいと思ってしまうのです。

## RictyにNerdフォントをぶっ込められる

との情報を目にしたのでやってみた所存であります。

## どうすれば…？

まずWSL上でアプリを入れます。Pengwinなのでaptです。

``` sudo apt install fontforge python-fontforge fonttools ```

Rictyを作る環境(フォルダ)を作り、そのフォルダで

``` git clone --depth=1 https://github.com/ryanoasis/nerd-fonts.git ```

なんか重いなーと思ってましたが10GB以上あるリポジトリなのでそら重い。

``` git clone https://github.com/powerline/fontpatcher ```

参考にしたサイトが落としてたので、PowerLineのフォントパッチも落としました。これはNerdフォントに含まれているっぽいからいらないかもしれない。

で、以下のシェルスクリプトを実行します。正規表現がよく分からないので後半はぐだぐだになっていますが、これでとにかく出来上がったフォントにWindows向け修正を行っています。Rictyスクリプトの配布元のOS2なんとかというシェルは効きませんでした。全角スペースの可視化はあんまり好きじゃないので、Ricty生成スクリプトには-zのオプションを入れています。

何周かしましたが1周結構長いです。走らせたら飯食うのもいいかもしれません。

``` sh
rm -f Ricty*.ttf Ricty*.ttx Ricty*.ttx.bak
sh ricty_generator.sh -z auto
if [ -f "fontpatcher/scripts/powerline-fontpatcher" ]; then
  for R in Ricty*.ttf; do
    python3 fontpatcher/scripts/powerline-fontpatcher "$R"
  done
fi
if [ -f "nerd-fonts/font-patcher" ]; then
  for R in Ricty*.ttf; do
    python3 nerd-fonts/font-patcher --complete "$R"
  done
fi
for P in Ricty*Nerd*.ttf; do
  ttx -t OS/2 "$P"
  sed -i.bak -e 's,xAvgCharWidth value="967",xAvgCharWidth value="500",' "${P%%.ttf}.ttx"
  mv "$P" "${P%%.ttf}.orig.ttf"
  ttx -m "${P%%.ttf}.orig.ttf" "${P%%.ttf}.ttx"
done
for P in Ricty-*.ttf; do
  ttx -t OS/2 "$P"
  sed -i.bak -e 's,xAvgCharWidth value="940",xAvgCharWidth value="500",' "${P%%.ttf}.ttx"
  mv "$P" "${P%%.ttf}.orig.ttf"
  ttx -m "${P%%.ttf}.orig.ttf" "${P%%.ttf}.ttx"
done
for P in RictyDiscord-*.ttf; do
  ttx -t OS/2 "$P"
  sed -i.bak -e 's,xAvgCharWidth value="940",xAvgCharWidth value="500",' "${P%%.ttf}.ttx"
  mv "$P" "${P%%.ttf}.orig.ttf"
  ttx -m "${P%%.ttf}.orig.ttf" "${P%%.ttf}.ttx"
done
for P in Ricty*Powerline*.ttf; do
  ttx -t OS/2 "$P"
  sed -i.bak -e 's,xAvgCharWidth value="940",xAvgCharWidth value="500",' "${P%%.ttf}.ttx"
  mv "$P" "${P%%.ttf}.orig.ttf"
  ttx -m "${P%%.ttf}.orig.ttf" "${P%%.ttf}.ttx"
done
```
で、出来上がったフォントを見ます！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145502/1b729fea-7398-1cff-2929-5cbdf45f86f5.png)

多分良さげ！インストール！おしまい！

## 難しかったところ

Nerdフォントを入れると、修正するCharWidthが変わってた所が見つけるのに苦労した。ずっと間隔が広いままだった。なんでWindowsだけフォント周りこんなにめんどくさいんですかね…。

## 参考

https://qiita.com/mura1008/items/5699b41e2deaa6ddb8f1

https://shinespark.hatenablog.com/entry/2022/03/28/090000
Railsのテストで、Could not find tableエラーを解決する方法



# 概要

Railsのテストを実行した際に、Could not find table というエラーが起きる場合があります。

本記事では、このエラーがなぜ起きるのか、どう解決するのかを解説します。

# この記事で伝えたいこと

- Could not find tableのエラーが起きる理由
- Could not find tablエラーを解決する方法

# 実行したテスト

ユーザインスタンスを作成し、ユーザが有効かどうか検証する。

```ruby
class UserTest < ActiveSupport::TestCase

# 事前に、ユーザインスタンスに名前等の各値を設定する
# setupメソッドは、テスト実行時に自動で実行される
  def setup
    @user = User.new(name: "Emi", email: "emi@a.com", password: "fooooo", password_confirmation: "fooooo")
  end

  test "should be valid" do 
    assert @user.valid?
  end 
...
end
```

# 発生したエラー

テスト実行時に、テーブルが存在しないというエラーが発生します。

下記の`ActiveRecord::StatementInvalid` とは、ActiveRecord（モデル）がデータベースにクエリ（命令）を実行した際に発生するエラーです。

```ruby
Error:
UserTest#test_should_be_valid:
ActiveRecord::StatementInvalid: Could not find table 'tag_relations'
``` 
:::note info
ActiveRecordとは
ビジネスデータ（データベースに保存される顧客情報等のデータ）と、ビジネスロジック（データをどう操作するかが書かれた処理）を操作する役割。
簡単に言うと、Modelとデータベースのやり取りがスムーズになるように、仲介する役割。
:::

# エラーが起きる原因

`test_helper.rb`でフィクスチャファイルを読み込む設定になっているのに、フィクスチャファイルで適切な設定がされていません。

以下の、 `fixtures :all` で、全てのフィクスチャファイルを読み込む設定になっています。

```
# test_helper.rb
module ActiveSupport
  class TestCase
	  ...
    # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
    
    fixtures :all
		...
  end
end
```

:::note info
test_helper.rbとは

テスト全体で使用したい設定を保存するファイル。
:::

::: note info
フィクスチャファイルとは

- テストデータベース用のサンプルデータのことで。
- フィクスチャを使用すると、事前に定義したデータを、テスト実行直前にテストデータベースに導入できます。
:::
# エラーを解決する方法

## 解決方法の種類

エラーを解決する方法として、以下の３つがあります。
今回のテストではデータベース内のデータが必要ないため、**２のフィクスチャを無効化する方法を行います。**

### １．フィクスチャを設定する

事前にデータベースにデータが必要な場合(データの永続化が必要な場合)は、フィクスチャを使用。

### ２. フィクスチャを無効化する

データベースにデータが必要ない場合は、フィクスチャを無効化する。

### ３． FactoryBotを使用する

複数のモデルで関連づけや、attribute(型の変換や、デフォルト値を設定)が異なるデータを多く作成する場合に使用。

フィクスチャを使用すべきかの判断は、下記のサイトが参考になります。

[Rails Fixtures再考](https://speakerdeck.com/mstshiwasaki/rails-fixtureszai-kao?slide=33)

## フィクスチャ無効化の方法

test_helper.rbをコメントアウトする。
フィクスチャの使用を無効化すると、フィクスチャのテストが通るようになります。

```python
# test_helper.rb
module ActiveSupport
  class TestCase
	  ...
    # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
    
    #fixtures :all
		...
  end
end
```

## フィクスチャ無効化のデメリット

テスト実行時にデータベースにデータが必要な場合は、フィクスチャやFactoryBotを使用する必要があります。
【Unity】いまさらColliderのisTriggerを結合して判定する方法を知ったのでメモ

# Composite Colliderについて

UnityにはComposite Colliderという仕組みがあります。
これはRigidbodyの下（自身と子オブジェクト）にColliderが複数ある時、Colliderを一つにまとめて処理してくれるというものです。

参考
[【Unity】複数のColliderを結合するComposite Collider 2Dを使って少し遊ぶ](https://tsubakit1.hateblo.jp/entry/2017/02/22/230100)

子にRigidBodyがついていれば、それ以下の階層がさらにグループとして扱われる仕様のようです。
物理挙動で言えばそれだけなのですが、OnTriggerEnterなどのイベントについてはかなりわかりにくく、今更ながら混乱してしまいました。

要はプリミティブ形状のColliderを組み合わせて1つで判定したいのに、何度もイベントが呼ばれるうえ間引くことが非常に難しいという問題にぶつかりました。

# 方法

isTriggerでも同様にRigidBody(isKinematic)をアタッチしてグループ化し、相手のRigidBodyがほしいなら`Collider.attachedRigidbody`で取得する。

これだけでした。
つまり
・GameObjectA（RigidBody isKinematic）（EventScript）
　・ChildA_1（Collider isTrigger）
　・ChildA_2（Collider isTrigger）
　・ChildA_3（RigidBody isKinematic）（EventScript）
　　・ChildA_3_1（Collider isTrigger）
　　・ChildA_3_2（Collider isTrigger）

  のような感じです。
  
  Child1にほかのCollider（例：ChildB_1）が衝突すると、GameObjectAのEventScriptのOnTriggerEnterが呼び出されます。
  ここでOnTriggerEnterの引数でわたってくるColliderはChildB_1のColliderですが、実際は大枠のGameObjectAとGameObjectBの衝突を見たいはずです。

  そのようなときは`Collider.attachedRigidbody`で相手側のRigidBodyが取得できるようです。

```
		private void OnTriggerEnter(Collider other)
		{
			var triggerGroupParent = other.attachedRigidbody;
			if (triggerGroupParent == null)
			{
				return;
			}

			Debug.Log(triggerGroupParent.name);
		}
```

# 結論
つまりはそういうことです。