OmniAICreator/Qiita-1.07M huggingface dataset:
【Unity】NRSDK1.3.0のHelloMRシーンを読んでみる【Nreal】

##はじめに

NRSDK 1.3.0にあるHelloMRシーンを観察していきます。

もし間違いがあれば、指摘いただければ幸いです。

###HelloMRシーンについて
NrealSDKに既存で入っているシーン
平面を検知し、床オブジェクトを生成、床オブジェクトをタッチした位置にマスコットを配置するというもの
おそらく、Nreal実機確認の際に一番初めに使用するであろうもの

###シーン構成
以下の6つからなる

| シーン構成 | 
|:-----------|
| NRCameraRig|
| NRInput|
| NRLogo|
| TrackingInfomationTips|
| PlaneDetector|
| Directional Light|

###NRCameraRig
子にLeftCamera、CenterCaemra、RightCameraがある名前の通りカメラのプレハブ
NRSDK>Prefabsに存在する
Nrealでは、Unity既存のMainCameraではなく、NRCameraRigを使う。

| スクリプト名 | 役割
|:-----------|:-----------|
| NRSessionBehaviour|ARシステムの状態を管理するNRSessionManagerを生成し、SessionConfigの情報を設定している。SessionConfigは平面検知方法や画像認識の有無、画像認識ソースなどを設定している|
| NRHMDPoseTracker|カメラパラメータを初期化し、デバイスの姿勢を更新するために使用する。TrackingType（3Dof,6Dof）が設定できる。
| AppManager|Nrealのコントローラーのイベントを設定している。NRInputクラスのAddClickListenerで設定している
| NRMultiDisplayManager|NrealLightでスマートフォンをコントローラーとする時に必要なものらしい（参考：https://developer.nreal.ai/develop/unity/customize-phone-controller）

###NRInput
コントローラーの状態の取得、コントローラーの状態の更新など、コントローラーに関連する処理を行うメインクラス

公式ページに非常にわかりやすく説明してありました。
→https://developer.nreal.ai/develop/unity/controller

| スクリプト名 | 役割
|:-----------|:-----------|
| NRInput | コントローラーの状態の取得、更新などを行うクラス。UnityEditorで実行した際のコントローラーオブジェクトなどはこのクラス経由で作られているみたい。通常はNrealDeveloperKitのコントローラーが生成されるが、EmulateVirtualDisplayInEditorをTrueにすると、NrealLightで使用するスマートフォンのコントローラーが生成される。

###NRLogo
Nrealのロゴ
特にアタッチされているスクリプトはない

###TrackingInfomationTips
カメラのトラッキング状態をコンソール、または視覚的に伝えてくれるもの
NRSDK>Demo>ResourceにあるLostTrackingTip、UnInitializedTipなどを生成してくれる

###PlaneDetector

| スクリプト名 | 役割
|:-----------|:-----------|
|PlaneDetector|平面と認識された場所に視覚化するためのオブジェクトを生成する平面オブジェクトはPolygonPlaneVisualizerが設定されており、インスペクタから変更可能
|HelloMRController|Rayを飛ばし、ヒットした場所にオブジェクトを生成するもの。サンプルシーンでは、Mascotが設定されており、インスペクタから変更可能|
|UserDefinePanel|UserDefinePanelを生成するもの

・Directional Light
Unity製のライト

##終わりに
今後もほかのシーンを観察しつつ、学べたらと思います。
理解次第、追記していきます。
AWS S3のCloudTrailによるログとS3サーバアクセスログのサンプル

S3へのアクセスのログを取るには、CloudTrailを使う方法とS3サーバアクセスログを使う方法があります。

2つのログの比較は公式ドキュメントにも説明があります。

[Amazon S3 でのログ記録 - Amazon Simple Storage Service](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/logging-with-S3.html)

実際に両方のログを取ってみたのでサンプルを載せておきます。


# CloudTrail S3オブジェクトレベルログ

CloudTrailでのログはJSONをgzで圧縮したものがS3に保存されます。

情報量が多いです。JSONですので項目名が書かれており、わかりやすいです。

S3サーバアクセスログと違って、イベントが発生したらすぐに保存されるようです。


```json
{
  "Records": [
    {
      "eventVersion": "1.07",
      "userIdentity": {
        "type": "IAMUser",
        "principalId": "AIDAXXXXXXXXXXXXXXXXX",
        "arn": "arn:aws:iam::XXXXXXXXXXXX:user/xxxxxxxx",
        "accountId": "XXXXXXXXXXXX",
        "accessKeyId": "AKIAXXXXXXXXXXXXXXXX",
        "userName": "xxxxxxxx"
      },
      "eventTime": "2020-07-06T13:37:17Z",
      "eventSource": "s3.amazonaws.com",
      "eventName": "GetObject",
      "awsRegion": "ap-northeast-1",
      "sourceIPAddress": "172.XXX.XXX.XXX",
      "userAgent": "[aws-cli/1.18.68 Python/3.8.1 Linux/4.15.0-1057-aws botocore/1.16.18]",
      "requestParameters": {
        "bucketName": "XXXXBUCKETNAMEXXXX",
        "Host": "XXXXBUCKETNAMEXXXX.s3.ap-northeast-1.amazonaws.com",
        "key": "test1.txt"
      },
      "responseElements": null,
      "additionalEventData": {
        "SignatureVersion": "SigV4",
        "CipherSuite": "ECDHE-RSA-AES128-GCM-SHA256",
        "bytesTransferredIn": 0,
        "AuthenticationMethod": "AuthHeader",
        "x-amz-id-2": "XXXXAMAZONREQUESTIDXXXX",
        "bytesTransferredOut": 6
      },
      "requestID": "XXXXREQUESTIDXXXX",
      "eventID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "readOnly": true,
      "resources": [
        {
          "type": "AWS::S3::Object",
          "ARN": "arn:aws:s3:::XXXXBUCKETNAMEXXXX/test1.txt"
        },
        {
          "accountId": "XXXXXXXXXXXX",
          "type": "AWS::S3::Bucket",
          "ARN": "arn:aws:s3:::XXXXBUCKETNAMEXXXX"
        }
      ],
      "eventType": "AwsApiCall",
      "managementEvent": false,
      "recipientAccountId": "XXXXXXXXXXXX",
      "vpcEndpointId": "vpce-xxxxxxxxxxxxxxxxx",
      "eventCategory": "Data"
    }
  ]
}
```


# S3サーバアクセスログ

S3サーバアクセスログは、Apacheのログのように1リクエストで1行書き出されます。

ログには項目名がなく、値だけがスペース区切りで書かれるので、何が書かれているのか分かりづらいのですが、公式ドキュメントに説明があります。

[Amazon S3 サーバーアクセスログの形式 - Amazon Simple Storage Service](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/LogFormat.html)

S3にログが保存されるまでに少しタイムラグがあるようです。試したときは1時間半ぐらいかかりました。

```
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx XXXXBUCKETNAMEXXXX [06/Jul/2020:13:37:17 +0000] 172.XXX.XXX.XXX arn:aws:iam::XXXXXXXXXXXX:user/xxxxxxxx XXXXREQUESTIDXXXX REST.GET.OBJECT test1.txt "GET /test1.txt HTTP/1.1" 200 - 6 6 12 11 "-" "aws-cli/1.18.68 Python/3.8.1 Linux/4.15.0-1057-aws botocore/1.16.18" - XXXXAMAZONREQUESTIDXXXX SigV4 ECDHE-RSA-AES128-GCM-SHA256 AuthHeader XXXXBUCKETNAMEXXXX.s3.ap-northeast-1.amazonaws.com TLSv1.2
```

1つ目の64文字の項目はバケット所有者の「正規ユーザーID」というものらしいです。

