OmniAICreator/Qiita-1.07M huggingface dataset:
Docusaurus でインライン TOC (Table of Contents) を表示させる


## はじめに

Meta社が管理する React ベースのドキュメント管理ツール Docusaurus 。

Docusaurus は Markdown (`.md`) に加えて MDX (`.mdx`) も表示可能です。
MDX でドキュメントを書くことで ドキュメント内に React Component も表示可能になります。

今回は、標準で用意されている Inline TOC (Table of Contents)を表示させる方法を記載します。

## ドキュメントの用意

インライン TOC を表示させたいドキュメントを用意します。
すでに Markdown 形式でドキュメントを書いていた場合は拡張子を `.md` から `.mdx` に変更してください。

```mdx:docs/test.md
# 見出し1

これは Docusaurus の Inline TOC のテストのためのドキュメントです。

## 見出し2_1

見出し2_1 のテキスト

## 見出し2_2

見出し2_2 のテキスト

## 見出し2_3

見出し2_3 のテキスト

## 見出し2_4

見出し2_4 のテキスト
```

## Inline TOC を表示させる定義の追加

用意済みのドキュメント (`docs/test.md`) に `TOCInline` 表示用の Component を import します。

```mdx
import TOCInline from '@theme/TOCInline';

<TOCInline toc={toc} />
```

```mdx:docs/test.md
import TOCInline from '@theme/TOCInline';

# 見出し1

これは Docusaurus の Inline TOC のテストのためのドキュメントです。

<TOCInline toc={toc} />

## 見出し2_1

見出し2_1 のテキスト

## 見出し2_2

見出し2_2 のテキスト

## 見出し2_3

見出し2_3 のテキスト

## 見出し2_4

見出し2_4 のテキスト
```

下記スクリーンショットのように Inline TOC が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55950/59156a8a-ff12-aa43-3255-1ba1a3ba3eb5.png)

## さいごに

今回は Inline TOC の説明だけに留めましたが、自身で React Component を定義することでドキュメントをよりリッチにすることも可能です。

https://docusaurus.io/docs/markdown-features/react

## Ref

https://docusaurus.io/docs/markdown-features/toc#inline-table-of-contents
Strong Parametersの重要性

この記事は東京海洋大学NePPの Advent Calendar 2024の6日目です。

# はじめに
こんにちは！
私がStrong Parametersについて学んだことのアウトプットの機会として
この記事を書きました。

あくまで個人的な見解ですので、あしからずご容赦ください。



# Strong Parametersとは
Strong Parametersは、ユーザーからのリクエストの際に悪意のあるパラメータに対するセキュリティを強化するためのものです。
ユーザーから送られてくるリクエストの中のパラメータに指定した値のみをDBに保存することを可能にするものです。(指定外の値は保存されない。)
これによって、悪意のあるユーザーが不正な値をパラメータに含んでリクエストを送ってきても、DBに保存されず、無視することができます。

# Strong Parametersがなぜ必要なのか
結論から言うと、Mass Assignmentの脆弱性を防ぐためです。

## 例
Railsでは、フォームやAPIリクエストから送られてきたデータを、一括でモデルに割り当てる「Mass Assignment」という仕組みがあります。

```
@user = User.new(params[:user])
```

このコードは、送信されたparams[:user]のすべての値を、Userモデルのフィールドに対応付けて保存しようとします。ですが、このままだと以下のような脆弱性が発生します。

```
{
  "user": {
    "name": "Hashimoto",
    "email": "Hashimoto1111＠.com",
    "admin": true
  }
}
```
例えば上記のようなリクエストが送信されると、adminフィールドがtrueに設定されてしまい、攻撃者が管理者権限を取得する可能性があります。


## 解決策

ここで出てくるのが
**Strong Parameters**です！明示的に許可されたフィールドだけをモデルに渡すことで、この脆弱性を防ぐことができます。
この場合はnameとemailのパラメータのみをモデルに渡すことができます。

```
def user_params
  params.require(:user).permit(:name, :email)
end

@user = User.new(user_params) 
```

# おわり

ここまで、なぜStrong Parametersが必要なのかということに触れてきました。
このように、なぜその実装が必要なのかやなぜその実装が必要になったのかという背景を理解できるととても理解力が上がると思います！
くも膜下出血になったElixirプログラマーの一年後

昨年の9月に「くも膜下出血」で手術しました

https://qiita.com/t-yamanashi/items/1d563a83d2713dccf669

https://qiita.com/t-yamanashi/items/32501ea9313af4e62faa

# 現在仕事
- 順調に回復してElixirの仕事を0.5人月してます
- 今月から0.75人月と徐々に増やして行きます
- 近いうち1人月にしたい(相手先の予算関係もあるので) 

# 仕事時系列
- 1〜2月は入院中
  - 少しだけ仕事もしてました
  - 趣味でもプログラム組んでいました
- 3月〜8月退院後
  - Brightの開発
- 今 
  - Elixir教材系の仕事をしてます

# もし、フリーランスでなかったら…
多分、絶望的だったと思う
会社員だったら復帰厳しいかもね
今は病気の関係で免許返しているため物理的に運転できないから通勤が制限される
IT系+フルリモートで救われた

# どうやって回復を加速したか
- ほぼ毎日プログラムを打つ
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/b38366c5-be8f-ac62-31f3-38e8e667d78f.png)

- ほぼ毎日ジムに行く
- 食事を気にした
  - 結果:血圧低下した
- ストレスの貯まる物を徹底的に排除した


# 退院後でも成長できた事
Elixirのノウハウを地味増やして行きました
成長グラフ見るとわかります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/7352f6ba-d681-18c8-2776-ddb87a8f1378.png)

時間がある時は調べごとをしてました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/0099ff1b-bba4-bbef-1b42-e9f90c1a5b34.png)

# 一番効果ある回復
好きでパソコンいじったり、プログラムを書くことであります
歯医者がうっかりマナビDXクエストに挑戦してみた

