OmniAICreator/Qiita-1.07M huggingface dataset:
robloxでassistant その138

# 概要
robloxでassistantやってみた。
練習問題、やってみた。

# 練習問題
pluginでmake scriptせよ。

# サンプルコード

```
local PluginBar = plugin:CreateToolbar("creator")
local Button1 = PluginBar:CreateButton("creator", "Create new script", "rbxassetid://14978048121", "Create")

Button1.Click:Connect(function()
	local helloScript = Instance.new("LocalScript")
	helloScript.Name = "helloscript"
	helloScript.Parent = game.ReplicatedFirst
	helloScript.Source = "print(\"hello\")"
	print("ok")
end)

```


以上。
Uncaught Error: [Routes] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>エラー解決法

## Uncaught Error: [Routes] is not a <Route> component. All component children of <Routes> must be a Route or React.Fragmentエラー解決法

# エラーが発生する原因になっているコード
```App.jsx
<Routes>
      <Route path="/" element={<Home />} />
      <Routes path="/page1">
        <Route index={true} element={<Page1 />} />
            <Route path="detailA" element={<Page1DetailA />} />
            <Route path="detailB" element={<Page1DetailB />} />
        </Routes>
      <Route path="/page2" element={<Page2 />} />
    </Routes>
```
# エラー原因
* Routesの中にRoutesを入れていて、入れ子状態になっている為。
⇒Routesの中でRoutesを入れ子にして使うことはできない

# 解決法
Routesは全体で1つにして入れ子にしたいところはRouteで囲う

# 修正したコード
```App.jsx
<Routes>
      <Route path="/" element={<Home />} />
      <Route path="/page1">
        <Route index={true} element={<Page1 />} />
            <Route path="detailA" element={<Page1DetailA />} />
            <Route path="detailB" element={<Page1DetailB />} />
        </Route>
      <Route path="/page2" element={<Page2 />} />
    </Routes>
```
【JavaScript】宝くじ (paizaランク C 相当) やってみたのと解説

これのやつです。

https://qiita.com/official-events/9ab96aa95d62fe3cbdd7

今回は、「どんな風に書いていこうかな」ってノリを模索するために書いてます。
書き方は他の人のを真似しています。

# 問題
https://paiza.jp/works/mondai/c_rank_skillcheck_archive/lottery

# 解答コード
```javascript
process.stdin.resume();
process.stdin.setEncoding('utf8');
// 自分の得意な言語で
// Let's チャレンジ！！
var lines = [];
var reader = require('readline').createInterface({
  input: process.stdin,
  output: process.stdout
});
reader.on('line', (line) => {
  lines.push(line);
});
reader.on('close', () => {
    const winningNumber = Number(lines[0]);
    
    const adjacents = [];
    if(100000 < winningNumber) adjacents.push(String(winningNumber - 1));
    if(199999 > winningNumber) adjacents.push(String(winningNumber + 1));
    
    const n = Number(lines[1]);
    for(let i=0; i<n; i++){
        const currentNumber = lines[i+2];
        
        if(currentNumber === lines[0]){
            console.log("first");
        }else if(adjacents.includes(currentNumber)){
            console.log("adjacent");
        }else if(currentNumber.endsWith(lines[0].substr(-4))){
            console.log("second");
        }else if(currentNumber.endsWith(lines[0].substr(-3))){
            console.log("third");
        }else{
            console.log("blank");
        }
    }
    
});
```

# 解説
色つけと書き込みすぎて汚いかも
![CleanShot 2024-07-20 at 20.46.45@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435274/dc336fa0-d04d-c82b-6802-a1af4a21d48e.png)

# 感想
自分なりに解説書いてみたけど見にくいかも。
というか問題文のスクショって載せて大丈夫なのだろうか。
とりあえず、その時々でこんな感じでやってみる。
今日の発見 input要素にv-modelをしたときにstringになる

まずこちらをご覧ください。

https://play.vuejs.org/#eNp9kc1OwzAQhF/F8qWtVBIQnKq0EqAe4AAIOPoSpZs0xX+y16EoyruzdpTSA+rNmpmd/Vbu+b21WReAr3jhK9daZB4w2I3QrbLGIeuZg3pZGWUDwo4NrHZGsRnNzISujPbIdFBsHWPz68WkKd+QNo3N54v1Bn8smDqms66UAShb5ONSWlcgKCtLBHozVuxvUn7F+j51DUORk5a8VlMp666U2YFcC06NgrM8luRnLXzJ0RNN3TbZwRtNN/ZxXvCI1UpwrxZbohWc1kQneqWU5vs5aegCLCe92kP19Y9+8MeoCf7mwIPrQPCTh6VrAEd7+/ECR3qfTKIPktIXzHfwRobIOMYegt4R9lku0T6ln2p18+m3RwTtp6MiaEwOKS84fdrjhdP/cG+zuzQn9MCHX8LatqY=

`num`にはリアクティブな0が入ってて、`msg`には`num`の値の型を`computed`で出力します。
`num`が代入された直後なので上に表示された型名は`number`ですが、下のinput要素内の値を変えてみてください。

**なんと変えた瞬間に型名が`string`になったではないですか!!**

