OmniAICreator/Qiita-1.07M huggingface dataset:
複数条件でのsort.Sliceの書き方工夫

Goで↓みたいな並び替えをしたい場合。
> xxxで 降順、同じならyyyで降順、それも同じならzzzで降順。

素朴に書くとless関数がこんな感じになるんだけど…

```go
if a.xxx < b.xxx {
  return true
}

if a.xxx > b.xxx {
  return false
}

if a.yyy < b.yyy {
  return true
}

if a.yyy > b.yyy {
  return false
}

return a.zzz < b.zzz
```

switch文で組み立てると{}がなくなるので少しマシになるみたい。

```go
package main

import (
	"fmt"
	"sort"
)

type person struct {
	firstName string
	lastName  string
	age       int
}

func main() {
	people := []person{
		{"taro", "tanaka", 20},
		{"hanako", "suzuki", 21},
		{"taro", "sato", 22},
		{"taro", "sato", 21},
	}
	fmt.Println(people)
	sort.Slice(people, func(i, j int) bool {
		a, b := people[i], people[j]
		switch {
		case a.firstName < b.firstName:
			return true
		case a.firstName > b.firstName:
			return false
		case a.lastName < b.lastName:
			return true
		case a.lastName > b.lastName:
			return false
		default:
			return a.age < b.age
		}
	})
	fmt.Println(people)
}
```

しかし、もう少し短くできないだろうか。。
FlutterでTextFieldのフォーカスを正しく外す方法　Listener編

GestureDetectorを使う方法だと、ボタンをタップした場合はフォーカスが外れない。
Listenerを使うと正しく外れました。

**追記 2021/02/21**
コメントよりご指摘いただきました。
長押しから貼り付けを選択した際にもフォーカスが外れて貼り付けされないようです。
良い方法があれば、教えてください！

#環境
flutter 1.25.0

#方法
```
Listener(
  onPointerDown: (_) {
    FocusScopeNode currentFocus = FocusScope.of(context);
    if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
      currentFocus.focusedChild.unfocus();
    }
  },
  child: MaterialApp(...),
);
```

#参考
https://flutterigniter.com/dismiss-keyboard-form-lose-focus/

GestureDetectorを使う方法（古いバージョンだと問題ない模様）
https://qiita.com/tsukushibito/items/d7fde1d998a30292add7
[React] ReactとNode.jsを使って何か作ってみる 20210202

#[React] 作ってみているものをWebに公開する

前回までの記事
[[PostgreSQL] 昨日作ったDBにサンプルデータをmigrationしてみる](https://qiita.com/IwashiMorino/items/926cd1fcb5a9338bfaeb "[PostgreSQL] 昨日作ったDBにサンプルデータをmigrationしてみる")
[[PostgreSQL] PostgreSQLの使い方](https://qiita.com/IwashiMorino/items/c47d76da6bc9d6c1f6b2 "[PostgreSQL] PostgreSQLの使い方")
[[React] ReactとNode.jsを使って何か作ってみる 20210130](https://qiita.com/IwashiMorino/items/e94473c286fd85568b85 "[React] ReactとNode.jsを使って何か作ってみる 20210130")

###バックエンドはHeroku、フロントエンドはNetlify

現時点のものを、バックエンドはHerokuに フロントエンドはNetlifyにデプロイしました。

Netlifyは以下のURLになります！

https://cocky-swartz-cb6f8a.netlify.app/

（※ サンプルデータが無事表示されました！）

Herokuは、だいたいいつもSleepしていると思いますので、ロードされるのに数秒かかると思います。
【HTML】iframeタグの使い方

#プログラミング勉強日記
2021年2月2日
iframeタグの使い方をちゃんと理解していなかったので簡単にまとめる。


#iframeタグとは
　iframe(読み方：「アイフレーム/インラインフレーム」)タグはInline Frameの略で、HTMLの中に別のHTMLを埋め込むために利用する。

　iframeタグは`<body>~<body>`内で使用する。src属性でフレーム内に表示する内容を指定することができる。name属性でフレームに名前を付けることができ、そのインラインフレームをリンクの表示先としてしてできる。


#iframeの使い方

##src属性にページを埋め込むページを指定
　基本的な使い方はとても簡単で、src属性に埋め込むページのURLを指定する。

```html
<iframe src="埋め込みたいページのURL"></iframe>
```

###フレームの幅と高さを指定する
　widthとheightを使ってフレームの幅と高さを指定できる。デフォルトは300px(幅)×150px(高さ)になっている。(幅と高さはCSSでも指定できる)

```html
<iframe
  src="埋め込むHTMLのURL"
  width="フレームの幅(単位なし)"
  height="フレームの高さ(単位なし)"
></iframe>
```


```html:サンプルプログラム
<p>iframe↓</p>
<iframe src="https://mzmz02.github.io/travel/" width="500" height="500"></iframe>
```

実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/ca45f02d-5473-a85f-0c0c-77fdc549bd3c.png)

##srcdocで直接HTMLを書き込む
　srcdoc属性に埋め込むHTMLを直接書き込むこともできる。ただ、`"`と`&`を使う場合はエスケープ文字を使用する。`"`は`&quot;`を、`&`は`&amp;`に置き換える。

```html
<iframe
  srcdoc="埋め込みたいHTMLコード"
  src="srcdocが使えなかった場合に表示するURL"
></iframe>
```


##YouTubeの動画を埋め込む
　よくサイトで見かけるようにYouTubeを埋め込むこともできる。

1, 埋め込みたい動画を開いて、共有をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/21ee6552-7ae4-1261-8c0f-ca3dabf82fa4.png)

2, `埋め込む`をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/69680f0d-ece2-90af-4794-679d59bd1904.png)

3, でてきたコードをコピーする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/77682974-8e9a-3098-42e5-7da724d19ff9.png)


```html:YouTubeの埋め込み
<p>iframeを使ってYouTubeを埋め込む</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/gdZLi9oWNZg" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
```

実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/8e46c17e-31ee-63bf-5380-b57750d3598a.png)


#参考文献
[IFRAME …… インラインフレームを作る](http://www.htmq.com/html/iframe.shtml)
【Rails共同開発】GitHubに公開したくないパスワード等を『dotenv-rails』を使った環境変数で管理する方法

# はじめに
Railsの共同開発で環境開発を構築する際、DBのパスワードなどの設定は各自それぞれの開発環境ごとに異なります。個人の設定をdatabase.ymlなどに直接入力すると、特定の環境でしか動かなってしまいます。また、パスワードなどの情報はGitHubにあまり公開したくありません。

そこで、開発環境ごとに異なるパスワード等の情報は環境変数として管理できるgem（dotenv-rails)を導入する事で、各自それぞれの開発環境に対応し、GitHubには公開しないように設定します。

# 環境
- macOS Big Sur
- Rails 6.1.1
- Ruby 2.7.2
- mysql 5.7.31

# dotenv-rails gemをインストール
Gemfileに以下を記述します。

```Ruby:Gemfile
gem 'dotenv-rails'
```
以下のコマンドを実行し、gemをインストールします。

```
$ bundle install
```

# .envファイルの作成と環境変数の設定
環境変数を設定したいアプリのルートディレクトリで`.env`ファイルを作成します。
ルートディレクトリで下記コマンドを実行。

```
$ touch .env
```
作成した`.env`ファイルに環境変数を記述します。
例えば、DBのユーザーネームとパスワードの場合は以下のように設定します。

```:.env
DB_USERNAME = '********' # 使用したいユーザーネームを記述
DB_PASSWORD = '**************' # 使用したいパスワードを記述
```

# 環境変数の呼び出し
`.env`ファイルに設定した環境変数を呼び出すには以下の様に記述します。
今回の場合はユーザーネームとパスワードを呼び出しています。

```database.yml
...

default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV['DB_USERNAME'] %> # 環境変数で呼び出し
  password: <%= ENV['DB_PASSWORD'] %> # 環境変数で呼び出し
  socket: /tmp/mysql.sock

...
```
これで開発環境ごとに異なるパスワード等の設定値は、各自それぞれが`.env`に記述することで使えるようになります。

# .gitignoreの設定
このままpushすると`.env`ファイルがGitHubに公開されてしまうので、`.gitignore`ファイルに以下を追加し、公開しないように設定します。

```:.gitignore
/.env
```
これで`.env`ファイルはGitの管理対象から外れる為、安心してGitHubにコードを公開できるようになります。

# .env.sampleの作成
各自それぞれが`.env`に設定すべき項目が分かるように`.env.sample`ファイルを作成します。(`.env.sample`ファイルはGitの管理対象に入れておます。)
プロジェクトごとに設定項目は違ってくるかと思いますが、万が一流出してもOKなダミーデータや、設定項目のkeyだけを記述しておきます。
例えば、DBのユーザーネームとパスワードの場合は以下のように記述しておきます。

```:.env.sample
DB_USERNAME = 'mysqlのユーザーネームを記入’
DB_PASSWORD = '設定したパスワードを記入'
```
これで、GitHubからプロジェクトをクローンしてきたときは、この`.env.sample`をコピーして`.env`ファイルを作成すると設定が楽になります。

