OmniAICreator/Qiita-1.07M huggingface dataset:
Aurora MySQL 2から3へのバージョンアップで挙動が変わるSQL(2)

こんにちは。

本投稿では、Aurora MySQL 2 の EOS 対策として Aurora MySQL 3 へのバージョンアップ(MySQL 5.7からMySQL 8へのバージョンアップ)を検証した際に、Aurora MySQL 2で実行できていたSQLが3で実行できなくなるという情報をいただいたので、実際にそのSQLをSQLテストツール(Insight SQL Testing)を使って確認してみた例を紹介します。

## はじめに

Auoroa MySQL 2から3 (MySQL 5.7から8) へのバージョンアップを考えた際、以下の変更点などのMySQLのドキュメントを参照することの多いのではないでしょうか？

https://dev.mysql.com/doc/refman/8.0/en/upgrading-from-previous-series.html#upgrade-sql-changes

ここに書いてある変更がどんなものか、自分たちのサービスやアプリケーションで使用していないか、それらを探すのは骨の折れる作業だと思います。また、ここに書かれている内容以外にも何か影響にあるものがあるとしたら、考えるのも嫌になりますね！

今回ご紹介するSQLは、まさにそういった「変更点」としては含まれていないSQLの挙動の変更になります。

## 対象のSQL

対象のSQLは以下のようなSQLです。

```sql
select 
  *
from
  emp
where
  hiredate >= '1981-05'
```

Web検索で調べてみたところ、以下のように問題に直面している例もありました。なかなかこういった非互換を検出するのはとても難しいと思います。この挙動変更はバグフィクスという扱いにされていたため、バージョンアップに伴い発生する非互換とは認知されていないようです。

https://rabbitfoot141.hatenablog.com/entry/2020/07/01/215728

それではさっそく Insight SQL Testing で確認してみましょう。

## Aurora MySQL 2での実行

実際にAurora MySQL 2では以下のに実行されるので、正しく実行されていると思ってしまうケースが多いでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480312/5d1a18ed-77a3-6986-a97d-85a005660ab3.png)

ただし、実際は警告が出ていたようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480312/d97d3135-b389-d548-5362-0e7f2ac912e8.png)

とはいえ、なかなかこのような警告にも気づきづらいでしょうし、Aurora MySQL 3になっても同様に動作すると期待してしまいますよね？

## Insight SQL Testingを使った検出

Insight SQL Testingを使うと、実際にAurora MySQL 2とAurora MySQL 3に対してSQLを実行し、以下のように挙動の違いが検出されます。現在使用されているSQLをテストケースとし、そのSQLでテスト実行を行った結果です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480312/f8580ef7-bda6-7670-01ab-8591b991f33c.png)

## 参考

今回のMySQL 8におけるSQLの非互換問題については、以下のサイトなどを参考にしました。

https://qiita.com/kytomtom/questions/afa3cd13f5bba932cb1b

## おわりに

Insight SQL TestingはこのようにSQLの挙動の違いを検出することのできるツールです。
詳細について確認されたいときは、以下の記事等もご参照ください。

https://qiita.com/takumats/items/980948d6d4d9cf3bec43

## おまけ

投稿のタイトルを「～(2)」としているのは他のSQLを既に別記事で紹介したからです。

* GROUP BYの暗黙ソートがなくなる挙動変更
    * https://dev.mysql.com/doc/refman/8.0/en/upgrading-from-previous-series.html#upgrade-sql-changes の最初に出てくる挙動の変更で、あるあるの挙動変更なのでご存じの方も多いと思います。

そのほか、予約語もたくさん追加されてますのでご注意ください。

## 更新情報
* 2024/4/1: Insight Database Testingの製品名がInsight SQL Testingへ変更になったのでそれにあわせて更新しました
基本情報技術者試験に合格するまでの道のりと情報共有

一般的な基本情報技術者試験は、
午前試験を合格⇒午後試験の受験となりますが、
会社にて午前免除試験を一度だけ補助してもらえる制度を活用したため、
午前免除試験を受けるよという方は参考になると思ます。

<b><font color="Red">一番気を付けてほしいこと
　試験日の申込は、即日行いましょう。先延ばし厳禁です。</font></b>

私はCBT方式の試験で午後試験の日程を自由に選べるようになりました。
試験会場によって、空きはすぐなくなります。
最悪のケースは会場が取れなくて受験できない可能性があります。

※私は申込を先延ばしにした結果、
受験可能な会場はすべて申込日から5日～2週間後の直近でした。
一応、1か月後の会場もありましたが、
『片道2時間 かつ開始時間は朝』と
自分にとって都合が悪い場所が多かったです。。

# 受験前の知識レベルと経歴
  ・SE5年目
  ・java開発経験あり
  ・TL経験あり。顧客折衝の経験あり。

## 合格するまでの流れ(期間)
| 年月| 内容 |
|:----------|:------------|
| 2023年4~5月       | 午前問題の学習               |
| 2021年06月　　|  基本情報技術者の午前免除試験⇒ <font color="Red">合格</font>    |
| 2021年11月         | 午後問題の学習                |
| 2021年11月         | 基本情報技術者試験(午後) ⇒ <font color="Red">合格</font>|

**午後の試験結果**
　午前 -点、午後62.50点
 　午後問題
　　(1)情報セキュリティ
　　(3)データベース
　　(4)ソフトウェア設計
　　(5)データ構造及びアルゴリズム
　　(8)ソフトウェア開発(java)

