OmniAICreator/Qiita-1.07M huggingface dataset:
行列を用いて、砲台を回してみた。

はいどーもー。バーチャルDXライブラリストのキズナア i ...(殴)

冗談は置いておいて、初めまして、SHIBRBKと申します。
DXライブラリで主に3Dを扱ってます。

今回は一応初投稿ということで、文やコードが拙いと思いますが、そこはまぁ、多めにお願いします。

事前準備品
　　戦車のモデル(砲塔と車体のフレームが別のやつ)
　　DXライブラリ
  
```C++:コード
int tankModelid_ = MV1LoadModel("Tank.mv1")

MATRIX mat = 
MV1GetFrameBaseLocalMatrix(tankModelid_, フレーム番号);// 指定のフレ-
ムの初期状態での座標変換行列を取得する.

VECTOR scale=MGetSize(mat);//大きさ

MATRIX matscl = MGetScale(scale);// 拡大行列を取得する

VECOTR pos = MGetTranslateElem(mat);//行列の平行移動成分を取得する

VECTOR TurretLocalPos = TurretQua.PosAxis(/*砲台が車体から離れた座標分補完させる(ここは直値になった)*/);

pos = VAdd(pos, TurretLocalPos);

MATRIX matPos=MGetTranslate(pos);
mat = MMult(mat, matscl);//大きさ
mat = MMult(mat, TurretQua.ToMatrix());//回転
mat = MMult(mat, matPos);//位置

MV1SetFrameUserLocalMatrix(tankModelid_,フレーム番号, mat);

```

クォーターニオンクラス作ったほうがいいかも…
```C++:クォーターニオン.h
public:

Quaternion::Quaternion(double ww, double wx, double wy, double wz)

//座標を回転させる
static VECTOR PosAxis(const Quaternion& q, VECTOR pos);
VECTOR PosAxis(VECTOR pos) const;

// クォータニオンから行列へ変換
static MATRIX ToMatrix(const Quaternion& q);
MATRIX ToMatrix(void) const;

private:
double w; 
double x;
double y;
double z;
```

```C++:クォーターニオン.cpp
Quaternion::Quaternion(double ww, double wx, double wy, double wz)
{
    w = ww;
    x = wx;
    y = wy;
    z = wz;
}

VECTOR Quaternion::PosAxis(const Quaternion& q, VECTOR pos)
{
    // 位置情報に回転情報を反映させる
    // pos' = q・pos・q(-1)
    Quaternion tmp = Quaternion();
    tmp = tmp.Mult(q);
    tmp = tmp.Mult(Quaternion(0.0f, pos.x, pos.y, pos.z));
    tmp = tmp.Mult(q.Inverse());
    return { (float)tmp.x, (float)tmp.y, (float)tmp.z };
}

VECTOR Quaternion::PosAxis(VECTOR pos) const
{
    return PosAxis(Quaternion(w, x, y, z), pos);
}

MATRIX Quaternion::ToMatrix(const Quaternion& q)
{
    MATRIX mat;

    float sx = static_cast<float>(q.x * q.x) * 2.0f;
    float sy = static_cast<float>(q.y * q.y) * 2.0f;
    float sz = static_cast<float>(q.z * q.z) * 2.0f;
    float cx = static_cast<float>(q.y * q.z) * 2.0f;
    float cy = static_cast<float>(q.x * q.z)* 2.0f;
    float cz = static_cast<float>(q.x * q.y)* 2.0f;
    float wx = static_cast<float>(q.w * q.x)* 2.0f;
    float wy = static_cast<float>(q.w * q.y) * 2.0f;
    float wz = static_cast<float>(q.w * q.z) * 2.0f;

    mat.m[0][0] = 1.0f - (sy + sz);	mat.m[0][1] = cz + wz;			mat.m[0][2] = cy - wy;			mat.m[0][3] = 0.0f;
    mat.m[1][0] = cz - wz;			mat.m[1][1] = 1.0f - (sx + sz);	mat.m[1][2] = cx + wx;			mat.m[1][3] = 0.0f;
    mat.m[2][0] = cy + wy;			mat.m[2][1] = cx - wx;			mat.m[2][2] = 1.0f - (sx + sy);	mat.m[2][3] = 0.0f;
    mat.m[3][0] = 0.0f;				mat.m[3][1] = 0.0f;				mat.m[3][2] = 0.0f;				mat.m[3][3] = 1.0f;
    //mat.m[3][0] = trans.x;				mat.m[3][1] = trans.y;				mat.m[3][2] = trans.z;				mat.m[3][3] = 1.0f;

    return mat;
}

MATRIX Quaternion::ToMatrix(void) const
{
    return ToMatrix(Quaternion(w, x, y, z));
}

```

一応自分のプロジェクトから引っ張ってきたのですが、まだ直せてないところもあるます！

まさかりかついだ金太郎もバンバン飛ばしちゃってください。

色々修正したものはしばらくしたら上げますのでお待ちください
子コンテナーを開始できません

# JavaでWeb開発を進めようとすると・・

こういうの出るときありませんか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287651/06ac4694-b682-2ed3-5a2e-3910a9450d4d.png)

コンソール見ると「子コンテナーを開始できません」との記載も。うーむ。

# 色々試したが・・
サーバーのスクラップ＆ビルドもしたし、クリーンもした。
少なくともサーバー作り直せば治ると思っていたがエラー変わらず。

# 解決方法
URLの向き先を設定する際、@WebServletとweb.xml両方使おうとしていたので、
web.xmlを削除後、@WebServletだけを使用するように変更して解決。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287651/180b1a9b-36f2-45ad-842d-39f975016164.png)

# 解決方法その2
@WebServlet('URLパターン')のURLパターンが重複している可能性もある。
別のサーブレットでも同じURLパターンを使用していないか調査する必要あり！
地味だけどめちゃくちゃ使えるVSCodeの拡張機能5選

# はじめに
今回は、フロントエンジニアとしてVSCode上で日々コードを書く上で、地味だけど、個人的によく使っている便利な拡張機能を5つ紹介します！

## 1. CodeSnap
https://marketplace.visualstudio.com/items?itemName=adpyke.codesnap

**Web上やチーム内にコードを共有したいときに使える**拡張機能です。
スマホで直撮りをしたり、コピペして貼り付けるよりも見栄えが良く読みやすいものになります。

### 使い方
使い方はとても簡単です。
1. 共有したいコードがあるファイルを開き、

![スクリーンショット 2023-12-13 16.47.49.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3071973/2d688698-0f9f-3fc7-6c05-2688178cd10d.png)
1. `command` + `shift` + `p`でコマンドパレットを開き、`CodeSnap`と入力して開く

![スクリーンショット 2023-12-13 16.48.12.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3071973/9a032136-ebaf-309c-9286-bb765ad90010.png)
1. CodeSnapが別タブで開くので、共有したいコードを選択して、シャッターボタンを押す

![スクリーンショット 2023-12-13 16.48.43.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3071973/2c9bb4fd-7840-a7ff-af79-7090b20a77a3.png)

これだけで、綺麗にコードの共有ができます。ハイライトもされているのでめちゃくちゃ見やすいです。

## 2. Better Comments
https://marketplace.visualstudio.com/items?itemName=aaron-bond.better-comments

こちらは、コメントに色をつけてくれる拡張機能で、**コメントに特定の文字を入れることで色分けをする**ことができます（<font color="Blue">`?`だったら青</font>、<font color="Red">`！`だったら赤</font>というような感じ）

![スクリーンショット 2023-12-13 16.51.33.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3071973/685c0ed7-ee26-11d9-a79e-a6f07ecbf7b5.png)

setting.jsonから細かくカスタマイズもできます！

![スクリーンショット 2023-12-13 18.13.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3071973/28881b35-e2ab-b99b-3131-568c2466521a.png)

## 3. Super Console log
https://marketplace.visualstudio.com/items?itemName=ChakrounAnas.turbo-console-log

デバックで何回書いたかわからない**`console.log`を簡単に書きやすく、使いやすくしてくれる**拡張機能です。
### 使い方
- console.logの対象にしたい変数を選択する
- ショートカットコマンドを入力
    - (Mac) `shift` + `option` + `L`
    (フォーマッターを入れている場合上記コマンドと被るので`control`+`option`+`L`の場合あり) 
    - (Windows) `ctrl` + `alt` + `L`

![ezgif.com-video-to-gif-converted.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3071973/e8809ba2-8400-b0ed-7720-32938daa6f59.gif)

どのファイルのどこにあるかまで書いてくれるので便利ですね。

## 4. Auto Rename Tag
https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag

HTMLタグを修正するときに、**開始タグと一緒に閉じタグも修正する必要**がありますが、それを自動で行ってくれる拡張機能です。
階層が複雑になっていて`<div>`が大量にあったりする時に、対応する閉じタグを間違えてしまうこともなくなるので重宝しています。

![ezgif.com-video-to-gif-converted.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3071973/b9d1eac0-3d62-b6a2-a7c8-44071d8a7620.gif)

## 5. Import Cost
https://marketplace.visualstudio.com/items?itemName=wix.vscode-import-cost

こちらは`import`するパッケージがどのくらい大きかを確認できる拡張機能です。
`imoort`するときに、**サイズが大きいパッケージを使いたくない時**や**必要なものだけをimportできているか**を確認するための一つの指標になります。

