OmniAICreator/Qiita-1.07M huggingface dataset:
llama-cpp-pythonでmadlad400の英日翻訳を試してみた

llama.cppでT5のサポートを始めたそうで、llama-cpp-pythonでもお試し実装があったのでmadlad400のggufで翻訳を試してみた。

- [llama : add T5 (encoder-decoder) support #5763](https://github.com/ggerganov/llama.cpp/issues/5763)
- [Cannot run T5-based models #1587](https://github.com/abetlen/llama-cpp-python/issues/1587)

## セットアップ
```
$ git clone --recurse-submodules https://github.com/fairydreaming/llama-cpp-python.git -b t5
$ cd llama-cpp-python
$ pip install -e .

# madlad400 ggufモデル取得
$ curl -LO https://huggingface.co/mtsdurica/madlad400-3b-mt-Q8_0-GGUF/resolve/main/madlad400-3b-mt-q8_0.gguf
```

m1 macなので`pip install`ではなく、makeでllama-cpp-pythonをインストールした。
```
$ make build.metal

# cudaの場合
$ make build.cuda
```

## サンプルコード

[英語ニュース](https://www.eigo-net.jp/easy_readings/easy_readings-3723)から英文を取得

```python: test.py
from llama_cpp import Llama

llama = Llama("madlad400-3b-mt-q8_0.gguf")

def trans(text):
    text = f"<2ja>{text}".encode()
    tokens = llama.tokenize(text)
    llama.encode(tokens)
    tokens = [llama.decoder_start_token()]
    buf = ""
    for token in llama.generate(tokens, top_k=0, top_p=0.95, temp=0, repeat_penalty=1.0):
        buf += llama.detokenize([token]).decode()
        if token == llama.token_eos():
            break
    return buf

text = """
IT glitch hits airlines, banks around the world.

A massive tech failure hit computers around the globe on July 19, disrupting banks, airlines and telecommunications companies.

In the United States, several major airlines, including United, American Airlines and Delta, stopped all flights."

In Australia, telecommunications provider Telstra reported outages, while National Australia Bank and ANZ had access issues.

The global glitch was reportedly caused by a software update that cybersecurity firm CrowdStrike provided to Windows computers of its corporate customers.
"""

for txt in text.split("\n"):
    if txt == "":
        continue
    buf = trans(txt)
    print(buf)
```

### int8 結果
```
 ITの問題で航空会社や銀行が 世界中で倒産してる
 7月19日に 世界中のコンピュータに 巨大な技術的故障が起きました 銀行や航空会社 電気通信会社を混乱させました
 アメリカ合衆国では、ユナイテッド航空、アメリカン航空、デルタ航空などの主要航空会社が全ての飛行を停止した。
 オーストラリアでは、電気通信プロバイダのテルストラが停電を報告し、ナショナル・オーストラリア銀行とANZはアクセス問題を抱えていた。
  世界的なグリッチは、サイバーセキュリティ会社CrowdStrikeがその企業顧客のWindowsコンピュータに提供したソフトウェアアップデートによって引き起こされたと報告されている。
```

最初の一文から航空会社と銀行が倒産している（笑）

### 和訳

```
世界各地の航空会社や銀行にシステム障害

7 月 19 日、世界各地のコンピュータに大規模な障害が発生し、銀行、航空会社、通信会社に混乱が生じた。

米国では、ユナイテッド航空、アメリカン航空、デルタ航空を含む大手航空会社数社が全便を欠航とした。

オーストラリアでは、通信会社のテルストラがサービス停止を報告し、ナショナルオーストラリア銀行と オーストラリア・ニュージーランド銀行でもアクセスに問題があった。

世界各地で起きた不具合は、サイバーセキュリティー企業クラウドストライク（CrowdStrike）がウィンドウズを搭載した顧客のコンピュータにアップデートしたソフトウェアを提供した際に引き起こされたとされている。
```

## MEMO

その他の環境でのmadlad400の実行

### mlx float16

https://github.com/ml-explore/mlx-examples/issues/980

### ctranslate2 int8

https://forum.opennmt.net/t/ctranslate2-supports-madlad-400/5564/2
QtでLibTorchを使えるようにした

## はじめに

Qt に LibTorch を導入する方法を簡単にまとめておきます。
その際に吐かれたエラーについてもその解決法を記しておきます。

## 環境

OS : Ubuntu 22.04
Qt : 6.7.2
Qt Creator : 13.0.2

## Libtorch のダウンロード

下記公式サイトから、欲しいものを選んでダウンロードし、zipファイルを解凍します。
その後、（中に入っている）libtorch ディレクトリを、ホームディレクトリの直下に配置しました。

https://pytorch.org/

この部分は、他の方が解説してくださっているので省略します。

https://qiita.com/koba-jon/items/2b15865f5b4c0c9fbbf7

## CMakeLists.txt (LibTorch関連部分のみ抜粋)

LibTorch を使用するために、CMakeLists に追記します。

```cmake:CMakeLists.txt
set(Torch_DIR $ENV{HOME}/libtorch/share/cmake/Torch)

# --- 中略 ---

find_package(Torch REQUIRED)

# --- 中略 ---

target_link_libraries(MainWindow ${TORCH_LIBRARIES})
```

## エラー解消

とりあえず、Qt Creator 内で適当に .cpp ファイルを作成し、ビルドしてみます。

```cpp:Sample.cpp
// LibTorch
#include <torch/torch.h>
#include <torch/script.h>
```

すると、次のようなエラーを吐かれました。

```txt:Error
error: expected unqualified-id before ‘)’ token
 1566 |   const std::vector<IValue>& slots() const {
      |                                    ^
```

原理としては単純で、Qt では slots が予約語になっているので、関数としての slots() を正しく認識できません。

なので、LibTorch のファイルを少し改変します。全部で４か所です。
slots() という名前が悪いだけなので、これを例えば、getSlots() とかにしてあげればよいだけです。

```
const std::vector<IValue>& getSlots() const {  // Rename
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3607016/0e504ed7-3fb1-1159-6fb3-d993920b55a9.png)
▲この４か所

エラーが出ている４か所すべてを slots() から getSlots() にします。（４か所で良かった...）

---

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3607016/3ce28597-fad9-324f-15cc-89613dc25008.png)

これで、ビルドすると、ちゃんと通ってくれました。めでたしめでたし。
【React】ビルドフォルダを変更したい

# この記事の概要
- `npm run build`でReactで開発したファイルをビルドするとき、現在ディレクトリのbuildフォルダ配下にファイルが作成される
- このbuildフォルダの名前や配置を変更できないかと思った
- 【結果】現在ディレクトリの`.env`ファイルに`BUILD_PATH={フォルダ名}`を入力すると変更できる


# 1. 背景
Reactのビルドを行うと現在ディレクトリに`build`フォルダとその配下にビルド後のファイルが生成される
ふと、buildフォルダの名前やパスを変更できないか気になり、ソースコードを確認した

# 2. 調査
1\. 実行ファイルの確認
Reactビルド時には`react-scripts build`が実行されている
```
$ npm run build

> src@0.1.0 build
> react-scripts build
```
node_moduleフォルダ配下に`react-scripts`とbuildを起動しているプログラムがありそう
```
$ find ./node_modules/ -name react-scripts

./node_modules/.bin/react-scripts
./node_modules/react-scripts
```
コードを確認したところ、
- ./node_modules/.bin/react-scripts：エントリーポイント
- ./node_modules/react-scripts配下：実行

のようだった

2\. プログラムの確認
`
node_modules/react-scripts/scripts/build.js`からbuildフォルダを指定している箇所を確認する
```build.js
const buildFolder = path.relative(process.cwd(), paths.appBuild);
```
110行目に変数`buildFolder`を発見
`paths`ファイルの`appBuild`を使用しているっぽい

```paths.js
appBuild: resolveOwn(path.join('../..', buildPath))
```
buildPath変数の定義を確認
```paths.js
const buildPath = process.env.BUILD_PATH || 'build';
```
■コードの意味
- `process.env`：現在ディレクトリの`.env`ファイル内の環境変数を使用するプログラム
- `~.BUILD_PATH`：`.env`ファイル内の`BUILD_PATH`変数の値を参照
- `~.BUILD_PATH`がundefinedなら`'build'`をパスとする

### 調査結果
現在ディレクトリに`.env`ファイルを作成し、`BUILD_PATH={フォルダ名}`と入力すれば、buildフォルダの名前やパスを変更できそう

# 3. 実践
1\. BUILD_PATHを指定しない場合(デフォルトの場合)

■実行前
```
.
├── node_modules
├── public
├── package-lock.json
├── package.json
└── src
```
■実行後
直下に作成された
```
.
├── build
│   └── static
├── node_modules
├── public
├── package-lock.json
├── package.json
└── src
```

2\. srcフォルダ配下に作成する
`.env`ファイルにパスを入力
```.env
BUILD_PATH=src/build2
```
名前も`build2`に変更

■実行前
```
.
├── .env
├── node_modules
├── public
├── package-lock.json
├── package.json
└── src
```

■実行後
src配下に生成された
```
.
├── .env
├── node_modules
├── public
├── package-lock.json
├── package.json
└── src
    └── build2
        └── static
```


# 4. まとめ
- Reactのビルドでは`node_modules/react-scripts/scripts/build.js`を実行している
- 実行時に`.env`の`BUILD_PATH`を参照し、入力されていなければ`./build`にビルドファイルを作成する
- 現在ディレクトリの.envファイルにBUILD_PATH={フォルダ名}を入力すると、ビルドフォルダの名前やパスを変更できる
Ubuntu 24.04 に .NET 6 と .NET 8 をインストールしてみた

ある案件の開発環境は Ubuntu 22.04 LTS を使用しています。現在の開発環境から Ubuntu 24.04 LTS に乗り換えたく環境整備をしていましたが、単純に .NET 6 がインストールできなかったので、調べてインストールできるようにしてみました。

## OS 情報確認

```bash:bash
$ cat /etc/os-release | grep PRETTY_NAME
PRETTY_NAME="Ubuntu 24.04 LTS"
```

## .NET 6 がインストールできない状態

```bash:bash
$ sudo apt-get install -y dotnet-sdk-6.0 dotnet-sdk-8.0
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Package dotnet-sdk-6.0 is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

E: Package 'dotnet-sdk-6.0' has no installation candidate
```

## Ubuntu の .NET バックポートリポジトリを登録

```bash:bash
$ sudo add-apt-repository ppa:dotnet/backports
```

## Microsoft パッケージリポジトリを登録

```bash:bash
$ source /etc/os-release

$ wget https://packages.microsoft.com/config/$ID/$VERSION_ID/packages-microsoft-prod.deb -O packages-microsoft-prod.deb

$ sudo dpkg -i packages-microsoft-prod.deb

$ rm packages-microsoft-prod.deb

$ sudo apt update
```

## .NET 6 と .NET 8 をインストール

```bash:bash
$ sudo apt-get install -y dotnet-sdk-6.0 dotnet-sdk-8.0
```

## .NET SDK を確認

```bash:bash
$ dotnet --list-sdks
6.0.133 [/usr/lib/dotnet/sdk]
8.0.108 [/usr/lib/dotnet/sdk]
```

## 参考

https://learn.microsoft.com/ja-jp/dotnet/core/install/linux-ubuntu-install?tabs=dotnet8&pivots=os-linux-ubuntu-2404#ubuntu-2404

https://learn.microsoft.com/ja-jp/dotnet/core/install/linux-ubuntu#ubuntu-net-backports-package-repository
XSSなどの脆弱性まとめ

引き続き、[体系的に学ぶ 安全なWebアプリケーションの作り方](https://www.amazon.co.jp/%E4%BD%93%E7%B3%BB%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B6-%E5%AE%89%E5%85%A8%E3%81%AAWeb%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9-%E7%AC%AC2%E7%89%88-%E8%84%86%E5%BC%B1%E6%80%A7%E3%81%8C%E7%94%9F%E3%81%BE%E3%82%8C%E3%82%8B%E5%8E%9F%E7%90%86%E3%81%A8%E5%AF%BE%E7%AD%96%E3%81%AE%E5%AE%9F%E8%B7%B5-%E5%BE%B3%E4%B8%B8/dp/4797393165)を読んだので、覚えたい部分を記事にしていく。


## クロスサイトスクリプティングとは

XSS(クロスサイトスクリプティング)とは、外部からの入力などに対して、表示が変化する部分があり、そこのHTML生成の実装に問題があることで生じる脆弱性のこと。
XSS脆弱性があることで以下のような問題が発生する。
- 利用者のブラウザ上でスクリプトが実行されてしまう
- 偽の入力フォームが表示されて、個人情報が盗まれる

### 対策
- 要素内容については`<`と`&`をエスケープする
- 属性値は、`"`で囲い、`<`と`"`と`&`をエスケープする
- HTTPレスポンスに文字エンコーディングを明示する

## SQLインジェクションとは

SQLの呼び出し方に不備がある場合に発生する脆弱性のこと。
- DBの情報が盗まれる
- DBの情報が変更される
-などの影響がある。

### 対策
SQLインジェクション脆弱性の根本的な原因は、パラメータとして指定した文字列の一部がリテラルをはみ出すことにある。
なので、それを防ぐ必要がある。
- プレースホルダによりSQL文を組み立てる
- アプリケーション側でSQL文を組み立てるときに、リテラルを正しく構成するなどして、SQL文が変更されないようにする

## クロスサイト・リクエストフォージェリ(CSRF)
重要な処理の受付の際には、利用者の意図したリクエストであることを確認する必要がある。
が、その確認が抜けているとCSRF脆弱性になる。
その結果、利用者のブラウザから勝手に重要な処理が実行されるといったことが発生する。

### XSSとCSRFの違い
1. 罠サイトの閲覧
1. 仕掛けのあるHTMLが利用者のブラウザで実行される
1. 正規サイトに攻撃用のリクエストをする
ここまではどちらも、同じ流れ。

#### XSSの場合
XSSの場合は、3のリクエストに含まれるスクリプトが、そのまま利用者のブラウザにレスポンスとして返却される。
利用者のブラウザ上で、スクリプトが実行される。
なので、ブラウザ上でできることは何でも悪用可能。

#### CSRFの場合
CSRFの場合は、3のリクエストに対するサーバー側の処理を悪用するもの。

### 対策
重要なリクエストが正規の利用者が意図したものかを確認する必要がある。
- CSRF対策の必要なページを区別
- 正規利用者の意図したリクエストを確認できるように実装

## クリックジャッキング
利用者が気づかないうちに攻撃対象のサイトでのクリックを誘導する攻撃手法。

### 対策
X-Frame-Optionsヘッダで、クリックジャッキング攻撃は防ぐことができる。
VRChatのUdonでテレポートをした際に視点だけ移動する場合、Delayすると解決するかもしれない

# 概要
チーム開発していた際にテレポートを使用したギミックを組んだ際に、なぜか視点だけ移動してアバターが移動しない事が発生しました。

# 環境
- Unity 2022.3.22.f1
- VRChat SDK 3.6.1

# コード背景
ドアをUseした際にテレポートをさせますが、その際同時に何らかのObjectをPlayerに追従させています。このObjectにはコライダーは存在しませんが、テレポート時に現在位置からテレポート位置までの間に存在する部屋や地面などのコライダーに引っかり視点のみが移動します。(アバターも移動するが、コライダーに阻まれる)

# 解決策
以下がもしかしたらテレポートできない場合のコード。
```動かない.cs
// かなり略

// テレポート発火関数(独自)
public void OnTriggerTeleportButton(){
    Networking.LocalPlayer.TeleportTo(targetPosition.position, targetPosition.rotation);
}

```

以下がもしかしたらテレポートが解決する場合のコード。
```動く.cs
// かなり略

// テレポート発火関数(独自)
public void OnTriggerTeleportButton(){
    SendCustomEventDelayedFrames(nameof(TeleportTo), 10);
}

// 独自関数
public void TeleportTo()
{
    Networking.LocalPlayer.TeleportTo(targetPosition.position, targetPosition.rotation);
}
```

# 原因
Delayをはさんだことにより、おそらく内部的な処理が終了した段階で安全にテレポートできるようになったと思われます。
この解決策で二人程救いました。
もし詳しい原因がわかる方はコメントなどで教えていただけますと幸いです。
DB取得データとキーが一致する処理データの値を比較して処理する方法【Python】

## 説明

### 処理の流れ
1. `db_data` から `id` と `code` をキーにした辞書 `db_dict` を作成します。
2. `chk_data` の各エントリの `id` と `code` を組み合わせて、`db_dict` のキーとして使用します。
一致するDBデータがあれば`db_match`に格納され、なければ`None`になります。
3. `db_match` が存在する場合、`chk['pos']`（処理データの位置）と`db_match['pos']` （DBデータの位置）を比較して、対応するメッセージを返します。
```python
# 処理データ
chk_data = [
    { 'id': 1, 'code': 'A10', 'pos': 52 },
    { 'id': 3, 'code': 'A30', 'pos': 52 },
    { 'id': 4, 'code': 'A40', 'pos': 52 },
    { 'id': 5, 'code': 'A50', 'pos': 52 },
]

# DBデータ
db_data = [
    { 'id': 1, 'code': 'A10', 'pos': 51, 'sort': 101 },
    { 'id': 2, 'code': 'A20', 'pos': 52, 'sort': 102 },
    { 'id': 3, 'code': 'A30', 'pos': 53, 'sort': 103 },
]

# (id, code)をキーとした辞書に格納
db_dict = {(db['id'], db['code']): db for db in db_data}

# 処理データのキー(id, code)と一致するDBデータを取得し、posを比較
for chk in chk_data:

    key = (chk['id'], chk['code'])  # 辞書のキーとなるタプル
    db_match = db_dict.get(key)  # 辞書からデータを取得

    if db_match:
        # posの比較
        if chk['pos'] > db_match['pos']:
            print(f"ID: {chk['id']}, Code: {chk['code']} - OVER")
        else:
            print(f"ID: {chk['id']}, Code: {chk['code']} - OK")
    else:
        print(f"ID: {chk['id']}, Code: {chk['code']} - DBデータが見つかりません")

# ID: 1, Code: A10 - OVER
# ID: 3, Code: A30 - OK
# ID: 4, Code: A40 - DBデータが見つかりません
# ID: 5, Code: A50 - DBデータが見つかりません
```
PytorchがCUDA12.4に対応してたから環境構築して試す

# いつの間にかPyTorchがCUDA12.4に対応していた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3568254/ba06b7a5-ddd3-d9b6-3ef9-b64f9959db47.png)

この前まで12.1までだった気がします。

# 作成した環境

- WSL2
- Dockerイメージ: nvidia/cuda:12.4.0-base-ubuntu22.04

# 手順

- CUDA12.4.0が入っているコンテナを作成してコンテナに入る

```bash
docker run -itd --gpus all --name sandbox1240 nvidia/cuda:12.4.0-base-ubuntu22.04
docker exec -it sandbox1240 /bin/bash
```

- 諸々アップデートしてPythonをインストール

```bash
apt update
apt upgrade -y
apt install python3.11 python3.11-venv -y
```

- 仮想環境を作成してActivateし、pipをアップグレード

```bash
python3.11 -m venv .env
source .env/bin/activate
python -m pip install -U pip
```

- ここでPyTorchをインストール

```bash
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124
```

- PyTorchでGPUを使えているか確認

```python
import torch
torch.cuda.is_available()
# -> True
torch.Tensor([0, 1, 2]).to('cuda')
# -> tensor([0., 1., 2.], device='cuda:0')
```

ちゃんと動いたっぽいです。

## ローカルLLM(Gemma-1.1-2b-it)の動作確認

```bash
pip install transformers accelerate
```

```python
import os
import getpass
os.environ['HF_TOKEN'] = getpass.getpass('HF_TOKEN:')

from transformers import AutoTokenizer, AutoModelForCausalLM

model_name = 'google/gemma-1.1-2b-it'
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    device_map='cuda',
)
chat = [
    {'role': 'user', 'content': '徳川幕府の歴代将軍を表形式で教えてください。'},
]
input_ids = tokenizer.apply_chat_template(chat, tokenize=True, return_tensors='pt').to(model.device)
outputs = model.generate(input_ids, max_new_tokens=1000)
print(tokenizer.decode(outputs[0]))
```

```:出力
<bos><start_of_turn>user
徳川幕府の歴代将軍を表形式で教えてください。<end_of_turn>
* 1333年 - 1335年：足利義昭
* 1335年 - 1346年：足利義元
* 1346年 - 1351年：足利義昭
* 1351年 - 1368年：足利義元
* 1368年 - 1374年：足利義昭
* 1374年 - 1380年：足利義元
* 1380年 - 1382年：足利義昭
* 1382年 - 1385年：足利義元
* 1385年 - 1394年：足利義昭<eos>
```

出力内容はともかくちゃんと動きました。

# CUDA12.4.1でも動作確認

コンテナイメージが`CUDA12.4.0`のほかに`CUDA12.4.1`がありましたので、こちらでも試してみました。
結果としては、`CUDA12.4.1`でもちゃんと動作しました。

環境構築のや実行の方法は`12.4.0`のときとほぼ同じで、コンテナ作成の`nvidia/cuda:12.4.0-base-ubuntu22.04`を`nvidia/cuda:12.4.1-base-ubuntu22.04`に変えるだけです。

# まとめ

いまだにCUDA12.1でPyTorchを動かしている人は、頃合いを見計らってCUDA12.4に乗り換えましょう。
データインテリジェンスを理解するための簡単なガイド

[The short guide to understanding data intelligence \| Databricks Blog](https://www.databricks.com/blog/short-guide-understanding-data-intelligence)の翻訳です。

:::note warn
本書は著者が手動で翻訳したものであり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

職場環境においては、「データガバナンス」、「生成AI」、「大規模言語モデル」ような用語が一般的になってきています。

しかし、ビジネスリーダーはそれらを単に会話やプレゼンテーションに散りばめるだけでは不十分です。彼らは、それらのトレンド、テクニック、技術が実際に何を意味するのか、自身の組織の未来においてどのような役割を担うのかを理解しなくてはなりません。

助けとなるように、データインテリジェンスのキーとなるいくつかのコンポーネントを定義し、リーダーたちのために、最終的には次世代のオペレーションをサポートすることになるこのようなバズワードを理解することがなぜ重要なのかを説明したいと思います。

**データインテリジェンス:** これは、情報以上のことを意味します。データインテリジェンスでは、プロプライエタリなデータから正確かつ適切でユニークな洞察を抽出するためにAIを活用します。これによって、企業が市場での競争優位性を作り出し、新たな収益のストリームを特定したり、従業員がより生産的になったり、オペレーションをより効率的なものにできるようになります。

**データサイロ:** データインテリジェンスをサポートするために必要な情報は、多くの場合、企業のさまざまなアプリケーションやシステムに囚われています。統合された一連のアセットアクセスできない場合、企業はより限定的で、場合によっては不正確でミスリードな情報に基づいて重要な意思決定を行わなくてはなりません。そして、データの統治や保護のような重要なタスクは困難で高コストなものになります。

**データレイクハウス:** 広く導入されているオープンソースプロジェクトのApache Spark、Delta Lake、MLflowによって実証されたデータレイクハウスは企業データの新たなホームとなっています。クローズなエコシステムやプロプライエタリなフォーマットから解放されることで、このアーキテクチャはデータサイロを排除し、最終的にはデータインテリジェンスワークロードの起点として動作する構造化、非構造化アセットを対象とした統合情報ストアを構築できるようになります。

**データインテリジェンスプラットフォーム:** DIプラットフォームは、企業向けの新たなオペレーティングエンジンを作成するために、レイクハウスアーキテクチャとAIを組み合わせます。単一のシステムで、取り込みから分析やAIワークロードの開発、デプロイメントに至るインテグレーションによって、データライフサイクル全体に対応し、開発者からデリバリー、継続的改善、ビジネス価値をドライブするダイナミックなデジタルソリューションにおける統合ガバナンスやコラボレーションの強化を提供します。

**データガバナンス:** データは制御され、追跡される必要があります。企業は認証されたユーザーによって資産が適切に活用されるようにしなくてはなりません。内部のチームは、アプリケーションのパフォーマンスに影響を与える可能性のあるデータ品質の問題をクイックに発見できる必要があります。しかし、IT環境のサイロ化された状況によって、データガバナンスに対する多数のさまざまなアプローチが必要となるケースが数多く存在します。DatabricksのUnity Catalogを用いることで、単一のフレームワークでガバナンスが管理され、企業にすべてのエコシステムに対する一貫性がありユニークなポリシーを設定できる能力と、ライフサイクルを通じてアセットを追跡できる能力を提供します。

**自然言語処理(Natural Language Processing:NLP):** 生成AIの基盤であるNLPによって、ユーザーはWebブラウザで検索するのと同じ方法でデータに質問することができます。レポートを作成するためにエンジニアやアナリストのチームにお願いするのではなく、例えばCEOによる「来年の売り上げはどのようになるのか？」といったプロンプトで、必要なビジネスインテリジェンスを生成できるようになります。

**データの民主化:** 自然言語のプロンプトでデータアセットにクエリーすることで、非技術者のユーザーが独立してインテリジェンスを生成でき、より良い、より情報に基づいた意思決定を生み出す助けとなります。このデータをアクセス、活用できるユーザーベースを安全に拡大するためには、堅牢なガバナンスが必要となります。しかし、最終的には民主化によって、企業が自分たちのデータから獲得できる価値を最大化することができます。

データインテリジェンスの完全なイントロダクションに関しては、[Data Intelligence for Dummies](https://www.databricks.com/resources/ebook/maximize-your-organizations-potential-data-and-ai)をチェックするか、企業が自分たちのデータインテリジェンスジャーニーのどこにいるのかに関して学ぶための最新の[State of Data \+ AI](https://www.databricks.com/discover/state-of-data-ai)レポートをチェックしてください。

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
指定キーのデータがDBから取得したデータに存在するか確認する方法【Python】

## 説明

1. `db_data` の各レコードから `id` と `code` をキーとしてセットを作成します（`db_keys`）。
2. `chk_data` 内の各データについて、`db_keys` に同じ `id` と `code` のペアが存在するか確認します。
3. 存在しないものは `ng_data` リストに追加され、最終的に結果を出力します。
```python
# 処理データ
chk_data = [
    { 'id': 1, 'code': 'A10', 'pos': 52 },
    { 'id': 3, 'code': 'A30', 'pos': 52 },
    { 'id': 4, 'code': 'A40', 'pos': 52 },
    { 'id': 5, 'code': 'A50', 'pos': 52 },
]

# DBデータ
db_data = [
    { 'id': 1, 'code': 'A10', 'pos': 51, 'sort': 101 },
    { 'id': 2, 'code': 'A20', 'pos': 52, 'sort': 102 },
    { 'id': 3, 'code': 'A30', 'pos': 53, 'sort': 103 },
]

# DBデータを (id, code) のセットに変換
db_keys = {(data['id'], data['code']) for data in db_data}

# chk_data の (id, code) をリスト化
chk_keys = [(data['id'], data['code']) for data in chk_data]

# chk_keys に含まれる (id, code) が db_keys に存在しないものをリストに追加
ng_data = [key for key in chk_keys if key not in db_keys]

# 結果を出力
if ng_data:
    print("存在しないデータ:", ng_data)
else:
    print("全てのデータが存在します")

# 存在しないデータ: [(4, 'A40'), (5, 'A50')]
```
Google Fonts を使ってみて〜エンジニア初学者の備忘録〜

## はじめに
こんにちは、未経験からエンジニア転職を目指しているものです。
オンラインスクールで本格的に学習して4ヶ月目に入りました。勉強し始めの頃の自分が疑問に思っていたことを整理してみようと思い記事を書いております。今回はHTML,CSSでウェブサイトを模倣してみた時、Google Fontsを使用時に感じた内容をまとめました。

## Google Fontsとは？
Googleが提供する無料のウェブフォントライブラリです。無料で利用可能で多様なフォントスタイルを簡単に導入できます。

## Font Familyとは？
CSSのプロパティで、テキストにしようするフォントを指定するために使います。複数のフォント名を指定することができ、ブラウザが最初のフォントが表示できない場合、次のフォントを順に試します。

### 使用例
```html
body{
    font-family:'Noto Sans JP', 'Arial', sans-serif;
}
```
この例では、もしNoto Sans JPが利用できなければ、Arialが適用され、それもなければブラウザに内蔵されたsans-serifフォントが使われます。

## Google Fontsの使い方
Google Fontsから「Noto Sans JP」というフォントを選んでウェブページを使いたい場合、以下のように行います。
### 使用例
1.Google Fontsからフォントを選ぶ
　例：Google Fontsで「Noto Sans JP」を選ぶ
2.HTMLにフォントを読み込む
　選んだフォントに対応する<link>タグをHTMLに追加します。
```html
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP&display=swap" rel="stylesheet">
```
3.CSSでfont-familyを指定する
　読み込んだフォントをCSSでfont-familyに指定します。
```html
body {
  font-family: 'Noto Sans JP', sans-serif;
}
```

## Font-Familyについて参考にさせてもらったサイト
下記のICS MEDIAさんのサイトを参考に勉強させてもらいました。

https://ics.media/entry/200317/

## Font-Familyについてのまとめ
上記のサイトで学んだ内容を私なりに整理してみました。
・fontの種類が多ければ多いほど、容量が増え通信スピードが遅くなる。
・fontの種類が多ければ多いほど、たくさんのOSでの表示をカバーできる。(フォールバック)
・OSのバージョンアップで急にフォントが変わる事がある。（そんなに多くはない）
　どのOSの環境下でも無難に表示されるようにFont Familyを使用している。
・colorやfont-sizeなどのプロパティは都度組み合わせて対応すれば良い。


最後までご覧いただき本当にありがとうございました！！
【Chatwork】自分宛てのメッセージ（返信含む）と全員宛てのメッセージを別のルームに転送する

```js
const pData = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("必要事項入力欄"); 
const pToken = pData.getRange("B2").getValue();//APIトークン
const roomID = pData.getRange("B3").getValue();//このルームでの自分宛てのメッセージを一覧化する
const accountID = pData.getRange("B4").getValue();//自分のアカウントID　環境設定から確認できる
const mychatID = pData.getRange("B5").getValue();//自分だけのルームID

function getMessages(){

  var params = {
    headers : {"X-ChatWorkToken" : pToken }, //チャットワークAPIトークン
    method : "get"
  };
  
  var url = "https://api.chatwork.com/v2/rooms/" + roomID + "/messages?force=1"; //指定のグループチャットからメッセージを取得
  
  
  try {
    var respons = UrlFetchApp.fetch(url, params).getContentText(); //チャットワークAPIエンドポイントからレスポンスを取得
    var json = JSON.parse(respons); //文字列をJSON形式として解析しJSONオブジェクトとして返


    json.forEach (function(obj) {
      
    var message = obj.body;
    var fromAccountId = obj.account.account_id;
    var messageId = obj.message_id;
    var sendTime = obj.send_time;
    var toaccount = getTOAccount(obj,accountID).flat();
    

    if(toaccount.includes(String(accountID))){

       // 情報を整形して投稿する
      var client = createClient_(pToken);
      client.sendMessage(
        {
          room_id: mychatID,
          body: Utilities.formatString("[qt][qtmeta aid=%s time=%s]%s[/qt]\nhttps://www.chatwork.com/#!rid%s-%s", fromAccountId, sendTime, message, roomID, messageId),
        }
      );
    }

    });

  } catch(e) {

    Logger.log("エラーが発生しました");
    Logger.log(e.message);
  }
}


function createClient_(api_token)
{
  return ChatWorkClient.factory(
    {
      'token': api_token,
    }
  );
}

//メッセージが誰宛か取得する・誰に返信したかも取得する・全員当てのメッセージも自分宛てに変換
function getTOAccount(obj,accound_id){
  let body = obj.body;
  let reg = /To:[0-9]{7}/g;
  let to_ids = body.match(reg);
  let reg2 = /\[rp aid=[0-9]{7}/g;
  let aid_ids = body.match(reg2);
  
  let reg3 =/\[toall\]/g;
  let toall_id = body.match(reg3);

  let toaccount = [];
  if(Array.isArray(to_ids) || to_ids !== null){
    to_ids.map((value,index,array)=>{
      
      value = String(value);
      value = value.replace(/To:/g,"");
      array[index] = value;
      
    })
    toaccount.push(to_ids);

  }else if(Array.isArray(aid_ids)){
    aid_ids.map((value,index,array)=>{
      
      value = String(value);
      value = value.replace(/\[rp aid=/g,"");
      array[index] = value;
      
    })
    toaccount.push(aid_ids);
  }else if(toall_id !== null){
    toaccount.push(accound_id)
  }else{
    toaccount.push(to_ids);
    toaccount.push(aid_ids)
  }
  return toaccount;
}
```
DiscordのグループDMの作り方の解説！

こんにちは、りょうです。
やり方教えろっていうのがあったので今回はDiscordでのグループDMの作成方法の解説になります。

## 手順
まずはここのフレンドを押して、右上にあるグループDM作成を押します。
![Screenshot 2024-09-04 10.58.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/81c3b7a6-cb8f-53ef-e396-099e0698c235.png)
![Screenshot 2024-09-04 11.03.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/42de0896-5c4a-3656-4c07-aacc5fc6ab3c.png)

グループDMに追加したいユーザーを選択し、DMの作成を押します。
人数の上限は自分を含めて10人になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/7ab23318-6b01-8c06-6ff5-36599974ae2c.png)

そうするとこのようにグループDMが作成されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/2eefb35b-4f5d-306d-671f-81abb3794521.png)

ここでDMへの招待リンクの作成、アイコン変更、脱退ができます。
また、作成者が脱退した場合は最初に追加された人に所有権が移動します。
脱退時は通知して抜けるかどうかの選択もできるようになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/a39323de-8f4c-7245-ebf8-1ddc12db012b.png)

## まとめ
今回はグループDMの作成方法の解説でした。
使わないので知らない人が結構いるみたいなので知ってて損はないとおもいます。

わからないことあったら書いてくれれば答えていきます。

**Discordにいる荒らしの情報や対策方法の共有をしている自鯖です**
ぜひ参加お願いします↓↓↓↓

https://discord.com/invite/ESRGwGQhxc
Common Lisp風のLISPを作ってみる（１６．gensym）

さて、今回からマクロ編となります。まずは一番やさしそうな`gensym`からやっていきましょう。とはいえ、本物の`gensym`を実装しようとするとコードを全体的に書き換えなければならなくなるので、妥協できそうな`gensym`もどきを作ってやります。元々の`gensym`が、ユーザーが定義できないシンボル、というような感じなんですけど、エスケープ文字を使わなければ定義できないシンボル、としておけば日常的には問題ないのではないかと思いましたので、そのようにしました。
[ソースコード](https://github.com/haruo-wakakusa/my-lisp2/tree/main/chapter16)
# built_in_func.c
`f_gensym`関数は`gensym`関数の実体です。
```built_in_func.c
/* gensymは引数を取らないこととする */
void *f_gensym(void *args) {
    static int count = 1;
    char name[16];
    if (list_length(args) != 0) {
        fprintf(stderr, "FUNCTION \"GENSYM\": 引数の数が不正です\n");
        state = STATE_ERROR;
        return 0;
    }   
    sprintf(name, "#:G%d", count);
    count++;
    return make_symbol(name);
}
```
# printer.c
`gensym`で生成したシンボルについてはエスケープ文字が付いてプリントされないようにしました。
```printer.c
static void print_symbol(FILE *stream, void *obj) {
    SYMBOL *symbol = (SYMBOL *)obj;
    char *p;
    int multiple_escape_is_needed = 0;
    for (p = get_symbol_string(symbol); *p != '\0'; ++p) {
        if (*p >= 'a' && *p <= 'z') {
            multiple_escape_is_needed = 1;
            break;
        }
        switch (*p) {
        case '(':
        case ')':
        case '\'':
        case ';':
        case '\"':
        case '`':
        case ',':
        case '#':
        case '\\':
        case '|':
        case ' ':
        case '\t':
        case '\n':
            multiple_escape_is_needed = 1;
            goto LOOPEND1;
        default:
            ;
        }
    }
    LOOPEND1:

    p = get_symbol_string(symbol);
    if (*(p++) == '#' && *(p++) == ':' && *(p++) == 'G' && isdigit(*(p++))) {
        int is_gensym = 1;
        while (*p != '\0') {
            if (!isdigit(*p)) {
                is_gensym = 0;
                break;
            }
        }
        if (is_gensym) multiple_escape_is_needed = 0;
    }

    if (!multiple_escape_is_needed) {
        fprintf(stream, "%s", get_symbol_string(symbol));
    } else {
        fputc('|', stream);
        for (p = get_symbol_string(symbol); *p != '\0'; ++p) {
            switch (*p) {
                case '\\':
                    fputs("\\\\", stream);
                    break;
                case '|':
                    fputs("\\|", stream);
                    break;
                default:
                    fputc(*p, stream);
            }
        }
        fputc('|', stream);
    }
}
```
# 動かしてみよう
まあ、こんなものです。
```
> (gensym)
#:G1
> (gensym)
#:G2
```
julia言語：複数の配列を一行で宣言

# 前置き
julia言語での話ですが、他の言語でも当てはまるでしょう。
何も考えずに、コードを書いてると次のようなことが起こります。
（備忘録）

↓
複数の変数の定義であれば、
```
a = b = c = d = 0
```
このように初期化しておいて、あとからプログラムの進行に応じて値を書き換えて使うことは自然に行うと思いますが、複数の配列について同じことをすると問題が起こります。具体的には
```julia
x = y = u = v = Array{Float64}(undef, 2, 2)
```
のようにすると、x, y, u, vの配列のいずれかの中身を、書き換えると他の3つも変更されます。

それもそのはず、配列は参照渡し<sup>[1](https://dxsato.hatenablog.com/entry/2020/04/27/123609)</sup>なので当たり前なのですが、
（x, y, u, vというシンボルが、すべて同じインスタンスを参照します）
一瞬「ん？」となりました。

# 解決策
解決策としては、
```julia
x = Array{Float64}(undef, 2, 2)
y = Array{Float64}(undef, 2, 2)
u = Array{Float64}(undef, 2, 2)
v = Array{Float64}(undef, 2, 2)
```
でも良いのですが、冗長すぎてすこし嫌なので
```
x, y, u, v = map(_->Array{Float64}(undef, 2, 2), 1:4)
```
こうします。
★解決！！★（※コメントでご指摘頂いた通り、もっといい方法がありました。→【補足】へ）

ーーー
一つ注意点があります。
mapは配列`Vector{...}`を返すので、
```
x = y = u = v = (map_->Array{Float64}(undef, 2, 2), 1:4)
typeof(x) # 結果：Vector{Matrix{Float64}}
```
つまり、x, y, u, vすべてに、Vector{Matrix{Float64}}のやつがぶち込まれています。なので、きちんと分割代入をするために、カンマを使ってあげましょう。
脳死でプログラムを書いていると間違えるので気をつけないとですね。
ーーー

**【補足】**（追記）
より良い方法をコメントでご指摘頂きました。ありがとうございます！
こちらのほうがスマートですね。
```
x, y, u, v = (similar(arrowmap, Float64) for _=1:4)
```


# 使い道
そもそも、なんでこんなことしたいのか？ですが、
グラフに矢印を描画するときに、4つの配列使いたくなるからです。
以下が例です。
この図のようなタイルの色に応じた矢印を描きたいとしたとき、下記のコードで描くことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724482/b29b3fda-ea94-07c4-57cc-e5328d1ccc3a.png)

```julia
using Plots, MLStyle
n = 4
function generate_arrows(n)
    arrowmap = rand(1:4, n, n)
    return arrowmap
end

function putmap(arrowmap)
    heatmap(arrowmap, legend=false, aspect_ratio=1)
    l = 0.6 # 矢印の長さ
    direction = Array{String}(undef, size(arrowmap)) # これは使ってません
    x, y, u, v = map(_->Array{Float64}(undef, size(arrowmap)), 1:4)
    for i in 1:n
        for j in 1:n
            direction[i, j], x[i, j], y[i, j], u[i, j], v[i, j] = @match arrowmap[i, j] begin
            1 => ("↑", j,     i-l/2, 0.,  l)
            2 => ("→", j-l/2, i,      l, 0.)
            3 => ("↓", j,     i+l/2, 0., -l)
            4 => ("←", j+l/2, i,     -l, 0.)
            end
        end
    end
    quiver!(vec(x), vec(y), quiver=(vec(u), vec(v)), color=:white, lw=4)
    quiver!(vec(x), vec(y), quiver=(vec(u), vec(v)), color=:red, lw=2)
end

arrowmap = generate_arrows(n)
putmap(arrowmap)
```

# 参考文献
- [Julia特有の構文メモ２](https://dxsato.hatenablog.com/entry/2020/04/27/123609)
[Amazon Web Services]AWS re:Invent2024 レポート#0 「参加します！！！！！　」

AWSに出会ってから約1年、、、**AWS re:Invent 2024**に参加できることになりました！！！！！
参加にあたっての事前調査を兼ね、AWS re:Invent 2024をご紹介させていただきます！

## AWS re:Invent 2024 とは
AWS re:Invent 2024とは、一言でいうと、
楽しみながら学べてつながれる、アマゾン ウェブ サービス（AWS）主催のラーニングカンファレンスです。

開催地：**アメリカ ネバダ州 ラスベガス**
開催日程：**2024年12月2日～2024年12月6日**

>AWS re:Invent は、AWS が世界中のクラウド コンピューティング コミュニティ向けに主催する学習カンファレンスです。対面式のイベントでは、基調講演、トレーニングと認定資格の機会、2,000 を超える技術セッションへのアクセス、Expo、営業時間外のイベントなど、さまざまなイベントが開催されます。
日程は2024 年 12 月 2 日から 6 日まで、ネバダ州ラスベガスの複数の会場で開催されます。
https://reinvent.awsevents.com/faqs/?trk=qiita.com

## セッション
学習型カンファレンスということで、AWS re:Inventでは様々な形式の学習・情報共有の機会（セッション）が提供されます。
セッションには下記の14種類があり、Topic、Industry、Area of Interest、Level、Roleなどの観点から参加するセッションを選択することができます。
https://reinvent.awsevents.com/experience/session-content/?trk=qiita.com
https://registration.awsevents.com/flow/awsevents/reinvent24/public/page/catalog

- Keynote
- Innovation Talks
- Bootcamp
- Breakout session
- Builders' session
- Chalk talk
- Code talk
- Community activities
- Dev chat
- Exam Prep
- Gamified learning
- Interactive training
- Lightning talk
- Workshop

## Expo（博覧会）
セッションだけでなく、AWS re:InventではExpo（博覧会）が開催されており、
最新のイノベーションに触れ、日々の学習や業務では得られない想像力を養うことができます。
https://reinvent.awsevents.com/experience/expo/?trk=qiita.com

最近話題の生成AIアプリ開発サービスAmazon Bedrockをはじめ、AWSを使ってどんな課題解決が行われているのかを学び、今後の活動に生かしたいと思います。


- AWS Village
- Builders’ Fair
- AWS Marketplace
- AWS Marketplace
- Community Developer Lounge
- Lightning theaters

## Community（More than just learning 学習以上のもの）
AWS re:Invent は技術スキルの向上だけにとどまりまらず、新しい友人や同僚と出会う場が提供され、
個人またはグループで様々なアクティビティイベントに参加しながら楽しい時間を過ごすことができます。
例えば、5kmのランニングレースやビンゴ、ヨガクラスが開催されるようで、私はぜひランニングレースに参加してみたいと思います！！

## re:Play (仲間とくつろぐクロージングパーティー）
1週間にわたるハードワークを祝って、
最終日前日の 2024年12月5日 にはクロージング パーティーである re:Play が開催されます。

###### 食べて、飲んで、パーティーして、くつろいで
ライブミュージックや美味しい食事、ドッジボールやボタンマッシュなどのアクティビティで最後の夜を祝います。
文字だけでは伝えきれない「とんでもないわくわく感」がAWS re:Invent公式ページに動画・画像形式で掲載されているので、ぜひ一度ご覧いただければと思います！
https://reinvent.awsevents.com/experience/replay/?trk=qiita.com

## 最後に
これ以上ない大変貴重な機会をいただいた認識です。
より多くのものを吸収することができるように準備したいと思います。
個人的によく使いそうな Vim コマンド

# 編集モード時

## 行内移動

|動作|コマンド|
|:-:|:-:|
|空白で区切られた次単語の先頭に移動|W|
|空白で区切られた次単語の末尾に移動|E|
|空白で区切られた前単語の先頭に移動|B|
|行末に移動|$|
|行頭に移動|^|

## 行間移動

|動作|コマンド|
|:-:|:-:|
|ファイル1行目の先頭に移動|gg|
|ファイル末行の先頭に移動|G|
|任意行に移動|NG（※Nは数字）|

## コピー＆ペースト

|動作|コマンド|
|:-:|:-:|
|行コピー|yy|
|N単語コピー|Nyw（※Nは数字）|
|行下に貼り付け|p|
|行上に貼り付け|P|

## 削除

|動作|コマンド|
|:-:|:-:|
|1文字削除|x|
|単語削除|dw or dW|
|行削除|dd|

# ノーマルモード時

## 編集モードへの切り替え

|動作|コマンド|
|:-:|:-:|
|現在位置で編集モード|i|
|行頭に移動して編集モード|I|
|現在位置の一つ後ろで編集モード|a|
|行末に移動して編集モード|A|
|行下に一行挿入して編集モード|o|
|行上に一行挿入して編集モード|O|

## redo / undo

|動作|コマンド|
|:-:|:-:|
|undo|u|
|redo|cntr+r|

## 行番号の表示 / 非表示

|動作|コマンド|
|:-:|:-:|
|行番号を表示|:set number|
|行番号を非表示|:set nonumber|

## 任意文字列を検索

|動作|コマンド|
|:-:|:-:|
|文字列検索|/word（※wordは文字列）|
|検索結果を進む|n|
|検索結果を戻る|N|

## ウィンドウ分割

|動作|コマンド|
|:-:|:-:|
|新しいファイルを縦並びに分割|:new|
|新しいファイルを横並びに分割|:vnew|
|現在のファイルを縦並びに分割|:split|
|現在のファイルを横並びに分割|:vsplit|

## タブ追加 / 移動 / 削除

|動作|コマンド|
|:-:|:-:|
|新しいタブを追加|:tabnew|
|ファイルを別タブで開く|:tabnew path（※pathはファイルパス）|
|N番目のタブに移動|:tabnN（※Nは数字）|
|右隣のタブに移動|:tabn+|
|左隣のタブに移動|:tabn-|
|タブを削除|:tabclose|
|N番目のタブを削除|:tabcloseN（※Nは数字）
|カレントタブ以外を削除|:tabonly|


## その他

|動作|コマンド|
|:-:|:-:|
|バッファ一覧表示|:ls|
Ruby on RailsでSidekiqを使ったバックグラウンドメール送信の設定方法 | Redis活用ガイド

## 背景
個人開発で、ある機能を実装していた際に、一度に約40通のメールを送信する必要がありました。通常のコントローラーでメール送信を処理すると、すべてのメール送信が完了するまでリクエストが処理され続けるため、時間がかかりすぎるという問題に直面しました。このため、ユーザーへのレスポンスを早くするためにも、メール送信をバックグラウンドで行う必要がありました。

## Redisとは
Redis は、高速で軽量なデータベースとして動作するインメモリ型のデータ構造ストアです。ジョブキューの管理にも利用され、リアルタイムアプリケーションやキャッシュとして広く使われています。Sidekiq のようなバックグラウンドジョブ処理システムのキュー管理にも使用され、ジョブの順序管理やステータスを効率的に処理します。

## Sidekiqとは
Sidekiq は、Ruby on Rails アプリケーションのバックグラウンドジョブを処理するためのツールです。ジョブを並列処理できるため、メール送信やファイル処理などの重いタスクを別のスレッドで非同期に実行し、パフォーマンスを向上させることができます。バックエンドとしてRedisを使用し、スムーズにジョブ管理が行えます。

## 設定手順

### ステップ１
Gemfileに sidekiq を追加し、インストール

```
gem 'sidekiq'
```
インストール後、bundle install を実行します。

### ステップ2
ActiveJobの設定を開発環境に追加 config/environments/development.rb に以下の設定を追加します。

```
config.active_job.queue_adapter = :sidekiq
```

### ステップ3
メール送信のバックグラウンド設定 メール送信箇所で deliver_now を deliver_later に変更します。

```
User.enabled.find_each do |user|
  EventMailer.participation(user, @event).deliver_later
end
```

### ステップ4
Redisサーバーの起動 Sidekiq は Redis を利用するため、以下のコマンドで Redis サーバーを起動します。

```
redis-server
```

### ステップ5
Redis CLIで接続確認 redis-cli コマンドを使用して、Redisが正しく起動しているか確認できます。

```
redis-cli
```

### ステップ6
Sidekiqの起動 Sidekiq を起動するため、以下のコマンドを実行します。
```
bundle exec sidekiq
```
バックグラウンドジョブが正常に実行されるか確認 Sidekiq のログやWebインターフェース（localhost:3000/sidekiq）でジョブの処理状況を確認できます。

## まとめ
バックグラウンドでメールを送信することで、処理時間を大幅に短縮し、ユーザーへのレスポンスが速くなります。ActiveJob と Sidekiq の設定は簡単で、メール送信の負荷が大きいアプリケーションでもスムーズに動作します。
WSLのimportが終わらなかった

タイトルの通り。
WSLでRHELを使ってみようと思ったら```wsl --import```が待てど暮らせど終わらなかった話

# 結論
Windowsの機能からLinux用Windowsサブシステムを有効にしたらいけた。

# 詳細
WSLを使ったことがない私がWSLにRHELをインストールするまでを書く。
未来の私のための備忘録。
結論は既に出てるので解決した人はブラウザバックでいいよ。

## 環境
Windows11

## やりたかったこと
WSLを入れる。
WSLのインストールは簡単でマイクロソフトの公式ドキュメントを参照すれば即入る。
https://learn.microsoft.com/ja-jp/windows/wsl/install
```wsl install```を実行するとインストールされるディストリビューションはUbuntuだ。
また、WSLで使用できるディストリビューションのうち、ダウンロード可能なものは```wsl --list --online```から参照できる。
```
PS C:\Users\purimena> wsl --list --online
インストールできる有効なディストリビューションの一覧を次に示します。
'wsl.exe --install <Distro>' を使用してインストールします。

NAME                            FRIENDLY NAME
Ubuntu                          Ubuntu
Debian                          Debian GNU/Linux
kali-linux                      Kali Linux Rolling
Ubuntu-18.04                    Ubuntu 18.04 LTS
Ubuntu-20.04                    Ubuntu 20.04 LTS
Ubuntu-22.04                    Ubuntu 22.04 LTS
Ubuntu-24.04                    Ubuntu 24.04 LTS
OracleLinux_7_9                 Oracle Linux 7.9
OracleLinux_8_7                 Oracle Linux 8.7
OracleLinux_9_1                 Oracle Linux 9.1
openSUSE-Leap-15.6              openSUSE Leap 15.6
SUSE-Linux-Enterprise-15-SP5    SUSE Linux Enterprise 15 SP5
SUSE-Linux-Enterprise-15-SP6    SUSE Linux Enterprise 15 SP6
openSUSE-Tumbleweed             openSUSE Tumbleweed
PS C:\Users\purimena>
```
しかし私はRHELを使用したかった。
見てもらえれば分かるがRHELはない。
当たり前と言えば当たり前な話だが。

## WSL用のRHELを用意する。
Red Hatの公式ブログにRHELのWSL用イメージ作成手順が記載されている。
https://developers.redhat.com/articles/2023/11/15/create-customized-rhel-images-wsl-environment
何が素晴らしいってHybrid Cloud Consoleからイメージを作成すると、イメージ作成に使用したRed Hatアカウントのサブスク情報が紐づいたイメージが作成されるところだ。
わざわざサブスクマネージャーから登録する必要なくdnfが使える。

## イメージをWSLにインポートする
ここで躓いた。
ブログのタイトルにしている問題はここだ。
先に作成したイメージをWSLにインポートするために下記のコマンドを実行した。
```wsl --import RHEL9 . "<image_path>"```
すると画面上に
```
インポート中です。この処理には数分かかることがあります。
```
と表示されるのだが一向に終わらない。
記憶が確かなら3,4時間は待ったと思う。

### 解決法
冒頭でも書いたが
```スタートメニュー->「Windowsの機能」と入力し「Windowsの機能の有効化または無効化」を開く-> 「Linux用 Windowsサブシステム」にチェック```
で終わり。
そもそもLinux用サブシステムが有効化されていないという凡ミス。
### 疑問
私が上記のチェックが入っているか確認が遅れた理由としては、```wsl --install```を実行してインストールされたUbuntuは起動できていた点だ。
なんでUbuntu君は起動できたんすかね…

## 無事インポート
上記の作業後もう一度インポートを試みると数秒でインポートが完了した。
```
$ cat /etc/redhat-release 
Red Hat Enterprise Linux release 9.4 (Plow)
```
無事WSLにRHELをインストールできた。

## 終わり
初歩的なミスで詰まったが未来の俺は同じミスをしでかす自信があるので残した。
感謝しろ未来の俺。
【Swift】メモ


## 同期処理　非同期処理
**同期処理**とは、<font color="orange">順番に処理を実行する</font>ことです。
**１→２→３**
１が終わったら２を実行、２が終わったら３を実行のように一つのミッションが終わるまで、次のミッションをやることはできません。
また、２を飛ばして３をやることはできず、決めた順番に従って実行されます。
エラーが出た場合は対処はしやすいですが、同時に実行することができません。

**非同期処理**とは、<font color="orange">複数の処理を同時に行うことができる</font>ことです。
ある処理を実行中に同時に別の処理を実行できます。

## インクリメント
何かの数字に<font color="orange">+1</font>をすること

## デクリメント
何かの数字から<font color="orange">-1</font>すること
【個人メモ】便利SOQL

## 組織情報
### 使用中のライセンス一覧
```
select Id, Name, UsedLicenses, TotalLicenses, Status, LicenseDefinitionKey from UserLicense Order by Status

```

### ユーザーに割り当て済みのプロファイル名とライセンス一覧
```
Select Name, IsActive, Profile.Name, Profile.UserLicense.Name, Profile.UserLicense.LicenseDefinitionKey, Profile.UserLicense.TotalLicenses, Profile.UserLicense.UsedLicenses, Profile.UserLicense.status 
From User 
Order BY Profile.Name DESC
```
Next.js(App Router)のレンダリングについて理解を深める

# 🪩 はじめに
Next.jsを一通り学習したので復習としてレンダリングの種類について書いていきます．自身の理解で書いているのでもし間違っている箇所があれば指摘してください🙇‍♂️

# 🪩 自己紹介
初めまして．趣味でweb開発を勉強している273*(ﾂﾅｻﾝﾄﾞ) / Kei.と申します．関西の大学生です．最近はフルスタック開発やツール制作を行なっています．まだまだ初心者です．

# 🪩 本題

### CSR（Client Side Rendering）
CSRを設定すると，リクエストに対してサーバーからHTMLとJavaScriptが返され，ブラウザ上でJavaScriptが実行されて，実際に表示するHTMLをレンダリングします．ページ遷移が高速ですが，初回読み込み時に全部のデータを取得するので最初だけ表示が遅くなります．端末のスペックに依存します．Reactは標準でCSRです．ファイルの先頭に```use client```ディレクティブを設定するだけでCSRになります．SPAとも言われます．使いどきは動的なやり取りや常に更新したりするサイトに使います．
※CSRの中にSSRやSSGなどを入れてもCSRとして扱われるので注意．SSRの中に入れるのがおすすめです．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3530539/68acfa4f-02c7-7f0b-6874-84dafae764c5.png)


### SSR（Server Side Rendering）
SSRを設定すると，リクエストに対してサーバー側でJavaScriptを実行して表示するHTMLをレンダリングします．生成したHTMLをクライアントに返して表示します．CSRと比較し，クライアントはHTMLを表示するだけなので端末のスペックに依存しません．よってどのユーザも安定した速度で表示ができます．あらかじめHTMLが生成されているのでSEOにも強いのが特徴です．fetch関数の第二引数にcache: ```no-store```を記述することで使用できます．```useEffect```や```useState```などは使用できません．```onClick```とかもブラウザ依存なのでダメだったはず．ブログやコーポレートサイトなどに向いている．ReactのフレームワークであるRemixはSSRを採用しています．

### SSG（Static Site Generation）
SSGを設定すると，アプリのビルド時に静的ページを生成してサーバーに保管されます．リクエストがあった時にそれを返すだけなので，4つのレンダリングの中で最も高速で表示されます．データの更新が入った際は手動でビルドしなければならないので，静的サイト以外ではデメリットになる．fetch関数の第二引数にcache: ```force-cache```を記述することで使用できます．Next.jsはデフォルトでSSGが設定されてるので省略もできます．これも```useEffect```などは使えないです．

### ISR（Incremental Statice Regeneration）
SSGの欠点(手動でビルドしないといけない)を解決したレンダリングの方法．SSR x SSGみたいな．ビルド時に静的ページを生成してサーバーに保管して，リクエストを返すのはSSGと同様．ISRでは指定した時間が経過したら自動で再ビルドを実行することができます．その関係で，常に最新の状態を保つことが難しく，データの更新が入るとビルドの後にページを手動でロードしないと最新の表示ができません．表示は最速です．fetch関数の第二引数に```next: { revalidate: 60 }```(revalidateの値は秒数)を記述することで使用できます．vercelでしか使用できなかったはずです．

### PPR (Partial Pre Rendering)
静的レンダリング，動的レンダリング，ストリーミングを同じルートで組み合わせる方法．ページを全体を静的レンダリングに設定し，一部を動的レンダリングにする．SSG・ISRのページの一部にSSRな部分を組み合わせられるようなイメージ．ページを読み込む際に，データを取得した後に表示するのではなく，予め静的なエリアを表示しておいて，ローディング画面(loading.tsx：<Suspense>のfallbackとほぼ同義)を表示することが可能．SSR+CSRとはまた違う．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3530539/cff4bcd6-1bc9-bdaa-2352-3c7640de223c.png)


# 🪩 参考文献
- [Building Your Application: Data Fetching | Next.js](https://nextjs.org/docs/pages/building-your-application/data-fetching)
- https://nextjs.org/learn/dashboard-app/streaming
- https://nextjs.org/learn/dashboard-app/partial-prerendering
- https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming

# 🪩 最後に
Next.jsのレンダリングについて振り返りができるようにまとめてみました．誰かの参考になれば幸いです！最後まで読んでいただきありがとうございました．それでは！
資格勉強をやってみて感じたメリット

## 軽く自己紹介

私は文系異業種から独学でエンジニアに転身したものです。
これまで特にIT関係の資格は持っておらず、恥ずかしながら無免許エンジニアをやらせてもらってそろそろ3年近くになります。

ただ頑張ってキャッチアップしたり日々コツコツと学習を続けているおかげか、
これまで参画したプロジェクトでは評価も悪くなく、少しずつですがエンジニアとして成長できている実感があります。

そういうこともあり、
**「資格なんて時間の無駄だし仕事できれば別にいらないだろう」**
という考えを持っていました。

実際資格を持ってなくてもすごいエンジニアは何人も知っています。

しかし、食わず嫌いな状況も良くないだろうと考えが変わり、
とりあえず基本的な資格は取ってみようと資格勉強へ取り組むことを決意しました。
（無駄だと思ったらやめれば良いですし）

## 状況

現在、並行して以下の資格勉強を行なっています。

* 基本情報技術者
* ~~クラウドプラクティショナー（24年8月に取得済）~~
* ソリューションアーキテクト

会社でAWSを触る機会が増えてきたのと、面白そうだという興味本位でAWSの資格を取ろうと思っています。

基本情報に関しては**エンジニアとして最低限必要**、ということはよく耳にするのでそれならばと勉強しています。

もちろん応用まで狙っています。

## 資格勉強をする上での自分なりのポリシー

無駄だと思ったらやめれば良いとは思いつつ、
何かしらポリシーを持って考えて勉強しないと本当に無駄な時間になるので自分なりに約束事は決めました。

* **合格するためだけの勉強にしない**
* **実際に手を動かす**（特にAWS）

これだけは守ろうと意識しています。

**目的はエンジニアとしてしっかりとした知識を身につけ成長することで、
あくまで資格はその手段でしかないからです。**

なので試験範囲だけ勉強するということはせず、
わからない概念や単語などが出てきたら派生する形で試験範囲関係なくキャッチアップをしています。

## 資格勉強のメリット

では実際に感じたメリットについてお話しします。

* ミーティングなどで話されている内容の理解度が高まった
* AWSのサービスを触る際、自分が今何をしているかという解像度が上がった
* 不具合が発生した時に原因を切り分ける観点が増えた

他にもあったら追記しようと思いますが、パッと思いついたところではこんな感じです。

> ミーティングなどで話されている内容の理解度が高まった

まず、知識が増えたことで「調べる」という一手間がなくなり、仕事のスピードが上がった感覚があります。

チャットなどの非同期コミュニケーションにおいては別に大きな弊害にはならないかもしれませんが、
ミーティングなどの同期コミュニケーションにおいては分からないことをその場で都度調べていては置いていかれます。

その場その場でちゃんと話についていけることが、どれだけその後の仕事のスピードや質を上げるのか実感できました。

> AWSのサービスを触る際、自分が今何をしているかという解像度が上がった

また、実際にやっていることの解像度が上がったことで自分がやっていることに自信が持てるようになりました。

特に、AWSのサービスを理解する上で基本情報の内容が理解の助けになるという場面が多々ありました。
（「あ、ここ進研⚪︎ミでやったところだ！」状態）

> 不具合が発生した時に原因を切り分ける観点が増えた

さらに、今までブラックボックス状態だったところが見えてくることで、
何か不具合が発生した時に原因の切り分けがしやすくなりました。

これは想像しやすいかと思います。

---

元々文系出身だったこともありそもそもの体系的な知識が足りていないことがこのように感じる要因だったのだろうと思いますが、
資格勉強をすることで満遍なく必要な知識が手に入り、それが多方面で助けになっていると実感しました。

## まとめ

資格勉強、思った以上に良い。
正直メリットしか感じず勉強にハマっています。

まだ言語化できてない部分もありうまくお伝えできないのですが、
同じように異業種から転身した方や現場でキャッチアップしてきた方は同じ感覚を覚えやすいのではないかと思います。

## あとがき

ぶっちゃけ会社の福利厚生の制度がありがたすぎる。

書籍購入補助があるので資格対策の本が入手しやすいですし、
受験補助もあるため合格したら自己負担なしという状況です。

このまま継続して頑張っていきたいと思います！！
Jira Automationでブランチを使って子課題のステータスが変更された時に親課題のステータスを自動変更する方法

# これはなに？
Jiraを使ってタスク管理をしていると、
**「子課題のステータスだけ変えて、親課題のステータス更新を忘れていた......」**
**「ストーリーやサブタスクが多すぎて、ステータス全部変えるの大変......」**
ということ、ありませんか？

それをAutomationで解決する方法について書いている備忘録になります。

# 結論

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452658/ee233e5b-1333-8ef6-c329-ec56f9521598.png)

Automationの設定としてはこのようになります。
この例では、子課題のステータスが「対応中」に変わったら、親課題も「対応中」へ変わるようになっています。

JQLは使いません。かなりシンプルですね。

# 自動化の設定詳細

トリガーやIF条件はそのままなので説明を割愛します。
ここではポイントとなる「ブランチ」コンポーネントとルール詳細の設定について記載します。

## ブランチ（分岐）

https://support.atlassian.com/ja/cloud-automation/docs/jira-automation-branches/

JiraのAutomationにおけるメインルートのルールでは、トリガーした課題に対して処理が実行されますが、
トリガーした課題とは別の課題を操作したい場合は、このブランチコンポーネントを使って設定を行います。

### ブランチでどのような課題を対象にできるか

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452658/9cb80f10-bb15-b7f9-0779-7f5bae2930c9.png)

2024年9月現在、関連課題のタイプとしては下記項目が選べます。

- **現在の課題**
- **親**
- **子**
- **サブタスク**
- **ストーリー（またはエピックの他の課題）**
- **エピック**
- **作成されたすべての課題**
- **最も最近に作成された課題**
- **リンクされた課題**
- **ターゲットの課題**
- **JQL**
- **バージョンで修正された課題**
- **スプリントの課題**
- **類似する課題の説明**

今回はブランチルール内で親を対象に操作していましたが、対象が上記のように色々と選べるので、下記のようなこともできそうですね。

- 親課題が完了したら子課題もすべて完了ステータスに変わる
- 課題が完了したら、その課題に関連している課題を次スプリントにセットする
- スプリント終了の〇日前になったら、スプリントバックログで未対応になっている課題にアサインされているメンバーにメンション付きコメントを飛ばす

### ブランチの制限

ブランチコンポーネントで分岐させたルール内では、いくつか制限事項があります。

- **入れ子**
    - あるブランチを別のブランチの中に入れることはできません
- **If/else条件**
    - If/elseブロック条件をブランチ内で使用することはできません
    - 結論に書いたフローのように、他のIF条件コンポーネントは使用可能
- **独立**
    - ブランチで生じた変更は、メインルールやその他のブランチからは確認できません
    - たとえば、ブランチに [変数を作成] アクションがある場合は、作成したスマートバリューは同じブランチでは使用できますがメインルールや他のブランチでは使用できません


## ルール詳細でAutomationのアクションによるトリガーを許可する

結論に書いたルールを例にすると、ただルール部分を設定しただけでは下記のような状態になってしまいます。
- サブタスクのステータス変更時にその親のストーリーは自動でステータス変更される
- しかし、そのストーリーの親となるエピックまでは自動変更がされない

**Automationによって変更されたアクションもトリガーの対象としたい**場合は、ルール詳細で下記のチェックを入れる必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452658/5921f180-f5e5-c2f7-fcf5-35a1866727fb.png)

このチェックを入れると、Automationによるアクション時でもトリガーとして機能し、自動化ルールが動くようになります。
Railway CLIでRails開発中にDatabase 'railway' does not exist

# はじめに
Herokuまわりのゴタゴタがあって、個人開発はRailwayを使うようになったのですが、ちょっと困ったことがあり、自分用メモとして残しておきます

# db:migrate:resetができない？
開発の初期って、DBの設計が決まっていなくて、実装していくうちに、あ、あれ足りなかったな。
ということは多いでしょう。

そんなとき、結構気軽にマイグレーションを一からやり直すコマンド

```
rake db:migrate:reset
```

をしたらいいか！くらいのノリで個人開発をやっているのですが、ちょっと問題が発生しました。

```
 % railway run rake db:migrate:reset
Database 'railway' does not exist
We could not find your database: postgres. Which can be found in the database configuration file located at config/database.yml.

To resolve this issue:

- Did you create the database for this app, or delete it? You may need to create your database.
- Has the database name changed? Check your database.yml config has the correct database name.

To create your database, run:

        bin/rails db:create
Couldn't create 'railway' database. Please check your configuration.
rake aborted!
ActiveRecord::NoDatabaseError: We could not find your database: postgres. Which can be found in the database configuration file located at config/database.yml.

To resolve this issue:

- Did you create the database for this app, or delete it? You may need to create your database.
- Has the database name changed? Check your database.yml config has the correct database name.

To create your database, run:

        bin/rails db:create


Caused by:
PG::ConnectionBad: could not translate host name "postgres.railway.internal" to address: nodename nor servname provided, or not known
```

DBがないとは、、、いや、あるが？？

そんなつまづくとこだっけ？と思って調べてると公式のQAのやり取りが

https://help.railway.app/questions/suddenly-can-t-connect-privately-using-p-0f1537ab

なにやら、「DATABASE_URLにtimeoutまでの時間を設定して3秒待たせてみる」とか、「ENABLE_ALPINE_PRIVATE_NETWORKING=true」の環境変数を設定するとか、
いろいろとTipsがあるようでしたが、どれもうまくいきませんでした。

# はずかしながら回避策
真正面からの解決策ではないのですが、とりあえず、なんとか実行できた方法が以下です。
Railwayにデプロイされた際に実行させるProcfileのマイグレーションは問題なく実行されていたので、一時的にそこで実行しました

```bash:Procfile
web: rake db:migrate && bin/rails server -b 0.0.0.0 -p ${PORT:-3000}
```

を以下に変更

```bash:Procfile
web: rake rake db:migrate:reset && bin/rails server -b 0.0.0.0 -p ${PORT:-3000}
```

**もちろん、ことが終わったら戻しましょう！デプロイのたびにDBが初期化されます！**

釈然としないですが、とりあえずこれで回避できたので備忘録として。
staticについて【初級編】

# staticとインスタンスの役割
### static
* staticプロパティ(変数)とメソッド(関数)はクラスに関連付けられており、インスタンスではなくクラス自体に属します。
* クラス名を使ってアクセスすることが求められます。
* インスタンスからはアクセスできない。
* staticプロパティ(変数)は**クラスの全体で共有される**ため、すべてのインスタンスが**同じ値を参照**します。
* staticメソッド(関数)はクラスの機能として提供されます。


#### インスタンス
* インスタンスプロパティ(変数)は各インスタンスごとに異なる値を持ちます。

# 具体的なコードで解説
```
class StaticMembers {
    // static プロパティ
    static stNum: number = 0;

    // インスタンスプロパティ
    num: number = 0;

    // static メソッド
    static countUp(value: number) {
        StaticMembers.stNum += value;
    }
    
    // インスタンスメソッド
    countUp(value: number) {
        StaticMembers.stNum += value;
        this.num += value;
    }
}

// インスタンスを2つ作成
const staticA = new StaticMembers(); // (1)
const staticB = new StaticMembers(); // (1)

// AのcountUp()を引数10で実行
staticA.countUp(10); 

// Aのプロパティをそれぞれ出力
console.log(`staticAのstNum: ${StaticMembers.stNum} num: ${staticA.num}`); 
// 出力する値: staticAのstNum: 10 num: 10

// BのcountUp()を引数5で実行
staticB.countUp(5); 

// Bのプロパティをそれぞれ出力
console.log(`staticBのstNum: ${StaticMembers.stNum} num: ${staticB.num}`); 
// 出力する値: staticAのstNum: 15 num: 5

// StaticMembersのstaticプロパティのみ出力
console.log(`stNum: ${StaticMembers.stNum}`); 
// 出力する値: 15

```
# 参考URL
https://wa3.i-3-i.info/word1118.html

https://atmarkit.itmedia.co.jp/ait/articles/1803/20/news005.html
業務内容に比べて年収の下限が低い求人がもたらすもの

業務内容や要求する技術水準が高いのに、年収の下限の値が低すぎると感じさせる求人がある。
それは求人上得策ではないことを伝えたい。

## 推測する状況
- その能力を満たす新卒が見つかったときに、その低い側の給与水準にしたい。
- 中途採用での前職の給与水準から、金額を積み増ししなくても応募してくれるならば、低めの金額にして要相談としておこうとなるのだろう。
- あるいは、スタートアップで、まだ利益がないので、賃金を抑制しなくちゃならない。
そういう理由のため、業務内容に比べて年収の下限が低い求人条件となるだろうと思う。

## その分野の専門能力を持つ人が、必須条件をみて判断するしたとき
- 「十分な能力を持つ院卒の学生が入社しても、他のふつうの学生と同じ待遇しかしないんだろうな」
- 「入社年度の先輩・後輩を意識したチーム運営をするんだろうな。」
- 「そうすると、その分野の専門知識があっても、先輩をたてるやりかたをするんだろうな」
- 「そして、昇給はそんなに期待できないだろうな」
専門性を評価してもらえなんだなあ。
中途採用だったら、〇〇◯の年収なのに、新卒だと安いんだからやってらねないよ。
さっさと経験積んだら、転職するのが良さそうだ。

という判断を招き寄せていないだろうか。

## 会社によっては、新卒でも高い年収水準
### 事例１
![Screenshot from 2024-09-07 09-58-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83761/c7e5e50d-c6aa-f16f-22d3-660f4995200a.png)
新卒エンジニア職の「給与 500万円以上」(残業代の有無は不明)

カンファレンスでの発表経験とあるので、その分野での専門性と能力を見ている。

### 事例２
![Screenshot from 2024-09-07 10-14-52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83761/282e8df8-2229-d1fb-2c85-2fedf575f732.png)

これは、また別の会社の新卒の条件だ。

伸びている技術分野で、人こそが重要であることをわかっている会社での採用条件だ。

## 会社によっては、新卒・中途採用の区別のない求人
採用のための条件が厳しいが、採用後の年収は６００万円以上になっていたりする。

新卒だから、入社したあとに、半年の研修をして配属などという時代とは変わっている。
こういう分野で採用されたければ、学部や大学院での研究内容を選ぶ必要がある。



## 何が起こっていると推測するか
### その技術分野での新卒の院生
- 専門性を考慮しない一括採用の大企業は、就職先の候補から外している。
#### 想定している採用後の状況（一括採用の大企業）：
- 目的の分野に配属されるとは限らない。
- 配属先にいる人も、その分野のこと知らなすぎる。
- でも権限だけは持っていて、自分たちに任してくれない。
- 成果出しても、昇給幅の上限は決まっているから、いつまで立っても給料の水準は上がらない。
- 数年後の自分の未来を描けなくなる。

### 想定している採用後の状況（機械学習分野の求人の特化型の採用の場合）
- まず、新卒の院生でも、優秀な開発のできる人を見抜こうとしている。
- 開発の中身が魅力的である。
- 組織は、その技術分野がわかる人にあふれていて、技術的な話題が楽しい。
- 組織運営は比較的フラット（あるいはとてもフラット）である。
- 事業としての成功はこれからだが、力いっぱいやるだけのことをやればいい。


## 「大学での研究なんて大したことない」
「大学での研究なんて大したことない」とか偉そうに言っている人は、それ以上の成果をあげているだろうか。
レベルの高い研究をしている人たちが**いる**ことを知ったうえで言っているだろうか。
あなたの事業分野で、その成果がそのまま役立たないのは、しかたがない。
ちゃんとしたデータとの向き合い方をしたうえで、
研究をやり遂げ、開発をやり遂げられる人間になるには
どれだけ努力が必要かわかるだろう。

## 必要なのは、抱える課題を一緒に解決していく方法を見つけること
人を採用するときは、抱える課題を一緒に解決していく方法を、その人と一緒に見つけられるかということが一番の課題である。
そのためには、なぜ人を中途採用しようと考えるのか
何を一緒になって取り組んでもらいたいのか
それを伝え、応募者が、それに対する自分が何ができそうかを伝えてすり合わせていくものである。

## まとめ
- 採用活動を行なっている方々は、その採用での下限の年収を上げるように、社内で提案してくださることを希望します。
- そうすれば、能力の高い人が集まりやすくなると私は考えています。