## 勉強方法
**午前問題**
過去問道場_基本情報(午前)をひたすら繰り返す。年(春と秋)の5年分
 　リンク：[過去問道場_基本情報(午前)](https://www.fe-siken.com/s/fekakomon.php)
**午後問題**
過去問道場_基本情報(午後)を使用
 　リンク：[過去問道場_基本情報(午後)](https://www.fe-siken.com/fekakomon_pm.php)

## 感想
**午前免除試験の学習方法**
通勤時間(片道1時間)を使い、過去問道場をひたすら繰り返しました。
主は、通勤時間の往復。
試験２週間前の土日は、本番と同様の試験時間で問題を解くを練習しました。

**基本情報技術者試験(午後)の学習方法**
学習期間は2週間で
・平日の仕事終わりに午後問題を1問
・休日は午後問題を4問
を行いました。
平日残業で1問も解けないときは、過去問題を流し見して問題の傾向を把握

**当日の試験**
問題傾向を把握したことで、
解けそうな選択問題をすぐ判断できたので、
試験時間を有効に使うことができました。
Dockerリソースとコードを同じリポジトリ管理にしてもコンテナにアタッチしたVSCodeからgit操作したい

# はじめに

Dockerリソースとコードが同じリポジトリ管理になっている場合にVSCodeの[DevContainer](https://code.visualstudio.com/docs/devcontainers/containers)を使う時に、こんなことできたらいいのになぁ...がとりあえず達成できたので覚書です。

# Dockerリソースとコードを同じリポジトリ管理にしてVSCodeのDevContainerを使うことで対峙した問題点

VSCodeからgitを利用する場合、VSCodeで開いているディレクトリ配下の.gitを参照することで使うことができます。
しかしながら、Dockerリソースとコードを同じリポジトリで管理し、コードをアプリケーション用のコンテナにマウントしてそのコンテナにVSCodeをアタッチして使用する場合、.gitはコンテナ側に無いため、VScode上からgit操作することができず、ホストマシンからgit操作をする等で対応する必要がありました。

(Docker(インフラ)関連を管理するリポジトリと、コードを管理するリポジトリを分ければいい話ではあると思いますが、それも面倒だったため解決させる方法が無いか探していました。)



イメージ的には下記のような感じです。

![名称未設定ファイル-ページ1のコピーのコピー.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/ff403010-7654-681b-b541-e89c18f8ab61.png)


```yaml:docker-compose.ymlサンプル
version: "3.8"

services:
  php:
    build:
      context: .
      dockerfile: Docker/php/Dockerfile
    volumes:
      - ./src:/var/www/html
```

↓VSCodeで開いているディレクトリ配下に.gitが無いため、gitを使うことができない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/988b450c-cdb0-fb76-dcb5-713293598666.png)


# 解決策

## 概要

コンテナの適当なディレクトリにリポジトリのルートディレクトリごとマウントさせて
コードの格納ディレクトリをシンボリックリンクを貼ることで対応します。

![名称未設定ファイル-ページ1のコピー.drawio (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/0a098d39-a304-f3ec-7b21-b55de708c710.png)


## 詳細

まずdocker-compose.yml等でリポジトリのルートディレクトリを適当なディレクトリ(今回は/usr/local/src配下とします)にマウントさせておきます。

```yml:docker-compose.ymlサンプル
version: "3.8"

services:
  php:
    build:
      context: .
      dockerfile: Docker/php/Dockerfile
    volumes:
      - ./:/usr/local/src   ### プロジェクトルートごと/usr/local/srcにマウントさせる
```

続いてシンボリックリンクの設定をします
※シンボリックリンクを設定する先は各プロジェクトごと適切な位置に読み直してください

```sh:シンボリックリンク設定
### 先に/var/www/htmlディレクトリが存在するので削除
$ rm -rf /var/www/html
$ ln -sb /usr/local/src/src/ /var/www/html
```

この例の場合、Dockerfileで以下のようにしておくのも可

```dockerfile
RUN rm -rf /var/www/html \
  && ln -sb /usr/local/src/src/ /var/www/html
```

この状態で、VSCodeで開くディレクトリは/usr/local/srcを開いておくことで、開いたディレクトリ直下に.gitがある状態になるので、VSCodeからgitの操作ができるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/eb10ce10-a54f-c2b0-8c38-740531c215ef.png)


# おわりに

途中参画したプロジェクトでVSCodeだけで実装→git操作まで完結できるといいのになぁ...と悩んでいたところ、なんとか対応できて快適になりました！

自分の中でなんとなくこんな感じでいいかな？ぐらいの感じではありますので、
他にいい案等ありましたらコメント等お待ちしております:bow:
Mind Webアプリケーション(CGI)の実行環境を構成する

# はじめに
ここでは"日本語プログラミング言語Mind"(以下Mind)を中心とした投稿になります。
バージョンはWindows版のMind Ver.8.xを前提にしています。

# 動機
筆者は中小企業の社内IT部門に所属しています。
社内用バイナリ配布とバージョン管理には手間が掛かりますが、Webアプリケーションにすればこれらの手間が省けます。
また、MindにはGUIや印刷の機能がありませんが、これらの弱点を吸収出来るとも考えました。

# Webサーバーのダウンロードとインストール
Mindのドキュメントに記載がある"04WebServer"を使います。
以下からダウンロード出来ます。

http://soft3304.net/04WebServer/

インストールで気をつける点はありません。

# Webサーバー設定
04WebServerサーバーコントローラーを起動し各種設定を行います。
私の環境は以下ですが、個人それぞれの環境に読み替えて設定して下さい。
必要に応じて適宜フォルダを作成して下さい。

|ディレクトリ設定|フォルダ名|Server Path|Local Path|SSI/CGIを許可|書き込みを許可|
|:-:|:-:|:-:|:-:|:-:|:-:|
|ドキュメントルート      |D:\WWW   |/|D:\WWW\ | | |
|Mindインストールフォルダ|D:\pmind |/cgi|D:\pmind\ |●|●|

CGIの設定は以下のようにします。

|拡張子|ファイルヘッダ|CGI実行プログラム|
|:-:|:-:|:-:|
|cgi   |実行ファイル | %FilePath% %Query%  |

SSIを実行するファイル拡張子は"shtml"のみが設定されていますが、"html"を加えて下さい。

|ファイル名|
|:-:|
|html|
|shtml|

以上の設定が終わったら、サーバー再起動　して下さい。
設定変更したらサーバー再起動しないと設定が有効になりません。

# ランタイム
最後に、Mindランタイムをコピーします。
binフォルダの **mrunt160.exe** を pmind フォルダにコピーして下さい。
これでMind Webアプリケーションの実行環境が整いました。


# Mind Webアプリケーションの作成
```Mind:cgi-test.src
メインは
	「ＭｉｎｄによるＣＧＩのテスト」で、HTMLヘッダ出力し
	「こんにちは、Ｍｉｎｄ！」を、大きく表示すること。
```
コンパイルします。ライブラリは **cgilib** です。

```Mind:cgilibにコンパイル
D:\pmind>bin\mind.exe cgi-test.src lib\cgilib

日本語プログラミング言語 Ｍｉｎｄ Version 8.09 for Windows
          Copyright(C) 1985 Scripts Lab. Inc.
コンパイル中 .. 終了
Coping.. D:\pmind\bin\mindexcgi.exe --> cgi-test.cgi
```
実行します。
URLに http://localhost/cgi/cgi-test.cgi と入力して下さい。

![shot_240107_003959.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174456/44ce43c6-3ede-2287-c5b9-569ce0127e7a.jpeg)

# おわりに
今後、プログラムを書いていく上で気をつける点は、複数のユーザーが非同期にWebアプリケーション(CGI)を使うので、単独プログラムでは考慮する必要の無かったトランザクションの管理、例えば排他制御を考慮してコードを書いていく必要が出てきます。
なお、セキュリティーの点からインターネットへの公開等、不特定多数のアクセスは考慮していない点に十分ご注意下さい。
interpreter 2.0のアップデートではまったこと

interpreter が2.0にアップデートしたので、使ってみた。
```
interpreter --os
`````
音声でパソコンを操作できるのだが、
海外のデモを見ると、コンピュータで伝えるだけで、実行できるようです。
上記のコマンドなどを実行すると以下のエラーが出る場合があります。
```
```go
PS C:\> interpreter --os

▌ Missing Package(s): cv2, plyer, pywinctl

These packages are required for OS Control.

Install them?

(y/n) > y
Microsoft Windows [Version 10.0.22621.2861]

(c) Microsoft Corporation. All rights reserved.
```
pipでcv2, plyer, pywinctlをインストールする必要があります。

cv2とは、OpenCVという画像処理や機械学習に使えるライブラリのPython用バインディングです。1 cv2をインストールするには、pipというパッケージ管理ツールを使って、次のコマンドを実行します。
```
pip install opencv-python
```
plyerとは、WindowsやLinuxなどの異なるプラットフォームに対応したネイティブな機能を提供するライブラリです。
```
pip install plyer
```

 pywinctlとは、WindowsのGUI操作を自動化するためのライブラリです。
```
pip install pywinctl
```

これで正常にコマンドを実行できました。
私はマイクがない。早速購入してテストしたい。
マイクがないのでHelloと入力して挨拶したら、デモでPCのテキストファイルを起動された。
Windows、Mac Linux対応です。
Llama 2の各modelのパラメータ数と他LLMとの比較

## はじめに
ここ最近はMicrosoftのPhi-2はじめ、小規模言語モデルが話題になってますね。
そのあたりはまた別記事にする予定ですが（下書きで温めてる）、本記事ではMetaのLLM、Opensourceの筆頭とも言えるLlama 2について書いていこうかなと。

## 概要
・Llama 2とは、Meta社が2023年7月に公開したオープンソースのLLM
・本記事ではパラメータ数をもとに、Llama 2と他LLMを比較してみた

## Llama 2のパラメータ数
それでは、主役のLlama 2から。

Llama 2はパラメータ数の異なる、3種類のmodelがあります

* 7B（70億） 
* 13B（130億）
* 70B（700億）

このパラメータ数の分だけmodelがトレーニングされているので、基本的に各modelの性能と考えても間違いではないです。

※パラメータ数だけが各modelの性能を決めるわけではない、という話は、ここではしれっと割愛…

パラメータ数が増加してくると、modelが肥大化する、計算コストがかかる、といったデメリットもあります。
「大きければ大きい方がいい！」という単純な話ではないということですね。
何のためにそのmodelを使いたいのか？、をハッキリさせた上で、使うmodelを決めるとよさそうです。

## 他LLMとの比較
ということでパラメータ数はあくまで一つの数値でしかないですが、とはいっても、そのmodelの性能を推し量る指標でもあります。
ということで、他LLMのパラメータ数と比較して性能を考えてみたいと思います。

### OpenAIのパラメータ数
生成AIを牽引しているOpenAIは、パラメータ数を公表していません。
性能をもとに推定された数字ではあるのですが、おおよそ下記のパラメータ数でトレーニングされていると言われています。

* GPT-4：100兆
* GPT-3：1,750億
* GPT-2：15億
* GPT-1：1.17億

様々な報告でLlama 2の性能が評価されていますが、パラメータ数だけを見ればOpenAIのGPT-4の方が文字通り桁違いなトレーニングが行われていることがわかります。

ただし、このパラメータ数はあくまで非公表のデータなので、この数値だけをもとに判断するのは避けた方がよさそうです。

### Geminiのパラメータ数

Googleが展開しているGemini。
記事執筆時点で3つのmodelがあります。

* Gemini-Ultra：1.6兆
* Gemini-Pro：500億
* Gemini-Nano：32.5億

2024年初頭から使用できるとされているGemini-Ultraは、まだ十分な評価を受けていません。
辛口評価を受けているGemini-Proは500億と、Llama 2（70B）と比べると同程度といった感じでしょうか。

トレーニング数だけを見るとOpenAIからビハインドといった感じですが、Googleの各サービスとの連携/親和性もあったりと、総合的に判断した方がよさそう。

## まとめ
非公開とはいえ、GPT-4のパラメータ数が際立っている感じでしょうか。

とはいえ、、

業務でGPT-4を使っている自分としては、単純にパラメータ数だけではなく、スピードやカスタマイズ性も含めた総合点で判断したいです。
RAGやFinetuningのしやすさなんかも重要だったりします。

パラメータ数を一つの指標として、トータルでどうか？、を見ていきたいところです。

ちなみに、冒頭で話題に上げた軽量な言語モデルは、LLMにはやりづらいところをパワーアップ＆補完してくれると思います。この辺はまた別記事で取り上げますね！
M5StickCPlus1.1をBluetoothキーボード化しiPhoneのスクショボタンにすーる

# はじめに
M5StickCでBluetoothキーボード化しスクショボタンにしていきます

https://saasan.github.io/blog/2021/04/04/m5stickc%E3%81%A7%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89%E6%93%8D%E4%BD%9C%E3%82%92%E8%87%AA%E5%8B%95%E5%8C%96%E3%81%99%E3%82%8B.html

https://lang-ship.com/blog/work/m5stickc-iphone/

# 開発環境
- Windows 11 PC
- M5StickCPlus 1.1
- Arduino IDE 2.2.1
- iPhone 12 Pro

# 導入
1．Arduino IDEをインストール
https://www.arduino.cc/en/software

2．ESP32-BLE-Keyboard v0.3.0をダウンロード
https://github.com/T-vK/ESP32-BLE-Keyboard/releases

3．スケッチ->ライブラリをインクルード->.ZIP形式のライブラリをインストール…からESP32-BLE-Keyboard.zipを選択

4．ツール->ボード->ボードマネージャからesp32 2.0.11をインストール
![20240106-144251-3725d061.png](https://gachimoto-qiita-storage.s3.amazonaws.com/20240106-144251-3725d061.png)

5．スケッチ->ライブラリをインクルード->ライブラリを管理からM5StickCPlusをインストール
![20240106-150128-67f8bf05.png](https://gachimoto-qiita-storage.s3.amazonaws.com/20240106-150128-67f8bf05.png)

6．M5StickCPlusをUSBで接続し、COMポートを選択
![20240106-150548-68fcbc29.png](https://gachimoto-qiita-storage.s3.amazonaws.com/20240106-150548-68fcbc29.png)

7．プログラムを書き、M5StickCPlusにアップロード

~~~c
#include <vector>
#include <M5StickCPlus.h>
#include <BleKeyboard.h>

// -----------------------------------------------------------------------------
// 定数
// -----------------------------------------------------------------------------
// 電源ボタンが1秒未満押された
const uint8_t AXP_WAS_PRESSED = 2;

// -----------------------------------------------------------------------------
// 変数
// -----------------------------------------------------------------------------
// ESP32-BLE-Keyboard
BleKeyboard bleKeyboard;

// -----------------------------------------------------------------------------
// 関数
// -----------------------------------------------------------------------------
// 画面を消去する
void clearScreen() {
    M5.Lcd.fillScreen(TFT_BLACK);
    M5.Lcd.setCursor(0, 0);
}

void setup() {
    M5.begin();

    // 画面の表示設定
    M5.Lcd.setRotation(1);
    M5.Lcd.setTextFont(2);
    clearScreen();
    M5.Lcd.println("ESP32-BLE-Keyboard");

    // Bluetooth接続
    bleKeyboard.begin();
}

void loop() {
    M5.update();

    // 電源ボタンが押されたらリセット
    if (M5.Axp.GetBtnPress() == AXP_WAS_PRESSED) {
        esp_restart();
    }

    if (bleKeyboard.isConnected()) {
        // Bluetooth接続済みの場合
        // ボタンAが押されたらキーを送信
        if (M5.BtnA.wasPressed()) {
            bleKeyboard.press(KEY_LEFT_GUI);
            bleKeyboard.press(KEY_LEFT_SHIFT);
            bleKeyboard.press('3');
            delay(100);
            bleKeyboard.releaseAll();
        }

        delay(10);
    }
    else {
        // Bluetooth未接続の場合は5秒待つ
        M5.Lcd.println("Waiting 5 seconds...");
        delay(5000);
    }
}
~~~

# 実行結果

iPhoneのBluetoothでESP32 Keyboardに接続し、M5StickCPlusのボタンを押すとスクショできました。

https://x.com/sotongshi/status/1743656356740211071?s=20

電源ボタンを6秒押すと電源が切れます。
お疲れさまでした。
GraphQLクライアント Relayのキャッシュを有効化する

## Relayとは
Meta 製の GraphQL クライアント。
記事執筆時の最新バージョン：Relay v16.1.0

https://relay.dev/


## Cacheについて

一口にキャッシュにもいくつか種類があり、ここでは以下2つのキャッシュを扱う。

### Query Cache（Document Cache）
- query単位のcache dataのこと

- consoleで以下オブジェクトに情報が格納されていることが確認できる
`__RELAY_DEVTOOLS_HOOK__.environments.get(1)._store._roots`

![スクリーンショット 2024-01-06 20.36.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321338/384ba6cb-5377-06a6-3733-00970b40b87e.png)

- store生成時のoptionで有効期限を設定できる（後述）

- valueにfetchTimeを含んでいるため、これをもとにキャッシュの有効期限を判断している模様

![スクリーンショット 2024-01-06 20.37.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321338/6b39e2e5-32ed-425e-7a0e-62f45da34c2d.png)


### Store data（Normalized Cache）
- Relay Storeに格納される正規化されたdataのこと

- [Relay DevTools](https://relay.dev/docs/debugging/relay-devtools/)で確認することができる

![スクリーンショット 2024-01-06 20.29.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321338/eafebb4e-0176-20bc-9286-b33b72548c57.png)

- console.logでも確認できる`__RELAY_DEVTOOLS_HOOK__.environments.get(1)._store._recordSource._records`

![スクリーンショット 2024-01-06 20.33.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321338/05c29d0c-c37b-fb73-f9ba-aca550033a66.png)




- グローバルなIdで識別される
- 専用のAPIを叩くか、query cacheの有効期限が切れない限りstaleにならない
- Query cacheが利用できない条件でも、Store dataに必要な情報が揃っている場合は、network requestを送信しない場合がある

## Fetch Policy

[loadQuery](https://relay.dev/docs/api-reference/load-query/) の option で [fetchPolicy](https://relay.dev/docs/guided-tour/reusing-cached-data/fetch-policies/) を指定すれば、画面ごとにキャッシュの利用有無を設定できる。（Query CacheとStore Dataの両方に適用される）

実際に使用することが多い fetchPolicy の種類と概要を以下に示す。
|  | store-or-network | store-and-network | network-only |
|:-----------|:-----------|:-----------|:-----------|
|概要|デフォルトfetchPolicy。<br>有効なキャッシュが存在していればキャッシュを利用して画面を表示する。<br>なければネットワークリクエストを送信する。|有効なキャッシュが存在していればキャッシュを利用して画面を表示する。<br>その後キャッシュの有無に関わらず常にネットワークリクエストを送信し、キャッシュを更新する。|キャッシュを利用せず、常にネットワークリクエストを送信する。|
|メリット|キャッシュを利用するので表示が早い|キャッシュを利用するので表示が早い| 常に新しいデータで画面を表示する  |
|デメリット| キャッシュの有効期間内に裏でデータが書き換わっている場合、古いデータで画面を表示してしまう。 | キャッシュの有効期間内に裏でデータが書き換わっている場合、一度古いデータで画面を表示して、その後最新データ取得後に画面が書き換わるので一瞬じらつきが生じる。 | キャッシュを利用する場合に比べて画面表示が遅くなる。 |


実装はloadQueryの第4引数にoptionを指定する。

```ts:example
const queryReference = loadQuery(
  MyEnvironment,
  query,
  {id: '4'},
  {fetchPolicy: 'store-or-network'},
);
```


## 有効期限

storeのインスタンス化の際に、query cache の有効期限を設定できる。

https://relay.dev/docs/guided-tour/reusing-cached-data/staleness-of-data/#query-cache-expiration-time

```ts
// 5分の query cache を設定
const store = new Store(source, {queryCacheExpirationTime: 5 * 60 * 1000 });
```

一度queryを叩いた時間を基準にして、ここで設定した期間内にもう一度同じqueryを叩いた場合に、network requestを送信せずにキャッシュを利用する。

## 参考
- [Relay Docs | Reusing Cached Data](https://relay.dev/docs/guided-tour/reusing-cached-data/)
- [Document cacheとNormalized cacheの違いをおさらい](https://zenn.dev/yutaro1031/scraps/8ebcd5c728801a)
【SwiftUI】オーディオの出力変更を検知する

## 始めに
有線のイヤホンやairpodsなどが端末と接続されオーディオの出力先が変更したとき、これを検知することができますが、少し躓いたので書き留めておきます。

## 本題
```swift
import SwiftUI
import AVFoundation

class AudioSessionManager: ObservableObject {
    @Published var headphonesConnected: Bool = false

    init() {
        do {
            try AVAudioSession.sharedInstance().setActive(true) // この処理がなくて躓いた
            print("AVAudioSession is now active")
        } catch {
            print("Failed to activate AVAudioSession. Error: \(error)")
        }
        let nc = NotificationCenter.default
        nc.addObserver(
            self,
            selector: #selector(handleRouteChange(_:)),
            name: AVAudioSession.routeChangeNotification,
            object: nil
        )
    }

    @objc func handleRouteChange(_ notification: Notification) {
        print("Route Change")
        guard let userInfo = notification.userInfo,
              let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
              let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue) else {
            return
        }

        switch reason {
        case .newDeviceAvailable:
            headphonesConnected = true
            if headphonesConnected {
                print("イヤホンが接続されました。")
            }

        case .oldDeviceUnavailable:
            headphonesConnected = false
            if !headphonesConnected {
                print("イヤホンが解除されました。")
            }

        default: break
        }
    }
}

struct ContentView: View {
    @ObservedObject var audioSessionManager = AudioSessionManager()

    var body: some View {
        VStack {
            Text(audioSessionManager.headphonesConnected ? "イヤホンが接続されています。" : "イヤホンが接続されていません。")
        }
    }
}
```

## 終わりに
これでオーディオの出力先が変更された場合に検知することができます。

## 参考文献
https://developer.apple.com/documentation/avfaudio/responding_to_audio_route_changes
【SwiftUI】メニュー内のボタンを押した後、メニューを閉じない

# はじめに
iOS16.4から`menuActionDismissBehavior`というメソッドが使用できるようになりました。
これはメニュー内のボタンを押した後、メニューを閉じないようにすることができます。

# 実装
```diff_swift
import SwiftUI

struct ContentView: View {
    @State private var searchText = ""
    
    var body: some View {
        Menu {
            Button {
                print("heart")
            } label: {
                Label("heart", systemImage: "heart.fill")
            }
            
            Button {
                print("star")
            } label: {
                Label("star", systemImage: "star.fill")
            }
            
            Button {
                print("cross")
            } label: {
                Label("cross", systemImage: "cross.fill")
            }
        } label: {
            Text("メニュー")
        }
+       .menuActionDismissBehavior(.disabled)
    }
}
```

# 比較
|`enabled`|`disabled`|
|-|-|
|![Simulator Screen Recording - iPhone 15 - 2024-01-07 at 00.24.05.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/a1baf617-718f-461b-95db-db1b4d00f2f4.gif)|![Simulator Screen Recording - iPhone 15 - 2024-01-07 at 00.24.32.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/08474109-8c1a-2ce9-6a92-69eddec4418a.gif)|

# おわり
メニュー内のボタンを押した時にメニューを閉じたくない場合ってあんまり考えられないですね。
まぁ自由度が上がって嬉しいですね

# 公式ドキュメント
https://developer.apple.com/documentation/swiftui/view/menuactiondismissbehavior(_:)
Kaggle参戦記：ビギナーズラックでスコアが0.961に上昇。上位12%へ

# ラッキーパンチが当たった

　引き続き、生成AIの文章か人間の文章かを判別するタスク「[LLM - Detect AI Generated Text](https://www.kaggle.com/competitions/llm-detect-ai-generated-text)」で奮闘しております。[昨日の記事](https://qiita.com/rho-guy/items/e6bc4ce56a4d85c01655)で、トップ集団がやっていることを解説した後、自分でも何かできることはないかと思って、軽くジャブを打ってみたところ、たまたまうまい具合に当たったようで、スコアが0.96から0.961に上がりました。「たったの0.001ポイントじゃん」と思うかもしれませんが、ランキングでは上位33%から一気に上位12%（473位/3778人中）まで駆け上がることができました。銅メダルの圏内が見えてきた。これはうれしい。

 やったことは「データ拡張」です。とはいえ、これも自分でLLMを動かしてデータを集めたわけではありません。昨日の記事で、「ソースコードの中で、読み込まれてはいるけれど使われていない」と言っていた、コンペ側が提供するオリジナルのトレーニングデータを、DAIGTデータセットにくっつけて使っただけです。

　しかも、submitした後に判明したことですが、実は、DAIGTデータセットには、すでにオリジナルのトレーニングデータが取り込まれていたのでした。私がデータのuniqueを取り忘れていたために、「人間が書いたエッセイが一部重複してデータに含まれている状態」だったわけです。あー、どおりで、みんな使ってないわけだわ。データサイエンティストとしてはお恥ずかしいくらいの初歩的なミスだったのですが、どうやらこのミスがたまたま良い方向に働いたようで、結果は0.961へのスコアアップとなりました。ラッキー！

 ![ラッキーパンチ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3666147/16513467-174d-d35b-fe45-cc454deb8ab8.jpeg)
 はじめの一歩36巻p.119（講談社）より引用。
 Kaggleにはラッキーパンチもある、と思う。


 # データ拡張祭りじゃ！
　というわけで、データ拡張にちょっとした手ごたえを感じたので、「他にも使えるデータはないか？」といろいろと探してみました。Kaggleのコンペでは、プライベートなデータセットを使うことはできませんが、Kaggle内で公開されているオープンなデータセットであれば、気軽に使うことができます。

　公開データセットを自分のNotebookに取り込む方法は下記の通りです。
 ①Kaggle Notebookの右側の「Data」の欄にある「Add Data」ボタンをクリック

 ②これまで他人のNotebookをいろいろのぞいていれば、その時に見えていたデータセットの一覧が出てくる。データセットの説明を読んで、良さそうと思ったデータセットの「+」マークをクリック。なければ「LLM generated」などのキーワードで検索しても良い。
 
 ![DatasetSearch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3666147/612c3461-dcb0-81b9-67c6-e658fe815805.png)

③Notebookの右側の「Data」欄に戻ると、Inputの項目に取り込んだデータセットの一覧が出るので、そこをクリック

④データファイル名（csv）が出てくるので、マウスオーバーしてクリックするとファイル名をコピーできる。
 
![InputData.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3666147/83f7224c-f1d7-4a1b-f963-0bd5dce3a0ba.png)

⑤Notebookのソースコードで、ファイルを読み込むところにペーストすればOK
~~~.py
daigt_train = pd.read_csv("/kaggle/input/daigt-v2-train-dataset/train_v2_drcat_02.csv")
~~~
 
というわけで、Codeで高スコアを出しているNotebookをいろいろ観察しながら、使われているデータセットをつらつらと眺め、有望そうなものをいくつかピックアップして組み合わせながらsubmitしてみました。この場合、[DAIGT V2 Train Dataset](https://www.kaggle.com/datasets/thedrcat/daigt-v2-train-dataset)と[DAIGT | External Dataset](https://www.kaggle.com/code/rhoguy/llmdetect/edit/run/157872612)の組み合わせが一番成績が良かったのですが、それでもスコアは0.961とラッキーパンチを越えるまでには至らず。。。また、トレーニングデータが58000件を超えたあたりでsubmit後の実行時にメモリーオーバーフローになってしまいました。どうやら、このくらいのデータ量でやりくりする必要があるようです。

こちらのコンペでは1日のSubmit回数は5回が上限なので、本日は打ち止め。ソースコードの概要はざっくり理解したものの、細かい中身はまだブラックボックスがいっぱいなので、とりあえず外堀から埋めていく感じになりました。明日あたりからは、いよいよ、特徴量の選択や分類器の選定などに入っていきたいと思います。Good Luck!
Windows11のメモ帳(notepad.exe)でメモリ不足のエラーが出続けるときの対処

# 症状

クソデカ文字列がクリップボードにある状態でメモ帳にペーストしたらなった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18902/462f4193-7de3-57fe-f0c2-883bfb7b519e.png)

検索用

> メモリ不足のためこの操作を実行できません。1つ以上のアプリケーションを終了して空きメモリ領域を増やしてから、もう一度お試しください。

ググったらwindowsに昔からあるバグらしくて、開きなおせば治るからそんなに問題じゃなかった。
だけど最近アプリ閉じても前回の内容を復元する機能がついたので永遠に出続けるようになった。

- [「メモ帳」に自動保存機能が搭載へ ～アプリを閉じても次回タブと編集内容を自動復元 - 窓の杜](https://forest.watch.impress.co.jp/docs/news/1528102.html)

コピーしたのは3万文字だからメモリぜんぜん足りてるけどね

# 試したけどだめだったこと

- メモ帳をタスクマネージャーから強制終了
- メモ帳の設定を変更(前回のセッションを無視するよう変更)
- 再起動
- 新しいウィンドウ or ファイルを開く

設定はメモ帳の閉じるボタンの下にあるギアアイコンから変更可能

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18902/5619642b-5a25-6248-5ef6-7fba8481cfcd.png)

上記の手順とか色々試してみたけど出続けたからもう最終手段しかない。ふざけんあ！

# 解消手順(メモ帳をリセット)

- 設定アプリを立ち上げる(Windows + i)
- アプリ > インストールされているアプり
- 「メモ帳」を検索して「…」から詳細オプションを開く
- 「リセット」ボタンを押す (「修復」ボタンじゃだめだった)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18902/2be477f5-6f05-468e-ae6b-e2d7fcd2d0a8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18902/3374bdee-4189-c84e-e114-9730ab341283.png)

メモ帳の設定は元に戻ってしまうけどメモ帳ごときの設定すぐ元に戻せるでしょう
時間を無駄にする人が一人でも減りますよーに
"とりあえずプログラミングを学びたい" という受動的な理由で専門学校や大学に行くのはやめよう

## 📢 はじめに
専門学校や大学そのものに行くこと自体を否定する意図はありません。
姿勢、マインド的な部分に関する記事です。


## 😭 世の中ってそんなに甘くない
私自身、地方の専門学校に通っていたので一応は実績値になりますが、地域によって異なりますので参考程度に。
- ゲームプログラマになりたくて進学しても卒業までに内定できるひとって 10% ～ 20% です。
- IT系のエンジニアになりたくて進学しても卒業までに内定できるひとって 50% ぐらいです。


## 🤔 でも、エンジニア不足なんでしょ？
企業は、仕事が「できる」エンジニア人材が不足しているだけです 🥺


## 🎓 学校で学べることってなんだろう
主に
- プログラミング言語
- オブジェクト指向に関して
- 資格
- チーム開発
- コミュニケーション能力

簡単に挙げられるのはこれぐらいでしょうか。
読み進める前に、他にもないか考えてみてください...

さて、思い浮かべた学校で学べそうなことは、絶対に学校じゃないと学べないのでしょうか？
ネットには Qiita のほかにも初心者向けの解説サイトが大量にあり、学校に行かなくても基礎のキが **無料** で学べるような世の中になっています。

チーム開発はもしかしたら学校でないと体験できないかもしれませんが、
クラスの中で、上位 数人しかチーム開発をやらせてくれないような学校もあります。（少なくとも、かつて私の通っていた学校はそうでした。）

さて、私立系の学校に通った場合、毎年100万前後かかります。
最終的に思い浮かんだ「絶対に学校で学べないこと」は、年100万の価値があるものでしょうか？

資格勉強は学校に行かずとも可能ですし、業界経験年数を重ねれば重ねるほど、資格よりもこれまで何をやってきたかが問われるようになります。


## 🥶 とはいえ、高卒でIT企業へのエンジニア（プログラマ）としての就職は厳しい
大体の企業が、新卒採用として専門学校や大学卒業（or 見込み）の人を対象にして採用活動をしています。
そのため、あくまで大学や専門学校は、会社に就職するための踏み台と捉えることが大切です。
何かを学びに行く場所とは捉えないようにして、学びたい場合は能動的に自分から情報を取りに行くべきです。

※ 高卒 & 無条件（未経験大歓迎！！） で入れる会社は、致命的なほどに人がいない（=定着しない）と考えることができ、ブラック企業の可能性が高いかもしれません。

※ 専門や大学に通っていない、あるいは全く別の業種だとしてもポートフォリオや自分で何かサービスをリリースしたりした実績があることで、就職が叶うケースもあります。

## 🫵 自分がどのようなフェーズに置かれていても能動的であることは重要です
- 専門 / 大学 に通っている人も、与えられた課題をこなすだけでなく、能動的に行動してポートフォリオを充実させたり、エラー発生時の自己解決能力を向上させ、最終的なアウトプットの量や質を高めることが重要です。

- IT エンジニアとして業務をしている人も、継続的かつ能動的に勉強しなければ、エンジニアとしての自分の商品価値が落ちていきます。

- 受動的にタスクをこなした結果、何らかのミス、納期遅延により、自社およびステークホルダーに重大な損害を与えることになるかもしれません。

- 現在、会社でプロダクトを作っていたとしてチームメンバーが能動的に動かなければ、やがてそのプロダクトは腐ります。

- 人の上に立つ者が、もしも受動的に動き、他責思考になれば、その組織はいつか崩れます。


## :writing_hand: さいごに
勢いに乗って雑記してしまいましたが、専門学校や大学に行くこと自体が悪いわけではありません。
目的、意志をもつことが大切です。
高いお金を払って通うことになります。
奨学金を借りる人は金額によっては、向こう何十年も返済することになります。
この業界は一度学んだことが一生使いまわせる業界ではなく、常に流行り廃りがあります。
学校で学んだフレームワークも数年後、終焉を迎えている可能性もゼロではありません。
常に能動的に勤勉に居続けることが、エンジニア人生を豊かにしていくためのライフハックかと思います。
WebでAPIを叩く

## はじめに
API（Application Programming Interface）を利用することは、開発者にとって欠かせないスキルですが、理解が難しいと感じて1年間避けてきました。しかし、今年こそは理解し、実際に試してみることにしました。その結果、意外にも簡単にできたので、まとめてみます。

## WebAPIとは
WebAPIは、ウェブ上で異なるソフトウェア同士が情報をやり取りするための一連の定義やプロトコルです。これにより、異なるプログラム間でデータを共有し、相互に連携させることが可能です。本記事では、Web上でAPIを操作することで、その仕組みを感覚的に理解していきます。

## WebAPIを叩くイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/540f5545-bc35-0266-8560-ced7d6c7a267.png)
WebAPIではURLで欲しいデータを指定してWebサーバーにアクセスすることで、サーバーからXML形式やJSON形式のデータを取得します。
URLにアクセスすることを`リクエスト`、返ってくるデータを`レスポンス`と言います。

## 実際に叩いてみる
ブラウザで、以下のurlを打ち込んで見てください。
`https://sysbird.jp/toriko/api/?apikey=guest&keyword=抹茶&format=json`

下の写真のようになったでしょうか？この、謎の文字の大群がレスポンスです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/770739f8-a2f9-8593-cc91-65ee5f4be5d7.png)

