OmniAICreator/Qiita-1.07M huggingface dataset:
Juliaでコンペに参加した。

# はじめに
以前からちょくちょく参加していたNishika様が主催するコンペにJuliaで挑戦しましたので、まとめたいと思います。
今回の記事では、結果を提出するまでの流れを併せて、どのような処理をしていったかを紹介します。
処理内容については過去の記事と同じことを行っています（可視化の部分は省略）。

https://qiita.com/inoshun/items/7b0b91e3d621b29443f3

# Nishikaのコンペ参加方法
とりあえずアカウントを作成してください。
以下のURLからNishikaのページへアクセスし、右上の新規登録からアカウント登録を行ってください。

https://www.nishika.com/

登録を行い、ログインすると

![nishika.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/52d5959a-1c8c-a54d-f9ac-53c88d42d27f.png)

このような画面になると思います(スカウト等は企業名が出てるので伏せております)。
上記タブの一番左に`Competition`とあるので、クリックします。

![conpe.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/34c88068-a2ed-3a7a-4688-f5ada400a4af.png)

このような画面になると思います。
開催中のコンペティションの`中古マンション価格予測 2024冬の部`というコンペがあるので、クリックします。

![manshon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/97ccd8ad-d737-3471-0ff0-dbd3e44bbdbe.png)

私は既に参加してしまっているので、表記が異なりますが、タブのの一番右に`コンペに参加`という青いボタンがありますので、クリックして参加することができます。

`コンペ概要`タブから、評価方法をクリックし、このコンペのデータの評価方法を確認します。
今回は、ターゲットは`取引価格（総額）_log`、評価指標は`MAE`となっていますね。↓
![hyouka.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/2009652a-5c14-7184-0369-5705fe2c2f30.png)

その後、データタブから必要なデータをダウンロードします。

![data.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/a925f3a4-a8b0-4d20-3bbe-291b2cce6450.png)

これでコンペの準備は整いました！

---

ダウンロードしたデータを用いて、データの前処理や機械学習モデルを作成し、予測値を算出します。
算出した予測値をcsvファイルとして出力し、Nishikaのコンペページの一番右タブの`結果を投稿`というボタンをクリックして提出します。

![teishutu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/45dae373-4cf7-d6e4-c16d-09895582362f.png)

提出すると5～10秒ほどでスコアが出ます。
ランキングタブから自身のスコアを確認することができます。
最初のスコアでは18位でした。
これから順位を上げていきたいですね！
前処理や機械学習モデルを作成したコードはコンペ終了後に記事として上げたいと思います。

![18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/c21674d8-2726-a56b-b49c-aae7b364cb37.png)

他にもトピックなどでヒントやデータについての情報などが出回ることがあるので定期的に確認するといいかもしれません。
ただ、ほとんどPythonなので、他言語を用いている方は参考程度にするとよいかもしれません。

# まとめ
私は過去に数回ほどNishikaのコンペに参加した経験がありますが(kaggleも数回)、今回はJuliaの可能性を確かめるためにJuliaのみ使用していこうと思います。
まあ、`PyCall.jl`で呼び出すことはあるかもしれませんが、極力Juliaのみで挑戦してみようと思います。

もし、自分もJuliaで挑戦したい！と強い気持ちをお持ちの方は是非 X(旧Twitter)の方でDMをいただけると嬉しいです。
チームは5人まで参加可能で、すでにお一人声をかけていただいておりますので、良ければ一緒にデータサイエンスしながらJuliaを学びましょう！

それでは！！！
Elixirのエントリーポイント

# はじめに

ElixirとErlangは切ってもきれない関係にあります。
Elixirのelixirコマンドの実態はErlangのerlコマンドで、elixirはErlangVMの上で動作します。

# elixirコマンドの実体

elixirコマンドの実体を確認するために、環境変数`ELIXIR_CLI_DRY_RUN`に値を入れて実行してみましょう。
[ここ](https://github.com/elixir-lang/elixir/blob/main/bin/elixir#L244C11-L248)にあるように、elixirコマンドを実行する際、この環境変数に値が入っていると、elixirコマンドを実行(exec)するのではなく、表示(echo)します。

```
$ elixir -v
Erlang/OTP 26 [erts-14.0.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit]

Elixir 1.16.0 (compiled with Erlang/OTP 24)
$ ELIXIR_CLI_DRY_RUN=1 elixir -v
erl -noshell -elixir_root /Users/ohara_tsunenori/.asdf/installs/elixir/1.16.0/bin/../lib -pa /Users/ohara_tsunenori/.asdf/installs/elixir/1.16.0/bin/../lib/elixir/ebin -s elixir start_cli -elixir ansi_enabled true -extra -v
$
```

`elixir -v`の例を見ると、elixirコマンドの実体はerlコマンドだとわかります。

# erlコマンドの実体

それではerlコマンドの実体は何でしょうか？
erlangをコンパイルすると、erlコマンドが生成されます。
このerlコマンドの実体は、[このような](https://github.com/erlang/otp/blob/master/erts/etc/unix/erl.src.src)シェルスクリプトです。

コマンドの実体としては、[以下の様な](https://github.com/erlang/otp/blob/master/erts/etc/unix/erl.src.src#L57C1-L57C33)erlexecプログラムです。

```
exec "$BINDIR/erlexec" ${1+"$@"}
```

# erlexecプログラムの実体

では、erlexecプログラムの実体は何でしょうか？
それは[C言語で実装](https://github.com/erlang/otp/blob/master/erts/etc/common/erlexec.c)されたプログラムです。

Erlangをコンパイルすると最終的にこのCソースコードがコンパイルされてerlexecになります。

# まとめ

elixirとerlangの実行コマンドのエントリーポイントを紹介しました。
elixirのプログラムが実行されるとき、裏で何がおこっているのかは、これらのエントリーポイントから追っていくと理解できます。
Amazon EKS - プライベートクラスター

# プライベートクラスター

ここでは、AWS クラウド上にデプロイされているが、アウトバウンドのインターネットアクセスを持っていないAmazon EKS クラスタをデプロイする方法について学習します。


# VPC エンドポイント

クラスターの VPC サブネットには、Pod がアクセスする必要のあるすべての AWS のサービス に対して VPC エンドポイントが必要です。

|サービス|エンドポイント|
|---|---|
|Amazon EC2|	com.amazonaws.region-code.ec2|
|Amazon Elastic Container Registry (コンテナイメージの取得用)|	com.amazonaws.region-code.ecr.api、com.amazonaws.region-code.ecr.dkr、および com.amazonaws.region-code.s3|
|Application Load Balancerおよび ネットワークロードバランサー|com.amazonaws.region-code.elasticloadbalancing|
|Amazon CloudWatch Logs|	com.amazonaws.region-code.logs|
|AWS Security Token Service (サービスアカウントに IAM ロールを使用している場合に必要)|	com.amazonaws.region-code.sts|

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/private-clusters.html


# パターン A

CloudFormation で VPC エンドポイントを先に作成し、privateAccess を有効にする

https://eksctl.io/usage/vpc-cluster-access/

```yaml
vpc:
  clusterEndpoints:
    publicAccess:  <true|false>
    privateAccess: <true|false>
```

## 1. VPC エンドポイントを作成する(Cloudformation)
  
![スクリーンショット 2023-12-30 17.12.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/48c6d8e3-37b3-d552-712c-5791fc815627.png)

https://repost.aws/ja/knowledge-center/eks-cluster-node-group-private-network

## 2. ClusterConfig で、clusterEndpoints.privateAccess: true にする

ここでの設定は、

- エンドポイントのプラーベートアクセス: 有効
  - クラスターの VPC 内から送信される Kubernetes API リクエストは、VPC エンドポイントを使用
- エンドポイントのパブリックアクセス: 有効（アドレス指定有り）
  - インターネットからパブリックエンドポイントと通信するためのアドレスを指定

としています。

その他の組み合わせについては以下ドキュメントを参照。

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/cluster-endpoint.html#modify-endpoint-access

```ClusterConfig.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: cluster-demo
  region: ap-northeast-1
  version: "1.28"  

iam:
  withOIDC: true

fargateProfiles:
  - name: fargate-default
    selectors:
      - namespace: default
      - namespace: kube-system

vpc:
  subnets:
    private:
      us-east-1a:
        id: "subnet-XXXXXXXXXXXXXXXXX"
      us-east-1b:
        id: "subnet-YYYYYYYYYYYYYYYYY"
      us-east-1c:
        id: "subnet-ZZZZZZZZZZZZZZZZZ"
  clusterEndpoints:
    privateAccess: true
    publicAccess:  true
  publicAccessCIDRs: ["1.1.1.1/32", "2.2.2.0/24"]
```


# パターン B

privateCluster を有効にすることで、完全プライベートなクラスターを作成する。
この時、冒頭で説明させていただいた、VPC エンドポイントが作成される。

https://eksctl.io/usage/eks-private-cluster/

```yaml
privateCluster: 
  enabled: true
```

## 1. ClusterConfig で、privateCluster.enabled: true にする

```ClusterConfig.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: cluster-demo
  region: ap-northeast-1
  version: "1.28"

iam:
  withOIDC: true

fargateProfiles:
  - name: fargate-default
    selectors:
      - namespace: default
      - namespace: kube-system

privateCluster:
  enabled: true

vpc:
  subnets:
    private:
      ap-northeast-1a:
        id: "subnet-XXXXXXXXXXXXXXXXX"
      ap-northeast-1c:
        id: "subnet-YYYYYYYYYYYYYYYYY"
      ap-northeast-1d:
        id: "subnet-ZZZZZZZZZZZZZZZZZ"
```
Node.js のインストール方法

# はじめに
Qiita CLI の利用にあたり、Node.js をインストールする事になったので手順をStep by Step で記録しておきます。
本記事は出来るだけエンジニア以外の方にも分かりやすいように執筆していきます。エンジニアの方にはかえって回りくどい事もあるかよ思いますが、ご承知おきください。

# 環境
- Windows11

# インストールしたバージョン
- node-v20.10.0-x64

# インストール手順
1. [Node.js](https://nodejs.org/en/download) のHPにアクセスし、インストーラーをダウンロードします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/0d2a8fe4-4651-fbfd-ea10-fb644a09768b.png)


    :::note info
    システムの種類はバージョン情報から確認できます。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/9447671d-96d2-a6c0-e98a-8e2c49c7a9df.png)

2. 「ファイルを開く」をクリックして、インストーラーを実行します。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/cae65a8e-7ae0-dcca-0c26-9864370dbe44.png)

3. Next をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/6f92f1cd-6269-0ed6-714a-897b1f93ef32.png)

4. 「I accept the terms in the Lincense Agreement」にチェックを入れ、「Next」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/dd7d501a-a9ac-d9ec-67ae-43948276bb7f.png)

5. インストールフォルダを確認して、「Next」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/b0554beb-e28c-c682-66f9-2d84d61f81c8.png)

    :::note
    インストールフォルダを変更したい場合は「Change」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/229dc76f-9d0f-abd7-5350-c551d3a99144.png)
    Look in からフォルダを指定して「OK」をクリックし、変更します。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/4e2e6d5b-8a36-c10d-fa81-187c3e65a831.png)

