OmniAICreator/Qiita-1.07M huggingface dataset:
[リサーチ・メモ]viコマンドでスタブレスポンスを書き換える

テストケース作成時にviコマンドでスタブのレスポンスを書き換える必要があり、使用したことがなかった為まとめる。

## 使用したコマンド
|seq|コマンド|内容|
|:--:|:--:|:--:|
|1|vi ファイルパス指定|書き換えファイルの指定|
|1|gg|ファイルの先頭に移動|
|2|V|ビジュアルモード(範囲操作ができる)|
|3|G|最終行に移動(全選択になる)|
|4|d|選択行を削除|
|5|i|挿入モード|
|6||レスポンス貼り付け|
|7|:wq|保存して終了|


## viコマンド時のエラー対応
下記メッセージが表示された場合は、編集中のファイルに関連するスワップファイル（一時ファイル）が既に存在している為、「:q!」で変更破棄や、「rm スワップファイル指定」で削除する。
```
E325: ATTENTION
Found a swap file by the name "ファイル名.json.swp"
          owned by: default   dated: Tue Dec 26 01:45:22 2023
         file name: ファイル名
          modified: YES
         user name: default   host name: stub001-0
        process ID: 3432 (still running)
While opening file "/ファイル名"
             dated: Mon Aug  1 06:36:04 2022
```
React×TypeScriptでhtmlのinputタグのonChangeみたいな動作をする入力コンポーネントの作成(備忘録)

# めっちゃ簡単
```react
import {Component, ChangeEvent, KeyboardEvent} form "react"

export class TextInput extends Component<{
type?: "text"|"email"|"password",
value?: string,
className?: string,
onChange?: (e:ChangeEvent) => void,
onCommit?:(e:KeyboardEvent) => void
}> {
    state: {
        isComposition: boolean
    } = {
        isComposition: false
    }
    render() {
        return <>
        <input
        type={this.props.type}
        value={this.props.value}
        className={`${this.props.className} defaultClassName`}
        onChange={this.props.onChange}
        //ここから
        onCompositionStart={() => {this.setState({isComposition: true})}}
        onCompositionEnd={() =>{ this.setState({isComposition: false})}}
        onKeyDown={(e) => {
            if(e.key === "Enter" && !this.state.isComposition && this.props.onCommit){
                this.props.onCommit(e);
            }}
            //ここまでが要
        />
        </>
    }
}
```

# 解説

- ### onCompositionStartとは?
React公式ドキュメントでは
> CompositionEvent ハンドラ関数。インプットメソッドエディタ (IME) が新しいコンポジションセッションを開始するときに発火します。

と書いてるが簡単にいうと、変換を開始すると発火するみたい


### onCompositionEndとは
> CompositionEvent ハンドラ関数。インプットメソッドエディタがコンポジションセッションを完了またはキャンセルするときに発火します。

つまりこれは変換が終わった時に発火するみたい


## 処理の流れ
1. 変換中かどうかの状態をisCompositionという名前のstate変数で保持
1. onKeyDownによってキーボードの押下状態を常に監視
1. Enterキーが押された&&変換中でない&&this.props.onCommitに関数が設定されてる場合のみthis.props.onCommitを発火する


注意： onCommitの設定は任意にしているためthis.props.onCommitはundefinedにもなり得るので条件に追加している
React の MUI で TimeLineを使おうとしたらなんかエラーが出た話．

# TL;DR
これらを実行したらなんか動いた．

:::note warn
適当に実行したものを順番通りに書いてるだけです．
再現性があるかよくわかりませんが，自己責任で実行してください．
:::

```Bash
$ npm install @mui/material @emotion/react @emotion/styled
$ npm install @mui/lab@latest
$ rm -r node_modules
$ rm package-lock.json
$ npm install
```

# 経緯
ReactのMUIを用いてウェブサイトを作っていた時，`<TimeLine>`を使いたくなった．だけど，`<TimeLine>`は`@mui/lab`の中にあるらしいからまだモジュールに入ってなかったらしい．だから，愚直に`npm install @mui/lab`した．だけど，なんかエラー(`ERROR in ./node_modules/@mui/lab/node_modules/@mui/base/index.js
Module build failed (from ./node_modules/source-map-loader/dist/cjs.js):
Error: ENOENT: no such file or directory, open `)が出たからどうしようかと．適当にググったものとChatGPTに聞いた結果を(~~適当に~~)実行した(**危険**)．

# 結果
冒頭にもあるとおり，以下のコマンド群を実行した．
```Bash
$ npm install @mui/material @emotion/react @emotion/styled
$ npm install @mui/lab@latest
$ rm -r node_modules
$ rm package-lock.json
$ npm install
```

:::note alert
再三になりますが，適当に実行したものを順番通りに書いてるだけです．
自己責任で実行してください．
:::

# P.S.
今さっき起きたことを忘れないうちに記述しました．
誤字脱字etcのご指摘，感想etcお待ちしています．
AI-900 受験記 (2023年12月合格)

2023年12月末にAI-900: Microsoft Azure AI Fundamentalsを受験した記録です。
結果は合格 (1000点満点中750点)です。
日本語で受けています。

# 受験した動機
生成AIの流行を受け、AIの基本的な用語や概念を習得したいと思ったため

# 受験後の感想
個人的には学習目標が取得でき受けてよかったと思います。

1.世間でよく聞く機械学習の用語や処理の概要をつかむことができました。
(教師あり/なし学習、モデル、トレーニング等)

2.試験勉強にChatGPTが役立ちました。
各用語の違いや、処理の順番など聞きまくりました。

3.生成AIやAzure Open AIに関する出題は１問もなく拍子抜けしました。
2023年11月に更新の試験範囲ではAzure Open AIが追加されてます。
しかしローカライズに8週間なので、日本語での新しい試験範囲は2024年になるようです。

試験 AI-900: Microsoft Azure AI の基礎の学習ガイド
https://learn.microsoft.com/ja-jp/credentials/certifications/resources/study-guides/ai-900#skills-measured-as-of-november-2-2023

# 学習の注意点
1.用語は意味だけでなく、試験では具体例も聞かれます。
たとえば、「教師あり学習　事例」など調べておくとイメージがつきやすいです。

2.AzureのAIサービスを理解するのが難しかったです。
特にサービスの統廃合を行っているため、最新の情報を確認するよう注意が必要です。

例：以下のように以前のCognitive Servicesが現在はAzure AIサービスに含まれている。
https://learn.microsoft.com/ja-jp/azure/ai-services/luis/what-is-luis

3.Azure PortalでAI Serviceの実機を見ておくことをおすすめします。
どんなサービスが存在しているか、メニューで見ておくとイメージがつきやすいです。

4.責任あるAIは数題出題があります。得点できるようおさえましょう。
https://www.microsoft.com/ja-jp/ai/responsible-ai?activetab=pivot1%3aprimaryr6

# おすすめの教材、勉強サイト
Microsoft 提供の無料問題集が役に立ちました。
https://learn.microsoft.com/ja-jp/credentials/certifications/exams/ai-900/practice/assessment?assessmentId=26&assessment-type=practice

以下のように図で機会学習の流れを解説しているサイトが大変役に立ちます。
文字ベースより、図で処理の全体像を掴んだ方が早いと感じました。
https://www.itmedia.co.jp/enterprise/articles/1901/04/news009.html
https://www.kamishima.net/archive/mldm-overview.pdf

以下の過去問サイトでどんな問題が出るか雰囲気はつかめます。
ただ情報が古いものが含まれているため、個人的にはお役立ち度は少なめです。
https://www.examtopics.com/exams/microsoft/ai-900/
エンジニアはITコンサルタントの本当の役割を果たすべき

## 胡散臭いITコンサルタントが多い
IT業界では「ITコンサルタント」が今でも高収入で人気を誇っている。Sier時代は協業でITコンサルタントと一緒に仕事をやることはこれまでいくつかあったがこれって普通にエンジニアがやればいいんじゃないかってことがほとんどだった。エピソードを言うと、難しそうにITコンサルタントが課題について長時間MTGしてくることがあった。だらだらと抽象的な話を交えつつ、結論何が課題か聞いてみると文字化けについてどう解決すべきかというようなめちゃくちゃ簡単なことだった。結果、移行先のシステムに対応している文字コードを変えることで済んだが、そのことすら知らなかったのだ。
クライアントの課題を解決してあげることがコンサルの大まかな責務だと思うけど、プログラミングもシステム設計もしたことないのにこんなレベルでどうやって課題解決できるの？っ思う。ちなみにそこは結構有名な大手コンサルだった。

### ITコンサルタントは実装経験不足またはゼロ！

