OmniAICreator/Qiita-1.07M huggingface dataset:
Sparkのコンポーネント

# 概要
Sparkには様々なコンポーネントが用意されています。

- Spark SQL
- Spark MLlib
- Spark Structured Streaming
- GrephX
- 他

これらは全てSparkのライブラリですが、
耐障害性の機能は分かれています。

これらは、scala, SQL, Python, Java, Rで実装することが出来ます。

## Spark SQL

Spark SQLで使えるデータは以下です。

- RDBMS
- CSV
- text
- JSON
- Avro
- ORC
- Parquet
- AWS S3
- 他

読み込まれたデータは、Spark DataFrameとして扱われます。
データの操作は、SQLと同じように操作をすることが出来ます。

```
//データを読み込みDataframeとして扱う
spark.read.json("ファイルパス")

//SQLを使いデータ操作
spark.sql("""SELECT id, name FROM customer WHERE city = 'tokyo' ORDER BY id""")
```


## Saprk MLlib
MLlibは、一般的な機械学習モデルを、APIで構築することが出来ます。
APIは、引用・変換した特徴量、学習評価のためのパイプライン、学習済みモデルのデプロイが許可されています。
また、線形代数や統計学を使うこともできます。

```
//ライブラリの読み込み
from pyspark.ml.classification import LogisticRegression

//CSV読み込み
training = spark.read.csv("ファイルパス")
test = spark.read.csv("ファイルパス")

//モデル定義
lr = LogisticRegression(maxIter=10, regParam=0.3, elasticNetParam=0.8)

//学習
lrModel = lr.fit(training)

//予測
lrModel.transform(test)
```

## Spark Structured Streaming

Apache Spark2.0から、以下が提供されました。
- experimental Continuous Streaming model
- Structured Streaming APIs
- Spark SQLエンジン、DataFrame-based APIs

Spark2.2から、エンジニアや開発者の環境下で使うことが、広い範囲で使えるようになりました。

また、Structures Streaming modelの下の、Spark SQLのエンジンでは、
straming Applicationなどを、耐障害性のある処理で扱うことが出来ます。

そして、Spark3.0ではストリーミングデータのリソースに以下が追加されました。

- Apache Kafka
- Kinesis
- HDFS-based
- クラウドストレージ

```
//ライブラリの読み込み
from pyspark.sql.functions import explode, split

//データ読み込み
lines = (spark
    .readStream
    .format("socket")
    .option("host", "localhost")
    .option("port", 9999)
    .load())

//データ分割
words = lines.select(explode(split(lines.value, " ")).alias("word"))

//wordのカウント
word_counts = words.groupBy("word").count()

//Kafkaへ書き込み
query = (word_counts
    .writeStream
    .format("kafka")
    .option("topic", "output"))
```

## GraphX

GraphXは、分析、コネクション、探索など。様々なグラフの処理に使われます。

```
val graph = Graph(vertices, edges)
messages = spark.textFile("ファイルパス")
val graph2 = graph.joinVertices(message){
    (id, vertex, msg) => ...
}
```
ChromeでYoutubeの広告をブロック