6. 「Next」 をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/7c5659d6-0bb5-3e93-fc76-2c5a1ab2ccbc.png)

7. 「Next」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/8a6b1812-855a-cb9e-2b84-bced3e2aadaf.png)

8. 「Install」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/b3829b06-25ba-fd89-2651-643dfd7a8343.png)

9.「はい」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/f33665a1-334a-1d24-4720-c3fa5da10ecc.png)

10.インストールが完了したら、「Finish」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/5cfacff8-2076-f6b8-5178-f185758ac9d9.png)

# 起動確認
1. タスクバーの検索に「node」と入力します。

2. node.js がヒットするので「開く」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/129526f9-e41c-c41b-b394-b13af3884be8.png)

3. Node.js が起動し、バージョンが表示されます。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/134b94dc-9096-780a-b66d-dac7c11985d6.png)
第4回　StreamlitとLangChainとLM studioを使って自分専用LLMウェブアプリを作りたい！

# 第3回

今回は要約アプリを実際に使ってみました。
参照URL：https://blog.streamlit.io/langchain-tutorial-3-build-a-text-summarization-app/
GitHub:https://github.com/s1932072/LangChain-tutorial-3/tree/main
```Python:main.py
import streamlit as st
from langchain import OpenAI
from langchain.docstore.document import Document
from langchain.text_splitter import CharacterTextSplitter
from langchain.chains.summarize import load_summarize_chain

def generate_response(txt):
    # Instantiate the LLM model
    llm = OpenAI(base_url="http://localhost:1234/v1", api_key="not-needed")
    # Split text
    text_splitter = CharacterTextSplitter(
        #chunk_size = 50,  # チャンクの文字数
        #chunk_overlap = 10,  # チャンクオーバーラップの文字数
    )
    texts = text_splitter.split_text(txt)
    # Create multiple documents
    docs = [Document(page_content=t) for t in texts]
    # Text summarization
    chain = load_summarize_chain(llm, chain_type='map_reduce')
    return chain.run(docs)

# Page title
st.set_page_config(page_title='🦜🔗 Text Summarization App')
st.title('🦜🔗 Text Summarization App')

# Text input
txt_input = st.text_area('Enter your text', '', height=200)

# Form to accept user's text input for summarization
result = []
with st.form('summarize_form', clear_on_submit=True):
    #openai_api_key = st.text_input('OpenAI API Key', type = 'password', disabled=not txt_input)
    submitted = st.form_submit_button('Submit')
    if submitted :
        with st.spinner('Calculating...'):
            response = generate_response(txt_input)
            result.append(response)
            #del openai_api_key
if len(result):
    st.info(response)
```
OpenAI APIをLocalLLMに変更しました。

このプログラムをでは、入力された文章を分割します。その後分割された文章毎に要約を行う。その後要約した各文章を順番に繋げることで、要約する。

一方でこのプログラムだと、使用している　LLMmodelの入力可能token数を超えるとエラーが出てしまう。
そこで、
```Python:main.py 
#chunk_size = 50,  # チャンクの文字数
#chunk_overlap = 10,  # チャンクオーバーラップの文字数
```
この部分でチャンクの文字数とオーバーラップを指定しましたが、エラーが出てしまったので、一旦コメントアウトしておきました。

# 収穫
今回行えた要約が、私のしたかったことの一部分になります。
私の目指すゴールの一つに、RSSやwebからニュース本文を取得して要約したい、がありました。

入力テキスト数によるエラーさえ回避できれば、完成です。

今後加筆修正する可能性もあります。
ご了承ください。

# 次回
この調子でstreamlitの記事を実装していきます。
JavaScriptカスタマイズでは、イミュータブルにEventオブジェクトを変更しよう

kintoneのJavaScriptカスタマイズでは、様々なイベントハンドラを利用してアプリの挙動を拡張します。これらのイベントハンドラ内で使用されるEventオブジェクトをイミュータブル（変更不可）に扱うことでバグを減らすことができます。

# ミュータブルなコードとは

## 例
例えば下記のようなコードは、どのタイミングでも値の変更をゆるすことで、ミュータブルに値を扱っていることになります。
```js
// イベントハンドラ
kintone.events.on('app.record.create.submit', (event) => {
    const record = event.record;
    record.fieldCode.value = 123; // 数値フィールドを変更
    return event;
});
```

## 問題点
パット見るとなにも問題ないようにみえますが、上記のようにeventで渡ってくるコードを直接書き換えてしまうと、ハンドラの中身が長くなったときにどうコードを変更したかがわからなくなり、　バグの温床になります。
間に、ミュータブルにレコードを操作する関数があると最悪で、いつどのように値が変わったかが追えなくなり、非常にやっかいなコードになります。
　
```js
// イベントハンドラ
kintone.events.on('app.record.create.submit', (event) => {
    const record = event.record;
    record.fieldCode.value = 123; // 数値フィールドを変更

    // いくつかの処理をかく

    // ここで、オリジナルのデータを想定した処理をかいてしまう
    if(record.fieldCode.value > 100) {
      // 省略
    }
    
    return event;
});

```

# イミュータブル（変更不可）なコードで表現する

