OmniAICreator/Qiita-1.07M huggingface dataset:
AtCoder初心者振り返りメモ ABC211～

# 211 C-問題
https://atcoder.jp/contests/abc211/tasks/abc211_c

**問題文**
文字列 S が与えられます。このうち8 文字を選び下線を引き、
下線を引いた文字が左から順に c , h , o , k , u , d , a , i となるようにする方法は何通りありますか？
ただし答えは非常に大きくなる可能性があるので、(10 9乗 +7) で割った余りを出力してください。

**ポイント**
DPを理解することが、今の自分の力量では難しい
````Python:211C.py
import math,sys,datetime,random,glob,os,re

# 入力
s = input()
MOD = 10 ** 9 + 7

# DP表を用意
# 9列のうち先頭は1とし、残り8列(chokudai 8文字)を0が初期値

dp = [0] * 9
dp[0] = 1

# 一文字ずつ判定し、一致する場合は　dp[i-1]に加算する
for c in s:
    if c == 'c':
        dp[1] = (dp[0] + dp[1]) % MOD
    elif c == 'h':
        dp[2] = (dp[1] + dp[2]) % MOD
    elif c == 'o':
        dp[3] = (dp[2] + dp[3]) % MOD
    elif c == 'k':
        dp[4] = (dp[3] + dp[4]) % MOD
    elif c == 'u':
        dp[5] = (dp[4] + dp[5]) % MOD
    elif c == 'd':
        dp[6] = (dp[5] + dp[6]) % MOD
    elif c == 'a':
        dp[7] = (dp[6] + dp[7]) % MOD
    elif c == 'i':
        dp[8] = (dp[7] + dp[8]) % MOD

print(dp[8])
````
**メモ**
類似の問題が出たときに、このDPを活用できれば御の字かと思う(2023/10/15)

アルゴ式：動的計画法ってなに？　(導入)
https://algo-method.com/descriptions/44

# 212 C-問題
https://atcoder.jp/contests/abc212/tasks/abc212_c

**問題文**
それぞれ N 個、M 個の正整数からなる 2 つの数列が与えられます。
それぞれの数列から 1 つずつ要素を選んだときの2 つの値の差の最小差を求めてください。

**ポイント**
・２つの数列をソートして差を順番に求める
・小さい値のインデックスを進めることで無駄な計算を行わない

````Python:212C.py
# 入力
N,M = map(int,input().split())
A = list(map(int, input().split()))
B = list(map(int, input().split()))

# リストをソートする
A.sort()
B.sort()

# 最小値を求めるため、答えをものすごく大きい数を設定しておく
ans = 10**10

# インデックス
i = 0
j = 0

while i < N and j < M:
    
    # 二つのリストの値を比較して最小値をもとめ、ans と比較する
    ans = min(ans,abs(A[i]-B[j]))

    # 次のループで上で計算したときの小さい値が格納されていたリストの次の値と比較するため、i のインデックスを進める
    if A[i] < B[j]:
        i += 1
    
    elif  A[i] > B[j]:
        j += 1
    
    else:
        print(0)    # 一致する場合は、ゼロが最小値となる
        exit()

print(ans)
````

# 214 C-問題
https://atcoder.jp/contests/abc214/tasks/abc214_c

**ポイント**
・回ってくる宝石か、高橋君から宝石をもらうか早い時刻でリストを更新する
・1番目のすぬけ君は、前周のN番目のすぬけ君から宝石をもらうので、%Nをインデックスとする

````Python:214C.py
# 入力
N = int(input())
S = list(map(int, input().split())) # となりから宝石をもらう時刻
T = list(map(int, input().split())) # 高橋君がすぬけ君に渡す時刻

# 高橋君が渡す時間リスト　をより早く宝石を受け取った時間で更新する
for i in range(N):
    T[(i+1)%N] = min(T[(i+1)%N] ,T[(i)%N] + S[(i)%N])

# 円周なので、もう一周する。インデックスはNで割った余り
for i in range(N):
    T[(i+1)%N] = min(T[(i+1)%N] ,T[(i)%N] + S[(i)%N])

print(*T)
````

# 215 C-問題
https://atcoder.jp/contests/abc215/tasks/abc215_c

**問題文**
文字列 S の各文字を並べ替えて作ることが可能な文字列を辞書順にすべて列挙したとき、前から 
K 番目にくる文字列を求めてください。

**ポイント**
・順列を全列挙するライブラリ「from itertools import permutations」を使う
・set で重複をなくす
・関数　「 ''.join 」 を使って各文字を結合する
・ソートするために　set から list に置き換える

````Python:215C.py
# permutationsというライブラリで列挙する
from itertools import permutations
import math,sys,datetime,random,glob,os,re

# 入力 
S, K=map(str, input().split())
K = int(K) # まとめて受け取ってから　Kを整数に変換

# セットを使って文字列の重複をなくす
ST=set()

# S を構成する文字で　tmpに全列挙する　a,b,c  b,c,a  a,a,a 
for tmp in permutations(S):

    # joinで結合した文字列をセットに格納していく
    word = ''.join(tmp)
    ST.add(word)

# セットをリストに変換してから辞書順にするためソート
ans = list(ST)
ans.sort()

# K-1番目の要素を出力
print(ans[K-1])
````
【Android】コードで画面の明るさを調節する【Kotlin】

# 実践

```
  val windowAttributes = window.attributes
  windowAttributes.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_OFF
  window.attributes = windowAttributes
```
今回例で使用した、
**WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_OFF**は　最小値で
最大値を設定したい場合は**WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL**を使う。
または、数値でも指定可能で　0.0f　〜　1.0fで指定することができる。

**WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE**を使うことで、画面の明るさをデフォルトの明るさにする、もしくは、明るさを変えないようにできる。



# 参考

https://developer.android.com/reference/android/view/WindowManager.LayoutParams#screenBrightness

https://dev.classmethod.jp/articles/adjust-brightness/
ChatGPTに競馬の写真を見せて「これはエッフェル塔の写真です」と回答させる

# はじめに
![pic1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479797/46e07df4-a1e5-41cb-bd19-7c7e81380c07.png)
これは何の画像でしょうか、ChatGPTに質問してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479797/085e4ae5-a936-4ddd-cd97-96d15c9a1b56.png)
エッフェル塔の写真らしいです。

というわけで、今回はこのやり取りに至るまでに試してみたことをお伝えします。

# きっかけ
きっかけは、以下X(旧Twitter)の投稿でした。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">GPT-4Vの解析ブロックできたw <a href="https://t.co/mcuxl0HusD">pic.twitter.com/mcuxl0HusD</a></p>&mdash; キリイ (@ytiskw) <a href="https://twitter.com/ytiskw/status/1713097154930352309?ref_src=twsrc%5Etfw">October 14, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

どうやら、画像に特定の文字を埋め込むことで、ChatGPTの回答を狂わせることができるようです。

# 試してみる
## 通常の画像
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479797/34e1b094-422d-29b7-2ebd-e3a6bbeaef53.png)

この画像に色々と加工をしていきます。

## わかりやすく文字を入れてみる
英語版
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479797/e8a2f6a5-36ab-2e25-f10f-48da2c0a8d1e.png)
日本語版
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479797/a83e3b8a-6e9b-cade-d520-7d5588f62b36.png)

日本語だとうまくいきませんでした。


## 文字を分かりづらくする
### サイズを小さくしてみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479797/cd4e8c2d-0246-6dd5-a140-376b5a3e84c7.png)
フォントサイズ3までは読み取ってくれました。
### 文字を透過させてみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479797/7c91f68c-c58f-8774-6c33-aab4eb7ae5d5.png)
透過率50%までOKでした、75%だとダメだったので一旦50%でいきます。

### 文字色を背景と揃える
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479797/085e4ae5-a936-4ddd-cd97-96d15c9a1b56.png)
そして冒頭のやり取りに戻ります。
文字色を緑にしたうえで、少し位置も変更してみました。

皆さんはどこに文字があるか分かりますか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479797/4a207afa-f309-c605-ce92-aa2a24bab77d.png)
ここにあります。
もはや自分でも気を付けないと見失います。。
(冒頭の画像もよく見るとこの文字が入っています。)

# おわりに
今回は画像に特定の文字を埋め込むことで、本来の画像とは異なる回答をChatGPTにさせることに成功しました。
何の役に立つのかと質問されると回答に困りますが、ChatGPT-4Vに少しでも興味を持っていただけたら幸いです。
命名規則あれこれ

## 目的
毎回命名規則なんだったっか...となるのでまとめます

## ケース
|ケース|例|
|--|--|
|スネークケース|snake_case|
|パスカルケース|PascalCase|
|キャメルケース|camelCase|
|チェインケース|chain-case|
|アッパースネークケース|UPPER_SNAKE_CASE|

## Python
|項目|ケース|
|--|--|
|変数|全て英小文字 or snake_case|
|定数|UPPER_SNAKE_CASE|
|関数|全て英小文字 or snake_case|
|クラス|PascalCase|
|モジュール|全て英小文字 or snake_case|
|パッケージ|全て英小文字|
|ファイル名|全て英小文字 or snake_case|

https://atmarkit.itmedia.co.jp/ait/articles/2308/08/news020.html

## JavaScript
|項目|ケース|
|--|--|
|変数|camelCase|
|定数|UPPER_SNAKE_CASE|
|関数|camelCase|
|クラス|PascalCase|
|ファイル名|全て英小文字 or snake_case|

https://google.github.io/styleguide/jsguide.html#naming

## JSON
|項目|ケース|
|--|--|
|キー|camelCase|

## HTML
|項目|ケース|
|--|--|
|id|chain-case|
|class|chain-case|
|ファイル名|chain-case|

