OmniAICreator/Qiita-1.07M huggingface dataset:
【ServiceNow】Utah新機能「トピック ページの新しいコンテンツを追跡する」


ServiceNowの新バージョンであるUtahが正式にリリースされました。
Employee Centerの新機能である「トピック ページの新しいコンテンツを追跡する」を使用してみた結果をまとめました。

https://docs.servicenow.com/ja-JP/bundle/utah-employee-service-management/page/product/employee-center/concept/track-new-content.html

簡単に言うと、<strong>コンテンツを新規で作成すると、スケジュールジョブで自動的にトピックページに紐づけしてくれる</strong>。という機能です。

トピック ページとは
---
トピックページとは、以下の画面です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335478/26a16cbd-066f-2448-92dc-67dff583f042.png)
通常メニューにてカテゴリをトピックと紐づけることで、カテゴリの中のカタログアイテムが、Employee Centerに表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335478/a09b95fc-3159-f513-f427-95c0d100a92b.png)


事前準備
---
taxonomy_adminロールが必要です。
プラグインのインストールは不要です。

スケジュールジョブを利用して、トピックページに新しいコンテンツを追加する
---
スケジュールジョブを使用して、トピックページに追加できる新しいコンテンツの紐づけが定期的に実施されるようにします。

<strong>１．アプリケーションメニューより、All > System Definition > Scheduled Jobsを開いて検索</strong>
　Name：Surface New Unconnected Content of Categories
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335478/4d831f20-1677-278f-b67c-2f2137602518.png)
<strong>２．スケジュールジョブの設定</strong>
Time:任意の時間
Run this script：そのままでも良いですが、下記画像のように「gs.log("スケジュールジョブ");」を入れておくと後にシステムログ上で確認ができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335478/57f2f953-dc50-bd39-5e7d-90385bdf92e6.png)

<strong>３．カタログアイテム新規作成</strong>
該当のトピックページ（All > Content Taxonomy > Topics）を開き、関連リスト「Catalog and knowledge categories」に紐づけられているカテゴリのカタログアイテムを新規で作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335478/e4e0e103-ab35-0cdc-f8ce-41fa99bf39c4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335478/9474f1bb-9a5c-daff-e37c-9238617ac3b4.png)
<strong>４．スケジュールジョブの実行</strong>
スケジュールジョブが実行されると、トピックページの上部にポップアップが表示されます。
同時に、関連リスト「Catalog and knowledge categories」の「Available content for association」の数に、新規作成したアイテムの数が表示され、コンテンツがトピックページに紐づけられます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335478/370e7628-3264-f23e-bf9f-bcf6677d89fe.png)
<strong>５．画面表示</strong>
Employee Centerにアイテムを表示させるため、関連リンク「Check for new content in categories」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335478/08695222-06c1-b3b3-70cf-f93fc1fe4cfa.png)
追加するアイテムの行にチェックを入れ、「Add content to topic」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335478/9a2d241c-a45b-dfe3-cb4c-df1835c78146.png)
<strong>６．動作確認</strong>
Employee Centerのトピックページにアイテムが追加されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335478/15be305d-ed69-57f2-c49a-87aeefc414a7.png)

おわりに
---
ポータル画面にEmployee Centerを採用されている方は大いに利用する機能だと思います。
また、現在は採用していないという方も、ServiceNowとしてはEmployee Centerの利用が推奨されているので、是非試してみても良いかと思います。
Djangoでcookieを使うJWTレスポンスのテストコードの書き方

# Djangoでcookieを使うJWTレスポンスのテストコードの書き方
### ポイント
・JWTレスポンスのテストはunittestでやります。
・SimpleCookieでtokenをジェネレーターする

```python:test.py
import pytest
import uuid

from unittest import mock
from django.http import HttpResponse
from django.test import TestCase
from http.cookies import SimpleCookie

from rest_framework.test import APIRequestFactory
from rest_framework import status

from . import AuthMiddleware

def user_login():
    factory = APIRequestFactory()
    url = "http://127.0.0.1:8000/login"
    post_data = {
        "email": "unit@test.com",
        "password": "test"
    }
    request = factory.post(url, data=post_data)
    response = login(request)
    return response

@pytest.mark.django_db
class MiddlewareTest(TestCase):
    """
    JWTテスト
    """
    def setUp(self):
        # tokenをバリデートするミドルウェアをイニシャル
        self.mock_init = mock.patch.object(
            AuthMiddleware, "__init__", fake_init
        ).start()

        self.addCleanup(mock.patch.stopall)

    def test_JWTテスト_成功_200(self):
        # get token
        # 前に作成されたuser_loginフンクションでtokenを取得する
        response = user_login()
        token = response.cookies.get('jwt_cookie').value

        # create URL
        id = str(uuid.uuid4())
        url = "http://127.0.0.1:8000/users" + "/" + id

        # call API
        # modify token for NOT pass the token authorization
        self.client.cookies = SimpleCookie({'jwt_cookie': token})
        # getメソッドを呼び出し、tokenバリデーションが成功になったら200を返します
        # 自動的にAuthMiddleware(ミドルウェア)でtokenをバリデーションする
        response = self.client.get(url, content_type='application/json')

        # check is the response is correct
        assert(response.status_code == status.HTTP_200_OK)
```
【Road to Cassandra Day】CassandraをリアルタイムAIに活用するには〜導入編:フィーチャー（特徴量）ストアとは何か？

# はじめに

## Cassandra Day Tokyo

今年、2023年６月１日に、[Cassandra Day](https://www.datastax.com/events/cassandra-day-japan)が日本でも開催されます。
Cassandra Dayは、昨年、ベルリン、ロンドン、アムステルダム、ハノイ、ジャカルタ、ヒューストン、サンタクララ、シアトル、シンガポールでも開催されました。

今回の東京での開催に向けて、Apache Cassandraに関する記事を発表していきます。

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/6a879803-d135-348b-f815-08be011607fa.png)](https://www.datastax.com/events/cassandra-day-japan)

## Apache Cassandraについて

Apache Cassandraとは、一言でいうなら、オープンソースの分散データベース管理システムです。

他の分散データベース管理システム同様、複数の汎用サーバーを用いて、ひとつのデータベースを構築します（開発などの目的のため、一つのサーバーのみで構成することも可能です）。

ここでは、詳しい説明は割愛し、興味のある方へのご紹介の役割は、公式サイトやWikipediaに譲ります。

https://cassandra.apache.org/_/index.html

https://en.wikipedia.org/wiki/Apache_Cassandra


# CassandraとAI

## この記事のソース

本稿では元Google Quantum AIのAlan Ho氏の下記の記事「Cassandra をリアルタイムフィーチャー（特徴量）ストアとして使用するための実践者向けガイド(Practitioner’s guide for using Cassandra as a real-time feature store)」から、導入の情報をお伝えします。

この記事自体は、「リアルタイムフィーチャー（特徴量）ストアとして使用するためのベストプラクティスについて説明」しています。ここでは、How（ベストプラクティス）ではなく、なぜそれが重要かをお伝えしたいと思います。

https://planetcassandra.org/post/practitioners-guide-for-using-cassandra-as-a-real-time-feature-store/

## リアルタイムAIとは何か？

リアルタイム AI では、現在発生しているイベントに基づいてモデルを推論またはトレーニングします。

従来、モデルのトレーニングとモデルに基づく推論 (予測) は、通常は夜間に、または 1 日を通じて定期的にバッチで行われてきました。
現在、最新の機械学習システムは、可能な限り正確な予測を提供するために、最新のデータを用いて推論を実行するようになってきています。
TikTok や Google のような少数の先進的な企業は、オンザフライでのモデルトレーニングを組み込むことで、リアルタイム パラダイムをさらに推し進めています。

このような変化を前にして、特徴量データ (ML モデルのトレーニングと推論の実行に使用されるデータ) の扱い（具体的には、永続化層としてのデータベース）についても、適応の必要が発生しています。


## フィーチャー（特徴量）ストアとは何か?

フィーチャー（特徴量）ストアは、機械学習 (ML) に固有の次のような機能を持つデータシステムです。

 - 生データを特徴量に変換するデータパイプラインを実行する
 - 特徴量データを保存および管理する
 - トレーニングと推論の目的のために特徴量データを一貫提供する

以下にフィーチャーストアのライフサイクルを示します。 (ブログ「What is a Feature Store」から引用)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/035be5e9-ab94-aac6-58a0-24d7c543b7f9.png)


https://feast.dev/blog/what-is-a-feature-store/




また、以下はフィーチャーストアの主要コンポーネント (同上のブログから引用)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/5470bd21-dd0e-6093-1665-06de10205cb6.png)

## Cassandraとフィーチャー（特徴量）ストア

リアルタイム AI は、特にモデルの提供とモデルのトレーニングのための特徴量データの扱いに関して、永続層であるデータベースには、一定の（性能等）要件が課されます。

Cassandraは、こうした要件を満たすデータベースとして用いられています。

## 具体例としてのUberでの採用例