そう、input要素のvalueプロパティは`string`になるのです！知ってましたか？
自分は知りませんでした。しかし今日発見しました。
## 自分が今まで気づかなかった理由
皆さんご存じだと思いますが、JavaScriptは動的型付け言語です。
開発者ツールのコンソールなどで以下を入力してエンターしてみてください。
```js
"2" * 2
```
![2024-07-19 (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3744180/ea070cd1-ca2a-c217-61ed-83cc4cd20fa4.png)

**なんと4になるではないですか!!**

しかし本当は文字列なのかもしれない。という希望をもって`typeof`してみましょう。
```js
typeof ("2" * 2)
```
![2024-07-19 (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3744180/7d674b5f-b3b8-4402-c3fa-8bd1a76438d5.png)

**なんと普通の数字ではないですか!!**

そう、こういう文字列を数字と解釈したりするため、気づかないことがあるのです!!

:::note info
ちなみに確認した範囲では`-`、`/`、`**`、などの演算子、
`===`以外の比較演算子や、`Math`オブジェクト系も勝手に`number`に解釈するようです
:::

## 自分が今日気づいた理由
`+`したら気づきました。

再現画像
![2024-07-19 (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3744180/b672975a-8b1f-557d-771e-f81b8f0bf42e.png)

**なんと`+`するときは`number`を`string`に解釈するではないですか!!**

は？となりますが、このコードをみればその理由がわかるでしょう。
```js:sample.js
let pi = 3.14;
console.log("円周率は" + pi + "だよ！");
```
2行目の二つの文字列を`number`に変換しようものなら両方が`NaN`になって`NaN`が出力されてしまいます。
## 対処法
### 1.演算時にparseIntする(Vueじゃなくてもいい)

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/parseInt

```js
import {ref} from "vue"
const num = ref(0)
watch(num,()=>{
    console.log(parseInt(num.value) + 1)
})
```
演算するたびにこの関数が必要になります。
### 2.parseIntするcomputedを参照する

https://ja.vuejs.org/guide/essentials/computed

```js
import {ref,computed} from "vue"
const input = ref(0)
const inputnum = computed(()=>parseInt(input.value))
watch(inputnum,()=>{
    consle.log(inputnum.value + 1)
})
```
演算するたびに呼び出さなくていいし、Vueの要素プロパティに直接使えます。
### 3.computedのセッターとゲッターを使う
```js
import {computed} from "vue"
let realNum = 0
const num = computed({
  get() {
    return realNum
  },
  set(newval) {
    realNum = parseInt(newval)
  }
})
```
値が入った瞬間に数値に変換します。
`computed`を代入した変数でリアクティブに使えるし、
`realNum`では関数内などで`.value`無しで読み取りできます。
これが一番便利だと思います。
## まとめ
これはVueに限らないので知っておいて損はないです。
数字の`input`は`parseInt`しよう！
Google Home Miniが動かなくなっちゃったときの対処法

# なんか動かなくなった
最近X(旧Twitter)でもちょっと話題になっていたGoogle Home(Google Nest)が動かなくなる事象、我が家でも発生しました。
症状としては
- 「ねぇGoogle」「OKGoogle」「HeyGoogle」などのウェイクアップコマンドを呼びかけると数秒待ってから「エラーが発生しました、数秒後にもう一度お試し下さい」と応答する
    - ネットワークが繋がらなくなったときに似ている…？
- キャストによるストリーミング再生は出来る(YouTube Music等)
- Google Homeアプリで操作は出来る

といったような状態でした。
再起動を行っても改善しなかったため強制リセットを試してみました。

# 強制リセット
やり方としては
1. 本体の裏面電源差込口側に丸いエンボスがあるのでそれを通電中に15秒ほど長押しします
1. 「リセットしようとしています。リセットしたくない場合は手を離して下さい。」みたいなことを警告されます
1. リセットが完了するとチャイム音が鳴り、初期状態に戻って音声ガイダンスが開始します

以上で強制リセットが完了します。
Google Homeアプリを起動して再設定を行った所、動かなくなった問題は解消しました。

ぶっちゃけGoogleである理由はないので完全にぶっ壊れたらAlexaに乗り換えるかなぁ…
【AWS】取得したドメインが使えなくなっていた話と解決策【Route53】

## 問題
以前は問題なく使用できていたアーキテクチャのALBでヘルスチェックが「Unhealthy」になりました。
EC2インスタンスの設定やセキュリティグループの問題かと疑いましたが、すぐには原因が特定できず時間をとられてしまったので備忘録です。

## 問題の原因
結局原因はRoute 53でドメイン名を登録した際に、メールから連絡先の検証をし忘れていてドメインが無効になっていたためでした。

Route 53でドメイン名を登録する際にAmazon Route 53から登録者の連絡先情報を確認するメールが届きます。
ドメイン登録手続き後そのメールが送られてきて15日以内にそのメールにあるリンクをクリックしてメールアドレスの認証をしないとドメインが停止されます。
今回そのメールの存在に気づいておらず、ドメインが無効になっていたために、ALBがターゲットのDNS解決に失敗し、ヘルスチェックが「Unhealthy」となっと考えられます。

以下ドメインが無効になった旨の通知メール。

:::note info
メール内容：
○○○ドメインは、2024年4月4日までに登録者連絡先のメールアドレスを確認しなかったため、一時停止されました。

noreply@registrar.amazon.com から ××× への一時停止に関するメールを1通以上送信しましたが、返信がありませんでした。
これらのメールに返信しても、現在は無効です。

ドメイン名システムを管理するICANNは、ドメインの登録、移管、または登録データの更新後に、登録者が連絡先情報を確認することを要求しています。
:::

![S__95051785.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/1709fad6-f67b-cfd9-e8a6-fb09927ec2af.jpeg)

## 解決策
AWSマネジメントコンソールより確認メールを再送し、認証を行うことでドメインを有効化することができます。

1). 更新されたリンクを含むメールメッセージを再送信するようリクエストします。

リクエストするには、Amazon Route 53コンソールのドメインページ（https://console.aws.amazon.com/route53/home?#DomainDetail:testawsapp.com）に移動し、「Send email again（再送信）」を選択します。

2). メールを受け取ったら、15日以内にリンクをクリックします。

![S__94683142 - コピー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/63b5bf8c-6dd8-e519-eafe-6891b570b5c6.jpeg)

クリックすると連絡先の検証がされた旨のメッセージが表示されます。
![S__94683144.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/dc45c7dd-ca91-45d5-e3f3-a43ab77068cf.jpeg)

この作業をしたところALBのヘルスチェックが無事「healty」となりました。

## 終わりに
今回はRoute 53の検証メールを放置していた結果ドメインが無効になってしまっていたというもので、原因も解決策も簡単なものでしたが、知らないと沼ってしまう方もそこそこいるのではないでしょうか。

ちなみに、Route 53でのドメイン名の取得手順については過去に書いていますので、もし興味ある方いましたらご一読よろしくお願いします！
[【AWS】 Amazon Route 53で独自ドメインを取得する手順 【Amazon Route 53】](https://qiita.com/SoraoKosaka/items/f252f9c04e5cf5d8cae8)

この記事が参考になりましたらぜひ「いいね」「フォロー」など励みになるのでよろしくお願いします！
【備忘録】inputタグに必須マークをつけるCSS

# はじめに
inputタグにつけるlabelタグに必須マークをつけるCSSの **備忘録** です。

# スクリーンショット
・参考記事リンクでは必須マークが下にずれてしまいますが、
この記事では縦方向の中央に揃えています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/e930995f-17d9-5d4a-f54e-3d7dd2615b87.png)

# 必須マークのコード
```css
.required {
  position: relative;
}

.required::after {
  content: "必須";
  background-color: #f0ad4e;
  color: #fff;
  font-size: 12px;
  font-weight: bold;
  min-width: 10px;
  padding: 3px 7px;
  margin: 0px 5px;
  line-height: 1;
  white-space: nowrap;
  text-align: center;
  border-radius: 10px;
  display: inline-block;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  right: -50px; /* 必要に応じて調整 */
}
```

```tsx
<label htmlFor="deploy-url" className="font-bold text-xl required">デプロイ先URL</label>
```

# さいごに
参考にさせていただいた記事のリンクです。

https://qiita.com/ponsuke0531/items/9dbe3f03f45412c048bf
勢いだけでAWS Certified Security - Specialty受けたら落ちた話

AWS Certified Security - Specialty (SCS-C02)を受けて来ました。

https://aws.amazon.com/jp/certification/certified-security-specialty/

# １回目
## 勉強量

#### CloudTech

・ずいぶん前に40問くらい解いた。

#### Udemy
・25問の6セットくらいあって、内バラバラに30問くらい解いたとと思う。

#### 書店で購入した参考書※
・演習問題40問を3週
・選択肢について、なぜ正解なのかなぜ不正解なのかを調べて理解
　（参考書内の記載場所を書いてあったので便利。書いて無いこともあったのでそれはぐぐりました。）

※参考書
要点整理から攻略する『AWS認定 セキュリティ-専門知識』 

https://www.amazon.co.jp/%E8%A6%81%E7%82%B9%E6%95%B4%E7%90%86%E3%81%8B%E3%82%89%E6%94%BB%E7%95%A5%E3%81%99%E3%82%8B%E3%80%8EAWS%E8%AA%8D%E5%AE%9A-%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3-%E5%B0%82%E9%96%80%E7%9F%A5%E8%AD%98%E3%80%8F-NRI%E3%83%8D%E3%83%83%E3%83%88%E3%82%B3%E3%83%A0%E6%A0%AA%E5%BC%8F%E4%BC%9A%E7%A4%BE/dp/4839970947

### 理解度

・SAAは持ってるけど、インフラの実務経験なし。
・新しい演習問題を解くと、2割くらいの確率で見たことがある雰囲気の問題が出てくる。
・たまに知らないサービス名とか出てくる。
・解いた問題はちゃんと不正解の選択肢についても調べたので自信があったが、物量に自信がない。

## 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/7842ed0c-b6b8-dfa2-2fdc-526c5b855250.png)

落ちました。
ということで、再来週もう一度受けてきます！

### 手応え

全部わからないみたいなことはなかったです。
勉強した範囲は正しかった感触なので、次は物量を増やして守備範囲を広げる方向にしようと思います。
ただし最小限勉強にしたいです。

## 次受けるまでにすること予定

・Udemy全部解く

# ２回目

落ちました、、

# 3回目

coming soon...
params[:id]とparams[:テーブル名_id]との違い

プログラミング歴、1年未満の初学者です。
タイトルでもある通り、params[:id]とparams[:cocktail_id]（例）との使い分け方について、webアプリを作成中に知ったので、cocktailを例に上げて、書かせていただきます。

cocktail = Cocktail.find(params[:id])の場合
一般的に、詳細ページや編集ページに使われ、URL -> /cocktail/1となり、：idパラメータを探します。

cocktail = Cocktail.find(params[:cocktail_id])の場合
一般的に、config/routesでネストしたときに使われるそうです。URL -> /users/1/cocktails/1

ネストしたときとは↓
```ruby:routes.rb
resources :users, only: %i[new create]
    resources :cocktails do
      collection do
        get :bookmarks
      end
    end
```
以上です。わかりにくいかもしれませんが、お役に立てれば幸いです。
【Suno AIでつくった楽曲】しろぶりゅーの歌 ver.1 (3拍子のアコースティックソング + 口笛)【Fan-Made Song】【動画 1分19秒】【YouTubeチャンネルからの転記です】

この記事は、わたしの[YouTubeチャンネル](https://bit.ly/Yamanaka-YouTube "Living without things. 持たない生き方 手放す生き方")にある公開動画を転記しております。
( どこかのタイミングで、プログラミング-Google Apps Script or iPaaS-Zapier をつかって自動転記させる予定です )

転記のための時間コストを少なくしたいので、文字装飾( Markdown記法 )を極力つかわずに書いております。

こちらが動画内容です👇

***

![01 YouTube再生中の画像 Suno AI _ しろぶりゅーの歌 ver.1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386308/a23882ef-3337-0c8a-cbfb-a9370c489328.png)



* # 動画URL
    * https://youtu.be/L3hY5uKrCNU

<br>

* # 動画タイトル
    * 【Suno AIでつくった楽曲】しろぶりゅーの歌 ver.1 (3拍子のアコースティックソング + 口笛)【Fan-Made Song】【動画 1分19秒】

<br>

* # 動画の説明欄(一部を抜粋)

📅撮影日 = 2024-07-20(土)

Suno AIとは、文章から音楽を生成することができるAI( Text-to-Music-AI )です。
わたしは、2024-04-02(火)に初めてSuno AIで有償プランを契約してから、時々楽曲をつくって遊んでいます。

🎦【Suno AI】文章から音楽を生成するAI( Text-to-Music-AI )で、3分間で2曲、6分間で4曲作りました【試聴可能】1)伴侶の曲 2)税理士の曲【動画 16分11秒】
https://youtu.be/QKfhk4HgQ_g

🎦“Suno AIでつくった楽曲”シリーズ
https://www.youtube.com/playlist?list=PLpQhBHT4oghMLdiSVqwvSs_Z5y0H4VGOe

