OmniAICreator/Qiita-1.07M huggingface dataset:
ORMフレームワークについて

## データベースを使ってプログラムを開発するには？
データベースと連携してプログラムを開発する必要がある。プログラムでデータを読み書きしても、

データベースは表形式を扱う
プログラムはオブジェクトを扱う

と扱うデータの種類が異なり、どう扱うかが問題になる。その問題を解消したのが、ORMだったんですね。


## ORM(Object Relational Mapping)とは？
データベースとオブジェクト指向プログラミング言語(JavaやRubyなど)の「翻訳者」として機能しているプログラム技術または仕組みのこと

・UserテーブルからIDを条件にレコードを取得する場合
&lt;SQLの場合&gt;
```
SELECT * FROM USER WHERE ID = 1 LIMIT 1;
```
&lt;RailsのActive Recordの場合&gt;
```
User.find(1)
```

Active Recordを使って分かるのが、
①データベースの「テーブル」を、オブジェクト指向プログラミング言語の「クラス」として扱っている
②「クラス」に紐づくメソッドを使ってデータベースを操作するので、SQLより短く直感的で分かりやすい


## ORMデザインパターンの種類について
①Active Record
データベースの各テーブルをモデルとして扱います。そしてActive Recordを使うORMは、CRUDメソッドを用意していて、オブジェクトを生成しやすくなる。
![20220803082244.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3568357/233b396e-de4f-65d0-bb1b-fb886a964778.png)
画像取得元：https://blog.colopl.dev/entry/2022/08/31/110152

②Data Mapper
Active Recordと違って、テーブル操作の機能を集めたDataMapperが存在し、モデルとテーブルの仲介役となる。
![20220803082137.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3568357/bd32a64e-1d52-b658-1fc3-3952c61051f3.png)
画像取得元：https://blog.colopl.dev/entry/2022/08/31/110152


## 調べてみて分かったこと
「データベースは表形式」「プログラムはオブジェクト」とデータの種類が異なっても、翻訳機能を持つORMフレームワークのおかげで、オブジェクト指向プログラミング言語を使ってデータベースを操作できる
VisualStudio2022でOpenCVを使う(Python編)

仕事中にVisualStudio2022+Python+OpenCVの環境が必要になったのでメモ
### 1.Pythonプロジェクトを作成する
①.今回は「Pythonアプリケーション」でプロジェクトを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616522/c4eb566c-6718-13a1-b7ad-dd03ddaefce4.png)

②.プロジェクト名と保存場所を決定し「作成」を押す
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f333631363532322f38626332356363662d643163342d663961622d333738632d3832616132316237643162382e706e6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616522/8031e9d3-c677-525c-6501-bd415eaa95c7.png)


### 2.OpenCVのパッケージをインストール
①画面左の「ソリューションエクスプローラー」から「Python環境」を右クリックして「すべてのPython環境を表示」をクリック」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616522/5f47efcc-4440-8a65-e420-9648ba3392ec.png)

②Pythonライブラリのインストール画面が出てくるので検索ボックスから「opencv-contrib-Python」を見つけてクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616522/54fb43e8-2b29-1138-07ef-e54235a507f5.png)

③このようなポップアップが表示されますので「今すぐ昇格」を選択して管理者権限でインストールします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616522/9e0d5655-8fb3-75db-4458-a87554bda319.png)

④インストールが完了し、画面下の出力画面に以下のようなログが出れば成功です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616522/a8500a14-8c1c-c831-ab1c-bac6985b32b8.png)
オブジェクト指向　クラス情報をメモリにロードするタイミング

:::note
オブジェクト指向プログラミングでは、クラスからインスタンスを作ってプログラムが動作する。この時、インスタンスを作る前にクラスの情報をメモリにロードしておく必要がある。

クラスの情報とは、個々のインスタンスに依存しないクラス固有の情報のことで、最も重要なのはメソッドに書かれたコード情報。

同じクラスから作られたインスタンスの場合、インスタンス変数の値は各々で変わりますが、メソッドに書かれたコード情報は変わらない。
:::

### メソッドに書かれたコード情報は1クラスにつき1つだけロードする

クラス情報をメモリにロードするタイミングは大きく分けて、2つある。

#### 事前に全てのクラスの情報を一括してロードする方式
全てのクラス情報をアプリケーションの開始時にまとめてメモリにロードする方式。コード情報を最初に全てロードする方式は、従来の多くのプログラミング言語で一般的な仕組みで、C++ではこの方式を採用している。

#### 必要な時点で逐次ロードする方式
Javaや、インタプリタで動かすことが多いPythonやRubyなどもこの方式を採用している。

この方式では、新しいクラスを使うコードを実行するたびに、ファイルから対応するクラス情報を読み込んでメモリにロードする。そしてそのタイミングで、ロード済みの他のクラス情報との関連付けも行う。

この方式のメリット

* 実際に動くコードの分だけメモリを使うので、全体のメモリ使用量を減らせる
* ネットワーク越しに分散して管理しているプログラムファイルを実行時に結合して動かすことが容易になる
Qiita のアカウントを作ったので、CLIを設定してみた

# ブログ書いていくぞ！

HTB 開発チームのOrganizations をQiita に作ったので、ブログ書いていきたい。個人的にはブログ書くよりスライド作って喋る方が得意なのですが

頑張って書いていきたい

## まずは環境構築


Qiita CLI やらがあるそうなので、入れてみる

https://github.com/increments/qiita-cli

記事の追加も簡単に以下のコマンドから出来る

```console
npx qiita new 記事のファイルのベース名
```

この時生成される `.md`　ファイルの説明が以下のように書いてある

```yaml
---
title: newArticle001 # 記事のタイトル
tags:
  - "" # タグ（ブロックスタイルで複数タグを追加できます）
private: false # true: 限定共有記事 / false: 公開記事
updated_at: "" # 記事を投稿した際に自動的に記事の更新日時に変わります
id: null # 記事を投稿した際に自動的に記事のUUIDに変わります
organization_url_name: null # 関連付けるOrganizationのURL名
slide: false # true: スライドモードON / false: スライドモードOFF
ignorePublish: false # true: `publish`コマンドにおいて無視されます（Qiitaに投稿されません） / false: `publish`コマンドで処理されます（Qiitaに投稿されます）
---
# new article body
```

### ちょっとだけハマったところ

`organization_url_name` にフルのURLを入れては失敗を繰り返していた。
`organization_url`　じゃなくて、　`organization_url_name` だもんね。

でも、この時のエラーが、記事が存在しないことを示すようになっていたので、ちょっと混乱してしまった。

```
記事が見つかりませんでした
Qiita上で記事が削除されていないかご確認ください
```

Readmeがすばらしく
GitHub Actions まで簡単に設定が終わったので、サクサク書いていけそう。

## Qiita Preview もすばらしい

localhost での環境も用意されてた。素晴らしい。

```
npx qiita preview
```

### 引き続きやっていきます

継続的にがんばるぞ！
Livewire3にアップグレードしてupdatedが動かない時の対処法

# Livewire2→Livewire3でupdatedが動かない
↓もしかしたら誰か同じ問題にぶつかってないかなーと、質問投げてみた。
やっぱりLivewireって使ってる人少ないのかな。

https://qiita.com/limtae/questions/dd62f8ada7bc1cee6e28#answer-25b9fb12200de07c676d

これもけっきょくドキュメントに書いてたね。
Lifecycle Hooksばかり見てたけど、Formの方に書いてあった。

https://livewire.laravel.com/docs/forms

Livewire２で以下のように書いてたのを
```
<input type="text" wire:model="name">
```
以下のように.liveをつけてあげるだけ。
```
<input type="text" wire:model.live="name">
```

これで無事動くようになった！
【MAYA】ローカル軸とワールド軸をショートカットで切り替えるヤツ【MEL】

しょーもなスクリプトだけど便利なローカル軸とワールド軸を切り替えられるmelを配布しますわ！！ホットキーエディタ登録して使用してくださいまし。これだけで作業効率が変わりますわよ！

```mel:AxisChange.mel
string $ctx = `currentCtx -c`;
print $ctx ;
//move
if($ctx == "moveSuperContext"){
if(`manipMoveContext -q -mode Move` == 0){
manipMoveContext -e -mode 2 Move;
}
else{
manipMoveContext -e -mode 0 Move;
}
}
//rotate
if($ctx == "RotateSuperContext"){
if(`manipRotateContext -q -mode Rotate` == 0){
manipRotateContext -e -mode 1 Rotate;
}
else{
manipRotateContext -e -mode 0 Rotate;
}
}
//scale
if($ctx == "scaleSuperContext"){
if(`manipScaleContext -q -mode Scale` == 0){
manipScaleContext -e -mode 2 Scale;
}
else{
manipScaleContext -e -mode 0 Scale;
}
}

```

