OmniAICreator/Qiita-1.07M huggingface dataset:
ダウ理論、エリオット波動検出のコード

ダウ理論を定義、検出するためのコードを作ってみました。
まずはいつものようにアカウント設定をします。

```python
pip install oandapyV20 pandas

import oandapyV20
from oandapyV20 import API
import oandapyV20.endpoints.instruments as instruments
import pandas as pd

API_KEY = 'あなたのAPIキー'
ACCOUNT_ID = 'あなたのアカウントID'

client = API(access_token=API_KEY, environment="live")
```
次に為替データの取得をします。
通貨ペアと時間足、ローソク足の数も好きな数値に設定。

```python
params = {
    "granularity": "D",  # 日足データ
    "count": 100  # 取得するデータの数
}

r = instruments.InstrumentsCandles(instrument="USD_JPY", params=params)
client.request(r)

data = r.response['candles']
df = pd.DataFrame([{
    'time': candle['time'],
    'open': candle['mid']['o'],
    'high': candle['mid']['h'],
    'low': candle['mid']['l'],
    'close': candle['mid']['c']
} for candle in data])

df['time'] = pd.to_datetime(df['time'])
df.set_index('time', inplace=True)
```

以下はダウ理論の定義。安値切り上げと高値切り上げをuptrendと定義し、高値切り下げと安値切り下げをdowntrendと定義、それ以外はsidewaysと定義します。

```python
def identify_trends(df):
    df['trend'] = None
    for i in range(1, len(df)-1):
        if df['high'][i] > df['high'][i-1] and df['low'][i] > df['low'][i-1]:
            df.at[df.index[i], 'trend'] = 'uptrend'
        elif df['high'][i] < df['high'][i-1] and df['low'][i] < df['low'][i-1]:
            df.at[df.index[i], 'trend'] = 'downtrend'
        else:
            df.at[df.index[i], 'trend'] = 'sideways'
    return df

df = identify_trends(df)
```

次にエリオット波動の第3波と第5波の定義になります。

```python
def detect_elliott_waves(df):
    wave_data = []
    
    for i in range(2, len(df)-1):
        if df['trend'][i-2] == 'uptrend' and df['trend'][i-1] == 'downtrend' and df['trend'][i] == 'uptrend':
            wave_data.append((df.index[i-2], 'wave 1 start'))
            wave_data.append((df.index[i], 'wave 3 start'))
        
        if df['trend'][i-2] == 'downtrend' and df['trend'][i-1] == 'uptrend' and df['trend'][i] == 'downtrend':
            wave_data.append((df.index[i], 'wave 5 start'))
    
    return wave_data

waves = detect_elliott_waves(df)

for wave in waves:
    print(wave)

print(df)
```

ここにもう少し追加して検証をしていこうと思います。
Codilityでコーディングテスト受けた感想と対策

# はじめに
転職活動中にCodilityでコーディングテストを受けました。ちょっと面白かったので、その感想と私がやった対策をまとめます。

# 感想 :notepad_spiral: 
- Codilityは言語が選べるのがとてもありがたい… (企業さんが使っている言語を指定されることもあったので、もしかしたら会社に方針によるかもです。)
- 練習問題もいくつか用意してくれているので、それらを一通りやっておいたのがとても良かったです。
- 過去受けたコーディングテストでは練習問題(多分エディターになれるためのやつ)と本番の内容が全然異なる難易度で大変苦戦しましたが、Codilityで受けたテストは比較的同じような難易度の問題だったと感じました。

# 対策 :pencil: 
### :pencil2: Codilityの練習問題
エディターにも慣れることができるし、とても勉強になります。私は一応Easyを全部やってみてから本番へ臨みました。
パフォーマンスや正答率などが出ますが、答えは出ないので調べつつやるのが良さそうです(私はchatGPTに聞きました)🤖

### :pencil2: LeetCode
Codilityの問題を見た時、似てるなと思いました。おそらくeasyからmediumくらいの難易度な気がしています。こちらはより良いパフォーマンスを出せるコードなど他の人の回答を見ることができるのでおすすめです。
この辺りは特に似ている問題たちです。
	1. Two Sum (LeetCode 1) → 配列＋ハッシュマップ
	2.	Missing Number (LeetCode 268) → 数列の法則
	3.	Binary Gap（Codilityの有名問題）→ ビット操作
	4.	Permutations (LeetCode 46) → 再帰・バックトラッキング
	5.	Max Profit (Stock Buy/Sell) (LeetCode 121) → Greedy

# おわりに
LeetCodeやっておくと比較的入りやすいテストでした。今後はコーディングテストを受けるときのポイントをまとめたいと思います。
 => https://qiita.com/araiWorks/items/519a5b219da899d7864d
参考になれば幸いです:apple:
[Javascript] AA.BB.CCの `.` は何を意味するか

python, C++と使用してきて，javascript独特な記述方法について困ったので，以下に纏めた．

## In a nutshell
`.`はドット演算子とよばれる，オブジェクトや配列などのプロパティやメソッドにアクセスするための演算子である．

## 詳細な説明

JavaScriptにおける `.`（ドット）は，主にオブジェクトのプロパティやメソッドを呼び出すために使用される．例えば，`AA.BB.cc`というコードがある場合，それは次のように解釈できる．

1. **オブジェクトのプロパティアクセス**
   - `AA` はオブジェクトであり，その中に `BB` というプロパティが存在する．
   - `BB` はさらにオブジェクトまたは値を持ち，その中に `cc` というプロパティが存在する．
   - この場合，`AA.BB.cc` は，まず `AA` オブジェクトの `BB` プロパティにアクセスし，次にその `BB` プロパティが持つ `cc` プロパティにアクセスすることを意味する．

2. **オブジェクトのメソッドアクセス**
   - `AA.BB.cc` の `cc` が関数であった場合，`AA.BB.cc()` はその関数を呼び出すことを意味する．
   - 例えば，`AA.BB.cc` が `function() { return "Hello"; }` という関数であれば，`AA.BB.cc()` は `"Hello"` を返す．



### 具体例

Hello.World は Hello オブジェクトの World プロパティにアクセスして，その値である "Hello, World" を返す
```
// オブジェクトのプロパティへのアクセス
const Hello = {
  World: "Hello, World"
};

console.log(Hello.World); // Hello, World
```

---

この場合，Hello.World() は Hello オブジェクトの World メソッドを呼び出して，その結果である "Hello, World" を返す．
```
// メソッドの呼び出し
const Hello = {
  World: function() {
    return "Hello, World";
  }
};

console.log(Hello.World()); // Hello, World
```

--- 
## Summery
- JavaScriptの`.`（ドット）は、オブジェクトや配列のプロパティ、メソッドへのアクセスに使用される。
- 例えば、`AA.BB.cc` は、`AA`オブジェクトの`BB`プロパティを参照し、その`BB`プロパティの`cc`プロパティをさらに参照する。
- `AA.BB.cc()`のように、`cc`が関数の場合、メソッドの呼び出しが行われる。


### 参考文献
 - MDN Web Docs: JavaScript のオブジェクト [https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Working_with_objects](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Working_with_objects)
 - MDN Web Docs: JavaScript 関数 [https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Functions](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Functions)
PowerVSの課金表示が分かりやすくなった

PowerVSの課金表示が分かりやすくなりました。
https://cloud.ibm.com/docs/power-iaas?topic=power-iaas-release-notes#Feb-2025
新しく作成したワークスペースから反映され、既存ワークスペースは6月までに対応予定とのことです。

Usage画面で、Power Virtual Serverの項目が表示されています。
https://cloud.ibm.com/billing/usage

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/54fb9819-171e-4af7-a133-b59fb3f261bf.png)

詳細画面に入ると、各サーバー、各ストレージのリソース費用として確認可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/1edafa6c-0c0f-4962-8141-8055862d6660.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/f22c71c4-390e-4115-8dbc-3769a42c1b97.png)

ちなみに、0.25core, 2GBメモリ, 20GBストレージのサーバーを6時間使った際のBillingです。0.25x6=1.5、2x6=12、20x6=120で、それぞれのQuantityと一致している事が分かりやすいです。

:::note
これまでは、ワークスペースとしての表示でした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/02806d24-0b5d-4c15-8230-13ae94056654.png)

昨年に改善の第一弾としてConsumer IDが入るようになったので、紐付けは可能でしたが、自分でIDを確認する必要がありました。
https://qiita.com/y_tama/items/63baa24037d92d3e1693
:::
sourcetreeのカスタムアクションでコミットしたファイルだけをzipダウンロードする

ファイルのディレクトリ構造も維持してzip化します。