![スクリーンショット 2023-12-13 16.50.30.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3071973/2052e73d-b389-bb13-1337-70cf3bf2c118.png)

## まとめ
以上になります！便利な拡張機能を使って、開発体験を向上させていきましょう！
他にも便利なものがあったらぜひ教えてください！
AWS Lambdaでサーバーレスプログラミングをマスターする🚀

## 🌱 プロジェクトの背景: 「スマートガーデニングシステムの革新」

考えてみましょう。あなたは「スマートガーデニング」という革新的なプロジェクトに取り組んでいます。目標は、植物の成長を最適化するために、温度、湿度、土壌の状態をリアルタイムに監視する高度なシステムを開発することです。しかし、一つの大きな課題が立ちはだかります。これらのデータを効率的に処理し、適切なタイミングで植物に水や栄養を供給するためには、連続して稼働するサーバーが必要ですが、これは高い維持費と管理の複雑さを意味します。

## 🌟 AWS Lambdaの導入

AWS Lambdaは、このようなシチュエーションに最適なソリューションです。サーバーのプロビジョニング(実際の物理サーバーを準備し、使えるように設定すること）や管理の必要がなく、必要な時にのみコードを実行するリソースを提供します。センサーからのデータがLambda関数をトリガーし、必要な処理を行います。処理が完了すれば、Lambdaは自動的にシャットダウンし、リソースの無駄遣いを防ぎ、コストを削減します。
なんかAirbnbみたいですよね。

## ✅ Lambdaのメリット

- **スケーラビリティ**: 自動的に温度、湿度調節！（データ量に基づいて自動的にスケーリングします。
- **コスト効率**: 使った分だけ！（使用したリソースに対してのみ課金され、アイドル状態のコストは発生しません。）
- **管理の簡素化**: めんどくさい設定は一切なし！（サーバーの設定や保守の必要がありません。

## 🐍 Pythonで「Hello World」を実行

1. **AWSコンソールにログイン** 🌐:
    - AWSアカウントにログインします。(アカウントがない場合は、サインアップが必要です。)

2. **Lambdaサービスへ移動** 🔍:
    - コンソールの検索バーで「Lambda」を検索し、Lambdaサービスページにアクセスします。

3. **新しい関数を作成** 🛠️:
    - 「関数の作成」ボタンをクリックし、「新しい関数を作成」を選択します。

4. **関数の設定とロールの割り当て** 📝:
    - 関数名を入力し、ランタイムとして「Python 3.x」を選択します。
    - 「ロールの選択または作成」セクションで、Lambda関数に適切なロールを割り当てます。
        - **既存のロールを使用**: 既に作成された適切な権限を持つロールを選択します。
        - **新しいロールの作成**: 新しいIAMロールを作成し、必要なポリシーを添付します。このロールはLambda関数が他のAWSリソース（例：S3, DynamoDB）にアクセスするための権限を提供します。

5. **コードの記述** 🖥️:
    - Lambda関数のエディタに以下のPythonコードを記述します。
      ```python
      def lambda_handler(event, context):
          return {
              'statusCode': 200,
              'body': 'Hello World!'
          }
      ```

これらのステップにより、AWS Lambdaでの関数の作成からロールの割り当て、基本的なコードの実装までをカバーできます。これにより、サーバーレスプログラミングの基本をしっかりと理解し、実際にLambda関数を実行することが可能になります。

## 🛡️ Lambdaのロールと設定

Lambda関数には、適切な権限を持たせるための「ロール」が必要です。これは、AWS Identity and Access Management (IAM) を通じて設

定されます。

1. **IAMロールの作成**: AWS管理コンソールでIAMサービスに移動し、「ロール」セクションから新しいロールを作成します。
2. **ポリシーの選択**: Lambda関数に必要な権限を持つポリシー（例：S3バケットへのアクセス権限）を選択します。
3. **ロールの関連付け**: 作成したIAMロールをLambda関数に関連付けます。

## 🌍 まとめ

AWS Lambdaは、サーバーの管理やコストに関する心配を減らし、効率的かつスケーラブルなサーバーレスコンピューティング環境を実現します。スマートガーデニングのようなリアルタイムのデータ処理を必要とするプロジェクトにとって、Lambdaは理想的な選択肢です🌟
Aspidaという素敵なAPIクライアント

## はじめに
最近AspidaというAPIクライアントと出会い、開発体験の良さに感動しました。
この記事で紹介しようと思います。
https://github.com/aspida/aspida

## 何ができるか？
Aspidaは内部ではaxiosが使われていて、 APIの管理やリクエストをより良くしてくれます。

たとえば、axiosなどを使ってAPIにリクエストを送信するときbaseURLやパスを設定していくと思います。

```typescript
axios.get('https://api.example.com/api/v1/articles')
```

Aspidaを使うと下のように書けます。

```typescript
api.v1.articles.get()
```

パスに型をつけられるだけでなくリクエストパラメータやレスポンスボディにも型をつけることができます。
例えばapi/v1/loginへPOSTリクエストをするときにemailとpasswordが必要なら下記のように書けます。

```typescript
const onSubmit = async () => {
  try {
    await api.v1.login.post({
      body: {
        email: formValue.value.email,
        password: formValue.value.password
      }
    })
  } catch (error) {
    console.log(error)
  }
}
```

リクエスト時のタイポで時間が奪われてしまった経験は誰しもあると思います。
それを防ぐことができるのは嬉しいですよね。

## 使い方
簡単に導入方法を紹介します。

まずインストルールです。

```terminal
npm install aspida @aspida/axios axios
```

次にaspidaが読み込むためのapiディレクトリを作成します。
自分はvue-cliで作成した後のプロジェクトなのですがsrc配下にapiディレクトリを追加しました。

次にaspidaの設定ファイルをプロジェクトルートに配置します。
ファイル名は`aspida.config.js`です。

```aspida.config.js
module.exports = {
  input: 'src/api',
  baseURL: 'xxx',
}
```

あとはパスに合わせてTSファイルを書いていきます。
たとえばapi/v1/loginにPOSTリクエスト、リクエストボディはemail, passwordを指定するとしたら下記のようになります。

```ts:src/api/v1/login/index.ts
import { DefineMethods } from "aspida";

export type Methods = DefineMethods<{
    post: {
        reqBody: {
            email: string,
            password: string
        }
    }
}>
```

かなり直感的に書けますよね。
日本語のドキュメントも準備されていてかなり親切なので是非確認してみてください。

https://github.com/aspida/aspida/blob/main/packages/aspida/docs/ja/README.md
Reactでブラウザの横幅を取得する

## はじめに
タブレットやPCなどで表示を切り替える場合、横幅を取得する必要がある。Reactで横幅を取得する方法を記載します。

## 成果物
![width.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/4e537c1f-3132-af5c-83e5-c34c4812f5ea.gif)

## 開発

```tsx:App.tsx
import React, { useState, useEffect } from 'react';

const useWindowWidth = () => {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', handleResize);

    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []);

  return width;
};

const App: React.FC = () => {
  const width = useWindowWidth();

  return (
    <div>
      <p>ブラウザの横幅: {width}px</p>
    </div>
  );
};

export default App;
```
WinFormsでTreeNodeダブルクリック時の子ノードの展開、折りたたみを制御する

WinFormsにおいて、TreeViewのノードをダブルクリックするとその子ノードが展開したり、折りたたみしてしまうので、メモ程度にその制御方法を記述する。

```
private void TreeView_BeforeExpand(object sender, TreeViewCancelEventArgs e)

private void TreeView_BeforeCollapse(object sender, TreeViewCancelEventArgs e)
```
主に、この二つのイベントを使用する。BeforeExpandはノードが子ノードを展開しようとする直前で、BeforeCollapseはノードが子ノードを折りたたみしようとする直前で実行されるイベントである。
つまり、このイベントの手前でダブルクリックかどうかを判断し、boolなどにダブルクリックをしたときのフラグを入れてやればよい。そこで、ノードが展開される直前、さらにその前に実行されるイベントの、TreeView_MouseDownを使用する。
```
private bool isDoubleClick = false;

private DateTime lastClickTime = DateTime.Now;

if(e.Button == MouseButtons.Left && (DateTime.Now - lastClickTime).TotalMilliseconds < SystemInformation.DoubleClickTime)
{
    isDoubleClick = true;
}
else
{
    lastClickTime = DateTime.Now;
}
```
このコードをTreeView_MouseDownに入れてあげることで、ダブルクリックかを判断できる。ダブルクリックの1回目のクリックでelseに入り1回目のクリックを保持したのち、二回目のクリックで今の時間と前回のクリック時間を比較し、それがダブルクリック以内かを判定することでisDoubleClickというbool値にtrueを入れると、ダブルクリックをしたという処理は完了。
この次に入るBeforeExpandと、BeforeCollapseでこのようなコードを入れてあげればよい。
```
if (isDoubleClick)
{
    e.Cancel = true;
}
else
{
    e.Cancel = false;
}
isDoubleClick = false;
```
これで、ダブルクリック判定されたときだけe.Cancel = trueを通り、ノードの展開、折りたたみはなくなる。
LLMを用いたRAGシステムの拡張予測

# RAGの基礎的な仕組み
RAG（Retrieval-Augmented Generation）システムは、LLM（Large Language Model）と呼ばれる大規模言語モデルと、Retrieval（文書検索モデル）を組み合わせた、質問応答（QA）を行うための自然言語処理（NLP）システムの一種です。その主な機能は、大量の情報源から必要な情報を取り出し、その情報に基づいて回答を生成することです。

毎日、私たちはインターネットを利用して無数の情報を調査し、情報を手に入れるためにWebページをクリックし、記事を読み、情報を収集しますが、その過程は時間がかかり、また情報を見つけ出す能力も個々のスキルに依存する形になっています。RAGを使うことで、機械学習モデルが大量の情報源から必要な情報を見つけ出し、その情報に基づいて答えを生成してくれるという体験が実現されます。

RAGシステムは大きく二つのステップで機能します。最初のステップである「Retrieval」ステップでは、入力されたクエリに基づいて、RAGシステムはナレッジベースから関連する文書を検索します。二つ目のステップである「Generation」ステップでは、選択された文書をベースにして最終的な回答を生成します。

このRAGシステムの登場により、LLMの強みである流暢な言葉で回答する能力に加え、LLMの弱点である間違った回答をしてしまう（ハルシネーションが起こる）可能性を回避し、知識をもとに正しい回答を行うことが可能になりました。

# RAGのコア：ナレッジの検索と選択
RAGの鍵となる機能は、大量の情報から必要な情報を検索し選び出すことです。
このプロセスは、「情報の検索」と「選択」の2ステップで実現されます。まず「情報の検索」では、AIモデルは特定の特徴を持つクエリに基づいて情報を検索し、適切な候補をナレッジベースから取り出します。この取り出された情報は、次のステップである「選択」の中で評価されます。

「選択」ステップでは、取り出された候補情報が評価され、その中から最適な情報源が選ばれます。選択の中心となるのは特徴量に基づく類似度です。この類似度は、入力されたクエリと様々な情報源との間の類似度を評価します。

具体的には、情報源は多次元空間上の点として表され、その位置は情報源が持つ特徴量に基づいて決定されます。次に、各情報源と入力クエリの間の類似度が計算され、最も類似度の高い情報源が選ばれます。このプロセスは効率化されており、数千から数百万の情報源の中から瞬時に適切な情報を選択することが可能になっています。

▼RAGの仕組み図　出典：https://storialaw.jp/blog/9916
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625415/b9a13a61-79cc-4e2e-850f-ab3b0e97ad6c.png)


