OmniAICreator/Qiita-1.07M huggingface dataset:
【TypeScript + Express】 "npm run dev"でError: Cannot find module が出たら

 こんにちは。

 Qiita1発目の記事を何にしようかと悩んでいたのですが、ちょうど
「TypeScriptでバックエンドつくってみよー」
 と、半分軽い気持ちで作っていたら見事ハマったので備忘録。

nodemonからts-node-devに変更し、package.jsonでパスエイリアスをフルパスで表記したら、エラーが発生しなくなったので紹介する。

__※ts-nodeがインストールされていることが前提条件__

<h2>何にハマったのか</h2>
REST APIをnodemonで実行したら、モジュールエラーが発生した。

エラー文は以下。
```
Error: Cannot find module './index.ts'
```

<h2>解決法</h2>

<h3> 1. 「npm uninstall nodemon」でアンインストール。</h3>
→解決方法とまではいかないが、理由としてはモダンなツールではないらしいので。
というよりも、ググって出てきた方法では解決できなかった。

<h3> 2. 「npm i ts-node-dev」でインストール</h3>
→これがnodemonよりモダンらしいので導入。

<h3> 3. 「npm i --save-dev tsconfig-paths」もインストール</h3>
→これも一緒にインストールしないと、パスエイリアスが通らないのでインストール。

<h3> 4. 「package.json」に追記</h3>

 ```php:package.json
"scripts": {
    "start": "ts-node -r tsconfig-paths/register ~/ディレクトリ名/index.ts",
    "dev": "ts-node-dev -r tsconfig-paths/register ~/ディレクトリ名/index.ts",
    "build": "tsc"
}
```
上記のように、「ディレクトリ名」の前にホームディレクトリを表す「~/」から、フルパスで記入した。
この方法で、実行時の「Error: Cannot find module」のエラーは発生しなくなった。

<h3>環境</h3>
クライアントOS: macOS Monterey 12.04

サーバーOS: Linux (debian10)

ts-node-dev: ver2.0.0
ts-node: ver10.8.2
typescript: ver4.7.4
<h2>参考</h2>

ts-node で path alias が効かないにハマる
https://chaika.hatenablog.com/entry/2021/12/20/083000
anyenvでrbenvをインストールしても動かなかった話(pyenvの影響)

## 結論

2022/7/12現在、anyenvを通してpyenvをインストールすると、その他の一部のenvコマンドが `command not found` になる。
`anyenv init -`のコードで、pyenvの設定より下になっているものが問題。

以下でissueが起票されているので、治るのを待つ。

https://github.com/anyenv/anyenv/issues/101

## 環境

MacOS 12.4
anyenv 1.1.4 (brew経由でinstall)

## 経緯

- 2022/7/8に、rbenvをインストールしてrubyを使っていた。これは問題なく動いていた。
- 2022/7/11に、pyenvをインストールしてpythonをダウンロード。
- 2022/7/12に、rbenvを使おうとすると、 `command not found`が発生。

このあと、rbenvを再インストールするが解決せず。
`exec -l $SHELL` を実行すると治る（rbenvが使えるようになり、$PATHにrbenvが追加される)ので、
`eval $(anyenv init -)`が問題と推測。

`anyenv init -` を実行すると、pyenvの記載に違和感があり、issueを探すと上記issueを発見した。

## 対応

pyenvを一旦アンインストールし、rbenvを再インストール。
必要になったときはpyenvはbrew経由でインストールして使う予定。

## 今後のために

使っているリポジトリのissueは読んだ方がいい。
Airflow資料抄訳(8)：データ区間（Data Interval）

