OmniAICreator/Qiita-1.07M huggingface dataset:
「Amazon Bedrock 生成AIアプリ開発入門」レビュー #Bedrock開発入門

ありがたい事に著者の @minorun365 さんに献本頂きましたので、
「<a href="https://www.amazon.co.jp/Amazon-Bedrock-%E7%94%9F%E6%88%90AI%E3%82%A2%E3%83%97%E3%83%AA%E9%96%8B%E7%99%BA%E5%85%A5%E9%96%80-AWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89-%E5%BE%A1%E7%94%B0/dp/4815626448">Amazon Bedrock 生成AIアプリ開発入門</a>」の特徴を見ていきたいと思います。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3573242/3b0ce0b4-c495-651c-ffcb-559470b823b1.png" width="30%">

# 想定される読者

どれぐらいの知識があれば内容についていけるのか？という部分ですが、「AWSアカウントを作成する」というところから説明されているので、AWSのレベルでいうとゼロから始めて、最終的には200～300ぐらいの内容まで踏み込んでいきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3573242/4fac84b1-8715-0213-810f-63b62aa43aad.png)

コマンドやプログラムも全て記載されているので、「クラウドもLLMを触ったことが無い」という非技術者の方やレガシー寄りの方でも、本書一冊とブラウザがあれば、チャット・RAG・AIエージェントの各アプリ作成まで到達し、世の中の「LLMを使ったアプリケーション開発」の分野を一気にキャッチアップする事ができそうです。

少なくとも界隈の議論のかなりの部分が理解できるようになると思うので、AWSを使う予定じゃない方でもLLM界隈のキャッチアップ用に使うのも手だと思います。

:::note warn
P.5 にサンプルコードを公開されているGitHubリポジトリのURLが記載されているので、流し読み癖のある人は気を付けましょう（これを見落としてしまうと体験がだいぶ変わる）
:::

# 前提知識や用語の説明が丁寧

生成AI界隈は（に限らずですが）、界隈では当たり前になっている用語が説明なしで登場して、特に初学者にとっては何が何だか分からない状況に陥る事があると思います。
生成AI、LLM、トークン、埋め込み、RAG、エージェント…

本書はこのあたりの説明が丁寧なのと、頻出ワードは一通りカバーしている印象なので、開発者以外の方にとっても基礎知識学習の教材になると思います。ググっても意外とドンピシャの情報って出てこないんですよね。

# 情報の鮮度

以下のような新しいどころをビックリするぐらいカバーしています。
特にこの3～5月はBedrock関連のリリースラッシュだったので、よくここまでカバーされたなとちょっと驚きです。

- LCEL記法
- langchain-aws
- GW頃にリリースされたモデル（Command R+、Titan Text Embeddings v2）、5月下旬にリリースされた Mistral Small
- 5月末にリリースしたConverse API

等等
数か月でも目を離すと情報が古くなっていくこの分野ですが、いまリリースが少し落ち着いているのでタイミングとしてはちょうど良さそうです。

# 情報の幅

実際にLLM or Bedrockに触れている方でも、実際に直面しなければ「聞いたことはあるけど後回し」にしている情報が色々あると思います。

- Claude以外のモデル
- トークン数のカウント
- LangChain以外のフレームワーク（Dify等）
- Pinecorn
- StepFunctionsを使ったノーコード構成
- 最近追加されたBedrockの新機能諸々
- Amazon Q ほげほげ

等等
かなり広めにカバーされており、普段Bedrockで開発されている方でも新しい知識を得る事が出来ると思います。

# まとめ

APIレベル・プログラムレベルで操作する事で理解が深まりますので、LLMを分かっているようで理解が曖昧な方、AWSは使っているけどBedrockは使った事が無い方、には特におすすめです。

以下のページの試し読みで目次が全部見えるので見てみてください。

https://www.sbcr.jp/product/4815626440/
Fedoraとwindowsでデュアルブート中にwifiが使えなくなるエラー

# はじめに
環境
windows10 64bit
fedora39
上記の構成でのデュアルブート
地味で拙いですがfedoraの日本語記事は少ないので投稿していきます。

# 状況
ある日、fedoraを起動した際にwi-fiが使用できなくなりました。
windowsではwi-fi使用できたのでこれはハードのエラーか・・・
と、色々調べてwi-fiアダプターをfedora上で認識しているか確認すると、
しっかりと認識していました。
これはfedoraの再インストールが必要かと、色々調べていたら、
windowsを再起動してからfedoraを起動すれば正常にwi-fiが動作するように
なるとのこと。

神に祈りながらwindowsを再起動すると、無事fedoraで再びwi-fiが使えるようになりました。

# まとめ
windowsとfedoraでデュアルブートをしている人で突如wi-fiが使えなくなった人は、(実際にする人もあまりいないとは思いますが)fedoraを再インストールする前にwindowsの再起動を試してみてください。
初心者から見たVue3コンポーネントの実装のしやすさについて Vision.7

# Vue3コンポーネントの実装のしやすさについて Vision.7
Vue3のコンポーネントの実装について、前回はVue3コンポーネントの詳細から、
ローカル登録について、まとめました。

前回：ローカル登録

https://qiita.com/babel_0101/items/5dde78d187b18a96bcdb

今回は、propsの宣言を以下にまとめます。

