OmniAICreator/Qiita-1.07M huggingface dataset:
ゲームを作る：すいのゲームを作ろう（第4回）

#ゲームの実装方法を考える
![proposal.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/f39589c4-9079-87d2-6971-e1c6963b7f96.jpeg)
新しい技術を覚えていくのも大切ですが、自分ができることの中で実装していくことをお勧めします。学びと実装を同時に行うと完成まで時間が掛かり、モチベーションが下がりやすくます。完成までたどりつけない確率も多くなります。
出来ると思っていたことでも完成までには何かしらトラブルは起きるものです。思うように動かないときは調べる必要があり。自分ができると思っていたことでも時間が掛かるものです。なおさら自分のできる範囲で実装方法を考えるべきだと思っています。
スキルを身に着けたいときは別でプロジェクトを立ち上げ、そこで学習した方がいいです。ソースや素材の管理がシンプルになることで学ぶことに集中できます。

さて、今回は果物が走っているシーンを作ろうと思います。実際に走らせることもできますが、私は背景を動かして、果物が走っているとみせかける方法を採ろうと思います。こちらの方が背景を動かすだけなので実装が簡単です。

衝突する紐については、実装するのが難しそうだったので、まるたを吹き飛ばす仕様に変更しようと思います。内容としては2本の丸太を並べて、果物が接触した時に、各丸太がそれぞれ別の方向に飛んでいくことにします。それで、果物が丸太を吹き飛ばすという表現にします。

#オブジェクトの配置
![スクリーンショット 2022-01-10 151501.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/18ffcd01-72b5-680b-f215-10b9c491c7ac.png)
私の基本的なHierarchyはこのようになっています。特徴的なのがGameDirectorを作ることです。ここにScriptは集約しています。

![スクリーンショット 2022-01-10 151833.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294598/4c915862-f3db-8bfd-9016-361b7ecc7476.png)
またゲームで使用する定数についてはResourcesのなかにScriptableObjectを作成し一括で管理してます。使用するクラスごとに分けることでわかりやすくしています。レベルデザインの際はこの定数を変更することでプレイしながら調整できるようにしています。

#クラスの構成
```
namespace Assets.Myscripts.BaseUtil
{
    public abstract class BaseMono : MonoBehaviour, I_BaseMono
    {
        public abstract void CycleDisp();
        public abstract void CycleSt();
        public abstract void Init();
    }
}
```
私のクラスはこの独自で作ったBaseMonoをもとにスクリプトを作成しています。ゲームは様々な状態が連携して大きなシステムを作っています。そのために必ず利用するものを基底クラスとしています。

Initは初期化時に一回のみ実行。CycleStは状態を変化させる条件のみを書きます。CycleDispは状態をもとに実行する処理を書いていきます。

```
        public override void Init()
        {
            fieldCtrl = gameObject.GetComponent<FieldCtrl>();
            fieldCtrl.Init();
            fruitsButtonCtrl = gameObject.GetComponent<FruitsButtonCtrl>();
            fruitsButtonCtrl.Init();

        }
        public override void CycleSt()
        {
            fieldCtrl.CycleSt();
            fruitsButtonCtrl.CycleSt();
        }
        public override void CycleDisp()
        {
            fieldCtrl.CycleDisp();
            fruitsButtonCtrl.CycleDisp();
        }
```
これをGameDirectorのクラスが実行することでシステムを構成しています。状態遷移と実行を別にするのを厳守しています。また遷移条件と実行をクラス内でまとめることでクラスの独立性を保っています。
Kubernetest(オンプレ)マスターノードとワーカーノードの関連付け

#####Kubernetes(オンプレ)で、ワーカーノードを再起動後にマスターノードへ再度関連付けをする時の手順となります。

++++++++++++++++++++++++++++++++
[環境]
Ubuntu 20.10
クラスタのバージョン 1.22.2
++++++++++++++++++++++++++++++++


#1) kubeadmによってkubeletの状態をリセットします。(ワーカーノード側)
```
$ kubeadm reset
```

#2) --discovery-token-ca-cert-hashの生成(マスターノード側)
```
$ openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
```
出力されたハッシュをメモ帳などに貼り付けておきます。

#3) --tokenの生成(マスターノード側)
```
$ kubeadm token create
```
出力されたトークンをメモ帳などに貼り付けておきます。

#4) マスターノードへの紐付け(ワーカーノード側)
2)と3)で出力した値を利用します。

``` 
kubeadm join [マスターノードのIP]:6443 --token [マスターノード側で作成したトークン] --discovery-token-ca-cert-hash sha256:[マスターノード側で作成したハッシュ値]
```
Rustでダイクストラ法を実装する

## ダイクストラ(Dijkstra)法とは？

グラフの各頂点への最短経路を求めるアルゴリズムです。
(辺の重みが正の場合のみ適用できる)

詳細についてはネットで検索すれば分かりやすく解説しているページが出てくると思いますので、詳細な説明はそちらをご覧になってください。:bow:

## 実装

BinaryHeapを用いて実装しているので、計算量は$O((E+V)\log V)$です。 
(Vは頂点の数、Eは辺の数)

`let d = Dijkstra::new(n, edge, 0);` で初期化し、
`let dist = d.distance(i);` で頂点への距離、
`let path = d.get_path(i);` で最短経路を返却します。

コメント軽く説明を追加してあります。

```rust
use std::{cmp::Reverse, collections::BinaryHeap};

const INF: usize = 1 << 31;

struct Dijkstra {
    distance: Vec<usize>,
    parent: Vec<usize>,
}

impl Dijkstra {
    // n:usize 頂点の数
    // edge: Vec<Vec<(usize,usize)>> edge[i] = [(2,3), (3,1), (頂点への道,重み)]
    // init:usize どの頂点を起点に考えるか
    pub fn new(n: usize, edge: Vec<Vec<(usize, usize)>>, init: usize) -> Self {
        let mut distance = vec![INF; n];
        let mut parent = vec![INF; n];
        let mut heap = BinaryHeap::new();
        for i in 0..n {
            if i == init {
                // 始点は0
                // BinaryHeapはpopで最大値を取得するので、Reverse()で最小値を取得できるようにする
                heap.push((Reverse(0), i));
            }
            heap.push((Reverse(INF), i));
        }
        while let Some((Reverse(d), target)) = heap.pop() {
            if distance[target] < d {
                // 既にもっと短い経路が見つかってるので無視
                continue;
            }
            distance[target] = d;
            for &(next, cost) in &edge[target] {
                if distance[next] > d + cost {
                    // 短い経路の候補となるので処理を行う
                    distance[next] = d + cost;
                    heap.push((Reverse(distance[next]), next));
                    // ひとつ前の頂点を保存しておく
                    parent[next] = target;
                }
            }
        }
        Self { distance, parent }
    }

    pub fn distance(&self, target: usize) -> usize {
        self.distance[target]
    }

    pub fn get_path(&self, target: usize) -> Vec<usize> {
        let mut current = target;
        let mut res = vec![current];
        while self.parent[current] != INF as usize {
            let next = self.parent[current];
            res.push(next);
            current = next;
        }
        res.reverse();
        res
    }
}
```

コードと簡易的なテストは以下にのせております。

https://github.com/okaponta/atcoder-rust/blob/master/utils/src/graph.rs

最後まで読んでいただきありがとうございました！:blush:
Rails memberとcollectionの違い

#結論
memberを用いることでidを用いて特定のリソースに対してアクションを実行することができ、collectionを用いることで全てのリソースに対してアクションを実行することができる。

##公式API
**member**
https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-member
**collection**
https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-collection

#member
```ruby:routes.rb
resources :users do
    member do
        get :hoge
    end
end
```
memberを使うとルーティングは以下のようになります。
![スクリーンショット 2022-01-10 15.28.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675878/36d0efd9-f150-1917-f1f2-acd24bc61cd0.png)

idを指定することができるので特定のUserに対してhogeアクションを行いたい場合に用いることができます。

#collection
```ruby:routes.rb
resources :users do
    collection do
        get :piyo
    end
end
```

collectionを用いるとルーティングは以下のようになります。
![スクリーンショット 2022-01-10 15.29.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675878/da5154ff-1375-82b2-b1ea-a2cefbb116c8.png)

memberを用いた場合とは異なり、idを指定しないので全てのUserに対してpiyoアクションを行いたい場合に用いることができます。

#おわりに
特定のリソースに対してアクションを実行するか、全てのリソースに対してアクションを実行するかによってmemberとcollectionを使い分けることが必要です。
[Ruby]Stringクラスのsliceメソッド

学習したことのアウトプットとして

# sliceメソッド
rubyの組み込みライブラリ
配列や文字列から指定した要素を取り出すことができるメソッド
取り出したとしても、配列や文字列はもとのまま
例）

```ruby
# 配列を作成します
array = [0,1,2,3,4,5,6]

# 配列から引数で指定した要素を取得します
ele1 = array.slice(1)
puts ele1
#=> 1

# 配列番号-4から4つ分の要素をsliceします
ele2 = array.slice(-4,4)
puts ele2
#=> 3, 4, 5, 6

# 配列はもとのままです
puts array 
#=> [0,1,2,3,4,5,6]
```

