OmniAICreator/Qiita-1.07M huggingface dataset:
ローカル環境のMySQLにAWSAuroraのDBデータをインポートする方法

タイトルの内容を作業する際にイメージできていなかったので、備忘録として残します。

## この記事で分かること

- **DB(MySQL)のインポート、エクスポート方法**
- **AWSへのssh方法(ローカル環境→踏み台サーバー接続→本番環境サーバー接続)**
- **AWSのDBデータをローカルにコピー(インポート)する方法**

行きましょう！

## DB(MySQL)のインポート、エクスポート方法

### エクスポート

```bash
$ mysqldump -u migration_user -p --set-gtid-purged=OFF --no-tablespaces -R -h hoge-aurora.cluster-ro-fuga.ap-northeast-1.rds.amazonaws.com hogefuga > hoge.sql
```
ホスト名はamazon-aurora。
データベース名はhogefuga。
これらをhoge.sqlというファイル名でエクスポートします。

オプションの意味は以下の通りです。
mysqldump:DBのバックアップコマンド(「ダンプ」と呼ばれます)

-u : ユーザー名
-p : パスワード指定ログイン
-R(—routines) : [ストアドプロシージャ](https://atmarkit.itmedia.co.jp/ait/articles/0710/29/news118.html#:~:text=%E3%81%A6%E3%81%84%E3%81%8D%E3%81%BE%E3%81%97%E3%82%87%E3%81%86%E3%80%82-,%E3%82%B9%E3%83%88%E3%82%A2%E3%83%89%E3%83%97%E3%83%AD%E3%82%B7%E3%83%BC%E3%82%B8%E3%83%A3%E3%81%A8%E3%81%AF,%EF%BC%88STORED%EF%BC%89%E3%81%97%E3%81%9F%E3%82%82%E3%81%AE%E3%81%A7%E3%81%99%E3%80%82)・[CREATE FUNCTION](https://www.postgresql.jp/document/9.4/html/sql-createfunction.html)、トリガーをダンプに含めるオプション
-h : ホスト名

--set-gtid-purged : @@GLOBAL.gtid_purgedステートメントを出力に追加するかを指定し、GTID情報を制御します。GTIDは、マスターで作成され、コミットされた各トランザクションに関連づけられる一位識別子です。つまり、ダンプファイルに書き込まれる位置識別子を追加するか否かということ。今回はローカル環境にインポートするため、他の環境に持ち出した時にGTIDが悪さをするリスクを排除するためにOFFに設定しています。

—no-tablespaces : CREATE LOGFILE GROUP ステートメントおよび CREATE TABLESPACE ステートメントを出力に書き出さない。tablespacesはDB側で作成されるファイルを任意に指定できる機能。ちゃんと理解していませんが、このオプションがないことによって、権限関係のエラーが発生する記事がたくさんありました。テーブルスペース情報が不要ならば-no-tablespacesを記述しておくのが良いと思います。

### インポート

```bash
# DB名hogefugaにhoge.sqlのデータを投入
$ mysql -u root -p hogefuga < hoge.sql
```

インポートはシンプルですが、hoge.sqlが存在するディレクトリに移動していないと実行エラーが発生します。別ディレクトリの場合は正しいPATHをしていしてください。

## AWSへのssh方法(ローカル環境→踏み台サーバー接続→本番環境サーバー接続)

基本的なコマンドですが、よく忘れて調べるので、、、

```bash
# ssi -i 秘密鍵ファイル ユーザー名@IPアドレス
$ ssh -i ~/.ssh/hoge.pem fuga@〇〇.〇〇.〇〇.〇〇

 __|  __|_  )
 _|  (     /   Amazon Linux 2 AMI
___|\___|___|

# ssh権限ユーザに切り替え
$ sudo su fuga
# 秘密鍵不要
$ ssh fuga@〇〇.〇〇.〇〇.〇〇

 __|  __|  __|
 _|  (   \__ \   Amazon Linux 2 (ECS Optimized)
____|\___|____/

# ここでmysqldumpを実行する
```

## AWSのDBデータをローカルにコピー(インポート)する方法

### 手順

①踏み台サーバーから本番環境にscpコマンドでdumpファイルを取り込む

②ローカル環境から踏み台サーバーにscpコマンドでdumpファイルを取り込む

③ローカル環境で自分のMySQLにファイルをインポート

順番にやっていきましょう。

### ①踏み台サーバーから本番環境にscpコマンドでdumpファイルを取り込む

```bash
# scp ユーザー名@IPアドレス:dumpファイルの階層 踏み台サーバーでのファイル保存場所
$ scp fuga@〇〇.〇〇.〇〇.〇〇:/path/to/hoge.sql /tmp/hoge.sql
```

すごく初歩的ですが、/tmp/は一時保存用のディレクトリです。
基本的には誰でも「読み書き」可能で、ファイルを一時保存する際には便利なディレクトリです。

### ②ローカル環境から踏み台サーバーにscpコマンドでdumpファイルを取り込む

①と同じ要領です。

```bash
scp -i ~/.ssh/hoge.pem hogehoge@IPアドレス /tmp/hoge.sql ~/Download/hoge.sql
```

これで、ローカル環境にDBデータを持ってこれました。

### ③ローカル環境で自分のMySQLにファイルをインポート

先ほど紹介したコマンドで実行

```bash
# DB名hogefugaにhoge.sqlのデータを投入
$ mysql -u root -p hogefuga < hoge.sql
```

これで完了です。

AWSのDBをローカルにインポートする方法について書かれた記事があまりなかったので少し苦戦しました。

環境構築系は幅広い知識が必要なので非常に勉強になりますが、大変ですね。
[FastAPI] 知っておくと超便利！！！ミドルウェアを使用したエラーハンドリング

# この記事を読んでできること
- エラーハンドリングができる
- 同じような例外処理を各APIに書かなくても済む（可読性・保守性の向上）
# 概要
StarletteのBaseHTTPMiddlewareを使用して共通した複数の例外処理の機能を受け持つようにする
# 記述しないこと
- FastAPIについて
- 例外処理について
# 使用技術
- Python 3.10.4
- fastapi 0.78.0
- Starlette  0.19.1

# ミドルウェアの処理の流れ
1. アプリケーションに届いたリクエストをミドルウェアが受け取る
1. そのリクエストに対して何らかのコードを実行する
1. アプリケーションの残りの部分にリクエストを渡して (path operation によって) 処理させる
1. ミドルウェアはアプリケーション (の path operation) によって生成されたレスポンスを受け取る
1. そのレスポンスに対して何らかのコードを実行する
1. レスポンスを返す
# 実装例
```main.py
from fastapi import FastAPI
from middleware import ErrorHandlingMiddleware


app = FastAPI()

app.add_middleware(ErrorHandlingMiddleware)
```
アプリケーションにミドルウェアを呼び込むには`app.add_middleware()`を追記する

```error.py
class InvalidInputError(Exception):
    """APIにて受付番号が発行されなかった場合のカスタムエラー"""

    pass
```
自作エラーの設定

```middleware.py
from fastapi import Request, Response, status
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware

from error import InvalidInputError


class ErrorHandlingMiddleware(BaseHTTPMiddleware):
    """エラーハンドリングをするミドルウェア
    API内で発生したエラーをキャッチして処理を施す
    Args:
        BaseHTTPMiddleware : リクエスト/レスポンスインタフェースに対するASGIミドルウェアを記述するための抽象クラス
    """

    async def dispatch(self, request: Request, call_next) -> Response:
        try:
            response: Response = await call_next(request)

        except InvalidInputError as e:
            response = JSONResponse(
                {"msg": "InvalidInputError:受付番号が発行されませんでした。送信内容をもう一度確認してください。"},
                status.HTTP_500_INTERNAL_SERVER_ERROR,
            )
        except TypeError as e:
            response = JSONResponse(
                {"msg": "TypeError:内容を確認してもう一度データ挿入をしてください。"},
                status.HTTP_404_NOT_FOUND,
            )
        except TimeoutError as e:
            response = JSONResponse(
                {"msg": "TimeoutError:タイムアウトエラーが発生しました。"},
                status.HTTP_408_REQUEST_TIMEOUT,
            )
        except RuntimeError as e:
            response = JSONResponse(
                {"msg": "RuntimeError:ランタイムエラーが発生しました。"},
                status.HTTP_500_INTERNAL_SERVER_ERROR,
            )
        except Exception as e:
            response = JSONResponse(
                {"msg": "Exception:基底クラスエラーが発生しました。"},
                status.HTTP_500_INTERNAL_SERVER_ERROR,
            )
        return response
```
- APIで発生したエラーは最終的にこのミドルウェアでキャッチしてエラーメッセージを返すことができる
- 自作エラーも使用することができる
- エラー以外にも共通する処理であればなんでもできる
# まとめ
ミドルウェアってすごい便利だね
# 参考
- [ミドルウェア 公式ドキュメント](https://fastapi.tiangolo.com/ja/tutorial/middleware/)
- [Handling Erros 公式ドキュメント](https://fastapi.tiangolo.com/ja/tutorial/handling-errors/)
- [Advanced Middleware 公式ドキュメント ](https://fastapi.tiangolo.com/ja/advanced/middleware/?h=middle)
- [Web サービスを開発するときのエラーハンドリングについて](https://zenn.dev/ryamakuchi/articles/111aa3f125e507#api-%E3%81%8B%E3%82%89%E8%BF%94%E3%81%A3%E3%81%A6%E3%81%8F%E3%82%8B%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9%E3%82%A8%E3%83%A9%E3%83%BC)
GhostBSDのデータ救出法 - もしくは、痛い目に会って学ぶzfs

# 前提
GhostBSD（もちろんFreeBSDでもいいけど）でファイルシステムzfsにしているが、何らかの理由でGhostBSDがまともに起動しなくなってしまったので、zfs対応のNomadBSDをUSBメモリから起動して、GhostBSDからデータを救出するぞ、です。そんな人がどれだけいるか知りませんけど。（あ、でも、以下に書いてある話は、zfsであればOSに依存しない（はずの）話なので、ファイルシステムがzfsな人には役に立つかも。もちろん、自己責任でお願いしますが。）
あと、zfsは暗号化が可能だったような気がしますけど、自宅のデスクトップパソコンにそこまでは、、、ということで暗号化はしてません（、のはず）。

# やったこと
GhostBSDがまともに起動しなくなってしまったパソコンのUSBにNomadBSDがインストールされたUSBメモリを差し込んで、NomadBSDを起動、と言うのは当たり前ですね。
次に、とにかく
~~~
sudo zpool import
~~~
です。sudoという強い権限で何かをimportしそうなので、かなりドキドキしますが、これは以下のようにimport可能なものを表示してくれるだけです。
~~~
   pool: zroot
     id: xxxxxxxxxxxxxxx
  state: ONLINE
 action: The pool can be imported using its name or numeric identifier.
 config:

	zroot       ONLINE
	  ada0p10   ONLINE
~~~
zrootという名前のpoolがあることが分かります。（idに表示されているxxxxxxxxxxxxxxxでも行けるのかもしれませんが、試したことはありません。）
いきなりsudoは怖いよね、ということでsudoをつけないで
~~~
zpool import
~~~
だけだと
~~~
cannot discover pools: permission denied
~~~
と権限が足りなくて怒られます。まあ、ディスク（厳密には「ストレージ」と呼ぶべきでしょうか）のメタな情報を見るわけですからそうなりますよね。
actionに書いてあるように、名前を指定して再度挑戦です。
~~~
sudo zpool import -R /mnt zroot
~~~
その結果は
~~~
cannot import 'zroot': pool was previously in use from another system.
Last accessed by <unknown> (hostid=0) at Tue MMM dd hh:mm:ss yyyy
The pool can be imported, use 'zpool import -f' to import the pool.
~~~
よそのシステムで使われていたものっぽいけど大丈夫か、と聞いてきているようです。
GhostBSDで使っていたシステムですから、こうなるのは当然ですね。
強制的にimportすべく、最後の行にあるように"-f"を付けてやってみましょう。
~~~
sudo zpool import -R /mnt -f zroot
~~~
何も表示されませんでした。成功した模様です。
/mntの下を確認してみましょう。
~~~
nomad@NomadBSD$ ls /mnt/usr/home/koizumi/Pictures/
usagi_mod_pal.xcf
usagi-f.xcf
usagi.png
スクリーンショット_2022-12-11_08-33-33.png
~~~
あ、見えました。年賀状のためにウサギの画像を何とかしようとして苦労した記録が、、、
ここまで行けば/mnt/usr/home/koizumiがGhostBSDでのホームディレクトリですから、必要なデータだけ取り出すでも、全部バックアップするもやりたい放題（のはず。実はまだやってません:sweat_smile:[^done]）。

# なぜ"-R /mnt"か
"-R /mnt"なしの
~~~
sudo zpool import -f zroot
~~~
でもマウントには成功します。が、デフォルトでは/（ルート）にマウントしてくれます。ということはNomadBSDの/以下がごっそりGhostBSDの/に置き換わるわけで、NomadBSDとしては大混乱です。たとえばアイコンの情報とかもおかしくなるらしく、徐々に画面が崩れていくというホラーみたいな状況になります。（と、言い切らせてもらいます。はい、実際に体験しましたので。）
ということで、"-R /mnt"を付けることで、GhostBSDのディスクの内容が/mnt以下に来るようにしてNomadBSDの/が破壊されないようにしています。

[^done]: この記事を書いた後のことにはなりますが、ここに書いた方法でGhostBSDのデータを退避してGhostBSDを再インストールしました。が、その時はGhostBSDのGUIが起動しなかっただけだったので、わざわざNomadBSDを持ち出すまでもなくGhostBSD上でデータを逃がせば良かったような、、、
草莽Erlang ── 32. lists:flatlength


口で言うより行うことがErlang習得への近道と信じています。

https://qiita.com/mnishiguchi/items/9237780e849d80a85e11

## lists:flatlength/1

入れ子になったリストを平坦化した場合の要素数を数えます。結果は[lists:flatten/1](https://www.erlang.org/doc/man/lists.html#flatten-1)と[length/1](https://www.erlang.org/doc/man/erlang.html#length-1)を別個に実施した場合と同じですが、[lists:flatlength/1](https://www.erlang.org/doc/man/lists.html#flatlength-1)を使った方が効率良く処理されるそうです。

https://www.erlang.org/doc/man/lists.html#flatlength-1

```erlang
> L1 = [1, [[2], 3]].

> length(L1).
2

> lists:flatlength(L1).
3

> length(lists:flatten(L1)).
3
```

[listsモジュール](https://www.erlang.org/doc/man/lists.html)には他にもリスト処理のための関数がたくさんあります。

## Elixirにも挑戦したい

闘魂ElixirシリーズとElixir Schoolがオススメです。

https://qiita.com/torifukukaiou/items/3b65e5c04fa8c55f526e

https://elixirschool.com/ja

https://qiita.com/piacerex/items/09876caa1e17169ec5e1
Javascript 比較仕様 備忘録。


https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Less_than

両者が文字列の場合は、Unicode値による比較。

    文字列 文字列  ＝＞  Unicode値 Unnicode値

両者が文字列でない場合は、非数値型を数値に変換し比較。

    ＜ 変換仕様 ＞

    true -> 1

    false -> 0
    
    null -> 0

    "数値" -> 数値  （ "5" -> 5 ）

    "数値でない文字列" -> NaN  （ "p5" -> NaN ）

    undefined -> NaN


**いずれかの値が NaN の場合、演算子は false を返す。**

片方がBigInt型の場合も比較可能。

    "5" < 7n  ＝＞  true
     5n < 3   ＝＞  false
SQLは新人エンジニアが調べても分からない落とし穴

### はじめに

当記事は駆け出しエンジニアへ向けた記事となります。
つよつよエンジニアの方は是非迷えるエンジニアの救いの手になってくださるよう
記事への補足を頂けますようお願いします。

# 調べたSQLがエラーを起こしてしまう話

まず実行したいSQLがあった場合、何を調べましたか？調べた結果は何でしたか？
テーブルを作成したいときには以下を調べたのではないでしょうか。
➀「SQL テーブル 作成」 ➁「SQL create table」

上記でGoogle検索をすると以下が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822365/297cc8fc-7469-9e74-dc51-3e0d00060bd1.png)

# SQLの落とし穴

残念ながら、先に記述しましたSQLを用いてSQLを書いて実行しても期待通りに動かない場合があります。以下がこれからSQLを書き始める駆け出しエンジニアに伝えたい事実です。

__SQLはサーバーによって書き方が変わります。__

具体的には、指定できるデータ型や制約の指定方法が変わります。
例）SQL Serverでは数値データ型はINTを使用しますが、OracleではNUMBERです。

ここで試しに「Oracle テーブル 作り方」で調べてみましょう。

私たちが求めた結果が帰ってくるのではないでしょうか。

# 失敗しないためには

SQLに限った話で言えば、使用している環境(DB)をまずは知ってほしいです。
さらにSQLは書き直しはあまりされません。先輩からSQLを貰ってもうまくいかない場合は、何か環境に変化はなかったか。いつごろ行ったSQLなのか聞いてみましょう。

### 最後に

駆け出しエンジニアから脱却するために身に着けたい基本的な知識を伝えます。

- データモデリング
-> 自分の担当機能がシステム内でどこに位置しているか知ることで書くべき実装が見えてきます。
- デザインパターン
-> 一人で開発はできません。デザインパターンはエンジニアの共通認識です。
- ネットワークエンジニアリング
-> 自分の実装がどのような起動経路で行われているのか描けるとデバッグスピードに繋がります。
コントロールを理解する

キャンバスアプリのコントロールについて自分のための備忘録として残します。少しずつ更新していく予定です。

https://docs.microsoft.com/ja-jp/learn/modules/controls-canvas-apps/

# コントロールに関連するデータの型
https://hobby-compass.com/powerapps%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E7%A8%AE%E9%A1%9E%E3%82%92%E7%9F%A5%E3%82%89%E3%81%AA%E3%81%84%E3%81%A8powerapps%E3%81%AF%E3%82%8F%E3%81%8B%E3%82%89%E3%81%AA%E3%81%84/

# 画面について
## 表示モード
 DisabledにするとScreen配下のコントロールは選択できません。コントロールのカラーがグレー表示になります。
また、コントロールを疑似的にクリックする(任意のコントロールのOnSelectプロパティ下の式を実行する)[Select関数](https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-select)は、複数の画面で使用することができません。

# 入力系
## ドロップダウン

https://sinyblog.com/powerapps/dropdown-001/

## コンボボックス
- 既定値設定のプロパティはDefaultプロパティではなくDefaultSelectedItemsプロパティです。
なお、DefaultSelectedItemsプロパティは式を入れても意図した動作をしません。

## DatePicker
- 表示形式はFormatプロパティで変更
    -  dateTimeFormat列挙体の他、テキストで指定することもできます。
▽テキストで指定した場合▽
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218676/1cb41e19-b485-c8e1-35e9-297b126897dc.png)

## Timerコントロール
| プロパティ名 |  |
| --- | --- |
| Value | 現在の値をミリ秒単位で取得 |
| Duration | タイマーの長さをミリ秒単位で取得 **※1000=1秒** |

👇触ってみる👇

https://tech-blog.cloud-config.jp/2019-11-18-powerapps-timer/

## HTMLテキスト
- ハイパーリンク化したURL文字列を埋め込む際などに便利です。

https://docs.microsoft.com/ja-jp/powerapps/maker/canvas-apps/controls/control-html-text

# ペン入力
https://www.si-jirei.jp/2019/04/30/powerapps%e3%82%b3%e3%83%a9%e3%83%a0-3/

# 一覧画面の作成(ギャラリーとデータテーブル)
## ギャラリー
データソースにあるデータを一覧にして表示させてくれるコントロールです。
Itemプロパティに任意のデータソースを設定します。
Itemプロパティに設定するデータソースはFilter関数などで取得行数を絞り込むこともできますが、注意点があります。詳細は別記事にまとめてあります。

https://qiita.com/fsgwmhr/items/7f1e60308779f77e3446

https://sinyblog.com/powerapps/gallery_change_color/

## データテーブル
いつの間にかプレビュー機能になっていました。手軽に一覧画面を作成するならこちらのコントロールが良いです。

https://www.kyoukasho.net/entry/powerapps-datatable


# フォーム
https://docs.microsoft.com/ja-jp/learn/modules/write-data/

## データカード
https://docs.microsoft.com/ja-jp/powerapps/maker/canvas-apps/working-with-cards

**注意点**

https://web-breeze.net/no_item_to_display/

### Unsavedプロパティ
このプロパティを使用して、ユーザーが変更を保存していないかどうかをチェックできます。フォームが編集されたのに送信されていない場合は、true です。

# メディアコントロール
https://www.youtube.com/watch?v=sHcQXgqLMT8

# バーコード読み取り

- JANコード読み取りも可能。
- QRコードでハイパーリンクを読み取ってもハイパーリンクとして機能しない。

https://www.youtube.com/watch?v=n8UP2cEA3TQ

連続読み取りは「バーコードスキャナ」コントロールのほかにコレクションやギャラリーを使用します。

https://www.youtube.com/watch?v=cbCQM8UNzxk

# PDF ビューア
https://ippu-biz.com/development/powerplatform/powerapps/pdfviewer/
npmでプロジェクトを作成する


nvmでNode.jsをインストールし、
その後npmでVue.jsプロジェクトを作成した。

## 手順

#### 新しいプロジェクトの作成
latestだけでもOK、コマンド実行後にプロジェクト名、使用するテンプレート、言語を選択する。	
viteはビルドツール。				
```bash							
npm init vite@latest [プロジェクト名] -- --template vue					
```
								
#### 作成したプロジェクトフォルダへ移動
今回はfirst-vue-appという名前のプロジェクトを作成したので、そこに移動する。								
```bash			
cd first-vue-app
```
													
#### Vue.jsを動作させるためのパッケージをインストール
```bash						
npm install	
```												
自動的に色々と作成してくれる。
#### 開発サーバを起動													
```bash
npm run dev													
```
サーバを起動するとポートが出るので、ブラウザでアクセスすれば初期画面が表示される。

```bash
➜  Local:   http://localhost:5173/
```
サーバを止めたい時は`ctrl + c`で止めることができる。
<br>



#### 関連記事

https://qiita.com/suzuki_q/items/2d086b1efa75945b166e
Node.jsの基礎をまとめる1

node.jsとはJavaScriptでサーバーまで作れるよという設計手法のことである。

JacaScriptやReactというのはクライアントサイドをつくるものである。

そして、非同期処理を得意とするため、リアルタイムの処理を得意とする。処理の速さも優秀である。

プロジェクトのディレクトリを作成したら、以下のコードを入力する。

```
npm init -y
```
これを行うとpackage.jsonが作成される。これによって、作成するプロジェクトの依存関係を管理してくれる。

そして、モジュールをインストールするやり方を示す。
httpモジュールをインストールするには以下のように入力する。

```
npm install --save-dev http
```
そうすると、package.jsonのdevDependenciesのところにパッケージが追加されているのが分かる。

![Untitled (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2971002/82832b38-7bf7-7d61-e618-e2bec849cbf7.png)

実際には、httpモジュールは基からインストールされているので、インストールの必要はない。

インストールの際に「--save-dev」オプションを付与することで「package.json」の"devDependencies"に必要な情報を自動的に追記することが出来る。

そして、サーバーを実行させるには、
```
node ファイル名
```
で実行することが出来る。また、実用的なサーバーを実行させる方法は、package.jsonをいじる方法である。

package.jsonのscriptsを以下のように変更する。

```
"scripts": {
    "dev": "node server.js"
  },
```

そうすると、ターミナル上で"scripts"で定めたキーの値を用いて"node server.js"と同じ実行を行うことが出来る。

```
npm run dev
```
そうすると、以下のように実行される。

```
C:\Users\yusuk\node-project\nodejs-tutorial-youtube>npm run dev

> nodejs-tutorial-youtube@1.0.0 dev
> node server.js

nodejs
```

ちなみに、server.js内の記述は"console.log("nodejs");"である。

そして、サーバーでまずやるべきことはインストールしたモジュールを読み取ることである。
ここでは、httpモジュールを読み込む。

```
const http = require("http");
```

requireを使って読み込む。

そして、ここから実際にwebサーバーを作る。
createServerという関数があるのでこれを用いる。そして、今回はアロー関数というものを用いる。

アロー関数を知らなかったので調べてまとめる。

従来の関数式をより簡潔に直感的にした代替構文。使用できる場面は限られている。

```
const materials = [
  'Hydrogen',
  'Helium',
  'Lithium',
  'Beryllium'
];

console.log(materials.map(material => material.length));
// Expected output: Array [8, 6, 7, 9]
```

例ではこちらのコードが使われいていた。

```
> Array [8, 6, 7, 9]
```
出力は上のようになる。

map()関数でリストを展開してそれぞれの要素をmaterialに代入する。そして、それの単語の長さを返すという直感的にわかりやすい構造をしている。

従来の関数とアロー関数を比較する。
```
// 従来の関数
function (a){
  return a + 100;
}

// アロー関数
a => a + 100;
```

アロー関数ではfunctionという定義とreturnは含まれている。

こちらはよく見るやつ

```
// 従来の関数
function (a, b){
  return a + b + 100;
}

// アロー関数
(a, b) => a + b + 100;

// 従来の関数 (引数なし)
let a = 4;
let b = 2;
function (){
  return a + b + 100;
}

// アロー関数 (引数なし)
let a = 4;
let b = 2;
() => a + b + 100;
```
引数が複数になる場合、()で囲う必要がある。
引数の定義が不要なときも()のみの表記が必要になる。

繰り返し処理をしない場合などは直感的でわかりやすいかもしれない。

ということでアロー関数を用いて、

```
const server = http.createServer((req, res) => {
   
});
```

この中にクライアントからのリクエストがあった場合のレスポンスなどを書いていく。
続きはまた明日書く。
エンジニアインターン5日目

今日は残りのlpのテンプレートを完成させ、サイトに適用させることを目標として取り組んだ。徐々に完成に近づいてきた時sqlで日付指定をして、常に最新の情報を更新するような仕組みを追加する案が出た。gitで新しいissueを作り、ブランチを切り替え、コーディングした。(git branch -b 指定するブランチ)を入力することで、新しくブランチを作ると同時に新しく作ったブランチに切り替えてくれる。自分は最新3ヶ月の情報を得たかったため、betweenを使い、現在から3ヶ月前から現在までの値を得て、1番最新の情報を表示するようにした。コーディングが終わったらgitにpull&requestして先輩エンジニアにレビューしてもらい、細かな部分を修正してやっと日付指定の作業が終わった。テスト環境のwordpressに適用させて行く途中にまた新たに修正しなければならないところが出てきた。フィールドの値が文字列が少し違っていて、データベースに引っかからないということだった。フィールドから引っ張ってきた値をreplaceして文字列を変えてデータベースに渡せば解決できた。この作業も日付指定の時と同じ流れで開発した。この作業はif文を使いreplaceやexplodeして適切な値が取得できるようにした。この作業もなんとか終わらすことができたが、今日サイトに適用させるという目標は達成できなかった。原因として自分のコーディング力や思考力がまだ劣っていることも原因であるが、作業を進めて行く中で新たな問題やアイディアが出てきてやることが予想より多くなってしまったことも原因だと考えられる。エンジニアは自分がタスクをこなす中で思わぬ課題や新たなアイディアが出てきて、常に対応し、実装する能力が求められる職業であるということを実感した。そのためには、たくさんコードを書き、いろんなエンジニアと関わっていろんなコードを見て、対応力と創造力を身につける必要があると感じた。今日は先輩エンジニアからも褒められ、とても良い1日になった。
Figmaでトラックパッドの拡大/縮小が効かなくなる事件

### 解決方法
システム設定 > トラックパッド > スクロールとズーム > 拡大/縮小
をoff/on繰り返すと直る。

### 背景
10分に1度くらいこの現象に見舞われる。
Figmaを使うときはバックグラウンドで
```システム設定 > トラックパッド > スクロールとズーム > 拡大/縮小```
を開いておこう。全く根本的解決ではないが備忘録に。
paiza.ioでelixir その179

# 概要
paiza.ioでelixirやってみた。
練習問題やってみた。

# 練習問題
プログラム管理のため、コピペでファイルを作れ。

# 方針
F.save(ファイルネーム)エンターで、ペースト。

# サンプルコード

```
defmodule F do
	def sline(name, data) do
		case IO.gets("") do
		:eof ->
		    IO.inspect(data)
		    File.write(name, data)
			:ok
		line ->
			data = data <> line
			sline(name, data)
		end
	end
	def save(name) do
	    sline(name, "")
	end
end

F.save("F.exs")

{result, 0} = System.cmd("ls", [])
IO.puts result
{result, 0} = System.cmd("cat", ["F.exs"])
IO.puts result


```

# 実行結果

```
"defmodule F do\n\tdef sline(name, data) do\n\t\tcase IO.gets(\"\") do\n\t\t:eof ->\n\t\t    IO.inspect(data)\n\t\t    File.write(name, data)\n\t\t\t:ok\n\t\tline ->\n\t\t\tdata = data <> line\n\t\t\tsline(name, data)\n\t\tend\n\tend\n\tdef save(name) do\n\t    sline(name, \"\")\n\tend\nend\n\n"
exec_command
exec_stderr.txt
exec_stdin.txt
exec_stdout.txt
F.exs
Main.exs
main.tar.gz
runner_mysql
runner_php
run_user

defmodule F do
	def sline(name, data) do
		case IO.gets("") do
		:eof ->
		    IO.inspect(data)
		    File.write(name, data)
			:ok
		line ->
			data = data <> line
			sline(name, data)
		end
	end
	def save(name) do
	    sline(name, "")
	end
end


```

# 成果物

https://paiza.io/projects/hHVEhTDOoPtVXxfnaHAnwg


以上。
【Swift】returnの為だけに改行したくない

# はじめに
何を言ってるのかというと
```swift
guard let url else {
    print("URLが見つかりませんでした")
    return
}
```
guard文を使用するとelseでは必ずreturnを書かないといけません。

しかしreturnを書く為だけに改行をするのはちょっと。。。
って思うのは私だけですか？？

# やりかた
```swift
guard let url else { print("URLが見つかりませんでした"); return }
```

# 解説
`;`で繋げる感じですね

# おわり
これが良いのかどうかはわからないですが、個人的には1行にした方が見やすいと思いました。
クエリパラメータを使用してパラメータを受け渡す

## はじめに
- 今回クエリパラメータを使用してパラメータの受け渡しを行う。
- Controllerでパラメータを受け取り、where句を使ってルート先を変更させる。

## クエリパラメータとは
クエリパラメータとはサーバーに情報をおくるために用意する、URLの文末に渡す値(変数)などのことを言う。(クエリ文字列ともいう)
検索などしたときにURLの?以降についている○○=△△というやつです。

![スクリーンショット 2023-01-19 18.08.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589286/82ecbbaa-0930-b156-06dd-ad75eddb86fb.png)

## 今回やりたいこと
- `choice.blade.php` でクエリパラメータを使いcreateメソッドで受け取る
- `group=○` というクエリパラメータを渡し、その値に応じてcreateメソッドでは反映させるものを変える
- `create.blade.php` で反映させる

### クエリパラメータを使う
クエリパラメータを使うにはフォームを使用し、getでリクエストしてあげる。
特にユーザーに入力してもらう箇所ではないので、hiddenを使い送信してあげる。
※これだけではわからないですが、choice.blade.php でいくつかカードのようなものを提示しており、それらのどれかを選択するような感じなので、あらかじめvalueの値は決まっています。

```choice.blade.php
<form action="{{ url('/trsupportrecords/create') }}" method="get">
    <input type="hidden" name="group" value="A">
    <input class="btn btn-info btn-sm" type="submit" value="選択する">
</form>
```

### Controllerでクエリパラメータを受け取る
今回createメソッドで受け取ったので下記のように記述する
```Controller.php
public function create(Request $request) {
    // クエリパラメータを受け取り$groupに入れる
    $group = $request->group;
    // where句を使いgroupカラムが先程受け取った$groupの値と等しいものをとってきて$trSupportMenusに入れる
    $trSupportMenus = TrSupportMenu::where('group', $group)->get();
    // Viewに返す
    return view('trsupportrecords.create', compact('trSupportMenus'));
}
```

### create.blade.php で使ってあげる
Viewではいつもどおりforeachで。使いたいカラムを書いてあげる。
```
@foreach ($trSupportMenus as $item)
    {{$item->menu}}
    {{$item->min_reps}}
    {{$item->max_reps}}
    {{$item->sets}}
@endforeach
```

### これで良いのか??な点
- クエリパラメータを使う際フォームを使用してhiddenを使ってやってみたがこれが適切かどうか
- aタグだったりでできるようならそちらのほうがセキュリティ的にも良い??
検索画面実装時(ギャラリーコントロール使用時)の注意点

以下の内容はDataverseをデータソースとする場合の挙動についてです。
他のデータソースを使用した場合同現象が発生するのかはまだ検証していないです。

# 取得行数が2000行以上になる場合の注意点
検索機能を実装する場合、<font color="red">関数で取得した結果が**2000行以上**であり</font>かつ<font color="red">ギャラリーコントロールを使用して表示しようとすると</font>正しい表示結果が表示されなくなります。※エラーにもなりません。

このため回避策として、検索機能を実装する場合コレクション機能を使用する必要があります。
また、取得した結果の行数が2000行以上の場合はギャラリーを表示しない、などの仕様の検討も必要です。

:::note info
(2023/03/15 追記)
委任の問題が絡んでいるようです。
:::

https://jpdynamicscrm.github.io/blog/canvasapp/Canvas-app-delegation/


# 複数の検索機能を実装する場合の注意点
- 様々なコントロールのイベントプロパティで同様の処理を何回も呼び出す必要が生じます。
対策としては、非表示のボタンを追加してファンクションのように扱い、トリガーとしたいイベントのプロパティには```select(非表示ボタン)```と記述し、非表示ボタンをクリックさせます。
  - ただし、別の画面からselect関数を実行することはできません。

- 完全一致の検索を行うFilter関数と部分一致検索を行うSearch関数は同時に実行することが不可能です。（動きはしますが、警告文が出ます。）
このため、
   1. 完全一致検索の結果をコレクションに格納
   1. 部分一致の条件に当てはまる行をコレクションから削除する
などの処理をコーディングすることで実装することでができます。

【実装例】検索機能1および検索機能2の条件に該当する行を取得する
```
ClearCollect(
    Collection1,
    ForAll(
        Filter(任意のデータソース下の任意のテーブル,
            列名 = 検索機能1.Value
        ),
    {Collction1の新しい列名1:ThisRecord.元データの列1, Collction1の新しい列名2:ThisRecord.元データの列2, Collction3の新しい列名:ThisRecord.元データの列3})
);

//検索機能コントロール2
If(IsEmpty(Trim(検索機能2.Value))<>true,
    RemoveIf(Collection1, !OR(検索機能2の条件));
);

UpdateContext({NumberRows: CountRows(Collction1)});
```

上記の場合、ギャラリーのItemプロパティには
```
If(NumberRows<2000, Collection1)
```
と記述します。
paizaラーニング レベルアップ問題集 二分探索メニュー JavaScript 太巻きを分けよう (おなかペコペコ)

太巻きを分けよう (おなかペコペコ) (paizaランク A 相当)

https://paiza.jp/works/mondai/binary_search/binary_search__application_step2

# 解説
>切れ目の選び方を工夫したとき、最も短い太巻きの長さを最大でいくつにできるかを答えてください。

とあるので、最も短い太巻きの長さについて、二分探索ができそうです。


最も短い太巻きの長さと、与えられたAの情報から、何か関係式が作れないか考えます。

***

与えられた情報から、太巻きの切れ目ごとの長さを求めます。

ある最も短い太巻きの長さをmidとすると、太巻きを切った長さは、少なくともmid以上でないといけません。

また、midを以上の場合、できるだけmidに近づけたいので、できるだけ短く切ります。
すなわち、mid以上ならすぐに切ります。

太巻きの１つ１つの長さを調べていきます。

midに満たなかったら、切らずに次の太巻き１つと長さを出します。
mid以上ならば、すぐに切ります。

これを繰り返して、最後の切り身を１本として、全部で切り身が何個になったか調べます。

n人で分けないといけないので、nに満たない場合は、もっとmidを短くして(right=midにして)再度調べます。
nを超えたら、midをもっと長くします。left=midとして再度調べます。

答えは整数なので、範囲が１以下になれるまで繰り返せばよいです。すなわち、範囲の両端を右端right,左端leftとすると、right-left<=1です。

# 解答例
```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
//長さ L [cm] の太巻き, n 人で分け, k 個の切れ目
const [L, n, k] = lines[0].split(" ").map(Number);
const A = lines[1].split(" ").map(Number);
//太巻きのそれぞれの長さB
const B = A.map((v, i, arr) => {
  if (i === 0) {
    return v;
  } else {
    return v - arr[i - 1];
  }
});
B.push(L - A[A.length - 1]);

//最も短い太巻きの長さについて二分探索する
let [left, right] = [0, L + 1];//太巻きの長さの範囲
while (right - left > 1) {//範囲が1以下になればよい
  
  let mid = (left + right) / 2;
  //長さがx以上ならy<=xの全てのyについても成り立つので、left=mid
  //Aから、midの入った関係式を導く
  let tmp = 0;//一時的な長さ
  let num = 0;//太巻きの本数
  //最短を求めるので１本ができるだけ短くなるようにする
  for (let j = 0; j <= k; j++) {
    tmp += B[j];//加えて検討する
    if (tmp >= mid) { //もし最低限の長さをクリアしていたら
      num += 1;//そこでカットして１本に
      tmp = 0;//一旦リセット
    }
    //最後まで行ったら残りを１本に
    if (j === k) num += 1;
  }

  //切った本数がnより多かったら、最長の長さはもっと長い
  if (num > n) {
    left = mid;
  //切った本数がn以下なら、最長の長さはもっと短い
  } else {
    right = mid;
  }
 
}
console.log(left);
```

# 解答例(Python3の場合参考)
答えは整数であることがわかっているので、left と right の差が 1 以下になるまで狭めればよいです。
```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
//長さ L [cm] の太巻き, n 人で分け, k 個の切れ目
const [L, n, k] = lines[0].split(" ").map(Number);
const A = lines[1].split(" ").map(Number);//切れ目の情報だけ

A.unshift(0);//先頭
A.push(L);//末尾

//最も短い太巻きの長さについて二分探索する
let [left, right] = [0, L + 1];
while (right - left > 1) { //答えは整数なので差が1以下まででよい
  
  let mid = Math.trunc((left + right) / 2);//整数なので切り捨て

  let last_index = 0;//最後に太巻きを切った番号
  let parts = 0;//太巻きの本数
  for (let i = 0; i < k + 2; i++) { //太巻きの切れ目で切った時の本数
    //切った太巻き１本分の長さがmid以上になるように
    if (A[i] - A[last_index] >= mid) { //太巻き長さ＝末尾側切れ目ー先頭側切れ目
      parts += 1;//太巻き１本とする
      last_index = i;//最後に太巻きを切った番号
    }
  }
  //切った本数が少なかったら、もっと短くする
  if (parts < n) {
    right = mid;
  //多かったら、長く
  } else {
    left = mid;
  }
}
console.log(left);
```
Sudachi Elasticsearch v3.0.0をうまく使おう

# 初めに

[Sudachi Elasticsearchプラグインが新しくリリースされました](https://github.com/WorksApplications/elasticsearch-sudachi/releases/tag/v3.0.0)。以前のバージョンで課題となっていた重複解析問題が解決され、解析が場合によって数倍速くなりました。

# 重複解析解析問題

同じテキストを[複数のAnalyzer](https://www.elastic.co/guide/en/elasticsearch/reference/current/multi-fields.html#_multi_fields_with_multiple_analyzers)に掛けるともっと検索の精度を上げることができます（A単位とC単位で解析した結果をそれぞれフィールドに入れるなど）。なので文章を解析するときに複数のAnalysis Chainを設定することがあります。例えば、次の設定例[(フルバージョン)](https://github.com/WorksApplications/elasticsearch-sudachi/blob/v3.0.0/test-scripts/10-init-index.json)では４つのフィールドが設定されています。単語の見出しだけではなく、読み、読みのローマ字、辞書形がインデックスに入っています。

```jsonc
{
"mappings": {
    "properties": {
      "text": {
        "type": "text",
        "analyzer": "sudachi_a_analyzer", // # 1
        "fields": {
          "reading_romaji": {
            "type": "text",
            "analyzer": "sudachi_romaji_analyzer" // # 2
          },
          "reading_katakana": {
            "type": "text",
            "analyzer": "sudachi_readingform_analyzer" // # 3
          },
          "baseform": {
            "type": "text",
            "analyzer": "sudachi_baseform_analyzer" // # 4
          }
        }
      }
    }
  }
}
```

プラグインの3.0.0以前のバージョンはAnalysis Chainの数だけ解析を行っていましたが、3.0.0以上では解析結果がキャッシュされるため重複していたAnalysis Chain3つ分速くなります。

# 制限と正しい使い方

この改善は解析のキャッシングによって行っているものですので、メモリーが無制限に使われることを防ぐため入力が長い時はキャッシングが使われません。具体的な制限はUTF-16のコードユニット（例えばJavaでの`String.length()`が返す値)32ｋ分です。

幸いにこの制限を回避するための措置があります。Elasticsearchにテキストを32ｋユニット以内に分割してArrayとして渡すと、Arrayの中身が連結されているかのように解析が行われます。

```bash
curl -X PUT "localhost:9200/sudachi_test/_doc/test-doc" \
 -H 'Content-Type: application/json' \
 -d @- <<EOF
{"text":"このドキュメントが非常に長ければ文章が複数回解析されます"}
EOF
```

:::note warn
解析する文章を段落単位に分けて、Arrayとしてドキュメントに入れないと長いドキュメントでは最適化が無効になる可能性があります。
:::

```bash
curl -X PUT "localhost:9200/sudachi_test/_doc/test-doc" \
 -H 'Content-Type: application/json' \
 -d @- <<EOF
{"text":["Arrayとして渡せば", "長い文章を分割することができます"]}
EOF
```

:::note info
bashの`<<EOF`の記法は https://qiita.com/take4s5i/items/e207cee4fb04385a9952 で解説されています。
:::

# 実験

実験としてWikipediaのダンプをElasticsearchに入れました。コードは https://github.com/eiennohito/wikipedia-benchmark です。

実験は2つのパソコンで行っていて、1つ目のPCはベンチマークのコードを実行し、ネットワークを通じてドキュメントをElasticsearchに追加します。2つ目のPCはElasticsearchのサーバーとして動きます。実験では1万記事をインポートしています。記事は段落ごとに分けてArrayとして渡しています。

比較結果は次のテーブルにまとめています。1万記事のインポートが3.3倍速くなりました。

| コミット | インポート時間、秒 | 比較係数 |
|:-:|:-:|:-:|
| [2ed32e8](https://github.com/WorksApplications/elasticsearch-sudachi/commit/2ed32e808c075ffa9f1f5927912c1e975656c3c1) (改善前) | 558.7   | 3.3  |
| [838f680](https://github.com/WorksApplications/elasticsearch-sudachi/commit/838f680f47b2b4b91024d6bc5cdbefdeff385d16) (改善後)  | 167.4  | 1.0  |

# おわりに

Elasticsearch-sudachi v3.0.0では同じフィールドを違う設定で解析するようなケースで高速に解析されるようになりました。ただし、長い文書では段落などでArrayに分ける必要があります。

これまでの Java のコードをKotlinで再実装しています。不具合などありましたら、issueをお願いいたします。

ではよい Sudachi life を。
習慣について考えてみた

# はじめに
この記事は、筆者の身の回りで流行っている「30分でアウトプットしよう」
という取り組みの一環で書いたものをそのまま張り付けています。
ゆえに、乱文・誤りなどあればご容赦いただければ幸いです...!!


# では本編
継続は力なり、とはよく言ったものですが、継続ってなかなか難しいですよね。
そこで今回は、継続＝習慣化と捉え、習慣化することについて語ってみようと思います。

まず習慣化とは、日常生活の中に組み込むことだと思いますが、その目的は「習慣にすること」じゃないと思うんですね。
運動の習慣化→「健康維持」、読書の習慣→「知識のインプット」といったように、何かしら本来の目的が裏にあるかと思います。

そこで大事なのは、その本来の目的（健康維持や知識のインプット）と、習慣化することを
分けて考えることじゃないかなぁと思うのです。

僕は筋トレを日課にしているのですが、昨年はそれに加えて、ストレッチを始めました。
（筋トレしてるにもかかわらず、恥ずかしながら腰を痛めてしまったのでw）
ストレッチを習慣にする本来の目的は「体の柔軟性を取り戻すこと」なのですが、この達成のためにステップを2つに分けました。
>STEP1:ストレッチを習慣にする
>STEP2:（習慣化できた）ストレッチにより、柔軟性を取り戻すこと

ここでのポイントは、STEP1では「体の柔軟性を取り戻すこと」を目的としないことです。
とにかく、ストレッチを日常生活に組み込むことにフルコミットする。
なので、1日に10秒でもストレッチに時間を割けたらヨシ、という意識でいました。

そんな生活を続けていると、いつしかストレッチをしないことが不自然に感じるようになるんですね。
「あ。今日ストレッチやってないや」みたいに。
そこまでいけば勝ちです（笑）STEP2に移行しましょう。
ここで初めて、体の柔軟性を取り戻すことにコミットします。

結果としてストレッチは僕にとって、筋トレと同じく日常のルーティンになりました。それこそ歯磨きや食事のように。
やる気があるとかないとかそういうレベルではなく、やることが当たり前という風にインプットされています。

習慣化する上で一番大変なのは「やってない→やっているへの移行」だと思います。だから0→1ではなく、0→0.01くらいで良い。
0.01でも「やっている状態」に移行できれば、それを10なり100なりにするのは驚くほど簡単です。

人が何かを習慣にするには66日間の継続が必要である、というの研究結果で見た記憶があります。
諸説あるとは思いますが僕はこれを信じて、何かを2か月継続できたら「よし、習慣化できた」と思いこむことにしていますｗ
大事なのは習慣化することなので、そう自己暗示できる要因があれば何でもいい気がします。

というわけで、僕なりの習慣の作り方についてまとめると、以下のようになります。
* 習慣化フェーズと目的達成フェーズを分けよう
* 習慣化フェーズでは、本来の目的は意識しない。
* 0→1を目指さない、0.01でいい
* 2か月続けてみよう、そしたら目的達成フェーズに移行しよう

2023年、何かに取り組もうとされている方の参考になれば幸いです。
AmazonConnectで日本の電話番号取得にサポート問い合わせが必要だった件について

# 前提条件
この記事は、2023/01頃に書かれています。

# ドキュメントの手順

https://docs.aws.amazon.com/ja_jp/connect/latest/adminguide/claim-phone-number.html

管理コンソールから取得できるとドキュメントには記載されていますが、管理コンソールからは取得できません。
昔は管理コンソールから取得できていた時代もありました。
（はじめてAmazonConnectを触った頃は出来ていたのになぁ～・・・）

# 番号払い出しの流れ

+ AmazonConnectのインスタンス作成（申請にはインスタンスのARNが必要）
+ 身分証明・会社証明などの書類準備（起票前に準備が望ましい）
+ AWS管理コンソールからサポートケースを起票(Service limit increase)からの起票（日本の電話番号を取得したい旨を記載）
+ 申請用のリッチテキストファイル（IdentityDetails.rtf）をサポート担当から貰える
+ 必要書類をS3にアップロードする
+ 承認OKがでれば番号が貰える（３～５日位待ちます）

# AmazonConnectのインスタンス作成
割愛

# 身分証明・会社証明などの書類準備

　　A. 記入済リッチテキスト形式ファイル（上記1でケースに添付されているファイルとなります）
　　B. 申請者の行政機関発行の有効な身分証明書 (運転免許証、パスポートなど)
　　C. 申請者と企業の関連性を示すドキュメント（社員証や、その他所属を確認できる書類）
　　D. 公共料金の請求書、法務省からの企業登録証明書 (登記事項証明書など)、行政機関からの領収書、国税または地方税に関する証明書 (納税証明書など)、社会保険料の領収書などの書類
　　※日本のどの電話番号の取得を希望される場合でも、A～D まで全て提出が必要となります。
　　※東京の 03 番号の取得を希望される場合は、D の書類にて 03 番号が使用可能な住所が記載されているものを提出いただく必要がございます。

を用意しなさいと言われるので、前もって準備しておくと良い。（A．のリッチテキストはサポートケースを起票しないと記入する為のファイルが貰えないので後回し）

弊社の場合は、
+ リッチテキストファイル
+ 履歴事項全部証明書
+ 免許証（履歴事項全部証明書に記載のある方の免許写し）

https://corporate.ai-con.lawyer/articles/registration-certificate/12

で、AWSから承認が貰えました。

# AWSからケース起票
起票する為のカテゴリが、どこからやって良いのか分かりずらいですよね。

![制限解除申請.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281768/427d5a0d-923a-2e06-daea-b42ff066a2d7.jpeg)

+ Service limit increase

|項目|内容|
|:--|:--|
|Limit type|Amazon Connect|
|コンタクトセンターのインスタンス ARN - optional|払い出したAmazon Connect インスタンスARN|
|リージョン|アジアパシフィック（東京）|
|Limit|日本（東京）の電話番号|
|New Limit Value|欲しい電話番号の数|
|Use case description|AmazonConnectで電話番号を取得した旨を記載する|

で、問い合わせを起票します。

# 申請用のリッチテキストファイル

サポート担当から、必要書類の案内と、リッチテキストファイル（雛形）が貰えます。

が、私の場合は、<strong>担当者の添付忘れでリッチテキストファイル（雛形）が１回目の回答で貰えなかった</strong>ので、１往復してツッコミをいれたら添付されてきました。（＾＾

リッチテキストファイルは、英語で記載する必要がありますが、どんな項目が必要か？の列挙をしておきます。

+ 提示する身分証明書の方の氏名(姓名)
+ 会社名
+ 会社住所
+ 欲しい電話番号の種類（050 / 0120 / 0800）
+ 欲しい電話番号の数

# S3にアップロードする

注意点
+ ログインしているIAMユーザにS3関連の権限が必要
+ アクセス権の追加

### 依頼原文
５．アクセス権の追加
「アクセス許可」のプルダウンをクリックし、「アクセスコントロールリスト (ACL)」のセクションで「個別の ACL アクセス許可の指定」を選択してください。
ページ下部に「他の AWS アカウントのアクセス」というセクションが現れますので、「被付与者の追加」をクリックください。

６．「被付与者」の下の入力フィールドに、下記正規 ID を入力してください。
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

７．「オブジェクト」の読み込みのチェック欄にチェックを入れてください。
※「オブジェクト ACL」についてはチェックは不要です。

アクセス権の付与を忘れると、先方が閲覧できずに、無駄にやり取りを往復することになります。（<strong>自分が忘れたという自戒</strong>）

# 承認OKがでれば番号が貰える
結構時間がかかります。案件などで電話番号を取得する時は余裕をもって申請をしましょう。
（実例：月曜に申請して払い出しが金曜とかです）

# AWSの相談・お困りごとありましたら、、、

AWSの活用方法や、お困りごとの相談、随時、お仕事の受付しております。

https://www.cs-cloud-aid.com/
【Laravel】同値チェックのバリデーション

# はじめに
確認用の入力でバリデーションがしたく、同値チェックができるもののまとめ


# same:フィールド名
指定したフィールドと同じ値であるかどうか
```PHP
'name' => ['same:confirm']
```

# different:フィールド名
指定したフィールドと異なる値であるかどうか
```PHP
'sub_email' => ['different:main_email']
```

# confirmed
[フィールド名]_confirmationフィールドと同値であるかどうか

```PHP
'email' => ['required', 'confirmed']
```
入力確認用に使用するものであるが、[フィールド名]_confirmationの存在が必要となる
上記だとemail_confirmationが必要
```
メールアドレス<input type="text" name="email">
メールアドレス（確認用）<input type="text" name="email_confirmation">
```


以上
プリザンターのスクリプト機能を使い、マニュアルにあるサンプルコードから実際に動かしてみた

 # はじめに
サンプルコードを見ても、よくわからないときありますよね。それに、何をどこに記述すればよいのかもわからないときは困ります。私はいつもシンプルなコードを作って、どのような値が返ってきて、どうすれば想定通りの動きをするのか試しています。私が研修中にサンプルコードでは少しわかりにくいかもなと思ったスクリプトや業務でこのスクリプトは結構使えるかもと思ったものをご紹介したいと思います。
※ここでご紹介する例はすべて動作検証済みです。そのため、環境が同じであればコピペですぐ動きます。ご利用の際はお客様の環境に合わせてご利用ください。

 # $p.getControl(項目名)
こちらは項目の要素をとってきてくれるスクリプトです。とても便利なので、一度使ってみてください。
```javascript
$p.getControl('ClassA');
```
→分類Aの要素を取得します
また、上記のスクリプトに「.val()」をつけることでその要素の値を取得することができます。
```javascript
$p.getControl('ClassA').val();
```
→分類Aに入力されている値を取得します

 # $p.set(変更対象の要素, その要素に入れたい値)
こちらは第一引数に変更対象の要素を指定し、第二引数にその要素に入れたい値を指定します。
```javascript
$p.set($p.getControl('Title'), '頑張ろう')
```
→タイトルを頑張ろうに変更します

 # $p.on(イベント名, 監視項目, 任意の処理)
こちらは上記2つよりも難しいです。正直私も最初につまずきました。しかし、このスクリプトはとても便利です。実際に私がサポートしていく中で、このスクリプトはぴか一で便利だと実感しました。今回はその業務で利用したような方法をに近い形で記載いします。
```javascript
$p.on('change', 'DateA', function () {
    $p.set($p.getControl('DateB'), $p.getControl('DateA').val());
})
```
→日付Aが変更されたとき、日付Bに日付Aの日付を転記する
こちらは上記2つと合わせるとすごく便利です。
また、$p.onの第一引数を変えることでどのようなときに処理が続行されるのか調整できます。
```javascript
$p.on('click', 'checkA', function () {
    $p.set($p.getControl('ClassA'), 'こんにちは');
})
```
→チェックAがクリックされたとき、分類Aにこんにちはと記載する
こちらも考え方は同じです。ですが、イベントとは何でしょうか。マニュアルでは、Ajaxのイベント名と記載があります。そのため、調べてみたのですが、下記資料を参考にしてください。

http://ajax.studynet.jp/event/eventhandler/event-handler

こちらの記事では、「onchange」など頭文字に「on」がついていますが、上記のように「on」は不要なのかもしれません。私が試したのは「change」と「click」の2つでした。そのほかはまだ検証していないため、これから検証していこうと思います。
【Python】`typing.overload`で引数指定のお行儀を守らせる方法

## やりたいこと

下記のような、スパムとハムを任意の数、(対象物へ)食べさせる関数があるとします。
```py

def feed(spam: int = 0, ham: int = 0) -> None:
	...

```
この関数は対象物にスパムとハムを食べさせるときに便利なので、チーム内で広く可読性よくコーディングさせたいです。

何を何個食べさせるか可読性良く明示することを強制させるとしたら、このような実装になるでしょう。
```py
def feed(*, spam: int = 0, ham: int = 0) -> None:
    ...

# できる
feed(spam=1)
feed(ham=2)
feed(spam=1, ham=2)
feed(ham=2, spam=1)
# できない
feed(1)
feed(1, 2)
```

しかし、チーム内のドメイン知識として、いつも同時にスパムとハムを食べさせるときには必ず`(spam, ham)`の順番にすることが浸透していました。
そのため、2つ同時に与えるときに引数名が必ず必要なのは開発体験が低くなってしまいます。
- `feed(ham=2, spam=1)`となっている分には誤解がないので許容されています。

しかし、`feed(1)`だとスパムだけを1つ食べさせるのかハムだけを1つ食べさせるのかわからないので、1種類だけ食べさせるときには`feed(spam=1)`, `feed(ham=2)`のように名前付き引数を使うことが推奨されています。
また、どれも1つも食べさせない時にはそもそも関数を呼ばないことが推奨されています。

```py
# 推奨
feed(spam=1, ham=2)
feed(ham=2, spam=1)
feed(1, 2)
feed(spam=1)
feed(ham=2)
# 非推奨
feed(1, ham=2)
feed(1)
feed()
```

このようなことをコーディング規約として守らせたいとき、残念ながらPython 3.11現在では(上述のキーワード限定引数のようなことを)実行時レベルで簡単にやる方法はありません。


## 引数指定の違反を`typing.overload`を使ってコーダーに伝える
しかし、`typing.overload`を使うと、非推奨の使い方をしている場合にはVSCodeの言語サーバー`pylance`(が内蔵する静的型チェッカー`pyright`)に警告を出させることが可能です。

```py
from typing import overload


@overload  # 引数名を両方とも指定しない
def feed(spam: int, ham: int, /) -> None: ...
@overload  # 引数名を両方とも指定する
def feed(*, spam: int, ham: int) -> None: ...
@overload  # 引数名をspamだけ指定する
def feed(*, spam: int) -> None: ...
@overload  # 引数名をhamだけ指定する
def feed(*, ham: int) -> None: ...

# 実装
def feed(spam: int = 0, ham: int = 0) -> None:
    ...


# 実行時にはいずれもエラーは発生しない
feed(spam=1, ham=2)
feed(ham=2, spam=1)
feed(spam=1)
feed(ham=2)
feed(1, 2)
# 非推奨
feed(1, ham=2)
feed(1)
feed()

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364180/faea18e2-b72a-7b29-e034-dcd284847432.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364180/33fb1f0a-eb73-a4b3-46f3-de8ca15b1166.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364180/b573b18a-f208-896d-0779-0c514df2ae01.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364180/6850deab-0ec1-5fd6-9e51-91ba581d5253.png)

あくまでも型チェッカーによる静的解析の結果の警告なので、実行時にはエラーなく動きます。
しかし目的はコーディング規約を守らせることなので、これはこれで目的を達成することができました。

## 参考文献
https://docs.python.org/ja/3.10/glossary.html - "parameter"
https://docs.python.org/ja/dev/library/typing.html#typing.overload
https://peps.python.org/pep-0484/
mocopiを使ってQuest単体版のVRChatでフルトラをする方法

# 概要

Sonyから発売されたモーションキャプチャデバイス「mocopi」を使用して、Meta Quest単体版のVRChatでフルボディトラッキングをする方法を説明します。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Quest 単体でフルトラできた！<a href="https://twitter.com/hashtag/mocopi?src=hash&amp;ref_src=twsrc%5Etfw">#mocopi</a> <a href="https://twitter.com/hashtag/VRChat?src=hash&amp;ref_src=twsrc%5Etfw">#VRChat</a> <a href="https://t.co/cHiw4nPdcM">pic.twitter.com/cHiw4nPdcM</a></p>&mdash; サックー@XR (@VRC_Sakk) <a href="https://twitter.com/VRC_Sakk/status/1616279137240649729?ref_src=twsrc%5Etfw">January 20, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 手順
### １．mocopiのキャリブレーションまでを済ませる
これはアプリの案内に従ってやればできると思います。
ただHMDを付ける上でHEADの位置は工夫が必要かもしれません。
デバイスに応じていい位置を見つけてください。

### ２．mocopiアプリでIPアドレスを設定する
まず前提としてmocopiアプリが入ったスマホとQuestを同じWi-Fiに接続する必要があります。
次にQuestのIPアドレスを調べます。
Wi-Fi設定から接続しているものを選ぶと、下に詳細設定という欄があります。
![IMG_1696.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/a2490e90-f44c-9468-a203-dc6f40c9697e.jpeg)
そこを選ぶとIPアドレスを確認することができます。
![IMG_1698.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/829c68ee-c29b-8565-296f-5ab661fdf045.jpeg)
この番号を控えておきましょう。
今度はmocopiアプリ側の設定です。
右上の三点ドットから設定を開きます。
![IMG_1703.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/32cfd8f5-dbd6-f859-4927-3852f51dbb8a.png)
次に「PC接続設定」を開きます。PCは使いませんがこれであってます。
![IMG_1701.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/dffc44a1-2820-cecc-e787-6330cb47e487.png)
そしてIPアドレスの欄にさっき調べたQuestのIPアドレスを入力し、送信フォーマットでVRChatを選びます。
![IMG_1702.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/a598a976-b6d2-a373-7998-4883cbdfc829.jpeg)

### ３．mocopiアプリでモーションデータを送信する
元の画面に戻ったら一番上真ん中を「ビデオ」から「モーション」に切り替えます。
次にその下が「保存」になっていると思うので「送信」に切り替えます。
最後に一番下真ん中のボタンを押せばモーションデータの送信が始まります。
![IMG_1700.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/83bf119e-21a1-fadc-dfa7-73123b69e86c.jpeg)

### ４．VRChatでフルトラをする
ここからVRChat側に行きます。
QuestをかぶってVRChatを起動しましょう。
この時HEADがずれてしまったら再キャリブレーションが必要かもしれません。
起動したらエクスプレッションメニューを開き、「Options」に入ります。
すると「OSC」というのがあるのでさらにそこに入ります。
![IMG_1708.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/1c0f8095-795a-1005-eb3a-49adf6fe553d.jpeg)
そして下の「Disable」を「Enable」にします。
![IMG_1704.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/90a16880-6ab8-27c6-6ee0-3b9daffdb5a2.jpeg)
いよいよキャリブレーションです。
普通にクイックメニューを開くと、「Calibrate FBT」というのが出現しているはずです。これを選びます。
![IMG_1705 (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/4b959e1a-c2be-bd00-c2a8-180a96549db7.jpeg)
するとアバターがTポーズになって内部でのトラッカー相当の位置が表示されます。リアル側でアバターと同じぐらい足を開いて、両手の人差し指トリガーを引きましょう。足とトラッカー表示位置が重なっている必要はないです。
![IMG_1706.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/2cfc147f-5273-fcb6-bff7-a26a41438dea.jpeg)
これで無事Quest単体でフルトラができましたね！お疲れ様でした！
![IMG_1707.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/d5032dd5-106c-c649-b1ab-0f954755590a.jpeg)

トラブルシュートなどは追記する可能性があります。
シェルコマンドechoのスペース区切りに対する不可解な挙動

スペース区切りの文の単語数を調べていたところ
```
$ echo "【 対象 者 】"  | wc -w
       4
$ echo "【 対象 旅行 者 】"  | wc -w
       6
```

「旅行」の2文字があると、1単語ではなく2単語としてカウントしてしまう模様...
- 「旅」を消した場合
```
$ echo "【 対象 行 者 】"  | wc -w
       5
```

echoは信用ならないとわかったので、参考程度に使いつつ、pythonのsplit関数を信用していこうと思います。

※勘違い、知らない仕様である可能性は多いにあるので、現在(2023.01.20)も調べています。有識者の方のアドバイスをお待ちしております。
※環境はmacOS Monterey バージョン12.3.1のターミナル(コメントを受けて追記、1/21)
【UE5】Aポーズにする方法(VRMも可)

メモ


「Create」→「Import from Pose Asset」→「TargetのキャラクターのPOSEを選択」→
「POSE_T」になっているところを「POSE_A」に選択するとAポーズになる


https://twitter.com/ruyo_h/status/1601914146794401794?s=20&t=YsMAfgwPFLXKTEGx43Gaxw

<br>
<br>
<br>
<br>
<br>
<br>

動画Ver

https://gyazo.com/39a1d970bfe6e960af976ec7d41819ab


<br>
<br>
<br>
<br>
<br>
<br>

残りの手順はここに

https://note.com/littlekei/n/nce5df7c1111e

「（２）TポーズからAポースに変更」　を飛ばして、この方法をやるとリターゲットができる

<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>

## ・「フォロー」と「いいね」という、プレゼントを下さい

Twitter

https://twitter.com/MapleSyrup77


<br>
<br>
<br>
<br>
<br>

Noto

https://note.com/ggrks_ue4

<br>
<br>
<br>
<br>
<br>

Discord鯖　　(気軽に進捗上げてね、デバッグ募集とかもOK！)

http://discord.gg/xBMBWbrRDS
SVGファイルをPDFに一気に変換する

複数のSVGファイルをPDFに変換するためにコマンドを紹介します。

今回はUbuntuで実行しました。ディレクトリ構造は以下です。svgディレクトリの中にあるSVGファイルをPDFに変換したものをpdfディレクトリの中に保存します。

```
├── svg
│   ├── image1.svg
│   ├── image2.svg
│   ├── image3.svg
│
├── pdf
|

```
## librsvg インストール
変換にはlibrsvgを用いました。
Ubuntuでは
```bash
sudo apt-get install librsvg2-bin
```
MacではHomebrewでインストールできるようです。
```bash
brew install librsvg
```
## rsvg-convertコマンド
`rsvg-convert`コマンドを次のように用いてinput.svgをoutput.pdfに変換できます。
```bash
rsvg-convert -f pdf -o output.pdf input.svg
```
## 複数のsvgファイルをpdfに変換
今回は次のように`xargs`と組み合わせることで複数のsvgファイルをpdfに変換しました。
```bash
find ./svg -type f -name '*.svg' | xargs -I{} sh -c 'rsvg-convert -f pdf -o "./pdf/$(basename {} .svg).pdf" {}'
```
Rust+DockerでWebサーバーにアクセスできない

# はじめに

以下の書籍をやっていたところ躓いたエラーになります

https://www.amazon.co.jp/Web%E3%82%A2%E3%83%97%E3%83%AA%E9%96%8B%E7%99%BA%E3%81%A7%E5%AD%A6%E3%81%B6-Rust%E8%A8%80%E8%AA%9E%E5%85%A5%E9%96%80-%E4%BD%90%E8%97%A4%E6%98%AD%E6%96%87/dp/4798067318/ref=sr_1_2?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=ZDD7NV0CB1UD&keywords=rust&qid=1674203712&sprefix=rus%2Caps%2C183&sr=8-2

ここでは書籍通りではなく、Rustのコンテナ環境上でWebサーバーを立てていたので、それが起因して問題が起きていました

# 問題

以下のコードを実行しました

```rust:main.rs
use axum::{routing::get, Router};
use std::net::SocketAddr;

#[tokio::main]
async fn main() {
    let app = Router::new().route("/", get(root));
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));

    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

async fn root() -> &'static str {
    "Hello, World!"
}
```

そして`docker-compose.yml`を以下に設定します

```yml:docker-compose.yml
version: '3'
services:
  rust:
    build: .
    container_name: rust
    tty: true
    ports:
      - "3000:3000"
    volumes:
      - .:/app
```

そして

```
$ curl http://localhost:3000
```

にアクセスしたところアクセスができませんでした

# 解決方法

サーバーの起動するIPが間違っていました

```
$ docker ps


CONTAINER ID   IMAGE                                  COMMAND                  CREATED         STATUS         PORTS                                       NAMES
94bf63a7cdc8   learn-rust-with-web-application_rust   "/bin/sh"                5 minutes ago   Up 5 minutes   0.0.0.0:3000->3000/tcp, :::3000->3000/tcp   rust
b0f3a5289ff5   4251bd246069                           "/bin/sh -c 'rustup …"   27 hours ago    Up 27 hours  
```

コンテナの情報をみたところ

```
0.0.0.0:3000->3000/tcp
```

とありました

コードを見ると

```rust
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
```

とあり、`127.0.0.1`となっていました
そこで以下のように変更しました

```rust
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
↓
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
```

これで問題なくアクセスできるようになりました

最終的なコードは以下になりました

```rust:main.rs
use axum::{routing::get, Router};
use std::net::SocketAddr;

#[tokio::main]
async fn main() {
    let app = Router::new().route("/", get(root));
    let addr = SocketAddr::from(([0, 0, 0, 0], 3000));

    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

async fn root() -> &'static str {
    "Hello, World!"
}
```

# おわりに

いままでの言語ではIPの部分を気にしなくても動いていたので、一瞬ハマってしまいました
VSCodeのrust-analyzerで#[tokio::main]がエラーになる(proc macro `main` not expanded: no proc macro dylib present)

# はじめに

以下の書籍をやっていたところVSCode上でエラーが表示されたので解決方法についてまとめていきます

https://www.amazon.co.jp/Web%E3%82%A2%E3%83%97%E3%83%AA%E9%96%8B%E7%99%BA%E3%81%A7%E5%AD%A6%E3%81%B6-Rust%E8%A8%80%E8%AA%9E%E5%85%A5%E9%96%80-%E4%BD%90%E8%97%A4%E6%98%AD%E6%96%87/dp/4798067318/ref=sr_1_2?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=ZDD7NV0CB1UD&keywords=rust&qid=1674203712&sprefix=rus%2Caps%2C183&sr=8-2

# 問題

以下のコードを書いたところ

```rust:main.rs
use axum::{routing::get, Router};
use std::net::SocketAddr;

#[tokio::main]
async fn main() {
    let app = Router::new().route("/", get(root));
    let addr = SocketAddr::from(([0, 0, 0, 0], 3000));

    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

async fn root() -> &'static str {
    "Hello, World!"
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/7d8a28b3-e651-0fd3-0d12-d888a24d55ef.png)

```rust
#[tokio::main]
```

で`rust-analyzer`のVSCodeの拡張でエラーが表示されました

# 解決方法

以下の記事を読みました

https://www.reddit.com/r/rust/comments/vj2ghz/suddenly_proc_macro_main_not_expanded_proc_macro/

>これは、rust-analyzer で導入されたバグです。修正はすでにマスターにマージされています。修正プログラムはまだリリースされていません。それが本当にあなたを悩ませているなら、今のところプレリリース版に切り替えることができます

これはバグが原因であり、実行自体は問題なくできるとのことでした
プレリリース版に変えることで治るようですが、あまり気にせず実行したところ問題なく実行できました

# おわりに

早く正式リリースしていただけたらとは思っています

# 参考

https://www.reddit.com/r/rust/comments/vj2ghz/suddenly_proc_macro_main_not_expanded_proc_macro/
RustでCargo.tomlを導入したらlinker `cc` not foundエラーがでる

# はじめに

この度転職で利用するであろうRustの学習を始めることにしました
Rustは最高難易度の言語と呼ばれているほど難しいのを知っていたので、初心者がつまづきそうな問題をどんどん記事にしていきます

今回はWebサーバーで`Hello World`しようとしたときにつまづいたものです

# 問題

`Cargo.toml`を導入して`cargo run`をしたところ以下のエラーがでました

```
linking with `cc` failed: exit status: 1

以降入れたライブラリがcompile後にエラーになる
```

書籍通りにやっているのになぜか動きませんでした

# 解決方法

これはコンパイラが環境になかったことで起きていました

https://omohikane.com/rust_cargo_build_linker_cc_not_found/

私の場合はDockerのAlpine環境で動かしていたので以下を追加することでうまく行きました

```Dockerfile:Dockefile
RUN apt install alpine-sdk
```

これは`build-essential`の代わりとなります

# おわりに

はじめて触る言語はある程度全体的に学ぶまでは問題がおきるととても不安になります

# 参考

https://omohikane.com/rust_cargo_build_linker_cc_not_found/
アクツクMV：スクリプトでプレイヤーの体力をMAXにする


前回は「データベース（オブジェクト用）」https://qiita.com/havin_nothin/items/b0c0695292bff7e9fdbd でした。
今回は、スクリプトの基本的な使い方を解説します。

スクリプトを使って、プレイヤーの体力を最大体力にしようと思います。

最初から体力が最大体力と同じだと、変化が見えないので、プレイヤーのオブジェクトの初期設定で、
体力を３、最大体力を１０にしておきます。
![Script01Hp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3103492/ab6b4d7d-0e93-1ea2-7d5f-a230b01d4c70.png)

それからプレイヤーのアクションプログラムにアクションを追加して、「初期化」という名前をつけ、そこを初期アクションに設定します。（初期アクションはアクションを右クリックしてメニューを出すと出てきます／あと無条件に待機へつなげています）

ここまでは準備段階。

では本番です。
さっそく、「初期化」アクションに「スクリプトを実行」を追加して、以下のスクリプトをコピー＆ペーストしてください。

```
(function(){
var self = Agtk.objectInstances.get(instanceId);
var maxhp = self.variables.get(self.variables.getIdByName("最大体力")).getValue();
self.variables.get(self.variables.getIdByName("体力")).setValue(maxhp);
})()
```
![Script02Script2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3103492/64ffc98f-3c09-fd98-04b0-1b5bfe81ffab.png)

実行して、体力が１０になっていればOKです。（テキストで変数を表示しています→参照：https://qiita.com/havin_nothin/items/039d955d39fcedaa93bd   ）
![Script02Result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3103492/a59d3347-c3a0-aaae-f9ff-27460d08f2d5.png)

このプログラムを解説していきます。

１．最初の１行と最後１行は、お約束です。必ずこう書きます。
(function(){
　この間にプログラムを書く
})()
　というルールです。

２．var self = Agtk.objectInstances.get(instanceId);

　変数selfに、自分自身のオブジェクトを入れます。自分自身とはここでは「プレイヤー（のオブジェクト）」が入っています。instanceIdはアクツクMVがすでに用意している変数です。とりあえずAgtk.objectInstances.get(instanceId)と書けば、自分自身のオブジェクトを返してくれるという理解でいいです。それを変数をselfで受けて、selfで操作できるようにしています。先頭のvarは変数を定義しますという意味です。

３．var maxhp = self.variables.get(self.variables.getIdByName("最大体力")).getValue();
　変数maxhpに、自分自身の変数「最大体力」の値を入れます。"最大体力"を別の変数名にすればその値になります。（""は半角です）

４．self.variables.get(self.variables.getIdByName("体力")).setValue(maxhp);
自分自身の変数「体力」にmaxhpの値を入れます。やはり"体力"の部分を別の名前にすれば別の変数へ値をセットできます。

長々しいですが、簡単にまとめると、
１．スクリプト開始のお約束
２．自分自身をselfと定義し、
３．selfの「最大体力」をmaxhpに入れ、
４．selfの「体力」をmaxhpにする。
というプログラムになっています。

ではこれを応用してみます。
プレイヤーに変数「レベル」を作り、この「レベル」×１０が最大体力になるというスクリプトです。

```
(function(){
var self = Agtk.objectInstances.get(instanceId);
var level = self.variables.get(self.variables.getIdByName("レベル")).getValue();
var maxhp = level * 10;
self.variables.get(self.variables.getIdByName("最大体力")).setValue(maxhp);
})()
```
![Script03LevelResult.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3103492/5b9f0679-323a-faac-fabf-35d861ef51df.png)

「レベル」の初期値をいろいろ変えて実行してみてください。

プログラムの文法はJavascriptなので、ネットを検索すれば山のように出てきます。
（たとえばこちら：JavaScript 基礎文法 https://qiita.com/Fendo181/items/cca476da99e8f09b6b97 シンプルにまとまってます；「昔はvarがあったが、今は使わない」って書いてあった；；）

とりあえず、自分自身の変数を参照、操作するスクリプトができるようになりました。

次回は、自分自身以外のオブジェクトの変数をスクリプトで扱ってみます。
https://qiita.com/havin_nothin/items/2a8bab1f72a325e784bb
ではまた。

（Thanks:今回のスクリプトは
 Scripting Made Easy　作者： baz　https://steamcommunity.com/sharedfiles/filedetails/?id=2566824894 　のTargeting Switches & Variablesにあるコードをシンプルに書き換えたものです。
ただこちらのコードはなぜか「最大体力」を名前で取得すると、うまく動きませんでした）