OmniAICreator/Qiita-1.07M huggingface dataset:
ショート動画でクイックに知る！ IBM watsonx Code Assistant for Zとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52151/06e01ec5-0ab0-4107-bf11-be1db02ed618.png)

# はじめに

みなさん、IBM Videoというサイトをご存知でしょうか？
IBMが提供する製品をショート動画でわかりやすくご紹介している動画サイトです。
* スキルアップしたくてもなかなか時間が取れない
* 気になる製品があるけど、マニュアルを読んで理解するのはきつい
* 製品の特徴やメリットをクイックに知りたい

という方には、うってつけの動画を提供するサイトです。
興味のある方はぜひご覧いただければと思います。

# 今回ご紹介する動画へのリンク

[IBM watsonx Code Assistant for Zとは](https://video.ibm.com/recorded/134061102)

# IBM watsonx Code Assistant for Zとは

IBM watsonx Code Assistant for Z (WCA4Z) は、メインフレームアプリケーションのモダナイゼーションを支援する生成AI製品です。この製品の主な機能は以下の通りです：

## 主な機能
1. **アプリケーションの検出と分析 (理解)**
   - IBM Application Discovery and Delivery Intelligence (ADDI) を使用してアプリケーションを分析。
2. **自動でのコード・リファクタリング**
   - COBOLコードをモダナイズする。
3. **コード最適化**
   - アプリケーションのコードのリファクタリングや効率化を図る。
4. **COBOLからJavaへの変換**
   - Java変換ようにチューニングされたモデルによって自動変換する。
5. **テスト自動生成 (検証)**
   - 検証プロセスを効率化が可能です。

## ADDIの主な機能
- **メインフレーム上のアプリケーションやデータの関係を可視化**  
  プログラム間の相関関係やフローを視覚的に分析。
- **SQLテーブルの使用状況や変数の影響範囲を詳細に把握**  
  各プログラムのフローチャートや詳細レポートを生成。

## 使用方法
1. **ADDIへの接続**  
   - IBM Developer for Z を使用してADDIに接続。
2. **プロジェクトの選択と分析**  
   - コールグラフやプログラムフローを分析。
3. **データ使用状況の確認**  
   - SQLテーブルの使用条件やプログラム内の操作を確認。
4. **分析結果のレポート出力**  
   - 変数の影響範囲やコード詳細をレポートとして出力可能。

## 活用方法
- ADDIはWCA-4Zの一部ですが、単独で無料評価版を試すことが可能。
- アプリケーションのモダナイゼーションを低リスク・低コストで実現。

ぜひ、強力な分析ツールであるWCA4Z & ADDIを活用してください。
【BizRobo！】javascriptを使って最大公約数を算出

前回の記事で配列を使った集計を行いましたが

https://qiita.com/tantanshio/items/9fc738345e0e4b793ced

今回は2次元配列の予定を変更し、最大公約数を算出したいと思います。
（理由・目的はまとめにて記載）

:::note warn
javascript初心者のため、誤った解釈が含まれている可能性があります。
利用の際は十分ご注意ください。

:::


# １．そもそも最大公約数とは

最大公約数（さいだいこうやくすう、英: greatest common divisor[注釈 1]）とは、すべての公約数を約数にもつ公約数である。

引用元：Wikipedia（https://ja.wikipedia.org/wiki/%E6%9C%80%E5%A4%A7%E5%85%AC%E7%B4%84%E6%95%B0）



## ２．お題

3項目の最大公約数を算出し、Excel入力する


![00.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523511/05c007d1-d6a5-d329-53a6-c32ff51dd000.jpeg)




## ３．作成イメージ

前回のロボット同様、1行ずつループ取得
取得結果の最大公約数を算出
最大公約数を入力

## ４．対応内容

前回の配列に使ったロボットをベースにサクっと作成

![02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523511/cb3c5b8d-1035-6728-0529-89eb5b61b732.jpeg)


#### この次のステップで使うJavaScriptが重要。

![03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523511/951b497a-d663-c68d-dc5a-45957a8e9e1a.jpeg)





```ruby:BizRobo！用コード
>>function gcd(x, y) {
  if (y === 0) {
    return x;
  }
  return gcd(y, x % y);
}
function gcdOfThree(a, b, c) {
  return gcd(gcd(a, b), c); 
}
OUTPUT = gcdOfThree(<<+項目1+>>, <<+項目2+>>, <<+項目3+>>);
<<
```

コード的には以下の状態

![04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523511/0dbb2f7c-64fb-0f1c-8864-11420d4b620e.jpeg)



最後に入力するステップを追加すれば完了

![05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523511/8c9a66c1-ff9a-6ec6-a5d2-cc8cabf652b9.jpeg)










## ５．結果　
　　　　➡出来た

![06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523511/e209f478-736a-e7b6-9e05-ead17a328a13.jpeg)




## ６．まとめ

これさえ、あれば
いつなんどき、子供に最大公約数を聞かれても正しい答えを教えられること間違いなし！
※Excelのgcd関数でも求められるので、わざわざロボット作らなくても対応できます。



ついでに、ロボットで最大公約数を算出する必要がある人にもおススメ。
Amazon Bedrock を用いたClineの導入

# はじめに
ClineのBedrock経由での利用に際して参考記事が少なく苦労したので、備忘録も兼ねこの記事でClineをBedrockで利用するための設定手順について纏めます。
# Clineとは
一応記載
> [cline github](https://github.com/cline/cline)より引用（日本語訳）
>>Clineは、複雑なソフトウェア開発タスクをステップバイステップで処理することができます。
ファイルの作成と編集、大規模なプロジェクトの探索、ブラウザの使用、ターミナルコマンドの実行（許可後）などを可能にするツールを使って、コード補完や技術サポート以上の方法であなたを支援することができます。
自律型AIスクリプトは従来サンドボックス環境で実行されていましたが、この拡張機能では、すべてのファイル変更とターミナルコマンドを人間が承認するGUIを提供し、エージェント型AIの可能性を探るための安全でアクセスしやすい方法を提供します。

与えられたタスクを自分で考えてよしなに遂行してくれるAIエージェントだと 私は
解釈しています。

# 導入手順
## 1. VSCode への Cline 拡張機能のインストール
VSCode の拡張機能マーケットプレイスから以下の拡張機能をインストールします
```
saoudrizwan.claude-dev
```
## 2. Bedrockのアクセス付与
画像のようにBedrock上でClineにて利用するモデルのアクセス権を得ます（`リクエスト可能`→`アクセスが付与されました`）
今回は`Claude 3.5 Sonnet v2`を`us-west-2`（オレゴン）で利用する想定です。
![スライド2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1974522/f3020742-2124-a10f-61fe-1a75edabd845.png)

## 3.  IAMユーザーの作成と認証情報の取得
Cline の利用には`Action`として `InvokeModelWithResponseStream` が許可されていれば問題ないようです。
今回は、別モデルを利用することも想定して任意のリージョンの任意のモデルにアクセスできるポリシーを作成します（勿論 別モデルを利用するには、対象モデルが`アクセスが付与されました`である必要があります）。
ポリシーをアタッチしたIAMユーザーを作成し、アクセスキーとシークレットキーを取得します。
```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowBedrockModelStreamingAccess",
            "Effect": "Allow",
            "Action": "bedrock:InvokeModelWithResponseStream",
            "Resource": [
                "arn:aws:bedrock:*::foundation-model/*",
                "arn:aws:bedrock:*:*:inference-profile/*"
            ]
        }
    ]
}
```

## 4. Clineの設定
vscodeにて下記画像のように設定します。
Access Keyと Secret KeyはIAMユーザーより取得した値を用います。Session Tokenは今回使用しません。
AWS RegionとModelはアクセス付与したBedrockモデルを設定します（今回だと`Claude 3.5 Sonnet v2`を`us-west-2`）。

![image6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1974522/c32f536a-c308-f66b-5287-f7b2d669cb44.png)

## 5. 動作確認
何かchatしてみましょう。
Agentから返事が返ってくればBedrockと正常につながっていることになります。
![image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1974522/30ff0ba5-6a8f-9fa4-32c7-84b5eae9fc3f.png)


# 注意点
clineはタスクの遂行にあたって多くのtokenを要するので、利用に際しそれなりにコストがかかる印象です（所感 1＄/task）.
`prompt cashing`が利用できるようになるともう少しコストは抑えられるのでしょうが、Bedrockを用いてclineを利用するにあたってはコスト面に少し注意する必要がありそうです（幸いにもコストは見えやすい場所に表示されているので）
オークション分析レポートで競合の掲載状況を確認しよう

# オークション分析レポートとは
こんにちは、所属企業で広告運用を担当している鈴木です。

検索広告はオークション形式のため、競合他社の掲載状況を把握しながら運用を行っていく必要があります。
Google広告には、管理画面上で簡単に競合分析を行うことができるツールが用意されており、
このツールの見方を覚えておくことで、戦略立てを効率よく進めることができるようになります。

今回はこのGoogle広告の「オークション分析レポート」について書いていきたいと思います。

## オークション分析レポートの表示方法
![スクリーンショット 2024-11-07 174505.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/2c9bc41d-1b01-f581-0373-adf116cba827.png)

Google広告管理画面にログイン後、左メニュー「キャンペーン」をクリックし分析情報とレポートから
「オークション分析」を選択します。

ここで、自社と同じオークションに参加している競合他社の状況を確認していきます。

## オークション分析レポートで使用される指標
オークション分析で確認することができる指標は以下の6つです。

- インプレッションシェア
広告が表示される可能性のあった回数のうち、実際に表示された回数の割合

- 重複率
同じオークションにおいて、自社と競合他社が同時にインプレッションを獲得した割合

- 上位掲載率
競合他社が自社よりも上位に掲載された割合

- 上部表示率
自社および競合他社の広告が、オーガニック検索結果の上部に表示された割合

- 最上部表示率
自社および競合他社の広告が、オーガニック検索結果の上部かつ1位に表示された割合

- 優位表示シェア
自社の広告が競合他社よりも上位に表示された割合、または自社のみが表示された割合

### まとめ
競合他社の動きを知ることはとても重要なことですが、競合他社に競り勝つことが全てではない
ということを意識した運用を心掛けなくてはならないと考えています。

自社広告を測定する際の判断材料の一つとして活用してみてください。

以上、鈴木でした。
S3に保存したWAVファイルをAmazon Transcribeで文字起こししてみる

# はじめに

WAF形式の音声ファイルを文字起こしする必要がでてきたのでその時に使用したスクリプトを紹介します。

# 準備

boto3に依存しているのでインストール

```
$ pip install boto3
```

# スクリプト

音声ファイルはあらかじめバケットの`audio`ディレクトリに保存しています。
バケットからWAVファイルのパスを取得し、1件ずつAmazon TranscribeのJobを実行するようにしています。ここでは音声のチャネル識別のみ有効化しています。
生成された文字起こしのJSONファイルはどうバケットの`transcription`ディレクトリに保存されます。


```python
import boto3

s3_client = boto3.client("s3")
tran_client = boto3.client("transcribe")

BUCKET_NAME = "your bucket name"
AUDIO_PREFIX = "audio"
TRANSCRIPTION_PREFIX = "transcription"


def main():
    paginator = s3_client.get_paginator("list_objects_v2")
    for page in paginator.paginate(Bucket=BUCKET_NAME, Prefix=AUDIO_PREFIX):
        for content in page["Contents"]:
            key = content["Key"]

            if not key.endswith(".wav"):
                continue

            job_name = key.split("/")[-1].rsplit(".", 1)[0]
            tran_client.start_transcription_job(
                TranscriptionJobName=job_name,
                LanguageCode="ja-JP",
                Media={"MediaFileUri": f"s3://{BUCKET_NAME}/{key}"},
                MediaFormat="wav",
                OutputBucketName=f"{BUCKET_NAME}",
                OutputKey=f"{TRANSCRIPTION_PREFIX}/",
                Settings={"ChannelIdentification": True},
            )


if __name__ == "__main__":
    main()
```
サンクスページがない場合のフォーム送信CVの計測方法

# サンクスページが存在しないサイト
こんにちは、所属企業で広告運用を担当している鈴木です。

広告運用を行うなかで、フォーム送信のコンバージョンを計測するケースは非常に多いと思います。
大抵の場合、フォームページからの送信完了時に表示される、いわゆるサンクスページに
タグを設置することで計測を行うと思いますが、そのサンクスページが存在しないサイトもあります。
よくあるケースとしては、WordPressプラグインの「Contact Form 7」を使ったフォームを設置している場合などです。

では、そのようなサイトではどのように計測を行うのか、今回はその方法について書いていきたいと思います。

## Googleタグマネージャーを使えば簡単
![スクリーンショット 2024-11-07 175314.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/5271ca40-0740-edfd-bf99-d8b2249a85a6.png)

今回のケース、実はGoogleタグマネージャーを使うことで簡単に解決します。

タグマネージャーでは、設置するタグに合わせたトリガーを設定することでタグを発火(機能)させますが、
このトリガーのタイプを「フォームの送信」にするだけです。

これで、フォーム送信時にページが切り替わらない場合でも、フォーム送信CVを計測することが可能となります。

### まとめ
フォーム送信時に確認画面があるサイトでは、確認画面の時点で計測となってしまうため別途さらに設定が必要ですが、
Googleタグマネージャーを使用することで解決する場合が多いと思いますので、ぜひ参考にしてみてください。

以上、鈴木でした。
[小ネタ] java.util.List#sort で NullPointerException になったり、ならなかったり

# 環境
- java (amazon-corretto) 17.0.8


# どう違うか？
`["a", null]` のソートと `[null]` のソートでは NPE 発生有無の振る舞いが違う。

null の element が含まれていれば sort 時に NPE になるんだろなぁ、
と思ったら `[null]` のときは起きなくて「ん！？」となった。

## `["a", null]` のソート
```
jshell> List<String> s1 = new ArrayList<>();
s1 ==> []
jshell> s1.add("a");
$2 ==> true
jshell> s1.add(null);
$3 ==> true
jshell> s1.sort(String::compareTo);
|  例外java.lang.NullPointerException
|        at TimSort.countRunAndMakeAscending (TimSort.java:355)
|        at TimSort.sort (TimSort.java:220)
|        at Arrays.sort (Arrays.java:1307)
|        at ArrayList.sort (ArrayList.java:1721)
|        at (#4:1)
```

## `[null]` のソート
```
jshell> List<String> s2 = new ArrayList<>();
s2 ==> []
jshell> s2.add(null);
$6 ==> true
jshell> s2.sort(String::compareTo);     // <------- NPE にならない！
jshell> s2
s2 ==> [null]
```

# なんで？
想像付くかもしれませんが、size() <= 1 のときはわざわざソートするまでもないので、
sort() の中では即 return している都合上、element は参照されず NPE にもならない、ということ。

sort() に関連するユニットテスト書いていて NPE にならなかったので、ちょっとハマりました。
【Nuxt GitHub Pages】pages/hoge.vueでexample.com/hoge/←スラッシュが後につく問題【autoSubfolderIndex】


`nuxt.config.ts`を下記に修正しよう。SSGで`example.com/hoge/index.html`ではなく`example.com/hoge.html`が生成されるよ

```nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    prerender: {
      autoSubfolderIndex: false
    }
  }
})
```

https://nuxt.com/deploy/cloudflare#route-matching

folderのfは小文字にしてね！

https://github.com/nitrojs/nitro/issues/2129
ID_SERIAL_SHORTがない時にデバイスファイル名を同じにする方法

# 状況
マイコンとPCでシリアル通信を行いたい．
しかしUSBを刺す順番によって、表示されるデバイス名が変わってしまい面倒なので、いつも同じにしたい．
普通なら

```
udevadm info -q property -n {割り振られたデバイス名} |  grep -E "ID_SERIAL_SHORT=|ID_VENDOR_ID=|ID_MODEL_ID="
```
* ID_VENDOR_ID
* ID_MODEL_ID
* ID_SERIAL_SHORT
を取得して

以下参照のとおりにすればよい
[[Ubuntu20.04] Arduinoのデバイスファイル名を同じにする方法](https://qiita.com/ousagi_sama/items/1b403858113be2287583)

しかし，今回ID_SERIAL_SHORTがないマイコンに遭遇したため(安価なマイコンだとそういうこともあるらしい)，デバイスを認識することができなかった．



# 解決方法
その場合ファイルに書き込むのはID_SERIAL_SHORTを抜いた
```
SUBSYSTEM=="tty", ATTRS{idVendor}=="調べたID_VENDOR_ID", ATTRS{idProduct}=="調べたID_MODEL_ID",SYMLINK+="表示させたい名前", MODE="0666"
```
とすれば無事デバイスファイルを認識することができた．

# 最後に
記事に書くまでもなく当然なことだった．
しかしudevルールを全く知らない自分からしたら困惑したので記事にした．
整数211を2進数に直して遊ぶ(人力の時)

参考


https://www.foresight.jp/fe/column/binary-hexadecimal/



x 過去ログを見よ!!
x M5NanoC6での予定は、未定



いきなり答え 1101 0011


余り法を実際に人力で計算してみる



211 を 1/2する

105と1

余りは、1なので、メモ「1」

105  を 1/2する

 52と1

余りは、1なので、メモ「11」

 52   を 1/2する

 26と0

余りは、0なので、メモ「110」

 26  を 1/2する

 13と0

余りは、0なので、メモ「1100」

 13 を 1/2する

 6と1

余りは、1なので、メモ「11001」

 6 を 1/2する
 
  3と0

余りは、0なので、メモ「110010」


  3 を 1/2する

  1と1

余りは、1なので、メモ「1100101」

  1なのでメモ「11001011」


反対にすると
1101 0011
DjangoWebアプリをAWS EC2で動作させる

ローカルで開発した Django WebアプリをEC2で稼働できるようにするための手順。
事前にWebアプリはGitHubにアップロード済み。
静的ファイル収集とライブラリの出力もしておきます。
```py:settings.py
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
```
```
python manage.py collectstatic

pip freeze > requirements.txt
```

## EC2 の作成と設定
・ColoudFormation用のyamlファイルを作成してVPC, EC2Instance, InternetGateway, PublicSubnet, RouteTable, SecurityGroup を作成しておきます。
コンソールで作成してもOK お好きな方で。
(ここは各自設定が違うと思うので割愛)

・セキュリティグループにDjango用のポートを設定
カスタムTCP TCP 8000 Anywere-IPv4
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/bd716006-a126-dbba-241c-e2d595647143.png)

## EC2 へアクセス
・EC2の設定のためターミナルからアクセスします(VScode AWS-Cli を使用)。
パブリックIPの取得 -> ログイン
```sh
> aws ec2 describe-instances --filters "Name=instance-state-name,Values=running" --query "Reservations[*].Instances[*].[InstanceId,PublicIpAddress]" --output table
>>
------------------------------------------
|            DescribeInstances           |
+----------------------+-----------------+
|  i-***************** |  **.***.***.**  | <- $Public_IP
+----------------------+-----------------+

> ssh -i "セキュリティキーパス/ファイル名.pem" ec2-user@$PUBLIC_IP

   ,     #_
   ~\_  ####_        Amazon Linux 2023
  ~~  \_#####\
  ~~     \###|
  ~~       \#/ ___   https://aws.amazon.com/linux/amazon-linux-2023
   ~~       V~' '->
    ~~~         /
      ~~._.   _/
         _/ _/
       _/m/'
```

## Gitインストール -> Webアプリ Pull
```sh
sudo yum update -y
sudo yum install git -y

git clone <リポジトリのURL>.git
```
取り込まれたWebアプリのファイルが表示されればOKです
```sh
$ ls
CloudFormationTemplate.yaml  config          django_command.sh  manage.py          package.json    react_command.sh  templates
Lib                      connect_ec2.sh  ec2_command.sh     node_modules       pyvenv.cfg      requirements.txt  update_settings.py
Scripts                  db.sqlite3      equity_hub         package-lock.json  react-frontend  staticfiles       users
```

## 必要なライブラリインストール
事前にインストール済みのライブラリを requirements.txt に出力してWebアプリ内に保存していたのでまとめてインストール。
合わせてサーバー起動用のgunicorn, 静的コンテンツ公開用のwhitenoiseをインストール
```sh
pip install -r requirements.txt

pip install gunicorn

pip install whitenoise
```

## 実行確認
<webアプリディレクトリを私はconfig にしているので Webアプリ内で実行するときは
gunicorn config.wsgi:application --bind 0.0.0.0:8000 となります。
```sh
gunicorn <webアプリディレクトリ>.wsgi:application --bind 0.0.0.0:8000
```
おそらく Invalid HTTP_HOST header: が表示されたと思います。
settings.py 内の ALLOWED_HOSTS = [] 内にEC2のパブリックIPを指定しないといけません。

## ALLOWED_HOSTS 設定
```sh
sudo nano settings.py

ALLOWED_HOSTS = ["**.***.***.**"] <- Public_IP

＃入力後 CTRL + X, Y, ENTER
```
再度実行後[http://Public_IP:8000] にアクセス

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/2c6884ac-c81a-30a6-4d51-a5dfdfde2a75.png)

ページが表示されればOKです。

## 終わりに
・これで起動が確認できましたが、気になる点が2つ。
1:毎回ターミナルでサーバーを起動しないとWebアプリを使用できない。
2:EC2を一度停止するとPublic_IPが変わってALLOWED_HOSTS の変更が必要になる。

次回はこの対応を考えてみようと思います。
ROS2 サービス通信でサーバの処理が終わるまで待機したい

# やりたいこと
サービス通信で，クライアントがトリガーを投げたら，それを受け取ったサーバが処理を実行し終わるまで待ちたい
# 方法
spin_until_future_complete　を使う
サービスタイプはTrigerで実装した

```python:service_server.py
import rclpy
from rclpy.node import Node
from std_srvs.srv import Trigger #service type
 
import time
 
 
class ServiceServer(Node):
 
    def __init__(self):
        super().__init__('service_server')
        self.srv = self.create_service(Trigger, 'service_name', self.handle_request)
        self.get_logger().info('server is ready')
 
    def handle_request(self, request, response):
        self.get_logger().info('executing hundle_request')
        
        '''
        実行したい処理
        例
        time.sleep(10)
        '''
 
        response.success = True
        response.message = "finished"
        self.get_logger().info('finished hundle_request')
 
        return response
 
 
def main(args=None):
    rclpy.init(args=args)
    server = ServiceServer()
    rclpy.spin(server)
    server.destroy_node()
    rclpy.shutdown()
    
 
 
if __name__ == '__main__':
    main()
```

```python:service_client.py
from std_srvs.srv import Trigger #service type
import rclpy
from rclpy.node import Node
 
 
class ServiceClient(Node):
 
    def __init__(self):
        super().__init__('service_client')
        self.cli = self.create_client(Trigger, 'service_name')
        while not self.cli.wait_for_service(timeout_sec=1.0):
            self.get_logger().info('service not available, waiting again...')
        self.req = Trigger.Request()
 
    def send_request(self):
        self.get_logger().info('send a request')
        self.future = self.cli.call_async(self.req)
        rclpy.spin_until_future_complete(self, self.future)
        return self.future.result()
 
 
 
def main(args=None):
    rclpy.init(args=args)
 
    client = ServiceClient()
    response = client.send_request()
    #サーバの処理が終わるまで待機
    client.get_logger().info(response.message)
 
    client.destroy_node()
    rclpy.shutdown()
 
 
if __name__ == '__main__':
    main()
```
ノーコードツールとしてのChatGPT3.5と4o　～spring bootで簡単なアプリに機能追加してもらった～

2024/11/13～11/19の作業メモ

# ChatGPTで簡単なクイズアプリに機能追加してみた。

## 動作イメージ
![20241119_quizapp.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3562068/32e5e825-bfcc-f8b5-0110-294eb6de0a1f.gif)


## 目的
- 自習用のクイズアプリに機能追加したい。
- 無料でChatGPTの4o使えるということで、活用して何か動くものを作りたい。

## 状況
- 前回アプリを一つ作ってもらって以来メンテしてなかったので色々忘れてる。

https://qiita.com/kubo4ka/items/39bf9a35ab16a69bb229

## 制約
- コードは自分では書かない。提案されたものでDB含めて構築していく。
- 仕様は会話ログ参照。今回の対応はざっくりと三点。
  - 択複機能追加
  - クイズテーマ機能追加
  - 認証機能追加

## 1週間での状況
- 会話ログ

https://chatgpt.com/share/673c5b29-ebec-8008-8635-925d2ef32a26

↓

https://chatgpt.com/share/673c5b63-6c24-8008-bd90-872335e50a58

- ソース

https://github.com/kubo-4ka/quizapp/tree/master

- デモ

https://quizapp-xzmf.onrender.com

## これまでのまとめ
- 1年ぶりくらいの会話でも直ぐに対応してくれてありがたい。自分は全く何のことだかどの端末のどこのワークスペースだかも、renderやsupabaseの設定も頭から消えてました。
- 拡張性考えてなかったアプリを良い感じに実用的な改修提案してくれた。
- 会話が長くなったら新しいチャットにしてねとアドバイスくれたので、適当に会話を分けた。
- 4oと3.5の切り替わるタイミングで英語応答になった気がする。
- 多分4oの方がスマートに提案してくれている気がする。なるべく3.5では作業進めないようにした。
- 自分がある程度理解できて整理して会話したという点もあって、前回よりはスマートだったと思う。
- 相変わらず、エラーメッセージを連携した場合の解説は迅速で助かった。
- spring securityをさらっと導入してくれた。正しいかは要検証だが、取り敢えずは動いてる。
- 相変わらずwinmergeで提案してもらったコードと現状を比較して自分も理解して進めた。

## ノーコードか？
相変わらず、ノーコードではないと思う。

それでも、一人でこの短期間で3つも機能追加できなかっただろうし、
エラー対処やcssの細かな修正など、
確実に生産性は上がっている。
自分ひとりじゃできないことを可能にしてくれている。
ローコードではあると思う。

## 今回の時間かかった点
- 択複機能追加では、チェックボックスの維持実現に時間がかかった。redirectAttributes.addFlashAttributeの利用に至るまでが長かった。結局自分でｇｇってリダイレクトが原因じゃね？って指摘した。
- クイズテーマ機能追加では、テーマ単位での出題にならずに右往左往した。あと、作成してもらったクイズ内容の登録SQLがたまに正解整合性取れてなくてソースの問題かマスタレコードの問題か右往左往した。既存のテーブル設計が、「正解」を2カ所に保存してしまっているのが諸悪の根源だと思う。あとは命名規約とか事前の整理がないから場所によって変数名が被ったりずれたりで誤解が生じて時間がかかった。
- 認証機能追加では、簡単な認証で良いと思っていたが、結局結構手が入ったし、さっき提案してくれたソースと矛盾する提案をくれたりで時間がかかった。特定のクイズテーマだけ認証をかけたい、とずっと書いていても、全テーマ一律の制御しか提案されない点に時間がかかった。

## 今回のスムーズで感動した点
- 最後に、次回追加したい機能くらいのノリで相談した採点結果画面の結果一覧について、ほぼ提案とおりでスムーズに実装できた。
- クイズテーマの選択画面について、ただの一覧表をイメージしてたけど、カード形式を提案してくれて何か良い感じで凄いなと思った。
- ボタン配置、ヘッダ配置などはさっと意図を汲み取って提案してくれた。
- springsecurityのバージョンによって利用できる機能、できない機能、代替案など、さっと提案してくれる点はやはり、不慣れな言語やFWでの対応でありがたいと思った。

## 今回の見送った点
- スマホでの見栄え、操作性。
- 時間計測機能。
- 一つのテーマの中で、サブテーマの導入。
等々

＼(^o^)／ちょっと疲れた
この後は資格対策とかのクイズ内容をSQLにしてもらって、当初の目的である自習に進めるはず。

以上
GO言語におけるREST APIの実施

別サイトに投稿していました記事の再掲載シリーズです。
## はじめに

初めまして。
現在インターンでGo言語を使用したバックエンド関係の学習をしている新米エンジニアです。

今回から第1弾と第2弾でRESTとgRPCについて学んでいきたいと思います。
第1弾の今回は基礎的な学習を一度離れ、実際に簡単なREST APIを作成しました。
第2弾では実際にgRPCとRESTを比較をしていきたいと思います。

## 今回解決したい課題
第2弾のgRPC編までに、私の基礎的なGo言語の学習状況から抜け出しAPI周りを学習したいというのが今回解決したい課題です
## 解決方法
今回は実際に簡単なTODOのAPIを制作していくことで、課題解決に取り組みました。

## 解説

まず今回はGo言語のフレームワークであるGinをダウンロードしていきたいと思います
```go
go get github.com/gin-gonic/gin
```

次にTODOリストの構造体を作成し、それらをJSON形式に変換する流れを作ります。

```go
package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

type todo struct { 
	ID		string `json:"id"`
	Item		string `json:"title"`
	Completed	bool	`json:"completed"`
}

var todos = []todo{
	{ID:"1",Item:"部屋掃除",Completed: false},
	{ID:"2",Item:"本を読む",Completed: false},
	{ID:"3",Item:"買い物",Completed: false},
}

// jsonに変換
func getTodos(context *gin.Context){
	context.IndentedJSON(http.StatusOK, todos)
}
```

実際にサーバーを立ち上げ、これらの情報をGETするように書きます。
```go
func main() {
	router := gin.Default()
	router.GET("/todos",getTodos)
	router.Run("localhost:9090")
```

サーバーを立ち上げpostmanで確認すると情報が取得できていることがわかります。

```go
go run main.go
```

```
[GIN-debug] Listening and serving HTTP on localhost:9090
```

![](https://storage.googleapis.com/zenn-user-upload/6eb2ff82f127-20230520.png)

次に新たな情報をPOSTするための流れを作ります。
```go
func addTodo(context *gin.Context){
	var newTodo todo

	if err := context.BindJSON(&newTodo); err!= nil {
		return
	}

	todos = append(todos, newTodo)

	context.IndentedJSON(http.StatusCreated, newTodo)
}
```

そして以下の内容をPOSTする。
![](https://storage.googleapis.com/zenn-user-upload/620d44d2fdcf-20230520.png)

もう一度情報をGETすると、追加した情報が確認することができます。
![](https://storage.googleapis.com/zenn-user-upload/3977ac06889c-20230520.png)

## おわりに

今回はGinのフレームワークを使用した簡単なTODOのREST APIの作成でした。
まだgRPCには本格的に触れていませんが、やはりRESTのほうが視覚的にも分かりやすい構文ですし、相手が理解しやすいという点ではとて利点を感じます。
第2弾でgRPCを利用し、Go言語の並列処理などの利点等がどのように発揮できるのか楽しみです。

以上で今回の記事は終わらせていただきます。ご清聴ありがとうございました！！！

## 参考文献
https://www.youtube.com/watch?v=d_L64KT3SFM&list=PLcXb41AEl1Seo1LdC0Ff84fnzKBJYwCjY
DynamoDBのテーブルを作って手動でデータを入れてみる

## はじめに

こんにちは。
今回はDynamoDBテーブルを作って、手動でデータを入れてみました。

本記事は以下記事の続編です。

https://qiita.com/uccy/items/3100b14ce674c234b738

↓参考にしたハンズオンはこちら。

https://pages.awscloud.com/JAPAN-event-OE-Hands-on-for-Beginners-Serverless-1-2022-confirmation_422.html

## やってみた
では早速やってみます。
まずはマネジメントコンソールにアクセスし、DynamoDBのページにアクセスします。
「テーブルの作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/885ec994-95cb-ad6c-c029-29635a89affe.png)

テーブル名は「translate-history」、パーティションキーは「timestamp」とします。
ソートキーは何も指定しません。　
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/20e0c0b8-df1e-55c5-0cde-fe889a0b6fa7.png)

テーブル設定は「設定をカスタマイズ」を選択、テーブルクラスは「DynamoDB標準」とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/28916024-d40a-046f-78a3-ef1660a790df.png)

キャパシティーモードは「プロビジョンド」を選択します。
読み込み/書き込みのAuto Scalingはオフに設定しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/67c408d2-835f-43d5-aa67-c15d7bbfa2dd.png)

このまま下までスクロールして「テーブルの作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/7f4db5f1-f927-5b39-1d21-d83b9aa0a05b.png)

