OmniAICreator/Qiita-1.07M huggingface dataset:
React: JSON をテーブルで表示 （連想配列）

こちらのプログラムを改造して、連想配列を表示します。
[React: JSON をテーブルで表示](https://qiita.com/ekzemplaro/items/c7ea5e70eaeb1c0596b4)

次の JSON を CORS のヘッダーがある形で受信します。
>Access-Control-Allow-Origin: *

```json:cities.json
{
  "t0921": { "name": "宇都宮", "population": 41295, "date_mod": "2003-8-12" },
  "t0922": { "name": "小山", "population": 38756, "date_mod": "2003-5-15" },
  "t0923": { "name": "佐野", "population": 71294, "date_mod": "2003-6-8" },
  "t0924": { "name": "足利", "population": 27138, "date_mod": "2003-7-21" },
  "t0925": { "name": "日光", "population": 74682, "date_mod": "2003-4-19" },
  "t0926": { "name": "下野", "population": 82951, "date_mod": "2003-10-14" },
  "t0927": { "name": "さくら", "population": 96823, "date_mod": "2003-5-24" },
  "t0928": { "name": "矢板", "population": 57926, "date_mod": "2003-2-12" },
  "t0929": { "name": "真岡", "population": 64187, "date_mod": "2003-11-14" },
  "t0930": { "name": "栃木", "population": 82354, "date_mod": "2003-7-04" },
  "t0931": { "name": "大田原", "population": 72681, "date_mod": "2003-9-17" },
  "t0932": { "name": "鹿沼", "population": 23749, "date_mod": "2003-7-20" },
  "t0933": { "name": "那須塩原", "population": 12759, "date_mod": "2003-3-12" },
  "t0934": { "name": "那須烏山", "population": 62531, "date_mod": "2003-8-17" }
}
```

次のファイルを書き換えます。

```js:src/App.js
import React, { useState, useEffect } from 'react';
import './App.css';

function TableData() {
    const [data, getData] = useState([])
    const URL = 'https://example.com/cities.json';

    useEffect(() => {
        fetchData()
    }, [])


    const fetchData = () => {
        fetch(URL)
            .then((res) =>
                res.json())

            .then((response) => {
                console.log(response);
                getData(response);
            })

              }

    return (
        <>
            <h1>連想配列の表示</h1>
            <table>
            <thead>
                <tr>
                    <th>no</th>
                    <th>key</th>
                    <th>name</th>
                    <th>population</th>
                    <th>date_mod</th>
                </tr>
            </thead>
            <tbody>
            {Object.keys(data).map((key, ii) => (
                    <tr key={ii}>
                        <td>{ii}</td>
                        <td>{key}</td>
                        <td>{data[key].name}</td>
                        <td>{data[key].population}</td>
                        <td>{data[key].date_mod}</td>
                     </tr>
                    ))}
               </tbody>
            </table>

        </>
    );
}

export default TableData;
```

実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/2a348573-f8b3-e64b-705d-e55abc3b3df4.png)
【Sharepoint Online】"評価の設定" を有効にするとフォームが強制的にクラシック表示になる

# 挙動

チームサイトのカスタムリストの設定で、[全般設定] > [評価の設定] を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111975/1ed38a37-13df-8d14-f971-9d7a272694c7.png)

※コミュニケーションサイトでは [評価の設定] 機能が無効になっているので有効にしないと表示されません。

https://zenn.dev/ymasaoka/articles/enable-list-rating-settings-in-sharepoint-online

[評価の設定] を『はい』にします。(いいね! or 星評価)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111975/5512c655-39c0-1338-6cf2-48bcb66bc926.png)

リストのアイテムをフォーム (DispForm, EditForm) で表示しようとすると、モダン表示に設定していても強制的に **クラシック表示** になってしまいます。

- リンクのコピーなどで取得したURL
- リスト Web パーツで埋め込んだリストの項目を開く
- URL による直リンク

```
/sites/{サイト名}/Lists/{リスト名}/DispForm.aspx?ID={ID 番号}
/sites/{サイト名}/Lists/{リスト名}/EditForm.aspx?ID={ID 番号}
```

# モダン表示に戻す

[評価の設定] を『いいえ』にしただけでは、モダン表示に戻りません。
モダン表示に戻すには、[評価の設定] 機能を有効にした際に自動追加される列をすべて削除する必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111975/ff90f462-8898-e618-9b09-f29494e4b1b2.png)

※[評価の設定] を『いいえ』に戻さず『はい』に設定されたままで自動追加される列を削除してしまうと、[評価の設定] が自動的に『いいえ』に設定され、[評価の設定] 機能を再度『はい』にすることができなります。  
その場合、今のところ対処方法はないそうです(MSサポート回答)。
(2022/08 現在)

# Feedback Portal

改修要望の投稿です。

