OmniAICreator/Qiita-1.07M huggingface dataset:
エラーメッセージの役割とフォーマットの工夫

# 概要

この記事はエラーメッセージの役割とフォーマットの工夫について書きました。
本文はとても短いので、ご飯のお供にでも気軽にお読みください。


# エラーメッセージの役割

プログラムの実行で異常を検知した場合に、警告やエラーメッセージを出力することがあります。エラーメッセージには以下のような役割があります。

- 処理の実行中に異常、問題があったことを伝える
- エラー発生の原因を伝える
- 追跡する為の情報を伝える
- 問題を解決する為のヒントを伝える

### エラーメッセージは蜘蛛の糸

メッセージは開発者のメモ書きでは無いので、何を伝えるのかを明確にし、伝え方の工夫が求められます。開発者がとりあえず何か出しておくか…のようなノリで実装していると、本人が思っている以上にそのコードが長く残り続けていたり、想定以上の活用のされ方をしたりして、そのメッセージの質が後々技術的負債にまでなってしまうことだってあります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104643/1816ae6e-2999-5187-941c-53948c602605.jpeg" width=300>




システムやプログラムを利用する側は、エラーメッセージこそ、問題解決の最も重要なヒントとして捉えています。藁にもすがる思いでそのメッセージをヒントに問題解決を図るので、出来るだけ利用者の助けになる出力を心がけましょう。

:::note info
利用者の助けになるメッセージを心がける
:::



# フォーマットの工夫

例えば以下のようなケースを考えます。

- リソースを読み込む処理中で、指定されたデータが見つからなかった

二つの例文を考えてみます。

```
The specified resource 'A' was not found.
```

```
The specified resource was not found. resource:A
```

どちらが良さそうでしょうか。状況を伝えるだけでしたら大差はありません。しかし、後者の方がより二次活用をしやすいという点で優れています。
例えばこのプログラムが世の中で広く公開されているもので、類似のトラブルが無いか検索しようとします。その際に、リソース名を表すAという部分は可変になるので、前者の場合だと検索の仕方に工夫が必要になる場合があります。

![個人用アーキテクチャ-ページ35.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104643/8bbc6403-6167-6402-0705-24b4507109dc.jpeg)


同様にエラーの統計を取ろうとした場合に、やはりメッセージの途中にある可変部分を塗り潰すなどしないと、別のエラーとしてカウントされてしまいます。後者であれば、例えばピリオドまでの前方一致でエラーをまとめられたりします。


:::note info
エラー内容を表す本文と、具体的なIDやEntityを指すテキストは分離して表現すると、よりエラーを活用しやすくなる
:::


# 終わりに

この記事ではエラーの本文については触れませんでしたので、そちらの工夫も機会があれば書きたいと思います。皆様がステキなエラーメッセージライフを過ごされますように。
Elixir の min, max とパイプラインでスマートに条件処理

## はじめに

