OmniAICreator/Qiita-1.07M huggingface dataset:
本当に関心を分離するための Tailwind CSS

## HTML と CSS について

HTML と CSS について、これは関心が分離されているから良いという話を聞きます。 HTML には文書構造、 CSS にはデザインをまとめるのが良いという話です。
今から20年くらい前、 CSS が登場したばかりのネットではほとんどの場合はこれが正しかったと思います。なぜなら、当時はコンテンツを作るのには HTML を手元で書いて、デザインは HTML 要素とその属性に書くのが当たり前だったからです。
この時代では、サイトに一貫したデザインを持たせたいときは1ヶ所デザインに変更があったなら全てのページの HTML を書き直す必要があったり、レイアウトのために table 要素を使ってしまうためコンテンツの機械的な解析が困難だったりと、HTML の文書構造と見た目が分離していないのは実際に弊害があったのです。

## Tailwind CSS を見たとき

難しい CSS の設定を簡単にできるのがすごい！と思いました。特に `divide-y` などを見ると割と面倒な計算をやってくれていて、これはなんて楽にスタイルを適用できる技術なんだ！とびっくりしたものです。

しかしもうひとつ思いました。「これは文書構造に見た目を依存させるという意味で、CSS 前の世界に戻っていないか？」

## Tailwind CSS は本当に CSS 前の世界に戻ったのか？

考えてみましたが、この答えは完全に NO です。

今はサイトを一から手書きすることなどなく、デザインを1ヶ所変更したいならソースファイルの1ヶ所を変更してサイトを生成し直せばいい話ですし、見た目のために HTML 要素を使うこともほぼ無くなったため、HTMLコンテンツを機械解析するのもやりやすくなりました。

文書構造と見た目が一つになっていることの欠点はこの記事で取り上げたものだけではないでしょう。しかしそれらもまた技術の発展によって克服されいると思われます。そんな今という時代は、文書構造と見た目の分離はこの先も本当に必要なのかを問い直されている時代なのではないでしょうか？

## 文書構造と見た目の密結合は悪いことなのか

プログラミングをしていると、密結合と聞いたら悪い印象があるかも知れません。
しかし、HTML 文書には見た目も含めて機能である要素がたくさんあります。 `nav` や `button` といった要素がそれです。

テキストサイトが主流だった20年前はともかく、今はウェブサイトで出来ることは格段に増え、HTML は文書構造だけではなく UI コンポーネントのスケルトンという性質も持つようにもなりました。
そうした現代の HTML から見た目の情報を剥がすことにはどれだけの意味があるでしょうか。

本当に関心を持つべきはユーザーにどのような体験を提供するのかであり、HTML や CSS をどのような構成にするのかではありません。そしてユーザー体験を提供するには UI のデザインは避けて通れない道です。

そのため、CSSの複雑さをなるべく隠蔽し、HTML にどのような UI を持たせるのかに注力できるようにするのが Tailwind CSS のアプローチだと考えます。

## まとめ

CSS が現れた時代にはウェブサイトはテキストがメインコンテンツで、デザインというとそれをいかに見せるのかというところに関心がありました。そのため、文書構造と見た目の設定が分かれていることに大きな価値がありました。

しかし今のウェブサイトはウェブアプリと呼ばれるものがメインで、そのウェブアプリを使ってどのような体験をしてもらうかに関心があります。ユーザー体験をよくするためには UI デザインの問題は避けて通れません。

そして、ウェブ技術で UI を実現するには HTML と CSS が疎結合であることにはあまりメリットがないと考えます。

なので、Tailwind CSS が採用しているユーティリティファーストは、CSS の複雑さをなるべく隠蔽してどのような UI を作るのかに注力できるようになるアプローチだと思います。

参考URL : https://adamwathan.me/css-utility-classes-and-separation-of-concerns/
wslで、最小のカーネルをコンパイル その9

# 概要
wslで、kernel.elfのコンパイル、やってみた。
キーボード読めるので、cで、書いたカーネルで、俺言語を組み込む。

構想編

# 俺言語とは

自分が、開発している、Elixir、javascript、arduino、avrで動く、教育用のtoy言語。




# 俺言語の仕様。

対話形式で、一行ずつ解釈するインタープリタ方式。
行番号を持ち、分岐できる。
エディタモードとダイレクト実行モードがある。
文は、代入文のみ。
行は、行番号、スペース、代入文。
行番号は、１から２５５まで。
変数は、a,b,c,d,e,f。
数値は、０から２５５まで。
*+ - * / で加減乗除。
%は、剰余。
$は、乱数。０から255。
0は、ソースリスト。
ソースは、256バイトまで。
= < > で論理式、値は０と1を取る。
文は、左から順に評価される。2+5\*6は、42となる。(重要)
＃は、プログラムカウンター
if文は、#=a<100*20でaが100より小さいなら、行20に飛ぶ
？は、プリント文。
?=a　数値表示
?="hello" hello表示
行番号無しなら、ダイレクト実行。
#=1 でrun
100 a=0で、インサート
100で、デリート
100 a=100で、エディット
使う文字種
0123456789=#<>?+*/-%"!$



# サンプルコード

ズンドコを求める

```
0               リスト表示
5 a=0　　　　　  変数aを初期化
10 #=$<126*60　　乱数が126以下なら、行６０へ飛ぶ。if文
20 ?="zun "　　 zunをプリント
30 a=a+1　　　  変数aをインクリメント
40 #=a>4*90　　 変数aが４より、大きいなら、行９０へ飛ぶ。if文
50 #=10　　　　 行１０へ、飛ぶ。goto文
60 ?="doko "　　dokoをプリント
70 a=0　　　　  変数aを初期化
80 #=10　　　　 行１０へ、飛ぶ。goto文
90 ?="doko ki yo shi!!"　　doko kiyoshiをプリント
 
#=1　　         ダイレクトに、行１へ、飛ぶ。なのでRUN
```
九九
```
10 a=1
20 b=1
30 ?=a*b
40 a=a+1
50 #=a<10*30
60 b=b+1
70 a=1
80 #=b<10*30
90 #=0

```
fizzbuzz
```
10 a=0
20 a=a+1
30 b=a/15
40 #=%=0*120
50 b=a/5
60 #=%=0*140
70 b=a/3
80 #=%=0*160
90 ?=a
100 #=a<100*20
110 #=200
120 ?="fizzbuzz "
130 #=100
140 ?="buzz "
150 #=100
160 ?="fizz "
170 #=100


```

```

10 a=0
20 b=123
30 b=b*5
40 b=b-1
50 #=$<0*110
60 ?="zun "
70 a=a+1
80 #=a>3*140
90 #=30
110 ?="doko "
120 a=0
130 #=30
140 ?="doko ki yo shi!!"



```

以上。
プロンプト入門

プロンプト(Prompt)とは、生成型AIを使用する上で必須の前提であり、良いプロンプトは生成型AIにより精確な結果を出すことを可能にします。これにより時間の節約だけでなく、トークンの節約にも繋がります（これは米ドルですよ）。そこで、生成型AIが登場した後、プロンプトエンジニアという職種が誕生しました。それに伴い、プロンプトのシェアに関する記事や、様々な場面でのプロンプトを集めたウェブサイトも多く出現しています。
OpenAIの公式サイトではプロンプトガイドが提供されており、原文はhttps://platform.openai.com/docs/guides/prompt-engineeringにあります。ここではその提案について見ていきましょう。
クリアなプロンプトの作成
GPTモデルがプロンプトの内容を明確に理解するほど、より正確で満足のいく回答を提供します。
具体的な方法は以下の通りです。
- 詳細な問題の説明：問題を明確に記述することで、期待に沿った答えを得ることができます。
- GPTに役割を持たせる：GPTに特定のアイデンティティを設定すれば、そのアイデンティティの思考で結果を出してくれます。
- 区分けのためのセパレーターの使用：“----”のようなセパレーターを使用して、異なるプロンプトを区分けします。例: 翻訳する内容と翻訳指示を分ける。
- GPTに思考プロセスを示す：論理的な内容生成の場合、GPTにステップバイステップで結果を出させることができます。
- 例示を提供する：特定のフォーマットが必要な場合、それに倣った例をGPTに示しましょう。
- 提示の制限：出力が期待に沿うように（トークンの節約のため）、プロンプトに出力の制限を加えます。例: 長さやテーマなど。
参照テキストの提供
言語モデルは仮説の答えを自信を持って提供することができますが、深遠なトピック、引用、URL等に対する質問があった場合、モデルに参照テキストを提供することで、創作の少ない回答を促進できます。
具体的な方法は以下の通りです。
- モデルに参照テキストを使用して回答するよう指示する
- モデルが参照テキストの中から引用して回答するよう指示する
複雑なタスクを単純なサブタスクに分割
複雑なタスクを多くの小さなタスクに分解し、GPTに回答させることで、前後関係がある場合は明確な論理関係を示すことが重要です。
具体的な方法は以下の通りです。
- カテゴリー化：ユーザーの問い合わせと最も関係のある指示を意図の分類によって決定する。
- 階層化：長時間の会話を必要とするアプリケーションでは、以前の会話内容を要約またはフィルタリングする。
- 再帰：長文書のステップバイステップな要約と、その要約を再帰的に構築すること。
モデルにより多くの考え時間を与える
ある程度複雑なデータ処理を求められた場合、すぐに正しい答えが出ないことがありますが、モデルに段階的に考えさせることで、より良い答えが得られます。
具体的な方法は以下の通りです。
- 結論を急がず、モデルに自らの解決策を提示させる
- 内心の独白や一連の質問を利用して、モデルの推論過程を隠す
- モデルに以前の伝達で何かを見落としたかを尋ねる
外部ツールの利用
モデルに外部ツールの出力を提供することで、モデルの弱点を補完することが可能です。例えば、一般的に使用されている「テキスト検索システム(RAG)」では、まずローカルの知識ベースから関連する内容を見つけ出し、それをモデルに提供することで、より適切な内容の出力を実現します。
また、データ処理に関しては、モデルが得意としない場合がありますが、「電卓」を利用することが可能です。タスクを言語モデルではなくツールでより信頼性をもって、またはより効率的に完了させることができる場合は、ツールを使用し、両者の長所を活かして最良の効果を目指します。
具体的な方法は以下の通りです。
- 埋め込みベースの検索を使用して、効率的な知識検索を実現
- より正確な計算を実行したり、外部APIを呼び出すためにコード実行を利用する。
- モデルに特定の機能へのアクセス権を与える
総合的なシステムのテスト
性能を定量化することで、性能を向上させることができます。モデルの出力結果の品質を定量化し、プロンプトを最適化して、改善後の出力品質を高めます。
具体的な方法は以下の通りです。
- 標準的な答えの参考に基づいて、モデルの出力効果を評価する。

