OmniAICreator/Qiita-1.07M huggingface dataset:
SysOps(SOA)受かりたいならラボ試験がなくてもハンズオンをやりなさい

# はじめに
こんにちは。記事を開いてくださりありがとうございます。
12月にSOA(ラボ試験なし)を受験して不合格、2週間後の1月にリベンジして合格したもののかなりギリギリでの合格だったため、確実に受かるにはどうしたらよいのかを振り返ってみました。しくじり日記みたいなものなので、今後SOAを受験する予定のある方の参考になればなと思います。

※ハンズオンをやれという理由のみ知りたい方は[こちら](#ラボ試験がなくてもハンズオンをおすすめする理由)に飛んでください。

# プロフィール
- 受験時の保有資格
  - SAA (AWS Certified Solutions Architect - Associate)
  - DVA (AWS Certified Developer - Associate)
- AWS認定試験受験履歴
  - SAA-C03(23/10/29受験)：合格(23/10/30発表)
  - DVA-C02(23/12/02受験)：合格(23/12/02発表)
  - SOA-C02(23/12/27受験)：不合格(23/12/28発表)
  - SOA-C02(24/01/13受験)：合格(24/01/13発表)
- 仕事概要
    - 未経験入社1年目
    - アプリケーション開発(フロント・バックエンド両方)
    - AWSは設定を読み解く経験はあってもいじる経験はなし(**=ハンズオンほぼなし**)
      - 今後AWSの設定に触れる数が増えるため勉強を開始

# SysOps(SOA)の記録まとめ
以下SOAの記録をまとめたものになります。
※SAA・DVAの記録まとめは[こちら](https://qiita.com/hoshi7_n/items/bed0c94fc92d23a9c5c7)からご覧ください。

## 受験1回目(不合格)
  - 結果：**695点**(720点合格)
  - 勉強時間：**30~40時間**
  - 勉強開始から本番までの日数：**14日**
  - 解いた問題数：**約800問**(重複あり)
  - 勉強方法：**CloudLisenceでアウトプット**
  - かかったお金(受験費用8250円除く)：**0円**(CloudLicenseはSAA時に支払い済み)
  - 試験終了から結果が出るまでの時間：**9時間**

DVAの時と同じぐらい問題集を解いたので大丈夫だろ～と思って受験したら見事に落ちました。このときは勉強時間の短さが原因だろうと思っていました。(後ほど詳しく)

あと参考までにですが、不合格だと結果通知は合格時より遅いみたいです。DVA、SOA受験2回とも土曜日の15:30からの受験で、受かったときは当日の20時ごろに通知、落ちたときは次の日の朝4時に通知でした。(SAAの時は日曜受験だったので、結果は受かってても1日後に通知でした。)

## 受験2回目(合格)
  - 結果：**724点**(720点合格)
  - 勉強時間：**50~60時間**
  - 勉強開始から本番までの日数：**31日**
  - 解いた問題数：**約1310問**(重複あり)
  - 勉強方法：**落ちた時の単元別でUdemy問題集学習・CloudLisenceでアウトプット+AWS公式サイトで間違えたサービスの復習**
  - かかったお金(受験費用16500円除く)：**4580円**(CloudLicenseプロへの更新)
  - 試験終了から結果が出るまでの時間：**3時間**

問題集8~9割取れている状態で受験して、本番も2択で迷うことが多かったけどまぁきっと大丈夫だろうと思い、開示をみたらなんとギリギリでの合格。かなりショックでした。
開示後、高得点を取るためにどうしたらよかったかを考えてみると、ハンズオンやらなかったのが大きかったなーと思いました。

# ラボ試験がなくてもハンズオンをおすすめする理由
長くなりましたが、本題です。
SOAに余裕をもって合格するためにハンズオンをおすすめする理由は、 **「SOA-C02は実技が文章になって出るから」** です。
何を当たり前なことを言ってるんだ！読んで損した！と思うかもしれませんが、**「ラボ試験がない＝DVAやSOAと同じ勉強法で合格できる」ではない**ということです。

正直2回目のSOA受験はDVAの時よりもかなり勉強して、問題集は8~9割安定してとれるぐらいになったのにもかかわらず(DVA、SAAの時は7割ギリギリで受験していました、、)、ギリギリ合格となってしまった理由は、**ハンズオンの有無**にあるなと2回目の受験でやっと気づきました。1回目の不合格の時は単なる勉強不足だと思っていたので、そのままDVAやSAAの受験勉強と同じやり方で対策してしまったから、受かったけどギリギリだったんだなと、、。
逆に言うと実務でAWS触られている方は、問題集7割でも合格できるのかなと思いました。AWSを実務で使っていない状態で受験を考えている方は、ハンズオンを実施することを強くおすすめします。
[公式サイト](https://aws.amazon.com/jp/certification/certified-sysops-admin-associate/)の試験準備に再度目を通すのも良いかもしれません。

## 余談（SOAって自動車の本免試験みたいだよねという話）
SOAを受験してみて、本番と練習の点数の差に乖離が出た理由を考えたときに、ラボ試験なしのSOAは「自動車の本免の実技試験が筆記試験に変わった」みたいな感じで、落ちた理由は「けど、従来の標識や交通ルールが出る筆記試験しか対策してなかったから」に近いのかなーと思いました。

わかりづらいと思うので例を出すならこんな感じです。
>あなたはハイブリッドカーの運転をするためにエンジンをかけようとしています。しかし、ボタン式のエンジンを押してもエンジンがかかりません。バッテリーやガソリンの残量には問題は見られませんでした。原因は何だと考えられますか。
>
>1.後部座席が半ドアになっている
>2.ガソリンが足りない
>3.ブレーキを踏んでボタンを押していない
>4.ボンネットが開いた状態になっている

運転したことがある人ならガソリンは足りてるって問題文に書いてあるし3かなぁと感覚でわかると思うのですが、運転したことがない&従来の筆記しか対策してないと(本物の本免筆記試験は○×ですが、、)標識とか運転ルールしか問題集になかったじゃん！となり、間違えてしまう、みたいなイメージです。
SOAは実際に触ってたら細かい挙動までわかるよね？みたいな問題が本番で出されて、そこでいくつか間違えたなという印象でした。

# おわりに
実務で使えるために、まずは3つの座学たちであるAssociateをマスターしよう！というゴールで勉強を進めていましたが、SOAは座学というよりどれくらい実務で通用するスキルがあるかをはかる試験だったなーと改めて考えさせられました。
これからはハンズオンに切り替えて、実務で使えるような勉強したいなと思います。
また裏目標？ですが、年内にProfessionalやSpecialityもチャレンジしたいです。
最後までお読みいただきありがとうございました。
分類と回帰における主要な評価指標の理解

## 導入
機械学習の分野で、モデルの性能を正確に評価することは非常に重要です。このブログでは、分類と回帰、それぞれのタスクでよく用いられる主要な評価指標について解説します。これらの指標は、予測モデルの精度を理解し、改善するために不可欠です。

## 分類における指標
混同行列（Confusion Matrix）
混同行列は、分類タスクの性能を評価するための基礎となります。
この行列は、モデルによる予測と実際のラベルを比較して、真陽性（TP）、偽陽性（FP）、真陰性（TN）、偽陰性（FN）の4つの異なるカテゴリに分類します。

### 正解率（Accuracy）
正解率は、モデルが全てのサンプルをどの程度正確に分類したかを示します。これは最も直感的な性能指標の一つで、全予測のうち正しい予測の割合を計算します。

```math
\text{Accuracy} = \frac{\text{TP} + \text{TN}}{\text{TP} + \text{FP} + \text{TN} + \text{FN}}
```

しかし、不均衡なデータセットでは、多数クラスの予測に偏ってしまう可能性があります。このため、正解率だけでモデルの性能を判断するのは適切ではない場合があります。

### 適合率（Precision）
適合率は、陽性と予測されたケースの中で実際に陽性である割合を示します。つまり、モデルが陽性と判断したデータの中で、どれだけ正確であったかを測ります。
```math
​\text{Precision} = \frac{\text{TP}}{\text{TP} + \text{FP}}
```
適合率は、偽陽性（誤って陽性と判断されるケース）を低減することが重要な場合に特に重視されます。たとえば、スパムメールのフィルタリングなどがその例です。

### 再現率（Recall）
再現率は、実際に陽性であるケースの中で、モデルが陽性と正しく予測した割合です。
```math
\text{Recall} = \frac{\text{TP}}{\text{TP} + \text{FN}}
```
この指標は、実際の陽性ケースを見逃さないことが重要な場合に重要です。例えば、病気の診断で陽性ケースを見逃すことは大きな問題になります。
しかし、すべて陽性と予測すれば、1となってしまうため単独では用いず、適合率と併用して評価します。
 
### F値（F-Score）
F値（特にF1スコア）は、適合率と再現率の調和平均を取ったものです。この指標は、適合率と再現率のバランスを測定します。
```math
F\text{-Score} = 2 \times \frac{\text{Precision} \times \text{Recall}}{\text{Precision} + \text{Recall}}
```
適合率と再現率はしばしばトレードオフの関係にあり、一方を上げるともう一方が下がる傾向があります。F値はこの二つの指標を均等に考慮し、全体的なモデルの性能を評価します。
この値が大きいほど、RecallとPrecisionの両方が良いことを示します。


## 回帰における指標

### 平均絶対誤差（MAE: Mean Absolute Error）
平均絶対誤差（MAE）は、予測値と実際の値との差の絶対値の平均です。この指標は、予測エラーの平均的な大きさを示します。

```math
\text{MAE} = \frac{1}{n} \sum_{i=1}^{n} |y_i - \hat{y}_i|
```


### 平均二乗誤差（MSE: Mean Squared Error）
平均二乗誤差（MSE）は、予測値と実際の値の差を二乗して平均したものです。
```math
\text{MSE} = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2
```
MSEの特徴は、大きな誤差に対して非常に敏感である点です。誤差を二乗することで、大きな誤差はより強調されます。これは、モデルが大きな予測誤差を生じさせることを特に避けたい場合に有用です。しかし、その結果として、MSEは誤差の実際の大きさよりも大きく見積もることがあります。

### 平均二乗誤差の平方根（RMSE: Root Mean Squared Error）
平均二乗誤差の平方根（RMSE）は、MSEの平方根であり、誤差の尺度を元の変数の尺度に戻します。
```math
\text{RMSE} = \sqrt{\frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2}
```
RMSEはMSEと同様に大きな誤差に敏感ですが、誤差の尺度を元のデータの尺度に戻すため(目的変数と同じ単位になる)、解釈が容易になります。例えば、予測対象が金額である場合、RMSEは「通貨単位」の誤差として解釈できます。

# 結論
このブログでは、分類タスクの指標（正解率、適合率、再現率、F値）と回帰タスクの指標（平均絶対誤差、平均二乗誤差、平均二乗誤差の平方根）について学びました。これらの指標は、モデルの予測性能を多面的に評価するために重要です。

特に、不均衡なデータセットや大きな予測誤差が問題となる状況では、特定の指標の重要性が増します。例えば、不均衡なデータセットでは、正解率だけではなく、適合率や再現率を考慮することが重要です。また、大きな誤差を避けたい回帰タスクでは、平均二乗誤差やその平方根が有用です。
オブジェクト指向が人類には難しすぎると思う3つの理由


## コードは書かれるよりも読まれる時間が長い

プログラミング言語は一度書いたら終わりではなく、他のエンジニアが読みます。
（あるいは、そのコードを読むのは一月後のあなたかもしれません）

その時に、「どこから読んだらいいかわからない」「追いかけるスタート地点が見えない」となるケースは避けたいはずです。

（これについてはリーダブルコードが未だ人気を誇っている点からも共通認識と考えて良いでしょう）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1678228/7d831dce-776f-7597-30d7-0f7b6850412e.png)

「コードは書かれるよりも読まれる時間が長い」というのは、**オブジェクト指向 vs 関数型プログラミング**のメイントピックだと思います。


## オブジェクト指向は難しすぎると思った。

まず、オブジェクト指向は難しすぎると思いました。

そもそもオブジェクト指向の中心にあるプログラム側は`class`という概念ですが、
このクラスには「プロパティ」と「メソッド」が含まれます。


```python
class Car:
    def __init__(self):
        self.x = 0

    def move(self, n):
        self.x += n
```

自分がオブジェクト指向を難しいと思っている理由は、**この「プロパティ」と「メソッド」をどのように利用すれば良いかは、このクラスを作成した人間しかわからないのではないか?** と考えているからです。


## 可能なら長いドキュメントは読みたくない

仮にどのように動作するかをドキュメントで説明しようとすれば、今度はこのドキュメントを読む必要があります。
このドキュメントが受け手に正しく解釈されるかどうかは自然言語の書き手と読み手に依存してしまいます。

このドキュメントは長ければ長いほど誤解を生む原因になると思いますし、そもそもドキュメントとコードが一画面に収まらなければ読みきれません。

少なくとも長いドキュメントは読みたくない...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1678228/fd617cd9-9061-a747-b722-7e84d97b97da.png)

AWSの公式ドキュメントもとても親切丁寧に書いてますが、理解できるかどうかはまた別の問題ですね。



## 人間はラプラスの悪魔にはなれない

ラプラスの悪魔という概念があります。

> もしもある瞬間における全ての物質の力学的状態と力を知ることができ、かつもしもそれらのデータを解析できるだけの能力の知性が存在するとすれば、この知性にとっては、不確実なことは何もなくなり、その目には未来も（過去同様に）全て見えているであろう。

https://ja.wikipedia.org/wiki/%E3%83%A9%E3%83%97%E3%83%A9%E3%82%B9%E3%81%AE%E6%82%AA%E9%AD%94

あらゆる状態を完全に理解した個体をラプラスの悪魔と呼び、
この個体は未来のあらゆる事象を予見できると言います。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1678228/5388f376-2845-9b5c-2549-3484932c5d66.png)