しかし、質問文との類似度で知識を引っ張ってくる仕組みについて、「回答に必要な知識＝質問に似た知識」とは限らないと考えられるため、今後このナレッジ検索の技術は進化していくと考えられます。

# 未来の方向性: 知識グラフとRDF
具体的には、将来的には類似度に基づく関連知識の検索ではなく、知識グラフやRDF（Resource Description Framework）といったツールを活用し、情報の検索がより進化すると予想しています。

知識グラフとは、実体間の関連性をグラフ形式で示すことができるツールであり、RDFは情報を主語、述語、目的語の3つの要素で組み合わせて表現するシステムです。これらの手法が活用されると、より直感的で人間らしい検索と情報の抽出が可能になると考えられます。

▼知識グラフ概要　出典：https://keywordmap.jp/academy/knowledge-graph/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625415/1cb2d369-891b-6954-e963-c4fa5bc2f102.png)



これは、単に特徴量の類似性による評価を越えて、意味的な関連性や情報の階層構造を利用して情報を抽出する能力をRAGにもたらす可能性があります。システムが自ら問いを解決するための文脈を理解し、どの情報が適切な知識として利用できるかを判断する方法を学ぶことが可能になるかもしれません。

これはあくまでも予想ですが、引き続き新しいアプローチと技術がRAGシステムにどのように統合され、どのように知識検索技術が進化していくのか、これからの見どころだと考えられます。
その2

`ItemsControl`の先頭アイテムに対して特別な処理を行うためには、`ItemContainerStyle`や`ItemTemplateSelector`を使用して、先頭アイテムに異なるスタイルやテンプレートを適用することができます。

以下に例を示します。先頭のアイテムに異なるスタイルを適用するケースです：

```xaml
<ItemsControl ItemsSource="{Binding YourCollection}">
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Style.Triggers>
                <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                    <!-- 先頭アイテムに適用されるスタイル -->
                    <Setter Property="Foreground" Value="Red"/>
                    <!-- 他にも必要なスタイルを追加できます -->
                </Trigger>
            </Style.Triggers>
        </Style>
    </ItemsControl.ItemContainerStyle>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <!-- 通常のアイテムに適用されるテンプレート -->
            <TextBlock Text="{Binding YourProperty}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
```

この例では、`ItemContainerStyle`内の`Trigger`を使用して、`ItemsControl.AlternationIndex`が0（つまり先頭アイテム）の場合に先頭アイテムに対して異なるスタイルを適用しています。 `ItemsControl.AlternationIndex`はアイテムの表示順に基づいて割り当てられる値です。

もし先頭アイテムに対して異なるテンプレートを適用したい場合は、`ItemTemplateSelector`を使用する方法もあります。
【Unity】ビルド完了後に自動でZipファイルを作成する方法

2023年アドベントカレンダー 11日目の記事です。

# はじめに
ビルドの生成物をZipした後にアップロードを頻繁に行うユースケースと遭遇したので出来るだけ作業が楽になる方法を考えて見ました。
今回紹介するのはビルド終了時にモーダルを表示し、`はい`を選択すると`./Build/Build_プロジェクト名_ビルド終了時間.zip`のファイルを生成するEditor拡張の作成例になります。

ビルド後に表示されるモーダルはこのような見た目になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1336886/39174db5-775f-5537-ad87-cc04350b5d00.png)


# ソース例

Editor拡張用のスクリプトとなるため、例の如くプロジェクト内の任意の場所に`Editor`ディレクトリを作成し、その中に入れて利用してください。

```cs
#if UNITY_EDITOR
using System.IO;
using System.IO.Compression;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;

/// <summary>
/// ビルド完了時にZipファイルを作成できるEditor拡張
/// </summary>
public class PostprocessBuildZip : IPostprocessBuildWithReport
{
    // ビルド完了コールバックの優先順位
    public int callbackOrder { get { return 0; } }

    /// <summary>
    /// ビルド完了時にZipファイルを作成する
    /// </summary>
    /// <param name="report"></param>
    public void OnPostprocessBuild(BuildReport report)
    {
        // ダイアログが表示されたことを音を鳴らしてユーザーに知らせる
        EditorApplication.Beep();

        // ユーザーにZipファイルを作成するかどうか確認するダイアログを表示
        bool isCreateZip = EditorUtility.DisplayDialog(
            "Zipファイルの作成",
            "ビルドが完了しました。Zipファイルを作成しますか？",
            "はい",
            "いいえ"
        );

        // ユーザーが「はい」を選択した場合のみ処理を続行
        if (isCreateZip)
        {
            // プロジェクト名の取得
            var directoryInfo = new DirectoryInfo(Application.dataPath).Parent;
            string projectName = directoryInfo!.Name;
            

            // 現在の日時をフォーマット
            string dateTimeFormat = report.summary.buildEndedAt.ToString("yyMMddHHmmss");

            // "Build"サブディレクトリのパス
            string buildDirectory = Path.Combine("./", "Build");

            // ディレクトリが存在しない場合は作成
            if (!Directory.Exists(buildDirectory))
            {
                Directory.CreateDirectory(buildDirectory);
            }

            // Zipファイルの生成
            string userSettingBuildPath = report.summary.outputPath; // ユーザーが指定したビルド先のパス
            string zipFileName = $"Build_{projectName}_{dateTimeFormat}.zip"; // Zipファイル名
            string zipPath = Path.Combine(buildDirectory, zipFileName);
            ZipFile.CreateFromDirectory(userSettingBuildPath, zipPath);
            Debug.Log("Build zip created at: " + zipPath);
        }
    }
}
#endif
```

# 主要部分の解説

## IPostprocessBuildWithReport
ビルドプロセスが完了した直後に実行されるメソッド`OnPostprocessBuild`と`callbackOrder`のプロパティが定義されており、今回最も重要な箇所になります。
このInterfaceを実装することによりビルド後の処理が実行可能になります。

## OnPostprocessBuild
ビルド後に呼ばれるメソッドです。
引数としてビルド情報`BuildReport`を受け取っているので、ここからユーザーが指定したビルド先のパスやビルド終了時間を取得しています。

## callbackOrder
複数のクラスで`IPostprocessBuildWithReport`が定義されていた場合の優先度です。
小さい方が優先度が高いです。

# 最後に
OnPostprocessBuildの中でビルド生成物をサーバーにアップロードしたり、バックエンドAPIを叩いたりできそうなので、かなり応用が効きそうだと思いました。
よろしければ本記事を参考に色々試してみてください。
Next.jsでCSVをAPIに送るのに苦戦した

# はじめに

Next.jsからファイルをAPIにポストしようとしたのですが、調べてもすぐに解決できなかったのでまとめていきます。

# 問題

以下のようにインプットにいれたファイルを登録できるようにしました