🎦“効果的にSuno AIを活用するヒント”シリーズ
https://www.youtube.com/playlist?list=PLpQhBHT4oghPuaNOVZn-N53wVvsBkeHdI


今回は、Suno AIでつくった曲を WAV で出力してから、動画編集いたしました。

スロージョギングの途中に、早朝の中目黒で偶然出会った「しろぶりゅー」-ShiroBrew-のテーマソング( イメージソングは和製英語です )を、1人のファンとして自主的につくりました。
つまり「しろぶりゅー」のファンメイドテーマソングです。

ぜひ聴いてみてください。
そして、ぜひみなさんも、あなたが大好きなお店やブランドや企業のために楽曲をつくってみてください！

作曲日:
2024-07-20(土)

契約の種類:
Pro Plan

楽曲の正式名称:
しろぶりゅーの歌 #1

Suno AI Library URL:
https://bit.ly/ShiroBrew-01

Custom Mode: On

Audio Inputs: Not Used

With Vocals:


---


Lyrics:

[Break]

[Intro]

[Whistling]

[Scat]

[Verse]
真っ白な心

[Verse 2]
そよ風感じる

[Chorus]
コーヒーの香りと
真っ白な心

[Whistling]

[Outro]


---


Suno AIへの指示文章( プロンプト/Prompt ): Custom Modeの場合は”Style of Music”を指定します。


🇬🇧English

[Waltz][lo-fi][japanese][Female]


🇯🇵日本語訳

[ワルツ][ローファイ][日本語][女性]


---


Suno AI 公式URL
https://accounts.suno.ai


SHIROノMONO 公式URL - Instagram
https://www.instagram.com/shiro_nomono


---


✓ 🎥この動画と関連が強いわたしの動画 ↙
　・“Suno AIでつくった楽曲”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghMLdiSVqwvSs_Z5y0H4VGOe


　・“効果的にSuno AIを活用するヒント”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghPuaNOVZn-N53wVvsBkeHdI


　・“Suno AIで3拍子”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghNy-xIeeMZV6D2YAnax9Nzw


　・“しろぶりゅー ファンメイドソング”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghPk5-_YwWl499DNAOVKlcvZ


✓ 🎥Shortened URL for this video | この動画の短縮URL ↙
　https://bit.ly/469Pflr
【git stash入門｜初心者向け】3分で学べる！git stashの基本的な使い方

## この記事でわかること
git stashの基本的な使い方

## 主な想定読者
- Git初心者（特に、add, commitなどの基本操作は知っているが、stashは知らない方）
- 複数人での開発を最近始めた方

## git stashとは
現在のブランチ上で行った変更内容を、**コミットせずに**一時保存しておくことができるGitコマンド

## 主な使用場面
- 現在のブランチから別のブランチに切り替えないといけないが、今の状態ではコミットを行いたくない時
  - 例）作業中、差し込みタスク（レビュー依頼や緊急バグ修正対応など）が入ってきたのでブランチを切り替えないといけないが、現在のブランチでの作業の進み具合が中途半端なので、コミットは行いたくない時
- 誤って、作業するつもりだったブランチではない、別のブランチでガッツリと作業を進めてしまった時
  - git stashを使えば、あるブランチAで行った作業内容を一時保存し、その作業内容を別のブランチBに反映させることが可能

## 基本的なコマンド
### `git stash` - 変更内容を一時保存
- 現在のブランチ上で行われた変更の内容が一時的に保存される
  - 補足：正確には、現在のブランチ上の変更差分がスタックに保存される
```:ターミナル
git stash
```

### `git stash push -m "コメント"` - コメント付きで変更を一時保存
- `git stash`がコメント付きで実行され、変更がコメントと共に一時保存される
```:ターミナル
git stash push -m "ログイン機能開発途中"
```

### `git stash list` - stashした変更の一覧表示
- `git stash`によって一時保存された変更内容を、リストとして一覧表示できる
```:ターミナル
git stash list

<実行結果の例>
stash@{0}: On bug_5678: バグ修正：ユーザー登録画面のバリデーション
stash@{1}: On new-feature_1234: 新機能追加：パスワードリセット機能の実装
stash@{2}: On develop: 画像プレビュー表示機能の実装途中
```
  
### `git stash apply` - 変更を現在のブランチに適用
- git stashで一時保存しておいた変更が、現在のブランチに適用される
- 複数の変更が保存されている場合は、最新のものが適用される
- 例えば以下のように、スタッシュ名を指定することによってstashリスト内の該当する変更を適用できる
```:ターミナル
git stash apply
```
```:ターミナル
git stash apply stash@{2}
```

### `git stash pop` - 変更を現在のブランチに適用 ＆ stashリストから変更を削除
- `git stash`で一時保存した変更のうち、最新のものが現在のブランチに適用され、さらにその変更はstashリストから削除される
- 適用された変更はstashリストから削除される点が、`git stash apply`と異なる
- `git stash apply`と同じく、スタッシュ名を指定して該当の変更を適用・削除できる
```:ターミナル
git stash pop
```
```:ターミナル
git stash pop stash@{1}
```

### `git stash drop` - stashリストから変更を削除
- stashリストから、該当する変更が削除される
- `git stash apply`と同じく、スタッシュ名を指定して該当の変更を削除できる
```:ターミナル
git stash drop
```
```:ターミナル
git stash drop stash@{0}
```

### `git stash clear` - stashリストの変更全てを削除
- `git stash`で一時保存された変更全てが、stashリストから削除される
```:ターミナル
git stash clear
```

## おわりに
最後までお読み頂き、ありがとうございました！
この記事が少しでもお役に立てば幸いです。
Docker で Nginx を 利用する

# はじめに
DockerのNginxをrootlessで構築するときのメモ残しです。
Warnがログに出ていたところを見逃していましたので、その修正対応込みでの記事となります。
ただ、エラーログにnoticeが出ますので、もう少し良い方法があるかもしれません。

# 確認環境
- WSL2(Ubuntu 22.04.3 LTS)
- Docker 26.0.0
- Docker Compose v2.26.1
- Nginx 1.27.0

# フォルダ構成

```
[projectfolder]
 ├─ compose.yml
 ├─ Dockerfile
 ├─ conf.d 
 │    └─ default.conf (コンテナからコピー)
 ├─ log
 │    └─ (アクセスログを格納)
 └─ html
      └─ index.html (表示確認サンプル)
```

## 設定ファイルをコンテナからコピーする
```shell
# プロジェクトフォルダに移動
cd {projectfolder}
# コンテナを仮立ち上げ
docker run --name nginx-temp -itd nginx:1.27.0
# 設定ファイルをコピー
docker cp nginx-temp:/etc/nginx/conf.d conf.d
# 仮コンテナを削除
docker rm -f nginx-temp
```

# コード
```yaml:compose.yml
services:
  web:
    build: 
      context: .
    ports:
      # ポート設定
      - "80:80"
    environment:
      # タイムゾーン
      TZ: "Asia/Tokyo"
    volumes:
      # ドキュメントルート
      - ./html:/usr/share/nginx/html
      # 設定ファイル
      - ./conf.d:/etc/nginx/conf.d
      # アクセスログ
      - ./log:/var/log/nginx
```

```Dockerfile:Dockerfile
# Nginx を指定
FROM nginx:1.27

# GID,UID変更(必要があれば)
# RUN groupmod -g 1000 nginx
# RUN usermod -u 1000 nginx

                        # キャッシュフォルダの所有者を変更
RUN chown -R nginx:nginx /var/cache/nginx/ \
                        # pidのデフォルト設定場所の所有者を変更
                         /var/run/ \
                        # ログフォルダの所有者を変更
                         /var/log/nginx/

# nginx.conf の先頭行の user nginx; をコメントアウト
RUN sed -i 's/^\(.*user  nginx;.*\)$/#\1/' /etc/nginx/nginx.conf
```

```diff:conf.d/default.conf ※差分のみ
-    #access_log  /var/log/nginx/host.access.log  main;
+    access_log  /var/log/nginx/access.log  main;
```

```html:html/index.html（確認用ですのでお好きに）
<html>
    <h1>IT'S WORKS!!</h1>
</html>
```

# 立ち上げコマンド
```shell:shell実行
docker compose up -d
```
※立ち上げ後、ブラウザから `localhost` に接続して、`index.html` の内容が表示されていたら、OKです

# 注意点＆解説
- GID,UID については、必要があれば変更してください
- nginx.conf のuser nginx; は rootユーザーではないと、できない設定みたいなので、root以外のユーザーで残して実行するとWarningが出てしまいます
- default.conf と記載していますが、末尾が`.conf`であれば読み込んでくれます(複数の場合はルールがあったかと思いますので、調べてください…)

# 最後に
Warningの内容をAI(Gemini Pro 1.5) に聞くと、原因と解決策をすぐに出してくれましたので、すごく楽でした。とはいえ最近、検索して解決する能力がどんどん落ちてきている気がします😢
Let's discuss what is Testing Automation

Don't count on testing automation to do all things and make any judgement for us.
It is still the situation that human is the main actor!Human Creates and uses automation continuously.Especially it is the case in agile development.