https://dic.pixiv.net/a/%E3%83%A9%E3%83%97%E3%83%A9%E3%82%B9%E3%81%AE%E6%82%AA%E9%AD%94

裏を返せば、
**未来の事象を完全に予測するためには全ての状態を理解する必要がある** ということです。

プログラマーはコードを理解できるチェックポイントの一つとして、「コードが想定通りに動くという点が挙げられますが」
オブジェクト指向における「現在の事象」は「プロパティ」のことだと考えます。

つまり、オブジェクト指向で書かれたプログラムの動作を予測するためには**全てのプロパティとその動かし方を熟知しなければなりません** 

先ほどの`Car`クラスは、プロパティが一つの単純なクラスでしたが、ここに燃料の概念を加えるとどうでしょう？

```python
class Car:
    def __init__(self):
        self.x = 0
        self.fuel = 0
        self.fuel_max = 100

    def move(self, n):
        self.x += n
        self.fuel -= n

    def fill_fuel(self):
        self.fuel = self.fuel_max
```

`move`メソッドは座標だけでなく、燃料の概念も管理しなくてはならなくなってしまいました。
今の状態であれば管理は可能ですが、プロパティの数が増えるに従って、人間の理解を超えてしまいます。

ラプラスの悪魔みたいなエンジニアもいますが、全てのエンジニアがそうではありません。


## でもオブジェクト指向とは付き合っていかないとね...

そうはいっても「全てのプロパティ」を理解しなければならない時もあると思います。

フロントエンド開発をしている時、あらゆるプロパティを `useState`で管理しなければなりません。

大変ですね〜


## じゃあどうするの？

ここまでの内容をまとめると

- コードは書かれるよりも読まれる時間が長い
- 長いドキュメントは読みたくないし、コードは短い方がいい
- 人間は全てのプロパティを理解できない

となりました。

これを解決するためには、関数型プログラミングが必要だと考えていますが、それはまた別のお話...。
期待値には「幅」をもたせる

筆者は、いろんな人と仕事をするとき、期待値調整を重要視しています。

期待値を明確にして達成すること（あるいは未達を早めにつたえること）は、個人・チームのパフォーマンスに影響します。これは「プロジェクト・アリストテレス」でも「(心理的安全の次に)相互信頼や目標の明確さが生産性の高いチームになるための要素である」と述べられている通りです。

このエントリでは、期待値をつくるときに意識することを書いてみたいと思います。

## 「点」の期待値はつくらない

期待値調整においてよくやってしまいがちなのがこれです。

メンバー・チームの期待値を「点」つまり1つに固定してしまうのはアンチパターンになりうると考えています。

ある仕事の完了日を聞かれて「今週の金曜日に終わる」のように答える場合は、ほぼ確実にその日に終わる（あるいは終わらせる）自信があるときだけにします。

それ以外は「今週の金曜日までに、遅くとも来週の火曜日には終わる」など、期間で答えることを意識します。

## どのようにして「幅」をもたせるか

期間で答えることを意識するだけであれば、とても簡単です。

「今週の金曜に終わります。**でも一生かかる可能性もあります**」と言えば期間になるからです。しかしこれを目の前の同僚や上司に言う勇気はさすがにないでしょう。

つまり「どのように幅をもたせるか」が重要であり、ここにその人のセンスや経験が出てきます。

### 極端なケースは考えない

幅をもたせて考えるためには想像力が必要となりますが、妄想レベルのことも期待値に反映させることは避けます。地球に隕石が降ってきた場合の納期を考える必要はありません。

もうすこし現実的なケースをあげれば、たとえばほぼ必ず通る最終確認のようなステップについて、それが失敗して調査する場合の工数などは見積もりに含める必要はないでしょう。

もちろん発生する可能性は隕石より遥かに高いですが、それは発生したときに速やかに報告してリスケすべきものだと考えています。

### ストーリーを添える

あるプロジェクトの完了について、いろんなケースを想定したうえで「来月中に終わる」と回答しました。

これでも十分ですが、可能であれば「その幅に収まるストーリー」も回答できると、相手も安心しますし、自身も見積もりに対する精度を認識できます。

たとえば「来月の中旬ぐらいに終わりそう。早くなるかもしれないし遅くなるかもしれないから、来月中ぐらい」という場合、その期待値は正規分布のような形をしています。

同じように「今月末に終わるぐらいのペースで進めるが、このたぐいのプロジェクトは終盤にいつも問題が見つかるので、来月中を目安にしたい」という場合は、今月末に近づいた時点でどのような状況下を見極めなおすべきでしょう。

### 途中のゴールを示す

ストーリーも回答しようと思うと、タスクやプロジェクトの中間地点もイメージできてきます。この中間地点も期待値として設定しておくと、より良くなります。

「この時点で〜が完成している」というような期待値を描けると、期待値の設定の正しさにもより自信が持てるはずです。