テーブルの作成が始まります。
1分程度待ったと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/92447629-c5ca-7265-894a-603dae23338f.png)

テーブルが作成されたようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/a748db55-674d-775e-c3aa-740eafea4d61.png)

データを格納してみます。
「アクション」をクリックして「項目を作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/f607c9a5-dcbc-c27d-eb34-8225d1de4a4a.png)

今回、パーティションキーはtimestampのみを指定しています。
20241117171300(2024年11月17日17時13分00秒)を入れてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/f6e6cf5a-38d8-6033-7c3c-1c16e73fad24.png)

更に項目を追加してみます。
「新しい属性の追加」をクリックして「文字列」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/717b04a0-605c-b287-2cfc-e524e69f0b46.png)

項目を2つ追加しました。
input_textに「★こんにちは」、outputに「★Hello」と入力しました。
後から追加した項目であることが分かるように、値に「★」を入れています。
入力後、「項目を作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/9e67ee5e-31fa-e9d0-bfb0-f2884009c02f.png)

項目と値が追加されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848705/09fe7367-07c5-ea70-48eb-3571eb83f929.png)

今回はここまでです。
次回は他サービスと連携して、APIが呼ばれたときに履歴情報をテーブルに保持するようにしてハンズオン終了になります。
文字列「8951」速く来いを整数に変換して遊ぶ