```ts
  const [file, setFile] = useState<File>()

  const handleSubmit = async () => {

    const res = await fetch(
      `/api/v1/resources/mappings`,
      {
        method: "POST",
        body: { fle: file }
      },
    );
    const { body } = await res.json();
    setResponse({ status: res.status, body });
  };
  ```

  そしてNext.jsのAPIでさらに外部APIを叩くようにしています

```ts
export async function POST(request: NextRequest) {
  const json = await request.json();
  const formData = new FormData();
  formData.append("file", JSON.stringify(json.file));
  const response: createMappingResponse = await fetch(
    `${process.env.EP_ORIGIN}/api/internal/v1/mappings`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: formData,
    },
  ).then((res) => res.json());
  const status = response.result.failed.length === 0 ? 201 : 400;

  return NextResponse.json({ body: response.result, status });
}
```

しかしこれではうまくファイルを送ることができあせんでした

# 解決方法

ファイルの送り方をformdataに包んで送るようにしました
また、handleSubmitの段階で送る時にformdataを使っていなかったので使うようにしました

```ts
  const handleSubmit = async () => {
    const formData = new FormData();
    formData.append("file", file!);

    const res = await fetch(
      `/api/v1/resources/mappings`,
      {
        method: "POST",
        body: formData,
      },
    );
    const { body } = await res.json();
    setResponse({ status: res.status, body });
  };
  ```


```ts
export async function POST(request: NextRequest) {
  const formData = await request.formData();
  const response = await fetch(
    `${process.env.EP_ORIGIN}/api/internal/v1/mappings`,
    {
      method: "POST",
      body: formData,
    },
  ).then((res) => res.json());

  return NextResponse.json({ body: response.result, status: response.status });
}
```

# おわりに

なぜか結構難しいなと感じたのはNext.jsのAPIと外部APIの2回で渡していたのが原因かなと思いました
うまくいったよかったです
【明示的待機】WEBサイトが完全に開いたら次のアクション



## はじめに
に関しての備忘録です。
初心者です😅
間違えてる部分、多々あると思います。
もし見つけた場合、ツッコミいただけると助かります🙇
<br>
## 🦁<INS>**結論**</INS>🦁

```python:sample.py
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait

# WebDriverのインスタンスを作成
driver = webdriver.Chrome()

# ウェブサイトを開く
driver.get("http://example.com")

# ページが完全にロードされるのを最大3秒間待機する
WebDriverWait(driver, 3).until(
    lambda x: x.execute_script('return document.readyState') == 'complete'
)

# ここにページが完全にロードされた後の処理を書く
# 例: 特定の要素の検索、データの取得、クリック操作など

# ブラウザを閉じる
driver.quit()
```
***

:::note info
押さえておくべき点
* execute_scriptメソッドを使用して、ブラウザでJavaScriptコードを実行し、ページの読み込み状態を確認してる
* ページの読み込み状態はdocument.readyStateプロパティによって判断される（）
* タイムアウト設定が引数に入れる必要がある（入れないと例外）
:::  

document.readyStateプロパティ
* 'loading': ページがまだ読み込み中です。
* 'interactive': ページのDOMは読み込まれていますが、まだ完全には読み込まれていない。
* 'complete': ページの読み込みが完了。

***


:::note warn
利用シーン
* Webページが完全な読み込みをさせてから次のアクションを行いたいとき
* パフォーマンスモニタリングをしたい場合（どのぐらいの時間がかかるのか？など）
:::  
***


:::note alert
注意点
* 例外処理を行う必要あり（タイムアウトする可能性）
* JavaScriptの実行権限が制限されてる場合がある。
:::  

***
【Flutter】画像の読み込みが遅かった問題をcached_network_imageで改善する

![スクリーンショット 2023-12-13 9.45.59（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/28d250d0-fde5-5f14-ea58-3b08b534edef.png)


:::note info
この記事は、<b>株式会社ゆめみの23卒 Advent Calendar 2023</b>のアドベントカレンダーになります！！
色々な種類の記事が投稿されるので、お楽しみに🤗
:::

https://qiita.com/advent-calendar/2023/yumemi-23-graduation


# 初めに

開発を進める中で画像の読み込みが遅いな？？と思った時にすぐに改善策を思いつかずにいたので、今後も忘れないようにと思い、記事を書くことにしました。


# cached_network_imageについて

https://pub.dev/packages/cached_network_image

簡単に説明すると、
- ネットワークから取得した画像をキャッシュして表示を高速化するためのPackageです。

キャッシュの仕組みについては以下の記事がわかりやすくまとめていただいているので掲載させていただきます🙇

https://zenn.dev/flutteruniv_dev/articles/20220615-160504-flutter-cached-network-image-test


# 導入までの流れ

```terminal
flutter pub add cached_network_image
```

```yaml
dependencies:
  cached_network_image: ^3.3.0 # 適宜最新のバージョンを入れてください
```



# cached_network_imageを使用なしと使用あり

| 使用なし | 使用あり | 
|:-----------:|:------------:|
| ![RPReplay_Final1702511938.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/a48ec6d1-b286-c330-6152-b5e1d701e72c.gif)  |  ![RPReplay_Final1702511963.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/31853229-0b1a-0f1c-0115-107c842d6ccf.gif)  | 


今回の場合は、写真の数が多くないため、大きな違いは見られないかもしれませんが、それでも違いが見られますね。


## cached_network_imageを使用なしと使用ありの実装

```dart

// 使用なし
Image.network(
  '',
  fit: BoxFit.cover,
),


// 使用あり
CachedNetworkImage(
  imageUrl: '',
  fit: BoxFit.cover,
),

```




# 最後に
今回は少し画像でしたが、大量になってくると辛いなと思っていたのでよかったです💦


# ちょっとした宣伝

株式会社ゆめみの23卒のメンバーでアドベントカレンダーを作成しています。
新卒のフレッシュな記事がたくさん投稿予定なので、少しでも興味があれば購読いただけると幸いです！！


https://qiita.com/advent-calendar/2023/yumemi-23-graduation



<img width="1240" height="112" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/6d8a7098-9aef-a19a-54fe-83a2d493e033.png" alt="YUMEMI New Grad Advent Calendar 2023">
Gemini Pro APIをGAS（Google Apps Script)で利用してみた【サンプルコード】

# 概略
- 2023年12月13日(日本時間12月14日)に公開されたGemini Pro APIをGASで使ってみました。
- APIキーの取得方法と、動作するGASサンプルコードを作成しましたので置いておきます。

# APIキーの取得方法
[Google AI Studio](https://makersuite.google.com/app/apikey)のGet API Keyで、APIキーを取得します。

注意）通常のGoogleアカウントでは問題なく取得できました。私のGoogle Workspaceアカウントでは早期アクセスアプリ へのアクセス権をonにしても利用できませんでした。（早々に利用可能になると思います。）

同意項目は一番目は必須です。2番めはニュースレターの登録、3番目は調査研究参加への招待状が欲しい場合です。
![2023-12-14_08h55_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2543470/059d207c-eba4-cde7-b467-ec5f166cb5af.png)

これで得たAPIキーを安全な場所に保存しましょう。

## GAS（Google Apps Script)のコード

下記に作成したサンプルコードを示します。


```GAS:getGeminiProResponse

function fetchApiResponse() {

  const apiKey = "YOUR_API_KEY"; // 実際のAPIキーに置き換えてください
  const questionText = "200文字程度で、地球の大きさについて教えて下さい。"; // 実際の質問テキストに置き換えてください

  let resultText = getGeminiProResponse(apiKey, questionText);
  Logger.log(resultText);

}

function getGeminiProResponse(apiKey, questionText) {
  const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${apiKey}`;

  const payload = {
    "contents": [{
      "parts": [{
        "text": questionText
      }]
    }]
  };

  const options = {
    "method": "post",
    "contentType": "application/json",
    "payload": JSON.stringify(payload)
  };

  const response = UrlFetchApp.fetch(url, options);
  const jsonResponse = JSON.parse(response.getContentText());

  if (jsonResponse && jsonResponse.candidates && jsonResponse.candidates.length > 0) {
    const answerText = jsonResponse.candidates[0].content.parts[0].text;
    return answerText;
  } else {
    return "回答を取得できませんでした。";
  }
}

