OmniAICreator/Qiita-1.07M huggingface dataset:
Amazon FSx




## 1.FSx for Windows

### 1.1.FSx For Windows File Server
<font color="red">**AWS内のシステムからの**</font>ファイル共有用です。
FSx For Windows File Serverのファイルシステムには、ファイルシステムの作成時に設定されたスループット容量があります。ファイルシステムのスループット容量は、必要に応じていつでも変更できます。
DFSR（Distributed File System Replication）を備えたファイル共有を利用できます。

共にFSという文字を含んでいて紛らわしいですが、FSx for Windows File ServerはNFSストレージとして利用することはできません。(AWS Storage Gateway ファイルゲートウェイを使います)


### 1.2.ADサーバーとの連携
FSx For Windows File Serverは、オンプレミスのActive Directory(AD)サーバーと連携させることができます。これにより、既存のADにおけるユーザーやアクセス権の管理を踏襲してAWS上でも同等のアクセス制御を実現することができます。


### 1.3.SMB (Server Message Block) 
SMBは、主にWindowsを中心とした環境でLANを通じてファイル共有やプリンタ共有などに使用される通信プロトコルの総称です。OSI参照モデルでは第7層アプリケーション層に該当します。認証つきプロセス間通信機構としても動作します。

AWSでSMBファイル共有を作成するには、AWSのFSx for Windows File Serverを使用するのが一般的な方法です。

## 2.FSx for Lustre
FSx for Lustreは高速でスケーラベルで共有可能なストレージサービスで、機械学習などのストレージに最適です。

FSx for Lustreの特徴の一つとして、S3との連携があります。S3バケットをFSx for Lustreファイルシステムに統合すると、ファイルシステムとS3バケット間でデータを自動的にインポートおよびエクスポートします。これにより、S3に保存されているデータをFSx for Lustreから透過的に利用できるようになります。
### [2.1.Lustre (ラスター)](https://ja.wikipedia.org/wiki/Lustre_(%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0)) 
Lustreは、一般に大規模のクラスターコンピューティング・スーパーコンピュータで使用されている分散ファイルシステムです。

### 2.2. Amazon SageMakerとの連携
FSx for Lustreは、Amazon SageMakerとの統合が公式にサポートされており、大規模な機械学習ワークロードに対して非常に高性能なファイルストレージを提供します。

- SageMakerトレーニングジョブの入力データとしてFSx for Lustreをマウント可能です。

- データの前処理やバッチ処理において、大容量のファイル読み書きが必要なケースで、S3よりも高速にアクセスできます。

- SageMaker Studio Notebooksからも、FSx for Lustreをマウントしたトレーニングインスタンスを利用できます。

- 学習済みモデルの保存や後続処理にもFSx for Lustreを活用することで、I/Oボトルネックを回避できます。

S3とFSx for Lustreを連携させておくことで、S3にあるデータをFSxで高速に処理し、結果を再びS3へエクスポートすることも可能です。

## 3.参照サイト

- [公式の漫画](https://aws.amazon.com/jp/campaigns/manga/smb-cloud-dx/vol2/)
robloxでassistant その99

# 概要
robloxでassistantやってみた。
練習問題やってみた。

# 練習問題
ライントレースロボットを、シュミレーションせよ。
センサーを、2個にせよ。

# 手順
- ServerScriptServiceに、scriptを追加。
- スクリプトを書く。

```

local d0 = Instance.new("Part", workspace)
d0.Anchored = true
d0.Size = Vector3.new(1, 1, 1)
local d1 = Instance.new("Part", workspace)
d1.Anchored = true
d1.Size = Vector3.new(1, 1, 1)
local road0 = Instance.new("Part", workspace)
road0.Anchored = true
road0.Size = Vector3.new(12, 1, 4)
road0.CFrame = CFrame.new(0, 1, -20) * CFrame.Angles(0, math.rad(90), 0)
road0.Name = "road"
local road1 = Instance.new("Part", workspace)
road1.Anchored = true
road1.Size = Vector3.new(12, 1, 4)
road1.CFrame = CFrame.new(-20, 1, -20) * CFrame.Angles(0, math.rad(90), 0)
road1.Name = "road"
local road2 = Instance.new("Part", workspace)
road2.Anchored = true
road2.Size = Vector3.new(24, 1, 4)
road2.CFrame = CFrame.new(-10, 1, -28) * CFrame.Angles(0, math.rad(0), 0)
road2.Name = "road"
local road3 = Instance.new("Part", workspace)
road3.Anchored = true
road3.Size = Vector3.new(24, 1, 4)
road3.CFrame = CFrame.new(-10, 1, -12) * CFrame.Angles(0, math.rad(0), 0)
road3.Name = "road"
local part = Instance.new("Part", workspace)
part.CFrame = CFrame.new(-1, 2, -24) * CFrame.Angles(0, math.rad(90), 0)
local s = 90
local h = 19
local i = 15
local f = 6
local b = 4
while true do
	local rayOrigin = part.Position + Vector3.new(math.cos(math.rad(s + h)) * -2, 0.1, math.sin(math.rad(s + h)) * 2)
	local rayDirection = part.Position + Vector3.new(math.cos(math.rad(s + h)) * -2, -10, math.sin(math.rad(s + h)) * 2)
	d0.Position = part.Position + Vector3.new(math.cos(math.rad(s + h)) * -2, 1.2, math.sin(math.rad(s + h)) * 2)
	local raycastResult = workspace:Raycast(rayOrigin, rayDirection)
	if raycastResult then
		if raycastResult.Instance.Name == "road" then
			rayOrigin = part.Position + Vector3.new(math.cos(math.rad(s - h)) * -2, 0.1, math.sin(math.rad(s - h)) * 2)
			rayDirection = part.Position + Vector3.new(math.cos(math.rad(s - h)) * -2, -10, math.sin(math.rad(s - h)) * 2)
			d1.Position = part.Position + Vector3.new(math.cos(math.rad(s - h)) * -2, 1.2, math.sin(math.rad(s - h)) * 2)
			raycastResult = workspace:Raycast(rayOrigin, rayDirection)
			if raycastResult then
				if raycastResult.Instance.Name == "road" then
					part.Velocity = Vector3.new(math.cos(math.rad(s)) * -f, 0.3, math.sin(math.rad(s)) * f)
				else
					part.Velocity = Vector3.new(math.cos(math.rad(s)) * b, 0, math.sin(math.rad(s)) * -b)
					s += i
					part.CFrame = part.CFrame * CFrame.Angles(0, math.rad(i), 0)
				end
			end
		else
			part.Velocity = Vector3.new(math.cos(math.rad(s)) * b, 0, math.sin(math.rad(s)) * -b)
			s += -i
			part.CFrame = part.CFrame * CFrame.Angles(0, math.rad(-i), 0)
		end
	end
	wait()
end






```


# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/5c3936a4-3d64-fc67-3726-48a48f6f07a0.png)

以上。
Jetpack Composeでcontextを取得する方法

# 実践
```
val context = LocalContext.current
```
これだけでOK

# 注意
自分はToastをJetpack Composeで使用するときにこの状況になったのですが、
```
@Composable
fun MyScreen() {
    Button(
        onClick = {
            Toast.makeText(LocalContext.current, "", Toast.LENGTH_SHORT).show()
        }) {}
}
```

このようにcontextが必要な引数に直接 **LocalContext.current**を入力したところ、以下のようなエラーが出ました。
>@Composable invocations can only happen from the context of a @Composable function

このエラー内容は、簡単にいると@Composable アノテーションを付けた関数内でのみ呼び出すことができます。

といった内容なので、インスタンス化してから引数として渡すようにします。

```
@Composable
fun MyScreen() {
    val context = LocalContext.current

    Button(
        onClick = {
            Toast.makeText(context, "", Toast.LENGTH_SHORT).show()
        }) {}
}
```
これでエラーがなくなりました。
OpenWrtとWireGuardでフルトンネルしつつ、mwan3でトンネル障害発生時に自動でwanへ経路変更する

# 設定
> 今回はフルトンネル出口側を`親`、入口側を`子`と呼びます。
> 特に明記されていない場合、記載されている作業を親子両方に行ってください。

## 下準備(`親`/`子`)
luciにログインして`システム`→`ソフトウェア`より`wireguard`で検索し下記の4つをインストールする
- wireguard-tools
- kmod-wireguard
- luci-proto-wireguard
- mwan3(`子`のみ)

## インターフェース作成(`親`/`子`)
`ネットワーク`→`インターフェース`を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3314743/b6ca4c70-3b4b-c82b-28b4-06ec2f2e073f.png)をクリック
適当な名前を付けてデバイスを`WireGuard VPN`にする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3314743/ff2c9b79-4ce9-f77c-3e98-85c2a86e9e9b.png)
とりあえず基本に沿っていい感じに設定すればOK、重要なのは下記の5つ。
- `詳細設定`タブの`ゲートウェイメトリックを使用`をwanより大きい数値にする
(よくわからなければ`0`より大きい数字でOK)
- `ピア`タブにて許可されたIPに相手ピアのIPアドレスをサブネット無しで設定する
- 拠点間通信をしたい場合、許可されたIPに相手NWのサブネットを追加する
- `子`のみ許可されたIPに`0.0.0.0/0`を追加する
- `親`/`子`共に`許可されたIPのルート`にチェックを入れる

この状態でWireGuardインターフェースに設定したIPアドレスに対し相互にPingして通信でき、ついでに拠点間通信も出来ていればインターフェースの設定はおしまい。

