OmniAICreator/Qiita-1.07M huggingface dataset:
FetchAPIを使用してJSONデータをPOSTリクエストする

エンタメ系企業の社内もろもろを担当しているakibinです。

Twitterアカウント @AkibinMusic
[Youtubeチャンネル](https://www.youtube.com/channel/UC-JOpwEnJn3gCrUA4NdCYgg)

今年のM1は声が大きいコンビが多かった。テレビのスピーカーがビリビリいってましたよ。

# 内容
Markdownのサービス間のデータ移行として、JSONデータを移行先サービスのAPIにPOSTする必要があり、また自分でプログラムを作らないといけなかったので、Javascriptで作ってみました、簡単なやつですが。

# 色々準備
#### 【環境】
macOS Catalina

#### 【Node.jsをインストール】
Note.jsにFetchAPIというHTTPリクエストを送れるモジュールがあるようなので、Node.jsをインストールする必要があります。
[こちら](https://qiita.com/kyosuke5_20/items/c5f68fc9d89b84c0df09)のページなど、Homebrewからインストールと、パスを通す設定も書いてあるのでとてもわかりやすいです！

#### 【FetchAPIをインストールする】
npmでFetchAPIのモジュールをインストールします。

```bash:
npm i node-fetch --save
```

#### 【トークンを取得しておく】
移行先サービスにデータインポートするためのトークンが提供されているはずなので、そのトークンを取得しておく。

# 作ったプログラム
単純に各パラメータとデータのハッシュを作って、JSONデータとして投げつけています。

```js:
'use strict';

// 各データを取得
const send_title = "タイトルテスト";
const send_body = "本文テスト";
const send_memo = "メモテスト";
const send_tags = [{"name":"タグテスト"}];

// POSTするパラメータとデータ
var data = {
    title:send_title,
    body:send_body,
    memo:send_memo,
    tags:send_tags
};

// FretchAPIオプション
const param  = {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": "Bearer token" // ここに取得したトークンをコピペ
    },
  
    // リクエストボディ
    body: JSON.stringify(data)
  };

// POSTリクエスト送信
const fetch = require('node-fetch');

fetch("URL", param) // 移行先のサービスのAPIのURLをコピペ
  .then(response => response.json())
  .then(data => {
    console.log('Success:', data);
  })
  .catch((error) => {
    console.error('Error:', error);
});
```

FetchAPIを使用する場合は以下を追加する必要がありますので。

```js:
const fetch = require('node-fetch');
```

あとは、JSONファイルから必要なパラメータを取って来る感じに更改して、ガンガンこのプログラム回せばデータ移行完了！

よし！！
【Swift】アプリ内にデータを保存する UserDefaults を使う

# UserDefaults とはなにか

掲題のとおりアプリ内にデータを保存することができる。
PHPでいうとこのセッションと違ってアプリを端末から消去しない限り半永久的に残る。
ウェブ開発からアプリ開発をやってみたら「そっか、こういう場合でもデータベース使わなくてもいいんだ。。」と思って気が楽だった。

## 保存する

```swift
UserDefaults.standard.set(変数とか保存したいもの, forKey: 文字列)
```

## 取り出す

```swift
if UserDefaults.standard.object(forKey: 文字列) != nil {
    // キーの中身が空でなければ変数に入れる
    変数 = UserDefaults.standard.object(forKey: 文字列)
}
```

上に書いたとおりだが、アプリを閉じて再起動しても保存したデータはちゃんと表示される。感激！
Google cloud platform(GCP) でのstartup-scriptにtmuxを動かしたいとき。


#問題点

単純にtmuxを使うために
startup-scriptに
tmux new -s hogehoge
で動かそうとすると
root権限での動作のため
>sudo journalctl -u google-startup-scripts.service

に

```
Dec 22 16:41:56 <product_name> systemd[1]: Starting Google Compute Engine Startup Scripts...
Dec 22 16:41:58 <product_name> startup-script[2058]: INFO Starting startup scripts.
Dec 22 16:41:58 <product_name> startup-script[2058]: INFO Found startup-script in metadata.
Dec 22 16:41:58 <product_name> startup-script[2058]: INFO startup-script: open terminal failed: not a terminal
Dec 22 16:41:59 <product_name> startup-script[2058]: INFO startup-script: no server running on /tmp/tmux-0/default
Dec 22 16:41:59 <product_name> startup-script[2058]: INFO startup-script: Return code 1.
Dec 22 16:41:59 <product_name> startup-script[2058]: INFO Finished running startup scripts.
Dec 22 16:41:59 <product_name> systemd[1]: google-startup-scripts.service: Succeeded.
Dec 22 16:41:59 <product_name> systemd[1]: Finished Google Compute Engine Startup Scripts.
```

というログが残ります。

ならば

#### *実行させるユーザーを変えてやればいい*

カスタムメタデータのstartup-scriptに

```
#! /bin/bash
sudo -u <user_name> tmux new-session -s hogehoge -d
tmux send-keys -t hogehoge:0 ls
```

を設定することで、実行させるユーザーを指定して、
指定した名前のtmuxを起動させることができる。

日本語での情報がほぼなかったのでここに記す。


### 参考

- [シェル-tmuxオープンターミナルが失敗しました：ターミナルではありません-スタックオーバーフロー](https://stackoverflow.com/questions/25207909/tmux-open-terminal-failed-not-a-terminal)
- [起動スクリプトの実行  |  Compute Engine ドキュメント  |  Google Cloud](https://cloud.google.com/compute/docs/startupscript?hl=ja#console)
- [【sudo】Linuxで指定したユーザーでコマンドを実行する | UX MILK](https://uxmilk.jp/53095)
rubyのformについて


#form_for
Railsでフォームタグを作成できるメソッド
ユーザの登録や情報の更新機能はform_for、検索機能はform_tag

##form_forの引数
引数にはモデルのインスタンスを指定。
※モデルのインスタンスとは、データベースに保存したいクラスのインスタンス。

```erb

<%= form_for(@user) do |f| %>
  <%= f.text_field :name %>
  <%= f.submit %>
<% end %>
```
`form_for`では`form_tag`のようにパス先の指定をしない。

```rb

def new
  @user = User.new
end

def edit
  @user = User.find(params[:id])
end
```
コントローラで作成したインスタンスが`newメソッド`で作成され、情報を持っていなければ`createアクション`、すでに情報を持っていれば`updateアクション`等に割り振ってくれる。

##form_forでの投稿フォームの作成の仕方

「f.htmlタグ名：カラム名」という風に記載する。

```erb

<%= form_for(@user) do |f| %>
  <%= f.text_field :name %>
  <%= f.submit %>
<% end %>
```
上記の例だと`userテーブル`の`nameカラム`に保存される。

##form_forで使用できるhtmlタグ
<img width="742" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597913/e6291f06-54f0-d185-f8d4-dcbcbe57b507.png">



####・form_tag
検索フォームのようなフォームはデータベースが必要ではないため、form_tagを使用する。

####・urlオプション
<%= form.submit %>を押した時のアクションを指定できる。

```erb

<%= form_for @fruit, url: fruit_bulk_create_path do |form| %>
<%= form.label :name %> <%= form.text_field :name, id: :fruit_name %>
<%= form.label :description %> <%= form.text_area :description, id: :fruit_description %>
<%= form.submit "一括登録" %>
<% end %>
```

上記のコードでは「form.submit」を実行すると、「fruit#fruit_bulk_create」アクションが実行される。
CWLのインプットにwildcard(glob)を使いたい

# 背景

- 2021/01/13 追記
- 2021/03/08 コマンドライン上で実行する方法を追記

CWL(Common Workflow Language)で作られたスクリプトは、`type: File[]`とすることで複数ファイルを入力パラメータとして入力することが可能です。
ただし、*.txtのようにwildcard(glob)を入力とした実行は、CWLでは考えられておらずユーザー側で対処する必要があります。

# 解決策

## 1. 変数に配列として代入後、引数付きで変数展開する

手軽に実行するならこれが一番手っ取り早いです。

```{bash}
a=(fuga.*)
cwltool hoge.cwl ${a[@]/#/--infile }
# cwltool hoge.cwl --infile fuga.1 --infile fuga.2 --infile fuga.3 という形になる
```

## 2. yml形式に出力してymlで実行

以下のワンライナーを実行するか、関数にして使ってください

```{bash}
ls *.* | awk '{print "- class: File"; print "  path: " $0}'
or 
ls2cwlyml() {　ls $@ | awk '{print "- class: File"; print "  path: " $0}'}
ls2cwlyml *.*
```
以下のように出力されるので、cwl実行用のymlに貼り付けてください

```{yml}
- class: File
  path: README.md
- class: File
  path: RT.png
- class: File
  path: log.txt
```


## 3. glob用のcltを使う

以下のCLTをWFに組み込んで使う。
出力が`type: File[]`になるので、次のCLTにファイルとして渡すことができます。

```{yml:glob.cwl}
#!/usr/bin/env cwltool
class: CommandLineTool
cwlVersion: v1.0
baseCommand: echo
arguments: 
    - "glob $(inputs.glob_glob.basename) in"
inputs:
    glob_root:
        type: Directory
        inputBinding:
            position: 1
    glob_glob:
        type: string
outputs:
    glob_file:
        type: File[]
        outputBinding:
            glob: $(inputs.glob_root.basename)/$(inputs.glob_glob)
requirements:
    InitialWorkDirRequirement:
        listing:
            - $(inputs.glob_root)

```

```{bash}
cwltool glob.cwl --glob_root hoge --glob_glob "*.txt"
```
Raspberry PiのHomebridgeとESP32でスマートスイッチを作る

この記事はスマートホーム自作 Advent Calendar 2020、23日目の記事です。
Raspberry PiにHomebridgeという、HomeKitに様々なものを対応させるソフトウェアとESP32を使って、HomeKitに対応した電灯スイッチを作っています。23日までに完成する予定だったのですが、まだ完成していないので予定と途中経過を書こうと思います。
なにか進捗があれば更新していこうと思います。


## 概要

- 3Dプリンターで印刷したマウンターで、サーボモーターとESP32を電灯のスイッチ付近の壁にマウント。
- Raspberry Pi上で動かしているHomebridgeでHomeKitに対応
- homebridgeのhttp-switch拡張でHomebridgeからESP32にhttpリクエストを送る
- ESP32はHomebridgeからのリクエストを受け取り、サーボモーターを動かす。

## ソフトウェア
三連スイッチなどにも対応するため、1という数字をつけています。

| リクエスト | メソッド | 説明                   |
| ---------- | -------- | ---------------------- |
| /on1       | GET      | オンにする命令         |
| /off1      | GET      | オフにする命令         |
| /status1   | GET      | 現在のステータスを返す |
### Homebridge
Homebridge本体と、[こちらのサイト](https://simple-was-best.com/blog-entry-homebridge-config-ui-x-intall.html)を参考に、Homebridge Config UI Xというプラグインもインストールしました。
とても便利なのでおすすめです。

また、ESP32とhttpで通信してスイッチを操作するのに、[homebridge-http-switch](https://www.npmjs.com/package/homebridge-http-switch)もインストールしました。


## ハードウェア

- サーボモーター
- ステータス切り替えボタン(将来的には照度センサーでステータスを検知も？)
- 手動切り替えボタン

スマホ以外から操作できないのは不便そうなので、手動で操作するようのスイッチもつけたいと思っています。
yumって？？

#はじめに

AWSにてデプロイするため、環境構築を行なっていましたが、yumコマンドを使用する機会があったので、備忘録のため記述します。

#yumコマンド

👉Linuxにおけるソフトウェア管理の仕組み。
👉MacOSで言う、「homebrew」と同じ役割。
👉yumコマンドを使用することで、yumの管理下にあるプログラムの
バージョンを管理したり、一括でアップデートしたりできる。

また、yumを学ぶ上で「パッケージ」と言う概念も出てきました。

#パッケージ

👉yumコマンドを使ってアップデートされるプログラムのこと
👉LinuxOS下におけるある役割・機能を持ったプログラムの集合
👉「ソフトウェア」や「ライブラリ」とも呼べるが、あくまでLinuxOSではプログラムの集合のことをパッケージと呼ぶ。
XSS CSRF まとめ

# XSS
- 攻撃の対象はブラウザ
- 攻撃内容は不正なJavaScriptの実行
    - ブラウザに保存されているユーザの情報を抜く
    - 不正な文字などを表示
- 対策は不正なJavaScriptを実行させないようにする
    - HTMLの出力の際に特殊文字をエスケープ

# CSRF
- 攻撃の対象はwebサーバ
- 攻撃内容はユーザになりすまして、webサーバにリクエスト
    - 商品の購入
    - コメントの書き込み
- 対策はユーザになりすませないようにする
    - 画面遷移前後でトークンチェック
    - ログイン直後にセッションを再発行


# 参考
https://qiita.com/att55/items/a50ca43adde206017525
[Swift] IntとDataの相互変換

Swift5で動作確認をしています。

# 実装
```Int+Data.swift
import Foundation

extension Int {
    var data: Data {
        var int = self
        return Data(bytes: &int, count: MemoryLayout<Int>.size).reversedData
    }
}

extension UInt8 {
    var data: Data {
        var int = self
        return Data(bytes: &int, count: MemoryLayout<UInt8>.size).reversedData
    }
}

extension UInt16 {
    var data: Data {
        var int = self
        return Data(bytes: &int, count: MemoryLayout<UInt16>.size).reversedData
    }
}

extension UInt32 {
    var data: Data {
        var int = self
        return Data(bytes: &int, count: MemoryLayout<UInt32>.size).reversedData
    }
}

extension UInt64 {
    var data: Data {
        var int = self
        return Data(bytes: &int, count: MemoryLayout<UInt64>.size).reversedData
    }
}
```

```Data+Int.swift
import Foundation

extension Data {
    var reversedBytes: [UInt8] {
        var values = [UInt8](repeating: 0, count: count)
        copyBytes(to: &values, count: count)
        return values.reversed()
    }

    var reversedData: Data {
        return Data(bytes: reversedBytes, count: count)
    }

    var uint8: UInt8 {
        UInt8(bigEndian: withUnsafeBytes { $0.load(as: UInt8.self) })
    }

    var uint16: UInt16 {
        UInt16(bigEndian: withUnsafeBytes { $0.load(as: UInt16.self) })
    }

    var uint32: UInt32 {
        UInt32(bigEndian: withUnsafeBytes { $0.load(as: UInt32.self) })
    }

    var uint64: UInt64 {
        UInt64(bigEndian: withUnsafeBytes { $0.load(as: UInt64.self) })
    }
}

```

# テスト

```Int+DataTest.swift
final class IntPlusDataTest: XCTestCase {
    func testToData() {
        XCTAssertEqual(123_456, 123_456.data.uint64)
        XCTAssertEqual(10, UInt8(10).data.uint8)
        XCTAssertEqual(1234, UInt16(1234).data.uint16)
        XCTAssertEqual(123_456, UInt32(123_456).data.uint32)
        XCTAssertEqual(4_294_967_295_000, UInt64(4_294_967_295_000).data.uint64)
    }
}
```

# 参考
- https://gist.github.com/bpolania/704901156020944d3e20fef515e73d61
【GAS】UNIX time を取得する方法

# 調べたきっかけ

とある API のドキュメントを見ていたら UNIX timestamp 形式で時間単位の指定が可能と書かれていました。
[LINE WORKS API - 監査データのダウンロード](https://developers.worksmobile.com/jp/document/30014002?lang=ja)

UNIX timestamp 形式を採用している API って割とあるんですね。

# UNIX time とは

UNIX time（UNIX 時間）とは、協定世界時 (UTC) での1970年1月1日午前0時0分0秒から形式的な経過秒数のことです。
[ウィキペディア（Wikipedia）- UNIX 時間](https://ja.wikipedia.org/wiki/UNIX%E6%99%82%E9%96%93)

秒数なので、気の遠くなるほど大きい数ですね( ﾟДﾟ)

# UNIX time を取得する

と、言うわけでタイトル通り Google Apps Script で UNIX time を取得したいと思います。

探したところ、[Date.parse() メソッド](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/parse)を使うのが良さそうです。
日時の文字列を読み込み、UTC からの経過時間を表すミリ秒単位の数値を返してくれます。

```js:getUnixTime.gs
function getUnixTime(){
  const now = new Date()
  Logger.log(`now: ${now}`)

  const formatNow = Utilities.formatDate(now, 'GMT', 'dd MMM yyyy HH:mm:ss z')
  Logger.log(`formatNow: ${formatNow}`)

  const unixTime = Date.parse(formatNow)/1000
  Logger.log(`unixTime: ${unixTime.toFixed()}`)
}
```

```
now: Tue Dec 22 17:14:27 GMT+09:00 2020
formatNow: 22 Dec 2020 08:14:27 GMT
unixTime: 1608624867
```

# コード解説

- 日付フォーマットの差異

`new Date()` で取得できる日付と `Date.parse()` の引数として入れる日付のフォーマットが異なっていたので `Utilities.formatDate()` を使って揃えました。

特に、月が `Dec` とかの英字形式でないと容赦なく `NaN` が返ってきます。

- 戻り値で返ってくるのはミリ秒単位

`Date.parse()` で返ってくる値はミリ秒単位なので 1000 で割って秒単位にしています。

- 整数表記にする

最後に toFixed メソッドを使用して整数表記にしました。

# おわりに

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

調べてみたら UNIX time を返してくれる API がありました。
[Unix Timestamp converter REST API](https://unixtime.co.za/)

UNIX time は、実はあまり馴染みがなかったのですが、馴染んでおくとどこかで役に立ちそうですね！
少なくとも「ナニソレ？美味しいの？？」状態にはならなさそうです( ﾟДﾟ)

ではまた！(^^)/

# 参考にさせていただきましたm(_ _)m

[MDN Web Docs - Date.parse](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/parse)
[Google Apps Script 公式 - Utilities.formatDate(date, timeZone, format)](https://developers.google.com/apps-script/reference/utilities/utilities#formatDate(Date,String,String))
[java.text - Class SimpleDateFormat](https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html)
[ウィキペディア（Wikipedia）- UNIX 時間](https://ja.wikipedia.org/wiki/UNIX%E6%99%82%E9%96%93)
GoogleCloudShellのteachmeコマンドが便利

[PONOS Advent Calendar 2020](https://qiita.com/advent-calendar/2020/ponos) 23日目の記事です。
昨日は@caramel_cafeさんの[【Unity】快適なジャンプ操作について考えてみる
](https://qiita.com/caramel_cafe/items/c4d0288a0a7f2d6b78fd)でした。

# はじめに
今年は新卒エンジニア向けにFirebaseのハンズオンをしたのですが、そのときに使ったGoogleCloudShellのteachmeコマンドがなかなか便利だったので紹介します。

# チュートリアルをする方法
GoogleCloudShellではMarkdown形式のファイルとteachmeコマンドを使ってチュートリアルを表示できます。
![Screen Shot 2020-12-22 at 17.07.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356727/1cad7254-3e2b-7478-4fc1-b466833f00ff.png)

1. GoogleCloudShellを起動する
https://console.cloud.google.com/cloudshell/editor
GCPのコンソールから開くか上記のURLにアクセスしてGoogleCloudShellを起動します。

2. チュートリアル用のMarkdownファイルをダウンロードする
リポジトリやGCSからMarkdownファイルを持ってきます。

3. teachmeコマンドでチュートリアル開始
以下のコマンドでチュートリアルを開始できます。

```shell
$ teachme <Markdownファイル名>
```

チュートリアル専用のスタイルも用意されているので詳しくは[公式のドキュメント](https://cloud.google.com/shell/docs/tutorial-writing-guide?hl=ja)を参照してください。

# さいごに
teachmeコマンドを使うと画面の切り替えをせずにチュートリアルを見ながらgcpのコマンドを実行したりファイルの編集ができるので、ハンズオンを行う際に非常に便利でした。


明日は@kenta-sanさんの記事です。
起動できなくなったArduino IDEの修復

# はじめに

M5StackシリーズのためにArduino IDEを使用していたが、[以前投稿した記事「Arduino IDEの設定 (M5Stackシリーズ)」](https://qiita.com/penguinprogrammer/items/774d4b719464e41cdcf3)のために設定をいろいろと変えていたらArduino IDEが起動できなくなってしまった。（画面もエラーメッセージも何も表示されない）

Arduino IDEを再インストールしたりレジストリを削除したりしたが修復できず、OSの再インストールも覚悟した(有償ソフトがインストールされているので再インストールは避けたかった)が、どうにかArduino IDEが動作するようになった。

また同じ状況に陥ったときのためにまとめた。

# 環境

Windows PC：Windows 10 Pro 64bit (1909) と（20H2）
Arduino IDE：V1.8.13

# 原因

あくまで想像だがArduino IDEの環境設定で`追加のボードマネージャのURL`を何度も変更したり、後述するローカルミラーサーバーを立てたりしてArduino IDEのファイル間に不整合を起こしてしまったと考えている。

# 再インストール方法

1. 「コントロールパネル」等からArduino IDEをアンインストール
2. Windowsを再起動（念のため）
3. エクスプローラーの表示設定で隠しファイルを表示できるように変更（`C:￥Users￥<ユーザ名>￥AppData￥`が不可視フォルダのため）
4. Arduino IDEの環境設定ファイル`C:￥Users￥<ユーザ名>￥AppData￥Local￥Arduino15￥preferences.txt`をバックアップ
5. Arduino IDEのデータ`C:￥Users￥<ユーザ名>￥AppData￥Local￥Arduino15￥`以下を削除（必要があればバックアップも）
6. Arduino IDEを再インストール
7. バックアップしておいた環境設定ファイル`preferences.txt`をもとの場所にリストア
8. Arduino IDEを起動
8. ボードマネージャで追加したボードを再度追加する。（ライブラリマネージャから追加したライブラリは再度追加する必要はない）

今回のポイントは隠しフォルダの`C:￥Users￥<ユーザ名>￥AppData￥Local￥Arduino15￥`以下を削除することで、Arduino IDEのインストール後の設定等がすべて初期化されてしまうが、環境設定ファイルをリストアすることで再設定を最小限にできる。

# (おま環) M5Stackボード情報のローカルミラーサーバー

上記再インストール方法の問題点はM5Stackのボード情報を再度追加する必要がある点で、最近のM5Stack製品（CoreInk等）ではM5Stack社のサーバーからボード情報をダウンロードする必要がある。
しかし、このサーバーがとにかく遅くArduino IDEがいつもタイムアウトを起こしていた。

そのためボード情報（インデックスのjsonファイルと実体のzipファイル）を別途ダウンロードしておいてローカルミラーサーバーを立てていた。だが、Arduino IDEはこれらをファイル名だけで管理しているようでM5stack社のサーバーのファイル名とローカルミラーサーバーのファイル名を同一にしていたのも問題があったのかもしれない。

現在は、ローカルミラーサーバーのJSONファイル名をM5stack社のファイル名と変更することによって管理している（なお、jsonファイル名には命名規則があるようで、`xxx_index_mirror.josn`は認識されずに`xxx_mirror_index.json`なら認識された）
また、ボード情報の実体であるzipファイルはファイルが同一なのでファイル名も変えていない。
[MySQL]外部キーカラムを追加

カラムの追加と外部キー制約の追加をそれぞれ行うことがポイント

```sql

ALTER TABLE table
    ADD id BINARY(16) NOT NULL,
    ADD CONSTRAINT table_fk01
        FOREIGN KEY (id)
        REFERENCES other_table (other_id)
        ON DELETE CASCADE
        ON UPDATE NO ACTION;
```
ＶＢＡはじめました　-データ範囲と最終行の取得ｰ

#データ範囲の取得
A2からB6がデータ範囲として
#####１．CurrentRegionを使って
```vb
Dim Rg As Range
Set Rg = Range("A1").CurrentRegion
```
#####２．1行目が項目の時は
```vb
Set Rg = Rg.Offset(1, 0).Resize(Rg.Rows.Count - 1)
'または
Set Rg = Intersect(Rg, Rg.Offset(1, 0))
```
これでデータ範囲（項目行無し）になります。
#データ範囲の活用
####１．最終行の取得
```vb
Dim Gyou As Double
Gyou = Rg.Rows(Rg.Rows.Count).Row
```
別の方法だと

```vb
Dim Gyou As Double
Gyou = Range("A1").Offset(Rows.Count - 1, 0).End(xlUp).Row
'
Gyou = Range("A" & Rows.Count).End(xlUp).Row
'
Gyou = Sheets(1).Columns("A").Find("*", , xlValues, , , xlPrevious).Row
```
####２．各行を順次取得には
#####a.Range内の行を取得する方法

```vb
Dim gRg As Range
For Each gRg In aRg.Rows
    Debug.Print gRg.Address
Next
```

#####b.１列のRange内の行番号で指定する方法

```vb
Dim i As Double
For i = 1 To Rg.Columns(1).Rows.Count
    Debug.Print Rg.Rows(i).Address
Next
```
#####c.１列のRangeをひとつずつ取得して指定する方法
```vb
Dim gRg As Range, hRg As Range, dRg As Range
Set hRg = Rg.Columns(1)
For Each dRg In hRg
    Set gRg = Rows(dRg.Row)
    Debug.Print gRg.Address
Next
```
これがエラーとなる

```vb
For Each dRg In Range("A2:A6")
    Set gRg = Rows(dRg.Row)
    Debug.Print gRg.Address
Next
```
これは動く、違いは？？
Rg.Columns(1)で１列に絞ったこと??
一応動くようにはなったが、一つしかエリアがないのに
Areasで拾わないといけない

```vb
Dim cRg As Range, gRg As Range, hRg As Range, dRg As Range
For Each cRg In hRg.Areas
    For Each dRg In cRg
    Set gRg = Rows(dRg.Row)
    Debug.Print gRg.Address
    Next
Next

```
#####c-1.このままだと１行指定なので

```vb
Set gRg = Rows(dRg.Row)
```
をIntersectを使って

```vb
Set gRg = Intersect(Rg, Rows(dRg.Row))
```
これで　データ範囲の各行を取得できる。

#####c-2.別の列の指定

```vb
Set gRg = Intersect(Rows(dRg.Row), Range("D:F"))
```
一人暮らしで実家にも帰れないから本気でfirefoxを使う。

#はじめに
グーグル、アマゾン、フェイスブック、アップル。
私は便利さのためなら彼らと血の契約を交わし、個人情報をすべて渡す覚悟だが、家まで届けてくれるアマゾン、彼の地の友人の近況を教えてくれるフェイスブック、古よりCUIフレンドリーなアップル、そして検索と便利なブラウザを提供してくれるグーグル。

ん？chromeそれほど便利か？なんかいつの間にか体感速度遅くなってたりしないか？googleアカウントに依存しすぎじゃないか？は？もう無理。firefox使おう。Rustちょー早いし。

ということでchromeのヘビーユーザーでしたが、firefoxにリプレースしました。実は何度目かのリベンジでこの度、満足に移行できそうなのでその結果を自慢する。

##心得
自分の情報は自分で管理するということが好きな人と友達になりたい。

chromeは使い始めはとっつきやすくていいかもしれないが、管理するユーザーやブックマークなどが多くなると管理がダルくなる。逆にgoogleに管理されてる気分になる。youtubeのpサーバーが落ちたりする昨今、google依存度を下げたい。

セキュリティをgoogleに丸投げするのをやめる。

chromeのレンダリング早いのに、余計な通信のせいで表示が遅れるのうざいなって思う。

いつの間にかchromeのキャッシュファイルが肥大化して10Gとかになるのもはやバグだと思う。

##やること

* パスワードマネージャーを導入し、イカしてるマスターパスワードを考える
* 今使っているすべてのブラウザからパスワード情報などをすべて消す
* 新たにgoogleアカウントを作成し、誰にも教えていないgmailアカウントからすべてのメールアドレスの送受信設定をする。そしてgmailnotiferを入れる。
* chromeのユーザー切り替えの代わりにfirefoxのプロファイルの切り替えを使う。

##利点
* ブラウザに依存せずにパスワードを管理すればめちゃくちゃストレスが減るし、パスワードの自動生成で脳死してアカウントが作れる。
* 便利でセキュリティが良くて省メモリ
* プロファイルをdotfileで管理できるので、gitでブラウザ設定を管理できる。
* プロファイル（chromeだとユーザー）ごとに新しいアカウントは必要ないってこと。

##年末暇なエンジニアへ、
bitwardenとfirefoxでchromeのリプレースしたらめちゃくちゃストレス減るよ！

##小ネタ
下のようにブックマークツールバーをアドオンと並べて配置できます。”USER”としているブックマークは"about:profile"ってURIでプロファイルの切換えができます。私はprivateとdeveloperのプロファイルを使い分けています。
![スクリーンショット_2020-12-22_17-30-23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127774/23939646-c019-f599-a5d1-4bee95954e46.png)
【ECS】codepipelineでECSへデプロイする

# ゴール
下記で作成したECS環境へのデプロイをcodepipeline化する
https://qiita.com/chanP_yamazaki/items/1760a952c4da8d3fde19

# S3にソースファイルを作成

``` :imagedefinitions.json
[{"name":"php-fpm","imageUri":"アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/ECRリポジトリ名:php-fpm"}]
```
バージョニング設定を有効にしたS3バケットを作成後
上記ファイルを作成し、zip化してからアップロードする

# codepipelineを作成

|ステップ | 名称       | 設定値 |
|:----------|:----------|:-------|
|ステップ1| パイプライン名       | test |
|ステップ2| ソースプロバイダ       | Amazon ECR |
|| リポジトリ名       | test |
|| 画像タグ       | php-fpm |
|ステップ3| ビルドステージをスキップ       |  |
|ステップ4| デプロイプロバイダ       | Amazon ECS |
|| クラスター名       | test-cluster |
||サービス名|作成済みのものを指定|

# codepipelineを編集
作成後にステージの調整をしたいので編集を実行

SourceステージでS3を追加

| 名称       | 設定値 |
|:----------|:-------|
| アクション名       | s3 |
| アクションプロバイダー       | Amazon S3 |
| バケット       | ソースファイルを置いたバケットを指定 |
| S3 オブジェクトキー       | imagedefinitions.json.zip |
|出力アーティファクト|s3|

Deployステージで編集

| 名称       | 設定値 |
|:----------|:-------|
| 入力アーティファクト       | SourceArtifact → s3 |
| イメージ定義ファイル       | imagedefinitions.json |

# デプロイ開始/終了通知用のlambda関数用意
ランタイム: python

```
import json
import urllib.request
 
def post_slack(message):
    send_data = {
        "text": message,
    }
    send_text = json.dumps(send_data)
    request = urllib.request.Request(
        'webhookURL',
        data = send_text.encode('utf-8'),
        method = "POST"
    )
    with urllib.request.urlopen(request) as response:
        response_body = response.read().decode('utf-8')
         
def lambda_handler(event, context):
    snsMessageObject = json.loads(event['Records'][0]['Sns']['Message'])
    state = snsMessageObject['detail']['state']
 
    if state == 'STARTED':
        message = 'コンテナデプロイ開始します'
    elif state == 'SUCCEEDED':
        message = 'コンテナデプロイ終了しました'
    elif state == 'FAILED':
        message = 'コンテナデプロイに失敗しました。'
    else:
        message = event['Records'][0]['Sns']['Message']
 
    post_slack(message)
```

# パイプラインの通知ルールを作成

| 名称       | 設定値 |
|:----------|:-------|
| 通知をトリガーするイベント       | Pipeline execution - Failed/Started/Succeeded |
| ターゲット       | 「ターゲットの作成」を押下して作成。作成後に「ターゲットの選択」は自動入力される |

# SNSトピックの編集
先ほど作成したトピックのサブスクリプション作成

| 名称       | 設定値 |
|:----------|:-------|
| プロトコル       | Amazon Lambda |
| エンドポイント       | 通知用に作成したlambda関数 |

# デプロイ実施
codepipelineの「変更のリリース」もしくはECRへのイメージpushでデプロイが開始し、開始と終了タイミングで通知が来れば成功

# 追加
ECRへのpushでデプロイを発火させずに承認アクションを追加することも可能
https://qiita.com/yukinosuke/items/17bcdae3fe4512e22eea
Arduino Unoを使って、ATtiny85に駆け足で書き込む。

年末も近いので"Arduino Uno"を使ってATtiny85に駆け足で書き込むことを想定している(意味不明)

~~駆け足で書いたので色々と問題ありかもしれないが許してくれ~~

#はじめに...
http://drazzy.com/package_drazzy.com_index.json を追加ボードマネージャー[^1]に入力し、ボードマネージャ[^2]からATTinyCoreをインストールしておくこと

※うまく行かない場合はインターネット環境やプロキシ設定を見直すこと[^3]

#必要なもの...
・Arduino Uno			1つ
・ATtiny85			1つ
・ジャンパー線			10本ほど

・確認用LED			1つ
・330Ω抵抗			1つ
・1~10uF電解コンデンサ		1つ	__←必須の可能性が大__

#手順
__1.Arduinoに"ArduinoISP"[^4]を書き込む__
※ボードは"Arduino Uno"に合わせる。"書き込み装置"は"AVRISP mkll"を選択した。

__2.Arduino UnoとATtiny85の間を配線する。__
https://ht-deko.com/arduino/bootloader.html#02 の[Arduino UNO を使った書込装置]を参考にした。

※一応、配線中はPCとArduino Unoとの接続を切って行うことを推奨する。

__3.ATtiny85に書き込みたいプログラムを開き、以下のようにボード設定を行う__

| 1 | 2 |
|:-:|:-:|
|　ボード　|　ATtiny25/45/85(No bootloader)　|
|　Chip　|　ATtiny85　|
|　Clock　|　8MHz(internal)　|
|　書き込み装置　|　Arduino as ISP(ATtinyCore)　|

その他はそのままで__ヨシ！__（現場猫）
	
__4.配線や設定が間違っていないかを確認した後、マイコンボードに書き込む。__
これでプログラムがATtiny85に書き込まれたはずである。

※エラーを吐いてうまく行かない場合は、Arduinoの"RESET"ピン(+)と"GND"ピン(-)の間に__1~10uFの電解コンデンサ__を追加して手順４をもう一度行う。

#おまけ
下に簡単な動作確認プログラムを記載した。1秒毎にLチカを繰り返すプログラムである。ATtiny85の3番ピンにLEDをつなげよう。

```
#define PIN 4	//デジタル4番ピンにLEDと抵抗を接続
#define T 1000	//ディレイとして1000ms

void setup() {
  pinMode(PIN, OUTPUT);
}

void loop() {
  digitalWrite(PIN, HIGH);
  delay(T);
  digitalWrite(PIN, LOW);
  delay(T);
}
```

[^1]:ファイル>環境設定>追加ボードマネージャーのURL
[^2]:ツール>ボード>ボードマネージャ
[^3]:ファイル>環境設定>ネットワーク
[^4]:ファイル>スケッチ例>11.ArduinoISP>ArduinoISP
【SQL Server】bcpコマンドで任意のクエリをCSVやTSV形式で出力（ダンプ）する。

自分用のメモです。


#■やり方

```shell
#-tオプションで「\t」をしていするとTSV形式
#-tオプションで「,」をしていするとCSV形式
bcp "select * from hoge;" queryout "[インポート先パス]" -c -t\t -r\n -S [サーバ名] -d [DB名] -U ユーザ名 -P [パスワード] -T
```
Nuxt.js の http クライアントの使い方 (Post)

プロジェクトの作成

```bash
npx create-nuxt-app proj01
```

```vue:pages/post.vue
<!-- post.vue -->
<template>
  <section class="container">
      <h2>{{title}}</h2>
	<pre>{{data_aa}}</pre>

<table>
<tr><th>args</th>
<td> {{data_aa.args}} </td></tr>
<tr><th>headers</th>
<td> {{data_aa.headers}} </td></tr>
<tr><th>origin</th>
<td> {{data_aa.origin}} </td></tr>
<tr><th>url</th>
<td> {{data_aa.url}} </td></tr>
<tr><th>json</th>
<td> {{data_aa.json}} </td></tr>
</table>
	<hr>
	<p>{{now}}</p>

 </section>
</template>

<script>

const axios = require('axios')

const url = 'https://httpbin.org/post'



export default {
	data: function(){
	return {
		title: 'http Post',
		now: 'お待ち下さい...',
		};
	},

	asyncData: async function () {
		const args = {
            data: { user: "jiro", password: "123456" },
            headers: { "Content-Type": "application/json" }
            };
		let result = await axios.post(url,args);
		return {data_aa: result.data};
	},
	created: function (){
		setInterval(() =>{
	var d = new Date();
	this.now = d.getHours()
		+ ':' + d.getMinutes()
		+ ':' + d.getSeconds();
	},1000);
	},
};
</script>

<style>
.container {
	padding: 5px 10px;
}
h2 {
	font-size: 30pt;
	color: green;
}

p {
	padding-top:5px;
	font-size: 20pt;
	color: cyan;
}

pre {
	padding: 10px;
	font-size: 10pt;
	color: blue;
}

hr {
	margin:10px 0px;
}

</style>
```

サーバーの実行

```bash
yarn dev
```

http://localhost:3000/post/ にアクセスする。
![nuxt_post.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/50d9007d-1ca4-190e-6bcb-9c3bb7da7949.png)
ExcelのテンプレートをもとにPHPでPdf出力する

## 概要

Laravelを使用した環境にて、以下を行います。

* Excelのテンプレートを読み込む。
* 読み込んだテンプレートに任意の値を挿入。
* 任意の値を挿入したExcelを出力。
* そのExcelをPdfに変換。

## Laravel Excel(PhpSpreadsheet)のインストール

※Laravel Excelを使おうとしたら、結局Laravel Excel内で使用してるPhpSpreadsheetで完結してしまったという私の背景があります。ここでは状況を合わせてLaravel Excelのインストールを行います。

Laravelのホームディレクトリで以下を実行

```
COMPOSER_MEMORY_LIMIT=-1 composer require maatwebsite/excel
```

## LibreOfficeのインストール

以下を実行

```
sudo yum -y install libreoffice libreoffice-langpack-ja
```

インストールできたかバージョン表示で確認

```
libreoffice --version
```

## LaravelのStorageにディレクトリ作成・Excelテンプレートの配置

Excelのテンプレートを配置。```storage/app/excel/template/template.xlsx```
Excelを出力するディレクトリを作成。```storage/app/excel/export```
Pdfを出力するディレクトリを作成。```storage/app/pdf/export```

↓こんな感じ。

```
storage/
　┗app/
　　┣excel/
　　┃　┣export/
　　┃　┗template/
　　┃　　┗template.xlsx
　　┗pdf/
　　　┗export/
```

## 実装

### ルーティング

```/routes/web.php
<?php

use Illuminate\Support\Facades\Route;

Route::get('pdf', 'ExportController@pdf')->name('pdf');
```

### コントローラー

```/app/Http/Controllers/ExportController.php
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Services\ExportService as ExportService;
use Illuminate\Support\Facades\Storage;

class ExportController extends Controller
{
    public function pdf()
    {
        $file_name = 'filename_' . date('YmdHis');
        $export_service = new ExportService();
        $export_service->makePdf($file_name);
        $file_path = Storage::path('pdf/export/' . $file_name . '.pdf');
        $headers = ['Content-Type' => 'application/pdf'];
        return response()->download($file_path, $file_name . '.pdf', $headers);
    }
}
```

### サービス

```/app/Services/ExportService.php
<?php

namespace App\Services;

use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;

class ExportService
{
    public function makePdf($file_name)
    {
        // もとになるExcelを読み込み
        $excel_file = storage_path('app/excel/template/template.xlsx');
        $reader = new XlsxReader();
        $spreadsheet = $reader->load($excel_file);

        // 編集するシート名を指定
        $worksheet = $spreadsheet->getSheetByName('hoge');

        // セルに指定した値挿入
        $worksheet->setCellValue('A1', 'fugafuga');

        // Excel出力
        $writer = new XlsxWriter($spreadsheet);
        $export_excel_path = storage_path('app/excel/export/' . $file_name . '.xlsx');
        $writer->save($export_excel_path);

        // Pdf出力
        if (file_exists($export_excel_path)) {
            $export_pdf_path = storage_path('app/pdf/export');
            $cmd = 'export HOME=/tmp; libreoffice --headless --convert-to pdf --outdir ' . $export_pdf_path . ' ' . $export_excel_path;
            exec($cmd);
        }
    }
}
```

## あとがき

サンプルなのでExcel出力とPdfを一緒のメソッド内でやってしまっているところなどありますが、
見積書などpdfで出力する際のご参考になればと思います。
【Metashape】個別画像の特定点の三次元座標を求めた～Agisoft forumを参考にPython APIから実装～

#Metashapeとは？

修士研究でドローンの画像処理をしていることもあり、Metashape（旧：Photoscan）という三次元構築ソフトウェア？を使っています。
元々個別画像で画像処理をしていて、検出した作物の位置情報を求める必要が出てきました。
事前に個別画像からモザイク画像は作成していたのですが、個別画像で求めたポイントとモザイク画像の一致点を求めることで、三次元座標を求めることが出来るのでは？という仮説のもと、進めました。

#Metashape Python APIを理解するのは大変です

MetashapeにはPython APIがあり、ソフトで実装されていない機能などはPythonでコードを書くことで実行することが出来ます。
しかし、Metashapeを使っている人やPython APIを使っている人が少ないのか、日本語で検索してもなかなか情報がありません。

例えば、山口大学の空中測量研究室のブログには日本語で唯一ともいえる程、Metashapeに関する情報が載っています。
[MetashapeのPython APIメモ](https://ameblo.jp/rs-algorithm-designer/entry-12549159944.html)

おそらく、あとは英語による情報収集になるでしょう。
Metashape公式のAPI解説では、200ページ近い説明書があり、これを参考にしながらコードを書くことになります。

[Metashape Python Reference Release 1.6.0](https://www.agisoft.com/pdf/metashape_python_api_1_6_0.pdf)

しかし、この説明書は説明がなかなか単純化されていて、目の前のトラブルを解決するには情報が不足しています。不親切ですね。
その代わり、Agisoft forumという質問コーナーにナレッジが蓄積されており、非常に参考になります。

https://www.agisoft.com/forum/index.php

以上のサイトを参考にしながら、試行錯誤していくことになります。


#解決方法

やろうとしたことを整理すると、
**モザイク化する前の画像における座標：[x,y]**
から
**3次元座標：[X,Y,Z]**
を取得したい！ということです。
以下の記事を参考にして、実現しました。

[How to add marker using camera's coordinates.](https://www.agisoft.com/forum/index.php?topic=12160.msg54374#msg54374)

```script.py
import Metashape 
doc = Metashape.app.document
chunk = doc.chunk
camera = chunk.cameras[N]
surface = chunk.model
point = surface.pickPoint(camera.center, camera.transform.mulp(camera.sensor.calibration.unproject(Metashape.Vector([x,y]))))
marker = chunk.addMarker(point)
marker_coord = chunk.crs.project(chunk.transform.matrix.mulp(marker.position))
```
1行目～4行目：Metashapeをimportして、モザイク化する前の画像を1枚指定。
5行目～6行目：画像座標系上の点[x,y]に、画像特有の変換行列（モザイク化で作成済み）をかけることで変換。
7行目～8行目：pointに対応するマーカーをchunkに設置し、この点を絶対座標系に変換。

おそらく、一番難しいのは座標系の変換です。
**画像座標系→？？座標系→絶対座標系**
に変換しています。

いずれにしても、個別画像の特定のポイントに対応する3次元座標を取得することが出来ました。
「csvをインポートして、変換をforループで回した後、結果をcsvで出力」とかすれば、いい感じになりそうですね。（語彙力）

#まとめ

Metashape Python APIを使うには、Agisoft forumで情報収集しつつPython API referenceを参照する必要があります。
もし参考になればいいね！お願いします～
Nuxt.js の http クライアントの使い方 (Get)

プロジェクトの作成

```bash
npx create-nuxt-app proj01
```

```vue:pages/get.vue
<!-- get.vue -->
<template>
  <section class="container">
      <h2>{{title}}</h2>
	<pre>{{data_aa}}</pre>

<table>
<tr><th>args</th>
<td> {{data_aa.args}} </td></tr>
<tr><th>headers</th>
<td> {{data_aa.headers}} </td></tr>
<tr><th>origin</th>
<td> {{data_aa.origin}} </td></tr>
<tr><th>url</th>
<td> {{data_aa.url}} </td></tr>
</table>
	<hr>
	<p>{{now}}</p>

 </section>
</template>

<script>

const axios = require('axios')

const url = 'https://httpbin.org/get'



export default {
	data: function(){
	return {
		title: 'http Get',
		now: 'お待ち下さい...',
		};
	},

	asyncData: async function () {
		let result = await axios.get(url);
		return {data_aa: result.data};
	},
	created: function (){
		setInterval(() =>{
	var d = new Date();
	this.now = d.getHours()
		+ ':' + d.getMinutes()
		+ ':' + d.getSeconds();
	},1000);
	},
};
</script>

<style>
.container {
	padding: 5px 10px;
}
h2 {
	font-size: 30pt;
	color: green;
}

p {
	padding-top:5px;
	font-size: 20pt;
	color: cyan;
}

pre {
	padding: 10px;
	font-size: 10pt;
	color: blue;
}

hr {
	margin:10px 0px;
}

</style>
```

サーバーの実行

```bash
yarn dev
```

http://localhost:3000/get/ にアクセスする。
![nuxt_get.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/9e42bacd-9cb6-5804-9342-18f60e91bd68.png)
Unity　Timelineでアニメーションウィンドウの全体像表示


はまったのでメモ、キーボードのAのキーを押すと
選択中のキーアニメーションの全体像が見れるようになりました。
縦にスクロールできなくて値が見えずに悩みました。

めちゃくちゃ助かりました

参照URL：http://tsubakit1.hateblo.jp/entry/2016/09/05/235900
【Swift】非同期処理「GCD」について

#GCD とは
GCDとは、非同期処理を容易にするための技術です。
GCDではキューを通じて非同期処理を行い、直接スレッドを管理することはありません。

**スレッドの管理はシステムが担当し、
CPUのコア数や負荷の状態などを考慮して自動的に処理を最適化します。**

つまり、処理の並列数やスケジューリング、
どの処理をどのスレッドで行うかなどをプログラマーが考える必要がありません。

プログラマーが考えることと言えば、
**タスクをキューに追加することだけです。**

スレッドはその都度生成される訳ではなく、
事前に準備されていたスレッドの中から空いているものにタスクが振られます。

この時に空いているスレッドが存在しなかった場合は、
スレッドが空くまで待機することになります。

このような管理の手法を**スレッドプール**と言います。

##実装方法
GCDのキューはディスパッチキューと言います。
ディスパッチキューはタスクの実行方式によって２種類に分類されます。

**・直列ディスパッチキュー
->現在実行中の処理の終了を待ってから次の処理を実行する
・並列ディスパッチキュー
->現在実行中の処理の終了を待たずに次の処理を実行する**

###ディスパッチキューの取得
GCDの既存のディスパッチキューとして、
１つもメインキューと複数のグローバルキューを提供しています。

メインキューは、**メインスレッドでタスクを実行する直列ディスパッチキューです。**

メインキューの取得方法はmainクラスプロパティを使用して取得します。

```swift

import Dispatch

let queue = DispatchQueue.main   // メインディスパッチキューを取得
```

ユーザーインターフェースの更新、つまりユーザの操作は、
常にメインキューで実行されています。

他のディスパッチキューで実行された非同期処理の結果を反映させる場合、
メインキューを取得してタスクを追加することになります。

グローバキューは並列ディスパッチキューのことを指し、
**実行優先度を指定して取得します。**

その実行優先度のことを**QoS**と言い優先度の高い順に下記の５つがあります。

**① userInteractive**
アニメーションの実行などの、
即座に実行されなければフリーズしているように見える処理に用いる

**② userInitiated**
何かをタップした場合などのユーザからの入力を受けて実行される処理に用いる

**③ default**
QoSが何も指定されていない場合に利用される

**④ utility**
視覚的な情報の更新を伴いながらも、
即時の結果を要求しない処理に用いる

**⑤ background**
バックアップなどの目に見えないところで行われ、
数分から数時間かかっても問題ない処理に用いる

###タスクの追加
取得したディスパッチキューにタスクを追加するには、
DispatchQueue型の`async(execute:)`メソッドを用います。

直列ディスパッチキューも並列ディスパッチキューもタスクの追加方法は同様です。

次のサンプルコードでは、
並列ディスパッチキューに対してasync(execute:)メソッドを呼び出して
非同期処理を行っているコードになります。

メインスレッドでのfor-in文に加え、非同期処理のfor-in文も行っています。
並列で処理を行っているので実行結果がごちゃごちゃになります。

```swift

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

let queue = DispatchQueue.global(qos: .userInitiated)
queue.async {
    for item in 0..<5 {
        print("非同期処理:\(item)")
    }
}

for item in 0..<5 {
    print("同期処理:\(item)")
}

実行結果
同期処理:0
非同期処理:0
同期処理:1
非同期処理:1
同期処理:2
非同期処理:2
同期処理:3
同期処理:4
非同期処理:3
非同期処理:4
```
今回のQoSは`userInitiated`でしたが、
これを`userInteractive`にするとまた結果が変わるります。

```swift

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

let queue = DispatchQueue.global(qos: .userInteractive)
queue.async {
    for item in 0..<5 {
        print("非同期処理:\(item)")
    }
}

for item in 0..<5 {
    print("同期処理:\(item)")
}

実行結果
非同期処理:0
同期処理:0
非同期処理:1
同期処理:1
非同期処理:2
非同期処理:3
同期処理:2
非同期処理:4
同期処理:3
同期処理:4
```

userInitiatedより優先されているのがわかると思います。
少し結果が変わってくるので、
**非同期処理を行う際はその時に必要な並列処理の優先順位を明確にしましょう。**

##利用すべきとき

GCDを利用する場面としては**単純な非同期処理の実装**になります。
その理由は、タスクをクロージャとして表現できるためです。

メインスレッドから時間のかかる処理を別のスレッドに移し、
その処理が終わったらメインスレッドに通知する場面を例にします。

```swift

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

let queue = DispatchQueue.global(qos: .userInteractive)
queue.async {
    print("非同期処理実行-1")

    let queue = DispatchQueue.main
    queue.async {
        print("メインスレッド実行")
    }

    print("非同期処理実行-2")
}
```

非同期処理が行われてからメインスレッドに制御が戻っていることがわかります。
このようなシンプルな非同期処理は楽に実現することができます。


**逆に、タスクどうしの依存関係の定義や、条件に応じたタスクのキャンセルなどは、
OperationQueueクラスなどを利用しましょう。**

以上でディスパッチキューについての説明は終わります。

単純な非同期処理についてはこれで十分かと思いますが、
複雑な処理を行う場合はOperationQueueクラスなどを利用しましょう。

最後までご覧いただきありがとうございました。
Reactでdotenvを使っても環境変数が読み込めずundifinedとなるときのTips

Reactで[dotenv](https://github.com/motdotla/dotenv#readme)を使って、任意のページで環境変数を読み込みたい。でも、なぜか`undifined`が返ってくる。そんなときの対処法を紹介します。

## 確認ポイント

1. 変数は`REACT_APP_`から始まっているかどうか(例: *REACT_APP_FIREBASE_API_KEY*)
2. サーバーを再起動したかどうか
3. `.env`ファイルはプロジェクトルートに配置されているかどうか
4. `require('dotenv').config()`は必要ありません

## 変数は`REACT_APP_`から始まっているかどうか

create-react-appを使っていて、`.env`を使う際に、変数の先頭に`REACT_APP_`とつけないと`undifined`になります。

また、`.env`ファイルはそれぞれの行に`コロン(:)`、`セミコロン(;)`をつける必要はありません。

```.env
REACT_APP_FIREBASE_API_KEY=xxxxxxxxxxxx
REACT_APP_FIREBASE_AUTH_DOMAIN=xxxxxxxxxxxxxxxx
```

## サーバーを再起動したかどうか

環境変数についてのコードの変更を行った際は、変更を反映するためにサーバーを再起動する必要があります。

`Ctrl+C`でサーバーを停止して、`npm start`や`docker-compose up`などで再起動しましょう。

## `.env`ファイルはプロジェクトルートに配置されているかどうか
`package.json`や`README.md`、`.gitignore`などのファイルがあるプロジェクトルートの階層に`.env`を配置する必要がります。**srcフォルダの中ではなく、プロジェクトルートです。**

## `require('dotenv').config()`は必要ありません

`dotnev`は以下のような使い方をしますと公式に書かれています。

```sample.js
require('dotenv').config()
```

しかし、このコードは**必要ありません！！**

理由は、create-react-appがすでに`.env`ファイルを使えるようにしてくれているからです。(dotenvをインストールした意味がなかった。。😅)

以下のように読み込みたいファイルで直接`process.env`で読み込めます。

```sample.js
const sampleId = process.env.REACT_APP_SAMPLE_ID;
```

## 参考
[react evironment variables .env return undefined](https://stackoverflow.com/questions/53237293/react-evironment-variables-env-return-undefined/53237511)

[Reactにおける環境変数を設定について、ようやく理解したので原因と共にまとめてみる_100DaysOfCodeチャレンジ38日目(Day_38:#100DaysOfCode)](https://qiita.com/yuta-ushijima/items/a653e9ca4847276f19cd)

[create-react-appのプロジェクトで環境変数を.envから読み込めない原因と解決策](https://qiita.com/wakeupsloth/items/ec19b9fbfddfb1cd58bb)
AWS Solutions Constructsがあったのでわざわざ自作のCDKパッケージを作る必要がなかった話

# はじめに

悔しさのあまり記事にしました。[こういった自作CDKライブラリ](https://www.npmjs.com/package/cdk-lambda-api)を作ったりしていたのですが、どうやらAWS公式が既に同じOSSの取組をしていたようでした。
[reinvent2020](https://virtual.awsevents.com/)の**Turbocharge the AWS CDK with AWS Solutions Constructs**というセッションを聞いて初めて知ったのですが、どうやらCDKのためのパターンセットみたいなものがあるようです。

# [AWS Solutions Constructs](https://docs.aws.amazon.com/solutions/latest/constructs/welcome.html)

Solutions ConstructsとはCDKのためのオープンソースライブラリで、multi-service、well-architectedなパターンのAWSサービスを素早く構築するために作られたとのことです。[AWS CDK](https://aws.amazon.com/jp/cdk/)は個別にサービスを定義してアーキテクチャを構築するのに対して、Solutions Constructsはある程度まとまった（2~3個くらい)パターンのサービスを定義してアーキテクチャを構築するといった違いがあります。
[ライブラリ郡はここ](https://docs.aws.amazon.com/solutions/latest/constructs/api-reference.html)にまとめられています。個人的によく使いそうなパターンが結構ありました。

- [aws-apigateway-lambda](https://docs.aws.amazon.com/solutions/latest/constructs/aws-apigateway-lambda.html)
- [aws-lambda-s3](https://docs.aws.amazon.com/solutions/latest/constructs/aws-lambda-s3.html)
- [aws-cloudfront-s3](https://docs.aws.amazon.com/solutions/latest/constructs/aws-cloudfront-s3.html)
- [aws-lambda-dynamodb](https://docs.aws.amazon.com/solutions/latest/constructs/aws-lambda-dynamodb.html)

[サンプルコード集](https://docs.aws.amazon.com/solutions/latest/constructs/sample-use-cases.html)もあるので、使い方の雰囲気も掴めそうです。

# おわりに

reinventは新しいサービスももちろんですが、知っているつもりだったAWSサービスの知らなかった情報とかを知る機会にもなったりしますね。正しくカンファレンスのタイトル通り**再発明**だと思いました（意味あってるのかな...）。
PythonのZeroDivisionErrorを使った例外処理

# はじめに
今回は大学のレポートで「Pythonでなにかしらの例外処理を作れ！」とのことだったので簡単なものではありますが、例外処理を作成しました。
例外処理で詰まっている方の参考になれば嬉しいです。

#作成したコード

```python:try_except.py
#割り算がしたくなるように仕向ける
print("\n_____________________________________________________\n")
print("現在、あなたは割り算がしたい欲求がたまっています。")
print("ここで思う存分に、割り算をしてください。")
print("数字を入力したらEnterを押して、次の数字を入力してください。")
print("\n※ ちなみに、yに「0（ゼロ）」は決して入れてはいけませんよ※")
print("_____________________________________________________\n")

#数字をインプットして出力
print("x = ",end="")
x = float(input())
print("y = ",end="")
y = float(input())
print("\n" + str(x) + " ÷ " + str(y))

#例外処理
try:
    z = 0
    z = x / y
    print("= " + str(z))
    print("Correct!\n")
except ZeroDivisionError as e:
    print("= \nYou don't deserve an answer.")
    print("Don't come here again.")
    print("\nあ、、、yに0を入れてしまったのですね\n")
```

#実行結果（yに0以外の数字を入れた場合）

```
_____________________________________________________

現在、あなたは割り算がしたい欲求がたまっています。
ここで思う存分に、割り算をしてください。
数字を入力したらEnterを押して、次の数字を入力してください。

※ ちなみに、yに「0（ゼロ）」は決して入れてはいけませんよ※
_____________________________________________________

x = 2
y = 1

2.0 ÷ 1.0
= 2.0
Correct!
```

普通に計算ができ「Correct!」と出ます。

#実行結果(yに0を入れた場合)

```
_____________________________________________________

現在、あなたは割り算がしたい欲求がたまっています。
ここで思う存分に、割り算をしてください。
数字を入力したらEnterを押して、次の数字を入力してください。

※ ちなみに、yに「0（ゼロ）」は決して入れてはいけませんよ※
_____________________________________________________

x = 2
y = 0

2.0 ÷ 0.0
= 
You don't deserve an answer.
Don't come here again.

あ、、、yに0を入れてしまったのですね

```

yに0を入れてしまうと、かなり怒られます。

#おわりに
今回はPython3で簡単な例外処理のコードを書いてみました。
このコードにプラスαできる箇所はたくさんあると思うので興味があれば強化してみてください。
それではまたまた。
Week6(10/28の内容)

![Mac OS X-10.15.7](<https://img.shields.io/badge/MacOSX-10.15.7-brightgreen>) ![ruby-2.7.1p83](<https://img.shields.io/badge/ruby-2.7.1p83-brightgreen>)

# 内容<span class="timestamp-wrapper"><span class="timestamp">&lt;2020-10-28 Wed&gt;</span></span>

$$\frac{1}{4}$$

qiitaでこんな感じに出力する↓

    $$
    \frac{1}{4}
    $$

------
 - **source** ~/grad_members_20f/members/kotanlab/week6.org
C 言語のポインターの概説

ポインタと普通の変数との違いは 「何を格納するか。」です。
とはいえ、値を格納するという意味では同じです。あまり複雑に考える必要はありません。

* 普通の変数：プログラマが操作出来る、任意の数を格納・保持する。
* ポインタ：メモリアドレスといった、一般的に直接指定できない値を格納・保持する。

両者を仲介する記号が、&と * です。特に * は 3種類の意味をもちます。

- &：変数(オブジェクトも可)アドレスを参照(GET)する。

- *(1)：Declare 変数を定義するときに、ポインタだと明示する。
- *(2)：Set 右側に=がある時は、その値を代入する。
- *(3)：Get 式中に出てきた場合、そのポインタが示す先の値を参照する。

使い方：
【*(1)】ポインタが定義出来ます。ここではついでに普通の変数も定義します。
int i = 0 , *pt; // ptがポインタ

【&】ポインタと普通の変数を関連付けます。
pt = &i; // pt変数の値は、i変数のアドレス。

【*(2)】ポインタに対して、+1してみます。
*pt += 1; この場合、pt の参照先の変数、つまり i の値が 1 追加されます。

ここで、pt+=1 とすると、pt変数自体が+1されます。これはつまり、ポインタが参照するメモリアドレスの変数値が一個先に進むことを指しています。

【*(3)】ポインタの値を参照します。
printf( "%d" , *pt );
1が表示されますが、これはptの値が増えたのではなく、
(2) の操作によって ptの示す変数、つまりiが1増えたことを意味します。
ですので *pt == i の関係にあります。
【Mask R-CNN】AttributeError: 'Model' object has no attribute 'metrics_tensors' にぶち当たったら考えること。

#Mask R-CNNの続き

修士研究で植生の検出をするために、matterport社のMask R-CNNを使ってインスタンスセグメンテーションを実装しています。
他にもエラー記事をまとめているのでご覧下さい。

[AttributeError: module 'tensorflow' has no attribute 'log' を解決した話。](https://qiita.com/skperfarming/items/dc2e95476bb97c830856)

[【前編】Mask R-CNNで発生したエラー「UserWarning: An input could not be retrieved. It could be because a worker has died」を解決してみた。](https://qiita.com/skperfarming/items/68cdec8ad8672837bd38)

[【後編】Mask R-CNNで発生したエラー「UserWarning: An input could not be retrieved. It could be because a worker has died」を解決してみた。](https://qiita.com/skperfarming/items/8c0ebfe5e72ce7357cf2)

#AttributeError: 'Model' object has no attribute 'metrics_tensors' が発生しました。

準備が終わり、以下のプログラムを実行していざ学習をさせようとすると…

```Mask_RCNN.py
model.train(dataset_train, dataset_val, 
             learning_rate=config.LEARNING_RATE, 
             epochs=40, 
             augmentation=augmentation,
             layers='heads')
```

```実行結果.
AttributeError: 'Model' object has no attribute 'metrics_tensors' 
```
このようなエラーが発生してしまいます。
早速、解決していきましょう。

#解決方法１：kerasのダウングレード

お馴染み、githubの質問コーナーに同様のトラブルが記載されていました。

[Training balloon model on gpu: AttributeError: 'Model' object has no attribute 'metrics_tensors' #1754](https://github.com/matterport/Mask_RCNN/issues/1754)

kerasを2.0.8にダウングレードすれば良さそうです。
しかし、ダウングレードによって他のコードでもエラーが発生する危険性があり、いたちごっこになりそうだったので、私は解決方法２・３を試しました。

##解決方法２：keras_model.metrics.append(loss)に書き換え

前にも紹介しましたが、このエラーはmodel.pyに書かれているコードが古いことに起因しています。
Ctrl+Fで検索することで該当箇所を見つけ、kerasの新バージョンに対応するコードに書き換えました。

```model.py
self.keras_model.metrics.append(loss)
```
結果、エラーは解消！学習を進めることが出来ました！

**一件落着！と、思いきや…何かがおかしい！**

```実行結果.
Epoch 1/20 105/105 [==============================] - 1146s 11s/step - loss: 2.8658 - val_loss: 2.2283
```
本来ならば、rpn_class_loss等が計算されるはずなのに、計算されているlossは2種類だけなのです。
これを解決するためには解決方法３を試す必要があります。

＜参考＞Mask R-CNNで計算されるlossについての解説はこちら
[loss function #1111](https://github.com/matterport/Mask_RCNN/issues/1111)



#解決方法３：keras_model.add_metric(loss,name)に書き換え

[Training balloon model on gpu: AttributeError: 'Model' object has no attribute 'metrics_tensors' #1754](https://github.com/matterport/Mask_RCNN/issues/1754)

を見てみたところ、もう一つの解決方法が紹介されていました。
先程同様、model.pyの該当部分を以下のように書き換えます。

```model.py
self.keras_model.add_metric(loss,name)
```

すると、エラーを発生させずに、かつ他のlossも計算させることができました！
（実行結果は追い追い更新します…）


#まとめ

まとめると、自分が今悩んでいることは、以前地球上の誰かも悩んでいたと踏んでいるので、
他にもMask R-CNNでのエラーが発生したらgithub Issuesを見てみて下さい！
日本語でヒットしないものでも、英語ではヒットすることが多くあるので、英語の重要性をひしひしと感じますね～

一件落着です！
参考になればいいね！お願いします～
[ServiceNow]システムプロパティ値の修正方法

ServiceNowの公式Docsを見ていると、「システムプロパティの値を変更」で設定を変えられるという記事を見かけるが、対象のプロパティまでの辿り方は明記されていないことが多いので、メモ程度に表題について記載します。

#システムプロパティ値の修正方法
システムプロパティの修正方法としては、
①対象の主要管理モジュール専用のプロパティ画面を表示し、対象のプロパティ値を修正
②システムプロパティ一覧画面を表示し、対象のプロパティ値を修正
の2種類が考えられると思います。

##プロパティ値の修正

###（記事執筆時の）インスタンスメジャーバージョン
- Orland

###修正方法
####①対象の主要管理モジュール専用のプロパティ画面を表示し、対象のプロパティ値を修正
1. [プロパティ]とナビゲーターに入力し検索
2. 修正対象の管理モジュールのプロパティモジュールを選択（画像例は、インシデントモジュールのプロパティ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/7a67d971-d766-6713-1110-ce89cb5d9570.png)

3. インシデントモジュール関連のプロパティが表示されるので、対象のプロパティ値を修正
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/26857e6f-540b-a0ed-890b-46a9776d5500.png)

####②システムプロパティ一覧画面を表示し、対象のプロパティ値を修正
1. ナビゲーターに[sys_properties.list]と入力し、Enterキーをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/e9dfe0e5-15e7-c5bc-cf39-a44bd894114a.png)

2. システムプロパティ一覧画面が表示されるので、修正したいプロパティを検索し、名前のリンクをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/ff4a8bb5-afc0-deb2-a758-bb1aed29b41c.png)

3. 値を修正し、更新
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/15970049-76d0-6634-36da-49a0a6521eb0.png)

##補足
システムプロパティ一覧画面のモジュールも存在する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/e65bc9bd-b228-c350-f808-cd95d131d1c2.png)

ただし、OOTBでは「すべてのプロパティ」モジュールは非表示設定になっているので、モジュールにロールを付与する必要がある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/cc17a55e-5f2e-e54a-e785-aea25bf7ee68.png)
squidでdアニメストアを見るための設定

今まではプロキシサーバー経由でもdアニメストアを視聴できたけど、最近なぜか突然プロキシサーバーを経由すると全部「海外扱い」とされてパソコンから視聴できなくなった（しかしスマホアプリだと視聴できて草）。その訳のわからない制限を突破するためのsquidの設定です。

```/etc/squid/squid.conf
従来からある設定内容
via off
forwarded_for delete
```

としたあとに `systemctl reload squid.service` する。念のため [リモート診断くん](http://re.pdata.jp/) でプロキシサーバーの存在が検出されない設定となっているか確認する。以上
Human In The Loop実装してみた  ― Part③ HITL実装(最終回) ―



[Human In The Loop実装してみた ― Part① ダッシュボード ―](https://qiita.com/motonobu_ut/items/f05021b9e885d3770724)
[Human In The Loop実装してみた ― Part② 検証ツール ―](https://qiita.com/motonobu_ut/items/0fa3e1f2aa89e1bd5546)
の続きです。

■	これまでの流れ

-	Part①：目標設定、使用データ紹介、モニタリング用ダッシュボードの実装
-	Part②：有識者用検証ツールの実装
-	Part③：HITL（①と②＋モデル再学習の仕組み）　←今回

※　前提条件や目標、利用技術などの詳細はPart①、Part②をご確認ください。

■	HITL実装結果
![simple](https://user-images.githubusercontent.com/17790965/102861567-3b321d80-4473-11eb-8a6c-e19dead3afd0.gif)
##Part③で何をやるか
Part①ではモニタリング用のダッシュボードを実装し、Part②では有識者判定を効率化させる検証ツールを実装しました。最終回となる今回は、作成したダッシュボードと検証ツールに、モデルを再学習する仕組みを追加することで、以下のシナリオのHuman In The Loopを実演します。（実演する範囲は以下「イメージ」のモニタリング、有識者判定、知見反映の部分）

■ シナリオ※
1. 検知モデルが未知検知(機械学習モデルは異常と判定)
2. 検証者が未知検知部分を検証、正常と判定
3. 判定を受け、該当部分をモデルが正常と判定するよう再学習を実行

※　未知データの確認をダッシュボードで、検証を検証ツールで行います

今回はじめて出てくるのは「モデルの再学習」の部分です。実装に入る前に、再学習について簡単に説明し、HITLにおける再学習の重要性を整理します。

 

##再学習とHITL
再学習とは「ある学習をしてから一定の期間を経て再び学習してその学習効果を保持すること」を意味し、AIにおいてはモデル運用時の品質劣化を避けるための仕組みとして組み込むことがあります。[参考1]
一部の安定した環境を除き、現実のデータは時間と共に傾向が変化するため、過去のデータを学習した学習済モデルを運用する場合、適切なタイミングでモデルを調整することが推奨されます。
ある程度の精度劣化が許容される場合は数か月に一回などの定期的な調整を検討することもありますが、異常検知などの迅速に対応しなければならないタスクでは、リアルタイムにモデルを調整することが必要となります。
HITLのように再学習させる仕組みをあらかじめ設けておくことで、定期的であれリアルタイムであれ、適切なタイミングでモデルを調整することが可能となります。


##実装
以下に分けて実装していきます。
１．	ダッシュボード
２．	検証ツール　
３．	HITL（①と②＋モデル再学習の仕組み）←　今回


##３．HITL実装
■	実装内容

- 目標：ダッシュボード＋検証用データ送付＋再学習
- 確認：検証へ送付するデータを選択し確認
- 開始と終了の時間を指定する
- 更新：検証へデータを送付する
- 再学習：再学習フラグを更新→再学習してフラグを戻す

■	実装イメージ　
![HITL_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/892617/1556e1a6-583a-7595-7834-4efa637001c0.png)
■	実装結果
![simple](https://user-images.githubusercontent.com/17790965/102861567-3b321d80-4473-11eb-8a6c-e19dead3afd0.gif)
##再学習について注意点
このシリーズでは教師有モデルとして決定木系のLightGBMを使用しています。これは、比較的高速で前処理が楽といった理由で採用していますが、このモデルは再学習の際、ニューラル系のような追加学習はできず、全データで学習しなおさなくてはならないというデメリットがあります。
そのため、データが膨大になると再学習のラグが大きくなってしまったり、メモリが足らずエラーになってしまったりすることが想定されます。大量のデータを扱うタスクでは、モデルをニューラル系にしたり、学習し直すデータの範囲を絞ったりすることも検討してください。
また、今回のモデルに限らず、少数の未知データの検証結果をきちんと再学習で反映させるためには、対象データへの重みづけを強くするなどの工夫が必要になります。こういった微調整は繰り返すことで既存の学習を脅かしてしまうことがあるので、その点は注意して運用する必要があります。


##まとめ
今回はダッシュボードと検証ツールに、モデルを再学習する仕組みを追加することで、Human In The Loopを実演しました。
ダッシュボード、検証ツール、再学習の仕組みを組み合わせることで、未知の入力に対して素早く検知、検証、再学習が可能になることが分かりました。また、入力データやモデルを変更することで、監視などのタスクに応用できると考えております。
本シリーズはあくまでデモとしてHuman In The Loopのイメージを掴んでいただくために作成しているため、本実装は実際の運用を保証するものではないということをご了承ください。改善点やご質問などあれば、コメントいただければ幸いです。

##参考
1.	再学習という言葉
https://monitor.adish.co.jp/glossary/relearning/

2.	Dashで機械学習ができるWebアプリを作る [Step1]
https://wimper-1996.hatenablog.com/entry/2019/10/28/dash_machine_learning1
※	Dashのテーブルデータ処理などで参考にさせていただきました

3.	コード公開(予定)
http://github.com/utmoto

4.	Dash
https://dash.plotly.com/

5.	plotly
https://plotly.com/
エラーメッセージ unrecognized selector send to instance "***" が出た時の対処法

#開発環境
Swift5, Xcode12.3です。
作成中のプロジェクト名が"EngineerApp"です。
#エラーについて
![エラー](https://i.gyazo.com/cd8f03aa5a66349dcf3666abca67a256.jpg)
見にくくて申し訳ないんですが、画像の赤い部分を見ると
unrecognized selector send to instance "EngineerApp" 
とあります。
#原因と対処
問題が発生したのはtableViewCellに繋がれていたボタンなんですが、確認の手順としては
1.StoryboardでButtonを選択
2.その状態で、右側のプロパティなどが編集できるエリアの一番右のアイコンを選択する
そうすると、次のような画面が右側に映ると思います。
![画像](https://i.gyazo.com/fde8c00a902ee185fba1bcbea213c36e.png)
この Touch Up Inside というところを見ると、2つのメソッドが紐付けられているのがわかります。今回の場合は、上側が過去にIBActionでつないだものがあって、それをコード側でメソッド名を変更したりメソッドだけ削除したりしてStoryboard側の変更をしていなかったものであるため、❎を押して消したらエラーがなくなりました。
#まとめ
エラー "unrecognized selector send to instance" が発生したら、Storyboard側でも変更できているか、不要な接続が残ってないかを確認する。
最後まで読んでいただき、ありがとうございました。参考になれば幸いです。ご指摘や他の対処など、知っている方がいましたら気軽にコメントしていただきたいです。
【Spring Boot】各クラスの役割

## Model
- データモデルを扱う

## Controller
- アノテーション: `@Controller`
- フロントからのリクエスト、およびフロントへのレスポンスのハンドリングのみを行う

## Service
- アノテーション: `@Service`
- 業務処理を提供する

## Repository
- アノテーション: `@Repository`
- DBアクセスを行う