OmniAICreator/Qiita-1.07M huggingface dataset:
スワップ領域を追加してみた

# はじめに
今回は、以下の記事で紹介しているOracle Database 21cのインストレーション作業など、プロセスの途中でスワップ領域が不足してしまった場合の追加方法について紹介する。インストレーションの詳細は以下のリンクを参考にするとよい。

https://qiita.com/tk_miya/items/afc1390717816a87408e#ouioracle-universal-installer%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%97%E3%81%A6oracle-database-21c%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B

Oracle Databaseのインストレーション作業でOUIを使用したとき、前提条件でスワップ領域が不足しているとこのように注意される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2511285/97aa15dd-ce1b-1791-a871-f4644edec9ec.png)

今回は上記のOUIの前提条件より600MBほどのスワップ領域が必要とされているため600MB追加することにする。
# スワップ領域の追加方法
## ディスクの空き容量の確認
まず、OUIのウィンドウを閉じずに新たにターミナルを立ち上げ、以下のコマンドでディスクの空き容量を確認する。

```oracle:rootユーザー
free -m
```
オプション-mはメガバイトで表示する。※デフォルトはキロバイト
以下のように、メモリー(Mem)とスワップ(Swap)の総容量(total)、使用容量(used)、空き容量(free)がそれぞれ表示される。

```oracle:実行結果
# free -m
              total        used        free      shared  buff/cache   available
Mem:           1694        1159          82          12         452         483
Swap:          2107         119        1988

```

## スワップ用の領域を作成
以下のコマンドでスワップ領域として使用するためのファイルを作成する。

```oracle:rootユーザー
dd if=/dev/zero of=/var/swp bs=1M count=600
```

### ddコマンドについて
``` dd if=fileA of=fileB```
fileAをfileBにコピーするという内容。

``` dd if=/dev/zero of=作成するファイル名 bs=ブロックサイズ count=ブロック数```
/dev/zeroは全てnullを返すというスペシャルファイルである。また、bsとcountで作成するファイルのサイズと個数を指定できる。

以上より、今回実行した上記のコマンドは、「***600M(1M×600)バイトの(中身が全てnullの)ファイルを作成する***」という内容である。

```oracle:実行結果
# dd if=/dev/zero of=/var/swpfile bs=1M count=600
600+0 records in
600+0 records out
629145600 bytes (629 MB, 600 MiB) copied, 0.776777 s, 810 MB/s
```

## スワップ用ファイルに変換
以下のコマンドを実行して、作成したファイルをスワップ領域として使用できるファイルに変換する。

```oracle:rootユーザー
mkswap /var/swp
```

```oracle:実行結果
# mkswap /var/swp
mkswap: /var/swp: insecure permissions 0644, 0600 suggested.
Setting up swapspace version 1, size = 600 MiB (629141504 bytes)
no label, UUID=af2e5f79-ccfe-4433-af69-9bd2aeccbc10
```

また、以下のコマンドで作成したファイルに権限を付与する。

```oracle:rootユーザー
chmod 600 /var/swp
```

## スワップ領域の追加
以下のコマンドで、作成したスワップ領域用のファイルをスワップ領域に追加する。

```oracle:rootユーザー
swapon /var/swp
```

## 追加されているか確認する
以下のコマンドを実行してスワップ領域が追加されていることを確認する。

```oracle:rootユーザー
free -m
```

```oracle:実行結果
# free -m
              total        used        free      shared  buff/cache   available
Mem:           1694        1101          28          12         564         542
Swap:          2707         158        2549
```

以上よりスワップ領域が600MB追加されていることが確認できた。
iPhone で video タグを使う場合、最初のフレームを読み込まず画面が一色のままになる問題の対処

# 問題

HTML で video タグを貼った場合、動画の最初のフレームをプレビュー画面として表示して欲しい。
これはほとんどの環境でそういう仕様になっているが、iPhone はそうなっていない。

# 原因

以下でやり取りがある通り、比較的近年になって起こるようになった問題のようだ。

https://developer.apple.com/forums/thread/129377

原因は iPhone の video タグの実装で preload に何を指定しても再生するまで動画を読み込まないこと。

https://developer.mozilla.org/ja/docs/Web/HTML/Element/video

にもある通り `preload="auto"` は「読み込んでも良い」というだけで、別段読み込まなくても良いという解釈ができる。 そのため、iPhoneでは通信量削減のために自動的に動画を読み込まないものと推測される。
preload は auto, metadata, none の値を設定可能だが、「必ず読み込め」という指示はできない。 そのため、実装依存で掲題のような何も表示されない画面が表示されることになる。


# 対処

## `#t=0.00001` などを src の末尾に付与する

https://www.w3.org/TR/media-frags/#naming-time

`#t=...` は再生する動画の範囲を指定するための構文である。
そのため、これで始点をわずかに開始から動かすことで、強制的に動画を読み込ませるというハックができる。

https://muffinman.io/blog/hack-for-ios-safari-to-display-html-video-thumbnail/

より細かくは上記を参照。


## poster を作成してその画像を poster 属性で指定する

そもそも、動画の最初を自動表示するという機能に頼らず、poster 属性を利用して適切な画像をプレビューとして表示すれば対処できる。
個人的に最高だった解説ページ集【JavaScript編】

数多くある解説記事の中で、個人的にすごくわかりやすかったものを一覧にしてみました。
執筆者の皆様には感謝と尊敬の気持ちでいっぱいです。。

## コールバック関数

https://sbfl.net/blog/2019/02/08/javascript-callback-func/

簡単なコードの例から順を追って、かみ砕いて解説してくださってます。
　


## Promise

https://qiita.com/cheez921/items/41b744e4e002b966391a

数多くあるPromise解説記事の中でも、説明が具体的で自分には一番しっくりきました。
　

## async/await

https://qiita.com/soarflat/items/1a9613e023200bbebcb3

LGTM数3000超え（2022年2月時点）の大人気記事です。
aysncを単体で使った場合の例なども使用し順を追って解説してくださってます。
※async/awaitの理解にはPromiseの知識が必要です。
　


## イベントループ・コールスタック・タスクキュー

https://qiita.com/UTDoi/items/d49ea919818d9b519f93

同期処理や非同期処理の実行が、どのような仕組み・ルールに基づき進められていくのかを
図を交えて非常に丁寧に説明してくださっています。
　


## 例外処理

https://uhyohyo.net/javascript/9_8.html

例外処理の意味、`throw new Error()`や`try,catch`についてわかりやすく説明されています。

　

## 非同期処理全般

https://qiita.com/ryosuketter/items/dd467f827c1b93a74d76

コールバック関数、Promise、async/await、例外処理など
非同期処理全般について幅広く解説してくださってます。
個人的には、各項目の復習・全体的な理解用に適しているかなと感じました。
PHP用SlackAPIのUtilityライブラリを公開しました！

タイトルの通りです！！
私が長期インターンでおこなった業務の中に、PHPでSlackAPIを使うものがいくつか含まれていて、今後使うことがあるかもしれないメソッドがあったので、経験の意味も込めて、ライブラリにして、composerで使えるようにPackagistで公開してみました！！

##リンク
・Githubリポジトリ
https://github.com/Hottomo0610/php-slackapi-util

・Packagist
https://packagist.org/packages/hottomo/slack-api-utility



##作った経緯と感想
今まで自分が作ったもので何か外部に公開できるものが欲しい、そしてあわよくば就活で使いたい、という浅ましい考えのもとに作りました（なおレベルが低すぎるので恥ずかしい）。
もちろんライブラリの公開というのは初めての経験だったので、とても新鮮な気持ちでしたし、自分が作ったものが世に出るってこういうことなんだな、と思いました。

正直特に感想とか思いつかなくてゴミみたいな文章書いてしまいましたが、このライブラリ、ぜひ使ってみてください！
私が言いたいのはそれだけです！

ではまた！！
マネージャの大切な行動「アンブロック」

# はじめに
「Regional Scrum Gathering Tokyo 2022」の牛尾剛氏のセッションで、「アンブロック」という単語が登場した。
「アンブロック」という行動は、マネージャにとって、とても大切な行動だと思えたので、情報をまとめておく。

# 「アンブロック」とは

https://www.publickey1.jp/blog/22/1_regional_scrum_gathering_tokyo_2022.html

> マネージャのすごく大事な仕事に「アンブロック」というのがあります。
> 開発者の人がどこかで詰まっている状態になると、マネージャが助けてくれる。ブロックされているものをアンブロックしてくれるんです。
> 例えば、僕が技術的に詰まるとして、誰かに聞かなあかんけど、誰か聞かなあかん人がなかなか答えてくれへんとか、そういうこともあるかもしれないです。そういうブロックをされる状況が一番生産性を阻害すると思うんですね。そういうときにマネージャがアンブロックを手伝ってくれる。ある人に繋いでくれたり、マネージャ経由で他の人が僕に協力してくれたりとか。