# .envファイルをpushしてしまった場合
`.env`ファイルをGitHubにpushした場合は`.gitignore`に追加するだけでは設定が反映されず、Gitの管理対象から外れません。（.gitignoreに登録されていても、gitのキャッシュに残っていると管理対象になってしまうみたい。)
その場合は以下のコマンドを実行し、キャッシュの削除を行います。

```
$ git rm -r --cached .
```
これでGitの管理対象から外れます。

# まとめ
プログラミング初学者が、Railsの共同開発で最初の環境開発の構築を担当した際に生じた、疑問点や学んだ点をまとめました。

内容的に間違いがあればぜひコメントいただけると嬉しいです。
gradlewでテストが多すぎる時のシェルスクリプト

# 背景

いつものようにSpring Boot Kotlinで開発している際に、

「テ、テストケース800近い。。。ビルドなげぇ。。。」
なんて思っていると、

**JDBC関連のDB接続エラー**

これがたまに起きてしまいます（原因は結局よくわからず。。。）
テストの件数が多すぎてなっているような気がするのですが、急ぎではないので（CIなどでは問題が起きない）
いつも放置します

ただ、忙しい開発期間ではどうしても**ビルドがちゃんと通るか見たい、テストが通るか見たい**という状況にはなるので、
仕方がないので一個一個ディレクトリごとにfindで掘って実行するようにしました


# スクリプト例

### 通常ver.

```shell
#!/bin/bash

echo "##### Start clean build exclude test"
./gradlew clean build -x test

echo "##### Start tests per dir"
for i in $(find $1 -type d -d)
do
  if find $i -maxdepth 1 -name "*.kt" | grep -v "^\s*$" > /dev/null 2>&1
    then
      DIR_PATH=$(echo $i | sed -e "s/$(echo $1 | sed -e "s/\//\\\hoge\//g" | sed -e "s/hoge//g")\\///")
      MODULE_NAME=$(echo $DIR_PATH | sed -e "s/\\//\\./g")
      echo "##### Start test $MODULE_NAME"
      time ./gradlew test --tests "$MODULE_NAME.*"
  fi
done
```

### grep ver.

```shell
#!/bin/bash

echo "##### Start clean build exclude test"
./gradlew clean build -x test

echo "##### Start tests per dir"
for i in $(find $1 -type d -d)
do
  if find $i -maxdepth 1 -name "*.kt" | grep -v "^\s*$" > /dev/null 2>&1
    then
      DIR_PATH=$(echo $i | sed -e "s/$(echo $1 | sed -e "s/\//\\\hoge\//g" | sed -e "s/hoge//g")\\///")
      MODULE_NAME=$(echo $DIR_PATH | sed -e "s/\\//\\./g")
      echo "##### Start test $MODULE_NAME"
      time ./gradlew test --tests "$MODULE_NAME.*" | grep -e "BUILD" -e "FAILED"
  fi
done
```
RubyでSSM Parameter StoreとSecrets Managerを使う

## 何がわかるか

シークレット情報などを保存するためのSSM Parameter StoreとSecrets Managerについて

AWSCLIでシークレットを作成し、RubyやRailsなどのアプリケーションで簡単に取得する方法を書きたいと思います。

ちなみにParameter Storeは条件付きで無料で使えて、Secrets Managerは最初から有料みたいです。

