OmniAICreator/Qiita-1.07M huggingface dataset:
【React】Reactの環境構築（M1 mac）

## Reactの環境構築（M1 mac）

### Node.jsをインストール
まず、以下の手順でNode.jsがインストールされているか確認します。

```:ターミナル
$ node -v
v16.14.0
```

`node -v`を実行して上記のようにバージョンが表示された場合には、すでにNode.jsがインストールされていますので、Node.jsのインストールはスキップしてください。
表示されない場合にはインストールが必要になりますので次の手順でインストールを行なってください。
尚、Node.jsのインストール方法には今回記載する方法の他にnodebrewを使用する方法等がありますので、興味のある方は調べてみてください。
今回は、Node.jsのホームページからインストールする方法をご紹介します。

まず、以下のURLにアクセスしてください。

https://nodejs.org/ja/

下画像のページが表示されると思いますので赤枠の推奨版をクリックします。

![スクリーンショット 2022-02-20 23.35.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/a25785b2-7c7c-ddef-95c7-9ea31d9e0be5.png)

すると、.pkgファイルがダウンロードされますのでファイルを実行します。
「Node.jsをインストール」というウィンドウが開きますので内容を確認しながらインストールまで進めます。

インストールが完了したら、最後にインストールされているか確認します。
ターミナルで以下のコマンドを実行してください。

```:ターミナル
$ node -v
v16.14.0
```

上記のようにバージョンが表示されればインストールができています。

### create-react-appを実行
Node.jsのインストールが完了したらcreate-react-appを実行します。
create-react-appの詳細については以下のページをご参照ください。

https://ja.reactjs.org/docs/create-a-new-react-app.html#create-react-app

create-react-appを実行するには、ターミナルで以下のコマンドを実行します。

```:ターミナル
$ npx create-react-app test-app
```

`npx create-react-app 任意のアプリケーション名`を実行することで新たにアプリケーションを作成することができます。

次に作成したアプリケーションのフォルダに移動し、以下の手順で動作確認を行います。

```:ターミナル
$ cd my-app
$ npm start
```

上記コマンドを実行後にブラウザで http://localhost:3000/ にアクセスします。（自動でブラウザが開かれると思います。）

以下の画面が表示されれば正常に動作しています。

![スクリーンショット 2022-02-21 0.01.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/4ec5baef-37dd-106b-e6e5-68701c52ae15.png)
[ECS/Fargate]RailsコンテナにECS Execログインする


# はじめに
ECS Execを使用することで、SSHを介さずFargate上で動作するコンテナに対しdocker execコマンドを実行することができます。

# 前提
既に、ECS上で下記リソースを作成済みであること
- クラスター
- サービス
- タスク定義


# IAMポリシー
ECSの[タスク定義]-[タスク実行ロール]で使用するIAMポリシーの設定値です。

AmazonECSTaskExecutionRolePolicy.json

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:GetAuthorizationToken",
                "ecr:BatchCheckLayerAvailability",
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}
```

ecs_task_role_exec.json

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssmmessages:CreateControlChannel",
                "ssmmessages:CreateDataChannel",
                "ssmmessages:OpenControlChannel",
                "ssmmessages:OpenDataChannel"
            ],
            "Resource": "*"
        }
    ]
}
```

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_execution_IAM_role.html


# aws cli2のインストール
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv2-mac.html#cliv2-mac-install-gui

# Session Manager プラグインをインストール


```shell
curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/mac/sessionmanager-bundle.zip" -o "sessionmanager-bundle.zip"
unzip sessionmanager-bundle.zip
sudo ./sessionmanager-bundle/install -i /usr/local/sessionmanagerplugin -b /usr/local/bin/session-manager-plugin

# インストールが完了したか確認
session-manager-plugin
```

# ECS Execの有効可

```shell
CLUSTERNAME="ecs-rails-cluster"
SERVICENAME="ecs-rails-service"
TASKDEFNAME="ecs-rails-def"
CONTAINERNAME="app"

aws ecs update-service \
    --cluster $CLUSTERNAME\
    --service $SERVICENAME \
    --enable-execute-command \
    | grep enableExecuteCommand
```

## タスクを強制デプロイ
```shell
aws ecs update-service \
    --cluster $CLUSTERNAME \
    --service $SERVICENAME \
    --task-definition $TASKDEFNAME \
    --force-new-deployment
```


## Fargateにログイン
```
TASKNAME=`aws ecs list-tasks --cluster $CLUSTERNAME --query "taskArns[0]" --output text`

aws ecs execute-command \
    --cluster $CLUSTERNAME \
    --task $TASKNAME \
    --container $CONTAINERNAME \
    --interactive \
    --command "/bin/sh"
```


# 参考資料
https://dev.classmethod.jp/articles/ecs-exec-for-fish-shell/
https://qiita.com/notakaos/items/eda64c3c38b17f181698
RaspberryPi4 crontabが発火しない

## 環境

ちょっとした検証環境として新規作成。

| Pi | 使用イメージ |
| ---- | ---- |
| 4B |  64 bit Raspberry Pi OS Lite<BR>https://downloads.raspberrypi.org/raspios_lite_arm64/images/raspios_lite_arm64-2022-01-28/|

加えて以前投稿した[スクリプト](https://qiita.com/god19/items/cbfb04b4f6333009b633 "Rapberry Pi 初期設定の半自動化 シェルスクリプト版 - Qiita")で初期設定。
更に加えて[こちら](https://web.archive.org/web/20210517004054/http://garastyle.xyz/raspberrypi-fixed-term-report "Raspberry Piに自身の状態を定期報告させる")を参考にした定期報告を`crontab`に設定。（※ 今回投稿にあたり久しぶりに確認しようとしたらアクセスできなかったので Internet Archive から発掘）

## 問題発覚
環境構築の数日後、`crontab`で設定したスクリプトが発火していない（しなくなった）ことに気が付いた。
`crontab`が動かない。よくある問題でぐぐると多数の情報が見つかる。
まず確認すべきは、`crontab`サービスが動いているか。`Active:`項目が`active (running)`であれば OK。

```shell-session
pi@raspberrypi4:~ $ sudo systemctl status cron
● cron.service - Regular background program processing daemon
     Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2022-02-16 01:12:49 JST; 4 days ago
       Docs: man:cron(8)
   Main PID: 430 (cron)
      Tasks: 1 (limit: 4165)
        CPU: 25.506s
     CGroup: /system.slice/cron.service
             mq430 /usr/sbin/cron -f
```

次は設定したコマンドが動くか。自分が`crontab`に設定したコマンドは以下。深夜0時に定期報告メールを飛ばすもの。

```shell
00 00 * * * sh state.sh | mutt -F mutt.conf -s "pi4定期報告" ***@gmail.com
```

`sh state.sh | mutt -F mutt.conf -s "pi4定期報告" ***@gmail.com`をコピペでコマンドラインに流し込み実行。
返ってこない。えぇ？
更に確認すると、`state.sh`スクリプト内の以下、`df -h`で返ってこないことが分かった。

```shell
# ファイルシステム
df -h
```
これもよくある問題らしく、ぐぐると多数情報が見つかる。
そういえば別の Pi で、USB外付けHDD を接続し 24時間稼働しているものがあり、そちらも時々`df`コマンドが返ってこない現象が発生する。使い古しの USB外付けHDD なので、それが原因と思われるが、一時的なデータしか保持しない用途であることと、再起動すると大抵直るので放置している。

実は今回 Pi4B の環境作成に使用した microSDカードも　Pi3時代からの使い古しで、`Win32DiskImager`でイメージを吸い出そうとすると極端に速度が遅い上にエラーで停止するという症状が発生するようになり使用を中止（放置）していたもの。
最近、パーティションの解放、再完全フォーマット等を行ったら使えるようになったっぽいので、その検証も兼ねていた。

という経緯があるので、microSDカードが原因の可能性が極めて高いが、再起動したら`df`コマンドで固まる問題は一応解決。取り合えずこれでよしとする。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254888/bb7f02cd-c198-ff14-9d8b-876c601310c6.jpeg" width=50%>
（ダメだろ）

## 次の問題
しかし 0時になってもメールが飛んでこない。他の Pi も同様の設定が施してあり、毎日 0時に複数のメールが飛んでくる状況だけど、Pi4B だけ飛んでこない。
改めて Pi4B に`ssh`接続し、状況確認。あれれ……。ファイルのタイムスタンプがおかしい……。
そういえば`raspi-config` でローカライズ設定していなかった……。＿|￣|○
デフォルト設定、世界標準時間のままだった。
初歩的過ぎる事項ってぽっかり抜けることがあるよなぁ。という自戒を込めた備忘録。

[Raspberry Pi Documentation - Configuration](https://www.raspberrypi.com/documentation/computers/configuration.html "Raspberry Pi Documentation - Configuration")
システムエンジニア（？）の日常と属人化の恐怖

技術記事じゃないけど、まっとうなエンジニアライフを送るために、反面教師として役立てて頂ければ幸いです。
やさしさがほしい。。。

# 技術力特化なエンジニアが技術力特化じゃない部署に所属すると・・・

## 問題解決能力がアダになる

経験上、周囲との技術レベル差が大きいとき、技術スキルと仕事のヒエラルキーは逆転する。
しかも放っておくと学習は強化される。

技術力があるほど突発的なトラブルに巻き込まれてしまう。
ほかの人が解決できなかった仕事が依頼されてくるので、依頼関係のフローとしてはヒエラルキー最下層に位置してしまう。
解決難易度も相対的に高くなる。結果的にますます技術力が磨かれていく。
ビジネスマン的には解決できるところに仕事を切り出すのが良しとされる風潮があると思うけど。半分正しくて半分間違っている気がする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438183/094928e4-c3c5-2b76-39c9-bd2e59cd8130.png)

## 周囲が育たない

「締め切り今日中ね！」とかの短納期トラブルを個人プレーで解決してしまい、周囲の問題解決能力が伸びない。
それが組織学習上のダメな行為だとわかっていてもプレッシャーと時間に負けてしまい、生みの苦しみの壁を超えられない。
手順書や説明資料を残したとて、自力で解決していないと解決能力が伸びない。
下記の本で言われているダメな行為そのもの。

https://www.google.co.jp/search?q=%E5%AD%A6%E7%BF%92%E3%81%99%E3%82%8B%E7%B5%84%E7%B9%94%E5%85%A5%E9%96%80

## 外から見て大変さがよくわからない／負荷が読めない

特にソフトウェアの仕事は、畑違いの人からは理解されづらい。
そもそも当の本人も、依頼の概要やトラブルの一次情報だけだど難易度がよくわからないことも多々ある。
ソフトウェアエンジニアの生産性は数百倍の開きがあるという説もある。
「どうすればできる？」とか「分担しよう」ってなっても、短期的にはスキル的に引きはがせない。
「何人必要？」って言われるけど重要なのは人数じゃない。

トラブルだらけで今日明日の負荷すら予測できない。
自宅でも仕事できてしまうため、ブラックボックス化が加速していく。なぜか出勤日は仕事の消化量がマイナスで、休日に補填しようとし始める。
しかし、適切な休息を取らないと集中力が落ち、合理的な判断ができなくなる。

# 組織上の問題

よくわからないルートから依頼がとんできたりしても、急いでると直接やりがち。
チャットツールが導入されて効率はあがったけどブラックボックス化に拍車がかかっている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438183/08963b3a-0519-32bb-ea7f-2ba02deebf78.png)

## 分業化の弊害とよくある組織間トラブル

だいたい八方ふさがりになって、ソースコードを調べ始める。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438183/95d3a303-79b5-7757-86ae-72fa861d4431.png)


