OmniAICreator/Qiita-1.07M huggingface dataset:
nodenv-aliases を使って node-version の管理を簡単にしよう

私は React Native の開発に Node.js (以下、Node) を利用しています。言葉通り、Node はリリースではなく開発中にしか利用しないので、Node のバージョンは開発環境で動けば良いだけなんです（バージョンが重要な方は御免なさい）。

さて、Node のバージョン管理と言えば、`nodenv` をインストールして、プロジェクトごとに `node-version` を設定する方が多いのではないでしょうか。私もこのパターンです。

```:node-version
18.14.0
```

私が面倒だなと思うことは、不具合などで Node のバージョンを挙げた際に `node-version` を更新する PR を出さないといけない、別マシンで開発環境を構築した際に Node のバージョンを揃えなければならない。Node のバージョンは私には重要ではないのに！（バージョンが重要な方には本当に御免なさい）

## エイリアスを設定する

上記問題の解決方法はあります。`nodenv` が公開している `nodenv-aliases` を利用して、エイリアスを作成します。

https://github.com/nodenv/nodenv-aliases

手順は簡単で、すでに `nodenv` が導入済みなら1行で終わります。

```bash
git clone https://github.com/nodenv/nodenv-aliases.git $(nodenv root)/plugins/nodenv-aliases
```