【使い方】
1.「ウィンドウ」→「設定/プリファレンス」→「ホットキーエディタ」
2.「ホットキーを編集」をcustomscriptに
3.ランタイムコマンドエディタで「新規」を押す
4.任意の名前をつけて言語をmelに
5.上記のスクリプトをペースト
6.「保存」を押す
7.カスタムスクリプトに追加されるので空いている好きなキーで登録する

(きーたに描くべきでないようなショーもなスクリプトですまんな。人に共有するついでにかいたんや。許してくれ。)
環境変数設定でやりがちなミスと注意事項

## 環境変数設定でやりがちなミスと注意事項

環境変数の設定はアプリケーションの正常な動作に重要ですが、設定時によくあるミスや注意事項があります。以下にそれらをまとめました。

### 1. ターミナルタブごとに設定

環境変数はターミナルセッションごとに設定されるため、設定を行ったターミナルタブでサーバーを起動することが重要です。異なるターミナルタブで設定した環境変数は反映されません。

### 2. ターミナルタブの紛失

環境変数を設定したターミナルタブを見失った場合、全てのターミナルタブで以下のコマンドを実行して設定を再読み込みしてください。

```bash
source ~/.zshrc
```

またはBashを使用している場合は:

```bash
source ~/.bash_profile
```

### 3. ターミナルの再起動

環境変数に関連するエラーが発生した場合、ターミナルを終了して再起動することで問題が解決されることがあります。環境変数の変更は、新しいセッションでのみ反映されます。

これらの注意事項を遵守することで、環境変数の設定と再読み込みを効果的に行い、アプリケーションが正常に動作することを確認できます。環境変数の適切な管理はアプリケーションの安定性とセキュリティに貢献します。
ESP32からChatworkへメッセージを送る

ESP32からChatworkへメッセージを送ろうと思ったけど、ぴったりの情報が見つけられず試行錯誤したので記録に残します。

## 動機
M5stackでネットワーク機器にpingして死活確認を行い、落ちてたらChatworkで通知を送ってくるようにしたい。

## 成功したコード
以下のコードで送れました。
```cpp:chatwork_send.ino
// Chatwork api活用
#include <WiFi.h>
#include <HTTPClient.h>
#include <ESPping.h>

const char* SSID     = "mySSID";
const char* PASSWORD = "myPASSWORD";

String BASE_URL  = "https://api.chatwork.com/v2/rooms/";
String ROOM_NAME = "xxxxxxxx";                  //グループID
String MYTOKEN   = "xxxxxxxxxxxxxxxxxxx";       //Token
String URL       = BASE_URL + ROOM_NAME + "/messages";

void chatwork_send(String message) {
  String httpRequestData ="";
  httpRequestData += "body=" + message;
 
  //HTTPClientでPOST
  HTTPClient httpclient;
  httpclient.begin(URL.c_str());

  httpclient.addHeader("Content-Type", "application/x-www-form-urlencoded");
  httpclient.addHeader("x-chatworktoken", MYTOKEN.c_str());

  int httpCode = httpclient.POST(httpRequestData);
  
    if (httpCode == HTTP_CODE_OK) {    //送信OK
    Serial.println(httpRequestData);
    Serial.println("chat send!");
    } else {    //送信失敗
    Serial.printf("[HTTP] POST... failed, error: %s\n", httpclient.errorToString(httpCode).c_str());
    Serial.println("chat error!");
    }
  Serial.println();
  httpclient.end();  //HTTPClient終了
  delay(1000);
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(SSID, PASSWORD);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500); Serial.print(".");
  }
  Serial.print("\nWiFi connect: OK");
  chatwork_send("テストだよ");
}

void loop(){}
```

以上です。
AtCoder初心者 DailyTrainingメモ 2023/11/7

# ABC255 A-問題
https://atcoder.jp/contests/abc255/tasks/abc255_a

**問題文**
整数 R,C と 2 行 2 列からなる行列 A が与えられるので、 A[R][C]を出力してください。

**ポイント**
入力される値を二次元配列に格納する記述を覚える

````Python:255A.py
R,C = map(int,input().split())

# 二次元配列で受け取る
# (入力例)
# 90 80
# 70 60
A = [ list(map(int, input().split())) for i in range(2) ]
# A: [[90, 80], [70, 60]]

# インデックスなので　-1
R -= 1
C -= 1

print(A[R][C])
````
# ABC254 B-問題
https://atcoder.jp/contests/abc254/tasks/abc254_b

![254B.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547298/010dd1fa-cee3-5fc3-1d97-a8f21b4f1d67.png)

**ポイント**
動的計画法を用いる

````Python:254B-1.py
# DP　動的計画法で解く
N = int(input())

ans = [1]
for _ in range(N):
    print(*ans)

    # DP に格納する
    dp = [0] * (len(ans) + 1)

    for i in range(len(ans)):
        dp[i] += ans[i]
        dp[i + 1] += ans[i]
    ans = dp
````
````Python:254B-2.py
# N * N の二次元配列で解く
N = int(input())

# 二次元配列を作る
A = [[0] * N for i in range(N)]

for i in range(N):
    for j in range(i+1):

        # 条件1  j=0 または j=i の時、a i,j = 1
        if j == 0 or j == i:
            A[i][j]=1
        
        # 条件2 それ以外
        else:
            A[i][j] = A[i-1][j-1] + A[i-1][j]

for i in range(N):
    # A[i]の0~i番目までを出力
    print(*A[i][:i + 1])
````

# ABC295 C-問題
https://atcoder.jp/contests/abc295/tasks/abc295_c

**問題文**
N 枚の靴下があります。i 枚目の靴下の色は Aiです。
あなたは以下の操作をできるだけ多い回数行いたいです。最大で何回行うことができますか？

・まだペアになっていない靴下の中から同じ色の靴下を2 枚選んでペアにする。

**ポイント**
defaultdict を活用して靴下の各色の枚数を格納する

````Python:295C.py
from collections import defaultdict

N = int(input()) 
A = list(map(int, input().split()))

# 辞書を用意する
dic = defaultdict(int)

# 各色をカウントしていく
for i in range(N):
    color = A[i]
    dic[color] += 1

ans = 0

# 各色を 2で割った答えを加算する
for color in dic:
    ans += dic[color] // 2

print(ans)
````
Assistant APIの良さを知りたくてPlaygroundで遊んでみた

# はじめに
OpenAI DevDay で発表されたAssistant APIがなんだかすごそうなんだけど
英語がよくわからなくてピンとこなかったので実際に試してみることにしました

# Playgroundで試せます

https://platform.openai.com/playground?mode=assistant

# 2023/11/07 追記
https://platform.openai.com/docs/assistants/overview

を読んで少しわかったけどAssistant APIのホントの良さは、
Threadによるメッセージ管理ができるようになったところなのかなと思いました。
なので、、、これはPlaygroundからではなく、実際にAPIを使って実装しないとピンとこないなって思いました。
また別の機械で確かめることにしよう。

# やってみる
リンク先の画面がこちら
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/bb3c2f37-90bb-f2be-2a6d-6875355c18aa.png)

画面左側のCreateをクリックして実行。
項目の概要は以下の通り
* Name
    * assistantの名称。なんでもいい
* Instructions
    * AIに何をしてほしいのかを書く。Assistant APIなので、「何を助けてほしいか？」を具体的に書くのが大事
* Models
    * 回答に使用するAIのモデルを選択。たくさんある
    * ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/288cea46-3caf-e6a9-c83a-f85b88fa0985.png)
* Tools
    * Assistants APIが現在対応している連携ツール
    * Function
        * Calling Functionの要領で外部呼出し関数の定義を書くことができる
    * Code Interpreter
        * 課金勢にはおなじみのCode Interpreterが使える
    * Retrieval
        * Fileをアップロードすることで、その情報も使って回答してくれる

以下の要領で設定してみました。Saveクリックして準備完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/1b831f1b-4cc2-e601-4725-29f3bc03441e.png)

ポップアップもできて正常終了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/db92ec3d-4692-88a0-54af-e6018e688469.png)

# 話しかけてみる
真ん中の入力欄に自己紹介をして Add and run クリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/44c02362-02c4-cde1-c577-6d6e5c73c33c.png)

返事が来た。英語はでてこない・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/124026b5-b254-6560-e8d3-49ac4ba67190.png)

もうちょっと話しかけてみたところ、返事をしてくれた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/c9e62fff-0f08-3d86-e992-f82b4b4f63c5.png)

次は英会話の授業らしく、英語で話しかけたら付き合ってくれるか試してみよう。
→めちゃちゃんと話しかけてくれた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/e0e120f5-7ace-7c60-6b0d-e20b0da77b2a.png)

最後に添削をお願いしたらちゃんと添削までしてくれた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/bc89e9e6-ac1c-4326-80f2-9123ff4770d0.png)

# 今日はここまで
きっとAssistant APIの良さはToolsが使えるところにあるんだろうと思ったけど
思った以上に簡単に試せたことに驚いた。

