OmniAICreator/Qiita-1.07M huggingface dataset:
JavaScriptの配列について

# [JavaScript]配列について

## はじめに
配列はとても種類が多く、一回の投稿ではまとめることができませんでした。なので随時更新していこうと思います。勉強したものをアウトプットさせて頂きます。

## 配列とは何か？
複数の値をまるで1つのデータのように取り扱うことができるようになるもの。
、データを入れる箱のようなもの。

## 配列の作成方法
[]のなかにデータを入れていく。

```javascript

let drink = ['コーラ', 'オレンジジュース', '烏龍茶'];
```

##配列の要素を検索する方法
「indexOf()」は、指定した「値」が配列データに存在する場合にその場所を「インデックス番号」で取得できる機能を持っています。なのでこちらのメソッドを使用します。

```javascript

const drink = [ 'コーラ','オレンジジュース','烏龍茶','メロンソーダ','コーラ']

console.log(drink.indexOf('コーラ'));// 0
console.log(drink.indexOf('コーラ',2));//4
console.log(drink.indexOf('ぶどうジュース'));-1 配列に存在しないと-1が表示される。
```

##配列の要素を追加する
pushメソッドを使用することで配列の最後に要素を追加できる。

```javascript

let drink = ['コーラ', 'オレンジジュース', '烏龍茶'];

drink.push('メロンソーダ');
 
console.log(drink);　　// =>['コーラ', 'オレンジジュース', '烏龍茶' 'メロンソーダ']
```

##配列の要素を削除する
deleteメソッドを使用することで、指定した要素を削除できます。

```javascript

let drink = ['コーラ', 'オレンジジュース', '烏龍茶'];

delete drink[1];
 
console.log(drink);　　// =>['コーラ', '', '烏龍茶']
```

##配列を連結・結合する方法
join()メソッドを使用することで、配列の各要素を連結・結合して「文字列（String）」として出力することができる。
※引数に何も指定しなければカンマ区切りになります。

```javascript

const months = [2022, 2, 8 ];
 
const result = months.join('/');
 
console.log( result );　　// =>2022/2/8
```

##処理した要素を新しい配列で作成する方法
map()メソッドを使用することで、処理した後に新たに配列を作成してくれます。

```javascript

const months = [1,2,3,4,5];
 
const result = months.map(function( value ) {
 
    //配列の各要素を2倍にする
    return value * 2;
 
});
 
console.log( result );　　// =>[2, 4, 6, 8, 10]
```

##配列要素を繰り返し処理する方法
forEach()メソッドを使用することで、配列データに対してのみ実行することが可能で、各要素1つずつに任意の処理を実行させることができます。

```javascript
const drinks = ['コーラ', 'オレンジジュース', '烏龍茶']

drinks.forEach(function (drink, i) {
    console.log(`${i}:${drink}`) //配列の要素が置き換わるので添字が必要ない
})// =>"0:コーラ","1:オレンジジュース","2:烏龍茶"
```


大まかではありますが配列についてまとめてみました。
勉強したらまた投稿させて頂きます！
Laravelにおける、UT実装でのメソッドのモック化

## 使うタイミング
PHPUnitでテストコードを作成するとき、実際に呼ぶと全ての機能が通るテストデータを毎回用意するのは大変なので、既存のメソッドを呼ぶだけの場合はモック化したほうが早いのでよく使う。
※それぞれの機能のテストを既にしていること。
※最後まで処理を通す正常系ならモック化せずテストデータを用意して通すべきで、例えば3つ目のメソッドで例外を出したときに、予期するエラーメッセージで例外が発生することを確認したい場合や指定メソッドが指定回数呼ばれているかの確認などにモック化が有効。
例外が出るようにテストデータを調整してもよいが、処理が複雑だとかなりの時間がかかるので、こういうときはモック化すると効率が良い。

モック化で便利なのが、「Mockery」
https://readouble.com/mockery/1.0/ja/index.html

## 実際に使う
まず、use文で使える状態にする。

```php:hogeTest.php
use Mockery;
```

テスト対象メソッドを呼ぶためのクラス変数を用意

```php:hogeTest.php
private $hoge_rp;
```

モック化に限らず、テスト対象のメソッドを呼べるようにするために、
テスト前処理として、setUp()の中に設定しておく
※PHPUnitであらかじめ用意されているもので、自動的に呼ばれる。

```php:hogeTest.php
    public function setUp(): void
    {
    $this->hoge_rp = app()->make(HogeService::class);
    }
```

→以下の例では、HogeServiceクラスの中のupdateHogeメソッドをモック化している。

```php:hogeTest.php
        $mock = Mockery::mock(
            app(HogeService::class)
        )->makePartial();
        $mock->shouldReceive('updateHoge')->andReturn(true);
        $this->app->instance(HogeService::class, $mock);
        $this->hoge_rp = app()->make(HogeService::class);
```
→Mockery::mock()の第一引数に、モック化したいメソッドのあるクラスを指定
→shouldReceive()の中に、モック対象のメソッド名を指定
→andReturn()の中に、好きな想定戻り値を指定。これを指定するだけで、もしメソッドの中身が何もなかったとしてもtrueを返してくれる。なのでテストデータを用意しなくても動作する
→instance()は、モックしたインスタンスをコンテナへ、instance結合する必要がある。
→最後の $this->hoge_rpは、モックの設定をする前に既に用意しているとして、これをモックの設定した後にもう一度こうやって書いてモックの設定を反映させるために必要。

## その他機能
その他様々なテストができるように、便利なメソッドが用意されている。


上記では、andReturnで指定した値で戻り値を返すように設定できたが、もちろん意図的に例外を発生させることも可能。
以下のように、andThrow()メソッドの中に独自の例外クラスを指定したりすると、
指定したメソッドで例外が発生するよう設定できる。

```php:hogeTest.php
$mock->shouldReceive('updateHoge')->andThrow(HogeException::class);
```

以下の例では、指定したメソッドが1回呼ばれていることを確認できる。つまり、指定したメソッドで例外を発生させたら、後続処理のメソッドは実行されないはずなので、そのようなテストをしたければ、times()の中に0を指定する。もし0を指定していて呼ばれないはずなのに呼ばれてしまっていたらテストが失敗するので、そういうテストが出来る。

```php:hogeTest.php
$mock->shouldReceive('getHogeData')->times(1)
```

## 感想
過去の現場で初めてモックを知ったときはなんとなーく仮で呼ぶものというか「未実装のものを仮で呼ぶ」みたいなふわっとした理解だったが、今ははっきりどういう時に使うものなのかが分かるようになってよかった。
nrf9160 : mqtt_simple MQTT connection failure return -12

nRF9160 の mqtt_simple サンプルアプリケーションの検証時に、

ユーザー認証機能を利用した際、mqtt_connect()実行時に -12のエラーが戻ってきた。

エラー番号-12は、バッファーサイズが足りない時のエラー。
といっても、実際に足りないわけではない。
問題だったのは、ユーザー名やパスワードなどが異常に大きなサイズで認識されていたこと。

外部で static な変数領域を確保し、必要に応じてそこに書き込むようにするだけでエラーは解消できた。

以上。
[01] 書籍「nginx 実践ガイド」の学習環境を docker-compose を用いて作成する


## 概要

`「nginx 実践ガイド」(渡辺高志 著) (インプレス)` の学習のための docker 環境構築メモである.

御著書(以降「nginx 実践ガイド」)は、物理ホスト上に nginx やその他サービスを導入する前提になっている.　そこで、Docker 上に「nginx 実践ガイド」の検証環境を構築するための手順を記す.

つまり、本記事は次の方針で記したものである. 従って nginx 設定については触れていない.

・**物理ホストを汚さずに「nginx 実践ガイド」の学習ができるように、docker 上に同環境を作る手順を記す**
・**ただし、「nginx 実践ガイド」の無断転載にならぬように nginx に関する内容は記さない**


## 環境

### ホスト

| 項目 | バージョン |
|:--|:--|
| OS | Ubuntu 18.04 |
| docker-compose | 1.29 |
| Docker Engine | Community 19.03.13 |

### docker コンテナ

| 項目 | バージョン |
|:--|:--|
| nginx | 1.21 |
| jekyll | 4.0 |

　

## docker-compose 置き場

使い方は RADME.md に記している

```
https://github.com/robozushi10/nginx-jekyll.git
```

　

## 補足説明

### 1. 構築するシステムの構成

nginx の設定を変更したい場合は PV/etc/nginx/conf.d/default.conf を編集する.

本サンプルでは、PV/SHARE/www/dir/. に公開したいファイルを配置する.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1246056/f94e12f9-6055-a679-fe3c-8dcb23f16996.png)

　

### 2. ファイル構成

「nginx 実践ガイド」の無断転載になるといけないので、詳細は記さない

