OmniAICreator/Qiita-1.07M huggingface dataset:
PHP+PostgreSQLから読み解くトランザクション制御

# 始めに
こんにちは。新人エンジニアの打越です。
現場に配属されて2か月。現在は、主にPHPを業務の中で学んでおります。まだ配属されて間もないこの2か月の間、プログラムの仕組みをイメージすることに何度も苦戦しました。その中でも、苦戦したこと…「トランザクション制御」について今回は記事にしました。
 
# トランザクション制御とは
## トランザクション制御について調査してみた感想
私の感想「なにそれ、、、おいしいの？」
決して説明が悪いわけではありません。新人エンジニアの私は、イメージができなかったのです。調査を繰り返しても、様々な情報で溢れ、頭が混乱してしまいました。
そんな私は、現場で使われているPHP+PostgreSQLのコードを読み進めることでイメージできるようになりました。なので、一つ一つのコードで何を処理しているのか確認しながら、トランザクション制御についてイメージしていきましょう。
PHP+PostgreSQLが分からない方も安心してください。今回は、トランザクション制御がイメージできるようになることが目的です。

# PHP+PostgreSQLのコードからトランザクション制御を読み解く
## トランザクション制御とは一連の流れを表す
「begin」から行っている処理の途中で、トラブルが発生した場合、「rollback」で「begin」の前の状態に戻る。正常に処理が進んだ場合、「commit」で「begin」から行っている処理を確定する。
この一連の流れをトランザクション制御といいます。この流れをコードを見ながら理解していきましょう。
## トランザクション制御を行っているPHP+PostgreSQLのコード
今回は、以下の手順で処理をする想定でトランザクションの確認をしようと思います。
データを削除する
データを追加する
なお、SQLのinsert文とdelete文は処理内容を省略しております。(insert …,delete…という文にしております)
```php
<?php
$conn = pg_pconnect("dbname=publisher");//”publisher”という名前のデータベースに接続する
if (!$conn) {
  echo "An error occurred.";
  exit;
}//接続に失敗した場合、 "An error occurred."と表示する
 
pg_query($conn,"begin");//トランザクション開始する
$result = pg_query($conn,"delete ...");//delete...を実行する
if(!$result){
    pg_query($conn,"rollback");
    pg_close($conn);
    exit;
}//トランザクションが失敗した場合、トランザクション開始直前の状態に戻る
 
$result = pg_query($conn,"insert ...");//insert...を実行する
if(!$result){
    pg_query($conn,"rollback");
    pg_close($conn);
    exit;
}//トランザクションが失敗した場合、トランザクション開始直前の状態に戻る
 
pg_query($db->conn,"commit");//トランザクションを確定する
pg_freeResult($result);
pg_close($conn);//データベースとの接続を切断する
 
?> 
```
# 最後に
今回は、トランザクション制御についてPHP+PostgreSQLのコードの流れに沿って学んでいきました。
日々目まぐるしいほどインプットされるIT用語たち。理解する方法はたくさんあります。
自分に合った理解の仕方を一緒に探していきましょう！

