OmniAICreator/Qiita-1.07M huggingface dataset:
【Laravel6】Vue.js3 + TypeScriptを導入してみた٩( 'ω' )و☆★

## 概要

Dockerで構築したLaravel6環境に**Vue.js3 + TypeScript**を導入してみました。

[Laravel-MixがVue.js3に対応した(TypeScript導入まで)](https://qiita.com/ProjectEuropa/items/71da8b3450c812aca01a)を存分に参考にしながらやったのですが、この記事の前段階で少し詰まるところがあったのでまとめておきます。


## 環境

```
$ composer -V
Composer version 2.0.9 2021-01-27 16:09:27

$ php artisan --version
Laravel Framework 6.20.16

$ npm list vue
/var/www/html
`-- vue@3.0.7
```

## 前提

- Laravelの環境構築が終わっている
- Docker環境じゃなくてもできると思いますが検証してないです
- エラー吐きつつ導入したのでこの中で不要な工程もあるかもですm(__)m

Laravel + Vue.jsのDocker環境を構築したい方は僕が過去に執筆した記事も併せて見てみてください。

- [絶対に失敗しないDockerでLaravel+Vueの実行環境（LEMP環境）を構築する方法〜前編〜](絶対に失敗しないDockerでLaravel+Vueの実行環境（LEMP環境）を構築する方法〜前編〜)
- [絶対に失敗しないDockerでLaravel6.8+Vueの実行環境（LEMP環境）を構築する方法〜後編〜](https://qiita.com/shimotaroo/items/679104b7e00dd9f89907)


## Laravel6にVue.js3 + TypeScriptの導入

### Vue.js3のインストール

```
$ npm install vue@next -D
```

### vue-loaderのインストール

```
$ npm install vue-loader@next -D
```

これをインストールしてなくて`npm run dev`でエラー吐きました。

### laravel-mix-vue3のインストール

```
$ npm install laravel-mix-vue3 -D
```

### @vue/compiler-sfcのインストール

```
$ npm install @vue/compiler-sfc -D
```

### TypeScript用の必要なモジュールをインストール

```
$ npm install @types/webpack-env typescript ts-loader -D
```

### 以降の作業

[Laravel-MixがVue.js3に対応した(TypeScript導入まで)](https://qiita.com/ProjectEuropa/items/71da8b3450c812aca01a)の通りにやれば完了です😁

（と言いながらlaravel-mix-vue3、@vue/compiler-sfc、TypeScript用の必要なモジュールのインストールも記事に載っています...）

## package.jsonの中身

```json:package.json
{
    // 略

    "devDependencies": {
        "@types/webpack-env": "^1.16.0",
        "@vue/compiler-sfc": "^3.0.7",
        "axios": "^0.21.1",
        "browser-sync": "^2.26.14",
        "browser-sync-webpack-plugin": "^2.3.0",
        "cross-env": "^7.0",
        "laravel-mix": "^5.0.1",
        "laravel-mix-vue3": "^0.7.0",
        "lodash": "^4.17.19",
        "resolve-url-loader": "^3.1.0",
        "sass": "^1.15.2",
        "sass-loader": "^8.0.0",
        "ts-loader": "^8.0.18",
        "typescript": "^4.2.3",
        "vue": "^3.0.7",
        "vue-loader": "^16.1.2"
    }
}
```

※`browser-sync`、`browser-sync-webpack-plugin`等は別の機能用モジュールなので不要です。
## まとめ

- 基本的に添付の記事がとてもわかりやすいのでそちらを見れば（多分）できますw
- TypeScriptでVueコンポーネントをimportしようとすると下画像のように赤波線が出て気持ち悪いけど解決方法がわからぬ...
![スクリーンショット 2021-03-12 9.17.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/57b2afbb-c0af-4570-bf9a-652ba632c06e.png)


## 参考

- [Laravel-MixがVue.js3に対応した(TypeScript導入まで)](https://qiita.com/ProjectEuropa/items/71da8b3450c812aca01a)
- [laravel-mix-vue3](https://www.npmjs.com/package/laravel-mix-vue3)
Docker環境のLaravelアプリをHerokuデプロイ

Docker環境でLaravelアプリをデプロイするのが初めてだったので記事にまとめてみました。

# はじめるにあたり
Docker環境の作り方やLaravelアプリの作り方はもんしょーさんのブログを参考にしています。
- https://simablog.net/docker-laravel-nginx-mysql/
- https://simablog.net/laravel-keiziban/
Herokuに登録し、クレジットカード登録も済んでいる事を前提に進めていきます。
今回のディレクトリ構造です。

```
larapic
 ├── README.md
 ├── infra
 │   ├── mysql
 │   ├── nginx
 │   └── php
 ├── docker-compose.yml
 └── laravel
     ├── app
     ├── bootstrap
     ├── config
     ├── ・・・
```

# Herokuにアプリを作成
ブラウザでHerokuを開きログインします。
Newボタンから
![7fe3c4fa47ef90b4b5073631c4f544ce.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/851225/621a3e0e-256e-d597-f39f-6b44f355039a.png)
App nameにアプリケーション名を入力
（アプリ名） is available
となるように命名します。

# Githubと連携
![d1c80f9d75445f25aec358b64b7710d8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/851225/165b0374-0d8d-1c81-3fd8-20e54881868f.png)

# Procfileの作成

```
larapic
 ├── README.md
 ├── infra
 │   ├── mysql
 │   ├── nginx
 │   └── php
 ├── docker-compose.yml
 └── laravel
     ├── app
     ├── bootstrap
     ├── config
     ├── ・・・
　　　├── Procfile（新しく作成）
　　　├── ・・・
```

↑のようにProcfileを作成します。

```php:Procfile
web: vendor/bin/heroku-php-apache2 public/
```

このようにProcfile内に記述する事でHeroku起動時にapacheサーバーが起動するようです。
ローカルではnginxを使っていたのでnginxにしたかったのですが、いろいろ面倒くさそうだったのでapacheにしました（←apacheに失礼）。

# DBはMySQLを利用
ローカルでMySQLを使っていたので本番でもMySQLを使いたいと思います（nginxを断念したので今回は頑張ります）。
HerokuでMySQLを使いたい場合はClearDBを利用します（クレジットカード登録が必要です）。

```php:terminal
% heroku addons:create cleardb:ignite
```

herokuでMySQL5.7以降を使う場合はJawsDBを利用します。

```php:terminal
% heroku addons:create jawsdb:kitefin
```

自分の場合、ClearDBで進めた結果

```
Mysql2::Error: Specified key was too long; max key length is 767 bytes 
```

このようなエラーが出ました。
解決はこちらの記事を参照→https://qiita.com/reiya018/items/ba8ceaa732edac07e491
結論としてはJawsDBを使用する事で解決します。

# Buildpacksの設定
![171a3e2b072719c226a6f6fe99d08b34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/851225/b66c53c2-da80-c961-7782-20d78e3209de.png)
このようにブラウザから入力しても構いませんし
ターミナルからなら↓

```php:terminal
% heroku buildpacks:set https://github.com/timanovsky/subdir-heroku-buildpack
% heroku buildpacks:add heroku/node.js
% heroku buildpacks:add heroku/php
```


# 環境変数の設定
Laravelの場合はAPP_KEYの登録が必要です。

```php:terminal
% heroku run "php artisan key:generate --show"
# （出力）base64:◯△□×・・・
% heroku config:set APP_KEY=base64:◯△□×・・・
```

DBの設定も環境変数に設定します。

```php:terminal
% heroku config:get CLEARDB_URL（もしくはJAWSDB_URL）
# （出力）mysql://◯◯◯◯:△△△△@□□□□/××××?reconnect=true
% heroku config:set DB_CONNECTION=mysql
% heroku config:set DB_USERNAME=◯◯◯◯
% heroku config:set DB_PASSWORD=△△△△
% heroku config:set DB_HOST=□□□□
% heroku config:set DB_DATABASE=××××
% heroku config:set DB_PORT=3306
```

デプロイさせたいフォルダ(今回の場合はlaravel)を指定して環境変数に設定します。

```
larapic
 ├── README.md
 ├── infra
 │   ├── mysql
 │   ├── nginx
 │   └── php
 ├── docker-compose.yml
 └── laravel　←ここ
     ├── app
     ├── bootstrap
     ├── config
     ├── ・・・
```

```php:terminal
% heroku config:set PROJECT_PATH=laravel/
```

# マイグレーション
Herokuにテーブルを作ります。

```php:terminal
% heroku run php artisan migrate
```

# デプロイ

```php:terminal
% git push heroku main
```

これでデプロイできました。
開発手法について

チームで開発を行う際に、開発を進める手法があります。
今回は、アジャイル型開発とウォーターフール開発について
簡単な記事を書きたいと思います。

## アジャイル型開発
アジャイル型開発は、一度にまとめてでは無く、少しずつ確認をはさみながら開発を進めていくことが特徴です。利用者の反応や、関係者からの継続的なレビューを得ながら、計画を調整しつつ進めて行きます。

・メリット
手直しが容易で仕様変更に柔軟に対応可能

・デメリット
進捗が把握しづらい

### どのような開発の時に使われるか?
・最終的な要件がはっきりしていないプロジェクト
プロダクトの使い勝手を見ながら残りの詳細を詰めていくようなプロジェクトにアジャイル型開発は有効です。「この機能だけは絶対に欲しい。一方で、それ以外の機能は実際に使ってみながらでないと必要かどうか判断できない」といった開発プロジェクトにおいて用いることができます。

・顧客ビジネスの状況によって開発の優先度が変わる可能性のあるプロジェクト
後々の状況に応じて変更を加える前提のプロジェクトにアジャイル型開発は有効です。アジャイルでは1〜4週間がひとつのサイクルです。そのサイクル内で完成したものを顧客やユーザーに届けることができます。詳細まで時間をかけて作り込むのではなく、実際に作ってみてから改善点を探していくことで、よりスピーディーに本質的な開発を続けることができます。

## ウォーターフォール型開発
初めに決めた要件を、ある期限までに完了するという手法です。契約→開発→納品というフローに則ったシンプルなものです。厳密な要件定義と納期に合わせた進捗管理を行うことができれば、大きな問題は発生しません。しかし、はじめの要件定義が上手く行われていなかった場合や、作りたいものが途中で変わってしまった場合に対応することが難しくなります。

・メリット
開発計画がシンプルで、進捗管理がしやすい

・デメリット
仕様変更に対応しにくい

### どのような開発の時に使われるか?
・大規模システム開発プロジェクト
大型システムの開発のように多くのエンジニアが関わるプロジェクトにおいて、明確に役割分担を行う必要がある際にウォーターフォール型開発が有効です。携わる人々の役割と期間を明確に決めることで、大規模でもスケジュール管理がしやすくなります。ただし、開発途中で仕様変更などが発生しないことを前提とするため、綿密な計画が必要です。

・ユーザーの要件が明確に定まっているプロジェクト
明確に欲しい要件が決まっている際には、仕様どおりに開発を粛々と進めれば良いため、ウォーターフォール型開発が有効です。役割を明確に決めることで、最短効率で開発を行うことができます。
DataCore SANsymphonyでCapacity Optimizationを試してみる

DataCore SANsymphony V10 **PSP12**で追加された新機能 **Capacity Optimization** こと**インライン重複排除＆圧縮機能**を試してみます。

##有効化
さっそくGUIで新しく増えたボタンを押してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/7ff42a62-4a21-44a8-5fd4-7d1c6f6f1a1a.png)

こんなことを言うので設定が終わったら再スタートさせましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/4fad83b0-3d6b-1ea3-1f69-64c7725300f7.png)

ではいきます。
ディスクプールに所属していないディスクの中からこの機能で使用するディスクを選択します。これらに重複排除されたあとのデータが保存されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/086cb576-1f35-2285-c0ac-8ff781556c93.png)

機能を有効にするディスクプールを選択します。あとからでも有効／無効の変更ができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/b4a80a16-f5da-e730-2cf4-e259ed8033b5.png)

##サーバーリスタート
指示されたとおりサーバーを右クリックして一度Stop→Startしておきましょう。


##確認
サーバーを見てみます。圧縮比がわかるGUIが追加されていますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/1fc4da37-5404-d964-a5ee-cee835fc19e5.png)

ディスクプールを見てみると項目が増えています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/5c7e65ae-bad0-a4dd-15a4-04c1860d33da.png)

物理ディスクを見てみるとUsageが変わりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/6c150ec7-9266-039e-b501-58dd94be5d42.png)

##仮想ディスク作成
それでは仮想ディスクを作ってみます。ここにチェックを入れるだけですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/794011b4-9746-1d61-7c71-475371075867.png)
チェックを入れると警告が出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/44a1b1b1-8652-c05d-9ff3-bc20c942ef5e.png)
やっぱりちょっと性能は落ちちゃうようです。
**最強性能をとるか容量効率を取るか究極の選択です。**
**Learn More**のリンク先はこちらです。参考までに。
https://docs.datacore.com/SSV-Webhelp/#Enabling_Capacity_Optimization.htm

形式的に管理上どのディスクプールに作るか指定します。実際は先ほど有効にした物理ディスクに配置されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/1b58d25c-fe7e-c8d9-1c7c-733b12ac3f3a.png)

作成された仮想ディスクを見るとチェックが入っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/00be804a-a4f0-5cef-c20f-0ddb6bc7ce42.png)

##機能確認
今回は簡単なテストをしてみます。
###まずは無効の状態
自身でマウントして空っぽの固定長VHDファイルをたくさん作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/b7d10603-e09f-e72d-615c-787f5f31dadf.png)

###有効にすると
移動を開始しています。仮想ディスクによる消費は0Bになっているけど実はまだ18GB（約5%分)ほど残っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/54e1b1e8-ec3b-46c2-67e6-73ec4211b75c.png)
###有効化が終わったあと
ディスクプールの消費がなくなっています。
もともと空っぽのファイルのコピーなので重複排除&圧縮がしっかり効いて数MBしか消費しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/a8082b31-e95b-4611-3f84-d83d553a1b59.png)

##まとめ
+ Capacity Optimizationことインライン重複排除&圧縮が機能することが確認できました。
+ ポイントはこの絵の通りで、便宜的に青枠のディスクプール上に作られるけど、データは赤枠の"[Capacity Optimization]"がついているディスクに書かれるというところです。
+ ディスクプールには所属していないため、複数のディスクプールを超えて（跨いで）ここに書かれます。
+ ご覧の通り有効化したディスクを並列で使ってしまいます。まだ階層化（を含むいくかの機能との組み合わせ）には対応していません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115778/17b324ec-8d1b-a2e1-a9f2-56005ba17963.png)

次は性能の違いやちゃんと中身があるファイルを作ってサイズの違いを見てみたいと思います。
S3 SourceをトリガーにしたCDKで作成したCodePipelineにて二重で実行されてしまう問題


# 事象

S3 SourceをトリガーにしたCDKで作成したCodePipelineにてS3ファイルが更新されると2回実行されてしまう。

以下スクショのように、同じS3のトリガーに対して時間差で`CloudWatchEvent`と`PollForSourceChanges`の2つ分のPipeline実行がされてしまう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91562/d1565cc1-f0cc-1993-2285-aed6b64a0053.png)

# 調べる

以下のAWS公式ページで原因の説明が書かれていました。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/codepipeline-running-twice/

そしてこの文言を見つけました

> CodePipeline コンソール以外の方法を使用してパイプラインを作成し、コンソールを使用して帯域外パイプラインを更新すると、CodePipeline は自動的に追加の CloudWatch Events ルールを作成します。

これに関して身に覚えがあり、CDK作成されたCodePipelineを一度手動で更新したことがありました。

そしてCloudWatch Eventを確認すると、Eventが存在していることを確認しました。

# 解決

CloudWatch Eventを削除することで解決しました。
slack-notifier補完計画

## はじめに
Slack通知に便利なgem「slack-notifier」がRuby3に対応してなかった。
バグ通知とか便利だからこれがないと困る。

pingメソッドを実行すると

```
ArgumentError (wrong number of arguments (given 2, expected 1))
```

しょうがないからモンキーパッチを当てて対応した。
極力モンキーパッチしたくないけど、gem壊れてたらしょうがないよね。


## 前提
Rails 6.1.0
Ruby 3.0.0
slack-notifier 2.3.2

※2021年3月12日現在までは動くことを保証してますが、
それ以降は自己責任でお願いします。

## 説明すること
- slack-notifierが動かなくなった理由
- 対応方法

## slack-notifierが動かなくなった理由
Ruby 3で、キーワード引数が通常の引数とは独立した引数になったことが原因みたい。

Ruby 3ではこんな感じで引数を入れてあげないとErrorになるらしい。

``` rb
# キーワード引数を受け取るメソッド
def foo(key: 42)
end

foo(key: 42)      # OK: キーワード引数を渡している

opt = { key: 42 }
foo(opt)          # NG: 普通の引数を渡しているのでエラー（2.7では警告付きで動いていた）

foo(**opt)        # OK: ハッシュを明示的にキーワードに変換している
```
参照：https://techlife.cookpad.com/entry/2020/12/25/155741


この変更のせいで「Slack::Notifier::Util::LinkFormatter」がお亡くなりになったようです。


## 対応方法
モンキーパッチをしてあげましょう。

### モンキーパッチって何？
ソースを直接いじらず、RailsとかGemとかの外部モジュールを変更すること。

wikipediaにはこんな感じで書いてる
`モンキーパッチは、オリジナルのソースコードを変更することなく、実行時に動的言語(例えばSmalltalk, JavaScript, Objective-C, Ruby, Perl, Python, Groovy, など)のコードを拡張したり、変更したりする方法である。`

参照：https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%B3%E3%82%AD%E3%83%BC%E3%83%91%E3%83%83%E3%83%81


### 実際のソース



```lib/monkey_patches/slack_notifier.rb
require 'slack-notifier/version'
unless Slack::Notifier::VERSION == '2.3.2'
  raise 'Consider removing this patch'
end

module MonkeyPatches::SlackNotifier
  def initialize string, opts = {}
    @formats = opts[:formats] || %i[html markdown]
    @orig    = string.respond_to?(:scrub) ? string.scrub : string
  end
end

Slack::Notifier::Util::LinkFormatter.prepend(MonkeyPatches::SlackNotifier)
```



```config/initializers/monkey_patches.rb
Dir[Rails.root.join('lib/monkey_patches/*.rb')].sort.each do |file|
  require file
end
```


### 参照
[Gemにモンキーパッチを当てるサンプル
] (https://qiita.com/ham0215/items/96726d73a563ae8a4c60)
普段使っているクリーンアーキテクチャのUseCaseの作り方と使い方

Templateつくりました！
https://github.com/yosuke1985/Clean-MVVM-Generator/blob/main/Clean%20MVVM/UseCase.xctemplate/___FILEBASENAME___UseCase.swift

例えばuserに紐付いたTodoを取得するGetTodoListUseCaseがあるとして、

テスタブルな設計にするためにもInputとOutputをプロトコルで定義する。
Inputは　userID:String
Outputは　GetTodoListUseCaseResult　で定義する。
Outputには、成功パターンと失敗パターンを明記する。


``` swift
import UIKit
import RxCocoa
import RxSwift

enum GetTodoListUseCaseResult {
    case success(element: [Todo])
    case failure(errorType: ErrorType)
    
    enum ErrorType {
        case someError
    }
}

protocol GetTodoListUseCaseInjectable {
    var getTodoListUseCaseImpl: GetTodoListUseCase { get }
}

extension GetTodoListUseCaseInjectable {
    var getTodoListUseCaseImpl: GetTodoListUseCase {
        return GetTodoListUseCaseImpl()
    }
}

protocol GetTodoListUseCase {
    func getTodoList(userID: String) -> Single<GetTodoListUseCaseResult>
}

class GetTodoListUseCaseImpl: GetTodoListUseCase {
    let bag = DisposeBag()
    
    func getTodoList(userID: String) -> Single<GetTodoListUseCaseResult> {
         // ここでレポジトリ経由でタスクをゲットする
        return Single<GetTodoListUseCaseResult>.never()
    }
}

```

上記のUseCaseのoutputはGetTodoListUseCaseResultですので、

```swift
GetTodoListUseCaseResult.getTodoList(userID: "yosuke8080")
           .subscribe( onNext: { getTodoListUseCaseResult in

             switch GetTodoListUseCaseResult {
              case .success(let todoList):
                 // ここで取得したtodoListでゴニョゴニョする
              case .failure(let error):
                // 准正常系
                
              }
          }, onError: { error in
              // 異常系
              fatalError(error.localizedDescription)
         })
          .disposed(by: bag)
```

ここでは、異常系に入る場合はfatalError()でアプリ自体を落とす処理にしています。
[Rails]rspecでsettings.ymlの設定を無理やり書き換える方法

モックで可能。

例えば、settings.ymlで

```
test:
   is_xxx: true
```

という設定をしていた場合、
specファイル側で

```
    context "正常なレスポンス" do
      before do
        allow(Settings.test).to receive(:is_xxx).and_return(false)
      end

      it "test" do
        ....
      end
    end
```

とすると、settings.ymlでis_xxxがfalseに設定されていたかのようにテストすることができる。
DETRとは？

#まえがき
本記事は、最近勉強したDETRを書き残す。
初学者なので、間違いもあるかも。

# DETRとは？
DETRとは、2020年に発表された新しい物体検出手法です。
論文： [■](https://arxiv.org/pdf/2005.12872.pdf)
コード：[■](https://github.com/facebookresearch/detr)

特徴としては、

- End-To-Endで検出 
- transformerが物体検出デビュー

### End-To-Endで検出
従来、物体検出では、NMS（non-maximal suppression）といった後処理をする必要がありました。
というのも、写真のように複数領域が検出されるため、もっともらしいものを選択する必要があります。
![NMS説明.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147946/f07e430b-4fb8-84f2-f650-f0228720d4bd.jpeg)
（NMSに関しては[このサイト](https://meideru.com/archives/3538#R-CNN)がわかりやすかったです。）
そのため、従来手法では
①入力画像から物体領域候補を検出
②複数の物体領域候補からもっともなものを選択
というように２ステップ踏んで最終的な領域を検出していました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147946/af6a910e-e01a-9694-e00d-b669562b4902.png)
一方で、DETRでは「入力画像から最終領域を検出」をワンパスで検出することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147946/23a46689-de5a-9dec-eece-e7f6b943231f.png)

### transformerが物体検出デビュー
transformerとは、[Attention Is All You Need](https://arxiv.org/abs/1706.03762)という論文で発表されたCNNやRNNを使わないNueralNetworkです。
自然言語処理の分野で発展してきた手法で、BertやGPT-3といったモデルで利用され、色々なタスクで大幅な精度向上を達成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147946/ca48dc1e-96dc-3d29-ce56-62eb087d0869.png)
特徴的なのは、論文のタイトルにもなっている「Attention」というレイヤーです。従来、RNNやCNNを使って各要素の関係性を抽出していましたが、ここでは「Attention」を使ってその関係性を抽出します。RNNように逐次実行せず、一気に行列計算ができるので、並列化しやすくなっています。
（[このサイト](https://qiita.com/halhorn/items/c91497522be27bde17ce)の説明がわかりやすい）


# 構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147946/e33b3359-98d7-0f56-b164-91ddad73fb40.png)
詳しい説明はしませんが、構成は図の通りでそれぞれの機能の意味として下記の感じかなと思っています。

- backbone
    - 画像から特徴量の抽出
- transformer
    - 関連性を加味した値を出力
- FFN
    - 物体検出（ボックスの検出）

また、Loss計算も工夫をしていて、１対１で対応する集合を予測するために、ハンガリアン法を使っています。従来だと、例えば画像に検出したい物体が複数体いたとしたらそれぞれに対して独立して検出をしてそれぞれの結果でLoss計算をすると思います。ここではそれに加えて、集合としての対応関係のLoss計算（bipartite matching loss）も加味しています。
したがって、予め検出数を与えて、検出する物体がいなければ「no object」が割り当てられます。例えば、検出数が5で、画像上には検出できる鳥が２体いて正しく検出できれば、２個の箱に鳥の情報が入り、他の３つには「no object」が入ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147946/0ceec84f-5ef0-a43b-92b5-245401806ebb.png)

この論文では後半では、Transformerの各レイヤーがどのような寄与をしているかパラメータを色々変えて実験をしています。
その内容も面白いのですが、それと加えて、Transformerを構成している、EncoderのSelf-AttentionとDecoderのSelf-Attentionを可視化してこのモデルがどこに注目しているのか見られるのも面白いと感じました。

### EncoderのSelf-Attention
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147946/8bccb7ec-8667-3021-bf8b-5f272659d314.png)
ここで各動物を捉えていて、それぞれ領域がまとまりが可視化されていますね。

### DecoderのSelf-Attention
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147946/bee1fd70-39b1-2622-2f1b-aa950bee4720.png)
Decoder側では、ボックスを検出するのに必要な境界部分を求めていそうです。象やシマウマをよく見てみると動物と矩形の接点が色づいています。（Attentionでの可視化領域）

#　最後に
Attentionで可視化できるとモデルがどこに着目しているのかわかるので面白かったです。
もっと詳しく知りたい人は論文かこの記事がまとめられているなと感じたので読んでみてください。

https://ai-scholar.tech/articles/object-detection/detr-object-detection-transformers-paradigm
class基本　記事まとめ

#クラスに関する一連の記事のまとめリンクです

[PHP try{}catch, throw, Exceptionの考え方（基本）](https://qiita.com/H-Toshi/items/297d0c8fda92e85b18a6)
[PHP classについて（基本）コンストラクタ使い方 / staticを使用したメソッド呼び出し / selfの使用 / 例外処理について](https://qiita.com/H-Toshi/items/dbe7a1f05a55c10161b9)
[PHP classの基本　例外処理について](https://qiita.com/H-Toshi/items/b16df9117c4a6fbcab07)
[PHP 基本　extends(この記事の内容は学習中）](https://qiita.com/H-Toshi/items/584fe392a73fad598f3a)
[PHP class基本　アクセサ（アクセス権）](https://qiita.com/H-Toshi/items/072f158cdcabe4730a3e)
[class 基本　名前空間](https://qiita.com/H-Toshi/items/afa21bf3f1533d262ec5)
[PHP class useのasについて](https://qiita.com/H-Toshi/items/c863859e65510f43649e)
[PHP クラスについて　::parent](https://qiita.com/H-Toshi/items/aa5f5c81f84e367229be)
[php $this使い方　cakephpなどフレームワークを使う為の基礎知識](https://qiita.com/H-Toshi/items/314aa49a948a89b94eb1)
[PHP クラスについて　::parent](https://qiita.com/H-Toshi/items/aa5f5c81f84e367229be)
[PHP class useのasについて](https://qiita.com/H-Toshi/items/c863859e65510f43649e)
[PHP classの継承（オーバーライド）について
](https://qiita.com/H-Toshi/items/9922f419701e6d3e6d53)
PHP class基本　アクセサ（アクセス権）

#private, protected, publicについて
privateを使用するようになるとアクセサを使用する

```php
private $name;
public function getName()
{
   return $this->name;
}
```
上記のgetName(){}のようにprivateにされたプロパティを外部から読み取りのみ出来るようにする為に設定するメソッドを**アクセサ**という。

過去記事の例を参考にアクセス権を付与した例が以下
**※過去記事**
[PHP 基本　extends(この記事の内容は学習中）
](https://qiita.com/H-Toshi/items/584fe392a73fad598f3a)


###例）

```php

<?php
//Entreeクラスの拡張

//親クラス
class Entree
{
    private $name;
    protected $ingredients = [];

    public function getName(){
        return $this->name;
    }

    public function __construct($name, $ingredients)
    {
        if (!is_array($ingredients)) {
            throw new Exception('$ingredientsは配列を指定してください');
        }
        $this->name = $name;
        $this->ingredients = $ingredients;
    }

    public function hasIngredient($ingredient)
    {
        return in_array($ingredient, $this->ingredients);
    }
}

//子クラス
class Zensai extends Entree
{
    public function __construct($name, $entrees)
    {
        parent::__construct($name, $entrees); // Entreeのコンストラクタを参照
        foreach ($entrees as $entree) {
            if (!$entree instanceof Entree) {
                throw new Exception('Elements of$entrees must be Entree objects');
            }
        }
    }



    public function hasIngredient($ingredient)
    {
        foreach ($this->ingredients as $entree) {
            if ($entree->hasIngredient($ingredient)) {
                return true;
            }
        }
        return false;
    }
}

//インスタンス
$soup = new Entree('鳥スープ２', ['chicken', 'water']); //スープインスタンス
$sandwich = new Entree('鳥サンド', ['chicken', 'bread']); //サンドイッチインスタンス
$zensai = new Zensai('Soup + Sandwich', [$soup, $sandwich]); //前菜インスタンス


foreach (['chicken', 'water', 'pickles'] as $ing) {
    if ($zensai->hasIngredient($ing)) {
        if ($zensai->hasIngredient($ing)) {
            print "前菜には食材（{$ing}）が含まれている.\n";
        }
    }
}

結果
/*
前菜には食材（chicken）が含まれている.
前菜には食材（water）が含まれている.
*/
```
上記例ではプロパティ```protected $ingredients = [];```をpravateにするとエラーになる。
Python: 関数のデフォルト引数にはOptional指定は不要

言われてみれば当たり前なんですけど、typing使い始めたばかりのころのコードで勘違いをしていたのを発見したのでメモ。
バグの原因になる可能性がありました。

参考：[typing --- 型ヒントのサポート — Python 3.9.2 ドキュメント#typing.Optional](https://docs.python.org/ja/3/library/typing.html#typing.Optional)

検証：Visual Studio Code, Pylance, Python 3.8.5


# 簡潔に
`Optional` ＝「Nullable（Noneable）」だということ。
引数が英語で言う「optional」だという意味ではない。


# 例
## 正しい例
以下のように、引数`right`にデフォルト引数を設定することを考えます。

```py3:correct.py
# 引数2個を加算して返す関数（正しい例）
def add_num(left: int, right: int = 0) -> int:
    added = left + right
    return added

# 正しい使い方
eight = add_num(3, 5)
seven = add_num(7)  # 自動的に2番目の引数に 0 が設定される

# これはおかしいので警告が出るべき
wrong = add_num(9, None)  # Type "None" cannot be assigned to type "int"
```

最後の行で関数`add_num`に不適切な引数を渡しているので、以下のように警告が表示されます。

```:typingのエラー文（一部）
  Type "None" cannot be assigned to type "int"
```

## 間違った例
「デフォルト引数は省略可能だから、optionalだよね」と勘違いをして以下のように`Optional`指定をしてしまっていました。

```py3:wrong.py
from typing import Optional

# 引数2個を加算して返す関数（typingの指定がおかしい）
def add_num(left: int, right: Optional[int] = 0) -> int:
    added = left + right
    return added

# 正しい使い方
eight = add_num(3, 5)
seven = add_num(7)  # 自動的に2番目の引数に 0 が設定される

# これは本来おかしいのだが…
wrong = add_num(9, None)  # 警告は出ない
```

`Optional`指定はあくまでも **`None`を渡すことができる** ということを示すものなので、このような場合は`Optional`指定は不適切です。

今回の例の場合は、~~コーディングの段階では警告は表示されません。~~
実行時に`int`と`None`を加算しようとして例外が発生することになります。

⇒ 追記：現在（Python3.11）は`int`と`int | None`との加算はできない旨のエラーメッセージが出ます。当時は出てなかったはず。

## 不適切ではない例
正しい`Optional`指定の使い方はこんな感じ。
（あくまでもOptionalの使い方の話です。なんでそこで`None`を渡すんだとかいうツッコミは無しで…）

```py3:correct_optional.py
from typing import Optional

# 引数2個を加算して返す関数（rightにNone指定が可能）
def add_num(left: int, right: Optional[int] = 0) -> int:
    right_int: int = 0  # intであることが確実な変数
    if right is not None:
        right_int = right

    added = left + right_int
    return added

# 正しい使い方
eight = add_num(3, 5)
seven = add_num(7)  # 自動的に2番目の引数に 0 が設定される

# 関数の仕様として意図した使い方
not_wrong = add_num(9, None)  # もちろん警告は出ない
```

## 不適切ではない例その２
~~Python4.0で`int | None`的な書き方ができるようになるらしいですが、~~
Python3.10で`int | None`的な書き方ができるようになりました。
参考：[組み込み型 — Python 3.11.0b5 ドキュメント#Union Type](https://docs.python.org/ja/3/library/stdtypes.html#types-union)

```py3:correct_optional_2.py
from typing import Optional

# 引数2個を加算して返す関数（rightにNone指定が可能）
def add_num(left: int, right: int | None = 0) -> int:
    right_int: int = 0  # intであることが確実な変数
    if right is not None:
        right_int = right

    added = left + right_int
    return added

# 正しい使い方
eight = add_num(3, 5)
seven = add_num(7)  # 自動的に2番目の引数に 0 が設定される

# 関数の仕様として意図した使い方
not_wrong = add_num(9, None)  # もちろん警告は出ない
```

Noneを引数で渡す！ということが明確になって良いですね。

`int | None`的な書き方ができる環境なら、`Optional`なんてわかりにくいものは使っちゃダメです。
【Python】#2「演算子、比較演算子」( ..)φメモメモ

比較演算子ちょっと苦手。
数学的になればなるほど無理ゲー。
いや、日本語の理解力の問題かもしれない。日本語ムズカシイ。

#演算子
```python
1 + 1
2 - 1
3 * 1
4 / 2                           #ただの計算なので説明することはない

5 % 3                           #割り算のあまりを出力してくれる

10**2                           #二乗してくれる　べき乗って言うんだね
```


#比較演算子

True Falseで返ってくるあれ。
このへんまだごっちゃになる。

```python

print(2 > 1)  #超過
print(2 < 1)  #未満
print(2 >= 1) #以上
print(2 <= 1) #以下
print(2 == 2) #平等　※型が違うときはFalse
```
___

#bool演算子
###and, or, not
***・and*** ......2つの条件がどちらも真のときTrueを返す
***・or*** ......2つの条件のどちらかが真のときTrueを返す
***・not*** ......notは条件式がTrueの場合に式全体がFalseになる

```python
1 == 1 and 2 == 2

True                                #実行結果
____________________________________________________
1 == 1 or 2 == 1                    #2/2 1/2 0/2

True                                #実行結果
____________________________________________________
not 1 == 1                          #反対の式

True                                #実行結果
____________________________________________________
```
ここだけ唐突に実行結果を書いてしまた。

#さらに演算子

```python
num == num1
num != num1                         # = の逆
num is num1
num is not num1                     # is の逆
num_list is num_list                #変数名も同じでないとTrueが返ってこないのが「is」
```


___

飽きた。今日はここまで。
また編集するかもだけど。にゃん。
バーチャルホストで複数サイトを管理する

## 0. はじめに
~~サーバー代をケチるために、~~バーチャルホストで複数サイトを管理したので、備忘録として記事化することにしました。

## 1. バーチャルホストとは
1つのサーバーで複数のドメイン(例：hoge-blog.com + fuga-stagram.com)のサイトを公開するための技術になります。
メリットとしては、サーバーのコストを下げることができます。
デメリットとしては、1つのドメインの負荷があがったり、障害が発生した場合、他のドメインにも影響を及ぼしてしまいます。

## 2. 環境
- Conoha VPS
- Ubuntu (20.04.1 LTS)
- Apache (2.4.41)

## 3. 前提
- ドメインを2つ取得していること。今回は以下を例にして記載。
  - hoge-blog.com
  - fuga-stagram.com
- Apacheのインストールが完了していること。

## 4. 手順

### 4-1. バーチャルホスト設定ファイルを作成する

今回は「hoge-blog.com」のバーチャルホスト設定ファイルを作成することとします。

①以下のディレクトリに移動します。

```
cd /etc/apache2/sites-available
```

②`000-default.conf`という設定ファイルが既に存在するかと思いますので、これをコピーして「hoge-blog.com」用の設定ファイルを作成します。名前は任意ですが、どのドメインに対応しているか把握できる名前をつけるといいかと思います。

```
cp 000-default.conf hoge-blog.conf
```

③`hoge-blog.conf`を以下のように変更します。

- ServerName・・・バーチャルホストのドメイン名
- DocumentRoot・・・ドメインのドキュメントルート(後で作ります)

```
vi hoge-blog.conf
------------------------------------------
<VirtualHost *:80>
        ...
        ServerName hoge-blog.com
        DocumentRoot /var/www/hoge-blog/
        ...
</VirtualHost>
------------------------------------------
```

443ポート(https)に設定したい場合も同様です。

```
vi hoge-blog.conf
------------------------------------------
<VirtualHost *:443>
        ...
        ServerName hoge-blog.com
        DocumentRoot /var/www/hoge-blog/
        ...
</VirtualHost>
------------------------------------------
```


### 4-2. バーチャルホスト設定ファイルを登録する
①以下のコマンドを実行し、バーチャルホスト設定ファイルの登録を行います。

```
a2ensite hoge-blog.host
```

上記のコマンドを実行すると、`/etc/apache2/sites-enable/`配下に登録されます。
なお、削除する場合は以下のコマンドを実行します。

```
a2dissite hoge-blog.host
```

### 4-3. テストサイトを作成する

①以下のディレクトリに移動します。

```
cd /var/www/
```

②ドキュメントルートとなるディレクトリを作成します。

```
mkdir hoge-blog
cd hoge-blog
```

③テスト用ページを作成します。

```
vi index.html
------------------------------------------
<html>
<body>
hoge blog
</div>
</body>
</html>
------------------------------------------
```

### 4-4. 動作確認
①apacheの再起動を行います。

```
systemctl restart apache2
```

②ブラウザからページにアクセスしてみて、テストページが表示されればOKです。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247638/3561caf3-370a-50fb-7a6c-2189db5adf41.png)

★別のサイト(fuga-stagram.com)を立ち上げたい場合は、[**4. 手順**](https://qiita.com/i-tanaka730/items/3f28150eb1b3b7f8183c#4-%E6%89%8B%E9%A0%86)をもう一度実施すればOKです。

## 5. 参考
https://www.server-world.info/query?os=Ubuntu_20.04&p=httpd&f=2

https://karappi.mydns.jp/linux_memo/apache24.html
Seleniumでテキスト入力時にプレースホルダに入力される問題の回避方法

レガシー管理システムに大量の情報を入力しなければいけない事態になり、例によってSeleniumちゃんに頼むことにしました。

その際に、名称を挿入する際になぜかプレースホルダに追記されてしまう事件が発生しました。

# 解決方法

解決方法は簡単でした。入力したいエリアを一度クリックしたのちに入力します。

```ruby
driver.find_element(:xpath, "/html/body/div[3]/div[3]/div/form[1]/input").click

driver.find_element(:xpath, "/html/body/div[3]/div[3]/div/form[1]/input").send_keys('田中')
```
ブラウザで操作してると、一度そのテキストフォームをクリックするとプレースホルダが消えてテキストを入力できるようになったので、同様の行動をSeleちゃんにもやってもらいました。

同じところで躓く方にこの記事見つけてもらえたらうれしいです！
50代のおじさんはJDLA E資格に合格できるのか!?

注)ただの自己満記事です。

## TL;DR
- JDLA E資格2021#1 に合格できたので調子にのって初投稿  
- E資格の難易度かなり高い(私にとって)  
- ぶっちゃけ落ちたと思ったので受ける気がなかった3月のG検定に申し込みました(順序逆だろ)  
- 資格不要という人もいますが、幅広い知識を得られるので非常に有用です。スキルの証明になります。  が、合格すれば十分というわけでなく、実務に向けたスタートラインに立てたという感覚。あと体系立てて学べるのが良い所。
- 興味のある分野以外も強制的に学ぶので知識が偏らなくて良い。
- 社内でAI民主化を推進するときに、自分でモデルを組めるスキルがある事は大事だと思います(説得力が上がる)。

## 1. JDLA E資格について  
- 一般社団法人日本ディープラーニング協会(略称：JDLA）が実施しているディープラーニングの試験。G検定(ジェネラリスト向け)とE資格(エンジニア向け)がある。
https://www.jdla.org/certificate/  

- G検定
ディープラーニングの基礎知識を有し、適切な活用方針を決定して、事業活用する能力や知識を有しているかを検定する。
- E資格
ディープラーニングの理論を理解し、適切な手法を選択して実装する能力や知識を有しているかを認定する。
※E資格はJDLA認定講座を受講しないと受験できない。講座は結構高額(~30万)だが最近値下がりして条件によって10万以下の講座もあり

## 2. 「E資格（エンジニア資格）2021#1」結果発表(抜粋)  
https://prtimes.jp/main/html/rd/p/000000080.000028865.html


合格率は例年より約10%高く、平均得点率は例年より若干高め。コロナの影響で2020#2が中止になったので受験者が増えたせい？？

|  開催日  |  申込者数  |  受験者数  |  合格者数  |  合格率  |
| ---- | ---- | ---- | ---- | ---- |
|  2021#1 |  1723  |  1688  |  1324  |  78.44%  |  


| 科目 | 応用数学 | 機械学習 | 深層学習 | 開発環境 |
| ---- | ---- | ---- | ---- | ---- |
| 平均得点率 | 69.65% | 72.14% | 67.80% | 78.39% | 78.44% |

私の場合、応用数学と開発環境は平均より少し上、機械学習と深層学習は、ほんの少し上という程度なので合格ラインの参考に。

50代の合格者ってたった6%程度です。まあそりゃそうですよね(^^;

## 3．私の受験状況
### 3.1 バックグラウンド
高専→情報工学部3年に編入→就職→社会人学生で修士号取得(ITでない)。
現在、IT企業ではない会社のIT部門に所属。プログラミングに抵抗はないがメジャーな言語には縁がない。Pythonおよび機械学習は数年前から独学で勉強開始し、下記講座等に参加。線形代数や確率統計って習ってたっけ？というレベル。

### 3.2学習方法
- 講座：
キカガク ディープラーニングハンズオンセミナー＋補講動画 
https://www.kikagaku.co.jp/  

- 書籍：
徹底攻略ディープラーニングE資格エンジニア問題集
https://book.impress.co.jp/books/1118101176
人工知能プログラミングのための数学がわかる本
https://www.kinokuniya.co.jp/f/dsg-01-9784046021960
ゼロから作るDeep Learning ① Pythonで学ぶディープラーニングの理論と実装
ゼロから作るDeep Learning ② 自然言語処理編
Pythonで学ぶ強化学習　入門から実践まで

下の3つは知りたい所を一部だけ見るという感じでした。逆にこれをきちんと読める人は簡単に合格できると思います。  

- ネット記事  
Qiitaに限らずいろんな記事を参考にさせて頂きました。質問させて頂いた方、ありがとうございました。

### 3.3 学習期間
実質3~4ヶ月程度 (11月初旬~2月中旬)
・少し特殊で講座を受けたのは2020年5月だが8月の試験(2020#2)が中止になったのでだらだらしていたら年末になり焦って勉強開始。最後の1~2か月は週5、1~2時間くらいかと。

# 4．まとめと感想(&ぼやき)
- 合格だけを目指すなら、試験はとにかく時間が足りないので難しい&時間がかかるものは適当に答えて次へ。
- 問題はシラバスの順番に出ない。最初から私にとっての難問(生成モデル)で出鼻をくじかれたので慌てないように。全集中で。
- 試験PCのモニターが横長だと文章がとても読みにくい。
- 数式は意味を理解すると覚えやすい。とは言え難しすぎる。他の方はこれを普通に理解できるのだろうか？
- 合格できたが十分理解しているとは思えない。さらなるスキルアップが必要。でも結果と、とにかくやったという事に十分満足 !!
- 今後は社内のAI民主化に向けて頑張ります。
CloudFormationを運用する上で知っておきたかったこと

運用してて困った・知っておきたかったことをつらつら書きます
自分が運用してた範囲なので内容は散発的です

基本的にaws-cdkで運用してきてるのでyml/jsonに関する事情はあんまり触れないです

# tl;dr

[公式のユーザーガイド](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/Welcome.html) を隅々まで読もう

# DeletionPolicyについて

[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-attribute-deletionpolicy.html)

## 問題になるケース

- リソースの削除をしたかったのにDeletionPolicyがデフォルトでRetainになってるケースがあり、リソースが残り続けてしまう
- うっかり論理名を変更しちゃってデプロイした結果、削除されてほしくないリソースに対して削除→作成が走ってしまう

## 知っておきたかった

- そもそもDeletionPolicyという概念が存在する
- DeletionPolicyがデフォルトで設定されているリソースがある
  - `AWS::RDS::DBCluster` など
  - aws-cdkの場合、aws-cdkのデフォルト実装でRetainになってテンプレートが生成されるリソースがある（ `AWS::S3::Bucket` などが該当）

# Stackの削除保護について

[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/using-cfn-protect-stacks.html)

## 問題になるケース

- 削除保護をしてないStackを誤って削除してしまう
  - 恐怖

## 知っておきたかった

- 存在を知っておきたかった
- 知ってる諸氏は必ず設定しましょう

# スタックのリソースの更新動作について

[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html)

## 知っておきたかった

- リソース更新時の振る舞いとして以下の3つがあること
  - 中断を伴わない更新(Update with No Interruption)
  - 一時的な中断を伴う更新(Updates with Some Interruption)
  - 置換 (Replacement)
- 状態を持たないリソースは Replacement の変更をしても問題になりにくい
  - 例えばSecurityGroupなどは作り直しになっても問題がない
  - DBClusterやS3::Bucketなどのような状態を持つリソースが Replacement を伴う変更が発生する場合は特別な対応が必要になる

# リソース同士の依存関係について

[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-attribute-dependson.html)

## 知っておきたかった

- 基本的にちゃんとCloudFormationの記述をしていればdependsOn属性が必要になることはない
- 逆に上記ドキュメントにないケースで必要になった場合そもそも書き方が悪い可能性がある
  - CloudFormation側がリソース間の依存関係を解決できるような記述方法に直せるなら直すべき
  - （CloudFormationしぐさみたいなところはありそう）

---

# CFn管理外リソースとの付き合い方

## 知っておきたかった

- CFn管理外リソースに依存する場合、Stackを分ける
    - 例えばECSクラスタ、ECSタスク定義、タスク定義をキックするCloudWatchEventというリソースがあり、ECSタスク定義だけがCFn管理外だった場合、ClusterStack,EventStackの用に分離しておく
    - そうすれば、CFnとコンテナのデプロイをそれぞれ独立して運用できる

ECSの例だとわかりやすいが、あまり変更がないタイプのリソース（AWSアカウントをまたいだAssumeRoleのようなもの）だと見落としがちなので注意

## 問題になるケース

- CFn管理外リソースに依存する・されるようなStack定義になっていると、0ベースでStack構築ができなくなる
  - たとえばECSタスク定義がないとそのタスク定義に依存するCloudWatchEventは定義できないので、もしECSクラスタとCloudWatchEventを両方同じStackで定義しているとStack構築を0から出来ない

# （番外）aws-cdkで定義した論理名について出力されたテンプレート上ではアンダースコアが消し飛ばされている

## 問題になるケース

- 論理名に依存した処理（例えば `aws ec2 describe-instances` コマンドで特定のインスタンスを取得したい、など）でaws-cdkの実装上で定義した名前が使えない

## 知っておきたかった

- 論理名はキャメルケースで定義するべし
  - しれっと変換するくらいなら例外吐いて止まってほしい


# Outputsの使い方・export/import/get_export
# 各種Stackの更新ステータスで取るべき対応

（時間切れでした）
（気が向いたら更新したい）

---

以上でした
Pythonの環境構築（Windows）

# Pythonのインストール
以下のリンクから、任意のバージョンのPythonをダウンロードしてください。

[https://www.python.org/](https://www.python.org/)

ダウンロードが完了したら、そのファイルを実行してください。

※途中で「Add Python X.X to PATH」というチェックボックスが表示されますので、必ずチェックをしてください。

コマンドプロンプトに以下のコマンドを入力して、Pythonがインストールされたかどうかを確認してみましょう。

```
python --version
```

`Python X.X.X`と表示されれば、正常にPythonがインストールされています！
RubyonRails再学び直し1-bundle installのエラー-

もう一度学び直す。

前回までの反省
本やUdemyによるインプットが中心でアウトプットが足りていなかった。
プログラムよりQiita眺めている時間の方が多くなっていた。
もっとコードを書き、アウトプット。Github、Herokuに上げることをめんどくさがらずにやります。

#エラーメッセージから逃げない
rails newで普通に壁にぶち当たった。bundle installが出来ないと。
足りないgemである`gem install racc -v '1.5.2'`をインストールしても完了しない。

今までなら、検索してどうすればいいかここで探していたが、ターミナルからメッセージでログファイルを見ろと教えてもらったのでそうすることにする。

```
less [file]
```
で参照する。

```
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
checked program was:
```

初めて見るので全くわからん。
解決策
https://o-tyazuke.hatenablog.com/entry/2018/05/03/121739
http://linesnova.hatenablog.com/entry/2015/06/09/213259


`xcode-select --install`はMacのシステムを変えるので、使いたくない。というか、そんなに大ごとなのか？

https://teratail.com/questions/109244
rbenvとrubyのバージョンがあっていないっぽい？
でもシステムのデフォルトのバージョンを変えるのは嫌だな。

https://qiita.com/w7tree/items/0860e2856f2429b20eee
gemがrbenvで切り替えてもシステムデフォルトの方が使われるらしい？

というわけで

#gemのパスやインストール済gemを確認
参考：https://qiita.com/h5y1m141@github/items/74029cab9706971c8dbe

```
ruby -v
ruby 2.5.8p224
```

```
rbenv global
2.6.6
```

```
gem environment
RUBYGEMS VERSION: 3.1.4
RUBY VERSION: 2.5.8
```
rbenv globalより`rbenv version`の方がいい。

 >rbenv global の出力は「今のディレクトリでのRubyのバージョン」ではなくて、「 .ruby-version ファイルによるバージョン指定がない時に使われるRubyのバージョン」です。
このディレクトリでのrbenvが管理しているRubyのバージョンを知りたい場合には、 rbenv version コマンドや rbenv local コマンドを実行すると良さそうです。 rbenv version コマンドなら「なぜそのバージョンになっているか」が表示されるので、そちらのほうがこの場合は良いかも

#質問すると返答が…
https://qiita.com/kodai_0122/items/56168eaec28eb7b1b93b
でやっぱりターミナルのシステムを変えた方がいいらしい。

```
The compiler failed to generate an executable file. (RuntimeError)
You have to install development tools first.
```

 >raccのコンパイルに失敗していますね。(解説) Rubyのライブラリは多くがRubyで書かれていますが、raccなど一部のライブラリはC言語で書かれています(Cでないとできないことや、Cのほうが得意なことがあるため)。で、C言語をコンパイルするのに要るのがdeveloment toolsです。

`xcode-select --install`したらbundleinstallまで無事に完了！
PCIデバイスを仮想マシンに割り当てる

##パススルーを有効にするスクリプト
あとでWhere条件式をかえてNVMeだけにする予定。

ひとまず最初に`Connect-VIServer`


```
$esxName = 'MyEsx'

$esx = Get-VMHost -Name $esxName
$ptMgr = Get-View -Id $esx.ExtensionData.ConfigManager.PciPassthruSystem
$config = @()
$ptMgr.PciPassthruInfo | where{$_.PassthruCapable -and -not $_.PassthruEnabled} | %{
    $ptConfig = New-Object VMware.Vim.HostPciPassthruConfig
    $ptConfig.Id = $_.Id
    $ptConfig.PassthruEnabled = $true
    $config += $ptConfig
}
if($config){
    $ptMgr.UpdatePassthruConfig($config)
}
else{
    Write-Host "No Passthru capable devices found"
}
```

ホストを再起動して、


##テンプレートから仮想マシンをデプロイして、デバイスを追加

```
テンプレートからデプロイ
$NewVM = New-VM -Name 'VMNAME' -VMHost 'HOSTNAME' -OSCustomizationSpec 'OSTEMPLATE' -Template 'TEMPLATENAME' -Datastore 'DATASTORE'

$ESX = get-vmhost -name esxi01.aaa.local

$ScsiDevice = Get-PassthroughDevice -VMHost $ESX -Id "Uid"
Add-PassthroughDevice -VM $NewVM -PassthroughDevice $ScsiDevice
```


##参考文献
https://thinkit.co.jp/story/2011/02/24/2008
https://qiita.com/nori4k/items/3028d4ba349bf53b63d5
https://communities.vmware.com/thread/566477
VideoTrackReaderが削除されるようなのでMediaStreamTrackProcessorを使う

# 概要
WebCodecsにて登場したAPIである[`VideoTrackReader`](https://wicg.github.io/web-codecs/#videotrackreader-interface)はVideoTrackからVideoFrameを取得することができるようになるクラスです。
ですが、[`MediaStreamTrackProcessor`](https://w3c.github.io/mediacapture-insertable-streams/#track-processor)という別のAPIが良いという内容の[Chromiumのissue](https://crbug.com/1157610)や[GitHubのissue](https://github.com/WICG/web-codecs/issues/131)が存在し、M91で`VideoTrackReader`は削除されるようです。そのため、新しいAPIを使って書き換えてみます。

# 具体的にやること
現在のVideoEncoderがチャンクを生成するまでの流れは以下のとおり

1. `navigator.mediaDevices.getUserMedia()`でカメラからMediaStreamを取得
2. `getVideoTracks()`でMediaStream内のVideoTrackを取得
3. `new VideoTrackReader()`でVideoTrackからVideoFrameを取る準備をする
4. VideoTrackReaderのコールバック関数内でVideoEncoderへVideoFrameを渡す

今回はこの3,4の手順をMediaStreamTrackProcessorを使うように変更します。
従来のVideoTrackReaderを使ったコードを簡略化すると以下のようになります。

```js:VideoTrackReader.js
const stream = await navigator.mediaDevices.getUserMedia();
const [videoTrack] = stream.getVideoTracks();
const videoEncoder = new VideoEncoder();
await videoEncoder.configure();

const videoReader = new VideoTrackReader(videoTrack);
videoReader.start((videoFrame) => {
  videoEncoder.encode(videoFrame, {keyFrame: false});
});
```

MediaStreamTrackProcessorを使うように変更すると以下のようになります。

1. `navigator.mediaDevices.getUserMedia()`でカメラからMediaStreamを取得
2. `getVideoTracks()`でMediaStream内のVideoTrackを取得
3. `new MediaStreamTrackProcessor()`でVideoTrackの処理をする準備をする
4. MediaStreamTrackProcessorからreaderを取得する
4. readerの処理をするwhile文のループ内でVideoEncoderへVideoFrameを渡す

```js:MediaStreamTrackProcessor.js
const stream = await navigator.mediaDevices.getUserMedia();
const [videoTrack] = stream.getVideoTracks();
const videoEncoder = new VideoEncoder();
await videoEncoder.configure();

const processor = new MediaStreamTrackProcessor(videoTrack);
const frameReader = processor.readable.getReader();
const reader = async () => {
  while (true) {
    const { done, value: videoFrame } = await frameReader.read();
    if (done) return;
    videoEncoder.encode(videoFrame, {keyFrame: false});
  }
};
reader();
```

VideoTrackReaderではコールバック関数に処理を書いていましたが、MediaStreamTrackProcessorではStream APIになっており、WebTransportなどと同じようなAPIで利用できるようになっています。
違いとして引数でVideoFrameを取得していたのが`read()`で取得するようになっています。
注意点としてはコールバックではなくasyncな関数内で処理をしている点です。
もし以下のようにVideoTrackReaderの処理と同じ場所に書くと無限ループになりその後ろに処理を書いていても動かなくなります。

```js
const frameReader = processor.readable.getReader();
while (true) {
  const { done, value: videoFrame } = await frameReader.read();
  if (done) return;
  videoEncoder.encode(videoFrame, {keyFrame: false});
}
// ここ以降はreadしている限り実行されない
```

## 起動時の注意点
WebCodecsのAPIを有効にするにはChromeの起動時のフラグに`--enable-blink-features=WebCodecs`が必要でしたが、MediaStreamTrackProcessorを利用するには代わりに`--enable-blink-features=WebCodecs,MediaStreamInsertableStreams`をつける必要があります。
openvino/RaspberryPi

#RaspberryPiでopenvino

参考記事
https://jellyware.jp/kurage/openvino/c03_setting.html
https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_raspbian.html

https://download.01.org/opencv/
よりツールキットをインストール(最新版推奨)

インストール先ディレクトリ

```
sudo mkdir -p /opt/intel/openvino
```


解凍

```
sudo tar -xf さっきダウンロードしたファイル --strip 1 -C /opt/intel/openvino
```

サンプルコードをビルドするためのソフトをインストール

```
sudo apt install cmake
```


環境変数を反映

```
source /opt/intel/openvino/bin/setupvars.sh
```

起動時に上を実行させるためにbashに書き込み

```
echo "source /opt/intel/openvino/bin/setupvars.sh" >> ~/.bashrc
```

USBルールに追加

```
sudo usermod -a -G users "$(whoami)"
```
```
sh /opt/intel/openvino/install_dependencies/install_NCS_udev_rules.sh
```

##サンプルコードを実行
作業フォルダ作成

```
mkdir build && cd build
```

ビルド

```
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=armv7-a" /opt/intel/openvino/deployment_tools/inference_engine/samples/cpp
```
```
make -j2 object_detection_sample_ssd
```

動物認識プログラムをダウンロード

```
git clone https://github.com/openvinotoolkit/open_model_zoo
```
```
cd open_model_zoo/tools/downloader
```
```
python3 downloader.py --name face-detection-adas-0001
```
```
cd ~/build
```
画像を~/buildに置く

実行

```
 ./armv7l/Release/object_detection_sample_ssd -m ./open_model_zoo/tools/downloader/intel/face-detection-adas-0001/FP16/face-detection-adas-0001.xml -d MYRIAD -i 画像.jpg
```

~/buildに画像ファイルが出力されているので確認できる。
【AWS】CloudFormationの概要を5分で理解する

|　　　　　　　　  　　　　　　　　   　　　　　　　　　　　　　　　　　　　　　　　　　|
|:-:|
|![CF.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1197988/0fd39ec8-59c1-3e4c-4a28-3e5db911606a.png)|

アプリケーション開発で実践されているような、コード管理・作業の自動化をインフラ構築にも導入し、インフラ構築作業内容をコードで記述して管理できるようにしたIaC(Infrastructure as Code)という考え方があります。

参考
https://www.sbbit.jp/article/cont1/39402


そしてAWSで、IaCを実現したサービスがCloudFormationです。

# 想定している読者
- CloudFormationについてほとんど知識がない方。
- CloudFormationの概要や利用することのメリットを知りたい方

# 本記事のゴール
- CloudFormationについての概要が理解できること
- CloudFormationを利用することのメリットが理解できていること

# そもそもCloudFormationとは？
- AWS内の全てのリソースを自動でプロビジョニングできるAWSサービス
- 構成定義ファイルをjson,yaml形式で記述可能
- CloudFormationを利用することに対する料金は発生しない
- CloudFormationを利用して作成したリソースに対して、手動で作成した場合と同様の料金が発生

# 重要な用語
- テンプレート
リソースの構築内容を定義するファイル。それぞれのリソースの依存関係もこのテンプレートに記述される。また、json,yamlの2種類の形式で記述可能。（2020/3/12現在）

- スタック
テンプレートを利用してCloudFormationによってプロビジョニングされるAWSリソースの集合体。スタックを削除すればスタック内の全てのリソースも削除される。また、テンプレートを更新した場合に、差分のあるリソースのみに対して変更を加えることも可能。

# ユースケース
- AWSのリソースを効率的に構築したい
- 開発・テスト・本番など、同一の構成の環境を複数構築したい
- 環境構成をバージョン管理したい

# CloudFormationを利用するメリット

## 素早くリソースを構築できる
手動で構築する場合と比べて圧倒的に短い時間でリソースを構築することが可能です。
ざっくりとした比較をすると、慣れた人であっても30分ぐらい時間がかかるような作業であっても、CloudFormationを利用すれば実行1分、構築まで3分ぐらい短時間で構築が完了してしまうようなイメージです。

## 何度でも同じ構成を再現できる
手動で作業をすると、どうしても手順にミスなどが発生しますが、CloudFormationを実行することで、全く同じ構成がリソースを構築できます。本番環境とテスト環境などで、同じ構成を実現したい場合に有効です。

## インフラストラクチャの運用をバージョン管理できる
インフラ環境の運用をコードで管理しているため、同じ作業であれば、以前実行したコードをそのまま流用できます。また、環境構成に変更が生じた場合には、該当箇所のみコードを修正し、修正版の環境を構築できます。これにより、インフラ環境のバージョン管理が容易に実現できます。

## 不要になったリソースを確実に削除できる
手動でリソースを削除する場合、どうしても依存関係が複雑で消すのに苦労したり、消し忘れが発生します。有料のリソースを利用している場合、当然消し忘れた分の費用も発生します。しかし、CloudFormationはスタック単位でリソースがまとまっており、スタックを消せば、スタック内の全てのリソースが削除されます。これによって、不要になったリソースを確実に削除することができます。
git commitしたら"Waiting for your editor to close the file..."と怒られた話

こんにちは、JeffTechです。

# エラー文
```bash
$ git commit
hint: Waiting for your editor to close the file... code --wait: code: command not found
error: There was a problem with the editor 'code --wait'.
Please supply the message using either -m or -F option.
```

# 説明
私はGitのデフォルトエディタにVScodeを使用しているのですが、`git commit`をした後、COMMIT_EDITMSGファイルにてコミットメッセージを入力しました。
その後アクシデントが発生して、COMMIT_EDITMSGファイルを閉じないままvscodeを終了してしまったので、正しくコミットできていなかったので再度`git commit`したら怒られてしまいました。
`Waiting for your editor to close the file...`エディタがファイルを閉じるのを待っています。。。　はい、ですよね笑


# エラー解決法
最初にGitのデフォルトエディターをVScodeにしたと思いますが、全く同じことをしていきます。

まずはコマンドパレットを開きましょう。
- Mac：「command + shift + p」
- Windows：「Ctrl + shift + p」

開いたら、下記コマンドを実行してください。

```
> Shell Command: Install 'Code' command in path
```

次にターミナルから下記のコマンドを実行してください。

```bash
$ git config --global core.editor "code --wait"
```


# 最後に
これで私の場合は治りました。
こんなミスはめったにしないと思いますが、なっちゃった方はぜひ試してみてください。

少しでも役に立った！という時は、いいねをポチッとして
フォローしてくださると嬉しいです、、、笑

役に立たなかった時は、怒らないでコメント頂けますと幸いです笑

Twitterもやってますので、よかったら見てみてくださいね！
https://twitter.com/jefftechsaku
jupyterlab で画像を 2D 数値データとして plot したいときのメモ

## 背景

Jupyterlab で RAW 画像データの値を見たい.
画像処理とかしたあとの値の違いとかを見たい.

などで, 画像データを 2D 数値マップとしてみたいときがあります.

## カラーバーつき plot

単に imshow(グレースケール画像)だとどの色がどの値に対応するかがわかりません.

colorbar をつける必要がありますが, `imshow(cbar=True)` みたいにお手軽ぺろっとできるわけではなくて, 一旦 subplots を作る必要がありました.
 
```
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
pos = ax.imshow(img)
fig.colorbar(pos)
```

## 値の範囲を指定したい.

HDR 画像のようにダイナミックレンジが大きい画像で特定の範囲だけみたいときなど.

`imshow(img, vmin=0.5, vmax=100)` のように vmin, vmax で範囲を指定できます.
 
## interactive plot モード

```
%matplotlib widget
```

をつけることで, マウス位置のピクセル値を出したりできる.
ただし notebook ごとに一個しか表示できないっぽいので, 複数画像プロットしたいときには使えない.
Pointを受信するDisplay pluginを作る

【[rviz2プラグインの作り方 トップページへ](https://qiita.com/Kotakku/items/d3510c1ca505b4c0aa1e)】

# 実行例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207366/3bb04610-47c9-ce1a-952b-63a861c4c8c6.png)
[作成したTool plugin](https://qiita.com/Kotakku/items/0649fe5d1cd70a677ceb)でpublishしたトピックを使用して矢印を動かす例

# ROS1版
こちらのコードをrviz2用に書き直します
[ROS講座111 Pointを受信するrviz display pluginを作る](https://qiita.com/srs/items/9977b8493e1a83cf764f)

# ROS1からの主な変更点
## point_display.hpp

https://github.com/Kotakku/sample_rviz_plugins/blob/main/src/point_display.hpp

受け取るトピックの型を直します

```.hpp
    // void processMessage(const geometry_msgs::PointStamped::ConstPtr &msg);
    void processMessage(geometry_msgs::msg::PointStamped::ConstSharedPtr msg) override;
```

矢印のオブジェクトの名前空間を直します

```.hpp
    //boost::shared_ptr<rviz::Arrow> vis_arrow_;
    std::shared_ptr<rviz_rendering::Arrow> vis_arrow_;
```

```properties::``` が入ったので追加します

```.hpp
    rviz_common::properties::ColorProperty *color_property_;
    rviz_common::properties::FloatProperty *alpha_property_;
```

## point_display.cpp

https://github.com/Kotakku/sample_rviz_plugins/blob/main/src/point_display.cpp
PHP classの基本　例外処理について

#例外処理について覚えていく

###例１）まずエラーを出す

```php

<?php

class Entree
{
    public $name;
    public $ingredients = [];

    public function __construct($name, $ingredients)
    {
        if (!is_array($ingredients)) {
            throw new Exception('$ingredientsは配列を指定してください');
        }


        $this->name = $name;
        $this->ingredients = $ingredients;
    }


    public function hasIngredient($ingredient)
    {
        return in_array($ingredient, $this->ingredients);
    }
}

//ドリンクインスタンス
$drink = new Entree('1杯の牛乳','milk');
if($drink->hasIngredient('milk')){
    print 'うまい';
}
```
上記コードは

```
Fatal error: Uncaught Exception: $ingredientsは配列を指定してください in /Applications/MAMP/htdocs/test/class1.php:11
Stack trace:
#0 /Applications/MAMP/htdocs/test/class1.php(34): Entree->__construct('1\xE6\x9D\xAF\xE3\x81\xAE\xE7\x89\x9B\xE4\xB9\xB3', 'milk')
#1 {main}
  thrown in /Applications/MAMP/htdocs/test/class1.php on line 11
```
こういったエラーを出す。
原因はドリンクインスタンスの第二引数で配列を使用していない為。

この件については過去記事
[PHP classについて（基本）コンストラクタ使い方 / staticを使用したメソッド呼び出し / selfの使用 / 例外処理について](https://qiita.com/H-Toshi/items/dbe7a1f05a55c10161b9)

[PHP try{}catch, throw, Exceptionの考え方（基本）
](https://qiita.com/H-Toshi/items/297d0c8fda92e85b18a6)

にて説明。

こういったエラーに対応する為には
**１.　例外を発行する可能性のあるコードをtryブロック内に入れる
２. 問題に対応する為に、例外を発行する可能性のあるコードの後ろにcatchブロックを使用する。**

###修正例）

```php


//ドリンクインスタンス
try{
    $drink = new Entree('1杯の牛乳','milk');
    if($drink->hasIngredient('milk')){
        print 'うまい';
    }
}catch(Exception $e){
 print "ドリンクは結果を表示出来ません。" .$e->getMessage();
}

結果
/*
ドリンクは結果を表示出来ません。$ingredientsは配列を指定してください
*/
```
ドリンクインスタンス部分を上記のようにtry{}catch(){}で囲む
するとエラーの結果が分かりやすいエラー文になる。
Logを受信してOverlay表示する

【[rviz2プラグインの作り方 トップページへ](https://qiita.com/Kotakku/items/d3510c1ca505b4c0aa1e)】

```rcl_interfaces::msg::Log``` を受け取って表示するプラグインを作ります

# 実行例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207366/e4844f0e-efa5-3632-7aaf-ee3e460d953c.png)

# ROS1版
こちらのコードをrviz2用に書き直します
[ROS講座118 overlayで表示するのrviz display plugindを作る](https://qiita.com/srs/items/343f859d7b741ccd5711)


# ROS1からの主な変更点
## log_display.hpp

https://github.com/Kotakku/sample_rviz_plugins/blob/main/src/log_display.hpp

関数を追加

```.hpp
    virtual void onInitialize();
    virtual void reset();
```

トピックの受信を```RosTopicDisplay```で行います

```.hpp
class LogDisplay : public rviz_common::RosTopicDisplay<rcl_interfaces::msg::Log>
{
private:
    // 以下は使用しない
    // ros::NodeHandle nh_;
    // ros::Subscriber log_sub_;
};
```

## log_display.cpp

https://github.com/Kotakku/sample_rviz_plugins/blob/main/src/log_display.cpp

以下のファイルの読み込みを忘れずに
Dashing環境(たぶんEloquentでも)ではこのファイルがincludeディレクトリに存在せずincludeできないので
Githubから持ってくるかローカル環境の中にある```render_system.hpp``` を```/opt/ros/[distribution]/include/rviz_rendering``` 以下に配置してください


```.cpp
#include <rviz_rendering/render_system.hpp> // 重要
```


```.cpp
void LogDisplay::onInitialize()
{
    rviz_rendering::RenderSystem::get()->prepareOverlays(scene_manager_); // 重要
    RTDClass::onInitialize();
}

void LogDisplay::reset()
{
    RTDClass::reset();
}
```

```prepareOverlays()``` の呼び出しを追加しています。これがないとrviz上で描画処理が走らないので何も表示されません。