## リクエスト（URL）の解説
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/b1dd6ffb-155f-7da6-824d-203717b93326.png)
通常、APIを用いるにはAPIkeyというものを取得する必要がありますが、[お菓子の虜](https://sysbird.jp/toriko/webapi/)というサイトで提供されているAPIではその必要なく手軽に試せるので、今回はこちらを用いました。
サイトにはリクエストURLやパラメータ、利用規約などの情報が得られます。
本記事では先ほどのURLに用いた情報のみ抜粋して説明するので、詳しくはサイトをご覧ください。

### 基本仕様
|項目|内容|
|----|----|
|プロトコル|REST|
|レスポンス|XML形式、JSON形式、JSONP形式|
|リクエストURL|https://sysbird.jp/toriko/api/|

### パラメータ
|パラメータ|項目名|説明|
|----|----|----|
|apikey|APIキー（必須）|"guest"固定|
|format|レスポンスの形式|xml, json, jsonp|
|keyword|キーワード|お菓子の名称で部分一致検索。UTF8でURLエンコーディング|

パラメータは`?`で始めた後、`&`で複数繋げることができます

## レスポンスの解説
先ほどのリクエストから、レスポンスとして、
お菓子の名称に"抹茶"が含まれるお菓子のデータがjson形式で返される
と予測されます。改めて見返してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/770739f8-a2f9-8593-cc91-65ee5f4be5d7.png)