# 参考
[トランザクション制御｜KENスクールブログ](```)
[PHP:Postgre関数 - Manual](```)
[データの取得(SELECT) - Postgreへの接続 - PHP入門](https://www.javadrive.jp/php/postgresql/index5.html)
Unity コマンドラインからプロジェクトのUnityバージョンを取得する

# 導入
CIツールを使用する時など、コマンドラインからUnityを実行したいことがあります。
例えばMac・Unity Hub経由でインストールすると以下のパスに実行ファイルが存在します。
```bash
/Applications/Unity/Hub/Editor/2021.1.20f1/Unity.app/Contents/MacOS/Unity
```
このパスの中にある`2021.1.20f1`というバージョンはプロジェクトによって異なりますから、
できれば決め打ちではなく、自動的に取得したいです。

# コマンドライン経由でのバージョン取得
バージョン情報はプロジェクトディレクトリから見て
```
./ProjectSettings/ProjectVersion.txt
```
のファイル内に存在し
```yaml:ProjectVersion.txt
m_EditorVersion: 2021.1.20f1
m_EditorVersionWithRevision: 2021.1.20f1 (be552157821d)
```
という形で記載されています。ですので、

```bash
cat ProjectSettings/ProjectVersion.txt | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+[a-z]{1}[0-9]+' | head -1
```
というコマンドでバージョンを取得することができます。

さらにこれを利用することで、Unity実行パスを以下で取得することができます
```bash
UNITY_VERSION=$(cat ProjectSettings/ProjectVersion.txt | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+[a-z]{1}[0-9]+' | head -1)
UNITY_PATH=/Applications/Unity/Hub/Editor/${UNITY_VERSION}/Unity.app/Contents/MacOS/Unity
```
react 忘却録　＃1

本投稿はプログラミング初心者の忘却録を兼ねた勉強の一部です。
問題点、ミスなどがありました。時に厳しく時に優しくご教示いただけると大変助かります。
（割合は厳しさ２：優しさ８でお願いします）

# Reactを使ってみたい
そもそも画面に描画する時にはHTMLの　_ドキュメント言語_　に変換しなくては描画することはできません。
また、ReactはもともとJavaScriptのためJavaScript→HTMLのドキュメントに変換する作業が発生します。
その際に使用するのが　_React.createElement_　と言われています。

```React.createElement
React.createElement(
  'button',
  {className: 'btn-blue'},
  'Click me!'
)
```
と記述すると'btn-blue'のクラスを持った'button'が作られ、中には'Click me!'が入っています。

面倒ですね...。

# JSX...?
そこで使用されるのがJSXというものになります。
JSXとはJavaScriptの _拡張言語_ になります。
Java Scriptというプログラミング言語とHTMLというドキュメント言語を同時に使えるようにしたものになります。
また、JSXを使って上の記述と同じ意味の記述をすると
```
<button className={'btn-blue'}>
 Click me!
</button>
```
こうなり、HTMLに近い（HTMLライク）な記述になります。
こっちの方が記述量が少なくて楽ですね。
AWS SDK for PHP: DynamoDB だけ? リトライを 10 回する件

参考) [retries - AWS SDK for PHP](https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_configuration.html#config-retries)

## 概要

リファレンス上リトライのデフォルトは以下のとおり(のはず)だが、DynamoDB のときだけ(?) 10 回リトライしている。

- retry_mode: legacy
- max_attempts: 3

## 例

### DynamoDB (リトライ未指定)

```php
$ddbClient = new Aws\DynamoDb\DynamoDbClient([
    'region' => 'ap-northeast-1',
    'version' => '2012-08-10',
    'endpoint' => 'http://192.168.1.1',  // 応答なし
    'http' => [
        'connect_timeout' => 3,
    ],
]);
$res = $ddbClient->query($params);
```

→10 回リトライ (計 11 回試行) してエラー。

### DynamoDB (リトライ指定)

```php
$ddbClient = new Aws\DynamoDb\DynamoDbClient([
    'region' => 'ap-northeast-1',
    'version' => '2012-08-10',
    'endpoint' => 'http://192.168.1.1',  // 応答なし
    'http' => [
        'connect_timeout' => 3,
    ],
    'retries' => [
        'mode' => 'legacy',
        'max_attempts' => 3,
    ],
]);
$res = $ddbClient->query($params);
```

→リトライ 3 回 (計 4 回試行) してエラー。

## 推測

上記のようにリトライを明示的に指定したところ、まれに InternalServerError で失敗する現象が発生するようになった。AWS のサポートに問いあわせたところ、「内部的なフェールオーバーやスケーリングなどがサービス側で自動でおこなわれ、InternalServerError が発生する場合がある」とのこと。特に legacy リトライモードではリトライ間隔が(観測した限りでは)徐々に間隔を空けていくエクスポネンシャルバックオフっぽい挙動であるものの、リトライ 3 回ではその間隔が非常に短いため、リトライで回収しきれず結果エラーとなってしまっている気がする。そのための 10 回リトライ? (あくまで推測です!)

## 結論

standard リトライモードを使いましょう。
Python3でRM mini3をコントロール


以前はBlackBeanControlなどにPython2が必要だったのが、
Python3だけで使えるようになったのでセットアップメモ

# 環境
Ubuntu 22.04
Python 3.10.4
RM mini 3

Raspberry Piでも確認
　Kernel version: 5.15
　Debian version: 11 (bullseye)
　Python 3.9.2

# 前提
既にRM mini 3がネットワークに繋がっていること。


# python-broadlinkインストール

pipでpython-broadlinkをインストール

```bash
sudo apt install git pip
pip3 install broadlink
```


必須ではないがテスト用にcliを取ってくる

```bash
cd
git clone https://github.com/mjg59/python-broadlink.git
cd python-broadlink/cli
```

#### 動作確認
こんな感じでRMMINIが見つかればOKです。

```bash
$ ./broadlink_discovery
Discovering...
###########################################
RMMINI
# broadlink_cli --type 0x2737 --host 192.168.0.xxx --mac 34ea34xxxxxx
Device file data (to be used with --device @filename in broadlink_cli) :
0x2737 192.168.0.xxx 34ea34xxxxxx
```


# BlackBeanControlインストール
gitに書いている方法そのまま

```bash
cd
git clone https://github.com/TheGU/rm3_mini_controller.git
cd rm3_mini_controller
pip install -r requirements.txt
```

#### 動作確認
こちらも同じくDeviceが見つかればOKです。

```bash
$ python3 test_run.py
Scanning network for Broadlink devices (5s timeout) ...
Found 1 broadlink device(s)
Device 1:
IPAddress = 192.168.0.xxx
Port = 80
MACAddress = 34:ea:34:xx:xx:xx
enter_learning (5s timeout) please press any key on remote to test

Check data
RM3 not receive any remote command
```

#### 設定
上記のDevice情報を元に、iniファイルを修正する
・IPAddress、MACAddressを追記

```bash
vim BlackBeanControl.ini

[General]
IPAddress = 192.168.0.xxx
Port = 80
MACAddress = 34:ea:34:xx:xx:xx
Timeout = 3

[Commands]
```


# リモコンの登録とテスト

```bash
python3 BlackBeanControl.py -c test_comm
※ここで登録したいリモコンのボタンを押す
※RM mini3が反応すると、commandがセットされる。
b"&\x00P\x00\x00\x01'\x92\x13\x12\x146\x13\x12\x14\x12\x13\x12\x13\x12\x14\x11\x146\x146\x13\x12\x146\x137\x13\x12\x137\x136\x14\x12\x13\x12\x137\x13\x12\x137\x136\x14\x12\x13\x12\x137\x136\x14\x12\x136\x14\x12\x13\x12\x137\x136\x14\x12\x13\x00\x05<\x00\x01'I\x14\x00\r\x05\x00\x00\x00\x00\x00\x00\x00\x00"
2600500000012792131214361312141213121312141114361436131214361337131213371336141213121337131213371336141213121337133614121336141213121337133614121300053c0001274914000d050000000000000000
Set command test_comm
```
もう一度同じコマンドで、RM mini3から登録したcommand信号が送信される。
```bash
python3 BlackBeanControl.py -c test_comm
```
登録したcommandは、iniファイル内の[Commands]に登録される。
```
$ cat BlackBeanControl.ini
[General]
IPAddress = 192.168.0.xxx
Port = 80
MACAddress = 34:ea:34:xx:xx:xx
Timeout = 3

[Commands]
test_comm = 2600500000012792131214361312141213121312141114361436131214361337131213371336141213121337131213371336141213121337133614121336141213121337133614121300053c0001274914000d050000000000000000
```
#### コマンドについて
``
test_comm = 26005000000～
``
新しいリモコンのコマンドを登録するには、
上記のように手持ちのリモコンを使って登録する方法と、
ネット上のリモコン信号データをもとに、RM mini3用に変換して登録する方法もある。
データの変換方法は[こちらの記事](https://qiita.com/po-te/items/cc7e9b0b8e962af06daf)
https://qiita.com/po-te/items/cc7e9b0b8e962af06daf

## 参考サイト
https://qiita.com/CoTechWorks/items/6b075ae43894d670cba4
https://github.com/mjg59/python-broadlink.git
https://github.com/TheGU/rm3_mini_controller.git
Chart.jsでいろいろ

![filename(9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/c3899ea4-3d04-664f-6bad-446e3c31d864.png)

スマートメーターから拾ったデーターで日ごとの電気の使用量を表示してます。countはスマートメーターへのアクセス回数で、ときどき失敗しているので、確認のため表示してます。10分おきにアクセスしてるので、失敗しないと144回です。

![filename(10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/d8e3335f-27c0-88a3-38fd-3491b06027bc.png)

昨日の電力の1時間おきの使用量です。当日分も表示できます。

![filename(11)(1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/72b71e3d-5ec4-9974-56c3-22c63aa8e701.png)

使用量ごとの時間数を集計してます。

![filename(12).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/fa874717-9af1-c461-143b-b82723f4520e.png)

NTP ST1のntpqした値です。GPSが二台とJJYが二台分のグラフがあります。横軸の時間は全部表示するとうるさいので、抜いてあります。

![filename(13).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/54ba9f3e-be62-9541-4cf6-2681b7bd2768.png)

Ethernet switchのmibのポートごとのインバウンドのバイト数です。RealtekとAtherosのswitchのデータを表示してます。凡例をクリックすると表示・非表示を切り替えられます。

![filename(14).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/fa8d5ecf-566e-8590-2504-fcfdc9e9f29e.png)

PCなどからのDNSのリクエスト数です。

![filename(15).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/b94590ce-cb01-0e86-dfca-f7b6aa6fa29f.png)

気温と湿度です。

![filename(16).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/37650740-a31a-549f-d123-441089552d4e.png)

気圧です。

![filename(17).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/76c1662b-0913-b90e-df10-abd5cf27d04b.png)

照度です。これはデフォルトのベジエ曲線です。

![filename(18).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/452906d0-3f6d-ca0e-9fae-b19cf88ea14f.png)

2週間分の気温の変化です。このデーターは生のデータを毎日計算して、別のDBに移しています。
PythonからSlackに通知

PythonからSlackに通知を投稿。
ものすごく簡単だった。


# 1. WebHookを追加する
Slackの「App」から検索し、「Incoming Webhook」を表示。「追加」をクリック
![WebHook追加.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389667/abf9b2d2-a0c4-76e2-63c4-f5aa06f2a7ac.png)

# 2. 次の画面で「Slackに追加」をクリック
![WebHook追加2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389667/04d1e103-0ec1-326f-641d-be34a732814c.png)

# 3. チャンネルを選択し、Incoming Webhookインテグレーションの追加をクリック
![WebHook追加3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389667/a843f7d2-d171-88c3-01fc-72a4d5382977.png)

# 4. WebhookのURLを取得
メモしておきましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389667/9677ae7e-9120-e840-3eb9-16f62939e7ea.png)

# 5. モジュールをインストール
```bash
$ pip install slackweb
```

# 6. ソースコード書いて実行
これで投稿される
```python:main.py
import slackweb

WEBHOOK = 'メモしたWebHookを記入'
slack = slackweb.Slack(url=WEBHOOK)
slack.notify(text='TEST')
```

# 参考
[3分でPythonでslackに通知を送る方法を徹底解説](http://shimadays.com/2021/05/24/python-slack-notification/)
Youtube API使って得たコメント読み上げさせたい

読み上げてくれればチャット欄見なくていいよねってことで、Youtube APIからライブ配信のコメントをポーリングしつつ、取得したコメントを読み上げさせようとTryしました。

主に処理部分についての話をします

## 要素

### Youtube API（Data API, Live Streaming API）

今回使用するAPIは以下です。いずれもAPIキーで認証します

#### Videos：https://developers.google.com/youtube/v3/docs/videos/list?hl=ja
    
動画IDを引数にデータを取得し、チャットIDを取得します

```ts 

// VideoResponseは省略

export interface IVideoApi{
  list(videoId:string) :Promise<VideoResponse>
}

export class VideoApi implements IVideoApi{
  private readonly key:string

  constructor(key:string){
    this.key = key
  }

  list(videoId:string): Promise<VideoResponse> {
    const config: AxiosRequestConfig = {
      params:{
        part: "liveStreamingDetails",
        id: videoId,
        key:this.key
      }
    }
    return axios.get("https://www.googleapis.com/youtube/v3/videos", config).then(r => r.data)
  }
}
```



#### LiveChatMessages：https://developers.google.com/youtube/v3/live/docs/liveChatMessages/list

チャットIDを引数にコメントを取得します。レスポンスのpageTokenを引数に使用することでコメントをつづきから取得できるので、apiのパラメータは初回/それ以降の２種類にしました。

```ts 

// LiveChatMessagesResponseは省略

export class LiveChatMessagesApi implements ILiveChatMessagesApi{
  private readonly key:string = ""
  constructor(key:string){
    this.key = key
  }

  async startList(liveChatId: string, maxResults: number, nextPageToken: string | null): Promise<LiveChatMessagesResponse> {
    let config: AxiosRequestConfig
    if (nextPageToken === null) {
      config = {
        params:{
          liveChatId,
          part: "id,snippet,authorDetails",
          maxResults,
          key:this.key
        }
      }
    } else {
      config = {
        params:{
          liveChatId,
          part: "id,snippet,authorDetails",
          maxResults,
          key:this.key,
          pageToken:nextPageToken
        }
      }
    }

    const response = await axios.get("https://www.googleapis.com/youtube/v3/liveChat/messages", config)
    return response.data
  }
}
```

### SpeechSynthesis

文字列を読み上げさせる

```ts 
export interface ISpeaker{
  speak(txt:string):void
}

export class Speaker implements ISpeaker{
  // 設計の都合上クラスにしているが、この関数だけで良い
  speak(txt: string): void {
    const synthes = new SpeechSynthesisUtterance(txt)
    synthes.lang = "ja-JP"
    speechSynthesis.speak(synthes)
  }
}
```

## 処理のイメージ 

* 角丸長方形はオブジェクト、長方形は処理 
* 実線は処理の流れ、点線はオブジェクトへの参照
* APIからコメント取得するのと読み上げは非同期ループ

というイメージです

```mermaid 
graph TD;

A[urlから動画ID取得]
B[Videos APIからチャットID取得]
C[LiveChatMessages APIからコメント取得]
D[インターバル]
store(コメントのキュー FIFO)
history(読み上げたものの履歴)
Z[コメント読み上げ]
Y[インターバル]

A-->B
B-->C
C-->D
D--停止するまで繰り返す-->B
C-.登録.->store

Z-.取得.->store
Z-->Y
Y--停止するまで繰り返す-->Z
Z-.登録.->history

```

`読み上げたものの履歴`をUIに表示させればWebアプリとしてはある程度の形になります。(ユーザー名、コメント内容は黄色で伏せてます)

![スクリーンショット 2022-07-28 22.33.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2088399/974c800c-ffaf-759a-c77e-7841d28f9c76.png)
React+MUI+React Hook Formでタグ入力フォームの作り方

## 概要
大変だったのでシェア。

やりたかったかことは、タグ入力で使うフォーム。
オートコンプリート＋テキスト入力＋チップで構成してある。

React Hook Form的には外部ライブラリを使う場合はregisterではなく、controllerを使いましょう。ということだったのだが、デフォルト値のセットがどうやってやるのかよくわからなかったし、なぜかサブミットに値が入らなかった。
コード的には以下でできたよ。

もっといいのあったら教えてー

## コード
```javascript:uniq.jsx
  const [hogehoge, setHogehoge] = useState([]);

  const { control, handleSubmit, setValue, reset } = useForm({
    mode: "onChange",
    defaultValues,
  });

 const defaultValues = useMemo(() => {
    let defaultValue = {
      hogehoge: [],
    };

    if (hogehoge && hogehoge.length) {
      defaultValue.hogehoge = hogehoge;
      setHogehoge(defaultValue.hogehoge);
    }

    return defaultValue;
  }, [hogehoge]);

  useEffect(() => {
    reset(defaultValues);
  }, [defaultValues]);

  return (
      <Controller
        name={props.id}
        control={props.control}
        render={({ field, fieldState }) => (
          <FormControl fullWidth error={fieldState.invalid}>
            <InputLabel id={props.id + "-label"}>{props.label}</InputLabel>
            <Select
              {...field}
              labelId={props.id + "-label"}
              id={props.id}
              multiple
              value={props.value}
              onChange={props.handleOnChange}
              input={<OutlinedInput label={props.id} />}
              renderValue={(selected) => (
                <Box sx={{ display: "flex", flexWrap: "wrap", gap: 0.5 }}>
                  {selected.map((value) => (
                    <Chip key={value} label={value} />
                  ))}
                </Box>
              )}
            >
              {props.selective.map((selective) => (
                <MenuItem key={selective} value={selective}>
                  {selective}
                </MenuItem>
              ))}
            </Select>
            <FormHelperText>{fieldState.error?.message}</FormHelperText>
          </FormControl>
        )}
    )
 
```
Python チュートリアル第４版のそのままでは動かないコードに加筆して解説する試み


Python 3 エンジニア認定基礎試験の公式テキストとして、オライリーのPythonチュートリアル第４版が指定されています。

しかしチュートリアルとはいいつつも完全な初心者が読むにはやや不親切な場所が目立ちます。

特にそっくりそのまま写しても実行できないコードが何の注意書きもなく書かれているのは初心者泣かせです。
なので、私NMRが（自信はありませんが）加筆することで最低限動くコードとしてみようかなと思います。

私自身Python初日かつ、経験は浅いので修正箇所を見つけた場合はなるべくわかりやすく教えていただけると助かります。

また、熟練者から見ると「その言葉遣いは誤解を招く」などあると思います。
そういった表現の訂正も歓迎です。

### 第４章 4-2　P24のfor文

このコードで筆者が言いたいことの意訳。

Pythonを書いている時に「コレクション（リストやセットのこと）に要素を追加、削除したい」ということがあると思います。
例えば100人の顧客リスト「UserListA」の女性だけを削除して、男性だけの「UserListB」を作りたいなどです。
直感的に考えると、UserListAをfor文で直接操作して要素を削除したくなります。

しかしそうするとPythonはエラーを返します。
なぜならPythonでfor文を回すときにはイテレーターという物が内部で動作しています。

イテレーターが動作している時に、内部の要素の数を変えてはいけないからです。

※イテレーターに関するこの説明は正確ではありません。
（私NMRの知識・理解不足です。）

#### 戦略　コピーをかけるのパターン
```Python
# usersは辞書オブジェクトです。
# key:valueの形で値を保存します。
users = {1: 'active', 2: 'inactive'}

# ここでusersをコピーしています。copy()もitems()もPythonで使えるメソッドです。
# メソッドというのはprint()とかです。
# {}内の1: 'active', 2: 'inactive'
# をuser, statusに代入して、最後の要素になるまで繰り返します。
# もしkey:valueは1組なのでif文でstatus（value）の中身が'inactive'
# だった場合のみ、該当するuser(key)を削除するというコードです。

for user, status in users.copy().items():
    if status == 'inactive':
        del users[user]

# 出力内容の確認のため
print(users)
```

```
# 出力結果
{1: 'active'}
```
#### 戦略 新しいコレクションを作るのパターン
```Python

users = {1: 'active', 2: 'inactive'}
active_users = {}

for user, status in users.items():
    if status == 'active':
        active_users[user] = status

print(active_users)

```

```
# 出力結果
{1: 'active'}
```

#### 参考までにPythonチュートリアルの筆者的に直感的でないパターン

```Python
users = {1: 'active', 2: 'inactive'}

for user, status in users.items():
    if status == 'inactive':
        del users[user]

print(users)

```
↑これはイテレーターでエラーになります。
Pythonチュートリアルの筆者はこういったエラーに直面した場合は、先に挙げた２つのコードのように対処してくれたらいいよ！と言ってくれているわけです。
【SQLServer】空文字のデータを挿入したい



### 1.背景

業務中、上司から下記の指示がありました。

上司「一部のカラムには空文字を入れるINSERT文を作成して。」

私（空文字ってどうやるんやろう？）

・・・ついつい方言が出てしまったので、備忘録としてまとめます。


### 2.環境

- windows10 バージョン21H2
- Microsoft SQLServer Management Studio 18.12.1


### 3.準備

今回はhoge_DBというテーブルを作成してみました。

idは自動採番、全カラムにNOT NULLをつけて必ず何かしら入れるように設定しています。

:::note info
NOT NULL制約：NULL（無記入）ではいけない
（→必ずデータが入っていなければならない）
:::

```sql
CREATE TABLE hoge_DB(
auto_id int NOT NULL IDENTITY(1,1), -- id(自動採番) 
title nvarchar(100) NOT NULL, -- タイトル
text nvarchar(200) NOT NULL -- テキスト
);
```

### 4.入れてみた

今回は、titleとtextに空文字を挿入します。

通常だと、`'String'`のようにシングルクォーテーションで囲んで挿入します。
シングルクォーテーションのみでやってみましょう・・・

挿入ができました。

```sql
INSERT INTO hoge_DB(title,text)VALUES('','');
--(1 行処理されました)
```

ちなみにダブルクォーテーションで挿入しようとするとエラーになります。

```sql
INSERT INTO hoge_DB(title,text)VALUES("","");
--オブジェクト名または列名がないか、空です。SELECT INTO ステートメントの場合は、各列に名前が付いていることを確認してください。その他のステートメントの場合は、空の別名を検索してください。"" または [] として定義された別名は許可されません。別名を有効な名前に変更してください。
```
Microsoft SQLServer Management Studioでも挿入ができていることを確認できました。
（空文字なのでわかりづらいですね:sweat_smile:）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689555/56f20ff0-44d8-1c32-f5fc-b49a1a026ffa.png" width=40%>


### 5（おまけ）.NULLと空文字の違い

NULLと空文字は別物です。

:::note info
NULL：データが何もない
空文字：0文字の文字データ
:::


### 6.参考

1.書籍：ミック, SQLゼロからはじめるデータベース操作, 翔泳社, 2016.
2.[SQLにおけるダブルクォーテーションとシングルクォーテーションの使い方](https://style.potepan.com/articles/24875.html)
3.[null / ヌルとは](https://digitor.jp/dictionary/null/)
4.[「NULL」と「空文字」の違い](https://wa3.i-3-i.info/diff290moji.html)


### 7.最後に

NULLと空文字が曖昧だったので理解できました。
読んでいただき、ありがとうございました！
【#42 エンジニア転職学習】GinTutorialのWebApp改造

# はじめに
富山県に住んでいるChikaといいます。
毎日投稿を目標に、バックエンドエンジニア転職に向けた学習内容をアウトプットします。

7月いっぱいまでGoのフレームワークであるGinについて、
学習をしていきます。

バックエンドエンジニアになるまでの学習内容は以前投稿した以下の記事を基にしています。


https://qiita.com/Chika110/items/ef54dddd565a0193ef44

# 本日の学習内容
GinのTutorialで作成したAPIを改造して、簡素なWebアプリを作成しようと思います。
本日はそのための機能・仕様策定、API・タスク整理をしました。

* **アプリ開発タスク整理等　←Topics!!**


# アプリ開発タスク整理等
先述のとおり、Ginのtutorialで作成したalbum APIに機能追加・DB連携等して簡素なWebアプリを作成します。
本日はタスク整理でほとんど終了しましたので、明日より設定したタスクを1つずつ切り分けて実施していきます。

##### 追加する機能等
* APIのPUTとDELETE
* albumデータのDB管理
* ブラウザ上での表示（HTMLから）
* キーワード一致のGET

##### タスク
1. PUTとDELETEのコード記述
1. GORMの基礎学習とMySQLのDBテーブル作成
1. GORMを使用したAPI部分とDBの連携
1. フロントエンド部分のインターフェース作成、Goと連携
1. キーワード一致GET機能の追加、実装

##### 使用している教材はこちら↓


https://go.dev/doc/tutorial/web-service-gin


# おわりに
最後までお読みいただきありがとうございました。
アドバイス・応援コメント等いただけますと幸いです。
20220728学んだこと


・tsxファイルはコンポーネントを返すファイルにつける名前。
 txはコンポーネントを返さないファイルにつける名前。ex)API,type,use~ファイル等

・ファイル構成
 データをとってくるファイル　1個 ex)useLoginStore → APIでデータとってくるところ
 データをコンポーネントで使うための関数をかくファイル　1個　ex) useLogin　→ APIでとってきたデータを使うところ
 コンポーネント → 関数を使うファイル
 とったファイル構成が良い。

　 コンポーネントファイル、indexファイルには関数のロジックが入らない。

・型定義に関して
　　コンポーネントの型定義はコンポーネントに書くべき

・shared>layout>useContainerは画面よりもっと上位にある概念。画面遷移してもレンダリングされない。ログイン画面からホーム画面に移動しても再レンダリングされないので、ここにヘッダーを置けば、ページが切り替わってもレンダリングされなくなる。認証未であればヘッダーを表示しないようにして、ログイン画面だけ、ロジック組めばOK。
Cloud Functionsの関数作成時の構造

# 環境
- python 3.10.4
- Ubuntu 22.04LTS
- gcloud インストール済み

# 構造
関数は、main.py からスタートする決まりになっている。
また、ソース構造は下記の3パターン

```bash:依存関係が不要な場合
.
├── .env.yaml
└── main.py
```

```bash:依存関係がある場合。requirements.txtに依存関係を記述
.
├── .env.yaml
├── main.py
└── requirements.txt
```

```bash:ローカルに依存関係で利用するソースを含める場合
.
├── .env.yaml
├── main.py
└── mylocalpackage/
    ├── __init__.py
    └── myscript.py
```


requirements.txtの内容例。
python3.10 の場合、下記に記述してある依存関係は
CloudFunctionsのデプロイ時に自動でインストールされる。

```text:requirements.txt
click==8.0.3
cloudevents==1.2.0
deprecation==2.1.0
Flask==2.0.2
functions-framework==3.0.0
gunicorn==20.1.0
itsdangerous==2.0.1
Jinja2==3.0.3
MarkupSafe==2.0.1
packaging==21.3
pathtools==0.1.2
pyparsing==3.0.6
setuptools==60.3.1
watchdog==1.0.2
Werkzeug==2.0.2

```

ランタイム環境変数は、.env.yamlで指定。
デプロイ時に、gcloud functions deploy FUNCTION_NAME --env-vars-file .env.yaml　と指定する
```yaml:.env.yaml
 FOO: bar
 BAZ: boo
```
<br>
デプロイの時は、オプションも多いのでスクリプト作っておくと便利。
例えばこんな感じ

```bash:deploy.sh
#!/bin/bash
# オプションrun-service-accountは、--gen2 が指定されたときのみ設定される
gcloud functions deploy 関数名 \
       --project=プロジェクト名 \
       --region=asia-northeast1\
       --runtime=python310 \
       --entry-point=実行開始するPython関数名 \
       --trigger-topic=Pub/Subのトピック名 \
       --env-vars-file=.env.yaml \
       --memory=256MB \
       --service-account=サービスアカウント名 \
       --run-service-account=サービスアカウント名 \
       --timeout=180S 
```

<br>
実行の時は以下のコマンド打つだけ

```bash
$ bash deploy.sh
```

# 参考
[ローカルマシンからのデプロイ](https://cloud.google.com/functions/docs/deploying/filesystem?hl=ja)
[gcloud functions deploy](https://cloud.google.com/sdk/gcloud/reference/functions/deploy?hl=ja#--runtime)
[Cloud Pub/Subトリガー](https://cloud.google.com/functions/docs/calling/pubsub?hl=ja)
【図解】ニューラルネットワークって？Part02【初心者向け】

# YouTubeでも公開中
この記事の内容は動画で見ることもできます！
<iframe width="560" height="315" src="https://www.youtube.com/embed/-aY1Izw72BA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

前回の続きです。

前回は、ニューラルネットワークの基礎を解説しました。
この内容をベースとして、ニューラルネットワークの中の動きについて、もう少し詳しく解説していきます。

内部の動きを理解するために、まず、ニューラルネットワークに入力される画像がどうなっているのかを知っておきましょう。

# 画像の構成要素

![main-nn02 (0-02-15-23).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458623/20d9fc92-a2e1-1a01-eeb7-f7e4920ba878.jpeg)
ニューラルネットワークでは、入力層に数値を入力し、掛け算や足し算、活性化関数の計算を繰り返しながら、数値を運んでいきます。そして、最終的な結果が、出力層に出てきます。このとき、入力層にいれる数値とは、どのような数値でしょうか。画像を分類するニューラルネットワークを作る場合を例にして、入力される画像について、もう少し詳しくみていきましょう。

![main-nn02 (0-03-06-17).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458623/99631f55-4b10-3e64-60c0-ac70c7b5ad88.jpeg)
今回は、分かりやすくするために、シンプルな画像を考えます。これは、数字の「0」を手書きした画像です。画像は 28×28 ピクセルで作られています。1 ピクセルにはそれぞれ、白から黒の色がついていて、それらがたくさん集まることで、1つの画像ができています。

これらの色は、コンピュータ内では「数値」として表されています。白は「1」、黒は「0」として表され、薄くなると、だんだん「1」に近づき、濃くなると「0」に近づきます。この数字を集めることで、1枚の画像を作る事ができます。

![main-nn02 (0-03-35-17).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458623/80ac77e9-ff3e-952a-8361-b599f0d1e1d0.jpeg)
さて、今回はもっとシンプルな画像を考えます。この図は 8×8 の空間に、0, 1, 2, 3, 4, 5, 6, 7, 8, 9 を書いた画像です。この図を数値で表すと、0.0〜1.0の数値の集まりになります。説明の都合上、文字の部分を「0.9」、背景を「0.1」とします。ニューラルネットワークには、このような画像が入力されます。


# ニューラルネットワークの入力と出力

さて、ここからは、実際に画像が入力される場合を考えてみます。ニューラルネットワークの入力と出力に注目しましょう。
![main-nn02 (0-04-31-22).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458623/d5fb0c0f-6b71-b1a6-3527-19c3d32795d0.jpeg)
今回は分かりやすくするために、中間層のないニューラルネットワークにします。入力のニューロンを 64 個、出力のニューロンを 10 個にしました。なぜ、このニューロン数に決めたのでしょうか？

### 入力層の仕組み
![main-nn02 (0-05-04-13).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458623/80fd2ebb-5556-c3af-339c-7889f38b15f8.jpeg)
入力層の 64 個のニューロンは、8×8 の画像を表しています。画像の 64 ピクセルの数字を、入力層の 64 個のニューロンに入れます。つまり、画像の数字が、それぞれ1つずつニューロンへ入っていくという事です。基本的なニューラルネットワークの場合、このように、画像の全画素の数だけ、入力ニューロンを用意します。

### 出力層の仕組み
![main-nn02 (0-05-38-23).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458623/fc844106-a9d9-0988-19f2-a976f87aa8f9.jpeg)
次は出力層に注目します。出力層の 10 個のニューロンは、0〜9 の 10 個の数字を表しています。最終的に、この 10 個のニューロンには、ニューラルネットワーク で計算された結果が入ってきます。出力層では、全てのニューロンに、結果の値が入ってきます。

この 10 個のニューロンで、一番大きな数字のニューロンが、判別結果となります。


# 続きはYouTubeに公開しています！

[![ねこアレルギーのAI](https://storage.googleapis.com/zenn-user-upload/8db674d6a88921e1308143b3.jpg)](https://t.co/4ltE8gzBVv?amp=1)
[ねこアレルギーの AI](https://www.youtube.com/channel/UCbCHn_q5MUAz5ZDNA-wKsug)
続きはYouTubeに公開しています。お時間ある方は覗いていただけると喜びます。
https://www.youtube.com/channel/UCbCHn_q5MUAz5ZDNA-wKsug

Created by NekoAllergy
クラウドなんでもLT会#6

NCDC様の **クラウドなんでもLT会#6** でAWS CDKについて発表させて頂きました。
参加させて頂いた理由はLTの題名を見て内容が面白そうだったからです。実際、参加させて頂いて大変勉強になりました。自分の発表内容(**AWS CDKを触ってみて**)と特に面白かった **AWSとAzureで「サーバレス」が全然違う件** について記載させて頂きます。次回も参加させて頂きたいと思います!!

# 概要

https://ncdc-dev.connpass.com/event/251073/

# AWS CDKを触ってみて
AWS CDKとBaseline Environment on AWS(BLEA)の概要や使用方法を発表させて頂きました。
ALBとFargateを使用した構成を数行で書くことが出来ます。

https://speakerdeck.com/toru_kubota/try-the-aws-cdk

# AWSとAzureで「サーバレス」が全然違う件
使用したことはありませんが、Azure FunctionsといえばAWSのLambdaと同じように使用出来るイメージがありました。Azureのサーバレスのサービスということではあるのですが、使用の際に注意点があるようです。
3種類ある料金プランの内、Lambdaの様に使用した分だけ料金を支払うには「従量課金プラン」を選択する必要があります。大きな注意点は **「従量課金プラン」を選択した場合はVNet統合がサポートされていないという点です。** VNet統合とは仮想ネットワークに繋ぐ機能ということになります。
AWSでいうとこの**Lambdaは使用出来るけどVPCに接続出来ない**ということになります。

公式のドキュメントを調べると各プランごとの制限事項の記載があり**ネットワーク機能**の箇所に記載がありました。

https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-scale#networking-features

AWSを触ることが多いので、どうしてもAWSのイメージで考えてしまいがちになってしますので、他のクラウドサービスを使用する際はしっかり特徴を理解した上で使用していきたいと思います。
linq.jsのforEach,Select備忘録

# linq.js
どうして、orderとかwhereとか使いたくて使ってます。
メンテありがとうございます。

https://github.com/mihaifm/linq

## はまったところ

```tsx
//これだと最後まで実行してくれなかった
Enumerable.from(Ary).forEach(x => x.isSelect = false);

//{}がいる
Enumerable.from(Ary).forEach(x => {x.isSelect = false});
```

なんでか調べてはないけど…
とりあえず備忘録
CO2センサー(MG-812)を買ったので、CO2濃度測ってみた

秋葉原の秋月電子通商さんで以下のCO2センサーを売ってたので、買ってみた。
https://akizukidenshi.com/catalog/g/gK-16446/

ブレッドボードに差して、arduinoにつなぐ所までは順調。
5VとGNDとA0をそれぞれ繋ぐだけ
<img width="400" alt="arduino" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2709872/7fead2c8-a8c3-7676-a48e-a305eb4fd07d.jpeg">

問題は、センサーから来るアナログデータをどう二酸化炭素濃度にするかわからないという・・・
(公式には計算式など無くイケて無いグラフだけ・・・)

なので先ずCSVデータをグラフから目と手で主観的に作ります💢
<img width="600" alt="graph" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2709872/08b684ea-3790-ac7c-3f6e-77048ee798d2.png">

Pythonでそれっぽい式が出るよう計算させます。
```Python
import pandas as pd;
import matplotlib.pyplot as plt;
import numpy as np;
import scipy.optimize as opt;
from scipy.optimize import curve_fit
from scipy.stats import linregress;
def func(x, a, b, c):
    return a**(x+b)+c
df = pd.read_csv('mg812.csv', header=0, names=['x','y']);
plt.plot(df['x'], df['y'], label='');
plt.xlabel('x');
plt.ylabel('y');
plt.title('MG812 CO2 ppm vs Output mV');
tmp = df.to_numpy();
X = tmp[:,0];
print("X values");
print(X);
y = tmp[:,1];
print("Y values");
print(y);
params, cov = curve_fit(func, X, y);
plt.plot(X, func(X, *params), 'r-', label='fit');
print('Parameters:', params);
plt.legend();
plt.show();
```
<img width="750" alt="graph" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2709872/ef07e8f4-593f-09c7-5668-deb10bcc52ca.png">

Arduinoでセンサーからの値を二酸化炭素濃度値ppmに変換させてシリアルで読めるようにします。
```C
int mg812 = 14; // MG812 connected to A0

const uint32_t SERIAL_SPEED{115200};  ///< Set the baud rate for Serial I/O
void setup() {
  Serial.begin(SERIAL_SPEED);  // Start serial port at Baud rate
#ifdef __AVR_ATmega32U4__      // If this is a 32U4 processor, then wait 3 seconds to init USB port
  delay(3000);
#endif
}  // of method setup()
void loop() {
  static char     buf[16];                        // sprintf text buffer
  static uint16_t loopCounter = 0;                // Display iterations
  static int32_t  analog_v;
  static float    output_mv, co2;
  if (loopCounter % 25 == 0) {     // Show header @25 loops
    Serial.print(F("\nLoop  CO2 ppm\n"));
    Serial.print(F("==== ======\n"));  
  }                                                     // if-then time to show headers
  analog_v = analogRead(mg812);
  //Sensor value = analogRead * 5V / 1023 * 1000 / 10(which akizuki made)
  output_mv = analog_v*(5.0 / 1023.0) * (1000 / 10); 
  co2 = pow(0.94831961, (output_mv-438.34187965))-184.81299894;
  if (loopCounter++ != 0) {                             
    sprintf(buf, "%4d", (loopCounter - 1) % 9999); 
    Serial.print(buf);
    sprintf(buf, "%6d\n", (int16_t)(co2));
    Serial.print(buf);
    delay(1000);  // Wait 10s
  }                // of ignore first reading
}  // of method loop()
```
これにて完了。
p.s. BME680という温湿度・気圧・悪性ガスセンサーとか言うスーパーマルチセンサーも同じブレッドボードに載せてますが、気が向いたらそれに関しても書こうかと。
M1,2(arm64)でnode-sassを使用するには

### はじめに

最近、intel macからM2 macに変更したのですが、環境構築等を行っているときにnode-sassに関してのエラーが発生し、解決に時間がかかったので備忘録として残しておきます。

### エラー内容
プロジェクトをyarn install した際に以下のエラーが発生しました。
```
.../node_modules/node-sass: Command failed.
Exit code: 1
Command: node scripts/build.js
Arguments:  ...
Directory:  ...
...
gyp info using node-gyp@3.8.0
gyp info using node@14.17.0 | darwin | arm64
gyp verb command rebuild []
gyp verb command clean []
gyp verb clean removing "build" directory
gyp verb command configure []
gyp verb check python checking for Python executable "python2" in the PATH
gyp verb `which` failed Error: not found: python2
...
gyp verb check python checking for Python executable "python" in the PATH
gyp verb `which` failed Error: not found: python
...
```

### 試したこと
・ node-sassのバージョンが4.14.1だっためそれに対応するnodeをインストールする(私の場合はv14.17.0)
・ エラー内容に書かれている通り、python2がないですよ！と言われているのでinstall

以上の二つを行うことでエラーは解決した。

### 参考
・ node-sass document

https://github.com/sass/node-sass/releases/tag/v4.14.0

・ node.jsインストール手順

https://qiita.com/kyosuke5_20/items/eece817eb283fc9d214f

・ pythonインストール手順

https://zenn.dev/kenghaya/articles/9f07914156fab5
早明浦ダムの貯水率をワンライナーでスクレイピング

```sh
curl -s "http://www1.river.go.jp/cgi-bin/DspDamData.exe?ID=1368080700010&KIND=3&PAGE=0" \
| xmllint --html --xpath 'string(/html/body/center/p[1]/a/@href)' - \
| sed 's;^/;http://www1.river.go.jp/;;' \
| xargs -n 1 curl -s \
| iconv -f sjis -t utf8 \
| sed 's/^#//' \
| awk 'NR==7 || NR>9{print $0}' > sameura.csv
```
nest.jsはじめの一歩

# nest.js学習備忘録
```
$ npm i -g @nestjs/cli
$ nest new project-name
```
初めにプロジェクトを作成すると以下のようなファイルができる


app.controller.ts	
単一経路を持つ基本的なコントローラー
app.controller.spec.ts	
コントローラのユニットテスト
app.module.ts	
アプリケーションのルートモジュール
app.service.ts	
単一のメソッドを持つ基本的なサービス
main.ts	
コア関数NestFactoryを使用してNestアプリケーションのインスタンスを生成するアプリケーションのエントリファイル

```main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();
```

main.tsには、アプリケーションを起動するための非同期関数が含まれています。

Nestアプリケーションのインスタンスを作成するには、コアのNestFactoryクラスを使用する。
NestFactoryは、アプリケーションのインスタンスを生成するための静的メソッドをいくつか公開しています。
create()メソッドは、INestApplicationインタフェースを満たすアプリケーションオブジェクトを返します。
上記のmain.tsの例では、HTTPリスナーを起動し、アプリケーションがHTTPリクエストの受信を待機するようにします。
AWS EC2とGithubをGit連携しているが、リモート先をBacklogGitに変更してみた。

# 今回やりたい事_説明
* EC2インスタンスとGithubをGit＞SSH接続済みだが、GithubをbacklogGitに変更したい。
* backlog側では接続元IPアドレスによって、アクセスを制限したい。

# 今回やりたい事_イメージ図
![イメージ図](https://qiita-cs-articletowrite.s3.ap-northeast-1.amazonaws.com/02article/h1Img.png)

### ▼環境案内▼
:::note info
PC：Windows　OS 10（非エンジニアなので細かいことは書かない。）
Backlog：管理者権限を保持
Git：WindowsPC、EC2に事前インストール済み
backlog：WindowsマシンのNetworkのGIP登録済み、Gitリポジトリ作成済み
NETWORK：普通に自宅のWi-fi か　会社有線LAN環境
:::

***

## １．EC2にコンソールで接続しGitリモートURLを変更する
EC2サービスを選択し接続する
![サービス選択](https://qiita-cs-articletowrite.s3.ap-northeast-1.amazonaws.com/02article/01-01.png)
![インスタンス接続](https://qiita-cs-articletowrite.s3.ap-northeast-1.amazonaws.com/02article/01-02.png)

対象のユーザ名を入力し、Gitリポジトリのディレクトリまで移動し以下コマンドでGit存在確認
* 1 ``git --version`` ←Gitのバージョン確認。（ちゃんとGitあるよね？の確認）
* 2 ``git remote -v`` ←Gitのリモート接続先URLを確認できる（URLはちゃんとGithubのリポジトリURLだよね？の確認）
![Gitリモート確認](https://qiita-cs-articletowrite.s3.ap-northeast-1.amazonaws.com/02article/01-03.png)
![Gitコマンド入力](https://qiita-cs-articletowrite.s3.ap-northeast-1.amazonaws.com/02article/01-04.png)

gitremoteの結果は以下のように返答あり
````
origin Github接続先のSSHURL (fetch)
origin Github接続先SSHURL (push)
````

### ここからが本番
* 3　``git remote set-url origin BacklogGitのSSH接続URL`` ←Gitのリモート接続先URLを変更できる
すると、、、、何も反応なし
* 4　``git remote -v`` ←Gitのリモート接続先URLを確認できる（URLはちゃんと **Backlog** のリポジトリURLだよね？の確認）

gitremoteの結果は以下のように返答あり

````
origin BacklogGit接続先のSSHURL (fetch)
origin BacklogGit接続先SSHURL (push)
````

### 変わってる！よっしゃ！

## 2．Gitリモート先にfetchしてみる
* 1 ``git fetch`` ←Gitのリモート先に状態を確認アンド最新情報を取得する。（つまりリモート先のBacklogGitに接続できているよね？の確認）

gitremoteの結果は以下のように返答あり。何か聞かれている。無邪気に「Yes」を選択
````
The authenticity of host 'backlogURL (000.000.000.000backlogサーバのIPっぽいもの)' can't be established.
ECDSA key fingerprint is SHA256:固有の値.
ECDSA key fingerprint is MD5:固有の値.
Are you sure you want to continue connecting (yes/no)? yes
````

すると、、、
````
Warning: Permanently added 'backlogURL,(000.000.000.000backlogサーバのIPっぽいもの)' (ECDSA) to the list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

````

### なんかダメと言われている気がする。。正直ここからハマりました。。。

* 2　ダメ元でGitpullしてみる
``git pull`` ←Gitのリモート先からファイルを呼ぶ。（つまりリモート先のBacklogGitに存在するファイルをEC2にダウンロードするコマンド）
````
Warning: Permanently added 'backlogURL,(000.000.000.000backlogサーバのIPっぽいもの)' (ECDSA) to the list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

````
### なんかダメと言われている。わかんない。。Googleさんで調べる。Qiitaでもしらべる。。。。けどないよ。。引っかかる事例ではローカルリポジトリは大体ローカル環境な事がほとんどでEC2をローカルリポジトリにしている事例がないな。。

### 迷子。。

## 3．問題解決にはげむ。Google検索調べまくり。。

``Permission denied (publickey).``しらべるとこのメッセージが出ているって事は、BacklogGitにはコマンドが届いている証拠らしい。

なので１－４でおこなったseturlの値は間違ってない。
けど認証できていないらしい。くらいまではわかった。。。でも事例が見つからないですね。。

ダメ元でEC2のパブリックIPv4アドレスをBacklogの接続元IPに追加してみた。
![IPｖ４](https://qiita-cs-articletowrite.s3.ap-northeast-1.amazonaws.com/02article/03-01.png)

### すると、行けた。``git fetch`` も``git pull``もできました。

はい。ここまで。ポイントはEC2インスタンス自体のパブリックIPv4アドレスです。もちろん、EC2側のネットワーキング設定でいろいろ条件違ってくると思いますが、誰かの参考になれば。
公開鍵暗号化方式と使用してログインパスワードを暗号化する方法

# opensslを使用してパスワードを暗号化する

運用スクリプトを作成するにあたり、ログインパスワードをスクリプトに直書きするのは、
よろしくないのでは？
ということでopensslコマンドを使用してパスワードは別ファイル、しかも暗号化されたものを使用するやり方を記載します。

## 作業の流れ

1. 秘密鍵の作成
2. 公開鍵の作成
3. パスワード暗号化
4. パスワード複合化
5. ログイン確認

今回ログインするのはMySQLとする。

## 1. 秘密鍵の作成

以下コマンドで作成します。

```bash
naoki@:~$ openssl genrsa 2024 > secret_key
Generating RSA private key, 2024 bit long modulus
........................+++
..............+++
e is 65537 (0x10001)
```

## 2. 公開鍵の作成

先ほど作成した秘密鍵を使用して公開鍵を
以下コマンドで作成します。

```bash
naoki@:~$ openssl rsa -pubout < secret_key > pub_key
writing RSA key
```

## 3. パスワード暗号化

作成した公開鍵を使用して暗号化されたパスワードファイルを作成します

```bash
	naoki@:~$ echo "password" | openssl rsautl -encrypt -pubin -inkey pub_key > mysqlpwd
```

ここで```cat mysqlpwd```でファイルを読み取ることができなければ問題ないです。
文字化けする感じで表示されるはずです。

## 4. パスワード複合化

以下複合化します

```bash
naoki@:~$ openssl rsautl -decrypt -inkey secret_key -in mysqlpwd 
password
```

ここで先ほどechoで入力したパスワードが表示されていれば、複合化成功です

## 5. ログイン確認

先ほどのパスワード複合化手順を使用MySQL内のデータベース一覧を取得します。

```bash

naoki@:~$ MYSQLPASS=`openssl rsautl -decrypt -inkey secret_key -in mysqlpwd`
naoki@:~$ echo $MYSQLPASS
naoki@:~$ mysql -u root -p$MYSQLPASS
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 13
Server version: 8.0.23 Homebrew

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
```

## 今回の暗号複合化の方式について

こちらは公開鍵暗号化方式を使用してます

### 公開鍵とは

公開鍵暗号化方式で使用する鍵の1つで、鍵をかけるための鍵です。
この鍵でファイルの暗号化することができます。
公開鍵は、秘密鍵と対になるものため、作成する場合は秘密鍵を使用して作成します。

### 秘密鍵とは

公開鍵暗号化方式で使用する鍵の1つで、鍵を開けるための鍵です。
この鍵で暗号化されたファイルを複合することができます。

今回は、パスワードを公開鍵を使用して鍵をかけ（暗号化）、
秘密鍵を使用して鍵を開ける（複合化）する内容となることがMySQLログインパスワードを暗号化する作業で学習することができました。
このように実際にやってみることでインプット学習していたものが、
より身につきやすくなることが分かりました。

以上です。
AmazonLinux2のAWSCLI2にアップデート

基本コマンド
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html

バージョンアップされない時の参考サイト
https://www.secuavail.com/kb/tech-blog/tb-211005_01/

使用コマンド
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install --update

unzipがインストールされていない時
sudo yum install zip unzip

yumがインストールされていない時
sudo yum update

＝＝
Found same AWS CLI version: /usr/local/aws-cli/v2/2.7.19. Skipping install.
＝＝
上記エラー出力時コマンド
source ~/.bash_profile
React Hooksの備忘録(useState、useEffect)

# はじめに

普段C#で開発を行っていますが、最近Web開発技術も勉強中です。
React Hooksについて学ぶ機会があったのでまとめます。

# React Hooksとは

React Hooksによって今までほぼViewを返すだけだった関数コンポーネントで状態(state)やライフサイクルを持てるようにしたものと理解しています。

# useState

関数型コンポーネントで状態(state)を扱うためのものです。
以下のように、useStateを呼ぶことで、stateの値(下のコードではcount)とその値を更新するための関数(下のコードではsetCount)が宣言されます。これにより、関数を抜けてもstateの値が保持されるようになります。
また、useStateの引数にはstateの値の初期値を入れます。

```react
import React, {useState} from "react";
const MyHooksComponent = () => {
  const [count, setCount] = useState(0);
};
```

以下のようにsetCountを呼ぶことで、ボタンクリック時にcountが更新されます。

```react
import React, {useState} from "react";

const MyHooksComponent = () => {
    const [count, setCount] = useState(0);

    const handleClick = () =>{
        setCount(count + 1);
    };

    return <div>
        <h1>MyHooksComponent</h1>
        <div>{count}</div>
        <button onClick={handleClick}>PLUS 1!</button>
    </div>
}

export default MyHooksComponent;
```
# useEffect

ライフサイクルメソッドを関数コンポーネントで実現するためのものです。
UseEffectはDidMountおよびDidUpdateのタイミングで呼ばれる、つまり、毎回のレンダー後に呼ばれるものです。
UseEffect内で関数をreturnする処理を書くと、その処理がCleanUp(WillUnMount)時に呼ばれます。これも毎回のレンダー後に呼ばれます。
UseEffectを使うと、DidMount, DidUpdate, WillUnMountがuseEffect内に1つにまとまるイメージでしょうか。
毎回のレンダー後でなく、特定のstateの変化があった場合のみ呼ぶ場合は、useEffectの第2引数に配列(依存配列)を渡し、配列の中に対象のstateを記載します。
また、useEffectの第2引数に空の配列を渡すと、DidMountおよびWillUnMount時のみ(毎回のレンダーで呼びたくない)処理を実行できます。

```react
import React, { useEffect, useMemo, useState } from "react";

const MyHooksClock = () => {
    const [date, setDate] = useState(new Date());
    const [count, setCount] = useState(0);

    const tick = () => {
        console.log(new Date());
        setDate(new Date());
    };

    useEffect(() => {
        // setIntervalでは渡された関数を定期実行する関数
　　    // 第2引数に空の配列を指定すると、レンダー後、一回のみsetIntervalが呼ばれる
        // レンダーの度(1秒ごと)にsetIntervalが増殖するのを防げる
        const timerId = setInterval(()=> tick(),1000);
        return () => {
            clearInterval(timerId);
        };
    }, []);
    
    useEffect(()=>{
        // ボタンをクリックして、setCountでcountが変化したときだけ呼ばれる
        if (count === 10) {
            alert("10!!");
        }
    },[count]);

    return (
        <div>
            <h1>What time is it?</h1>
            <h2>It is {date.toLocaleTimeString()}.</h2>
            <button onClick={()=>setCount(count+1)}>count + 1</button>
            <h3>{count}</h3>
        </div>
    );
};

export default MyHooksClock
```

# 最後に

React自体学びたてなので色々怪しいですが、記事を書いて少し整理できました。
React Hooks使えるようになれそうです。
【Xcode】パーミッションリクエストが反映されない

# 問題
`NSPhotoLibraryAddUsageDescription`を記述しているにも関わらず、記述されていない判定でクラッシュする
![スクリーンショット 2022-07-28 18.15.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/74b83dcc-8eb3-f036-3761-e44c23e97f28.png)
```
This app has crashed because it attempted to access privacy-sensitive data without a usage description.  The app's Info.plist must contain an NSPhotoLibraryAddUsageDescription key with a string value explaining to the user how the app uses this data.
```
![スクリーンショット 2022-07-28 18.14.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/9d493da5-1fc8-5fb7-5049-8918db3bfea6.png)

# 原因
SwiftUIはXcode13からデフォルトで`Info.plist`が表示されなくなりました。
ですので、`Info.plist`の編集はこちらから行います。
![スクリーンショット 2022-07-28 18.44.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/f141f0ba-b074-c3ca-c8a1-2b7f00489924.png)

しかし、1度編集を行うとプロジェクト内に`Info.plist`ファイルが生成されます。
![スクリーンショット 2022-07-28 18.47.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/1e60ac38-01dc-13d5-cf21-25650d3abb12.png)

こちらから`NSPhotoLibraryAddUsageDescription`を追加しても反映されていませんでした。
![スクリーンショット 2022-07-28 18.47.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/53ffe551-1dbc-7c8d-7779-a792c6aa0242.png)


# 解決方法
ターケット内のInfoからパーミッションリクエストを記述する
![スクリーンショット 2022-07-28 18.49.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/c492f422-d77f-370d-0c3e-86569517a533.png)

# おわり
おそらくバグです
Airflowの日時関連概念おさらい

このところAirflowについて公式資料を読んできた中で、重要概念としてしばしば登場した各種の日付概念をおさらいしておきます。

---

# データ区間（data interval）

ワークフロー（DAG）の実行中に処理対象となるデータの区間（期間）。
バッチ処理の対象となるデータを特定するための情報。
開始日時（data_interval_start）と終了日時（data_interval_end）で示される。

例えば一日ごとに起動するワークフローならば、
「今回」`2022-07-23 00:00:00`に起動した回のデータ区間は `2022-07-22 00:00:00` から `2022-07-23 00:00:00`、
次回のデータ区間は `2022-07-23 00:00:00` から `2022-07-24 00:00:00`、
次次回のデータ区間は `2022-07-24 00:00:00` から `2022-07-25 00:00:00`、
・・・と推移する。

タスクやオペレーターのPythonコードでは`context`オブジェクトを使ってこれらの日時情報を取得できる。例： `context['data_interval_start']`。
Jinja2テンプレートの中でも同名の変数として利用できる。例：`{{ data_interval_start }}` ・ `{{ data_interval_end }}` （[参考ページ](https://airflow.apache.org/docs/apache-airflow/stable/templates-ref.html#variables)）。
タスクやオペレーター内のビジネスロジックでは、例えばSQLのフィルタに開始日時と終了日時の条件を加えるなどして、処理対象のデータを制御する。
Web UIではワークフロー（DAG）の「Last Run」や「Next Run」の (!) マークにマウスオーバーすると確認できる。

# スケジュール間隔（schedule_interval）

DAGのパラメーターの1つ。
ワークフローのスケジュール実行の起動間隔を定義するもの。
crontabの記法を使用して指定できる。

この間隔でdata intervalが刻まれていく。
例えば`@daily`なら1日間隔となり、1日あたり1回実行されるワークフローとなり、data interval も直近24時間を表すものになる。また例えば`@hourly`なら1時間間隔となり、1日あたり24回実行されるワークフローとなり、data interval も直近1時間を表すものになる。

# 開始日時（start_date）

DAGのパラメーターの1つ。
一連のデータ区間（data interval）の最初のものの開始日時。
この日時から`schedule_interval`で指定された時間が経過した後、ワークフローは初回起動する。

初回起動の時は一連のデータ区間（data interval）の開始日時と一致する。
つまり `start_date` ＝ `data_interval_start`。そして `start_date` + `schedule_interval` ＝ `data_interval_end`。
次回起動の時は `start_date` + `schedule_interval` ＝ `data_interval_start`で、`start_date` + (`schedule_interval` * 2) ＝ `data_interval_end`。

# 論理日時（logical_date）

旧称： `execution_date`。v2.2以降、現在の名称になった。
スケジュール実行した場合とそうでないとき（手動実行など）で内容が異なる。
スケジュール実行された場合は、`data_interval_start` と同じになる。
手動実行された場合は、起動指示が行われた日時になる。

タスクやオペレーターのPythonコードでは`context`オブジェクトを使ってこれらの日時情報を取得できる。例： `context['logical_date']`。
Jinja2テンプレートの中でも変数として利用できる。データ精度やフォーマットにより複数用意されている。例：`{{ ds }}` や `{{ ts }}` （[参考ページ](https://airflow.apache.org/docs/apache-airflow/stable/templates-ref.html#variables)）。
Web UIではワークフロー実行（DAGRun）の一覧で確認できる。

# 参考情報

https://qiita.com/mizukyf/items/20cafca6cc929ad8c4df

https://qiita.com/mizukyf/items/acca8d4f486204c37cd2

https://qiita.com/mizukyf/items/16db22e0f649b611aa89

https://qiita.com/mizukyf/items/35a719b5f8aa3bc05caf

---

Jinja2テンプレート内で参照できる変数名については公式リファレンスの[こちらのページ](https://airflow.apache.org/docs/apache-airflow/stable/templates-ref.html#variables)を参考にしました。また、Contextオブジェクトが持つエントリーのキーについては公式リポジトリの[こちらのコード](https://github.com/apache/airflow/blob/5efe6f34fd4a00f388d2979a708c90884f2e09ac/airflow/utils/context.py#L45)を参考にしました。
正十六角形「公立千歳科学技術大学2019年Ⅱ期第１問(2)」をwolframalphaとsympyでやってみた。

オリジナル
「三角比の問題」だそうです。

https://mathmathmass.exblog.jp/32093274/

以下,半角の公式は、使っていません。半角の公式を勉強して使えるようになったら、追加する予定です。
# wolframalphaで

https://www.wolframalpha.com/input?i=1%2F2*R*R*sin%282*pi%2Fn%29*n&lang=ja

https://www.wolframalpha.com/input?i=R%3D1%2Cn%3D16%2C1%2F2*R*R*sin%282*pi%2Fn%29*n&lang=ja

# sympyで

```python
from sympy import *
var('R n')
print("#",(Rational(1,2)*R*R*sin(2*pi/n)*n).simplify())
#
R=1
n=16
print("#",(Rational(1,2)*R*R*sin(2*pi/n)*n).simplify())
#
print("#",(Rational(1,2)*R*R*sin(2*pi/n)*n).simplify().subs({R:1,n:16}).simplify())
# R**2*n*sin(2*pi/n)/2
# 4*sqrt(2 - sqrt(2))
# 4*sqrt(2 - sqrt(2))
```

# 参考
正十六角形は定規とコンパスによる作図が可能な図形である。＜wikipwdia
今は、CADでしょうか。


https://ja.wikipedia.org/wiki/%E5%8D%81%E5%85%AD%E8%A7%92%E5%BD%A2

https://en.wikipedia.org/wiki/Hexadecagon

wolframalphaについて、日本語版の方が項目が多いです。
定義不等式?　わかられる方へ。さわりだけでも教えてもらうと、勉強になります。

https://www.wolframalpha.com/input?i=%E6%AD%A3%E5%8D%81%E5%85%AD%E8%A7%92%E5%BD%A2&lang=ja

https://www.wolframalpha.com/input/?i=hexadecagon
Git submoduleを、リモートリポジトリのmainブランチの最新版に反映させる

## 初めに

とあるプロジェクトの`リポジトリA`で、
`外部リポジトリB`をsubmoduleとして登録している場合に、
`外部リポジトリB`側のリモートリポジトリの**main(master)ブランチ**に新しいコミットが追加されたとします。


`リポジトリA`側にも、`外部リポジトリB`の上記の変更を反映させたい場合、
反映させる方法は概ね２パターンあります。

### 前提条件
今回ご紹介する例では、
- `リポジトリA`のディレクトリ名を、`main_project_A`
- `外部リポジトリB`のディレクトリ名を、`sub_project_B`

とします。


## パターン①：リポジトリA側だけでコマンド実行

こちらの方法が楽だと思います。
`リポジトリA`側のプロジェクトのルートディレクトリに移動して
`git submodule update --remote`コマンドを実行します。
この時、**--remote**オプションをつけないと反映されません。

```shell
# main_project_A ディレクトリに移動
$ cd main_project_A

# リポジトリA側から参照するsubmoduleを、外部リポジトリBのリモートリポジトリの最新のmainブランチに反映させる
$ git submodule update --remote
Submodule path 'sub_project_B': checked out 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' # ←コミットID

```

次に、`git status`コマンドを実行すると
差分が検知されるので、
`git add`コマンド -> `git commit`コマンドで反映完了です。


ちなみに、
`git submodule update --remote`コマンドの実行結果を
やっぱりなかったことにしたい場合は、**--remote**オプションを外して
再度`git submodule update`コマンドを実行すれば元に戻ります。


## パターン②：両方のリポジトリ側でコマンド実行

まず`外部リポジトリB`側のプロジェクトのルートディレクトリに移動します。
次にmainブランチを指定してから
`git pull origin main`コマンドを実行して、
`外部リポジトリB`（ローカル）を、リモートリポジトリの最新のmainブランチと同期させます。

```shell
# sub_project_B ディレクトリに移動
$ cd sub_project_B

# mainブランチを指定
$ git checkout main
$ git branch
* main

# git pullで、リモートリポジトリの最新のmainブランチと同期
$ git pull origin main

```

次に、`リポジトリA`側のプロジェクトのルートディレクトリに移動します。
`git status`コマンドを実行すると、
submoduleが最新のリモートリポジトリのmainブランチと同期された変更により、
差分が検知されるようになります。

なので、ここからはパターン①と同様に、
`git add`コマンド -> `git commit`コマンドで反映完了です。

```shell
# main_project_A ディレクトリに移動
$ cd main_project_A

# git statusを実行すると、差分が検知されるようになる
$ git status
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
  (use "git push" to publish your local commits)

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   sub_project_B (new commits)

no changes added to commit (use "git add" and/or "git commit -a")

# git add & git commitで反映させる
$ git add .
$ git commmit

```
Webプログラマーに資格は必要なのか

Webプログラマーになるには資格は必要なのか。

こちらの記事ではWebプログラマーとはどんな仕事を行うのか、またどのような人材が求められているのかなどについてご紹介しています。
https://shikakuhiroba.net/it/45964


必ず資格が必要な職業というわけではありませんが、やはり資格取得や、知識の確保はしておいた方が良いでしょう。
また、コミュニケーション能力も非常に重要な職業です。

就職や転職はもちろん、フリーランスとしても活躍できるWebプログラマーについてまとめています。
Laravel-Lang/publisherでLaravelを日本語対応する

# Laravel-Lang/publisherとは
[Laravel-Lang/lang](https://laravel-lang.com/)を使用しLaravelの多言語対応を簡単に行えるパッケージです。
詳細については[Laravel-Lang/publisher](https://publisher.laravel-lang.com/)を参照して下さい。

## 環境
- PHP 8.1.1
- Composer version 2.3.10
- Laravel Framework 9.22.1
## 手順
1. laravel-lang/publisherとlaravel-lang/langをインストールします。
    ```
    composer require laravel-lang/publisher laravel-lang/lang --dev
    ```

2. langフォルダ配下にjaフォルダとja.jsonを作成します
    ```
    php artisan lang:add ja
    ```

3. config/app.phpを編集
    ```
    'locale' => 'ja',
    ```
これで日本語化されているはずです。

## あとがき
現在[Laravel-Lang/lang](https://laravel-lang.com/)では78もの言語が翻訳されているそうです。
こんなに簡単に多言語対応させていただけるのは素晴らしいですね。

## 参考文献
[Laravel-Lang/lang](https://laravel-lang.com/)
[Laravel-Lang/publisher](https://publisher.laravel-lang.com/)
【備忘録】PostgreSQLでautoincrementのidを再設定する。

PostgreSQLでauto_incrementの再設定方法です。idを途中から設定する方法を記載します。

```sql:再設定方法
SELECT SETVAL ('テーブル名_カラム名_seq', idの開始No, false);
```

```sql:具体例(usersテーブルのidカラムを１００に設定する。)
SELECT SETVAL ('users_id_seq', 100, false);
```
OpenAI gymでAtariをインストールするまで

gymの仕様変更に伴って，Atariのインストール手順が少し変化したので，自分用のメモ
## インストール方法
```shell
pip install gym[atari]
pip install autorom
pip install gym[accept-rom-license]
```
gym経由でatariをダウンロードするのに加えて，自前でAtari ROMをインストールする必要がある．一応，ROMの使用は研究目的のみ可みたいなことが書いてあったりするので，その辺を注意する必要がある．

## 備考
gym==0.19.0だとROMをインストールしなくても，gym[atari]だけでAtariを動かすことができる．ただし，Defenderのゲームだけgym.makeするとハングアップする現象が確認されたので，もしDefenderで実験したい場合は上記で示した最新パージョンでのセットアップを行う必要がある．