```

### 実行ログ

![2023-12-14_09h18_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2543470/f7ff2f93-117a-a967-6520-706bf71179a4.png)

問題なく結果が得られました。

### API Reference
[Gemini Docs and API Reference  \|  Google AI for Developers](https://ai.google.dev/docs?hl=en)

### 2025/1 追記
Gemini Pro APIが登場してすぐにひとまず使えるGASコードを書いたので、現在だと動かないかもしれません。

上記のサンプルを元にして、最近の環境でも動作するGASコードの例を書いていただいている記事を見つけましたので、よろしければ参考にしていただくのもいいかと思います。
[SlackにRSS配信の要約投稿をLLMでやらせてみた。 | まじ（本気）](https://xs239983.xsrv.jp/maji/2024/07/29/slack%e3%81%abrss%e9%85%8d%e4%bf%a1%e3%81%ae%e8%a6%81%e7%b4%84%e6%8a%95%e7%a8%bf%e3%82%92gemini-api%e3%81%a7%e3%82%84%e3%82%89%e3%81%9b%e3%81%a6%e3%81%bf%e3%81%9f/)
EPUBからのPDF生成用としてVivliostyle CLIを導入した

　EPUB制作時の校正用PDF生成目的で<strong><a href="https://vivliostyle.org/" rel="noopener" target="_blank">Vivliostyle Viewer</a></strong>をローカルマシン内にサーバ起動する形で使ってきたのですが（<strong><a href="https://vivliostyle.org/viewer/#src=https://vivliostyle.github.io/vivliostyle_doc/ja/vivliostyle-user-group-vol2/index.html&bookMode=true&f=epubcfi(/10!)" rel="noopener" target="_blank">参考</a></strong>）、先日ブラウザからのPDF出力で白紙ページが大量に入ってしまうChromeのバグを踏んでしまい、いい機会だったのでVivliostyle開発者の村上（<a href="https://twitter.com/MurakamiShinyu" rel="noopener" target="_blank">@MurakamiShinyu</a>）さんに助言をいただいて、上記参考先のコードを書いたときにはまだ無かったローカル環境向けの<strong><a href="https://docs.vivliostyle.org/ja/vivliostyle-cli.html" rel="noopener" target="_blank">Vivliostyle CLI</a></strong>に切り替えましたのでメモを残しておきます。環境はmacOS13.6です。

<div style="padding-left:1em" class="clear">
<h3 style="border-bottom: medium solid gray">Vivliostyle CLIの環境構築</h3>
　まず、node.jsを入れます（<strong><a href="https://tech-blog.s-yoshiki.com/entry/254" rel="noopener" target="_blank">参考</a></strong>）。homebrewは入っていることが前提です。ターミナルで
 
<pre class="lang:sh decode:true " >brew install node</pre> 

これだけ。
 
<pre class="lang:sh decode:true " >node --version</pre> 

でnodeのバージョンが表示されればOKです。

　次にVivliostyle CLIを入れます。同じくターミナルで
 
<pre class="lang:sh decode:true " >npm install -g @vivliostyle/cli</pre> 

これだけです。
</div>

<div style="padding-left:1em" class="clear">
<h3 style="border-bottom: medium solid gray">Perl経由で自動化</h3>
　これを従来同様にPerlで実行できるようにしたのが以下のコード。

 
<pre class="lang:perl decode:true " >######追加CSSファイルのパス、表示するepubファイルの順でパスを指定するとepubファイルをVivliostyle CLIで開いてChromiumで表示する。Mac専用。######
use utf8;
#Encodeモジュールをインポート
use Encode qw/encode decode/;

#############################################

#追加CSSファイルのパスを取得
my $addCssPath = $ARGV[0];
$addCssPath = decode('UTF-8', $addCssPath);

#表示するepubファイルのパスを取得
my $epubFilePath = $ARGV[1];
$epubFilePath = decode('UTF-8', $epubFilePath);

#Vivliostyle CLIで処理してChromiumで表示
my $openVivliostyleCliCmd = "osascript -e " . "'" . "tell application \"Terminal\" to do script " . "\"" . "vivliostyle preview " . $epubFilePath . " --style " . $addCssPath . "\"" . "'";
system $openVivliostyleCliCmd;</pre> 


　ノンブル表示、見開き指定などのための追加CSSは --style オプションを使って外部ファイルを読み込む形としました。その方が修正もしやすいし（追加CSSの参考例はVivliostyle CLIのオンラインマニュアル内にある）。<strong>「vivliostyle preview」</strong>を指定しているので、Chromiumブラウザが起動してページが表示されます。あとはこれまで通り印刷ウィンドウでPDFを保存を選択して出力するだけです。だいぶ簡単になりましたね。
　なお、その後Chrome側でバグが修正されたとのことなので今は古い方のスクリプトでも問題なくPDF生成はできるようです。
</div>
C# 起動中のプロセス一覧の取得、起動、終了

# 背景

業務で使用しているツールを自動化するために色々と試しました。その備忘録です。
・ツールを起動する
・ツールを終了する
・ツールが起動するか確認する

# プロセスを起動する

```cs
//メモ帳を起動する
Process p = Process.Start("notepad.exe");
```

# プロセスを終了させる

```cs
//ローカルコンピュータ上で実行されている"notepad"という名前の
//すべてのプロセスを取得
Process[] ps = Process.GetProcessesByName("notepad");

//配列から1つずつ取り出す
foreach (Process p in ps)
{
	p.Kill();//プロセスを強制的に終了させる
}
```


# 起動中のプロセス一覧を取得する

```cs
using System.Diagnostics;

//ローカルコンピュータ上で実行されているすべてのプロセスを取得
Process[] ps = Process.GetProcesses();

//配列から1つずつ取り出す
foreach (Process p in ps)
{	
	try	
	{
		tbMessage.Text += $"プロセス: {p.ProcessName} {p.Id} {p.MainModule.FileName}" + Environment.NewLine;
	}
	catch (Exception ex)
	{
		tbMessage.Text += $"エラー: {ex.Message}";
	}
}
```


# メモ帳が閉じない？
`p.Close();`を使って「メモ帳を閉じる」ことが出来ると思っていましたが、期待する動作になりませんでした。
もう少しプロセスについて理解を深める必要がありそうです。

![memo_GPT.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/d6c6b712-4384-24ca-13ff-249434b56fff.png)


# 参考ページ

https://dobon.net/vb/dotnet/process/getprocesses.html

https://dobon.net/vb/dotnet/process/getprocessesbyname.html
milk-V Duo カメラのトラブルシューティング

カメラを接続して、サンプルスクリプト `CviIspTool.sh` を動かします。


# 環境

- milk-V Duo
- カメラ: CAM-GC2083

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/5601c8da-8599-a49e-8c5d-f879f4f11130.png)

# 接続

![IMG_20231210_144500 (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/b11bbc3f-25b2-caf7-6967-63a3c9ad5622.jpeg)

# スクリプトの起動

```
root@milkv-duo]/mnt/data/install# ./CviIspTool.sh 64M
pin PAD_MIPIRX1P
func IIC1_SDA
register: 30010f0
value: 4
.
.
.
```

# 正常な反応

以下のように進んでいきます。

```
.
.
.
awbInit ver 6.7@10121100
0 R:1400 B:3100 CT:2850
1 R:1500 B:2500 CT:3900
2 R:2300 B:1600 CT:6500
Golden 1024 1024 1024
WB Quadratic:0
isWdr:0
ViPipe:0,===GC2083 1080P 30fps 10bit LINE Init OK!===
********************************************************************************
cvi_bin_isp message
gerritId:      36403          commitId:      c69c5863e      
md5:           cab880835a2ad5184de5ed7762404b84
sensorNum      1              
sensorName0    2083        
.
.
.
[SAMPLE_COMM_ISP_Thread]-95: ISP Dev 0 running!
CVI_ISP_GetPubAttr Get FPS: 30.000000
VpssChn0 , Enable Vpss Grp: 0
VPSS init with src (1920, 1080) dst (1920, 1080).
CVI_VPSS_CreateGrp:0, s32Ret=0
rtsp://127.0.1.1:8554/stream0
prio:0
CVI_RTSP_SERVICE_CreateFromJsonFile[./cfg_64M.json]
connect: 192.168.42.138
[REMOTE] cvi_raw_dump_run,158: raw dump ready...
waiting for connect...

```

と続いていきます。

# ケーブルが接続できていない

以下のようになったときは、ケーブルが接続できていません。
```
.
.
.

**** - venc_cfg.videoFormat:0
**** - venc_cfg.videoFullRangeFlag:0
**** - venc_cfg.colourDescriptionPresentFlag:0
enable online mode 1
ISP Vipipe(0) Allocate pa(0x83364000) va(0x0x3ff4b5d000) size(290968)
stSnsrMode.u16Width 1920 stSnsrMode.u16Height 1080 25.000000 wdrMode 0 pstSnsObj 0x3ff4fb7878
[SAMPLE_COMM_VI_StartMIPI]-483: sensor 0 stDevAttr.devno 0
vi init failed. s32Ret: 0xffffffff !
init vi fail
CVI_RTSP_SERVICE_CreateFromJsonFile fail -1
CVI_RTSP_SERVICE_CreateFromJsonFile[./cfg_64M.json]
[REMOTE] cvi_raw_dump_run,158: raw dump ready...
waiting for connect...
```


# 着目点

うまくいってないときには devno が取得できていません。

```
[SAMPLE_COMM_VI_StartMIPI]-483: sensor 0 stDevAttr.devno 0
```
AVR ISP Shield（書き込み装置）せっかく買ったのに使えなかった。

今回ATmega328Pの開発案件があり、毎回装置を自作して
書き込みするのが面倒くさかったので、
amazonで書き込み装置を購入してみた！

自作した書き込み装置
https://qiita.com/Kurogara/items/e19ccd6a307d43e221c7

購入した書き込み装置
https://www.amazon.co.jp/dp/B07HLMMJJM/

ATmega328Pは、秋月でブート書き込み済みの物を
購入したのでスケッチをそのまま書き込んだが
一番初めは何事もなく成功！！

しかし二回目からうまく書き込みができない。。。
なぜ？

調べてみたらArduino as ISPで書き込む時の配線接続と
AVR ISP Shieldの配線が微妙に違う。。。

仕方なく自作で書き込み装置を作って書き込むことに。。。
これで正常に二回目からも書き込みができるようになった。

まじで無駄なものを買ってしまった。
書き込んだプログラムが悪い可能性もありますが、
皆さんも注意してください。
【Day 18】API 環境構築 - Docker Postgresql

## はじめに

![スライド19.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/dd6ea09c-9533-f3b5-66a9-51e9e4a7011e.png)


---

**2023年アドベントカレンダー18日目**です。

https://qiita.com/advent-calendar/2023/life-sync-app

本日は前回に引き続き「開発者はAPIの開発を進めることができる」を進めています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/2b71c2cf-703a-c8de-0753-e49bd0512782.png)

今回はPostgresqlをDockerで立てて、初期データを入れるところまでやっていこうと思います

## Postgresql

https://www.postgresql.jp/

### Postgres on Docker Compose

今回は`docker compose`で構築していきます

```yaml:compose.yaml
version: '3'

