OmniAICreator/Qiita-1.07M huggingface dataset:
ブラウザで音声再生ならhowler.js使っておこうな

# howler.js

[howler.js - JavaScript audio library for the modern web](https://howlerjs.com/) は
全てのプラットフォームのwebブラウザ上で音声を簡単に操作できるライブラリです。
画面の遷移時だったり、CSSアニメーション中など、HTMLのaudio要素を直接使わない音声再生をする場合ならとりあえず使っとけ！ってライブラリです。

browser上での音声再生の`面倒くささと難しさ`を引き受けてくれます。

いやいや、でもちょっと音声再生するだけよ？
Audio要素作ってplay呼び出せばいいんじゃない？
と思うところですが、こんな時でも使いましょう。

```javascript

function playSound(url) {
	const audioElem = new Audio();
	audioElem.src = url;
	audioElem.play();
}
```

# なぜ使うのか？
上で記載した程度のコードでもブラウザと端末の組み合わせと状況によっては正しく再生されません。
むしろ正しく再生されることの方が少ないかもしれないです。

基本的にブラウザではユーザインタラクションが発生していないページで突然音声を再生させることはできないです。
このことを知っていると、じゃあそこだけ気を付けておけばライブラリなんて必要ないじゃん！と思ってしまいますが、どうか利用してください。
それだけじゃないんです。

ユーザインタラクション後なら上記コードにある`playSound`をいつ、どんなときに呼び出しても再生が正しくされるか。というとそうはいきません。
AudioContextの扱いや、同時再生数、WebAudioとHTML5 Audioどちらを使うべきか。
考慮すべき点がどんどん出てきます。
ちょっと音声が出したいだけなのに、Webの音声の技術についていろんなことをキャッチアップしないと「アレ！？おかしいぞ！！」がぽんぽんでてきます。
そうなるくらいなら、とりあえず使っておく。というのが私のお勧めです。

# 利用するには？

[GitHub - goldfire/howler.js: Javascript audio library for the modern web.](https://github.com/goldfire/howler.js)

READMEにあるように従えば利用できます。

```javascript

import {Howl, Howler} from 'howler';

const sound = new Howl({
  src: ['sound.mp3']
});

sound.play();
```


1番最初に出したサンプルの`playSound`をhowler.jsを利用して実装してみると以下のようになります。

```javascript

function playSound(url) {
  const sound = new Howl({
    src: [url]
  });

  sound.play();
}
```

TypeScriptを使っているのなら [@types/howler  -  npm](https://www.npmjs.com/package/@types/howler) で型定義ファイルも提供されています。嬉しいですね。

# 最後に
とりあえず音声再生にはhowler.jsを使っておけよ！という主張ですが過去の自分に1番してやりたいです。

ユーザテストを前にして、howler.jsを使わない自前の音声再生の実装が正しく動かないことに気づき、慌てて修正を試みるが治らない！そもそも原因がわからない！！なんてことがありました。
ところがhowler.jsを利用したら起きていた問題は消え去りました。
この時はhowler.jsの存在を知っていたのに入れなかった自分をビンタしたくなったものです。

ライブラリをとりあえず入れる。というのは考えものですが、howler.jsは入れない強い動機がなければとりあえずいれてみてはいかかでしょうか。
Rでの性別、身長、体重、血液型データの作成方法

# はじめに
[こちらの記事](https://qiita.com/ryamamoto0406/items/bd73166848a0c0fda54b)で作成したデータをもっと扱いやすいデータフレームにきちんとまとめようと思い執筆。男女の割合をデータ数に反映する事など改良を行った。データ生成の参考文献については、記事末尾に記載した。

※追記：2021/02/18 コメントで頂いた通り、性別と血液型の生成に `sample` 関数を使う場合のコードも示した。

# データ生成
$N$人についてランダムサンプルを行った際の性別、身長、体重、血液型の模擬データの作成コードを以下に示す。最初の変数指定でデータのパラメータが調整可能なようにした。

```R:
###パラメータ
#人口の男女比
male <- 6143 #万人
female <- 6480 #万人

#男女の身長、BMIの値
male.height.mean <- 171.7 #cm
male.height.sd <- 6.6 #cm
male.bmi.mean <- 23.12
male.bmi.sd <- 4.24
female.height.mean <- 158.3 #cm
female.height.sd <- 5.7 #cm
female.bmi.mean <- 20.82
female.bmi.sd <- 3.42

#血液型の割合
A <- 0.39
B <- 0.22
O <- 0.29
AB <- 0.10

#データ数
N <- 1000


###男女のベクトルを作成
mf <- c()
for(i in 1:N){
  tmp <- runif(1)
  if (tmp < (male/(male+female))) mf <- c(mf, "male")
  else                            mf <- c(mf, "female")
}

###血液型のベクトルを作成
bt <- c()
for(i in 1:N){
  tmp <- runif(1)
  if (tmp < A)                           bt <- c(bt, "A")
  else if (A <= tmp & tmp < (A+B))       bt <- c(bt, "B")
  else if ((A+B) <= tmp & tmp < (A+B+O)) bt <- c(bt, "O")
  else                                   bt <- c(bt, "AB")
}

###身長、体重のベクトルを作成
h <- c()
w <- c()
for (i in 1:N) {
  if (mf[i] == "male") {
    height <- rnorm(n=1,mean=male.height.mean,sd=male.height.sd)
    bmi <- rnorm(n=1,mean=male.bmi.mean,sd=male.bmi.sd)
  } else {
    height <- rnorm(n=1,mean=female.height.mean,sd=female.height.sd)
    bmi <- rnorm(n=1,mean=female.bmi.mean,sd=female.bmi.sd)
  }
  weight <- (height * 0.01)^2 * bmi
  h <- c(h, height)
  w <- c(w, weight)
}

###data.frame化
df <- data.frame(SEX=mf,HEIGHT=h,WEIGHT=w,BLOOD=bt)
```

生成されたデータを見てみると…、

```R:コード
head(df)
```

```:出力
     SEX   HEIGHT   WEIGHT BLOOD
1 female 158.4726 40.46012     B
2   male 178.1273 68.64015     A
3   male 176.7241 65.13530     O
4 female 166.6573 44.02083     A
5   male 168.1153 57.24288     A
6   male 179.5274 82.10058     A
```
となる。一応できてそう。

# `sample` 関数を使った場合
上記のコードの26行目から42行目を下記の様に書き換える。

```R:
###男女のベクトルを作成
mf <- sample(c("male","female"), N, replace = TRUE, prob = c(male, female))

###血液型のベクトルを作成
bt <- sample(c("A","B","O","AB"), N, replace = TRUE, prob = c(A,B,O,AB))
```
こうすると1行で書けるのでだいぶすっきりする。コメントありがとうございました！

# データの可視化
作成したデータの可視化については[こちらの記事](https://qiita.com/ryamamoto0406/items/c5eb550a61a7daadfb0d)でいろいろなプロットを作ってみる事とする。

# 参考文献

- [【機械学習】練習用データセットの作成【身長・体重】](https://qiita.com/sakabe/items/df7fac64e6ffbb50848c)
- https://keisan.casio.jp/exec/system/1374719499
- https://www.stat.go.jp/data/jinsui/topics/topi1201.html
rbenv installでエラーが出たときのメモ

#環境
MacOS 10.13

#エラー
```
dyld: Library not loaded: ＄HOME/.rbenv/versions/3.0.0/lib/libruby.3.0.dylib
```
#対処
なぜうまくいくか知らないが以下を実施
### `global`のバージョンを`system`より上のバージョンに変更

```
* system
  2.7.2 (set by $HOME/.rbenv/version)
```
↓

```
  system
* 2.7.2 (set by $HOME/.rbenv/version)
```
Junitでthe temporary folder has not yet been created例外


## 発生バージョン

- Spring boot 2.4.2

## トレースログ
```
java.lang.IllegalStateException: the temporary folder has not yet been created
    at org.junit.rules.TemporaryFolder.getRoot(TemporaryFolder.java:299)
    ...
```

## 原因のコード

```java
@Rule
private TemporaryFolder tempFolder = new TemporaryFolder();
```

## 原因
`@Rule`, `TemporaryFolder`はJunit5で削除されていた。
JUnit3 -> 4みたいに破壊的な変更はないんだな～と思いながら書いてけど、そうでもなかったｗ

## JUnit5での書き方
```java
@TempDir
public Path tempFolder;
```


そもそも使わなくなった@RuleとTemporaryFolderがなんで@Deprecatedされてないんだと思い調べてみたところ、`spring-boot-starter-test`だけ依存してる場合は@Rule等が参照できずコンパイルエラーになりました。  
少なくとも`spring-batch-test`を依存関係に追加すると、使えもしないのにJunit4のモジュールが参照できてしまうようです。  
使わないなら消しといたほうがよさそうです。

```diff_gradle
dependencies {
    ...

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
-   testImplementation 'org.springframework.batch:spring-batch-test'

    ...
}
```
【メモ】Swagger UIを使ってみる

Swagger UIを使ってみたときのメモです。

* Swagger Editorを開く
https://editor.swagger.io/ 

* Generate Serverから、nodejs-serverを選択して、zipファイルをダウンロード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580406/c88bddfc-69bc-83d4-caea-bd820f16eedc.png)

* zipファイルを解凍
* コマンドプロンプトで以下実行

```
$ cd (解凍したファイルの場所)\nodejs-server-server-generated\nodejs-server-server
$ npm install
$ node index.js
Your server is listening on port 8080 (http://localhost:8080)
Swagger-ui is available on http://localhost:8080/docs
```

* http://localhost:8080/docs にアクセスすると、Swagger UIが見れる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580406/33013869-e66f-46b1-8dda-e37de0b04a3a.png)
* [Ctrl]+[c] 2回で終了。（コマンドプロンプトの場合）

# 参考サイト
* [Qiita - Swaggerの概要をまとめてみた。](https://qiita.com/gcyata/items/342073fa7607fd4082bd)
* [Qiita - SwaggerでRESTful APIの管理を楽にする](https://qiita.com/disc99/items/37228f5d687ad2969aa2)
LilyGO TTGO ESP32の復旧方法

TTGO Tジャーナルカメラモジュール開発ボードOV2640(LilyGO製外部アンテナ付ESP32 Cameraボード)にArduinoでサンプルプログラムを微修正したものを書き込んでたら、ある時、正常に動かなくなってしまった。

(2021/2/22追記 はじめ)
「正常に動かなくなってしまった。」は誤りで
実際には、「......」表示が出続けてたのは、WiFi親機への接続待ち状態を表しており、その時、5GHzのSSIDに対して接続しようとしていたのが問題だった。
ただ、本手順は、あるバイナリイメージの書き込み手順としては使えるので　このまま置いておく。
(2021/2/22追記 おわり)

![41heVNTY9HL._AC_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131546/242693ef-6475-354c-7921-d1f72b49a6ac.jpeg)

![41WGMeTmLGL._AC_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131546/109e7bea-dee7-ef4b-4c24-c598b3a0bee6.jpeg)

![41Wi5UpZmVL._AC_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131546/beea4c10-ca68-37a5-56d6-e3cdb9789770.jpeg)

USBシリアルでTeraTermで見ると
ずっと「......」表示が出続けます。何かをウェイトしている？
同じスケッチを３回　書き込み直しても同じ症状だった。

なんとか工場出荷状態に戻せたので、その手順を記す。

# 1.ダウンロードツールの入手
ESP32製造元の[ESPRESSIF Tools](https://www.espressif.com/en/support/download/other-tools)で
Flash Download Tools (ESP8266 & ESP32 & ESP32-S2) をダウンロードする。
(2021年2月17日現在、V3.8.6 2020.04.26 が最新)

# 2.LilyGO TTGO ESP32の工場出荷時のバイナリイメージ取得
https://github.com/LilyGO/ESP32-Camera
にアクセスし、一式を取得する。
私の場合はGit GUIを用いて
https://github.com/LilyGO/ESP32-Camera.git
からクローンした。

# 3.Flash Download Toolの起動
先にダウンロードしたFlash Download Toolのzipファイルを解凍し
flash_download_tool_3.8.5.exe
を起動する。
![2021-02-17 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131546/b882c32f-036f-f5fe-7359-fecb308fcc34.png)
「Developer Mode」ボタン押下。
![2021-02-17 (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131546/07c5437e-8336-17d1-caf7-993f63426e89.png)
「ESP32 DownloadTool」ボタン押下。

# 4.Flash Download Toolの設定
「2.LilyGO TTGO ESP32の工場出荷時のバイナリイメージ取得」で取得したファイル中の
bin/Config.jpg
がFlash Download Toolの設定のスクリーンショットなので
これを真似して設定する。
右下のCOMポート番号は　そのまま真似せず、自分の環境に合わせて設定する。ボーレート(BAUD)はイジらない。
必要な全てのファイルは、bin/ フォルダ内に存在する。
左のチェックボックスにチェックを入れるのを忘れないこと。（私はチェックしないまま、Startボタンを押していた…）

# 5.バイナリイメージの書き込み
![2021-02-17 (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131546/50984b83-8f1d-3d10-9312-90d2f94c8b00.png)
左下の「START」ボタン押下。
何分もしない内に「FINISH」と表示されるので終わり。

これで、リセットすれば（リセットボタン押下　か　USBケーブル抜き挿し）
SoftAPモードで立ち上がり、OLEDにIPアドレスが表示される。
PCで無線LAN AP「TTGO-CAMERA」に接続後、webブラウザで同IPアドレスにアクセスしたら
ボードのカメラのプレビューが表示された。

めでたしめでたし。
【LINE BOT】NBA選手のスタッツを返信する公式アカウントを作った。

#NBA stats というLINE公式アカウントを作りました(beta版)。

このボタンをクリックして追加できます。
(2/18追記:現在メンテナンス中)

<a href="https://lin.ee/TTVGVXY"><img src="https://scdn.line-apps.com/n/line_add_friends/btn/ja.png" alt="友だち追加" height="36" border="0"></a>

##機能

選手名を送信すると直近のスタッツがflex message形式で返信されるというもの。
こんな感じ↓

![10CDDB62-FBC7-4158-8436-749CFC851AB4_1_105_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/996173/4a368144-8894-69dc-4339-052515844821.jpeg)

よきっち, トリプルダブルの活躍。

##何を打てば返信してくれるのか。


| You send... | type | OK or error |
|:----------:|:-----------:|:------------:|
| Andre Drummond       | 英語, フルネーム, 先頭大文字        | OK!         |
| andre drummond     | 英語, フルネーム, 小文字      | OK!       |
| AndreDrummond      | 英語, フルネーム, 空白なし        | error...         |
| Andre Drummond !       | 余計な文字 (!など）          | error...           |
| Harden       | 英語, 部分のみ, 先頭大文字       | OK!       |
| zion    |  英語, 部分のみ, 小文字    | OK!       |
| れぶろん    |  日本語ひらがな (愛称)    | OK!       |
| ていたむ    |  日本語ひらがな (愛称)    | OK!       |
| るか    |  日本語ひらがな (愛称)    | OK!       |
| :    |  :    | :       |
| ルカ    |  日本語カタカナ (愛称)    | error...       |

愛称については下記を参考にしてください。もっと追加していく予定です。

```
{
    "ていたむ": "Jayson Tatum", "るか": "Luka Dončić", "やにす": "Giannis Antetokounmpo", "れぶろん": "LeBron James", "らめろ": "LaMelo Ball", 
    "けんば": "Kemba Walker", "かりー": "Stephen Curry", "よきっち": "Nikola Jokić", "ヘジテーション": "Jaylen Brown", "るい": "Rui Hachimura", "ゆうた": "Yuta Watanabe",
    "kp": "Kristaps Porziņģis", "めろ": "Carmelo Anthony", "ぺいとん": "Payton Pritchard", "ぶっかー": "Devin Booker", "ad": "Anthony Davis","kd": "Kevin Durant",
    "あーびんぐ": "Kyrie Irving", "はーでん": "James Harden", "まれー": "Jamal Murray", "でいむ": "Damian Lillard", "ごべあ": "Rudy Gobert", "しもんず": "Ben Simmons"
}
```

##現在の問題点


①エラーのメッセージを改良。

②フロント整える。

③『Nikola Jokić』や『Luka Dončić』など、英語アルファベットではない(?)ものについては、現在変換されていない。つまり、『doncic』と打ってもエラーになってしまう。「č」や「ć」を「c」と変換させるコードを追加する。

④『curry』と打つと『Seth Curry』か『Stephen Curry』の選択ができるようにしたい。ボタンで選べるように。

(Githubはコードが整い次第公開予定。)
M1 Mac で Docker イメージをビルドしようとすると no match for platform in manifest が出る

# TL;DR
## docker
`docker build -t name --platform linux/amd64 .`

## docker compose
`services` の該当コンテナ定義に以下を追記。

```yaml
services:
  db:
    # 略
    platform: linux/amd64
```

# 背景

```Dockerfile
FROM mysql:5.7
```

M1 Mac上でこれだけ書いた `Dockerfile` を `docker build -t my_mysql .` でビルドしようとすると以下のエラーが出ます。

```
failed to solve with frontend dockerfile.v0: failed to create LLB definition: no match for platform in manifest sha256:853105ad984a9fe87dd109be6756e1fbdba8b003b303d88ac0dda6b455f36556: not found
```

`docker pull --platform linux/amd64 mysql:5.7 && docker run -it --rm mysql:5.7` は正常に動作するのでなぜ？と思っていたのですがビルド時にも `platform` を指定する必要があったようです。考えてみれば当たり前ですし後から振り返ると対策もtrivialなんですがマルチCPUアーキテクチャを意識せずにボケっとDockerを使っていたので無駄にハマりました。ググってもヒットしなかったので同じトラップにハマってる人の助けになればと思い備忘録的に記録することにしました。
カイ二乗分布・t分布・正規分布・F分布をPythonで使う方法 まとめ

数値解析ライブラリScipyのstatsを使えば，様々な統計量を簡単に使うことができます．しかし，資料が分散していたり，記事が英語だったりで，いざ統計量を使いたいというときにパッと使えなかったりします．
本記事は統計でもよく使う カイ二乗分布/t分布/正規分布/F分布 の使い方について，簡単にまとめています．Pythonで統計量を使う際の早引きとなれば幸いです．

##Scipy.statsのインポート
t分布などの名前がシンプルなので，名前かぶりを防ぐよう下記でインポートしておきます．

```Python
import scipy.stats as sps
```

##下側累積確率を指定してパーセント点を得る
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534476/07120dfb-fb16-41f6-0294-8960810451ec.png" width=80%>

```Python
#カイ二乗分布（q : 下側累積確率，df : 自由度）
sps.chi2.ppf(q = 0.95, df = 4)

# t分布（q : 下側累積確率，df : 自由度）
sps.t.ppf(q = 0.95, df = 4)

#正規分布（q : 下側累積確率）
sps.norm.ppf(q = 0.95)

#F分布（q : 下側累積確率，dfn : 自由度ν1，dfb : 自由度v2）
sps.f.ppf(q = 0.95, dfn = 3, dfd = 2)
```

##パーセント点を指定して下側累積確率を得る
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534476/b02572ec-06f5-28a2-b41c-1a2a005d9436.png" width=80%>

```Python
#カイ二乗分布（x : パーセント点，df : 自由度）
sps.chi2.cdf(x = 0.710723, df = 4)

# t分布（x : パーセント点，df : 自由度）
sps.t.cdf(x = 2.13184, df = 4)

#正規分布（x : パーセント点）
sps.norm.cdf(x = 0.710723)

#F分布（x : パーセント点，dfn : 自由度ν1，dfb : 自由度v2）
sps.f.cdf(x = 19.164292, dfn = 3, dfd = 2)
```
####参考サイト
http://njf.jp/cms/modules/xpwiki/?Python%2F%E3%82%AB%E3%82%A4%E4%BA%8C%E4%B9%97%E5%88%86%E5%B8%83

https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.f.html
herokuに変更を反映できない。branchの問題

**問題**
herokuに変更を反映できない。

**原因**
ローカル環境でbranchをmargeしてなかった。


**環境**
laravel
cloud9
heroku
ブランチ名：validate



**手順**
①
$ git log
コミット履歴の閲覧

```
commit 7ed952f927331833295a120672ed70c3f0793402 (HEAD -> validate, origin/validate)
Author: ＊＊＊＊
Date:   Tue Feb 16 11:50:26 2021 +0000

    error_commit
```
②
$ git status

```
On branch validate
Your branch is up to date with 'origin/validate'.

nothing to commit, working tree clean
```
③
$ git checkout main
mainブランチに切り替え
（$ git checkout ブランチ名　：特定のブランチやコミットに切り替える）

④
$ git merge validate
validateブランチをmergeする

⑤
$ git status
セッションとクッキーの違い

#ブラウザにおける情報の一時記憶

`「昨日ログインしたサービスを今日も利用しようとしたら、自動的にログインの状態になっていた」`という経験があるかと思います。

>TwitterやこのQiitaもその機能が搭載されている
その都度ログインを行わなくて良いので便利

この機能が実現できるのは、`セッション`と`クッキー`という仕組みのおかげ
Webアプリケーションの使い勝手が良くなるため多くのサービスで使用されている

>ゴリゴリのSPが出入り口にいて色々手続きをしないと入場できない施設が常連になると顔パスで素通り出来る様になる感じ？

##セッションとは
**Webサービスにおいて`情報を一時的にDBに記憶`しておく仕組み**

ショッピングサイトにログインしていると「お買い物カゴ」などに商品を追加でき、その状態を維持できるようになっている

>ユーザーの情報やお買い物カゴの情報を一時的に保存し、初回のログイン以降も保持することで、一度ショッピングサイトのページを離れても、再度アクセスした時にログインの状態やお買い物カゴの情報を維持したままショッピングが再開できる仕組みが実装されている

**この仕組みにより、何度もログインする必要がなくなる**

###session
Ruby on Railsでセッションを使用する際に使うオブジェクト
コントローラーで使用することが出来る

```rb:◯◯s_controller.rb
class ◯◯sController < ApplicationController
 def index
  session[:sample] = 1
 end
end
```
- sessionというハッシュに値を追加するような記述で使用
- ユーザー情報を保持したい場合などに用いると便利
- deviseというGemで実装すると自動でセッションを利用できる
    - 内部の処理でセッションを利用してログイン機能を実現しています。

---

##クッキーとは
ブラウザが持っている、`データを保存できる領域`のこと
ブラウザにあるセッションの情報の保存場所のことを`クッキー`
**Webサービスにおいて`情報を一時的にブラウザに記憶`しておく仕組み**

>「Google Chrome」にも導入されている
Ruby on Railsにも、セッションの保存先がある

###CookieStore
- Ruby on Railsでセッションを用いる際の、デフォルトの保存先
- `セッションストレージ`と呼ぶことが一般的

セッションはCookieStoreに`ハッシュ形式で保存される`
session[:sample]という記述は、

```rb:◯◯s_controller.rb
class ◯◯sController < ApplicationController
 def index
  session[:sample] = 1
 end
end
```
ハッシュと同じ記法でしたが、これがその理由です。

`セッションは悪意のあるユーザーが利用すると非常に厄介な項目`
ユーザー情報をセッションを用いて一時的に保存していたら、その情報が盗まれて悪用されてしまう可能性がある
そうならないために、CookieStoreはセッションの情報を暗号化したり、また定期的にリセットしたりすることで対策を行っている
投稿　新しい順に表示　laravel

問題
SNSサイトを作ったが、
投稿が古い順に表示される。
投稿日時が新しい順にしたい。

解決
sortByDescを使う。
（メモ：sortByDescは降順sortByは昇順）

Controllerを編集
例）

```php


class DogsController extends Controller
{
    // 投稿された記事の一覧を表示する
    public function index(Request $request)
    {
        $tags = Tag::all();
        $pref = $request->pref;
        $city = $request->city;
        $place = $request->place;
        $query = Post::query();
        if ($pref != '') {
        $query->where('pref', $pref);
        }
        if(!empty($city)) {   
        $query->where('city', 'like', '%'.$city.'%');
        }
        if ($place != '') {
        $query->where('place', 'like', '%'.$place.'%');
        }
        if ($request->tags && 0 < count($request->tags)){
        $query->whereIn('id', Post::getPostIdbyTags($request->tags));
        }
//この一文を書き換える！
        $posts = $query->get();
//下に書き換えた
        $posts = $query->get()->sortByDesc('created_at');


        return view('dogs.index', ['posts' => $posts, 'pref' => $pref, 'tags' => $tags]);
    }

```
【JavaScript】実行コンテキストの違いによるthisの参照先について

転職先の業務でReactを使うので勉強していたところ、公式Docs中の文で分からなかった箇所があったので調べてまとめました。ぱっと見て分からない場合は、ぜひ読み進めていただけると分かると思います。

> JavaScriptにおいて、以下の2つのコードは同等ではありません。
https://ja.reactjs.org/docs/faq-functions.html より

```javascript
obj.method();
var method = obj.method;
method();
```

## 実行コンテキストによってthisの参照先が異なる

どっちも同じことをしているのではないかと思われたかもしれません。しかし、オブジェクトの中にthisが存在すると話が変わってきます。

```javascript:sample.js
window.name = 'Suzuki';

const obj = {
    name: 'Sakai',
    method: function() {
        console.log('Hello! ' + this.name);
    }
}

obj.method();  // Hello! Sakai
var method = obj.method;
method();  // Hello! Suzuki
```

ここで大事なのが、thisが何を参照するかです。
**オブジェクトのメソッドとして実行される場合、thisは呼び出し元のオブジェクトを参照**します。一方、**関数として実行される場合、グローバルオブジェクトを参照**します。

`obj.method()`の形で実行された場合、`method`はオブジェクトのメソッドとして実行されているので、`this`は呼び出し元のオブジェクト、つまり`obj`を参照します。従って、コンソールには`Hello! Sakai`が出力される。

一方、`var method = obj.method;`で変数`method`に**関数の形で保存**され、`method()`でその関数が実行される形になるので、`this`の参照先はグローバルオブジェクトとなる。従って、コンソールには`Hello! Suzuki`が出力される。

## 参照先のオブジェクトを固定するにはbindを使う
`this`を使う場合に注意が必要なのは、分かっていただけたかと思います。ただ、
関数として実行してかつ`obj`の`name`を参照したい場合もあるかと思います。そういうときは`bind`を使います。

```javascript:sample.js
window.name = 'Suzuki';

const obj = {
    name: 'Sakai',
    method: function() {
        console.log('Hello! ' + this.name);
    }
}

obj.method();  // Hello! Sakai
var method = obj.method.bind(obj);
method();  // Hello! Sakai
```

`var method = obj.method.bind(obj)`のようにbindメソッドを使います。これは、bindの引数のオブジェクトを`method`の中で実行される`this`の参照先として設定しています。そうすることで、関数として実行しても`this`の参照先が`obj`にバインド(英語で結びつけるという意味です)されているので、`obj.method()`と同じ結果が得られます。


## さいごに
最初に戻ると、bindを使ってやると下の2つのコードは同等になります。

```javascript
obj.method();
// var method = obj.method
var method = obj.method.bind(obj);
method();
```

何か間違いや分かりにくいところがあれば教えてくださると幸いです。
ここまで読んでいただきありがとうございました。
【Ruby】ライブラリまとめ（標準ライブラリ？組み込みライブラリ？外部ライブラリ？）


Rubyには、初期状態で使えるクラス・モジュールが多く用意されています。
今回は、ライブラリの概要を整理しました。

## 概要図
![スクリーンショット 2021-02-17 17.24.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184054/ae1945a1-71e2-fadd-b854-341ae32994ae.png)


## 標準ライブラリ

標準ライブラリは、組み込みライブラリと組み込みではないライブラリに分けることができます。

### 組み込みライブラリ

組み込みライブラリは、Ruby本体に組み込まれているライブラリです。

***文字列のStringクラス
数値のIntegerクラス
ハッシュのHashクラス
配列のArrayクラス***

などが例として挙げられ、プログラミングをしていく上で最低限の機能が用意されています。

このライブラリに含まれるクラスやモジュールは `require` を書かなくても使うことができます。
※`require`は外部のRubyファイルを読み込むためのメソッドです。
そのため下記のようにメソッドを使うことが出来ます。（class Array）

```ruby:test.rb
p [1, 2, 3]
=> [1, 2, 3]

[1, 2, 3].length
=> 3
```

参考：[組み込みライブラリ](https://docs.ruby-lang.org/ja/latest/library/_builtin.html)

### 組み込みではないライブラリ

組み込みではないライブラリを使うためには `require`で読み込む必要があります。ここが組み込みライブラリとの違いです。

Dateクラスを例にします。
Dateクラスは日付を扱うことができます。

```ruby
require "date"

puts Date.today
# => 2021-02-17
```

`require` を抜きにして実行をすると下記のようにエラーが発生します。

```ruby:test.rb
# require "date"

puts Date.today
```

```:ターミナル
`<main>': uninitialized constant Date (NameError)
Did you mean?  Data
```

参考：[ライブラリ一覧](https://docs.ruby-lang.org/ja/latest/library/index.html)

## 外部ライブラリ

次に外部ライブラリに関してです。

標準ライブラリのおかげで様々なことができますが、それで全てが網羅されているわけではありません。そこで登場するのが外部ライブラリです。


外部ライブラリはRuby本体に含まれていないため、
使いたいライブラリは環境にインストールする必要があります。

そしてそれらは `gem` という形式で公開されています。

Ruby のライブラリは主に [RubyGems.org](http://rubygems.org/) に gem として置かれています。直接ウェブサイトを閲覧したり、gem コマンドを使用してそれらを探すことができます。

gemは世界中の有志が作成しています。
そのため、自分が作成して、公開することも可能です！

使い方としては下記2点が必要です。

- gemをインストールする
- インストールしたgemを読み込み使用する


```ターミナル
$ gem install gem名
```

```ruby
require 'gem名'

# 処理
```

## まとめ
このように先人の方々の偉大な設計のもプログラミングが出来ていると思うと感慨深いです。


記事に関して、修正・指摘などございましたらご連絡頂ければ幸いです！
備忘録　俺得　いつか丁寧に記事にする

##cloudinary edit処理##
1 formにdataのうむの核にン upload(form) delete(oldpublicid) getfile(newpublcid) 
apiのcall数が2倍(delete and upload)下は1回(upload)
2 publicid and url are stayのほうが更新は楽だがformを介してpublicidを持ってuploadする方法がわからない
##formに入力されたデータの受取##
cha_name = form.cleaned_data.get('cha_name')
register_number = form.cleaned_data.get('register_number')
cha_url = form.cleaned_data.get('cha_url')    
results['genre'] = request.POST.getlist("genre")
genre = {'genre_id': results}
##localhostが勝手にhttpsにリダイレクト##
1度setting.pyでhttpsにリダイレクトしてくれるコードを追加したところlocalhostで安全な接続ができないかなんとかが出てサーバーが立てられなかったのでコードを消した。するとそれ以降毎回httpsにredirectされてしまった
->
Chrome 設定 > 詳細設定 > 閲覧履歴データを消去する > 「キャッシュされた画像とファイル」にチェックを入れデータ消去を実行
##form.is_validがエラーになる##
->引っ張て来ているformのform.pyにおけるfieldがすべて検証されているか
##改めてherokuにデプロイしたときにmakemigrations/migrateはうまくいくのにカラムがないと怒られる##
$ heroku run python manage.py dbshell
でデータベースの中身を確認したところローカルの奴と違う
↑開発しているときにdb,migrationsを削除したからテーブルの中身が反映されていない
->herokuのアドオンからdbを削除して再びmigrations/migrateをすればうまくテーブルが作られた
dbを消さずにカラムなどを追加する方法を学ばねば運用できないやばい
##manytomanyfieldのデータ作成追加削除##
参考
https://djangobrothers.com/blogs/many_to_many_objects/
##いいね機能の実装##
https://h-memo.com/how-to-make-a-like-button-using-django-session/
これを参考に脳死でできた
##テーブルをまたいだレコードの取得##
genreに繋がったchannelに繋がったfavのuser_idがuser.idに一致するgenreを取得
genres = Genre.objects.filter(channel__fav__user_id = user.id).all()
##googleanalyticsapiを使ってユーザーに訪問者数を確認できるようにする##
初期設定　https://zerofromlight.com/blogs/detail/36/　
データ取得　https://zerofromlight.com/blogs/detail/40/
##googleサービスアカウントの秘密鍵jsonファイルをherokuで読み込ませる##
##csvをherokupostgresにリモートから追加する##
https://tanuhack.com/pandas-heroku-postgres/#DataFrame-2
Windows10に20H2を適用されるために翻弄されたメモ

あるユーザーのPCのWindows10が1909で
20H2にしたいなーと
色々やって駄目だったので
結局
https://www.microsoft.com/ja-jp/software-download/windows10
の
Update Assistant が最新バージョンの Windows 10 へのアップデートをお手伝いします。開始するには、 [今すぐアップデート] をクリックします。

で【今すぐアップデート】をやったのですが

結構時間がかかる……

デスクトップにショットカットが出来ているが
それに気が付かずモガイていてミスりました(^_^;)

100%になるまで時間がかかるので明日確認っ
PythonでXMLを辞書にしたり辞書をXMLにしたりする

以下ライブラリを使います。

PyPI：https://pypi.org/project/xmltodict/
GitHub：https://github.com/martinblech/xmltodict
PyPI：https://pypi.org/project/dicttoxml/
GitHub：https://github.com/quandyfactory/dicttoxml

# インストール方法

```
>pip install xmltodict
>pip install dicttoxml
```

# 実装

```python:convert_xml.py
import xmltodict
import dicttoxml
import json

xml = """<?xml version="1.0" encoding="UTF-8" ?>
<foods>
  <food>
    <name>イチゴ</name>
    <color>赤</color>
  </food>

  <food>
    <name>バナナ</name>
    <color>黄</color>
  </food>
</foods>
"""

# XMLから辞書に変換
dict_xml = xmltodict.parse(xml)
print(json.dumps(dict_xml, indent=2, ensure_ascii=False))

# 辞書からXMLに変換
# attr_type：属性に型名を付ける
# root：rootの要素を付与する
xml = dicttoxml.dicttoxml(dict_xml, attr_type=False, root=False)
print(xml.decode('utf-8'))
```

# 結果

```
>python convert_xml.py
{
  "foods": {
    "food": [
      {
        "name": "イチゴ",
        "color": "赤"
      },
      {
        "name": "バナナ",
        "color": "黄"
      }
    ]
  }
}
<foods><food><item><name>イチゴ</name><color>赤</color></item><item><name>バナナ</name><color>黄</color></item></food></foods>
```

配列は`<item>`要素でラップされたり、属性はうまく復元できないので完全にもとに戻すのは難しそう。
Netlifyでリバースプロキシする

（netlify-cliをインストール済み・Gatsbyを使っている）
①netlify login
②gatsby-node.jsを編集

```
  createRedirect({
    fromPath: '/news/*',
    toPath: 'https://foge/blog/:splat',
    isPermanent: true,
    force: true,
  });
```

* fromPathにて、ワイルドカード以降で渡されたPathが、『:splat』にそのまま入ってリダイレクトされる。
* isPermanent：status codeを301にする。（意味とstatusCodeを一致させる。）
    * buildしたら```_rediercts```に301の行ができる。
    * 昔はSEOの観点で301と302で差があったみたい。現在は差はなく、速度は301のほうが早いとのこと。
        * 参考：https://www.suzukikenichi.com/blog/both-301-and-302-pass-full-pagerank/
* force：fromPathが一部一致してたらリダイレクトがトリガーされる。

【Netlify】https://docs.netlify.com/routing/redirects/redirect-options/#splats
【Gatsby】https://www.gatsbyjs.com/plugins/gatsby-plugin-netlify/

③netlify build
④netlify deploy
ExcelVBA怖いよ

#初めまして、とある企業内で、サーバ管理してます。
検索すると、とにかくQiitaにお世話になっているので、少しは恩返し（なるのか？）と思って、何かと乗り切っていることを、バレないように書こうかなと。

###泣けてくるぜレガシーVBA###
いきなり、キミ、スクリプト出来るので、VBAも出来るよね？
と渡される、何の仕様も残っていないVBAファイル。
*近代化よろしく*と言われても、どうすりゃいいの？

中身を覘くと、VBA好きの現場の方が、ネット見て、くみ上げた超大作。
もちろん、あとから直すことを考えていないので、もう力業のオンパレード。
しかも、現場はExcel以外受け付けないよと言われる始末。

僕も知らなかったのですが、VB.netぐらいのコトが出来るだろうと舐めてたら、
**.netのクラス読み出せたら簡単だろう**と高をくくってると
実は、<font color="DeepPink">VBAとVBって別物</font>なんですね。
調べても、ズバッと言ってくれてるサイトは無いし、ここでメモとして書いておこう。

###そこで、外部プログラムをキックですよ###
ExcelVBA→Powershell→CSV出力→ExcelVBA
この方法だと、~~時代遅れ~~（失礼）なVBAを使わなくて済む。

あと、ExcelVBAからのキックだと、副産物として、
必要なライブラリーを読み込むことが可能になります。

Powershell5.1だと、例えば、標準で、AccountManagementがロードされていないわけで、
classを利用している場合、Add-Typeしていても、瞬間Error、この辺が防げるのが強み。

```VB
Dim objWSH as Object
Set objWSH = CreateObject("Wscript.shell")
objWSH.Run "powershell -Nologo -ExecutionPolicy RemoteSigned -Command " test.ps1
```
test.ps1の前に、ロードしたいモジュールを記述するとOK

```powershell
"Add-Type 'System.DirectoryService.AccountManagement';"
```

※ADを検索するのに、DirectorySearcherを使っている方は、比較的簡単に使える、AccountManagementを利用すると、若干楽になるかも。なぜか、標準で読み込まれないんですよね。

後は、外部で実行、結果をCSVにして、VBAでCSV読み込みにして、完了。
見た目は、Excelで操作しているので、Excel至上主義の人にもセーフですね。

ではでは、次回の講釈で。続きが書けるといいなぁ。
Windowsでフォルダ分けして整理したファイルを１箇所にまとめたい

# なぜこんな記事を？
Windowsを使っているとMacと違ってファイルにラベリングできない都合もあって、フォルダ階層でファイル整理することが多いです。その場合に整理すればするほどディレクトリの階層が深くなって後から見返すのが不便になります。

例えば、報告書のPDFファイルを章ごとにフォルダ分けして保存したが、これをすべて一つのフォルダに集めてPDF結合したい場合や、日報CSVファイルを年別フォルダの下の月別フォルダにきれいに保存していたがバックアップに際して一つのフォルダに集約したいということは結構あります。

## バッチファイルの中身
以下のコードをメモ帳に打ち込んで、.batの拡張子で保存してください。

``` bat
@echo off
SETLOCAL enabledelayedexpansion
for /d %%i in (.\*) do (
cd %%i
rem 該当ファイルの拡張子をこの行で指定。
for /r . %%j in (*.pdf) do (
set STR=%%j
set STR=!STR:%CD%\=!
set STR=!STR:\=_!
copy "%%j" "%CD%\!STR!"
)
cd ..
)
ENDLOCAL
```

## 使い方
あとはこのバッチファイルをファイルを集約したいディレクトリにおいて、ダブルクリックして実行してください。

そのフォルダにそのディレクトリ以下の該当ファイルがコピーされて集約されます。コピーする時には元々整理されていたフォルダ名を元にリネームされるので集約後のファイルもきちんと整理された状態になります。
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111) 　対処法

MySQLを起動させようと思ってやってみたら

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111) 

でかなり詰まったのでぜひ誰かの役に立てばと思い書きました。



まず、ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111) 対処法などでググってみましたが、/var/lib/mysql/mysql.sock　がないとか権限がないとかだったのでちょっと困ったぞと。

https://qiita.com/edward999th/items/f62af00c0a0975dfbe57

上の記事を参考にするととりあえずログを見るところまではできたのでログを見ると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636843/a5bd36d8-f0a2-b992-2ce8-41cf010d4553.png)


なんかメモリが足りなさそう、、、、ということで


https://www.memory-lovers.blog/entry/2018/02/04/170033


t2.micro swap 拡張などで検索したら出てくると思いますがこの記事などを参考にしてsawp領域を広げました。

このエラーはt2.microを使っていたら遭遇することがあるらしいのでもしt2.microを使っていてMySQLを起動できなくなったよーってことならエラーログを確認してみてください。


これを見つけるのに時間がかかりましたがそれさえわかれば、それ以降のMySQLを起動させるのもすんなりできました。

あんまり調べてもこのパターンの解決策がすんなり見つかることがなかったので書きましたが、結果はログを見ればわかるということです。




こんな感じで少しずつアップデートしながら書いていこうと思っているのでよろしくお願いします。
Ruby 　２重ハッシュを取得する

# はじめに
今回の内容
・２重ハッシュの取得方法
・digメソッド

2重ハッシュを簡単に取得する方法と、それぞれの特徴について書きました。

## 結論
結論：　多重層階となる値はdigメソッドの方が扱いやすい。
　　　 以下で説明させていただきます。

# 取得方法
```ruby
hash = {user: {profile:{name: 'user_name'}}}

# ハッシュの出力結果↓
{:user=>{:profile=>{:name=>"user_name"}}}
```

今回は上記のハッシュを取得します。

```ruby
puts hash[:user][:profile][:name]      #①
puts hash.dig(:user, :profile, :name)  #②
# user_name
```
取得するためにはハッシュの変数名とキーを特定のキーまで連続して記述することで取得することが可能になります。
①様にすることで取得が可能になりました。
もう一つ取得する方法があります。それはrubyが標準で用意しているdigメソッドです。
②メソッドは多重階層にあるハッシュの値をまとめて取得することができるメソッドです。

```ruby
app_data = [
    {web: {app: {name: 'facebook'}}},
    {web: {app: {name: 'twitter'}}},
    {web: {app: {name: 'instagram'}}},
   ]

puts app_data.dig(0, :web, :app, :name)
# facebook

app_data.each do |p|
    puts p[:web][:app][:name]
end
# facebook
# twitter
# instagram
```

digメソッドは配列の中にあるハッシュも取得することができます。digメソッドは複数のハッシュの値をより特定して取得をすることが可能になります。特定の値を複数連続して取得する場合はeach文を用いて取得することができます。

# まとめ
2重ハッシュを取得する時は
・キーを連続して指定する。
・digメソッドを使用する

配列の中にあるハッシュを取得する時は、
・each文を用いて取得することができる。
・指定した値が複数あれば複数取得するとになる。

digメソッドを使用すると、
・特定した中の特定の値を取得する。
・複数取得するにはeach文を用いることで取得ができる。
OpenCVForUnityのArucoの備忘録

#バージョン
**OpenCV for Unity**：2.3.2
**Unity**：2018.3.14f1


#ArUcoDictionary
マーカーのタイプを指定するもの．

```
public ArUcoDictionary dictionaryId = ArUcoDictionary.DICT_6X6_250;
```
上記の
【6X6】の部分でビット数を指定し，
【250】の部分で使用するマーカーの個数を指定している．

このコードの場合は，「6X6ビットのマーカーを250個まで使用する」という意味になる．

ビット数が小さく，使用するマーカーの数が少ないほど，エラーに対して堅牢になる．

#MarkerType
- Canonical Marker
    - 基本的なマーカー．
    - 複数個使用でき，それぞれのマーカーを別々に識別する．
    - 参考：https://docs.opencv.org/master/d5/dae/tutorial_aruco_detection.html
    
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654759/e2cb6c47-a18e-85db-91ea-04f11a0ba54f.png)


- Grid Board
    - Canonical Makerが一定の感覚で配置されているもの．
    - マーカー間の相対位置が既知なため，全てのマーカーからボード全体の向き（姿勢）を推定できる．
    - ボードの一部しか見えていない場合やオクルージョンが発生した場合でもCanonical Makerよりも高精度に姿勢推定ができる．
    - (おそらく一つしか使えない．)
    - 参考：https://docs.opencv.org/3.4/db/da9/tutorial_aruco_board_detection.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654759/f4c1dd42-faca-e9b0-e9d6-4f14dc3d1862.png)

- ChAruco Board
    - チェス盤（**Ch**essboard）と**ArUco**を組み合わせたもの（**ChAruco Board**）．
    - Grid Boardよりも高精度なので，カメラキャリブレーション等に使用できる．
    - 一つしか使えない．
    - 参考：https://docs.opencv.org/3.4/df/d4a/tutorial_charuco_detection.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654759/dcfac91a-3393-8b4b-766b-9fb775776d69.png)

- Ch Aruco Diamond Maker
    - ChAruco Boardと違って，複数個使うことができる．
    - Canonical Markerより高精度．
    - 参考：https://docs.opencv.org/master/d5/d07/tutorial_charuco_diamond_detection.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654759/6bef0ab1-e5c1-167a-99d8-233d0fe89da3.png)

#WebCamTextureToMatHelper
- Webカメラ周りのことを色々とやってくれる便利なやつ．
- 映像をテクスチャからMatに変換してくれたり，カメラのFpsやWidth，Height等も教えてくれる．

参考：https://enoxsoftware.github.io/OpenCVForUnity/3.0.0/doc/html/class_open_c_v_for_unity_1_1_unity_utils_1_1_helper_1_1_web_cam_texture_to_mat_helper.html#a663ccd2cd229db13c5466e1c3edfd3e5

#FpsMonitor
謎

#ArUco Create Marker Example
上記の『Ch Aruco Diamond Maker』を除いた3種類のマーカを生成できる．
ここで生成した**マーカーがうまく認識されない場合は，画像を反転させると認識してくれる**．自分がそうであった．

#ARマーカーのID抽出
```
if(ids.get(0, 0) != null)
{
    Debug.Log("ID number：" + ids.get(0, 0).GetValue(0));
}
```
- ids.get( **x**, 0 ) の **x** 部分が**x個目**に認識されたマーカー．
- そのマーカーをGetValue(0)することでマーカーIDを手に入れられる．
- 参考：https://qiita.com/hsgucci/items/37becbb8bfe04330ce14
RaspberryPi4 にLeap MotionをUSBで付けたかった駄目メモ

結論的には、CPUがARMなのでドライバーのインストールでエラーでました

AMD:64てきなエラーワード出たけど、ここに至るまで時間を要した。。無知

- RaspiにUbuntuインストール
- Linuxのドライバーをダウンロードしてインストール
- エラー出る
- CPUが合わないらしいに至る


##参考サイト

V2 Tracking &mdash; Leap Motion Develope
https://developer.leapmotion.com/legacy-v2/

Ubuntu 16.04にLeapMotionを導入
https://qiita.com/KnnnNAko/items/fc47224a83e9109296d0

Raspberry Pi 4でUbuntuデスクトップを動かして遊ぶ
https://qiita.com/y-tsutsu/items/b50d44bd70c25279d130#vnc%E3%81%AE%E8%A8%AD%E5%AE%9A

[Note] Leap Motion on Ubuntu 20.04
https://blog.keithkim.com/2020/07/note-leap-motion-on-ubuntu-2004.html
Xcodeと英語を同時マスターする方法を見つけてしまった！

最近、iOS開発の勉強を始めてXcodeを触るようになったんですが表示の全てが英語！英語！英語！で、ナチュラルジャパニーズの私には何がなんだか・・・（　＾ω＾）

という状態だったため、これは効率が悪い！となり、どうすればいいか考えたところ

「単語帳にしちゃえばよくね？」

っておもったのでつくってやりました。これでXcode開発効率は爆上がり・・のはず。
↓こちらがその単語帳になります。

[XCodeメニューに関わる英語](https://ankilot.com/view/?id=CpBMmBcOAl)

共有設定を「公開」にしてますので私と同じような境遇の方はぜひ使ってみて下さい！

## 使い方

URLにアクセスすると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/871774/5ff13128-38f1-eef5-07de-c05b8bdae189.png)

このようなメニューが出てきますので、好きな方法を選んでください。
出力することもできます。CSVやTxtファイル、JSONで取得なんかもあるみたいです。自分の環境で使いたいという方はこちらからお使いください。

## なぜこれを作ろうと思ったのか

Xcodeを触っている中で設定項目をいじりたくても英語で表示されていて、やりたいことを探すにもまず英語の翻訳から！という死ぬほど効率の悪いことをしていました。

だったら、全て覚えてしまえ！あ、そういえば英語の勉強もしたかったよな！一石二鳥だ！

となり、単語帳アプリ「Ankilot」を使ってメニュータブ（っていうの？）にのってる英語を全て単語帳にしてやりました。

## 対象者

・最近、Xcodeを使い始めた方

・iPhoneアプリ開発に関わる英語？を勉強したい方

・普通に英語を勉強したい方

## どんな単語が勉強できるのか

普通に、メニューに載ってるものはだいたい網羅していると思います。
以下、一例です！ご参考にどうぞ！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/871774/fd4f0a40-13c2-acdb-0bae-a12dd7698ee7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/871774/12e79862-592c-c8d5-6aa7-4cb5bf101160.png)



## さいごに

実際に効果があるかはわかりません。笑

私個人としては、この単語帳を作成すること自体がアウトプットで
すでに結構頭に入りました。
もうちょっと復習でつかっていこうかなという感じです。

効果がありそうだったら、別の単語帳も作ってみようかな。
ヒントを書くこともできるので意味と、使い方まで記載した単語帳にすればもっと勉強になるかも・・・と思っていますが時間があるときに追加したいと思います。

もし、使ってみた方がいらっしゃいましたら感想を教えて頂ければと思います！

それでは！！

### 補足

直訳で翻訳してるので、よくわからないのがまじってるかもしれません・・
見つけたらご報告いただけると嬉しいです！
LeapMotion2台以上使いたいときはWebSocket取得の環境構築で

Leap Motionを2台以上使ってみたい機会があったので、IP指定してWebSocketでデータ取得する方式の環境構築のメモ
Leap Motionのドライバーはインストール済みの想定です

![SnapCrab_NoName_2021-2-17_15-59-2_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48015/4328e5ac-387d-1621-f87e-59df10993bb9.png)

##LEAP Motion の WebSocketサーバー

ビジュアライザー診断などのLeap Motionドライバーには、起動時にWebSocketサーバーが起動しているようです

```
ws://localhost:6437/
```


##config.jsonに追記

下記の情報をconfig.jsonに追記

Leap Motionのドライバーは停止したほうが良かったです

```
"images_mode": 2,
"websockets_allow_remote": true,
"websockets_enabled": true
```

2箇所ほどありますが、編集できる方のみでもOKかもです

```
C:/ProgramData/Leap Motion/config.json
```

```
C:/Users/Username/AppData/Roaming/Leap Motion/config.json
```

``` config.json
{
  "configuration": {
    "image_processing_auto_flip": true,
    "image_processing_flipped": false,
    "images_mode": 2,
    "websockets_allow_remote": true,
    "websockets_enabled": true
  }
}
```

## Windowsファイヤーウォール「ファイヤーウォールによるアプリケーションの許可」への追加

コントロール パネル\すべてのコントロール パネル項目\Windows Defender ファイアウォール\許可されたアプリ

「別のアプリの許可」から３つLeap Motionのexeを追加しました

```
C:\Program Files\Leap Motion\Core Services
LeapControlPanel.exe
LeapSvc.exe
Recalibrate.exe
```

![SnapCrab_NoName_2021-2-17_15-52-29_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48015/9ae59abe-456c-8f6b-5538-082f0dab5491.png)

##PC再起動

再起動しないと反映されなかったようなので。。

別PCは再起しなくてもできたので、規則がわかりません。。


##取得できたデータ

```
{"currentFrameRate":85.811661,"devices":[],"hands":[{"direction":[-0.174163,-0.504862,-0.845448],"id":200,"palmNormal":[0.524506,-0.774201,0.354268],"palmPosition":[15.470428,276.754761,-43.167252],"palmVelocity":[8.048999,-102.844597,1.154462],"timeVisible":1.555471}],"id":563536,"pointables":[{"direction":[-0.319512,-0.901732,-0.291190],"handId":200,"id":2000,"length":50.776791,"timeVisible":1.555471,"tipPosition":[-22.385941,202.880341,-14.876396],"width":21.074820},{"direction":[0.050678,-0.890562,-0.452031],"handId":200,"id":2001,"length":56.992455,"timeVisible":1.555471,"tipPosition":[-15.500284,197.979477,-96.916260],"width":20.130669},{"direction":[0.074383,-0.855941,-0.511696],"handId":200,"id":2002,"length":64.708893,"timeVisible":1.555471,"tipPosition":[6.423775,203.599457,-118.352493],"width":19.770990},{"direction":[0.203443,-0.811137,-0.548332],"handId":200,"id":2003,"length":62.036518,"timeVisible":1.555471,"tipPosition":[37.534515,220.833786,-121.149231],"width":18.813351},{"direction":[0.385315,-0.769903,-0.508706],"handId":200,"id":2004,"length":48.716534,"timeVisible":1.555471,"tipPosition":[68.231056,244.532608,-106.366425],"width":16.711489}],"timestamp":17154280370}
```


###参考サイト

Raspberry Pi 3BでLeap Motionを使う
https://www.pentacreation.com/blog/2016/10/161008.html

leapmotion/leapjs
https://github.com/leapmotion/leapjs

LEAP Motion と WebSocket
https://gist.github.com/uupaa/6102441
Expo アプリで Gravatar アイコンを表示する

# Expo アプリで Gravatar アイコンを表示する

Expo / React Native で構築されたアプリに [Gravatar](https://ja.gravatar.com/) のアイコンを表示する方法です。

ユーザーのメールアドレスに基づいたアイコンを登録できる Gravatar を利用すれば、ユーザー毎のアイコンを表示することができ、アプリ内でのユーザーの区別がしやすくなります。

## コード

```js
import * as Crypto from "expo-crypto";
// 
const mailAddress = 'test@example.com'
const hash = await Crypto.digestStringAsync(
    Crypto.CryptoDigestAlgorithm.MD5,
    mailAddress.trim().toLowerCase()
);
//
```

```react
<Image source={{ uri: `https://www.gravatar.com/avatar/${hash}?d=retro` }} />
```

MD5 ハッシュの作成には expo-crypto モジュールを利用します。

画像の表示には Image コンポーネントを利用し、ユーザーが Gravatar に登録していない場合のプレースホルダー画像は `d` [オプションで指定します](https://ja.gravatar.com/site/implement/images/#default-image)。
PowerApps ポータル tips1（ヘッダ表示）

#はじめに
ポータル作成時の細かなご要望にお応えしてきた記録として
(自分がどうやって対応してきたか忘れちゃうので備忘録として)
はじめてポータル触る方は、このあたりから知りたいのではないかと思いまして。

#要望: デフォルトで表示されているヘッダ部分を非表示としたい。

![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418815/9319b09b-75fd-1832-4a2c-fa5e027cfa2c.png)
対象は、以下
1. ホーム
2. 新しいページ(1)
3. 検索マーク
4. サインイン

#１．ホーム　と　２．新しいページ(1)　の消し方


ポータル管理を起動する。
DefulatのWebリンクセットで、対象WEBページの公開方法を「公開済み」から「下書き」に変更する。

![2-0.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418815/9283bd83-ddbc-5a42-b0e7-f8765ba401ec.png)

![2-1-1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418815/055a8d85-9c48-2dad-2b0c-4b80c5c2c0c0.png)
![2-1-2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418815/51b5b4f7-a0fa-5654-f840-a28795f5ee2d.png)
![2-2-1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418815/0c9680c2-ac2e-1988-2313-4d008ce28253.png)
![2-2-2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418815/ba20db3d-a066-c751-8dc5-0655b91b4fd6.png)

保存して、ポータル側で同期させるといかとなり、ヘッダにWEBページのリンクが表示されなくなります。

![2-result.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418815/5c710c63-591e-bbf9-9a20-4662114237c6.png)

#3.検索マーク　の消し方


![3-0.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418815/d4a4cf55-7254-697b-6225-81dc439185ac.png)

ポータル管理を起動する。
Search/Enabledを、TrueからFalseへ変更する。

![3-1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418815/24ae260c-75d5-9b76-53e4-4179f7611217.png)

![3-2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418815/61871a8f-2260-be06-00e2-16ec901c7641.png)

保存して、ポータル側で同期させるといかとなり、ヘッダに検索マークが表示されなくなります。

![3-result.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418815/615741f0-1d23-9261-e6a3-40eb6d817442.png)

※こちらの方法ですが、次の方法のHeaderのなかに、このSearch/EnabledがTrueかどうかで表示非表示を制御している個所があるため、非表示となります。次の対応のようにHeaderを直接編集する方法でも対応可能です。

#4.サインイン　の消し方

![4-0.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418815/cc84076d-c1e6-afd0-cef6-c155aa6c4500.png)

ポータル管理から、Webテンプレート → Header で、Header内容を編集。。
![4-0-1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418815/63b4a03c-88ac-9c6a-26b2-f1eac2a0235a.png)

Sing_inで検索すると出てくる子の黄色の個所をコメントアウトします。
![4-1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418815/75341516-532a-9319-313e-e928d8bf541a.png)

![4-2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418815/3bd7210c-a08f-dcb4-3216-89db24e2f4b9.png)

保存して、ポータル側で同期させるといかとなり、ヘッダにサインインが表示されなくなります。
![4-result.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418815/435f81b2-1f64-fff5-7b1f-e6d8e6f9d71b.png)

#おわりに
最後まで、お読みくださってありがとうございます。
対応方法が違っていたり、誤植や、不適切な記述等ありましたら、ご指摘いただけますとありがたいです。
[iOS14]IDFA取得許可ダイアログを表示する

##はじめに

iOS 14.5以降では、これまでの方法ではIDFA（広告ID）を取得できなくなります。
IDFAを取得できないと、AdMobなどで下記のようなことが起こります。

他社アプリと共通で参照できる端末固有のIDを使用できなくなる
　↓
端末内の他社アプリの広告閲覧・クリック状況との紐付けができない
　↓
表示する広告をユーザの興味に合わせてカスタマイズすることの精度が下がる
　↓
ユーザの広告クリック率が下がって、アプリ提供者の収益が下がる


簡単に言うと
「IDFA取得できないと、AdMob広告とかのeCPMが下がって収益が下がるよ(たぶん)」
ということです。

iOS 14.5以降では、個別のアプリごとにIDFA許可を求めるダイアログを表示する必要があります。
このページではその方法を説明します。


##動作確認環境

Xcode: 12.4
iOS: 14.4


##準備

Info.plistに NSUserTrackingUsageDescription キーを追加します。
これをしておかないと、後述のダイアログ表示の時にアプリがクラッシュします。

```Info.plist
	<key>NSUserTrackingUsageDescription</key>
	<string>「許可」を押すと、よりお客様に適した広告が表示されます。</string>
```


##トラッキング要求ダイアログ表示

IDFA取得許可を得るダイアログを表示したいタイミングで下記を実行すれば良いです。
ただし、許可要求できるのは基本的に１回だけなので、タイミングはよく考えた方が良いです。

```swift:IDFA取得させて欲しいとお願いする.swift
import AppTrackingTransparency
(中略)
    ATTrackingManager.requestTrackingAuthorization { (status) in
        switch status {
        case .authorized:
            print("許可いただきありがとうございます！")
        case .denied:
            print("許可してもらえなかった。残念！")
        case .restricted:
            print("他の理由で制限されてるっぽい。18歳以下かな？")
        default:
            print("その他のステータス")
        }
    }
```


##要求時以外に現在の許可状況を確認することも可能

ATTrackingManager.trackingAuthorizationStatus で現在のIDFA取得許可状況を確認することができるます。
下記は、許可状況がdeniedだったら、設定画面でIDFA取得許可設定を変更をお願いするサンプルです。
（たぶんユーザに嫌がられるので実際にやるのはオススメはしませんが。）

```swift:しつこくIDFA取得を求める.swift
if ATTrackingManager.trackingAuthorizationStatus == .denied {
    let alertController = UIAlertController(title: "考え直して欲しいなぁ", message: "IDFA取得を設定画面から許可してくれませんか？", preferredStyle: .alert)
    alertController.addAction(UIAlertAction(title: "いいよ", style: .default, handler: { (action) in
        let url = URL(string: UIApplication.openSettingsURLString)!
        UIApplication.shared.open(url, options: [:], completionHandler: nil)
    }))
    alertController.addAction(UIAlertAction(title: "やだ", style: .cancel, handler: nil))
    present(alertController, animated: true, completion: nil)
                        
} 
```


##その他、所感

「自社アプリでIDFA取得できるようになったら、これまで通りの広告カスタマイズがされる」というわけではないと思っています。

これまでは端末内の全アプリ横断で広告クリック状況をもとに最適化できていたのに、
今後は他社アプリの多くでの広告クリック状況を最適化に使えなくなります。
そのため、自社アプリがIDFA取得できるか否かに関わらず、広告の最適化効果は下がると思っています。

IDFA取得できたとしても、その効果は実はそれほどないかもしれません。

私はアドテクの専門家でもなんでもない趣味プログラマーですので、
この考えについては間違ったことを言ってるかもしれません。
間違ってたらご指摘いただけると嬉しいです。
ColaboratoryでPython3.9を動かす

Google ColaboratoryでPython3.9を動かしたい。
## まとめ
以下を実行することでPython3.9をColaboratoryにインストール出来ます。

```bash
!sudo add-apt-repository -y ppa:deadsnakes/ppa
!sudo apt-get -y update
!sudo apt-get -y install python3.9
!sudo apt-get -y install python3.9-dev
!sudo apt-get -y install python3-pip
!sudo apt-get -y install python3.9-distutils
!python3.9 -m pip install --upgrade setuptools
!python3.9 -m pip install --upgrade pip
!python3.9 -m pip install --upgrade distlib
```

あとはrequirements.txtなどでパッケージをインストールします。わざわざ`python3.9 -m pip ...`としなくても`pip ...`で動作するようです。

```bash
!python3.9 -m pip install -r requirements.txt
```


`python3.9`コマンドでスクリプトを実行。

```bash
!python3.9 example.py
```

## 感想など
Colaboratoryを単にGPUの使える実行環境として活用しています。セル内にPythonコードを書いてJupyterのように実行することはしていません。
個人的にはセルにコードを書いて次々実行していくスタイルは使い捨てのゴミコードが生まれるだけなのでおすすめしません。しっかりコードを書いたほうがあとあと得が多いと思います。

最後までお読みいただきありがとうございました。
GoogleAppsScriptのトリガーを毎日10時ジャストに発動させる

# はじめに
こんにちは。いきものがかりのボーカルの吉岡聖恵さんのフォトエッセイの発売が発表されて、発狂しました、筆者です:yum:

**GoogleAppsScript**のトリガー便利ですよね。
サーバレスで定時(?)実行が可能です。

ただ、日次でのトリガーでは、1時間の間のどこかで実行される曖昧性を持っているため、毎日10:00ぴったりにslack botでつぶやきたいんだ！というのは、そのままではできないのが悲しいところです:thinking_face:

しかしながら、ぴったりに行いたい処理もあるのが現実です。

よし！ではぴったりに実行しよう！

# GoogleAppsScriptのトリガーを10:00ジャストに発動させる
以下の手順で行います。

## 1. 10:00に発動したい関数を作成.
```javascript
const main = () => {
  console.log('Hello World!')

  // 指定日時実行のトリガーは、終了後、無効なトリガーとして残り続けるので削除しておく.
  const triggers = ScriptApp.getProjectTriggers()
  for (let i in triggers) {
    if ('main' == triggers[i].getHandlerFunction()) {
      ScriptApp.deleteTrigger(triggers[i])
    }
  }
}
```

## 2. 10:00にトリガーをセットする関数を作成.

```javascript
const setTrigger = () => {
  const date = new Date()
  ScriptApp.newTrigger('main')
    .timeBased()
    .at(new Date(date.getFullYear(), date.getMonth(), date.getDate(), 10, 0, 0))
    .create()
}
```

## 3. 1の関数を毎日9時台にトリガーセットする

# おわりに
内部的には、毎日10時に発動するトリガーをセットしているのですが、こうすることで、10時ジャストに毎日スクリプトを走らせることができます:+1:

また、発動したトリガーは残り続けるので、削除しておくことをおすすめします。
トリガーを設定できる上限値に達したときにエラー吐きますので... :sob:

それでは！
Gravio 4の日付フォーマットはGo言語の形式を使う

Gravio 4のマッピングで、日付をフォーマットしたい時は `DateFormat` という関数を使う。

# デフォルトのフォーマット

例えば、LINEにセンサーからデータ取得したい日付を送る場合、そのままだとデフォルトのフォーマットで送信される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/728a751c-62cd-4473-ba41-8bfe77c2b882.png)

```:cp.Message
tv.Timestamp
```

結果はこう。Web APIなんかにJSONで投げるときはだいたいこのままでもいいですが、LINEやSlackに投げるときには味気ない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/08a3beab-a7ec-cfc1-e568-34a21906a067.png)

# 任意のフォーマットに変換する

そういうときに `DateFormat`を使います。

```:cp.Message
DateFormat(tv.Timestamp, "2006年1月2日 15時04分05秒にデータを受信しました")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/ca80f9f7-5192-1199-4fb7-c0a41e76bb70.png)

`DateFormat`の詳細は、[ヘルプ][Gravio-Date]の中に書かれてますが、次のように引数を渡します。

```
DateFormat(t, layout)
```

|引数|内容|
|:---|:---|
|t|日付型のデータ|
|layout|Go言語形式のレイアウト|

## Go言語形式の日時フォーマット
これがちょっと曲者。他の言語のように、`Y`だの`HH`だので指定しない。サンプル日付みたいなものを使って表現します。
かなり雑な覚え方で、正確性に欠くかもしれないですが、次のように覚えておくといいと思います。

|単位|値|例|
|:---|:---|:---|
|年|2006年|2006,06|
|月|1月|1, 01, Jan, January|
|日|2日|2, 02, _2|
|時|午後3時|3, 03, 15|
|午前/午後|PM|pm, PM|
|分|4分|4, 04|
|秒|5秒|5, 05|
|秒以下(最後の桁の0は省略)|.9|.999, .999999|
|秒以下(桁数分0で補完)|.0|.000, .0000000|
|タイムゾーン|MST,UTC-7時間|MST, -0700, Z07:00|
|曜日|月曜日|Mon, Monday|


詳しくは[Go言語のtimeパッケージのヘルプ][Go-Time]、[formatのソースコード][Go-Format]を見てください。

## スニペット
### 一般的な時刻表記
```:一般的な時刻
DateFormat(tv.Timestamp, "2006/1/2 15:04:05.000")
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/8d25df7c-e21c-4252-2ffa-777955fa540f.png)

### 日本語の時刻
日本語の時刻単位を付ける場合はそのままフォーマットの中に書けばいいです。

```:日本語の時刻
DateFormat(tv.Timestamp, "2006年1月2日 15時04分05秒.000 (タイムゾーン MST)")
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/80ae3836-6346-dc02-072c-f76104d64e48.png)

午前・午後表記にするには、`15`のところを`PM03`とします。

```:日本語の時刻(AM/PM)
DateFormat(tv.Timestamp, "2006年1月2日 PM03時04分05秒.000 (タイムゾーン MST)")
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/990ba752-c15c-730e-5f1a-2262fdb40a75.png)


### ISO8601形式
あまり最近は使われてないかもしれないですが、ISO8601形式も。
月や日などを二桁にするには `01`のように `0`を付加します。


```:IS8601
DateFormat(tv.Timestamp, "20060102T150405-0700")
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/00a5343c-a350-408a-6162-af58fb61a23c.png)



# 参考
* [Go言語のtimeパッケージのヘルプ][Go-Time]
* [Go言語のformatのソースコード][Go-Format]
* [Gravio][]
* [日付関数][Gravio-Date]
* [アクション内で利用できる変数と変数型][Gravio-Variables]
* [Pre Mappings / Post Mappingsでの式の記述の仕方][Gravio-Mappings]

[Go-Time]:https://golang.org/pkg/time/
[Go-Format]:https://golang.org/src/time/format.go
[Gravio]:https://www.gravio.com/jp
[Gravio-Date]:https://doc.gravio.com/manuals/gravio4/1/ja/topic/date-functions
[Gravio-Variables]:https://doc.gravio.com/manuals/gravio4/1/ja/topic/available-variables-in-action
[Gravio-Mappings]:https://doc.gravio.com/manuals/gravio4/1/ja/topic/premappings-postmappings
ネットワーク構築〜ルーティングプルトコルについて〜

本日はCCNAの試験勉強してる際にでてきたルーティングプロトコルについてまとめていきます！

参考URL
https://www.infraexpert.com/study/eigrpz1.html
https://www.infraexpert.com/study/distancevector.html

#今回説明するルーティングプロトコル

###RIP EIGRP

以上２つをまとめていきます。
代表的なものでOSPFが参考書などでも取り上げられていましたが、
それ以外のプロトコルの概念も範囲であるということと、
それぞれ仕組みを理解していく必要がありそうなのでこの３点に絞ります！


#RIP

###ディスディスタンスベクタ型
ディスタンス（距離）とベクタ（方向）でメトリックを求め、経路を決定する。
経由するルーターの数（ホップ数）で表す。

バージョンが２つあり、RIPv1・RIPv2で表されます。
違いとしては、クラスフルに対応しているのかそうでないのか。

RIPv1・・・クラスフル対応
RIPv2・・・クラスレス対応

要するにVLSM(可変長サブネットマスク)のネットワーク設定に対応できるのかということ。
また、隣接するルータ同士でバージョンを揃える必要があり、
違うバージョン同士の際はインターフェイスごとの設定が必要。

     (config) router rip #RIP起動
     (config-router) network IPアドレス #ネットワーク範囲指定
     (config-router) version 1|2 #バージョン指定

#EIGRP

###拡張ディスタンスベクタ型（ハイブリット型）

![スクリーンショット 2021-02-17 15.27.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626890/4492a1a0-7048-d2c9-7f7c-3da796def12f.png)

問題でよく問われる印象があるのは、①③④⑤でしょうか。

DUALはアルゴリズムとなります。
こちらを用いて計算したメトリック値で一番小さいルートを算出します。（サクセサ）
また予備のルートも同時に用意します（フィージブルサクサ）
オブジェクトをStringに変換しkeyの「”」を外す

```javascript:sample.js

const obj = {
  obj1: "1111",
  obj2: "1111",
  obj3: "1111",
  obj4: {
    obj1: "1111",
    obj2: "1111",
  },
};

objToStr(obj);

function objToStr(sampleObj){
    const s_Json = JSON.stringify(sampleObj, null, 2);
    const line = s_Json.split('\n');

    line.forEach(function (val) {
        let keyAndValue = val.split(':');
        let left = keyAndValue[0].replace(/"/m, '');
        left = left.replace(/"/m, '');
        const right = keyAndValue[1] ? ':' + keyAndValue[1] : '';
        console.log(left + right + '\n');
    });
}
```

```
実行結果

{
  obj1: \"1111\",
  obj2: \"1111\",
  obj3: \"1111\",
  obj4: {
    obj1: \"1111\",
    obj2: \"1111\"
  }
}