(Translated by GPT)

元のリンク：https://mp.weixin.qq.com/s?__biz=MzA3NDM1MzIyMQ==&mid=2247487892&idx=1&sn=8b04e5135d4d7dea3dcb1f5c43acb96a&chksm=9f004ebea877c7a80f25e45ae69b49aa824f0da16b3bde422356d9bf81bd77740715e644ae6e&token=1601329047&lang=zh_CN#rd
Rでの並列計算

Rで並列計算を頻繁に行うのですが、その度に「あれ、どうやるんだっけ」となるので、備忘録として方法を記しておきます。
いくつか並列計算の方法があるようですが、自分は`doParallel`パッケージの`foreach`で実行しています。

## コード
```
library(doParallel)

# 1
cores <- 10 # No. of cores to be used

# 2
cl <- makeCluster(cores)
registerDoParallel(cl)

# 3
result <- foreach(i = 1:100) %dopar% { 
    # calculation
}

# 4
stopCluster(cl)
```

## コードの内容
1. 並列計算の数（使用するコア数）を決める
1. 1で定めた数のスレッドを確保する
1. `foreach`内で定めた範囲（上の例だと i = 1 ~ 100）で、`%dopar%`以降の中身を並列・繰り返し計算し、その結果を`result`に入れる
1. 並列化を終了し、コアを開放する

`result` はlist形式のオブジェクトとして作られる。要素数は総計算数（上の例だと100）であり、各要素に各計算結果が収まっている。
mindの研究 その78

# 概要
mindが、謎なので調べてみた。
練習問題やってみた。

# 練習問題
mindで、QiitaのuserのContributionを取れ。

# 方針
HttpGetは、Vbsの力を借りる。
正規表現も、Vbsの力を借りる。
msgboxも、Vbsの力を借りる。

# サンプルコード

```

出力ファイルは　ファイル。

メインとは
　「scra.vbs」で　出力ファイルを　新規オープンし
　「Function Scraping(url)」で　出力ファイルに　一行書き込み
　「	SamAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"」で　出力ファイルに　一行書き込み
　「	Set objHTTP = CreateObject("Microsoft.XMLHTTP")」で　出力ファイルに　一行書き込み
　「	objHTTP.Open "GET", url, False」で　出力ファイルに　一行書き込み
　「	objHTTP.SetRequestHeader "User-Agent", SamAgent」で　出力ファイルに　一行書き込み
　「	objHTTP.Send」で　出力ファイルに　一行書き込み
　「	Set objStream = CreateObject("ADODB.Stream")」で　出力ファイルに　一行書き込み
　「	objStream.Type = 1」で　出力ファイルに　一行書き込み
　「	objStream.Open」で　出力ファイルに　一行書き込み
　「	objStream.Write objHTTP.responseBody」で　出力ファイルに　一行書き込み
　「	objStream.Position = 0」で　出力ファイルに　一行書き込み
　「	objStream.Type = 2」で　出力ファイルに　一行書き込み
　「	objStream.Charset = "utf-8"」で　出力ファイルに　一行書き込み
　「	http_source = objStream.ReadText」で　出力ファイルに　一行書き込み
　「	objStream.Close」で　出力ファイルに　一行書き込み
　「	Set re = New RegExp」で　出力ファイルに　一行書き込み
　「	re.Pattern = "Contribution: ([0-9].+[0-9]) "」で　出力ファイルに　一行書き込み
　「	re.IgnoreCase = True」で　出力ファイルに　一行書き込み
　「	re.Global = True」で　出力ファイルに　一行書き込み
　「	Set Matches = re.Execute(http_source)」で　出力ファイルに　一行書き込み
　「	For Each Match in Matches」で　出力ファイルに　一行書き込み
　「		RetStr = RetStr && Match.submatches(0) && " です。" && vbCRLF」で　出力ファイルに　一行書き込み
　「	Next」で　出力ファイルに　一行書き込み
　「	msgbox RetStr」で　出力ファイルに　一行書き込み
　「	Set re = Nothing」で　出力ファイルに　一行書き込み
　「	Set Matches = Nothing」で　出力ファイルに　一行書き込み
　「	Set objHTTP = Nothing」で　出力ファイルに　一行書き込み
　「	Set objStream = Nothing」で　出力ファイルに　一行書き込み
　「End Function」で　出力ファイルに　一行書き込み
　「Scraping("https://qiita.com/ohisama@github")」で　出力ファイルに　一行書き込み
　出力ファイルを　クローズし
　「C:\Windows\SysWOW64\cscript scra.vbs」を　プログラム実行する
。





```

# 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/1f0ed44a-2666-a621-25cf-0ef0e8004da4.png)



以上。
【SQL】膨大なINSERT文をとにかく楽して生成したい

# はじめに
検証の際などボリューミーなデータが必要になると、作るのにかなり億劫ですよね:rolling_eyes:

今回は、**Excel**（＋メモ帳）を使用して膨大なINSERT文を生成する方法をご紹介します。

:::note warn
こちらは"**MySQL**"を想定しております。
他データベースと異なる点に関しましては、適宜修正してください。
:::

# INSERT文とは
SQLの知見があまりない方向けにご説明しておくと、INSERTは"<font color="Red">**該当テーブルにデータを投入するSQL文**</font>"です。

```sql
INSERT INTO スキーマ名.テーブル名 (`カラム名1`, `カラム名2`, `カラム名3`) VALUES ('値1', '値2', '値3');
```

これで1レコード（行）分です。
数レコードならデータベース上で手打ちでも問題ないのですが、何万レコードとなると発狂します。
腱鞘炎になっちゃう。。~~業務とはいえ、たまに投げ出したくなる~~

# INSERT文の生成方法
ここからが本題です。
何万レコードを手打ちはさすがに現実的ではないので、私はExcelとメモ帳を駆使しINSERT文を作っています。

### ■ Excel
まずはINSERT文生成用のExcelフォーマットを用意する必要があるので、構成からご説明いたします。

#### ▼ **全体**
スキーマ名.テーブル名、カラム名を関数で取得し、INSERT文に自動反映されるようにしています。
![スクリーンショット 2024-03-13 213355.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726107/b8ec3641-cade-0fa2-0a98-573d28379f36.png)

#### ▼ **値を直接入力**
F8~H10

#### ▼ **スキーマ名.テーブル名、カラム名を取得**
C2：スキーマ名
C3：テーブル名
C4：`=C2&"."&C3`

F7~：カラム名

#### ▼ **INSERT文に各カラム名を取得**

E列：
```
="INSERT INTO "&$C$4&" (`"&$F$7&"`,`"&$G$7&"`,`"&$H$7&"`)VALUES('"
```

#### ▼ **最後の値に閉じ括弧+αを付与**
2レコード目以降は1レコード目の値をコピペ
B列：`=H8`　**※最後のカラム列**
C列：`');`
D列：`=B8&C8`

D列の値を最後の列（H列）に値貼り付け
※B列、D列の関数に変な値が反映されてしまっていますが、以降の工程には影響しないので問題ないです。
![スクリーンショット 2024-03-13 214155.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726107/0043fbe9-bb3e-64af-ff47-59add46cc810.png)


### ■ メモ帳　※サクラエディタ推奨
Excelの値をそのままデータベース上にコピペするだけでは構文が不十分なので、メモ帳で置換する工程を挟みます。

#### ▼ **メモ帳に値を貼り付け**
E8からH10をコピーして貼り付け
![スクリーンショット 2024-03-13 221952.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726107/07ae0889-75cf-da5d-b375-efcddd89b72e.png)

#### ▼ **正規表現に☑を入れて、以下を置換**
置換前：¥t　<font color="Red">**※"¥t"という文字列ではなくtabキーでできた空欄**</font>
置換後：`','`

#### ▼ **正規表現に☑を外して、以下を置換**
置換前：`('',`
置換後：`(`

置換完了後、メモ帳の値をすべてデータベース上に貼り付けると、実行できる状態になります。
![スクリーンショット 2024-03-13 223733.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726107/32853201-387e-a073-7a73-0debaa29d2ed.png)