```
./PV
./PV/nginx
./PV/nginx/etc
./PV/nginx/etc/nginx  #.................... Docker Image「nginx:1.21」から取り出したファイルを置く
./PV/nginx/etc/nginx/fastcgi_params #...... Docker Image「nginx:1.21」から取り出したファイル
./PV/nginx/etc/nginx/scgi_params #......... Docker Image「nginx:1.21」から取り出したファイル
./PV/nginx/etc/nginx/nginx.conf #.......... 「nginx 実践ガイド」を参照
./PV/nginx/etc/nginx/uwsgi_params #........ Docker Image「nginx:1.21」から取り出したファイル
./PV/nginx/etc/nginx/conf.d
./PV/nginx/etc/nginx/conf.d/default.conf #. 「nginx 実践ガイド」を参照
./PV/nginx/etc/nginx/mime.types #.......... Docker Image「nginx:1.21」から取り出したファイル
./PV/nginx/etc/nginx/modules #............. Docker Image「nginx:1.21」から取り出したファイル(symlink)
./PV/SHARE
./PV/SHARE/www
./PV/SHARE/www/dir
./PV/SHARE/www/dir/index.html .......... 日時を書き出しただけのテキストファイル
./PV/SHARE/www/dir/_site
./PV/SHARE/www/dir/_site/index.html .... 上記 index.html が複製されて配置される
./docker-compose.yml

```

### 3. ファイル詳細

#### docker-compose.yml

```yaml
version: '3.7'
services:
  nginx:
    image: nginx:1.21
    container_name: mynginx0121
    ports:
      - "51338:80"
    volumes:
      - "./PV/nginx/etc/nginx/:/etc/nginx/"
      - "./PV/SHARE/www/dir:/www/dir"
    logging:
      driver: json-file
      options:
        max-file: '4'
        max-size: 1m
    depends_on:
      - jekyll
  jekyll:
    image: jekyll/jekyll:4.0
    container_name: myjekyll
    expose:
      - "4000"
    command: >
        bash -c '
          date +"%Y/%m/%d %H:%M:%S" > /srv/jekyll/index.html
          jekyll serve --force_polling
        '
    volumes:
      - "./PV/SHARE/www/dir:/srv/jekyll"
    logging:
      driver: json-file
      options:
        max-file: '4'
        max-size: 1m
```

　

## 実行結果

次のように物理ホストの `./PV/SHARE/www/dir/index.html` が配信されていれば OK.

index.html は docker-compose.yml の中で作成しており、単に日時が記されたファイルである.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1246056/d1e133ee-b3df-87c0-306b-3b35b3549f13.png)

　

以上.
【RDKit事始め】RDKit+Jupyter notebookの環境構築

# RDKitとは
ケモインフォマティクス（cheminformatics: 化学 x 情報学の分野）やマテリアルズ・インフォマティクスで使われるオープンソースのツール。

- 化学分野に特有のファイルであるsdfファイルやSMILES表記の読み書き
- 2D、3Dで分子を描写し、反応性が高い部位などを描画する
- LogPなど分子の各種指標（記述子と呼ばれる）を計算する

など、化学物質を統計的に扱ったり、構造を確認する上で、様々なことができる。

# RDKit+Jupyter notebookの環境構築

RDKitは、Pythonで動かすが、通常のライブラリのように、<b>pip installが使えない</b>（<a href="http://rdkit.blogspot.com/2019/11/why-rdkit-isnt-available-on-pypi.html">→理由</a>）。<a href="https://www.rdkit.org/docs/Install.html">RDKitの公式サイト</a>では、Anacondaを使ってそれ専用の環境を用意する方法をすすめているので、基本的にそれに従ってインストールする。

本記事ではさらにJupyter notebook上で、R言語のようにインタラクティブに動かす環境の構築を目指す。Jupyter notebookを使うと、データやライブラリをいちいち読み込まなくていい上に、実行結果を随時確認できるのが便利である。（ただし、画像データを扱うときに一工夫必要な時がある。）

# 手順
【動作確認OS】Windows 10、MacOS

1. Anacondaを（<a href="https://www.anaconda.com/products/individual">公式サイト</a>）からダウンロード・インストールする。


1. Anacondaがすでにインストールされている場合には、conda prompt（＊Windowsの場合。Macの場合はターミナル上、以下同様。）上で、```$ conda update conda```をして最新の状態にアップデートしておく。


1. conda prompt上で、```$ conda create -c conda-forge -n my-rdkit-env rdkit```と入力して実行。インストール途中で proceed?と聞かれたら```y```を入力してEnter。


1. RDKitのインストールが終わったあと、```$ conda activate my-rdkit-env```とすると、RDKitが動く環境がアクティベートされる（プロンプト上に(my-rdkit-env)の文字が表示される）。


1. 上記の状態で、<code>$ conda install notebook ipykernel</code>と入力して実行し、my-rdkit-env環境の中にJupyter notebookをインストールする。

1. 続けて、<code>$ipython kernel install --user --name my-rdkit-env</code> とすると、Jupyter notebookのkernelに、作成した”my-rdkit-env”環境が追加される（再起動すると表示されるようになる）。

1. Jupyter notebookを開いている場合にはいったん終了する。conda promptを閉じ、Anacondaを終了する。

# テスト：SMILESから構造式を描写してみよう！
1. Jupyter notebookを開く。conda promptで<code>$jupyter notebook</code>と入力すると、WebブラウザでJupyter notebookの画面が立ち上がる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523984/fc8e3d13-5478-d091-d228-f710bb5a5512.png)

1. 右上の「新規」からプルダウンでmy-rdkit-envをクリックする。
1. ファイルを開いたら、セルに以下を入力する。

```
from rdkit import Chem
m = Chem.MolFromSmiles('COC(=O)c1ccccc1O')
m
```

入力したセルを実行する（Shift+Enter）と、以下の出力が得られる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523984/d23f42be-f09c-cc44-55cf-ec585273f341.png)

# もっと色々な機能を試したい人は...。
有志の方が公式ドキュメントを日本語に翻訳してくれています。順に試してみましょう。
https://rdkit.org/docs_jp/Getting_Started_with_RDKit_in_Python_jp.html
webのキャッシュについて

以前実務で、「キャッシュよく使うから調べといて〜」的なことを言われ、調べたので解説します

##キャッシュって何？
キャッシュとは、**以前みたWebサイトのデータを保存する仕組み**のことです

普通、Webサイトをみるには、ブラウザがwebサーバーにリクエストを投げて、webサーバーがレスポンスを返すということが行われています

そこで先人達は考えたんです。「最近訪れたサイトをあらかじめブラウザ上でデータを保存しておけば、Webサーバーにリクエスト送らんでも良くね？しかも表示スピード上がるやん！」ってなったわけです。

そこで生まれたのがキャッシュというものです

キャッシュは、ブラウザごとにデータ保存量の上限が決まっていて、上限に達すると、古い情報ずつキャッシュのデータが削除されていきます

##キャッシュのメリットとデメリット
メリットは先ほども述べたように、Webサイトを高速で表示できるというのがメリットです。
しかしながら、デメリットもあります。

キャッシュは、以前訪れたwebサイトの情報を保存しているため、サイトの情報を更新されていたら変更内容が保存されないんです。

キャッシュサーバーやキャッシュブラウザなどの用語もあったので、それも追々調べていこうとおもいます
flattenメソッドについて

##flattenメソッド
flattenという英単語は、均す(ならす)という意味です。
flattenメソッドとは、多次元配列を1次元配列に変えるメソッドなんです。
実際にコードを見ていきましょう

```
arr = [1, 2, 3, [6,8], 9]
arr.flatten
=> [1, 2, 3, 6, 8, 9]
```
上記の例をみると、多次元配列が、1次元配列になっています。

このメソッドは配列だけでなく、ハッシュでも使われます。ハッシュで使われると、1次元配列にしてくれます。
実際にコードを見ていきましょう

```
hash = { 'hoge': 100, 'fuga': 200 }
hash.flatten
=> [:hoge, 100, :fuga, 200]
```
このようにハッシュでも1次元配列にしてくれるメソッドなんですね。

多次元配列じゃない配列に破壊的メソッドであるflatten!を適用すると、nilが返ってくるんです。

```
 ['hoge','fuga','hogehoge','fugafuga'].flatten!
=> nil
```

##実際に問題を解いてみましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485775/8e6d8e86-497d-3326-da26-c4eb6cada449.png)
Rubyの自己代入（||=）について

実務をこなしていく中で、自己代入を使ったコードをよく見るので、それを解説していきます。

例えばこんなコードです。

```
a = 'hoge'
b ||= 'fuga'
b
=> "fuga"
```
このコードでは自己代入が使われています。この自己代入とは
**左辺の変数が、nilもしくはfalseのとき||=の右辺にある値を代入する**という意味です。
上記のコードでいえば、変数bがnilもしくはfalseのときfugaという文字列を変数bに入れてくださいね、という意味になります。
変数bはそれに当てはまるので、bにはfugaという文字列が入ります。

下記のようなコードを書いて見ましょう

```
a = 'hoge'
a ||= 'fuga'
a
=> "hoge"
```
上記のコードでは、aはfalseでもnilでもないのでfugaはaに代入されません。

```
a ||= 10
```
上記のコードは、