また、Parameter StoreはKMSを使用する場合は有料になります。
[AWSのParameter StoreとSecrets Manager、結局どちらを使えばいいのか？比較]([https://qiita.com/tomoya_oka/items/a3dd44879eea0d1e3ef5)

## 環境

Ruby: 2.5.7

aws-cli: 2.0.7

## 前提
- aws-cliをinstallしていること
- IAMユーザにParameter StoreとSecrets Managerの必要な権限(createとget)が備わっていること

## SSM Parameter Store
gemを入れてbundle install

```
gem 'aws-sdk-ssm'
```

aws-cliでparameterを作成します

```shell
$ aws ssm put-parameter --name "<パラメータ名>" --type String --value "<パラメータの値>"
```

暗号化したい場合はtypeをSecureStringにしてください。--keyでkmsキーを指定することもできます。

あと、上書きしたい場合は--overwriteを付けるだけで大丈夫です。

moduleの作成

```parameter_store.rb

require 'aws-sdk-ssm'

AWS_REGION = '<リージョンを入れる>'

module ParameterStore
  def self.request(name)
    client = Aws::SSM::Client.new(region: AWS_REGION)
		# KMSで暗号化している場合はwith_decryption: true
    client.get_parameter({ name: name, with_decryption: false })
  end
end
```

後は取得するだけです

```ruby
# 生rubyの場合
require 'parameter_store.rb'

parameter = ParameterStore.request('/hoge')
puts parameter
#=> "<値>"
```

## Secrets Manager
gemを入れてbundle install

```
gem 'aws-sdk-secretsmanager'
```

aws-cliでsecretを作成します

```shell
$ aws secretsmanager create-secret --name "<シークレット名>" --description "<説明>" --secret-string "<シークレットの値>"
```

moduleの作成

```secrets_manager.rb
require 'aws-sdk-secretsmanager'

AWS_REGION = '<リージョンを入れる>'

module SecretsManager
  def self.request(secret_name)
    client = Aws::SecretsManager::Client.new(region: AWS_REGION)
    get_secret_value_response = client.get_secret_value(secret_id: secret_name)
    get_secret_value_response.secret_string
  end
end
```

後は取得するだけです

```ruby
# 生rubyの場合
require 'secrets_manager.rb'

secret = SecretsManager.request('/hoge')
puts secret
#=> "<値>"
```

# まとめ
簡単に導入できるので試してみてください！
EC2からEFSにDNS経由でマウントヘルパーを使用してマウントする方法

#3つのマウント方法に関して
EC2からEFSをマウントする方法は以下3種類あります。

1.DNS経由でマウントヘルパーを使用する方法
2.DNS経由でマウントヘルパーを使用しない方法
3.IP経由でマウントヘルパーを使用しない方法


ファイルシステムのマウントを簡素化するためのツールで、amazon-efs-utilsというEFS向けのパッケージをインストールすることで利用できる。以下参照。
https://docs.aws.amazon.com/ja_jp/efs/latest/ug/efs-mount-helper.html0

amazon-efs-utilsのインストール方法に関しては、後述します。
今回の記事では、1の方法でマウントする方法を紹介します。

#マウントまでの4つの手順

大まかな手順は以下の通りです。
2はとても沼りやすい工程なので、注意してください。

1.EFSコンソールからファイルシステムの作成を行う
2.1の過程で作成するEFSと接続元のEC2に共通のセキュリティグループを付与する(ここ重要)
3.EC2にamazon-efs-utilsをインストールする
4.EC2からマウント作業を行う

それでは、以下の段落から詳しく手順を紹介します。
##1.EFSコンソールからファイルシステムの作成を行う方法について
EFSのコンソール画面から、「ファイルシステムの作成」を行うと、以下ページに遷移。カスタマイズを選択。
![スクリーンショット 2021-02-02 16.39.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784921/68d468dd-c8fa-6e52-01aa-58c5af943687.png)

下記画面に遷移するので、自身が求めるスペックに変更。
![スクリーンショット 2021-02-02 15.48.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784921/6227404f-108e-9e69-67ed-6e58ccb09eb3.png)
接続したいネットワークと、接続元のEC2と共通のセキュリティグループを付与する。セキュリティグループの詳しい設定に関しては、次の段落をご覧ください。
![スクリーンショット 2021-02-02 15.50.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784921/c5b10e4b-a850-5578-8558-10ad120fbeb7.png)
ポリシーを付与して、作成完了。
![スクリーンショット 2021-02-02 15.50.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784921/1c5d2da8-c908-3529-7794-267dbe88a292.png)

#2.1の過程で作成するEFSと接続元のEC2に共通のセキュリティグループを付与する
先ほども述べましたが、共通のセキュリティグループを付与させる必要があります
具体的なルールに関しては、下記ページに記載があります。

https://docs.aws.amazon.com/ja_jp/efs/latest/ug/accessing-fs-create-security-groups.html

下記画像は、上記ページからルールの設定に関して一部抜粋したものです。

![スクリーンショット 2021-02-02 16.43.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784921/410f2435-8a20-e615-63ad-44a3468de72e.png)

上記の内容を反映させたのが、以下です。画像のように、セキュリティグループのインバウンドルールが設定されていれば問題ないです。
![スクリーンショット 2021-02-02 15.42.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784921/66e4b8a4-9f67-2477-6b56-ad4c32df4f57.png)

アウトバウンドに関しては、デフォルトで全て許可されているので、特に設定の変更は必要ないです。

#3.EC2にamazon-efs-utilsをインストールする方法
マウントしたいEC2にssh接続を行い、以下のコマンドを実行します。

```
sudo yum install -y amazon-efs-utils
```

#4.EC2からマウント作業を行う

結論、マウント作業には、下記コマンドを実行します。その前に、マウントに使用するディレクトリを作成する必要があります。

```
sudo mount -t efs -o tls ファイルシステムID:/ ディレクトリ名
```

ファイルを作成するために以下コマンドを実行。

```
mkdir ディレクトリ名
```

ディレクトリが作成できたら、下記コマンドを実行。ファイルシステムIDは、EFSのコンソール画面のトップページに記載があります。

```
sudo mount -t efs -o tls ファイルシステムID:/ ディレクトリ名
```

ちなみに、 -o tlsのオプションを記述する意味ですが、下記ページに紹介されていますので、詳しくはそちらをご覧ください。
https://dev.classmethod.jp/articles/amazon-efs-encryption-in-transit-behind-the-scene/

最後に、マウントができているかの確認ですが、一例として下記を挙げておきます。

```
df -h 
```

実行すると下記画像のように、マウントが確認できます。

![スクリーンショット 2021-02-02 16.05.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784921/b06aeb51-dc86-9cbe-aa2a-35af9be7b0e3.png)
【C言語】ポインタ入門編

# はじめに
本記事はC言語初学者の多く人が躓くであろうポインタ変数について説明したものである。
ポインタはC、C++特有なものであり、これを理解しないとアプリ開発の仕事できないでしょう。しかも初心者が一番躓くと言われている。実際私も苦労した。
そこでポインタについてザックリと解説していこうと思う。

# 前提知識
・メモリ
・変数の型
・2進数、16進数

上記の内容が理解しないとポインターについて理解するのは難しいであろう。
ほとんどのC言語学習本やサイトは上記の内容に触れているはずなのでしっかりと読んでほしい。

# ポインタの宣言・初期化
さっそく本題のポインタである。
ポインタを調べるとよくこういった内容が載っている。
「ポイントとは何らかのオブジェクトを指し、オブジェクトを間接的に参照するためのである。」
抽象度が高すぎてピンと来ない人が普通である。
実際にコードを書いて使ってみたほうがはやいです。

ポインタはアドレスを参照するということ頭に入れておいてください。

```sample.c
#include <stdio.h>

int main(void){
    char x = 'a';
    char *ptr = &x; //xのアドレスで初期化

    printf("%p\n",ptr);
    printf("%p\n",&x);
    return 0;
}
```
上記は変数Xのアドレスをポインタ変数ptrに代入して表示させてプログラムである。
同じ結果が得られるはずである。

# char型とint型の違い
char型の場合

```sample.c
#include <stdio.h>

int main(void){
    char x[10];
    char *ptr;

    for (int i = 0; i < 10; i++)
    {
        ptr = &x[i];
        printf("%p\n",ptr);
    }
 return 0;
}
```

int型の場合

```sample.c
#include <stdio.h>

int main(void){
    int x[10];
    int *ptr;

    for (int i = 0; i < 10; i++)
    {
        ptr = &x[i];
        printf("%p\n",ptr);
    }
 return 0;
}
```

出力結果を比べてみてください。

| char型 | int型 | 
| --- | --- | 
| xxxx0 | xxxx0 |
| xxxx1 | xxxx4 |
| xxxx2 | xxxx8 |
| xxxx3 | xxxxc |

お気づきでしょうか？
int型のアドレスが4つずつなっていることに！
理由はint型は4バイトのメモリを確保するためである。

# ポインタの指す先を参照
さきほどアドレスを参照したが今度はアドレスの中身を参照を行う。

```sample.c
#include <stdio.h>

int main(void){
    int x = 533;
    int *ptr = &x; //xのアドレスで初期化

    printf("%d\n",*ptr); //Xの値を表示
    printf("%p\n",ptr);  //xのアドレスを表示
 return 0;
}
```
ポインタの中身を参照したい場合は*(間接演算子)つける。⇒これがいわゆる参照外しと呼ばれている。
これが多くの初学者が混乱するところだ。
宣言時に使われているint *ptr と処理中の *ptrが同じ表記であるが意味は<font color="Red">全くの別物</font>である。
宣言時はあくまでも型の一部あることを理解していただきたい。

```sample.c
#include <stdio.h>

int main(void){
    int x = 533;
    int *ptr = &x; //xのアドレスで初期化

    *ptr = 333;

    printf("%d\n",x);
 return 0;
}
```

```
x = 333
```

上記のように参照先の中身まで変更することが可能である。

# まとめ
ポインタとはデータのアドレスのことであり、アドレスが分かれば中身を干渉することができる。

### 次回はポインタの使い方を投稿予定
pythonで写真の色温度(Kelvin)に調節

### 色温度からRGBに転換

色温度は画像処理で良く使う概念です。色温度から具体的なRGBの数値に転換の方法は幾つありますが、ほとんどの方法は色温度の数値によって、色座標やRGB空間に転換し、ピクセルのRGB値を求める。異なる計算式を使って、精度や効率は違うです。つまり、色温度からRGBの転換の結果は唯一ではないです。

出力の1000kから40000kの画像：
![1000k-40000k.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1053652/3e55dc1b-c6ea-653b-3929-b9711e7303b0.png)


今回紹介したい方法は、色座標やRGB空間に転換ではなく、色温度からピクセルのRGBの数値を計算出来で、効率的な方法です。

### 色温度からRGB相対値の計算式


[Charity’s original blackbody values](http://www.vendian.org/mncharity/dir3/blackbody/UnstableURLs/bbr_color.html)からのデータを参考し、RGB値と色温度の変化曲線で表示する。
![20200126173517800.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1053652/5ed10497-9a10-a49b-07f5-a73e3e11a12f.png)

そして、数式を使って曲線の流れを表現します。曲線あてはめにする。

### 色温度とRGB値曲線あてはめ

![20200126173646108.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1053652/3225058f-c5f1-1538-5b4d-dc0a9eba1cbe.png)
![20200126173706423.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1053652/dee6ccbf-789f-9aa8-de11-e2730ca9cdc2.png)
![20200126173713861.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1053652/579ab201-fe86-9a71-b5e4-62e306eb6882.png)
![20200126173737894.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1053652/7977c41b-79f6-fa77-3070-4868751fa6fe.png)

ここで使ったのは簡単な指数と対数関数です。異なる関数を使って曲線をフィットして、最終の精度も違います。

### python転換関数
```
def calc_kelvin(stepSize): 
        
    temp = 6600
    temp = (temp + stepSize) / 100
    
    if(temp<=66):
        red = 255
    else:
        red = temp-60
        red = 329.698727446 * pow(red,-0.1332047592)

        if(red < 0):
            red = 0
        if(red>255):
            red =255
    

    if(temp <= 66):
        green = temp
        green = 99.4708025861 * math.log(green) - 161.1195681661

        if(green < 0):
            green = 0
        if(green > 255): 
            green = 255
    else:

        green = temp - 60
        green = 288.1221695283 * pow(green, -0.0755148492)

        if(green < 0): 
            green = 0

        if(green > 255): 
            green = 255
    
    if(temp>=66):
        blue = 255
    else:
        if(temp<=19):
            blue = 0
        else:
            blue = temp - 10
            blue = 138.5177312231 * math.log(blue) - 305.0447927307
            if(blue<0):
                blue = 0
            if(blue>255):
                blue = 255

    print("red:"+str(red) + ",green:"+ str(green) + ",blue:"+str(blue))
    return red,green,blue
```
最終の調節結果：
![img.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1053652/6945b339-1d6a-ba3b-0061-4be9b6330a06.jpeg)
[DO NOT ARTICLE]Qiita の og:image を取得するためのテスト用

![kotowaza_gorimuchu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207007/45b5d497-f259-cd2b-0716-8ee3730908b9.png)

これは自分のアカウントを人柱として、 `Qiita` の `og:image` を取得を検証するための投稿です。
閲覧者には何一つ意義のないものなのでブラウザバックを推奨します。
ESP32+I2S DACでシンプルにMP3とWebRadioを再生する

色々ネットサーフィンしていたところ、schreibfaul1さんが公開されているライブラリで簡単に
MP3とWebRadioをMP3コーデックで再生できたためそのメモです。

#準備
* ESP32とSDカードアダプタとI2S DACを接続しておく→ [こちら](https://qiita.com/Geek493/items/2bdcfcd2732b46b78db1) 参照
* [こちら](https://github.com/schreibfaul1/ESP32-audioI2S)からライブラリをダウンロードしてArduino¥librariesにインストールしておく
* ESP32のボードライブラリを最新にしておく

※ボードマネージャのESP32ライブラリが古いとコンパイルエラーが出てコンパイルができませんでした。
どうやらコンパイル時のエラーメッセージから1.05.0c以上が必要なようです。
（2021/02/02時点）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067139/d6e22243-3bfd-448f-f8aa-3813b0b38f47.png)


現時点でStable Releaseの1.04が最新となってますので、Arduino IDE→環境設定→追加ボードマネージャのURLに下記Dev　Release用のURLを記入後、ESP32で検索すると最新版がインストールできます。今回は1.0.5-rc6を入れました。

```
https://raw.githubusercontent.com/espressif/arduino-esp32/ghpages/package_esp32_dev_index.json
```
■環境設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067139/e4bf31ad-7b66-d26a-559e-3a2023c5b8e9.png)

■ボードマネージャの起動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067139/f19798f2-2de3-24ca-862e-39a6ca77cc10.png)

■ESP32で検索して更新
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067139/f50cb238-f81d-c783-6602-d359f5a4c11b.png)


#ソースコード
 ★１のSSIDとpasswordはWiFiに合わせて選択する。
 ★２でSDカードからmp3を再生するかWebから再生するかコメントアウトで切り替えて試してみてください

```
#include "Audio.h"

// SDCard Pinout (SSCK　to IO18, MOSI to IO23 MISO to IO19
#define SD_CS   5

// I2S to DAC pinout difinition
#define I2S_DOUT  22
#define I2S_BCLK  26
#define I2S_LRC   25

Audio audio;

const char* wifi_ssid = "xxxxxxxxx";            // ★1ここにWiFi ssidを記入
const char* wifi_password = "xxxxxxxxxxx";      // ★1ここにWiFi passwordを記入

void setup(void) {
  
  Serial.begin(115200);
  Serial.println(F("Hello! this is Audio player Test"));

  //Mount sdcard
  if(!SD.begin(SD_CS)){
      Serial.println("Card Mount Failed");
  }

  WiFi.disconnect();
  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_ssid, wifi_password);
  
  // WiFi connection try forever
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println("...Connecting to WiFi");
    Serial.print(".");
    delay(1000);
  }
  
  Serial.print("Connected to ");
  Serial.println(WiFi.localIP());

  audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); 
  audio.setVolume(21); // 0...21

  audio.connecttohost("http://listen.181fm.com/181-beatles_128k.mp3"); //  128k mp3  ★2 ←どちらか選択 WebRadio
//audio.connecttoSD("/pno-cs.mp3");                                                  ★2 ←どちらか選択 MP3
  
}

void loop(){
  audio.loop();
}
```

以上
手を動かしながら学ぶReact入門  1. Create React App

WebフレームワークであるReactについて、実際に手を動かしながら学んでいきたいと思います。

1.　Create React Appでプロジェクトの雛形を作成　←　ここ
2.　[Reactについて学ぶ](https://qiita.com/basio/items/80bdf2c1e59f84777f90)
3.　[三目並べを関数コンポーネントで実装する](https://qiita.com/basio/items/f1ce1f3747463e7ad0e5)

# そもそもReactって？
>ユーザーインターフェース構築のためのJavaScriptライブラリ
>https://ja.reactjs.org/

と記載がある通り、JavaScriptでユーザーインターフェースを構築するためのライブラリです。
**コンポーネント**と呼ばれる単位で要素を作り、それを組み上げてUIを構築していきます。


# Create React Appでプロジェクトの雛形を作成
まずはCreate React AppでReactシングルページアプリケーションの雛形を作りましょう。
## create-react-appの取得
yarnで`create-react-app`をインストールします。

```console
$ yarn global add create-react-app
```

私の環境（Windows）ではyarnでインストールしましたが、`command not found: create-react-app`と怒られてしまいました。
どうやらパスが通っていなかったようで、`C:\Users\<ユーザー名>\AppData\Local\Yarn\bin`を環境変数のPATHに追加することでcreate-react-appコマンドが打てるようになりました。

## create-react-appの実行

`create-react-app`でプロジェクトを作成します。

```console
$ create-react-app プロジェクト名
```
プロジェクト名のところは適当に変更してください。今回はプロジェクト名を`react-example`として実行します。
すると、下記のようなフォルダ構成が出来上がります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556091/0357b32e-a9b3-ad4a-9afa-8970be10dd28.png)

## 初めてのReactアプリケーションの実行
`yarn start`でReactアプリケーションを実行できます。

```console
$ yarn start
```

これを実行すると、デフォルトブラウザが立ち上がり下記のような画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556091/e8ca8094-6b79-582d-63c9-d017410e329d.png)

どうやら、localhost:3000でサーバーが立ち上がっていますね。
最終的なReactアプリケーション自体はサーバーを含みませんが、`yarn start`を行うとソースコードに変更がある度に動的に画面を更新してくれるサーバーを立ち上げます。そこにアクセスしているわけですね。

## Reactアプリケーションのビルド
Webサーバーで静的ホスティングするためには、`yarn build`コマンドを実行して、作成された`build`フォルダの中身をWebサーバーに配置します。

```console
$ yarn build
```
下記のようなフォルダができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556091/5c1d1405-1f99-eead-4e89-e0d6dd28faf5.png)