## 命名規則の参照先
### Python
- [PEP8](https://peps.python.org/pep-0008/)
- [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html)

### JavaScripit
- [Google JavaScript Style Guide](https://google.github.io/styleguide/jsguide.html#naming)

### HTML
- [Google HTML/CSS Style Guide](https://google.github.io/styleguide/htmlcssguide.html)

## おまけ
- [名付け方などの参考になるサイト](https://ferret-plus.com/4680)
- [status と state の区別](https://e-words.jp/w/%E3%82%B9%E3%83%86%E3%83%BC%E3%83%88.html)
    - status: 「〇〇（対象）の状態」
    - state : 「〇〇（オンやオフなど）である状態」
コンポーネント開発の例（続・フレームワークって何？おいしいの？）

# はじめに

前回
https://qiita.com/jun2/items/ae09f35c307711ac4dd5
にてフレームワークは必要か？について記事を投稿しましたが、その続編となります。
実際色々触ってみてやっぱり強力だなと思う点についてもう少し詳細に触れていきたいと思います。
基本的にNuxt.jsをベースとしたお話です。

# 業務システムでは特に旨味ありか？

Atomicデザインに基づいて開発を進めてみたところ、当初はvuetifyなどコンポーネントフレームワークを利用することで、Atomsレベルの開発は行わないのでは？と考えていました。
ただ、業務系システムでは「一般的である」ことは求められません。
業務に特化する必要があり、顧客の要望を一般化という正論で押し通すことは難しいことは携わる方なら「わかる。つらいとことだよね。」と同調してくださる方もいらっしゃるのではないでしょうか？
例えば、生年月日の入力については「和暦での入力・表示」を求められます。
正直私は和暦で年齢を推測することはよほど近くない限りはできません・・・
一方要件定義での場では他は西暦での入力に抵抗はあまりないが、生年月日だけは・・・と言われてしまうことが多々。
もちろんvuerifyを使っても和暦入力を許容するようなオプションはありません。
ここでatomレベルでの開発が必要となってくるのでしょう。

# コンポーネント化するとどうなるのか？

手元に実行環境がないところで記事をおこしましたので、誤字も含めだいぶニュアンス実装ですがご了承ください。

BirthdayInput.vue
```
<template>
  <v-text-field v-model="birthday" @blur="change" \>
<\template>
<script>
const birthday=ref();
const change = () => {
 birthday.value = 半角に直した上で、西暦でも和暦でも和暦文字列に直す関数(birthday.value)
}

</script>

```

これが、
```
<template>
  <BirthdayInput />
</template>
```
これだけですむわけですね。
正直「半角に直した上で、西暦でも和暦でも和暦文字列に直す関数」が面倒くさいだけであって、utilとして用意してあればあまり苦ではないかもしれません。
それでも、**「どうやってやるんだっけ？」「参考ソースは・・・」などいちいち考えず**に実装できることが大きいと思います。
開発者によってどの程度気が利くかの差がでないのもいいですね。

# 他思いつくもの

* 生年月日から年齢の自動計算
* 氏名漢字入力から氏名カナの自動補完
* 郵便番号から住所自動補完

など、AtomsからMoleculesレベルでの作り込みがその後の開発を相当楽にさせるだろうと思いました。
作成したものは検索しやすいようにしておくといいでしょう。
また、前回の記事通りこれらをsubmoduleとした構成をテンプレート化することによって追加モジュールやバグフィックスしたモジュールを他のプロジェクトでも簡単に反映させられるため、非常に効率的だと思います。


いいね！ストック！などモチベーションに繋がりますのでポチッていただけると嬉しいです(^^)
非エンジニアの業務プロフェッショナルとエンジニアが考えている業務ロジックの妥当性を共有する方法案

# はじめに

ドメスティックなシステム化案件では非エンジニアの業務プロフェッショナルとの対話は主に自然言語の日本語を介して、コミュニケーションが図られます。補助的にUMLなどの図形表現が日本語の注釈を伴って提示される場合があります。

また要求仕様の厳密な記述にVDM[^1] などの数学的形式記述言語の導入が提唱されますが、これらは仕様の内部的な整合性を事前検証できるところに効用があり、非エンジニアの業務プロフェッショナルとの対話ツールとしては、そのままでは直接使えないと考えられます。

そこで、非エンジニアの業務プロフェッショナルとの対話ツールとして、他になにか使えるものがないかを検討したのがこの記事です。UMLの使用を否定するものではなく、通常UMLでも記述の難しい業務ロジック、ビジネスロジックそのものの内容の共有についての発案です。

# 業務ロジックの妥当性を非エンジニアと共有する際の壁
## 自然言語の曖昧さ
日本語も識別子に使われた数学的形式記述言語との対比で、自然言語の日本語を使った記述の曖昧さが繰り返し指摘されます。

これは日本語に関わらず、自然言語をつかって厳密な内容を記述すると、自然言語の同意他語や他意同語の存在、その他表現の多様性が、解釈の曖昧さにつながるものと考えられます。

## プログラミング言語の可読性の低さ
プログラミング言語とは、人間同士が意思疎通に用いる自然言語に対して、人間がコンピュータに手順を認識させ、人間側もどのような手順であるかを認識しておくため、ある程度人間にもわかるように自然言語の語彙も一部使った形式的な言語です。

これは一般的に英文字(ASCII)を使って予約語などのトークンが設計されており、昨今は記号表記も多用されるにいたっており、人間がある程度読めるといってもそれはエンジニアが前提で、非エンジニアの業務プロフェッショナルとの対話言語には使えないことはかなり自明です。（サブ業務的に使いこなしているひと除く）


## 複雑な業務ロジックはそもそも記述が難しい
複雑な業務ロジックはそもそも記述が難しいものがあります。データや変数・構造体の他、データべースに記録する情報の内容を決めた上で、それらをそれらがどういう条件のときにどのような計算を行うかということをち密に記述する必要があります。

## 非エンジニアの業務プロフェッショナルに伝えられるロジックの詳細にはおのずと限度がある

非エンジニアの業務プロフェッショナルに伝えられるロジックの詳細にはおのずと限度があり、厳密に実行可能で計算可能な状態のロジック詳細を共有することは難しい場合もあります。

しかし、通常アルゴリズムを構造的に実装する場合、あるいはオブジェクト指向的な構造も使用する場合、上位関数から下請けの下位関数の実装といった形で、段階的な詳細記述を実装ロジックの面でも採用できます。TransactionalScriptのような一本書きではなく、ある程度抽象的な表現の機能の下請けにより具体的な機能を、関数やサブ手順でわけて書くことになります。

# 業務ロジックの妥当性を共有する際の材料
## 日本語プログラミング言語の可読性の高さ
日本語の文字認識が日本語話者・識字者にとって他の言語より瞬間的で広範囲に及ぶことはある程度自明で、その点を利用したプログラミング言語の範疇として、日本語プログラミング言語[^2] があります。

日本語プログラミング言語はその可読性の高さは認識されながらも、ソフトウェアエンジニアリングの開発現場には普及せず、現状は非エンジニアがサブ業務で使用するツールの実装や趣味で使うプログラミング言語に多くはとどまっています。プロフェッショナルな開発事例がないという意味ではありません。

## 日本語プログラミング言語の存在は日本語も形式化すれば曖昧さを排除できることのエビデンス

開発現場で普及はしていないものの、厳密にコンピュータ上で実行可能なネイティブコード、中間コードにコンパイルできるコンパイラ言語として存在していることは、日本語もある程度形式化すれば曖昧さを排除できるということの好適なエビデンスとなっていると言えます。

つまり、**手順的に形式化された日本語で、ロジックを厳密に記述することは可能**ということです。これは日本語表記による疑似コーディングの範疇を超えた、非常に厳密な話です。

# 業務ロジックの妥当性を共有する方法案
日本語プログラミング言語またはそれに準ずる言語を使って、ロジックを記述し、それを非エンジニアの業務プロフェッショナルに読んでいただくという流れを意味します。

これはエンジニアであっても、要求仕様フェーズなど上流工程を繰り返し担当しているエンジニアの場合は、実装言語が読めなくなっている場合もありますので、非プログラマの業務プロフェッショナルに近いエンジニアとのコミュニケーションにも有用です。



# おわりに
VDM++の日本語の各種資料から、日本で使われる場合は構文中に日本語の識別子が普通に使われていることが読み取れます。やはり、直接関係する情報（解決課題や要求）が自然言語の日本語で書かれている場合は、その仕様記述として同じ日本語の用語を使用し続けるのに実装言語のような抵抗はないと見受けられました。

しかしながら、離散数学的な形式記述はその概念を理解していない業務プロフェッショナル（多くは文系のビジネスパーソン）には、たとえ日本語が多用されているとはいえ、敷居はかなり高いと考えれます。

そこで、日本語プログラミング言語の中には、自然言語の語順も導入した処理系も存在しますので、手順的形式言語の範疇で日本語で記述された場合は、業務プロフェッショナルにも十分理解される可能性があります。

[^1]: IBMのウィーン研究所で1960年代から70年代にかけて開発された形式手法。その実装には1996年にISO標準（ISO_IEC_13817-1）となったVDM-SLと、そのオブジェクト指向拡張のVDM++がある。
[^2]: Qiita [「なでしこ」「プロデル」「Mind」三大日本語プログラミング言語を徹底解説](https://qiita.com/mylifewithviolin/items/3d366097847ae9c36de0)
Django基本１０～Template にStaticを取込んでみた。

雨の日に出かけると靴がびちょびちょに、、、ひえー(;'∀')
ということで今回はTemplateにstaticを取込みます。
※static → cssファイルや画像、javaスクリプトの事らしいです。

■Templateの修正方法
　　　{% load static}を指定し、画像の取り込み時にも指定します。
　　　以下のような感じです。
    　　　　{% load static}
　　　　＜ims src="{% static "app/xxxx.jpg" %}"alt="XXXの画像"＞

では実際にやってみますね。
１．アプリケーションフォルダ配下にstaticというフォルダを作成します。
２．ここに画像や、cssを入れていきます。
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/f90449c8-c3bb-848c-8452-3032a511c0e4.jpeg)
３．fil.htmlに画像を挿入してみます。
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/baa03699-e6a0-4077-c76c-e17f5a440810.jpeg)
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/6d55526b-ec16-ab8b-b790-d6892abf18c5.jpeg)
上手くできました。
４．CSSを作成してみます。
（１）staticフォルダにnorizo.cssを作成します。
　　ここでは背景とｐタグに色を付ける指定をしています。
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/8a06a6a9-0cb6-0383-b6e0-c036c42b2b68.jpeg)

ご参考リンク
https://djangobrothers.com/tutorials/memo_app/template_extending_css/
https://jajaaan.co.jp/web-production/frontend/css-background/
https://www.profuture.co.jp/mk/column/22273

（２）fil.htmlにcssの取り込みをしています。
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/1f594664-22be-d74e-6799-c78dedc7f609.jpeg)
（３）結果を確認してみます。
上手くいきました、背景とｐタグに色が付きました。
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/b01f9e85-c52a-f17f-8cf8-ef0b5f9a823b.jpeg)
５．staticフォルダの配置換え
　　以前、Templateフォルダの配置換えをしてみましたが、同様にフォルダを
　　配置換えできます。早速やってみましょう
（１）setting.pyの修正
TEMPLATE_DIRと考え方は同じです。
BASE_DIR(ここではnorizo?project4ですね）の直下に配置する感じです。
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/14e93b14-7ffd-5e00-035a-5aeea0200d5b.jpeg)
ここはTemplateと少し違うところです。
settinng.pyの初期作成時にはこの指定はないので追加します。
STATICFILES_DIRSと、STSTIC_DIRを紐づけます。
ちょっと気を付けたいのが、STATICFILES_DIRSの方は最後に
「S」がついてます。STATICS_DIRの方は、「S」がつかないのでご用心。
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/8f57efa0-fb39-4862-be82-04b6e82c8c73.jpeg)