# 「アンブロック」に必要なこと
私もマネージャとして「アンブロック」を実施している。
「アンブロック」実施するうえで必要になるのが、以下の3点と考えている。

1. 詰まっている状態を知る仕組み
1. 様々な有識者との人脈
1. アンブロックを手伝える余裕

## 1. 詰まっている状態を知る仕組み
私は、詰まっている状態を知る仕組みとして、以下を用意していた。そのときの状況によって、一部の仕組みしか使っていない場合もある。

* デイリーMTG（デイリースクラム、朝会）
* 日報
* 分報

詰まっている状態を知る仕組みを運用するときに大切になることは、**「報告を受けた人ではなく、報告をした人が、その労力に見合う成果を得られるようにする」**という考え方である。

また、「詰まったら打ち上げて」と言っても、「忙しい皆さんの邪魔になってしまうかもと考えると、打ち上げにくいです。」と言う若手メンバがいた。
これに対する対策として、『分報』とGoogle人工知能チームの『15分ルール』は、有効だった。


### 参考記事

https://qiita.com/kaizen_nagoya/items/97ad8ac9217c12c3bb69

https://qiita.com/tatesuke/items/fd5483be1b72727d3d34

https://qiita.com/kojimadev/items/ea8825dec1b0d0d2874c

https://tkybpp.hatenablog.com/entry/2016/08/16/173055

## 2. 様々な有識者との人脈
私は、詰まっている状態をなんでも解消できるほどのスキルを有していなかったため、人にアンブロックの手伝いをお願いする必要があった。
そのために、社内の誰が何を知っているか把握し、社内の様々な人と関係を作っておいた。
関係を作るために、意識したのは以下の2つである。

* 頼まれたことは、ハイ！よろこんで（嫌がらない・断らない・後回しにしない）    
  まず自分が相手に何かしらの貢献をしておけば、次は自分に何か困りごとがあったときに助けてもらえる可能性が出てくる。つまり、Giveが先でTakeが後。
* 社内イベントへの積極的な参加  
  社内イベントに参加すると、普段のプロジェクトでは関連のない方々と、情報交換・意見交換ができる。この情報交換・意見交換に、時間を投資する。その時点では、すぐに価値がでないかもしれないが、ゆくゆく投資した時間が価値を生み出すことがある。

### 参考記事
http://www.daisyo.co.jp/yorokonde/

## 3. アンブロックを手伝える余裕
詰まっている状態を知り、様々な有識者との人脈があっても、マネージャに余裕がなければ動けない。
プレーイングマネージャだと、早い「アンブロック」の行動は難しいかもしれない。

以下の書籍の考え方も重要だと思う。

* 「人月の神話【新装版】」，Jr FrederickP.Brooks

> 製作主任と技術主任を分けるべき（同一人物にすべきではない）
> 有能な管理的能力と強力な技術的能力を兼備している人間はめったにいない
> 技術主任の時間を圧迫せず、技術的判断を下せる権限を確立してやるべき

* 「ソフトウェアエンジニアリング論文集80's~デマルコ・セレクション」，トム・デマルコ, ティモシー・リスター

> （ワインバーグの論文より）
> 1 自分に対する圧力を緩め、自分の業界や分野以外に興味をもち、他の業界や分野から学ぶ時間を作る。
> 2 自分に対する過度の管理をやめれば、他人への過度の管理もやめられる。


### 参考記事
https://qiita.com/kazuo_reve/items/6976029e72763ea73245


# おわりに

ちなみに、うちのチームでは、メンバもある程度の余裕が持てていたので、マネージャが「アンブロック」する前に、メンバがお互いに「アンブロック」をしてくれていました。
メンバに感謝です。ありがとう。


# 関連記事
https://qiita.com/kazuo_reve/items/d7d2cd4ecce2e383bb3f

https://qiita.com/kazuo_reve/items/6976029e72763ea73245
データ整備こぼれ話 vol.1: Presto で文字列を配列化して最後の要素を取得

Python の `list[-1]` みたいなことをやりたい。
本来ドメイン的には Auto increment の数値が入っている場所に、過去データはカンマ区切りで複数の値が入っていたため (なので `TEXT` 型だった)、最後を取得して数値に用途で作成したスニペットです。

# Athena presto

```sql
SELECT SPLIT('aaa,bbb,ccc', ',')[CARDINALITY(SPLIT('aaa,bbb,ccc', ','))]
>>> ccc

SELECT SPLIT('aaa', ',')[CARDINALITY(SPLIT('aaa', ','))]
>>> aaa
```
Docker Composeでログの設定をする

こんにちは、@hanamichiです!
今回はDockerログについてまとめました〜

## やること
ロギングドライバを設定してDockerコンテナの保存されるログのサイズやファイル数を変更する。

## ロギングドライバとは？
Dockerには実行中のコンテナやアプリから情報を得るために複数のログ記録（ロギング）機能があり、これらの仕組みをロギングドライバと呼びます。

## docker-compose.ymlにロギングドライバを設定する

