OmniAICreator/Qiita-1.07M huggingface dataset:
iOS で体温記録する

体調管理の一環で、体温を記録しようと思っても、
どのアプリを選んだら良いか迷ってしまう、という私のための記事です。

↓こんなことがやりたい
![ios_shortcut_011.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59810/60165a8d-f32f-53bf-0ef0-565d142e6a6a.jpeg)

> **おことわり。**
> 体温情報は、個人の健康に関連する機微情報の一つだと考えています。どこに保存すべきか、そもそも保存するべきかの判断は、個々人で配慮いただければと思います。本記事の趣旨としては、iOS ショートカットでこんな使い方もできる、というアイデアの一例のご紹介です。

閑話休題。

いわゆる普通の体温計 (水銀じゃなくても) で体温測るのですが、記録をどこに残そうか、そのためにわざわざアプリ入れるのも、高機能な体温計を探すのもなぁ・・

そうだ、ヘルスケアアプリに直で記録してしまえ。

iPhone などの iOS の機能の **ショートカット** と **ヘルスケア** アプリでお手軽に実現できたので、ご紹介まで。
なお、期せずしてノーコードっぽい感じなので、スクリーンショット多めです。

それではさっそく iOS で「ショートカット」を開きます。

## 1. 入力フィールドの作成

右上の＋マークから新規ショートカットの作成を開始します。

アクションを追加を選択すると、いくつか選択肢が出てきます。
![ios_shortcut_002.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59810/949318d9-e4e3-4b91-247e-cfc5e4d6e671.jpeg)

検索フィールドに「入力」と入れ、候補が絞り込みされるので、「入力を要求」を選択します。

![ios_shortcut_003.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59810/462dc3ba-1aef-8734-9ed4-a3b38a0b1504.jpeg)

「プロンプト」を「体温」に、「テキスト」を「数字」に変更します。

入力を表示を増やすを選択すると、入力ルールを調整することもできます。

![ios_shortcut_005.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59810/9e1a388a-bf23-fd16-3cc0-9178e723f8e5.jpeg)



## 2. 「ヘルスケア」への書き込み

下部の＋から、ステップを追加します。
今度は、「ヘルスケアサンプルを記録」を追加します。

### 「種類」の指定

「種類」を「体温」に変更します。

ここで、ヘルスケアアプリへのアクセス許可を確認されます。

![ios_shortcut_006.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59810/1a326e64-3235-bb33-4e07-3fcfe4c6af35.jpeg)

一度、「ショートカット」アプリから「設定」アプリへスイッチし、
プライバシー - ヘルスケアから、
「ショートカット」からの書き込みを許可します。
(今回の用途では読み出しは不要です)

![ios_shortcut_007.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59810/967323cb-21ea-1991-d43e-837e32b9a85f.jpeg)

### 「値」の参照と適用

ショートカットの作成画面に戻って、「値」を指定します。

マジック変数 (杖っぽいアイコン) をクリックすると、
直前の入力ステップの下に指定入力という項目が現れるので、これを選択します。

![ios_shortcut_008.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59810/ac3e2a3f-3a45-678b-5501-f5ed5c084f6d.jpeg)


### 「日付」の指定 (とタイムゾーンを意識したフォーマット)

日付を、「現在の日付」にします。

![ios_shortcut_009.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59810/42a82193-6cc5-0df4-c37e-32cd017fcf82.jpeg)

このままだと、私の iPhone では、記録日時が期待通り動かなかったので (12 時間ずれてたりする)、日付フォーマットをカスタムフォーマットに変更の上、
「`yyyy-MM-dd HH:mm:ss Z`」を指定します。

![ios_shortcut_010.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59810/3b95cefa-c940-48ba-665b-f99a9d37826f.jpeg)


## 3. テストラン＆保存

右下の再生ボタン (横向き三角) を選択すると、入力プロンプトが現れるはずです。
体温の数値を更新して、実行すると、ヘルスケアへの記録が実施されます。

最後に右上の次へを選択し、ショートカットに名前をつけて、完成です。
実行するとこんな感じ。
![ios_shortcut_012.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59810/5fb96b1e-2032-6a21-2c7b-7077543d842f.jpeg)


記録された結果は、ヘルスケアアプリの体温を確認すると、
冒頭のようなグラフ表示 (最初は点しか無いと思いますが) に反映されていることが確認できるかと思います。

![ios_shortcut_011.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59810/60165a8d-f32f-53bf-0ef0-565d142e6a6a.jpeg)

だいたい 10 分くらいでそれなりの形になるかと。
あとは工夫次第で、どうぞ。
Windows10にGitをインストール

# はじめに

Windows10にGitをインストールしたときの、チェックボックスをメモとして残しておく。

# 手順