上記で紹介したブログ記事では、性能要件の数値にまで踏み込んで、ベストプラクティスが紹介されています。

この記事では、実際の採用例として、Uber社の例を紹介することで、現在のリアルタイムAIとフィーチャーストアをめぐる状況について、注目を喚起することで稿を終えたいと思います。

下記は、Uber社のエンジニアリングブログで紹介されているシステムの全体像です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/26f0791c-a8fd-38f7-fd33-289dd01c6c05.png)

詳細については、ブログ本文に譲ります。

https://www.uber.com/en-JP/blog/michelangelo-machine-learning-platform/


## 最後に

本稿では、CassandraとAIを取り巻く状況として、リアルタイムAI、フィーチャーストアというキーワードを紹介しました。

また、より具体的な内容を把握したい方向けに、いくつかの情報源へのリンクを提示しました。

この「導入編」を踏まえて、また別の機会に、より踏み込んだ内容の記事を発表できればと考えています。
locust load test

# Locustとは
Pythonで開発された負荷テストツールです。
https://docs.locust.io/en/stable/

# インストール
```
# インストール
pip3 install locust
# バージョン確認
locust -V
```

# Locustでの負荷テスト
## locust.pyを作成します。
```python:locust.py
from locust import tag, task, TaskSet, SequentialTaskSet, HttpUser, constant_pacing

# テストクラス
class TestClass(SequentialTaskSet):
    # login info
    data = {
        "email": "your email", # e.x. "email@locust.com"
        "password": "your password"
    }

    # ログイン
    @tag('user')
    def on_start(self):
      """
      test user login
      """
      self.client.post("/login", json=self.data, headers={"User-Agent":"locust"})

    # ユーザー編集APIをテストする
    @tag('user')
    @task
    def user(self):
        response = self.client.patch("/user", json={
            "user_name": "abc"}, headers={"User-Agent":"locust"})

    # テストを終了する
    class testStop(TaskSet):
        @tag('user')
        @task
        def stop(self):
            self.interrupt()

# テストを起動する
class TestRun(HttpUser):
   tasks = {TestClass:1}
   wait_time = constant_pacing(1)
```
## ターミナルで下記のコマンドを実施します。
locust -f locust.py --headless --users 4 --spawn-rate 1 -t 1m --csv output_csv_report.csv --html output_html_report.csv

--users/--spawn-rate: 毎秒1ユーザーずつ、4ユーザーまで増加させる
-t: テスト時間、デフォルトの単位はs(秒)になります
--csv/--html: 出力レポート

# Refrence
https://book.st-hakky.com/docs/locust-intro/
https://note.com/shift_tech/n/n77be58376523
json の差分比較

```python
import json
from jsondiff import diff

# 比較するJSONファイルのパス
file1_path = "/path/to/file1.json"
file2_path = "/path/to/file2.json"

# JSONファイルの読み込み
with open(file1_path) as f:
    file1 = json.load(f)
with open(file2_path) as f:
    file2 = json.load(f)

# JSONファイルの差分を計算
result = diff(file1, file2)

# ファイル1にしか存在しない要素を出力
file1_only = []
for k in result.keys():
    if k.startswith("-"):
        file1_only.append(result[k])
with open("file1_only.json", "w") as f:
    json.dump(file1_only, f, indent=2)

# ファイル2にしか存在しない要素を出力
file2_only = []
for k in result.keys():
    if k.startswith("+"):
        file2_only.append(result[k])
with open("file2_only.json", "w") as f:
    json.dump(file2_only, f, indent=2)

# 両方のファイルに存在するが、値が異なる要素を出力
different_values = []
for k in result.keys():
    if k.startswith("~"):
        different_values.append(result[k])
with open("different_values.json", "w") as f:
    json.dump(different_values, f, indent=2)

```
VSCode カーソルを行末に挿入するショートカットキー

## 概要

選択した行末に複数カーソルを挿入する `editor.action.insertCursorAtEndOfEachLineSelected` コマンドがあります。

デフォルトだと `Shift` + `option` + `¥` となんとも押しづらいです。

![ScreenShot 2023-05-11 11.15.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52879/d12eb988-5a62-97e1-79af-c5c14e2a738c.png)

`Command` + `L` で行全体を選択するというオプションなので、
`Command` + `Shift` + `L` でカーソルを行末に挿入するコマンドに設定します。

![ScreenShot 2023-05-11 11.15.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52879/162df363-6e41-8125-6833-76bc11a19ddc.png)

## ショートカットの変更手順

- `Command` + `K`, `Command` + `S` でキーボードショートカットを開きます。
  - 基本設定(Preferences) > キーボードショートカット でも行けます。
- `editor.action.insertCursorAtEndOfEachLineSelected` のコマンドを検索します。
- ✏️アイコンからショートカットを変更します。
  - `Command` + `Shift` + `L` を押した後 `Enter` で設定完了です。
会話型AIサービスGoogle Bardが日本語に対応したので使ってみた

# はじめに
2023年5月10日にGoogleが試験運用中の会話型AIサービス **Google Bard** が日本語に対応したというので使ってみました。

https://bard.google.com/

最初は注意書きを読む必要があります。
あとインターフェイスはまだ英語でした。

# 質問(Google Bardに自己紹介してもらう)
さっそく日本語で質問してみます。
Ｑ．Google Bardとはなんですか？
<dd>Google Bardは、Googleが開発した会話型AIサービスです。テキストの生成、言語の翻訳、さまざまな種類のクリエイティブコンテンツの作成、質問への回答を有益な方法で行うことが可能で、まだ開発中ですが、次のような多くの種類のタスクを実行することを学びました。

あなたの指示に従い、あなたの要求を慎重に完了するように最善を尽くします。
オープンエンド、やりがいのある、または奇妙な質問であっても、その知識を使用して、包括的かつ有益な方法で質問に答えます。
詩、コード、スクリプト、楽曲、メール、手紙など、さまざまなクリエイティブなテキスト形式のテキストコンテンツを生成します。私はあなたのすべての要件を満たすために最善を尽くします。
Google Bardは、Googleが開発した大規模言語モデルLaMDA（Language Model for Dialogue Applications：対話アプリケーションのための言語モデル）に基づいています。LaMDAは膨大なテキストデータを使ってトレーニングされており、「直前の単語につながる可能性が最も高い次の単語を予測する」仕組みで、文章を生成します。

Google Bardは、2023年3月21日（米国時間）に、アメリカとイギリスで一般公開されましたが、日本での公開時期は未定です。</dd>

GoogleBard自身を聞いてみましたが正確な回答が来ました、これは期待出来そうです。

# 質問（健康に関する個人的な興味）
健康に関することを聞いても問題無く回答が来るのか質問してみました。

Ｑ．夜中にお腹が空いたときの対処方法は？
<dd>夜中にお腹が空いたときの対処法はいくつかあります。

* 水を飲む。空腹感と喉の渇きは似ているため、水を飲んで空腹感を紛らわすことができます。
低カロリーで消化の良いものを食べる。ヨーグルト、果物、野菜などがおすすめです。
* カフェインやアルコールを避ける。これらの物質は睡眠を妨げる可能性があるため、空腹感を悪化させる可能性があります。
* 早寝する。十分な睡眠をとることで、空腹感を減らすことができます。
規則正しく食事をする。空腹感を防ぐために、1日3回の食事と2回の軽食を心がけましょう。
* ストレスを管理する。ストレスも空腹感につながる可能性があります。運動、ヨガ、瞑想など、ストレスを管理する方法を見つけましょう。

これらの対処法がうまくいかない場合は、医師または登録栄養士に相談することをお勧めします。</dd>
<br>
いくつかの候補をあげてきた上に最後に医師や栄養士への相談を勧めてくるなど対応も完璧です。

# 質問(サンプルプログラムを書いてもらう)
言語の命令の使い方を説明するとき、どんなサンプルが良いのかよく迷うので質問してみました。

Ｑ．C言語でforループを使ったサンプルプログラムを書いて
<dd>
はい、C言語でforループを使ったサンプルプログラムをご紹介します。

```sample.c
#include <stdio.h>

int main(void) {
  int i;
  for (i = 0; i < 10; i++) {
    printf("Hello, world!\n");
  }
  return 0;
}
```
このプログラムは、1から10までの数字を出力します。forループは、初期化、条件、更新の3つの部分で構成されています。初期化部分では、変数iに0を代入します。条件部分では、変数iが10未満かどうかをチェックします。条件が真の場合、ループの本文が実行されます。ループの本文では、Hello, world!というメッセージが出力されます。更新部分では、変数iに1を加算します。これにより、ループは次の反復で1から10までの次の数字をチェックします。条件部分が偽になったら、ループは終了します。

他にご不明な点がございましたら、お気軽にお問い合わせください。
</dd>

<br>
ループ文のサンプルとしてはまあこんなものでしょう、「お気軽に問い合わせください」で締めくくるのは面白いですね。