## mwan3設定(`子`)
1. `ネットワーク`→`MultiWan Manager`を開き、`インターフェース`タブを開く
1. `ネットワーク`→`インターフェース`の名前(色がついている所)と同じ名称で名前を入れ、`追加`を押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3314743/a83bd916-8af0-fba4-8cc4-9672c8dc2c61.png)
(おそらく一般的な環境であれば`wan`/`wan6`/`今回作成したWireGuardインターフェース`の3つを作ることになると思われる)
1. 各インターフェースを適宜いい感じに設定する
WireGuardインターフェースの場合のみ、`トラッキングホスト名またはIPアドレス`の箇所に対向のWireGuard IPアドレスを指定し`conntrackテーブルのクリア`に`接続時`/`切断時`を追加する。
    
    :::note warn
    `conntrackテーブルのクリア`設定を忘れるとオフライン判定になってもいつまで経ってもルートが切り替わらない原因になるので注意
    WireGuardインターフェースのみ下記の画像の通りになればOK
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3314743/fe5876c7-c541-7cb9-a5c1-30c809bbfea9.png)
    
1. `メンバー`タブを開き、適当にメンバー設定を行う。オススメは`<IF名>_<メトリック>_<ウエイト>`で名付けると分かりやすい。
インターフェース名やポリシー、ルールと名称を被せることは出来ないので注意。
今回はWireGuardインターフェースを最優先で通信させたいので、下記画像のような状態になればOK。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3314743/3d677bc0-6c35-2c63-5f83-c8a335fd85ee.png)
メトリックは小さければ小さいほどインターフェースが優先され、ウエイトは同じメトリックの場合の重み付けとして使われる。
1. `ポリシー`タブを開き、`WireGuard`、`wan`、`wan6`の順に使われるポリシーと、`wan`、`wan6`のみ使われるポリシーの2つを作る。
下記のような感じに設定できればOK。ここでも名称を被せることは出来ないので注意。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3314743/76e8f2d7-c8eb-1bab-72e5-ea0901ce4196.png)
1. `ルール`タブを開き、下記画像のように設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3314743/21395927-aa7f-dca7-b1be-da29859b95d6.png)
多分default_v6は無くても問題ないが、なんとなく付けておいた。
特定のIPアドレスだけトンネルから除外したい場合はdefaultルールの上に特定IPアドレス宛の通信をwan側に向けるポリシーに向けてやったり、一部のアドレスだけトンネルしたい場合は宛先アドレスを書き換えてやればOK。

ここまで正しく設定できていれば、OpenWrtのトップページ最下部に下記画像のような表示が増えているはず。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3314743/12f4fd14-b522-5c53-8f51-fd0317e8bf08.png)

試しに対向のWireGuardを停止してみると、WireGuardインターフェースが黄色→赤と色が変わり、オフラインになって自動で経路が`wan`に切り替わる。
インターフェースを再起動すると、黄色→緑に戻り、自動で経路が戻るようになります。
お疲れ様でした。
ActiveRecord のパフォーマンス関連 Tips

## はじめに
これは ActiveRecord のメモリ節約や処理速度向上等のパフォーマンスに関していくつか調べたり知り得たことを書き留めたメモです。どちらかというと API よりバッチ処理に主眼をおいた Tips になります。
またパフォーマンスを重視する場合、コードの読みづらさだったり、バグを仕込んでしまったりとのデメリットとのトレードオフになることも多いのでその点はご留意ください。


## インスタンス化を避ける
ActiveRecord のインスタンス化はかなり時間の掛かる処理です。
例えば CSV を元に何千何万件の登録を行うような処理で、事前に各レコードに対して ActiveRecord のバリデーションやフックアクション（`before_validation`とか）を通したいことがあります。
この時に毎回 `new` して `valid?` していくとめちゃくちゃ時間がかかりますが、一度初期化したインスタンスにデータだけを上書きして使い回すようにするとかなり早くなります。ただし、使い回すことによる副作用もあると思いますのでその点は十分ご注意ください。



## `eager_load` しない
あるテーブルの条件を使って関連テーブルの値の一覧を取得したい場合、`eager_load` や `preload` と `map` を組み合わせるより `pluck` を使える形に直したほうが早くなります。
※ N+1 クエリの解消等の目的で使う分には当然 `eager_load` 等したほうが良いです。

以下のようなテーブル構造で `Device` の一覧を元に `Account#code` を取得したい場合、

```ruby:例
class Device
  belongs_to :user
  has_one :account, through: :user
end

class User
  has_one :account, dependent: :destroy
  has_many :devices, dependent: :destroy
end

class Account
  belongs_to :user
end
```

`Device` から引くよりも `Account` から `pluck` したほうが良いです。

```ruby
# 前提条件
devices = Device.where(id: 1..10000)

# eager_load して map するよりも
devices.eager_load(user: :account).map { |d| d.user.account.code }
# merge で条件指定して pluck したほうが速い
Account.joins(user: :devices).merge(devices).pluck(:code)
```

レコード数にもよりますがだいたい10倍ほど速かったです。


## マルチスレッド内ではコネクションプールは共有する
これはパフォーマンスチューニングというより注意ですが、マルチスレッド等で DB 処理を行う場合はスレッド数分だけコネクションを貼ろうとして、設定上限数をオーバーする可能性があるので `ActiveRecord::Base.connection_pool.with_connection` でコネクションプールの共有を行う必要があります。

```ruby
# parallel gem を使った例
Parallel.each(arrays, in_threads: 8) do |array|
  ActiveRecord::Base.connection_pool.with_connection do
    # コネクションプールが共有される
  end
end
```

その他随時追記予定です。
【python】ローソンお試し券ページをスクレイピングしてみた

## ＜ はじめに ＞
ローソンお試し券さま、いつもお世話になっております(_ _)
（販売価格の半額ほどのポイント数で交換できるやつ）



#### さて、困りごと・・
個人的に、ローソンホームページのお試し引換券一覧なんか見づらいのです。
日付、ポイントが小さいとか
![Screenshot_20240601-133947.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693459/1eaf1c9a-d64d-95db-e96b-3896902fd907.png)

こんな日付、商品、ポイントがパッと見わかるやつが欲しい（PDFではある）
![スクリーンショット 2024-06-01 180043.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693459/77e16849-cdb8-cdbb-cde5-fb01ee7222ba.png)


#### やりたいこと・・
スマホ画面でも、何日に何の商品が何ポイントで交換できるのか、パッと見わかる一覧で見たいです✨

#### 手段・・
せっかくなのでpythonのスクレイピングにより、なんかいい感じに表示させたいです。

## ＜ やってみた ＞
htmlソースを見ると、sec-02のulタグのliタグ単位で商品が並んでいるのがわかる
その中に各情報があるような感じ
![スクリーンショット 2024-06-02 145251.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693459/c8d9cdb5-db76-317a-a8a4-b5c092ce5136.png)

うまく指定して抜くと
![スクリーンショット 2024-06-02 145129_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693459/aec27fe2-2564-c68c-2688-5920745dc8c6.png)
：
：
![スクリーンショット 2024-06-02 145206_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693459/41c4cbb1-7345-d810-e687-01def7499af2.png)
最後まで取得できた！

``` py:取得までのソース（レイアウトがリニューアルされると変わるので注意）
import requests
from bs4 import BeautifulSoup

url='https://www.lawson.co.jp'
list_url1 = "https://www.lawson.co.jp/ponta/tsukau/otameshi/"
list_url2 = ""

#接続先取得
r= requests.get(list_url1)
soup = BeautifulSoup(r.content, "html.parser")

#指定URLに飛ばされるので、それを取得
list_url2 = url + soup.html.meta["content"].replace('0; URL=','')

#指定URL先からhtml取得
r= requests.get(list_url2)
bsoup = BeautifulSoup(r.content, "html.parser")

# HTMLから商品情報の範囲を取得
products = bsoup.select("#sec-02 > ul.col-2.heightLineParent > li")
for item in products:
    print(item.select_one("div.rightBlock > p.ttl").text) # 商品名
    print(item.select_one("div.rightBlock > p.text01").text) # 値段
    print(item.select_one("div.leftBlock > img").attrs["src"]) # 画像URL
    print(item.select_one("div.rightBlock > dl > dd:nth-child(2)").text) # 日付
    print(item.select_one("div.rightBlock > dl > dd:nth-child(4)").text) # ポイント
    print(item.select_one("div.rightBlock > dl > dd:nth-child(6)").text) # 先着数

quit()
```
## ＜出来上がり＞

なんだかんだと、HTML/CSSを使って取得した情報を、とりあえず、日付、商品画像とポイント、お酒、Loppi限定かを表示させるとこまで出来た！
![スクリーンショット 2024-06-02 152729.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693459/6fd733bd-481a-12ed-aa23-372a2627ea91.png)

（ついでに、クリックすると詳細が出るようにした）
![スクリーンショット 2024-06-02 153812.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693459/108526ba-7415-3450-c05c-0afcc3b0f1ca.png)

なんかカラフルだけど、とりあえずこれでイイかと。
細かいところが気になるけど。。

スマホでみると
![Screenshot_20240602-155459.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693459/6fe4bae8-f9ef-5746-0b7e-88a1e558609b.png)
![Screenshot_20240602-155505.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693459/a45adc6d-a152-ed32-4b48-f4ea897cffb8.png)

## ＜おわりに＞
スクレイピング自体、パターンさえ見つければそんなに難しくない👍
が、表示レイアウトが難しい🤔結局タイル表示が一番見やすい気がする。
SoftwareDesign 2024/6月号 輪読会メモ (2024/6/3)