x 過去ログを見よ!!!
x M5NanoC6での予定は、未定
x ポケベルメッセージ

オンラインコンパイラ

```c++

#include <iostream>
using namespace std;
int main(void){
    // Your code here!
    char *a = "8951";
    int b;
    
    b = (a[0]-'0')*1000+(a[1]-'0')*100+(a[2]-'0')*10+(a[3]-'0');
    
    printf("b = %d\n",b);
    
}

```



```

b = 8951

```
【小ネタ】EC2+Dify環境でもIAMロールでS3にアクセスしたい

## はじめに
とあるEC2+Dify構成の検証で、ナレッジを作成する際にアップロードしたファイルをEC2のStorageではなくS3に格納させたい、となったときに公式ドキュメントを読んでいたらS3関連記述がぱっと見下記しかなく「BedrockをIAMロールで呼べるのにIAMアクセスキーでしかS3は使えないはずがなかろうよ」と調べたというのが出発点です。

https://docs.dify.ai/ja-jp/getting-started/install-self-hosted/environments#fairusutorji

```
S3_ENDPOINT：S3エンドポイントアドレス
S3_BUCKET_NAME：S3バケット名
S3_ACCESS_KEY：S3アクセスキー
S3_SECRET_KEY：S3シークレットキー
S3_REGION：S3リージョン情報（例：us-east-1）
```