■Testing
　Testing is a group of activies parallel to development activities in Agile Development model. 
  It should include activities like the ones as indicated in following table
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3838358/8eb4d4a4-f008-b50a-b3d7-87db976ea75e.png)
  And in the usual occasion,there should be serveral projects going on in parallel,therefore it becomes more difficult 
■Testing Automation　
　 Testing　automation aims to  help improve business code quality and efficiency in Testing process and activities,therefore it should function as the digram indicates
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3838358/b17f8946-5085-42cd-3c72-be84b8ebc4a6.png)
 ■ Therefore,Testing Automation is a kind of testing which uses technology to 
 . solve difficult issues like data issue
 . find more defects earlier like the ones in  page display and whole scenario 
 . to improve efficiency in operations like  repetitive inputtings in a group of pages
 ■ Therefore,Testing automation should be used within development process,never first focus on so-called future regression Tests.Acutally whenever  there is a need for regression tests,there must be a development or maintenace project there.That is,Regression test should exist within a project,where we should create,improve automation while we use it.
 ■Therefore,Automation Team working outside the project is not effetive at all!
 ■ More CI/CT sometimes only waste more of our time, since tests fail due to busiess code change while testing automation scripts haven't been changed correspondingly.
 ■Therefore,If you like to be an automation engineer,please first be a tester,who understand business,system and management,communication,and even technology.
 ■ The Automation Life Cycle should be as following diagram
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3838358/df1a3849-447f-94de-0efe-a8e6012b85bb.png)
バッファレスレンダリングで25行から始めるWebGL2

WebGLが動くかどうか試そうと思った方、ちょろっとコードを書いてみようとしても、頂点バッファを用意するのって微妙に面倒ですよね。
WebGL2では、頂点シェーダで`gl_VertexID`という内部変数を使うことができます。

これをうまく使うことで、頂点バッファを使わずに三角形を描画することができます。

@cx20 さんの以下の記事のコードをベースに、さらに短い最短のWebGLコードを書いてみましょう。

https://qiita.com/cx20/items/0597cdbccdd370e05956

## 25行のWebGL2コード 

こんな感じになります（２５行と言いつつ厳密には２６行なんだけど）。

```javascript
let c, gl;
let v = '#version 300 es\nprecision highp float; void main() { float x = float(gl_VertexID - 1); float y = float((gl_VertexID & 1) * 2 - 1); gl_Position = vec4(x, y, 0.0, 1.0); }';
let f = '#version 300 es\nprecision highp float; out vec4 fragColor; void main() { fragColor = vec4(0.0, 0.0, 1.0, 1.0); }';
function initWebGL() {
    c = document.getElementById("c");
    gl = c.getContext("webgl2");
}
function initShaders() {
    var p = gl.createProgram();
    var vs = gl.createShader(gl.VERTEX_SHADER);
    var fs = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(vs, v);
    gl.shaderSource(fs, f);
    gl.compileShader(vs);
    gl.compileShader(fs);
    gl.attachShader(p, vs);
    gl.attachShader(p, fs);
    gl.linkProgram(p);
    gl.useProgram(p);
}
function draw() {
    gl.drawArrays(gl.TRIANGLES, 0, 3);
}
initWebGL();
initShaders();
draw();
```

実行するとちゃんと三角形が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12753/50bed476-f123-5ef3-89f1-b91fc74bd6e6.png)

実際に動くコードは以下のJSBinに置きました。

https://jsbin.com/vaditawoya/edit?html,js,output

頂点シェーダの部分を紐解いてみましょう。`gl_VertexID`の部分にそれぞれ0, 1, 2が来た時を想像して暗算してみると、三角形ができることがわかると思います。「こんなの思いつかないよ」と思われるかもしれませんが、ある程度パターンが決まっているので、そのままおまじないとして覚えてしまうのがよろしいかと思います。

```glsl
#version 300 es
precision highp float;
void main() {
    float x = float(gl_VertexID - 1);
    float y = float((gl_VertexID & 1) * 2 - 1);
    gl_Position = vec4(x, y, 0.0, 1.0);
}
```

## 番外編: 画面全体を覆う矩形を頂点バッファなしで描画する

ちなみに、以下のコードで画面を完全に覆う矩形を描画することができます。テクスチャ座標付きなので、頂点バッファを用意せずにポストプロセスやスクリーンスペースの処理ができ便利です。このコードもおまじないと思ってメモっておきましょう。

```glsl
#version 300 es
precision highp float;
out vec2 texCoord
void main() {
    float x = float((gl_VertexID & 1) << 2); // 0, 4, 0
    float y = float((gl_VertexID & 2) << 1); // 0, 0, 4
    texCoord.x = x * 0.5;
    texCoord.y = y * 0.5;
    gl_Position = vec4(x - 1.0, y - 1.0, 0, 1);
    // x, y, u, v
    // -1, -1, 0, 0
    // 3, -1, 2, 0
    // -1, 3, 0, 2
}
```

図にするとこんな感じ（図中の数字はUVです）。大きな三角形を描画して、ラスタライズステージでフレームバッファに合うようはみ出た部分のフラグメントは破棄されるんですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12753/8f75f9b0-0eac-193c-e99e-d167bee193b5.png)

こうした、頂点バッファを使わずに何らかの描画を行うことをバッファレスレンダリングと呼んだりするそうです。

## まとめ

「最短25行で書けちゃうWebGL2」という記事でした。バッファレスレンダリングを行うことで、頂点データのセットアップを省略でき、コードをシンプルに保つことができます。どんどん使っていきましょう。
K8S内のVictoriaMetricsが起動しなくなった

## 概要
電源の瞬断によりVictoriaMetricsが以下のエラーを履いたので修正できるように直した。

```bash
2024-07-20T09:08:55.771Z	panic	VictoriaMetrics/lib/storage/part_header.go:150	FATAL: cannot parse "/victoria-metrics-data/data/small/2024_07/17E1AD9C3BD4C517/metadata.json": unexpected end of JSON input
panic: FATAL: cannot parse "/victoria-metrics-data/data/small/2024_07/17E1AD9C3BD4C517/metadata.json": unexpected end of JSON input
```

## 原因を調べる
上記で、フォルダ名を調べたら以下の通り0バイトファイルなっていた。
```bash
$ ls -la
合計 656
drwxr-xr-x+ 2 root root   4096  7月 20 18:52 .
drwxr-xr-x+ 9 root root   4096  7月 20 18:53 ..
-rw-rw-r--+ 1 root root      0  7月 20 18:52 index.bin
-rw-rw-r--+ 1 root root      0  7月 20 18:52 metadata.json
-rw-rw-r--+ 1 root root      0  7月 20 18:52 metaindex.bin
-rw-rw-r--+ 1 root root      0  7月 20 18:52 timestamps.bin
-rw-rw-r--+ 1 root root      0  7月 20 18:52 values.bin
```
とりあえず、これが怪しいので、フォルダごと削除したけど、ソフトを再起動したけど以下のログ吐いた

```bash
panic: FATAL: cannot parse metadata from "/victoria-metrics-data/data/small/2024_07/17E1AD9C3BD4C517": unexpected number of substrings in the part name "17E1AD9C3BD4C517": got 1; want 5
```

そういえば、`parts.json`ファイルを調べたら、`17E1AD9C3BD4C517`という文字列があったので、編集して削除したフォルダの文字列を削除を実施

一応、その再起動で、ソフトがうまく起動したので、問題は解決した

## 結論
以下の作業を実施すればとりあえずは解決する
* panicメッセージのフォルダの中身を確認して異常がないことを調べる
* もしフォルダを削除する場合はparts.jsonのファイルを編集する
NEM NIS1ノードを建ててみよう [夏休みの自由研究に]

さあ夏休みがやってまいります。
自由研究の課題、どうしようとお悩みのそこのあなた。
どうでしょう、この夏はブロックチェーンのノード構築に挑戦してみませんか。

### 必要なもの
- 自宅のインターネット光回線
- Linuxが動くコンピュータ
- (スーパーノードプログラムに参加するなら) 10,001XEM
  - https://docs.nem.io/pages/Guides/supernode-program/docs.en.html

### 手に入るもの
- Linuxの経験
- Dockerの経験
- NEM NIS1ノード構築の経験
  - https://github.com/NemProject/nem-docker
- (スーパーノードプログラム参加報酬として)1日1ドル程度のXEM

未経験者にとってはハードルが高くて大変だと思います。が、そこは先輩方も通った道。頑張りましょう。

### ポート開放
- 7890 … NIS1基本通信用 (http)
- 7778 … Websockets用 (http)
- 7891 … NIS1基本通信用 (必要ならhttps)
- 7779 … Websockets用 (必要ならhttps)
- 7880 … スーパーノードプログラム サーヴァント用

docker のインストールは以下の記事などを参考
https://qiita.com/curupo/items/d89990bf5e2ae371dd25

### 準備

nemユーザーを作成しsudoグループに追加
```
# adduser nem
New password: <適宜入力>
Retype new password: <再度入力>
⇒あとはリターンをしておく
# cat /etc/group | grep sudo
# usermod -aG sudo nem
# cat /etc/group | grep sudo
# exit
$ su - nem
⇒ログインできること
```
nemユーザーをdockerグループに追加
```
$ su -
# cat /etc/group | grep docker
# usermod -aG docker nem
# cat /etc/group | grep docker
# exit
$ exit
```