# 会話型AIサービスとしてどうなのか？
日本語対応をうたっているAIサービスでもよく回答が英語だったりしますがGoogleBardは常に日本がで返してきます。
回答はメールやGoogle Docに送ることが出来ますがその機能は必要なのか？
仕組みのほどはよくわかりませんが、回答に使用した出典元の記載はありません。

回答が3パターンありますが、気に入らなければ再度問い合わせも出来ます。
試しに問い合わせると微妙に言い回しに変化がありました。

これは **かなり使える**  会話型AIサービスのように思います。
今のところ回答は3～5秒かかっていますがそれも許容範囲でしょう。

ついにGoogleも単語検索で情報を調べる方式から会話型AIサービスで情報を探す時代になるのかも知れませんね。
【Android】公式から Compose のスクリーンショットテストツールがついに登場！

## はじめに

Google I/O '23 にて、**Host-side Screenshot Testing** と呼ばれるスクリーンショットテストのためのツールが発表されました。

これまで [Paparazzi](https://github.com/cashapp/paparazzi)や [Showkase](https://github.com/airbnb/Showkase) といったサードパーティのライブラリを組み合わせてスクリーンショットを撮っていたかと思いますが、ついに公式でサポートされる形になりそうです。

:::note warn
Host-side Screenshot Testing は記事執筆時点で未リリースです。Android Gradle Plugin 8.2 でリリース予定とアナウンスされています。また 実験的な機能のため内容が変更になる場合があります。
:::

## セットアップ

* Android Studio Hedgehog と Android Gradle Plugin 8.2 の環境を用意します。
* `main` や `androidTest` ディレクトリと同じ場所に `screenshotTest` ディレクトリを作成します。こちらがスクリーンショットテストのための sourceSet になるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56635/de9ed914-3913-67ba-de05-3a40e0567145.png)
* スクリーンショットテストの対象にしたい Composable の Preview を `screenshotTest` 内に作成します。通常の Preview と同じように書けばOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56635/8459d28c-0192-0ba6-d9b8-a087b076eeb5.png)

## スクリーンショットテストを実行する

### リファレンスの作成

リファレンスを生成するために以下の Gradle タスクを実行します。成功するとプロジェクト内にスクリーンショットが保存されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56635/206a68e4-8ff8-2eb8-7c58-8c422677e099.png)

### リグレッションの検知

生成したリファレンスをもとにリグレッションの検知を行うには以下の Gradle タスクを実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56635/b74ac90a-2d8c-dc0c-540d-fbf63cea85b0.png)

実行結果は HTML 形式のレポートで見ることができます。差分があれば分かりやすく表示されるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56635/6871a6e7-7bfc-787c-edae-3483ed5733c6.png)

## Host-side Screenshot Testing のすごいところ

* 追加のライブラリが不要
* Jetpack Compose の Preview をそのまま流用できる
* 実機で実行するよりもかなり高速
* 実行環境に関わらず手元のマシンであっても複数の条件(画面サイズ、Theme など)でテストすることができる


## Host-side Screenshot Testing の気になること

記事執筆時点では手元で試せないため、現時点で気になることを以下にまとめます。

* Multipreview annotations に対応しているか
* 一定量スクロールした状態でスクリーンショットを撮るような動的なシナリオはサポートされているか(おそらくサポート外で、Espresso 等で実現することが想定されていそう)
* Jetpack Compose に加えて View もサポートされているか(おそらくサポート外。`AndroidView` でラップすればできるかも？)
* スクリーンショットをプロジェクトのディレクトリ以外の場所に置く方法はあるか(言い換えるとスクリーンショットをコミットに含めない方法はあるか) 

## まとめ

Google I/O '23で発表された Host-side Screenshot Testing についてまとめました。追加のライブラリが不要で通常の Preview をそのまま使えて、しかも複数の条件でスクリーンショットテストを簡単に行える点が特徴です。気になる点も残っていますが、実際に使えるようになるのがとても楽しみです。


## 動画 

9:09〜 から

https://www.youtube.com/watch?v=L6CSaH0kDnI
【React×TypeScript】イベントハンドラの型

## はじめに
```tsx
const handleChange = (event) => {
    console.log(event);
    console.log(event.target.value);
};

return <input type="text" onChange={handleChange} />;
```

こちらはReact×TypeScriptの環境で、フォームのonChange時に`handleChange`というイベントハンドラが発火するようにしています。
一応動きますが、引数`event`で以下のエラーが出てしまいます。

```
Parameter 'event' implicitly has an 'any' type.
```

引数`event`に型が必要なようです。
`any`型は避けて、以下の型注釈をすることでエラーを解消できます。

```tsx
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    console.log(event);
    console.log(event.target.value);
};
```

解消はできましたが、よくわからなかったので`React.ChangeEvent`と`HTMLInputElement`について、それぞれまとめます。

## React.ChangeEventとは
React.ChangeEventとは、**フォームの値が変更された時に発生するイベント**に関連するオブジェクトです。
エディター上で`command+クリック`で辿っていくと、`SyntheticEvent`を継承し、さらに辿ると`BaseSyntheticEvent`を継承していることがわかります。

React.ChangeEventは`target`や`type`などのプロパティを持っています。
これらのプロパティは、上述したサンプルコードでconsole.logしている`event`オブジェクトにもあります。
このことから`event`の型にReact.ChangeEventを設定できることがわかります。

![スクリーンショット 2023-05-11 14.08.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633215/41be7c0a-fb72-4d05-b3c9-2f216bddc6c9.png)

## HTMLInputElementとは
HTMLInputElementとは、**input要素に関するプロパティやメソッドを提供する**HTML DOM APIの一つです。
今回はReact.ChangeEventのジェネリクスに設定しています。
コードを辿っていくと、ChangeEventの`target`プロパティに、HTMLInputElementを設定していることがわかります。

```tsx:index.d.ts
interface ChangeEvent<T = Element> extends SyntheticEvent<T> {
    target: EventTarget & T;
}
```

そこで試しにジェネリクスの箇所を削除してみると、`target.value`で以下のエラーが出ます。（`event`では出ません）

```tsx
const handleChange = (event: React.ChangeEvent) => {
	console.log(event);
	console.log(event.target.value);
};
```

```
Property 'value' does not exist on type 'EventTarget & Element'.
```

このことから、onChangeイベント時に入力値（`target.value`）にアクセスしたい場合、HTMLInputElementの設定が必要であることがわかります。

## まとめ
以上のことから、onChange時に発火するイベントハンドラの引数には`React.ChangeEvent<HTMLInputElement>`の型注釈が必要であることがわかりました。

また、このようなイベントハンドラの型はエディター上から手軽に探ることができます。
まず以下のように記述します。

```tsx
<input type="text" onChange={(event) => {}} />
```

続いて`event`の箇所にホバーすることでヒントを得ることができます。

![スクリーンショット 2023-05-11 12.23.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633215/31b340e0-2810-7b5f-c725-eea469e78b4a.png)

## 参考記事
https://ja.legacy.reactjs.org/docs/events.html

https://zenn.dev/kenta0313/articles/a39fb1d8edc3a4

https://qiita.com/Takepepe/items/f1ba99a7ca7e66290f24

https://dev-k.hatenablog.com/entry/event-handler-for-react-hook-dev-k

https://reffect.co.jp/react/react-typescript-event

https://developer.mozilla.org/ja/docs/Web/API/HTMLInputElement

## 採用のお知らせ
株式会社Relicでは、エンジニア・デザイナーを積極的に採用中です。
またRelicでは、地方拠点がありますので、U・Iターンも大歓迎です！🙌
少しでもご興味がある方は、Relic採用サイトからエントリーください！

https://relic.co.jp/recruit?utm_source=qiita&utm_medium=article&utm_campaign=qiita_article

https://relic.co.jp/categories/job_4?utm_source=qiita&utm_medium=article&utm_campaign=qiita_article
【PHP/Laravel】データを特定のグループごとに集計

# はじめに
データを特定のグループごとに抽出した上で、さらに合計したりなど集計処理を行いたい場合があると思います。
（実際、これまでの業務ではかなりありました！）

本記事では、そのやり方をまとめていきます。

# 開発環境・前提

### 開発環境
- OS：Windows11 22H2
- PHP 8.2.0
- Laravel 9.44.0

### 前提
- ローカルにLaravel開発環境があり、開発サーバーを起動済みであること。
- テーブルが作成済みで、データが格納されていること（今回の例ではcreaturesテーブル）。
- 対象はcreaturesテーブルのみであり、今回の例でリレーションは考慮しない。

【今回使用するcreaturesテーブルの中身】
![スクリーンショット 2023-04-25 155212.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512880/f01d49ee-4cc9-064c-d7eb-15297d96d9ac.png)

# 手順

1\. ルーティングを編集（今回の例ではデフォルトのルーティングを変更）。
```web.php
Route::get('/', [App\Http\Controllers\Controller::class, 'sumCount']);
```

2\. コントローラーを編集。

```Controller.php
<?php

namespace App\Http\Controllers;

use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\DB;

class Controller extends BaseController
{
    public function sumCount()
    {
        $collection = DB::table('creatures')->get();
        
        $groupBy = $collection->groupBy('class');

        $sumCount = $groupBy->map(function ($item) {
            return $item->sum('count');
        });

        return view('groupBy')->with('test', $sumCount);
    }
}
```