# 第1特集
SQLチューニングする前に知っておきたい
実行計画＆インデックスのしくみ

P.17

    …… 奥野 幹也
    第1章：RDBMSとSQLの基礎概念
    リレーショナルモデル理論から理解するSQLの性質

P.18

    第2章：SQL実行のしくみと実行計画
    効率的にクエリを実行できているか見極める

P.27

    第3章：インデックスの機能とアルゴリズム
    検索処理を高速化させるしくみを理解する

P.35

# 第2特集
［実証］Bun
次世代JavaScriptランタイムの実体に迫る

P.43
試しにNode-REDで動かしてみました。

https://qiita.com/kitazaki/items/82fb1e5a4a953c6b9966

    第1章：Bunの全体像をつかむ
    誕生の背景，特徴，機能を押さえよう
    …… 鈴木 正樹

P.44
Bun　→Bundleの由来、JavaScriptCoreエンジン、Bun Shell (Shell Scriptを書ける)

    第2章：Bunを使ってみよう
    追加設定不要！ 標準機能で始める快適開発
    …… 近藤 正裕

P.52
p.56 Node.jsとの対応表、シングルファイル実行形式作成

    第3章：BunとNode.jsの徹底比較
    どちらがどれくらい速いのか，性能の違いを見よう
    …… 鈴木 正樹

P.62

# 特別企画

    DI―依存性の注入―はなぜやるの？
    「コンポーネント間の結合度を下げる」とは
    ……成瀬 允宣

P.72

# 連載

    ITエンジニア必須の最新用語解説
    【186】WinterJS……杉山 貴章

ED.1
高速なJavaSCriptランタイムWinterJS、第2特集Bunにも触れている

    万能IT技術研究所
    【25】人類の歩みを眺めるために，過去の世界に行ってみる――昭和初期から最終氷期まで，時代の水辺にダイブする……万能IT技術研究所

P.1
古地図、海進/海退
巨椋池　→6/2(月) 7:45 NHKのさわやか自然百景で取り上げられていた。

    ドメイン解体新書
    【5】DNSへの攻撃とセキュリティ……谷口 元紀

P.6
新しい攻撃手法の紹介はなかったが、レガシーな攻撃への防御の難しさが継続していることに共感した。

    ハピネスチームビルディング
    【27】会議で主体的に発言してもらえるようにする……小島 優介

P.12
発言しない人　→ 日頃のコミュケーションの問題

    エンジニアのためのやる気UPエクササイズ
    【22】継続率と生産性を高めるエンジニア向けグループエクササイズ……えくろプロテイン

P.14
平日21時Xスペースでグループエクササイズ

    【新連載】成功するPSIRTの極意
    【1】PSIRTってどんなもの？／PSIRTの始め方……杉浦 英史

P.82
PSIRT　→プロダクトのセキュリティー対応、freeeでは女性が2割以上在籍

    実践データベースリファクタリング
    【7】意図を忘れ去られたテーブル……曽根 壮大

P.90
テーブルの意図の忘却、割れ窓効果、renameと一時利用不可

    Google Cloud流クラウドネイティブなシステムデザインパターン
    【5】CI/CDシステム……北野 敦資，監修：阿部 正平

P.96

    あなたの知らないChromeの世界
    【5】Progressive Web Appのしくみ……小河 亮

P.103
Service Worker、Web Worker(5月号)、ふぐ🐡=ネイティブ機能は美味しいけど毒がある

    レガシーシステム攻略のプロセス
    【2】ZOZOTOWNリプレイスにおけるIaCやCI/CD関連の取り組み……籏野 光輝，堀口 真

P.117

    Databricksで勝つデータ活用
    【3】機械学習の実運用をサポートする機能……志賀 優毅

P.118

    ぼくらの「開発者体験」改善クエスト
    【6】アーキテクチャ特性からみるWeb開発基盤の改善……飯田 有佳子

P.126

    Cloudflare Workersへの招待
    【7】RustとCloudflare Workers……井手 優太

P.134
Rustはコンパイラが厳しい　→面倒見が良い

    実践LLMアプリケーション開発
    【9】LangGraphで開発するリサーチエージェント……西見 公宏

P.142
LangGraph　→LangChainを拡張したマルチエージェントシステム開発ライブラリ

    AWS活用ジャーニー
    【21】Amazon CodeWhisperer……杉金 晋

P.152
コードやコマンドをAIで生成するサービス

    魅惑の自作シェルの世界
    【19】whileコマンドの実装……上田 隆一

P.158

    あなたのスキルは社会に役立つ～エンジニアだからできる社会貢献～
    【150】能登半島地震におけるIT DARTの支援活動～IT技術者ができる災害支援～……大菊 健太

P.166
IT DART　→情報支援レスキュー隊、平時の準備が災害時の力に

    SD NEWS & PRODUCTS

P.170
PSTI法　→IoT製品のサイバーセキュリティ対策の向上を目的とした法律
VDP　→脆弱性開示プログラム
EUサイバーレジリエンス法準拠

obniz Now (後付け遠隔保守)

https://iot.obniz.com/solutions/now
2024年版[Docker] `docker`と`docker compose`コマンドを整理_個人用途

## 参考
## 予備知識
## `docker` コマンド
## `docker compose` コマンド

| コマンド | オプション | 説明 |
|:-:|:-:|:-:|
|  `docker compose build` |  --no-cache |  ソースコードや設定ファイルの変更を反映します。Dockerfile自体の変更を反映します。アプリケーションに新しく追加したパッケージやライブラリを反映します。既存のイメージやキャッシュが古い場合、最新の状態に更新されたクリーンなイメージを構築できます。 |
|  `docker compose up -d` |   |   |
|  `docker compose down ` |  --rmi all, --volumes |   |
|  `docker compose exec [サービス名] [サービス内で実行するコマンド]` | 
  |   |
|  `` |   |   |
初心者にとってのフレームワーク学習(Laravel)

# 自分の状況
　初めてのフレームワーク学習ということでLaravelに触れてみた。これまでにフレームワークの学習経験はなく、MVCモデルとは、といった部分から開始。簡単な記事投稿サイトを作りながら学んだ。
# 雑感と注意点
　`htmlspecialchars()`というタイプしづらい文字列を書かなくてよいとか、`@csrf`とするだけで対策してくれるとか、その便利さを感じることができた反面、その便利さが初心者にとって学習上の障壁になる面もあると感じた。
　具体的にはImplicit Binding(暗黙の結合)の仕組みを学ぶ際に直面した問題である。Implicit Bindingは「ルーティングのパラメータ名とコントローラー内の関数の引数を同じにして型を指定すると、idが対応するインスタンスを渡してくれる」というものである(と理解している)。この挙動についても即座に理解できるようなシンプルなものではないが、その挙動を理解した後に、「なぜそうなっているのか」や「どういった処理がされているのか」といった疑問を持ってしまうと大変である。おそらく「そうなっているから」と答えるしかないと思われるが、詳しい人からそう言われなければ初心者はずっと頭を悩ませてしまうことになりかねない。
　プログラミング学習全般に言えることだが、フレームワーク学習においては特に疑問を抱えたまま進める姿勢が重要なのかもしれない。
# 余談
　ログイン機能を実装するためにLaravel Breezeが必要になり、インストールしようとしたが、
`composer require laravel/breeze --dev`
の後に
`php artisan breeze:install`
を入力しても<font color="yellow">`WARN`</font>や<font color="red">`ERROR`</font>となって全然進まずに苦労することがあった。
　いろいろな方法を試したが、結局はnode.jsのバージョンが古かっただけであった。特に初心者は、基本的なことに気を配るのを忘れてはならないということだろう。
UbuntuでGRUBのテーマをカスタマイズする方法

UbuntuのGRUBのテーマを自由にカスタマイズする方法を解説します

## 環境
バージョン - Ubuntu24.04LTS
カーネル - 6.8.0-31-generic

## 1. GRUBのテーマをダウンロード
まずは自分の好きなGRUBのテーマをダウンロードする必要があります
[gnome-lock.org](https://www.gnome-look.org/browse?cat=109&page=3&ord=latest)から自分の好きなテーマを選び、ダウンロードしてください

## 2. GRUBのテーマを専用フォルダに移動
ターミナルを開き、以下のコマンドを実行しましょう
```
sudo nautilus
```
するとrootユーザーのNautilusが開きます
テーマをダウンロードしたディレクトリに移動して、テーマを解凍・コピーしてください
そしたら、/boot/grub/にthemesという名前のフォルダを作成して、
そこに、コピーしたテーマのフォルダをペーストしてください
（以下画像のようになったらOK）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691296/f07ed751-13b6-509d-fbc8-4afd0dc0d7ce.png)

そして、今回はコマンドを揃えるために、
テーマフォルダの名前を`grubtheme`に変更してください

そしたら、Nautilusを閉じて、ターミナルを開いて、以下のコマンドを実行してください
```
sudo nano /etc/default/grub
```

そしたら、以下のような行を11行目くらいに追加してください
`GRUB_THEME=/boot/grub/themes/grubtheme/theme.txt`

そして、Ctrl+Xで保存し閉じます

**（以下重要）**
**そして、ターミナルで以下のコマンドを実行してください**
```
sudo update-grub
```
**(このコマンドを実行しないと変更が反映されません)**

そして、再起動し、
BIOSテキストが消えた直後からESCキーを連打して、
<grub>というターミナルのようなものがでてくるので、
normal と打ってEnter＆直後にESCキーをすることで、
カスタマイズされたGRUBメニューが表示されます

