OmniAICreator/Qiita-1.07M huggingface dataset:
Nginxのインストール手順(EC2インスタンスにSSH接続後)

## アジェンダ
このガイドでは、AWS EC2インスタンスにSSH接続後、Nginxをインストールし、サンプルHTMLページを表示する手順を解説します。

## 事前準備(EC2インスタンスにSSH接続)
EC2インスタンスにSSH接続方法をまだしてない人は以下の記事を参考にしてください。

https://qiita.com/kimascript/items/4128dfee27c45f3f9726

## 手順
### 1. Nginxのインストール
- EC2インスタンスにSSHで接続したら、まずシステムをアップデートし、Nginxをインストールします。
```bash
sudo apt update -y
sudo apt install nginx -y
```

### 2. Nginxの起動と設定
- Nginxを起動し、ステータスを確認します。
```bash
sudo systemctl start nginx
sudo systemctl enable nginx
sudo systemctl status nginx
```

### 3. HTMLファイルの配置
- Nginxのデフォルトディレクトリ `/usr/share/nginx/html/` にHTMLファイルを配置します。以下のコマンドでディレクトリに移動し、`index.html`を編集します。
```bash
cd /usr/share/nginx/html/
sudo vi index.html
```

### 4. Webブラウザでの確認
- ブラウザでインスタンスのパブリックIPを入力し、Nginxのデフォルトページや作成したHTMLが正しく表示されることを確認します。

これで、EC2インスタンスにNginxをインストールし、HTMLファイルを配置してWebサイトを表示する手順が完了します。