```
a = a || 10
```
このように論理演算子で考えると分かりやすいとおもいます。論理演算子の理解があやふやな方は、[こちら](https://qiita.com/wangqijiangjun/items/f23fd235fe783fde46b4)の記事を参照してみてください。

以上です。何か間違いがございましたら、ご教示いただけますと幸いです。

【参考資料】

https://docs.ruby-lang.org/ja/latest/doc/spec=2foperator.html

https://qiita.com/ryosuketter/items/3e5f7cc46163a8c247ed
public_sendとsendの違い

実務をしていく中で、public_sendとsendというメソッドが出てきたので、詳しく調べたので、記事にしようとおもいます。

結論からいうと、privateメソッドを呼び出せるか否かの違いなんです。
詳しく解説していきます

##privateメソッドとは
privateメソッドと普通のメソッド(クラスメソッドやインスタンスメソッド)の違いは、他のクラスで使えるかどうです。
実際に具体例を見ていきましょう

```
class Test
  def public_method
    puts 'publicメソッドだよーん'
  end

  private

  def private_method
    puts 'privateメソッドだよーん'
  end
end

class Test2
  def public_method2
    puts 'これもpublicメソッドだよーん'
  end

  test = Test.new
  test.public_method
  => publicメソッドだよーん

　test.private_method
　=> NoMethodError: undefined method `private_method' for #<Test2:0x0000000007d78578>
end
```
まず、privateメソッドでないインスタンスメソッドを定義するとクラス外でも使えるんです。上記の例にあるようにTest2クラス内でも、Testクラスのpublic_methodをつかえるんですね。
しかし、privateメソッドを書くと、クラス外からは呼び出せないんです。上記の例のように、NomethodErrorが起きます。

##public_sendメソッドとsendメソッド
上に書いたprivateメソッドの意味を理解したうえで、この2つのメソッドを見ていきます。
結論からいうと、先ほども述べましたが、privateメソッドを呼び出せるか否かの違いなんです。

先ほどのコードを例に見ていきましょう

```
class Test
  def public_method
    puts 'publicメソッドだよーん'
  end

  private

  def private_method
    puts 'privateメソッドだよーん'
  end
end

Test.new.public_send(:public_method)
=> publicメソッドだよーん
Test.new.public_send(:private_method)
=> NoMethodError: private method `private_method' called for #<Test:0x00007fbd6c6c6160>

Test.new.send(:public_method)
=> publicメソッドだよーん
Test.new.send(:private_method)
=> privateメソッドだよーん
```
public_sendメソッドはプライベートメソッドじゃないメソッドのみを呼び出せます。
ちなみに、public_sendメソッドの引数はシンボルだけでなく、文字列でもOKです。

それに対して、sendメソッドは、プライベートメソッドも呼び出せるんです。
ぼく個人的には、sendメソッドは脆弱性があるんじゃないのかなとおもいます。

##いつ使えるか
条件別にメソッドを使いたい時に使います
具体的に見ていきましょう

```
class Test
  def math(result)
    puts "数学は#{result}です"
  end

  def english(result)
    puts "英語は#{result}です"
  end

  def chinese(result)
    puts "中国語は#{result}です"
  end
end

test = Test.new
test.public_send("math", "合格")
数学は合格です
test.public_send("english", "不合格")
英語は不合格です
test.public_send("chinese", "合格")
中国語は合格です
```
このように条件別にメソッドの使い分けができるんです。

以上です。
何か間違いがございましたら、ご教示いただけますと幸いです。

【参考資料】

https://nyakanishi.work/%e3%80%90ruby%e3%80%91public_send%e3%81%a8send%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6/

https://docs.ruby-lang.org/ja/latest/method/Object/i/send.html

https://qiita.com/ngron/items/05d3a9624c2c3ec5dbb6

https://qiita.com/mitsuooo/items/0ffadc6ab696ef903f65
Ruby  Threadについて

##Threadとは？

メインのプログラムを読み込む作業と並列して実行されるrubyのプログラムのことです。
実行したいプログラムを分担するようなイメージですね。

その並行して実行させているプログラミングのことを並行プログラミングといいます。

##Threadの種類と、それの作り方
Threadには、プログラムが開始されたときに実行されるmainThreadや、現在実行されているcurrentThreadなどがあります。

実際にそのコードを打ってみましょう

```
p Thread.main
=> #<Thread:0x000001d6ff90c450 run>

p Thread.current
=> #<Thread:0x000001d6ff90c450 run>
```
自分の実行環境では、スレッドを作ってないため参考にならないかもしれませんが、違う数字が返ってくることもあります。

では、実際にあらたなスレッドを作ってみましょう。
スレッドの作り方はnew, start, forkを使って、その後ろにブロックをつけてあげることで生成することができます。

```
Thread.new { 'hogehoge' }
=> #<Thread:0x000001d684e78680 (irb):108 run>
Thread.fork{ 'fugafuga' }
=> #<Thread:0x000001d684eb2e98 (irb):114 run>
Thread.start{ 'fugahogefuga' }
=> #<Thread:0x000001d684e09e60 (irb):115 run>
```

##並行プログラミングを実際に使ってみる

```
#スレッドを使わない場合
def hoge
  sleep(2)
  puts Time.now.strftime("%H時%M分%S秒")
  p 'hoge'
end

def fuga
  sleep(2)
  puts Time.now.strftime("%H時%M分%S秒")
  p 'fuga'
end

hoge
10時48分18秒
=> "hoge"

fuga
10時48分20秒
=> "fuga"


#スレッドを使った場合
threads = []
threads << Thread.fork { hoge() }
threads << Thread.fork { fuga() }

threads.each { |thr| thr.join }

=>10時56分26秒
"hoge"
10時56分26秒
"fuga"
```

上のコードを書くことで、複数の処理を同時並行で処理が可能になるんです。
※上のコードでjoinメソッドを使っていますが、[公式ドキュメント](https://docs.ruby-lang.org/ja/latest/method/Thread/i/join.html)によると、処理が終わるまで待機していると書いているのですが、上のコードでなぜ処理が終了する時間が同じなのかわかりません。
分かる方いらっしゃったらご教示いただけると幸いです。
【参考資料】

https://qiita.com/k-penguin-sato/items/1326882c400cac8c109b

https://docs.ruby-lang.org/ja/latest/class/Thread.html

https://wa3.i-3-i.info/diff165thread.html
[備忘録]4GPiセッティング

# 4GPiセッティング

- 4gpi用OS
https://github.com/mechatrax/4gpi/tree/master/os


- ラズパイセットアップ
http://kobore.net/4GPi.mm.html
https://qiita.com/vascodagama/items/114619c2bcf020226cd7

以下、例

```
nmcli con add type gsm ifname "*" con-name <name> apn <apn名> user <user> password <password>
```


- APN設定
APNとは、携帯電話ネットワークのデータ通信で必要になる接続先を指定する識別子の事
http://kobore.net/4GPi.mm.html

- nginx導入
https://www.fabshop.jp/webserver-nginx/

- nginxに接続
http://raspberrypi.local/

- /boot/config.txtに書く

```
dtparam=i2c_arm=on
dtparam=i2c_vc=on
dtoverlay=rpi-sense
```

- /etc/modulesに書く

https://yamaryu0508.hatenablog.com/entry/2015/03/10/214144

```
echo i2c-dev >> /etc/modules
```


- MSS設定でネットワークにつながるようにする


https://qiita.com/sirius246/items/dd0f008d4e5ad3ccb989#3-dhcp%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E8%A8%AD%E5%AE%9A
ジェネレータ メモ


```python
def test():
    yield [1,2,34] # ここで一時停止
    print('aaaa')  # 2回目のnext実行中に出力される


def test2():
    gen = test()
    print(next(gen)) # [1,2,34]
    print(next(gen)) # 'aaaa'
```
```
[1, 2, 34]
aaaa
StopIteration
```

----
【備忘録】異なるネットワーク同士をつなげるためには？

#SSHするための環境を整備する方法
- DDNS
- グローバルIPの固定化
- IPVPN設定
#DDNS
ダイナミックドメインネームシステム (Dynamic Domain Name System、ダイナミックDNS、DDNS) は、動的に割り当てられるIPアドレスと、そのホスト名の対応を、動的に登録・管理する仕組みである。


###DDNSの必要性
・基本的にネットワークはインバウンド通信には厳しく、アウトバウンド通信には優しくなるように構築すため、インバウンド通信を厳しくするためにグローバルIPアドレスは度々更新されるようになっている。他にも数に限りがあるIPアドレスを有効に活用するためでもある。
・IP固定化よりもお手軽にできる。
・度々変更されるグローバルIPとドメイン名の紐付けに時間がかかるため接続が不安定になっていまうことがある。

#グローバルIPの固定化
・プロバイダに設定してもらう
・固定IPを持つSIMカードを購入する

#VPN
Virtual Private Network（バーチャル プライベート ネットワーク、VPN）とは、インターネット（本来は公衆網である）に跨って、プライベートネットワークを拡張する技術、およびそのネットワークのことである

###VPNの必要性
・機密情報の転送の際にPublic Networkを使用せずに専用回線によるPrivate Networkを使用して、物理的に改ざんや盗聴ができないようにしていた
・ただ専用線は費用が高くなるという欠点があり、インターネットを介したVPNが利用されるようになった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/908963/c30f0795-cf93-22a6-58f0-b3da114ad45d.png)

↑インターネット上に各PrivateNetworkを結ぶ仮想的な通信路を作る
（wikupedia参考：https://ja.wikipedia.org/wiki/Virtual_Private_Network）


###IPsecを利用したVPNの構築
・IPヘッダの後ろに「暗号ヘッダ：ESP」「認証ヘッダ:AH」をつけて、データを暗号化し解読できないようにする
・IPsecはRFC4301で策定されているネットワーク層のプロトコルであり、IPパケット単位での暗号化/認証を提供
・IPsecはESP(暗号ヘッダ)、AH（認証ヘッダ：パケットが改ざんされていないことを保証）、IKE(鍵交換：AHとESPの共通鍵の規定)の3つで構成されている
・トランスポートモードとトンネルモードの2つがある
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/908963/2c9ba5ff-c999-8c80-3c8e-038d8ac0e09d.png)
↑参考：https://www.atmarkit.co.jp/ait/articles/0011/27/news001_3.html