データベース上に、データが正常に投入されました！
![スクリーンショット 2024-03-13 223825.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726107/9202f370-3f23-f00c-f616-a27850a2cf9d.png)

# 最後に
今回は、膨大なINSERT文を楽して生成する方法をご紹介いたしました。
今後暇を見つけて、もっと効率的かつやりやすい方法を実践してみようと思います。（おそらく先は長い。。）

最後までお読みいただき、ありがとうございました:information_desk_person_tone1:
【AtCoder】リストの入力の受け取りを美しく書く

# はじめに

こんにちは！　中2のAwashAmityOakです！　AtCoderでは、早く解くために、<font color="red">**解法を思いつく思考力**</font>だけでなく、<font color="red">**コードを短く読みやすく書く**</font>ことも重要です。今回は、私が実践している、<font color="red">**リストを受け取るときのTips**</font>を広める記事です。

# 良くないコード

例えば、次のような形式で、入力が与えられるとしましょう。すべて数値とします。

$N \quad M$
$A_1, \quad A_2, \quad \dots, \quad A_N$
$B_1, \quad B_2, \quad \dots, \quad B_M$

このとき、Pythonでは、

```python
N, M = map(int, input().split())
A = list(map(int, input().split()))
B = list(map(int, input().split()))
```

と書くことができます。

しかし、`map()`の前後が`list()`で囲まれていて、少しタイプしにくいかと思います。

# 改善点

そこで、私が提案するリストの受け取り方はこんな書き方です。

```python
N, M = map(int, input().split())
*A, = map(int, input().split())
*B, = map(int, input().split())
```

どうですか？　きれいに見えませんか？

`A`の部分で`*A,`という書き方をすることで、`list()`がいらず、3行ともすべて`map(int, input().split())`という<font color="red">**統一された書き方**</font>ができます。

# 何をしているか

Pythonの<font color="red">**アンパック(Unpack)**</font>という構文を使っています。(「分割代入」と呼ばれることもあります。)

上記のコードの`N`と`M`のように、変数の個数(この場合は2個)が決まっている場合は、`N, M = ...`のように、<font color="red">**まとめて代入式を書く**</font>ことができます。この書き方をアンパックと言います。アンパックでは、代入式の右辺は<font color="red">**イテレータ**</font>である必要があります。(`map()`の戻り値は、`map`型というイテレータです。)これは、競プロの入力の受け取り方などを調べると、たくさん情報が出てくるので、知っている人も多いかと思います。

しかし、アンパックがすごいのは、これだけではありません。`*`(アスタリスク)を使うことで、変数の個数が決まっていなくても、<font color="red">**「残り全部」をリストとして代入**</font>することができるのです。

```python
a, b, *c = [0, 1, 2, 3, 4, 5]
```

例えば、このコードでは、`a`に`0`、`b`に`1`が代入されるのは、一目瞭然ですが、`*`がついている`c`には、`a`と`b`に入った`0`と`1`以外のすべての要素(`[2, 3, 4, 5]`)がリストとして代入されます。

`*`を使う<font color="red">**位置は、変えることも可能**</font>です。

```python
a, *b, c = [0, 1, 2, 3, 4, 5]
```

この場合は、`a`に`0`、`b`に`[1, 2, 3, 4]`、`c`に`5`が代入されます。

`*`をつける変数の数は、<font color="red">**0個か1個**</font>でなければなりません。

```python
# エラーになる
a, *b, *c = [0, 1, 2, 3, 4, 5]
```

変数の数が1個で、その変数に`*`でアンパックで代入したい場合は、次のコードのように、<font color="red">**変数名の後ろ**</font>に`,`(コンマ)をつける必要があります。

```python
*A, = map(int, input().split())
```

先ほどのコードの一部です。(分割代入とか言いながら、もはや分割していませんけどね…。)

# 応用