[***これ***](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo)をインストールした後、[***これ***](https://greasyfork.org/scripts/386925-youtube-ad-cleaner-include-non-skippable-ads-works/code/Youtube%20Ad%20Cleaner(Include%20Non-Skippable%20Ads-%20works).user.js
) または [***これ***](https://github.com/TheRealJoelmatic/RemoveAdblockThing/raw/main/Youtube-Ad-blocker-Reminder-Remover.user.js) をインストールする
Ectoで他のスキーマを参照するスキーマを生成する

# Ectoで他のスキーマを参照するスキーマを生成する

- [Ectoで他のスキーマを参照するスキーマを生成する](#ectoで他のスキーマを参照するスキーマを生成する)
  - [マイグレーションファイル\&スキーマモジュールの作成](#マイグレーションファイルスキーマモジュールの作成)
  - [テーブル参照](#テーブル参照)
    - [referencesで参照するテーブルを指定](#referencesで参照するテーブルを指定)
    - [参照されるテーブルへの制約の追加](#参照されるテーブルへの制約の追加)
    - [belongs\_toで参照先スキーマを指定](#belongs_toで参照先スキーマを指定)
    - [has\_one、has\_manyで参照元との関係を記述](#has_onehas_manyで参照元との関係を記述)
  - [クエリから参照する](#クエリから参照する)
  - [結論](#結論)


## マイグレーションファイル&スキーマモジュールの作成

次のコマンドを実行する。

<font color="chocolate">`mix ecto.gen.schema コンテキスト.スキーマ テーブル名 カラム:データ型`</font>

## テーブル参照

テーブル参照をする場合にはマイグレーションファイルに
以下の記述を行う。

* <font color="green">**references**で参照するテーブルを指定</font>
* <font color="green">参照されるテーブルへの制約の追加</font>

### referencesで参照するテーブルを指定

<font color="red">referencesでは参照するテーブルの指定を行う。</font>

参照するカラム(<font color="gray">デフォルトではid</font>)を追加するには、
<font color="chocolate">`add :スキーマ名_id, references(:テーブル名)`</font>
と記述する。

### 参照されるテーブルへの制約の追加

テーブルによっては値が一意である必要な場合がある。一意制約をテーブルに追加するためには、
<font color="chocolate">`create unique_index(:テーブル, [:フィールド])`</font>
と記述する。

またこの場合スキーマモジュールのchangesetには
<font color="chocolate">`unique_constraint([:フィールド])`</font>
を追加する必要がある。

スキーマファイルには以下の記述を追加する必要がある。

* belongs_toで<font color="green">参照先スキーマを指定。</font>
* has_one、has_manyで<font color="green">参照元との関係を記述。</font>

### belongs_toで参照先スキーマを指定

スキーマファイルに参照元を追加するには<font color="red">`belongs_to`</font>を記述する必要がある。

belongs_toに
<font color="chocolate">`belongs_to :role, Roles`</font>
と記述することで参照先スキーマを指定することができる。

### has_one、has_manyで参照元との関係を記述

スキーマに参照元を記述するためには<font color="chocolate">`has_one`</font>か<font color="chocolate">`has_many`</font>を記述する必要がある。

参照元と1対1であれば<font color="red">`has_one`</font>、1対多であれば<font color="red">`has_many`</font>を記述する。

また以下のように記述を行う

* has_one - <font color="chocolate">`has_one :user, User`</font>
* has_many - <font color="chocolate">`has_many :role, Roles`</font>

## クエリから参照する

参照先は<font color="red">preload</font>を使用することで参照することができる。

```elixir
import Ecto.Query

def list_employee() do
    query = 
        from e in Employee,
        preload: [:role, :user] 

    Repo.all(query)
end
```

## 結論

これらをまとめると他のスキーマを参照するスキーマを定義する方法は

1. <font color="chocolate">`mix phx.gen.schema`</font>でマイグレーションファイルとスキーマモジュールを作成。
2. 生成されたマイグレーションファイルに、<font color="chocolate">`references()`</font>で参照先テーブルを記述する。
3. 生成されたスキーマモジュールに<font color="chocolate">`belongs_to`</font>で参照先スキーマを記述する。(<font color="gray">changesetも書き換える。</font>)
4. 既存の参照先スキーマモジュールに参照元のスキーマを記述する。

となる。
【正規表現】 ^[^ -~｡-ﾟ] がなぜ全角文字を検出できるのか説明できますか？



# 正規表現について

正規表現とは

https://ja.wikipedia.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE

入力フォームのバリデーションチェックなどで使用したり、全角の値を半角に変換したりするときに使われていますね。
今まで何度も使用してきましたが、詳しく調べたことはありませんでした。

## 正規表現で全角文字を表す ^ [^ -~｡-ﾟ] がなぜ全角文字を検出できるのか。

TypeScriptにてフロント開発中、バリデーションチェックを作成している際ふと気になりました。

正規表現は大抵`[a-z]`や`[0-9]`、`[A-Z]`など、検出する文字列が正規表現に含まれているのですが、
##### `^[^ -~｡-ﾟ]` には全角文字は含まれていません。

なのになぜ全角文字を表す正規表現なのでしょうか？

# 順番に見ていく。

## 「^」

まずは`「^」`についてですが、この部分が答えでした。

### 正規表現において` [ ] `内先頭にある ` ^ `は否定を表します。
つまり、`「^」`以降の内容と真逆になるわけですね。なので`^[^ -~｡-ﾟ]`には全角文字が含まれていないわけです。

## [ -~」

続いて`[ -~」`の部分。こちらは

##### 「半角スペース」- 「チルダ」となっています。

ASCII文字コード表 ( http://smilebasic.com/supplements/unicode02/ )

によると、`半角スペース(U+0020)`から`チルダ(U+007E)` 中には半角英数字も含まれます。

`U+007F`であるバックスラッシュは取得していないようですね。

## 「｡-ﾟ」

こちらはまず`「｡」`がUnicodeで`U+FF61`だそう。

参考

https://unicd.net/char/FF61

そして`「ﾟ」`は`U+FF9F`とのこと。

### つまり`U+FF61～U+FF9F`を指定しています。

この中に含まれている文字は `｢` や`ﾞ` もありますが、メインは「半角カタカナ」でした。`((ｦ)U+FF66 ～ (ﾝ)U+FF9D)`

## まとめ

以上を全て踏まえたうえで `^[^ -~｡-ﾟ]`を見ていきましょう。

順番に

#### 「否定」「半角英数字」「半角記号」「半角カタカナ」

となっています。

つまり、半角英数字、半角記号、半角カタカナ以外を取得しているわけですね。

`[a-z]`のように全角文字のみ取得する方法はないのかかなり回りくどいやり方になっているように見えますが、正しく動作しているみたいです。

すっきりしました。

# andmore...

他にもこんな記事書いてます。

https://qiita.com/SZR/items/e4e8a2381b4b616990b1

https://qiita.com/SZR/items/3e3a02e6c316438fe5a3

https://qiita.com/SZR/items/1c8a7be4267071f6c295

https://qiita.com/SZR/items/1d8edaf95fa2f5bbe821

https://qiita.com/SZR/items/1b42bc8cd203fd6c6f26

https://qiita.com/SZR/items/dce75a3d08c5170d4365

https://qiita.com/SZR/items/396533c1b1e14489a782

https://qiita.com/SZR/items/f46822b009fa47e1ca53

https://qiita.com/SZR/items/401a1f839723d89bd7f2

https://qiita.com/SZR/items/176586cde17ea0e9828a

https://qiita.com/SZR/items/a000cbaa583dcd2a344b

https://qiita.com/SZR/items/1debe21a6759d0067ad7
Github, GitlabのSSH接続手順（秘密鍵・公開鍵の作成から）

# 概要
Github, GitlabにおけるSSH接続の手順をまとめます。SSH接続とは、簡単に言うと秘密鍵・公開鍵を利用した保護された接続方法です。
備忘録程度なので曖昧性高めですが、ご容赦ください。

# この記事で扱うこと
- sshファイルの作成方法
- 鍵の作成
- Githubへの公開鍵の登録
- Gitlabへの公開鍵の登録
- 接続テスト

# この記事で扱わないこと
- Github,Gitlabでのアカウント登録
- Gitbashのダウンロード
- 接続後のローカルでの操作（リモートブランチからのクローンなど）

# 手順
## sshファイルの作成
- エクスプローラーを起動し、ユーザーのホームディレクトリに移動
- ユーザーのホームディレクトリで右クリック→「Git Bash Here」でGit Bashを起動
- 以下のコマンドを実行
```bash
# .sshのディレクトリ作成
$ mkdir .ssh

# .sshディレクトリに移動
$ cd .ssh
```

## 鍵の作成
- .sshディレクトリにいる状態で以下コマンドを実行し、鍵を作成
```bash
# ssh-keygen で2種類の鍵（秘密鍵・公開鍵）を作成
# -t オプションで鍵タイプを設定（以下ではrsaを選択）
# -f オプションで鍵の名前を設定（以下では"id_rsa"という名前で作成）
$ ssh-keygen -t rsa -f id_rsa
```
- 上コマンドを実行するとパスフレーズを求められますが、未設定にすることも可能です。その場合は何も入力しない状態でEnterを押してください。
- パスフレーズの再入力が求められるので、再度入力します。（未設定の場合は再度空欄でEnter）
- エクスプローラーの.sshディレクトリに2つのファイルができていることを確認
    - 上の例では **秘密鍵の「id_rsa」と、公開鍵の「id_rsa.pub」** が作成されます
    - 簡単な説明
        - 2つのうち、公開鍵の方をGithub,Gitlabに登録します。
        - 登録した公開鍵とローカル（手元）にある秘密鍵のキーペアによって接続のセキュリティが担保されます。
        - 秘密鍵はほかの人に漏洩することのないよう保管してください。
::: note warn
Tips. **「id_rsa」という名前**
※読み飛ばしていただいても大丈夫です
今回は省略しますが、他サイト等のセットアップ法で紹介されているConfigファイルに関する設定をしない場合、デフォルトでは.sshディレクトリの「id_rsa」という名前のkeyが読み込まれる仕様になっています。
こだわりがない場合は上例の名前で鍵を作成して問題ありませんが、所属する組織のルールによってはすでにid_rsaという名前の鍵が作成されている場合もありますので、別途ご確認ください。
:::


## Githubへの公開鍵の登録
- 作成した公開鍵を適当なエディタで開き、全選択→コピーする
- Githubを開き「SSH and GPG keys」の設定画面を開く
    - Githubの画面右上のユーザーアイコンをクリック
    - Settingをクリックし、設定画面に遷移
    - 画面左のサブメニューから「SSH and GPG keys」を選択
- 右上の「New SSH key」からSSH鍵登録画面を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515840/a6da31ea-87af-9976-e8f0-d8b487dbc00e.png)
    - Title … 任意でOK。（Githubを登録したときのメアドとかが通例？）
    - Key type…デフォルトの「Authentication Key」
    - Key … 先ほどコピーした公開鍵をペースト
- 「Add SSH keys」を押下

## Gitlabへの公開鍵の登録
- Githubへの登録の手順で登録する
- Gitlabを開き「SSH key」からSSH鍵登録画面を開く
    - Gitlabの画面右上のユーザーアイコンをクリック
    - Preferencesをクリックし、設定画面に遷移
    - 画面左のサブメニューから「SSH keys」を選択
- 画面右上の「Key」に先ほどコピーした公開鍵をペースト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515840/cafbbfef-45d0-b32a-a5f7-1d607f3a2c89.png)
    - Title … 任意でOK。（上と同様にGitlabを登録したときのメアドとかが通例？）
    - Expiration date … 鍵の有効期限。セキュリティ的には定期的に更新したほうが良いが、空欄でも大丈夫。
- 「Add key」を押下

## 接続テスト
- 再度.sshディレクトリでGitBashを開く。
- 以下コマンドを実行し、接続テストをする。（Github,Gitlabそれぞれで実行してください）
```bash
# 「ssh -T git@」までは共通。@以降ではリポジトリを指定するので、ご利用のプロジェクト・リポジトリ名を入力してください。
$ ssh -T git@repositoryName
```
- 「Hi！～」「Welcome to Githlab,~」のようなリアクションが表示されたら接続成功
- 「~ : Permission denied (publickey).」と表示されていたら失敗
    - @以降でプロジェクト・リポジトリ名を適切に指定できていますか？
    - 各種Setting画面でキチンと公開鍵を登録できていますか？（登録完了するとSSH keys の画面に登録済みの鍵が表示されます。）

# 終わりに
接続テストが完了すればSSH接続は完了です。記事を書くにあたって参考にしたサイトを掲載しますのでご確認ください。
セットアップお疲れ様でした！

# 参考サイト
- https://laraweb.net/environment/8473/
- https://qiita.com/shizuma/items/2b2f873a0034839e47ce
Kubernetes上で自分の作成したプログラムでXML-RPCモジュールを動かす方法

# 目的
今回はKubernetes上で自分の作成したプログラムでXML-RPCモジュールを動かす方法について書いていきます．もし僕と同じことをしようとしている人がいれば参考になるといいです．

***環境***
Kubernetes(K3s)
***使用言語***
Python3.10.12
***使用ライブラリ***
xmlrpc.client
xmlrpc.server


## イメージ図
今回は仮想マシンを2台立ててRPCを使用していきます．以後仮想マシンはVMと呼びます．


RPCはネットワーク上で離れたプログラムを呼び出す手法です．詳しくは[この記事](https://qiita.com/il-m-yamagishi/items/8709de06be33e7051fd2)がわかりやすいと思います．
RPCクライアントはKubernetesをインストールしRPCサーバはVMのままです．
イメージ的には以下のような図になります．



![スクリーンショット 2023-10-16 20.04.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2747698/2f10181a-86e2-2eba-9400-f14e00372a08.png)

RPCプログラム(クライアント)はRPCプログラム(サーバ)に対して呼び出しを行い，それに対してRPCプログラム(サーバ)は応答を返します．まあやっていることはRPCプログラム(クライアント)がRPCプログラム(サーバ)の関数を呼び出して出力をRPCプログラム(クライアント)側で受け取る形となります．

## 準備
 VMは各自で用意してください！

***クライアント側***


Kubernetes(K3s)のインストール
以下の手順で行いましょう．
```
$ curl -sfL https://get.k3s.io | sh -
```
めちゃめちゃ簡単です

各ファイルの用意
- kustomization.yaml
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- name: myapp
  files: 
  - hello.py
resources
- agent.yaml
```

- agent.yaml
```yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: myapp
spec:
  backoffLimit: 3
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: myapp
        image: python:3
        command:
        - "python"
        - "/myapp/hello.py"
        volumeMounts:
        - mountPath: /myapp
          name: script
      volumes:
      - name: script
        configMap:
          name: myapp
```

- hello.py
```python
import xmlrpc.client

with xmlrpc.client.ServerProxy('http://サーバ側のIPアドレス') as proxy:
    print(proxy.hello_return())
```


***サーバ側***
以下のファイルを用意
- hello_return.py
```python
from xmlrpc.server import SimpleXMLRPCServer #RPCモジュールをインポート

with SimpleXMLRPCServer(('0.0.0.0', 6000)) as server: #6000番のPortで待ち受ける

    def hello_return(): #Hellowを返す関数
        return 'Hello'

    server.register_function(hello_return, "hello_return")
    server.serve_forever()
```


## 実行手順


では実行しましょう！
***サーバ側***
```
$ python3 test.py 
```

***クライアント側***
まずは以下のコマンドを入力しましょう！
```
$  kubectl apply -k . -n python
configmap/myapp-ht7tttt747 created
job.batch/myapp created 
```
Podの状態を観察
```
$ kubectl get pods -n python -w
NAME          READY   STATUS              RESTARTS   AGE
myapp-s2k2f   0/1     ContainerCreating   0          14s
myapp-s2k2f   0/1     Completed           0          21s
```

ログを見てみる
```
$ kubectl logs myapp-s2k2f -n python
Hello
```



サーバ側の状態も見てみましょう！
ちゃんと送られていそうですね
```
$ python3 test.py 
 - - [20/Oct/2023 04:33:22] "POST / HTTP/1.1" 200 -
```

## 最後に
作成したプログラムをコンテナで稼働させられるとかっこいいのでよかったら使ってみてください！！！


# 参考
https://blog.sakashita.dev/2020/11/pythonmd.html
OCRで画像から文字列を抽出

## sample
```py
import cv2
import base64
import numpy as np
from PIL import Image
import pyocr

class SampleClass:
    """Sample class for OCR
    This code use tesseract-ocr
    """

    def scan(self, reqdata):
        """画像から文字列を抽出
        :param reqdata APIリクエストで画像ファイルデータを受け取る
        :return: 抽出した文字列をJSONで返却
        """
        # 保存先の画像ファイルパスを指定
        image_file=f'ファイルパス'
        # APIリクエストされた画像ファイルをbase64
        img_binary = base64.b64decode(reqdata)
        # バッファーを配列に変換
        jpg=np.frombuffer(img_binary,dtype=np.uint8)
        # デコードと書き出し
        img = cv2.imdecode(jpg, cv2.IMREAD_COLOR)
        cv2.imwrite(image_file,img)

        # OCRエンジンで画像を文字列に変換
        tesseract = pyocr.get_available_tools()[0]
        res = tesseract.image_to_string(Image.open(image_file),
            lang="jpn",builder=pyocr.builders.TextBuilder(tesseract_layout=6))

        # 返す
        return 200, {'message': 'ok', 'code': '0', 'data': res}

```
cv2で画像の読み取り、切り取りは[こちら](https://note.com/lizefield/n/nbd553366d55e)のようにもできる

画像をグレースケールに変える等は[こちら](https://imagingsolution.net/program/python/pillow/image_file_open_save/)

より詳しい使い方等は[こちらのQiita記事](https://qiita.com/masa1124/items/198ceea22becdf311f31)がまとまっていました。

## CentOSでOCRエンジンを入れる
```sh
# リポジトリを追加
yum-config-manager --add-repo 
# 公開鍵を追加
https://download.opensuse.org/repositories/home:/Alexander_Pozdnyakov/CentOS_7/

sudo rpm --import https://build.opensuse.org/projects/home:Alexander_Pozdnyakov/public_key
yum update
yum install -y tesseract
yum install -y tesseract-langpack-jpn
```

library
```sh
python3 -m pip install pyocr
python3 -m pip install opencv-python
```
[pyocr](https://pypi.org/project/pyocr/)
[opencv-python](https://pypi.org/project/opencv-python/)
[wsl]学内wifiでプロキシを自動セットアップするスクリプト[windows]

シェルスクリプトを使ってプロキシを自動でセットアップします。

## スクリプト
以下のコードをホーム直下に配置して、~/.bashrcの中で実行するようにしてください。

```shell
#!/bin/bash
# WSL/WSL2用

PROXY={ここにプロキシのurlを書く}
HTTP_PROXY=http://${PROXY}
HTTPS_PROXY=http://${PROXY}
SSID="{ここにプロキシを使いたいwifiのssidを書く}"

NAME=`/mnt/c/Windows/System32/netsh.exe wlan show interface | grep ${SSID}`

# 使いたいプロキシのコメントを外す
if [ "${NAME}" != "" ];then
  export http_proxy=${HTTP_PROXY}
  export https_proxy=${HTTPS_PROXY}

  git config --global http.proxy ${HTTP_PROXY}
  git config --global https.proxy ${HTTPS_PROXY}
  git config --global url.git@github.com:.isnteadOf https://github.com:

  # npm -g config set proxy ${HTTP_PROXY}
  # npm -g config set https-proxy ${HTTP_PROXY}
  # npm -g config set registry "http://registry.npmjs.org/"

  # yarn config set proxy ${HTTP_PROXY} -g > /dev/null 2>&1
  # yarn config set https-proxy ${HTTP_PROXY} -g > /dev/null 2>&1
else
  unset http_proxy
  unset https_proxy

  git config --global --unset http.proxy
  git config --global --unset https.proxy
  git config --global --unset url.git@github.com:.isnteadOf

  # npm -g config delete proxy
  # npm -g config delete https-proxy
  # npm -g config delete registry

  # yarn config delete proxy -g > /dev/null 2>&1
  # yarn config delete https-proxy -g > /dev/null 2>&1
fi
```

## 簡単な解説
プロキシの設定を書き換える部分はほとんど参考にしたサイトと変わっていません。

変更点はssidの取得についてです。
wsl特有の問題として、wsl側から直接wifiの情報を集めることができません。なので、windows側のコマンドを直接呼び出します。これにより問題が解決できました。

めでたしめでたし。

## 参考にさせて頂いたサイト
https://zenn.dev/yuina_blend/articles/2a5df5a79a93ef


[茨城高専の学内Wifi接続時のプロキシ設定を自動化するスクリプト](https://gist.github.com/Lockdef/0b57d0837da153e45eb6293cefa44ef4)
AWS CloudFormationのOutputの書き方

CloudFormationの作成時にoutputの書き方に注意せずスタック作成失敗になったことがあったので今回はスタック作成時に簡単に情報を取得できるoutputの書き方と注意点について説明します。

## Outputとは
>Output (任意)
オプションの Outputs セクションは、他のスタックにインポートする (クロススタック参照を作成)、応答として返す (スタック呼び出しについて記述)、または、AWS CloudFormation コンソールで表示する出力値を宣言します。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html  

## なぜOutputを使用するのか？
`Outputs`セクションは、スタックの作成または更新後に表示される情報を定義するために使用されます。
特定のリソースの属性やスタック内で作成されたリソースへの参照など、リソース情報を簡単に取得できます。

## Outputの基本的な書き方

基本的な`Outputs`セクションの構造は以下のようになります。

```yaml
Outputs:
  Logical ID:
    Description: Information about the value
    Value: Value to return
    Export:
      Name: Name of resource to export
```

- `Description`: Outputの説明。オプションですが、何の情報が出力されるのかを明確にするために推奨されます。
- `Value`: 出力する情報の値。この属性は必須です。
- `Export`: スタック間での値の共有を可能にするための名前。この名前を使用して、他のスタックからこのOutput値を参照できます。

## 各サービスのCloudFormationのReturn Valuesを確認
### Return Valuesとは
CloudFormationのテンプレート内でリソースを定義する際、そのリソースが持つ属性や情報を他の部分で参照したい場合があります。
このときに利用するのが、各リソースの`Return Values`です。特定のリソースが作成または更新された後に利用可能な値を示しています。

各サービスのCloudFormationのUserGuidで該当サービスが返せるReturn Valuesが確認できます。
例えば、[Amazon S3のCloudFormation UserGuide](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html#aws-properties-s3-bucket-return-values)によれば、`AWS::S3::Bucket`リソースのReturn Valuesは以下の通りです：
- `Ref`: バケットの名前を返します。
- `Fn::GetAtt`: 
  - `Arn`: バケットのAmazon Resource Name (ARN)を返します。
  - `DomainName`: バケットのドメイン名を返します。
  - `DualStackDomainName`: バケットのデュアルスタックドメイン名を返します。
  - `WebsiteURL`: バケットのウェブサイトURLを返します。

### Return Valuesで確認した値をs3のCloudFormationの例に挙げて説明をします。

以下は、S3バケットを作成する簡単なCloudFormationテンプレートの例です：

```yaml
Resources:
  MySampleBucket:
    Type: "AWS::S3::Bucket"

Outputs:
  BucketName:
    Description: "The name of the S3 bucket"
    Value: !Ref MySampleBucket

  BucketArn:
    Description: "The ARN of the S3 bucket"
    Value: !GetAtt MySampleBucket.Arn

  BucketDomainName:
    Description: "The domain name of the S3 bucket"
    Value: !GetAtt MySampleBucket.DomainName
```

`AWS::S3::Bucket`リソースを作成しましたので`Outputs`セクションでReturn Valuesを使用して情報を出力してみましょう。

- `BucketName`: `!Ref`を使用してバケットの名前を出力します。
- `BucketArn`: `!GetAtt`を使用してバケットのARNを出力します。
- `BucketDomainName`: `!GetAtt`を使用してバケットのドメイン名を出力します。

### Outputを書く際の注意点
Outputを記述する際の注意点として、変数と属性を適切に組み合わせることが重要です。使用する変数や属性が、対象となるサービスでサポートされていることを確認する必要があります。サポートされていない変数や属性を使用すると、スタック作成時にエラーが発生します。

例えば、S3のOutputにAWS::Backup::BackupPlanのoutputの属性BackupPlanArnを使用すると構文エラーが発生します。

```yaml
Outputs:
#S3のoutputの属性
  BucketName:
    Value: !Ref BucketName

  BucketARN:
    Value: !GetAtt S3Bucket.Arn
#AWS::Backup::BackupPlanのoutputの属性
  BackupARN:
    Value: !GetAtt S3Bucket.BackupPlanArn
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3330696/1ff70056-8356-c7c5-a15d-28ad8b5d4bd9.png)
バッチファイルでフォルダのサイズを調べ、一覧で表示する。

## フォルダの容量を調べたい
一つずつ画面から調べるのは面倒なので、コマンドプロンプトで作成しました。


下記がソースです。調べたいフォルダと同じ階層に置いてたたくと、AllFolderSizeList.txtにフォルダ名：バイト数で記載されます。
最初のFor文でフォルダ一覧の取得、その後フォルダごとに中のファイルサイズを調べ、最終行の合計サイズをファイルに出力します。ファイルはUTF-8で保存してください。

#### フォルダ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3123325/8b4b54d7-e262-925e-4971-cb850b6233a8.png)
#### 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3123325/07c9bd2a-48b6-3446-806f-18f85c7aae57.png)
プロパティで確認した値
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3123325/68efe55c-49ea-e7dc-4c0c-b3ec34d27b58.png)

### ソース
```batchfile:GetAllFolderSize.bat
@echo off
rem 変数のおまじない
setlocal enabledelayedexpansion

rem 文字コード UTF-8
chcp 65001

rem 結果ファイル
set outFile=%~dp0AllFolderSizeList.txt

rem 結果ファイルの削除
del !outFile!

rem 全件検索の場合 
for /D %%a in (*) do (
	set fname=%%a
	set size=""
	echo %%a
	for /f "tokens=3" %%b in ('dir /s /a "%%a"2^>nul ^| find "File(s)"2^>nul') do (
		set size=%%b
	)
	if not !size! == "" (
	 	echo !fname!:!size!バイト>>!outFile!
	)
)

```
## 指定したフォルダの容量を調べたい

フォルダ名を指定して容量を調べたい場合は、FolderNames.txtにフォルダ名の一欄を記載します。
```batchfile:GetFolderSize.bat
@echo off
rem 変数のおまじない
setlocal enabledelayedexpansion

rem 文字コード UTF-8
chcp 65001

rem 入力ファイル
set inFile=%~dp0FolderNames.txt
rem 結果ファイル
set outFile=%~dp0FolderSizeList.txt


rem 結果ファイルの削除
del !outFile!

for /f "tokens=*" %%a in (!inFile!) do (
rem 全件検索の場合→ for /D %%a in (*) do (
	set fname=%%a
	set size=""
	echo %%a
	for /f "tokens=3" %%b in ('dir /s /a "%%a"2^>nul ^| find "File(s)"2^>nul') do (
		set size=%%b
	)
	if not !size! == "" (
	 	echo !fname!:!size!バイト>>!outFile!
	)
)

```

## ネットワーク上にあるフォルダの容量を調べたい
ネットワークフォルダを調べる場合は、処理の初めと終わりに以下を追加してください。
```batchfile:GetAllFolderSize.bat
pushd ネットワークフォルダ
~~~GetAllFolderSize.batのFor文~~~
popd
```

## 参考にしたサイト
ほとんどこのサイトのコマンドを使いましたが、オプションが足りず正確な容量ではなかったので少し修正しました。

https://jak-san.hatenablog.com/entry/20081117/1226902554

バッチの書き方を調べるのに便利でした。

https://qiita.com/kshibamo/items/9368b0b2a4a2f40b61f1
Dockerでよく使うコマンド一覧の備忘録

Dockerを使ってLaravelを使う事あったのでDockerよく使うコマンドを忘れないように残しておこうと思います。

## よく使うコマンド

docker ps
動いてるどっかを一覧で表示する時によく使う

doceker exec -it コンテナ名　bash
コンテナの中に入る時によく使う
【Flutter】DropdownButtonFormFieldの枠線の色を変える

# どういうことか

こういうWidgetの枠線の色を変える。

![スクリーンショット 2023-10-20 11.22.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413699/98312ac5-c2b6-1377-cbce-b365c5fee82b.png)

枠線をつける方法は出てくるが、色を変更する方法は軽く探した感じ見当たらなかった。

https://www.choge-blog.com/programming/flutterdropdownbuttonformfieldborder/

## やる

実は `TextFormField` の枠線の色を変更する方法と同じ。

```dart
child: DropdownButtonFormField(
  decoration: InputDecoration(
    enabledBorder: OutlineInputBorder( // 非選択状態の枠線の色
      borderSide: BorderSide(color: Colors.grey)
    ),
    focusedBorder: OutlineInputBorder( // 選択状態の枠線の色
      borderSide: BorderSide(color: Colors.blue)
    ),
    fillColor: Colors.white, // 背景色
    filled: true, // これ付けないと背景色が適用されない
    contentPadding: EdgeInsets.all(8),
  ),
// 中略
)
```

おわり(´・ω・｀)
langchainのMultiVectorRetrieverを使って、PDFデータのRAGを進化する

中国のSNSでlangchainでPDFデータをうまくRAGする手法の記事を読みました。

PDFデータにRAGを適用する際に、よくある問題は、PDF内にテーブルが存在すること、またはテーブルが画像形式で含まれていることです。これらのテーブルを適切に分解せずにembeddingすると、モデルの性能がかなり下がります。今まであまりよい解決方法なくて、PDFのRAG処理はいつも難しかったです。

この人が考えてた手法は、OCR作業（tableの部分を識別）と普通のテキストembeddingを同時に進めて、その後langchainの「MultiVectorRetriever」を使えてRAGするやり方です。MultiVectorRetrieverは複数のembeddingのRAGを同時に実行できるものです。MultiVectorRetrieverをマルチモーダルで使うことは意外にいけます。
（少し複雑なタスクなので、GPT4以外はまだうまく対応できないような感じです。）

アーキテクチャとしては以下のようです。最近試してみたいと思います。
![图片_20231020121434.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/9318c976-680e-b3fb-9f83-529e02bc6161.png)
ReactアプリをSAP BTP（Cloud Foundry）へデプロイする方法：①buildpack指定

# やりたいこと
https://qiita.com/curlneko/items/c062eed59e2f077f8915

・前回CloudScapeを導入したReactアプリをSAP BTPへデプロイする
 (CloudScapeなしの状態でも、SAP BTPへデプロイ方法は同じ)

# やり方
まず、ローカルでReactアプリを作成し（作成方法は割愛）、ビルドしたうえ、
```ruby:
 npm run build
```

Cloud Foundryへデプロイする設定ファイルmanifest.yml を、必要最小限で、以下のように設定してください～

```ruby:manifest.yml 
---
applications:
- name: app-name
path: build/
instances: 1
buildpack: https://github.com/cloudfoundry/staticfile-buildpack.git
memory: 256M
```

:::note info
少し注意点を説明すると、
・「name」はお好きなアプリネームにする
・「path」はReactのTopフォルダじゃなく、かならずビルドして作られた「build」フォルダへ指定
・「buildpack」はかならずそのURLを指定（CloudFoundryのインスタンスをWebサーバとするため）、buildpack未指定の場合、デフォルトはnodejsの環境となりReactアプリは動けない
:::



そして、通常通りのプッシュ
```ruby:
cf push
```

プッシュが無事成功したら、SAP BTP Cockpitを開き確認すると、このようにアプリができて、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/8dd7a700-91e1-c835-360c-b384ffeea943.png)

アプリのインスタンスをクリックし、さらにApplication Routesをクリックすると、
（buildpackがちゃんとmanifest.ymlで指定されたやつとなってるね）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/e7f196c6-1775-5eef-72bf-7be0ca685103.png)
作ったReactアプリがブラウザで開けた！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/baafc1fe-16f3-124e-c4e2-1bbd5a3f9228.png)




# 参考サイト
https://blogs.sap.com/2020/07/23/deploy-your-reactjs-application-in-cloud-foundry/
[laravel-admin]検索条件でセレクトボックス複数選択「multipleSelect」を使用した時、削除ボタンでレイアウト崩れ

<h1>事象</h1>
laravel-adminで作成した検索画面で複数選択できる様に、「multipleSelect」を使用した場合に、選択後削除ボタン(右側×ボタン)押下するとレイアウトが崩れる問題が発生。
    
    
   
<h2>解消方法</h2>

```javascript
$script = <<<<SCRIPT
    // 画面遷移対応
    $(document).on('pjax:end', function(){
        $({セレクトボックスのクラス名かid属性名} option:first).remove();
    });

    // リロード対応
    $(document).ready(function(){
        $({セレクトボックスのクラス名かid属性名} option:first).remove();
    });
SCRIPT;
Admin::script($script);
```

上記を、$gridに追加したら上手く動作しました。
１つ目に不要要素が入っていた為、削除アイコンが消えない不具合だったみたいです。
CI/CD ハンズオン（GitHub Actions & Android 編）全体説明

# CI/CD の概要

- Continuous Integration（継続的インテグレーション）
- Continuous Delivery/Deployment（継続的デリバリー）
- ソフトウェア開発のライフサイクルにおける処理を自動化
  - 市場へ迅速に、継続的な価値を提供

---

# GitHub Actions

- GitHub が提供する CI/CD サービス
  - 2019年11月に正式版がリリース
  - public リポジトリなら無料で使える（全機能ではない）
- GitHub でのソフトウェア開発と親和性が高い
- Software Design 2022年2月号が参考になる
  - https://www.amazon.co.jp/dp/B09QKG3C1L

---

# ハンズオン

https://github.com/hkusu/cicd-android-hands-on/wiki

- https://github.com/hkusu/cicd-android-hands-on/wiki
   - Android アプリの開発経験が無くても進められる内容になっています^^

---

# 開発フローの自動化

- ビルドやテスト以外でも、開発フローの自動化に利用できる
  - 例： [プルリクの assignees を自動で設定する](https://zenn.dev/yumemi_inc/articles/b3e11b50869c1a)
- GitHub CLI が便利
  - https://cli.github.com

---

# GitHub Marketplace

https://github.com/marketplace?type=actions

- https://github.com/marketplace?type=actions
  - 自分で作って公開もできる

---

# 実際のプロジェクトでの例

https://speakerdeck.com/hkusu/cd

- https://speakerdeck.com/hkusu/cd
react-webcamで撮った画像をFastAPIのサーバーに送信する

## はじめに
Reactを使ったWebアプリケーションでカメラ撮影する機能について調べてみました。
ただ撮影するだけではなく、サーバーに撮った画像を送信するところまでやってみました。

## Reactでカメラを使う
Reactでカメラを使用する場合、現状(2023/10月現在)だと以下のライブラリが候補になります。
* react-webcam
  + https://github.com/mozmorris/react-webcam
* react-html5-camera-photo
  + https://github.com/mabelanger/react-html5-camera-photo
* react-camera-pro
  + https://github.com/purple-technology/react-camera-pro

ダウンロード数、GitHubのスター数などreact-webcamが圧倒しているので、基本的にはreact-webcamから検討していくのがよさそうです。

## react-webcam
単純にreact-webcamを使うだけなら難しいことは何もなく、[usage](https://github.com/mozmorris/react-webcam#usage)にある通り、`<WebCam />`のみで使用できます。
撮影した画像を取得したい場合は、`getScreenShot`を呼び出せばよいだけでこちらも簡単に使用できます。
https://github.com/mozmorris/react-webcam#methods

## イメージをサーバーに送信する
react-webcamで撮影した画像をそのまま表示するだけなら問題ないのですが、サーバーに送信する場合は、

* base64をBlobに変換する
* Fileオブジェクトを作成する

必要があります。
これについては、検索すればたくさんの情報があります。
* https://qiita.com/ns777/items/24f1a48fd9301ff3dcdb
* https://zenn.dev/nana/articles/688636736ac1e9

## デモ
react-webcamで撮った画像を送信するコードをCode Sandboxで動くようにしてみました。
https://codesandbox.io/s/react-webcam-example-tfq9cc


## イメージを受け取るサーバー
上記で送信した画像を受け取るために、FastAPIを使いイメージを受け取って保存するサーバーを作成します。
FastAPIでファイルをアップロードするAPIを作るには、以下を参考にすれば簡単に作成できます。
https://fastapi.tiangolo.com/tutorial/request-files/

今回は、アップロードされたファイルをJPEGとして保存するため、PILを通して保存します。

```python
import time
from PIL import Image
from fastapi import FastAPI, UploadFile

app = FastAPI()

@app.post("/image")
async def save_image(file: UploadFile):
    image = Image.open(BytesIO(await file.read()))
    image.save(f"{int(time.time() * 100000)}.jpg")
    return "ok"
```

## 参考資料
* https://dev.classmethod.jp/articles/get-image-with-react-webcam-and-typescript/
* https://zenn.dev/shinobuy/articles/170e5fef9aa780
* https://blog.usize-tech.com/take-photo-by-react-app/
Docker内でXdebugを使いたいのに、デバッグが通らない問題

Docker上で開発作業を行っている。
##### ある日Xdebugを起動したところ、有効化されているのにデバッグが通らない。phpinfo()で確認しても問題は無さそう。
##### とりあえず再度`docker-compose up --build`をしてみるが直らない。

解決策
--
`docker compose build --no-cache`

で解決。キャッシュが邪魔していたらしい。問題なくデバッグ出来ました。
エンジニアに向けて最初に理解したいところ

## はじめに
はじめまして、エンジニアに向けて日々勉強中の@goooooonです。まだ勉強して1年ではありがますが、Qiitaの記事にはいろんな場面で助けていただきました。今までの復習を兼ねて(それと少しでもこれから勉強される方の0.01mでも参考になったら幸いです)今後少しずつ記事を投稿していきたいと思います。

今回は未熟者なりにこれは最初に理解していたいところだなーと思い返した所を記事にしてみました。
***

みなさんが普段利用しているWebアプリケーションの処理の流れってイメージできますか？
私はこんなふうに思ってました。
とりあえずすごいことをしているんだろう....はい

## サーバーの存在 ##
### サーバーとは ###
>サービスを提供するコンピュータやプログラム(またはその役割)です。それには種類がある。
![メールサーバ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3580152/2171a5a9-0dc2-bfb7-44d2-f1fea74e19dd.png)
この他にもDNSサーバー、キャッシュサーバー、仮想サーバー、ファイルサーバー、プリントサーバーなどがあり用途に応じて異なる役割する。

### Webサーバー ###
HTMLやCSS、画像ファイルなどWebコンテンツを配信するサーバー。
あらかじめ保存しているコンテンツしか返さない。

### APサーバー ###
JavaやRuby で書かれたプログラムを実行して必要な処理を行うサーバー。
動的にHTMLなどのコンテンツを作成しクライアントに返す。

### メールサーバー ###
電子メールの送信、受信、保管を管理し、電子メールの通信を可能にするサーバー。

### DBサーバー ###
データーベースの管理や操作を行うサーバー。

***
## Webアプリケーションの処理の流れの確認
#### (APサーバーの処理の流れ) ##
①ユーザーはブラウザを通してWebサーバーにリクエストを送る 
②Webサーバーは動的なリクエストを処理できないのでAPサーバーに処理を依頼 
③APサーバーはリクエスト中のクッキーから現在のユーザーを取得しそのユーザに紐づくデータの取得をDBサーバーにリクエスト 
④DBサーバーはリクエストに応じたデータをAPサーバーに返す 
⑤APサーバーは取得したデータを元にHTMLを生成し(この時にerbなどのテンプレートからHTMLが作られる)、Webサーバーに返す 
⑥Webサーバーがユーザーにレスポンスを返す 
**🌟ポイント
APサーバー単体で機能するのではなくWebサーバーやDBサーバーと連携して操作する。
DBサーバーに接続するには接続情報が必要になる。Railsでいうとapp/config/database.ymlの部分。**

# イメージ図 #
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3580152/264f1fcf-cfde-ce21-9537-8607da46abcf.png)

***
##### 上記の流れを踏まえてRailsアプリケーションでの処理の流れを確認

①クライアントからのリクエストはWebサーバーを介してRailsアプリケーションへと受け渡される。
②ルーティング機能がそのリクエスト処理を行うなうべきコントローラ(クラス)とアクション(メソッド)を特定し、アクションを呼ぶ。
③アクションでは、必要に応じてモデルを利用。例えば一覧機能であるindexアクションでは、全ユーザーデータをUserオブジェクト群としてUserクラスから取得。
④モデルがデータベースで永続化されている場合、モデルはデータベースの書き込みや読み出しも担当。indexアクションの場合は、データベースのuserテーブルからの全レコードを読み出すSQLが実行される。
⑤アクションごとに、対応するビューテンプレートを用いてHTML等を生成。
⑥コントローラがレスポンスを作成し、Webサーバを介してクライアントへと返す。
### イメージ図
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3580152/8b9ef4f9-ce8c-c946-13c6-b38c2df7884c.png)

#### APサーバとDBサーバーの連携

DBサーバーに接続するには接続情報が必要になる。
app/config/database.ymlの中では、development,test,productionの３種類の環境用に、それぞれデータベースの接続に必要な設定がされている。
必要に応じて記述する。

```
  adapter: DBの接続に使用するアダプタ名(mysql2,postgresqlなど)
  encoding: 文字コード
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> (コネクション数の上限)
  database: データベース名
  username: データベースに接続するユーザ名
  password: データベースに接続するパスワード
  host: データベースが動作しているホスト名またはIPアドレス

＊IPアドレスとはコンピュータに割り当てられた「住所」(識別番号)
```


## まとめ
処理の流れの大体イメージしてから勉強を進めるとに入ると頭に入りやすくなると思います

#### 参考書 
・Web技術の基本
・現場で使えるRuby on Rails5 速習実践ガイド
RPCIを受講してきた

# はじめに
RCPIは情報処理安全確保支援士が受講を義務付けられている特定講習の1つです。情報処理安全確保支援士でなくても受講は可能ですが、情報処理安全確保支援士が優先されます。なお、私が受講した回は定員48名のところ10名しかおらず、かなり空きがある状態でしたので、情報処理安全確保支援士でなくても受講することはできそうです。
ただし講師によれば、春と冬がピークらしいので、受講する方はこのピークを避けた方が良いかもしれません。

https://rpci.nict.go.jp/

なお、受講する会場はかなり広く、48名の定員が全員入っても十分な広さがあります。
時節柄密を避けているものと思います。

# 講習の内容
まず最初に、シナリオの内容についてはネタバレになるため記載しません。ここではシナリオのネタバレにならない範囲でどのような内容だったか記載します。

受講前に事前学習があります。内容はツールの使い方がメインで、知っている人は飛ばしても良いです。私は事前学習はほぼ行わずに当日を迎えても問題ありませんでした、

当日の講習内容は、疑似的なセキュリティインシデントに対応するため7つの課題をチームでこなすというものです。1チームは３～４名で、最初に役割（ベンダ担当、連絡担当、情シス担当）を決めます。決められた役割ごとに与えられる情報が異なるため、チーム内で素早く情報を共有する必要があります。
あとは与えられた情報を元に、実機を触ったりしながら調査を進め、インシデントの収束に向けて頑張るというものです。私のチームでは最も経験があったのが私だったので、率先してリーダーを引き受け、引っ張っていくように動きました。

# 注意点
最初の事前説明の後は終了時間まで各チームで頑張ることになり、休憩は自由にとれます。ただし、特定講習では9割以上の時間で出席する必要があるため、会場から出る際に時刻が記録されます。昼休みおよび指定された休憩時間以外で退室できる時間は36分までです。このため、例えば急に仕事の電話が入ったなどで中座する際は、36分を超えてしまうと受講証明が出ず、資格の更新ができませんので注意が必要です。ここは厳密に記録されるので、途中中座しなくて済むように業務調整が必要です。この36分にはトイレ休憩も含まれます。トイレは開始前や昼休み等に済ませておきましょう。

# 最終結果
後日、受講証明書とともに課題の採点結果が送られてきます。
1日を通して行った実習が上の点数、最後に行われた確認テスト（個人で受けたもの）が下だと思いますが、なぜかグループ得点と記載されています。

課題１～６はほぼ満点でしたし、インシデント報告書もかなり高得点が取れてよかったと思います。確認テストは受ければOKとのことだったので正直深く考えずに解いてしまったのですが、それでもまあまあ得点できたかなと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549537/0483f8b9-5ec6-3da3-7601-6ff88e54f865.png)


# 感想
実際のインシデントに近く、非常に良い講習だと思いました。技術的なことがわからない人に対しても手厚いサポートがあり、途中で詰まることはまずないと思われます。
情報処理安全確保支援士試験ではそれなりに技術的な内容を問われますが、業務ではそれほどテクニカルな内容をやっていないという人も多いと思います。そういった方でも安心して受講できると思います。

これだけ充実した内容で8万円というのはかなり安いんじゃないでしょうか？
他の講習は軒並み高額で、内容は充実しているものと思いますが、費用対効果を考えれば、RPCIはかなりお得だと思います。NICTが国立研究開発法人であり、民間企業ではないというのが大きいでしょう。
【Flutter/Dart】Providerのコンストラクタで非同期処理をする方法

:::note warn
警告
Flutter初心者が応急処置的に取った方法です。
公式に推奨される方法ではないかもしれないためご注意ください。
:::

サーバーのデータベースにあるデータを使ってProviderのクラスを初期化したかったのですが、async/awaitがコンストラクタでは直接使えないため、ハマりました。

最終的に、このようにして解決しました。

* 非同期処理を別の関数に切り出す。私はinit関数に処理を書きました。
```dart
init() async {
// ここに処理を書く
}
```
* コンストラクタ内で、このように書く
```dart
Future(() async {
    await init();
    notifyListeners();
});
```
Ubuntu のグループ操作覚書

## グループの作成

```shell
$ addgroup グループ名
```

## グループにユーザーを追加

```shell
$ usermod -a -G グループ名 ユーザー名
```

## グループからユーザーを削除

```shell
$ deluser ユーザー名 グループ名
# または
$ gpasswd -d ユーザー名 グループ名
```

## ユーザーの所属しているグループ一覧

```shell
$ groups ユーザー名
```

## グループに所属しているユーザー一覧

```shell
$ getent group グループ名
```
Next.jsでImageが表示されない現象の解決


Next.jsで画像を表示するのに結構手間取ったので備忘録として書いておきます

# 目次
1.[エラー](#エラーメッセージ)
2.[原因と解決法](#原因と解決法)

## エラー

画像を以下のように表示しようとしていたが、表示されなかった。

```Next.js

<Image src='assets/icons/icon.png' alt='logo' width={100} height={100} />

```

## 原因と解決法

### 原因その１ : publicフォルダに入れていなかった
Next.jsで静的ファイルを扱うときはプロジェクト直下にpublicフォルダを作ってそこにいれなきゃならんらしいです。

```Next.js

<Image src='public/icons/icon.png' alt='logo' width={100} height={100} />

```

しかしそれでも表示されない...

### 原因その２ : パスの指定の仕方が間違っていた

Next.jsではpublicフォルダの中身はルートディレクトリとして扱われる?ので、publicフォルダの中身を指定するときは以下のように書く必要があるみたいです。

```Next.js
// <Image src='public/icons/icon.png' alt='logo' width={100} height={100} />
<Image src='/icon.png' alt='logo' width={100} height={100} />
```

ここまでやって無事表示されました。

### 解決法

imageファイルなどの静的ファイルを扱うときは、

1. publicフォルダに入れる
2. パスは`public/icons/icon.png`のような階層構造であっても`/icon.png`と書く


お役に立てば幸いです。
WindowsでサクっとApache Benchを実行する

久しぶりに手元にMacOS機がなくなった。Apache Bench実行しようとしたのだが、当然、OS標準的な機能ではないし、Apache httpdはインストールしたくないしで、どうしようかと考えたので、その結果を記しておく。

# 結論
WSL(Windows Subsystem for Linux)とUbuntuのインストール。Ubuntuで、

`sudo apt-get install apache2-utils `

で、apache httpd等無駄なファイルインストール無しに、Apache Benchのインストールが可能。なにかと、Linux使えた方が便利と思えば、この方法がもっとも現実的。
jestを実行するとjest syntaxerror package.json Unexpected end of JSONエラーが出る

# はじめに

とあるタイミングで`node_module`を削除したところ`jest`が通らなくなったのでまとめます

# 問題

```
$ npm run test
```

をすると以下のエラーが発生しました

```
jest syntaxerror package.json Unexpected end of JSON
```

node_moduleのエラーだったので、Nodeのバージョンを見たところ20系で問題なさそうでした
また

```
$ rm -rf /node_modules && npm i
```

をしてもうまくいきませんでした

# 解決方法

キャッシュを消して、`.npm`を削除したところうまくいきました

```
$ npm cache clean --force &&  rm -rf ~/.npm &&  rm -rf node_modules
```

# おわりに

たまにこのエラーで悩まされるので供養しておきました
Eclipse ショートカット Cheat Sheet

# はじめに
業務でEclipseを触りだして1か月の初心者が、覚えたてのショートカットをまとめてみました！

# コーディング
|ショートカットキー  |内容  |備考  |
|---|---|---|
|Ctrl + Z  |元に戻す。  |  |
|Ctrl + S  |上書き保存する。  |  |
|Tab  |インデントを1つ下げる。  |  |
|Tab + Shift  |インデントを1つ上げる。  |  |
|Ctrl + Shift + F  |コードフォーマットを整える。  |  |
|Ctrl + /  |１行単位でコメントアウトする/解除する。  |範囲選択可能  |
|Ctrl + Shift + /  |複数行をコメントアウトする。 |  |
|Ctrl + Shift + \  |複数行をコメントアウトを解除する。 |  |
|Ctrl + クリック  |宣言を開く。  | メソッドの中身を確認する |


# デバッグ
|ショートカットキー  |内容  |備考  |
|---|---|---|
|F5  |呼び出しメソッドの中に入って一時停止する。  |  |
|F6  |次の行で一時停止する。  |  |
|F7  |呼び出し元のメソッドに戻って一時停止する。  |  |
|F8  |プログラムの終了まで実行する。  |ブレークポイントが存在する場合、プログラムを再開してからブレークポイントまで実行し、そこで一時停止する。  |
|Ctrl + F2  | デバッグを終了する。 |  |

# テスト
|ショートカットキー  |内容  |備考  |
|---|---|---|
|Ctrl + 9  |対応するテストを開く。なければ作成する。 |  |
Chromeの最小フォントサイズの10px制限がなくなった

## 概要
Chrome 118からフォントサイズの下限値10pxの制約がデフォルトでオフになり、特にユーザ側で設定していない場合は0pxが下限値になるようになりました。

## 影響
- CSSで10px未満を指定した場合や相対サイズ(em, %など)が10px未満でもそのまま反映されるようになる
- 上記に起因したレイアウト崩れが起きる可能性がある

## 設定値の変更
設定値はChromeのフォント設定画面の`最小フォントサイズ`という項目で変更することができます。
chrome://settings/fonts

## 参考
https://developer.chrome.com/blog/chrome-118-beta/#consistent-minimum-font-size-across-languages
定時帰る術-Linuxファイル編集（viコマンド）

Linuxの世界では、「Everything is a file」という設計思想というか、名言というか、わかりません、そのファイルをいじるときにviがよく使われている
viが定義ファイルの編集手段の一つとなる。
**windowsでファイルを編集して、Linuxにアップロードすることでもいけないはない。
文字コードと改行コードに注意する必要があるから、個人的にはやらない方がいいと思う**
仕事でよく使うコマンドを記載しようと思う

### viでファイルを開く
```
vi anaconda-ks.cfga
```

### カーソル移動
コマンドでもキーボードの矢印キーでもできる
```
上：↑：k
下：↓：j
左：←：h
右：→：l
e：現ワードの最後の文字に移動
gg：ファイルの先頭行に移動
```

### 追加
```
a：カーソルの右にテキストを追加 
A：行の末尾にテキストを追加 
0：カーソルがある下の行にテキストを挿入
o：カーソルがある上の行にテキストを挿入 
yy：行コピー 
p：カーソルがある行の下に挿入 
P：カーソルがある行の上に挿入 
```
### 削除
```
x：カーソルの文字を削除
dd：行削除
d99：99行削除
```
### 検索
```
/test：文字例検索
n：検索方向の前方に/で検索した文字列を検索 
N：検索方向の後方に/で検索した文字列を検索 
```

### :系
```
:321：321行目に移動
:set number ：行数を表示される
:q!：保存せず終了
:wq：変更保存し終了
```

### 文字例置換
```
:%s/#//g：「#」を「」にする（#を削除する）
```
np.exp(x) よりも np.e**x の方が速いことがあるらしい

# 経緯・目的
`numpy.exp()`の計算速度が気になって少し調べているときに，[np.exp much slower than np.e?](https://stackoverflow.com/questions/30021428/np-exp-much-slower-than-np-e) という記事を見つけた．
質問と回答を読んでざっくり理解したことはこんな感じ：

- `np.exp(100)`よりも'np.e**100'の方が10倍くらい速い．
- これは`np.exp()`が array に対応しているので，型の判定をする分のoverheadで遅くなっている可能性がある（ただしこれだけで速度差のすべてを説明できるわけではなさそう）．

これは2015年の記事なので，そのあと変化があったのか気になり，同じような簡単な計測をしてみた（Python 3.11.5, numpy 1.26.1を使用）．

# 結論
上に引用した記事と同様の結果だった：

- 引数がスカラー値（arrayではないという意味）の場合には`np.e**(x)`の方が速い．
- 引数がarrayの場合にはそこまで差がないか，要素数が多ければ`np.exp(x)`の方がかなり速い．

＊網羅的に調べたわけではないので，環境や引数の具体的な値によって結果が変わり得ると思う．

# 具体的なコードと結果
簡単な計測なのでターミナルで実行していく．
バージョンはPython 3.11.5，numpy 1.26.1．

はじめに`timeit`をimportしておく．
```python
>>> from timeit import timeit
```
## 引数の要素数が1の場合
引数の要素数が1である場合，`int`や`float`の変数をそのまま渡すと`np.e**x`の方がだいぶ速いが，要素数1の`ndarray`を渡すと速度の差が小さくなった．

`int`型をそのまま渡すと`np.e**(x)`の方が数倍速い．
```python
>>> timeit("np.exp(x)", setup="import numpy as np; x = 10")
0.48411501699956716
>>> timeit("np.e**(x)", setup="import numpy as np; x = 10")
0.07219130100020266
```
1要素からなる1次元の`ndarray`を渡すと，`np.exp(x)`は速くなって，`np.e**(x)`はかなり遅くなる．
```python
>>> timeit("np.exp(x)", setup="import numpy as np; x = np.array([10], dtype='f8')")
0.2373395429995071
>>> timeit("np.e**(x)", setup="import numpy as np; x = np.array([10], dtype='f8')")
1.2322995980002815
```
ちなみに`x = np.array([10])`とすると（`dtype`の指定をやめると）多少速くなった．
しかしそれでも`np.exp(x)`の方が速かったし，バグのもとだと思うので個人的には`dtype`は明示しておきたい．

引数の値を変えても傾向は変わらない．引数がarrayではない場合，むしろ差が開く．
```python
>>> timeit("np.exp(x)", setup="import numpy as np; x = 100")
0.5663321909996739
>>> timeit("np.e**(x)", setup="import numpy as np; x = 100")
0.06345759199939494
```
```python
>>> timeit("np.exp(x)", setup="import numpy as np; x = np.array([100], dtype='f8')")
0.24133333999998285
>>> timeit("np.e**(x)", setup="import numpy as np; x = np.array([100], dtype='f8')")
1.221896048000417
```

## 引数の要素数が2以上の場合
2以上といいながら`np.arange(95, 105, dtype="f8")`で試した結果だけを載せる．
```python
>>> timeit("np.exp(x)", setup="import numpy as np; x = np.arange(95, 105, dtype='f8')")
0.2651955380006257
>>> timeit("[np.e**(n) for n in x]", setup="import numpy as np; x = np.arange(95, 105, dtype='f8')")
1.3422866170003545
```
ちなみにこのケースでは`dtype`を指定した方が速かった（指定しないと2 - 5倍程度時間がかかった）．

# 教訓
- 要素数1の変数しか扱わないことが確実な場面では`float`型の変数を使って`np.e**x`とすると速い．
    - `ndarray`から取り出したスカラー値は`np.float64`などになっていて，これだと`np.e**x`はそこまで速くない．トリッキー．
- 要素数1でも`ndarray`を渡すなら`np.exp(x)`とした方がよい．また`np.exp(x)`を使うなら引数は`ndarray`にしておいた方が速い．
    - コードの他の部分の都合で1要素から成る`ndarray`を扱うことがあるので，この点は（自分にとっては）意外と大事．
    - 例えば`x = np.arange(5, dtype="f8")[2:3]`のようにして要素数1の`ndarray`を扱うときがある．`size`属性とか使いたい場合．
- 複数の値に対する結果がほしい場合は`ndarray`の`x`を引数として`np.exp(x)`とするのがよい．
    - `x`を生成するときは`dtype`も指定しておくとより速そう．
PowerShellサンプルの集まり（MSMQ送受信、MS-TEAMSのメッセージ）

## 前書き
* ソースはインターネットから参照し、自分が動作確認済み
* 参照先は省略


## PowerShellコマンド
:::note info
Teamsと連携
:::

```powershell:Teamsと連携
Connect-MgGraph -Scopes "Chat.ReadWrite, ChannelMessage.Send"

Get-MgChat -All | Select-Object Id, Topic > d:\temp.txt
Get-MgChat -All | Where-Object {$_.Topic -like '*社員群*'}

$chatId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$params = @{ body = @{ content = "PowerShell send message to Teams:Hello World2" }}
New-MgChatMessage -ChatId $chatId -BodyParameter $params
```

:::note info
MSMQと連携
:::

```powershell:MSMQ メッセージ送信
[Reflection.Assembly]::LoadWithPartialName("System.Messaging")

function WriteMessageToMSMQ($queueName, $message, $label) {
  $utf8 = new-object System.Text.UTF8Encoding
  $msgBytes = $utf8.GetBytes($message)

  $msgStream = new-object System.IO.MemoryStream
  $msgStream.Write($msgBytes, 0, $msgBytes.Length)

  $msg = new-object System.Messaging.Message
  $msg.BodyStream = $msgStream
  if ($label -ne $null) {
    $msg.Label = $label
  }

  $queue = new-object System.Messaging.MessageQueue $queueName
  $queue.Send($msg)
  Write-Host "Message written"
}

#-------------------------
#Test the above functions 
#-------------------------
cls  #clear screen (junk from prior runs) 
$queueName = ".\Private$\Test"

$message = "This is my first test message"
WriteMessageToMSMQ $queueName $message $null

$message = "This is my second test message"
WriteMessageToMSMQ $queueName $message "MyLabel"

Write-Host "Completed"
```

```powershell:MSMQ メッセージ受信
[Reflection.Assembly]::LoadWithPartialName("System.Messaging")

function ReadMessageFromMSMQ($queueName) {
  $queue = new-object System.Messaging.MessageQueue $queueName
  $utf8  = new-object System.Text.UTF8Encoding

  $msgs = $queue.GetAllMessages()
  write-host "Number of messages=$($msgs.Length)" 

  foreach ($msg in $msgs) {
    write-host $msg_.Id
    write-host $utf8.GetString($msg.BodyStream.ToArray())
  }
  $queue.Purge() #Clear All Message
}

#-------------------------
#Test the above functions 
#-------------------------
cls  #clear screen (junk from prior runs) 
$queueName = ".\Private$\Test"
ReadMessageFromMSMQ $queueName
Write-Host "Completed"
```

:::note info
環境変数設定
:::
```powershell
[Environment]::SetEnvironmentVariable("NODE_PATH", "C:\aaa\nodejs\", "User")
```

## TypeScript サンプル

```typescript:日付フォーマット
DateFormat(dateObj: Date): string {
  let sss: string = dateObj.getFullYear() + "."
    + this._ZeroPadding((dateObj.getMonth() + 1), 2) + "."
    + this._ZeroPadding(dateObj.getDate(), 2) + "-"
    + this._ZeroPadding(dateObj.getHours(), 2) + "."
    + this._ZeroPadding(dateObj.getMinutes(), 2) + "."
    + this._ZeroPadding(dateObj.getSeconds(), 2);
  return sss;
}
```

```typescript:「0」を埋める
_ZeroPadding(num: number, len: number){
    return ( Array(len).join('0') + num ).slice( -len );
}
```

## SVNコマンド
フォルダのみ残し、ファイルをコミットしない。
```svn propset svn:ignore * .```
不動産取引価格情報取得API（国交省）のPythonラッパーを作った

# お断り

この記事を作った時点では、このAPIは動作していたのですが、2024/5/12日時点では、APIが停止したため、このラッパーも意味をなさなくなりました。

不動産関連のデータ取得には、国交省から新たな[不動産ライブラリ](https://www.reinfolib.mlit.go.jp/)が利用できます。APIの利用には申請が必要ですが、無料で活用できます。

以前のものより充実した内容になっているので、おすすめのAPIです。

この記事はもう使えなくなったAPIのラッパーに関する記事ということでお読みいただけますと幸いです。

## 本文

最近、日本の不動産価格が上昇しているという記事をよく見ます。昨日はマンションが値上がりしているという記事を見かけました。

https://www.nikkei.com/article/DGXZQOFC1539C0V10C23A9000000/

足元金利が上がり始めているので、この上昇が継続するのかもよくわからないけど、どんな感じで取引されているのか理解したいと思いました。一方で、不動産取引は取引所とかで取引されているわけでないので、どれくらい盛り上がっているかとか、近所でどんな取引があるかつかめない印象でした。

しかし、調べたところ、日本の不動産取引価格は国交省がAPIで提供していることが分かりました。

不動産取引価格情報取得API（国交省）: https://www.land.mlit.go.jp/webland/api.html

「人生で最も高い買い物の不動産の価格こそ、しっかりその動向をつかんでおくべきではないか！」と思い、APIをPythonから叩きやすくしたラッパーを作り、PYPIに公開しました。

https://github.com/mazarimono/j_realty_api

https://pypi.org/project/j-realty-api/

## 概要
j_realty_api は[国交省の不動産取引価格情報取得API](https://www.land.mlit.go.jp/webland/api.html)を使いやすくするパッケージです。

使ってみて、都道府県コードが分からないとAPIが使えないことが分かり、都道府県コードを探す機能を付けました。都道府県コードと市町村コードが簡単に探せて、不動産の取引価格の情報が得られます。

## 使い方
まずはインストールしてください。

```sh
$ pip install j_realty_api
```

APIは日本語、英語の2種類があります。

### 英語
まずは英語の使い方サンプルです。([サンプルノートブック](https://github.com/mazarimono/j_realty_api/blob/main/samples/sample_j_realty_en.ipynb))

1. 都道府県名の一部または全部を渡します。それにより、都道府県コードが得られると共に、city_json に市町村名とコードのjsonが渡されます。そこからどのような市町村があるかや市町村コードを探せます。
2. 次に市町村名を渡すと、指定した市町村のコードが得られます。
3. 上記で得た都道府県コード、市町村コードを使って、不動産取引価格情報取得APIから情報を得ます。期間は四半期ごとの指定となるため、西暦の後に第何四半期化を渡します（YYYYQ）。
4. データを得ます。得たデータはpandasのDataFrameで返されます。

```python
# English
from j_realty_api import j_realty_en as jrn

j = jrn.CityCode('Kyoto') #1
pref_code = j.pref_code 
city_code = j.city_code('kyoto') # 2
pt = jrn.PropTransactions(pref_code, city_code, 20223, 20224) #3
df = pt.get_data() #4
```

ここの例では京都府、京都市のデータを取得しました。APIからの情報は取引価格以外にも、建築年、間取り、広さ、建蔽率、リノベーションの有り無しなどの情報が含まれます。

![スクリーンショット 2023-10-20 093937.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85433/e1bdcb45-688f-3ee4-f988-f3e82c98eb7f.png)
(得られるデータの一部)

もちろん完璧にそろっているわけではありませんが、結構そろっているので、いろいろと分析できます。

### 日本語

日本語のAPIもあります。こっちは結構前処理をしています。もう少ししないとなぁとは思うのですが・・・。使い勝手は英語と同じような感じです。([サンプルノートブック](https://github.com/mazarimono/j_realty_api/blob/main/samples/sample_j_realty_jp.ipynb))

```python
from j_realty_api import j_realty_jp as jrp

j = jrp.CityCode('京都')
pref_code = j.pref_code
city_code = j.city_code('京都')
pt = jrp.PropTransactions(pref_code, city_code, 20223, 20224)
df = pt.get_data()
```

![スクリーンショット 2023-10-20 095943.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85433/52b868f7-5f93-3dfa-8459-6ea16a301a51.png)


## まとめ
というわけで、不動産の取引動向が知れる国交省のAPIのラッパーパッケージj_realty_apiを作成しました。人生で最も高い買い物の不動産、その取引動向がつかめるのは非常に参考になる思います。

あと、パッケージへの要望やアドバイス、プルリクも大歓迎です。Qiitaの「いいね」やgithubへの「スター」もいただけますと幸いです。お読みいただきありがとうございました。

https://github.com/mazarimono/j_realty_api
C# 超入門

# はじめに
仕事でC#を使うことになりそうなので、Pythonの経験しかない私がC#の基本から学習していく過程をアウトプットしていこうと思います。
今回は、基本的なことをコンソールに出力しながら実行していきます。
# 環境
- Windows10
- Visual Studio 2022

# 環境構築
### Visual Studioのインストール
以下のサイトからVisual Studio コミュニティをダウンロードし、ローカルにインストールします。

https://visualstudio.microsoft.com/ja/downloads/

# プロジェクトの作成
VisualStudioを起動し、「新しいプロジェクトの作成」をクリックします。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610435/b23fb8ac-3ba9-139d-fe85-acf9b884e285.png)
### 「コンソールアプリケーション(.NET Framework)」をクリックします。
![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610435/1659fe72-aad5-ce3b-4aac-3d14394c8d0a.png)
### プロジェクト名を入力し、「作成」をクリックします。
![図3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610435/d799c5b2-84d6-6927-081f-cc6839baa1f1.png)
プロジェクトが作成され、「Program.cs」が表示されます。
```Console.WriteLine("C#を勉強するぞ！！")```と入力して実行してみます。
```cs:Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FIrstConsoleApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("C#を勉強するぞ！！");
        }
    }
}
```
![図4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610435/ef45f2f4-1bb8-14a4-9573-e47478b83256.png)
出力されました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610435/582dc083-e1a3-4963-b1b9-e35bd5ebd109.png)

# 基本的なこと
### コメントアウト
- ```//コメント```
- ```/*コメント:/```
```cs
 //コメント

/*コメント
 コメント*/
```
コメントアウトのショートカット
コメントアウトしたい行にカーソルを移動（または範囲を選択）して
1. 「Ctrl」 + 「K」
2. 「Ctrl」 + 「C」

コメントアウトを外すときは
1. 「Ctrl」 + 「K」
2. 「Ctrl」 + 「U」

### 変数のつけ方
変数を宣言するときは```var``` ```int``` ```string```をつける。

:::note info
var enything = '';
int number = 0;
string text = "aaa";
:::

型の種類
- 自動推論（自動的にどんな型なのか推測してくれる）: var
- 整数型: int unit long
- 文字列型: char string
- コンポーネント型: MonoBehaviour Sample Transform

とりあえずvarを使っていると、コードを後から見た特にわかりにくいためデータ型をしっかり書いた方がいいとのこと。

### if文
```cs
if (条件式)
{
    Trueのとき
}
else
{
	Falseのとき
}
```

### List

型の後に[]をつけ、{}の中に要素をカンマ区切りで入れる。
異なる方は格納できない
```cs
string[] fruits = {"バナナ", "ブドウ", "リンゴ"}

int[] arrNum = new int[] { 1, 2, 3, 4, 5 };

string[] fruits = {"バナナ", "ブドウ", 1} //NG
```
リストをfor文で処理する
```cs
for(int i=0; i<fruits.Length; i++) //.Lengthでリストの長さを取得できる
{
    Console.WriteLine(fruits[i]);
}
```

---
今回はここまで。
変数の宣言がpythonとは違うようです。
Visual Studioでのショートカットも他のエディタ（VScode、sublime）とは違うようなので、今後慣れていきます。

### 参考にしたサイト
https://www.youtube.com/watch?v=YBisOscPHBQ