恥ずかしながら最近になって知ったワークフローエンジン [Apache Airflow](https://airflow.apache.org/)。日本語の紹介記事もちらほら出てきていますが、[公式ドキュメント](https://airflow.apache.org/docs/)をちょっとずつ抄訳しながら読んでいこうと思います。

8回目の今回は[データ区間](https://airflow.apache.org/docs/apache-airflow/stable/dag-run.html#data-interval)（Data Interval）。
バージョン2.3.3時点のものです。

---

# データ区間（Data Interval）

各DAG Runはそれが処理する範囲を表す「データ区間」を充てがわれています。例えば`schedule_interval`引数で`@daily`（`0 0 * * * `と同義）というスケジュールを指定されたDAGの場合、そのデータ区間は各日の同日00時に始まり翌日の00時に終わるといった具合です。

DAG Runはふつう紐づけられたデータ区間が終わった後にスケジュール実行されます。これは当該の実行中にデータ区間の範囲のデータを漏れなく処理対象にするためです。別の言い方をすれば、2020-01-01 のデータ期間を処理対象とするDAG Runは2020-01-01が終わり2020-01-02 00:00:00以降となるまでは起動しないということです。

Airflowで使用する各種の日時情報はすべて何らかのかたちでこのデータ区間の概念に結び付けられています。例えばDAG Runの「論理日付」（logical date。Airflow バージョン2.2以前は`execution_date`と呼ばれていました）は、DAGが実際に実行された日時ではなくデータ区間のスタートの日時を示します。

これと同様に、DAGとそのタスク群の`start_date`は皆同じ論理日付を指します。この値はDAGのタスクが実行され始めた日時ではなく、DAGの一連のデータ区間の中でも最初のものの開始日時を示します。別の言い方をすれば、DAG Runは`start_date`のあと1データ区間分の時間が経過したあとにスケジュール実行されるわけです。

:::note info
Tip
`schedule_interval`引数がDAGのスケジュール、論理日付、あるいはデータ区間の定義に役不足な場合は、[Timetables](https://airflow.apache.org/docs/apache-airflow/stable/concepts/timetable.html)をご覧ください。`logical date`についてより詳しくは「[DAGを実行する](https://airflow.apache.org/docs/apache-airflow/stable/dag-run.html#data-interval)」や 「[execution_dateが意味するもの](https://airflow.apache.org/docs/apache-airflow/stable/faq.html#faq-what-does-execution-date-mean)」をご覧ください。
:::

---

1つ前の記事「[DAGを実行する（Running DAGs）](https://qiita.com/mizukyf/items/20cafca6cc929ad8c4df)」に続いてDAG実行の理解に欠かせない日付概念について見てきました。
データ区間（Data Interval）は日時を示す概念の中で中核に位置するもので、ドキュメントの中でもそこら中に登場するので、ここをきちんと理解しておかないといけません。。
Laravelテストの基本

## テストクラスの置き場所

- testsディレクトリ下
    - Feature
        - 機能テスト用
    - Unit
        - メソッド単位のテスト用
        - こっちのテストはアプリが起動されないので、DBにアクセスできない

## コマンド

### テストクラス作成

```
php artisan make:test クラス名
```

### すべてのテストを実行

```
php artisan test
```

### テストクラス実行

```
//Featureディレクトリに対象ファイルがある場合
php artisan test tests/Feature/テストクラス名.php
```

## 他にもtipsがありそう

- [CPUコアの数だけ並列実行してテスト時間を削減](https://readouble.com/laravel/9.x/ja/testing.html#:~:text=on%2Dfailure-,%E3%83%86%E3%82%B9%E3%83%88%E3%82%92%E4%B8%A6%E5%88%97%E3%81%A7%E5%AE%9F%E8%A1%8C,-Laravel%E3%81%A8PhpUnit)
- [データベースシーダでテストレコードをまとめて用意](https://readouble.com/laravel/9.x/ja/database-testing.html#:~:text=%3D%3E%20fake()%2D%3Eparagraph()%2C%0A%20%20%20%20%5D%3B%0A%7D-,%E3%82%B7%E3%83%BC%E3%83%80%E3%81%AE%E5%AE%9F%E8%A1%8C,-%E6%A9%9F%E8%83%BD%E3%83%86%E3%82%B9%E3%83%88%E4%B8%AD)

## 参考文献

[テスト: テストの準備 9.x Laravel](https://readouble.com/laravel/9.x/ja/testing.html)
[データベーステスト 9.x Laravel](https://readouble.com/laravel/9.x/ja/database-testing.html)
【unity】衝突判定を実装する

# はじめに
2Dにて衝突判定を実装したことはあるが、その際は特殊な方法（ダミーのオブジェクトをプレイヤーの周囲に配置して判定していた）で行っていた。
今回3Dにて衝突判定を行ったため、メモ。

# 内容
特殊なメソッドであるところの`OnCollisionEnter()`を実装する。
このメソッドは、メソッド名の通りアタッチされているオブジェクトの当たり判定の内部に別の当たり判定がぶつかった（正確には重なった）時に呼ばれるメソッドとなる。
```c#:衝突判定
    /// <summary>
    /// 衝突した際に呼ばれるメソッド
    /// </summary>
    /// <param name="collision">衝突したオブジェクトとの衝突情報</param>
    void OnCollisionEnter(Collision collision)
    {
        // タグが「objectA」のオブジェクトと衝突した場合
        if (collision.gameObject.tag == "objectA")
        {
            // ここに処理を書く
        }
        // 名前が「objectB」のオブジェクトと衝突した場合
        else if (collision.gameObject.name == "objectB")
        {
            // ここに処理を書く
        }
    }
```

# 詳細
上のコードを見ていただければおそらくわかっていただけるだろうが、一応説明をしておく。
`collision.gameObject`にてオブジェクトを取得し、そのタグや名前にて絞り込みを行って、衝突したオブジェクトを特定している。
（ほかにも絞り込みの方法がある可能性もあるが、ここでは割愛させていただく。）

# まとめ
これで衝突判定を行う際に、衝突したオブジェクトによって処理を変えることができるようになる。

# 参考文献
- [Unity Tag（タグ）を使った衝突判定とボール落下位置の調整](https://3dunity.org/game-create-lesson/action-pazzle-game/tag-collision-judgement/)
【Flutter】TextFieldのHintTextを常時表示する

# ヒントテキストをテキスト入力に合わせてゴニョゴニョしたい
ヒントテキストを使って気の利いたUIを作りたい。
ただ、Flutter標準のTedtFieldだと、テキスト入力があるとHintTextは消えてしまう。
常時表示が出来ない。

だったら、ダミーのTextを上から被せてみよう。
さらに、テキスト同士が重ならないように、テキスト入力に合わせて、ヒントテキストもオフセットさせる。

# 作ってみた

![スクリーンショット 2022-07-12 23.01.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535406/1dd9f522-911a-a07f-262b-a8690c8d73b7.png)
簡単に実装してみたら、イイ感じ。
あとはゴニョゴニョするだけ♪

DatPadで動作確認できます。

https://dartpad.dartlang.org/?id=5a83011914cfad90ef4a03beea9f5568

# ソース

```
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _title,
      home: Scaffold(
        appBar: AppBar(title: const Text(_title)),
        body: Center(
          child: InputDecoratorExample(),
        ),
      ),
    );
  }
}

class InputDecoratorExample extends StatefulWidget {
  @override
  InputDecoratorExampleState createState() => InputDecoratorExampleState();
}

class InputDecoratorExampleState extends State<InputDecoratorExample> {
  TextEditingController _textController = TextEditingController();
  String inputText = '';

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        TextField(
          controller: _textController,
          decoration: InputDecoration(
            border: OutlineInputBorder(),
          ),
          onChanged: (value) {
            setState(() {
              inputText = value;
            });
          },
        ),
        IgnorePointer(
          child: SizedBox(
            height: 50,
            child: Align(
              alignment: Alignment.centerLeft,
              child: Row(
                children: [
                  SizedBox(width: 12),
                  Opacity(
                    opacity: 0,
                    child: Text(
                      inputText,
                      style: TextStyle(
                        color: Colors.grey[600],
                        fontSize: 16.0,
                      ),
                    ),
                  ),
                  if (inputText != '') SizedBox(width: 6),
                  Text(
                    'Name',
                    style: TextStyle(
                      color: Colors.grey[500],
                      fontSize: 16.0,
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ],
    );
  }
}
```
Datadog Logsのよく使うログ検索構文をまとめてみた

## はじめに

Datadog Logsのログの検索方法についてまとめてみた記事です。
特定のログを抽出するうえで、よく使う検索条件をまとめました。

## Datadog Logsとは

その名の通り、ログの収集、処理、監視等が出来るDatadogの機能の一つです。
「Live Tail」を使えばリアルタイムにログ監視をすることが可能ですし、ログを基にメトリクスを作成したり、ログの各項目に対する分析を行うことが可能です。

<https://docs.datadoghq.com/ja/logs/>

## 検索構文の例

公式ドキュメント内、[ログ検索構文](https://docs.datadoghq.com/ja/logs/explorer/search_syntax/)を参考にしています。

### 仮定

スロークエリログを分析するというシーンを想定し、以下二つの属性を仮定しています。

- スロークエリが発生したSQL文：`sql_text`
- クエリの実行秒数：`query_time`

## 文字に対する検索

- 完全一致で特定のクエリを検索する場合

`@sql_text:"検索ワード"`

- 前方一致、後方一致で特定のクエリを検索する場合、ワイルドカード「*」を利用

`@sql_text:*検索ワード`
`@sql_text:検索ワード*`

- 特定の文字を除外する場合、「-」を付ける

`-@sql_text:*除外したいワード*`

## 数値に対する検索

- 5秒から10秒のクエリを検索する場合

`@query_time:[5 TO 10]`

- 10秒以上のクエリを検索する場合

`@query_time:>10`

## 積の確認

- 10秒以上かつ`UPDATE*`のクエリの場合

`@query_time:>10 AND @sql_text:UPDATE*`

## 和の確認

- `UPDATE`か`DELETE`のクエリの場合

`@sql_text:UPDATE* OR @sql_text:DELETE*`
React18で追加されたAutomatic Batchingとは

先月ついにReact18の正式版がリリースされました。
今回のリリースで追加された機能をコード付きでざっくり解説していきたいと思います。

紹介する機能は公式のReact Blogの下記記事に掲載されているものとなります。

https://reactjs.org/blog/2022/03/29/react-v18.html

## Automatic Batching

`useState`を使った下記のようなコードがあるとします。

```jsx
function Sample1() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  const increment = () => {
    setCount(count + 1);
    setFlag(!flag);
  };

  console.log("rendering");

  return (
    <div className="App">
      <button onClick={increment}>increment</button>
      {`count: ${count}, flag: ${flag}`}
    </div>
  );
}
```

`increment`関数を呼び出すと`setCount`,`setFlag`でそれぞれ`count`,`flag`の状態を更新します。
2つの`state`が更新されますが、再レンダリングは1回のみとなります。
![sample1_1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215011/de2fdb96-d96b-37f9-a55a-e57a1594249b.gif)


React18以前でもReactのイベントハンドラ内の複数の状態の更新は、バッチ処理として一回の再レンダリングにまとめてくれています。
ただし、下記のような`setTimeout`や`Promise`のようなイベント内での更新はバッチ処理に対応していませんでした。

```jsx
function Sample2() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  const incrementTimeout = () => {
    setTimeout(() => {
      setCount(count + 1);
      setFlag(!flag);
    }, 100);
  };

  console.log("rendering");

  return (
    <div className="App">
      <button onClick={incrementTimeout}>increment</button>
      {`count: ${count}, flag: ${flag}`}
    </div>
  );
}
```

試しにReact17の環境で`incremant`関数を呼び出すと2回レンダリングされていることがわかります。
React18ではこのような場合でもバッチ処理を行ってくれるようになりました。

|React17|React18|
|----|----|
|![sample2_1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215011/2f8616ed-1833-93c4-e36f-eb07828815a3.gif)|![sample2_2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215011/8d4c2307-7774-ff20-2e42-bb5e9adf3cdf.gif)|
「だから言ったじゃん」を封印しよう

# 「だから言ったじゃん」はいつもそこに
ウォーターフォールが染み付いたメーカーで、アジャイルな体質に変えていけないかと日々模索しております。
その中で僕は、最近表題の言葉を封印しようと思い立ちました。

> 「だから言ったじゃん」

アジャイルを意識していると、日々のイテレーションの中で、小さな違和感に気づきやすいと思います。それがあまりにも小さい場合、ウォーターフォール的思考の周囲の人からしたら、「ささいなこと」「まだ大丈夫」のように流されてしまうことも。そして時間がたち、小さな違和感が大きな問題になったとき、みんなで大慌てすることになるのです。

アジャイルな皆さんなら、「だから言ったじゃん」と一言添えて、颯爽と問題解決に取り組むのではないでしょうか？（偏見）
僕は、半ば鉄板ネタのような気持ちで何度も口にしてきました。

# 「だから言ったじゃん」は何も生まない
しかし、その「だから言ったじゃん」は慌てふためく皆さんをムキーッと怒らせ、日々漫然と生きている皆さんの頭をハテナ（え、そんな話あったっけ？）で埋めます。言ったところで、自分はわかっていた、自分は賢い、自分は先見の明がある、といった自己満足のみで、生産性は皆無なのです。

そもそも、小さな違和感の時点でなぜ潰せなかったのでしょうか。反省の余地大有りです。逆に、自分はわかっていたのに何もしなかった、と誇らしげに言っているようなものです。**「だから言ったじゃん」の矛先は、実は過去の自分なのです。**

# 「だから言ったじゃん」と言えないようにしよう

そうですね。もうやめましょう。

未来の自分が「だから言ったじゃん」と言えないように、その時その時自分で考えられる最善の策を講じていきましょう。

小さな最善の策が繰り返され、組織は少しずつアジャイルになっていくと信じて。
PhpstromにXdebugを導入する

# 環境概要

```
Summary
Xdebug installed: no
Server API: Command Line Interface
Windows: no
Zend Server: no
PHP Version: 7.4.5
Zend API nr: 320190902
PHP API nr: 20190902
Debug Build: no
Thread Safe Build: no
OPcache Loaded: yes
Configuration File Path: /usr/local/etc/php/7.4
Configuration File: /usr/local/etc/php/7.4/php.ini
Extra Configuration Files Path: /usr/local/etc/php/7.4/conf.d
Extra Configuration Files:
/usr/local/etc/php/7.4/conf.d/ext-opcache.ini
Extensions directory: /usr/local/lib/php/pecl/20190902
```

# 手順


# php.iniからXdebugのインストール手順を把握する

下記の記事を参考に、
xdebug.orgでXdebugのインストール手順を把握する

https://qiita.com/camomile_cafe/items/7a91aa177bffd9402fb1

`php -i > phpinfo.txt `でphp.iniに書かれている内容を書き出し、
その内容をxdebug.orgに転記する。


## 具体的なインストール手順

1. Download xdebug-3.1.5.tgz
2.Install the pre-requisites for compiling PHP extensions.
　On your Mac, we only support installations with 'homebrew',
 and `brew install php && brew install autoconf` should pull in the right packages.
3. Unpack the downloaded file with tar -xvzf xdebug-3.1.5.tgz
4. Run: cd xdebug-3.1.5
5. Run: phpize (See the FAQ if you don't have phpize).

As part of its output it should show:
```
Configuring for:
...
Zend Module Api No:      20190902
Zend Extension Api No:   320190902
```
If it does not, you are using the wrong phpize. Please follow this FAQ entry and skip the next step.

6. Run: `./configure`
7. Run: `make`
8. Run: `cp modules/xdebug.so /usr/local/lib/php/pecl/20190902`
9. Create /usr/local/etc/php/7.4/conf.d/99-xdebug.ini and add the line:
zend_extension = xdebug


https://www.karakaram.com/phpstorm-xdebug/
Figmaで擬似的にファイル内検索コマンド「⌘F」を使う方法（Mac）

:::note
2022年10月からFigmaで公式にファイルない検索・置換がサポートされたので、現在は特に対応せずとも「⌘F」を利用できるようになっています。
Ref https://releases.figma.com/2022/10/we-now-support-find-and-replace.html
:::

## はじめに

Figmaでデザイン上のテキストやレイヤー名で検索をかけようとしてついつい「`⌘F`」を押したことはありませんか？

私は頻繁にあります！
しかし、現時点のFigmaにはレイヤー名やデザイン内のテキストを検索する機能は（私の知る限りは）用意されていません。

そのため、「`⌘F`」を押しても何も起こりません。

しかし、「[Find and Replace](https://www.figma.com/community/plugin/735072959812183643)」というプラグインにショートカットを設定することで、「`⌘F`」でファイル内検索をすることができるようになります！

## 「Find and Replace」とは

「Find and Replace」とは、FigmaのCommunityで公開されているプラグインです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577501/cc2e3467-9810-869f-edd8-93201c54205c.png)|
-|
https://www.figma.com/community/plugin/735072959812183643/Find-and-Replace|

本来はテキスト置換のためのプラグインですが、Figma上のテキストやレイヤー名の検索ができて、さらに前後に移動できるので私はファイル内検索としても愛用しています。

### プラグインの使用方法

1. プラグインを起動する
1. Figma上のテキストを検索したい場合は「Text タブ」、レイヤー名を検索したい場合は「Layer Name タブ」を選択する
1. 「Find」に検索したいワードを入力する
    - 右のメニューを開くと、文中でのテキストの位置や選択中のFrame内での検索などの検索オプションを設定できます
1. `Enter`、`Shift + Enter`で検索結果を前後に移動できます :sun_with_face:
1. テキスト置換をする場合は、「Replace with」に置換したいテキストを入力し「Replace」または「Replace All」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577501/b4b41aea-3a73-f2be-2928-a9d4c086ae7f.png)

## ショートカットの設定方法

1. 「Find and Replace」プラグインを有効にする
1. Macのシステム環境設定を開く
1. 「キーボード」->「ショートカット」->「アプリケーション」を開き、左下の「＋」をクリック
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577501/f98e05f7-4109-b3bc-c6c4-af7b01943224.png)
1. ショートカットの情報を入力
    - アプリケーション：`Figma.app`を選択
    - タイトル：「Plugins->Find and Replace」と入力
    - キーボードショートカット： `Command+F`を入力し、`⌘F`と表示されればOK
    - 「追加」をクリック
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577501/7bb076be-373c-6406-a222-e81baa2037ed.png)
1. Figmaで「Command + F」を入力して「Find and Replace」が起動されれば完了です :tada:

Macのショートカット作成の公式ヘルプはこちら⬇️


https://support.apple.com/ja-jp/guide/mac-help/mchlp2271/mac
エンジニア成長記#1

7月11日(月)
本日の経験

・githubの基礎知識

ワークツリー→インデックス→リポジトリ
(作業環境)　→(準備場所)　→(コミット場所)
clone：github上のリポジトリをローカルに複製する。
add:ワークツリーからインデックスに登録すること
push:ローカルリポジトリの内容をリモートリポジトリにアップロードすること。

インデックスの役割：変更点をいきなりコミットすると更新されてほしくない箇所も更新する恐れがある。色々変更を加えたけど、ファイルAとBを変更したとき、Aだけコミットしたいことがあるとする。インデックスにAだけを登録することで、変更して欲しいファイルだけコミットすることができる。

プルリクエスト：自分のコードを見てもらいレビューしていただくためのリクエスト。
・wslの環境構築
・Dockerの環境構築

・コマンドの利用
make：Linuxにおいてソースファイルをコンパイルするのに必須のコマンド。実際にはコンパイルだけでなくソースファイルの管理など、さまざまな役割を担っている。
git：git操作を行うコマンド
setup：デバイスとファイルシステムの初期化を行い、√ファイルシステムのマウントを行う。
ls フォルダ内の内容をリスト形式で表示
mv 移動元ファイル/フォルダ 移動先ファイル/フォルダ
cp コピーしたいファイル/フォルダ 移動先ファイル/フォルダ：コピーする
clear 消さずに画面をきれいにする
mkdir フォルダ名：フォルダを作成
touch ファイル名：ファイルを作成する
rmdir フォルダ名：空のフォルダを削除する


・オプション・引数の利用(コマンドにくっつける条件)
-v(--version)：バージョン確認

・その他単語
ビルド：プログラミング言語で書かれたソースコードなどを元に実行可能ファイルや配布パッケージを作成する処理や操作のこと。
vendor：開発者側(売る側)のこと

覚えることがあまりにも多すぎて当然不安はあるが、先輩方が丁寧に教えてくださるので、経験を積みながら自然と覚えていき、慣れるように必死に頑張りたい。
【#27 エンジニア転職学習】DB入門　テーブル設計

# はじめに
富山県に住んでいるChikaといいます。
毎日投稿を目標に、バックエンドエンジニア転職に向けた学習内容をアウトプットします。

DBの入門をざっくり学習していきます。

バックエンドエンジニアになるまでの学習内容は以前投稿した以下の記事を基にしています。


https://qiita.com/Chika110/items/ef54dddd565a0193ef44

# 本日の学習内容
本日はRDBMのテーブルおよびその設計に関して学習しました。

* テーブル
* **テーブル設計の基本ルール　←Topics!!**
* 正規化

# テーブル設計の基本ルール
RDBではすべてのデータがテーブルに保存される。それらの整合性を高めるために設計ルールが決まっています。
基本的なルールは下記のとおりです。
* 最も上位の概念集合にまとめる
* 「列」では個体の「属性」を表す
* 必ず主キー（PrimaryKey）を設定する
* 定義を途中で変えるリスクがない設計にする

使用している教材はこちら↓


https://www.amazon.co.jp/%E3%81%8A%E3%81%86%E3%81%A1%E3%81%A7%E5%AD%A6%E3%81%B9%E3%82%8B%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E3%81%8D%E3%81%BB%E3%82%93-%E3%83%9F%E3%83%83%E3%82%AF-ebook/dp/B00TTRZFDC/ref=tmm_kin_swatch_0?_encoding=UTF8&qid=1657112653&sr=8-1


# おわりに
最後までお読みいただきありがとうございました。
アドバイス・応援コメント等いただけますと幸いです。
DNSの勉強始めました

まずは用語の整理

### ドメイン空間
.comや.jp等のトップレベルドメインを含む「ドメイン」で表現されるツリー構造の全てを表現する言葉

##### ゾーン
 ゾーンはドメイン空間の中の一部を表す言葉。example.jpゾーンは/jp/example配下の空間を表現する。

### ネームサーバ
ドメインを問い合わせると、紐づけられた情報を返却するサーバの総称。主として二つの機能を持つが、どちらも同じプロトコルを用いる

#### 権威サーバ
ゾーンについての一次情報を返却する。

#### キャッシュサーバ
自身ではゾーンを管理せず、他のDNSサーバ(権威サーバまたはキャッシュサーバ)に再問合わせを行い、結果を返却する。
一度問い合わせた結果は「一定時間」保持し、再度問い合わせを受付けた場合は別のDNSサーバに問い合わせることなく、有効期限内のゾーン情報を返却する。
キャッシュの機能を持たず、再問合わせを行うシステムは特に「リゾルバ」と呼ばれる。


### ラベル
63バイト以下
ドメイン名の最小構成要素。
[名前] == [ラベル].[ラベル].[ラベル]

### 名前
255バイト以下

### TTL
符号付32bitの整数。正の値に限定される。(なんで符号付なんや……)

### UDPメッセージ
512バイト以下

### リソースレコード(RR)
特定のドメイン名における情報。実際にDNSをユーザが使用する際にはここを参照する事を目的にしている事が多い。
一つのRRは少なくとも[タイプ][クラス][TTL]の三要素以上で構成される

##### タイプ
###### A
一番よく使うアレ。ドメイン名とIPアドレスを直接紐づける。IPv6はAAAAを用いるが今回はIPv4を考えるため気にしない。

###### CNAME
昔はよく使ったアレ。Aレコードに対してシンボリックリンクのように別名をつけるのに使う。
一つのIPアドレスに対して複数のAレコードが設定できるため、実はあまり使い道が無い。

###### HINFO
ホストが使用するCPUとOSを表現する。こんなの使ったことない。

###### MX
電子メールのエクスチェンジを設定する。MXレコードはさらに優先度を設定する。数値が小さいほうが優先のため、優先度0が最優先。

###### PTR
別のゾーンを含む、ドメイン名空間の別の場所へのポインタ(これではちょっと意味が分からない……)
一般的には逆引きアドレスを表現するのに用いられる。

###### SOA
このRRが所属するゾーンの情報が記載される。
```SOAレコード
 [権威サーバ(MNAME)] [管理者メールアドレス(RNAME)] (
    [シリアル(SERIAL)]
    [リフレッシュ時間(REFRESH)]
    [リトライ時間(RETRY)]
    [有効期限(EXPIRE)]
    [ネガティブキャッシュの有効期限(MINIMUM)]
)
```

- **SERIAL**: 大きければ優先。整数のみ
- **REFRESH**: ゾーン情報の有効期限
- **RETRY**: REFRESHが失敗した場合、何秒後に再取得を試みるか
- **EXPIRE**: REFRESHが失敗した場合、何秒間古い情報を持ち続けるか
- **MINIMUM**: 存在しないドメインについての情報について「存在しない」という情報を何秒間持ち続けるか

##### CLASS
プロトコルを指定する。インターネット用にはINが用いられるので、普段見るのはINのみのはず。

###### IN
インターネットシステム。よく見る。

###### CH
CHAOSシステム。
ちょっと意味が分からないので後でもうちょい調べる。


---

今回の目的はGSuiteの無料版使ってて個人利用申請し忘れてたので、自前でサービス作るのに必要かな、というところなのでこの辺で。
MX,A,NSとラベル,RRの概念を理解できれば大丈夫。

でもDKIMとかSPFもDNS使った技術なのよね。
この辺はDNSというより電子メール関連の技術扱いなのか。
石膏ボード(3×6）の必要枚数を計算する

# 初めに
建設業界で働いていると図面から必要な建材の拾い出しを行わなければならない場面があります。

タイトルにある石膏ボードもその一つで、

必要な枚数を拾い出そうとすると、まあとにかく面倒くさい。

そこで普段電卓でしていることをそのままコードにしました。

それでは聞いてください。

```python:code
#CHが1820に満たないとき
import math
def PB(ch,width):
    x = math.ceil(width /910)
    if ch <= 1820:
        num = 1820 // ch
        #PBの余りが足りないとき
        if num <= 1:
            PB_num = x
        elif num >= 2:
            PB_num = x / num
            
    elif ch > 1820:
        #余っている分を考える
        y = ch % 1820
        y_num = ch // 1820
        #下の数を考える
        PB_num = x * y_num
        
        #合計
        num = 1820 // y
        PB_num += math.ceil(x / num)
    return print(PB_num)

```
ffmpeg 画面録画 Windows

Windows サウンドカード名の取得（ステレオ ミキサーのほう）
<pre>ffmpeg -list_devices true -f dshow -i dummy</pre>

ディスプレイサイズの取得（エラーログから取得）
<pre>
ffmpeg -video_size 99999x99999 -f gdigrab -i desktop display_size.mp4
</pre>

画面録画（音声付き）
<pre>ffmpeg -video_size 1920x1080 -framerate 16 -f gdigrab -i desktop -f dshow -i audio="ステレオ ミキサー (Realtek High Definition Audio)" -vcodec libx264 -pix_fmt yuv420p -map 0:v:0 -map 1:a:0 -y test.mp4
</pre>

マルチディスプレイの場合はoffsetを使用
<pre>ffmpeg -video_size 1920x1080 -offset_x 1920 -offset_y 0 -framerate 16 -f gdigrab -i desktop -f dshow -i audio="ステレオ ミキサー (Realtek High Definition Audio)" -vcodec libx264 -pix_fmt yuv420p -map 0:v:0 -map 1:a:0 -y test.mp4</pre>
jsonの要素を全て表示する方法

## 概要

JSONで値の取り出し方を毎回ググっているので、具体例を以下においておきます。

```javascript
var json = {
   one: [11, 12, 13, 14, 15],
   two: [21, 22, 23],
   three: [31, 32]
}

for(var key in json) {
  console.log(key);
   for (var key1 in json[key]) {
       console.log(json[key][key1])
   }
}
```

## 結果
```
one
11
12
13
14
15
two
21
22
23
three
31
32
```

## 参考
https://www.microverse.org/blog/how-to-loop-through-the-array-of-json-objects-in-javascript
Using Firebase SDK version '9.2.0' defined in 'firebase_core'

firebase_core等のSDK versionがアップデートされていますが、最新にしても

`Using Firebase SDK version '9.2.0' defined in 'firebase_core'`

エラーが自分は出ている [github issue](https://github.com/firebase/flutterfire/issues/9022)

このエラーは [fixしたはず](https://github.com/firebase/flutterfire/commit/bea70ea5cbbb62cbfd2a7a74ae3a07cb12b3ee5a) なのですが実行できないのでversionを下げます


以下のversionに合わせると動きます
SDK version '9.2.0'の一つ前SDK version '8.15.0'のlatestです

```
firebase_core: 1.18.0
firebase_auth: 3.3.20
firebase_analytics: 9.1.10
firebase_crashlytics: 2.8.2
firebase_performance: 0.8.0+14
firebase_remote_config: 2.0.9
firebase_messaging: 11.4.2
firebase_in_app_messaging: 0.6.0+16
firebase_dynamic_links: 4.2.6
firebase_database: 9.0.16
firebase_core_platform_interface: 4.4.1
```

おわり
AWS Certified Cloud Practitionerを受けて合格しました

先月の話になりますが、AWS Certified Cloud Practitionerを受験し、合格したのでふりかえってみました。

## 受けた試験について

https://aws.amazon.com/jp/certification/certified-cloud-practitioner/

AWSのプロットフォームに関するもっとも基礎的な試験で、クラウドへの理解と基礎的な AWS の知識について問われます。
対象者としては6ヶ月間触れていることなどとあります。

実務でもEC2をはじめとしていろいろ触っていたので、今回力試しのために受験してみることにしました。

## Cloud Practitionerから受験した理由

AWS資格の受験については、 [AWS Certified Solutions Architect - Associate](https://aws.amazon.com/jp/certification/certified-solutions-architect-associate/) を受験されている方が自分の観測範囲では多いように思いました。
実務的にも1年以上使ってきたので、最初は Solutions Architect Associate からの受験を考えていました。

しかし[Cloud Practitionerのサンプル問題](https://d1.awsstatic.com/ja_JP/training-and-certification/docs-cloud-practitioner/AWS-Certified-Cloud-Practitioner_Sample-Questions.pdf)を読んだところ、1、4、7、10番などの問題がさっぱりわかりませんでした。
これまで関わったことがなかったサービスや概念もあったので、一から体系的に学び直すことを決め、Cloud Practitionerを受験しました。

## 教材

今回、自分の中の新しいチャレンジとして、動画学習を取り入れてみようということで Udemy を試してみました。
動画教材としてはAWS公式のものもありますが、そちらは見ていないです（時間があるとき、比較のため今度見てみます）。

[【2022年版】これだけでOK! AWS認定クラウドプラクティショナー試験突破講座（豊富な試験問題290問付き）](https://www.udemy.com/course/ok-aws-e/)

また練習問題はこちらを解きました。

[【2022年版】この問題だけで合格可能！AWS 認定クラウドプラクティショナー 模擬試験問題集（7回分455問）](https://www.udemy.com/course/aws-4260/)

書籍も一応購入しましたが、上記の教材で大半を抑えられたので、ほとんど読みませんでした。

[AWS認定資格試験テキスト　AWS認定 クラウドプラクティショナー](https://www.sbcr.jp/product/4797397406/)

## 勉強のふりかえり

まず、教科書的なレクチャーメインである突破講座をすべて見ながら、ハンズオンも全部やってみました。
しかしながら模擬試験問題集での問題を解いたところ、6割程度の正解率にとどまり、合格基準であるスコア700に届いていないように思いました。

そこで何度も上記の教材の模擬試験問題集を解きながら、間違えた問題についてはメモを取りながら、記憶強化するようにしました。
何度も解きなおすうちに模擬試験問題集の正解率が上がっていきました。

これに関しては2点反省があります。

- 練習問題に触れるタイミングが遅く、問題を解けるほどの知識が十分についていなかったことを自覚するタイミングが遅かった
- 公式が用意している模擬問題や教材を生かせなかった

次回、上位試験を受ける際には、上記についてそれぞれ改善していきたいです。

- 練習問題は早めに解く
- 公式が用意している模擬問題は少なくとも解いておきたい

## 結果について

2022/6/12にテストセンターで受験し、862点で合格でした。自宅での受験も可能でしたが、ワンルームの家で何もない背景で、という環境を用意することが難しく、テストセンターにせざるを得ませんでした。
Udemyの模擬問題を1回目に説いた際は、一回も合格スコアに届いていそうな正解率ではなかったので、本番でよい結果が取れてよかったと思っています。


## 勉強してよかったこと

先日、検証用のサーバーを建てる機会があったのですが、EC2を手動でセットアップしました。
その際にVPCのセットアップや、EC2のセットアップ、EC2インスタンスサイズの選定などを行いましたが、今回Cloud Practitionerを勉強した知識が生かされ、スムーズに行えたと感じます。

勉強していてよかったなーと思っています。こちらの内容についても、公開していきたい内容なのでそのうち書きます。

## 最後に

元々、Solutions Architect Associateの受験を考えていたこともあり、8月に受験します。
[公式からのアナウンスもある通り](https://aws.amazon.com/jp/certification/coming-soon/) 、8/30から新しいテスト形式に移行するとのことなので、今の範囲のうちに合格したいです。
（そもそも過去に買った教材や資料が無駄になるのも勿体無いので、この機会を生かして受けます）

[サンプル問題](https://d1.awsstatic.com/ja_JP/training-and-certification/docs-sa-assoc/AWS-Certified-Solutions-Architect-Associate_Sample-Questions.pdf)を読んでいる限り、Cloud Practitionerよりも詳細なことが聞かれる印象ですが、頑張っていきたいです。
（勉強している感じ、Cloud Practitionerで学んだことも生きてきています！）
【JS、rails】要素の外側をクリックすると、その要素が閉じる

# 実装したいこと
クリックすると要素が変化し、要素外をクリックすると要素が元に戻るという機能を実装します。

今回の例は、自分のオリあぷに実装したものです。
検索フォームにホバーするとアンダーバーが表示されます。
検索フォームをクリックすると、アンダーバーの表示が維持されます。
検索フォーム以外をクリックすると、アンダーバーが消えます。
わかりにくいですがGifを参照ください。
https://gyazo.com/a36d20cbf9d2dd2b66f00d4b73b437b3
# 結論
JavaScriptを利用します。
```javascript:JavaScript
function search_box() {
  const search_box = document.querySelector("#search-box");   // クリックした時にイベントを発火させるための要素を取得
  if (!search_box) return null;  //　目的の要素がないページでは何も処理しないようにする。⇨ページの挙動がよくなる
  const line = document.querySelector(".search-form"); // 今回挙動を変えるターゲットを取得
  // ページをクリックした時の処理
  document.addEventListener("click", (e) => {　//クリックの時に発火
    // ifではクリックした要素（"document"）の親要素に("#search-box")があるかどうかを判定している
    if (e.target.closest("#search-box")) {
      // "#search-box";がある場合の処理
      line.classList.remove("search-form");
      line.classList.add("is-fixed");
    } else {
      // "#search-box";がない場合の処理
      line.classList.add("search-form");
      line.classList.remove("is-fixed");
    }
  });
}

window.addEventListener("load", search_box);
```
eとはイベントオブジェクトのこと。今回の場合、document(ページ全体のこと)をクリックした時に得られるさまざまな情報を含んでいる。どのような情報かというと、e.typeとすると発生したイベントの型を返し、e.timestampとするとイベントの発生時間を返す。e.targetはイベントの発生源を返すので、今回はdocumentのことを示す。要素.closest（"aaa"）は要素の親要素にaaaがあるかどうかを判定する。詳しくは参考サイトを参照。

以下はjsで取得した要素を載せたhtmlと、バーを表示させるため記述したcss。念の為置いておきます。
```ruby:html.erb
<%= form_with(url: search_rooms_path, local: true, method: :get, class: "search-form") do |form| %>
<%= form.button type:"submit",class: 'search-button' do%>
<i class="fas fa-search"></i>
<%end%>
<%= form.text_field :keyword, placeholder: "検索する", class: "input-box",id:'search-box',autocomplete: 'off',value:params[:keyword] %>
<% end %>
```
```css:
.search-form,
.is-fixed {
  margin-left: 20px;
  position: relative;
}

.search-form::after {
  position: absolute;
  left: 0;
  content: "";
  width: 100%;
  height: 2px;
  background: var(--font-color);
  bottom: -1px;
  transform: scale(0, 1);
  transform-origin: left top;
  transition: transform 0.5s;
}

/* js用に使用、クリックした際バーがずっと表示されるように */
.is-fixed::after {
  position: absolute;
  left: 0;
  content: "";
  width: 100%;
  height: 2px;
  background: var(--font-color);
  bottom: -1px;
  transform: scale(1, 1);
  transform-origin: left top;
  transition: transform 0.5s;
}

.search-form:hover::after {
  transform: scale(1, 1);
}
```

# 参考サイト
https://fuuno.net/nani/nani04/nani04.html

https://qiita.com/takkyun/items/c6e2f2cf25327299cf03

https://hirakublog.com/outside-click-event-js/

https://gxy-life.com/2PC/PC/PC20210923.html
【Laravel】orangehill/iseedが「No such file or directory」となる場合の対処

# orangehill/iseedとは
こちらのライブラリ
https://github.com/orangehill/iseed

DBデータからシーダーを生成してくれるというものです
[データベースからLaravelのSeederを逆生成する](https://qiita.com/imunew/items/3973658bdcae9ab77b8a)

が、しかし、、

# :cry:  orangehill/iseedが動かない...!!!

Laravel7.x以前だと、
実行するとそんなディレクトリ無いよと言われてしまう。。:tired_face:

```sh
# php artisan iseed tests

   ErrorException  : file_put_contents(/var/www/html/test/database/seeders/TestsTableSeeder.php): failed to open stream: No such file or directory
   # ↑ そんなディレクトリ無いよ！僕は知らんへんよ！ というエラー
```

# :thinking: どうすれば？
Laravel8.xを境にシーダーディレクトリ名が変わったことが原因:open_mouth:
* Laravel8.x以降：database/**seeders**
https://laravel.com/docs/8.x/seeding
* Laravel7.xまで：database/**seeds**
https://laravel.com/docs/7.x/seeding

config配下に個別の設定ファイルを作ってあげればおｋ！

```php:config/iseed.php
<?php
// vendor\orangehill\iseed\src\config\config.php の設定上書き
return array(
    'path' => '/database/seeds', // シーダーディレクトリ名を実態と合わせる
    'chunk_size' => 500
);
```


再実行

```sh
# php artisan iseed tests

File TestsTableSeeder.php already exist. Do you wish to override it? [yes|no] (yes/no) [no]:
> yes

Created a seed file from table tests
```

無事成功！！！

# :mag: 原因判明～対応策発見まで

orangehill/iseedのソースを見ると、
シーダーディレクトリ名が特定バージョンから変わっていた :scream:
https://github.com/orangehill/iseed/commit/cc311c44dc2976ed7ebf9b9cf6308453c8149180

<br>
<br>

oh,no...でも流石に決め打ちにはなってないっしょ。。！ :scream:
という仮説（願い）を胸に関連ソースを見ていると、
設定ファイルを別途設ければそちらに沿って動作するようになっていた！
https://github.com/orangehill/iseed/blob/master/src/Orangehill/Iseed/IseedServiceProvider.php#L66-L78

```php:vendor\orangehill\iseed\src\Orangehill\Iseed\IseedServiceProvider.php
    /**
     * Register the package resources.
     *
     * @return void
     */
    protected function registerResources()
    {
        $userConfigFile    = app()->configPath().'/iseed.php';
        $packageConfigFile = __DIR__.'/../../config/config.php';
        $config            = $this->app['files']->getRequire($packageConfigFile);

        if (file_exists($userConfigFile)) { // アプリケーション側のconfigにiseed.phpがあればそれを読み込んでるっぽい
            $userConfig = $this->app['files']->getRequire($userConfigFile);
            $config     = array_replace_recursive($config, $userConfig);
        }

        $this->app['config']->set('iseed::config', $config);
    }
```

# まとめ
* ライブラリ側のエラーだったとしても、以外に簡単に解決できることもある:sunglasses:
* ライブラリのソースも臆せずガリガリ読む！:smirk_cat:
目指したいエンジニアのふるまい

これまでいくつものプロジェクトや、チームの中で一緒に仕事をしてきた経験の中から自分も目指したいと思ったエンジニアのふるまいを書いてみたい。

### 日々のアウトプットが安定している
エンジニアには地道な作業が多い。日々の安定した継続的なアウトプットの確認の中でこそ、大きなテーマに向かっての前進や積み上げの確かな手応えを確認することができる。

最初の要件定義からアウトプットまで早く貫通させることが重要。
あとは同じように小さなタスクを1つずつ継続的にコンプリートすることで大きなゴールの達成に近づく。

あまりにも膨大で幅広い業務が全体的に進んでいるように見えても、小さな単位でのアウトプットが1つも出てきていない場合はキケン。何ヶ月も時間を費やした後に最終的に何も出てこない場合がある。

### 絡みあった問題点をそのまま報告するのではなくコア部分に単純化して問題解決しやすい形で報告できる
複雑な問題を解決する時に予め問題箇所を絞り込み、切り分けを行うことが重要。余分な条件を除外してミニマムに問題を再現することができれば、問題を簡単に共有でき、解決までの道のりを最短化できる。

### 問題解決時に簡潔なレポートとエビデンスを添付してくれる
問題の調査解決をタスクとしてアサインされた場合、問題の再現手順と解決のエビデンスを簡潔にレポートにまとめて報告できることの価値は高い。

解決の報告を受けた側が同様の手順の再現と問題解決の確認を行う手間が大幅に短縮できる。
解決したつもりでも実は解決していなかったという手戻りを回避することができる。
解決した側も後で同じような問題が再発した時に自信を持って既に解決した根拠を瞬時に示すことが可能になる。

### チームや同僚が遭遇するであろう問題や必要な手順をすぐWikiなどのドキュメントにまとめて共有してくれる

チームで仕事をしていると色々な場面で同じ問題に遭遇する。
開発環境導入、アプリケーションのビルド、リリースオペレーションなど様々な場面で同じ手順を実行する場面も多い。
個人のメモの代わりに各人が共有場所にメモを残すことで、チームの生産性が大きく向上する。

### チームメイトの経験や成長につながるような報告ができる
チームメンバー同士が互いに積極的に情報をシェアすることでチームの経験値が何倍にも膨らむ。
レビューを通して問題を一緒に解決し、合意にたどり着くプロセスを何度も繰り返す共同体験はエンジニアキャリアの宝にもなる。

引き続き目指したいエンジニアのふるまいについて書き溜めていきたいと思います。
過去の自分にも伝えたい。
HottyDB（検索エンジン＋レコメンド＋RDBMS）のレコメンド機能の使い方

# この記事の概要
HottyDB（検索エンジンとレコメンドエンジンを搭載したRDBMS）という、筆者が個人開発したソフトウェアのレコメンド機能について紹介したいと思います。

前回の記事でHottyDBの概要と検索エンジン機能について解説しているので、そちらも是非参照してみてください！

https://qiita.com/toru1055/items/0fe400989373823e9c78

# レコメンド機能
この機能では、「この商品を購入した人は、この商品も購入しています」や「この記事にイイネしている人は、この記事にもイイネしています」などのアイテムベースのレコメンデーションを実現します。 SQL LIKEなコマンドで、これらを自動的に計算する使い方を紹介します。

## 前提
説明のため、「この記事にいいねしている人は、この記事にもいいねしています」というアイテムベースのレコメンデーションを実現するための例を紹介したいと思います。

事前に、下記のような「いいね管理テーブル(`likes`)」という「どのユーザーがどの記事にいいねしたか？」を管理するテーブルが作成されている前提で進めます。
```SQL
CREATE TABLE likes (uid INT, aid INT)
```

* `uid`: ユーザーID
* `aid`: 記事ID

## レコメンドインデックスの作成
アイテムレコメンデーションを実現するために、HottyDBではまずレコメンドインデックスを作成する必要があります。
レコメンドインデックスの作成コマンドは下記の通りです。

### CREATE RECOMMEND INDEXの構文
```SQL
CREATE RECOMMEND INDEX `インデックス名`
ON `テーブル名`
(`ユーザーIDのフィールド名`, `アイテムIDのフィールド名`)
```

### CREATE RECOMMEND INDEXの例文
`前提`で作成した`likes`テーブルにレコメンドインデックスを作成する場合、下記のようになります。
```SQL
CREATE RECOMMEND INDEX r1 on likes (uid, aid)
```

つまり、レコメンドインデックスの作成は、レコメンデーションの元となるデータテーブルの、どのフィールドがユーザーIDでどのフィールドがアイテムIDかをHottyDBに教えてあげることを指します。

これにより、HottyDBは「このアイテムを選択したユーザーは、このアイテムも選択しています」というレコメンデーションの関係性を学習することができます。


## 通常のINSERT
レコメンドインデックスを作成した時点では、まだレコメンデーションの関係性は学習されません。
レコメンドインデックスを作成したあとに発生した`likes`テーブルへの`INSERT`処理で逐次レコメンデーションが更新されていきます。


## レコメンデーションの推論
学習されたレコメンドインデックスから、レコメンデーションを取得しSELECT文で利用する方法を解説します。

### RECOMMENDメソッドの構文
```SQL
SELECT
    _item_id,
    _similarity
FROM RECOMMEND(`インデックス名`, `シードアイテムID`)
```

* `_item_id`: レコメンドアイテムのID
* `_similarity`: シードアイテムとレコメンドアイテムの関連度
* `インデックス名`: 作成したレコメンドインデックスの名前
* `シードアイテムID`: レコメンド元となるアイテムID

### RECOMMENDメソッドの例文
`記事ID=5`にいいねした人がいいねしている記事IDを関連度順で出力する場合
```SQL
SELECT
    _item_id,
    _similarity
FROM RECOMMEND(r1, 5)
ORDER BY _similarity DESC
```

> (注) RECOMMENDメソッドの出力は`_similarity`でソートされていません


以上のように、RECOMMENDメソッドは通常のテーブルのようにSELECT文で扱えるため、他テーブルとJOINすることなども可能となります。


## サンプルコード
以上のコマンドを実際に使ってみたJavaのサンプルコードはこちらです。
こちらも是非参考にしてみてください。

#### [＞＞レコメンドエンジン機能のサンプルコード](https://gitlab.com/hottydb/hottydb-sample/-/blob/main/src/main/java/org/example/RecommendEngine.java)


# フィードバックをお待ちいています！
HottyDBはまだ生まれたばかりのソフトウェアです。 

使い方に関すること、分かりづらい点、バグ報告や改善提案、機能の要望など、なんでもOKなので下記のいずれかの方法でフィードバックをいただけると助かります。

- このQiitaのコメント欄
- [お問い合わせフォーム](https://docs.google.com/forms/d/e/1FAIpQLSfyokt68QP4yq4774xFyDEO2DyvVKvnvpnKh5vhOfbRSA1wnA/viewform?usp=sf_link)
- [Twitter](https://twitter.com/hottydb)

https://www.hottydb.com/other/contact/
Atcoder解いてみた AGC 020 A - Move and Win

# AGC 020 A - Move and Win 解いてみた
問題は[こちら](https://atcoder.jp/contests/agc020/tasks/agc020_a)

## 回答
```C++
#include <iostream>

using namespace std;

int n, a, b;


int main() {
	cin >> n >> a >> b;
	if (n == 2){
		cout << "Borys" << endl;
		return 0;
	}

	if ((b-a+1) % 2 == 0) {
		cout << "Borys" << endl;
		return 0;
	}
	else if ((b-a+1) % 2 != 0) {
		cout << "Alice" << endl;
		return 0;
	}
}

```
PearsonVueで自宅受験する際のメモ

いくつか気付きを得たのでメモ　Microsoftの試験を一例に書きます

PearsonVueにより提供される試験ソフトOnVueはAutodeskの認証ソフトや、Chrome remote desktopなどを停止しないと進めません。事前にテストしておきましょう。
タスクマネージャーのServiceタブのdescription項目を見て、該当するものを右クリック, stopを押して停止させましょう。
ブラウザや、Nvidia broadcastなどはつけたままでも大丈夫でした。

実例としてMicrosoft社の資格認定試験では、設定した受験日の24時間前まで受験のキャンセルやリスケジュールを行うことができます。
受験日を遅めに設定し、都合で早めることが可能なので、来週受けるつもりだったけど明日にリスケしてしまおう　ということが可能でもあります(再指定する日程は翌日以降である必要があることは注意ですし、その日程が空いてるとは限りませんが)
LPIの試験などは数時間前でもリスケ可能だったりするので、同じPearsonVue試験でもだいぶ違いがあります。

リスケジュールはダッシュボードから可能です。
サインインしている状態で、https://docs.microsoft.com/en-gb/　
の右上アイコンからprofileページへ行き、そこの左にあるCertifications項目から、PearsonVueに飛ぶことが可能です。　
そもそもPearsonVueのサイトからベンダー別サイトに飛ぶことができます。

身の回りにおいてよいものは透明なボトルにいれた水、パスポートとPCと周辺機器です。スマートフォンはチェックイン後、手の届かない範囲におく必要があります。
サブモニターは許可されず、時計の着用も禁止になっています。
オーディオのチェックが入りますが、受験時はイヤホンの着用を禁止されており、チャットでは解決できない問題が発生した場合など、試験官から指示があってから着用することになります。スピーカーなら問題ありません
どの会社のものでも受験中はフルスクリーンで試験が表示され、windowsのタスクバー右下の時計などを見ることはできませんが、右上に残り時間と、解いた問題数/総問題数　が表示されます。
前の問題に戻れるかどうかは試験を実施している会社次第です。
実施会社によっては、日本語で受験していても英語表記(原文表記)に切り替えることが可能です(LPI,Microsoftの試験は可能、Ciscoは現状不可 その他不明)
早く終了することが可能で、スコアは即座に表示されますが。OnVueを閉じるまでは記録されているのでスコアを取ろうとスマホなど使わないようにしましょう。スコアはPearsonVueでスコアレポートとして確認できます。


アクセスコードをコピーしてOnVueで試験開始すると、windowsのコピー履歴がオフにされる(アクセスコードのみペースト可能に)なるので、終了後再度履歴機能をオンにするのを忘れないように。
(Cisco試験ではホワイトボード機能を用いることができます。また、コマンドなど入力する欄がある場合、日本語入力にしているとIMEの変換予測が出てくるので注意してください。　記録が公表されているのはカメラ映像とマイク音声だと思いますが、試験画面も監視、録画されていた場合は変換履歴が出てしまうことでカンニングを疑われてしまうかもしれません。　対策としてはNDA表示前にチャットの入力欄でIMEを半角英数に切り替えておきましょう)
c#でlibyara その4

# 概要
c#でlibyaraやってみた。
練習問題やってみた。

# 練習問題
yaraルールを10個、集めよ。

# サンプルコード

```
rule WarningRule {
	strings:
		$error_str = /this.+?is.+?a.+?slow.+?regex/
	condition:
		$error_str
}

rule hw {
	strings:
		$a = "Hello"
		$b = "World"
		$c = {58 35 4f 21}
	condition:
		($a or $b) and $c
}

rule AsciiExample {
	strings:
		$ascii_string = "hello"
	condition:
		$ascii_string
}

rule UnicodeExample {
	strings:
		$unicode_string = "hello" wide
	condition:
		$unicode_string
}

rule HexExample {
	strings:
		$hex_string1 = { 0123456789ABCDEF }
		$hex_string2 = { 0123456789abcdef }
		$hex_string3 = { 01 23 45 67 89 ab cd ef }
	condition:
		$hex_string1 or $hex_string2 or $hex_string3
}

rule WildcardHexExample {
	strings:
		$hex_string1 = { 012345????ABCDEF }
		$hex_string2 = { 012345????abcdef }
		$hex_string3 = { 01 23 45 ?? ?? ab cd ef }
	condition:
		$hex_string1 or $hex_string2 or $hex_string3
}

rule OffsetExample {
	strings:
		$mz = "MZ"
	condition:
		$mz at 0
}

rule RangeExample {
	strings:
		$pe = "PE"
	condition:
		$pe in (32..100)
}

rule RelativeOffsetExample {
	strings:
		$mz = "MZ"
		$pe = "PE"
	condition:
		$mz at 0 and $pe in (@mz[0]..0x200)
}

rule IsPeFile {
	strings:
		$mz = "MZ"
	condition:
		$mz at 0 and uint32(uint32(0x3C)) == 0x4550
}

rule EntryPointExample {
	strings:
		$ep = { 55 8b ec }
	condition:
		$ep at entrypoint
}

rule ConditionsExample {
	strings:
		$string1 = "hello"
		$string2 = "hello"
		$string3 = "hello"
	condition:
		any of them
}

rule NumberStringsExample {
	strings:
		$hello = "hello"
	condition:
		#hello >= 5
}

rule RuleReference {
	strings:
		$hello = "hello"
	condition:
		$hello and IsPeFile
}


```

以上。
Airflow資料抄訳(7)：DAGを実行する（Running DAGs）

恥ずかしながら最近になって知ったワークフローエンジン [Apache Airflow](https://airflow.apache.org/)。日本語の紹介記事もちらほら出てきていますが、[公式ドキュメント](https://airflow.apache.org/docs/)をちょっとずつ抄訳しながら読んでいこうと思います。

7回目の今回は[DAGを実行する](https://airflow.apache.org/docs/apache-airflow/stable/concepts/dags.html#running-dags)（Running DAGs）。
バージョン2.3.3時点のものです。

---

# DAGの起動

DAGは次の2つのうちいずれかの方法で起動されます：

* 人手もしくはWebAPI経由の操作に基づく起動
* DAGの一部として定義されたスケジュールに基づく起動

DAG宣言にスケジュールは必須ではありません。しかしスケジュールがあるのがふつうです。スケジュールは`schedule_interval `引数を使って次のようにして指定します：

```py
with DAG("my_daily_dag", schedule_interval="@daily"):
    …
```

`schedule_interval`引数は妥当な [Crontab](https://en.wikipedia.org/wiki/Cron) スケジュール値であれば何でも指定できます：

```py
with DAG("my_daily_dag", schedule_interval="0 * * * *"):
    …
```
:::note info
Tip
`schedule_interval `の値についてより詳しくは[DAG Run](https://airflow.apache.org/docs/apache-airflow/stable/dag-run.html)を御覧ください。
DAGのスケジュール指定に`schedule_interval `では役不足のときは、[Timetables](https://airflow.apache.org/docs/apache-airflow/stable/howto/timetable.html) をご覧ください。`logical date`についてより詳しくは[データ区間](https://airflow.apache.org/docs/apache-airflow/stable/dag-run.html#data-interval) や [execution_dateが意味するもの](https://airflow.apache.org/docs/apache-airflow/stable/faq.html#faq-what-does-execution-date-mean)をご覧ください。
:::

DAGを起動とはすなわちDAGの新しいインスタンスの生成です。このインスタンスのことをAirflowでは[DAG Run](https://airflow.apache.org/docs/apache-airflow/stable/dag-run.html)と呼びます。DAG Runは同じDAGについて多重（並列）で起動することができます。それぞれのDAG Runはデータ区間を持ちます。これは当該DAGのタスクが処理するデータの期間を指し示すものです。

なぜこれが便利なのでしょうか？　例えば今あなたは日次の実験データの集まりを処理するDAGを作成しているとしましょう。それらのデータが書き換えられて、過去3ヶ月分のデータを処理し直さないとならなくなったとします。問題ありません。AirflowならDAG Runのコピーを過去3ヶ月の各日分をまとめて作成しデータを埋め戻す（backfill）ことができます。

これらのDAG Runはすべて同一の日時に起動しますが、それぞれのDAG Runは過去3ヶ月間の各日を範囲とするデータ区間（data interval）を持ち、そのデータ区間は当該DAGに含まれるすべてのタスク、オペレーター、そしてセンサーから参照されます。

DAGの起動の都度DAG Runが生成されるのとほとんど同じ方法で、DAG内の個々のタスクについても[タスク・インスタンス](https://airflow.apache.org/docs/apache-airflow/stable/concepts/tasks.html#concepts-task-instances)が生成されます。

DAG Runは開始日と終了日を持ちます。これはDAGが実際に実行された期間を示します。この日付情報とは別に、論理日付（logical date）という別の日付情報もあります。これはスケジュールもしくは人手／WebAPI経由で要求されたDAGの起動時刻を示すものです。「論理～」という呼び名は、DAG Run自体のコンテキストに応じて、複数の意味を持ちうるというこの日付の性質に由来します。

例えば、あるDAG Runが人手で起動されたとき、論理日付はそのDAG Runが起動された日時となります。そしてこの値はDAGの開始日と一致します。一方、DAGが所定の`schedule_interval`に基づき、スケジュール起動したとき、論理日付はデータ区間の開始日を指します。つまりDAG Runの開始日は論理日付＋`schedule_interval`となります。

---

タイトルとは裏腹に、このセクションで一番注目すべきなのは各種の日付の概念だと思います。
`logical date`は以前は`execution_date`と呼ばれていたそうで、Airflowについて学ぶときにはこの読み替えも知っておく必要があるでしょう。
このへんについてとくにデータ区間（data interval）を軸にまとめてくださっている[こちらの記事](https://note.com/dd_techblog/n/n54bba21c8598)がとても参考になります。
Ruby On Rails7.0.3でscssファイル適用時の'cannot load such file -- sassc'エラー

rails7.0.3でアプリケーション作成中に、'cannot load such file -- sassc'のエラーメッセージが...

調べてみると以前のversionはデフォルトでinstallされていた`gem "sassc-rails"`が、rails7からデフォルトでコメントアウトされているとのこと。

Gemfileを確認してみると46行目あたりに
```ruby:Gemfile
45 # Use Sass to process CSS
46 #gem "sassc-rails"
```
との記載が、これを以下のように修正

```ruby:Gemfile
45 # Use Sass to process CSS
46 gem "sassc-rails"
```
`bundle install`します。
その後サーバーを再起動すると、無事解決しました！
Resolver のクエリのログ記録を他アカウントのS3バケットに保存する方法

<h1>やりたいこと</h1>
Route53 Resolverのクエリのログ記録先を他アカウントのS3バケットに保存する

<h2>参考サイト</h2>
<a href="https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/resolver-query-logs-choosing-target-resource.html">バケットポリシー書いてるサイト</a>

<a href="https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/s3-bucket-user-policy-specifying-principal-intro.html">ポリシーのリージョン指定方法</a>


<h2>S3バケットポリシー</h2>
```

{
    "Version": "2012-10-17",
    "Id": "CrossAccountAccess",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "delivery.logs.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::ログ名/AWSLogs/ログを有効化するアカウント/*"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "delivery.logs.amazonaws.com"
            },
            "Action": "s3:GetBucketAcl",
            "Resource": "arn:aws:s3:::af-s3-dns"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::ログを有効化するアカウント:root"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::ログ名"
        }
    ]
} 

```
Athenaのunloadが業務で必要だったので試してみた

## 結論
クエリを実行した結果、s3に想定したファイルが出力がされた
また、CLIからも実行可能

## 実行
以下のクエリを記載しathenaのコンソール上から実行
```
UNLOAD (SELECT
  hoge,
  fuga,
  piyo
FROM
  db.table) TO 's3://xxxxx/xxx/'
WITH (format = 'AVRO')
```
→指定のS3にavro形式でファイルが出力された

AWS CLIを利用してクエリを出力することが可能なのか？
以下のCLIを実行
```
aws athena start-query-execution \
    --query-string　"UNLOAD (SELECT hoge,　fuga,　piyo　FROM　db.table) TO 's3://xxxxx/xxx/' WITH (format = 'AVRO')"
```
結果を確認
```
aws athena get-query-execution --query-execution-id xxxxxxxx | jq '.QueryExecution.Status.State'
"SUCCEEDED"
```
→同様にs3にファイルが出力された

## エラー
```
[ErrorCode: INTERNAL_ERROR_QUERY_ENGINE] Amazon Athena experienced an internal error while executing this query. Please contact AWS support for further assistance. You will not be charged for this query. We apologize for the inconvenience.
```
→オブジェクトのパスをs3://xxxxxにしていた→s3://xxxxx/xxx/でうまくいった
同じパス配下におけるクエリ結果は1つのため、定期実行の際は日付などでパスを区切る必要がある


## まとめ
これで他システムのデータ連携において、様々なファイル形式で可能になった
boto3を使用しても可能か検証したい

### 参考
https://dev.classmethod.jp/articles/20210807-amazon-athena-unload/
Ruby で配列に対して find したアイテムを消していく

# やりたいこと

配列に対して、特定のアイテムを1つずつ見つけてそのアイテムを配列から消していきたい。`Array#delete` だと対象に合致するものがすべて削除されてしまうので、 `find` 的に最初の一件のみを対象に削除したい。


```ruby
# 候補者
candidates = [
  { name: 'Taro' },
  { name: 'Jiro' },
  { name: 'Saburo' },
  { name: 'Shiro' },
  { name: 'Goro' },
  { name: 'Rokuro' },
  { name: 'Shichiro' },
  { name: 'Hachiro' },
  { name: 'Kuro' },
  { name: 'Juro' },
  ...
]

# 当選者
first_elected = [
  'Shiro',
  'Saburo',
  'Jiro',
  'Juro',
  ...
]

# 追加当選者
second_elected = [
  'Taro',
  'Kuro',
  ...
]
```


# やりかた

`Array#find_index` しながら `Array#slice!` していく。（絶対メソッド用意されてると思ってるんだけど見つけられなかった。見落としてるのかな？ https://docs.ruby-lang.org/ja/latest/class/Array.html)

```ruby
first_elected.map { |elected|
  # 候補者を見つけながら候補対象から外す
  candidates
    .find_index { |item| item[:name] == elected }
    .then { |index| index && candidates.slice!(index) }
}
```

# Docs

- https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/detect.html
- https://docs.ruby-lang.org/ja/latest/class/Array.html#I_FIND_INDEX
- https://docs.ruby-lang.org/ja/latest/class/Array.html#I_SLICE--21
- https://docs.ruby-lang.org/ja/latest/class/Array.html#I_DELETE
ActiveRecord で find_each しながら map したい

大きなデータを扱うときに使う `find_each` ([doc](https://api.rubyonrails.org/classes/ActiveRecord/Batches.html#method-i-find_each)) しながら値を集めたいとき

```ruby
processed = []

User.where('age > 30').find_each do |user|
  # user に対するなんらかのバッチ処理
  ...

  processed << user.id
end

processed
```

みたいにやっていたけど、 `find_each` は `Enumerator` かえすので普通にメソッドチェーンを使えば良い気がする。

```ruby
processed = User.where('age > 30').find_each.map do |user|
  # user に対するなんらかのバッチ処理
  ...

  user.id
end
```
初心者　MySQL8に挑戦する 2

# M1Macでやり直した理由

使用機種は　MacBookPro Monterey12 AppleM1Max

　前回、MacBookAir Monterey12 IntelCore15に無事導入したのだけれど、そこではたと立ち止まった。いや、このDBはどこに繋がるんだろう？
　現在、私の主機はMacBookProで、旧機Airが空いてるからDB専用にしよう、と、素人考えではなんだかすごく格好いいことをしている気分だったんだが、それがまったくもってめんどうくさい話なんだということに気づかされ、結局、Proのほうに再構築することにした。

## ちゃんとARMを選んだんだけどね

　恋も二度目なら♪、とはなうたまじりで、 MySQL Community Downloadsからのダウンロードは簡単、installもさくさく。が、起動しようとすると、mysqlなどというコマンドはない、とのたまう。パスが通ってないのね、ということで、あの手、この手で設定するも、頑として通らない。「再installで一発解決」という記事もあったのでやってみたけど、通らない。

　結局、かんたんwizard自動インストールを捨て、下記を頼りに手動でinstall。
　はい、よくできました。

https://qiita.com/centipede/items/d3d937360a5dda2e8120

https://qiita.com/dongri727/items/a07565c8bf13b7fa2672

https://qiita.com/dongri727/items/92b9cb412f91980f6003
psqlでDBにアクセスする際にパスワードを入れたくない時はPGPASSWORDで変数化する。


自分用のメモ

Linuxの場合

`export PGPASSWORD="postgresのパスワード"`

複数のアクセス先を管理したい場合は.pgpassファイルを作成し管理すると良い
~/.pgpass

参考URL

https://www.postgresql.jp/docs/9.4/libpq-pgpass.html
[Unity] Timelineのアニメーションクリップの Playable Asset プロパティーについて

# 初めに
TimelineでCameraの動きのアニメーションをつけて
Cameraの動きをTimelineのRecorder Track機能使って
Animation Clipを作ったのだけど
別のカメラにTimline上で作ったAnimation Clipを再生すると
なんかずれる。。。なんでだ。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37068/fca45de1-9dfe-67ef-d54f-e58e6d9d260f.png)
赤が元、青がレコーディングしたものを再生してる物

※cameraのギズモが常に表示させたかったので下記のBlogを参考にしてます。

https://debuglog.tumblr.com/post/48923836563/%E9%9D%9E%E9%81%B8%E6%8A%9E%E6%99%82%E3%81%AB%E3%82%82%E3%82%AB%E3%83%A1%E3%83%A9%E3%83%93%E3%83%A5%E3%83%BC%E3%81%AE%E3%82%AE%E3%82%BA%E3%83%A2%E3%82%92%E8%A1%A8%E7%A4%BA


## 問題はアニメーションクリップの Playable Asset プロパティーの設定でした
Remove Start Offsetのチェックボックスを（デフォルトはチェック入ってます）
外さないといけませんでした。チェック入れていると初期値を削除して、アニメーション
の移動値のみ(差分)を入れる形になっていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37068/f41a2a07-22c0-cd08-17a0-b9b34dd340a2.png)

https://docs.unity3d.com/ja/Packages/com.unity.timeline@1.5/manual/insp_clp_anim_plyb.html

### 別の方法では大丈夫でしたのですよ。。
動かしたいカメラにアニメーションコントローラーを追加して作ったAnimation Clipを再生する分には
アニメーションは同じように再生されるようでした。こっちは、初期値を削除するような
機能はなかったのかな？？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37068/53cf0072-c90d-e44d-9c1f-adca622d5516.png)


#### 最後に

分からなかったら、ドキュメントをちゃんと読もうかな。。
と言うか何が悪かったのか分からなかったので、自分用に記事かいたのですがね。
基本情報（ディスプレイ）

ディスプレイは出力装置の一つです。
コンピュータからの出力を画面上に映し出します。

見た目は家庭用のテレビと酷似しており、コンピュータの出力結果を画面上に映すのが役割です。

## 解像度と、色のあらわしかた
ディスプレイは表示面を格子状に細かく区切り、ひとつひとつの点（ドット）を使って画像を表現します。
つまりディスプレイに表示されている内容は、どれだけ滑らかに見えても、点の集まりに過ぎません。

ディスプレイをどれだけ細かく区切るかで表示される画面の滑らかさが決まります。
ディスプレイが表示するきめ細かさのことを**解像度**と呼びます。

解像度が高いとより多くの情報を表現することができます。
解像度が低いと少しの情報しか表示できません。

ディスプレイは1つのドットを表現するために、RGB3色の光を重ねて色を表現しています（RはRed、GはGreen、BはBlue)

## VRAM(ビデオRAM)
コンピュータは画面に表示させる内容をVRAM(ビデオRAM)という専用のメモリに保持します。
VRAMの容量によって、扱うことのできる解像度と色数が決まります。

画像データのサイズは
```
横✖️縦のドット数で求められる総ドット数
「何ビットの色情報を持たせるか」
2色　   １６色　   256色  65.536色  16.777.216色（フルカラー）
1ビット  4ビット  8ビット  16ビット    24ビット  
```

1024 * 768ドットの表示能力をもつディスプレイがあります。
このディスプレイで65,536色を表示させたい場合、必要なVRAMの容量は何Mバイトになるか計算します。
```
1024ドット * 768ドット * 16ビット = 12,589,912ビット
1バイトは8ビットのため
12,589,912ビット / 8 = 1,572,864バイト = 1.6Mバイト
```
## ディスプレイの種類と特徴
|  |説明  |
|---|---|
|CRTディスプレイ |ブラウン管を使ったディスプレイ。古いパソコン。奥行きがあるため広い設置面積が必要  |
|液晶ディスプレイ   |電圧によって液晶を制御。バックライトもしくは外部からの光を取り込むことで表示する仕組みのディスプレイ   |
| 有機ELディスプレイ | 有機化合物に電圧を加えることで発光する仕組みを利用したディスプレイ。液晶と違って自らが発光するためのバックライトが不要で省電力。 |
| プラズマディスプレイ| プラズマ放電による発光を利用するディスプレイ。高電圧が必要なため、パソコン専用として使われることはあまりない |

## まとめ
MACは違い将来有機ELディスプレイになるかもしれないとのことです。
ディスプレイは目にも影響したりするので、注目しておきたい分野ですね。
https://www.gizmodo.jp/2022/03/macbook-to-adopt-oled-display-in-2025.html