おかしいですね。数字と文字の暗号が返されました。
JSONは一般的にエンコードされます。エンコードとは、全角文字や制御文字も問題なく送信するために半角文字に置き換える手法です。それではエンコードされたデータをデコードしましょう。[Syncer](https://lab.syncer.jp/Tool/JSON-Viewer/)というサイトがおすすめです。
`整形前`のところにレスポンスのデータを貼り付けてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/73919236-adf9-a417-ad21-fd6b523c9ba8.png)
下にスクロールし、'ビューアー'をみてください。デコードされています！　今度はちゃんとお菓子の名称に"抹茶"が含まれるお菓子のデータがjson形式で返されていますね！
![スクリーンショット 2024-01-06 23.45.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/df827264-f6b0-74d7-65ce-2dd5c50ecbb6.png)

## 最後に
これでAPIの理解はできました。次は、実際に開発でAPIを使ってみようと思います！
【Next.js】Linkコンポーネントにクエリパラメータを指定する方法

以下のように記述することで`Link`コンポーネントにクエリパラメータを指定できます。

```jsx
// Navigate to /about?name=test
<Link
  href={{
    pathname: '/about',
    query: { name: 'test' },
  }}
>
  About
</Link>
```
【書評】Good Code, Bad Code ～持続可能な開発のためのソフトウェアエンジニア的思考