（２）norizo_project4直下に移動する。
参照フォルダが変わったことを確認する為、
norizo_app4配下のstaticフォルダとは異なる
背景とpタグの色指定をしました。
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/73267629-17bd-9153-40c3-5447b214dd1f.jpeg)
（３）結果を確認してみます。
上手くいきました。
ちょっとざわざわする配色ですが、ご勘弁を(^^;)
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/b9673cbb-0e36-00b2-503f-fe5085a61cd9.jpeg)
ロケーションヘッダーってなに？

nginxの設定ファイルをいろいろいじっていて、わからない言葉がたくさん出てきました。その中でもプロジェクトの大先輩がこれは知っておいた方がいいと言っていた「ロケーションヘッダー」について詳しく調べてみることにしました。「サーバ」についてそもそもよくわかっていないので、調べていくうちに出てくるよくわからない言葉も深堀りしていこうと思います。

## ロケーションヘッダー
まずはGPTに聞いてみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/057849e6-66e0-f3f7-f621-00f4886bbeb4.png)

リダイレクトする機能っていうのは知ってたけど、リダイレクトがそもそもあまりわかっていなかった。

リダイレクト応答とともに、ってあるけど、なにこれ？```HTTP 301 Moved Permanently```や```HTTP 302 Found```って何が違うの？

リダイレクトってURLにちょっとパスを付け足すだけと思ってたからサーバ内で遷移してると思ってたけど、そうじゃなくて一旦クライアントにレスポンスを返してるっぽい。で、クライアントに強制的に新しいURLにアクセスさせてるっぽい。

図にするとこんな感じ↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/0eb60aa7-04ac-6d00-18e2-1c7e00b4c400.png)

と思っていたけど、実際はこう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/a4d3f3e9-d4e2-aeab-2263-09c051a90443.png)


```HTTP/1.1 302 Found``` や ```HTTP/1.1 201 Created``` とかは「ステータスライン」というらしい。レスポンスはステータスライン、ヘッダー、ボディで成り立つってどっかで学んだことある気がするけど全く覚えてなかった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/cc396672-3dcf-9712-31eb-dc7284c06d94.png)


で、サーバーがクライアントに対してもう一度リクエストすることを強制できるのか気になったから認識があっているか聞いてみた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/f6209690-1050-bc17-cf01-3dd06ff08a3c.png)

3xx系は自動的にもう一度リクエストするらしいけど、201は自動的にリクエストしないらしい。この辺は各サーバ、クライアントの設定次第って感じっぽい。

最後に！
URLとURIの違いが気になったから聞いてみる。(これも絶対調べたことあるけど覚えてない)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/ec662f7e-ad50-66fe-466a-8418b7c53b5a.png)

そうそう、URNとかいうやつもおった。URIという上位の概念があって、その中にURLとURNがいる。URLはスキーマ(アクセスの仕方？使用するプロトコル？)、ドメイン、リソースという情報が含まれる。URNがいまいちピンとこないのでURLとURNの違いをもうちょっと聞いてみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/1ee457a0-3344-804a-cba2-36cb7e1fa1b6.png)

どうやらURNはある空間内で一意に定まる名前ってだけらしい。uuidみたいなこと？曰く、URLはIT関係なさそう。住所とかもURNって言ってよさそう。


## まとめ
- ロケーションヘッダーとは、HTTPレスポンスの一部
- HTTPレスポンスはステータスライン、ヘッダー、ボディで構成される。ロケーションヘッダーはヘッダーの一部
- クライアントはサーバからのレスポンスにロケーションヘッダーがあれば、自動的にクライアントに再びリクエストを送ることもある。（これがリダイレクト？）
- URIの中にURLとURNがある。URNはIT関係なさそう。

GPTに聞いてるので間違いがあるかもしれません。怪しい記述を発見した方はソースとともに正しい情報をぜひお知らせください！
letter_opener_web設定

railsを使ってメールを送信するまでの手順です。

## 環境
`rails 6.1.7.6`
`ruby 3.0.6`
`letter_opener_web 2.0.0`

## 手順
1. `letter_opener_web`インストール
1. Mailer設定
1. mailerジェネレーター実行
1. ビュー編集

### `letter_opener_web`インストール
devleopment環境だけしか使わないので環境を限定してインストールします。

```ruby:Gemfile
group :development, :test do
  gem 'letter_opener_web', '~> 2.0'
end
```

### routes編集
`letter_opener_web`のUIを確認できるパスを設定します。

```rb:config/routes.rb
if Rails.env.development?
  mount LetterOpenerWeb::Engine, at: "/letter_opener"
end
```


### Mailer設定
railsではActionMailerというライブラリを使ってメールを扱うようです。
`devleopment.rb`を編集することで初期設定を行います。

```rb:config/environments/development.rb
config.action_mailer.raise_delivery_errors = true
config.action_mailer.perform_caching = false
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
config.action_mailer.delivery_method = :letter_opener_web
config.action_mailer.perform_deliveries = true
```

### Mailer作成
railsジェネレーターを使ってメーラーを作成します。

```terminal
rails g mailer hoge
```

下記のようなファイルが作成されます。

今回はメールが送信できたらそれで良いので宛先も件名も適当に決めます。
```rb:app/mailers/hoge_mailer.rb
class HogeMailer < ApplicationMailer
  def hoge
    mail(to: 'a@b.com', subject: 'Hoge')
  end
end
```

## View作成
`hoge`というアクションを作成したのでそれに対応するviewを作成します。

```erb:app/views/hoge_mailer/hoge.html.erb
<p>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
```

あとはメールを送信したいアクションで下記のメソッドを実行すれば送信できます。

```rb
HogeMailer.hoge.deliver_now
```
Google Spread Sheat で複数行のテキストがセルに隠れてしまうので縦幅をフィットさせるには？ ( 解決: セルとセルの間をダブルクリックする)

# 問題

セルの幅をいちどでも自分で伸縮させるとその縦幅が固定されてしまい、文字の縦幅に応じてフィットしてくれなくなる。テキストが隠れる部分が出てきてしまう。


<img width="324" alt="image" src="https://github.com/YumaInaura/YumaInaura/assets/13635059/32ddbbe9-7d64-48ff-8b6b-2b1ef1b17796">

# 解決

すべての行を選択状態にしておいて、行と行の間をダブルクリックすると、すべてのセルで文字の量に合わせてセルが自動調整されるようになる。
この操作をおこなうと、その後にテキストを変更した時も、文字の量に応じて縦幅が伸縮してくれる。

次の画像でいうと1と2の間や、2と3の間をダブルクリックする。