```docker-compose.yml
services:
  xxx:
    logging:
      options:
        max-size: "10k"
        max-file: "1" 
      driver: json-file

```
```driver: json-file```
ログの保存方法を設定しており、ここではJSON形式で指定しています。
他にも[syslog](https://qiita.com/sasakiki/items/7975bad6fb12fbd6158e)や[awslogs](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/using_awslogs.html)の指定できます。

```options: ```
ここではサイズやファイル数などログの形を指定できます。
[参考記事](https://github.com/compose-spec/compose-spec/blob/master/spec.md)


ぜひ参考にしてみてください!
OSI参照モデルとTCP/IPの階層をわかりやすく表にしてみた

#1.OSI参照モデル
OSI参照モデルとはISO（国際標準化機構）が決めた異なるベンダ感で相互通信するための「ネットワーク・モデル」と言われる統一規格のことです。

|　層　|　名前　|　役割　|　プロトコル　|
|----|--------|--------|:-----------|:-----------|:-----------|
|第7層|アプリケーション層|ユーザーへサービスの提供をする|HTTP、SMTP、POP3、SSHなど
|第6層|プレゼンテーション層|データの表現方式の変換|HTTP、SMTP、POP3、SSHなど|
|第5層|セッション層|通信の開始かと終了を制御|HTTP、SMTP、POP3、SSHなど|
|第4層|トランスポート層|通信の信頼性の確保|TCP、UDP|
|第3層|ネットワーク層|経路制御|IP|
|第2層|データリンク層|隣接間の配送|IP|
|第1層|物理層|論理的信号と物理的信号の制御|IP|




#2.TCP/IP
TCP/IPとはインターネットなどで標準的に用いられる通信プロトコル（通信手順）で、TCP(Transmission Control Protocol)とIP(Internet Protocol)を組み合わせたものです。

| 階層 | 名前 |対応するOSI参照モデル|
|:--|:--|:--|
| 第1層  |ネットワークインタフェース層  |物理層、データリンク層
| 第2層  | インターネット層  |ネットワーク層
| 第3層  | トランスポート層  |トランスポート層]
| 第4層  |  アプリケーション層 |セッション層、プレゼンテーション層、アプリケーション層
#3.補足
##3-1.基本用語の説明
LAN・・Local Area Networkの略で導入したユーザが主体となって管理しているネットワーク
WAN・・Wide Area Networkの略で広い範囲を結ぶネットワーク。電気通信事業者が運用している。
プロトコル・・通信手順
クライアント・・サービスを受ける側
サーバー・・サービスを提供する側
#4参考記事
[押さえておきたいTCP/IPの基礎](https://qiita.com/Yasuaki-Nagai/items/c322c48684cf89b50ca4)
[[初心者向け]プロトコルとOSI基本参照モデル](https://qiita.com/tochisuke221/items/9a516746a4db3bafc08e)
Spring Boot開発環境構築

##概要

先日Spring Bootを使ってWebサーバーを構境構築していたら、謎のエラーに苦しみ4時間程の時間を費やしてしまいました。（エラーの内容をメモし忘れるという致命的なミスをしてしまいました）

特にエラーなく環境を構築できたならいいのですが、僕と同じ謎のエラーに苦しんでいる人もいるかもしれないと思い、僕のやり方を書き残しておきます。
ちなみに未だに何が原因で何がエラーを解決したのかはよくわかっていません。

####参考

https://youtu.be/9SGDpanrc8U

##環境

言語：Java 17
OS：Windows 10 x64
IDE：Intellij Community Edition 2021.3.2
フレームワーク：Spring Boot 2.6.3
プロジェクト管理ツール：Maven

##用語解説

**Spring Boot**：Java言語の環境下で使用することが出来るWebアプリケーションの開発をサポートするフレームワーク。

**Intellij**：Javaなど数多くのプログラミング言語に対応した統合開発環境（Wikipediaより引用）

**Maven**：Java用プロジェクト管理ツール（Wikipediaより引用）

##セットアップ

###Java

まずJavaをダウンロードしましょう。

https://www.oracle.com/java/technologies/downloads/#jdk17-windows

今回は、Java 17をダウンロードしました。11や8でも大丈夫だと思います。

そしてPathを通します。
システム環境変数の編集>環境変数

例）
Path > C:\Program Files\Java\jdk-17.0.2\bin
JAVA_HOME > C:\Program Files\Java\jdk-17.0.2

###Intellij

Community Editionをダウンロードしてください。

https://www.jetbrains.com/idea/download/#section=windows

###Maven

Apache Mavenをダウンロードしましょう。

https://maven.apache.org/download.cgi

そしてPathを通します。
システム環境変数の編集>環境変数

例）
Path > C:\Users\IEUser\Downloads\apache-maven-3.8.4-bin\apache-maven-3.8.4\bin

###Spring Boot

https://start.spring.io/

Project -> Maven Project
Language -> Java
Spring Boot -> 2.6.3
Packaging -> Jar
Java -> 17

残りの設定は変えないで大丈夫です。プロジェクトのデフォルトの名前は"demo"になっているので変えたい場合は変えてください。

###仕上げ

では最後の仕上げをしましょう。
Intellijを起動して、ターミナルを開きます。
そして"mvn"というコマンドを実行します。いろいろとダウンロードされるはずです。
そして先程ダウンロードしたSpring Bootのプロジェクトをopenしましょう。開くと同時にこちらも様々なダウンロードが始まります。

この段階でエラーが無ければ環境構築成功です。

##最後に

この記事が皆さんのお役に立てれば嬉しいです。最後まで読んでくださってありがとうございました。

質問がある方は是非コメントしてください😃
【OCI】Private Subnetのインスタンスから、AutonomousDBのOracle Database API for MongoDBに接続する方法

# やりたいこと

- VCN環境のプライベートサブネットにあるインスタンスから、Oracle Database API for MongoDBに接続する
    - 必要なコンポーネントと設定を確認する

# 導入
OCIのAutonomousDBにて、2021/12にOracle Database API for MongoDBがGAしました。
これは、MongoDB用に作成された既存のアプリケーションをAcutonomousDBに接続できるようになるサービスです。

[英語サイト:Using Oracle Database API for MongoDB](https://docs.oracle.com/en/cloud/paas/autonomous-database/adbsa/mongo-using-oracle-database-api-mongodb.html#GUID-8321D7A6-9DBD-44F8-8C16-1B1FBE66AC56)



使用にあたる制限事項として、ネットワーク・アクセスの選択は「許可されたIPおよびVCN限定のセキュア・アクセス」しか選べません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276568/b3f5218e-1815-b0f8-4942-26404fb0e0f7.png)

# 構成図
赤矢印部分を何で満たすか

![構成図集-20220204_blog1.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276568/3b23c561-aa1d-c48f-0d69-dec653543660.png)



# 実現方法
## 1.サービス・ゲートウェイ経由
![構成図集-20220204_blog2.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276568/3bea7eb2-886c-a1f8-476d-7ebaf2cb044d.png)


### 設定内容

#### VCN プライベートサブネット ルート表
[All IAD Services In Oracle Services Network]をサービス・ゲートウェイに紐付ける

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276568/ecb02543-a23b-3e86-48d8-35b598b3e716.png)


#### AutonomousDBのネットワーク設定
対象のVCNと、対象インスタンスのプライベートIPアドレスを紐付ける
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276568/9a77124b-ea35-2bfa-b544-5c764831b201.png)

#### 動作確認
mongoshコマンドで接続出来ることを確認
![adb接続Log1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276568/4c46587f-9c2b-0d83-3b5e-811d65008878.png)


## 2. Natゲートウェイ経由
![構成図集-20220204_blog3.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276568/1bf37618-776f-3f80-ad2d-d2f598a18c1e.png)


### 設定内容

#### VCN プライベートサブネット ルート表
[0.0.0.0/0]をNatゲートウェイに紐付ける
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276568/7ee4ffc7-c75c-a6a1-6930-836507e62a6d.png)

#### AutonomousDBのネットワーク設定
NatゲートウェイのパブリックIPアドレスを紐付ける
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276568/19b6ce08-0490-c05a-56a7-9fed847e1696.png)

#### 動作確認
mongoshコマンドで接続出来ることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276568/03b161e8-7db8-29ad-cc98-7d627c7b1933.png)

# 結論

サービス・ゲートウェイ経由によるプライベート接続、Natゲートウェイ経由によるパブリック接続いずれも可能でした。