先日がんばってプログラムでFunctionsがやっと理解できたところなのに
あっという間に「それ、プログラム頑張って作らなくてもいいっすよ」と言われたような
うれしいような悲しいような気持ちになった。
【VSCode】You have deprecated linting or formatting settings for Python への対応

**実行環境**
Windows10
VSCode version 1.84

## はじめに
VSCode を [October 2023 (version 1.84)](https://code.visualstudio.com/updates/v1_84) にアップデートしたら、以下の警告がポップアップするようになりました。

![popup.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1409923/cd64a1b8-2213-09f8-ab6b-b9dc975c8dfb.png)


この警告への対応と内容について簡単に説明します。

## 対応
settings.json から、以下の文字で始まる設定をすべて削除し警告を解除します。

+ python.linting.*
+ python.formatting.*

ユーザ設定用 settings.json ファイルは、 VSCode のコマンドパレットから settingsjson 等で検索して開くことができます。

その後、必要に応じて Pylint や Flake8 の拡張機能をインストールします。

## 警告の内容
> You have deprecated linting or formatting settings for Python.

本記事のタイトルにしている上記の文は「Python という拡張機能で linting と formatting に関する非推奨の設定を使っている」と警告しています。（現在完了形ではなく現在形）

ポップアップ上の log のリンクをクリックすると VSCode のログが表示されます。

私の場合、以下のエラーログが見つかりました。

![log.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1409923/c82e20c0-6460-d168-3cad-132a3c429416.png)

<details><summary>テキスト版</summary>

[error] Following setting is deprecated: "python.linting.flake8Enabled"
[error] All settings starting with "python.linting." are deprecated and can be removed from settings.
[error] Linting features have been moved to separate linter extensions.
[error] See here for more information: https://code.visualstudio.com/docs/python/linting
[error] Please install "flake8" extension: https://marketplace.visualstudio.com/items?itemName=ms-python.flake8
</details>

上記の通り、2行目に「python.linting. で始まるすべての設定は非推奨で settings から削除できます」と明記されています。

また親切にも、詳細へのリンクや代替の拡張機能へのリンクも載っています。

## 警告の詳細情報
警告のポップアップに載っている詳細情報ボタンをクリックすると、以下のページが開きます。

https://github.com/microsoft/vscode-python/wiki/Migration-to-Python-Tools-Extensions

「Python という拡張機能の一部として提供していた機能を単独の拡張機能に分離しました（大意）」ということのようです。

掲載されている表には、削除した設定 (Setting Prefix) に対する代替策 (Alternative) が載っていて、Pylint や Flake8 などの機能を使いたい場合は、単独の拡張機能をインストールして使ってください等々が書かれています。

また、以下の VSCode リリースノートの Deprecated built-in linting and formatting features にもあるように、python.linting.* だけでなく python.formatting.* も非推奨の対象となっています。

https://code.visualstudio.com/updates/v1_84#_deprecated-builtin-linting-and-formatting-features

## おわりに
本記事のタイトルにある警告文に対する対応方法について書きました。

ここでは Deprecated を「非推奨」と訳しましたが、「廃止」という意味のほうが分かりやすいかもしれないですね。

それと、これを機にというわけではないですが、いっそ Ruff に乗り換えようかという迷いもあります。（というかたぶん乗り換えます）
Azure DevOps Wiki でアイコンを使いたい時は、Office UI Fabric Icons で探すと使える時もある

# 背景

Azure DevOps の Wiki で、Azure 関連のまとめを書いている。
で、Azure のボタンアイコンなんかをそのまま表示できないものか？と思ったら、似たようなものが使えたって話

# 概要

- Azure のボタンにアイコンが付いてたりする。例えばこういうの

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/f31f8ecb-4732-82a8-a12d-1c2ca9de1ff7.png)

- こういった Icon を Azure DevOps Wiki でもで使えるよってお話

## 実際、上記のメニューで試してみると、3/6 しか使えない :sob:

Reset とか普通に使えると思ったんですけどねぇ・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/34a6b2fe-e306-d012-5fb2-ce4bfc9c33b8.png)


# 名前取得サイト

以下のサイトで、Icon を探せます

[Office UI Fabric Icons](https://uifabricicons.azurewebsites.net/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/6591c191-eb69-d01d-0072-1b2491816f10.png)


# 使い方

1. [Office UI Fabric Icons](https://uifabricicons.azurewebsites.net/) にアクセス
1. 欲しいものを検索して、右クリックメニューから、Friendly Name をコピー<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/f20c3156-74f0-9fb5-ca35-5b9f70d56c43.png)

1. あとは、突っ込みたいところに、以下のような感じで突っ込む。<br>
   ```html: ms-Icon--{Friendly Name}
   <font class="ms-Icon--{Friendly Name}"></font>
   ```

   - 例）上で検索した Build の例<br><blockquote>\<font class="ms-Icon--Build">\</font ></blockquote>上記の例だとこんな感じ　⇒　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/d2d09b0d-3f88-a8d8-5721-523ddc3e9fd8.png)



# あとがき

全部使えるわけじゃないので、そもそもの体系が違うんだろうとは思うが、その辺はよくわかってない・・ :sob:
CDN版Vue3で単一ファイルコンポーネントを作る