設定を反映させるため再度ログイン
```
$ su - nem
```

動作テスト
```
$ docker run hello-world
Hello from Docker!
⇒OK
```

### nem-dockerで構築

https://github.com/NemProject/nem-docker

```
$ ~/
$ git clone https://github.com/NemProject/nem-docker.git
$ cd ~/nem-docker
$ cp custom-configs/servant.config.properties.sample custom-configs/servant.config.properties

$ vi custom-configs/servant.config.properties
---
nem.host = <put vps ip address here>
servant.key = <put your NIS boot key here>
---

$ ./boot.sh
⇒とりあえず全てリターン
⇒途中いろいろとエラーがでる

とりあえずコメントアウトで回避します
$ vim Dockerfile
---
+#RUN sha=$(curl -L -s http://hugealice.nem.ninja:7890/transaction/get?hash=$(curl -L -s http://bob.nem.ninja/nis-0.6.101.tgz.sig | grep txId | sed -e 's/txId: //') | jq -r '.transaction.message.payload[10:74]') && \
+#    echo "$sha nis-0.6.101.tgz"  > /tmp/sum && \
+#    sha256sum -c /tmp/sum
---

$ vim Dockerfile（自身の構築環境に合わせて適宜修正）
---
-RUN useradd --uid 1000 nem
+RUN useradd --uid 1002 nem
---
$ vm boot.sh
---
-chown -R 1000 nem
+sudo chown -R 1002 nem  # なぜかroot権限でログファイルができるstderr出力対応。
+sudo chgrp -R 1002 nem  # もっと良い方法があるかも。javaよくわからん
---

logファイルのパーミッション
$ ~/nem-docker/nem
$ sudo chown nem:nem nis-std*.log

再度起動
$ ./boot.sh
All done, here are the services running:

ncc                              STOPPED   Not started
nis                              RUNNING   pid 14, uptime 0:00:02
perms                            RUNNING   pid 13, uptime 0:00:02
servant                          STOPPED   Not started
⇒起動成功

動作確認
$ curl http://localhost:7890/node/info
$ curl http://localhost:7890/chain/height

スーパーノードプログラムに参加する場合はサーヴァントを起動
$ ./service.sh start servant
servant: started

停止
$ ./stop.sh
```

参考

https://github.com/NemProject/nem-docker

https://qiita.com/nizveyl/items/80498fef93f2523f174f

https://qiita.com/ftakao2007/items/8ad9e844cf7b01d3970f

https://github.com/curupo/nis-docker

https://github.com/curupo/nem-docker
ElixirでCPUの周波数を取得をする

# 前提
OS Ubuntu 22.04
実行環境 Livebook 

# ソース

```Elixir
File.read!("/proc/cpuinfo")
|> String.split("\n")
|> Enum.filter(&String.match?(&1, ~r/cpu MHz/))
|> Enum.each(&IO.puts(&1))
```

・`/proc/cpuinfo`からCPU情報を取得
・1行毎に分割
・`cpu MHz`の行でフィルター
・表示

# 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/b4313b76-20f3-4739-f2e9-214e35100bff.png)


```結果
cpu MHz		: 985.976
cpu MHz		: 1096.658
cpu MHz		: 1091.907
cpu MHz		: 800.000
cpu MHz		: 1074.477
cpu MHz		: 800.000
cpu MHz		: 1098.162
cpu MHz		: 1090.260
cpu MHz		: 1100.000
cpu MHz		: 800.000
cpu MHz		: 1084.603
cpu MHz		: 800.000
cpu MHz		: 1099.995
cpu MHz		: 1100.007
cpu MHz		: 1087.751
cpu MHz		: 1092.324
cpu MHz		: 800.019
cpu MHz		: 800.018
cpu MHz		: 799.974
cpu MHz		: 800.001
cpu MHz		: 800.013
cpu MHz		: 800.172
cpu MHz		: 800.006
cpu MHz		: 800.011
cpu MHz		: 800.145
cpu MHz		: 800.000
cpu MHz		: 800.112
cpu MHz		: 800.000
cpu MHz		: 800.098
cpu MHz		: 800.000
cpu MHz		: 800.000
cpu MHz		: 800.000
```
Ubuntu環境にLubuntuデスクトップ環境を適用する方法

## 前提条件

- 既にUbuntuがインストールされていること
- 基本的なコマンドライン操作の知識があること

## 手順

### 1. パッケージリストの更新

まず、パッケージリストを最新の状態に更新します。

```bash
sudo apt update
```

### 2. Lubuntuデスクトップ環境のインストール

Lubuntuのデスクトップ環境をインストールするために、以下のコマンドを実行します。

```bash
sudo apt install lubuntu-desktop
```

このコマンドにより、必要なパッケージがすべてダウンロードされ、インストールされます。インストール中に表示されるプロンプトに従い、必要な設定を行います。

### 3. デフォルトのディスプレイマネージャの選択

インストール中に、デフォルトのディスプレイマネージャを選択するプロンプトが表示されることがあります。`lightdm`（Lubuntuのデフォルトディスプレイマネージャ）を選択します。

### 4. システムの再起動

インストールが完了したら、システムを再起動します。

```bash
sudo reboot
```

### 5. Lubuntuデスクトップ環境への切り替え

システムが再起動したら、ログイン画面でLubuntuのデスクトップ環境に切り替えます。

1. ログイン画面でユーザー名を選択します。
2. パスワードを入力する前に、画面右上または右下にあるセッション選択アイコンをクリックします。
3. 「LXQtデスクトップ環境」を選択します。
4. パスワードを入力し、ログインします。
ransackで"数値項目"と"文字列項目"を一緒に検索する場合

## はじめに
ransackを使用して、数値項目と文字列項目を一緒に検索した際にエラーが出たので、対処法について記載します。
今回はid(Integer),name(String)でor検索を実装して、どちらかに検索対象文字が含まれていたら表示するというコードを記載している際にエラーが出ました。
<br>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1003708/fe7b61c4-c573-4683-937e-5eb612d5513f.png)


## エラー内容
38のついたid(No) / 商品名を検索しようと検索欄に38を入れて検索ボタンを押すと下記のエラーが出ました。
型が異なるので型変換してくださいねといった内容のエラーとなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1003708/34833601-f49a-555d-9558-9d9d334fff39.png)

## 修正方法
モデルに、`ransacker`という拡張機能を使いidを数値から文字列に型変換をする。
例のコードはpsql対応のコードです。idカラムを文字列に型変換しています。
(DBはpsqlを使用していたのですが、ずっとpsqlでは対応していないCONVERT関数を使っておりエラーが出続けたので要注意です)

```ruby:app/models/product.rb
  ransacker :id do
    Arel.sql("to_char(#{table_name}.id, '9999999')")
  end
```
<br>

無事エラーも出ず検索することができました。

![スクリーンショット 2024-07-20 18.22.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1003708/b936e5c7-b26f-bf75-6bed-5c9ccaa37de9.png)
業務で使っているシステムとスプレッドシートを連動させる仕組み

作ってみたものの、セキュリティ面で問題になりそうなので中断。
過程のメモです。

◆概要
GoogleCOLAB上でPython／seleniumを使い、業務システムの情報をスクレイピングしスプレッドシートに出力するシステムの構築。

◆中断の理由
Pythonを用いてスプレッドシートにデータを出力する際、承認処理が必要となり、Googleアカウントへのアクセスを求められる。
個人アカウントだったら良いものの、社用アカウントはリスクになりそう。

・出力された警告
＞Google 認証情報へのアクセスをこのノートブックに許可しますか？


◆作成したソースコード
```

#諸々のインストール
!pip install selenium
!apt-get update
!apt-get install -y chromium-chromedriver
!cp /usr/lib/chromium-browser/chromedriver /usr/bin
!pip install selenium gspread oauth2client
!pip install selenium gspread oauth2client webdriver-manager

#seleniumやスプレッドシートを扱うためのAPIをインポート
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import pandas as pd
from google.colab import files

# Google Sheets APIの認証設定
def authenticate_gspread():
    scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
    creds = ServiceAccountCredentials.from_json_keyfile_name('/content/credentials.json', scope)
    client = gspread.authorize(creds)
    return client

# Seleniumのセットアップ
def setup_selenium():
    chrome_options = Options()
    chrome_options.add_argument("--headless")  # ヘッドレスモードでブラウザを起動
    chrome_options.add_argument("--no-sandbox")
    chrome_options.add_argument("--disable-dev-shm-usage")
    service = Service(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service, options=chrome_options)
    return driver

# URLから要素を取得する関数
def get_element_from_url(url):
    driver = setup_selenium()
    driver.get(url)
    # ここで要素を取得します。例として最初の<a>タグを取得します。
    element = driver.find_element(By.TAG_NAME, 'a')
    element_text = element.text
    driver.quit()
    return element_text

# スプレッドシートにデータを書き込む関数
def write_to_spreadsheet(value):
    client = authenticate_gspread()
    sheet = client.open_by_key('スプレッドシートURL').worksheet('シート名')
    cell = sheet.find('特定のセル').row + 1
    sheet.update_cell(cell, 1, value)  # 1列目にデータを書き込む

# メイン関数
def main():
    url = 'https://book.impress.co.jp/books/1123101044'
    element_text = get_element_from_url(url)
    write_to_spreadsheet(element_text)

if __name__ == "__main__":
    # Google Sheets API認証情報をアップロード
    uploaded = files.upload()
    
    # 認証情報ファイルをColabに保存
    for filename in uploaded.keys():
        if filename.endswith('.json'):
            credentials_path = f'/content/{filename}'
            break
    
    # メイン処理を実行
    main()
```