# 実践（ラズパイにVPNサーバを立てて異なるネットワークからSSH）

以下を参考に
https://qiita.com/nmatsui/items/30adbeebd15b4c3de0ea
FastAPIで異なるセンサーからデータをGETする

# FastAPIの動作確認

公式チュートリアルを見ながらmain.pyを作成し、ライブサーバーを実行する

https://fastapi.tiangolo.com/ja/tutorial/first-steps/

同一ネットワーク下で以下のようにGETすると、jsonが吐き出されます

```
curl http://127.0.0.1:8000　

→{"message":"Hello World"}
```

例えば、複数のセンサーがつながったラズパイを用意して、FastAPI経由で特定のセンサーデータを取得したい場合は以下のようなmain.pyを作成すれば良い

```
from fastapi import FastAPI

app = FastAPI()


@app.get("/sensorA")
async def root():
    return {"time": "yyyy:mm:dd","temp":"25degree"}

@app.get("/sensorB")
async def root():
    return {"time": "yyyy:mm:dd","humid":"40%"}

@app.get("/sensorC")
async def root():
    return {"time": "yyyy:mm:dd","co2":"400ppm"}

```

もちろん、ライブサーバーを立てたり閉じたりするのは面倒なので、以下のようにコードが叩かれたらサーバーも常に起動するようにしても良い


```
from fastapi import FastAPI
import uvicorn

app = FastAPI()


@app.get("/sensorA")
async def root():
    return {"time": "yyyy:mm:dd","temp":"25degree"}

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)
```


ラズパイにlocalhostのポート8000でライブサーバーを立てた場合は「<ラズパイIP>:8000」でGETできる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/908963/ce10ea8d-aaf9-fe3b-eba6-e1acd32f6917.png)



センサーAにレスポンスが来た際に以下のようにして、センサーAのデータが取得できるようにする。
sensorA_dataスクリプトに取得スクリプトを買いとけば良い

```
from fastapi import FastAPI
import sensorA

app = FastAPI()


@app.get("/sensorA")
async def root():
    sensorA_data = sensorA.get_data()
    return sensorA_data

```



Nginxに取得データ情報を飛ばし、確認

```
from fastapi import FastAPI
import sensorA

app = FastAPI()


@app.get("/sensorA")
async def root():
    sensorA_data = sensorA.get_data()
    return sensorA_data

```


外から作成したスクリプトを呼ぶ際はcurl
https://qiita.com/danishi/items/07dd1b2f2a28255f7a85



# メモ
- GET、POSTの使い分け
    - https://blog.senseshare.jp/get-post-method.html　　
- 忘れっぽい言葉「冪等性」
    - https://qiita.com/suin/items/316cb8aaf8dfcf11abae
- FastAPIの特徴
    - https://fastapi.tiangolo.com/ja/
- "async"による並行処理（非常に面白いハンバーガーの例えが載っています）
    - https://fastapi.tiangolo.com/ja/async/
- データモデルを用いて引数をカプセル化するのが常套手段らしい
    - https://fastapi.tiangolo.com/ja/tutorial/body/
- stripeのAPIを参考に
    - https://stripe.com/docs/api
[備忘録]Gitメモ

## Git
#### gitとは
分散型バージョン管理システムのことでLinuxのソースコードを効率的に管理するために開発された

#### 覚えるべきアクション
ローカルにレポジトリをクローン

```
git clone <path>
```

ブランチ確認

```
git branch
```

ブランチ作成

```
git branch <branchname>
```

ブランチ切り替え

```
git checkout <branchname>
```

変更内容を確認

```
git status
```

ローカルでの変更内容をstaged状態にする

```
git add <変更箇所>
```

starged状態の変更をローカルリポジトリに更新する

```
git commit -m <"コメント">
```

ローカルリポジトリの内容をリモートリポジトリに反映する

```
git push
```

リモートリポジトリの変更内容をローカルに反映
（pull = fetch + merge）

```
git pull
```

リモートのmasterブランチの内容をローカルの「origin/master」ブランチに反映

```
git fetch
```

ローカルの「origin/master」ブランチの内容をローカルの「master」ブランチに反映

```
git fetch
```

前回のstargedとの差分を表示

```
git diff
```


#### メモ
- gitについてはこちらに全て書いてある  
https://backlog.com/ja/git-tutorial/intro/01/

- originとmasterの違い  
origin : リモートリポジトリ  
master : メインブランチ  
ex) origin master : リモートリポジトリのmainブランチ  
https://qiita.com/seri1234/items/e651b3e108a695a92809

- origin/masterとorigin masterの違い  
origin/master : リモート追跡ブランチ  
origin master : リモートリポジトリのmasterブランチ  
https://qiita.com/bitarx/items/4558f86e43a2c3493fa9

- git pull,fetch,mergeの違い  
https://qiita.com/wann/items/688bc17460a457104d7d
- 共同開発で勉強すべきポイント  
https://qiita.com/mackeee-orange/items/afbed5ec3816d4af2e58


- git-flowの１部ランチ
https://qiita.com/hatt0519/items/23ef0866f4abacce7296


- conflictの調べ方
git merge main
IBMCloud CIS 移行ツール


IBMCloudのCISサービスのHint&Tipsになります。
利用中のCISの設定の移行ツールを紹介します。

[CIS tools (GitHub) へのリンク](https://github.ibm.com/NetworkTribe/CIS_Support/tree/master/tools)

IBMCloudのCDNサービスであるCISサービスを利用しており、CISのプランをStandardからEnterprizeへの移行検討されている方や、アカウントを一時停止して再度利用する際に設定を引き継いでおきたい方は利用をご検討ください。
DockerでReactの環境構築してみた

##環境

- macOS Big Sur 11.4
- Docker Desktop 4.4.2
- Docker 20.10.12

```
.
├ app
│   └ react-basic
└ docker-compose.yml
```
##手順

###1. docker-compose.yml
用意するファイルはこれだけです

```docker-compose.yml
version: "3"
services:
  node:
    image: "node:17"
    tty: true
    user: "node"
    working_dir: /home/node/app
    environment:
      - NODE_ENV=development
    volumes:
      - ./app/react-basic:/home/node/app
    ports:
      - "3000:3000"
```

###2. dockerコンテナの起動
```
$ docker-compose up --build (-d)
```

###3. Create React App
Dockerコンテナに入る
"node"の部分はコンテナ名

```
docker-compose exec node bash
```
Reactアプリを構築する

```
npx create-react-app .
```

###4.動作確認
 http://localhost:3000 にアクセス。
下のページが表示されれば成功
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524155/ee983e68-ad50-53dd-2485-8761dd30d28e.png)
SQLServerで個人的に忘れがちなクエリまとめ

すぐ忘れてしまうのでメモ
ごちゃごちゃですみません。。


## リネーム処理

```sql:リネーム 
EXEC sp_rename 'スキーマ.リネーム前テーブル名', 'リネーム後テーブル名';
```


## テーブル作成&更新日時の確認
```sql:テーブル日時 
SELECT
	name AS 'テーブル名',
	create_date AS '作成日時',
	modify_date AS '更新日時'
FROM
	sys.tables 
WHERE name like '%検索したいテーブル名%'
ORDER BY 更新日時 DESC
```


## テーブルロック確認
```sql:テーブルロック 
--管理者権限でのログインが必要
SELECT
     resource_type AS type --オブジェクトの種類
    ,resource_associated_entity_id as entity_id  --エンティティID
    ,( CASE WHEN resource_type = 'OBJECT' THEN
          OBJECT_NAME( resource_associated_entity_id )
      ELSE
          ( SELECT
              OBJECT_NAME( OBJECT_ID )
           FROM
             sys.partitions
           WHERE
               hobt_id=resource_associated_entity_id )
      END)
        AS object_name
    ,request_mode --ロックの種類
    ,request_type --要求の種類
    ,request_status  --状態
    ,request_session_id AS Session_id --セッションID
        ,(SELECT hostname 
          FROM sys.sysprocesses 
          WHERE spid = request_session_id) AS ProcessName
FROM
    sys.dm_tran_locks
WHERE
    resource_type <> 'DATABASE'
ORDER BY
    request_session_id
```