services:
  db:
    image: postgres:16
    ports:
      - 5432:5432
    environment:
      POSTGRES_DB: blog
      POSTGRES_USER: blog_user
      POSTGRES_PASSWORD: blog_password
    tty: true
    stdin_open: true
```

これで起動はできるはずです

```bash
$ docker compose up
```

ただし、テスト用の初期値(seed)を入れておきたいので、次のSQLを作成しました。

```sql:init/init.sql
CREATE TABLE blog (
    id UUID PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    author VARCHAR(255) NOT NULL,
    body TEXT NOT NULL,
    created_at VARCHAR(255) NOT NULL
);

INSERT INTO blog (id, title, author, body, created_at)
VALUES 
('123e4567-e89b-12d3-a456-426614174000', 'カフェの隅で見つけた幸せ：私のお気に入りの隠れ家', '田中太郎', 'ブログの本文', '2023-12-09 09:00:00');
```

作った初期化SQLを`/docker-entrypoint-initdb.d`に設置します

```diff_yaml:compose.yaml
version: '3'

services:
  db:
    image: postgres:16
    ports:
      - 5432:5432
    environment:
      POSTGRES_DB: blog
      POSTGRES_USER: blog_user
      POSTGRES_PASSWORD: blog_password
+   volumes:
+     - ./init:/docker-entrypoint-initdb.d
    tty: true
    stdin_open: true