インストール後に `alias` を実行するとエイリアスが作成されます。例えば、私の環境では `18` とだけを指定すれば、実際にインストールされている `18.14.0` が選択されます。また、細かいエイリアス設定はあるので、詳しくは `nodenv-aliases` の [README](https://github.com/nodenv/nodenv-aliases/blob/master/README.md) を参考にください。


```bash
% nodenv alias --auto
16 => 16.13.0
18 => 18.14.0
16.13 => 16.13.0
18.14 => 18.14.0
```

## エイリアス後の node-version

私の開発プロジェクトでは以下のように `node-version` はメジャーバージョンだけを指定しています。

```:node-version
18
```

そして、エイリアスにより `18.14.0` が選択されています。

```shell:nodenv versions
 % nodenv versions       
  16
  16.13
  16.13.0
* 18 => 18.14.0 (set by /Users/mitsuharu/projects/hogehoge/.node-version)
  18.14
  18.14.0
```

仮にこのバージョンに不具合があっても、開発環境の Node をアップデートするだけで済みまし、他の開発環境はとりあえずメジャーバージョンさえ揃っていれば開発ができます。楽です！

## まとめ

~~私のようなズボラで~~ `node-version` の管理を楽したい人には、`nodenv-aliases`　はおすすめです。是非、楽して開発しましょう。
git

`format`

```sh
eval "$(conda shell.bash hook)"
conda activate Formatter

pysen run lint
pysen run format
```

`pyproject.toml`

```toml
[tool.pysen]
version = "0.10"

[tool.pysen.lint]
enable_black = true
enable_flake8 = true
enable_isort = true
enable_mypy = true
mypy_preset = "strict"
line_length = 120
py_version = "py38"
[[tool.pysen.lint.mypy_targets]]
  paths = ["."]
```

`.gitignore`

フォルダは維持する

```
*
!.gitignore
```

[generator](https://www.toptal.com/developers/gitignore)を使う
Android Studioで出力されるAPKに任意の名前をつける

Android Studioのビルド時に"app-release.apk"から毎回リネームするのが面倒なので、デフォルトで名前をつけたい。
ここでは、リリース時は"MyAndroidApp-v1.x.x-20230204-131212.apk"という名前をつけるようにする。デバッグ時はもとの"app-debug.apk"にする（なにもしない）。

### 開発環境
Android Studio Dolphin | 2021.3.1 Patch 1
Gradle version 7.3.3

### 変更箇所

```gradle:(project)/app/build.gradle
...
buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        // ここから追加
        applicationVariants.all{
            variant ->
                variant.outputs.each{
                    output->
                        // app-release.apk -> MyAndroidApp-v1.x.x-20230204.apk
                        def myAppName = 'MyAndroidApp'
                        def formattedDate = new Date().format('yyyyMMdd-HHmmss')
                        def newName = output.outputFile.name
                        def version = variant.versionName
                        newName = newName.replace("app-release", "$myAppName-v$version-$formattedDate")
                        output.outputFileName  = newName
                }
        }
}
...
```


### 参考
* https://www.geeksforgeeks.org/how-to-change-the-default-generated-apk-name-in-android-studio/
* https://stackoverflow.com/questions/28249036/app-release-apk-how-to-change-this-default-generated-apk-name
ITパスポート3日で取得した話

# 初めに
本記事はできるだけ早くITパスポートを取得するといったことに重点を置いているので知識の定着や技術のノウハウといったことは重視してません

## 実施したこと

### 一日目
本を一周流し読み(6時間)

読んだ本はこちら

[情報処理教科書 出るとこだけ！ITパスポート テキスト＆問題集 2022年版](https://www.amazon.co.jp/%E6%83%85%E5%A0%B1%E5%87%A6%E7%90%86%E6%95%99%E7%A7%91%E6%9B%B8-%E5%87%BA%E3%82%8B%E3%81%A8%E3%81%93%E3%81%A0%E3%81%91%EF%BC%81IT%E3%83%91%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88-%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%EF%BC%86%E5%95%8F%E9%A1%8C%E9%9B%86-2022%E5%B9%B4%E7%89%88-%E6%AF%94%E4%BD%90%E5%AD%90-ebook/dp/B09HC62CK8/ref=sr_1_5?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=2JDK4SCIEJMVX&keywords=it%E3%83%91%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88+%E3%81%A7%E3%82%8B%E3%81%A8%E3%81%93%E3%81%A0%E3%81%91&qid=1675505845&sprefix=it%E3%83%91%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88+%E3%81%A7%E3%82%8B%E3%81%A8%E3%81%93%E3%81%A0%E3%81%91%2Caps%2C174&sr=8-5)

[令和03年　ITパスポート合格教本](https://www.amazon.co.jp/%E4%BB%A4%E5%92%8C03%E5%B9%B4-IT%E3%83%91%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88%E5%90%88%E6%A0%BC%E6%95%99%E6%9C%AC-%E6%83%85%E5%A0%B1%E5%87%A6%E7%90%86%E6%8A%80%E8%A1%93%E8%80%85%E8%A9%A6%E9%A8%93-%E5%B2%A1%E5%B6%8B-%E8%A3%95%E5%8F%B2-ebook/dp/B08NWSBVXQ/ref=sr_1_7?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=2FOXVP0R9P8FM&keywords=it%E3%83%91%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88+%E5%90%88%E6%A0%BC%E6%95%99%E6%9C%AC&qid=1675506082&sprefix=it%E3%83%91%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88+%E5%90%88%E6%A0%BC%E6%95%99%E6%9C%AC%2Caps%2C169&sr=8-7)

過去問を4年分解いた(令和4年春期令和3年春期令和2年秋期令和元年秋期)(5時間)

https://www.itpassportsiken.com/



一日目勉強時間11時間

### 二日目
体調を崩したため過去問を1年分(平成31年春期)(1時間)と一日目に解いた直近二年分の過去問の不正解の個所勉強した(1時間)不正解した問題の分野を本で復習(1時間)のみ、

二日目勉強時間3時間

### 三日目(試験当日)
友達と会う予定があったため過去問を直近一年分(令和4年春期)(1時間半)と再度一日目と二日目に解いた直近二年分の過去問の不正解の個所を勉強した(1時間)

三日目勉強時間2時間半

![スクリーンショット 2023-02-04 200246.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/813031/cca781eb-6e43-cfda-13b6-231d08d62490.png)


## 総勉強時間
約16時間半

## 試験を受けてみた感想
自分はネットのブログ記事を参考に過去問をひたすら勉強したが、実際の試験問題は過去問から出るものはそこまで多くないと感じた。

過去問をひたすらやるよりかはもっと情報量の多い参考書を読んだ方が良いと感じた。

# 試験を合格する要素

ここからがメイン

はっきり言って上に挙げた二冊は流し読みとわからないところの復習くらいで2~3周したくらいなので買う価値はあまりない。どっかの図書館で借りればいいレベル。

過去問は直近3年間を1~2周と間違えたところを復習するくらいで十分。実際の試験はそこまで過去問に出てきてはいないのでそれ以上時間をかける時間は無駄といっていい。(結果から言うと自分は過去問にあまりにも依存しすぎていた)

もっと詳しく書かれた本を読むべき、自分は読まなかったが、用語であったり体系的な情報が書かれている本を買ってそれをひたすら覚えまくるといった方が試験の対策となる。

# 三日で試験を合格した自分が考える最短で試験を合格する方法

最初に、一日目に上に挙げた二冊を借りてきて流し読みをする。

過去問を3年分を一周して問題の傾向をつかむ。問題自体は問題に出てきた用語とそれに近いとされる選択肢を選ぶといった方法で十分。(内容を完璧に覚えなくても試験には受かる)

過去問の学習履歴から自分の成績が低い分野をひたすら復習し、もっと情報の載っている本で知識を頭に叩き込む。(ここで試験と過去問の類似性とは独立して自分の知識の定着度がわかるので、分野別の勉強法を勧める)

本での勉強方法では過去問で出てこなかった内容などを勉強する必要がある。過去問に載っていなくても試験には普通に出てくるのでまんべんなく覚えることが重要と考える。

## 加えて勉強のコツなど

試験は理系大学の期末テストくらいの難易度といった感じ。（6割とれればいいので受かることだけを考えると）

英語の頭文字の略称が多く出てくるのでこの部分は注視して勉強しておくとよい

本も読むならなるべく直近に出版された本を読んだ方が良い。（直近の本では試験に出題される率は高い）

知識を頭に叩き込むのがメインとなるのでなるべく短期集中で取得するのがおすすめ。(IT関連の職種についてる人だと勉強時間が一日でも取得できる難易度。未経験でも10日で取得できる難易度)

IT未経験でもマネジメント分野、ストラテジ分野は多少の知識はあると思うのでテクノロジ分野を重点に置けばよい

### 最後に

以上最短でITパスポートを取得するあれこれをかきました
PHP で テキストのハッシュタグへリンクを貼る

　PHPで、テキスト文字列内のハッシュタグ（#から始まる単語）をリンクに変換する関数をChatGPT に聞きながら、作成してみました。その時のメモです。


Q.
```
php で　テキストのハッシュタグに検索リンクを貼るロジックを教えて
```
A.
```php
<?php
function add_hashtag_links($text) {
    $hashtag_regex = "/#(\w+)/";
    $replace = "<a href='search.php?q=$1'>#$1</a>";
    return preg_replace($hashtag_regex, $replace, $text);
}

$text = "こんにちは #PHP でハッシュタグをリンクに変換しましょう。";
$linked_text = add_hashtag_links($text);
echo $linked_text;

```


下記のサイトで確認したところ、全角スペースに対応していななたったので、
https://ja.functions-online.com/preg_replace.html

Q.
```
全角スペースも対応した、ハッシュタグを検索する正規表現を教えて
```
A.
```php
/#(\S+)/u

```

結果作成したソースです。
```php
function hashToLink($content)
{
    $hashtag_rege = '/#(\S+)/u';
    $replace = "<a href='/search/?keyword=#$1'>#$1</a>";
    return $result;
}
```

残念ながら、検索URLに # が入っているため、うまく動作しません。ChatGPT に聞いても、正しく動作するコードが得られないためGoogle 先生に聞いたところ、preg_replace_callback を使えばよいということなので、結局次のようになりました。

```php
function hashToLink($content)
{
    $hashtag_rege = '/#(\S+)/u';
    $result = preg_replace_callback($hashtag_rege, function ($matches) {
        return '<a href="/search/?keyword=' . urlencode($matches[0]) . '">' . $matches[0] . '</a>';
    }, $content);
    return $result;
}
```

preg_replace_callback まで入力したら、Github Gopilot が　察してくれたようで、自動的に作成してくれました。

　WordPress への適用は、下記のとおり。
```
add_filter( 'the_content', 'hashToLink', 6); 

```
【SwiftUI】特定の条件でのみアニメーションをループさせる

# はじめに
特定条件の場合のみ、ループアニメーションを付与します。

# サンプルアプリ
![Simulator Screen Recording - iPhone 14 Pro - 2023-02-04 at 20.16.09.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/faa55b56-cd37-17fb-418a-d5e86db9e477.gif)

# やりかた
```swift:ContentView
import SwiftUI

struct ContentView: View {
    @State var isAnimation: Bool = false
    var body: some View {
        VStack(spacing: 50) {
            Toggle("", isOn: $isAnimation)
                .labelsHidden()

            Button {
                print()
            } label: {
                Text("ボタン")
            }
            .buttonStyle(.borderedProminent)
            .scaleEffect(isAnimation ? 1.5 : 1.0)
            .animation(.default.repeat(while: isAnimation), value: isAnimation)
        }
    }
}
```

```swift:Animation+
import struct SwiftUI.Animation

extension Animation {
    func `repeat`(while expression: Bool, autoreverses: Bool = true) -> Animation {
        if expression {
            return self.repeatForever(autoreverses: autoreverses)
        } else {
            return self
        }
    }
}
```

# おわり
`animation`のAPIが新しくなってからはじめに使いました笑
PowerShellでWindowsの画面ロック抑制

# 定期的にキーを勝手に押してロック画面に戻るのを抑制します

CTRLキーを200秒毎に打鍵します
停止はCtrl+Cで止めてください。
```
add-type -AssemblyName System.Windows.Forms
$m=200;
while(1){
	Get-Date;
	[System.Windows.Forms.SendKeys]::SendWait("^");
	Start-Sleep $m;
}
```

Get-Dateは日付を出すだけで意味はありません
不要なら除いてください

# 1行に詰めた
間を詰めて１行にしたのがこれです、変に読みやすいと秒で見破る人が居るので
あと上矢印キーとエンターで再実行できるので、1行が便利です。
```
add-type -AssemblyName System.Windows.Forms;$m=2;while(1){Get-Date;[System.Windows.Forms.SendKeys]::SendWait("^");Start-Sleep $m;}
```

# 注意点
こっそりやる奴ですがバッチ化するとウィルスチェック系の奴に引っかかります。
txtファイルに残すのも場合によっては見つかって超怒られますので注意してください。

自分の場合は、OutlookでAlt + F11でvbaソースに置いといて、どうしても必要な時だけ使います
⇒長考してぇのに5分毎にアクションが必要になってウザいとき

⇒これ走らせておいてWindows＋Lでロックをかけると、スクリーンセーバーにならず時計表示のままになります。
ロックしといて離席しても、この動きを知ってる人が居たらバレることがあります。
たまにマウス動かして偽装などしてくださいね

このスクリプトを使用した場合の責任は取れませんので、自己責任でお願いします。
マジで
Railway.appのメモリ使用量を減らすためにやったこと

Railway.appはherokuの代替として注目されたPaaSで（枕言葉）、自分もfly.ioのVMでは重くて難しい処理をRailway.appの方に任せるという方法で無償運用している。

やってるのは数時間に一回、Redisを伴ったSidekiq/schedulerのワーカーを回してるだけで、回してるワーカー自体の負荷は毎回数分ということもあって大した負荷はないのだが、Railsを回してるだけでも結構メモリを喰ってしまう。5ドルを超えると有償になってしまうというのもあるので、なるべくこのメモリ使用量を減らしたい。そんなわけでいろいろやったことをつらつら。

## MALLOC_ARENA_MAX=2
環境変数でMALLOC_ARENA_MAX = 2に指定しろというやつ。本当に意味があるかは正直不明。体感あるほど変わった印象はない。ちなみにherokuでは自動で2として設定されるらしい。

## Webなど不必要なviewやコントローラーなど全部destroyして消した
これはかなり効果があった。一応動作テストで作ってたviewなどがあったため、自分の場合はwebは全てfly.io側で賄っていたのもあり、回していなかったページも全て消した。あと、ActionMailerなどもGASなどに肩代わりすることで消去。これらはかなり効果があった。

## プロセスをフォークして切り捨てる
これは「[Sidekiqのメモリが増え続ける問題対処](https://qiita.com/ktanoooo/items/55228112d7f2e8000b1c)」でまんま紹介されてる方のコードをそのまんまコピペしただけ。これについては**劇的に効果があった**。300MB前後でほとんど張りつくようになり、メモリの消費量の揺れがほとんどなくなった

## Github Actionsで定期デプロイするようにした
メモリの待機消費量を劇的に減らす方法は「定期的に再起動すること」なんだけれど、システムでrails restartなどしてもほぼだめなのでどうしたらいいか相当迷ってた。しかしGithub Actionsでcronを指定した定期実行で、自動でデプロイするようにしたら待機でじわじわ増えるメモリをこれも激減した（もっと簡単な方法があるかもしれないが）

自動デプロイ自体は[Railway.appの公式ブログ](https://blog.railway.app/p/github-actions)でも設定例が紹介されている。Project Settingの設定のTokensの項目から、適当な名前でトークンを作る。それをgithubのリポジトリのSettings→Secrets and Variables→Actionsの項目にいき、New repository secretsから新しいトークン設定ページへ。RAILWAY_TOKENの名前で、先ほどのトークンを入力する。

その上で、.github/workflowsフォルダにymlファイルを作って、以下のコード。

```yaml
name: Auto Redeploy

on:
  schedule:
    # 分 時 日 月 曜 日本時間はUTC時間に+9時間
    - cron: '0 0 * * *'
    - cron: '0 12 * * *'

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Use Node 18
        uses: actions/setup-node@v1
        with:
          node-version: 18.x

      - name: Install packages
        run: yarn install --frozen-lockfile

      - name: Install Railway
        run: npm i -g @railway/cli

      - name: Deploy
        run: railway up
        timeout-minutes: 10
        env:
          RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
```

自分はとりあえずこれで、cronの時間に自動でrailway.appにデプロイし直してくれる。もっとちゃんとした方法があるかも。
Qiita投稿のマークダウン記法

# 概要

Qiita記事を書く際の基本的なマークダウンについて

# 目次

[1.本題の前に](##1-本題の前に)
[2.見出し](##2-見出し)
[3.リスト](##3-リスト)
[4.コードの挿入](##4-コードの挿入)
[5.引用](##5-引用)
[6.リンク](##6-リンク)
[7.リンクカード](##7-リンクカード)
[8.画像埋め込み](##8-画像埋め込み)
[9.テーブル](##9-テーブル)
[10.数式の挿入](##10-数式の挿入)
[11.ページ内リンク、目次リンク](##11-ページ内リンク、目次リンク)
[あとがき](#-あとがき)

## 1.　本題の前に

### 開いているQiita記事のURL末尾に「.md」を入力すると、マークダウン表記に変換される

試しに本記事のURL末尾に「.md」を入力してみて下さい。
表示されていた記事がどういうマークダウンで書かれているのか確認できます。
気になった記法はこれで簡単に真似できるので、覚えておくと便利かもしれません。

### エディタとプレビューを両方開くと、自分の編集内容が確認できて便利

編集画面に進み本文タブ右端の「エディタとプレビュー」を選択すると、
左に編集画面、右に確認画面が表示されます。
自分の記法をリアルタイムで確認できるので、記事を書く際には便利です。

## 2.　見出し

「半角#」＋「全角スペースを1つ」
※「#」の数が増えるごとに、見出しの大きさが小さくなります。

## 3.　リスト

「半角-」＋「全角スペース1つ」
※リスト表記で改行すると、次の行からは自動でリスト表記にしてくれます。

## 4.　コードの挿入
コードの上下にバッククオート「`」かチルダ「~」を3回以上連続で記載します。
~~~md:例
```md:hello world
puts hello world
```
~~~
結果
~~~md:hello world
puts hello world
~~~

## 5.　引用

## 6.　リンク

## 7.　リンクカード

## 8.　画像埋め込み

## 9.　テーブル

## 10.　数式の挿入

## 11.　ページ内リンク、目次リンク
- []と()で記載します。
- []の中身がリンク先や目次の一覧となります。
- ()の中身は[]と同じにします。
例
~~~
# 目次
[①.概要](##①-概要)
[②.本題](##②-本題)
　　　　　　　　　　・
　　　　　　　　　　・
　　　　　　　　　　・
~~~
結果
[1.概要](##1-概要)
[2.本題](##2-本題)
##1.　概要
##2.　本題

# あとがき

Qiita初投稿だが、そもそもマークダウンがおぼつかなかったので練習も兼ねて投稿。
備忘録として、今後新たに覚えたことは本記事に反映。
Red Hat OpenShift on IBM Cloud(ROKS)で、ワーカーノードのカーネルパラメータを変更する

### 注意

マニュアルにも記載されているとおり、デフォルトの設定を変更することで、サポートが得られなくなる可能性がありますので、ご注意ください。（変更により生じた問題の解析等は行えなかったり、その可能性を排除するために、デフォルトの状態に戻しても同じ問題が再現することの確認を求められる可能性があります）

> デフォルトの設定を変更する場合は、お客様自身の責任で行ってください。 変更された設定に対してテストを実行すること、および環境内の設定変更が原因で発生する可能性がある障害についてはお客様が責任を持ちます。

とはいえ変更しないとPodが起動しない状況になってしまったので、試してみました。

### 参照した情報

[Tuning performance - IBM Cloud Docs](https://cloud.ibm.com/docs/openshift?topic=openshift-kernel)

### 確認した環境

+ Red Hat OpenShift on IBM Cloud(ROKS)
    + 4.10
    + ワーカープールはRHEL8に更新済み
    + ワーカーのバージョン：4.10.50_1554_openshift

### 経緯

とあるPod(SonarQube)が以下のようなエラーで起動してくれなかったので調査。

```
2023.02.04 04:55:10 INFO  es[][o.e.b.BootstrapChecks] explicitly enforcing bootstrap checks
ERROR: [1] bootstrap checks failed
[1]: max virtual memory areas vm.max_map_count [255732] is too low, increase to at least [262144]
```

デバッグPodで侵入して確認すると、確かに小さい。

```
$ oc debug node/[ノードのIPアドレス]
# cat /proc/sys/vm/max_map_count
255732
```

ここでsysctlコマンドで変更しても、ノードのリブートやリプレースがかかると元に戻ってしまうので、永続的に設定を反映させる方法が必要になります。

冒頭のリンク先の後半にあるinitContainerによる方法を試します。（Node Tuning Operatorの方法は、なぜかうまくいきませんでした・・・）

マニュアルにあるサンプルを編集したファイルを用意します。

```yaml:worker-node-kernel-settings.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kernel-optimization
  namespace: kube-system
  labels:
    tier: management
    app: kernel-optimization
spec:
  selector:
    matchLabels:
      name: kernel-optimization
  template:
    metadata:
      labels:
        name: kernel-optimization
    spec:
      hostNetwork: true
      hostPID: true
      hostIPC: true
      initContainers:
        - command:
            - sh
            - -c
            - sysctl -w vm.max_map_count=262144;
          image: alpine:3.6
          imagePullPolicy: IfNotPresent
          name: sysctl
          resources: {}
          securityContext:
            privileged: true
            capabilities:
              add:
                - NET_ADMIN
          volumeMounts:
            - name: modifysys
              mountPath: /sys
      containers:
        - resources:
            requests:
              cpu: 0.01
          image: alpine:3.6
          name: sleepforever
          command: ["/bin/sh", "-c"]
          args:
            - >
              while true; do
                sleep 100000;
              done
      volumes:
        - name: modifysys
          hostPath:
            path: /sys
```

そして適用します。

```
$ oc apply -f  worker-node-kernel-settings.yaml 
daemonset.apps/kernel-optimization created
```

しばらくすると反映されたようで、CrashLoopBackOffだったPodも無事起動してきました。

試しに、ノードをリプレースしてみても、デフォルトの設定が更新されており、問題なく起動してくることが確認出来ました。

### 戻し方

マニュアルにあるコマンドではネームスペースの指定がありませんので、`-n kube-system`を追加して削除を実行し、その後すべてのノードを順次リブートします。

```
$ oc delete ds kernel-optimization -n kube-system
daemonset.apps "kernel-optimization" deleted
```

### おしまい

ElasticSearchでも同様の事象が多くあるようですが、サポートの点があるので、そこを十分ご理解いただきつつ、ご参考まで。
ツイキャス録画君で出来たファイルのリネーム

ツイキャス録画君で残したtxtファイルの中のタイトルを、
ファイル名に追記するバッチファイルになります。

txtファイルの中身がUTF-8のために、
batファイルだけだと処理できないため
PowerShellを使います。

ツイキャス録画君で残したファイルは、
本体のmp3とtxtの２種類になります

テキストファイルの中はこんな感じ
```userID（2023年02月04日16時34分00秒）.txt
【ライブURL】http://twitcasting.tv/userID/movie/moiveID
【録画開始時間】2023年02月04日16時34分00秒
【ユーザー名】ユーザー名
【ユーザーID】userID
【タイトル】だだだだ
```

これのタイトルを取得して、txtファイルをリネームします。

Befor　userID（2023年02月04日16時34分00秒）.txt
After　userID（2023年02月04日16時34分00秒）だだだだ.txt


まずはPowerShellのスクリプトを呼び出すbatファイル
```TitleToFileName.bat
powershell .\TitleToFileName.ps1
pause
```

それで本命のPowerShellのスクリプトはこんな感じです

１）実行場所のtxtファイル分ループ
２）ファイル名の（から後ろを抽出します
３）抽出した文字長が26なら、処理前なので処理する
４）ファイル名と拡張子の間にtxtファイルの５行目（０スタートなので４）を突っ込んで
５）【タイトル】を_に置換
４）リネーム

```TitleToFileName.ps1
$itemList = Get-ChildItem *.txt;
foreach($item in $itemList)
{
	#日付から拡張子までの長さで、タイトル追加済みを判断する
	$item.Name -match "（.*.txt";

	if ( 26 -eq $Matches[0].length ){
		$oldFn = (Get-ChildItem $item).BaseName+(Get-ChildItem $item).Extension
    	$newFn = (Get-ChildItem $item).BaseName+(Get-Content -Encoding UTF8 $item)[4]+(Get-ChildItem $item).Extension
    	$newFn = $newFn -replace "【タイトル】","_"

		write-host("処理 "+$item.Name);
		Rename-Item $oldFn -NewName $newFn;
	}else{
		write-host("処理済 "+$item.Name);
	}
}
```

直接mp3,mp4ファイルの方をリネームしたいときは、こんな感じです

```TitleToFileName2.ps1
$itemList = Get-ChildItem *.txt;
foreach($item in $itemList)
{
	#日付から拡張子までの長さで、タイトル追加済みを判断する
	$item.Name -match "（.*.txt";

	if ( 26 -eq $Matches[0].length ){
		$oldFn = (Get-ChildItem $item).BaseName+".mp3"
    	$newFn = (Get-ChildItem $item).BaseName+(Get-Content -Encoding UTF8 $item)[4]+".mp3"
    	$newFn = $newFn -replace "【タイトル】","_"

		write-host("処理 "+$item.Name);
		Rename-Item $oldFn -NewName $newFn;
	}else{
		write-host("処理済 "+$item.Name);
	}
}
```



これで、文字コードを指定したテキストファイルの中身で、
ファイル名を処理することが簡単になりました。
ChatGPTとは？という記事をChatGPTで書いてみたら。。

## 概要
OpenAIが提供した「ラージ・ランゲージ・モデル」というモデルを使用して大量に学習させたオリジナルのテキストを生成することができる人工知能ツール「chatGPT」が猛威を振るっているということで、ChatGPTでChatGPTを解説してもらいました。
![ChatGPT.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1180499/0c406e8c-3b10-13c1-b80e-0da5f2dc4bdb.jpeg)

以降：ChatGPT

## ChatGPTとは？　
Generative Pre-trained Transformer 3 (GPT-3) とも呼ばれる ChatGPT は、OpenAI によって開発された最先端の言語生成モデルです。この AI テクノロジーは、テキスト補完、質問応答、機械翻訳、テキスト要約など、さまざまな言語関連のタスクを実行できます。

ChatGPT は、自然言語処理 (NLP) の分野に革命をもたらしたニューラル ネットワークの一種であるトランスフォーマー アーキテクチャ上に構築されています。トランスフォーマー アーキテクチャにより、ChatGPT は大量の入力データを処理し、一貫性のあるコンテキストを意識した出力を生成できます。

ChatGPT のユニークな機能の 1 つは、事前トレーニング プロセスです。このモデルは、書籍、記事、Web サイトなどの膨大な量のテキスト データでトレーニングされ、単語、フレーズ、概念の間のパターンと関係を学習します。この事前トレーニングにより、モデルは新しい入力データに対して首尾一貫した人間のような応答を生成できます。

自然言語出力を生成する ChatGPT の機能により、ChatGPT はさまざまなアプリケーションで人気のあるツールになりました。たとえば、人間のようにユーザーとやり取りできるチャットボットなどの会話型 AI システムを構築するために使用できます。自動化されたニュース記事、製品説明、さらには詩を生成するためにも使用できます。

結論として、ChatGPT は強力な AI テクノロジーであり、私たちが言語と対話する方法を変える可能性を秘めています。人間のような応答を生成する機能と、膨大な量のテキスト データでの事前トレーニングを組み合わせることで、さまざまなアプリケーションに適用できる汎用性の高いツールになります。

## ChatGPTで質問したことによるエラー

日本語翻訳

①
アプリケーション エラー: クライアント側の例外が発生しました (詳細については、ブラウザー コンソールを参照してください) 。

②
エラーが発生しました。この問題が解決しない場合は、help.openai.com のヘルプ センターからお問い合わせください。


エラー詳細
参照
[ChatGPTでエラーが発生する原因と対処法を解説](https://app-story.net/chatgpt-error/)
FAAD2を試してみた

AACのデコーダーで有名なFAAD2をZRouterのportsもどきに追加してFreeBSD/mipsのRT3883でためしてみました。

```
# faad -o /dev/null sample4.aac 
 *********** Ahead Software MPEG-4 AAC Decoder V2.10.0 ******************

 Build: Feb  4 2023
 Copyright 2002-2004: Ahead Software AG
 http://www.audiocoding.com
 bug tracking: https://sourceforge.net/p/faac/bugs/
 Floating point version

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License.

 **************************************************************************

sample4.aac file info:
ADTS, 244.506 sec, 133 kbps, 44100 Hz

  ---------------------
 | Config:  2 Ch       |
  ---------------------
 | Ch |    Position    |
  ---------------------
 | 00 | Left front     |
 | 01 | Right front    |
  ---------------------

Decoding sample4.aac took: 247.61 sec.  0.99x real-time.
```

実時間を越えています。いとしのRalink最速のRT3883がそんな遅いはずはない。ソースを見たところFIXED_POINTでも処理できるようなので試してみました。

```
# faad -o /dev/null sample4.aac 
 *********** Ahead Software MPEG-4 AAC Decoder V2.10.0 ******************

 Build: Feb  4 2023
 Copyright 2002-2004: Ahead Software AG
 http://www.audiocoding.com
 bug tracking: https://sourceforge.net/p/faac/bugs/
 Fixed point version

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License.

 **************************************************************************

sample4.aac file info:
ADTS, 244.506 sec, 133 kbps, 44100 Hz

  ---------------------
 | Config:  2 Ch       |
  ---------------------
 | Ch |    Position    |
  ---------------------
 | 00 | Left front     |
 | 01 | Right front    |
  ---------------------

Decoding sample4.aac took: 63.72 sec.  3.84x real-time.
```

まー、こんなもんですかね。

HLSのtsファイルがデコードできるかと思ったのですが、

```
Error: Channel coupling not yet implemented
```

でした。残念。

誰かChannel couplingを実装してくれませんか？
rex0220 項目検証プラグイン よくある値チェック

項目検証プラグインで、電話番号やメールアドレスなどのよくあるチェックを行ってみます。

# 概要

項目検証プラグインのカスタムバリデーション機能で、よく使われるチェックを行います。

エラー表示例
![2023-02-04_17h09_46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/117e55a0-c1db-9575-d35e-34d9338d03ac.png)

項目検証プラグインのカスタムバリデーション設定例
![2023-02-04_17h18_40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/3e117c4e-200d-d10e-850e-61e406453942.png)

# TESTRE 関数と正規表現

TESTRE 関数は、文字列の検索(正規表現)で、文字の有無（true, false）を返します。
正規表現を使うと文字列をパターンでチェックできます。

## ３桁の数字チェック例

３桁の数字以外をエラー
※必須項目の場合は、必須チェックが優先されます。

~~~
// 検証条件
NOT(TESTRE(文字列,"^[0-9]{3}$"))
// メッセージ
"３桁の数字に問題があります"
~~~

- 「３桁数字」以外をエラーにします。
    - NOT( : 否定（パターンに一致しないもの）
        - TESTRE( : 文字列を正規表現でチェック（パターンに一致するもの）
            - 文字列 : フィールドコード
            - "^[0-9]{3}$" : 正規表現のパターン
                - ^ : 文字列の先頭
                - [0-9]{3} : 数字３桁
                - $ : 文字列の最後


## 入力時のみ３桁の数字チェック例

文字列が入力かつ３桁の数字以外をエラーにする場合、AND 関数で未入力をチェックしたり、正規表現で未入力をチェックできます。

- AND 関数で、未入力をチェック
~~~
// 検証条件
AND(文字列,
  NOT(TESTRE(文字列,"^[0-9]{3}$"))
)
// メッセージ
"３桁の数字に問題があります"
~~~

- 正規表現で、未入力をチェック
~~~
// 検証条件
NOT(TESTRE(文字列,"^([0-9]{3})?$"))
// メッセージ
"３桁の数字に問題があります"
~~~

? : 直前の"([0-9]{3})" の 0 回か 1 回にマッチ

# 郵便番号

正規表現で「３桁数字-４桁数字」のパターンに一致しないものをエラーにします。
~~~
// 検証条件
NOT(TESTRE(郵便番号,"^[0-9]{3}-[0-9]{4}$"))
// メッセージ
"郵便番号に問題があります"
~~~

- 「３桁数字-４桁数字」以外をエラーにします。
    - NOT( : 否定（パターンに一致しないもの）
        - TESTRE( : 文字列を正規表現でチェック（パターンに一致するもの）
            - 郵便番号 : フィールドコード
            - "^[0-9]{3}-[0-9]{4}$" : 正規表現のパターン
                - ^ : 文字列の先頭
                - [0-9]{3} : 数字３桁
                - \- : ハイフォン
                - [0-9]{4} : 数字４桁
                - $ : 文字列の最後


# 電話番号

~~~
// 検証条件
NOT(TESTRE(電話番号,"^0([0-9]-[0-9]{4}|[0-9]{2}-[0-9]{3}|[0-9]{3}-[0-9]{2}|[0-9]{4}-[0-9])-[0-9]{4}$"))
// メッセージ
"電話番号に問題があります"
~~~

※リンク項目の場合は、kintone API の仕様により、値変更イベントが発生しないため、リンク項目の値が変更されたタイミングでは、エラーチェックが行われません。
他の項目チェックまたはレコード保存時に、リンク項目のチェックが行われます。

# 携帯番号

~~~
// 検証条件
NOT(TESTRE(携帯番号,"^0[789]0-[0-9]{4}-[0-9]{4}$")){4}$"))
// メッセージ
"携帯番号に問題があります"
~~~

# メールアドレス

~~~
// 検証条件
NOT(TESTRE(メールアドレス,"^[a-zA-Z0-9_.+-]+@([a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]*\.)+[a-zA-Z]{2,}$"))// メッセージ
"メールアドレスに問題があります"
~~~

# 半角英数字

~~~
// 検証条件
NOT(TESTRE(半角英数字,"^[0-9a-zA-Z]*$"))
// メッセージ
"半角英数字のみ"
~~~


# 半角数字

~~~
// 検証条件
NOT(TESTRE(半角数字,"^[0-9]*$"))
// メッセージ
"半角数字のみ"
~~~

# 全角ひらがな

~~~
// 検証条件
NOT(TESTRE(全角ひらがな,"^[\u3040-\u309F]*$"))
// メッセージ
"全角ひらがなのみ"
~~~

# 全角カタカナ

~~~
// 検証条件
NOT(TESTRE(全角カタカナ,"^[\u30A0-\u30FF]*$"))
// メッセージ
"全角カタカナのみ"
~~~

# 全角文字

~~~
// 検証条件
NOT(TESTRE(全角文字,"^[^ -~｡-ﾟ]*$"))
// メッセージ
"全角文字のみ"
~~~

# 半角文字

~~~
// 検証条件
NOT(TESTRE(半角文字,"^[ -~｡-ﾟ]*$"))
// メッセージ
"半角文字のみ"
~~~
Push通知の証明書だけ切れた場合（p12形式）

# はじめに
「あれ？急にiOSアプリにPush通知が届かなくなった」、そんなことないでしょうか？

私は今週ちょうどありました。

色々調べてもらって、原因っぽいのがFirebaseに登録している証明書が期限切れになっていたこと。
「じゃあ、証明書更新するか（管理上の問題でPJで更新作業ができるのは私だけ）...」
「あれ？前どうやったっけ？Wikiに書いたけど、Wikiを読んでも記憶が...」

ってことになりました。
キャプチャ付きでWikiを書いておけばいいのですが、前回はトラブルシューティングとしてあれこれやった結果、解決した...って感じだったので、テキストで要点しか残っておらず...

今回もそうなりそうですが、ひとまずOutputすることで記憶の定着に役立てばと思い記事を書いています。

※この記事は主に自分自身の備忘録です。
※iOSはメインスキルではないので、理解が誤っている部分もあるかもしれません🙇

# やったこと（テキストメモ）

- 認証局に証明書をリクエスト（使用するメールアドレスは管理者権限のアドレスを使用）
- AppleDeveloperでCertificateを作成
（開発はSandBoxの方のApple Push Serviceを選択 / リリースビルドは SandBoxなしのApple Push Serviceを選択）
- CertificateをビルドするMacにダウンロードして、ダブルクリック→キーチェーンに登録
- キーチェーンからp12を書き出す
- p12をFirebaseにアップロード

これで、Pushが届くようになりました！開発環境は！...
Adhoc配信用にリリースビルドも行っている場合、本番証明書も必要です。

Certificateを使いまわさず（ここ重要みたいです）、
上記と同じ手順を実行...

証明書を更新しようとしてエラーが出たら、一度証明書を削除して、アップロードし直すと更新できました。

ちなみに、解説等はこちらのサイトが参考になりました。

https://zenn.dev/karabiner_inc/articles/5934d07986948c

# 他に書いておくこと

p8 形式の鍵を使うと更新の手間から解放されるみたいです。
AppleもFirebaseも今後はこちらが主流になりそう（なってる？）ですが、すでにp12で運用していると移行はちょっと怖いですね。とはいえ、進めてみたいところです。

# まとめ

p８を使うようになるとこの知識が不要になる。
とはいえ、Push以外の証明書で類似の手順が必要なら結局そちらで苦労は続くのかもしれない😅
Pythonのself

### はじめに
最近pythonを勉強していて出会ったselfが少し曖昧だったので少しまとめておく。

### クラスとは
オブジェクトを生成する型のようなもの。
以下のように使われる。
```python:qiita.py
class className():
    pass

instance = className()
```

### selfとは
インスタンス自身のこと。
以下のように使われる。
```python
class className():
    def __init__(self, strA, strB):
        self.strA = strA
        self.strB = strB

instance = className("hello", "qiita")
print(instance.strA)
print(instance.strB)
```
このコードでいう`instance`が`self`なのではないかという認識。

### 注意点
これは面白いなと思ったのがpythonはクラス変数にもインスタンス変数にも値がある場合は、インスタンス変数を優先して参照する。
```python
class className():
    strA = "Hello qiita"
    def __init__(self):
        print("1: " + self.strA)
        self.strA = "Hello World!"
        print("2: " + self.strA)
        strA = "Hello python"
        print("3: " + self.strA)
 
test = className()
```
結果は
```python
1: Hello python
2: Hello World!
3: Hello World!
```
strAよりもself.strAが優先される。

### 最後に
ちょっと知らなかったことに出会ったのでまとめてみました。間違いがあったらぜひ教えてください。
<JavaScript> Memo: A Function to Order Amateur Radio Callsigns According to JARL Bureau's Rule

## Goal

To issue QSL cards (contact confirmation cards) to amateur radio stations, we need to sort them according to a certain rule defined by JARL (Japan Amateur Radio League):

https://www.jarl.org/Japanese/5_Nyukai/qsl-sq.htm

I wrote a function to obtain sorting keys from callsigns for this purpose.


## Code

```JavaScript:JavaScript

const JACallSignRegex = /^(?<prefix>J[A-S]|7[J-N]|8[J-N])(?<area>\d)(?<suffix>[0-9A-Za-z]+)(?:\/(?<modifier>.+))?$/i;

function JARLBureauOrderKey(callSign){

    let resultKey = "";

    if(JACallSignRegex.test(callSign)){
        let callSignMatch = callSign.match(JACallSignRegex);
        switch(callSignMatch.groups.prefix[0]){
            case "J":
                resultKey = "1" 
                        + ((parseInt(callSignMatch.groups.area) - 1 + 10)% 10 + 1).toString(16)
                        + callSignMatch.groups.prefix
                        + callSignMatch.groups.suffix.length
                        + callSignMatch.groups.suffix;
                break;

            case "7":
                resultKey = "7"
                        + callSignMatch.groups.prefix
                        + ((parseInt(callSignMatch.groups.area) - 1 + 10)% 10 + 1).toString(16)
                        + callSignMatch.groups.suffix;

                break;

            case "8":
                resultKey = "8"
                        + callSignMatch.groups.prefix
                        + ((parseInt(callSignMatch.groups.area) - 1 + 10)% 10 + 1).toString(16)
                        + callSignMatch.groups.suffix;

                break;

            default:
                resultKey = "0" + callSign
        }
    }
    else{
        resultKey = "0" + callSign
    }

    return resultKey;
}
 
```

## Example

In the ASCII order,...
```
[Callsign]       [Key]
7J1xxx     ->   77J3xxx
7N1xxx     ->   77N1xxx
7N4xxx     ->   77N4xxx
8J0x       ->   88Jax
8N2xxxx    ->   88N2xxxx
JA0xxx     ->   1aJA3xxx
JA1AAA     ->   11JA3AAA
JA1QQ      ->   11JA2QQ
JA2AA      ->   12JA2AA
JR1xxx     ->   11JR3xxx
JR2xxx     ->   12JR3xxx
JR3xxx     ->   13JR3xxx
```
("x" stands for an arbitrary alphabet)

These should be ordered as
```
JA1QQ
JA1AAA
JR1xxx
JA2AA
JR2xxx
JR3xxx
JA0xxx
7J1xxx
7N1xxx
7N4xxx
8J0x
8N2xxxx
```
and so are they by using the key.
【AWS S3】直接アップロードしたファイルが公開できない

こんにちは、現在エンジニアを目指して勉強中の一般男性です。

ポーフォリオ作品を制作しているなかで
外部のファイルストレージにはAWS S3を選択しました。
その中で、ポートフォリオサイトからのファイルアップロード、表示には成功するものの
S3に直接入れたファイルを表示することができませんでした。

S3まわりは権限設定等が複雑でいろいろな記事もあったのですが、
今回私が解決できた方法は見受けられなかったので
メモとして残しておきます。

## 環境
・macOS Monterey 12.6
・PHP 8.1.13
・Laravel 9.3.12
・Laravel Sail
・Docker 20.10.2

## エラー時の状況

![スクリーンショット 2023-02-04 12.35.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2535390/5902e279-114f-e450-162a-554f1edcfa04.png)

AWSマネジメントコンソールの画面にて、
オレンジ色のアップロードボタンからからファイルを直接アップ。
`img`タグで読み込もうとするも表示されない。

そこでS3内のオブジェクトを呼び出すURLをそのまま検索してみると、
![スクリーンショット 2023-02-04 17.51.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2535390/022b8691-6b3a-e5f7-32a6-340753fb35d6.png)
アクセスが拒否されている。。

## 公開設定

いろいろな記事を読んでガチャガチャやったのですが、
結局自分の場合は以下の方法でした。

### マネジメントコンソールで対象オブジェクトのアクセス許可を確認

![スクリーンショット 2023-02-04 18.07.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2535390/33e1be3b-58ee-d39e-6423-461baa3dfe8c.png)

### 公開できているオブジェクトの設定と比較

![スクリーンショット 2023-02-04 18.23.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2535390/746299dd-4274-69ae-e013-6e1aeafbf604.png)

比較してみると一目瞭然ですね。
読み込めないオブジェクトは所有者しか読み込みができない設定で、
公開できているものは __パブリックアクセスがオブジェクトを「読み込み可」__ になっています。

なので、公開したいオブジェクトに戻って __「編集」をクリック！__

### アクセスコントロールリストを編集

![スクリーンショット 2023-02-04 18.28.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2535390/d9c00871-16ea-ecae-dff4-8d20e10b1676.png)

これで無事に公開できました！

## 参考

公式がYoutubeやっていたのでご参考までに、、

https://www.youtube.com/watch?v=hI64CFAjmig
Salescloud Consultant 学習メモ③

<h3>価格表</h3>
商品の価格を管理するオブジェクト

<h3>商品</h3>
商品情報を管理するオブジェクト（商品名、商品コードなど）

商談、見積、注文、サービス契約に関連する

＜商品を追加する方法＞
①価格表選択
②同じ価格表から商品を追加（複数可）


価格表と商品を使用するためには必要な設定は？
：それぞれ有効化する必要がある

価格表へのアクセス権
：組織の共有設定、価格表の手動共有

<h3>商品スケジュール</h3>
商品の支払い、納品サイクルを管理


＜商品スケジュールを使用する方法＞
①組織の設定で有効化
②スケジュールを使用する商品で有効化

数量スケジュール：一括で支払い・段階的に受け取る（お客様への納入サイクル）
収益スケジュール：分割で支払い・一度に受け取る（お客様からの支払いサイクル）
数量+収益スケジュール：分割で支払い・分割で受け取る

・商談にスケジュールを設定する場合→商談商品にデフォルトでスケジュールが作成される。
・商談商品のスケジュールは編集や再設定が可能

<h3>マルチ通貨</h3>

＜マルチ通貨を使用する方法＞
・マルチ通貨の有効化（サポートに問い合わせ）
※一度有効化すると無効かできない

取引先、リード、商談、商談商品などで使われる
標準価格と商品のリスト価格を複数通貨で設定することが可能

<h3>見積</h3>
商談　+　商談商品　➡　見積

＜見積の作成方法＞
①商談レコードの関連リストから見積を選択
②新規をクリック→詳細情報を入力して作成
③商談に同期したい場合、「同期開始」ボタンをクリック
（ちゃんと同期されたのか確認するためには、同期中項目にチェックが入っているのか確認）

※商談には複数の見積を設定できるが、一度に同期できる見積は１つだけ

<h3>売上予測</h3>
一定の期間内に成立する見込みがある商談のこと
パイプラインの１つの要素

<h5>売り上げ予測の種別</h5>
・商談の金額をベースにした予測

・商談の数量をベースにした予測
・商談ファミリごとの金額・数量
・テリトリーごとの予測

※４つまで有効化できる

<h5>売上予測の除外</h5>

①商談フェーズを「売上予測から除外」に移動
②確度を0%に設定

<h5>売上予測マネージャー

売上予測階層で割り当てをすることによって設定が可能

<h5>売上目標の登録</h5>
・設定の「売上予測目標」で入力

・データローダ
・API
Docker＋nginx＋Laravel シンボリックリンク

以前したミスを忘れていてなんやかんや5時間試行錯誤したのち、突然思い出したのでもう忘れないようにメモ

storageに対してのシンボリックリンクを貼る方法を調べると基本的に
```
php artisan storage:link
```
こいつが出てくるのでphpの方でコピペしてやってしまいがちだが、これではnginxコンテナの方で間違ったルーティングがされてしまうため、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3123564/b59a9e8a-9de6-7125-871f-7af5c21f6c30.png)
nginxのコンテナに入って
```
cd usr/share/nginx/html/public
ln -s /usr/share/nginx/html/storage/app/public storage
```
こう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3123564/01ef7ddc-55d6-0c6f-ca87-5e6a60fe7555.png)
以上。

試行錯誤の中で、アクセス権限やnginxの仕組みについて少し理解が深まった。
Litで@clickイベントが発火しない

# はじめに

マイクロフロントエンドを行うことになったので、Litというフレームワークの学習を始めました

https://lit.dev/

そこで簡単なフロントエンドを作った際にクリックイベントでつまづいたのでまとめます

# 問題

以下のようなコードを作成しました

```ts
  private _imageClick() {
    console.log("Click")
  }

(省略)

          <img
            src="${this.user.topImage}"
            class="subImg"
            @click=${this._imageClick()}
          />
```

画像をクリックするとコンソールに`Click`と表示するような簡単なコンポーネントになります

しかし、なぜか画像をクリックしても発火せずコンソールに何も表示されませんでした

# 解決方法

```ts
@click=${this._imageClick()}
↓
@click=${this._imageClick}
```

としたところでうまくいきました
また引数を渡そうとして`this._imageClick(this.user.image)`のように引数を渡したのですがこれも動きませんでした

なにか方法があるのかと思いますが、そこまではまだわかりませんでした

関数側では`Event`を受け取れるので、そこからhtmlの属性を使うことができます

```ts
  private _imageClick(e: Event) {
    this.topImage = (e.target as HTMLImageElement).src;
  }
```

# おわりに

まだまだわからないことばかりですが、がんばりたいです
[Rust] Get通信を行う処理をラッピング

## ディレクトリ構造

```
.
├── Cargo.toml
└── src
    ├── main.rs
    └── request.rs
```

## 使用ライブラリ
```toml: Cargo.toml
[package]
name = "application"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
tokio = { version = "1", features = ["full"] }
reqwest = "0.11.14"
http = "0.2.8"
```

## 自作ライブラリ
```rust: request.rs
use reqwest::{Client, Response};

/// reqwestのClientを使い回すための構造体
pub struct Request {
    pub client: Client,
}

impl Request {
    /// Get通信を実施してresponseを返す
    pub async fn get_response(&self, url: &str) -> Response {
        self.client.get(url).send().await.unwrap()
    }
}

#[cfg(test)]
mod tests {

    use super::Request;
    use http::StatusCode;

    fn init_request() -> Request {
        Request {
            client: reqwest::Client::new(),
        }
    }

    /// get通信のステータスコードが200（正常通信）である場合のテスト
    #[tokio::test]
    async fn test_get_response_200() {
        let request = init_request();
        let url = "https://crisis.yahoo.co.jp/evacuation/";
        assert_eq!(StatusCode::OK, request.get_response(url).await.status());
    }

    /// get通信のステータスコードが200以外（異常通信）である場合のテスト
    #[should_panic]
    #[tokio::test]
    async fn test_get_response_404_panic() {
        let request = init_request();
        let url = "hoge";
        request.get_response(url).await;
    }
}

```

## main処理
```rust: main.rs
use reqwest::Client;

mod request;

#[tokio::main]
async fn main() {
    let request = request::Request {
        client: Client::new(),
    };
    let url = "https://crisis.yahoo.co.jp/evacuation/";
    let html = request.get_response(url).await.text().await.unwrap();
    println!("{html}");
}

```
JavaScriptでデザインパターン〜シングルトン

# デザインパターンとは
　デザインパターンは、大規模なソフトウェア開発の課題に対する一般的な解決策を提供するものです。これらのパターンは、特定のタイプの問題に対してよく使われる方法をまとめたものです。
　例えば、本を作ることと同じように、ソフトウェア開発も複雑な作業です。そのため、作り方を整理することが重要です。「本を作るためのレシピ」のようなものがデザインパターンです。これらのレシピに従っていけば、正しい作り方を覚えることができます。
　デザインパターンは、ソフトウェア開発においても同じような問題を解決するためのレシピのようなものです。これらのパターンを知っていることで、効率的かつ正確なソフトウェア開発を行うことができます。

# シングルトン
　シングルトンパターンは、ある特定のクラスのインスタンスがアプリケーション内で最大1つしか生成されないことを保証する設計パターンです。これにより、クラスのインスタンスを共有して、全体のコード内で同じ状態を共有することができます。


　Javascriptにはクラスがなく、オブジェクトしかないため、新しく作成されたオブジェクトはシングルトンになります。
```Javascript:singleton.js
var a = {
  word: 'あいう'
}

var b = {
  word: 'あいう'
}

console.log(a === b) // false
```
このようにkey-valueが同じオブジェクトを作成しても、お互いを比較した時にFalseとなり
異なるオブジェクトとなります。

　そのためJavaScriptで実装する場合は、コンストラクタ関数を使用してクラスを定義し、そのクラスのインスタンスを生成するためにnew演算子を使用する代わりに、単一のインスタンスを保持するプロパティを持った単独のオブジェクトを使用することが一般的です。

```Javascript:singleton.js
class Sample {
  constructor () {
    if (Sample.instance) {
      return Sample.instance
    }
    Sample.instance = this
  }
}
const c = new Sample()
const d = new Sample()

console.log(c == d) // true
console.log(c === d) // true
```
メールで送られてくる週報が、期限通りに提出されているかの集計を自動化する


# 動機

自分の会社ではメールで週報をチーム内で送付しており、これが期限通りに出されているか部門内でチェックしている。これまではそれは手動集計していたが、手間もかかるのでPowerAutomateで自動化したい。

中身の確認はまた別の話題として、ここでは期限までに間に合っているか、のみを確認する。

またそもそもそういう形式の週報は時代遅れ、みたいな話もあると思うが、いったんそれも置いておく。

# Listの準備

結果を登録するためのListを作成する。

| 項目  | 種類  | 補足  |
| --- | --- | --- |
| タイトル | 文字列 | デフォルトであるカラムなので適当に使う |
| 受信日 | 日時  |     |
| 送信者 | ユーザー |     |
| 週報の対象期間 | 日時  |     |
| 判定  | 選択肢 | OK, Late, Too Late |

判定は文字列でもいいのだが、選択肢の方がListを見たときに色で識別できて、なんとなくわかりやすいので選択肢にしている。

# ワークフロー作成

全体感は以下

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/0d742f99-bf8e-e517-4f63-81461bfa43ce.png)

## 新しいメールが届いたとき(V3)

これはそのまんまなので割愛。仕訳ルールなどで、特定のフォルダに仕分けしておいた方がやりやすいだろう。

## 条件4(RE:の除外)

これもほぼそのままだが念のため。もっとうまい方法ありそうだけど。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/d4e064e0-8d9e-53f5-16e0-6b1ca4b1ad51.png)

## 変数を初期化する(週報の対象期間の初日を取得)

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/f926f34c-d1a5-1180-4551-bb01ec6dce82.png)

`split(triggerOutputs()?['body/subject'], ' ')[4]`

自分の場合、件名にその週報が対応する期間の記載があるので、この方法で対象の期間を指定している。以下のような件名から、「2022/06/27」を抜き出す。

例: 【チーム名】[文字列] - 週報 2022/06/27 - 2022/07/03　XXXX

## 変数を初期化する2(何日遅れか)

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/f4567e5d-596f-5650-f593-9d5a73fb935b.png)

`int(split(dateDifference(triggerOutputs()?['body/receivedDateTime'],formatDateTime(variables('期間'))),'.')[0])`

こちらのような式で、提出がどのくらい遅れているかを整数で取得する。

## 変数を初期化する3(遅れ具合の判定)

いったん遅れ具合を判定する変数を作る。定義時に細かい条件分けできないので、いったんOKをデフォルトとして、受け皿を作る感じ。

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/bd3b2969-c9bb-be0f-4c92-cac708f92fff.png)

## 条件2(遅れ具合の判定)

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/51e1b612-60ca-fee2-cb0b-bf7b3564ca1b.png)

自分の場合、翌週の火曜日までに提出するので、9日遅れまでをOKとして、2週間以上の遅れをToo Lateとしている。

## 項目の作成

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/04fbc194-0d04-8bae-454c-c58747cd23e1.png)

後は用意したListに追加するだけ

# さらに

List化しているので、これをPower BIなどで可視化するとより見やすくなるだろう。

またこれだと、「そもそも出していない」人は識別できないので、注意が必要。
Azure更新情報（2023/2/4）

インフラ好きなので少し偏りがありますが、新たにGAまたはPreview開始したサービスのご紹介などを中心にAzureの最新情報をお届けします。

# Updates
## Blobタイプを変換できるようになりました！

https://azure.microsoft.com/en-us/updates/generally-available-apply-azure-storage-access-tiers-to-append-blobs-and-page-blobs-with-blob-type-conversion/

AzureのオブジェクトストレージであるBlobは、あまり意識することはないですが内部的には3つのストレージタイプ(Append Blob/Page Blob/Block Blob)が存在します。

https://learn.microsoft.com/ja-jp/rest/api/storageservices/Understanding-Block-Blobs--Append-Blobs--and-Page-Blobs

また、BlobはHot/Cool/Archiveというアクセス層を提供しており、アクセス層によって読み込み速度や単価が異なります。さらにライフサイクル管理という機能を用いて古くなったデータを適切なアクセス層に自動的に移行することができます。

https://learn.microsoft.com/ja-jp/azure/storage/blobs/lifecycle-management-overview

しかし、このアクセス層の変更はBlock Blobでのみ許可されており、Defender for Cloudログやアクティビティログ、AzurePolicy準拠ログなどはAzure StorageへAppend Blob（追加Blob）として格納されアクセス層の変更はできませんでしたので、これは便利ですね！

## Load TestingがGAしました！

https://azure.microsoft.com/ja-jp/blog/microsoft-azure-load-testing-is-now-generally-available/

JMeterのマネージドサービスですね。既にJMeterを利用している場合、既存の スクリプトを再利用することで簡単に始めることができます。

## Cost Managementが機能追加されました！

https://azure.microsoft.com/ja-jp/blog/microsoft-cost-management-updates-january-2023/

Cost Managementは最近どんどんアップデートされ、コストに関するより詳細な分析や集計がBIツールをなどを使うことなくAzure Portal上で簡単にできるようになってきています。しかも無料で！
機能追加されたものをいくつか紹介しますと、

- Azure PortalでEA契約も管理できるようになりました
    - これまでEA PortalとAzure Portalの2つが存在していたので、よりシンプルになりましたね
    - https://learn.microsoft.com/ja-jp/azure/cost-management-billing/manage/direct-ea-administration
- 「最近使った項目」が出るようになりました
    - 現時点ではCost Managementを開くと「コスト分析（プレビュー）」と「コスト分析」の二つがありますが、どちらかでよく使うビューを記憶し、より早くいつもの分析をできるようになりました。
    ![スクリーンショット 2023-02-04 174019.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124498/6436b80e-688c-749c-b432-2164a233ba88.png)


- ドキュメントと動画がアップデートされました
    - 例えばこんな感じです
        - https://www.youtube.com/c/AzureCostManagement
        - https://learn.microsoft.com/ja-jp/azure/cost-management-billing/savings-plan/buy-savings-plan
 

# ブログ
## Scale Azure Firewall SNAT ports with NAT Gateway for large workloads

https://azure.microsoft.com/ja-jp/blog/scale-azure-firewall-snat-ports-with-nat-gateway-for-large-workloads/

SNATポート枯渇に関する記事。下図のようなAzure FirewallとNAT Gatewayを組み合わせることで、SNATポート枯渇とアウトバウントトラフィックのセキュリティ対策を同時に実現することができます。
![ac98cb18-8495-4e50-afdc-f325432ed279.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124498/59b7d31e-6ae8-95be-c047-28a23b005b7e.png)

## Reflecting on the first year and future of The Azure Storage Migration Program

https://techcommunity.microsoft.com/t5/azure-storage-blog/reflecting-on-the-first-year-and-future-of-the-azure-storage/ba-p/3720451

2021年2月にAzure Storage Migration Programを発表して2年が経つので、これまでの取り組み（80TBのデータをAzure Filesに移行した事例）とこれから（Azure Storege Moverとか）についてまとめています。

https://learn.microsoft.com/ja-jp/azure/storage-mover/service-overview
Node http-serverの使い方

## パッケージインスコ(グローバルインストール)

```
npm i -g http-server
```


サーバー起動(事前にhtmlファイルを設置してください。)
```
http-server .
```

ポート指定
```
http-server . -p 8080
```

## パッケージページ
https://www.npmjs.com/package/http-server
知識０から学ぶソフトウエアテスト　メモ

## 著者
米Microsoft社・独SAP社、でソフトウエアテスト業務に従事。ソニーのソフトウエア品質担当部長を経て、株式会社デジタルハーツホールディングスCTSOに就任。

## 1章　
高橋寿一氏は、
「ソフトウエアテストで重要なのは、どの部分にバグが出やすいのか、そこにどのようなテスト手法を適用すれば十分な品質が得られるかを知ることである」
と説いている。

## 2章
ホワイトボックスとは、プログラムの構造を分析する作業。
ブランチカバレッジとは、分岐コードのtrueとfalseの結果を少なくとも1回は出力するテスト手法。
カバレッジテストで検出できないバグとは、プログラムのループ、要求仕様自体の誤り及び機能不備、データに関するバグ、タイミングに関するバグ。
TDDとは、短期間でテスト・リファクタリングを行うテスト手法

## 3章
ブラックボックスとは、ソースコードを見ず、行うテスト手法
同値分割手法とは、有効な入力値クラスと無効な入力値クラスに分けて、テストを行う手法。ポイントとしては、入力値が網羅する範囲を理解しておくこと。
境界値分析法とは、有効同値と無効同値の間をテストする手法
テストする時に必ず入力すべきデータとは、使用者が使いそうなデータ、プログラムが許す最小値と最大値、ゼロ。一方ですべきでないデータは、極めて小さな値や大きな値、長いデータ、無効なデータ。
状態遷移テストとは、画面の切り替え等をテストする手法
デイシジョンテーブルとは、あらゆる入力を表にし、その入力に対する出力を明記するテスト手法

## 5章
非機能要求のテストにおける重要な項目とは、パフォーマンス、セキュリティ、信頼性
パフォーマンスでは、ベンチワークを下回っていないかをチェックする。
セキュリティでは、プログラムだけでなく、ネットワークやDBからの入力によってプロダクトが機能不全や改竄されたりすることがないかテストする。
信頼性とは、負荷テストを行い、バグが発生しないかチェックする。


## 参考資料
知識ゼロから学ぶソフトウェアテスト 【改訂版】
超旧式 iOS でストレージが不思議に一杯に？！

10年以上前に購入した iPad 2 をまだ使っている。iOS はこのモデルの最終版 9.3.5。最新のアプリはもちろんのこと、普通のネットのブラウジングもほぼ全く不可能。
でも、音楽の再生には充分。Music アプリの他、LAN のストリーミングサーバー Jellyfin をブラウザーでアクセス（Jellyfin アプリは使えない）、そして NHK のラジオアプリを使っている。Jellyfin はたまに落るが、NHK アプリ全く問題ない。

それが、数ヶ月前から「ストレージ一杯」の警告が出始めた。いらないメディアやテータ、古いアプリを消してみた。でも時間が経つとまたストレージが減って行く。更に削減。全ての写真と音楽ファイルを削除。

それでも。結局消せるものを全て消しても、64GB のストレージの残量が 0 バイトに。アプリの一時的データも保存できないので、操作がガクっと遅くなる。もう使い物にならない。詳細を見ると、ストレージを所有しているのは90%以上が「その他」。(古い OS でデバイス上では見れないが、iTunes で見れる。)。つまり、OS が内部で取っている一時データで、設定などからのアクセスは不可能。

Apple のフォーラムを調べたら、この問題は既に挙げられていたが、解決法がない。
取り敢えず完全バックアップ & リストアしてみたが、効果なし。ただし、完全リセットするととアプリも消えてしまうのでこれは怖い。インストールされているアプリは随分古いので、AppStore から再度インストールが不可能らしい。再度 Apple フォーラムで質問を挙げると、即時解答が：「あなたのストレージの管理に問題があるのでは」と。完全バカにしてる、こいつ。

結局どうしようもなく、バックアップ + 完全リセット + リストアでシステムを復元できた。幸いにアプリもちゃんと入っていた。（古い OS だから？）。そしてストレージを見ると、使用中 1.7GB、フリー 55GB! すっきり！

それが... 復元して以来、使っているのは（前通り）音楽の再生のみ。今朝は NHK アプリで 2時間ほどのストリーミング、そして、Jellyfin で一時間程の再生。で、ストレージを見ると、なんと使用中がもう 4.7GB に上がっている。

これじゃ、一ヶ月でまた一杯になるじゃないか。それでまた完全リセットか？！

iOS 酷すぎる。
YDLIDARのGS2をpythonで扱う


# 背景
- RCサイズのモビリティに適したLidarが欲しい
- サンプリングレートが30Hz位は欲しい
- 30cm位は検知範囲欲しい
- ホビー用途でお財布にやさしい

## ➔YDLIDAR GS2
![GS2image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350922/703278c8-1ac5-f658-aa01-beeaab24b618.png)
https://www.ydlidar.com/products/view/11.html

価格は6000円位
https://ja.aliexpress.com/item/1005004291137996.html
複数利用のため、808nmと850nmの2つの帯域が有る。

## Pythonで使いたい
DonkeycarやJetracerに簡単に組み込むため、pythonが良い
- 直接pySerialで値を拾おうと思ったが、通信が開始されず断念。
- gitにSDKとチュートリアルが落ちてる。これを使う。
https://github.com/YDLIDAR
https://github.com/YDLIDAR/YDLidar-SDK/blob/master/doc/tutorials/writing_lidar_tutorial_python.md
- githubの説明に沿ってインストール
https://github.com/YDLIDAR/YDLidar-SDK/blob/master/doc/howto/how_to_build_and_install.md

# サンプルの場所とパラメータ設定に注意
- 色々触ってみて、GS2が動くサンプルはこれ。GS2+S2で使う場合のもの。
https://github.com/YDLIDAR/YDLidar-SDK/blob/master/samples/tri_and_gs_test.cpp
- 上記を参考に下記のようにいじる。
```diff_python:lidar_tutorial.py
import os
import ydlidar

if __name__ == "__main__":
    ydlidar.os_init();
    laser = ydlidar.CYdLidar();
    ports = ydlidar.lidarPortList();
    port = "/dev/ydlidar";
    for key, value in ports.items():
        port = value;
    laser.setlidaropt(ydlidar.LidarPropSerialPort, port);
-    laser.setlidaropt(ydlidar.LidarPropSerialBaudrate, 512000);
+    laser.setlidaropt(ydlidar.LidarPropSerialBaudrate, 921600);
-    laser.setlidaropt(ydlidar.LidarPropLidarType, ydlidar.TYPE_TOF);
+    laser.setlidaropt(ydlidar.LidarPropLidarType, ydlidar.TYPE_GS);
    laser.setlidaropt(ydlidar.LidarPropDeviceType, ydlidar.YDLIDAR_TYPE_SERIAL);
    laser.setlidaropt(ydlidar.LidarPropScanFrequency, 10.0);
    laser.setlidaropt(ydlidar.LidarPropSampleRate, 20);
    laser.setlidaropt(ydlidar.LidarPropSingleChannel, False);

```


## できた（jetsonnanoで実行）
```console:shell
(env) jetson@jetson-desktop:~/YDLidar-SDK-master/ydlidar_tutorials-master/python_tutorials$ python lidar_tutorial/lidar_tutorial.py
YDLidar SDK initializing
YDLidar SDK has been initialized
[YDLIDAR]:SDK Version: 1.1.3
send: A5A5A5A500640000
send: 64
LiDAR successfully connected
send: A5A5A5A500640000
send: 64
[YDLIDAR]:Lidar running correctly ! The health status: good
send: A5A5A5A500620000
send: 62
[YDLIDAR] Connection established in [/dev/ttyUSB0][921600]:
Firmware version: 2.9
Hardware version: 0
Model: GS2
Serial: 2022090200140896
LiDAR init success, Elapsed time 129 ms
2
send: A5A5A5A500640000
send: 64
send: A5A5A5A500600000
send: 60
[YDLIDAR] GS Lidar count 1
send: A5A5A5A500610000
send: 61
send: A5A5A5A500630000
send: 63
[GS2Lidar] Create GS2 thread 0x931FB1F0
[CYdLidar] Successed to start scan mode, Elapsed time 99 ms
[YDLIDAR] Fixed Size: 506
[YDLIDAR] Sample Rate: 4K
[YDLIDAR INFO1] Current Sampling Rate : 4K
[YDLIDAR INFO] Now YDLIDAR is scanning ......
Scan received[ 1675496681637647000 ]: 160 ranges is [ 1257.86163533801 ]Hz
Scan received[ 1675496681767328000 ]: 160 ranges is [ 12048.192917021735 ]Hz
```

これからパラメータをいじって、モビリティの挙動の制御を進める。
ChatGPT:複数の動画ファイルをpythonで結合するプログラム（完動）

ChatGPTでのプログラミング

#### 課題
複数のmkvファイルを受け取り、python ffmpegを用いて、再エンコードなしで結合するpythonプログラムを作成してください。　mkvファイルはGUIで選択できるようにpysimpleguiを使ってファイルを選択できる仕様にしてください。

追加のお願い
subprocessは使わずpython-ffmpegというライブラリでお願い


```
import ffmpeg
import PySimpleGUI as sg

def merge_mkv_files(file_list):
    inputs = [ffmpeg.input(file) for file in file_list]
    output = ffmpeg.concat(*inputs)
    output = ffmpeg.output(output, 'output.mkv', vcodec="copy")
    ffmpeg.run(output)

def file_picker():
    layout = [
        [sg.Text('Select MKV Files to Merge:')],
        [sg.Input(), sg.FilesBrowse()],
        [sg.Submit(), sg.Cancel()]
    ]
    window = sg.Window('MKV Merge', layout)

    event, values = window.Read()
    window.Close()

    if event == 'Submit':
        file_list = values[0].split(';')
        merge_mkv_files(file_list)

if __name__ == '__main__':
    file_picker()

```


#### 結果
再エンコードなしでという指定は無視されたものの、結合プログラムは完璧にできた
【Rails/Heroku】「`write': No such file or directory @ rb_sysopen - tmp/pids/server.」または、用意したのにYour app does not include a heroku.yml に陥った時

## やりたいこと
- GithubのRepoのmainブランチにマージされたら、Herokuにデプロイされて欲しい
- Docker上で動かしているので、ビルドなどもしてほしい


## 起こったことと対応
公式によると、heroku.ymlを用意する必要があるとのことだったので、サンプル通りに用意しました。

```yaml:heroku.yml
build:
  docker:
    web: Dockerfile
run:
  web: bundle exec puma -C config/puma.rb
```

heroku.yml を使用して Docker イメージをビルドする | Heroku Dev Center 
https://devcenter.heroku.com/ja/articles/build-docker-images-heroku-yml

これでOKと思ってデプロイしたところ、

```
/usr/local/bundle/gems/puma-5.6.5/lib/puma/launcher.rb:259:in
`write': No such file or directory @ rb_sysopen - tmp/pids/server.pid (Errno::ENOENT)`
```

というエラーがHerokuで発生。
調査の結果、`tmp/pids`ディレクトリができていないとのことだったので、下記のように修正しました。

```yaml:heroku.yml
build:
  docker:
    web: Dockerfile
run:
  web: mkdir -p tmp/pids && mkdir -p tmp/sockets && bundle exec puma -C config/puma.rb
```

よし、今度こそ...と思ったら、次はこちらでビルドに失敗します。


```
=== Fetching app code
=!= Your app does not include a heroku.yml build manifest. 
To deploy your app, either create a heroku.yml: https://devcenter.heroku.com/articles/build-docker-images-heroku-yml
Or switch back to buildpack-based deploys: https://devcenter.heroku.com/articles/container-registry-and-runtime#changing-deployment-method
```

**いや、今まさに作ったんだが？**

ということでしばらく悩んだのですが、原因がわかりました。

自分のプロジェクトは下記のような構成で、フロントとバックをそれぞれ別のプラットフォームにデプロイしています。

```
project
├── .git
├── backend
├── docker-compose.yml
└── frontend
```

それで、backendだけをherokuにデプロイしているので、この中でheroku.ymlを作成していました。
これがHeroku側から参照できていないのかな...？と思い、以下のように構成を変えました。

```
project
├── backend
├── docker-compose.yml
├── frontend
└── heroku.yml
```

Dockerfileも一階層下を見にいくようにします。

```yaml:heroku.yml
build:
  docker:
    web: backend/Dockerfile
run:
  web: mkdir -p tmp/pids && mkdir -p tmp/sockets && bundle exec puma -C config/puma.rb
```

これでデプロイしたら、無事ビルドされました...！
Docker側の設定で、Heroku.ymlの場所を指定するとかもあるかなと思ったのですが、見当たらなかったのでルートに配置した次第です。

誰かのためになれば幸いです。