## 重複データの件数チェック
```sql:重複データの件数

SELECT COUNT( DISTINCT CONCAT(Aカラム, Bカラム)) AS 件数  FROM テーブル名 WHERE LEFT(Bカラム,2) = '00';

```


## カラム検索
```sql:カラム検索 

SELECT   SCHEMA_NAME(t.schema_id) AS SchemaName, 
	 T.name AS TableName,
         C.name AS ColumnName,
         K.name AS ColumnType
FROM     sys.tables AS T
            INNER JOIN sys.columns AS C
               ON T.object_id = C.object_id
            INNER JOIN sys.types AS K
               ON C.user_type_id = K.user_type_id
WHERE    C.name LIKE '%カラム名%'
ORDER BY SchemaName,
	 TableName,
         ColumnName;

```

## 列単位の照合順序の確認
```sql:照合順序の確認 

SELECT t.name TableName, c.name ColumnName, collation_name  
FROM sys.columns c  
inner join sys.tables t on c.object_id = t.object_id
WHERE t.name = 'テーブル名称' ;  

```


随時追加していきます！
WSLからSSHでGUIを表示する方法（自分用）

## 手順
### 1. WSLでGUIを表示させる

WindowsにVcXsrvをインストールして走らせる。Xmingでも可。

`DISPLAY`の環境変数を変更する。

Bashでは

```
export DISPLAY=$(grep nameserver /etc/resolv.conf | grep nameserver | awk '{print $2}'):0
```

Fishでは

```
set -x DISPLAY (grep nameserver /etc/resolv.conf | grep nameserver | awk '{print $2}'):0
```

WSL内から`xcalc`などで動作確認。

### 2.　クライアント側の`ssh_config`を編集する

`sudo vim /etc/ssh/ssh_config`で以下の通りに編集する。

```
Host *
   ForwardAgent yes
   ForwardX11 yes
   ForwardX11Trusted yes
   ...
   Port 22
   Protocol 2
   ...
   XauthLocation /usr/bin/xauth
```

### 3.　新しく追加された画面の.Xauthorityファイルを作成する

```
touch .Xauthority
xauth generate $DISPLAY .
```

### 4. サーバー側の`sshd_config`を編集する

```
X11Forwarding yes
X11UseLocalhost no
```

### 5. OpenSSHサーバーを再起動する

```
sudo systemctl restart ssh
```

SSHしてサーバ内から`xcalc`などを走らせて動作確認。
Azure DevOps Server でリポジトリをTFVCからGitに移行する手順

# 概要

Azure DevOps Server でリポジトリを TFVCからGitに移行する手順を記載する。

(1) Azure DevOps Serverの標準の機能でリポジトリをTFVCからGitに移行
(2) TFVCのリポジトリをアクセス不可に設定

という手順で作業する。

:::note
TFVCのリポジトリをアクセス不可に設定する手順は必須ではないが、誤操作を防ぐために設定を検討する。
:::

# 手順

## (1) Azure DevOps Serverの標準の機能でリポジトリをTFVCからGitに移行

### 事前確認

事前準備として、`.gitignore`の準備などが必要。次のページで必要な事前作業のチェックと実施を行う。
対象ブランチは1つ、最大180日間の履歴のみ移行、などの制限があるため、ドキュメントの十分な確認が必要となる。

https://docs.microsoft.com/ja-jp/devops/develop/git/migrate-from-tfvc-to-git

### 移行を実施

次のページの手順に従い、Azure DevOps ServerでTFVCからGitへの移行を実施する。

https://docs.microsoft.com/ja-jp/azure/devops/repos/git/import-from-tfvc?view=azure-devops

## (2) TFVCのリポジトリをアクセス不可に設定

### プロジェクトの設定から変更する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204150/aa820187-1d7a-7110-dbda-0f99fd944cc3.png)

### チェックイン権限

- CIの再構築も含めて動作に問題ないことを確認したら、誤って更新しないような設定を行う。
- 対象のTFVCリポジトリの「チェックイン」権限を拒否に設定する。
    - プロジェクト管理者
    - 共同作成者

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204150/f7349e0f-2ca0-ebc8-f9b2-9e26b0b17522.png)


### 読取り権限

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204150/39b3eb6f-cadb-f985-358a-9fe988903e04.png)


- 履歴が不要でな場合は、閲覧させないための設定を行う。
- 「読み取り」権限を「拒否」に設定する。
    - 共同作成者
    - 閲覧者
- 必要な場合は、プロジェクト管理者も読取権限を「拒否」に設定する。

:::note warn
プロジェクト管理者で読み取り権限を「拒否」とすると、設定も変更できなくなる。
最後のプルーフセーフとして、プロジェクトコレクション管理者は閲覧できるはずだが、プロジェクトコレクション管理者の権限で閲覧できる設定となっているかを事前に確認しておくこと。
:::
爆速で説明するreact-routerの使い方