クエリ問題で、以下の形式のクエリを受けることがあります。(先日の[ABC344](https://atcoder.jp/contests/abc344)の[E問題](https://atcoder.jp/contests/abc344/tasks/abc344_e)がこれでした。)

> 次の2種類のどちらかがクエリとして渡される。
> `1 x y`
> `2 x`

このときは、入力を受け取るまで、変数の個数が<font color="red">**3個と2個のどちらなのかわからない**</font>ですよね？　このようなとき、アンパックを駆使して、こんな書き方をすると、<font color="red">**スマート**</font>です。

```python
# ...前略
for q in range(Q):
    t, *a = map(int, input().split())
    if t == 1:
        x, = a
        # 処理...
    elif t == 2:
        x, y = a
        # 処理...
# 後略...
```

(実際のコンテスト中は、きれいなコードを書くことを、意識する必要なんてまったくありませんが…。)

# おわりに

今回は、アンパックを使用して、AtCoderのコードを短く綺麗に書く方法をお伝えしていきました。

# 参考

https://note.nkmk.me/python-tuple-list-unpack

---

この記事が良いと思ったら、ぜひいいねとフォローをよろしくお願いします！　[Xアカウント](https://twitter.com/awashamityoak)のフォローなどもしてくれると泣いて喜びます！

最後まで読んでくださり、ありがとうございました！
vimとvim-tinyとの違い

# muttがつかうエディターについて

muttmuaがよびだすvimって、タイニーのほうなんですね。

そちらをアンインストールしたから、muaからみつからないって言われました。

```
cd ../../bin/
ls vim*
```

こうやるとvimしかないことがわかりました。当然ですね。

`.muttrc`というのがホームディレクトリにあって、これが設定ファイルです。
そのなかに、editorうんぬんというアイテムがあり、そこが
vim-tinyとなっているばあいには、なおす必要があります。

# エディターを変更

これでぶじにエディターをかえることができました。
SIerのトンチキスクラムについて (6)

# プロダクトオーナー
プロダクトに価値を与えるのはプロダクトオーナー(PO)の仕事です。

プロダクトの価値について、探求と情報収集、考察、開示および評価が仕事の全てです。

真にプロダクトの価値を知る者がこの役割を引き受けるべきでしょう。

という綺麗事を述べたうえで現実の話しをしよう。

結論からいうと、この仕事はとても難しい。

まず、真にPOをつとめる人物が必ずしもPOをやれるとは限らない。
その場合代理を任命するか雇うかすると思うのですが、環境と人の両面が適切ではなければ、真のPOの代理にすらなれない事例をいくつか見てきました。

コレはその中でも割とわかりやすい例です。

その人達はチームでPOをやろうとしていました。
「仕様を作るという作業をする」チームです。

おわかりいただけただろうか？

いやそんなもん仕様作るスクラムチーム１個作ってそこにぶん投げればいいんですよ・・そこにPOとされている人々が全力でコミットする必要はありません。

このPOとされる人たち、世間ではこう言い表されると思います。

「ガキの使い」

これについてとあるスクラムのえらい方とお話する機会があり、この状態を通訳の方を通して説明していただいた結果、ただ一言でこれを言い表してくださいました。

***Fake PO***

でも偽物が本物に勝ったらアカンって道理はないよね。

彼らは一生懸命でした。

ここからさきは伝え聞いた話で余白。

そして真のPOから指名を受けたPOであるべき人、数百人を率いる事業部長相当の方だったのですが・・その人なんて言ったと思います？

「こんな些末なことは部下に任せればいいだろう私は忙しいんだ」

かくして不幸なスクラムは続く。
文字列からJSONへ変換、JSONからキーを削除、String型からbyte型に変換


JSONの操作には、Jackson使っています。

メソッドには、throws UnsupportedEncodingException, JsonMappingException, JsonProcessingException を付けています

jacksonに関するimport

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;

```java
String jsonStr = "{\"ID\": 2, \"Name\": \"taro sato\", \"token\": \"axffee33333ffd\", \"Age\": 27}";

// String型からbyte型に変換
byte[] byteArray = jsonStr.getBytes("UTF-8");

// byte[] -> String 変換
String byteToStr = new String(byteArray);
System.out.println(byteToStr);

// 文字列からJSONへ変換
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(byteToStr);
ObjectNode object = (ObjectNode) jsonNode;

// JSONから、tokenというキーを削除
object.remove("token");
String updatedJson = objectMapper.writeValueAsString(object);
System.out.println(updatedJson);

// String型からbyte型に変換
byte[] byteToArray = updatedJson.getBytes("UTF-8");
```

```sh
{"ID": 2, "Name": "taro sato", "token": "axffee33333ffd", "Age": 27}
{"ID":2,"Name":"taro sato","Age":27}
```
はじめまして！のご挨拶

初めまして！
ブログサイト『ぱそぱそ遊楽町』と『ひかるねっと』を運営するろいむと申します！
主にサイトの運営に注力しており、サイト分析やペルソナ分析に力を入れております。
競合がめちゃくちゃ強いですが、自分が生きている間に大きいメディアに成長させたいので、
めげずに頑張っていこうと思います！

質問を投げかけたり、逆に回答させていただくことがあるかもしれません！
ではでは、よろしくおねがいいたします！

・ぱそぱそ遊楽町
https://roimsblog.com
・ひかるねっと
https://hikarunet.com
・X(旧Twitter）
https://twitter.com/roim_blog
GitHub docsにcontributionしようとissueを起票したら秒でcloseされた話

# GitHub docsにcontributionしようとissueを起票したら秒でcloseされた話

issueに起票するタイミングでコントリビューションしようとするタイミングでそれこそドキュメントを読んでなかっただけです。GitHub社のトリアージ担当の方にお手数をおかけしてしまいました。ごめんなさい。

## 読め

https://github.com/github/docs/blob/main/contributing/types-of-contributions.md#earth_asia-translations

思い出にQiitaに残しておこうと思う。

## 実際に起票したissue

https://github.com/github/docs/issues/32063
line-bot-sdk-python V3のコードサンプル

# はじめに
慣れないpythonでLINEBotを作ろうとして、line-bot-sdk-pythonを使っていましたが、[公式ドキュメントのサンプル](https://github.com/line/line-bot-sdk-python/blob/master/linebot/v3/messaging/docs/MessagingApi.md)が2024年3月時点で全然整備されていないので、最新版のV3のコードサンプルを自分用にまとめます。

パパッと作りたい人は以下参考にしてみてください

https://qiita.com/cog1t0/items/5769b939396051127aa0

# コードサンプル
試したものから随時追加していきます。

## 共通部分
```python
from linebot.v3.messaging import (
    Configuration,
    ApiClient,
    MessagingApi,
)
configuration = Configuration(access_token=CHANNEL_ACCESS_TOKEN)
 with ApiClient(configuration) as api_client:
        line_bot_api = MessagingApi(api_client)
        ## ここから下はそれぞれ
```

## reply_message

```python
from linebot.v3.messaging import (
    ReplyMessageRequest,
    TextMessage,
)
```

```python
message=TextMessage(text='返信メッセージ')

line_bot_api.reply_message_with_http_info(
            ReplyMessageRequest(
                reply_token=event.reply_token,
                messages=[message]
            )
        )
```

### quick_reply

```python
from linebot.v3.messaging import (
    ReplyMessageRequest,
    TextMessage,
    QuickReply,
    QuickReplyItem,
    MessageAction
)
```

```py
items = [
    QuickReplyItem(
        action=MessageAction(
            label="Ruby",
            text="Rubyが好き"
        )
    ),
    QuickReplyItem(
        action=MessageAction(
            label="Python",
            text="Pythonが好き"
        )
    )
]
quick_reply = QuickReply(items=items)

message=TextMessage(text='返信メッセージ', quickReply=quick_reply)

line_bot_api.reply_message_with_http_info(
            ReplyMessageRequest(
                reply_token=event.reply_token,
                messages=[message]
            )
        )
```

クイックリプライでは他にも以下のアクションが使える。
- Postback action
- URI action
- Datetime picker action
- Camera action
- Camera roll action
- Location action
- Richmenu Switch Action
- Clipboard action

:::note
対応するクラスが以下に _action.pyというファイル名でまとめてあるので、対応するものを使う
https://github.com/line/line-bot-sdk-python/tree/master/linebot/v3/messaging/models
:::

参考

https://developers.line.biz/en/reference/messaging-api/#action-objects

## send_message

```python
from linebot.v3.messaging import (
    PushMessageRequest,
    TextMessage,
)
```

```python
message=TextMessage(text='送信メッセージ')

line_bot_api.push_message_with_http_info(
            PushMessageRequest(
                to='送信先のID',
                messages=[message]
            )
        )
```

# 参考記事
https://mo22comi.com/line-messaging-api-sdk-v3/
Elasticsearchのインストール手順

## 環境
VirtualBoxの仮想マシンで実行。
　RHEL9.3
　Elasticsearch 8.12

## 手順
### ホストOS上で行う 
Elasticsearchの公式サイトにアクセスし、圧縮ファイルをダウンロード(linux x86_64)
https://www.elastic.co/jp/downloads/elasticsearch
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664791/326183cb-79de-332f-9e25-8112c735bf13.png)

ゲストOSにファイル転送
~~~
C:\Users\inu>scp -r C:\Users\inu\Downloads\elasticsearch-8.12.2-linux-x86_64.tar.gz neko@192.168.56.101:/home/neko/kyoyu
~~~

### ゲストOSで行う
ダウンロードしたファイルのあるフォルダに移動
~~~
[neko@localhost ~]$ cd /home/neko/kyoyu
~~~
解凍
~~~
[neko@localhost kyoyu]$ tar -xzf elasticsearch-8.12.2-linux-x86_64.tar.gz
~~~
解凍できていることを確認
~~~
[neko@localhost kyoyu]$ ls 
elasticsearch-8.12.2  elasticsearch-8.12.2-linux-x86_64.tar.gz
~~~
解凍したフォルダに移動
~~~
[neko@localhost kyoyu]$ cd elasticsearch-8.12.2
~~~
elasticsearch.ymlを修正
~~~
[neko@localhost elasticsearch-8.12.2]$ sudo vi config/elasticsearch.yml
~~~
xpack.security.enabled:__`false`__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664791/e27d7049-0219-1e15-5b0c-333cc172c776.png)

実行
~~~
[neko@localhost elasticsearch-8.12.2]$ ./bin/elasticsearch
~~~

※初回実行時のみセキュリティ構成情報が表示されるので控えておく。

ブラウザからアクセスする
http://localhost:9200　
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664791/cf0e429d-25e0-e6b1-e6d6-0a889278a0e3.png)

`Ctrl＋C`で終了


※初回実行時に表示されたパスワードは環境変数に保存しておく
~~~
[neko@localhost elasticsearch-8.12.2]$ export ELASTIC_PASSWORD="パスワード"
~~~



参考
https://www.elastic.co/guide/en/elasticsearch/reference/current/targz.html
IntuneでWindows PCを雑に管理する

えるしってるか、[ユーザーグループはユーザーグループ同士、デバイスグループはデバイスグループ同士でしか判定ができん](https://learn.microsoft.com/ja-jp/mem/intune/configuration/device-profile-assign#exclude-groups-from-a-profile-assignment)のじゃ…

というわけで、「ユーザーグループ」で管理してうまくいかなくなりがちなWindows PC、「[動的デバイスグループ](https://learn.microsoft.com/ja-jp/azure/active-directory/enterprise-users/groups-dynamic-membership#rules-for-devices)」でサクッと管理しましょう

　

なんと、以下の静的クエリを設定した動的デバイスのセキュリティグループを作るだけです

### 1. Intune登録済のWindows PCのグループ

※`Microsoft Entra joined` (`Azure AD joined`)、会社所有も条件としています

```Ruby:Dynamic devices membership rule
(device.deviceManagementAppId -eq "0000000a-0000-0000-c000-000000000000") and (device.deviceTrustType -eq "AzureAD") and (device.deviceOwnership -eq "Company") and (device.deviceOSType -eq "Windows")
```

### 2. Windows 11 のグループ

※Ver.は実は11ではなく、`10.0.2xxxx.xxxx`です

```Ruby:Dynamic devices membership rule
(device.deviceOSVersion -startsWith "10.0.2") and (device.deviceOSType -eq "Windows")
```

### 3. Windows 10 のグループ
※ここまで書かないと、10と11両方になってしまいますよ、よよよ…

```Ruby:Dynamic devices membership rule
(device.deviceOSVersion -startsWith "10.0.1") and (device.deviceOSType -eq "Windows")
```

### (おまけ) Windows Autopilotのグループ　※使ってる場合

```Ruby:Dynamic devices membership rule
(device.devicePhysicalIDs -any (_ -contains "[ZTDID]"))
```

これだけであら不思議、大抵の組み合わせには事欠かないという…

　

例えば、「コンプライアンスポリシー」や「Windows Updateポリシー」でOSバージョンの判定をしたい場合

- 1.を対象にする
- 2.または 3. を除外対象にする

こうすると、例えば『[Win11 23H2](https://learn.microsoft.com/ja-jp/windows/release-health/windows11-release-information)』と『[Win10 22H2](https://learn.microsoft.com/ja-jp/windows/release-health/release-information)』のような組み合わせでのポリシー準拠判定も楽ちんですね！
（※当然OSごとにポリシーを作る必要はありますが、「Win11のバージョンポリシーにWin10PCが違反する」みたいな初歩的なミスは簡単に防げます）

なお注意点として、デバイスグループは「条件付きアクセスポリシー」の管理には使えません（ユーザーグループ）。
まぁ、マネージドデバイス用のフィルターを作るうえでは参考になる点もあると思いますので、その辺はよろしくやって、どうぞ

　

ちなみに、こちらは「`Intune Managed` + `Entra joined`」での管理をベースにしております。
BYOD や `Entra resistered` の端末を合わせて管理する場合は、もうちょっと複雑になってきます（Win以上にスマホがだるい←）が、それはまた、別のお話…
Gmailの例の件のメモ

以下に関連して、やるべきことのまとめ

https://support.google.com/a/answer/81126?hl=ja

1. [メールドメインの一覧を用意する](#1-メールドメインの一覧を用意する)
2. [SPFレコードのチェック](#2-SPFレコードのチェック)
3. [DMARCのチェック](#3-DMARCのチェック)
4. [DKIMのチェック](#4-DKIMのチェック)
5. [最後に](#5-最後に)

# 1. メールドメインの一覧を用意する

MXレコードを登録してるドメインは、**サブドメインも含めて**一通り要チェックや！サブドメインもちゃんと見ましょう、マジで。

とは言うものの、メールサービスによってサブドメインやエイリアスドメインの実装が異なる場合もありますので、そもそも論として「大量のメール送信をするのに、メインドメイン以外を使うな」が安定だと思われます。

# 2. SPFレコードのチェック

各メールドメインのTXTレコードに以下のような行が存在して、そのドメインを利用しているメールサービスが網羅されていること

```Ruby:TXTレコード
"v=spf1 include:_spf.google.com include:spf.protection.outlook.com ~all"
```

よく使いそうなメールサービスはこの辺かな（その他は自分で調べて←）

>* [Gmail](https://support.google.com/a/answer/33786?hl=ja)：　`include:_spf.google.com`
>* [Exchange Online](https://learn.microsoft.com/ja-jp/microsoft-365/security/office-365-security/email-authentication-spf-configure?view=o365-worldwide)：　`include:spf.protection.outlook.com`
>* [Amazon SES](https://docs.aws.amazon.com/ja_jp/ses/latest/dg/send-email-authentication-spf.html)：　`include:amazonses.com`
>* WP Mail SMTP：　ホストしてるサーバーの[IPアドレス](https://salt.iajapan.org/wpmu/anti_spam/admin/operation/information/spf_i01/)など

最低限は上記があれば一旦はOK。`rua`とかは居ても居なくても

# 3. DMARCのチェック

**各ドメインのサブドメイン『_dmarc』のTXTレコード**を見る。`contoso.com` の場合は、 `_dmarc.contoso.com` を見て、最低限以下が存在するか

```Ruby:TXTレコード
"v=DMARC1; p=none;"
```
最低限は上記があれば一旦はOK。ruaとかは居ても居なくても

# 4. DKIMのチェック
各ドメインのdomainkeyのレコードをチェックして、無ければ設定する。（設定手順は各サービスの手順を見て）

### (1) Google Workspace (Gmail)
`google._domainkey.contoso.com` に以下のTXTレコードが居ること
（※『`p=～`』はテナントごとに異なる）

```Ruby:TXTレコード
"v=DKIM1; k=rsa; p=～"
```

居ない場合は、[GWSの管理コンソール](https://admin.google.com/ac/apps/gmail/authenticateemail)で生成したレコードをDNSにぶち込む

https://support.google.com/a/answer/180504?hl=ja

2048 bit が入らなかったら 1024 bit でもOK。それすら入らない（某×serverとか）場合はDNSを乗り換えるべし（[Cloudflare DNS](https://www.cloudflare.com/ja-jp/application-services/products/dns/)がオススメ）

### (2) Microsoft 365 (Exchange Online)
`******._domainkey.contoso.com` に以下のTXTレコードが居ること
（※`******`はテナント毎に可変）

```Ruby:TXTレコード
"v=DKIM1; p=～"
```
居ない場合は、以下の手順を参考に生成したレコードをDNSにぶち込む

https://learn.microsoft.com/ja-jp/microsoft-365/security/office-365-security/email-authentication-dkim-configure?view=o365-worldwide

# 5. 最後に

チェックツールとかでチェックすべし（以下は一例）
（**※TTL値によっては反映まで時間がかかるので注意**）

* [Google Message Header](https://toolbox.googleapps.com/apps/messageheader/)
    * 当該ドメインから送信したメールヘッダをチェックします
    * MAツールやメールフォームを用いている場合、実際にそちらから送信したメールでチェックしましょう
* [Check MX](https://toolbox.googleapps.com/apps/checkmx/)
    * 基本はGmail用のチェックツールなので、それ以外では一部利用不可の機能有
    * DNSによっては非対応の場合もありそう…

　

あとはよしなに！

なんか設定できないのがあったら、今後のことも考えてメールサービスやDNSの乗り換えも含めて検討すべし
ローカル環境で大量のHEIF形式（HEIC形式）の画像をJPEG形式に一括変換する方法（職場環境編）

# 概要
画像ビュワーのIrfanViewを使い、Windows10のローカル環境で画像の形式をHEICからJPEGに変換できるようにする。ただし、ソフトウェアのインストールなどに一部制限のある職場環境で行う。


# 背景
大量のHEIC画像をJPEG形式に変換したいが、私の職場環境では次のような制約がある。

:::note alert
**職場での制約**
- Microsoft Store経由でのインストールはできない
- 勝手に有料ソフトウェアに課金できない
- オンラインの変換ツールは使用できない（情報漏洩防止の観点から）
:::

そこで、オフラインで動作するフリーソフトのみを使用し、変換できる環境を構築する。

**今回登場する用語メモ**
- IrfanView: 有名なフリーの画像ビュワー
- HEIC: HEIF形式の画像の拡張子（圧縮率が高くiOSで標準に設定されている）


# 方法
## ゴールの確認
:::note info
**ゴール**
- IrfanViewでHEIC画像を表示できるようにする
:::

前提として、WindowsにIrfanViewをインストールしただけの環境では、そもそもWindows標準の画像ビュワーでもHEIC画像を表示することができない。もちろんIrfanViewでもHEICファイルを表示することができない。逆に、IrfanViewで表示できるようになれば、そのときは変換もできるようである。そのため、IrfanViewでHEIC画像を表示するというのが実質のゴールになる。

## 手順
1. IrfanViewをインストールする
2. コーデックをインストールする
3. HEIC画像を開いて確認する

### 1. IrfanViewをインストールする
公式サイトへアクセスし、インストーラをダウンロードする。

https://www.irfanview.com/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587871/1164b25f-2c67-d13a-ab56-513e8ec523d9.png)

## 2. コーデックをインストールする
公式サイトのFAQを見ると、方法が3種類あると書かれている。

> Q: How to load  HEIC files in IrfanView?
> A: You must install the HEVC extension/codec. 
>      1) If you have Windows 10/11, you can install it from Microsoft Store:
>      You need to install 2 (!!) extensions from Microsoft Store: HEVC Video Extensions from Device Manufacturer  AND  HEIF Image Extensions. 
>      or
>      2) Download and install the HEIC Codec, version 1.0.1 and later (Freeware, for Win7/Win8/Win10/Win11).
>      HEIC Codec
>      or
>      3) Search on internet for the "CopyTrans HEIC" Windows codec and install it (Free for personal use, for Win7/Win8/Win10/Win11).
>      CopyTrans HEIC Codec

https://www.irfanview.com/faq.htm#:~:text=Q%3A%C2%A0How%20to%20load%20%C2%A0HEIC%20files%20in%20IrfanView%3F

1番の方法はMicrosoft Storeを使うということで、今回は適していない。3番の方法は、別の画像ビュワーをインストールする方法で、余計なソフトが入るのでできれば避けたい。ということで、今回は2番の方法を試す。

リンク先にアクセスし、「wic_heic-v1.0.3.zip」をダウンロードする。

https://github.com/prsyahmi/wic_heic/releases/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587871/e5644ce5-4f58-1662-8e66-eee5241d6e26.png)

ダウンロードしたファイルを解凍し、「x64」フォルダ内の「_install.bat」を管理者権限で実行する（職場によっては許可が必要かもしれない）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587871/b5597867-1c1f-a535-c021-c43be224efa9.png)

これでコーデックのインストールは完了である。


## 3. HEIC画像を開いて確認する
最後に、画像を開いて変換できることを確認する。

IrfanViewを起動し、「File > Open」から画像を選択する。ファイルの種類で、「All files」か「HEIC/AVIF」を選んでおかないと表示されないため注意する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587871/5382b8c5-0d0b-5845-d182-c47d254babbb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587871/5e9a7231-65af-3102-111a-ab4b4ee0470d.png)

ファイルが正しく開けていることを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587871/665c5f75-d15d-08dc-b666-6fb273e0503b.png)

あとは、「File > Save As」でファイルの種類を「JPG」にして保存すれば、変換完了である。もちろんバッチ処理による一括変換もできる。

# あとがき
いくつかの制約がある職場で、画像を変換する環境が構築できた。

念のため、この内容は私が所属している組織が発信するものではなく、個人の表現として発信するものです。

なお、今回使用したソフトウェアのバージョンは次のとおりである。
- OS: Windows 11
- IrfanView: v4.66
- HEIC Codec: v1.0.3

# 参考

https://forest.watch.impress.co.jp/docs/news/1158690.html
gcc の簡単な更新方法

# なぜ更新しようと思ったか
競プロ(Atcoder)の環境はgcc12.2である。
しかし自分の環境はmingw installation managerで構築した古い環境であり、使える標準ライブラリが一致せず不便なため。

# 環境・日時
Windows 11・2024/03/14

# 更新した方法
1. [ダウンロード](https://www.mingw-w64.org/downloads/)に行く
1. Mingw-buildsのGitHubをクリック
1. Release of 12.2.0-rt_v10-rev2をクリック
1. x86_64-12.2.0-release-win32-seh-ucrt-rt_v10-rev2.7zをダウンロード
1. 7-zipで解凍する
1. 解凍して出てきたmingw64をCドライブのprogram Filesに移動させる
1. 用意した /mingw64/bin を環境変数に設定する

# vscode上の設定
1. ctrl + shift + p を押して"C/C++ Edit Configuration UI"を選択
1. 以下の項目を変更
    - コンパイラパス: bin内のgccのパスを設定
    - c++ 標準: C++20にする
Raspberry Piで.bashrcに正しくパスが指定されているのに反映されない問題

## 概要
- .bashrcには正しく設定されているにもかかわらず、反映されていない場合の覚書

## 対処法
```sh
source ~/.bashrc
```

## テラタームで接続しなおすと再度設定しなおさなければならない問題の対処法
```sh
# これに追記することでログイン時に読み込まれるようになる
nano ~/.bash_profile
```

```~/.bash_profile
# 最後の行に追記する
source ~/.bashrc
```


## 参考サイト
https://qiita.com/SamAkada/items/5798c758b1b23d2403b6
Linuxで定期実行する方法【crontab】

## 概要
- crontabの設定方法を忘れてしまうので、簡単にまとめる

## 設定方法
```bash
# 設定ファイルを開く
crontab -e
```

## 設定方法
```/tmp/crontab.lb4eVp/crontab
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').
#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h  dom mon dow   command

# 時間の指定　繰り返し間隔　実行コマンド
00 20 * * * /home/pochi/.nvm/versions/node/v20.11.1/bin/node /home/pochi/program/notify_rakuten_card_usage_stable-0.1.0/dist/App/Adapter/Cli/FetchRakutenCardTransactions.js
00 00 * * * /home/pochi/.nvm/versions/node/v20.11.1/bin/node /home/pochi/program/notify_rakuten_card_usage_stable-0.1.0/dist/App/Adapter/Cli/FetchRakutenCardTransactions.js

19 00 * * * /home/pochi/.nvm/versions/node/v20.11.1/bin/node /home/pochi/program/notify_rakuten_card_usage_stable-0.1.0/dist/App/Adapter/Cli/FetchRakutenCardTransactions.js
```

今回は、nodeのパスと、実行したいファイルの絶対パスを指定して実行した

## ログの確認方法
```bash
# ラズパイOSではどちらかで取得可能
journalctl | grep CRON
journalctl -u cron.service
```
ほかの環境では試せていないが、ほかにもログに関しては取り方がいっぱいありそうであった、、
20240313の日記（git diffで"terminal is not fully funcitioal"というエラー、仮想環境重すぎ）

### Powershellでgit diffしたらnot fully functionalとか言われた
こんなやつ
```
> git diff .\runTool.py
WARNING: terminal is not fully functional
Press RETURN to continue
```

TERMの設定がいまひとつだと出る
[Why does git diff on Windows warn that the "terminal is not fully functional"? - Stack Overflow](https://stackoverflow.com/questions/7949956/why-does-git-diff-on-windows-warn-that-the-terminal-is-not-fully-functional)
PowershellをAlacrittyで使ってるのでTERMをみるとalacrittyと表示される
```
echo $ENV:TERM
alacritty
```
なので$PROFILEのなかで
```
$ENV:TERM="xterm-256color"
```
とすると解決

### 仮想環境のWindowsでラロワ動かすと重すぎる

100件のデッキデータ取得にホスト機ではだいたい1000秒ほどで終わる
だから、えーと、17分ほど？

→ 仮想環境では1件につき3分くらいかかる
→ 100件で300分かかる
→ 5時間？！

これは使えない
Dockerコンテナで動かすことを考えよう

Windows上でWindowsコンテナを動かすとホスト同じくらい速いはず、、、？？
DirectXを使っているので基本的にはWindowsでしか動かないんだけど、なかにはArchLinuxでDirectX使えるようにしてFF14やっている猛者もいるからできるんじゃないか、と思ってる
けど、かなり沼りそうだからしばらく仮想環境であれこれはやめておこう

[FF14をArchLinuxで動かす(DirectX11対応) | Arch使いの日記](https://blog.grainrigi.net/post/ff14-on-linux/)
物件の細かいスペック情報を入力できるサービスを作ってみた

# 作ったもの

## スクリーンショット
![スクリーンショット 2024-03-13 19.08.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201010/c8ad3812-64b4-0469-1dd4-ce792bd495c3.png)
![placeof-app-dashboard-places-cltcvtfo600006v77zjybp5ad-features.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201010/6e7fa398-4093-f467-f5e7-bb38c8c46dab.png)
![A-life-in-Gallaratese (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201010/7984dfd2-6138-3b18-7bd9-3d1744734f33.png)
https://www.placeof.app/places/cltcvtfo600006v77zjybp5ad


## 出来ること

- 物件保有者は「スペック情報」「特徴」「関与したクリエイター」などの細かい情報を入力できます。また、その物件に関する「日々の投稿」をすることもできます
- その物件に興味を持った人は、「waiting list」に登録することができます
- 「waiting list」に登録すると、物件保有者と「チャット」ができます

# 技術構成
## Next.js
全体的に使いやすいのでNext.jsにしました。とはいえ、このサービスには多種多様なフォームがありますが、Server Actionsはそこまで使っていません([contactページ](https://www.placeof.app/contact)では使ってます)。[Intercept Routes](https://nextjs.org/docs/app/building-your-application/routing/intercepting-routes)は少し挙動が不安定な気がしますが、ひとまず使っています。今後に不安がないか、と言われれば何とも言えません。
## PlanetScale/Prisma
これまではFirestoreを使っていましたが、機能が増えると「集計機能」「クライアントジョイン」周りがボトルネックになりやすいと感じ、SQLにもどってきました。ちょうど、水平スケール出来るMySQLであるPlanetScaleがあり、ピッタリでした。deploy requestをしてマイグレーションをする方式も違和感なく使えています。PrismaとDrizzleで迷いましたが、開発を始めた段階でPrismaの方が情報量が多く、出来ることもそこまで変わらないと感じ、Prismaにしてます。
## Vercel 
Cloud Runでリリースする予定だったのですが、Vercelが想像以上に使いやすくこのまましばらくは使い続ける気がします。Vercelの環境設定画面も、スペックを動的に追加する画面の参考になりました。

# 主なポイント
## スペックを動的に追加する画面

「スペック名のサジェスト機能」をshadcnの[Combobox](https://ui.shadcn.com/docs/components/combobox)を使って実装しました。こちらの[issue](https://github.com/shadcn-ui/ui/issues/173)が参考になりました。
また、「[C値]のときは、値の入力欄は[数字]」「[キッチンのブランド]のときは、値の入力欄は[文字列]」のようにしたく、[Zod](https://zod.dev/)のsuperRefineを使って実装しています。



## 地図

地図は、[Mapbox](https://www.mapbox.jp/)を使っています。その物件の郵便番号の中心点から半径数キロの円を描画し、大体この辺だよというのが伝われば良いかなと思いました。また、物件登録時に郵便番号で住所も自動入力した方が良いと思いました。
とはいえ、データを用意するのが意外に難しかったです。結局、[GeoNames](https://www.geonames.org/)のデータを使わせて頂くことにしました。精度はともかくほぼ全ての国に対応可能なようです。

ハザードマップなり国土地理院のベクトルタイルなりPlateauなりいろいろな不動産データを追加することも考えましたが、[全世界のいろいろなサイトを調べて](https://note.com/waitliststuff/n/n80573060fdf9)、ひとまずシンプルで良いかなと感じています。

## i18n

Next.jsのi18n機能はURLが変更され、ディレクトリ構造も変わるため、react-i18nextでi18n機能を作りました。こちらの記事を参考に
https://zenn.dev/k0kishima/articles/956ba3f3dc9629
client sideとserver sideで使っています。[Zodとの連携](https://github.com/aiji42/zod-i18n)もしています。

なお、距離や面積の単位も国ごとに違うので、MySQLではメートルで保持し、見る方の国によって表示を変えています。

# TODO
- 関与したクリエイター周りの動的フォームをしっかり作る
- 「潜在的な買い手や借り手とつながる」世界観をより強く打ち出す機能の開発

# まとめ
是非物件を登録してみてください

https://placeof.app/places/new


# 参考にしたサイト
https://qiita.com/tak001/items/cfbaa9dcb542929ff235
https://zenn.dev/aiji42/articles/171f26af4e5b5c
【JavaScript】fetchで指定した回数リトライする方法

以下のように記述すると指定した回数リトライします。

```js
const fetchWithRetry = async (url, options, n) => {
  try {
    return await fetch(url, options)
  } catch (err) {
    if (n === 1) throw err
    return await fetchWithRetry(url, options, n - 1)
  }
}

fetchWithRetry("http://localhost/sample", {}, 5)
  .then(res => {
    console.log("Success:")
  })
  .catch(err => {
    console.log("Error:", err.message)
  })
```
令和最新版 GitHub Actions 自動草生やし

![w.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243093/f2914971-5908-86a2-35b2-43d5d412bdb0.png)

一日一回 感謝の草生やし

# リポジトリ作成
偽りの草を生やす為、適当なリポジトリを作成する。
その際 `Add a README file` をチェックして、README ファイルも作成する。

以降の手順で README ファイルへの変更を自動化する。

# シークレット登録
作成したリポジトリ内の **Settings** > **Secrets and variables** > **Actions**

**New repository secret** をクリックする。

- **Name** `USER_NAME`
  - **Secret** GitHub のアカウント名
- **Name** `USER_EMAIL`
  - **Secret** GitHub アカウントに紐づけたメールアドレス または GitHub が提供している noreply メールアドレス

上記の内容でそれぞれ登録する。

# 書き込み権限の付与
作成したリポジトリ内の **Settings** > **Actions** > **General**

**Workflow permissions** 内
**Read repository contents and packages permissions** が選択されている場合は
**Read and write permissions** へ変更して **Save** をクリックする。

# 秘伝の YAML
作成したリポジトリ内の **Actions** > **set up a workflow yourself** をクリックする。

```yaml:.github/workflows/main.yml
name: auto grow grass

on:
  workflow_dispatch:
  schedule:
    - cron: 0 0 * * *

jobs:
  auto-grow-grass:
    permissions:
      contents: write
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: auto push
        run: | 
          echo "w" >> README.md
          git config --local user.name ${{ secrets.USER_NAME }}
          git config --local user.email ${{ secrets.USER_EMAIL }}
          git add .
          git commit -m "w"
          git push -u origin main
```

上記をコピペ後 **Commit changes...** > **Commit changes** をクリックして反映する。

# 試運転
作成したリポジトリ内 **Actions** > Workflows 内 **auto grow grass** > **Run workflow** を
実行する。
緑のチェックマーク（成功）で草が生えていることを確認する。

以降、毎日だいたい朝十時頃に草が生える。
Flask初心者

# Flask
　pythonでwebアプリをつくるためにFlaskを調査しました。  
   [公式docs](https://flask.palletsprojects.com/en/3.0.x/)

# 仮想環境の構築
　最初に作成したいフォルダに仮想環境を構築します。
```
$ python -m venv venv
```
　起動方法
```
$ venv\Scripts\activat
```
　終了方法
```
$ deactivate
```

# Flaskのインストール
```
$ pip install Flask
```

# その他のライブラリインストール
　エラーが発生したので追加しました。
```
$ pip install arrow
$ pip install ipython
$ pip install ipywidgets
$ pip install psutil 
$ pip install pyarrow
```

# Hello World アプリケーション
　ファイル名はhello.py。flask.pyはエラーになるので使用禁止。

```hello.py
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "<p>Hello, World!</p>"
```

やっていること
1. 最初にFlaskクラスをimport。このクラスのインスタンスはWSGI（Web Server Gateway Interface）アプリケーションです。
2. 次に、Flaskクラスのインスタンスを作成します。最初の引数はアプリケーションのモジュールまたはパッケージの名前で、__name__がショートカットとして機能します。これはテンプレート、静的ファイルなどのリソースを探す場所をFlaskが知るために必要になります。
3. それからroute()デコレータを使って、どのURLが関数のトリガーかをFlaskに伝えます。
4. その関数はユーザのブラウザで表示したいメッセージを返します。標準のコンテント・タイプはHTMLです。

# Flaskの起動
　公式docsにはflaskコマンドが記載してありますが、環境変数の設定が不明だったのでpythonコマンドで起動。hello.pyを起動します。
```
$ python -m flask --app hello run
```
　デバッグモードだと、サーバー起動しながら編集できます。  
　ブラウザの更新ボタンで反映されます。
```
$ python -m flask --app hello --debug run
```

# ブラウザ表示
　`http://127.0.0.1:5000/`でブラウザ表示されます。  
　サーバー停止は`crtl+c`です。
Laravel OctaneをDockerで動かす

### Laravel Octane

Laravel Octaneは、アプリケーションの起動後全ての処理をメモリ上にロードした状態を維持しリクエスト間で使い回すことによって、高速なアプリケーションを提供するツールです。

SwooleやOpenSwooleなどを使った非同期処理のアプリケーションサーバーに載せることができます。またApacheやNginx不要でWebサーバーを建てることができます。

https://readouble.com/laravel/9.x/ja/octane.html

そこで今回はこの「Laravel Octane」をDockerで動かしてみました。

### やってみる

ディレクトリ構成
```
├── octane-server
│   ├── app
│   ├── bootstrap
│   ...
│    
└── Dockerfile
```

とりあえず公式の手順に従ってLaravelのプロジェクトを作成します。

```shell
$ composer create-project laravel/laravel octane-server
$ cd octane-server
```
次に[Laravel Octane](https://readouble.com/laravel/10.x/ja/octane.html)のインストール手順に従いcomposerにoctaneを追加します。

```
$composer require laravel/octane
```



（実際にはローカルでも試しましたが）Dockerfileをこんな感じで書きました。

```Dockerfile
FROM php:8.3

RUN apt-get update

RUN pecl install swoole && docker-php-ext-enable swoole

COPY ./octane-server /app

WORKDIR /app

ENV COMPOSER_ALLOW_SUPERUSER=1

COPY --from=composer /usr/bin/composer /usr/bin/composer
RUN composer install

RUN php artisan octane:install --server=swoole

RUN docker-php-ext-install pcntl

ENTRYPOINT [ "php", "artisan", "octane:start", "--host", "0.0.0.0"]
```

1.`RUN pecl install swoole && docker-php-ext-enable swoole`

Laravel Octaneは[FrankenPHP](https://frankenphp.dev/), [Swoole](https://www.php.net/manual/en/book.swoole.php), [OpenSwoole](https://openswoole.com/), RoadRunnerからWebサーバーを選択できます。今回は、たまたまSwooleの本を読んでいたのでSwooleにしました。

SwooleはPHPのPECL拡張なので、インストールと有効化を済ませる必要があります。
[PHP official image](https://hub.docker.com/_/php)を使用したので、提供されるコマンドで有効化します。

2.`RUN php artisan octane:install --server=swoole`

オプションでswooleを指定します。

3.`RUN docker-php-ext-install pcntl`

pctnlはPHPのプロセス制御を行う機能で非同期処理の実行に必要なようです。

https://www.php.net/manual/ja/pcntl.installation.php

4.`ENTRYPOINT [ "php", "artisan", "octane:start", "--host", "0.0.0.0"]`

ENTRYPOINTでサーバーを立ち上げます。Octaneはデフォルトではport8000でサーバーを起動します。ホストは0.0.0.0を指定しないとアクセスできません。

https://zenn.dev/shake_sanma/articles/1c6475ba73da48

ビルドして立ち上げ、`http://127.0.0.1:8000`にアクセスしLaravelの画面が開けると成功です :clap: 


```shell
$ docker build . -t octane-server
$ docker run -p 8000:8000 octane-server

   INFO  Server running…

  Local: http://0.0.0.0:8000 

  Press Ctrl+C to stop the server

  200    GET / .............................................. 21.26 mb 36.45 ms

```

![スクリーンショット 2024-03-13 23.12.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584114/c596ce3d-fddf-2991-840b-cca0cd23465b.png)

### さいごに

> Laravel Octaneは、アプリケーションの起動後全ての処理をメモリ上にロードした状態を> 維持し、リクエスト間で使い回すことによって高速なアプリケーションを提供するツールです。

このような仕組みの関係上、実装上注意する点もありそう([依存注入とOctane](https://readouble.com/laravel/9.x/ja/octane.html))だったり、情報がまだ乏しいのは欠点ですが、Laravelで超高速なサーバーを構築できるのは魅力的だと思いました。

### 参考資料

以下の記事や書籍を参考にさせていただきました。ありがとうございます。

https://speakerdeck.com/sadnessojisan/sahatohahe-kawoli-jie-site-kontena1tuteshi-xing-siyou-phperkaigi2024

https://qiita.com/hiroaki-u/items/f2455d62f8a4017663cb

https://qiita.com/kamihork/items/296ee689a8d48c2bebcd

[Swooleで学ぶPHP非同期処理　～並行処理／並列処理の基礎から実践的な開発手法まで一気にわかる](https://www.amazon.co.jp/dp/429713358X)

https://developers.cyberagent.co.jp/blog/archives/35832/
Vue.js でPHPの連想配列を出力するときのたった一つのコツ

# はじめに
.phpファイル上でVue.jsを動かしていて、ブラウザ上でのアクションに合わせてPHPの変数を出力したくなり、はてどうやるんだ？と調べた結果、うまくいったものを紹介します。

# 問題
筆者の環境
・CDNでVue.jsを導入
・PHPファイルで、HTMLを記述
・Vue.jsのv-forディレクティブで、PHPの連想配列を出力したくなった

# 解決方法
PHP標準の、json_encode関数を用いることです。
PHPの連想配列そのままでは、Vue.jsで出力することができません。
実例
```index.php

<?php $dataArray = array(
  array(
    "id" => 1,
    "name" => 'John'
    "age" => '15'
  ),
  array(
    "id" => 2,
    "name" => 'Mary'
    "age" => '15'
  ),
  array(
    "id" => 3,
    "name" => 'Tom'
    "age" => '16'
  ),
  
);
?>

<!DOCTYPE html>
<html>
<head>
 <!-- Vue.jsをCDNで読み込み -->
</head>
<body>
<div id="app">
    <ul class="list" v-for="(data,index) in dataArray :key=index">
        <li>{{ data.id }}</li>
        <li>{{ data.name }}</li>
        <li>{{ data.age }}</li>
    </ul>
</div>


<script>
const app = Vue.createApp({
  data() {
    return {
      // json_encode()を用いて、PHPの配列をJSON形式に変更する
      dataArray: <?php echo json_encode($dataArray); ?> 
      // ↓ダメな例。値が出力されない。Chromeのdevモードで見ると、Arrayとだけ出力される↓
      // dataArray: <?php echo $dataArray; ?> 
      
    }
  },
})

app.mount('#app')


</script>
</body>
</html>


```

# おわりに
echoでいけるんや、ふーん余裕やん:yum:と思ってから、JSON形式にする手順に気付かずしばらく悪戦苦闘しました。
知ってしまえばなんてことはない話ですが、誰かの助けになれば幸いです。
IntelliJ の CheckStyle-IDEA Plugin で、Checkstyle v8 系の対応が削除されました

IntelliJ の CheckStyle-IDEA Plugin ですが、 **2024/03/10 にリリースされた v5.88.0 で Checkstyle v8 系の対応が削除されました。**

> 5.88.0: Breaking: Drop support for Checkstyle 8, to reduce archive size.
> [Release 5.88.0 · jshiell/checkstyle-idea](https://github.com/jshiell/checkstyle-idea/releases/tag/5.88.0)

![checkstyle.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205989/218045b2-d7e2-aa39-6d81-c83ecc7da2ab.png)

現在、設定で選べる Checkstyle のバージョンが v9.0.1 〜 v10.14.0 になっています。
ただ、Checkstyle はプロパティの入れ替えが結構多いので、バージョンが変わるとこんなエラーが出たりします。

> Checkstyle-Plugin: cannot initialize module TreeWalker - cannot initialize module JavadocMethod - Property 'allowUndeclaredRTE' does not exist, please check the documentation
> Checkstyle-Plugin: cannot initialize module TreeWalker - cannot initialize module JavadocMethod - Property 'scope' does not exist, please check the documentation

そのため、エラーメッセージをもとに `checkstyle.xml` の設定を修正する必要があります。

```diff
 <module name="JavadocMethod">
-    <property name="scope" value="public"/>
+    <property name="accessModifiers" value="public"/>
 </module>
```

もしくは、最新の [google_checks.xml](https://github.com/checkstyle/checkstyle/blob/master/src/main/resources/google_checks.xml) を持ってきてもいいかもしれません。

ただ、困ったことにIntelliJ でエラーが出ないように `checkstyle.xml` を直すと、今度は Gradle でエラーになります。
これは Gradle の Checkstyle Plugin が使うバージョンは [v8.3.7](https://github.com/gradle/gradle/blob/5ec3f672ed600a86280be490395d70b7bc634862/subprojects/docs/src/snippets/dependencyManagement/catalogs-settings/groovy/settings.gradle#L48) になっているためです。

そのため、IntelliJ で設定したのと同じバージョンの Checkstyle が使われるように `build.gradle` に設定を追加する必要があります。

```gradle
checkstyle {
    toolVersion = '9.0.1'
}
```


# 参考

* [checkstyle – Checks](https://checkstyle.sourceforge.io/checks.html)
* [JavadocMethodCheck: swap scope to access modifiers · Issue #7417 · checkstyle/checkstyle](https://github.com/checkstyle/checkstyle/issues/7417)
* [GradleでCheckStyleを利用する](https://zenn.dev/takasasa/articles/d0d9a1a3417cb0#checkstyle%E3%81%AE%E6%9C%80%E6%96%B0%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E3%82%92%E4%BD%BF%E3%81%86%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B)
本当に恐ろしいサクラのレンタルサーバー

本当に恐ろしいサクラのレンタルサーバー

レンタルサーバーの選択は、技術者にとって重要なノウハウの被ちつだと考えます。
qiitaは如何様にも理由をつけて記事の削除をするでしょう。

https://www.sakura.ad.jp/corporate/information/announcements/2019/12/27/1968202441/
真っ赤な嘘です。

今だに謝罪も報告もありません。それどころかサクラの言動の99.９９％は誤魔化し、責任転嫁、隠蔽に特化したものでした。如何に責任逃れするかにサクラの労力の99.９９％がつぎ込まれているように感じました。

何年もデタラメな言い訳が繰り返され、徒に引伸が行われています。
連絡先を聞いても言えないと言うことで、サポートにも何度も何度も連絡しても何もできない復旧には協力できないなぜなら、田中さんが決めてるのでどうしようもないと言うことでした。

こちらは、自分の作ったシステムを壊されて、復旧のためにはサクラの協力が必須なので
我慢に我慢を重ねていますが、田中さんの行なっていることは、復旧してほしいこちらの
弱みに漬け込んだデタラメな言動のくりかえしでした。その挙句にいきなり連絡拒否です。

言い逃れ、誤魔化しきれなくなったのでしょう。

びっくりするような妄言、暴言
本当に怖いレンタルサーバであるとしか言えません。

大事なシステムをサクラで運用して本当に後悔しています。

田中さんは、自分が逆の立場だったらニヤニヤしていられますでしょうか？

Qiitaとも仲良しで、国に関わる仕事もされていて素晴らしい方です。
何を書いても、サクラの力があれば圧力をかけることも消す事も可能でしょう
Åしかし、隠蔽や責任逃れに使う１％の力で復旧も可能なはずです。

経緯の報告にさえもに何年もかかるって異常ですよ。今だに報告ないですが。
さくらには自分のミスは絶対認められない方針があるのでしょうか？

サクラが本当に誠実な対応をした場合には、報告を書きます。
それがないと言うことは、出鱈目な対応が続いていることになります。

↓真っ赤な嘘でした。
今後につきましては、記事を書かれたと思われるお客さまと誠実に対話を進めていくとともに、ご安心・ご満足いただけるサービスとサポートを第一に取り組んでまいります。
Cloud 9のプレビューの仕様は多分こんな感じ

Cloud 9上には、Cloud 9上で起動しているWebサーバーに外部からアクセスする機能があります。

https://docs.aws.amazon.com/cloud9/latest/user-guide/app-preview.html#app-preview-preview-app

要件に

> アプリケーションはポート 8080、8081、または 8082 を経由して HTTP プロトコルを使用して実行している。

とあるのですが、8080番ポートと8081番/8082番ポートを使用した場合の動作が異なりましたので記録しておきます。


:::note
実験した環境は、パブリックサブネットで起動したCloud 9で、セキュリティグループのインバウンドルール未設定（全拒否）状態です。
:::

## 8080番ポートでサーバー起動した場合

```
docker run -it --rm -p 8080:80 nginx
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/91315c94-ef37-4298-afe5-8fea0b14fd68.png)

この状態で、上部の`Preview`メニューの`Preview Runninng Application`をクリックします。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/bafe3710-c88b-746f-2a16-77b98f823e6d.png)

すると、IDE内でブラウザっぽいタブが開き、Webサーバーからのレスポンスが表示されます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/7721eda2-ce15-ad7b-763c-a5bb5bd9e8ca.png)

さらに、`Browser`ボタンの右側のアイコンをクリックすると、別のタブが開いてNginxの画面が表示されます。

:::note warn
別タブで開いたURLでアクセスが可能なのは、Cloud 9にアクセスしているユーザーセッションがあるブラウザのみのようです。
なので、ChromeでCloud 9にアクセスしている場合はChromeでのみアクセス可能です。
シークレットモードやFirefoxではアクセスできません。

どういう仕組みなんだろう。。
:::

## 8081番ポートでサーバー起動した場合

同じ手順を8081番ポートでやってみます。

```
docker run -it --rm -p 8081:80 nginx
```

すると、画面いっぱいの**Oops**

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/410cf3f3-7862-7578-7d57-4132f3cddd83.png)

8082番ポートを使った場合も同様です。

## 8081番ポートの使い方

色々試してわかったのですが、**ポート番号を明示的に指定すると、同じ番号のサービスに繋がる**ということがわかりました。

なので、8081番ポートで起動しているサービスに接続したい場合は、`https://aaaaaaaaaaaaaaaaaaaaaaa.vfs.cloud9.us-east-1.amazonaws.com:8081/`のように指定します。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/55f5a655-65ba-c686-5193-a73c0b6a73cc.png)

（ブラウザ部分のURLが`/`と、ドメインとポートの部分が省略されますが、8081を指定しています）

接続はHTTPS通信ですので、未指定時（=443番ポート使用時）のみ、8080に上手に転送されるようになっているようです。

まとめると

| 条件 | 接続先サービス |
| --- | --- |
| ポート番号未指定 | 8080で起動しているサービス |
| `443`を指定 | 8080で起動しているサービス |
| `8080`を指定 | 8080で起動しているサービス |
| `8081`を指定 | 8081で起動しているサービス |
| `8082`を指定 | 8082で起動しているサービス |

ちなみに、8083など、8080～8082以外のポートは全ブロックされているように思います。

## おまけ

8080～8082までの3つは自由に使えるので、以前紹介した、[Cloud 9 でVSCodeを使う](https://qiita.com/moritalous/items/e72a8c8cf75a03ca6b77)で一つポートを使っても、まだWebアプリを起動させる余裕ができます。

Cloud 9 でVSCodeを使うの実用化（？）に一歩近づきました😁

https://qiita.com/moritalous/items/e72a8c8cf75a03ca6b77


* Cloud 9でvscode Serverを8082番ポートで起動し、vscode内で8080番ポートを使用するサーバーを起動するの図

    ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/767c695e-1f54-a779-0eda-3492d92e67d5.png)
tailwindcssでGoogleFontsを使用

## はじめに
tailwindcssでGoogleFontsをNext.jsで使用するにあたり
クラス＋プロパティで書きたいので```tailwind.config.ts```ファイルに追記するも反映されなくて困った話

## 問題
今回は```courgette```の文字を追加したかったので
tailwind.config.tsにfontfamilyを追加

```tailwind.config.ts
import type { Config } from "tailwindcss";

const config: Config = {
  content: [
    "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  theme: {
    extend: {
      fontFamily: {
        'courgette': ['Courgette', 'cursive'],
      },
    },
  },
  variants: {},
  plugins: [],
};
export default config;
```
このままでは反映されず

## 解決
global.cssファイルに
`@import url('https://fonts.googleapis.com/css2family=Courgette&display=swap');`の1文を追加

```global.css
@import url('https://fonts.googleapis.com/css2?family=Courgette&display=swap');

@tailwind base;
@tailwind components;
@tailwind utilities;
```
```
<div className="font-courgette">
```

![スクリーンショット 2024-03-13 225753.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622777/12fe7792-5b25-5598-c2af-8ed24c360210.png)

反映させることが出来ました！

## 参考記事
この方の記事でimportの1文を追加するところにたどり着きました
https://zenn.dev/natonao/articles/280324541b86ba