3\. ブラウザでの確認用に`groupBy.blade.php`ファイルを作成し、bodyタグ内に以下を追記。

```groupBy.blade.php
<h1>{{ $test }}</h1>
```

4\. `http://localhost/`に接続し、ブラウザで結果を確認。
![スクリーンショット 2023-04-25 155510.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512880/f7141310-afe9-fb28-c518-cf4ffa575895.png)

# 解説（主にコントローラーの内容）
- `use Illuminate\Support\Facades\DB;`
クエリビルダを用いるため、DBクラスをuse宣言しています。

- `$collection = DB::table('creatures')->get();`
`DB::table()`の引数にテーブル名を指定し、そのテーブルのデータを取得しています。
この戻り値は`Illuminate\Support\Collection`のインスタンスであり、それを変数に格納しています。
なお、今回は単純な例としてそのまま`get()`で処理していますが、取得するデータ量が多い場合はメモリ不足に陥る可能性があるのでご注意ください。

- `$groupBy = $collection->groupBy('class');`
変数$collectionには`Illuminate\Support\Collection`のインスタンスが格納されているので、Collectionメソッド`groupBy()`を活用でき、引数に指定したキーの値ごとにデータをまとめています。
今回の例では、classキーにはanimal・fish・birdの3つの値があるので、3つのグループごとにデータがまとめられ、それらを変数に格納しています。

- `$sumCount = $groupBy->map(function ($item) {
            return $item->sum('count');
        });`
変数$groupByに格納されたデータをCollectionメソッド`map()`を使い、グループごとに処理しています。
`$item->sum('count')`の部分でcountキーの値の合計値を算出しています。
ここではanimal・fish・birdの各グループごとにcountの合計値が計算され、それらを変数に格納しています。

- `return view('groupBy')->with('test', $sumCount);`
withメソッドでbladeファイル`groupBy.blade.php`に値を渡しています。
第1引数にbladeファイル上で用いる変数名、第2引数にコントローラー上で求めた合計値が格納された変数名を指定します。

最後に、コントローラーから渡された変数をbladeファイルで指定すれば作業完了です。
ブラウザで確認すると、animalの合計値が7、fishの合計値が11、birdの合計値が3ということが分かるはずです。

# まとめ
クエリビルダを使えばデータ取得、Collectionを使えばデータの加工や集計が簡単にできます！
実際の開発でも使うことは多々あると思うので、今のうちに慣れておきましょう！

本記事が少しでも読者の皆様の参考になれば幸いです。

それでは良き開発ライフを！！

# 参考情報
Laravel公式

https://readouble.com/laravel/9.x/ja/queries.html

https://readouble.com/laravel/9.x/ja/collections.html
「材料力学の教科書」を大学のシラバス等より調べてみたい。

(2025/04/22)更新はしていません。

(調査中)おすすめの、まとめサイトを探しています。教えて下さい。
~~シラバス掲載図書等 があると助かります。公式サイト外もあります。(2023/11/23)~~

# 国立大学のシラバス

https://www.janu.jp/univ/syllabus/

# (2025-03-01)以下は旧いです。更新していません。


# 国公立大学
(調査中)

~~北海道大学 https://www.hokudai.seikyou.ne.jp/wp/wp-content/uploads/2021/04/hokubu_kikai.pdf~~
北海道大学 https://syllabus01.academic.hokudai.ac.jp/Syllabi/Public/Syllabus/SylDetail.aspx?lct_year=2023&lct_cd=015077&langMode=1
~~東北大学 https://text-it.jp/front/student/text/tohoku/search/show/113088~~
東北大学 わかりにくい。
筑波大学 
東京大学 https://taiyaki-exam.com/2017/12/01/2330/
東京工業大学
東京医科歯科大学
一橋大学
新潟大学 テキストに「図解でわかる　はじめての材料力学（2002年，有光　隆＝著，株式会社技術評論社）」を使用する。  
浜松医科大学
名古屋大学
岐阜大学
京都大学 https://ocw.kyoto-u.ac.jp/syllabus/?act=detail&syllabus_id=tech_5189&year=2022
大阪大学 http://www.md.ams.eng.osaka-u.ac.jp/~nakatani/Lectures/Strength_of_Materials/
神戸大学 https://op.lib.kobe-u.ac.jp/opac/opac_details/?lang=0&amode=11&bibid=2002152038
岡山大学　材料力学，中井善一他著，朝倉書店　ISBN-13: 978-4-254-23792-4
広島大学 ~~https://momiji.hiroshima-u.ac.jp/syllabusHtml/2023_12_K7551030.html~~
広島大学 https://momiji.hiroshima-u.ac.jp/syllabusHtml/2024_12_K5014011.html
香川大学
九州大学 https://aerospace.nbu.ac.jp/single.php?166010667732185
札幌医科大学
大阪公立大学
# 私立大学
慶應義塾大学 https://search.lib.keio.ac.jp/discovery/fulldisplay?vid=81SOKEI_KEIO:KEIO&docid=alma9926628250404034
早稲田大学 https://platjam.jmooc.jp/220220562
東北医科薬科大学
埼玉医科大学
東京女子医科大学
杏林大学
昭和大学
順天堂大学
東京医科大学
東京慈恵会医科大学
日本大学
日本医科大学
東海大学
藤田医科大学
近畿大学
関西大学
関西学院大学
関西医科大学
同志社大学
立命館大学 
大阪医科薬科大学
兵庫医科大学
久留米大学
福岡大学


# 参考

以下、検索用ひな形

https://www.google.com/search?q=%E6%9D%90%E6%96%99%E5%8A%9B%E5%AD%A6+%E6%95%99%E7%A7%91%E6%9B%B8+%E5%A4%A7%E5%AD%A6&rlz=1CAUHAM_enJP1038JP1038&sxsrf=APwXEddQ_iZCtY-lCQV07F4FQR6yUFzAJA%3A1683780342019&ei=9nJcZLpY1I_4BtDggfgO&ved=0ahUKEwi6q6nJuuz-AhXUB94KHVBwAO8Q4dUDCA8&oq=%E6%9D%90%E6%96%99%E5%8A%9B%E5%AD%A6+%E6%95%99%E7%A7%91%E6%9B%B8+%E5%A4%A7%E5%AD%A6&gs_lcp=Cgxnd3Mtd2l6LXNlcnAQDDIGCAAQCBAeOggIABCiBBCwAzoFCAAQogQ6CAgAEIkFEKIESgQIQRgBUNwSWK4VYNRBaAFwAHgAgAF5iAHmAZIBAzAuMpgBAKABAcgBA8ABAQ&sclient=gws-wiz-serp

amazon

https://www.google.com/search?q=amazon+%E6%9D%90%E6%96%99%E5%8A%9B%E5%AD%A6&rlz=1CAUHAM_enJP1038JP1038&oq=amazon+%E6%9D%90%E6%96%99%E5%8A%9B%E5%AD%A6&aqs=chrome..69i57j35i39j0i4i15i30l2j0i8i30j0i4i8i10i15i30.17286j0j7&sourceid=chrome&ie=UTF-8

材料力学 名著

https://www.google.com/search?rlz=1CAUHAM_enJP1038JP1038&sxsrf=APwXEdee2RKUSghYEAD_POtsGaEvRAr3DQ:1683781382220&q=%E6%9D%90%E6%96%99%E5%8A%9B%E5%AD%A6+%E5%90%8D%E8%91%97&sa=X&ved=2ahUKEwilpaq5vuz-AhUEA4gKHTfrC8MQ1QJ6BAh1EAE&biw=1366&bih=645&dpr=1

一覧作成のため大学名を参照

https://kamelink.com/exam/index.php?2023%C7%AF%B2%F2%C5%FA%C2%AE%CA%F3
Deno KVでキューを実装【Deno Deploy】

```bash
# プッシュ
curl https://kvq.deno.dev/mykey -d '[{"a":"b"},"foo",null,42]'

# プル
curl https://kvq.deno.dev/mykey
{"a":"b"}
curl https://kvq.deno.dev/mykey
foo
curl https://kvq.deno.dev/mykey
null
curl https://kvq.deno.dev/mykey
42
curl https://kvq.deno.dev/mykey
```



```typescript
import { serve } from "https://deno.land/std@0.177.0/http/server.ts";

const kv = await Deno.openKv();

serve(async (req: Request) => {
    const pathname = new URL(req.url).pathname
    if (req.method === 'GET') {
        for await (const { key, value } of kv.list({ prefix: [pathname] }, { limit: 1 })) {
            kv.delete(key)
            return new Response(typeof value === 'object' ? JSON.stringify(value) : value, { headers: { "Access-Control-Allow-Origin": "*" } })
        }
    } else if (req.method === 'POST') {
        const now = Date.now()
        const entries = await req.json()
        const id = Math.random()
        for(var i=0; i<entries.length; i++) {
            kv.set([pathname, now, i, id], entries[i])
        }
        return new Response('201 Created', { status: 201, headers: { "Access-Control-Allow-Origin": "*" } })
    }
    return new Response('', { status: 404, headers: { "Access-Control-Allow-Origin": "*" } })
});
```
mysqlコンテナで日本語入力できない