**slice!**(破壊的メソッド)だとオブジェクト自身の内容は変更される
例）

```ruby
string = "this is a string"
string.slice!(2)        #=> "i"
string.slice!(3..6)     #=> " is "
string.slice!(/s.*t/)   #=> "sa st"
string.slice!("r")      #=> "r"
puts string             #=> "thing"
```

※補足等ありましたらコメントいただけると幸いです
IT業界に転職した私のマインド、学習結果、勉強方法【AWSエンジニア未経験～1年目】

# はじめに
初投稿。
何を書くか迷いましたが、youtube、twitterでは自分のスキル、勉強方法やマインド（モチベーション）についてあまり語った事が無かったので初学者向けに語ってみたいと思います。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [マインド](#Chapter1)
1. [勉強した結果](#Chapter2)
1. [勉強方法](#Chapter3)
1. [まとめ](#Chapter4)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# マインド
高校生へ向けた孫正義氏の言葉
###「登りたい山を決める」「志高く、人生一度しかない」

これを聞いたときに目が覚めました。
__誰の役に立つのか分からない、お金をもらうに値しない仕事を続けることは辞めよう__と思ったんですよね。
当時の私は転職したら全く使えない属人的なスキルばかり身についてましたので…

AWSをはじめとするITスキルに目を付けた理由以下です。

* クラウドの将来性
* 興味がある分野
* 習得するまでの期間が短い

習得までに時間が掛かる分野（医者、税理士など）に比べると、ITは比較的楽だと感じました。
__※比較的に楽なだけであって、簡単に身につくわけではないです__


<a id="#Chapter2"></a>
# 勉強した結果


- 小規模なWeb開発において、フロント～ネットワークの全体像を俯瞰することはできる。
- AWSでのコンテナ開発環境の構築や、CI/CDなどの基本的な設定はできる。


例えば、WEBサーバーにNginx、バックエンドにPython(FastAPI)などを用いるコンテナ開発において、基礎インフラ（VPC、セキュリティグループなど）を用意し、AWS側でECS（Fargate、EC2）を用いてデプロイできるようにはなりました。
LinuxはLPIC、Dockerやバックエンド、Gitの操作は参考書や、Udemy等を用いて何度か学習していたため、開発側の知識もある程度身についているのが大きいです。

### 資格(2022年1月時点）
- AWS認定クラウドプラクティショナー
- AWS認定ソリューションアーキテクト・アソシエイト
- AWS認定デベロッパー・アソシエイト
- AWS認定SysOpsアドミニストレーター・アソシエイト
- ITパスポート
- CCNA
- GCP アソシエイトクラウドエンジニア
- LPIC 101 102
- LPIC 201 202

### 今後の課題

- DBに関する知識が乏しい
- サーバーサイド言語理解の深度化
- 実務経験が乏しい
- 作業に時間が掛かる 

個人的なアプリ開発の過程で適当にテーブルやユーザーを作ったことしかないので。資格で言うところのアソシエイトレベルの知識は習得しておこうと思います。
サーバーサイド言語はPythonを今後使って行く予定です。他の言語でも良いですが、Django、Flask、FastAPIと、一通り自己学習で触ったフレームワークもあり、世間の注目度も高いので。
実務経験不足のため、ログ設定など本来考慮すべき知識にかなり抜けがある気がします…ここら辺は時間で解決するしかないですかね…

調べれば大体のことを解決できる自信はありますが、知らないことを調べている時間が長いので、後1年くらいは必至に勉強した方が良いなと感じました。

<a id="#Chapter3"></a>
# 勉強方法

まず勉強する範囲を決めます。これは目標によって異なりますが、AWSエンジニア（開発構築、運用）として勉強べき分野は個人的に大きく分けて以下の5つだと思います。

- ネットワーク
- OS（Linux）＋Docker
- DB（MySQL、PostgreSQL、Oracle など）
- サーバーサイド言語（Ruby、Python、PHP、Node.js など）
- AWS

（）内は選択で、どれか一つに絞って勉強すれば良いと思います。
__AWSは他の4つをある程度知っている前提で使うSaaS__なので、__AWSだけ勉強するのは個人的におススメしません！__※AWS認定だけを盲目的にやり続けてしまうとか…

### 具体的な勉強方法

- __簡単そうな事、知らない事、覚えきれてない事__
上記に当てはまる事を勉強する。

- __難しい事、知っている事、覚えている事__
は勉強しない。

例えば、プログラミングで関数やクラスが分かるのに、実際に開発しようとしない事は新しい知識が入ってこないですし、いきなりMWの設定ファイルの中身を勉強しようとし、意味が分からないまま時間が経過してしまうのは基本的なIT用語や知識が不足しているので、勉強内容のハードルを下げた方が良いと思います。
ハードルを下げ切った状態で、分からない事を勉強します。

後は資格の受験日や、参考書、Udemyをやりきる日を決め、勉強するだけです。
おおよそ100時間で取得できる資格を1か月で取得するならば、1日平均3時間以上の学習時間を設ける。時間的に難しいなら2か月で1日平均1時間30分にすれば良いと思います。

### 勉強をサボる＝人生詰み

今後も一般的な日本の社会人の平均年収は減り続け、物価は上昇し続けます。
サボったら軽く人生詰みますね☆
「周りも下がるから別にいいや、何とかなるやろ！」って感じなら気にしないでください。

無理なペースで勉強しなくとも、周りの社会人は5分も勉強していないので、__1日1、2時間勉強できたら自分を褒めてください。__
私は2021年の1年間、暗いトンネルの中で先が見えず不安だらけでしたが、ようやく出口の光が見えてきたような気がします。

### 「小さなことを積み重ねることが、とんでもないところへ行くただ一つの道」byイチロー

<a id="#Chapter4"></a>
# まとめ
偉そうに色々語りましたが、私は実力的に大したことありません。個人的に満足もしていません。
2020年の自分のようにこれから勉強し始める人、勉強し始めたけど先が見えなくて不安な人の参考になれば幸いです。
WebAssembly をためしてみる

## WebAssemblyとは

スタックベースのインストラクションセットで、Webブラウザ内でネイティブバイナリに近い速度で動作することを目的としている。Mozillaが主導していたようだが、基本的にすべての近代的なブラウザで動作するようだ。RustやC言語のバックエンドとして使うことができる。


## watとwasm
WebAssemblyにはテキスト表現とバイナリ表現があり、それぞれwatとwasmを拡張子として用いる。多くのコンパイラはバイナリ表現を直接吐くようだ。テキスト表現からバイナリ表現にコンパイル？するツールがあるのだが、シンボル名が[最近変わった]
(https://github.com/WebAssembly/spec/issues/884)らしく、Web上にあるコードがコンパイルできなくて混乱した。

## wabt
コード変換やネイティブコードへの変換を実現するツールチェーンがこれ。

https://github.com/webassembly/wabt

`cmake`で普通にビルドできるが、m1 macのバイナリフォーマットがサポートされておらず、ネイティブコンパイラはビルドできなかった。が、watからwasmに変換するコードはm1でもビルドできたので気にしない。

## コード例
フィボナッチ数を計算するコードを書いてみた。
WebAssemblyはスタックマシンなのだけど、純粋なスタックマシンではなく、例えば関数呼び出しの引数は、localと呼ばれる領域に用意されるし、スタック以外にローカルな変数領域を持つことができるらしい。そのあたりのことは下のページに書かれている。

http://troubles.md/wasm-is-not-a-stack-machine/

とはいえば基本的な演算の考え方はごく普通のスタックマシンで、スタックトップに対して演算が行われ、結果がスタックトップに置かれる。関数呼び出しを行う際も、スタック上に引数をプッシュしてから呼び出す。にもかかわらず、呼び出された側ではローカルに入って見えるというのはちょっと不思議？
このコードのように、引数を何度も使う場合には、何度も複製しなくて済むので楽ではある。


``` wst
;; if n < 2 return 1
;; else return fib(n-1) + fib(n-2)

(module
  (func $fib (param f64) (result f64)
    local.get 0    ; 引数nをスタックに積む
    f64.const 2    ; 定数2をスタックに積む
    f64.lt         ; 比較する n < 2
    if (result f64)
      f64.const 1  ; 返り値をスタックに積む
    else
      local.get 0  ; 引数nをスタックに積む
      f64.const 1  ; 定数1をスタックに積む 
      f64.sub      ; 引く. n - 1
      call $fib.   ; n-1を引数にしてfibを再帰呼び出し。結果はスタックトップに置かれる。
      local.get 0  ; 引数nをスタックに積む
      f64.const 2  ; 定数2をスタックに積む 
      f64.sub      ; 引く. n - 2
      call $fib.   ; n-2を引数にしてfibを再帰呼び出し。結果はスタックトップに置かれる。
      f64.add      ; fib(n-1) と fib(n-2)の結果がスタック上にあるのでそれらを加算。
    end)
  (export "fib" (func $fib)))
```

## コンパイル
wabt の`wat2wasm`を使ってコンパイルする。

```
% ../wabt/build/wat2wasm fib.wat
% od -x fib.wasm               
0000000      6100    6d73    0001    0000    0601    6001    7c01    7c01
0000020      0203    0001    0707    0301    6966    0062    0a00    013a
0000040      0038    0020    0044    0000    0000    0000    6340    7c04
0000060      0044    0000    0000    f000    053f    0020    0044    0000
0000100      0000    f000    a13f    0010    0020    0044    0000    0000
0000120      0000    a140    0010    0ba0    000b                        
0000131
```

## 実行
Webブラウザで実行するには、JavaScriptから呼び出してやる。ごく普通の関数として利用できる。

``` javascript
<script type="text/javascript">
WebAssembly.instantiateStreaming(fetch('fib.wasm'))
   .then(obj => {
       or (let i = 1; i < 20; i++) {
          console.log('fib '+ i +' = '+ obj.instance.exports.fib(i));
       }
   });
</script>
```

実行すると下のように出力がブラウザのコーソルに出る。
``` 
(index):5 fib 1 = 1
(index):5 fib 2 = 2
  :
(index):5 fib 17 = 2584
(index):5 fib 18 = 4181
(index):5 fib 19 = 6765
```

## 所感
スタックベースのVMをブラウザに埋め込む、というのはJavaと何が違うのか、と考えてみたり。まあ、色々違うわけですが。
そのオープンソースプロジェクト、公開前に大事な情報コミットしてない？



通常、秘密鍵やAPI Tokenはソースコードとは分離させ、.envファイルなどに保存しておいて、Gitのコミットには含めない。しかし、実装の初期には.envを一時的にコミットに含めている事例も珍しくない。それを後で削除してコミットしても、履歴としては残っている。

この記事では、スマートコントラクト用の秘密鍵や、APIトークンなどの情報をGitのコミット履歴から検索し、リポジトリを公開する前に安全を確認できるツールを紹介する。


##コミット履歴を展開する
私の作ったesightというツールを使う。

https://github.com/TakutoYoshikai/elemental-sight

git logを使って確認するのが一般的だが、一度全て展開した方が、後の編集や確認が楽になる。

**インストール**

```bash
pip3 install git+https://github.com/TakutoYoshikai/elemental-sight.git
```

**コミット履歴の展開**

出力先ディレクトリに、全てのコミットの差分ファイルが展開される。そこからターゲットとなる文字列を検索し、それを修正すればよい。

```bash
esight /path/to/repo {BRANCH} -o {OUTPUT DIR}
```

展開されたディレクトリはこうなっている
![スクリーンショット 2022-01-10 13.15.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149717/06671f68-5c97-1168-617d-d95ae97b8069.png)

コミットが順番に番号のディレクトリに出力されて、差分のファイルが保存されている。



## APIトークンや秘密鍵などの文字列を検索するツール
このesightを使用して、gitのコミット履歴を展開した後、正規表現で**ランダムな文字列を検索するツールshiba**を開発した。

https://github.com/TakutoYoshikai/shiba

このshibaは、正規表現によってhex文字列や、普通の文字列を検索した後に、その文字列がランダムに生成されたかどうか、文字の出現頻度の分散を計算し、閾値以上のものを表示する。

**インストール**

```bash
git clone https://github.com/TakutoYoshikai/shiba
cd shiba
./install.sh

#パスを通す
echo "export PATH=\$PATH:/path/to/shiba/bin" >> ~/.bash_profile
```

**使い方**

```bash
# APIトークンを探す
shiba /path/to/repo {BRANCH} {TOKEN LENGTH}
# ./SHIBA_RESULT にコミット履歴が展開されている

# hex文字列を探す
shiba /path/to/repo {BRANCH} hex {TOKEN LENGTH}

#例: ローカルにcloneしたreactのリポジトリの中から32文字のhex文字列を検索する
shiba ./react master hex 32
```

結果は以下のように表示される

```
./0/message.json 4hQ0v2z7fNRvvOji0jShV5SpNqYEgajJ
./1/message.json zkjhJgeY336mqEADvkvE494xxi2XyB8u
./2/env oe7tGfeBW1YJga7DieAjtrxCgNhs1c5X
```

##コミット履歴を確認した後
公開してはいけないデータを見つけた場合の対処法が、以下のメルカリの記事に修正の方法がまとめられている。

https://engineering.mercari.com/blog/entry/20211207-removing-sensitive-data-from-github/
Google Cloud アップデート (12/30/2021-1/5/2022)

### Security Command Center: [Dec 30, 2021](https://cloud.google.com/security-command-center/docs/release-notes#December_30_2021)
- Security Health AnalyticsでDataprocのイメージバージョンがLog4j 2の脆弱性影響を受けているか確認してくれるディテクタをGAで追加したよ！

### Vertex AI: [Jan 4, 2022](https://cloud.google.com/vertex-ai/docs/release-notes#January_04_2022)
- PyTorch 1.10でトレーニングするのが事前ビルドされたコンテナでできるようになったよ！

### SAP: [Jan 4, 2022](https://cloud.google.com/solutions/sap/docs/release-notes#January_04_2022)
- HANA Standby Nodes用のStorage Manager v2.3が李衣r-すされたよ！
    - フェイルオーバ時のディスクのハンドリングが改善された。

### Workflows: [Jan 5, 2022](https://cloud.google.com/workflows/docs/release-notes#January_05_2022)
- v1:
    - Cloud FunctionsとCloud Runで[ingressの通信制御されてる場合でも起動できる](https://cloud.google.com/workflows/docs/calling-run-functions#internal_ingress)ようになったよ！

### Compute Engine: [Jan 5, 2022](https://cloud.google.com/compute/docs/release-notes#January_05_2022)
- regionalとzonalのManaged Instance Groupsで[リサイズ時にVM作成がリトライするのを無効化](https://cloud.google.com/compute/docs/instance-groups/creating-groups-of-managed-instances#disabling_creation_retries_mode_during_resize)で機能がプレビューになったよ！


### ディスクレーマ
- アップデートの内容はあくまでも個人の理解していることを書いています。正しい内容はリリースノート等を確認下さい。
- リリース内容できるだけ拾うようにしているのですが、抜けていそうなリリースノートは追加するのでぜひ教えて下さい！(一覧[ここ](https://qiita.com/kenzkenz/items/ac18a359b803dbb6b490)で更新してます。)
【Rails】ajax化とは

##ajax化とは
Asynchronous JavaScript + XML の略で、非同期通信と呼ばれる通信方法のこと。
Webブラウザ上で非同期通信を行い、ページ全体の再読み込み無しにページを更新する。

##同期通信、非同期通信とは？
**◆同期通信**
クライアントとサーバー間の通信においては、通常、同期通信と呼ばれる方法が用いられ、``一瞬画面が白く``なった後、画面が切り替わるような通信は、全てこの同期通信となる。

ページが一瞬真っ白になってから表示されるまでの間は、``ユーザーは他の操作を何もする事が出来ない。``また、同期通信は``ページ全体を１から作成して表示させている``ので、どうしても表示までの``時間がかかる。``

[![Image from Gyazo](https://i.gyazo.com/d839480fa2bd646c00eadd4e729af8ab.png)](https://gyazo.com/d839480fa2bd646c00eadd4e729af8ab)

**◆非同期通信**
一方、非同期通信では、クライアントからのリクエスト送信後、サーバーの処理中にも、``ページ遷移無しに他の作業を行うことができる。``

[![Image from Gyazo](https://i.gyazo.com/4cc343d408f2ce7c3cf4a01e9a2e9a0b.png)](https://gyazo.com/4cc343d408f2ce7c3cf4a01e9a2e9a0b)

##Railsにおけるajax化の方法
非同期通信の方法は2種類あり、
①remote:true形式
②ajax関数を使った形式
の2パターンが存在するが、今回はremote:true形式を記載。

例として、掲示板のお気に入り(いいね)ボタンを押した時に、お気に入りの登録、解除を行うという仕組みをajax化していく。

**1.コントローラーの設定**
``redirect先の指定``をコメントアウト。

```bookmarks_controller.rb
class BookmarksController < ApplicationController
    def create
        @board = Board.find(params[:board_id])
        current_user.bookmark(@board)
        # redirect_back fallback_location: root_path,success: t('user_sessions.boards.bookmarks.create.success')
    end

    def destroy
        @board = current_user.bookmarks.find(params[:id]).board
        current_user.unbookmark(@board)
        # redirect_back fallback_location: root_path,success: t('user_sessions.boards.bookmarks.destroy.success')
    end

end
```

**2.ブックマークボタンをajax化**
ブックマークボタンのコードを記載している
``app/views/boards/_bookmark.html.erb``
``app/views/boards/_unbookmark.html.erb``
この２つのコード内の``<%= link_to ~　%>``に``remote: true``を追加。

**``remote: true``を指定することによって、AjaxでHTTPリクエストを送信するように設定される。
更に、``html.erbファイルではなくjs.erbファイルをレンダリング``してくれる。**

**3.ブックマークボタンの切り替え処理を追加**
指定したid属性を持つ部分を置き換える。それぞれブックマーク登録・解除に置き換えるよう記述。

``$(置換対象).replaceWith(置換後の要素)``
**replaceWith**は要素を置換するメソッド。

```app/views/bookmarks/create.js.erb  
$("#js-bookmark-button-for-board-<%= @board.id %>").replaceWith("<%= j(render('bookmarks/unbookmark', board: @board)) %>");
```

```app/views/bookmarks/destroy.js.erb
$("#js-bookmark-button-for-board-<%= @board.id %>").replaceWith("<%= j(render('bookmarks/bookmark', board: @board)) %>");
```

##参考記事
[⭐️ブックマークボタンのajax化](https://sasakix10.hateblo.jp/entry/2021/05/26/125759)
[【Rails】remote:true形式でAjax通信を行う(お気に入り登録機能のajax化)](https://qiita.com/ryota21/items/e7fedfe6656c4238c0b8)
[【IT用語】 Ajaxとは？初心者向けに豊富な画像で仕組みを解説](https://pikawaka.com/word/ajax)
nvm-windowsでNode.jsをインストールする


## nvm-windowsとは
Node.jsのバージョンを管理するアプリケーション。
複数のバージョンをインストールして、好きなタイミングで使用するバージョンを切り替えたりできる。

## nvm-windowsをインストールする
[Gitリポジトリ](https://github.com/coreybutler/nvm-windows/releases)から`nvm-setup.zip`をダウンロードし、`nvm-setup.exe`を実行する。

:::note warn
聞かれる質問は基本的に全てデフォルトで問題ないが、インストール先のフォルダのパスの半角スペースが含まれる場合、コマンド実行時に動作しない可能性がある。
:::

## mvnのバージョンを確認する
インストールできたら下記のコマンドでバージョンを確認できる。

```
❯ nvm version
1.1.9
```

## インストール済みのNode.jsを確認する
現段階ではまだ何もインストールしていないため、`No installations recognized.`が出力される。

```
❯ nvm list
No installations recognized.
```

## Node.jsのLTS（長期の保守運用が約束されたバージョン）を確認してインストールする
下記コマンドでインストールできるNode.jsのバージョンを確認できる。

```
❯ nvm list available

|   CURRENT    |     LTS      |  OLD STABLE  | OLD UNSTABLE |
|--------------|--------------|--------------|--------------|
|    17.3.0    |   16.13.1    |   0.12.18    |   0.11.16    |
|    17.2.0    |   16.13.0    |   0.12.17    |   0.11.15    |
|    17.1.0    |   14.18.2    |   0.12.16    |   0.11.14    |
|    17.0.1    |   14.18.1    |   0.12.15    |   0.11.13    |
|    17.0.0    |   14.18.0    |   0.12.14    |   0.11.12    |
|   16.12.0    |   14.17.6    |   0.12.13    |   0.11.11    |
|   16.11.1    |   14.17.5    |   0.12.12    |   0.11.10    |
|   16.11.0    |   14.17.4    |   0.12.11    |    0.11.9    |
|   16.10.0    |   14.17.3    |   0.12.10    |    0.11.8    |
|    16.9.1    |   14.17.2    |    0.12.9    |    0.11.7    |
|    16.9.0    |   14.17.1    |    0.12.8    |    0.11.6    |
|    16.8.0    |   14.17.0    |    0.12.7    |    0.11.5    |
|    16.7.0    |   14.16.1    |    0.12.6    |    0.11.4    |
|    16.6.2    |   14.16.0    |    0.12.5    |    0.11.3    |
|    16.6.1    |   14.15.5    |    0.12.4    |    0.11.2    |
|    16.6.0    |   14.15.4    |    0.12.3    |    0.11.1    |
|    16.5.0    |   14.15.3    |    0.12.2    |    0.11.0    |
|    16.4.2    |   14.15.2    |    0.12.1    |    0.9.12    |
|    16.4.1    |   14.15.1    |    0.12.0    |    0.9.11    |
|    16.4.0    |   14.15.0    |   0.10.48    |    0.9.10    |

This is a partial list. For a complete list, visit https://nodejs.org/en/download/releases
```

LTSの最新バージョンが`16.13.1`であることが確認できたため、バージョンを指定してインストールする。

```
❯ nvm install 16.13.1
Downloading node.js version 16.13.1 (64-bit)...
Extracting...
Complete

Installation complete. If you want to use this version, type

nvm use 16.13.1
```

## 使用するバージョンを選択する
PowerShellを**管理者権限で実行**し、下記のコマンドを実行する。

:::note warn
管理者権限で実行しない場合、「exit status 1」というメッセージが表示され、バージョン選択に失敗する。
:::

```
❯ nvm use 16.13.1
Now using node v16.13.1 (64-bit)
```

## インストール済みのNode.jsを確認する

`nvm list`コマンドでインストール済みのNode.jsを確認できる。

:::note info
下記は1つしか表示されていないが、複数のバージョンをインストールした場合はその全てが表示され、現在選択しているバージョンに「*」がつく。
:::

```
❯ nvm list
  * 16.13.1 (Currently using 64-bit executable)
```

Node.jsのバージョンを確認すると、nvmで選択しているバージョンと一致していることが確認できる。

```
❯ node -v
v16.13.1
```

## 参考
- [nvm-windowsをインストールする](https://utsu-programmer.com/programming/js/nvm-windows-install/)
- [【入門】Electron完全に理解した](https://zenn.dev/unsoluble_sugar/articles/c5b5faefddd35c1be8a3)
MySQLで調査時によく使う確認方法まとめ

MySQL使用時、設定情報や接続情報を中に入って確認する際に、個人的によく使うものメモ。

# 基本
```
MySQL> SHOW GLOBAL VARIABLES;
```
で、MySQLサーバーのシステム設定値を確認できる。

```
MySQL> SHOW GLOBAL STATUS;
```
で、MySQLサーバーのステータス値を確認できる。
ここから、確認したい値をgrepする。
以下、よく使うものを記載する。

## システム設定値
### 許可されている最大同時接続数を確認する
```
MySQL> SHOW GLOBAL VARIABLES like 'max_connections';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 45    |
+-----------------+-------+
1 row in set (0.00 sec)
```
ちなみにAWS RDS使用時は、最大同時接続数はDBインスタンスサイズによってデフォルト値が規定されている。
[参考](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/CHAP_Limits.html#RDS_Limits.MaxConnections)

## ステータス値
### 累積のDB接続数を確認する
```
MySQL> SHOW GLOBAL STATUS LIKE 'Conn%';
+-----------------------------------+-------+
| Variable_name                     | Value |
+-----------------------------------+-------+
| Connection_errors_accept          | 0     |
| Connection_errors_internal        | 0     |
| Connection_errors_max_connections | 0     |
| Connection_errors_peer_address    | 0     |
| Connection_errors_select          | 0     |
| Connection_errors_tcpwrap         | 0     |
| Connections                       | 47    |
+-----------------------------------+-------+
7 rows in set (0.00 sec)
```
のうち、`Connections`　の値が累積でのDB接続数。

### 現在のDB接続数を確認する
```
MySQL> SHOW GLOBAL STATUS LIKE 'Threads_connected';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_connected | 11    |
+-------------------+-------+
1 row in set (0.00 sec)
```

# その他使いそうなコマンド
### 現在実行されているスレッドを確認する
```
MySQL> SHOW PROCESSLIST;
```

### 現在オープンされているテーブルを確認する
```
MySQL> SHOW OPEN TABLES;
```

### ユーザの権限を確認する
```
MySQL> SHOW GRANTS;
```

### クエリで発生したエラー系
```
クエリで発生した警告
MySQL> SHOW WARNINGS

クエリで発生したエラー
MySQL> SHOW ERRORS;
```

## 補足
`\G`を最後に付与してコマンド実行すると、出力結果横幅が広い際に見やすくなる。

## 参考
- [リファレンス](https://dev.mysql.com/doc/refman/5.7/en/)
【GCP】CloudBuild 設定

最近、cloudbuild での設定で使ったtips をメモします。

背景としては、自分でとあるオープンソースをCloudCuild で docker build するのに３０分近くかかってしまいました。そのとき

- timeout の設定
- ビルドに使用するコアをパワーアップさせる

ということができるこを知ったのでメモしておきます。


### Timeout 

注意するのは、各ステップと全体の２か所でtimeout の設定があるということ。[こちらにある解説](https://runkiss.blogspot.com/2021/09/using-google-cloud-build.html) が分かり易い。感謝。

```yaml:cloudbuild.yaml
build:
  steps:
    - id: main
      name: my-builder-image
      entrypoint: bash
      timeout: 600s
      args:
        - /workspace/build.sh
        - ${BRANCH_NAME}
        - ${COMMIT_SHA}
        - ${SHORT_SHA}
  timeout: 600s
```

全体のtimeoutはコマンドラインから実行するときも```gcloud builds submit --timeout=900s ...```で指定できるらしい。

### machine type

使用するマシンを選べるようです。[Cloud Build pricing](https://cloud.google.com/build/pricing)のページにマシンの型と料金が書かれています。

Machine type	|Virtual CPUs|Memory	| Price (USD)
 --- | --- | ---| ---
e2-medium	|1|4GB	| $0.003 / build-minute. First 120 builds-minutes per day are free.
e2-highcpu-8| 8	| 8GB	| $0.016 / build-minute
e2-highcpu-32 |32 |32GB	|$0.064 / build-minute

cloud build の設定ファイルは以下のように書いたら、ビルドの時間は短くなった。ので効果は分かる。でもお金少しかかりそうなので、普段は使わない方がいいのかな。

```yaml
options:
  machineType: 'E2_HIGHCPU_8'
```

### Logging

別のところで、CloudBuild で以下のエラーに出くわす。build を始めてもらえない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294040/b7ff419e-4a21-a244-b494-e610baf949ff.png)

ここでは(b)で解決しました。、実は設定したサービスアカウントがLogging への権限を持っていないことが原因だったようです。

```
options:
  logging: CLOUD_LOGGING_ONLY
```
としました。参考にした記事は下記。


https://stackoverflow.com/questions/68779751/error-publishing-source-code-from-cloud-build-to-a-bucket-using-triggers



# まとめ

とりあえずGCPのCloudBuildの使い方のメモとして書きました。GithubActions よりこちらの方がコストはかからなそうなので、個人ではこちらを使う方が良いのかな。
(2021/01/10)
Google Pixelのデメリット　クソ仕様について

#最近Googleが糞すぎる

###Google Homeを買って音楽を再生させようとしたらyoutube  premiumの宣伝が毎回のごとくはいってきたり。サブスクサービスは固定費のため基本的に入っていけません。金のムダ。Appleは最上級に嫌いですし、Amazonもほどほどに嫌いですが、Googleもとうとう嫌いになりました。今日はGoogleに対するグチを殴り書きするだけの記事です。GCPもたっけえし。ほんとにもうウザい。

#本題Google  Pixelのゴミな点
##DisplayPort Alternate Modeが使用できない
DisplayPort Alternate Modeとは、スマホとhdmiを有線ケーブルで繋ぐことにより外部ディスプレイに画面を出力させる機能の事です。
彼女とホテルのテレビで映画を見るために、type-c⇔hdmi ケーブルを買ったのになぜかPixelだけ使用できない。 これは私も持っているchromecastとかいうクソ端末を購入させる戦略だそうです。非常にゲボはくほどむかつきますね。
ちなむとchromecastはホテルで使用できないことが多いです。それは、公共wifiと同じで多数の端末を接続させるから？　まあとりあえずコロナ化で50件ほどホテルに泊まりましたが、使用できたのはわずか1件のみ。そこはairbnbのような1件ごとにwifiがわり振られているやつ。ほぼ使用できない。

ちな、DisplayPort Alternate Modeが使用できる端末は以下を参照。彼女とホテルで映画を見たいときに非常に苦労します。
https://smaphone-data.com/?p=198

##指紋認証がほどほどウンコ。
端的に指紋認証精度が優れたスマホランキングを記載します。※ちなむと筆者は手汗多めです。過去彼女10名のうち、8名ほどに酷評されきました。普通の人は使用に支障がでるラインが異なる場合があります。ただ、俺が使えなきゃ何も意味がねぇ。だからグチとして書く。

①Huawei p30 lite、honor
②iphone 7
---使うのに支障が出るラインの壁
③Pixel 4a 5G
④Samsung Galay 7 edge
Elixirで総当たり戦プログラム

# このプログラムについて
Elixirで総当たり戦のプログラムを書く機会があり、[こちらのサイト](https://note.com/kuronekohomuhomu/n/nd619fd64e78b)を参考にして作成しました。
参加者の人数が奇数だった際は、対戦の発生しない組が生まれるようにしてあります。
そこそこ再利用しやすいかなと思い、Qiitaで共有させていただきます。

# プログラム
https://gist.github.com/Papillon6814/70c27d353a711140b97964995aebcba4

```elixir
defmodule Util do
  def main() do
    n = "number of members: "
      |> IO.gets()
      |> String.trim()
      |> String.to_integer()

    w = 1
    x = gen_members_list_odd(n)
    y = gen_members_list_even(n)

    next_round(n, w, x, y)
  end

  defp next_round(n, w, list_x, list_y) when n >= w do
    IO.puts("Round #{w}")

    list_x = List.insert_at(list_x, length(list_x), Enum.at(list_y, length(list_x)-1))
    list_y = List.insert_at(list_y, 0,              Enum.at(list_x, 1))
    {_, list_x} = List.pop_at(list_x, 1)
    {_, list_y} = List.pop_at(list_y, length(list_y)-1)

    list_x
    |> inspect()
    |> IO.puts()

    list_y
    |> inspect()
    |> IO.puts()

    0..length(list_x)-1
    |> Enum.to_list()
    |> Enum.each(fn i ->
      IO.puts("#{Enum.at(list_x, i)}-#{Enum.at(list_y, i)}")
    end)

    next_round(n, w+1, list_x, list_y)
  end
  defp next_round(_, _, _, _), do: nil

  defp gen_members_list_odd(n) do
    1..n*2
    |> Enum.to_list()
    |> Enum.filter(&rem(&1, 2) == 1)
    |> Enum.filter(&(&1 <= n))
  end

  defp gen_members_list_even(n) when rem(n, 2) == 0 do
    1..n*2
    |> Enum.to_list()
    |> Enum.filter(&rem(&1, 2) == 0)
    |> Enum.filter(&(&1 <= n))
  end

  defp gen_members_list_even(n) do
    n-1
    |> gen_members_list_even()
    |> List.insert_at(0, nil)
  end
end

Util.main()
```
VSCodeのJupyterNotebookの行番号を常に表示させておくSettings.json

# 参考

[こちらがとても分りやすく参考になりました！](https://amzn.to/3tGa0mV)
# 方法

```json:settings.json
{
  "notebook.lineNumbers": "on", // 行番号を常に表示
}
```
Re:VIEWでページ番号なしで裏表紙を入れる

追記：こんなことしなくてもconfig.ymlの`backcoverimage`で設定すればOKでした…。
`cover_fit_page`をtrueにすれば解像度が実寸とあってなくても大丈夫です。

```
# TechBooster Re:VIEW-Template独自設定
techbooster:
  # 表紙および裏表紙を実寸ではなく仕上がりサイズにリサイズするか
  # texdocumentclassでcover_fit_page=trueを付けるのと同じ
  # cover_fit_page: true
  # 裏表紙画像指定。画像はimages/から探索される
  backcoverimage: backcover.png
```
追記ここまで

Re:VIEWで裏表紙を入れるには、[FAQ - Re:VIEW の使い方について（TeX PDF）](https://review-knowledge-ja.readthedocs.io/ja/latest/faq/faq-tex.html#732c59539192eec34b69a97f76ff6af5)に記載の通りやれば挿入できます。
しかし、[TechBooster/ReVIEW-Template](https://github.com/TechBooster/ReVIEW-Template)を使用している場合、ページ番号が入ってしまいます。

ページ番号を入れないようにするには、作成したbackcover.texを変更するだけで対応可能です。

```backcover.tex
% imagesフォルダのbackcoverファイルを裏表紙とする
\includefullpagegraphicswithoutnmbl{images/backcover.pdf}
```

これをPDFに含めるようにconfig.ymlで設定すると完了です！
電子書籍の方だけ含めるようにconfig-ebook.ymlに書いてもいいですね。

```config.yml
…
pdfmaker:
  backcover: backcover.tex
…
```

Twitterの奥地からの情報でした。
https://twitter.com/kmuto/status/1173535500084236289
【新卒エンジニア就活】名古屋に住める企業

## はじめに

僕は23卒でエンジニアとして就活していました。
できれば名古屋に住みたいなと思って就活をしていました。

結果として2021年12月に、
この記事で紹介する企業の中からいくつか内定を頂くことができました。
名古屋に住みたいという希望も叶いそうです。

Web系企業は東京に集まっているので、名古屋で働ける企業を探すのに少し苦労しました。
同じように新卒から名古屋で働きたいって思ってる人に対して、絶対に役に立つと思ってまとめることにしました。

新卒から名古屋で住むことができる企業を紹介していきます。

ここで紹介する企業は、僕が選考を受けた企業や友人が受けた企業なので、他にもあると思います。
もし良ければコメントなどで教えていただけると嬉しいです🙇‍♂️
掲載させて頂きます。 (教えてくれた方のアカウント付き可)

直接人事から聞いた話を基本的に載せていきますが、制度が変わることも多いと思うので、読んでくださっている方が就活している時とは違う可能性もあります。間違っている可能性もあると思って、一応確認もよろしくお願いします🙇‍♂️

## 企業紹介


### 名古屋に本社・支社がある

##### freee株式会社
freeeさんは最近名古屋の支社を立ち上げた所です。
今はエンジニア5名と言っていました。
中部支社のエンジニアの人も人事の人も出来るって言っていたので、かなりの可能性でできると思います！
(思います！)

##### 株式会社マネーフォワード
今年名古屋支社を立ち上げた所です。
立ち上げた人に聞きましたが、「出来ると思います！」ってことでした。
もしかしたら、状況によっては出来ない可能性もあるので確認忘れずにです！！

##### 株式会社エイチーム
エイチームは名古屋に本社があります！
コロナの状況にもよりますが、新卒は出社必須みたいです！
たくさん知り合いができそうです！
基本的に名古屋配属です。

##### おまけ情報
Sansan株式会社は、名古屋に支社がありますが、現在では、新卒から名古屋在住は基本的に出来ないようです。
ただ、1Dayインターンに行った時に、「多くのエンジニアに囲まれて1、２経験を詰んだ後に、名古屋を盛り上げるみたいなことはして欲しい。」と言っていました。
1、２年経験を積んで、名古屋ということはおそらく可能そうです。

### フルリモート (殆ど)

##### ヤフー株式会社
人事との面談でリモートで働ける確認取りました。
名古屋オフィスもあるのですが、新卒1年目は基本的に東京配属です。
名古屋オフィスに行くことも出来ます。

どこにでも住めるわけではなく、何かあった時に11時までに出社出来る距離のようです。
名古屋は住めるけど、沖縄とかは住めないようでした。

※追記:この記事出した次の日に、どこでもOKになったみたいです。
https://news.yahoo.co.jp/articles/9061963bc5657dd888752ec8472c3546611a0a77


##### 株式会社ZOZO
人事との面談でフルリモートで働ける確認取りました。
フルリモートって感じがすごく強いです笑

##### サイボウズ株式会社
人事との面談でフルリモートで働ける確認取りました。
サマーインターンの時にメンターしてくれた方も、新卒で入ってから、まだ2回しか言ってないって言ってました。
リモートで働いている人がすごく多いみたいです。

##### DeNA: 株式会社ディー・エヌ・エー
合同説明会で人事の方が、名古屋に住むこと可能って言ってました。
健康診断とか、必要な時だけ出社すれば良いらしく交通費も結構出るらしいです。
新卒でそういう人もいるみたいです。

最初、そんな感じしてなかったので、知った時は以外だーって思いました。(雑談)

##### 株式会社ゆめみ
内定もらってる友人から聞きました。
フルリモートのようです！！

### おまけ情報
確かメルカリもフルリモートって言っていた気がします。が確認できていないので、一応ここに書いておきます。

ここに記載した企業以外で有名な企業ですと、サイバーエージェントやLine、クックパッド、ゲーム系ですとミクシィやグリーなどがありますが、東京での出社が基本的にあるってことでした。

就活で接点がなかったですが、他にも楽天やリクルートなど人気な企業は沢山ありますので、気になる企業と話すことができそうなイベントに参加して聞いてみてください。各社独自の就活イベントやサポーターズさん主催の合同会社説明会などです！！

### さいごに

新卒1年目から名古屋でも働ける企業は意外とたくさんありました！
新卒からフルリモートは、人間関係を作れなかったり大変なこともあると思うので、そこら辺は考えないとですね！！
名古屋にもオフィスがあるのはやっぱり嬉しい！！

Web系企業でリモート環境が整っていても、新卒何年間かは、出社が必要ってことが多かったです。ミクシィさんとかも、確か何年間か勤務してフルリモートになる人がいるって言ってた気がします。

名古屋で就職を考えている人の参考になったら嬉しいです！！
名古屋のエンジニア界隈、盛り上がって欲しいなっ！
Blenderで球面上の頂点から凸包を作り色を割り当てよう

## やること

- 球面上にランダムに頂点を作成します。
- [Blenderで凸包を作ろう](https://qiita.com/SaitoTsutomu/items/fae863598c5110a5c8d4)を使って、頂点から凸包を作ります。
- [Blenderで隣り合う面に異なる色を割当（四色問題）](https://qiita.com/SaitoTsutomu/items/8def3fb4b99f8520b6ed)を使って、凸包に色を割り当てます。

### 実行例

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/8eeb63d7-9acd-9af4-d1b9-83acc4dd9e2e.jpeg" width="300">

## Pythonのコード

30個の頂点を球面上にランダムに作成し、凸包を作って色を割り当てます。
Scriptingワークスペースで新規作成してコピペして実行してください。

```py
import bmesh
import bpy
import numpy as np
from mathutils import Vector


def rand_sphere(radius):
    while True:
        x = np.random.randn(3)
        r = np.linalg.norm(x)
        if r:
            return x / r * radius


def add_vertex_on_sphere(n: int, radius: float = 1, name: str = ""):
    """球面上にランダムに頂点を作成し凸包にする

    :param n: 頂点数
    :param radius: 半径
    :param name: 名前
    """
    pts = [rand_sphere(radius) for _ in range(n)]
    mesh = bpy.data.meshes.new(name=name or "Sphere")
    mesh.from_pydata([Vector(pt) for pt in pts], [], [])
    obj = bpy.data.objects.new(mesh.name, mesh)
    bpy.context.scene.collection.objects.link(obj)
    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.mode_set(mode="EDIT")
    bpy.ops.mesh.convex_hull()
    bpy.ops.object.mode_set(mode="OBJECT")
    return obj


def set_five_color(obj):
    """隣り合う面に異なる色を割当"""
    colors = [
        (1, 0.1, 0.1, 1),
        (0.1, 0.2, 1, 1),
        (0.8, 0.8, 0, 1),
        (0, 0.8, 0.1, 1),
        (0.8, 0.2, 0, 1),
    ]
    bpy.context.view_layer.objects.active = obj
    # 編集モード
    bpy.ops.object.mode_set(mode="EDIT")
    bm = bmesh.from_edit_mesh(obj.data)
    # マテリアルのスロットを5つ用意
    for _ in range(len(colors) - len(obj.material_slots)):
        bpy.ops.object.material_slot_add()
    # 5つのマテリアルを作成
    for i, color in enumerate(colors):
        material = f"M{i}"
        mat = bpy.data.materials.get(material) or bpy.data.materials.new(name=material)
        mat.use_nodes = True
        mat.node_tree.nodes["Principled BSDF"].inputs["Base Color"].default_value = color
        obj.active_material_index = i
        obj.active_material = mat
    # 面ごとに隣り合う面と異なるように、色を若番から割当
    n = len(bm.faces)
    res = [0] * n
    dj = [[] for _ in range(n)]  # 面ごとの禁止領域リスト
    for edge in bm.edges:
        if len(edge.link_faces) == 2:
            i = edge.link_faces[0].index
            j = edge.link_faces[1].index
            dj[max(i, j)].append(min(i, j))
    for i in range(n):
        res[i] = ({1, 2, 3, 4, 5} - {res[j] for j in dj[i]}).pop()
    # 色のマテリアルを面に設定
    for face, i in zip(bm.faces, res):
        if i:
            obj.active_material_index = i - 1
            bpy.ops.mesh.select_all(action="DESELECT")
            face.select = True
            bpy.ops.object.material_slot_assign()
    bm.free()
    # オブジェクトモード
    bpy.ops.object.mode_set(mode="OBJECT")


if __name__ == "__main__":
    obj = add_vertex_on_sphere(30)
    set_five_color(obj)
```

参考：[BlenderでPythonを実行する方法](https://qiita.com/SaitoTsutomu/items/cec67381a8789b40e377)

以上
React Hook Form バリーデーション実装

ReactHookを使ってバリデーション機能実装の復習用記事です。

**React Hook Form**・・・入力フォームの管理に特化したReact向けのライブラリ
https://ja.reactjs.org/docs/uncontrolled-components.html

###バリデーション

実装コード

```react.tsx

const {
  register,
  handleSubmit,
  formSteate: { errors }
} = useForm<Values>();

```

useFormからメソッドを受け取る

register・・・入力または選択された要素を登録
handleSubmit・・・検証が成功するとフォーム内のデータを受け取る
formSteate: { errors }・・・バリデーションエラーを受け取る


```react.tsx

<input id="email"
       name="email"
       type="text"
       {...register("email", 
           {required: true,
           pattern:/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/,})}/>

```

inputに入力した内容がregisterに登録された内容で検証される

```react.tsx

<span className="text-red-600">
      {errors.email?.type === "required" && "メールアドレスを入力してください"}
      {errors.email?.type === "pattern" && "正しい形式でメールアドレスを入力してください"}
</span>

```

registerでエラーが発生した場合、そのregisterに設定したkeyでerrorから取り出すことができる{error.key}
エラーが存在しているかどうかでエラーメッセージを表示する
※typeでどの条件のエラーかを判別



####submitを押さなくてもバリデーションが行われる

```react.tsx

const {
  register,
  handleSubmit,
  formSteate: { errors }
} = useForm<Values>({mode:"onChange"});

```
mode:"onChange" ・・・submitを押さなくてもonChangeでバリデーションが実行される
スマホでリアルタイムで物体を認識したいなら、CoreMLモデルにカメラフィードを食わせるだけでOK 

#iPhoneのカメラでリアルタイムで物体認識をする方法です
![Jan-10-2022 13-44-52.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/59552d75-749b-820e-4e79-d605d9573c12.gif)

#スマホのカメラで物体認識をするのはかんたんなのか？
スマホのカメラにうつるものがリアルタイムで判別できれば、色々なアプリに応用できそう。
しかし、物体認識は機械学習でおこなうが、ちょっとややこしそうな気もする。
しかも、1枚の画像ならまだしも、リアルタイムでカメラの映像を認識するのは設定が多そう。

#CoreMLモデルにCaptureOutputを食わせるだけ
実は、それほどたくさんコードが必要なわけではない。
CoreMLモデルさえあれば、AVFoundationで取得したフレームをモデルに与えるだけで、リアルタイム物体認識ができる。

#手法

まずはCoreMLの画像認識モデルを入手する。
ネット上から入手できるので、好みのものを使おう。
[**Appleが公式に配布しているもの**](https://developer.apple.com/jp/machine-learning/models/)など、画像認識モデルにはいろいろな種類があり精度もさまざまだが、
今回は、CoreMLモデル・ズーである[**CoreML-Models**](https://github.com/john-rocky/CoreML-Models)から最新モデルである**RepVGG**をダウンロードしてつかってみる。

https://github.com/john-rocky/CoreML-Models

https://github.com/DingXiaoH/RepVGG

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/61936da7-c1db-c9dc-3574-302c53bf3ed2.png width=500>

モデルをSwiftで初期化する。

```swift
self.coreMLRequest = VNCoreMLRequest(model: try! VNCoreMLModel(for: try! RepVGG-A0(configuration:MLModelConfiguration()).model))
```

AVCaptureOutputのフレームをモデルに食わせる。

```swift
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {        
    guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }

    let handler = VNImageRequestHandler(cvPixelBuffer:buffer, orientation: .right, options: [:])
    do {
        try handler.perform([self.coreMLRequest])
        guard let result = self.coreMLRequest.results?.first as? VNClassificationObservation else { return }
        let label = observation.identifier
        let confidence = observation.confidence
    } catch let error {
        print(error)
        return nil
    }
}
```

これで、リアルタイムで認識結果のラベル（クラス名）と信頼度が得られます。
高速にフレームごとに処理してくれます。
![Jan-10-2022 13-44-52.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/59552d75-749b-820e-4e79-d605d9573c12.gif)

#さまざまな用途に

このような手法でスマホのカメラに映った任意のものをリアルタイムで判別できれば、コンシューマーだけでなく例えば監視カメラの映像を判別したり、工場のラインで物体認識したり、いろいろな用途に使えます。

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLやARKitを使ったアプリを作っています。
機械学習／AR関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
Linuxユーザーの追加・確認・削除

###現在ログインしているユーザーの確認
下記3つのうちどれか。

```bash
$ echo $USER
```

```bash
$ who
```

```bash
$ users
```

###ユーザー一覧の確認

```bash
$ cut -d: -f1 /etc/passwd
```

ユーザー名が分かっている場合は`grep`してあげる。

```bash
$ cut -d: -f1 /etc/passwd | grep hoge
```


###ユーザーを新規追加

ユーザーの登録

```bash
$ useradd testuser
```

ユーザーが登録されているかの確認

```bash
$ cat /etc/passwd | grep testuser

# testuser:x:1000:1000::/home/testuser:/bin/bash
```

###ユーザーにパスワードを設定

```bash
$ sudo passwd testuser
```

###ユーザーの削除

※ホームディレクトリ配下のユーザーディレクトリも削除する場合は`-r`オプションが必要。

```bash
$ sudo userdel -r testuser
```
sympyのplaneを調べてみた。

オリジナル

https://docs.sympy.org/latest/modules/geometry/plane.html

#Pycharmで

```python
from sympy import *
def myPtoM(myPoint3D):
    return Matrix([myPoint3D.x,myPoint3D.y,myPoint3D.z])
def myMtoP(myMatrix):
    return Point3D(myMatrix[0],myMatrix[1],myMatrix[2])
def myCrosstoP(P1,P2):
    return myMtoP(myPtoM(P1).cross(myPtoM(P2)))
def myPlane(myA,myB,myC):
    return Plane(myA, normal_vector=myCrosstoP(myB-myA,myC-myA))
O=Point3D(0.0,0.0,0.0)
A=Point3D(1.0,0.0,0.0)
B=Point3D(0.0,1.0,0.0)
C=Point3D(1.0,1.0,1.0)
D=Point3D(0.0,0.0,1.0)
myPlane1=Plane(O,D)
myPlane2=Plane(O, normal_vector=D-O)
myPlane3=myPlane(O,A,B)
#
print("#1",type(myPlane1),myPlane1)
print("#2",type(myPlane2),myPlane2)
print("#3",type(myPlane(O,A,B)),myPlane(O,A,B))
print("#1",myPlane1.projection(C))
print("#2",myPlane2.projection(C))
print("#3",myPlane3.projection(C))
#1 <class 'sympy.geometry.plane.Plane'> Plane(Point3D(0, 0, 0), (0, 0, 1))
#2 <class 'sympy.geometry.plane.Plane'> Plane(Point3D(0, 0, 0), (0, 0, 1))
#3 <class 'sympy.geometry.plane.Plane'> Plane(Point3D(0, 0, 0), (0, 0, 1))
#1 Point3D(1, 1, 0)
#2 Point3D(1, 1, 0)
#3 Point3D(1, 1, 0)
```
Windows版Oracle19cをインストールしようとしてハマったこと

# Introduction
Windows版Oracle19cをインストールしようとしてハマったことのメモです。
結論が残念過ぎて検索しても解決に至る検索結果が出てこなくてツラかったです。


# Environment
- Windows 10 Pro 21H1 19043.1415
- Oracle Database 19.3.0


# 現象
Database Configuration Assistant(dbca)でデータベースの作成をしようとすると、
[そのサービスは指定時間内に開始要求または制御要求に応答しませんでした。]
というエラーが発生してデータベースを作成できない。


# 結論
**デバイス名（コンピュータ名）を15文字以下にしてください。**

デバイス名[TUF-H370-PRO-GAMING]という名前を[H370]に変更したらできました。

名前を短くしたらできたという所でピンと来ました。
listener.oraでは以下の様にデバイス名が扱われます。

``` listener.ora
LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = H370)(PORT = 1521))
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
    )
  )
```

ホスト名になるのだから長過ぎる名前ではダメですね。


# References
## インストール方法
- [Oracle19c(Windows)メモ](https://qiita.com/kero3/items/e541cb17cc3e3146e41a)
- [【Oracle Database 19c】インストール手順【Windows】](https://ai-can-fly.hateblo.jp/entry/oracle-database-19c-install)
- [【Oracle Database 19c】DBCAを使用したデータベース作成【Database Configuration Assistant】
](https://ai-can-fly.hateblo.jp/entry/oracle-database-create)

## 何度も削除して試したので削除方法
- [Oracle Databaseソフトウェアの削除](https://docs.oracle.com/cd/F19136_01/ntdbi/removing-oracle-database-software.html#GUID-1423C1B2-5501-48AE-BE57-CFDF96290F6C)

## 作成後検証用のSQL*Plusの使用方法
- [SQL*Plusを使用したOracle Databaseへのアクセス](https://docs.oracle.com/cd/E96517_01/ntdbi/accessing-oracle-database-with-sql-plus.htm)
- [テーブル一覧、インデックス一覧、ビューの定義の一覧](https://www.shift-the-oracle.com/view/data-dictionary-view/table-index-view-list.html)
- [CREATE USER、ユーザーの作成](https://www.shift-the-oracle.com/config/create-user.html)

## 結論がわかって脱力した情報
- [コンピューター、ドメイン、サイト、および US の Active Directory の名前付け規則](https://docs.microsoft.com/ja-jp/troubleshoot/windows-server/identity/naming-conventions-for-computer-domain-site-ou)

## 今回は関係なかったが、発生したエラーの対策方法
- [登録されたサービス アプリケーションが開始に失敗する現象について](https://social.msdn.microsoft.com/Forums/vstudio/ja-JP/3bc24915-2ee8-4f64-90d7-6174e6cfe9f7/303313768212373124281238312469125401249912473?forum=windowssdksupportteamja)
- [[Oracle]46%で止まる。Database Configuration Assistant](https://www.tksoft.work/archives/4307)
Gmailで大量にメールを削除したらGmailが停止した話（解決方法あり）

死んだかと思った…。

**2021年1月10日夜、余談に更に追記**

# 結論
https://mail.google.com/mail/u/0/h/1pq68r75kzvdr/?v%3Dlui
ここにアクセスして簡易HTML形式でGmailに入る（ここで見れなかったら詰みかもしれない）
下の方に行き、Gmal表示を標準に切り替える
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597848/5e2784fd-f928-216e-af5b-872001c3b6b5.png)
以上で治るはず！

# 症状詳細
https://support.google.com/accounts/thread/16938729/一時的なエラーでgmailが開けません?hl=ja
ここにあるやつまんまです。Gmailにアクセスすると
> 一時的なエラー
>
申し訳ございませんが、Gmail は一時的にご利用いただけません。ご迷惑をおかけしますが、数分後にもう一度お試しください。サービスの現状は G Suite ステータス ダッシュボードでご確認いただけます。
>
しばらくしても問題が解決しない場合は Gmail ヘルプセンター » をご覧ください。
>
やり直す ログアウト
>
詳しい技術情報を表示しない
数値コード: 2

と表示されて、Gmailにアクセスできなくなります。僕の場合は、PC（2台同じネットワーク下）では両方とも同じ症状が出てきて、スマホ（同じネットワーク下）のアプリを使ったところ正常にアクセスできました。また、スマホからでは、送信も出来ることを確認しました。

Chromeの拡張機能では新しいメールの到着通知が来たので、アカウントBANではないというところまでは確信が持てていました。

# 原因

Gmailの容量が気になってみたら1.5GBあったので、ちょっとは減らすかぁということで、3万4千件ほどあるメールを検索して削除を繰り返し、7000件まで減らしたところでエラーが出ました。
おそらく、大量のリクエストに対してGoogle側がロックをかけたのが原因だと思います。

# 解決法の模索
まずは、日本語で検索するも有益な情報は出ず…（一番上に貼った記事ではどうにもできなかった。）
英語で検索したところやはり同じ症状の人がいました。
https://support.google.com/mail/thread/4322218/how-do-i-resolve-the-temporary-error-with-numeric-code-2?hl=en
で、以下の投稿を発見。
https://support.google.com/mail/thread/4322218/how-do-i-resolve-the-temporary-error-with-numeric-code-2?hl=en&msgid=17968269
>I'm having the same problem after deleting bunch of emails.
>I clicked this link (Basic HTML version).
>
>https://mail.google.com/mail/u/0/h/1pq68r75kzvdr/?v%3Dlui
>
>It loaded then clicked the standard version>
>It seems to have fixed the issue.

大量のメールを削除したときも同様の現象が起こるとのこと。そして、リンク先に飛んで、標準HTML表示に切り替えればうまくいくよ！とのことらしいので試したところ解決ということ。

# 対策
### メール削除の間隔
メールの削除は日頃からこまめに行う。確かに1日に2万件のリクエストを短期間に行うのはあまりにも馬鹿げているし、Googleから異常と判断されて止められても仕方ない。

### Googleに課金する
WorkSpace所持者なら、Googleに問い合わせることが出来るらしい。ドライブの容量も増えるしいっそのことそうした方が良いのではないかと思う。

### Google依存の脱却
流石に僕のアカウントは作成からちょうど10年目ということもあり、あまりにも多くのサービスが紐付けられているため、その現状を把握することが出来ないが、Twitter・Instagram・このQiita・その他連絡先に今回使えなくなったメアドを脳死で使用してしまっているため、このメアドが使えなくなると僕はネット上の屍になる。早急に有料アカウントを取得するとかして主要なアカウントは移動して、なんとかしないといけない。

# 余談
僕は今日この症状が出て、今日解決したところなので、まだ何もそれ以来起こっていないが、この症状は定期的に出る可能性があるらしいです。
これからしばらく怯えながらいつアカウントが停止されてもいいように準備していきます…

-----以下、追記分-----
結果として、Gmailで頑張って削除しまくったメールはたかが数十MBにしかなってなかったらしく、少し悲しい思いをしました。
Gmailの容量の大半はテキストのメールではなく、おそらくメールに含まれるファイルによるものだと思います。みなさんもGmailの容量を削減したいときは、ファイルを持っているメールを削除しましょう。

今回を機に、GoogleOneの契約をしました。年間2500円でGoogleアカウントの容量が100GBになりました。当分容量で心配することはないでしょう。同時に、GoogleOneに契約してあると、Googleのサポートに連絡出来るようになるらしいので、むしろそちらの権限を購入したというほうが正しいのかもしれません。Googleの誤BANといえば、YouTubeが有名ですが、（僕もやられたことがある）あっちはこんなふうにサポートに連絡して人とやりとりする権利すら買えないので、YouTubeでそういうのが出来たらめちゃくちゃ儲かるんじゃないかなぁなんて思いました。
アナログ−ディジタル変換入門

アナログ値からディジタル値に変換する際に、コンピュータ上でどのような処理が行われているのかをまとめてみます。
ちなみにアナログからディジタルに変換することを、**AD変換**(Analog to Digital Convert)といいます。
（こちらの記事の続きです↓）

https://qiita.com/tatataichi/items/01955133cc685d62c3a2


#なぜAD変換が必要なの？
コンピューターは1か0か（**ある**か**ない**か）しか処理ができないので、**1.5**とか、**0.1**とかそういった**1でも0でもない数値**は扱えません。

たとえば、**音**は空気を一定周期で振動させることで発生する情報です。
空気の振動はアナログ値の振動になります。
こんなかんじ↓
![スクリーンショット 2022-01-10 10.55.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2255713/b8437683-8d75-1507-4363-be2b51b9a112.png)
上図は-1から1までを行き来する波形であり、離散量であるディジタルではその間の数値は表現できません。
そのため、**現実世界に溢れている情報は全て1か0かに変換しなければいけません**。

#AD変換の流れ
ここからはAD変換の基本的な流れをまとめます。
詳細は後述しますが、基本的には以下のステップで変換していきます。

**1.標本化（Sampling）**
**2.量子化（Quantization）**
**3.符号化（Coding）**

ものすごくざっくりと説明すると、
アナログ信号を一定間隔で切り出して(標本化)、切り出したそれぞれの値をまるめて（量子化）、それらを二進数に直します（符号化）。

##標本化
標本化は英語でsamplingと言いますが、そちらの方が聞き慣れた方は多いかもしれませんね。
標本化のフェーズでは、**元となるアナログ情報を一定間隔で切り取っていきます**。
なぜそんなことをするのかと言うと、アナログ情報は途切れのない連続量ですので、その全ての量に対して変換作業を行うと**とんでもないデータ量になってしまう**ためです。

標本化のイメージとしては以下図になります。
以下図の**赤線が標本化**です。
![sampling.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2255713/72ac70f0-383b-5145-d411-8495dc8bf60f.png)
鋭い方はお気づきかもしれませんが、**標本化の間隔が狭ければ狭いほど情報の劣化が少なくなりますがデータ量も多くなります**。（逆に、間隔が広すぎると元の情報から大幅に劣化することになります）

そして、元の波形を正確にディジタル値に変換するためには、**元の信号の最大周波数の2倍以上の周波数**で標本化する必要があります。
これを**標本化定理**といいます。
その時の周波数のことを**サンプリング周波数**といい、元の周波数のことを**ナイキスト周波数**といいます。
また、サンプリング周波数の逆数を取ればサンプリングに必要な周期間隔である**サンプリング周期**も求められます。
サンプリング周波数を$f_s$、ナイキスト周波数を$f_n$、サンプリング周期を$T_s$とすると・・・

```math
f_s = 2f_n\\
f_n = \frac{f_s}{2}\\
T_s = \frac{1}{f_s}
```
という関係になります。


ちなみに、CDのサンプリング周波数は一般的に**44.1KHz**です。
これは**人間の可聴周波数が20Hz~20KHz**であり、
可聴最大周波数の20KHzをナイキスト周波数とした時に・・・

```math
\begin{align}
f_n &= 20 kHz\\
f_s &= 2\times　f_n\\
&= 2 \times　20KHz\\
&=40KHz
\end{align}
```

となるため、40KHz以上であれば元の周波数を完全に再現できることがわかります。
従って、人間が聴くCDのサンプリング周波数は40KHz以上である44.1KHzとなっています。

さらにちなみにの余談ですが、44.1KHzよりも高いサンプリング周波数でAD変換された音源は、**ハイレゾ**といったりします。人が聞こえる音以上の周波数でサンプリングしてどうするんでしょうね！！

##量子化
続いては標本化した波形を量子化していきます。
量子化はこの後に行う「符号化」をやりやすくするための中間作業です。

まずは縦軸を一定間隔で区切っていきます。そして元の値を区切った値にまるめて行きます。
この間隔のことを**量子化ビット数**といいます。
以下の図では量子化として、**●の値を▲の値にまるめていきます**。
![量子化.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2255713/5d1b0974-7d30-b0b1-49ce-f373d33cd815.png)
またしても鋭い方ならお気づきかもしれませんが、この**量子化ビット数が狭ければ狭いほど情報の劣化が少なくなりますがデータ量も多くなります**。
また、量子化で近似した値と元の値との間に生じる誤差は、**量子化誤差**と呼ばれ以下の通り求めます。

```math
\begin{align}
量子化誤差 = 標本化した値 － 量子化した値
\end{align}
```
##符号化
最後に、量子化した値を二進数に変換していく**符号化**という作業を行います。
![符号化.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2255713/cbbd06b9-16a7-a3bd-209d-b3e728e9a22f.png)

ということで、符号化された値を時系列順に上から並べてみると・・・
1000
1010
1001
0100
0001
0010
0110
1010
1001
1000
0101
0001
0001
0101
となります。

人間の目から見ればなんだこりゃな羅列ですが、コンピューターからみれば**元の波形を復元できるデータ列**となるわけです。

こんな感じで、コンピューターはアナログデータをディジタルに変換して行きます。
コンピューターで情報を処理するたびに情報が劣化するのは、標本化・量子化の段階で切り捨ててしまうからです。

最後の最後に余談ですが、パソコンやらスマホやらに音などのアナログデータを取り込むと、必ずAD変換が行われます。それには当然**声も含まれます**。
**声をAD変換して相手に送ったり受けたりすることで、「通話」をすることができます**。
その際に回線が重かったりすると、数秒分の音情報がつっかえた状態で送られたり、そもそもデータ送信自体が遅延したりすることで**「ラグ」が発生したり「急に早口になったり」します**。

以上、AD変換についてでした。