## Hello World
まずは余分なものを取り払って、Hello Worldだけを表示するようにしてみましょう。
CSS（App.css）とテスト用ファイル（App.test.js）は今回利用しないため、削除します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556091/2efcf4cf-eea7-5e44-483c-d99ac8ce67b4.png)

App.jsをバッサリと削って、Hello Worldだけ表示するようにします。

```diff_jsx:App.js
-import logo from './logo.svg';
-import './App.css';
-
-
 function App() {
   return (
-    <div className="App">
-      <header className="App-header">
-        <img src={logo} className="App-logo" alt="logo" />
-        <img src={logo} className="App-logo" alt="logo" />
-        <p>
-          Edit <code>src/App.js</code> and save to reload.
-        </p>
-        <a
-          className="App-link"
-          href="https://reactjs.org"
-          target="_blank"
-          rel="noopener noreferrer"
-        >
-          Learn React
-        </a>
-      </header>
-    </div>
+    <h1>Hello World</h1>
   );
 }
``` 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556091/d2415485-a793-7f13-66eb-162864e67da1.png)
すっきりしましたね！
これをベースにReactの要素に触れていきたいと思います。

次：[Reactについて学ぶ](https://qiita.com/basio/items/80bdf2c1e59f84777f90)
Apache2.4でMarkdownを表示する

# この記事のターゲット
- Markdown大好きな人
- 家のサーバとかで公開したいけど変換するのが面倒
- せっかくリモートでサーバに上げれるのに変換なんてナンセンス
などと思っている方

# 手順
## 1. 準備

```
# apt install build-essential libtool automake autoconf
# apt install libmarkdown2-dev apache2 apache2-dev
# cd /usr/lib/apache2/modules
```

```
$ which apxs apxs2
```
↑は後で必要になるのでメモしておく

## 2. mod_markdownのインストール
### hamano/apache-mod-markdownのダウンロード
1. `git clone https://github.com/hamano/apache-mod-markdown`
2. [Discount](http://www.pell.portland.or.us/~orc/Code/discount/)からダウンロード

### パッケージのビルド

```
# autoreconf -if
# ./configure —-with-apxs=/usr/bin/apxs2 —-with-discount=/usr
# make
# make install
```
`/usr/bin/apxs2`には[準備](https://qiita.com/drafts/4413e27734411f51a2b5/edit#1-%E6%BA%96%E5%82%99)でメモしたものを使用する

## 3. Apacheの設定

```/etc/apache2/apache2.conf
~追記~

LoadModule markdown_module /usr/lib/apache2/modules/mod_markdown.so
<Location />
    AddHandler markdown .md
    
    # MarkdownCss style.css
</Location>
```

## 4. Apacheの再起動
```
# apachectl configtest
Syntax OK
# systemctl restart apache2
```
git blameとgit log -pを使ってファイル編集履歴を見ながらコンフリ解消する

## ファイル編集履歴を見ながらコンフリ解消したい
　共同開発をするにあたって、コンフリを解消する際にどのように解消して良いかわからない時がある。
　そんな時、そのファイルを誰がいつ、どのように変更したか、またその変更に至るまでにどのようなコミット履歴があったのか、がわかればコンフリ解消の手掛かりになる。
　以下のコマンドでは、上記のコンフリ解消の手掛かりを得ることができる。

## git blame
 git blameでは、指定したファイルの各行が変更された最終コミットを知ることができる。

```
$ git blame file_path
コミットID (変更した人の名前    変更した日時  行番号)     コード
```

## git log -p 
　git log -p では、指定したファイルのコミットの履歴を見ることができる。

```
$ git log -p file_path
```
【Shopify】自社サービスを4時間でリリースした話

#はじめに
今回は、自社サービスを4時間でリリースした話を書いていこうと思います。

この記事は**「俺らはサービスを4時間でリリースしたぜ！凄いだろ」**という記事ではなく、**「Shopifyでこんなこともできるんだよ！Shopifyって凄い！」**というShopifyを褒め称える記事です。

4時間ほどでLPとサービス内容を実装した「UnReact メンター」というサービスについて、その裏側を解説していきます。

それでは、頑張って書いていこうと思います。

# Shopify アプリのご紹介

Shopify アプリである、「商品ページ発売予告アプリ | リテリア Coming Soon」は、商品ページを買えない状態のまま、発売日時の予告をすることができるアプリです。Shopify で Coming Soon 機能を実現することができます。

https://coming-soon.reterior.jp/

https://apps.shopify.com/shopify-application-314?locale=ja&surface_detail=%E3%83%AA%E3%83%86%E3%83%AA%E3%82%A2&surface_inter_position=1&surface_intra_position=1&surface_type=search

#自社サービスについて
以下が自社サービスです。興味があれば見て下さい。

[UnReact メンター](https://unreact-commerce.jp/pages/unreact-mentor)

サービス内容はShopifyについて好き放題メンターに質問できるサービスです。

LPとサービスが一緒になっています。

LPをサクッと作った後、Shopifyの予約アプリを用いてメンターの時間を予約できるようにしました。決済や予約システムもShopifyアプリで全て終わるので、楽勝です。

ちなみに、このサービスはShopify専門のメンタープラットフォームではなく、あくまでShopifyメンターに質問できるサービスです。

つまり、外部のShopifyメンターは登録していないため、ただ単に自社の社員が一時間Shopifyに関する質問に答えることになります。

自分も、~~暇だったら~~都合があえばShopifyのメンタリングをさせて頂いてます。
#Shopifyって何？
Shopifyについて簡単に解説すると、世界最大のECサイト構築プラットフォームです。

お洒落で良い感じのサイトを簡単に構築でき、決済や商品登録・配送周りのECに必要な機能が込み込みで入ってます。

Shopifyで作られた有名なECサイトとして、[allbirds](https://allbirds.jp/)などがあります。

その他、有名どころの企業としては、[レッドブル](https://www.redbullshopus.com/)などですかね。

世界的には結構有名になっていて、全世界の3%ほどのWebサイトがShopifyで作られているほどです。

今自分はShopifyのことをECサイト構築プラットフォームと書いたんですけど、実態は結構異なります。

ECサイトも勿論構築できるのですが、Shopifyで構築できるのはそれだけではありません。

ホテルや美容院、病院などの予約サイトに加えて、オークションサイトやテイクアウトサイト、デリバリーサイトや、BtoB向けの卸売サイトまで全てShopifyで構築することができます。

ちなみに、デジタル教材の販売もできるので、形のないものを売ることもできます。

少し工夫すれば、弊社のサービスのようにメンターサービスだって作れてしまいます。

何が言いたいのかというと、**Shopifyはめちゃくちゃ凄い**という話です。

ここでもう一度、今回の記事の趣旨をおさらいしましょう。

**「Shopifyでこんなこともできるんだよ！Shopifyって凄い！」**

当然限界もあるのですが、想像以上に色んなことができます。

#なぜこのサービスを作ったの？
結論から書くと、簡単に作れそうだったからです。

あと、「自社サービス」っていうのが格好良いですよね。

普段はShopifyの受託をしてるので、「自社サービス」というものに憧れてたんですよ。

本当はゴリゴリコードを書いて、バックエンドから開発したかったんですけど、今回は既存のプラットフォームを利用することにしました。

#開発期間
開発期間は4時間ぐらいです。

自分が3時間ぐらいでLPを作って、1時間ぐらいで予約機能を導入しました。

開発期間が4時間といっても、適当に作ったわけではありません。

しっかりと真剣に4時間開発しました。

そこそこきちんとしたサービスになっていると思うので、一度見て下さると嬉しいです。

#使用技術
使用技術は`Shopify`のみです。殆どノーコードで実装しました。

最近のノーコードって凄いんですよね。とりあえずリリースして市場調査をするのにぴったりだと思います。

また、`Shopify`のみだと予約機能が導入できないので、かなりマイナーなShopifyの予約アプリである`Tipo Appointent Booking`を使用しました。

この予約アプリ、日本では殆ど使われてないんですけど、個人的には使いやすくてオススメです。

もともと海外で作られたアプリで、ジムのインストラクターやダンスの講師の時間を予約するためのアプリです。今回のメンターサービスにピッタリだったので、このアプリを選びました。

その他にもShopifyには、様々なアプリがあるので、オススメです。

なんといっても5000個以上のアプリがありますからね。大抵のことはできてしまいます。

#感想
晴れて自社サービスをリリースすることができました。

数人ほどのお客様にご購入いただいたので、とても嬉しいです。

思ったより反響がありそうなら、真面目にプログラミングで開発してプラットフォーム化もありかな～と考えたんですが、プラットフォームって難しいですよね。

やっぱりものを作るのって楽しいんで、これからも頑張って色々作っていこうと思います。

#おまけ
UnReactメンターも宜しくおねがいします。

~~暇だったら~~都合が合えば、自分がメンターさせて頂きます。

[【UnReactメンター】](https://unreact-commerce.jp/pages/unreact-mentor)

# Shopify アプリのご紹介

Shopify アプリである、「商品ページ発売予告アプリ | リテリア Coming Soon」は、商品ページを買えない状態のまま、発売日時の予告をすることができるアプリです。Shopify で Coming Soon 機能を実現することができます。

https://coming-soon.reterior.jp/

https://apps.shopify.com/shopify-application-314?locale=ja&surface_detail=%E3%83%AA%E3%83%86%E3%83%AA%E3%82%A2&surface_inter_position=1&surface_intra_position=1&surface_type=search
CodeBuildでGitHubリポジトリのメタデータ(ブランチ、タグetc）を取得する方法

# 解決したいこと

CodeBuildからGithubのタグを取得して、CodeArtifactのタグに流用したいと思ったのでやってみました。前提としてCodePipelineでCI/CDを構成することとします。

# 解決方法

CodePipelineのソースステージでGitHub（バージョン２）を選択すると「完全クローン」を選択することができる。このオプションを選択すると内部的にgitリポジトリのクローンを作成するので、コミット履歴やメタデータを取り込めるようになります。

# 手順

CodePipelineのソースステージの設定でGitHub(バージョン２）を選択
![スクリーンショット 2021-02-02 15.33.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16555/e1c31679-b755-7af7-07ec-90ccc00ee18e.png)

すると出力アーティファクト形式に「完全クローン」の項目が出るので選択。
これを選択するとロールにcloneを許可するロールを作成する必要があるので合わせて[こちら](https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/troubleshooting.html#codebuild-role-connections)を実施。

![スクリーンショット 2021-02-02 15.41.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16555/93a968a7-a357-c51a-bd80-61c3eeabc148.png)

あとは適当に動作確認ができるようにCodeBuildに設定を追加。

```
version: 0.2

env:
  git-credential-helper: yes
phases:
  install:
    runtime-versions:
      nodejs: 10
  pre_build:
    commands:
      - ls -lt
  build:
    commands:
      - git status
      - git describe --all
```

git describe --allの実行結果が出ているのでメタデータの取得ができているのが確認できました。あとは煮るなり焼くなり何なりと。

![スクリーンショット 2021-02-02 15.45.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16555/bd12cd9e-4463-dfad-ca38-e42ecc8dfff2.png)



# 参考
1. [公式チュートリアル](https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/tutorials-github-gitclone.html)
2. [GitHubアクセス許可を追加する/CodeBuildからgitcloneできるようにする権限付与設定](https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/troubleshooting.html#codebuild-role-connections)
【Xcode】Simulatorで画面録画する方法

Xcodeでアプリを開発していく上で、シミュレーターの画面録画をしたいときがたびたびあるので、記録としてその方法を残しておきます。

####1. simulatorを起動しておく  

####2. ターミナルにて動画を保存したいディレクトリまで移動する。 

```bash:terminal
 $ cd ../動画を保存したいディレクトリ名  
```


####3. ターミナルにて以下のコマンドを実行する。  

```bash:terminal
 $ xcrun simctl io booted recordVideo (動画名).mov  
```

(※ option + クリック でターミナル内で指定した場所にカーソル持っていくことができ、動画名を編集できる)  

####4. ターミナル内にてRecording startedと表示されると録画が開始されている証なので、simulatorを操作し収録する  

####5. 収録を終えたあと、ターミナルに戻り、 control + C で録画終了、指定したディレクトリに保存される
【Ruby on Rails】gemを使わずにアップロードされた画像を保存する方法（初学者向け）

#

プログラミングの学習を初めてこのかた、今まで`refile`を使用した画像の投稿の仕方のみを実装してきたため、gemを使用しない画像ファイルの保存方法を知らずに来てしまった。
が、先日Railsのデフォルトの機能のみで画像ファイルを保存する方法を学んだので、備忘録として記載しておこうと思う。

ちなみにテーブルのカラムは以下の通り
postsテーブル
・title
・content
・image_name

# 1.publicフォルダ内に画像ファイルを格納するフォルダを作成

アップロードされた画像ファイルを格納する`post_imagesフォルダ`を`publicフォルダ`階層下に作成する。
![スクリーンショット 2021-02-02 15.54.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/936377/7e88465e-a982-3906-9686-80183abded06.png)
アップロードされた画像ファイルはこのフォルダの中に`"id.jpg"`という名前で保管されることとなる。
一覧画面や詳細画面で画像を表示する際は、`"id.jpg"`の中身の記述を参照し、画像として読み込んで処理をする流れとなる。

つまり、データベースのカラムに保存されるのはあくまで`"id.jpg"`という画像ファイルを示す名前であって、実際のファイルはこのpublic内に用意した場所で保管する必要がある。

# 2.controllerに処理を記述する

今回は`params`の中身が分かりやすいように、あえてストロングパラメータを使用しない書き方で説明していく。

```rb:app/controllers/posts_controller.rb
:
  def create
    @post = Post.new
    @post.title = params[:title]
    @post.content = params[:content]
    # image_nameカラムにid.jpgという値を代入  
    @post.image_name = "#{@post.id}.jpg"
    # 変数imageにフォームから送信された値を代入
    image = params[:image]
    # File.binwriteで、public/post_imagesにファイルを作成
    File.binwrite( "public/post_images/#{@post.image_name}", image.read )
    @post.save
  end
:
```

上記の処理内容を詳しく見ていく

**1.image_nameカラムに`id.jpg`という値を代入**

```rb
@post.image_name = "#{@post.id}.jpg"
```
この名前でファイルを作成する為、アップロードされた画像は`jpg形式`に変換されて保存される。

**2.変数imageにアップロードされた画像ファイルを代入**

```rb
image = params[:image]
```
ここで`変数image`にフォームから送られてきた画像ファイルの中身を代入する。

**3.public/post_imagesにファイルを作成**

その前に軽く説明しておくと、Railsにはデフォルトで用意されているFileクラスというものが存在し、このクラスにwriteメソッドを使用することで、引数で指定した場所に、指定した記述内容のファイルを作成することができる。

```rb

# 基本形
File.write(ファイルの場所, ファイルの中身)

# 使用例
File.write("public/hello.text", "Hello")
```
↓

```rb:public/hoge.text
Hello
```

これを踏まえた上で以下の行の流れを解説すると以下の通りになる

```rb
File.binwrite("public/post_images/#{@post.image_name}", image.read)
               #第一引数　　　　　　　　　　　　　　　　　　　　#第二引数
```

・`Fileクラス`に対し、`binwriteメソッド`を使用（画像ファイルの場合はwriteではなくbinwriteでファイルを作成）
・第一引数で格納先に先ほど用意した`post_imagesフォルダ`を指定
・第二引数として渡す内容を読み込む為に、`変数image`に`readメソッド`を使用して、変数の中身を参照

## 感想

結論から言ってこちらの方法に関してはあくまで流れを理解するという名目に留めておき、実際はgemを使うのが一番手取り早いように感じる。

**記載内容に間違いがあった場合はご指摘頂けると嬉しいです。
ご連絡お待ちしております。**
vscodeでgithubdesktopを使う

今日はvscodeで Github Desktoを使い、pullrequestを使う方法について説明します。
実は今とあるベンチャーのインターンで働き始めた時、どのエンジニアもこれを使っていたので自分を使うようになりました。

そもそもGithub Desktopとはなんや？から説明します。GitHub DesktopとはGitをデスクトップのアプリケーションで動かすことができます。

筆者が感じたメリット
・最初のエディターとの連携が非常にスムーズである。最初のgit add remote originみたいな設定やgit initみたいなめんどくさいことをすることなくできます。
・Desktop側からchoreのgithubのレポジトリを作成することができます。
・cloneが鬼早い
・commitする前のコードの差分が分かりやすく、なっている

デメリット
今のところはない。個人開発する分には最適だと思う。



①まずはdesktopにフォルダを作ります。
②次にvscodeを開いて一番上のファイルをクリックする。
③フォルダを開くをクリックし、先程ファイルを作った場所を選択し、開くを押す。

④次にGithub Desktpに戻ります。
⑤current repozitoryを押し、addを押す。　
⑥add exsiting repozioryを押す。
⑦chooseを押し、作成したフォルダをクリックする。青文字のcreate a repozitoryを押す。create repozitoryを押す。
⑧publish repozitoryを押す。もう一回publish repozitoryを押す。
⑨そうするとchromeのgithub側のripozitroyが作られています。initial commitができていると思います。
⑩Github Desktop側でcurrent branchを押しbranch名を作り、newbranchを pull&&request1とします。（仮）

vscode側に戻ります。そうすると下のbranchがかわっています！

```test1.php

⑪適当にファイルを編集
<?php
$nummbers =  array(19,20,21,null)
//配列に数字を代入するtest
echo $nummers[0];
//$nummbersという配列の0番目の要素を出力する
$nummers[] = 22;
//$nummbersという配列に新しい要素を最後の要素に代入する
echo $nummers[4];
//$nummbersに新しく代入した要素を出力する
$nummbers[0] = 1;
//$numbersという配列の0番目の要素を1に上書きする
echo $nummers[0];
//$nummbersという配列の上書きした0番目の要素を出力する

if ($nummers[3] == null){
    //$numbersという配列の三番目の要素がnullの場合の条件分岐
  echo '$nummersの3番目の要素には数字が入っていません';
  //$nummbersという配列の三番目の要素がnullの場合出力される
  }else{
  echo '$nummersの3番目の要素には数字が入っています';
  //$nummbersという配列の三番目の要素がnullではない場合出力されます
 } 
   

?>

```


⑫次にGithub Desktopに戻り commit名を打ちます。
⑬commit 打つ。publishbranchを押す。create pullrequestを押す。chormeのgitに自動的にいく　create pullrequest打つ。これで完成 pullrequest完成。margeはみてもらう人にやってね
[未経験エンジニア]のオリジナルアプリ制作の反省3. 「多対多の関連付け時のデータ取得は、気をつけよう」

# 今回書くこと
中間テーブルを必要とする多対多の関連付けを行った時の、データ取得でつまづいたことを共有。

## 環境
Ruby 2.6.5
Ruby on Rails 6.0.4.3

## 結論
多対多の関連付けを行った時、関連するテーブルのレコードごとの値を利用（表示など）したいときは、**値が配列で返ってくる。**

## 実際に失敗した様子と改善後
作成したオリジナルアプリには、タグ機能が備わっている。
ここで定義するタグは、「一つのタグは複数の記事に付与され、一つの記事は複数のタグを持つ」。
このような、１対多、1対１でもない**多対多の関連付け**がなされている状況で、課題を抱えた。

この状況で、記事の詳細を表示する。そこに、その投稿に紐づいたタグ（一緒に保存されたタグ）を含んだ形で表示したいと考え、以下のように記述した。

```show.html.erb
(略)
  <%= @article.tag.image %>
（略）
```

示されているインスタンス変数は、コントローラーで取得された保存済みの記事の情報

```articles_controller.rb
  def show
    @article = Article.find(params[:id])
  end
```

しかし、エラーが。
エラー文を見ると、"**No method errorです。tagsじゃないですか？**"とのご提案があったので、ん？と思いながらその通りに書いてみました。

```show.html.erb
(略)
  <%= @article.tags.image %>
（略）
```

そしたら、"**tagじゃないですか？**"とのこと。どっちやねん。

## 解決の決め手
いろいろ試していると、どうやら、最初のエラーが結構的を射ていたのではないか、ということに気づきます。つまり、tagsは正しかったのです。

「tags...ってことは、複数...あ、タグは複数あるのか。そしたら、一つの文字列では返ってこないよな。あ、配列か！！」
と閃きます。

そこで、以下のように記述しました。

```show.html.erb
（略）
 <% @article.tags.each do |tag|%>
 　　<%= safe_join(tag.name.split("\n"), tag(:br))%>
 <% end %>
（略）

```

配列で値が返ってきているということは、**eachメソッドを用いて一つ一つ取り扱ってあげれば良いということ。**これで、タグがすべて表示されました。

## オマケ1
```show.html.erb
(略)
  <%= @article.tag.image %>
（略）
```
先ほど出てきたこの記述は、アソシエーションが組まれているテーブル同士だからできる記述です。もし、うまくいかないなと思ったときは、モデルに記述しているであろうアソシエーションが正しいか確認してみてください。

([こちら](https://qiita.com/kazukimatsumoto/items/14bdff681ec5ddac26d1)の記事では、アソシエーションのことについて、詳しすぎるくらい丁寧に説明されています。僕はこの記事に救われました。)

## オマケ2
```show.html.erb
（略）
 <% @article.tags.each do |tag|%>
 　　<%= safe_join(tag.name.split("\n"), tag(:br))%>
 <% end %>
（略）

```
こちらで出てきた、safe_joinについて補足します。これは、入力されDBに保存されたデータが、入力された通りに改行とインデントを行うようにする記述です。

```erb
(tag.name.split("\n"), tag(:br))
```
tag.nameは、tagsテーブルのnameカラムを呼び出す記述です。そこに、.split("\n"), tag(:br)と追記することで、改行やインデントを入力通りに表示してくれます。

この記述については、参考になる記事を貼っておきます。もう少し深く知りたいと思った方はご覧ください。

- [safe_join (ActionView::Helpers::OutputSafetyHelper) - APIdock](https://apidock.com/rails/ActionView/Helpers/OutputSafetyHelper/safe_join)
- [「simple_format」や「safe_join」を使って、正常に改行表示させる方法（Rails）](https://www.ryotaku.com/entry/2019/06/25/%E3%80%8Csimple_format%E3%80%8D%E3%82%84%E3%80%8Csafe_join%E3%80%8D%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%80%81%E6%AD%A3%E5%B8%B8%E3%81%AB%E6%94%B9%E8%A1%8C%E8%A1%A8%E7%A4%BA%E3%81%95%E3%81%9B)

## 最後に
最後まで読んでいただいた皆様、ありがとうございます。
ソースコード、記事の書き方について**「もっとこうしたほうがいいよ！」というご意見**、**「そこどうなっているの？」というご質問**など、お待ちしております。


## 参考文献
- [【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】🎸](https://qiita.com/kazukimatsumoto/items/14bdff681ec5ddac26d1)
- [safe_join (ActionView::Helpers::OutputSafetyHelper) - APIdock](https://apidock.com/rails/ActionView/Helpers/OutputSafetyHelper/safe_join)
- [「simple_format」や「safe_join」を使って、正常に改行表示させる方法（Rails）](https://www.ryotaku.com/entry/2019/06/25/%E3%80%8Csimple_format%E3%80%8D%E3%82%84%E3%80%8Csafe_join%E3%80%8D%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%80%81%E6%AD%A3%E5%B8%B8%E3%81%AB%E6%94%B9%E8%A1%8C%E8%A1%A8%E7%A4%BA%E3%81%95%E3%81%9B)
chromedriverが読み込めなくなった。(自分用メモ)

### 内容
実行すると下記エラーが発生する。

~~~
$ python seleniumtest.py
Traceback (most recent call last):
  File "/usr/lib/python3.7/site-packages/selenium/webdriver/common/service.py", line 76, in start
    stdin=PIPE)
  File "/usr/lib/python3.7/subprocess.py", line 775, in __init__
    restore_signals, start_new_session)
  File "/usr/lib/python3.7/subprocess.py", line 1522, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: '': ''

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "seleniumtest.py", line 4, in <module>
    driver = webdriver.Chrome(executable_path='')
  File "/usr/lib/python3.7/site-packages/selenium/webdriver/chrome/webdriver.py", line 73, in __init__
    self.service.start()
  File "/usr/lib/python3.7/site-packages/selenium/webdriver/common/service.py", line 83, in start
    os.path.basename(self.path), self.start_error_message)
selenium.common.exceptions.WebDriverException: Message: '' executable needs to be in PATH. Please see https://sites.google.com/a/chromium.org/chromedriver/home
~~~

### 解決策
#### 1. PATH直打ち

~~~
driver = webdriver.Chrome(executable_path='/c/******/******/chromedriver.exe')
~~~

バックスラであることに注意。

#### 2. chromedriverの更新
下記を参照し使っているChromeのバージョンにあったchromedriverに更新する。
https://sites.google.com/a/chromium.org/chromedriver/
Touch Keyboard and Handwriting Panel Serviceを停止すると全角入力ができなくなる。

Windows10だけでしょうか？
PCの起動を速くしたい、もったりした動作を解消したいという思いからサービスなどを見直していました。

これは関係ないだろうと停止した「Touch Keyboard and Handwriting Panel Service」が思いっきり影響ありまくりでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662111/92313378-f822-11cf-71fa-2c99c934e2d9.png)

何をしても半角入力から脱出できずに全角入力に切り替えられませんでした。

ググってもダメだったので残しておきます。無事に日本語が入力できてよかったです。
ビルドエラー：Exception: Calling TargetGuidByName with name='Unity-iPhone' is deprecated.

# 環境
Unity 2019.4.19f1

# 該当のコード

```csharp

                var target = proj.TargetGuidByName("Unity-iPhone");
                proj.AddFrameworkToProject(target, "WebKit.framework", false);
```

# 発生したエラー

`Exception: Calling TargetGuidByName with name='Unity-iPhone' is deprecated. There are two targets now, call GetUnityMainTargetGuid() - for app or GetUnityFrameworkTargetGuid() - for source/plugins to get Guid instead.`

ただのDeprecatedなのでビルドは成功するけど、上記メッセージを残して終了する。
理由はメッセージの通り、`There are two targets now`であるからだ。

で、たぶんこのままXcodeでビルドしようとするとだいたい失敗する。


どう修正すべきかもメッセージ通りで、アプリ用なら`GetUnityMainTargetGuid()`, プラグイン用なら`GetUnityFrameworkTargetGuid()`を呼ぶようにすればよい。

# 解決


```csharp

                var target = proj.GetUnityFrameworkTargetGuid();
                proj.AddFrameworkToProject(target, "WebKit.framework", false);
```


# 結論
エラーメッセージを読め
初心者の私がaws,laravel,nginxでつまずいたケース

#題名の通り、自分がlaravelをnginxで立ち上げ、awsでデプロイさせる際につまったケースです。参考になれば幸いです。

## 前提

- nginx,php,php-fpm,laravel等のインストール 


##① nginxのconfファイル設定

まず、nginxのconfファイルの設定でつまずきました。
confファイルでroot設定を正しくしているのに、index.phpを読み込んでくれず、404エラーとなってしまう状況となりました。

``` etc/nginx/nginx.conf


    server {
        listen       80;
        listen       [::]:80;
        server_name  _;
        root         /var/www/<ディレクトリ名>/public;
        index        index.php index.html index.htm;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
           try_files      $uri $uri/ /index.php?$query_string;
        }

        #redirect server error pages to the static page /40x.html
        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        location ~ \.php$ {

            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass   unix:/var/run/php-fpm/php-fpm.sock;
            fastcgi_index  index.php;
            include        fastcgi_params;
            fastcgi_param  SCRIPT_FILENAME  $document_root/index.php;
        }

         # redirect server error pages to the static page /40x.html

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }

```

一見問題なさそうなので、とても解決するのに時間がかかりました。
結論この設定で問題なのは

```
   include /etc/nginx/default.d/*.conf;
```

この記述でした。
どうやらincludeの読み込み指定で、どのconfを読み込めばいいかわからず、エラーとなっていたそうです。
やはり、公式サイトを見るのが吉ですね。。。

[laravel公式サイト](https://readouble.com/laravel/6.x/ja/deployment.html)

##② laravelのkey作成

### laravelの権限関係

上記の通り、root指定できたので、laravelのキーを作らないといけないと思い、

```
php artisan key:generate
```

をしたところ、

```
The stream or file "/var/www/laravel/storage/logs/laravel.log" could not be opened: failed to open stream: Permission denied
```

あ、権限与えていなかったと思って、

```
sudo chmod 777 /storage/logs
```

としましたが、まだ権限エラーが出ていました。
なぜかと思い、laravel.logを見に行ったら、権限が通っていませんでした。
そのため、laravel.logにも777してあげると、権限エラーは消えましたが、下記の通りになりました。


## envファイルエラー

```
file_put_contents(/var/www/laravel/.env): failed to open stream: Permission denied
```

なんだこれは。。envの権限がない？
とはいっても、.envに777渡すわけにはいけないよなと思っていたところ、
あ、rootユーザでやってみたらどうだろうと思い、

```
sudo su

//rootユーザーに変身！

php artisan key:generate
```

をしたころ、コマンドが通りました！！！

ブラウザで確認したところ、

![laravel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/764103/c87d1a46-59ab-6d43-dee6-bbe8968ae1c3.png)


おーー！いけました！


## 反省

全体的に、知識が足りなかったです。もっと勉強します。笑

今回学んだこと

- [nginxのconfの記述](https://readouble.com/laravel/6.x/ja/deployment.html)
- [swpファイルの削除](http://www.php-mysql-linux.com/linux/swp-delete/)
- [改めて権限関係](https://qiita.com/shisama/items/5f4c4fa768642aad9e06)
- [つまづくとつまずくの違い](https://business-textbooks.com/tsumazuku-tsumaduku/)
ファイル管理

現在勉強している基本情報技術者試験についてまとめたものです。
自分のアウトプット用なので見やすさなどは期待しないでください。

# ファイル形式

**ファイル**とはデータを一つの塊として記録するために使う単位で、そのファイルを作成したアプリケーション以外では読み込めない独自フォーマットのファイル形式と、多種多様な環境でデータのやり取りを行いたい場合に使用する共通フォーマットのファイル形式がある。

共通フォーマットとして広く使用されているファイル形式には下記がある。

・**テキスト形式**・・・文字コードと、改行やタブなど一部の制御文字のみで作られるファイル形式。

・**CSV形式**・・・基本的にはテキスト形式だが、ここのデータである文字や数字をカンマで区切り、行と行を改行で区切ることで、表形式のデータを保存することに特化したファイル形式。

・**PDF**・・・画像が埋め込まれた書類を、コンピューターの機種やOSの種類に依らず、元の通りに再現して表示することができる電子文書のファイル形式。

| 画像用のファイル形式 |  |
|:-:|:--|
| BMP | 画像を圧縮せずにそのまま保存するファイル形式で、画像は一切劣化しないがファイルサイズが大きくなる。 |
| JPEG | 写真を保存するのに向いているファイル形式で、不可逆圧縮を行うため、圧縮のレベルに応じて画像が劣化する。 |
| GIF | イラストやアイコンなどの保存に適した画像圧縮形式で、可逆圧縮であるため画像の劣化はないが、扱える色数が２５６色までという制限がある。 |
| PNG | フルカラーを扱える上に可逆圧縮であるため画像の劣化もないという、ある意味万能な画像圧縮形式だが、単純な圧縮率ではJPEGの方が勝る。 |

| 音声用のファイル形式 |  |
|:-:|:--|
| MP3 | 音声を圧縮して保存するファイル形式で、人に聞こえない範囲の信号を削り落とすことでデータ量を削減するなど、不可逆の圧縮を行う。 |
| MIDI | 音声そのものではなく、ディジタル楽器の演奏データを保存することができるファイル形式。 |

| 動画用のファイル形式 |  |
|:-:|:--|
| MPEG | 動画を圧縮して保存するファイル形式で、不可逆圧縮を行う。 |

圧縮されたファイルを開くときは、逆方向の伸張という展開作業を行なって、元のデータを復元する。
元々のデータを間引く形で圧縮したものは、伸張後も厳密な意味の元と同じデータにはならず、このような圧縮方法を**不可逆圧縮**と呼び、戻せる場合は**可逆圧縮**という。

# ディレクトリ

**ディレクトリ**
ファイルをグループ化して整理するもので、補助記憶装置の中はディレクトリで管理されている。

階層構造の一番上位に位置するディレクトリを**ルートディレクトリ**と呼び、他のディレクトリに含まれるディレクトリを**サブディレクトリ**と呼ぶ。
また、自分が今開いてい作業しているディレクトリのことを**カレントディレクトリ**といい、カレントディレクトリを含む１階層上のディレクトリのことは、**親ディレクトリ**と呼ぶ。

ファイルを指定するときは、どこのディクトリに入っており、そのディレクトリはどこにあるのかを支持しなければならない。
このファイルまでの場所を指し示す経路のことを**パス**という。

パスには、ルートディレクトリからの経路を書き示す**絶対パス**と、カレントディレクトリからの経路を書き示す**相対パス**という２種類の書き表し方がある。
パスを表記するにあたって、次の決まりがある。

1. ルートディレクトリは「/」または「¥」で表す。
2. ディレクトリと次の階層との間は「/」または「¥」で区切る。
3. カレントディレクトリは「.」で表す。（相対パス）
4. 親ディレクトリは「..」で表す。（相対パス）

# 汎用コンピュータにおけるファイル

企業の基幹業務などで利用される大型のコンピュータ（汎用コンピュータ）におけるファイルは、一連のデータ（**レコード**）をまとめたものの集合が**ファイル**。
汎用コンピュータの場合はOS自身がどのようにレコードを格納するかを定義づけた、**ファイル編成方**をいくつか用意して、プログラムに提供している。

ファイルに対して読み書きを行う際の**アクセス方法**については、下記の３種類がある。

・**順次アクセス**
先頭レコードから順番にアクセスする方法で、シーケンシャルアクセスとも呼ばれる。

・**直接アクセス**
任意のレコードに直接アクセスする方法で、ランダムアクセスとも呼ばれる。

・**動的アクセス**
順次アクセスと直接アクセスとを組み合わせた方法で、任意のレコードに直接アクセスした後、それ以降を順次アクセスで順番に処理する。

ファイル編成方の中でも、代表的なものは以下がある。

・**順編成ファイル**
頭から順番にレコードを記録していく最も単純な編成方法で、順次アクセスのみが可能。

・**直接編成ファイル**
レコードの中のキーとなる値を利用することで、直接アクセスを可能とする編成方法で、**直接アドレス方式**（キー値の内容をそのまま格納アドレスとして用いる方式）と**間接アドレス方式**（**ハッシュ関数**という計算式により、キー値から格納アドレスを算出して用いる方式）がある。

ハッシュ関数による計算の結果が重複することで、異なるレコードが同じアドレスで衝突してしまうことを**シノニム**という。

・**牽引編成ファイル**
牽引を格納する**牽引域**と、レコードを格納する**基本データ域**、そこから溢れたレコードを格納する**あふれ域**という3つの領域から構成され、牽引による直接アクセスと、銭湯からの順次アクセスという、両方の特性を備える編成方。

・**区分編成ファイル**
**メンバ**と呼ばれる順編成ファイルを複数持ち、それらを格納する**メンバ域**と、各メンバへのアドレスを管理する**ディレクトリ域**とで構成される編成方法。
s3のファイルをダウンロードリンクurl作り

### S3のファイルをダウンロードurl作る方法

s3にアップしたファイルを、webでダウンロードできるurlの取得方法です。
python使ってます。

s3にあるファイルをwebダウンロードurl取得
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88511/c5a165c0-b11c-b76f-3479-ea860ad2317a.png)


### pythonコード
```python
import boto3

s3_client = boto3.client('s3')

BUCKET = 'my-bucket'
OBJECT = 'foo.jpg'

url = s3_client.generate_presigned_url(
    'get_object',
    Params={'Bucket': BUCKET, 'Key': OBJECT},
    ExpiresIn=300)

print(url)
https://xxxxx-voice.s3.amazonaws.com/thumnail.jpg?AWSAccessKeyId=xxxxxxxx&Signature=Zq%2FlTTK6zuD%2BAgtqrjJ2gIHTN9Y%3D&Expires=xxxxx
```


### htmlリンク
```
<a href="https://xxxx-xxxx.s3.amazonaws.com/thumnail.jpg?AWSAccessKeyId=xxxxx&Signature=Zq%2FlTTK6zuD%2BAgtqrjJ2gIHTN9Y%3D&Expires=1612243885" download>download</a>
```
【Laravel】413 Request Entity Too Largeが出たときの対処法

# 環境

laradock環境

# 対処法
①docker-compose exec nginx bashでコンテナに入る
②etc/nginx/nginx.confをviで編集する
③ client_max_body_sizeの値を変更する
④nginxのコンテナを再起動する

以上
Eclipse.ini に -Dfile.encoding=utf-8 を設定すると起動しない

## 環境
```
>java -version
openjdk version "11.0.8" 2020-07-14 LTS
OpenJDK Runtime Environment 18.9 (build 11.0.8+10-LTS)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.8+10-LTS, mixed mode)
```
pleiades-2020-03-java-win-64bit_20200322 を利用

## 解決法
`eclipse.ini`の`-javaagent:～～～～pleiades.jar`の後ろに`=no.clean.message`を足す。

## 参考
https://github.com/cypher256/pleiades.io/issues/36
terraformで「run.googleapis.com/client-version」の差分をignore_changesする

GCPのフルマネージドでコンテナをよろしく動かすサービスの`CloudRun` をterraformで構築・運用した時の、ちょっとした問題を解決できました。（1年くらい悩んでました）

[Cloud Run: コンテナを秒単位で本番環境にデプロイ  \|  Google Cloud](https://cloud.google.com/run?hl=ja)
[google\_cloud\_run\_service \| Resources \| hashicorp/google \| Terraform Registry](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloud_run_service)

# 事象

`template.metadata.annotations.run.googleapis.com/client-version` が、必ず差分が出てしまう。

terraform planの結果抜粋

```terraform
   ~ template {
          ~ metadata {
              ~ annotations = {
                    "autoscaling.knative.dev/maxScale"      = "1000"
                    "client.knative.dev/user-image"         = "gcr.io/XXXXXX"
                    "run.googleapis.com/client-name"        = "gcloud"
                  - "run.googleapis.com/client-version"     = "318.0.0" -> null
                    "run.googleapis.com/sandbox"            = "gvisor"
                }
                generation  = 0
                labels      = {}
            }
```

今の値が「318.0.0」だから、tfファイルに書けばよいのでは、、、と思うかもしれませんが、、、、

```terraform
 template {
    metadata {
      annotations = {
        "autoscaling.knative.dev/maxScale" : 1000
        "run.googleapis.com/client-name" : "gcloud"
        "client.knative.dev/user-image" = "gcr.io/XXXXXX"
        "run.googleapis.com/client-version" = "318.0.0"
        "run.googleapis.com/sandbox" = "gvisor"
      }
    }
  }
```

このバージョンはCloudRunが自動でバージョンアップするので、通常のデプロイを繰り返していると、どこかのタイミングでずれます。



```terraform
```terraform
   ~ template {
          ~ metadata {
              ~ annotations = {
                    "autoscaling.knative.dev/maxScale"      = "1000"
                    "client.knative.dev/user-image"         = "gcr.io/XXXXXX"
                    "run.googleapis.com/client-name"        = "gcloud"
                  - "run.googleapis.com/client-version"     = "319.0.0" -> "318.0.0"
                    "run.googleapis.com/sandbox"            = "gvisor"
                }
                generation  = 0
                labels      = {}
            }
```


# 対応

terraformで変更を無視する`ignore_change` という設定があるので、これを入れればよいのですが、値が入れ子なので書き方にコツがいります。

正解はこうです。

```terraform
  lifecycle {
    ignore_changes = [
      template[0].metadata[0].annotations["run.googleapis.com/client-version"]
    ]
  }
```

`template`と`metadata`がlistになっているようで、`[0]`をつけないといけないのが大変わかりにくいです。


# 参考

[terraformで入れ子の値を無視（ignore\_change）する方法 \- Qiita](https://qiita.com/moya_dev/items/b3fc4c8f3242e8bb65f4)