OmniAICreator/Qiita-1.07M huggingface dataset:
macOS に Node.js (npm) をインストールする方法

macOS のPCに[Node.js](https://nodejs.org/ja/about/)とパッケージ管理システム npm (Node Package Manager) をインストールして確認するまでの手順を備忘録としててまとめました。参考にして頂ければ幸いです。


- 前提条件（環境）
- インストーラーのダウンロード
- Node.jsのインストール
- インストール完了の確認

# 前提条件（環境）

今回インストール下のハードウェアのmacOSの仕様は次の通りです。

- macOS Monterey バージョン  12.3.1

# インストーラーのダウンロード

Node.jsの[公式日本語サイト](https://nodejs.org/ja/)にアクセスすると、OSに対応したインストーラが表示されるので、そのままダウンロードします。<br>
![image.png](https://raw.githubusercontent.com/gahoh/articles-qiita/main/install-nodejs-macos/images/download1.png) <br>
ここでは、LTS（安定版）の 16.15.0　をダウンロードしています。<br>

# Node.jsのインストール

インストーラーをダウンロードしたら、早速ファイルを実行してをインストールしていきましょう。
なお、インストールの手順は他のmacosアプリと同じようにインストーラーが自動的に行ってくれるため、とても簡単です。また、基本的には特別なオプションを指定することなくインストールを行えばOKです <br>
なお、Node.jsをインストールすると、一緒にパッケージ管理ツールのnpmが利用できるようになります。

## はじめに

ダウンロードしたインストーラー node-v16.15.0.pkg をクリックし、インストール実行します。   
インストール画面が起動したら、[続ける] をクリックする。   
![image.png](https://raw.githubusercontent.com/gahoh/articles-qiita/main/install-nodejs-macos/images/Install1.png)

## 使用許諾契約

使用許諾契約を確認・チェックしたあとに[続ける] をクリックする。<br>
![image.png](https://raw.githubusercontent.com/gahoh/articles-qiita/main/install-nodejs-macos/images/Install2.png)<br>
次のような画面が表示されたら、[同意する] をクリックする。<br>
![image.png](https://raw.githubusercontent.com/gahoh/articles-qiita/main/install-nodejs-macos/images/Install3.png)<br>

## インストール先

### インストール先の選択
[続ける] をクリックする。<br>
![image.png](https://raw.githubusercontent.com/gahoh/articles-qiita/main/install-nodejs-macos/images/Install4.png)<br>

## インストール先の種類
インストール先を指定します。ここでは、特に変更しなくて進めていきます。<br>
[インストール] をクリックする。<br>
![image.png](https://raw.githubusercontent.com/gahoh/articles-qiita/main/install-nodejs-macos/images/Install5.png)<br>
パスワードを入力し、[ソフトウェアをインストール] をクリックする。<br>
![image.png](https://raw.githubusercontent.com/gahoh/articles-qiita/main/install-nodejs-macos/images/Install6.png)<br>
インストール中になります。しばらくお待ちください。

## インストール

## 概要

インストールが完了。<br>
![image.png](https://raw.githubusercontent.com/gahoh/articles-qiita/main/install-nodejs-macos/images/Install7.png)<br>

[閉じる]をクリックする。<br>
![image.png](https://raw.githubusercontent.com/gahoh/articles-qiita/main/install-nodejs-macos/images/Install8.png)<br>

以上でインストール完了となります。

# インストール完了の確認

引き続き、ちゃんとインストールされたかの確認も行っていきます。<br>

Node.jsとnpmのインストールを確認するには、ターミナルで次のコマンドを実行します。

```
node -v; npm -v
```
または、
```
node --version; npm --version
```

コマンドの実行結果にNode.jsおよびnpmのバージョンが表示できればOKです。
実行例は次の通りです。

```
$ node -v;npm -v
v16.15.0
8.5.5

```

これで、macOS への Node.js（npm）のインストールは完了です。

---
composer update したら Laravel-admin のログイン画面でリダイレクトのループをしてしまった件

Laravel 5.x の環境で、composer update 後に Laravel-admin のログイン画面でリダイレクトループで死んでしまったので解決策をメモっておく。

対策 : config/admin.php に admin.auth.excepts の設定を追加

```config/admin.php
    'auth' => [

        'controller' => App\Admin\Controllers\AuthController::class,

        'guards' => [
            'admin' => [
                'driver'   => 'session',
                'provider' => 'admin',
            ],
        ],

        'providers' => [
            'admin' => [
                'driver' => 'eloquent',
                'model'  => Encore\Admin\Auth\Database\Administrator::class,
            ],
        ],
        
        'excepts'   => [
            'auth/login'
        ]
    ],
```

いろいろ追いかけたけど最終的にこれだけでなおった。
tmuxでpaneを入れ替える ― swap-pane


# tmuxでpaneを入れ替える

ペインを入れ替える方法についてのメモを残しておきます。
コマンドは`swap-pane`という名前で、ペインの並びを整理したいときに使います。

## 具体例

ペインの並びが下記のようであるとします。

`| a | b | c |`

この時、ペインを次のように並び替えたいとします。

`| b | a | c |`

これは下記のコマンドで実現できます。

`$ tmux swap-pane -s 1 -t 2`

-sでsrc-paneの番号を指定、-dでdest-paneの番号を指定しています。
指定するための番号を確認するには、`prefix_q`でペイン上に表示された番号を見ます。
ちなみに、-sと-tで指定している番号を入れ替えても結果は変わりません。

蛇足ですが、このコマンドでペインを並び替えても、番号の並びは変わりません。
例えば、今回の例においては、常に、左から 1, 2, 3 と並んでいます。
つまり、下記のようになります。ただし、ペインと、その番号を次のように表記しています: `ペインを表す記号:ペインの番号`。e.g. `a:1`.

```
| a:1 | b:2 | c:3 |

↓ `tmux swap-pane -s 1 -t 2`

| b:1 | a:2 | c:3 |
```

なので、このコマンドを二回繰り返せばペインの並びは元に戻ります(何もしていないように見えます)。


```
| a:1 | b:2 | c:3 |

↓ `tmux swap-pane -s 1 -t 2`

| b:1 | a:2 | c:3 |

↓ `tmux swap-pane -s 1 -t 2`

| a:1 | b:2 | c:3 |
```

## 参考文献

`man tmux`

## あとがき

tmux関連の投稿が増えたら一つの記事にまとめて自分用チートシートにする予定です。
[Permission] プログラミング初心者向け 権限について

# はじめに
```
chmod 777 ~/hoge/config
```
プログラミング初心者の方は、参考にしたサイトで上記のようなターミナルのコマンドを見たことがあると思います。
私自身、初めの頃は意味もわからずがむしゃらにコマンドを叩きまくっていました(真似しないように)。
permissionの設定はセキュリティに関わるため初心者の方こそ知っていてほしいと思い、記事にまとめました。
まだまだ私も勉強中なので、至らない部分があるかもしれませんが
プログラミング初心者の方々へのお力添えになれると幸いです。

# permission(パーミッション)とは
permissionとは、```ファイルやディレクトリに対するアクセス権限```のことです。
それぞれ```「所有者」「グループ」「その他のユーザ」```にパラメータを割り振りが可能となっています。
特殊なパラメータもありますが、パラメータは基本的に```「読み込み」「書き込み」「実行」```の３つです。
「はじめに」でも記載した通り、permissionはセキュリティのために重要です。
例えば、本番環境にあるWebサイトを誤って編集してしまったということが無いように、責任者以外は本番環境のWebサイトを編集できないようにすることなどができます。
permissionを適切に管理すると事故防止になります。

# 実際のpermission
permissionはアルファベット、もしくは数字で表されます。
数字は後ほど説明します。まずはアルファベットから見てみましょう。表にまとめるとこんな感じです。

【 ファイルへのアクセス権 】
|アクセス権|表記|説明|
| :- | :-: | :- |
| 読み取り(Read) | r | ファイルの読み込みが可能 ( 内容表示など ) |
| 書き込み(Write) | w | ファイルへの書き込みが可能 ( 編集や上書きコピーなど ) |
| 実行(eXecute) | x | ファイルの実行が可能 ( プログラムやシェルスクリプトの実行 ) |

【 ディレクトリへのアクセス権限 】
|アクセス権|表記|説明|
| :- | :-: | :- |
| 読み取り(Read) | r | ディレクトリの読み込みが可能 (ディレクトリに登録されているファイル名の表示) |
| 書き込み(Write) | w | ディレクトリの書き込みが可能 ( 新規ファイル作成、削除、名前変更など） |
| 実行(eXecute) | x | ディレクトリに登録されいているファイルへのアクセスが可能 |

```※　ファイルへのアクセス権限にreadの許可があっても、ディレクトリのexecute許可がなければファイルにアクセスできません。```

実際にこれらをターミナルで確認してみましょう。
ターミナルで適当な位置で以下コマンドを入力してください。
```
ls -al
```
次のようになると思います。
```
drwxr-xr-x  10 onyankopon  staff    320  9  8  2021 directory-name
drwxr-xr-x  11 onyankopon  staff    352  9  8  2021 directory-name
-rwxr--r--  17 onyankopon  staff    544  9  8  2021 file-name
-rwxrwxr-x   3 onyankopon  staff     96  9  8  2021 file-name
-rwxrwxrwx   6 onyankopon  staff    192  9 22  2021 file-name
```
これはカレントディレクトリ(現在位置)の中身の情報を表しています。
この左側に注目してください。
(一番左の　```d``` はディレクトリ　```-``` はファイル　その他表記あり)
左側の```r```から```x```までがそれぞれ```「所有者」「グループ」「その他のユーザ」のアクセス権限```になります。
|所有者|グループ|その他ユーザー|
| :-: | :-: | :-: |
| rwx | rwx | rwx |

例えば
```
rwxr-xr--
```
これが何を意味するかと言うと
```所有者```：```読み込み・書き込み・実行```　が許可されている
```グループ```：```読み込み・実行```　が許可されている
```その他```：```読み込み```　が許可されている
こうなります。

# permissionの変更
ここまでざっくりアクセス権限について理解できてきたかなと思います。
ここからは変更について説明していきます。
アクセス権限の変更を行いたい場合は以下コマンドを入力します。
```
chmod 777 ~/hoge/config
```
冒頭に出てきたこいつです。この```chmod```コマンドで変更します。
ではその横の数字は何かと言うと、先ほど説明を後回しにした```数字で表したpermission```です。
さらに言うと、permissionの```rwx```を２進数で表して８進数に変換した数字です。
混乱しそうですが実際は簡単なので表にまとめます。
|表記記号|２進数|８進数|
| :-: | :-: | :-: |
| --- | 000 | 0 |
| --x | 001 | 1 |
| -w- | 010 | 2 |
| -wx | 011 | 3 |
| r-- | 100 | 4 |
| r-x | 101 | 5 |
| rw- | 110 | 6 |
| rwx | 111 | 7 |

これだけです。

これをもとに先ほどのコマンドを見てみると
```
chmod 777 ~/hoge/config
```
この```７７７```は```rwxrwxrwx```を表していることがお分かりいただけるかと思います。
つまり```config```のアクセス権を```rwxrwxrwx```に変更するコマンドと言うことです。
```
chmod 640 ~/hoge/config
```
この場合は、
```config```のアクセス権限を```rw-r-----```に変更するコマンドです。
これでpermissionの扱い方が分かっていただけたかと思います。

# まとめ

意味もわからず```chmod 777```を入力すると誰でも触りたい放題のアクセス権限が完成し、そのまま気にもせず放置してしまう可能性も大いにあります。（```chmod 777```が悪いと言う意味ではありません。）
調べたコマンドを入力する前にそのコマンドの意味を理解しましょう。
また、今回はアクセス権限にフォーカスしたのでその周りの細かいところ(ユーザー等)には触れていません。
最後まで読んでくださった初心者の方々はこれを機に自分で```permission```について調べてみてください。


以上です。
Nodejs 環境周りメモ


# 背景
久しぶりにnodejsを触ってバージョン管理関係の知識がゴチャゴチャしていたので、整理する。


# 開発環境

PC:macOS Montery（Intel Core）
エディター：Visual Studio Code

Homebrew 3.4.11

# 内容
「OS上でのnodejsのバージョン管理」と「プロジェクト毎にnodejsのバージョンを管理」が混ざっていたので、今回は後者の「プロジェクト毎にnodejsのバージョンを管理」についてまとめる。

「OS上でのnodejsのバージョン管理」だと[nodebrew](https://github.com/hokaccha/nodebrew)や[fnm](https://github.com/Schniz/fnm)などがある。

「プロジェクト毎にnodejsのバージョンを管理」には、nodenvを採用する。（pyenvやrbenvを使用したことがあり、似たようなものを検索したら出てきたため）


まず、homebrewを使用して、nodenvをインストールする。ターミナルから下記コマンドを実行する。

```
brew install nodenv
```

下記コマンドを実行して、インストールされていることを確認。
```
nodenv -v
```

下記コマンドを実行すると、インストール可能なバージョンが確認できる。
```
nodenv install -l
```

以下のようにバージョンを指定して、インストールすることができる。
```
nodenv install 18.0.0
```

新しいバージョンのNodeをインストールしたら、このコマンドを実行する。
```
nodenv rehash
```

インストールしたnodeに切り替えるときは以下のようなコマンドで行う。
```
nodenv local 18.0.0
```

nodenvが反映されるように「.zshrc」に以下を追記する。(「.bash_profile」などもあるが、ここでは「.zshrc」を使用する)
```
export PATH="$HOME/.nodenv/bin:$PATH"
eval "$(nodenv init -)"
```

※上記を追記しないと、各プロジェクトでnodenvで指定したバージョンを認識してくれないので、注意

# その他
Flutterのバージョン管理でasdfを使用しているので、Nodejsもasdfを使用して管理するようになったら追記予定。

# 参考記事

https://qiita.com/heppokofrontend/items/5c4cc738c5239f4afe02

https://github.com/nodenv/nodenv
PandasのDataFrameでappendの代わりの方法

# PandasのDataFrameでappendの代替

## FutureWarning

pandasのDataFrameに対してappendを用いると以下のような警告がされる。
いつかなくなるメソッドだからappendではなくconcatを使ってね、とのこと。
```text
 FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version.
   Use pandas.concat instead.
```

## appendを使用する目的

カラム名だけで値は空のDataFrameを用意して、カラムを追加していきたい。

## 結論

コード
```python
# カラム名のみの空DataFrameを作成
cols = ['col_{}'.format(s) for s in range(9)]
df = pd.DataFrame(index=[], columns=cols)
# >> Empty DataFrame
# >> Columns: [col_0, col_1, col_2, col_3, col_4, col_5, col_6, col_7, col_8]
# >> Index: []

# カラムデータの作成
transaction = ['hoge'] * len(cols)
record = pd.Series(transaction, index=df.columns)

# appendの役割
df.loc[len(df)] = record
```

結果
```text
  col_0 col_1 col_2 col_3 col_4 col_5 col_6 col_7 col_8
0  hoge  hoge  hoge  hoge  hoge  hoge  hoge  hoge  hoge
```

concat使ってないじゃんと思いますよね。僕も思いました。
むしろこのやり方って、よくIndexOutにならないなって感心してます。詳しい人いらしたらご教授いただけると幸いです。

## 失敗談

concatをappendの代わりに使用して、目的の動作が達成できなかったためこのようなやり方となってしまった。
concatで試してダメだったバージョンを以下に。

コード (# appendの役割 の部分をこれに変えたもの)
```python
df = pd.concat([df, record])
```
結果
```text
      col_0 col_1 col_2 col_3 col_4 col_5 col_6 col_7 col_8     0
col_0   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN  hoge
col_1   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN  hoge
col_2   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN  hoge
col_3   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN  hoge
col_4   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN  hoge
col_5   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN  hoge
col_6   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN  hoge
col_7   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN  hoge
col_8   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN   NaN  hoge
```

多分、どこかのパラメータの指定がうまく行ってないのだとは思います。
【Trello】カードの期限が来たら推しのアイドルがDiscordで催促してくれるBOTをノーコードで簡単に作ってみる

さて、皆さんはタスク管理してますか？ 僕は仕事ではAtlassian社のJiraを使ってタスク管理をしてますが、個人（趣味）でのタスク管理は結構適当だったりします。

なかなか趣味や身の回りのことだと、きっちりタスク管理をする気が起きませんね？

趣味では以前からTrelloを使ってタスク管理をしてますが、期限を設定しても守れた試しがありません。

そこで、もしかして、推しのアイドルが「タスクをやってね！！」って催促してくれたらやる気が出るのでは！？！？と思った僕は、自動でTrelloのカードの期限が切れたら推しメン（概念）が催促してくれたら良いのではと思ってBOTを組んでみました。

## 用意する物
- Discord
    - 適当なアカウント(普段使っているフリープランのもので問題ないです)
    - Discordサーバ(なんでもいいです)
    - Disocrdサーバ上のwebhook(1つ推しのアイドルの名前を設定して作っておきましょう)
- Trello
    - 適当なアカウント(普段使っているフリープランのもので問題ないです)
    - 適当なカードが入っているボード

## TrelloのButlerを使って自動化する
TrelloにはButlerという機能があり、**Zapierなどを使わなくてもノーコードで自動化した動作を組むことが出来ます**。

しかも、**簡単なHTTPSリクエストを投げる程度であれば超簡単にできちゃったりする**ので、早速活用していきましょう。

まずは、事前に用意したDiscordサーバのwebhookのURLを用意しておきましょう。

あとは、推しのアイドルに話しかけて欲しい文言を考えておきましょう！(むしろ、これが一番重要まであります)

> ね～～～！！！もう！とれろの 「(ここにTrelloのカードの名前)」 のカードがぜんぜんおわってないよ！！！！はやくやってほしいな～(⊃´-`⊂)
> (ここにTrelloのカードのURL)

僕はこのような文言を考えておきました。

## 設定する
ボードメニューの自動化からButlerの画面を開いて、Due Dateの項目を選んでおきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41743/33e66ce1-8c7d-3c56-784f-5d277430b447.png)

トリガーに **the moment a card is due** を選んで、アクションには**HTTP requests**を選んでおきます(画像では一番下の項目)。

HTTP requestsの設定値には以下の値を入れておきましょう。

`post to` url `https://discordapp.com/api/webhooks/xxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxxxxx` `with payload`

Payloadの中身には以下のJSONを指定しておきます。
(デフォルトで`Content-Type`は`application/json`になっているので、その設定は不要です)

```json
{"content": "ね～～～！！！もう！とれろの **「{cardname}」** のカードがぜんぜんおわってないよ！！！！はやくやってほしいな～(⊃´-`⊂)\n{cardlink}"}
```

設定は以上です。あとは、カードの期限が来るのを待って動作を見てみるだけ！超簡単ですね。

## 通知を受け取った自分がタスクをやるのかどうかはさておき、動作を見てみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41743/3b0569d9-352e-df23-ea89-9f30d69d4aa1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41743/392af6e4-e81c-7ca8-bea5-bba504331241.png)

.......キタ！！！！！！

## あとがき
タスクを積んでもすぐ忘れてしまう自分でも、忘れた頃にしっかり通知が来ることでタスクを消化することを習慣化することが出来ました。

Appare!の[藤宮めい](https://twitter.com/appare_may)ちゃんには感謝しないといけないですね。
JavaScript クエリパラメータをエスケープ処理

## はじめに

クエリパラメータに、扱えないマルチバイト文字などが含まれる可能性がある場合は、
表記可能な文字列に変換するエスケープ処理が必要です。このような変換処理を「URIエンコード」と言います
方法は主に三つ。

# [encodeURI()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)
URIの予約文字以外の記号をエンコードするグローバル関数
decodeURI()で元の文字列に戻せます。

>エスケープされないもの:
>
>    A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) #


```JavaScript
var set1 = ";,/?:@&=+$#"; // 予約文字
var set2 = "-_.!~*'()";   // 予約されていない記号
var set3 = "ABC abc 123"; // 英数字 + 空白

console.log(encodeURI(set1)); // ;,/?:@&=+$#
console.log(encodeURI(set2)); // -_.!~*'()
console.log(encodeURI(set3)); // ABC%20abc%20123 (空白は %20 にエンコードされる)
```
# [encodeURIComponent()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent)
encodeURI()に加え、HTTPのGET,POSTリクエストでの特別な文字もエスケープするようにしたグローバル関数
decodeURIComponent()で元に戻せます。
>エスケープされないもの:
>
>    A-Z a-z 0-9 - _ . ! ~ * ' ( )
```JavaScript
var set1 = ";,/?:@&=+$#"; // 予約文字
var set2 = "-_.!~*'()";   // 予約されていない記号
var set3 = "ABC abc 123"; // 英数字 + 空白

console.log(encodeURIComponent(set1)); // %3B%2C%2F%3F%3A%40%26%3D%2B%24%23
console.log(encodeURIComponent(set2)); // -_.!~*'()
console.log(encodeURIComponent(set3)); // ABC%20abc%20123 (空白は %20 にエンコードされる)
```

# [escape()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/escape)
非推奨。Web標準から削除された。使用しているプラットフォームやブラウザーで得られる結果が異なる。特別な理由がない限り使わない。

## 参考
[JavaScript 本格入門 - 山田 祥寛](https://www.amazon.co.jp/%E6%94%B9%E8%A8%82%E6%96%B0%E7%89%88JavaScript%E6%9C%AC%E6%A0%BC%E5%85%A5%E9%96%80-%E3%83%A2%E3%83%80%E3%83%B3%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%81%AB%E3%82%88%E3%82%8B%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E7%8F%BE%E5%A0%B4%E3%81%A7%E3%81%AE%E5%BF%9C%E7%94%A8%E3%81%BE%E3%81%A7-%E5%B1%B1%E7%94%B0-%E7%A5%A5%E5%AF%9B/dp/477418411X)
[Kotlin][Android] object と Serializable

## 状況説明

Android アプリ開発をしていて、ちょっと困った状況になりました。
すぐに解決したんですが、こんなことがあるのね、と勉強になったのでこれを書いています。

その「ちょっと困ったこと」は Activity 間であるデータをやり取りしようとしていて起こりました。

### 渡すデータ

Activity 間でデータの受け渡しをするために、次のような sealed class を作成したとします。
(実際のコードとは異なります)

```kotlin
sealed class Answer : Serializable {
    object Yes : Answer()
    object No : Answer()
    data class Other(val text: String) : Answer()
}
```

### 呼び出し側

`Answer` クラスは `Serializable` を実装しているので、 Intent の putExtra() に渡せます。
今回は仮に `Yes` を渡すことにします。

```kotlin
val intent = Intent(context, MainActivity::class.java).apply {
    putExtra("answer", Answer.Yes)
}
startActivity(intent)
```

### 受け取り側

シンプルに受け取って、 when で分岐処理します。
when の分岐は Android Studio で生成するのが楽ですね。
「alt + Enter」→「:bulb: Add remaining branches」で全ての分岐を補完してくれます。

```kotlin
val answer = intent.getSerializableExtra("answer") as? Answer
val text = when (answer) {
    Answer.Yes -> "はい"
    Answer.No -> "いいえ"
    is Answer.Other -> "その他(${answer.text})"
    null -> "未選択"
}
```

上記のコードを実行したとき、どのような結果になるでしょうか？

### 実行結果

上記コードを実行すると、例外が発生します。
`kotlin.NoWhenBranchMatchedException` という例外です。
when は全て網羅されているはずなのに何故？と疑問に感じますが、状況が状況なので割とすぐ見当が付きますね。
シリアライズ・デシリアライズされたことで、 `Answer.Yes` とは別のインスタンスが生み出されてしまっています。
インスタンスが一致しないので、該当する分岐がなく例外が発生してしまったというわけです。

## 解決するには

### すぐ思いついた方法

最初に行ったのは、 when の分岐の `Yes` も `No` も `is` で比較するようにすることでした。

```diff
-    Answer.Yes -> "はい"
+    is Answer.Yes -> "はい"
-    Answer.No -> "いいえ"
+    is Answer.No -> "いいえ"
```

この状態であれば、期待通りに動作します。
しかし、 `object` で定義された `Yes` や `No` のインスタンスが複数存在しても良いのか？ :thinking: とスッキリしません。

### きちんと同一インスタンスを返すには

スッキリしないので調べてみると、 Serializable なシングルトンオブジェクトを作成するときの実装方法が見つかりました。
`readResolve()` というメソッドを定義してあげれば良いようです。
Android の Serializable のページにも書かれていますね(ちゃんと読んでないけど)。

https://developer.android.com/reference/java/io/Serializable

```kotlin
sealed class Answer : Serializable {
    object Yes : Answer() { private fun readResolve(): Any = Yes }
    object No : Answer() { private fun readResolve(): Any = No }
    data class Other(val text: String) : Answer()
}
```

`readResolve()` でデシリアライズ時の処理を上書きできるようなので、ここで `Yes` `No` を返すことで Serializable を実装していても object のインスタンスを 1つにすることができました。
このように object が定義されていれば、 when の分岐でわざわざ `is` を使わなくても大丈夫です :thumbsup: 

## まとめ

object で定義したクラスを Serializable にするときは気をつけようね、という話でした。
調べればすぐわかるようなものなので、ハマることはないと思います。
知らなかったことを知ることができて、楽しかったです。
正規表現一覧

## 正規表現一覧
```
.	任意の1文字に合致
*	直前の文字が0回以上繰り返されている場合に合致
+	直前の文字が1回以上繰り返されている場合に合致
?	直前の文字が０個か１個の場合に合致（最長一致）
*?	直前の文字が0回以上繰り返されている場合に合致（最短一致）
+?	直前の文字が1回以上繰り返されている場合に合致（最短一致）
??	直前の文字が０個か１個の場合に合致（最短一致）
[  ]	[ ]の中のどれか1文字に合致
[^  ]	[ ]の中の文字以外に合致
( ～ | … )	～か…かどちらかに合致
{n}	直前の文字の桁を指定
\w	アルファベット、数字、アンダスコア（ _ ）のどれかの1文字
\W	アルファベット、数字、アンダスコア以外の1文字
\d	数字1文字
\D	数字以外の1文字
\s	半角スペース、タブ、改行のどれか1文字
\S	半角スペース、タブ、改行以外の1文字
(  )	( )内を1文字扱い
^	行頭
$	行末
\<	単語の先頭
\>	単語の末尾
\b	単語の先頭か末尾
\B	単語の先頭、末尾以外
\A	ファイルの先頭
\z	ファイルの末尾
\G	直前の一致文字列の末尾
\0	一致した文字列全体
\l	次の1文字を小文字にする
\L ～ \E	挟まれた文字列を小文字にする
\u	次の1文字を大文字にする
\U ～ \E	挟まれた文字列を大文字にする
\n	改行
\t	タブ
```
【A Tour of Go】基本編② 〜フロー制御〜

公式の [A Tour of Go](https://go-tour-jp.appspot.com/list) ではじめて Go 言語を触ってみました。
以下、フロー制御（for, if, switch, defer）について学んだことのメモ。

前回の記事はこちら

https://qiita.com/BitterBamboo/items/58d80a1a1a85e18188ce

## `for`

* 初期化ステートメント: 最初のイテレーションの前に初期化が実行される
* 条件式: イテレーションごとに評価される
	* 条件式の評価が false となった場合にイテレーションを停止
* 後処理ステートメント: イテレーションごとの最後に実行される

``` go
package main

import "fmt"

func main() {
	sum := 0
	for i := 0; i < 10; i++ {
		sum += i
	}
	fmt.Println(sum) // 0 + 1 + ... + 9 = 45
}
```

* 初期化ステートメントと後処理ステートメントは任意

``` go
package main

import "fmt"

func main() {
	sum := 1
	for sum <= 4 {
		sum += sum
	}
	fmt.Println(sum) // 1 + 1 + 2 + 4 = 8
}
```

## `if`

* 括弧は不要
* if のスコープ内だけで有効な変数を宣言できる

``` go
package main

import (
	"fmt"
	"math"
)

func pow(x, n, lim float64) float64 {
	if v := math.Pow(x, n); v < lim {
		// v は if のスコープ内でのみ有効
		return v
	} else {
		// v は else の中でも使える
		fmt.Printf("%g >= %g\n", v, lim)
		return lim
	}
}

func main() {
	fmt.Println(
		pow(3, 2, 10), // 9 < 10 なので return v
		pow(3, 3, 20), // 27 < 20 ではないので return lim
	)
}
```

## `switch`

* if-else ステートメントのシーケンスを短く書く方法
* break 不要
* case が定数や整数値である必要はない

``` go
package main

import (
	"fmt"
	"runtime"
)

func main() {
	fmt.Print("Go runs on ")
	switch os := runtime.GOOS; os {
	case "darwin":
		fmt.Println("OS X.")
	case "linux":
		fmt.Println("Linux.")
	default:
		// freebsd, openbsd,
		// plan9, windows...
		fmt.Printf("%s.\n", os)
	}
}
```

* 条件のない switch は `switch true` と同義
* 長くなりがちな if-then-else のつながりをシンプルに表現できる

``` go
package main

import (
	"fmt"
	"time"
)

func main() {
	t := time.Now()
	switch {
	case t.Hour() < 12:
		fmt.Println("Good morning!")
	case t.Hour() < 17:
		fmt.Println("Good afternoon.")
	default:
		fmt.Println("Good evening.")
	}
}
```

## `defer`

* deferへ渡した関数の実行を、呼び出し元の関数のreturnが完了するまで遅延させる
* deferへ渡した関数の引数はすぐに評価されるが、実行は呼び出し元のreturnが終わるまでお預け

``` go
package main

import "fmt"

func main() {
	defer fmt.Println("world")

	fmt.Println("hello")
}
```

* deferへ渡した関数が複数ある場合、その呼び出しは stack される
* LIFO (last-in-first-out) の順番で実行される

``` go
package main

import "fmt"

func main() {
	fmt.Println("counting")

	for i := 0; i < 10; i++ {
		defer fmt.Println(i)
	}

	fmt.Println("done")
}

// 9, 8, ..., 1, 0
```

# 次回

https://qiita.com/BitterBamboo/items/6732a7a9fb2c904641b1
git clone

sasakiyuuya@mbp ~ % cd .ssh
sasakiyuuya@mbp .ssh % chmod 400 jojotech.pem
sasakiyuuya@mbp .ssh % ssh -i jojotech.pem ec2-user@54.249.7.206
[ec2-user@ip-10-0-8-195 ~]$ cd /var
[ec2-user@ip-10-0-8-195 var]$ sudo chmod 755 www
[ec2-user@ip-10-0-8-195 var]$ cd www/
[ec2-user@ip-10-0-8-195 www]$ sudo git clone https://github.com/jojo232/cloud9.git
[ec2-user@ip-10-0-8-195 cloud9]$ gem install bundler
[ec2-user@ip-10-0-8-195 ~]$ gem install rails -v 6.1.4
[ec2-user@ip-10-0-8-195 ~]$ cd /var/www/cloud9
[ec2-user@ip-10-0-8-195 cloud9]$ bundle install
[ec2-user@ip-10-0-8-195 cloud9]$ sudo chown -R ec2-user:ec2-user .

vim config/database.yml ←ファイル変更
production:
  <<: *default
  database: jojorion_production
  username: admin
  password: adminadmin
  host: raistech-live8-2022-database-1.crsw7ysdmznk.ap-northeast-1.rds.amazonaws.com

[ec2-user@ip-10-0-8-195 cloud9]$bundle exec rails webpacker:install
[ec2-user@ip-10-0-8-195 cloud9]$EDITOR=vim bin/rails credentials:edit

↓ローカルフォルダーからマスターキーを引っ張ってくる

sasakiyuuya@mbp jojorion % cat config/master.key
24496010253b94a8ab64e93fe0257ccd
[ec2-user@ip-10-0-8-195 cloud9]$vim config/master.key
[ec2-user@ip-10-0-8-195 cloud9]$RAILS_ENV=poroduction bundle exec rails db:create
[ec2-user@ip-10-0-8-195 cloud9]$RAILS_ENV=poroduction bundle exec rails db:migrate
[ec2-user@ip-10-0-8-195 cloud9]$RAILS_ENV=poroduction bundle exec rails s -b 0.0.0.0
npxやnpmでのインストールが失敗する場合はNode.jsのバージョンを確認しよう

完全に自戒です

Next.jsをインストールしていて、
インストールは一見成功したみたいですが、

```
$ npx create-next-app@latest --typescript

$ npm run dev

ReferenceError: TextEncoder is not defined
```

インストール後の初期状態で起動コマンドを打ち込んでみるとエラーが出てしまいます。


さらに、Storybookをインストールしようとすると

```
$ npx storybook init

input.flat is not a function
```

エラーが出て失敗します。

エラー文で検索してもあまりいい情報がヒットしなかったのですが、
ふとNodeのバージョンはどうだったっけと思ったらv10でした。（現時点でLTSはv16）

Nodeのバージョンを更新してから試したら問題なくインストール成功しました。
初心者向け Ret Hat OpenShift on IBM Cloud に アプリケーションをデプロイ （Webコンソールを利用）

## 内容
[前回作成したOpenShiftクラスター](https://qiita.com/fikuko555/items/828bd89a68b40aad8a8e)に、Webコンソールを使ってアプリケーションをデプロイしました。学んだことの覚え書き。
利用したチュートリアルは以下のStep2。
https://cloud.ibm.com/docs/solution-tutorials?topic=solution-tutorials-openshift-microservices&locale=en


## 目標
+ アプリデプロイに関連するOpenShift Web Console画面をなんとなく理解する
+ OpenShiftの基本的な用語をなんとなく理解する


## OpenShift Webコンソールを開く
1. IBM Cloudにログインし、「OpenShift」 -> 「クラスター」の一覧から作成したクラスター画面を表示。
1. 「OpenShift Webコンソール」を押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648751/698b083c-8e3d-0129-18f9-875f8ca40c19.png)

OpenShift Webコンソール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648751/c98decab-a75a-daed-c76b-619a91743d51.png)


## プロジェクトを作成する
1. 「Administrator」パースペクティブで「ホーム」 -> 「プロジェクト」を選択
1. 「プロジェクトの作成」を押す
1. 「プロジェクトの作成」画面で「名前」を入力して「作成」を押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648751/94f5081c-6db3-74ce-7b3a-1fc3fab74b9f.png)


## example-healthプロジェクトにGitリポジトリーからインポートする
1. 「Developer」パースペクティブで「+追加」を選択
1. （下にスクロールして）「Gitからのインポート」を押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648751/48b23510-282b-588b-255e-47bc443fbc26.png)

3. 「Gitからのインポート」画面で各種値をチュートリアル通り入力して「作成」を押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648751/fc420520-d88d-bfe2-a1e4-e0d1de71c1bd.png)
4. 「トポロジー」画面が表示される
a) Deployment Configをクリックすると詳細画面が右パネルに表示
b) リソースタブを押してリソース情報を確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648751/6e6fd9eb-8398-3143-faac-b27bfcbb23f9.png)


## デプロイしたアプリケーションにアクセス
1. Deployment Configの「リソース」タブの「ルート」に記載されているURLをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648751/3076e861-10fb-83cb-8d7a-482759aceecc.png)

2. アプリが表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648751/21f173bb-0fe3-d134-9004-08156dae7aa0.png)


## 登場人物のまとめ（ざっくり）
<dl>
  <dt>イメージ</dt>
  <dd> アプリケーション </dd>
  <dt>コンテナ</dt>
  <dd> イメージのランタイム </dd>
  <dt>Pod</dt>
  <dd> 一つのホスト上にデプロイされる1つまたは複数のコンテナ </dd>
  <dd> コンテナのグループ、ボリューム、IPアドレスで構成 </dd>
  <dd> 定義・デプロイ・管理される最小単位 </dd>
  <dt>Deployment/Deployment Config</dt>
  <dd> アプリケーションをPodとしてロールアウトするストラテジー </dd>
  <dt>サービス</dt>
  <dd> Podが利用する永続的な内部IPおよびホスト名を提供 </dd>
  <dt>ルート</dt>
  <dd> 外部から到達可能なホスト名 </dd>
  <dt>ビルド</dt>
  <dd> ソースコードを実行可能なイメージに変換するプロセス </dd>
  <dt>プロジェクト</dt>
  <dd> ユーザーや開発者の分離およびコラボレーションの単位として機能 </dd>
<dd> オブジェクト、ポリシー、制約、およびサービスアカウントの独自のセットを持つ </dd>
<dd> namespaceとしても知られる　</dd>
</dl>

### 環境イメージ図（グレー表記は今回作成されていないもの）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648751/7d833a8a-d93f-50be-3383-e86b1d39e4f0.png)

以上
MSAccessのSQLリンクテーブルが最近#Deleted表示になった場合、ODBCドライバを変えて接続してみる

# エラー内容
2021年5月末、以前にSQLサーバーへリンクテーブルで繋いでおいたAccessファイルを起動してみると、一部テーブルのデータが全て #Deleted で表示される。
![access_result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/568190/555d7250-87ea-f373-d0c0-2521aeb8abd9.png)
SQL上にはデータテーブルが存在し、リンクしている一部のテーブルのみが#Deletedが表示され、そして新規Accessファイルでリンクテーブルを作成し直しても同様の症状が発生しました。
Accessの表示上は#Deletedでも、他ソフトからAccessに繋いでのデータの取得は可能でした。

## 動作環境
当時、Access2019は64bit版、バージョン2205、ビルド16.0.15225.20172でした。
調べると32bit版でも同様の症状が発生したそうです。

# 原因
[参考記事](https://codekabinett.com/rdumps.php?Lang=2&targetDoc=msaccess-bug-v2205-odbc-deleted-nvarchar-primary-key) によると、AccessのバージョンとODBCによっては相性が悪く、主キーに NVarchar を使用していると #Deleted 表示になることがあるそうです。
今回は、主キーに NVarchar を使用し、ODBCドライバーは[参考記事](https://codekabinett.com/rdumps.php?Lang=2&targetDoc=msaccess-bug-v2205-odbc-deleted-nvarchar-primary-key)で相性が悪いとされていた「SQL Server」を使用してAccessにリンクテーブルを作成していました。

# 対処法
ODBCデータソース(アドミニストレーター)でインストール済みのODBCドライバーを確認。
「SQL Server」の他に、[参考記事](https://codekabinett.com/rdumps.php?Lang=2&targetDoc=msaccess-bug-v2205-odbc-deleted-nvarchar-primary-key)で相性が良いとされていた「ODBC Driver 17 for SQL Server」がインストールされていたので、こちらを使用することとした。
リンクテーブル作成時に使用するdsnファイル内のODBC指定を「ODBC Driver 17 for SQL Server」に書き換え、書き換えたdsnファイルを使用してAccessでリンクテーブルを新規作成。
![access_dsn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/568190/91a7bc40-6672-574f-6548-f86eef23caaf.png)

# 所感
画面表示が#Deleted一面に変わった時は、何かいけないことをしてしまったのではないかと焦りました。
英語で対処法が書かれているページを見つけたまではよかったのですが、理解が浅く先輩に助けてもらって解決できました、ありがとうございます。
バグが修正されると嬉しいです。

# 参考記事
- [New Bug in Microsoft Access 365 Version 2205 - SQL Server NVarchar Primary Keys cause #DELETED when linked with ODBC](https://codekabinett.com/rdumps.php?Lang=2&targetDoc=msaccess-bug-v2205-odbc-deleted-nvarchar-primary-key)
【JavaScript】【HTML】console.logの出力結果をブラウザ(Webページ)上に表示する方法

　スタックオーバーフローで「[console.logの出力結果をブラウザ上で表示したい](https://ja.stackoverflow.com/questions/88784/console-log%e3%81%ae%e5%87%ba%e5%8a%9b%e7%b5%90%e6%9e%9c%e3%82%92%e3%83%96%e3%83%a9%e3%82%a6%e3%82%b6%e4%b8%8a%e3%81%a7%e8%a1%a8%e7%a4%ba%e3%81%97%e3%81%9f%e3%81%84/88805#88805)」という質問に対して回答した内容をまとめたものです。
　console.logに対して、DOM操作でHTML上の要素を操作す関数式を代入することによって実現しました。サンプルコードは以下のものです。以下のコードはブラウザ上に1～100の数値を改行して出力します。
```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script>
        // ページ読み込み時のイベントを登録
        window.onload = function () {
            // ブラウザ上に表示する文字列を保持する一時変数
            let outstr = "";
            // console.logの挙動
            console.log = (...args) => {
                for (let arg of args) {
                    // console.logに入力された文字列を改行つきで保持
                    outstr = outstr + arg + "<br>";
                }
                // HTMLのid="console"に対して文字列outstrを設定する
                document.getElementById("console").innerHTML = outstr;
            }

            // 1～100までを出力するコード
            for (let i = 1; i < 100; i++) {
                console.log(i);
            }
        }
    </script>
</head>

<body>
    <!-- ブラウザ上の出力先 -->
    <p id="console"/>
</body>

</html>
```
　```document.getElementById("console").innerHTML=outstr```でHTMLのidがconsoleの要素へ設定してます。
　処理が完了してからブラウザに反映されるようなので1～100までを出力するコードを以下のような処理が完了しないコードに書き換えると動作しません。
```javascript
            // 1からの値を出力するコード
            for (let i = 1;; i++) {
                console.log(i);
            }
```
　console.logを介さず直接```document.getElementById("console").innerHTML```で文字列を設定した方が早いかもしれません。しかし、初心者にとっては1～100までを出力するコード部分を書き換えてconsole.logで操作した方がわかりやすいのかもしれません。
topic branchで変更した内容を全部なかったことにしてくれ〜〜〜！！！

# トピックブランチをマージしてないのにmain(master)に変更内容がmergeされてる...?

勉強不足で恐縮ですが、 topic branchをマージせず、checkoutしてmain branchに戻すだけで変更内容を消せると思っていた。
実際やってみたら、コンフリクトせず、topicで変更した内容が反映されているように見えた。

そこで、以下変更内容を完全に消すようにしたい。
```
$ git status 
On branch topic-branch
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   README.md
        deleted:    app/assets/stylesheets/users.scss
        modified:   app/javascript/packs/application.js
        modified:   app/views/layouts/_rails_default.html.erb

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .DS_Store
        app/.DS_Store
        app/javascript/stylesheets/

no changes added to commit (use "git add" and/or "git commit -a")
```
・ステージングにあり、追跡されているが編集されているもの
・新たに追加されたため、追跡されていないもの
の二種類がある状態から、２ステップの作業を行っていく。

# master branchから変更内容を削除する 
https://leben.mobi/blog/git/other/

上記記事を参考に変更内容をmaster branchから削除した。
まず、modifyされた内容を取り消す。
```
$ git checkout .
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .DS_Store
        app/.DS_Store
        app/javascript/stylesheets/
       
nothing added to commit but untracked files present (use "git add" to track)
```
次に、ファイルが削除されたり、追加されたりしている、追跡対象外のファイルやディレクトリを削除する。
```
$ git clean -df .
$ git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean
```

これで全ての変更内容が取り消せた。
以上
【Angularアプリケーション開発 #5】双方向バインディング

今回は双方向バインディングを実装してみます。
イメージとしては↓こんな感じです。
![スクリーンショット 2022-05-31 23.39.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689436/4ea5fc78-df22-0b2e-6e49-44a6193432ce.png)
入力フォームの田中太郎の「郎」の文字を消してみます。
すると、、、
![スクリーンショット 2022-05-31 23.41.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689436/581167ea-c55a-1e98-3400-6fa37bfe94ce.png)
入力フォームと連動して名前をh2タグのラベルも「田中太」になりました。
このように、html側→ts側、ts側→html側へと値が共有されている状態を双方向バインディングと言います。（私個人のイメージです。）

それでは実装していきましょう。
- まずはFormsModuleというモジュールをapp.module.tsに追加します。
import文の追加と@NgModuleのimportsにFormsModuleの追加を行います。
```typescript:app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { MembersComponent } from './members/members.component';
import { MemberDetailComponent } from './member-detail/member-detail.component';
import { FooterComponent } from './footer/footer.component';

@NgModule({
  declarations: [
    AppComponent,
    MembersComponent,
    MemberDetailComponent,
    FooterComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
```
- 次に双方向バインディングを扱う、htmlです。
```html:members.component.html
<h2>{{member.name}}</h2>
<div>
  <label>id:</label>{{member.id}}
</div>
<div>
  <label>名前:
    <!-- 双方向データバインディング -->
    <input type="text" [(ngModel)]="member.name" placeholder="名前">
  </label>
</div>
```
- 最後に双方向バインディングを行う、tsファイル側です。
```typescript:members.component.ts
import { Component, OnInit } from '@angular/core';
import { Member } from '../member';

@Component({
  selector: 'app-members',
  templateUrl: './members.component.html',
  styleUrls: ['./members.component.css']
})
export class MembersComponent implements OnInit {

  member:Member =
    {id:'1',name:'taro'};

  constructor() { }

  ngOnInit(): void {
  }
}
```

補足です。
memberオブジェクトはMemberインターフェースを型としています。
別ファイルにインターフェースを定義しています。
ちなみにexportを付けることで外部から参照できるようになります。
```typescript:member.ts
export interface Member{
  id:string;
  name:string;
}
```
git cloune

sasakiyuuya@mbp ~ % cd .ssh
sasakiyuuya@mbp .ssh % chmod 400 jojotech.pem
sasakiyuuya@mbp .ssh % ssh -i jojotech.pem ec2-user@54.249.7.206
[ec2-user@ip-10-0-8-195 ~]$ cd /var
[ec2-user@ip-10-0-8-195 var]$ sudo chmod 755 www
[ec2-user@ip-10-0-8-195 var]$ cd www/
[ec2-user@ip-10-0-8-195 www]$ sudo git clone https://github.com/jojo232/cloud9.git
[ec2-user@ip-10-0-8-195 cloud9]$ gem install bundler
[ec2-user@ip-10-0-8-195 ~]$ gem install rails -v 6.1.4
[ec2-user@ip-10-0-8-195 ~]$ cd /var/www/cloud9
[ec2-user@ip-10-0-8-195 cloud9]$ bundle install
marginが効かないときの対処法【備忘録】

自分が個人開発していく中でハマった部分の備忘録を残しておきます。

## インライン要素にmarginは効かない
結論これです。具体例を見ていきましょう

```
<div class="col-sm-7">
    <h3>こんばんは</h3>
    <span class="pt-md-0">こんばんは</span>
    <br>
　　<span class="en">KONBANHA</span>
</div>
```
自分が開発していく中で、知ったのはインライン要素にmarginは効かないんです。
インライン要素とは、***行の中の一部のまとまり***です。
ブロック要素とは、***行全体のまとまり***のことを言います。

簡単にまとめました。

参考になれば幸いです！

【参考資料】

https://qiita.com/7note/items/3eaecf9688e957eeb93d
【A Tour of Go】基本編① 〜パッケージ、変数、関数〜

公式の [A Tour of Go](https://go-tour-jp.appspot.com/list) ではじめて Go 言語を触ってみました。
以下、パッケージ・変数・関数について学んだことのメモ。


## パッケージ

### package

* Goのプログラムはパッケージで構成される

``` go
// プログラムは main パッケージから開始される
package main

// "fmt" と "math/rand" パッケージを import
import (
	"fmt"
	"math/rand" // `package rand` ステートメントで始まるファイル群
)

func main() {
	fmt.Println("My favorite number is", rand.Intn(18))
}
```

### import

* `import`ステートメントの書き方
	* 括弧で複数の`import`を整理する（*better*）
	* 複数の`import`ステートメントを書く

``` go
// factored import statement
import (
	"fmt"
	"math"
)

// multiple import statements
import "fmt"
import "math"
```

### export

* 大文字で始まる名前は、外部のパッケージから参照できる export された名前である

``` go
package main

import (
	"fmt"
	"math"
)

// wrong "undefined: math.pi"
func main() {
	fmt.Println(math.pi)
}

// correct
func main() {
	fmt.Println(math.Pi)
}
```

## 関数

### 書き方

* 型は後ろに書く
* 複数の引数が同じ型である場合は、最後の型を残して省略できる

``` go
func add(x int, y int) int {
	// add(x, y int) とも書ける
	return x + y
}
```

### 複数の戻り値

* 関数は複数の戻り値を返すことができる

``` go
package main

import "fmt"

func swap(x, y string) (string, string) {
	// 複数の戻り値！
	return y, x
}

func main() {
	a, b := swap("hello", "world")
	fmt.Println(a, b)
}
```

### 名前付き戻り値

* 戻り値となる変数に名前を付けることができる（**名前付き戻り値**）
	* 関数の最初で定義した変数名として扱われる
	* `return`ステートメントに何も書かなくてよくなる（**Naked return**）
		* 可読性の観点から、短い関数でのみ利用すべき

``` go
func split(sum int) (x, y int) {
	// x, y が named return values
	x = sum * 4 / 9
	y = sum - x
	return // Naked return
}
```

## 変数

### 基本的な変数宣言

* `var`ステートメントで変数を宣言できる
* 複数の変数の最後に型を書くことで、それらの変数を一括で宣言できる
* 初期値が与えられている場合、型は省略可能

``` go
var i, j int = 1, 2
```

### 短い変数宣言

* 関数の中では`var`の代わりに、短い`:=`の代入文を使って暗黙的な型宣言ができる

``` go
func main() {
	k := 3
	fmt.Pringln(k)
}
```

### 基本的な型

* bool
* string
* int, int8, int16, int32, int64
* unit, unit8, unit16, unit32, unit64, unitptr
* byte（unit8の別名）
* rune（int32の別名）
* float32, float64
* complex64, complex128

> int, uint, uintptr 型は、32-bitのシステムでは32 bitで、64-bitのシステムでは64 bitです

### ゼロ値

* 数値型(int, float など): `0`
* bool型: `false`
* string型: `""`

### 型変換

* T(v) は変数 v をT 型へ変換する

``` go
i := 42
f := float64(i)
u := unit(f)
```

### 型推論

``` go
i := 42 // int
f := 3.142 // float64
u := unit(f)  // complex128
```

### 定数

* 定数は bool, string, 数値でのみ使える
* `:=` を使って宣言できない

# 次回

https://qiita.com/BitterBamboo/items/f72ce6f7ce20e6b5f6c7

https://qiita.com/BitterBamboo/items/6732a7a9fb2c904641b1
地図上にピカチュウを表示させてみた

## はじめに
最近会社と家の往復がメインになっていて、ちょっと癒しが欲しくなっています。
癒されたい、でも何か取り組みたい、、、

そうだ、地図上にかわいいポケモンを表示させたら癒されるかもしれない！と思ってやってみました。

## 内容
```python
 #APIからピカチュウの画像習得
import requests
url = 'https://pokeapi.co/api/v2/pokemon/25/'
r = requests.get(url, timeout=5)
r = r.json()
image = r['sprites']['front_default']
print(image)
```

こんな感じの画像です。かわいいですよね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1259951/e0353434-f3dc-054d-f8a5-e1a6310936c6.png)

```python
 #urlから画像を取得して保存する
file_name = 'pikatyu.png'
response = requests.get(image)
img = response.content

with open(file_name,"wb") as f:
    f.write(img)
```

ここからは画像上にピカチュウを配置していきます。
```python
 #モジュールのインポート
!pip install folium
import folium 
from folium.features import CustomIcon

 #アイコン設定
pika = '/content/pikatyu.png'

icon = CustomIcon(
    icon_image = pika,
    icon_size = (100, 100),
    icon_anchor = (10, 10),
    popup_anchor = (3, 3)
)

 #池袋駅の座標
latlong = [35.728926,139.71038]

 # 地図を描画する
map = folium.Map(location=latlong, zoom_start=15)

 #--- 地図に自作アイコンを載せる---
 # アイコンの座標（サンシャインシティ）
icon_latlng = [35.7288148, 139.7200041]
 # アイコンを追加
folium.Marker(
    location = icon_latlng,
    popup = 'ピカチュウ！',
    tooltip = 'ピカ！',
    icon = icon
).add_to(map)

 # 地図をJupyter上に表示
map
```

ポケモンセンターがサンシャインシティにあるので、ここに配置されるようにしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1259951/4ed5d7d8-8e25-ff8e-7b90-b0111bd260f5.png)

クリックすると鳴き声も聞こえます(ピッ、ピッカ！ピカチュウ★)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1259951/0e3440c4-43cd-90fa-9cf7-6c1eac2df258.png)

## まとめ
かわいいピカチュウを表示させることができました。他にもヤドンなど、ゆるっとしたキャラクターを使ったら楽しいかもしれない。

## 参考
https://taiyosite.com/pokeapi-elementary/
https://chayarokurokuro.hatenablog.com/entry/2021/07/11/175024
https://pokeapi.co/
WordPress関連の単語まとめ

最近WordPressに入門しました。
よく分からない単語がいくつかあったので書籍やサイトを参考にまとめてみました。

## WordPress
- ブログやホームページを作ることができるオープンソースソフトウェア
- ウェブの43% が WordPress で構築されている
- プラグインが豊富で拡張性が高い
- CMS（コンテンツ・マネジメント・システム）の一つ

## CMS
- ウェブサイトを管理・更新できるシステム
- 管理画面からテキストや画像を入れ替えて更新することができる
- 動的サイトに分類され、WordPressではPHPが使われている

## PHP
- オープンソースの汎用スクリプト言語
- サーバーサイドで動的なWebページを作成することができる
    - データベースに保存されている情報を取得し、HTMLに変換する

## ページ
- 投稿ページ
    - ブログのページ
    - 管理画面から自由に投稿を増やすことができる
- 固定ページ
    - ホームページとして公開するページ

## テーマ
- Webサイトの外観を制御するモジュール
- WordPressのテンプレートファイルの集まり
- テーマは、wp-includes/themes ディレクトリにインストールされる
- WordPressの公式からテーマが配布されている
    - https://ja.wordpress.org/themes/

## テンプレートファイル
- PHPで記述したHTML生成用のファイル

## 参考文献
- [WordPress.com](https://wordpress.com/ja/)
- [ブログから大規模サイトまで作れる CMS | WordPress.org](https://ja.wordpress.org/)
- 中田亨(2017) 『WordPressのツボとコツがゼッタイにわかる本』秀和システム
- プライム・ストラテジー株式会社(2015) 『詳解 WordPress』オライリー・ジャパン
Codelab から ViewModel と LiveData の Unit テストを学ぶ1


# はじめに
あまりテストを書いたことがないなぁということで休み中に Unit テストの Codelab をやってみました。
実際に手を動かしてみて自分的に学びになった箇所や途中で詰まった箇所をまとめたいと思います。


## Advanced Android in Kotlin 05.1:Testing Basics
https://developer.android.com/codelabs/advanced-android-kotlin-training-testing-basics?hl=ja#0

## 気になったところ
### Page6
- `Hamcrest` を導入する場合は[こちら](https://mvnrepository.com/artifact/org.hamcrest/hamcrest-all) を参照する
    - 今回は2022/05/29時点で最新の `1.3` を導入
    - Hamcrest を使う際に `assertThat` と `Matcher(is)` を使おうとしたらうまく import に引っ掛からなかったので以下を手動で入れた。
        - `import org.hamcrest.MatcherAssert.assertThat`
        - `` import org.hamcrest.Matchers. `is` ``
        
※自分は `Hamcrest` の `` `is` `` が辛そうだなと感じたので [Truth](https://truth.dev/) を導入しました。

### Page7
- 業務でまずどこからテストを書こうってなったら、`ViewModel` だけにしかないロジックのテストを書くことから始めると良いのかもと思った。
- 依存関係の設定が何を追加すれば良いのか分かりにくかった
    - Step3 に記載されているライブラリと `Robolectric` を個別で入れれば動く
- AndroidX Test は Local Test でも InstrumentedTest でもどちらでも同じライブラリで動くので個別でテストごとの作法を覚える必要がない。
- TestRunner とは JUnit がテストを実行するための JUnit のコンポーネントでこれがないとテストが実行されないらしい。
     - LocalUnitTest でも `RunWith(AndroidJUnit4::class)` を使って Android のリソースを使ったテストが可能

### Page9
- `LiveData` を使ったテストを書く場合は `@get:Rule` アノテーションを使って、 `InstantTaskExecutorRule` を呼び出す
    - バックグラウンドで実行されるアーキテクチャコンポーネントの処理が同一のスレッド上で実行されるようになるので、実行可能な順序でテスト中は実行されるようになる
- `LiveData` のテストをする際に `observe` を使うと `LifecycleOwner` が渡せないので、 `observeForever` を使うとよい。
    - Transformations を使用していた場合は特に重要らしい。
- `LiveDataTestUtil.kt` について
    - `LiveData`　から値を取得するための処理で、値が取れるまで `CountDownLatch` で待ってくれる
    - https://medium.com/androiddevelopers/unit-testing-livedata-and-other-common-observability-problems-bb477262eb04

# 最後に
今回の Codelab だけだと `viewModelScope` を使ったテストはまだできないようなので、次の Codelab もやっていきます。

https://developer.android.com/codelabs/advanced-android-kotlin-training-testing-test-doubles?hl=ja#0
FLIRCのBlackMagic Probe互換機にファームウェアを焼く


# 概要

FLIRCが販売しているOpenSourceなJTAG Probe、まぁ要はBlackMagic Probe互換機にファームウェアを焼く手順。自分のメモ的な要素が強い。

ref. https://flirc.tv/products/flirc-jeffprobe?variant=42687976866020

# 前提

公式で述べられているような手順は使えない。

ref. https://github.com/blackmagic-debug/blackmagic/wiki/Upgrading-Firmware

```
$ scripts/stm32_mem.py blackmagic.bin
```

正確には以下のように書き込めはする。けど文鎮化する。そもそも書き込みアドレスが根本的に違ったりする。
ちなみに死んでしまっても、後述の正しい手順で書き込み直せば良いだけなのであまり気にしなくて良い。

```
$ python3 scripts/stm32_mem.py blackmagic-native-v1_8_0.bin 
-
USB Device Firmware Upgrade - Host Utility -- version 1.2
Copyright (C) 2011  Black Sphere Technologies
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
-
Device ID:	 1d50:6018
Manufacturer:	 Black Sphere Technologies
Product:	 Black Magic Probe (SAMD), (Firmware v1.6.2)
Serial:		 D724B5B1
Failed to read device state! Assuming APP_IDLE
Invoking DFU Device
Device ID:	 1d50:6017
Manufacturer:	 Black Sphere Technologies
Product:	 DFU Demo
Serial:		 DEMO
Programming memory at 0x0801B400
-
All operations complete!
```
# 手順

まずFLIRCのリポジトリにあるファームウェアをありがたく頂戴する。
* https://github.com/flirc/blackmagic/releases/tag/v1.6.3

次にFLIRC BlackMagic Probeのボード上のプッシュスイッチを押しながらUSB接続を行う。これでDFUモードで立ち上げられる。うまくいっていないなら次の手順でエラー吐くのですぐわかる。

`dfu-util`を使って書き込む。公式のwikiに書かれているdfu-utilの手順は参考にしてはいけない。
オリジナルBlackMagicProbeの`0x08002000`とは異なるアドレスであることに注意。

```
$ dfu-util -d 1d50:6018,:6017 -s 0x2000:leave -D blackmagic.bin
```

e.g.
```
$ sudo dfu-util -d 1d50:6018,:6017 -s 0x2000:leave -D blackmagic_fw/blackmagic.bin
dfu-util 0.11

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2021 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

dfu-util: Warning: Invalid DFU suffix signature
dfu-util: A valid DFU suffix will be required in a future dfu-util release
Opening DFU capable USB device...
Device ID 1d50:6017
Device DFU version 011a
Claiming USB DFU Interface...
Setting Alternate Interface #0 ...
Determining device status...
DFU state(2) = dfuIDLE, status(0) = No error condition is present
DFU mode device DFU version 011a
Device returned transfer size 4096
DfuSe interface name: "Internal Flash   "
Downloading element to address = 0x00002000, size = 105308
Erase   	[=========================] 100%       105308 bytes
Erase    done.
Download	[=========================] 100%       105308 bytes
Download done.
File downloaded successfully
Submitting leave request...
Transitioning to dfuMANIFEST state
```

# 参考

* https://github.com/sureshsitaula/blackmagic-jeffprobe
[Zabbix]ログ監視の手法について

# ログ監視の設定方法

## item設定例
名前：アイテム名（監視項目の名前）
タイプ；Zabbixエージェント(アクティブ)
キー：((設定方法は下記に記載))
データ型：ログ
監視間隔：1m
ヒストリの保存期間：30d
ログの時間の形式：((ログフォーマットによる))
アプリケーション：APP‗LOGやOS_LOGなどを作成
説明：そのログがなんのログなのか記載
有効：チェック


### アイテムキー
利用するアイテムキーについて
logかlogrt、
Windowsのイベントログにはイベントログ用のeventlogが用意されている

キーの使い方の詳細は以下リンクを参照
[log,logrt](https://www.zabbix.com/documentation/4.0/en/manual/config/items/itemtypes/zabbix_agent)
[eventlog](https://www.zabbix.com/documentation/4.0/en/manual/config/items/itemtypes/zabbix_agent/win_keys)


## アイテムキーはどれを使うか

**log** 固定したファイルパスでファイルが1つだけの場合
**logrt** 固定したファイルパスでファイルが複数ある場合（※正規表現で指定）
**eventlog** windowsのイベントログの場合

という使い分けになる

**logrt**についてはログ名がerror.log.0、error.log.1だったり、
app_20220511.log、app_20220512.logなど
日付や特定の数字などが名前に入るログに対して利用できます。
[Zabbix]ZabbixAPIで対象のテンプレートが適用されているホストを調べる方法

### テンプレート名を指定してテンプレートID取得
```
curl -sS -d '
{
   "jsonrpc": "2.0",
   "method": "template.get",
   "params":
       {
           "output": "extend",
           "filter":
               {
                   "name":
                       ["<テンプレート名>"]
               }
       },
   "auth": "<認証キー>",
   "id": 1
}
' -H "Content-Type:application/json-rpc" https://<zabbixのIP>/zabbix/api_jsonrpc.php | python -mjson.tool | grep templateid | gawk -F'"' '{print $4}'
```
### 取得したIDを利用してテンプレートIDに紐づくホスト一覧を取得
```
curl -sS -d '
{
   "jsonrpc":"2.0",
   "method":"host.get",
   "params":
       {
           "output":"extend",
           "selectInterfaces":"extend",
           "templateids":"<テンプレートID>"
       },
    "auth": "<認証キー>",
    "id": 1
}
' -H "Content-Type:application/json-rpc"  https://<zabbixのIP>/zabbix/api_jsonrpc.php | jq -r -c '.result[] | .host' | more
角度のある画像で顔検出できるのか(MTCNN)

# 気になったこと
画像から顔検出するライブラリのMTCNNが、角度のある顔画像に対してどの程度検出できるのかが気になったので、画像を回転させてどこまで検出できるか試してみようと思います。

# やったこと
このような処理を作成しました。
まず、読み込ませた「ivan.jpg」の画像をangleの値だけ回転させて保存します。
その画像をMTCNNで顔検出させたとき、angleをどこまで上げても大丈夫なのかを確認しました。

``` python
import cv2
from mtcnn import MTCNN
from PIL import Image

angle = 45

filename = "ivan.jpg"
output1 = "rotate_" + filename
output2 = "drow_" + filename
detector = MTCNN()

#画像を傾かせて保存する
pil_image = Image.open(filename)
rotate_image = pil_image.rotate(angle)
rotate_image.save(output1)

#画像を読み込んで顔検出
image = cv2.cvtColor(cv2.imread(output1), cv2.COLOR_BGR2RGB)
result = detector.detect_faces(image)

#画像に描画して保存
bounding_box = result[0]['box']
keypoints = result[0]['keypoints']

cv2.rectangle(image,
              (bounding_box[0], bounding_box[1]),
              (bounding_box[0]+bounding_box[2], bounding_box[1] + bounding_box[3]),
              (0,155,255),
              2)

cv2.circle(image,(keypoints['left_eye']), 2, (0,155,255), 2)
cv2.circle(image,(keypoints['right_eye']), 2, (0,155,255), 2)
cv2.circle(image,(keypoints['nose']), 2, (255,155,0), 2)
cv2.line(image,(keypoints['mouth_left']),(keypoints['mouth_right']),(0, 0, 0),2)

cv2.imwrite(output2, cv2.cvtColor(image, cv2.COLOR_RGB2BGR))

print(result)
```

# やった結果
### 回転なし。もちろん顔検出出来ています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1359985/64db7e07-682a-a6e0-c891-8bb54ba40e8f.jpeg" width=40%>

### 45度回転。顔検出は出来ていますが、パーツの位置がずれています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1359985/2d50fc12-aa44-57bf-6577-f826dcc9f8e3.jpeg" width=40%>

### 90度回転。顔検出は出来ていますが、パーツの位置がめちゃくちゃです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1359985/a92159e5-fafd-6917-bb6c-ad1dc2330201.jpeg" width=40%>

### 120度回転。顔検出は出来ていますが、パーツの位置がめちゃくちゃです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1359985/2d8ced03-7612-d3e9-2200-51dfcd23082d.jpeg" width=40%>

### 150度回転。顔検出は出来ていますが、パーツの位置がめちゃくちゃです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1359985/65e6a6dc-3ac9-a103-650f-ea40d95eeceb.jpeg" width=40%>

### 180度回転。顔検出は出来ませんでした。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1359985/7d2ea66f-c60b-f7e9-1b15-12f60089f4ad.jpeg" width=40%>

# まとめ
この結果を見る限り、MTCNNで顔検出する場合、多少角度がきつくても顔検出はできているように見えました。
ただ、目、鼻、口の位置は信用できない情報になりそうです。
また、この結果はこの画像での結果でしかないので、別の人だと結果が違ってくるのかもしれません。
Windows で OpenSSL を ビルドする

# Windows で OpenSSL をビルドする

Windows版のビルド方法は、以下に記載されていました。

https://github.com/openssl/openssl/blob/master/NOTES-WINDOWS.md

上記の情報を元にビルドしてみました。

## 必要なアプリケーション

* OpenSSL 3.0.x
* Visual Studio 2022 Community
* Strawberry Perl for Windows
* NASM (アセンブラも使ってビルドすときに必要)

## アプリケーションのインストール

OpenSSL の ソースコードを以下からダウンロードします。

https://www.openssl.org/source/

Visual Stuido 2022 Commnunity を以下からダウンロードとしてインストールします。

https://visualstudio.microsoft.com/ja/free-developer-offers/

Strawberry Perl を以下からダウンロードしてインストールします。

https://strawberryperl.com/

アセンブラも使用してビルドする場合、NASMが必要です。

~~最新版の2.15.05 では、何故かビルド時にエラーが出て、OpenSSLのビルドに失敗したので、2.14.02を使います。~~

64bit版のOpenSSLを作成する場合、以下の64bit版 NASM をダウンロードし、インストールします。

~~https://www.nasm.us/pub/nasm/releasebuilds/2.14.02/win64/~~

https://www.nasm.us/pub/nasm/releasebuilds/2.16.01/win64/

32bit版のOpenSSLを作成する場合、以下の32bit版 NASM をダウンロードし、インストールします。

~~https://www.nasm.us/pub/nasm/releasebuilds/2.14.02/win32/~~

https://www.nasm.us/pub/nasm/releasebuilds/2.16.01/win32/


## OpenSSLのビルド

### Visual Studio用 コマンドプロンプトを 起動

64bit版のOpenSSLを作成する場合、x64 Native Tools Command Prompt for VS 2022 を管理者権限で実行します。32bit版のOpenSSLを作成する場合、x86 Native Tools Command Prompt for VS 2022 を管理者権限で実行します。

### 圧縮ファイルの展開
OpenSSLの圧縮ファイルを展開します。

```
>tar xvf openssl-3.0.2.tar.gz
```
cd
### ビルド

#### 64bit版 アセンブラを使用しないでコンパイル

```
> cd openssl-3.0.10
> perl Configure VC-WIN64A no-asm
> nmake
> nmake test
> nmake install
```

#### 64bit版 アセンブラを使用してコンパイル

NASM.EXEのフォルダを環境変数 PATH に設定してからコンパイルを実施します。

```
> cd openssl-3.0.10
> set PATH=%PATH%;C:\Program Files\NASM
> perl Configure VC-WIN64A
> nmake
> nmake test
> nmake install
```

#### 32bit版 アセンブラを使用しないでコンパイル

```
> cd openssl-3.0.2
> perl Configure VC-WIN32 no-asm
> nmake
> nmake test
> nmake install
```

#### 32bit版 アセンブラを使用してコンパイル

NASM.EXEのフォルダを環境変数 PATH に設定してからコンパイルを実施します。

```
> cd openssl-3.0.2
> set PATH=%PATH%;C:\Program Files (x86)\NASM
> perl Configure VC-WIN32
> nmake
> nmake test
> nmake install
```

### 完成
作成されたOpenSSLは、64bit版は、以下に格納されます。

C:\Program Files\OpenSSL

32bit版は、以下に格納されます。

C:\Program Files (x86)\OpenSSL