OmniAICreator/Qiita-1.07M huggingface dataset:
CloudFront 基本の”キ”

# CloudFrontについて
お疲れ様です、第三システム部の稲村です。
3月末より新しいプロジェクトに参加しまして、その際にCloudFrontに触れる機会に恵まれましたので、改めて発表用に向けた資料となります。

## 参考資料
いわずもがなメインはBlackBeltを参考にしています（こっちの方が詳し（以下ry）
参考サイト：[[AWS Black Belt Online Seminar] Amazon CloudFront deep dive 資料及び QA 公開](https://aws.amazon.com/jp/blogs/news/webinar-bb-amazon-cloudfront-deep-dive-2020/)

## CloudFrontとは
![cloudfront](https://cloud5.jp/wp-content/uploads/2022/04/スクリーンショット-2022-04-15-21.44.36-640x356.png)
20201028 AWS Black Belt Online Seminar Amazon CloudFront deep dive より

- コンテンツの配信を**高速化**する
- AWS global networkにより、**非キャッシュも高速化**する
- オリジンへの負荷を**オフロード**（肩代わりしてけ軽減してくれる）

## CloudFront設定する際に押さえておきたい用語
![](https://cloud5.jp/wp-content/uploads/2022/04/スクリーンショット-2022-04-16-15.08.58-640x302.png)

- **Distribution（ディストリビューション）**:**CloudFront自身**の設定
- ** Origin（オリジン）**:**コンテンツ提供元のサーバ**の設定
- **Behavior（ビヘイビア）**:**キャッシュの動作**設定

## CloudFront料金モデル
![cloudfrotn_price](https://cloud5.jp/wp-content/uploads/2022/04/スクリーンショット-2022-04-17-9.37.57-640x225.png)
- CloudFrontの料金以外にも、**ブラウザキャッシュ**における考えも考慮してアーキテクトを考えなければいけない

### ブラウザキャッシュについて
大きくブラウザには2つの**強いキャッシュ**と**弱いキャッシュ**というものがあります。
#### 強いキャッシュ
ブラウザ側でリソースを保持して、期限が切れるまでサーバにHTTPリクエストを発効しません。そのため、一度ブラウザにキャッシュされると、**サーバ側からハンドリングすることができなくなります**
- Cache-Controlヘッダー
- Expiersヘッダー

#### 弱いキャッシュ
アクセスに対して都度リソースが更新されているかチェックをおこないます、ブラウザ側でキャッシュされていても、リソースを更新すればブラウザに更新情報を届けられ、**サーバ側でハンドリングできる。**
- Last-Modifiedヘッダー
- ETagヘッダー

### ブラウザのキャッシュ戦略
**弱いキャッシュをハンドリングするような設定にして、CloudFrontで全体的なキャッシュの設定を行う。**

料金について:[Amazon CloudFrontの料金](https://aws.amazon.com/jp/cloudfront/pricing/)
UIImageViewでAspectFitを指定した時の画像サイズを取得する

`imageView.frame.size`でUIImageViewのサイズを取得するみたいに、`imageView.image.frame.size`のように取得したいができない、、、

## 方法
```
import AVFoundation

guard let image = imageView.image else { return }
let frame = AVMakeRect(aspectRatio: image.size, insideRect: imageView.bounds)

print("x = \(frame.origin.x)")
print("y = \(frame.origin.y)")
print("height = \(frame.size.height)")
print("width = \(frame.size.width)")
```

## 参考記事
https://developer.apple.com/documentation/avfoundation/1390116-avmakerect

https://blog.kishikawakatsumi.com/entry/20130524/1369329430
Flutterのlibディレクトリの例

## 初めに

Flutterのlibディレクトリをどうするのが良いのか、初めめちゃくちゃ悩んだので
現在よく利用している分け方を紹介します。


## libディレクトリの例

```
lib
├── main.dart
├── commons
├── configs
├── enums
├── models
│   ├── firestore
│   └── providers
├── services
└── views
    ├── atoms
    ├── molecules
    ├── organisms
    ├── pages
    └── templates
```

- viewの中身は、atomic designで分割
- modelsはデータを保有
- servicesは、ロジックを保有
- configは、環境変数系
- enumsは、全体で利用するenumを保有
- commonsは、共通処理を保有

## 最後に

今の現状がこの構造になっているだけで、今後も変わっていくと思います。
Expressフレームワーク、MongoDBを使ったAPIの作成

まず、Expressフレームワークをインストールします。

```shell-session
$ npm install express
```
次に、mongodb用のドライバであるmongodbをインストールします。
```shell_session
$ npm install mongodb
```
次に、Expressアプリケーションを作成します。
```
$ express myapp
$ cd myapp
$ npm install
```
そして、app.jsファイルを開き、次のように記述します。

```js
var express = require('express');
var app = express();

// mongodb用のライブラリを読み込む
var MongoClient = require('mongodb').MongoClient;

// mongodbに接続
MongoClient.connect('mongodb://localhost:27017/myapp', function(err, db) {
  // データベースに接続できたら、APIを実装する

  // GET /api/users
  app.get('/api/users', function(req, res) {
    // usersコレクションから全てのドキュメントを取得
    db.collection('users').find({}).toArray(function(err, docs) {
      // 取得したドキュメントをjson形式で返却
      res.json(docs);
    });
  });

  // サーバを起動
  app.listen(3000, function() {
    console.log('Server started on port 3000');
  });
});
```

上記のコードでは、mongodbに接続してから、GET /api/usersに対する処理を定義しています。この処理では、usersコレクションから全てのドキュメントを取得し、json形式で返却します。

最後に、サーバを起動して、APIが正常に動作するか確認します。

```
$ node app.js
```
ブラウザから、http://localhost:3000/api/users にアクセスすると、json形式のデータが表示されるはずです。
入れ子構造からなるjson形式のオブジェクトの複数配列から、特定の値を抽出して、新しいjson形式を作成する。

# Json形式のデータ 整形方法を学ぶ①

以下のようなデータがあります。

```javascript
const jJSON= {
  "users": [
    {
      "name": "John",
      "age": 30
    },
    {
      "name": "Jane",
      "age": 25
    }
  ]
}

```

json形式のオブジェクトから特定の値を抽出するために、JavaScriptのmap()メソッドや、filter()メソッドを使用することができます。これらのメソッドは、配列から新しい配列を作成することができます。

例えば、次のようなコードでは、json形式のオブジェクトから、nameとageの値を抽出し、新しい配列を作成しています。

```javascript
const extracted = json.users.map(user => ({
  name: user.name,
  age: user.age
}));

console.log(extracted);
// => [
//   {
//     "name": "John",
//     "age": 30
//   },
//   {
//     "name": "Jane",
//     "age": 25
//   }
// ]

```
Pythonで二項分布を使って確率pのガチャをN回まわした時に何回当たりを引けるか可視化する

## 二項分布とは

　二項分布(Binomial Distribution)とは、互いに独立したベルヌーイ試行をn回行ったときに、ある事象が何回起こるかの確率分布です。例えば、「コインを5回投げた時に表2回出る確率」「SRの出現割合が1%のガチャを100回まわして1回SRを引ける確率」などを表した確率分布です。

　※ベルヌーイ試行・・・「成功か失敗か」「表か裏か」「勝ちか負けか」のように２種類のみの結果しか得られないような実験、試行のこと

　二項分布は科学技術計算でよく使われるライブラリSciPyにあるstatsを使用して計算することができます。

## 確率50%のコインを10回投げて表が出る確率の二項分布の例

　まずは簡単に例題としてコインを10回投げた時の表の出る確率の二項分布を表示してみます。pは確率、nは試行回数を入力します。
　
```python
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats

plt.style.use("seaborn-darkgrid")

n = 10 #試行回数
p = 0.5 #確率
x = np.arange(n + 1)

plt.bar(x, stats.binom.pmf(x, n, p))
plt.xlabel('number of successes')
plt.ylabel('probability')
```

出力結果

![Qiita_2022-12-10_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350321/0f4f7334-4651-cd92-e621-1965917f931e.png)


　このグラフでは、5回ほど表が確率が最も高くだいたい25%、そして9回、11回ほど表が出る確率が同じくらいで約20％ということがわかります。

## 確率1%の当たりのガチャを100回まわした確率の二項分布の例

　そして上記のコードのnとpの値を変えれば、確率1%(p=0.01)のガチャを100回(n=100)まわした時に当たりが何回出るかをグラフ化することができます。

```python
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats

plt.style.use("seaborn-darkgrid")

n = 100 #試行回数
p = 0.01 #確率
x = np.arange(n + 1)

plt.bar(x, stats.binom.pmf(x, n, p))
plt.xlim(-1, 10) #X軸の表示範囲を指定
plt.xlabel('number of successes')
plt.ylabel('probability')

```

出力結果

![Qiita_2022-12-10_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350321/c250965e-67e9-4977-f4fa-e33403c02c83.png)


　グラフから確率1%のガチャを100回まわした場合、1回当たりが出る確率はだいたい36%程度で、0回もほぼ同じ確率ということがわかります。

## 確率1%の当たりのガチャを100回、200回、300回とまわしてみた場合の比較

　それでは上記のコードに少し手を加えて最後に確率1%の当たりのガチャを100回、200回、300回とまわしてみた場合の二項分布を比較をしてみたいと思います。

```python
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

plt.style.use("seaborn-darkgrid")

def show_binom(x, n, p):
    plt.bar(x, stats.binom.pmf(x, n, p), alpha=0.5, label=r"$N$:"+str(n))

p = 0.01 #確率

n = 100 #試行回数
x = np.arange(n + 1)
show_binom(x, n, p)

n = 200 #試行回数
x = np.arange(n + 1)
show_binom(x, n, p)

n = 300 #試行回数
x = np.arange(n + 1)
show_binom(x, n, p)

plt.xlim(-1, 12) #X軸の表示範囲を指定
plt.xlabel('number of successes')
plt.ylabel('probability')
plt.legend()
plt.show()
```

出力結果

![Qiita_2022-12-10_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350321/61ad312f-294e-96ff-fbfe-a07e2b3effba.png)

　この結果を見ると、当たりの確率1%のガチャを300回まわしても、5%ぐらいの確率で当たりが出ないということがわかりますね。

## まとめ

　ガチャってやっぱり怖いね。
海外サッカー日本代表のスコア可視化

## データ取得
２０２２年のプレミアリーグ、ブンデスリーガ、ラリーガ、リーグアンで活躍する選手のデータを取得した。
https://www.kaggle.com/datasets/vivovinco/20222023-football-player-stats

## Tableauで可視化
Tableau Desktopにデータをアップロードし、簡易的に可視化。
![サッカー.JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3014658/a185475b-fd80-9c3a-89b0-c7bb666958cc.jpeg)
チケット販売サイト アクセス集中対策

# はじめに
株式会社メタップスのアドベントカレンダー11日目の記事です。

メタップスの子会社であるメタップスペイメント社のチケット販売サービス「チケットペイ」では、販売するイベントによっては販売申し込み開始時に大量のサイトへのアクセスが発生します。

本記事では、チケットペイにて行っている負荷対策についてご紹介します。

# 環境

RDB: MySQL

基盤: AWS

本記事で登場するAWSサービス: CloudFront, Aurora MySQL, SQS, ALB, ECS


# CDN(CloudFront)の利用

CloudFrontの利用がアクセス負荷対策の効果が一番大きいです。

全リクエストの大体4/5がCloudFrontから返却されるようになっています。

ビヘイビア設定では、パスパターンにjs,css,画像のパスを指定し、S3上にファイルがある場合はS3にリクエストさせ、ホストに配置してあるファイルはキャッシュ上から取得させるようにしています。

キャッシュポリシー CachingOptimizedAllQuery は、デフォルトである CachingOptimized のポリシーをベースにしており、クエリ文字列が異なる場合は実際のファイルを取得するようにしています。※ファイルアクセス時にクエリ文字列まで含めてリエスとさせており、ファイル更新時はクエリ文字列部分が変更されるような更新運用を行っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867400/6b8a99c0-c073-262d-3093-4de86d0af712.png)


その他は、エラーページ設定を行っております(後述)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867400/72162fb8-a14d-331b-6e57-1191b5631338.png)

# RDB(MySQL)のパラメータ設定

以前アクセス集中し、DBへの負荷が上昇した際、

以下の記事にある server has gone away のエラーが発生したため、記事に記載されているように max_allowed_packet の値を 20M に設定し wait_timeout も 60 に設定しました。

https://style.potepan.com/articles/19640.html

この設定変更により、同様のエラーは発生しなくなりDBアクセスが安定しました。

# スケールアップ・スケールアウト対応

アクセス集中することが予め分かっているような場合は、事前にスケールアップ・スケールアウト計画を立て、当日に実行します。アクセス集中するのはチケット販売開始直後の僅かな時間なので、アクセスが落ち着いてきたらスケールダウン・スケールインさせます。コストを最小限に抑えるためにこのような手法を採っています。

### ALB

ALBについては事前に暖機申請を行います。

参考:

https://qiita.com/pict3/items/b5c2b62ab284cefba87d

直前に申請を行っても対応できないこともあるので、余裕を持って申請する必要があります。

### ECS

Fargateではなく、 ECS on EC2を利用しているので、Auto Scaling グループにて容量(台数)を増加します。

台数は過去実績を元に、ある程度余裕を見て決めます。

インスタンスタイプをスケールアップする場合は、新たな起動テンプレートを作成しAuto Scaling グループに設定します。

### RDB

通常、xlargeのインスタンスをライター1台リーダー1台で稼働させています。

アクセス集中時はインスタンスタイプをスケールアップさせ、リーダーインスタンスは2〜4台程度に増加させます。

ライターをスケールアップする際はフェイルオーバーが必要ですので、その間は一時的にALBにてサイトをメンテナンス状態に変更します。

# アプリケーション側の対策

RDBへの接続は、ライターに負荷が集中しないよう、参照系のクエリはリーダーインスタンスに接続するように制御しています。これでリーダーインスタンスの台数を増やすことによって負荷分散が行えます。

また、アプリケーション処理時に外部へ接続するような場合はその外部サイトへの負荷がかかり、処理遅延になってしまう可能性があります。

そこで、外部へ接続するような処理の場合は同期処理から、AWS SQSを利用し非同期処理になるよう実装を変更しました。

AWS SQSの選定理由としては、AWSマネージドであることと、他にもSQSを利用しており実績もあり実装にも慣れているため実装コストもそこまでかからなかったためです。

# その他の対策

基盤設定も重要ですが、他にも対策できることがあります。

例えば、チケット申し込みには会員登録が必要になっているため、事前に会員登録をしていただくようアナウンスをして登録を促しておくことも対策です。

また、「抽選」の申し込みであればチケット販売開始時に殺到して申込みをする必要はないので、販売事前説明にて申込みタイミングによって抽選結果は変わらないことを伝えておくようなことも有用だと思われます。

万が一、予想を超えるような負荷が発生し、502 Bad Gateway のようなエラーになってしまう場合、Sorryページにはメッセージだけではなく、デザインを入れておくことによりユーザの心象を損なわないようにするようなことも必要です。

sorryページの設定は前述のCloudFront上で行っております。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867400/948a1ad1-71ef-385c-40bd-ddf79124bf8e.png)
アニメリアクションチャンネルで英語を学ぶ

# はじめに

以前に海外の学会に参加して、話すのは何とかなるけど聞くのがだいぶ苦手だなぁと実感したのですが、アニメリアクションチャンネルを聞きまくったらなんか英語力ものすごく上がったのでまとめておきます。

ちなみにアニメリアクションチャンネルとは、海外のYoutuberが日本の有名なアニメを（著作権の関係上映像や音を程よく隠しながら）見てリアクションして感想を言うという系統のチャンネルです。

### 何でアニメリアクションチャンネル？

- Youtubeには**字幕自動生成機能**があり、英語に関してはかなり正確なので、聞き取れなかったところの復習などができる。
- 自分がすでに見たシーンをもとに英語を話してくれるので、知らない表現があっても程よく理解できる。
- 教材のCDなどに収録される英文と違い、とっさに出る言葉、悪態、感情表現などが、**本来の使用頻度**で使われる。例えば「やっぱり！」を意味する"I knew it!"はかなりの頻度で使われるが、教材では多数の英語表現を網羅することを優先しているので、たぶん出てきても1回きりで、とてもじゃないが身につかない。
- 「○○さんがこんなときこんな表現使ってた」みたいに、人間は結局、他の人間がどういう場面でどんな表情をしながらどんな言葉を発したかで記憶しているように思います。その点、よく言われるのが、外国人の恋人を作るのが最適らしいですが、まあ無理なのでアニメリアクションチャンネルで行きましょう。

### アニメそんなに見ないんだけど...

自分も別にディープなアニメファンでなく、進撃の巨人とかスパイファミリーとか、最近ではチェンソーマンとか、有名どころをかじっていれば十分です。

# おすすめチャンネルを紹介

字幕付きの切り抜き動画もありますが、リアクション自体に重点を置いた切り抜きなので、あまりお勧めしません。本家を見ましょう。

ちなみに、各チャンネルの画面の「再生リスト」でアニメごとにまとまっています。

### Nicholas Light TV

https://www.youtube.com/@NicholasLightTV

**主なアニメ:** 進撃の巨人、鬼滅の刃、呪術廻戦、ワンパンマン、チェンソーマン、スパイファミリー、デスノート、その他多数

###### 特徴

- American accentではっきりしゃべっているので、速いが聞き取りやすいほう。
- リアクション密度が高くて、アニメを見ながらでも常に何かしゃべっている。
- Fワード多め。
- シンプルにめちゃくちゃ笑える。
- チェンソーマン好きが高じてチェンソーを購入&rarr;なぜかチェンソーでキーボードを破壊する。
- 進撃好きが高じて地下室のカギのタトゥーを入れる。
- 鬼滅のチュン太郎が好きすぎて、他のアニメで雀が登場するたびにハイになっている。なお、チェンソーマンでパワーが雀を食べるシーンで発狂。
- 元カノを超嫌っている。
- アニメにハマってから日本・日本人を崇拝している。

### Animaechan

https://www.youtube.com/@Animaechan

**主なアニメ:** 進撃の巨人、鬼滅の刃、呪術廻戦、ナルト、ワンピース、チェンソーマン、スパイファミリー、その他多数

###### 特徴

- American accent寄りだけど、"t"をはっきり発音するなど、日本人にとってはだいぶ聞き取りやすい話し方をする。ごくたまにAfrican accentが入る。
- 1話見終えたあとに、同じくらいの時間をかけて感想・レビューをしてくれる。
- デリケートな問題（人種差別・性差別など）に対して、**自身の意見を動画で論じる場面が所々ある**。
- 可愛い。
- プライベートの話もよくする。
- 日本語勉強中で、たまにキャラクターのセリフを日本語で復唱する（可愛い）。

### Michael Angelo

https://www.youtube.com/@MichaelAngeloMAN

**主なアニメ:** 進撃の巨人、鬼滅の刃、東京リベンジャーズ、僕のヒーローアカデミア、その他多数

###### 特徴

- どこの訛りだろう？普通に聞き取りやすいです。
- イケボ。
- ちょいちょいテンション上がってマシンガントークになる。
- 感情移入しすぎて過呼吸になりかけている。知っている中で一番リアクションが強烈。
- 好きなセリフを日本語で暗記する。

### AutoSave

https://www.youtube.com/@AutoSaveFamily

**主なアニメ:** 進撃の巨人、デスノート、かぐや様は告らせたい、ハイキュー!!、その他多数

###### 特徴

- American accent。
- アニメ視聴中の発言は少なめだが、見終えた後に2人で**かなり深いところまで議論**する。特に進撃の巨人は本気で視聴していて、1話分の動画で80分超える場合も。英語学習には非常に向いていると思います。
- 考えを整理しながら話す場面が多いので、あまり早口ではない。
- モンスターを常飲してて少し心配。

### Carlie & Ange

https://www.youtube.com/@CarlieAndAnge

**主なアニメ:** 進撃の巨人、鬼滅の刃、呪術廻戦、スパイファミリー

###### 特徴

- 強めのオーストラリア訛り。
- 2人で楽しんでいる感が伝わってくる。**「会話」という感じの英語**にも触れられる。
- 視聴中もどちらかは一言二言発している。お手本のようなリアクション動画。
- Ange（男の方）が「この子好きだわ～」て言ってはCarlie（女の方）に睨まれる。

### OtakuMai

https://www.youtube.com/@OtakuMai

**主なアニメ:** モブサイコ100、スパイファミリー、進撃の巨人、不滅のあなたへ、その他多数

###### 特徴

- **かなり早口**。子音が曖昧なことが多い。聞き取り難易度高め。
- 各動画の進行がとてもスムーズ（空白の時間が少ない）。
- アニメの内容をしっかりと理解し、視聴後にキャラごと、シーンごとのレビューを話す。アニメがちゃんと好きという感じ。
- ちゃんと推しを作る。

### G.O.T. Games

https://www.youtube.com/@GOTGames

**主なアニメ:** 進撃の巨人

- British accent。
- 要所要所で視聴を一時停止して感想を述べるスタイル。
- 常にテンション高め。

# 最後に

楽しく英語を勉強していきましょう！
IPアドレスとは何か？（シンプルまとめ）

# 目次
- [IPアドレスとは](#ipアドレスとは)
- [IPアドレスの種類](#ipアドレスの種類)
    - [グローバルIPアドレス](#グローバルipアドレス)
    - [プライベートIPアドレス](#プライベートipアドレス)
- [グローバルIPアドレスとプライベートIPアドレスの関係性](#グローバルipアドレスとプライベートipアドレスの関係性)
- [IPアドレスから個人情報は漏洩する？](#ipアドレスから個人情報は漏洩する？)
- [その他](#その他)
- [参照](#参照)


# IPアドレスとは
- スマホやPC、ルーターなどに割り当てられる**インターネット上の住所**。
- メールやデータの送信先・受信先を識別しなければならないが、その**識別にIPアドレスが使われる**。


# IPアドレスの種類
- グローバルIPアドレス
- プライベートIPアドレス

## グローバルIPアドレス
- インターネットに接続する際に割り振られるアドレス。
- 全世界で通用するアドレス。
- 世界にただ一つのアドレス。
- XXX.XXX.XXX.XXXのように0〜255の数字4組で作られる。

## プライベートIPアドレス
- ローカルIPアドレスとも呼ばれる。
- 自宅や会社など**特定のネットワークの範囲内(ローカルネットワーク内)** で用いられるIPアドレスのこと。
- インターネットに直接接続するわけではない機器に割り当てるIPアドレス。
- プライベートIPアドレスではほとんどの場合、「192.168.x.x」が使われる。


# グローバルIPアドレスとプライベートIPアドレスの関係性
![](https://storage.googleapis.com/zenn-user-upload/fb20a7afca14-20221210.png)

- グローバルIPアドレスが割り振られるのはWi-Fiルーター。そこに接続するスマホやPCなどにはプライベートIPアドレスが設定される。これで各機器はルーターを介してインターネットに接続可能になる。
- 各機器はプライベートIPアドレスを経由し、グローバルIPアドレスを持つルーターを通してインターネットに接続している。


# IPアドレスから個人情報は漏洩する？
- IPアドレスから個人情報が漏洩することはない。
- IPアドレスを第三者に知られても大きなリスクはない。
    - そもそもIPアドレスは公開情報である。


# その他
- 基本的には、Wi-Fi（無線LAN）に接続しているスマホにはローカルIPアドレスが割り当てられ、モバイルデータ通信を行っているスマホにはグローバルIPアドレスが割り当てられる。


# 参照
https://time-space.kddi.com/ict-keywords/20200930/2984
https://it-biz.online/it-skills/global_vs_private/
プリザンターに入力した電話番号を使って電話をかける

本記事は [OSSのノーコード・ローコード開発ツール「プリザンター」 Advent Calendar 2022](https://qiita.com/advent-calendar/2022/pleasanter) 11日目の記事です。

# はじめに
[プリザンター](https://pleasanter.org) に入力した電話番号をtel:をつけたリンクにすることで、クリックやタップで電話をかけられるようにします。プリザンターのアンカー機能を使用します。

## 電話番号項目の設定
「テーブルの管理」→「エディタ」→「電話番号項目を選択」→「詳細設定」とクリックします。下記の画面が表示されますので、下記の設定を行います。

1. スタイル：ワイド（見やすさ向上のため）
1. アンカー：オン
1. アンカー書式：tel:{Value}

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78230/11e8888c-72d6-7cca-424d-71bac1bcefbc.png)

## 画面で確認
電話番号項目に電話番号を入力すると、リンクとなりこれをクリックすることでデバイスに接続された電話機から電話をかけることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78230/0dbd6ef5-5322-6974-4014-088fc2d867c2.png)


## 開発者ツールで確認
Chromeブラウザで電話番号の部分を右クリックして検証をクリックすると、開発者ツールが開きリンク先を示すのhref属性が確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78230/511bbb02-7533-f299-0ae9-2011b25551fc.png)

## その他
アンカー機能はURLの一部を入力した文字列にする機能です。
https://pleasanter.org/manual/table-management-anchor
AWS Copilot CLI を用いて ECS の機密データを SSM に一括設定

## 概要

AWS Copilot CLI を用いて ECS を構築していた場合、
ローカル環境からコマンドを実行するだけで、AWS System Manager（SSM） のパラメータストア（SecureString）に環境変数等の機密データを一括で設定できるので、やり方をご紹介します。

## 事前準備

※ ローカル環境は Mac OS で AWS で IAM アカウント作成済み（ECS 操作権限あり）であることが前提です。

#### AWS Copilot CLI のインストール

以下のコマンドで AWS Copilot CLI をインストールします。

```
$ brew install aws/tap/copilot-cli
```

#### プロファイル設定

.aws/credentials に以下を追記する。

```
[sample]
aws_access_key_id =
aws_secret_access_key =
```

※ aws_access_key_id と aws_secret_access_key は IAM でアカウント単位で作成した値を入力ください。`[]`内は任意の名前を入力ください。

## 手順

#### 設定ファイルの作成

secrets.yaml（ファイル名は任意）に以下のような形式で記述します。
今回は staging 環境と production 環境の DB の情報を一括で設定します。

```
DB_USERNAME:
  staging: hoge
  production: fuga
DB_PASSWORD:
  staging: password
  production: password
```

#### コマンドを実行

Copilot で`my-app`というアプリケーションを作っていた場合、
設定ファイルが配置してあるディレクトリで以下のコマンドを実行すると、パラメータを一括で設定することが可能です。

```
$ AWS_PROFILE=sample copilot secret init --app my-app --cli-input-yaml secrets.yaml
```

上記を実行すると、SSM パラメータストアでは以下のようなパスで保存されます。
`/copilot/my-app/{環境名}/secrets/{変数名}`

Service の Manifest ファイルで呼び出す場合は以下のように記述します。

```
environments:
    staging:
      secrets:
        DB_USERNAME: /copilot/my-app/staging/secrets/db_username
        DB_PASSWORD: /copilot/my-app/staging/secrets/db_password
    production:
      secrets:
        DB_USERNAME: /copilot/my-app/production/secrets/db_username
        DB_PASSWORD: /copilot/my-app/production/secrets/db_password
```

## おわりに

Copilot コマンドを用いることで、AWS のマネジメントコンソールで 1 パラメータずつ入力しなくて良いので、手間が省けます。また、同じ設定でコマンドを実行すると値を上書きしてくれるので、更新も同じコマンドでできます。本記事がお役に立てば幸いです。
Flutterで新規プロジェクトを作成した際のサンプルコードのコメントを一括で消す方法

## Android Studioの場合


新規でプロジェクトを作成すると以下のようにサンプルコードが表示されるかと思います。
![スクリーンショット 2022-12-05 15.11.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1248189/c433b0fd-af90-3008-8a62-64d0c9f78ebb.png)


この状態から
①command+rを押し、文字の置換を行うテキストボックスを表示させます。
![スクリーンショット 2022-12-05 15.12.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1248189/e03ff8fb-2200-e6af-dbae-6068c18b9f54.png)

②「//.* 」を打ち込んで、テキストボックスの右側にある「.*」をクリック。
（画像のようにコメント群が緑色で選択された状態になる）
画像にある「Replace All」を押します。
![スクリーンショット 2022-12-05 15.15.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1248189/4f6631c3-b6a6-bc3e-a600-394ce7d412e2.png)



これでコメントを一括で全削除できたかと思います！
![スクリーンショット 2022-12-05 15.16.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1248189/e51627b8-1de2-5a48-7954-c613f03b3f66.png)


## Visual Studio Codeの場合

新規でプロジェクトを作成すると以下のようにサンプルコードが表示されるかと思います。
![スクリーンショット 2022-12-05 14.44.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1248189/5ff4690a-e60d-02dc-ef94-d7ea0e68b9c8.png)


この状態から
①command+FでFinderを表示させます。
![スクリーンショット 2022-12-05 14.46.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1248189/1faed67e-3f1b-abd1-d7ff-fe50e1751437.png)

②「//.* 」を打ち込んで、テキストボックスの右側にある「.*」をクリック。
（画像のようにコメント群がオレンジ色で選択された状態になる）
「＞」を押しドロップダウンしたら、画像にある「全てを置換」を押します。
![スクリーンショット 2022-12-05 14.56.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1248189/3d2d8cf1-82e3-7e98-e758-c06b2588f364.png)


これでコメントを一括で全削除できたかと思います！
![スクリーンショット 2022-12-05 14.58.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1248189/fd581510-2dbc-b69d-95a5-3db527d1a555.png)


いいなと思った方がいらっしゃっいましたら、新規にプロジェクトを作成した際は、ぜひ活用してみてください！
異常終了時に吐かれた core ファイルから procstat を使ってプロセス情報を調べる

## 残された core から手がかりを探る

　プロセスが何らかの理由で異常な状態になった場合、core ファイルを出力して終了してしまうことがあります。
　core にはプロセス終了直前のメモリ状態などが記録されていて、デバッガ(FreeBSD ならば lldb)などを使えばどの関数でエラーが発生したかなど調べられます。しかしデバッガの操作はそれなりに面倒で欲しい情報が簡単にはわからない場合も多いです。
　そこで procstat コマンドを使えば、終了直前のメモリ使用状況、
なんのファイルを開いていたか、環境変数がちゃんと切り替わっているかなど簡単に調べることができます。
　また、procstat は core ファイルでなく現在動いているプロセスも、プロセスID指定で調べることができます。

　FreeBSD 独自だからかあまり存在が認知されていない感じがする（気のせい？）なので紹介してみます。

## 基本

　procstat コマンドは、なんの情報が欲しいかを指定するサブコマンドと、情報がほしいプロセスの pid（現在実行中のプロセス情報の取得） または coreファイル(すでに終了しているプロセスの情報の取得)をコマンドライン引数で指定して実行すると、その結果を表示します。

　サブコマンドを指定しない場合はサブコマンド basic（基本情報）を指定したとみなして実行されます。

```
procstat (pid/core ファイル)
or
procstat basic (pid/core ファイル)
```

　basic で得られる情報は実行時の pid/ppid/実行ユーザー名などです。

```
$ procstat kstars.core
  PID  PPID  PGID   SID  TSID THR LOGIN    WCHAN     EMUL          COMM        
 2030  1855  2030  1855  1855  13 suzuki   -         FreeBSD ELF64 kstars      
```
## 開いてたファイル

　設定ミスで変な場所のファイルを開いてた、なんてミスが起きてないか確認するには、サブコマンド file (または -f オプション)でなんのファイルを開いていたかをチェックします。
　実行すると終了直前に開いていたファイルの一覧が得られます。

```
$ procstat file kstars.core

  PID COMM                FD T V FLAGS    REF  OFFSET PRO NAME        
 2030 kstars            text v r r-------   -       - -   /usr/local/bin/kstars
 2030 kstars            ctty v c rw------   -       - -   /dev/pts/0        
 2030 kstars             cwd v d r-------   -       - -   /usr/home/hige    
 2030 kstars            root v d r-------   -       - -   /         
... (略) 

```
 
## コマンドライン引数

　どんなコマンドラインで実行されたかは、pargs サブコマンドを指定します。

```
$ procstat pargs main.core 
58384:  main
argv[0]: ./main
argv[1]: -x
argv[2]: -y
```
　main というコマンドを引数 -x と -y を指定して実行したことがわかります。

## 実行時の環境変数

　環境変数でプロセスの処理が切り替わるというパターンは結構あるわけですが、実際に環境変数が思ったとおりにプロセスに渡っているか怪しい場合があります。
　そんな場合はサブコマンド penv を指定して実行すると、実行時の環境変数一覧が得られます。

```
$ procstat penv kstars.core
2030:  kstars
envp[0]: PAGER=more
envp[1]: VENDOR=amd
envp[2]: LANG=ja_JP.UTF-8
envp[3]: MM_CHARSET=UTF-8
envp[4]: XDG_CURRENT_DESKTOP=LXQt
envp[5]: GTK_CSD=0
envp[6]: QT_IM_MODULE=ibus
... (略)
```
## 実行コマンドのパス名

　サブコマンド binary (または -bオプション)を指定すると、実行したコマンドのファイルパスがわかります。複数の場所にコマンドがインストールされいる場合、どのパスのコマンドでエラーが起きたかも知りたい情報です。

```
$ procstat binary kstars.core 
  PID COMM                OSREL PATH
 2030 kstars            1400073 /usr/local/bin/kstars
```

## 詳しくは man で

　他にもスレッド情報取得など、サブコマンドがいろいろ用意されています。
　より詳細な使い方は [man procstat](https://www.freebsd.org/cgi/man.cgi?query=procstat&apropos=0&sektion=0&manpath=FreeBSD+13.1-RELEASE&arch=default&format=html "man procstat")を見ながら試してみてください。
GitでPullした際に「Enter passphrase for key」が毎回聞かれる時の対応

# はじめに
<!-- 発端や概要を記載 -->
たまにGitでfetchやpullした時、「Enter passphrase for key」を毎回聞かれるのでそれの解決方法の忘却録です。

<!-- 問題点 -->
# 問題点
使用しているid_rsaのパスワードを入れれば解決するが、毎回入れるのだるい問題
```
Enter passphrase for key '/Users/*****/.ssh/id_rsa': 
```

<!-- 解決方法 -->
# 解決方法
ssh-agentに登録すること

```
// 登録していないと下記になっている
localhost ~ : ssh-add -l
The agent has no identities.
----
// 登録する
localhost: ~ $ ssh-add .ssh/id_rsa
Enter passphrase for .ssh/id_rsa: // パスワード入れる
Identity added: .ssh/id_rsa (.ssh/id_rsa)

// 登録確認
localhost: ~ $ ssh-add -l
2048 SHA256:7ZAVVzW8rtyGtTtbHT3JuNWxadghk+u9fN5qwfghEbgs /Users/*****/.ssh/id_rsa (RSA)
```

<a id="#reference"></a>
# 参考文献
https://docs.github.com/ja/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent
【AdMob】-[UIView setAdUnitID:]: unrecognized selector sent to instanceの解決方法

# はじめに
個人開発で広告の表示をするときに出会ったクラッシュの解決方法をメモ的に残しておきます。

# 環境
- MacBook Pro (13-inch, 2020, Two Thunderbolt 3 ports) intel mac
- macOS Monterey 12.6
- Xcode 14.1

# 症状
- 広告が表示される画面とクラッシュする画面がある

# エラーの内容
![スクリーンショット 2022-12-10 13.23.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2644705/bd18df9c-91a9-b834-adf1-6d666d03f1e9.png)

# 解決方法
Custom Classを設定するときに「inherit Module From Target」のチェックを外して、moduleが「none」になるようにしてください。これで表示されるはずです。
これでうまくいかないよーという人はCustomeClassに「GADBannerView」を設定した後にIBOutletを繋げているか確認してみてください！
![スクリーンショット 2022-12-10 13.28.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2644705/9bf10aac-126b-5339-8b78-b10580f026fd.png)

おわり！
該当するファイル名を検索し、中身の文字列を検索→置換する方法

### find + sed で一斉置換
- ファイル名に.txtを含むファイルを検索し、中身のhogeをHOGEに書き換える。
```
find . -type f -name "*.txt" -print0 | xargs -0 sed -i -e "s/hoge/HOGE/"
```
おわり
[Swift] 配列の使い方

# 目次
-  **配列の書き方**
-  **空の配列を作成**
-  **配列へのアクセス**
-  **要素の検索**
-  **要素の追加**
-  **要素の削除**
-  **要素のソート**
-  **要素の絞り込み**

##  配列の書き方

配列の宣言には [ ] 記法を使うことができます。

配列を構成する1つ1つの値を「,」で区切って定義します。
```
let numbers: [Int] = [3, 6, 123, 11, 45]  //複数のIntを配列として格納している値
```



## 空の配列を作成
```
var emptyString: [String] = []  //String型の空配列
var emptyInt: [Int] = []        //Int型の空配列
```
## 配列へアクセス
```
var values = ["A", "B", "C", "D", "E"]
 
    print(values[0]) // "A" が表示される
 
    print(values[3]) // "D" が表示される
 
    values[4] = "X"  // 値の置き換え
 
    print(values)    // ["A", "B", "C", "D", "X"] が表示される
```
#### 配列の全ての要素にアクセス

配列の全ての要素にアクセスするには、次のようにfor-inループを使用して繰り返し処理します。

 ```
    let fruits = ["apple", "orange", "banana"]  // 文字列の配列
 
    for value in fruits {
        print("I like \(value).")
    }
 
    // I like apple.
    // I like orange.
    // I like banana.
```

## 要素数を調べる
countプロパティで配列の要素数を調べられます。

 
    let oddNumbers = [1,3,5,7,9]
 
    print(oddNumbers.count)    // 要素数の5が表示される
 
## 要素の追加
append() メソッドで配列の最後に要素を追加できます。

 
    var values = ["A", "B", "C"]
 
    values.append("D") // 配列の最後に追加
 
    print(values)      // ["A", "B", "C", "D"]
 
## 要素の削除
#### 任意の要素を削除
任意の要素を削除する場合は、remove(at:)メソッドを使います。

 
    var values = ["A", "B", "C"]
 
    values.remove(at: 1)  // 要素番号１を削除
 
    print(values)         // ["A", "C"]
 
#### 全ての要素を削除
 removeAll()メソッドで全ての要素を削除します。


 
    var values = ["A", "B", "C"]
 
    values.removeAll()  // 全ての要素を削除
 
    print(values)       // [] （空の配列）

## 配列のソート(sorted)
配列をソートするにはsortedを使用します。

sortedは以下のように記述します。
#### 書き方（昇順）
```
配列.sorted {$0 < $1}
```
#### 書き方（降順）
```
配列.sorted {$0 > $1}
```
## 要素の絞り込み
filterメソッドで、条件にマッチした要素のみに絞り込む事ができます。
条件はクロージャーで定義し、見つからない場合は空の配列を返します。

```
let fruits = ["apple", "orange", "banana"]  // 文字列の配列
 
///条件にあう要素だけ抽出する（文字数が5文字よりも多いもの）
let newArray = fruits.filter{ $0.count > 5}
 
print(newArray)     // ["orange", "banana"]
 ```
特定のディレクトリやファイルを除いて、一括してコピーする方法

### 特定のディレクトリやファイルを除いて、dir1以下をサブディレクトリ含めてdir2に一括してコピーする
- まずは実行せずに確認だけ (オプションのnを忘れずに)
```
rsync -ahvn ./dir1/ ./dir2/ --exclude 'XXX' --exclude 'YYY' --exclude 'ZZZ'
```
- 問題なければ実行する (オプションのnを消す)
```
rsync -ahv ./dir1/ ./dir2/ --exclude 'XXX' --exclude 'YYY' --exclude 'ZZZ'
カレントディレクトリ以下にあるファイルを検索して一括コピーする方法

### ファイルの拡張子を指定して検索し、一括コピーする
- カレントディレクトリ以下にあるJPGファイルを検索して、./tempにコピーする例
```
find . -name "*.jpg" | xargs -I {} cp {} ./temp
```
おわり
Linux上でのユーザ作成・削除・Sudo権限付与の方法

### ユーザ管理
Linux上でのユーザ作成・削除・Sudo権限付与の方法のメモ。

- これで自動的に/home/ユーザディレクトリを作ってくれる
```
sudo adduser ユーザ名
```

- (必要あれば) ユーザにsudo権限を付与する
```
sudo usermod -aG sudo ユーザ名
```

- 不要なユーザを削除する
```
sudo userdel -r ユーザ名
```
- ユーザの一覧を確認する
```
cat /etc/passwd
```

- 私は誰？
```
whoami
```

- 現在ログインしているユーザの確認
```
who # または
users
```
ただの文系大学生が学生エンジニアになるためにやったことの話

# はじめに
この記事は[株式会社LabBase テックカレンダー Advent Calendar 2022](https://qiita.com/advent-calendar/2022/labbase) 10日目の記事です。

こんにちは、[株式会社LabBase](https://labbase.co.jp/)でインターンをしているf426kです。
初めてのQiita投稿＆初めてのアドベントカレンダー参加になります。
私は今年の10月からLabBaseにjoinしてReact/TypeScriptでフロントエンド開発をしています。

私は現在大学生で来年から社会人になるのですが、タイトル通り文系の学部からエンジニアになりました。今回はプログラミングにも情報系にも何も詳しくなかった私がスクールに通わずエンジニアになるためにどのようなことをしたのか書いてみようと思います。

まだプログラミングや情報系の知識はほとんどないけど、これからエンジニアを目指したいという方の参考になれば嬉しいです。

# プログラミングを学ぶ上で心掛けたこと
プログラミングと言っても本当にいろんな種類があって何を目指してどのようなことから学び始めればいいかわからないと思います。
その上どの分野を学ぶにしても情報量が多すぎてパニックになりやすいです。

情報量の多さで挫折してしまうのは勿体無いので、以下のことを意識していました。
## 1. 少しでもいいから毎日学習に取り組む
1日で一気に詰め込んでもうまくいかないので毎日短時間でもいいのでコツコツと学習をすることが大切です。
## 2. 暗記力よりも検索力を身につける
プログラミングの学習では単語や関数の書き方は検索すればわかることなので、どういうことができるのかを覚えておけば十分です。プログラミングの学習では暗記をすることよりも検索する力を身につけることの方が重要です。
## 3. エラーが起きた時は落ち着いて見直す、調べる
プログラミングの学習にエラーはつきものです。初心者じゃなくてもエラーは起きるものなので、焦らずに対処することが重要です。エラーが起きたときには自分の書いたものを見直して、それでも分からなければ調べて原因を把握できるようになることが解決への第一歩です。


##### 学習の中で計画通りにいかず焦ることもあると思いますが、基礎を理解することが大切なのでゆっくりとやっていきましょう！


# プログラミング学習で使ったサービス
ここでは私がIT知識がほとんどない頃に学習をするのに使ったサービスを紹介します。
人それぞれにあった学習方法があるので、いろいろなサービスを利用して自分にあう学習方法を探してみてください。
### [progate](https://prog-8.com/)
プログラミングの学習の一番最初に使ったのがprogateです。プログラミングがどういうものなのかを知るのにぴったりです。また、progateでは学習前に必要な環境構築をせずに学習をスタートすることができるので情報系の知識がほとんどない人がプログラミングに触れるのにはちょうどいいと思います。

### [ドットインストール](https://dotinstall.com/)
ドットインストールではprogateよりも実践的な内容を学ぶことができます。短い動画で学習をするので毎日少しずつ勉強をするのに向いています。さまざまなプログラミング言語だけではなく、AWSやgitなどの講座もあり理解を深められます。

### [Udemy](https://www.udemy.com/)
Udemyではさまざまな講座を勉強することができます。講座がたくさんあるので自分の興味のあるプログラミング言語の講座の中から評価が高くて購入者が多い、最終更新が１年以内の講座を受講してみてください。講座の中でアプリを作成し、見よう見まねだけではなくどのようなことをおこなっているのか理解したり、さらに追加機能をつけるなどのアレンジを自分で考えながら行ったりすることでより実務に近い学習ができます。

### youtube
youtubeにもプログラミングの学習ができる動画をUPしてくれているチャンネルがいくつかあります。無料なので更新頻度が遅かったり、内容に当たり外れがあったりはしますが手軽に学習する方法の一つではあるので、興味のある内容の動画を見つけた際はぜひやってみてください。

# 基礎を固めた後にやったこと
上記のサービスを利用して基礎を固めた後、更に実践的なことを学びたいと思いました。
そこで私が取り組んだのはインターンです。wantedlyなどで調べるとたくさんの企業がインターン生の募集をおこなっているので、力試しと更に実践的なことを学ぶのにインターンは最適だと思います。現在インターンをしているLabBaseにもwantedlyで出会いました。

現在３社での長期インターンを経験していますが、やはり1人での学習では学ぶことができない実際にサービスとして使われているコードを読んだり触ったりして理解し、実際にプロダクトのコードを書きながら学ぶというのがプログラミングが一番身につく方法だと思っています。また、インターンとして入ることでその会社で実際にエンジニアとして働いている方に直接聞くことができたり、書いたコードをレビューしてもらえるというのは1人で学習しているときにはできないことでインターンを行う大きなメリットです。
時間のある大学生だからこそできることなので、責任を持って実務に取り組んでみたいと思う方はぜひチャレンジしてみてください。

# さいごに
「エンジニアは常に勉強しなければいけない」とよく言われるのですが、勉強しなきゃいけないと思うとしたくなくなるものです。
勉強をする中でいろんな人から、「この本を読むといい」、「この動画を見るといい」などたくさんのアドバイスをもらうと思います。同年代で自分よりもできる人に出会って焦ることもあると思います。

でもプログラミングはすぐに身につくものではありません。
焦らず、自分にあった学習法で、自分のペースで、学習に取り組んでみてください。

最後まで読んでいただきありがとうございました。
react-final-form から react-hook-form への移行

株式会社エイチームコマーステックのkazzです。

タイトルの通り、今回は React 用のフォームライブラリである `react-final-form` から `react-hook-form` への移行について、開発での実体験を交えながら軽めにお話しできたらと思います。

## なぜ移行するのか

フォームの開発をしやすくするために `react-final-form` を使って開発をしていましたが、1年半ほど改修を繰り返す中で、 `react-final-form` の以下の点が目につくようになりました。

- 不具合が多く、かつ中々対応されない
- 直近のcommit・リリースが少ない
- 比較的、ドキュメントが不充実

要するに、メンテが不十分であることが要因で色々と不都合が起こるようになってきました。そして、大きめの改修をキッカケに、 `react-hook-form` への移行を決意しました。

## hook-form の選定

`hook-form` でシステムに必要な機能要件も満たしていそうであり、かつ実行パフォーマンスに関してもバンドルサイズもトータルで僅かに減で、非制御コンポーネントにより再レンダリングを抑えやすくなったため、パフォーマンス改善も見込めました。

|                           |  react-final-form + final-form  |  react-hook-form  | (formik) |
| ----                      | ----                            | ----              | ---  |
|  bundled size (minified)  |  25.8kB                         |  25.1kB           | 44.3kB |
|  control                  |   制御コンポーネント               | 非制御コンポーネント | 制御コンポーネント |
|  メンテナンス                  |  1年で4commits                | たくさん | ほぼなし |
|  ドキュメント（主観）                  |  見ずらい          | 見やすい | 見やすい |


## 移行作業

### 1. コンポーネントの作り直し

共通化しているコンポーネント・処理が `final-form` にがっつり依存していることが判明。該当のフォームだけを順々に直していく想定でいましたが、共通部分からの作り直しが必要になってしまいました。

このフェーズでは、新たなディレクトリへ `hook-form` でも使えるコンポーネントの実装を行いました。合わせて、formとUIの疎結合化も進めてます。

これを、

```tsx:共通コンポーネント
// こんな感じで、外枠から　final-form に依存している
import { Field } from 'react-final-form';
...
const InputText = () => {
    return <Field>...</Field>
}
```

このようにUIとformに分けて実装することで、処理の見通しも良くなり、共通化部分とformが疎結合になりました。

```tsx:共通コンポーネント
import { useController } from 'react-hook-form';

// 純粋なUIコンポーネント
const InputText = ({onChange, onBlur, ref, ...}) => {
    return <input onChange={onChange} onBlur={onBlur} ref={ref} />
}

// formに関わる処理をラップしたコンポーネント
const InputTextForHookForm = ({control, registerName, ...rest}: {control: Control, control: string ...}) => {
    const { field } = useController({ control, name: registerName});
    return <InputText {...field} />
}
```

`hook-form` は イベントハンドラーやrefを正しく末端まで引き継いであげればライブラリの機能をしっかり使えるので、その点はこのformとUIの疎結合化はしやすかったかなと思います。

### 2. form部分の作り替え

これは一律でやるもの予定はなく、改修のたびに置き換えていくよう進めてます。

非制御コンポーネントの扱いは最初は慣れませんでしたが、 `useWatch` のようなAPIを活用していくことで、欲しい部分に再レンダリングを挟みつつレンダリングの回数を抑える実装ができるので使い勝手は良いです。

制御・非制御コンポーネントの違いを先に理解しておくのはMUSTかと思います。

### 3. 後処理

置き換えを進める中で不要になり次第既存のコンポーネントを消していったり、ライブラリ自体の削除をします。`final-form` はそれなりにサイズも大きいので、忘れず行います。

## 最後に

不具合やドキュメントの見づらさから、開発体験を大きく落としている部分だと感じながら開発していたので、移行作業ができていることは嬉しく思います。

最近は、React も Next.js もどんどん新機能が出てくる中で、メンテ不足により機能追従がされなくなる不安もあったため、今後のためを思い移行を進めました。

今回は全体の流れをさらっと説明しましたが、各項目でここをもっと具体的に知りたいなど要望があれば、別記事で出そうかなと思います。

次回アドベントカレンダーの投稿は、@o93 さんの 「誤差と あいまいさと 不確かさと」 です！
拡張ドメインを有効にし、必要な更新を行うのに役立つ追加のヘルプ トピック。


+ [質問と回答](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000LFYQrSAP)

独自のドメインを所有しているという場合、Salesforce URL のサブドメインを指定できる [私のドメイン]機能を使用しているのかどうかはわかりません([私のドメイン] ログイン URL の形式はhttps:/ /MyDomainName.my.salesforce.com )、またはExperience Cloud サイトまたは Salesforce サイトを提供するhttps://www.example.comなどのカスタムドメイン。

いずれにせよ、拡張ドメインは必要であり、影響が大きいため、Salesforce がドメインをリリースする前に、サンドボックスでテストしてから本番環境にリリースすることを強くお勧めします。

より詳しい情報：
拡張ドメインは、私のドメイン機能の最新バージョンです。これらは最新のブラウザ要件を満たしているため、すべての組織で必要です。

拡張ドメインをリリースすると、Salesforce が組織用にホストするすべての URL で組織の [私のドメイン] 名が使用されます。この機能では、最新のセキュリティ基準に合わせてドメイン サフィックス ([マイ ドメイン] 名の後の部分) も変更されます。インスタンス名がないため、拡張された [私のドメイン] URL はユーザが覚えやすく、組織が別の Salesforce インスタンスに移動しても変更されません。拡張ドメインで変更される URL のリストについては、Salesforce ヘルプの[「 拡張ドメインを有効にした場合の私のドメインの URL 形式の変更」](https://help.salesforce.com/s/articleView?id=sf.domain_name_url_format_changes_enable_enhanced.htm&type=5)を参照してください。

Salesforce が拡張ドメインをいつリリースして適用するか、および自動リリースをオプトアウトして機能を無効にするための各リリースのオプションについては、Salesforce ヘルプの[「拡張ドメインのタイムライン」](https://help.salesforce.com/s/articleView?id=sf.domain_name_enhanced_timeline.htm&type=5)を参照してください。

拡張ドメインを有効にし、必要な更新を行うのに役立つ追加のヘルプ トピック。 

+ [私のドメインの変更の計画](https://help.salesforce.com/s/articleView?id=sf.domain_name_plan.htm&type=5)- 拡張ドメインの展開に使用できるチェックリストが含まれています (チェックリストには多くのものが含まれています。おそらく、自分に適用される手順に絞り込む必要があります)。
+ [拡張ドメインに関する考慮事項](https://help.salesforce.com/s/articleView?id=sf.domain_name_enhanced_considerations.htm&type=5)
+ [拡張ドメインを有効にする](https://help.salesforce.com/s/articleView?id=sf.domain_name_enhanced_enable.htm&type=5)
+ [私のドメインのログイン URL の変更中にログイン アクセスを保持する](https://help.salesforce.com/s/articleView?id=sf.domain_name_login_change_preserve_access.htm&type=5)
+ [私のドメインの変更を展開する](https://help.salesforce.com/s/articleView?id=sf.domain_name_testing_and_rollout.htm&type=5)
+ [私のドメインの変更後に認証を更新する](https://help.salesforce.com/s/articleView?id=sf.domain_name_auth_update.htm&type=5)
+ [私のドメインの変更に合わせて組織を更新する](https://help.salesforce.com/s/articleView?id=sf.domain_name_guidelines.htm&type=5)
+ [私のドメインの変更をテストする](https://help.salesforce.com/s/articleView?id=sf.domain_name_test.htm&type=5)

組織で拡張ドメインが有効になっているかどうかを判断するには、Salesforce ヘルプの[「拡張ドメインが有効になっているかどうかを判断する」](https://help.salesforce.com/s/articleView?id=sf.domain_name_enhanced_prerequisites.htm&type=5)を参照してください。
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrunへの対処

# xcrun: error: invalid active developer path...によりgitコマンドが実行できなくなってしまった

## 要因

- macOSをMontereyからVenturaにアプデしたから（ググってると似たような内容が多いですね・・・）

## 対処法

### 下記コマンドを実行すると解決されると思います。

```terminal
xcode-select --install

```

### インストールが終わると下図のような画面がでて完了します
だいたい5分少々くらで完了しますかね。
最初40時間って表示が出て焦りましたが、意外と早かったです。
![スクリーンショット 2022-12-10 12.45.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1103633/83c98a6c-42a7-1943-eebd-e2edc0d33576.png)
pythonのenumerateを使用して、配列に格納したカラムのデータを一括で可視化する。

pythonのenumerateが、データを一括で可視化する際に見やすいコードを書くのに役に立ったためメモ

# 使用コード
```
# [~DISASTER_TWEETS]の~は否定演算子。[DISASTER_TWEETS==False]と同義

METAFEATURES = ['word_count', 'unique_word_count', 'stop_word_count', 'url_count', 'mean_word_length',
                'char_count', 'punctuation_count', 'hashtag_count', 'mention_count']

DISASTER_TWEETS = train_df['target']==1

fig,ax = plt.subplots(ncols=2, nrows=len(METAFEATURES), figsize=(20, 50), dpi=100)

for i, feature in enumerate(METAFEATURES):
    sns.distplot(train_df.loc[~DISASTER_TWEETS][feature], label='Not Disaster', ax=ax[i][0], kde=True, color='#ffb6c1')
    sns.distplot(train_df.loc[DISASTER_TWEETS][feature], label='Disaster', ax=ax[i][0], kde=True, color='#4169e1')
    
    sns.distplot(train_df[feature], label='Training', ax=ax[i][1])
    sns.distplot(test_df[feature], label='Test', ax=ax[i][1])
    
    for j in range(2):
        ax[i][j].set_xlabel('')
        ax[i][j].tick_params(axis='x', labelsize=12)
        ax[i][j].tick_params(axis='y', labelsize=12)
        ax[i][j].legend()
        
    ax[i][0].set_title(f'{feature} Target Distribution in Training Set', fontsize=13)
    ax[i][1].set_title(f'{feature} Training & Test Set Distribution', fontsize=13)
    
plt.show()
```
# 使用コードの解説

## 1)後程使用するデータを変数に格納して用意する

```
METAFEATURES = ['word_count', 'unique_word_count', 'stop_word_count', 'url_count', 'mean_word_length',
                'char_count', 'punctuation_count', 'hashtag_count', 'mention_count']

DISASTER_TWEETS = train_df['target']==1
```
* METAFEATURESに、データを可視化したいカラムの一覧を配列形式で格納する。
* DISASTER_TWEETSに、train_dfのtarget=1という情報を格納する。

※ちなみに、METAFEATURES変数に格納している名前のカラムには、下記の画像のように値が格納されている。
![スクリーンショット 2022-12-10 12.40.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/883573/93965d57-8e1a-c7eb-8e80-364db2efac93.png)


## 2)enumerateを使用して、配列に格納したカラムのデータをfor文の中のiとfeatureにループで代入していく。
```
for i, feature in enumerate(METAFEATURES):
    sns.distplot(train_df.loc[~DISASTER_TWEETS][feature], label='Not Disaster', ax=ax[i], kde=True, color='#ffb6c1')
    sns.distplot(train_df.loc[DISASTER_TWEETS][feature], label='Disaster', ax=ax[i], kde=True, color='#4169e1')
        
    ax[i].set_title(f'{feature} Target Distribution in Training Set', fontsize=13)
```
* `for i, feature enumerate(METAFEATURES)`で,`i`にインデックス番号、`feature`に要素をループで代入。
* `[~DISASTER_TWEETS]`の`~`は、否定演算子で`[DISASTER_TWEETS==False]`と同じ意味。
  └`train_df['target']==1`or`train_df['target']==0`を表現するために使用。

※イメージ図
![スクリーンショット 2022-12-10 10.38.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/883573/c1d2b9e5-b190-cd51-a49d-ddc561c2c6bd.png)
【CommonLisp】eq, eqlでの文字列比較は処理系によって結果が異なる

## eq

```common-lisp
(format t "~a~%" (eq "hoge" "hoge"))
```

### SBCL

```
T
```

https://ideone.com/uRIhXj

### CLISP

```
NIL
```

https://ideone.com/icYUaa

## eql

```common-lisp
(format t "~a~%" (eql "hoge" "hoge"))
```

### SBCL

```
T
```

https://ideone.com/mCH17l

### CLISP

```
NIL
```

https://ideone.com/znKOgT

## まとめ

文字列比較は
string= もしくは equal
を使おう
Laravel(APIモード)のControllerからModelのメソッドを呼び出したい

今までクエリをControllerに直接記述していましたが、Modelに移行することにしました。
Controllerでは極力指令を送るだけにして、可読性を上げることが目的です。

## 目次
- 現在の実装
- 実装したいこと
- ControllerからModelのメソッドを呼び出す方法（実装）←ここに結論あります
- 解説

それではやっていきます！
## 現在の実装
- ユーザーテーブル（`User`）
- お知らせテーブル（`Notificaton`）
- 既読管理の中間テーブル（`NotificationUser`）
が今回の主役です。
現在、ログイン時にお知らせを表示しており、表示した中に次回以降表示しないボタンを設置しています。
チェックして閉じると、中間テーブルにリクエストがPOSTされます。
次回お知らせを表示する際には、**NotificaitonControllerにクエリビルダを直接記述し**、表示制御を行っています。ここを改善するのが今回のテーマです。
※今回は中間テーブルを作成するための`migration`や`Model`の記述内容は割愛させていただきます🙇
## 実装したいこと
1. NotificationControllerではメソッドの呼び出しとレスポンスのみ担当させる
2. NotificationUserモデル（中間テーブルのモデル）でデータ取得のメソッドを作成
## ControllerからModelのメソッドを呼び出す方法（実装）
先に結論です。
NotificationController.php
```php
public function notify() {
    $notification = new NotificationUser();
    $notify_user = $notification->check_notify_user();
    $auth_user = $notification->auth_user();
         
    if(Auth::check()) {
	return response([ 'notifies' => $notify_user, 'user_id' => $auth_user, 200);
    }
}
```
NotificationUser.php
```php
// 表示するお知らせを取得
public function check_notify_user() {
// 実際にはもっと複雑なクエリを書いていますが、読みにくいので省略しています。
    $query = DB::table('notifications as n')
        ->leftJoin('notification_user as nu', function ($join) {
            $join->on('n.id', "=", 'nu.notification_id')
                 ->where('nu.user_id', "=", auth()->user()->id);
        })
        ->get();

    return $query;
}

// 認証ユーザーのID取得
public function auth_user() {
    return Auth::user()->id;
}
```
## 解説
### Modelについて
中間テーブルでメソッドを定義しました（理由は複数のコントローラーにメソッドを散りばめると可読性が下がると考えたため）。
`public function メソッド()` として、Controllerからよびだせるようにしています。
初歩的ですが、`return` を書いていなくて一瞬ハマってました。
`check_notify_user()` で表示するお知らせを取得しています。
`DB::` を使う際は`use Illuminate\Support\Facades\DB;` の記述が必須ですので注意してください。
`auth_user()` でリクエストしたユーザーを取得しています。
LaravelPassportを使用している方は、`use Illuminate\Support\Facades\Auth;` の記述が必要です。
### Controllerについて
`$notification = new NotificationUser();`でNotificationUserモデルをインスタンス化しています。
`$notify_user` と`$auth_user` でインスタンスからメソッドを取得しています。
あとはレスポンスの中に変数を入れてあげればOKです。
ひよこになるため日記〜1日目〜12月9日

# 今日したこと
日記1日目です。今日からコツコツとやっていきましょう！！
- Atcorderのbeginersの過去問（A問題、B問題、C問題）
- WEBアプリケーション作成に向けて！！

# AtcorderBeginners Contest 280のA問題、B問題に挑戦！！
友達から練習をするにはこの問題解くといいよとおすすめしてもらったので今現在の実力を測るために復習がてら解くことにしてみました。
## A問題
まず、恥ずかしながら「shit」+@でmacはバックオート出すんですね、、
この[記事](https://qiita.com/shizuma/items/8616bbe3ebe8ab0b6ca1)で知りました！恥ずかしながら今日知りました、、、、
では問題は[こちら](https://atcoder.jp/contests/abc280/tasks/abc280_a)！！

自分が書いたプログラムはこんな感じです！！
```
s = input().split()
count = 0
for _ in range(int(s[0])):
  moji = list(input())
  for i in range(int(s[1])):
    if '#'== moji[i]:
      count += 1
else:
  print(count)
```
他の人のコードを見ると１行目の代わりにmap関数を使っていました。
map関数を知らなかったので調べました！！

```
map(関数,イテレーター（リストやタプル))
```
という形でイテレータの変数を関数によって弄れるらしいです。
具体的にはint型に変えたいときなどに使うみたいです。
今回の１行目を変えるとしたらこんな感じで
```
s,w=map(int,input.split())
```
使えば良いみたいです！！
これでsとwにはint型の文字が代入されています。

他には
```
open(0)
```
関数を使っている人がいました。
https://qiita.com/kyuna/items/8ee8916c2f4e36321a1c#4-open0
これはこの記事を参考にしてください！！
すごく詳しく書いていました。

## B問題
問題は[こちら](https://atcoder.jp/contests/abc280/tasks/abc280_b)！！

そして自分が書いたプログラムが↓↓↓
```
s = int(input())
num = list(map(int,input().split()))
count = 0
list = []
for i in range(s):
    if i==0:
        count+=num[i]
        list.append(num[i])
    else:
        k = num[i]-count
        count += k
        list.append(k)
else:
    for i in range(s):
        print(list[i],end=' ')
```
A問題で学んだmap関数を使った。

print関数は改行が含まれる。
end を入れることにより、改行の代わりのものを出力。。
```
for i in range(s):
        print(list[i],end=' ')
```
以下の形で書き換えできるらしい。
```
print(*list)
```
これはアンパックをしているらしい。
よくわからないけど、勉強しなければ、、、


## C問題
C問題は[こちら](https://atcoder.jp/contests/abc280/tasks/abc280_c)
そして自分が書いたプログラムが↓↓↓
```
S = list(input())
T = list(input())
count = 1
for i in range(len(S)):
    if S[i] == T[i]:
        count += 1
    else:
        break
print(count)
```
他の人のプログラムを見たところここではcountを出力するのではなくiの値を出力すればいいのか！！
# Webアプリ作成に向けて

今回、とりあえず何か作ってみることが重要かなと思ったので、Udemyで作れるものを探します！！
ちょっと、最後適当になったけどこれからも頑張ります！！


# 宿題
- アンパックとは？？
Figmaのフレームで詰んだ話（アドレスバーの挿入方法）

# 初歩的なところで詰んだ
仕事上Figmaを使っているので大体の使い方は知っているものの0-1で作ったことがないので作ってみようとした矢先に積みました。
SafariでもChromeでもHeaderよりもさらに上の最上部にあるURLとか書いてあってタップすると検索欄に切り替わるあの”アドレスバー”をどのようにデザインするのかわからない・・・
どの　```Figmaでデザインを作ってみよう！```　系の記事やYoutubeにも記載がなかったので色んな記事読んだり動画見たり・・・でも書いてない！！
```figma アドレスバー```　って調べても出てこない・・・

前の記事で書いているui kitの存在を思い出して早速検索！！

# 解決（？）


```Figma Safari ui kit``` 　で調べると、

Safariのスマホ版、あったああああ！！！！！！
ありがとうございます（？）！！！
スクロール前とスクロール後のデザインがあるので、プロトタイプ設定でいじれば本当に使える！！
（[お困りのあなたにもお届け](https://www.figma.com/community/file/922738986195002030)）
![スクリーンショット 2022-12-10 11.45.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529394/27f3c6ed-f379-a75c-685f-3748104015eb.png)

パソコン版はなくてもいいかもと思いつつ
```Figma chrome ui kit```　と調べてみる。
色々出てきたけど、これが一番使えるかな？
（[お困りのあなたにもお届け](https://www.figma.com/community/file/1102522827078484202)）
![スクリーンショット 2022-12-10 12.00.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2529394/cfaba87b-91f7-cb47-8ff5-b98e67e1d938.png)

両フレームともコピペで使えるので本当に有難い・・・！！


# 最後に

関係ない場所を30分くらい探し回り、一発で解決！
ぜひこの30分を私に返してほしいと思うこの日この頃。
そもそもデザインナーの皆さんがこうやってるのかが少し疑問ですが・・・とにかくデザインとして完成する以上問題はないかな、と判断しました。
そして、まさかこんな単純とは・・・ただ、初心者なら知る術なさそうなので共有させてもらいました！
私と同じように迷子の方へ、届きますように:pray_tone2:
末尾の文字列を3回出力するプログラムの実装


対象の文字列の末尾に位置する文字を取得し、それらを任意の回数繰り返して出力するプログラムを実装します。以下の要件を満たすextra_endメソッドを実装しましょう。

- 対象の文字列から末尾にある2文字を取得すること
- 取得した2文字を3回繰り返して出力すること
- ヒント: sliceメソッドを使いましょう。


```:解答するときの雛形
def extra_end(str)
  # 処理を記述
end

# 呼び出し例
extra_end('Hello') 
```

# sliceメソッドとは
配列や文字列から、指定した要素を取り出すことができるメソッド。
[sliceメソッドの公式ドキュメント](https://docs.ruby-lang.org/ja/latest/method/String/i/slice=21.html)

```
# 配列を作成します
array = [0,1,2,3,4,5,6]

# 配列から引数で指定した要素を取得します
ele1 = array.slice(1)
puts ele1
#=> 1

# 配列番号-4から4つ分の要素をsliceします
ele2 = array.slice(-4,4)
puts ele2
#=> 3, 4, 5, 6

# 配列はもとのままです
puts array 
#=> [0,1,2,3,4,5,6]
```


```:自分の解答
def extra_end(str)
  puts str.slice(-2, 2) * 3
end

# 呼び出し例
extra_end('Hello') 
```

```:模範解答
def extra_end(str)
  right2 = str.slice(- 2, 2)
  puts right2 * 3
end

# 呼び出し例
extra_end('Hello')
```

模範解答では、
1行目でextra_endメソッドの仮引数strには対象の文字列’Hello’が格納。
2行目ではstrに対してsliceメソッドを使用し、指定した要素を取り出しています。
自分の解答では、2行目で * 3 を続けて記述していました。
Github Actionsのcustom actionsを使って、共通処理を外部に切り出し再利用できるようにしたい

ディップ Advent Calendar 2022 10日目です。そろそろ折り返しですね。

業務でGithub Actionsを使っているのですが、共通になった処理を再利用したいケースがありました。

custom actions, composite action, reusable workflow を用いて実現可能ですが、今回は custom actions を用いて説明します。

## 詳細なドキュメント

https://docs.github.com/ja/actions/creating-actions/about-custom-actions

## 構造

```shell
❯ exa -T -I .git -a
.
├── .github
│  ├── actions
│  │  └── hello_action
│  │     └── action.yml
│  └── workflows
│     ├── workflow-a.yml
│     └── workflow-b.yml
├── .gitignore
└── README.md
```

芸がありませんが、受け取った名前を使って `hello, ○○!` みたいなものをログに出力してみます。

## 呼ばれる側
### .github/actions/hello_action/action.yml

```.github/actions/hello_action/action.yml
inputs:
  action_user_name:
    description: "action user name"
    required: true
runs:
  using: "composite"
  steps:
    - name: Hello!
      run: echo "hello, ${{ inputs.action_user_name }}!"
      shell: bash
```

custom actions では `inputs` として変数値を渡すことができ、柔軟な動作変更が可能です。
（今回は紹介しませんが `output` というものもあり、 custom actions で処理した結果を参照することもできます）

`steps` では実際に `echo` で受け取った変数値を出力するようにしています。

## 呼ぶ側
### .github/workflows/workflow-a.yml

```.github/workflows/workflow-a.yml
name: Hello World A

on:
  push:
  workflow_dispatch:

jobs:
  say_hello:
    runs-on: self-hosted
    steps:
      - uses: actions/checkout@v2
      - name: workflow A
        with:
          action_user_name: 'Action User A san'
        uses: ./.github/actions/hello_action
```

呼び出し側からは `with` を用いて変数に渡します。

## 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2253330/e169a232-29d1-1cba-0b37-2475ab5267ac.png)


## 実際プロジェクトではどう使っているのか

リリース作業で特定のブランチに対してPRを出すのですが、それを後続の開発ブランチに取り込みたい需要があり、自動的にPRを作成しています。
他のCIを使うよりもActionsのイベントからPRの情報が取れるGithub Actionsを活用しました。

運用をしていく中で、いくつかの操作で同じものが出てきてしまったため、処理をまとめたいという需要からcustom actionsを見つけて適用しています。

## まとめ

プログラムを書く際に再利用性について意識するシーンがありますが、Github Actionsでも同様にできるのは良い発見でした。

入力値による操作が分岐などにより複雑になってしまうと利便性の問題も出てきそうですが、適切な範囲でactionを分割することにより、よりよい開発体験を実現できそうです！
Laravelでphp artisan系コマンドを実行すると、「Could not open input file」と表示される。

php artisan系コマンドを実行した際に、「Could not open input file」と表示された際は、
自分のLaravelプロジェクトディレクトリ配下に移動していないことが原因と考えられます。

なのでcdコマンドで移動してから、再度php artisan系コマンドを実行してみて下さい。
CLIPassoの公式のColabデモが動かないので直した

# はじめに
絶賛修論書いてる途中なのですが、休憩がてらに何か触ろうかと、CLIPassoとやらを見つけたので、回そうと思った。
CLIPassoとは何かは、詳細は省きますが、要するに画像からスケッチを描く画像生成手法の一種です(≠GAN)。

https://github.com/yael-vinker/CLIPasso

なんだけど、これが、Google Colabで動かない。まいったなぁ

実際にissueでこのあたりの投稿沢山あったので、直してみましょう。

# 原因
まずは著者のColabを触ってみると…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/783413/f6af5f39-6475-8edf-340e-ab4acde7f8e1.png)

tensorflowの切り替えでエラーがでちゃってます。これについては[Google ColabにおけるTensorFlow 1.x系のサポート終了への対応](https://qiita.com/katoyu_try1/items/0228870c41d9ac54e6e9)にある通り、2022年8月でtensorflow1.xのサポートがcolabで終了してしまったためですね。

tensorflow 1.xでビルドしている理由は、おそらく直後の[`diffvg`](https://github.com/BachiLi/diffvg)のビルドのためでしょう。diffvgはデフォルトでtorchとtensorflow用のビルドを行います。tensorflow用ではソース見た感じ1.x想定でビルドされているようなので、1.xのときのtensorflowのinclude使ってビルドしてるって感じでしょうか。

(…ん? CLIPassoはtorchで動いてるのだから、diffvgでtensorflow用のビルドしなくてよいのでは…?)

あとはリポジトリの中身を探します。詳細は省きますが、動かなさそうな原因はまだありました:
1. U2Netのダウンロード先がgdownで取れない。ファイルサイズが大きすぎてチェックが必要なためか。そのまま動かしてもFileNotFoundErro吐きます。
1. CLIPasso/CLIP_/clip/auxilary.pyで`F._pad`がAttributeエラーを起こす

## Dockerならできるのでは…?
研究室のGPUでやってみたが、torchのバージョン古すぎてRTX 3090では動かず
dockerでdiffvgのbuildのビルドはめんどくさいので、いろいろ環境が整ったcolabにします。

# 修正
さて、上の節で色々言いましたが、原因は次の通りです。
1. tensorflow 1.x系がサポート終了している
2. `torch.nn.functional._pad`が存在しない(pytorch公式から削除された可能性)
2. U2Netのダウンロードがgdownで取れない

直してみましょう。

## solve: tensorflow 1.x系がサポート終了している
まず、tensorflowを使う意味がないので、`tensorflow 1.x`は消します。

次にdiffvgの`CMakeLists.txt`を弄ります。一番下にtensorflow使うかのところがあるので、`if(NOT WIN32)`以降を消します。

## solve: `torch.nn.functional._pad`が存在しない
`auxilary.py`の`F._pad`を`F.pad`に直すだけです。

(CLIP_内は実は[openAIのCLIPのコピー](https://github.com/openai/CLIP)っぽいのですが、MHAのAttensionの重み使ってるあたり、最新版に置き換えるのはめんどくさそうです。このまま使いましょう)

## solve: U2Netのダウンロードがgdownで取れない
これは著者のissueでもあったので、それに従って直します。リンク先をHuggingFaceのリンクに変えて、gdownではなく普通にwgetで取ります。

# 結果
<img width="512" alt="fig1_small.jpg (349.6 kB)" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/783413/b228af18-2723-7897-cd17-2e78e9873039.jpeg"><img width="512" alt="fig1_small.jpg (349.6 kB)" src="https://raw.githubusercontent.com/ppza53893/ppza53893.github.io/main/box/pictures/sketch.svg">

見事に動きました。CLIPassoやばいですね…

# 終わりに
動いたのでColabのリンク上げときます。著者のcolabとは違って、パッケージインストール辺りもきれいにしたのと、その他いろいろあった問題も解決させました。<br><a href="https://colab.research.google.com/github/ppza53893/CLIPasso/blob/main/CLIPasso_fix_errors.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab" width=160/></a><br>特に著者にプル投げたりとかはしないつもりなので、そのあたりやりたい方はお任せします。

あと最後に言うのもなんですが、CLIPassoはreplicateにもあります。めんどくさかったらこっちで動かしたりするのも有りでしたね(ただこっちは1回回したらリミット喰らいます)

https://replicate.com/yael-vinker/clipasso