```

この状態で起動することで、Seedが入った状態でPostgresqlを起動することができます

```bash
$ docker compose up
```

これでRustの開発環境ができました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/2b71c2cf-703a-c8de-0753-e49bd0512782.png)


明日からはRustでAPIの実装を進めていきます👍
駆け出しエンジニアがスキル不足を感じながらも楽しく働くために心がけていること３選

この記事は [クラウドワークス Advent Calendar 2023](https://qiita.com/advent-calendar/2023/crowdworks) シリーズ2 の 17日目の記事です。

## はじめに
こんにちは、エンジニアの井上です。

私は2023年6月にクラウドワークスへ入社しました。

それ以前はSI系の企業でSEとして働いていましたが、開発経験は1年未満です。
いわゆる「駆け出しエンジニア」に相当するかなと思っています。

「駆け出しエンジニア」が直面する問題として、自分のスキルと現場で求められる能力との乖離が大きすぎてつらい・病む、といった現象が挙げられます。
実際に入社当初、1on1で「大丈夫ですか？」「辛くないですか？」と心配していただくことが多々ありました。

ところが私の場合、自分のスキル不足は常々感じておりますが、それはそれとしてとても楽しく・モチベーション高く働けています。

ただし、私は根っからのポジティブ人間というわけではありません。むしろメンタル弱いです。
なので前向きな気持ちを保ち続けるための取り組みを普段から色々しています。

そこで本記事では、そういった自分なりの心がけや工夫をいくつかみなさんに共有してみようと思います。

## 1. 自分を責めすぎない

タスクの消化に時間がかかったり、「自分には難しすぎるな」と無力感を感じても、自分のせいにしすぎないことを何より心がけています。

自己肯定感が下がってしまうと、働くことがどんどん辛くなってしまうからです。せっかくエンジニアとして働いているのに、それではあまりに悲しいしもったいないです。

私の場合、最初は何が分からないのかも分からず、でも早く戦力になりたい思いもあって大パニックに陥っていました。その時に「このままじゃ息切れしそうだな」と感じ、考え方を改めることにしました。

現在は「自分なりにやるだけやってそれでもダメなら誰かが助けてくれるだろう」といった心持ちで働くようにしています。これは投げやりな考えではなく、「何か問題があったら周りの人が軌道修正してくれるはず、だからとりあえず思ったことをやってみよう！」というポジティブな開き直りです。このように考え始めてから、落ち込んだり気持ちが萎えたりせず、ただ目の前の業務を一生懸命取り組むことだけに集中できるようになりました。さらに日々の業務を楽しむ余裕も生まれました。

「他人任せは良くない」「責任感を持て」といった意見も当然あるでしょう。しかし自分を追い込み過ぎて自己肯定感が下がって辛くなってしまうくらいなら、ときには開き直ってでも前向きな気持ちを維持し続ける方が、自分にとっても会社にとっても良いかなと判断しています。

そして何よりこういったマインドで働けているのは、実際に助けてくれる先輩方や「いざとなったら助けてもらえそうだ」と思わせてくれる、クラウドワークスの雰囲気の良さのおかげだと常々思っています。

## 2. SNSを見ない

なるべくSNSを見ないようにしています。

ついつい他人と比較してしまいそうになるからです。

クラウドワークスに入社当初、自分の現在地が気になるあまり、経歴の近いエンジニアのアカウントを多数フォローしていました。しかし「もうこんなに色々やってるんだ〜」とか「もうこんなに稼いでるんだ〜」など、自分と比較してただただ劣等感が高まるだけでした。逆に、挫折したり鬱になっている方のアカウントを見るのもそれはそれで、「自分も引っ張られそうで危ないな」と思いました。「フォロー外せばいいだけじゃん」と思われるでしょうが、怖いもの見たさで見たくなってしまう自分を制御できないため、可能な限りSNS自体を避けています。

本来SNSは情報収集のツールとしてもアウトプットの場としても有益ですし、エンジニアであれば上手に使いこなすべきですが、現時点での自分にとってはメリットよりも精神面に与えるデメリットの方が大きいため、もったいないと感じつつもこの意思決定に至りました。

悩みや気になることがあれば先輩方といつでも気軽に1on1ができるので、わざわざSNSに頼らなくても良いかなと今のところは考えています。

## 3. 運動する

定期的に何かしらの運動をするようにしています。

気分転換にもなるし、身体を動かすことで精神的な疲れを紛らわせることができると感じているからです。

私の場合は週2, 3の頻度でジムへ行くことを習慣づけています。とはいえ「ベンチプレス100kg挙がります」とか「ささみとブロッコリーしか食べません」みたいなガチ勢ではないです。それでもたまに身体を動かすとメンタル面でもだいぶスッキリする感覚があり、心と身体が繋がっているなと実感できます。それに、体型の変化を感じたり以前より重いダンベルを持てたりすると、小さな成功体験が積めて自己肯定感も高まる気がしています。

「ジムはハードルが高い」という方は、朝や業務後に近所を散歩したりするだけでも、少しは気晴らしになるはずです。運動そのものというよりも、外に出るなどしてアナログな時間を過ごすことが効果的なのかもしれません。

## おわりに
いかがだったでしょうか？

こういった取り組みを続けて半年ほど経過しましたが、ポジティブなマインドやモチベーションは、工夫次第で意外とコントロールできるものだなと手応えを感じています。今後も楽しく働くことを忘れず、着実に成長していければと思います。

同じような境遇の方の参考になれば幸いです。

最後にクラウドワークスでは様々な仲間を募集しております。
ご興味のある方は以下のリンクからご応募ください！
https://crowdworks.co.jp/careers/
出先や会社から家のWindows PCに接続する【AnyDesk編】

# AnyDesk って何？

高速な遠隔操作とリモートアクセスソリューション AnyDesk
https://anydesk.com/ja

* リモートアクセスのための賢い選択
* 170,000社以上の信頼と導入実績
* グローバルプロキシサーバー

# AnyDesk 無償版でできること

Anydeskの価格（料金・費用）を紹介！無料も含めたプランごとの年間・月額費用も掲載
https://www.itreview.jp/products/anydesk/price

【無償版】
0 円 / 月
●無料ユーザー1人
●同時接続1（発信）
●管理デバイス3台（無人アクセス）
●接続元デバイス1台
●接続デバイス無制限（インタラクティブアクセス）
●機能制限

# AnyDesk のセットアップ

サーバー側(自宅PC)のセットアップと、出先PC側での簡単な設定が必要になります。

## AnyDesk アカウントの作成

* https://anydesk.com/ja にアクセスしてアカウントを作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/14e8b195-35e3-e9c4-3043-0e9bf9bad5b2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/42681d31-f805-89fe-df07-9246be69e121.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/4719ce45-ea76-8c80-5920-e518f014b499.png)

## サーバー側(自宅PC)のセットアップ

* https://anydesk.com/ja からダウンロードした AnyDesk.exe をデスクトップ等におきます。
(インストールして使うので、とりあえずの置き場所はどこのフォルダでもいいです)

* AnyDesk.exe をダブルクリックして起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/f34f49f1-3b77-8c22-dd7e-bce42d89f809.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/f8da8ce2-cae3-2e51-a42b-3935e29794fd.png)

* リモートから無人でアクセスするにはパスワードの設定が必要です。

以下の手順で、リモートからアクセスするためのパスワードを設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/52fee114-90ac-f69d-f804-ec7f56e1b114.png)

* ワークスペース・アドレスの記録

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/7fc1977f-7e3a-89ca-4764-38713faeecbd.png)

* AnyDesk.exe をUSBドライブにコピー

⑧でワークスペース・アドレスを記入したテキストファイルとともに、AnyDesk.exe もUSBディスクにいれておきましょう。

これでサーバー側(自宅PC)のセットアップは終わりです。

# 出先PCからの接続

* USBにコピーした AnyDesk.exe を起動します(インストールはしません)。

* ③で登録したメールアドレスとパスワードでログインします。(ライセンス未登録のメッセージを抑制するため)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/97e0e769-92fa-8d73-4872-602c56fd1bc7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/9c9c24dc-4bf7-9d8d-2c65-60903fed33d4.png)

* ⑧でテキストファイルに貼り付けたワークスペース・アドレスを使って接続します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/9fb7b9db-7721-e01b-06eb-cd4b566a366e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/966ec1d5-420e-86b8-e53c-af6ef118366d.png)

* 全画面モードに切り替えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/5a7879e4-f970-9601-4eb8-d8bb25433e19.png)

* キーボードを「翻訳」モードに切り替えます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/90656ff8-1887-20c0-b814-4df3f28c0806.png)

# 最後に

AnyDesk は解像度を自動的にあわせてくれないので(拡縮して表示)、接続後にデスクトップを右クリックして、「ディスプレイ設定」から解像度を変更する必要があります。

AnyDesk を使っていると「半角/全角」キーでIMEをON/OFFしようとすると変換候補が変なところにういて表示され使いづらいです。
そこで、自宅PC(サーバー)側だけ以下の設定をして、Ctrl-Space キーでもIMEが切り替わるようにしておきます。
出先から AnyDesk 経由で自宅PCを使っているときは、Ctrl-Space でIMEを切り替えると入力欄の中で漢字変換できます。

※ Windows Ctrl + Space キーでMicrosoft IMEの漢字入力のON/OFF を切り替えたい
https://www.ipentec.com/document/windows-switch-microsogt-ime-using-ctrl-and-space-key
AWS Distro for Open Telemetryの超詳細解説

# はじめに
この記事はDevOps on AWS大全の一部です。
DevOps on AWS大全の一覧は[こちら](https://qiita.com/tech4anyone/items/b06f88035d27c6ef13b2)。

この記事ではAWS Distro for Open Telemetryに関連する内容を超詳細にまとめています。

具体的には以下流れで説明します。

- AWS Distro for Open Telemetryとは
- AWS Distro for Open Telemetryの活用
- AWS Distro for Open Telemetryのベストプラクティス

AWSの区分でいう「Level 200：トピックの入門知識を持っていることを前提に、ベストプラクティス、サービス機能を解説するレベル」の内容です。

# この記事を読んでほしい人
- AWS Distro for Open Telemetryがどういうサービスか説明できるようになりたい人
- AWS Distro for Open Telemetryを採用するときのベストプラクティスを説明できるようになりたい人
- AWS Certified DevOps Engineer Professionalを目指している人

## AWS Distro for Open Telemetryとは
AWS Distro for Open Telemetryは、AWSが提供するオープンソースの分散トレーシングフレームワークです。
これは、アプリケーションのパフォーマンスを監視し、問題を診断するためのツールを提供します。

なお、Open Telemetryは、メトリクス、トレース、ログなどのテレメトリーデータを収集し、分析するためのAPI、ライブラリ、エージェントを提供するオープンソースプロジェクトです。

AWSのサービスでいうとX-Rayと被る部分が多いのがAWS Distro for Open Telemetryです。
X-RayとAWS Distro for Open Telemetryのどちらを選んだほうが良いのか、という話はEKSとECSのどちらを選んだほうが良いか、という観点と同じです。

X-Rayを採用すればAWSの各種サービスと統合しやすい代わりにAWS Distro for Open Telemetryと比べるとやや柔軟性に欠ける部分があります。

一方、AWS Distro for Open Telemetryを採用すればX-Rayと比較して設定がやや複雑になりやすいですが、その分、やりたいことをやれる可能性が高まります。
また、オープンソースベースのため、マルチクラウドで展開している場合にはAWS以外のクラウドサービスへの展開が良い鵜になります。

## AWS Distro for Open Telemetryの活用
AWS Distro for Open Telemetryは、以下のようなシナリオで活用できます

- パフォーマンス監視
アプリケーションのパフォーマンスをリアルタイムで監視し、問題を迅速に特定できます。これにより、ユーザーエクスペリエンスを向上させることができます。

- 問題診断
トレーシングデータを使用して、問題の原因を特定し、解決策を見つけることができます。これにより、開発者は問題の根本原因を迅速に特定し、修正することができます。

- コスト最適化
リソースの使用状況を理解し、コストを最適化することができます。これにより、企業はITコストを削減し、ビジネスの効率を向上させることができます。

また、AWS Distro for Open TelemetryはAWSの監視系サービスと統合することができます。

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

具体的には、AWS Distro for Open Telemetryで収集したメトリクスやデータをX-RayやCloudWatchに送信することが可能です。
これにより、AWS Distro for Open Telemetryで収取したメトリクスやデータをもとにAWSのサービスを用いたイベント駆動なアーキテクチャが実現可能になります。

## AWS Distro for Open Telemetryのベストプラクティス
AWS Distro for Open Telemetryを最大限に活用するためのベストプラクティスは以下の通りです。

| ベストプラクティス | 説明 |
| --- | --- |
| 適切なサンプリング率を設定する | トレーシングデータは大量に生成される可能性があるため、必要な情報を取得しつつ、コストやパフォーマンスに影響を与えないようにサンプリング率を調整することが重要です。 |
| 適切なタグや属性を付与する | トレーシングデータには、リクエストやレスポンスの詳細だけでなく、サービス名やバージョンなどのタグや属性を付与することで、分析やフィルタリングが容易になります。 |
| 適切なエクスポーターを選択する | AWS Distro for Open Telemetryは、複数のエクスポーターをサポートしており、それぞれにメリットやデメリットがあります。例えば、OTLPエクスポーターは、Open Telemetry Protocolに基づいてデータを送信するため、高速で効率的ですが、セキュリティや可用性の面で課題があります。一方、X-Rayエクスポーターは、X-Ray Daemonを介してデータを送信するため、セキュリティや可用性が高いですが、パフォーマンスや柔軟性の面で劣ります。自分のニーズに合わせて最適なエクスポーターを選択することが重要です。 |


# まとめ
この記事ではAWS Distro for Open Telemetryに関連する内容を超詳細にまとめました。

- AWS Distro for Open Telemetryとは
- AWS Distro for Open Telemetryの活用
- AWS Distro for Open Telemetryのベストプラクティス

次回からはセキュリティとコンプライアンスについて詳細にまとめていきます。
【UEFN】スタティックメッシュのメモリ容量を早急に減らしてみる

## 背景
あるプロジェクトでメモリ容量が100000を少し超えて早急に対応しなければならない状況でした。同じメッシュののものをたくさん複製していたのでメッシュの軽量化をすればすぐに対応できそうだということで調べ始めました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692976/333a424b-3c7d-fa67-2c11-7c29bfaba6e7.png)

## 軽量化ポイント
- ポリゴン数減らす
- 頂点数を減らす

https://creator.cluster.mu/2023/01/11/blender-3dweight/

## 軽量化をやった結果
**頂点数やポリゴン数を2000程減らすことに成功しました**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692976/ad416a42-3797-1cf0-3260-7479f44cf6bb.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692976/feb20496-ffd0-22e3-1fa7-fcac1e0f1e2b.png)

**メモリに関しては1678から1603まで減らすことができました**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692976/10b3fc03-870e-a36e-3579-fa68772562c6.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692976/74c7d56c-a884-23af-20e7-cddf964054a6.png)


## やり方
コンテンツドロワーから指定のスタティックメッシュをダブルクリックして以下のような設定項目を開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692976/797b534c-4379-29c6-c6c1-42fbe72e9fc9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692976/7172c892-67bd-7f8c-00c1-dc4fd1b92972.png)

設定を以下のように変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692976/07af5c01-4f5b-901c-7d3c-8f76a2cc16f7.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692976/1c4f8ab5-9927-a3ac-0a22-dbdc1a92ff6c.png)

:::note warn
警告
かなりメッシュの解像度が下がるので少しずつ精度を落とすことをお勧めします。
:::

## まとめ
今回の方法に関してはかなり解像度が下がるのでローポリ系プロジェクト専用技となっています。今回の方法のほかにもマテリアルの設定を減らすことなども効果があるみたいです。深ぼっていくことでより大きなプロジェクトができそうだと感じました。

がんばっていきましょー

## 余談
この度UEFN/Verseに関するオープンコミュニティサーバーを建ち上げました。ちょっとでも興味があれば奮ってご参加くださいませ。

https://discord.gg/MehcNhyxdq
自衛官からエンジニアへ Elixirから始める Web開発 Part14

この記事は「Elixir Advent Calendar 2023」14日目の記事です
東京にいるけどfukuokaexのYOSUKEです。

普段は 合同会社TheWaggle で教材開発・システム開発・研修講師などマルチに活動してます。

このシリーズでは、文系ですらない、体育会系でも始められるプログラミング学習　というテーマで元自衛官だった僕が
自衛官からエンジニアになってもらいたいという気持ちを込めて、普段は大人しいですが、このコラムシリーズでは、あえて、体育会系のノリで、貴様ら理屈で覚えるなら体で覚えろ！というノリで書いてみたいと思います。

なので、初学者向けですが、理論は後回し、まずは動かして体感しろってノリの第14回目です。

それでは、いくぞ！

## パイプ演算子による関数の連鎖

よーし、貴様ら今回は[前回](https://qiita.com/Yoosuke/items/4f128cb7ef5c8ac6d693)の続きだ、

```elixir
Enum.map([{1,2}, {3,4}], &Tuple.to_list(&1))
[[1,2],[3,4]]
```

Enum.mapの2番目の要素には```fun```を入れるとあって、それは```関数```のことだと言ったな、そして、それであれば```Tuple.to_list()```も使えると教えたはずだ。

ただし、よーく見ると```&Tuple.to_list(&1)```とあって、この```&```は```キャプチャ演算子```と行って、`&`を置いた右側を```関数化```してくれる便利な道具だという話しをした。```&1```は関数を使う時に値を入れる入り口になる役割をになっている。この関数に値を渡す入り口の事を```引数```という。

そして、```&```は、ちょっとした仕事をさせたい時、```変数```に入れて使う事ができる。というのが前回教えた事のまとめだ。例えば、田中に仕事をさせる様を変数```tanaka```とした場合、数値を渡したら２倍にする仕事を頼む様子を以下のように表現できる。

```elixir
tanaka = & &1*2
tanaka.(2)
4
```

また、前回は鈴木に数字を渡したら、-1する仕事も頼んだ

```elixir
suzuki = & &1-1
suzuki.(2)
1
```

ここまでが前回にやった事だ、そして、今日は貴様らに頼んだ仕事を連携するやり方を教えてやろう。
例えば、tanakaに頼んだ仕事をしたのち、鈴木に仕事を頼み、渡した数字を２倍したあと、-1する事をお願いした場合だ。

```elixir
suzuki.(tanaka.(2))
3
```

さて、このように```引数```に直接、tanakaを入れても良いのだが、これだと順番がわかりづらいな。間違えて逆にしてしまうと結果がまるで変わってしまう。

```elixir
tanaka.(suzuki.(2))
2
```

このように本来、３という結果を期待してるのに、順番が変わるだけで違う結果が返ってきてしまう。
この呼び方は少々、順番がわかりづらい！

そこで、貴様らでも命令の順番がわかりやすいように今日は、```関数```に仕事をさせる上で命令の呼び出し順をわかりやすくする書き方を教えてやろう！

そこで使うのが```|>```これだ```パイプ演算子```という。こいつを使って、tanakaとsuzukiの命令順が明確になる。

```elixir
tanaka.(2) |> suzuki.()
3
```

これは、tanakaに先に仕事をさせ、２を渡して２倍にする、そしてその後にsuzukiにtanakaが仕事をした結果の値をそのまま渡して使えという事で```suzuki.()```の`()`の中は空のままでいい事になっている。

もし、suzukiに２つの引数を入れるような仕事を与えた場合はどうなるかも見せてやろう。

```elixir
suzuki = & &1 - &2
suzuki.(2,1)
1
```

このように最初の引数の値を２つ目の引数で引く仕事とした場合だ。この場合、tanakaとの連携は以下のように命令すれば良い。

```elixir
tanaka.(2) |> suzuki.(1)
3
```

このように、一つ目の引数は、tanakaから渡ってくるから、2つ目の引数の数値をsuzukiに渡せば良い。

何？頭がこんがらがってきただと！
貴様らのような奴は自分で必ず体験しろと言っただろう！何をボーッと説明を聞いてるんだ。

自分たちでも手を動かして、色々と数字を入れたりさせたい仕事を変えてみたりして試すんだ！
何？ 実際にやったら変なのが出るだと？

```elixir
tanaka = & &1*2
#Function<42.125776118/1 in :erl_eval.expr/6>
```

```#Function<42.125776118/1 in :erl_eval.expr/6>```これは、田中、貴様には認識番号があるな？
もし、戦場で死亡しても認識番号が書いてあるタグを仲間が持って帰れば貴様が戦場で倒れた事が明確になる。