◆今後の展望
スプレッドシートに認証の要らない（たぶん）GASで再チャレンジ
AWS KMS データーキーちゃんと理解して使っている？

### KMSについて細かいことわかっていない
AWSを使用するにあたりよく出てくるKMS。
マスターキーとデータキーとかいろいろ複雑な仕組みで細かく仕様を理解しないまま使っていました。。

### 結論
S3の暗号化などしているとAWS側でデータキーを勝手に生成してくれて、そのデータキーで暗号化をしてくれていそう。

### マスターキーとデーターキー
一口に暗号化のキーと言っても実際にデータを暗号化する「データーキー」と「マスターキー」の2種類があります。どちらのキーでも暗号化は可能ですが、データーキーで暗号化するのがベストプラクティスのようです。何となくこの辺の話は聞いたことがありましたが、こちらのサイトで何で2種類を使い分ける必要があるかとても分かりやすく書いていました。
[10分でわかる！Key Management Serviceの仕組み](https://dev.classmethod.jp/articles/10minutes-kms/ "タイトル")

### とりあえずS3を暗号化
KMSのコンソール上に表示されているキーはマスターキーのようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823786/1bbb971c-dd47-00f6-6c7b-99907ae5231e.png)

実際に自分がよく暗号化を使用するS3を例に考えてみます。
S3のバケット作成する際に暗号化方式を選びます。
KMSのAWSマネージドキーである、SSE-KMSを選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823786/19f5c2ea-bbb0-1e0a-79b9-f4e6661d4299.png)

っていうところで疑問に思いました。
AWSはマスターキーからデータキーを作成して、データキーで暗号化を行うべきと言っている。なのにコンソールでマスターキーを選択できるのは、矛盾があるような。。

### なんやかんやデータキーで暗号化されてるっぽい
先ほど作成したバケットにファイルをアップロードして、CloudTrailログを見てみました。すると。。
GenerateDataKeyイベントが発生していました。
どうやら内部的にSSE-KMSキーを使用してデータキーを作成して、それで暗号化を良しなにしてくれているっぽい！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823786/36e82dcd-4bf2-1313-0e76-bc8553e2816e.png)

### 暗号化されたファイルをダウンロードしてみる
暗号化されたファイルをダウンロードすると、裏でDecrypt（復号）のイベントが発生していました。予想通り！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823786/6a5a6b54-bcd4-0e14-9e61-61cea7b4732a.png)
Prometheus Operator: node_exporter のメトリクスを Node ラベルで絞り込む

PromQL でフィルタするのではなく、そもそもメトリクスを除いておきたい場合の話。

ServiceMonitor `spec.attachMetadata.node` フィールドを `true` に設定することで、Kubernetes Node の meta labels がターゲットに追加される。

- `__meta_kubernetes_node_label_<labelname>`
- `__meta_kubernetes_node_labelpresent_<labelname>: true`

あとはこれを使って Node ラベルで絞り込めばよい。

- https://prometheus.io/docs/prometheus/latest/configuration/configuration/#kubernetes_sd_config

`dedicated=db` ラベルを持つ Node 上で実行される node_exporter のみをスクレイプしたい場合は次のようになる。

```yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  labels:
    jobLabel: node-exporter
    release: kube-prometheus-stack
  name: kube-prometheus-stack-prometheus-node-exporter
spec:
  jobLabel: jobLabel
  selector:
    matchLabels:
      app.kubernetes.io/instance: kube-prometheus-stack
      app.kubernetes.io/name: prometheus-node-exporter
  attachMetadata:
    node: true
  endpoints:
  - port: http-metrics
    relabelings:
    - sourceLabels:
      - __meta_kubernetes_node_label_dedicated
      regex: db
      action: keep
    scheme: http
```

ただ、この方法ではすべての node_exporter pods をサービスディスカバリで発見したうえで、Node ラベルでスクレイプ対象をフィルタしているため、Prometheus UI の "Service Discovery" ページにすべての Node のラベルが晒されてしまう。

晒されるとまずい場合には、そもそもサービスディスカバリが発見する node_exporter 自体を絞り込んでやる必要がある。これは ScrapeConfig CR で kubernetes_sd `node` role を使うことで実現できる。

```yaml
apiVersion: monitoring.coreos.com/v1alpha1
kind: ScrapeConfig
metadata:
  name: node-exporter
  labels:
    release: kube-prometheus-stack
spec:
  jobName: node-exporter
  kubernetesSDConfigs:
  - role: node
    selectors:
    - role: node
      label: dedicated=db
  relabelings:
  - sourceLabels: [__address__]
    targetLabel: __address__
    regex: "(.*):.*"
    replacement: "$1:9100"
```

ScrapeConfig CR は生の Prometheus 設定をそのまま書けるのでなんでもできる。困ったらこれを頼ればよい。

- https://prometheus-operator.dev/docs/developer/scrapeconfig/

ただし、アルファ API なので、将来スペックに破壊的変更が入る可能性がある。気になる場合は Prometheus 設定を生で書いて Prometheus サーバに直接渡せばよい。

そのほか、スクレイプしたいグループ毎に node_exporter DaemonSet を分けて作成してやれば ServiceMonitor でも晒さないようにできるが、これは面倒だとおもう。
【備忘録】初めてのiOSアプリ開発 第4回 DispatchQueue

## DispatchQueueとは
・タスクの非同期実行や並列処理を行うためのキュー
・バックグラウンドタスクの実行やメインスレッドでのUI更新を簡単に行う。
・AppleのGrand Central Dispatch（GCD）技術の一部。システムリソースを効率的に利用しながら、アプリケーションのパフォーマンスを向上させる。


## Grand Central Dispatch（GCD）とは
・Appleが提供する並列プログラミングのための技術。
・iOSやmacOSで効率的なマルチスレッド処理を実現するために使用される。マルチスレッドを使用することで、プログラムの並列処理の実行や応答性の向上を図る。
・開発者がスレッドやキューを直接管理する必要なく、並列処理を実装できる。

## DispatchQueueの種類
### 直列キュー (Serial Queue)
タスクを順番に1つずつ実行します。タスクの実行順序が保証され、競合状態を避けるのに適しています。

・キューに追加されたタスクを一つずつ順番に実行する。
・1つのタスクが完了するまで次のタスクは実行されません。
・すべてのUI更新が直列に処理されることを保証する。

メインキュー
UIの更新など、メインスレッドで行う処理のためのキュー。

バックグラウンドキュー
重い処理やネットワーク通信などのためのキュー。

### 並列キュー (Concurrent Queue)
複数のタスクを同時に実行することができます。タスクの順序は保証されませんが、より効率的に複数のタスクを処理できます。
・キューに追加されたタスクを同時に実行します。
・複数のタスクが並行して処理されることが可能

## 関連用語
|関連用語   |説明      　|    
|:--------------------------|:-------------------------|
|並列処理|複数の計算やタスクを同時に実行することで、全体の処理時間を短縮する技術や方法。|
|同期実行|タスクが完了するまで次のタスクに移らない方式|
|非同期実行　　　|タスクをバックグラウンドで実行し、完了を待たずに次のタスクに進む方式。重い処理を行っている間もUIは応答可能な状態を保つことができる|
	
## 参考サイト

https://zenn.dev/egg_head/articles/d5fd84264875b5

https://swri.jp/glossary/%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89
【合格体験記】AZ-104：Azure Administrator Associate

ギリギリとはいえ合格したので、備忘録的に合格体験記を残しておきます。

↓合格ツイート

https://x.com/3_nipa/status/1814576062874972603


# 1. AZ-104とは
Microsoft Azure において、主要な専門的機能を構成、管理、セキュリティ保護、管理するための主要なスキルを示す試験らしい

https://learn.microsoft.com/ja-jp/credentials/certifications/azure-administrator/?practice-assessment-type=certification

# 2. 私について
 - PMやセールスの人
 - 業務でクラウドに触ることはない
 - 2,3年前?ぐらいにAZ-900を取得
     - AZ-104の勉強を開始した時にはAzureの記憶はない状態
 - SAAは半年前に取った

# 3. 受験動機
- 某フォロワーさんたちが、資格試験に合格＆合格体験記を書いてたので、わいも書くか！そのために試験受けるか！という勢い&ノリ（が最初）
- エンプラ顧客が多く、Azureを使っているケースが多くなってきたため
- 昨今、OpenAIが強いので、個人的に遊びたいと思ったから

