OmniAICreator/Qiita-1.07M huggingface dataset:
LangChainのAgentsを使用し天気情報をWebから取得する

[Chat Completions APIでFunction callingを試す](https://qiita.com/horiday/items/d53ea63dd81cbb4c3ea0)で実装した処理を、LangChainのAgentsで置き換える。
Function callingでは、関数の実行はアプリケーション側で実行し、実行結果をLLMへ返す必要があったが、AgentsではLLMが実行してくれる。
今回はduckduckgoでWeb検索を行うように実装する。

## ライブラリインストール
```
pip install langchain openai
```

## ソースコード
```
from langchain.agents import AgentType, initialize_agent, load_tools
from langchain.chat_models import ChatOpenAI

chat = ChatOpenAI(
    model="gpt-3.5-turbo",
)
tools = load_tools(["ddg-search"])
agent_chain = initialize_agent(tools, chat, agent=AgentType.OPENAI_FUNCTIONS)

result = agent_chain.run("What's the weather like in Fukuoka?")
print(result)
```

## レスポンス（例）
The weather in Fukuoka is currently sunny with a temperature of 27°C (81°F). The minimum temperature for tonight is expected to be 16°C (61°F). Tomorrow's temperature is forecasted to be warmer with a maximum of 27°C (81°F) and a minimum of 16°C (61°F).
スクリプトの最後に「終了するには何かキーを押してください」と表示させ、実行が無事終わったことを認識しやすくする

作ったスクリプトの最後に以下の文を記述してください。
```
Read-Host "終了するには何かキーを押してください" 
exit
```

PowerShellに馴染みのない方にps1ファイルを実行させる際、このような表示を用意してあげることで、実行者が処理が終了したことを認識しやすくなる……と思っています。

昔、初めてps1ファイルを実行した時にこういった記述が表示されたのを見かけたのですが、数年経っていざ自分で作るとなった際にググったところ、残念ながらそれらしいものが出てこなかったので、備忘録を兼ねて今回この記事を書きました。
（そもそも一般的にはこういう書き方はしないのかもしれませんが…）
reactで`npm start`時に以下のエラーが出る(export 'default' (imported as 'Amplify') was not found in 'aws-amplify')

以下を試している際に

> https://aws.amazon.com/jp/blogs/mobile/add-maps-to-your-app-in-3-steps-with-aws-amplify-geo/

reactで`npm start`時に以下のエラーが出る(export 'default' (imported as 'Amplify') was not found in 'aws-amplify')

```
export 'default' (imported as 'Amplify') was not found in 'aws-amplify'
```

以下のように`{}`をつけることで解決した

> https://github.com/aws-amplify/amplify-js/issues/10827#issuecomment-1366948142
> import { Amplify } from 'aws-amplify'

```
import { Amplify } from 'aws-amplify';
```

# 参考
https://aws.amazon.com/jp/blogs/mobile/add-maps-to-your-app-in-3-steps-with-aws-amplify-geo/

https://github.com/aws-amplify/amplify-js/issues/10827#issuecomment-1366948142
Azure で Terraform をはじめる

Azure のリソースを Terraform で管理すべく、とりあえず「リソースグループだけ作成する」ところまでやった。

## Azure 側準備
前提として、Azure テナントとサブスクリプションは既に作成済みであるものとする。

### 1. tfstate 置き場を作る
**[2024.03 追記]** Blob コンテナに tfstate 置くやりかた書いてみたけど、わりとめんどいので雑に検証するだけならローカルに tfstate 置くやりかたでいいと思う **[追記終わり]**

Azure リソースを Terraform で扱うのであれば特定のリソースグループ全体を扱うのがわかりやすいと思うし、その場合 tfstate の保存場所はそのリソースグループとは別の場所であるべきなのではないか。

1. tfstate 用のリソースグループを作る
    - 名前は `{プロジェクト名}-tfstate` にした
2. ストレージアカウントを作る
    - 名前が Azure 全体で unique かつ24文字までしか使えなくて困る
    - とりあえず `tfstate{ランダム数字列}` にした
3. Blob コンテナを作る
    - 名前は `tfstate` にした

### 2. Terraform 用のサービスプリンシパルを作る
Terraform にリソースの作成をしてもらうためには権限を与える必要があるので、そのためのサービスプリンシパルを用意する。

1. サービスプリンシパルを作る
    - `Microsoft Entra ID` > `アプリケーションの登録`
    - 名前は `{プロジェクト名}-terraform` にした
2. クライアントシークレットを作る
    - `(1.で作成したアプリケーション)` > `証明書とシークレット` > `クライアントシークレット`
    - 作成したクライアントシークレットを控えておく
3. `共同作成者` ロールを付与する
    - `サブスクリプション` > `アクセス制御 (IAM)` > `追加` > `ロールの割り当ての追加`
    - ロールに `共同作成者` を指定、メンバーにさきほど作成したアプリケーション (サービスプリンシパル) を指定する

## Terraform コードを書いて適用する

### Terraform コード
``` variables.tf
variable "project_name" {
  type = string
}

variable "region" {
  type = string
}

variable "azure" {
  type = object({
    tenant_id       = string
    subscription_id = string
    service_principal = object({
      client_id     = string
      client_secret = string
    })
  })
}
```

``` provider.tf
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>2.0"
    }
  }
  backend "azurerm" {}
}

provider "azurerm" {
  features {}
  tenant_id       = var.azure.tenant_id
  subscription_id = var.azure.subscription_id
  client_id       = var.azure.service_principal.client_id
  client_secret   = var.azure.service_principal.client_secret
}
```

``` main.tf
resource "azurerm_resource_group" "rg" {
  name     = var.project_name
  location = var.region
}
```

``` production.tfbackend

resource_group_name  = "my-project-tfstate"
storage_account_name = "tfstate01234567"
container_name       = "tfstate"
key                  = "production.tfstate"
```

``` production.tfvars
project_name = "my-project-production"
region = "japaneast"
azure = {
  tenant_id       = "..."
  subscription_id = "..."
  service_principal = {
    client_id     = "..."
    client_secret = "..."
  }
}

```

### Terraform コマンドを実行
``` console
$ terraform init -backend-config=production.tfbackend
```

``` console
$ terraform plan -var-file=production.tfvars
```

``` console
$ terraform apply -var-file=production.tfvars
```

``` console
$ terraform destroy -var-file=production.tfvars
```

## 参考資料
- [Azure に対して Terraform を認証する | Microsoft Learn](https://learn.microsoft.com/ja-jp/azure/developer/terraform/authenticate-to-azure?tabs=bash)
- [リソースにアクセスできる Microsoft Entra アプリケーションとサービス プリンシパルを作成する | Microsoft Learn](https://learn.microsoft.com/ja-jp/entra/identity-platform/howto-create-service-principal-portal)
Creative CloudにAdobeFontsを追加する方法

## 初めに
今回はAdobeFontsをCreative Cloudに追加する方法について説明していきます。

## Adobe Fontsとは
「Adobe Fonts」（アドビフォント） は、追加料金なしで使えるAdobeが提供するオンラインフォントサービスです。
数千〜数万種類に及ぶフォントコレクションから任意のフォントを選択することで、「Adobe XD」だけでなく、使用している「illustrator」や「photoshop」などにも自動的にフォントが追加されます。

## Adobe Fontsのページで追加したいフォントを検索する
![スクリーンショット 2023-11-05 23.49.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524155/067f6329-73de-a645-41a5-ede4eb8276eb.png)
上の画像は、Adobe Fontsのページ上部にある一番右側の「フォント一覧」のタブが選択された状態です。画面左側に検索条件を絞り込む欄がありますので、それぞれの項目を設定し、インストールしたいフォントを探します。
今回はCreative CloudにAdobeFontsを追加する方法について説明していきます。

## 追加したいフォントのファミリーを追加
![スクリーンショット 2023-11-05 23.58.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524155/0fefb974-0e35-d08f-6ffc-35031eec18b5.png)
「ファミリーを追加」をクリック
画面右側にフォントが表示されています。実際のフォントもプレビューで確認できますので、気になったフォントや使用目的に合ったフォントを探してみましょう。

インストールしたいフォントがあったら、フォントをアクティベートするスイッチをONにします。

フォントのファミリー（同じフォントスタイルで太さや斜体などのバリエーションをひとまとめにしたもの）が存在するものには、右側に「ファミリーを表示」というボタンが表示されていますので、ここをクリックします。

ファミリーがないフォントは、この画面にアクティベートボタンが表示されているので、使いたいフォントをONします。

## フォントのファミリーのページからアクティベート
「ファミリーを追加」をクリックすると、選択したフォントのファミリーのページが表示されます。ここにあるアクティベートのスイッチボタンをONすることでも、フォントが使えるようになります。

ファミリーすべてをアクティベートONにしたい場合は、上部にあるボタンを、一つ一つを選んでONにしたい場合はそれぞれのフォントの右側にあるボタンをONにします。

アンインストールしたい場合は、スイッチボタンをディアクティベート（OFF）にします。

## 最後に
１つのフォントを入れると、XD・Photoshop・Illustratorなど全てAdobeアプリ全てで使えるので、それぞれ設定せずに使用できて便利です！
ぜひ活用してください。
PokeAPIでポケモンの日本語名を取得するには

# はじめに
前回の記事（[PokeAPIで取得できるポケモンのデータを簡単にまとめてみた](https://qiita.com/jinto/items/c953ab25253d8ec82e30)）で、
`GET https://pokeapi.co/api/v2/pokemon/{id or name}/`
では、英語のポケモン名しか取得できないため、日本語名を取得したい場合は別途処理が必要であるという説明をしておりました。

こちらの記事では、`PokeAPI`でポケモンの日本語名を取得するための関数を、実際に作成してみようと思います。

# 実装コード
今回はpythonを使用することとします。

日本語名の取得には、
`GET https://pokeapi.co/api/v2/pokemon-species/{id or name}/`
を実行する必要があります。

参考：https://pokeapi.co/docs/v2#pokemon-species

```python
import requests

BASE_URL = "https://pokeapi.co/api/v2/"

def get_pokemon_japanese_name(english_name):
    response = requests.get(BASE_URL + f'pokemon-species/{english_name.lower()}')
    if response.ok:
        data = response.json()
        
        for name_info in data['names']:
            if name_info['language']['name'] == 'ja-Hrkt':
                return name_info['name']
        return "日本語名が見つかりません。"
    else:
        return "ポケモンの情報を取得できませんでした。"

# 使用例
english_name = "Bulbasaur" # ポケモンの英語名を入力
japanese_name = get_pokemon_japanese_name(english_name)
print(f"{english_name}の日本語名: {japanese_name}")
```

`GET https://pokeapi.co/api/v2/pokemon/{id or name}/`
では各言語でのポケモン名を取得できるので、上記のような関数を作成することで、英語のポケモン名を日本語に置換することが可能です。

どなたかの参考になれば幸いです。

# 関連

https://qiita.com/jinto/items/c953ab25253d8ec82e30
形式記述言語VDM++の制御構文（if文）をJava C# Re:Mind(自作言語)と比較

# はじめに

数学的形式手法VDM(Vienna Development Method)[^1]のオブジェクト指向拡張言語VDM++ですが、ロジックの実装も記述できる構文が用意されています。本記事ではVDM++の制御構文をJavaとC#そして自作言語のRe:Mind[^2] と比較してみます。

## この記事内容の作業目的
VDM++の下記の制御構文[^3][^4]についていくつかの記事に分割して比較検討します。VDMのような数学的形式手法を使わない場合は、一般的に自然言語の日本語で要求仕様が記述されているものと推察されます。本記事では数学的形式手法と自然言語の日本語記述とのはざまで、構造化された日本語が要求仕様記述に使えないか模索しています。

・ブロック文
・代入文
・**条件文**　←本記事対象
・ループ文
・call文
・return文
・コメント文
・例外

Re:MindはJavaやC#の経験者向けに設計された日本語プログラミング言語の一種で、ロジック仕様記述言語とトランスコンパイラ言語とで言語仕様を共有しています。
クラスの定義構文についてはこちらの記事[^5]を参照することができます。

## この記事内容の保証
各言語で書かれた引用ソースの妥当性は保証されません。また、本記事に開示された自作言語の仕様は、開発中の仕様のため予告なく変更される場合があります。

# 構文比較
## VDM++
```vdm:VDM++
    if i>0 then (
       --todo1
           )
    else if i<0 then (
       --todo2
    )
    else (
       --todo3
    )
```
## Java
```java:Java
    if(i>0){
       //todo1
   }else if(i<0){
       //todo2
    }else{
       //todo3
    }
```
## C#
```cs:C#
    if(i>0){
       //todo1
    }else if(i<0){
       //todo2
    }else{
       //todo3
    }
```

## Re:Mind
```mind:Re:Mind
    ◇i > 0 の場合
        //todo1
    ◇他に i < 0 の場合
        //todo2
    ◇他に
        //todo3
    ◇ここまで
```


# おわりに
VDM++はオブジェクト指向言語的な言語要素を持ち、数学的形式手法言語の中では一般のプログラミング言語のオブジェクト指向言語に近い面があります。VDM++のif文ですが、then句があるのがシェルスクリプトっぽいですね。


[^1]: IBMのウィーン研究所で1960年代から70年代にかけて開発された形式手法。その実装には1996年にISO標準（ISO_IEC_13817-1）となったVDM-SLと、そのオブジェクト指向拡張のVDM++がある。
[^2]: Qiita [オープンな設計言語仕様 日本語ロジック仕様記述言語 Re:Mind（リマインド）](https://qiita.com/mylifewithviolin/items/52f806777e6ea031de94) 参照
[^3]: FMVDM　[VDMTools 付属文書](http://fmvdm.org/doc/index-ja.h
[^4]: FMVDM-> github [[PDF] VDMTools VDM 言語マニュアル VDM++](https://github.com/vdmtools/vdmtools/raw/stable/doc-jp/lang-man/langmanpp_a4J.pdf)
[^5]: Qiita [要求仕様 形式記述言語VDM++ との構文比較 ロジック仕様記述言語 Re:Mind（リマインド）](https://qiita.com/mylifewithviolin/items/2a8c6dc66cead04536a8)
【TailwindCSS】PrettierでclassName以外に記述したクラスを並び替える

## `prettier-plugin-tailwindcss`をインストール

以下のコマンドを実行して`prettier`と`prettier-plugin-tailwindcss`をインストールします。

```terminal
npm install -D prettier prettier-plugin-tailwindcss
```

## `prettier.config.js`を記述する

`prettier.config.js`に以下を追記します。

```prettier.config.js
module.exports = {
  tailwindAttributes: ['myClasses'],
}
```

`myClasses`に記述したクラスも並び替えられるようになります。
勉強記録ウェブアプリ作成の軌跡 3:ルーティングinサーバーサイド

# 概要
「【Rails×React】UberEats風アプリを作りながら、SPA開発を学ぼう」を使って学んでいく上で自分で勉強記録アプリを作りたいと思ったので、完成するかは置いといて、とりあえず学んだことを自分が作りたいものに置き換えて考えていく。

# 内容
サーバーサイドにおけるルーティングを書いていく。いわゆるwebページのURLを決めていく感じである。
例えば、買い物をするサイト(sample.com)があったとする。そのTOPページのURLが`https://sample.com`だとする。そこから商品一覧ページに遷移した時のURLは`https://sample.com/goods`のようなURLとなるでしょう。また、そのサイトにおける自分のプロフィールページは`https://sample.com/myprofile/12334`などが考えられる。最後の数字はユーザごとに割り当てられたIDと考えてもらえれば。。。

このように特定のURLいわゆるリソースを取得するための道筋、ルートを書き記していく。

# 実装
基本的な書き方は以下の通りである。

- do endのブロックでくくることでrailsのルーティングを定義できる。
```config/routes.rb
Rails.application.routes.draw do
  ...
end
```
- namespace: hogeと書くことで名前空間を付与できる。
    - これはコントローラを表したものになっており、下記のようなnamespaceを用いるのであれば`app/controllers/api/v1/`というディレクトリに作成することになる
    - namespaceは複数配置することができる
```config/routes.rb
namespace :api do
  namespace :v1 do
    ...
  end
end
```
- 特定のリソースを表したい場合は、`resources`を使う
    - `resources :hoge`で`:hoge`というリソースに対して7つのルーティングが自動で生成される。
    - 7つというのはGETやPOST、DELETEなどのHTTPメソッドと呼ばれるものに対応したルーティングである。
    - 気になる方はこちらを<a href="https://railsguides.jp/routing.html#crud%E3%80%81%E5%8B%95%E8%A9%9E%E3%80%81%E3%82%A2%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3">参照</a>
- 特定のリソースを表したい場合は以下のような書き方でも可能
    - これはつまり「`line_foods/replace`というURLに対してPUTリクエストがきたら、`line_foods_controller.rb`の`replace`メソッドを呼ぶ」ということを意味する
    - `resources :hoge`との違いは、アプリケーション独自のルーティングとコントローラー、そのアクションに対応させられるという点
    - 原則は`resources、resource`で書く、例外的に必要であれば`put ... to:`も許容する形が学習サイト曰く良いらしい
```config/routes.rb
put 'line_foods/replace', to: 'line_foods#replace'
```

上記の書き方を元に書いた`config/routes.rb`が以下の通りである。
```config/routes.rb
Rails.application.routes.draw do
  resources :users do
    resources :articles do
      resources :scores
    end
  end
end
```

ちなみにターミナル上で下記コマンドを叩くことでそのアプリケーションで定義されているルーティングの一覧を見ることができる。
下記画像が現段階のルーティングの一覧である。httpメソッドをちゃんと指定していないため、不要なルーティングが残った状態である。今後コントローラを作成していく際に消していきたいと思う。

![スクリーンショット 2023-11-25 23.32.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1906633/bb9a0639-3a4f-db98-b731-f9ebed728104.png)

またルーティングの一覧の中から今後特定のルーティングを探したいときが来ると思われる。
その際は以下のような`grep`コマンド等を駆使することで容易に見つけることができるので、興味ある方はこういうことも学ぶといい。

```sh
# 出力されたrouts一覧から、'order'が含まれる一行のみを出力する
$ rails routes | grep order
```
# 参考記事
- 【Rails×React】UberEats風アプリを作りながら、SPA開発を学ぼう
    - https://www.techpit.jp/courses/138
ViteとGithub Pagesを使ってデプロイしたら画面真っ白！(React Routerが原因)

# はじめに

GitHub Pagesを使って作成したWebサイトをデプロイしてみたところ、画面が真っ白になりました！

デベロッパーツールを見ても、***エラーは特に出ていないのに、画面が真っ白*** という方がいれば、この記事が役立つかもしれません。

## 結論

私の場合はReact Routerが原因でした。

具体的にはGithub Pagesでデプロイすると、そのURLは

```
https://ユーザ名.github.io/リポジトリ名/
```

というようになり、URLのベースをリポジトリ名に合わせる必要があります。

この対策を行わなければ、React Routerが 
```
https://ユーザ名.github.io/
```
にアクセスしてしまっている？と思います。

それが原因で、ページが表示されず、真っ白になります。



## 解決策

それでは解決策に入りましょう。

環境変数やvite.configをいじったり、何個か解決策は存在しますが

私が最も簡単だと感じた方法を紹介します。
以下がその方法です！

```typescript
ReactDOM.createRoot(document.getElementById("root")!).render(
  <BrowserRouter basename={import.meta.env.DEV ? "/" : "/レポジトリ名/"}>
    <App />
  </BrowserRouter>
);
```

主な変更点は、***BrowserRouter*** に以下の部分を追加した点です。

```typescript
basename={import.meta.env.DEV ? "/" : "/レポジトリ名/"}
```

こちらを軽く解説すると、
<br>

まず、***import.meta.env.DEV*** によって開発環境か否かを認識します。

そして、その結果が ***True*** であれば ***"/"*** 

***False*** であれば ***"/レポジトリ名/"*** を

***basename*** に代入しています。

<br>

これによって、
デプロイ後の本番環境には、レポジトリ名をベースとしてReact Routerが画面遷移を行い、ページを正常に表示することが可能となります。

# 終わりに

エラーも出ずに、画面が真っ白になって驚いた方のお役に立てれば光栄です。
【Laravel】Route [ ] not defined. エラーの解決方法

## エラー内容
Laravelでルーティングを設定した後にブラウザでアクセスを試した際に、以下のエラーが発生。
```
Route [ルーティング名] not defined.
```
「ルーティングが正しく定義されていない」というエラー内容です。
コードを確認しても間違っていないのにエラーを解消できないことがあるので、その場合の解決方法を記事にして残しておこうと思います。
誤った点・補足等があれば、ご指摘していただけますと幸いです。

## ルーティングを確認してみる
エラー内容の通り、ルーティングの定義が正しくできていない可能性が高いので、まずは設定しているルーティングの内容を確認してみます。
以下のコマンドを実行してLaravelで設定されているルーティング一覧を表示します。
（この時、ルーティング設定しているファイル(routes/web.php)を確認するのも良いですが、コードが多いと何かと間違いに気づけないことも多いので、コマンド実行がおすすめです。）
```
php artisan route:list
```
コマンドを実行すると以下のように現在設定されているルーティング一覧が表示されます。
１行ずつ設定されているルーティングの情報が表示されており、左から順番にメソッド、ルーティング、ルーティング名...と書かれています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3527297/69e2ab38-54a1-c6c5-e5d5-6e78a1068f9c.png)

大事なのは、今回発生したエラーの**ルーティング名**（「Route [] not defined. 」の[ ]内にあたる部分）が正しく定義されいるかです。
恐らくエラーが発生した場合は、ここに定義したはずのルーティング名が表示されていないのではないでしょうか。

## リソースコントローラを用いてる場合は注意
コード上ではルーティングを正しく定義しているけどLaravel側では定義されていない場合、**同じルーティングが重複して定義が上書きされている可能性が高い**です。

特に、リソースコントローラを用いている場合は注意が必要です。
リソースコントローラは、CRUD操作を行うコントローラがセットになったもので、resourcesメソッドを用いると**たった１行**でCRUD操作のルーティングを自動で作成することができます。
[Laravel 8.x コントローラ](https://readouble.com/laravel/8.x/ja/controllers.html)
```php:routes/web.php
Route::resource('users', QuizController::class);
```
1行で複数のルーティングを定義できるという便利な反面、自動的に定義されたルーティングが何であるのかをしっかり把握しておく必要があります。
これを把握できていないと、気づかないうちに新しく作成したルーティングによって定義が上書きされてしまいます。

例えば、以下のようにルーティングを定義した場合、
```php:routes/web.php
Route::resource('users', UserController::class);
Route::get('users/create', [UserController::class, 'create'])->name('users.make');
```
上のresouecesメソッドで定義された「users/create」（ルーティング名 users.create）は下で定義した「users/create」（ルーティング名 users.make）によって上書きされます。
実際に、「php artisan route:list」を実行して確認すると、「user/create」は下で定義した「users.make」という名前になっていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3527297/af21e284-891f-f951-a6d4-00983986545e.png)

このように、resourcesメソッドを用いている場合、知らぬ間にリソースコントローラのルーティングを上書きしてしまうことがあります。
その結果、今回のエラーの発生要因にもなりやすいです。
この場合、どちらかのルーティングの定義を重複しないように変更すれば解決できます。

## キャッシュを削除してみる
ルーティングの定義の上書きがないことを確認したのにエラーがまだ解決できない場合、Laravel内部のキャッシュが原因で変更が反映されていない可能性があります。
その場合、以下のコマンドを実行してキャッシュを削除すると解決できます。
```
php artisan cache:clear
php artisan config:clear
php artisan route:clear
php artisan view:clear
```

## まとめ
Laravelで「Route [ ] not defined.」のエラーが発生したら、
*  「php artisan route:list」を実行してルーティングが定義されていないか確認する。
*  リソースコントローラを用いている場合はルーティングの定義の上書きに注意する。
*  キャッシュを削除してみる。

---
参考サイト
*  [リソースコントローラーを用いた際に、定義済みのルートを上書きしてしまってLaravel Route [ ] not defined.が発生。](https://qiita.com/Maru_Technical/items/74c265d9dc4ca8649376)
*  [【Laravel】コードが間違ってないのにエラーになる時の対処法](https://network-beginner.xyz/laravel_code_error)
*  [Route not defined.](https://laracasts.com/discuss/channels/laravel/rout-not-defined)
【python】setの計算量（AtCoder/競プロ）

## はじめに
[AtCoderのABC329のF問題](https://atcoder.jp/contests/abc329/tasks/abc329_f)を解いていて、

pythonのsetは、
小さい方（lengthが小さいset）を大きい方（lengthが大きいset）に
代入するようにupdateする方が実行速度が速いことを初めて知り、

本当にそうなのか？

と疑問に思ったので、調べてみました。

## 本当に代入する方向で計算量が変わるのか

実行時間を比較するために、以下のようなpythonファイルを作ってみました。
```py:set_set.py
# set の作成
set_long = {i+10 for i in range(1, 10000001)}
set_short = {i for i in range(1, 11)}
```
```py:short2long_update_set.py
set_long = {i+10 for i in range(1, 10000001)}
set_short = {i for i in range(1, 11)}

# 大きいsetに小さいsetを代入する
set_long.update(set_short)
```
```py:long2short_update_set.py
set_long = {i+10 for i in range(1, 10000001)}
set_short = {i for i in range(1, 11)}

# 小さいsetに大きいsetを代入する
set_short.update(set_long)
```


まずは、setを作るのにどれくらい時間がかかるのかを測ります。
```sh:ターミナル
$ time python3 set_set.py 
python3 set_set.py  0.38s user 0.24s system 77% cpu 0.794 total
```

次に、set_long（大きいset）にset_short（小さいset）を代入するときの時間を測ります。

```sh:ターミナル
$ time python3 short2long_update_set.py
python3 short2long_update_set.py  0.38s user 0.24s system 75% cpu 0.820 total
```
これを見ると、setを作るのにかかる時間とほとんど変わらない時間でupdateできていることが分かります。
つまり、代入の処理にはほとんど時間がかかっていないと言えます。

さらに、set_short（小さいset）にset_long（大きいset）を代入するときの時間を測ります。

```sh:ターミナル
$ time python3 long2short_update_set.py
python3 long2short_update_set.py  0.54s user 0.77s system 66% cpu 1.989 total
```

これを見ると、set_longにset_shortを代入するときより、実行にかなり長い時間がかかっていることが分かります。

以上から、

大きい方（lengthが大きいset）を小さい方（lengthが小さいset）に
代入するようにupdateするより、

小さい方（lengthが小さいset）を大きい方（lengthが大きいset）に
代入するようにupdateする方が、

実行速度が速いことが確認できました。

## どうしてなのか

どうして実行速度がこんなにも違うのか疑問に感じたのですが、
pythonのドキュメントを読んでもいまいち分からず...。

updateメソッドは、元のsetに代入したい要素を一つずつaddしている？と考えると、
なんとなくイメージできそうです。

詳しい方がいれば、updateメソッドの仕組みをぜひ教えていただけると幸いです。
ASP.NET Core MVC トランのテーブルから複数同じマスタを参照（JOIN）するModel

例えば「売上」テーブルがあって「担当者ID」「入力者ID」とそれぞれ「従業員」マスタテーブルを参照する項目があった場合、確か（うろ覚えだが）ASP.NET MVCでシステムを構築していた際にModelの作成がうまくできず（結合できない？）、仕方がないからSQLServer側に従業員マスタから「入力者従業員」とView（MVCだとややこしいがMVCの画面のViewではなくデータベース）を作ってASP.NET MVCではModelをそれぞれ「担当者」「入力者」とそれぞれ作成、売上テーブルからもそれぞれ参照という無駄？な作りにした。

今回、ASP.Core MVCに移行することになって同様に作成（というかコピー）していたところ、View（MVCだとややこしいがMVCの画面のViewではなくデータベース）で作成したModelをDBContextからLINQ？で呼び出した際に以下のエラーになってしまった。
Unable to determine the relationship represented by navigation

半日くらい調べてようやく解決。

以下のようModelを設定する。(データベースの「入力者従業員」は結果不要になった)

「売上」

 [Column("employee_id")]
 [DisplayName("担当者")]
 public int? EmployeeId { get; set; }
 
 [Required(ErrorMessage = "{0}は必須入力です。")]
 [Column("enter_employee_id")]
 [DisplayName("入力者")]
 public int EnterEmployeeId { get; set; }
 ・・・
 public virtual Employee? Employee { get; set; }
 public virtual Employee? EnterEmployee { get; set; }


「従業員」（前は「担当者従業員」と「入力者従業員」の2つ作成していた）
public int Id { get; set; }
public string Code { get; set; } = null!;
public string Name { get; set; } = null!;
・・・
[InverseProperty("Employee")]
public virtual ICollection<Sale>? EmployeeSales { get; set; }
[InverseProperty("EnterEmployee")]
public virtual ICollection<Sale>? EnterEmployeeSales { get; set; }

ポイントはInversePropertyですかね。
Workato：OpenAIに文字数の多いデータを扱わせる方法（翻訳を例に）[後編]

#### 前編はこちらです
先に前編を読んでいただけると理解がしやすいかと思います。

https://qiita.com/tsuyu_masa/items/4186c3d0b40a91c85891

## 制限を回避する方法（レシピ）
今回は、翻訳したい文章(英語)を入力として受け取り、翻訳結果をdriveにアップするファンクションを作成しました。画像と共に各Stepを説明していきます。

#### 1. 変数等の準備

- ファンクションの宣言（入力として翻訳対象の文章を受け取る）
- 翻訳対象の文章を変数に保存
- 切り出す各ブロックの開始位置を指定する変数を作成

![スクリーンショット 2023-11-25 20.50.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628220/7f0cedd9-406d-0c03-561c-b2ed5db1cccc.png)

#### 2. ループ数の計算


- 翻訳対象の文章`file content`のサイズを知るため、`.bytesize`を用いる。
また、それを5000で割り、1を足すことで、何ブロック（ループ）を回す必要があるかを事前に計算する。

![スクリーンショット 2023-11-25 20.50.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628220/a61b740a-bab1-b0b2-22d0-d3dfbfbc563e.png)

#### 3. 補助リスト

- ループを④を作成した回数分回したいため、補助的なlistを作成する。
`Lists by Workato`→ `Create repeat helper list`

![スクリーンショット 2023-11-25 20.51.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628220/68bb263d-3d61-fea1-0acc-187e7440b77f.png)

#### 4.　5000文字を切り出す
- `.slice`を用いて、翻訳対象の文章のindexから5000文字(`0~4999文字目`)を切り取る。
(`Next translated`という変数に保存)

- また、step7で、翻訳後の日本語を貯めていくための変数を作成しておく。

![スクリーンショット 2023-11-25 21.07.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628220/18c2198a-722c-4d5b-6599-4986d7ff620f.png)

#### 5. ループ部分

- 作成した補助listの回数分だけloopを回す。

![スクリーンショット 2023-11-25 20.51.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628220/f6e8faae-de8b-95e7-46ac-d59f8ed86176.png)

#### 6. OpenAIのAPI呼び出し

- `Next translated`には、次に翻訳する英文が入っているため、それをOpenAIのAPIへの入力とする。
- OpenAIの翻訳に関するアクションは、`Translate text`ではなく、`Send messages to ChatGPT`を利用した。（`Send messages to ChatGPT`でrewiteをお願いする方が、より自然な翻訳ができる気がする、、）

![スクリーンショット 2023-11-25 20.52.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628220/67b08026-802b-4e7e-61d2-09494e24769f.png)

#### ７. 翻訳結果を結合

- `.join`を用いて、すでに翻訳されたものと、新しく翻訳したものを結合し、一時変数に保存する。
- また、step11でindexの更新を行う。(`index`の値は、0->5000->10000と5000ずつ増やす)

![スクリーンショット 2023-11-25 20.52.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628220/71f8d465-119b-612e-e83d-507a893658d7.png)

#### 8.　次の翻訳対象を切り出す

- 更新したindexを用いて、次の翻訳対象の5000文字を切り取り、`Next translated`として保存する。

![スクリーンショット 2023-11-25 20.52.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628220/65ed759d-2f2f-0d19-adbb-015644150364.png)

#### 9. 最後に

- 最終的な結果を格納。
- Driveにアップロード。

![スクリーンショット 2023-11-25 20.52.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628220/a7887531-d50b-9691-f4d8-a0c62afca6e4.png)

##
長々と書いてしまいました、、ここまで読んでいただいてありがとうございます！
このようなレシピで、OpenAIを用いて、どれだけ長い英語の文でも、無制限に翻訳できるようになりました！
#####
皆さんのお役に立つことを願っております🤲
MetaQuest3でテンプレートのVRアプリを実機テストしてみた

MetaQuest3の実機でUnityのVRテンプレートを動かしたのでメモしておきます。

## UnityでVRテンプレートを用意
まずUnityのプロジェクトを新規作成でVR(core)のテンプレートで作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105499/f11651ce-b57a-8390-1e12-07c52ffe825d.png)

:::note warn
Unityバージョンが古い場合は画面がピンク色のマテリアルのシェーダでエラーが出ます。これはUnity Registryというプラグインの保管庫があるのですが登録されてるURPプラグインが古いからです。Unityを最新バージョンにすると直りますが簡易な方法でしのぐこともできます。
:::

**方法１.シェーダをStanderdシェーダに置き換える**
まず、アセットの検索欄でt:Materialを入れて絞り込みます。
ピンク色のマテリアルをすべて選んでshaderをStanderdShaderに変更します。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105499/890ec353-6d7d-88ac-340c-02fb60b7d3c7.png" />

**方法2. 今のURPパッケージを更新する**
下図のように古いURPパッケージを削除して新しいURPをインストールします。
ちなみに方法1でStanderdシェーダに変更した場合は、上記と同じようにピンクのマテリアルをすべて選んでshaderをUniversal Render Pipeline/Litに変更してください。

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105499/ce3b0ab5-e253-8184-27d9-46c93651ec7c.png" />
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105499/e42e10f2-c78d-8781-d302-67511a19f99a.png" />

するとこんな感じになります。
（普通にUnityを最新バージョンにするほうがいいと思われます...）
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105499/3c99e4cf-231c-9b54-1dec-bff0bb1e62ef.png" />


## Unityの出力プラットフォームをAndroidにする
実はMetaQuest端末はモバイル端末の分類でしてアプリはAndroidアプリでした。
File > BuildSettings からPlatformをAndroidにスイッチします。

## 開発者モードをON
次にMetaQuest3実機をPCで認識するために開発者モードをONにします。
これはスマホのMetaQuestアプリから行います。

:::note info
MetaQuestの初期設定で実機をWi-fiにつなぐ際に、スマホにQRを読ませて連携します。するとMetaQuestのアプリのインストールをそくされ実機とスマホをペアリングする流れになります。こうしてスマホアプリはMetaQuest実機のリモコンみたいになります。
:::

スマホアプリの設定から開発者モードをONにすると<b>実機でポップアップが出るので許可を選択します</b>。

:::note warn
実機のポップアップを見逃していたので、MetaのサイトからMetaQusetDeveloperHubをPCにインストールしてADB Pathを設定しましたがなくても認識できると思われます。
:::

次にケーブルでPCに接続すればUnityのビルド設定のDevice欄のプルダウン内にMetaQuest3の項目が現れるので選択します。
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105499/cc21b797-adb8-6860-5f6d-20ed1fb8bb14.png" />

Build And Runでしばらくすれば実機でアプリが動きます。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105499/1e2fac2d-66c1-9384-3da3-b355fb23c308.png" />
PyTorch Geometricのデータセットの自作するための簡単なまとめ

PyGはグラフの機械学習に有用だが、データセットの自作が最初は難しかったので最低限必要な知識を記しておく。

## InMemoryDataset

CPUメモリに収まるデータセットを構成できる便利なクラス。

### 概観

最初にインスタンスを生成すると、`process`メソッドが呼び出されてデータセットが処理される。
`torch.save()`でデータが`data.pt`に保存され、次回以降高速に読み込める。

#### 最低限知っておけばよいメソッド
- `raw_file_names`
処理前の生のデータのファイルがあればここに書いておく。

- `processed_file_names`
処理されたデータが、`__init__`で渡したディレクトリの下にこのファイル名で保存される。

- `process`
グラフのノード, エッジ, 重み, 特徴量の設定などを行う。基本的に`torch_geometric.data.Data`クラスでグラフを表現し、`torch.save()`でファイルに保存される。

```python
import torch
from torch_geometric.data import Data, InMemoryDataset


class MyDataset(InMemoryDataset):
    def __init__(self, root="データセットを保存するパス") -> None:
        super(MyDataset, self).__init__(root)
        self.data, self.slices = torch.load(self.processed_paths[0])

    @property
    def raw_file_names(self) -> list:
        return []

    @property
    def processed_file_names(self) -> list:
        return ["data.pt"]

    def process(self) -> None:
        data = Data(...)
        self.data, self.slices = self.collate([data])

        torch.save((self.data, self.slices), self.processed_paths[0])
```

### Dataクラスの使い方

グラフの表現には`torch_geometric.data.Data`クラスを使用する(素のPyTorchにも`Data`クラスがあるので一応区別して書く)。

#### 最低限知っておけばよいアトリビュート

![スクリーンショット 2023-11-26 9.17.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588797/d737df31-9ffd-12be-b838-af90a1491af2.png)


- `x`: ノードの特徴量、例えば座標など。
インデックスがノード番号に対応する。
```python
x = torch.tensor(
    [
        [0, 1],
        [1, 2],
        [1, 0],
        [2, 2],
        [2, 0]
    ]
)
# shape: (ノード数, ノードの特徴量の次元)
```

- `edge_index`: エッジのインデックス(COO format)。エッジの始点を行ベクトルで並べ、同じ順で終点を並べる。

```python
edge_index = torch.tensor(
    [
        [0, 0, 1, 2, 4],
        [1, 2, 4, 4, 3]
    ]
)
# shape: (エッジ数, 2)
```

- `edge_attr`: エッジの特徴量、例えば重みなど。
`edge_index`と同じ順で対応させる。

```python
edge_attr = torch.tensor(
    [
        [1, 3, 2, 6, 1]
    ]
)
# shape: (エッジ数, エッジの特徴量の次元)
```

- `y`: ノードのラベル、例えば属するコミュニティなど。予測タスクのための学習などに用いる。`x`と同じ順で、ノード番号に対応させる。

```python
y = torch.tensor(
    [
        [0, 0, 0, 1, 1]
    ]
)
# shape: (ノード数, 任意)
```
[React]Docker環境でホットリロード出来なくなってしまった

[以前書いた記事](https://qiita.com/ysda/items/2e1c497f0275a4300302)で開発を進めていたら、ホットリロードが出来なくなっていた。
それどころか、リロードしても修正が反映されない。。。
開発環境をDockerに移行した途端このような事態になったので、原因はDockerにあるはず。というわけで、調査＆修正を行った。

## 原因
原因はすごく簡単な事だった。
Dockerfileで、コードをbuildして静的ファイルを作成→Nginxコンテナに静的ファイルをコピーという手順を踏んでいる。
ブラウザで表示しているのはNginxコンテナ内のファイルであるため、いくらコードに修正しても反映されるわけがない。
そりゃそうだ。。。

```Dockerfile
FROM node:21-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
ENV NODE_OPTIONS=--openssl-legacy-provider
RUN npm install
COPY . ./
# 原因1
RUN npm run build

FROM nginx:alpine
# 原因2
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
```

## 修正内容
ホットリロードするためには、ソースをbuildせずnpm startでプロジェクトを実行すればいい。
とはいえ、本番環境ではNginxに静的ファイルを置いたほうがいい。(ファイルサイズの圧縮とかパフォーマンスの向上のため)
ということで、docker-composeファイルを作ってマルチステージビルドすることにした。

・Dockerfile(修正後)
```Dockerfile
# development stage
FROM node:21-alpine AS dev
WORKDIR /app
COPY package.json package-lock.json ./
ENV NODE_OPTIONS=--openssl-legacy-provider
RUN npm install
COPY . ./
CMD ["npm", "start"]

# build stage
FROM dev AS build
RUN npm run build

# production stage
FROM nginx:alpine AS prod
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
```

docker-compose.yml
```yml
version: '3'
services:
  front:
    build: 
      context: .
      #　ここ重要
      target: dev
    volumes:
      - .:/app
      - /app/node_modules
    ports:
      - "${PORT_MAPPING}"
    environment:
      - NODE_ENV=${NODE_ENV}
```

## 制御方法
Dockerfileでやっていることは以下。
開発環境では1、本番環境では1~3を実行するようコマンドで制御する。
1. developmentステージでアプリケーションのイメージ作成
1. buildステージで静的ファイル作成
1. Nginxに静的ファイルをコピー



本番用のイメージを作りたい時はオプションでprodを指定する。
こうすることで、上記1~3を実施する。

```sh
docker build --target prod .
```

開発環境ではdocker-compose upするだけでOK。
```
docker-compose up
```
Ender3V2neoでプレビューを表示する

# 初めに
Ender3 v2 neoを買って使ってたのはいいけどなぜか自分が作ったG-codeファイルを使うとプリンターのほうでプレビューが表示されてなかったので自分が作ったG-codeでもプレビューが表示できるようにしました。
# 注意
この方法はあくまで**Ender3V2neo専用**です
# 環境
- OS: win11
- スライサー: Cura5.5
- プリンタ: Ender3 v2 neo
# 方法
1. 初めに[こちら](https://raw.githubusercontent.com/KenHuffman/UltimakerCuraScripts/main/scripts/CreateV2NeoThumbnail.py)を右クリックして`名前を付けてリンク先を保存`を押してファイルをダウンロードしておいてください。多分`CreateV2NeoThumbnail.py`というファイルがダウンロードされます。
1. 次にCuraを起動させて`「ヘルプ」->「コンフィグレーションのフォルダを表示する」`の順に進んでください。フォルダが大量にあるエクスプローラーが開かれると思うのでそのフォルダ群から`scripts`というフォルダを見つけ出してその中にさきほどダウンロードした`CreateV2NeoThumbnail.py`を貼り付けてCuraを再起動してください
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3495899/bf6ae465-eaf9-2044-e1e8-4241fd4acacf.png" width="500">

1. 再起動したら`「拡張子」->「後処理」->「G-codeを修正」`と進んでください。
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3495899/2ee3476a-76cb-6e32-c23e-634e7b0ef14c.png" width="500">
1. `プラグイン処理後`というウィンドウが開かれると思うのでその中にある`スクリプトを加える`をクリックし、その中の`Create V2Neo Thumbnail`というファイルを選択してください。
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3495899/5c8faed8-cc6e-c39d-76b0-ef56626b726d.png" width="500">
 このような画面になると思うので右のパラメータを好きなように変更してもらって`閉める`を押してください。
1. これで設定は終了です。あとは適当に生成してプリンタで確認してみるとちゃんとプレビューできてることが確認できるとおもいます。
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3495899/8bc91448-0d34-fae5-22fe-079cf895de67.jpeg" width="500">
# 参考物件
https://github.com/KenHuffman/UltimakerCuraScripts/tree/main
isucon初参加の雑振り返り

ISUCON13に参加しました！
初めての参加で結果はアレでしたが、忘れない＆やる気があるうちに雑な振り返りを書きます。
もう本当に準備不足で色々ひどいという感じです。ご容赦ください。
他チームの方々と比べてやってることが稚拙すぎて恥ずかしいですが、この気持ちを忘れないためにも投稿しておきます。

## 準備編

全然準備できていませんでした。不甲斐なくてなんか謝りたい気分です。ごめんなさい。
isucon本は少しずつ読んではいたものの、卒論やらレポートやらで忙しく、6章あたりまでしか読めていませんでした。
また、同期のチームメンバーも似たような状況だったためか、チームで予定をあわせることができずチーム3人で通し練習みたいなのも一度もやらずに本番となってしまいました。あぁ‥

## 本番

最初、CloudFormationをどうすればいいのか、sshの鍵、AWSのクレジットなどでバタついた他、ベンチはどのサーバーを指定すればいいのかなどが分からずかなり時間を取られてしまいました。
これに関しては、最初10分ちょっとで最初の測定が終わっているチームと比べて、1時間くらい競技時間が短かったんじゃないかというレベルでグダグダでした。当たり前オブ当たり前ですが、やはりチームで一度通すべきでした‥

それでもお昼を食べ終わった辺りからは、全員がなんとなく開発のイテレーションの回し方を把握できた感じになり、少しずつスコアが伸びていきました。

競技中特にモヤモヤしたのは、作業がスコアに直結するとは限らないという点です。
リクエストの合計時間が一番長いエンドポイントのn+1を解消したのですが、そこが点数的な意味でのボトルねくではなかったようで、殆どスコアは変わらないというようなことがありました。
スコアの計算方法をもっとしっかり読んでおくべきだったように思います。

最後、残り20分くらいのタイミングで急にベンチがコケるなどのアクシデントにも見舞われましたが、なんとかちゃんと動くバージョンまでロールバックでき、最終的なスコアは6000点ほどになりました。6桁にたどり着いてるチームは本当にすごいんだなと思い知らされました。

## その他雑な反省点

だんだん疲れてきたので、雑にまとめます

- 最初、どうイテレーションを回していくかみたいなのが分からなかった点
  - 全員でどうやったらアプリケーションを再起動できるか確認する時間とかあったらよかったかも
  - 何ならgit pullしてこのコマンド打てばいい感じになる、みたいなスクリプトとかあればもっと楽‥？
  - ブランチ戦略にもよりそう↑
- 最初の立ち上がりが少しモッサリしてた点
  - CloudFormationとかクラウド料金のやつちゃんと把握してなかったのスマン
  - 最初の測定とその評価にたどり着くまでかなり時間がかかってしまった
- htop専用画面生えてたの良かった
  - 分かりやすい
- alp用ワンライナーちゃんと共有しておいてよかった

## すればよかった細かい工夫

- nginxのログのローテーションを事前準備
- mysqlのスロークエリログのローテーションも事前準備
- nginxのログをjsonに書き換える設定も用意しておく
- 横着せずに.ssh/configをちゃんと書く
  - 毎度discordからコピペしてたのアホ
- alpのワンライナーをコピペする際、ログのタイムスタンプを毎度変えるのがめんどくさい
  - 最新っぽいやつを勝手に表示するワンライナーもあった方がいい
- hosts書き換え、ホスト側windowsだけじゃなくてwslもやればよかった
  - 雑curlデバッグのやりやすさがかなり違う
- 競技インスタンス上のシェルが使いづらすぎた。
  - zshやfishを入れておくべきだった
- ブランチ管理やgitの使い方が下手だった
  - 横着してコミットせずにインスタンス上でちゃちゃっと直しちゃうみたいなのよくない
  - これのせいで混乱が生じた
- 当日ガイドもっとしっかり読んで、点数に寄与する部分をしっかり見るべきだった
  - 全員でガイド読んだ方がいいというのを実感した
- ローカルでテストする用の準備
  - dbをササッと立ち上げたり、認証のミドルウェアをデバッグ時だけ消すようにしたりの手順をまとめてチーム内で共有すべき

## まとめ

一度でも通しで練習をしておけばそうはならんかっただろ、みたいな反省点が多く目立ちました。来年はちゃんと素振りします。
AtCoderでよくある##...###..やxooxxooooxxxooxみたいな文字列を0と1のnumpy配列に変換する

## やりたいこと
以下のような問題で、入力文字列を0と1の配列に、解答用の0と1の配列を#と.の配列に変換するクラスを定義する
https://atcoder.jp/contests/abc075/tasks/abc075_b
https://atcoder.jp/contests/abc107/tasks/abc107_b

## コード

```python
def signs_to_np_binary(signs):
    """ 文字列を1と0のリストにする """
    list_ = list(signs)
    binary = [1 if x == "#" else 0 for x in list_]
    binary = np.array(binary)
    return binary

num_array = signs_to_np_binary(input())

for i in range(h-1):
  s = signs_to_np_binary(input())
  bom_map = np.vstack([bom_map, s])
```

```python
class DotsAndHashes():
  def __init__(self, choice_0 = ".", choice_1 = "#"):
    self.choice_0 = choice_0
    self.choice_1 = choice_1

  def input(self,h,w):
    """input is h*w strings of .or#, return 0or1 array"""
    self.h = h
    self.w = w
    self.str_arr = list( input() )
    self.bin_arr = np.array( [0 if x==self.choice_0 else 1 for x in self.str_arr] )
    for i in range(1,self.h):
      self.str_arr = list(input())
      self.bin_arr = np.vstack([self.bin_arr,np.array( [0 if x==self.choice_0 else 1 for x in self.str_arr] )])
    return self.bin_arr

  def output(self,num_arr):
    """ input is 0or1's numpy array , return strings """
    self.num_arr = num_arr
    for i in range( len(self.num_arr) ):
      self.list_ = self.num_arr[i,:]
      self.list_ = [choice_0 if choice_1 else "#" for x in self.list_]
      print("".join(self.list_))
```

## 注意
w=1, もしくは h=1 の場合は例外処理をしなければなりません。
もしご要望がありましたら、追記いたします。
snpEffを動かす [備忘録]

GATKやsamtoolsなどを用いて検出したバリアントについて，どの遺伝子に影響があるのかを調べるためには，アノテーションをつける必要がある。snpEffを用いると，アノテーションとバリアントの効果を予測することができる。snpEffの使いかたについて，簡単に備忘録としてまとめる。

snpEffについて詳しい情報は以下を参照。

https://pcingola.github.io/SnpEff/

また，日本語だと，以下の上坂一馬さん(id:kazumaxneo)のサイトが詳しい。(ただし，カスタムアノテーションについては，configファイルを書き換える方法もあるので，特にその部分については私が書いたカスタムアノテーションの項目についても参照してほしい)

https://kazumaxneo.hatenablog.com/entry/2021/05/13/120000

## 使用環境等
MacOSで，snpEffは以下にようにcondaでインストールした。
```
$ mamba install -c bioconda -y snpeff

$ snpEff -h
SnpEff version SnpEff 5.2 (build 2023-09-29 06:17), by Pablo Cingolani
Usage: snpEff [command] [options] [files]
```
## アノテーション
基本的な使用方法は以下の通り。
（１） データベースのダウンロード
まず，用いる生物種のデータベースがあるか確認する。
```
$ snpEff databases
```
上記のコマンドだと，データベースにあるものが全部表示されるので，以下のように見つけたい生物種で絞り込む。(ここでは，Aspergillus oryzaeを対象とする)
```
$ snpEff databases | grep -i Aspergillus
```
用いる生物種のデータベースが見つからない場合は，以下の[カスタムアノテーション](https://qiita.com/shibanosuke/items/7fd695ffa9a04448f1db#%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%82%A2%E3%83%8E%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3)に進む。

用いる生物種のデータベースが見つかった場合は，以下のようにデータベースをダウンロードする。
```
$ snpEff download -v Aspergillus_oryzae
```

（２）アノテーションの実行
以下のように，実行する。(variant.vcfはアノテーションをつけたいファイル，annotation.vcfはアウトプットファイルの名前)
```
$ snpEff -v -stats result.html Aspergillus_oryzae variant.vcf > annotation.vcf
```

## カスタムアノテーション
データベースに目的の生物種，もしくはアノテーションデータがない場合には，自身で登録したファイルも使用可能。bed，gtfファイルなどが使用できるが，ここではgffファイル(gff3)を用いる方法を紹介する。

（１）ファイルの準備
ゲノムのリファレンス配列(fastaファイル: .faの拡張子にする)とアノテーションファイル(gff3形式のファイル: .gffの拡張子にする)を用意する。ここでは，RIB40という株についてアノテーションをつけることにする。公式ではgz圧縮した例が紹介されているが，非圧縮ファイルでも作業内容は同様。

（２）ファイルのbuild
snpEffのインストールディレクトリにまず移動する。condaで導入した場合には以下のような感じ。
```
$ cd /Users/Username/mambaforge/share/snpeff-5.2-0 
```
このディレクトリにある，snpEff.configファイルに，ゲノムの情報を追加する。例えば以下のような感じ。(上一行はなんでも良い気がするが，よくわからない)
```
\# RIB40 genome, version RIB40
RIB40.genome : RIB40
```
/snpeff-5.2-0/data/ディレクトリに移動。新しいディレクトリを作成する。この時，名前はアノテーションをつける株の名前にしておく。(つまり，"RIB40"という名前のフォルダを作る)

/snpeff-5.2-0/data/RIB40/に移動し，gffファイルを置く。ファイル名はgenes.gffにする。
さらに，fastaファイル(RIB40.fa)をsequences.faに名前を変えて置く。
(fastaファイルは，/snpeff-5.2-0/data/にgenomes/というディレクトリを作り，その中にRIB40.faとしてファイルを置いても良い)

/snpeff-5.2-0/に移動し，以下のコマンドを打つ。
```
$ snpEff build -gff3 -noCheckCds -noCheckProtein -v RIB40
```
-v オプションで株名(データベース名)を指定する。また，今回はgff3形式ファイルを用いたので，-gff3 オプションで指定する(他のファイル形式は公式サイトを参照)。
他のサイトには詳しく述べられていないが，ここで"-noCheckCds"と"-noCheckProtein"オプションを入れることが重要。<font color=red>CDSとProteinの情報を入れていない場合にはerrorが起きてbuildが実行できないので，必ずこのオプションを入れること</font color=red>。
うまくbuildできれば，/data/RIB40/ディレクトリに.binファイルが作られているはず。

（３）アノテーション
アノテーションは，データベースをダウンロードした場合も，カスタムアノテーションも同じ。
```
$ snpEff -v -stats result.html RIB40 variant.vcf > annotation.vcf
```
Renderで独自ドメインを設定する

### 【概要】
---
独自ドメインについてです。
なぜか、お名前.comでは取得できなかったので、`Xserver`で今回は取得しました。

### 【前提・環境】
---
・Ruby 3.2.2
・Rails 7系
・Webアプリケーションサーバ render
・PostgreSQL
・render

### 【実装方針】
---
下記の手順に沿って実装いたします。

1.Render側でDNS周りの設定をする。
2.`Xserver`で、独自ドメインを取得する。
3.アプリに設定を仕込む。


### 【1.Render側でDNS周りの設定をする。】
---

1.`Render`の`Seeting`から、`Custom Domains`にて設定を追加します。
`www.自身が設定したいドメイン名.com`で設定を行います。(今回は、sample-xxx-appという名称)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538926/71088bfd-fbfc-14fb-2f6a-b1524eba0d90.png)

作成後は、下記のようになります。

![スクリーンショット 2023-11-25 22.11.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538926/5628f037-43b0-e7a7-1afa-c0be650b768a.png)

使用するのは、以下2つになります。メモしておいてください。

`www.自身が設定したいドメイン名.com`　→ `www.sample-xxx-app.com`
`ipアドレス`　→ `216.24.57.1`

Render側は一旦完了です。


### 【2.`Xserver`で、独自ドメインを取得する。】
---

まずは、下記サイトに遷移してから設定を行います。

https://www.xdomain.ne.jp/search/domain.php

1.検索ボックスから、取得したいドメイン名を検索します。

![スクリーンショット 2023-11-25 21.44.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538926/7ced531b-cd8f-df49-9477-bc8e456ab095.png)

2.`.com`にチェックを入れて、下記に遷移します。

![スクリーンショット 2023-11-25 21.45.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538926/5d97529a-4879-b0e8-cdc6-9a74da104c6f.png)

3.今回は、Renderでアプリをアップするため、ドメインのみ取得するようにします。
そのため、`サーバーの申し込み`には`利用しない`にチェックを入れます。

![スクリーンショット 2023-11-25 21.46.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538926/50eb71b7-5714-0241-d7d9-dc80a30bf5a1.png)

4.支払い情報に遷移するので`お申し込み完了`まで、内容通りに手続きを進めます。(既に作成済みのため770円になっております。1円になっている想定です。)

![スクリーンショット 2023-11-25 21.49.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538926/597ba077-8f11-8df4-e0ab-609eb02b0e31.png)

5.申込まで完了したら、自身のユーザー画面に推移してください。(下記からでもいけます。)
https://secure.xserver.ne.jp/xapanel/xdomain/index

5-1.下記の右側のボタンを選択し、`DNSレコード設定`を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538926/0e9546fc-451b-352a-1ab5-a29d9ee8275e.png)

5-2.
現状、このような表記になっていると思います。
ここに、先ほど設定しました`IPアドレス`、`DNS`を設定したいと思います。

![スクリーンショット 2023-11-25 22.16.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538926/5d1dcb86-dfa2-1de1-9408-e98e2d05bdd6.png)

5-3.
`DNSレコードを追加する`から下記のように設定します。

![スクリーンショット 2023-11-25 22.20.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538926/d964152a-6ece-2379-44ef-115dffdb4ba2.png)

ここで、上記２つの設定が完了しましたら、Xserverの設定は完了です。


### 【3.アプリに設定を仕込む。】
---ここまできたら下記のように設定すれば完了です。

```ruby:config/environments/production.rb
config.hosts << 'www.設定したドメイン名.com'
#config.hosts << 'www.sample-xxx-app.com'
```

デプロイして、下記のようになっていれば完了です。お疲れ様でした！！

![スクリーンショット 2023-11-25 22.23.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538926/fc57e30a-201c-c1b9-e3fe-36eab07e1bb2.png)


### 【引用】
---

https://qiita.com/kumaryoya/items/fa0debae1da92eb125a2
WindowsUpdateが終わらないときの対応 （備忘録）

バッチファイルを作成して「管理者として実行」
### 「WindowsUpdateのキャッシュフォルダを削除」と「Bitsキューを削除」


```windows-update.bat
echo 自動更新サービスと BITS サービスの停止
net stop usosvc
net stop dosvc
net stop wuauserv
net stop bits

echo SoftwareDistribution フォルダーのリネーム
ren %SystemRoot%\SoftwareDistribution SoftwareDistribution.old
ren %systemroot%\System32\catroot2 catroot2.old

rem BITS のジョブを削除
rem del %AllUsersProfile%\Microsoft\Network\Downloader\qmgr0.dat
rem del %AllUsersProfile%\Microsoft\Network\Downloader\qmgr1.dat
del /q %AllUsersProfile%\Microsoft\Network\Downloader\*

echo 自動更新サービスと BITS サービスの開始
net start bits
net start wuauserv
net start dosvc
net start usosvc
```

# 手動でインストールも可能
「KB〜〜〜」で検索してダブルクリックしてインストールする

https://www.catalog.update.microsoft.com/Home.aspx

https://lapivy.wordpress.com/2019/02/22/%E8%87%AA%E5%8B%95%E7%9A%84%E3%81%AB%E5%90%8C%E6%9C%9F%E3%81%95%E3%82%8C%E3%81%AA%E3%81%84%E6%9B%B4%E6%96%B0%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%82%92wsus%E3%82%84sccm%E3%81%8B%E3%82%89/

# Windows Update に関する参考サイト

https://www.ikt-s.com/category/windows-update/

https://www.run-tomorrow.com/category/windows-update-%E6%83%85%E5%A0%B1/

https://freesoft.tvbok.com/

http://capacitor.jp/blog-category-9.html

https://www.ikt-s.com/category/windows-update/
自然係鯖とは？大学は？年収は？すべて調べてみました！

こんにちは！私はTypeScriptをこよなく愛し愛され足の踏み場にされているあきかきです！

# 技術記事を書く場所なので一応TypeScriptのコードを置いておきます

Discordのロールみたいなやつが追加できるやつ
```ts
import { MouseEventHandler } from "react";



export const RoleLikeButton = ({ color , name , onClick , isMe } : { color : string ; name : string, onClick ?: MouseEventHandler , isMe ?: boolean}) => {
    if(typeof color === "undefined" || color === "#0") color = "#9CA3AF"
    return (
        <button
            style={isMe ? { borderColor: "#4B5563"} : {}}
            className="flex flex-1 h-5 w-auto m-2 px-2.5 py-0.5 border border-gray-300 rounded justify-start items-center bg-gray-100"
            onClick={onClick}
        >
            <div 
                style={{backgroundColor : color}}
                className="h-3 w-3 rounded-full mr-2"
            ></div>
            <p className="text-sm text-gray-600"> {name.split('').splice(0,name.length > 10 ? 10 : name.length).join('')+`${name.length > 10 ? "..." : ""}`} </p>
        </button>
    )
}
```

# 本題

自然係鯖とは？年収とは？全部調べてみました！

## 自然係鯖とは？

自然係鯖とは [HP](https://shizen.aknet.tech) より参加できる素晴らしいサーバーです！

## 結果

調べた結果、自然係鯖ということ以外分かりませんでした！
皆さんも調べてみてください！

# 終わりに

[こんなクソ記事書いてごめんなさい](https://watashiha_warukunai.com)
FirebaseでHostingする方法をChatGPTに聞いてみた


<h3>質問「ReactのプロジェクトをFirebaseでhostingする方法を教えてください」</h3>

<b>GPT</b>

ReactプロジェクトをFirebase Hostingでホスティングする手順は以下の通りです。Firebase CLIを使用してプロジェクトを初期化し、ビルドした後にデプロイします。

<b>Firebase CLIのインストール:

Firebase CLIをインストールするために、ターミナルまたはコマンドプロンプトで以下のコマンドを実行します。

```
npm install -g firebase-tools
```

<b>Firebaseプロジェクトの作成:

Firebaseコンソールで新しいプロジェクトを作成します。

<b>Firebaseプロジェクトとの紐付け:

ターミナルまたはコマンドプロンプトで、Reactプロジェクトのルートディレクトリで以下のコマンドを実行します。
```
firebase login
```
ログインが完了したら、次にFirebaseプロジェクトを初期化します。

```
firebase init
```
Firebase CLIが対話的に質問をしてくるので、以下の設定を選択します：

・Hosting: Configure and deploy Firebase Hosting sites
・Use an existing project: 既存のFirebaseプロジェクトを選択
・What do you want to use as your public directory? ビルド後のファイルがあるディレクトリを選択 (通常は build や dist など)
・Configure as a single-page app (rewrite all urls to /index.html)? シングルページアプリケーションを使用している場合は "Yes" を選択

<b>Reactプロジェクトのビルド:

Reactプロジェクトをビルドします。通常、以下のコマンドを使用します。
```
npm run build
```
もし yarn を使用している場合は、yarn build です。

<b>Firebase Hostingへのデプロイ:

FirebaseプロジェクトとReactプロジェクトが正しく設定されたら、ビルドされたReactアプリケーションをFirebase Hostingにデプロイします。
```
firebase deploy
```
デプロイが完了すると、Firebase HostingにデプロイされたアプリケーションのURLが表示されます。このURLにアクセスすると、デプロイされたReactアプリケーションが表示されるはずです。

これで、ReactプロジェクトがFirebase Hostingでホストされました。



------------------

ChatGPTって本当に便利ですね....今後AIだけ使ってブログを書く人も増えてくると思います。
Rails Girls Kagoshima 2nd でコーチを経験してきました

こんにちは、GMOペパボでWEBエンジニアをしているほりゆうと申します。
今回はRails Girlsのアドベントカレンダーに参加しました！

今年、コーチとして参加した時の記録を書きます📝

## Rails Girlsとは
公式サイトから引用します。

https://railsgirls.jp/guide

>Rails Girlsは女性がプログラミングを理解するための道具を提供することを目的にしています。自分が作ったRailsアプリをインターネット上に公開するという、これまでにない経験をしてもらうのがRails Girlsです。

## なぜ、鹿児島で参加？
Rails Girlsは幅広い地域で開催されています。今年の9月には鹿児島で開催されていました。

[Rails Girls Kagoshima 2nd \- connpass](https://railsgirls-kagoshima.connpass.com/event/285075/)

私が鹿児島で参加した理由は、開催場所がGMOペパボの鹿児島オフィスだったためです。
初めての鹿児島はサイコーでした！鹿児島オフィスの皆さんにもお会いできて嬉しかったです。

時間が全体的にゆったり流れている感覚がして、食べ物も美味しく、景色も綺麗でした。
朝にランニングをして、西郷隆盛さんにも挨拶できました。笑

<img width="320px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557847/5cea1b2d-86a4-63c3-8947-8b77f079f56a.jpeg" />


## なぜ、Rails Girlsのコーチとして参加？
Rails Girlsの参加者さんにRailsを教える側の人たちは、コーチと呼ばれています。

[Rails Girls \- Japanese | Rails Girls のコーチになるには?](https://railsgirls.jp/coach)

コーチとして参加した理由は3つあります。

### 開催の趣旨に共感したから
Rails Girlsは公式ガイドのページにも紹介されているように、女性にRailsでアプリケーションをリリースする体験を通じて、テクノロジーに触れてもらう機会を提供しています。

>これらのガイドは、女性がテクノロジーやアイディアを形にする方法を理解するためのツールやコミュニティを提供するため作られています。

[Rails Girls \- Japanese](https://railsgirls.jp/)

私は、過去に異業種（教員）からエンジニアに転職をしました。そして、2023年11月現在、妻も同じく異業種からエンジニアを目指し、プログラミングを学習しています。Rails Girls Tokyoにも参加させてもらいました。

妻の話や、Rails Girlsに参加した方々の記事を読んで、こういった素敵な場・考えに自分も貢献できたら良いなとってコーチとして参加させていただきました。

### 頑張っている人を応援したいから
自分は頑張っている人を応援することが生き甲斐です。
Rails Girlsを通じて新しいことに挑戦したり、興味を持って取り組んだりする人のことを応援したいと考えました。

### エンジニアに興味を持っている人がいたら、お話をしたかったから
最後に、エンジニアという仕事にも興味を持っている人がいたら、自分の経験を踏まえていろいろお話がしたかったからです。

最近、こんな記事を書きました。

https://note.com/yuki82511988/n/n31a5a46610d8

昨今のエンジニア転職は、結構大変だと私は感じています。時間やお金もかかりますし、勉強も大変です。
ただ、エンジニアという仕事に興味を持ってチャレンジしてみようかな...という人がいたらぜひ相談に乗りたかったので、今回もそういう方がいらしたらお話ししてみたいなと思っていました。

## 参加してどうだったか？
参加者の方は学生から社会人、主婦の方など様々でした。自分のテーブルでは2人の方がレッスンを聞いてくださり、無事アプリケーションのデプロイに成功しました🎉

参加者の方が興味を持っていることを教えるのは非常に面白く、白い紙にいろいろ書くなどしてガッツリと教えるのは教員時以来の体験でした。

改めてプログラミングを教えることは楽しいなと気づくことができましたし、Rails Girlsに参加されるような方々を応援したい気持ちが強くなりました。

<img width="320px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557847/b1efbd5f-1eaa-48fa-3ca1-6660d93575a9.jpeg" />

また、レッスン中に気づいたOSSの修正ポイントを、帰宅後にコントリビュートして直すこともできたのでよかったです。
[「GitHubに自分のアプリをPushする」のmasterへのpushに関する注意事項を記載する by yuki\-snow1823 · Pull Request \#735 · railsgirls\-jp/railsgirls\.jp · GitHub](https://github.com/railsgirls-jp/railsgirls.jp/pull/735)


## 今後どうするか？

noteにも書いたように、個人的に来年以降は初学者支援や、そもそもエンジニアを目指す前段階の人の相談に乗ると言った活動を進めていきたいなと思います。

また、Tokyoでの開催があればRails Girlsにもコーチとして参加したいなと思います。
【Ruby】+ と<<で配列の要素を追加した時の話

https://qiita.com/advent-calendar/2023/infratop

シリーズ2の1日目です！卒業生とメンターさんがコラボして書いています📝

まずは、これを見てください。

```rb:sample.rb
numbers = [1,2,3]
numbers += [4]

p numbers # [1, 2, 3, 4]
```

```rb:another_sample.rb
numbers = [1,2,3]
numbers << [4]

p numbers # [1, 2, 3, 4]
```

一見、配列に要素を追加しただけに見えます。

しかし、[Object#freeze](https://docs.ruby-lang.org/ja/latest/method/Object/i/freeze.html)を使ってみると以下のような違いが出てきます。

```rb:freeze_sample.rb
numbers = [1,2,3]
numbers.freeze

# numbers << [4] # can't modify frozen Array: [1, 2, 3] (FrozenError)
# numbers += [4] # 実行してもエラーにならない
```

初めてこの違いに気づいた時、調査をしてみました🔍
間違い・不足している部分などがあればご指摘いただけますと幸いです。

## + の行っていること
Arrayには[+メソッド](https://docs.ruby-lang.org/ja/latest/method/Array/i/=2b.html)があります。

>自身と other の内容を繋げた配列を生成して返します。

>[PARAM] other:
自身と繋げたい配列を指定します。配列以外のオブジェクトを指定した場合は to_ary メソッドによる暗黙の型変換を試みます。

[Array\#\+ \(Ruby 3\.2 リファレンスマニュアル\)](https://docs.ruby-lang.org/ja/latest/method/Array/i/=2b.html) から引用

説明を読んでみると、自身とotherの繋げた配列を生成して返すとのことです。
サンプルコードも載っていました。

```rb:例
a = [1, 2]
b = [8, 9]
p a + b     #=> [1, 2, 8, 9]
p a         #=> [1, 2]        (変化なし)
p b         #=> [8, 9]        (こちらも変化なし)
```

元の配列に変化はなく、新たに配列ができているということですね！
一応、[object_id](https://docs.ruby-lang.org/ja/latest/method/Object/i/object_id.html)もチェックしてみましょう。

```rb:irb
numbers = [1,2,3]

p numbers.object_id # 260

numbers += [4]

p numbers.object_id # 280
```

IDが違いますね。ということは元のオブジェクトには影響を与えず、新しいオブジェクトになっていることがわかりました。

## << の行っていること

では次に[Array#<<](https://docs.ruby-lang.org/ja/latest/method/Array/i/=3c=3c.html)を見てみましょう。

ドキュメントの説明を読んでみると、下記のように書いてあります。

>指定された obj を自身の末尾に破壊的に追加します。

「破壊的に」とは、[class String \(Ruby 3\.2 リファレンスマニュアル\)](https://docs.ruby-lang.org/ja/latest/class/String.html)で説明がありました。

**<font color="gray">--- ここから引用 ---</font>**

「破壊的な変更」とは、あるオブジェクトの内容自体を変化させることです。例えば文字列のすべての文字を破壊的に大文字へ変更する String#upcase! メソッドの使用例を以下に示します。

例:String#upcase!

```rb
a = "string"
b = a
a.upcase!
p a   # => "STRING"
p b   # => "STRING"
```

**<font color="gray">--- ここまで引用 ---</font>**

つまり、``<<``で要素を追加しようとすると、レシーバのオブジェクトの末尾に、オブジェクトの内容を変更する形で追加されるのですね。

実際にやってみます。

```rb:irb
numbers = [1,2,3]

p numbers.object_id # 260

numbers << 4

p numbers # [1, 2, 3, 4]
p numbers.object_id # 260
```

「4」の要素追加前と後で`object_id`が変わっていませんね。

同じオブジェクトの値を変更したことがわかりました。

## まとめ
一見、どちらのメソッドも結果の出力は同じですが内部で行われていることが違うことがわかりました。

特に、`<<`の方は破壊的な変更を加えているので、freezeを使用した後にこのメソッドを使うとエラーになったんですね。
逆に、`+`だと別のオブジェクトが生成されるから大丈夫だったということがわかりました。

このようなメソッドの挙動の違いに注意して、使用する際はなぜそのメソッドを選択したか説明できるようにしていきましょう！

## 追記：速度を測定してみた
Xでアドバイスをいただいて興味が湧いたので、実行速度を計算してみました！

```ruby
require 'benchmark'

p RUBY_VERSION
numbers1 = [1, 2, 3]
numbers2 = [1, 2, 3]

n = 10000

Benchmark.bm do |x|
  x.report("+=: ") { n.times { numbers1 += [4] } }
  x.report("<<: ") { n.times { numbers2 << 4 } }
end
```

```
"3.1.2"
       user     system      total        real
+=:   0.082590   0.031661   0.114251 (  0.114364)
<<:   0.000419   0.000222   0.000641 (  0.000640)
```

`<<`の方が`+=`より高速であることがわかりました！🎉

`+=`の方は上述したように、新しい配列を作成し元の配列に追加するため、より多くのメモリや処理の時間が必要だからではないかと考えました。何をしたいかにもよりますが、これら観点を持って判断したいと思います。