```#Function<42.125776118/1 in :erl_eval.expr/6>```これは、貴様にこの仕事を頼んだことが明確になるようにプログラム側が認識するための認識番号のようなものだ。今のところ、貴様らがあまり気にする必要はない！

気にせず、試せ！わかったな。

よし、ではいよいよ、この仕事```&Tuple.to_list(&1)```を```|>```を使ってわかりやすく紐　とくとこうなる。

```elixir
& &1 |> Tuple.to_list()
```

では、実際に動かしてみよう。

```elixir
Enum.map([{1,2}, {3,4}], & &1 |> Tuple.to_list())
[[1, 2], [3, 4]]
```

そして、 ```& &1```は何をしてるか、さらに次の命令をtakahashiにやってもらおう。

```elixir
takahashi = & &1
takahashi.(1)
1
```

これは、```&```関数化する道具だが、右側には特に何もなく、```&1```で入り口を作ってるだけ。よって、値をそのまま引き渡す役割を担っているわけだ。

要するに、あらかじめ用意されている関数に値を引き渡す役割を```&Tuple.to_list(&1)```このような命令書いてたわけだ。

つまり、```& &1 |> Tuple.to_list()```関数にただただ、値を引き渡しているだけってことだな。

よし、今日はここまで、それでは次回 Part15でまた会おう！
AtCoder Beginners SelectionをGoで解いてみた（後半）

[**前半記事**](https://qiita.com/rapirapi/items/75ff6d4ff5fd9a6a8d4b)の続きから解いていく


### ABC085B	Kagami Mochi
https://atcoder.jp/contests/abs/tasks/abc085_b

ソートした後に前から要素を見て今まで見たどの要素より大きい値が取れたら、カウントする

#### ACコード
```go
package main

import (
	"fmt"
	"sort"
)

func main() {
	var n int
	fmt.Scan(&n)
	d := make([]int, n)
	for i := 0; i < n; i++ {
		fmt.Scan(&d[i])
	}
	sort.Ints(d)
	ans := 0
	work := 0
	for _, num := range d {
		if num > work {
			work = num
			ans += 1
		}
	}
	fmt.Println(ans)
}

```


### ABC085C	Otoshidama
https://atcoder.jp/contests/abs/tasks/abc085_c

2種類のお札の数を定めるともう1種類のお札の数が定まるので、2種類のお札の数で全探索する

#### ACコード
```go
package main

import (
	"fmt"
)

func main() {
	var n, y int
	fmt.Scan(&n, &y)
	for i := 0; i <= n; i++ {
		for j := 0; j <= n-i; j++ {
			if 10000*i+5000*j+1000*(n-i-j) == y {
				fmt.Println(i, j, n-i-j)
				return
			}
		}
	}
	fmt.Println(-1, -1, -1)
}

```
### ABC049C	白昼夢
https://atcoder.jp/contests/abs/tasks/arc065_a

追加する文字列を末尾から見ると解ける。  
`strings.HasSuffix`で指定された文字列が特定のサフィックスで終わっているかどうかを判定することができる。

#### ACコード
```go
package main

import (
	"fmt"
	"strings"
)

func main() {
	var S string
	fmt.Scan(&S)

	words := []string{"dream", "dreamer", "erase", "eraser"}

	for len(S) > 0 {
		found := false
		for _, word := range words {
			if strings.HasSuffix(S, word) {
				S = S[:len(S)-len(word)]
				found = true
				break
			}
		}
		if !found {
			fmt.Println("NO")
			return
		}
	}
	fmt.Println("YES")
}

```
### ABC086C	Traveling
https://atcoder.jp/contests/abs/tasks/arc089_a

`math.Abs`で絶対値を計算できる。`float64`でしかけいさんできないので、型変換が必要になる。


#### ACコード
```go
package main

import (
	"fmt"
	"math"
)

func main() {
	var N int
	fmt.Scan(&N)

	var t, x, y int
	var prevT, prevX, prevY int

	for i := 0; i < N; i++ {
		fmt.Scan(&t, &x, &y)

		distance := math.Abs(float64(x-prevX)) + math.Abs(float64(y-prevY))
		time := t - prevT

		if int(distance) > time || (time-int(distance))%2 != 0 {
			fmt.Println("No")
			return
		}

		prevT, prevX, prevY = t, x, y
	}

	fmt.Println("Yes")
}

```

## おわりに
AtCoderの問題を解くことで、新しいパッケージや関数を知ることができた。
今後も新しい言語を学ぶときにAtCoderを活用していこうと思う。