## 読んだ本

https://www.shuwasystem.co.jp/book/b620733.html

## 概要

実際にコードを書くプログラマーに向けて、良いコードの書き方を丁寧に教えてくれる内容だった。目次は以下のようになっている。

- Chapter 1 コードの品質
- Chapter 2 抽象化レイヤー
- Chapter 3 コードでの契約
- Chapter 4 エラー
- Chapter 5 コードを読みやすくする
- Chapter 6 想定外の事態をなくす
- Chapter 7 誤用しにくいコードを書く
- Chapter 8 コードをモジュール化する
- Chapter 9 コードを再利用、汎用化しやすくする
- Chapter 10 ユニットテストの原則
- Chapter 11 ユニットテストの実践

各項目では、まず悪いコードを提示してくれて、なぜ悪いか、どう解決するのがいいかを順を追って説明してくれる。扱う範囲についても、細かいコードの書き方からテストまで幅広く網羅できていて、もう少し早く発売してくれていたらなあと思った。

## おすすめの人

- チーム開発を初めて１年ほど経過した人（DIなどの話も出てくるので、SOLID原則などがわからない人は、「リーダブルコード」や「プリンシプルオブプログラミング」などを先に読むことを推奨）
- コードレビュアーで、悪いコードだと直感的にわかるけど言語化がうまくできない人

## 次に読むなら

認知科学の観点から、悪いコードはどういった負担を生むのかに興味があれば「プログラマー脳」がおすすめ。
初心者でもう少しクラスなど広い範囲の良い設計について知りたい場合は「オブジェクト指向設計実践ガイド」がおすすめ。

## 感想

ほとんど悪いコードを見たタイミングでどう直すべきかは想像できてしまい、目新しさはなかった。テストについてはできていない箇所が多く、改善していかないとなあと反省した。
nullオブジェクトパターンは古いと書いてあって、たしかにoptional型やnull安全な言語が出てきたことでnullの扱いについて認識が変わってきているなあという気付きがあった。
Chapter7で誤用しにくいコードについて言及されているが、今業務で扱っているrubyでは特にこの点が重要だと感じている。
Leetcode日記 (Day 1)

# 初めに
　今日から解いたLeetCodeの問題を解答含め解説していければと思います．
興味ある人はぜひご覧ください～～．と言っても，プログラミングの問題を解くのは殆ど初めてなので，「なんだこれ？」と思う人も多々いらっしゃると思います．なので，多めに見ていただきたいです～～