なお、Vision2で[propsの受け渡し](https://qiita.com/babel_0101/items/05261108683e9d59dd9d#vue3%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AE%E5%9F%BA%E7%A4%8E2)について触れましたが<br>今回はその深掘りとなっています。

## Vue3のコンポーネントの詳細3
公式ページ：[propsの宣言](https://ja.vuejs.org/guide/components/registration#local-registration)を読み進めながら、以下のように解釈。

1. **`<script setup>`を使用する場合の宣言:** Vision2のおさらいですが<br>単一ファイルコンポーネントで`<script setup>`を使用する場合、defineProps()マクロを<br>使ってpropsを宣言します。

    ```vuejs:anyComponent.vue
    <script setup>
    const props = defineProps(['message'])
    
    console.log(props.message)
    </script>
    ```
    <br>

1. **`<script setup>`を使用しない場合の宣言:** `props`オプションを使って<br>propsを宣言します。
    ```javascript:anyComponent.js
    export default {
      props: ['message'],
      setup(props) {
        // setup() は第1引数にpropsを受け取ります。
        console.log(props.message)
      }
    }
    ```
    defineProps()を使用して宣言する場合でも、単に`props`オプションを使用する場合でも<br>vueの裏側では、同じプロパティにアクセスしていることが分かりました。
    <br>

1. **オブジェクト構文での宣言:**
    propsの宣言には、文字列の配列を使用した宣言に加え、オブジェクト構文も<br>使用できます。<br>`<script setup>`を使用する場合
    ```vuejs:anyComponent2.vue
    <script setup>
    defineProps({
      title: String,
      likes: Number
    })
    </script>
    ```
    `<script setup>`を使用しない場合
    ```javascript:anyComponent2.js
    export default {
      props: {
        title: String,
        likes: Number
      }
    }
    ```
    
    オブジェクト宣言の構文に含める各プロパティについて<br>キーには、propsの名前<br>値には、目的の型のコンストラクター関数<br>を指定します。
    
    これはコンポーネントを文書化するだけでなく<br>誤った型を渡した時に、ブラウザーのコンソールに警告が表示されるようになり<br>コンポーネントを利用する他の開発者のためにもなります。<br><br>公式ページの説明については、オブジェクト宣言の構文を使用することで<br>可読性と保守性を上げる効果があると読み取りました。
    <br>

1. **型アノテーションでの宣言:**
TypeScriptと`<script setup>`の組み合わせを用いる場合、型アノテーションを<br>そのまま使ってpropsを宣言することも可能です:

    ```vuejs:anyComponent3.vue
    <script setup lang="ts">
    defineProps<{
      title?: string
      likes?: number
    }>()
    </script>
    ```
公式ページには、更に以下のページへのリンクが張られていました。<br>記事にするのは、ずっと後になりそうですね。

詳細: コンポーネント props の型付け 

https://ja.vuejs.org/guide/typescript/composition-api.html#typing-component-props

今回はPropの深掘りについて、まだようやく第一歩を踏み出したというレベルですね。
先は長そうですが、難易度はまだ高くないです。

次回：props渡しの詳細

https://qiita.com/babel_0101/items/46e14871f4fcff8c5349
サブネットにて使用できるIP数を求める方法

今回はIPv4のサブネットにて使用できるIPアドレス数を求める方法をご紹介致します。

## 初めに

IPv4アドレスは32ビットの数値で構成されております。

サブネットマスクによってネットワーク部分とホスト部分が区切られます。

下記IPアドレスの例となります。

```
192.168.1.0/24
```
※上記アドレス例となっており、深い意味はありません。

上記の「/24」はネットワーク部分が24ビットという事になります。

全体が32ビットとなっておりますのでホスト部分は8ビットという事になります。

## 計算方法

それでは利用できるPアドレス数を求める計算方法をご紹介します。

例は先ほど同様に以下を使用します。

```
192.168.1.0/24
```

### ホスト部分のビット数を求める

初めにホスト部分のビット数を求める必要があります。

「/24」の場合は以下のようになります。

```
32 - 24 = 8
```

今回のホスト部分のビット数は「8ビット」となります。

### ホスト部分で利用できるIPアドレス数を計算する

次に利用できるIPアドレス数を計算します。

公式は以下となります。

```
2のn乗
```

上記のnの部分に先ほど求めたホスト部分のビット数を代入します。

今回の場合の計算式は以下となります。

```
2の8乗

2✖️2✖️2✖️2✖️2✖️2✖️2✖️2 = 256
```

したがって利用できるIPアドレスはは256個となります。

### 利用できないPアドレスを除く

通常のサブネットでは最初のアドレスと最後のアドレスは利用できないルールとなっております。

その為、先ほど計算した数字から2を引く必要があります。

```
256 - 2 = 254
```

### 結果

以上の計算を元に使用できるIPアドレス数は「254個」となります。
LC_ALL設定のリスクと正しいロケール管理方法

最近 `LC_ALL` に値を設定したことによりハマったのでメモ。

## LC_ALLを設定しないほうがいい理由とLANG設定が効かない問題

システムのロケール設定は、プログラムやシステムの振る舞いに大きな影響を与えます。特に、環境変数`LC_ALL`と`LANG`は、その設定方法によっては期待通りの動作をしないことがあります。

## ロケール設定の基礎知識

UNIX系システムでは、ロケール設定は以下の環境変数を使って行われます。

- `LANG`
- `LANGUAGE`
- `LC_CTYPE`
- `LC_NUMERIC`
- `LC_TIME`
- `LC_COLLATE`
- `LC_MONETARY`
- `LC_MESSAGES`
- `LC_PAPER`
- `LC_NAME`
- `LC_ADDRESS`
- `LC_TELEPHONE`
- `LC_MEASUREMENT`
- `LC_IDENTIFICATION`
- `LC_ALL`

これらの環境変数は、文字のエンコーディング、日時の表示形式、通貨の表示形式など、システムやアプリケーションのロケールに関連するさまざまな設定を制御します。

## ロケール関連の環境変数の優先順位

ロケール関連の環境変数の優先順位は、以下の通りです：

1. **LANGUAGE**: 最も高い優先順位を持ち、主にGNU gettextによって使用されるメッセージ翻訳言語を設定します。
2. **LC_ALL**: 全ての`LC_*`変数を上書きします。値が設定されると、`LC_*` の設定は無視されます。
3. **LC_***: 特定のロケールカテゴリ（`LC_CTYPE`、`LC_NUMERIC`、`LC_TIME`、`LC_COLLATE`、`LC_MONETARY`、`LC_MESSAGES`など）を設定します。
4. **LANG**: これらの変数が設定されていない場合のデフォルト値として使用されます。

https://www.gnu.org/software/gettext/manual/html_node/Locale-Environment-Variables.html

## `LANG`設定が効かない問題

`LANG`は、デフォルトのロケール設定を指定するために使用されます。しかし、`LC_ALL`が設定されている場合、`LANG`の設定は無視されます。これが`LANG`設定が効かない主な理由です。

### 具体例

例えば、以下のように環境変数を設定した場合を考えます。

```sh
export LANG=ja_JP.UTF-8
export LC_ALL=en_US.UTF-8
```

この場合、`LANG`は`ja_JP.UTF-8`に設定されていますが、`LC_ALL`が`en_US.UTF-8`に設定されているため、`LANG`の設定は無視されます。結果として、システムはすべてのロケール設定に`en_US.UTF-8`を使用します。

## `LC_ALL`を使用しないほうがいい理由

1. **デバッグが難しくなる**: `LC_ALL`を設定すると、他のすべてのロケール設定が上書きされるため、特定のロケール設定がどのように機能しているのかを確認するのが難しくなります。
2. **柔軟性の欠如**: アプリケーションやシステムの異なる部分で異なるロケール設定を使用したい場合、`LC_ALL`を設定するとそれが不可能になります。
3. **予期せぬ動作**: `LC_ALL`が他のすべてのロケール設定を上書きするため、予期しない動作を引き起こす可能性があります。

## まとめ

* `LC_ALL`は他のすべてのロケール設定を上書きするため、設定すると柔軟性が失われ、デバッグが難しくなります。
* `LC_ALL`が設定されていると、`LANG`の設定は無視されます。
* ロケール設定を適切に行うためには、`LC_ALL`の使用を避け、必要に応じて個別のロケール設定を行う方法が良さそうです。

私は単に `LC_ALL` は `LC_*` を上書きするだけだと思ったのですが、`LC_ALL` に値を設定してしまうと `LC_*` だけでなく `LANG` よりも優先された値として扱われるということでした。
正しく理解していないとハマるのでご注意ください。
Google検索で使われているccTLD (国別コードドメイン) の一覧。それぞれのページへのリンクも貼ってある。

https://www.eventbrite.com/e/ai-famecatalyst-oto-all-6-otos-links-bonuses-2024-tickets-927634318217
https://www.eventbrite.com/e/ai-famecatalyst-oto-1-to-8-otos-links-hot-bonuses-2024-tickets-927645190737
https://www.linkedin.com/pulse/ai-famecatalyst-oto-1-2-3-4-5-all-five-otos-links-here-jvupsell-ozymc
https://www.eventbrite.com/e/gsite-revolution-review-all-oto-features-info-coupon-tickets-927651660087
https://www.eventbrite.com/e/10k-accelerator-review-full-oto-details-can-help-you-tickets-927740606127
https://www.eventbrite.com/e/10k-accelerator-review-100-honest-insights-oto-upsells-tickets-927741448647
https://www.eventbrite.com/e/everhost-ai-oto-1-to-7-otos-links-epic-25k-bonuses-tickets-927656875687
https://www.eventbrite.com/e/puzzlebooks-ai-review-fe-all-oto-features-coupon-tickets-927028425977
https://www.eventbrite.com/e/puzzlebooks-ai-oto-1-2-3-4-5-all-otos-fe-links-tickets-927028676727
https://www.linkedin.com/pulse/puzzlebooks-ai-oto-1-2-3-4-5-all-five-otos-links-here-getoto-oenrc
https://www.linkedin.com/pulse/puzzlebooks-ai-oto-all-9-otos-links-hot-bonuses-2024-getoto-wt5gc
エンジニアリングマネージャーとの効果的なコミュニケーション

# はじめに
エンジニアリングマネージャーとの良好なコミュニケーションは、重要なスキルの一つです。
技術的な課題や進捗状況をオープンに共有することで、チームの効率性が格段に向上します。この記事では、私がやっているもしくはやりたい実践的なコミュニケーションのコツを紹介しようと思います。

## 進捗報告と目標の共有
私たちのチームでは、進捗報告を社内のコミュニケーションツールを活用して定期的に行っています。
このツールを使うことで、プロジェクトの状況や小さなぼやきまでオープンに共有できるのが良いところです。また、マネージャーとの1on1の中で、定期的に目標やリファクタリングの計画を共有し合っています。

## 解決策の提案
これからできるようになりたいこと
問題を深く理解し、その背景や影響の分析。
データの収集や関連する情報を整理し、根本的な原因を特定すること。
ブレインストーミングやミーティングでチームと協力し、異なる解決策のアイデアを出し合う。自身の考えを積極的に投稿し、他のメンバーのアイデアにも対して建設的なフィードバックする。
コラボレーションで相乗的な価値を提供できると個人プレーからチームプレーに変わっていくと思います。

## 決断
何かと決断を迫られることが増えていきますが、根拠が大切と思います。
リスクを評価し、可能なリスクを事前に予測し、管理する能力。
また、自信を持って意思決定を行うこと。初めは不安ですが信念を感じてついてきてくれるメンバーがいるはず。

## さいごに
全てを完璧にすることは難しいですが、次々を現れる優秀な新人の素敵なロールモデルになれるように、
個人プレーからチームでの価値を、また会社全体の価値を考えられるように一歩づつ前進したいものです。
C_TS422_2021 SAP Certified Application Associate SAP S/4HANA Production Planning and Manufacturing対策（11/100）

【11日目】
トピック2：SAPS/4HANA生産計画の概要（5/5）

≪問題11≫
計画独立所要量による計画の主な利点は何ですか。
（２つ選択）
□生産時間が短縮される。
□生産リソースの需要予測計画を利用できる。
□納入時間が短縮される。
□受注生産を利用できる。

≪解答≫
□生産時間が短縮される。
■生産リソースの需要予測計画を利用できる。
■納入時間が短縮される。
□受注生産を利用できる。

≪解説≫
◆計画独立所要量は、将来の需要予測に基づいて導き出される在庫所要量です。
◆見込生産では、得意先所要量（受注など）を待たずに品目の調達を開始する必要がある場合、計画独立所要量を利用することができます。これにより、納入時間を短縮することができます。また、需要予測計画を活用して生産リソース間で負荷を均等に分散させることが可能です。さらに、得意先所要量がなくても生産をトリガーすることができます。
Rubyでデザインパターン (2) Adapterパターン

## この記事は何
デザインパターンについて、Rubyでどのような使い方ができるかをまとめた記事です。
デザインパターン自体の解説は詳しく行いません。

## Adapterパターンとは
Adapterパターンとは、既存のクラスを変更せずに、新しいインターフェースに適用させるためのデザインパターンです。

詳しくはこちらをご覧ください。

https://qiita.com/shoheiyokoyama/items/bd1c692db480b640c976

## Rubyでのコード例
Rubyにはインターフェースがないため、moduleで代替します。

```rb
module NewInterface
  def new_method
    fail NotImplementedError
  end
end

class OldClass
  def old_method
    'This is OldClass method'
  end
end

class Adapter < OldClass
  include NewInterface

  def new_method
    old_method
  end
end

adapter = Adapter.new
puts adapter.new_method
```

```:出力結果
This is OldClass Method
```

## どのような時に使えるか
Rubyの場合でも、Adapterパターンが欲しくなるのは「既存のクラスに変更を加えずに、必要なインターフェースに則った処理を行いたい時」がメインになると思います。

例えば、以下のようにすでに実装されているいくつかのクラスのインターフェースを統一化し、同じように逐一処理できるようにしたいときなどに役に立ちます。

```rb
# 既存のクライアント
class ApiClient
  def fetch_data
    "API Data"
  end
end

class DatabaseClient
  def retrieve_record
     "Database Record"
  end
end

class FileClient
  def read_file
    "File Content"
  end
end

# 新しいインターフェース
module DataSource
  def get_data
    fail NotImplementedError
  end
end

# Adapterクラスの定義
class ApiClientAdapter < ApiClient
  include DataSource

  def get_data
    fetch_data
  end
end

class DatabaseClientAdapter < DatabaseClient
  include DataSource

  def get_data
    retrieve_record
  end
end

class FileClientAdapter < FileClient
  include DataSource

  def get_data
    read_file
  end
end

sources = [ApiClientAdapter.new, DatabaseClientAdapter.new, FileClientAdapter.new]

sources.each do |source|
  puts source.get_data
end
```
lambdaまたはAPI GatewayのAWSリソース（プライベートサブネット）へのつなぎ方

## はじめに
LambdaとAPI Gatewayの勉強をしていて、パブリックサブネット内にあるLambdaまたはAPI Gatewayからプライベートサブネット内のAWSリソース(RDS等)へのアクセス方法が似ていて、どちらがどちらか迷いそうだったのでまとめます。

## Lambdaのプライベートサブネットへのアクセス方法
作成したLambdaはLambdaサービスが所有するVPC内で実行されます。
デフォルトでは、Lambda 関数はアカウントのVPCに接続されていません。インターネットや、インターネットを経由してパブリックサブネット内のAWSリソースにはアクセスできます。
なので、以下の方法でプライベートサブネット内のリソースに接続します。
- NATゲートウェイの設定をする(VPC-to-VPC NAT)
- Lambdaの実行の際にENI (Elastic Network Interface) が、LambdaのVPC のサブネット構成ごとに割り当てれる
- プライベートサブネット内のリソースにアクセス
上記を実行すると、プライベートサブネット内へのリソースにはアクセスできますが、インターネットへアクセスできなくなります。

https://qiita.com/TaigoKuriyama/items/a1fcbadd10fa7ba41a04#:~:text=2020%2D02%2D04-,ENI%20(Elastic%20Network%20Interface)%20%E3%81%A8%E3%81%AF,Network%20Interface%20Card%EF%BC%89%E3%81%AE%E3%81%93%E3%81%A8%E3%80%82

https://blog-benri-life.com/lambda-vpc-eni/

## API Gatewayのプライベートサブネットへのアクセス方法
Amazon API Gatewayで作成したAPIはVPC外に配置されるため、インターネットからパブリックサブネット内のAWSリソースにはアクセスできます。
ただ、プライベートサブネット内のAWSリソースにはアクセスできません。
なので、以下の方法でプライベートサブネット内のリソースに接続します。
- API GatewayのVPCリンクを作成する
    - ターゲットにNLBを指定する（インスタンスを直接は指定できない）
- 作成完了後、プライベートサブネット内のリソースにアクセス

https://dev.classmethod.jp/articles/vpc-link-api-gateway/

## まとめ
まだまだ、勉強が足りていませんが、わかる範囲でまとめてみました。
もやっとしていた部分が明確になったと思います。
プロデルで Welcome to AtCoder を解いてみた

[Qiita Engineer Festa 2024（キータ・エンジニア・フェスタ 2024） - Qiita](https://qiita.com/official-campaigns/engineer-festa/2024)
において、約1ヶ月で38記事という大量の記事の投稿を要求されることがわかった。
そこで、あまりコストをかけずに記事数を稼ぐ方法を考えた結果、「Welcome to AtCoder を様々な言語で解く」ことを思いついた。
単に解くだけでなく、使用する言語仕様の解説を入れれば、記事として一応成立するだろう。

# Welcome to AtCoder

[PracticeA - Welcome to AtCoder](https://atcoder.jp/contests/abs/tasks/practice_1)

Welcome to AtCoder では、以下の形式で整数 $a$, $b$, $c$ および文字列 $s$ が入力として与えられる。

```text
a
b c
s
```

この入力をもとに、与えられた整数の和 $sum = a + b + c$ および文字列 $s$ を、以下の形式で出力することが求められる。

```text
sum s
```

# 今回用いるプロデルの機能

[プロデルマニュアル](https://produ.irelang.jp/docs/)

## 変数宣言

[プロデルで始める日本語プログラミング言語入門(#2) 「値を記憶する変数」 - プロデルブログ](https://produ.irelang.jp/blog/2020/02/592/)
[変数と代入文 - プロデル言語仕様](https://produ.irelang.jp/docs/syntax/variable.html)

プロデルでは、変数名に漢字・ひらがな・カタカナ・英数字(全角・半角)を使用できる。
変数を最初に使う場所でその変数名を `【】`で囲むことで、**変数を宣言**できる。
`【】` を使わずに変数名を書いても変数を使えることもあるが、「てにはへ」を含む変数名などの宣言しないと使えない変数名があるため、宣言はした方が無難である。

変数宣言で `【変数名:型名】` と書くことで、型を指定して変数を宣言できる。
今回は、「整数」型を用いる。

## 計算と代入

[式 - プロデル言語仕様](https://produ.irelang.jp/docs/syntax/expr.html)
[数値 - プロデル言語仕様](https://produ.irelang.jp/docs/syntax/number.html)
[変数と代入文 - プロデル言語仕様](https://produ.irelang.jp/docs/syntax/variable.html)

`+`、`-`、`()` などを用いた式を書くことで、計算を行うことができる。

```
(変数)は、(値)
```

と書くことで、「変数」に「値」を代入できる。
数値型の変数に文字列型の値を代入すると、自動でその文字列が表す数値に変換される。

## 標準入出力

[コンソール - プロデルマニュアル](https://produ.irelang.jp/docs/core/console.htm)

```
コンソールから受け取って(格納先の変数)とする
```

と書くことで、標準入力から1行読み込み、結果の文字列を指定した変数に代入できる。
代入する文字列に末尾の改行文字は含まれない。

```
(値)をコンソールへ表示して改行する
```

と書くことで、「値」を標準出力に出力し、さらに改行を出力できる。

## 文字列操作

[文字列 - プロデルマニュアル](https://produ.irelang.jp/docs/primitive/string.htm)
[文字列を操作する - プロデル逆引き辞典](https://produ.irelang.jp/docs/lookup/string_lookup.htm)
[文字列関連操作 - プロデルマニュアル](https://produ.irelang.jp/docs/core/global_string.htm)

`「」` で囲むことで、文字列を表現できる。
`「文字列[値]文字列」` のように文字列の中に値 (変数や式など) を `[]` で囲んで書くことで、その値を文字列中に展開できる。

以下の操作において、文字列の最初の文字は1文字目である。(すなわち、1-origin)

```
(探される文字列)から(探す文字列)を探して(変数)とする
```

と書くことで、「探される文字列」の中で最初に「探す文字列」が始まる場所の位置を表す数値を「変数」に格納できる。
JavaScriptでいうと `変数 = 探される文字列.indexOf(探す文字列) + 1;` である。

```
(文字列)の先頭から(量)文字取り出して(変数)とする
```

と書くことで、「文字列」の最初の「量」文字の部分を「変数」に格納できる。
JavaScriptでいうと `変数 = 文字列.substring(0, 量 - 1);` である。

```
(変数)は、(文字列)の(位置)文字目以降
```

と書くことで、「文字列」の「位置」文字目とそれより後の部分を「変数」に格納できる。
JavaScriptでいうと `変数 = 文字列.substring(位置 - 1);` である。

:::note info
この「文字目以降」は、今回紹介した他の操作と違って**名詞手順**というものであり、他の操作とは使い方が異なる。
今回は、代入操作と組み合わせた形で紹介している。
:::

# 提出コード

```
コンソールから受け取って【a:整数】とする
コンソールから受け取って【数値2個】とする
コンソールから受け取って【s】とする

数値2個から「 」を探して【空白位置】とする
数値2個の先頭から(空白位置-1)文字取り出して【b:整数】とする
【c:整数】は、数値2個の(空白位置+1)文字目以降

【和】は、a+b+c
「[和] [s]」をコンソールへ表示して改行する
```

[提出 #54697193 - AtCoder Beginners Selection](https://atcoder.jp/contests/abs/submissions/54697193)
httpのリクエストについて勉強してみた

## 目的
サーバー構築、httpのリクエストに興味があるので、サーバーを立ち上げて簡易的なコードで学習する。
※筆者は情報系の初心者なので悪しからず

## 環境情報
Macbookpro M2チップ
```terminal
% sw_vers
ProductName:		macOS
ProductVersion:		14.4.1
BuildVersion:		23E224
```
apache
```terminal
% httpd -v
Server version: Apache/2.4.58 (Unix)
Server built:   Feb 10 2024 01:12:11
```
## 実装
### 概要
1.pythonのパッケージFlaskを利用する
2.curlを用いてHTTP POSTリクエストを送信する
3.サーバーを立ち上げているターミナルでPOSTリクエストの出力を確認する

### Code
```main.py
from flask import Flask, request

app = Flask(__name__)
@app.route('/')
def index():
    return 'Hello World!'

@app.route('/post', methods=['POST'])
def handle_post():
    data = request.form

    # 受信データをコンソールに出力
    print(f"Received POST data: {data}")
    # レスポンスを返す
    return f"Received POST data: {data}", 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)
```
スマホなどの別端末からアクセスするためにはhostに0.0.0.0を指定して全てのインターフェースをバインドする必要がある。（ただし必要ないなら指定なしで問題ない）


#### 注意点
curlでPOSTリクエストする際はContent-Typeが色々あるので注意
→今回は平文を送ったがrequest.formから受け取ることができた
他にはrequest.get_json()やrequest.dataなどある（今後調べていきます！！）

### 実行
```terminal
python3 main.py
```
以下のような表示になる
```
 * Serving Flask app 'main'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:8080
 * Running on http://XXX.XX.XX.XX:8080
Press CTRL+C to quit
```

curlでlocalhostにアクセスする
```terminal
curl http://localhost:8080
Hello World!%
```
出力を得ることができた

#### POSTリクエストを送る
POSTリクエストを送る際にはcurlに-Xと-dのオプションをつける
[-Xの意味]：curlは通常GETリクエストを送信するため-XでPOSTやPUTなどを指定する必要がある
[-d]:POSTリクエストのボディに含めるものを指定できる

```terminal
curl -X POST http://localhost:8080/post -d "This is a test POST request"
```
出力結果
```terminal
Received POST data: ImmutableMultiDict([('This is a test POST request', '')])%
```
※ImmutableMultiDictとはFlaskにて用いられる特殊なデータ構造で通常の辞書型とは異なりデータの変更ができないImmutaleの辞書型


またサーバー側のターミナルでは
```terminal
Received POST data: ImmutableMultiDict([('This is a test POST request', '')])
```
以上のような出力が確認できることからPOSTリクエストを正しく受信できていると確認できる。

## 感想
リクエストのデータ構造にもっと詳しくなる必要がありそう。またIPアドレスについても知りたい。

## 参考にしたページ
https://jisou-programmer.beproud.jp/%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF/105-127.0.0.1%E3%81%A80.0.0.0%E3%81%AE%E9%81%95%E3%81%84.html
Coqのnatやssrnatでは0で割った答えは0になる

何度目か分からないが、 $\mathbb{X}$ で、小学の算数テストで0で割った答えがどうこうのという話題を見て、思い出したので書いておく。
言うまでもないが、Coqと小学生の算数テストの間には特に関係がない。

# Vanilla Coqでのnatの除算

[`div`の定義](https://coq.inria.fr/doc/V8.18.0/stdlib/Coq.Init.Nat.html#div) を見ると、 0 で割ると 0 になることは定義から分かる。 (`y` が `0` のとき、 `y` を返すのだからそう)

```coq:divの定義
Definition div x y :=
  match y with
    | 0 => y
    | S y' => fst (divmod x y' 0 y')
  end.
```

そうすると、気になるのが、矛盾とかが出てきて困らないの?ということだが、特に矛盾は出てきていないっぽい。

`x / y = z` のとき `x = y * z` になるはずだけど、 `y = 0` だとそれが成り立たない、という話は真っ先に思いつくはずだ。それはその通りである。

```coq:x / y = zならばx = y * zが一般には成り立たないことの証明
Goal ~(forall x y z, (Nat.div x y) = z -> x = y * z).
intro H.
assert (1 = 0 * 0) as C.
  apply H; easy.
discriminate C.
Qed.
```

しかし、Coqの `div` は割り算の余りは無視する定義になっているので、`y = 0` でなくても `x / y = z -> x = y * z` は成り立たない。

```coq:yが0ではない場合にx / y = zならばx = y * zが一般には成り立たないことの証明
Goal ~(forall x y z, y <> 0 /\ (Nat.div x y) = z -> x = y * z).
intro H.
assert (3 = 2 * 1) as C.
  apply H; easy.
discriminate C.
Qed.
```

なお、 `y = 0` 以外での除算に関しては、除算と剰余のペアを返す関数 `divmod` を通じて定義されている。少し変更すれば、ここでの場合分けは不要となるはずである(もちろん、 `divmod` では場合分けは発生する。次に見るMathComp/ssreflectでは現にそのように定義されている)。

# MathComp/ssreflectでのssrnatの除算
ssrnatでは、[除算(`divn`)](https://github.com/math-comp/math-comp/blob/d15522db878ddab2f17669d20159126b6274dd1a/mathcomp/ssreflect/div.v#L59)は、

```coq:divnの定義
Definition edivn_rec d :=
  fix loop m q := if m - d is m'.+1 then loop m' q.+1 else (q, m).

Definition edivn m d := if d > 0 then edivn_rec d.-1 m 0 else (0, m).

Definition divn m d := (edivn m d).1.
```

と定義されている。記法が独特で慣れないが、除算と剰余のペアを返す関数 `edivn` の1つ目の要素を返す形で `divn` が定義されている。

`edivn` の定義より、 `edivn x 0` は `(0, x)` となることが分かるので、 `divn x 0 = 0` となる。
これは [`divn0`](https://github.com/math-comp/math-comp/blob/d15522db878ddab2f17669d20159126b6274dd1a/mathcomp/ssreflect/div.v#L88) という名前のLemmaが示されている。

ssrnatには、これらを利用したLemmaがたくさん示されている。これらは、0除算を避けられているものもあれば、0より大きいことを明示的に条件に入れているものもある。

例えば、除算結果の不等号に関する補題を2つ見る。

## 除算結果の不等号に関する補題 `leq_div2r`

[`leq_div2r`](https://github.com/math-comp/math-comp/blob/d15522db878ddab2f17669d20159126b6274dd1a/mathcomp/ssreflect/div.v#L196-L197) は、 $m \le n$ ならば $m / d \le m / n$ が成り立つ、という補題である。

```coq:leq_div2r
Lemma leq_div2r d m n : m <= n -> m %/ d <= n %/ d.
```

$d = 0$ のとき、今回の定義では、 $m / d$ も $n / d$ も共に `0` になるので、この補題は $d = 0$ においても成り立つ。

## 除算結果の不等号に関する補題 `leq_div2l`

[`leq_div2l`](https://github.com/math-comp/math-comp/blob/d15522db878ddab2f17669d20159126b6274dd1a/mathcomp/ssreflect/div.v#L179) は、 $0 < d$ かつ $d \le e$ ならば、 $m / e \le m / d$ が成り立つという補題である。

```coq:leq_div2l
Lemma leq_div2l m d e : 0 < d -> d <= e -> m %/ e <= m %/ d.
```

これは、 $d = 0$ は条件により明示的に避けられている。もしこの条件がなければ、$d = 0, m / e > 0$ のときに補題が成り立たない(たとえば$m = 1, d = 0, e = 1$のとき)。
特定免許状失効者管理システムにおける犯歴情報の流れ

『特定免許状失効者管理システム業務マニュアル』(文部科学省、令和5年5月19日)の第3章「2. 本システムの使用目的」には

> 本システムは、個人情報の保護に関する法律（平成15年法律第57号。以下「個情法」という。）第18条第3項及び第69条第1項2に基づき、「法令に基づく場合」として、「教育職員等を任命し、又は雇用しようとするとき」（法第7条第1項）を目的とする場合に限り、本人の同意なく個人情報を収集・利用しているものであり、他の法令に基づく場合を除き、これ以外の目的による使用は、個人情報の目的外利用として、個情法違反に問われる恐れがあります。

と書かれている。さて、この「法令に基づく場合」に該当するというのは、本当だろうか。ここでいう「法第7条第1項」は、[教育職員等による児童生徒性暴力等の防止等に関する法律](https://elaws.e-gov.go.jp/document?lawid=503AC0000000057)の

> **第七条**　教育職員等を任命し、又は雇用する者は、基本理念にのっとり、教育職員等を任命し、又は雇用しようとするときは、第十五条第一項のデータベースを活用するものとする。

を指しているはずなので、このシステムまわりにおける「犯歴情報」の流れを、ざっとGraphvizで可視化してみよう。Google Colaboratoryだと、こんな感じ。

```
g="""digraph{
  node[shape=box,fontname=Helvetica]
  市町村教育委員会->都道府県教育委員会[label="犯歴情報\l懲戒免職情報　　\l"]
  教育職員等の任命権者->都道府県教育委員会[label="免許状失効通知　　　\n免許状取上げ通知　　"]
  戸籍の附票ネットワーク[shape=cylinder]
  戸籍の附票ネットワーク->市町村教育委員会[label="附票本人確認情報　　",penwidth=2]
  戸籍の附票ネットワーク->都道府県教育委員会[label="附票本人確認情報",penwidth=2]
  官報[shape=note]
  都道府県教育委員会->官報[label="失効者情報　　",penwidth=2]
  官報->都道府県教育委員会[label="失効者情報　　",penwidth=2]
  特定免許状失効者管理システム[shape=cylinder]
  都道府県教育委員会->特定免許状失効者管理システム[label="失効者情報　　",penwidth=2]
  特定免許状失効者管理システム->教育職員等の任命権者[label="失効者情報　　",penwidth=2]
}
digraph{
  rankdir=LR
  node[shape=record,penwidth=0,margin=0.05]
  x[label="<1>|<2>"]
  y[label="<1>法律に基づく個人情報の提供|<2>省令に基づく個人情報の提供"]
  x:1:e->y:1:w[penwidth=2]
  x:2:e->y:2:w
}"""
import graphviz
graphviz.Source(g)
```

私(安岡孝一)の手元では、以下の図が出力された。

![kyoshokuDB.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428317/7d4f8e2e-2085-8bb0-48ef-c5b031b514fe.png)

うーん、市町村教育委員会がどうやって「犯歴情報」を知るのか、どこにも書かれていない。まあ、小中学校の教育職員が逮捕されれば、当然、地元の噂になるはずだし、それで十分なのかもしれないが、何とも気持ち悪い。また、失効者情報における「氏名・本籍の異動」は、附票本人確認情報から原理的には辿れるが、その際

> 特定免許状失効者等情報は失効・取上げ処分当時のものを入力するが、現在の氏名、本籍が判明している場合、その情報も別データとして入力する

と『特定免許状失効者管理システム業務マニュアル』には書かれていて、なかなかスリリングな運用である。その上、氏名・本籍については

> JIS第三水準等の文字がある場合、JIS第二水準までの文字までに置き換えて入力する
> 　<INS>齊</INS>藤　→　<INS>斉</INS>藤
> 　<INS>髙</INS>橋　→　<INS>高</INS>橋
> 　山<INS>﨑</INS>　→　山<INS>崎</INS>
> 　渡<INS>邊</INS>　→　渡<INS>辺</INS>

とのことで、私個人としては、かなり絶望的な気分になる。こんなやり方で「犯歴情報」をデータベース化するのは、いくら「法令に基づく場合」だと強弁したところで、非常に危険だと思う。
ナビゲーション

```tsx 
// BottomNavigationComponent.js
import React, { useEffect, useState } from 'react';
import { BottomNavigation, BottomNavigationAction } from '@mui/material';
import { useLocation, useNavigate } from 'react-router-dom';
import HomeIcon from '@mui/icons-material/Home';
import SearchIcon from '@mui/icons-material/Search';
import AccountCircleIcon from '@mui/icons-material/AccountCircle';

// Define the type
type PathToIndexType = {
  path: string;
  name: string;
};

// Create the array and ensure it's typed correctly
const pathToIndex: PathToIndexType[] = [
  { path: '/', name: 'Home' },
  { path: '/search', name: 'Search' },
  { path: '/profile', name: 'Profile' },
];

const BottomNavigationComponent = () => {
  const location = useLocation();
  const navigate = useNavigate();
  const [value, setValue] = useState<number>(0);

  useEffect(() => {
    // 現在のURLパスを取得
    const currentPath = location.pathname;
    // パスに対応するインデックスを取得
    const index = pathToIndex.findIndex((item) => item.path === currentPath);
    // インデックスが見つかれば、valueを更新
    if (index !== -1) {
      setValue(index);
    }
  }, [location.pathname]); // location.pathnameが変わる度に実行される

  const handleChange = (event: React.SyntheticEvent, newValue: number) => {
    setValue(newValue);
    const selectedPath = pathToIndex[newValue]?.path;
    if (selectedPath) {
      navigate(selectedPath);
    }
  };

  return (
    <BottomNavigation value={value} onChange={handleChange}>
      {pathToIndex.map((item, index) => (
        <BottomNavigationAction
          key={item.path}
          label={item.name}
          icon={
            index === 0 ? (
              <HomeIcon />
            ) : index === 1 ? (
              <SearchIcon />
            ) : (
              <AccountCircleIcon />
            )
          }
          sx={{ color: value === index ? 'primary.main' : 'inherit' }}
        />
      ))}
    </BottomNavigation>
  );
};

export default BottomNavigationComponent;

```
ActiveHash

# ActiveHashとは
カテゴリー名などの、変更される予定の無いデータをモデルファイルに記入することで、データベースに保存することなくActiveRecordのようなメソッドを使用することができるようにするGemのことです。

# なぜActiveHashを使用するのか
ActiveHashを使用する理由は、データベースへのクエリと比較すると負荷が小さく、アプリケーションのパフォーマンスへの影響が少ないと考えられるからです。  

ActiveHashを使用した場合データはメモリ上に保存され、データベースに保存するよりも、高速でデータの取得を行うことができます。

# インストール方法
Gemfileの最下部に以下の内容を追加します。
``` :Gemfile
gem 'active_hash'
```
ターミナルで実行します。
```
bundle install
```

# 使用方法
ActiveHashを使用するために、まずはモデルを作成します。（今回はCategoryモデル）
```
rails g model category
```
ActiveHash::Baseを継承します。
``` :app/models/category.rb
class Category < ActiveHash::Base
```
ActiveHash::Baseは、あるモデル内でActiveHashを使用する際に必要なクラスです。

ActiveHash::Baseを継承することで、ActiveRecordと同様なメソッドを使用することができるようになったので、データの内容を入力します。

``` :app/models/category.rb
class Category < ActiveHash::Base
  self.data = [
    { id: 1, name: 'トップス' },
    { id: 2, name: 'ボトムス' },
    { id: 3, name: 'アウター' },
  ]
  end
```

これで、データベースに保存することなく、データを取り出すことができるようになります。
ZIOのScopeについて

# 概要

Scope型は、ZIOの安全で合成可能なリソース処理基盤です。
これは一つまたは複数のリソースのライフタイムを表します。リソースはスコープ内で使用され、スコープが閉じられるときに解放されます。

# 最初の例

`Scope#make`を呼び出すと`UIO[Scope.Closeable]`型の値を手に入れることができます。
`Closeable`は`Scope`を継承したトレイトです。

`Scope`は`addFinalizer`を呼び出すことにより、
ファイナライズ処理を追加することができます。

```scala
object Main extends ZIOAppDefault:
  override def run: ZIO[ZIOAppArgs & Scope, Any, Any] = 
    for {
      scope: Scope.Closeable <- Scope.make
      _: Unit <- scope.addFinalizer(
        for {
          _ <- ZIO.debug("ファイナライズ処理")
        } yield ()
      )
      _: Unit <- ZIO.debug("開始")
      _: Unit <- scope.close(Exit.succeed(()))
      _: Unit <- ZIO.debug("終了")
  } yield ()
```

```txt:実行結果
開始
ファイナライズ処理
終了
```

# ZIO#acquireRelease

`ZIO#acquireRelease`を使うことによって、
リソースの取得と解放を1つのZIOエフェクトにまとめられ、リソース解放漏れのリスクを軽減できます。

```scala:acquireReleaseの使用例
object Main extends ZIOAppDefault:
  def acquire(name: => String): ZIO[Any, IOException, Source] =
    ZIO.attemptBlockingIO(Source.fromFile(name))

  def release(source: => Source): ZIO[Any, Nothing, Unit] =
    ZIO.succeedBlocking(source.close())

  def source(name: => String): ZIO[Scope, IOException, Source] =
    ZIO.acquireRelease(acquire(name))(release(_))

  override def run: ZIO[ZIOAppArgs & Scope, Any, Any] =
    for {
      s: Source <- source("/Users/tobita/.gitignore_global")
      lines: Iterator[String] <- ZIO.attemptBlockingIO(s.getLines())
      _ <- Console.print(lines.mkString("\n"))
    } yield ()
```

```txt:実行結果
.DS_Store
.idea
```

# ZIO#scoped

`ZIO#scoped`は、渡されたZIOエフェクトを新しいスコープ内で実行し、そのスコープを自動的に閉じる関数です。

```scala
object Main extends ZIOAppDefault:
  def inScope: URIO[Scope, Unit] = for {
    _ <- ZIO.addFinalizer(ZIO.debug("ファイナライズ処理"))
    _ <- ZIO.debug("スコープ内の処理")
  } yield ()

  override def run: ZIO[ZIOAppArgs & Scope, Any, Any] =
    for {
      _ <- ZIO.debug("開始")
      _ <- ZIO.scoped(inScope)
      _ <- ZIO.debug("終了")
    } yield ()
```

```txt:実行結果
開始
スコープ内の処理
ファイナライズ処理
終了
```
Elastic Searchでcurlで時間を範囲指定してデータを取得する

# TL;DR

Range queryで範囲指定することが可能です。

https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html

```txt:過去1日のデータを取得するクエリ
GET /test-index/_search
{
    "query": {
        "bool": {
          "must": [
            {
              "match_all": {}
            }
          ], 
          "filter": [
            {
              "range" : {
                "time" : {
                  "gt": "now-1d"
                }
              }
            }
          ]
        }
    }
}
```

# 前準備

Elastic Searchのサーバーを立てます。
以下の記事では、DockerでElastic Searchのサーバーを立てていますので、
ご参考までに。

https://qiita.com/tobita_yoshiki/items/9de9cfc4beed26b792c1

# テストデータの投入

まず、データの投入先となるインデックスを作成します。

```shell
curl --cacert http_ca.crt -u elastic:$ELASTIC_PASSWORD -X PUT "https://localhost:9200/test-index?pretty"
```

次にテストデータを投入します。

```json:投入対象のデータ
{"id": "1", "time": "2024-06-14T01:00:00+09:00"}
{"id": "2", "time": "2024-06-15T01:00:00+09:00"}
{"id": "3", "time": "2024-06-16T01:00:00+09:00"}
{"id": "4", "time": "2024-06-17T01:00:00+09:00"}
{"id": "5", "time": "2024-06-18T01:00:00+09:00"}
```

```shell:curlでデータ投入
curl --cacert http_ca.crt -u elastic:$ELASTIC_PASSWORD -X POST "https://localhost:9200/test-index/_doc" -H 'Content-Type: application/json' -d '{"id": "1", "time": "2024-06-14T01:00:00+09:00"}'
curl --cacert http_ca.crt -u elastic:$ELASTIC_PASSWORD -X POST "https://localhost:9200/test-index/_doc" -H 'Content-Type: application/json' -d '{"id": "2", "time": "2024-06-15T01:00:00+09:00"}'
curl --cacert http_ca.crt -u elastic:$ELASTIC_PASSWORD -X POST "https://localhost:9200/test-index/_doc" -H 'Content-Type: application/json' -d '{"id": "3", "time": "2024-06-16T01:00:00+09:00"}'
curl --cacert http_ca.crt -u elastic:$ELASTIC_PASSWORD -X POST "https://localhost:9200/test-index/_doc" -H 'Content-Type: application/json' -d '{"id": "4", "time": "2024-06-17T01:00:00+09:00"}'
curl --cacert http_ca.crt -u elastic:$ELASTIC_PASSWORD -X POST "https://localhost:9200/test-index/_doc" -H 'Content-Type: application/json' -d '{"id": "5", "time": "2024-06-18T01:00:00+09:00"}'
```

# 時間を範囲指定してデータ取得

以下は[Search API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html)を使って、時間を範囲指定してデータを取得した結果です。

```
$ date
2024年 6月18日 火曜日 17時07分03秒 JST

$ curl --cacert http_ca.crt -u elastic:$ELASTIC_PASSWORD -X GET "https://localhost:9200/test-index/_search" -H 'Content-Type: application/json' -d '{
    "query": {
        "bool": {
          "must": [
            {
              "match_all": {}
            }
          ],
          "filter": [
            {
              "range" : {
                "time" : {
                  "gt": "now-1d"
                }
              }
            }
          ]
        }
    }
}'
{"took":16,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":1,"relation":"eq"},"max_score":1.0,"hits":[{"_index":"test-index","_id":"r8lbKpABH2JNu7nWNfEY","_score":1.0,"_source":{"id": "5", "time": "2024-06-18T01:00:00+09:00"}}]}}
```

`"id": 5`のデータが取得できています。
GitHub Actions学んでみた②

# はじめに
初めまして！
エンジニアになって数年、今まで本を読むだけでしたが、もっとプライベートで楽しみながら成長したい！自分が学んだ足跡を残していきたい！と思い記事を書きました！
最終的には自在に開発できるようになりたいと思っています。:triumph:
いろいろな記事を参考にさせてもらっています。:bow_tone2:

**「いいね」か「ブックマーク」**
を頂けると僕のモチベーションアップになります！:thumbsup:
少しでも気に入っていただけたらよろしくお願いいたします！:thumbsup:


# 今回の目的
自分の作ったコンポーネントを確認したり検証するための技術を身に付けたい！
公式のクイックスタートを参考に進めていきます。
項目ごとに補足のみ書いて進めています。わかりづらいところの理解の手助けになれば幸いです！

# 主に参考にさせていただいた記事

https://docs.github.com/ja/actions/quickstart

# アクションの検索とカスタマイズ
ワークフローで使用するアクションが定義できるところは下記の三つ
・ワークフロー ファイルと同じリポジトリ
・すべてのパブリック リポジトリ
・Docker Hubで公開された Docker コンテナイメージ
Marketplaceにはワークフローで使用できるアクションが公開されている
（例）Checkout
https://github.com/marketplace/actions/checkout


# ワークフローエディタで Marketplace アクションを参照する
実際に編集画面に行き「Checkout」を検索すると下記の画像のように検索結果の詳細で表示ができる。
![スクリーンショット 2024-06-18 20.33.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/943982/71decf56-442d-7805-9153-8a6202c162ee.png)

# ワークフローにアクションを追加する
## GitHub Marketplace からのアクションの追加
Upload a Build Artifactを追加してみます。
```yml
      - name: Upload a Build Artifact
        uses: actions/upload-artifact@v4.3.3
        with:
              name: github-actions-demo.yml
              path: .github/workflows/*
```

コミットして動作確認しましょう。
![スクリーンショット 2024-06-18 21.09.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/943982/25cc2131-f741-0156-6bec-52193f64d2a3.png)

## 同じリポジトリからのアクションの追加
actionフォルダを作成して引っ張ってくる方法です。
下記の内容をaction.ymlに書きます
```yml
runs:
  using: 'composite'
  steps:
    - name: Upload a Build Artifact
      uses: actions/upload-artifact@v4.3.3
      with:
        name: github-actions-demo.yml
        path: .github/workflows/*
```
呼び出し側
```yml
  - name: Use local hello-world-action
    uses: ./.github/actions/hello-world-action
```


# 次
https://qiita.com/mr_noppo/items/da814ef0cdfbe18a585e
Qiitaをはじめました

考えるだけで何も始まらないと私はずっと思っていました。
今までYunNoteやOneNoteに自分の経験と知識を記録しましたが、何度もQiitaの記事に救われ、後は少し私利私欲なことも含め、本日アカウントを作成しました。
アカウント登録はそんなに複雑ではありませんが、正直、他のサイトの画面と比べたら少しショボく感じました。ユーザー名にアルファベットのみって最初に入力の時に教えてくれればよかったのに。
雑談はここまでで、本日からはよろしくお願いいたします。自分もここで成長できますようにー
【GAS】Qiitaのストック記事をスプレッドシートで管理

今回はGAS入門記事です。
Qiita APIを用いて自分のストックした記事を Google Spread Sheet に書き出す方法を紹介します。

Spread Sheet でデータを管理するような方がどの程度いるかわかりませんが、「GAS始めて触るよ」という方のきっかけになればいいかなと思います。

## QiitaAPIの準備
Qiitaにログインして、アプリケーション設定から「**個人用アクセストークン**」を発行します。

![スクリーンショット 2024-06-18 21.26.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334980/af673090-364a-a62b-f8bb-456d4f8c9ab6.png)

## GoogleSpreadSheetの作成
新規でSpread Sheetを作成してください。

## AppScriptの設定
拡張機能の Apps Script を押下します。（初回は少し時間がかかるかも）

![スクリーンショット 2024-06-18 21.29.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334980/bb686220-3321-b370-f2c9-2738bad89532.png)

`コード.gs`内に以下の記述を行います。

![スクリーンショット 2024-06-18 21.31.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334980/039caf8c-b9f0-9581-1ea7-68b1a64ebd0d.png)

```js
function fetchQiitaStocks() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const token = '--TOKEN--'; // 設定したアクセストークン
  const userId = '--USERID--'; // Qiitaのユーザー名
  const url = `https://qiita.com/api/v2/users/${userId}/stocks?page=1&per_page=100`;
  const options = {
    'method': 'get',
    'headers': {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    }
  };

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

  // スプレッドシートにデータを転記
  json.forEach((item, index) => {
    sheet.appendRow([
      item.title,
      item.url,
      item.user.id,
      '未読'
    ]);
  });
}
```

``token``と``userId``に自身のアクセストークンとユーザーIDを指定してください。

Qiitaで公開されているAPIにFetchを行い、取得したデータをSpreadSheetに入力(転記)するようなプログラムです。
細かい解説は省きます。

## 実行して確認
「実行」ボタンを押して、スクリプトを実行します。

![スクリーンショット 2024-06-18 21.40.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334980/556b1eec-9aaa-47da-b12a-2f7fc16a1463.png)

「実行ログ」が画面下部にでてきたら成功です。

SpreadSheetを確認してみましょう。

## 動作確認
いい感じですね。

![スクリーンショット 2024-06-18 21.41.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334980/8080219d-c24b-e1d1-63fc-8c9a940fc55e.png)

僕は結構ストックよりいいね派です。

## 参考

https://qiita.com/api/v2/docs
SQLite3で日付時刻文字列からミリ秒付きのUnixTimeを作る

# 準備
以下の要領で確認用のデータを作る

```shell_session
$ sqlite3 temp.db "CREATE TABLE 'Example'(Time TEXT)"
$ sqlite3 temp.db "INSERT INTO Example VALUES ('2024-06-18T21:19:30.833627900+09:00')"
$ sqlite3 --table temp.db "SELECT Time FROM Example"
+-------------------------------------+
|                Time                 |
+-------------------------------------+
| 2024-06-18T21:19:30.833627900+09:00 |
+-------------------------------------+
```

# `%f`を使う方法
AIに聞いて答えてくれた方法

```shell_session
$ sqlite3 --table temp.db "SELECT strftime('%s', Time) || substr(strftime('%f', Time), 3) FROM Example"
+---------------------------------------------------------+
| strftime('%s', Time) || substr(strftime('%f', Time), 3) |
+---------------------------------------------------------+
| 1718713170.834                                          |
+---------------------------------------------------------+
```

# subsec修飾子を使う方法
もう少しきれいな方法はないかなー、と思いながらSQLiteの[ソースコード](https://github.com/sqlite/sqlite/blob/bebe2d8be8acfd02592c4972f4ba32c3b4e4a33f/src/date.c#L1497-L1506)を眺めて見つけた方法
`subsecond`でも可

```shell_session
$ sqlite3 --table temp.db "SELECT strftime('%s', Time, 'subsec') FROM Example"
+--------------------------------+
| strftime('%s', Time, 'subsec') |
+--------------------------------+
| 1718713170.834                 |
+--------------------------------+
```

# メモ
いずれの方法でも小数点以下3桁より小さい値は表示できないようなので[^1][^2]、1ミリ秒より小さい時間を扱うには元の文字列のまま取り出して別の方法で処理する必要がありそう。
ただし「[The current implemention increases the resolution from seconds to milliseconds, but this might increase to a higher resolution in future releases of SQLite](https://www.sqlite.org/lang_datefunc.html#subsec)」とあるので、将来的には変わるかもしれない。

[^1]:https://github.com/sqlite/sqlite/blob/bebe2d8be8acfd02592c4972f4ba32c3b4e4a33f/src/date.c#L1430-L1435
[^2]:https://github.com/sqlite/sqlite/blob/bebe2d8be8acfd02592c4972f4ba32c3b4e4a33f/src/date.c#L1499-L1500
【Java】ABC081B_ Shift Only #AtCoder

自分用にAtCoderの解答をまとめていきます。誤った情報があったら、申し訳ございません。

## 覚えること

- setメソッド
Listクラスのsetメソッドは、1つ目の引数は書き換えたいList内の位置を指定し、2つ目の引数は実際の変更の仕方を指定できる。


## コード
```java:ABC049C_Daydream
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class ABC081B_ShiftOnly {
    public static void main(String[] args) {
        try (Scanner sc = new Scanner(System.in)) {
            int s = sc.nextInt();
            int count = 0;
            boolean judge = true;
            List<Integer> arrayList = new ArrayList<>();

            for (int i = 0; i < s; i++) {
                int t = sc.nextInt();
                arrayList.add(t);
            }

            while (judge) {
                for (int i = 0; i < arrayList.size(); i++) {
                    int t = arrayList.get(i);
                    if (t % 2 != 0) {
                        judge = false;
                        break;
                    }
                    arrayList.set(i, t / 2);
                }
                if (judge) {
                    count++;
                }
            }

            System.out.println(count);
        }
    }
}


```

## 感想&振り返り
わざわざArrayList使う必要ない気がします。要素数が先に決まっているなら、配列でいいんじゃないかなって今では思います。調べてみると、微妙に配列の方が処理速度は速いみたいですし、今後は配列で記述しようかなって思います。（このレベルだと多分変わらない気がしますが、）



## 参考にしたサイト
https://qiita.com/drken/items/fd4e5e3630d0f5859067

https://docs.oracle.com/javase/jp/17/docs/api/java.base/java/util/List.html

https://took.jp/post-992/#google_vignette

https://yujisoftware.hatenablog.com/entry/20090928/1254154372
ディープリンク・ユニバーサルリンク・アプリリンクの話

# はじめに

あるURLにアクセスした時、スマホに指定のアプリがインストールされていればそれを起動し、未インストールでさればストアを表示したい。

ユニバーサルリンクでアプリ未インストールだとストア表示してくれる、みたいなことをいくつか見かけたので調べた。

# ディープリンク、ユニバーサルリンク、アプリリンク

いずれもURLっぽいもので、対応したアプリがインストールされていると、そのアプリが起動する。

ディープリンクの中に、
・カスタムURLスキーム
・ユニバーサルリンク
・アプリリンク
がある。

- カスタムURLスキーム

URLの先頭部分（httpやftpのところ）をアプリ独自に定義したもの。
例：Googleマップ comgooglemaps:

- ユニバーサルリンク と アプリリンク

iOSとAndroidでの呼び名が違うだけで同じもの。
URLと同じ形式なので、対応するアプリがインストールされていないと普通にWebページが表示される。

ただし、これらだけではストアの表示は行わない。

しかし、ユニバーサルリンクとアプリリンクは、表記がWebページと同じURLのため、対応するアプリが入っていない場合にWebサイトを表示する。（通常のWeb表示が行われる）

このときWebページ側でストアに遷移するような細工を行うことで「未インストール時はストア表示」を実現できる。
同一のURLでAndroid/iOSそれぞれのストアを表示出来るのも、Webページ側の細工によるもの。

- その細工とは

単に UserAgent による振り分けと、OSに応じたリダイレクトをするだけ。

# 一連の流れ

Webページやメールに記載した ユニバーサルリンク（アプリリンク） をタップする。（A,B,Cに分岐）

(A)
対象のアプリがインストールされている場合、該当のアプリが起動する

(B)
対象のアプリがインストールされていない場合、ブラウザがWebページにアクセスする
↓
サーバ側でUserAgentによりiOS用/Android用　それぞれのアプリストアのURLへリダイレクトする
↓
ストアアプリのユニバーサルリンク（アプリリンク）が反応し、該当アプリのストアページが表示される

(C)
PCによるアクセスの場合、普通にWebページを表示する

※ただし、一部のアプリ内ブラウザではユニバーサルリンク（アプリリンク）が機能せず、Webページが表示されることがある

# カスタムURLスキームでストア表示を行うには

呼び出し側のアプリで、カスタムURLスキームに反応したらそのままアプリが起動。
何も起きなかったら別途用意したURLに遷移させる、という動きを作る。


# .htaccessでUserAgentによる振り分け

.htaccess
```
# iPhone
RewriteCond %{HTTP_USER_AGENT} iPhone
RewriteRule ^$ /ios.html [R]

# iPad
RewriteCond %{HTTP_USER_AGENT} iPad
RewriteRule ^$ /ios.html [R]

# Android
RewriteCond %{HTTP_USER_AGENT} Android
RewriteRule ^$ /android.html [R]

```

ios用
```
<meta http-equiv="refresh" content="0;url='https://apps.apple.com/jp/app/id??????????'" />
```

android用
```
<meta http-equiv="refresh" content="0;url='https://play.google.com/store/apps/details?id=xxx.xxxx.xxxx.xxxxxx'" />
```

以上
[Android] targetSdkVersion 34でGoogle Play Core Libraryの利用方法

# 背景
アプリ申請時にGoogle Play Consoleから下記の警告メールがきた

>com.google.android.play:core: 1.8.0
>Google Play Core (com.google.android.play:core) は、SDK バージョン 1.8.0 に関して次の注記を追加しました:
>
>Play Core Maven 依存関係を Android 14 互換バージョンに更新してください。現在の Play Core ライブラリは targetSdkVersion 34 (Android 14) と互換性がありません。このバージョンでは、ユーザーのセキュリティを強化するために、ブロードキャスト レシーバーに下位互換性のない変更が導入されています。8 月 31 日より、Google Play ではすべての新しいアプリ リリースで Android 14 をターゲットにすることが義務付けられます。アプリのクラッシュを回避するには、Play Core ライブラリの依存関係を最新バージョンに更新してください: https://developer.android.com/guide/playcore#playcore-migration
>
>2024 年 9 月 17 日 00:00 (UTC) 以降、この SDK バージョンを含むアプリの新しいバージョンを製品版またはオープンテストにリリースできなくなります。

アプリのレビュー依頼を実装するために
`com.google.android.play:core: 1.8.0`
を使用していたがtargetSdkVersion 34とは互換性がないとの警告であった。

# 修正方法
下記の公式URLの内容通りです。
>Play Core Java and Kotlin Library は、機能別に複数の Android ライブラリに分割されました。これにより、Play Core ライブラリがアプリに追加するサイズが減り、個々の機能のリリース サイクルを短縮できます。

https://developer.android.com/guide/playcore?hl=ja#playcore-migration

機能ごとに分割されたとのことで、それぞれ必要な機能を追加する。
今回はレビュー機能だけを使っていたので以下の通り。

```
dependencies {
    // 互換性なし警告が出るので削除
//    implementation("com.google.android.play:core-ktx:1.8.1")

    // This dependency is downloaded from the Google’s Maven repository.
    // Make sure you also include that repository in your project's build.gradle file.
    implementation("com.google.android.play:review:2.0.1")

    // For Kotlin users, also import the Kotlin extensions library for Play In-App Review:
    implementation("com.google.android.play:review-ktx:2.0.1")
    ...
}
```

その他についても`com.google.android.play:core-ktx`は削除して
使っているライブラリごとに追加すれば良いだけかと思います。

以上です。
Python: Quart での Debug 設定の調査記録

# 背景

サンプルアプリで、Flask から Quart になった
で、Debug mode って文字が見えたので、有効化しようとした記録

```text: こんな感じのやつ
 * Serving Quart app 'app'
 * Debug mode: False
 * Please use an ASGI server (e.g. Hypercorn) directly in production
 * Running on http://localhost:50505 (CTRL + C to quit)
```

<code>app.run(debug=true)</code> が一番楽そう
だったんだけど今回はこれは出来なかった為の調査

# 結論

- 提起のやつなら、環境変数で以下を設定すれば OK
   ```powershell: QUART_DEBUG 
   $Env:QUART_DEBUG = "True"
   ```

- Class を用意して、Config に読み込む場合は以下な感じ

   ```python: config pattern
   class Config:
       DEBUG = False
       TESTING = False
       SECRET_KEY = 'secret'

   class Development(Config):
       DEBUG = True

   class Production(Config):
       SECRET_KEY = 'an actually secret key'

   def create_app(mode='Development'):
       """In production create as app = create_app('Production')"""
       app = Quart(__name__)
       app.config.from_object(f"config.{mode}")
       return app
   ```

詳細は以下で

https://quart.palletsprojects.com/en/latest/how_to_guides/configuration.html#configuration

# 奮闘記録

## Document 眺めて、お？これちゃうんと思った instance_relative_config

app = Quart(__name__, instance_relative_config=True)

instance フォルダーにおいて、なんか色々やれるのかと思ったら、 違った

これは、Git管理したくないSecretとかを、Quart管理外から読み込むオプションみたい 

https://quart.palletsprojects.com/en/latest/how_to_guides/configuration.html#instance-folders

## normal/debug 用の app を二重に用意して切り替えよう

いや、そこまでしたら無意味じゃん・・と突っ込みするレベル :p
config 設定パターンをみて、"Production", "Development" を切り替えようとして陥った話

下記のようにして・・と一瞬考えてしまった :laughing: 

```python: main.py
app = create_app()
app_local = create_app(mode="Development")
```

## powershell の実行時に、run() に引数渡そう

```powershell: app.run()
Start-Process -FilePath $venvPythonPath -ArgumentList "-m quart --app main:app run --port $port --host $hostname --reload" -Wait -NoNewWindow
```

powershell で渡せないか格闘したけれど、知識不足で敗退

.ps1 上で直接書いたらエラーの例
> Error: No such command 'run(debug=true)'.

> Error: Got unexpected extra argument (debug=True')

## powershell で カスタム引数付けたらいけるんじゃね？と

そもそも、main:app 自体が引数なので、ダメだった・・

```python: parser
parser = argparse.ArgumentParser()
parser.add_argument(
    "--running_mode", required=False, help="Development, Default: None(Production)"
)
args = parser.parse_args()
args.running_mode
print(args.running_mode)
```

# あとがき

今回はドキュメントを見たけど、勘違いもあって嵌った。

ただ、Quart のソースも実際に見られるので、中身見ればいいじゃんって、コードを読んで環境変数に気付けたのだった。

教訓、毎度のことながら

- コードを読もう
- ドキュメントを読もう
cached-providerを作ってみた

# はじめに
キャッシュとは、一度取得したデータを一時的に保存しておき、次回同じデータが必要になったときに再取得せずに素早く提供する仕組みです。例えばAPIからデータを取得する場合、最初のリクエスト時にそのデータをキャッシュに保存しておき、次回からはキャッシュからデータを返すようにすると、処理が速くなります。

しかし、初回のデータを取得している間にも次のリクエストが来るかもしれません。ロックを取得して待たせるという選択肢がないTypeScript/JavaScriptの場合、このようなケースを綺麗に扱うのは意外と難しいものです。

その問題を解消するために書いた自作ライブラリの紹介です。

[cached-provider on npm](https://www.npmjs.com/package/cached-provider)

# 基本的な構成
## ObjectIdMapper
JavaScriptのObjectには固有のIDがありません。そのため、Objectに対してロック処理をするためには、Objectを一意に識別する仕組みが必要になります。ObjectIdMapperはWeakMapを用いることで、Objectごとに固有な文字列IDを生成、保持します。

## Synchronizer
TypeScript/JavaScriptの世界では、同期化はPromiseを連結していくことで行います。Synchronizerは文字列キーに対応するPromise Chainを保持し、新しいPromiseをその後ろに繋げていくことで同期化を実現します。

ObjectIdMapperと組み合わせることで、オブジェクトごとに独立した同期化を行うことができます。

## CachedLazyProvider
Synchronizerを用いると、キャッシュは比較的簡単に実装できます。最大限のパフォーマンスを得るために、キャッシュは３段階で処理を行います。
1. 同期化前のキャッシュ取得 (hitA)
1. 同期化後のキャッシュ取得 (hitS)
1. 同期化後の値生成 (miss)

CachedLazyProviderはその名の通り怠惰で、キャッシュがない状態での初回アクセスはどうしても遅くなります。

## CachedProvider
キャッシュがない場合の遅延対策として、キャッシュの有効期限が切れるより前にバックグラウンドでキャッシュを更新することが考えられます。
CachedProviderはCachedLazyProviderの拡張であり、データ取得とは独立して定期的にバックグラウンドでの値更新を行います。適切にTTLを設定することで、値取得時の遅延をほぼ0に抑えることができます。

# より詳しい解説
ニーズがあれば書く予定
【supabase】Prismaのmigrationがいつまでも終わらない


## 目次
1. [状況](#状況)
2. [解決方法](#解決方法)
3. [解説](#解説)
4. [それでも解決しない場合](#それでも解決しない場合)

## 状況
Next.jsで作成したアプリケーションにおいて、Prismaで定義したスキーマをデータベースに作成する際に次のコマンドを実行しました

```
npx prisma migrate dev --name init
```

このコマンドを実行すると、エラーは表示されないものの、処理が終了しないという問題が発生しています。

## 解決方法

Connection pooler　ModelをTransaction modelからsession modelに変更する
![スクリーンショット 2024-06-18 0.52.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3721753/6ee1d166-fe51-220a-fc0e-add183348963.png)
![スクリーンショット 2024-06-18 0.52.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3721753/da4d6ff5-9ec2-136e-eaf7-6fc6d51cd5c1.png)


## 解説
Transaction modelとsession modelでポート番号が違う
ポート番号6543=>5432

### URIの形式
```
postgres://postgres.[USER]:[YOUR-PASSWORD]@[revision]:[port]/postgres
```

#### Transaction model
```
postgres://postgres.[USER]:[YOUR-PASSWORD]@aws-0-ap-northeast-1.pooler.supabase.com:6543/postgres
```

#### Session model
```
postgres://postgres.[USER]:[YOUR-PASSWORD]@aws-0-ap-northeast-1.pooler.supabase.com:5432/postgres
```

公式ドキュメントによると
- **session model**
  - セッション モードは、データベースに直接接続するのと近い
- **transaction model**
  - サーバーレス環境から接続する場合は、トランザクション モードが推奨

[supabase公式ドキュメント/connection-pooler](https://supabase.com/docs/guides/database/connecting-to-postgres#connection-pooler)

## それでも解決しない場合
1. データベース接続の確認：データベースが正しく稼働しており、Prismaが接続できているか確認する
2. Prismaの設定ファイル：prisma/schema.prismaや.envファイルが正しく設定されているか確認する
3. ログの確認：Prismaのログやデータベースのログにエラーメッセージが出ていないか確認する
4. コマンドの再実行：一度コマンドを中断して、再度実行してみる
5. 依存関係の再インストール：node_modulesディレクトリを削除してから、npm installまたはyarn installを実行する