![image](https://github.com/YumaInaura/YumaInaura/assets/13635059/16694b29-8594-4a54-908c-10cee398da32)

## 結果の例

![image](https://github.com/YumaInaura/YumaInaura/assets/13635059/6d5c5a33-21f3-467a-9f37-2165569abd28)

# Note



# ちなみに横幅を合わせるには


同じくすべての行・列を選択状態にしておいて、折り返し設定をすれば良い

<img width="232" alt="image" src="https://github.com/YumaInaura/YumaInaura/assets/13635059/d477dd1b-9571-47c2-bd04-bc84cd0d2e7d">



# チャットメンバー募集


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

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


# Twitter

https://twitter.com/YumaInaura
Flaskの二重ロードでハマったのでメモを残す

# 問題
Flaskを動作させているWebサーバー側でSeleniumを利用して下記のようにブラウザを起動したい。
この処理が二重に呼び出される不具合が発生した。
```python
self.driver = webdriver.Chrome()
```

# 問題発生の原因
Flask を debug=True で実行した場合、リローダを使って変更を開始してファイルに変更が検出されるとアプリケーションを」自動的に再起動している。この動作のためFlaskは2つのプロセスを起動している。このため其々のプロセスで同じコードが呼び出されるため二重起動していた。

# 問題解決方法
use_reloaderオプションをFalseに設定することでリローダを無効にする。ただし。リローダを無効にすると、変更を監視して自動的にアプリケーションを再起動する機能は利用できなくなる

```python
app.run(host="0.0.0.0", port=8080, debug=True, use_reloader=False)
```
長時間使ってるとFirefoxでコピペができなくなる件を解決した

# はじめに

いつからか、PC立ち上げてから一日以上たつとFirefoxでコピペができなくなるようになりました。
chromeはコピペできるのでブラウザが原因なんだろうなぁと思いながら多少面倒でもPC再起動していたんですが、このたび我慢の限界に達したので解決方法を探してみました。

# 解決方法

https://lp.ranabase.com/support/online-m/setting_06.html

こちらの記事を参考。

> Firefoxの初期設定ではセキュリティ上の観点からブラウザタブ間をまたがるオプジェクトのコピー&ペースト操作に制限がかけられています。
Ranabaseで、クリップをスケッチを跨いでコピー&ペーストする操作も、デフォルトではこの制限にかかり実行できません。
コピー&ペーストを可能とするには、次の手順で設定変更を行なってください。
(恐れ入りますが、実施可否は自己責任でご判断をお願い致します。)

とのことで、
FirefoxブラウザURL欄に「about:config」と入力して設定値を変えると直るらしい。
上部の検索窓に「clipboard」と入れてでてきたやつ全部Trueにしちゃいなヨ！
と剛毅なことを書かれています。

でも全部が全部関係してるってことはなくない？
セキュリティ、怖くない？

ということで１つ１つポチポチTrueFalesを切り替えて確認してみた結果、「widget.clipboard.use-cached-data.enabled」だけTrueにすれば解決できました。
もしかするとおま環かもしれませんが、参考までに。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3565603/9a048e26-8378-80e7-b8e0-029f679e12a7.png)
【Bing＋ImageCreator 画像あり】女性の顔画像→町中に立つ女性を生成


　どうも、カーブミラーです。

　今回は、Bing＋ImageCreatorを使ってみました。女性の顔画像から、町中に立つ女性を生成します。

***
　まずは、今回の経緯から。

　ゆうべ、
　　YouTuberかわごんさんと
　　　ChatGPT＋DALL-E3で
　　　　いろいろとやっていて、
　　　　　触発された、
　　　　　　ただそれだけですw

　少し前に、
　　記事も書いたので、
　　　やり方は、知っています。
[【ChatGPT】【Bing＋ImageCreator】GPT-4Visionはまだないけど、疑似体験してみよう。](https://qiita.com/kabumira/items/0cec8a34111d3fb45aee)

　ちなみに、
　　今まで、
　　　記事に画像を
　　　　使用していなかったのは、
　　　　　単にアップできなかった
　　　　　　だけです。

　原因は、ブラウザでした。
　　Google Chrome（スマホ版）を
　　　使用してのアップを
　　　　してきたわけですが、
　　　　　アクセス権が
　　　　　　得られない状況
　　　　　　　でした。

　たまたま、
　　違うブラウザを使用していて、
　　　「あれ？　アップできる？」
　　　　とわかって、やってみたら
　　　　　アップできた、という
　　　　　　感じです。

　でも、
　　これまで、
　　　画像なしで
　　　　やってきたので、
　　　　　乱用しないつもりです。
***
　さて、
　　やってみましょう。

　女性の顔画像から、
　　町中に立つ女性を生成するのが
　　　目標です。

　まずは顔画像。
　　これは、たまたま生成された
　　　画像です。
![_27fc3456-1085-46fe-81e0-2ee34c082980.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/f1b86826-5264-1235-b610-f9a49f189479.jpeg)

　次に
　　Bingにこの画像をアップして
```Text:顔画像→町中シーンのプロンプト作成
この女性が町中に立つシーンの画像を得たいです。画像生成AIに渡すプロンプトを英語で作成してください。
```
　　　と入力して生成します。

　英語にするのは、
　　英語の方が
　　　しっかり描かれるから。
　　　　YouTuberかわごんさんから
　　　　　伝授されました。

```Text:Bingで生成されたプロンプト１
A scene of a town with a woman in the foreground who has her face obscured and her hair tied up. She is wearing a casual outfit and looking at the camera. The background shows a lively street with many pedestrians and storefronts.
```

　これをImageCreatorに与えて、
　　できたのが、
　　　こちら。
![_1790ca50-6ba4-4f63-b959-64bc5c20a8b1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/1cc4b893-462a-c450-a4da-cfa1592f624d.jpeg)

　のっぺらぼうです。
　　うん、意図的ではありません。
　　　どうやら元画像を
　　　　解析した際に
　　　　　“隠れた顔”と
　　　　　　出ていたようです。

　仕方ないので
　　ほかの候補を入力。
　　　あっ、候補は三つありました。
```Text:Bingで生成されたプロンプト２
A woman with dark hair in a bun and a blurred face standing in a busy town with various shops and people around her.
```

　出てきたのが
　　こちら。
![_c5817f5d-2fcf-4f12-bdfd-7fb789641a54.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/b47bab8c-87cd-fa67-14e3-e7882cf9d390.jpeg)

　うん、いいですね。

　今回は、ここまで。
MacでElgato Virtual Cameraなどの仮想カメラ表示を完全削除する方法

# 概要
- 何らかのWebカメラを利用する際、専用のアプリケーションをインストールすることが多いですが、そのようなアプリケーションを完全にアンインストールしても、OBS、Discord、Zoom、Google Meet、Teams、Webexなどのカメラを選択するアプリケーションで、削除したはずの仮想カメラが選べてしまうことがあります。
- 本記事ではその解決方法を説明します。

## 解決を確認した環境
  - macOS: Sonoma 14.0
  - CPU種別: Apple Silicon

# 方法①： DALプラグイン内のディレクトリを削除する

1. 以下のDevice Abstraction Layer(DAL) Plug-Insの中身を確認します。
   ```
   $ ls -l /Library/CoreMediaIO/Plug-Ins/DAL
   ```

2. 例えば、GoPro Webcamをインストールしていた場合、以下のディレクトリが残っていることがあります。
   ```
   drwxr-xrwx  3 root  wheel  96  MM DD YYYY GoProWebCam.plugin
   ```

3. このディレクトリを削除すれば解決します。
   ```
   $ sudo rm -rf /Library/CoreMediaIO/Plug-Ins/DAL/GoProWebCam.plugin
   ```

# 方法②： System Extensions内のディレクトリを削除する
1. Elgato Camera Hubをインストールしていた場合、DALプラグイン内には該当のディレクトリは存在しないため、以下のコマンドでメーカー名などをキーワードに全体検索します。
   ```
   $ mdfind -onlyin / -name elgato
   ```

2. 以下のSystemExtensions配下に該当ディレクトリが存在していることがわかります。
   ```
   /Library/SystemExtensions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/com.elgato.CameraHub.CameraExtension.systemextension
   ```

3. このディレクトリは普通に削除することができないため、macOS復旧からターミナルを使います。起動手順は以下の通りです。
   1. Macの電源を切ります。
   1. Appleシリコンを搭載したMacの場合は、電源ボタン長押しで起動し、画面が表示されたらオプションを選択します。
   1. メニューバーからターミナルを選択して起動します。

4. System Integrity Protection（SIP）を一時的に無効にします。
   ```
   $ csrutil disable
   ```

5. 目的のディレクトリを削除します。（通常ログイン時よりも階層が増えているので注意）
   ```
   $ rm -rf "/Volumes/Macintosh HD/Library/SystemExtensions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/com.elgato.CameraHub.CameraExtension.systemextension"
   ```

6. SIPを有効に戻します。
   ```
   $ csrutil enable
   ```

7. Macを再起動して完了です。
突然キーボード入力がおかしくなった

## はじめに
先日、PC使用中に突然押し下げたキーとは違う文字が入力される現象が発生しました。入力された文字を確認するとNum LockキーやCaps Lockキー有効時によく起こるものとは異なるし、特定のアプリ使用時に発生するのではなさそう…
この記事は不具合解消のために試したこと、今回の原因と思われるもの、その[対処法](https://qiita.com/A_Este/items/f2cec1f5adec121e5ae9#%E5%8E%9F%E5%9B%A0%E3%81%A8%E5%AF%BE%E5%87%A6%E6%B3%95)を記しました。

## PCの仕様
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3368170/f42e068e-07ce-d072-2556-6174211ea25f.png)


## 発生した不具合
- 例）[A]→c　[M]→３　[L]→あ　[K]→i　[半角/全角/漢字]→い　と入力される
- 複数の異なるキーで同じ文字が入力される

## 試したこと
１\. 再起動 
　⇒ 一時的に直るも、しばらくすると再発
２\. 一応Caps Lockキーなどを無効化 
　⇒ 改善せず
３\. キーボードのトラブルシューティング 
　⇒ 異常は見つからず
４\. 別のアプリ、ブラウザを利用する 
　⇒ 一時的に直る場合もあったが、しばらくすると再発
５\. キーボードドライバーの再インストール 
　⇒ 改善せず
６\. Windows 10 22H2の更新プログラムのインストール 
　⇒ 改善せず

## 原因と対処法
結論を端的に言えば、今回の不具合はセキュリティソフト <strong>ESET Internet Security</strong> によるものだと思います。社内で類似の現象に遭遇し不具合を解消した方の話を聞き、もしやと思い私もその方法を試したところ現在に至るまで不具合は再発していません。

手順は以下の通り。

１\. ESET Internet Securityの画面で <strong>設定</strong> から <strong>⚙詳細設定</strong> を開く。 
![ESET設定セキュリティ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3368170/601cb106-3c3f-c006-64be-5998a00489b2.png)


２\. <strong>Webとメール</strong> を開くと出現する <strong>インターネットバンキング保護</strong> をクリック。<strong>キーボードの保護</strong> を無効にし、画面下部にある <strong>OK</strong> をクリック。
![ESET設定セキュリティ２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3368170/31215ccb-aee6-5564-fcd0-3bc5374e7e03.png)

以上。1箇所設定を変えるだけで不具合とイライラが解消されました。
無効化した <strong>キーボード保護</strong> の詳細はこちらを参照してください。

https://help.eset.com/eis/16.1/ja-JP/idh_config_opp.html

セキュリティの観点からはキーボード保護は有効にしておくべきでしょうが、当面は無効化で様子を見るほかないかもしれません。

## おわりに
「キーボード入力不具合」「キーボード入力おかしい」等の検索ワードでは辿り着けませんでしたが、ESET の仕業では？と目星をつけてから検索をすると類似の報告が何件もヒットしました。ESETあるあるだったんですね（苦笑）
中にはESETのバージョンアップによって解消されたという記事が複数ありましたが、逆に疑問点が増えてしまいました。

１\. 私の環境におけるバージョンは <strong>16.1.14.0</strong> で、検索でヒットした記事の投稿時点の”最新バージョン”よりも新しいものです。更なるアップデートで再び同じ不具合が生じているのでしょうか？

２\. 最新バージョンは2023/10/12に公開された<strong>16.2.15.0</strong>です。不具合が初めて生じたのは最新版が公開された日と同日です。が、何故か10/15現在も自動アップデートによる最新化ができていません。手動によるアップデートも何度か試みましたが変化は見られず…（ちなみに、検出エンジンのバージョンは28073で10/14に最新化されています。）

![ESETアップデート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3368170/b04240b0-3ade-4fbd-06fe-92f2bb72b600.png)

何か新しく分かったことがあれば随時追記したいと思います。
spring系のシステムでSerializationExceptionが出る

# はじめに

あまり見たことのないエラーで躓いたので備忘録です。

# 問題
SpringBootで開発したアプリケーションをデプロイ後、エラー画面が出ていたのでCloudWatchでログを確認したら以下のようなログが。
どうやらredis系のエラーのようです。

```
exception": "org.springframework.data.redis.serializer.SerializationException: Cannot deserialize
```

ローカルでアプリケーション起動して確認してもこのようなログは出なかったので不思議に思いました。

# 解決方法
AWSのElasticCache→対象のredisを再起動で解決しました。

デプロイした環境のredisがうまく動いてなかったんですかね。

# おわりに
恥ずかしながら、シリアライズというものを理解していなかったのでお勉強してきました。

> シリアライズとは、オブジェクトをバイトストリームや文字列形式に変換し、キャッシュストレージ（例：メモリ、ディスク）に一時保存するプロセスを指します。これにより、再利用可能なデータを迅速にアクセスでき、システムのパフォーマンスを向上させることができます。

> 一方、デシリアライズはキャッシュからデータを取り出し、利用可能なオブジェクトやデータ構造に変換するプロセスを指し、アプリケーションがこのデータを利用できるようにします。

今回はSerializationException: Cannot deserializeとあるように、保持したキャッシュデータ(redisから)の復元ができずにエラーになっていたということでしょうか。

何かの影響でキャッシュした時と取り出す時のデータがズレてしまいキャッシュデータを取り出せなかった、とかですかね。

単純な解決法でしたが、同じエラーで躓いた方はぜひ参考までに🙏

# 参考
https://qiita.com/esgr_dxx/items/346b0e08ffeece9df1de

https://e-words.jp/w/%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA.html
【docker】コンテナがExited (0)で起動しない時の対応

docker-composeでコンテナを起動して、コンテナの中に入ろうとすると「Exit (0)」が原因で入れなかったときの対応方法。

## 【事象】Exited(0)でコンテナが起動しない

docker-composeでコンテナを立ち上げ後、以下コマンドを実行してコンテナ内に入ろうとすると入れなかった。
```php
docker compose exec サービス名 bash
// 実行結果
// service "サービス名" is not running
```
実行結果で「service is not running」と表示されているので、どうやらコンテナが稼働していないようです。
念のため、「docker ps -a」コマンドを実行し、コンテナの稼働状況を確認してみる。
```
$ docker ps -a
CONTAINER ID   IMAGE            COMMAND                  CREATED          STATUS                     PORTS     NAMES
4c0e3f7d179c   docker-dev-app   "docker-php-entrypoi…"   20 minutes ago   Exited (0) 7 minutes ago             docker-dev-app-1
```
ステータスを確認すると、「**Exited (0)**」と表示されていました。
Exitのステータスコードは「0」なので、コンテナが起動してそのまま正常終了しています。

## 【原因】 コンテナを起動させ続けるプロセスがない

色々調べてみると、原因はdocker側の仕様で、ポート待受をしていないコンテナを起動した場合、コンテナを起動させ続けるためのプロセスを実行させておかないと、そのまま正常終了するようになっているからでした。
そのため、特にエラーもなく、正常終了しているのはdockerの仕様上では間違っていないということです。
原因がわかったので、コンテナを起動させ続けるための何らかのプロセスを入れることで解決できそうです。

## 【対策】 コンテナとホストマシンの標準入出力を繋げる
コンテナ起動後にフォアグラウンドで動作するプロセスを実行させることで解決できます。
フォアグラウンドとは、実行する処理（プロセス）の完了を待ち、それが完了するまで次のプロセスが実行できない状態のことを意味します。
dockerには、コンテナとホストマシンの標準入出力を繋げる設定があるので、それをに有効にすることでコンテナを起動させ続けることができます。

docker composeを用いる場合、docker-compose.ymlの設定項目の、「stdin_open」と「tty」をtrueにすることで設定を有効にできます。

```yml:docker-compose.yml
services:
  サービス名:
        images: xxxxx
        container_name: xxxxx
        (省略)
        stdin_open: true
        tty: true
```
* 「stdin_open」は、ホストマシンの標準入力とコンテナを繋ぐオプションで、trueにするとホストマシンでの入力がコンテナに伝えることができるようになる。
* 「tty」は、ホストマシンの標準出力とコンテナを繋ぐオプションで、trueにするとコンテナの出力をホストマシンで確認できるようになる。

ちなみに、docker composeを用いずに、docker runコマンドでイメージファイルからコンテナを起動させたい場合は、「-itdオプション」をつけると同じ設定でコンテナを起動させ続けることができます。
```
docker run -itd イメージ名
```

## まとめ
Exited (0)でコンテナが起動せずにそのまま終了してしまう原因は、コンテナ起動後にフォアグラウンドで動作するプロセスが存在しないため。

コンテナとホストマシンの標準入出力を繋げる設定を有効にすることで、コンテナを起動し続けることができる。
* docker composeで起動する場合は、docker-compose.ymlの 「stdin_open」と 「tty」をtrueにしておく
* docker runで起動する場合は、「-itd」オプションを付与しておく

「Exited (0)」でコンテナが起動できないときは、この辺りの設定を忘れていないか注意しておきたいです。

---
参考サイト
[docker-compose で exit with status 0 の解決法](https://zenn.dev/torkralle/articles/388ae878cb5f8b)
[Dockerコンテナをずっと起動しておく](https://utouto97.hatenablog.com/entry/2022/03/15/092924)
EC2にSSH接続をする際、出力されたエラー

AWS-EC2にSSH接続しようと、コマンドを実行。

```bash
ssh -i ~/.ssh/EC2_01.pem ec2-user@{EC2-01のIP}
```

すると、以下2つのエラーが出力。

```bash
WARNING: UNPROTECTED PRIVATE KEY FILE! 
```

```bash
Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
```

1つ目のエラーは、「プライベートキーが保護されていない」と教えてくれてる模様。

2つ目のエラーは、「権限がないよ〜」と言われている。

2つ目のエラーは、SSHを理解していないと解けなかったので、もし同じエラーでつまづいてる人が居たら参考にしてみてください。

# 試したこと


今回試したこととしては、以下になります。

- 権限変更
- 秘密鍵から公開鍵を発行
- AWS側のサーバーに公開鍵を配置

## 権限変更


こちらは、権限を読み込みのみに変更すればいいので以下のコマンドを実行。

```bash
chmod 400 EC2_01.pem
```

このコマンドを実行した後、`WARNING: UNPROTECTED PRIVATE KEY FILE!` は表示されなくなった。

## 秘密鍵から公開鍵を発行


僕は最初、EC2から秘密鍵をダウンロードしてきたら、それを.ssh配下に配置して、コマンドを実行すれば、サーバー側の操作をリモート環境で行えるものと思ってました。

色々調べていくと、どうやら秘密鍵から公開鍵の作成が必要ということで、（よく考えたら当たり前ではある）以下コマンドを実行。

```bash
# DLしてきた、.pemファイルを指定
# -y OpenSSH形式の秘密鍵ファイルを読み出し、OpenSSH形式の公開鍵を標準出力する
# -f ファイルを指定
ssh-keygen -y -f EC2_01.pem
```

```bash
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0rQiX6i5TzCGfKQ/e1Hn2Wd+lC+G4JYzY/yYZ8JIfn3Erym247NeDk7Qk4tppHC/GFlk1mt2SvG9A/5CFn7ngXzKsYpFeqzeoOtlnknqRn7xsD3xzFO0bgOs8xcMzzejXc2WLzgXlHHx9TZARGevx8GzW9ErTCZR9pPqqiy18fsLOcCM+xqCfTmSLggIVKfz0pq5wr5jLNurjtf0aiWnwJtH3EN6qwrW7Bvu17M4t63xgzLUs+JcoSFXIMlbM/xNZcg7D3urHvQ6nkVh5qohbDEISCWxi5JkVIVeF1vE11ZYDy6dki4EE7Geym+zh7Bso/v41YhKnc6zFbX4Gbcxx
```

こんな感じで、キーが作成されるので、一旦これをコピー。

## AWS側のサーバーに公開鍵を配置


先ほど、コピーした公開鍵をAWS側のサーバーに配置したいので、AWS側の操作を行う。

インスタンスの概要>インスタンスの接続に`EC2 Instance Connect`があるので、そこをクリックすると以下のような画面が表示される。

![スクリーンショット 2023-10-15 10.58.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2597943/5e814cbc-8b23-b406-ed64-eecb90ca49b1.png)


右下の接続をクリックすると、AWS側のターミナル画面が開く。

以下コマンドで、.sshファイルがあるか確認。

```bash
ls -la
```

デフォルトで、`authorized_keys`のファイルがあると思うでのこの中に、先ほどコピーした公開鍵をペースト。

こちらもファイルの権限の変更が必要な場合は、先ほどと同じように変更する。

```bash
chmod 400 authorized_keys
```

自分のパソコンのターミナルに戻り、以下を実行すると…

```bash
ssh -i ~/.ssh/EC2_01.pem ec2-user@{EC2-01のIP}
```

![スクリーンショット 2023-10-14 22.52.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2597943/050ecf1f-9564-910e-9715-ebb7cd5a8bad.png)


接続に成功！！！

# まとめ

今回はsshをいまいち理解していなかったために、起きたエラーでした。なんとなく理解してるものは、エラーのもとになるというのがよくわかる事例でした。

## 参考

https://utubou-tech.com/mac-ec2-ssh/

http://psychedelicnekopunch.com/archives/2738
テストの概要

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/746c5686-5492-e8a1-f245-bf4e08c52a28.png)
①トップダウンテスト：
　最上位のモジュールから順に結合していきテストを行います。通常、上位モジュールは下位モジュールに指示を出して処理をさせ、その結果を取りまとめるという動作をします。したがって、下位モジュールが正しい結果を返さないと、上位モジュールが正しく動作しているのかを調べることはできません。上位モジュールが必要になります。しかし、本物の下位モジュールは、まだテストが終わっていませんから、正しい結果を返すかどうかわかりません。
　そこで、テスト用の仮の下位モジュールを用意します。これをスタブと言います。スタブはテストデータに対してだけ正しい結果を返却するようにプログラムされています。
　トップダウンテストには、上位モジュールほど何度もテストされて品質レベルが上がるという利点と、テスト作業を並行して行いに行くという欠点があります。
　
②ボトムアップテスト：
　最下位のモジュールから順位結合していきテストを行います。ボトムアップテストでは、仮の上位モジュールであるドライバが必要でになります。ドライバは、下位モジュールを試しに使ってみるテストプログラムであうr。
　ボトムアップテストには、テストの初期段階でテスト作業を並行して行えるという利点と、テストの最終段階にならないと全体の動作をテストできないという欠点があります。

④ビッグバンテスト、一斉テスト：
　一度にモジュールを結合テストを行います。いわば、出たとこ勝負で「ェイ」と動かしみるテストです。手っ取り早くテストを実施できますので、正しく動作すれば良いのですが、正しく動作しなかったときには、どの部分が悪いのかを切り分けることが非常に困難です。　
　ビッグバンテストは、単体テストを終えてから一度に結合してテストを実施します。
　一斉テストは、単体テストをも省略し程度に結合してテストを実施します。

⑤一斉テスト：単体テストを省略して、モジュールを一度に結合する。

１：システムテスト
　システムが設計仕様を満たしているかをテストとします。外部設計、内部設計工程の誤りの発見を行います。

「システムテスト」
・機能テスト：使用で定められた機能が全て備わっているかをテストする。
・性能テスト：使用で定められた性（レスポンスタイム、スループット）が出るかをテストする。
・負荷テスト：負荷をかけた時でも正しく動作するかをテストする。
・障害テスト：障害発生時の対応が正しく行われるかをテストする。

２：運用テスト
　ユーザが主となって、実際位の環境下でシステムを運用するテストです。いわゆる試運転です。

３：退行テスト
　退行テスト（リグレッションテスト）は、変更の影響が他の機能に及んでいないことを確認するテストです。誤りを修正したら、今まで正しく動作していた機能が正しく動作しなくなったということのないようにテストします。
Django基本９～Templateで画面遷移してみる。

スポーツの秋ですね。運動会ラッシュです。

今回は、ホーム画面に戻っとり、更に別の画面の遷移するなど、、、
画面遷移をやってみました。

措定の仕方はこうなります。
（１）アプリケーションフォルダの.urls.pyを確認
　　　　・app_name＝アプリケーション名を確認する。
　　　　・urlpatternsのpath中のname=記載された名前を確認する。
（２）Tnplate内の記載方法
　　　"{% url %}"を指定する。

　例１aタグのherefに記載する
    ＜a href =　"{% url 'アプリケーション名:path内のname名'%}＞home＜/a＞
　例２．viewsに値を渡す場合
　　＜a href =　"{% url 'アプリケーション名:path内のname名}'
   　　  項目名１＝'値',項目名２＝’値２' %＞home＜/a＞

実際にやってみますね
前回までに使用しているnorizo_projevt4を使用します。
（１）norizo_app4/urls.pyを見ていきます。
 　　　・app_name='norizo_app4'
 　　　・pathその１のname＝’wareki'
 　　　・pathその２のname='fil'
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/9ca9174c-07b7-de63-f71b-a5f9b8d0d4d0.jpeg)
（２）templateの修正
　🔹wareki.htmlの修正
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/ecf89427-7e38-fd6b-5b22-c1e9ed15a3c1.jpeg)
サーバを起動して確認してみます。
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/d8d00996-7604-7fd8-2dfa-fb46699e6c9f.jpeg)
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/bd782cae-ce53-cf3b-ed42-d3af5a2c23d6.jpeg)
フィルターページをクリックしてみます。
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/91b5160d-86db-96e0-4fb0-808726e49458.jpeg)