# 目的
自分が読んだreactの最近の参考書にはreact-routerの使い方の説明が一切書かれていなかったため、[公式ドキュメント](https://reactrouter.com/docs/en/v6/getting-started/tutorial)を参考にして備忘録として使い方を記す。

# 実践
index.jsx(ts使うならtsx)に下記のように記載する。

各コンポーネント、ファイルの置き場所をsrc/routes,src/components配下としたが、これは特に定められているわけではないので場合によってはもっとネストさせたディレクトリの下などから呼ぶこともあるだろう。

## index.jsx
結局index.jsxを"root"にレンダリングするため、全てのRouteをindex.jsxに記載する。
HeaderやFooterなどの固定するものはどこのページでも表示するため、<BrowserRouter>内<Routes>外に記載する。

```<Route path="/" element={<Home />} />```では、URLを例えば```http://localhost:3000/```とすれば、<Home />コンポーネントが表示されるということ。

```index.jsx
import { render } from "react-dom";
import {
  BrowserRouter,
  Routes,
  Route
} from "react-router-dom";
import { Works } from "./routes/works";
import { Contact } from "./routes/contact";
import { Home } from "./routes/home";
import { Career } from "./routes/career";
import { Footer } from "./components/footer";
import { Header } from "./components/header";

const rootElement = document.getElementById("root");
render(
  <BrowserRouter>
    <Header />
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="career" element={<Career />} />
      <Route path="works" element={<Works />} />
      <Route path="contact" element={<Contact />} />
    </Routes>
    <Footer />
  </BrowserRouter>,
  rootElement
);
```

## header.jsx
ここでは```<Route path="/" element={<Home />} />```の場合は<Link>のtoにpathを記載する。

```header.jsx
import { Link } from "react-router-dom";
export const Header = () => {
  return (
    <>
      <nav
        style={{
          borderBottom: "solid 1px",
          paddingBottom: "1rem"
        }}
      >
        <Link to="/">Home</Link>
        <Link to="/career">Career</Link>
        <Link to="/works">Works</Link>
        <Link to="/contact">Contact</Link>
      </nav>
    </>
  );
}
```


# 参考

https://reactrouter.com/docs/en/v6/getting-started/tutorial

なんだかんだ公式が一番わかりやすいです。
sortメソッドと<=>の解説

##sortメソッド
sortとは、日本語で「並び替える」という意味です。つまり、sortメソッドとは、ある一定の基準で並び替えるメソッドです。
実際に具体例を見てみましょう

```
ary = [4, 2, 9, 8, 3, 16, 10]
p ary.sort
=> [2, 3, 4, 8, 9, 10, 16]
```
sortメソッドは、デフォルトで昇順に並び替えるメソッドです。上記の例では、配列の中身が昇順で並び変わっています。

降順で並び替えるには、2つの方法があります。
➀reverseメソッドを使う
➁<=>演算子を使う
順に説明していきましょう

##➀reverseメソッド
reverseとは「反転する」という意味です。つまり、reverseメソッドは、配列やハッシュなどの値を反転させるメソッドなんです。
実際にコードを書いてみると以下のようになります。

```
ary = [4, 2, 9, 8, 3, 16, 10]
p ary.sort.reverse
=> [16, 10, 9, 8, 4, 3, 2]
```
このように書けます。個人的にはメソッドを2個連続書けることに驚きました(今更なんですけどね笑)。同じクラスのメソッドは連続で書けるみたいですね。

##➁<=>演算子
宇宙船演算子ともいわれています。見た目が宇宙船に似ているからだそう。個人的にはあまり似ていないように見えますが笑
どんな使い方をするかというと、公式ドキュメントに書かれているのは
>self <=> other は
・self が other より大きいなら正の整数
・self と other が等しいなら 0
・self が other より小さいなら負の整数
・self と other が比較できない場合は nil

実際に具体例を見てみましょう

```
2 <=> 1
=> 1
2 <=> 2
=> 0
2 <=> 3
=> -1
2 <=> 'hoge'
=> nil
```
上記の具体例をみると、公式ドキュメントに書いてあることが理解できるとおもいます。要は、
>左辺が右辺よりも大きければ、1を返し、
左辺と右辺が同じでなら、 0 を返し、
左辺が右辺よりも小さければ、-1を返し、
比較できない場合は、nilを返す

それを理解したうえで、以下のようなコードを書くと降順になるんです。

```
ary = [4, 2, 9, 8, 3, 16, 10]
p ary.sort {|a, b| b <=> a}
=> [16, 10, 9, 8, 4, 3, 2]
```
僕はこの書き方を見て、{|a, b| b <=> a}をみて、「どんな処理をしてるんだろう？」って思ったので、どんな処理をしているのかを解説していきます。

##{|a, b| b <=> a}は何をしているのか？
これを考えるとき、比較するとよいのが下記のコードです。

```
ary = [4, 2, 9, 8, 3, 16, 10]
p ary.sort{|a, b| a <=> b}
=> [2, 3, 4, 8, 9, 10, 16]
```
ここで考えなければならないのが、各要素の「戻り値の合計」の変化によるものなんです。どんなものかを見ていきましょう
|a= 4, b=2|の時の戻り値 
4 <=> 2
=> 1
|a= 4, b=9|の時の戻り値 
4 <=> 9 
=> -1
|a= 4, b=8|の時の戻り値
4 <=> 8
=> -1
|a= 4, b=3|の時の戻り値 
4 <=> 3
=> 1
|a= 4, b=16|の時の戻り値
4 <=> 16
=> -1
|a= 4, b=10|の時の戻り値
4 <=> 10
=> -1

戻り値の合計は、1-1-1+1-1-1=-2

|a = 2, b=4|の時の戻り値 
2 <=> 4
=> -1
|a = 2, b=9|の時の戻り値 
2 <=> 9 
=> -1
|a = 2, b=8|の時の戻り値
2 <=> 8
=> -1
|a = 2, b=3|の時の戻り値 
2 <=> 3
=> -1
|a = 2, b=16|の時の戻り値
2 <=> 16
=> -1
|a = 2, b=10|の時の戻り値
2 <=> 10
=> -1

戻り値の合計は、-6
このように、a = 16までをやってみると、戻り値の合計が7個出てきます。

a=4のとき、戻り値の合計は、-1
a=2のとき、戻り値の合計は、-6
a=9のとき、戻り値の合計は、2
a=8のとき、戻り値の合計は、0
a=3のとき、戻り値の合計は、-4
a=16のとき、戻り値の合計は、6
a=10のとき、戻り値の合計は、5
この戻り値の合計を比較して、少ない順にみていくと、[2, 3, 4, 8, 9, 10, 16]と昇順になるんです。
つまり、

```
ary = [4, 2, 9, 8, 3, 16, 10]
p ary.sort{|a, b| a <=> b}
=> [2, 3, 4, 8, 9, 10, 16]
```
のようなブロックにすると昇順になるんです。理由が分かりましたね。
では逆に、

```
ary = [4, 2, 9, 8, 3, 16, 10]
p ary.sort{|a, b| b <=> a}
```
この場合はどうなるのでしょうか。
同じように計算すると、
a=4のとき、戻り値の合計は、1
a=2のとき、戻り値の合計は、6
a=9のとき、戻り値の合計は、-2
a=8のとき、戻り値の合計は、0
a=3のとき、戻り値の合計は、4
a=16のとき、戻り値の合計は、-6
a=10のとき、戻り値の合計は、-5
この戻り値の合計を比較して、少ない順にみていくと、[16, 10, 9, 8, 4, 3, 2]と降順になるんです。

まとめると、{|a, b| b <=> a}は何をしているのかというと、**要素同士の比較をしているということです。**

##実際に問題を解いてみましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485775/16015441-74f4-4c67-6599-3a406950c72f.png)

提示されているプログラムは、ブロック内で降順になります。降順になる理由は、先ほど述べましたね。
そして、降順になった配列にreverseメソッドを適用することで昇順になるんです。

よって、今回の正解は、選択肢➁です

以上です。
何か間違いがございましたら、ご教示いただけますと幸いです。
【参考文献】

https://docs.ruby-lang.org/ja/3.0/class/Array.html#I_SORT

https://pikawaka.com/ruby/sort#%E5%BF%9C%E7%94%A8%E7%9A%84%E3%81%AA%E4%BD%BF%E3%81%84%E6%96%B9

https://genkichi.hateblo.jp/entry/2019/02/25/130332
2 行目で与えられる N 個の整数の入力  JavaScript編

2 行目で与えられる N 個の整数の入力 JavaScript編

入力：5
　　　8 1 3 10 100

lines[0]が繰り返し回数、lines[1]に数値が半角スペースで入っている。

lines[1] を split で分割して適当な変数（配列）に代入し、それを  lines[0] 回、for文で繰り返し処理してあげればいい。

以下解答例

----
process.stdin.resume();
process.stdin.setEncoding('utf8');
// 自分の得意な言語で
// Let's チャレンジ！！
var lines = [];
var reader = require('readline').createInterface({
  input: process.stdin,
  output: process.stdout
});
reader.on('line', (line) => {
  lines.push(line);
});
reader.on('close', () => {
<font color="#000080">
  input = lines[1].split(" ");
  for(var i = 0; i < lines[0]; i++){
      console.log(input[i]);
  }</font>

});

----
基本情報技術者試験ロードマップ2022

## はじめに
IT未経験者が最短で確実に基本情報技術者試験に合格できるための学習の全体像をまとめました。
## この記事の対象者
■初学者
・IT企業に就職する学生
・未経験でIT業界への転職を考えている方
・会社から基本情報を取得するよう指示された方

■育成者
・研修担当者
## 午前試験対策
#### 過去問道場のアカウント作成
過去問道場を使います。
アカウントを作成しましょう。
https://www.fe-siken.com/fekakomon.php

#### 演習
隙間時間でひたすら過去問道場をやり込みます。
とりあえず1000問程度を目安にしてください。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266611/b971cb1f-c88d-e14e-0450-1147927eb690.png)

学習履歴を確認し、直近300問くらいの正答率が80％程度になればOKです。
（この画像では61％ですが・・・）
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266611/2473e46f-9d3e-597a-5e4e-62e4888ea4b7.png)

![基本.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266611/5832cffe-6835-6985-e308-bb1f0cc57fc9.png)

午前試験対策はこれ以上の勉強は不要なので、午後試験対策に移りましょう。

## 午後試験対策
#### 選択問題の決定
選択する問題を決めまで問題を見てから決めるのではなく、事前に決めた問題を重点的に学習します。
![スクリーンショット 2022-01-26 22.25.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266611/d2021612-4105-d079-548f-d7b9434ac611.png)

以下から3分野を選択して勉強します。
2分野だと勉強した分野が出題されない可能性があります。
マネジメント・ストラテジ系は主題範囲が広いのでオススメしません。

|分野|オススメ度|
|-----|-----|
|データベース|★★★|
|ネットワーク|★★★|
|ソフトウェア設計|★★|
|プロジェクトマネジメント、サービスマネジメント、システム戦略、経営戦略・企業と法務|★|
<br>
ソフトウェア開発分野は以下から1題を選択します。
未経験なら表計算ソフトを選択しましょう。経験のある言語なら選択してもいいかもしれません。

|問題|オススメ度|
|-----|-----|
|C|★|
|Java|★|
|Python|★|
|アセンブラ言語|★|
|表計算ソフト|★★★|

選択した問題の過去問を20回分（6問を20回）やりましょう。
試験本番で全く分からないという問題に出会う確率が限りなく0に近くなります。



## スケジュール
#### ではいつから勉強を開始したらいいのか？
余裕があるなら試験日の3ヶ月前から開始してください。

#### 試験の3か月～2か月前
午前：過去問道場を週100~200問
午後：過去問を週10問

#### 試験の2か月～1か月前
午前：過去問道場を週100~200問
午後：過去問を週10問

#### 試験の1か前～試験前日
午前：総合成績の正答率が不足している場合はここで調整
午後：過去問を週10問
<br>
このペースで進めると、午前1000～1500問、午後120問できる計算になります。


## ここまでやっても落ちてしまう人
#### データ構造とアルゴリズム、ソフトウェア開発の理解不足
この2分野は過去問の解説を理解していないと点数が取れません。
さらに両分野とも配点が25点で他より高いです。（ここが満点ならそれだけで50点になります）

## 最後に
以上、基本情報技術者試験に合格するまでのロードマップでした。
この記事がお役に立てれば幸いです。
1 行目で与えられる N 個の整数の入力 JavaScript編

1 行目で与えられる N 個の整数の入力 JavaScript編

入力：18 9941 4154 8745 6456 9469 1924 1482 2010 3807 2233 7584 7675 8767 9157 5553 9282 8693 279

入力が1行なので、splitで分割して変数に代入（ここではinput)。
input[0]がNなので、これをカウンターにしてfor文で繰り返し。

カウンタiの初期値を１にして、input[0]以下にしておくことで、iをそのままinput[i]と設定できる。
（input[1]～input[N]まで表示できる）

以下回答文

```js
process.stdin.resume();
process.stdin.setEncoding('utf8');
// 自分の得意な言語で
// Let's チャレンジ！！
var lines = [];
var reader = require('readline').createInterface({
  input: process.stdin,
  output: process.stdout
});
reader.on('line', (line) => {
  lines.push(line);
});
reader.on('close', () => {
  input = lines[0].split(" ");
  for(var i = 1; i <= input[0]; i++){
      console.log(input[i]);
  }
});
```
tailwind3.0 + react + typescript エラー