# 4. 勉強方法
## 学習期間
- 期間：7/7（日）〜7/20（土）（ちゃんと勉強開始したのは、15日から…）
- 時間：50時間ぐらい

↓ここから本気で頑張りました。

https://x.com/3_nipa/status/1812510466733998270

## 使用教材
- 黒本
    - 何も調べずに買ってしまった
    - 1周読んでやめた。（古いのでお勧めしない）

https://amzn.asia/d/0aJImAji


- 緑本（私が勝手に呼んでる）
    - 2周読んだ
    - 2024/6/1に出版された書籍で、比較的新しいので準拠している
    - 模擬試験もやや似ている？気もした。ここ半年〜1年ぐらいの期間ならオススメできる！

https://amzn.asia/d/0ityaTxA


- Udemyの400問
    - とりあえず、定番の
    - 全くわからなくて心が折れました
    - 2,3周しました
    - 7-8割ぐらい取れるようにしました

https://www.udemy.com/share/109evM3@loV_kGctm2p1Ufk7grX5RfLgfbZp3R0pTQ4ecqKK8DFIMS-8RRzXpruDkKysDojdWw==/

- ExamTopics
    - これだけでええやーん。っていう声を見たので50問ぐらい解いてみた
    - 数問だけど、似たような問題ができた
    - 飽き性の自分には、1問1問解けるのは良かった

https://www.examtopics.com/exams/microsoft/az-104/view/


- GPTsを使ってみる
    - 隙間時間にいくつか問題出してもらって勉強した
    - あとわからないところはめちゃくちゃ質問した

https://chatgpt.com/g/g-pC2ND7pkq-az104-coach

- 先人の知恵を借りる（チートシート）
    - 受験当日直前に見たけど、最初に押さえておけば良かったと後悔している

https://zenn.dev/michinoku/articles/4b8282b8c68a3c


- 公式模擬試験（Microsoft Learn）
    - 問題の難易度は本番の方がちょっと難しいかも
    - こちらは、2周しました

https://learn.microsoft.com/ja-jp/credentials/certifications/azure-administrator/?practice-assessment-type=certification

# 5. 結局、どの勉強法がいいん？
色々試した結果、個人的におすすめの勉強方法です。
私は飽き性で1問解く→やり直しするスタイルが好きなので、以下をお勧めする。
そうでない方は、2と3を逆にしてもいいかも。

### 学習順
1. 新しい緑の本＆チートシートをサッと読む
2. Microsoft Learnで2,3周する
3. Udemyを解く
4. （余裕があれば、）ExamTopicsを50問ぐらい解いてみる

※隙間時間で、GPTsで苦手分野を補強する


# 6. 振り返り
- 最初、Azureまったくわからーんで辛すぎた
- テキストである程度抑えたつもりだったが、Udemy解いてもわからなかった
（解きながら心が折れた）
- 試験中にMSLearnを使うことができるので、時間がある人はMicrosoft Learnに触れておくと良さそう
- 最初、試験画面のUXが苦手すぎて集中しきれなかった。（※テストセンター受験）
- Microsoft Learnをたくさん検索して、なんとか合格できた気がする
yukicoder No.8 N言っちゃダメゲーム　解説

[問題文](https://yukicoder.me/problems/no/8)

# 解説
N言っちゃダメゲームの勝利はある条件によって決まる
・$N$%$(K+1)=1$なら後手の勝ち
・そうでないなら先手の勝ち
この方法で実際に確かめればOK

<details><summary>自分なりの証明</summary>

例えば、K=5とする。
先手：1 後手：23456
先手：12 後手：3456
先手：123 後手：456
先手：1234 後手：56
こんな感じで後手はK+1-(前に行った数)いうことができる。
この時、N%(K+1)==1ならこれを繰り返すだけで勝てる。
また、N%(K+1)!=1なら最初に先手がN%(K+1)-1個言えばあとは後手に合わせてうまく言うだけで勝てる。
もしこれで後手が（先手+後手）!=K+1という感じにしたら相手にチャンスが渡るだけ。

</details>

# C++での解答例
```C++
#include <bits/stdc++.h>
using namespace std;

int main(){
  int p;cin>>p;
  for(int i=0;i<p;i++){
    int n,k;cin>>n>>k;
    cout<<(n%(k+1)==1 ? "Lose\n":"Win\n");
  }
}
```
【Golang 備忘録】VSCodeで"BrokenImport"が出たときに読んでほしい記事

<h1>導入</h1>
こんにちは。<br> 
Golangを学び始めて１ヶ月が経ち、ついにVSCodeでAPIサーバーを作ってみました。そこで、<code>BrokenImport</code>にとても苦しまされたのでその解決策を備忘録という形で残すことにしました。<br>
初投稿であり、読みにくいと感じられる点もあるかと思いますが、参考になれば幸いです。
<h1>問題</h1>
私のAPIサーバーのディレクトリは下のようになっていました。（一部略）<br>
<blockquote>
api<br>
├ cmd/<br>
│  └ go.sum<br>
│  └ <font color="Red">go.mod</font><br>
│  └ main.go<br>
├ internal<br>
│  ├ domain<br>
│  │  └ user.go<br>
│  │  └ works.go<br>
│  ├ router<br>
│  │  └ router.go<br>
:<br>
├ <font color="Red">go.mod</font><br>
└ go.sum<br>
</blockquote>
私は、internalフォルダ内にある、domainやrouterをcmdフォルダ内で呼び出そうとした際に<code>BrokenImport</code>が表示され、エラーを吐きました。<br>
考えられる問題点として、赤字で示したようにプロジェクトディレクトリ下に複数の<code>go.mod</code>が存在していることが挙げられます。
<h1>解決策</h1>
それぞれの<code>go.mod</code>が存在するディレクトリが各々workspaceであることを示すために<code>go.work</code>を作成します。<br>
私の場合、ターミナル内で以下のように実行しました。<br>

```
go work init ./cmd ./internal
```

すると、以下のファイルがプロジェクトディレクトリに作られます。<br>

```:go.work
go 1.22.4

use (
	./cmd
	./internal
)
```

<code>work.go</code>を作成した後は、<code>main.go</code>でinternalフォルダ内のものをcmdフォルダ内でうまく呼び出すことができました。<br>
以上で終わりです。最後まで読んでくださり、ありがとうございました。
<h1>参考記事</h1>

https://qiita.com/haruyama480/items/10c5135ef96fed61128a
Blenderの正規表現リネーム メモ

Blenderにはオブジェクト等のリネーム機能があって
選択したボーンの名前を正規表現で一括置換といったこともできます

ボーンの一括リネーム等の作業は数か月に1度程度でどうしても忘れてしまう部分があるので覚え書きです
## 基本
リネームは　編集メニューの**名前を一括変更**[Ctrl+F2] で呼び出せます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/bb146f52-dc71-d96d-31b1-93288c4c4404.png)
ボーンの編集モードで　タイプからボーンを選択することで個々のボーン名を変更できます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/8c0b2648-d727-dcc8-04e8-807bc349e482.png)
他の置換処理のタイプは他のサイトでも解説しているし 試せばわかる程度なので割愛
検索　置き換えの横のアスタリスクアイコンをオンにすることで　正規表現のモードになります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/fa7f085e-0d06-73df-7605-6f61cdeef759.png)
他の正規表現同様に"()"でグループ化 置き換え側で\\(半角￥)＋番号でグループのマッチング内容を利用できます
図のmixamorig:LeftHandMiddle1 は　HandMiddle1_L　に置換できました

:::note
"\\"を利用するのが毎回分からなくなるポイントで　このメモを書きました
:::

## ちょっとだけ複雑な正規表現
Blenderでは　左右のボーンの判別を接尾語もしくは接頭語で判別するのですが
他の環境では　leg_L0_0_jnt　leg_R0_0_jnt といった感じに中間部分に入っていることはあります
これをleg_0_0_L　leg_0_0_R のように並び替えるのは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/b5206cfa-14b7-0206-ee54-42609cba274b.png)
検索を　(.+?)_([L|R])(\d*)_(.+)_jnt
置き換えを　\1_\3_\4_\2
といった具合にしました
"(.+?)_"　が　"_"までの任意の文字列の最少マッチ　"[LR]"がLRのどちらかとマッチといった感じです


## メタ文字メモ
|  |  |
|:-:|:-:|
|  .  |  任意の1文字  |
|  *  |  直前のパターンの0回以上繰り返し（最長一致）  |
| \+	| 直前のパターンの1回以上繰り返し（最長一致）|
| ?	| 直前のパターンの0～1回繰り返し（最長一致）
| ～\|～	|  \| の左右の文字列のいずれか（～または～）|
| [～]	| ～のいずれか1文字|
| [^～]	| ～に含まれない1文字|
| ^	| 論理行頭|
| $	| 論理行末|
| \\	| 直後のメタ文字をエスケープ|
| \\n	| 改行文字|
| \\t	| タブ文字（制御コード 0x09）|
| \\s	| 空白文字（半角スペース、\t、\n、\r、\f）すべて|
| \\S	| 空白文字（半角スペース、\t、\n、\r、\f）以外|
| \\x##	 | 16進数 #は0～9、a～ｆ、A～Fのいずれか|
| \\d | すべての半角数字 |
| \\D |	 半角数字以外すべて|
| \\w | すべての半角英数字とアンダースコア|
| \\W  | 半角英数字とアンダースコア以外すべて|
| \\l	|半角英小文字|
| \\L	|半角英小文字以外すべて（英大文字、数字、全角文字などすべて）|
| \\u	|半角英大文字|
| \\U	|半角英大文字以外すべて（英小文字、数字、全角文字などすべて）|
生成AIパスポート試験合格しました！：市場価値を飛躍的に向上させるエンジニアの革新