## まとめ

最後に、ここまで「納期」に絞って書いてきましたが、たとえばQCDを参照すれば「質」や「コスト」、あるいはプロセスや副産物に関する期待値を設定すべき場合もあります。

しかしどの観点においても原則としてピンポイントで期待値は設定せず、適切な幅をもたせるように工夫することで、うまく物事を進められるはずです。

この記事を読んだ感想などあれば、ぜひコメントもお願いします！
std::vector::reserveは何のために行うのか？

## 概要
c++のboostライブラリ内で、vectorのpush_back前にreserveしている箇所があった。
vectorって動的配列だからあらかじめ要素を確保しておく必要はないんじゃないか？ と思ったので調べてみた。

## 目次
- std::vector::reserveとは
- 勘違い
- あらかじめcapacityを確保する意味は？
- まとめ

## std::vector::reserveとは
constexpr void reserve(size_type n);
vectorのcapacityを引数nに変更する。

## 勘違い
「capacity」=「size」ではない。
size = 要素数。
capacity = 割り当てられている容量。

◆確認用コード
    
    #include <iostream>
    #include <vector>
    #include <chrono>
    
    int main()
    {
        std::vector<int> v;
    
        std::cout << "reserve()前のサイズ：" << v.size() << std::endl;
        std::cout << "reserve()前の容量：" << v.capacity() << std::endl;
    
        v.reserve(5);
    
        std::cout << "reserve()後のサイズ：" << v.size() << std::endl;
        std::cout << "reserve()後の容量：" << v.capacity() << std::endl;
    
        v.push_back(1);
    
        std::cout << "push_back()後のサイズ：" << v.size() << std::endl;
        std::cout << "push_back()後の容量：" << v.capacity() << std::endl;
    }

◆実行結果

    reserve()前のサイズ：0
    reserve()前の容量：0
    reserve()後のサイズ：0
    reserve()後の容量：5
    push_back()後のサイズ：1
    push_back()後の容量：5