# 解決策

目の前のタスクをこなしてもむしろ状況は組織学習は強化されていき、より負荷がのしかかってくる。
基本的に歯止めがかからないので、成り行きで放っておくとろくな結果にならない。
納期が延びることはまず期待できないので、受注が減るとかで業務量が減らない限りは状況は悪化していく。
案件の炎上を一時放置してでも、長期的には仕組みや育成に注力したほうがましだが、育成については離職リスクが付きまとう。
また、転職でスーパーマンが来る場合もまれにあるかもしれないが、昨今の売り手市場でそんなやばい部署に優秀な人間はそうそう引っかからない。

ワーカホリックになってじわじわ病んでいくか、理不尽さにぶち切れて人間関係が壊れるか。
そしていずれ体やメンタルを壊す。
もはや手に負えない質と量の属人化した仕事を抱えているので平和に抜けるのは不可能。
残された手段は長期休職か部署移動か転職（退職）しかない。しぬよりはまし。

# 予防策

業界選び、会社選び、部署選び
組織作り
長期的な視点
適切に休みをとること
室内環境をGrafanaで可視化する。

温室度センサ(BME280)やSwitchBot温湿度計を使って室温、湿度の記録は取ってあったが、CO2センサ（SCD40)を導入したので、Grafanaを用いて計測データを可視化してみた。