[Your AWS account identifiers - AWS General Reference](https://docs.aws.amazon.com/ja_jp/general/latest/gr/acct-identifiers.html)
CognitoのAPIを直接叩く＠IDプール編

## CognitoのAPIを直接叩く＠IDプール編

### GetId（IDトークン有り）

```http
POST https://cognito-identity.ap-northeast-1.amazonaws.com/ HTTP/1.1
content-type: application/x-amz-json-1.1
x-amz-target: AWSCognitoIdentityService.GetId

{
    "IdentityPoolId": "ap-northeast-1:IdentityPoolId",
    "Logins" : {
        "cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_xxxxxxxxx": "idToken"
    }
}
```

### GetId（IDトークン無し）

```http
POST https://cognito-identity.ap-northeast-1.amazonaws.com/ HTTP/1.1
content-type: application/x-amz-json-1.1
x-amz-target: AWSCognitoIdentityService.GetId

{
    "IdentityPoolId": "ap-northeast-1:IdentityPoolId"
}
```

### GetCredentialsForIdentity（IDトークン有り）

```http
POST https://cognito-identity.ap-northeast-1.amazonaws.com/ HTTP/1.1
content-type: application/x-amz-json-1.1
x-amz-target: AWSCognitoIdentityService.GetCredentialsForIdentity

{
    "IdentityId":"ap-northeast-1:IdentityPoolId",
    "Logins" : {
        "cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_xxxxxxxxx": "idToken"
    }
}
```

### GetCredentialsForIdentity（IDトークン無し）

```http
POST https://cognito-identity.ap-northeast-1.amazonaws.com/ HTTP/1.1
content-type: application/x-amz-json-1.1
x-amz-target: AWSCognitoIdentityService.GetCredentialsForIdentity

{"IdentityId":"ap-northeast-1:IdentityPoolId"}
```

### GetOpenIdToken（IDトークン無し）
※基本フローの許可設定が必要
※許可しないと→のエラーが出る。"Basic (classic) flow is not supported with RoleMappings, please use enhanced flow."

```http
POST https://cognito-identity.ap-northeast-1.amazonaws.com/ HTTP/1.1
content-type: application/x-amz-json-1.1
x-amz-target: AWSCognitoIdentityService.GetOpenIdToken

{"IdentityId":"ap-northeast-1:IdentityPoolId"}
```

### GetOpenIdToken（IDトークン有り）
※基本フローの許可設定が必要
※許可しないと→のエラーが出る。"Basic (classic) flow is not supported with RoleMappings, please use enhanced flow."

```http
POST https://cognito-identity.ap-northeast-1.amazonaws.com/ HTTP/1.1
content-type: application/x-amz-json-1.1
x-amz-target: AWSCognitoIdentityService.GetOpenIdToken

{
    "IdentityId":"ap-northeast-1:IdentityPoolId",
    "Logins" : {
        "cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_xxxxxxxxx": "idToken"
    }
}
```

### GetOpenIdTokenForDeveloperIdentity（独自認証）
※クレデンシャルが必要なので直で行きたい場合、ちゃんとヘッダ付与する必要ある

```http
POST https://cognito-identity.ap-northeast-1.amazonaws.com/ HTTP/1.1
content-type: application/x-amz-json-1.1
x-amz-target: AWSCognitoIdentityService.GetOpenIdTokenForDeveloperIdentity

{
    "Logins" : {
        "provider": "identifier"
    }
}
```

### 関連

[CognitoのAPIを直接叩く＠ユーザプール編](https://qiita.com/k_hoso/items/7896fa2efd6d753de482)
AWS Route53でドメインを移管後、名前解決が失敗するようになった

AWSアカウント間でドメインを移管した後、全く同じレコード設定をしても「IPアドレスが見つかりません」になってしまって、 `dig www.example.com` とかやると

```txt
$ dig www.example.com

; <<>> DiG 9.10.6 <<>> www.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 11843
︙
```

`SERVFAIL` って出て、 `dig +trace www.example.com` とか見てみると、どうやら `example.com` のNSレコードは生きてそうなのにサブドメインでコケてるとか…
([参考](https://aws.amazon.com/jp/premiumsupport/knowledge-center/delegated-subdomain-resolve/))


そんなアナタは、WHOISを見てみると良いことがあるかもしれません

```txt
$ whois example.com

︙
Tech Fax:
Tech Fax Ext:
Tech Email: tech-xxxxxxxx@example.com.whoisprivacyservice.org
Name Server: ns-yyy.awsdns-yy.org
Name Server: ns-yyy.awsdns-yy.co.uk
Name Server: ns-yyy.awsdns-yy.com
Name Server: ns-yyy.awsdns-yy.net
DNSSEC: unsigned
URL of the ICANN WHOIS Data Problem Reporting System: http://wdprs.internic.net/
>>> Last update of WHOIS database: 2020-01-01T00:00:00.000Z <<<

```

`dig +trace` と違うネームサーバーが書かれていたらこれが原因です

```txt
$ dig www.example.com

︙
www.example.com.		7200	IN	NS	ns-xxx.awsdns-xx.com.
www.example.com.		7200	IN	NS	ns-xxx.awsdns-xx.org.
www.example.com.		7200	IN	NS	ns-xxx.awsdns-xx.co.uk.
www.example.com.		7200	IN	NS	ns-xxx.awsdns-xx.net.
;; Received 265 bytes from 208.78.71.31#53(ns-xxx.awsdns-xx.com) in 13 ms
︙

```

Route53のWHOIS情報ページへは [ドキュメント](https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/domain-update-contacts.html) の「ドメインの連絡先情報の更新」に書いてあります

WHOIS情報ページの「ネームサーバーの追加/編集」で、**`dig` で返ってきた方の** ネームサーバーに書き換えてください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147904/fe16d17c-10e4-f388-9cf9-3a8a07e23c7a.png)


いくら調べても出てこなくて丸3日くらい溶かしました :hotsprings:
【LINEWORKS API】postback 設定時にダブルクォート(")をエスケープする方法

最近、割と引っかかってしまったので備忘録的に書いておきます。

# 前置き

LINEWORKS トーク Bot の ListTemplate や ButtonTemplate などでは、ボタンを押した際に postback パラメータを設定することができます。
postback があることにより、どのボタンを押したのかがわかるので Bot コンシェルジュみたいに必要なことを案内したり、アンケート集計みたいなこともできます。

![1597993315.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/46fd3810-150c-6989-02ec-9b5863e23f07.png)

![1597993442.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/990c9113-f1a8-3b91-9e78-3e8a820b3ec8.png)


# エスケープの基本

みなさんご存じだと思うのですが、ダブルクォート(") なんかはプログラムに影響するので、これは文字情報なのだとわかるようにエスケープ処理をします。
基本的に LINEWORKS API では JSON 方式を採用していますので、JSON でのエスケープ同様、バックスラッシュ( \\ ) を使用します。

```js
"json":"fine は\"晴れ\""
```

通常のメッセージなんかは、この書き方でダブルクォート(") を送信できます。

```js
{
  "accountId": "xxx@xxx",
  "content": {
    "type": "text",
    "text": "ダブルクォートだよ(\")"
  }
}
```

![1597994979.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/ddd2cd1b-25de-58db-1aee-1a60e09ff08d.png)

### でも、Postback を設定するときは…

なぜかわからないのですが、Postback ではバックスラッシュ( \\ ) によるエスケープは使えないみたいです。
代わりに、URL エンコードによるエスケープをします。
具体的に言うと、こうですね。

```js
"postback":"fine は%22晴れ%22"
```

なので、Request 時の Body 情報を以下のように書くと、

```js
{
  "accountId": "xxx@xxx",
  "content": {
    "type": "button_template",
    "contentText":"今日の天気は？",
    "actions":[{
        "label":"晴れ",
        "type":"message",
        "text":"晴れ",
        "postback":"fine は%22晴れ%22"
    },{
        "label":"雨",
        "type":"message",
        "text":"雨",
        "postback":"rainy は%22雨%22"
    }]
  }
}
```
![1597993315.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/417ea380-fc0e-fec7-c916-3056c68e3c00.png)

![1597994141.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/9c64c7f0-3119-5da1-a672-6f4c5163c52b.png)

となって、無事にダブルクォート(") が表示されます。
やったね！( ﾟДﾟ)

#おわりに
ここまでお付き合いいただきありがとうございました。

ちなみに、エスケープするためにエンコードが必要な文字は (") (/) (\) の３つだそうです。
Community の投稿を見ていたら、今後のアップデートでバックスラッシュと URL エンコードと、両方のエスケープが使えるようになるそうです。
早く対応するといいですね～。

ではまた！(^^)/

#参考にさせていただきましたm(_ _)m
[LINEWORKS Developers](https://developers.worksmobile.com/jp/document?lang=ja)
[LINEWORKS Developers Community](https://forum.worksmobile.com/jp/)
CognitoのAPIを直接叩く＠ユーザプール編

## CognitoのAPIを直接叩く＠ユーザプール編

### 認証（USER_PASSWORD_AUTH）を許容する必要あり

```http
POST https://cognito-idp.ap-northeast-1.amazonaws.com/ HTTP/1.1
content-type: application/x-amz-json-1.1
x-amz-target: AWSCognitoIdentityProviderService.InitiateAuth

{
    "AuthFlow": "USER_PASSWORD_AUTH",
    "ClientId": "ClientId",
    "AuthParameters": {
        "USERNAME": "username",
        "PASSWORD": "password"
    }
}
```

### 属性設定・更新

```http
POST https://cognito-idp.ap-northeast-1.amazonaws.com/ HTTP/1.1
content-type: application/x-amz-json-1.1
x-amz-target: AWSCognitoIdentityProviderService.UpdateUserAttributes

{
    "AccessToken": "access_token_str",
    "UserAttributes": [
        {
            "Name": "address",
            "Value": "address_value"
        }
    ]
}
```

### ユーザ削除

```http
POST https://cognito-idp.ap-northeast-1.amazonaws.com/ HTTP/1.1
content-type: application/x-amz-json-1.1
x-amz-target: AWSCognitoIdentityProviderService.DeleteUser

{
    "AccessToken": "access_token_str"
}
```

### 関連

[CognitoのAPIを直接叩く＠IDプール編](https://qiita.com/k_hoso/items/7f2763421dd37a5e2cd4)
branch出来ずに困った件

現在初めて共同開発をしており、私のリモートリポジトリを開発メンバーで共有しております。

その中で、メンバーから
>ローカルでブランチを作りpublish branchを押すとforkになる

とのこと。

Fork？？
何故branch出来ない？？

解決すべく色々と調べたことを書いておきます。

## branchとfork
簡単に調べた印象をまとめます。

### branch
* 目的 共同開発
* やっていること 分岐
* 最終的にマージする

### fork
* 目的 既存アプリの改良など
* やっていること コピー
* 最終的にマージしない（できるけど私にしか出来ない）

## 何故branchをpublishできないの？？
私がメンバーを招待していないから
#### 招待方法
githubから
setting→manage access→invite a collaboratorをポチ
username, full name,or emailで検索
出てきたメンバーを招待
メールを受け取ったメンバーが許可。

## まだクローンしてない場合
クローンしてください。
ブランチを作れば publish branch が可能かと思います。

## 既にクローン・フォークしていた場合
恐らくprojectsフォルダ内のアプリのフォルダが作業フォルダになっていると思います。
1. その作業フォルダをデスクトップなどに移動します。
２. projectsフォルダで

```
% git clone https://github.com/***/***.git
```
3.出来たアプリのフォルダに移動して確認

```
% git remote -v
> origin  https://github.com/***/***.git (fetch)
> origin  https://github.com/***/***.git (push)
#urlがクローン元になっていることを確認
```
4.branchを切ってデスクトップ上のフォルダから作業フォルダへ変更したファイルを上書きする。

以上で問題ないと思います。
【Gitコマンド】git stash正しく使えてるう？？【まとめ】

すみません、私は使えてませんでした・・・・
ということで、git stash正しく使っていきましょう。

#ブランチの変更点を一旦、置いておくstash

git stash便利ですよね。
今作業しているブランチから、別のブランチを覗きたいときに、一旦現ブランチの変更点を避けてくれるやつ。よく使ってます。

そんな中ふと、自分の作業中ブランチから、自分の別のブランチで新しいファイルを作成して、最初のブランチに戻ってコミット積んだら、自分の別のブランチで作業していた内容もコミットに含まれていた。。

状況としては、こんな感じ。

```
master---branch1（自分のタスク1）
      |
      |--branch2（自分のタスク2）
```

つまり、branch2でやっていた内容が、branch1にも反映されてコミット内容に含まれていたということ。

原因は、結論、```git stash```は**新規ファイル作成についての変更点は避けることができない**ということだった。

どうしても、新規ファイル作成も避けたい場合は、-uオプションを付ければ良いらしい。

```shell
$ git stash -u
```

#git stashコマンドのまとめ

ここからは、使い方のまとめになります。
流れを落とし込んで正しく使っていけるようにしましょう！


##現在作業中のブランチから離れて、別ブランチに移動したい時

1. 現在作業中のブランチ内の変更を一旦避けて、別ブランチに移動できる状態にする
2. その後、移動し、やることを終えて、変更を避けたブランチに戻る
3. 避けておいた変更点を呼び戻す


###現在作業中のブランチ内の変更を一旦避けて、別ブランチに移動できる状態にする

```shell

# 変更を避けておく
$ git stash

# 新規ファイルも退避対象に含める
$ git stash -u
```

###避けておいた変更点を呼び戻す

```shell

# 直近のスタッシュをカレントブランチに適用する + スタッシュを残す
$ git stash apply

# 直近のスタッシュをカレントブランチに適用する + スタッシュを削除する
$ git stash pop
```


##特定の避けたスタッシュを呼び戻したい

1. スタッシュ一覧を表示する
2. スタッシュ番号を指定して、適用する


###スタッシュ一覧を表示する

```shell

# スタッシュリストを表示
$ git stash list

# スタッシュ番号: WIP on work/ブランチ名: 親コミットID コミットメッセージ

stash@{0}: WIP on work/Signup: 789ijkl third commit
stash@{1}: WIP on work/Login: 456efgh second commit
stash@{2}: WIP on work/add-rubocop: 123abcd first commit
```

###スタッシュ番号を指定して、適用する

```shell

# 直近のスタッシュをカレントブランチに適用する + スタッシュを残す
$ git stash apply stash@{0}
$ git stash apply

# スタッシュ番号1を指定して、カレンとブランチに適用 + スタッシュを残す
$ git stash apply stash@{1}

# スタッシュ番号2を指定して、カレンとブランチに適用 + スタッシュを削除する
$ git stash pop stash@{2}
```


##スタッシュを削除したい

```shell

# 直近のスタッシュを削除
$ git stash drop stash@{0}
$ git stash drop

# スタッシュ番号1を指定して削除
$ git stash drop stash@{1} 

# すべて削除
$ git stash clear
```
magicleap入門-projectのコピーを作りたい

# はじめに
magicleapをunityで開発するにあたってunityプロジェクトのセットアップが必要でした．これを毎回行うのは手間なのでセットアップのみ準備したたプロジェクトを用意しようとしました．そのためにはいくつか手順を踏む必要があったのでメモします．

# これは何をやりたいのか
自作のmagicleap用のテンプレートを用意します．

# 大まかな流れ
1. プロジェクトファイルのコピー
2. 名前の変更
3. 一時ファイルの削除

# プロジェクトファイルのコピー
プロジェクトを複製します．このとき，複製するものはコピーしたいプロジェクト名のついたフォルダを丸ごとコピーします．

# 名前の変更
名前が被らないようにします．

# 一時ファイルの削除
特別な手順はこれだけです．unityのプロジェクトファイルには**プロジェクト名.sln**，**プロジェクト名.csproj**という一時ファイルのようなものが生成されるようなので削除します．これはプロジェクトを開いたときに生成されるものなので削除しても問題ないようです．プロジェクト固有のものなので別のプロジェクトとして開いたときに悪さをするものです．

エディタによってはuserprefsファイルも生成されるようなので同様に削除しておきます．

# 参考にしたもの
1. [完成したUnityプロジェクトを再利用しよう！プロジェクト丸ごとコピー術](http://bumpy-game.jp/live/unity_project_copy/)
slim-lintで怒られslimで改行したい時に便利な大括弧

# slim-lintで改行を求められた時に大括弧で解決する

普通に1行で書いてしまうと、余裕で怒られてしまう。

```slim:index.html
.conversion-button#conversion001 data-event-category="売り上げ追加：CV" data-event-action="資料ダウンロード" data-event-label="資料ID001" width="300" height="250" data-slot="/banner001" type="doubleclick"
```

大括弧を使うことで、みやすく自由に改行できるようになります。

```slim:index.html
.conversion-button#conversion001[
  data-event-category="売り上げ追加：CV"
  data-event-action="資料ダウンロード"
  data-event-label="資料ID001"
  width="300" height="250"
  data-slot="/banner001" type="doubleclick"]
```

slim-lintで怒られた時は大括弧優秀ですね。美しい。
初心者でもgemの修正依頼したら直してくれた話

たまには感想的なこともメモ。

## 経緯
amazonの書籍検索に使うためのgemを使っていたところバグを発見
↓
若干ビビりながらもgithubから修正を依頼する
↓
一瞬で直してくれた(^○^)

ちなみに書籍検索のやり方は記事にしてるので気になる方は[こちら](https://qiita.com/koki_73/items/da9f2ed01aadd6394702)をどうぞ

## 感想
amazonの書籍検索は0から自分で実装すると少々面倒くさそうだったので、なんとかgemを使いこなそうと奮闘していました。

バグに気づいて開発者に報告した方が良いよなーと思う一方で
**「実は自分の使い方が間違っているかも…」**とか**「英語でうまく伝わるか…」**
などと思って少しビビっていました。
（なんせ開発者のプロフ画像がもろ外国人）

とはいえ直してもらえたらこっちとしても使いやすいし、自分が間違っていたとしてもある意味経験になるだろうということで、英作文はGoogle先生に頼りながら報告をしました。

どんな回答がくるかなーとドキドキしてたら、1時間ほどで修正されて「バグ報告ありがとう」的な回答がきました。

対応早すぎて「SUGEEEEE!!!!!」ってなりましたね笑

githubで海外の人とやり取りするなんてまだまだ先のことだろうと思っていましたが、案外うまくいって良い経験になりました。

## やり取りした履歴
こちらのページに飛ぶとどんなやりとりしたか見れます。
少し恥ずかしいですが参考にしてください笑
https://github.com/dkam/paapi/issues/6#issuecomment-678065606
【Nuxt.js】複数ページでパラメータ利用を試してみた【勉強２】

## はじめに

自分が勉強した内容のまとめなので、正確性は保証しません。

[こちらのサイト](https://moneyhack.tech/06-nuxt/)にcodesandboxを埋め込んでいます。

実際の振る舞いを見ながらコードの確認ができるので非常に便利です。

https://moneyhack.tech/06-nuxt/

シンプルにcodesandboxめちゃくちゃおすすめなので、気になる方使ってみてください。

## パラメータ利用とは

パラメータを利用したページとは、同じ vue ファイルのページでも、

URL によって見た目が変わってくるページです。

[まずは実際の振る舞いを確認して、イメージを膨らましてください。](https://moneyhack.tech/06-nuxt/)

以下、サンプルで作成したコードの解説です。

Home Page から 3 つのリンクを載せています。

この 3 つのリンクは URL は異なりますが、同一の Vue ファイルにアクセスしています。

pages フォルダの構成は次のようになっており、アクセス先は welcome/\_user.vue です。

    pages
        welcome
            _user.vue
        index.vue
        README.md

## パラメータを利用したページの作り方

作り方自体は、フォルダ構成とファイル構成を意識すれば簡単に作成することができます。

サンプルのように、単一のパラメータを利用したい場合は、

好きな名前のフォルダと\_（アンダーバー）付きの Vue ファイルを用意します。

    xxxフォルダ
        _yyy.vue

複数のパラメータを設定したい場合は、パラメータの数だけ\_（アンダーバー）付きのフォルダを追加します。

2 つのパラメータを設定したい場合は次のようなフォルダ構成となります。

    xxxフォルダ
        _yyyフォルダ
            _zzz.vue

## パラメータの受け取り方

URL に設定されたパラメータは次のコードで取り出すことができます。

    this.$route.params.設定したパラメータ名

会員制のページなどでは、

ようこそ〇〇様みたいな形でパラメータが取り出され、利用されています。

URL に表示されるため、password などを渡すのに使うのはおすすめ出来ないかもしれません。

## おまけ（method と computed の使い分け）

クリック等で呼び出される場合は method、

呼び出されずに変更があった場合に変更を加えたい場合は computed を使います。

## おわり

パラメータの使い方について学びました。

複数人向けのサービスを作るとなると、意外と使う場面は多く出てくると思います。

積極的に活用していきましょう。

お疲れ様でした。
【Swift】Decodable(Codable)でparseエラーになる条件まとめ

仕事してて混乱してしまったので、整理します。

# サンプル
基本はこんな使い方をしますよね。

```swift
struct Sample: Codable {
    let name: String
    let age: Int
}
```

```json
{
    name: "Tommy",
    age: 20
}
```

今回はparseエラーになる条件を整理します。
（そもそもデータをLoadできてないなどのエラーについては扱わず、parse自体は行ったが、エラーになったケースだけにしぼります）

# parseエラーになる条件
- キー名が不一致
- 型情報が不一致
- 非オプショナルで指定した値が存在しない

# キー名が不一致
```swift
struct Sample: Codable {
    let name: String
    let age: Int
}
```

```json
{
    user_name: "Tommy",
    age: 20
}
```

API担当者とちゃんと認識合わせしましょう、以上なんですが、
Swiftのルールとサーバーサイドの命名ルールが合わなくて苦しむこともあると思うので、そういうときは無理に統一せず、`CodingKeys`を使いましょう。

```swift
struct Sample: Codable {
    let name: String
    let age: Int

    enum CodingKeys: String, CodingKey {
        case name = "user_name"
    }
}
```

# 型情報が不一致
JSONの型と想定している型が不一致だとparseに失敗します。

```swift
struct Sample: Codable {
    let name: String
    let age: Int
}
```

```json
{
    name: "Tommy",
    age: "20"
}
```

# 非オプショナルで指定した値が存在しない
こういうことです。

```swift
struct Sample: Codable {
    let name: String
    let age: Int
}
```

```json
{
    name: "Tommy",
}
```

あったりなかったりするキーはオプショナルにすると、キーがなかったときはnil扱いでparse成功します。
欠落する可能性がある要素は認識合わせときましょう！！！

```swift
struct Sample: Codable {
    let name: String
    let age: Int?
}
```

# parseエラーになりそうだけどイケる例
- オプショナルで指定したキーに対する値がnull
- キーの順序がランダムに返る

# オプショナルで指定したキーに対する値がnull
```swift
struct Sample: Codable {
    let name: String
    let age: Int?
}
```

```json
{
    name: "Tommy",
    age: null
}
```

小文字nullはJSONでNULL値を表す正式な記法なので、Codableでもちゃんとnil扱いにしてくれます。
ただAPI側でもNULL値の表現として、

- null
- キー自体を欠落
- （Stringなら）""
- (配列なら)[]

などの選択肢があるので、欠損時にどう突っ込むかはやはりAPI側と認識を合わせたいですね。

# キーの順序がランダムに返る
今回僕がこの記事を書くきっかけになったのがこのケースでした。
漠然と順不同だと思っていたのですが、デバッグ中にコケた原因が順序っぽかったので、「Codableって順序性見るんだ〜」と誤認しました。
（よく確認したら、順番なおす過程でプロパティ名も修正していて、そっちが効いた模様）

当たり前過ぎるのか、ドキュメントに明示的に書かれてなくて、混乱しました。
結論的には順不同です。

```swift
struct Sample: Codable {
    let name: String
    let age: Int
}
```

```json
{
    age: 20
    name: "Tommy",
}
```

# まとめ
まとめると、parseエラーになる条件は下記の三つです。

- キー名が不一致
- 型情報が不一致
- 非オプショナルで指定した値が存在しない

故にAPI担当者と認識合わせないといけないのは、キー名、型名、NULLがあるか/どう表現するか。
他にもこんなケースあるんじゃない？　というのがあれば補足お願いします！
とにかくすぐに自然言語の分類を行う[simpletransformer , transformer]

# とにかく最低ラインの自然言語(text)の分類を行いたい

前処理や単語のベクトル化等を行わずに学習および推論を行う方法の紹介、精度はそこまで高くない場合が多いです。

# simpletransformer
pythonのパッケージで自然言語系のあれこれを簡単にできるように実装されています。

### インストール
pandas等の基本的なものは入っている前提で書いています、またcondaでもpipでも両方行うことができます。

#### pytorchのインストール
pytorchが既に入っている場合には以下の手順は飛ばしてください。
gpuの場合

```
pip install pytorch>=1.6 cudatoolkit=10.2 -c pytorch
```

cpuのみ

```
pip install pytorch cpuonly -c pytorch
```

#### simpletransformersのインストール
simpletransformersはcondaではできないと思います。

```
pip install simpletransformers
```

#### オプション(wandb)のインストール(任意)
web上で学習の可視化を行う用のwandbのインストールです、なくても動くのでいらない人は飛ばしてください。使い方等は記述しません。

```
pip install wandb
```

# 使用方法
使用にはpandasのdataframeにテキストとそれに対応するラベルが格納されているという想定で行います。

pandasのtextが書かれているcolumnの名前を”text”、labelが書かれているcolumnの名前を”label”に変更。

#### 各paramの設定
```python
params = {
    "output_dir": "out_models/bert_model/",
    "max_seq_length": 256,
    "train_batch_size": 128,
    "eval_batch_size": 128,
    "num_train_epochs": 10,
    "learning_rate": 1e-4,
}
```

output_dirには任意のディレクトリを指定してください。学習した際に作成したされたモデルの保存先ディレクトリとなります。

#### 学習に使用するコード
```python
from simpletransformers.classification import ClassificationModel

model = ClassificationModel(“bert”, “bert-base-cased”,num_labels=10, args=params, use_cuda=True)

model.train_model(train_df)
```

“bert”には使いたいモデルの各名前、”bert-base-cased”には使いたい事前学習済みのモデルの名前を入れます。学習済みモデルと各名前は[こちら](https://huggingface.co/transformers/pretrained_models.html)で参照してください。
num_labelsはラベルの数ですラベルは0からスタートする様に整形してください。
train_dfは”text”と”label”のcolumnsで作成されているdataframeです。

#### 推論方法
学習用のdataframeと同じ形式をとっているtest用のdataframeがあること前提です。

```python
pred, _ = model.predict(test_df['text'])
```

predに予測されたラベルが出力されます。

# まとめ
simpletransformersのドキュメントは[こちら](https://simpletransformers.ai/)になります。他にも機能が多くあるようなので使用してみてください。前処理、後処理などは重要なものなので今回に無視するとあまり精度が期待できないことを忘れないでください
だれでもオリジナルのニュースが作れる「素人ニュース」をリリースした。(個人開発)

今回は素人ニュースというwebアプリを公開しました。誰でもオリジナルニュースが作れると言うものです。今回もいつもどおり開発途中の出来事を紹介します。
↓素人ニューストップページ
https://amateur-news.herokuapp.com/

##使った技術
rails6
heroku hobbyプラン(freeだとスリープするのがつらい)
**NewsAPI**
ドメインは取得してません。

使ったgem（一部省略してあります）

```
gem 'ridgepole'
gem "jquery-rails"
gem 'image_processing', '~> 1.9.3'
gem 'carrierwave'
gem "devise"
gem 'kaminari'
gem 'bootstrap'
gem 'devise-i18n'
gem 'devise-i18n-views'
gem 'omniauth-google-oauth2'
gem 'omniauth-twitter'
gem 'dotenv-rails'
gem 'activeadmin'
gem 'rails-i18n'
```

今回始めて使ったgemなどはありません。ただ今回は**NewsAPI**について書こうと思います。

##紹介

###できること

オリジナルニュースが投稿できる。
デマだと思ったら通報することもできる
フォローして特定の人の記事だけを読むこともできる
タグ機能があるので好きなものだけ見れる

![newstop3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480294/5fe75645-075b-b4ac-71f5-e12af60217c9.png)


トップページ（開発環境での画面です。）上方は素人ニュースのサンプルで下方がNewsAPiで取得したニュースです。

##YahooニュースのRSS

NewsAPIに入る前に少し話したいことがあります。実は最初RSSを利用しYahooニュースを載せようとしてました。ただ実装したあとに「著作権ダイジョブなのかな？」と思いqiitaでこんな質問をしていました。

[自分のサイトにrssを利用してyahooニュースを掲載したら著作権違法なのか](https://qiita.com/VXNlci00ODAyOTQ=/questions/4c1d6e2bc46b04c6a38e)

そしたらいろいろな回答が来ました。切り取ると

・「Yahoo! ニュースの場合、「黒」か「白」かと言ったら、限りなく黒に近いグレーですが、黒ではありません。ただ、見る人によってはブラックです。」
・「法律はどう解釈できるようにもなっているので一概にいえない」
・「それは裁判が決めることなので判例をみて考えるしかない」
・「基本的にはその RSS の提供元が示している利用規約に従うのが無難」
・「判例を元に資格のない人がアドバイスすると違法になります。」

ということでした。一概には言えないということでしたが読んでみると結構ためになる部分がありましたのでぜひ自分で回答を読んでみてください。
それで自分も色々調べたのですがこのような記事を見つけました。

[RSSでの記事取得、掲載について著作権上の問題はありますでしょうか。](https://www.bengo4.com/c_23/b_858104/)

回答は
・「著作権（複製権）侵害の恐れが生じます。」
とのことでした。ただ最後に「著作権法上の問題については、複雑になってきますので、顧問弁護士の方とも相談しながら進められていかれればと思います。」と書かれていました。やはり複雑な問題のようです。

こうして出た結論は**掲載をやめるでした**。勇気を出して載せて見ようとも考えましたがまだ中学生なのでなんかあったら親にも迷惑がかかります。このアプリはyahooニュースがメインではないしリスクが大きすぎるのでやめることにしました。

##NewsAPI

それでもやっぱりなんか載せたいなーと思っていたら[NewsAPI](https://newsapi.org/)という物を見つけました。無料でニュースのデータを取得できるというものでした。rubyにも対応してる。「完璧じゃん！！」と思って早速実装しようとしてみましたが、日本語の参考サイトがあまりにもないんです。あってもすべて取得するとこまででjsonデータをhtmlに表示するところがありません。これはまた記事にしますが本当に困りました。teratailで２回も質問してなんとか実装しましたが3,4日位かかってしまいました。メインの機能でもないところに...。今度絶対にNewsAPIの記事（取得から表示まで）を書きます。一応自分のteratailの質問載せときます。

[News-Apiを使ってニュースを保存したいがNoMethodErrorが出る](https://teratail.com/questions/284878)
[Jqueryでjsonデータをhtmlに表示したい](https://teratail.com/questions/285032)

なにかの参考に

##まとめ

。一つ言えることは[素人ニュース](https://amateur-news.herokuapp.com/)お願いします。

追記：トップページのデザイン変えました
追追記：NewsAPIの使い方の記事書きました。[NewsAPIを使い簡単にニュースサイトを作る](https://qiita.com/UTOG/items/f6438420e81b6488a508)
追追追記：（前前前世みたいになってる...）トップページのデザインを再度変更しました。
【ActiveReports】ファイルまたはアセンブリ'xxx'、またはその依存関係の一つが読み込めませんでした。エラーの解決方法

# はじめに

こんにちは。
突然ですが、ActiveReportsって便利ですよね。
複数のレポートデザインが用意されていて開発も簡単にできるので、帳票を作成する際はよく使用しています。

そんなActiveReportsですが、ある日、実行環境でテストを行ったときにエラーが出て解決に時間がかかったため、エラー内容と解決方法について記録しておきたいと思います。

# エラー内容
「ファイルまたはアセンブリ'xxx'、またはその依存関係の1つが読み込めませんでした。指定されたモジュールが見つかりません。」

# 解決方法
「ファイルまたはアセンブリ'xxx'、またはその依存関係の1つが読み込めませんでした。」エラーは、主に`ランタイムファイルの配置忘れ`や、`アプリケーションの参照しているランタイムファイルのバージョンと配置したランタイムファイルのバージョンが一致していないこと`が原因として考えられるみたいです。
![ランタイムファイル.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688106/2e637b71-cb7e-14ca-35fd-b4ac4abcd472.jpeg)
↑ランタイムファイル

しかし、今回は実行環境にランタイムファイルは配置してあるし、バージョンも一致していました。どうして……と悩んでいたところ、ランタイムファイルのサイズが`0KB`になっていることに気づきました。USBに貼り付けた際に破損してしまったっぽい:sob:

もう一度ランタイムファイルをUSBに貼り付けて実行環境に配置したところ、うまく動作しました:blush:

#さいごに
まさかランタイムファイルが破損しているなんて考えもしなかったので、ちゃんと確認しないといけないなと感じました。

【参考サイト】
[GrapeCity - ナレッジベース](https://dev.grapecity.co.jp/support/kb/detail.asp?id=31591)
Unity 3D入門 #16 [シーンの遷移&ボタンの配置]

https://bibinbaleo.hatenablog.com/entry/2017/10/08/161733 を参考に、Sceneをフェードアウトしながら変更するようにしました。
上のリンクにも明記してありますが、フェードアウトpackageを配布しているサイトはhttps://github.com/naichilab/Unity-FadeManager/blob/master/README.ja.md で、左のサイトからZIPファイルをダウンロードします。

詰まったところとして、FadeManager.unitypackage をUnity3Dプロジェクトにインポートするにはファイル名をダブルクリックで良いことが分からず、時間を使ってしまいました。


ボタンの配置についてhttps://qiita.com/2dgames_jp/items/b3d7d204895d67742d0c を参考にしました。

onClickの処理に関して、関数を書いたスクリプトをアタッチするだけでは動かず、Buttonオブジェクトで設定をしなければならない点は注意が必要です。
AWS Glue Job実行時にデータ重複を避けたい(めっちゃ簡単)

#はじめに
業務でAWS Glueを触る機会があり、
『Glue Job実行でデータ重複を避ける方法』で困ったので備忘録として残しておきたいと思います。


#対象ケース

- GLue Jobでデータソースから定期的に最新データを取得したい


以下具体例です。
RDSからGlue Jobで最新データを取得し、S3に保存。
保存データはQuickSight、Athena、SageMakerなどに使用する。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593135/23307e44-aad2-70e0-be2c-ae8f9b93daf9.png" width=75%>

#本題
今回の目的である
「Glue Job実行時にデータ重複を避ける」方法は実はいくつかありますが、
今回ご紹介するもの以外の方法は、
一定の制約があるものや、SQL文の追加が必要だったりして少し複雑です。
(と自分は思っちゃいました。自分の技術不足なだけかもしれませんが。。。)

###原因
データ重複が起きる原因としては、**前回Job実行時のデータがS3に残っている**ということです。

###思いついた解決方法
Glue Job実行のタイミングでS3のデータ全消しして丸ごと最新データに置き換えればいいじゃん！！

図に起こすとこんな感じです。
1.まずはGlue JobがS3バケットにアクセスして過去データを消去します。
<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593135/330a5fa7-3638-3470-d8d7-9ac90c93e087.png" width=60%>

2.Glue JobがRDSにアクセスしデータを取得、
　取得データを空になっているS3バケットに保存する。
<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593135/0dcb942c-86a8-e67e-462c-5cf5d30de9e2.png" width=60%>


これでS3内はRDSから取得したての最新データのみになり、
その後の接続先からも最新データを扱えるということになるわけです。

###手順
前置きが長くなりましたが、実際の手順をご紹介します。
タイトル通りめっちゃ簡単です。
**Glue Jobスクリプトにpurge_s3_pathの１行を追加する**だけです！

1.Glue Jobのスクリプト編集ページを開きます。
　
2.スクリプト内から以下コードを見つけてください。

```
sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
```

この部分に

```
purge_s3_path(s3_path, options={}, transformation_ctx="")
```

を追記してください。
作業はこれで完了です。
ちなみに
purge_s3_pathのパラメータについてはこんな感じです。(公式ドキュメントから引用)

- s3_path – 削除するファイルの Amazon S3 のパス（s3://<bucket>/<prefix>/ 形式）

- options – 削除するファイルとマニフェストファイルの生成のためのファイルをフィルタリングするオプション。

 - retentionPeriod – ファイルを保持する期間を時間単位で指定します。保存期間より新しいファイルは保持されます。デフォルトでは 168 時間（7 日）に設定されています。

 - partitionPredicate – この述語を満たすパーティションは削除されます。これらのパーティションの保存期間内のファイルは削除されません。デフォルトでは "" – 空に設定されます。

 - excludeStorageClasses – excludeStorageClasses セット内のストレージクラスを持つファイルは削除されません。デフォルトは Set() – 空白のセットです。

 - manifestFilePath – マニフェストファイルを生成するためのオプションのパス。正常にパージされたすべてのファイルが Success.csv に記録され、失敗したファイルは Failed.csv に記録されます。

- transformation_ctx – 使用する変換コンテキスト (オプション)。マニフェストファイルパスで使用されます。

- catalog_id – アクセス中の データカタログ のカタログ ID（データカタログ のアカウント ID）。デフォルトでは、None に設定されています。None のデフォルト値は、サービス内の呼び出し元アカウントのカタログ ID になります。


#最後に
今回はGlue Job実行時のデータ重複を避ける方法についてめっちゃ簡単な方法をご紹介しました。
どなたかのお役に立てていれば幸いです。
お読みいただきありがとうございました。
FirebaseErrorの解決法 (備忘録)

## あらすじ
先日、React NativeとFirebaseでアプリを作成していたら、こんなエラーに遭遇しました。
![スクリーンショット 2020-08-21 14.54.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669290/b50bd62c-5a0c-8614-9ffb-7f54b705fb2c.png)
##　Errorの理由
Firebaseのinitialize methodが何度も呼び出されているからです。
##　解決方法
FirebaseのinitilizeをこのIF文で囲みましょう。

```App.js
// Initialize Firebase
if (!firebase.apps.length) {
  firebase.initializeApp(firebaseConfig);
}
```
seleniumのChromeドライバーでバージョンエラーが発生した場合の対処方法

# 概要
selenimでChromeドライバーを使用している場合、Chromeのバージョンアップの関係で

`Message: session not created: This version of ChromeDriver only supports Chrome version [XX]`
※[XX]は任意のバージョンの数値

のようなエラーが発生する場合あがある。
回避方法の手順を簡単にまとめる。

# 手順

## 共通設定

1、 Chromeのブラウザを立ち上げ、Chromeのバージョンを確認する
2、 設定からChromeのバージョンを確認する
　　※下記のURLを叩くでもOK
　　chrome://settings/help
![設定 - Chrome について 2020-08-21 14-28-39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445229/494ea8c7-7b55-1672-ea47-7e3c3252f015.png)

## chromedriver-binaryを利用している場合

▼Chromedriver
https://pypi.org/project/chromedriver-binary/

1、 Navigationの一覧から「Release history」を開く
![chromedriver-binary · PyPI 2020-08-21 13-56-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445229/5e1d7ff0-033a-68ad-0102-9f1f371ab080.png)
2、 「Release history」の一覧からChromeのバージョンと同じ or 近いバージョンのリンクを開く  
　　※今回は84.0.4147.30.0を選択する
![chromedriver-binary · PyPI 2020-08-21 14-33-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445229/35fb6013-9360-010a-22be-cc4248cb4855.png)
3、 画面上部のpipコマンドを取得(コピー)する
4、 ターミナル(コマンドライン)を開く
5、 chromedriver-binaryをアンインストールする

```
pip uninstall chromedriver-binary
```
6、 取得したコマンドで再インストールする
　　※下記は84.0.4147.30.0のコマンド

```
pip install chromedriver-binary==84.0.4147.30.0
```

  →これでpythonの処理を実行してエラーが発生しなければOK

## chromedriverをダウンロードしている場合

▼ChromeDriverのダウンロードページ
http://chromedriver.chromium.org/downloads

1、 ChromeDriverのダウンロードページを開き、Chromeのバージョンと同じ or 近いバージョンのリンクを開く
　　※今回は84.0.4147.30.0を選択する
![Downloads - ChromeDriver - WebDriver for Chrome 2020-08-21 15-03-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445229/deac6e33-2554-f0b0-f2a8-50f0560fadfe.png)
2、 利用環境のOSに合わせたzipファイルをダウンロードする
![https:chromedriver.storage.googleapis.com:index..png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445229/bd16d094-c489-4c19-af4d-a8709ca561d1.png)
3、 ダウンロードしたChromeDriverを既存のChromeDriverと置き換える

  →これでpythonの処理を実行してエラーが発生しなければOK
ASP.NET Core のStartup.csのConfigureメソッド内でDBを使うとき

#経緯
　StartupのConfigureの処理中に、DBの内容を参照したい。
　具体的には初回起動時にDBのシステム設定のテーブルが空なら、初期設定画面に強制遷移したい。その為にDBが見たかったのですが、ちょっと引っかかってしまったので、備忘録として書いときます。
　まあ、引っかかってる人がいれば参考になるか、もっといい方法があるぞとか教えてください。

#実装
　Startup.csでDBが以下の様に登録されている場合。(Npgsqlになっているのはご愛嬌)

```C#:Startup.cs

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseNpgsql(
                    Configuration.GetConnectionString("DefaultConnection")));
        ...
        }
```

　同じくStartup.csのConfigureメソッドでDIを利用して以下のように記述して使おうとすると

```C#:Startup.cs
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ApplicationDbContext dbContext)
        {
            if(dbContext.Settings.Count() == 0)
            {
                // 初期設定できてないので初期設定画面を表示
                context.Response.Redirect("/Initialize");
                return;
            }
        ...
        }
```

　実行時に以下のようなエラーメッセージが表示されてしまいます。

ObjectDisposedException: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'ApplicationDbContext'.

　オブジェクトはありそうですが、中のDB接続が破棄されてるみたいです。
　引数「IApplicationBuilder app」から取得する必要がありそうですが、なかなかそういった記事が見当たらないので試してみたところ、

```C#:Startup.cs
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            var dbContext = app.ApplicationServices.CreateScope().ServiceProvider.GetRequiredService<ApplicationDbContext>();

            if(dbContext.Settings.Count() == 0)
            {
                // 初期設定できてないので初期設定画面を表示
                context.Response.Redirect("/Initialize");
                return;
            }
        ...
        }
```

　とするとうまくいきました。
　分りにくかったのは、app.ApplicationServicesにも「GetRequiredService<>」メソッドがあるのですがこちらでは取得できません。上記の様にスコープを作ってそこのサービスから取得しないといけない様です。

　とりあえずこれでできたのいいのですが、こうすべきというやり方があればコメントください。
Deviseを導入した際のエラーの対処法！

##devise導入の手順
1.Gemファイルに記述する

```ruby:Gemfile
   gem 'devise'
```

2.ターミナルで　bundle install

3.rails g devise:install　コマンド
追加したdeviseというgemの設定関連ファイルが自動で作成されます。

4.rails g devise user

5.rails db:migrate

------
###rails g devise:installコマンドを間違って入力してしまった!
今回のエラーとしては、rails g devise installと誤って入力してしまい
":"をつけ忘れました！
その結果、
installモデルなどが作成されてしまい、
その後rails g devise:install　コマンドを正しく入力しても以下のエラー文がでます。

<エラー文>

```
method_missing': undefined method `devise' for Install (call 'Install.connection' to establish a connection):Class (NoMethodError)
```

###対処法
bundle installの直前の処理まで戻す必要があります！
以下の順番で進めて行きます。

1.routes.rbに記載してある`devise_for: installs`というコードの記述を削除

2.`rails db:migrate:status`コマンドでデータベースの状況を確認します
　　upになっている場合　→ `rails db:rollback`
   　※downになってる場合はそのまま次の作業に移ります

3.`rails d model install`を実行
モデルを作成した際に作成された全てのファイルが削除されます。

```
Running via Spring preloader in process 6570
      invoke  active_record
      remove    db/migrate/20200821050217_create_installs.rb
      remove    app/models/install.rb
      invoke    test_unit
      remove      test/models/install_test.rb
      remove      test/fixtures/installs.yml
```

※removeと表示されていればokです！


これでbundle installの直前の処理まで戻せました！

###このあとの処理の流れ
1.`rails g devise:install`を実行

```
Running via Spring preloader in process 6597
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
```

2.`rails g devise user`コマンドを入力



これで正しくdeviseが導入でき、deviseのuserモデルを作成できました◎
【Unity】iOSのHome Indicatorを常に半透明にする

#HomeIndicatorを隠したい
HomeIndicatorを隠して画面をスッキリさせたい。
ただ困ったことに、HomeIndicatorは、非表示の設定にしても画面をタップすると表示される仕様のようです。
そこで、半透明にして目立たなくするようにしてみました。
![HomeIndicator.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535406/b2af0ffd-84ad-eb54-687f-78331e6c029a.gif)
半透明の場合、スワイプが入力されるまで半透明を維持します。

#HomeIndicatorを半透明にする
Unityの「Project Settings」→「Player」の「Other Settings」に「Hide home button on iPhone X」という項目があります。これを有効にするとHomeIndicatorを非表示にできますが、上記で述べたようにタップすると表示されてしまうので、**無効**になっているか確認してください。
![スクリーンショット 2020-08-21 14.48.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535406/fd4990a1-46ea-22bb-7e9e-f7b5b0ef90a9.png)
ついでに、上の項目の「Defer system gestures on edges」の「Bottom Edge」を有効にしておきます。これで、画面下端を2回スワイプしないとHomeIndicatorのアクションが実行されないようにできます。必須ではないですが、誤操作防止のためにやっておくといいでしょう。

ビルドし、XCode上で「UnityViewControllerBase+iOS.mm」を書き換えます。

```UnityViewControllerBase+iOS.mm
- (BOOL)prefersHomeIndicatorAutoHidden
{
    //return UnityGetHideHomeButton();
    return NO;
}
```
prefersHomeIndicatorAutoHiddenでNOを返すとHomeIndicatorが半透明になります。
ちなみに、trueを返すと非表示、falseを返すと表示されるようになります。

以上で、HomeIndicatorを半透明にできます。
【個人アプリ開発作業メモ】小数点第1位での入力を可能にする実装


修正する箇所は２箇所。
・投稿するところ。
・最初のユーザー情報入力のところ。

まず投稿する方から。

https://qiita.com/suzy1031/items/7b182f6b126475c69ff6
こちらの記事を参考に進めていく。

```ruby
= f.number_field :calorie, placeholder: '例）200'
```
このようなnumber_fieldでは整数での入力しかできない。

```ruby
= f.number_field :calorie, step: '0.1',placeholder: '例）200'
```
`step: '0.1'`を追加することで小数点第1位まで入力可能になるらしい。


次にカラムの型を変更する。

マイグレーションファイルを作る。

```ruby:ターミナル
rails g migration change_data_calorie_to_post
```

```ruby:
class ChangeDataCalorieToPost < ActiveRecord::Migration[5.2]
  def change
    change_column :posts, :calorie, :float
  end
end
```
float型に変更するという記述を書いて、これで
rails db:migrate
する。

これでOK。
あとはこれと同じことを、他の項目でも設定していく。
![スクリーンショット 2020-08-21 午後3.02.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547640/84db3005-0b30-2545-4c32-47536ca3f0b0.png)
ちゃんと小数点第1位までで投稿できるようになりました。

あとは最初のユーザー情報入力のところ。

体重、体脂肪率、除脂肪体重、カロリー、タンパク質、脂質、炭水化物の入力フォームにも
step: 0.1
を追加した。

あとはそれらの情報を保存するためのstandardsテーブルのカラムの型をinteger型からfloat型に変更する。

![スクリーンショット 2020-08-21 午後3.22.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547640/b7cb3d48-959e-e9ec-aa4d-6d43ce57c5c8.png)
この通り小数点でも保存できるようになりました。
スプレッドシートを学べるスプレッドシートを作りました

スプレッドシートやエクセルの関数をなんとなく知ってるけど実はあまり使えないという人のために、よく使う関数に特化して知識を学べる問題付きのスプレッドシートを作りました。

まだ、執筆中＆改善予定なのですが、もしかしたら誰かの役に立つかもしれないと思い先行公開しました。

[エクセルマスターへの道](https://docs.google.com/spreadsheets/d/1Ux7AflOFJWnJjoe-dU6lzi2MgR1BctmcDNNLg-dEaVg/edit?usp=sharing)

※基本的にスプレッドシートをベースにしていますが、わかりやすさのためにタイトルにはエクセルの名前を使いました。

このスプレッドシートを使って勉強したい人は、自分のGoogleドライブにコピーして使ってくださいね。
誤字脱字などあるかもしれませんが、まだ執筆中ということもありご容赦くださいませ。
メモ：tmpwatch使わずに/tmp下を定期削除

この記事は
===

* 完全なる個人メモです

メモ
===

* /tmpの下にゴミが溜まってくるので日付が古くなったものは自動削除したい！
* ふつうはtmpwatchを使うんだけど、alpineとかdocker使い捨て前提みたいなOSには存在しない！
* で、なんとfindコマンドで実行できることがわかったのでメモっておく

```
find /tmp -mtime +7 ! -type d -delete
```

終わりに
===

* find無敵だな
tkinterの勉強のとき参考にしたもの

## 背景
pythonをちょっとやった程度の人が、GUIアプリケーションを作らなければならなくなったので勉強したが、情報集めに存外苦労したのでメモとして残しておきます。

## 書籍
これが案外少ない、tkinterにちょっとだけ触れている本ならかなりあるのだろうが、表題になったりして専門的に扱っている和本がamazonだと数冊くらいしかなかった。

[PythnをおぼえたひとがGUIアプリケーションを開発するためのtkinter速習入門](https://www.amazon.co.jp/Python%E3%82%92%E3%81%8A%E3%81%BC%E3%81%88%E3%81%9F%E4%BA%BA%E3%81%8CGUI%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA%E3%82%92%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AEtkinter%E9%80%9F%E7%BF%92%E5%85%A5%E9%96%80-%E6%A8%99%E6%BA%96%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%81%A7GUI%E4%BD%9C%E6%88%90-%E8%BE%9B%E5%B3%B6%E4%BF%A1%E8%8A%B3-ebook/dp/B07NC8756Q)
kindleで650円。どちらかというと名前の通り入門向けで網羅的に知りたい人には物足りないかもしれないが、初学者が読むには丁度いい軽さで、するする入ってきた。おすすめ

[packt](https://www.packtpub.com/)
これ実は本じゃなくて出版社なんですけど、packtは
amazonで検索するとしばしば出てくる英語のシンプルな表紙のアレです。
イギリスの会社らしいのですが、プログラミング等の出版が多く、結構ニッチな内容も本で出してくれているのでtkinterの本も日本語ソースの本の数をこの一社で上回るくらいあります。
また、月10ドル（年間100ドル）くらいでサブスクもあり、それらが読み放題です。
英語に抵抗がなければなかなかgoodです。

## web page

[紫藤のページ](https://www.shido.info/py/index.html)
実例が多く、逐一何をしているかの説明があるので大変わかりやすい。

[Python Tkinter 入門メモ](https://qiita.com/aoirint/items/ca2386b68e8fec16ff53)
だいたいこれでいいんじゃないかな？というくらいくまなく書いてあるため、この記事を書くべきか悩んだくらいの記事。

[適当のごった煮](https://www.tekito-gottani.com/entry/2016/09/29/192522#tanjun)
こちらも説明がコマンドごとに言及されていることが多く大変ありがたかった。

[Tkinter による GUI プログラミング](https://python.keicode.com/advanced/tkinter.php)

[tkinterでGUIをつくろう](https://cauldron.sakura.ne.jp/thinkpython/thinkpython/Tkinter.pdf)
[tkinter tutorial](https://www.python-course.eu/python_tkinter.php)を訳してくださったもの。一通り実例とともに書いてあるのでありがたい。

[どん底から這い上がるまでの記録](https://www.pytry3g.com/entry/2018/02/04/185141#Listbox)
記事ごとにやりたいことがわかりやすく、機能ごとに細切りにして紹介していってくださるので、理解のためのハードルが最小で済み、非常に助かる。学習するなら最小構成で覚えるのが地味だけど一番いいよね。

[だえうホームページ](https://daeudaeu.com/category/python/tkinter/)
mainloopの仕組みなど、ただがむしゃらにやるだけだと躓いてしまうような内容にも触れてくれており、読んでおきたい内容。
AWS認定 高度なネットワーキング - 専門知識 に合格したので

# はじめに

AWS認定 高度なネットワーキング - 専門知識 に合格しました。
合格までにやったこと、試験に向けてのポイントなどを書いていきます。
中の人はISP（プロバイダ）出身でBGP等のネットワーク技術の知識は元々持っておりそのあたりの勉強法については記載していません。

# どんな試験なのか

ネットワークに関連した（これがかなり広い）AWSのサービスと一般的なネットワーク技術に関する試験です。
ネット上では「ダイレクトコネクトの試験」等と揶揄されていたりしますが出題割合からそう言われるのも納得だなと思います。
専門知識シリーズ共通ですが、AWSのサービスに限らずネットワーク全般についての知識はもちろん必要です。

# 受験までにやったこと

- AWS専用線アクセス体験ラボ に参加する（無料）
    - AWS Direct Connect は殆どの人は触れる機会がありません。ハンズオンで実際に環境を構築できる貴重な場で多くを得ることができました。
    - https://aws.amazon.com/jp/dx_labo/

- AWSJ公式ブラックベルトウェビナーを視聴する
    - AWS Direct Connect
        - https://aws.amazon.com/jp/blogs/news/webinar-bb-aws-direct-connect-2018/
    - AWS Transit Gateway
        - https://aws.amazon.com/jp/blogs/news/webinar-bb-aws-transit-gateway-2019/
    - Amazon VPC
        - https://aws.amazon.com/jp/blogs/news/webinar-bb-amazon-vpc-basic-2019/
    - Elastic Load Balancing
        - https://aws.amazon.com/jp/blogs/news/webinar-bb-elastic-load-balancing-2019/

- AWSJ公式ドキュメントを読む

    - VPC全般
        - https://docs.aws.amazon.com/vpc/index.html
        - 量多いけど全部。Transit Gatewayとかよく読む。
        - API関連はどんな感じの名称があるのかを把握する程度で。
    - AWS Direct Connect
        - https://docs.aws.amazon.com/ja_jp/directconnect/latest/UserGuide/Welcome.html
        - 出題率がかなり高い。全部しっかり読む。
    - AWS VPN
        - https://docs.aws.amazon.com/ja_jp/vpn/
        - インターネットVPN接続と経路の関係とか
    - Amazon EC2 におけるネットワーキング
        - https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-networking.html
        - 拡張ネットワーキング(ENI,ENA)の細かな動作とかもスルーせずじっくり読む
    - Elastic Load Balancing (ELB,ALB,NLB)
        - https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/
        - 3種類のロードバランサそれぞれの動作、できることとできないことを把握
    - Amazon Route53
        - https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/Welcome.html
        - オンプレミスDNSとの連携や別ネットワークからのアクセス可否を把握


# 勉強のポイント

- 模擬試験やサンプル問題は参考程度
    - 数が少ないからですが本試験では全然別の問題も出ます
- 上限緩和申請不可能な制限を覚える
    - 特にDirect Connectは制限事項が多いのでしっかりと
    - 例：DX接続１本に作成可能な仮想インタフェースは上限50
    - Direct Connect GatewayやTransit Gatewayに接続可能なVPCやDXの数とか
    - https://docs.aws.amazon.com/ja_jp/directconnect/latest/UserGuide/limits.html
- VPC,DX,VPN,TGWのルーティングや接続でできること、できないことを覚える
    - ２種類のVPCエンドポイントの動作、別ネットワークからの通信可否
- APIは名称をざっとでいいから目を通しておく
    - あたかも存在しそうな名前だけど実は存在しないAPI名等を見抜けるように
- アーキテクチャに依存した制限事項を覚える
    - 例：インターフェースエンドポイント(AWS Privatelink)へのVPCピアリング越しのアクセスはNitro世代(c5,m5,i3.metal等)のみ可能

# 結果

80%を目標にしていましたが一歩届かず。難しかったです。

```
総合成績： 78%
分野別の成績 :
1.0  Design and implement hybrid IT network architectures at scale: 75%
2.0  Design and implement AWS networks: 71%
3.0  Automate AWS tasks: 100%
4.0  Configure network integration with application services: 85%
5.0  Design and implement for security and compliance: 83%
6.0  Manage, optimize, and troubleshoot the network: 71%
```

# まとめ

専門知識シリーズの中でも難しい部類に入るであろう試験ですが、AWS専用線アクセス体験ラボに参加してDirect Connectを一度経験しておけばあとは座学でなんとかなると思います。
AWSJ本社(目黒)で定期的に開催されていますから是非参加して合格を目指しましょう。

======
intelliJでsbt reloadしてもimportしているlibraryが認識されない対処メモ

# 困ったこと
+ build.sbtに正しくlibraryDependenciesが記載されている。
+ `sbt reload`をしてもファイル上でimportを認識しない。
+ サイドバーのsbtタブ内のDependenciesには読み込まれている。
+ なんでだよ？？？

# これをすれば直った
`File` → `Invalidate Cashes/Restart`で`Invalidate and Restart`を選択してキャッシュを無効にすれば直った。
command+shift+AでActionの検索ができるので、上の`Invalidete~`を検索できます。
ディスクには残しつつ Git のレポジトリからはファイルやディレクトリを削除する方法


パスワードが入ったファイルや、本番・テスト環境によってパラメータが違うけれども同じファイル名で保存しないといけないファイルがあったとします。

Git で管理しているものの、間違ってブランチ同士をマージした時にファイルを上書きしてしまうかもしれません。

そんなときは、ローカル・サーバー上でファイルを残しつつ git レポジトリからだけファイルやディレクトリを削除したい場合の方法です。

つまり `git rm --cached` の説明です。

(実施する回数がレアで、いつも忘れちゃう・・・。)

# ステップ解説

## STEP 1. gitignore ファイルに対象のファイルを追加する

ローカル・サーバー上にはずっと残しておきたいので、該当するファイルやフォルダを gitignore に追加します。

```
cd [git レポジトリの場所]
vi .gitignore
```

## STEP 2. git rm -cached コマンドで git レポからは削除する

--cached オプションを加えることで、git レポジトリだけに反映されます。

```
git rm --cached [ファイル]
git rm --cached -r [ディレクトリ]
```

あとは普通にコミット & プッシュします

```
git commit -m "メッセージ"
git push [リモート名] [ブランチ名]

```

# おまけ

僕の作業用の手順書をここにおいておきます。

僕のコピペ用です。

通常、この作業をするときは、サーバー上での話なので、直接サーバーから作業します。

入れないといけない、メールアドレス、ファイル名、git commit メッセージ、push のときのブランチ名などは **省いています** 。

## サーバー上で Apache ユーザーとして行う場合

```
# サーバーからは初コミットかもしれないので、ユーザーを設定する
sudo -u apache git config --global user.name "Nginx User"
## メールアドレスを設定する
sudo -u nginx git config --global user.email nginx@

# git の場所
cd 
# クリーンなレポジトリか確認する
sudo -u apache git status
# .gitignore編集
sudo -u apache vi .gitignore
# 削除ファイルを入れる
sudo -u apache git rm --cached
# 削除ディレクトリを入れる
sudo -u apache git rm --cached -r 
# コミットメッセージをいれる
sudo -u apache git commit -m ""
# ブランチ名をいれる
sudo -u apache git push origin 
```

## サーバー上で Nginx ユーザーとして行う場合

```
# サーバーからは初コミットかもしれないので、ユーザーを設定する
sudo -u nginx git config --global user.name "Apache User"
## メールアドレスを設定する
sudo -u nginx git config --global user.email apache@

# git の場所
cd 
# クリーンなレポジトリか確認する
sudo -u nginx git status
# .gitignore編集
sudo -u nginx vi .gitignore
# 削除ファイルを入れる
sudo -u nginx git rm --cached
# 削除ディレクトリを入れる
sudo -u nginx git rm --cached -r 
# コミットメッセージをいれる
sudo -u nginx git commit -m ""
# ブランチ名をいれる
sudo -u nginx git push origin 
```



以上

参考
https://stackoverflow.com/questions/1143796/remove-a-file-from-a-git-repository-without-deleting-it-from-the-local-filesyste
nginx-unitで再びpython-flask【macOS】

前にnginx-unitをmacで使ってみたが、pythonの勉強がてらflaskでかんたんなWebappを作った。
uWSGIを使ってもいいんだけど、前に使ったnginx-unitでやってみようと思い、再度やってみた。

## 前回と違うところ
・Homebrewで用意されるようになった。

ということで、前にソースから入れたものは消しておく。
`$ make uninstall`
をソースファルダでうっておく。

あとは公式の通りにインストール
https://unit.nginx.org/installation/#homebrew

ちなみにだが、Homebrewでインストールしたときは`/usr/local/`から下に/varとか/tmpとかがある。
なので、unitdのconfigぶっこむようのソケットは
`/usr/local/var/run/unit/control.sock`
にある。
同様にログファイルは
`/usr/local/var/log/unit/unit.log` (Linux系だと`/var/log/unit/unit.log`)
に作られることになる。

さらにhomebrewでインストールされるパッケージの場所を変えている場合は、
`brew --prefix`
で確認しておくとよい。

## config.jsonをぶっこんだときに「"error": "Failed to apply new configuration."」
上記のエラーが出まくってよくわからんときは、ログを見ましょう。
（上記のログファイルの場所がわからずに原因究明に手こずった…）

Python周りのエラーなのか、jsonの書き方に問題あるのかが詳細に出てきています。
↓例として

``` 
2020/08/20 23:19:03 [notice] 89400#2700292 process 89405 exited with code 1
2020/08/20 23:19:03 [warn] 89404#2700311 failed to start application "flask_app"
2020/08/20 23:19:03 [alert] 89404#2700311 failed to apply new conf
2020/08/20 23:19:03 [alert] 89403#2700310 failed to apply previous configuration
2020/08/20 23:19:07 [info] 89410#2700380 "flask_app" application started
2020/08/20 23:19:07 [alert] 89410#2700380 Python failed to import module "views"
```

こんな感じでちゃんと出てました。

## config.json for flask
https://unit.nginx.org/howto/flask/
これもやはり公式を見たほうが早い。
注意すべき点は

> Mind that Unit will look for an application callable in the WSGI module.

ここですね、appとかにしてると動かないので注意しましょう。


nginx-unitだと複数のアプリを動かしたりできるので、便利ですね。
次はrubyと共存させてみようと思う。（dockerでも使いたい）
VirtualBoxで、VBOX_E_OBJECT_NOT_FOUND ＆ inaccessibleで仮想マシンを認識できなくなった場合の対処

環境

```shell
$ VBoxManage -v
6.0.16r135674
```

仮想マシンを起動しようとして、こんなエラーになってとても困ったという話。

```shell
$ VBoxManage startvm "仮想マシン名" --type headless
VBoxManage: error: Could not find a registered machine named '仮想マシン名'
VBoxManage: error: Details: code VBOX_E_OBJECT_NOT_FOUND (0x80bb0001), component VirtualBoxWrap, interface IVirtualBox, callee nsISupports
VBoxManage: error: Context: "FindMachine(Bstr(pszVM).raw(), machine.asOutParam())" at line 721 of file VBoxManageMisc.cpp
```

仮想マシンの一覧を見ると`inaccessible`になっているし、GUIで見ても仮想マシンにアクセスできなくなってたりします。

```shell
$ VBoxManage list vms

...

"<inaccessible>" [仮想マシンのUUID]

```

どうやら、仮想マシンの電源を入れたままホスト側をシャットダウンすると、こういう状態になることがあるようで…。

GUIで見ると、ISOファイルにアクセスできないとか出てたので

仮想マシンが置いてあるディレクトリにある`[仮想マシン名].vbox`、`[仮想マシン名].vbox-prev`という2つのファイルを開き、以下の記述を探して

```xml
      <DVDImages>
        <Image uuid="[UUID]" location="/path/to/VBoxGuestAdditions.iso"/>
      </DVDImages>
```

次にアタッチされている場所を探します。で、いくつか書かれているのですが、`port="1"`となっている部分を削除。

```xml
       <AttachedDevice passthrough="false" type="DVD" hotpluggable="false" port="1" device="0">
          <Image uuid="[UUID]"/>
        </AttachedDevice>
```

これで、仮想マシンを認識できるようになります。

1度仮想マシンの一覧から削除して、`.vbox`ファイルを選んで仮想マシンを開き直してください。

参考） [VirtualBox VM Inaccessible](https://www.mattbrill.com/tag/vbox_e_object_in_use/)