この記事では、Elixir で [`min/2`](https://hexdocs.pm/elixir/Kernel.html#min/2) と [`max/2`](https://hexdocs.pm/elixir/Kernel.html#max/2) を活用し、パイプラインと組み合わせて簡潔かつ読みやすいコードを書く方法を紹介します。

例えば、音量ボリュームの目盛りが 0 から 10 の場合、値を 0 未満や 10 を超える設定にすることはできません。このような制約を持つ回路を Elixir でどのように表現するかを考えてみます。

## 数字を範囲内に収める

例えば、次のような数字のリストを考えます：

```elixir
[-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
 12, 13, 14, 15, 16, 17, 18, 19, 20]
```

このリストのすべての要素を次の条件に当てはめたいとします：

- 値が 0 未満の場合は 0 にする。
- 値が 10 を超える場合は 10 にする。

最終的に次のようなリストを得ることを目指します：

```elixir
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 10,
 10, 10, 10, 10, 10, 10]
```

## 色んな方法でやってみよう！

### パターン 1: `Enum.map` とガード節

まずは、`Enum.map/2` とガード節を使った方法です：

```elixir
-10..20
|> Enum.to_list()
|> Enum.map(fn
  n when n < 0 -> 0
  n when n > 10 -> 10
  n -> n
end)
```

ガード節を使って条件を処理しています。シンプルですが、条件が増えると少しコードが長くなりがちです。

### パターン 2: `for` と `cond` を使う

`for` と `cond` を使う方法もあります：

```elixir
for n <- -10..20 do
  cond do
    n < 0 -> 0
    n > 10 -> 10
    true -> n
  end
end
```

`for` ループの中で条件を処理します。わかりやすいですが、`cond` の条件が多くなると少し複雑に見えるかもしれません。

### パターン 3: `min` と `max` の組み合わせ

ここで、`min` と `max` を使ったスマートな方法を試してみます：

```elixir
Enum.to_list(-10..20)
|> Enum.map(fn n -> n |> max(0) |> min(10) end)
```

`max(0)` で値を 0 未満にしないようにし、続いて `min(10)` で値を 10 以下に抑えます。この方法は短くて直感的ですね！

### パターン 4: `&` を使ったシンプルな無名関数

無名関数をさらに簡潔に書ける方法として、Elixir でよく使われる `&` 演算子を活用できます。この方法を使うと、`fn` を省略してコードを短く書けます。

```elixir
Enum.to_list(-10..20)
|> Enum.map(& &1 |> max(0) |> min(10))
```

ここでは、`fn n -> n |> max(0) |> min(10) end` の代わりに、`&` 演算子を用いて簡略化しています。この `&` の後に続く `&1` は、無名関数の最初の引数を指します。

この方法を使うことで、コードの見た目がスッキリし、簡潔に書けるようになります。

### パターン 5: ネストする方法もアリ！

`min` と `max` を直接ネストして書く方法もあります：

```elixir
Enum.to_list(-10..20)
|> Enum.map(&min(max(&1, 0), 10))
```

ネスト構造でパイプラインを使わずに書くこの方法も十分読みやすいです。お好みに応じて選びましょう！

## 参考: パイプライン演算子についてもっと知りたい方へ

Elixir のパイプライン演算子について、もっと深く知りたい方には以下の記事がおすすめです：

https://qiita.com/torifukukaiou/items/f99bad9a9ed0dee02ba1

パイプライン演算子の基本から応用まで、非常にわかりやすく解説されています。ぜひ読んでみてください！

## おわりに

この記事では、Elixir の [`min`](https://hexdocs.pm/elixir/Kernel.html#min/2) と [`max`](https://hexdocs.pm/elixir/Kernel.html#max/2) を活用して、数値を指定した範囲内に収めるさまざまな方法を紹介しました。

このテクニックは値のクリッピングなど、幅広い場面で役立ちます。特にパイプラインと組み合わせると、コードがスッキリして読みやすくなるのが嬉しいポイントですね！
【AWS Elastic IP】「The maximum number of addresses has been reached.」の対策方法

ある日、AWSのElastic IPを新たに割り当てようとしたところ、
コンソールに以下のエラーが出てきました。
```
Elastic IP アドレスを割り当てることができませんでした。
The maximum number of addresses has been reached.
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935946/5f292163-7c94-4319-dd42-9efa7eeb1924.png)
こんな感じ↑

内容としては「作成できる上限値に達したので新規追加できないよ」ってことみたいです。

この場合はAWSにてサービスクォータの引き上げを申請しにいきます。
マネジメントコンソールにログインして、[サービスクォータの引き上げ](https://ap-northeast-1.console.aws.amazon.com/servicequotas/home/services/ec2/quotas)へ遷移します。
※↑のリンクは東京リージョンへ推移しますので、別リージョンで引き上げ申請する場合はリージョンの変更をお願いします。

ひと昔前まではサポートから直接引き上げ申請しに行ってた記憶がありますが、今はService Quotasというサービスから申請できるみたいですね！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935946/c52cc2ee-de51-10da-3775-6d01131a7923.png)




## 引き上げ申請のやり方

サービスクォータの検索窓にて「EC2-VPC Elastic IPs」と検索
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935946/220c3d2e-9157-78c1-020b-3263b91bf87f.png)

「アカウントレベルでの引き上げをリクエスト」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935946/df95d72d-3d7d-b69c-dd5f-dba3308da240.png)


引き上げたい値を入力して「リクエスト」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935946/303ca4a6-25f9-fbf0-32a1-9e2fdbee21ec.png)
今回はデフォルトの5⇒10へ変更。

ステータスが「保留中」となっていればOKです。後は反映待ちです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935946/97ca5771-b689-2a61-963c-72a452465e14.png)

## どのくらいで反映されるの？
ドキュメントをみると、数日程度の期間が掛かる場合もあるそうです。
また、申請される規模やサービスにより処理時間も異なるみたい。

https://docs.aws.amazon.com/ja_jp/general/latest/gr/aws_service_limits.html
>AWS Support は、クォータ引き上げリクエストを承認、拒否、または部分的に承認する場合があります。引き上げはすぐには付与されません。引き上げが有効になるまでに数日かかる場合があります

割と時間かかる場合もあるんですね( ﾟДﾟ)

自分の場合は申請してから大体10分~20分待つと承認されました！
以下のようにステータスが「承認済み」になっていればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935946/8074e287-5ea4-1b79-44f9-c28e46864ad6.png)


あとはEIPが作成できるか確認して～っと♪
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935946/acc7e01f-07ab-178a-b389-2531edc52205.png)
問題なく割り当て出来ました！

おわり
また見てね
[備忘録] AWSでeventのサンプルが欲しいときは

# 概要

AWSでサービスに触れると、`event`というワードをよく見かけますが、実際どんな値が入っているのかわからないことがありました。
そんな時、[aws-sam-cli](https://github.com/aws/aws-sam-cli)を使用することで、`event`のサンプルを出力してくれることを知ったのでここに残します。

# 前提

aws-sam-cliのインストール方法については割愛します。
インストール方法はGitHubまたはAWS公式ページを参照してください。

- [aws-sam-cli](https://github.com/aws/aws-sam-cli)
- [AWS SAM CLI のインストール](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/install-sam-cli.html)

# 使用方法

## 前提コマンド

```shell
sam local generate-event {{ AWS サービス }} {{ イベント }}
```

### 使用例

```shell
$ sam local generate-event s3 put

{
  "Records": [
    {
      "eventVersion": "2.0",
      "eventSource": "aws:s3",
      "awsRegion": "us-east-1",
      "eventTime": "1970-01-01T00:00:00.000Z",
      "eventName": "ObjectCreated:Put",
      "userIdentity": {
        "principalId": "EXAMPLE"
      },
      "requestParameters": {
        "sourceIPAddress": "127.0.0.1"
      },
      "responseElements": {
        "x-amz-request-id": "EXAMPLE123456789",
        "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
      },
      "s3": {
        "s3SchemaVersion": "1.0",
        "configurationId": "testConfigRule",
        "bucket": {
          "name": "example-bucket",
          "ownerIdentity": {
            "principalId": "EXAMPLE"
          },
          "arn": "arn:aws:s3:::example-bucket"
        },
        "object": {
          "key": "test/key",
          "size": 1024,
          "eTag": "0123456789abcdef0123456789abcdef",
          "sequencer": "0A1B2C3D4E5F678901"
        }
      }
    }
  ]
}
```

## 使用可能なサービス一覧取得

```shell
$ sam local generate-event

Commands:
    alexa-skills-kit
    alexa-smart-home
    alb
    apigateway
    appsync
    batch
    cloudformation
    cloudfront
    codecommit
    codepipeline
    cognito
    config
    connect
    dynamodb
    cloudwatch
    kinesis
    lex
    lex-v2
    rekognition
    s3
    sagemaker
    ses
    sns
    sqs
    stepfunctions
    workmail
```

## 使用可能なイベント一覧

```shell
$ sam local generate-event s3

Commands:
  batch-invocation  Generates an Amazon S3 Batch Operations Invocation Event
  delete            Generates an Amazon S3 Delete Event
  put               Generates an Amazon S3 Put Event
```
Salesforce モバイルアプリケーションでforce:navigateToURLを使ってレポートに遷移すると集計レポートが機能しない

**使っているクラウドなどの小ネタ Advent Calendar 2024 13日目**


ボタンをクリックするとレポートに遷移するコンポーネントを作成しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/388aa443-f161-d880-6135-e0e5876bd0e0.png)

以下のコードで遷移

```
	handleClick01 : function(component, event, helper) {
        //AR年間ランキング(担)
		var urlEvent = $A.get("e.force:navigateToURL");
        var myUrl = "/lightning/r/Report/00OIR000008QK5F2AW/view?queryScope=userFolders";    
        urlEvent.setParams({
          "url": myUrl
        });
        urlEvent.fire();
	},
 ```

 デスクトップだと問題なく表示できます。
しかし、モバイルアプリではサマリーレポートの明細行が表示されてしまいますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/b615e858-e45d-a373-c660-e5660384beea.png)

もしかして、window.open( myUrl ); なら機能するかと思って変更すると...
なんと、機能します。何で？バグかなぁ。別画面かな？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/2a08b7b8-e44e-b811-35dc-25b664e3880c.png)
【Terraform】Windows環境にTerraformをインストール

お疲れ様です。広瀬と申します。

今回は、Terraformって何？っていうところから、WindowsPCへのTerraformインストール方法までを投稿していきたいと思います。
目次としまして、

１．Terraformとは

２．IaCとは

３．Terraformインストール

の3本立てとなります。

それでは、早速やっていきましょう！

## Terraformとは
Terraformは、インフラストラクチャをコード（IaC: Infrastructure as Code）として管理するためのツールです。HashiCorp社が開発しています。
AWS、Azure、GCPなど、様々なクラウドプロバイダに対応しています。
【Copilotからの引用】

![terraform1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3898218/c94d0ebc-b3ab-1791-dba9-6b31dbded869.png)


## IaCとは
IaCとは？
Infrastructure as Code（IaC）とは、物理または仮想のインフラストラクチャをコードとして定義・管理するアプローチです。
従来の手動によるインフラ構築・管理と比べ、自動化・一貫性・効率性が向上するというメリットがあります。
【Copilotからの引用】

## Terraformインストール
１．下記のURLからTerraformパッケージのダウンロード
https://developer.hashicorp.com/terraform/install?product_intent=terraform

![terraform2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3898218/1410700a-a205-f538-f452-4a8feaba289c.jpeg)

２．ダウンロードした圧縮ファイルを任意のフォルダで解凍する。（今回は、C:\Windows配下に解凍します。）

![tera3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3898218/ca83cc7c-2b99-d6c6-3da9-0f74d5e512c4.png)


３．コマンドプロンプトやターミナルを開き、terraform.exeの絶対パスを入力・実行します。
```
C:\Windows\Terraform\terraform.exe
```

４．環境変数PATHへの指定
・Win＋「R」にて、「ファイル名を指定して実行」を開く。
・「sysdm.cpl」を入力し「OK」押下
・「システムのプロパティ」の「詳細設定」より「環境変数」をクリック

![tf4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3898218/1ad61df2-c718-6019-bb7a-2ca32b7cc3b6.jpeg)


・「ユーザ環境変数」もしくは「システム環境変数」において編集を行う。

![tf5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3898218/9ba5800b-b94a-2369-417a-aeaa3eb93cbe.jpeg)


![tf6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3898218/bdabc24c-994b-f0fa-a32d-8aa93f6fc023.jpeg)


・コマンドプロンプトを再度開きなおす。
　（環境変数の変更部分の読み込みを行うため。）

・terraformコマンドが打てるか確認
```
terraform -v
```

## やってみての感想
私自身、TerraformやIaCとは何かについて、知らなかったので、とても難しものに感じていましたが、実際にハンズオンでインストールしてみると、
実体がつかめて、学習のハードルが下がりました。
今後は、TerraformとAWSの連携を行い、Terraform上で作成したIaCを使用して、AWSリソースの作成も投稿していくつもりです。

是非、皆さんの参考にしていただければと思います。
导出IOS模拟器中的沙盒数据

1. 打开终端
1. 找到模拟器的位置
    模拟器的位置通常位于一下路径
    `~/Library/Developer/CoreSimulator/Devices/`
    在这个目录下，你可以看多个以UUID命名的文件夹，每一个文件夹对应一个模拟器设备
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780104/a8890edb-f71b-a47a-1f08-01e57f0b577c.png)
1. 确定当前使用的模拟器的 UUID
    使用 `xcrun simctl lists` 命令查看当前系统中所有的模拟器，找到你当前正在使用的模拟器，旁边有该模拟器的 UUID
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780104/56b6261e-b4cf-cbf5-d70b-0f81270a3331.png)
1. 导出数据
    使用如下数据导出你当前模拟器中的app的数据
    ```
    cp -R $(xcrun simctl get_app_container <device-uuid> <app-bundle-id> data) ~/Download
    ```
    - 将 `<device-uuid>` 替换为你的模拟器的UUID
    - 将 `<app-bundle-id>` 替换为你应用的 bundle id
    - 该命令是将模拟器中的指定app的数据导出到 Download 文件目录下

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780104/84b82378-e07b-b663-429a-446e1e7cb385.png)
IPv6のヘッダー

# ルーターはフィールドを調べることでパケットの種類を知るができる
>IPv4からの移行が開始してからもう10年以上経つが、この移行が完了するまでの間、`ルーターはこのフィールドを調べることでパケットの種類を判別`している。

### DiffServフィールド
>パケットの配送に要求されるリアルタイム性の違いに応じて、`パケットのサービス・クラスを区別`するために用いられる。このフィールドは、IPv4におけるDiffServフィールドと同様にDiffServのアーキテクチャと組み合わせてQoSの実現に利用される。また、IPv4と同様、`輻輳の明示的な通知`に用いらる。

### フロー・ラベルフィールド
>送信元とあて先との間で擬似的なコネクションを形成し、ネットワークに対して同じ要求をもち、同じように扱うべき`パケットのグループに対して印をつける`のに用いられる。

>例えば、送信元ホスト上のあるプロセスから、あて先ホスト上のプロセスへとパケットのストリームを送信する際、`遅延に関する厳しい要求があり、帯域を予約しておく必要がある`とする。
...
フローを用いることで、パケットをデータグラム・ネットワークのように`柔軟に配送する`方法と、仮想回線ネットワークのように`性能を保証しつつ配送`する方法の両方が選択できるようになる。

### ペイロード長
>図5−57で示した40バイトの`ヘッダーの後に何バイト続くか`を表す。IPv4の全長フィールドとは異なり、ヘッダー部分の40バイトを含めないため、名前が変更されている。これにより、ペイロードの最大長はIPv4の65,515バイトから、65,535バイトへと増加した

### 次ヘッダー・フィールド
>パケットに付加サービスを明記するために用いられる。IPv6でヘッダーを単純化することができたのは、オプションとして利用する付加サービスを明記した拡張ヘッダーを追加できるようになったためである。

>そのヘッダーが最後のIPヘッダーである場合には、`どのトランスポート・プロトコル(TCPやUDPなど)のハンドラヘそのパケットを渡せば良いか`を次ヘッダー・フィールドで示す

### ホップ制限・フィールド
>パケットがネットワーク上を`さまよい続けることを防ぐ`ために用いる。

### 送信元アドレスとあて先アドレスのフィールド
>`16バイトの固定長アドレスが最も妥当`であるという結論に至った。

# IPv4からIPv6から削除されたヘッダー
### フラグメント化に関するヘッダー
>IPv6に対応したすべてのホストは、パケット・サイズを動的に決定することが想定されている。
...
MTU発見手順を用いる。簡単に言えば、ホストが送信したIPv6パケットが大きすぎる場合はには、そのパケットを分割するのではなく、`処理できなかったルーターがそのパケットを破棄し、誤りメッセージを送信元ホストへ返送`する。誤りメッセージを受け取ったホストは、その後、その`あて先へ送信するすべてのパケットのサイズを小さく`する。

### チェックサム・フィールド
>`計算に非常に時間がかかる`ために削除された。ネットワークの信頼性が上がったことや、データリンク層とトランスポート層でもそれぞれチェックサムが計算されていることを考えると`性能を犠牲にしてまで、チェックサムをもう一つ増やす価値はない`であろう。
Authorization Required、basicauthでのベーシック認証について

前年のチームからの業務を受け継ぎ、djangoの開発を行っている際に、前チームのリポジトリをcloneしてrun serverしようとしたところ、以下のエラーが出ました。
```
Authorization Required
```

以下のコードによってあるテスト環境でベーシック認証を行うことができ、その設定が行われていましたが、私の環境にはbasicauthの設定ができておらずエラーが発生しました。

```Django:settings.py
MIDDLEWARE = [
    'basicauth.middleware.BasicAuthMiddleware',
]
```

あるテスト環境でベーシック認証を行うことができ、その設定が行われていましたが、私の環境にはbasicauthの設定ができておらずエラーが発生しました。
これを解決するため、自分のローカル環境のlocal_settings.py(このファイルは.gitignoreファイルに書いてあるのでgithub上にはあがらない)に以下のコードで解決しました。
```dj:local_settings.py
BASICAUTH_USERS={"ユーザー名": "パスワード"}
```

ただし、自分のローカル環境で作業する場合は、ベーシック認証が不必要なので、該当するコードを削除またはコメントアウトすれば解決します。
【Eclipse】Tomcat起動時エラーの解消方法、確認事項

Javaアプリケーションの環境構築時に詰まっていたため、備忘録として記載します。

# 事象
Maven プロジェクト更新後、EclipseでTomcat起動してローカル環境にアクセスすると404になっちゃう。
Tomcat起動時に以下のコンソールが出力されているため、Tomcat関連が原因でしょう。


```
重大: クラス [org.springframework.web.context.ContextLoaderListener] のアプリケーションリスナの設定中にエラーが発生しました
重大: 前のエラーのためにアプリケーションリスナのインストールをスキップします
重大: 1つまたは複数のリスナーが開始に失敗しました。 完全な詳細は適切なコンテナログファイルにあります。
重大: 以前のエラーのためにコンテキストの起動が失敗しました
```

出力メッセージを基に調べて解消を試みたのですが、同じメッセージでも原因や解決方法が状況によってまばらなので解消にたどり着くまで大変でした。。。

# 解消方法
##### いや普通に起動したTomcatのバージョンが環境構築したJavaアプリと対応していないだけでした。
新しいプロジェクトに着手するときにはしっかりここら辺最初に確認しようね...。
設計書で確認できればいいんですけど、すぐに確認できない状況、環境だったりだとか、リバースエンジニアリングで設計書これから作るからそんなもんないよっていうのも珍しくないですからね...。[^1]

### 他解消方法
私がエラー解消したのは前述の通りなんですけど、また別の状況で同じエラーが発生した時のために確認するべき事項を以下に記載します。

- Mavenの依存関係が読み込めてるか
- 見慣れないディレクトリにいつの間にか生成されている `web.xml` 削除
- ポート競合（これについては確か前述とは別のメッセージで出てくると思います）

表題のコンソールメッセージで詰まる場合はMavenの依存関係が原因な事が多いと思われます。

# さいごに
上記に記述したものとはまた別の方法で解消したり、詰まっている場合共有して頂けるとすっごく助かります。。
これを読んだあなた。どうか真相を暴いてください。それだけが私の望みです。

[^1]: 最近はAIがプロジェクトの内容読み込んで設計書自動生成してくれるんだとか。すげーや。
GraphAI入門：簡単なインストールとHello Worldを試してみよう！

## はじめに

GraphAIは、データフローグラフを使って非同期プロセスをシンプルに定義できるツールです。特に、エージェント間のデータの流れを直感的に記述し、効率的に処理を行うことが可能です。宣言的な記述によって、複雑な処理も簡潔に表現できます。この入門記事では、GraphAIをインストールして、簡単な"Hello World"を表示させる手順を説明します。プログラミングに慣れていない方でも安心して進められる内容ですので、一緒に始めてみましょう！

## 事前準備

### 必要な環境

- npm（最新バージョンを推奨）

### インストール手順

GraphAIを使うために、次の手順に従ってGraphAIクライアントをインストールします：

1. GraphAIクライアントをインストールします：

```bash
npm i -g @receptron/graphai_cli
```

## Hello Worldを作ろう

GraphAIをインストールしたら、次に「Hello World」を表示させる簡単なワークフローを作ってみましょう。

### YAMLでHello World

まずは、下記の内容を`hello_world.yaml`という名前のファイルに保存します：

```yaml:hello_world.yaml
version: 0.5
nodes:
  message:
    value: "Hello, World!"
  output:
    agent: echoAgent
    isResult: true
```

### GraphAI CLIで実行する方法

GraphAIクライアントを使って、上記のYAMLファイルを実行します。

```bash
graphai hello_world.yaml
```

### 実行結果

ターミナルに次のように表示されます：

```
{
  "node1": {
    "message": "hello"
  }
}
```

## まとめ

この記事では、GraphAIのインストールと「Hello World」の表示に集中して紹介しました。最初のステップを終えることで、GraphAIがどのように動くかを体感できたと思います。次は少しずつ、より複雑なワークフローの作成にチャレンジしてみましょう！

## 参考サイト

GraphAIに関する詳細な情報は下記のドキュメントを参考にしてください：

以下に参考文献をマークダウン形式でまとめました。

- [GraphAIの紹介 | Singularity Society](https://singularitysociety.org/projects/ai/graphai/graphai-tutorial-1/)
- [GraphAI - Full-Stack TypeScript Tool for AI Applications | Speaker Deck](https://speakerdeck.com/isamu/graphai-full-stack-typescript-tool-for-ai-applications)
- [GraphAI - シンプルなサンプル | Zenn](https://zenn.dev/singularity/articles/graphai-sample-simple-graph)
- [GraphAI | Singularity Society](https://singularitysociety.org/projects/ai/graphai/)
- [GraphAI | Speaker Deck](https://speakerdeck.com/isamu/graphai)
- [graphai | npm](https://www.npmjs.com/package/graphai)
- [GraphAI - LLM, Ragなどを組み合わせたMulti Agent AIのためのデータフロー・プログラミング | YouTube](https://www.youtube.com/watch?v=0mh_Nu9SefQ)
Windows11からAndroid（Xperia）へクリップボード共有したかった

## Swiftkeyってのがある
ネットにいっぱい情報あるのでその通りに設定。

https://play.google.com/store/apps/details?id=com.touchtype.swiftkey

ネットの情報と違うポイントは下記。
リッチ入力 → クリップボード で クリップボード履歴の同期 をオン　とするところで、もう一度Microsoftアカウント認証が走った。

## 結果
AndroidからWindows11へのクリップボード共有はOK。
けど、逆はNG。Windows11からAndroidへのクリップボード共有が使いたかったのに。。。
PCもスマホも再起動したけど変わらず。
ま、キーボード変わるのいやなのでやめ。
ジェネリクス関数で引数の制約はできるが、関数内で引数を合成して得られる値は動的解析するしかない

## ことの発端

思えば当たり前なのだが、久々に小一時間ハマった。（実際は３時間）
最近歳のせいか、鈍った自分へ喝をいれるため投稿。

## 具体例

```ts
function test<T, K extends keyof T>(
  data: T,
  key: T[K] extends string ? K : never,
) {
  const x: string = data[key]; // error: 残念（泣）
}

interface X {
  s: string;
  n: number;
}

const x: X = {s: 'string', n: 1};

test(x, 's');
test(x, 'n'); // error: 期待通り
```

### 説明

* `test()` は第１引数にオブジェクト `T`、第２引数にオブジェクトのプロパティ `K` を渡すことを想定
* オブジェクトのプロパティ `T[K]` の **【 値 】** は `string` のみにしたいことを表明するため `key: T[K] extends string ? K : never` として制約
* `test(x, 'n')` がエラーとなりハッピー
* ところが、`test()` 内で `data[key]` が `string` として認識しない

```
Type 'T[T[K] extends string ? K : never]' is not assignable to type 'string'.
  Type 'T[K]' is not assignable to type 'string'.
    Type 'T[keyof T]' is not assignable to type 'string'.
      Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'string'.
        Type 'T[string]' is not assignable to type 'string'.ts(2322)
```

## つまり

呼び出し時は `test()` の第２引数を制約することはできるけど、制約された `data` と `key` を使って得られる値には制約が及ばない。
ここで `as` を使いたくないのであれば、実行コストがかかるが `typeof` を使わないといけない。

```ts:【対応１】asに負ける
function test<T, K extends keyof T>(
  data: T,
  key: T[K] extends string ? K : never,
) {
  const x: string = data[key] as string;
}
```

```ts:【対応２】asに屈しない
function test<T, K extends keyof T>(
  data: T,
  key: T[K] extends string ? K : never,
) {
  const x = data[key];
  if(typeof x !== 'string') {
    throw new Error('Invalid type');
  }
  // x は string 型
}
```

しっかり型管理されているのであれば `【対応1】` で良いと思う。しかしながら、型管理されているということは極論 `as` なんか使わずに型を伝搬し続けることを意味するので、コード上に `as` が登場するのは異常事態[^1]であるので、相当なコメントを書くなどして、この `as` の正当性をしっかりと説明する必要がある[^2]。
また、データが外部から与えられた動的なものの可能性がある場合、パフォーマンスを考えるより堅牢性を考え `【対応２】`になる。

[^1]:WebAPIとかで得られるJSONのように型が無い世界からデータをお迎えする場合は異常事態ではないが、かなり気を遣う場面であることには違いない。
[^2]:とは言え、そんなコメントを書いても `as` を平然と書く輩がいると、そう遠くない未来にプロジェクトは炎上か破綻する。まぁ、`ESLint`や `husky` で抑止はできるけど、本質的な問題を理解していないと誰も幸せになりません。
IPv6

# 将来的なIPの枯渇に対する解決法がIPv6
>長期的な解決方法は、大きいアドレス空間を持つIPv6(IP version 6)へ行こうすることのみである。IPv6は128ビット長のアドレスを用いており、`将来的にアドレスが不足することはまずない`であろう。
# IPv6とIPv4の互換性はない
>IPv6は導入が非常に難しいことが知られている。IPv6は、IPv4と類似している部分も多いが異なるネットワーク層プロトコルであり、`互換性がない`。

# IPv6の制定の目標
>1.非効率なアドレスを割り当てても、数十億台のホストに対応できること
>2.ルーティング・テーブルのサイズを削減すること
>3.ルーターの処理を高速化するため、単純なプロトコルとすること
>4.より良いセキュリティ（認証やプライバシー）を提供すること
>5.リアルタイム・データなど、サービスの種類に注目したプロトコルとすること
>6.スコープを指定できるようにし、マルチキャストを行いやすくすること
>7.ホストがアドレスを変えることなくローミングを行えるようにすること
>8.将来の発展を見越したプロトコルにすること
>9.数年の間は、新しいプロトコルと古いプロトコルが共存できるようにすること

### ローミングとは
>ローミングとは、携帯電話やインターネット接続サービスなど、利用者が契約している通信事業者の提供サービス範囲外の場所で、他の事業者の設備を通じて音声通話やインターネットなどのデータ通信を利用できるようにする仕組みです。

https://www.softbank.jp/sbnews/entry/20221109_01#:~:text=%E3%83%AD%E3%83%BC%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%A8%E3%81%AF%E3%80%81%E6%90%BA%E5%B8%AF%E9%9B%BB%E8%A9%B1%E3%82%84%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88%E6%8E%A5%E7%B6%9A%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AA%E3%81%A9%E3%80%81%E5%88%A9%E7%94%A8%E8%80%85%E3%81%8C%E5%A5%91%E7%B4%84%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E9%80%9A%E4%BF%A1%E4%BA%8B%E6%A5%AD%E8%80%85%E3%81%AE%E6%8F%90%E4%BE%9B%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%AE%E5%A0%B4%E6%89%80%E3%81%A7%E3%80%81%E4%BB%96%E3%81%AE%E4%BA%8B%E6%A5%AD%E8%80%85%E3%81%AE%E8%A8%AD%E5%82%99%E3%82%92%E9%80%9A%E3%81%98%E3%81%A6%E9%9F%B3%E5%A3%B0%E9%80%9A%E8%A9%B1%E3%82%84%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88%E3%81%AA%E3%81%A9%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E9%80%9A%E4%BF%A1%E3%82%92%E5%88%A9%E7%94%A8%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B%E4%BB%95%E7%B5%84%E3%81%BF%E3%81%A7%E3%81%99%E3%80%82

# IPv6の称号を得たSIPP
>修正案が三つ提出された。この後、多くの議論と検討を重ねた結果、DeeringとFrancisの提案を統合し、修正を加えた`SIPP(Simple Internet Protocol Plus:シンプル・インターネット・プロトコル・プラス）と呼ばれ、IPv6（インターネット・プロトコル　バージョン６）の称号を得た`。

# IPv6の特徴
>IPv6ではIPv4に比べて長いアドレスが用いられる。`アドレス長が128ビット`であり、これにより効果的に無尽蔵のインターネット・アドレスを提供できる。

>ヘッダーが単純化されたことである。IPv4のヘッダーが13個のフィールドを持っていたのに対し、`IPv6ではわずか7個`である。これにより、ルーターがパケットを高速に処理できるようになり、スループットや遅延が改善する効果がある。

>オプションのサポートの強化である。IPv6では、以前は必須であったいくつかのフィールドがオプションとなっているため、この変更は不可欠である。また、オプションの表現方法が変更されたことで、`ルーターが自身に関係ないオプションの処理を簡単に飛ばす`ことができるようになった。この特徴により、`パケットの処理時間が高速化`される。

https://bookplus.nikkei.com/atcl/catalog/23/03/16/00728/

# 感想
IPv6はアドレス長が長く、ヘッダーも少なく、オプションフィールドも飛ばすことができる。
任意の件名からメールが来たら、メールの以下の文を置換してへんしんする。

```vb
Private Sub Application_NewMailEx(ByVal EntryIDCollection As String)
    Dim objNamespace As Outlook.NameSpace
    Dim objItem As Object
    Dim objMail As Outlook.MailItem
    Dim EntryID As String
    Dim arrEntryIDs() As String
    Dim i As Integer

    ' EntryIDCollectionを分割
    arrEntryIDs = Split(EntryIDCollection, ",")

    Set objNamespace = Application.GetNamespace("MAPI")
    
    ' 各メールに対して処理
    For i = LBound(arrEntryIDs) To UBound(arrEntryIDs)
        EntryID = arrEntryIDs(i)
        Set objItem = objNamespace.GetItemFromID(EntryID)
        
        ' メールアイテムの場合
        If TypeOf objItem Is Outlook.MailItem Then
            Set objMail = objItem
            
            ' 指定の件名をチェック
            If objMail.Subject = "指定した件名" Then
                Dim replyMail As Outlook.MailItem
                Dim bodyText As String
                
                ' 本文の文字列置換
                bodyText = objMail.Body
                bodyText = Replace(bodyText, "aaa", "xxx")
                
                ' 返信メール作成
                Set replyMail = objMail.Reply
                replyMail.Body = bodyText
                replyMail.To = "返信先のメールアドレス@example.com" ' 指定アドレス
                replyMail.Send
            End If
        End If
    Next i

    ' 解放
    Set objMail = Nothing
    Set objItem = Nothing
    Set objNamespace = Nothing
End Sub
```
atcoder練習(2024.11.27)

# キーワード

# 問題
https://atcoder.jp/contests/abc377/tasks/abc377_b

## 問題文
縦8マス、横8マスの64マスからなるマス目があります。
上からi行目(1≤i≤8)、左からj列目(1≤j≤8)のマスをマス(i,j)と呼ぶことにします。
それぞれのマスは、空マスであるかコマが置かれているかのどちらかです。
マスの状態は長さ8の文字列からなる長さ8の列(S1​,S2​,S3​,…,S8​)で表されます。
マス(i,j)(1≤i≤8,1≤j≤8)は、Si​のj文字目が.のとき空マスで、#のときコマが置かれています。
あなたは、すでに置かれているどのコマにも取られないように、いずれかの空マスに自分のコマを置きたいです。
マス(i,j)に置かれているコマは、次のどちらかの条件を満たすコマを取ることができます。
i行目のマスに置かれているj列目のマスに置かれているたとえば、マス(4,4)に置かれているコマは、以下の図で青く示されたマスに置かれているコマを取ることができます。
あなたがコマを置くことができるマスがいくつあるか求めてください。

## 制約
Si​ は ., # からなる長さ 8 の文字列 (1≤i≤8)

## 入力
入力は以下の形式で標準入力から与えられる。
S1​
S2​
S3​
S4​
S5​
S6​
S7​
S8​

## 出力
すでに置かれているコマに取られずに自分のコマを置くことができる空マスの個数を出力せよ。

## 入力例 1
...#....
#.......
.......#
....#...
.#......
........
........
..#.....

## 出力例 1
4

すでに置かれているコマは、以下の図で青く示されたマスに置かれたコマを取ることができます。
よって、あなたがすでに置かれているコマに取られないように自分のコマを置くことができるマスはマス (6,6), マス (6,7), マス (7,6), マス (7,7) の 4 マスです。

## 入力例 2
........
........
........
........
........
........
........
........

## 出力例 2
64

コマがひとつも置かれていないこともあります。

## 入力例 3
.#......
..#..#..
....#...
........
..#....#
........
...#....
....#...

## 出力例 3
4


# 回答
```Python
s = []
key = 0

for _ in range(8):
    line = input().translate(str.maketrans(".#", "01"))
    s.append([int(i) for i in line])

    if any(s[-1]):
        s[-1] = [num + 1 for num in s[-1]]
        key += 1

list = [sum(column) for column in zip(*s)]
list = [num - key for num in list]

for i in range(8):
  if sum(s[i]) == 0:
    s[i] = list

ans = sum(r.count(0) for r in s)
print(ans)
```

# 参考

# 備考
- 多分もうすこし綺麗なアルゴリズムが書ける。
- 頭の中の処理とアルゴリズムが一致していないような気がする。まぁでも動いたからいいや
- コードを書いた上で、そのコードを添削する方法がいい感じな気がする。
- 昨日でこのコードをかけたのだが、提出すると実行時エラーが全部で発生して正解しなかった。コードテストのサンプルでは正解できていたし、コードテストもものすごい時間がかかっていたことから、atcoder側のエラーな気がする。つまり僕は悪くない！
- 他の人のコードを見る限り、forでiとjを動かして、どちらかに#があるとアウトみたいな探している人が多いような気がする。
MATLAB/SimulinkのSimscape Electricalテストベンチメモ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3759109/2cec37cb-188c-4f07-0026-4ce7cccfad5c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3759109/7a98f8ee-068c-6674-51f2-831c4dc9b4b8.png)
laravelデータベースのテーブルからモデルを自動生成

# やりたいこと

```console:コンソール
php artisan make:model モデル名
```
でモデルを一つずつ作成するのが大変なので

[Reliese Laravel Models](https://github.com/reliese/laravel)
を使用してDBのテーブルからmodelを自動生成したい。

# コマンド
以下のコマンドでmodelファイルが自動生成されます。
```console:コンソール
composer require reliese/laravel

php artisan vendor:publish --tag=reliese-models

php artisan code:models
```

・複数回実行しても重複されない。
・casts、fillableも生成される
・migrationsテーブルは無視される
　（config/models.php 'except'で管理される）

 便利なので使ってみてください。
Gspread の使い方 (シートのコピー）

Sheet1 を Sheet2 にコピーします。

Sheet1
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/efec7c96-d490-8f03-942c-19efc6de81bf.png)


## プログラム

```py:sheet_copy.py
#! /usr/bin/python
#
#	sheet_copy.py
#
#						Nov/27/2024
# ------------------------------------------------------------------
import sys
import os

package_path = os.path.expanduser('~/.local/share/pipx/venvs/gspread/lib/python3.12/site-packages')
sys.path.append(package_path)

package_path = os.path.expanduser('~/.local/share/pipx/venvs/gspread-dataframe/lib/python3.12/site-packages')
sys.path.append(package_path)

import pandas as pd
import gspread
from gspread_dataframe import get_as_dataframe, set_with_dataframe
#
# ------------------------------------------------------------------
sys.stderr.write("*** 開始 ***\n")

# Google Sheets APIの認証情報
json_file = 'service_account.json'

# スプレッドシートのID
sheet_id = '1D1hk5LH6O3BlFehaBgnzfGt*****'

# 読み込み元と書き込み先のシート名

read_sheet_name = 'Sheet1'
write_sheet_name = 'Sheet2'

# Google Sheets APIの認証
gc = gspread.service_account(filename=json_file)

# スプレッドシートの読み込み
spreadsheet = gc.open_by_key(sheet_id)
worksheet = spreadsheet.worksheet(read_sheet_name)

# データの読み込み
#df = get_as_dataframe(worksheet, header=None)
df = get_as_dataframe(worksheet)
print(df)

ws_list = spreadsheet.worksheets()
print(ws_list)
sheet_names = []
for tt in ws_list:
	sheet_names.append(tt.title)
print(sheet_names)
if not write_sheet_name in sheet_names:
	spreadsheet.add_worksheet(title=write_sheet_name, rows=50, cols=10)
#
worksheet = spreadsheet.worksheet(write_sheet_name)
#set_with_dataframe(worksheet, df, include_column_header=False)
set_with_dataframe(worksheet, df)
#
sys.stderr.write("*** 終了 ***\n")
# ------------------------------------------------------------------
```

## 参考情報
[Gspread の使い方 (シートのRead)](https://qiita.com/ekzemplaro/items/b0fbbcf141c1155153b3)
[Gspread の使い方 (シートのCreate)](https://qiita.com/ekzemplaro/items/4fdb32f579dcf1bc9064)
プログラミングにおけるthisとは何者か

プログラミングでよく登場するthisというキーワード。初めて見たときは「これって何者？」と思うかもしれません。でも、thisはとても役に立つもので、オブジェクト指向プログラミングで重要な役割を果たします。
**thisの基本的な意味**

**thisは、現在のオブジェクト自身を指すキーワードです。言い換えれば、thisは「このオブジェクト」という意味を持っていて、その場面で使われているオブジェクトを表します。**

例えば、クラスを使ってオブジェクトを作るとき、クラスの中でthisを使うことで、そのクラスが持つデータやメソッドにアクセスすることができます。

# JavaScriptにおけるthis

JavaScriptでは、thisの動きは少し複雑です。thisが指すものは、その関数の呼び出し方によって変わります。

**メソッドとして呼び出された場合：thisはそのメソッドが属するオブジェクトを指します。**

```JavaScript
const user = {
  name: '太郎',
  sayHello: function() {
    console.log(`こんにちは、私は${this.name}です。`);
  }
};
user.sayHello(); // こんにちは、私は太郎です。
```

この場合、thisはuserオブジェクトを指します。


**関数として呼び出された場合：thisはグローバルオブジェクト（ブラウザならwindow）を指します。**
```JavaScript
function showThis() {
  console.log(this);
}
showThis(); // グローバルオブジェクト（ブラウザでは`window`）
```


**アロー関数の場合：アロー関数では、thisはその関数が定義されたスコープのthisを引き継ぎます。**

```JavaScript
const user = {
  name: '太郎',
  sayHello: () => {
    console.log(`こんにちは、私は${this.name}です。`);
  }
};
user.sayHello(); // こんにちは、私はundefinedです。
```

アロー関数ではthisがuserを指さないので、nameはundefinedになってしまいます。

# Javaにおけるthis

**Javaなどのオブジェクト指向プログラミング言語では、thisはもっとシンプルです。クラスのメンバ変数やメソッドにアクセスするために使われ、現在のインスタンスを指します。**

```Java
public class Person {
    String name;

    public Person(String name) {
        this.name = name; // `this`は現在のインスタンスを指す
    }

    public void greet() {
        System.out.println("こんにちは、私は" + this.name + "です。");
    }
}
```

この場合、this.nameはそのクラスのインスタンスのnameを指し、コンストラクタで渡された引数と区別するために使われています。

# まとめ

thisは「今、自分が操作しているオブジェクト」を表すキーワードです。プログラミング言語によって意味や使い方が少し異なるので、最初は混乱するかもしれませんが、慣れてくるとクラスやオブジェクトを扱う際に非常に便利です。

覚えておくべきポイントは、thisがどのオブジェクトを指しているかはコードがどのように呼び出されているかによって決まることです。実際にコードを書いて試してみることで、thisの使い方にもっと慣れていけると思います！


**最後までよんでいただきありがとうございます。
@y-t0910をフォロー,いいねしていただけると嬉しいです！**
オブジェクト指向設計ならわかる人に贈るRDBテーブル設計

## テーブル定義

オブジェクト指向設計におけるクラス定義と同様に考える

- メンバフィールドのみを持つクラスとして考える
- Class, Enum, Dict の概念は全てテーブル化する
- List 型の包含関係が発生する場合は独特の思考が必要になる (後述)


## 正規化

オブジェクト指向設計として妥当な定義をしていれば勝手に正規化されている


## 包含関係の表現


### 1対1

オブジェクト指向設計と同様

![rdb_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670736/c88b9b81-4a14-238a-4151-28094bd5febe.png)
![rdb_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670736/8529acb2-3b12-75eb-8acb-15e0071a3105.png)


### 多対1

包含関係の表現がオブジェクト指向設計とは異なる

  - **どのインスタンス（xxxx_id）に包含されるか** の情報を持たせる

![rdb_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670736/4ca253b4-928b-4f8f-a85c-6a364d6a51b5.png)
![rdb_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670736/b1d7c164-196b-c010-74fc-323cb158c4d1.png)


### 多対多… に進む前に

 - 多対1で例示したテーブル設計では **Userが複数のGroupに属することができない**

オブジェクト指向設計的には例と同じクラス設計であっても、
あるUserインスタンスを複数のGroupインスタンスに包含させることができる
そのためオブジェクト指向設計を起点にテーブル設計をしていると失念しやすい


### 多対多

テーブル設計においては**マッピングテーブル**を設けることで多対多の包含を実現する

![rdb_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670736/e6f5c773-ec07-223f-9f34-c4a66c40b520.png)

  - 多対1の包含関係でも将来的な拡張性のために上記設計の採用が検討候補に挙がる
  - User, Group 双方のテーブルから包含関係に関するカラムを排除できるのも利点
  - 1対1の包含関係の場合は冗長になりパフォーマンス低下まであるので基本不採用


## カラム設計

設けるべきカラムのテンプレート

### エンティティテーブル

  ![rdb_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670736/c7548e07-ca85-fc45-de6b-722beb8d25d1.png)

  - ID
      - プライマリキー用途（後述）
      - `id` ではなく `foobar_id` というネーミングにすること
          - 外部キーとして `foreign_id` カラムなどを追加する場合にネーミングの一貫を保つ
  - Name
      - システムのユーザ視点における一意識別子
          - 意味論的に UNIQUE 属性を付与しておくことを推奨
      - 例えばUserテーブルにおける `user_name` はログインネームが該当する
  - Label
      - UIなどに表示する文字列
      - 例えばUserテーブルにおける `user_label` はニックネームが該当する
  - 日付系
      - 特定の期間で抽出したくなる場面は頻出であるため



### マッピングテーブル

  - ID
  - マッピング対象の外部キー ×2
      - 重複するマッピングを防ぐために**複合ユニークキー**とする
  - 日付系


### トランザクションテーブル

処理結果などを蓄積するためのテーブル

例えば操作履歴にユーザ情報を併せて記録する場合、ユーザの削除後も有効なレコードでなければならない
このように**外部キーによる参照をするべきではないケースが存在する**ので注意

  - ID
  - 諸々の情報
      - 例えばユーザ情報を記録する場合、ユーザ削除後のトレースを考慮して以下を残す
          - user_id (※外部キー属性を付与しない)
          - user_name
  - 日付系


## プライマリキー

各テーブルに設けるプライマリキー（主キー）の設定については以下の方針を推奨
どちらもパフォーマンスへの影響の観点から

  - 数値型または固定長文字列型とする
  - 複合プライマリキーは採用しない
      - 上でマッピングテーブルにIDカラムを設けたのはこのため

### 数値型

AUTO_INCREMENT 属性の付与により一意な連番IDを自動生成する

ただしID情報をシステム外部とやり取りする場合はスクレイピング耐性が悪化する
具体的には `user_id = 123` であるUser情報に以下のようなURLでアクセスできる場合

  - `https://www.my-website.com/user/123`

これが AUTO_INCREMENT によって生成されたIDである場合、URLの `123` の部分を変更することで色々とできてしまう

なので**外部からのアクセスを想定しないテーブル（マッピングなど）での採用に留めるべき**

### 固定長文字列型

UUIDからハイフンを削除した32byteで一意なIDを生成する
上記のようにシステム外部にID情報が露出するケースでも耐性に影響が無い

ちなみにPostgreSQLにはUUID型が存在するが、MySQLには存在しない
移植性を考えるならPostgreSQLであっても型定義は `CHAR(32)` を推奨
python 組み込みモジュール② os

## モジュール概要
os は "operating system"（オペレーティングシステム）の略です。
os モジュールは、Python プログラムがオペレーティングシステムと連携するための様々なインターフェースを提供します。ファイルやディレクトリの操作、プロセスの管理、環境変数の操作などが可能です。

メリット：
1. OSとの連携が簡単：os モジュールを使用することで、ファイルシステムの操作やコマンドラインタスクの実行が簡単に行えます。
2. コードの移植性向上：コードがクロスプラットフォームで動作する可能性が高まり、様々なOS環境で一貫した結果が得られます。


## osモジュールでよく使われるメソッド
&nbsp;

* popen()
システムコマンドを実行して返されるオブジェクトを使用し、read メソッドで文字列を読み取ります。この際、エンコーディングを自動的に変換することが可能です。
```python
obj = os.popen("ipconfig")
```

* listdir()
指定したディレクトリ内のすべてのファイルとディレクトリ（隠しファイルを含む）をリストとして取得し、一覧表示します。
```python
lst = os.listdir()
```

* getcwd()
現在の作業ディレクトリの絶対パス、つまり現在Pythonスクリプトが動作しているディレクトリの絶対パスを取得します。
```python
res = os.getcwd()
```

:::note info
補足:
現在の Python スクリプトのパスとファイル名を取得する
print(\_\_file__)
:::

* chdir()
現在のスクリプトの作業ディレクトリを変更する。
Shellのcdコマンドに相当します。
```python
os.chdir("/home/test/work")
```

:::note info
補足 : environ
環境変数を取得または変更する
print(os.environ["PATH"])
:::

* makedirs()
ディレクトリを再帰的に作成する
```python
os.makedirs('dirname1/dirname2') 
```

* os.mkdir('dirname')
単一のディレクトリを作成します
Shellの mkdir dirname を実行するのと同じです
&nbsp;

* os.rmdir('dirname')
単一の空のディレクトリを削除します
ディレクトリが空でない場合、削除できずエラーが発生します
Shellの rmdir dirname を実行するのと同じです
&nbsp;

* os.remove()
ファイルを削除します
&nbsp;

* os.rename('oldname', 'newname') 
ファイルまたはディレクトリの名前を変更します
&nbsp;
Angular 18 アップデート後のプロキシ問題：/api/* と /api/** の違い

# まずは結論から
`/api/`以下の全階層のリクエストに対してプロキシを適用したい場合、パスには `*` を2つ書きましょう。

``` javascript: .proxy.conf.js
const PROXY_CONFIG = {
  "/api/**": { // OK
    target: "http://localhost:4321",
  },
  "/api/*": {  // NG
    target: "http://localhost:4321",
  },
};
```

# 解説
Angular 17 まではプロキシの設定で `/api/*` と書くと、`/api` から始まるすべてのリクエストに対してプロキシが適用されていました（[詳細は後述します](#webpack-dev-server-v4-と-vite-のパスの違い)）。

この挙動が Angular 18 から変わっています。

Angular 17 と 18 でプロキシの挙動が変わってしまった要因は２つあります。
* 開発サーバーが webpack-dev-server から Vite に変わった
  * [Automated migration (Recommended)](https://angular.dev/tools/cli/build-system-migration#automated-migration-recommended)
* webpack-dev-server のバージョンが 4系から5系になった

直接的な原因は Angular そのものではなく、Angular CLI が依存している webpack-dev-server にあります。


## Angular 18 アップデートの影響


何も考えずに `ng update` で Angular 18 にすると、既存のプロジェクトのビルダーが `@angular-devkit/build-angular:application` にマイグレーションされます（拒否もできます）。

``` json:Before: angular.json (Webpack)
...
"architect": {
  "build": {
    "builder": "@angular-devkit/build-angular:browser",
...
```
``` json:After: angular.json (esbuild + Vite)
...
"architect": {
  "build": {
    "builder": "@angular-devkit/build-angular:application",
...
```
ビルダーが `browser` から `application` に変わると、使用されるバンドラーも Webpack から esbuild に変わります。
それに伴って開発サーバーも webpack-dev-server から Vite に変わります。
 　
`application`ビルダーは、Angular 17 から正式にサポートされましたが、当時は新規プロジェクトのデフォルトビルダーになっただけで、既存のプロジェクトに影響はありませんでした。

それが Angular 18 からは、アップデート時に既存のプロジェクトのビルダーがマイグレーションされるようになりました。

また、そのまま Webpack を使用する場合も注意が必要で、 webpack-dev-server のバージョンが5系になったことで、どちらにせよ今回の問題に直面します。

## webpack-dev-server (v4) と Vite のパスの違い 

次のように末尾が `/*` の挙動が webpack-dev-server (v4) と Vite で異なります。

``` javascript: .proxy.conf.js
const PROXY_CONFIG = {
  "/api/*": {
    target: "http://localhost:4321",
  },
};
```
上記の場合、
* webpack-dev-server
    *  `/api` から始まるすべてのリクエストに対して機能する
* Vite
    * １階層までのリクエスト（`/api/users`まで）に対して機能する

| リクエストパス | webpack | Vite |
|:-|:-:|:-:|
| /api/users  |  ◯ |  ◯ |
| /api/users/settings  | ◯ | × |
| /api/users/settings/admin  | ◯ | × |
| /apihoge.html  | ◯ | × |

このように挙動が異なるのは、 webpack-dev-server (v4)  が後方互換性のために[独自の実装](https://github.com/webpack/webpack-dev-server/blob/v4.15.2/lib/Server.js#L1493)をしているからです。
webpack-dev-server (v4) では、パスの末尾にある `/*` は削除されます。
そのため、`/api/*` と `/api` は同じパスとして扱われ、`/api` で始まるすべてのリクエストにマッチします。

これは誤解を招く実装であるため、v5では削除されています。
https://github.com/webpack/webpack-dev-server/issues/2454



# おわりに
この件は GitHub に Issue として挙げられています。
[#53652 Proxy config works differently when switching from Webpack to Vite devserver](https://github.com/angular/angular/issues/53652)
そこでも言及されていますが、このことは Angular 公式のアップデートガイドには記載されていません。
[Angular Update Guide from v17 to v18](https://angular.dev/update-guide?v=17.0-18.0&l=3)
クリティカルな変更点なので載せてもらいたいですが、せめて本記事が同じ問題でお悩みの方々の助けとなれば幸いです。
環境ごとにApp.configファイルを分ける【Windowsフォームアプリケーション】

## １・既存の `App.config` をコピーして `App.Debug.config` と `App.Release.config` を作成する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187987/4c031cf2-2bfb-eabf-0b8d-a0c8210d0866.png)


## ２・ソリューション エクスプローラーからプロジェクトのプロパティを開く。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187987/cb397635-f38e-8343-80a3-fb2727ff18a5.png)


## ３・ [ビルド イベント]-[ビルド後イベントのコマンド ライン] に以下のコードを追加する。

```bat:ビルド後イベントのコマンド ライン
set src=$(ProjectDir)App.$(ConfigurationName).config
set dest=$(TargetDir)$(ProjectName).exe.config
copy %src% %dest%
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187987/0cc1cea9-db5f-b939-744b-2594636362f4.png)


これで、Debugビルドの場合は App.Debug.config を、Releaseビルドの場合は App.Release.config を読み込んでくれるはずです。
AWS コスト管理入門メモ

https://www.youtube.com/watch?v=vqDJzy3dMX0&t=2163s

この動画のメモ。

### コスト管理の基本サイクル
可視化→監視・分析→最適化→可視化→...のサイクルを回す。
AWS Cost Explorer、AWS Trusted Advisor、Computer Optimizerなどを使う。

### AWS Organizationsによるアカウント統合管理
AWS Organizationsでアカウントの統合管理。
一括請求（Consolidated Billing）によるボリュームディスカウントの恩恵を得る。
各アカウントで50TB利用の場合、各アカウントでその50TB以下のレートで請求。
統合した場合、100TBとして換算され、50TB以上のレートでのディスカウントを得ることができる。

### 購入オプションの種類
購入オプション：オンデマンド、リザーブド、スポット。
オンデマンド：使った分だけ。
リザーブド：予約して先に支払う。超えた分はオンデマンドレート。
スポット：AWSの余剰リソース。余剰がなくなるとインスタンスが落ちる。いつ停止してもよくて、ただしスパイクがあるものに使える。バッチ処理とか非重要タスクなど。

### コスト配分タグによるコストの細分化
コスト配分タグによるコスト可視化の細分化、監視・分析・最適化の精緻化。
AWS Billingで有効化できる。
アプリケーション毎に管理したりできる。

### ステート（状態）とリソースの分離
ステートとリソースを分離する。
セッション情報や設定などの状態データはDynamoDBに、ログデータはCloudWatch Logsに転送し、インスタンスが落ちても影響がない状態にする。
例を通して学ぶ戦略策定プロセス①　概要・経営戦略

[ビジネスエンジニアリング（B-EN-G）アドベントカレンダー2024](https://qiita.com/advent-calendar/2024/b-en-g) の16日目です！他の記事もぜひご参照ください！

https://qiita.com/advent-calendar/2024/b-en-g

# はじめに

先日、戦略策定について学ぶ機会がありました。
プロダクトマネージャーとして、製品の立ち位置を整理しどのような戦略を立てるべきか考えるために、一通りのプロセスの理解が重要と強く感じています。
そのため、復習と理解向上もかねて記事にします。

具体例を通して説明してみます。参照いただく方の理解が進めば幸いです。

:::note warn
本記事の内容こそが唯一のものではありません。状況、業種、役割などにより検討する内容や範囲は異なります。
:::

## 対象読者
記事の対象読者として以下を想定しています。
- プロダクトマネージャーの卵
- 事業戦略・企画のプロセスを知りたい人

## 注意事項
PPM分析やPEST分析などのフレームワークを記載しています。ただ、これらのフレームワークの説明までは本記事では行いません。使い方に不明点がある方はぜひ調べてみてください。

# いきなりまとめ
経営理念・経営ビジョンという長期的に不変な価値観をベースに、経営戦略→事業戦略→製品戦略の流れで戦略が策定されます。
それぞれの関係性は以下の図のとおりです。
<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620254/ad847a0d-59dd-b97a-c610-caf1fb539f3f.png" Width=40%>

具体的なプロセスは以下のとおりです。
<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620254/451ae630-626d-a209-bea6-fa603058f557.png" Width=80%>


- プロセスに従い検討を進めていくことで、徐々に情報が整理されて戦略立案が進みます。
- それぞれがストーリーとしてつながり、矛盾なく説明できる必要があります。
- 自身の担当範囲だけでなく上流にまで目を向けた方が良いです。会社から求められていることや他事業との関係性を理解できます。

なお、ボリュームを考え記事を分割しています。本記事では<B>経営戦略まで</B>を対象範囲とします。

# ここからは例を通して各プロセスを見ていきましょう
主人公であるAさんと、Aさんが所属するQ計算株式会社を例にプロセスを見ていきます。

::: note warn
以下記載の内容はフィクションです。実在の人物や団体などとは関係ありません。
ビジネス上の穴、分析品質の低さ、納得いかない点など多くあるかと思われますがツッコミ無用です。
また、本記事には数字が特にありませんが、実務では定量情報に基づいた戦略立案が重要です。
:::

## AさんとQ計算株式会社について
AさんはQ計算株式会社の「電卓事業」に所属しています。
今回、事業の拡張を目指し、新製品（サービス）の企画および統括を担当することとなりました。

Q計算株式会社は、卓上電卓の製造から始まった会社です。会社のビジョン（長期的なゴール）として<B>「世界から計算ミスをなくす」</B>を掲げています。
事業として「電卓事業」「学習コンテンツ事業」「データ入力代行事業」を持ちます。

<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620254/3c03e822-8f0f-2a11-d5c1-8bca6eaa1af4.png" Width=60%>

電卓事業はハードウェアの製造・販売を事業としてきましたが、時代の変遷とともにスマホ領域の可能性を探る動きが出てきました。

Aさんは<B>関数電卓</B>に関して、関数電卓そのものをスマホアプリに移行しつつ、新たな価値を出せないか検討することとしました。
既存事業を考え、デバイスをメインにスマホアプリを付加価値とするやり方も考えました。が、良い体験を提供するにはスマホへの一本化が必要、という思いがあるようです。

## 経営戦略
### 事業ドメインの定義
企業/事業のコアを明確にし、戦う領域を決めます。
属性を付与することで領域を具体化できます（例：電卓->関数電卓->グラフ関数電卓）。ただし、具体化すればするほど事業の拡張性がなくなるため、バランスが重要です。

Q計算株式会社は、計算機器の研究・開発・販売を長年続けており知見を培っています。計算の精度と市場認知度に強みがあり、特に電卓は教育・科学研究用途で高く評価されています。


### 資源配分
経営者はPPM（プロダクションポートフォリオマネジメント）や製品ライフサイクルなどを参考に、事業/製品への資源投資の配分（増やす、維持する、減らす、撤退する）を決定します。
１プロダクトマネージャーの視点からしても、自分の製品が市場でどのような立ち位置か確認する際にPPMを利用できます。

シェアや成長率の調査方法としては以下があげられます。
- 市場調査レポートの活用
- 独自の市場調査の実施
- WEB上の発信量の分析（SNSやGoogle Trendsなど）
- フェルミ推定
- etc.

Aさんは会社から過去に共有されたPPMを確認しました。
PPMは市場成長率とシェアに対して事業（製品）売上をマッピングしたものです。位置によって投資方針（の目安）が決まります。

<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620254/122f0a00-b283-ca2a-d5a4-c489e4de07a5.png" Width=70%>

PPMから、電卓事業は花形ポジションにいることがわかります。電卓の領域でトップシェアを目指すべく投資量を増やす判断となったようです（市場が伸びているという点は直感的には疑問があるかもしれませんが、そういう設定です）。

事業/製品ライフサイクルも投資方針の参考とされます。
<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620254/b68929d0-1cda-86f7-2f1d-92e326bc2f77.png" Width=60%>

# まとめ

経営戦略では以下を行う。

- 事業ドメインの定義
    - 企業/事業のコアを明確にし、戦う領域を決める。
- 資源配分
    - 事業/製品への資源投資の配分を決める。
    - その判断基準として、業界内の事業の立ち位置や、ライフサイクルを確認する。

事業戦略以降については以下の記事を参照ください。

--- 
①概要・経営戦略　←本記事
②[事業戦略](https://qiita.com/hotarian/items/b9246cf80697e3f88705)
③製品戦略　←後日公開
プチ話 学校の友だちと弟にBrainF*ckを布教する話

どうもAtsu1209です。
今回は友達と弟にBrainF*ckを布教した話を書いて行きます。
実は私、弟がいました。かなり面倒くさがりの弟です。

# 本題
最近私かなりの量のBrainF*ck記事を書いています。
そんなことをやってたらいつの間にか「AaaLang」とか言う狂ったやつも作ってました

そして友達にこの楽しさを布教すべく
「ねね とてもBrainがF*ckな言語見つけたんだけど」といって布教しました。

弟には
「これ見て」と言ったら「WTF」って言ってました。

# 最後に
みなさんも職場や仲間にBrainF*ckを布教しましょう。

短いけどこれで終わり
MySQLのウィンドウ関数（Window Functions）

MYSQLで知っていると便利なウィンドウ関数について紹介したいと思います！
※MYSQLバージョンが8以上から使用可能です。


◆ウィンドウ関数とは
MySQLのウィンドウ関数は、PARTITION BYやORDER BYを使ってデータをグループ化したり並べ替えたりした後、各行に対して計算を行うことができる非常に強力な機能です。

◆使用方法
RANK() OVER (PARTITION BY 'グループ化の基準になる項目' ORDER BY ’データを整列する基準になる項目’ DESC) AS 'RANK_NUM'


◆ウィンドウ関数
１．集計
・SUM(): 合計を計算
・AVG(): 平均を計算
・MIN(): 最小値を計算
・MAX(): 最大値を計算
・COUNT(): 行数を計算

２．順位
・RANK(): 順位が同じ場合はスキップ（同じ順位の次は飛ばします
・DENSE_RANK(): 順位が同じでもスキップせず、順位を連続的に付けます
・ROW_NUMBER(): 各行にユニークな番号を付けます。順位が同じでも番号は重複しません。

■userテーブル
| USER_ID |USER_TM_ID  | USER_SALES | 
|:---------|:-----------:|:-----------:|
| 1  |1  | 300     | 1   |
| 2  |2  | 300     | 1   |
| 3  |1  |400     | 3   |
| 4  |2  | 500     | 4   |


指定したグループ化基準に含まれないカラム：USER_SALES
指定したグループ化基準のカラム：USER_ID

    SELECT USER_ID
          ,USER_TM_ID
          ,RANK() OVER (PARTITION BY 'USER_ID' ORDER BY ’USER_SALES’ DESC) AS 'RANK'
    FROM USER

| USER_ID |USER_TM_ID  | USER_SALES | RANK |
|:---------|:-----------:|:-----------:|-----------:|
| 1  |1  | 300     | 1   |
| 2  |2  | 300     | 1   |
| 3  |1  |400     | 3   |
| 4  |2  | 500     | 4   |


    SELECT USER_ID
          ,USER_TM_ID
          ,DENSE_RANK() OVER (PARTITION BY 'USER_ID' ORDER BY ’USER_SALES’ DESC) AS 'DENSE_RANK'
    FROM USER
| USER_ID |USER_TM_ID  | USER_SALES   | DENSE_RANK  | 
|:---------|:-----------:|-----------:|-----------:|
| 1  |1  | 300     |1   |
| 2  |2  | 300     |1   |
| 3  |1  |400      |2   |
| 4  |2  | 500      |3   |

    SELECT USER_ID
          ,USER_TM_ID
          ,ROW_NUMBER() OVER (PARTITION BY 'USER_ID' ORDER BY ’USER_SALES’ DESC) AS 'DENSE_RANK'
    FROM USER


| USER_ID |USER_TM_ID  | USER_SALES |  ROW_NUMBER  |
|:---------|:-----------:|:-----------:|-----------:|
| 1  |1  | 300     |1|
| 2  |2  | 300       |2|
| 3  |1  |400    |3|
| 4  |2  | 500      |4|


■ 結果まとめ
| USER_ID |USER_TM_ID  | USER_SALES | RANK  | DENSE_RANK  |  ROW_NUMBER  |
|:---------|:-----------:|:-----------:|-----------:|-----------:|-----------:|
| 1  |1  | 300     | 1   |1   |1|
| 2  |2  | 300     | 1   |1   |2|
| 3  |1  |400     | 3   |2   |3|
| 4  |2  | 500     | 4   |3   |4|

---
GROUP BY との違い

GROUP BYは指定したグループ化基準に含まれないカラムを集計関数（SUM,AVG）で使用可能です。

    SLEECT USER_TM_ID,MAX(USER_SALES) FROM USER GROUP BY USER_TM_ID

 | USER_TM_ID | MAX | 
|:---------|:-----------:|
| 1  | 400     | 
| 2  | 400     | 
 
---

実際の利用例
【順位を付ける関数を使用する前】
①PHPでSQLを利用してデータ検索
②PHPで配列加工
③配列を特定項目基準でソートするように配列加工

【順位を付ける関数を使用する後】
①PHPでSQLを利用して特定項目基準でソートするようにデータを検索
②PHPで配列加工


PHPの処理をSQLで簡単に実行できるので、無駄なコードが減ります！
とても気をつけてほしい「SQLSTATE[HY000] [2019] Unknown character set」

# はじめに
PHPとDBを連携させる練習をしていたのですがタイトルの
```
SQLSTATE[HY000] [2019] Unknown character set
```
のエラーが消えずに困っていました。
今回はその解決策を紹介します。

# 解決策
### .を,に変更するです！

# 原因
phpファイルの一部分を抜粋したものがこちら
```
    <?php
    try {
        $db = new PDO('mysql:dbname=todo_maneger;host=localhost;charset=utf8'.'root'.'root');
    } catch (PDOException $e) {
        echo 'DB接続エラーです: ' . $e->getMessage();
    }
    ?>
```
この中に間違っている部分があるのですが私は気づきませんでした。
charsetの後の区切り方が原因でエラーが出ていることを発見しました。
修正後のファイルがこちら
```
    <?php
    try {
        $db = new PDO('mysql:dbname=todo_maneger;host=localhost;charset=utf8','root','root');
    } catch (PDOException $e) {
        echo 'DB接続エラーです: ' . $e->getMessage();
    }
    ?>
```
これで解決!
# 最後に
web上の記事ではutf-8をutf8に見たいな記事しかなくて困りましたが解決できてよかったです。
アプリで書籍を見ていると細かいところを間違えていることに気づかないので気をつけます。
困っている方の参考になればうれしいです！
タンパク質モデリングソフトRosetta/PyRosettaのインストール方法など備忘録(Ubuntu)

Rosettaはタンパク質モデリング等を行うソフトウェアパッケージですが、インストール段階で躓くこともしばしば。
コケた所をどうやって解決したか毎度忘れてググる、の繰り返しだったので、備忘録として残しておきます。
2023年8月31日時点での情報なので、今後変わってくる箇所もあるかもしれません。


# 環境
Ubuntu 22.04 LTS
Rosetta 3.13



# Rosettaのライセンスの取得とダウンロード

まずは公式サイトからライセンスを取得し、必要ファイルをダウンロード
https://www.rosettacommons.org/software/license-and-download

Numbered ReleaseとWeekly Releaseの二択がありますが、今回はNumbered Releaseの3.13をダウンロードします。
Rosetta 3.13 sourceをダウンロード(5.5G、解凍すると13.1G)


# PyRosettaのダウンロード
ついでにPyRosettaもダウンロードしておきましょう。
Rosettaと同様にライセンスを取得、License and Downloadのページからダウンロードします。
Latest PyRosetta Versions, Python and Python-wheel Packages:
[US East coast mirror] [US West coast mirror]
からダウンロード、EastでもWestでもどちらでもよいです。
Ubuntu 22.04.2でのpythonのバージョンを確認するとpython3.10.6だったので、
/PyRosetta4.Release.python310.ubuntu/PyRosetta4.Release.python310.ubuntu.release-35５.tar.bz2
をダウンロード(1.4G)


# ダウンロードしてきたものを解凍
ダウンロードしてきたRosettaを解凍すると、rosetta_src_2021.16.61629_bundleが生成されるので、
名前を適当に変更(今回はroseta3.13とする)に変更してHome直下に置く。
(/home/rosetta3.13となっている)

PyRosettaも併せて解凍すると、
PyRosetta4.Release.python310.ubuntu.release-350が生成されます。
名前が長いので変更&任意の場所に置く。
今回は/home/rosetta3.13/PyRosetta4という感じでrosetta内に置きました。


# コンパイルの準備
sconsを使ってコンパイルするため、Sconsを入れる。

```diff_python
sudo apt-get install -y scons
```

Ubuntu22.04ではpythonコマンドがpython3となっているので、それに関するエラーを解消する。
python3から/usr/bin/pythonへのシンボリックリンクを貼るか、
rosettaのファイルを書き換える。
scons.py --> 1行目pythonをpython3
update_options.sh --> 8行目pythonをpython3
update_ResidueType_enum_files.sh --> 8行目pythonをpython3
にそれぞれ書き換えると、走るようになります。

ターミナル上でrosetta3.13/main/sourceに移動して、scons.pyを実行。

```diff_python
./scons.py -j <number_of_cores_to_use> mode=release bin
```

<number_of_cores_to_use>は使用するコアの数に置き換えるため、nprocなどでコア数確認し、例えば4コア使用なら

```diff_python
./scons.py -j 4 mode=release bin
```

など。
詳しくは公式サイトを参照。
https://new.rosettacommons.org/demos/latest/tutorials/install_build/install_build

:::note
g++、gccがないと言われたら、
```
sudo apt install build-essential
```
を実行。
:::

:::note
コンパイラ次第で、
scons: building terminated because of errors.
というエラーが出る。
これはRosetta 3.13 がリリースされたときに存在していたものよりも新しいコンパイラを使用しているためとのこと。(古いコンパイラで動作していたものが動作しなくなった)
https://rosettacommons.org/node/11709
最近のweekly releasesでは修正されているようなのでこのエラーが出ることはないが、今回は3.13を使用しているため、
```
#include <cstdint>
```
を
src/protocols/features/FeatureReporter.fwd.hh
の先頭へ追加することで、コンパイルが進むようになる。
:::


# コンパイル中
g++: warning: switch '-ffor-scope' is no longer supported
とか出てきますが、さしあたっては問題なし。

以下のようなzlibがないというエラーが出たので、
/usr/bin/ld: cannot find -lz: No such file or directory
インストールします。
```
sudo apt-get install zlib1g-dev
```

# rosetta完了
終了したら
scons: done building targets.
というメッセージが出てきます。
これでrosettaはOKです。

PATHを通しておいた方が良いかも。
rosetta/main/source/bin
にPATHを通しておくと、のちのち便利かと思います。

# PyRosetta
続いてPyRosettaをインストールする。
rosetta3.13/PyRosetta4/setup
に移動。
```diff_python
sudo python3 setup.py install
```
と入力してインストールができる。

:::note
setuptoolsに関するエラーが出たら、
pip3 install setuptools

pip3が入っていない場合は、
sudo apt update
sudo apt install python3-pip
pip3 -V
:::

# PyRosetta完了の合図
以下のようなメッセージと共に完了します。
Finished processing dependencies for pyrosetta==2023.24+release.9fbc647ae70

pytonにて
import pyrosetta; pyrosetta.init()
と打ってエラーが出なければ成功してます。