- [Add Star rating for modern experience List](https://feedbackportal.microsoft.com/feedback/idea/5a60f89b-de1c-ec11-b6e7-0022481f8914)

# 参考サイト

- [SharePoint Online のリストで評価の設定を有効化する](https://zenn.dev/ymasaoka/articles/enable-list-rating-settings-in-sharepoint-online)
- [Sharepoint 2013: 既存の機能 GUID](https://social.technet.microsoft.com/wiki/contents/articles/14423.sharepoint-2013-existing-features-guid.aspx)
- [【Sharepoint Online】"対象ユーザー設定の有効化" するとフォームが強制的にクラシック表示になる](https://qiita.com/MakotoIshikawa/items/15d6f74153f61ae3146e)
Growiのバージョンアップ

まずは、株式会社WESEEK様に感謝

サーバー（PCですが）入れ替えに伴い最新版にバージョンアップしようとしましたが、躓いたので備忘録。

## 解決方法
v3.4.4➔　v5.0.5　でGrowiが起動しない
v3.4.4➔　v.4.5.20➔　v5.0.5　で成功

## 手順
### 現サーバーにてバックアップ
MongoDB
$ sudo mongodump -o /tmp/growi_backup/growi_2022xxxx/ -d growi

アップロードファイル
$ sudo tar zcvf /tmp/growi_backup/growi_uploads_2022xxxx.tgz /opt/growi/public/uploads/
※バージョンにより格納先が異なるので注意
（2019/10頃～） 　 /opt/growi/public　
（2021/9頃～）　　/opt/growi/packages/app/public　

### 新サーバーにインポート
||バージョン|
|:-:|:-:|
|Growi|4.5.20|
|node|14.x|
|npm|6.x|
|Elasticsearch|6.x|
|MongoDB|4.4|

①MongoDBのインポート
　MongoDBはサービス起動しておく
　　$ sudo systemctl start mongod
　ディレクトリ移動
　　$ cd /usr/bin
　データインポート
　　$ mongorestore -d growi /tmp/growi_2022xxxx/growi/ --drop

②アップロードファイルのコピー
　/opt/growi/packages/app/public/　配下に『uploads』ディレクトリコピー
　※パーミッションに注意

③Growi起動
　$ sudo systemctl start elasticsearch
　$ cd /opt/growi
　$ MONGO_URI=mongodb://localhost:27017/growi \\  ELASTICSEARCH_URI=http://localhost:9200/growi \\  npm start

④Growi設定
　ユーザーも移行されているので管理者でログイン後管理画面にて
　　・【アプリ設定】のアップロード設定で、ファイルアップロード方法を『Local』に変更
　　・【全文検索管理】で、インデックスのリビルド、再接続、正規化を行う

⑤トップ画面に戻り、正常稼働を確認する。

## Growi5.0.5へのアップグレード
サービスはすべて停止しておく。
### Elasticsearch
プラグインのアンインストール
　$ /usr/share/elasticsearch/bin/elasticsearch-plugin remove analysis-kuromoji
　$ /usr/share/elasticsearch/bin/elasticsearch-plugin remove analysis-icu

レポジトリを新バージョンに書き換え
　$ vi /etc/yum.repos.d/elasticsearch.repo　←新サーバーセットアップ時のファイル
~~~
[elasticsearch-7.x]
name=Elasticsearch repository for 7.x packages
baseurl=https://artifacts.elastic.co/packages/7.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
~~~

アップデート
　$ yum update -y elasticsearch --enablerepo=elasticsearch-7.*

メモリサイズ設定
　$ vi /etc/elasticsearch/jvm.options
　（デフォルト記述なさそうなので、-Xms1g　-Xmx1g　を追記した）

プラグイン追加
　$ /usr/share/elasticsearch/bin/elasticsearch-plugin install analysis-kuromoji
　$ /usr/share/elasticsearch/bin/elasticsearch-plugin install analysis-icu

サービスが正常起動するか確認
　$ sudu systemctl start elasticsearch

### Node.jsのアップグレード
　$ sudu yum remove -y nodejs
　$ sudu curl -sL https://rpm.nodesource.com/setup_16.x | bash -
　$ sudu yum install -y gcc-c++ make
　$ sudu yum install -y nodejs
　$ sudu yum install -y yarn
　※npmバージョンは6.xとあるが、8.xで問題なさそう。

### Growiアップグレード
　$ cd /opt/growi
　$ git fetch --tags
　$ git tag
　$ git stash
　$ git checkout v5.0.5
　$ yarn

※Growi起動後はファイルアップロード先がデフォルトになっているので、Localへ変更必要
Angular v9.x から v10.x にした時の問題点

Angular　v９の環境からv10に上げる過程で困ったこと・対処メモ

# 困った内容

Angularを９から１０にしようとした時に、`@angular/cdk`と`@angular/material`が１０に上がらない問題が発生。
下記の状態になってしまった…
```
 Name                               Version                  Command to update
     --------------------------------------------------------------------------------
      @angular/cdk                       9.2.4 -> 10.2.7         ng update @angular/cdk@10
      @angular/cli                       10.2.4 -> 11.2.9         ng update @angular/cli@11
      @angular/core                      10.2.5 -> 11.2.9         ng update @angular/core@11
      @angular/material                  9.2.4 -> 10.2.7         ng update @angular/material@10
```
この状態ので`ng serve`してみると下のエラーが表示されるようになった。
```
deprecationwarning access to process.binding('http_parser') is deprecated.
(Use `node --trace-deprecation ...` to show where the warning was created) 
```

この時のDockerFileの設定。
```
FROM node:16.15.1-stretch

ENV PYTHONUNBUFFERED 1

RUN npm install -g @angular/cli@^10

EXPOSE 8080
```
# 原因は？
原因としてはNode.jsのバージョンが新しすぎたっぽい。
Node.jsのバージョンを14.17.5に変更。
```
FROM node:1４.17.5-stretch

ENV PYTHONUNBUFFERED 1

RUN npm install -g @angular/cli@^10

EXPOSE 8080
```
変更後、@angular/cdkと@angular/materialをアップデート。
無事にアップデートが完了した。
```
# ng update
Using package manager: 'npm'
Collecting installed dependencies...
Found 36 dependencies.
    We analyzed your package.json, there are some packages to update:
    
      Name                               Version                  Command to update
     --------------------------------------------------------------------------------
      @angular/cdk                       10.2.7 -> 11.2.9         ng update @angular/cdk@11
      @angular/cli                       10.2.4 -> 11.2.9         ng update @angular/cli@11
      @angular/core                      10.2.5 -> 11.2.9         ng update @angular/core@11
      @angular/material                  10.2.7 -> 11.2.9         ng update @angular/material@11
```
# このあとは…
バージョンアップを引き続き行っていく予定
10->11
11->12
12->13
13->14
となる予定？予定は未定。

こうした方がいいよ、ここ間違ってるよ等あったらご指摘お願い致します。

# 参考記事
https://stackoverflow.com/questions/67503242/how-to-fix-node12364-dep0111-deprecationwarning-access-to-process-binding
あ、Postmanもう要らね。Thunder Clientもバイバイ。

# Postmanのリクエスト画面に行くまでが邪魔くさい
APIをテストする時、PostManの
`Workspace`=>`新しいタブを開く`=>`TEXT->Raw->JSONを選択`
という手順が若干邪魔くさかった。

なのでAPI連携のためのコードを開発する際、"VS Code内のPostman"みたいなThunder Clientを知ってからはもっぱらそれを使うか、Make(旧 Integromat)のモジュールを走らせてみて、Chrome Addonのディベロパーツールでリクエストのコンテンツに潜ってそこからBodyやURLをコピペしていた。

# テストしたリクエストからコードが生成できる！ Rapid API Client
Rapid APIは、最近楽天から切り離されたのかな？詳しい経緯は調べていないが、色んなサービスのAPIをテストできるプラットフォーム。
なんとそれがVS Codeのアドオンを出していた！
早速使ってみると、設定画面はPostmanやThunder Clientとほぼ同じ。
- クエリパラメータやJSONエディターがついている
- 変数使用可
- レスポンスの自動パース
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1984110/be20aa30-243a-7827-4507-f5e38da48744.png)

これになんと、各言語でのコード生成機能がついてくる！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1984110/e09550c1-c740-0d76-f37d-dadf1843f28e.png)
試しに生成してみると・・・
```python
import requests

url = "https://weather.tsukumijima.net/api/forecast"

querystring = {"city":"130010"}

response = requests.request("GET", url, params=querystring)

print(response.text)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1984110/944b4ef7-906d-c903-19e7-6350219818cc.png)

これははかどるわ～　Makeと併用してもいいかも。

## ちなみに、変数の使用方法
1. `Environments`の横の三点リーダーを押して
1. `Manage`を選択
すると変数設定画面が出れくる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1984110/67561f5f-7327-ad95-a1ea-b923becef969.png)
そしてコンフィグでは
1. `{`を入力
1. `Environment Variable`を選択
1. 画面上にでてきた`Environment Variable`をクリックして変数を選ぶ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1984110/5e11148a-a949-7344-95d1-15fa533e697d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1984110/4ede1908-b818-8d15-9511-f213d9fbe0fa.png)
Aurora MySQLをbinlogレプリケーションしようとしたらうまくいかなかった話

# 概要
- 運用中のAurora MySQLをAurora Serverless v2に移行するのにbinlogレプリケーションを試した
- ドキュメントの通りに進めたら取得できると書いてあった情報が表示されない事態になる
- サポートによると設定に問題がなくてもドキュメントにある方法でbinlogデータが取れないケースがあるとのこと
- 2022/07時点での挙動で、今後修正されそう


# やりたかったこと
Aurora MySQL 5.7系のクラスターとAurora Serverless v2でバイナリログレプリケーションを実施したかった。
最終的にはAurora Serverless v2だけにしてDB関連のメンテを楽にしたかった。


# 実施した内容
以下のドキュメントのステップに沿って実施。

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Replication.html#AuroraMySQL.Replication.MySQL

作業対象がバイナリログレプリケーションをサポートするクラスターであることは確認済み。

- パラメータグループのbinlog_formatをMIXEDに設定しbinlogを有効化
- バイナリログの保持タイムフレームを設定
- スナップショットの取得
- スナップショットの復元

ここまで実施、以降の作業はドキュメントには以下のとおり書いてあったが、binlogの情報が最近のイベントに出てこない。

```
コンソールで、[データベース] を選択し、復元された Aurora DB クラスターのプライマリインスタンス (書き込み) を選択してその詳細を表示します。
[最近のイベント] までスクロールします。
binlog ファイル名と場所を含むイベントメッセージが表示されます

Binlog position from crash recovery is binlog-file-name binlog-position
```

## （余談）うまくいかない事を受けてのServerless化対応
最終的にはServerless v2にするのが目的だったので、レプリケーションはせずにServerlessへの移行を実施した。
Aurora MySQL v3であればインスタンスの変更からAurora Serverless v2に移行することが可能。

実施直後はインスタンスに接続できたが、数分するとMySQL のCan't connectエラーが発生するようになる（ダウンタイムの発生）。
今回は1インスタンス実施して10min程度でインスタンスへの接続が可能になった。

# サポート問い合わせ
ドキュメント通りに実施したのにbinlog情報が出ない旨を問い合わせ。

## 返信要約
- DBクラスター / インスタンスの設定に問題がない状況でも、Auroraでは binlog 情報がスナップショットからの復元時にイベントに表示されないことがある
- ソース DB クラスターで binlog の出力を有効化した後に、バイナリログが出力されるような操作を実施していない場合、スナップショットの復元時にバイナリログの情報がコンソールに表示されない/エラーログに記録されない場合がある
    - binlog出力の有効化した後にバイナリログが出力される操作を実施してからスナップショットの取得をすること

とのことなので場合によっては今回の状態になることが分かった。


# 現状での対応策
サポートの返信によると以下でbinlogの情報を取得できるとのこと。

1. クラスターの復元後、RDSコンソールから対象クラスターのプライマリインスタンスを選択する
2. 最も古いエラーログを確認する (error/mysql-error-running.log) 
3. ログの中から復元時の binlog のポジションとファイル名を確認する

確かに `/aws/rds/cluster/hogefuga-cluster/error` で `binlog` フィルターをかけるとファイル名とポジションらしき情報が出てくる。
（ただしドキュメントのフォーマットと少々異なる模様）

この現象については「担当部署もすでに把握しており対応を検討している状況」だそうなので今後修正されることを期待。
Windowsで全タスクスケジューラー情報をcsvで取得

# やり方

コマンドプロンプトで下記。

```bat
schtasks /query /V /FO CSV > C:\Users\unko\Desktop\list.csv
```

『/V』は詳細情報を出力するオプションなので付けておいた方が何かと便利。

# どんなcsv？

文字コードはShift-JIS。

タスクスケジューラーのフォルダー階層単位でヘッダー行が入ってくる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/fcc654f8-3605-d93d-8e9a-829bf2595775.png)

カラム一覧。

| 項番 | カラム名 |
|--|--|
| 1 | ホスト名 |
| 2 | タスク名 |
| 3 | 次回の実行時刻 |
| 4 | 状態 |
| 5 | ログオン モード |
| 6 | 前回の実行時刻 |
| 7 | 前回の結果 |
| 8 | 作成者 |
| 9 | 実行するタスク |
| 10 | 開始 |
| 11 | コメント |
| 12 | スケジュールされたタスクの状態 |
| 13 | アイドル時間 |
| 14 | 電源管理 |
| 15 | ユーザーとして実行 |
| 16 | 再度スケジュールされない場合はタスクを削除する |
| 17 | タスクを停止するまでの時間 |
| 18 | スケジュール |
| 19 | スケジュールの種類 |
| 20 | 開始時刻 |
| 21 | 開始日 |
| 22 | 終了日 |
| 23 | 日 |
| 24 | 月 |
| 25 | 繰り返し: 間隔 |
| 26 | 繰り返し: 終了時刻 |
| 27 | 繰り返し: 期間 |
| 28 | 繰り返し: 実行中の場合は停止 |

# 参考サイトさん

https://qiita.com/sunmontue1006/items/fca3d99fcddc5e2d94db

https://windows.command-ref.com/cmd-schtasks-query.html

# バージョン

Windows 10 Pro 21H2 OSビルド 19044.1889

TODO:/FOなどのオプションについてまとめる。（ヘッダー無しにしたり、xml形式で出力できたり、もっと扱いやすい形式にできるかもしれない、参考サイト2番目）
【PHP】try-catch-finallyの挙動について

ふと、tryやcatchのブロックでreturnしている場合finallyのブロックって実行されるのかな？と疑問に思ったので詳しく調べてみることにしました。

## そもそもtry-catch-finallyとは
tryブロックの中の処理に例外的なエラーが発生したときにcatchブロックの処理がされます。エラーが発生しなかった場合はcatchブロックの処理はされません。エラーハンドリングをする際によく使われます。
そしてfinallyとは例外は発生したかどうかは関係なくtryおよびcatchブロックの後で常に実行されます。

早速挙動確認していきます。
```php
try {
    echo 'try';
} catch (Exception $e) {
    echo 'catch';
    echo $e->getMessage();
} finally {
    echo 'finally';
}

//実行結果
try
finally
```
例外が発生していないのでcatchブロックの処理はされません。

次はあえて例外を発生させてみます。
```php
try {
    throw new Exception('例外を投げる');
    echo 'try';
} catch (Exception $e) {
    echo 'catch';
    echo $e->getMessage();
} finally {
    echo 'finally';
}

//実行結果
catch
例外を投げる
finally
```
例外が発生したときにcatchブロックへ行きその後finallyブロックが実行されます。
このようにfinallyは必ず実行されます。

ではこの場合はどうでしょうか？
```php
try {
    throw new Exception('例外を投げる');
    echo 'try';
} catch (Exception $e) {
    echo 'catch';
    echo $e->getMessage();
    return 'catchブロック終了';
} finally {
    echo 'finally';
}

//実行結果
catch
例外を投げる
finally
catchブロック終了
```
私は最初catchブロックでreturnしているのでfinallyブロックに行かずに終了するのでは？と思いました。ただ実行してみるとfinallyが実行された後にreturnが実行されていることが分かります。

公式にはこのように記述されています。
>finally ブロックと return 文の間には注意すべき相互作用があります。 return 文が try や catch ブロックの内部に存在した場合でも、 finally ブロックは実行されます。 さらに、return 文は出現した時に評価されますが、 結果は finally ブロックが実行された後に返されます。

ここで1つ注意しないといけないのが、finallyブロックにもreturnがある場合です。

finallyブロックにreturnを追記して実行してみます。
```php
try {
    throw new Exception('例外を投げる');
    echo 'try';
} catch (Exception $e) {
    echo 'catch';
    echo $e->getMessage();
    return 'catchブロック終了';
} finally {
    echo 'finally';
    return 'finallyブロック終了';
}

//実行結果
catch
例外を投げる
finally
finallyブロック終了
```
finallyブロックのreturnが優先されています。
公式にはこうあります。
>finally ブロックにも return 文が存在した場合は、 finally ブロックから値が返されます。

これは1つ勉強になりました。

## DB接続時のtry-catchについて
少し話は変わりますが、PHPではDB接続時によくtry-catchを使うと思います。
```php
try {
    $pdo = new PDO($dsn, $user, $pass);//変数は定義してある程です
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $sql = 'SELECT * FROM users';
    $users = $pdo->query($sql);
    $rows = $users->fetchAll();
    var_dump($rows);
    // 接続を閉じる
    $pdo = null;
} catch (PDOException $e) {
    echo $e->getMessage();
}
```
上記のようにtryブロックの中に`$pdo = null（接続を閉じる処理）`が書かれているコードをたまに見ます。このコードでは例外が発生した時に、接続が閉じられることなく処理が終了してしまいます。catchブロックの中にも`$pdo = null`を書いてもいいですが、finallyブロックを追記してその中で`$pdo = null`を書いてあげれば1回で済みますよって話でした！

```php
try {
    $pdo = new PDO($dsn, $user, $pass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $sql = 'SELECT * FROM users';
    $users = $pdo->query($sql);
    $rows = $users->fetchAll();
    var_dump($rows);
} catch (PDOException $e) {
    echo $e->getMessage();
} finally {
    // 接続を閉じる
    $pdo = null;
}
```
AWSでALBを共有するがサブドメインごとに別々のEC2にアクセスしたい

## やりたいこと
- ALBを共有したい
- サブドメインごとに別々のEC2にアクセスさせたい
- HTTPSでアクセスしたい

今回の例では
aaa.ksawada1979.com
bbb.ksawada1979.com
というドメインを使用して設定します。
LinuxのVirtualホストを使って実現することが多いかと思いますが、今回はALBを共有して別々のEC2にアクセスさせます。

## 前提条件
- EC2上でApacheが起動済み
- ALBの基本設定は完了済み
- Certificate Manager(ACM)でSSL証明書が発行済みであるものとします。
  - *.ksawada1979.comのワイルドカード証明書を発行
- Route53でaaa.ksawada1979.comとbbb.ksawada1979.comのレコードは登録済み

## 構成図
非常に簡単な構成図ですが以下のような構成を想定しています。
![ksawada1979_alb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101744/375fad3e-4042-a31f-1ef5-8bbd3a1dc1e4.png)

## ターゲットグループ作成
ALBの基本的な設定はできている前提のためいきなりですがターゲットグループを作成します。
aaa.ksawada1979.com用とbbb.ksawada1979.com用の2つのターゲットグループを作成します。
VPC内部はhttpで通信するためにTargetのポートは80番になります。
![targetgroup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101744/78d92d78-daa0-75ed-1e66-debed0521abb.png)

## ルール設定
次にALBのルール設定をします。
ロードバランサー設定の「リスナー」タブを選択し「ルールの表示/編集」をクリックします。
![alb-rule.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101744/dc19de19-9e8d-ad01-7ccd-8db317da15ba.png)
上記のように2つのターゲットグループを作成します。

次に+をクリックして「ルールの挿入」→「条件の追加」→「ホストヘッダー」を選択して「aaa.ksawada1979.com」を入力します。
![rule01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101744/cca9a0da-72c3-6f8e-92f2-47f8fba9945e.png)

次に「アクションの追加」選択、さらに「転送先」をクリックして先ほど作成したターゲットグループaaa.ksawada1979.comを選択します。
![rule02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101744/81c74f0a-ba6c-70c6-d596-7fe95292ffc0.png)

同様にbbb.ksawada1979.com用の設定も入れて最終的に以下のように設定します。
![rule03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101744/42f9dd29-33c7-8656-672f-e7276f405b62.png)

上記でルールの設定は完了です。

## 確認
実際にブラウザでaaa.ksawada1979.comとbbb.ksawada1979.comにアクセスできるか確認します。
![aaa.ksawada1979.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101744/865d6475-72cf-3d35-2699-28fd38b9d126.png)
![bbb.ksawada1979.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101744/96c54c0b-399c-0273-7335-bccf708ed847.png)

それぞれアクセスすることができました。
ちょっとこの画面だけだとそれぞれのEC2アクセスできているかわかりにくいですが、それぞれのEC2の/var/www/html/index.htmlをそれぞれ書き換えて確認しました。
ALBを共有するがサブドメインごとに別々のEC2にアクセスしたいというケースはレアケースかもしれませんが、どなたかのお役にたてば幸いです。
PHPでGoogleスプレッドシートの値を取得する方法 

## 前提
- Web開発経験なし（環境もなし）
- Mac OS（intel）
- ローカル環境で実施
- Webサイトでスプレッドシートの値を取得したい
- Google Sheets APIを使う

## 作業1 - ターミナル
### 1. homebrewを知る
homebrewとは何？と思ったので以下を参考に気持ち把握する
https://qiita.com/omega999/items/6f65217b81ad3fffe7e6

### 2. homebrewをインストール
1. 以下を参考に実施する（インストール途中、思ったより止まったけど待っていれば完了するはず）
https://qiita.com/zaburo/items/29fe23c1ceb6056109fd

2. Appleシリコンの場合は以下を参考にしてMacがパスを通す（intel前提だけどメモとして）
https://zenn.dev/sprout2000/articles/bd1fac2f3f83bc#1.-%E3%83%91%E3%82%B9%E3%81%AE%E8%A8%AD%E5%AE%9A

### 3. PHPをインストール
1. インストールするPHPのバージョン確認
   今回は既存のプロジェクトどうのこうのではないので以下を見たりして8.0を採用とする
   https://kinsta.com/jp/blog/php-benchmarks/

2. PHP8.0をインストール
   ターミナルで以下を実行
    ```
    brew install php@8.0
    ```

3. PHPのパスを通す
   1. ターミナルで以下を実行してデフォルトシェルが`/bin/zsh`であるかを確認（Catalina以降のMac OSの場合)
        ```
        echo $SHELL
        ```
   2. ターミナルで以下を実行
        ```
        vim ~/.zshrc
        ```
   3. 続けて`i`を入力して実行
   4. 続けて`export PATH="$PATH:/usr/local/opt/php@8.0/bin"をそのまま入力
   5. escキーを押下し`:wq!`を実行（貼り付けると上手くいかないかも）
   6. ターミナルで以下を実行してPHPバージョンが表示されることを確認
        ```
        php -v
        ```
     
        確認結果内容例）
        ```
        PHP 8.0.21 (cli) (built: Jul  7 2022 13:13:21) ( NTS )
        Copyright (c) The PHP Group
        Zend Engine v4.0.21, Copyright (c) Zend Technologies
          with Zend OPcache v8.0.21, Copyright (c), by Zend Technologies
        ```

### 4. Composerをインストール
以下を参考にして、homebrewとPHPの２パターンがあるが今回はPHPでインストール実施
https://labo.kon-ruri.co.jp/composer-macos-install/

## 作業2 - Google Cloud
### 1. Google Cloudの設定とスプレッドシートの準備
1. 基本的には以下に記載されている通りに実施すれば問題なし
https://sterfield.co.jp/programmer/google%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E3%82%B7%E3%83%BC%E3%83%88%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92php%E3%81%A7%E5%8F%96%E5%BE%97/

### 2. 上記のわからなかった箇所の補足（知識なさすぎて）
> 尚、Sheets APIの実行には、事前にComposer(パッケージ依存管理ツール)を使用して、
> 作業ディレクトリにGoogle Client Libraryをインストールしておく必要があります。
> Composer導入後、以下のコードをコマンドラインにてあらかじめ、実行してください。

作業ディレクトリって何？て思いましたが、試した限りだとディレクトリ切ってそこにphpファイルだったりをまとめればOKっぽかったので、

1. 以下のパスになるworkフォルダ（作業フォルダ）を作成
    ```
    /Users/ユーザー名/work
    ```
2. workフォルダに以下のコマンドを実行してGoogle Client Libraryをインストール
   バージョンはとりあえず最新の2.12.6を採用
   https://github.com/googleapis/google-api-php-client/tree/v2.12.6
    ```
    composer require google/apiclient:^2.12.6
    ```

3. workフォルダにvenderフォルダが生成されていることを確認
4. workフォルダに作成した実行するphpフォルダを格納
5. 作業2-1-1で自動生成されたサービスアカウントキーのjsonファイルもworkフォルダに格納
6. phpを実行するためにターミナルで以下を実行（実行方法も知らなかったので...）
   ```
   php /Users/ユーザー名/work/作成したファイル名.php
   ```
   今回はスプレッドシートに4行分書いたのを読み込んだので以下が結果
    ```
    Array
    (
       [0] => Array
           (
               [0] => id
               [1] => name
           )
    
       [1] => Array
           (
               [0] => 1
               [1] => taro
           )
    
       [2] => Array
           (
               [0] => 2
               [1] => jiro
           )
    
       [3] => Array
           (
               [0] => 3
               [1] => saburo
           )
    
    )
    ```

## 参考
https://qiita.com/GcNok/items/2cb7c3501be5c9e92602
https://web-guided.com/1874/
https://dekfractal.com/780.html#PHP8221hello_PHP8221
ゲートウェイサーバーの設定について

### 環境
RedHat5.2


### はじめに
物理的に異なる２つのネットワークがあります。そのネットワークどうしを繋げるためにはどのようにすればいいでしょうか。

物理的に異なるのであれば、各ネットワークのハブどうしを、LANケーブルでカスケードすればいいでしょう。カスケードのインターフェースがなければ、新たにハブを追加することになります。

２つのネットワークのネットワークアドレスが共に同じであれば、それだけの対応で問題ないでしょう。ただし、２つのネットワークの各ノードで、IPアドレスの重複がないことが前提になります。ネットワークアドレスが共に同じということは、つまり、双方のネットワークアドレスが、192.168.19.0であった場合、サブネットも24ビットどうしだということです。

２つのネットワークのネットワークアドレスが異なっていた場合は、それだけでは不十分です。TCP/IPで会話したいと思ったら、ネットワーク層どうしで接続ができるようにする必要があります。

データリンク層でつながるプロトコルであれば、ハブで接続するだけでやりとりができるようになります。データリンク層でつながるプロトコルとは、昔、Windowsで使われてたNetBEUIのようなプロトコルのことです。小規模なネットワークであれば、NetBEUIがデフォルトでWindowsに入っていたため、物理的に接続するだけで、いとも簡単にファイル共有ができるようになるといった時代がありました。IPアドレスの管理などする必要はありません。そのうち、ネットワークの規模が大きくなるにつれて、おしゃべりなプロトコルは、ネットワークに大きな負荷をかけることになり、厄介者扱いされるようになっていきました。インターネットの世界だけで使われていたTCP/IPが、いつやらデファクトスタンダードとなり、社内LANにも標準的に使われるようになってきてからは、NetBEUIのチェックは外すことが推奨されるようになってきました。そしていつのことだろうか、Windowsから消えることに。

さて、話が少しそれました。つまり、ハブはデータリンク層までしかつなぐことができません。ネットワーク層をつなげるには、ハブではなくルーターが必要になります。

### ゲートウェイサーバーの設置
ルーターは新しく購入してもいいが、古いパソコンがあれば、Linuxをインストールして、ゲートウェイサーバーにすることで、ルーターの代用ができます。ただし、NICが２枚必要になります。当然、Linuxに対応できるNICを購入する必要があります。自力で探す他ありません。

ゲートウェイサーバーをたてて、ルーターの役割をさせるためには、ルーティングテーブルを設定する必要があります。当然、スタティック（静的）に設定します。社内LANで、RIPやOSPFを使って、ダイナミック（動的）にルーティングテーブルを設定することは、自分の経験上まずありません。

ルーティングテーブルとはパケットが流れたきたとき、どの方向にルーティングさせるかを指示するための経路表のことです。ルーティング先はIPアドレスから判断して決定します。MACアドレスからではありません。補足になりますが、MACアドレスはルーティングされるのではなく、データリンク層でスイッチングされます。よって、MACアドレスがルーターをまたぐことはありません。





### ルーティングテーブルの設定
ルーティングテーブルを設定するコマンドは**route**コマンドです。**route add**コマンドでルートの追加を行います。実際に行った設定例が下記です。

```
route add -host 127.0.0.1 lo
route add -net 192.168.19.0 netmask 255.255.255.0 eth1
route add -net 192.9.200.0 netmask 255.255.255.0 eth0
route add default gw 192.168.19.7 eth1
```

１行ごとに解説していきます。１行目は、ループバック用のIPアドレスを設定しています。**lo**とはループバックの意味です。ループバックはNICが正常動作しているか診断する時に使います。ループバックに**ping**を投げて帰ってこなければ、NICが故障していると判断できます。NICが故障することは滅多にありませんが、トラブルシュートを行う時、原因の調査で必ず必要になるため、ループバックの設定は必須です。

２行目は192.168.19.0のネットワークにいくときは、eth1のインターフェースからですよという設定です。eth1のNICが、192.168.19.0側のネットワークのハブとLANケーブルで物理的に接続していることになります。

３行目は192.168.200.0のネットワークにいくときは、eth0のインターフェースからですよという設定です。eth0のNICが、192.168.200.0側のネットワークのハブとLANケーブルで物理的に接続していることになります。

４行目はデフォルトゲートウェイは192.168.19.7ですよ。そして、そっちに向かうインターフェースはeth1ですよという設定です。デフォルトゲートウェイは、宛先のIPアドレスが社内LANにない場合に向かう先です。つまり、デフォルトゲートウェイとは、イコール、外部のインターネットのゲートウェイのことと、読み替えて捉えても全くOKです。インターネットで使われるグローバルなIPアドレスは、社内LANには存在しないため、全て、デフォルトゲートウェイに向かわせて、そこから外に出ていきます。

作成したルーティングテーブルは下記のコマンドで確認します。
```
cat /proc/net/route
```

このコマンドで設定内容に誤りがないか、最後に確認をしましょう。
Timberのセットアップ

# 初めに
今回はLogに出力するためによく使われるTimberライブラリのセットアップを備忘録程度に残しておこうと思います。
### 本文
まずは、Timberの初期化を行うためのクラスを作成します。
`BuildConfig`によって分けておくことによって同時に`Crashlytics`の追加もできます。
```kotlin
class TimberInitializer : Initializer<Unit> {
    override fun create(context: Context) {
        Timber.plant(
            if (BuildConfig.DEBUG) {
                Timber.DebugTree()
            } else {
                CrashlyticsTree()
            }
        )
    }

    override fun dependencies(): MutableList<Class<out Initializer<*>>> = mutableListOf()
}
```
次に呼び出しをします。
`Activity`などでは呼び出さず、`Manifest`で直接呼び出しちゃいます。
`name`のところには絶対パスを入れるようにしてください。
```xml
<provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            android:exported="false"
            tools:node="merge">
            <meta-data
                android:name="jp.co.sampleApp.TimberInitializer"
                android:value="androidx.startup" />
        </provider>
```
### 最後に
内容的には自分の備忘録としての役割が強いので、お役に立てるかはわかりませんがもしよかったらご活用いただけると嬉しいです
【Docker】DockerfileのCOPYで権限や所有者を変更する

## 権限の変更
以下のように記述することで変更できます。
```Dockerfile:Dockerfile
COPY --chmod=755 /sample-file /sample-file 
```

## 所有者の変更
以下のように記述することで変更できます。
```Dockerfile:Dockerfile
COPY --chown=ユーザー名:グループ名 /sample-file /sample-file 
```
RX65N搭載ロボットOS（ROS2）が動く小型ボード 国産ボード久々に購入

### ルネサスの案件が有りそうなので　開発環境確認します。
三菱のCPU-M16＆M32は、照明制御の最悪のノイズの中でも20年近く安定動作しています。500個以上は買い販売しました。　久々に日本製、良いですね! 
![DSGR-ROSE.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378482/dbb1d8cc-1595-680b-3456-72ac9b2f50ab.jpeg)

### ROS2も確認したいのでGR-ROSEを購入、GR-SAKURAと併用で進めます。
https://www.renesas.com/jp/ja/products/gadget-renesas/boards/gr-rose

### オンラインコンパイラ　Mbed　比べても遅くてあまり使いたくは有りませんね。
http://tool-cloud2.renesas.com/index.php

### ide4gr LED点滅だけは簡単に動きました
https://www.renesas.com/jp/ja/products/gadget-renesas/ide-gr

### ROS　Wifi接続でつまずきました。中断中です。

### 参考サイト　
残念ながら、GR-ROSEの開発環境であるIDE for GRの最新版は2020年9月のVersion 1.13であり、1年ほど更新されていない状態です。　
学習も　Amazon FreeRTOS　に移行予定です。
https://qiita.com/lutecia16v/items/820199bf6d0d790267e4
Rails/webpackerのバージョン確認

# 書く理由
検索で見つけづらかったのでメモとして

# 確認方法

Railsの下記コマンドでwebpakerをインストールした際にできるpackage.josonに書いてありました。
~~~
rails webpacker:install
~~~
![スクリーンショット 2022-08-03 10.37.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468139/2c452e90-8560-e02f-89bf-e6a742bf5338.png)
React: JSON をテーブルで表示

次の JSON を CORS のヘッダーがある形で受信します。
>Access-Control-Allow-Origin: *

```json:cities_array.json
[
  {"key": "t0921", "name": "宇都宮", "population": 41295, "date_mod": "2003-8-12" },
  {"key": "t0922", "name": "小山", "population": 38756, "date_mod": "2003-5-15" },
  {"key": "t0923", "name": "佐野", "population": 71294, "date_mod": "2003-6-8" },
  {"key": "t0924", "name": "足利", "population": 27138, "date_mod": "2003-7-21" },
  {"key": "t0925", "name": "日光", "population": 74682, "date_mod": "2003-4-19" },
  {"key": "t0926", "name": "下野", "population": 82951, "date_mod": "2003-10-14" },
  {"key": "t0927", "name": "さくら", "population": 96823, "date_mod": "2003-5-24" },
  {"key": "t0928", "name": "矢板", "population": 57926, "date_mod": "2003-2-12" },
  {"key": "t0929", "name": "真岡", "population": 64187, "date_mod": "2003-11-14" },
  {"key": "t0930", "name": "栃木", "population": 82354, "date_mod": "2003-7-04" },
  {"key": "t0931", "name": "大田原", "population": 72681, "date_mod": "2003-9-17" },


  {"key": "t0932", "name": "鹿沼", "population": 23749, "date_mod": "2003-7-20" },
  {"key": "t0933", "name": "那須塩原", "population": 12759, "date_mod": "2003-3-12" },
  {"key": "t0934", "name": "那須烏山", "population": 62531, "date_mod": "2003-8-17" }
]
```

次のように表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/b28e3005-a681-92e3-5f85-e9191cddd30e.png)

プロジェクトの作成と実行

```bash
create-react-app ex05
cd ex05
yarn start
```

次のファイルを書き換えます。

```js:src/App.js
import React, { useState, useEffect } from 'react';
import './App.css';

function TableData() {
    const [data, getData] = useState([])
    const URL = 'https://example.com/cities_array.json';

    useEffect(() => {
        fetchData()
    }, [])


    const fetchData = () => {
        fetch(URL)
            .then((res) =>
                res.json())

            .then((response) => {
                console.log(response);
                getData(response);
            })

              }

    return (
        <>
            <h1>How to display JSON data to table in React JS</h1>
            <table>
            <thead>
                <tr>
                    <th>key</th>
                    <th>name</th>
                    <th>population</th>
                    <th>date_mod</th>
                </tr>
            </thead>
            <tbody>
                {data.map((item, i) => (
                    <tr key={i}>
                        <td>{item.key}</td>
                        <td>{item.name}</td>
                        <td>{item.population}</td>
                        <td>{item.date_mod}</td>
                    </tr>
                ))}

                       </tbody>
            </table>

        </>
    );
}

export default TableData;
```

```css:src/App.css
/* -------------------------------------------------------------- */
/*

        App.css

                                                Aug/03/2022

*/
/* -------------------------------------------------------------- */
td, th {
   border: 1px solid #ddd;
   padding: 8px;
 }

/* -------------------------------------------------------------- */
```
GitリポジトリをBitbucketからGitLabへ移行する

## はじめに
古いプロジェクトでBitbucketを利用していたため、
現在メインで利用しているGitLabへ移行しました。
めんどくさそうと思っていたのですが一括で移行でき簡単でした。

ちなみに作業中、特に問題はないですがBitbucket側でしばらくリポジトリを読み込めない状態になりました。
（GitLabのリンクでBitbucketへ移動するとセッションがおかしくなる？再ログインで戻った）
GitLab側は何も問題なく移行できていました。

## 移行
GitLabにて
Menu > Project > Create new Project > Import project > Bitbucket Cloud

![スクリーンショット 2022-08-02 16.21.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564978/208de654-df19-9774-ab15-f06696f263ca.png)

Bitbucketへ移動するのでアクセス許可する

Import projects from Bitbucket
という画面へ移動するので、
それぞれ「To GitLab」と書かれた移行先URLの項目を設定、確認してから右側のImportボタンを押す
すべて移行で問題なければ左上の「Import n Repository」を押してもOK
※この画面でBitbucketへのリンクで飛ぶとBitbucket側のセッションがおかしくなり、ログアウトせざるをえなくなりました

これだけで移行は完了です。

## 移行後の処理
ローカルのGitの紐付けを変更します。


```
$ git remote -v
origin	git@bitbucket.org:example/example.git (fetch)
origin	git@bitbucket.org:example/example.git (push)
```
で現在の設定を確認

```
$ git remote set-url origin [new ssh url]
```

e.g.)$ git remote set-url origin git@gitlab.com:example/example.git
を実行することでGitLabへの接続設定を保存

```
$ git remote -v
origin	git@gitlab.com:example/example.git (fetch)
origin	git@gitlab.com:example/example.git (push)
```

で@gitlabとなっていることを確認できたらOK
$ git pull などを実行して接続できることを確認

以上で完了です。
不安であれば簡単なコミットをpushして確認するとよいです。

## 参考
[【git】リポジトリの移行時などでremote urlを変更する](https://kde.hateblo.jp/entry/2018/02/18/200459)
STEPをAssemblyとしてインポートする

今見たら普通に読み込んでTreeViewのオブジェクトの左にある三角形押したら出たね…

![Screenshot from 2022-10-06 16-03-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29692/6726dc65-c889-e602-08b4-84c15c57c035.png)

せっかくなのでSTLをSTEPから抜き出すスクリプトも置いときます

```py:extractSTLFromSTEP.py
#!/usr/bin/env freecadcmd
import FreeCAD
import Mesh

import os
import sys
#print(sys.argv)
if len(sys.argv)<2:
    raise Exception("specify filenames")
for filename in sys.argv[2:]:
    basename = os.path.basename(filename)
    if '.' not in basename:
        raise Exception("fname does not contain '.'")
    dirname = os.path.join(os.path.dirname(filename), basename.rsplit('.',1)[0])
    os.makedirs(dirname, mode=0o755, exist_ok=True)
    FreeCAD.loadFile(filename)
    doc = FreeCAD.activeDocument()
    for obj in doc.findObjects():
        if obj.TypeId == 'Part::Feature':  # check for 'Part' for whole object
            Mesh.export([obj], os.path.join(dirname, obj.Label+'.stl'))
    FreeCAD.closeDocument(doc.Name)
```

以下は不必要な情報です、失礼しました。

----

- Tools -> Addon Managerから **Assembly3** をインストールする
- Workbench(メニュー)をAssembly3に変更する
- Import from STEP

あとはTree viewからパーツを選択可能になります、選択した状態でSTL Exportすることもできます

- Assembly2にもImport機能がありますがFreeeCAD 0.19では動きませんでした
- A2Plus/Assembly4にはImport機能がなさそうでした
画面を閉じてもターミナル上のプログラムを止めないようにする！

# Macを閉じたらターミナル上のプログラムが止まっちゃう・・・
ターミナル上で長時間の計算を行う際、画面を閉じてしまうとプログラムが止まってしまいますよね。
Macはディフォルトで画面を閉じるとスリープしてしまいます。
スリープモードになると計算が止まってしまうんですよね。

そこで今回は、スリープモードへの移行を防ぐ方法を紹介します。

# スリープを無効にするコマンド
以下のコマンドでスリープを無効化できます。
```
sudo pmset -a disablesleep 1
```
スリープができたか以下で確認します。
画像の赤矢印部分が　1 になっていれば、無効化が成功しています！
```
pmset -g
```
<img width="400" alt="sleep.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2519906/6c4e1481-d8ac-5d6c-fa3e-5d4a12154d05.png">

# スリープを有効にするコマンド
```
sudo pmset -a disablesleep 0
```

#　終わりに
これでスリープ無効はできます！
既存のプロジェクトを monorepo プロジェクトに移行する手順

# 既存のプロジェクトを monorepo プロジェクトに移行する手順

## 現在開発中のプロジェクトを `monorepo` として扱えるようにするための手順

`npm workspace` を使用します。

### 1. 新しいプロジェクトを作成

```bash
mkdir sample
cd sample
npm init
```

### 2. package.json を編集

```json:pakcage.json
{
  ...,
  "private": true // 追加
}
```

### 3. workspace を追加

```bash
npm init -w packages/pack1
```

このコマンドを実行することで、プロジェクト直下に`packages/pack1`ディレクトリが作成されます。

```bash
$ tree
sample
|- packages
 |- pack1
  |- packages.json
```

また、ルートの`package.json`が以下のように変更されます。

```json:package.json
{
  ...,
  "workspaces": [
    "packages\\pack1"
  ]
  ...
}
```

### 4. 開発用の依存パッケージを、全ての workspace から使用できるように変更

`eslint`や`prettier`などのリンターやフォーマッター、あるいは`typescript`や`babel`といったトランスパイラなど、各 workspace で共通して使用する可能性のあるパッケージは、ルートプロジェクトにインストールします。

インストール方法は、通常の手順と同じです。

```bash
npm i -D <package name>
```

逆に、各 workspace に個別でインストールする場合は、以下のようにします。

```bash
npm i -w packages/pack1 -D <package name>
```

以下は、共通して使用する可能性のあるパッケージの一例です。

- typescript
  - ts-node
  - @types/node
- jest
  - ts-jest
  - @types/jest
  - @jest/types
- prettier
- eslint
  - eslint-config-prettier
  - @typescript-eslint/eslint-plugin
  - @typescript-eslint/parser
- rimraf
- npm-run-all
- simple-git-hooks

### 5. 既存プロジェクトのデータを、作成した workspace に移動

node_modules を除く、全てのファイル・ディレクトリをコピーします。この時、ルートプロジェクトにインストールしたパッケージと重複するものがある場合、`package.json`から削除しておきます。

### 6. workspace ごとに、必要なパッケージをインストール

```bash
npm i -w packages/pack1
```

## workspace 間で、相互に参照

ルートプロジェクトで`npm install`を実行すると、**node_modules**配下に各 workspace のシンボリックリンクが作成され、workspace 間で相互に参照できるようになります。

```bash
npm install
```
Ruby学習アウトプット　

転職活動において、技術試験がいくつか出されており、改めてこちらの本でRubyの勉強をしています。
https://www.amazon.co.jp/%E7%8F%BE%E5%A0%B4%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B-Ruby-Rails-5%E9%80%9F%E7%BF%92%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89-%E5%A4%A7%E5%A0%B4%E5%AF%A7%E5%AD%90/dp/4839962227
そのアウトプットとして、よくRailsでみるRubyの記法が解説されていたので、アウトプットさせてください。


## nilガード

```
number||=10
```
上と下は同じ意味

```
number||(number= 10)
```

もしもnumberがあれば、number なければnumberに１０を代入する

### 使うとき
- 変数にnilが入っているかもしれない状況で、nilの代わりになにかデフォルト値を入れておきたい場面で使う
- 認証のcurrent_userとかで使うイメージ

## ボッチ演算子

`&.`記法のこと

`&.`を使って演算子を使ってメソッドを呼び出すと、レシーバーがnilで合った場合でもエラーが発生しなくなる

正式名称は「safe navigation operator」

if文や三項演算子を使ってこのように記載するか、
```Ruby
name= object ? object.name : nil
```

こうかける
```Ruby
name=object&.name
```
上下のコードは同じ意味になる

## %記法

すべての要素が文字列である配列は「％ｗ」を使ってかける

```Ruby
> ary1 =['apple','banana','orange']
=> ["apple", "banana", "orange"]
> puts ary1
apple
banana
orange
=> nil
```

```Ruby
> ary2 = %w(apple banana orange)
=> ["apple", "banana", "orange"]
> p ary2
["apple", "banana", "orange"]
=> ["apple", "banana", "orange"]
```

すべての要素がシンボルの場合、「%i」

```Ruby
> ary3=[:apple,:banana,:orange]
=> [:apple, :banana, :orange]
> p ary3
[:apple, :banana, :orange]
=> [:apple, :banana, :orange]

> ary4=%i(apple banana orange)
=> [:apple, :banana, :orange]
> p ary4
[:apple, :banana, :orange]
=> [:apple, :banana, :orange]
```

このように書くほうが、可読性が高くなる

## 配列の各要素から特定の属性だけを取り出す

```Ruby
class User
    attr_accessor :name
    # name属性を付与 
end

user1=User.new
user1.name= 'Aさん'

user2=User.new
user2.name= 'Bさん'

user3=User.new
user3.name= 'Cさん'

users=[user1,user2,user3]
```

このコードではusers配列に３つのUserオブジェクトが入っている。
この配列からname情報のみの取得をする場合。

いくつかパターンがある

### eachと<<を使う方法

```Ruby
# names配列を定義
names=[]

# users配列からname属性をnames配列へ格納していく
users.each do |user|
   names << user.name 
end
```

## mapを使う方法

mapメソッドは配列に対してブロック（do 〜　endの中で指定した処理）を実行した結果を格納した新しい配列を返す

```Ruby

names=users.map do |user|
    user.name
end
```

ブロックは｛｝でも記述できる

```Ruby
names=users.map{|user| user.name}
```

＆とシンボルを使って次のようにもかける
```Ruby
names=users.map(&:name)
```

※ちなみに&はto_procメソッドの略らしい。
to_iは整数に直すのはよく見るが、to_procとはProcクラスにするメソッドのようです
https://style.potepan.com/articles/29663.html#:~:text=Proc%E3%81%A8%E3%81%AF%E3%80%8C%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E3%82%92,%E6%B8%A1%E3%81%99%E3%81%93%E3%81%A8%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82

## 感想
いままで(&:)の意味がわからなかったけど、to_procメソッドとシンボルの組み合わせと知ることができた

コードを書きながら０からかけるようにして、自分のものにしていきたい。
【Oracle】オブジェクト権限の数を権限の種類ごとにカウントする【SQL*Plus】

`where`句の後は適宜変更。
`tp.OWNER = 'OWN_USER'`
`tp.GRANTEE = 'GRA_USER'`
OWN_USERが付与元(テーブル所有者)、GRA_USERが付与先です。
`ob.OBJECT_TYPE = 'TABLE'`
オブジェクトタイプ指定はあったほうが便利なので。
(例えば、全テーブルに権限付与するとき、dba_tablesからcount(*)したものと一致してるか、みたいな使い方)

`col ~~~ for a20`の`a20`は文字数に合わせて変えます。
```sql*plus:
set lin 300
set pages 300
col owner for a20
col grantee for a20
col privilege for a20
col object_type for a20

select tp.OWNER,tp.GRANTEE,ob.OBJECT_TYPE,tp.PRIVILEGE,count(*)
from dba_tab_privs tp 
inner join
dba_objects ob on
tp.TABLE_NAME = ob.OBJECT_NAME and
tp.OWNER = ob.OWNER
where
tp.OWNER = 'OWN_USER' and
tp.GRANTEE = 'GRA_USER' and
ob.OBJECT_TYPE = 'TABLE'
group by tp.OWNER,tp.GRANTEE,ob.OBJECT_TYPE,tp.PRIVILEGE
order by 1,2,3,4;
```
実行例サンプル。
```sql
OWNER                GRANTEE              OBJECT_TYPE          PRIVILEGE              COUNT(*)
-------------------- -------------------- -------------------- -------------------- ----------
OWN_USER             GRA_USER             TABLE                DELETE                       10
OWN_USER             GRA_USER             TABLE                INSERT                       10
OWN_USER             GRA_USER             TABLE                SELECT                       10
OWN_USER             GRA_USER             TABLE                UPDATE                       10
```
Rechartsで凡例をカスタマイズする


Rechartsを使って凡例のフォーマットを変更する必要があったので調査しました。

```react
    <LineChart
      width={600}
      height={300}
      data={data}
      margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
    >
      <CartesianGrid strokeDasharray="3 3" />
      <XAxis dataKey="name" />
      <YAxis />
      <Tooltip />
      <Legend formatter={renderColorfulLegendText} />
      <Line
        type="monotone"
        dataKey="hoge"
        stroke="#8884d8"
        activeDot={{ r: 8 }}
      />
      <Line type="monotone" dataKey="fuga" stroke="#82ca9d" />
    </LineChart>
```
```Legend```で```formatter```で関数を指定すれば凡例を操作できます。   

```react
const colorList = ["#FFFFFF", "#00C49F", "#FFBB28", "#FF8042"];
const renderColorfulLegendText = (value: string, entry: any, index:　number) => {
  const color  = colorList[index];
  return <span style={{ color }}>{value}</span>;
};
```
サクラエディタの設定が反映されない件

サクラエディタにて、共通設定やタイプ別設定のあと、エディタを開いても初期設定のままという時の備忘録。

サクラエディタのインストール時に次のチェックを外していることが原因かもしれないので、再インストールをしてみよう。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759593/2b291a85-6321-8b66-99be-959f44140cb3.png)

サクラエディタは、次のGitHubで入手できる。
[リリース]
　https://github.com/sakura-editor/sakura/releases

解決した人はここまで。


ここからは、まだそれでも解決しない人向け。


「ん？インストールしてないぞ？！」という人は、圧縮版をダウンロードしている可能性あり。

![２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759593/10b2c2af-cc4e-7f50-4f0d-2ff877aa0b58.png)


インストーラでない＝リリース版は、圧縮ファイルなので解凍しただけで利用できる。

貸出PCを利用してる場合は、管理者権限の都合で、このリリース版を使っている人も多いだろう。
インストールしなくても不便はないが、今回のように設定を保存したいときはインストール版で、保存設定する必要がある。
GoogleAppsScript(GAS)からQiitaAPIを使ってQiita投稿記事を更新する。

GoogleAppsScript(GAS)からQiitaAPIを使ってQiita投稿記事を更新しました。その際のソースコードを備忘録として残します。
前回：[GoogleAppsScript(GAS)からQiitaAPIを使ってQiita投稿記事(限定共有記事)を投稿する。
](https://qiita.com/Pell/items/598f4af4c2a9bb99c5dd)

# 本記事の環境

※PCに環境構築を行う必要はありません。
WEBブラウザ(Google Chome)
Googleアカウント

# 使用技術

GoogleAppsScriptのみ。

# 事前準備

* Qiitaにて、「設定」から「アプリケーション」を選択する。
* 「個人用アクセストークン」を発行する。※私は読み書き権限両方を付けました。
* 発行した「個人用アクセストークン」をメモする。※後で入力します。

# 手順

* 以下の成果物をGoogleスプレッドシート/拡張機能/Apps Scriptにコピー&ペーストし、「アクセストークン」と「投稿記事タイトル」と「投稿記事ID」を書き換える。
* 「実行」ボタンを選択して、実行が終わるまで少し待つ。
  * 初回は、承認、Googleアカウントへのログイン、リクエストの許可が求められる。
* 実行が終わったら実行ログを確認する。
* 実行ログに問題がなければQiitaの投稿記事を確認する。

# 所感

* Qiita記事の投稿、更新で処理に大きな違いはなく難しくなかった。
* GoogleAppsScript(GAS)からQiita記事を投稿、更新できたので、次回は自投稿記事のランキングを作成し自動更新させます。

# 成果物

```javascript
// 全権限トークン
const TOKEN_ALL2 = "[発行したトークン]";
// 投稿記事タイトル
const ITEM_TITLE2 = "[投稿記事タイトル]";
// 投稿記事ID
const ITEM_ID = "[投稿記事ID]";

// 記事更新処理
function updateQiitaTest() {
  const apiUrl = "https://qiita.com/api/v2/items/" + ITEM_ID;
  const item_data = {
    'body' : "# Example",       // 投稿記事本文
    'title' : ITEM_TITLE2,      // 投稿記事タイトル
  };
  const headers = {'Authorization' : 'Bearer ' + TOKEN_ALL2};
  const params = {
    'method' : "patch",
    'contentType' : "application/json",
    'payload' : JSON.stringify(item_data),
    'headers' : headers,
    'muteHttpExceptions' : false
  };

  const response = UrlFetchApp.fetch(apiUrl, params);
  if (response.getResponseCode() >= 300) {
    Logger.log("記事更新失敗 : " + response.getContentText());
  } else {
    const obj = JSON.parse(response.getContentText());
    Logger.log("記事更新成功 : title[" + obj.title + "]、url[" + obj.url + "]");
  }
}
```
PostgreSQL の TIMESTAMPTZ 型はタイムゾーンに関する情報を保持しない

PostgreSQL の TIMESTAMPTZ 型について誤解していた部分があったので記事にします。以下の記事を参考にさせていただきました。

https://qiita.com/yuba/items/7852a29d63d6279c6f6e

## この記事で伝えたいこと

- TIMESTAMPTZ 型はタイムゾーンに関する情報を保持しない
- DB に設定されているタイムゾーンで挙動がかわってしまう操作があるので注意が必要

## TIMESTAMPTZ 型はタイムゾーンに関する情報を保持しない

TIMESTAMPTZ 型は、_timestamp with time zone_ という名前にも関わらず、**タイムゾーンの情報を持たない**。

#### 実験:

タイムゾーンの異なる、同じ日時の値を SELECT してみる → **SELECT して表示される日時のタイムゾーンは同じ**

```sql
SELECT '2022-07-31 12:53:00+00'::TIMESTAMPTZ; -- 2022-07-31 21:53:00+09
SELECT '2022-07-31 21:53:00+09'::TIMESTAMPTZ; -- 2022-07-31 21:53:00+09
```

「日」で切り詰めてみる → **切り詰められた日時は同じ**

```sql
SELECT date_trunc('day', '2022-07-31 12:53:00+00'::TIMESTAMPTZ); -- 2022-07-31 00:00:00+09
SELECT date_trunc('day', '2022-07-31 21:53:00+09'::TIMESTAMPTZ); -- 2022-07-31 00:00:00+09
```

TIMESTAMPTZ 型は単に **UTC 時間だけ**を保持するようなものだと思われる。

## DB に設定されたタイムゾーンで挙動がかわる操作

たとえば、以下のような場合に挙動の違いがありそう:

- DB のタイムゾーンによって挙動が変わる関数を利用するとき
- タイムゾーンコードを渡せる関数にタイムゾーンコードを渡さずデフォルトのタイムゾーンを利用しているとき
- TIMESTAMP 型を受け取る関数に TIMESTAMPTZ 型の値を渡すとき
- TIMESTAMP 型の値を TIMESTAMPTZ にキャストするとき

以下のような関数を利用するとき、意図しないタイムゾーンの変換をしてしまっているかもしれない。

- `date_trunc`（日や月で切り詰めるとき、など）
- `to_char`（文字列に変換するとき、など）
- `to_timestamp`（文字列から変換するとき、など）

#### 挙動が変わってしまう例

以下のような書き方のコードだと、DB に設定されたタイムゾーンによって挙動が変わることがある。

```sql
SELECT date_trunc('day', now());
SELECT to_char(('2022-08-02 23:00:00+00'::TIMESTAMPTZ), 'YYYY/MM/DD');
SELECT to_timestamp('20220802', 'YYYYMMDD');
```

以下のような書き方をすると DB に設定されたタイムゾーンを気にしなくてよくなる。

```sql
SELECT date_trunc('day', now(), 'UTC');
SELECT to_char(('2022-08-02 23:00:00+00'::TIMESTAMPTZ) AT TIME ZONE 'UTC', 'YYYY/MM/DD');
SELECT to_timestamp('20220802', 'YYYYMMDD')::TIMESTAMP AT TIME ZONE 'UTC';
```

#### 実験

DB のタイムゾーンによっては結果が変わる書き方:

```sql
SET TIME ZONE 'Asia/Tokyo';
SELECT date_trunc('day', now()); -- 2022-08-02 00:00:00+09
SELECT to_char(('2022-08-02 23:00:00+00'::TIMESTAMPTZ), 'YYYY/MM/DD'); -- 2022/08/03
SELECT to_timestamp('20220802', 'YYYYMMDD'); -- 2022-08-02 00:00:00+09

SET TIME ZONE 'UTC';
SELECT date_trunc('day', now()); -- 2022-08-02 00:00:00+00
SELECT to_char(('2022-08-02 23:00:00+00'::TIMESTAMPTZ), 'YYYY/MM/DD'); -- 2022/08/02
SELECT to_timestamp('20220802', 'YYYYMMDD'); -- 2022-08-02 00:00:00+00
```

タイムゾーンによらず同じ値を返す書き方:

```sql
SET TIME ZONE 'Asia/Tokyo';
SELECT date_trunc('day', now(), 'UTC'); -- 2022-08-02 09:00:00+09
SELECT to_char(('2022-08-02 23:00:00+00'::TIMESTAMPTZ) AT TIME ZONE 'UTC', 'YYYY/MM/DD'); -- 2022/08/02
SELECT to_timestamp('20220802', 'YYYYMMDD')::TIMESTAMP AT TIME ZONE 'UTC'; -- 2022-08-02 09:00:00+09

SET TIME ZONE 'UTC';
SELECT date_trunc('day', now(), 'UTC'); -- 2022-08-02 00:00:00+00
SELECT to_char(('2022-08-02 23:00:00+00'::TIMESTAMPTZ) AT TIME ZONE 'UTC', 'YYYY/MM/DD'); -- 2022/08/02
SELECT to_timestamp('20220802', 'YYYYMMDD')::TIMESTAMP AT TIME ZONE 'UTC'; -- 2022-08-02 00:00:00+00
```

以下のようになっていればこの記事の内容を気にしなくて済むかもしれない。

- 「DB のタイムゾーンは UTC にする」などの決まりがあって、それが開発メンバーに共有されている
- タイムゾーンが絡む操作はテストされた共通の関数を利用する
ルートゾーンLGR とは

## 勉強前イメージ

DNSのルートゾーンとLGR？？

## 調査

### ルートゾーンLGR とは

Root Zone Label Generation Rules の略で、日本語でルートゾーンラベル生成ルールと呼ばれています。
トップレベルドメインの空間に関するルールで、国際化ドメイン名を使用する際に利用できる文字列(ラベル)を規定したルールになります。

トップレベルドメイン(TLD)とは ドットで区切られた一番右の `.jp` や `.com` の部分のことを指します。
ちなみにセカンドレベルドメイン(2LD) はドットで区切られた2番目の `co` などを指します。
また国際化ドメイン名とは英数字(ASCII)以外の文字を使えるようになったものになり、日本語のドメイン名は国際化ドメイン名の一つです。
国際化ドメイン名は略してIDNと言われています。

つまり、 `.jp` ドメインなどで日本語など英数字以外を使用する際の文字列のルールになり
このルートゾーンLGRに従ったものだけがルートゾーンに登録することができます。

### ルートゾーンLGR の2つのプロセス

1. 生成パネル(GP)
	各言語の有識者や言語の専門家から構成される、ラベル作成ルールを作成するためのパネル
	TLDごとに組織とされます。

2. 統合パネル(IP)
	国際化ドメイン名の専門家により構成される、各言語で作成された各生成パネルの整合性を取って一つにするためのパネル
	これは1つだけです。

## 勉強後イメージ

知らない言葉いっぱい出てきた・・・・
日本語のドメイン使えるよ、みたいなのは昔見たことあるけど
このルートゾーンLGRを経て、使える文字が決まるってことかー
各TLDについては [ここ](https://qiita.com/miyuki_samitani/items/d2a6224728535bde3df4) で調べてたりしてます。

## 参考

- [ルートゾーンLGRとは](https://www.nic.ad.jp/ja/basics/terms/rootzone-lgr.html)
- [トップレベルドメインのラベル生成ルール「ルートゾーンLGR」の概要](https://jprs.jp/related-info/guide/topics-column/no25.html)
100日後くらいに個人開発するぞ！day064

## 今日はWebアプリケーションについて学んでみた！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2632394/852b13fc-6588-839a-b80b-1fc093ce3cec.png)



## 今日の学び
### Webアプリとは
* HTMLだけで作成されたWebサイトは作成者が更新しない限り毎回同じものが表示される
* Webアプリではメモを追加・閲覧するなど高度な機能をもつことができる
* WebアプリはiOSやAndroidなどのスマホアプリと異なり、ブラウザから使うアプリ


### Webアプリの仕組み
* Webアプリの処理
    * ブラウザがサーバーにリクエストを送る
    * サーバーはリクエストの内容(URLなど)に応じて処理を実行
        * 処理の例
            * データベースの操作やデータの取得・追加・更新・削除
            * データベースのデータをHTMLへ変換しページ内容を変更
    * 処理したHTMLをブラウザに返す
    * ブラウザにHTMLが表示される

### Webアプリの開発に必要なプログラミング言語
* ブラウザ上で必要な言語（クライアントサイド）
    * HTML
    * CSS
    * Java Script
* サーバーサイド
    * Node.js
    * Ruby
    * Python
    * PHP
* データベース
    * SQL
Docker Desktopの代わりにRancher Desktopを使用しています。

Docker Desktop が有償化されましたので、会社から支給されている Windows PC 環境で使用できる代替プロダクトを色々とゴニョゴニョと試していました。テレワークで VPN を使用するためにインストールされている Cisco AnyConnect との相性もよく、「使いやすいな」と思えるプロダクトをみつけましたので、メモしておきます。

その名も Rancher Desktop です。オープンソースですが、開発主体は SUSE、ライセンスは Apache License, Version 2.0 です。Windows、Mac、Linux の各OSで利用できます。

https://rancherdesktop.io/

インストールは、Windows の場合、インストーラーをダウンロードして、実行するだけです。前提条件もありますので、公式のドキュメントを参照してください。

https://docs.rancherdesktop.io/getting-started/installation

Docker に慣れていれば、使用も簡単です。公式のドキュメントをパッと眺めるだけで、簡単さが伝わると思います。

https://docs.rancherdesktop.io/tutorials/working-with-containers

現在まで、開発時に開発者の環境で手軽に動かす分には、特に問題なく使用できています。開発者の手元を離れる場合は、AWS、GCP、Azure といったクラウド環境でコンテナを動作させることが多いと思います。従って、プロダクションやステージング環境では使用していませんが、おすすめできるプロダクトです。