## インストーラをダウンロード
* ダウンロードサイト ([git-scm.com](https://git-scm.com/))
* ダウンロードサイト右の"Download 2.x.x for Windows"をクリック

## Gitのインストーラを起動
* "Git-2.x.x-64-bit.exe" をクリック
* "このアプリがデバイスに変更を加えることを許可しますか?"は"はい"を押す

### Information
* "Next" をクリック

### Select Destination Location
* "To continue, click Next. If you would like to select a different folder, click Browse."
    * 変更なし
    * "C:\Program File\Git" 
* "Next" をクリック

### Select Components
* ☑ "Additional icons" 
    * ☑ "On the Desktop" 
* ☑ "Windows Explorer integration"
    * ☑ "Git Bash Here"
    * ☑ "Git GUI Here"
* ☑ "Git LFS (Large File Support)" 
* ☑ "Associate .git* configuration files with the default text editor" 
* ☑ "Associate .sh files to be run with Bash" 
* ☑ "Use a TrueType font in all console windows" 
* ☑ "Check daily for Git for Windows updates" 
* "Next" をクリック

### Select Start Menu Folder
* "To continue, click Next. If you would like to select a different folder, click Browse."
    * 変更なし
    * "Git" 
* ☐ "Don't create a Start Menu folder"
* "Next" をクリック

### Choosing the default editor used by Git
* "Use Visual Studio Code as Git's default editor" に変更
* "Next" をクリック

### Adjusting the name of the initial branch in new repositories
* ◯ "Let Git decide" 
* ⦿ "Override the default branch name for repositories" 
    * [main]
* "Next" をクリック

### Adjusting your PATH environment
* ◯ "Use Git from Git Bash only" 
* ⦿ "Git from the command line and also from 3rd-party software" 
* ◯ "Use Git and optional Unix tools from the Command Prompt" 
* "Next" をクリック

### Choosing HTTPS transport backend
* ⦿ "Use the OpenSSL library"
* ◯ "Use the native Windows Secure Channel library" 
* "Next" をクリック

### Configuring the line ending conversions
* ⦿ "Checkout Windows-style, commit Unix-style line endings"
* ◯ "Checkout as-is, commit Unix-style line endings"
* ◯ "Checkout as-is, commit as-is" 
* "Next" をクリック

### Configuring the terminal emulator to use with Git Bash
* ⦿ "Use MinTTY (the default terminal of MSYS2)"
* ◯ "Use Windows' default console window" 
* "Next" をクリック

### Choose the default behavior of `git pull`
* ⦿ "Default (fast-forward or merge)"
* ◯ "Rebase"
* ◯ "Only over fast-forward" 
* "Next" をクリック

### Choose a credential helper
* ⦿ "Git Credential Manager Core"
* ◯ "Git Credential Manager"
* ◯ "None" 
* "Next" をクリック

### Configure extra options
* ☑ "Enable file system caching" 
* ☐ "Enable symbolic links" 
* "Next" をクリック

### Configuring experimental options
* ☐ "Enable experimental support for pseudo consoles." 
* "Next" をクリック

## Installing
* インストール中

## Completing the Git Setup Wizard
* ☐ "Launch Git Bash" 
* ☐ "View Release Notes" 
* "Finish"ボタンを押す

# 終わり

本記事は終了です。

# References
フォームバリデーション（Forms validations）について解説してみた。

#・初めに
この記事は以下の方を対象としています。また、記事修正のコメントやLGTMなどモチベーションにつながるので**ポチっと**お願いします‼

+ Forms validationsについて知りたい方
+ 初学者の方
+ フロントエンドエンジニア志望の方

#・導入
閲覧ありがとうございます。この記事は、初学者がフロントエンド目指してロードマップに沿ってアウトプットしていく記事になります。
こちらの記事はPart4です。最初からご覧になりたいかたは、以下よりどうぞ。

#・記事一覧
[part1: Internet【HTTP,Browsers】](https://qiita.com/n4suka7/items/ac3c16b3e30ec59fff0d)
[part2: Internet【DNS,Domain,Hosting】](https://qiita.com/n4suka7/items/decb31c452cd8efbf4cb)
[part3: HTML【basics】](https://qiita.com/n4suka7/items/75be9cd6e5d68d99ccb3)

#・Part4 HTML【Forms validationos】
##Forms validationsとは
データをサーバーへ送信する前に、フォームに入力された情報が正しく入力されているかを検証(validation)することを、クライアント側で行われる**フォームバリデーション**といいます。
フォームバリデーションには、ブラウザーで行われる検証である**クライアント側検証**と、サーバー側で行われる**サーバー側検証**がありますが、今回はクライアントサイドの話をまとめていきたいと思います。

例えば、有名なサイトの登録フォームに行きフォームに入力漏れがあると、次のようなメッセージが表示されることがあると思います。これはフォームバリデーションによって表示されています。

・「このフィールドは必須です」
・「有効なメールアドレスを入力してください」 
・「パスワードは 8 文字から 30 文字の間で、1 文字以上の大文字、記号、数字を含む必要があります。」

なぜフォームバリデーションが必要かというと、1つはユーザーが正しい情報を入力しない場合、ユーザーのデータが誤った形式で保存されたり、アプリケーションが正しく動作しないことがあるため。2つ目はユーザーのデータを保護することにつながるため。そして3つ目は、保護のないフォームを悪用して、そのフォームを一部に持つアプリケーションに不正アクセスする方法がたくさんあるためです。
まとめると、フォームバリデーションはユーザーの操作のしやすさがあがるだけでなく、通信を保護することができるなど、多くのメリットがあるということが言えます。

##validationの方法
form validationの方法はいくつかあります。こちらは丸暗記というよりは、使うときになったら調べるスタンスでいいと思います。今回はHTMLで行う基本的な方法についてみていきます。

###コード
簡単に以下のコードを用意しました。

```hoge.html
~~
<form>
  <label for="choose">Which do you like banana or apple?</label>
  <input id="choose" name="i_like">
  <button>Submit</button>
</form>
~~
```

```foo.css
input:invalid {
  border: 2px solid red;
}

input:valid {
  border: 2px solid black;
}
```

このコードは、好きな果物をbananaかappleから選べる入力欄です。単純なテキストの`<input>`とそれに合わせたラベル、送信の`<button>`から成ります。送信が成功なら、cssの`input:valid`クラスが適用され、失敗なら、`input:invalid`クラスが適用されます。

##HTMLのrequred属性を使用する
required属性は、使うのが簡単なHTMLのバリデーション機能です。入力欄を必須にしたい場合はこの属性を使用します。

```html
<form>
  <label for="choose">Which do you like banana or apple?</label>
  <input id="choose" name="i_like" required>
  <button>Submit</button>
</form>
```

```css
input:invalid {
  border: 2px solid red;
}
input:invalid:required {
  background-image: linear-gradient(to right, pink, lightgreen);
}
input:valid {
  border: 2px solid black;
}
```

この CSS によって、入力が妥当でない場合には、入力を赤線で境界線を描きますが、入力が妥当な場合には、黒線で境界線を描きます。要求された値があり、値が妥当でないときは背景にピンクとライトグリーンのグラデーションを追加します。何も入力されないときは、デフォルトのエラーメッセージ(「このフィールドは入力必須です。」) が表示され、フォームの送信を阻止します。

#まとめ
今回は、簡単なフォームバリデーションの使用方法と、バリデーションについてまとめていきました。バリデーションの方法はこのほかにもJavascriptを使用した方法や、正規表現を使用した方法があります。
また、Formのテンプレートやコードは多く公開されていますので、調べてみると勉強になるかもしれません。

#次回予告
ここまで、Forms validationsついて書いてきました。次回はConventions and  Best Practices(HTMLの従うべき慣習)についてです。次回もよろしくお願いします。

#参考文献
[MDN Web Docs](https://developer.mozilla.org/ja/docs/Learn/Forms/Form_validation)
BlackHole + Audio MIDI設定でWEB会議を音声ごとキャプチャする(Mac)

# やりたいこと・対象ユーザー

- QuickTime Playerで画面録画する際、標準だとPC内部でなる音が録画されないので、「自分の声」　＋　「相手の声」　の音声を載せて録画できる環境を整えたい
- SoundFlower + LadioCastで環境作ったけど不調で代替案を探している（私はこのパターンです。録画中にLadioCastが突然クラッシュすることが頻繁にありました...)

---


# 環境

- MacOS Catalina 10.15.7(Intelチップ)

---


# 手順

---


## BlackHoleのインストール

---


```jsx
brew install blackhole-16ch
```

これで音声設定にて「BlackHole-16ch」が選択できるようになる

![Screenshot 2021-05-12 22.48.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490917/0339934f-b827-7910-466f-3c20d44ff6dc.png)


---


## Audio MIDI設定(Mac標準アプリ)

---


- アプリを開く

「midi」で検索すれば一発で出てくる
![Screenshot 2021-05-12 22.50.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490917/2f494ca1-9d24-73cb-40b6-a03a92b79986.png)

---


- 「+」をクリックし「複数出力装置」を選択

![Screenshot 2021-05-12 22.53.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490917/b2aec365-c46e-894f-4cb5-9bf88a827b90.png)

---


- 下記の通り「(自分の使用している出力デバイス)」「BlackHole 16ch」の[使用]にチェック

![Screenshot 2021-05-12 22.55.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490917/b866f3ef-828e-411a-5442-b6b3abc9dcbe.png)

---


- 同様に「+」をクリックし、次は「機器セット」を下記の通り設定
    - 私のようにヘッドセットを使用している場合は「入力」のチャンネルが設定されている方をチェックすることに注意

![Screenshot 2021-05-12 22.58.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490917/434dce97-81d2-35d3-edf6-63dd66afef22.png)

---


- 「複数出力装置」上で右クリック
    - ⇒ 「このサウンド出力装置を使用」

![Screenshot 2021-05-12 23.01.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490917/d54bb94a-92d9-1d67-5a3e-6e93fc149dac.png)

---


- 「BlackHole 16ch」上で右クリック
    - ⇒「このサウンド入力装置を使用」

![Screenshot 2021-05-12 23.15.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490917/8d305a66-b741-d63f-ec18-aaac95210418.png)


---


## QuickTime Playerで録音

- ⌘ + ⇧ + 5でQuickTime Player(録画)を起動
- 画面下部に現れる設定バー？で下記設定
    - オプション > マイク > 「機器セット」 を選択

---


## 録音スタート！
あとはそのまま録音スタートで画面を録画すると
「自分の声」　＋　「相手の声」　の音声が載った録画ができる！
(このタイミングで一度Youtubeとか流しながら録画してみてちゃんと音声拾えているかのテストはしてください)

---

## memo: 個別に出力装置を設定できる会議ツールについて
- ex. Google meet
- 出力の設定が「複数出力装置」になっていることを確認してください

![スクリーンショット 2021-05-20 10.20.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490917/16eb1ec8-4b14-256d-b1c6-f20d4bfb2e21.png)

---

# 参考

https://pc.watch.impress.co.jp/docs/column/yajiuma-mini-review/1262744.html

---


# 注意
- デメリット
    - 「複数出力装置」はマスタ音量がいじれない
        - 今は使っているヘッドセットの出力レベルをMIDI設定画面で弄って調整してますが、RightとLeftをそれぞれ弄るのが手間...誰か解決方法知りませんか？
mb_send_mail(): Unsupported transfer encoding &quot;7bit &quot; - will be regarded as 8bit　のエラー対応

先日、下記のサーバーエラーが出て困ったときの対応方法です。

実行環境：

  - CentOS Stream release 8
  - Apache/2.4.37
  - PHP 7.4.16

エラー詳細：

```
AH01071: Got error 'PHP message: PHP Warning: mb_send_mail(): Unsupported transfer encoding &quot;7bit &quot; - will be regarded as 8bit
```
対応方法：
色々確認していたら、メール処理でヘッダーに渡していたpostfixのバージョンがサーバー実機と違うことに気づきました:flushed:

```
[example@123-45-678-90]$ postconf | grep mail_version
mail_version = 3.5.9
milter_macro_v = $mail_name $mail_version
```

上のコマンドで確認したバージョンに修正します。

```
  // 【ユーザー宛】ヘッダーリスト
  $headers = [
    'MIME-Version'              => '1.0',
    'Content-Transfer-Encoding' => '7bit',
    "Content-Type"              => $default_char_set,
    "Return-Path"               => $from_mail,
    "From"                      => $from,
    "CC"                        => '',
    "Sender"                    => $from,
    "Reply-To"                  => $to_admin,
    "Organization"              => $display_name,
    "X-Sender"                  => $to_admin,
    'X-Mailer'                  => 'Postfix/3.5.9',
    'X-Priority'                => '3',
  ];
```

上記で `mb_send_mail()` のエラーも解消しました。コードはやはり、他からコピーしてくるときは注意ですね。
数字　並び替え

##学ぼうと思ったきっかけ
高校数学でデータの分析の課題で、表にあるデータを小さいものから順に並び替えて、そこから計算をしていくのだけれど、いちいち並び替えるのは面倒だし、ミスも連発するから、コードかけばいいやと思ったから！

##sort関数を使う
sort関数とはなんぞや？というと、配列の中の要素を一度文字列にして、文字コード順に並び替える！
それだけ！
だが、sort関数は引数に関数を指定できるので、渡す関数で並び替えのルール（規定）をつくることができるのだ！

``` index.js

const array = [2,1,5,4,77,123];
console.log(array.sort());

//[1,123,2,4,5,77]

```
このようになる！
きちんとした昇順ではない！
そこで、比較関数を引数に渡せばいい！！
比較関数（引数に渡す関数）とは、ソートするルールを決めるものぐらいの認識でいい！

```index.js
const array = [2,1,5,4,77,123];

function compare(a,b){
 return a - b;
}

console.log(array.sort(compare));
//[1,2,4,5,77,123]
```
#####二つの配列の要素の差で考える
・戻り値が正なら、引数１を引数２の後ろに並び替え
・戻り値が負なら、引数１を引数２の前に並び替え
・戻り値が０ならば並び替えない

今回は昇順を取り上げたが、降順なら引数に渡す値を

```index.js
const array = [2,1,5,4,77,123];

function compare(a,b){
 return b - a;
//bとaを逆にすると良い
}

console.log(array.sort(compare));
```

もっときれいな書き方やまちがいがあったらぜひぜひ教えてください！！
Windows10にPythonをインストール

# 手順

Windows10にPythonをインストールしたときの、チェックボックスをメモとして残しておく。

## インストーラをダウンロード
* ダウンロードサイト ([www.python.org](https://www.python.org/))
* ダウンロードサイト上部の"Downloads"をクリック
* "Download Python 3.9.5"をクリック

## Pythonのインストーラを起動
* "このアプリがデバイスに変更を加えることを許可しますか?"は"はい"を押す

### Install Python 3.9.5 (64-bit)
* ☑ "Install launcher for all users (recommended)"
* ☑ "Add Python 3.9 to PATH"
* ☑ "Customize Installation"
* "Next" をクリック

### Optional Features
* ☑ "Documentation" 
* ☑ "pip" 
* ☑ "tcl/tk and IDLE" 
* ☑ "Python test suite"
* ☑ "py launcher" 
* ☑ "for all users (require elevation)" 
* "Next" をクリック

### Advanced Options
* ☑ "Install all users" 
* ☑ "Assciate files with Python (requires the py launcher)" 
* ☑ "Create shortcuts for installed applications" 
* ☑ "Add Python to environment variables" 
* ☑ "Precompile standard library"
* ☑ "Download debugging symbols" 
* ☐ "Download debug binaries (requires VS 2017 or later)" 
* "Customize install location" は変更なし
    * [C:\Program Files\Python39]
* "Install" をクリック

## Setup Progress
* インストール中

## Setup was successful
* インストール完了
* "Close"ボタンを押す

# 終わり

本記事は終了です。

# References
JBoss EAP XP( Eclipse MicroProfile準拠の製品 ) 覚え書き

# モチベーション

掲題の製品名を伺う機会あったが、さっぱり存じなかったので
自分向けに備忘するもの。

# JBoss EAP XP とは
JBoss EAPに追加インストールできる、Eclipse MicroProfile仕様のImplementationモジュール。
公式HPにてjarファイル形式で絶賛、配布中。

正式名称は`JBoss Enterprise Application Platform expansion pack`とのこと。

# 公式ガイド辿り方

1. [JBoss EAPの公式HP](https://access.redhat.com/documentation/ja-jp/red_hat_jboss_enterprise_application_platform/)にアクセス
1. 左メニューの`Product Version`から、JBoss EAP製品バージョンを選択。  
*:2021年5月時点:JBoss EAP v7.3でしか利用不可の様子
1. 左メニューの`Category`から、`JBoss Enterprise Application Platform expansion pack (EAP XP)`で絞り込み。
1. 画面中央あたり`JBoss EAP XP x.y.z での Eclipse MicroProfile の使用 `が公式ガイド。  
*:2021年5月時点:[JBoss EAP XP 2.0.0](https://access.redhat.com/documentation/ja-jp/red_hat_jboss_enterprise_application_platform/7.3/html/using_eclipse_microprofile_with_jboss_eap_xp_2.0.0/index) が最新。

# JBoss EAP XP自体のライフサイクル

公式の[Life Cycle and Update Policies](https://access.redhat.com/support/policy/update_policies/)から辿れる。  
具体的には[こちら](https://access.redhat.com/support/policy/updates/jboss_eap_xp_notes)のページ。

2021年5月時点では以下。

* 1.x 系:  
  Full Supportは2021年1月11日に終了済。  
  Maintenance supportも2021年4月11日に終了済。
* 2.x 系:  
  Full SupportはEAP XP 3.0リリースを以って終了予定。  
  Maintenance supportは同3.0リリースから+3ヶ月の猶予が有る予定。(= 1.x 系のスパンを踏襲)

# その他:互換あるJBoss EAPバージョン(x.y.z の、zの部分)

ガイドの中(`1.2. JBoss EAP XP のインストール`)に明記あり。

JBoss EAP XP 2.0の場合は[こちら](https://access.redhat.com/documentation/ja-jp/red_hat_jboss_enterprise_application_platform/7.3/html/using_eclipse_microprofile_with_jboss_eap_xp_2.0.0/jboss_eap_xp_for_the_latest_microprofile_capabilities#jbossxpshortname-installation_default)。
以下、引用。
> JBoss EAP XP 2.0.0 を JBoss EAP 7.3.0 にインストールする場合は、最初に JBoss EAP 7.3.4 GA パッチを適用する必要があります。

# 参考リンク
[JBoss EAPの公式HP](https://access.redhat.com/documentation/ja-jp/red_hat_jboss_enterprise_application_platform/)
[Eclipse MicroProfile Configについて](https://qiita.com/omix222/items/3716db1e9c1a1b7930c9)
【Swift】キーボード表示時にviewを移動させる処理で詰まったこと(メモ)

# 症状
textFieldをタップした際にいい感じにviewを上に移動させたいが下記のような状態になってしまう。

![qiita用1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613702/3c18fd75-1124-830d-c91c-afb71068688b.gif)

本当は上に動くようにしたいのに、viewが下に動いてしまって何も見えなくなってしまっています・・・

この部分の処理はこんな感じ↓（ViewdidLoadでsetUpNotificationForTextField（）を読んで使用している）

~~~swift
    func setUpNotificationForTextField() {
        let notificationCenter = NotificationCenter.default
        // キーボードが出る時に呼ばれる
        notificationCenter.addObserver(self, selector: #selector(self.keyboardWillShow(_ :)),
                                       name:UIResponder.keyboardWillShowNotification, object: nil)
        // キーボードが隠れる時に呼ばれる
        notificationCenter.addObserver(self, selector: #selector(self.keyboardWillHide(_ :)),
                                       name:UIResponder.keyboardWillHideNotification, object: nil)
    }
    
    // キーボードが出てきた時の処理
    @objc func keyboardWillShow(_ notification: Notification) {
        // キーボードのMinYを取得
        let keyboardFrame = (notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as AnyObject).cgRectValue
        guard let keyboardMinY = keyboardFrame?.minY else { return }
        
        // doneBtnのmaxYを取得
        let btnMaxY = doneBtn.frame.maxY
        
        // 動きを登録
        let distance = btnMaxY - keyboardMinY + 60
        let transform = CGAffineTransform(translationX: 0, y: -distance)
        
        // アニメーション
        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [], animations: {
            self.view.transform = transform
        })
    }
    
    //キーボードが隠れた時の処理
    @objc func keyboardWillHide(_ notification: Notification) {
        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [], animations: {
            self.view.transform = .identity
        })
    }
~~~

上記でコードを載せたはいいが他画面では、ほぼ同じ処理で正常に動作しているのでコードが原因ではなさそう・・・

# 原因

原因は下記の赤枠部分をstackViewに入れているからでした。
![スクリーンショット 2021-05-12 22.09.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613702/42889527-281b-68bd-bfb7-2dccc57c4a95.png)

下の部分のコードは、下記画像の赤色部分ように画面上部からdoneBtnの下部までの距離を取得するのが意図でしたが、ボタンをstackViewに入れることで下記画像の緑部分のように、stackViewの上部からdoneBtnの下部までの距離を取得してしまっていたことが今回の症状の原因でした。

二つのボタンをstackViewから出してあげることで正常に動作しました。

~~~swift
// doneBtn(チェックマークのボタン)のmaxYを取得
        let btnMaxY = doneBtn.frame.maxY
~~~
![スクリーンショット 2021-05-12 22.43.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613702/ef58f608-42e1-bcae-32dd-ee9d8b47d249.png)

# わかったこと
UI部品のMaxY, MinY , MaxX, MinXは親viewを基準にしている（間違っていたらすみません）

以上です。
風景を北斎風に変換するアプリつくりました

技育CAMPの初めてのハッカソン~vol.3~に参加した記事です。

#開発したもの
アップロードされた画像を北斎風に変換して出力するwebアプリです。僕にとっては初めてのwebアプリ開発でした。
URL:https://github.com/koouu/fakeHokusai
![henkan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/503318/a109b506-86c8-465c-c9f1-a9af34f07624.png)



#チームメンバー
学校の同級生と2人で出場しました。

役割
僕　  ：画像変換、バックエンド
N君　:フロントエンド

使用した技術
![画像1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/503318/701c72a9-a819-13e7-71d5-0c98c4eb2306.png)


#変換モデル
Googleのcolabで、画像変換の機械学習を行っていました。UGATITというcycleGANの応用したものを使いました。形状の変化に強くて、人間をアニメ風に変換したとかが有名です。全結合層にAttentionを使ってるみたいです。
また記事にまとめるかも。




※GANとは
偽物作るAI作る時偽物かどうか分別するAIも一緒に学習すれば上手な偽物作れるようになるよねって感じ
※cycleGANとは
本物に戻せる偽物作れるように学習すれば元画像の特徴残せるよねって感じ
![画像2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/503318/d068e8c4-eb5a-f0e3-6194-c1533318a3f2.png)


論文
U-GAT-IT: UNSUPERVISED GENERATIVE ATTENTIONAL NETWORKS WITH ADAPTIVE LAYERINSTANCE NORMALIZATION FOR IMAGE-TO-IMAGE
TRANSLATION
https://arxiv.org/pdf/1907.10830.pdf


#バックエンド
pythonのflaskを使いました。flask使うのは初めてだったけど、シンプルで使いやすかったです。


#フロントエンド
htmlを使いました。ほんとはJS使いたかったけど、Pythonとうまくデータのやりとりができなかったので断念。



#大変だったこと
UGATITの学習モデルのサイズが1G超えてて、ローカルだと、cuda out of memoryがでて動きませんでした。結局風景を北斎風にする以外の部分全部削って動きました。gitからダウンロードできるモデルもその状態になってます。
あとシンプルにwebアプリ開発初めてだったんで難しかったです。

#今後
ローカルでしか実装できなかったんで今度は公開できるように頑張ります。
後発表終わった後に二枚目以降の画像の変換の出力が全部1枚目の画像を変換したものになっていることがわかりました。原因がわからないからもうちょっと勉強します...

#追記　(21/7/6)
二枚目以降の画像の変換の出力が一枚目と変わらないのはhtmlのキャッシュが原因でした。
cpuのモデルに変換しgpuがなくても動くようになりました。


#まとめ
楽しかった!
クラス継承時の処理の順番について

# クラス継承時の処理の順番について

JavaSilverSE11の勉強中、クラスの継承に関する問題の解説を読んで、よく混乱していたので、ここで自分なりにクラス継承時の処理の順番について調べてまとめてみました。
<br>

<!-- 各チャプター -->
<a id="#Chapter1"></a>

## 継承とは何か？
継承とは新しく機能を実装するときに、以前実装した機能と共通する機能を引き継ぐことです。

継承はJavaを中心とするオブジェクト指向の基本的な概念となります。

<br>
## クラスの継承
既存のクラスをもとに、新しい別のクラスを作成し、既存のクラスにある機能を引き継ぐことです。

クラスの継承により、継承先のクラスは同じプログラムを書く手間が省け、新しい機能（差分の機能）を実装するだけで良くなります。
![クラスの継承イメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1282434/0385e3fc-81ee-fad4-8843-9f86a0999353.png)

既存のクラス（継承元のクラス）のことをスーパークラス、

新しく作成したクラス（継承先のクラス）のことをサブクラスといいます。
<br>
<br>

## 継承の書き方

`class　サブクラス名　extends　スーパークラス名　｛　｝
`

・継承先のクラス（サブクラス）には「extends」を記述し、「extends」の後ろに継承元のクラス（スーパークラス）を記述する。

・継承元のクラス（スーパークラス）は一つしか記述できない。

・継承したクラスをさらに継承できる。

<a id="#Chapter2"></a>
# クラス継承時の処理の順番をコードを通して紹介
実際にクラス継承時の処理の順番を、メッセージのやり取りを例にコードを通して紹介します。

以下のコードのコメントに処理の順番を割り振っています。

【スーパークラス】

```Java
class SuperSample {
        public SuperSample() {
            //[5]SuperSample（）メソッドで「1」と出力をし、SuperSampleクラスのSuperSample（String　tmp）メソッドに戻る。
            System.out.println("1");
        }
         public SuperSample(String tmp) {
            //[4]thisを使い、SuperSampleクラスのSuperSample（）メソッドを呼び出す。
             this();
            //[6]SuperSample（String　tmp）メソッドで「2」と出力をし、SubSampleクラスのSubSample（）メソッドに戻る。
            System.out.println("tmp");
        }
}
```

【サブクラス】

```Java
class SubSample extends SuperSample {
        public SubSample() {
            //[3]superを使い、SuperSampleクラスのSuperSample（String　tmp）メソッドを呼び出す。
            super("2");
            //[7]SubSample（）メソッドで「3」と出力をし、SubSampleクラスのSubSample（String　tmp）メソッドに戻る。
            System.out.println("3");
        }
         public SubSample(String tmp) {
             //[2]thisを使い、SubSampleクラスのSubSample（）メソッドを呼び出す。
             this();
            //[5]SuperSample（）メソッドで「1」と出力をし、SuperSampleクラスのSuperSample（String　tmp）メソッドに戻る。
            System.out.println("tmp");
        }
}
```

【エントリーポイント】

```Java
class Main {
        public static void main(String[] args) {
            new SubSample("4"); //[1]エントリーポイントからSubSampleクラスのSubSample（String　tmp）メソッドを呼び出す。
        }
}
```
このコードは以下のように出力します。

```
1
2
3
4
```

まずこのコードに登場する「this」や「super」について説明します。

「this」はコンストラクタ内から、`オーバーロードされた別のコンストラクタ`を呼び出します。

「super」はコンストラクタ内から、`スーパークラスのコンストラクタ`を呼び出します。

今回記述したエントリーポイントやSubSampleクラスでは「this」や「super」を記述することで明示的にコンストラクタを呼び出しています。
<br>
<br>

<a id="#Chapter3"></a>
# まとめ
上記のコードの処理順はすごくややこしいと思いますが、以下を把握しておくと処理の順番が把握しやすいと思います。

・this();でコンストラクタ内から、オーバーロードされた別の引数のないコンストラクタを呼び出す。

・「super」はコンストラクタ内から、スーパークラスのの引数のないコンストラクタを呼び出す。
<br>
<br>

<a id="#reference"></a>
# 参考文献
[https://www.internetacademy.jp/it/programming/java/java-class-inheritance-function.html]
 [https://itsakura.com/java-inheritance]
pg_dumpでアーカイブファイル抽出からのリストア

# ダンプ

アーカイブ形式でダンプを取ります。

```sh
pg_dump \
    --file=$HOME/dump --format=t --dbname=mydb \
    --username=dbuser --host=localhost --port=5432
```

`--schema` もしくは `-s` でスキーマ指定

```sh
pg_dump \
    --file=$HOME/dump --format=t --dbname=mydb --schema=myschema \
    --username=dbuser --host=localhost --port=5432
```

# リストア

アーカイブファイルをDBに読ませます。
スキーマやテーブル定義とかもまるっとリストアしてくれます。

```sh
pg_restore \
  -h localhost -p 5432 -U dbuser -W -d mydb \
  --format=t $HOME/dump
```

既にスキーマやテーブルが存在する場合は `--clean` もしくは `-c` を付けるとオブジェクトを消してからリストアしてくれるので不要なエラーログが出力されず、精神衛生上よろしいかと思います。

```sh
pg_restore \
  -h localhost -p 5432 -U dbuser -W -d myuser \
  --clean --format=t $HOME/dump
```

おわりです。
Synology の NAS で NVMe SSD にボリュームを割り当てる

Synology DS720+ には通常のSATAのベイが2つと，M.2スロットが2つあります．

https://www.amazon.co.jp/dp/B087Z6SNC1

深く考えず，SATAとMVMeを組み合わせれば，4台のSSDを使えるだろうと思って購入しました．初めてのNASです．

# 結論

M.2に挿したSSDはキャッシュ専用になってしまうみたいで，Web UI (DiskStation Manager) からはボリュームを作成するときに選択できませんでした．
なので，NASにSSHでログインして自分で初期化する必要があるみたいです．


### 手順

NVMe接続のSSDは `/dev/nvme0` または `/dev/nvme1` として認識されるので，NASに入っている synopartition コマンドを使ってパーティションを作成して初期化します．以下のようにrootで実行．

```bash
synopartition --part /dev/nvme0n1 13
mdadm --create /dev/md2 --level=1 --raid-devices=1 --force /dev/nvme0n1p3
mkfs.btrfs -f /dev/md2
reboot
```

- synopartition のオプションの `13` はパーティションの構成で，`synopartition --list`で一覧が表示されます．また，初期化済みのディスクがあれば， `synopartition --check /dev/sata1` 等で確認できるので同じやつを指定するのが無難そう (下の方に書いてありますが，小さいやつ選ぶほうが少し得かもしれません)
- `md2`はまだ使ってないデバイスを適当に．synopartition を実行すると3つのパーティションが作成されますが，`p3` がデータ領域のようです．
- ファイルシステムは ext4 か btrfs が良いようです
- 再起動するとWebUIからストレージプールが見えるようになります


![ssd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58515/0509fcf8-b9b6-5a73-34ac-c76f52ea8af7.png)

名前は「キャッシュ デバイス」のままですが，未初期化から「正常」になっています．
(最初の以外は，寄せ集めなのでメーカーも容量もバラバラですが)

![pools.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58515/f2596893-2047-2b30-b3c4-8375ef9d0e8f.png)

ストレージプールにも追加されました．

# 試したことのメモ

### とりあえずM.2スロットにSSDを挿す

キャッシュ専用になってしまう．
２つあるスロットどちらに挿してもボリュームの作成ボタンはグレーアウトしていて押せない．

### 手動でフォーマットしてマウント

fdiskでパーティション切って適当にフォーマットすれば使えるが，WebUIに出てこないので共有フォルダ作ったりするのが面倒．
ダメ元でmdadmでRAIDに追加したりしてみたけど，表示されないし，再起動時に自動でマウントされない．

### synopartition コマンドでパーティションを作る

同じことで困ってる人いるだろうと思って探したら，Redditの投稿を見つけた．

https://www.reddit.com/r/synology/comments/a7o44l/guide_use_nvme_ssd_as_storage_volume_instead_of/

synopartitionコマンドでパーティション作れば良いらしい．解決．

### パーティションの構成

基本的に3つのパーティションが必要．データ領域以外はRootパーティションとSwap領域として使われるっぽい．
データ領域以外はNVMeだと使われないみたいなので，数GB無駄になるけど最近のストレージ事情からしたら微々たるサイズ(？)

synopartitionでパーティションを作るとき，Rootパーティションが小さくなる `9` にしても良さそう(1-Bayとなってるやつは使えませんでした)

### DSMをNVMe SSDに入れる

本来はRootパーティションにDSMがインストールされて他のディスクとRAID1で同期されるようなので，NVMeも同様にすればSATAのディスクを全部抜いてもNASは動作するので便利な気がしました．

ただ，手動でRAID1に加えても再起動時にRAIDから外れてしまい，NVMe SSDだけではディスクが無いと言われて起動できず．

起動処理を眺めると，NASのフラッシュメモリ上のLinuxカーネルをロードして initrd に入っているスクリプトでストレージの設定をしていそう．
一通りカーネルモジュールのロードは終わってるし，NVMeも見えるはずだけど `/usr/syno/bin/synodiskport -installable_disk_list` がSATAしか返さない実装になっているようで，NVMeだけでは起動しない．

このLinuxカーネルが入っている領域は `/dev/synoboot2` からアクセスできるので変更できそうだけど，色々面倒そうなので断念．
npm run dev を行ったときの、newline required at end of file but not found のエラーの対処

vue.jsとrouterを読み込んだプログラムを再び
npm run dev でビルドしたときのエラーの対処をまとめます。

エラーコードをみると

```
newline required at end of file but not found
 src\router\index.js:20:3
```

ファイルの最後に空白が必要ということが書いてあります。
上記のコードのもと
src\router\index.js
の最後の行が詰まっていたので、改行します。

```
import Vue from 'vue'
import Router from 'vue-router'

import page1 from '@/components/page1'
import page2 from '@/components/page2'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      component: page1
    },
    {
      path: '/page2',
      component: page2
    }
  ]
})
　ここが改行してできた行
```

これをしたら正常にビルドできました。

また、
npm run dev
のビルドを実行するときは、
vue create でつくったファイルに移動してから実行しないと動きません。
Salesforce リリース準備状況戦略 ⇒ Sandbox プレビューによる早期アクセス

１．プレビュー Sandbox でリリースにアクセスするには、どうしたらよいですか?
２．プレビュー Sandbox を使用する利点は何ですか?
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634241/43a49fdc-081a-7f0d-f89b-d8a64ea7a455.png)
Elmer に STL を読み込ませる

# はじめに
チュートリアルもある程度やりましたので、好きな形状で解析をしたいものです。

モデリングソフトはいろいろあると思いますが、`OpenSCAD`というソフトが好きです。
# OpenSCAD
[OpenSCAD](https://openscad.org/) は、所謂パラメトリックCADで、CADに馴染みがないけれどプログラミング経験があってCADをやってみたい方にはうってつけのソフトです。
![20210512a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538241/3354468e-7a8c-09a8-c1b3-b78121762ae8.png)

```openscad.js
cube([200, 20, 10]);
```
`javascript`風のプログラミング言語でモデリングをします。
# 失敗
OpenSCADで`beam.stl`ファイルを出力します。
それを`Elmer`で開きますが、表示されないようです。
![20210512b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538241/bca500be-93f0-f588-e3a8-ebf4d6cc69e0.png)
`Input file`にbeam.stlは表示されているのですが．．．
# MeshLab
[「Elmer」ではじめる連成解析](http://www.kohgakusha.co.jp/books/detail/978-4-7775-2128-9) を読みますと、どうやらSTLファイルのバイナリー形式は駄目でアスキー形式にする必要がありそうです。
![20210512c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538241/f31279de-3637-31f7-a610-d2a0050bc2f0.png)
ここでは、[MeshLab](https://www.meshlab.net/) でSTLファイルを開き
![20210512d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538241/c6dbe983-664e-cb06-c1fc-dae67b4e6099.png)
`Binary encoding`のチェックを外してSTLで保存します。
# 成功
![20210512e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538241/cbff46dc-6cc0-60de-974f-cbe109d6c3d1.png)
無事読み込みに成功しました。
# おまけ
![20210512f.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538241/2a47145f-bc5c-d69d-5db1-72df57afef24.png)
ハリの上の文字で強度が変わるかもしれません。
~~曲げる方向により引張と圧縮で異なるかもしれませんが、構造としては負けられないところかもしれないです~~
# まとめ
+ Elmer さんありがとう
+ OpenSCAD さんありがとう
+ MeshLab さんありがとう
Zoom授業に入室するのが面倒くさいのでAppleScriptで自動化した

# いきさつ
昨年から大学ではZoom授業が行われ，今年もまだ遠隔授業...．
毎時間カレンダーアプリを開いてZoomリンクを開くのは面倒くさい．
プログラマの三大美徳でも怠惰って言うじゃないか．
だったら自動化してしまおう！

# 使うもの
* スクリプトエディタ
* Mac標準カレンダーアプリ

# カレンダーアプリの設定1
1. カレンダーアプリを開き，予定(イベント)を作成する
1. イベントの"メモ"または"URL"に授業のリンクを貼る

[注意] 同期しているGoogleカレンダーなどでも利用できます．しかし，googleカレンダーにはイベントにURLを設定できないため”メモ”部分にリンクを貼り付けてください

# プログラムを書く
1. スクリプトエディタを開く
1. 新規書類を選択し，エディタウィンドウを開く
1. AppleScriptが選択されていることを確認する（ウィンドウ左上）
1. 以下のプログラムを書き込む
1. メニューバー（画面上部） -> ファイル -> 書き出す
1. ファイルフォーマットを"スクリプト"から"アプリケーション"に変更して保存する

```scpt:hoge.scpt
script Method
	on main()
		try
			tell application "Calendar"
				set CurrentTime to (current date)  --現在時刻の取得
				tell Method to setSecond(CurrentTime)  --秒数を00に変更
				set cTime to result  --現在時刻を取得(検索開始時間)
				
				-- (設定1)
				set theEndDate to cTime + (10 * minutes) - 1 --検索終了時間 現在から30分後まで取得
				
				--カレンダー内のイベント情報を取得（現時刻から指定終了時間までの範囲指定）		
				--このカレンダーの名前(授業)から時刻でイベント検索
                                -- (設定2)
				set EvList to every event of calendar "授業" whose (start date ≥ cTime) and (start date ≤ theEndDate)
				
				--取得したイベント1つづつに実行
				repeat with theEvent in EvList

                                        -- (設定3)
					tell Method to openUrl(url of theEvent)

				end repeat
			end tell
		end try
	end getUrl
	
	on openUrl(link)
		-- デフォルトのブラウザで引数linkを開く
		open location link
	end openUrl
	
	on setSecond(theDate)
		-- 秒数を0秒に設定する
		set time of theDate to ((time of theDate) div minutes) * minutes
		return theDate
	end setSecond
end script

tell Method to main()
```

**[注意]**
(設定１)  theEndDateでは10分後に始まるイベントまでを取得するようにしています． 1時間後まで取得したい場合は 10*minutes を 1*hours に，1日後まで取得したい場合は 1*days のように変更してください．
(設定2)  カレンダー名（ここでは「授業」）を取得したいカレンダー名に変更してください．登録しているカレンダー名はカレンダーアプリで表示されているものです．
(設定3)  イベントの"メモ"にリンクを記述した場合は"url of theEvent" から "summary of theEvent"に変更してください．

# カレンダーアプリの設定2
1. カレンダーアプリを再度開き，登録したイベントを編集する
    1. 通知を なし -> カスタム
    1. サウンド付きメッセージ -> ファイルを開く
    1. 新たに表示されたカラムを カレンダー -> その他
    1. 先ほど作成したアプリケーションファイルを選択
    1. 通知時間を 5分前 くらいにする
    1. OKをクリックして確定

[注意]
授業は毎週あると思いますが，イベントを繰り返し設定すると来週以降リンクを取得できません．
1週間分の授業予定を登録 -> 全イベント選択 --> 来週以降にコピペ　をしてもらえると反応すると思います．
[OutSystems]Mobileでも多言語機能（Technical Preview）を使える

昨年末頃にTechnical Previewとして公開されたReactive Web Appの多言語機能ですが、Mobileでも利用できます。Mobileでも軽く動作確認してみました。

# 確認環境
Personal Environment(Version 11.11.0 (Build 26942))
Service Studio (Version 11.10.22)

# 前提条件とTechnical Previewの有効化
[以前書いた記事](https://qiita.com/jyunji_watanabe/items/b753c3e61af0b30dc522#%E5%89%8D%E6%8F%90%E6%9D%A1%E4%BB%B6)を参照

# テスト用モジュールを用意
以下のような画面を用意。吹き出しをつけた4箇所を、多言語機能を使って翻訳してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/e6f2b88d-2f4f-6cb5-d9a6-5fa1e255754c.png)

翻訳対象となるテキスト：
1. Text Widgetに固定で設定した文言「サンプルテキスト」
2. Expression WidgetのValueに設定した式「"サンプルエクスプレッション" + " " + CurrDate()」の「サンプルエクスプレッション」の部分
3. Client Actionで出力パラメータに固定で設定する「サンプルクライアントアクション」
4. Server Actionで出力パラメータに固定で設定する「サンプルサーバーアクション」

# 翻訳テキストの設定
## ロケールの設定
OutSystemsの多言語機能は、WidgetやAction内の翻訳対象テキストをデフォルト値として、指定のロケールでアプリケーションが動作するときに、事前設定しておいた翻訳テキストを代わりに表示します。

よって、まずは、翻訳対象となるロケールをモジュール内に定義します。
Service StudioでData > Multilingual Localesを右クリックして対象のロケールを追加。
ここでは、en-US（アメリカ英語）を追加しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/cc5481ac-c928-5f63-9d07-d4e6812ee914.png)

## ロケールに対する翻訳テキストを登録
Data > Multilingual Locales > en-US - English (United States)を右クリックして、「Edit Translations...」で、登録用のダイアログを開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/2fcc5dde-fc99-0364-c1f6-c53d2949e4af.png)

このダイアログで、ロケールを英語にしたときの翻訳テキストを指定してみます。
1. Translation inで「en-US」を選択
2. Text列で翻訳を行う先のテキストを見つける
    2-1. Behavior列を「Translate」に設定（これでこの行のテキストは翻訳対象と指定される）
    2-2. Translation in の列に翻訳後のテキストを設定

上記手順で、「翻訳対象となるテキスト」に書いた4つのテキストの翻訳を設定しています。

# 実行時にロケールを変更する
## System/SetCurrentLocaleでロケールを設定する
Client Actionです。
以下のようにロケールのテキストを入力引数に渡して実行すると、指定したロケールで動作するようになります。この式は、BooleanVarがTrueのときにen-US、それ以外ならja-JP（日本語）という指定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/eedf2dd6-bfd0-4bdf-7c4b-f361d3441a28.png)

## Systems/GetGurrentLocaleで現在のロケールを取得する
引数は不要です。
デフォルトでは、en-USでした。空文字列を渡すとエラーになったので注意が必要ですね。

# 配布方法による違い
モバイルアプリケーションには、ブラウザプレビュー（デバッグ用）、PWA、ネイティブアプリにビルド、という配布方法があります。
動作確認してみたら、いずれも多言語機能は動作しました。

ネイティブアプリにした場合に、翻訳テキストを更新して再Publishしたときの再インストールは不要でした。
（OutSystemsのネイティブアプリはネイティブアプリとしてインストールするときも、通常は更新ごとの再インストールが不要です。この場合は、Service StudioでPublishした内容をアプリ側から通信で取り込んでくれます。一部の修正はこれが機能せず、再インストールが必要になるのですが、多言語用の翻訳テキスト更新の場合は不要でした）

# 参考
Reactiveで動作確認したときの記事：[Reactive Web Appの多言語機能（Technical Preview）を試す](https://qiita.com/jyunji_watanabe/items/b753c3e61af0b30dc522)
公式ドキュメント：[Technical Preview - Multilingual Reactive Web and Mobile Apps](https://success.outsystems.com/Documentation/11/Developing_an_Application/Design_UI/Technical_Preview_-_Multilingual_Reactive_Web_and_Mobile_Apps)
CloudFormationで空のスタックを作成する

```yaml
Conditions:
  HasNot: !Equals [ 'true', 'false'  ]
  
# dummy (null) resource, never created
Resources:
  NullResource:
    Type: 'Custom::NullResource'
    Condition: HasNot
```

ダミーとして空のスタックを一旦作ってからにすると、スタックが削除されるロールバックがなくなって開発が楽になる。
【図解】妻がホームオフィスしたら、夫のネットがつながらない事件

##概要
タイトルのとおり、私のPCの有線LANがインターネットにつながらなくなってしまった。

ネットワークエンジニアとしては見過ごせない事象なので、原因と対策を図で解説する。

##原因：使用可能なグローバルIPアドレスが足りなくなったため
契約時の書面から、2つのグローバルIPアドレスが払い出されていることが確認できた。今回の事象の原因は、私のPCが3つ目のグローバルIPアドレスを必要とする状況になり、グローバルIPアドレスが足りなくなったためと考えられる。

※グローバルIPアドレス：ここでは、インターネットに接続するときに必要なIPアドレス、といった意味。対義語として、インターネットに直接接続できないプライベートIPアドレスがあり、こちらはたくさん使える。

##図１：夫のみホームオフィス(有線LAN接続)している状態
![スライド1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464218/2e78ef05-fc9f-c5db-0a0f-5c36ee545b36.png)

まず、妻がホームオフィスを始める前、私のPCが正常に有線LAN接続できていたときの構成が図１だ。品質の高い有線LANで通信し、無線LANはオフにしていた。

##図２：妻は有線LAN接続。夫は有線LAN接続不可のため無線LAN接続している状態
![スライド2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464218/87f9c786-cafb-468d-ee5a-dad5737f3c74.png)

今回の事象が発生した状態。妻がホームオフィスを開始することになり、リビングの壁面LANジャックで有線LAN接続した。リビングにはもうひとつ壁面LANジャックがあり、無線LANルータと接続している。

つまり、妻のPCと無線LANルータでそれぞれグローバルIPアドレスを持つことになる。契約で払い出されているグローバルIPアドレスは2つなので、私のPCに払い出されるはずのグローバルIPアドレスが不足し、有線LANでのインターネット接続ができない状態になった。

暫定対策として、有線LAN接続をやめて、無線LAN接続に切り替えた。無線LANで接続すれば、問題なくインターネットに接続できた。

なお、無線LAN接続したPCに払い出されるのはプライベートIPアドレスで、無線LANルータのグローバルIPアドレスを使ってインターネット接続を行う形になる(NAPT変換)。

##図３：夫妻ともに有線LAN接続している状態
![スライド3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464218/c06898a6-1aa7-16b9-7728-b4c35b9b5020.png)

図３の構成が恒久対策である。妻のPCを、無線LANルータのLANポートと接続することで、有線LAN接続でありながらプライベートIPアドレスを使う状態にする。一方、洋室の私のPCは今までどおり壁面LANジャックで有線LAN接続し、グローバルIPアドレスを使う。

この構成によって、私と妻の両方が有線LAN接続をしながら、グローバルIPアドレスの使用数を2つに留めることができる。

##まとめ
・契約内容をしっかり把握しておくことが大切。いわば仕様書。
・頭の中だけで考えず、図に落とし込んで構造化・視える化するとわかりやすい。


※noteにも書いてます。

https://note.com/anpanda_44075/n/na6fee6b9d572
【Vue】CompositionAPIでcomputed, data, method

# data
Vue2で定義していたdataプロパティ内の変数はcompositionAPIからは`reactive`又は`ref`の中に定義する

```vue
<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  setup() {
    const state = reactive({ hoge: 'huga' })

    return { state }
  }
})
</script>
```

型定義する場合

```vue
<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  setup() {
    const state = reactive<string>({ hoge: 'huga' })

    return { state }
  }
})
</script>
```

# computed
Vue2ではcomputedプロパティ内で記述していたメソッドはCompositionAPIではかなり異なる

```vue
<template>
  <div>{{fullName}}</div>
</template>

<script lang="ts">
import { defineComponent, computed } from 'vue'

interface UserName {
  firstName: string
  lastName: string
}

export default defineComponent({
  setup() {
    const state = reactive<UserName>({
      firstName: 'hoge',
      lastName: 'huga'
    })

    const fullName = computed(():string => state.firstName + state.lastName)

    return { state, fullName }
  }
})
</script>
```

# method
Vue2ではmethodプロパティ内でメソッド定義していたがCompositionAPIでは異なる

```vue
<template>
  <div>
    <button @click="clickEvent()">Click Me!<button>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  setup() {
    const clickEvent = ():void => alert('Clickしたよ!')

    return { clickEvent }
  }
})
</script>
```

関数型でかけていい感じ！

# Vue+TypeScriptの公式
https://v3.ja.vuejs.org/guide/typescript-support.html#npm-%E3%83%8F%E3%82%9A%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B7%E3%82%99%E5%86%85%E3%81%AE%E5%85%AC%E5%BC%8F%E5%9E%8B%E5%AE%A3%E8%A8%80
vue.jsとVue Routerを用いて、簡易なwebアプリ（SPA）を作る　CDN読み込み

環境　windows10

Vue routet　を　CDNを用いて行います。

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Vue Router</title>
  <!-- Vue Router のCDNの読み込み -->
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>
<body>
  <div id="app">
    <h1>{{ title }}</h1>
    <nav>
      <router-link to="/">ホーム</router-link>
      <router-link to="/news">ニュース</router-link>
      <router-link to="/about">About</router-link>
    </nav>
    <router-view/>
  </div>
<!-- javascriptの記述 -->
<script>
// コンポーネントの設定
const Home = { template: '<div>初めてのVue Resource</div>'}
const News = { template: '<div>今週のニュースは....</div>'}
const About = { template: '<div>会社までのアクセス方法は....</div>'}

// ルーティングの設定
const router = new VueRouter({
	routes : [
		{path:'/', component : Home},
		{path:'/news',component: News},
		{path:'/about',component: About}
	]
})

//Vueインスタンスへrouterインスタンスを渡す
var app = new Vue({
	el: '#app',
	data:{
		title: 'Vue Resource',
	},
	router,
});
</script>
</body>
</html>
```

とりあえず動かしたい人はコピペしてください。

なぜか公式のURLコピペしても動かなかったので参考までに。

参考
https://reffect.co.jp/vue/first-time-vue-router
細かい解説は
https://qiita.com/yuta-38/items/889f5edc5a0075aba274
rails DM機能　メッセージ編

class MessagesController < ApplicationController
  before_action :authenticate_user!, :only => [:create]

  def create　#room_idには@room.idを渡される（二人がDM時に開いているルームのID）
    if Entry.where(:user_id => current_user.id, :room_id => params[:message][:room_id]).present? 　#ログインしているユーザーの、二人がDM時に開いているルームに入った情報があるか[:message]には作ったメッセージに渡されたルームIDとコンテンツが入っている
      @message = Message.create(params.require(:message).permit(:user_id, :content, :room_id).merge(:user_id => current_user.id))
      redirect_to "/rooms/#{@message.room_id}"
    else
      redirect_back(fallback_location: root_path)
    end
  end
end
【FE】情報セキュリティ（まとめ1）



## IPsec

####1.1 ​定義

>暗号技術を用いてインターネットでデータを安全に送受信するための規格である。

####1.2 仕組みの種類

>​①　暗号化に利用する鍵を安全に交換する仕組み；

>②　相手のVPNルータを認証する仕組み。

####1.3 暗号化の仕組み

>実現方法：ＤＨ法（共通鍵を生成し、ノード間で共有するアルゴリズム）。

####1.4 VPNルータ認証の仕組み

>実現方法：RSAアルゴリズムを用いたディジタル署名。

####1.5 IPsecを利用したVPNの導入効果

>IPsecはOSI基本参照モデルのネットワーク層（TCP/IPモデルのインターネット層）でのプロトコル。

>ディジタル署名の役割：改ざんの検知と、送信元の認証（なりますしの検知）。

>VPN：インターネットを介して仮想的な専用通信路を構築する仕組み。

​
PythonでのIPアドレスの取扱いについて

#はじめに
IPアドレスの8進数の不適切な検証の脆弱性(CVE-2021-28918)がPythonのipaddressモジュール影響あるということで、ipaddressにおけるIPアドレスの取扱いを調べた。
また、ドット区切りIPアドレスからドット区切りなしIPアドレスへの変換を行う関数を作成した。

#ipaddressモジュールにおけるIPアドレスの扱い
以下のように、ipaddressモジュールがインポートされていることを前提とします。

```python
>>> import ipaddress
```
例として、ローカルループバックアドレス(127.0.0.1)を用います。

##ドット区切りIPアドレスにおける8進数の扱い
先頭の0は単に除外される

```python
>>> ipaddress.IPv4Address('127.0.0.01')
IPv4Address('127.0.0.1')
```

3桁を超えるとエラーになる（この例はChromeなどでは「88.0.0.1」に変換される。）

```python
>>> ipaddress.IPv4Address('0127.0.0.1')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.9/ipaddress.py", line 1302, in __init__
    self._ip = self._ip_int_from_string(addr_str)
  File "/usr/lib/python3.9/ipaddress.py", line 1199, in _ip_int_from_string
ipaddress.AddressValueError: At most 3 characters permitted in '0127' in '0127.0.0.1'
```

##ドット区切りなしIPアドレスの扱い
###10進数
```python
>>> ipaddress.IPv4Address(2130706433)
IPv4Address('127.0.0.1')
```
###8進数
```python
>>> ipaddress.IPv4Address(0o17700000001)
IPv4Address('127.0.0.1')
```
（Pythonでは、0oXXXが与えられるとXXXを8進数と認識し、内部では10進数として扱います。すなわち、本質的には10進数の場合と同じことをしています。）
###16進数
```python
>>> ipaddress.IPv4Address(0x7f000001)
IPv4Address('127.0.0.1')
```
（Pythonでは、0xXXXが与えられるとXXXを16進数と認識し、内部では10進数として扱います。すなわち、本質的には10進数の場合と同じことをしています。）
###バイト型
```python
>>> ipaddress.IPv4Address(b'\x7f\x00\x00\x01')
IPv4Address('127.0.0.1')
```

#ドット区切りIPアドレスからドット区切りなしIPアドレスに変換
例として、ローカルループバックアドレス(127.0.0.1)を用います。

##10進数
ドットごとに数値を取得し、最初の数値（例では、127）から順にに$ 2^{24}, 2^{16}, 2^8, 2^0 $を掛けて、合計を出力することで変換しています。
$ n\cdot2^x $の部分は、左シフトで計算しています。

```python
>>> def ipv4d2nd(ipv4):
...     return sum((int(n)<<8*d for d,n in enumerate(reversed(ipv4.split('.')))))

>>> ipv4d2nd('127.0.0.1')
2130706433
```

（以降は単に変換方法になります。）
##8進数
```python
>>> oct(ipv4d2nd('127.0.0.1'))
'0o17700000001'
```

##16進数
```python
>>> hex(ipv4d2nd('127.0.0.1'))
'0x7f000001'
```

#バイト型
```python
>>> ipv4d2nd('127.0.0.1').to_bytes(4, 'big')
b'\x7f\x00\x00\x01'
```

#参考文献
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-28918

https://news-block.com/python-is-also-affected-by-a-critical-ip-address-validation-vulnerability/
目次・まとめていきたいこと


# 勉強し、まとめていきたいもの


* Figma
    * Figmaを使ったWeb開発の高速化
* GCP
    * 資格取得にむけて
* Python
    * Djangoの開発


# 今後にむけて
随時内容を更新していこう
将来の見通しはわからないし、どうなるかもわからない
でも、そんな中でも自分ができるのは準備しておくこと
今後のためにいろいろ勉強して、準備をしておこうと思う
Wine での Python のありかのメモ(Python 使う app の cross-compile 用)

## 背景

Python を使うアプリ(e.g. pybind11)を Linux で cross-compile したい

python.org にある embedded(zip)だとヘッダファイルとかが無い.

どのようにしてビルドしたかの config.h ファイルが異る(はず)であろうから. .lib/.h だけ適当にディストーションから抜き出して利用というのも問題がありそう.

wine を使って .exe(installer)の Python を使うとします.

Python 3.9 を想定します.

## 手順

winecfg で, 利用する Windows バージョンを指定しておきます.

3.9 からは Windows 8.1 以上でないと使えなくなったようです.

あとはインストーラー起動してファイルインストールすれば OK

デフォルトでは, Windows 10 に設定した wine では(Linux 上では)以下にインストールされました.

```
.wine/drive_c/users/<USERNAME>/Local Settings/Application Data/Programs/Python
```

CI 環境などセットアップしたい場合は, 

https://docs.python.org/ja/3/using/windows.html

を参考に cli オプションを指定して.

## TODO

* [ ] Wine 上で conda 環境を作り conda の Python 環境を使って cross compile する.
railsにてlink_toの文字色を変える

link_toにて各リンク先を作成したが、デフォルトの色が青色なのでこの色を変えたいと思います。
![スクリーンショット 2021-05-12 21.02.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1340120/f337e1b1-6287-abdd-3a01-aaf326888732.png)
これはスキンケア用品に関するクチコミサイトですが、色合いがおかしいです。

やり方は簡単で、link_toの末尾にclass指定して、cssで変更します。

```ruby:view
<%= link_to category.category_name, categories_path(category_id: category.id) %>
これを、
<%= link_to category.category_name, categories_path(category_id: category.id, class:link) %>
```

```scss:scss
.link {
    text-decoration: none;
    color: white ; 
}
```
これで文字色の指定ができます。
文字色以外もこのscss上で編集できます。

![スクリーンショット 2021-05-12 21.31.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1340120/d6c1209b-214d-7337-d7e2-2c0dd604d93e.png)


以上、link_to内にclassを作るのがポイントでした。
AWS Lambda (Python 3.8)&Wrike APIで取得したjsonをパースし任意のキーで取り出してみる。

#この記事の概要
前回の続き

https://qiita.com/katoiek/items/b2fb9ce7ad759e5fb5aa

せっかくなのでほしい要素を取り出してみる。

#本記事の投稿者
前も書きましたがPython＆Lambda初心者（両方とも初めて書いてみた）なのでセオリー的なPerseの仕方などはわからないので力技です。

#大まかな手順
Wrikeで永続トークンを生成し、LabmdaでPythonの関数つくって実行し、かえって来たクエリの任意のキーを取り出す。

#今回の目的
サンプルソースからpermalink要素を抜き出す。
今回はpermalinkをキーとしましたが、その他クエリに使えそうなキーはWrike公式APIリファレンスを参照してください
https://developers.wrike.com/api/v4/tasks/#query-tasks
→こちらのResponseです。

#APIからのレスポンス（例）
```sample.json
{
    "kind": "tasks",
    "data": [
        {
            "id": "TASKID",
            "accountId": "AccountID",
            "title": "タスクのタイトル",
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
省略
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            "permalink": "https://www.wrike.com/open.htm?id=00000000",
        }
    ]
}
```
#ソース
```python:lambda_fucntion_2.py
import json
import urllib.request
from pprint import pprint

permanent_token='Wrike API 永続トークン'
url = 'https://www.wrike.com/api/v4/tasks'
header ={ 'Authorization': 'bearer '+ permanent_token}

def lambda_handler(event, context):
    req=urllib.request.Request(url, headers=header)
    
    with urllib.request.urlopen(req) as res:
    # resは http.client.HTTPResponse
        json_data = json.loads(res.read().decode('utf8')) # レスポンスボディ
        headers = res.getheaders() # ヘッダー(dict)
        status = res.getcode() # ステータスコード

        # data要素のみを格納
        data = json_data['data']
        #パーマリンクのみ取得　ここを任意のキーにすることで項目を変えられます。
        for entry in data:
            print(entry['permalink'])
```
#キー
今回はpermalinkをキーとしましたが、その他クエリに使えそうなキーはWrike公式APIリファレンスを参照してください
https://developers.wrike.com/api/v4/tasks/#query-tasks
→こちらのResponseです。
rails でDM機能　rooms編

rooms コントローラー
class RoomsController < ApplicationController
  before_action :authenticate_user!

  def create
    @room = Room.create　
#エントリー情報は一つのルームにつき二つ
    @entry1 = Entry.create(:room_id => @room.id, :user_id => current_user.id)  #ログインしているユーザーのエントリー情報を登録
    @entry2 = Entry.create(params.require(:entry).permit(:user_id, :room_id).merge(:room_id => @room.id)) #showで受け取った情報
    redirect_to "/rooms/#{@room.id}"　#roomのshowへ
  end

  def show
    @room = Room.find(params[:id])　#二通りのもらい方　新しいのか前のか
    if Entry.where(:user_id => current_user.id, :room_id => @room.id).present?　#エントリー情報があるか
      @messages = @room.messages　#ルームが持つメッセージ
      @message = Message.new　
      @entries = @room.entries　#ルームはエントリーを二つもっている。
    else　#なければ違う人のルームに入ろうとしているということ
      redirect_back(fallback_location: root_path)
    end
  end
end



ルームのshowビュー

<% @entries.each do |e| %>
  <h5><strong><a href="/users/<%= e.user.id %>"><%= e.user.email%>さん</a>　</strong></h5>

#二つのエントリー情報をもとに、アソシエーションつたってIDとe-mailを取得

<% end %>

<hr>
<% if @messages.present? %>　#messagesはルームにあるすべてのメッセージ
  <% @messages.each do |m| %>
    <strong><%= m.content %></strong>
    <small>by <strong><a href="/users/<%= m.user_id %>"><%= m.user.email %>さん</a></strong></small>
    <hr>
  <% end %>
<% else %>
  <h3 class="text-center">メッセージはまだありません</h3>
<% end %>

<%= form_for @message do |f| %>　#　@messageはカラのメッセージ
  <%= f.text_field :content, :placeholder => "メッセージを入力して下さい" , :size => 70 %>
  <%= f.hidden_field :room_id, :value => @room.id %>
  <br>
  <%= f.submit "投稿する" %>
<% end %>

<%= link_to "ユーザー一覧に戻る", users_path %>
docker+blackfire環境の構築(php)

##blackfireとは
パフォーマンスプロファイリングサービスです。
関数がどの経路で読み込んでいて、
どのくらい処理に時間がかかり、
どのくらいメモリを使用しているのか、
目視で確認できるので、アプリケーションのパフォーマンス向上などに使用します。

##用意するもの
* docker（念の為最新にしておきましょう）
* blackfireのアカウント（[ここから作れるよ！](https://blackfire.io/login)）
* chrome([拡張機能も使うので入れておく](https://chrome.google.com/webstore/detail/blackfire-profiler/miefikpgahefdbcgoiicnmpbeeomffld))
* 挫けない心

##環境を構築していく
```docker-compose.yml
blackfire:
    image: blackfire/blackfire
    ports: ["8707"]
    environment:
      BLACKFIRE_SERVER_ID: {サーバーキー}
      BLACKFIRE_SERVER_TOKEN: {サーバートークン}
      BLACKFIRE_CLIENT_ID: {クライアントキー}
      BLACKFIRE_CLIENT_TOKEN: {クライアントトークン}
```
サーバーキー・トークン、クライアントキー・トークンは、[blackfireのマイページ](https://blackfire.io/my/settings/credentials)から確認できます。

```docker:Dockerfile
RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \
   && curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/alpine/amd64/$version \
   && mkdir -p /tmp/blackfire \
   && tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \
   && mv /tmp/blackfire/blackfire-*.so $(php -r "echo ini_get ('extension_dir');")/blackfire.so \
   && printf "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8707\n" > $PHP_INI_DIR/conf.d/blackfire.ini \
   && rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz
```
用意していたDockerfileに追記する形で問題ありません。
また、すでに構築ずみの環境でしたら、buildし直しましょう。

```
$ docker-compose buide --no-cache

$ docker-compose up -d
```
これで環境は問題なくできるはずです。

##blackfireの使い方
計測したいページを開きます。（ローカル環境でも大丈夫です。）
拡張機能のblackfire profilerを起動し、profile!ボタンを元気よくクリックすれば計測してくれます。
![スクリーンショット 2021-05-12 21.11.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569093/f29ed832-9dae-6738-41fb-04da2c0c0a06.png)

結構待ちますが、終わったらView Call Graphをクリックで、ページ遷移し詳細がみれます。

##使ってみた感想
当環境が、Laravelを使っています。
サービスプロバイダーやミドルウェア、ビジネスロジック、Collection操作などの見直しに便利だったなぁと思いました。
SQLチューニングも行ったのですが、blackfireはあくまでロジックの精査に使用し、SQLに関してはdebugbarなどで確認しました。
日々の開発の中でなかなか最高パフォーマンスを出しながら開発するのも難しいですが、気づいたらめっちゃ遅い！とかなると思うので、タイミング見てパフォーマンスを気にしながら進めるのも重要だなと実感しました。