OmniAICreator/Qiita-1.07M huggingface dataset:
「漏れのある抽象化の法則」要約

## はじめに

Joel Spolskyさんの記事[「漏れのある抽象化の法則」](https://web.archive.org/web/20190713175331/https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/)を要約したのでシェアします。

## 結論

抽象化されたものは便利だけど、使う時は仕組みを知ってから使おう。

## 抽象化とは

>TCP. It is what computer scientists like to call an abstraction: a simplification of something much more complicated that is going on under the covers.
→TCPは、コンピュータ科学者が「抽象化」と呼ぶもので、もっと複雑なことを単純化し、その下で行われています。

ざっくりいうと以下の意味かと思います。

- 中で行っている「複雑なこと」を、外からは単純な方法で使えるようにすること
    - 外からは「複雑なこと」を**どのように実現しているか**は見えない
- 単純化されてるおかげで、本来気にしなくちゃいけないことも意識せず行えて便利

## 抽象化の漏れとは

上述の抽象化に漏れがあること。  

これにより抽象化されたものだけじゃ問題に対処できなくなってしまう。

車の例が分かりやすかったです。

>your car has windshield wipers and headlights and a roof and a heater, all of which protect you from caring about the fact that it’s raining (they abstract away the weather), but lo, you have to worry about hydroplaning (or aquaplaning in England) and sometimes the rain is so strong you can’t see very far ahead so you go slower in the rain, because the weather can never be completely abstracted away, because of the law of leaky abstractions.  
→車にはワイパーも ヘッドライトも 屋根も ヒーターもついていて 雨が降っていることを気にしなくて済むようになっています （天候を抽象化しています） しかし、ハイドロプレーニング（イギリスでは アクアプレーニング）を心配しなければなりません 時には雨が強くて前がよく見えないので 雨では速度を落とします なぜなら天候は抽象化の漏れという法則により 完全に排除することができないためです。

## 抽象化の仕組みを理解して使おう

この記事では抽象化されたものをただ使うのではなく、
仕組みを理解して使うことが推奨されています。

抽象化されたものを思考停止して使っていると、
**問題（抽象化の漏れ）が起きた時に対処できなくなる**からですね。

問題というのは中で行っている「複雑なこと」のどこかのステップがコケてるということなので、
**中で何が起きているのか知らないと原因を特定できない**です。

僕は最近プライベートでDockerを触り始めたんですが、まさにこの状態になりました。

とりあえず設定ファイルを見様見真似で書いたはいいものの、依存関係やコンテナ内部の設定に問題が起きた時に、どこをイジればいいのか分からず困ることが多かったです。


もちろん全部の仕組みを網羅するのは厳しいと思います。

最初から全部理解しようとすると、
勉強のハードルが上がったり時間がかかったりするので、「とりあえず手を動かしてみる」というのが必要な場面もあるかと。


ですが初期コストをかけてでも仕組みを理解することで、開発トータルで見ると得するんじゃないかなと改めて感じました。

以下の言葉が本質をついているように思えます。

>So the abstractions save us time working, but they don’t save us time learning.  
  つまり、抽象化によって作業時間は短縮されるが、学習時間は短縮されないのだ。

## 終わりに

「強いエンジニアは仕組みを理解してから手を動かす」
と耳にすることが多かったんですが、その理由が言語化できてよかったです。

本能に逆らって、仕組みの理解から入る習慣を少しずつ実践していこうと思います。

## 参考文献

[「漏れのある抽象化の法則」](https://web.archive.org/web/20190713175331/https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/)
Raspberry Pi で起動と同時にpythonファイルを実行する(Raspberry Pi OSがGUIなしで立ち上がる)。




<br><br><br>

## 私の目的
◆GPIOを利用した「オリジナルなセンサー付きのタブレット端末」を作成したい。
◆マウスもキーボードもない状態で使用したいので。RasPiを立ち上げるとOSを一切操作せず、
GUIなアプリケーション一つだけ使いたい。情報KIOSK(キオスク)端末のようなイメージ

<br><br><br><br><br>

参考にさせていただいたURL

[Raspberry Piでプログラムを自動起動する5種類の方法を比較・解説](https://qiita.com/karaage0703/items/ed18f318a1775b28eab4)

<br><br><br>

調べるといくつか情報が出てくるが、私は　/etc/rc.local　や　crontab　といった方法だとうまくいかなかった。私の勉強不足だとは思う。
<br>
autostart　という方法が簡単でうまくいったのでまとめておきたい。

<br><br><br>

<br>

## 概要

<br><br><br>

仕組みは簡単。「OSをGUIなしで立ち上げ、指定したプログラムを自動起動」する機能がそもそも用意されていて、そいつがautostartくんなのだ。

<br><br>
大きく、
特定のディレクトリにautostartというファイルを作る→autostartに起動したい.pyの場所を書き込む→再起動
<br>
だけ。簡単だね。


## 環境
・Raspberry Pi3 B+
・Raspbian 11(bullseye)

<br><br><br>

１．autostartファイル作成。ターミナルに以下。失敗したら、隠しファイルの表示かもしれない。エクスプローラー？ファインダー？上で右クリックから、「隠しファイルの表示」をしておく。
```
sudo nano /home/pi/.config/lxsession/LXDE-pi/autostart
```
<br>
空のautostartがnanoで開く。ここに自動起動したいヤツを記入すると登録されるイメージ。pythonであれば以下。

```
@sudo python3 /home/pi/Public/test.py
```

<br><br><br>
再起動してみよう。指定したプログラムが起動と一緒に立ち上がるはず。OSのGUIは非表示だが、右クリックやショートカットでターミナルを出せるので十分だ。
<br><br><br>

## 解除方法
メンテ、調整で戻したい時があるだろう。単純にautostartファイルを削除する。ターミナルに以下。
<br>
```
sudo rm /home/pi/.config/lxsession/LXDE-pi/autostart
```
<br>
わざわざ記事にするまでもない内容だが、私はここにたどり着くのにいくらか煩わされた。コーディングにリソースを割きたいので、こういった周辺雑務は多少の手間よりシンプルさを優先したい。


<br><br><br><br><br><br>
flatpickrの日本語化

私の環境では以下のソースで動いている。
```sample.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
</head>
<body>
<input type="text" name="myDate" id="myDate">
<script src="https://npmcdn.com/flatpickr/dist/flatpickr.min.js"></script>
<script src="https://npmcdn.com/flatpickr/dist/l10n/ja.js"></script>
<script>
    flatpickr("#myDate", {
        "locale": "ja",
        }
    );
</script>


</body>
</html>
```
【JavaScript関数ドリル】中級編の dropRightWhile関数の実装アウトプット

## dropRightWhile 関数の課題内容

\_. dropRightWhile 関数を自分で実装する課題。
https://lodash.com/docs/4.17.15#dropRightWhile

「課題内容」/「解説動画」/「解答例」を確認したい場合は、以下リンク先のページを参照。
https://js-drills.com/blog/dropRightWhile/

## 課題に取り組む前の状態

- 関数の説明文と例を見たところ、第二引数が関数の場合とそうでない場合があり、解答を見ないと分からないと思った。

## 課題に取り組んだ後の状態

- 動画の最初の説明で、今回は第二引数は関数の場合だけを想定して実装するとあったので、そこで動画視聴は一旦中断して、自分で実装を試みた。なんとか、サンプルの処理結果と同じように処理できるものができた。
- breakを使用するのを忘れたため、今後気をつけたい。

## dropRightWhile 関数の実装コード（答えを見る前）

```javascript
function dropRightWhile(array, predicate) {
  const newArray = [...array];
  for (let i = array.length - 1; i >= 0; i--) {
    // console.log(newArray[i]);

      if (predicate(newArray[i])) {
          newArray.pop();
      } else {
          return newArray;
      }
  }
  return newArray;
}
```

## dropRightWhile 関数の実装コード（答えを見た後）

```javascript
function dropRightWhile(array, predicate) {
  const newArray = [...array];
  for (let i = array.length - 1; i >= 0; i--) {
    // console.log(newArray[i]);

    if (!predicate(newArray[i])) {
      break;
    }
    newArray.pop();
  }
  return newArray;
}

var users = [
  { user: "barney", active: true },
  { user: "fred", active: false },
  { user: "pebbles", active: false },
];
console.log(
  dropRightWhile(users, function (o) {
    return !o.active;
  })
);
```
GitHubでの作業の流れと使うコマンド

## ①リモートから情報取得

### ゼロからの場合（ローカルはまっさらな状態）
`git clone <remote_repo_URI>`

### ローカルもリモートもまっさらな場合
1. GitHubでリモートリポジトリ作成
1. ローカルの作業ディレクトリで`git init` (`add`&`commit`...)
1. `git remote add <remote_name> <remote_repo_URI>`
1. `git branch -M main`
1. `git push -u origin main`（ユーザーネームとパスワードを聞かれる。GitHubマイページ＞Settingsでトークン発行）

### 既に以前のリモートの状態がローカルにある場合
1. `git fetch <リモート名> <ブランチ名>`
2. `git merge <リモート追跡ブランチ名>`

## ②ローカルで作業〜プルリクまで
1. `git checkout -b <ブランチ名>` （ブランチ名はfeature/developなど）
2. 作業進めて　`git add`
3. `git commit`
4. `git push <リモート名> <ブランチ名>`
5. GitHubページ上でプルリクエスト作成

## ③プルリクマージ後
1. GitHubページ上でリモートブランチ削除
1. `git pull`
2. `git fetch --prune`（リモート追跡ブランチ削除）
3. `git branch -d <ブランチ名>`（ローカルブランチ削除）


## 参考
- [Gitで不要なローカル・リモート追跡ブランチを削除するコマンドまとめ](https://www.engilaboo.com/delete-git-branch/)
export default って？

vue を学習していると以下のように書いてくださいと当たり前のように「export default」が使われることがある。

```
<script>
export default({
    data(){
        return{
        }
    },methods:{}
})
</script>
```

export default って　vueの仕様なのかと思って調べてみたら、JavaScriptの仕様でした。
[MDN Export](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/export)
【Python】pythonで毎時0分にtweetするようにしてみた

## 概要
pythonで毎時0分にtweetするようにしてみた。

## 前提条件
Pythonが既にインストールされていること。
tweepyがすでにインストールされていること。
APIキーとアクセスキー、トークンの取得ができていること。
（<a href="https://qiita.com/tamago_pinoko/items/221f5df4db06778bf83b">【Python】pythonでtweetしてみた</a>の続編です。）


## 定期実行関数モジュール（schedule）のインストール
コンソールを開いて下記のコマンドを実行する。

```
pip install schedule
```

## tweetプログラムに定期実行処理を追加
tweetプログラムにschedule関数を追加して毎時0分に実行できるようにする。

実際に実行したプログラムは下記になります。
```py
import tweepy
import schedule
from time import sleep
import datetime

# Twitter Deverloper Portalで取得
ck = 'xxxxxxxxxxxx'
cs = 'xxxxxxxxxxxx'
at = 'xxxxxxxxxxxx'
ats = 'xxxxxxxxxxxx'

client = tweepy.Client(consumer_key=ck, consumer_secret=cs, access_token=at, access_token_secret=ats)

#01 定期実行する関数を準備
def tweet():
    dt_now = datetime.datetime.now()
    client.create_tweet(text="時報：只今" + dt_now.strftime('%H時です。'))

#02 スケジュール登録
schedule.every().hour.at(":00").do(tweet)

#03 イベント実行
while True:
    schedule.run_pending()
    sleep(1)
```

処理の内容は下記になります。
schedule.run_pending()でschedule.every()を呼び出し
schedule.every()の条件に当てはまればtweet()を呼び出して実行
sleep()で1秒待機（カッコ内は秒数）

schedule.every()の実行条件の詳細は下記URLに記載されてます。
https://di-acc2.com/programming/python/4574/#index_id4

## 実行結果

実行した結果は以下のようになります。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2056482/951d4c08-2afe-6a2f-d45b-7ddebe35ec7f.png)

## 余談
来月のBUMPのライブが楽しみです。
Delta Live TablesのUDFに複数カラムを渡して処理を行う

こちらで紹介したように、Delta Live Tables(DLT)ではUDF(User Defined Function:ユーザー定義関数)を活用することで、処理をモジュール化することができます。

https://qiita.com/taka_yayoi/items/123347aa8323b4a90730

前回紹介したのは、integerを引数として渡すシンプルなUDFでしたが、ケースによっては以下のようにテーブルの全てのカラムを渡して処理を行いたいというケースがあるかと思います。

```py:Python
@dlt.table
def silver_data():
  return (
    spark.sql("SELECT *, makeColSum(*) AS sumResult FROM live.bronze_data")
  )
```

現状、私が調べた範囲ではこちらのUDFに配列を渡すことができないので、以降で説明する、ある意味泥臭いやり方を取る必要があります。ただ、列数が変動しても柔軟に処理を行えるというメリットがあります。

こちらのアプローチは、`列のすべての値を文字列結合してUDFに渡して、UDF側で値に分離して処理を行う`というものです。

# 呼び出し側の準備

まず、ダミーデータを準備します。

```py:dlt-python-caller
@dlt.table
def bronze_data():
  return spark.sql("SELECT id AS id, rand() * 100 AS col1, rand() * 100 AS col2 FROM RANGE(10)")
```

こちらのデータの全カラムの値の総和を取るUDFを呼び出します。

```py:dlt-python-caller
@dlt.table
def silver_data():
  return (
    spark.sql("SELECT *, makeColSum(CONCAT_WS('_', *)) AS sumResult FROM live.bronze_data")
  )
```

ここでの肝は`CONCAT_WS`です。セパレーターを指定して全カラムを文字列結合します。これをUDF`makeColSum`に渡します。

# 呼び出されるUDFの準備

```py:dlt-python-callee
from pyspark.sql.functions import *
from pyspark.sql.types import *
import math

def colSum(x) -> float:
    """
    指定された行の総和を取るUDF
    :param x: Pyspark/SQLのカラムを`_`で連結したもの
    :return: 総和
    """
    
    # separatorで分割
    str_list = x.split('_')
    # floatのlistに変換
    float_list = list(map(float, str_list))
    # 総和の計算
    sum_result = math.fsum(float_list)

    return sum_result

spark.udf.register("makeColSum", colSum, FloatType())
```

# パイプラインの実行

上記のノートブックを用いてパイプラインを作成して実行します。2つノートブックをノートブックライブラリとして追加します。
![Screen Shot 2022-06-12 at 11.43.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/a7bbf5d3-30b2-ea1b-e7c7-90eef06490d7.png)

パイプラインの設定(JSON)は以下のようになります。

```json:JSON
{
    "id": "432c0f50-99be-45e3-8860-02a8d4061dfa",
    "clusters": [
        {
            "label": "default",
            "autoscale": {
                "min_workers": 1,
                "max_workers": 5
            }
        }
    ],
    "development": true,
    "continuous": false,
    "edition": "advanced",
    "photon": false,
    "libraries": [
        {
            "notebook": {
                "path": "/Users/takaaki.yayoi@databricks.com/20220610_dlt_udf_process_all_columns/dlt-python-caller"
            }
        },
        {
            "notebook": {
                "path": "/Users/takaaki.yayoi@databricks.com/20220610_dlt_udf_process_all_columns/dlt-python-callee"
            }
        }
    ],
    "name": "dlt_custom_udf",
    "storage": "dbfs:/user/takaaki.yayoi@databricks.com/dlt",
    "target": "dlt_takaaki_yayoi_databricks_com_db"
}
```

# 結果の確認

このように全カラムの総和が`sumResult`に格納されています。
![Screen Shot 2022-06-12 at 11.44.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/1b2f24e4-566f-7775-142d-54c0310cb6c3.png)

今回は基本的な処理のみをカバーしました。列名含めた文字列として渡して、特定の列を除外するといった実装を行うことも可能です。

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
Seleniumで利用するDriverの自動更新方法（Java）

個人開発でseleniumを利用しているのだが、Chromeが頻繁に更新されるので、手動更新がめんどくさくなった。
自動更新の仕方を調べ、実際にコーディングし、意図する結果になっているので、整理しておく。

**※多少雑だが個人的備忘なのでご了承ください。**

なおPythonの記事は以下で記載しているので参考まで。

https://qiita.com/soepy/items/b9dc97feb8997b0b9391


# 環境情報

- Java8
- Gradle6.7.1
- Windows 10
- eclipes photon

※なお対象のdriverはchromedriver

# 実装
- build.gradleに以下の記述を追加

```
dependencies {
	implementation 'org.seleniumhq.selenium:selenium-java:3.12.0'
	compile group: 'org.seleniumhq.selenium', name: 'selenium-chrome-driver', version: '3.12.0'//これ無くても動くかも
	compile group: 'io.github.bonigarcia',name :'webdrivermanager',version:'5.2.0'
}
```
※seleniumの最新はもっと行っているはず（あと、implementation とcompileの差はわからない。調べてない。）
※記事執筆時点でのwebdrivermanagerの最新は5.2.0が最新のtags
FYI：https://github.com/bonigarcia/webdrivermanager

- Refresh Gradle Projectを実行

- 環境に存在しているchromedriverを自動更新する

```java

public void setupChromedriver(){
		// 1. Auto installs
		WebDriverManager.chromedriver().setup();
}

```
これで勝手に更新してくれる。

場所は、**%HOMEPATH%\.cache\selenium\chromedriver\win32**以下にversionごとにフォルダができて、chromedriver.exeが存在しているはず。

seleniumuで自動テストなどを書いている場合は、実行の都度更新されていないとバージョン差異によって失敗するので、更新ロジックに続けでそのまま処理を書いる。
※そんなことしなくても大丈夫なはず。

- driverを利用してseleniumで起動、実行

```java
public void setupChromedriver(){
		// 1. Auto installs
		WebDriverManager.chromedriver().setup();
}

public void execute(String url){

		setupChromedriver();//呼び出してdriverを更新しておく

		// 2. use the selenium with the driver
		// headlessで実行したい場合はoptionsに「--headless」を詰めておく
		ChromeOptions options = new ChromeOptions();
		options.addArguments("--headless");

		// インスタンス生成（引数はなくても生成可能）
		WebDriver driver = new ChromeDriver(options);

		try {
			// URL遷移
			driver.get(url);

			// BOMを取得する場合はWebElementのリスト型で取得できる
			// この場合はclassで取得している
			List<WebElement> webElements = driver.findElements(By.className("XXXXX"));

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (driver != null) {
				//close ではなくquitにしないとPCのプロセスに残り続ける
				driver.quit();
			}
		}
}
```

一応こんな感じで実行できることは確認できている。
【JavaScript関数ドリル】中級編のdifference関数の実装アウトプット

## difference関数の課題内容

_. difference関数を自分で実装する課題。
https://lodash.com/docs/4.17.15#difference

「課題内容」/「解説動画」/「解答例」を確認したい場合は、以下リンク先のページを参照。
https://js-drills.com/blog/difference/


## 課題に取り組む前の状態

- 解答例を見なくてもできそうと思った。


## 課題に取り組んだ後の状態

- 解答例では引数が配列でない場合の処理を実装しているので、その点も考慮できるようにしたい。


## difference関数の実装コード（答えを見る前）
```javascript
function difference(array, values) {
  const diffArray = [];

  if (!Array.isArray(values)) {
    return [...array];
  }

  for (let i = 0; i < array.length; i++) {
    if (!values.includes(array[i])) {
      diffArray.push(array[i]);
    }
  }

  return diffArray;
}

console.log(difference([2, 1], [2, 3]));
// => [1]
```

## difference関数の実装コード（答えを見た後）
```javascript
function difference(array, values) {
    const diffArray = [];

    if (!Array.isArray(values)) {
        return [...array];
    }

    for (let i = 0; i < array.length; i++) {
        if (!values.includes(array[i])) {
            diffArray.push(array[i]);
        }
    }

    return diffArray;
}
```
【C】初めてのC言語（7. for文）

# はじめに

* これまでの学習に続いて、今回はfor文について学んだ結果をまとめてみました。
  * [【C】初めてのC言語（1. Hello world）](https://qiita.com/nkojima/items/518c1a4ec06861d74b3c)
  * [【C】初めてのC言語（2. 四則演算とフォーマット指定子）](https://qiita.com/nkojima/items/36ea93b7296ce9e8a55b)
  * [【C】初めてのC言語（3. ポインタ）](https://qiita.com/nkojima/items/825bb9f931016faccd68)
  * [【C】初めてのC言語（4. 構造体）](https://qiita.com/nkojima/items/40a1101f2f6f5800bc2d)
  * [【C】初めてのC言語（5. 関数）](https://qiita.com/nkojima/items/1fa3317c04f25fe24276)
  * [【C】初めてのC言語（6. 配列）](https://qiita.com/nkojima/items/eda3ff6675b47e7ab5f0)

# 学習環境

* 今回は[paiza.io](https://paiza.io/ja/projects/new)のC言語のエディタを使いました。

# 構文

* 以下の構文は[こちらのサイト](https://www.sejuku.net/blog/25197)から引用したものですが、Javaと同じ構文なので覚えやすいと感じました。

```
for (初期化式; 継続条件式; 変化式) {
    // 継続条件式がtrueのときに繰り返す処理
}
```

# サンプルコード

## 基本的なfor文の使い方

* 以下のサンプルコードでは、カウンタ変数`i`を0から1ずつ増やして、計5回繰り返しています。

```c:main.c
#include <stdio.h>
int main(void){
    for (int i=0; i<5; i++) {
        printf("%d回目のループです。\n", i+1);
    }
}
```

```text:実行結果
1回目のループです。
2回目のループです。
3回目のループです。
4回目のループです。
5回目のループです。
```

## 配列との組み合わせ

* 配列と組み合わせる場合には、配列の要素数に合わせてループさせる必要がありますが、これがJavaやC#と比べて少々厄介です。
* C言語では`{配列}.length`のように配列の要素数を直接調べる方法がないため、`sizeof演算子`を使って間接的に配列の要素数を求めます。
  * `sizeof(配列)`で配列全体のサイズを求めた後、`sizeof(配列のデータ型)`で1要素分のサイズを求めて、`配列全体のサイズ÷1要素分のサイズ`で配列の長さを求めています。

```c:main.c
#include <stdio.h>
int main(void){
    int int_ary[8] = {0, 1, 1, 2, 3, 5, 8, 13};
    
    // 配列全体のサイズ÷1要素分のサイズで、配列の長さを求める。
    int ary_size = sizeof(int_ary) / sizeof(int);
    
    for (int i=0; i<ary_size; i++) {
        printf("%d番目の要素は%dです。\n", i+1, int_ary[i]);
    }
}
```

```text:実行結果
1番目の要素は0です。
2番目の要素は1です。
3番目の要素は1です。
4番目の要素は2です。
5番目の要素は3です。
6番目の要素は5です。
7番目の要素は8です。
8番目の要素は13です。
```

### 無限ループとbreak

* 初期化式、継続条件式、変化式を書かず、`for (; ; ) {...}`と書くと無限ループになります。
* 本当に無限ループしてしまうとまずいので、以下のコードでは`break`を使って100回繰り返した所でループを抜けるようにしています。

```c:main.c
#include <stdio.h>
int main(void){
    // ループ回数のカウンタ
    int loop_cnt = 0;

    for (; ;) {
        loop_cnt++;
        if (loop_cnt==100) {
            break;
        }
    }
    
    printf("%d回ループしました。", loop_cnt);
}
```

```text:実行結果
100回ループしました。
```

### continueによる処理のスキップ

* 任意の場所に`continue`を入れることで、以降の処理をスキップさせてループの先頭に戻すことができます。

```c:main.c
#include <stdio.h>
int main(void){
    printf("奇数だけを出力します。\n");

    for (int i=1; i<=10; i++) {
            
        if (i%2==0) {
            continue;
        }
        
        printf("%d\n", i);
    }
}
```

```text:実行結果
奇数だけを出力します。
1
3
5
7
9
```

# 参考URL

* [【C言語入門】for文の使い方(break、continue文でループ制御)](https://www.sejuku.net/blog/25197)
* [【C言語入門】配列の使い方まとめ(初期化、代入、宣言、コピー)](https://www.sejuku.net/blog/24359)
* [配列の要素数を調べる](https://kaworu.jpn.org/c/%E9%85%8D%E5%88%97%E3%81%AE%E8%A6%81%E7%B4%A0%E6%95%B0%E3%82%92%E8%AA%BF%E3%81%B9%E3%82%8B)
SQL 初級編 Vol.2 基本用語の整理（データベース、テーブル、カラム、レコード、フィールド）

# はじめに
この記事では前回の[SQL 初級編 Vol.1（SQLとは？+ MySQLインストール+DBeaver インストール）](https://qiita.com/RelaxBoy/items/d571c21dc27c0f78d540)に続いてデータベース関連で最もよく出てくる基本用語（データベース、カラム、レコード、フィールド）について確認していきます。

※DBエンジニアと話してるとカラムとレコード、フィールドとかよく出てくるけど、とりあえずわかってるふりして出てくるたびに毎回こっそりGoogleさんに聞いているそこのあなた。がんばって覚えようぜという気持ち。（雑談）

# 基本用語の整理
![スクリーンショット 2022-06-12 9.58.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/961164/b6c58a06-1d88-fe0f-a327-b8eddf1f7fee.png)
### データベース（Database）
データベースは複数のテーブルを中に持つバケツ（入れ物）のような存在です。サーバやPCにインストールされた1つのRDBMSの中には複数のデータベースを作成してデータを管理することができます。Excelで考えると１つのファイルに相当するものと考えるとわかりやすいと思います。私なりに現時点で考えてみましたがデータベースを分割しておくメリットは以下のような点ではないでしょうか。

- システムごとに管理するデータを完全に分離したい
- セキュリティ上、データベースを分離しておくことでデータが覗かれるリスクを低減できる
- ミスオペレーションのリスク範囲を局所化できる
- バックアップやリストアの範囲を分離できる
- 後々パフォーマンスの問題が発生したときに、データベース単位で分割（引っ越し）することでスケールが用意

### テーブル（Table）
テーブルはデータベースの中で管理される1つ1つの表のことです。Excelでいうとシートに相当する存在です。Relatinal Databaseではこのテーブル同士が関連付けされて管理されることからRelationalと言われています。RDBMSではSQLを使ってテーブル同士のデータを必要に応じで組み合わせて取り出すことができます。

![スクリーンショット 2022-06-12 10.07.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/961164/9c983cd4-1af5-91e0-90bb-88c52ed52106.png)
### カラム（Column）
カラムはテーブルの中の"列"のことです。カラムの中には同じ属性（数値、文字、日付、時間などのデータ型のこと）のデータが保管されます。いろんなデータ属性のものが１つのカラムに入ることはありません。例えば、１つのカラムに数値データと文字データが同時に入ることはないということです。当たり前ですが異なるデータが１つのカラムに保存されていては集計などの管理ができなくなるので、きれいにデータ型(Int, CHAR, DATE etc）を揃えて格納する必要があります。そのためカラムを作成、追加、変更する際には必ずデータ型を指定します。
### レコード（Record）
レコードはテーブルの中の１つ１つの行に保管されたデータのことです。

### フィールド（Field）
フィールドはテーブルの中の行と列が交差する１つ１つのセルのことです。データベースにおいてデータを管理する一番小さな単位になります。

# まとめ
RDBMSの中にデータベース、データベースの中にテーブル、テーブルの中にカラム、レコード、フィールドが含まれている構造となっています。SQLを扱う上では常にこのカラムやレコード、データベースの構造を理解していないといけません。上に書いた図をイメージできるようになること、Excelで考えると何だっけ？という形で頭の中を整理するとわかりやすいと思います。
我が家のDAC

いろいろあるので一覧。

ONKYO CDプレーヤー C-1VL - WM8740(Wolfson) x 2

Mac mini G4 USB DAC HUD-mx1 - WM8740(Wolfson) ACアダプタはトランスタイプのものに変えてある。

Mac mini G4 USB Roland UA-4FX - 旭化成(猫のお留守番でFPGA FM TunerからのSPDIFの録音用なのでDACは、ほとんど使わない)

Roland UA-1G - 旭化成

FPGA FM Tuner - PCM1716(TI)

ONKYO SE-U55 - Philips

ONKYO SE-80PCI - WM8716(Wolfson)

SPDIF変換 DCT-3 - UDA1355H(Philips) ACアダプタはトランスタイプのものに変えてある。チップの表面の字が消えているが、ピン数などでチップの型番を探した。

iPhone 3G - Wolfson

自作DAC - FN1241,FN1242(新潟精密), AK4382A(旭化成), [PCM1795](https://qiita.com/yamori813/items/9d9e9e52afebb1134053),PCM5102(TI), TDA1543(Philips)

秋月D級アンプモジュール(Mac G4 Cube audio unit) - UAC3552A(Micronas)

中華 USB DAC - CM6206, TP6902, TP6911

アンプは今はTA-F333ESXを使っていて、GT-2000以外はすべてデジタルです。

ONKYOのSE-90も手に入り80と同じWM8716でした。ONKYOのPCIカードはSE-50,70,80,90,150,200がありSE-300はPCIEのようです。

PCM5102はコネクタ刺し違えて一つ飛ばして、秋月で最後の一個を買ってきました。（在庫まだ有ったようです）
【C】初めてのC言語（6. 配列）

# はじめに

* これまでの学習に続いて、今回は配列について学んだ結果をまとめてみました。
  * [【C】初めてのC言語（1. Hello world）](https://qiita.com/nkojima/items/518c1a4ec06861d74b3c)
  * [【C】初めてのC言語（2. 四則演算とフォーマット指定子）](https://qiita.com/nkojima/items/36ea93b7296ce9e8a55b)
  * [【C】初めてのC言語（3. ポインタ）](https://qiita.com/nkojima/items/825bb9f931016faccd68)
  * [【C】初めてのC言語（4. 構造体）](https://qiita.com/nkojima/items/40a1101f2f6f5800bc2d)
  * [【C】初めてのC言語（5. 関数）](https://qiita.com/nkojima/items/1fa3317c04f25fe24276)

# 学習環境

* 今回は[paiza.io](https://paiza.io/ja/projects/new)のC言語のエディタを使いました。

# サンプルコード

## 基本的な配列の使い方

* 以下のサンプルコードでは、配列の宣言をした後に1つずつ要素に値を代入しています。
  * Javaなどとほとんど同じ構文なので覚えやすいです。

```c:main.c
#include <stdio.h>
int main(void){
    // 配列の宣言のみ
    int int_ary[3];
    
    int_ary[0] = 1;
    int_ary[1] = 3;
    int_ary[2] = 5;
    
    printf("0番目の要素は%dです。\n", int_ary[0]);
    printf("1番目の要素は%dです。\n", int_ary[1]);
    printf("2番目の要素は%dです。\n", int_ary[2]);
}
```

```text:実行結果
0番目の要素は1です。
1番目の要素は3です。
2番目の要素は5です。
```

## 配列の要素を全て0で初期化する

* 配列の宣言時に`{}`で初期化すると、配列の要素が全て0となります。
* なお、gcc等のコンパイラでは`{}`を許しますが、標準のC言語では少なくともひとつの要素を必要とします。

```c:main.c
#include <stdio.h>
int main(void){
    // 配列の宣言と同時に0で初期化
    int int_ary[3] = {};

    printf("0番目の要素は%dです。\n", int_ary[0]);
    printf("1番目の要素は%dです。\n", int_ary[1]);
    printf("2番目の要素は%dです。\n", int_ary[2]);
}
```

```text:実行結果
0番目の要素は0です。
1番目の要素は0です。
2番目の要素は0です。
```

## 配列の宣言と同時に初期化する

* 配列の宣言時に`{要素1, 要素2, ...}`を代入すると、配列の要素を初期化できます。
* 「配列の要素数が5の時、3番目の要素まで初期値を指定する」ということも可能ですが、その場合は残りの要素は0で初期化されます。

```c:main.c
#include <stdio.h>
int main(void){
    // 配列の宣言と同時に初期化する
    int int_ary[3] = {1, 3, 5};
    
    printf("0番目の要素は%dです。\n", int_ary[0]);
    printf("1番目の要素は%dです。\n", int_ary[1]);
    printf("2番目の要素は%dです。\n", int_ary[2]);
}
```

```text:実行結果
0番目の要素は1です。
1番目の要素は3です。
2番目の要素は5です。
```


# 参考URL

* [【C言語入門】配列の使い方まとめ(初期化、代入、宣言、コピー)](https://www.sejuku.net/blog/24359)
4.23 (易) 多項分布

## 答案

![4.-38.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1702786/17a4bd87-3b4d-43ae-351c-9cb8140e2953.jpeg)
![4.-39.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1702786/04bab0f8-c741-9acf-a64f-e21d9639b482.jpeg)

## 参考文献

- 『[現代数理統計学の基礎](https://www.kyoritsu-pub.co.jp/bookdetail/9784320111660)』(久保川達也　著)
IBM Cloud認定資格の試験勉強をするためのサイトIBM Cloud Prepが公開された

# IBM Cloud Prepとは

これまでIBM Cloudの認定資格を受験しようとした場合、公式のラーニングサイトIBM Center for Cloud Trainingを見て学習をしていました。このサイトはカリキュラムに従ってIBM Cloudのスキルを身に着けることはできましたが、試験対策としては、特に中級・上級試験では必ずしも十分ではないところがありました。

https://www.ibm.com/training/cloud/

ところがこの度、試験対策に特化したサイトIBM Cloud Prepが公開されました。

https://ibm-cloud-prep.yourlearning.ibm.com/

IBM Cloud Prepでは、Flash Cardや練習問題が公開されています。あまり大きな声では言えませんが、内容はかなりリアルです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/24994124-985b-0e74-6296-77c5f7b42def.png)

IBM Cloudは十分に知っている、あるいは、時間がないので試験対策だけしたい、という方は、是非このサイトのマテリアルを暗記して受験の臨んでみてください。
Freezed利用時のトラブルシューティング

# はじめに

Flutterアプリの開発などでよく利用される [freezed](https://pub.dev/packages/freezed) を利用する際のハマりポイントとその対応方法をまとめています。

# 1. json_serializableで、キーの指定が正しいはずなのにデコードができない

JSONでの命名とクラスのプロパティ名が一致している場合は基本的にはデコードが成功するはずです。
しかし、build.yamlで `field_rename` が指定されている場合、これがうまく動かないケースがあります。

```yaml
targets:
  $default:
    builders:
      # ...
      json_serializable:
        options:
          # ...
          field_rename: snake # none => スネークケース
          # ...
```

```dart
part 'some_response.freezed.dart';
part 'some_response.g.dart';

@freezed
class SomeResponse with _$SomeResponse {
  const factory SomeResponse({
    required int someValue, // キャメルケース
  }) = _SomeResponse;

  factory SomeResponse.fromJson(Map<String, dynamic> json) =>
      _$SomeResponseFromJson(json);
}
```

`field_rename` の方を変更してしまうとプロジェクト全体に影響が及んでしまうため、この場合は対象のプロパティに `@JsonKey` を指定してキー名を明示することで問題を回避することが可能です。

```dart
part 'some_response.freezed.dart';
part 'some_response.g.dart';

@freezed
class SomeResponse with _$SomeResponse {
  const factory SomeResponse({
-   required int someValue,
+   @JsonKey(name: 'someValue') required int someValue,
  }) = _SomeResponse;

  factory SomeResponse.fromJson(Map<String, dynamic> json) =>
      _$SomeResponseFromJson(json);
}
```

# 2. json_serializableで、ルートがリストのJSONをデコードできない

以下のようなルートがArrayのJSONをデコードする場合、

```json
[
  1,
  2
]
```

これを下記定義のfromJSONにそのまま渡すとデコードがうまくできません。

```dart
part 'some_response.freezed.dart';
part 'some_response.g.dart';

@freezed
class SomeResponse with _$SomeResponse {
  const factory SomeResponse({
    @Default(<int>[]) List<int> ids,
  }) = _SomeResponse;

  factory SomeResponse.fromJson(Map<String, dynamic> json) =>
      _$SomeResponseFromJson(json);
}
```

```dart
final jsonMap = json.decode(response.body) as JsonMap;
final response = SomeResponse.fromJson(jsonMap); // 正しくデコードされない
```

この形式のデータに対応するには、Dart側で定義したプロパティ名に対応したキーをルートに追加した上でデコードを行うと正しく変換することができます。

```dart
- final jsonMap = json.decode(response.body) as JsonMap;
+ final jsonMap = json.decode('{"ids": ${response.body}}') as JsonMap;
final response = SomeResponse.fromJson(jsonMap);
```
初心者こそ命名規則を意識すべき3つの理由

みなさんこんにちは。
数ヶ月間、新卒の未経験エンジニアさんたちにプログラミングを教える機会がありました。
新人エンジニアさんたちに、**コーディング規則を意識してくれぇ...**　と思う機会がありましたので、その理由を3つ書きます。

### そもそも命名規則とは?

変数やクラス名に名前をつける時のルールです。
例えば定数は全て大文字で書くとか、ローカル変数は小文字でアンダーバーをつなげて書くとか、そういうやつです。

あくまでルールであって、そうしなければコードが動かないということはありません。
アンダーバーをつける部分につけなくても、大文字を書くべきところで小文字を書いても動きます。


### ①命名規則を守ると、使っている用語の理解度が上がる

初学者は「クラス」や「コンストラクタ」、「ローカル変数」などの新出単語に苦戦します。
苦戦するからするからこそ、その用語の意味をはっきりさせて理解度を上げましょう。
**命名規則を守ると決めたら一つ一つの意味や役割をはっきりさせないといけません。**
これが理解度アップにつながるのです。
それなりに苦労するステップでしょうが、苦労するのは最初だけなのでサッサと乗り越えられる壁は乗り越えちゃいましょう。

### ②自分がコードを見直すときに読む時間が減る

初学者は自分が書いたコードをスラスラ理解できるほど慣れていません。そのため、コードを読むのに時間がかかってしまいます。
**ですが、命名規則を守れば用語の役割や意味が分かるので、過去の自分が何をしたかったかが分かりやすくなります。**
だからこそ命名規則は守りましょう。

### ③他の人がコードを読むときにスムーズに読んでもらえる

初学者は誰かにコードを見てもらう機会が多いかと思います。より成長するためには、何度も誰か自分のコードを読んでもらって、添削をしてもらうのが良いです。
**誰かに読んでもらうときにスムーズに読んでもらえるとあなたへのフィードバックのスピードが速くなります。**
そうすると成長スピードが速くなります。

### 何よりも自分のために命名規則は守りましょう

一見重要じゃないように思えるかもしれませんが、頑張りましょう！
アイコンや背景画像の作成方法

■概要
　・スマホ画面に配置する背景画像やアイコンの簡単な作成ノウハウです。
　・私がAndroidアプリの画面設計を始めた当初（この方法を知らなかったため）、
　　Google等からフリーのPNG画像を取得しておりましたが、ドンピシャの
　　アイコンがなく、下記サイトから作成ノウハウを勉強させて頂いた次第です。
　・参照サイト：https://powerpoint-univ.com/save-as-figure/
　・作成例：私の記事（＊）の、下の方のスクリーンショットをご参照下さい。
　　（＊）https://qiita.com/voibow/items/bf8c66efbcfe803d5053

■作成方法
　・パワーポイント純正のアイコンを使います。以上！（笑）
　　（私が使用しているPPTバージョン：PowerPoint2019）
　・挿入＞アイコン＞好みのものを選択＞挿入＞適当な大きさにして右クリック＞
　　グラフィックスの書式設定＞塗りつぶしや影などでお化粧＞右クリック＞
　　図として保存＞pngを選択＞保存。　
　　　※自由に切り貼り／重ね合わせをすれば、あなただけのアイコンになります。
　　　※画像サイズは、この段階では適当でOKです。
　　　　AndroidStudioにアップした後にactivity_main.xml上で調整します。

■AndroidStudioへのアップ方法
　・作成したpngを、デスクトップなど適当な場所に置いておく。
　・AndroidStudioを起動＞置いたpngを右クリック＆コピー＞
　　AndroidStudioのapp\res\drawable選択＞
　　右クリック＞貼り付けを選択＞選択画面が表示されるので、
　　例えば\app\src\main\res\drawableを選択しOK＞
　　drawable直下にアイコンがアップされる。
　・後は、activity_main.xmlを使って、自由に配置／リサイズを行う。

いかがでしたでしょうか。もっと簡単な方法があればご教示ください。
Blaster対策のパケットフィルタについて

## 記事

2003年頃、Blasterというウイルスが大流行したのを憶えているだろうか。このウイルスは厄介だったということを憶えている。大量のパケットが流れてきて、回線が自動で接続されてしまうのだ。

当時は、今のような光回線を使った常時接続といった環境はなく、ISDN回線を使ったダイアルアップ式が主流の時代であった。そんなISDN回線であるが、2024年1月をもって、いよいよサービスが終了しようとしている。今でも使われているのだろうか。恐らく、バックアップ回線として一応残しているという使い方が殆どのような気がする。ISDN回線の速度だが、驚くことなかれ128kbpsだ。正確にいえば、64kbpsが論理的に２回線存在している。インターネットの黎明期はこんな太さの回線を使ってネットサーフィンをしていたのだ。しかも、課金を気にしながら。

Blasterだが、外からパケットが流れてくると、ISDN回線のセッションが自動でつながってしまうという厄介な代物であった。月末にNTTから送られてくる請求書を見て驚くことになる。ISDN回線時代の課金問題は、多くのインフラエンジニアを悩ませている。賠償問題にまで発展したケースもあったに違いない。

Blaster対策として、ルータでBlaster関係のポートを閉じる設定を急遽行うこととなった。今の光回線の環境であれば、課金で問題になることはないが、変なパケットが外から大量に流れてきてたら速度に影響が出るし、そもそも、気持ちもよくないだろう。今の回線環境であっても、Blaster対策は行って損ではないと思われる。

具体的にどういうことをするかと言えば、下記のポート番号を、外から内に対して遮断してやればいいことになる。

| プロトコル | ポート番号 | 
| ---------- | ---------- | 
| epmap      | 135        | 

Blaster対策はこれだけでは終わらない。亜種も猛威を振っていたからだ。亜種も同じように止める必要がある。亜種を遮断するポートは下記です。

| プロトコル | ポート番号 | 
| ---------- | ---------- | 
|Microsoft-DS|	445       | 
|apertus-ldp |	539       | 
|nv-video    |	4444      | 


パケットフィルターで上記のポートを止めるとBlaster対策は基本的にOKとなります。
AxiosでSlack botによる通知を送信する

## 前提
Slack APIでwebhook URLを取得済み

## コード

```js
import axios from 'axios';

const notification = (content, image_url) => {


    const data = {
        "text": "料理が新しく投稿されました!",
        "attachments": [{
            "fields": [
                {
                    "title": content,
                    "value": content,
                }],
            "image_url": image_url
        }]
    }

    axios.post(
        {WebhookのURL},
        JSON.stringify(data),
        // corsエラー回避
        {
            withCredentials: false,
            transformRequest: [(data, headers) => {
            delete headers.post["Content-Type"]
            return data
            }]
        }
    )
    .then(res => {
      console.log(res)
    })
    .catch(e => {
      console.log(e)
    });
}
```

## 結果
このような通知がチャンネルに飛んできます。
![スクリーンショット 2022-06-12 8.41.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689205/87737ec7-9b42-4758-7239-ace10192b8b5.png)


## 参考

CORSエラーの対処法
https://stackoverflow.com/questions/41042786/cors-issue-using-axios-with-slack-api

リッチな通知UIの作り方（公式）
https://api.slack.com/messaging/composing/layouts

SlackAPI attachment チートシート
https://qiita.com/daikiojm/items/759ea40c00f9b539a4c8
Unable to boot simulator


`XCode` > `Windows` > `Device and Simulators`
でシミュレーターの詳細を確認

![スクリーンショット 2022-06-12 8.43.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239663/6df5d51e-b2a8-804d-3171-118d12812d46.png)

`iOS 15.5` となっている。

続いて、XCodeのバージョンの方も　`15.5` に合わせるとシミュレーターが起動できるようになる

![スクリーンショット 2022-06-12 8.44.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239663/228e51a8-972e-8d75-2533-ea04a4d54479.png)
わかりやすいシステム構成図の書き方


### わかりにくいシステム構成図とは
こんなシステム構成図を書いてないでしょうか？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33447/97f01025-4108-5cf2-af15-dced154d6f5e.png)



このシステム構成図のわかりにくい点が３つあります。それは

1. 製品名は書いてあるが「役割」が書いていない
2. データと処理が区別できない
3. データの流れと制御の流れが区別できない

の３つです。

### わかりやすいシステム構成図

これら３つのわかりにくい点を改善したわかりやすいシステム構成図が↓です

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33447/e291be02-bd95-19bf-aecb-cc3a9303f401.png)





ポイントを解説していきます

#### ポイント1. 製品名称ではなく「役割」を書く

システム構成図には製品名称ではなくシステムコンポーネントの「役割」を書きます。

役割とは、例えば〇〇データや〇〇処理といったことであり、それを読むだけでシステムの動きを理解できる文字列です。役割をかかずに製品名称のみを書いてしまうと、その製品を知らない人が見たときに理解できません。例えば「Cloud Pub/Sub」という製品はGCPというパブリッククラウドの分散キュー製品ですが、知らないとわかりません。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33447/f95436df-6a64-d938-feba-3a3f828b7969.png)


#### ポイント2. データと処理を形で書き分ける

コンピュータシステムはつきつめると「データを処理する」ことです。必然的に、システム構成図にはデータと処理という大きく異る２つのものが登場するため、それらを異なる形で表現し書き分けるとわかりやすくなります。

例えば、ファイルやDBの中のテーブルは、そこにデータが永続されているためデータといえます。一方で加工処理やワークフローエンジンなどはそれ自体はデータを持たないため、処理に分類できます。これらについて、明確にかき分けることでわかりやすくなります。

この例では、処理を長方形に統一し、データは世の中でよく使われているイメージしやすいアイコンにしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33447/e1385729-9d38-f043-831f-1719541272c6.png)


#### ポイント3. データの流れと制御の流れで線を書き分ける

データと処理をかき分けた後は、それらを線でつないでいくのですが、その際にポイントはデータの流れと制御の流れを異なる線で書き分けることです。システムの動きを理解する上ではデータの流れを追うことが重要ですので、データの流れを明示的に書くことにより、構成図を見た人はデータがどのように流れているかひと目で分かるようになります。一方で制御の流れはそこまで重要でない事がおおいため、控えめに書きます。

具体的には、データの流れは実線で、制御の流れは破線で示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33447/cfa3d6be-9a4a-ec18-b656-54d23eab5ef2.png)

データの流れを書く場合は、処理を起点としてデータに対して矢印を書きます。ポイントは**矢印の起点を処理にする**ことです。これにより、処理が能動的にデータにアクセスしにいっている様子がひと目でわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33447/79c6f9e4-425b-3b07-ee81-91deead1a8b3.png)


制御の流れは、ある処理が別の処理を呼び出す際のことであり、呼び出し元となっている処理を起点として、呼び出し先の処理に向けて破線を書きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33447/dea34ae1-f984-fb86-df4d-1c20c3f5c467.png)

わかりやすいシステム構成図の例では、ワークフローエンジンがテーブル復元処理を起動するときは制御の流れの破線を用い、更新ログが復元したデータに変換される部分はデータの流れの実線を用いて表現しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33447/b16f6c6d-04c9-9712-02b3-5a9937fd6f2e.png)

### ただし、より複雑な場合はUMLを検討する

今回説明したシステム構成図は、よくあるクラウドベースのシステム構成図であり、それをよりわかりやすくするという文脈でブログを書きました。
より大規模なシステム構成図やアプリケーションの詳細な動きを示したい場合は、従来からあるUMLのシステムコンポーネント図やシーケンス図を検討することをおすすめします。

参考： [UMLの9種類のダイアグラムとは？](https://atmarkit.itmedia.co.jp/fjava/devs/dstylefaq/uml/uml1_2/uml1_2.html)

### まとめ

以下の３つの点を気をつけてかくと、わかりやすいシステム構成図になります。

* ポイント1. 製品名称ではなく「役割」を書く
* ポイント2. データと処理を形で書き分ける
* ポイント3. データの流れと制御の流れで線を書き分ける

ただし、より複雑な場合はUMLを検討する。
【Swift・Xcode】原因不明で未解決のエラー集

# はじめに
原因不明で解決できなかったエラーをここに記載します。
解決できたら解決策の記事を書いてここにリンク載せます。

こうしたら治ったよ。みたいなコメント待ってます。

随時追加予定


## Umbrella header for module 'GoogleMobileAds' does not include header 'GADDelayedAdRenderingOptions.h'
![スクリーンショット 2022-06-11 18.32.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/2e33f94f-4d2b-7bfd-846d-81bf9e705090.png)

**SDKバージョン**
8.13.0
**警告文**
```
Umbrella header for module 'GoogleMobileAds' does not include header 'GADDelayedAdRenderingOptions.h'
```

## GoogleMobileAdsを9.0.0以上にするとiPadでクラッシュ
**発生条件**
- AdMob SDK 9.0.0
- おそらく実機のみ
- iPad

**同様の事例**

https://stackoverflow.com/questions/71899292/admob-crash-on-ipad-with-window-container-should-not-be-nil

## error: IB Designables: Failed to render and update auto layout status for ViewController (MOh-CZ-3ki): The bundle “XXXXXXXXXXXX” couldn’t be loaded because its executable couldn’t be located.

- エラーが発生していてもビルドはできる
- [MarqueeLabel](https://github.com/cbpowell/MarqueeLabel)を使用すると発生

公式のドキュメントでも[同様の事例](https://github.com/cbpowell/MarqueeLabel#ibdesignables)が報告されている
記載されている解決策を試したが効果なし
access2000の作法 その41

# 概要
access2000の作法、調べてみた。
練習問題やってみた。

# 練習問題

qiita apiを叩いてテーブルに格納せよ。


# qiita apiを叩いてテーブルに格納する手順
- リボンの「作成」→「クエリデザイン」を選択します。
- 「テーブルの表示」が表示されますが、ここでは追加せずにそのまま閉じます。
- 画面左上の「SQL 表示」をクリックします。
- SQL を記述します。
```
CREATE TABLE qiita(ino AUTOINCREMENT CONSTRAINT PrimaryKey PRIMARY KEY, created_at DATETIME, title TEXT(200), body TEXT, url TEXT(100))"

```
- 画面左上の「実行」をクリックします。
- menuフォームを右クリック。
- ボタンを設置
- ウィザードが開く	キャンセル
- プロパティシートを開く
- イベントを開く
- クリック時、コードビルダーを開く
```
Private Sub コマンド62_Click()
    Dim json
    json = http_get("https://qiita.com/api/v2/users/ohisama@github/items?page=1&per_page=5")
    Set jDic = JSON2Dic(json, 1, cDicIdx, 1)
    Dim db As DAO.Database
    Set db = CurrentDb
    For i = 0 To 4
        db.Execute "INSERT INTO qiita(title,created_at,body,url) VALUES('" & jDic(i)("title") & "',#" & Mid(jDic(i)("created_at"), 1, 10) & "#,'" & jDic(i)("body") & "','" & jDic(i)("url") & "');"
    Next
    MsgBox "ok"
End Sub

```
- フォームを閉じる
- 保存する


以上。
access2000の作法 その40

# 概要
access2000の作法、調べてみた。
json2dicやってみた。

# 参考にしたページ。

https://qiita.com/imoimo2009/items/f69f27393c3fae506523

# json2dicボタンを作る手順。
- menuフォームを右クリック。
- デザインビューを開く
- ボタンを設置
- ウィザードが開く	キャンセル
- プロパティシートを開く
- イベントを開く
- クリック時、コードビルダーを開く
```
Private Sub コマンド4_Click()
	wkStr = "{""term1"":""abc"",""term2"":{""term3"":123,""term4"":""def"",""term5"":[456,{""term6"":""789"",""term7"":""012""}]}}"
	Set docObj = JSON2Dic(wkStr, 1, cDicIdx, 1)
	Debug.Print docObj("term1")					  		' abc
	Debug.Print docObj("term2")("term3")			 	' 123
	Debug.Print docObj("term2")("term4")			 	' def
	Debug.Print docObj("term2")("term5").Count	   		' 2
	Debug.Print docObj("term2")("term5")(0)		  		' 456
	'Debug.Print docObj("term2")("term5")(2)("term6") ' 789
	'Debug.Print docObj("term2")("term5")(2)("term7") ' 012
	Debug.Print Dic2Str(docObj, 3)
End Sub
```
- フォームを閉じる
- 保存する


以上。
access2000の作法 その39

# 概要
access2000の作法、調べてみた。
練習問題やってみた。

# 練習問題
湯婆婆を実装せよ。


# 湯婆婆フォームを作る手順。
- 作成>フォームデザインを右クリック。
- ラベルを設置
```
契約書                                                                
		甲は油屋当主として、乙を油屋に雇用することを契約し、
		労働に伴う対価の支払いを右の通り、約定する。
		なお、一日の労働の対価は金百円とする。                    
		甲　油屋当主　湯婆婆
		
		乙
```
- テキストボックスを設置
- ボタンを設置
- ウィザードが開く	キャンセル
- プロパティシートを開く
- イベントを開く
- クリック時、コードビルダーを開く
```
Private Sub コマンド4_Click()
    Dim name As String
    name = テキスト0.Value
    Dim str As String
    str = "契約書だよ。そこに名前を書きな。" & vbCrLf
    str = str & "フーン。" & name & "というのかい。贅沢な名だね。" & vbCrLf
    Dim newName As String
    newName = Mid(name, Rnd() * (Len(name) - 1) + 1, 1)
    str = str & "今からお前の名は" & newName & "だ。いいかい、" & newName & "だよ。分かったら返事をするんだ、" & newName & "!!"
    MsgBox str
    
End Sub

```
- フォームを閉じる
- 保存する


以上。
CakePHPので変数を渡しているViewの上に展開させているReactでその値を拾う


今までフロントから api でデータフェッチするやり方しか知らなかったのでこのような方法もあるというメモ
- data属性を使う
cakephp の View ファイルでは以下のように data 属性に入れておく
```php:View/index.ctp
<div class="hoge" data-object-for-modal='<?= json_encode($object) ?>'></div>
```
以下 React の jsx | tsx ファイル
```tsx:components/index.tsx
// DOM を取得
const HOGE = document.querySelector('.hoge') as HTMLElement 
// データ属性に埋め込まれてる値を取得
const { objectForModal } = HOGE.dataset;
// パースする
cosnt object = objectForModal && objectForModal !== '[]' ? JSON.parse(objectForModal) : null
```
cakephp の view で data 属性に渡す値が動的に変化する値で、 null が渡されることがある場合はデータ属性から値を取得する時にエラーとなるので注意。
Codility lesson3 PermMissingElem

Lesson3のPermMissingElemは欠けている数字を当てるというものです。
長さNのリストには1~N+1のいずれかが異なる形で入っている、逆にいうと一つ欠けていることがわかります。
[1,2,4,5]は3ですね。
[1,2,3,4]は5ですね。

さて今回の問題を考える上で、配列の順番を変えても特に問題はありませんよね。
例えば
[3,1,2,4]を[1,2,3,4]にする
[4,5,1,2]を[1,2,4,5]にした方が処理しやすいですよね。
なので今回は前回のlesson2 OddOccurencesInArrayのとき同様に先にソートしてから処理していきます。

アルゴリズムは以下の通りです。
1.順番通りにソートする
2.インデックス番号と比較してインデックス番号に対応している数字が来ていれば次に進む。
3.2の処理を繰り返し行うことでインデックス番号と対応していない数字、つまり欠けている数字の場所に到達するまで行う

コードは以下の通り

    def solution(A):
        A = sorted(A)
        i = 0
        len_A = len(A)
        while  i+1 == A[i]:
            if i < len_A -1:
                i +=1
            elif i == len_A -1:
                i +=1
                break
        return i+1

さて結果は。。。。？

![スクリーンショット 2022-06-12 3.02.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1667538/21dda34d-76bf-19ad-4e96-e36a8b3c3fab.png)

あれ90%...?
どうやら空のリストを受け取った時の処理を書いていなかったためにエラーが生じてしまっているようです。
ただ空のリストの時何を返せばいいんでしょうか。。。？
【phpコマンドでのエラー】ターミナルでの"zsh: command not found: php"を解決する方法

## はじめに
Laravelの開発環境を構築をしようと思い、phpのコマンドを叩いた際につまずいたので
同じような現象で困っている方の解決方法の一つになれば幸いです。

## 環境
・OS : macOS Monterey
・バージョン : 12.3.1

## 起きている現象
まず、PHPのライブラリ依存関係を管理する「Composer」をインストールするため
下記コマンドを入力。

```
 php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
```

すると、、、

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

上記の内容が返ってくる。
※homebrewはインストール済みのため、一応phpのパスを確認　↓

```
 brew --prefix php@7.4
```
、、、
```
 /usr/○○/○○/php@7.4
```

反応しないのかと思いきや、しっかりとパスは返却される。

## 結論
アップデートができておりませんでした。。。


という訳で、具体的な解決方法と手順を以下に記します。

## 解決方法
再インストールする形で、以下のコマンドを叩きアップデート。
```
 brew install php@7.4
```
5分くらいで、まあまあ長いインストールが終わるので、
リンクするためのコマンドを実行。
```
 brew link --overwrite --force php@7.4
```
パスを通すため、以下のコマンドも実行。
```
 echo 'export PATH="/usr/local/opt/php@7.4/bin:$PATH"' >> ~/.zshrc
 echo 'export PATH="/usr/local/opt/php@7.4/sbin:$PATH"' >> ~/.zshrc
```
次のコマンドで、変更を反映
```
 source ~/.zshrc
```
これで手順は以上です!!

最後にphpコマンドが効くか、バージョン確認のためのコマンドを実行。
```
 php -v
```
、、、
```
 PHP 7.4.30 (cli) (built: Jun  9 2022 09:30:03) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
```
今度は、正常にphpコマンドが効いているのがわかります。

もちろん、最初にエラーが起きた以下のコマンドも問題なく実行がされます。
```
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
```

## まとめ
やはり、定期的なアップデートは大事なのだと改めて実感させられました。
コマンドの知識に関してはまだまだ乏しいので、気づきやその過程で発生する
問題の解決が出来たら、その内容をもとに少しでもお役に立てるような
情報を投稿できればなと思います。
また、間違っている文言などにつきましては、ご指摘いただけますと幸いです。
宜しくお願いいたします。
最後までお読みいただきありがとうございました!!
本日の勉強✏️

ドットインストール詳解CSS 基礎文法編

#12〜#20



HTML、CSSは以前もProgateで勉強しているため、結構吸収していると思います。

やはり目に見えてデザインが変わるのは使ってて楽しいですね。

若かりし高校生の時、一部の人で、無料サーバを借りてHTMLで携帯サイトを作るのが流行ってました。

友達とプロフィールや日記、アルバムを
作って、ランキングに載せたり…


今思うとあの時からプログラミングには惹かれていたと思います。





仕事の休憩中にはProgateのアプリで、
復習しています。
このアプリは本当によくできていて、ありがたすぎます。
【TypeScript】プリミティブ型

## 目次
- [number](https://qiita.com/P-man_Brown/items/04d59e780b2da05a4809#number)
- [string](https://qiita.com/P-man_Brown/items/04d59e780b2da05a4809#string)
- [boolean](https://qiita.com/P-man_Brown/items/04d59e780b2da05a4809#boolean)
- [void](https://qiita.com/P-man_Brown/items/04d59e780b2da05a4809#void)
- [null](https://qiita.com/P-man_Brown/items/04d59e780b2da05a4809#null)
- [undefined](https://qiita.com/P-man_Brown/items/04d59e780b2da05a4809#undefined)
- [any](https://qiita.com/P-man_Brown/items/04d59e780b2da05a4809#any)

## number
```ts
let year: number = 2000
// year = false
// error TS2322: Type 'boolean' is not assignable to type 'number'.
console.log(year)

let age: number = 0x2b
```

## string
```ts
let name: string = "田中"
// name = 10
// error TS2322: Type 'number' is not assignable to type 'string'.
console.log(name)
```

## boolean
```ts
let isFinished: boolean = true
isFinished = false
// isFinished = 1 
// error TS2322: Type 'number' is not assignable to type 'boolean'.
console.log({ isFinished })
```

## void
```ts
// いかなる返り値も持たないことを明示
function returnNothing(): void {
  console.log("don't return anything")
}

console.log(returnNothing())
```

## null
```ts
// nullのみ
let absence: null = null
// absence = "moji"
// error TS2322: Type '"moji"' is not assignable to type 'null'.
```

## undefined
```ts
// undefinedのみ
let data: undefined = undefined
// data = 329
// error TS2322: Type '329' is not assignable to type 'undefined'.
```

## any
```ts
// いかなる値もエラーはなし
let year: any = 2000
// year = false
// エラーなし
console.log(year)
```
Codility lesson3 FrogJmp

Lesson3のFrogJmpの問題はカエルが登場したり飛んだり文章が無駄に長くなっていますが、要点は至ってシンプルです。
位置XにいるカエルはYに到達するまでに何回ジャンプすれば良いかというものです。

例えばX = 30 Y = 60 一回のジャンプで進む距離D=20だとすれば
最短2回で到達します。

(60-30)//20 = 1に　1を加える

例えばX = 30 Y = 60 一回のジャンプで進む距離D=30だとすれば
最短1回で到達します。

(60-30)//30 = 1

今回はアルゴリズムは説明するまでもなく、コードを見てもらった方が早いと思うので、
コードは以下の通りです。

    def solution(X,Y,D):

        if (Y - X)%D >= 1:
            return (Y - X)//D +1
        else:
            return (Y - X)//D


さて結果は。。。。？

![スクリーンショット 2022-06-12 0.50.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1667538/fcd38e5d-13c7-f4da-4e57-e07ebfb1609a.png)

　でした！
ちなみにスクリーンショットを毎回撮るのは面倒なので結果を確認してから毎回同じ写真を使ってます（）
c++ 配列にsizeof演算子を適用する場合、引数とそうでない場合で異なる値を取得する


c++で配列の長さを求める方法として、配列全体のバイト数/配列の要素の型のバイト数 で求める方法がよく知られている。
```c++
int array[] = {1, 2, 3, 4, 5, 5, 5, 5, 5};
cout << sizeof(array) << endl; // 36
cout << sizeof(array[0]) << endl; // 4
cout << "arrayの長さ： " << sizeof(array) / sizeof(array[0]) << endl; // arrayの長さ：9
```

しかし、関数の引数となっている配列をsizeof演算子に適用すると、上記とは異なる結果となる
```c++
size_t arr_size(int arr[])
{
    return sizeof(arr);
}

int array[] = {1, 2, 3, 4, 5, 5, 5, 5, 5};
cout << sizefunc(array) << endl; // 8(上記と異なる)
cout << "arrayの長さ： " << sizefunc(array) / sizeof(array[0]) << endl; // arrayの長さ：2
```

原因がよくわからないが、引数の場合はポインタ型になる(=> sizeof(arr) -> sizeof(int *) となる?)から?
関数内で配列のサイズを求めるのではなく、関数の引数に配列そのものに加えて、配列のサイズも追加する方法がよく見られる気がする。
jetson での顔照合を調査中

NVIDIA Jetson Orinを使った顔検出・顔照合に提供されているライブラリを調査する。
- TensorRTに移植されているオープンソースの実装がどれくらいあるのか、
- TensorRTで動作する市販ライブラリがどういったあるのかを調査中のメモです。
- 調査が足りていないので、もっと有名なライブラリが抜けていると思う。


## Recognize 2000+ faces with your Jetson Nano.
RetinaFace or MTCNN Arcface
https://github.com/Qengineering/Face-Recognition-Jetson-Nano

> First, the faces and their landmarks are detected by RetinaFace or MTCNN. Next, the database is scanned with Arcface for the matching face. In the end, Face Anti Spoofing tests whether the person in front of the camera is real and not a mask or a cardboard photo.

![Screenshot from 2023-11-16 21-47-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83761/15cf97c2-03af-0c6c-5217-e190c867c830.png)




## [face_recognition](https://github.com/ageitgey/face_recognition) モジュールを使う例
[Face Recognition On NVIDIA JETSON NANO](https://www.hackster.io/Hardi2409/face-recognition-on-nvidia-jetson-nano-2fe321)


次もface_recognitionを使う例の記事
[Build a Face Recognition System for $60 with the New Nvidia Jetson Nano 2GB and Python](
https://medium.com/@ageitgey/build-a-face-recognition-system-for-60-with-the-new-nvidia-jetson-nano-2gb-and-python-46edbddd7264)

Jetson Nano の接続手順から丁寧に書いてあるのでわかりやすい。


## 商用ライブラリFaceMe
https://github.com/FaceMe-SDK/FaceRecognition-ServerSDK

- これは商用ライブラリ　FaceMeを使ってサーバーを立ち上げるSDKである。
- FaceMeはCyberlink社の市販する顔照合ライブラリ
### FaceMe それ自体
https://www.cyberlink.com/faceme/tech/nvidia
![Screenshot from 2023-11-18 11-48-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83761/d9d8cd86-f56f-70a0-2c21-f4c2dcb92cde.png)

FaceMe の各種性能についての記載
https://jp.cyberlink.com/stat/technology/enu/tech_face.jsp?tab=spec

-------
### 顔検出
https://github.com/elliottzheng/batch-face

### Jetson　Nano での顔検出の記事
顔検出 mtCNN

Google FaceNet

### 顔照合
[Face Recognition with Arcface with TensorRT](https://medium.com/@penolove15/face-recognition-with-arcface-with-tensorrt-abb544738e39)


https://developer.ridgerun.com/wiki/index.php/NVIDIA_Jetson_Orin/RidgeRun_Products/GstInference
- Facenetを使った顔照合の例を記述している。
【Rails】通知機能~変更点と補足~

## 記事の対象者
実装した処理の動きについて理解したい人

## 前提条件
Ruby 2.6.3
Rails 6.1.5

## 参考にした記事
実装については、下記記事を参考にしました。
今回は一部変更した点と、実装した処理の動きについて自分で補足した部分を書いていきます。

https://qiita.com/nekojoker/items/80448944ec9aaae48d0a#%E5%8F%82%E8%80%83%E3%81%AB%E3%81%97%E3%81%9F%E8%A8%98%E4%BA%8B

## 実装の流れ（フォロー通知）
**①通知モデルの作成(Notification)
②モデルの関連付け（UserとNotification）
③モデルに通知作成メソッドを作成
④コントローラーに通知作成メソッドの呼び出し処理作成
⑤ビューに通知一覧画面及び通知アイコンの作成**

## 変更箇所
下記が変更点となります。補足を交えながら説明していきます。
・default_scope
・update_attributesメソッド

## ②モデルの関連付け（UserとNotification）
default_scopeですが、RuboCopの解析では引っかかってしまいます。
理由としては、default_scopeのメンテナンス性の悪さなどがあるようです・・・。
こちら、参考記事となります。
https://qiita.com/yusabana/items/f0b3a80111d6bd4ec8b0

ですので、コントローラーに同じ内容で書き直しました。
デフォルトスコープの内容は、「作成日時の降順」で指定となります。

```php:Notification.rb
default_scope -> { order(created_at: :desc) }
```

↓ この内容をこちらへ変更

```php:notifications_controller.rb
@notifications = current_user.passive_notifications.order(created_at: :desc)
```

## ③モデルに通知作成メソッドを作成
"?"は比較演算子の時に使用します。
"and"で繋いでいるので全ての条件が揃うデータのみ取得します。
```php:User.rb
temp = Notification.where(["visitor_id = ? and visited_id = ? and action = ? ", current_user.id, id, 'follow'])
```
if 修飾子
「真(true)」となった場合に実行したい処理 if 条件式　となります。
すなわち、バリデーションでtrueの場合のみsaveを実行します。

```php:User.rb
notification.save if notification.valid?
```

## ⑤ビューに通知一覧画面及び通知アイコンの作成

下記処理は、「未確認→確認済み」になるように更新を行っています。
しかし、**update_attributes**メソッドはRails 6.1になり、消去されてしまったため、使用することができません。
こちらは**update_attributes**から**update**に変更して実装しましょう。

```php:notifications_controller.rb
notification.update_attributes(checked: true)
```


## まとめ
Railsのバージョンにより変更が多くありますね。
その点について意識しながら実装することができたので、今後の他の実装にも生かしていきたいです！
最後まで読んでいただきありがとうございました。
Codility lesson2 OddOccurencesInArray

Lesson3のOddOccurencesInArrayの内容はリスト内のペアになっていないものを返すというものです。
例えば、[1,2,3,4,3,2,1]においてペアになっていないものは4だけです。
例えば、[1,1,1,3,1,1,1]においてペアになっていないものは1です。
例えば、[1,1,1,3,3,1,,1]においてペアになっていないものは1です。

さて、ペアでないものを見つける一番はやい方法はなんでしょうか。

それはまずは並び替えるということです。

[1,2,3,4,3,2,1]ならば[1,1,2,2,3,3,4]なので4
[1,1,1,3,1,1,1]ならば[1,1,1,1,1,1,3]なので3
[1,1,1,3,3,1,,1ならば[1,1,1,1,1,3,3]なので1

こうした方が見やすいですよね。

アルゴリズムは以下の通りです。

[アルゴリズム]
1.リストの数字を小さい順に並び替える
2.先頭から順番に、現在の要素と次の要素が等しければ、それがペアとなるので、次のペアを探していく。
3ペアとならないものを見つけたらその数字を返す。


具体的にコードを見ていきましょう。


    def solution(A):
        A = sorted(A)#Aをソートする
        len_A = len(A)
        i = 0
        if len_A > 1:
            while A[i] == A[i+1] and i < len_A: #ペアになっていない、あるいは配列の走査が終わったら終了
                if i+2 == len_A-1: #リストの最後に答えがある場合にA[i]==A[i-1]のような比較対象がそもそもないためwhile文の処理が行えない
                    return A[i+2]
                else:
                    i +=2
            return A[i]
        else:
            return A[0] #リストが一個だけだった場合


さて結果は。。。。？
![スクリーンショット 2022-06-12 0.50.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1667538/3c394b47-6f1d-ecbc-59b1-3c6901cd5a02.png)

よかったです。処理速度についても
![スクリーンショット 2022-06-12 2.06.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1667538/385c96a3-ad26-83f6-a54b-2fb835cae025.png)

こんな感じ。
今回のように先にソートさせてから考える方が二重ループを回避でき、処理が早く済むということがある。メモメモ…
転職エージェントはエンジニアの敵か味方か

## この記事の目的
エンジニアが、ハイクラス転職やら、ヘッドハンターやら、
耳障りの良い言葉に釣られて、食い物にされる被害を減らすこと

## 転職エージェントとは
企業の代わりに、応募者の募集・選考を代行し、
入社が決まった暁には年収の30％を頂くというシステム。

マッチしない人材をフィルタリングできるというのが表向きの名目だが、
実際には、雇った人材が期待はずれだった場合
「エージェントのXXさんが優秀な人だって言ったから」
と**人事が言い訳するため**に、多額の費用を払っているのが実態。

## 利害の一致という幻想
転職エージェントの手数料は、候補者の年収×30％となるため
年収が高くなるほうが、手数料も高くなる。
だから、転職エージェントも年収を上げるように仕向けてくれる？
などと考えてしまうと、それは大きな間違いである。

奴らにとって何よりも重要なのは**ノルマ消化**であるため
応募者の年収が上がろうが下がろうがどうでもよく
とにかく放り込みやすいところに放り込むことしか考えていない。

そして、ブラック企業に放り込むことも厭わない、というか
むしろブラック企業に入ってくれたほうがありがたい。
なぜなら、またすぐに転職が発生して手数料を得られるから。

:::note alert
転職エージェントにとって、他人の不幸は蜜の味
:::

## 利益相反のケーススタディ
このようなケースがあるとする。
```
企業側は、年収600万円で雇いたいと考えている
応募側は、年収700万円で働きたいと考えている
```

転職エージェントが得られる手数料は年収の30％なのでこうなる。
年収600万円 → 手数料180万円
年収700万円 → 手数料210万円

一見、年収が高くなるほうが手数料も高くなると思うが、
転職エージェントは**期待値**で物事を考える。
年収600万円 → 手数料180万円 × 内定率80％ = 期待値144万円
年収700万円 → 手数料210万円 × 内定率20％ = 期待値42万円

そのため、転職エージェントは応募者の希望など無視して、
なるべく企業側に寄せて、とにかく内定が出るように仕向ける。

極端な話
A社（年収500万円）で働いている応募者を
B社（年収500万円）に転職させようとすることすらある。
応募者にメリットがあろうがなかろうが知ったこっちゃない。
自分達さえ手数料を得られればそれで良いのだ。

:::note alert
転職エージェントは、年収を下げるように仕向けてくる。
:::

## 根本原因と解決策
転職エージェントにとってのお客様とはカネを出す企業様。
だから、必然的に企業サイドの肩を持つようになる。

また、年収をアップさせるように企業と交渉するよりも、
年収を値切り倒して応募者を泣かせるほうが簡単。

だから、転職エージェントは情報を得るためだけに使うべき。
非公開求人の情報を聞き出したら、その企業に**直接応募**する。
採用が決まったら、エージェントからの連絡はすべてブロック。
これが転職エージェントとの正しい付き合い方である。

:::note alert
年収の30％を手数料として払うぐらいなら、
入社祝い金として本人に100万円あげるほうが効果的
:::