#データの記録
SCD４xの計測コードは[GithubにPythonで書かれたもの](https://github.com/adafruit/Adafruit_CircuitPython_SCD4X"Adafruit_CircuitPython_SCD4X")があるので、ダウンロードして利用。

```python:exampl.py
# SPDX-FileCopyrightText: 2020 by Bryan Siepert, written for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
import time
import board
import adafruit_scd4x

i2c = board.I2C()
scd4x = adafruit_scd4x.SCD4X(i2c)
print("Serial number:", [hex(i) for i in scd4x.serial_number])

scd4x.start_periodic_measurement()
print("Waiting for first measurement....")

while True:
    if scd4x.data_ready:
        print("CO2: %d ppm" % scd4x.CO2)
        print("Temperature: %0.1f *C" % scd4x.temperature)
        print("Humidity: %0.1f %%" % scd4x.relative_humidity)
        print()
    time.sleep(1)
```
サンプルコードは毎秒計測する上に、温度、湿度のデータもついてくるが、CO2濃度だけ1回吐いてくれれば良いので、出力を削ってループも廃止して、

```python:scd4x_measure.py
import time
import board
import adafruit_scd4x

i2c = board.I2C()
scd4x = adafruit_scd4x.SCD4X(i2c)

scd4x.start_periodic_measurement()

time.sleep(10)
#センサのウェイクアップ待ち

if scd4x.data_ready:
    print("%d" % scd4x.CO2)
```
書き慣れたrubyでjson化して、シェルで繋いで出力。

```ruby:co2_measure.rb
require 'json'
require 'net/http'
require 'openssl'
require 'uri'

data = gets.chop
output_data = {"CO2" => data }
puts JSON.pretty_generate(output_data)
```

```shell:json_output.sh
python3 /home/pi/scd40/scd4x_measure.py |ruby /home/pi/scd40/measure.rb > /mnt/ramdisk/co2_data.json
```

```json:co2_data.json
{
  "CO2": "726"
}
```
他の計測データとまとめて、部屋の名前を書き足して、nginxなどで公開しておく。

```json:measured_data.json
{
  "temperature": 20.5,
  "humidity": 52,
  "co2": "1556",
  "position": "LDK",
  "time": "2022-02-20 23:28:14"
}
```

#データ集積
MySQLかMariaDBサーバを立てておいて、以下のようなテーブルを作成

| ID | date | room |temp|humidity|co2|
|:-----------|:------------:|:------------:|:------------:|:------------:|:------------:|
| 1       | 2022-02-20 23:28:14.000| LDK|20.5|52|1556|

各部屋ごとにおいてあるraspbery piからデータを集めてデータベースへ書き込み。

```ruby:sql.rb
#!/usr/bin/ruby

require 'mysql2'
require 'json'
require 'net/http'

room_list = ["raspizero.local","raspi2.local"]

room_list.each do |raspi|
  room_condition = Hash.new
  room_condition=JSON.parse(Net::HTTP.get(raspi,'/measured_data.json'))
client = Mysql2::Client.new(
  host: "sql server url", 
  username: "username",
  password: "password",
  init_command: "USE iot")
client.query("INSERT INTO roomdata (id,date,room,temp,humidity,co2) VALUES (NULL,'#{room_condition["time"]}','#{room_condition["room"]}','#{room_condition["temperature"]}','#{room_condition["humidity"]}','#{room_condition["co2"]}');")

end
```

#可視化
Grafanaでは計測データの取り込み部分に直接SQL文を書いた。

```sql:measure.sql
SELECT
  UNIX_TIMESTAMP(date) AS "time",
  room AS metric,
  value
FROM roomtemp
WHERE
  room = "LDK"
  and
  $__timeFilter(date)
ORDER BY date
```
ということで割と簡単に可視化できた。
![IMG_3840.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23964/77e05484-f748-ecfa-f7b6-dcec1e66a9c3.jpeg)
CO2濃度高くて、なかなか1000ppm切らないので、２４時間換気の導入検討中。
また、いちいちスマホやPC使わずに値を見たいので、適当な小型ディスプレイなどで表示させたいところ。
Facebook（フェイスブック）の動画をダウンロードして保存する方法

Facebook（フェイスブック）の動画をダウンロードして保存する方法

https://ferret-plus.com/5016

Facebookの動画をダウンロード保存する方法 2021【iPhone／Android】

https://appllio.com/facebook-video-download

これが最新決定版！Facebook動画をスマホ・PCに保存する方法

https://localfolio.leadplus.co.jp/blog/facebook-video-save

Facebook動画を手軽に保存する方法 | スマホでもPCでも利用可能

https://utilly.jp/article/facebook-movie-dl/

４つの方法で失敗した。

どうしようか思案中。

macOS ちょと古い。
100日でSQLの達人になる@LeetCode! Day19 <SQLで正規表現>

## 1517. Find Users With Valid E-Mails （問題レベル: Easy）要課金
今日の問題はこれ。
正しいe-mailアドレスのみリストアップするという問題。

結局、正規表現の使い方がポイント。

`MySQL`では`検査対象 REGEXP '正規表現'`が使えるのでシンプルに記載できる。
しかし、`MS SQL Server`は`REGEXP`が使えないので`like句`,`not like句`,`[]`を駆使する工夫が必要。
正規表現で使う`*`が`%`で同じ働きをする。
`[]`内は通常の正規表現と同様に記載が可能。
後は、discussを何度も見ながら、`left(mail,len(mail)-13 not like '%[^a-zA-Z._-]%'`を使ってクリアした。

* [LeetCode](https://leetcode.com/)の問題は、MS SQL Serverで解いています。
仕事しながら1ヶ月半で基本情報技術者試験を合格した話

#はじめに#
去年の春に基本情報を合格したので記事を書いてみようと思いました。
IT企業で働いていて基本情報を取ってみようと思う方は是非参考にしてみてください。
初投稿なので読みづらいところもありますが最後までよろしくお願いします＾＾

#自己紹介#
2018年3月：大学（情報学部）卒業
2018年4月：某IT企業に就職
2021年2月：基本情報技術者試験合格
2022年9月：転職のため退社
2022年12月：別のIT企業に就職

仕事ではLinuxやC言語を触っています。大学時代から基本情報を取るまで勉強は全くやっていませんでした。（単位を取るのも精一杯）
仕事後も勉強は全くやる気が起きず飲みに行くかパチンコを打ったりして遊んでました。

#何故資格を取ろうと思ったのか#
前働いていた会社で基本情報を取れ取れ言われていました。会社側が申し込み費用を負担してくれるならまだしも全額自己負担かつ、試験日が休日のため全くやる気が起きずに約3年間過ごしてきました。
そんな自分が何故資格を取ろうと思ったのかというと…
コロナが凄すぎて外で遊べなくなったからでした＾＾
気分屋の僕は2021年の年始にやることもなかったのでそろそろ基本情報でも取るか〜って思ったのが始まりでした。

#勉強方法#
まずは試験日を明確にするために基本情報技術者試験に申し込んだ。
試験日は2/8と2/20。コロナ禍の試験のため午前、午後を別日に受けられた。

使用したサイト…過去問道場（https://www.fe-siken.com/fekakomon.php）
過去問道場はアカウントを作成すること。

まずは午前問題を過去問道場で解いてみる。
結果は…46.3%
60%取れば合格なので60%を目指して過去問道場をやりまくる。
過去問題から約40％同じ問題が出題されるらしいのでとにかくやりまくる。
基本暗記問題はやっていれば解けてくる。わからないところはネットで調べてメモをする。（計算問題や難しい問題は軽く解説読んで流す）
自分はEvernoteに間違えた単語をメモして通勤時間に復習していた。
毎日3-4時間勉強していれば60%を超えてくる。
この辺りから計算問題や難しい問題にも挑戦するようになった。
最終的に70-80%くらい取れるようになった。
2/8の試験では73.75%取れた。

そして午後問題
まずは午後問題を過去問道場で解いてみる。
結果は…63%
午後問題も過去問道場にあるのでひたすら解いていく。
ぶっちゃけ午前問題を70-80%取れて理解していればアルゴリズムと言語問題以外はわかるようになるのでアルゴリズムと言語問題を重点的にやる。
アルゴリズムと言語問題は過去問でひたすら解いて理解していく。
（言語問題はC言語を選んだが未経験の人は表計算がオススメらしいです）
試験一週間くらい前から時間を測って通しでやってみる。
最終的に午後も70-80%くらい取れるようになった。
2/20の試験では76.2%取れた。

![B1D453E2-FFE7-4A42-9FD6-D76B29F04C9C.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2532998/b5eff4de-4bd2-f58c-cf17-4fd3512ca731.jpeg)
![247CB935-3D0D-4375-9611-4F08F222A27C.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2532998/d9174d59-4ce1-2741-b255-8574cf7bcb1c.jpeg)


#感想#
午前問題を十分理解できれば午後のアルゴリズムと言語問題以外はスラスラ解けました。
ぶっちゃけ未経験者でなければ分厚い参考書を読むより過去問をひたすら解くほうが効率いい気がします。基本情報レベルなら参考書に書いてあることは調べれば出てくるので参考書は必要ないと感じました。
今年は応用情報技術者試験か統計検定辺りを取ろうかな〜と考えています。合格できたらまた記事を書こうと思います。

長くなりましたが、ここまで読んでくださりありがとうございます。参考になるかは分かりませんが、たくさんの方に記事が届くと嬉しいです。
VBAオブジェクト変数の宣言時に1行でAs Newした時と2行に分けてSetした時の違い

# オブジェクト変数の宣言方法
VBAでオブジェクト変数を宣言する際、2通りの書き方があります。

1. 宣言とオブジェクトのSetを分けて2行で書く場合

	```VB
	Dim x As MyClass
	Set x = New MyClass
	```

1. 宣言と同時にNewして1行で書く場合

	```VB
	Dim x As New MyClass
	```


どちらも正しいコードとして処理されますが、何か違いがあるのか調べてみました。

# 2つの宣言方法の違い
Microsoftは、VB.NETでオブジェクト変数の宣言と同時にNewして1行で書くコードは、オーバヘッドが大きいので使うべきではないと以下のページで書いているようです。

[VB 6.0 ユーザーのための VB .NET 移行ガイド - Dim x As New MyClass | Microsoft Docs](https://docs.microsoft.com/ja-jp/previous-versions/technical-document/dd297716(v=msdn.10)?redirectedfrom=MSDN)

違いについて次の表にまとめてみました。

| 比較項目 | 2行で書いた場合 | 1行で書いた場合 |
|:--|:--|:--|
| Nothingを設定してオブジェクトを破棄した時 | 再度Newしない限りNothingのまま | オブジェクトの存在が必ず保証されるため、再利用すると自動で再作成される |
| オーバーヘッドの有無 | 無 | 有（オブジェクトが利用されるたびに毎回チェックが入る） |

# 実際の挙動の違い
実際にコードを実行して、挙動の違いを調べてみました。

## 2行で書いた場合
2行で書いた場合は、「Set c = Nothing」でオブジェクトを破棄すると、「Is Nothing」の比較結果はTrueとなります。
また、Nothingでオブジェクトを破棄した後は、「c.Add」はエラーとなります。

```VB
Sub 宣言とオブジェクトのSetを分けて2行で書く場合()
    'オブジェクト変数の宣言（2行）
    Dim c As Collection
    Set c = New Collection
    
    'Nothingを設定してオブジェクトを破棄
    Set c = Nothing
    
    '変数がNothingかどうか比較
    If c Is Nothing Then
        MsgBox "cはNothign"		'★Nothingと判定される
    Else
        MsgBox "cはNothignではない"
    End If
    
    'コレクションを追加
    c.Add "コレクションを追加"		'★オブジェクトは破棄されているのでAddはできない
    MsgBox c.Item(1)
    
End Sub
```

## 1行で書いた場合
1行で書いた場合、オブジェクトの存在が必ず保証されるため、再利用すると再作成されるとのことです。
次のコードを実行した場合、「Set c = Nothing」でオブジェクトを破棄しても、「Is Nothing」の比較結果はFlaseとなります。
また、オブジェクトを破棄しているにもかかわらず「c.Add」ができてしまいます。

Nothingを設定してオブジェクトを明示的に破棄しても、そのオブジェクトを参照したり利用したりすると自動でオブジェクトが再作成されてしまうようです。

```VB
Sub 宣言と同時にNewして1行で書く場合()
    'オブジェクト変数の宣言（1行）
    Dim c As New Collection
    
    'Nothingを設定してオブジェクトを破棄
    Set c = Nothing
    
    '変数がNothingかどうか比較
    If c Is Nothing Then
        MsgBox "cはNothign"
    Else
        MsgBox "cはNothignではない"		'★Nothingではないと判定される
    End If
    
    'コレクションを追加
    c.Add "コレクションを追加"		'★オブジェクトは破棄されているのにAddできてしまう
    MsgBox c.Item(1)
    
End Sub
```

# 結論
細かいことを気にしなければどちらを使ってもよいが、宣言とSetを分けて2行で書く方が無難。

# 参考にしたサイト
[VBA オブジェクト変数の宣言時にNewすると何がまずいのか - t-hom’s diary](https://thom.hateblo.jp/entry/2016/09/27/221527)

[VBAでオブジェクト変数の宣言とNewを１行で書いてよいか ｜ Excel作業をVBAで効率化](https://vbabeginner.net/write-class-declaration-and-new-in-one-line/)
【MediaPipe】カメラで手の指を検知するゲームを作ってみた

# 概要

## MediaPipeとは？

- Google社が提供するライブストリーミングのためのオープンソースのMLソリューションです
- Android・iOSなどのプラットフォームや、Python・JavaScriptなどの様々な言語で、メディア向けの機械学習を利用できます
  - メディア向けというのは顔や手をカメラで認識する仕組みになると思います

## 何を作ったのか？

- 今回は機械学習に関する部分は一切に触れていません
- 既存のJavaScriptの手の検出のサンプルを元に表題のゲームを作成しました
- JavaScriptも素のJavaScriptで作成しています
- タイトルとゲームでそれぞれのHTMLファイルで作成しています

## 作ったゲームのルール

- 赤い枠に人差し指が入ったら点数が加算されます
- 最初のハイスコアは30でスコアがそれ以上になると更新され記録されます

## 参考にした資料とフレームワーク

- MediaPipeの手の認識のサンプル
  - https://codepen.io/mediapipe/full/RwGWYJw
- Bulma
  - https://bulma.io/ 

# 成果物

## 公開しているコード

https://gitlab.com/tamoco-mocomoco/mediapipe-finger-game

## 実際に遊べるページ

https://tamoco-mocomoco.gitlab.io/mediapipe-finger-game

## スクリーンショット

<img width="300px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/bde38203-894c-c9bf-df95-3620a89222c2.png">

<img width="300px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/6bd00be0-c826-611a-c3e0-1cf15fe27b37.gif">

※取得したGIFがボケていますが実際はボケていません


# 一部コードの説明や改善点など

- コントロールパネルは外せなかったため非表示にしてあります
- selfieModeという反転処理がありますが使用していません
  - 使用しなかった理由は以下のとおり 
     - drawingUtilsが反転に対応していないので赤い枠の計算が難しくなるため
     - 基本的には全面のカメラを利用するため反転する処理はcanvasでstyleで行いました
- とりあえず動くものを目指して最速で頑張りました
  - DOMを取得してそのinnerTextでそのまま計算したりはよくはないです
- 一応ゲームなのでハイスコアを記録するようにしています

# ふりかえり

- 既存の機械学習のモデルを使うだけなら簡単に利用できる
- 顔の認識もJavaScriptで使えるので何か作れそう
  - Electronとかでパソコンに前に着席しているかチェックするアプリとか・・・
40 代おっさん Spreadsheetサービスについて学ぶ

## 本記事ついて

本記事は プログラミング初学者の私が学習していく中でわからない単語や概要をなるべくわかりやすい様にまとめたものです。
もし誤りなどありましたらコメントにてお知らせいただけるとありがたいです。

## Spreadsheetサービス

Spreadsheetサービスとは
GASでスプレッドシートを操作するためのクラスと、そのメンバーを提供するサービス

Spreadsheetサービスの主なクラス

|クラス|説明|
|------|---|
|SpreadsheetApp|Spreadsheetサービスのトップレベルオブジェクト|
|Spreadsheet|スプレッドシートを操作する機能を提供する|
|sheet|シートを操作する機能を提供する|
|Range|セル範囲を操作する機能を提供する|

スプレッドシートを操作の基本てな流れ

❶SpreadsheetAppから配下のオブジェクトをたどっていき、目的のオブジェクトを収得
❷対応するクラスのメンバーを使って目的のオブジェクトを操作

## 参考資料

<https://www.amazon.co.jp/s?k=google+apps+script+%E5%AE%8C%E5%85%A8%E5%85%A5%E9%96%80&adgrpid=110264232688&gclid=CjwKCAiA9aKQBhBREiwAyGP5lSl7AJJLCvOEHb4wQgMlyqW1fll5X8GDTT_Rkd1_soUAyIPMXQr26hoClHEQAvD_BwE&hvadid=553833563682&hvdev=c&hvlocphy=1009076&hvnetw=g&hvqmt=b&hvrand=4378489642044417389&hvtargid=kwd-594191211348&hydadcr=4106_13159878&jp-ad-ap=0&tag=googhydr-22&ref=pd_sl_2x1owglv0s_b_p52>
scrivenerで目次の前に表紙を持ってきたい

今技術書典に出そうと思って執筆しているのですが、scrivenerの使い方をググってもほぼ情報がなく、本にも掲載されていなかったので、ググって出てくるようになると嬉しいなーの意味を込めて。

・コンパイルを選択します
・コンパイル対象をepubにします
・以下のようなアイコンが右にあると思うので、右から二番目をクリック
![スクリーンショット 2022-02-20 23.09.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2143543/11ddb3ae-ab8b-1658-8d2b-af6bfcf56406.png)
・順序が前後するかも知れませんが、画像データを中央の長方形の枠にドロップ
・上のセレクトボックスからそのファイルの名前を選択
![スクリーンショット 2022-02-20 23.13.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2143543/a720f8fe-f78f-d375-6d9e-304ba98d34b8.png)
・続いて最初の画像のアイコンの一番右をクリック
・以下のようにする。太くするなどはご随意に
![スクリーンショット 2022-02-20 23.14.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2143543/34e7077b-6397-e37b-f681-5921217c0780.png)

これで最初に表紙が入り、その次にリンク付きの目次が自動生成されます
振る舞い検知ってなにするの？

## 勉強前イメージ

監視と似たようなもの？

## 調査

### 振る舞い検知 とは

「怪しい動きをしている」 という普通ではない挙動でウイルスを検知するもの。
未知のウイルスにも対応できるという特徴があります。

### そもそもウイルス検知の種類

- パターンマッチング

こちらがウイルス対策ソフトで一般的に使われている手法になります。
ウイルスのパターンを記録しておき、それと一致すればウイルスである という検知の方法です。
事前にウイルスのパターンを記録しておかないといけないという方式から、未知のウイルスには対応していないですが、マッチングするため誤検知の可能性は低くなります。
ウイルスは1日に大量の種類が作られているので、パターンマッチングだけでは対応しきれません。

- ヒューリスティック

ウイルスには一定の特徴があり、特徴をあらかじめ登録しておくことで
その特徴にハマったプログラムが見つかった際にウイルスだと判断する手法になります。

- 振る舞い検知

↑にも書いている通り、ウイルス特有の怪しい動きを検知するという方法。
ビヘイビアという振る舞いを見て危険だと判断する方法です。
こちらは未知のウイルスにも対応できるという反面、「ウイルスである可能性が高い」だけで正常のアクセスすらも弾いてしまう、誤検知をする可能性もあります。

## 勉強後イメージ

振る舞い、どう動いてるのかを見て検知する方法ってことか。
監視とは全然違うw

## 参考

- [振る舞い検知とは？その特徴やメリットデメリットを徹底解説](https://cybersecurity-jp.com/security-measures/31419)
- [「振る舞い検知」とは？未知の脅威対策に必要不可欠！](https://www.hammock.jp/assetview/media/what-is-behavior-detection.html)
Javaの基本的なデータ型の操作についてまとめてみた

Javaシルバーの勉強をしていて、Javaの基本的なデータ型の操作で詰まったので、ここで解決していきたいと思います。
問題を解いていたら本当に正解率が悪かった。。

なのでまとめて見ようと思います。

# Javaの基本的なデータ型の操作

##ラッパークラス

Javaの型には参照型と基本型があるのですが、基本型では主に数値を用いた計算や数値や文字を格納する働きがあります。
しかし、Javaでは格納した値を操作するやり方がありません。
そんな時に使うのがラッパークラスです。

ラッパークラスをつかうことで、基本型をオブジェクトとして扱うことができるようになり、操作をすることができます。

|基本型  |ラッパークラス  |
|---|---|
|boolean  |Boolean  |
| byte  |Byte  |
| char  |Character  |
| short |Short  |
| int  |Integer  |
| long  |Long  |
| float  |Float  |
| double  |Double  |

上記に挙げられている型の基本型は、計算を行ったりすることができません。
しかし、それらをラッパークラスにすることで、文字列の最後の文字を消したり、演算子を用いて計算をさせることができます。

ではそのオブジェクトの作成方法を見ていきましょう。

## オブジェクトの生成のやり方

Integerクラスでは、主に2通りのやり方があります。

今回はnewメソッドを使ってintをIntegerにするやり方と、StringをIntegerにするやり方を説明します。

```
new Integer(int num);
```

こうして、newでオブジェクトを生成して、その引数に値を入れてあげることで、int型がIntegerになりました。
同じ要領で、StringをIntegerに変換します。

```
new Integer(String str);
```
次に、値の取得について説明します。

# 値の取得

##　Integer型の場合
そして、生成したオブジェクトに値を入れていきます。やり方は2種類あり、先程の`new`で生成したオブジェクトを代入するやり方か、`valueOf();`で値を入れていくやり方です。
まず最初に、オブジェクトを代入させるやり方でやっていきます。

```
Integer　変数名 = new Integer(String str);
```

はじめにラッパークラスで変数を宣言して、その後に=でオブジェクトを宣言しているコードを直接宣言して置くことで代入させます。

2つ目のやり方の、`valueOf`の引数の値に基本型の変数をいれてあげることで代入させます。

やり方としては、

```
Integer 変数名 = Integer.valueof(引数);
```

このようにします。

先程は、Integer型の説明をしましたが、次はBoolean型の説明をしていきます。

## Boolean型の場合

Bootleanの場合、Trueかfalseしか入りませんが、これは大文字小文字関係ありません。

```
・TRUE
・true
```
のように書いてもコンパイルエラーにはなりません。

なので、

```SampleBoolean.java
public class JavaApp2 {
    public static void main(String[] args) {
        String strBool = "true";
	String strBool2= "TRUE";
        
        Boolean bool1 = Boolean.valueOf(strBool);  
     	Boolean bool2 = Boolean.valueOf(strBool2);
        System.out.println("bool1の値を文字列として出力:" +bool1.toString());
        
	System.out.println("bool2の値を文字列として出力:" +bool2.toString());
    }
}
```

このように、小文字、大文字にして書いても問題なく出力されます。
結構そこはゆるくしてくれるんですね。
まぁ厳しくする意味もないですが。

ちなみに、trueのところを`TRUEEEEEEEEEEE`にしても動きます。面白いですよねwww
ただ、IntegerもBooleanもこんな書き方をしていたら非常に面倒くさいですよね。
なので、次にそれを省略できる書き方を紹介します。

# オートボクシング機能

このように

```
Integer i = Integer.valueOf(16);
```

とすることで、変数iに対して16という値を入れることができましたが、こんな直感的でないやり方でやりたくないですよね。普通の編集宣言みたいにやっていきたいですよね。

それを可能にしてくれるのがオートボクシングと呼ばれるものです。
これをすることで、先程のコードを修正してみると

```
Integer i = 16;
```

となります。
詳しく解説すると、先程のように宣言することで本来ラッパークラスの記述をするべきところを、自動的に変換してくれるので省略することができます。

こうすることで、省略していくことが可能です。

ただ、プリミティブ型は便利ですが計算ができるということは、計算ができてしまうのが欠点です。僕みたいなアホがいじってバグを作ってしまうので。。。
なので、必要に応じて計算ができないようにラッパークラスから、基本形に戻せるようにしたい場合にそれができる便利なものがあるので、それを紹介します。

## アンボクシング

先程言った、ラッパークラスを基本形に戻してやるやり方を紹介します。
やり方としては、
Integer型の変数をもう一度int型の変数の中に格納するように宣言するだけです。試しに、アッパークラスのInteger型の変数iをint型のsampleIに入れてみたいと思います。

```main.java
class Main{
    public static void main(String args[]){
        Integer i = 16;
        int sampleI = i;
        System.out.println(sampleI);
    }
}
```

このようにすることをアンボクシングといいます。
これ場合めっちゃ使い道ありそう。
【Rails】繰り返し処理におけるインデックスについて

# each do 文におけるインデックス

```erb:hoge.html.erb
<% @hoges.each_with_index do |hoge, i| %>
  <div data-columns="<%= i %>">
    <%= hoge.content %>
  </div>
<% end %>
```
上記のように、each do を each_with_index do と記述し、
インデックスのブロック変数( i )を与えてやることで、繰り返し処理にインデックスを振ることができる。
上記の例のようにdata-*属性を与えたい時などに応用することができる。

# render partial の collectionオプションにおけるインデックス

* viewの記述

```erb:hoge.html.erb
<%= render partial: 'hoge', collection: @hoges, as: 'hoge' %>

```
* partialの記述

```erb:_hoge.html.erb
<div data-columns="<%= hoge_counter %>">
    <%= hoge.content %>
</div>
```
先程の each do 文と同様の内容を partial の collection オプションを使って書くと上記のようになる。
collectionオプションの場合は、インデックスは自動で生成されており、「変数の名称_counnter」として扱うことができる。（この命名は与えたpartialの名称に依存する。）
40 代おっさん GASのグローバル関数について学ぶ

## 本記事ついて

本記事は プログラミング初学者の私が学習していく中でわからない単語や概要をなるべくわかりやすい様にまとめたものです。
もし誤りなどありましたらコメントにてお知らせいただけるとありがたいです。

## グローバル関数

グローバル関数とは
JavaScriptの組み込みオブジェクトに含まれず、かつどこからでも呼び出せる関数のこと

|分類|メンバー|戻り値|説明|
|----|--------|------|----|
|グローバル関数|encodeURI(uri)|String|URI文字列uriをURIコンコードして返す|
|グローバル関数|encodeURIComponent(str)|String|文字列strをURIコンコードして返す|
|グローバル関数|decodeURI(uri)|String|URI文字列uriをURIデコードして返す|
|グローバル関数|decodeURIComponent(str)|String|文字列strをURIデコードして返す|

### URIエンコードとURIでコード

漢字、ひらがななどはURIの構成文字として使用制限がある。これらを使うには、制限されていない文字に変換する必要がある。
その変換処理をURIエンコードと言い、URIエンコードされたURIを復元する処理をURIデコードと言う。

```javascript
function toshiki4() {
  const str = '利樹';
  console.log(encodeURI(str));
  console.log(encodeURIComponent(str));  

  const uri = 'https://www.google.co.jp/search?q=利樹';
  console.log(encodeURI(uri));
  console.log(encodeURIComponent(uri));
}
```

## 参考資料

<https://www.amazon.co.jp/s?k=google+apps+script+%E5%AE%8C%E5%85%A8%E5%85%A5%E9%96%80&adgrpid=110264232688&gclid=CjwKCAiA9aKQBhBREiwAyGP5lSl7AJJLCvOEHb4wQgMlyqW1fll5X8GDTT_Rkd1_soUAyIPMXQr26hoClHEQAvD_BwE&hvadid=553833563682&hvdev=c&hvlocphy=1009076&hvnetw=g&hvqmt=b&hvrand=4378489642044417389&hvtargid=kwd-594191211348&hydadcr=4106_13159878&jp-ad-ap=0&tag=googhydr-22&ref=pd_sl_2x1owglv0s_b_p52>
モノリシックとマイクロサービスの比較 メモ

## 概要
自社でコンテナを使ったマイクロサービスについての記事を作成する取り組みがあり、
その過程で物知りっくとマイクロサービスの比較について記事を出している人がいたので便乗してみようと考えをまとめてみました。
以前あったAWS Innovate2021の内容の受け売りだったししますが・・・

## システムの構成
* モノリシックの例
![モノリシックシステム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657697/9e500b35-503e-0bac-66cc-3d4a49a6c265.png)

* モノリシックなシステムはすべてのサービスが一つの塊として存在している
* 後述のマイクロサービスのようにサービス間の連携は不要のためサービス間の連携がボトルネックになることはない
* ただし変更する際にはシステムすべてを変える必要がある

* マイクロサービスの例
![マイクロシステム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657697/098f8f80-8ab4-936e-8698-a2d2f86faab3.png)

* 各サービスごと別に分かれている
* サービス間を連携させるためにひと工夫が必要で状況によっては情報のやり取りがボトルネックになることも
* 以下の点で基本的にモノリシックなものより有利になる
    * 変更容易性
        * 変更する際はサービス単位で変更を行うことができるので変更範囲が小さくできる
    * 俊敏性
        * 各サービスごとに処理が分かれているためそれぞれ別に処理を走らせることができる
    * 拡張性
        * 水平拡張が可能なためインスタンスのタイプでの頭打ちなどはない
    * 回復性
        * 問題が起こってもサービスだけに限ることができる
    * 影響範囲の局所化
        * 前述のとおりサービスが分かれているため影響もそこで抑えられる
    * デプロイ時間の短縮
        * 全体をデプロイする必要はないため基本的に早くなる


## モノリシックからマイクロサービスへの移行手順
* モノリシックからマイクロサービスに切り替える場合以下のアプローチが考えられます
    * 一気に作り変える
        * 現在動いているシステムをとめて一気にタイミングを決めて切り替える場合に取る手順です
        * 中身を個別に切り出すことができないけどマイクロサービスに切り替えたい場合に思い切って実施することができる
    * 段階的に切り分ける
        * クライアントとサーバの間にAPIGateWayを配置しサーバ側を徐々に切り替える手順です。
        * 切り替える際にアプリをコンテナにしたりサーバレスにしたりそこは状況に応じて設定します。
        * 徐々に切り替えていき最終的に古い部分を削除することで切り替えを完了します。

## サービスを切り出す時に検討すること
* サービスとして切り出す際にはやみくもに切り出すのではなく以下の観点で切り出していくことがよさそうです。
    * 分解のし易さが高い
    * 分解によって得られる価値が高い
* 逆に分解しづらいところは分解せずにあえてそのままで進めるという方法の方がよさそうです。
* また得られる価値が低い場合は投入するコストに見合わないため辞めておくのがよさそうです。
* マイクロサービス化する際にはサービスごとに独立できること(変更を行った際に別のサービスも修正する必要があるようなケースは避けるべき)
* AWSであればサービス間の結合を疎結合にさせるため以下のサービスを活用していくことを考える
    * Amazon SNS
    * Amazon SQS
    * AWS Lambda

## 最後に
ひとまずモノリシックとマイクロサービスについての簡単な比較とモノリシックからマイクロサービスに切り替えるときの進め方を記述してみました。もうちょっと具体例をあげられるようになったらつづきを記載してみようかと思います。
標準ライブラリ

##基本
[abs](https://qiita.com/drafts)	
[sin/cos/tan](https://qiita.com/sibata_yuna/items/e9fe5213bf029d2d1bce)	
[string](https://qiita.com/sibata_yuna/items/5934603a365bb437d59e)	

##初心者(100~300)
[min/max]	
(https://qiita.com/sibata_yuna/items/8cdb93a062bcee84bfda)
[swap](https://qiita.com/sibata_yuna/items/abb2857dd8c28b1c0ba5)
[__gcd](https://qiita.com/sibata_yuna/items/7bac6be71249d1566cf7)
[rand](https://qiita.com/sibata_yuna/items/ffb64ce1e6c2b7d7f261)
[clock](https://qiita.com/sibata_yuna/items/8698da53a37709fbf7e1)
[reverse](https://qiita.com/sibata_yuna/items/ca3f2865b76ab83588db)
[sort](https://qiita.com/sibata_yuna/items/f66deee54bae28e5dbdf)

##中級者(200~400)
[vector](https://qiita.com/sibata_yuna/items/8b4dd1ad69a164c47d18)
[stack](https://qiita.com/sibata_yuna/items/7f15a2ec9affa9eae1a7)
[queue](https://qiita.com/sibata_yuna/items/8739e24822af02ab5f10)
[priority_queue](https://qiita.com/sibata_yuna/items/e60837f111cf97929bdc)
[map]
(https://qiita.com/sibata_yuna/items/d69ad0977caca218ff42)
[lower_bound](https://qiita.com/sibata_yuna/items/d825f6fa37508f01ac09)
[set](https://qiita.com/sibata_yuna/items/e713b6202a2ea7bcc4b8)
[pair](https://qiita.com/sibata_yuna/items/674f011ad485668afd9a)
[tuple](https://qiita.com/sibata_yuna/items/907d9c7a594b1626a02a)

##上級者
[assert](https://qiita.com/sibata_yuna/items/b0b1e4cc4c05a9f146f5)
[count](https://qiita.com/sibata_yuna/items/c76105548f1cf15e422e)
[find](https://qiita.com/sibata_yuna/items/fd8620fd3f9f50cc2918)
[next_permutation](https://qiita.com/sibata_yuna/items/183eac702b324db0d374)
[__builtin_popcount](https://qiita.com/sibata_yuna/items/af02743b82acd065531f)
[bitset](https://qiita.com/sibata_yuna/items/a4e5dad78c57a20e9aea)
40 代おっさん GASのObjectオブジェクトについて学ぶ

## 本記事ついて

本記事は プログラミング初学者の私が学習していく中でわからない単語や概要をなるべくわかりやすい様にまとめたものです。
もし誤りなどありましたらコメントにてお知らせいただけるとありがたいです。

## Objectオブジェクト

Objectオブジェクトとは
オブジェクトとしての基本的な性質を提供するもの
すべてのオブジェクトの土台となっているもの

new演算子にてObjectオブジェクトのインスタンスを生成できる。

構文

```javascript
new Object()
```

上の場合、生成されるのは空のオブジェクトです。

特定のプロパティを持つオブジェクト生成するのであれば、オブジェクトリテラルを使用する。

構文

```javascript
{プロパティ1: 値１, プロパティ2: 値2 ...}
```

共通のプロパティ、メソッドを持つオブジェクトを生成するのであれば、クラスを定義し、インスタンスを生成する。

Objectオブジェクトの主なメンバー

|分類|メンバー|戻り値|説明|
|----|--------|------|----|
|メソッド|toString()|String|オブジェクトを表す文字列を返す|
|静的メソッド|Object.freeze(obj)|Object|オブジェクトを凍結し変更を不可とする|
|静的メソッド|Object.seal(obj)|Object|オブジェクトを封印しプロパティの追加・削除を不可とする|
|静的メソッド|Object.isFrozen(obj)|Boolean|オブジェクトが凍結されているかどうかを判定する|
|静的メソッド|Object.isSealed(obj)|Boolean|オブジェクトが封印されているかどうかを判定する|
|プロパティ|constructor||オブジェクトを生成したクラス（コンストラクタ関数）を返す|

```javascript
function toshiki4() {
  const obj = new Object();
  console.log(obj.toString());
  console.log(obj.constructor);

  const person = {name: '利樹', age: 4};
  console.log(person.toString());
  console.log(obj.constructor);

  const number = 123;
  console.log(number.toString());
  console.log(number.constructor);

  const d = new Date;
  console.log(d.toString());
  console.log(d.constructor);

  const array = [10, 20, 30, 40];
  console.log(array.toString());
  console.log(array.constructor);
}
```

### オブジェクトの凍結、封印

オブジェクトは定数を格納した場合、再代入はできないがプロパティの追加、値は変更できる。
それをできなくすることが可能

freezeメソッドは、オブジェクトを凍結するメソッド

構文

```javascript
Object.freeze(オブジェクト)
```

sealメソッドは、オブジェクトを封印するメソッド

構文

```javascript
Object.seal(オブジェクト)
```

新たなプロパティの追加できないが、プロパティの変更は可能

```javascript
function toshiki4() {
  const person = {name: '利樹', age: 4};
  Object.seal(person);
  person.name = 'パパ';
  person.favorite = 'みかん';
  console.log(person);

  Object.freeze(person);
  person.name = 'ママ';
  person.favorite = '野菜';
  console.log(person);
}
```

## 参考資料

<https://www.amazon.co.jp/s?k=google+apps+script+%E5%AE%8C%E5%85%A8%E5%85%A5%E9%96%80&adgrpid=110264232688&gclid=CjwKCAiA9aKQBhBREiwAyGP5lSl7AJJLCvOEHb4wQgMlyqW1fll5X8GDTT_Rkd1_soUAyIPMXQr26hoClHEQAvD_BwE&hvadid=553833563682&hvdev=c&hvlocphy=1009076&hvnetw=g&hvqmt=b&hvrand=4378489642044417389&hvtargid=kwd-594191211348&hydadcr=4106_13159878&jp-ad-ap=0&tag=googhydr-22&ref=pd_sl_2x1owglv0s_b_p52>
PowerAutomate: Qiita API を使ってみる

# 背景
備忘録的に使ってることが多いので、タグでまとめたリンク投稿が欲しいな、と
その為に、まず一通り使いそうな API を試してみた記録。

特に躓くこともないので、あとは、全取得して、定期的にまとめ用の記事をどう更新するようにするか？かな

# 概要
1. アクセストークンを取得。[ここで](https://qiita.com/settings/tokens/new)
1. あとは、[標準の HTTP Action](https://docs.microsoft.com/ja-jp/learn/modules/http-connectors/2-webhook) でサクッと行ける。
    1. 自身の記事一覧は、[get-apiv2authenticated_useritems](https://qiita.com/api/v2/docs#get-apiv2authenticated_useritems) で
    1. 記事投稿、[post-apiv2items](https://qiita.com/api/v2/docs#post-apiv2items)
    1. 記事更新、[patch-apiv2itemsitem_id](https://qiita.com/api/v2/docs#patch-apiv2itemsitem_id)

実施例はこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/f5c96e89-7464-c945-e122-dbc974f37855.png)

```json:Authorization
Bearer  {accessToken}
```

```json:Content-Type
application/json
```

# 補足
## 躓きポイント

- こんな感じで、いけるのかと思ったけど駄目。Doc を信じましょう :laughing: 
    - NG<br><code>https://qiita.com/api/v2/authenticated_user/items/{itemID}<cpde/>
    - OK<br><code>https://qiita.com/api/v2/items/{itemID}<cpde/>
- 必須情報は以下。あれ？消せないって時は確認を<br>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/48d3d8e6-206a-7f9a-378f-13d221d8bb64.png)
- アクセストークンも確認を。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/9b98de11-d973-b440-5723-0f55ac888143.png)



# 参考
Qiita API の Document

https://qiita.com/api/v2/docs

Power Automate の Http Connector の学習はこちらで

https://docs.microsoft.com/ja-jp/learn/modules/http-connectors/

# 追記
実際に作ったものについては以下

https://qiita.com/baku2san/items/6ee373a7d9168ebf6444
[JavaScript] プロトタイプチェーンをいじって継承元を変更する

## 環境

- Node.js v16.14.0

## 詳細

JavaScript のプロトタイプチェーンをいじれば人を神（のサブクラス）にすることもできる。

```js
'use strict';

class God {
  destroy() {
    console.log('Destroy!');
  }
}

class Animal {
  hunt() {
    console.log('Hunt!');
  }
}

class Human extends Animal {
  hack() {
    console.log('Hack!');
  }
}

const isAnimal = (target) => target instanceof Animal;
const isHuman = (target) => target instanceof Human;
const isGod = (target) => target instanceof God;

const adam = new Human();

console.log(isAnimal(adam)); // true
console.log(isHuman(adam));  // true
console.log(isGod(adam));    // false

adam.hunt();
adam.hack();
// adam.destroy(); できない

Object.setPrototypeOf(Human.prototype, God.prototype); // 人を神（のサブクラス）にする
// 以下と等価（__proto__ は ECMAScript 標準ではないので非推奨）
// adam.__proto__.__proto__ = God.prototype;

console.log(isAnimal(adam)); // false
console.log(isHuman(adam));  // true
console.log(isGod(adam));    // true

// adam.hunt(); できない
adam.hack();
adam.destroy(); // できる！
```
PDBの「save state」について


### PDB自動起動設定確認
```
col CON_ID for 9999
col CON_NAME for a10
col INSTANCE_NAME for a15
col RESTRICTED for a10
col STATE for a10

select CON_ID,CON_NAME,INSTANCE_NAME,STATE,RESTRICTED from DBA_PDB_SAVED_STATES;

<実行結果例>
CON_ID CON_NAME   INSTANCE_NAME   STATE      RESTRICTED
------ ---------- --------------- ---------- ----------
     3 PDB        orcl1           OPEN       NO

上記実行結果はsave stateにより、PDBが自動起動するよう設定されていることを意味する。
結果が「no rows selected」と表示された場合はsave stateによるPDB自動起動設定はされていない。
```

### save stateによるPDB自動起動設定
```
--全てのPDBに対して現在のPDB起動状態を保存する
alter pluggable database all save state;

--PDB名を指定して現在のPDB起動状態を保存する
alter pluggable database <pdb_name> save state;
```
### save state を無効にする
```
--全PDB
alter pluggable database all discard state;

--PDB指定
alter pluggable database <pdb_name> discard state;
```
ブラウザゲームを作ってみよう(その5:図形表示)

#はじめに
[その4](https://qiita.com/noji505/items/ac21d108add93d2470e6)ではファイル分割を行いました。
今回は図形表示を行いたいと思います。

#図形を表示してみよう
実は既に今までのサンプルで使用していました。
(毎回ループの最初で画面をクリアするときに使用)

ライブラリに以下のメソッドを定義しています。

```javascript:shape.js
//-----------------------------------------------------------
// drawRect : 矩形描画
//     引数 : X,Y,幅,高さ,色,透明度
//   戻り値 : 無し
//-----------------------------------------------------------
function drawRect( x, y, w, h, c, alpha )
{
	c = hexToRGB( c );	// 色を16進数へ変換

	if( alpha == null ){	// 透明度なし
		c = "rgb( "+c.r+", "+c.g+", "+c.b+" )";
	} else {				// 透明度あり
		c = "rgba( "+c.r+", "+c.g+", "+c.b+", "+alpha+" )";
	}

	x += SC_X;
	y += SC_Y;

	g.strokeStyle = c;			// 色
	g.strokeRect( x, y, w, h );	// 描画
}

//-----------------------------------------------------------
// drawFill : 塗りつぶし矩形描画
//     引数 : X,Y,幅,高さ,色,透明度
//   戻り値 : 無し
//-----------------------------------------------------------
function drawFill( x, y, w, h, c, alpha )
{
	c = hexToRGB( c );	// 色を16進数へ変換

	if( alpha == null ){	// 透明度なし
		c = "rgb( "+c.r+", "+c.g+", "+c.b+" )";
	} else {				// 透明度あり
		c = "rgba( "+c.r+", "+c.g+", "+c.b+", "+alpha+" )";
	}

	x += SC_X;
	y += SC_Y;

	g.fillStyle = c;			// 色
	g.fillRect( x, y, w, h );	// 描画
}
```

使用用途はそれぞれ以下となります。
drawRect・・指定した大きさと色の枠を表示する
drawFill・・指定した大きさと色で塗りつぶして表示する

#実行イメージ

```javascript:sample.js
drawRect( 30, 30, 50, 50, 0x000000, null );
drawFill( 100, 30, 50, 50, 0xFF0000, null );
```

上記のソースで、以下のような表示になります。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="VwrXpev" data-user="noji505" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/noji505/pen/VwrXpev">
  Qiita16_sample01(図形表示)</a> by nojima (<a href="https://codepen.io/noji505">@noji505</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

キャンバスを使えば他にも<b>線(Line)</b>や<b>円弧(Arc)</b>を描画することが出来ます。

#最後に
自分はあまり絵が描けないので図形を駆使して表現することが多いです。
上手く活用すれば表現の幅が広がると思います。
Automation Anywhere のパッケージについて学ぶ

# パッケージについて学ぶ。
本日も技術ブログで学習することとした。

https://licensecounter.jp/engineer-voice/blog/articles/20200603_AutomationAnywhere-A2019-Package.html

# 勉強方法
今回は読むのがメインなので、上記技術ブログをそのまま読んでいった。
内容の理解については、本ブログ下記にまとめた。
認識に誤りがないか不安だが、いずれ誰かツッコんでくれるかもしれない。

# １．パッケージ/アクションとは？
Automation Anywhere では、バージョンによって呼び方が変わるものがあるようだ。
V11で「コマンド」と呼んでいたものを、A360では「**パッケージ**」
V11で「サブコマンド」と呼んでいたものを、A360では「**アクション**」
と呼ぶそう。
イメージが付かない方はブログの画像を確認してほしい。

画面の説明時に役に立ちそうなので、覚えていきたい。

# ２．パッケージのバージョン管理
クラウド上のBotはパッケージのバージョン管理を自動でしてくれるらしい。
Excel関連のパッケージがあったら、自動で変更されてしまうそう。
ただし、Botを作成して使用しているパッケージは自動更新はされないそう。
元に戻したりもできるのはさすがだなと思った。

# ３．カスタムパッケージの追加
Javaで自作したパッケージもアップできるとのこと。
さすが！

# 本日の学び
１．パッケージとアクションの単語を具体的に学んだ。
２．パッケージのバージョン管理は自動。Bot作成後は手動。
３．Javaで自作したパッケージを追加できる。
パスワードのハッシュ化の手法のメモ

今更ながら、ハッシュ化の手法を勉強中。
この世界にも歴史があって、いたちごっこで成長しているので、基礎的なことから知らないと全然話についていけないし、ググって得た知識が古いのか新しいのかも判断できない。（投稿する人のレベルもあるので、記事の投稿日時は頼りにならない。）

ということで、この記事は素人が書いています。
基本的に古い知識＆間違いもあろうと思いますので、穏やかな目でご覧いただきご指導いただけると幸いです。m(_ _)m

----

# IDとパスワードのハッシュ化について
- あるシステムへのIDとパスワードを、システム内で保持し、ユーザーが入力した際に照合することを考える。
- そのIDとパスワードの一覧・テーブルが丸っと流出した場合でも、「それでも割と安全、簡単にはログインはできない」と言える状態を目指す。
- 異なるユーザーが同じパスワードを使った場合、システム内に保持する文字列を一致させないようにする。なるべく。
  - クラッカーが"cracker1"のパスワードを"password"とかでシステム登録して、そのハッシュを得られた場合、そのハッシュを持つ別のユーザーのパスワードが"password"であることがバレてしまうことを避けたい。
- memo
  - 弱衝突耐性: 特定のハッシュを持つデータを求めることの難しさ
      - こちらの方が難しい
  - 強衝突耐性: 同じハッシュを持つ２つのデータの組を求めることの難しさ
      - 23人集まると、誰かと誰かが同じ誕生日の２人がいる確率は50%以上で、意外と多いという話


## 有名なクラック手法
- [レインボーテーブル](https://ja.wikipedia.org/wiki/%E3%83%AC%E3%82%A4%E3%83%B3%E3%83%9C%E3%83%BC%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB)
  1. 仮のパスワードをたくさん用意する
     - "abcd"とか、"password"とか、機械的に１文字ずつずらして自動生成したもの等を膨大に
  2. それらをすべてmd5、sha256などでハッシュ化して、仮のパスワードとハッシュ化した文字列の対応表を作っておく
     - パスワード候補が多い場合はかなり時間はかかるが、クラッカー視点では、アタックとは別の時に延々とできるので、問題はない。
       - 2012年の[記事](http://passwords12.project.ifi.uio.no/Jeremi_Gosney_Password_Cracking_HPC_Passwords12.pdf)で、8文字英数字の総当たり(220兆パターン)のハッシュを20分で作れるパソコンの記述あり
     - インターネット上でも簡単に入手できそう
  3. 対応表を使い、流出して入手したデータのハッシュ値から、それに対応するパスワードを検索する
     - 瞬間的に検索できる
  4. パスワードを手入力して、システムへログインする
  - ⇒ これに対抗できる必要がある
- 伸長攻撃
  - パスワードmに対するハッシュがわかった場合、mの後ろに文字を付けたハッシュも計算できるという特性を利用し、1文字とか短いパスワードのハッシュをもとにしてパスワードを延ばし(伸長)、長いパスワードのハッシュを計算する方法
  - SHA1、SHA2、MD5などはこの特性を持つ。


## 対応方法
- salt
  - 元のパスワードに、秘密の固定の文字列(saltと呼ぶ)を追加し、それをハッシュ化し、システム内に保持する
  - これによりレインボーテーブルで復元できたとしても、元のパスワードに当たれない
  - システム全体で１つのsaltを使うのでなく、IDからsaltを生成させる（つまりIDごとにsaltが違う）と、解読難易度がさらに上がる
- iteration
  - 生成したハッシュを、元の文章だと思ってもう一度ハッシュ化する、これを繰り返す
  - 繰り返す回数は秘密の回数
    - 適切な回数は、1万、10万、と参考文献によってさまざまだが、コンピューターの性能に依存するので、おそらく年々上がる
    - 一方、上げると突き合わせの時間がちょっと増える
      - クラック側への影響ほどではないが
- HMAC(Hash Based Message Authentication Code)
  1. saltを固定値Aに対して排他的論理和をかけsalt-Aとし、固定値Bにも同様に算出しsalt-Bとする
  2. 元のパスワードにsalt-Aを加えハッシュ化し、h-Aとする
  3. h-Aにsalt-Bを加えハッシュ化し、h-Bとする
  4. h-Bを保存する
  - ⇒ これにより、伸長攻撃に対する耐性と、強衝突耐性が上がる（らしい）


# 参考
- [【Cryptography】Pythonでデータを暗号化する](https://ymgsapo.com/2019/08/05/cryptography-python/)
- [【Python】hashlibによるハッシュ化](https://tech.nkhn37.net/python-hashlib-basic/)
- [ソルトとハッシュ関数だけでパスワードをハッシュ化するのが微妙な理由](https://qiita.com/yyu/items/2196b05208fb730e5af0)
- [いまさら聞けないパスワードの取り扱い方](https://www.slideshare.net/ockeghem/ss-25447896)


# 素朴な疑問メモ
- iterationをしてる間の、例えば100回に一度、前半分と後ろ半分をごそっと入れ替えるとか、換字暗号化するとか、ハッシュ手法変えるとか、そういう非公開のローカルロジックを入れると、耐性がめちゃ上がるのでは？
javaScript84_String型オブジェクトのメソッド

String型オブジェクトに関して使用するメソッドをまとめました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/d6f3b485-7009-fb23-1d89-f9afddae4be5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/09b83c09-1d40-5b60-dc73-9bd92c407a72.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/f0fe3121-fcda-da52-8879-e6378dee2593.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/cb8b7a4c-4b24-d831-edce-0df5e41a6386.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/9b50f55a-2aee-329c-9000-007e8396acdb.png)
Rust 言語仕様01　配列とmutとシャドーイングとprintlnとポインタ

Rustの勉強をしつつコンピュータサイエンスの勉強をしております。さらに、WebAssembly(WASM)も使っていきたいと考えているので、それのアウトプットとして投稿いたします。

まずがベーシックなところから、コードベースで載せます。

## Rust

### 配列

```rust
let a1 = [1, 2, 3, 4, 5];
let a2 = [0; 10];
println!("{:?} {:?} {} {}", a1, a2, a1[2], a1[3]); // => → [1, 2, 3, 4, 5] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 3 4
```

### mut　可変にできるようにする
```rust
let mut x: i32 = 5;
println!("The value of x is: {}", x);
x = 6;
println!("The value of x is: {}", x);
```


### シャドーイングによって前の変数が隠れる
```rust
let y = 5;
println!("Stack address of y is: {:p}", &y); // 格納されているアドレスをポインタ形式で表示
let y = y + 1; // 同じ変数名でletが使える はシャドーイングによって前の変数が隠れる
println!("Stack address of y is: {:p}", &y); // 格納されているアドレスをポインタ形式で表示
let y = y * 2; // 同じ変数名はシャドーイングによって前の変数が隠れる
println!("Stack address of y is: {:p}", &y); // 格納されているアドレスをポインタ形式で表示
println!("The value of y is :{}", y);
```

### println!("Memory address of const is: {:p}", &変数名もしくは定数名);

大体は`{}`で賄えるのが、`{:p}`を利用することで、複雑なデータ型も表示ができる。
`{:p}`と`&`（アンパサンド）で格納されているアドレスをポインタ形式で表示にしています。

### 各要素の値だけではなくポインタも取得する
```rust
let mut t2 = ((0, 1), (2, 3));
let ((ref mut x1_ptr, ref mut y1_ptr), _) = t2; // 各要素の値だけではなくポインタも取得する場合は、refをつける
*x1_ptr = 5; // 参照はずし * アスタリスクつける
*y1_ptr = -5; // 参照はずし * アスタリスクつける
```

## 最後に
まだまだやり始めなので、よく耳にする習得が難しいについて自分はまだわかりません。
ただ、コンピュータの仕組みが知識として知っていたことが今まさに生かされている感覚があるので、これからも引き続き勉強しつつ、Rustの可能性に触れていきながら、自分の目的達成に向かっていこうと思います。
キオスクモードで開いたGoogleChromeをデバッグする

#経緯
諸事情によりキオスクモードのGoogleChromeをDeveloper Toolsでデバッグしようと思ったところ、
キオスクモードの目的考えれば当然なのですが、F12でDeveloper Toolsが立ち上がらなかったのであーだこーだした記録です。

#キオスクモードの立ち上げ方
これ見に来ている時点でわざわざ書く必要はないとは思いますが、こんな感じでキオスクモードは立ち上がります。
` "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --kiosk https://qiita.com/ --user-data-dir="%UserProfile%\Documents\Chrome User Data"` 

` --kiosk`が、キオスクモードの指定です。
すでに別でChromeが立ち上がっている場合、それに引きずられてキオスクモードで立ち上がらなくなってしまうので、
その場合はユーザーデータを切り替えます。取り合えず単品で動かせる場合は不要です。
`--user-data-dir="%UserProfile%\Documents\Chrome User Data"`

※Chromeの場所やユーザーデータフォルダの場所は適宜変更して下さい。

#キオスクモードでのデバッグツールの利用方法
ここからが本題で、キオスクモード時はF12でDeveloper Toolsを立ち上げられません。
このため、Chromeの機能であるリモートデバッグを利用します。本来は、Android端末などを遠隔でデバッグしたい場合に使う機能です。
キオスクモード起動時に、以下のオプションを追加します。
`--remote-debugging-port=9222`

その後、以下のURLに別で起動したChromeでアクセスします。
`chrome://inspect/#devices`
ここで、キオスクモードのChromeしか立ち上げていないと、逆にキオスクモードに引きずられるので、適宜どちらかのユーザーデータフォルダを変えてください。

Remote Targetという欄に、キオスクモードで開いたURLが表示されるので、その下にある「inspect」というリンクをクリックします。
すると、現在キオスクモードで表示している画面のDeveloper Toolsが表示されます。
ここまで来ればいつも通りのデバッグが可能です。

#おまけ
キオスクモードをデバッグしたい場合、基本的にはデュアルディスプレイで作業をしていると思います。
その際にキオスクモードの画面をどちらか望んだ方に出したいケースがあると思います。
その場合は、まず、キオスクモードなし、ユーザーデータフォルダ指定でChromeを立ち上げた後、
出したいディスプレイの方に表示されたChromeを移動させ、最大化した後でChromeを閉じてください。
その後立ち上げると最後に閉じたディスプレイ側でキオスクモードが立ち上がるようになります。

#参考にしたページ
https://developer.mozilla.org/ja/docs/Tools/Remote_Debugging/Chrome_Desktop

http://chrome.half-moon.org/43.html#obcd30eb
XMLでViewにグラデーションの設定をする

まずはdrawableにグラデーションの設定をしていきます

```
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:angle="270"
        android:startColor="#ffffff"
        android:endColor="#0000ff" />
</shape>
```

それぞれ説明していきます

    android:angle="270"
アングル、つまりグラデーションをかける角度のことです
その角度を２７０度に設定することによって　上から下に向けてのグラデーションをかけることができます
グラデーションをかけたい方向を変えたいときは android:angle を調整しましょう
０（未設定）では左から右へ
９０　で　下から上へ
１８０で　右から左へ　のグラデーションになります


    android:startColor="#ffffff"
ffffff は　white

    android:endColor="#0000ff"
0000ff は　blue 



カラーコードや色の名前は
[WEB色見本　原色大辞典](https://www.colordic.org/)
より


今回はwhiteからblue になる設定をしました


そして先ほどのdrawableを　グラデーションをかけたいbackgraundに設定すると

![スクリーンショット 2022-02-20 21.51.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394054/4ff26664-9b0f-496d-bd9b-b96273707512.png)

上から下にかけて白から青にグラデーションのかかったbackgroundを設定することできました
【JavaScript】Object.deepEquals(仮)

こんにちは。

今回はJavaScriptにおける未解決問題(?)のお話です。

## オブジェクト比較
JavaScriptにおいて、オブジェクト同士の比較は非常に面倒なことのひとつです。

割と有名な話なので、いくつかのパターンをざっとおさらいすると...

```ts:Equal
const o1 = {};
const o2 = {};

o1 == o2; // false
o1 === o2; // false
```

それぞれ別インスタンスなので、中身のプロパティが何であれ `false` と解釈されます。

```ts:for-in
const o1 = {};
const o2 = {};

for (const key in o1) {
    if (o1[key] !== o2[key]) {
        throw "Not equal";
    }
}
```

含まれていることは証明されますが、一致の証明にはなりません。
また、ネストしたオブジェクトの場合は、再帰処理をしないと前例のとおり「別インスタンス」と見なされてしまいます。

```ts:JSON-Compare
const o1 = {};
const o2 = {};

JSON.stringify(o1) === JSON.stringify(o2); // ???
```

良さげな感じはしますが、オブジェクトがシリアライズされる時のプロパティの順番は㍉も保証されておらず、実行エンジンやタイミングによって都度変動するため、実は全くアテになりません。

恐ろしいことに、巷ではオブジェクト比較の場面において、この実装が使用されるケースはそこそこあると、風の噂で聞いたことがあります。

他にも、たくさんの諸先輩方がこの難題へ立ち向かおうと執筆された記事が、いくつも存在します。

## deepEquals
そのうち、私が立ち向かい辿り着いた解をご紹介します。

```ts:deep-equals.ts
function deepEquals(d1: unknown, d2: unknown) {
    function toKV(o: unknown) {
        return Object.entries(o).sort(([k1], [k2]) => {
            let i = 0;

            while (k1.at(i) === k2.at(i)) {
                if (k1.at(i) === undefined && k2.at(i) === undefined) {
                    throw "Same property name.";
                }

                i++;
            }

            return (k1.codePointAt(i) ?? 0) - (k2.codePointAt(i) ?? 0);
        });
    }

    if (d1 === d2) {
        return true;
    }

    if (typeof d1 !== "object" || typeof d2 !== "object" || d1 === null || d2 === null) {
        return false;
    }

    const kv1 = toKV(d1);
    const kv2 = toKV(d2);

    if (kv1.length !== kv2.length) {
        return false;
    }

    for (let i = 0; i < kv1.length; i++) {
        const [k1, v1] = kv1.at(i);
        const [k2, v2] = kv2.at(i);

        if (k1 !== k2 || !deepEquals(v1, v2)) {
            return false;
        }
    }

    return true;
}
```

順を追って見ていきましょう。

まずショートサーキットとして、同じインスタンスであれば一致、どちらかが `object` 型でなけれなば不一致となります。
そして必然的に、引数としてプリミティブが入力された際もここで捌くことができます。

次に、当メソッドの特徴である  `Object.entries()` でオブジェクトを配列化し、ソーティングします。

ソーティング方法は、ざっくり言うと前後のプロパティ名をUnicodeの数値へ変換して比較するのですが、プロパティ名が途中まで同じ場合への対策として、同じ文字であれば1文字ずつ位置をずらしていき、異なる文字が現れたときに初めて比較します。
なお、同名プロパティは存在し得えませんが  `while` を使用していることもあり、どちらも `undefined` になった場合は、無限ループ回避で念のため例外を出すようにしています。

ソートを終えたら、双方の配列長を比較し、異なれば則ちプロパティ数が違うことになるので不一致となります。

ここからは `for` ループで1要素ずつ中身を精査していきます。

まず、双方のプロパティ名が異なるか、再起処理でプロパティ値を入力し不一致が返されれば不一致となります。
上述の通り、再起処理は引数として渡すプロパティ値がオブジェクトでもプリミティブでも問題ありません。

そして `for` を抜け、最後まで到達したということは、則ち全て一致していたことになるので `true` を返します。

なお、配列を `Object.entries()` へ入力した場合、インデックスがそのままプロパティ名となるため、引数として配列を入力しても挙動には影響ありません。

```ts
Object.entries(["value", "value", ...]);
// [["0", "value"], ["1", "value"], ...]
```

欠点として、同クラスから生成された異なる `this` の値を持つインスタンスや、単純にメソッドなどは比較できません。

そこだけ注意すれば、割とマトモに動くのではないでしょうか。

## さいごに
JavaScriptのオブジェクト比較は本当に厄介なので、ご指摘などありましたらご教示いただければ幸いです。