ITコンサルと名乗る人たち、彼らってその責務を果たすには実装経験がちゃんと必要じゃないだろうか？そもそも業界未経験から転職で参入したり、文系出身の新卒が実装経験ゼロで参入したりするのが当たり前に横行している。例えば、「オブジェクト指向のクラスとオブジェクトの違いについて簡単に説明してください」ってITコンサルに聞いてみるといい。結構詰まる人が多いと思う。
ある程度実装してたら基本のことだから知っていて当たり前だと思うけど、実際うまい事言葉巧みに回避してくるのでそういう口のうまい人には注意したほうがいい。クライアントの話を理解しやすくするために、オブジェクト指向とか基本的なことを知っていないと、詳細な要件をどのようにモデル化するか、あるいは大まかなシステム構築の概要すらクライアントに説明できない。
ITコンサルが提案したシステム案を委託先に丸投げし、システムが実際の運用段階で非効率的であることが発覚し、結局委託先のエンジニアが要望を再調整して修正していくことなんてざらにあるしもはや当たり前になっている。
設計構築においてもしかり、モジュール化やデータベース設計、アーキテクチャ設計などの基本的な設計知識が課題解決には必須、これらに疎いコンサルタントが多く見受けられ、クライアントのビジネスニーズにマッチしたシステムを提供できていない。ただの横流しだ。


### クライアントの低いリテラシーを逆手に取った高額請求

そしてITコンサルが抱える別の問題は、クライアントの技術リテラシーの低さを利用した高額請求だ。よくあるのがクラウドシステムの導入案件。導入するだけで初期費用といって導入するだけで数百万なんてざらにある。導入だけならなんてはっきりいって初期設定するくらいなのでエンジニアじゃなくてもだれでもできる。こんなことは社内で行いましょう。ほかにもあるクライアントは基本的なウェブサイトの構築を依頼したが、ITコンサルがクライアントの理解力に付け込み、高度なカスタマイズが必要だと主張して高額な料金を請求することもあり、結局、必要のない機能を含んだ過剰なプロジェクトが進行し、クライアントの予算を圧迫するなんてことも多い。案外クライアント自体もうまく騙されていることに気づいていないことが多い。
もし話を進めているのならば担当者がエンジニアとしての知見がちゃんとあるのか確認したほうがいい。

### エンジニアに求められる多面的なスキル

一方で、エンジニアも問題を抱えている。圧倒的コミュ力が低い。私自身営業界隈にもいた人間なのでその差に愕然とあきれることがある。技術スキルだけでなく、コミュニケーション力やビジネス理解、ユーザビリティに対する感度が求められている。例えば、クライアントとのミーティングで技術的な側面だけでなく、ビジネスニーズを理解し、それに基づいた提案ができるエンジニアの重要性は増しているのにもかかわらず、プログラムだけやっていればいいという考えの人がいまだにいる。だからITコンサルよりいつまでたっても収入が低いんだろう。

## まとめ

今こそエンジニアが多面的なスキルを身につけ、コンサルティングにもリーダーシップを発揮すべき。より効果的な提案とクライアントへの価値提供が可能になり、ITコンサルタントとエンジニアの枠組みを超えた総合的なソリューションが求められる。専門性だけでなく柔軟性も重視され、新たなビジネス領域への挑戦が必要で、エンジニアは変化に適応し、リーダーシップを発揮していかないといけない。エンジニアは横流し仲介屋のITコンサルタントを排除し、ダイレクトで技術解決をしていくべきだ。
Python 3.12でのCレベル再帰の上限導入の問題

Python 3.11以前では、Pythonレベルの再帰はCレベルの再帰を常に引き起こしていました。
ですので、Pythonの再帰の深さはCレベルのスタックの大きさに依存していました。
Linuxではスタックは動的に増加出来るのですが、Windowsでは出来ません。

下記の深い再帰は、WindowsではPython 3.10はスタックオーバーフローを起こします。

```python
import sys

sys.setrecursionlimit(100_000)

def foo(n):
    return 0 if n == 0 else foo(n-1) + 1

print(foo(10_000))  # Process finished with exit code -1073741571 (0xC00000FD)
```

再帰を前提とするプログラムで、デフォルトのスタックサイズでは再帰の深さが足りない場合、スタックサイズを最大値に指定したスレッドを一つ作成して、そのスレッドで再帰を実行するなどの対応が必要でした。