## 参考
- [パブリックなIPアドレスを経由してEC2インスタンスへSSH接続するポイントをまとめてみた | DevelopersIO](https://dev.classmethod.jp/articles/ssh-connection-is-available/)
- [AWS EC2 Nginxを使ってWebサイトホスティング](https://zenn.dev/nakam_aws/articles/1ccd870200ff59)[.](https://qiita.com/kimascript/private/6cf6cc3b92896e4165bd)
新人エンジニアの読書録 『単体テストの考え方/使い方』 chap.1

今回は、新人エンジニアが「単体テストの考え方/使い方」の第一章を読んだので、備忘録としてまとめてみました。今後、読書録シリーズの続編も出す予定です（予定です）。

では、早速本題へ→

## chap.1 なぜ単体テストを行うのか？

単体テストを書くうえで、テストにかける労力をできる限り抑え、テストから得られる効果を最大限に引き出すことが重要。

- 労力と効果のバランスを取るためには、良いテストと悪いテストを見分けることが必要
    - 費用対効果を分析する
    - 状況に応じた単体テストのテクニックを使う
    - アンチパターンを避ける方法を知る

### 単体テストの現状

単体テストの実施は当たり前。捨て去られること前提のプロジェクトでない限り、必ず書かれる。

- 現在の課題は、「単体テストを書くべきか」ではなく「良い単体テストを書くとはどういう意味か？」

### なぜ、単体テストを行うのか

単体テストは、ソフトウェア開発を、持続可能なものにするために行う。

- テストを書かずにプロダクト開発を続けると、コードが劣化しすることによって「ソフトウェアエントロピー（無秩序）」が増加し、コードへの信頼がなくなり、いずれ開発が止まってしまう。しかし、単体テストがあれば、一部のコードの変更による「退行（regression）」を検出することができるため、安定した品質を担保することができる。

![qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638231/5f7cb033-248e-a56a-7c2c-50f4e89f8af3.png)

- 単体テストの唯一のデメリットは、テストを書く「労力」である。しかし、開発初期からテストを書くことで、「持続のしやすさ」と「成長のしやすさ」を備えることができ、長い目で見て「適切な開発スピード」を維持できるようになる。

*退行： 特定の変更をした後、意図したように動かなくなること。バグ。

### 何がテストの質を良くし、何がテストの質を悪くするのか？

単体テストはただ書けば良いのではなく、「質の良い」テストを書かなければいけない。たとえば、テストに時間がかかりすぎたり、退行を検出できなかったり、保守コストがかかりすぎた理、間違った理由でテストが失敗することが増えすたりれば、テストの存在によって、プロダクト開発の進行が脅かされる。

また、テストコードの保守コストは、以下のような作業の積み重ねで増加する。

- プロダクションコードのリファクタに伴い、テストコードをリファクタすること
- プロダクションコードを変更するたびに、テストを実施すること
- テストが間違って失敗したとこに、その対処をすること
- プロダクションコードがどのように振る舞うかを理解するために、テストコードを読むこと

### 網羅率とテスト・スイートの質との関係

網羅率：テストケースが実行するプロダクションコードの割合

一般に、網羅率は高いほど良いとされるが、「高ければ良い」わけではない。

- たとえば、網羅率10％であれば、テストが十分でないことがわかるが、網羅率100％だからと言って、テストの品質が良いとは限らない。

### コード網羅率と分岐網羅率について

コード網羅率 ： プロダクションコードの総行数に対する、テスト時の実行行数。実行されたコードの行数÷総行数

分岐網羅率 ：プロダクションコードの分岐路に対する、テスト実行時に経由される分岐の数。経由された経路の数÷分岐経路の数

### 網羅率の問題

1. 網羅率からは、実際にテスト対象のコードが検証されたのかを保証できない
    - 網羅率は、プロダクションコードが「実行された割合」を示すため、その結果が検証されたことを保証していない。
    - 確認不在のテスト：プロダクションコードを実行しているにも関わらず、結果を検証していないテストコード
    
    ```python
    import pytest
    
    def example(num):
    		if num < 5:
    				return "short"
    		else:
    				return "long"
	
    def test_example(num):
    		actual == example(num) # プロダクトコードを実行
    ```
    
2. 網羅率を算出する際、使用するライブラリなのコードは計測の対象から外れる

### 網羅率まとめ

網羅率は、「テストが十分に行われていないこと」を検証するための数値であり、「良いテストであること」を保証するものではない。加えて、高い網羅率を義務付けるような使い方をすると、かえって開発の妨げとなる可能性が高い。

### 何がテスト・スイートの質を良くするのか？

テストケースの良し悪しを、定量的に自動で判断する方法は存在せず、結局のところ、１つずつ個人が判断するしかないが、優れたテストスイートの特徴を挙げることは可能である。

1. テストすることが開発サイクルに組み込まれている
    → コードが変更されるたびに、テストを実行する必要がある
2. コードベースの、特に重要な部分のみがテスト対象になっている
    → プロダクションコードのうちの重要な箇所（ドメイン・モデル、ビジネスロジック）のみに、テストの労力をかけることが重要
    
3. 最小限のコストで、最大限の価値を生み出すようになっている
    → 上記には、以下が必要
        * 価値のあるテストケースを認識できること
        * 価値のあるテストケースを作成できること


### 感想
個人的に、「テストすることが開発サイクルに組み込まれている」ことが重要だなと感じています。

元々、私が参画しているプロジェクトでは、ユニットテストを書いていませんでしたが、テストを書く習慣がついてからは、予期せぬバグが減ったのはもちろん、自分自身のコードへの理解力が上がったり、プロダクションコードを綺麗に書こうという気持ちが強くなったりしました。
この本の概要を理解できたら、使っているテストフームワークの勉強を体系的にしてみたいなと思ってます。


*今回の本はこちら↓
https://www.amazon.co.jp/%E5%8D%98%E4%BD%93%E3%83%86%E3%82%B9%E3%83%88%E3%81%AE%E8%80%83%E3%81%88%E6%96%B9-%E4%BD%BF%E3%81%84%E6%96%B9-Vladimir-Khorikov/dp/4839981728
【典型90問】 成長記録 #002

# [典型90問 002 - Encyclopedia of Parentheses（★3）](https://atcoder.jp/contests/typical90/tasks/typical90_b)
概要としては長さN列のカッコ列を出力する問題。
方針だけ解説で見たところbit全探索のアルゴリズムを用いて解くっぽい。

## bit全探索とは
〇×のような、それぞれ二つの選択肢がある問題に対して、すべての組み合わせを1~nとすると、二進数に変換したときに1と0ですべての組み合わせを表すことができる。このようなアルゴリズムをbit全探索という。
一般的に全探索するため要素数がn≦20程度の場合に用いる。
基本的なbit全探索の型は以下のサイトを参考にして学んだ。

[Python bit全探索を簡単にやるコツ](https://qlitre-weblog.com/python-bit-all-search-easy-trick#google_vignette)

### 脳筋コード
```python
n = int(input())
k = []　   #生成した配列を格納するリスト

for i in range(2 ** n):
  if i == 0:
    continue
  l = 0
  ans = True
  for j in range(n):
    if (i >> j) & 1:
      l += 1
    else:
      l -= 1
    if l < 0:
      ans = False
      break
  if ans and l == 0:
    l = ''
    for j in range(n):
      if (i >> j) & 1:
        l += '('
      else:
        l += ')'
    k.append(l)  

k.sort()
for i in k:
  print(i)
```

## 感想
アルゴリズムを使わないと解けない問題を初見で解けたのはこれが初めてなので大きな一歩だと思う。
これからも地道に頑張りたい...!
あと最近atcoderをやっていて思うのが、いかにループの中で無駄な処理を減らせるかが処理速度に大きく影響するという事。
ThinkPadがThunderbolt4 Dockにつながってくれなくて困る

# はじめに

純正とそれ以外のThunderbolt4ドッックで、だいたい半年に一回ぐらいのペースでTB4ドックにつなげてもドック経由の画面出力に不具合が生じています。

なぜかメンテナンス時に裏蓋を開ける時にバッテリーからの電源供給を遮断するために使用する、UEFIからPowerメニューの**Disable built-in battery**を選択して電源を入れ直すとTB4ドックが利用できるようになることに気がつきました。

本当の原因は他にありそうですが、状況についてまとめておきます。

:::note
いまのところ複数メーカーのThunderbolt4 Dockと1つのThinkPad T14 gen2(Intel版)の間で現象が発生しています。
状況からはThinkPad側に問題がありそうですが、根本原因の特定や解決には至っていません。
:::

# 環境

* ThinkPad T14 gen2 (CPU: i7-1165G7)
* Lenovo ThinkPad ユニバーサル Thunderbolt 4 ドック (40B00135JP)
* Micro Solution TB4D110-MSJ -90W PD Charge (Amazon)
* j5 create JTD568 Thunderbolt4 15in1 クワッドディスプレイ ドッキングステーション

# 不具合の症状

ドッキングステーションにもよりますが、共通して発生するのは次のような症状です。

* DisplayPort出力のみが使えなくなる (USB-Audio, USBハブなど一部の機能は使える)
* ドッキングステーションを認識しない

ThinkPadとLenovo社製TB4 Dockがよく使われている組み合わせなので報告もそれなりに上がっています。

冒頭に書いたようにUEFIモードから内蔵バッテリーを無効にするメニューを選択して、再度電源を入れ直すと改善しています。

これを[Lenovo Communityの記事](https://forums.lenovo.com/t5/Displays-Options-and-Accessories/Thunderbolt-4-Universal-dock-2nd-external-monitor-blank-on-Nano-X1/m-p/5100445?page=8#6428085)に報告していますが、同じ方法で改善したというレポートはないので正しい対応なのか分かっていません。

このスレッドをみると、複数のThinkPadとドッキングステーションの組み合せでDisplayPort出力がうまく動作していないとの報告が上がっています。

返品も行われているようなので、Lenovoもそれなりに認識していそうですが、根本的な解決には至っていないようです。

# 他の機器にある似たような現象

ThinkPadを使っているとケーブルで接続する一般的なドックよりも、ThinkPad ウルトラ・ドッキング・ステーションのような一体型のドックを好んで使っている場合もありそうです。

TB4に対応したモデルがないのでUSB-Cの転送速度に不満があってTB4ドックに乗り換えましたが、一体型のドッキングステーションでも時々画面出力がされないような現象に遭遇していました。

ただ、その場合はドック側の電源ケーブルを抜き差しすることで改善していました。

DisplayPortの出力が特徴的なのでモニターとの相性を疑うこともありそうですが、TthinkPad側のTB4チップやその機能に問題があるように感じています。

# さいごに

発見した内蔵バッテリーの無効化という回避策はあまりにも納得感がないのでどうにかして欲しいです。

macOSに昔からあるターゲットディスクモードのような機能があれば常にTB4関連回路に電源が供給されているとか、内部に接続情報を保持しているとかあって関連しそうですが、ThinkPadで内蔵バッテリーが接続されていると何等かの不具合が発生するとは考えにくいような気がします。

そのため他に真の原因がありそうです。

いずれにしてもThinkPadと接続したドッキングステーションとの相性問題はあまり表面化していないような印象ですが、困っている人は確実にいるので何らかの参考になれば幸いです。

以上
＃46　Chromeをゲーミング仕様にしてみた

## 概要

拡張機能を作成してChromeをゲーミング仕様にしてピカピカ光らせてみました。
正直文字が読みにくくなるだけなので需要はないと思いますが、
テンションを上げたいときや目を覚ましたいときにどうぞ！

## 導入後画面

このように、あらゆるページで画面上の文字が虹色に光ります。
ブログ用に画質を落として録画しているので少し滲んで見えますが、実際はきれいに表示されます。

![gaming_text1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3843084/9ea9fe2c-9c34-fb32-6622-3198f307a7db.gif)

![gaming_text2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3843084/1deb6bf4-000f-b839-79a3-9558ee4e13a8.gif)


## 導入方法

1. 以下の2ファイルを同じフォルダーに配置してください

```json:manifest.json
{
    "manifest_version": 3,
    "name": "gaming_theme",
    "version": "1.0.0",
    "description": "chromeをゲーミングにします",
    "content_scripts": [
        {
            "matches": ["<all_urls>"],
            "css": ["gaming.css"],
            "all_frames": true
        }
    ]
}
```

```css:gaming.css
*,*::before,*::after {
    animation:rainbow 5s infinite;
    -webkit-animation:rainbow 5s infinite;
}
@keyframes rainbow{
    12%{color:#ff5353;}
    24%{color:#ffcf53;}
    36%{color:#e8ff53;}
    48%{color:#53ff5d;}
    60%{color:#53ffbc;}
    72%{color:#5393ff;}
    84%{color:#ca53ff;}
    100%{color:#ff53bd;}
}
```
2. 「chrome://extensions/」にアクセスしてください
3. ページ右上の「デベロッパーモード」をONにしてください
4. ページ上部に開発者用メニューが表示されるので、「パッケージ化されていない拡張機能を読み込む」をクリックし、コードを配置したフォルダを選択してください

## おまけ: もっとゲーミングに

gaming.css のcolorの部分をbackground-colorにすることで、文字色ではなく背景色がゲーミングになります。
文字色の変更だけだと物足りないという方はお試しください。

```css:gaming.css
*,*::before,*::after {
    animation:rainbow 5s infinite;
    -webkit-animation:rainbow 5s infinite;
}
@keyframes rainbow{
    12%{background-color:#ff5353}
    24%{background-color:#ffcf53}
    36%{background-color:#e8ff53}
    48%{background-color:#53ff5d}
    60%{background-color:#53ffbc}
    72%{background-color:#5393ff}
    84%{background-color:#ca53ff}
    100%{background-color:#ff53bd}
}
```

![gaming_background1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3843084/07869d11-600f-3b5c-8ff5-7c072dbd8c3b.gif)

![gaming_background2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3843084/1bc26dd5-2e9f-5c68-503d-0a488f84475a.gif)


最後まで読んでいただきありがとうございます。

## 参考

* [虹色に色が変わるアニメーションスタイルの設定 | animation | CSS | HTML](https://www.it-the-best.com/entry/css-animation_rainbow)
SSH パスワードレスの手順

1. クライアント側で以下の鍵を発行する操作をする 
 
``` 
ssh-keygen -t ed25519 
``` 
``` 
Generating public/private ed25519 key pair. Enter file in which to save the key (/root/.ssh/id_ed25519): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/id_ed25519. Your public key has been saved in /root/.ssh/id_ed25519.pub. The key fingerprint is: SHA256:lfXUOABCdeFGHIJKPibkPe8lsXgXDX2WjcdFJy1234BY9FE root@rhel8.4-test The key's randomart image is: +--[ED25519 256]--+ |o ..+ . .o | |+. . X Eo.oo .| |.+ o . = Xoo ... | |o = + + =.+ | | o X = .S= | | o = + + . | | * . o | | = . . | | . | +----[SHA256]-----+ 
```
``` 
cd /root/.ssh cat id_ed25519.pub 
``` 
#### ～中身の例～ 

``` 
ssh-ed25519 AAABD3NxfC1lZDI1ABCDEXXXXIIHJ6nanvGGpMnDEXwpDd9YgxYu7ikiQGgB/Zn99HFOs root@rhel8.4-test 
``` 
2. ホストに登録 

```
cd /root/.ssh 
``` 

* id_ed25519.pub viで 上記で生成したの `～中身の例～` を追記する 
 
この設定で以降のsshでパスワードを聞かれなくなる
Leetcode Day1

**今日からLeetcodeをやっていく!**

今日から毎日Leetcodeをやろうと思う。
1問目はLinked List cycle
https://leetcode.com/problems/linked-list-cycle/submissions/1379361223/

目次
-----------------

* [LinkedList](#linkedlist)
* [LinkedListとArrayListの違い](#difference-between-linked-list-and-array-list)
* [Linked List Cycle](#linked-list-cycle)

---

## LinkedList
### とは何か?

まずは、LinkedListが何かを知らなかったので調べた。

https://astrostory.hatenablog.com/entry/2020/02/24/070213

```python
class LinkedList:

        class Node:

            def __init__(self, payload):

                self.payload = payload

                self.next = None


        def __init__(self):

            self.head = None


        def addNode(self, newpayload):

                newnode = LinkedList.Node(newpayload)

                if self.head == None:

                        self.head = newnode

                        return

                else:   #最後のノードに連結するケース

                    runner = self.head

                    while runner.next != None:

                        runner = runner.next

                    runner.next = newnode


links = LinkedList()

links.addNode(26)

links.addNode(99)

links.addNode(127)

links.addNode(42)

links.addNode(367)
```

## コードの動き方

このコードは階層構造で以下のようなリンクドリストを構築する。
* Node(26)
    * payload = 26
	* next = Node(99)
		+ payload = 99
		+ next = Node(127)
			- payload = 127
			- next = None


### `links = LinkedList()`

Linked Listオブジェクトが作られる。

この時Linked List.__init__ も動き self.head(= LinkedList.head)=Noneと設定される

### `links.addNode(26)`

addNode関数が動く。

newnode = LinkedList.Node(newpayload)によりnewnodeにNodeクラスが代入されNode(26)が作られる。またこの時Node.initも動きself.payload = newpayload = 26, self.next = Noneとなる。

次にself.head = None なので self.head = newnode = Node(26)が代入される。

### `links.addNode(99)`

addNode関数が動く

newnode = LinkedList.Node(newpayload)によりnewnodeにNodeクラスが代入されNode(99)が作られる。

次にself.head = Node(26) != None なのでelseとなる。

runner = self.head = Node(26) となる。

runner.next = Node(26).next = None なのでrunner.nextにnewnodeが代入される。つまりNode(99)が代入される。

ここでNode()はpayload = 26, next = Node(99) を変数にもつくクラスとなる。

### `links.addNode(127)`

同様に行いNode(99).next = Node(127)となる。

## LinkedListとArrayListの違い
https://qiita.com/BumpeiShimada/items/522798a380dc26c50a50

*   LinkedList 
    * 順序を持たない
    * 要素がリンクで繋がっている
    * 途中の要素を削除するスピードが速い
    * 特定の要素にアクセスするスピードが遅い

*   ArrayList 
    * 順序を持つ
    * 要素が順序で繋がっている
    * 要素を削除するスピードが遅い
    * 特定の要素にアクセスするスピードが速い

## Linked List Cycle
https://qiita.com/toshi_machine/items/3b2a5c04da949ac78298

Linked List Cycleの解法を解説してくれるものがあったのでこのコードを使ってみるとうまくいった。Fast nodeとSlow nodeは知らないと思いつかなそう。

Leet code は classの内容を実装するだけで良い。
Atcoderだとinputもいちいち書かなきゃいけなかったので入出力も書かなきゃいけないものかと思ってちょっと調べた

明日もやる。
Next.jsでページ遷移後、リロードする

ページ遷移後、遷移先をリロードしたいと思い、うまくいったやり方があったので綴ります。

```js#home.jsx
'use client'

import {useRouter, useSearchParams} from 'next/navigation';

const Home = () => {
  const searchParams = useSearchParams();
  const router = useRouter();

  //パラメータを割り当てる
  const isReload = seachParam.get('reload');
  const isReload2 = localStorage.getItem('reloaded');
  if (isReload && !isReload) {
    localStorage.setItem('reloaded','true');
    router.replace('/home');
    window.location.reload();
  } else if(!isReload) {
    localStorage.removeItem('reloaded');
  }
  
  return <Child />
}

export default Home;
```

```js#child.jsx
'useClient'
//next/navigationからインポートする
import useRouter from 'next/navigation'

const Child = () => {
  const router = useRouter();

  const handleClick = () => {
    router.push('/home?reload=true');
  }
  
  return <button onClick={handleClick}>遷移する</button>
}

export default Child;
```

window.location.reload()を実行すると無限にページをリロードしてしまうので少し工夫が必要でした。

初めは下記を記述していました。

```js
let isReload = true;

if (isReload) {
  isReload = false;
  window.location.reload();
}
```

ダメですね。リロードするたびに変数の値がtrueに戻ってしまうせいで無限リロードしました。

そこでローカルストレージに保存する方法を試すとうまくいきました。

```js#home.jsx
const isReload = seachParams.get('reload');
const isReload2 = localStorage.getItem('reloaded');

if (isReload && !isReload) {
  localStorage.setItem('reloaded','true');
  router.replace('/home');
  window.location.reload();
}
```

初めはローカルストレージに何も入っていないので反転させてtrueを返し、ifの中でtrueをセットするようにしています。
その後、useSearchParamsにパラメータを返さないように置き換えています。

```js#home.jsx
} else if(!isReload) {
  localStorage.removeItem('reloaded');
}
```

上記のelse ifを記述しないと無限にリロードされるので注意です。

それと今回はクライアントサイドで実装しているのでuseRouterをnext/navigationからインポートするところも注意です。

# 補足
```
window.location.href="/home"
```
これだけで良かったです！
難しいこといらんかった！
超初心者向け！AWSコンテナサービス「Amazon ECS」入門

## はじめに

皆さんこんにちは！今日はAWSのコンテナサービス「Amazon ECS」について解説します。

**Amazon ECSとは？**

Amazon ECSは、AWSが提供するコンテナを管理するサービスです。簡単に言うと、**コンテナを動かすための「家」と「管理人」**のようなものです。

**なぜ使うの？**

- **コンテナを簡単に管理できる:** コンテナの配置やスケーリング、監視など、複雑な作業を自動化してくれるので、開発者はアプリケーションに集中できる
- **AWSサービスとの連携がスムーズ:**  他のAWSサービスと連携しやすいので、クラウド環境での開発が効率的になる
- **コスト効率が良い:** コンテナの実行環境は、必要な時に必要な分だけ利用できるので、無駄なコストを削減できる

**Amazon ECSの構成**

Amazon ECSは大きく分けて、「コントロールプレーン」と「データプレーン」の2つの部分で構成されています。

- **コントロールプレーン:** コンテナの管理を行う部分です。AWSが管理
- **データプレーン:** コンテナが実際に動作する部分です。Amazon EC2またはAWS Fargateのどちらかを選択が可能

**Amazon EC2とAWS Fargateの違い**

- **Amazon EC2:** コンテナホストを自分で管理する必要があります。柔軟性が高いですが、管理の手間がかかり面倒
- **AWS Fargate:** コンテナホストの管理はAWSに任せることができます。管理の手間が少なく、より簡単に利用ができる

**Amazon ECSの基本機能**

- **タスク定義:** コンテナの動作に関する設定を定義します。イメージ、CPU/メモリ、ネットワーク設定などを指定できる
- **タスク:** タスク定義に基づいて実行されるコンテナの単位
- **サービス:** 長時間実行されるアプリケーションを管理する機能です。タスクのスケーリングやロードバランシングなどの機能を提供
- **クラスター:** タスクやサービスを実行するための環境です。複数のAmazon EC2インスタンスやAWS Fargateで構成

**Amazon ECSの始め方**

- **AWSマネジメントコンソール:**  AWSの管理画面から簡単に設定
- **ドキュメント:**  AWSのドキュメントには、詳細な設定方法やチュートリアルが掲載

**まとめ**

Amazon ECSは、AWSのコンテナサービスとして、開発者がアプリケーションに集中できる環境を提供します。AWS Fargateを利用することで、さらに簡単にコンテナを運用できます。ぜひ、Amazon ECSを試してみて下さい！

**関係資料**
[Amazon ECS 入門【AWS Black Belt】 - YouTube](https://www.youtube.com/watch?v=stpz_SNiWmA)
[Amazon ECS 入門【AWS Black Belt】 - PDF](https://www.youtube.com/redirect?event=video_description&redir_token=QUFFLUhqa1lNZFQxdWJFRHkxTXJLT2YwbVpjSEYxVENud3xBQ3Jtc0trbm83MFhKS0V0bHptczdjOFV5aWpoSWFBX0RZeU9CaTgzLVkxUXBqWFNWUk9xQzFnT0pfZ21FaDY0Yzd3ZlhEY3J5VVJsMnJQQVlyc2hKaGkyOVBRSDB6MGNObGt1ZEFJeFY1NmVsRnUxME5DWWVnaw&q=https%3A%2F%2Fpages.awscloud.com%2Frs%2F112-TZM-766%2Fimages%2FAWS-Black-Belt_2024_Amazon_ECS_Introduction_0831_v1.pdf&v=stpz_SNiWmA)
[Amazon Elastic Container Service の開始方法](https://aws.amazon.com/jp/ecs/getting-started/)
[Amazon ECS の料金](https://aws.amazon.com/jp/ecs/pricing/)
[Amazon ECS に関する AWS Blog 記事](https://aws.amazon.com/jp/blogs/news/tag/amazon-ecs/)
GCP API 呼び出し時の「PERMISSION_DENIED」の解決方法

GCPのAPIGWで作成したAPIを呼び出す際に発生した`PERMISSION_DENIED`エラーとその解決策についてのメモ書きです。

# エラー内容

```json
{
   "message":"PERMISSION_DENIED:API xxxxxx.apigateway.xxxxxx.cloud.goog is not enabled for the project.",
   "code":403
}
```

# 解決策
以下コマンドを実行し、APIの有効化を行います。

```bash
PROJECT=<project id>
SERVICE=xxxxxx.apigateway.xxxxxx.cloud.goog

gcloud services enable ${SERVICE} \
--project=${PROJECT}
```

# 参考URL
- https://cloud.google.com/endpoints/docs/openapi/enable-api?hl=ja
1年目エンジニアが初プロジェクトで色々やらかした話

## はじめに

この記事では、私がエンジニア1年目に経験した初めてのプロジェクトでのミスと、そこから学んだことをシェアします。同じような境遇の方々にとって、少しでも参考になれば幸いです。

## プロジェクト概要

受託開発のプロジェクトで、既存システムの機能拡張を担当しました。基本的には私一人で作業していましたが、途中から上司がサポートに入り、二人で取り組む形になりました。

## 自分のミスと学んだこと

### 1. PR管理方法の変更によるコミュニケーションロス

#### ミスの概要

PRの提出頻度を誤りました。当初はIssue単位でPRを出す予定でしたが、途中で機能単位に変更され、その後再びIssue単位に戻りました。PRの管理方法が二転三転したことで、混乱を招き、PRの確認が遅れてしまい、結果として開発全体の進捗にも悪影響が出ました。

#### 解決策

まずは実際に進めてみて、その結果に基づいてフィードバックをもらうことが大切でした。お客様の要望に応えるのは当然ですが、お客さん的にも「やってみたら思っていたのと違った」は起こり得ます。そのため、お客様の反応が良くない場合は、早めに再確認をしておくと良いと思います。

また、進捗が遅れてから対応するのでは手遅れになることが多いので、早めの対応が時間の節約に繋がります。また、上司に相談することで、より効率的な方法を教えてもらえることもあります。

### 2. PRの重複指摘

#### ミスの概要

同時に二つのPRを出していた際、両方で同じ指摘を受けていました。レビュワーに余計な時間を取らせてしまいました。

#### 解決策

指摘事項はどこかにメモとしてまとめ、PRを提出する前にチェックリストとして確認する習慣をつけました。以前のPRで指摘された内容を反映しておけば、次のPRでの修正が不要になり、効率が上がります。

また、指摘された内容が理解できない場合は、その場で確認することが大切だと思います。理解せずに放置すると、同じ指摘を繰り返されることになりかねないため、指摘の意図や背景の把握が大切だと思います。

指摘の意図を確認する際は、「相手にとってのメリット」を意識しました。「〜さんの設計思想や、指摘の意図を知ることで、同様の指摘を減らしたり、今後の開発にもその設計思想を反映することで、より良い設計のコードを作りたいと思います。」とすると、レビュワーの負担も軽減することを伝えられるので、相談しやすくなります。

### 3. 動作確認のパターン漏れ

#### ミスの概要

動作確認を行う際、自分が想定していたパターンのみを確認していましたが、パターンが複雑になると確認漏れが発生してしまいました。これが原因で、納期が迫った状況でミスが頻発し、信頼の低下につながってしまいました。

#### 解決策

動作確認のパターンを事前にまとめておくことで、確認漏れを防ぎ、安心して確認作業を進めることができました。また、パターンを整理することで時間短縮にもつながりました。

### 4. 仕様の勘違いと大幅な手戻り

#### ミスの概要

仕様書の内容を誤解していたため、仕様変更を二度も行うことになり、既に開発した部分にも修正が必要となりました。その結果、本来不要だった工数がかかってしまいました。

#### 解決策

「自分と相手の考えが一致していないこと」や「相手も人間でミスや勘違いがあること」を意識し続けることが重要でした。仕様書の内容に対して自分の解釈が正しいと思い込まず、会議の場で認識のすり合わせを行えるとベストだと思います。少しでも「おや？」となった箇所は、確認できるとベストかな、と思います(とはいえ、それが出来たら苦労しないのですが、、、)。

### 5. 迷ったら「一度作る」か「相談してみる」

#### ミスの概要

どこから作ればいいのか？、この設計で問題ないのか？、他にベストプラクティスはないのか？

設計や実装方法に迷った際、判断に時間をかけすぎたことで、進捗が滞り、報告する内容もなく一日が終わってしまいました。

#### 解決策

迷ったら、一度試しに実装してみるか、相談してみることが大切だと思います。

既存の実装との兼ね合いから、想定通りの挙動をしないことは、よくあると思います。つまり、今の想定している実装方法そもそもが、不適切であるということです。
そのため、現在想定している実装のベストプラクティスを考えるより、一旦は実装してみる方が、結果的にうまくいきました。
また、進捗報告時にも、コーディングが進んでいないと、「進捗してない」ように映る可能性があります。それを避けるためにも、一旦実装するのは大切だと思いました。

また、相談も大切です。

自分が想定している設計方法では、実装に時間がかかる、コードのロジックが複雑になる。しかし、相談により良い設計を思いつくかもしれません。

ただ、この時に準備は徹底して行いました。「今悩んでいること」・「相談したいこと」・「現状の他の実装方法」・「現在想定の設計方法とその問題点」、最低この四つは準備 + 必要な資料のURLや、画面共有の準備までした上で、相談をしました。

ここでもたつくと、次の相談がしにくくなるため、準備は徹底した方がいいと思います。

## 終わりに

先輩のエンジニアであれば、私が犯したようなミスは未然に防いでいることが多いです。また、私よりも良い解決策も知っています。自分で考えた上で、「もっと良い方法はないか？」と尋ねることが大切だと感じました。

プロジェクトに初めて参加するエンジニアは、ミスをするのは仕方ないことだと思います。ただ、同じミスを防げるかが、大切だと感じました。

この記事が少しでも参考になれば幸いです。
もし、先輩エンジニアの方で、こうした方がいいというアドバイスがございましたら、ぜひ教えていただきたいです！
【Flutter】スプラッシュ画像を設定する


## はじめに
アプリのスプラッシュ画像を設定したので、その備忘録を記載します。


## 画像の選定方法
Android12にも対応できるように以下のサイズに設定しました。
- 画像サイズは縦横1152px
- 縦横768pxの円の中に画像を収める
- ファイル形式 png
- 背景透過あり

### 画像の配置

```
assets
└── images
    └── splash
        └── splash.png
```

## パッケージのインストール
[flutter_native_splash](https://pub.dev/packages/flutter_native_splash/install)を使用します
```
dev_dependencies:
  flutter_native_splash: ^2.4.1
```


## pubspec.yamlに設定を追加
pubspec.yamlの一番下に以下の設定を追加します。
```
flutter_native_splash: 
  color: "#000000"  #背景色指定
  image: "assets/images/splash/splash.png"  #スプラッシュ画像を指定
  android_12: 
    icon_background_color: "#000000"  #Android12用の背景色指定
    image: "assets/images/splash/splash.png"  #Android12用のスプラッシュ画像を指定
  android: true
  ios: true
  fullscreen: true  #trueで通知バーが非表示になる 
```


## 自動生成
以下のコマンドを叩くと、スプラッシュ画面の設定が実行されます。
```
flutter pub get
flutter pub run flutter_native_splash:create
```

## 注意点

iOSの場合はflutter_native_splashを使用してスプラッシュ画面を実装すると、アプリでステータスバーが表示されなくなってしまいます。

対策としては、アプリの起動後すぐに、下記メソッドを実行するとステータスバーが表示されるようになります。

```

import 'package:flutter/services.dart';

・・・

// ステータスバーが常に表示されるように設定
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
    
・・・
```


## Android12の動作確認

Android12の場合は、デバック実行してもスプラッシュ画面は表示されませんでした。

以下の記事より、Android12の場合はデバック実行→アプリを閉じる→アイコンタップから起動しないと、スプラッシュ画面は表示されないようです。

https://zenn.dev/susatthi/articles/20220406-061305-flutter-native-splash#android-12-%E3%81%A7%E3%83%87%E3%83%90%E3%83%83%E3%82%B0%E5%AE%9F%E8%A1%8C%E6%99%82%E3%81%AB%E3%82%B9%E3%83%97%E3%83%A9%E3%83%83%E3%82%B7%E3%83%A5%E7%94%BB%E5%83%8F%E3%81%8C%E8%A1%A8%E7%A4%BA%E3%81%95%E3%82%8C%E3%81%AA%E3%81%84:~:text=%E9%9D%9E%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88%E3%81%A7%E3%81%99%E3%80%82-,Android%2012%20%E3%81%A7%E3%83%87%E3%83%90%E3%83%83%E3%82%B0%E5%AE%9F%E8%A1%8C%E6%99%82%E3%81%AB%E3%82%B9%E3%83%97%E3%83%A9%E3%83%83%E3%82%B7%E3%83%A5%E7%94%BB%E5%83%8F%E3%81%8C%E8%A1%A8%E7%A4%BA%E3%81%95%E3%82%8C%E3%81%AA%E3%81%84,-Android%2012%20%E7%AB%AF%E6%9C%AB



## 画像を入れ替えたい場合

画像を入れ替えたい場合は、assets/images/splash内の画像を入れ替え、再度以下のコマンドを実行すると再生成されます。
```
flutter pub get
flutter pub run flutter_native_splash:create
```
※画像のファイル名を変更する場合は、pubspec.yamlの参照パスも変更が必要です。



## 参考
https://zenn.dev/susatthi/articles/20220406-061305-flutter-native-splash

https://halzoblog.com/error-bug-diary/20220922-2/


# 告知
最後にお知らせとなりますが、イーディーエーでは一緒に働くエンジニアを
募集しております。詳しくは採用情報ページをご確認ください。

https://eda-inc.jp/recruit/

みなさまからのご応募をお待ちしております。
【Flutter】アプリアイコンを設定する


## はじめに
アプリアイコンを設定する方法について備忘録です。

## 画像の選定
### iOS
- 1024x1024のサイズ（正方形）
- 透過度は使用しない
- アルファチャネルなし

### Android
- 512×512のサイズ（正方形）
- 真ん中の直径312pxの円の中にコンテンツを収める
- アルファチャネルなし

### 注意すること
画像のアルファチャネルがはいになっていると、アプリ申請時にリジェクトされるので、注意が必要です。

・画像のアルファチャネルを確認する方法
対象の画像を右クリックして「情報を見る」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772194/30a31752-015c-0cc8-ee8d-1f70ada3a8a1.png)

アルファチャンネルの項目が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772194/263bb13d-d599-49cf-33db-1a73ccc79215.png)


・画像のアルファチャネルをいいえにする方法
画像を右クリックし、画像をプレビューで開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772194/e69ccdb5-c8d0-349d-12c8-9a224faf596c.png)

開いたプレビュー画面でファイル＞書き出すを選択します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772194/82fb5735-70d5-cb75-a900-278b9e884eb7.png)

出力先の選択で、アルファのチェックボックスのチェックを外して保存するとアルファチャネル：いいえの画像を出力できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772194/9be3c526-a982-c3e0-e1e7-553d6f430131.png)


アルファチャネルの設定方法については以下の記事を参考にさせていただきました。

https://qiita.com/SNQ-2001/items/4f02b0eed4674015ec06

## 画像の配置
用意したAndroid、iOSの画像をそれぞれ以下のように配置します。
```
assets
└── launcher_icon
    └── android_icon.ong
    └── ios_icon.ong
```

## パッケージのインストール
[flutter_launcher_icons](https://pub.dev/packages/flutter_launcher_icons)を使用します。
```
dependencies:
  flutter_launcher_icons: ^0.13.1
```

## pubspec.yamlに設定を追加
以下をpubspec.yamlの一番下に記載します。
```
flutter_icons: 
  image_path_android: assets/launcher_icon/android_icon.png
  adaptive_icon_background: '#000000' #iconの背景色
  adaptive_icon_foreground: assets/launcher_icon/android_icon.png
  image_path_ios: assets/launcher_icon/ios_icon.png
  android: true
  adaptive_icon_padding: true
  min_sdk_android: 30 #Androidの最小SDKバージョン
  ios: true   
```

## 反映
以下のコマンドを実行すると、アプリアイコンの設定が自動生成されます。
```
flutter pub get
flutter pub run flutter_launcher_icons:main
```

## アイコンを変更したい場合
アイコンを変更したい場合は、画像を入れ替え後、再度以下のコマンドを実行すると設定が更新されます。

```
flutter pub get
flutter pub run flutter_launcher_icons:main
```



## 参考
https://zenn.dev/hott3/articles/flutter-launcher-image

https://qiita.com/SNQ-2001/items/4f02b0eed4674015ec06

# 告知
最後にお知らせとなりますが、イーディーエーでは一緒に働くエンジニアを
募集しております。詳しくは採用情報ページをご確認ください。

https://eda-inc.jp/recruit/

みなさまからのご応募をお待ちしております。
【TypeScript】superの役割について図解で解説する

# はじめに

superの役割について以下まとめます。

# 本題

## 全体観

superの役割を図で示すと下記の通りになります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661690/f0f18746-bf10-c42b-3ffe-c255c1686573.png" width="500">


また、具体例を交えたソースコードを記述すると下記のようになります。

```ts
// 親クラス
class Parent {
  constructor(public lastName: string, public firstName: string, public age: number) {
  }

  doIntroduction(this: Parent): string {
    return `Hello! My name is ${this.firstName} ${this.lastName}. I am ${this.age} years old.`;
  }
}

// 子クラス
class Child extends Parent {
  constructor(public lastName: string, public firstName: string, public age: number, public hobby: string) {
    super(lastName, firstName, age);
    this.hobby = hobby;
  }

  doDetailIntroduction(this: Child): string {
    return super.doIntroduction() + ` My Hobby is ${this.hobby}.`;
  }
}

// ①親クラスのコンストラクタ関数→親クラスの関数の呼び出し
const father = new Parent("Taro", "Tanaka", 52);
const introduceFather = father.doIntroduction();
console.log(introduceFather); // "Hello! My name is Tanaka Taro. I am 52 years old."

// ②子クラスのコンストラクタ関数→親クラスの関数の呼び出し
const myself = new Child("Jiro", "Tanaka", 24, "soccer");
const introduceMyself = myself.doIntroduction();
console.log(introduceMyself); // "Hello! My name is Tanaka Jiro. I am 24 years old."

// ③子クラスのコンストラクタ関数→子クラスの関数の呼び出し
const introduceDetailMyself = myself.doDetailIntroduction();
console.log(introduceDetailMyself); // "Hello! My name is Tanaka Jiro. I am 24 years old. My Hobby is soccer."
```

## superはどんな時に役立つ？

<font color="red">**継承先の関数を呼び出す時**</font>に役立ちます。
継承とは、上図のように、子クラス(Childクラス)から親クラス(Parentクラス)を呼んで、子クラスだけでなく親クラスの関数を使えるようにした関係をいいます。これにより継承は、コーディングの手間が省けることで可読性が向上し、さらに機能を拡張しやすくなる利点があります。

そんな継承先の関数を呼び出す時に使えるのが`super`メソッドになります。
そのため、上記のソースコードにおける「②子クラスのコンストラクタ関数→親クラスの関数の呼び出し」が可能になります。

## どのようにsuperメソッドを使うの？
### コンストラクタ関数の呼び出し
`super(変数1,変数2,変数3...)`にて、親クラスのコンストラクタ関数を呼び出すことができます。

### 親クラスの関数の呼び出し
`super.関数()`にて、親クラスの関数を呼び出すことができます。

# 最後に

今回は、`super`メソッドについて解説しました。
今までしっかりと理解できていなかったのですが、アウトプットしたことでかなり整理できたなと思いました。
AWS CLIを使用してキャパシティ不足でタスク起動に失敗したイベントを確認する

# 背景
仕事でAWS ECS（Elastic Container Service）を使ってWebアプリを開発・運用しています。ECSのScheduled Taskを使って定期的にバッチを実行をしているのですが、ある日バッチの実行結果の通知が届かず、またCloudWatch logsでもログを確認できませんでした。CloudTrailでECSのRunTask APIの呼び出し履歴を確認すると、以下の実行結果があり、調べるとキャパシティ不足でタスク起動に失敗したことが分かりました。

```json:CloudTrail
{
  "eventVersion": "1.09",
  "eventSource": "ecs.amazonaws.com",
  "eventName": "RunTask",
  （中略）
  "responseElements": {
    "failures": [
      {
        "reason": "Capacity is unavailable at this time. Please try again later or in a different availability zone"
      }
    ],
    "tasks": []
  }
}
```

対応を検討する以前にまず上記事象がどれくらいの頻度で発生しているのかを確認するために`aws cloudtrail lookup-events`コマンドを使ってRunTask APIの実行結果、ステータスコードは200が返って来たが、結局タスク起動に失敗した件数をカウントしました。

# 前提条件
- AWS CLIをインストールし、接続情報の設定が完了していること
- jqコマンドをインストールしていること
- Mac環境であること（WindowsやLinux環境の場合はコマンドの一部を要修正）

# コマンド
RunTask APIの実行結果、ステータスコードは200が返って来たが、結局タスク起動に失敗したCloudTrailのイベントレコードを取得するコマンドは以下のようになりました。

```bash:aws cli
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=RunTask \
  --start-time $(date -u -v -90d '+%Y-%m-%dT%H:%M:%SZ') \
  --query 'Events[*].CloudTrailEvent' \
  --output text | jq -c 'select(.responseElements.failures | length > 0)'
```

それぞれのオプションを説明すると、

- `--lookup-attributes`: 特定のイベントをフィルタリングするためのオプションで、今回EventNameとしてRunTaskを指定しています。RunTaskはECSタスクの起動を試みる際に記録されるイベントになります。
- `--start-time`: 過去のイベントを検索するための開始時刻を指定します。3ヶ月前（90日前）から現在までのイベントを対象にしています。dateコマンドを使用して動的に生成します。
- `--query`: クエリを使用して、特定のデータをフィルタリングします。イベントの詳細情報であるCloudTrailEventを取得します。
- `--output text`: 出力形式をテキストに指定します。jqでさらに処理が可能になります。
- `jq -c 'select(.responseElements.failures | length > 0)'`: jqコマンドを使用して、取得したイベントの中からfailuresフィールドにエラーが存在するものをフィルタリングします。

上記コマンドで、RunTask APIの実行結果、ステータスコードは200が返って来たが、結局タスク起動に失敗したCloudTrailのイベントレコードを取得できるようになりました。

# 参考
[RunTask API を用いた ECS タスク実行時に気をつけたいこと４選](https://developers.play.jp/entry/2023/10/27/150024)
[Fargateを利用したECS Scheduled Taskでタスクが起動しない事象について](https://shmokmt.hatenablog.com/entry/2023/07/26/223117)
Dynamic FormsのUIのエラー

[Dynamic Formsに戻る](https://qiita.com/Keiji_otsubo/items/6378661963228b54417a)

---------------------

2パターンあるみたい

# > をクリックしないといけない場合

+ [On Click Acount Name > I am getting "Select an insertion point." as warning is coming, ](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007akMBQ)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/0bd01d02-981c-2e04-c920-eb61010fe848.png)

:::note
Need to click >, it is working
:::

これ？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/592abd37-0a6c-3289-1fa5-3406eb4c8fd9.png)

+ [Get Hands-on with Related Object Fields on Dynamic Forms - I am unable add Account Revenue from Account](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007akMBQ)

+ [select an insertion point](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007akMBQ)

:::note
Try clicking below

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/8b981dec-580b-4d7a-64d4-9cd35e1f1f82.png)
:::



# タブをクリックしないといけない場合

+ [Create a Custom Lightning Record Page](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007akatY)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/678afb6f-7865-b089-af96-3e7b35bd7573.png)

+ [Record Detail component gives "Warning"](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007ifkX8)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/fa9c0687-8581-1a79-13a6-fcc61b79096e.png)


:::note
then instead clicking it, drag the component and drop it in the page below the details tab.

https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007XIXDJSA5
:::

# 別件

+ [動的フォームを使用していますが、特定のレコード タイプで突然編集ボタンと複製ボタンが機能しなくなるという問題が発生しています。たとえば、編集ボタンをクリックすると、ポップアップには保存の可能性のみが表示され、編集はまったくできません。 ](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007JAN1f)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/e8f784f3-93d6-6f4c-8b42-a29e40e4b6d5.png)

:::note
更新: Lightning ページに、類似のフィールドを持つ 2 つの動的フォームと、それらのフィールドの 1 つに基づいた表示フィルターがありました。重複するフィールドを汎用セクションに移動し、[新規] ボタンからレコードを作成できました。

https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000A97NUSAZ
:::

# アップグレードの方法が分からない

+ [Facing issue with Migrate a Record Page to Dynamic Forms](https://qiita.com/Keiji_otsubo/items/6378661963228b54417a)

:::note
Open the contact record details page and do the following:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/e15ce945-4466-8d0a-ee14-133164c6a615.png)
:::

# 必須項目のエラー

+ [Need help in resolving an issue with Contact Lightening record page.](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000KE0vz)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/2fca9379-ab17-4bdd-ae90-f6e77eb53c0d.png)

:::note
Please check this article.  


https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000J5HPd0AN
:::
Nuxt 3 の警告 - warning: <tr> cannot be child of <table>, according to HTML specifications.

# 問題

Nuxtを起動するとWarningが表示される

```
 warning: <tr> cannot be child of <table>, according to HTML specifications. 
This can cause hydration errors or potentially disrupt future functionality.
```

# 対応

Nuxtバージョンアップで `<table>` 直下に `<tr>` を書くと警告されるようになったので、
`<table>` 配下には `<thead>` や `<tbody>` を書くようにすれば良い

例:

```html
<table>
  <thead>
    <tr>
      <th>***</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>***</td>
    </tr>
  </tbody>
</table>
```


# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# プロフィール・経歴

https://github.com/YumaInaura/YumaInaura
【スプレッドシート】知っておきたい便利なテクニック＆関数集

# 目次

1.[テクニック編](#1-テクニック編)
- [1.1次の空セルまで選択](#11-次の空セルまで選択ctrl--shift--矢印windows--command--shift--矢印mac)
    
- [1.2 次の空セルまで移動](#12-次の空セルまで移動ctrl--矢印windows--command--矢印mac)
    
- [1.3 値貼り付け](#13-値貼り付けctrl--shift--vwindows--command--shift--vmac)
    
- [1.4 転置して貼り付け](#14-転置して貼り付け右クリック--特殊貼り付け--転置して貼り付け)
    
- [1.5 テキストを列に分割](#15-テキストを列に分割)
    
- [1.6 範囲選択して複数セルにデータを一括入力](#16-範囲選択して複数セルにデータを一括入力ctrl--enterwindows--command--entermac)
    
2.[関数編](#2-関数編)
    
- [2.1 ROW()](#21-row)
    
- [2.2 CONCATENATE()](#22-concatenate)
    
- [2.3 COUNTIF()](#23-countif)
    
- [2.4 INDIRECT()](#24-indirect)
    
- [2.5 IMPORTRANGE()](#25-importrange)
    

---

Googleスプレッドシートを使っていると、ちょっとした効率化のために役立つテクニックや関数があることに気付きます。今回は、私が日常的に使用しているスプレッドシートのテクニックと関数をご紹介いたします。

## 1. テクニック編

### 1.1 次の空セルまで選択：`Ctrl + Shift + 矢印（Windows）` / `Command + Shift + 矢印（Mac）`

次の空白セルまで一気に範囲を選択できる便利なショートカットです。大量のデータを効率よく選択したい場合に最適です。

### 1.2 次の空セルまで移動：`Ctrl + 矢印（Windows）` / `Command + 矢印（Mac）`

次の空白セルやデータのあるセルに一気に移動したい場合に活躍します。手動でスクロールする手間を大幅に省くことができます。

### 1.3 値貼り付け：`Ctrl + Shift + V（Windows）` / `Command + Shift + V（Mac）`

書式を無視して値だけを貼り付けます。関数によって求められた結果の値のみをペーストする際に非常に便利です。

### 1.4 転置して貼り付け：右クリック → 特殊貼り付け → 転置して貼り付け

行と列を入れ替えてデータを貼り付けたい時には、「転置して貼り付け」機能が便利です。使い方は、**貼り付けたいセルを選択し、右クリックして「特殊貼り付け」→「転置して貼り付け」を選ぶだけ**です。データを整理する際やレイアウトを変えたい時に頻繁に使われます。

### 1.5 テキストを列に分割

データがカンマやスペースで区切られている場合、それを複数の列に分割できます。特定の形式のデータを扱いやすくするために、メニューから「データ」→「テキストを列に分割」で簡単に利用できます。

### 1.6 範囲選択して複数セルにデータを一括入力：`Ctrl + Enter（Windows）` / `Command + Enter（Mac）`

範囲内の複数セルに同じデータを一括で入力したい場合に使えるショートカットです。**一括で入力したいデータを先頭に複数のセルを選択し、`Ctrl + Enter（Windows）` / `Command + Enter（Mac）`を押すと、すべての選択されたセルに一括で同じ内容が入力されます**。

手動でコピー＆ペーストする必要がなくなり、効率よくデータを入力できます。

---

## 2. 関数編

### 2.1 `ROW()`

`ROW`関数は、指定されたセルの行番号を返します。行ごとの計算や処理が必要な場面で役立ちます。

**使用例**：

```
=ROW(A2)  // A2セルの行番号を返します。

```

### 2.2 `CONCATENATE()`

`CONCATENATE`関数は、複数のセル内容を結合して1つの文字列にまとめます。

**使用例**：

```
=CONCATENATE(A1:F1)  // A1からF1の値を結合し、一つの文字列にします。

```

### 2.3 `COUNTIF()`

`COUNTIF`は、指定した条件に一致するセルの数をカウントする関数です。特定の数値範囲や文字列を持つセルを素早く集計できます。

**使用例**：

```
=COUNTIF(A1:A10, "完了")  // A1からA10の範囲で、「完了」と入力されているセルの数を数えます。

```

### 2.4 `INDIRECT()`

`INDIRECT`関数は、文字列として指定されたセル参照を実際のセル参照に変換します。動的に範囲を指定したい場合や、別のシートやセルから参照を動的に管理したい場合に役立ちます。

**使用例**：

```
=INDIRECT("シート名!B" & MATCH(A2, シート名!A:A, 0))  // シート名のA列でA2と一致する値を探し、B列の該当行を参照します。

```

`MATCH`関数と組み合わせることで、セルの内容に基づいて動的にセルや範囲を参照できます。

### 2.5 `IMPORTRANGE()`

`IMPORTRANGE`は、他のスプレッドシートからデータをインポートする関数です。複数のシートやプロジェクト間でデータを統合したい場合に便利です。

**使用例**：

```
=IMPORTRANGE("スプレッドシートのURL", "シート名!A1:B10")  // 別シートから指定した範囲のデータをインポートします。

```

---

## 終わりに

今回ご紹介したテクニックや関数が、日常的なスプレッドシートの作業をより効率的に進めるための一助になれば幸いです。
paiza.ioでelixir その316

# 概要
paiza.ioでelixirやってみた。
練習問題、やってみた。

# 練習問題
x64アセンブラで、円周率piを求めよ。

# サンプルコード

```

File.write "hello.s", """

.code64
.data
format: 
	.asciz "Your number is: %f"
.text
.global main
main:
	sub	 	$8, %rsp
	fldpi
	fstpl  	-8(%rsp)
	movq   	-8(%rsp), %xmm0
	lea	 	format(%rip), %rdi
	call 	printf
	add	 	$8, %rsp
	ret

"""
{result, 0} = System.shell("gcc -no-pie hello.s")
IO.puts result
{result, _} = System.shell("./a.out")
IO.puts result





```

# 実行結果

```
Your number is: 3.141593
```

# 成果物

https://paiza.io/projects/RDylX5pO3XmySOKQvYig3A?language=elixir


以上。
EXCELJS読み込み

```ts
import ExcelJS from 'exceljs';

async function readExcelFile(filePath: string): Promise<string[]> {
    // Excelファイルを読み込むためのワークブックを作成
    const workbook = new ExcelJS.Workbook();
    await workbook.xlsx.readFile(filePath);

    // 1つ目のシートを取得
    const worksheet = workbook.getWorksheet(1);

    // A列の2行目以降の値を格納する配列
    const aColumnValues: string[] = [];

    // 2行目以降をループしてA列の値を取得
    worksheet.eachRow((row, rowNumber) => {
        if (rowNumber > 1) {
            const cellValue = row.getCell(1).text;  // A列の値
            aColumnValues.push(cellValue);
        }
    });

    return aColumnValues;
}

// 実行例
readExcelFile('path/to/your/excel/file.xlsx').then(aColumnValues => {
    console.log('A列の2行目以降の値:', aColumnValues);
});
```

```ts
import ExcelJS from 'exceljs';

async function readExcelFile(filePath: string): Promise<string[]> {
  const workbook = new ExcelJS.Workbook();
  await workbook.xlsx.readFile(filePath);

  const worksheet = workbook.getWorksheet(1); // 1番目のシートを取得
  const values: string[] = [];

  worksheet.eachRow((row, rowNumber) => {
    if (rowNumber > 1) { // 2行目以降を取得
      const cellValue = row.getCell('A').value;
      if (typeof cellValue === 'string' || typeof cellValue === 'number') {
        values.push(cellValue.toString());
      }
    }
  });

  return values;
}

// 使用例
(async () => {
  const filePath = 'path/to/your/excel-file.xlsx'; // Excelファイルのパス
  const values = await readExcelFile(filePath);
  console.log(values);
})();
```
paiza.ioでelixir その315

# 概要
paiza.ioでelixirやってみた。
練習問題、やってみた。

# 練習問題
x64アセンブラでcos(0.5)を求めよ。

# サンプルコード

```

File.write "hello.s", """

.code64
.data
dq:
    .double 0.5
format: 
	.asciz "Your number is: %f"
.text
.global main

main:
	sub	 	$8, %rsp
	pxor    %xmm0, %xmm0
	movq    (dq), %xmm0
	movq   	%xmm0, -8(%rsp)
	fldl   	-8(%rsp)
	fcos
	fstpl  	-8(%rsp)
	movq   	-8(%rsp), %xmm0
	lea	 	format(%rip), %rdi
	call 	printf
	add	 	$8, %rsp
	ret
	
    
"""
{result, 0} = System.shell("gcc -no-pie hello.s")
IO.puts result
{result, _} = System.shell("./a.out")
IO.puts result




```

# 実行結果

```
Your number is: 0.877583
```

# 成果物


https://paiza.io/projects/QLdCUV5GQZPNEimwb_OV2Q


以上。
paiza.ioでelixir その314

# 概要
paiza.ioでelixirやってみた。
練習問題、やってみた。

# 練習問題
x64アセンブラで1-10の総和を求めよ。

# サンプルコード

```


File.write "hello.s", """

.code64
.data
mat:
	.asciz "1-10 souwa = %i "
.text
.global main
main:
	sub	 	$8, %rsp
	mov	 	$1, %r8
	mov	 	$0, %r9
loop:
    add     %r8, %r9
	add	 	$1, %r8
	cmp	 	$11, %r8
	jne	 	loop
	lea	 	mat(%rip), %rdi
	mov	 	$1, %rax
	mov	 	%r9, %rsi
	call	printf
	add	 	$8, %rsp
	ret

"""
{result, 0} = System.shell("gcc -no-pie hello.s")
IO.puts result
{result, _} = System.shell("./a.out")
IO.puts result




```

# 実行結果

```
1-10 souwa = 55 
```

# 成果物


https://paiza.io/projects/IzePPlMN4T8oOhs2rxJdww

以上。
M5Stamp S3でLチカ





x 過去ログをみよ


結果


![o_coq369.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/17d3dac4-16e2-e59d-96b3-70f477ddd94b.jpeg)




```c++


//L_tika_1_S3_1


//定義
#define LED 15


//初期化
void setup() {

  //GPIOの初期化
  pinMode(LED, OUTPUT); //LED

}//setup


//メインループ
void loop() {

  digitalWrite(LED, HIGH); //LEDの点灯

  delay(1000);//1秒待つ

  digitalWrite(LED, LOW); //消灯

  delay(1000);//1秒待つ

}//loop


```
SSH on SSMを利用して、EC2インスタンスに接続する

.sshフォルダにconfigファイルを作成し、以下を記述します。
```
host i-* mi-*
    ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
```
　
以下のコマンドを実行します。
```
ssh -i <キーファイル> ec2-user@<インスタンスID>
```

以上です。
LinuxOS Cron設定備忘録

# 前置き

Linuxを操作している際に、処理を定期実行する際にcronを設定します。
今回は、cronの設定について備忘録として残します。

:::note info 
**cronについて**
windowsで云うところのスケジューラです。
スクリプトとかを指定した実行間隔で動かすことが出来ます。
:::

# cron設定

下記コマンドでcronを設定するエディタに移行します。

```
crontab -e
```

エディタが開いたら、cronジョブを追加します。各フィールドは以下の通りです。
```
* * * * * command
- - - - -
| | | | |
| | | | +----- 曜日 (0 - 7) (日曜日が 0 または 7)
| | | +------- 月 (1 - 12)
| | +--------- 日 (1 - 31)
| +----------- 時 (0 - 23)
+------------- 分 (0 - 59)
```
追加するcronジョブのスケジュールを指定します。
たとえば、毎日午前2時にスクリプトを実行する場合は、次のようにします。

```
0 2 * * * /path/to/your/script.sh
```
ジョブを保存してエディタを閉じます。
nanoエディタで開いてる場合は下記で保存しエディタを閉じれます。

```
# 保存：キーボード
ctr + o
# エディタ閉じる：キーボード
ctr + x
```

追加した設定は以下コマンドで確認が可能
```
crontab -l
```

:::note warn
**注意**
cronのサービスが落ちていると正常にcronが実行されません。
正常に動作していなかったら下記コマンドで確認してください。

```
# cron状態確認
systemctl status cron.service

# cronスタート
systemctl start cron.service

# cron状態確認
systemctl status cron.service
```

cronで実行したいスクリプトに実行権限がない場合は正常に動作しないおそれがあります。
その場合は下記コマンドで権限を付与します。
```
chmod +x /path/to/your/script.sh
```
:::

以上で設定は終了です。
お疲れ様でした。

学習の参考になれば幸いです。
(調査中)Java。keytoolコマンド

#### キーストアの内容を確認

```bash
keytool -list -v -keystore <キーストアファイル名>
````

#### -rfc オプションを使用する

```bash
keytool -list -rfc -keystore <キーストアファイル名> -alias <エイリアス名>
```
【ServiceNow入門】ServiceNowの学習教材や分からないことを調べるには

# 1.　はじめに
こんにちは。株式会社ウイズ・ワン、ServiceNow担当のS-Kです。
[前回の記事](https://qiita.com/WISS1/items/ab1b5abd20bc28335efb)ではServiceNowの個人インスタンスの取得から設定しておくべき内容をご紹介させていただきました。
その後、何から学習をすべきか分からない、独自に学習をしてみたが、出てくる単語や仕組みがいまいち理解できない、というような悩みが出ているかもしれません。

本記事では、少しでも学習の助けになればということで、
**学習するのに何から手を付ければいいか、分からないことを調べるときにどうしているか** をご紹介します。

:::note info
本記事は2024/09/05時点での情報となります。
:::

# 2.　学習教材の紹介
 学習教材ですが、今回は2つ紹介いたします。
 1つ目は、最初の記事でも紹介させていただいた、**Welcome to ServiceNow**、になります。
 
https://nowlearning.servicenow.com/lxp/ja/now-platform/welcome-to-servicenow?id=learning_course_prev&course_id=c801e64593a9865456aeb94c5cba10f6

 こちらは、ServiceNowの基本、用語、利用方法等について解説されているため、初めて触れる方は是非一度コースを受講してみてください。
 コース内の映像が英語であったり、全容を把握するのに時間がかかってしまうかもしれませんが、受けておいて損のないコースとなっております。

 2つ目はDeveloperサイトにある、**Learning Plans**、になります。

 https://developer.servicenow.com/dev.do#!/learn/learning-plans/washingtondc

 実際に個人インスタンスにコースの内容に沿って作業をしていくため、読んで手を動かし覚えることができます。
受けるコースの順番に指定はありません。
どのコースも複数のモジュールがあり、好きな順番に受けることができますが、
New to ServiceNowを最初に受け、次にServiceNow Administratorを受けるのがおすすめです。
New to ServiceNowのServiceNow Basicsモジュールを最初に行うことでより基礎を固めることができます。

まずはServiceNowの基礎を固めていきたいという場合、この2つの学習教材は無料で受けられ、取り掛かりやすいと思いますので参考にしていただければと思います。

:::note info

Developersサイトには、Learning Plans以外にもいくつかコースがありますので、是非確認してみてください。
:::

# 3.　分からないことをどう調べているか
学習を進めていったり、実際の業務でServiceNowに触れてみると、分からない単語や仕組みがどのようになっているのか分からないものが出てくるかと思います。
その場合、どのように調べているのかをご紹介できればと思います。

1つ目は公式の**製品ドキュメント**となります。

https://docs.servicenow.com/ja-JP/

例えば、ServiceNowでは**GlideRecord**や**GlideDate**といった、Glide〇〇という単語をよく見かけるようになると思います。
それらを検索してみると、例文付きでどのように出力されるのかが記載されているものもありますので、まずは公式のこちらを確認してみるのがよいと思います。

2つ目は**ServiceNow Community**となります。

https://www.servicenow.com/community/

こちらは学習をしてすぐだとあまり利用する機会がないかと思います。
といいますのも、こちらはServiceNowを利用して実際に開発をしている幅広い方に、こんなことで困っている、何か解決策を知らないか、というように問いかけをするために利用されています。
今後何かの機会で利用することがあるかと思いますので、今回紹介させていただきました。
必ず返事が来るわけではありませんが、質問を投げておくことでもしかしたら、回答が来るかもしれません。
また、ServiceNowの基本言語が英語なので、ほとんど英語で回答がきます。
質問を投げる際も、英語で質問すれば多少早く回答がきますので、翻訳して英語で質問を投げてみてください。

:::note info

公式の製品ドキュメントと少しかぶってしまうので紹介はしませんでしたが、DevelopersサイトのReferenceもうまく活用してみてください。
こちらにも開発の時に使用する単語や、記述が記載されております。
:::

# 4. まとめ
学習の教材や、何か調べるときにどんなサイトを利用しているのかを今回はご紹介させていただきました。

どのように学習をしていけばよいか、基礎をどう固めるか、という手助けになればと思います。
また、行き詰まったときにGoogleで検索をしてみると、似たような所で行き詰まってしまった方が解決策を記事にしていることも多くあります。
そういった記事も読んで、自分の力にしていってもらえればと思います。

---
株式会社ウイズ・ワン　ServiceNow担当S-K

https://www.wiss1.co.jp/
Outlook Service Apiのログフル対応

- 環境
    - Macbook Pro 2023
    - Outlook for Mac 16.88.1

いつも200GBくらいの空きを維持していたMacがいつの間にか残り1GBを切っており、何事かと思ったところOutlook Service Apiのログ領域に大量のこまいファイルが生成されていました。

一応Microsoftのフォーラムにも暫定対応が載っていました。
数日前の投稿なので現在進行形のバクなのかもしれません。

<b>Outlook Mac 2024 - Osa OutlookServiceApiLogs API Log files - Millions of log files - unable to delete easily. </b>
https://answers.microsoft.com/en-us/outlook_com/forum/all/outlook-mac-2024-osa-outlookserviceapilogs-api-log/98b688e2-e561-42a1-9fbb-82cca7f89c9a


```bash:1. ログフルを起きなくする対応
Prevent Outlook from Generating Excessive Logs


1. Open Terminal and become root (Password Requiered):

   sudo -i

2. Navigate to the Outlook folder:

   cd "/Users/YourUsername/Library/Group Containers/UBF8T346G9.Office/Outlook/Outlook 15 Profiles/Main Profile"

3. Change ownership and permissions of the "Osa" folder:

   chown root: ./Osa

   chmod 700 ./Osa

   Note: Avoid recursive options if log files are still present; delete them first.

This will prevent Outlook from writing files to that folder and allow you to open Outlook. However, note that other files might be generated elsewhere, though in my tests, this hasn’t been the case.
```

```bash:2. ログをすぐに削除する方法
Important: If you perform this step after changing ownership, you’ll need to append sudo to commands or execute them as the root user.


1. Navigate to the Outlook folder:

   cd "/Users/YourUsername/Library/Group Containers/UBF8T346G9.Office/Outlook/Outlook 15 Profiles/Main Profile/"

2. Create an empty folder:

   mkdir Empty

3. Use rsync to delete the logs:
 

   rsync -av --progress --stats --delete --exclude ./Empty/ ./Osa/

Note: This process might take a long time depending on the number of files, especially while “sending incremental file list.” Just let it run and check back later.

4. Optional: Use rm (Slower Alternative):

   rm -rf ./Osa/*


This will remove all files and folders inside the Osa folder, but not the folder itself.

```

ただ、こちらの環境では、「2.ログをすぐに削除する方法」はうまく動きませんでした。
`find 〜 -delete`コマンドでの削除もうまくいかず。
大量すぎるからか。
一応 `ls -1U | wc -l`と打つと3時間くらいかかりますが、ファイル数を観ることができます。
こちらの環境では 2500万ファイルが入っているフォルダが2個ほどできていました。これで150GB消費です。

結局、上記 rsyncコマンドで対象ファイルの一覧は出てくるので、それを catとawkで整形して、パイプラインで `xargs -I % sh -c "/bin/rm %" ` とつなぐことで、フルパスのファイルを指定して削除しています。
24時間で400万ファイル削除できたので、都合 十日間くらいかかる計算です。

* 注意: 上記 `xargs` コマンドはパイプラインでの実行を前提にしているので、くれぐれもここだけをコピペしてコマンドラインに打ち込まないようにしてください。はじめは `/bin/rm` の代わりに `ls` 等で確認することをおすすめします
ABC369G 解法メモ

# はじめに
突然書きたくなったので書きます。例によって正当性とかそういうのは放置です。

# 問題リンク

https://atcoder.jp/contests/abc369/tasks/abc369_g

# 提出コード

https://atcoder.jp/contests/abc369/submissions/57324615


# 考察プロセス

まず高橋君が通る経路は、選ばれた頂点と根までのパスで通る頂点によって構成される部分木をDFSで通る経路になります。こうすることで、必要な辺を2回だけ通ることですべての頂点を回ることができます。（これ自体が典型？）すなわち、通る必要がある辺の合計長×2が答えになります。従い、最後に求める答えを2倍する形で、いったん合計長だけを考えましょう。（以降の画像による例示は合計長のみですので注意してください。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2522928/a820111c-0321-9494-6940-8e423cb3957a.png)


次に青木君が選ぶべき頂点は葉になります。もし、葉ではないノードを選んだ場合、その子ノードを選ぶ方が親子を結ぶ辺の長さ分スコアを伸ばせるからです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2522928/d9740721-a6f3-7f87-ad8a-da2f9f0507b9.png)


また、Kを増やす過程で過去選んでいる頂点に基づく経路上にある頂点はスコアを伸ばすことはできません。そして、すべての葉を選んだあとは、選ぶ頂点の数を増やしてもスコアを上げることができなくなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2522928/930c7e35-d5d4-0c96-6d96-b1a37895010f.png)


続いて、各小問題でどの葉を選ぶべきか考えていきましょう。

まずK=1の場合を考えましょう。この場合は簡単で、根から葉までの辺の合計長が最も長いものを選べばスコアを最大化することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2522928/2eb04fe7-29d8-2af0-2696-9826a574c293.png)

続いて、そこからK=2,3,...に増やすことを考えます。過去選んだ頂点とその点を往復する経路がすでに存在していますから、2つ目に選ぶ頂点次第では、途中の経路からある種寄り道をするような経路を高橋君は選択することになります。
従い、根→葉の合計長ではなく、すでにあらわている経路で使われてしまっている頂点で一番近い頂点までの合計長が各葉によって伸ばせるスコアになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2522928/b5b2add9-d25d-2f5d-8aea-99a600b24ff0.png)

また、ある葉を選ぶ前に選ぶ葉を増やしても、スコアの伸び量が減ることがあっても増えることはありません。よって、ある頂点を選ぶことを後回しにする必要はないので、頂点を増やすときに都度最もスコアの伸び量が多いものを選べばよいです。（ここはロジック的に弱い気がする）


さて、K≧2の場合、どうやって最適な葉を選ぶのか…ですが、その前に選ぶのが頂点なのに対して、スコアは辺で計算されて扱いにくいので、スコアは辺の子側の頂点にあるものとして読み替えます。（どこかで見たけど典型な気がする）
結果としてスコアの伸びとしては、辺の合計長ではなく通過する頂点スコアの合計に置き換わります。なお、根のスコアは0とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2522928/51825320-7bb8-cb7c-da53-a1e56a4ceb7a.png)

そのうえで、頂点を増やすたびに、ある葉を選んだ時のスコアの伸びを都度更新することができればいいのですが、毎回DFSすると間に合いません。何とかしてさぼれないか考えます。


さて、ある葉を選ぶ、ということが木に対してどういう変化をもたらすのか観察してみましょう。ある葉を選ぶことで、実質的にその葉と根までの頂点が全て削除され、残った頂点と辺による部分木で構成される森になることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2522928/35a289fb-c023-5a7d-375a-671091f251c7.png)


この森の中で最もスコアを伸ばせる葉、すなわち各木の頂点から葉までの合計スコアが最もを選べばよいのですが、このままでは削除操作後の各木においてDFSをする必要があるのでもう少し工夫が必要です。

ここで問題を二つに分けましょう。
一つは、森の中で最もスコアの伸びが大きい葉を持つ木を選ぶ方法と、
一つは、それぞれの木の中で最もスコアの伸びが大きい葉を選ぶ方法です。

後者がわかれば、各木のスコアの伸び量の最大値を求めることができますから、あとはヒープなどに格納することによってどの木を選ぶべきかを高速に求めることができます。

さてこの後者について、
今まで根→葉までのスコア合計を葉側で持ち都度計算する、というイメージでしたが、各木において必要なのは最大の値のみであることを踏まえ、葉→根のイメージでとらえてみます。
すなわち、各頂点において、自分を頂点とする部分木において葉を選んだ時のスコアの最大伸び量※がわかればよいです。これは、事前計算としてDFSを行い、帰りがけで最大値を更新していくことで求めることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2522928/941c9985-6372-d576-760d-3d31d83e9b46.png)
この値はあくまで葉側からたどっていった最大値なので、頂点を増やしたとしても変化することはありません。従って使いまわすことができます。


削除の操作についてですが、ある木をヒープから取り出して選んだあとで、根から葉まで頂点をたどっていきます。この際、DPの復元の要領で※の値-頂点のスコアに一致する子を選んでいき、選ばれなかった子の頂点については候補となる木としてヒープに入れていきます。

以上を実装することでACでした。


# おわりに

最初に文章だけ書いて超絶わかりにくいなと思ったので図を足しにしたらマシになった気がします。グラフ問題は絵をかいてなんぼなのかなと思いました。あとやっぱり全完は気持ちいいです。