上手くいきました。

　🔹fil.htmlの修正
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/3e323ad3-3098-71fb-f456-2b36295baa81.jpeg)
結果を確認してみます
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/85d0e38f-5288-42db-daa5-d396be141a7e.jpeg)
和暦ページをクリックしてみます。
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/49d30039-4ba2-22c8-564d-61093f07fd1c.jpeg)
上手くいきました。
要求仕様 形式記述言語VDM++ 識別子として日本語は使われているのか

# はじめに
上流工程ではどの程度日本語が使われているのかを調査するため、工程上の位置づけは内部設計の上になりますが、要求仕様記述段階での使用が主に想定されているVDM(Vienna Development Method)[^1]の具体的な記述例を引き続き[^2] 調査しました。


## この記事内容の作業目的
内部仕様の記述用に設計したロジック仕様記述言語 Re:Mind（リマインド）[^3] が要求仕様記述用途で使用できるか、不足する言語仕様要件はなにかといった点を検討しています。要求仕様->内部仕様->実装で一貫した形式記述を採用することで、開発工程の生産性向上に寄与することが目標です。ここでいう「一貫した形式記述」とは、VDMのような数学形式に限定されません。



# 形式記述言語VDM++の日本語識別子の記述例
## 厳密な仕様記述入門 - IPA (独)情報処理推進機構
血縁関係のクラス定義など、基本的に日本語で例示されています。