Python 3.11では、["純粋な"Pythonレベルの再帰はCレベルの再帰を生成しなくなりました](https://docs.python.org/3/whatsnew/3.11.html#inlined-python-function-calls)。このため、上記のプログラムは、Windows上でも成功するようになりました。しかし、下記のように`__call__`メソッドは内部でCレベルの再帰を作成しているようで、3.11でもスタックオーバーフローを起こします。


```python
import sys

sys.setrecursionlimit(100_000)

class Foo:

    def __call__(self, n):
        return 0 if n == 0 else self(n - 1) + 1


print(Foo()(10_000)) # Process finished with exit code -1073741571 (0xC00000FD)
```

Python 3.12では、[C-レベルの再帰の上限が導入](https://github.com/python/steering-council/issues/102)され、CPythonの内部で値がハードコードされました。その結果、スタックオーバーフローになる前に、かなり浅い段階でPythonのRecursionErrorで止まるようになりました。

```
Traceback (most recent call last):
  File "C:\Users\xxx\temp5.py", line 11, in <module>
    print(Foo()(10_000))
          ^^^^^^^^^^^^^
  File "C:\Users\xxx\temp5.py", line 8, in __call__
    return 0 if n == 0 else self(n - 1) + 1
                            ^^^^^^^^^^^
  File "C:\Users\xxx\temp5.py", line 8, in __call__
    return 0 if n == 0 else self(n - 1) + 1
                            ^^^^^^^^^^^
  File "C:\Users\xxx\temp5.py", line 8, in __call__
    return 0 if n == 0 else self(n - 1) + 1
                            ^^^^^^^^^^^
  [Previous line repeated 496 more times]
RecursionError: maximum recursion depth exceeded

Process finished with exit code 1
```

この変更を実装したMark Shannonの理由としては、
* Pure Pythonの再帰がPythonの再帰と分離されたのだから、以前からあったPure Pythonの再帰上限とは別に、Cレベルの上限を設定すべき。
* スタックオーバーフローは好ましくない。
* スタックサイズはプラットフォームごとに仕様が異なるので、とりあえずどのサポートされているプラットフォームでもオーバーフローしない小さい値に上限を設定する。

という理由でした。

この仕様は、深いＣレベルの再帰が可能であったLinuxなど、Cのスタックサイズが十分にあう場合でも新規の浅い上限で`RecursionError`となるため、[Memoizationを提供する`functools`の`cache`など再帰を前提とするプログラムでCレベルの再帰を使用するプログラムに致命的な支障をきたす](https://github.com/python/cpython/issues/112215)ため、反対意見が出されています。

Mark Shannonは、3.12.0での上限は保守的過ぎたため、実際はもっと高い値に設定可能であり変更をコミットしています。また将来的には、[スタックサイズを事前に把握し、スタックオーバーフローを起こさない程度まで動的にリミットを設定出来るように改善したい](https://github.com/python/cpython/pull/113403#issuecomment-1868484161)、としています。
3年目エンジニア『リソース構築手順書』の作成・レビュー観点ふりかえり

# 記載目的 
先日チームメンバより『リソース構築手順書』の作成・レビューで何に気をつけてるのか質問されました。
改めて今まで自己流で手順書の作成・レビューをしてしまっていたなと思い、まずは現状自身が気を付けてる観点を言語化してみようと思います。

それと弊チームは『Excel手順書』大好きチームなので、IaCでコード管理して云々のようなことに関しての記載はございません。

## 『リソース構築手順書』を作成する場合に気を付けてること
個人的には『プロジェクトの背景と目的の理解』が重要で、背景をしらないでつくられたものと、背景ありきでつくられたもののの精度に大きく関係していると考えている。


### プロジェクトの背景と目的の理解: 
- 新機能の実装にあたりプロジェクトの背景や目的を理解するため、依頼者との会話や関連ドキュメントを確認して、『リソース構築手順書』フェイズに至る前段を把握する。

### 成果物の確認:
- レビュアーや作業者との視点を合わせるために目的や手順書の粒度について事前の会話を実施する。
- 最も重要なポイント（クリティカルポイント）を共有し、確認するべき事項を明確にしてメンバー間で周知する。

### 用語の統一と説明: 
- 専門用語や略語を使用する場合は、それらを一貫して使用し必要に応じて用語の定義や説明を記載する。

### フローの確立:
- 手順書は既に確立されたフローに基づいて作成されていること（例えば、検証環境での事前確認など）。

### 網羅性:
- 手順書のページ前に全体の構築フローを記載することで、本構築における全量が把握出来るようなページを作成する。

### 詳細な手順の記述:
- 構築対象のリソース名(プロジェクトの命名規則確認)や具体的な構築手順を記載する。
- 作業者の経験レベルによっては、必要に応じて画面キャプチャを取り入れる。
※基本的に手順書作成者と実際のリソース構築者は同じものとする。

### 終了・成功条件の記載：
- 1つの作業につき、1つの終了・成功条件を記載する。


## 『リソース構築手順書』をレビューする場合に気を付けてること
当然かもしれないが『フローの実用性』が重要で、そもそもリソースの構築がされないと話しにならない。
その上で構築されたリソースが他のリソースへの影響を考える必要があると思っている。

### フローの実用性: 
- 作成された手順書に沿ってサービスが構築できるかを確認する。不明瞭な点があれば実際に手順を試行及び、関連するブログや文献を参照する。

### 既存運用への影響：
- リソースが構築されることによる、運用されている他リソースへの影響を想像する。
(例)Lambda実行に伴うマネージドで構築される、CloudWatchLogsのログ・監視の設定

### 通信要件のチェック: 
- 特に問題の起きるセキュリティグループ（SG）やネットワークACL（NACL）の部分に注意、通信要件をチェックする。

### 命名規則の確認
- 用語やリソースの命名が一貫性を持ち、明確であるかを確認する。
   用語については作成者が定めたものなのか、AWSのものなのか、PJ独自のものなのかのを明瞭にする。

### 読みやすさ視認性:
- 文書の構成、フォーマット、語尾の揺れ、言語の明瞭さ、について評価する。


## さいごに
大変属人性高めだったので、改めて文章にできてよかったです。
より精度を上げるために、AWSのベストプラクティスや、IPA（情報処理推進機構）のセキュリティガイドラインなども読んで、また来年からの『構築手順書』作成・レビューをしていきたいと思います。
他にもコレ読んでいたほうがいいなどありましたら教えてください。
SwallowのLlamaForCausalLMに常用漢字を追加するには

私(安岡孝一)の[12月21日の記事](https://qiita.com/KoichiYasuoka/items/60c44df1740efb38e04e)にも書いたが、Swallowのトークナイザは[常用漢字2136字](https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kijun/naikaku/kanji/)のうち51字をサポートしておらず、これら51字はバイトフォールバックしてしまう。この問題に対し[昨日の記事](https://qiita.com/KoichiYasuoka/items/0717587f80b79d169b08)では、[`Replace`](https://huggingface.co/docs/tokenizers/api/normalizers#tokenizers.normalizers.Replace)を使って「𠮟」「塡」「剝」「頰」の4字を救う手を示したが、これだと抜本的解決にならない。抜本的解決としては、これら51字のトークンをSwallowのLlamaForCausalLMモデルそれ自体に追加して、追加したトークンで追加学習をおこなうしかない。端的には、こんな感じ。

```
#! /usr/bin/python3
import urllib.request,json
from transformers import LlamaTokenizerFast,LlamaForCausalLM,DataCollatorForLanguageModeling,TrainingArguments,Trainer
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 for i,j in zip(joyo,tkz(joyo)["input_ids"]) if len(j)>3]
tkz.save_pretrained("mySwallow-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("mySwallow-7b-instruct-hf/tokenizer.json")
mdl=LlamaForCausalLM.from_pretrained("tokyotech-llm/Swallow-7b-instruct-hf",device_map="auto")
tkz=LlamaTokenizerFast.from_pretrained("mySwallow-7b-instruct-hf",modex_max_length=mdl.config.max_position_embeddings)
mdl.resize_token_embeddings(len(tkz))
q=[tkz("常用漢字は子供の名づけに使えます。"+"は常用漢字なので、子供の名づけに使えます。".join(c+["\n"]))]
arg=TrainingArguments(num_train_epochs=1,per_device_train_batch_size=1,output_dir="/tmp",overwrite_output_dir=True,save_total_limit=1)
trn=Trainer(args=arg,model=mdl,data_collator=DataCollatorForLanguageModeling(tkz,mlm=False),train_dataset=q)
trn.train()
trn.save_model("mySwallow-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)に、たった1行だけ追加学習をおこなうにもかかわらず、NVIDIA A100-SXM4-40GBが4枚も必要になって、なかなかに大規模言語モデルの悲哀を感じた。しかも、私の手元で出力された結果は以下のとおり。

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

70bモデルにも挑戦してみたい気がするのだが、さて、GPUが何枚ほど要るんだろ。
今年が終わるので転職してから今日までを振り返る

初めましてKonbuGXと申します。
今年が終わるので転職してから今日までをざっくりと振り返りたいと思います。

# 前職のことをざっくり
前職は新卒でSES企業にエンジニアとして入社しました。
客先では主に詳細設計書作成からテストまでを担当しておりました。

# 今年の振り返り
**・4月**
　入ってばかりで参画する案件が決まっていなかったので、自社で利用しているツールの
　ドキュメントなどを読み漁っていました。
　途中から案件が決まり、インフラ周りのドキュメントを読みつつツールを
　触っていました。
 
**・5月**
　先輩一人と顧客の数人でazureでのインフラ環境構築の案件が始まりました。
　先行作業としてインフラ環境の構築に最低限必要なリソースを洗い出したり、
　テスト環境でリソースを作成して動作検証をしておりました。

**・6月**
　必要なリソースの洗い出しが終わったので、リソースを作成する際の
　設定値を洗い出してまとめておりました。
　インフラをがっつり触るのは初めてなので、かなり苦労しました。

**・7月**
　この月もリソースを作成する際の設定値を洗い出しをしておりました。
　本来なら6月中旬ぐらいから環境構築に入るスケジュールだったのですが
　顧客の都合で環境構築の作業に入れませんでした。
　なので、この案件から外れて別の案件に携わることになりました。
　ちなみに次の案件は決まっておりませんでした。

**・8月**
　次の案件が決まっていないので自己学習をしておりました。
　ずっとazure周りのドキュメントを読んでおりました。
　途中から案件が決まったので、案件先で利用する技術の学習を進めていました。
　一人で客先常駐でしたので、面接で言ってたことと全然違うやんって思ってました。

**・9月**
　この月から新たな案件に携わりました。
　内容はサーバのリプレイスに伴うバッチの新規作成・改修でした。
　現行サーバの資料を読み漁りつつ、新サーバにする際の影響範囲や
　新規で作成しないといけないバッチの洗い出し、
　マスタのマッピング定義書を作成をしておりました。

**・10月**
　引き続きマッピング定義書を作成しておりました。
　中旬ぐらいからバッチ処理を作成。
　バッチ処理の期日がびっくりするぐらい短いので毎日残業してました。

**・11月**
　この月では、作成したバッチ処理の単体・結合テストを進めてまいりました。
　途中、客先の顧客から仕様変更が何度か入り、バッチ処理の修正も進めておりました。
　テスト完了後は現行サーバのデータを利用して新サーバを稼働させ
　出力結果が現行と新で同じか時々確認しておりました。

**・12月**
　この月では出力結果の確認をしつつ、新サーバで動くバッチファイルの
　一覧を作成しておりました。
　中旬ぐらいから仕様変更がガンガンきて、バッチファイルの修正と
　テストを最終出勤日前まで進めておりました。
　客先の顧客が仕様を勘違いしていての変更が入ってばかりでしたので、
　しっかりしてくれって思いました。しわ寄せが全部降りかかって大変なので。

# 今年の気づき
**・どこの会社もたいして変わない**
　前の会社のよくない部分が嫌で別の会社に行っても
　前の会社の良い部分が別の会社ではよくなかったりと
　自分が望む良い部分は両立しないと感じました。
　また、心無い言葉を平気で投げかける顧客や上司・先輩はどこにもいるんだと
　気づき、どこの会社もたいして変わらないと思いました。

**・会社勤めに向いてない**
　無駄な会議やルールに腹が立ったり、自分のペースで仕事を進められないことに
　非常にストレスを感じたりなど、こんなもんだと納得できずガチガチに縛られて
　思うように仕事を進められないことでストレスに感じることが非常に多いです。
　そのため、自分は会社勤めするには向いてない性分だと気づきました。
　また、細かい報連相も煩わしく感じ、必要最低限のコミュニケーションしか取らないと
　協調性がないので、余計に会社勤めするには向いてないと思いました。
　
**・中途は放置されやすい**
　今の会社や客先に入って感じたのですが、これといった説明もなく
　あとはよろしくと放置さることが多々ありました。
　中途で業務経験者だから、これといった説明やフォローがなくても
　すぐに業務できるでしょと思っているのが言動から感じられました。
　業務経験があるといっても前の会社と今の会社ではルールや業務の進め方などで
　異なる点があると思うので、メンバーレベルであれば最初のうちは
　フォローするべきだと思いました。

# 感想
　まだ触ったことのない領域にさわれたり、自分は何が好きで何が嫌いか、
　どういう生き方が自分に合うのかなど、色々と経験して
　自分を見つめる時間が増えたように思います。
　今年はqiitaで記事を思うように書けなかったり、アプリを作れなかったりと
　アウトプットが少ないので、来年はアウトプットを増やしていきます。
　来年も自分のペースで頑張ります。
SAMでAPI Gateway AuthorizerをプリフライトリクエストのOPTIONSメソッド時に除外する方法

## はじめに
LambdaのトリガーとしてAPI Gatewayを指定し、すべてのリソースに一括でAuthorizerを設定したところ、OPTIONSリクエストにもAuthorizerが設定されてしまい、通信に失敗してしまいました。日本語で解説記事がなかったため執筆することにしました。

## 対象者
この記事は下記のような人を対象にしています。

- APIをSAMを使ってLambdaにデプロイしようとしている人
- Lambda Authorizerを使用してAPI Gatewayに認証をかけたい人

## 前提知識
- [SAM](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/what-is-sam.html)
- [Preflight request](https://developer.mozilla.org/ja/docs/Glossary/Preflight_request)

## 結論
下記の通り、 `AddDefaultAuthorizerToCorsPreflight: False` を記載します。
CognitoAuthorizerを例に挙げていますが、IAMでも同様です。

```yaml:template.yaml
Parameters:
  UserPoolArn:
    Type: String
    Description: replace

Resources:
  SampleApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      Auth:
        DefaultAuthorizer: CognitoAuthorizer
        Authorizers:
          CognitoAuthorizer:
            UserPoolArn: !Ref UserPoolArn
        AddDefaultAuthorizerToCorsPreflight: False // この記述でPreflight requestの認証を除外
  SampleFunction:
    Type: AWS::Serverless::Function
    Properties:
      PackageType: Image
      Events:
        Sample:
          Type: Api
          Properties:
            Path: /hello
            Method: get
            RestApiId: !Ref SampleApi
```

デプロイ後のAPI Gatewayリソースをコンソール上で確認してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/852882/ed536224-f0ba-cc0e-3953-81e0de200653.png)
GET リクエストには認可設定が適用されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/852882/d2413805-cb15-a050-4220-cd583ec90805.png)
OPTIONS リクエストでは、認可設定がNONEになっています。無事に除外できたようです。


## おわりに
以上、SAMでAPI Gateway AuthorizerをプリフライトリクエストのOPTIONSメソッド時に除外する方法についてまとめました。

## 参考記事
- [GitHub Issue](https://github.com/aws/serverless-application-model/issues/725)
- [SAM](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/what-is-sam.html)
- [Preflight request](https://developer.mozilla.org/ja/docs/Glossary/Preflight_request)
Use Product Options to Construct Bundles



+ [Error ‘Attempt to de-reference a null object’ on Product Selection in Salesforce CPQ](https://help.salesforce.com/s/articleView?id=000381802&type=1)

+ [CPQ Attempt to de-reference a null object](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000A8ti4SAB)

:::note
Are all of the product options associated to both a parent (configured SKU) and child (optional SKU), and are all of those products active, with price book entries in the price book assigned to your current opportunity and quote?
:::

+ [Error when processing quote : Attempt to de-reference a null object](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007JB3pv)

+ [Apply to Product Option not working as expected](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000A8tP4SAJ)

+ [Use Product Options to Construct Bundles](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007Ebu8ySAB)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/c2bee01a-87fc-e037-27f6-7ef2065d7f39.png)


:::note
Do you have any Validation Rules defined for Quotes or Quote Line Items?  If so, check to see what fields they are requiring.  You might need to update your quote line item "edit multi-line layout" for the page layout you are using to add the required fields.

Check for Validation Rules under Setup > Customize > Quotes and Setup > Customize > Quotes > Quote Line Items. 

https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000A7uT4SAJ
:::
[ TypeScript ] fs などで相対パスを使うとビルド時にパスがずれちゃう問題の処方箋

# 症状
ある日、いつものように TypeScript を使って開発をしていました。
フォルダ構造はこんな感じ。

```
project
├ src
│ └ test.ts
└ resource
　 └ data.json
  ```

`src`の中にソースコードを置き、`resource`の中にデータを設置する、よくあるプロジェクトです。

ビルド設定として、`build`フォルダ内にビルド結果を出力するようにします。
結果としてはこんな感じ。

```diff
project
	src
		test.ts
	resource
		data.json
+ 	build
+		src
+			test.ts
```

たとえば`src/test.ts`に書いたコードは、ビルドを通して`build/src/test.js`に置かれる、といった具合ですね。

そしたらコーディングをしていきます。
`test.ts`の中身はこんな感じ。

```test.ts
import fs from 'fs';
import path from 'path';

// 相対パス
const filePath = path.join(__dirname, '../resource/deck.json');

// data.json ファイルを読み込み
let fileContents = fs.readFileSync(filePath, 'utf8');
let data = JSON.parse(fileContents);
```

`fs` モジュールで json ファイルの中身を読み込む処理です。
パスは `path` モジュールを使った、`test.ts` からの相対パスで書いています。

そしたら実行してみます。
`npx tsc` して、`npm run start` すると...

```
Error: ENOENT: no such file or directory, open 'C:\hogehoge\project\build\src\resource\deck.json'
```

あれれ...エラーが出てしまいました。

# 原因
このエラーが発生する原因は、相対パスにあります。
ビルド前の`test.ts`とビルド後の`test.js`の、`data.json`までの相対パスを比較してみます。

- `test.ts` ( ビルド前 ) : `../resource/data.json`
- `test.js` ( ビルド後 ) : `../../resource/data.json`

そう、原因はここにあります。
ビルドファイルのほうが**階層が一つ深いために、元のコードとずれが生じてしまう**わけですね。

# 対処法
もっともシンプルなアイデアとして、 **`resource`フォルダをビルド時に`build`フォルダにコピーする** というのがあります。

「相対パスの先にフォルダがないなら作っちゃえばいいじゃん！」って話ですね。
実際、ほかのビルドツール（Gradleなど）ではこの方針を取っていた記憶があります。

<hr>

というわけで実践です。
実際には、以下のような手順で実現していきます。

1. `fs-extra` というライブラリをインストールする
1. `resource`フォルダをコピーするスクリプト、`copy-files.js`を書く
1. ビルド時に`copy-files.js`を一緒に呼ぶようにする

## `fs-extra` をインストールする
ファイル・フォルダのコピーには、`fs-extra`を使います。
早い話が「fsの機能を拡張するライブラリ」ですね。

プロジェクトフォルダに`cd`し、以下のコマンドを実行してください。
```sh
npm i fs-extra
```

これでOK。

## `copy-files.js`を書く
そしたら、ビルド時に実行するスクリプトを書いていきます。
置き場所はどこでもよいです。僕はプロジェクトフォルダ直下に置きます。

```diff
  project
  ├ src
  │ └ test.ts
  ├ resource
  │ └ data.json
  ├ build
  │ └ src
  │ 　 └ test.ts
+ └ copy-files.js
```

そしたらスクリプトを書きます。
以下のような感じ。

```js
const fs = require('fs-extra');
const path = require('path');

// ビルドディレクトリへのパス
const buildPath = path.join(__dirname, 'build');

// フォルダをコピーする
fs.copySync(path.join(__dirname, 'resource'), path.join(buildPath, 'resource'));
```

8行目で`resource`フォルダをまるごと`build`の中にコピーしてるわけですね。

## ビルド時に`copy-files.js`を呼び出し
最後に、ビルド時にこのスクリプトを呼び出すようにします。
方法は簡単、`package.json`の中の`npm run build`の内容にちょっと付け足すだけ。

```diff_json
  "scripts": {
+   "build": "tsc && node copy-files.js",
    "start": "node ./build/app.js"
  },
```

`build`コマンドに`node copy-files.js`を追加して、ビルド時に呼ぶようにしています。
この状態でビルドすると...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883146/6a3af709-7338-d7cb-3e02-8436da1fb21f.png)

`build`フォルダの中に、`resource`がコピーされていますね。
【Salesforce認定アドミニストレータ試験】公式模擬試験の英日翻訳と図解解説 (3)

この試験を受けるための勉強をした際に思わぬ苦戦をしたので、英語公式模擬問題を翻訳しながら図解解説として整理しました。

第3回目の投稿です。　～レコードタイプとページレイアウトに関する問題～

第1回目、第2回目、第3回目で投稿した設問に共通するのは「レコードタイプ」です。第1回目の解説に書きましたが、レコード タイプを使用すると下記の制御ができます。

　1. ビジネスプロセス（フェーズ、進捗パターン）
　　　a. 商談：営業プロセス
　　　b. ケース：サポートプロセス
　　　c. リード：リードプロセス
　2. 選択リスト値
　3. ページ レイアウト

Aung


第1回目の投稿　～レコードタイプと営業プロセスに関する問題～
https://qiita.com/Aungz/items/204d20c5c2c72a52c9df

第2回目の投稿　～営業プロセスと選択リスト値に関する問題～
https://qiita.com/Aungz/items/5ecaa907ff6500924420

![スライド1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3626902/71b80777-d2b2-760f-0c8f-9049e69d187d.jpeg)
![スライド2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3626902/ee2b78c3-1fd7-7cb7-0696-4abb027d4c68.jpeg)
![スライド3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3626902/43bdd0f7-6d31-a546-c003-c30e3b28059e.jpeg)
リストをStream化する

有限長のリストを，あたかも無限長のStreamであるかのように扱いたい時があったので，実装してみたところ，うまくいきましたので，ご報告します．

## 実装例

```elixir
fn list, default_value ->
  Stream.unfold(list, fn
    [] -> {default_value, []}
    [h | t] -> {h, t}
  end)
end
```

## 使用例

```elixir
iex> f = 
...>   fn list, default_value ->
...>     Stream.unfold(list, fn
...>       [] -> {default_value, []}
...>       [h | t] -> {h, t}
...>     end)
...>   end
#Function<41.105768164/2 in :erl_eval.expr/6>
iex> s = f.([1, 2], 0)
#Function<63.53678557/2 in Stream.unfold/2>
iex> Enum.take(s, 10)
[1, 2, 0, 0, 0, 0, 0, 0, 0, 0]
iex> s = f.([9, 8, 7, 6, 5, 4, 3, 2, 1], 0)
#Function<63.53678557/2 in Stream.unfold/2>
iex> Enum.take(s, 10)
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
iex> s = f.(9..1, 0)
#Function<63.53678557/2 in Stream.unfold/2>
iex> Enum.take(s, 10)
** (FunctionClauseError) no function clause matching in :erl_eval."-inside-an-interpreted-fun-"/1    
    
    The following arguments were given to :erl_eval."-inside-an-interpreted-fun-"/1:
    
        # 1
        9..1//-1
    
    (stdlib 5.2) :erl_eval."-inside-an-interpreted-fun-"/1
    (stdlib 5.2) erl_eval.erl:963: :erl_eval.eval_fun/8
    iex:3: (file)
    iex:3: (file)
iex> s = f.([:a, :b], :c)
#Function<63.53678557/2 in Stream.unfold/2>
iex> Enum.take(s, 10)
[:a, :b, :c, :c, :c, :c, :c, :c, :c, :c]
iex>
```
JavaScript まわりの用語あれこれ

# 概要
～script だの ～js だのが多すぎたのでまとめ。

# ECMAScript
- JavaScript の仕様、構文などをまとめた標準規格
- 要するに JavaScript のバージョンを示す（ 例：ES6 )

---

# Browser JS

- ブラウザ上で動作する JavaScript 環境
- 正確にはこんな単語はない（単に「ブラウザ上で動くJS」の意）
    - 正確な表現があれば教えてください

# Node.js

- サーバー側で動作する JavaScript 環境
- **npm ( Node Package Manager )** と呼ばれるパッケージの管理システムを同梱している

---

## CommonJS

- JavaScript において、**モジュール**を使用するためのシステム
- Node.jsではデフォルトで全てのモジュールをこれで扱っている
- `require()`、`module.exports`などを使用

## ESModules

- ECMAScript 標準のモジュール管理システム
- 最新版の Node.js で採用されつつあり、次第にこちらに移行している
- **CommonJSのモジュールを読み込める（逆は不可）**
- `import`、`export` を使用
Node.js に入門したときの覚え書き

# はじめに
どうも。
普段は Express.js とか axios.js あたりを使ってﾁｮﾒﾁｮﾒしてるんですが、前提技術である **Node.js** について何も知らなかったので、改めて学んでみました。

内容的には以下の記事の嵩増しみたいなもんなので、改めて勉強される方はこちらの記事を推奨します。（とほほさん、いつも助かってます）

https://www.tohoho-web.com/ex/nodejs.html

# Node.js とは？

- **サーバーサイド**の JavaScript 実行環境
- **npm ( Node Package Manager )** と呼ばれるパッケージ管理システムを同梱
- **MEAN ( MongoDB ＋ Express ＋ AngularJS ＋ Node.js )** と呼ばれる構成で利用されることも多い

# なぜ Node.js なのか

- **Google V8 JavaScript エンジン** を採用しているため、高速
- 負荷の大きい処理（暗号化など）を内部で複数スレッド処理できる
- 様々なスケールに対応しうる
    - 小規模なプロダクトにも対応
    - 10k問題 ( クライアント1万台レベルになると性能が極端に悪化する問題 ) に対応

# Node.js の歴史

- 2009: カリフォルニア州の Ryan Dahl 氏が Node.js の開発に着手
- 2011: 初期公開バージョン ( `v0.1.14` ) をリリース

# Node.js とブラウザ JavaScript の違い

- Node.js には `document` や `window` などのオブジェクトは存在しない
    - サーバーサイドであるため、これらのDOMオブジェクトは使用できない

- ブラウザにはファイルシステムへのアクセス機能などの API が使用できない

- Node.js にはバージョンの制御ができる
    - 過去の JavaScript バージョンを含め、プロダクトに応じた環境設定ができる

# Node.js を動かしてみる

## Hello World ( コンソール版 )

- `node` コマンドで js ファイルを選択することで実行ができる

```bash
node hoge.js
```

```jsx
// hoge.js
console.log("Hello World!");
```

## Hello World ( Web 版 )

- Web サーバとして動作させたい場合は、以下のように`http`ライブラリを使う
    - 以下のコードを書いた後、ブラウザで`localhost:8080`にアクセスすると確認できる

```jsx
// hoge.js
const PORT = 8080;

var http = require('http');
var server = http.createServer(function(req, res) {
  res.write("Hello world!\n");
  res.end();
}).listen(PORT);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883146/9492a2ea-782b-40b3-bb90-4b03fc017128.png)

- または、別のコンソールを開いて`curl`を使うことでも確認できる

```jsx
curl localhost:8080
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883146/3b0183e2-3d3e-c206-fc9a-27c7a961ec16.png)

## コンソールに出力する

- `console.log()`: ログの出力関数。基本的にはこれを使う。
- `process.stdout.write()`: ↑の改行なしバージョン。

## クライアントからの情報を得る

- Web のシステムは ********************************リクエスト(要求)******************************** と ******************レスポンス(応答)****************** のセットで動いている
    - これらはそれぞれ`req`、`res`と命名されることが多い
    - 上のコードでも`http.createServer()`の引数の関数で受け取っているのがわかる

```jsx
// hoge.js
const PORT = 8080;

var http = require('http');
var server = http.createServer(function(req, res) {     // <- ここ
  res.write("Hello world!\n");
  res.end();
}).listen(PORT);
```

- この`req`にはさまざまなデータが詰まっている
    - ******URL******: ユーザーがアクセスした場所
    - ******メソッド:****** ユーザーがサービスに対してやりたいこと（例：`GET` → データが欲しい）
    - ****Content-Type****: データの種類を示すもの（例：`text/html` → HTMLデータ）

```jsx
// hoge.js
const PORT = 8080;

var http = require('http');
var server = http.createServer(function(req, res) {
  console.log("URL: " + req.url);
  console.log("Method: " + req.method);
  console.log("Header[Content-Type]: " + req.headers['content-type']);
  res.end();
}).listen(PORT);
```

# 参考

https://www.tohoho-web.com/ex/nodejs.html

https://nodejs.org/en/learn/getting-started/differences-between-nodejs-and-the-browser
個人的な学習メモ2

## ノート
1. 気になっていた本「世界一流エンジニアの思考法」という本を読んだ。
1. 内容としては概ね今まで読んだことがあるような内容の本だった。
1. アジャイル・スクラムなどの基本思想、エンジニア向けというわけではない一般的な内容が記載されていた。
1. 日本的な文化を少し批判するような内容も書かれていたが、概ね自分も同感する内容。
1. 日本企業の形式的な仕事について。
1. このメモのフォーマットはこの本を参考にさせてもらっている。


## キュー
長期休暇中にエンジニア関連の本を読みたいな。

## サマリー
アジャイル・スクラム・自己組織化したチームの日常を内側にいるメンバーの視点で語っている本。
--dart-define-from-fileでXcode Cloud

## 環境
- M2 Mac mini
    - macOS 13.5
- Xcode 15.0.1
- Flutter 3.13.9

## はじめに
[--dart-define-from-fileでFirebase Test Lab](https://qiita.com/m_okubo/items/de453ea2667b0bab7250)に続き、Xcode CloudでCI/CD環境を構築する時にも`--dart-define-from-file`を適用するのに苦労したので、記事に残しておきたいと思います。
尚、`--dart-define-from-file`以外の部分については[Continuous delivery with Flutter](https://docs.flutter.dev/deployment/cd#xcode-cloud)に従ってCI/CD環境が構築できているものとします。

## 定義ファイルの配置方法
`--dart-define-from-file`を使用する場合、定義ファイルには通常秘匿情報が含まれるので、git管理対象外にしていると思います。そのため、Xcode Cloudで`--dart-define-from-file`を使用する場合はワークフローの環境変数を使用します。

![スクリーンショット 2023-12-30 11.57.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291442/b022d7a2-3cb6-f90a-6433-da8715e467e8.png)

シークレットにチェックをつけると、値がログに出力されることも抑制できるので秘匿したい情報はシークレットにしましょう。
これで`ci_post_clone.sh`から環境変数が参照できるようになるので、`echo`コマンド等を使用して定義ファイルを作成します。（Firebaseを使用している場合は同様に`GoogleService-Info.plist`も作成してください。）

```sh
echo "{
  \"flavor\": \"$flavor\",
  \"appIdSuffix\": \"$appIdSuffix\",
  \"appName\": \"$appName\",
  ...
}" > dart_defines.json
```

## 依存性の注入方法
定義ファイルを配置しただけでは環境変数が取り込まれないので、下記のコマンドを実行して`ios/Flutter/flutter_export_environment.sh`と`ios/Flutter/Generated.xcconfig`ファイルを作成します。

```sh
flutter build ios --config-only --debug --dart-define-from-file=dart_defines.json
```

これで`xcodebuild archive`実行時に環境変数が取り込まれてCI/CDができるようになります。

## さいごに
`--dart-define-from-file`はすごく便利なのですが、ネットで検索しても、この辺りの情報はあまり出てこないですね。この記事が誰かのお役に立てば幸いです。
勉強日記

Google　search　APIを使用して、広告文を抽出するということをやりたいのだけど、
検索エンジンを作成するだけで疲れました。


一時間ほどかかりました。

やったことをまとめながらしているのだから、そりゃかかりますが

疲れました。
明日も引き続き、やりますが。
疲れました。
早くAPIのターンに移りたい。
JestでTypeScriptのテストを書く(Step1:環境構築から実行まで)

## はじめに
表題通り、JestでTypeScriptのテストを書きます。
下記StepでJestの学習を進めていきます

[Step1: Jest(環境構築から実行まで)](https://qiita.com/koji0705/items/258166f4f281efbb2c46)←今回はここ
[Step2: Jest(Matcherを利用する)](https://qiita.com/koji0705/items/2049d581fe7d343d58d3)
[Step3: Jest(API検証)](https://qiita.com/koji0705/items/1f7099600a97f3a9b328)
[Step4: Jest(StubとMockとSpy)](https://qiita.com/koji0705/items/191a48e51b9eebb81db1)


## ソースコード

https://github.com/kouji0705/jest_ts

```shell:ディレクトリ
~/develop/react/jest_ts$ tree -I node_modules 
.
├── jest.config.js
├── package.json
├── src
│   ├── __tests__
│   │   └── sum.test.ts
│   └── sum.ts
├── tsconfig.json
└── yarn.lock

3 directories, 6 files
```

## 環境構築方法
```shell:環境変数作成
~/develop/react/jest_ts$ yarn init
~/develop/react/jest_ts$ yarn add typescript jest ts-jest @types/jest 
~/develop/react/jest_ts$ npx tsc --init  # tsconfig.json作成
~/develop/react/jest_ts$ npx jest --init  # jest.config.js作成
```
### 環境設定ファイル修正
```ts:tsconfig.json
{
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules"
  ],
  "compilerOptions": {
    "baseUrl": ".", // プロジェクトのルートディレクトリを基準にする
    "paths": {
      "@/*": ["src/*"] // '@' で 'src/' ディレクトリを参照できるように設定
    },
  },
}
```

```js:jest.config.js
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  moduleNameMapper: {
    "^@/(.*)$": "<rootDir>/src/$1"
  },
};

```

:::note info
環境設定ファイルは好みに応じて修正してください。
僕はエイリアスつけたいので、一部修正しています。
:::

## プロダクトコード作成

```ts:src/sum.ts
export const sum = (a: number, b: number): number => {
    return a + b;
  };
```

## テストコード作成
```ts:src/__tests__/sum.test.ts
import { sum } from '@/sum';

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});
```

## テスト実行
```shell:テスト実行
~/develop/react/jest_ts$ yarn test                         
yarn run v1.22.19
$ jest
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
 PASS  src/__tests__/sum.test.ts
  ✓ adds 1 + 2 to equal 3 (1 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.614 s, estimated 1 s
Ran all test suites.
✨  Done in 1.25s.
```
これで実装は完了です。
Google検索結果をAPIで取得する　part1

# 概要
1\. Google検索結果の自動収集を行い、
 競合他社の広告文を抽出する。

 2\.パンダスで表にする

 3\. 分析 手法


# 使用言語
Python

# 使用API
Custom Search API

# ファイル名
Google_searchAPI.ipynb


# 参照ページ
https://developers.google.com/custom-search/v1/overview?hl=ja


# 制作手順

## GCPでプロジェクト作成
コンソールへ移動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/65e2abb8-53ff-1924-83c6-628d167d6494.png)

プロジェクトの一覧をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/a703bb31-6bed-8796-6896-4e8a9bba4bae.png)

新しいプロジェクトを作成するので、
【新しいプロジェクト】を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/7c997838-116d-2ffa-b504-7cc6d4ec837e.png)

任意のプロジェクト名を入力し、作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/a5f95ea6-63c8-868f-08c8-46b9f8c40099.png)

## GCPでプロジェクト作成

①今回設定するプロジェクトを選択
②APIとサービスを選択
③ライブラリを選ぶ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/14eef8fa-7952-dea0-be40-3d3df37c09c6.png)


④使用するAPI名を入れて検索
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/7251e9b7-a9c1-a9d6-3d9d-a9d0986d76ad.png)

＜次のページ＞
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/083dff75-2099-cd16-430c-83b8720740b7.png)
【翻訳】
JSON Custom Search API を使用すると、Google Custom Search からプログラムで検索結果を取得して表示する Web サイトやアプリケーションを開
発できます。この API を使用すると、RESTful リクエストを使用して、Web 検索または画像検索の結果を JSON 形式で取得できます。

⑤有効にするをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/ea86941b-fd02-3e2a-d1e3-d93f9d130000.png)

⑥サイドナビ左上の、【有効なAPIとサービス（ダッシュボード）】をクリック
画面下のAPIリスト一覧で、【Custom Search API】をあることを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/d145eefc-48e1-61e3-b57f-d0128baac10f.png)


⑦APIキーを作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/0da34103-f97e-a89e-fd19-9bee8c34f39a.png)
くるくる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/234fa951-2f1b-4d8c-5629-7f0a898733db.png)

⑧APIキーを作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/46dfcdaa-5a96-4cb7-8c4c-a270abd83345.png)


8
念のためにアクセス制限をするのがおすすめ
操作＞三点リーダー＞APIキーを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/bbff1eb3-2fcc-5f5a-5db9-7e0161db3fb7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/e907586b-f785-f923-73b0-c28e8bcbcf43.png)

９．APIが」利用するGoogleカスタム検索エンジンを作成して、検索エンジンのIDを取得する。

 Programmable Searchにアクセス
https://programmablesearchengine.google.com/controlpanel/all

中央の【追加】より検索エンジンを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/9a751f08-fa22-1d91-9966-50df065e5aaa.png)

検索エンジンの詳細を決める。
青＞任意
赤＞必須。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/7c6a89ed-aad2-4aea-a83a-f7c9d1463aae.png)

検索エンジン完成！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557220/5c37cf74-39a8-5f69-d1be-4da2adf97746.png)

10　検索エンジンIDは
概要＞ページ　で確認が可能。


このカスタムサーチエンジンに設定した検索結果が、APIで取得する検索結果になります。
その際に検索エンジんIDを取得します。
AWS WAF の CrossSiteScripting_BODY ルールでバイナリデータを格納したリクエストがブロックされる

# はじめに
Amazon API Gateway の REST API に、AWS WAF のコアルールセット(CRS)マネージドルールグループを設定しています。

リクエストボディにバイナリデータを格納してこの API をリクエストすると、コアルールセット(CRS)マネージドルールグループに含まれる``CrossSiteScripting_BODY``ルールでリクエストがブロックされることがありました。

なぜバイナリデータでクロスサイトスクリプティング？と疑問に思い、色々調べてわかったことをまとめます。

# コアルールセット(CRS)マネージドルールグループとは
一般的な Web アプリに必要になるであろうファイアウォールのルールを、ひとまとめにしてくれている AWS WAF のマネージドルールグループです。

[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/aws-managed-rule-groups-baseline.html#aws-managed-rule-groups-baseline-crs)には「すべての AWS WAF ユースケースでこのルールグループを使用することを検討してください」と記載されており、AWS WAF を使う場合はとりあえずこのルールグループを設定しておくと良さそうです。

今回はリージョン Web ACL に本ルールグループを設定しています。

# CrossSiteScripting_BODY ルールとは
[AWS WAF クロスサイトスクリプティング攻撃ルールステートメント](https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/waf-rule-statement-type-xss-match.html)を用いて、リクエストボディに一般的なクロスサイトスクリプティングパターンが含まれていないかを検査するルールです。

リージョン Web ACL の場合、[検査の対象はリクエストボディに格納されたデータの先頭から 8KB 分のみ](https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/waf-oversize-request-components.html)になります。

# なぜブロックされたのか
[AWS re:Post](https://repost.aws/ja/knowledge-center/waf-upload-blocked-files) に答えがありました。

要約すると「ファイルや画像（バイナリデータ）のメタデータに含まれるランダムな文字列は、SQLインジェクションやクロスサイトスクリプティングの攻撃に含まれる文字列と類似しているため、WAF で誤検出されることがある」とのことです。

# どう対応したか
今回構築する Web アプリではクロスサイトスクリプティング攻撃によるリスクは無いと判断したので、``CrossSiteScripting_BODY``ルールの設定を``Block`` → ``Count``に上書きすることで対応しました。

また、コアルールセット(CRS)マネージドルールグループに含まれる``GenericLFI_BODY``ルールについても、同様の問題を引き起こしそうなので、同様の対応としました。
Ubuntu で Eigen-3.4.0 を CMake から利用する。 

 find_package() によって 線型代数ライブラリ Eigen ([https://eigen.tuxfamily.org/](https://eigen.tuxfamily.org)) を利用するやり方を報告します。プログラムを CMake でビルドするときに Eigen を検出させることができます。
 
なお、古いバージョンでよければ
```
$ sudo apt install libeigen3-dev
```
で使用できるようになりますが、最新バージョンは使えません。

 # ディレクトリ構成

ライブラリとそのソースは ~/dev にいれることにします。これは任意の場所に変更することができます。
```
~/dev/
├── eigen3
    ├── include
├── make
    ├── eigen-3.4.0
        ├── build
```
* ソースコードは ~/dev/make/eigen-3.4.0 にダウンロードします。
* ~/dev/eigen3 にビルドしたライブラリがインストールされます。
* インストール後、 ~/dev/make/eigen-3.4.0 は削除できます。

```~/.bashrc``` の最後に以下の内容のいずれかを追加する。
```sh
export CMAKE_PREFIX_PATH=$HOME/dev:$CMAKE_PREFIX_PATH
```
もしくは
```sh
export Eigen3_DIR=$HOME/dev
```
設定を反映させるために、端末（Terminal）を一旦閉じて開き直してください。

# Eigen のインストール
ディレクトリ ```~/dev/make``` がなければ作成し、端末（Terminal）で以下を実行する。
```console
$ cd ~/dev/make
$ git clone --depth 1 https://gitlab.com/libeigen/eigen -b 3.4.0 eigen-3.4.0
$ cd eigen-3.4.0
$ mkdir build
$ cd build
$ cmake -DCMAKE_INSTALL_PREFIX=$HOME/dev/eigen3 ..
$ make install
```
*  Eigen はヘッダオンリーライブラリなので configuration (Release/Debug) の指定は必要ない。


# ライブラリの使用方法
簡単な例で使い方を説明する。作業用の適当なディレクトリを用意して、以下の内容で ```test.cpp``` と ```CMakeLists.txt``` を作成する。
```test.cpp
#include <iostream>

#include <Eigen/Dense>
namespace ei = Eigen;
int main()
{
  ei::Matrix3d A{{1,1,1}, {0,1,1}, {0,0,1}};
  std::cout << A << std::endl;
  std::cout << A*A << std::endl;

  return 0;
}
```
```CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(test_eigen CXX)
set(CMAKE_CXX_STANDARD 14)

find_package(Eigen3 REQUIRED)
message(STATUS "Found Eigen-" ${EIGEN3_VERSION_STRING})

add_executable(test test.cpp)
target_link_libraries(test Eigen3::Eigen)
```
端末（Terminal）から
```console
$ mkdir build
$ cd build
$ cmake ..
$ make 
$ ./test
```
として実行できる。
[k8s] 自己署名証明書でkubernetesのIngressのTLS設定をしてみた

## はじめに
前回はfluxの通知がslackに流れるように設定を行いました。

https://qiita.com/piny940/items/88dedb16585671b6352b

今回は自己署名証明書を用いてingressのTLS設定を行なっていこうと思います。

## 手順

秘密鍵を作成
```
$ openssl genpkey -algorithm ed25519 -out priv.key
```

自己署名証明書を作成
```
$ openssl req -x509 -days 3650 -new -key priv.key -out server.crt
```

Secretを作成

```
kubectl create secret tls cluster-tls --key priv.key --cert server.crt
```

Ingressの`spec.tls`を次のように記述
```
...
kind: Ingress
spec:
  tls:
    - hosts:
        - www.example.com
      secretName: cluster-tls
...
```

これで自己署名証明書を用いたTLS通信ができるようになりました。

`kubectl get ingress`でHTTPSができるようになっていることを確認します。
```
$ kubectl get ingress
NAME                CLASS   HOSTS                     ADDRESS         PORTS     AGE
app-ingress      nginx   www.example.com        192.168.11.61   80, 443   35h
```

## 参考資料

https://qiita.com/cffnpwr/items/09995c5b19b01d7f1092

https://zenn.dev/vampire_yuta/articles/30bda4332f78c5

https://pebble8888.hatenablog.com/entry/2019/04/30/211832

https://www.openssl.org/docs/man3.0/man1/openssl-genpkey.html

https://www.openssl.org/docs/man3.0/man1/openssl-req.html

https://stackoverflow.com/questions/75358381/failed-to-create-secret-post-http-localhost8080-api-v1-namespaces-keycloak-t

https://stackoverflow.com/questions/46360361/invalid-x509-certificate-for-kubernetes-master

https://developers.cloudflare.com/ssl/origin-configuration/origin-ca

https://a.nel.cloudflare.com/report/v3?s=x%2FfpYTzbje2VANAx2u4iCo%2Bny4pCe2cMik43NgNI0HTL5oOzvgJtDx3OQub7%2FNDAqxQJmfL8TlavNDkgVDWX4D%2BkxhBSdIVn4r61uFvuQ1o%2B%2FhAUXLFGj7utRfgrC0p%2BlT2BN8l4Sgl%2F%2BkSj%2FYagvmtw6cqyiw%3D%3D

https://a.nel.cloudflare.com/report/v3?s=x%2FfpYTzbje2VANAx2u4iCo%2Bny4pCe2cMik43NgNI0HTL5oOzvgJtDx3OQub7%2FNDAqxQJmfL8TlavNDkgVDWX4D%2BkxhBSdIVn4r61uFvuQ1o%2B%2FhAUXLFGj7utRfgrC0p%2BlT2BN8l4Sgl%2F%2BkSj%2FYagvmtw6cqyiw%3D%3D
自動車エンジニアリングと仮想環境

自動運転、電気自動車、テスラ・BYDなどの勢い、100年に一度の革命期といわれる自動車業界。

その根幹を担っているのは自動車のITシステムです。
今回は自動車×ITという大テーマの中から「自動車エンジニアリングと仮想環境」についてお伝えできればと思います。

<li>①自動車エンジニアリングにおける「V字プロセス」</li><br>
<li>②「自動車ITエンジニア」はどんな仕事をしているの？</li>

<h2>①自動車エンジニアリングにおける「V字プロセス」<p>

![IMG_1562.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3626033/21debdb9-9e8e-7045-cacc-5a4227a381e9.jpeg)

自動車を作るためにもITシステム同様に「要件定義→基本設計→詳細設計→実装→結合試験→総合試験」があるのですが、画像にあるV字プロセスというやり方をします。

1. 車両設計（どんな車を作りたいか、車両一台の仕様を設計）
2. システム設計（その車を実現するために、エンジンやシャシーなどシステムレベルの仕様を設計）
3. ユニット設計（サブシステムともいいます、システム下のユニットの仕様を設計）
4. 部品設計（最後にそのユニットを実現するための部品の仕様を設計）

その後に試作品を作成し、部品検証→ユニット検証→システム検証→車両検証と、具体から抽象へ検証していきます。

また一気通関ではなく、部品だけを何度も設計・検証したり、部品とユニットを設計・検証したりもします。

この具体から抽象、抽象から具体、そしてループで設計検証するこの工程をV字プロセスと呼んだりしていて、現在はこのプロセスのほとんどを仮想環境で行なっています。


<h2>②「自動車ITエンジニア」はどんな仕事をしているの？<p>
私は業務で自動車のコンピュータ部分である「ECU（Electric Control Unit）」を扱っています。
自動車にはこのECUが車内外の至る所についていて、様々な情報のやり取りをしています。

例えば、「車に鍵を持って近づくと施錠が解除される」という機能を実現したいとします。
その時にはこういった条件が必要になるでしょう。
　1. その車のエンジンが停止していること
　2. その車が停止状態（0.0km/h）であること
　3. その車が施錠されている状態であること
　4. その車のドアが閉まっていること
　5. その鍵がその車の本物の鍵であること
など、これ以外にもたくさんの条件が揃っていないと安全な機能とは言えません。

これらの情報をやり取りするのがECU間ネットワークです。

例えば、1. その車のエンジンが停止状態であることは
エンジンがオフになっていてエンジンの回転数がゼロであるという情報を
エンジン系のECUが集めてきて、ドア施錠系のECUへ正常に伝達できれば条件達成です。

私はこの情報伝達（ECU間のコミュニケーション）を各ECU担当やシステム担当の仕様をもとに専用ツールの仮想環境で作成しています。もう少し言うと、仮想環境でECU間の信号（例えば、00 = Power OFF, 01 = Power ON[50%], 10 = Power ON[100%], 11 = Not available）のように2進数か16進数で作成していきます。

業務の秘匿性が高く一般的なことしかお伝えができないのですが、みなさんが日常的に使っているであろう自動車はこのように複雑なシステムであり、多くの人々の苦労によって作られていることが少しでも伝われば幸いです！
【ChatGPT有＋DALL-E3】で人物の向きをどう指定すればいいのでしょうか。

  
　どうも、カーブミラーです。

　今回は、人物の顔の向きをどう指定すればいいのか、に挑戦です。

:::note info
本記事は、ChatGPT（有料版）
＋DALL-E3で行なっております。
あしからず。
:::
　本題に行く前に。

　ニュース集め、
　　どうしていますか？

　いちいち、どこかの
　　ニュースサイトにアクセスして、
　　　そこで見ているかも
　　　　しれませんね。

　でも自分の欲しいニュースが
　　あるとは限りません。

　また、ほかのニュースが
　　煩わしい場合も
　　　多々ありますよね。

　そこで、
　　Googleアラートを設定して、
　　　欲しいニュースだけを
　　　　自動で集めましょう。

　Googleで「Googleアラート」を
　　検索してください。

　操作方法は、
　　簡単です。

　検索窓に、
　　知りたい情報の
　　　キーワードを入れて、
　　　　その下の
　　　　　“オプションを表示”で
　　　　　　必要な設定をして
　　　　　　　“アラートを作成”で
　　　　　　　　終了です。

　YouTuberかわごんさんが
　　動画をアップしていますので
　　　そちらを参照してください。
[【お役立ち】Googleアラートの効率的に情報収集：設定方法や使い方を解説します！](https://youtu.be/BMJsuWchLmw?si=TL82_h9EZ_DUftxC)
　
　あっ、それから
　　かわごんさんが、
　　　コンテストを開催しています。
[【第２弾】生成AIコンテスト募集開始!!生成おっさんはやらないよー！](https://youtu.be/wL1uacltJoc?si=rMierP_fVpWl8Q9y)

　こちらは、
　　四枚の画像と
　　　それのストーリー、
　　　　そのストーリーを出した
　　　　　生成AIとのやり取りを
　　　　　　スクショでOKなので
　　　　　　　提出するものです。

　詳しくは、
　　動画をごらんください。

　賞金は、
　　合計一万円。
　　　それを五人に、とのこと。

　私も考えて、
　　応募します。
***
　さて、本題です。

　DALL-E3で
　　人物の向きを
　　　どう指定すれば
　　　　いいのでしょうか？

　“横顔”とかだと、
　　45度や80度？に
　　　なりやすいです。

　そこで
　　ChatGPTさんに
　　　尋ねました。

　そうしたら
　　このような回答。
***
***ChatGPT***
真横からの横顔を描画する際には、以下のような指示が役立ちます：

1. **角度の明確化**: 「完全なサイドビュー」というフレーズを使用して、顔が真横から見えるように依頼します。これは、被写体の耳がはっきりと見え、鼻やあごのラインがサイドビューに特有な方法で描かれることを意味します。

2. **特徴の強調**: 「鼻、口、あごのラインがはっきりと描かれた、明瞭なサイドプロファイル」と指定することで、横顔の特徴がより鮮明に表現されるように依頼できます。

3. **顔の向きの指定**: 「顔はカメラ/視点に向かず、完全にサイドに向いている」と指定することで、正確なサイドビューが保証されます。

これらの指示を用いて、より正確なサイドビューの描画を依頼することができます。
***
　ふむふむ。
　　「完全なサイドビュー」という
　　　フレーズねぇ。

　どれどれ……。

“18歳日本人女性の右側の完全なサイドビューを描画してください。”
![DALL·E 2023-12-30 11.49.43 - An 18-year-old Japanese woman, viewed in a complete right side profile. The focus is on a clear side view showing her nose, mouth, and chin lines dist.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/e1bef97f-6271-aacd-bcbe-4626f3b605a2.png)

“同じ女性の、同じ瞬間の、左側の完全なサイドビューを描画してください。”
![DALL·E 2023-12-30 11.49.50 - An 18-year-old Japanese woman, viewed in a complete left side profile at the same moment as the previous image. The focus is on a clear side view show.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/12567aea-fa87-fa85-b4f1-f5456739b8fe.png)

　おお、うまくいった！

　ちなみに、
　　“同じ女性の”は
　　　書き入れないと
　　　　別の女性になります。
　　“同じ瞬間の”は
　　　書き入れないと
　　　　服装や髪型なんかが
　　　　　変わってしまいます。

　「完全なサイドビュー」か。
　　なんかメモしておかないと
　　　忘れそうだなw

　ということで、
　　今回は、ここまで。
フロントエンド開発のためのテスト入門まとめ 第３章

## 第３章

### 非同期処理のテスト

#### resolveする関数のテスト

```js
// resolveする関数
export function wait(duration: number) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(duration);
    }, duration);
  });
}