## はじめに
Vueでそこそこの規模のサイト作ろうとするとき、`index.html`にすべての処理を書き下すのではなく、コンポーネント別に`.vue`ファイル、作りたいですよね。
Vue-CLIなら手順がいくらでもありますが、CDNの場合そんなに情報が見当たりません。
[こちら](https://www.chaordic.co.jp/memorandum/chaordicdesign/46/)はありますが、`http-vue-loader`を用いているものはVue2限定です。

ということで、テンプレート化します。

## 結論
```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
    <title>タイトル</title>
    
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue3-sfc-loader/dist/vue3-sfc-loader.js"></script>
    
   </script>
</head>
<body>
    <div id="app"></div>

    <script>
        //vue3-sfc-loader初期設定
        const options = {
            moduleCache: {
                vue: Vue
            },

            //read subdirectory vue component file.
            async getFile(url) {
                
                const res = await fetch(url);
                if ( !res.ok )
                throw Object.assign(new Error(res.statusText + ' ' + url), { res });
                return {
                getContentData: asBinary => asBinary ? res.arrayBuffer() : res.text(),
                }
            },
            
            addStyle(textContent) {
        
                const style = Object.assign(document.createElement('style'), { textContent });
                const ref = document.head.getElementsByTagName('style')[0] || null;
                document.head.insertBefore(style, ref);
            },
        }
        const { loadModule } = window["vue3-sfc-loader"];
        
        //Appコンポーネントをマウント
        const app = Vue.createApp(
            Vue.defineAsyncComponent(
                () => loadModule("./src/components/App.vue", options)
            ),
        )
        app.mount('#app');
    </script>
</body>
</html>
```

慣習に倣って、`root`のdivを`App`コンポーネントにした例をご紹介していますが、マウントの処理は用途にあわせて編集して大丈夫です。

```vue: App.vue
<template>

</template>

<script>
    export default Vue.defineComponent({
        name: 'App',
        components: {
            "COMPONENT": Vue.defineAsyncComponent(() => loadModule("PATH.vue", options))
        },
    })
</script>

<style>
</style>
```

`.vue`ファイルはCLIと同じように構成して大丈夫ですが、**コンポーネントの読み込み**は`Vue.defineAsyncComponent(() => loadModule("PATH.vue", options))`を用いることだけ注意してください。

## 解説
[vue3-sfc-loader](https://github.com/FranckFreiburger/vue3-sfc-loader)を使います。これにより、CDNでも`.vue`ファイルを読み込むことができます。
しかし、初期設定が`http-vue-loader`と比べてメンドウなので、`index.html`の初期設定のスクリプトはテンプレートと考えて大丈夫です。

[i18nで多言語対応するにはこちらから](https://qiita.com/konbraphat51/items/9cdcc1ceacb3c736c9be)
【CSS・学習ログ4】ボックスモデルについて

<font color=gray>教材：侍テラコヤ『HTML/CSSの基礎を学ぼう』https://terakoya.sejuku.net/programs/51/chapters</font>

## ボックスモデルとは
![ボックスモデル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3520365/38d6fc20-9fba-3bb6-27eb-205d8d754c30.png)

- content：要素の中身
- padding：borderの内側の余白
- border：コンテンツ周辺の境界線
- margin：borderの外側の余白
※初期値はいずれも0

#### (1)border
![スクリーンショット 2023-11-05 063234.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3520365/1eddf96a-e903-8e7d-1df9-bf112e06272a.png)
```css
p {
	border: solid 5px yellow;
	padding: 10px;
	margin: 10px;
}
```
#### (2)padding
boderの内側に大きな余白を取ってみる。
![スクリーンショット 2023-11-05 063735.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3520365/8ecb2790-188f-8f00-9c98-0262e108a378.png)
```css
#second-paragraph{
	padding: 100px;
	border: solid 5px yellow;
}
```
#### (3)margin
borderの外側に余白を取ってみる。
※下に位置する要素とぶつかり合い、**相殺**という現象が起こることがあるため注意が必要である。被ってしまった場合、値が大きいほうが優先される。
![スクリーンショット 2023-11-05 063923.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3520365/551ad007-5ca8-53c4-41ff-98aea117f85d.png)
```css
#second-paragraph{
	margin: 100px;
	border: solid 5px yellow;
}
```
#### (4)余白の上下左右を指定する
4つの値を上から時計回りで書く。
```css
#second-paragraph{
	padding: 20px 15px 10px 5px;
	margin: 15px 10px 5px 0px;
	border: solid 5px yellow;
}
```
#### (5)余白の上下と左右を指定する
上下・左右の順で区切る。
```css
#second-paragraph{
	padding: 20px 10px;
	margin: 40px 20px;
	border: solid 5px yellow;
}
```
#### (6)上下左右いずれか１部だけを指定する
- padding-top/margin-top(上)
- padding-bottom/margin-bottom(下)
- padding-left/margin-left(左)
- padding-right/margin-right(右)
```css
#second-paragraph{
	padding-left: 20px;
	padding-right: 40px;
	margin-top: 20px;
	margin-bottom: 40px;
	border: solid 5px yellow;
}
```
#### (7)marginを利用して要素を中央揃えにする
左右にautoで余白を持たせて、要素を中央に寄せる。
![スクリーンショット 2023-11-05 065638.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3520365/7092e6f6-c069-f111-ed18-08a2d85a7957.png)
```css
div {
	margin-left: auto;
	margin-right: auto;
	width: 100px;
	height: 100px;
	background-color: red;
}
```
擬似言語プログラム

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/b2c47466-a6e9-7f68-a797-964baa61e419.png)
１：条件分岐
プログラム３では、起床した時の時刻が８時より前であれば、朝食を食べて（４行を実行）から家を出ます。八時以降の場合には、４行は実行せず、代わりに、６行を実行します。つまり、お茶を飲んでから家を出ます。

「プログラム３」
（行番号）
１：getup() //起床する
２：time　←　get_current_hour() //現在時を取得し、timeに格納する
３：if (time が　８　未満)
４：　  eat_breakfast() //朝食を食べる
５：else
６：　have/tea() //お茶を飲む
７：endif
８：leave_home() //家を出る

プログラム４では、起床した時の時刻が８時より前であれば、朝食を食べて（４行を実行）から家を出ます。８時〜９時までの間の場合は、お茶を飲んで（６行を実行）から家を出ます。９時以降の場合は、上司に連絡を入れて（８行を実行）から家を出ます。６行を実行するのは、８　≦　time < 9の時であると判断できるようになることが大切です。

「プログラム４」
（行番号）
１：getup() //起床する
２：time　←　get_current_hour() //現在時を取得し、timeに格納する
３：if (time が　８　未満)
４：　  eat_breakfast() //朝食を食べる
５：elseif(time　が　９未満)
６：　have/tea() //お茶を飲む
７：else
８：　call_boss() //上司に連絡を入れる
9：endif
１０：leave_home() //家を出る
CretateProcess()で標準出力をファイル出力

```c:sample.c
#include <windows.h>


int _tmain(int argc, _TCHAR* argv[])
{
    // 子プロセスが親プロセスから開いているハンドルを継承できるようにする
    SECURITY_ATTRIBUTES sa;
    sa.nLength              = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle       = TRUE;   
    
    HANDLE h1 = CreateFile(_T("out.log"),
        FILE_APPEND_DATA,    // ファイルを追記モードで開く
        FILE_SHARE_WRITE | FILE_SHARE_READ,  // 後からファイルを開くプロセスは読込と書込みを許可
        &sa,    // 継承しなくてよい場合は NULL で良いらしい
        OPEN_ALWAYS,   // ファイルがあれば開く、なければ作る
        FILE_ATTRIBUTE_NORMAL,    // 通常ファイルとして作成
        NULL );

    PROCESS_INFORMATION pi; 
    STARTUPINFO si;
    BOOL ret = FALSE; 
    DWORD flags = CREATE_NO_WINDOW;

    ZeroMemory( &pi, sizeof(PROCESS_INFORMATION) );
    ZeroMemory( &si, sizeof(STARTUPINFO) );
    si.cb = sizeof(STARTUPINFO); 
    si.dwFlags |= STARTF_USESTDHANDLES;
    si.hStdInput = NULL;
    si.hStdOutput = h1;   // 標準出力をリダイレクト
    si.hStdError = h1;    // 標準エラー出力をリダイレクト

    TCHAR cmd[]= TEXT("Test.exe 30");
    ret = CreateProcess(NULL, cmd, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi);

    if ( ret ) 
    {
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
        return 0;
    }

    return -1;
}
```
SpannerとPolarDBの比較

# spannerの罠
## 1. Spanner自身にAuto Increment機能はない
- 主キーをシーケンシャルな値にすることはパフォーマンスの劣化を生みます。
- つまりアプリでシーケンシャルなIDを生成・Insertすることも好まれません。

みなさんが現在運用しているサービスで使用されているDBではAuto IncrementされたシーケンシャルなIDをPrimary Keyとして割り当てたテーブルを使用することが多いのではないでしょうか？SpannerではこのようなシーケンシャルなPrimary Keyが割り当てられているとホットスポットという問題が発生してしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/281b18fe-9c21-325e-7aef-4ce11ee193fc.png)

SpannerではPKを元にレコードが並べられており、それらがスプリットと呼ばれる分散ストレージに分割されて 各ノードに割り当てられています。シーケンシャルなPKを利用すると新しいレコードは必然的に最後のスプリットに追加されてしまい、特定のノードへ負荷が集中してしまいます。これがホットスポットと呼ばれる現象です。これでは負荷分散できないことがわかりますね。

つまり、 シーケンシャルなPKを利用しているアプリケーションはそのままSpannerに持っていくことはできません。既存のテーブルにシーケンシャル出ないPK(UUID)を追加で修正する必要があります。

例えば、ユーザ管理テーブルであればユーザIDがシーケンシャルなPKとして扱われることが多いと思いますが、そこに公式のベストプラクティスであるVer4のUniversally Unique Identifier（UUID）で発行したIDをPKとして追加することでホットスポットの発生を防ぐことができます。
このようにSpannerを利用する場合はスキーマ設計のベストプラクティスに近づけるように課題をつぶしていくことが必須となります。


## 2. spannerに対応していないweb framework(厳密に言うとORM)はまだ多いです。
Spanner でサポートされているすべてのオープンソース ORM一覧

https://cloud.google.com/spanner/docs/drivers-overview?hl=ja

PHPやPerlなどは未対応しているため、PHPやPerlのアプリケーションでSpannerを利用するには自前でORMを実装する必要があります。

## 3. トランザクションの挙動はMysqlとだいぶ異なる
SpannerのRead-Write Transactionでは，読みる行に共有ロックがかかります。これはInnoDBでトランザクション分離レベルをSerializableに設定した場合と近い挙動です。Serializebleでは，もちろんダーティリード，ファジーリード，ファントムリードが発生しません。かわりに，ロックの獲得待ちで処理がブロックされるため，性能は低下します。SpannerではRead-Only Transactionを導入することで，性能の低下を防ぎつつトランザクションの高い分離性を担保しています。MySQLを前提としたトランザクション設計をそのままRead-Write Transactionにしても整合性の面では問題なさそうですが，Spannerの性能を最大限引き出すためには，Read-Only Transactionを活用できるような設計・実装を意識する必要があります。

https://recruit.gmo.jp/engineer/jisedai/blog/spanner_introduction/


# まとめ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/eb9e6721-7077-0082-5ed1-ab6684defd90.png)

SpannerはSQLのインタフェースを備えておりトランザクションをサポートしているため，シンプルな処理ではMySQLのようなRDBをそのまま置き換える形でも使うことができるでしょう。また，トランザクションの分離性も高いため，考慮不足により不整合が発生する危険性も低そうです。

ただし，分離性を担保するためにRead-Write Transactionは必ず共有ロックを取ったり，ロックの範囲が広かったりといった弱点もあります。
そのため，MySQL向けに設計したトランザクションをそのまま使用すると思わぬパフォーマンス低下を招く危険性があります。
単なるスケーラビリティ，アベイラビリティに優れたRDBの上位互換ではありません。
Spannerのトランザクションの特性をよく理解した上で，Spannerに合わせたトランザクション設計を行う必要があります。
TypeScriptからC#へ変換で、はまったポイント

TypeScriptからC#へ、プログラム（[NormalizeJapaneseAddressesNET](https://github.com/mikihiro-t/NormalizeJapaneseAddressesNET)）を移植していました。
はまったところをメモします。

## 正規表現の解釈が異なる
TypeScript(JavaScript)と、.NETとでは、正規表現の解釈が異なる場合があります。

- [JavaScriptと.NETのRegexは解釈が異なる（言語によって異なる）](https://qiita.com/hiro_t/items/b5963812544c6479dd2b)

## 正規表現でのReplace
JavaScriptでは、次の場合、１回のみの置換です。C#で対応するコードは工夫が必要です。

- 正規表現で、文字列のReplaceを行う
- 正規表現は、gフラグ（globalフラグ）が無い。

#### TypeScript
```typescript
const _pref = pref.replace(/(都|道|府|県)$/, '')
```


#### C#
```csharp
var r = new Regex("(都|道|府|県)$");
var _pref = r.Replace(pref, "", 1);
```
1は置換する回数です。1回のみ置換します。

- [RegExp.prototype.global](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/RegExp/global)
- [How to Regex search/replace only first occurrence in a string in .NET?](https://stackoverflow.com/a/39072686/9924249)

## number型
#### JavaScript

numberの、整数の場合の最大値・最小値です。
```javascript
const biggestInt = Number.MAX_SAFE_INTEGER; // (2**53 - 1) => 9007199254740991
const smallestInt = Number.MIN_SAFE_INTEGER; // -(2**53 - 1) => -9007199254740991
```

numberを、整数として扱い、整数としての範囲に対応するなら、C#では、integerでは範囲が狭く、代わりにlongを利用するので良いはずです。

#### C#
```csharp
int -2,147,483,648 ～ 2,147,483,647
long -9,223,372,036,854,775,808 から 9,223,372,036,854,775,807
```
- [Number](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number)

## 安定ソート
### TypeScript

```typescript
towns.sort((a, b) => {
    let aLen = a.town.length
    let bLen = b.town.length
    return bLen - aLen
})
```
JavaScriptの、ArryのSortは、ECMAScript 2019から、[安定ソート](https://ja.wikipedia.org/wiki/%E5%AE%89%E5%AE%9A%E3%82%BD%E3%83%BC%E3%83%88)です。

#### C#
これを、C#にそのまま移植すると次になります。しかし、安定ソートではありません。
```csharp
towns.Sort((a, b) =>
  {
      var aLen = a.town.Length;
      var bLen = b.town.Length;
      return bLen - aLen;
  });
```

安定ソートにするには、OrderByを利用します。

```csharp
var comparer = new TownsComparer();
towns = towns.OrderBy(x => x, comparer).ToList();

public class TownsComparer : IComparer<SingleTown>
{
    public int Compare(SingleTown a, SingleTown b)
    {
        var aLen = a.town.Length;
        var bLen = b.town.Length;
        if (bLen > aLen)
            return 1;
        else if (aLen == bLen)
            return 0;
        else
            return -1;
    }
}
```
- [Array.prototype.sort()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
- [Array の sort を越えてゆけ (JavaScript)](https://qiita.com/nagtkk/items/7ee8f312cd82858d0daa)
- [Sort in C# don't save the place](https://stackoverflow.com/a/12402519/9924249)
DockerにApacheをインストールして起動させる方法

## 参考サイト
　Dockerについて

 https://knowledge.sakura.ad.jp/13265/

　Apacheについて
 
 https://wa3.i-3-i.info/word12465.html

## 作業内容

### 1.systemctl コマンドを使用してDockerが起動しているかステータス確認する。
```
$ systemctl status docker
● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset>
     Active: active (running) since Tue 2023-09-05 10:28:57 UTC; 8min ago
TriggeredBy: ● docker.socket
       Docs: https://docs.docker.com
   Main PID: 125205 (dockerd)
      Tasks: 14
     Memory: 26.4M
        CPU: 465ms
     CGroup: /system.slice/docker.service
             mq125205 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/co>
```
### 2.Apacheコンテナを作成する
ここで使用するオプションについて
- **--name**
指定した名前でコンテナを作成する事が出来る
- **-p 8080:80**
ホストサーバのポート8080とコンテナのポート80を指定している
- **-v /home/user/website/:/usr/local/apache2/htdocs**
ホストサーバの /home/user/website/ ディレクトリを
Apacheコンテナの /usr/local/apache2/htdocs をマウント先として指定している
- **httpd**
インストールするDockerイメージを指定している

※先頭のsudoはrooy権限で作業する場合は不要

```
$ sudo docker run -dit --name apache-container -p 8080:80 -v /home/user/website/:/usr/local/apache2/htdocs/ httpd
```
### 3.Apacheコンテナが稼働している事を確認する
- **sudo docker ps**
現在稼働中のコンテナの一覧が表示される
※先頭のsudoはrooy権限で作業する場合は不要
```
$ sudo docker ps
CONTAINER ID   IMAGE       COMMAND              CREATED          STATUS          PORTS                                   NAMES
68533dfbe5ad   httpd   "httpd-foreground"   14 seconds ago   Up 13 seconds   0.0.0.0:8080->80/tcp, :::8080->80/tcp   apache-container
```
### 4.ブラウザで Server-IP:8080 を指定して稼働しているか確認する
apacheの起動画面が表示されたら作業完了。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616387/ea476885-db43-afb7-2ec4-a3596ff26d13.png)
AWSでの社内限定のWordPress管理画面が遅い！？速度改善方法を調査！

## 導入部
AWS上で運用する社内専用のWordPressサイトは、セキュリティ面で優れている一方で、管理画面が亀のように遅くなることがあります。そんなとき、何が原因で、どう解決すればいいのでしょうか？今回は、そんな切実な問題を抱えた私の体験を元に、具体的な解決策をシェアしたいと思います。

## 問題の発生
投稿ページなどはサクサク動くのに、なぜかダッシュボードやプラグインページの表示だけが異様に遅い。とにかく遅い。初期対応として考えられるプラグインの停止やテーマの変更も試してみましたが、大きな改善は見られませんでした。

## 原因調査と一時対応
次に取り組んだのが、「[Query Monitor](https://ja.wordpress.org/plugins/query-monitor/)」というプラグインを使ったパフォーマンスの監視です。その結果、ダッシュボードではブラウザやPHPのバージョンをチェックするプロセス、プラグインページではプラグインの更新をチェックするプロセスがタイムアウトを起こしていることが明らかになりました。

<br>

![2023-11-07 201750.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487238/487a83b5-4a3c-4b43-679e-1ecf6f2fb4b5.png)
_ダッシュボードの表示には元々10秒もかかっていました（タイムアウト5秒）_

<br>

![2023-11-07 201844.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487238/9002286a-c27d-b720-f226-ed856b62d954.png)
_プラグインページの表示には元々8秒もかかっていました（タイムアウト4秒）_

## タイムアウト設定の変更
デフォルトのタイムアウト時間は4~5秒。これを1秒に変更するコードをfunction.phpに記述することで、遅延はある程度改善されました。しかし、これはあくまでも一時的なバンドエイドに過ぎません。他のプロセスに影響を与えかねないリスクも抱えています。

```PHP:function.php
add_filter('http_request_args', 'custom_http_request_args', 100, 1);
function custom_http_request_args($r) {
    $r['timeout'] = 1;
    return $r;
}
```

## 根本的な解決策
本来であれば、WordPressが外部通信を行う際に必要な接続のみを許可するセキュリティグループ設定を見直したり、AWSのプロキシサーバーを経由させるなどの方法が考えられます。これらの方法でより安全で、サイト運用において持続可能な改善になるでしょう。

## 結論
タイムアウトを短く設定することで一時的にスピードは向上しましたが、これには応急処置です。表示スピードはまだ許容範囲であるため、この状態を「当面の解決策」と位置付けつつ、長期的な解決策を模索することをお勧めします。
C#で一時的にファイルを作成して編集、その後削除する

# 経緯

一時的にCSVファイルを作成し、外部に送信した後に削除する機能を作ることになった。
ファイルの作成と編集が別々に書いてある記事が多かったが、作成してそのまま編集できる方法があるようなので、備忘録代わりに。

# 環境

言語：C#
バージョン：.NET Framework 4.8

# 仕様の概要

1. C#のResourcesフォルダの中にsample.csvを作成
1. 中身のデータを書き加えていく
1. 外部にファイルを送信する（この記事では中略）
1. ファイルを削除する

# コード

完成形は以下です。
この記事では<code>File.CreateText</code>を使用します。

```csharp
List<string> values = new List<string>()
{
    // ID, 氏名, 誕生日, 性別
    @"""1"",""田中太郎"",""1900/04/01"",""男""",
    @"""2"",""中田花子"",""1900/05/21"",""女""",
    @"""3"",""高橋さとる"",""1900/10/03"",""男""",
}

// 1. C#のResourcesフォルダの中にsample.csvを作成
string filePath = "~/Resources/sample.csv";
string physicalPath = HostingEnvironment.MapPath(@filePath);

// 2. 中身のデータを書き加えていく
using (StreamWriter sw = File.CreateText(physicalPath)) 
{
    foreach (string item in values)
    {
        sw.WriteLine(item);
    }
}

// 3. 外部にファイルを送信する（この記事では中略）

// 4. ファイルを削除する
File.Delete(physicalPath);
```

続いて簡単に解説していきます。

```csharp
// 1. C#のResourcesフォルダの中にsample.csvを作成
string filePath = "~/Resources/sample.csv";
string physicalPath = HostingEnvironment.MapPath(@filePath);
```

ここで、どこにどんな名前でファイルを作るかを指定しています。
<code>HostingEnvironment.MapPath</code>を使うことで、サーバー上の物理パスを取得しています。

```csharp
// 2. 中身のデータを書き加えていく
using (StreamWriter sw = File.CreateText(physicalPath))
{
    foreach (string item in values)
    {
        sw.WriteLine(item);
    }
}
```

<code>File.CreateText</code>でファイルを作成しています。同じ名前のファイルがあった場合は上書きされます。
その後、<code>StreamWriter.WriteLine</code>を使って一行ずつデータを書き込んでいます。

```csharp
// 4. ファイルを削除する
File.Delete(physicalPath);
```

そのまんまですが、先ほど作成したsample.csvファイルを削除しています。
ファイルが見つからない場合でも、特にエラーは起きませんでした。

# その他

文字エンコーディングを指定する方法についても記事にしました。

https://qiita.com/moto-na/items/531f2a674f77d7665bf2

# 参考

https://learn.microsoft.com/ja-jp/dotnet/api/system.io.file.createtext?view=net-7.0

https://learn.microsoft.com/ja-jp/dotnet/api/system.io.file.delete?view=net-7.0

https://learn.microsoft.com/ja-jp/dotnet/api/system.io.file.create?view=net-7.0

https://learn.microsoft.com/ja-jp/dotnet/api/system.io.streamwriter.writeline?view=net-7.0

https://qiita.com/amam0102/items/469adb2b8fce1e46ad80

https://saitokou.com/archives/228
CodeArtifactの超詳細解説

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

この記事ではCodeArtifactとはどういうサービスで何ができるのかを超詳細にまとめています。

具体的には以下流れで説明します。
- AWS CodeArtifactとは
- AWS CodeArtifactの仕組み
- AWS CodeArtifactのセキュリティ
- AWS CodeArtifact for Advance

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

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

# AWS CodeArtifactとは
AWS CodeArtifactはアーティファクト管理ツールです。

ちなみに、アーティファクト管理とは相互に依存するソフトウェアパッケージの依存関係を管理することです。
そして、代表的なパブリックのアーティファクトリポジトリにはMavenやnpmなどが存在します。

AWS CodeArtifactはこれらのリポジトリと連携して独自のリポジトリを作ることができるサービスです。

![](https://storage.googleapis.com/zenn-user-upload/0b9c81d35589-20231107.png)

企業で開発を行っていると、承認されたパッケージのみ利用させたい、という場面が多々出てきます。
その時にAWS CodeArtifactを利用すると、簡単にこの要件を実現できます。

また、EventBridgeと連携が可能なのでCodeArtifactでパッケージ更新があったときにイベント駆動での通知やパイプラインのキックが可能です。

![](https://storage.googleapis.com/zenn-user-upload/2ff4fa672da5-20231107.png)

これによって、パッケージが更新されたら自動でアプリケーションを再ビルド、再デプロイできるようになるので運用コストを下げたいと思っている人は実装の価値が非常に大きいです。

# AWS CodeArtifactの仕組み
## 外部接続
AWS CodeArtifactから外部のリポジトリを見に行くためには外部接続を作成する必要があります。
これによりCodeArtifact内に存在しないパッケージを取得することが可能になります。

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

注意点としては1つのリポジトリにつき1つの外部接続しか作成できない点です。
そのため、npmとMavenを1つのリポジトリに接続することはできません。

これを実現したい場合には後述するアップストリームリポジトリの仕組みを活用するのがベストプラクティスです。

## ドメイン
ドメインはAWS CodeArtifactのリポジトリを仮想的に束ねるグループのようなものです。
ドメインはクロスアカウントで構築することができ、ドメイン内ではパッケージシェアが可能です。

つまり、各アカウントで共通して利用するパッケージを一か所で持つだけで済むようにできるためパッケージを保存するためのストレージコストの削減につながります。

# AWS CodeArtifactのセキュリティ
AWS CodeArtifactはクロスアカウントでのパッケージ読み取りが可能です。
デフォルトではクロスアカウントで読み取りできないので、実装したい場合にはCodeArtifactのリソースポリシーでアクセスを許可しましょう。

また、ドメイン内のすべてのアセットとメタデータはKMSを用いた暗号化が施されます。

# AWS CodeArtifact for Advance
## アップストリームリポジトリ
AWS CodeArtifactのリポジトリは多段構成にすることが可能です。
これは複数の外部リポジトリを1つのリポジトリのように扱いたい場合に有用です。

AWS CodeArtifactのリポジトリと外部接続のリポジトリは1対1にする必要があります。
しかし、実プロジェクトではnpmも見たいしMavenも見たいということはよくある話です。

そこで使うのがアップストリームリポジトリです。

![](https://storage.googleapis.com/zenn-user-upload/6fea63c7964b-20231107.png)

外部リポジトリを見に行くリポジトリと別にもう1つリポジトリを作成し、それを見に行くことであたかも複数の外部リポジトリを見に行くことができるような作りにすることが可能です。

## リテンション
アップストリームを用いた多段構成を作った場合、外部接続している側であるアップストリームリポジトリが更新されても開発者が参照している側であるダウンストリームリポジトリはその影響を受けません。

そのため、ダウンストリームリポジトリを更新したければ再度、新しいパッケージを要求する必要があるので注意しましょう。

また、中間リポジトリはパッケージを保持しない点も注意しましょう。

# まとめ
この記事ではCodeArtifactとはどういうサービスで何ができるのかを超詳細にまとめました。

- AWS CodeArtifactとは
- AWS CodeArtifactの仕組み
- AWS CodeArtifactのセキュリティ
- AWS CodeArtifact for Advance

次回はAmazon CodeGuruを超解説します。
ロボット開発にDockerを使う初学者向け資料まとめ

# はじめに

ロボット開発 (ROS/ROS2開発)　のためにDockerを使いたいが、何から勉強したらいいか分からない方のために、Docker初心者に参考になりそうな資料や記事などのリンクをまとめた。


# 書籍

### マンガでわかるDockerシリーズ

わかばちゃんと学ぶシリーズ　
現在4巻まで出ている。

マンガでわかるDocker ① 〜概念・基本コマンド編〜

https://booth.pm/ja/items/825879

マンガでわかるDocker ② 〜開発環境を作ろう編〜 

https://llminatoll.booth.pm/items/1036317

マンガでわかるDocker ③ 〜AWS編〜

https://llminatoll.booth.pm/items/1242542


マンガでわかるDocker ④ 〜Compose編〜 

https://llminatoll.booth.pm/items/3109503

### 実践 Docker - ソフトウェアエンジニアの「Docker よくわからない」を終わりにする本


https://zenn.dev/suzuki_hoge/books/2022-03-docker-practice-8ae36c33424b59

Zennの書籍、無料で読める。
今まで見た日本語の解説資料の中で一番分かりやすかった。



# 動画

###  ロボットシステム学第12回（Docker）


千葉工業大学　上田隆一先生の  ロボットシステム学　講義動画の一部

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



### Docker Basics for Robotics | ROS2 Developers Open Class #154

The Construct のOpen Classの動画　（英語）

https://youtu.be/kxAF-Pye8rI?si=3uBnjDInYK1tI5Qn


# ROS 開発において参考になりそうな資料


### 【連載 ROS Tips】ROS開発におけるDocker活用テクニック

https://tech.aptpod.co.jp/entry/2023/09/25/170000






## ROS/ROS2 環境構築についての記事

- Docker上でGUIのROS1/ROS2を一瞬でセットアップする方法

https://qiita.com/karaage0703/items/957bdc7b4dabfc6639da

- DockerでGPUやGUIを使えるROSの環境構築

https://www.techlife-hacking.com/?p=1117


- WSL2とDockerでWindowsにROS2環境を作る＋vscodeで開発できるようにする＋VNCなしでGUI(rqt, rviz2)を使う

https://mu-777.hatenablog.com/entry/2022/05/22/170738

# その他

VSCode Dev Containerを使った開発環境構築


https://blog.kinto-technologies.com/posts/2022-12-10-VSCodeDevContainer/



# おわりに

Dockerに関する書籍はたくさんあるがインフラエンジニア向けに書かれていてロボット開発のためには直接参考にならないため、なるべく無料の媒体でロボット開発目的でDocker使いたい人に参考になりそうな資料をまとめました。

Dockerの概要を理解したあとは、以下の要領で習得していくことをおすすめします。
1. 既存のDockerイメージからコンテナを作成しコマンドの使い方を覚える
2. 自分でROS環境のDockerfileを作ってみる
3. Dockerコンテナ内でGUI,USBデバイス, Ethernetデバイスを使ってみる
4. Docker HubやVS Code の Dev Containerなどの関連ツールを使ってみる

もし他に参考になりそうな資料がありましたらコメントで教えていただければ追加いたします。
Cameraであそぼう(距離・ヒートマップ）

# 作ってみたのが距離（短距離）とヒートマップを表現するCamera

https://github.com/mi-kaneyon/man-yard/tree/main/singlesterocam

https://github.com/mi-kaneyon/man-yard/blob/main/singlesterocam/samples.png

# データセットを作る

```Ubuntu:ターミナル
python  correct.py

```
これですくリプ内の指定ディレクトリにデータセットがそろいます。
- 距離をベースに数秒おきに撮影します。これが正確性を決めるので、しっかり撮影してください。

# 学習モデルを作る

```Ubuntu:ターミナル
python train.py

```
:::note info
インフォメーション
学習モデルが凝縮されたpthファイルが作られます。

:::

いざ撮影

:::note info
映りは人間がはっきり映るヒートマップ。
- 幼児には好評でした。

:::

## 進化させてくれる方に期待。
‐ 自分でも頑張りますけど！



:::note info
ステレオカメラはすぐそばにあるけど、上司に嫌われてるから触れない。
- だれか仲間がほしいな
- 製造時代のノウハウを持つ優秀な仲間はいるけど、お金がない・・・(-_-;)

:::
React の Sass フォルダー構造

フォルダー構造
以下はわかりやすくするために簡略化してありますが、本質的な構造は同じです。 実物をご覧いただけます

/src
• ———— /components
•      |———— /NominationContainer
•            |———— NominationContainer.js
•            |———— nominationContainer.scss  <—— (section 2)
•
•
• ———— /sassStyles  <—— (section 1)
•      |————  _animations.scss
•      |————  _functions.scss
•      |————  _global.scss
•      |————  _mixins.scss
•      |————  _typography.scss
•      |————  _variables.scss

![Captura de tela de 2023-11-07 11-24-55 copy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3587964/63a5fac0-8f48-234e-79b5-e05852059208.png)
Denoでプログレスバーを表示する


# はじめに

おにぎりくれる奴だいたい友達、[にわのわ](https://twitter.com/niwa_nowa)です。
本アドベントカレンダーのモチベーションを保つために、
アドベントカレンダーの進捗を表示するプログレスバーを作ることにしました。
プログレスバー、見てるとテンションアがるよね？

# 作ったもの
ソースはこちら

https://github.com/niwanowa/DenoAdventBar

![bar-kansei.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590707/a0e8eee9-ba6c-c596-8d35-63363f09b13b.gif)

# 要件

- ツイッターで呟きたいので1画面で収まるか、140字に収まること。
- 全体進捗と各記事の進捗を表示したい。
- 各記事の進捗は["タイトル未定", "タイトルだけ決まった" ,"書いてる","書いた"]の4段階で表現したい。

# 素材

もうライブラリあった。

https://deno.land/x/progress@v1.3.9

ということでREADMEにあったサンプルを動かしてみる
![bar-example.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590707/a2b27c0c-cb88-a653-daa0-9a28e7bdd953.gif)

いいじゃん！

# 作る

これから良い感じにカスタムしていきます。

同一ディレクトリにあるprogress.jsonを読みます。 jsonの形はこんな感じ。

```progress.json
"dayNN": {
        "tittle": "未定",
        "progress": "タイトル未定"
    },...
```

あとはサンプルコードをもとにプログレスバーの表示を行います

```main.ts
  function showProgress(progress: Progress[]) {
  if (completed <= total){
    completed += 1;
    bars.render(
      progress.map(p => ({ completed:(p.progress >= completed) ? completed:p.progress, total,  text: p.title }))
    )
    setTimeout(function () {
      showProgress(progress);
    }, 100);
  }else{
    bars.end();
  }
}
```
ポイントとしてはelseできちんとbars.end()を呼ぶことです。
でないとこんな感じで閉まらない終わり方になってしまいます。
![bar-kimoi.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590707/5280bdb1-de23-cebc-ceeb-b82da8bbd2a4.gif)

~~プログレスバーなのに完了しないことを想定してないからね…~~

# まとめ

プログレスバー、見てるとテンションアがるよね？
SSMのポートフォワーディング機能を利用してプライベートなECSにブラウザからアクセス

## 背景
プライベートに置いたECSにデプロイしたAPIについて、ブラウザからSwaggerUIで確認したいという要望があったので対応しました。
DBへのポートフォワーディングについての記事はよくありましたが、特殊な行為なのか、ECSへの接続の記事が見つけられなかったので、簡単ですが残しておきます。
(他に、ClientVPNを利用する方法とWindowsサーバーにSMMFleetManagerでRDP接続する方法も試したのですが、ClientVPNは料金が高い&ローカルにインストールするツールの挙動が安定せず、RDP接続はインスタンスタイプでそれなりの性能にしないとまともに使えず断念しました。。)

## 前提
- プライベートサブネットに、内部ALBのターゲットとしてECSを作成
- プライベート環境にEC2を作成し、セキュリティグループは開けずにセッションマネージャからアクセス可能

## 対応
```
# ポートフォワード
# ※9999は任意の値
aws ssm start-session \
--target 踏み台サーバーインスタンスID \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters '{"portNumber":["80"],"localPortNumber":["9999"],"host":["内部APIドメイン"]}'

# ブラウザでAPIにアクセス
http://localhost:9999/docs
```

## 構成図
![名称未設定ファイル.drawio (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710784/2a7e87c6-f3fc-db26-eab9-ee6191233e08.png)

## 参考
https://aws.amazon.com/jp/blogs/news/use-port-forwarding-in-aws-systems-manager-session-manager-to-connect-to-remote-hosts-jp/

どなたかの参考になれば幸いです！
【Laravel入門】Laravel sailとは？Laravel sailで環境構築までしてみる


Laravelは通常LEMPと呼ばれる開発環境をDockerで構築してその上で動作させます。
ただ、Dockerに自分でLinux・Nginx・Mysql・PHPをインストール＆設定するには学習コストが意外と高くてめんどくさい。。

Laravel sailはターミナルでコマンド実行するだけで、DockerでLaravel環境を一発で作ってくれる便利なコマンドラインツールです。

https://readouble.com/laravel/8.x/ja/sail.html

公式サイトを参考にLaravel sailをインストールしてみます。
（ここからはDockerはインストール済みの想定で進めます）

↓Dockerのインストールがまだの方はこちら
https://www.docker.com/products/docker-desktop/

# Laravel sailのインストール

Laravel sailをインストールするディレクトリを予め作成しておきます。
今回はtakegonsフォルダを作成しました。
```
mkdir takegons
cd takegons
```
``mkdir : ディレクトリを新規で作成するコマンド「mkdir ○○○」（MaKe DIRectory）``
`cd : ディレクトリを移動するコマンド「cd ○○○」（Change Directory）`

takegonsディレクトリへ移動したらLaravel sailをインストールします。
「example-app」の部分は任意で好きなプロジェクト名に変更してください。
```
curl -s "https://laravel.build/example-app" | bash
```
``
curl : 指定したURLに対して様々なことができるコマンド「curl http://example.com」
（今度curlについてもまとめます）
``

途中でパスワードが求められたらPCのパスワードを入力。

```
Please provide your password so we can make some final adjustments to your application's permissions.
```
下記メッセージが出たらインストール完了です。（ちょっと時間かかりました）
```
Thank you! We hope you build something incredible. Dive in with: cd example-app && ./vendor/bin/sail up
```

「example-app」ディレクトリへ移動してsailを立ち上げるコマンドを実行します。
```
cd example-app
./vendor/bin/sail up
```
ブラウザで「http://localhost/」 へアクセスするとLaravelのスタート画面が表示されます。

![スクリーンショット 2023-11-07 16.45.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3587166/50a78b16-322d-7da7-83c0-5a3b0cdf2dea.png)

これだけでLaravelの環境ができました。

# まとめ
初学者にはDockerでの環境構築はWEBサーバーやMySQLなど色々インストールしないといけなくて少し敷居が高いですが、Laravel sailなら何も考えずにすぐに環境構築ができるので、まずはLaravelを触ってみたい人におすすめだと思います。

:point_up:続く
Pythonで「フォーマット済み文字列リテラル(f文字列)を使った文字列の書式設定」の動作を確認してみた

# 概要

Pythonで「フォーマット済み文字列リテラル(f文字列)を使った文字列の書式設定」の動作を確認してみました。以下のページを参考にしました。

https://www.javadrive.jp/python/string/index25.html

# 実装

以下のファイルを作成しました。
```sample.py
name = "Suzuki"
old = 18
print("名前は{:<8s}です。年齢は{:>3d}歳です。".format(name, old))

name = "Suzuki"
old = 18
print(f"名前は{name:<8s}です。年齢は{old:>3d}歳です。")

name = "Suzuki"
print(f"名前は{{ {name:<8s} }}です。")

num = 0.0752
print(f"指数表記={num:e}")
print(f"固定小数点表記={num:f}")
print(f"パーセンテージで表示={num:%}")

str1 = "Lemon"
print(f"文字列=[{str1:<10s}]")
print(f"文字列=[{str1:^10s}]")
print(f"文字列=[{str1:>10s}]")

num = 1234567
print(f"数値={num:,d}")
```

以下のコマンドを実行しました。
```
$ python3 sample.py 
名前はSuzuki  です。年齢は 18歳です。
名前はSuzuki  です。年齢は 18歳です。
名前は{ Suzuki   }です。
指数表記=7.520000e-02
固定小数点表記=0.075200
パーセンテージで表示=7.520000%
文字列=[Lemon     ]
文字列=[  Lemon   ]
文字列=[     Lemon]
数値=1,234,567
```

# まとめ

何かの役に立てばと。
AWSのファイルストレージサービスについて新卒1年目がまとめてみた

AWSを学び始めて間もない方へ、Storage Serviceって色々あって分かりづらくないですか？
自分はあまりわからなかったので、この記事でまとめてみました。

## AWSのデータストレージサービスをまとめてみました

Data Storage Serviceは大きく分けてBlock Storage、File Storage、Object Storageの３つがあります。
その中でも、File Storageのサービスが一番多いですね、、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583957/9b48645f-772b-12c1-a544-2caf7cbe7896.png)


では、そのFile Storage Serviceの特徴を見ていきましょう！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583957/ce87f4f7-6757-e42b-aeaf-3a84843bdba8.png)
上の図を見ていただければわかるように、今回は5つに分類分けして考えていきます。
コストに関しては、
* ストレージ容量＝２Tb
* マルチAZ構成
* スループット＝125MBps
* 上記以外はデフォルトで算出しております。

プロトコルは、
一般的にLinuxで用いられるNFS、Windowsで用いられるSMBなどがあります。

拡張性については、
EFSのみが、自動拡張・縮小対応可となっていますね！

可用性については、
すべてのサービスでマルチAZ対応となっているのがわかります。




## ファイルストレージサービスのユースケースの確認
簡単なケーススタディですがお付き合いください！！


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583957/375ca7e4-c388-53fa-45d6-64a2aca40a67.png)

まずはケース１。
この場合、私ならAmazon FSx for NetApp　ONTAPを選択します。
理由としましては、プロトコルがNFSとSMBの両方対応可となっているからです。

次にケース２を見ていきましょう！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583957/111e7d5b-ec15-b880-8e47-c0a0b49da0fb.png)


この場合、私ならAmazon EFSを選択します。
理由は3つあります。
１つ目は、プロトコルがNFS対応可であるからです。
２つ目は、容量が自動的に拡張・縮小されるため手間が省けるからです。
３つ目は、使用したデータ分だけ課金されるからです。

## まとめ
僕のようなIT初学者、AWS初学者は似たようなサービスがあるとこんがらがってしまいます、、、、泣

なのでしっかりとサービスの違いを学び、お客様のご要望に合ったソリューションを提供できるように日々学び続けたいと思います！

一緒に頑張りましょう！
Eclipse基礎まとめ

# はじめに
自身の備忘録として記録する

# Eclipseってなに？
アメリカのIBM社が開発した統合開発環境(IDE)のこと。
IDEはIntegrated Development Enviromentの略
統合開発環境とは、開発に必要な便利ツールを統合した環境のこと
IDEはほかにもVSCodeやIntelliJ IEDAなどが挙げられる

**中でもEclipseは主にJavaの開発に強みがある環境**

しかし、Javaの開発のみしかできないというわけではなく、プラグインを使用することで、C、C++、JavaScript、PHP、Perl、Ruby、Pythonなどの言語を用いた開発環境としても使用することができる。

▼参考サイト

https://hnavi.co.jp/knowledge/blog/eclipse-development/

### Eclipseのいいところ
1. 無料で使えるオープンソース
2. 高機能で安定して動く(Java)
3. プラグインでカスタマイズできる(日本語化とか)


# JDKってなに？
JDKはJava Development Kitの略
Oracleが発行元のJava開発環境

Javaの開発をするためのすごく基礎の基礎のようなイメージ。

コーディングをする際には
エディター等は標準装備されていないため、さくらエディターなど
別でエディターを準備する必要がある。


# JDKとEclipseの違いって？
**JDK**
Javaを扱ううえで必ず必要な環境、コンパイラ
中枢部のようなイメージ、しかしJDKにはエディター等は含まれていないため、コーディングをする際には別でエディターソフトウェアなどを準備しないといけない。

**Eclipse**
JDKのようなコンパイラも含めたオールインワンセットのようなイメージ。しかしJDKではなく、似たようなECJというコンパイラが搭載されている。

***つまり***
開発環境の構築は

1. JDK＋周辺ソフト
2. EclipseのようなIDEを使用する

の２パターンになることが考えられる。

# EclipseにJDKって必要なの？
***結論：必要ない***

Eclipseには別でECJコンパイラが含まれており、
JDKを使用せずとも、Java開発が行うことができる。

### 注意点
JDKとECJは完全一致ではない。
JDKはoracle製、Java資格のoracleもJDK視点がおおい？
JDKにしかない機能等もある

https://computer.sarujincanon.com/2022/03/12/eclipse_java_jdk_no/

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

https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11148126591

# Eclipseインストール方法

https://rage1blog.com/environment_construction_jdkeclipse_from_installation_to_execution/

# Eclipseの基本的な使い方

https://workteria.forward-soft.co.jp/blog/detail/10311#anchor_1
bashでテキストファイルで特定文字列を含む行を抽出する

# はじめに
テキストファイルやエクセルで作成されたタスク管理表を自分で見るためにbashの特定文字列を含む行の抽出方法を調べた。

# 抽出方法
上記の内容を実現するために以下の二つを調べた。

## テキストファイルを1行ずつ読み込む方法
catしたものをパイプで`while read line`と書くことで一行ずつ処理が可能になる。
```bash
cat {filename} | while read line
do
    # $lineに対して具体的な処理
done
```

## 特定文字を含むかどうか判定する方法
ここに関してはいろいろな方法があると思いますが、私はif文で以下のような方法を選びました。
```bash
# やり方1
if [[ "$line" == *ToDo* ]]; then
    # ToDoを含むときの処理
else
    # ToDoを含まない時の処理
fi

# やり方2
if [[ "$line" =~ "ToDo" ]]; then
    # ToDoを含むときの処理
else
    # ToDoを含まない時の処理
fi
```

# 実際の実装
今回は、テキストファイル内のToDoを含む行のみを抽出したかったため、以下のようにテキストファイルの処理を行いました。
```bash
cat {filename} | while read line
do
    if [[ "$line" == *ToDo* ]]; then
        echo $line
    fi
done > todolist
```

# さいごに
bashは調べてみるといろいろと便利に使えるのですごく多機能だと感心します。業務の合間に少しずつ慣れていきたいなと思います。

# 参考
- [Bash Shell - 文字列比較、文字列が含まれているかどうかを確認する](https://codechacha.com/ja/shell-script-compare-string/)
- [コピペ可｜bash/while read lineで行単位で処理：5パターン](https://lanchesters.site/bash-while-read-line/)
言語聴覚リハビリ答えあわせプログラム　〜数字、仮名ソート〜

今年は入院しながらQiita書きます
入院中課題の答え合わせです

# 課題
- 数字→仮名
- 数字は小さい順
- 仮名は50音順


# プログラム
```Elixir
defmodule P1 do
  def run(), do: Enum.each(data(), fn x -> sort(x) end)

  def sort(v) do
    String.split(v, " ")
    |> Enum.sort()
    |> Enum.join()
    |> IO.inspect()
  end

  def data do
    [
      "5 き 1 さ 3",
      "4 つ 2 そ 1",
      "6 よ 3 ふ 8",
      "9 め 3 れ 2 た",
      "2 し 1 は 6 か",
      "7 く 9 ね 2 を",
      "1 お 3 ろ 5 て 4 ",
      "2 ひ 1 も 6 る 3 ",
      "4 む 8 せ 6 ら 7 ぬ",
      "6 ゆ 2 り 5 こ 4 の"
    ]
  end
end

```

# 結果
```
"135きさ"
"124そつ"
"368ふよ"
"239ためれ"
"126かしは"
"279くねを"
"1345おてろ"
"1236ひもる"
"4678せぬむら"
"2456このゆり"
```
# 余談　なぜ、入院した？
- くも膜下出血しました
　脳の手術しました
- 失語症なりました
　　リハビリの為、上記課題を実施してます
  　（これは、リハビリの一部です）