# 参考
環境構築は、以下の記事を参考にさせていただきました。
[[OCI]MongoDBクライアントからAutonomous JSON Databaseに接続してみた（MongoDB Shell編）](https://qiita.com/500InternalServerError/items/20f646bc38725dea580b)
GitHub Actions: Expression Syntax でトリガーイベントの情報を取得する (branch 名、tag 名、PR 番号)

GitHub Actions 実行時には Expression Syntax を使ってビルド情報にアクセスできます。

## Expression Syntax `${{ }}`

GitHub Actions では、特定の場所で Expression Syntax を使用できます。

Expression Syntax は値を記述する箇所ではほとんどの場所で使えると思われます。

`if:`

```yml
steps:
  - uses: actions/...
    if: ${{ <expression> }}
```

`env:`

```yml
env:
  MY_ENV: ${{ <expression> }}
```

その他 (例: run:)

この例ではシェルが解釈する前に expression の結果が文字列として置換されることになります。

```yml
steps:
  - run: |
    echo ${{ <expression> }}
```

https://docs.github.com/en/actions/learn-github-actions/expressions

## Contexts

Expression の中では GitHub Actions の環境情報として Contexts へアクセスできます。

https://docs.github.com/en/actions/learn-github-actions/contexts

| Context 名 | 説明 |
| --- | --- |
| github | Workflow やトリガー情報 |
| env | 環境変数 |
| job | 実行中の Job 情報 |
| steps | 実行中の step 情報、step の結果へのアクセスなど |
| runner | 実行中の runner (実行ホストマシン) 情報 |
| secrets | Github Actions Secrets |
| matrix | Workflow の Matrix 情報 |
| needs | 実行中の Job が依存する他の Job の情報 |
| inputs | Reusable Workflow の実行パラメーター |

トリガー情報は github コンテキストに含まれています。

## github.event

github.event にはその Workflow のトリガー情報が含まれます。

トリガーの種類によって github.event の payload は異なります。github.event の種類は以下のドキュメントを参照してください。

https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads

## PR 番号の取得

pull_request トリガーのときに取得できます。

```yml
#...
on: pull_request
#...
steps:
  - run: |
    echo ${{ github.event.number }}
```

pull_request のときの、github.context payload はこちらです。

https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#pull_request

## branch 名または tag 名の取得

push トリガーのときに取得できます。

```yml
#...
on:
  push:
    branches:
      - main
#    tags:
#      - release/**
#...
steps:
  - run: |
    echo ${{ github.ref_name }}
```

ref_name の説明は github context のドキュメントを参照してください。

https://docs.github.com/en/actions/learn-github-actions/contexts#github-context

## その他

よく使うもの

| 項目 | 説明 |
| --- | --- |
| github.sha | Workflow のコミットハッシュ。PR トリガーのときは PR 先とマージされたコミット |
| github.event.pull_request.head.ref | PR トリガーのとき、PR 先とマージされる前のコミットハッシュ |
perlでSalesforce SOAP API を利用する

# 前提条件

- salesforceにアカウントがある状態
- WWW::Salesforce インストール済み
https://metacpan.org/pod/WWW::Salesforce

## token取得
- ホーム > 画面右上のユーザアイコン > 設定 > 私のセキュリティトークンのリセット → 
新しいtokenがメールで届く

参考: セキュリティトークンのリセット
https://help.salesforce.com/s/articleView?id=sf.user_security_token.htm
注意: ログインパスワードを変更するとtokenもリセットされる


# Salesforce SOAP API を利用

## ログイン
以降の処理をする前にログインしておく必要がある

```perl

use WWW::Salesforce;
my $sf = WWW::Salesforce->login(
    username => (ログインユーザ名),
    password => (ログインパスワード) . (token),
    serverurl => 'https://login.salesforce.com/services/Soap/u/52.0',
);
```

## 情報取得

### 単一情報取得
ユーザー番号（カスタム項目）から顧客IDを取得

```perl
my $user_code = (ユーザー番号)
my $account_id;
eval {
  $query = "SELECT Id From Account WHERE user_code__c = '${$user_code}'";
  $response = $sf->query( query => $query );
  $records  = $response->valueof("//queryResponse/result/records/");
  $account_id = $records->{Id}[0];
};
&error('指定が正しくありません') if ($@ || !$account_id);
```

### 複数情報取得
商品IDを複数指定して商品情報を取得

```perl
my $product_ids_txt = "'1234','5678','91011'";
my @products;
eval {
  $query = "SELECT Id, ProductCode, Name From Product2 WHERE Id in (${product_ids_txt})";
  $response = $sf->query( query => $query );
  @products  = $response->valueof("//queryResponse/result/records/");
};
&error('商品情報が取得できません') if ($@ || !@products);
```

## 登録
商談の登録

```perl
my $opportunity_id;
eval {
  $response = $sf->create(
                  type => 'Opportunity',
                  AccountId => (顧客ID),
                  Pricebook2Id => (価格表ID),
                  CloseDate => $date,
                  Name => (商談名),
                  StageName => (ステータス)
                );
  $records  = $response->valueof("//createResponse/result");
  $opportunity_id = $records->{'id'};
};
&error('商談が登録できませんでした') if ($@ || !$opportunity_id);
```

## 一括登録
商談商品の一括登録
（一括登録としてupsertを利用しているのでkeyの指定はしていない）

```perl
my @lineitems;
my @opportunity_items;
my $opportunity_item;
foreach my $item_id ( keys %$items ) {
  $opportunity_item = {
                OpportunityId => $opportunity_id,
                PricebookEntryId => （価格表エントリのID）,
                Quantity => (数量),
                UnitPrice => (金額),
              };
  push(@opportunity_items, $opportunity_item);
};

eval {
  $response = $sf->upsert(
                'type',
                'OpportunityLineItem', #type
                '', #extern
                '', #id_name
                @opportunity_items
              );
  @lineitems  = $response->valueof("//upsertResponse/result");
};
&error('商品が登録できませんでした') if ($@ || !@lineitems);
```


#### 余談
upsertの引数が公式の説明と違う気がしているのだが
ソースコード見るとこうなんだよな‥。
100日でSQLの達人になる@LeetCode! Day3 <count(distinct var)>

##596. Classes More Than 5 Students （問題レベル: Easy）
今日の問題はこれ。
5人以上生徒がいるクラスをリストアップするという問題。

実は、この問題Day2の問題をやった後だったのでほぼ瞬殺でClearしました。
構文はほぼ同じで、
Day2のポイントは```having```句で```count()```を使うでした。

実際正解はしたのですが、やはりどんな問題でも学びはあります。
念の為とSolutionを確認すると、
今回の例では、たまたま、同じテーブルに重複した生徒名がなかったから正解したのですが、生徒が重複した場合では駄目なんですね。

そこで今回のポイント。
```having```句で```count(distinct 生徒名)```を使うでした。

[LeetCode](https://leetcode.com/)が良いのはSolutionに模範解答だけでなく、様々な生徒が正答した回答例があるのが学びになります！

* [LeetCode](https://leetcode.com/)の問題は、MS SQL Serverで解いています。
Salesforce組織のオブジェクト名、フィールド名のAPI名を取得するSOQLクエリ

# 初めに
Salesforceの開発者コンソールから下記のことが**SOQL**でしたいときに
- 組織の各オブジェクトのAPI名を知りたい
- あるオブジェクトの各フィールドのAPI名が知りたい

# 組織のオブジェクトのAPI名を知りたい場合
```
SELECT QualifiedApiName FROM EntityDefinition order by QualifiedApiName 
```

# あるオブジェクトのAPI名を知りたい場合
```
SELECT QualifiedApiName FROM FieldDefinition WHERE EntityDefinition.QualifiedApiName = 'Account' 
```

## API名だけでなく、フィールド名を知りたい場合は:
```
SELECT Label, QualifiedApiName FROM FieldDefinition WHERE EntityDefinition.QualifiedApiName = 'Account' 
```
Mavenで依存関係含めたJarを作成する

# 概要
依存関係に設定しているJarファイルを含めてJarを作成する方法を記載
単純に作成すると、依存関係無いJarファイルが作成される

#実行方法

## 作成するPOMファイル(一部)
以下記載を`<project>`タグの配下に記載する
<configuration>で作成する内容の詳細を記載する

``` xml
   <build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.2</version>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <finalName>jarFileName</finalName>
                    <appendAssemblyId>false</appendAssemblyId>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifest><mainClass>jp.co.xxx.MainClass/mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
```

## 設定内容詳細

### finalName
作成するJarの名前を指定する

``` xml
<finalName>jarFileName</finalName>
```
この例の場合は`jarFileName.jar`という名称のファイルが作成される

### appendAssemblyId

``` xml
<appendAssemblyId>false</appendAssemblyId>
```

これをfalseに設定しないと
`-jar-with-dependencies`とサフィックスが設定され
今回だと
`jarFileName-jar-with-dependencies.jar`という冗長な名称のファイルが作成される

### descriptorRef

``` xml
<descriptorRefs>
   <descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
```
上記定義を行う事により、参照しているライブラリを作成するJarに含めることができる

### manifest
``` xml
<archive>
    <manifest>
　　     <mainClass>jp.co.xxx.MainClass</mainClass>
    </manifest>
</archive>
```

上記定義を行うことによってmanifestファイルが作成され
実行するときのMainクラスを指定できる
日付を比較してどれだけ前かを表示したい

#初めに
今回、やりたいこととしては特定の日付と現在時刻を比較して、何秒前の物なのか等を出し分けるためのロジックです
組み分けとしては、0~59秒前、1~59分前、1~23時間前、1日前、それ以降は日付表示となっています

###コード
適当な名前で作った`DataClass`内に下記のコードを書くことにより、その`DataClass`を利用する際は`toString()`とするだけで望んだ結果が帰ってきます

```kotlin:
override fun toString(): String {
    val createdAt = at.toInstant().toEpochMilli()
    val nowAt = ZonedDateTime.now().toInstant().toEpochMilli()
    val diff = nowAt - createdAt
    val sec = diff / 1000L
    if (sec in 0..59) {
        return "${sec}秒前"
    }
    val min = sec / 60L
    if (min in 1..59) {
        return "${min}分前"
    }
    val hour = min / 60L
    if (hour in 1..23) {
        return "${hour}時間前"
    }
    val day = hour / 24L
    if (day == 1L) {
        return "1日前"
    }
    return at.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"))
}
```


###最後に
前回、
https://qiita.com/ryuji_sato/items/f909c49e2d57f721f33c
上記の記事にて受け取った日付用のDeserializerを紹介させていただいたので、それを利用したいい感じの記事を書きたいなと思い、書かせていただきました。
自分の備忘録がメインとはなっていますが、どなたかのお力添えになれたら光栄です
Qt4をgcc9でコンパイルすると、foreach文が1回しかループを反復しなくなる

Ubuntu18では正常に動いていたアプリケーションがあったのですが、OSのバージョンアップが必要になったため、Ubuntu20の環境でビルド・動作確認を実施。

すると、今までパスしていたテストが通らなくなってしまったので、色々と調査したところ、コンテナのサイズに関係なく、Qtのforeach文が1回分しかループを回していないという事実が判明しました。

Qtのforeach文はマクロ定義されていて、C++11以降で使えるようになった拡張for文とほぼ同じような感覚で使えます。

```c++
QList<qint32> qList;
qList << 1;
qList << 2;
qList << 3;
qList << 4;

foreach (qint32 val, qList)
{
    std::cout << val;
}
```

通常であれは「1234」の出力が期待できますが、「1」しか出力されないというのが今回起きた事象です。

調べてみたところ、どうやら同じ事象がstack overflowで話題に上がっているようでした。
https://stackoverflow.com/questions/61635549/qt-foreach-only-iterates-once-ignoring-the-rest-of-the-items

バグレポートとしても上がっているようです。
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90617

どうやらfor文の増減式の部分にbreakを入れた場合の振る舞いが、gcc9とそれより前のバージョンで異なることで、この問題が発生しているようです。

どちらかというと、gcc9より前では間違った動きをしていたので、gcc9ではそれが修正されているということのようですね。

Qt5ではこれを受けてかforeachのマクロ定義が異なった処理に修正されていますので、gcc9でコンパイルしても問題ないようです。

いずれにせよ、Qt4とgcc9の組み合わせで使用せざるを得ない場合は、foreach文の使用を避けて、通常のfor文や拡張for文を使うか、イテレーターを使ってコンテナに対してのループを回す必要があるということですね。
[py2rb] len(np.array(...).shape)

# はじめに
移植やってます。
( from python 3.7 to ruby 2.7 )
# numpy (Python)
```python
len(np.array(x).shape)
```
配列の次元を取得します。
# どうすRuby
```ruby
np.array(x).shape.size

NoMethodError: undefined method `size' for (3, 2):PyCall::Tuple
```
`len`だから`size`と単純に変換するとエラーになります。
`PyCall`では、`Ruby`で直接取り扱えないオブジェクト？を`@__pyptr__`として保持します。

```ruby
np.array(x).shape.to_a.size

np.array(x).mean(axis: 0).to_a # mean:平均 の例
```
したがって必要に応じた変換を行います。
# メモ
+ Python の numpy を学習した
+ 百里を行く者は九十里を半ばとす
Power Apps のキャンバスアプリに埋め込んだ Power BI に対してフィルターを適用する

## はじめに
Power Apps では Power BI で作成したレポートを、キャンバスアプリへ埋め込むことができる`Power BI タイル`コントロールが用意されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/1ac70433-6217-1687-946f-30f45b435443.png)

これを使用することで　Power Apps 内で簡単に Power BI のレポートを表示することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/3badccaa-049a-34a2-52e0-6e7d0e9612e9.png)

## やりたいこと
Power Apps に埋め込んだ Power BI タイルにフィルターをかけて Power Apps側からPower BI にクエリをかけてみます。

## やりかた
### 前提
Power BI は[URLパラメーターによるフィルタリングをサポート](https://docs.microsoft.com/ja-jp/power-bi/collaborate-share/service-url-filters)しており、以下のような形でリクエストを行うとフィルタをかけることができます。

```
https://app.powerbi.com/groups/me/reports/xxxxxxxxxxxxxxxx/ReportSection1?filter={Table}/{Column} eq 'Hoge'
```


### Power Apps で埋め込み URL を取得する
Power BI タイルコントロールをクリックして「プロパティ」→「データ」の「データがありません」をクリックして埋め込むデータを選択します。（この時までに Power BI で埋め込み対象のレポートを作成してダッシュボードにピン止めしておく必要があります）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/ad35c9f1-5bb3-294d-eb57-556639b1c48a.png)


再び Power BI タイルコントロールをクリックして「詳細情報」→「TileUri」の URL をメモ帳等にコピーしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/f3985680-f9a8-11d4-e6ea-023772dedd7d.png)

### クエリを追加する
コピーした TileURL は以下の形式になっているはずです。

```
https://app.powerbi.com/embed?dashboardId={DashboardID}&tileId={TileID}&config={SomeHash}
```

この URL の末尾にフィルタークエリを追加します。

```
https://app.powerbi.com/embed?dashboardId={DashboardID}&tileId={TileID}&config={SomeHash}&filter={TableName}/{ColumnName} eq '{Value}'
```

当たり前ですが、この時フィルターに指定することができるのは埋め込んでいるレポートに存在するテーブル名とカラム名に限られます。

### filter の値を動的に変更する
TileURL の値を以下のようにします。

```
If(mode=0,
"https://app.powerbi.com/embed?dashboardId={DashboardID}&tileId={TileID}&config={SomeHash}&filter=WebsiteSocialAnalytics/Browser eq 'Edge'",
"https://app.powerbi.com/embed?dashboardId={DashboardID}&tileId={TileID}&config={SomeHash}&filter=WebsiteSocialAnalytics/Browser eq 'Chrome'"
)
```

これでコンテキスト変数`mode`が 0 の時は WebsiteSocialAnalytics テーブルの Browser 列が[Edge]で、それ以外は[Chrome]のデータが表示されるようにフィルタがかかります。


### AllowNewAPI を true に設定する
Power BI タイルコントロールの`AllowNewAPI`フラグに`true`を設定します。これは Power BI API の新しいバージョンを使用するかどうかというフラグですが、false(古いAPI)だとフィルタの数が1個まで、などといった制限があるので特段の理由がない限りは`true`に設定しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/0deced14-fbce-5b38-4c64-181eb468ddc5.png)

### mode 変数を切り替えるボタンを作る
キャンバスにボタンを追加して OnSelect プロパティでmode変数を toggle する処理を書きます。

```
If(mode=0,
  UpdateContext({mode:1}),
  UpdateContext({mode:0})
)
```

## 完成！
グラフのレイアウトは同じなのでわかりづらいですが、[Number of visits]の数字をみてみるとボタンが押されるたびに数字が変わるのがわかります。
![Animation16.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/543c562f-6eff-f719-4a61-92a387def340.gif)


## 参考
https://docs.microsoft.com/ja-jp/power-bi/collaborate-share/service-url-filters

https://docs.microsoft.com/ja-jp/powerapps/maker/canvas-apps/controls/control-power-bi-tile
プルリク先のブランチがマージされたら、プルリク先は自動で変更されるのか

# どゆこと？
``プルリク先のブランチがマージされたら、プルリク先は自動で変更されるのか`` テキストだと意味不明なので図を用意。

![スクリーンショット 2022-02-04 14.14.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635641/3aa4e965-d8e1-b29a-90bf-2da120432e7d.png)
![スクリーンショット 2022-02-04 14.17.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635641/6c2abec4-7d23-31b3-ae81-6496a5487a26.png)
この状態になった時、``branch B``のマージ先は自動で``main``に更新されるのか分からなかったので実際に試してみた。

# 実際に試してみた。

![スクリーンショット 2022-02-04 14.16.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635641/0911c68f-1d72-a84c-2835-a2f0082141a8.png)

なんとなく予想していた通り、マージ先が変更されました。
アラフォー2児の母がMicrosoft Azure AI Fundamentals(AI-900)をサクッと取得


みなさんこんにちは。子育てしながらクラウド資格取得！ということで，この度アラフォー2児の母がAI-900 : Microsoft Azure AI Fundamentalsを取得しましたので，マンガ形式でゆるくお伝えします！


![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358174/0d13ddb2-8c50-9aeb-502c-523aa247b1f4.png)


![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358174/0762814f-7295-b238-fe98-52d67f8ed2bb.png)


![図3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358174/48349910-fc70-3599-f5cc-d8dd15d4be10.png)


https://qiita.com/mofu_mother/items/766fab0ce3bd62b0c513


![図4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358174/413cb7ed-f555-84c7-424d-c0b097e1c3f9.png)


![図5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358174/321bfa6e-3a15-24d6-cbe3-7064df2d1e70.png)


![図6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358174/f4c98e81-9d20-3d56-658c-c1099b5178ec.png)


![図7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358174/aeee49fb-556b-68a4-c6df-8943634fe226.png)


![図8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358174/ede020d8-a236-7edc-96cd-b8f095ede543.png)


https://www.microsoft.com/ja-jp/ai/responsible-ai


![図9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358174/67499bed-e895-ca22-714d-053d64e8ae90.png)


![図10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358174/73e6aa91-0e24-f4fb-b870-28ffab0bac75.png)


今回ご紹介した教材「AI-900:Microsoft Azure Data Fundamentals試験対策」については次のURLをご参照ください。

https://info.microsoft.com/JA-AzureApp-WBNR-FY21-04Apr-07-MKTOFY21AI900PrepSessionOndemandWebinar-SRDEM70306_LP02OnDemandRegistration-ForminBody.html
MCUXpresso でNXP FRDM-K22F の開発環境構築

# はじめに
手ごろな価格だったこともありNXPのK22の評価ボードFRDM-K22Fを購入した。
まずは、評価ボードで開発環境の構築と適当なアプリケーションの動作を目指す。
(K64の評価ボードも所有しています)

# 統合開発環境
ここ最近のNXPの開発環境としては、MCUXpressoではないだろうか。NXPのLSIをよく知っている方からもこれを薦められた。他の方法を知らないこともありMCUXpressoを使うことにする。以前ダウンロードしておいてv11.4を使うことにした。

## インストール後の起動
インストール時の選択はインストール先くらいで特に困ることはない。インストール後はそのあとの選択に困らないように配慮されたイマイチ分かりづらいWelcome画面が立ち上がる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/1fad5a50-f6c8-0145-cb65-015a14d87820.png)

## SDKのインストール
MCUXpressoではLSIとかボードごとのSDKはプラグインとして後からインストールするようになっている。まずはK22のSDKをインストールする。
「Download and Install SDKs」を押して、SDK選択画面に移るとたくさん出てくる。遷移先の画面の右上にFilterがあるので、K22と入れるとみたことのあるボードの画像と詳細情報が出てくる。選択ミスは考えづらい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/961f3327-845c-aa5b-ae90-879902d5ae17.png)
あとは下の方にあるInstallを押せば、ネットワーク上から取得してくれる。

## SDKが認識されない
SDKが認識させておらず、プロジェクトの作成でもK22が選択肢に出てこない事態になった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/c8a66c0f-de8d-ef20-f9ec-2b708a173934.png)
SDKの名称と情報が表示されていない。なんのバグ？
右クリックして、Open Locationで開いた先にはSDKらしきzipがあり、一見すると問題がない。

## 原因の推測と対策
新しいバージョンのMCUXpressoがリリースされているためでは？
この時点でv11.5がリリースされていることが分かった。またDLされたK22F SDKはversionが2.11だった。
となると、v11.5をインストールするか、v11.4が最新だった期間のSDKをインストールすれば認識されるのではないか。

## K22F SDK 2.10をインストール
(追記・修正)
この方法は使えないことが後から判明。
この設定画面でFlashの情報が正しく認識できないとエラーが出た。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/aa89dcf1-a681-aaef-55e6-7a6663265d93.png)

~~幸いにして、v11.4＋K22 SDK 2.10を構築した別PCが見つかったので、そこから取り出したK22 SDK 2.10を使うことにした。~~

~~インストールの前に、Select MCUEpresso SDKsでK22のSDKをアンインストールしておく、[SDKが認識されない](## SDKが認識されない) で空欄として認識された箇所でも右クリックしてUninstallしておく。とにかくエラーした情報は削除する。~~

~~Installed SDKsで右クリックし、Open Default Locationを開く。そして、K22 SDK 2.10のzipファイルをコピーする。~~
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/cea70d98-7f92-2f77-f125-e6aacd810c34.png)
~~その後、MCUXpressoを再起動する。~~

~~**認識された！**~~
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/02f6f4e4-37e6-81be-8095-bf5fe818f424.png)

## 改めてK22F SDK 2.10をインストール
残骸がある場合は、K22 SDKを削除する。
Select MCUEpresso SDKsで赤枠のところのShow latestのチェックを外すと、OldバージョンのSDKが選択できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/7b19cbe9-c516-f3be-508f-0218d9653c38.png)
原因はわからないが、v11.4では2.10.0が正しく認識でき、2.11.0は正しく認識できない。v11.4を使っていて、SDKバージョンにこだわりがなければ2.10をインストールしよう。これで正式な方法で認識されたのでエラーはないはず。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/81cbe19d-2067-6217-8819-7a57efb57406.png)


# 今後
* プロジェクトを作って適当なコードの実行を行う。
* v11.5（というかその時点の最新MCUXpresso）で環境構築して原因究明。
どうしてMath.max()は-Infinityになるし[].every(条件式)はtrueになるの？

`Math.max()` は与えられた複数の数値のうち最大の数を返します。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/max
引数を与えないと `-Infinity` という最小の数値を返すのが意外というのが最近ちょっと話題になりました。

```Javascript
> Math.max()
<- -Infinity
```

配列の`every`メソッドは、配列要素のすべてで条件式が成立する場合にtrueとなります。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/every
これも、空の配列で呼ぶと条件式が一回も成立していないのにtrueを返すのが意外だと話題です。

```Javascript
> [].every(x => false)
<- true
```

これらは、別に「JavaScriptの奇妙な仕様」ではありません。  
集合演算のできるほぼすべての言語が同様の仕様となっています。Javaの`Stream.allMatch()`だってC# LINQの`.All()`だってそう。
これらの仕様は「**中立元を返している**」のだと理解すると腹に落とすことができると思います。

中立元
------

どんな数に1をかけても同じ数です。
どんな数に0を足しても同じ数です。
これらのことを「かけ算の中立元は1だ」「足し算の中立元は0だ」と表現します。演算しても元の数と同じ結果になるような数のことを、その演算の中立元だと言うわけです。

さて、数のゼロ乗は1になることを中学で習うと思いますが、納得のいかなかった方、いらっしゃいませんか。

- 3<sup>3</sup>は3×3×3
- 3<sup>2</sup>は3×3
- 3<sup>1</sup>は3
- 3<sup>0</sup>は、3を一個もかけ合わさないってどういうこと⋯？　“虚無”⋯？ 仕方ない、先生が1と言ったから1だと覚えよう⋯

みたいになりそうじゃないですか。ところが1という中立元があると、以下のようにすんなり書けるわけです。（単にすんなり書けるというだけでなく、3<sup>3</sup>は3<sup>2</sup>の3倍、3<sup>2</sup>は3<sup>1</sup>の3倍、と同様に3<sup>1</sup>は3<sup>0</sup>の3倍が成立してキレイな関係が続くようにもなり美しくなります）

- 3<sup>3</sup>は1×3×3×3
- 3<sup>2</sup>は1×3×3
- 3<sup>1</sup>は1×3
- 3<sup>0</sup>は1

同様に0の階乗が1になることもすんなり納得できるはず。

`Math.max()` も同じです。「大きい方」という演算において中立元は「無限小」ですから

- `Math.max(a, b)` は `-Infinity` と `a` と `b` のうち最大の数
- `Math.max(a)` は `-Infinity` と `a` のうち最大の数 （→ `a`）
- `Math.max()` は `-Infinity` のうち最大の数 （→ `-Infinity`）

`.every` 、すべての論理値のANDをとるということですから、AND演算の中立元 true を使って

- `[a, b].every(cond)` は `true` && `cond(a)` && `cond(b)`
- `[a].every(cond)` は `true` && `cond(a)`
- `[].every(cond)` は `true`

となりますという次第です。

「**繰り返し演算は、対象がゼロ個だと中立元が答えになる**」
プログラミングでもそれ以外の分野でも役に立つことがときどきあるので是非覚えておいてください。
Google Cloud Functions で関数を編集するとデプロイに失敗する場合の応急措置

Cloud Functions の関数を編集した後、Python パッケージのインストールの最中にエラーが発生してデプロイに失敗することがあります。（経験的には PyTorch のインストール中に止まるようです。）
かなりマイナーな現象かもしれませんが、検索してもほとんど情報が見つからないので、症状と応急措置を書き残しておきます。

## エラーログの最終行

Python 3.8 の場合の例

```
Collecting torch; Error ID: 0ea8a540
```

Python 3.9 の場合の例


```
Collecting torch; Error ID: c84b3231
```

いったんこれに陥ると、**何度やり直してもデプロイに失敗し続ける**羽目になります。

## 原因

不明。わかる人がいたらコメントで教えてください。

## 応急措置

最も確実な方法は「**関数の再作成**」です。クリーンな状態で環境構築が走るからか、ほぼ必ず成功します。
具体的には関数を削除してから全く同じ関数を再度作成すればよいのですが、コンソールから操作していて細かい設定の再現が面倒な場合は、

1. 関数をコピー (function-1 → function-2)
1. 元の関数を削除 (function-1 を削除)
1. 関数をコピー (function-2 → function-1)

の手順で再作成すると楽です。

これ以外の解決方法があればコメントで教えてください。
React+typescriptで入力欄を動的に生成する。

プラスボタンを押下した回数に応じて入力欄が増えていくページをつくるのにハマったのでメモ。
参考のページを取り込もうとしてハマったところやポイントと思うところだけ書いておきます。

- 繰り返しはmapを使う。for文でuseStateを複数生成したりしない。
- JSXの入っているリスト（このコードのitems）は直接変更してはいけない。いったん中身をクローンして新しい配列を生成し、そっちを編集してから配列ごと入れ替える。 const newItems = [...items, newItem]; のところ。...で配列の参照ではなく実態をコピーしている。
- input:text のvalue属性は書き換え用のuseStateのsetterを呼ぶ関数を作ってそれをinputタグのonChangeで呼び出す。valueにuseStateの値を書いただけだと、何も入力できなくなる。
- 入力欄の識別はname属性にmapのindexを文字列加工してname配列にする。
- mapの中のJSXはdivタグで囲ってそこにkey={index}を属性として埋める。ないとwarningが出る。はじめdivタグじゃなくてフラグメント<>で括っていたらこのwarningが解消できなくてハマった。
- typescriptではアイテムリストを定義する時 const[items,setItems] = useState&lt;ItemsProps&gt;([]); のようにuseStateに型引数を与えないとコンパイルエラーで動かない。このtypeの中身はmapの中で入力欄に紐づけたい値の型を書く。またこのtypeは配列タイプとして記述する。

```tsx
import React, { Component, useState } from "react";
import { render } from "react-dom";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
    faChevronRight,
    faChevronLeft,
    faCircle,
    faCheckCircle,
    faPlus,
} from "@fortawesome/free-solid-svg-icons";

const targetDom = document.getElementById("hoge_sample");

export const HogeSample = () => {

    // Itemが１ユニット。
    type ItemsProps = {
        message:string,
    }[];

    const[items,setItems] = useState<ItemsProps>([]);

    const [inputValue, setInputValue] = useState('');

    //クリック時にitems配列に新しいitemを作る処理
    const handleAddButtonClick = () => {
        //作られるitemの定義
        const newItem = {
            message: inputValue,
        };

        //items配列にpushされる
        const newItems = [...items, newItem];

        //useStateのitemsに反映
        setItems(newItems);
    };

    // メッセージのテキストボックスの値が変わったら発火
    const handleChangeMessage = (index:number,message:string) => {
        //itemsを展開した配列、newItemsを作る
        const newItems = [...items];
        //テキストを更新する。
        newItems[index].message = message;
        setItems(newItems);
    };

    return (
        <>
            <FontAwesomeIcon
                icon={faPlus}
                onClick={() => handleAddButtonClick()}
            />

            {items.map((item,index) => (
                <div key={index}>
                    <input
                        type="text"
                        name={'message[' + index +']'}
                        value={item.message}
                        onChange={(event) => handleChangeMessage(index,event.target.value)}
                    />
                </div>)
            )}
        </>
    );
};

if (targetDom != null) {
    render(<HogeSample />, targetDom);
}

```

#参考
[【 React Hooks入門】useStateを使って買い物リストを作るチュートリアル](https://terrblog.com/%E3%80%90-react-hooks%E5%85%A5%E9%96%80%E3%80%91usestate%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E8%B2%B7%E3%81%84%E7%89%A9%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E4%BD%9C%E3%82%8B%E3%83%81%E3%83%A5%E3%83%BC/)
個人的に印象的な言葉

# はじめに

個人的に印象に残った言葉を記録するしていく。
一見、ソフトウェア開発等には関係ないように見えるかもしれないが、いつか・どこかで、この言葉の考え方を使うことがある気がしている。

# 印象的な言葉

## 「信用を稼ぐ」 by 西野亮廣

https://logmi.jp/business/articles/320691

## 「競技に参加するのではなくて競技を作っちゃったほうがいい」 by 西野亮廣

https://logmi.jp/business/articles/320627

## 「引き算」 by Yasuharu NISHI

https://mobile.twitter.com/YasuharuNishi/status/809743672065429504?fbclid=IwAR12mOI1kzAP2oS1LSDots9LI1YnFg8lHw4Wi7UOEWE2ymUQpn-LzXAgmho

> 最初の足し算はさ、引き算するための元を作る作業でね。何もなかったら引き算できないからね。でも足し算だけで終わると、ただの物知り自慢になって、頭がこんがらがって整理できず、役立つ成果は生み出せない。

引き算重要。捨てることで、本当に重要なことを、炙り出せる。

* 本の編集も
* 映像の編集も
* イベントの企画も
* セミナーや講演も
* 発表も

みんな引き算が肝。
昔、優秀な編集者は、捨てるのがうまいと聞いたことがある。自分が取材で労力をかけて集めた情報は、どうしても使いたくなるが、そこを我慢して捨てることが重要。
限られた時間や空間で、何かを伝えるためには、成果を出すためには、余分なものを削ぎ落とす。

## 「GNN（義理・人情・浪花節）」 by 川瀬武志

http://app.m-cocolog.jp/t/typecast/112636/100860/81759762

GNN（義理・人情・浪花節）教の教え。※宗教ではない。
個人・チームの能力を引き出す・向上させるために、大切な考え方だと思う。
自分の経験則と繋がることも多い。


## 「不為也、非不能也（為（な）さざるなり、能（あた）わざるに非（あら）ざるなり）」 by 孟子

https://qiita.com/kazuo_reve/items/a2e15627f0eff62e6af6


## 「肯定眼」 by 清水吉男
https://business087.com/gensisiroku/#toc4

https://affordd.jp/koha_hp/process/Proc.Square/Proc.Square.RV.htm#Anchor967099

> 成果物欠陥の指摘はレビューの主要な目的です。しかしながら、成果物欠陥の発見だけに終止することで、レビューアの目は「否定眼」に偏ってしまい、人の成果物から優れた箇所を見い出す「肯定眼」を手に入れることができなくなるのです。いや、すでに日本中の現場（組織）で、この「肯定眼」は失われたのではないかと危惧していますし、私自身、過去においてその現実を目撃しています。
> 
> そこにいる人が全員「否定眼」で覆われた組織の中では「能動」で動くきっかけを見い出すことは容易ではありません。いや、はっきりと困難と言ってもよいぐらいです。
> 
> こういう組織文化の中で、多くのエンジニアは「工夫」する楽しさを失っているのです。にもかかわらず、そのような文化が染み渡った状態のままで「CMM」を導入しようというのです。「能動」で動く楽しさを知らない組織にとって、CMMは負担にしかならない可能性があるのです。もちろん、CMMの取り組みの中で「能動」の楽しさに気付くことはありますが、はたしてそのように誘導できるコンサルタントはどれだけいるでしょうか。

https://www.juse.or.jp/sqip/workshop/user_voice/index.html#20180725_kashiwabara

* 大きな成果を生み出すために、研究成果を積み上げていく。  
  肯定眼をもって、過去の自分達の成果を見るべし（捨てるべからず）。
* 同様の課題の解決に取り組んでいる先人は多数いる。  
  肯定眼をもって、先人の論文・書籍等から学ぶ（盗む）べし。
* “うまくいく場合”と“うまくいかない場合”を比較することで、問題点が見える。  
  肯定眼をもって、“うまくいく場合”に着目すべし。

https://www.slideshare.net/NorikoKawaguchi/xddp-184637465


## 「人のキャリアは8割の偶然によって決定される」

https://logmi.jp/business/articles/321665?fbclid=IwAR0kgOoBm9X3us4WWS7uZlrD2CJqK3oNB7LV09HT3NrnpRIKr5hah7_EBqs

https://peisanblog.site/career-planned-happenstance-theory/

過去に得た人脈・知識・道具・経験などが、新しく始めたことに活かされると、小説で伏線を回収していくみたいな感覚で、面白いし、うれしいし、ありがたい。
過去に得た人脈・知識・道具・経験などが、必要に応じて取り出せるようにしておくことも大切かも。
過去に得た人脈・知識・道具などを、周りの方々に知らせることも大切かも。
論文・発表は、伏線を作るために、有効な行為かも。

## 「人にとって必要な経験は「貧乏」「失恋」「入院」」 by 松尾谷徹

> 「自身に対する自信：経験的成功感を一瞬で打ち砕く」 再出発ができます．
> 様々な調査でも，例えば資格試験で，合格ライン近辺で不合格になった者の方が、その後の努力が大きく成功しています．中途半端な成功は努力を失う！！

## 「それに、お前は1万賭けられるか？」by 山路厚

人間は何かを犠牲にする可能性のあるときに本気になれる。本気なら、何かが犠牲になるリスクを背負える。
現実的な犠牲（1万という払えるがそれなりの金額）が、本気度を測るために、有効。

# 関連記事

https://qiita.com/kazuo_reve/items/274c8e43fad4ed45715b

https://qiita.com/kazuo_reve/items/a3ea1d9171deeccc04da

https://qiita.com/kazuo_reve/items/bce7522fa2cca0995b85
Pythonでコメントのオンオフを簡単にスイッチする

# 方法
コメントアウトしたい部分を`# """`行で挟み、
頭の`#`を消すと囲んだ範囲全部がコメントアウト、
もう一度`#`をつけるとコメントアウト解除されます
(VSCodeなら`ctrl + /`のショートカットが便利)

対象範囲にもともと`"""`がある場合、`'''`を代用します


```python
# """ ← #をとると
def hoge():
    print("O")
# """ 
```


```python
"""
def hoge():
    print("X")
# """ # ここまでコメント
```


# 原理
引用符で囲んだ範囲は文字列とみなされます
もっとも、引用符の前に`#`を置くとコメントアウトとして機能します

```python
text1 = "# コメントアウトじゃないよ"
text2 = # "コメントアウトだよ"
```
また、三連引用符は改行を超えて文字列の範囲を指定できます

```python
text = """
改行できるよ
"""
```

ここで、一つ目の三連引用符に`#`を置いてみましょう

```python
text = # """
改行できるよ
"""
```
一行目の`#`より右側だけコメントアウトできました
`#`が有効なのは当該行だけみたいですね
今度は最終行に`#`を置いてみましょう

```python
text = """
改行できるよ
# """
```
前述のとおり、引用符内の`#`はただの文字なのでコメントアウトされません
したがって、三連引用符の締めに`#`を嚙ませると

1. 三連引用符の頭をコメントアウトして*いる*場合 
-> 締めの`#`は*コメントアウト*

2. 三連引用符の頭をコメントアウトして*いない*場合
-> 締めの`#`は*文字*

となるので、頭の`#`を付け外しするだけでコメントのオンオフを切り替えられるわけです

# 応用

前の機能を書き換えたけど消すのもちょっと怖いような場合、
間に三連引用符を挟むことで実装を切り替えることができます

```python
# """
def hoge():
   print(1)
"""
def hoge():
   print("一")
# """
```

```python
"""
def hoge():
   print(1)
"""
def hoge():
   print("一")
# """
```
使う機会が思いつきませんが、スイッチングしたい範囲がとびとびの場合はさらに三連引用符をつけて切り替えることができます


```python
# """
def hoge():
   print(1)
"""
def hoge():
   print("一")
"""
def huge():
   print("gif")
"""
def huge():
   print(岐阜")
# """
```

```python
"""
def hoge():
   print(1)
"""
def hoge():
   print("一")
"""
def huge():
   print("gif")
"""
def huge():
   print("岐阜")
# """
```
【RSpec】テスト後に画像ファイルを削除したいとき

CarrierWaveを使用していてRSpec実行した後のアップロードファイルを削除したいとき
下記を追記すればいいという記事をいくつか見かけた。

```spec/rails_helper.rb
config.after(:suite) do
  FileUtils.rm_rf("#{Rails.root}/public/uploads") #←ファイルがアップされるパス指定
end
```


.gigtinoreにパスを追記するだけで上記は必要なくなる。


```
public/uploads
```
import React from "react" はもう要らない

この記事は公式の[Introducing the New JSX Transform](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html)に基づいて書かれています。

# 結論
- `import React from "react";`はReact 17以降は必要ないよ。16以前は必要だよ。
- コンパイラが自動でインポートしてくれるようになったよ。

# 本編

Reactでコンポーネントのコードを書くときに、`React`をソースコードの中で特に使ってる訳ではないけど、`import React from "react";`って書いてますよね。

```react
import React from 'react';

function App() {
  return <h1>Hello World</h1>;
}
```

なぜ必要かというと、Reactコンポーネントは次のようにコンパイルされるためです。

```react:コンパイル後
import React from 'react';

function App() {
  return React.createElement('h1', null, 'Hello world');
}
```

コンパイル前のコードで`React`を使っていなくても、コンパイル後のコードで`React.createElement`を使っているからインポートが必要なんですね。でも、React 17以降はコンパイルの挙動が変更されました。

```react:React17以降
// 次の行はコンパイル時に自動で挿入される
import {jsx as _jsx} from 'react/jsx-runtime';

function App() {
  return _jsx('h1', { children: 'Hello world' });
}
```

エレメントを生成する関数が`React.createElement`から`jsx`に変わりました。また、`jsx`はコンパイル時に自動でインポートされるようになりました。よって、React 17以降は`import React from "react";`は書く必要がなくなったわけです。
Codeigniter4の'Access-Control-Allow-Origin'対策やAPI用出力のやり方

javascriptsのajax処理とかでAPIを作ったりすると、「'Access-Control-Allow-Origin'」のエラーが出たりする。のでそれの対策。

```php
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Methods: POST,GET, OPTIONS");
header("Access-Control-Allow-Headers: *");
```

これを追加することで'Access-Control-Allow-Origin'を回避することができる。

次に、json以外の余計な出力をしないようにする。

```php
    use ResponseTrait;
    function api() {
        header('Access-Control-Allow-Origin: *');
        header("Access-Control-Allow-Methods: POST,GET, OPTIONS");
        header("Access-Control-Allow-Headers: *");
        $this->response->setContentType('Content-Type: application/json');
        return $this->response->setJSON(true);

}
```

ResponseTraitを宣言しておいて、出力にsetJSONを使用。コンテンツタイプをjsonにすると、デバッグツールバーが無効になってくれる。
UnityでiPhoneやiPadなどの任意のデバイスサイズを計算する方法【C#】

UnityでuGUIを使っている中でレスポンシブデザインを考える必要が出てきたときに必要となりました．この方法を使えば，どのデバイスでも幅と高さを出すことができます．

# dpiと解像度

Unityでは`UnityEngine`名前空間の中に`Screen`というクラスがあります．これはその名の通りスクリーンに関する情報をたくさん持っていて，これをつかいます．

```csharp
float widthInch = Screen.width / Screen.dpi;
float heightInch = Screen.height / Screen.dpi;
```

これで計算できます．

`Screen.width`と`Screen.height`はどちらも**「ピクセル数」**を返し，`Screen.dpi`は**「ピクセル数/inch」**，つまり1インチにどれほどピクセル数があるか，の解像度を表します．つまり`Screen.width / Screen.dpi`は幅が何インチかを表すことになります．

実際に試してみれば本当にその数字になっていることが確認できるかと思います．

# さいご
いやそれにしてもuGUIは使いにくすぎる！
PaloAlto VM トライアル版のインストール

今回はPaloAltoVMトライアル版のインストールです。トライアル版はサイトより申請し受理されればメールでリンクが送られてきますので、そちらからダウンロードします（5GBちょいあります）

## 1. 環境
ESXiバージョン: 7.0.U2d-18538813
vCenterバージョン：7.0U2a-17867351
PaloAltoVM：PA-VM-ESX-10.0.4.vm_eval

## 2. 申請/ダウンロード
申請サイトはこちらです。※登録は企業名でないとまず受理されないと思います。

https://www.paloaltonetworks.com/vm-series-trial

## 3. OVAファイルからデプロイ
途中までの流れはFortigateVMとほぼ同じです。細かい内容は省略していますので良ければ下記リンクで補完してもらえればと思います。

https://qiita.com/nw-engineer/items/639d95e26dba6fffb02a


ダウンロードしたファイルを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/9f30d152-fbb3-b247-51b1-5f3f0c56a187.png)

仮想マシン名を入力して、「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/56e5190e-3b37-ca33-ad19-4d4d3bb6a62c.png)