## テーマを元に戻したい場合
GRUBテーマを元に戻す場合は、
```
sudo nano /etc/default/grub
```
を実行して、先程追加したGRUB_THEMEの行を消して、
```
sudo update-grub
```
で元に戻ります


## おまけ - GRUBを毎回表示させる方法
GRUBを毎回キーを押したりせずとも起動できるようにするには、
```
sudo nano /etc/default/grub
```
を実行して、
GRUB_TIMEOUT=0 を GRUB_TIMEOUT=10 に変えて、
GRUB_TIMEOUT_STYLE=hidden を GRUB_TIMEOUT_STYLE=menu に変えれば、
毎回何もせずともGRUBメニューが表示されるようになります
初転職も5か月で退職…未経験ITエンジニア転職の失敗談と注意点

「未経験でITエンジニアを目指そうと思っているけど、転職に失敗するのではないか」と不安に思っていませんか？実は未経験からのIT転職には、多くの落とし穴があります。なぜならIT業界への理解不足や準備不足が原因で、転職活動自体に失敗したり、転職後のミスマッチで離職してしまうケースが少なくないからです。

**私自身も初めてエンジニア転職した会社を5か月で退職**してしまい、未経験からのIT転職の難しさを身をもって体験してきました。この記事では私が未経験からのIT転職で陥った失敗談と、それらを回避するための対策をご紹介します。この記事を読むと未経験からIT業界に転職する際の落とし穴を事前に知ることができ、失敗を最小限に抑えられます。

## 私が未経験エンジニア転職した会社を短期退職した理由

![Why-I-left-the-company-where-I-started-my-new-job-as-inexperienced-engineer-for-short-period-of -time.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784196/25bfb1d0-c8f1-b474-9fe4-11be29459158.jpeg)


まず短期で退職を至った理由について、お話ししたいと思います。退職の理由としては、以下の2点です。

- **深夜に及ぶ長時間労働**
月80～100時間くらいの残業で、常に不眠と頭痛に襲われる
- **スキルの伸びない仕事内容**
マイナーなツールの専門家となるように上司に指示をされ、他社で通用しないような人材となる恐れを感じる