結論問題なくIAMロールでアクセス出来ており、いつもならそれで終わりなんですがアクセスキー運用が世に広まるのは良くないので小ネタですけど書きました。

## IAMロールでS3にアクセスさせる
1. EC2には該当のS3へのアクセス権限を付与したIAMロールを適用

2. 事前にS3バケットを作成して`.env`を編集
※環境変数の渡し方は自身の環境に合わせてください

・参考

https://github.com/langgenius/dify/blob/main/docker/.env.example

### 変更前
```.env
STORAGE_TYPE=local
S3_USE_AWS_MANAGED_IAM=false
S3_ENDPOINT=
S3_REGION=us-east-1
S3_BUCKET_NAME=difyai
S3_ACCESS_KEY=
S3_SECRET_KEY=
```

### 変更後
```.env
STORAGE_TYPE=s3
S3_USE_AWS_MANAGED_IAM=true
S3_ENDPOINT=https://s3.us-east-2.amazonaws.com # 自身のS3バケットのリージョンエンドポイントを指定
S3_REGION=us-east-2　# 自身のS3バケットリージョンを指定
S3_BUCKET_NAME=xxxxxxx　# S3バケット名を指定
#S3_ACCESS_KEY=
#S3_SECRET_KEY=
```

## 終わりに
Dify上でナレッジを作成してファイルをアップロードすると指定したS3バケットの`upload_files/xxxx/`配下にオブジェクトが格納されているので各々確認してみてください。
Prerequisites For Taking The CKS Exam