```
#!/bin/sh

# 出力先フォルダを指定（任意のパスに変更）
DEST_DIR="$HOME/Downloads/git_archives"

# 出力先フォルダが存在しない場合は作成
mkdir -p "$DEST_DIR"

# 選択されたコミットリストを取得
COMMITS="$@"

# 変更されたファイルのリストを取得（コミットに含まれているファイルのみ）
FILES=""
for COMMIT in $COMMITS; do
    PARENT=$(git rev-parse $COMMIT^)  # 直前のコミットを取得
    if [ -n "$PARENT" ]; then
        FILES+=" $(git diff --name-only --diff-filter=ACMRT $PARENT $COMMIT)"
    fi
done

# ファイルリストを整形
FILES=$(echo "$FILES" | tr ' ' '\n' | sort -u | tr '\n' ' ')

# ファイルが空の場合、処理を中断
if [ -z "$FILES" ]; then
    echo "No changed files to archive."
    exit 1
fi

# 選択したコミットの最新状態でアーカイブを作成
git archive --format=zip --prefix=archive/ -o "$DEST_DIR/archive.zip" HEAD -- $FILES

echo "Archive created at $DEST_DIR/archive.zip"
```
【2025年最新版】死ぬほど噛み砕いてN+1問題をふわっと理解する。

### 具体例
例えば、あなたはプログラミングスクールの先生だとして、複数の生徒とその成績を管理するWebアプリを運営・管理しているとする。成績発表の時期です。あなたは全ての学生とその成績を表示させないといけません。
### 問題の発生
あなたは、全ての学生のリストをデータベースから取得し、その全学生リストの各学生ごとにその学生の成績をデータベースから個別に取得する。

この方法だと100人生徒がいたら101回（最初のリスト取得が+1なので100+1で101回）もデータベースクエリを実行しないといけない

### 解決方法
関連するデータを一度のクエリでまとめて取得する！
つまり、データベースのjoinを使って、学生とその成績を一度に習得する。

### 参考文献

https://zenn.dev/goldsaya/articles/3af48dadc6cc0f
"deploymentId" is undefined | <Html> should not be imported outside of pages/_document.

いつも通り意味不明なNext.jsのエラー

# エラーメッセージたち
## "next dev"の場合
```
⨯ [TypeError: Cannot read properties of undefined (reading 'deploymentId')]
 ⨯ [TypeError: Cannot read properties of undefined (reading 'deploymentId')]
 GET / 500 in 5411ms
 ✓ Compiled /favicon.ico in 121ms
 ⨯ [TypeError: Cannot read properties of undefined (reading 'buildId')]
 ⨯ [TypeError: Cannot read properties of undefined (reading 'buildId')]
 ```
`deploymentId`も`buildId`もプロジェクト内では使っていません

## "next build"の場合
```
✓ Linting and checking validity of types 
✓ Collecting page data 
// ここまではOK

Error: <Html> should not be imported outside of pages/_document.
Read more: https://nextjs.org/docs/messages/no-document-import-in-page
    at b (.next/server/pages/_document.js:6:1351)
Error occurred prerendering page "/404". Read more: https://nextjs.org/docs/messages/prerender-error
Error: <Html> should not be imported outside of pages/_document.
Read more: https://nextjs.org/docs/messages/no-document-import-in-page

（大量のトレースバック）

Export encountered an error on /_error: /404, exiting the build.
 ⨯ Next.js build worker exited with code: 1 and signal: null
 ```
 エラー系のページは特に作成していないのですべてデフォルトです。デフォルト実装の404ページがエラーしています。

 # 解決策
 Nextのキャッシュとインストールしたパッケージをすべて消去すれば治ります。
 `rm -rf ./.next && rm -rf ./node_modules`
 Nextを消すほうは一度やった気がするので、node_modulesのどこかがおかしくなっていたと思われます。
rex0220 印刷屋プラグイン テーブル+カード表示