# はじめに
おはようございます。座禅いぬと申します。歯医者をやっております。  
本記事は[マナビDX Questで得たもの Advent Calendar 2024](https://qiita.com/advent-calendar/2024/manabi-dx-quest2024)　13日目の記事です！

今回、経済産業省主催のDX人材育成イベント「マナビDXクエスト」に参加、無事<b>ゴールド修了、コミュニティ貢献賞を受賞</b>しました。その勢いで自社DXにチャレンジしています。素人ながら挑戦したこと、そして得たものを活かしてこれから挑戦していくことについて体験を共有したいと思います。

# そもそも歯医者にDXとか必要なの？
当初僕は必要ないと思っていました。歯を削ったり検査をして検査結果を説明するという業務の中で、そりゃカルテや資料をデジタル化したら便利かもしれませんが、別に紙カルテで何も困らないわけです。

元々先代が、「データをもとにむし歯や歯周病の重症化を予防したい」という思いから検査結果を専用アプリに入力し、データを集計してエクセルなどで分析する文化があり、「ツールの導入だけでなく分析までしているんだから十分先進的だろう」という程度の認識でした。

# 挑戦した背景：コロナ禍での環境の激変
大きな変化が訪れたのは2020年のことです。新型コロナ感染の拡大により、歯科医院経営は大きな打撃を受けました。

当初感染源がはっきりせず検査もない状況で、唾液の飛沫で感染するリスクを最小限にするため、状況がわかるまで緊急性が高い処置以外を可能な限り避けることに決めました。スタッフもチーム分けし、交代で出勤することにより全員が感染しないように工夫するなど、様々な対応を行いました。

![medical_ppe_syoudokueki.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/850275/c45648b3-ff05-9a44-b6ac-38b0d8ee3082.png)

物理接触を避けるための仕組みの必要性が高まってきました。さらに日々厳しくなる環境によってスタッフの離職が続き、業務の効率化が必要になりました。そこで、今までやったことがないプログラミングを習得することを決意、python、ウェブフレームワーク、SQLやクラウドを学ぶことで業務アプリの内製化を行いました。

アプローチは成功し、かなりの工数削減を達成しましたが、そうこうしているうちに初診患者数が激減。おそらく物理的なクチコミが断絶したことによるのでしょう。さらに、物価・人件費がどんどん上昇する中で、保険診療の医療費は変化が遅いため、潜在的な経営危機に陥る恐れがでてきました。そこで、<b>①データ分析による経営打ち手の検討、②さらに高度な技術による業務の効率化</b>が必要になってきました。

# 挑戦したこと：AIによる外観検査の自動化!


実は歯科の業界でもDXは話題になっていたのですが、実際のところ本質的な変容は難しいため、ツールや機器の導入の話が多いという印象でした。経済産業省のDXレポートなどを読んでいると「このままではだめだ」という気持ちが強くなる一方だったのですが、そんな中で出会ったのが「マナビDXクエスト」でした。

マナビDXクエストでは、PBL(課題解決型学習の意味）と呼ばれるケーススタディを受講生が選択してチャレンジする形式をとっています。僕は「やったことがない画像分類にチャレンジしたらより成長できるのでは？」と考え、外観検査の課題を選択しました。

課題資料で<b>「やや難易度が高いテーマです」という文字を見たときには一瞬後悔</b>しましたが、無事修了することができました。

それもうれしかったのですが、何よりも価値を感じたのは仲間を得ることができたことです。DXに関する悩みや、今勉強していること、異業種でのノウハウや、別の勉強会で学んだことなど、毎晩のように色々な情報共有をすることができ、それを継続することができています。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/850275/3ca179b3-1549-e1d2-78ec-0797ce48d9fd.png)

また、上記画像でも触れているコミュニティマスターの皆さんは本当にすごい方々です。サポートしてくれるだけではなく、「この人のようになりたい！」という道標となってくれるような存在がいることで、学ぶ技術に現実味を感じました。勉強会を開いていただいたり、毎日のように声をかけていただいたり、わかりやすい説明をご自身の事例を交えてしていただいたりで、いくら感謝をしてもしきれないです。


# 挑戦すること：歯科領域での診断補助AI、企業協働etc

さて、どんなに苦労して出来ることが増えたとしても使わなかったら遊びです。早速自社で外観検査AIを応用できるか、PBLでやった手順通りやってみることにしました。<b>マナビDXクエストの素晴らしい点は、この「次は本番でやってみる」を前提に作られたと思われる実践性の高</b>さです。

PBLの手順がそのままフレームワークとして機能してくれるので、実際に自社でヒアリング、要求定義、要件定義、計画立案などを進め、<b>現在PoC（概念実証）としてPyTorchでモデル構築を行っています。</b>使用するコードもPBLで学んだことをベースに作れるようになりました。3か月前にはPyTorchとPyCharmの区別も怪しかったのに、ずいぶん成長できたものだと感じます。

内容としてはX線写真などの画像を利用した診断補助AIです。PBLと違うのは実際のデータである、というところぐらいだと思います。[医療デジタルデータの AI 研究開発等への利活用に係るガイドライン](https://www.mhlw.go.jp/content/001310044.pdf)などを参考に適切な運用を考えています。年内にPoC、年明けから実装に向けて動きたいと思っています。

さらに同時進行で、企業協働プログラムにも参加しています。これも驚異的なプログラムで、<b>実際の企業にデータをいただいたり、分析して提言をする機会をもらえます。</b>チームで参加するので、ここでも学び合いが発生したり、コミュニケーションのための技術など色々なことを学べる仕組みです。

他にも毎週のように勉強会がMetaLife上であったり、外部のデータサイエンス系の研修などにもチャレンジしています。次はLTも挑戦してみたい！と思っています。たぶんやります。仲間がいるので。

# 最後に伝えたいこと
### 自分のスキルの有無にかかわらず、やりたいなら飛び込むべき！
決して簡単ではないですが、不可能なことはないと思います！できるようになりたいことがあるなら、不安など無視して「うっかり」ぐらいの気持ちで飛び込めば人生が変わるような体験ができると思います。<b>気になってるなら、絶対参加するべきです！</b>
今更だがvalid?, invalid?のプロセスを誤解していた件

# 概要
業務で`ActiveModel::Validations`を`mix-in`したカスタムモデルでのレコード作成処理を実装しました。

その際に`valid?`, `invalid?` メソッドの挙動を履き違えていたことに気がついたため、自戒の念を込めて本記事の執筆に至りました。

# 該当処理

以下ユーザーの作成処理を担うカスタムモデル（サンプル）です。

```ruby
class CreateUser
  include ActiveModel::Validations

  attr_reader :name, :password

  def initialize(name, password)
    @name = name
    @password = password
  end

  def call
    # 任意の処理
    # ...

    # 問題があった場合にerrorsに追加
    errors.add(:base, '~が不正です')

    return if invalid?

    User.create!(
      name:,
      password:
    )
  end
end
```

# 当時の認識

当時の私は以下のような流れになると思っていました。

1. `valid?`, `invalid?` メソッドの実行
1. `validation`メソッドが実行
1. `errors` オブジェクトに値が格納されているか検証され、その結果が返る


# 実際の挙動

実際の挙動は以下になりました。

1. `valid?`, `invalid?` メソッドの実行
1. `errors` オブジェクトがクリアされる
1. `validation`メソッドが実行
1. `errors` オブジェクトに値が格納されているか検証され、その結果が返る

そのため、以下の`errors.add`で格納された情報は、後続の`invalid?`の実行によって`clear`されます。
結果、無効なデータはないと判断され、ユーザー作成処理が実行されます。

```ruby
# 問題があった場合にerrorsに追加
errors.add(:base, '~が不正です')

return if invalid?
```

# Source
`ActiveModel::Validations`のソースコードを確認しました。
`errors.clear`されることがわかりますね.

```ruby
def valid?(context = nil)
  current_context = validation_context
  context_for_validation.context = context
  errors.clear
  run_validations!
ensure
  context_for_validation.context = current_context
end

def invalid?(context = nil)
  !valid?(context)
end
```

ref. 

https://github.com/rails/rails/blob/main/activemodel/lib/active_model/validations.rb#L361

# まとめ
以上です。
本記事の内容について、認識齟齬などあればコメントいただきたいです🙏
Supabase Auth (local-development) 経由で送信されるメールタイトル・本文を変更する


## はじめに

Supabase Auth にはログイン認証時などメールを送信する機能が存在します。
デフォルトのままでも十分使用できますが、ローカライズしたり説明など本文やタイトルなどを変更を必要となる場面が少なからず発生します。
サイト上で動作しているときは Console から変更すればよいだけですが、ローカル環境(local-development)だと所定のファイルを変更し適用する必要があります。

## Supabase の設定ファイルについて

`supabase init` を実行すると `supabase/config.toml` が作成されます。
Supabase Auth 利用時に送信されるメール本文変更もこの設定ファイルに追記します。

## 設定変更可能なメールテンプレート

設定可能なメールテンプレートは以下の通りです。

- auth.email.template.invite
- auth.email.template.confirmation
- auth.email.template.recovery
- auth.email.template.magic_link
- auth.email.template.email_change

## テンプレート内で使用可能な変数

テンプレート内で利用可能な変数は下記ドキュメントに記載されています。
使用するテンプレートによって使用可能な変数も異なりますので検証しながら利用してください。

https://supabase.com/docs/guides/auth/auth-email-templates

## テンプレートを定義する

今回は、 `auth.email.template.invite` のメールテンプレートを独自に定義してみます。
Supabase の設定ファイル `supabase/config.toml` に追記後 `supabse stop && supabase start` で適用することができます。

### HTML ファイルを用意する

送信メールの HTML を定義します。
TXTメールは定義しませんが、定義された HTML からテキスト部分を抜き出し multipart メールとして送信してくれます。

ファイル名の指定はありませんが、わかりやすいように `supabase/templates/invite.html` とします。

```html:supabase/templates/invite.html
<h2>招待メール</h2>
<p>招待メール本文</p>
```

### Supabase の設定を変更する

`supabase/config.toml` に `auth.email.template.invite` のメール送信時に使用するテンプレートとタイトルを記載します。

```toml
[auth.email.template.invite]
subject = "招待"
content_path = "./supabase/templates/invite.html"
```

### Supabase local を再起動する

設定を適用するために Supabase のローカル環境を再起動します。

## Ref

https://github.com/supabase/supabase/blob/ad4de15b9e9a466b65b980a25d9ca3f9451ebdf4/apps/docs/content/guides/local-development/customizing-email-templates.mdx#L40

https://supabase.com/docs/guides/auth/auth-email-templates
Dockerを用いてIJONのセットアップを行う

# やりたいこと
IJONでファジングができる環境を整えること
また、IJONに必要なパッケージ等が非常に古くなっておりWSL等で動かそうとすると大体依存関係で問題が起こる
私が検証したときは
 - Ubuntu 24.04.6 LTSとUbuntu 22.04.6 LTSでは`clang-6.0`のインストールがうまくできない
 - Ubuntu 20.04.6 LTSでは`GLIBC_2.33`と`GLIBC_2.34`という比較的低レイヤーのライブラリを手動でインストールしなければならない
 という点で詰まってしまい、断念した。

時間を溶かす覚悟がある人は試してみてもいいかもしれない。
今回はDockerを用いてUbuntu16.04での環境構築の記事となる。
# 具体的な方法
1. Ubuntu 16,04のイメージをpullしてきて起動
    
    ```bash
    docker run -it ubuntu:16.04 /bin/bash
    ```
    
2. もろもろアップデート
    
    ```bash
    apt update
    apt upgrade
    ```
    
3. git インストール
    
    ```bash
    apt-get install git
    ```
    
4. homeディレクトリに移動してIJONのプロジェクトをgit pull
    
    ```bash
    cd home
    git clone https://github.com/RUB-SysSec/ijon.git
    ```
    
5. もろもろインスト
    
    ```bash
    apt install make
    apt-get install -y clang-6.0
    apt install clang
    apt install g++
    ```
    
6. 必要な環境変数を設定
    
    ```bash
    export AFL_NO_X86=1
    export LLVM_CONFIG=llvm-config-6.0 
    export CC=clang-6.0 
    export AFL_NO_X86=1
    ```
    
7. ijonをコンパイル
    
    ```bash
    cd ijon
    make
    ```
    <img width="2394.75" alt="スクリーンショット 2024-12-03 184332.png (376.8 kB)" src="https://img.esa.io/uploads/production/attachments/20311/2024/12/03/171224/d92710aa-f6ad-47d4-8aeb-116e19f6e9f2.png">

    
8. llvm_modeの中でもコンパイル
    
    ```bash
    cd llvm_mode
    make
    ```
    <img width="2858.25" alt="スクリーンショット 2024-12-03 184509.png (197.6 kB)" src="https://img.esa.io/uploads/production/attachments/20311/2024/12/03/171224/27016fdb-5dab-4a22-94c2-1999696bcd46.png">


# 完了！！！！！！！！！！！！！
Part2🤘🏻コピペOK🤘🏻GASを使ってSlackに当番通知する生産性向上をひっそり紹介します🫥

この記事は [ex-crowdworks Advent Calendar 2024](https://qiita.com/advent-calendar/2024/ex-cw)の8日目の記事です。

# はじめに
今年、株式会社クラウドワークスを退職した@nisyuuです。主食は[銀河のしずく](https://iwate-kome.jp/ginganoshizuku/)です。
エンジニアとしてクラウドワークステック（旧クラウドテック）というフリーランスと企業をマッチングするエージェントサービスを開発していました。

 [ex-crowdworks Advent Calendar 2024](https://qiita.com/advent-calendar/2024/ex-cw)の1日目に、GASを使った生産性向上の記事を投稿しました。
 今回は生産性改善Part2として、1日目に紹介した記事の内容を拡張するような内容を紹介します。

# 当番通知のタイミングを柔軟にする

当番を通知する条件に、2週間に1回や平日は毎日通知させたいけど土日祝日は通知させたくないといったこともあるのではないでしょうか。
そこで今回は、GASで平日の判定や祝日の判定を行う方法、カレンダーから指定の日に指定のイベント名があるかをチェックする方法を紹介します。


## 平日を判定する

土日の判定はこのようにできます。
特に変わった実装はないと思います。

下の関数では、指定の日が平日であればtrueを返すようにしています。

```javascript
/**
 * 指定の日付が平日か判定する
 * @param {Object} targetDate - 日付
 * @return {boolean} - 平日であるかの判定
 */
function isWeekday(targetDate) {
  const day = targetDate.getDay();  // 0 (日曜日) ～ 6 (土曜日)
  return (day !== 0 || day !== 6);
}
```

## 祝日を判定する

祝日の判定には、Googleカレンダーの祝日カレンダーを使用します。
実装時には祝日カレンダーのIDが必要で、祝日カレンダーの設定からIDは確認できます。

下の関数では、指定の日に祝日があるとtrueを返すようにしています。

```javascript
/**
 * 指定の日付が祝日か判定する
 * @param {Object} targetDate - 日付
 * @return {boolean} - 祝日であるかの判定
 */
function isHoliday(targetDate) {
  // 日本の祝日カレンダーのIDを定義
  const holidayCalendarId = 'ja.japanese#holiday@group.v.calendar.google.com';
  const calendar = CalendarApp.getCalendarById(holidayCalendarId);
  // 祝日情報を取得
  const events = calendar.getEventsForDay(targetDate);
  return events.length > 0;
}
```

## 指定の日に指定のイベント名を取得する

指定の日に、指定のイベント名を含むイベントがあるかチェックします。
イベント名があると、trueを返します。

イベントのチェックにはカレンダーIDが必要で、自分のカレンダー設定からカレンダーIDを確認することができます。
補足ですが、IDはメールアドレスになっていることが多いようです。

```javascript
**
 * 指定の日に指定のイベント名があるか判定する
 * @param {Object} targetDate - 日付
 * @param {Object} targetEventName - イベント名
 * @return {boolean} - 指定のイベントがあるかの判定
 */
function haveTargetEvent(targetDate, targetEventName) {
  const calendarId = 'xxxxxxxxxxxxxxxxxxx'; // カレンダーID
  let calendar = CalendarApp.getCalendarById(calendarId);
  var events = calendar.getEventsForDay(targetDate);

  for (i = 0; i < events.length; i++) {
      if(events[i].getTitle().includes(targetEventName)) {
        return true;
      }
  }

  return false;
}
```

# おわりに
通知のタイミングをカレンダーの日程や曜日に合わせて細かく調整したくなることは、よくあるケースなため紹介してみました。
通知のカスタマイズについて拡張アイデアをまだまだ持っているので、アドカレでまた後日紹介します。
Part3を乞うご期待ください。
HULFTで選択できるホスト種について

この記事は [**セゾンテクノロジー Advent Calendar 2024**](https://qiita.com/advent-calendar/2024/saison-tech) 9日目の記事です。
シリーズ2は [**HULFT10**](https://www.hulft.com/software/hulft-10) のエンジニアによる投稿をお届けします。
　

# 前書き
　初めに、HULFTってどういうイメージでしょうか。

　おそらく昔から使われてるというものが第一イメージかと思います。
　昔からあるがために、所々に昔ながらの部分が残っています。

　今回のHULFT10はZ世代(ざっくり若者くらいの意味です)の層にも触れやすいHULFTをというテーマで、表記の見直しを行いました。
　その中でも今回は、ホスト種周りの話を少ししようと思います。
 

# 8までのHULFT
  　早速ですが、HULFT8までのホスト種って、何が選べるかというと、下の画像のようなものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945895/ba2ab146-5274-e8b3-6395-25d73b09b401.png)
　正直に言うと、初めてこの項目値を見た時「？」が浮かびました。
　補足ですが、初めてHULFTに触れた時IT知識はほとんどなく、OSの知識はほとんどありませんでした。

 　
  色々ありますが、主に私が感じた違和感をまとめます。
  - 「WindowsNT」？
  - 「AS/400」？
  - 「Linux」は無いのかな？

 HULFT10ではこの辺りの違和感を払しょくするようになっています。

# 10からのHULFT
　10でのOSの一覧はこんな感じです。
 
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945895/0aea14e6-5bf8-53e7-7c22-938eb69e2ba8.png)

 　旧表記と新表記の差分はこんな感じになってます。
|旧表記       |新表記|
|:-----------------|:------------------|
| 「WindowsNT」 |  「Windosw」|
| 「UNIX」 |  「Linux/UNIX」|
| 「AS/400」 |  「IBMi」|
| 「K」 |  廃止|

簡単にそれぞれどうなったかを説明します。

# Windows系の表記
　詳しい方ならご存じでしょうが、今のWindows11のようなOSはWindowsNT系列からの発展です。
　では、8までの「Windows」は何を示していたかというと、Windows 9x系です。具体的に言うと、Windows 95などです。
 　今Windowsというと、WindowsNTからのものなので、選びやすいように「Windows」表記に統一しました。

# LinuxやUNIXの表記
　HULFTが開発されたときはUNIXがメインでしたが、今はLinuxが主流かと思います。ですがUNIXも無視できませんので、「Linux/UNIX」の両方の表記になっています。

# IBMiの表記
　8までは、HULFTの製品名には「HULFT For IBMi」のように、IBMiと記載していましたが、ホスト種に関しては昔ながらの言い方の「AS/400」が採用されていました。
　HULFT10ではこちらも「IBMi」に統一させていただきました。

# Kの廃止
　HULFT10では通信保証外OSとなりましたので、「K」は廃止になりました。

# 少し小話
　この話し、表記の修正だけに見えますが、実際には表記を変えることの影響が他の機能に影響がないかを確認したり、既存部分からの修正が最小限になるように設計を考えたりするのに苦労しました。特に、HULFTは他の製品との接続性や旧バージョンの互換など考慮することが多いのでこういった調査は地味に時間がかかります。
　ただ表記を変えるだけなのに、設計書を書き上げるだけで1か月以上かかったのは流石に驚きました。まだまだ力不足だなぁと痛感しました。

 # まとめ
　HULFTは昔から使われている製品のため、開発当時では需要の大きかったOSが今では撤退したり、表記が変わることはよくあります。サービス型の商品ですとここら辺の修正は柔軟に対応できるのですが、HULFTのようなパッケージ商品ですと、お客様に手に取ってもらえる一番のタイミングはバージョンアップですので、ここで変えるのが区切り良いのかと思います。
　今後のHULFTもこういった違和感があるような表記は変えていき、若い人でも親しみやすいHULFTを開発していきますので、よろしくお願いします。
PythonでNeo4Jに接続しようとしたら怒られた

# 事象

GraphRAGなどというものに挑戦してみようと思い、pythonからneo4jに接続を試みた

```
url = "bolt://172.18.0.1:7687"
username ="hoge"
password = "fuga"
graph = Neo4jGraph(
    url=url,
    username=username,
    password=password
)
```

結果、以下のようなエラーが発生
```
Traceback (most recent call last):
  File "/root/.pyenv/versions/3.11.0/lib/python3.11/site-packages/streamlit/runtime/scriptrunner/script_runner.py", line 584, in _run_script
    exec(code, module.__dict__)
  File "/home/volume/knowledge-graph_rag/langchain-examples/all-in-one/pages/7_Graph_RAG.py", line 19, in <module>
    graph = Neo4jGraph(
            ^^^^^^^^^^^
  File "/root/.pyenv/versions/3.11.0/lib/python3.11/site-packages/langchain_community/graphs/neo4j_graph.py", line 367, in __init__
    raise ValueError(
ValueError: Could not use APOC procedures. Please ensure the APOC plugin is installed in Neo4j and that 'apoc.meta.data()' is allowed in Neo4j configuration 
```

その時のNeo4JのDockerCompose
```
services:
    neo4j:
      image: neo4j:latest
      tty: true
      ports:
        - 7474:7474
        - 7687:7687
      volumes:
        - ./neo4j/data:/data
        - ./neo4j/logs:/logs
        - ./neo4j/conf:/conf
      environment:
        - NEO4J_AUTH=none
```

# 対応策
apocプラグインを有効化する
具体的には以下を行うことで無事解決した

## プラグインのインストール
以下からallinのjarを取得してpluginディレクトリに格納

https://github.com/neo4j-contrib/neo4j-apoc-procedures/releases/4.1.0.11

## 設定ファイル修正
neo4j.confに以下を追記
```
dbms.security.procedures.unrestricted=gds.*,apoc.*
```

## docker-compose.yml修正
修正後
```
services:
    neo4j:
      image: neo4j:latest
      tty: true
      ports:
        - 7474:7474
        - 7687:7687
      volumes:
        - ./neo4j/data:/data
        - ./neo4j/logs:/logs
        - ./neo4j/conf:/conf
        - ./neo4j/plugin:/plugin # この行追加
      environment:
        - NEO4J_AUTH=none
        - NEO4JLABS_PLUGINS=["apoc"] # この行追加
```

ドキュメントを見ると、環境変数として追記したものがあればプラグインの物理的格納はいらないのでは？という気もするが確かめてはいない
web-featuresのベースラインステータスをサイトに表示する

[`web-features`](https://web-platform-dx.github.io/web-features/web-features/)はWeb全体の機能の共通カタログを構築する取り組みです。
`web-features`のプロジェクトの1つにBaselineの制定があります(Baselineついて詳しく知りたい方は[ドキュメント](https://github.com/web-platform-dx/web-features/blob/main/docs/baseline.md)を参照してください)。
BaselineはApple Safari、Google Chrome、Microsoft Edge、Mozila Firefoxの4つの主要なブラウザで動作するWebの機能に関する情報を提供するものです。

下の画像のようにMDNでWebの機能のページを開いたときに、青色で囲んだ部分に表示されているものです。

![スクリーンショット 2024-12-06 10.03.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/d58f83b0-9997-d485-b92e-e31a72464ab8.png)

Baselineには`Widely Available`と`Newly Available`の2つの段階があります。また、Baselineにない機能の段階として`Limited Available`があります。

`Widely Available`は、Baselineのブラウザで一貫してサポートされてきた機能を指します。

`Newly Available`は、少なくともBaselineのブラウザの最新版でサポートされた機能です。`Newly Available`を示す際は多くの場合対応した年が共に添えられています。最新のブラウザ群では動作しますが、少し前のブラウザやデバイスでは機能しないこともあるので注意が必要です。

`Limited Available`となる機能はBaselineにはありません。Baselineの一部、もしくは全てのブラウザの最新版でサポートされていないことが多く、限定的に利用できます。

このようなBaselineのステータス(`Limited Available`も含めます)を表すコンポーネントはWeb Componentとして提供されています。

https://github.com/web-platform-dx/baseline-status

使い方はnpmとしてインストールして組み込むか、CDNを読み込むかです。
```command
npm install baseline-status
```
```html
<script src="https://cdn.jsdelivr.net/npm/baseline-status@1/baseline-status.min.js" type="module"></script>
```

いずれかの準備ができたら、以下のように`baseline-status`要素として宣言することでBaselineのステータスを表示させられます。
```html
<baseline-status featureId="async-await"></baseline-status>
```

`featureId`は表示したいWebの機能のIDです。`featureId`は[web-featuresのリポジトリ内の`features`](https://github.com/web-platform-dx/web-features/tree/main/features)から選択します。

以下が利用例です。

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

お手軽にWeb機能のベースラインのステータスを表示させられるので、便利ですよね。
Qiitaでも表示できるようになると、助かります🙏
AWS Lambdaのトリガー上限数

## はじめに
Lambdaにロググループとか色々トリガーとして設定することが多いと思います。
今回はトリガーの上限数についてまとめて行こうかなと思います。

## Lambdaとは
AWSが提供しているサーバレスコンピューティングサービス。
EC2とは違ってオペレーションシステム（OS）などの管理が不要で、開発者がコードを書くことに集中できるメリットがあります。

## トリガーとは
AWS Lambda関数を実行するきっかけとなるイベントのことを指します。
トリガーの設定をしてあげるとUIにトリガー数が表示されます。

## トリガーの上限
ただ、トリガー何個も何個も設定できるものではなくて上限が存在します。
Lambda関数のリソースポリシーのサイズが制限値を超えてしまうとエラーになります。
上限値は20KBでクォーターを引き上げることもできない。（もし、上限に達したらもう一つLambdaを作る必要あり）

## おまけ
リソースベースポリシーをうまく設定して上げることでlambdaをもう一つ作らなくてもできます。
例えば1つのロググループにリソースベースのポリシーステートメントが紐づけされているのでワイルドカード型にしてあげると節約できます。
ただ、UIで表示されているものはリソースベースポリシーを見て反映されているのでワイルドカード型にするとUI上でどのリソースなどがトリガーに
なっているかは確認できない罠があったりします。

## 公式情報
AWS Lambda エンドポイントとクォータ
https://docs.aws.amazon.com/ja_jp/general/latest/gr/lambda-service.html

Lambda クォータ
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/gettingstarted-limits.html
Azureコンテナー レジストリにdockerデータをpushしたい。

Azureコンテナレジストリにpushしたときのメモ。

まず最初に
Azureのホームページにいってコンテナー レジストリを検索し、作成する。

https://zenn.dev/08thse/articles/63-acr-image-upload
https://www.softbank.jp/biz/blog/cloud-technology/articles/202302/azure-docker-2/

参照。
コンテナレジストリを作成した後、
```
az login
az acr login --name ＜コンテナレジストリ名＞
```
でログインする。
後はpushまではこういう感じで
```
docker pull mcr.microsoft.com/hello-world

docker tag mcr.microsoft.com/hello-world <login-server>/hello-world:v1

docker tag mcr.microsoft.com/hello-world mycontainerregistry.azurecr.io/hello-world:v1

docker push <login-server>/hello-world:v1
```

削除は
```
docker rmi <login-server>/hello-world:v1
```
ルールベース戦略+MLフィルターが機能する条件は？

# はじめに
以前こういうポストをしました。ちょっとしたメモ程度ですが、これについて整理します。
https://x.com/pip_pip_pip_p/status/1756614320786743712
![スクリーンショット 2024-11-30 1.54.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2414890/7b352dce-e1e1-f2e0-f984-06b1cc12dc6e.png)
ようは目的変数の分布が時期によって変わるとモデルが機能しないというだけ話です。
ただ、ルールベースで既に右上がりだと爆益に目が眩み、相場が変わる懸念を忘れてしまいがちです。

そこで、ここではMLフィルターがうまくいく条件を考えてみようと思います。
あくまで素人が考えることなので、温かい目でみていただけると助かります。

mlbotチュートリアルはこれのことです
https://note.com/btcml/n/nc5c63a9f5aa2

# ルールベース戦略
まず例としてmlbotチュートリアルで使われるルールベース戦略の良い点と改善したい点を見ます
詳しくは上のnoteをご参照ください

### 良い点：サンプルを豊富に取れる
たとえば伝統的なロジックのチャンネルブレイクアウトをMLでメタラベリングすることを考え、訓練データとして「直近N期間高値をブレイクしたときのローソク足」を集めるとします。これだと学習に十分なサンプルが集まりません。一方、mlbotチュートリアルのロジックはローソク足の数だけサンプルが取れます。


### 良い点：単純で強力
単純なので実装が楽。
単純なロジックなので、執行ロジックだけならフィッティングしている心配が少ない。
ML使わなくてもパラメータを数個調整するだけでバブル相場なら右肩上がりになる。

### 改善したい点：時期によって強さが異なる
2021年のバブル相場なら右肩上がりで、それ以外だと右肩下がりになります。
binance BTCUSDTでルールベースだけの損益はこんな感じです。2021年は上向きですが、それ以降はよくないです。上昇相場の2024年11月12月でも右肩下がりです。MLフィルターで上向きにしようとしても自分のような素人ではなかなか難しいです。
![スクリーンショット 2024-12-07 16.59.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2414890/82d35c5a-fb72-9a16-62cf-e0bdd6e3ef20.png)

mlbotチュートリアルでは特徴量の分布が時間で変化しないことをチェックしていますが、似たようなことを目的変数に対して行うといいかもしれません。


# ML用ルールベース戦略にあると嬉しい性質

MLでメタラベリングする用のルールベース戦略に嬉しい性質をまとめてみます
以下のような性質があると嬉しいのではないでしょうか。
>①サンプルが豊富
>②目的変数がどの時期でも分布が同じ
>③単純
>④強力

①は必須の性質。他はあると嬉しいというかんじ。
嬉しさは②＞＞＞③＞④という感じで、③④は全然なくていいでしょう

手前味噌ですが、私が動かしているbotの一つがルールベース+MLフィルターのmlbotで、ルールベースだけだと2021年含めてほとんどの期間右肩下がりです。が、これでもMLフィルターかませばだいたい右肩上がりになります。②の性質のおかげだと考えています。


## どうやって探す？
じゃあどうやって①と②の性質を持つルールベース戦略を考えればええねんという話ですが、ファイナンス機械学習で紹介されたトリプルバリア法など参考になるのではと思います。トリプルバリア法は少なくとも①をみたします

上であげたグラフの2022年以降はずっと右肩下がりなのでこの期間だけ学習すればもしやうまくいく！？と思って試しても、あまりに右肩下がりなのでどうしようもないです。Profit Factorが1に近いならよいかも

みんなもやってみてね！
文字起こしモデル Whisperの実行Libraryまとめ

## Whisper (Official)

https://github.com/openai/whisper

```
# on MacOS using Homebrew (https://brew.sh/)
brew install ffmpeg
pip install -U openai-whisper

whisper audio.flac audio.mp3 audio.wav --model turbo
```

## faster-whisper (処理速度が最大4倍改善。)

https://github.com/SYSTRAN/faster-whisper

```
# Unlike openai-whisper, FFmpeg does not need to be installed on the system. The audio is decoded with the Python library PyAV which bundles the FFmpeg libraries in its package.
# 翻訳: openai-whisperとは異なり、FFmpegをシステムにインストールする必要はありません。音声は、FFmpegライブラリをパッケージにバンドルしたPythonライブラリPyAVでデコードされます。

pip install faster-whisper
# CLIは標準サポートしてない   検索すると別repoで見つかる
```

## mlx-whisper (AppleSilicon向け。MLXを使ったもの。早いらしい。)

https://github.com/ml-explore/mlx-examples/blob/main/whisper/README.md

```
# on macOS using Homebrew (https://brew.sh/)
brew install ffmpeg
pip install mlx-whisper

mlx_whisper audio_file.mp3
```

## lightning-whisper-mlx　(一番早いらしい。日本語で試したけど対応してないのか、ダメだった。)

https://github.com/mustafaaljadery/lightning-whisper-mlx

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3361273/06e6e59f-74f3-aa5b-7f3d-f23c0aaf279e.png)
https://github.com/mustafaaljadery/lightning-whisper-mlx/blob/main/speed_image.png

```
pip install lightning-whisper-mlx

# CLIは標準サポートしてない
```

## Whisper.cpp (C/C++でPortingしたもの。比較がないので速度は不明。いろんなデバイスでWhisper動かしたい人向けかも)

https://github.com/ggerganov/whisper.cpp


https://zenn.dev/piment/articles/24269616aa9c04
新卒一年目なんてこんなもんや安心せいという話

### 初めに
初めまして。mediba新卒2年目のバックエンドエンジニアです。
今回は、1年目の時にぶつかった壁と対処法を記していきます。
こんなやつもおるんやなとか、同じ人間がいて安心したと感じて頂ければと思います。

### 筆者のステータス（学生の頃）
話を進める上で必要なので軽く晒していきます。

- 4年制専門卒
- 資格取りまくり（学校の方針）
- 賞もいくつか
- チーム開発のリーダーなんかもしちゃったり（二度とやらん）
- 地元のweb系の会社で長期インターン（2年間くらい。ほぼバイト）
- 実家暮らし（田舎）

という感じで、ぱっと見めちゃくちゃ出来る子でした。学生の頃は。
クラスの中でもトップの方にいたりしてました。学生の頃は。

そんな軽くブイブイ言わせていた私に、社会の鉄槌が下されます。

### ブイブイネキ、全ロス
私の頃は8月から実際の開発チームに配属されていました。
初めての社会人エンジニア。学生の頃の開発とは全く違いました。
会社によって勝手も違うので細かいことは書きませんが、景色が何もかも違うわけです。
学生の頃はなんでも出来たのに、手も足も出なくなって何も出来ない
あの4年間は、今まで積み上げてきたものは何だったんだと思うくらい、喪失感でいっぱいでした。
今思えば、出来なくて知らなくて当たり前だろという感じですが、当時は辛かったですね。


### 対処法
- 目の前にあるものをこなすことに専念する
  - やっていけば出来るようになると思い込む
  - 未来の自分に賭ける
- 周りの真似をする
  - タスクの取り方とかコードの書き方とか
- 新生活に慣れるの大変だしとか思っとく
  - 実際大変。特に上京組

### 終わりに
ペラッペラな内容でしたが、ブラウザバックせずここまで読んでいただきありがとうございます。
全ロスしても辞めずに踏ん張り続けていれば、全ロス前よりも強くなっているはずです。マイクラと同じです。
信じられるのは己のみ。以上元ブイブイネキでした。
UML図を入れたMarkdown形式のファイルをPDFに変換する

# はじめに

タイトルの通りですが、UML図を入れたMarkdown形式のファイルをPDFに変換する方法を記載します。

Markdownは開発者にとって非常に使いやすく、文書の記載や管理が簡単です。
しかし、顧客に提供する場合など、そのままではドキュメントとしては見づらい場合があります。
また、図を埋め込んだ場合、閲覧するためには特定のツールやプラグインが必要になり、利用者にとってのハードルが上がることがあります。

上記解決のため、MarkdownをPDFに変換することで、誰でも簡単に閲覧できるようになり非常に便利です。

# 環境

**OS**: M2 Mac
(他の環境の場合、コマンドの差分は公式サイト等で確認してください)

# 使うもの

- Mermaid (mermaid-cli)
    - テキストで手軽に図が書くためのツールです
    - PlantUML をご存知の場合、似たツールと思ってください

https://mermaid.js.org

- Pandoc
    - Markdown => PDF の変換を実現するためのツールです
    - 本記事では扱いませんが、その他様々な形式に対応しています

https://github.com/jgm/pandoc

- pandoc-ext/diagram
    - Pandoc で各種ダイアグラムを変換できるようにするための拡張です

https://github.com/pandoc-ext/diagram

- MacTeX
    - pandoc で(日本語を含む)PDFを生成するために TeX を利用します
    - MacTeX は Mac向けのTeX ディストリビューションです ([wiki](https://ja.wikipedia.org/wiki/MacTeX))

https://www.tug.org/mactex/


# 手順

## 1. 必要ツールのインストール
### Mermaid (mermaid-cli)

https://github.com/mermaid-js/mermaid-cli

```bash
npm install -g @mermaid-js/mermaid-cli
```

### Pandoc + MacTeX

```bash
brew install pandoc
brew install mactex

# パスを反映 (Terminal再起動でもOK)
eval "$(/usr/libexec/path_helper)"
```

### pandoc-ext/diagram

[GitHub](https://github.com/pandoc-ext/diagram) から `diagram.lua` をダウンロードします。

curl コマンドで取得する場合は以下
```
curl -o diagram.lua https://raw.githubusercontent.com/pandoc-ext/diagram/refs/heads/main/_extensions/diagram/diagram.lua
```

## 2. Markdown ファイルの用意

以下のファイルを用意して、`login.md` という名称で保存します。
````
# システム設計書

## 1. はじめに
本システム設計書は、ネコネコシステムの設計をまとめたものである。

## 2. 機能一覧
- ユーザー管理機能
  - ユーザー登録
  - ログイン/ログアウト
- 猫管理機能
  - 猫情報追加
  - 猫情報編集

## 3. クラス図

```mermaid
classDiagram
class User {
    +String name
    +String email 
    +void login() 
    +void logout()
}
class Cat {
    +String name
    +float power
    +void add()
    +void edit()
} 
User "1" -- "many" Cat : manages
```
````

:::note
クラス図の部分を Mermeid で記載しています。
もちろん、シーケンス図など他のダイアログも書けるので、設計書はこれでバッチリです！
:::

:::note

VSCode で Markdown Preview Enhanced を入れると、リアルタイムでプレビューを確認できます。

https://marketplace.visualstudio.com/items?itemName=shd101wyy.markdown-preview-enhanced

:::

## 3. PDF ファイルへの変換

事前に用意した `diagram.lua` と `login.md` はコマンド実行ディレクトリ内に配置している前提とします。
それ以外の場合は、適宜コマンドで指定しているパスを変更して下さい。


以下のコマンドを実行します。

```bash
pandoc ./login.md \
    -o ./login.pdf \
    --pdf-engine=lualatex \
    -V documentclass=ltjarticle \
    -V geometry:margin=20mm \
    --lua-filter ./diagram.lua
```

| オプション | 説明 |
| ---- | ---- |
| ./login.md | 変換元のMarkdownファイル |
| -o ./login.pdf | 出力するPDFファイルの名前 |
| --pdf-engine=lualatex | PDFエンジンとしてlualatexを使用 |
| -V documentclass=ltjarticle | 日本語対応のためのドキュメントクラス設定 |
| -V geometry:margin=20mm | ページのマージン設定(お好みで) |
| --lua-filter ./diagram.lua | Mermaid 変換用のフィルターを指定 | 

## 4. 終わり！

`login.pdf` というファイルが生成されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3294382/15551c49-a527-3107-bbba-0c606bccb81a.png)

クラス図もしっかりと出ていますね！

# 最後に

簡潔ですが以上です。
GitHub Actions で自動生成する記事も別途執筆したいと思います。
ゲーム/エンタメ業界の経験を活かしてサービス企画職に！異業種で苦悩した話。

<h1>はじめに</h1>
ゲーム・エンタメ業界でのプランナーから転職してtoBのサービス企画を担当してから早3年目になったので、今回はtoCからtoBに転身した際に直面した苦悩と、それをどう乗り越えてきたかを振り返えってみようと思う。

私の経歴としてはゲーム・エンタメ業界では1->10の企画職でいわゆる運営プランナーというのをやっていた。(最初の１年間だけゲームプログラマーやってたけど..向いてなさすぎた..。)その後サービス企画1->10、0->1の両方を今経験している。

ちなみに、企画職って自分の作りたい企画考えるんだよね！楽しそうって思ったあなた。
実際楽しいよ！(自分の作りたい企画なんてほぼ作れないけどね。←なんで？と思う方は最後まで見れば自ずと答えがわかるハズ)

現実、業務は泥臭いこと(書類作成、打ち合わせ)5~6割、進行管理3~4割、企画立案0~2割。こんな割合ですな。
意外かと思う人もいるけど、企画立案していく内容のほとんどは書類作成や打ち合わせ(ユーザー調査)、データ(市場調査)との睨めっこですw(※企画も0->1と1->10でも違うのでこれが全てではないよ。)

余談はこれくらいにして、早速ゲーム、エンタメ業界のサービスとtoBのサービスを作る上での比較を表でまとめてみた。

<h1>自分の経験とGPTの力を借りて表にしてみた</h1>

|項目| toC | toB |
|:-:|:-:|:-:|
| ターゲット | 個人消費者、趣味嗜好、プレイスタイル、消費トレンドを分析、感情的満足度（楽しさ・共感・中毒性）を重視  | 企業、業界特性、導入効果を理解、収益性、課題解決を重視 |
| 企画のゴール  | ユーザーの楽しさを追求、話題性、継続的なファン形成、評価指標：売上、DAU、ARPU | プロダクトを通じて業務効率化・課題解決を実現、長期的信頼関係の構築、評価指標：契約額、プロダクトの利用率、満足度 |
|アプローチ方法|感覚的・視覚的な提案、プレイユーザーの調査、SNS拡散戦略、迅速なアップデート、ユーザーの声を反映 |論理的・データドリブンな提案、デモやPOC（概念実証）で製品の価値を体験してもらう、導入前後の運用計画を提示|
|企画内容 |ゲームのストーリー、キャラクター、イベント設計、消費者心理を刺激する仕組み、プロモーションと連動| クラウドサービス、業務ツールなどのプロダクト設計、業界特化型の機能提案、カスタマイズオプションの提供|
|スキルと能力|創造性、トレンド感覚、エンタメ知識、感情を掴む力 |問題解決力、論理的思考、顧客への知識説明力|
|成功の定義≒(良いものを作る) |ユーザーに「また遊びたい」と思わせる体験、「楽しさ」や「熱狂」の創出 |プロダクトを活用した業務改善、業績向上の実現、「なくてはならない」製品として顧客に定着すること|

似ているところなどはあるが、正直ほぼ別職種である...。
この表を元に私が苦戦した話をより具体的かつ自身の体験を交えて伝えてみる。

<h1>toCの企画からtoBの企画の「良いものを作る」というニュアンスの違いに苦戦</h1>
まず、

**「良いものを作ろう」という言葉は「ユーザーにとって使ってくれるもの=良いもの」**

と定義しがちだが...

これが自分の中で落とし穴だった。さっきの表の一番下を見てもらうとわかる通り、「良いもの」のそもそもの定義が全く違うのだ。これを自分の中で矯正させ、落とし込むまでに **半年から1年** かかった。
それだけ時間がかかった理由としては表の下から２番目に付随する。
ゲーム開発ではユーザーを楽しませるための感覚や創造性、エンタメといった知識が必要だった。一方toBでは問題解決力、論理的思考力、なぜそれが必要なのか？という説明力が大事という「スキルと能力」の土台がそもそも違った。

最近ではようやくこの辺りも理解しつつ業務に取り組んでいるが、実はゲーム,エンタメ業界のサービスとtoB向けのサービスを作る上でもう１段階決定的な違いあった。

<h1>他サービスの動向調査のし辛さに悪戦苦闘</h1>
まさしく今も悩みに悩んでいることである。ゲーム、エンタメ業界では「気になる！」と思ったらすぐに実機で触ってユーザー観点で利用することができる。だからこそ開発にも知識として落とし込むことは容易だった。

一方でtoBはどうだろうか・・・・・・

そう...触りたいと思った時に触ることができないのだ。正確にはユーザー観点で使ってみたいと思って利用するためには「資料請求」、「請求先の企業から連絡」「デモ環境を触る」といったフェーズが待っている。これが本当に辛い。

天の声で「サービス概要とHPに大体の機能載っているから十分でしょ？」と聞こえてきそうだが、
私からしたら実機を触ってボタンの配置や遷移の仕方、ロード時間、UI/UXにおいて実際に体験しないことにはどんなものが流行っていて、どんなところが良いから売れているのかがわからないのだ。これが本当に致命的すぎる。

じゃあどうやって他サービスの内容を知るのかというと...イベントなどに出向いてデモを触らしてもらったり、人脈を使ってそこ経由で少し話を聞いたりと...結構泥臭く知識を溜めているのだ。辛い。

<h1>終わりに</h1>
ゲーム、エンタメ業界ではtoCという特性もあると思うが...<br>
toBのサービスも狭いコミュニティだけでなく、全体的に業界を盛り上げようという意味で「自由にサービス触って良いよ！」という風潮が早くできないかなあと思っている。

私自身もこうしてtoBの企画職に入ってみて、「インタビュー調査」だったり「顧客の課題」を定める大切さを学べたのは経験して良かった。
前職の経験を活かして「創造性」や「ユーザーに楽しんでもらう」というのはtoBのサービスのどこかに組み込めないかは日々検討している。というか入れ込みたい。
これを説明するのが一番難しいんだけどね！論理的に説明できないものだし。(感覚値や視覚情報だから...)
けどそういう「本来必要ないけど、これがあったから使っている」というサービスが今後売れていくのかなって思ったりする。

だからそういうサービスを作って世に出していきながら **「良いものを作る」** ことが当面の目的であり目標にでも置こうかな。

ちなみに最後まで読んでみて、それでも **自分の作りたい企画をサービス化させたいんだ** という強い意思を持った方。
向いてるのでぜひプロダクト開発(サービス企画)の道へ来ないかい？エンジニアの知識を持った企画職は重宝されるらしいよ。
GitHubProjectで見やすくタスク・Issue管理


こんにちは！
デジタル創作サークルUniProjectのあかつきゆいとです。
今回は、GitHubProjectでIssueやタスク、PRなどをいい感じに管理した話です。

## GitHubPagesとは

GitHubのアカウントページやリポのタブで見る、あれです。

> プロジェクトは、作業の計画と追跡を効果的に行えるように GitHub 上の issue および pull request と統合できる、適応性のあるスプレッドシート、タスク ボード、ロード マップです。 issue と pull request をフィルター処理、並べ替え、グループ化することで複数のビューを作成してカスタマイズしたり、構成可能なグラフを使って作業を視覚化したり、team 固有のメタデータを追跡するためのカスタム フィールドを追加したりすることができます。 プロジェクトには、特定の手法を適用するのではなく、チームのニーズやプロセスに合わせてカスタマイズできる柔軟な機能があります。
> GitHub・Projectsについて[^1] より

ということで、いい感じにGitHubやリポにまつわるタスク管理ができるやつです。

[^1]:https://docs.github.com/ja/issues/planning-and-tracking-with-projects/learning-about-projects/about-projects

### メリット

今まで私はRedmineばっかり使ってきていて、それはそれでそこそこ使いやすいと感じていました。
ですが、GitHubProjectsだと、

- 何より、**いちいち同期しなくていい**
- IssueやPRをそのまま使える
- Projectのページからだけでなく、IssueやPRのページからも編集できる
- IssueやPRをCloseすると、Projectのステータスも自動的に変わる

他にもいろいろありますが、ぼくが特に便利だと思ったのはこんなところですかね。
Redmineでもできるかもしれませんが、めんどくさいでしょう。

### デメリット

もちろん、GitHubProjectの方が劣っている部分もあります。

- プラグインがない
- 非技術者にとってはわかりにくいかも
- デザインが決まっている
- リポに紐つけないと基本的に使えない

なので、そこは良し悪しですね。
リポにあるコード関連のものだけGitHubProjectを使うのもいいかもしれません。

## 使い方

### Projectの種類

まずは、プロジェクトを作成していくわけなのですが、最初からいくつかテンプレが用意されています。

![ghproj-temp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3342262/4c4a8faf-fd7a-1af4-b9a5-76bb9756dcba.png)

色々種類はあるのですが、今回は(ぼくが個人的によく使っているのもあるのですが、)**Kanban**という、カンバン形式のものを使ってみましょう。

このKanbanというのは、カンバン形式でIssueなどを管理できるテンプレートで、タスク管理をするときに、どのIssueやPRが今どのような状況であるかをサッと把握できるので重宝しています。

### Draftを作成してみる

AddItemsからタイトルを入力します。

![ghproj-create.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3342262/0df298a3-b489-b595-683c-e9efe3863cb3.png)

+を押すとこんな感じに出てきます。

![ghproj-addbtn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3342262/9ea14ded-9e8f-4c44-6b60-dbb08288e32e.png)

まずはDraftを作成してみましょう。

そしたら、できたものをクリックして見てみましょう。

![ghproj-detail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3342262/88c6f7e2-cd18-8f2d-50e2-f7af041e8422.png)

こんな感じで表示されると思います。
では各項目を詳しく見ていきましょう。

- Assignees

担当者です。
これを指定していると、変更があった際などに、その人に通知が行きます。

- Status

TODO、InProgress、Doneなどが指定できます。
他にも選択肢を追加することもできます。

- Priority

重要度です。
0-2で選べます。

- Size

これは、タスクの大変さ、サイズを表しています。

- Estimate

作業ポイントですね。
マイルストーンみたいな使い方ができます。

- Iteration

これは、期間ですね。
どの期間でやるかということが書いてあります。

- Start date/End date

開始日と完了日ですね。

これでProject特有の設定は大体終わりました。
これらの項目は消すこともできますし、独自の項目を増やすこともできます。

### Issueに変換する

ConvertIssueを押して、Issueに変換してみましょう。
リポジトリを選択すると、そのリポジトリにIssueが作成されます。

Issueの画面からも、Projectの項目を編集できることがわかります。

![ghproj-issue.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3342262/b078c3fd-a309-6b11-3bbd-e9a2f27ffa3e.png)

### PRを追加する

さっきのAdd itemsの+からリポジトリから追加を押して、選びます。

これは簡単ですね。
これをすると、PRの画面からも使えるようになります。

### PRやIssueを閉じる

PRやIssueを閉じてみましょう。
するとなんと！！！
**StatusがDoneになりました！！**

逆も然りで、Doneに(ドラックドロップなりで)移動すると、Closeされることがわかります。

### 表示を変えてみる

先ほどのBacklog以外にもRoadmapでガントチャート風の物を見れたり、色々見ることができます。

これは、自由に作ることもできますね。

今回は割愛させていただきます。

## まとめ

今回はGitHubProjectでいい感じにタスク管理をする方法をしました。

今回紹介した機能以外にも、自動化できる機能や、先ほど書いた表示を変える機能など、いろいろありますので、ドキュメントを見てみるのもいいかもしれません。

https://docs.github.com/ja/issues/planning-and-tracking-with-projects

ではまた...
Androidアプリ開発　備忘録

## Jetpack Compose 備忘録

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676163/d4be58ac-7bb7-b2f1-e7a3-6eb1a4e1f777.png)
上記画面に対して上下左右まとめて統一した間隔を設定したいとき

```kotlin
 modifier = modifier.padding(4.dp)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676163/3f8b7f5b-ecfc-3d36-080e-c7984dd488e6.png)
こうすることで等間隔で設定が行える
下記のように上下同士で統一させ、左右同士で統一させる場合は、"vertical" "horizontal"で値を指定する。
```kotlin
 modifire = modifier.padding(vertical = 4.dp, horizontal = 50.dp)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676163/ae5a1814-2696-5335-783d-5c4a66026041.png)
QVR ProにTS-NA230WPを接続して監視カメラにする

## はじめに
QVR Proでネットワークカメラを接続する方法。
ネットの海だけでは素直に解決できなかったので備忘録。
QNAPのNAS, TS-NA230WP, Windows環境で実施した場合で書いています。

I-O DATA製のカメラなら同じ手方法でイケると思います。

※Qwatch Monitorの辺は記憶で書いているので間違っていたらごめんなさい

## 事前準備
- ルータをRTSP許可 (設定方法はルータによると思うので省略)
- Qwatch Monitorのインストール (I-O DATAのアプリ)
- QVR Proのインストール

## やったこと
1.TS-NA230WPにLAN、ACアダプターを繋いで起動する (少し待つ)

2.Qwatch Monitorを起動
<dl>
  <dt>　ユーザ名</dt>
  <dd>　administrator</dd>
  <dt>　パスワード</dt>
  <dd>　自分で設定(だったはず)</dd>
</dl>

3.Qwatch Monitorのカメラ登録設定 (細かい点は省略)
<dl>
  <dt>　ユーザ名</dt>
  <dd>　admin</dd>
  <dt>　パスワード</dt>
  <dd>　MACアドレス</dd>
  <dd>　⇒パス変更を求められるので変更しておく</dd>
</dl>

4.カメラ登録画面からカメラ設定を開く
　RTSPのポートを確認する

5.QNAPにて、QVR Pro → カメラ設定でカメラの追加を行う

6.TS-NA230WPを検出したら選択して次へ

7.選択肢にI-O DATAがないため、メーカー：ONVIFとなるがそのままでOK

8.基本的には自動入力されている情報そのままで大丈夫なはず
　以下を入力
<dl>
  <dt>　RTAP</dt>
  <dd>　Qwatch Monitor経由で確認したRTSPポート番号に変更</dd>
  <dt>　ユーザ名</dt>
  <dd>　admin</dd>
  <dt>　パスワード</dt>
  <dd>　カメラ登録設定時に変更したパスワード</dd>
</dl>

9.接続確認すると通る(はず)

10.後は困ることなく完了するはず

とりあえず自分が困った所は以上。
以降の細かい設定は自分が出来てないし、個々人次第化かと思うので省略。

#### もし接続失敗した場合は
Surveilance Stationの方が接続失敗時のエラーメッセージは親切だったので、そっちで試してもらえれば……

## PoE設定について
ACアダプターを使わずPoEで接続したい場合、以下どちらかでなんとかなるはず
(念のため記載)
- PoE対応のルータを購入してカメラを接続
- PoE対応のスイッチングハブを購入して、ハブ経由でカメラを接続
Rustのclap(v4)でcliツール作成を触ってみた

## コードサンプル

https://github.com/tonakai-it/rust-cli-tool-sample

バージョン
```toml
[dependencies]
clap = { version = "4.5.23", features = ["derive"] }
```

## clapとは
引数パースを簡単にしてくれるクレート
## clapのArgAction
- `ArgAction::SetTrue` フラグをセット
- `ArgAction::SetFalse` フラグをリセット
- `ArgAction::Set` 値をセット
- `ArgAction::Append` 値を追加
- `ArgAction::Count` オプションが出た回数をカウント


## 位置引数
`.required(true)`をつける

## オプショナル引数
`.short`と`.long`をつける

## ArgAction::Appendの複数受け取り
`.num_args(1..)`

## コード例

```rust
use clap::{Arg, ArgAction, Command};

fn main() {
    // CLIの構成
    let matches = Command::new("Clap Sample")
        .version("1.0")
        .author("Your Name <youremail@example.com>")
        .about("A simple CLI example using clap")
        .arg(
            Arg::new("first")
                .help("The First Positional Argument")
                .required(true) // 必須の位置引数
        )
        .arg(
            Arg::new("second")
                .help("The Second Positional Argument")
                .required(false), // 任意の位置引数
        )
        .arg(
            Arg::new("name")
                .short('n')
                .long("name")
                .value_name("NAME")
                .help("Sets a custom name")
                .action(ArgAction::Set),
        )
        .arg(
            Arg::new("debug")
                .short('d')
                .long("debug")
                .value_name("DEBUG")
                .help("Enables debug mode")
                .action(ArgAction::SetTrue),
        )
        .arg(
            Arg::new("list")
                .short('l')
                .long("list")
                .value_name("List")
                .help("List")
                .action(ArgAction::Append)
                .num_args(1..), // 1つ以上の値を受け取る
        )
        .get_matches();
    ...
}

```
Web Speech API触ってみる

# はじめに

下記でポモドーロタイマーを作ってみたが音を出すことを忘れていたので

Web Audio APIを使ってMP3ファイルを再生しようとしていたところ、

勉強中にWeb Speech APIというAPIを知ったので

Web Speech APIのSpeechSynthesisを使ってタイマーのお知らせ音を設定してみる。


前回の記事

https://qiita.com/shisojuice/items/66a17b5540dd8cd86f3e

https://qiita.com/shisojuice/items/303019cc6d05bca3b20c

WebAudio API　とは(参考記事)

https://developer.mozilla.org/ja/docs/Web/API/Web_Audio_API

Web Speech API　とは(参考記事)

https://developer.mozilla.org/ja/docs/Web/API/Web_Speech_API

https://developer.mozilla.org/ja/docs/Web/API/SpeechSynthesis


# プロジェクトの作成

前回記事にしたソースに引き続き、タイマーのお知らせを実装していく。

Web Speech API の例

```javascript
 // SpeechSynthesisUtteranceオブジェクトを作成
  const utterance = new SpeechSynthesisUtterance('Hello');
  // 言語を設定 (オプション、日本語の場合は 'ja-JP')
  utterance.lang = 'en-US';
 // 音量 (0 ~ 1, デフォルト: 1)
  utterance.volume = 1;
  // ピッチ (0 ~ 2, デフォルト: 1)
  utterance.pitch = 1;
  // 話す速度 (0.1 ~ 10, デフォルト: 1)
  utterance.rate = 1;
 
  // 声を設定 (オプション)
  // speechSynthesis.getVoices() で利用可能な声を取得できる
  // 例: utterance.voice = voices.find(voice => voice.name === 'Google US English');
  // 例: https://developer.mozilla.org/ja/docs/Web/API/SpeechSynthesisUtterance/voice
 
  // 発声
  speechSynthesis.speak(utterance);
```

下記コードでは、

開始時に、TaskあるいはBreakの時間を宣言し、

終了時に、Finishとお知らせしてくれている。

```javascript:App.jsx
  // 略

  const longtime = 25 * 60;
  const shorttime = 5 * 60;
  const [timeIndex, setTimeIndex] = useState(0);
  const timecycle = [longtime, shorttime, longtime, shorttime, longtime, shorttime, longtime, longtime]; // (25+5)*3 + (25+25)
  const [timeLeft, setTimeLeft] = useState(timecycle[timeIndex]);
  const minutes = Math.floor(timeLeft / 60);
  const seconds = timeLeft % 60;
  const [isActive, setIsActive] = useState(false);
const [isActive, setIsActive] = useState(false);
  const explain = timeIndex % 2 == 1 ? `Break ${timecycle[timeIndex] / 60}min.` : `Task ${timecycle[timeIndex] / 60}min.`

  // Web Speech APIを設定
  const utterance = new SpeechSynthesisUtterance();
  utterance.lang = 'en-US';
  utterance.volume = 1;
  utterance.pitch = 1;
  utterance.rate = 1;

  useEffect(() => {
    let interval = null;
    if (isActive && timeLeft > 0) {
      interval = setInterval(() => {
        setTimeLeft(timeLeft => timeLeft - 1);
      }, 1000);
    } else if (!isActive && timeLeft !== 0) {
      clearInterval(interval);
    }
    else if (!isActive && timeLeft == 0) {
      setTimeLeft(timecycle[timeIndex]);
      clearInterval(interval);
    }
    else if (isActive && timeLeft == 0) {
      // Finish時に説明する
      utterance.text = explain + ` Finished`;
      speechSynthesis.speak(utterance);
    }
    return () => clearInterval(interval);
  }, [isActive, timeLeft, timeIndex]);

  const handleStart = () => {
    // Start時に説明する
    utterance.text = explain;
    speechSynthesis.speak(utterance);
    setIsActive(true);
  };

// 略
```

完成！

# 成果物ソース

デモURL

https://shisojuice.github.io/react_pomodorotimer/

ソース

https://github.com/shisojuice/react_pomodorotimer

# まとめ

前回作成したタイマーアプリに音出力機能を実装してみた。

普段の業務ではサウンドなどはつけることがないので、

Web Speech APIを学習する良い機会だった。
動画生成に関連する最近のLLM

動画生成などコンピュータービジョンに関するLLMの論文を2つ紹介します。

[1. きめ細かなストーリーテリングビデオの生成「DreamRunner」](##きめ細かなストーリーテリングビデオの生成「DreamRunner」)
[2. 拡散モデルを使用して4Dであらゆるものを作成する](##拡散モデルを使用して4Dであらゆるものを作成する)


## きめ細かなストーリーテリングビデオの生成「DreamRunner」
### DreamRunner: Fine-Grained Storytelling Video Generation with Retrieval-Augmented Motion Adaptation

入力されたテキストに沿ったビデオの生成、**SVG(Story Telling Generation)** をより質高く行うことができる生成手法「**DreamRunner**」が発表されました。

GitHubでサンプル動画を観ることができます。

https://github.com/wz0919/DreamRunner

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/ebf92cad-176a-a0c9-8f20-a8576d4d184a.png)

これまでのSVGには次のような課題がありました。

::: note warn
- 様々なオブジェクトがあり、その動きを再現しなければいけない
- 複数のオブジェクトが一貫してシーン内に存在する
- 被写体が一つのシーンで複数のモーションを必要とする
:::

この課題に対して、大きく3つの工夫をしました。

::: note 
- シーンのプランニングとモーションのプランニングの両方を実施するためのLLMを用意し入力するテキストを構成する
- 各シーンのモーションに対応するための検索(Retrieval Augmented)を行う
- 各シーンのオブジェクトをフレーム単位で認識するSR3AIをモジュールとして使う
:::

オブジェクトやシーンに一貫性のある動画をつくることができます。
一番下が**DreamRunner**です！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/7d91847b-1230-2da5-1441-abe8aa083296.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/d959b328-9599-0b4c-98cd-b1295247cff2.png)

## 拡散モデルを使用して4Dであらゆるものを作成する
### CAT4D: Create Anything in 4D with Multi-View Video Diffusion Models

まずはここで動画を観るとわかりやすいです！1視点の動画をマルチビューにすることができます。

https://cat-4d.github.io/videos/teaser_crf28.mp4

リンクは[こちら](https://cat-4d.github.io/)です。

これは**CAT4D**というモデルで、単眼の入力映像からダイナミックな3Dシーンをつくることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/060d9d58-dbee-4718-5cc6-d6eb050b4139.png)

2つのステップによってこのようなスムーズなマルチビューを実現しています。

::: note 
1. マルチビュー映像の拡散モデルを使い、マルチビュー映像に変換
2. 3次元ガウス表現を最適化し、動的な3Dシーンに再構築
:::

## 参考
### 各arXiv論文はこちらです。

- DreamRunner: Fine-Grained Storytelling Video Generation with Retrieval-Augmented Motion Adaptation

https://arxiv.org/pdf/2411.16657

- CAT4D: Create Anything in 4D with Multi-View Video Diffusion Models

https://arxiv.org/pdf/2411.18613
getattr の使いどころ

# 結論
可読性を損なわない程度の利用にとどめるべきだなと思いました。
なんでもそうですが、得られるものよりも失うもののの方が多いなら不適切ですね。

# getattr とは
オブジェクトの属性を動的に取得できる組み込みの関数で次のような構文です。
詳細は公式資料をご覧ください。
```python
getattr(オブジェクト, 属性名, 属性がない場合に返却する値)
```

# 具体的な使い方
まず、食品の栄養素情報のデータクラスがあるとします。
```python
@dataclass(frozen=True)
class FoodInformation:
    name: str
    energy: float
    protein: float
    fat: float
    carbohydrates: float
```

食品の情報を動的に取得したい場合、次のように記述できます。
```python
def get_nutrient_value(food: FoodInformation, nutrient: str) -> float | str:
    return getattr(food, nutrient, f"{nutrient} 属性は存在しません")

boiled_egg = FoodInformation(
    name="ゆでたまご",
    energy=134,
    protein=12.5,
    fat=10.4,
    carbohydrates=0.3
)

nutrient = "protein"
value = get_nutrient_value(boiled_egg, nutrient)
print(value)  # 出力値：12.5

nutrient = "fiber"
value = get_nutrient_value(nutrient)
print(value)  # 出力値：fiber 属性は存在しません
```

次に getattr を利用しない場合のコードを見てみます。
```python
def get_nutrient_value(food: FoodInformation, nutrient: str) -> float | str:
    if nutrient == "energy":
        value = food.energy
    elif nutrient == "protein":
        value = food.protein
    elif nutrient == "fat":
        value = food.fat
    elif nutrient == "carbohydrates":
        value = food.carbohydrates
    else:
        value = f"{nutrient} 属性は存在しません"
    return value

boiled_egg = FoodInformation(
    name="ゆでたまご",
    energy=134,
    protein=12.5,
    fat=10.4,
    carbohydrates=0.3
)

nutrient = "fat"
value = get_nutrient_value(boiled_egg, nutrient)
print(value)  # 出力値：10.4
```
想像してみてください、食物繊維の属性が増えたら？ビタミン B の属性が増えたら？アミノ酸スコアの属性が増えたら…。
繰り返しとなりますが、getattr は動的に属性を取得できるので便利だということです。

# 使うべきではないと思った場面
冷凍バナナを持ったら何でも叩きたくなるのと同じで、getattr の存在を知ってしまったらなんでもかんでも getattr したくなるのは当然です🐵
しかしながら、最終的に次のコードに戻ってくる話をします。始点であり現時点での終点です。
これは見てのとおり、min か max かによって比較演算子が変わるだけです。
```python
if min_max == "max":
    self.problem += (nutrient_value <= value, problem_name)
elif min_max == "min":
    self.problem += (nutrient_value >= value, problem_name)
```
一応説明しますが、このコードはたんぱく質、脂質、炭水化物の比率を求めるプログラムで制約条件を設定するコードの一部です。
たんぱく質は体重の 2 倍のグラム数にしたり、脂質は 20% 以下にしたりする等、制約を与えています。

getattr を無理やり適用した結果は次のようなものになります。
```python
import operator

min_max = "max"
operator_name = "ge" if min_max == "min" else "le"

comparison_operator = getattr(operator, operator_name)
self.problem += (comparison_operator(nutrient_value, value), problem_name)
```
もともと operator を利用する前提がなく、min や max から ge(greater equal) や le(less equal) に変換しているのもわかりづらい要因かと思いますが、その変換が無かったとしても結局わかりにくい気がします。
値を取得するだけならまだしも、関数を取得することで難易度が少し上がっているのだろうと思います。

getattr を使わずにまた別の書き方をする場合は辞書とラムダでしょうか。
```python
comparison_operators = {
    "max": lambda x, y: x <= y,
    "min": lambda x, y: x >= y
}

comparison_operator = comparison_operators[min_max]
self.problem += comparison_operator(nutrient_value, value), problem_name
```
先述の operator と getattr でやっていたことを目に見える範囲でやっただけと言い換えることができるかもしれません。
これはそんなに悪くない気がしているので、気が変わったらこれを採用するかもしれないのですが、結局単純な if else に戻りました。

# あらためて結論
getattr が便利なのはわかりましたが、できるかどうかではなく、やるべきかどうかは考えものだなあと思いました。
いろんなことに共通することかもしれませんが、数ある選択肢の 1 つとして持っておくのが大事で、何でもかんでも何も考えずに適用してしまうのは好ましくないなと思いました。