対象のESXiが選択されている状態で「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/294c186b-66d7-7038-d966-166cb1938964.png)

「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/cfa33883-1599-079f-c805-d5f285bf1a8c.png)

対象のデータストアを選択して「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/5859d7ed-79b4-6359-b82b-aa6b5cf47c25.png)

「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/40028c1f-4c2a-dcc2-518d-bcbe4eba10c3.png)

「完了」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/fd43a92a-5ea7-cb61-d2b9-dc5d75a0c065.png)

ではPowrOnしてWebコンソールを開きましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/813c355e-c2a5-b039-1848-edd007b950d3.png)

しばらくすると何やらエラーが出てきますが、しばらく待つとログインプロンプトが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/7fa2367b-d3a1-be4b-ffc4-bdb56225a5a7.png)


ID:admin/PW:adminでログインするとパスワード変更要求が促されますので、変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/c3950e7e-0c93-7ab1-dbeb-92cefe717c63.png)

DHCPでIPが払い出される環境であれば画面上の取得したIPが出てきます。私はそのIPで一度ブラウザアクセスしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/ad03b413-9179-7d99-1bd9-6d20eb819c76.png)

お決まりのようこそ的なメッセージが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/c094c54d-d181-1dc2-ca42-063ec4f2ad87.png)