## 例1
上記の例ですと、下記のように表現ができます。
[structuredClone](https://developer.mozilla.org/ja/docs/Web/API/structuredClone) というオブジェクトのコピーをする関数があり、それを利用して、新しいレコードを先につくります。

```js
// イベントハンドラ
kintone.events.on('app.record.create.submit', (event) => {
    const newRecord = structuredClone(event.record);
    const newRecord.fieldCode.value = 123; // 数値フィールドを変更
    // 省略

    // 最後に書き換え
    event.record = newRecord;
    return event;
});
```

## 例2
関数を作るときも、常に新しいオブジェクトを返すようにする（直接書き換えないようにする）ことでバグを減らすことができます。

```js

// イベントハンドラ
kintone.events.on('app.record.create.submit', (event) => {
    const newRecord = structuredClone(event.record);
    // 省略

    // 最後に書き換え
    event.record = addValue(record, 10);
    return event;
});

function addValue = (record, value) => {
    const newRecord = structuredClone(event.record);
    newRecord.fieldCode.value = Number(newRecord.fieldCode.value) + value;
    return newRecord;
}


```


# 補足
少しでもイミュータブルに始めれるとよいですが、下記のように毎回新しい値を作るのが理想です。基本的には上書きをせず、値を新たに定義していくイメージです。
最後に使っているのは[スプレッド構文](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax)というものです。

```js
// イベントハンドラ
kintone.events.on('app.record.create.submit', (event) => {
    const record = event.record;

    // 処理Aをしたレコード
    const executedARecord = funcA(record);

    // 処理Aのあと処理Bをしたレコード
    const executedBRecord = funcB(executedArecord);

    // 結果
    const result = {
        ...event,
        record: executedBRecord;
    }

    return result;
});

```
RealSenseで点群を取得する方法

Intel RealSenseは、深度センサーを使って3Dスキャンを行い、周囲の環境を3Dで捉えることができます。点群取得は、物理的な物から点を捉え、その3D表現を作成する物です。本記事では、Intel RealSenseを使用して点群を取得する方法を取り扱っていきます。

## 1: 必要な物
RealSenseデバイス: RealSenseデバイス（例えば、D415、D435など）が必要です。
RealSense SDK 2.0:動作確認用に [Intelの公式サイト](https://www.intelrealsense.com/sdk-2/)からRealSense SDK 2.0をインストールしてください。(なくてもOK)
Python: Pythonがインストールされていることを確認してください。
pyrealsense2: Python用RealSenseライブラリをインストールしてください。
```
pip install pyrealsense2
```
numpy: numpyインストールしてください。
```
pip install numpy
```
numpy: open3dインストールしてください。
```
pip install open3d
```
## 2: 点群取得のプログラムを作成
以下は、Pythonを使用してRealSenseデバイスから点群を取得し、表示するためのコードです。

```
import pyrealsense2 as rs
import numpy as np
import open3d as o3d

# RealSenseの設定
pipeline = rs.pipeline()
config = rs.config()
config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)

try:
    # ストリーミング開始
    pipeline.start(config)

    # 一定フレーム待つ
    for _ in range(30):
        pipeline.wait_for_frames()

    # フレームの取得
    frames = pipeline.wait_for_frames()
    depth_frame = frames.get_depth_frame()

    # 点群の取得
    pc = rs.pointcloud()
    pc.map_to(depth_frame)
    points = pc.calculate(depth_frame)

    # 点群をNumpy配列に変換し、2次元配列に形状変更
    vtx = np.asanyarray(points.get_vertices()).view(np.float32).reshape(-1, 3)

    # Open3Dを使って点群を表示
    pcd = o3d.geometry.PointCloud()
    pcd.points = o3d.utility.Vector3dVector(vtx)
    o3d.visualization.draw_geometries([pcd])

finally:
    # ストリーミング停止
    pipeline.stop()

```

上記のコードではOpen3Dを使用して点群を表示していますが、他の3D可視化ツールを使用することも可能です。
また、上記のコードでは2次元配列に変換していますが、これはOpen3Dの入力が2次元配列を求めている為です。したがって使用する用途に合わせて適切に変換をかけてください。
docker-compose build はやりたくない　rails

## はじめに
今回、ruby on rails を勉強のためdocker上で環境構築して学習しているのですが、

章が変わるごとにgemを追加して、docker-compose buildで2時間近くかかって、全然学習にならなかったので改善できないか調べて取り組んでみました

## 結論
docker-compose のvolumesを使えばできた。

```diff_yaml
 version: '3'
 services:
   web:
    volumes:
      - .:/app
+     - bundle:/usr/local/bundle
 volumes:
+  bundle:
```

## 概要
* PC : M1 Macbook
m1 Macbookは通常と違う点が多いのでご注意を。

ファイル構造
```:現在のディレクトリ

rails
 ├─ Dockerfile
 ├─ Gemfile
 └─ docker-compose.yml

```


* Dockerfile
* Gemfile
* docker-compose.yml


```:Dockerfile
FROM ruby:3.2.2-alpine
RUN apk update
RUN apk add git g++ make mysql-dev tzdata build-base python3
WORKDIR /app
COPY Gemfile .
RUN bundle config set force_ruby_platform true
RUN bundle install
```

```ruby:Gemfile
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby "3.2.2"

gem "rails", "~> 7.0.8"
```

```yml:docker-compose.yml
version: '3'
services:
  web:
    build: .
    command: sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/app
    ports:
      - 3000:3000
    depends_on:
      - db
    environment:
      MYSQL_ROOT_PASSWORD: 12345
    links:
      - db
    tty: true
    stdin_open: true
  db:
    image: mysql:8.0
    volumes:
      - db-volume:/var/lib/mysql
volumes:
  db-volume:
```
## rails app構築
qiitaで "docker rails 構築" と調べたらわかりやすい方がたくさんいるので簡略化します
1. rails new . --force --database=mysql --skip-bundle
1. docker-compose build
1. docker-compose up -d
1. docker-compose run web rails db:create
1. http://localhost:3000/　

## 本題
imageをもとにコンテナを作っているため、run web bundle installだとコンテナをdownしたらgemは使えなくなります。

docker compose のvolumesを使ってbundlerのデータをマウントして永続化することによって解決できます。

```diff_yaml
 version: '3'
 services:
   web:
     build: .
     command: sh -c "rm -f tmp/pids/server.pid && bundle exec 
rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/app
+     - bundle:/usr/local/bundle
     ports:
       - 3000:3000
     depends_on:
       - db
     environment:
       MYSQL_ROOT_PASSWORD: 12345
     links:
       - db
     tty: true
     stdin_open: true
   db:
     image: mysql:8.0
     volumes:
       - db-volume:/var/lib/mysql
 volumes:
+  bundle:
   db-volume:
```
その後
```
$ docker-compose run --rm web bundle install
$ docker-compose up
```
それでもエラーが出たり反映されなかったら、
```
$ docker-compose run web ash
/app# bundle install  
/app# exit
$ docker-compose up
```
私は前者ではエラーが出ました。なぜか後者のshellに入って実行すると上手くいきました。（なぜ）

ここで気をつけたいことが,linux-alpineを使っていますので、bashではなくashを使っています。
使っている環境によって使い分けてください。

:::note info
alpineのshellはash
:::


## 終わりに
まだまだ勉強しなくてはならないことがたくさんありますねぇ

## 参考文献
[docker-composeでRailsのGemを更新する時、docker buildするのを回避したい](https://qiita.com/neko-neko/items/abe912eba9c113fd527e)
[Docker Composeのvolumesについてわかったことをまとめる](https://qiita.com/taiga_tech/items/d9361f10d521a55659ee)
[Docker Composeのvolumesを使ってもっと効率的に](https://qiita.com/tanaken0515/items/a564d2c46b2942b83ebb)
【PowerShell  5.1】Compress-Archiveコマンドレットで作成したzipファイルを解凍すると文字化けする

## 前提
以下の環境で検証している。
OS : Windows 10 22H2
PowerShell : PowerShell 5.1
## 問題
Compress-Archiveコマンドレットで作成したzipファイルを解凍した際に、
文字化けすることがある。
## 原因
zipファイルを解凍する際に利用しているアーカイバが、
「UTF-8」に対応していないことが原因である。
## 回避方法
1. Windowsの標準機能で解凍する。
    <details><summary>Windowsの標準機能で解凍する方法</summary>
        <ol>
            <li>zipファイルを右クリックし、コンテキストメニュー内の「すべて展開」を選択する。</li>
            <li>「圧縮(ZIP形式)フォルダーの展開」ウィンドウにて、「展開(E)」ボタンを押下する。</li>
        </ol>
    </details>
2. Expand-Archiveコマンドレットで解凍する。
    - サンプルコード
        ```powershell
        $folder = Join-Path $env:USERPROFILE "\Desktop\Test"
        $zip = Join-Path $env:USERPROFILE "\Desktop\Test.zip"
    
        Expand-Archive $zip $folder
        ```   
3. アーカイバが対応しているエンコードを指定して、zipファイルを作成する。
   この方法では、Compress-Archiveコマンドレットを利用せず、
   別の方法でzipファイルを作成している。
   なぜなら、Compress-Archiveコマンドレットには、
   エンコードを指定するパラメータが存在しないためである。
   
   以下2つのサンプルコードは、アーカイバが「Shift_JIS」に対応している場合を
   想定している。
    - フォルダを圧縮する場合のサンプルコード
        ``` powershell
        Add-Type -AssemblyName System.IO.Compression.FileSystem
        
        $folder = Join-Path $env:USERPROFILE "\Desktop\Test"
        $zip = Join-Path $env:USERPROFILE "\Desktop\Test.zip"
        [IO.Compression.ZipFile]::CreateFromDirectory($folder,$zip,[IO.Compression.CompressionLevel]::Optimal,$false,[Text.Encoding]::GetEncoding("shift_jis"))
        ```
    - ファイルを圧縮する場合のサンプルコード
        ``` powershell
        Add-Type -AssemblyName System.IO.Compression
        Add-Type -AssemblyName System.IO.Compression.FileSystem

        $file = Join-Path $env:USERPROFILE "\Desktop\Test.txt"
        $fileName = Split-Path $file -Leaf
        $zip = Join-Path $env:USERPROFILE "\Desktop\Test.zip"
        $zipArchive =  [IO.Compression.ZipFile]::Open($zip,[IO.Compression.ZipArchiveMode]::Create,[Text.Encoding]::GetEncoding("shift_jis"))
        [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zipArchive,$file,$fileName)
        $zipArchive.Dispose()
        ```
## 参考文献
https://qiita.com/tats-u/items/5336bc780a4361e7b780

https://qiita.com/sueasen/items/91d931ef4a6f053aba26

https://learn.microsoft.com/ja-jp/dotnet/api/system.io.compression.zipfile.createfromdirectory?view=netframework-4.8#system-io-compression-zipfile-createfromdirectory(system-string-system-string-system-io-compression-compressionlevel-system-boolean-system-text-encoding)

https://learn.microsoft.com/ja-jp/dotnet/api/system.io.compression.zipfile.open?view=netframework-4.8#system-io-compression-zipfile-open(system-string-system-io-compression-ziparchivemode-system-text-encoding)

https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.archive/compress-archive?view=powershell-5.1

https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.archive/expand-archive?view=powershell-5.1
【SwiftUI】refreshableのProgressViewをカスタムしたい。。。

# はじめに
refreshableをカスタムするためにはScrollViewのスクロール位置を調べたり、RefreshActionをいじったりと、色々面倒なことが多いです。

手軽に済ませたい場合はUIKitをいじっちゃうのが手っ取り早いです。

# サンプルアプリ
![Simulator Screen Recording - iPhone 15 - 2023-12-31 at 20.08.52.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/a1401cc8-eda6-8257-d732-34c59ffc8e61.gif)

# カスタムローディングの実装
```swift
import SwiftUI

enum CustomProgress: CaseIterable {
    case state1
    case state2
}

extension CustomProgress {
    var rotationEffect: Angle {
        return switch self {
        case .state1: .degrees(0)
        case .state2: .degrees(360)
        }
    }
}

struct CustomProgressView: View {
    var body: some View {
        PhaseAnimator(CustomProgress.allCases) { phase in
            Image(systemName: "cross.fill")
                .resizable()
                .scaledToFit()
                .foregroundStyle(.green)
                .rotationEffect(phase.rotationEffect)
        }
    }
    
    static var uiView: UIView {
        let progressViewSize: CGFloat = 30
        let view = CustomProgressView().frame(width: progressViewSize, height: progressViewSize)
        let viewController = UIHostingController(rootView: view)
        viewController.view.frame = .init(x: (UIScreen.main.bounds.width / 2) - (progressViewSize / 2), y: 10, width: progressViewSize, height: progressViewSize)
        viewController.view.backgroundColor = .clear
        return viewController.view
    }
}
```

# 使用側の実装
```swift
import SwiftUI

struct ContentView: View {
    init() {
        // 元のローディングを透明にする
        UIRefreshControl.appearance().tintColor = .clear
        // カスタムのローディングを設定
        UIRefreshControl.appearance().addSubview(CustomProgressView.uiView)
    }
    
    var body: some View {
        List {
            ForEach(0..<50) { index in
                Text("index: \(index)")
            }
        }
        .refreshable {
            print("更新")
        }
    }
}
```

# おわり
今回紹介した方法ではアプリ全体に影響してしまいます。

カスタムローディングを作成するために`PhaseAnimator`を使用しています。
`PhaseAnimator`については以下の記事を見てください。

https://qiita.com/SNQ-2001/items/26c5b6fb64c095a97344
Cookieについて

- HTTP応答にCookieを入れてウェブブラウザに伝達すれば、以後ウェブブラウザでサーバーに要請する時、該当Cookieを継続的に送ってくれる。
- 永続的な CookieとセッションCookieがあるが、通常ブラウザ終了時にログアウトされることを期待するので、セッションCookieをお勧めする。
    > 永続的な Cookie : 有効期限を入力すると、その日まで保持
    > セッション Cookie : 有効期限を省略するとブラウザ終了時まで保持
    ```java
    @PostMapping("/login")
    public String login(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletResponse response) {
        if (bindingResult.hasErrors()) {
            return "login/loginForm";
        }
    
        Member loginMember = loginService.login(form.getLoginId(), form.getPassword());
    
        if (loginMember == null) {
            bindingResult.reject("loginFail", "IDまたはパスワードが正しくありません。");
            return "login/loginForm";
        }
    
        //ログイン成功処理	
    	Cookie idCookie = new Cookie("memberId", String.valueOf(loginMember.getId()));
    		response.addCookie(idCookie);
    
        return "redirect:/";
    }
    
    public String logout(HttpServletResponse response) {
        Cookie cookie = new Cookie("memberId", null);
        // 当該Cookieを即時終了
        cookie.setMaxAge(0);
        response.addCookie(cookie);
        return "redirect:/";
    }
    ```
- 問題点
    - クライアント側でCookie値を任意変更することができる。
    - 個人情報やクレジットカード情報を入れておけば、ウェブブラウザに保管されるため、パソコンを通じて情報を盗み取ることもでき、ネットワーク要請ごとにクライアントからサーバーに伝達され続けるため、ネットワーク伝送区間から情報を盗み取ることもできる。
サーバーからクライアントに配信するResponseデータを作成する3つの方法

## 1. 静的リソース
- ウェブブラウザに静的なHTML、css、jsを提供するときは静的リソースを使用する。
- **src/main/resources**はリソースを保管する場所であり、class pathの開始経路である。
- Spring Bootは、class pathの次のディレクトリにある静的リソースを提供する。
    - **/static , /public , /resources , /META-INF/resources**
    > 下記の経路にファイルが入っていれば
    > src/main/resources/static/basic/hello-form.html
    > ウェブブラウザで以下のように実行すればよい。
    > http://localhost:8080/basic/hello-form.html


## 2. View Template
- ウェブブラウザに動的なHTMLを提供するときは、ビューテンプレートを使用する。
- **static/main/resources/templates**にビューテンプレートを保管する。
- 一般的にHTML を動的に生成する用途で使用しますが、ビューテンプレートが作れるものなら何でも可能である。
    ```
    html以下の経路にビューテンプレートがあり
    src/maiΩn/resources/templates/response/hello.html
    
    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <p th:text="${data}">empty</p>
    </body>
    </html>
    
    以下のようにコントローラが作られていれば
    @RequestMapping("/response-view")
    public String responseView(Model model){
        model.addAttribute("data", "hello!");
        return "response/hello";
    }
    
    ウェブブラウザで以下のように実行すればよい。
    http://localhost:8080/response-view
    ```

    <details>
    <summary>コントローラーを作成する他の方法もある。</summary>
    <div>
    
    ```java
    @RequestMapping("/response-view")
    public ModelAndView responseView() {
        ModelAndView mav = new ModelAndView("response/hello")
                .addObject("data", "hello!");
    
        return mav;
    }
    ```
    </div>
    </details>

## 3. HTTPメッセージの使用
- HTTP APIを提供する場合にはHTMLではなくデータを伝達しなければならないため、HTTPメッセージボディにJSONと同じ形式でデータを直接入力して送る。

### 3.1.JSONの場合
```java
    @ResponseBody
    @GetMapping("/response-body-string")
    public HelloData responseBodyJson() {
        HelloData helloData = new HelloData();
        helloData.setUsername("userA");
        helloData.setAge(20);
        return helloData;
    }
```

<details>
    <summary>他の方法もある。</summary>
<div>

```java
@GetMapping("/response-body-string-v1")
public ResponseEntity<HelloData> responseBodyJsonV1() {
    HelloData helloData = new HelloData();
    helloData.setUsername("userA");
    helloData.setAge(20);
    return new ResponseEntity<>(helloData, HttpStatus.OK);
}
```
</div>
</details>

### 3.2.単純テキストの場合
```java
@ResponseStatus(HttpStatus.OK)
@ResponseBody
@GetMapping("/response-body-string")
public String responseBody() {
    return "ok";
}

// 動的にResponseStatusを変更したい場合は、その他の方法 > Responsity Entity を参考にして使用すればよい。
```
<details>
    <summary>他の方法もある。</summary>
<div>

```java
@GetMapping("/response-body-string-v1")
public void responseBodyV1(HttpServletResponse response) throws IOException {
    response.getWriter().write("ok");
}

@GetMapping("/response-body-string-v2")
public ResponseEntity<String> responseBodyV2(HttpServletResponse response) throws IOException {
    return new ResponseEntity<>("ok", HttpStatus.OK);
}
```
</div>
</details>
VR空間からGETリクエストを投げる方法 

この記事は以下の動画の内容を文字化したものです。
内容が有益なので文字ベースで理解したい、または動画より文字の方が良い時に利用してください
https://www.youtube.com/watch?v=n2uXFh91-Hs&t=30s

Fluxの取り出し
Inventory
Resonite Essentials
Tools
Proto Flux Tool選択

必要なノード
GET String
Network
|> GET String

DataModelObjectFieldStore<T>
Variables
|> DataModelStore
|> DataModelObjectFieldStore<T>

ObjectWrite<T>
Actions
|> Write
|> ObjectWrite<T>

https://x.com/N1809031125/status/1741396503237976562?s=20

デスクトップでの操作方法については下記が参考になりました。
https://qiita.com/e1ght3/items/6b3e1ba6a764607d9ae7
SwallowのLlamaForCausalLMにおける追加トークンの単語ベクトルはどうすべきか

[昨日の記事](https://qiita.com/KoichiYasuoka/items/3fb5aaac273716d347a5)で、Swallowへの常用漢字51字の追加に使った`resize_token_embeddings`は、追加したトークンの単語ベクトルをランダムにしか決めてくれない。異体字の`input_embeddings`ならば、[同じ値をコピーする](https://srad.jp/~yasuoka/journal/646122/)手もありうるが、言語生成モデルの`output_embeddings`でそれをやってしまうと、異体字同士で衝突が起こる。しかも追加する51字のうち、異体字があるのは[「𠮟」「塡」「剝」「頰」の4字だけだ](https://qiita.com/KoichiYasuoka/items/0717587f80b79d169b08)。何とか3バイトないし4バイトのUTF-8から、追加トークンの単語ベクトルをデッチあげたい。
論文を探してみたところ、Adam Ek, Jean-Philippe Bernardy『[Composing Byte-Pair Encodings for Morphological Sequence Classification](https://aclanthology.org/2020.udw-1.9/)』が同じ悩みにブチ当たっていて、`input_embeddings`にはRNNが最も良くて次がsumらしいが、`output_embeddings`に果たしてRNNが使えるのか、この論文からはイマイチわからなかった。RNNで実装すると前後が面倒そうだし、とりあえずsumでやってみることにした。

```
#! /usr/bin/python3
import urllib.request,json,torch
from transformers import LlamaTokenizerFast,LlamaForCausalLM
with urllib.request.urlopen("https://www.unicode.org/wg2/iso10646/edition6/data/JapaneseCoreKanji.txt") as r:
  joyo=[chr(int(t,16)) for t in r.read().decode().strip().split("\n") if not t.startswith("#")]
tkz=LlamaTokenizerFast.from_pretrained("tokyotech-llm/Swallow-7b-instruct-hf",pad_token="
")
c={i:j[2:] for i,j in zip(joyo,tkz(joyo)["input_ids"]) if len(j)>3}
tkz.save_pretrained("exSwallow-7b-instruct-hf")
d=json.loads(tkz.backend_tokenizer.to_str())
for i,j in enumerate(c,len(tkz)):
  d["model"]["vocab"][j]=i
tkz.backend_tokenizer.from_str(json.dumps(d)).save("exSwallow-7b-instruct-hf/tokenizer.json")
mdl=LlamaForCausalLM.from_pretrained("tokyotech-llm/Swallow-7b-instruct-hf",device_map="auto")
tkz=LlamaTokenizerFast.from_pretrained("exSwallow-7b-instruct-hf",modex_max_length=mdl.config.max_position_embeddings)
e=mdl.resize_token_embeddings(len(tkz))
f=mdl.get_output_embeddings()
with torch.no_grad():
  for k,v in c.items():
    e.weight[d["model"]["vocab"][k],:]=e.weight[v,:].sum(0)
    f.weight[d["model"]["vocab"][k],:]=f.weight[v,:].sum(0)
mdl.set_input_embeddings(e)
mdl.set_output_embeddings(f)
mdl.save_pretrained("exSwallow-7b-instruct-hf")
from transformers import TextGenerationPipeline
tgn=TextGenerationPipeline(model=mdl,tokenizer=tkz,max_new_tokens=128)
nlp=lambda txt:tgn(f"以下に、あるタスクを説明する指示があります。リクエストを適切に完了するための回答を記述してください。\n\n### 指示:{txt}\n\n### 応答:",do_sample=True)[0]["generated_text"]
print(nlp("頬と頰はどちらが子供の名づけに使えますか？"))
```

[Swallow-7b-instruct-hf](https://huggingface.co/tokyotech-llm/Swallow-7b-instruct-hf)に常用漢字51字のトークン追加をおこないつつ、追加学習はおこなわずに様子を見てみることにした。私(安岡孝一)の手元で出力された結果は以下のとおり。

> 以下に、あるタスクを説明する指示があります。リクエストを適切に完了するための回答を記述してください。
>
> \### 指示:頬と頰はどちらが子供の名づけに使えますか？
>
> \### 応答:頬は、男の子の名前としても女の子の名前としても使えます。

うーん、やはり追加学習しないと「頰」が生成されたりしないようだ。さて、どうしようかな。
Specification for CANXL transceiver driver, AUTOSAR 1015, R23-11, CP 

Specification for CANXL transceiver driver
https://www.autosar.org/fileadmin/standards/R23-11/CP/AUTOSAR_CP_SWS_CANXLTransceiverDriver.pdf

R22-11
https://www.autosar.org/fileadmin/standards/R22-11/CP/AUTOSAR_SWS_CANXLTransceiverDriver.pdf

# Release Overviews

3つの分類があります。Foundation, CAN, OSEK/VDXのClassic Platform, Ethernet/TCP/IP, POSIXのAdaptive Platform.

Foundation Release Overview, AUTOSAR 781, R23-11, FO
https://qiita.com/kaizen_nagoya/items/f249bdb8c313d8bff883

Classic Platform Release Overview, AUTOSAR No.0 ,R23-11, CP
https://qiita.com/kaizen_nagoya/items/9d22c8722cbc0f42b137

Adaptive Platform Release Overview, AUTOSAR 782, R23-11, AP
https://qiita.com/kaizen_nagoya/items/13a104606a34fe24fcf7

# Qiita 記事一覧

Autosar Foundation R23-11 一覧
https://qiita.com/kaizen_nagoya/items/c30674cb2dac2fcbbd04

AUTOSAR Adaptive Platform R23-11一覧
https://qiita.com/kaizen_nagoya/items/1dece8799a730367b0dc

Autosar Classic Platform R23-11 一覧
https://qiita.com/kaizen_nagoya/items/f770f6c2906e1dcbf180
# Terms
no


# Reference
[1] Glossary AUTOSAR_FO_TR_Glossary
https://www.autosar.org/fileadmin/standards/R23-11/FO/AUTOSAR_FO_TR_Glossary.pdf
[2] General Specification of Basic Software Modules AUTOSAR_CP_SWS_BSWGeneral
[3] Specification of CAN Transceiver Driver AUTOSAR_CP_SWS_CANTransceiverDriver
[4] Specification for CAN XL Driver AUTOSAR_CP_SWS_CANXLDriver
[5] Specification of CAN Driver AUTOSAR_CP_SWS_CANDriver
[6] Specification of CAN Interface AUTOSAR_CP_SWS_CANInterface
[7] Specification of Ethernet Interface AUTOSAR_CP_SWS_EthernetInterface
[8] CiA 610-1 version 1.0.0 (DSP) - CAN XL specifications and test plans - Part 1: Data link layer and physical coding sub-layer requirements http://www.can-cia.org
[9] CiA 611-1 version 1.0.0 (DSP) - CAN XL higher layer functions - Part 1:Definition of service data unit types
http://www.can-cia.org
[10] General Requirements on Basic Software Modules AUTOSAR_CP_SRS_BSWGeneral
[11] Requirements on CAN AUTOSAR_CP_SRS_CAN
[12] Specification of Ethernet Transceiver Driver AUTOSAR_CP_SWS_EthernetTransceiverDriver


## 補足資料（Additions）


2023 Countdown Calendar 主催・参加一覧
https://qiita.com/kaizen_nagoya/items/c4c2f08ac97f38d08543

CountDownCalendar月間　いいねをいただいた記事群　views　順
https://qiita.com/kaizen_nagoya/items/583c5cbc225dac23398a

＜この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。＞
This article is an individual impression based on the individual's experience. It has nothing to do with the organization or business to which I currently belong.


# 文書履歴(document history)
ver. 0.01 初稿 　20231231
### 最後までおよみいただきありがとうございました。
いいね　💚、フォローをお願いします。
#### Thank you very much for reading to the last sentence.
Please press the like icon 💚　and follow me for your happy life.
pip install pyrealsense2で対応するバージョンがないと言われた時の対処法

pythonでのRealSense開発環境を整えようとpip install pyrealsense2を実行した際に以下のようなエラーが出る場合があります。
```
ERROR: Could not find a version that satisfies the requirement pyrealsense2 (from versions: none)
```
このようなエラーの意味はpythonのバージョンに対応するライブラリが存在せずインストールができないという意味となります。そのためまずは、以下のPythonのバージョン確認コマンドでPythonのバージョンの確認を行ってください。
```
python --version
```
実行するとPythonのバージョンを確認することがで来ます。
次に[pypi](https://pypi.org/project/pyrealsense2/#files)のパッケージ検索でpyrealsense2のライブラリを調べます。Built Distributionsという項目にあるpyrealsense2のライブラリを確認します。名前の真ん中にある、cp311やcp310というが、それぞれPython3.11、Python3.10を指しています。
先ほど確認したpythonのバージョンをcp表記に直して探してみると恐らくライブラリがないはずです。なので最新のライブラリ（画像の場合はcp311、Python3.11）に対応するPythonをインストールしてください。
![スクリーンショット 2023-12-31 184906.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632959/6cdec6b2-f369-fea5-5d28-201b48f98f84.png)
MediaPlayerElementに紐づけたMediaPlayerをDisposeしたい場合、先にSetMediaPlayer(null); を呼ぶ必要がある

タイトルが全てですが、MediaPlayerElementに紐づけたMediaPlayerをDisposeしたい場合、先にSetMediaPlayer(null); を呼ぶ必要があります。

```csharp

MediaPlayer? mediaPlayer;

void InitializeMediaPlayerAndAtatchToMediaPlayerElement()
{
    mediaPlayer = new MediaPlayer();
    MyMediaPlayerElement.SetMediaPlayer(mediaPlayer);
}

[Obsolete]
void DisposeMediaPlayer_Before_DetachFromMediaPlayerElement()
{
    // SetMediaPlayer(null)より先にDisposeを呼ぶと例外が発生し、
    // UnloadやPageのNavigationFrom処理が途中の場合、
    // Xaml描画が崩れる原因にもなりうる。
    // mediaPlayer?.Dispose(); 
}

void DisposeMediaPlayer_After_DetachFromMediaPlayerElement()
{
    // MediaPlayerElementからデタッチした後でDisposeを呼ぶと問題ない。
    MyMediaPlayerElement.SetMediaPlayer(null);
    mediaPlayer?.Dispose();
    mediaPlayer = null;

}

```
第3回　StreamlitとLangChainとLM studioを使って自分専用LLMウェブアプリを作りたい！

# 第3回

# テンプレートの実装
前回、ユーザーからの入力内容について、返答を行うLLMwebアプリを作成した。
参考URL：https://blog.streamlit.io/langchain-tutorial-2-build-a-blog-outline-generator-app-in-25-lines-of-code/
プログラムの変更点はOpenAI APIではなくLocalLLMに繋いでいる点。
今回は”テンプレート”を用いてみたい。
これはテンプレートによって質問内容の大筋を決めてしまえる。

今回は使用したプログラムをいかに示す

```Python:main.py
import streamlit as st
from langchain.llms import OpenAI
from langchain import PromptTemplate

st.set_page_config(page_title="🦜🔗Blog Outline Generator APP")
st.title("🦜🔗Blog Outline Generator APP")


def generate_response(topic):
  llm = OpenAI(base_url="http://localhost:1234/v1", api_key="not-needed")
  # Prompt
  template = '経験豊富なデータサイエンティストとして、またテクニカルライターとして、次のようなブログのアウトラインを作成してください。 {topic}.'
  prompt = PromptTemplate(input_variables=['topic'], template=template)
  prompt_query = prompt.format(topic=topic)
  # Run LLM model and print out response
  response = llm(prompt_query)
  return st.info(response)

with st.form('myform'):
  topic_text = st.text_input('Enter keyword:', '')
  submitted = st.form_submit_button('Submit')
  generate_response(topic_text)
```

# プログラムとテンプレートの役割について

ここではtemplateを設定することで大まかな回答の方向を固定した。ユーザーからの入力はTopicの部分にのみ反映される。
これによって、定型的な部分は毎回ユーザーが入力することなく、実装できる。

![スクリーンショット 2023-12-31 18.29.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631067/0d80e47e-2fe7-d259-b0bd-1978dab146d3.png)


# 次回の予定
このままStreamlitの記事をLocalLLMで実装していきます。
Riverpod Generator TIPs / Stateの再ビルド時に現在のStateを考慮してビルドする

次の `SomeIntValue` は別の `OtherIntValue` の状態に依存しているため、`OtherIntValue` の状態が変わるたびに `SomeIntValue` のStateの再ビルドが行われます。

```dart:some_int_value.dart
@riverpod
class SomeIntValue extends _$SomeIntValue {
  @override
  int build() {
    final otherIntValue = ref.watch(otherIntValueProvider);
    // ビルド処理
    ...
  }
}
```

この再ビルド時に `SomeIntValue` の現在のStateをもとに新しい状態を作りたい場合は [stateOrNull](https://pub.dev/documentation/riverpod/latest/riverpod/Notifier/stateOrNull.html) を使うと良さそうです。`stateOrNull` は初回のビルド時には `null`、再ビルド時は現在の `state` が得られます。

```dart:some_int_value.dart
@riverpod
class SomeIntValue extends _$SomeIntValue {
  @override
  int build() {
    final otherIntValue = ref.watch(otherIntValueProvider);
    return (stateOrNull ?? 0) + otherIntValue;
  }
}
```
プログラミング教室の先生やってみたその１

## はじめに
２０２３年は転職以外に大きな変化がありました。
それは副業として小中高生プログラミングの非常勤講師を始めたことです。
副業といっても週に２コマのみを半年ほどですが
収入以上に学ぶところが大きかったのでまとめておきたいと思います。

## きっかけ
エンジニアは一部の教育向けシステムやゲーム開発以外を除き、
高校生以下のお子さんと関わることは殆どない職業かと思われます。
そのためなんとなく「社会貢献したい」という思いがあり
コロナ前から興味があったのですが、本業とは別に毎週末
教室に通うのはなかなかハードルが高く躊躇していました。

２０２３年になり、オンラインの授業を開講している教室を見つけ
非常勤講師として採用いただけることになりました。

## 教えられることの方が多い
まさにこれにつきます。

私が所属している教室では、「生徒さんが作りたい作品を作る」が基本です。

そのため、先生の一方的な説明を聞いて、
生徒さんがその通りプログラミングするだけ
というスタイルは皆無。

プログラミングを始めたばかりで、
まずは準備されている課題に取り組まれる生徒さんからも
「これを組み合わせたら面白くない？」
「ここ何回も書くの面倒だからまとめられない？」
と、頭の硬い自分では思いもつかないような質問が頻繁に飛び交います。

中にはそのままAppleの審査を通せばアプリ化できるんじゃないかと思うほど
完成度の高いゲームを作成される生徒さんもいらっしゃいます。

質問もなく黙々と作品をモデリング・プログラミングされていることもあり
先生の出番が全くないなんて回も頻繁にあります。

様々なこだわりや強みがある生徒さんがいらっしゃいますが、
みなさまそれぞれ発想力とアレンジ力が素晴らしく
詰め込み大学受験を経験してきた自分には目から鱗でした。

詳細は「**探究型学習**」というキーワードや、下記書籍をご覧ください。
- [ライフロング・キンダーガーテン　創造的思考力を育む４つの原則](https://bookplus.nikkei.com/atcl/catalog/18/P55550/)
![P55550_common_pc.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635225/685666b8-11bf-c359-0784-ed2806090ae0.jpeg)

- [「探究」する学びをつくる 社会とつながるプロジェクト型学習](https://www.heibonsha.co.jp/book/b529249.html)
![529249.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635225/80a16a75-242e-0a60-d5fe-987ed1b21553.jpeg)


## サードプレイス
「家庭」「学校」の他にもう一つの居場所ができることは
お子さんにとって大きな安心感、価値があります。

学校ではなかなか興味の合う友達が見つからなくても、
ゲームの話で盛り上がったり、自分のプログラミング作品で
遊んでもらえたりすることのできる場が、他にあると嬉しい。
この辺りは社会人にとっても同様ですね。

そのため、プログラミングを教える先生というよりも
放課後、児童館にいる（どこの誰だかよくわからないけど
話を聞いてくれる、自分に興味を持ってくれる）お兄さん、お姉さん
という位置付けが理想だと感じています。


## ロジックを説明するのって難しい
例えばfor文。
「そういうもの」としてすっかり慣れてしまっているのですが、
初めて触れる方にとっては
戸惑い以外の何者でもないことに気がつかせていただきました。

下記はスクールの代表の先生に教えていただいた、
わかりやすいフローチャートです。
for文の1行にこれだけのロジックが詰め込まれているのですね。

[while文とfor文のフローチャート](https://www.akita-pu.ac.jp/system/elect/ins/kusakari/japanese/teaching/Old/Programming/2005/note/6/Slide21.html)

![Screenshot at Dec 31 18-10-54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635225/fcf0da37-9a23-e73f-9f8e-c0061b1648e6.png)


長くなってしまったので[その２](https://qiita.com/tutti618/items/a073e0bb1e397099ca69)に続きます。
今年読んだ書籍の読書記録【2023年版】

## はじめに

2023 年に読んだ書籍を備忘録としてまとめました。

## プログラミング

### [【この1冊でよくわかる】 ソフトウェアテストの教科書 [増補改訂 第2版]](https://www.sbcr.jp/product/4815608750/)

SBクリエイティブ（2021年8月3日発売） / [Amazon](https://www.amazon.co.jp/dp/481560875X)
品質を決定づけるテスト工程の全体像と実施方法している本。

### [読みやすいコードのガイドライン -持続可能なソフトウェア開発のために](https://gihyo.jp/book/2022/978-4-297-13036-7)

技術評論社（2022年10月22日発売） / [Amazon](https://www.amazon.co.jp/dp/429713036X)
読みやすさの本質を学び、実践するための考え方を学ぶ本。

## チーム開発

### [ゾンビスクラムサバイバルガイド: 健全なスクラムへの道](https://www.maruzen-publishing.co.jp/item/b304740.html)

丸善出版（2022年10月3日発売） / [Amazon](https://www.amazon.co.jp/dp/4621307398)
スクラムを上手く扱えていないと感じるすべての人のために書かれた、「上手くいっていない」状態から脱却することを主眼にまとめた実用書。

### [熊とワルツを - リスクを愉しむプロジェクト管理](https://bookplus.nikkei.com/atcl/catalog/03/P81860/)

日経BP（2003年12月23日発売） / [Amazon](https://www.amazon.co.jp/dp/4822281868)
プロジェクトにおける「リスク管理」に焦点をあてたプロジェクトマネジメント本。

### [SCRUM BOOT CAMP THE BOOK【増補改訂版】 スクラムチームではじめるアジャイル開発](https://www.shoeisha.co.jp/book/detail/9784798167282)

翔泳社（2020年5月20日発売） / [Amazon](https://www.amazon.co.jp/dp/4798163686)
はじめて「スクラム」をやることになったら読む本。

## サーバー

### [図解即戦力 Amazon Web Servicesのしくみと技術がこれ1冊でしっかりわかる教科書](https://gihyo.jp/book/2019/978-4-297-10889-2)

技術評論社（2019年11月7日発売） / [Amazon](https://www.amazon.co.jp/dp/4297108895)
Amazon Web Services(AWS)のしくみや関連技術についてわかりやすく解説する図解本。

### [AWSで実現するモダンアプリケーション入門 〜サーバーレス、コンテナ、マイクロサービスで何ができるのか](https://gihyo.jp/book/2023/978-4-297-13326-9)

技術評論社（2023年1月21日発売） / [Amazon](https://www.amazon.co.jp/dp/4297133261)
アプリケーションの設計・構築・管理を継続的に見直し、変化に迅速な対応をする開発戦略を解説している本。

## その他

### [紙と鉛筆で身につける データサイエンティストの仮説思考](https://www.shoeisha.co.jp/book/detail/9784798172996)

翔泳社（2022年7月15日発売） / [Amazon](https://www.amazon.co.jp/dp/4798172995)
紙と鉛筆で学ぶというコンセプトのもとデータサイエンティストの思考過程を学ぶ本。

### [40代から手に入れる「最高の生き方」 今すぐ知っておくべき人生を左右する「やっていいこと」「わるいこと」](https://www.kadokawa.co.jp/product/322110001290/)

KADOKAWA（2022年8月1日発売） / [Amazon](https://www.amazon.co.jp/dp/4046056428)
40代を楽しむための本。

### [ユーザーの問題解決とプロダクトの成功を導く　エンジニアのためのドキュメントライティング](https://pub.jmam.co.jp/book/b622627.html)

日本能率協会マネジメントセンター（2023年3月11日発売） / [Amazon](https://www.amazon.co.jp/dp/4800590833)
ドキュメントを作成する方法をゼロから説明するフィールドガイド本。

### [「技術書」の読書術 達人が教える選び方・読み方・情報発信&共有のコツとテクニック](https://www.shoeisha.co.jp/book/detail/9784798171548)

翔泳社（2022年11月4日発売） / [Amazon](https://www.amazon.co.jp/dp/4798171549)
「技術書（コンピュータ書）」の読書術を指南する本。

### [お客様目線のつくりかた: 顧客視点は仕組みで生み出せる](https://www.goku-books.jp/book/b631263.html)

悟空出版（2023年7月31日発売） / [Amazon](https://www.amazon.co.jp/dp/4908117845)
ビジネスの現場で「お客様目線」を持つことの重要性と、その実現方法を体系的に探り、適切に理解し、それを自社の経営やサービスにどう取り入れるかという具体的な手法を解説した本。
AtCoder Daily Training MEDIUM 2023/12/5 15:30start　メモ

# 0.はじめに
　今週は、年末年始にかかるので、ABC非開催ということで
　連続投稿記録が途切れるのが惜しいので、トレーニングでやっている
　ADT(と、呼ばれているのかは定かではありませんが)のメモを残します。
　最初は毎日追いついていたのですが、いまや一か月差があいています。
　正月休みの間に詰められればと思います。


# 1.C - Booby Prize
　ABCのB問題並の難易度。
　リストAが相異なるので、単純に下から2番目の人を表示する。

　リストに、スコアと選手番号のタプルを格納。
　スコアで昇順にソートし、後ろから2番目の選手番号を表示して終了。

　https://atcoder.jp/contests/adt_medium_20231205_1/submissions/48923721


# 2.D - Number Box
　B問題にしては2次元表の探索をしなければならず、なかなかの難易度。
　とはいえ、ちょっと前のADTにも似た問題があったため
　それを参考に組み立て。
　起点座標ｘ、ｙと、ｘの増分ｄｘとｙの増分ｄｙを引数に持つ関数calcを定義
　ｘ、ｙをＮ回推移させていき推移毎に、ＮｘＮの範囲から超えた場合は
　問題文にあるように逆側に移動しつつ順番と逆順の2種類の数値を
　作成し、大きい方を返す。

　あとは、各座標ごとに4方向のcalcを求めその中で最大の数値を表示して終了。
　

　https://atcoder.jp/contests/adt_medium_20231205_1/submissions/48923900

# 3.E - Inverse of Permutation 	
　問題文をよんでも何が何やらさっぱりですが、とりあえず取り掛かり。
　リストAを読み込んでA[i]とi+1をタプルにしたリストBを作成。
　Bをソート。
　これで、リストAの値を昇順に並べその値のリストA内の位置を持ったリストが完成。
　あとはリストBのタプルの後ろ側を1行に表示して終了。

　https://atcoder.jp/contests/adt_medium_20231205_1/submissions/48923955

# 4.F - Manga
　なんとなくの雰囲気で解き始めましたが、大苦戦。
　最後は1問がACとならず、結局過去の自分の解答を参照。

　まず、１～Nまでのフラグリストを作り、与えられたリストAに
　含まれている場合はフラグを立てる。

　そのご、Nをセットした変数nokoriを用意。
　変数iを１～Nまで推移させ、フラグリストが真なら
　nokoriから1を、偽なら、2を引いていく
　nokoriが０になったら、その時点のiを
　-1になったら、その時点のi-1を出力して終了。
 
　https://atcoder.jp/contests/adt_medium_20231205_1/submissions/48947378


# 5.G - Find by Query
　インタラクティブな問題の練習用のような問題。
　昇順に並んでいれば、すむーずではありますが
　まぁ、どこかにある０と1との境目を2分探索のようにして
　求めていく感じで組み立て。

　【考え方】
　　L＝1、R＝Nとし、L+Rを2で割ったMのが０か１かを聞いていく。
　　１であれば、RにMを、0であればLにMをセットして
　　またL+Rを2で割ったMのが０か１かを聞いていく。
　　L+1＝Rとなれば、そこは境目となるので、Lを出力して終了

　https://atcoder.jp/contests/adt_medium_20231205_1/submissions/48953045

以上
「世界一流エンジニアの思考法」読書メモ

# はじめに
今回の記事は最近読んだ本の読書メモです
エンジニア歴2年目が感じた、面白かった内容や勉強になった内容を書いています

# 世界一流エンジニアの思考法
> 頭が先、手は後。一流の仕事のカギは順序にある。
――楠木建(経営学者)
 知的生産へのリスペクトがイノベーションの源泉だ。
――落合陽一(メディアアーティスト)
「怠惰であれ!」「早く失敗せよ」――
米マイクロソフトの現役ソフトウェアエンジニアの著者が、超巨大クラウドの開発の最前線で学んだ思考法とは?
“三流プログラマ”でもできた〈生産性爆上がり〉の技術!
・試行錯誤は「悪」。“基礎の理解”に時間をかける
・より少ない時間で価値を最大化する考え方とは?
・「準備」と「持ち帰り」をやめて、その場で解決する
・マルチタスクは生産性が最低なのでやらない
・“脳の負荷を減らす”コミュニケーションの極意
・コントリビュート文化で「感謝」の好循環を生む……etc.
仕事と人生を「自分の手でコントロールする」最高のスキルがここに!
引用：amazon.co.jp


## 試行錯誤は「悪」である

> 単なる思いつきでいろいろなパターンを試して正解を探しているだけなので、とても時間がかかる上、新しい知識を何も学んでいない。

> 事実（データ）を一つ見つける -> いくつかの仮説を立てる -> その仮説を証明するための行動を取る

プログラミングは「頭脳労働」であるとより理解でき、**できる**プログラマと**できない**プログラマとの差は、このような考え方から生まれているのだと理解。普段の勉強、仕事でも手当たり次第に試すのではなく、データを探して仮説を立てて動くように意識していく。


## 「理解に時間をかける」を実践する

> 「何かを早くできるように急ぐ努力」が返って本質的な理解を遠ざけてしまうのだ。

> 「理解には時間がかかるもの」として、急がず、徹底的に理解する習慣をつける
> 1. 定時後や週末に、プログラミングの基礎を学ぶ
> 2. C# の言語使用を勉強する
> 3. LeetCode を一番簡単なレベルから毎日やる

何事も基礎的な内容を深く理解することが大切で、小手先の技術より大元の原理原則を理解するように勉強していこうと思った。
世界トップレベルのエンジニアでも内容の程度はあれ、理解に時間をかけているため焦らず一歩ずつ進めていく。


## Be Lazy(怠惰であれ)

> 「最初の1個をピックアップしてやったら他はやらない。その一つにフォーカスしよう」という感覚だ。

> 「減らすこと」自体に価値がある

> 成功しまいが、まずややってみて、早くフィードバックを得て、早く間違いを修正していく ----- Fail Fast の精神

> 検討ばかりして、さっさと「やらない」ことの方が最大のリスク

考えすぎて動かないことこそが、リスクであること。さっさと動いた方が早く間違いを発見でき、修正でき結果早く終わること。物事のコアとなる1つのことに集中して他はしない。
選択と集中が大切。何でもかんでもはできないため、することを絞って絞った内容に集中する。


## いかに脳みその負荷を減らすか
> レベル１：何もググらずに即座に実践できるもの
レベル２：問題をどう解決するかはすぐ思いつくが、具体的な方法は忘れているので、ググる必要があるもの
レベル３：自分は解法を知らないが、スパイクソリューション（課題把握のための大まかなプログラム）をしたらできそうなもの
レベル４：自分だけでは解決が難しい、もしくはものすごく時間がかかるもの。
>
>生産性とはいかに「レベル１」を増やすか

> 頭の中のみで整理する

レベル１の即座に実践できる内容を増やしていくように意識する。会議では頭の中で整理できるように練習し、瞬間で最適な決定を出せるような脳みそへ変えていく。
レベル1の内容を増やすことも、当たり前だが時間がかかるため焦りすぎないでする。毎日の積み重ねがすべて。

## クイックコールのすすめ

> 音声のほうが100倍以上の情報量があってインタラクティブ性があり、フィードバックも速い

時間がかかる内容ではない限り、さっさと音声をつないで質問した方が無駄に時間を浪費しない。
自分からクイックコールをかけるようにすると、相手からも気軽にかけても良い雰囲気になるため気に留めすぎずにコールする。


# 最後に
（当たり前だが）すべてを実生活に落とし込むことは無理なので、少しずつ意識して一流エンジニアの思考を取り入れるようにしていきたい。
Datadogによるログの集約

**概要** 
---------------------------------------
Datadogを使用した、AWS上のEC2インスタンス上のログ監視を行う。
その前提として、Datadogによるログの集約(AgentからServerへの転送)が必要となる。
今回、ログ集約方法について説明する。

<br/>

注) Datadogコンソール上でのモニター設定(ログ監視設定)については別途説明する。(ここでは取り扱わない)





**Datadogを使用したログ集約設定**
---------------------------------------

Datadogでログ集約(転送)をするためには、Datadog Agent側でログ送信機能の有効化、並びに転送対象となるログの指定が必要である。

* Datadog Agentのインストール 
監視対象にDatadog Agentをインストールする。
インストール手順についてはここでは割愛する。

<br/>

* ログ送信の有効化

ログ送信の設定はdatadog.yaml(/etc/datadog-agent/datadog.yaml)内にあり、初期値は無効になっている。ここを有効に変更する必要がある。




例
Log collection Configuration内でogs_enabled:trueにする。

```ruby:/etc/datadog-agent/datadog.yaml
~~~~~~~~~省略~~~~~~~~~

##################################
## Log collection Configuration ##
##################################

## @param logs_enabled - boolean - optional - default: false
## Enable Datadog Agent log collection by setting logs_enabled to true.
#
logs_enabled: true

~~~~~~~~~省略~~~~~~~~~
```

※初期値は#logs_enabled:falseとなっているので、コメントアウトを外し、logs_enabled:trueとする。



<br/>

パラメーター変更後はDatadog Agentの再起動が必要。(再起動することで変更したパラメーターが反映される)

<br/>

* 送信対象のログの指定

送信対象となるログについては、構成ディレクトリと構成ファイルを作成し、定義が必要

例: 

```ruby:
sudo mkdir /etc/datadog-agent/conf.d/test_app.d/
sudo vi /etc/datadog-agent/conf.d/test_app.d/conf.yaml
```
この例では、転送対象のログのサービス名を"test_app"としている。



以下のような内容が含まれるように定義します。
例:

```ruby:/etc/datadog-agent/conf.d/test_app.d/conf.yaml
init_config:

instances:

logs:
  - type: file
    path: /work/monitoring_test.log
    source: application
    service: test_app
```

各項目の説明
path: 転送対象のログのファイル名(絶対パス)
source: 任意の名称
service: 任意の名称(ただし、ディレクトリ名と合致している必要がある)



<br/>

パラメーター設定後はDatadog Agentの再起動が必要。(再起動することで変更したパラメーターが反映される)



<br/>

* 転送されたログの確認

前項までの作業で、ログ転送の設定が完了した。
以降、監視対象ログに出力された内容が、Datadogサーバーに転送された、Datadogコンソール上で参照可能となる。

例: Logs → Live Tailでの参照

![Datadog_Live_Tail_2023-12-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3019894/6dd96e6f-85b6-427d-f570-8e0583803a03.png)




**参考にした情報** 
---------------------------------------



[ログの収集とインテグレーション](https://docs.datadoghq.com/ja/logs/log_collection/?tab=host)

[ホスト Agent ログの収集](https://docs.datadoghq.com/ja/agent/logs/?tab=tailfiles)

[Datadogを活用したアプリケーションのログ監視](https://blog.engineer.adways.net/entry/2021/03/19/160000)