# LeetCode (two sum )
問題はこちら
> Given an array of integers nums and an integer target, return indices of the > two numbers such that they add up to target.
> You may assume that each input would have exactly one solution, and you may > > not use the same element twice.
> You can return the answer in any order.

これは要約すると，「整数のリストとターゲットの値を上げるから，ターゲットの値を作る2つの数をリストから探してね」ってことですよね．多分．

ということでやってみましょう～～
早速解答はこちら．

```python
def twoSum(self, nums: List[int], target: int) -> List[int]:
        indices =[]
        for i,outer in enumerate(nums):
            for j,inner in enumerate(nums):
                if outer + inner == target:
                    indices= [j,i]
                    break
        
        return indices
```

これは単純に外側のループで取得した要素と，内側のループの要素の合計がターゲットの値と一致する場合その時点での,iとjを格納する方法です．
ただ，このコードだと，同じ要素を二度使用することが許されていると，正確な条件の解を見つけることが出来ないですし，条件に合致する組み合わせが複数あると，最初に見つかった組み合わせしか返さないので正確性には欠けそうですね．

やっぱりまだまだですね～～
修業は続きそうです！
【ABC335】コンテストメモ【AtCoder】

## はじめに
毎週取り組んでいる「AtCoder Beginner Contest」の感想・まとめをこちらの記事に散文的にまとめていきます。

:::note warn
使用言語はC++
:::

:::note warn
「未着手」は手を付けていない問題。
「未提出」は手を付けたけれど提出はしていない問題。
:::

## 結果
- 順位: 4050位
- 点数: 900点(1)
- 時間: 92:48
- pef: 782相当
- R: 165 → 215 (+50) Highest更新！
- 完問数:4完 ABC(1)D

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954837/bf0fb8ed-f615-3e70-0b69-34823cdb8f03.png)

## 問題別評価