Certified Kubernetes Security Specialist CKS Exam
The Certified Kubernetes Security Specialist (CKS) certification is a coveted credential for professionals skilled in securing container-based applications and Kubernetes platforms. This certification validates a candidate’s expertise in implementing security measures across the entire lifecycle, build, deployment, and runtime. To effectively prepare for this challenging exam, using a practice test is highly recommended. This [Kubernetes Security Specialist CKS Practice Exam](https://www.p2pexams.com/linux-foundation/pdf/cks) is designed to simulate the actual exam environment and help candidates sharpen their skills, ensuring they are well-prepared and confident when they sit for the exam. They are an essential resource for anyone looking to succeed in the CKS certification journey.

Who Is It For?
The Linux Foundation CKS exam is designed for accomplished Kubernetes practitioners who are already Certified Kubernetes Administrators (CKA). It is ideal for professionals who want to specialize in Kubernetes security and demonstrate their ability to apply best practices for safeguarding Kubernetes platforms and containerized applications.

Prerequisite for the Linux Foundation CKS Exam
Before pursuing the CKS certification, candidates must first earn the Certified Kubernetes Administrator (CKA) certification. This prerequisite ensures that candidates possess a foundational understanding of Kubernetes administration, enabling them to focus deeply on security-related aspects during the Kubernetes Security Specialist CKS exam preparation.

CKS Practice Test - Your Key To Success
If you are planning to take the CKS exam, it is crucial to thoroughly prepare to ensure success. I strongly recommend using a Linux Foundation CKS practice test as part of your preparation. These practice tests are highly effective in enhancing your understanding and readiness for the exam. Many candidates have found them indispensable for both exam preparation and passing the test. Every aspiring CKS candidate should make these practice tests an essential part of their study plan.
JISOU 課題2「学習記録アプリ」（データ永続化・テスト実装・CI/CD）振り返り

# はじめに

お疲れ様です、りつです。

参加させていただいているプログラミングスクール「[JISOU](https://projisou.jp)」の課題2がやっと完了しました！

今回は、その振り返り記事です。

# 何をやったのか

課題1で作成した学習記録アプリ（React + JavaScript）をコピーして新規のプロジェクトを作成しました。

https://github.com/ritsu21ctws/study-record

:::note info
ご参考までに、以下が課題1の振り返り記事です。
:::

https://qiita.com/ritsu21ctws/items/ae4a8302d4748ef5bcc0

その上で、課題2では以下を実施しました。
1. データベースによるデータ管理
2. テストコードの実装
3. GitHubActionsを用いたCI/CD

簡単にですが各詳細をご説明します。

## 1. データベースによるデータ管理
- Supabaseに`study-record`テーブルを作成しました
- 学習記録アプリの以下の部分を調整しました
  - データ読み込みのタイミングでローディング画面を表示するよう調整
  - 登録ボタン押下時に画面とテーブルにデータを追加するよう調整
  - 各学習記録の横に削除ボタンを追加し、ボタン押下時に画面とテーブル上から対象データを削除するよう調整

:::note info
補足
課題1では学習記録の追加には`useState`を使用しており、画面リロードを行うと追加したデータは消えてしまっていました。
:::


## 2. テストコードの実装
- React Testing Libraryを用いて、以下の4つのテストコードを実装しました
  - タイトル（「学習記録一覧」）が表示されている
  - フォームに学習内容と時間を入力して登録ボタンを押すと新たに記録が追加される
  - 削除ボタンを押すと学習記録が削除される
  - フォームに入力をしないで登録を押すとエラーが表示される

## 3. GitHubActionsを用いたCI/CD
- featureブランチからmainブランチへのプルリクエストを作成した際に以下を実行するようにしました
  - 自動でテストを実行
  - プレビュー用URLをPR画面のコメント欄へ表示
- mainブランチへマージすると、ホスティングURLに自動でデプロイされるようにしました

:::note info
GitHubActionsを用いてFirebaseへ自動デプロイする方法について、以下の記事を書きました。
:::

https://qiita.com/ritsu21ctws/items/408443f20f89b25a5a56

# 以前と比べてどのように成長したのか

課題2では、初めてSupabase、Firebase、GitHubActionsを使用しました。

いずれも名前は聞いたことがあるものの、どのようなことができるのかイメージできていない状態からのスタートです。

「何ができるのかいまいちわからない」ところから、「それらを使ってアプリを動かせる。簡易的にでもCI/CDできる」ところまでいけたところが一番成長を感じた部分です。
（実務で使用するとなると、まだまだ考慮すべき点はたくさんあるかと思いますが）

実際に使ってみることで、それぞれのサービスの便利さもより実感できたように思います。

# 大変だったところや工夫したところ

今回特に大変だったのは、テスト実装の部分とCI/CDの部分でした。
特に、ローカル環境で成功するテストがCI環境でエラーになる現象には、3日くらい頭を悩ませました(^^;)

テストケースが悪いのか？
はたまたワークフローのymlファイルの記述内容が悪いのか？

なかなか原因がつかめず、テストコードやGitHubActionsのymlファイルをちょっとずつ書き換えたり、実行ログを確認したりして進めました。

:::note info
本事象を解消した方法については以下の記事もご参照ください。
:::

https://qiita.com/ritsu21ctws/items/7f66315ab3ade8565c10

あとは、できるだけ公式のドキュメントも参考にするよう意識しました。

とはいえ、英語でなかなか内容をつかみ取れなかったりする部分もあるので、以下も活用しつつ理解できるよう努めました。
- 翻訳機能
- サンプルコードを使って説明してくれているサイトを見てみる
- Chat GPTに聞いてみる

# 気づきなど

今回、CI環境がローカル環境より動作が遅くなる可能性があることを想定できずハマりました。

環境起因であることに気づけず原因がつかめなかったので、エラーが出た際には環境が原因の可能性も頭の片隅に置きつつ、引き続き学習していけたらなと思います。

# おわりに

課題2では、自分の作ったアプリをDBを使ってデータ保持できるようにしたり、CI/CDを用いて開発～デプロイまでスムーズに行えるようにしました。

表側からはわかりにくいけれど重要な機能に触れる機会が多くあり、大変勉強になりました。
次はTypeScriptの学習も始まりますので、改めて学習頑張っていきたいと思います！

# おまけ

実はこの記事でQiita10記事目なんですよね。
JISOUに入る前は、自分がここまでQiitaにアウトプットできるなんて想像もできませんでした。

日々少しずつではありますが、作業を進めて、悩んだ部分や詰まった部分はアウトプットの種と思って取り組んできました。

こうして振り返った時に日々の積み重ねを実感できるのもアウトプットの良い面だなと思いつつ、おわりたいと思います！

# JISOUのメンバー募集中！
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？
興味のある方は、ぜひホームページをのぞいてみてくださ！
▼▼▼

https://projisou.jp
Jenkinsへの手動プラグイン導入方法

Jenkinsのバージョンが最新でない場合、互換性や依存関係の問題でプラグインのインストールが軒並み失敗することがある
その場合のインストール方法メモ

# プラグインファイル(.hpi)のダウンロード方法
https://updates.jenkins.io/download/plugins/
上記サイトから必要なプラグインをバージョン指定してダウンロード
「Requires Jenkins x.y.z」と自分のJenkinsバージョンを比べてインストール条件を満たすプラグインバージョンを選択
![スクリーンショット 2024-11-19 18.28.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298813/17a1230d-99f7-5b9c-9517-3ed3a63844bc.png)


# プラグインのインストール
Jenkinsの管理 > プラグインの管理 > 高度な詳細
画面の「プラグインのアップデート」から、hpiファイルをアップロードする
ダウンロードしたhpiファイルのバージョンが古いものだったとしても、これに依存するプラグインがインストールされていない場合、依存プラグイン側は一番新しいバージョンをインストールしようとするので、依存プラグインの方から互換性を満たすものを一つづつインストールしていく
![スクリーンショット 2024-11-19 18.22.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298813/56fa7e1d-4bd2-4121-db06-4cb81eb8a24b.png)
ハッカソンで最優秀賞を獲って思うこと

**Qiita初投稿です！**

先日，ハッカソンに参加して最優秀賞を頂いたので，それに関してQiitaデビュー戦としてなにか記事を書いてみようというマインドになった．

最優秀賞を目標にしていたので結果には非常に満足しているのだが，一旦気を引き締め直して，**開発期間に取り組む中でこだわった事**，**参加して感じた事**，**アドバイス**を深堀していこうと思う．

:::note warn
技術的な話は一切しません．かと言って根性論でもありません．普遍的な所を探っていきます．
:::


# Open Hack U
今回，私が参加したのは「Open Hack U」．
LINEヤフーが開催する，学校や学年の垣根を超えた学生ハッカソンイベントで，参加条件は「学生であること」だけ！

Open Hack Uの他にも，「個別開催 Hack U」という名の，Hack U教育機関とLINEヤフーが共同開催するHack Uもあるそう．近いうちにあなたの大学が会場となるかもしれないのでチェックしてみてはいかがでしょうか．

https://hacku.yahoo.co.jp/about/




# チーム編成

私は今までハッカソンなるものに参加した経験はなかったので，これが初めてのハッカソン．
研究室の同期5人とチームを組んで，1つの作品を作ろう！となったのが発表日の2か月前（9月）．
ちなみに私たちの専門領域は，「コンピュータビジョン」，「機械学習」，「深層学習」，「仮想現実」といったところ．

このハッカソンで作り上げた作品にも，深層学習の知識とVRをふんだんに使った．

参加者の中で，6人編成のチームは私たちだけだった（次に多かったのが5人編成）が，私たちが最優秀賞を獲ることができたのは「6人編成を活かしまくった」からだと思っている．


私たちのチーム編成と役割はこの通り．

:::note
:stew:：ハッカソンの猛者（参加回数10回いくとかいかないとか），Unity芸人
:ramen:，:robot:：ハッカソン経験アリ．深層学習コーディング担当．
:athletic_shoe:，:dancers:，:coffee:(me)：ハッカソン経験ナシ，Unityサポート担当
:::

厳密にいえば，細かいタスクの割振りが異なるが，大まかにまとめるとこうなる．

早速書いたことと異なるのだが，私は:stew:(Unity)のサポート役というよりかは，**タスクマネージャー兼コンテンツデザイナー**として動いた．
「コンテンツデザイナー」とは私の造語で，作品の一部のUIをデザインしたり，現地での発表の時に見せる資料の作成を担当した．




# 開発期間中にこだわった事

一言でいえば，**見やすさ**に尽きると思う．

ハッカソンのような公共の場では，自分たちが自由に使える発表時間には限りがある．
そのうえ，3~5分と決して長いものでもない．
その短時間で聞き手の心をつかんで，一つでも多く情報を伝えるには**見やすい資料**は必須である．
きつい言葉でいえば「必須」というより「大前提」に近いだろう．

私が思う「見やすい資料」とは **「目のやり場に困らない資料」** だと日々思っている．

いま，あなたは概要すら知らない未知の発表会の聞き手であるとしよう．

何も知らないあまり，あなたは発表者の説明を聞くのと同時に，プレゼン資料など視覚からも情報を得ようとするだろう．
その時にプレゼン資料が煩雑なものだったらどうだろうか．
発表者は今どこを説明しているのか分からくなったり，話している言葉でさえ理解できなくなるかもしれない．


ハッカソンのような3~5分の短い発表でこんなことがあっては致命傷だ．

では，どうすればいいのか．
- 情報量を増やし過ぎない＝**細かいことは書かない**
- **ぱっと見での情報量が，聴衆の第一印象を決める**ことを意識する
- **色使い**には慎重になる

この3点を抑えるだけでも，私は見やすい（目のやり場に困らない）資料になると思っている．（研究の進捗報告で作成する資料もこれはマストだと思っている）


それでも

- 「発表時間も有限だけど，開発期間も有限じゃん...」
- 「小規模チームだと発表資料に掛けられる時間も人も足りない...」

という意見もあるだろう．
そういった意見への根本的解決策を示すことはできないが，
（チームを大人数にするor計画的に開発を進めるしかない）
**発表資料の見やすさは，作品の技術力の高さ以上に評価を左右するもの**
であることは忘れてはいけない．


話を戻すと，
幸いにも，私たちのチームには発表資料作成に注力するメンバーを1人分確保できた（今回はそれが私だっただけの話）ので，資料作成に他の参加チームよりも時間を費やせたのが勝機だったと考えている．


# 参加して感じた事
- エンジニア界隈がよく言う，「開発期間の完徹」は意外と近いところに潜んでいる．
- 大がかりな作品であればあるほど，資料作成係として1人は確保するべき
- メンバーのタスクをお互いに共有できるタスク管理ページを作った方が良い（私はNotionで作った）
- 他チームとの技術的な差はあまりなく，差別化できる要素はデザイン性や将来性だったりする．



# これから参加される方へのアドバイス(準備ver.)
- ハッカソンは実際に動くモノがあると評価されやすい．
- 展示会（他チームの作品に触れる時間）がある場合，テーブルや椅子に貼る用の広告のようなものを作っておくと，他チームと差別化できる．
（私たちはYoutubeのサムネのようなものを製作してテーブルに貼ったのがウケた）
- 発表資料とは別に，製作中にこだわった技術的な要素などをまとめた補足資料を用意するといい．
- 発表スライドの1枚目はとことんこだわれ（静止画ではなくアニメーション付きのタイトルページとか）


# おわりに
初めてハッカソンに参加した身なのに所々大口をたたいてしまった気がしますが，開発期間を含め，非常に濃密で楽しかったです．
まだハッカソンに出たことない方は，身近に経験者がいれば壁を恐れずに是非ついて行ってみてください．きっと楽しい思い出になるはずです．
pip installで警告がでた話

# はじめに
`pip install 〇〇`を実行したところ、警告が表示されてしまいました。この記事ではその対処法を紹介します。
なお、表示された警告は``WARNING: Ignoring invalid distribution ~ip (C:\Python312\Lib\site-packages)``でした。少しでも参考になれば幸いです。

# この警告の解説
この警告メッセージは、`pip`がPythonの`site-packages`ディレクトリ内で、破損または不完全なパッケージ（ディストリビューション）を検出した際に表示されるものだそうです。どうやら、その破損しているものを取り除くことで解消されるらしいです。
次に、私が実際に試した方法をまとめます。

# 対処法
### 対処法１：破損したパッケージを探す
ターミナル上で以下のコマンドを実行します。

```
pip list
```

すると、インストールされているパッケージ名とそのバージョンが表示されるので、その中から不明なもの（`~ip`など）を探し、もし見つかれば削除しましょう。ちなみに、私の場合は見つからず、次の方法を試しました。

### 対処法２：`pip`自体をアップグレードする
以下のコマンドを実行すると最新の`pip`をダウンロードすることができます。

```
python -m pip install --upgrade pip
```

最新のバージョンを利用すればうまくいくこともあるようですが、私の場合は効果がなかったです。

### 対処法３：ファイルの手動削除
私はこの方法で警告がでなくなりました。最後はコマンドを打たずに自力で探しましょう。
警告メッセージ内に書かれている`C:\Python312\Lib\site-packages`を開いて`~ip`関連のものを手動で削除しましょう。
なお、私は削除して復元できないことを危惧して一応バックアップをとっておきました。（コピーしてデスクトップ上に一時保存しておきました）

作業が完了したら、もう一度`pip install`を実行して、警告がでないことを確認してください。

# おわりに
無事警告メッセージがでないようにすることができたでしょうか？もし手助けになれなかったら申し訳ないです。
では、短いですが今回の記事はここまでです。最後までお読みいただきありがとうございました。

# 参考
https://note.nkmk.me/python-pip-usage/

https://stackoverflow.com/questions/68880743/why-do-i-get-this-when-using-pip-warning-ignoring-invalid-distribution-ip
ddコマンドでAlmaLinuxUSBインストーラを作成する

# 0.はじめに
2024/11/18にAlmaLinux9.5がGAとなりました。

https://almalinux.org/blog/2024-11-18-announcing-95-stable/

RHEL9.5が出たのが2024/11/13ですので、なんと5日で出した事になります。ヒューッ! 
betaで動いてたにしても、やはり早いと言わざるを得ないです。

今回は、AlmaLinuxを使って、AlmaLinux9.5のインストーラをUSBメディアに焼き込む手順を紹介したいと思います。

:::note
大抵の皆さんはWindowsを使える環境にあると思いますので、そんな場合はRufusを使うのが単純で簡単です。
:::

https://rufus.ie/ja/

# 1.isoのダウンロード
まずはISOを取得します。
以下コマンドから自分の使いたいメディアイメージのものを選択して実行し、待ちます。

```bash
# minimalの場合
curl -O https://repo.almalinux.org/almalinux/9.5/isos/x86_64/AlmaLinux-9.5-x86_64-minimal.iso

# bootの場合
curl -O https://repo.almalinux.org/almalinux/9.5/isos/x86_64/AlmaLinux-9.5-x86_64-boot.iso

# DVD の場合
curl -O https://repo.almalinux.org/almalinux/9.5/isos/x86_64/AlmaLinux-9.5-x86_64-dvd.iso
```

##### minimalをダウンロードした実行例
```bash
[root@AL94 ~]# curl -O https://repo.almalinux.org/almalinux/9.5/isos/x86_64/AlmaLinux-9.5-x86_64-minimal.iso
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 2026M  100 2026M    0     0  45.8M      0  0:00:44  0:00:44 --:--:-- 57.4M
```

# 2.USBの準備
- `lsblk`コマンドで今の状態を確認します。

##### 実行例
```bash
[root@AL94 ~]# lsblk
NAME               MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda                  8:0    0   10G  0 disk
├─sda1               8:1    0  600M  0 part /boot/efi
├─sda2               8:2    0    1G  0 part /boot
└─sda3               8:3    0  8.4G  0 part
  ├─almalinux-root 253:0    0  7.4G  0 lvm  /
  └─almalinux-swap 253:1    0    1G  0 lvm  [SWAP]
sr0                 11:0    1 1024M  0 rom
```



- USBメモリを差します。
※USBメモリの中に入っているデータは上書き削除されるので注意して下さい。

- 再度`lsblk`コマンドを実行して、USBのデバイスファイルを確認します。
※今回の場合は`sdb`がUSBデバイスに該当します。

##### 実行例
```bash
[root@AL94 ~]# lsblk
NAME               MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda                  8:0    0   10G  0 disk
├─sda1               8:1    0  600M  0 part /boot/efi
├─sda2               8:2    0    1G  0 part /boot
└─sda3               8:3    0  8.4G  0 part
  ├─almalinux-root 253:0    0  7.4G  0 lvm  /
  └─almalinux-swap 253:1    0    1G  0 lvm  [SWAP]
sdb                  8:16   1 58.2G  0 disk        ←これがUSB
sr0                 11:0    1 1024M  0 rom
```


# 3.ddコマンドの実行
大抵のLinuxであれば標準で入っている、`dd`コマンドというものを使う事で、isoをUSBに書き込むことができます。
`dd`コマンドは以下のように実行します。
```bash
dd if=ファイル名 of=デバイスファイル名
```

今回ダウンロードした、AlmaLinux9.5は、`/home/yoyo`配下に保存したので、`if`は`/home/yoyo/AlmaLinux-9.5-x86_64-minimal.iso`を、デバイスファイルはsdbだったため、`of`は`/dev/sdb`を指定します。

また、`bs=4M`(書き込むブロックサイズを4Mにする)、`status=progress`(進捗を表示する)も追加します。
ちなみに、`if=input file`,`of=output file`,`bs=block size`と理解すると覚えやすいです。

##### 実行例
```bash
sudo dd if=/home/yoyo/AlmaLinux-9.5-x86_64-minimal.iso of=/dev/sdb bs=4M status=progress
2122317824 bytes (2.1GB,2.0 GiB)copied, 98 s,21.6MB/s
506+1 レコード入力
506+1 レコード出力
2124414976 bytes (2.1GB,2.0 GiB)copied, 98.1341 s,21.6MB/s
```

以上で終了です。あとは適当にUSBを抜いて、新端末へのインストールなどにお使い下さい。
Javaのプログラムが実行されるまでの一連の流れ

# Javaプログラムの実行プロセス ～JVMとバイトコードの仕組み～

JAVAerのみなさん、こんにちは。Javaを使用していると、「JVM」や「バイトコード」という用語をよく耳にします。これらはJavaの実行モデルの核となる概念であり、Javaの大きな特徴である「Write Once, Run Anywhere（一度書けば、どこでも実行できる）」を実現する重要な要素です。この記事では、Javaプログラムが実際にどう実行されているのかを自分なりにまとめたいと思います。



## 1. Javaプログラムの実行環境と開発ツール

### 1.1 Javaプログラム実行の流れ

Javaプログラムは次の手順で実行されます。

1. **ソースコードの作成**  
   ・開発者がJava言語でソースファイル(.java)を作成
   ・main()メソッドを含むクラスを定義

2. **バイトコードへのコンパイル**  
   ・Javaコンパイラ(javac)がソースコードをコンパイル
   ・バイトコードを含むクラスファイル(.class)が生成される

3. **JVMによる実行**  
   ・JVM（Java Virtual Machine）がバイトコードをその環境に適した機械語に変換
    ・変換された機械語コードが実行される

#### JVMの役割
- **移植性の実現**：異なるOS間で同じバイトコードを実行可能にします。
- **実行環境の提供**：メモリ管理や例外処理などを統一的に行います。

#### プロセス終了コード
JVMはプログラム終了時に次の終了コードを返します：
- `0`: 正常終了
- `1`: 例外やエラーが発生した場合

   ↓ 私はIntelliJを使用しているのですが、こんなメッセージがターミナルに出力されます。
   ![スクリーンショット 2024-11-19 18.10.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3915254/73708747-fc2a-090a-ad7d-0298aa5bc64d.png)


---

## 2. Java Development Kit（JDK）の役割と構成

### 2.1 JDKとは
JDK（Java Development Kit）は、Javaプログラムの開発および実行に必要なツールセットです。以下のような主要コンポーネントが含まれています：

- **コンパイラ（javac）**：ソースコードをバイトコードに変換します。
- **JVM（java）**：バイトコードを実行します。
- **開発ツール**：デバッガ、JARパッケージ作成ツール、ドキュメント生成ツール（Javadoc）など。

### 2.2 シンプルな開発環境の構築
Javaの開発を始めるには、JDKをインストールするのが最も簡単です。[Oracleの公式サイト](https://www.oracle.com/java/technologies/downloads/)からダウンロードできます。インストール後は、環境変数を適切に設定し、ターミナルやコマンドプロンプトでJavaコマンドを実行できるようにします。

---

## 3. 「Write Once, Run Anywhere」を実現する仕組み

Javaの移植性の高い特徴は、以下の仕組みによって支えられています：
- **バイトコード**：OSに依存しない中間表現を採用。
- **JVM**：OSやハードウェアに応じた機械語に翻訳。

これにより、Javaプログラムは1度コンパイルすれば、異なるプラットフォーム上で再コンパイルすることなく動作します。

---

## 4. 実際に見てみる

実際にJavaプログラムのコンパイルから実行までの流れを見ていきます。

### 4.1 サンプルプログラムの作成

シンプルな「Hello」と出力するだけのプログラムを作成してみましょう。
![](https://storage.googleapis.com/zenn-user-upload/1e419e3e791a-20241119.png)

ディレクトリに移動して、`ls`コマンドで確認できます。
![](https://storage.googleapis.com/zenn-user-upload/631b9404faa5-20241119.png)

### 4.2 バイトコードへのコンパイル
`javac`コマンドでソースコードをコンパイルすると、バイトコードを含む```Hello.class```が生成されます。
`ls`コマンドで、新しく`.class`ファイルが作成されたことが確認できます。
![](https://storage.googleapis.com/zenn-user-upload/b9cefae5ee72-20241119.png)

IDE内でも確認できます。
![](https://storage.googleapis.com/zenn-user-upload/f83758b62b4e-20241119.png)

### 4.3 実行
```java```コマンドで実行できます。この時、ファイル名ではなくクラス名を指定します。
ソースファイルで書いた通り、`Hello`と返ってきました。
![スクリーンショット 2024-11-19 17.09.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3915254/838243b6-b136-0752-e171-9ae9888c7b2e.png)


## 5. まとめ

本記事では、Javaプログラムがどのように実行されるのか、JVMとバイトコードの役割を中心に解説しました。また、Java開発に欠かせないJDKについても取り上げました。Javaの高い移植性はこれらの仕組みによって支えられています。ぜひ実行環境への理解を深め、より効率的で堅牢な開発を目指していきましょう！
cursorでLive Shareを使用する際の注意点

## 概要
cursorでLive Shareを使用する際はバージョンダウンする必要がある。
`v1.0.5936`をインストールする。

## バージョンを下げる手順
拡張機能としてインストールしたLive Shareを開く
アンインストールの右側にある矢印ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3469454/108c8078-da77-c479-73d9-61be229773d7.png)

特定のバージョンをインストール　をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3469454/d6470bb8-c10b-6b19-c8cd-251338522a40.png)

`1.0.5936`を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3469454/eea5afc5-76df-7c0d-efef-95f611be8e9a.png)


拡張機能の再起動 と 自動更新 のチェックを外すのをお忘れなく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3469454/be8bcd78-16a5-c4ac-cb31-942869cdfdfb.png)


## 補足
うっかり更新してしまわないように注意。
(一度やらかしたためにこの記事が生まれていたりする)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3469454/f5a63729-b7a1-7e76-34a2-ae4fdd8412eb.png)


参考サイト

https://forum.cursor.com/t/live-share-stopped-working-after-upgrading-to-mac-os-15-sequoia/17575/8
Advent of code 2015 Day 3 Part 2 を Livebook で楽しむ

## はじめに

Advent of code 2024 の準備として、過去回の Advent of code 2015 を Livebook で楽しみます

本記事では Day 3 の Part 2 を解きます

問題文はこちら

https://adventofcode.com/2015/day/3

実装したノートブックはこちら

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/aoc/2015/2015_day3_part2.livemd

Part 1 はこちら

https://qiita.com/RyoWakabayashi/private/e97fa04a1f8536ef1acc

## セットアップ

Kino AOC をインストールします

```elixir
Mix.install([
  {:kino_aoc, "~> 0.1"}
])
```

Kino AOC の使い方はこちらを参照

https://qiita.com/RyoWakabayashi/items/3d3abcf9134cee4dff05

## 入力の取得

"Advent of Code Helper" スマートセルを追加し、 Day 3 の入力を取得します

![スクリーンショット 2024-11-19 18.08.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/1845ddd1-21c9-39ff-81e9-ca35d94f8a2b.png)

## 私の答え

私の答えです。
折りたたんでおきます。
▶を押して開いてください。

<details><summary>回答</summary>

`Enum.reduce` で以下のものを保持しながら進めます

- 移動するのがサンタ(`0`)かロボサンタ(`1`)か: `s`
- サンタの現在地の座標: `{sx, sy}`
- ロボサンタの現在地の座標: `{rx, ry}`
- 通過した場所の座標配列: `houses`

`s` をトグルしながらサンタとロボサンタの座標を更新しつつ、通過した座標を記録して行きます

最後に `houses` の重複を排除して個数を算出します

```elixir
puzzle_input
|> String.codepoints()
|> Enum.reduce({{0, {0, 0}, {0, 0}}, [{0, 0}]}, fn direction, {{s, {sx, sy}, {rx, ry}}, houses} ->
  {x, y} = if s == 0, do: {sx, sy}, else: {rx, ry}

  new_point =
    case direction do
      ">" -> {x + 1, y}
      "<" -> {x - 1, y}
      "^" -> {x, y + 1}
      _ -> {x, y - 1}
    end

  new_sr =
    if s == 0 do
      {1, new_point, {rx, ry}}
    else
      {0, {sx, sy}, new_point}
    end

  {new_sr, [new_point | houses]}
end)
|> elem(1)
|> Enum.uniq()
|> length()
```

</details>

## まとめ

問題文から ChatGPT に画像を生成してもらいました

![robo_santa.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/45dc43b1-4cb4-1ab7-ff16-319f1c36762a.jpeg)

サンタとロボサンタを行ったり来たりするので少し複雑になりましたが、まだ素直に書けば通りますね
Advent of code 2015 Day 3 Part 1 を Livebook で楽しむ

## はじめに

Advent of code 2024 の準備として、過去回の Advent of code 2015 を Livebook で楽しみます

本記事では Day 3 の Part 1 を解きます

問題文はこちら

https://adventofcode.com/2015/day/3

実装したノートブックはこちら

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/aoc/2015/2015_day3_part1.livemd

## セットアップ

Kino AOC をインストールします

```elixir
Mix.install([
  {:kino_aoc, "~> 0.1"}
])
```

Kino AOC の使い方はこちらを参照

https://qiita.com/RyoWakabayashi/items/3d3abcf9134cee4dff05

## 入力の取得

"Advent of Code Helper" スマートセルを追加し、 Day 3 の入力を取得します

![スクリーンショット 2024-11-19 18.08.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/1845ddd1-21c9-39ff-81e9-ca35d94f8a2b.png)

## 私の答え

私の答えです。
折りたたんでおきます。
▶を押して開いてください。

<details><summary>回答</summary>

`Enum.reduce` で「現在地の座標」 `{x, y}` と通過した場所の座標配列 `houses` を保持しながら進みます

最後に `houses` の重複を排除して個数を算出します

```elixir
puzzle_input
|> String.codepoints()
|> Enum.reduce({{0, 0}, [{0, 0}]}, fn direction, {{x, y}, houses} ->
  new_point =
    case direction do
      ">" -> {x + 1, y}
      "<" -> {x - 1, y}
      "^" -> {x, y + 1}
      _ -> {x, y - 1}
    end

  {new_point, [new_point | houses]}
end)
|> elem(1)
|> Enum.uniq()
|> length()
```

</details>

## まとめ

問題文から ChatGPT に画像を生成してもらいました

![santa.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/25dd276b-aad0-a41e-a040-9860ed6da978.jpeg)

少し問題がややこしくなってきましたね

Part 2 はこちら

https://qiita.com/RyoWakabayashi/private/56f2e05684578258d7d5
PowerApps 2000件以上のデータを取得したい場合

# データ件数を4000件以下の場合
![image13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368087/011d983a-9082-7488-1856-5c18df66045f.png)

```
// Concurrent で前半、後半取得を同時実行
Concurrent(
    // 前半のデータを取れるだけ取得
    ClearCollect(
        col_datalistChunk1,
        Sort(
            datalist,
            ID,
            SortOrder.Ascending
        )
    ),
    // 後半のデータを取れるだけ取得
    ClearCollect(
        col_datalistChunk2,
        Sort(
            datalist,
            ID,
            SortOrder.Descending
        )
    )
);
// ClearCollect は複数のレコードまたはテーブルを指定可能
ClearCollect(
    col_datalist2,// ギャラリーのデータソース
    col_datalistChunk1,// 前半のデータ
    Filter(// 後半のデータから前半のデータを除外
        col_datalistChunk2,
        Not(ID in col_datalistChunk1.ID)
    )
);
Clear(col_datalistChunk1);
Clear(col_datalistChunk2);
```

# 参考サイト
https://itc-engineering-blog.netlify.app/blogs/powerapps-over2000
ABC378参加記録　by Python

# リアルタイムに解けた問題

## [A - Pairing](https://atcoder.jp/contests/abc378/tasks/abc378_a)

### 問題文
４個のボールがあり、$i$個目のボールの色は$A_{i}$です。
同じ色のボールは２つ選び両方捨てるという操作を最大何回行えるか求めてください。

### 制約
- $A_{1},A_{2},A_{3},A_{4}$はそれぞれ１以上４以下の整数

### アルゴリズム
リストの要素が1種類であれば、同じ色のボールを捨てる処理を2回行えるので、2を出力。for文で各要素を確認し、重複する値があれば、countを1増やす。最後にcountの数値を出力。

### ソースコード
``` python
A = list(map(int, input().split()))

count = 0

if len(set(A)) == 1:
  print(2)
  exit()

for i in range(4):
  if count == 2:
    break
  
  num_count = 0
  for a in A:
    if i+1 == a:
      num_count += 1
  
  if num_count >= 2:
    count += 1
    
print(count)
```

## [B - Garbage Collection](https://atcoder.jp/contests/abc378/tasks/abc378_b)

### 問題文
AtCoder市では、$N$種類のゴミを定期的に収集しています。$i(=1,2,...,N)$種類目のゴミは、日付を$q_{i}$で割ったあまりが$r_{i}$の日に収集されます。

$Q$個の質問に答えてください。$j(=1,2,...,Q)$番目の質問では、$d_{j}$日に$t_{j}$種類目のゴミが出ときに、次にそれが収集される日を答えてください。

ただし、$i$種類目のゴミが出た日が、$i$種類目のゴミが回収される日であった場合、そのゴミは同じ日に収集されるとします。

### 制約
- $1 \leq N \leq 100$
- $0 \leq r_{i} < q_{i} \leq 10^{9}$
- $1 \leq Q \leq 100$
- $1 \leq t_{j} \leq N$
- $1 \leq d_{j} \leq 10^{9}$
- 入力はすべて整数

### アルゴリズム
$q$日周期で$r$日目から始まる収集に対し、指定日(day)がちょうど収集日なら当日を、そうでなければ$(day//q)*q+r$で同じ期間内の収集日を計算し、それが過去なら次の周期(+q)を返す。

### ソースコード
``` python
N = int(input())
QR = []
for _ in range(N):
  q, r = map(int, input().split())
  QR.append((q, r))

Q = int(input())
TD = []
for _ in range(Q):
  t, d = map(int, input().split())
  TD.append((t - 1, d))

answers = []
for garbage_type, day in TD:
  q, r = QR[garbage_type]
  
  if day % q == r:
    answers.append(day)
    continue
  
  current_period = (day // q) * q + r
  
  if current_period <= day:
    current_period += q
  
  answers.append(current_period)
  
for answer in answers:
  print(answer)
```


## [C - Repeating](https://atcoder.jp/contests/abc378/tasks/abc378_c)

### 問題文
長さ$N$の正数列$A=(A_{1},A_{2},...,A_{N})$が与えられます。以下では定義される長さ$N$の数列$B=(B_{1},B_{2},...,B_{N})$を求めてください。

- $i = 1,2,...,N$について、$B_{i}$を次のように定義する：
　- $A_{i}$と等しい要素が$i$の直前に出現した位置を$B_{i}$とする。そのような位置が存在しなければ$B_{i}=-1$とする。
　  より正確には、正整数$j$であって、$A_{i}=A_{j}$となる$j<i$が存在するならば、そのうち最大の$j$を$B_{i}$とする。そのような$j$が存在しなければ$B_{i}=-1$とする。

### 制約
- $1 \leq N \leq 2 × 10^{5}$
- $1 \leq A_{i} \leq 10^{9}$
- 入力はすべて整数

### アルゴリズム
辞書(key)を使って各数値の最後に出現した位置を記録し、数値が既に辞書にあればその位置を出力して更新、なければ-1を出力して新規登録。

### ソースコード
``` python
N = int(input())

A = list(map(int, input().split()))

key = {}

for i in range(N):
  if str(A[i]) in key:
    print(key[str(A[i])], end=' ')
    key[str(A[i])] = i + 1
  else:
    print(-1, end=" ")
    key[str(A[i])] = i + 1
    
print()
```