# 現象
mysqlコンテナで、日本語を入力するとすぐに消えた

# 解決方法
## ①
https://qiita.com/tomo__x_/items/bd5d86d5f423f8f89b22

## ②
もし①の記事で解決できないなら、下記のコマンドでmysqlコンテナを起動してみましょう
```
docker exec -it mysql_container_name env LANG=C.UTF-8 /bin/bash
```
RDSのBlue/Greenデプロイをさわってみる

# ■概要

Amazon RDSの画面へ推移するとブルーグリーンデプロイに関するお知らせが表示されていますが、まだ気になっているけど試してないという方もいるんじゃないかと思います。
簡単な検証ではありますが、「Amazon RDS Blue/Green Deployments」をさわってみたいと思います。
（2023年2月に行った検証になります）

![](https://storage.googleapis.com/zenn-user-upload/b01a931ee561-20230211.png)

# ■そもそもBlue/Greenデプロイとは？

Blue/Greenデプロイについて知らないという方もいらっしゃるかと思うので簡単に説明すると、
システムのダウンタイムが短く、何かあった時はすぐに切り戻しができるデプロイの方法のひとつです

古いバージョンはブルー環境、新しいバージョンはグリーン環境と呼ばれます。

本番環境を元にステージング環境を作成。
↓
ステージングで検証を完了するとそのまま本番へ昇格させるというものです。

# ■ブルー/グリーンデプロイ機能の対象となるRDS
次のエンジンのすべてのバージョンで使用可能。
RDS for MariaDB
RDS for MySQL

なお次のエンジンでは使用不可（2023/02/11現在）
RDS for SQL Server
RDS for Oracle
RDS for PostgreSQL

# ■何が便利？
現状自分が知りうるメリットについて↓

・本番環境のテスト環境を簡単に作成する事ができで、作成したステージングは安全に本番DBへ昇格させる事ができます。

・またステージングと本番の設定内容をコンソール上で比較する事ができます。

# ■公式の情報
公式の情報は以下です。
ここで説明する必要が何もないくらいにとても詳細に記載してあるので、本記事ではサラッと噛み砕いて見てもらえるようにしたいと思います！

###### データベース更新のために Amazon RDS ブルー/グリーンデプロイを使用する
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/blue-green-deployments.html

# ■百聞は一見にしかず！

という事でとりあえずコンソールから確認してみようと思います！

# ■検証のRDSを作成
しました！（中は空です）
RDSのページからアクション欄にブルー／グリーンの項目がありますね

-----

![](https://storage.googleapis.com/zenn-user-upload/ef75348db033-20230211.png)

-----

早速作成に進むと、ステージングの識別子やグリーンのエンジンバージョン、パラメータグループなどを設定する必要があるようです。
下部にはグリーンデータベースの推定コストも出しくれてます。

-----

![](https://storage.googleapis.com/zenn-user-upload/d90f4c8f4ce2-20230211.png)

-----

# ■プロビジョニングが進行…

実際に作成に進むとこんな感じで、プロビジョニングが進んでいきます。
この間ももちろんブルー側RDSのステータスは利用可能のままです。
中は空の状態で、30分くらいかかりました！

-----

![](https://storage.googleapis.com/zenn-user-upload/0652a0863a4d-20230211.png)

-----

↓

-----

![](https://storage.googleapis.com/zenn-user-upload/9dad1171015e-20230211.png)

-----

# ■コンソール上で設定比較ができる
作成を完了後、設定を確認しようとすると、各種設定を並べて比較する事できるようです。
見た所、環境設定が違う場合はコメントしてくれてるっぽいですね（画面上部）

-----

![](https://storage.googleapis.com/zenn-user-upload/ab2d19d22d16-20230211.png)

-----

# ■ブルーとグリーンの切り替え

切り替えも右上アクションから行う事ができます。

-----

![](https://storage.googleapis.com/zenn-user-upload/b609c33ed3ff-20230211.png)

-----

切り替えの際も次の画象のように比較が可能です。
タイムアウトの設定も可能なので時間の制限も考えられそうですね。

-----

![](https://storage.googleapis.com/zenn-user-upload/1d26a8052145-20230211.png)

-----


# ■実際に切り替えてみる
実際に切り替えを実施してみます！
ステータスが切り替えに変わりました。

-----

![](https://storage.googleapis.com/zenn-user-upload/e0db445d81f5-20230211.png)

-----

あっという間に終わりました！（2,3分ほど？）

-----

![](https://storage.googleapis.com/zenn-user-upload/78fc59703c5e-20230211.png)

-----

# ■最後に
慣れが必要な感じはしますが、とても便利で直感的でもあるので実際の運用でも使いこなせるようになりたいですね！
新卒エンジニアがインターン生のピアメンターをやってみた

# はじめに
新卒1年目（執筆時点で2年目）の私が、エンジニアのインターン生のピアメンターを行いました。ピアメンターというのは、年次や技術力が近いもの同士で行うメンタリングです。

ピアメンターについては、以下の記事に詳しく記載しています。

https://qiita.com/k5mrt/items/814e1ee9819790512acd

本記事は、上の記事の続編ような位置付けです。



# 背景
内定者の方がインターンとして入社されたので、その方のメンターを行いました。ざっくりいえば、チーム開発へのレクチャーを行った形になります。

- お互いのレベル
  - メンター（筆者）：新卒1年目のWebエンジニア。業務内のコードは大まかに理解してきたが、DBのチューニングや運用回りなどはまだ経験が浅い。
  - メンティー：新卒の内定者インターン生。コンピュータ系のバックグラウンドはないが、習作でのVueの経験がある。チーム開発の経験はなし。
- 扱ったタスク
  - バグ修正や細かな変更
  - 予めインターン生向けに、簡単なタスクをいくつか確保してあった
  - 後半は大きめのタスクにも取り組み始めた
- 期間
  - 約2週間
  - 途中で、私自身に大きめのタスクが割り当てられたこと、またインターン生に割り当てられたタスクの技術難度が高かったことから、メンターを上司の方に引き継ぎました。



# メンターとしてサポートした内容
- 環境構築の全般
  - 事前にwikiを整備したので、まずはそれを読みながら進めてもらいつつ、疑問点があれば一緒に解決していった
- VSCodeなどの開発ツールのレクチャー
- 開発タスクのペアプロ
- Git, GitLabを使ったチーム開発のイントロ
- Slackなど社内ツールでのコミュニケーションのイントロ

エンジニアとしての立ち回り方、問題にぶつかった時の対処法などをメインにサポートしました。

VueやJS自体についてはある程度経験がありそうだったので、実装は可能な限り自分でやってもらい、ペアプロでそれを修正する、という形にしました。



# 感想

### メンティーからのフィードバック

実際にメンティーからいただいたFBです。

#### 開発する上で
- 勉強になったところ
  - Vueを使った基本的なフロントエンドの書き方は知っていたが、実際にリリースされているアプリのコードは見たことがなかったのでさまざまな点で参考になった
  - チームでの開発方法全般
  - 会社自体について
  - 設計
  - TypeScript
- 苦労したところ
  - TypeScript

#### メンティーとして
- 助かったところ
  - 環境構築
  - チームでの開発方法（一人での開発経験しかないので助かった。レビュー、テスト、リリースまでの一連の流れや、GitLabの使い方。）
  - 基本自分で考えて開発できたこと（基本自分でやって、わからない部分を相談できるのが最高。）
  - わかんないとこでも答えをすぐ出すのではなく、一緒に考えていく進め方（ブログに書いてある通り）
  - Macを初めて使ったので、そこらへんも教えていただいたのはありがたかった
  - 雑談（やっぱオンラインだし、雑談する機会あんまない。入ったばっかだと話す人もいないので雑談できてよかった。色々なこと知れました。）
- もっとこうして欲しかったところ
  - はじめに自社アプリを一緒に触ると、サービスへの理解度が深まったかなと思う。


### メンター（筆者）の振り返り

#### BAD

> はじめに自社アプリを一緒に触ると、サービスへの理解度が深まったかなと思う。

私たちのチームで開発しているのは[マッチングアプリ](https://couplink.jp/)というものなのですが、実際に使った経験に乏しいと、どのような機能があるか分かりにくかったと思います。

開発に着手する前に、どんな機能があるのか、どんなUIになっているかなどを、実際にサービスを触りながら理解してもらうフェーズを挟むべきでした。開発ツールやコードベースでのレクチャーに頭が偏ってしまい、その辺りを考慮できていなかったです。

メンターがどのようなバックグラウンドを持っているかの理解が甘かったように思います。初期の段階でヒアリングするなどして、そこを擦り合わせる必要性を感じました。

#### GOOD

[前回のメンター](https://qiita.com/k5mrt/items/814e1ee9819790512acd)と同様、「自立的な問題解決」に導けるように意識しました。

> 基本自分で考えて開発できたこと
> 
> わかんないとこでも答えをすぐ出すのではなく、一緒に考えていく進め方

という感想をいただけたのは、意図が上手く伝わったようで安心しました。

> 雑談（やっぱオンラインだし、雑談する機会あんまない。入ったばっかだと話す人もいないので雑談できてよかった。色々なこと知れました。）

業務時間後や開発の合間などに、開発に関係ない話題（趣味のこと、会社のことなど）について雑談をしていました。ここはあまり意識していなかった部分なのですが、思いのほか重要度が高かったかもしれません。

入社当初、特にリモートで勤務していると、なかなか他メンバーと話す機会がありません。雑談の時間を少し取り入れるだけでも、コミュニケーションの円滑化や心理的安全性の向上に繋がりそうです。特にピアメンターは年次や年齢が近い場合が多いので、より効果が高そうです。

エンジニアのメンターといえども、基本は人と人とのコミュニケーションなのだなと再認識しました。


# まとめ

短い期間ではありましたが、インターン生の最初のスタートダッシュには、少しばかり貢献できたようです。次に繋がる改善点も見つかったので、より経験を重ねてメンター力を上げていきたいですね。忌憚なくFBをくださったメンティーの方に感謝です。

### （宣伝です）
メンティーの方が、インターン時期から入社1ヶ月目にかけて担当していた機能がリリースされました。

「マッチングアプリで遊べるマインスイーパー」です！

ログイン不要で遊べるので、興味があればぜひ触ってみてほしいです。（登録・ログインすれば、対戦機能も使えるようになります！）

https://couplink.jp/s/share/games/minesweeper?from=qiita&
AWS SAMデプロイエラー時の対応

# 経緯

- AWS SAM CLIでデプロイ実行したところ、エラーで停止しました（初回デプロイ）
- CloudFormationスタックを確認すると、 `ROLLBACK_COMPLETE` で停止しています
- 失敗となった原因を修正し、再度デプロイを実行したのですが、下記のようなメッセージが表示され、デプロイされません

```
$ sam deploy

(snip)

Initiating deployment
=====================

File with same data already exists at sam-app/xxx.template, skipping upload
Error: Failed to create changeset for the stack: sam-app, An error occurred (ValidationError) when calling the CreateChangeSet operation: Stack:arn:aws:cloudformation:(...snip...) is in ROLLBACK_COMPLETE state and can not be updated.
```


# 原因と対処

初回デプロイで失敗し、CloudFormationスタックのステータスが `ROLLBACK_COMPLETE` となった場合は更新できない仕様のようです。

対処としては、削除後、再度デプロイします。
初回デプロイ失敗、つまりデプロイ不完全であり、削除することで問題になることは無さそうです。
（デプロイ成功し、動作後はアプリケーションによって出力されたデータ等の保全の考慮が必要になる可能性がありますが、初回デプロイで失敗しているのでその点については考慮不要）

### 削除

CloudFormationスタックが削除されます

```
$ sam delete
        Are you sure you want to delete the stack sam-app in the region ap-northeast-1 ? [y/N]: y
        Are you sure you want to delete the folder sam-app in S3 which contains the artifacts? [y/N]: y
        - Deleting S3 object with key sam-app/xxx
        - (snip)
        - Deleting S3 object with key sam-app/xxx.template
        - Deleting Cloudformation stack sam-app
Deleted successfully
```

### 再度デプロイ

成功しました

```
$ sam deploy --config-env dev

(snip)

Successfully created/updated stack - sam-app in ap-northeast-1
```

# 環境

- Ubuntu 20.04 on WSL2
- SAM CLI, version 1.82.0
【Rspec】Activehashを用いた結合テストコードの書き方

#### 経緯
オリジナルアプリケーションの結合テストコードを記述していたところ、activehashを用いた選択肢の部分で通常のフォームとは異なるため、記述の仕方がわからなかった。

#### 開発環境
Ruby:2.6.5
Rails:6.0.6.1

#### 書き方
フォーム入力する際はfill_inを用いるが、activehashを用いたテストコードは以下の形式で記入する。
`select '選択肢', from: 'name属性'`

![スクリーンショット 2023-05-11 12.47.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3349201/37ad813a-7832-90ea-c063-524bf57c1a17.png)
![スクリーンショット 2023-05-11 13.01.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3349201/9c5643e7-e3cd-dce7-ddbd-d161d49cc5a2.png)

selectの選択肢に箇所はプルダウンの選択肢を文字列として記載する。（htmlとして確認する場合は、検証ツールからoptionタグで囲まれているものを記述）
fromのname属性は、該当箇所を検証ツールで開いて確認して記載する。今回は性別の箇所を検証ツールで確認して、nameの`user[sex_id]`をfrom:の後ろに記載する。

```ruby:users.spec.rb
require 'rails_helper'

def basic_pass(path)
  username = ENV["BASIC_AUTH_USER"]
  password = ENV["BASIC_AUTH_PASSWORD"]
  visit "http://#{username}:#{password}@#{Capybara.current_session.server.host}:#{Capybara.current_session.server.port}#{path}"
end

RSpec.describe "ユーザー新規登録", type: :system do
  before do
    @user = FactoryBot.build(:user)
  end
  context 'ユーザー新規登録ができるとき' do 
    it '正しい情報を入力すればユーザー新規登録ができてトップページに移動する' do
      # トップページに移動する
      basic_pass root_path
      visit root_path
      # トップページにサインアップページへ遷移するボタンがあることを確認する
      expect(page).to have_content('新規登録')
      # 新規登録ページへ移動する
      visit new_user_registration_path
      # ユーザー情報を入力する
      fill_in 'メールアドレス', with: @user.email
      fill_in 'パスワード', with: @user.password
      fill_in 'パスワード（確認）', with: @user.password_confirmation
      fill_in 'ニックネーム', with: @user.nickname
      select "男性", from: 'user[sex_id]'
      select "161 - 165cm", from: 'user[height_id]'
      select "71 - 75kg", from: 'user[weight_id]'
省略
```
最後にコマンドを入力してテストが成功するか確認する。
```
bundle exec rspec spec/system/users_spec.rb
```

備忘録も兼ねて投稿しました。

#### 参考文献
- [【Rails】Active_hashの結合テストコードの書き方【Rspec】](https://qiita.com/RIN_HM/items/7d62d0288ed1920a774c)
docker で IHS をリモートにたてた形の実現

# あらまし

WebSphere Application Server (traditional) を docker で動かした。お次に実際の運用環境を想定して WEB サーバーをたてる。 IBM HTTP Server の docker を取得して、順次構成していく。

自分の試したコマンドを記録する。

### 今回の最終目標

IHS 経由で WebSphere Application Server 上のアプリを呼び出せること。

# Docker イメージの取得とコンテナ起動
## docker hub から取得しつつ起動

[ibmcom/ibm-http-server](https://hub.docker.com/r/ibmcom/ibm-http-server/) の記載されている次のコマンドを実行。

```bash
docker run --name ihs -h ihs -p 80:80 -it ibmcom/ibm-http-server bash
```

この段階ではまだ IHS は稼働していない。
次のコマンドを実行し IHS を起動する。

```bash
docker exec -d ihs /opt/IBM/HTTPServer/bin/apachectl start
```
Web ブラウザで http://localhost/ にアクセスし IHS のウェルカム画面が表示されることを確認。

IHS の停止。

```bash
docker exec -d ihs /opt/IBM/HTTPServer/bin/apachectl stop
```

## IHS の構成
### 実施手順の参照先

Knowledge Center の [IBM HTTP Server バージョン 9.0 の構成](https://www.ibm.com/support/knowledgecenter/ja/SSEQTP_9.0.0/com.ibm.websphere.base.doc/ae/tins_manualWebIHS80.html) と、それの子。

### 実施内容

IHS のコンテナで bash を起動して対話モードに入る。

```bash
docker exec -it ihs /bin/bash
```

#### IHS WEB サーバーの構成

アーキテクチャーの確認。

```bash
root@ihs> /opt/IBM/HTTPServer/bin/versionInfo.sh | grep Architecture
Architecture          x86-64 (64 bit)
Architecture    x86-64 (64 bit)
```

vi をインストールして vi で httpd.conf の最下行に Knowledge Center の指示通り追記。

```bash
root@ihs> apt-get update
root@ihs> apt-get install vim # vi が使えなかったのでインストール
root@ihs> vi /opt/IBM/HTTPServer/conf/httpd.conf

## 以下を再下行へ追加(64bits となっているのは上で 64 bit だったから)
LoadModule was_ap24_module /opt/IBM/WebSphere/Plugins/bin/64bits/mod_was_ap24_http.so
WebSpherePluginConfig /opt/IBM/WebSphere/Plugins/config/サーバー名/plugin-cfg.xml
```

ここで WebSpherePluginConfig については、IHS と WebSphere Application Server が別ノードの場合の指定が上記の内容。それ以外は「[IBM HTTP Server バージョン 9.0 の構成](https://www.ibm.com/support/knowledgecenter/ja/SSEQTP_9.0.0/com.ibm.websphere.base.doc/ae/tins_manualWebIHS80.html)」を参照。

ディレクトリーの作成とファイルのコピー。
パス中の「サーバー名」は WAS 上でプラグイン作成のために定義する Webサーバーの名前。

```bash
root@ihs> mkdir -p /opt/IBM/WebSphere/Plugins/{logs,config}/サーバー名
root@ihs> cp /opt/IBM/WebSphere/Plugins/etc/plugin-key* /opt/IBM/WebSphere/Plugins/config/サーバー名/          
root@ihs> cp /opt/IBM/WebSphere/Plugins/config/templates/plugin-cfg.xml /opt/IBM/WebSphere/Plugins/config/サーバー名/
```

#### IHS 管理サーバーの構成

管理サーバーを WebSphere Application Server の管理コンソールから起動、停止するための構成。

管理ユーザー用のグループとユーザーの追加。

```bash
root@ihs> groupadd グループ名
root@ihs> useradd -g グループ名 ユーザー名
```

管理ユーザーのパスワード設定。

```bash
root@ihs> cd /opt/IBM/HTTPServer/conf
root@ihs> ../bin/htpasswd -b admin.passwd ユーザー名 パスワード
```

ディレクトリー、ファイルへの権限の設定と admin.conf の更新。

```bash
root@ihs> cd /opt/IBM/HTTPServer
root@ihs> bin/setupadm -usr ユーザー名 -grp グループ名 -cfg /opt/IBM/HTTPServer/conf/httpd.conf -adm /opt/IBM/HTTPServer/conf/admin.conf -plg /opt/IBM/WebSphere/Plugins/config/サーバー名/plugin-cfg.xml
root@ihs> vim conf/admin.conf

## @@AdminPort@@ を 8008 に置換し保存する
Listen @@AdminPort@@
ServerName <16進数>:@@AdminPort@@
```

#### サーバーの起動

管理サーバーの起動。

```bash
root@ihs> cd bin
root@ihs> ./adminctl start
```

WEB サーバーの起動。

```bash
root@ihs> ./apachectl start
```

---

ここまで、とりあえず設定のメモを書いた。現時点でこれで意図通りになっているかどうか確認出来ていない。先へ進む前に最低限のところを確認する。
【エラー】dllを参照しているのに「アセンブリ参照が不足しています」が出るときの対処

## 不具合現象

Visual Studioの.NET Frameworkの開発中、
自作したdllファイルを参照しデバッグで起動しました。

デバッグでの起動はうまくいきましたが、
dll内のメソッドを使用する際に標題のエラーが発生しました。

もちろん、dllを参照していることは確認済です。

## 解決方法

自作したdllのプロジェクトの、

「Properties -> アプリケーション -> 対象のフレームワーク」と

デバッグ中のプロジェクトの対象フレームワークが異なることが原因でした。
上記の設定を同じにすることで問題なく対処できました。

デバッグまで起動できるのが謎ですが、
今回のケースでは、自作dllの内部で使用しているdllを使用する際に、
Frameworkが異なることが原因で、dllが不足する事態になったのだと推測します。
Atcoder典型90問 006 - Smallest Subsequence

# Atcoder典型90問 006 - Smallest Subsequence（★5）
▶︎https://atcoder.jp/contests/typical90/tasks/typical90_f

## 問題
英小文字のみからなる、長さ 
N の文字列 
S が与えられます。

長さが 
K である 
S の部分列のうち、辞書順で最小であるものを出力してください。

## 制約
```math
1≤K≤N≤100000\\
S は英小文字のみからなる長さ N の文字列\\
N,K は整数
```

## 試したこと
* 辞書は左から貪欲法。
    * 文字列のなかで辞書順が小さいアルファベットから順に探索していき、右側に残りの文字数分だけ文字列がとれるか調べれば良い。取れる場合はその文字を採用し、取れない場合は採用せずに次の文字に行く。
    * 文字を採用した場合、のこり選択回数を1減らし、その文字より右の文字列に対して再探索。
* 計算量やばいかなーと思ったら案の定やばくてTLE。
    * 再帰で書いたのもよくなかったのかもしれない。
    * よく考えたら再帰する必要ないな...
* アルゴリズム自体は容易に実装できたが、TLEの回避方法がわからなかった。挫折。

## 適切な方針
* 前処理を行う。

## 解説付きコード
コードは https://drken1215.hatenablog.com/entry/2021/10/10/195200　　
から引用させていただきました。大変わかりやすい解説がついていて参考になりました。

```py
# res[i][c] := i 文字目以降で最初に文字 c が登場する index
# 存在しないときは N
def calc_next(S):
    # 文字列 S の長さ
    N = len(S)

    # 答え
    res = [[N] * 26 for _ in range(N + 1)]

    # 後ろから見る
    for i in range(N - 1, -1, -1):
        # i + 1 文字目以降の結果を一旦 i 文字にコピー
        for j in range(26):
            res[i][j] = res[i + 1][j]

        # i 文字目の情報を反映させる
        res[i][ord(S[i]) - ord('a')] = i

    # 答えを返す
    return res

# 入力
N, K = map(int, input().split())
S = input()

# 前処理
res = ''
nex = calc_next(S)

# 貪欲法
j = -1
for i in range(K):
    for ordc in range(26):
        k = nex[j + 1][ordc]

        # ちゃんと K 文字が作れれば OK
        if N - k >= K - i:
            res += chr(ord('a') + ordc)
            j = k
            break
print(res)
```

## TLEしたコード
```py
def findAvailableSmallest(S, k, selected_s):
  if k == 0:
    return(S, k, selected_s)
  
  if len(S) == k:
    for i in range(len(S)):
      selected_s.append(S[i])
    return(S, k, selected_s)
  
  Slist = list(S)
  Slist.sort()
  for s in Slist:
    s_place = S.find(s)
    if s_place + k> len(S):
      continue
    else:
      selected_s.append(s)
      [S, k, selected_s] = findAvailableSmallest(S[s_place+1:], k-1, selected_s)
      break
  
  return(S, k, selected_s)
 
[N, K] = list(map(int, input().split()))
S = input()
selected_s = []
[S, K, selected_s] = findAvailableSmallest(S, K, selected_s)
 
print("".join(selected_s))
```
Bardは最新のニュースについても回答してくれた。

GoogleのBardが日本語でも利用できる様になったと言うニュースがあったのでさっそく使って見ました。

https://www.publickey1.jp/blog/23/googleaibard.html

レスポンスも早く、回答内容も質問に沿った内容で、ChatGPTに比べても負けず劣らず・・・という所管だったのですが、ひとつ圧倒的な違いがありました。

それは、Bardは最新の情報についての質問にも回答してくれると言うことです。
Bingの方は毎日学習モデルを更新して、これと同等のことが実現できているみたいなのですが、これも同じなのでしょうか？

いくつか比較した結果を掲載しておきます。
（この質問を行ったのは2023年5月11日 午前8時ごろです）

### 昨日の地震について

ChatGPT
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77722/b2818b02-b545-0a02-eb7c-2647dcd88d88.png)
Google Bard
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77722/6258d7cc-eed8-fb29-0db4-22cb5eecf8c7.png)


### 昨日の天気
ChatGPT
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77722/4ed76af0-bdf6-0430-6e5c-e526045eb851.png)

Google Bard
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77722/68a412aa-1f82-3567-c5b8-0b180d62b853.png)



### 昨日バズったニュース
ChatGPT
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77722/29f7ec7f-4d0a-e1fd-f705-5efc5f0938aa.png)


Google Bard
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77722/1e49184a-89ae-b008-5421-a07cea5519e1.png)



## まとめ

これまでChatGPTにしてきた色々な質問をBardにも投げて見たところ、概ね期待通りの回答を返してくれています。

他にも、Googleの方はデータを表形式で表示してくれたり、ダウンロードできたり、GoogleDocsと連携できたり、使っていて幾つかの機能差がありそうでしたので別途まとめて見たいと思います。
RubyでAtCoder ABC262(A, B, C)を解いてみた

# はじめに
Webエンジニアを目指して、RubyやRailsをいじってます。
今回は、RubyでAtCoder ABC262のA, B, Cを解きました。備忘録として解き方をまとめていきたいと思います。

# A - World Cup
https://atcoder.jp/contests/abc262/tasks/abc262_a
```ruby:a-262.rb
y = gets.to_i
a = y % 4
puts y + [2, 1, 0, 3][a]
```
## 解説
テストケースから分かるように答えはyに[2,1,0,3]のyを4で割った余りのインデックスに対応する要素を足したものになります。

# B - Triangle (Easier)
https://atcoder.jp/contests/abc262/tasks/abc262_b
```ruby:b-262.rb
n, m = gets.split.map(&:to_i)
array = Array.new(n + 1) { Array.new(n + 1, false) }
m.times do
  u, v = gets.split.map(&:to_i).sort
  array[u][v] = true
  array[v][u] = true
end

ans = 0
for i in 1..n - 2
  for j in i + 1..n - 1
    for k in j + 1..n
      ans += 1 if array[i][j] && array[j][k] && array[k][i]
    end
  end
end
puts ans
```
## 解説
Nが100以下と小さいため、3重ループを回して全探索することができます。

# C - Min Max Pair
https://atcoder.jp/contests/abc262/tasks/abc262_c
```ruby:c-262.rb
n = gets.to_i
a = gets.split.map(&:to_i)

count = 0
a.each_with_index do|i, j|
  count += 1 if i == j + 1
end

ans = (count * (count - 1)) / 2
n.times do |i|
  ans += 1 if a[i] > i + 1 && a[a[i] - 1] == i + 1
end
puts ans
```
## 解説
（[公式解説](https://atcoder.jp/contests/abc262/editorial/4477)を参考にしました）

```math
a_i=iかつa_j=j
```
```math
a_i=jかつa_j=i
```
のいずれかが成り立つことを利用することで答えを求めることができます。

https://qiita.com/shoya15/items/50fd17e37d7c64f2b166
Bardの衝撃。Bardはユーザから指示されたURLのページにアクセスできる。Webページの要約やスクレイピングも？


Google Bardが、日本からも利用できる様になりましたが、ChatGPTとの大きな違いがありました。
それは、ユーザが渡したURLにBardがアクセスができることです。

ChatGPTでは基本的にそういったことはできず、やれている様に見えても違った情報を返してしまっていました。


例えば、以下ページのURLを渡して要約してもらうと、返ってくるのは以下の様な返答になってしまいます。

アクセス先のページ

https://news.yahoo.co.jp/articles/57119079ca29698a0219c8242827690834906549

ChatGPTからの返答
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77722/a257fd3f-3394-481f-3386-45b5a20dca07.png)
なんだか、違うページを読み込んでいそうです・・・完全に間違っています。

-- 

それに対し、Google Bardは正しくリンク先の記事を読み取って要約をしてくれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77722/8876b9d9-fe59-4a19-ecb2-91bc3a460f6b.png)


本当にリクエスト先のURLにアクセスをしているのか不安だったので、試しに先頭50文字出してといったらちゃんと出してくれました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77722/94872891-7703-d19d-22ae-174c93f5d70c.png)

もしかしてスクレイピングができてしまうのか？と期待して、以下の様なリクエストを投げて見たところ・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77722/56fd60e4-aa89-b5e8-a36e-4659482c69bd.png)

なんと、、、リンク先一覧が作れてしまいました。。

## まとめ

Google Bardはその性能も十分期待ができるところですが、ChatGPTにはない機能も多く持ち合わせていそうですので、さらなる活用方法が考えられそうです。もしかすると、ChatGPTを超える可能性もあるのではないかという可能性を強く感じました。


## 5/12　追記

いろいろ試してみた結果、URLの先のページサイズが大きい場合、うまくデータを取得できていなさそうということが発生した。この場合でもエラーなどは発生せずに返事が返ってくるが、全然違うページの内容のことを返してきたりするので、裏の動きがよくわかっていない。対象のページにアクセスしている様に見えて、実は裏のキャッシュ情報をとっているだけなのかもしれない・・・
【流行に乗り切れない】chat gptのことが何もわかっていないが、ゴミ人間コミュ症にとってのbetterツールである件について(bestではない)

どうもダメ人間です。
GW中にプログラミングのわからないことについて唯一の友人(外国人)に聞いたところ「ChatGptに聞けばいいよ！」と教えてくれた。
なんか流行ってるやつーーそれに関わっていいのか、ダメ人間なので結構ためらった。

しかし、とても便利なやつで、ｇｇっても出てこないことに巧妙に回答してくれる。人間に聞くより敷居が低く、迅速かつどんな下手な言い回しでもいい。

できなくてもいい。正解への近道が一番わかっている人間だとしてもそれが強要されない限り、これからは人間には聞きたくない。ChatGptに聞いていきたい。そう思った。

なぜなら、ダメ人間とは他人に与えるDMG,ATK,BUFFが酷いのだらしい。
夜の23時にそういった趣旨の電話がかかってきた。
そのため、ダメ人間のデメリット；他人への被害；を最小に収め、事なきを得るために人間には聞きたくない。
夜の23時にそういった趣旨の電話をしなくてはいけない会社の仕組み自体狂っているし、そうさせる自分自身も会社に対してデメリットを被っているのだろう。
そう。ブラック企業で働くとはそういった人間性や人格の抑制が２４時間問わずかかってくる。
そのため、よくわからないがChatGptに聞くのが一番いい。
そのため、いかに進捗を聞かれても、それが仕事として強制力を課されていないならば、無難にChatGptに聞き、その誤りと自身の目的を擦り合わせる形で果てしなく遠回りを遠回りをしようではないか。
~~にしても、まだ完全ではないchatGPTとではすぐに物事を解決できない。。わかってる人間に聞くことの方が１００億倍は効率がいいのはいうまでもアルマジロ。。~~

歪み切っている前置きが長くなってしまったせいでかこうとしていた（ほぼ常識的）内容について書かずに済んでしまった。
書く気力がなくなってしまった。

あと数時間、chatGPTに色々聞いては落ち込もうではないか。


## おまけ
友人に「駅メモ」なるアプリを教えてもらった。
ちょうどごちうさコラボをしていた。
ただ、えぐい課金しないとコラボキャラは入手が難しそうだと判断した。
圧倒的放置ゲーなのだが、放置ゲーをイライラしながら構うのがダメ人間。
初回ガチャは振るわなかったのだが、チュートリアル終了後には砂田橋あきらというキャラを選んでしまった。。これからもしばらくの間はイライラさせてもらいながらスマホの充電を減らしてもらわせていただこう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2867756/958ae199-1da3-b1e6-03b7-4c1b36206d58.png)


### 参考文献
- 駅メモ！.「新でんこ「あきら」出発進行♪」.2021-06, https://ekimemo.com/news/20210601150000_2,(参照　２０２３-05-09).

転職活動とか、自信の向上のために過去Quiitaを消したはずなのに二の舞を待ってしまっている。。
仕方ない。ダメ人間だもの。
【MT7】PageButeでページネーション作成

## はじめに
**MovableType7**
静的ページ用ページ分割プラグイン「PageBute」を使ったページネーション（ページャー、ページ送り）の作り方について。

```
<MTPagination> 
  <MTPaginationHeader> 
    <ul> 
    <MTIfPaginationFirst> 
      <mt:ignore>最初のページ以外のとき</mt:ignore> 
      <li><a href="<$MTPaginationPrev$>" class="prev"><i class="fas fa-chevron-left"></i><i class="fas fa-chevron-left"></i></a></li> 
      <MTElse> 
        <mt:ignore>最初のページのとき/リンクなし</mt:ignore> 
        <li><span class="prev"><i class="fas fa-chevron-left"></i><i class="fas fa-chevron-left"></i></span></li> 
    </MTIfPaginationFirst> 
  </MTPaginationHeader> 

  <MTIfPaginationCurrent> 
    <mt:ignore>現在のページを表示</mt:ignore> 
    <li><span class="now"><MTPaginationLink element="number"></span></li> 
    <MTElse> 
      <mt:ignore>それ以外のページ（遷移用のリンク付き）</mt:ignore> 
      <li><a href="<$MTPaginationLink$>"><$MTPaginationLink element="number"$></a></li> 
  </MTIfPaginationCurrent> 

  <MTPaginationFooter> 
    <MTIfPaginationLast> 
      <mt:ignore>最後のページ以外のとき</mt:ignore> 
      <li><a href="<$MTPaginationNext$>" class="next"><i class="fas fa-chevron-right"></i><i class="fas fa-chevron-right"></i></a></li> 
      <MTElse> 
        <mt:ignore>最後のページのとき/リンクなし</mt:ignore> 
        <li><span class="next"><i class="fas fa-chevron-right"></i><i class="fas fa-chevron-right"></i></span></li> 
    </MTIfPaginationLast> 
    </ul> 
  </MTPaginationFooter> 

</MTPagination>
```
※矢印はFontAwesomeを使用しています。

## 出力結果
```
<ul> 
  <li><span class="prev"><i class="fas fa-chevron-left"></i><i class="fas fa-chevron-left"></i></span></li>  
  <li><span class="now">1</span></li>  
  <li><a href="">2</a></li>  
  <li><a href="">3</a></li> 
  <li><a href="">4</a></li> 
  <li><a href="">5</a></li> 
  <li><a href="" class="next"><i class="fas fa-chevron-right"></i><i class="fas fa-chevron-right"></i></a></li> 
</ul>
```

![a27e896fec198499c5bea640f78dd13f.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1104075/04c3cf9a-c4b3-a1cb-b3ff-a0f76c8c4c02.png)


## 参考サイト
・[静的ページ用ページ分割プラグイン:PageBute](https://product.skyarc.co.jp/engineerblog/entry/2642.html)