## あらかじめcapacityを確保する意味は？
reserveしない場合、push_backごとにメモリを確保しなくてはいけないため、その分処理速度に影響する。
実際にどれくらいの差が出るかについては、以下のページが参考となる。
[【C++】std::vectorにおける要素追加の速度比較（push_back, reserve, resize）](https://e-penguiner.com/cpp-comparison-speed-of-std-vector/)

## まとめ
あらかじめstd::vector::reserveでcapacityを確保するとしないとでは、要素追加時の処理速度に差が出る。
要素数にある程度の目星がついている場合はreserveしてからpush_backすること。
(とくに大きなデータを扱う場合。)
「リーダーの作法 ―ささいなことをていねいに」を読んだので、そのメモ

[リーダーの作法 ―ささいなことをていねいに | Michael Lopp, 和智 右桂 |本 | 通販 | Amazon](https://www.amazon.co.jp/dp/4873119898)

![](https://www.oreilly.co.jp/books/images/picture_large978-4-87311-989-2.jpeg)


- 第１幕　Ｎｅｔｓｃａｐｅ：マネージャー（誰からでも学ぶことがあると考える／会議ボケ／難題　ほか）
- 第２幕　Ａｐｐｌｅ：ディレクター（青テープリスト／我慢の限界まで任せる／採用するには　ほか）
- 第３幕　Ｓｌａｃｋ：エグゼクティブ（ゼロから作りたい病／兵士／文化の流れ　ほか）

短編で構成されており読みやすい。

## 感想

共感するのは以下。

[【書評】「リーダーの作法」は当たり前のことを当たり前にやろうという本だった - やわらかテック](https://www.okb-shelf.work/entry/the_art_of_leadership)

>>  〇〇という新しいマネジメント方法があってじゃな...
>>  〇〇というフレームワークを導入すればコミュニケーションがスムーズになるのじゃよ...

> 上記のような新しい話は一切ありません。
> まず、マネジメントでは当たり前とされていることの重要性が説かれています。

> 信頼関係の構築には1on1を行うのが良い
> 尊敬をもって相手に接するのが重要だ

例えば以下である。

- 誰からでも学ぶことがあると考える
- 多様性のあるチームを作ることで、見えている弱点と見えない弱点を補う
    - 自分に賛成してくれる人だけのチームを作れば、抵抗にあうことはほとんどない。しかし、意見は、賛成されても洗練されない。
    - 意見というものは健全な不一致を通じて力を蓄える。そのためには、できる限り幅広い視野と経験を持った人間を探して採用しなければならない


## 参考

[【書評】「リーダーの作法」は当たり前のことを当たり前にやろうという本だった - やわらかテック](https://www.okb-shelf.work/entry/the_art_of_leadership)
[リーダーの作法から学ぶ](https://zenn.dev/yumemi_inc/articles/learn-leadership)
[マイケル・ロップ氏の「リーダーの作法　ささいなことをていねいに」をじわじわと読み始めた話 #プロジェクト管理 - Qiita](https://qiita.com/w2mjra555/items/73fcac51e65dc20e8cba)


以上です～
Pythonで「集合に指定した値と同じ要素が含まれているか確認する」の動作を確認してみた

# 概要

Pythonで「集合に指定した値と同じ要素が含まれているか確認する」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/python/set/index7.html

# 実装

以下のファイルを作成しました。
```sample.py
myset = {"A", "B", "C"}
print("A" in myset)
print("D" in myset)

myfrozenset = frozenset(["A", "B", "C"])
print("A" in myfrozenset)
print("D" in myfrozenset)
```

以下のコマンドを実行しました。
```
$ python3 sample.py 
True
False
True
False
```

# まとめ

何かの役に立てばと。
最近は Apache で ServerTokens を Full にしただけではバージョンが表示されなかった

# はじめに

わざわざ Apache で ServerTokens を Full とかにしてバージョンを世間に公開するような方はおられないと思いますが、デフォルトでバージョンが表示されないからといって記述を省略せずきちんと設定していく教義の方に向けてお出ししてみます。

# 確認に用いた環境

以下の通りです。

    RockyLinux 9.0
    Apache 2.4.57

# 確認した内容

ServerTokens を Full にしましたが、Apache 公式のページを参照したところ、赤枠の部分を確認しました。

https://httpd.apache.org/docs/2.4/ja/mod/core.html#servertokens

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152700/f0051f49-d9a6-cf14-9161-128674ca6e36.png)

こんな項目あったかなあとおもいつつ、ServerSignature へのリンクを参照。

https://httpd.apache.org/docs/2.4/ja/mod/core.html#serversignature

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152700/137af226-55fd-f152-dd7e-3d60ee7bc9ef.png)

こいつが抑制してたんかと思いつつ、下記の設定に変更してみました。

    ServerTokens Full
    ServerSignature EMail

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152700/b16a17cb-3e39-6ac1-1b02-44232c0a5ab1.png)

バージョンが表示されました。この後、設定は両方とも無効化しておきました。
以上になります。
大学共通テスト数学Ⅰ・数学A第4問タイマーの問題をElixirでプログラミングしてみた

大学共通テスト数学Ⅰ・数学A第4問タイマーの問題をElixirでプログラミングしてみたので，報告します．

## 問題

T3，T4，T6を次のようなタイマーとする．

* T3: 3進数を3桁表示するタイマー
* T4: 4進数を3桁表示するタイマー
* T6: 6進数を3桁表示するタイマー

なお$n$進数とは，$n$進法で表された数のことである．

これらのタイマーは，すべて次の表示方法に従うものとする．

表示方法

1. スタートした時点でタイマーは000と表示されている．
1. タイマーは，スタートした後，表示される数が1秒ごとに1ずつ増えていき，3桁で表示できる最大の数が表示された1秒後に，表示が000に戻る．
1. タイマーは表示が000に戻った後も，2と同様に，表示される数が1秒ごとに1ずつ増えていき，3桁で表示できる最大の数が表示された1秒後に，表示が000に戻るという動作を繰り返す．

例えば，T3はスタートしてから3進数で$12_{(3)}$秒後に012と表示される．その後，222と表示された1秒後に表示が000に戻り，その$12_{(3)}$秒後に再び012と表示される．

## プログラム例

```elixir
defmodule Timer do
  def at(tick, base, count \\ 3) do
    tick
    |> Kernel.rem(base ** count)
    |> Integer.to_string(base)
    |> String.pad_leading(count, "0")
  end

  def to(tick, base, count \\ 3) do
    Enum.map(0..tick, &at(&1, base, count))
  end

  def zipped_display(tick, bases \\ [3, 4, 6], count \\ 3) do
    bases
    |> Enum.map(&to(tick, &1, count))
    |> Enum.zip()
  end
end
```

実行例

```elixir
Timer.zipped_display(10)
```

実行結果

```elixir
[
  {"000", "000", "000"},
  {"001", "001", "001"},
  {"002", "002", "002"},
  {"010", "003", "003"},
  {"011", "010", "004"},
  {"012", "011", "005"},
  {"020", "012", "010"},
  {"021", "013", "011"},
  {"022", "020", "012"},
  {"100", "021", "013"},
  {"101", "022", "014"}
]
```

実行例

```elixir
10 |> Timer.zipped_display() |> Enum.with_index()
```

実行結果

```elixir
[
  {{"000", "000", "000"}, 0},
  {{"001", "001", "001"}, 1},
  {{"002", "002", "002"}, 2},
  {{"010", "003", "003"}, 3},
  {{"011", "010", "004"}, 4},
  {{"012", "011", "005"}, 5},
  {{"020", "012", "010"}, 6},
  {{"021", "013", "011"}, 7},
  {{"022", "020", "012"}, 8},
  {{"100", "021", "013"}, 9},
  {{"101", "022", "014"}, 10}
]
```
2024/1/15主にITとかセキュリティの記事

中国政府が反政府運動対策のためにAirDrop機能をハッキング(1/13)
https://www.gizmodo.jp/2024/01/chinese-government-hacks-airdrop.html

AIを活用し水供給システムをサイバー攻撃から守る。イスラエルのスタートアップ「IXDen」の取り組み(1/13)
https://techable.jp/archives/225246

Magic Keyboardの入力内容が筒抜けになる脆弱性、ファームウェアで修正(1/13)
https://iphone-mania.jp/news-572558/

徳島県の公式X（旧ツイッター）が12日夜から凍結されている。原因は分からず、徳島県は凍結解除の手続きを行っている。(1/13)
https://news.yahoo.co.jp/articles/8d303871c3926d5b9fc137e2f40e8e014e407110

ベンチャー企業でゼロからゼロトラストセキュリティを導入した話(1/11)
https://qiita.com/lazy-kz/items/1975f0802b1680c53bb2

不正なPythonパッケージ「sellpass-sdk」に注意(1/13)
https://news.mynavi.jp/techplus/article/20240113-2861715/

事業継続計画（BCP）とは(1/13)
https://www.nikkei.com/article/DGKKZO77628120S4A110C2L61000/

「変なDMがきた」鳥取県公式インスタグラムアカウント乗っ取り被害　個人情報漏洩など調査中　県「絶対にメッセージ内のURLクリックしないで」(1/13)
https://nordot.app/1118821107046383972

Windowsで非HPプリンターがHP製と表示される問題のトラブルシューティングツール、脆弱性が修正される(1/13)
https://it.srad.jp/story/24/01/13/083254/
M1 Macで文字起こしを試してみる

Appleが昨年末(2023年12月)に[mlx](https://github.com/ml-explore/mlx)なるAppleシリコン上で機械学習が動くライブラリを出したそうなのでWhisperで文字起こしを試してみたので備忘録

## インストール
[ml-explore/mlx-examples](https://github.com/ml-explore/mlx-examples/blob/main/whisper/README.md)のWhisperのREADMEを参照してインストールと、今回使うライブラリの導入

```
$ git clone https://github.com/ml-explore/mlx-examples.git
$ cd mlx-examples/whisper
$ pip install -r requirements.txt
$ brew install ImageMagick
$ pip install yt_dlp pysrt moviepy ImageMagick
```
others ffmpeg

## 適当な動画をダウンロード

```python:download.py
from yt_dlp import YoutubeDL
ydl = YoutubeDL()
result = ydl.download(['https://www.youtube.com/watch?v=xxx'])
```

## 動画から文字起こし

デフォルトはtinyモデルなので[mlx-community](https://huggingface.co/mlx-community/)で好みのモデルを探す。
今回は、M1 Mac 8GBのメモリで[large-v3](https://huggingface.co/mlx-community/whisper-large-v3-mlx)を試してみたがどうやら動く模様。（なお、とても遅い）
一旦srt形式で字幕テキストを出力して後から別のコードで書き込むようにした。
あと、[`transcribe`のdecode_options](https://github.com/ml-explore/mlx-examples/blob/main/whisper/whisper/transcribe.py)で`fp16=True`を指定すると半精度で動きます。（若干速くなる）

```python:speech2text.py
import whisper
import pysrt
 
speech_file = "sample.webm"
result = whisper.transcribe(speech_file, verbose=True, language='ja', 
                            path_or_hf_repo="mlx-community/whisper-large-v3-mlx", fp16=True)

# References: https://note.com/9256/n/nce2ddc5e006a
subs = pysrt.SubRipFile()
sub_idx = 1

for i in range(len(result["segments"])):
    start_time = result["segments"][i]["start"]
    end_time = result["segments"][i]["end"]
    duration = end_time - start_time
    timestamp = f"{start_time:.3f} - {end_time:.3f}"
    text = result["segments"][i]["text"]
    
    sub = pysrt.SubRipItem(index=sub_idx, start=pysrt.SubRipTime(seconds=start_time), 
                           end=pysrt.SubRipTime(seconds=end_time), text=text)
    subs.append(sub)
    sub_idx += 1
    
subs.save("sample.srt")
```

## 動画にテキストを書き込む

TextClipにsizeを指定すると折り返しにも対応してくれるようだ。
結構時間がかかるので用途によってはmkvで書き出した方が良さそうだ。

```python:composite.py
# ffmpeg -i sample.webm -vf scale=-1:720 sample.mp4

from moviepy.editor import *
from moviepy.video.tools.subtitles import SubtitlesClip

video = VideoFileClip("sample.mp4")

generator = lambda txt: TextClip(
    txt, font='YuGothic-Medium', fontsize=48, color='white',
    stroke_width=10, method='caption', align='south', size=video.size)

subtitles = SubtitlesClip("sample.srt", generator)
result = CompositeVideoClip([video, subtitles.set_pos(('center','bottom'))])

result.write_videofile("out.mp4", fps=video.fps, temp_audiofile="temp-audio.m4a", remove_temp=True, codec="libx264", audio_codec="aac")
```
Cloud FunctionでFirestoreのコレクションとサブコレクションをまとめて削除する方法

## 背景
あるドキュメントが削除された際に、そのドキュメント配下にあるサブコレクションは残ってしまうという問題に直面した。

## 原因
Firestoreでは、ドキュメントを削除しても、そのドキュメント配下のサブコレクションは自動的には削除されない。
これは、特にドキュメントがサブコレクションを多く持っている場合、手動で一つずつ削除するのは非効率的で面倒な作業。

## やること
ドキュメントが削除された際に、そのドキュメント配下にあるサブコレクションもまとめて削除できるようにする。

## 解決案
Firebase Admin SDKを使用して、ドキュメントとそのサブコレクションを一括で削除する方法を採用。
Admin SDKにはrecursiveDeleteメソッドがあり、これを使用することで指定したドキュメントとそのサブコレクションを再帰的に削除することができる。


## 実装 Admin SDKで再帰削除する
最初、firebase-toolsを使った方法で試みたが、tokenの問題などに引っかかったり、その方法では有効期限切れも気にしないといけない。（[ドキュメント](https://firebase.google.com/docs/firestore/manage-data/delete-data?hl=ja#collections)）

それが嫌だったので、代わりにAdmin SDKを使う方法を試みた。（[ドキュメント](https://googleapis.dev/nodejs/firestore/latest/Firestore.html#recursiveDelete)）

完成したコードが以下。

```typescript:typescript
import * as functions from "firebase-functions/v1";
import * as FirebaseAdmin from "firebase-admin";
import * as logger from "firebase-functions/logger";

FirebaseAdmin.initializeApp();
const db = FirebaseAdmin.firestore();

export const onDeleteDocuments = functions
  .region("asia-northeast1") // regionの指定が必要ないなら、この行はいらない
  .firestore.document("collections/{collectionId}/subcollections/{subcollectionId}") // トリガーとなるドキュメント
  .onDelete(async (snapshot, context) => {
    const path = snapshot.ref.path; // 削除されたcollectionのpathを取得
    try {
      const docRef = db.doc(path);
      await db.recursiveDelete(docRef); // Admin SDKで再帰削除できる
      logger.log(`Successfully deleted collection and subcollection`);
    } catch (err) {
      logger.error(`Error deleting collection and subcollection: `, err);
    }
  });

```

ポイントとしては、以下があれば再帰削除ができるっぽい。

```typescript:typescript
FirebaseAdmin.initializeApp();
const db = FirebaseAdmin.firestore();
// 中略
  const docRef = db.doc(path);
  await db.recursiveDelete(docRef);
```

## コード解説

### Firebase Admin SDKの初期化
```typescript:typescript
FirebaseAdmin.initializeApp();
```
はFirebase Admin SDKを初期化し、FirestoreなどのFirebaseのサービスにアクセスする準備みたいな感じ。

### Firestoreインスタンスの作成
```typescript:typescript
const db = FirebaseAdmin.firestore();
```
これでFirestoreのインスタンスを作成。これにより、Firestoreのデータにアクセスできる。

### Cloud Functionsでのトリガー設定
特定のFirestoreドキュメントが削除されたときにトリガーされるCloud Functionを設定。
```typescript:typescript
.firestore.document("collections/{collectionId}/subcollections/{subcollectionId}")
  .onDelete(async (snapshot, context) => {
    // ...
  });
```
この関数は、指定されたドキュメントパス（ここでは `"collections/{collectionId}/subcollections/{subcollectionId}"`）にあるドキュメントが削除されると自動的に呼び出される。

### 削除されたドキュメントのパスの取得と再帰削除
削除されたドキュメントのパスを取得し、そのパスに基づいてドキュメントとそのサブコレクションを再帰的に削除。

```typescript:typescript
const path = snapshot.ref.path; // 削除されたドキュメントのパスを取得
try {
  const docRef = db.doc(path);
  await db.recursiveDelete(docRef); // 再帰的に削除
  logger.log(`Successfully deleted collection and subcollection`);
} catch (err) {
  logger.error(`Error deleting collection and subcollection: `, err);
}
```

`recursiveDelete` メソッドは、指定されたドキュメントとその下にあるすべてのサブコレクションを削除する。




## お疲れ様でした。
この方法により、Firestoreのデータ構造における親子関係を持つデータの整合性を維持しつつ、不要になったデータを効率的に削除できると思う。
また、この処理はサーバーサイドで実行されるため、クライアント側の負荷を軽減できる利点もある。

わからないところ、間違っているところ、もっといい方法がある場合は、コメントでもDMでも教えてください。
Ansible Tips: データ構造変換にはjinja2 for loopとfrom_yamlフィルターの組み合わせが使いやすい

備忘

Ansibleはプログラミング言語ではないので、loopなどを伴うデータ変換は苦手。
その様な際には、jinja2 loopを利用してYAMLとしてデータを構成し、データに変換し直すとうまくいくことがある。

# 例
以下の様なデータ変換を行う

## 元データ
```
- - hoge1
  - - foo: FOO1
      bar: BAR1
    - foo: FOO2
      bar: BAR2
- - hoge2
  - - foo: FOO3
      bar: BAR3
    - foo: FOO4
      bar: BAR4
```
## 変換先データ
```
hoge1:
- FOO1/BAR1
- FOO2/BAR2
hoge2:
- FOO3/BAR3
- FOO4/BAR4
```

## 変換task例

```
  - debug:
      msg: "{{ target_yml | from_yaml }}"
    vars:
    
      source_data:
      - - hoge1
        - - foo: FOO1
            bar: BAR1
          - foo: FOO2
            bar: BAR2
      - - hoge2
        - - foo: FOO3
            bar: BAR3
          - foo: FOO4
            bar: BAR4
            
      target_yml: |
        {% for i0 in source_data %}
        {{ i0[0] }}:
        {% for i1 in i0[1] %}
        - {{ i1['foo'] }}/{{ i1['bar'] }}
        {% endfor %}
        {% endfor %}
```
## 変換例
```
TASK [debug] ***************************************************************************************************************************
ok: [localhost] => {
    "msg": {
        "hoge1": [
            "FOO1/BAR1",
            "FOO2/BAR2"
        ],
        "hoge2": [
            "FOO3/BAR3",
            "FOO4/BAR4"
        ]
    }
}
```
XCTestでテスト実行しても「testing...」から進まない

## 背景
XCTest実行しても「testing...」からずっと進まない。

## 調査
[Xcode tests stuck in testing state](https://forums.developer.apple.com/forums/thread/729462)
> Also had the same issue, what worked is deactivating the "Execute in parallel" in the Tests options (Edit scheme -> Choose Test -> Select Test Plan and go to Options)

に書かかれている通り「Execute in parallel」のチェックを外すことで解決した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245300/7623b1c4-f573-d25f-c616-7e5d4aa62b44.png)
Power Automate Desktopの％％内でできること

## フロー変数
```javascript:変数の取得
%Value%
```

## シンプルなデータ型
```javascript:文字列リテラル
%'文字列'%
```

```javascript:文字列リテラル（数字も文字列として指定できる）
%'123'%
```

```javascript:数値リテラル
%123%
```

```javascript:ブール値リテラル
%True%
```
## 演算
```javascript:四則演算 → 2.5
%1 + 2 * 3 / 4%
```

```javascript:剰余 → 2
%5 mod 3%
```

```javascript:比較および論理演算子 → True
%'1' = 1 AND 'A' > 'a'%
```

```javascript:比較および論理演算子 → True
%NOT(4 <> 4)%
```
非等価演算子は`!=`で入力しても`<>`に変換されます。
論理演算子の組み合わせにより複雑なロジックを実装することができます。

```javascript:文字連結 → AB123
%'A' + 'B' + 123%
```

## 高度なデータ型
### List
```javascript:空のListの作成
%[]%
```

```python:Listの作成
%['A', 'B', 'C']%
```

```python:Listから要素の取得 → 2番目の要素
%List[1]%
```

```python:要素の追加 → [1, 2, 3, 4]
%[1, 2, 3] + 4%
```

### Datatable

```javascript:空のDatatableの作成
%{}%
```

```javascript:Datatableの作成
%{ ^['Column1', 'Column2', 'Column3'], ['A', 'B', 'C'], ['a', 'b', 'c'] }%
```
列数が可変のDatatableを作成できます。列名は`^`付きのリストで指定します。

```javascript:Datarowの取得
%Datatable[0]%
```

```javascript:値の取得（列インデックス指定）
%Datatable[0][0]%
```

```javascript:値の取得（列名指定）
%Datatable[0]['Column1']%
```

```javascript:行の追加
%Datatable + ['A', 'B', 'C'] + ['a', 'b', 'c']%
```
※ 列数を合わせる必要があります。

### カスタム オブジェクト
```javascript:カスタム オブジェクトの作成
%{ 'Key': 'Value' }%
```

```javascript:空のカスタム オブジェクトの作成
%{{ }}%
```

```javascript:値の取得（ドット表記法）
%CustomObject.Key%
```

```javascript:値の取得（ブラケット表記法）
%CustomObject['Key']%
```

# 参考資料

https://learn.microsoft.com/ja-jp/power-automate/desktop-flows/variable-manipulation
GitHub codespaces の豆知識

# はじめに
[GitHub Codespaces](https://docs.github.com/ja/codespaces/overview) の公式ドキュメントを読んでいて、勉強になった内容をまとめておきます。

## タイムアウト時間
`codespace` は、使用している間は実行され続けますが、一定時間非アクティブになるとタイムアウトします。 エディターとターミナル出力からのファイルの変更はアクティビティとしてカウントされるため、ターミナル出力が継続されていれば `codespace` はタイムアウトしません。 既定の非アクティブ タイムアウト期間は 30 分です。 

https://docs.github.com/ja/codespaces/getting-started/deep-dive#closing-or-stopping-your-codespace

## /workspaces ディレクトリ
`codespace` を作成すると、リポジトリが `codespace` 内の `/workspaces` ディレクトリに複製されます。 これは、コンテナーにマウントされる永続的なディレクトリです。ファイルの編集、追加、削除など、このディレクトリ内で行った変更は、`codespace` を停止して開始するとき、および `codespace` 内のコンテナーをリビルドするときに保持されます。

https://docs.github.com/ja/codespaces/getting-started/deep-dive#about-the-directory-structure-of-a-codespace

## Linux Universal Image
`Linux Universal Image` は `GitHub Codespaces` のデフォルトの `Ubuntu` ベースのイメージです。`Python`, `Node.js`, `JavaScript`, `TypeScript`, `C++`, `Java`, `C#`, `F#`, `.NET Core`, `PHP`, `Go`, `Ruby`, `Conda` 言語がインストール済みであるため、`All in One` な `codespace` 環境をセットアップしたい場合に有効です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/0ec7be6b-2d62-a9a0-2a38-11b0be44a19a.png)

### Linux Universal Image を使った .devcontainer.json
`codespace` 環境の初回のセットアップに時間がかかりますが、色々な言語が入った環境をセットアップしたい場合は `.devcontainer` の `image` に `mcr.microsoft.com/devcontainers/universal:linux` を指定することで、`Linux Universal Image` ベースのカスタムイメージを作成することが可能です。
```json:.devcontainer.json
{
	"name": "Ubuntu Universal Linux",
	"image": "mcr.microsoft.com/devcontainers/universal:linux",
	"features": {},
	"customizations": {
		"vscode": {
			"extensions": [
				"GitHub.copilot-chat",
				"GitHub.copilot"
			]
		}
	}
}

```

https://github.com/devcontainers/images/tree/main/src/universal

# おわりに
`GitHub Codespaces` の公式ドキュメントを読むと、想像以上に細かい機能や設定があることに気づきました。`GitHub Codespaces` の機能や設定のほんの一部しか知らない状態だと思うので、さらに勉強して快適で楽しい `GitHub Codespaces` ライフを目指したいと思います。
SAP Tutorialsで学ぼう

先日投稿したSAP BTP Free Trialで気がついたのですが、

https://qiita.com/IT_Tech_Firm/items/1f6c91be2807c1984f86

Start with Tutorialsなるメニューがありまして、
![スクリーンショット_2024-01-15_0_46_09.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1181562/7e6e6e20-0836-96a2-c6f0-3bebcb81211e.jpeg)

タイルをクリックすると、各チュートリアルの手順が表示されます。「＋」を押すと日本人好みの画像と解説付きの手順が表示されるので分かりやすいです。なぜ今までこういうものを作らなかったのか。
![スクリーンショット 2024-01-15 0.50.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1181562/2075a763-9de5-77e0-8056-75d61dea5846.png)

このSAP Tutorials自体は、こちらのリンクから開くことができます。手順をチェックするだけであればログインも不要です。
https://developers.sap.com/tutorial-navigator.html

ログインすると何ができるかというと、学習記録を残すことができます。下の画面ではDoneボタンが表示されていますが、ログインしていないとログインを促す文が表示されます。
![スクリーンショット 2024-01-15 0.57.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1181562/eaf94a04-a09e-dfb6-0864-299b7499e6c0.png)

Doneを押すとCompleteに変わります。
![スクリーンショット 2024-01-15 0.57.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1181562/80b43540-789d-b3fc-e39a-578f5b743eb1.png)

しかもこの学習コンテンツ、数がものすごいです。一連の手順がMission、細かい手順のひとかたまりがTutorialです。Missionは15分程度のものから11時間半の超大作まで様々です。平均すると2時間くらいな気がします。
![スクリーンショット 2024-01-15 1.01.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1181562/beac5d8d-020d-865c-f1de-86e5618508b6.png)

まるでMicrosoft Learningを思わせるコンテンツ、文章だらけでとっつきにくいMicrosoft Learningと比較して、1手順ごとに画像がついているので、セルフハンズオントレーニングをすることができます。これは良い。SAPが遂に本気を出してきた。

SAPの学習と言えば、数十万〜百万円超のトレーニング費用を支払わなければならず、e-learningのSAP Learning Hubでさえ1年間で数十万円という高級コンテンツでした。Open SAPという無料の学習コンテンツは、カンファレンスのプレゼンのような内容。

背景にはSAP Cloud, BTPを普及させたいという戦略があると思われます。世間ではSAPのクラウドと言えばAWSかAzureが一般的で、AWSとAzureは学習コンテンツと資格が非常に充実しているので、SAPも対抗してきていると推測します。これを機会に学習して、クラウド時代のSAPを制しましょう。
ABC336の記録

# はじめに
今週は日曜開催なんですね。

https://atcoder.jp/contests/abc336

成績：AB2完(300)

# A
"o" * nとすればoをn個出力できる。
```python:A
n = int(input())
print("L" + "o"*(n) + "n" + "g")
```

# B
bin()で10進数から2進数に変換できるので、変換した後に末尾から順に確認していき、0ならカウント、1ならループを抜ければ良い。

```python:B
n = int(input())
chara = bin(n)
cnt = 0
for i in range(-1, -len(chara), -1):
    if chara[i] == "0":
        cnt += 1
    else:
        break
print(cnt)
```

# C
「良い整数」は$p$桁目の数字が$5^{p-1}$ごとに0, 2, 4, 6, 8と変化し、$5^p$で一巡するという挙動をする。
なので、$p$桁目の数は$n-1$を$5^{p-1}$で割った商を5で割ったあまりに2をかけることで求められる。例えば$n$を5で割って商が0なら2桁目の数字は2、商が1なら4……となる。この商をさらに5で割っているのは、商が5なら商が0の時と同じことになるから。
1番目の数が0なので$n-1$を割らないとといけないこと、1桁目については値がずれることに気を付けて実装する。
```python:C
import math

def whatnum(n, p):
    return (n-1)//(5**(p-1))%5*2

n = int(input())
if n == 1:
    keta = 1
else:
    keta = math.floor(math.log(n-1,5)+1) #桁数を算出する。
ans = []
for i in range(keta, 1, -1):
    ans.append(str(whatnum(n,i)))
if n%5 == 1:
    ans.append(str(0))
if n%5 == 2:
    ans.append(str(2))
if n%5 == 3:
    ans.append(str(4))
if n%5 == 4:
    ans.append(str(6))
if n%5 == 0:
    ans.append(str(8))
print(''.join(ans))
```
ずいぶんと不格好になってしまった。まず桁数を確認してから下一桁以外はwhatnumという関数を定義して判定していき、下一桁はnを5で割った余りで対応するという方針。下一桁の処理はもっとやりようがある気がする……
また、joinを使って出力する際に文字列でないとエラーになるので文字列にしてからappendするという方法を取っている。


今回も考察不足のまま進んでしまうという悪癖が出た。各桁の数字がnに対してどのような挙動をするのかちゃんと考察できていなかったので、各桁の数字判定ができるようになるまで時間がかかってしまい時間切れに。ACできたのは終了5分後でした。
ちゃんと事象を理解し切ってから実装に進まないとダメ。

ちなみにn-1を5進数に変換するという発想ですぐ解けるらしい。言われてみればそうだ……ただそれに気づいたとしても、5進数への変換に手間取っていたような気もする。この変換方法は一度しっかり確認しておく必要がありそう。


日本代表が前半で3-0くらいにしてくれていればこんなことには……（言い訳）
git diff の各コマンドの違い

# 背景
`git diff --stat` をよく叩くが、`git diff` には複数の比較方法があるようで、いまいち以下3つの違いが分かっていない。
- `git diff --stat`
- `git diff main --stat`
- `git diff --cached --stat`

# 調べた結果
- `git diff --stat`
    - 前提：追跡されているファイル
    - ステージングと作業環境との差分を出してくれる。
    - 比較対象は ステージング:作業環境
    - `git status -s`　にて ?? になっている新規ファイルは含まれてこない。
- `git add .`
    - 変更をステージングに反映
- `git diff --cached --stat`
    - 比較対象は ステージング：最後のコミット内容
- `git diff main --stat`
    - 比較対象は 現在のブランチ：main
- `git commit -m "コメント"`

# 参考
一度もコミットしていない場合、以下は同じ結果になる
- `git diff --cached --stat`
    - 比較対象は ステージング：最後のコミット内容（main）
- `git diff main --stat`
    - 比較対象は 現在のブランチ：main

# 結果
あまりコミットを叩かない現段階では、git diff --stat だけでも良いかもしれない・・・・・
【CSS】スクロールバーのデザインを手軽におしゃれにする

# はじめに
一般的なWebサイトではグレー色のスクロールバーがあると思います。
その他の色がついているスクロールバーを見かけることは、ほとんどないのではないでしょうか。
気になったのでスクロールバーの色の変更方法を調べてみました。
本記事ではスクロールバーの色を変更する方法を紹介します。


# 作成するもの
スクロールバーとその背景の色にそれぞれグラデーションをかけています。

![scrollbar.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/a6d9f084-0dc0-9267-99c1-134bc0bf8628.gif)


# 環境
- vite：5.0.8
- React：18.2.43
- TypeScript：5.2.2

# ソースについて
スクロールするためにある程度高さのあるページを準備します。
高さが100vhの`section `タグを以下のように3つ作成しました。

```react:App.tsx
import './App.css'

export default function App() {
  return (
    <>
      <section>
        <div>hoge1</div>
      </section>
      <section>
        <div>hoge2</div>
      </section>
      <section>
        <div>hoge3</div>
      </section>
    </>
  )
}
```

```css:App.css
body {
  padding: 0;
  margin: 0;
}

section {
  height: 100vh;
  width: 100%;
  background-color: white;
  font-size: 5rem;
  text-align: center;
}
```

続いて本題のスクロールバーのデザインについてです。
- -webkit-scrollbar：スクロールバー全体の横幅の調整。

- -webkit-scrollbar-thumb：移動させるスクロールバーに`border-radius`で、
丸みを持たせています。
`background`プロパティで上下に水色⇔ピンク色のグラデーションを設定。

- -webkit-scrollbar-track：スクロールバーの背景に当たる部分の上下に、
`background`で水色⇔紺色のグラデーションを設定。

```css:App.css
// スクロールバー全体
::-webkit-scrollbar {
  width: 30px;
}

// 移動させるスクロールバー
::-webkit-scrollbar-thumb {
  border-radius: 30px;
  background: linear-gradient(0deg, #f8a8ff, #8ad3fa);
}

// スクロールバーの背景
::-webkit-scrollbar-track {
  background: linear-gradient(0deg, rgb(0, 50, 91), #d3e2ff);
}
```

<details><summary>main.tsx</summary>


```react:main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
)
```
</details>

# 実行結果
おしゃれなスクロールバーができました。
![scrollbar.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/1096726f-aa4d-f112-6e6b-7f5b5ac842c3.gif)

# 補足
次の画像のようにスクロールバーの背景がないように見せる事もできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/8a252412-486d-4541-efe6-fdd13e2e7dc5.png)


Webページの背景色とスクロールバーの背景色を揃えると、
スクロールバーの背景部分がないように見せる事ができます。
以下のCSSでは、Webページの背景色とスクロールバーの背景色を`aliceblue`に揃えています。

```css:App.css
section {
  height: 100vh;
  width: 100%;
  background-color: aliceblue;
  font-size: 5rem;
  text-align: center;
}

// スクロールバーの背景
::-webkit-scrollbar-track {
  background: aliceblue;
}
```
Linuxのタイムゾーンを変更したのに定期実行がUNIXタイムで実施された罠

# Linuxのタイムゾーンを変更したのに定期実行がUNIXタイムで実施された罠

## はじめに
- cronからsystemdのtimerの定期実行に変更した際に、なぜか定期実行がUNIX timeで実行された。
- dateで時間を調べてもJSTで取れているのになぜとなったので、作業ログとして残す

## 今回の環境
- Amazon EC2
- Amazon Linux 2023

## やったこと
- systemdのtimerを使って定期実行を設定
- LinuxのTimeZoneを日本時間（JST）に設定
    ```
    date
    Mon Jan 15 00:06:08 JST 2024
    ```

## なにがダメだったのか
- systemdにもtimedatectlという独自のTimeZone設定が存在したこと
    - 実際に見てみる
    ```sh
    timedatectl
               Local time: Sun 2024-01-14 15:09:59 UTC
           Universal time: Sun 2024-01-14 15:09:59 UTC
                 RTC time: Sun 2024-01-14 15:09:58
                Time zone: n/a (UTC, +0000)
    System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no
    ```
    確かにUTCだったわ…

## 設定をJSTに変更する
- 利用可能なタイムゾーンを確認するために
    - `timedatectl list-timezones`
    ```sh
    timedatectl list-timezones
    Africa/Abidjan
    Africa/Accra
    Africa/Addis_Ababa
    Africa/Algiers
    Africa/Asmara
    Africa/Asmera
    Africa/Bamako
    Africa/Bangui
    Africa/Banjul
    ```
    よし、やばそうだからgrepしよう…
    Asiaで絞ったら99件あったので、抜粋
    ```
    timedatectl list-timezones | grep Asia | wc -l
    99
    ```
    ```
    Asia/Thimphu
    Asia/Tokyo
    Asia/Tomsk
    Asia/Ujung_Pandang
    Asia/Ulaanbaatar
    Asia/Ulan_Bator
    ```
    Asia/Tokyoよし！

- 設定する
    - `sudo timedatectl set-timezone 設定するタイムゾーン名(今回はAsia/Tokyo)`
    - `sudo timedatectl set-timezone Asia/Tokyo`
- 確認
    - `timezonectl`
    ```sh
    timedatectl
                   Local time: Mon 2024-01-15 00:17:37 JST
               Universal time: Sun 2024-01-14 15:17:37 UTC
                     RTC time: Sun 2024-01-14 15:17:36
                    Time zone: Asia/Tokyo (JST, +0900)
    System clock synchronized: yes
                  NTP service: active
              RTC in local TZ: no
    ```
    よさそうですね～！

## まとめ
- この経験から、Linuxのタイムゾーン設定の重要性を再認識した
- systemd timersとcronの使い分けについて、状況に応じて検討することが重要ですね
JUnitのパラメーター化テストでパラメーターに名前を付ける方法

JUnitにはパラメーター化テストを実施したい場合に便利な機能があります。
以下のように`@ParameterizedTest`と`@ValueSource`を付けてパラメーターを指定することで、一つのメソッドで指定したパラメーターをテストすることができます。

### `ValueSource`
```java
    @ParameterizedTest
    @ValueSource(strings = {"0311111111", "08011111111"})
    public void phoneNumber_is_10_11_digits(String phoneNumber) {
        assertTrue(isPhoneNumber(phoneNumber));
    }
```
テスト結果：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458231/147f43b1-c225-81da-60bb-a9f3c01d8b4d.png)

しかし、このやり方ではパラメーターの値しか指定されていないため、パッと見て何をテストしているのかが判断できません。
パラメーターに説明などを付け加えて分かりやすいテストを書いていきたいです。

そこで、以下のように`@ValueSource`の代わりに`@MethodSource`を付けて、パラメーターに名前を指定したメソッドのメソッド名を指定することで、テストコードを見てどのようなパラメーターをテストしているかがわかりやすくなります。

### `MethodSource`
```java
    @ParameterizedTest
    @MethodSource("phoneNumberProvider")
    public void phoneNumber_is_10_11_digits(String phoneNumber) {
        assertTrue(isPhoneNumber(phoneNumber));
    }

    static Stream<Arguments> phoneNumberProvider() {
        return Stream.of(
                arguments(Named.of("10桁の固定電話番号", "0311111111")),
                arguments(Named.of("11桁の携帯電話番号", "08011111111"))
        );
    }
```
テスト結果：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458231/7f555a57-55b1-2d99-8c5d-bf23e27c63ad.png)

テスト結果もわかりやすくなりました。
VisualStudio で ctrl + /

###  拡張機能
Toggle Commentの拡張機能をインストールすることで
Ctrl + / でのコメントが可能になる

vscodeではできるのに…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3658170/f2837e9a-8dd4-6b8a-5af4-1663c46c63be.png)
Mindで倍精度整数を使ってみる

# はじめに
諸般の流れから日本語プログラミング言語Mindで固定小数点計算機能を書いてみようかなと思い立ち、Mind開発者の@killyさんからMind8に倍精度整数があると伺ったのでさっそく使ってみました。

# お題のソースコード
```mind:decimal.src
int32は　変数。
int64は　倍精度変数。

メインとは
	int32に　2147483647を　入れ
	int32を　数値表示し　改行し
	int32を　NOTし　数値表示し　改行し
	int32を　1だけ　左シフトし　数値表示し　改行し
	int32を　1だけ　右シフトし　数値表示し　改行し
	改行し
	int64に　2147483647を　入れ
	int64を　数値表示し　改行し
	int64を　NOTし　数値表示し　改行し
	int64を　1だけ　左シフトし　数値表示し　改行し
	int64を　1だけ　右シフトし　数値表示し　改行し
	改行し
	int64を　＄＄クアド表示し　＄＄改行し
	int64を　NOTし　＄＄クアド表示し　＄＄改行し
	int64を　1だけ　左シフトし　＄＄クアド表示し　＄＄改行し
	int64を　1だけ　右シフトし　＄＄クアド表示し　＄＄改行。
```

倍精度整数の変数名はよくわからなかったので、「倍精度変数」としたらコンパイラ通過しました。ただし、普通に整数文字を代入するとデフォルトの32bit整数になっているようで、11桁以上の数値は代入できませんでした。

# 実行結果
では実行してみましょう。
```
(コンパイル)
コンパイル中 .. 終了

(実行)
2147483647
-2147483648
-2
1073741823

2147483647
-2147483648
-2
1073741823

7FFFFFFF|00000000
80000000|00000000
FFFFFFFE|00000000
3FFFFFFF|00000000
```
「＄＄クアド表示」という便利単語でコンソール出力して改みると、倍精度整数の残り32bitは使われていないようでした。

ちなみに11桁入れようとすると下記のようにコンパイラに怒られました。
```
(コンパイル)
コンパイル中 .. 終了
1 個のエラーが有ります。

------infファイル内容ここから------
decimal.src 12 行目でエラー。行内容は、
	int64に　21474836470を　入れ
      要因１：数値の記述が誤りです。

------infファイル内容ここまで------
```

# お題のソースコード（改）
倍精度変数への代入方法を、「＄＄クアド表示」という便利単語を発見したsampleF\小数変数.srcというサンプルコードに書かれていた、文字列情報合成して代入する方法に書き換えてみます。

```diff:decimal.src
+	0ffffffffHと　099999999Hを　無処理し　文字列情報合成し　int64に　入れ
-	int64に　2147483647を　入れ
```

# 実行結果（改）
では実行してみましょう。
```
(コンパイル)
コンパイル中 .. 終了

(実行)
2147483647
-2147483648
-2
1073741823

-1
0
-2
2147483647

FFFFFFFF|99999999
00000000|99999999
FFFFFFFE|99999999
7FFFFFFF|99999999
```
「数値表示」は32bit部からしか出力できていないようですが、「＄＄クアド表示」では残り32bit部にも値が入ったことがわかります。
標準ビット操作単語は32bit部にのみ作用している感じ。

# つづく
しばらくつづきます:sweat_smile:


## この記事内容の作業環境
Windows11 Pro 22H2
CPU Intel(R) Core(TM) i3-5005U 2.00 GHz
Mind Version 8.0.08 for Windows
【TailwindCSS】背景のグラデーション

## 右へグラデーション

```html
<div class="h-20 bg-gradient-to-r from-blue-500"></div>
```

![スクリーンショット 2024-02-03 23.55.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/234af28b-75ba-4ce1-1cbd-d384ef16b1c0.png)

## 左へグラデーション

```html
<div class="h-20 bg-gradient-to-l from-blue-500"></div>
```

![スクリーンショット 2024-02-03 23.56.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/0f6c8163-b736-cd81-933e-35c4d7741c7e.png)

## 上へグラデーション

```html
<div class="h-20 bg-gradient-to-t from-blue-500"></div>
```

![スクリーンショット 2024-02-04 0.01.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/d3e7bc88-acb2-e499-f127-e7c520f29284.png)

## 下へグラデーション

```html
<div class="h-20 bg-gradient-to-b from-blue-500"></div>
```

![スクリーンショット 2024-02-04 0.03.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/877d5c36-70b7-cab9-4f2e-9e0a6a80af08.png)

## 右上へグラデーション

```html
<div class="h-20 bg-gradient-to-tr from-blue-500"></div>
```

![スクリーンショット 2024-02-04 0.09.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/fb809d4a-fc45-7163-f9c8-8263eb17579a.png)

## 左上へグラデーション

```html
<div class="h-20 bg-gradient-to-tl from-blue-500"></div>
```

![スクリーンショット 2024-02-04 0.11.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/65b4c53e-3a71-7d46-459e-e19ce5dd8886.png)

## 右下へグラデーション

```html
<div class="h-20 bg-gradient-to-br from-blue-500"></div>
```

![スクリーンショット 2024-02-04 0.14.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/4a826655-d357-6542-9cad-a89f0b64c0c2.png)

## 左下へグラデーション

```html
<div class="h-20 bg-gradient-to-bl from-blue-500"></div>
```

![スクリーンショット 2024-02-04 0.16.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/9d540949-e50f-ac92-076b-a81d813f5ca5.png)


## 終了色

```html
<div class="h-20 bg-gradient-to-b from-blue-500 to-red-500"></div>
```

![スクリーンショット 2024-02-04 0.05.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/eae07922-bc2b-d806-608b-52576f09ad77.png)


## 中間色

```html
<div class="h-20 bg-gradient-to-b from-blue-500 via-yellow-500 to-red-500"></div>
```

![スクリーンショット 2024-02-04 0.07.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/47b4d51f-aef6-b917-d231-9dc641581a74.png)

## ホバー時に反転

```html
<div class="h-20 bg-gradient-to-b from-blue-500 to-red-500 hover:bg-gradient-to-t"></div>
```

![スクリーンショット 2024-02-04 0.18.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/53e4320b-9287-03d8-fa38-26207158e3c6.png)

ホバー時
![スクリーンショット 2024-02-04 0.22.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/f71cc83b-ed57-55ab-04ba-7fe1704c9082.png)
6つのアクセス修飾子の公開範囲を理解しよう！

# アクセス修飾子とは
クラスやメソッドに外部からの使用の制限をもうけるために使用する修飾子。
公開範囲を指定できる修飾子は下記の6つあります！
**Swift5.9からpackageが追加されました。**
公開範囲が広い順で言えば、
**open > public > package > internal > fileprivate > private**
# アクセス修飾子を使用するメリット
`class、struct、enum、func、var、protocol`等の公開範囲をできるだけ狭くしてあげることで、意図しないところで外部から呼び出され、使用することを防ぐことができる！
# 6つのアクセス修飾子
6つのアクセス修飾子について説明する前にパッケージ、モジュールについて先に説明します！
## パッケージとは
パッケージとは、Swift Package Managerによって表現されるように、コード配布の単位です。いくつかのパッケージは単一のモジュールだけを含みますが、パッケージのコードを複数のモジュールに分割することも有用である。パッケージのコードを複数のモジュールに分割する例としては、モジュールがいくつかの`internal helper APIs`を含むとき、それらのAPIはユーティリティモジュールに分割することができ、他のモジュールやパッケージによって再利用される。
## モジュールとは
モジュールとは、コードを配布する際の単一のユニットです。
**フレームワークやアプリケーションのこと。**
フレームワークやアプリケーションは単一のユニットとしてビルドされて提供される。
モジュールを作成するには、Swift Package Managerでビルドターゲットを定義する！
**1つのビルドターゲットに対して、1つのモジュールが定義される。**
提供されたモジュールは、import キーワードを使って別のモジュールからインポートすることができる！
下記のような記述をよく見ると思いますが、Appleが公開しているFoundationフレームワークはモジュール内外のすべてのアクセスを許可しているため使用できる！
```Swift
import Foundation
```

## open
モジュール内外のすべてのアクセスを許可。

## public
モジュール内外のすべてのアクセスを許可。
ただし、`open`と異なり、モジュール外でクラスを継承したり、オーバーライドすることはできない。

## package
**Swift5.9からpackageが追加されました。**
定義されたモジュールの外側からアクセスされることを許可しますが、同じパッケージ内の他のモジュールからのみアクセスされます。これにより、パッケージ間の境界を明確に設定することができる。
`public`と同じように、モジュール外でクラスを継承したり、オーバーライドすることはできない。
コンパイラーは、2つのモジュールが同じパッケージ名でビルドされた場合、それらが同じパッケージに属しているとみなす。

現在、他のモジュールにアクセスするには、`public`と宣言する必要がある。しかし、`public`であることは、パッケージ内とパッケージ外の両方から、どのモジュールからでもそのシンボルにアクセスすることを可能にしてしまいます。このようなシンボルの可視範囲をよりコントロールできるようにするためには、新しいアクセス修飾子`package`が必要です。

**参考文献**

https://github.com/apple/swift-evolution/blob/main/proposals/0386-package-access-modifier.md

**ターゲットが1つであり、モジュールが1つのプロジェクトは下記の3つのアクセス修飾子を使用する！**

## internal　**（デフォルト）**
同一モジュール内のアクセスのみを許可。
アクセスレベルを明示的に書かないときは、デフォルトでinternalが設定される。
同一モジュール内のファイルであれば、どのファイルからもアクセス可能！

## fileprivate
同一のファイルのみアクセスを許可。
ファイル外からアクセスすることはできない。
```Swift:Playground
class FileClass {
    fileprivate func say() {
        print("同一のソースファイルのみアクセスを許可")
    }
}

FileClass().say()
```
出力結果
```
同一のソースファイルのみアクセスを許可
```



## private
定義されたスコープ内のアクセスのみを許可。
```Swift:Playground
class FileClass {
    private func say() {
        print("定義されたスコープ内")
    }
}

FileClass().say()
```
fileprivateからprivateにアクセス修飾子を変更すると下記のようなエラーになる！

:::note alert
'say' is inaccessible due to 'private' protection level
:::
保護レベルが「プライベート」であるため、「say」にはアクセスできません。というエラーになる！
# 参考文献



https://swift.codelly.dev/guide/%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB/#%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%83%AC%E3%83%99%E3%83%AB

https://qiita.com/Howasuto/items/bbbbbcb6bffa72c17484

https://swift.tecc0.com/?p=631

https://github.com/apple/swift-evolution/blob/main/proposals/0386-package-access-modifier.md

https://github.com/apple/swift-evolution/blob/main/proposals/0386-package-access-modifier.md
Google ColabとAWSを連携して、boto3を使う方法

# はじめに
Lambda関数を実装するなら、まずGoogle Colabでコードの挙動をひとつずつ確かめながら書いていく方が課金を抑えられるのではと気づいたので、手順をまとめました。

# 1.AWS設定ファイルをGoogle Driveに保存する
- config
- credentials
:::note info
macなら
~./aws/config
~./aws/credentials

Windowsなら
%USERPROFILE%.aws\config
%USERPROFILE%.aws\credentials
:::

https://docs.aws.amazon.com/ja_jp/sdkref/latest/guide/file-location.html

# 2.Google Driveのマウント
```py
from google.colab import drive
drive.mount('/content/drive')
```

# 3.AWS認証設定
```py
import os

config_file = "/content/drive/MyDrive/[保存フォルダ]/config"
os.environ['AWS_CONFIG_FILE'] = config_file

credentials_file = "/content/drive/MyDrive/[保存フォルダ]/credentials"
os.environ['AWS_SHARED_CREDENTIALS_FILE'] = credentials_file
```

# 4.boto3のインストール
```
!pip install boto3
```

# おわりに
無料利用枠があるとはいえ、舐めない方がいい。
たかが塵、されど塵。
塵も積もればかなりの課金になる。
herokuにデプロイしたrailsアプリケーションにfaviconを設定する

## 下準備
faviconに設定したい画像のサイズを300×300 pxに設定しておく


## 下記サイトでfaviconを作成していく
https://realfavicongenerator.net/

![IMG_7065.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533777/797a28c8-7b24-ab83-e698-3858d7e2fc4a.jpeg)

- *select your favicon image*を押下
→iOS、Android Chrome、macOS Safariなどに対応するfaviconを自動生成してくれる。

※背景色等も好みに合わせて変更可能
<br>

- Favicon for Android Chrome設定画面にて、*App name*にアプリケーション名を入力する
![IMG_7066.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533777/7f8fbfad-845a-47f9-e246-4aab59db7558.jpeg)

- 指定が終わったら画面下の
*Generate your Favicons and HTML code*を押下すると、ダウンロード画面に遷移する

![IMG_7067.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533777/2bf630ab-3b7c-0ed0-4863-34d4bcf9fcb5.jpeg)

- *Favicon package* を押下し、作成されたfavicon達をダウンロード、解凍する
<br>

- 解凍したフォルダを任意の名称にリネーム（今回はfavicons）する
<br>

- app/assets/images配下にfaviconsディレクトリを配置する
</br>

- app/views/shared/_favicon.html.erbを作成し、
- ダウンロード画面の項番3 *Insert the following code in the <head> section of your pages*
の内容をコピペし、以下のようにfavicon_link_tagを使用する形で書き直す。
```
<%= favicon_link_tag 'favicons/favicon.ico', rel: 'shortcut icon', type: 'image/x-icon' %>
<%= favicon_link_tag 'favicons/favicon-32x32.png', rel: 'icon', sizes: '32x32', type: 'image/png' %>
<%= favicon_link_tag 'favicons/favicon-16x16.png', rel: 'icon', sizes: '16x16', type: 'image/png' %>
<%= favicon_link_tag 'favicons/android-chrome-192x192.png', rel: 'icon', sizes: '192x192', type: 'image/png' %>
<%= favicon_link_tag 'favicons/android-chrome-256x256.png', rel: 'icon', sizes: '256x256', type: 'image/png' %>
<%= favicon_link_tag 'favicons/apple-touch-icon.png', rel: 'apple-touch-icon', sizes: '180x180', type: 'image/png' %>
<%= favicon_link_tag 'favicons/safari-pinned-tab.svg', rel: 'mask-icon', color: '#5bbad5' %>
<link rel="manifest" href="<%= asset_path('favicons/site.webmanifest') %>">
<meta name="msapplication-TileColor" content="#2b5797">
<meta name="msapplication-TileImage" content="<%= asset_path('favicons/mstile-150x150.png') %>">
<meta name="theme-color" content="#ffffff">
```


app/views/layouts/application.html.erbのheadタグ内に以下を記載する。
```
<%= render 'shared/favicon' %>
```

## 詰まりポイント
app/views/shared/_favicon.html.erbの中身をfavicon_link_tagに書き換えないと、「ローカル上ではfaviconが表示されるが、heroku上では表示されない」問題が発生、ド　が付くほどハマった。

## 参考
https://marketing-web.hatenablog.com/entry/rails_favicon

https://qiita.com/TheOkachanPG/items/9167ba77d1edf7addac2