[rex0220 印刷屋プラグイン](https://qiita.com/rex0220/items/9be2d9b20a3a1f016c76)で、テーブル+カード表示を行ってみます。

# 概要

[rex0220 印刷屋プラグイン テーブル複数ページ](https://qiita.com/rex0220/items/f65825f7f6dc73ee321c)に、カード形式を入れてみます。

TABLE_HTML 関数でテーブル形式、
FIELDS_HTML 関数で項目を並べるとカード形式になります。


![2025-02-28_00h01_59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/6068859a-4b43-4e77-a571-67e66713e2fb.png)

- プレビュー画面 1-2

![2025-02-28_00h06_37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/083bf63b-83b4-4a65-be7b-981444ad5c8f.png)

# 印刷屋プラグイン設定

![2025-02-28_00h08_59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/844a0a81-afd9-439b-bfc0-25531b2d5f07.png)

![2025-02-28_00h10_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/075d7d78-9864-438e-93f6-1fa417870e11.png)

```css:
.pcraft-card-item {
    border-bottom: 1px solid #ccc;
}
.card-image {
    text-align: center;
}
.card-image img {
  width:150px;
}
```

FIELDS_HTML 関数で、項目を並べるとカード形式になります。

```js:
TABLE_HTML(テーブル,
  OPT("title","時計","pagination","Y"),
  OPT("perPage","5"),
  ARRAY("概要",FIELDS_HTML(
    名称,添付ファイル
  )),
  ARRAY("画像",IMGSRC(添付ファイル,,"img"),"card-image")
)
```
pythonでIPv4作成時に raise ValueError('%s has host bits set' % self)が発生する

# はじめに
業務中にipaddressモジュールのIPv4Addressまわりで解決に時間がかかったので忘備録として記録します。

# 内容
オクテットを連結させてIPv4を作成する処理で下記エラーが発生していた。
```py
  File "/usr/lib/python3.11/ipaddresst.py", line 1507, in __init__
    raise ValueError('%s has host bits set' % self)
ValueError: 10.128.2.17/30 has host bits set
```
# 原因
[ipaddress --- IPv4/IPv6 操作ライブラリ](https://docs.python.org/ja/3.13/library/ipaddress.html)に以下の記載がある。
>ipaddress.ip_networkは正しい IPv4, IPv6 アドレスを表現していない場合や、ネットワークの host bit がセットされていた場合は ValueError を発生させます。

今回の場合、ipaddress.ip_networkの引数にhost bitが指定されていたため、ValueErrorが発生していた。
```py
ipaddress.ip_network(address, strict=True)
```

| 引数 | 説明 |
|:-:|:-:|
|address| IPネットワークを示す文字列または整数（IPv4 または IPv6）  |
| strict=True  |  ネットワークアドレスでないとエラーを発生させる（デフォルト True） |
# 今回の解決方法
取得元の値がそもそも誤っていた。
本来ネットワークアドレスを指定するはず箇所に、host bitが渡されていたため、対向システムの問題であった。
（本来であれば、10.128.2.16/30になるはずだった。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639400/690fcf9c-2d8d-477c-959c-bad33a5834f7.png)


# 使い方
### 1. 基本的な利用方法
ip_network() は、文字列で指定された CIDR表記のIPアドレス を IPv4Network または IPv6Network のオブジェクト に変換する。
```py
import ipaddress

network = ipaddress.IPv4Network("10.128.2.16/30")

print(network)  # 10.128.2.16/30
print(type(network))  # <class 'ipaddress.IPv4Network'>
```

### 2. ```strict=Fase``` の場合
デフォルトでは ```strict=True``` のため、ネットワークアドレス以外を指定するとエラーになる。
しかし、エラーを回避したい場合``` strict=False ```を設定すると、host bitが設定されていたとしても、ネットワークアドレスに自動的に補正される。
```py
import ipaddress

network = ipaddress.IPv4Network("10.128.2.17/30", strict=False)

print(network)  # 10.128.2.16/30
print(type(network))  # <class 'ipaddress.IPv4Network'>
```
「Teachable Machineではじめる機械学習  」

いよいよ興味がある勉強をしてきました。毎度:wave_tone5:何にも解決できないはちわれです。この勉強して４回目の投稿です。
少し前までは、(´;ω;｀)(´;ω;｀)の毎日が続いて、日々テンション低くなり
### やめてしまおう
と思っていましたが、色んな方に支えてもらい、切り替えができました。

今回参考にさせてもらいました記事はこちら

https://qiita.com/dx_kumagai/items/7fa7ca14c6af6c6a9d15

読んでて共感していました。


:::note info
今回の記事は、機械学習（なんの事⁈）予習で少し興味がありました。名前は存じません:sweat_smile:でも判別がパソコンでできるんですよ。すごいですよね。
:::

習ったこの判別を使い、やってみた事を記事にします。
### ステップ1：データ収集
Webカメラで撮影

![スクリーンショット 2025-02-27 195418.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3972925/9497a213-23a6-478c-a93f-8e618733b7bc.png)

今回アレルゲンにより近い仕事をしているので、記事を参考にしながらゆっくりですが進めました。写真撮りは、なかなか覚えが悪く:sweat:１００枚という指示に従い取りました。 クラスごとに最低100枚収集し、色んなクラスを作って判別も考えたけど、基本の２つのクラスにして作成。:hamburger:

 ### ステップ2：モデル訓練
 
 ![スクリーンショット 2025-02-27 205043.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3972925/beb457b0-f02d-42d2-9edd-c96b9e438c6a.png)

写真の後、トレーニングのボタンをクリック:bulb:その後コ－ドが出ます。しかしここからがつまづくことが、何度かありました。後でわかった事は、きちんとコピーを押していなかった事が判明してしまいました。:frowning2:予測結果が表示されない	　何故か原因を理解できず。等色々エラーに困惑しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3972925/625c68bf-f4e2-4856-8dca-b3f3916408aa.png)

２日間エラーと格闘しながら　上記の下に当たる部分　カメラを起動しないエラーにまた苦戦をしました。お助けマンとお助け隊２人に短い時間を借りて、自分もChatGPTを使い、聞き出しました。ようやく成功と結果を報告できると.....思っていたんですが、

:::note warn
label:の後の文面が、うまくいっていない。写真の撮り方を間違えている案件。でもパソコンのカメラには、問題ない。
:::
本来の撮り方ではないため　一番自分にできるやり方の動画です。

https://x.com/OXJLz7aOybRxSiu

トラブル続きがあり、動いている画像で時間来ました。:joy:いつもの事とはいえ、毎回こんな記事しか書けない自分に:scream:　今回応用編までいく段取りをしていたのに。:scream_cat:でもあきらめていません。

:::note alert
このようないい物を少しながら、学べている環境にいます。出来なくても、一歩一歩前に進めば、結果は自分の身になる事を授業中に学びました。時間ないではなく、やる順番をやりたいリストに書き出し、ChatGPTにお願いして時間配分してもらう。
:::

### 自分のため　今後の自分のため

 **やりたい事リスト** 🛍️
- [ ] 宿題の意図
- [ ] 記事の意図
- [ ] 実装の時間
- [x] 記事のかんせい

時々アナログに戻り、順番にチェックしていく。これも授業中学んだ事。後少しは応用編まで頑張ってやっていきます。
いつもながら　成功しない投稿を読んでいただきありがとうございました。
早速、useEffectを使う場面を見つけた話

先日、useEffectはあまり使わない方が良い的な話を書いたのですが、早速便利に使える場面がやってきました！

いつかと言うと、テーブルのレコードの値をモーダルに持っていって使う時です。

具体的に説明していきます。

モーダルとは、ボタンをクリックすると表示されるこれ。

https://ui.shadcn.com/docs/components/dialog

モーダルは、画面を読み込んだ時に、非表示として読み込まれます。

この時、useStete(初期値)のように、初期値を設定していたときには、画面読み込み時の初期値が入ります。

そのため、モーダル表示時ごとに初期値をセットすることができません。


そこで、便利なのがuseEffectです。
isOpenの値が変わるたびに、set〇〇で値をセットするように書くと、モーダルが開かれるタイミングで値をセットすることができます。

例えばこんな例
```react
import React, { useState, useEffect } from 'react';
import Modal from 'react-modal'; 

// モーダル用のコンポーネント例
function ExampleModal({ isOpen, onClose }) {
  const [inputValue, setInputValue] = useState('読み込まれる時にセットできる初期値');

  // isOpen が true になったときに初期値をセット
  useEffect(() => {
    if (isOpen) {
      setInputValue('モーダルが開かれたときの初期値');
    }
  }, [isOpen]);

  return (
    <Modal
      isOpen={isOpen}
      onRequestClose={onClose}
      contentLabel="Example Modal"
      ariaHideApp={false} // アクセシビリティ対応のための設定。必要に応じて調整してください
    >
      <h2>モーダルの内容</h2>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      <button onClick={onClose}>閉じる</button>
    </Modal>
  );
}

export default ExampleModal;
```

こんな時に、useEffectが便利に使えることが判明しました！

つい先日、useEffectが便利に使える場面があれば投稿しますと書いたばかりなのにもう見つけてしまいました。
BrainuxのSwap領域の作成の補足

Brainのlinux、Brainuxを使用する際、Brainのメモリ容量が128MBしかないため、スワップ領域の作成が推奨されています。
その[解説記事](https://wiki.brainux.org/tips/swap/)[^1]のコマンドコピペでは私が躓いたので、個人的に修正したコマンドを載せます。結論は`sudo`実行しないといけなかった、これだけです。

# 環境
- Brain PW-SH4 (電子辞書)
- sdimage-2024-12-23-202715.zip (Brainuxのイメージファイル)

# スワップの作成方法
1. 以下のコマンドを実行して、スワップのための領域を確保します
今回の例では、256MB（これ以上を推奨）の領域を確保しています。ほかの容量にしたい場合は適宜`bs`や`count`の値を変えてください。
    ```diff_batchfile 
    - dd if=/dev/zero of=/swapfile bs=1M count=256
    + sudo dd if=/dev/zero of=/swapfile bs=1M count=256
    ```
    ```batchfile 
    chmod 0600 /swapfile
    ```

2. スワップ領域を初期化します

    ```diff_batchfile
    - mkswap /swapfile
    + sudo mkswap /swapfile
    ```

3. スワップ領域を有効にします
    ```diff_batchfile
    - swapon /swapfile
    + sudo swapon /swapfile
    ```
なお、`--help`オプションを出すときも、例えば`mkswap --help`だと`command not found`となりますが、`sudo mkswap --help`だとしっかり説明文が出力されました。

[^1]:https://wiki.brainux.org/tips/swap/
【Docker】docker compose run でポートを作成する方法

`docker compose run` は `compose.yml` で指定したポートのいずれも作成しません。  

## ポートを作成するには

ポートを作成するには `--service-ports` オプションを指定する必要があります。

```shell
docker compose run --service-ports web python manage.py shell
```

または、`--publish`（`-p`）オプションでポートを指定します。

```shell
docker compose run --publish 8080:80 -p 2022:22 -p 127.0.0.1:2021:21 web python manage.py shell
``` 

## 参考

https://github.com/docker/compose/issues/1259#issuecomment-90878095

https://docs.docker.com/reference/cli/docker/compose/run/#:~:text=The%20second%20difference%20is%20that%20the%20docker%20compose%20run%20command%20does%20not%20create%20any%20of%20the%20ports%20specified%20in%20the%20service%20configuration.%20This%20prevents%20port%20collisions%20with%20already-open%20ports.%20If%20you%20do%20want%20the%20service%E2%80%99s%20ports%20to%20be%20created%20and%20mapped%20to%20the%20host%2C%20specify%20the%20--service-ports
Next.jsでLPを作成してみた

こんにちは！今回は Next.js を使って、流入元や天気によって表示が変わるコスメティック商品のLP（ランディングページ）を作成したので、その過程をまとめたいと思います。

## ✨ なぜ作ったのか？

Next.js に興味を持ち、実践的なプロジェクトで学びたい！ と思ったのがきっかけです。学習ロードマップは ChatGPT に相談しながら立てて、勉強を進めました。

## 📒 プロジェクト概要

このプロジェクトでは、Instagram や YouTube からの流入に応じておすすめ商品を変更したり、天気が雨の日には特別な商品を表示する仕掛けを作りました。

## 🚀 デモ

ぜひ実際に触ってみてください！

[通常LP](https://cosmetics-lp.vercel.app/lp)

[Instagram用LP](https://cosmetics-lp.vercel.app/lp/instagram)

[YouTube用LP](https://cosmetics-lp.vercel.app/lp/youtube)

## 🔧 インストール手順

以下の手順でプロジェクトを立ち上げられます。

### リポジトリをクローン

git clone https://github.com/kotafunahashi/cosmetics-lp.git
cd cosmetics-lp

### パッケージをインストール

npm install

### 環境変数を設定
.env ファイルを作成し、次のように API キーを設定してください。

OPENWEATHER_API_KEY=あなたのAPIキー

### サーバーを起動

npm run dev

ブラウザで http://localhost:3000 にアクセスすればOKです！

## 📖 使い方

http://localhost:3000/lp/instagram からアクセスすると Instagram 向けの画像が表示されます。

http://localhost:3000/lp/youtube では YouTube 向けの内容が展開されます。

天気が雨予報の日には、特別に「雨の日におすすめの商品」が表示されます！

## 📂 ファイル構成

/app
├── lp
│   ├── [source]
│   │   └── page.tsx
│   └── page.tsx
├── public
│   ├── products.json
│   └── images
└── .env

## ⚙️ 技術構成

このプロジェクトには以下の技術を使用しました：

Next.js：高速なサーバーサイドレンダリング

TypeScript：型安全性の向上

Tailwind CSS：スタイリングを効率化

OpenWeather API：天気予報の取得

## 📊 学んだこと

Next.js の動的ルーティング：Instagram や YouTube など、流入元ごとにパスを分けてページを切り替えました。

環境変数の管理：APIキーは .env ファイルに保存し、セキュリティを確保。

非同期データ取得：天気データと商品リストを非同期に取得し、レンダリングを工夫しました。

## 💼 ライセンス

このプロジェクトは MITライセンス のもと公開しています。

## 💡 まとめ

今回のプロジェクトを通じて、Next.js の便利さと、動的にページを切り替える楽しさを体感しました。これからもいろんな機能を追加していきたいです！

ぜひ GitHub リポジトリ をチェックしてみてください。
CodeSandboxって何？

ブラウザ上で環境の設定をすることなく開発を行うことができるCodeSandbox(コードサンドボックス)についての紹介です｡

フロント側のプロトタイプを作成する際､以下の問題に当たったことがあるので､都合の良さそうなツールを探していたところ､こちらを見つけました｡

+ 検証環境の作成 -> 毎回環境を作成するのは大変
+ （動きのある）UIの伝え方 -> 画像で済ますか、動画やGIFを作ってアップロードするのか悩む。後者は大変
+ ソースコードの公開 -> するのが望ましいが、GitHubにリポジトリを作って公開するのは大変
 
# CodeSandboxとは
CodeSandboxとは、Webアプリの作成と共有を迅速に行うことができるオンラインコードエディターおよびプロトタイピングツールです。

+ [CodeSandbox: Online Code Editor and IDE for Rapid Web Development](https://codesandbox.io/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676048/2b7e2a28-b0ff-4d04-873b-a978a58479b2.png)

CodeSandboxでは「サンドボックス」という環境を作成して Vue、React､Angular、JavaScriptなどのWebアプリの作成、検証、外部への公開を簡単に行うことができます。

# サンドボックスを立ち上げてみる
サインアップは[こちら](https://codesandbox.io/signin)からGitHubまたはGoogleアカウントで行えます。

サインインすると下記のようなダッシュボードが開きます。ここで自分が作成したサンドボックス環境を管理できます。

新しいサンドボックスの作成する場合は、右上の[+ Create]をクリックします。

![image-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676048/a99a448a-526c-43c6-a70a-51aca1a55c07.png)


すると代表的なSingle Page Applicationはもちろん、よく使われるWebアプリフレームワークがあらかじめ導入されたテンプレートが公式で用意されています。

![image-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676048/ebce8250-1394-4711-be47-607c8fbfd657.png)

適当なテンプレートを選択してみます｡

今回はReact TypeScriptを選択しました｡

![image-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676048/62f9237a-7d6b-4560-aede-9f68839253c1.png)

こんな感じのエディタがブラウザ上に開きます｡

軽くアコーディオンを試すためのコードを書いてみました｡

![image-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676048/4215be6c-f314-44db-8e67-3051637640f0.png)

コードを変更すると右側のブラウザプレビューに即座に反映されます。

# ブログ記事への埋め込み
サンドボックスのブログ記事への埋め込みをしたい場合は、サンドボックス画面右上の[Share]をクリックします。

![image-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676048/c2aedf5c-327d-4ba7-adf4-a93ae959219a.png)


表示されるダイアログの[Embed]をクリックします。

![image-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676048/ca5c2dc2-e3f7-4f45-bfea-f37f57d66002.png)

[Copy Embed Code]をクリックするとifarameタグが取得できるので、そのままブログのエディターに貼り付けます。

![image-9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676048/8d65615c-20aa-485a-a1c9-f0eff1029b2a.png)

また、サンドボックスのURLを共有すればそのままソースコードの共有もできて便利です。


# 注意点
無料のFree版で作成できるのはパブリックサンドボックスのみです。

非公開のプライベートサンドボックスを作成したい場合は有料のPro版にアップグレードする必要があります。

パブリックサンドボックスの場合は、URLが分かればサンドボックスにアクセスできてしまうので、秘匿情報をアップロードしないように注意しましょう。

# 参考サイト
[Webアプリケーションの実装ネタをブログ記事にするならCodeSandboxがすごく便利 - DevelopersIO](https://dev.classmethod.jp/articles/condsandbox-is-really-useful/)
LiteLLM管理画面のログインエラーを解決する方法

## エラー内容

LiteLLMの管理画面にログインしようとすると、以下のようなエラーが発生することがあります。

```json
{
  "error": {
    "message": "Authentication Error, User not found, passed user_id=default_user_id",
    "type": "auth_error",
    "param": "None",
    "code": "400"
  }
}
```

## 解決方法

以下の手順で問題を解決できました。

### 1. docker-compose.ymlでイメージを更新

```yaml
image: ghcr.io/berriai/litellm-database:main-v1.63.6-nightly
```

### 2. .envファイルを更新

```
LITELLM_MASTER_KEY="sk-1234"
LITELLM_SALT_KEY="your_random_salt_key"
UI_USERNAME=admin
UI_PASSWORD=sk-1234
PROXY_ADMIN_ID=admin
```

### 3. 管理者ユーザーを手動で作成

```bash
curl --location 'http://localhost:4000/user/new' \
--header 'Authorization: Bearer sk-1234' \
--header 'Content-Type: application/json' \
--data-raw '{"user_email": "admin@example.com", "user_id": "admin"}'
```

### 4. ログイン

- ユーザー名: admin
- パスワード: sk-1234（UI_PASSWORDの値）
自宅サーバー 自作NASボトルネック有無調査

# NASが流行っているがまだまだ高い
ので自作しよう。

## 目標
ネットワーク速度上限まで速度をあげたい
→達成を確認

## ボトルネックを調査する
結論ボトルネックはなく、ネットワーク帯域をおおむね使い切れているとわかった。安心。
我が家のネットワークは1000Mbpsが仕様。

### まとめ
| 測定箇所 | Gbps | 取得値 |Note|
|:-:|:-:|:-:|:-:|
| SMB転送  | 0.88 | 112647.1 kb/s  ||
| ネットワーク  | 0.936  | 936Mbits/sec  ||
| ディスクWrite  | 2.696  | 337MB/sec  |HWスペックより大きな値で疑問あり|


### ネットワーク速度
server
```
$ iperf -s
------------------------------------------------------------
Server listening on TCP port 5001
TCP window size:  128 KByte (default)
------------------------------------------------------------
[  1] local 192.168.1.29 port 5001 connected with 192.168.1.70 port 42854
[ ID] Interval       Transfer     Bandwidth
[  1] 0.0000-10.0201 sec  1.09 GBytes   936 Mbits/sec
```

client
```
$ iperf -c 192.168.1.29
------------------------------------------------------------
Client connecting to 192.168.1.29, TCP port 5001
TCP window size: 16.0 KByte (default)
------------------------------------------------------------
[  1] local 192.168.1.70 port 42854 connected with 192.168.1.29 port 5001 (icwnd/mss/irtt=14/1448/314)
[ ID] Interval       Transfer     Bandwidth
[  1] 0.0000-10.0214 sec  1.09 GBytes   936 Mbits/sec
```
### ファイル書き込み速度
server
```
$ dd if=/dev/zero of=/tmp/testfile bs=1M count=2048 oflag=direct
2048+0 records in
2048+0 records out
2147483648 bytes (2.1 GB, 2.0 GiB) copied, 6.36633 s, 337 MB/s
```

### SMBでの実転送速度
client
```
$ smbclient //192.168.[server address]/ -U [username] -t 60 --max-protocol=SMB3
Password for [WORKGROUP\user]:
Try "help" to get a list of possible commands.
smb: \> put dummy_2GB.bin 
putting file dummy_2GB.bin as \dummy_2GB.bin (91263.8 kb/s) (average 91263.8 kb/s)
```

kb/sがkbit/sなのかkbyte/sなのかわからず、下記で時間を測定したところ、結論、kByte/sであることがわかった。
2GB/20sec = 100MB/sec = 

```
$ time smbclient //192.168.[server address]/ -U [username] -t 60 --max-protocol=SMB3 -c "put dummy_2GB.bin"
Password for [WORKGROUP\username]:
putting file dummy_2GB.bin as \dummy_2GB.bin (112647.1 kb/s) (average 112647.2 kb/s)

real	0m20.594s
user	0m0.064s
sys	0m2.681s
```
滝沢ハッカソンver7に参加した感想

# 前回の課題・今回の目標

- 音や視覚的な要素で利用者を引きつける
- アイデアの重要性を再確認
- ターゲット層を明確に設定
- 利用者全員が使うメリットを感じられるものを作成
- 使ってみたいと思わせるアプリケーションを目指す


## テーマ
自治体が抱える課題に挑戦せよ！〜地方の農業を支える新しいつながりを創る〜

## 作成物
農助
https://hackathon-ver7-18df0.web.app

## 使用技術
- フロントエンド：React
- バックエンド：Firebase  
- 発表資料：Googleスライド


## 概要・背景

### ターゲット
- 農家（法人）および利用者（主に学生）

### 背景・目的
- 滝沢市の農業は後継者不足や経営の困難さが課題となっており、労働力不足や農業への意欲が低下しています。
- 地域の農家と働きたい人々、イベント参加者、農産物購入者をつなげることが目的です。

### 機能
- **利用者**: イベント、アルバイト情報、ショップ情報の閲覧、ログイン機能
- **農家（法人）**: イベントやアルバイトの募集、販売アイテムの作成機能

---

## 工夫した点
- UIデザインはAIに任せ、バックエンドの開発に注力しました。
- Firebaseを使用し、データの永続化を実現しました。


## 感想

### 良かった点
- チーム全員が分担して作業し、効率的に進めることができました。
- GitHubを用いたソースコードの連携により、開発がスムーズに進行しました。
- Git Flowを活用して、競合を防ぎながら作業を進められました。
- アイディアソンを長めに実施し、アイデアを深掘りできました。
- 初めてのWeb開発を経験し、成長を実感できました。
- ハッカソンでFirebaseを使い、データ永続化を実現できました。
- ターゲットを前回よりも明確に絞ることができました。
- Bolt.newやGeminiを使用し、UI基盤を構築できました。

### 次回改善点
- 競合が発生してしまったこと
- 改行コードの違いによる問題
- ファイル名の変更とファイル内容の変更を別々でpushしてしまったこと
airodump-ngでWi-Fiネットワークスキャンとパケットキャッチ

airodump-ngを使って、Wi-FiネットワークスキャンとターゲットWi-Fiのパケットをキャプチャしてみようと思います。

:::note  alert
この記事で記載する内容は全て学習のために自分自身のネットワークを使うことを徹底してください。
他人のネットワークに対して無断で行うことは法的に禁止されています。
:::

## 現在の状況
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3964004/37c30cbb-560d-4514-bbea-d9162b8459a0.png)

airmon-ngでWi-Fiアダプタをモニターモードにしています。

モニターモードに設定する方法は[「airmon-ngでモニターモードに変更する」](https://qiita.com/shunagas42/items/d7ddcba1f7e222c62e69)の記事で紹介しています。

## Wi-Fiネットワークをスキャン
近くのWi-Fiネットワークをスキャンします。
スキャンできる距離は使用するWi-Fiアダプタに依存します。

今回はaircrack-ngスイートの中でairodump-ngを使います。
airodump-ngはネットワークスキャン及びパケットスキャンに使用します。

以下コマンドでスキャンします。
```
sudo airodump-ng wlan0mon
```
大量のWi-Fiネットワークが出力されました。

私のスマホからテザリングしているWi-Fiはこちらです。

再度お伝えしておきますが、他の人の通信をキャプチャすることは不正アクセス禁止法に違反する可能性がありますので、絶対にやめてください。
学習用に自分のWi-Fiを使いましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3964004/10ccff56-6d04-432d-83ad-6cd295e19d20.png)

それぞれの項目の意味をまとめます。
・BSSID：アクセスポイント(AS)のMACアドレス
・PWR：信号強度（マイナス値で表記、0に近いほど強い）
・Beacon：ASが発信するビーコンフレームの数
・#Data：取得したデータパケットの数
・#/s：1秒あたりのパケット数
・CH：使用チャネル(11チャンネル=2452MHz)
・MB：最大通信速度（Mbps）
・ENC：暗号化方式（WEP/WPA/WPA2/WPA3など）
・CIPHER：暗号化アルゴリズム（CCMP/TKIP/WEPなど）
・AUTH：認証方式（PSK/SAE/MGTなど）
・ESSID：Wi-Fiのネットワーク名（SSID）

自分のWi-Fiは暗号化方式がWPA2、暗号化アルゴリズムがCounter Mode with CBC-MAC Protocol(CCMP)、認証方式はPSKだったので、現時点で脆弱性が多いものでないことを確認できました。

暗号化方式WPA3、認証方式SAEを使うことでさらに安全性を強化できます。

## パケットキャプチャ
キャプチャするWi-FiのBSSIDとCHを使って、以下コマンドでパケットをキャプチャします。
```
sudo airodump-ng -c <CH> --bssid <BSSID> -w capture wlan0mon
```
成功すれば、以下の画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3964004/40516a6e-bb5d-4402-ac68-9f648d8661df.png)

この画面から分かることを説明します。

上段はアクセスポイントの情報でスキャンした時とほとんど同じ情報です。
重複するものは省略します。
・RXQ：受信品質（パケットロスが少ないほど高い値）

下段はWi-Fiクライアント情報です。今回は何も接続していません。
・STATION：クライアントのMACアドレス
・Rate：クライアントとAP間での通信速度(Mbps)
・Lost：クライアントから送信されたパケットロスの割合(%)
・Frames：クライアントから送信されたフレーム(データパケット)の数
・Notes：何か特別なメモ等がある時表示
・Probes：クライアントがネットワークをプロービングしている時表示

実際にはPCを繋いで、下段にクライアント情報が表示されました。

今日のところは以上です。
CSV：ヘッダー変換(Python)

```
import csv

def replace_csv_header(input_file: str, output_file: str, header_mapping: dict):
    """
    CSVファイルのヘッダーを指定したマッピングに基づいて置き換える関数

    :param input_file: 元のCSVファイル名
    :param output_file: 変更後のCSVファイル名
    :param header_mapping: {元のヘッダー名: 置換後のヘッダー名} の辞書
    """
    with open(input_file, mode="r", newline="", encoding="utf-8") as infile, \
         open(output_file, mode="w", newline="", encoding="utf-8") as outfile:

        reader = csv.reader(infile)
        writer = csv.writer(outfile)

        # ヘッダーの変換
        header = next(reader)
        new_header = [header_mapping.get(col, col) for col in header]  # マッピングに基づいて置換
        writer.writerow(new_header)

        # 残りのデータを書き込む
        writer.writerows(reader)

    print(f"ヘッダーを変更したCSVを {output_file} に保存しました。")

# 使い方
header_mapping = {
    "user1": "田中",
    "user2": "ジョン",
    "user3": "サミー"
}

replace_csv_header("input.csv", "output.csv", header_mapping)

```
```
import csv

def load_header_mapping(mapping_file: str) -> dict:
    """
    ヘッダーの置き換えマッピングをCSVファイルから読み込む関数

    :param mapping_file: Key-Value形式のCSVファイル (ヘッダーなし)
    :return: {元のヘッダー名: 置換後のヘッダー名} の辞書
    """
    mapping = {}
    with open(mapping_file, mode="r", newline="", encoding="utf-8") as file:
        reader = csv.reader(file)
        for row in reader:
            if len(row) == 2:  # 正しいKey-Value形式のみ取得
                mapping[row[0]] = row[1]
    return mapping

def replace_csv_header(input_file: str, output_file: str, mapping_file: str):
    """
    CSVファイルのヘッダーを指定したマッピングに基づいて置き換える関数

    :param input_file: 元のCSVファイル名
    :param output_file: 変更後のCSVファイル名
    :param mapping_file: Key-Value形式のヘッダー対応表（CSVファイル）
    """
    header_mapping = load_header_mapping(mapping_file)

    with open(input_file, mode="r", newline="", encoding="utf-8") as infile, \
         open(output_file, mode="w", newline="", encoding="utf-8") as outfile:

        reader = csv.reader(infile)
        writer = csv.writer(outfile)

        # ヘッダーの変換
        header = next(reader)
        new_header = [header_mapping.get(col, col) for col in header]  # マッピングに基づいて置換
        writer.writerow(new_header)

        # 残りのデータを書き込む
        writer.writerows(reader)

    print(f"ヘッダーを変更したCSVを {output_file} に保存しました。")

# 使い方
replace_csv_header("input.csv", "output.csv", "header_mapping.csv")
```
TypeORMでSQL Serverにログインしようとしたら「Login failed for user 'sa'.」というエラーが出る

TypeORMを使用してDockerコンテナ内のSQL Serverに接続しようとした際、「Login failed for user 'sa'」というエラーが発生しました。このエラーの原因と解決方法について説明します。

### エラー内容

ユーザー名とパスワードが正しいにも関わらず、接続試行時に以下のようなエラーが出ました：

```
Failed to start the server: ConnectionError: Login failed for user 'sa'.
```

### 原因

エラーの原因は、SQL Server内にデータベースが存在しないことでした。SQL Serverは指定されたデータベースが存在しないと、ログインすらできないようです。（.NET EntityFrameworkはデータベースがなくてもマイグレーションでデータベースを作成できたので、その違いに戸惑いました。）

### 解決方法

1. **SSMS, Azure Data Studioなどでデータベースを作成**
   
   SQL Serverに接続後、`CREATE DATABASE`コマンドなどを使用して、接続したいデータベースを作成します。

2. **データベース作成後に再実行**

   データベースを作成した後、再度TypeORMの接続を試みてください。これで「Login failed for user 'sa'」エラーは解消され、ログインできるようになります。

### 最後に

`Login failed for user 'sa'`というエラーが出た場合、まずはデータベースが存在するかを確認してください。データベースが存在しないとログインできません。SSMSや他のSQLクライアントを使って、データベースを作成し、再度接続を試みることで、問題は解決できます。
【JavaScript】同期処理・非同期処理

# 同期処理（Synchronous Processing）
- 処理が順番に実行される
- 前の処理が終わるまで次の処理は始まらない
- シンプルだけど、重い処理があると全体が止まる（＝待ち時間が発生）

``` js
// 例）
console.log("1: 処理開始");

for (let i = 0; i < 1000000000; i++) {
  // 時間がかかるループ
}

console.log("2: 処理終了");
```
:::note info
1： 処理開始
（ループが終わるまで待つ）
2：処理終了
:::

**ループが終わるまでプログラムが完全に停止する**


# 非同期処理（Asynchronous Processing）
- 処理を並行して進められる
- すぐに終わらない処理（API通信・ファイル読み込みなど）を待っている間に、他の処理を進められる
- 効率が良いが、順番通りに動かないことがあるので注意

:::note info
APIからのデータ取得やファイル読み込みなどで必要
:::


```js
// 例） setTimeout を使った非同期処理
console.log("1: 処理開始");

setTimeout(() => {
  console.log("2: 2秒後の処理");
}, 2000);

console.log("3: 処理終了");

```

:::note info
1： 処理開始
3：　処理終了
（2秒後）
2： 2秒後の処理
:::

## 非同期処理の書き方
代表的なのは **コールバック、Promise、async/await** の3つ。

### ①コールバック関数
```js
function asyncProcess(callback) {
  setTimeout(() => {
    console.log("2: 非同期処理");
    callback();
  }, 2000);
}

console.log("1: 処理開始");
asyncProcess(() => {
  console.log("3: コールバック処理");
});
```
**⚠️問題点**
➡️ 「ネストが深くなる（コールバック地獄）」 ＝ 可読性が悪くなる


### ②Promise（プロミス）
非同期処理を扱うためのオブジェクト。
3つの状態（ステータス）を持つ
- pending（待機中）
    - 初期状態。まだ処理が終わっていない
- fulfilled（成功）
    - 非同期処理が 成功 して resolve() が呼ばれた状態
- rejected（失敗）
    - 非同期処理が 失敗 して reject() が呼ばれた状態

```js
function asyncProcess(success = true) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("2: 非同期処理");
      if (success) {
        resolve("データ取得成功");
      } else {
        reject("エラー発生");
      }
    }, 2000);
  });
}

console.log("1: 処理開始");

asyncProcess(true)
  .then((result) => {
    console.log("3: Promiseの処理");
    console.log(result);
  })
  .catch((error) => {
    console.error("エラー発生:", error);
  });

```

`.then()` で成功時の処理、`.catch()` でエラー処理

**✅ポイント**

-  `.then()` を使って処理をつなげる
- コールバックよりも見やすい

### ③async/await（最もシンプルなやり方）
```js
function asyncProcess() {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log("2: 非同期処理");
      resolve();
    }, 2000);
  });
}

async function main() {
  console.log("1: 処理開始");
  await asyncProcess();
  console.log("3: async/await の処理");
}

main();

```

## Promise と async/await の違い
|  | Promise | async/await |
|:-:|:-:|:-:|
| 書き方 | .then() と .catch() を使う | async 関数の中で await を使う |
| 可読性 | チェーンが長くなると見づらい | 同期処理のように書けるので見やすい |
| エラーハンドリング | .catch() を使う | try/catch を使う |
| ネスト | .then() をつなげると深くなりがち | シンプルでネストが少ない |
| 柔軟性 | Promise チェーンを使って処理をつなげられる | await を使うと順番に処理できる |



# 参考
https://qiita.com/Yuto_Tatsumi/items/cc87fd777dc47b8b4317
滝沢ハッカソンver6に参加した感想

# 滝沢ハッカソン (2024年6月29,30) ver6

### テーマ: 学校生活をよりよくするためには

### 作成物: 質問箱（キトク）

### 使用技術: Flutter (Dart)

### 発表資料: Canvaのスライド


## 概要・背景

### ターゲット
- 学校のことをまだよく知らない新入生や、学校に馴染み始めた学生

### 背景・目的
- 学校生活でわからないことを質問する際、先輩や先生に聞くのは少しハードルが高いと感じることが多いと思います。
- 一人ひとりに質問して回るのは非効率で、匿名で気軽に質問できる場を提供したいと考えました。
- 自身の経験として、テニス部に入る際、SNSを使っていなかったため、先輩に一人一人聞いて回ったことがあり、そのプロセスが非常に非効率であったと感じました。
- 特に新入生にとっては、質問すること自体にハードルを感じるため、匿名で質問できるサービスが必要だと思いました。


## 機能

- **質問ボード**  
  メイン画面には他のユーザーが投稿した質問が表示され、また新しい質問を作成するボタンがあります。

- **質問作成機能**  
  新しい質問を作成する際、テーマ、カテゴリ、具体的な質問を入力し、ホーム画面に追加されます。

- **回答機能**  
  投稿された質問に回答でき、回答には「good」と「bad」の評価ボタンを付けることができ、評価によって回答の信憑性を測定します。

- **カテゴリ絞り込み**  
  質問はカテゴリごとに絞り込むことができ、ユーザーは興味のあるトピックを簡単に見つけることができます。


## 工夫した点

- ユーザーが気軽に使えるように、イメージカラーに「青」を選び、親しみやすい印象を与えました。
- 匿名性を保ちつつ、質問内容が適当にならないように、「good」と「bad」ボタンを設置して評価を受ける仕組みを導入し、信頼性の確保に努めました。


## 感想

- **次回はデザインやアイデアにさらに力を入れたい**  
  前回は全部で4つのグループがあり、自分達だけがWebページの作成をし、他のチームはアプリケーション開発をしていたため、少し悔しさを感じました。そのため、今回はアプリケーション開発に挑戦しました。

- **役割とチーム構成**  
  チームは4人で構成され、デザイン担当が2人、プログラム担当が2人でした。プログラム担当の1人は1年生でFlutterの経験が少なかったため、比較的簡単な作業（例えばボタンの色付け）を担当してもらいました。

- **プログラマーの役割の広がり**  
  最近のプログラマーは、プログラミングだけでなく、デザインにも関与することが重要だと感じました。良い機能を持つアプリケーションでも、デザインが悪ければユーザーに使ってもらえません。

- **優先順位の重要性**  
  すべてを作り上げることは難しいため、優先順位をしっかりと決めて取り組んだことが良かったです。結果的に、データベース以外の実装は完了しました。

- **回答者へのメリット**  
  回答者にメリットが感じられないため、次回は回答を促す仕組みを取り入れるべきだと感じました。次回は、回答者が積極的に参加したくなるような報酬や特典を導入するべきだと思いました。


## 次に向けて

- **アイデアが重要**  
  アプリやサービスの成功には、ターゲット層に最適なアイデアが欠かせません。次回はターゲット層のニーズをさらに深く理解し、具体的な機能に落とし込もうと思いました。

- **全員にメリットのある設計**  
  すべてのユーザーが使いたいと思えるアプリにするため、利用者全員がメリットを感じられるような仕組みを考えようと思います。

- **視覚的・聴覚的な魅力**  
  他のグループではボタンを押した際に効果音が鳴る機能が評価されていたので、アプリやサービスが『使ってみたい！』と思わせるように、視覚的および聴覚的な魅力を高める工夫を施していきたいと考えています。
【コマンドプロンプト】ドメインユーザーの検索

Windowsのコマンドプロンプトでドメイン内のユーザーを検索するコマンド。

```net user /domain ユーザー名```

*ユーザー名を入力しないとAD内のユーザー一覧を表示させることになるので、大規模なAD上のユーザーを検索する場合は注意が必要です。
滝沢ハッカソンver5に参加してみての感想

# 滝沢ハッカソン(2023年12月9日)ver5

### ハッカソンの感想と学び

ハッカソンでは普段接点が少ない分野の人たちと協力してwebページを開発しました。特にデザイン担当との作業が印象的でした。以下が主なポイントです：

- **新しい経験**: デザイン担当と協力するのは初めてでした。見た目が重要なwebページにおいて、速やかにデザインを作成してもらえたことで、自分はプログラミングに集中できました。
- **短期間の開発**: 限られた期限内で優先順位を考えながら開発を進める体験が新鮮でした。特に、制限時間内に機能を絞り込んで実装するスピード感に刺激を受けました。
- **意外な発見**: 自分が作りたいものを形にするのが思ったより難しくなく、予想以上に気軽に取り組めたことに驚きました。
- **楽しい雰囲気**: プログラミングだけでなく、チームメンバーと意見交換をしながら進める点が楽しく、非常に有意義な時間でした。

---

### webページの概要と背景

**webページのテーマ**: 「おじいちゃんやおばあちゃんが観光地をおすすめしてくれるサービス」

盛岡がニューヨークタイムズの観光地ランキングで2位に選ばれ、多くの観光客に盛岡の魅力を楽しんでもらいたいという思いで、このサービスを企画しました。特に観光地情報を提供するだけでなく、地元の人々の視点を活かしたアプローチを目指しました。

### 主な機能
- **ランダム観光地紹介**: ボタンを押すとランダムで観光地を表示し、観光地を探す過程そのものも楽しめるようにしました。
- **英語翻訳機能**: 海外観光客向けに、日本語以外の言語（英語など）で観光地情報を表示します。
- **一言コメント**: 観光地に詳しい「おじいちゃん」や「おばあちゃん」のコメントを加え、訪れる前に具体的なイメージを持ってもらえるようにしました。

---

### 工夫した点

- **キャラクターの活用**: 単なる情報提供ではなく、観光地に詳しいキャラクター（おじいちゃん・おばあちゃん）を登場させ、その人たちの一言コメントを加えることで、アプリに温かみを持たせました。
- **写真だけでは伝わらない情報**: 観光地に関する詳細な情報を、コメントという形で補完することで、ユーザーがより深く理解できるように工夫しました。
- **ChatGPTの活用**: 観光地に対する一言コメントを生成するためにChatGPTを活用しました。将来的には観光客や地元の人からコメントを募集できる仕組みを作りたいと考えています。

---

### 今後の展望

- **海外観光客へのアプローチ**: 盛岡の魅力をより多くの人々に伝えるため、アプリを海外観光客向けにも積極的に展開し、観光を楽しんでもらえるようなサービスに成長させたいと思いました。
- **ターゲット層の具体化**: より使いやすいwebページにするため、ターゲット層を絞り込み、そのニーズに合わせた機能やUI設計を行っていきたいと考えたいです。
- **継続的な改良**: ユーザーからのフィードバックを元にアプリを継続的に改善し、データを蓄積しながらより使いやすい、魅力的なサービスに進化させたいと思いました。

ハッカソンを通じて、短期間で新しい体験と視点を得ることができ、大きな収穫となりました。これからも学びを活かし、さらなる開発に挑戦していきたいです。
【OCI】 VM.Standard.E2.1.Micro を軽く調整して pptp サーバにする

OCI一昨日からはじめたばっかりでぽっと出ですみません。

遅まきながら Always Free で VM.Standard.A1.Flex を取ってみようと思ったけど取れませんでした。ので、 VM.Standard.E2.1.Micro をお借りしています。OSは Oracle Linux 9 にしました。

---

まず、固定IPアドレスで開始してなかったので、以下を参考にさせていただいて、固定IPアドレスに変更します。

https://qiita.com/letian/items/c663461adc1e763e91dd

awsばっかりやってきたので固定IPアドレス無料はありがたい気がします。


---

デフォルトではじめたのでとりあえずディスクは50GB, ところが15GBほど `/var/oled` に取られてしまってるので、まずここから整理したいです。

https://www.reddit.com/r/oraclecloud/comments/ywwp41/reclaiming_10gb_varoled/

を参考に、 /dev/mapper/ocivolume-root を45GBまで拡張できました。

```
dnf remove pcp
umount /var/oled
mkdir /var/oled/crash
lvremove /dev/mapper/ocivolume-oled
lvextend -L +15G /dev/mapper/ocivolume-root
xfs_growfs -d /dev/mapper/ocivolume-root
vi /etc/fstab
```

---

次に、yumが不調なので、以下を参考に不要なリポジトリを無効にしたり、swapを増やしたりします。

https://blog.alicey.dev/2024/10/oci-yum-oom.html

```
vi /etc/yum.repos.d/oci-included-ol9.repo
swapoff /.swapfile
rm /.swapfile
dd if=/dev/zero of=/.swapfile bs=1M count=4096
chmod 600 /.swapfile
mkswap /.swapfile
swapon /.swapfile
```

---

selinux を Disabled にしたら、pptpをインストールしていきます。el9にパッケージは見当たらなかったので、el8をむりやり入れます。

ちなみに、https://dl.lamp.sh/linux/rhel/el9/x86_64/ に el9 の ppp / pptp のパッケージがありますね。勇気のある方はどうぞ。私は入れてません。

https://gist.github.com/yyang/8298541b19594bd09402 を参考に

```
dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm

yum install https://yum.oracle.com/repo/OracleLinux/OL8/baseos/latest/x86_64/getPackage/ppp-2.4.7-26.el8_1.x86_64.rpm
yum install https://dl.fedoraproject.org/pub/epel/8/Everything/x86_64/Packages/p/pptpd-1.4.0-23.el8.x86_64.rpm

echo 'localip 10.10.0.1' >> /etc/pptpd.conf
echo 'remoteip 10.10.0.100-199' >> /etc/pptpd.conf

echo 'ms-dns 8.8.8.8' >> /etc/ppp/options.pptpd
echo 'ms-dns 8.8.4.4' >> /etc/ppp/options.pptpd

echo 'YOUR_ID pptpd YOUR_PASSWORD *' >> /etc/ppp/chap-secrets

echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
sysctl -p

firewall-cmd --permanent --new-service=pptp

cat >/etc/firewalld/services/pptp.xml<<EOF
<?xml version="1.0" encoding="utf-8"?>
<service>
  <port protocol="tcp" port="1723"/>
</service>
EOF

firewall-cmd --permanent --zone=public --add-service=pptp
firewall-cmd --permanent --zone=public --add-service=gre
firewall-cmd --permanent --zone=public --add-masquerade
firewall-cmd --reload

systemctl start pptpd
systemctl enable pptpd
```

その後、OCIの Security List か Network Security Groups で TCP 1723 を解放すれば、pptpで接続できるようになると思います。

windowsから接続するときは、VPNを設定してから、アダプターのオプションで、当該接続のプロパティを表示し、`セキュリティ` タブから `Microsoft CHAP Version 2 (MS-CHAP v2)` のみチェックを入れておくと良いようです。

以上
M5stackなどのESP32製品のMACアドレスを簡単に調べる用スクリプト

# M5stackなどのESP32製品のMACアドレスを簡単に調べる用スクリプト

M5stackでなんか作ってるときに、MACアドレス知りたいなーということがまれによくあるのですが、なんかわざわざCのコードを機器にアップロードして確認する（という事例が多くて）だけど面倒だったのでUSBつないだ状態で調べる用のスクリプトを作ってみたので公開してみる。

中で使ってるesptool.pyをそのまま使っても同じ情報取れるんですが、他の機器情報がドバっと出たり表示されたMACアドレスを0xFF形式に書き直すのがダルかったのでMACアドレスだけ手軽に見る用のラップスクリプトとして作ったものです。ESPNowに設定する時コピペできたら書き間違え防げるし。

他の機器情報も見たい場合はesptoolを生で使うで十分かなとも思います。

以下、手前みそですがGitHubのReadmeと同じ文章です。

https://github.com/u-tanick/get-MACaddress-from-COM-port

# get-MACaddress-from-COM-poat

## 簡単解説

やってることはシンプルで、[esptool](https://lang-ship.com/blog/work/esp32-esptool-py/) を叩いて返ってきた値からMACアドレスの部分をパースしてるだけです。なのでコード云々を解説するまでもないというかなんというか。

とはいえ、あったら便利かもなーと思ったので、見つけやすいように記事化しておきます。

## 概要・使用方法:

USBにつないだ機器のMACアドレスを取得する.  
第一引数にUSBデバイスが使用するCOMポートの番号を与える.  
MACアドレスは以下の2つのフォーマット形式で出力される.

``` sh
$ python getMacAddrFromCOM.py COM8
FF:FF:FF:FF:FF:FF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
```

## 使用要件:

機器を接続しているCOMポートの番号は、別途デバイスマネージャーなどで調べておくこと.

esptoolを使用するため事前にインストールしておくこと.

``` sh
$ pip install esptool
```

esptool.pyへのパスを正しく通しておくこと.  
下記は一例、esptool.pyの場所を正しく指定する.


``` sh
$ PATH=$HOME/.local/bin:$PATH
```

## EN

## Overview & Usage:

This script retrieves the MAC address of a device connected via USB.  
Pass the COM port number used by the USB device as the first argument.  
The MAC address will be output in the following two formats:

```sh
$ python getMacAddr.py 8
FF:FF:FF:FF:FF:FF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
```

## Requirements:

Check the COM port number of the connected device using Device Manager or another tool beforehand.

Install esptool before running the script:

```sh
sh
$ pip install esptool
```
Ensure that the path to esptool.py is correctly set.
The following is an example—adjust the path according to your environment:

``` sh
$ PATH=$HOME/.local/bin:$PATH
```
【JavaScript】日付の存在チェックにおけるタイムゾーンの影響

## はじめに
Webページの制作で「年」「月」「日」で入力欄が分かれているようなフォームを設置した経験がある方も多いのではないでしょうか。こうしたフォームだと「11月31日」のような存在しない日付を入力できてしまうので、「日付が正しいか」のチェックは必要不可欠です。
| 年         | 月         | 日         |
|-----------|-----------|-----------|
| ▼ 2024   | ▼ 11       | ▼ 31      |


よくあるチェック方法の1つとして「`getDate` で返る『日』が入力された値と同じか」が挙げられると思いますが、下記のようなコードの場合、ある状況下において **「正しい日付なのに誤った日付だと判定される」** 事象が発生します。
```javascript
// 11月に31日は存在しない
year = 2024
month = 11
date = 31

// 「2024-11-31」は「2024-12-01」扱いとなる
if (new Date(`${year}-${month}-${date}`).getDate() != date) {
  // getDate()で「1」が返るためdateと一致しない
  console.log('誤った日付です')
}
```


## ローカルタイムゾーンの影響
「国内サイトに海外からアクセスした」ケースを想定します。今回はGoogle Chromeのデベロッパーツールでタイムゾーンを「サンフランシスコ(UTC-7)」に設定しコンソール上で動作を検証してみました。

![スクリーンショット 2025-03-19 21.21.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3941310/b497293c-9a16-4099-91ec-bef6afb9387a.png)


すると、「2024-11-30」は正しい日付ですが、「誤った日付である」と誤判定してしまっています。

![スクリーンショット 2025-03-19 19.33.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3941310/a90dee8d-a2e2-4cdf-9505-f1e76e6a3b08.png)


`getDate()` で何が返っているか見てみましょう。
![スクリーンショット 2025-03-19 19.35.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3941310/6d85b581-a48b-43c8-ba68-a4c2473d76e0.png)


「2024-11-30」と入力しているにも関わらず、「29」が返ってきています。

## getDateの仕様
JavaScriptのドキュメントには下記のように記されています。
> getDate() メソッドは、地方時に基づき、指定された日付の「日」を返します。

今回挙げた例の場合、日付文字列をそのまま判定処理に渡した結果、タイムゾーンの影響を受けて意図した挙動とは違う動きとなっていました。
JavaScriptにおける日付の扱い全般に言えることですが、ブラウザや環境によって異なる解釈をされる余地が生まれないよう、タイムゾーンを明示的に指定する等の対応が必要でした。

あるいは、単に「入力された日付と同じこと」を確認したいだけならば、ローカルタイムゾーンの影響を受けない `getUTCDate()` を使っても良いかもしれません。

**(2025/3/24追記)**
**コメントでご指摘をいただきました。`new Date`に日付文字列を渡して正しく解釈されると保証されているのはISO8601形式の場合だけで、このケースも「(多くのクライアントで)UTC時刻として扱われる」から結果的に合っている、というものです。**

![スクリーンショット 2025-03-19 19.36.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3941310/887353f5-9989-44ea-97bb-6f53bfe7f463.png)



## まとめ
- JavaScriptで日付を扱う際はタイムゾーンによく留意すること
- 特に、海外からもアクセスがあるようなWebサービスは要注意


## 参考
[Date.prototype.getDate() - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/getDate)
[Date.prototype.getUTCDate() - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/getUTCDate)
VitestとJestの違い -テストコード学習3本目


# 概要
このブログ記事は、テストフレームワークを学ぶ過程で執筆した記事の第2回です。VitestとJestの紹介と簡単な比較を行っています。

# Vitestについて
Vitestは、Vite環境向けに最適化されたjavascript,typescript用の高速なユニットテストフレームワークです。ViteとVitestの開発者であるEvan You（Vue.jsの作者）によって2022年に開発されました。
``` typescript
// vitestの基本的なテスト例
import { describe, it, expect } from 'vitest'

describe('基本的な計算', () => {
  it('足し算が正しく動作する', () => {
    expect(1 + 1).toBe(2)
  })
})
```

# Jestについて
Jestはシンプルさを重視したJavaScript用のユニットテストフレームワークです。facebook(meta)によって2012年に開発されました。
``` javascript
//jestの基本的なテスト例
test('足し算が正しく動作する', () => {
  expect(1 + 2 ).toBe(3);
});
```

# VitestとJestの比較
| 特徴 | Vitest | Jest |
|------|--------|------|
| **実行速度** | 非常に高速 | 比較的遅い（特に起動時間） |
| **設定の一元化** | Vite設定と共有・統一可能(vite.config.js) | Vite設定と独立した設定が必要(jest.config.js) |
| **スナップショットテスト** | サポート | サポート |
| **ウォッチモード**<br>(ファイルが変更されるたびに自動でテストを再実行する機能) | サポート | サポート |
| **カバレッジレポート** | v8/Istanbul | istanbul |
| **APIの互換性** | Jest APIと高い互換性あり | 独自API |
| **TypeScriptサポート** | ネイティブサポート | 追加設定が必要 |

参考記事:
https://vitest.dev/guide/coverage

# npm trendでの比較

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1893698/bd087c9f-5827-42cd-a343-321085909c52.png)
ラズパイで物体検出 yolo5 失敗談

## まず作るもの。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3882753/b02a410f-6122-43f2-a67c-612044fa8a8e.png)

今回はこの赤丸部分です。
サムターンの開閉を物体検出します。
モデルはyolo5を使用します。
【要件】10FPSくらいで画像処理しながら物体検出したい。
使うラズパイは4B RAM 4GB

## できたもの
https://www.youtube.com/shorts/yep-A3paJsQ

バッファクリアの処理いれてるんですが遅延しますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3882753/5c40b780-19e1-4628-92f9-257b05adda6e.png)

FPS:0.5の世界初めてみたw

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3882753/48329e3b-e150-4fca-84aa-08c14c4dcad8.png)

物体検出はできている模様

物体検出できてもこんだけ遅いと要件に合わないので失敗でした。

## なぜ失敗したか

・モデルが重い
→ラズパイ用に軽いモデルを使うのが吉 今回はwindowsで作ったモデルを流用しようとした。
→MobileNet SSD など。

・ラズパイのスペックが足りない
→GPUがない
→CPUも弱い

### 次回成功するために。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3882753/43d5c49f-4ede-4107-830c-4a9545a773a5.png)

①これを購入 -￥13,000 (泣)
エッジデバイス(ラズパイ)での物体検出の手助けをしてくれるらしい。youtubeで動画見てたら30FPSで画像処理しながら推論してた。強い。

②軽めのモデルを使用。
↑のCoral USB Accelerator は Edge TPU を搭載しており、主に TensorFlow Lite（TFLite） を最適化したモデルで動作します。
TensorFlow Liteあたりを学習して臨む。

次回の記事ではこれの挑戦です。

## 失敗談(まだある)
・windowsで作ったyolo5のモデルはラズパイで使えません。
・ラズパイで、windowsで作ったモデルを使うためにモデルをonnxに変換するも、うまくいきません。
・ラズパイで学習させるも20時間かかる。

一つずつ書いていく。

## windowsで作ったyolo5のモデルはラズパイで使えません。
学習した結果のモデルはこのbest.ptなのですが、ラズパイで使おうとするとwindowsPathが書かれていてラズパイで認識しませんみたいなこと言われます。
chatgptに相談すると、ラズパイでも使えるようにモデル変換することを勧められます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3882753/b138e8d9-5789-45ae-bfdf-0373c1f87a58.png)

## ラズパイで、windowsで作ったモデルを使うためにモデルをonnxに変換するも、うまくいきません。
onnxを使うための環境設定がうまくいきませんでした。
Raspberry Pi は ONNX Runtime の公式サポートがないため、onnxruntime をビルドする必要があります。
→色々chatgptしたり検索したりして進めましたがうまくいかず、windowsでモデルを作ったノリでラズパイでモデルを作ることにしました。

## ラズパイで学習させるも20時間かかる。
ラズパイは非力なので機会学習(めっちゃリソースを消費するという認識でおけ)に適さないことはわかっていたのですが、ラズパイで使うモデル作成に手間取っているので、ラズパイで学習させることに。
↓実際使ったコマンド
```
python train.py --img 640 --batch 4 --epochs 100 --data /home/pcmainte/project_ras3/dataset/dataset.yaml --weights yolov5s.pt
```
--img 640	入力画像のサイズ（640×640ピクセル）
--batch 4	バッチサイズ（1回の学習で処理する画像の数）
--epochs 100	学習エポック数（学習を100回繰り返す）

##### 1. --img 640（入力画像サイズ）
YOLOv5 は 正方形の画像 を使用するため、この例では 640×640 で学習。
小さくするとメモリ消費が減るが精度が落ちる。
大きくすると精度は上がるが処理速度が落ちる。
一般的なサイズ: 416, 512, 640, 1280 など

##### 2. --batch 4（バッチサイズ）
1回の学習ステップ（ミニバッチ）で処理する画像の数。
大きくすると学習が速くなる が、メモリを大量に消費する。
小さくすると学習が安定する が、時間がかかる。
Raspberry Pi では 2以下が推奨（VRAMが少ないため）。

##### 3. --epochs 100（学習エポック数）
学習データを何回繰り返して学習するか。
例えば 100 にすると、全データを 100 回学習。
一般的には 50 〜 300 が適切。
--epochs 50 で結果を見て、調整するのが良い。

##### ただしこのコマンドではラズパイのリソースが足りず処理が強制終了しています。

→batch 1で学習開始したら成功しました。
ただし20時間かかりました(^_^;)
後半でリソース不足で強制終了させられたり、エラー落ちしたりしなくて良かった・・・
実際のコマンドはこれです。
```
python train.py --img 640 --batch 1 --epochs 100 --data /home/pcmainte/project_ras3/dataset/dataset.yaml --weights yolov5s.pt
```