[生成AIパスポート試験について](https://guga.or.jp/generativeaiexam/)
# 合格証明証
![合格証明証_佐野貴信.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82835/67741e91-8db3-986d-0ba3-321e8b996da8.png)


![シラバス分野別得点率.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82835/517ade55-eafa-3209-35a8-b546e1670115.png)

# 今後の展望
AIパスポート取得後、以下のような社内への貢献を目指します。

### AI技術の社内展開:
社内勉強会やワークショップを通じて、AIの基礎知識や最新の応用事例を共有します。
具体的なプロジェクトにおけるAI活用例を紹介し、業務の効率化や精度向上を図ります。

### 継続的なスキルアップ:
社内メンバーと共に継続的な学習を行い、最新のAI技術を常に取り入れる姿勢を維持します。
これにより、社内全体の技術力向上と業務効率化を推進し、競争力の強化に寄与することを目指します。
【副業】LP制作で収入を得るまで_１日目

LP制作で副業収入を得ることを目的とした日記です。
日々学んだことを記録します。

## なぜ副業としてLP制作を選んだか
主な理由は以下の３つです。
* 副業を始める目的に、自分の仕事（SE）にも活きるものがよい
* LPページ制作は初心者の参入障壁が低い
* 案件数が豊富

案件の内容は、以下のサイトで調べました。

[クラウドワークスの求人ページ](https://crowdworks.jp/public/jobs?ref=public_header)
日本最大のクラウドソーシングのシステムで、発注者と受注者がオンラインで仕事を依頼・受注できるサービスです。

## 自身のスペック
年齢：20代半ば
IT業界歴：6カ月
業務内容：自社アプリ開発
使用言語：Java,HTML,CSS,JavaScript
主な資格：基本情報、応用情報、JavaSilver

## LP(ランディングページ)の概要(ChatGPT調べ)
LP：Landing Page(着地ページ)
ユーザーが広告や検索エンジンの結果などをクリックした際、最初にアクセスするウェブページのことを指します

## LPの目的(ChatGPT調べ)
訪問者に特定の行動（購入、登録、問い合わせなど）を促すこと

### 1.リードジェネレーション
「ユーザーの連絡先情報を取得するフォーム」を設置し、将来のマーケティング活動に利用します。
### 2.商品販売
「特定の商品やサービスを紹介」し、購入を促進します。
### 3.キャンペーン情報
「限定キャンペーンやプロモーションの情報を提供」し、参加や購入を促します。
### 4.イベント登録
ウェビナーやセミナーなどの「イベントへの登録」を促進します。

## LP制作で収入を得るまでに必要なスキル(ChatGPT調べ)

### 1. HTML & CSS
* レスポンシブデザイン（メディアクエリの使用）
* フレックスボックスやグリッドレイアウト

### 2. JavaScript & jQuery
* JavaScriptの基本文法とDOM操作
* フォームのバリデーション
* jQueryを使用した簡単なアニメーションやイベントハンドリング

### 3. フロントエンドフレームワーク
* BootstrapやTailwind CSSなどのフロントエンドフレームワークの使用
* テンプレートのカスタマイズ

### 4. デザインの基礎
* カラースキームの選定
* タイポグラフィの基本
* ユーザーエクスペリエンス（UX）の基本原則

### 5. コンテンツ作成
* 効果的なコピーライティング
* SEO（検索エンジン最適化）の基本
* 画像や動画の選定と編集

### 6. 分析と改善
* Google Analyticsの使用
* A/Bテストの実施方法
* データ分析と改善のための基礎知識

## ノーコードツールの利用
[STUDIO](https://studio.design/ja)：今流行りのノーコードツール

### WordPressとの違い

* 習得難易度の低さ
STUDIO > WordPress

* 拡張性の高さ
STUDIO < WordPress
(WEBマーケットとカレンダー予約機能はSTUDIOでは、
現状実装できないらしい)

参考動画
[ノーコードWeb制作で稼ぐ時代が来た！月100万円稼ぎたいならWordpressを勉強するな](https://www.youtube.com/watch?v=5Lmix6zbzo8)

## 今後の方針
* STUDIOに登録する
* STUDIOの機能や使い方を覚える
* STUDIOでポートフォリオサイトを作成する

## まとめ
取得スキルなど色々まとめたが、
ノーコードツールでLPを制作する方針が早く収入化できそうなので
STUDIOの使い方を勉強します。

本記事製作時間：2時間
ピュアCSSネストとSassでは入れ子セレクタ`&`の動作が違う、という話

## 概要

　CSSネストとSassの`&`の解釈が違うので、気をつけろ。
　特に、入れ子の親が単純セレクタではなくて`&`を後ろに置いて使うときには注意が必要。

## 前提

```css
.hoge{
    & .fuga{ 
        color: red;
    }
}
```

これは、Sassとしてコンパイルすると

```css
.hoge .fuga{
    color: red;
}
```

となりますが、CSSネストだと

```css
:is(.hoge) .fuga{
    color: red;
}
```

と等価になり、Sassと解釈が違います。
おおむね同様の結果になりますが、違う結果になる場合があります。

## 問題になるケース

```css
.outer .inner{
    .wrapper &{
        color: red;
    }
}
```

これは、Sassとしてコンパイルすると

```css
.wrapper .outer .inner{
    color: red;
}
```

となり、CSSネストとして解釈すると、

```css
.wrapper :is(.outer .inner){
    color: red;
}
```

と等価です。

一見同じように見えますが、少し違います。
Sassの場合、「.wrapperの子孫である.outerの子孫である.inner」なので、`.outer`は必ず`.wrapper`の子孫です。
CSSネストの場合、「.wrapperの子孫である（.outerの子孫である.inner）」なので、`.outer`と`.wrapper`の親子関係は明示されていません。

MDNでも記述があいまいになっているので、素直に読んでしまうと誤解しかねません。注意が必要です。

https://developer.mozilla.org/ja/docs/Web/CSS/CSS_nesting/Using_CSS_nesting#%E4%BE%8B_4

## サンプル

上記コードの表示は以下のようになります。

<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="KKjzvRG" data-pen-title="Difference between CSS nesting and sass" data-user="lhankor_mhy" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/lhankor_mhy/pen/KKjzvRG">
  Difference between CSS nesting and sass</a> by lhankor_mhy (<a href="https://codepen.io/lhankor_mhy">@lhankor_mhy</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

このサンプルのようにネストの親が単純セレクタではない場合は、Sassを想定していると、思わぬ結果になる場合があります。

## 参照

https://drafts.csswg.org/css-nesting-1/#syntax-examples
OpenStackのtoxでどのようにテストが実行されるのか

`tox`から実行されるunitおよびfunctionalテストがどのように実行されるのかを簡単にメモ。なお`stestr`には触れていない。

# テストツール

`tox`からテストを実行すると`tox.ini`に定義に従いテストツールが起動される。
unitテストとfunctionalテストともに通常は`stestr`が利用されている。

```sh
stestr --test-path=./nova/tests/functional run {posargs}
```

デバッグを行う場合は異なり、`stestr`ではなく`oslo_debug_helper`が利用される。

```sh
oslo_debug_helper {posargs}
```

# oslo_debug_helper

`oslo_debug_helper`の実体はshellスクリプト。 https://github.com/openstack/oslotest/blob/master/tools/oslo_debug_helper

デバッグを行う際には自分であらかじめbreak pointをコードに埋め込み、`tox`にて`-e debug`オプションを指定してデバッグを開始する。https://docs.openstack.org/oslotest/latest/user/features.html

```py
import pdb; pdb.set_trace()
```

`tox -e debug $TEST_DIR`コマンドを実行すると、`oslo_debug_helper`にて対象となるテストを`testtools`から起動する（`$TEST_DIR`は`xxx/tests`などを指定）。

`oslo_debug_helper`の中ではまず実行対象となるテスト関数をリストアップする。

```sh
${PYTHON} -m testtools.run discover -t ./ $TEST_DIR --list > $ALL_TESTS
```

ここで、`ALL_TESTS`には`TEST_DIR`配下にある全てのテスト関数が書き込まれるため、特定のテスト関数のみを実行する場合はフィルタリングが行われる。

```sh
# getopts friendly way of determining if a positional arg has been passed
ARG1=${@:$OPTIND:1}
if [ "$ARG1" ]; then
    grep "$ARG1" < $ALL_TESTS > $TESTS_TO_RUN
else
    mv $ALL_TESTS $TESTS_TO_RUN
fi
```

最後に`TEST_TO_RUN`に書き込まれた対象のテスト関数が実行する。

```sh
${PYTHON} -m testtools.run discover --load-list $TESTS_TO_RUN
```