[[PDF] 厳密な仕様記述入門 - IPA 独立行政法人 情報処理推進機構 2013/3
](https://www.ipa.go.jp/archive/digital/iot-en-ci/keishikisyuho/hjuojm000000m6wx-att/000026829.pdf)

## VDMによる画面機能仕様記述 - 日本科学技術連盟
「検索条件を入力する」など、基本的に日本語で例示されています。

[[PDF] VDMによる画面機能仕様記述 - 品質管理なら日本科学技術連盟 2014/2](https://www.juse.or.jp/sqip/workshop/report/attachs/2013/20140228-ii-entsuu.pdf)

## 「VDM++仕様記述と分析」の定石と手筋 - ソフトウェア技術者協会
「蔵書を削除する」など、基本的に日本語で例示されています。

[[PDF] 「VDM++仕様記述と分析」の定石と手筋 2017](https://www.sea.jp/ss2017/download/3-7_SS2017.pdf)

## VDMTools VDM++開発手法ガイドライン - 九州大学
プラントクラスのクラス定義など、基本的に日本語で例示されています。

FMVDM-> github [[PDF] VDMTools VDM++開発手法ガイドライン1.0 2016](https://github.com/vdmtools/vdmtools/raw/stable/doc-jp/guidelines/guidelines_a4J.pdf)

## いまさら聞けない 形式手法入門 - MONOist 
VDM++のクラス定義例で、「平方根」といった日本語が使われています。

MONOist [いまさら聞けない 形式手法入門](https://monoist.itmedia.co.jp/mn/articles/0701/19/news108.html)

# おわりに
VDM++の日本語の各種資料から、日本で使われる場合は構文中に日本語の識別子が普通に使われていることが読み取れます。やはり、直接関係する情報（解決課題や要求）が自然言語の日本語で書かれている場合は、その仕様記述として同じ日本語の用語を使用し続けるのに実装言語のような抵抗はないと見受けられました。

要求仕様から実装方法の記述詳細化もできるとされる形式記述言語VDM++の、もう少し構造化手順よりの構文（Re:Mindの◇、一般的にはif文switch文、Re:Mindの〇、一般的にはforループ）をVDM++ではどのように使っているのかを調べてみます。


[^1]: IBMのウィーン研究所で1960年代から70年代にかけて開発された形式手法。その実装には1996年にISO標準（ISO_IEC_13817-1）となったVDM-SLと、そのオブジェクト指向拡張のVDM++がある。
[^2]: Qiita [IPA (独)情報処理推進機構の「厳密な仕様記述入門」を読み解く - 要求仕様 形式記述言語VDM/VDM++](https://qiita.com/mylifewithviolin/items/57d8acad91f940360739) 参照
[^3]: Qiita [オープンな設計言語仕様 日本語ロジック仕様記述言語 Re:Mind（リマインド）](https://qiita.com/mylifewithviolin/items/52f806777e6ea031de94) 参照
Android Studio: OkHttp の使い方

## 設定

```xml:AndroidManifest.xml
（省略）
<uses-permission android:name="android.permission.INTERNET" />
（省略）
```

```text:build.gradele.kts(Module app)
（省略）
dependencies {
implementation("com.squareup.okhttp3:okhttp:4.10.0")
（省略）
```

## プログラム

```kt:MainActivity.kt
package com.example.okhttp01

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.util.Log

import okhttp3.*
import java.io.IOException
import java.lang.Thread.currentThread

class MainActivity : AppCompatActivity() {

    val client = OkHttpClient()

    override fun onCreate(savedInstanceState: Bundle?) {
        println("*** check *** aaa ***")
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        println("*** check *** ccc ***")

     //   var url_aa = "https://toridge.com/params.php"
     //   var url_aa="https://httpbin.org/get"
        var url_aa = "https://ekzemplaro.org/storytelling/repertoire/others.json"
        run(url_aa)
    }

    fun run(url: String) {
        println("*** run *** ddd ***")
        val request = Request.Builder()
            .url(url)
            .build()
        Log.i("toridge.okhttp3.run()", "Thread is " + currentThread().name) // Thread is main

        client.newCall(request).enqueue(object : Callback {

            override fun onFailure(call: Call, e: IOException) {}

            override fun onResponse(call: Call, response: Response) {
                println("*** onResponse *** fff ***")
                val request = Request.Builder()
                println(response.body!!.string())
                println("*** onResponse *** hhh ***")

            }
        })
    }
}
```

## 実行結果

View -> Tool Windows -> Logcat
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/f9932277-3c5b-261c-993d-bfa028744ef2.png)
firebaseの導入方法

## firebaseの導入方法


### 事前準備：firebaseのプロジェクトを作成する

firebaseのサイトURL：
https://firebase.google.com/?hl=ja

以下の手順でプロジェクトを作成し、ウェブアプリにfirebaseを追加する

##### （１）プロジェクトの作成
![スクリーンショット 2023-10-15 10.49.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576061/ba0653de-adeb-548a-01f7-7e370b32745e.png)
![スクリーンショット 2023-10-15 10.50.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576061/510c0735-3406-548a-b29c-ef33956c9ad8.png)
![スクリーンショット 2023-10-15 10.50.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576061/60eefb2e-3134-5959-1a56-2c77fa61ea56.png)

##### （２）ウェブアプリにfirebaseを追加
![スクリーンショット 2023-10-15 10.50.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576061/1c5f1a25-9ff1-f719-45ba-0fb9d2c93a49.png)
![スクリーンショット 2023-10-15 10.50.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576061/e5f89522-105f-e303-3548-7213834afdfa.png)
すると以下のような内容が出てくる。これをあとで使用するためコピーしておく。
```javascript
const firebaseConfig = {
  apiKey: '...',
  authDomain: '...',
  projectId: '...',
  storageBucket: '...',
  messagingSenderId: '...',
  appId: '...',
};
```


### firebaseを導入する


ターミナルで、firebaseを使用したいディレクトリに移動
```
cd プロジェクト名
```

npm intallをする
```
npm install firebase@8.7.1
```

main.jsでimportする
```javascript
import Vue from 'vue';

//firebaseの基礎部分
import firebase from 'firebase/app';

import App from './App.vue';
import './app.css';

//firebaseから取り入れたいサービス
import 'firebase/auth';
import 'firebase/firestore';
import 'firebase/storage';

Vue.config.productionTip = false;

//先ほどの「ウェブアプリにfirebaseを追加」で発行したapikeyなどをペーストする
const firebaseConfig = {
  apiKey: '...',
  authDomain: '...',
  projectId: '...',
  storageBucket: '...',
  messagingSenderId: '...',
  appId: '...',
};

firebase.initializeApp(firebaseConfig);

new Vue({
  render: (h) => h(App),
}).$mount('#app');
```

以上でfirebaseの導入方法は完成。
firebaseサービスのauthentication, firestore, storageについての扱い方については違う記事で紹介する。

## まとめ

①firebaseのサイトからAPIキーなどを取得する。
②npmインストールして、main.jsにimportして、そこにAPIキーなどを記載すればOK

さあ早速firebaseを使ってみよう！
Laravel × Reactでmap関数にエラーが出るようになった

## はじめに
LaravelとReactを使ったWebアプリ内で、dbからEloquentモデルを使って抽出したデータに対してJSのmap関数を使っていたところ、`a.map is not a function`というエラーが出てアプリが動かなくなってしまい、その解決法を備忘録を兼ねてまとめました。

## エラー原因
JSのmap関数は連想配列には使えないのですが、バックエンドから送られてきた配列が連想配列になってしまっていたことが原因でした。Eloquentモデルでデータ抽出をする際にwhere句を使うと、得られた配列のキーが0からの連番 (0,1,2...)にならないことがあり、そのような配列をJSに送ると連想配列になってしまうようです。おそらくJSの通常の配列はキーが0からの連番となる決まりがあるのだと思います。  

## 解決策
解決策としては、phpでキーが0からの連番になるようにするか、JSで連想配列にも対応可能にするかの二通りが考えられます。  
phpでの対処としては、配列を雑に作り直せばokです。スプレッド構文など使えば楽でしょう。
```php:example.php
$array = [ ...array ]
```
追記：getした後にwhereで絞り込んだときのみキーが連番でなくなるっぽいので、モデル取得時にwhereのあとにgetできればそれでも良い。

JSでの対処としては、Objectを使って値の配列を作りそれに対してmap関数を適用するとできます。
```javascript:example.js
Object.values(array).map((value) => {任意の処理})
```
AtCoder初心者振り返りメモ ABC323

# ABC323の回
##### 参考リンク
https://atcoder.jp/contests/abc323

# A-問題
https://atcoder.jp/contests/abc324/tasks/abc323_a

**問題文**
0 と 1 からなる長さ 16 の文字列 S が与えられます。
2 以上 16 以下のすべての偶数 i について S の i 文字目が 0 ならば Yes を、 そうでないならば No を出力してください。


````Python:A.py
# 入力を受け取る
S = str(input())

# 偶数なので２つおきに判定
for i in range(1,16,2):
    if S[i] != '0':
        print("No")
        exit()
print("Yes")
````

# B-問題
https://atcoder.jp/contests/abc324/tasks/abc323_b

本番は、自己流の書き方で正答できたがスマートではなかった。

**ポイント**
・勝ち数とi番目をソートするときに工夫が必要
・リストにペアで入力　：P.append((-wincnt, i+1))
・空白区切りで出力　　：print(i, end = " ") # 空白区切りで出力

````Python:B.py
# 入力
N = int(input())

# 結果格納先
P = []

# 文字列S を順に読み込んでいく
for i in range(N):
    S = input()
    
    # 文字列Sの中の勝ち数をカウント
    wincnt = S.count('o')

    # ソートのため、勝利数にマイナス１を掛ける工夫をして、[勝利数]と[i]番目を入力
    P.append((-wincnt, i+1))

#小さい順にソートされるので、マイナス勝利数と前からの順番でソートされる！
P.sort()   

# リストPから要素を呼び出し、i番目の人の数字で出力する
for wincnt, i in P:
    print(i, end = " ") # 空白区切りで出力
````
【自記事まとめ】AWSでplumberをコンテナにして実行した例

# はじめに

AWS上のコンテナサービスを触ってみるのに、サンプルとしてRのplumberをコンテナ化して使っていました。
「AWS上でplumberを動かしたい」や「コンテナサービスを触ってみたい」という方の参考になるかと思い、まとめました。


# ECS on Fargate
AWS Coplilotでデプロイした記事になります。メインは`run local`の話ですが、デプロイもしています。

https://qiita.com/a_b_/items/f0a5ba490670e6c85790

以下はデプロイに便利なサービスを使わないで行った記事です。今見ると大変面倒に見えてきます。

https://qiita.com/a_b_/items/32cbc21bd140321719c2

# App Runner
AWS Coplilotでデプロイした記事になります。

https://qiita.com/a_b_/items/decf0b0c020cab46e0f8

CFnで作成した記事になります。

https://qiita.com/a_b_/items/03e76bf70e13cbd1bdc8

# Amplify
Amplify CLIを使った記事になります。

https://qiita.com/a_b_/items/37d64a144360e02a8f4e

# Lambda

Lambda Web Adapterに中継してもらって実行する方法の記事になります。

https://qiita.com/a_b_/items/d14d8f1335ad5f014ec3

## おまけ：plumber未使用でLambdaでRのWeb API

RでLambdaを使える`lambdr`というのがありましたので、Web APIを作った例です。plumberは使えませんでしたが載せておきます。

https://qiita.com/a_b_/items/1afde637201fb70592ce
k8sでNodePortの公開

# k8sでNodePortの公開

## 1. はじめに

### 1.1 NodePortとは？
Kubernetesでは、NodePortは外部の通信をクラスタ内の特定のポートにリダイレクトする方法の一つです。これは開発やテスト、特定のユースケースで役立ちますが、いくつかの注意点も存在します。

### 1.2 本記事の目的と対象読者
本記事では、Kubernetes初中級者を対象に、NodePortを理解し、適切に利用する方法について詳しく解説します。

---

## 2. NodePortの基本

### 2.1 NodePortの役割と動作
NodePortは、外部からのトラフィックを、Kubernetesクラスタ内の特定のService（そして関連するPod）に転送します。

### 2.2 NodePortの設定パラメータ
主要な設定パラメータには`port`（Serviceがリッスンするポート）と`nodePort`（ノードがリッスンするポート）があります。

---

## 3. 実践: Kubernetes DashboardをNodePortで公開

### 3.1 環境構築
クラスタと`kubectl`のセットアップから始めます。

### 3.2 Kubernetes Dashboardのデプロイメント
Kubernetes公式からDashboardをデプロイします。

### 3.3 NodePortでのサービス公開の設定
```yaml
apiVersion: v1
kind: Service
metadata:
  name: kubernetes-dashboard-nodeport
  namespace: kubernetes-dashboard
spec:
  type: NodePort
  ports:
    - port: 443
      targetPort: 8443
      nodePort: 32443
  selector:
    k8s-app: kubernetes-dashboard
```

### 3.4 アクセス確認とトラブルシューティング
ブラウザを開き、`[Node-IP]:32443`にアクセスし、ダッシュボードを表示します。

## 4. NodePortの利用シナリオ

`NodePort` は一般的に開発やテストの環境、小規模なデプロイメント、あるいはクラスタ外部からの一時的なアクセスが必要な場合に利用されることが多いです。以下は、`NodePort` が推奨される可能性があるユースケースの一例です。

### 1. 開発・テスト環境
- **使用例:** 開発者がローカル環境やテスト環境でアプリケーションやサービスにアクセスする必要がある場合。
- **理由:** シンプルで手軽にセットアップでき、特別な設定やインフラを必要としないからです。

### 2. シンプルなユースケース
- **使用例:** 小規模なプロジェクトやシンプルなユースケースで、手間をかけずに外部からのアクセスを許可する必要がある場合。
- **理由:** 複雑なセットアップや追加のリソースを必要とせず、クイックスタートが可能だからです。

### 3. クラスタ外部からのデバッグ/トラブルシューティング
- **使用例:** クラスタ外部から一時的にサービスにアクセスして、デバッグやトラブルシューティングを行う場合。
- **理由:** 一時的なアクセスを容易に行え、後からアクセスを停止することが容易だからです。

### 4. インフラストラクチャの制約
- **使用例:** 既存のインフラストラクチャが LoadBalancer タイプのサービスや Ingress コントローラーをサポートしていない場合。
- **理由:** 他のオプションが利用できない場合、`NodePort` が直感的で単純なアクセスオプションを提供してくれるからです。

### 5. 特定のポートでの公開が必要な場合
- **使用例:** 外部のシステムやパートナーが特定のIPとポートでアクセスする必要がある場合。
- **理由:** `NodePort` を使用すると、静的なIPとポートを提供できるからです。

### 注意点
- `NodePort` は通常 30000-32767 の範囲で公開されますが、これはセキュリティの観点からあまり理想的とは言えません。
- スケーリングやロードバランシングの観点からも、`NodePort` は最も効率的とは言えません。
- そのため、`NodePort` の利用は限定的であり、よく検討し、適切なセキュリティ対策を講じることが重要です。

## 5. 代替案とその推奨の基準
NodePort を用いてサービスを公開する方法はシンプルでセットアップも容易ですが、セキュリティやスケーラビリティの観点から通常は推奨されません。本番環境や実際に公開するシステムにおいては、通常以下のオプションが利用されます。

### Ingress

Kubernetesの `Ingress` は、HTTPとHTTPSのトラフィックをクラスターサービスにルーティングするAPIオブジェクトで、外部からのアクセスをよりコントロールしやすくします。

- **利点:**
  - SSL/TLSの終端処理やホストベースのルーティングをサポート。
  - パスベースのルーティング（例: /app1 と /app2 を異なるサービスにルーティング）をサポート。
  - 通常、クラウドプロバイダに依存せず、様々なIngressコントローラー（Nginx, Traefikなど）が利用可能。

### LoadBalancer (LB)

Kubernetesの `Service` タイプの一つである `LoadBalancer` は、クラウドプロバイダ（AWS, GCP, Azureなど）を利用して、外部からのトラフィックをサービスに負荷分散してルーティングします。

- **利点:**
  - 設定が簡単で、クラウドプロバイダによっては自動でプロビジョニングされる。
  - スケーラビリティに優れ、高トラフィックを吸収可能。

- **注意点:**
  - 通常、クラウドプロバイダのリソースを利用するため、コストがかかります。
  - プラットフォームに依存する場合があり、移植性に注意が必要です。

一般的に、本番環境や外部に公開するシステムでは、これらのベストプラクティスを採用し、セキュリティ（TLS終端、認証、認可）、スケーラビリティ、そしてマネージメントの観点からも優れた方法を選択します。それぞれのケースにおいて、用途や要件に最も合った方法を選ぶことが重要です。

---

注意: 本記事は指南のみを提供し、完全なガイドとはなりません。実際の運用前には、Kubernetesのドキュメントを十分に理解し、テストを行ってください。これには、セキュリティのベストプラクティスやトラフィック管理も含まれます。

この記事があなたのKubernetesにおけるNodePortの理解と利用にお役に立てれば幸いです。もしフィードバックや質問がありましたら、お知らせください。
【Pyinstaller】Windows Defenderに引っかからないようにする

## 背景

- Pythonでデスクトップアプリを作成することがあり、exe化に[pyinstaller](https://pypi.org/project/pyinstaller/)を使用
- pyinstallerコマンド（`pyinstaller hoge.py`）でexe化したときに、windows defenderのセキュリティでウイルスが検知された
  - [Trojan:Win64/Malgent!MSR](https://www.microsoft.com/en-us/wdsi/threats/malware-encyclopedia-description?Name=Trojan:Win32/Malgent!MSR)というトロイの木馬[^1]区分のチェックに引っかかった
- pyinstallerを使った場合、windows defenderに引っかかることはよくあることらしい
  - [PyInstallerで作ったexeがウィルス判定される](https://note.com/koide_mizu1433/n/n914c3cb2e04a)
  - [[Python] Pyinstallerで実行ファイルがマルウェアに分類されてしまったときの対策](https://gamingpc.one/dev/python-pyinstaller/)

[^1]:有用なプログラムに見せかけて、裏で不正な処理を行うもの

## 要因

- `pip install pyinstaller`を実施するとコンパイル済みのBootloaderがインストールされる
  - pyinstallerコマンドでexe化するときに使うファイル
  - このファイルが要因でウイルス検知されるとのこと
    - [Program made with Pyinstaller now seen as a Trojan Horse by AVG](https://stackoverflow.com/questions/43777106/program-made-with-pyinstaller-now-seen-as-a-trojan-horse-by-avg)

## 対応：bootloaderを再構築する

### ① pyinstallerを任意のフォルダにcloneする

- bootloaderを再構築するには、[pyinstallerリポジトリ](https://github.com/pyinstaller/pyinstaller)をcloneする必要がある

``` cmd
git clone https://github.com/pyinstaller/pyinstaller.git
```

### ② bootloaderを再構築

- bootloaderに移動して、環境をクリーンにする

```cmd
cd pyinstaller/bootloader
python ./waf distclean all
```

:::note info
コンパイラ（ex.MinGW、MinGW-w64）が必要です。
ここでエラーが発生する場合は、コンパイラをインストールしてください。
:::

### ③ wheelのインストール

- bootloaderを再構築したpyinstallerをインストールするために、[wheel](https://pypi.org/project/wheel/)をインストールする

```cmd
pip install wheel
```

### ④ pyinstallerをインストール

- pyinstallerフォルダ下に移動して、再構築したpyinstallerをインストールする

```cmd
cd pyinstaller
pip install .
```

あとは従来と同様にpyinstallerコマンドを実行すれば、windows defenderに引っかからずにexe化できます。

## 参考資料

- [PyInstaller Manual](https://pyinstaller.org/en/stable/bootloader-building.html#)
- [PyInstallerで作ったexeがウィルス判定される](https://note.com/koide_mizu1433/n/n914c3cb2e04a)
- [【Pyinstaller】誤検知を回避する](https://qiita.com/wings/items/3310c83ccde1f687b7ec)
- [[Python] Pyinstallerで実行ファイルがマルウェアに分類されてしまったときの対策](https://gamingpc.one/dev/python-pyinstaller/)
- [PyInstallerで実行ファイルを作ったらSymantecに叱られる件](https://messykitchen.hateblo.jp/entry/2020/03/02/150948)
- [Program made with Pyinstaller now seen as a Trojan Horse by AVG](https://stackoverflow.com/questions/43777106/program-made-with-pyinstaller-now-seen-as-a-trojan-horse-by-avg)
- [wheel](https://pypi.org/project/wheel/)