test("指定時間待つと、経過時間をもってresolveされる", async () => {
  expect(await wait(50)).toBe(50);
});

```

#### 注目点
1. テストする関数のresolveで返り値を返すようにする
1. async関数にする
1. expect内でawaitする

#### rejectする関数のテスト

```js
// rejectする関数
export function timeout(duration: number) {
  return new Promise((_, reject) => {
    setTimeout(() => {
      reject(duration);
    }, duration);
  });
}

test("指定時間待つと、経過時間をもってrejectされる", async () => {
  expect.assertions(1); // アサーションが1度実行されることを期待する
  try {
    await timeout(50); 
    // アサーションが1度も実行されないまま終了したらテストは失敗する 
  } catch (err) {
    expect(err).toBe(50);
  }
});

```

#### 注目点
1. テストする関数のrejectで返り値を返すようにする
1. async関数にする
1. try, catchで囲む
1. expect.assertionsを使用してアサーションが実行されることをテストする
--dart-define-from-fileでFirebase Test Lab

## 環境
- M2 Mac mini
    - macOS 13.5
- Android Studio Giraffe
- Xcode 15.0.1
- Flutter 3.13.9

## はじめに
最近Mac miniを購入して、Flutterで新しいアプリを作成しました。環境依存部は`--dart-define-from-file`で実装したのですが、Firebase Test Labで動かすのに色々と苦労したので記事にします。
尚、ここでは Integration Test を作成してローカル環境での実行まではできているものとします。

## Android インストルメンテーションテスト
[Flutter との統合テスト](https://firebase.google.com/docs/test-lab/flutter/integration-testing-with-flutter?hl=ja)の「Androidの設定」を行います。リンク先のページに`gradlew`で`--dart-define`を使用する場合の説明も書かれており、`key=value`をbase64エンコードした値をカンマ区切りで`-Pdart-defines`オプションに渡せば良いことが分かります。ですが、環境変数を一つずつbase64エンコードしていくのは大変なので、下記のコマンドを実行します。
```sh
flutter build apk --dart-define-from-file=dart_defines.json --verbose | grep gradlew
```
すると、Flutterでビルドする時に`gradlew`を実行しているコマンドが表示され、`-Pdart-defines`を渡していることが分かります。これをコピペして下記のように`gradlew`コマンドを実行してみます。
```sh
./gradlew app:assembleAndroidTest -Pdart-defines="***,[...]"
```
ここでもし`build.gradle`内で環境変数を使用していると、`Could not get unknown property '{環境変数名}'`のようなエラーが表示されると思います。先ほどの`flutter build`コマンドの結果を見てもらうと分かるのですが、`-Pdart-defines`とは別に各環境変数の生値もオプションとして`gradlew`コマンドに渡しており、`build.gradle`内ではそちらの値を参照しているようです。そのため、`gradlew`コマンドに渡すオプションは下記のようになります。
```sh
./gradlew app:assembleAndroidTest -Pdart-defines="***,[...]" -Pkey1=value1 [...]
```
これで作成されたapp用のapkファイルとtest用のapkファイルを Test Lab にアップロードすればインストルメンテーションテストが実行できます。

## iOS XCTest
[Flutter との統合テスト](https://firebase.google.com/docs/test-lab/flutter/integration-testing-with-flutter?hl=ja)の「iOSの設定」を行います。こちらには`--dart-define`を使用する場合の説明が書かれていませんが、リンク先のページに提示されているスクリプトの`flutter build`コマンド実行時に`--dart-define-from-file`を指定すれば環境変数を取り込めます。尚、スクリプト内で定義している`dev_target`にはXcodeにインストールされている最新の iOS Deployment target のバージョンを指定する必要があるようです。（不明な場合はスクリプトを実行した後に`build/ios_integ/Build/Products`ディレクトリ内の`Runner_iphoneos{dev_target}-arm64.xctestrun`ファイルを確認してください。）
これで作成されたzipファイルを Test Lab にアップロードすれば XCTest が実行できるのですが、Integration Testで`tester.enterText`を実行している場合には注意が必要です。

https://stackoverflow.com/questions/71038404/integration-test-entertext-method-not-working-on-profile-or-release-mode

上の記事によると、`Profile`または`Release`モードで作成された Integration Test では`tester.enterText`が機能しないとのことです。これを回避するには Integration Test を下記のように修正します。
```dart
// IntegrationTestWidgetsFlutterBinding.ensureInitialized();
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
binding.testTextInput.register();
```
ただし、この修正を行うと、テストを実行している間はキー入力を受け付けなくなるため、注意してください。

## さいごに
Test Labで動かすまでは大変でしたが、一度動けば手軽に色々な実機でテストができる恩恵は大きいです。この記事が誰かの役に立てば幸いです。
micro:bitの電源についての調査・非常時に電池を使う仕組み

## 作りたいもの
「災害時に使える自動であかりがつく懐中電灯」を作ろうと考え、まずはmicro:bitの電源についての調査をしました。

## 電源について
micro:bitは、microUSBの端子、PHコネクタ(電池用)、本体下部の端子からの給電が可能ですが、今回の災害用懐中電灯は下記をイメージしています。

通常時：microUSBの端子から給電(ACなどから給電)
非常時：停電などでmicroUSBの端子から給電されなくなった際に電池を使う

## 実験
電池とmicro:bitを接続しておき、microUSBの端子からの給電の有無でPHコネクタ(電池)に流れる電流を調査

実験結果1)電池のみからの給電の場合：25mAがPHコネクタ(電池)から給電

実験結果2)microUSBの端子から給電＋電池の場合：2.5mAがPHコネクタ(電池)から給電

## 結論
PHコネクタ(電池)から流れる電流は減ったもののゼロにはなっておらず、このままの構成で利用した場合はいざ災害時には電池切れとなってしまう。