うーーん。Ver8ではお目にかかったことのないメッセージでした。とりあえず、「後にする」を選択しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/0ba514be-a2b4-28c3-8ddd-362e8ed666e4.png)

これで利用できる状態になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/408a7dad-07a6-e708-8317-49327977bf1a.png)

## 4. その他
次回は管理者ポリシーについて、見ていきたいと思います。
【Rspec】letとlet!、beforeの違い

##``let``と``let!``の違い
``let``は遅延評価と呼ばれ、テスト内でメソッドを使用した時に初めて評価（定義）され、

``let!``はテストが実行される前（it内のテストが実行される前）に評価（定義）される。

**■let**

```rb
 describe 'letの挙動を確認' do
    let(:user) { build(:user) }

    it 'userインスタンスが有効であること' do
      expect(user).to be_valid 
             ※↑ここではじめて読み込まれる
    end
  end
```

上記のように``let``は呼び出された時に、はじめてデータを読み込むので無駄にデータベースに問い合わせてしまってテストが遅くなるといったことを予防してくれる。

**■let!**

```rb
describe 'let!の挙動を確認' do
    let(:user) { create(:user) }
    let!(:user_task) { create(:task, user_id: user.id, title: 'test_title') } 

    it 'userがtaskを持っていること' do
      expect(user.tasks.first.title).to eq 'test_title' 
    end
  end
```