参考にした記事
[tailwind2.0 + react + typescript 環境構築](https://qiita.com/Mr_hana/items/f5f91011377cd6052e3b)

上記の記事通りすすめていったらいくつか躓いた点があったので記事にしました。
基本的な進め方は上記記事を参照してください。
tailwindのverが変わっておりそれに伴ってyarnスタート時にエラーが発生していました。

環境　
OS:win10

$ node -v
v16.13.2

$ yarn -v
1.22.17

$ npx create-react-app --version
5.0.0

<h2>エラーその１</h2>
```:gitbash
$ yarn start
yarn run v1.22.17
$ craco start
'craco' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
```


原因：すでにビルドしていたreactappがstartしたままの状態でtailwindとcracoをnpm installしたため正しくインストールできなかった

<h2>エラーその２</h2>
たぶん多くの人がこちらで引っかかったと思います。

エラー内容

```:gitbash
$ yarn start
yarn run v1.22.17
$ craco start
C:\myportfolio\node_modules\@craco\craco\lib\features\webpack\style\postcss.js:54
                craPlugins = match.loader.options.plugins();
                                                  ^

TypeError: match.loader.options.plugins is not a function
(省略）
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
```

原因：craco.config.jsの設定内容に問題があります。tailwind3.0からcracoの設定内容にtailwindに関する記述は必要なくなりました。

```js:craco.config.js
module.exports = {}
```

参考にしたサイト
https://github.com/facebook/create-react-app/issues/11771#issuecomment-997217680
フロントエンド初心者は何のテストを学習するの？②(ユニットテスト)

## フロントエンドのユニットテスト

今回は、フロントエンドのユニットテストについてアウトプットします。

フロントエンドのテストはチームの方針を元に行うべきで、確立してこれを行うといったことはないのかなというように感じました。

その中で、Testing Library の公式にはこのような思想が書かれています。

> The more your tests resemble the way your software is used,the more confidence they can give you.

私なりに訳すと、

**ユーザーの利用や挙動に似せたテストを行うことで、ソフトウェアに信頼性をもたらしてくれる。**

となりました。

フロントのエンジニアは、**ユーザーにとっての使いやすさ**をソフトウェア内で実現できているかをユニットテストを通して確認していくことが方針の1つだということになります。

**例**
**ユーザーがボタンをクリック**
↓
**イベント発火**
↓
**結果(テスト結果に整合性があるかどうか)**


## 簡単なテストを言語化してみる

### 【ログインの場合】(テスト用のemailとpasswordを用意)

ユニットテスト①
email入力
emailの値確認　←ここで[正常系と異常系](https://wa3.i-3-i.info/diff610test.html#:~:text=%E7%87%83%E6%96%99%E3%81%8C%E5%8D%81%E5%88%86%E3%81%AB%E3%81%82%E3%82%8B,%E3%81%8C%E7%95%B0%E5%B8%B8%E7%B3%BB%E3%83%86%E3%82%B9%E3%83%88%E3%81%A7%E3%81%99%E3%80%82)の確認をする。
ユニットテスト②
password入力
passwordの値確認　←ここで正常系と異常系の確認をする。

ユニットテスト③
buttonをクリック
送信処理のメソッド実行
送信結果またはページ遷移先の確認　←ここで正常系と異常系の確認をする。


こんな感じになりそうです。

```
表示→動作→表示→動作→表示→動作→表示→動作→表示→動作→表示→動作→表示→動作→・・・
```

これを1つずつ確認するのがユニットテスト。

### 注意
ユニットテストは細かく行おうとするとキリがありません。
「buttonがオレンジ色であること」はユーザーの挙動自体には関わりがないため、buttonを押した時にどう振舞うのかを確認するとこの方が大切です。



***
参考にした記事
1:[フロントエンドでTDDを実践する（理論編）](https://qiita.com/taneba/items/48db2ad9cf10ad644908)
2:[フロントエンドでTDDを実践する（react-testing-libraryを使った実践編）](https://qiita.com/taneba/items/b21f5fee17eb593b30c8#1%E8%A6%81%E4%BB%B6%E3%81%8B%E3%82%89%E3%83%86%E3%82%B9%E3%83%88%E3%82%B1%E3%83%BC%E3%82%B9%E3%82%92%E6%9B%B8%E3%81%8D%E5%87%BA%E3%81%99)
3: [フロントのテスト戦略！の知見が集まるところ](https://zenn.dev/seya/scraps/6f930e359d6a7c)
4: [React テスト応用、テストに悩む人へ](https://zenn.dev/tkdn/books/react-testing-patterns)
5: [【フロントエンド】コンポーネント指向（React, Vue）のテスト方針](https://qiita.com/noah-nao/items/3fd211deb8711fae8204)
HTMLのTableタグをJavaScriptの配列に変換する


HTMLのTableをcsvに変換するために色々調べてたんですが、その過程のJavaScriptでTable要素を配列に変換する方法をまとめておきます。

##HTML
HTMLの構造は以下の形を想定しています。

```jsx
<table id="table">
      <thead></thead>
      <tbody>
        <tr>
          <td>title</td>
        </tr>
        <tr>
          <td>1</td>
          <td>2</td>
          <td>3</td>
          <td>4</td>
        </tr>
        <tr>
          <td>1</td>
          <td>2</td>
          <td>3</td>
          <td>4</td>
        </tr>
        <tr>
          <td>1</td>
          <td>2</td>
          <td>3</td>
          <td>4</td>
        </tr>
        <tr>
          <td>1</td>
          <td>2</td>
          <td>3</td>
          <td>4</td>
        </tr>
      </tbody>
    </table>
```

##JavaScript
jsのコードはこんなかんじ

```jsx
const table = document.getElementById("table");
const tbody = table.lastElementChild;
const rowLength = tbody.childElementCount;
let resultArray = [];

CreateCSV();

async function CreateCSV() {
  // 配列の数が膨大な場合全件取得されない場合があるので非同期処理にする
  await CreateTableArray();
  // ↓以下にcsv変換したり、配列を利用するコードを書く↓
}

// CreateItemArrayの返り値をresultArrayに追加する
function CreateTableArray() {
  for (let i = 0; i < rowLength; i++) {
    let items = tbody.children[i];
    resultArray.push(CreateItemArray(items));
  }
}

// trタグ内のtdのテキストを全件取得し、配列に変換して返す
function CreateItemArray(items) {
  let array = [];
  for (let i = 0; i < items.childElementCount; i++) {
    let item = items.children[i].textContent;
    // 空白を取り除く
    item = item.replace(/^\s+|\s+$/g, "");
    array.push(item);
  }
  return array;
}
```

余談ですが、csvに変換する際には以下の記事が参考になりました。
[Javascriptを使ってCSVを生成してダウンロードする - 自動化無しに生活無し](https://noauto-nolife.com/post/javascript-download-csv/)

他に参考になったサイトや公式のドキュメント
[Element.childElementCount](https://syncer.jp/javascript-reference/element/childelementcount)
[Element.lastElementChild - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element/lastElementChild)

参考になれば幸いです。
GoogleDriveのファイルをコードからダウンロードしたい gdown

#ColabなどでGoogleDriveからファイルをダウンロードする方法です
![laputa049.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/1e1297a3-8f2b-c97b-18ac-9c2543e9b256.jpeg)

#大きなファイルをColabで扱いたい
機械学習モデルのデータセットやウェイト・チェックポイントなど、リポジトリ作成者が提供してくれたファイルはしばしばGoogleDriveにアップロードされています。
Colabで扱う際に、ドライブをマウントしてショートカットを作成してもいいのですが、Zipファイルなどの場合はダウンロードすると扱いやすいんじゃないかなと思います。
wgetやcurlでは大きなファイルはgoogleDriveからダウンロードできません。

#gdown
そこで便利なのがgdownです。

```python
import gdown

url = 'https://drive.google.com/uc?id=**************'
out_path = 'dataset.zip'
gdown.download(url, out_path, quiet=False)
```
これでダウンロードできます。

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

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

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
スプレッドシート　ピボットテーブルの範囲をGoogleAppsScript（GAS）で更新する



スプレッドシート上で作成したピボットテーブル。
便利なのですが、困ったことが。
<b>ピボットテーブルのデータ範囲が自動で更新されない。</b>

エクセルで作成したピボットテーブルなら、あたりまえのようにデータ範囲は自動で更新されるのに
<b>※ソースの指定をソース'!A:Gにしたら自動で更新されます。コメント欄で共有していただきました。(2022/12/24)</b>
過去の自分に教えてあげたい。!!

毎日ピボットテーブルのデータ範囲を手動で更新するのは嫌だと苦情がきたので、
GoogleAppsScript（GAS）で自動更新します。
<b>※Query関数でも似たようなことができるとコメント欄で共有していただきました。(2022/6/24)</b>

##環境・前提
・スプレッドシートでピボットテーブルを作成している
・GoogleSheetsAPIが有効になっている
・ただし、リアルタイムに自動更新されないので、GASにタイマーを設定する(時間指定のトリガー)
・シート名で管理しているの



具体的には以下の箇所をGoogleAppsScriptで更新します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369082/4f6ae591-2bc5-97e3-2462-7c34fa40e91f.png)

グーグルで検索してでてくるサンプルは
ピボットテーブルの左端がA1であることが前提のため、(2022年2月)
ピボットテーブルの位置を指定できるように追加しました。

↓参考ページ
[このページのソースに位置指定を追加](https://teratail.com/questions/346440)
[ピボットテーブル作成のサンプル](https://developers.google.com/sheets/api/guides/pivot-tables#apps-script)


```:GoogleAppsScript


function MoveFunction(){
  
  const SOURCE_SHEET="データシート";                    //ピボットテーブル用データのあるシート名
  const SOURCESHEETID="〇×YXf-uabcdiP_ur45tyudU_z23445656Y0";   //ピボットのあるシートのID
  const PIVOSHEETNAME="事業部";                       //ピボットテーブルのあるシート名
  const PIVOTSHOPROW=2;         //ピボットテーブルの開始行　0から数える　A3から開始する場合の場合
  const PIVOTSHOPCOLUMN=0;      //ピボットテーブルの開始列　0から数える  A3から開始する場合
  let pivotTableParams;                              //ピボットテーブルを入れる変数
  
  //ピボットテーブルのあるスプレッドシートを取得
  let sheet = SpreadsheetApp.openById(SOURCESHEETID); 
  //ピボットテーブル用データのあるシートを取得
  let sourcesheet=sheet.getSheetByName(SOURCE_SHEET);　
 //ピボットテーブルのあるシートのシートIDを取得する
  let pivotTableSheetId = sheet.getSheetByName(PIVOSHEETNAME).getSheetId(); 

  let fields = "sheets(properties.sheetId,data.rowData.values.pivotTable)";
  let sheets = Sheets.Spreadsheets.get(sheet.getId(), {fields: fields}).sheets;
  


  //--------------シートIDでピボットテーブルを取得する
  for (var i in sheets) {
    if (sheets[i].properties.sheetId == pivotTableSheetId) {      
      pivotTableParams = sheets[i].data[0].rowData[PIVOTSHOPROW].values[PIVOTSHOPCOLUMN].pivotTable;
      break;
    }
  }  
  
//ピボットテーブル用データ範囲の最終行設定
  pivotTableParams.source.endRowIndex = sourcesheet.getLastRow();　　

  // 更新されたパラメータを送す
  var request = {
  "updateCells": {
  "rows": {
  "values": [{
  "pivotTable": pivotTableParams
  }]
  },
  "start": {
  "sheetId": pivotTableSheetId,
  "rowIndex":PIVOTSHOPROW,
  "columnIndex":PIVOTSHOPCOLUMN
  },
  "fields": "pivotTable"
  }
  };  

  Sheets.Spreadsheets.batchUpdate({'requests': [request]}, SOURCESHEETID);
}

```


##上で記述した関数を以下のページを参照してタイマーで更新してます。
[Google Apps Script で毎日決まった時刻にスクリプトを実行するトリガー設定](https://tonari-it.com/gas-trigger-set/)

##GoogleSheetsAPIを追加する必要もあります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369082/38531dc1-dcce-f9d9-1d9b-394d547b93ad.png)
Rundeck 備忘録

##Ubuntu20.04にRundeckをインストールして使用するための備忘録
https://linoxide.com/install-rundeck-on-ubuntu/

##【MySQL】##
###ログイン
```
mysql -u root -p
```
###DB作成
```
CREATE DATABASE rundeckdb;
```
###ユーザー作成
```
CREATE USER 'rundeck_user'@'localhost' IDENTIFIED BY 'hogehugaPassword';
GRANT ALL PRIVILEGES ON *.* TO 'rundeck_user'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
```

##【Rundeck】
###ダウンロード

```
curl -L https://packages.rundeck.com/pagerduty/rundeck/gpgkey | sudo apt-key add -
sudo vim /etc/apt/sources.list.d/rundeck.list
```
|項目|説明|備考|
|----|----|----|
|コマンドの有無を確認|入っていれば、ディレクトリが返ってくる|例：which curl<br>/usr/bin/curl|
|curl -L|リダイレクト|https://qiita.com/shtnkgm/items/45b4cd274fa813d29539|
|apt-key|aptがパッケージを認証するのに使用するキーの一覧を管理するコマンド|https://manpages.debian.org/unstable/apt/apt-key.8.ja.html|

###下記追加
```
deb https://packages.rundeck.com/pagerduty/rundeck/any/ any main
deb-src https://packages.rundeck.com/pagerduty/rundeck/any/ any main
```
###インストール
```
sudo apt update
sudo apt install rundeck
```

###rundeck-config.properties 設定
```/etc/rundeck/rundeck-config.properties
grails.serverURL=http://xxx.xxx.xxx.xxx:4440
dataSource.driverClassName = org.mariadb.jdbc.Driver
dataSource.url = jdbc:mysql://localhost/rundeckdb?autoReconnect=true&useSSL=false
dataSource.username = rundeck_user
dataSource.password = hogehugaPasword

```
###framework.properties 設定
```/etc/rundeck/framework.properties

framework.server.name = xxx.xxx.xxx.xxx
framework.server.hostname = xxx.xxx.xxx.xxx
framework.server.port = 4440
framework.server.url = http://xxx.xxx.xxx.xxx:4440


```

###アプリケーションの起動
```
sudo systemctl enable rundeckd.service 
sudo systemctl status rundeckd.service
sudo service rundeckd start
```

##Apache 

```/etc/apache2/apache2.conf
ProxyPass xxx.xxx.xxx.xxx:4440/ http://xxx.xxx.xxx.xxx:4440
ProxyPassReverse xxx.xxx.xxx.xxx:4440/ http://xxx.xxx.xxx.xxx:4440

```

##上手くいかない時
|症状|原因|備考|
|----|----|----|
|xxx.xxx.xxx:4440に接続できない|原因不明<br>エラーログを確認する|/var/log/appache2<br>/var/log/rundeck|
|/var/log/appache2<br>access.logを確認したところ408エラーがでている|"-" 408 511 "-" "-"|rundeckが応答しないのでタイムアウトしたと思われる|
|/var/log/rundeck<br>service.logを確認したところ<br>SQLTransientConnectionException: Could not connect to address=(host=localhost)(port=3306)<br>ERROR pool.ConnectionPool - Unable to create initial connections of pool等のエラーが出ている|DBに接続できていないと思われるのでMySQLに設定したIDとパスでログインできるか確認する||


##詳細ファイル
/home/user 20220211_rundeckDL_インストール_設定時の備忘録.txt
Ruby Hanamiでguard-rspecを使うときのGuardfileの参考例



これで良さそう

```ruby
directories(%w[apps lib config spec].select { |d| Dir.exist?(d) ? d : UI.warning("Directory #{d} does not exist") })

guard :rspec, cmd: 'bundle exec rspec -c -fd' do
  require 'guard/rspec/dsl'
  dsl = Guard::RSpec::Dsl.new(self)

  # RSpec files
  rspec = dsl.rspec
  watch(rspec.spec_helper) { rspec.spec_dir }
  watch(rspec.spec_support) { rspec.spec_dir }
  watch(rspec.spec_files)

  # Hanami files
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
  watch(%r{^apps/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
  watch(%r{^apps/(.+)/controllers/(.+)\.rb$}) { |m| "spec/requests/#{m[1]}/#{m[2]}_spec.rb" }
end
```

### 想定動作
* apps, lib 以下のファイルを変更したときに対応するspecが実行される
* specs/requestsにはAPIのE2Eテストを配置する想定、controllersに変更があった場合に対応するunitテストと一緒に実行される


### 参考
* [GitHub: guard/guard](https://github.com/guard/guard)
2022/2/8主にITとかセキュリティの記事

主要PCメーカーが採用する「InsydeH2O UEFI」に脆弱性 - 侵害されると影響大
https://www.security-next.com/133943

「Emotet」感染でなりすましメールが送信される、情報流出も - テスコム
https://www.security-next.com/133941

壁紙専門店で「Emotet」感染 - 社名やサイト装うメールが送信される
https://www.security-next.com/133939

顧客のクレカ情報流出の可能性 - 医薬品容器メーカー
https://www.security-next.com/133204

県女性センターかたる不審メール、利用者メアド流出か - 愛知県
https://www.security-next.com/133936

Opera Software、なりすましによる偽の提携話に注意喚起(2/5)
https://www.zaikei.co.jp/article/20220205/659120.html

ペネトレーションテスト英語表記: Penetration Test(2/4)
https://eset-info.canon-its.jp/malware_info/term/detail/00163.html

ウクライナ情勢とサイバー防御　ＮＴＴサイバー専門家・松原実穂子(2/4)
https://www.sankei.com/article/20220204-LDOHHPQJSNLE5KQXXESZHV6VTM/

オンラインホワイトボードに熱視線、「テレワークで意思疎通が困難」の解決法とは(2/7)
https://xtech.nikkei.com/atcl/nxt/column/18/00001/06494/