[>> 退職のスムーズな流れについて完全解説！](https://taishi-official.com/2024/04/24/2190/)

## 未経験ITエンジニア転職での注意点

![What-to-look-out-for-when-changing-careers-as-inexperienced-engineer.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784196/04adfbd1-0747-c31a-dbe4-ea583895cc6f.jpeg)


未経験からエンジニア転職を成功させて、短期離職をしてしまいました。この経験を通して、これから同じように未経験エンジニア転職を目指している方にアドバイスをしたいです。以下の3点ついて、注意してもらえたらな思います。

- **会社規模が小さすぎない**
- **研修を手厚く行ってくれる**
- **仕事内容についてしっかり確認する**

[>> 各注意点の詳細説明はコチラ！](https://taishi-official.com/2021/01/19/678/#toc4)


## まとめ
ここまでいろいろと注意点について述べてきましたが、どんなに万全に調べたとしても入社してみるとブラック企業だったということもありえます。そんな時は、我慢せずさっさと退職してしまいましょう。前職で私の数か月前に入社した先輩は、うつ病になって退職してしまいました。<strong>うつ病になるところまで我慢してしまうと、社会に復帰するまでにかなりの時間を要してしまいます。

[>> エンジニアが感じるメンタル不調の原因と解決策](https://taishi-official.com/2024/01/21/1500/)

上記のようにさっさと辞めてしまって、転職先があるのか不安な方もいらっしゃると思います。しかし、今のIT業界は人手不足の状態です。私も結局半年弱の微経験の状態でしたが、コロナ禍ではありましたが、数社から選べるくらいには求人がありました。過剰に心配する必要はないです。

[>> 微経験でも相談可能！エンジニアにおすすめの転職エージェントまとめ](https://taishi-official.com/2023/12/08/1305/)

エンジニアになれば、人生の自由度が格段に高まります。多少ミスがあったとしても気持ちを切り替えて、エンジニアを目指していきましょう❗

### おまけ

https://qiita.com/taishi_will_be/items/70a8ce8938944286b487

https://taishi-official.com/changing-engineer/

<strong>＼Follow me／</strong>

- X（旧Twitter）：https://x.com/taishi_it_blog
- Instagram：https://www.instagram.com/taishi_will_be/
- YouTube：https://www.youtube.com/@Engineer_ILLBE
- TikTok：https://www.tiktok.com/@taishi_will_be
- note：https://note.com/taishi_wii_be/

<br>

最後にいいねお願いします:thumbsup:
Azure DevOpsのプライベートリポジトリから特定のディレクトリだけをZIPでダウンロードする

# 概要

Azure DevOpsで管理しているソースコードから一部ファイル群だけほしい状況があり、試しにbashで取得できないか試行しました。一部ファイル群だけほしいのは、プログラム中で取得する必要があるが、リポジトリが巨大で全部をcloneする時間が惜しかったからです。

# コード

```bash
#!/bin/bash

organization="organization"
project="project"
repository="repository"
directory="directory"
pat="personal access token"
localPath="path"

# 特定のディレクトリだけをダウンロード
url="https://dev.azure.com/${organization}/${project}/_apis/git/repositories/${repository}/items/items?path=${directory}&versionDescriptor%5BversionOptions%5D=0&versionDescriptor%5BversionType%5D=0&versionDescriptor%5Bversion%5D=master&resolveLfs=true&\$format=zip&api-version=7.2-preview&download=true"

curl -u ":${pat}" -L "${url}" -o "${localPath}"
```

注意点
- personal access tokenはbearerではなくbasic
- `versionDescriptor[BversionOptions]=0`などのカッコはちゃんとBase64 URLエンコードを施す
- `$`もエスケープする

# 雑感

URLの形式がわからず、GitHub Copilotに生成してもらいましたが、ほぼ正しく生成してくれました。
とても便利。
Ubuntuでvimを使おう！

Ubuntuでvimをインストールして使うところまでを説明していきます（）

## 環境
バージョン - Ubuntu24.04LTS
カーネル - 6.8.0-31-generic

## vimのインストール・使い方
まずはvimの方から解説していきます
Ubuntuには標準でインストールされていないので、
ターミナルで以下のコマンドを実行してください
```
sudo apt-get install vim -y > /dev/null 2>&1 ; clear
```
少し待ったら、入力待ち（$）になるので、
試しに、`vi ~/test`と入力してみましょう
すると、ホームディレクトリにtestというテキストファイルができます

ここでスクリプトを書いたり、メモを書いたりすることができます

## 例（できること）
### 1. シェルスクリプト（Hello World!と出力する）
```
#!/bin/sh

echo "Hello World!"
```

### 2. メモスクリプト（試してみてください）
```
#!/bin/bash

TERM=vt100 whiptail --title "たかしへ" --infobox "ご飯は電子レンジの中にあります。" 7 45
```
AWS CLIを使い始めるまで

[link-1]: https://docs.aws.amazon.com/ja_jp/singlesignon/latest/userguide/howtosessionduration.html "セッション期間の設定"
[link-2]: https://docs.aws.amazon.com/cli/latest/userguide/sso-configure-profile-token.html "トークンによる認証方法"
[link-3]: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html "AWS設定コマンド"
[link-4]: https://docs.aws.amazon.com/general/latest/gr/rande.html "リージョン一覧"

## はじめに
AWS CLIを認証する方法は複数あり、結局どのようにすれば良いのか迷ってしまいました。ここでは、公式が推奨している方法をまとめます。

## AWS CLIのインストール
Linux、MacOS、Windowsでインストール方法が異なります。公式ドキュメントの通りにインストールするのが確実です。

https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html

## IAM Identity Centerを使ったログイン
IAM Identity Centerは組織がユーザのアクセスを一元管理するサービスです。
ポータルサイトのURL(`https://xxx.awsapps.com/start/`のようなURL)にログインします。
アカウントが発行されていないなら、管理者に依頼するか、以下のドキュメントにしたがってIAM Identity Centerを導入する必要があります。

https://docs.aws.amazon.com/singlesignon/latest/userguide/getting-started.html

## 認証方法
SSOトークンを使った認証が推奨されています。
SSOとはシングルサインオン(Single Sign On)のことで、ユーザ認証を一度だけ行うことで複数のサービスを利用できる機能のことです。

### IAM Identity Centerの情報取得
認証に必要な情報を事前に取得しておきます。
まず、AWS access portalにログインして、`Access keys`のリンクをクリックしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2039603/07b08496-8415-b001-575d-021bf390d3ff.png)

クリックしたら以下のような画面になるので、自分が使っているOSを選んで、`SSO start URL`と`SSO Region`をコピーします。
認証のときに、この2つを使います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2039603/59b76b3b-36b2-f4f0-8d1d-64997a96d32d.png)

### コマンドによる認証
ポータルサイトにログインしたら、ローカルのターミナル等で次のコマンドを入力します。
```
$ aws configure sso
```
設定が必要になるので、以下の項目のように入力していきます。
|項目|入力|
|---|---|
|SSO session name (Recommended)|自由に設定|
|SSO start URL|前節でコピーしたURL|
|SSO region|前節でコピーしたURL|
|SSO registration scopes|`sso:account:access`と入力|

入力するとブラウザが起動して認証を求められます。
認証が終わると再びターミナルに戻り、残りの項目を入力していきます。
|項目|入力|
|---|---|
|There are n AWS accounts available to you.|使用するアカウントの選択|
|There are n roles available to you.|使用するロールを選択|
|CLI default client Region|[リージョン一覧][link-4]から選んで入力(例えば東京は`ap-northeast-1`)|
|CLI default output format|`json` `yaml` `yaml-stream` `text` `table`から選択|
|CLI profile name|設定の名前を自由に入力|

以上で設定は完了となります。正しく設定できたかどうかは、以下のコマンドを入力すると分かります。
```
$ aws s3 ls --profile [CLI profile name]
```

## セッションが切れたら
AWSではセッションの期間はデフォルトで1時間に設定されています。
> 新しいアクセス権限セットを作成すると、デフォルトでセッションの継続時間が 1 時間 (秒単位) に設定されます。セッション時間は、最短で 1 時間、最長で 12 時間まで設定できます。

セッションの期間を変更する場合は、[セッション期間の設定][link-1]にしたがいましょう。

セッション期間が切れると以下のようなメッセージが出力されます。
```
$ aws s3 ls --profile [CLI profile name]
> Error when retrieving token from sso: Token has expired and refresh failed
```
このときには以下のコマンドで再認証できます。
```
$ aws sso login --profile [CLI profile name]
```
## プロファイル名を忘れてしまったとき
ログインのときにはプロファイル名が必要ですが、忘れてしまった場合でも、以下のコマンドで設定したプロファイルの一覧が確認できます。
```
$ aws configure list-profiles
```

## 設定したプロファイルを削除するとき
設定情報は`~/.aws/config`ファイルに書かれているので、テキストエディタで削除できます。

## 参考
[トークンによる認証方法][link-2]
[AWS 設定コマンド][link-3]
Android データクラスをJsonに変換する方法


データクラスをJsonに変換する方法

`serialization`を使用するので、導入する必要があります。
導入しているプロジェクトが殆どだと思うので割愛します。


```.kt
//必要なインポート
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json



val user = User(member = false, userId = 0, userName = "user")
val userJson = Json.encodeToString(user)

```
`Json.encodeToString`の引数の値へJsonにしたいデータクラスを渡してあげるだけでできます。

`userJson`の表示結果

`{"member":false,"userId":0,"userName":"user"}`
絵文字をPOSTした際の数値参照形式を絵文字に戻す方法

## 1.背景
JSPの実装にて入力フォームに入力した絵文字を次ページの確認画面で表示する際に
数値変換形式に変換されてしまうため、絵文字で表示をするためにJavaScrpitにて処理を実装しました。

例：入力内容→😃
   数値変換形式→ ＆#128515;
 　上記を表示時に、😃へ戻す
  
## 2.　入力画面、受け取り画面について

以下は入力テキストとPOSTするボタンのみ配置の画面
```jsp:inputForm.jsp
<%@ page contentType="text/html; charset=Windows-31J" %>
<html>
<head>
    <title>送信データを扱うJSP</title>
</head>
<body onload="document.getElementById('hiddenButton').click();">
<h2>POST送信フォーム</h2>
<form action="jspReceipt.jsp" method="post">
    入力：
    <input type="text" name="htmlEntity" id="htmlEntity">
    <input type="submit" value="送信">
</form>
</body>
</html>
```

以下は入力された内容を表示する画面
```jsp:jspReceipt.jsp
<%@ page contentType="text/html; charset=Windows-31J" %>
<%
    // POSTされた絵文字
    String htmlEntity = request.getParameter("htmlEntity");
%>
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="emojiHenkan.js"></script>
<script type="text/javascript">
// ページがロードされた後に処理を行う
window.addEventListener('load', function() {
    // 初期表示時に関数を呼び出す
    replaceNumericReferenceWithEmoji('<%= htmlEntity %>');
});
</script>
    <meta charset="UTF-8">
    <title>入力内容の表示</title>
</head>
<body>
<div id="outputDiv"></div>
<br/>
</body>
</html>
```

## 3.　変換処理を行うJavaScript
以下、数値変換形式と絵文字をセットの配列を作成して、入力された内容に対して最終的に置換を行う。

```javascript:emojiHenkan.js
// 数値参照形式から絵文字に変換する非同期関数
async function convertNumericReferenceToEmoji(numericReference) {
    return new Promise((resolve, reject) => {
        // 数値形式部分を取り出す
        var numericParts = numericReference.match(/&amp;#(\d+);/g);
        if (!numericParts) return resolve([]);

        var emojis = numericParts.map(function(numericPart) {
            // 数字を10進数として解釈し、絵文字に変換
            var codePoint = parseInt(numericPart.replace(/[&amp;#;]/g, ''), 10);
            return String.fromCodePoint(codePoint);
        });

        // numericPartsとemojisをセットにした配列を作成
        var pairedArray = numericParts.map(function(numericPart, index) {
            return [numericPart, emojis[index]];
        });

        resolve(pairedArray);
    });
}

// 数値参照形式を絵文字に置き換える関数
async function replaceNumericReferenceWithEmoji(htmlEntity) {
    try {
        var pairedArray = await convertNumericReferenceToEmoji(htmlEntity);
        
        // 数値参照形式を絵文字に置き換える
        var replacedText = htmlEntity;
        pairedArray.forEach(function(pair) {
            replacedText = replacedText.replace(pair[0], pair[1]);
        });
        
        // 置換されたテキストを画面に表示
        document.getElementById("outputDiv").innerHTML = replacedText;
    } catch (error) {
        console.error('Error:', error);
    }
}

```

## ４. 終わりに
今回は入力画面も表示画面も、仕様上の誤動作のリスクに備えて、UTF-8には変換できず、Windows-31Jのままで使用することがあったため、JavaScriptで無理やり変換しております。
JavaでUTF-8に変換して表示させる方法では文字化けが解消されず、StringEscapeUtils.unescapeHtml4では、SQLインデクションを解消できず、やめました。

上記は割と自作になるのでご使用の際はご注意を。
[Virtual Architectute] ハイパーバイザ型、ホストOS型、コンテナ型とは

# イメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/b14fda22-3701-8e4c-aefe-dcb04ffd4f2d.png)

# 目次
- [ハイパーバイザ型](#ハイパーバイザ型)
- [ホストOS型](#ホストOS型)
- [コンテナ型](#コンテナ型)
 
# ハイパーバイザ型
ハイパーバイザ型（ベアメタル型）は、物理サーバ上で直接動作する仮想化レイヤーです。ホストOSを必要とせず、直接ハードウェア上で仮想マシンを管理します。

### 活用例
- **データセンターやクラウド環境:** 高いパフォーマンスとリソース管理が求められる環境で使用されます。
- **サーバー統合:** 複数の物理サーバーを1つのハイパーバイザ上に統合し、リソース効率を向上させる。

### 主要なソフトウェア
- **VMware ESXi:** 高機能な商用ハイパーバイザで、多くのエンタープライズ環境で使用されている。
- **Microsoft Hyper-V:** Microsoftによるハイパーバイザで、Windows Server環境でよく使用される。
- **Xen:** オープンソースのハイパーバイザで、Amazon Web Services (AWS) のベース技術として使用されている。

# ホストOS型
ホストOS型（ホストベース型）は、既存のホストOS上で動作する仮想化レイヤーです。ホストOSの上に仮想化ソフトウェアをインストールし、その上で仮想マシンを実行します。

### 活用例
- **開発環境:** 開発者がローカルマシンで異なるOSを実行し、アプリケーションの互換性をテストする。
- **テスト環境:** 新しいソフトウェアのリリース前に、異なるOS上での動作を確認するためのテスト環境として使用する。

### 主要なソフトウェア
- **VMware Workstation:** 主にデスクトップ環境で使用される仮想化ソフトウェア。
- **Oracle VirtualBox:** オープンソースの仮想化ソフトウェアで、広範なOSサポートを提供する。
- **Parallels Desktop:** macOS上でWindowsやLinuxを実行するための仮想化ソフトウェア。

# コンテナ型
コンテナ型は、ホストOSのカーネルを共有しつつ、隔離されたユーザー空間を提供する仮想化技術です。コンテナは軽量で起動が速く、効率的にリソースを使用します。

### 活用例
- **マイクロサービスアーキテクチャ:** 各サービスを独立したコンテナとしてデプロイし、スケーラビリティと管理の容易さを提供する。
- **継続的インテグレーション/継続的デリバリー（CI/CD）:** アプリケーションのビルド、テスト、デプロイを迅速に行うために使用される。

### 主要なソフトウェア
- **Docker:** コンテナ技術のデファクトスタンダードで、開発者や運用チームに広く使用されている。
- **Kubernetes:** コンテナのオーケストレーションを行うためのプラットフォームで、大規模なコンテナ環境の管理に使用される。
- **Podman:** Dockerに似たコンテナエンジンで、rootlessコンテナ実行をサポートしている。
- **LXC（Linux Containers）**: Linuxカーネルのcgroupsや名前空間機能を利用して、1つのホスト上で複数の隔離されたLinuxシステム（コンテナ）を実行するOSレベルの仮想化技術。
- **OpenVZ**: Linuxカーネルをベースにしたオープンソースのコンテナ型仮想化ソリューションで、1つの物理サーバー上に複数の独立したLinuxインスタンス（コンテナ）を効率的に作成することが可能。


# 参考リンク
- [仮想化技術について解説　ホスト・ハイパーバイザー・コンテナの違いとは？](https://www.itmanage.co.jp/column/virtualization-server-integration/)
- [Dockerが注目されている理由を探る](https://thinkit.co.jp/story/2014/12/02/5456)
- [令和4秋12_コンテナ型](https://www.ap-siken.com/kakomon/04_aki/q12.html)
- [令和3秋14_コンテナ型](https://www.ap-siken.com/kakomon/03_aki/q14.html)

# Ping-t
- [3380_コンテナ型](https://mondai.ping-t.com/question_subjects/31/question_sessions/31538033/progressing_questions/483250165)
- [3690_ハイパーバイザ型](https://mondai.ping-t.com/question_subjects/31/question_sessions/32527688/progressing_questions/498427171)
- [3691_コンテナ型](https://mondai.ping-t.com/question_subjects/31/question_sessions/31538033/progressing_questions/483250160)
- [3695_クラウド全般](https://mondai.ping-t.com/question_subjects/31/question_sessions/31593536/progressing_questions/484113869)
- [3696_ホストOS型](https://mondai.ping-t.com/question_subjects/31/question_sessions/32581786/progressing_questions/499228203?result=true)
- [3714_IaaS](https://mondai.ping-t.com/question_subjects/31/question_sessions/32725104/progressing_questions/501357400)
Node.js+expressで一部ファイルのみあえてキャッシュさせない

# やりたかったこと
ブラウザのキャッシュは便利ですが、要件によっては邪魔になってしまうこともあります。
最新のソースファイルが取れないと困る時もあるし、それでバグが起きては元も子もないですからね…
そこで、あえて今回はキャッシュをさせないようにする設定をしてみます。

# 実装してみる
今回の環境はタイトル通りNode.js+expressなので、HTTPヘッダをexpressのルーティングで制御すれば出来ます。
自力で設定してもよいのですが、npmにぴったりのモジュールである[nocache](https://www.npmjs.com/package/nocache)があるのでそれを使っちゃいましょう。
使い方はこんな感じ。

```javascript
import express from 'express';
import nocache from 'nocache';

const app = express();

// キャッシュ無効化
app.use(nocache());
```

以上です。迷うことが無いくらいにシンプル！
後は以降の処理でレスポンスを記述してしまえば、それらは全てキャッシュされないようになります。

まあ[nocache](https://www.npmjs.com/package/nocache)自体がやっていることは非常に単純で、HTTPヘッダに`Cache-Control`や`Expires`、`Surrogate-Control`を設定しているだけです。
とはいえ、じゃあキャッシュを無効化するために何を設定すべきか？と言われるといろいろと情報が新旧入り乱れて正確に考えるのは難しいので、ありがたいですね。（もちろん意味を調べて使うべきではありますが）

しかし、お分かりの通りこれだと**全てのキャッシュが無効化されます。**
目的は一部のみキャッシュさせないようにするなので、その形で実装してみましょう。

# 本題の実装
さて、先ほどの例だと全てのルーティングを通してしまったので、一部のみに制限すればよいのです。
ということでやってみました。

```javascript
import express from 'express';
import nocache from 'nocache';

const app = express();

// キャッシュ無効化
app.use((req, res, next) => {
  // img,fontsディレクトリのファイルのみキャッシュさせる
  if (/^\/static\/[img|fonts]/.test(req.path) === true) {
    next();
  }
  else {
    nocache()(req, res, next);
  } 
});
```

今回はリクエストのパスを見て、`static/img`or`static/fonts`ディレクトリは`nocache`の処理を通さないようにしました。
まあ特段することも無くそうだねって感じですが、微妙に`nocache()(req, res, next);`辺りの記述が変な感じになります。nocacheが返した関数を即実行しているだけなんだけども…
とりあえずこんな感じの実装をすれば、このファイルはキャッシュされると困るけどこれはキャッシュしてほしい！という我儘なケースにも対応できますね。

# 終わりに
今回の件は振り返ると特に難しいところでもなかったのですが、個人的にキャッシュ無効化した影響でここのパフォーマンス悪いな…でもキャッシュ無効化を外すのもな…と悩んでいたのを解決できたので備忘録も兼ねての記事でした。
キャッシュをどうするかはパフォーマンスひいてはユーザビリティに直結するので、何度も調整しながら進めていくことにします。
ABC356(Atcoder Beginner Contest)のA~D(A,B,C,D)問題をPythonで解説(復習)

# ABC356(Atcoder Beginner Contest)のA~D(A,B,C,D)問題をPythonで解説(復習)

# A問題

- ここ2週間それなりに忙しいので，省略します．ごめんなさい．
- コメントを見て下さい．
```A.py
"""
<方針>
- ここ2週間それなりに忙しいので，省略します．ごめんなさい．
- コメントを見て下さい．
"""

# 標準入力を受け取る．
N, L, R = map(int, input().split())

# 1〜Nまでの数字のリストを作成する．
ans = list(range(1, N+1))

# L〜Rまでを反転する．0-indexedに注意する．
ans[L-1:R] = list(reversed(ans[L-1:R]))

# 空白くぎりでリストを出力する．
print(*ans)
```

# B問題

- ここ2週間それなりに忙しいので，省略します．ごめんなさい．
- コメントを見て下さい．
```B.py
"""
<方針>
- ここ2週間それなりに忙しいので，省略します．ごめんなさい．
- コメントを見て下さい．
"""
N, M = map(int, input().split())

# 取らなきゃいけない栄養素
A = list(map(int, input().split()))

# 実際に取った栄養素
B = [0]*M

# 食べ物を食べていく．
for i in range(N):
  # i品目を食べる．
  X = list(map(int, input().split()))
  
  # どんな栄養素が取れたかを記録する．
  for j in range(M):
    # j番目の栄養素を記録する．
    B[j] += X[j]

# 全ての栄養素が足りているかを見る．
for i in range(M):
  # 足りない栄養素があった時，
  if(A[i]>B[i]):
    # Noを出力して，プログラムを終了する．
    print("No")
    exit()

# 全ての栄養素が足りている時，Yesを出力する．
print("Yes")
```

# C問題

- ここ2週間それなりに忙しいので，省略します．ごめんなさい．
- コメントを見て下さい．
```C.py
"""
<方針>
- ここ2週間それなりに忙しいので，省略します．ごめんなさい．
- コメントを見て下さい．
"""

N, M, K = map(int, input().split())

# 試した鍵の種類
AA = []
# 鍵が空いたかどうか
R = []
for i in range(M):
  CAR = list(map(str, input().split()))
  AA.append(list(map(int, CAR[1:-1])))
  R.append(True if CAR[-1]=="o" else False)

ans = 0
# 鍵のパターンを全て試す．
for i in range(1<<N):
  # 矛盾するとFalseが入る．
  ok = True
  # 試した鍵のパターンを全て確かめる．
  for j in range(M):
    # 正しい鍵の数
    col = 0
    for a in AA[j]:
      # 鍵が正しい時，
      if(i&(1<<(a-1))):
        col += 1
    
    # 矛盾したとき，
    if((R[j]) != (col>=K)):
      ok = False
  
  # 矛盾してない時，
  if(ok):
    # 鍵のパターンは合っているものとする．
    ans += 1

# 出力
print(ans)
```

# D問題

- ここ2週間それなりに忙しいので，省略します．ごめんなさい．
- コメントを見て下さい．
```D.py
"""
<方針>
- ここ2週間それなりに忙しいので，省略します．ごめんなさい．
- コメントを見て下さい．
"""
N, M = map(int, input().split())

MOD = 998244353
# 回数
ans = 0

# Mの各ビットを下から見ていく．
for i in range(60):
  
  # Mとkのi番目のビットが両方とも立つような回数．
  b = 0
  
  # i番目のビットだけを立たせた数字．
  m = 1 << i
  
  # Mのi番目のビットが立っている時，
  if M & m:
    # kが取れる全パターンから，m番目のビットが立っているようなパターン数
    di, mo = divmod(N+1, 2*m)
    # 割った数を足す．
    b += di * m
    # 余りを足す．
    b += max(0, mo - m)
  
  # 答えを足して，MODをとっておく．
  ans += b
  ans %= MOD

print(ans)
```

# 補足
### 関係するリンク(参考文献など)
- [今回のコンテスト](https://atcoder.jp/contests/abc356)
### 筆者について
- [Atcoderアカウント](https://atcoder.jp/users/mattsunkun)
- [今回の成績(oooo---)](https://atcoder.jp/users/mattsunkun/history/share/abc356)
- [解説で示したA問題の提出](https://atcoder.jp/contests/abc356/submissions/54154991)
- [解説で示したB問題の提出](https://atcoder.jp/contests/abc356/submissions/54155268)
- [解説で示したC問題の提出](https://atcoder.jp/contests/abc356/submissions/54155444)
- [解説で示したD問題の提出](https://atcoder.jp/contests/abc356/submissions/54153983)
### その他
- **間違いを含んでいる可能性があります．**
- 方針と言いつつ，方針ではない感想などを書いている可能性があります．
- A問題から解説がだんだん省略されます．
- コードに書かれている解説の文言と，その上に書いてある解説の文言を変えている場合があります．
### 最後に一言
- 先週の記事の`最後に一言`にも書いたんですけど，ゲキ忙しくて，解説サボってます．．．ごめんなさい．．．
Remixでプロジェクトを作ってバージョン確認したら全然違うバージョン情報が返ってきたんだけど

## 〜宣伝〜

:::note info
個人開発でエンジニア専門マッチングサービスを開発しましたので、是非未経験からエンジニア目指している人！現役エンジニアで教えたい人！使ってみてください！

β版リリース記念キャンペーン中です！

10名様限定、抽選でお好きな技術本1冊プレゼント！
🎉当選者にはメッセージ差し上げます(送付の際に住所はお聞きしません)
詳しくはこちらから↓

https://x.com/dokupro01/status/1796837336145436846
:::
https://dokupro.dev/

## 概要

下記の記事でRemixのプロジェクトを作ってみた。ターミナルから2種類のコマンドでバージョンを確認したら全然違うバージョンが返されて困惑したので簡単にまとめる。

## remixのバージョン確認コマンド

どうやらプロジェクトディレクトリに入り下記コマンドを実行することでRemixのバージョンを確認できるらしい。

```shell
npx remix --version
```

筆者は上記を実行し、2.9.2と返ってきた。package.jsonを見ても`"@remix-run/node": "^2.9.2",`と書かれているので間違いはなさそう。

```package.json
"@remix-run/node": "^2.9.2",
"@remix-run/react": "^2.9.2",
"@remix-run/serve": "^2.9.2",
```

## `npm`コマンドと`npx`コマンド

`npx`コマンドが初体験だったのでちょっと調べてみた。どうやら「インストールせずにパッケージを実行できる」らしい。ようはNode.jsのパッケージをインストールせずに実行できるツールのコマンドらしい。

## `npm remix --version`を実行してみたら、、、

上記の内容を聞きかじった自分は何を間違えたか「Node.jsのパッケージをインストールせず」ではなく「Node.jsをインストールせず」と勘違いしてしまった。
「自分のローカルPCにはNode.js入ってるし、`npm`コマンドも通るから`npm`コマンドでもいいやろ」ということで下記を実行してみた。

```shell
npm remix --version
```

9.8.1というバージョンが返された。npxを使ったときと全然違う。何だこれ。

## `npx remix --version`の挙動

正しい方のコマンドは下記の様に動作するらしい

1. remixパッケージを一時的にダウンロード（ローカルのnode_modulesディレクトリを確認、存在していたらそれを使う、なければnpmレジストリであるリモートサーバーからダウンロード）
1. remixパッケージから--versionオプションを使ってバージョン情報を表示

## `npm remix --version`の挙動

先にネタバラシすると、このコマンドはそもそもremixのバージョンを返すコマンドではなかった。
どうやらこのコマンドはnpmそのもののバージョンを返しているらしい。なので`npm remix --version`と`npm --version`は同じレスポンスになる。

```shell
$ npm remix --version
9.8.1
$ npm --version
9.8.1
```

また、なぜnpmは間に「remix」という文字列が入っていてもエラーにならずnpmのバージョンを返すかだが、これは`npm`コマンドのなかで`--version`のオプションが非常に優先度が高いためらしい。ようは「remix」という文字列がはいっていようが、末尾に`--version`がついていたら他のすべての引数は無視される。

## 正しいコマンド

ということで改めて正しいコマンドをまとめておく

### `npx`を使う場合

```shell
npx remix --version
```

### `npm`を使う場合

```shell
npm list @remix-run/react
```
Goでマイグレーションしようした時の構造体のタイポによるエラー

## 構造体の定義

```go
type Shop struct {
	ID        uint      `json:"id" gorm:"primaryKey"`
	ShopName  string    `json:"shopname" gorm:"not null"`
	Place     string    `json:"place"`
	Location  float64   `json:"location"`
	Price     uint      `json:"price"`
	Tag       string    `json:"tag"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
	User      User      `json:"user" gorm:"foreignKey:UserID; constraint:OnDelete:CASCADE"`
	UserId    uint      `json:"userid"`
}
```

上記のコードのままmigrationを実行しようとしたら、エラーが出てDBと接続できませんでした。

原因はUserのフィールドで外部キーの記述の部分でタイポでした。。。情けない。。正しくは下記のように定義します。

## 正しい構造体の定義
```go
type Shop struct {
	ID        uint      `json:"id" gorm:"primaryKey"`
	ShopName  string    `json:"shopname" gorm:"not null"`
	Place     string    `json:"place"`
	Location  float64   `json:"location"`
	Price     uint      `json:"price"`
	Tag       string    `json:"tag"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
	User      User      `json:"user" gorm:"foreignKey:UserID; constraint:OnDelete:CASCADE"`
	UserID    uint      `json:"userid"`
}
```
毎日ABC day10【c++】ABC336 A-C問題解説【ACコード付き】

# AtCoder Beginner Contest 336

https://atcoder.jp/contests/abc336

## A - Long Loong
Longという文字列を出力する。ただし、'o'だけは与えられる $N$ 個連続して出力する。

```cpp
int N;

int main()
{
	cin >> N;
	cout << "L";
	for (int i = 1; i <= N; i++) cout << "o";
	cout << "ng" << endl;
	return 0;
}
```

## B - CTZ
与えられる整数 $N$ を2進数表記した際に、末尾に0が何個続くかを出力する問題。

末尾から順番に、その桁の数字は $2^0, 2^1, 2^2, ...$で割った余りが0か1かを表しているので、末尾から1桁ずつ0であるかを確認し、何桁連続するかを出力すればよい。

```cpp
int N;

int main()
{
	cin >> N;
	int count = 0;
	while(N % 2 == 0)
	{
		count++;
		N /= 2;
	}
	cout << count << endl;
	return 0;
}
```

## C - Even Digits
10進法で表した時に、偶数の数字のみが登場する非負整数を"良い整数"と呼ぶ。

整数$N$が与えられるので、良い整数の小さい方から$N$番目の整数を求めよ、という問題。

5進数であるというところに着目できたら勝ち。

```cpp
long long N;
int digits[19];

int main()
{
    cin >> N;
    N--;
    for (int i = 0; i < 19; i++)
    {
        digits[i] = N % 5;
        N /= 5;
    }
    int i = 18;
    while (i >= 0 && digits[i] == 0) i--;
    if (i < 0)
    {
        cout << 0 << endl;
    }
    else
    {
        while (i >= 0)
        {
            cout << digits[i] * 2;
            i--;
        }
        cout << endl;
    }
    return 0;
}

```
【bash】キーで sort された連想配列のループ処理を実装

## はじめに

タイトルの通りですが、連想配列をキーで sort した後、ループ処理させる実装方法を備忘録として残しています。



## 前提

連想配列が以下のように定義されているとします。

```bash:連想配列
declare -A daily_costs

daily_costs["20240101"]="200000"
daily_costs["20240102"]="400000"
daily_costs["20240103"]="150000"
daily_costs["20240104"]="260000"
daily_costs["20240105"]="330000"
daily_costs["20240106"]="210000"
daily_costs["20240107"]="500000"
daily_costs["20240108"]="1000000"
```

連想配列のキーはループさせる際に順不同なので、一工夫が必要です。
（今回のメインテーマになります）

```text:取り出し順は保証されない
[ec2-user@localhost ~]$ echo ${!daily_costs[@]}
20240108 20240101 20240102 20240103 20240104 20240105 20240106 20240107
```



## 結論

以下のように記述すると、意図する sort 順で処理を実行することができます。

```bash:sort を考慮したループ処理
echo "${!daily_costs[@]}" | sed 's/ /\n/g' | sort -n | while read key
do
        echo "日付: ${key}, コスト: ${daily_costs[${key}]}"
done
```

```text:実行結果
日付: 20240101, コスト: 200000
日付: 20240102, コスト: 400000
日付: 20240103, コスト: 150000
日付: 20240104, コスト: 260000
日付: 20240105, コスト: 330000
日付: 20240106, コスト: 210000
日付: 20240107, コスト: 500000
日付: 20240108, コスト: 1000000
```

#### コマンドの説明

| コマンド | やっていること |
|:-|:-|
| echo "${!daily_costs[@]}" | daily_costsのキーを全て取得（区切り文字は空白） |
| sed 's/ /\n/g' | 取得したキーの区切り文字を、空白から改行に変更（ sort が適切に働くようにするため） |
| sort -n | 数値として、昇順でソート |


`|`（パイプ）でコマンドをつなげることで、前の実行結果を後ろに渡すことができます。

そのため、上記のように `while` 文の前にコマンドを並べることで、ソートされたキーを順番に取り出してループ処理させることが可能になります。



## 応用

二つの連想配列を組み合わせて処理させたい場合があります。

例えば上記の例に加えて、売上用の連想配列を用意します。

```bash:売上用の連想配列
declare -A daily_earnings

daily_earnings["20240101"]="600000"
daily_earnings["20240103"]="1200000"
daily_earnings["20240105"]="1800000"
daily_earnings["20240107"]="2600000"
daily_earnings["20240109"]="3300000"
daily_earnings["20240110"]="900000"
daily_earnings["20240112"]="900000"
daily_earnings["20240114"]="1500000"
```

二つの連想配列のキーの和集合を使ってループ処理をするには、以下のように記述します。

`uniq` : ソートされた文字列に対して、重複する行を一つにまとめるコマンド

```bash:キーの和集合を sort してループ処理
echo "${!daily_costs[@]} ${!daily_earnings[@]}" | sed 's/ /\n/g' | sort -n | uniq | while read key
do
        echo "日付: ${key}, 売上: ${daily_earnings[${key}]}, コスト: ${daily_costs[${key}]}"
done
```

```text:実行結果
日付: 20240101, 売上: 600000, コスト: 200000
日付: 20240102, 売上: , コスト: 400000
日付: 20240103, 売上: 1200000, コスト: 150000
日付: 20240104, 売上: , コスト: 260000
日付: 20240105, 売上: 1800000, コスト: 330000
日付: 20240106, 売上: , コスト: 210000
日付: 20240107, 売上: 2600000, コスト: 500000
日付: 20240108, 売上: , コスト: 1000000
日付: 20240109, 売上: 3300000, コスト: 
日付: 20240110, 売上: 900000, コスト: 
日付: 20240112, 売上: 900000, コスト: 
日付: 20240114, 売上: 1500000, コスト: 
```



## おわりに

連想配列は便利なのでいっぱい使いそう（小並感）
nRF5340 で OpenThread を使って、省電力要件を維持しつつ、待機時の応答時間を向上させた話。 

# 概要
下記記事の続き。

https://qiita.com/Akihiro-Sakaniwa/items/c8223577460c1c524205

前回の調査では、待機時電流のアヴェレージが 100uA未満という条件下にて、ESP32 ＆ ESPNOW での待機時の通信周期は、約90秒が限界だったが、流石に NG が出たので再調査を行うことになった。


たどり着いたのは、OpenThread。

ZIP圧縮されたファイルを解凍する必要があったので、
メモリの少ないnRF52系は選択肢から外れて、nRF5340 で検証した。

結論としては、

OpenThreadはゲートウェイとエンドデバイス間のUDP通信のデータレートが5KiB/s程度だが、8秒周期でゲートウェイとエンドデバイス間通信を実現できることがわかった。


単体構成だと、50KiBのZIP圧縮されたファイルの転送時間が１０秒程度、ZIP解凍する時間が２秒程度かかる。

通信速度の速いデバイスの電源スイッチとして利用するか、単体で全て処理するかの結論はまだ出ていないが、90秒から８秒まで、レイテンシーが向上したのは一つの成果と考えられる。



# 使用機材（電子ペーパー）

電子ペーパー周りは前回と同じく WaveShare のデバイスを利用した。
パワーMOSFETをつかって、エンドデバイスから電源管理を行った。


# 使用機材（エンドデバイス）

エンドデバイスは、技適のある RAYTAC MDBT53V-DB（もしくはMDBT53-DB） を使用。
オンメモリでは処理できないので QSPI-NOR フラッシュメモリを外付けした。
（SPI接続でも試してみたが、QSPI接続にくらべZIP解凍時間が６倍くらい遅くなったので QSPIを採用した）

https://www.raytac.com/product/ins.php?index_id=140

https://www.raytac.com/product/ins.php?index_id=139


nRF53とnRF53vの違いは、チップの大きさとGPIOの数。
53vは小型化されている分GPIOが少ない。


# 使用機材（ゲートウェイ）

ゲートウェイは、 RAYTAC MDBT53V-DB（もしくはMDBT53-DB）に OLIMEX ESP32-ISO を UART接続した。

Openthread と Ethernetを共存させると、Ethernetが正常に動作してくれなかったため、
サーバサイドの通信は、UARTを介して行うことにした。

※ nRF5340 単体で Openthread と Ethernet を共存できるかについては調査が完了していない。

https://www.raytac.com/product/ins.php?index_id=140

https://www.raytac.com/product/ins.php?index_id=139

https://www.olimex.com/Products/IoT/ESP32/ESP32-POE-ISO/open-source-hardware


# 使用機材（サーバー）

ゲートウェイとエンドデバイス間の調査が目的だったので、
今回は、Ethernet で LinuxPC（Debian）に接続してサクッとテストを行った。
サーバーサイドは Node-red を利用した。


# 以上。
Javaで「文字列の連結(+演算子)」の動作を確認してみた

# 概要

Javaで「文字列の連結(+演算子)」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/start/ope/index14.html

# 実装

以下のファイルを作成しました。
```JSample14_1.java
class JSample14_1{
  public static void main(String[] args){
    System.out.println(45 + 18 + "point");
    System.out.println("point" + 45 + 18);
    System.out.println("point" + (45 + 18));
  }
}
```

以下のコマンドを実行しました。
```
$ javac JSample14_1.java 
$ java JSample14_1 
63point
point4518
point63
```

# まとめ

何かの役に立てばと。
JavaScriptで現在の日時を取得する

## 日付と時刻
呼び出すときに例えば今日の日付をnew Date()で生成して引数で渡します。
```JavaScript:呼び出し側
const fileGenDate = this.formatDate(new Date()); // ファイル生成日時 YYYYMMDD_hhmm
```
YYYYMMDD_hhmmssの形式で取得します。

```JavaScript:定義側
public formatDate(date: Date): string {
		const year = date.getFullYear().toString(); // YYYY
		const month = (date.getMonth() + 1).toString().padStart(2, '0'); // MM　getMonth()は0から数えるため+1が必要
		const day = date.getDate().toString().padStart(2, '0'); // DD
		const hours = date.getHours().toString().padStart(2, '0'); // hh
		const minutes = date.getMinutes().toString().padStart(2, '0'); // mm
		const seconds = date.getSeconds().toString().padStart(2, '0'); // ss
		
        return `${year}${month}${day}_${hours}${minutes}`; // YYYYMMDD_hhmm
	}
```
Date オブジェクトが持つ値から日付と時刻の値をそれぞれ取得するメソッドとして次のものが用意されています。
```JavaScript:メソッド
getFullYear()      // 年の値を取得する
getMonth()         // 月の値を取得する
getDay()           // 曜日の値を取得する
getHours()         // 時の値を取得する
getMinutes()       // 分の値を取得する
getSeconds()       // 秒の値を取得する
getMilliseconds()  // ミリ秒の値を取得する
```
padStart()、padEnd()は文字列にのみ使用できるメソッド。
```JavaScript
'5'.padStart(2, '0'); // 5の場合、"05"
'5'.padEnd(2, '0'); // 5の場合、"50"
// (2, '0')の2は桁数、'0'は２桁に満たない場合に前0を付与する
'abc'.padStart(7, '@'); // "@@@@abc"のようにabcの前に@が付与し７文字列になる
'abc'.padEnd(7, '@'); // "abc@@@@"のようにabcの後に@が付与し７文字列になる
djb2ハッシュアルゴリズムの解説と実装

## はじめに
ハッシュ関数は、データを一意のハッシュ値に変換するための重要なツールです。この記事では、ダニエル・J・バーンスタイン（Daniel J. Bernstein）によって提案された有名なハッシュアルゴリズム「djb2」について解説します。具体的な実装例として、C言語での実装を見ていきます。

### djb2アルゴリズムとは

djb2アルゴリズムは、そのシンプルさと効果的なハッシュ値生成能力から広く使用されています。このアルゴリズムは、文字列を入力として受け取り、一意のハッシュ値を生成します。アルゴリズムの核心は、各文字の値に基づいてハッシュ値を更新するビット操作にあります。

### 実装例

以下に、djb2アルゴリズムを実装したC言語の関数 `passHash` を示します。この関数は、文字列 `str` を入力として受け取り、対応するハッシュ値を返します。

```c
unsigned long passHash(const char *str) {
    unsigned long hash = 5381;
    int c;

    while (c = *str++)
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */

    return hash;
}
```

### 実装の詳細

#### 関数の宣言

```c
unsigned long passHash(const char *str)
```
- **unsigned long**: 関数が返すデータ型。32ビットまたは64ビットの非負整数です（システムによって異なります）。
- **const char *str**: 入力として受け取る文字列。`const` 修飾子が付いているため、関数内部で文字列の内容を変更することはできません。

#### 変数の初期化

```c
unsigned long hash = 5381;
int c;
```
- **hash**: ハッシュ値を格納する変数。初期値は `5381` に設定されています。これは、djb2アルゴリズムの初期値として推奨されています。
- **c**: 現在の文字を格納するための変数。

#### ハッシュ計算ループ

```c
while (c = *str++)
    hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
```
- `while (c = *str++)`: ポインタ `str` が指す文字を変数 `c` に代入し、`str` を次の文字に進めます。文字列の終端に達する（`NULL`文字になる）までループが続きます。ここでは代入演算子 `=` が使われています。
- `hash = ((hash << 5) + hash) + c;`: 現在のハッシュ値 `hash` を更新します。具体的には、`hash` を左に5ビットシフト（`hash << 5`）し、それに元の `hash` を足し、さらに現在の文字 `c` を加えます。これは `hash * 33 + c` と等価です。

#### ハッシュ値の返却

```c
return hash;
```
- 最終的に計算されたハッシュ値を返します。

### ハッシュ計算の詳細

djb2アルゴリズムのハッシュ計算は次のように行われます：

1. 初期値 `5381` からスタートします。
2. 各文字に対して、現在のハッシュ値を左に5ビットシフトし、元のハッシュ値を足し、さらに文字の値を加えます。このシフトと加算は、ハッシュ値を生成するためのビット操作です。

以下に、このアルゴリズムの流れを追った具体例を示します：

#### 例：文字列 "abc" の場合

1. 初期値：`hash = 5381`
2. 'a' を処理:
   - `c = 'a'` (ASCII値 97)
   - `hash = ((5381 << 5) + 5381) + 97`
   - `hash = (172192 + 5381) + 97`
   - `hash = 177670`
3. 'b' を処理:
   - `c = 'b'` (ASCII値 98)
   - `hash = ((177670 << 5) + 177670) + 98`
   - `hash = (5687040 + 177670) + 98`
   - `hash = 5863208`
4. 'c' を処理:
   - `c = 'c'` (ASCII値 99)
   - `hash = ((5863208 << 5) + 5863208) + 99`
   - `hash = (187622656 + 5863208) + 99`
   - `hash = 193485963`
5. 結果のハッシュ値：`193485963`

このようにして、文字列 "abc" のハッシュ値は `193485963` となります。

### まとめ

djb2ハッシュアルゴリズムは、そのシンプルさと効果的なハッシュ値生成能力から、多くの用途で使用されています。特に文字列のハッシュ値を計算する場合に非常に便利です。このアルゴリズムの実装は簡潔でありながら、強力なハッシュ関数を提供します。