### A問題
- AC 3:07
- [実行結果](https://atcoder.jp/contests/abc335/submissions/49066209)
文字列の末尾を4に変更する。基本中の基本。

### B問題
- AC 6:44
- [実行結果](https://atcoder.jp/contests/abc335/submissions/49071289)
三重ループ。勝手に辞書順になってくれる。

### C問題
- AC(1) 87:48
- [実行結果](https://atcoder.jp/contests/abc335/submissions/49116592)

最初は毎回値を移動させていたのでO(N × Q)の計算量がかかってしまった。
[TLE](https://atcoder.jp/contests/abc335/submissions/49088207 )
最終的にはvectorで追加していって後ろだけを確認する予定

### D問題
- AC 63:32
- [実行結果](https://atcoder.jp/contests/abc335/submissions/49108306)
C問題の続き。ぐるぐる回って挿入する。C問題よりも簡単だと思う。

### E問題
- 未提出
union_findを使ったdfsな気がしている。解いていない

### F問題
- 未着手

### G問題
- 未着手

## 総評・まとめ
パソコンの調子が悪いためブラウザを何度も消すことになった。8年選手なので買い替えが必要なんだろうけど、それがなければ緑pefを出せたと思うと悲しい。準備が大切。それにもっと早く解けた問題が多かったので演習して慣れていくしかない。茶レートになるにはひどい成績の時期があったので仕方がない。直近は茶pef、緑pefを出せるように精進していこうと思う。
ミニマムなHelm Chartを作ってみる

# TL;DR

Helmは、Kubernetesアプリケーションにおけるパッケージマネジャーです。
この記事ではミニマムなHelm Chartを作成することにより、Helmの概要について説明します。

記事で使用するサンプルHelm Chartは以下のリポジトリにあります。

Github: https://github.com/cacapouh/helm-chart-minimum-example

# Helmパッケージの初期化

Helmパッケージを初期化するには、以下のコマンドを使用します。

```shell
helm create ${ディレクトリ名}
```

コマンド実行結果:

```
$ helm create simple-app
Creating simple-app

$ tree simple-app
simple-app
├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml
```

`helm create`コマンドを実行すると、デフォルトのマニフェストファイルが生成されます。
この記事ではミニマムなHelm Chartを作る関係で、以下のようにファイルを削除します。

```
$ cd simple-app
$ rm -rf charts values.yaml templates/*
$ tree .
.
├── Chart.yaml
└── templates
```

https://helm.sh/docs/helm/helm_create/

# Helm Chartのざっくり説明

Helm Chartは、Kubernetesアプリケーションのパッケージで、
主な要素は`Chart.yaml`ファイルと`template`ディレクトリです。

`Chart.yaml`はバージョン情報やパッケージ名を含むファイルで、[こちら](https://helm.sh/docs/topics/charts/#the-chartyaml-file)で詳細な仕様が説明されています。

```Chart.yaml
apiVersion: v2
name: simple-app
description: A Helm chart for Kubernetes
type: application
version: 0.1.0
appVersion: "1.1.0"
```

`template`ディレクトリは、適用するマニフェストファイルを格納する場所です。

この記事の例では扱いませんが、
`template`配下のマニフェストファイルでは、Go Templateが利用可能です。
(上記で削除してしまいましたが)テンプレートに使う値は、`values.yaml`で定義することが可能です。

※ Go Templateは、Go言語で利用されるテンプレートエンジンです。

# デプロイ対象のアプリ

サンプルアプリとして、以下の簡素なPythonスクリプトをデプロイします。

```python:${プロジェクトルート}/main.py
if __name__ == '__main__':
    print("Hello World")
```

# マニフェストの作成

次に上記のPythonアプリ用Dockerfileと、
Deploymentのマニフェストファイルを作成します。

```Dockerfile:${プロジェクトルート}/Dockerfile
FROM python:3.9.18-slim

RUN mkdir /work
WORKDIR /work

COPY main.py /work
ENTRYPOINT python main.py
```

```yml:${プロジェクトルート}/templates/deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: simple-app-deployment
  labels:
    app: simple-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: simple-app
  template:
    metadata:
      labels:
        app: simple-app
    spec:
      containers:
        - name: simple-app
          image: "simple-app:latest"
          imagePullPolicy: IfNotPresent
```

# Helmパッケージのインストール

Dockerビルドして、`helm install`コマンドを実行します。

```shell:Dockerビルド
$ docker build . -t simple-app

$ minikube image loadminikube image load simple-app:latest # minikube環境の場合
```

```shell:helm install
$ helm install ./simple-app --generate-name
```

# 動作チェック

以下は`helm install`後にPodのログを確認した結果です。
Pythonスクリプトに記載の通り、`Hello World`と出力されています。

```
$ kubectl get pods
NAME                                     READY   STATUS      RESTARTS      AGE
simple-app-deployment-678bcdc8bf-7kjpn   0/1     Completed   2 (27s ago)   29s
simple-app-deployment-678bcdc8bf-fp8bp   0/1     Completed   2 (27s ago)   29s

$ kubectl logs simple-app-deployment-678bcdc8bf-7kjpn 
Hello World
```

# おわりに

`template`ディレクトリ配下にマニフェストファイルを設置し、
`helm install`することにより、マニフェストを適用することができました。

実務でありそうなケースとして、
アプリケーションを構成する複数のマニフェストファイルが存在する場合、
Go Template機能を利用して1つのファイルで本番環境設定とテスト環境設定を切り替えることができます :thumbsup:
vueの環境を構築してみた

# はじめに
ライブラリの読み込みではなく、vueプロジェクトを作成してvueの環境を構築してみました。

# 環境
OS：macOS Ventura 13.6.3
yarn：1.22.21
nodenv： 1.4.1
node：16.13.2
vue：2

# Node.js
## インストール
まず、nodenvでnode.jsをインストールします。

```shell
$ brew install nodenv
```

## バージョンを指定
後述のvueプロジェクトの作成でnode.jsのバージョンが合わなかったため、バージョンを16.0.0以上に設定します。

```shell
$ nodenv install 16.13.2
$ nodenv local 16.13.2
```

16.0.0以上に設定されていることを確認

```shell
$ nodenv local
16.13.2
```

# yarn
続いてパッケージマネージャーをインストールします。

## インストール
```shell
$ brew install yarn
```

```shell
$ yarn --version
1.22.21
```

# vue
## パッケージをインストール
vueのパッケージをインストールします。

```shell
$ yarn global add @vue/cli
```

## プロジェクトを作成
vueのプロジェクトを作成します。

```shell
$ vue create vue-project
```

プロジェクトの設定内容を聞かれるのでそれぞれ選択します。

プリセットを選択します。
今回はvue2のデフォルト設定を選択します。

```shell
Vue CLI v5.0.8
? Please pick a preset: 
  Default ([Vue 3] babel, eslint) 
❯ Default ([Vue 2] babel, eslint) 
  Manually select features 
```

続いてパッケージマネージャーの選択です。
今回はyarnを選択します。

```shell
Vue CLI v5.0.8
? Please pick a preset: Default ([Vue 2] babel, eslint)
? Pick the package manager to use when installing dependencies: (Use arrow keys)
❯ Use Yarn 
  Use NPM 
```

結果、「Successfully」をなれば成功です。

```shell
・・・
🎉  Successfully created project vue-project.
👉  Get started with the following commands:

 $ cd vue-project
 $ yarn serve
```

# サーバーを起動して動作確認
## 起動
プロジェクト作成時に実行コマンドが出力されています。
プロジェクトディレクリに移動してサーバを起動します。

```shell
$ cd vue-project
$ yarn serve
```

「yarn serve」を実行すると、プロジェクト内のpackage.jsonで設定されているスクリプトが実行されます。
以下ですね。

```package.json
・・・
  "scripts": {
    "serve": "vue-cli-service serve"
  },
・・・
```

以下のように「successfully」となっていれば成功です。

```shell
・・・
 DONE  Compiled successfully in 767ms                                                                                    8:33:15 PM


  App running at:
  - Local:   http://localhost:8080/ 
  - Network: http://192.168.11.29:8080/
```

## ブラウザからアクセス
「yarn serve」実行時に出力された「http://localhost:8080/ 」にアクセスします

vueのWelcomeページが表示されれば成功です。

# ハマったポイント
```shell
% vue create vue-project
error eslint-plugin-vue@8.7.1: The engine "node" is incompatible with this module. Expected version "^12.22.0 || ^14.17.0 || >=16.0.0". Got "14.16.1"
error Found incompatible module.
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
 ERROR  Error: command failed: yarn 
Error: command failed: yarn 
    at ChildProcess.<anonymous> (/Users/xxx/.config/yarn/global/node_modules/@vue/cli/lib/util/executeCommand.js:138:16)
    at ChildProcess.emit (events.js:315:20)
    at maybeClose (internal/child_process.js:1048:16)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:288:5)
```

プロジェクトの作成で発生。
Node.jsのバージョンを16.0.0以上に指定して解消しました。

# 参考文献
https://chore-update--yarnpkg.netlify.app/ja/docs/install

https://cli.vuejs.org/
2023年，Qiitaでは何が流行ったのカナ？

# 前置き
2023年もたくさんの記事がQiitaに投稿されました．Qiitaではどのようなジャンルが人気だったか，タグの情報から見てみましょう．

# 動作環境
- Python 3.12.0
- Qiita API v2

Qiita API v2を使用する際の下準備は以下のサイトを参考にしました．

https://qiita.com/koki_develop/items/57f86a1abc332ed2185d

# ソースコード
前回の記事（[アドカレ開催中の流行はコレだ](https://qiita.com/suipy/items/4e143621362afec2f837)）に記載しているコードより，集計期間を変更しています．

# 月別タグ数ランキング
2023年に投稿された記事のうち，タグ数が多いTOP10を月別に集計した結果です．

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617469/0f46950c-c1bc-33de-007a-c42c8c57b6c5.png)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617469/04559b35-ab42-06b3-0c8c-02b0eed4d47a.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617469/14e97600-391b-c3b3-22a1-d9bc70dec871.png)
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617469/de376e44-68b5-9afc-292c-5e8eefe59cd5.png)

1年を通して，1位の座に輝いたのは```"Python"```でした．
"Python"の次に人気だった言語として，```"JavaScript"```や```"Java"```が挙げられます．

23年はAIの盛り上がりが凄かったこともあり，```"ChatGPT"```が上位にランクインしています．また，クラウドサービスの```"AWS"```も通年人気を博しています．

# 所感
23年はGPTの人気が凄かったですね．24年12月にGoogleがマルチモーダル生成AIモデル"Gemini"を発表したこと，24年にはGPT4を上回ると噂されている"Gemini Ultra"が発表されることもあり，24年はGeminiに関する記事が多く投稿されたり，引き続きAI関連の記事が多く投稿されたりするかもしれませんね．
ABC335回答メモ

# 0.はじめに
 新年一発目のABC。去年から引き続き緑を維持したいなと思いつつ挑戦。
 年末年始にいろいろあり、あまりトレーニングもできませんでしたが
 A~Dを解くことができたので、まぁ自分的には及第点でした。


# 1.A - 202
3

　しょっぱなのお題として肩慣らし的な問題。
　インプットをリストにすると、いろいろ面倒だったので
　リストに格納して、最後の文字を３から４に上書きし
　リストを結合して出力して終了としました。

　https://atcoder.jp/contests/abc335/submissions/49062788


# 2.B - Tetrahedral Number
　Bもまだ、正月気分な問題。
　回答例をみると、もう答えが出せそうな感じでした。
　制約もゆるいので、単純に3重ループで条件を満たす
　値を表示して終了しました。
 
　https://atcoder.jp/contests/abc335/submissions/49068230


# 3.C - Loong Tracking
　3問目から、急に難易度が上がりました。
　制約的にもTLEを意識しないといけなそうな感じ。

　【考え方】
 　　・竜の頭がどこにあるかのリストを作る
 　　・2の出力指示の時は、
   　　例えば、2番めの胴体の場合は頭が2個前に
     　あった場所を出力する。

　と、したところなんとかなりました。
　前準備として、実際は頭は通っていませんが
　胴体の初期位置も頭が通ったように
　セットしておくところがコツと言えばコツかなと思いました。

　https://atcoder.jp/contests/abc335/submissions/49084135


# 4.D - Loong and Takahashi
　Cより簡単かも。と思える問題でした。
　点数も350と、若干Cよりでした。
　条件を満たすためにはいろいろな
　方法はありますが、奇数固定で真ん中はTと決まっているので
　外から内にとぐろを巻くように数字を配置していく方法を取りました。

　【考え方】
 　　・右下左上に進むための増減値をリストに保持
 　　・左上からスタートし、枠外に出るか、進路が数字で
 　　　埋まっていたら方向転換
 　　・真ん中についたら終了

　最大Ｎ＝４５なので、あまり時間を気にせず作れました。

　https://atcoder.jp/contests/abc335/submissions/49101809


# 5.Non-Decreasing Colorful Path
　dfsでなんとか解けるかと提出してみましたがWAが出る始末。
　dp等もう少し考えないといけなさそうなので、解説を見ながら
　解いて置こうと思います。


以上
nvmでNode.jsのバージョンを変更したいのに反映されないときにしたこと

# 起こったこと
Next.jsのプロジェクトを作成したので「npm run dev」をしたところ、「You are using Node.js 16.16.0. For Next.js, Node.js version >= v18.17.0 is required.」が表示された。
※その時のバージョンは16.16.0を使用していました

Node.jsのバージョンをv18〜にするため、nvmで「nvm install v18.17.0」を実施し、「Now using node v18.17.0 (npm v9.6.7)」と表示された。

でも「node -v」をすると「v16.16.0」（過去にインストールしたバージョン）が表示され、更新されない。

「nvm use」や「nvm allas default」をしても変更されない。
# 結論
別のNodeJSのバージョン管理ツール「nodebrew」と競合していた。

# 対処
設定ファイル「.zshrc」を開いて、nodebrewに関するパスをコメントアウトし、再読み込みした。

## 手順（自分の場合）
vscodeを使用しているので、以下で編集
```
% code ~/.zshrc
```

```.zshrc
export PATH=/opt/homebrew/var/nodebrew/current/bin:$PATH
```
上記の行頭に#をつけてコメントアウトして保存。
```
% source ~/.zshrc 
```
上記を実行して設定を読み込み。
```
% node -v                          
v18.17.0
```
これで問題なくバージョンアップできました。
# さいごに
なぜこうなったのかは覚えていません。
おそらく昔によく分からずnodebrewを使用してそのままなんでしょう。

絶対問題がない方法かは分かりかねますので、もし参考にされる場合は自己責任でお願いします。

ちなみに解決に至るまでの調査はChatGPT（GPT4）に聞きまくりました。
初心者にとってはAI様様です。

理解を深めながらAIは今後も活用していこうと思います。
Nix向けシークレットを管理ツールagenixを使ってみる

## 背景
Nixでシークレット管理方法を探していたところ、agenixが良さそうだったので試してみることにしました。

## 流れ

下記を参考にインストールしていく
https://github.com/ryantm/agenix

今回はFlakes経由で以下の流れでagenixを試す

 - キーペアを作成する
 - agenixをインストール・設定
 - 機密情報を暗号化
 - 暗号化したシークレットをGitリポジトリにpush
 - Gitリポジトリにpushしたシークレットをnixから参照し復号化する

## キーペアを作成する

```bash
cd ~
ssh-keygen -t ed25519
```


## agenixをインストール


agenixのrust版であるragenixをインストール・設定を行います

```:flake.nix
{
  inputs = {
    agenix.url = "github:yaxitech/ragenix";
  };
}
```

```
{
  config,
  pkgs,
  username,
  inputs,
  ...
}: {
  # ageモジュールを導入
  imports = [
    inputs.agenix.nixosModules.default
  ];

  # agenixコマンドを導入
  environment.systemPackages = [
    inputs.agenix.packages."${pkgs.system}".default
  ];

  # 復号化に利用する秘密鍵を指定
  age.identityPaths = [
    "/home/${username}/.ssh/id_ed25519"
  ];
}
```

## 機密情報を暗号化

`secrets.nix`を作成する

```bash
mkdir secrets
cd secrets
vi secrets.nix
```

先ほど作った公開鍵をsecrets.nixに記入する

```nix:secrets.nix
let
  key1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMPUs/F1kXYEZ6b1+Twy4l/a9OT4MXDEfejh5Yc543zk";
in {
  "secret1.age".publicKeys = [key1];
}
```

以下のコマンドを使用して、シークレットファイルを作成する
```
agenix -e secret1.age
```

上記を実行するとエディタが開くので暗号化したい情報を入力、保存し終了すると暗号化されたファイルが`secret1.age`が生成される。暗号化したシークレットをGitリポジトリにpushする

暗号化して秘密鍵がないと復号化できないとはいえ、機密情報をGitにPushするのは抵抗があったため、プライベートGitリポジトリにしてpushしました。

## Gitリポジトリにpushしたシークレットをnixから参照する

nixからGitリポジトリを参照できるようにする

```diff:flake.nix
{
  inputs = {
    agenix.url = "github:yaxitech/ragenix";
+    mysecrets = {
+      url = "git+ssh://git@github.com/fabiiw05/xxxxx";
+      flake = false;
+    };
  };
}
```

暗号化したシークレットを復号化して任意のPathに配置する
```
{
  username,
  inputs,
  ...
}: {
  age.secrets = {
    id_rsa = {
      file = "${inputs.mysecrets}/keys/id_rsa.age";
      path = "/home/${username}/.ssh/id_rsa";
      mode = "600";
      owner = "${username}";
      group = "users";
    };
  };
}

```

## おわり
簡単に暗号化・復号化できました。
また、`agenix -e xxxxx`で暗号化情報を更新できるので運用面でも楽できそうです
Spring Boot + DB接続（H2データベース）

# はじめに
本記事ではSpring BootのWebアプリケーションにH2データベースを組み込む方法を記載します。

# 前提条件
- Spring Bootのプロジェクトが起動できること

上記がまだの場合は以下の記事を参考に起動まで実施してみて下さい

https://qiita.com/high_high/items/263cfcbd712ada6cddd3

# H2とは
H2とはオープンソースで開発されているRDBMSの1つで、プログラム本体のサイズが小さいため軽量に動作します。
また、H2はOSにインストールせずに利用できるというメリットがあり、Webアプリケーションに組み込んで使うのに便利なRDBMSです。
大量のデータを扱うような大規模アプリケーションでの利用には不向きですが、簡単なアプリケーションであれば十分に実用できます。

## 依存関係の追加
H2を利用するために依存関係を追加します。
※ビルドツールによって依存関係を追加するファイル名が異なります

- Mavenの場合
    ```pom.xml
    <dependencies>  
        ...
            
        // H2 を利用するための依存関係の設定
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
    
        // Spring JDBC を利用するための依存関係の設定
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
    </dependencies>
    ```
<br>

- Gradleの場合
    ```build.gradle
    dependencies {  
            ...   
            runtimeOnly 'com.h2database:h2'
            implementation 'org.springframework.boot:spring-boot-starter-jdbc'            
    }
    ```
:::note info
JDBC（Java DataBase Connectivity）とは
JavaのプログラムからRDBMSにアクセスしてデータの読み書きを行うためのAPI
:::

## application.properties に設定追加
JDBCドライバやデータベースへのアクセスに関する設定を追加します。

```application.properties
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:~/testdb
spring.datasource.username=h2db
spring.datasource.password=h2db

spring.sql.init.mode=always
spring.h2.console.enabled=true
```

|項目名|詳細|設定値（H2）|
|:-:|:-:|:-:|
|spring.datasource.driver-class-name|JDBCドライバのクラス名|org.h2.Driver|
|spring.datasource.url|データベースのパス|「jdbc:h2:」 + ファイルのパス<br>※上記例の場合`~/`配下に「testdb.mv.db」を作成して配置する|
|spring.datasource.username|ユーザ名|任意|
|spring.datasource..password|パスワード|任意|
|spring.sql.init.mode|SQLファイルを利用したデータベース初期化を行うかどうか|always：常に行う<br>embedded：組み込みデータベースの時のみ行う<br>never：行わない|
|spring.h2.console.enabled|H2コンソールを有効にするか否か|true：有効<br>false：無効|

:::note warn
**spring.datasource.url の設定値について**
H2には、メモリ上にのみ記録するインメモリデータベースと、
ローカルファイルに保存するローカルデータベースの二つのモードが用意されています。
インメモリデータベースの場合、アプリを停止するとメモリ上に記録されたデータは消えます。
ローカルデータベースの場合、データは消えずDBファイル（設定値に）に保存されます。(上記の例はローカルデータベースの場合)

インメモリデータベースの場合は以下のように設定します。
`spring.datasource.url=jdbc:h2:mem:データベース名`
:::

## 接続確認
アプリを起動してベースURLに「h2-console」という文字列を繋げてアクセスします。
例）ベースURLが「`http://localhost:8080`」の場合
`http://localhost:8080/h2-console`

以下の画面が表示されます。
![スクリーンショット 2024-01-06 23.03.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624418/31f727d3-4f1b-d7f1-35b6-3837705cd041.png)

JDBC URL , User Name , Passward に設定した値を入力して「Coonnect」をクリックします。
![スクリーンショット 2024-01-06 23.07.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624418/3b7c6af1-78ba-7568-c15b-87eb6d66ad21.png)

以下の画面が表示されれば接続成功です。
![スクリーンショット 2024-01-06 23.13.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624418/f8ea6dec-06a6-2bdc-9936-2b845cda8699.png)

# おわりに
2024年もよろしくお願いいたします🎍
間違いがありましたらご指摘くださいませ。
【SwiftUI】ボタンの長押ししている間は繰り返し処理を行う（iOS17）

# はじめに
言葉だけだとイメージしづらいと思うので具体例を出すと、キーボードのバックスペースボタンです。
バックスペースボタンを長押ししている間は文字を消し続けてくれます。

あれを自前で実装しようと思うと割と大変そうです。

iOS17から標準機能として提供され始めたので記事にしておきます。

# サンプルアプリ
![画面収録-2024-01-06-23.19.12.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/51e92b74-4e90-3a35-ca70-8cd669052b9c.gif)

# 実装
```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        Button {
            print("りんご")
        } label: {
            Text("長押しで「りんご」と繰り返し出力する")
        }
        .buttonRepeatBehavior(.enabled)
    }
}
```

:::note info
`disabled`を渡すといつも通りのボタンの動きになります。
```swift
.buttonRepeatBehavior(.disabled)
```
:::

# おわり
長押しで繰り返し処理ってキーボードのバックスペース以外に使われる箇所あるのかな？

# 公式ドキュメント
https://developer.apple.com/documentation/swiftui/view/buttonrepeatbehavior(_:)
AtCoder初心者振り返りメモ ABC335

# ABC335の回
https://atcoder.jp/contests/abc335

# A-問題
https://atcoder.jp/contests/abc335/tasks/abc335_a

![335A.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547298/af028778-f530-a045-bb83-8a210fdfdab3.png)


最初の発想は、"2023"を"2024"で置換するコーディングでしたが誤りがあり
末尾に '4' を追加する方針に変更しました。

````Python:A.py
# 2024/1/6 本番解答
# 入力
S = input()
T = ""
# 末尾を残して、T へ転記する
for i in range(len(S)-1):
    T += S[i]

# 末尾に '4' を追加する
T += '4'

print(T)
````

# B-問題
https://atcoder.jp/contests/abc335/tasks/abc335_b

![335B.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547298/328245e4-9ae5-51f2-a4b7-2c6e8114e8a2.png)

x,y,z の全通りを配列に格納しソートする方針で当初「set」で重複を削除するコードを書いていましたが、WAを記録したので重複削除をコメントアウトしたところ正答になりました。

````Python:B.py
# 2024/1/6 本番解答
N = int(input())

# x,y,z の全通りを配列Lへ格納
L = []
for x in range(N+1):
    for y in range(N-x+1):
        for z in range(N-x-y+1):
            if x + y + z <= N:
                w = []
                w.append(x)
                w.append(y)
                w.append(z)
            L.append(w)
# 配列Lをソート
S = sorted(L)

for i in range(len(S)):
    print(*S[i])
````

# C-問題
https://atcoder.jp/contests/abc335/tasks/abc335_c

![335C.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547298/320ea2c0-d6ee-d392-7475-0bf259187e5c.png)

問題通りの動作を実装しましたが、TLEで通りませんでした。時間を作って正答ができるように勉強します。

````Python:C.py
# サンプルは、解けるがTLE
N,Q = map(int,input().split())

S = []
T = []
for _ in range(Q):
    s,t = map(str,input().split())
    S.append(s)
    T.append(t)

C = [[0,0]]
for i in range(1,N+1):
    a = [i,0]
    C.append(a)

for i in range(Q):
    if S[i] == '2':
        t = int(T[i])
        print(*C[t])
    elif S[i] == '1':
        U = [[0,0]]
        if T[i] == 'U':
            x = C[1][0]
            y = C[1][1]
            U.append([x,y+1])
            for j in range(1,N):
                U.append(C[j]) 
        elif T[i] == 'R':
            x = C[1][0]
            y = C[1][1]
            U.append([x+1,y])
            for j in range(1,N):
                U.append(C[j]) 
        elif T[i] == 'D':
            x = C[1][0]
            y = C[1][1]
            U.append([x,y-1])
            for j in range(1,N):
                U.append(C[j]) 
        elif T[i] == 'L':
            x = C[1][0]
            y = C[1][1]
            U.append([x-1,y])
            for j in range(1,N):
                U.append(C[j]) 
        C = U
````