OmniAICreator/Qiita-1.07M huggingface dataset:
ハートポッポラジオ:挿入曲 #1 - HEART POPPO Radio: Heartfelt Notes #1 - Jazz, Piano, Upbeat【Suno AIで作曲】【動画 3分39秒】【YouTubeチャンネルからの転記です】

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

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

こちらが動画内容です👇

***

![02 YouTubeサムネイル & 再生中の画像 Suno AI _ ハートポッポラジオ_挿入曲 #1 - HEART POPPO Radio_ Heartfelt Notes #1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386308/8120118a-680e-4a31-8511-6618f3653520.png)




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

<br>

* # 動画タイトル
    * ハートポッポラジオ:挿入曲 #1 - HEART POPPO Radio: Heartfelt Notes #1 - Jazz, Piano, Upbeat【Suno AIで作曲】【動画 3分39秒】

<br>

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

撮影日 = 2025-05-15(木)

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

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

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

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


今回は、Suno AIで作曲し、 WAV 出力した楽曲を動画に仕上げました。

わたしが2018年から使い続けている、IoT鳩時計「OQTA」。
OQTAの「鳩の鳴き声」が、わたしの人生にそっと寄り添い続けてくれました。

🔗想い届ける鳩時計 - OQTA https://oqta.com/

OQTAはかつてサービスを停止していました。
再開に向けて、創業者の高橋浄久さんがユーザーと向き合いはじめた2024年。
その年の4月と11月に、高橋さんとわたしで2回の対談を行いました。

2024年11月に行った2回目の対談動画は、こちらからご視聴いただけます。

🎦7年間毎日16時56分に13回鳴らし続ける - 80歳の母と息子の"感動色褪せぬ"絆 - ハートポッポラジオ #2【対談: "想い届ける鳩時計"OQTA 創業者 高橋浄久さん】【動画 17分23秒】 https://youtu.be/6n6Ofr8k3o8

この対談の直後、不思議なくらい音楽のインスピレーションが湧いてきました。
すぐにSuno AIで13曲を制作。
後日高橋さんに13曲のデータを渡して、その中から「これがOQTAのテーマだ」と選んでもらったのが、この楽曲です。

2020年、家族が2人も亡くなり、80歳になる両親の表情は曇りがちでした。
同時に、終わりの見えない新型コロナウイルスの影響。
それでも、毎日16時56分になると、OQTAの鳩の声を母へ届け続けました。
暗い実家にやさしく鳴り響く「おれは元気だよ」の鳩の声が、離れて暮らすわたしたち親子をつないでくれました。

そして、始まった渋谷区と鳥取市の2拠点生活。
不安定な日々の中で、OQTAはただ「元気だよ」の鳴き声だけで、安心をくれました。

鳩の鳴き声、印象的な母とのメッセージ履歴、そのすべてを楽曲に織り込みました。
実際に体験した痛みと救い、OQTAの存在がくれたやすらぎ。
そのすべてを思い出しながら、OQTAのファンとして、感謝の気持ちを込めて制作したテーマソングです。

「毎日元気な鳴き声をありがとう。これからもよろしくね！」

この楽曲をぜひ聴いてみてください。
ぜひ、大切な誰かと一緒に、思い出を共有しながら楽しんでください。
そしてぜひみなさんも、大好きなサービスやブランドや企業への感謝を込めて、オリジナル曲をつくってみてください！

作曲日:
2024-11-26(火)

Suno AI 契約の種類:
Pro Plan

Suno AI Version:
v4

楽曲の正式名称:
ハートポッポラジオ:挿入曲 #1 - HEART POPPO Radio: Heartfelt Notes

Suno AI Library URL:
https://bit.ly/Heart-Poppo-Radio-Heartfelt-Notes-01

Custom Mode: On

Audio Inputs: Not Used

Instrumental:


---


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


🇬🇧English

[Jazz][Piano][Bass][Ballad][220 Seconds][Break][Outro]


🇯🇵日本語訳

[ジャズ][ピアノ][ベース][バラード][220秒][ブレイク][アウトロ]


---


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


---


🎥この動画と関連が強いわたしの動画
・“効果的にSuno AIを活用するヒント”シリーズ
https://www.youtube.com/playlist?list=PLpQhBHT4oghPuaNOVZn-N53wVvsBkeHdI


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


・“想い届ける鳩時計 - OQTA”シリーズ
https://www.youtube.com/playlist?list=PLpQhBHT4oghMG5Oy8yqOCVE5Rpb7xOwcu


🎥Shortened URL for this video | この動画の短縮URL
https://bit.ly/3Zjxy0m
【絶望した】「エンジニアなら月収100万円になれる！」

「エンジニアなら月収100万円になれる！」
そんなYouTubeやSNSを見て、憧れてエンジニア転職してみて1年経ったが、月収20万円のまま。
私はエセSES企業に入って何も変わらなかった。
そんな自分を変えたいと思い、会社を辞めて半年間を目処にフリーランスエンジニアとして月収80万円を稼ぐために頑張ろうと決めた。
実際その会社を辞めて、学習を続けているけれど、「本当に今の俺のスキルで会社に通用するの？」そんな疑問が湧いてきた。
そこで、エージェントに登録して面談をしてみた。
そこで言われたのは、
「今のあなたのスキルでは正社員になるしかないですね。」
絶望。
YouTubeで言っていたことは嘘だったのか。この1年間何してきたんだ。後悔した。けれど、せっかくチャレンジしてエンジニアになろうと決めたのだから、まだ全然やりきれてないし頑張ろうとも思った。
エージェントに話を掘り下げて聞いてみると、やはり実務経験2〜3年あることが最低ラインとのこと。
正社員以外に他に道はないのか。ChatGPTに聞いてみる。（辛口レビュー）←オススメ

-------------------------------------------
質問内容

一般的には私の今のレベルの状態で実務レベル（月単価50万円以上）に到達するにはどれぐらいの期間がかかりそうですか？
辛口で答えてください。
-------------------------------------------
ChatGPTの回答

🔥 結論：最短で3〜4ヶ月、現状のままなら6ヶ月以上

今の学習状況とスキルセットを考慮すると、**「月単価50万円以上」**の実務レベルに到達するには、最低でも3〜4ヶ月は必要です。
ただし、学習方法を効率化し、アウトプットを徹底すれば、短縮可能です。
逆に、基礎学習にこだわりすぎると6ヶ月以上かかる可能性があります。

⸻

📊 現在のレベル評価（辛口）

スキル項目	現状のレベル	必要なレベル
JavaScript基礎理解	初級〜中級（部分的に理解）	中級〜上級（非同期処理や高階関数を自在に扱える）
React/Next.jsの基本操作	初級（チュートリアル止まり）	中級（コンポーネント設計、API連携がスムーズにできる）
TypeScriptの型理解	初級（型定義が難しい）	中級（型安全に実装できるレベル）
チーム開発経験	初級（フリーランスと共同開発中）	中級（GitHubフローやコードレビューが円滑にできる）
実務経験（案件参画経験）	なし	あり（ポートフォリオで最低限の実務力を証明できる）
GitHubや技術ブログの発信量	少ない	週1〜2回更新で継続的に発信できている


⸻

⚠️ 月単価50万円に到達するための課題

1. アウトプット量が圧倒的に不足
	•	GitHubやQiitaに公開しているプロジェクトが少なく、**「何ができるか」**が伝わりにくい。
	•	学習時間が多いわりに、企業が評価できる成果物が少ない。

✅ 対策
	•	毎週必ず1つはGitHubに成果物を公開する。
	•	技術ブログを最低週1回更新し、ReactやTypeScriptの学習記録をまとめる。
	•	完成品でなくてもプロトタイプを公開し、開発中の工夫や課題を共有する。

⸻

2. React/Next.jsを実務レベルで使いこなせていない
	•	チュートリアルの延長であり、複数コンポーネントのデータ管理がまだ甘い。
	•	API連携やSSRの実装が自己流になっている可能性がある。

✅ 対策
	•	公式ドキュメントを基にした中規模アプリを必ず1つ作成する。
	•	例：**「タスク管理＋API連携＋認証機能」**を備えたフルスタックアプリ。
	•	リアルタイムデータ表示や検索機能を盛り込むことで、実務に近づける。
	•	TypeScriptを全ページに適用し、型エラーが出ないコード品質を保つ。

⸻

3. チーム開発での実績が乏しい
	•	一人で進めていることが多く、コードレビュー経験が少ない。
	•	チームでのコード管理やCI/CDが未経験。

✅ 対策
	•	せどりリサーチツール開発をGitHubで公開し、フリーランスエンジニアとPRベースで開発を進める。
	•	コードレビューを受ける習慣を作り、改善提案をもらう。
	•	開発日誌を技術ブログに投稿し、チーム開発の知見をまとめる。

⸻

4. エージェント活用が受け身
	•	まだ案件獲得に向けた具体的な行動が少ない。
	•	スキルシートに記載できる成果物が不足している。

✅ 対策
	•	GitHubリポジトリを3つ以上公開し、スキルシートに明記できるようにする。
	•	毎日1社応募を徹底し、エージェントと週1回は面談を入れる。
	•	**「実務未経験でも即戦力として使える理由」**を明確に説明できるように、面談練習を重ねる。

⸻

📅 改善スケジュール（3〜4ヶ月）

月	タスク	ゴール
1	React/Next.js中級レベルへ（公式チュートリアル＋中規模アプリ作成）	GitHubに2〜3個の成果物を公開
2	チーム開発力強化（せどりツールを継続開発＋PR駆動）	GitHubフローやコードレビュー経験を積む
3	実務形式のアプリを作成（CRUD＋認証＋API連携）	「実務レベルの開発経験」として説明できる状態
4	案件応募＋面談対策	月単価50万円の案件獲得を目指す


⸻

📈 数字で見る期待効果

項目	現状	改善後
GitHubリポジトリ数/月	1	3
技術ブログ投稿数/月	0	4
実務レベルのアプリ数	0	3
チーム開発経験（GitHub PR数）	0	10
面談通過率	低	中〜高


⸻

💬 最後に

現状では、学習量がアウトプットに反映されていないため、実務力が不十分です。
学びをすぐ形にして公開し、チーム開発経験を積むことで実践力を高めることが必須です。
また、案件獲得活動を積極的に行い、フィードバックを活かしてスキルシートを改善していきましょう。

辛口ですが、現実的に見ても3〜4ヶ月の集中学習と実践があれば到達可能です。
最速で成果を出すために、学習と実務を並行して進めましょう！
進捗があれば随時報告してください。ブラッシュアップを全力でサポートします！🔥🚀

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

そんな回答が返ってきた。
要は、企業に見せる用のアウトプットが少ない！
企業やエージェントは「本当にこの人を会社に入れたら活躍できるのか？」という疑問を解消したい。
その疑問を解消するために、スキルシートの確認と面談を実施している。むしろそこぐらいでしか判断できない。
だから、この人なら安心して任せられる！と思ってもらえるレベルに到達しないと受け入れてくれない。
私がどれだけ現実を見れていないのかを思い知らされた。
ただ、「月収80万円を到達するために何をすればいいのかわからない」という絶望していた状態から、やるべきことが見つかった。
今は収入がゼロの状態だが、半年後には最低でも月収50万円に到達できるように努力していく。
少しでもこの記事を読んで勇気をもらえる人がいてくれたら嬉しいです。
（この記事を書いている今現在、外でPCの電源が落ちてしまい、充電するところもない中、けれど今思ったことを投稿したいと思い、スマホで投稿しています。なので文章の見栄えが悪くてすみません）
Gemini API imagen3ではハイティーン少女の画像生成が禁止されている？

# はじめに
最近生成AIで画像生成が話題を呼んでいますが、実際に何かアプリに組み込もうとするとAPIで生成することが書かません。今回は[Gemini API の Imagen 3](https://ai.google.dev/gemini-api/docs/imagen?hl=ja)で遊んでいて不思議な現象を発見したので報告します。
# girlを含む画像生成
実行はgoogle colabで行いましたnotebookは
```
!pip install google-genai
```
```
from google.colab import userdata
# 環境変数の準備 (左端の鍵アイコンでGOOGLE_API_KEYを設定)
GOOGLE_API_KEY = userdata.get("GOOGLE_API_KEY")
```
```
from google import genai
# クライアントの準備
client = genai.Client(api_key=GOOGLE_API_KEY)
```
```
from google import genai
from google.genai import types
from PIL import Image
from io import BytesIO

from google.colab import userdata

# 環境変数の準備 (左端の鍵アイコンでGOOGLE_API_KEYを設定)
GOOGLE_API_KEY = userdata.get("GOOGLE_API_KEY")


from google import genai

# クライアントの準備
client = genai.Client(api_key=GOOGLE_API_KEY)

response = client.models.generate_images(
    model='imagen-3.0-generate-002',
    prompt='A 17 aged girl in the spring next to a lake',
    config=types.GenerateImagesConfig(
        number_of_images= 1,
    )
)
for generated_image in response.generated_images:
  image = Image.open(BytesIO(generated_image.image.image_bytes))
  image.save('imagen3.png')
  image.show()
```
gemini API keyの設定などが必要ですが、それは各自行ってください（[参考](https://note.com/npaka/n/nc7ae293a3d41)）。正常に実行されれば左端のファイルメニューにimagen3.pngという画像が生成されるはずですが、エラーが出ます。このエラーは画像が生成されなかったときに出るエラーのようです。何がいけないのでしょうか？
#  年齢で制限？
１７歳の少女というところ(A 17 aged girl)を２０歳に変えてみます('A 20 aged girl)。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199087/69db4cc6-de50-486d-8e51-bd36ee44706a.png)
問題なく生成されるようです。それでは何才だったらNGなんでしょう？調べた限りでは１７歳以下だとダメなみたいです。
# 他の表現
性別を表す他の表現はどうでしょう？A 17 aged person with two X chromosomeとしてみました。ダメでした。ちなみにA 20 aged person with two X chromosomeだと普通に成功するのでX染色体が２個という指示が理解されていないわけではないようです。どうやら、１７歳以下の若い女性の画像をimagen3 APIで生成することがアラインメントで禁止されているようです。A 17 aged elf who wears skirt in the spring next to a lakeでもダメだったので空想上の存在でもハイティーン少女を連想させるとみなダメなようです。A 20 aged elf who wears skirt in the spring next to a lakeなOKでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199087/7eac320b-4a0c-4883-a48e-1e383e54aa55.png)
この画像なんかは上半身裸なんですが（それに中性的でどっちかというと男性です）、２０歳ならいいのが面白かったです。
# ブラウザ版ではOK
[ブラウザ版のGemini](https://gemini.google.com/app?hl=ja)でも絵を描かせることができます。2.5 pro(preview)にdraw a 17 aged girl in the spring next to a lakeと入れてみました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199087/eeb9fb12-e436-4092-93ae-e502684d2202.png)
普通に描いてくれるようです。これ中身はimagen3だとされているので同じimagen3でもAPIでは１７歳以下の少女の画像が生成できず、ブラウザ版ならできるみたいです
# 考察
なぜこうなっているのでしょうか？APIではヤバい画像（裸体とか）を描かされてしまった場合、止めるのが難しいが、ブラウザ版ならプロンプトにヤバい命令が入っていたら拒否するという機能を内部的に設定できるからそこまで厳しくしなくてもいい、ということじゃないでしょうか？APIは多数回の実行が予想されますし、その一回一回にヤバい画像かどうかの判断を設定するので重くなり、負荷が増えるので厳しめにアラインメントされているのでは、と予想しました
# おわりに
APIをつかって何かしようとする人はこれから増えて来ると思うのですがこういうことがこれからもあるのかな、と思いました。
実装してみた1

朝Shorts眺めてたら流れてきた動画を一般化しようと思い、コードを作ってもらいました。

#
問題設定
n^nのマス目に、ランダムに点が配置されている。マス目の頂点の間は全て壁で仕切られていて、点は壁を貫通しない限り自由に動くことができる。
毎ステップ、k枚の壁が開き、各点は壁が開くことにより連結した点の集合のうちいずれかを選択する。
この時、時間に対してどれだけの点が集まれるかをプロットしたい。なお、点と点は、移動可能な「同じ空間」内にいたら即座に合流するものとし、一度合流したらその後ずっと共に移動する。

#
1. 二次元グリッドの場合
Union Findってこういうところで使えるんだなと勉強になりました。
```
import numpy as np
import matplotlib.pyplot as plt
import random
from collections import defaultdict

class DSU:
    def __init__(self, n):
        self.parent = list(range(n))
        self.size = [1]*n

    def find(self, x):
        while self.parent[x] != x:
            self.parent[x] = self.parent[self.parent[x]]
            x = self.parent[x]
        return x

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return
        if self.size[xr] < self.size[yr]:
            xr, yr = yr, xr
        self.parent[yr] = xr
        self.size[xr] += self.size[yr]

    def get_all_group_sizes(self):
        group_sizes = defaultdict(int)
        for i in range(len(self.parent)):
            root = self.find(i)
            group_sizes[root] += 1
        return list(group_sizes.values())

def simulate_with_group_sizes(n=10, k=5, steps=100):
    def index(x, y): return x * n + y

    walls = []
    for i in range(n):
        for j in range(n-1): 
            walls.append(((i, j), (i, j+1)))
        for j in range(n-1):  
            walls.append(((j, i), (j+1, i)))

    dsu = DSU(n * n)
    history = []

    for step in range(steps):
        opened = random.sample(walls, k)
        for (a, b) in opened:
            ax, ay = a
            bx, by = b
            dsu.union(index(ax, ay), index(bx, by))
        history.append(sorted(dsu.get_all_group_sizes(), reverse=True)) 

    return history
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4070539/7e31d421-5aea-40e5-8640-d21f64a4d032.png)
(n=10,k=10)

richer gets richer　的でおもろい。べきなのかなあ。
いくつかのグループがほぼ同時に集合するのもおもしろいですね.
一番目のところに吸収される(=多様性が失われる)のと、最終的によく集合することのバランスがどこでとれるかを見てみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4070539/a08056d1-7309-4a87-84db-000b60455613.png)
n=20で、kが横軸、各kについて100回の試行平均です。
こうしてみると、kが10％くらいのときに、状態が遷移していること、少し遅れて、より早い段階でtopの集合が早く集合することがわかります。このときだとk=15~23くらいが見ていて面白いのかもしれません。

最後に、モデルを高次元化します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4070539/7b80ac4d-9590-4c1c-9ec3-36e6d1601464.png)
例えば4次元でn=10、つまりノードの10％が毎回解放される設定でも、このように二次元の時とは全く挙動が違います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4070539/f4fd00c5-7eaa-44fa-8924-ea8e4fa2393a.png)
集合時間が遅くなるみたいです。これはこれで面白いですね。
ちょっと予定があるのであまり深掘りはしませんが、最後にネットワーク構造を定量的に変えてみてみようと思います。
n=1000で固定Edge（edge数はノード数の二乗の10％程度)のBAモデル上でこれをしてみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4070539/ba57a422-e154-4197-b144-8c51cbb7eeb1.png)
集合の様子が全く異なりました。ネットワーク指数を色々変えてもおもしろいかもしれません。
#
Shortsを見て思いついたのですが、かなり問題設定として面白いなと思いました。（というか、どこかにこんな問題があった気がする。）多様性とかをうまく定義できたらうれしいですね～
6000円(+α)でアイトラッキングする話

# VRCで表情って大事ですよね
どうも、無言勢を名乗っていたのどかはと言うものです

VRCは表情を相手に伝えることがとても重要です

あらゆる場面で、相手の表情から推察することで円滑なコミュニケーションが出来ます

果てには、表情だけで訴える新しい形の繋がりと関係性もあります

## 作ってみよう
そんな表情を伝える手段として、VRCではフェイストラッキングというものがあります

フェイストラッキングはとても高価で、品薄であり手を出しにくいので作ってみようと思います

秋月のesp-eyeという製品を見かけました

https://akizukidenshi.com/catalog/g/g116729/

こちらはカメラが付属しており、顔認識やらが出来たりする小さなコンピューターという優れものなんですが

これでEyeTrackingが出来ます

![IMG_2783.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090905/d59f4055-14b3-411c-a631-0e7cb74599e4.jpeg)


詳細は割愛しますが、EyeTrackingしたい有志によるプロジェクトがあります

https://docs.eyetrackvr.dev/

こちらのプログラム一式を使ってEyeTrackingしてみましょう

秋月から買ったESPをケーブルを使ってPCに差し込みます

Openirisというプロジェクトから、VSCodeの導入手順とドライバのインストールを済ませます(何故かmasterブランチにはこのドキュメントがない、なんで？？)

https://github.com/EyeTrackVR/OpenIris/tree/bugfix/camera-settings?tab=readme-ov-file#now-how-do-i-get-it-running

大まかな手順は
1. VSCodeダウンロードインストール
https://code.visualstudio.com/download
2. 拡張のインストール
https://marketplace.visualstudio.com/items?itemName=platformio.platformio-ide
3. ドライバのインストール
https://cdn.sparkfun.com/assets/learn_tutorials/8/4/4/CH341SER.EXE

修正を加えたこの僕のレポジトリをgitでクローンします(Download Zipでも良い)
https://github.com/nodokaha/OpenIris/tree/fix-espeye

そしてESP.code-workspaceを開き、ポチポチします(trustとか、PlatformIOの依存関係のインストール)

ESP/ini/user_config.iniのssidとpasswordを設定してください

そしたら蟻のマークからPROJECT TASKSにあるesp_eyeを選択のGenerarlのBuildとUploadをESP-EYEのbootボタン長押しにRSTボタン押しの後に書き込み

https://github.com/EyeTrackVR/EyeTrackVR/releases/tag/EyeTrackApp-0.2.0

をインストールして立ち上げて、ESP-EYEのIPをどうにか調べて(説明が大変で人によるので、頑張ってみてください)そのアドレスを入力すれば動きます

![IMG_2784.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090905/0083791e-4f50-40af-a918-4423212e3c15.jpeg)


# おわり
やったね

まあこれにさらにHMDに取り付けるための3Dプリントとか、HMD内は暗いのでミニ赤外線LEDをHMD中で光らせるための装置作らなきゃですが(+アルファ値段の部分)

試すと言う意味ではこれで十分です

2つ買っても6000円なので手軽にアイトラッキングできますねと言う話でした
Windows 11のタスクバーに秒数を表示する

# 秒数が表示されなくなったWin11（~~環境テロ~~）

Windows11になってから「消費電力削減のため」秒数が表示されなくなった。ノートパソコンならいざ知らず、デスクトップＰＣでもこれが強制される。これが表示されないからどの程度消費電力が減るのかわからないが、これも国連が推進するSDGsの影響なのかと勘繰ってしまう。

秒数がわからないと落ち着かない人間には非常にありがたくない措置だ。WindowsのＵＩ機能から表示させることもできるが、プログラマーならpowerShellで簡単にかっこよく秒数を表示させたいものだ。下の3つの項目を実行せよ。

1, powerShellを立ち上げろ（(Winキー + X) → I と押すか検索欄でpowerを入力)。
2, 下のコマンドをコピー・ペーストしろ。
3, Enterを押せ。

```powershell:

Set-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced -Name ShowSecondsInSystemClock -Value 1 -Force
```
統計検定1級　2023　統計応用(理工学)　問2　解説

![img20250514_08542831.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/62ff74e0-980d-45c6-9f07-a0086d88ba68.jpeg)
![img20250514_08550892.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/6367595f-24e4-492d-ac2b-8f5bc472ac71.jpeg)
![img20250514_08565639.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/d8496ac4-6b5c-4468-b7dd-d87b6243c42d.jpeg)
統計検定1級　2023　統計応用(理工学)　問1　解説

![img20250512_08384201.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/f81eb160-c102-459e-9b12-fd72e9a984de.jpeg)
![img20250512_08390624.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/6f495500-af47-4566-b825-b76b7bc29b6d.jpeg)
![img20250512_08393973.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/eaff9f3c-01b7-456a-960a-378e683cbebf.jpeg)
![img20250512_08400413.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/3a702fc8-127e-4120-a760-08fc99fd2427.jpeg)
GitHubにローカルのプロジェクトをリポジトリとして追加・公開する手順

## ✅ 事前準備

### 1. GitHubで新しいリポジトリを作成する
	1.	上記リンク先の GitHub アカウントにログイン
	2.	右上の「+」→「New repository（新しいリポジトリ）」をクリック
	3.	以下を入力・選択
	•	Repository name：例）my-sns-app
	•	Description（任意）
	•	Public / Private（好みに応じて）
	•	他のチェックは外してOK（READMEや.gitignoreはローカルで作成できます）
	4.	「Create repository」をクリック

## ✅ ターミナルでの作業（Mac）

### 2. ターミナルを開いて、プロジェクトディレクトリへ移動
```
cd ~/path/to/your/project
```
### 3. Git初期化 & コミット
```
git init
git add .
git commit -m "Initial commit"
```
### 4. GitHubのリモートリポジトリと接続
```
git remote add origin https://github.com/TK-19881224/リポジトリ名.git
```

### 5. リモートにプッシュ（初回はmainブランチを明示）
```
git branch -M main
git push -u origin main
```
## ✅ 完了！

これでGitHub上にあなたのプロジェクトがアップロードされます。
PHP個人的備忘録：PHPの開始・終了タグやecho文など、基本的な文法の整理してみた

## はじめに

この記事は、PHPの基本文法について学び始めた初学者の視点から、学習内容を整理した備忘録です。**個人の備忘録程度の走り書きとなっておりますが、温かい目で見守っていただければ幸いです。**

## 書こうと思ったきっかけ

個人的にPHPのキャッチアップをしたくて、勉強している初学者による備忘録として記録しています。文法の基本を段階的に整理し、今後の学習の土台にすることを目的としています。

## 内容

PHPの基本文法を学ぶために、以下の流れでキャッチアップしています。

### ステップ1：PHPの書き方の基本

#### PHPの開始と終了タグ

```php
<?php
  // ここにPHPコードを書く
?>
```

ブラウザに表示させるには、`.php` ファイルとして保存し、サーバーで実行する必要があります。

### ステップ2：画面に文字を表示する（出力）

```php
<?php
  echo "こんにちは！";
?>
```

**実際の開発画面**

![スクリーンショット 2025-05-15 7.33.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/d1f638d6-c7b9-4653-983a-74ecc646858d.png)

`echo` は文字を表示する関数です。

### ステップ3：変数の使い方

```php
<?php
  $name = "たろう";
  echo "こんにちは、" . $name . "さん！";
?>
```

**実際の開発画面**

![スクリーンショット 2025-05-15 7.36.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/12b92da1-9d7a-4780-a29d-374b96a86c45.png)

* `$` を付けて変数を作ります。
* 文字列の結合には `.` を使います。

**実際のブラウザ**

![スクリーンショット 2025-05-15 7.36.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/9b18c589-b0b1-4120-9bfb-1c66d058b98b.png)


## まとめ

* PHPは `<?php ?>` のタグで囲ってコードを書きます。
* 文字を表示するには `echo` を使います。
* 変数には `$` を使い、文字列の結合は `.` を使います。

次は条件分岐や繰り返し、関数などに進んでいく予定です。
ビット配列(集合)への書き出し


いろいろ注意
----

- UNOでの予定は、未定

プログラム
----

オンライコンパイラpaiza

```c++

#include <iostream>
using namespace std;

//32ビット分、2進数に変換して表示するマクロ(注意!!!入力は、破壊される
#define bit32_put(aa) for(int ii=32;ii!=0;ii--){if(aa&0x80000000){printf("1");}else{printf("0");}aa=aa<<1;}

#define BW(aa,bb,cc) aa[bb>>5]=((aa[bb>>5]&(~(0x01<<(bb&0x1f))))|(cc<<(bb&0x1f)))

int main(void){
    // Your code here!
    
    int a;
    
    unsigned long abc[16];
    
    abc[0] = 0;
    abc[1] = 0;
    
    BW(abc,0,1);
    
    printf("in [0]=1\n");

    a = abc[0];
    bit32_put(a);
    printf("\n");

    a = abc[1];
    bit32_put(a);

    printf("\n\n");

    BW(abc,63,1);
    
    printf("in [63]=1\n");

    a = abc[0];
    bit32_put(a);
    printf("\n");

    a = abc[1];
    bit32_put(a);

}


```


```


in [0]=1
00000000000000000000000000000001
00000000000000000000000000000000

in [63]=1
00000000000000000000000000000001
10000000000000000000000000000000




```
チーム内リーダーのすすめ

# はじめに

この記事では、私が直近1～2年間で複数のプロジェクトリーダーや職能別リーダーを務めた経験をもとに、リーダーとして「やるべきこと」や「意識すべきこと」を言語化しました。

初めてリーダーを務める際、「こんなふうに体系的に整理された記事があればよかったのに」と思ったことから、本記事を執筆しています。

すべてのチームやプロジェクトに当てはまるわけではないかもしれませんが、特に新米リーダーの方にとって、何かしらのヒントになれば幸いです。

# やるべきこと

### 進捗は極力可視化

進捗状況や現在のステータスを、誰でも把握できるようにしました。  
「誰が何をやっているか」「今どこで止まっているか」を見える化することで、周囲のフォローや巻き取りがしやすくなります。

### 自分が持っているタスクは極力可視化

リーダーである自分がボトルネックになってはいけません。  
自分の作業タスクや検討中の内容も、できる限りSlackやタスク管理ツール上でオープンにすることで、「頼みたいけど何してるか分からない」といった状態を防ぎました。

### 何を共有してほしいかを伝える

情報は“欲しい人が取りに行く”ではなく、“伝える側が何を伝えるべきかを判断する”ことが大切です。  
期待しているアウトプットや、定例会で何を共有してほしいかは、具体的に伝えるようにしていました。

### ステークホルダーとの会話は議事録を残して即共有

打ち合わせや1on1での会話も、必ずメモを残し、すぐに関係者に共有します。  
「自分だけが知っている情報」をゼロにすることが、チームのボトルネックを減らす第一歩だと考えています。

### 任せる（コアタスクを持たない）

基本的に自分は“動かない”。コアとなる開発や設計には関与しないよう意識しました。  
その分、メンバーが進みやすい環境整備に徹し、詰まったところへのフォローや意思決定に時間を割くようにしていました。

### めっちゃ感謝する

これは一番大事かもしれません。  
相談してくれたこと、決めてくれたこと、進めてくれたこと…すべてに「ありがとう」を伝える。  
「感謝がちゃんと届くチーム」は、信頼も前向きな空気も自然と育っていきます。

## 念頭におくべきこと

### パンクしたら負け

リーダーが倒れたら終わりです。  
どれだけ忙しくても、必ず休む時間・冷静に考える時間を意図的に確保していました。

### いかに仲間の手が止まらないかを考える

先手先手で動くことが重要です。  
「次にどんな懸念が出てきそうか」「誰が詰まりそうか」を予測して、予め布石を打つのがリーダーの役割です。

### チームに最低1人以上、同じ視野で話せる人を作る

すべてを一人で決めるのは難しいし、プレッシャーも大きい。  
そんなときに“同じ視野”で話せるメンバーがいると、意思決定が格段にスムーズになります。  
ちょっとした壁打ちでも助けになります。

### How Can I Help You？

「締切延ばす」「タスクを巻き取る」は最終手段。  
その前に、以下のような伴走的な支援を意識していました。

- 詰まっているところを一緒に考える（ペアプロ）
- 情報を渡す（過去事例やSlackリンク）
- 他の詳しい人に繋げる

「何かあったら言ってね」より、「どこが不安？」の方が、助けやすくなります。

### 達成感が半端ない

このスタイルは、手を動かすタスクが少ない分、“目に見える成果”がわかりにくいかもしれません。  
でも、メンバーが動きやすくなり、チームとして成果が出たときの喜びはとても大きいです。  
「自分がやりきった」ではなく「みんなで成し遂げた」と思えるこの達成感は、何ものにも代えがたいものでした。

## おわりに

プロジェクトリードの経験は、決して楽なものではありませんが、個人的には非常に得るものが多かったと感じています。  
本記事が、これからチームを率いていく方や、同じように悩んでいる方の参考になれば幸いです。
PHP個人的備忘録：MacでPHPローカルサーバーを立ち上げるまでの簡易メモ

## はじめに

この記事は、PHPの環境構築において遭遇したエラーとその解決手順を、初学者の視点から備忘録としてまとめたものです。

**個人の備忘録程度の走り書きとなっておりますが、温かい目で見守っていただければ幸いです。**

## 書こうと思ったきっかけ

個人的にPHPのキャッチアップをしたくて、ローカル環境で簡単なPHPコードを実行しようとしたところ、エラーに遭遇しました。今後同じような場面でスムーズに対応できるよう、記録として残しておきます。

## 内容

ターミナルで以下のコマンドを実行した際、

```
php -S localhost:8000
```

以下のエラーが表示されました。

```
zsh: command not found: php
```

これは、MacにPHPがインストールされていない、またはPATHが通っていないことが原因です。

### 解決手順

#### 1. PHPがインストールされているか確認

```bash
which php
```

* 何も表示されなければ → 未インストール
* `/usr/bin/php` などのパスが表示されれば → インストール済

#### 2. PHPをHomebrewでインストール

MacではHomebrew経由で簡単にインストールできます。

```bash
brew install php
```

インストール後、バージョン確認：

```bash
php -v
```

バージョン情報が表示されればOKです。

**実際の画面**

![スクリーンショット 2025-05-15 6.53.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/aa66ba4f-f3dc-4ec8-aa2d-8f644af3c914.png)

#### 3. ローカルサーバーを起動

再度、以下のコマンドを実行：

```bash
php -S localhost:8000
```

**実際の画面**

![スクリーンショット 2025-05-15 6.53.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/03bd7f30-fd3c-4f2b-a3e5-f4f342ba9f1e.png)


ブラウザで以下のURLにアクセス：

```
http://localhost:8000/test.php
```

**実際の画面**

![スクリーンショット 2025-05-15 6.54.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/4d18e1df-6f4a-49fd-84da-47246b0eba34.png)

PHPファイルの出力が確認できれば成功です。

## まとめ

* `php` コマンドが使えない場合は、まずインストール状況を確認する
* `brew install php` で簡単に導入可能
* `php -S` コマンドで手軽にローカルサーバーを立ち上げられる

初心者でも数ステップでPHPの実行環境を整えることができました...！
Linucレベル１勉強メモ　＃３６

＃ 第三章　GNUとUnixのコマンド

練習問題3.11
３台のホストに存在するユーザー名を重複なくリスト化しようとしています。

＄ cut -d: -f1 /etc/passwd > passwd1

というコマンドを実行し、ユーザー名一覧をpasswd1ファイルに保存しました。また、別のホストで同様にpasswd2、passwd3といったファイルにユーザー名一覧を保存しました。これらのファイルを、次のようにして結合しました。

＄cat passwd1 passwd2 passwd3 > users.list

users.listファイルには「root」やシステムアカウントなど、各ホストで重複するユーザー名が含まれています。そこで、重複行を１つにまとめるため、次のコマンドを実行しました。

＄ mv users.list users.list.org
＄ mv users.org > users.list

しかし、重複行は１つにまとまりませんでした。その理由として適切なものを選択してください。

A. catコマンドで結合する前に sortコマンドを実行しておく必要がある

B. mvコマンドの引数の指定が逆である

C. catコマンドでファイルを結合するには「>」ではなく「>>」で指定しないとファイルが上書きされてしまう。

D. uniqコマンドを実行する前にsortコマンドでソートしておく必要がある。

E. 重複行を１行にまとめるには、uniqコマンドではなくwcコマンドを使う。

（解答）D

（解説）
設問にあるようにcatコマンドファイルを結合すると、「passwd1ファイルの内容」「passwd2ファイルの内容」「passwd3ファイルの内容」の順に結合されます。uniqコマンドで重複行を１つにまとめるには、あらかじめソートしておく必要があります。gた、この状態ではソートされていません。そのため重複行がまとまらなかったのです。

＄ sort users.list.org | uniq > users.list

のようにあらかじめソートしておく必要があります。
catコマンドで結合する前にソートしておいても、上記の通り結合したファイルはソートされていないため、選択肢Aは不正解です。設問の、mvコマンドは、作成したusers.listファイルのファイル名をusers.list.orgに変更するために使われているので、引数の指定が間違っているわけではありません。catコマンドによるファイルの結合は「>]で構いません。「>>」でなければならないのは次のような結合の仕方を和る場合でしょう。

＄ cat passwd1 > users.list
＄ cat passwd2 >> users.list
＄ cat passwd3 >> users.list

wcコマンドはファイルの行数や文字数をカウントするコマンドなので、選択肢Eは不正解です。

（わからない単語解説）
* \>><br>コマンドの標準出力(実行結果)をファイルに追記する
* cutコマンド<br>ファイルの各行から指定したフィールドを取り出します。「-d」オプションはフィールドの区切り文字（デリミタ）を指定する（デフォルトはタブ）設問の $ cut -d: -f1　は区切り文字（デリミタ）を「：」として１番目のフィールドを取り出す。という意味合いになります。
* catコマンド<br>ファイルの内容を表示するために使われる、正確には、ファイルの内容を標準出力に出力する。そのため、シェルのリダイレクトを使って複数のファイルの結合をすることもできる
rubocopで「Rails/BulkChangeTable: You can use change_table :テーブル名, bulk: true to combine alter queries.」と指摘された時の対処法

## はじめに
今回躓いた内容の備忘録として、また他にも困った方がいた時の手助けになればと思い記事を作成しました。

## rubocopの指摘内容
rubocopをかけるとこのように表示されました。
```
db/migrate/20250507114656_add_column_to_user.rb:5:5: 
C: Rails/BulkChangeTable: You can use change_table :users, bulk: true to combine alter queries.
    add_column :users, :self_introduction, :text
```
これは、「change_tableにbulk: trueオプションをつけて一括で変更してね」ということを示しています。

## 対処法
### ①マイグレーションファイルの状態とIDを確認する
このコマンドを打つと、現在のマイグレーションファイルの状態（UP/DOWM)や、マイグレーションファイルごとのIDをみることができます。
```
$ rails db:migrate:status
```

### ②特定のマイグレーションファイルをDOWNの状態にする
Migration IDに編集したいマイグレーションファイルのMigration IDをコピーしてコマンドを実行してください。
```
$ rails db:migrate:down VERSION=Migration ID
```
今回はこのようにしました。
```
$ rails db:migrate:down VERSION=20250507114656
```
そうするとDOWN状態になっていると思います。

### ③マイグレーションファイルを編集する

Railsのmigrationで1つのテーブルについて複数の操作をする時に、このように個別に書くのではなく、
```ruby:変更前
class AddColumnToUser < ActiveRecord::Migration[7.0]
  def change
    add_column :users, :self_introduction, :text
    add_column :users, :place, :string
    add_column :users, :website, :text
  end
end
```

change_tableにbulk: trueオプションをつけてまとめましょう、というCopなので、このように変更します。
また、「:bulk」オプションをつけることで、変更内容を1つのALTER TABLE文にまとめることができます。
```ruby:変更後
class AddColumnToUser < ActiveRecord::Migration[7.0]
  def change
    change_table :users, bulk: true do |t|
      t.text :self_introduction
      t.string :place
      t.text :website
    end
  end
end
```
・使い方はこちらを参照：[change_table | Railsドキュメント](https://railsdoc.com/page/change_table)
<br>
こうすることで個別に実行されていたALTER TABLE文が
```
ALTER TABLE "users" ADD "self_introduction" text
ALTER TABLE "users" ADD "place" character varying
ALTER TABLE "users" ADD "website" text
```
まとめて実行されるようになって処理が高速化されます。
```
ALTER TABLE "users" ADD "self_introduction" text, ADD "place" character varying, ADD "website" text
```

### ④rails db:migrateコマンドを実行する
ターミナルに
```
$ rails db:migrate
```
と打ってください。編集したマイグレーションファイルをUPにします。

これでマイグレーションファイルの編集が完了！
<br>

:::note warn
注意
こちらの方法(ロールバック)を行うと、該当のテーブルのデータが消えてしまいます(マイグレーションをupの状態からdownの状態にするとテーブルが削除される。)。ですので、本番環境などで消えて欲しくないデータが保存されている場合は基本的には使わない方が良いです。
:::

## おわりに
今後、テーブルにカラムを複数追加する際は、add_columnを何度も重ねずに、change_tableを使って書こうと思います。

## 参考にしたサイト

https://qiita.com/matsu1226/items/ef7e52cf26db4a01972f

https://blog.rista.jp/entry/2020/05/30/152602

https://zenn.dev/lobo_kn/articles/2a8315cace39b3

https://nect-life.com/activities/23
動画配信アプリの作り方

# 目的
私が実装した動画配信の仕組みを見ながら、動画配信に必要な基本知識を理解することが目的です。

# インフラ構成
- 以下に今回使用したリソースを挙げます
  - CloudFront
  - S3
  - SNS
  - EventBridge
  - Lambda
  - Cognito
  - Mediaconvert
  - EKS
  - Aurora
- terraform における具体的なリソース名は、[私の CI/CD の結論 v2](https://qiita.com/ShiroatoHiro/items/21c68e25284a346a94a5) を参照してください。

# 流れ
## アップロード
1. ユーザは cognito にログイン
    1. ユーザはアプリ(EKS)にアクセスし、アプリは SDK を通じて cognito からトークンをもらって、ユーザに返します
1. ユーザは、先ほどもらったアクセストークンを使って、S3 にアクセスするための identityId, STS トークンを Cognito から取得します
    1. 先ほどと同様に、アプリを介して Cognito にアクセスします
1. ユーザはアプリに動画作成のリクエストを送ります
    1. もちろん、ここでは動画のメタ情報をアプリDB(Aurora)に登録するだけです
    1. ステータスは started とかにします
    1. 同時に、S3 のアップロードのエンドポイントをもらいます
        1. フロントで S3 のアップロードのエンドポイントを構築してもいいです
1. ユーザは、STSトークンを使って、S3に直接動画をアップロードします
    1. IAM Policy の設定により、自分のフォルダ(identityId によって判別)以外へのアップロードは禁止されています
    1. 本プロジェクトのフロントは、簡易的な C++ デスクトップアプリで実装したので、SDK For C++ を使いました
        1. TransferManager クラスを使うことで、進捗を把握するためのプログレスバーを実装することができます
1. S3 へのアップロードが完了したら、ラムダが発火します
    1. ラムダが Mediaconvert にジョブを積みます
1. Mediaconvert はアップロードされた mp4 や mov を、ストリーミング再生可能な HLS に変換して、S3 に配置します
    1. HLS は、各セグメントのメタデータを保持する m3u8 ファイルと、実際の動画データを持つ ts ファイルから構成されます
1. EventBridge は、Mediaconvert の状態を60秒ごと(適宜変更可能)に監視しており、SNS に伝えます
    1. Mediaconvert のステータスは、`["SUBMITTED", "INPUT_INFORMATION", "PROGRESSING", "STATUS_UPDATE", "COMPLETE", "ERROR", "CANCELED"]` のいずれかです
1. SNS はラムダを発火します
1. ラムダは internal api を通じて、アプリ(EKS) に、動画(Mediaconvert)のステータスとMediaConvert がアップロードした S3 のエンドポイントを送ります
    1. アプリの動画のステータスが complete とかになっていれば、ユーザがその動画にアクセスできます 

## 動画再生
1. ユーザはアプリから動画のメタデータを取得します
    1. アプリは S3 のエンドポイントから cloudfront のエンドポイントに変換して、ユーザに返します
    1. 必要に応じて、cloudfront のエンドポイントに署名します
        1. 署名付きURLと署名付きクッキーが選択肢としてありますが、HLSは複数ファイルにアクセスするため、署名付きクッキーが推奨されています
1. ユーザは、取得した cloudfront のエンドポイントを使って、動画をストリーミング再生します

# Youtube
## 署名付きURL or 署名付きクッキー
上述したように、ストリーミング再生では、複数のセグメントファイルへのアクセスが必要なので、署名付きURLではなくて署名付きクッキーが一般的に推奨されている。
しかし、Youtube のネットワークタブを見ると、署名付きクッキーではなくて、署名付きURLが使われていた。おそらく、m3u8 ファイルだけではなくて、全ての ts ファイルのエンドポイントに対しても署名しているのだと思う。m3u8 ファイル上の全ての ts ファイルのエンドポイントを署名付きURLに変更するのは、かなり技術的に難しそう。
ただ、署名付きクッキーが使えない場合は、このように実装するしかないのかもしれない。例えば、C++ の Qt ライブラリや、Unreal Engine の Media Player は、ヘッダーを持たせることができないので、どうしてもアクセスを制限したい場合は、署名付きURLを採用するしかない。
(そもそも、HLS じゃなくて DASH 使っているとか、細かい部分は違うかもしれないが、大まかなイメージはこんな感じだと思う)

## アクセス制限
詳しくはわからないが、署名以外にも、正規の方法以外から動画にアクセスできないように工夫しているはず。
例えば、Youtube のネットワークタブからURLを引っ張ってきて、デスクトップアプリで再生しようとしたら、CDN の CORS で弾かれた。
あとは、IPとか...
【公ド読】Copilot を使ってプロジェクトを別のプログラミング言語に移行する

【公式ドキュメントを読もうシリーズ】Copilot を使ってプロジェクトを別のプログラミング言語に移行する

## シリーズ概要

[https://qiita.com/yasu_programming/items/cec66f9e8d5d571e9ce3](https://qiita.com/yasu_programming/items/cec66f9e8d5d571e9ce3)

## URL

[https://docs.github.com/ja/copilot/using-github-copilot/guides-on-using-github-copilot/using-copilot-to-migrate-a-project](https://docs.github.com/ja/copilot/using-github-copilot/guides-on-using-github-copilot/using-copilot-to-migrate-a-project)

## 説明

別のプログラミング言語への移行手順を実際のプロンプトを用いながら説明してくれる。
原則なども準備してくれている。

## 所感
解像度高く移行手順が書かれている。
ただ移行前の言語、移行後の言語のどちらの知識も人間側で理解しておくことはこれからも大事ってことですね。
Spring WebClient のレスポンスヘッダから Transfer-Encoding を削除

```java
ClientResponse response = webClient.get()
    .uri("http://example.com/api")
    .exchange()
    .block();

ResponseEntity<byte[]> entity = ResponseEntity
    .status(response.statusCode())
    .headers(headers -> {
        headers.putAll(response.headers().asHttpHeaders());
        headers.remove(HttpHeaders.TRANSFER_ENCODING); // 削除
    })
    .body(response.bodyToMono(byte[].class).block());
```
今月のマテリアル

 モリブデンジスルフィド（001）層とモリブデンテルル化物（001）層の界面（MoS₂(001)/Te₂Mo(001)）、歪み整合超格子セル、6層構造。

  モリブデンジスルフィド（通称「モリ」）は、モリブデンと硫黄から成る無機化合物であり、化学式は MoS₂ です。
 この化合物は遷移金属ジカルコゲナイドに分類され、銀黒色の固体として存在し、天然にはモリブデンの主鉱石であるモリブデン鉱として産出されます。
 MoS₂ は比較的化学変化しにくく、希酸や酸素の影響を受けにくい性質を持っています。
 見た目や手触りはグラファイトに似ており、低摩擦で頑丈なことから、ドライ潤滑剤として広く使用されています。
 バルク状態の MoS₂ は反磁性を示す間接バンドギャップ半導体であり、シリコンと似た性質を持ち、バンドギャップは 1.23 eV です。

  モリブデン（IV）テルル化物、またはモリブデンジテルル化物（一般的にはモリブデンテルル化物）は、化学式 MoTe₂ の無機化合物です。
 この物質は半導体であり、蛍光性を持つことがあります。また遷移金属ジカルコゲナイドの一種であり、半導体としてのバンドギャップは赤外領域に位置します。
 そのため、電子機器や赤外線検出器への応用が期待されています。MoTe₂ は黒色で、Mo⁴⁺ および 2Te²⁻ と表記されることもありますが、実際にはイオン結合ではなく強い共有結合を特徴とします。

 Mat3ra プラットフォームにて公開中：https://platform.mat3ra.com/bank/materials/eLBE6DdGNL2tZuLy8

#materials #RnD #mat3ra #exabyteio #materialsscience #materialsdesign #materialsmodeling #science #technology

![c28faf55e892c76361fbffa951ac9bfd.original.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4022238/5b2cef41-f951-4f87-8a1f-0e398d4602a9.jpeg)
競合や重複設定の可能性があるHTTPヘッダーのキー

## 競合や重複設定の可能性があるヘッダー
以下のヘッダーは、Tomcatでも自動で入りうるし、Spring/reactor-netty でもアプリケーション側で設定されがちです：

#### 1.Content-Type
Springでは `@ResponseBody`, `@RequestMapping(produces="...")` によって明示的に設定される。

Tomcatでも response.getWriter() などを呼ぶと自動的に text/plain などが設定されることがある。

#### 2.Content-Length
明示的に .write() して完全なバイト数がわかっている場合は Tomcat が自動設定。

Springでも ResponseEntity などで body に String を指定すれば自動計算される。

WebFlux / Reactor Netty では Flux/Mono のサイズが確定しない場合は Transfer-Encoding: chunked になる。

#### 3.Transfer-Encoding
Tomcat：HTTP/1.1で Content-Length がないと chunked を自動設定。

Reactor Netty：デフォルトで chunked を使う（バッファリングしないストリーム型処理が前提）。

Spring WebFlux：Reactor Nettyに任せるが、条件次第で Transfer-Encoding: chunked になる。
リクエスト/レスポンスヘッダーの自動設定比較表(Spring MVC, Spring WebFlux, Tomcat, Reactor Netty, Apache HttpClient)

## リクエストヘッダーの自動設定比較表
|ヘッダー名|	Spring MVC|	Spring WebFlux	|Tomcat|	Reactor Netty|	Apache HttpClient|
|:-|:-|:-|:-|:-|:-|
|Content-Type|✅ 自動（`@RequestBody`など）|	✅ 自動（Mono/Fluxの型に応じて）|✅ リクエストから解析|	✅ リクエストから解析|✅ 自動（Entityから推測）|
|Content-Length|✅ 自動設定（明示されていない場合）|✅ 自動（Fluxなどでは未設定）|✅ 自動（ボディあり時）|✅ 自動（ボディサイズで）|✅ 自動（Entityサイズに応じて）|
|Transfer-Encoding|	✅ 自動（Content-Lengthが無いとき）|✅ 自動（chunkedが多い）|✅ 自動（HTTP/1.1で必要時）|✅ 自動（chunkedに）|✅ 自動（ストリーム送信時）|
|Connection|	✅ keep-alive(HTTP/1.1)|	✅ keep-alive|	✅ クライアント要求に基づき判断|	✅ 自動でkeep-alive|	✅ デフォルトでkeep-alive|
|Authorization|	✅ Spring Securityで処理|	✅ 同左|	❌ 自動付与しない|	❌ 同左|	❌ 明示的に付与が必要|
|User-Agent	|❌（クライアントに依存）	|❌|	✅ クライアント送信値|	✅ 同左|	✅ 自動（デフォルト値あり）|
|Accept|	✅ 自動（producesによる）|	✅ 自動（producesによる）|	✅ クライアント送信値|	✅ 同左|	✅ 自動（JSONなどに応じて）|
|Cookie|	✅ 自動で解釈|	✅ 同左|	✅ パースのみ|	✅ パースのみ|	✅ 自動（HttpContext使用時）|
|X-Forwarded-For|	✅（Proxy通過時）|	✅ 同左|	✅ Proxyから付与|	✅ 同左|	❌ 明示的に必要|
|Host	|✅ 自動設定	|✅ 同左|	✅ クライアント送信値|	✅ 同左|	✅ 自動（URIから）|

## レスポンスヘッダーの自動設定比較表
|ヘッダー名|	Spring MVC|	Spring WebFlux	|Tomcat|	Reactor Netty|	Apache HttpClient|
|:-|:-|:-|:-|:-|:-|
|Content-Type|	✅ 自動（produces属性/ResponseEntity）|	✅ 自動（Monoの型）|	✅ 自動設定される|	✅ 自動設定される|	✅ サーバからの値をそのまま取得|
|Content-Length|	✅ 自動（静的コンテンツなど）|	❌（通常未設定）|	✅ 自動（静的リソースなど）|	❌（chunkedに依存）|	✅ サーバからの値をそのまま取得|
|Transfer-Encoding|	✅ 自動（サイズ不明時）|	✅ chunkedが基本|	✅ chunkedを自動付加|	✅ chunkedを自動付加|	✅ chunked など受信値そのまま
|Set-Cookie|	✅ 自動（HttpServletResponseに追加）|	✅ 自動（ResponseCookie）|	✅ 自動でヘッダー出力|	✅ 同左|	✅ クッキーの受信可能|
|Cache-Control	|✅ 明示しない限りは未設定|	✅ 同左|	❌ デフォルトではなし|	❌ 同左|	✅ 受信ヘッダーとして取得可能|
|Connection|	✅ HTTP/1.1でkeep-alive|	✅ 同左|	✅ keep-alive自動設定|	✅ 同左|	✅ 受信ヘッダーに含まれる|
|Date|	✅ 自動（HttpServlet仕様）|	✅ 自動|	✅ 自動付加|	✅ 自動付加|	✅ サーバからの受信内容|
|Server|	❌ デフォルトなし|	❌	|✅ Apache Tomcat/X.X.X|	✅ ReactorNetty/X.X.X	|✅ サーバ側が送信した値|

## 補足ポイント

Spring MVC / WebFlux の自動設定は、アノテーションやレスポンスボディの内容に基づいて行われます。

Tomcat / Netty はそれぞれのサーバとしての役割で HTTP 仕様に準拠した自動設定を行います。

Apache HttpClient はクライアント側ライブラリであり、送信時の一部ヘッダーは自動設定されますが、Authorization などは明示的に設定する必要があります。

Transfer-Encoding や Content-Length は、ボディの存在・サイズにより自動的に判断されます。
Spring WebClient（reactor-netty）Transfer-Encoding: chunked だけでなく Content-Length にも対応させたい

## 【送信側】Content-Length と chunked の使い分け

1.Content-Length を明示的に使いたい場合

WebClientは、body()の内容がメモリ上に展開可能である場合、自動的にContent-Lengthを付与します
```java
String payload = "固定サイズのリクエスト";
client.post()
    .uri("http://example.com/api")
    .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(payload.getBytes(StandardCharsets.UTF_8).length))
    .bodyValue(payload)
    .retrieve()
    .bodyToMono(String.class)
    .subscribe(System.out::println);
```
上記のように、bodyValue を使うと Content-Length を自動設定してくれます。明示的に header() を使っても構いませんが、省略可能です。

2.Transfer-Encoding: chunked にしたい場合

FluxやDataBufferのようなストリーミング送信では chunked になります。以下のように Flux を使うと、Content-Length は付かず、自動的に Transfer-Encoding: chunked が設定されます。

```java
Flux<String> flux = Flux.just("chunk1", "chunk2", "chunk3");

client.post()
    .uri("http://example.com/stream")
    .body(BodyInserters.fromPublisher(flux, String.class))
    .retrieve()
    .bodyToMono(String.class)
    .subscribe(System.out::println);
```

## 【受信側】どちらにも対応するには？
WebClientは受信時に Content-Length でも chunked でも 自動的に判別してくれます。特に追加設定は不要です。
```java
client.get()
    .uri("http://example.com/data")
    .retrieve()
    .bodyToMono(String.class)
    .subscribe(System.out::println);
```
Databricksで初めての機械学習モデルを構築してみた

## 前提
・利用環境：Databricks

https://www.databricks.com/jp/try-databricks?scid=7018Y000001Fi15QAC&utm_medium=paid+search&utm_source=google&utm_campaign=17377047998&utm_adgroup=138148229998&utm_content=trial&utm_offer=try-databricks&utm_ad=732035937815&utm_term=databricks%20%E3%83%88%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%AB&gad_source=1&gclid=CjwKCAiA8Lu9BhA8EiwAag16b8b3zbkIb3V7gp-8VUwKukXnhtVZRQ-1RY8SbETmGVgNT4bQramYmRoCX5wQAvD_BwE#account

## 参考ドキュメント

https://docs.databricks.com/gcp/ja/getting-started/ml-get-started

## 操作手順（動画）
<iframe width="560" height="315" src="https://www.youtube.com/embed/acaxbHly3Do?si=TJ1oXym_hSSIqSm2" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
Ubuntuデスクトップを入れてみた

##  はじめに
僕は、1万円ほどの中古WindowsノートPCを買いました。
しかし、いざ使ってみると…動作が重くてまともに使える感じではありませんでした。
そこで、思い切って「Ubuntuデスクトップ」を入れて使ってみることにしました。
結果的にめちゃくちゃ快適になったので、
「同じように激安PCを手に入れたけど使いものにならない…」という方や
「WindowsじゃなくてLinux（Ubuntu）を使ってみたい！」という方の参考になればうれしいです。



##  注意⚠️
今回ご紹介するやり方ではパソコンの中身がすべて初期化（削除）されます。
つまり、Windowsや中のデータは完全に消えます。
必ず事前にバックアップを取っておいてください。


 ## ubuntuデスクトップインストール方法
 #### 1 Ubuntuをダウンロードする
 まずは公式サイトからUbuntu最新版（LTS版）をダウンロードします。
👉 https://ubuntu.com/download/desktop
僕は「Ubuntu 24.04 LTS」を使いました！
#### 2 インストール用USBを作る
- 8GB以上のUSBメモリを用意

- Windowsに「Rufus」というソフトをインストール
　👉 https://rufus.ie/ja/

- Rufusを起動して、ダウンロードしたUbuntuのISOを指定

- パーティション構成は「GPT（UEFI）」を選択

- 書き込み方式は「ISOイメージ」を選んでスタート

これで起動用USBが完成します！

#### 3 PCをUSBから起動
- USBを挿した状態でPCを再起動
- 起動時に「F12」キーを連打！（※使用しているPCよって変わる）
- 「Boot Menu（ブートメニュー）」が表示されたら、USBを選択

メモ: PCによってはF12連打しなくても再起動しただけでUbuntuの画面になる

#### 4 Ubuntuのインストールを開始！
- Ubuntuの画面が表示されたら「Ubuntuをインストール」をクリック
- 言語は「日本語」、Wi-Fiも接続
- インストールの種類で「ディスクを削除してUbuntuをインストール」を選ぶ


 ## まとめ
Ubuntuのインストールは思っていたよりずっと簡単でした！
むしろ、重すぎたWindowsより軽くて使いやすくてびっくりしました。
もし古いPCや激安PCで悩んでいるなら、Ubuntu化して蘇らせるのもアリ！
ぜひ試してみてください！


 ##  参考
 https://diagnose-fix.com/topic2-003/
 https://www.youtube.com/watch?v=JByFITb5Fyg
ByteArrayHttpMessageConverterをカスタマイズして、自動Content-Length やらないようにする

ByteArrayHttpMessageConverter をカスタマイズして、自動で Content-Length を設定しないようにすることは可能です。ただし、ByteArrayHttpMessageConverter 自体が Content-Length を明示的に HttpServletResponse に設定しているわけではなく、通常は Spring がレスポンスボディのサイズから自動で付けています。

## 方法1：カスタム HttpMessageConverter を作って登録（XML config）

ByteArrayHttpMessageConverter を拡張
```java
public class NoContentLengthByteArrayHttpMessageConverter extends ByteArrayHttpMessageConverter {
    @Override
    protected void writeInternal(byte[] bytes, HttpOutputMessage outputMessage) throws IOException {
        // Content-Length を書かないようにする
        outputMessage.getHeaders().remove(HttpHeaders.CONTENT_LENGTH);

        // 書き込みは通常通り行う
        StreamUtils.copy(bytes, outputMessage.getBody());
    }
}
```

XML コンフィグで登録
```xml
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="your.package.NoContentLengthByteArrayHttpMessageConverter"/>
            <!-- 他の必要なコンバーターも追加 -->
            <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
        </list>
    </property>
</bean>
```

## 方法2：Content-Length をわざと除外して返す（Controller側で）

ただし、Spring の内部処理で Content-Length を自動で上書きする可能性があるため、この方法は環境によって動作が保証されない場合もあります。


```java
@GetMapping("/no-length")
public ResponseEntity<byte[]> noContentLength() {
    byte[] data = ...;

    HttpHeaders headers = new HttpHeaders();
    headers.set("Transfer-Encoding", "chunked");  // chunked モードにする
    headers.remove(HttpHeaders.CONTENT_LENGTH);   // 念のため明示的に除去

    return new ResponseEntity<>(data, headers, HttpStatus.OK);
}
```

##  注意点
Content-Length を削除すると、HTTP クライアント側では chunked transfer として扱われる可能性があります。

HTTP/1.1 では Content-Length も Transfer-Encoding: chunked もないと レスポンス終了が認識できなくなるため、特別な目的がない限り非推奨です。
PowerShellでPythonをWindowsにインストール

このシリーズの他の記事は、[オラクル・クラウドの個人ブログ一覧 ](https://qiita.com/letian/items/10152a4fec813c1b7d98)からご覧いただけます。

**初めに**
このブログでは、PowerShellスクリプトを活用して、<strong>Python</strong>の自動インストールを実現する方法を解説します。特に、クラウド環境での効率的なセットアップを目指す方や、Computeインスタンスの作成時に自動的にインストールしたい方にとって、一助となれば幸いです。

__環境情報__
OS: Windows Server 2019 Standard Edition (VM)
Python バージョン: 3.13.3 (x64)

__ステップ__
- インストーラのダウンロード
- インストール開始（`/quiet PrependPath=1`）
- インストーラの削除（オプション）

```powershell
#ps1_sysnative

# Define the URL of the Python installer
$InstallerFile = "python-3.13.3-amd64.exe"
$InstallerUrl =  "https://www.python.org/ftp/python/3.13.3/$InstallerFile"

# Define the path where you want to save the installer
$InstallerPath = Join-Path $env:TEMP $InstallerFile

# Download the installer
$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri $InstallerUrl -OutFile $InstallerPath

# Unblock the downloaded file
Unblock-File -Path $InstallerPath

# Execute the installer silently
Start-Process  -Wait -FilePath $InstallerPath -Args "/quiet PrependPath=1"

# Clean up the installer after installation (optional)
Remove-Item $InstallerPath
```
:::note
OCI cloud-initスクリプトで使用する場合は、スクリプトの先頭に`#ps1_sysnative`を追加する必要があります。
:::

__パラメータ__
`/quiet`: ユーザーインターフェイスを表示せずにインストール／アンインストールを行います。
`PrependPath=1`: インストール・ディレクトリおよびスクリプト・ディレクトリを 環境変数 `PATH`に追加し、`.PY`を 環境変数 `PATHEXT` に追加します（デフォルト値はゼロ）。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1121622/fe362c65-a6b4-48fd-9907-a66d235f841c.png", width="550">

__インストール後の確認__

```powershell
PS C:\Users\opc> python -V
Python 3.13.3
```

以上

----
__関連記事__
[OCI Cloud-initスクリプト](https://qiita.com/letian/items/10152a4fec813c1b7d98#11-cloud-init%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88)

__オフィシャルドキュメント__
[Python Download](https://www.python.org/downloads/)
Using Python on Windows: [英語](https://docs.python.org/3.13/using/windows.html#installation-steps) [日本語](https://docs.python.org/ja/3.13/using/windows.html#installation-steps)
【Java】3分で読めるStreamAPIの基本知識

## StreamAPIとは
リストなどのコレクションを処理するAPIのこと

## 特徴
* 繰り返し処理やフィルタ処理を簡単にかける
* **中間処理（map,filterなど）** と **終端処理（collect,forEachなど）** で構成

## StreamAPIの使用例
▼例題
``List<String>``に格納された名前のうち、
"a"で始まる小文字の名前を大文字に変換し、結果をリストに格納する

▼StreamAPIを使わない場合
```
List<String> names = Arrays.asList("alice","bob","anna","Charie");
List<String> result = new ArrayList<>();

for(String name: names) {
    if(name.startsWith("a")) {
        result.add(name.toUpperCase());
    }
}

System.out.println(result); // [ALICE,ANNA]
```
▼StreamAPIを使用した場合
```
List<String> names = ("alice","bob","anna","Charlie");

List<String> result = names.stream()
    .filter(name -> name.startWith("a")) // 条件に合うものを選ぶ
    .map(String::toUpperCase) // 大文字に変換
    .collect(Collectors.toList()); // Listにまとめる

System.out.println(result); // [ALICE,ANNA]
```

## まとめ
* StreamAPIの場合、処理の目的が、filter,map,collectなど直感的で読みやすい。
* データの変換処理をパイプラインのように繋げて記述できる。

記事作成時間：20分
Spring MVCでコントローラのリクエスト受付メソッドがreturnした時に動くConverterクラス

Spring MVC のコントローラでリクエストを受け付けた後、レスポンスとして return されたオブジェクトは、Spring の `HttpMessageConverter` によってクライアントに返す形式（JSON や XML など）にシリアライズされます。

この変換処理は、`@ResponseBody` または `@RestController` が付いているメソッドやクラスに対して行われます。

## レスポンス変換の流れ（概要）

コントローラメソッドがオブジェクトを return。

`RequestMappingHandlerAdapter` が `HttpMessageConverter` を使って変換。

`HttpServletResponse` に `Content-Type`, `Content-Length` などを自動または手動で設定。

書き込み完了。

##  Spring MVCで使用される主な HttpMessageConverter の種類

| Converter クラス | 対応メディアタイプ |説明 |
| ---- | ---- |---- |
| MappingJackson2HttpMessageConverter | application/json |Jackson を使用して JSON に変換 |
| GsonHttpMessageConverter | application/json |	Gson を使用して JSON に変換（Jackson の代替） |
| MappingJackson2XmlHttpMessageConverter | application/xml |Jackson XML 拡張で XML に変換 |
| Jaxb2RootElementHttpMessageConverter | application/xml |JAXB を使用して XML に変換 |
| StringHttpMessageConverter | text/plain など |	String への変換 |
| ByteArrayHttpMessageConverter | application/octet-stream など |	バイナリ（byte[]）への変換 |
|ResourceHttpMessageConverter | ファイルや InputStreamResource など |ファイルレスポンスなど |
| FormHttpMessageConverter | 	application/x-www-form-urlencoded |フォームデータ対応 |

## Content-Length ヘッダの設定について

#### 自動設定されるケース

通常、`HttpMessageConverter` によってレスポンスボディが変換され、`HttpServletResponse` に書き込まれる際に：

バイト数が事前にわかる場合は、`Content-Length` ヘッダが自動的に設定されます（例：文字列、byte[] など）。

ストリームベース（例：`InputStream` や `Resource`）のレスポンスでは、chunked transfer encoding（`Transfer-Encoding: chunked`） になる場合があります。この場合は `Content-Length` は省略されます。


#### 明示的に設定したい場合

```java
@GetMapping("/custom-length")
public ResponseEntity<String> customLength() {
    String body = "Hello, world!";
    HttpHeaders headers = new HttpHeaders();
    headers.setContentLength(body.getBytes(StandardCharsets.UTF_8).length);
    return new ResponseEntity<>(body, headers, HttpStatus.OK);
}
```

## 補足

`Spring MVC` の戻り値は、対応する `HttpMessageConverter` によって変換される。

`Content-Length` は変換後のバイト長がわかる場合は自動設定される。

ファイルやストリームなどは `chunked` になる場合もある。

必要に応じて `ResponseEntity` で手動指定も可能。

HTTPの仕様上、`Content-Length`と`Transfer-Encoding`は両立することはできないため、仮に両方が付与されていた場合は、`Content-Length`ヘッダを優先するということになっています。
アプリ審査のリジェクトリスクを軽減しよう

# 概要
アプリ審査の対策をできそうなアイディアを思いついたのでメモ

# 用意するもの
- お好きな AI ツール
- アプリレビューガイドライン
  - [App Review Guidelines](https://developer.apple.com/app-store/review/guidelines/)
  - [Google Play デベロッパー プログラム ポリシー](https://play.google/developer-content-policy/)（今回は利用していません）
- 適当なプロンプト

# 検証
今回は Gemini の Gem を利用しています。

## Gem の作成
適当な名前を決めて、カスタム指示でレビューガイドラインに準拠したレビューを依頼します。

![create a gem](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476381/45f9c2bf-e73b-4e35-b777-b00b9d5409a9.png)

### 利用したカスタム指示
```text
あなたは App Store Connect から提出されるアプリを審査するレビュワーです。

以下の App Review Guidelines を熟知しています。
- https://developer.apple.com/app-store/review/guidelines/

入力された画像に対して、ガイドラインの基準を満たしているかどうかを厳しくチェックして、具体的な指摘をしてください。
また、ガイドラインには明記されていなくても、怪しそうな箇所を見つけた場合はその点にも触れてください。
```

## デザインをチェックしてもらう
任意のアプリ画面を添付して質問してみます。

![ask](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476381/305c46e5-bd6f-49a6-af58-f59bb1b242f5.png)

## 回答

この画像はアプリ内でのサブスクリプション購入画面を示すものと理解いたしました。App Review Guidelinesに照らし合わせ、以下の点がガイドラインに抵触する、あるいは懸念される要素となります。

### App Review Guidelines への抵触および懸念点

#### 1. 明確なガイドライン違反: 誤解を招く価格表示

* **ガイドライン関連:** 2.3.6 (Accurate Metadata), 3.1.1 (In-App Purchase), 3.1.2 (Subscriptions)
* **指摘内容:** 年間サブスクリプションの価格が「$69.99/yr」と表示されていますが、その下にある「Save 19% (only $69.99/mo)」という記載が著しく誤解を招きます。年間69.99ドルを12ヶ月で割った月額換算は約5.83ドルとなるはずです。しかし、ここでは1ヶ月あたり69.99ドルかのように表示されており、実際の月額換算価格と大きく乖離しています。このような不正確で誤解を招く価格表示は、ユーザーの購買判断に不正確な情報を提供することになり、ガイドラインに明確に違反します。

#### 2. 懸念される点（改善推奨）: 無料トライアルとサブスクリプションの遷移の明確さ

* **ガイドライン関連:** 3.1.2 (Subscriptions)
* **指摘内容:** ボタンのテキスト「Try Free and Subscribe」について、無料トライアル期間終了後に自動的に課金が開始されることが「Cancel anytime」という表記で補足されています。しかし、「Try Free, then Subscribe」や「Start Free Trial」など、無料期間があること、そしてその後にサブスクリプションに移行することをより明確に示す表現の方が、ユーザーにとってさらに分かりやすいでしょう。これは必須の修正ではありませんが、ユーザーエクスペリエンス向上のために検討することを推奨します。

### 結論

最も重大な問題は、年間サブスクリプションにおける**誤解を招く価格表示**です。これはApp Review Guidelinesに明確に違反しており、このままでは承認できません。速やかに正確な価格表示に修正してください。

上記の修正が行われた後、再度審査のために提出してください。


# まとめ
- 実際に審査でリジェクトされる前に、レビューガイドラインの観点でデザインのフィードバックをもらえる

副次的に...
- リジェクトされた後のデザイン作成や実装修正等のコストを軽減
- エンジニアのガイドラインの習熟度に依存しないレビューが可能
- しっかり作り込んでもらったデザインをガイドラインで叩かなくて済む（エンジニア）

他にレビュワーにしたら良さそうなもの...
- [ザ・ダークパターン ユーザーの心や行動をあざむくデザイン](https://amzn.asia/d/0t1zv5v)
- [ウェブアクセシビリティ導入ガイドブック](https://www.digital.go.jp/resources/introduction-to-web-accessibility-guidebook)
Entra IDのセキュリティグループをPowerShellで作る

# 動機
Entra ID で、セキュリティグループをそれなりに数作らなくてはいけなかったが、一気につくるわけではないしと、Entra管理センターでぽちぽちとやっていたら、辛くなってきたので、PowerShellでやることにした

# 使うことにしたコード
:::note Info
環境
* PowerShell 7.5
* Microsoft Entra PowerShell モジュール 1.0.7
:::

```PowerShell:New-EntraGroup/Add-EntraGroupOwner
# 基本的に単発なので、Excelで下記のとおり作成するグループごとに作る予定
New-EntraGroup -DisplayName "グループ名" -MailEnabled $false -SecurityEnabled $true -MailNickname "NotSet" | Select * | %{Add-EntraGroupOwner -GroupId $_.Id -OwnerId '所有者にしたいユーザーのObjectId'}

```

https://learn.microsoft.com/en-us/powershell/module/microsoft.entra/new-entragroup?view=entra-powershell


https://learn.microsoft.com/en-us/powershell/module/microsoft.entra/add-entragroupowner?view=entra-powershell

# 反省
* Preview版のEntraモジュールが入れっぱなしだった
* AzureADモジュールが入っていたおかげで、競合していたらしく、`-GroupId` `-OwnerId`では通らず、`Add-EntraGroupOwner -ObjectId GroupID -RefObjectID UserID`としないといけなくて、調べるのにかなり時間をかけてしまった。

# ついでに
DisplayNameでグループを絞り込みかけるときは、前方一致で以下の通りした。Containsはサポートしていないので、部分一致したい場合は、一度全体を取得した後、絞り込みかける必要あり。

```PowerShell:Get-EntraGroup
Get-EntraGroup -Filter "startsWith(DisplayName, 'prefix')"

```
Macのデフォルトbashとサーバーのbashは挙動が異なることがある

### 概要

今日、シェルスクリプトをサーバーにデプロイしたところ、とある箇所で何故か`exit 1`で終了してしまうコードがありました。
ローカルMacでは正常に終了することを確認していたので、わからなかったのですが調べて分かったことがあったので記録しておきます。

### 先に結論

MacOS15.4.1だとbashバージョンが低く（3系）、サーバーにインストールされているbashバージョン（AmazonLinuxやDebian12だと5系）と異なることで挙動が変わるので注意。
bashバージョンがサーバーと異なる場合は、homebrewでbashをインストールして挙動を確認しよう。

### MacOSバージョン

- 15.4.1

### コード

`set -e` で戻り値が0でなければ、終了することを想定しています。
`[[]]`は正規表現を使うために使用し、正規表現がマッチしなければ終了、マッチしたら`echo`を実行することを想定しています。

```sh
#!/bin/bash

set -e

[[ "hoge" =~ "fuga" ]]

echo 'ok'

```

Macで実行してみます。

```sh
$ /bin/bash -x /tmp/test.sh
+ set -e
+ [[ hoge =~ fuga ]]
+ echo ok
ok

$ echo $?
0
```

`set -e` により、戻り値が0以外なら終了するのですが、当該bashでは `[[]]`の戻り値では判定されず、その後の `echo`が実行されています。

同一のコードを `Debian 12`で実行してみます。
※Debian12では`/bin/sh`のシンボリックリンク先が `dash`だったため、フルパスでbashを指定してます。
※Macも `/bin/sh` は `bash` になっているので注意

```sh
$ /bin/bash -x /tmp/test.sh
+ set -e
+ [[ hoge =~ fuga ]]

$ echo $?
1
```

この通り結果が異なります。

### 理由

bashのバージョンが異なるためです。
バージョン4系から `set -e` および `[[]]` の挙動が異なるようです。
※残念ながら日本語の公式ドキュメントを見つけられず、挙動が変わった正確なバージョンについては不確かです。英語ドキュメントでそれらしい情報があったものの、引用は避けています


Debian
```sh
$ /bin/bash --version
GNU bash, バージョン 5.2.15(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2022 Free Software Foundation, Inc.
```

Mac(default)
```sh
$ /bin/bash --version
GNU bash, version 3.2.57(1)-release (arm64-apple-darwin24)
```

Mac(homebrew)
```sh
$ /opt/homebrew/bin/bash --version
GNU bash, バージョン 5.2.37(1)-release (aarch64-apple-darwin23.4.0)
Copyright (C) 2022 Free Software Foundation, Inc.
```

```sh
$ /opt/homebrew/bin/bash -x /tmp/test.sh
+ set -e
+ [[ hoge =~ fuga ]]

$ echo $?
1
```

homebrewでインストールしたbashは5系でDebianと同一の挙動になりました。

### まとめ

bashバージョンにより、`set -e` および `[[]]` の挙動が異なることがわかりました。
homebrewで最新版をインストールすることで、サーバーバージョンに近いバージョンをインストールできるので、homebrewでインストールしておくのが良さそうです。