``task``インスタンスの入った変数「user_task」が作成されたのち、expect内のテストが実行される。

##beforeとの違い
``let``と``let!`` 以外によく聞くのは``before``だが、``before``は``let!``と挙動がさほど変わらないと言っていい。

``let!``と主な違う点は、**インスタンス変数の定義以外にも使用できる**ことである。

```rb
describe 'beforeの挙動を確認' do
    let(:user) { create(:user) }
    before { login(user) } #loginメソッドを定義している前提

    it 'is success to edit user' do
      visit edit_user_path(user)
      fill_in "Email", with: "edit_user@example.com"
      click_button "Update"
      expect(page).to have_content 'User was successfully updated.'
      expect(current_path).to eq user_path(user)
    end
  end
```

例えば、ログイン後の動作をテストしたい場合、このテストコードの内容を見ると、既にログインをすましていて、ユーザープロフィールなどを更新できるかのテストを行っている。

この**「既にログインを済ます」**箇所が``before``にあたる。

また``let!``と``before``の実行順序は定義した順番で実行される。

##``let`` /``let!``/ ``before``の使い分け

**``let``**：テストで何回か使うインスタンス変数がある時
**``let!``**：テストのブロック内で毎回使うインスタンス変数がある時
**``before``**：テストのブロック内で毎回適用させたいメソッドなど（インスタンス変数以外）がある時

##参考記事
[【RSpec】"let"と"let!"とbeforeの違いと実行順序](https://qiita.com/kikikikimorimori/items/9512bdff1053ce483c0a)
[]()