OmniAICreator/Qiita-1.07M huggingface dataset:
Elixir/PhoenixでWebGLを動かしてみる

#初めに
フリック(https://twitter.com/TewiEwi_no96) ですω
モノづくりが好きな人はフォローをよろしくお願いします！
#動機
Elixir/PhoenixでもWebGL出来ないかな～と思い至り環境を整えてみましたω
#結果
https://twitter.com/TewiEwi_no96/status/1370654579063279617
#必要知識
・Phoenixサーバーを構築する知識
↓@piacerexさんの記事がお勧めです。
https://qiita.com/piacerex/items/a7558adc6856e3577dc6
・WebGLをBuild出来る知識
https://docs.unity3d.com/ja/2018.3/Manual/webgl-building.html

#実施環境
・Unity(2019.4.14f1)
・Phoenix v1.5.6

#手順
<b>①新規にUnityのプロジェクトを作成しWebGLでBuild</b>
Unityを立ち上げたら、File->Build Settings...を押してWebGLを選択、Buildを押してください。
余談：今回は適当にボックスを配置して、WASDでカメラを移動させるだけのものをサンプルとして作成しました。
![asdf.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556177/6fbc022a-9d5c-e339-13dd-11943db0b0f4.jpeg)
<b>②Buildした結果を格納するフォルダーを作成</b>
新しいフォルダーを押して、フォルダを作成し、フォルダーの作成を押してください。
そうするとBuildされ、index.htmlファイルとBuildフォルダ、TemplateDataフォルダが生成されます。
今回使うのは、BuildフォルダとTemplateDataフォルダの二つですω
余談:今回のフォルダ名はbuildにしました。
![ag.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556177/097e63c5-09ea-5ffa-a87a-2e09f1478f33.jpeg)
![asdgh.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556177/9e1f5a29-8030-d67e-2a54-2dc1b58c3869.jpeg)
<b>③Phoenixサーバーを構築&起動</b>
構築

```
mix phx.new webgl_sample --no-ecto
…
Fetch and install dependencies? [Yn] Y
…
cd webgl_sample
```
起動

```
iex -S mix phx.server
```
確認
ブラウザで「http://localhost:4000 」にアクセスすると、Phoenixで作られたWebページが見れます。
![adf.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556177/77952b41-447f-ace1-f983-db14dd29fba4.jpeg)
<b>④UnityでBuildしたファイルをPhoenixサーバーにコピペ</b>
BuildフォルダとTemplateDataフォルダを以下のフォルダにコピペ
webgl_sample/priv/static/js
![ejty.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556177/066b78e7-577e-f978-d5a6-74f59e7884ae.jpeg)
<b>⑤htmlと紐づけ</b>
app.html.eexに下記のように追記する。

```webgl_sample/lib/webgl_sample_web/templates/layout/app.html.eex
<!DOCTYPE html>
<html lang="en">
  <head>
    ...

    <link rel="shortcut icon" href="<%= Routes.static_path(@conn, "/js/TemplateData/favicon.ico") %>"/>
    <link rel="stylesheet" href="<%= Routes.static_path(@conn, "/js/TemplateData/style.css") %>"/>
    <script src="<%= Routes.static_path(@conn, "/js/TemplateData/UnityProgress.js") %>"></script>
    <script src="<%= Routes.static_path(@conn, "/js/Build/UnityLoader.js") %>"></script>
    <script>
      var unityInstance = UnityLoader.instantiate("unityContainer", "/js/Build/build.json");
    </script>

  </head>
  <body>
    ...
  </body>
</html>
```
index.html.eexに下記のように記載する。


```webgl_sample/lib/webgl_sample_web/templates/page/index.html.eex
<div class="webgl-content" style="margin-top: 350px;">
  <div id="unityContainer" style="width: 960px; height: 600px"></div>
  <div class="footer">
    <div class="webgl-logo"></div>
    <div class="fullscreen" onclick="unityInstance.SetFullscreen(1)"></div>
    <div class="title">WebGL_test</div>
  </div>
</div>
```
#完成
![fa.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556177/8330d6eb-ec63-5eae-4624-a2e78740d878.jpeg)
#終わりに
後はUnityのプラグインでjavascriptが動かせるのかやElixirの恩恵をどのように受けるのか試行錯誤できればな～って思う～
見てくれてありがとうごさいましたｂ

FUNBOXで支援してもらえると記事を書く励みになりますω

https://frick.fanbox.cc
TODOリスト実装にあたって、複数のランダムな id をつける方法（nanoid）

# 挨拶
> 初めまして。yuiと申します。プログラミング初学者です。Qiitaへの投稿は今回が初めてとなります。よろしくお願いします。さて、プログラミングを勉強していて、現在挫折期に入っています。（さらっと思春期的な言い方しましたが、皆さんは挫折期をどのように乗り越えましたか？）そんな中、プログラミングを学ぶ上で主にインプットしかしていないことに気づきました。「アウトプットして学びの定着を深めたい（泣）」と思っていたところ、Qiitaへの投稿を知人に勧められました。学びを他者に共有しながら自身の学びを定着を深められるなら最高かな！と思い今に至ります。初学者だからこそ分かりやすい言葉で、噛み砕きながら説明できるように心掛けます。みんなで勉強頑張りましょう！


#実装環境
- MacOS(MacBookPro)
- VScode
- Chrom
- React
- JavaScript

#著者について
- 1990年生まれのRedy👩
- 2020年3月からプログラミング学習を始めました。
 - ドットインストール⇨Progate⇨JS特化型プログラミングスクール⇨2021年6月卒業予定
 - 現在の学習進捗 - HTML ,CSS ,JavaScript ,React ,Github
- 現職は、ノーマル会社員

#nanoid(ナノID)とは
- 重複しない id を作れるやつ
 - 例えば、TODOリストを実装するとき、リストには「・掃除をする　・洗濯をする　・料理をする」などのTODO項目ができる。
 
> PGの気持ち
ユーザーが「洗濯終わった」ら「・洗濯をする」の項目は削除（もしくは完了）ボタンで完了できるようにしたい 
> そうだ！『TODOの項目にそれぞれ id を付けた上で、「このidの項目のボタンをクリックしたら、このidの項目を削除（完了）する」というコードを書けばいいんだな（💡）』

そこで1とか2とか3とかの単純な数字のidを付してもいいのですが、たまたま「洗濯をする」にも「料理をする」にも同じ数字のidが付されてしまったら、ユーザーは洗濯しか完了していないのに、同時に同じidを付された「料理をする」も削除（完了）となってしまいます。⇦TODOリストとして致命傷😨

ここでスーパーマンのごとく登場するのが　**nanoid(ナノID)** !

nanoidを使うと、ランダムな20文字くらいの文字列（英数字が混ざったもの）を勝手に作ってくれます。
 

#nanoidインストール方法
https://www.npmjs.com/package/nanoid

####上記のリンクからインストールできます。インストールには下記の赤枠をクリックコピーして、ターミナルへ貼り付ける

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1183440/c405ed43-5477-7278-0b80-b6e2277d879d.png)

### ターミナルへ貼り付けたら、Enterを押せば完了です。簡単簡単♪
#### ちゃんとインストール出来たかどうかは、VScodeの「package.json」の中に
```package.json
"nanoid": "^3.1.21",
```
という記載があればOKです。

#参考文献
- naoid  https://www.npmjs.com/package/nanoid

- ランダム文字烈を作成したい時に便利なjsライブラリ「nanoid」　https://co.bsnws.net/article/242
Excel　プログラム作成例　Data操作系

```
Option Explicit

'######################################################
'必要カラム抽出
'required_column(対象シート As Worksheet, 出力シート As Worksheet, 最終行 As Long, カラム番号リスト As Variant, 必要カラム数 As Long)
'＜入力例＞
'必要カラム数
'col_count = 3
'カラム番号リスト
'col_list = Array(1, 3, 4)
'######################################################
Sub required_column(target_ws As Worksheet, out_ws As Worksheet, maxrow As Long, col_list As Variant, col_count As Long)

Dim v As Variant
Dim i As Long, j As Long

j = 0
For i = 1 To col_count
    v = target_ws.Range(target_ws.Cells(1, col_list(j)), target_ws.Cells(maxrow, col_list(j)))
    out_ws.Range(out_ws.Cells(1, i), out_ws.Cells(maxrow, i)) = v
    j = j + 1
Next i

End Sub




'######################################################
''指定範囲配列化
'range_to_ary(シート As Worksheet, _
        開始行 As Long, 開始カラム As Long, _
        最終行 As Long, 終了カラム As Long) As Variant
'戻り値：Variant
'######################################################
Function range_to_ary(ws As Worksheet, _
        start_row As Long, start_col As Long, _
        end_row As Long, end_col As Long) As Variant

    With ws
        range_to_ary = .Range(.Cells(start_row, start_col), .Cells(end_row, end_col))
    End With
End Function

```
Raspberry Pi 4 用に Docker Compose をビルドする

Raspberry Pi 4 で動かしている Ubuntu Server 20.04.2 LTS の apt でインストールできる Docker Compose はバージョンが古いので、Raspberry Pi 4 用にビルドすることにしました。

## 前提

Docker がインストールされていること。

## Raspberry Pi 4 上で以下の手順を実行する

1. Docker Compose のプロジェクトをクローンする。

    ```bash
    $ git clone https://github.com/docker/compose.git
    ```

1. ビルドしたいリリースのタグに切り替える。

    ```bash
    $ cd compose
    $ git checkout 1.28.5
    ```

1. BuildKit を有効にして、`make` コマンドを実行する。

    ```bash
    $ DOCKER_BUILDKIT=1 make
    ```

1. 10分程度待ちます。ビルドが終わると次のようなエラーメッセージが表示されますが問題ありません。

    ```bash
    + mv dist/docker-compose-linux-amd64 dist/docker-compose-Linux-aarch64
    mv: 'dist/docker-compose-linux-amd64' を stat できません: そのようなファイルやディレクトリはありません
    ```
エラーメッセージが気になる場合は、`script/build/linux` を修正してください。

1. 実行ファイルのバージョンを確認する。

    ```bash
    $ ./dist/docker-compose-linux-arm64 --version
    docker-compose version 1.28.5, build c4eb3a1f
    ```

1. 実行ファイルをパスの通ったディレクトリーにコピー（もしくは移動）する。

    ```bash
    $ sudo mv ./dist/docker-compose-linux-arm64 /usr/bin/docker-compose
    ```

Docker Compose のビルドは Docker を使うように設定されているため、とても簡単にビルドすることができました。

以上です。
ヒアドキュメントについて

　テストの意味を兼ねての投稿です。

　私はPHPの超初心者なのですが、ヒアドキュメントで躓いてしまいました。
忘備録として、私の誤りを公開します(後悔しなければいいのですが…)。

ダメな例

```
<?php

$Sentence = <<<EOF
    First,
    Second,
    Third    
    EOF;   //この行がダメ、終端IDにはセミコロン以外の文字列が含まれてはいけない。この例だとタブが含まれている。

?>
```

正しい例

```
<?php

$Sentence = <<<EOF
    First,
    Second,
    Third    
EOF;   //セミコロンは例外的にOK

?>
```

　これ単体だと、そこまで解決が難しいものではなかったはずですが、
練習していた時には前後に他のコードがあり、しばらくはまってしまいました。

　このようなミスをみすみすしてしまうなんて、この半生で一番反省しました。

参考にさせていただいたサイト
<a href='https://www.php.net/manual/ja/language.types.string.php'>公式ドキュメント(PHPマニュアル 言語リファレンス 型)</a>
文字コード推定（UTF-8 と見なして正しいか）

こんにちは。
テキストデータの文字コードを推定するシェルスクリプトを作りました。```UTF-8``` と見なして正しいかの判定が主目的です（したがってASCIIデータも空データもUTF-8と判定します[^1]）。

基本的には ```nkf```コマンドを利用した推定ですが（```nkf --guess```）、下記の工夫を加えました。

```console
$ ./utf8.sh utf8.txt
UTF-8 (LF)
$ file utf8.txt
utf8.txt: Unicode text, UTF-8 text
```

```console
$ ./utf8.sh pure_ascii.txt
UTF-8 (LF)
$ file pure_ascii.txt
pure_ascii.txt: ASCII text
```

[^1]: 参考：「[「ASCIIをUTF-8にして」それが『できない』ことを理解してもらえなかった話](https://qiita.com/heeroo_ymsw/items/c6e15d5f9246b4e842eb)」


### 推定の正確度を上げる工夫

今回のシェルスクリプトは、推定の正確度を上げる工夫を行いました。ダミーのテキストデータ（UTF-8）を前置付加し、誤推定する確率を低減させました。

なお、```nkf --guess```をそのまま使うと、その推定ロジックは UTF-8 よりも EUC-JP を優先されやすいようです[^2]。またこれが原因となり文字コード混在と誤推定する場合もありました。

```console
$ echo © | nkf --guess
EUC-JP (LF)
$ 
$ nkf --guess utf8.txt
BINARY
$ file utf8.txt
utf8.txt: Unicode text, UTF-8 text
```

[^2]: 参考：「[_ \[Ruby\] nkf-utf8](https://matz.rubyist.net/20070103.html)」（Matzにっき）

### ソース

```utf8.sh
#!/bin/sh
DUMMY_UTF8="漢字"
code="$({ echo $DUMMY_UTF8; cat "$@"; } | nkf --guess)"
if echo "$code" | grep -q -v 'UTF\-8'; then
  code="$(cat "$@" | nkf --guess)"
fi
echo "$code"
```

```console
$ ./utf8.sh utf8.sh
UTF-8 (LF)
```
作成済みのEC2をterraform管理にする

terraform importコマンドを使用すれば、既存のリソースをterraform管理に出来るらしいので挑戦。今回はAWSのEC2でやってみます。


# 事前準備
EC2を事前に手動で作成しておきます。

そのあとに、インスタンスIDとAMI IDとインスタンスタイプを控えておきます。（terraformでEC2を管理するのに必須なステータス）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321507/edfa1034-9117-dadc-6420-f723d343dc17.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321507/e7f0c2ea-7949-e48f-75e2-c83d3a189556.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321507/24dd510a-c016-db9f-d330-8d2d563bea83.png)


# インポート前の準備

## プロバイダ情報の記載
インポートの為にプロバイダの指定が必要なので、terraformを管理する予定のディレクトリでファイルを作成しプロバイダ情報を記載。今回はAWSで、リージョンは東京を指定。


## EC2インスタンス情報の記載

リソースはEC2なので、aws_instanceを使用。
その中に事前に控えておいた`AMI ID`と`インスタンスタイプ`を記載します。

プロバイダとEC2インスタンスの情報を記載したファイルは下記のようになります。
amiとinstance_typeの箇所の記載は自身の環境に合わせて変更します。

```main.tf
# プロバイダ情報
provider "aws" {
  region = "ap-northeast-1"
}

# EC2インスタンス情報を記載
resource "aws_instance" "imported" {
  ami = "ami-0f27d081df46f326c"
  instance_type = "t2.micro"
}
```

# import実施

対象ディレクトリで`terraform init`を実施し、Terraformの準備をします。

```
# terraform init
```

インスタンスIDを指定し、importを実施。

```
terraform import aws_instance.imported i-037fec03a06ff16c7
```

# 確認
これでimportは完了です。terraform planを実施し、差分が無いことを確認出来ればOKです。

```
# terraform plan                                                                                     
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

aws_instance.imported: Refreshing state... [id=i-037fec03a06ff16c7]

------------------------------------------------------------------------

No changes. Infrastructure is up-to-date.
```

さらに管理されてるか気になるのであれば、`terraform destroy`を実施します。管理しているEC2が削除対象として出力されるはずです。

```
# terraform destroy
aws_instance.imported: Refreshing state... [id=i-037fec03a06ff16c7]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # aws_instance.imported will be destroyed
  - resource "aws_instance" "imported" {
      - ami                          = "ami-0f27d081df46f326c" -> null
<省略>
```

# 終わりに

管理外のリソースをimport出来ると知ったので、実際に試しました。
ちなみにリソースに必要な引数は事前に調べなくても、planを実施すればterraformに記載すべきステータスを教えてくれます。

例えば、amiを指定せずにplanを実施すればamiを指定するようにとエラーメッセージが出ます。

```
# terraform plan

Error: Missing required argument

  on main.tf line 5, in resource "aws_instance" "imported":
   5: resource "aws_instance" "imported" {

The argument "ami" is required, but no definition was found.
```
Django アプリ開発時に Chrome で LiveReload (ホットリロード) を使う手順

Djangoアプリの開発効率化のためにホットリロード（ライブリロード）をしたかったので、関連パッケージを調べたところ、4つの候補（ livereload, django-livereload, python-livereload, django-livereload-server ）が見つかったが、どれを使うべきか迷った。結果、 
 [livereload](https://livereload.readthedocs.io/en/latest/) を使えばできたが、パッケージを書き換える作業が別途必要だったので、そのメモを共有します。（※他の３つは試していません）


注意点：
 　- SASSでは使えないかもしれない（※未確認）
 　- 今回はChrome拡張機能も使ったが、他のパッケージを使えば、Chrome拡張機能は不要かもしれない

  
手順：
**【サーバ側】**

1. パッケージ LiveReload をインストール
``` % pipenv install --dev livereload ```

1. パッケージ内のserver.py ( パスの例： venv/lib/python3.8/site-packages/livereload/server.py ) を任意の名前(例：server2.py)に変更
							
1. livereload.py( パスの例： venv/lib/python3.8/site-packages/livereload/management/commands/livereload.py ) の 6行目のimport文を変更
　　変更前： from livereload.server import Server
　　変更後： from livereload.server2 import Server ( ※ファイル名をserver2.pyに変更した場合 ）( [画面例](https://gyazo.com/5f9ad84a776cc17ec7cae557e66d9470.png) )

1. settiings.py の INSTALLED_APPS に 'livereload' を追加
　（'django.contrib.staticfiles'がある場合はそれよりも手前に追加）

1. ターミナルで以下のコマンドを実行
``` % ./manage.py livereload ``` 
	（[この](https://gyazo.com/2d8bd127fb1de945e9718e4c112ca58f.png)ように表示されていれば成功）
							

1. デバッグ実行開始　


**【クライアント側】**
1. [Chrome拡張機能 「LiveReload」](https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei) をインストール
2. ホットリロードしたい対象のページをChromeで開き、LiveReload拡張機能のアイコンをクリック（これでこのページでのホットリロードが有効になる）  



以上の操作で、ソースコードを修正して保存すると自動でブラウザ側がリロードされるようになります。

（参考）[ホットリロードされる例](https://gyazo.com/660c1e467fc37c7fc7e43fddabc78c0b.mp4)

ちなみに、ホットリロードを有効にすると、[このように](https://i.gyazo.com/a2b6b74276fd58a64927e65640eb7858.mp4) PCとスマホレイアウトの同時確認の効率が特に上がります（この例では、「⭐」の１文字を追加して、保存しています）。
（私は実際にはメイン画面にソースコードを表示して、セカンダリモニタにPCとスマホの画面を表示しています）
ぼっち演算子　&.

#ぼっち演算子

正式名称はsafe navigation operator。

ぼっち演算子を使って、メソッドを呼び出すことで、レシーバがnilの場合でも、エラーが発生しなくなる。

```rb
$rails c

> user = nil
=> nil
> user.name
Traceback (most recent call last):
NoMethodError (undefined method `name' for nil:NilClass)
```
エラー発生。

```rb
> user&.name
=> nil
```

ぼっち演算子を使うとnilの場合、エラーではなくnilを返してくれる。
laradockでdocker-compose時のエラー

docker環境でlaradockを用いてプロジェクトを立ち上げようとした際のもの。
初めての作業にドキドキしつつ以下入力。

```:terminal
$ docker-compose up -d nginx mysql workspace phpmyadmin
```

すると下記のエラーが表示された。

```:terminal
Creating laradock_mysql_1            ... error
Creating laradock_docker-in-docker_1 ... done
Creating laradock_redis_1            ... done
Creating laradock_workspace_1        ... done
Creating laradock_php-fpm_1          ... done
Creating laradock_nginx_1            ... error
```

すぐ下に

```:terminal
ERROR: for mysql  Cannot start service mysql: Ports are not available: listen tcp 0.0.0.0:3306: bind: address already in use
ERROR: for nginx  Cannot start service nginx: Ports are not available: listen tcp 0.0.0.0:80: bind: address already in use
```

とあったため.envを

```:.env
MYSQL_PORT=3306
↓
MYSQL_PORT=3307

NGINX_HOST_HTTP_PORT=８０
↓
NGINX_HOST_HTTP_PORT=8888(８８８８で良いかは不明。。。)
```

と変更、コンテナを停止し、再度upコマンド入力。

無事

```:terminal
Creating laradock_mysql_1            ... done
Creating laradock_docker-in-docker_1 ... done
Creating laradock_redis_1            ... done
Creating laradock_workspace_1        ... done
Creating laradock_php-fpm_1          ... done
Creating laradock_nginx_1            ... done
```

となり無事起動。
エラー表示が出ても一旦しっかり確認すれば初めての技術を使ったときにも焦らず対応できるいい教訓を得た。
QMLでのWindows通知トースト表示について

# QMLのSystemTrayIcon.showMessageを使った際の表示内容について
QMLのSystemTrayIcon.showMessageを使用すると、Wundowsの通知トーストを表示できます。

```QML
Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    Button {
        text: qsTr("Test")
        onClicked: {
            systemTrayIcon.showMessage(qsTr("Title"), qsTr("Message"))
        }
    }

    SystemTrayIcon {
        id: systemTrayIcon
        visible: true
        icon.source: "qrc:/icon.png"
    }
}
```
こんな感じのQMLを実行すると
![toast.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201067/71367f59-1fe8-46a4-6a2d-212c806f2c16.png)
こんなトーストが表示されます。
***
見た通り、一番下に実行ファイル名(～.exe)が表示されます。
ここを任意の文字列に変えたい場合、.proファイルに、VERSIONとQMAKE_TARGET_DESCRIPTIONを追加します。

```
...
VERSION=1.0.0.0
win32:QMAKE_TARGET_DESCRIPTION = "test test test"
...
```
すると
![toast2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201067/b208145e-1a93-3415-787e-bddba03d19b5.png)
こんな風に変更することができます。
***
ここに日本語を表示したい場合、そのまま日本語を書くと
![toast3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201067/77627fbb-6224-2342-2dd2-cec7b9ee8f51.png)
こんな感じに見事に文字化けします。
が、.proファイルをShift-JISで保存すれば日本語が正常に表示されました。
![toast4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201067/c2cb984b-f5dc-86b4-9969-2e5756c79b6f.png)

***

ということで、トーストの一番下に「～.exe」が表示されちゃってかっこ悪い問題が解消しました。(^^;)
| | =　とは

##||=　を見かけたので調べてみた。

=だけならいつも通りのはずが、前に||がついていたので違いをメモ。

nilガードというらしい。

```rb

@current_user = User.find(session[:user_id])
```

上記だと、@current_userにUser.find(session[:user_id])を代入することになる。

```rb

@current_user ||= User.find(session[:user_id])
```
一方||=だと、@current_userがnilまたはfalseの場合の時のみUser.find(session[:user_id])が代入される。

つまり、||=の場合は正しい値が入っていれば、代入されない。
フォルダを違う階層に移動したい！


#初めてなので簡単に自己紹介
初めてQiitaに投稿します。ながたけいと言います。

主に週末、Reactを中心にプログラミングの勉強に励んでいます（Macユーザーです）。多くの記事を参考にさせてもらって、「Qittaに投稿する人まじで神！」と日頃みなさんから多大なる知識という恩恵をいただいております。

そんな駆け出しな僕ですが、今回ビギナーあるあるの一つと言ってもいい罠にかかりました。


#フォルダの階層間違えた
cd ..コマンドをし忘れ、作るべき階層ではないところにフォルダを作ってしまい（しかもなかなか気づかない…）、あぁなんかリモートリポジトリ変だと思ったら、

###**フォルダの階層間違えてるやないかい！**

とはいえ、まぁフォルダを一つ上にあげことくらい…、あれ？フォルダの階層どうあげるんだっけ？mvコマンド？と右往左往してしまいました。

いつも通りQiitaさんで探しても、なかなかそれっぽい記事が見つからず（泣）

とりあえずmvコマンドを実行！



名前だけが変わる！



うん、逆に冷静になる！
冷静になって考えたら簡単に解決できる糸口を見つけました笑


#フォルダを違う階層に移動する
移動させたいフォルダをコピーする。

コピーの仕方はcpコマンド使っても、UI画面で直接コピーしても良いと思います（僕はUI画面からコピーしました）。
そして移動させたい階層でペーストする！


###**以上**



そして最後に間違った階層に存在する対象のフォルダを削除して、一件落着です。

冷静になったからこその結果でしたが、やはりすぐにQiitaに頼るのではなく、自分で考える癖をつけることも重要ですね。


その辺の切り分けも今後ちゃんとしていきますか！


ということで、僕と同じような罠に引っかかって困ってる方はぜひ参考にしてみてください！



追記：やっぱりmvコマンドでもいけるらしいですね
【SQL Server】変数を使ってwhile文みたいなループを書く

変数をインクリメントしながら、ループでDB更新したいなあ
と思って調べたので残しておく

##ループの書き方##
```sql
--変数を宣言
DECLARE @index INTEGER

--変数を初期化する
SET @index = 1

WHILE @index <= 10
BEGIN
    --ループしたいクエリを書く

	  SET @index = @index + 1
END

```
こんな感じで書くと変数indexが1~10まで増えて、10回ループできる。

##update文のwhere条件をループで変える##
whereで指定する主キー(primary_key)の値をインクリメントさせてみる

```sql
--変数を宣言
DECLARE @id INTEGER

--変数を初期化する
SET @id = 100

WHILE @id <= 200
BEGIN
    update sales
	set 
	    column_name = 'テスト' 
	where id = @id 

	  SET @id = @id + 1
END

```

これでsalesテーブルのid列が100~200までのレコードを更新できます。

ただし、同じ値で更新するのにループさせるのは無駄の極みなのでご注意を(´·ω·`)


下のように書けば1回のupdateで更新できます

```sql
id BETWEEN 100 AND 200
--又は
id >= 100 AND id <= 200 
```

ループさせるのは各レコードの値も変えたい場合にしましょう

##使い道##
私はテストデータの作成をする際に使用しました。

CONVERT関数で変数idをvarcharに変換して
各レコードupadeteしています。

```sql
--変数を宣言
DECLARE @id INTEGER

--変数を初期化する
SET @id = 31

WHILE @id <= 40
BEGIN
    update sales
	set 
	    column_name = ('テスト' + CONVERT(varchar, @id))
	  , status = '1'
	  , updt = getdate()
	where id = @id 

	  SET @id = @id + 1
END

```

##参考##
こちらを参考にさせていただきました。
https://www.curict.com/item/bb/bb80194.html
ページとサイトの認識について

#はじめに
###今回は、学習をしていてページとサイトの認識が曖昧でしたので簡単な記事を書きたいと思います。



##web page 
ブラウザに表示される1枚のページ
伝えたい情報を1枚のページにまとめて、インターネット上で公開している文書のことを「webページ」という。

##Website
1つのドメインの中にあるページの集まり。
web pageの集合体。
　　　　↓
例）　
`1.トップページ`
`2.メニューページ`
`3.イベントページ`
`4.お店紹介ページ`
`5.お問い合わせページ`
がまとまったもの。

##home page
各ウェブサイトのトップページ。
1番最初のページ。
website ＝ homepage

##landing page 
ユーザーが最初にアクセスしたページ。
ユーザーが検索や広告経由に　最初に着地したページ。
業務で得た、RubyだったりRailsで使えるスクリプト達


## 記事を書いた背景
業務としてはエンドユーザーからやってくる、お問い合わせを元に、修正・仕様確認・緊急対応etcを行なっています。
エンジニアになった時は、開発こそエンジニアだと思っていたが、実際のところは日々起こる、小さな修正だったり、どデカイ緊急対応だったりをどれだけシンプルなロジックで早く対応できるかがエンジニアの本領発揮ポイントかなと思っています。

まぁ、なんやかんや書きましたが過去の僕みたいな人の助けになったら幸いです笑

## スクリプトたち
#### 1.更新の際、しっかりrescue

サービスを大きくするには開発が必要で、開発すると何かしらバグるのは必然。(バグらない努力は当然行うべきだが、これは運命)
そしてバグると意図しないデータが色々とできてしまう。

意図しないデータを意図する形に更新する時のスクリプトが結構怖いもので、
ここをミスると2次被害になりバタンキュー。

更新が途中で失敗すると結構詰むので、以下のように更新がうまくいかない世界線も予期してしっかりrescueしてあげよう。

```ruby
# 内容
# 今回は顧客のデータ(User.rb)が訳あってバグってしまって、正しい値に更新する時のスクリプト

# 不具合顧客のidがわかっている場合、target_user_idsに配列として定義
target_user_ids = [1,2,10,20,21,22,...]
# update_failure_listsは更新失敗したUserのidとその時のエラーメッセージを格納する空配列
update_failure_lists = []

def updates_data user, update_failure_lists
  ActiveRecord::Base.transaction do
    # ここに正しく更新したい内容記述
    # ex 
    # user.update!(name: 正社員石川)
  end
rescue => e
  error_message = "Reason::" + e.message
  update_failure_lists << [user.id, error_message]
end


User.where(id: target_user_ids).each do |user|
  updates_data user, update_failure_lists
end
```

このスクリプトの好きなところは以下の箇所で、
更新が失敗しても`ActiveRecord::Base`してるのでRollBackしてrescueに入り、
rescueに入った後も、どうして更新がミスったのかがわかるのが結構便利です。

```ruby

rescue => e
  error_message = "Reason::" + e.message
  update_failure_lists << [user.id, error_message]
end

```

#### 2.不具合時刻から対象を洗い出す
不具合時刻から誤ったデータを探す際に以下のスクリプトをよく使う。

```ruby
# 内容
# 2021年3月1日24:00から2021年3月1日06:00の間で不具合があり、その時間帯の顧客データを洗い出すスクリプト
# +0900とかは自分のサービス毎に確認してね

from_time = "2021-03-01T-00:00:00 +0900".to_datetime
to_time = "2021-03-01T-06:00:00 +0900".to_datetime
User.where(created_at: from_time..to_time)
```

正直この程度のことはruby・rails初学者向けの本に書いてありそうだが、
緊急の場合は、頭が真っ白になったり、自分の開発が生んだバグだったりすると、手が止まってしまうことがある。

なので一旦コードの意味を理解したらどこかにテンプレを作成して未来に備えて保存することをオススメします。

#### 3.たまに出てこなくなる曖昧検索

ruby,rails学びたての頃、部分一致の検索方法がよくわからず、毎回調べていたので多分みんな同じ悩みを抱えると思い記述。
SQLではどうやって書いてるのかも調べると繋がりがわかって理解が深まると思います。
コンソール叩いて走るSQL見るでもいいかも

```ruby
モデル.where("{カラム} LIKE ?", "{%調べたい言葉%}")
# ex
# User.where("name LIKE ?", "%ニート%")
# → user(name: ニート石川)がヒット
# 実際は「ニート%」でいける

```

## まとめ
パッと思い浮かぶスクリプトを3つ記載いたしました。
後半2つはスクリプトと言えるのか微妙ですが結構ど忘れしちゃうポイントかなと思いこれもまた一局。
他にも、間違えて更新した場合の対応スクリプトだったり、テーブルが4,5以上紐づいてるデータを洗い出するeach・mapスクリプトとかあるのですが需要があったらまたいつか書きます笑

なんやかんや誰かの役にたったら嬉しいなぁ
shutilを使ってpythonでzip圧縮

#zip圧縮
```python
import shutil

# DIR_NAME: zip圧縮するディレクトリのパス
# ROOT_NAME: 解凍後のルートディレクトリ名
shutil.make_archive(DIR_NAME, 'zip', ROOT_NAME)
```
#おまけ: 解凍
```python
import zipfile

#ZIP_FILE_PATH: 回答するzipファイルのパス
#UNZIP_PATH: 解凍先ディレクトリ
with zipfile.ZipFile(ZIP_FILE_PATH) as zf:
    zf.extractall(UNZIP_PATH)
```

###詳細は以下 🥳
https://docs.python.org/ja/3/library/shutil.html
擬似要素を使って文字入りの簡単な装飾を作る方法

##たとえば見出しとかで、以下のような装飾を付けたくなったとき
![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167539/708923af-5a1c-477f-be07-2e73097b3e63.png)
HTMLでspanタグなどを用いて作るのも一つの方法ですが、
擬似要素を用いることで余計なタグを書かずにスマートなマークアップをすることができます。

##装飾を付けたいタグに擬似要素を追加する
```html:sample.html
<h2>サンプルサンプルサンプル</h2>
```
上記タグに最初の画像のような、装飾を付けたい場合、

```css:sample.css
html{
  font-size: 10px;
}
h2{
  font-size: 2rem;
}
//ここから下が擬似要素の記述
h2::before{
  content: "Q1";
  display: inline-block;
  font-size: 2rem;
  color: #fff;
  text-align: center;
  line-height: 60px;
  background: #cc4242;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  margin-right: 12px;
}
```
スタイルシートに上記の擬似要素を適用してあげればOK！

一応、表示結果は下記のようになる↓
![sample02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167539/1717b6b3-c4f5-91ec-e73c-f7ea780fb6c4.png)

##今回の擬似要素の簡単な解説及びまとめ
取り敢えず、今回の設定で重要なところを抜粋すると（○○○の部分は任意の文字数字）

* `content: "○○○";`　→ここで、擬似要素内で表示する文字を設定する。
* `display: inline-block;`　→擬似要素を横並びにするのに必要な設定。
* `text-align: center;` `line-height: ○○○px;`　→この2つが無いと文字が表示領域内で上下左右中央に来ない。**line-heightは表示領域の高さと同じ値を入れてあげる。**
* `border-radius: 50%;`　→今回は丸型でしたが、この記述無くすと四角にもなる。

擬似要素を使えると、記述の幅が広がるので覚えておいて損はしないと思います。
皆さんも、擬似要素を積極的に使っていきましょう！
画像のチャネルごとの輝度値の出し方（OpenCV）

画像を分析する際にチャネルごとに情報を抽出する方法

```
import cv2

img = cv2.imread('sample.jpg')

# 画像をチャネルごとに分割
blue, green, red = cv2.split(img)

# 平均値を取得
green.mean()

# 表示する
blue = np.zeros([img.shape[0], img.shape[1]])
red = np.zeros([img.shape[0], img.shape[1]])
img = cv2.merge((blue, green, red))

```
DartでOptionalの変数をアンラップして利用する

# 目的
Optionalな変数をアンラップして利用したい。

# 環境
- Flutter `2.0.1`
- Dart `2.12.0`

# コード

`if` で `null` 判定を行い、`reutrn` で関数スコープ抜けると、
その後のコードでは、 `unwrap` されたとみなされます。

```dart
  void func(int? value) {

    if (value == null) {
      return;
    }

    print(value + 10);
  }
```

swift の guard文の逆みたいな感じですね。

ただ、Android Studio では if を入れる事で確かにコンパイルが通るようにはなるのですが、
swift の用に明示的に `Optional` でない `int` に再代入されるわけではなく、
若干、ルール縛りみたいな印象を受けるので、
個人的には swift の guard文 の方が明瞭で好きです。

# 参考にしたサイト
**Swift Optional vs Dart sound null safety _ I should go to sleep**
https://ishouldgotosleep.com/computer-science/swift-optional-vs-dart-sound-null-safety/
.Net 6.0.0 Preview 2 を Visual Studio Code から Docker 利用してみた

## 背景と目的

[.Net 6.0.0 Preview 2](https://github.com/dotnet/core/blob/main/release-notes/6.0/preview/6.0.0-preview.2.md) を使ってみたいが、ローカル環境を汚したくない。

Microsoft が公開している Docker イメージに .Net 6.0 Preview タグがついているものがあったので、これを Visual Studio Code から利用する。

## 前提条件

実施環境は、Mac + Visual Studio Code + Docker Desktop です。

```zsh:zsh
% sw_vers
ProductName:    macOS
ProductVersion: 11.2.3
BuildVersion:   20D91

% code --version
1.54.2
fd6f3bce6709b121a895d042d343d71f317d74e7
arm64

% docker --version
Docker version 20.10.3, build 48d30b5
```

## 実施内容

[vscode-dev-containers](https://github.com/microsoft/vscode-dev-containers) を参考に必要なファイルをダウンロードする。

```zsh:zsh
% mkdir -p dotnet6/.devcontainer/library-scripts
% cd dotnet6 
% curl -s https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/containers/dotnet/.devcontainer/base.Dockerfile \
  -o .devcontainer/Dockerfile
% curl -s https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/containers/dotnet/.devcontainer/devcontainer.json \
  -o .devcontainer/devcontainer.json
% curl -s https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/containers/dotnet/.devcontainer/library-scripts/common-debian.sh \
  -o .devcontainer/library-scripts/common-debian.sh
% curl -s https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/containers/dotnet/.devcontainer/library-scripts/node-debian.sh \
  -o .devcontainer/library-scripts/node-debian.sh
% curl -s https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/containers/dotnet/.devcontainer/library-scripts/azcli-debian.sh \
  -o .devcontainer/library-scripts/azcli-debian.sh
```

Docker イメージのバージョンを「 6.0 」に変更する。

```zsh:zsh
% sed -ie 's/"VARIANT": "5.0"/"VARIANT": "6.0"/g' \
  .devcontainer/devcontainer.json
```

Visual Studio Code の `command + shift + p` で「 Remote-Containers: Open Folder in Container... 」から、先ほど作成した dotnet6 フォルダを選択すると Docker イメージの作成が始まる。

## 実施結果

Docker イメージが自動的に起動されたら、Visual Studio Code のターミナルを開いて `dotnet --info` を実行し、「 .Net 6.0.0 Preview 2 」環境を確認する。

```bash:bash
vscode ➜ /workspaces/dotnet6 $ dotnet --info
.NET SDK (reflecting any global.json):
 Version:   6.0.100-preview.2.21155.3
 Commit:    1a9103db2d

Runtime Environment:
 OS Name:     ubuntu
 OS Version:  20.04
 OS Platform: Linux
 RID:         ubuntu.20.04-arm64
 Base Path:   /usr/share/dotnet/sdk/6.0.100-preview.2.21155.3/

Host (useful for support):
  Version: 6.0.0-preview.2.21154.6
  Commit:  3eaf1f316b

.NET SDKs installed:
  6.0.100-preview.2.21155.3 [/usr/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.0-preview.2.21154.6 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 6.0.0-preview.2.21154.6 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

To install additional .NET runtimes or SDKs:
  https://aka.ms/dotnet-download
```

## 参考

[Official images for the .NET SDK](https://hub.docker.com/_/microsoft-dotnet-sdk/)
PHPについて調べてみた

今後、時間があれば習いたい言語**PHP**について調べてみました。
フレームワークである**Laravel**をいつかは会得したいと目論んでいます。

　　
#PHPとは
PHPは**動的なコンテンツの作成に向いている**プログラミング言語で
スクリプト言語の一つでHTMLと組み合わせて使用できることが可能。
`スクリプト言語`とは多数あるプログラミング言語の中でも比較的容易に扱う事のできる言語を指す。
`WordPress`もPHPを用いた有名なアプリで、WordPressで作成されたWebページにユーザーがアクセスする度に**PHPがHTMLを生成**して表示している。
拡張子は.php(index.php)

#PHPのフレームワーク
###Laravel(ララベル)
Laravelの特徴は簡単なアプリケーションを自動生成できる。(**基本的なコード自動生成機能**)
習得まで時間があまりかからず、世界で１番人気のフレームワーク。
PHP向けフルスタックWebアプリケーションフレームワーク。

　　

###Cake PHP(ケイクPHP)
Cake PHPはPHP開発者が誰でも素早く快適に開発できるようにと生み出されたフレームワーク。
Laravelより動作が若干高速。
ドキュメントも日本語が多い。
　　

###Phalcon(ファルコン)
FhalconはC言語の拡張として書かれたPHP用のオープンソースフルスタックフレームワーク。
C言語の拡張なので**非常に高速**で動作する
処理速度ならPhalconがオススメ。(**次期バージョンで変わる可能性ありなので一違いには言えない**)

　　

###公式ドキュメント(一部抜粋)

Zephir-PHP 8
PHP 8に関しては、Zephirでいくつかの良い動きがありました。Alexanderは、Zephir PHP8との互換性を高めるためのイニシアチブを推進してきました。目標は、PHP8で動作するv4バージョンをリリースすることです。
この取り組みはまだ始まったばかりですが、うまくいくと楽観視しています。

現在、コードをZephirからPHPに変換しています。 v5がリリースされたら、コードに最適化を実装する作業を開始できるため、PHP側でフレームワークを可能な限り高速に取得できます。

Phalconを使用することで慣れていたパフォーマンスの一部が失われますが、PHP 7と（うまくいけば）PHP 8は、PHP5.xとPhalconを使用したときに見られたパフォーマンスのギャップを埋めることができました。

私たちの主な焦点は、常にフレームワークを可能な限り高速に保つことです。 PHPに切り替えることで、コミュニティはプロジェクトにより積極的に関与できるようになり、アドオンやインキュベーターなどの支援もできるようになりました。

すべての人に感謝し、v5が私たちに提示する新しい課題を楽しみにしています。　



##まとめ
新しい情報もドキュメント等見れば載っていることを知リました。(情報提供ありがとうございます！)
調べればキリがないので基本的な情報だけ調べてみました。
PHPにはその他フレームワークが存在し、臨機応変に使いわけしているみたいです。
自分は説明読むより実際に触ってどう動くのかを体感した方があっているので、
時間があればLaravelの学習をしていきたいと思います。
Amazon SP-API用Laravel8環境を作成してみた（まだ途中）

# 1.まずは爆速で、Laravel環境をローカルに作成する
https://qiita.com/ucan-lab/items/56c9dc3cf2e6762672f4

# 2.ローカル環境のphpをphp8にする
https://qiita.com/captainUmaru/items/a85321927fc4215d83a6

※補足で、Dockerfileのfpm-busterも`7.4`→`8.0`変更をしてください。

```
# Before
FROM php:7.4-fpm-buster
↓
# After
FROM php:8.0-fpm-buster
```
変更が終わったら、再ビルドしましょう↓

```
% docker-compose up -d --build
```

composer install とか update でこんなうざいのが出たら...↓

https://qiita.com/captainUmaru/items/52655f3337003836cf61

# 3.Amazon SP-APIのComposerをインストール

```
% composer require clousale/amazon-sp-api-php
```
バージョンの互換性に関する詳細は下記より確認してください

https://packagist.org/packages/clousale/amazon-sp-api-php
Is Subsequence 〜leetcode〜

#〜問題文〜
```
Given two strings s and t, check if s is a subsequence of t.

A subsequence of a string is a new string that is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (i.e., "ace" is a subsequence of "abcde" while "aec" is not).

 

Example 1:

Input: s = "abc", t = "ahbgdc"
Output: true
Example 2:

Input: s = "axc", t = "ahbgdc"
Output: false
 

Constraints:

0 <= s.length <= 100
0 <= t.length <= 104
s and t consist only of lowercase English letters.
 

Follow up: If there are lots of incoming s, say s1, s2, ..., sk where k >= 109, and you want to check one by one to see if t has its subsequence. In this scenario, how would you change your code?
```

引用元：　https://leetcode.com/problems/is-subsequence/
　　
ざっくりと翻訳すると、
「文字列sは、文字列tに順番を変えずに存在していますか？」
です。

## 他の人の回答例（正解ではない）

他の人の回答の「分析」と「改善案」と「気づき」。

```ruby:ruby
def is_subsequence(s, t)
  return true if s.empty? && t.empty?
  s_idx = 0
  t_idx = 0
  s_len = s.length
  t_len = t.length
    
  while(t_idx < t_len)
    s_idx += 1 if s[s_idx] == t[t_idx]
    return true if s_idx == s_len
    t_idx += 1
  end
  false
end
```  




#　以下、上記回答の分解分析


## 1. メソッドの定義


```ruby:ruby

def is_subsequence(s, t)
         
         〜省略〜

end
```

 
「is_subsequence」というメソッドを定義。
<b>第一仮引数</b>＝「s」、<b>第二仮引数</b>＝「t」と定義する。


## 2. メソッドの処理

```ruby:ruby

  return true if s.empty? && t.empty?
  
```

初っ端に

<b>「もし、sとtが空であったら本ステップで処理終了」</b>

という開幕直後の唐突処理😳

参考：https://docs.ruby-lang.org/ja/latest/method/String/i/empty=3f.html

```ruby:ruby

    
  s_idx = 0
  t_idx = 0

   
```
「s_idx」  と 「t_idx」 に対して「0」を代入する。
idxということで、s、ｔの文字を後に配列の<b>よう</b>に扱う際に、添字とするという思想があるのだろう（配列にはしていない）。
以後<b>while文内</b>で使用。


```ruby:ruby

  s_len = s.length
  t_len = t.length
```

「s_len」 に対し 「s.length」、 「t_len」 に対し 「t.length」を代入する。
これによって「s」、「t」の <b><font color="red"> 文字数 </font></b> が共に定義される。
以後<b>while文内</b>として使用。

```ruby:ruby


   while(t_idx < t_len)

         〜省略ー

   end

```
<b>「tの添字 < tの文字数」</b>の条件のあいだは繰り返しの処理を行う。

↓以下、while文の中身（処理）

```ruby:ruby

#while文内ステップ①
    s_idx += 1 if s[s_idx] == t[t_idx]

#while文内ステップ②
    return true if s_idx == s_len

#while文内ステップ③
    t_idx += 1

```
#### ステップ①
　もし、s[sの添字] == ｔ[tの添字]が等しかったら、自己代入演算子にて「s」に対して「+1」してあげる。
（sの添字（s_idx）は、0スタートだから。）



？　？　？



<b>↑おそらくここがおかしい部分</b>😎
　sとtは現状、<b>文字列</b>のままである。
　しかし、本ステップでは、配列と同じ振る舞い方をさせようとしている（添字idxをつけている）。

改善案として、while文の外で配列にする。
（例）s="abcd"　→　s = [a,b,c,d]




#### ステップ②　
　sの添字とsの文字数が等しければここで処理を返す。



#### ステップ③　
　②で処理が返らなければ、更にもう一度①から処理を繰り返す。

```ruby:ruby

  false
```


もし、①、②、③の全てのループを完走してしまったら、最後は上記「false」を処理の値として返却する。
【学習メモ】AWS　ElastiCache　キャッシュの活用

#概要
繰り返し使うデータへのアクセスはキャッシュを活用すれば、アクセスが高速化になれる。
AWSの中に、キャッシュ活用のサービスは下記の三つです。
・ElastiCache
・CloudFront
・S3

#ElastiCache
分散インメモリキャッシュサービス。
高性能と高コスパのメリット以外にも、分散インメモリキャッシュの構築と管理が簡単に実施できる。
ElastiCacheはMemcachedと交換性があり、Memcachedをベースにしたコード、APP、ツールなどを簡単にElasticCacheに移行可能。
・シンプルに利用する場合はMemcachedを利用するが、それ以外はRedisを利用する場合が多い。
同種類の分散インメモリキャッシュサービスに比べて、ElasticCacheは以下の特徴がある。

####構築簡単
AWSコンソール若くは簡単のAPIで数分間内で構築可能。
キャッシュソフトウェアのインストールやメンテなどを考慮しなくて良い。

####管理簡単（フルマネージド型）
reference：
https://aws.amazon.com/jp/elasticache/?nc=sn&loc=1
パッチ管理、エラー検査、バックアップといった管理タスクが不要。

####Memcachedと交換性あり
ElastiCacheはMemcachedと交換性があり、Memcachedをベースにしたコード、APP、ツールなどを簡単にElasticCacheに移行可能。

####スケーラブル
AWSのコンソールやAPIにより、アプリのニーズに応じて、キャッシュノードの増減を実施可能。

####高信頼性
キャッシュノードが失敗した場合、障害復旧を自動的に行う。

####高セキュリティー
####他のAWSサービスと組み合わせて使用可能
例えば：EC2がElastiCacheに速やかにアクセス。

####低コスト
長期契約なしに、ノードを実行する時間単位で、メモリ容量に対してお支払う。

##Memocached
・一つのクラスターは20個のノードをサポート可能。
・Auto Discoveryを通じて、Memcachedの中で使えるノードを自動的に検索し、最も適切なノードを選べる。
・key-value型のストレージ、複雑なデータ型に不適用。

##Redis
・一つのクラスターは一つのノードをサポートするが、一つのキャッシュノードに対して最大五つのリードレプリカを作成可能。それをredis replication groupに置けば、多種類のデータ型に適用。
（例えば,List,Mapなど）
・publish-subscribe機能。
・データを永続化できる。
・データ統計、ランクなどの機能がある。


#適用のデータ種類
■よくアクセスの静的データ：
　・Webページ
　・製品リスト
など

■一時的なデータ：
　・ショッピングカード
など

■複雑なSQL検索結果：
　・ビックデータの統計結果
　・ランキング情報
など

#不適用のデータ種類
■アクセス頻度が低いデータ：
　・キャッシュカード（CashCard）の残高
　・あるユーザーの通話履歴
　など・・・・

■よく変化のデータ：
　・ウェブの訪問数
　・ある商品の総オーダー数
　など・・・・
PHP例外処理

PHPで例外処理を行う方法を記載します。
#例外処理とは
意図しないエラー（例外）が発生したときに備えて、自分なりの処理を設定したり、メッセージを表示させたりと何かしらの対策をしておくことです。

#実際の例外処理の書き方

````
<?php

try {

//例外が発生する可能性があるコード

throw new 例外クラス名(引数)

}catch(例外クラス名 例外を代入する変数名){

//例外が発生した場合に行う処理

}

//エラーが発生しなければ続く通常の処理
````

throw new 例外クラス名(引数)でインスタンスを生成している。
例外クラス名とは
phpには元々定義済みの例外クラスがいくつかあります。
catch(例外クラス名 例外を代入する変数名)でインスタンスを変数に代入しています。

#実際に行なった例外処理
````
try {
    $pdo = new PDO($dsn, $username);
  } catch (PDOException $e) {
    var_dump($e->getMessage());
  }

````
【JavaScript】テンプレートリテラルの使い方

## 記事の目的
テンプレートリテラル(テンプレート文字列とも言います)の使い方を紹介します。 
テンプレートリテラルは、シングルクォート( *'* )やダブルクォート( *"* )の代わりに、**バッククォート( ` )**を用います

## 改行の記述が楽になる
テンプレートリテラルを使わなかった場合、改行を使用するとこのようになります。

```js
console.log(
  "こんにちは\nお元気ですか？\nよろしくお願いします。"
)
```

```shell
こんにちは
お元気ですか？
よろしくお願いします。
```

テンプレートリテラルを使った場合

```js
console.log(
`こんにちは
お元気ですか？
よろしくお願いします。`
)
```
```shell
こんにちは
お元気ですか？
よろしくお願いします。
```

書き方はテンプレートリテラルを使ったほうが直感的に分かりやすいですね。


## 変数と文字列の連結が楽になる。

テンプレートリテラルを使わなかった場合

```js
const num = 2
console.log("私はりんごを" + num + "つ食べたい。") // 私はりんごを2つ食べたい
```

テンプレートリテラルを使った場合

```js
const num = 2
console.log(`私はりんごを${num}つ食べたい。`) // 私はりんごを2つ食べたい
```

こちらもテンプレートリテラルを使ったほうが書き方がシンプルですね。

## まとめ
以上がテンプレートリテラルの使い方でした！
JavaScriptでの配列に格納されているオブジェクトの操作方法

# 初めに

* 参考にしたサイトは[こちら](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array)
* 各メソッドの型は参考サイトに記載があるのでこの記事ではコードを用いて各メソッドの説明を行います。

# 記事にする機能

* map
* filter
* reduce


# map

mapは与えられた関数を配列のすべての要素に対して呼び出しを行います。

* newArrayにはarrayが持っている値が一つづつ格納されます。indexには受け取った値が元の配列の何番目物なのか数値で格納されます。

```
function App() {
  const array = [{ name: 'Bob', age: 10 }, { name: 'Tom', age: 11 }, { name: 'Sum', age: 12 }];
  return (
    <>
      {array.map((newArray, index) => {
        return (
          <div key={index}>
            <h1>{index}:{newArray.name}は{newArray.age}です</h1>
          </div>
        )
      })}
    </>
  );
}
```
実行結果はは下記のようになります。

```
0:Bobは10です
1:Tomは11です
2:Sumは12です
```

#filter
filterは指定した値だけ配列から取り出します。

* 一つ目はarrayからfilterメソッドを使用しarrayの1番目の値を取り出しfirstArrayに格納しています。

* 二つ目はarrayからfilterメソッドを使用しarrayの1番目以外の値を取り出secondArrayに格納しています。

```
const array = [{ name: 'Bob', age: 10 }, { name: 'Tom', age: 11 }, { name: 'Sum', age: 12 }];
const firstArray=array.filter(value => value === array[0])
const secondArray=array.filter(value => value !== array[0])

console.log(firstArray)
//[{name:'Bob' ,age:10 }]
console.log(secondArray)
//[{name:'Tom' ,age:11 },{name:'Sum' ,age:12 }]
```
# reduce

>reduce() メソッドは、配列の各要素に対して (引数で与えられた) reducer 関数を実行して、単一の出力値を生成します。

説明が難しいのでコードを用いて説明します。

* reduceは二つの引数を取り一つ目はコールバック関数で二つ目は初期値の値となります。
* prevには前のコールバックの戻り値が格納されます。初回だけ初期値が格納されます。（prevは任意の文字）
* currentには配列の要素が順番に格納されていきます。（currentは任意の文字）
* この処理を配列の要素の数行います。

```
const array = [{ name: 'Bob', age: 10 }, { name: 'Tom', age: 11 }, { name: 'Sum', age: 12 }];
const total = array.reduce((prev, current) => prev + current.age, 0)

//出力結果
0+10
10+11
21+13
33
```
Slog ~ SlackをBlogに

## Slogとは
Slogではslackのチャンネルをblog風にして公開することができます。
site: https://slog.page

![slack_to_slog.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990680/d0664bd5-7ea6-9524-c647-0cc090e2399b.png)

## 始め方
まずは、slackのワークスペースを用意する必要があります
​
1. 既存のslackのワークスペースを利用する
2. 新規のslackのワークスペースを作成して利用する
​
実際に使ってるみる！
1. slackを利用してログインする
2. ログインしたワークスペースにslog botをインストールする
3. 追加でimageをアクセスできる権限を与える
4. blogにしたいチャンネルにbotを招待する /invite
​
* botが招待されているチャンネルのみにしかアクセス権限がありませんので他のチャンネルに影響が出ることはありません
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990680/122b1bf2-d5e3-0bbc-6215-67cca5867ab9.png)
​
​
## 技術スタック
- typescript
- blitzjs(nextjs, prisma, zod)
- chakra-ui
- vercel
- stripe
​

いろいろな候補があったのですが、まずは素早く作れるのを採用しようとなり、フロントのnextjsが外せなかったです😀
バックエンドはチームの経験値的にelixir/golang/nodejsあたりで悩んでいたのですが、一旦fullstackで合わせるのを試してみようということでblitzjsを採用してみました。
全体的にパフォーマンスがでて満足の結果ではあったのですが、

- blitz: graphqlのdataloaderを利用する、リソースのロードの最適化ができない
- zod: 再起的な構造のvalidationがしづらい
​

などちょっと辛いところもありましたが、小さい規模なのでとくに大きく問題はなかったです
​
## 今後
ロードマップを引いていていくつか追加機能を実装しようと思っています。

- リアクションによる記事操作
- Slackコマンド
- 独自ドメインの設定
- ...
​
![Screen Shot 2021-03-13 at 16.00.13.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990680/f47ffc87-bfae-db5a-e0ba-6969f5c36c6b.jpeg)
【Heroku】Confirmation did not match Herokuのアプリ名. Aborted.」と言われた時の対処法

<h2>症状</h2>
Railsチュートリアル第10章のHerokuデプロイ時に発生しました。

heroku run rails db:seedをしたところ、dbmigrateをもう一度試すように言われてしまいました。

```
#Herokuのデータベースをリセット
heroku pg:reset DATABASE

#Heroku上でdb:migrate
heroku run rails db:migrate
WARNING: Destructive action
 ▸    postgresql-hogefuga will lose all of its data
 ▸    
 ▸    To proceed, type hogepiyo or re-run this command with --confirm hogepiyo

#Heroku上のDBにseedのデータを適用
heroku run rails db:seed
try "run rails db:migrate"
```


<h2>解決法</h2>

heroku run rails db:migrateを実行したときにHerokuのアプリ名を確認として入力で解決しました。
メッセージに書いてあったので、メッセージを読め案件でした。

```
confirm hogefuga
```


<h2>参考</h2>
<a href="https://railstutorial.jp/chapters/updating_and_deleting_users?version=6.0#sec-updating_what_we_learned_in_this_chapter">Railsチュートリアル第10章</a>
ExcelVBAで、（WinAPIを使用せずに）UIAutomationで画面要素を取得＜文字を頼りに探す＞

##ExcelVBAで、（WinAPIを使用せずに）UIAutomationで画面要素を取得＜文字を頼りに探す＞

たとえば、画面の中の、ボタンなどを、文字を頼りに、
要素（UIAutomationElement）を探します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107418/077b8965-e571-93f8-43f4-f39dee4c2b80.png)

ここでは、「アクティブ時間」という文字で探してます。
結果は、イミディエイトウィンドウに出力します。
発見された要素から、順に親をたどっています。
上から下に行くにつれて、各要素から、より根側の要素へとさかのぼっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107418/003e549f-917b-6f48-0a16-e15ea32ac4c4.png)



```vb:sample.bas

'/---------------------------------------------------
'参照設定：UIAutomationClient

'/---------------------------------------------------
Sub main()
    ScWd = "アクティブ時間"
    findElmnt (ScWd)
End Sub

'/---------------------------------------------------
Sub findElmnt(ScWd)

Dim uia As New UIAutomationClient.CUIAutomation

Dim cnd As IUIAutomationCondition
Dim ret As IUIAutomationElementArray

Set cnd = uia.CreatePropertyCondition(UIA_PropertyIds.UIA_IsOffscreenPropertyId, False)

Do
    Application.Wait [Now() + "0:00:00.1"]
    DoEvents
    Set ret = uia.GetRootElement.FindAll(TreeScope_Element Or TreeScope_Children Or TreeScope_Descendants Or TreeScope_Ancestors Or TreeScope_Subtree, cnd)
Loop Until Not ret Is Nothing

'Debug.Print ret.Length

Dim tw As IUIAutomationTreeWalker
Set tw = uia.CreateTreeWalker(cnd)

Dim pe As IUIAutomationElement
For i = 0 To ret.Length - 1

    If InStr(1, ret.GetElement(i).CurrentName, ScWd) > 0 Then

        Debug.Print ""
        Debug.Print ""
        Debug.Print "1 _______________________________"
        Debug.Print ret.GetElement(i).CurrentName & "_" & ret.GetElement(i).CurrentClassName

        Set pe = tw.GetParentElement(ret.GetElement(i))
        Debug.Print "2 _______________________________"
        Debug.Print pe.CurrentName & "_" & pe.CurrentClassName
        
        Do
            Application.Wait [Now() + "0:00:00.1"]
            DoEvents
            Set pe = tw.GetParentElement(pe)
            If Not pe Is Nothing Then
                Debug.Print "3 _______________________________"
                Debug.Print pe.CurrentName & "_" & pe.CurrentClassName
            End If
        Loop Until pe Is Nothing
        
    End If

Next

End Sub

```



##参考にさせていただいたページ

神ってます

https://qiita.com/nobu-maple/items/86ba31c3b807658dcc84

https://qiita.com/kob58im/items/3587d8e595e655e9391d
【JavaScript】全集中、関数の呼吸、壱ノ型〜陸ノ型を紹介！【鬼滅の刃】

## 記事の目的
JavaScriptの関数の書き方は色々あります。
この記事ではJavaScriptの関数の様々な書き方を紹介していきます！(鬼滅の刃風に。。。)


## 関数の呼吸　壱ノ型　基本的な記述！
functionの後に関数名をを記述し、`{}`内に処理を記述しています。

```js
function hello(){
    console.log('霹靂一閃!');
};

hello(); // 霹靂一閃!
```


## 関数の呼吸　弐ノ型　変数代入！
関数名を変数のように定義し、その中に関数の処理を代入しています。

```js
const hello = function(){
    console.log('霹靂一閃!');
};

hello(); // 霹靂一閃!
```

## 関数の呼吸　参ノ型　アロー関数！
アロー関数は`=>`というキーワードを使って記述する方法です。

```js
const hello = () => {
    console.log('霹靂一閃!');
}

hello(); // 霹靂一閃!
```

## 関数の呼吸　肆ノ型　アロー関数の`{}`の省略！
**関数の処理が1行であれば**以下のように`{}`を省いてもOKです。

```js
const hello = () => console.log('霹靂一閃!');

hello(); //霹靂一閃!
```

## 関数の呼吸　伍ノ型　アロー関数の引数の`()`の省略！
引数を使った場合、引数が1つのみ(今回はtxt)であれば、`()`を省略することも可能です。

```js
const hello = txt => console.log('霹靂' + txt);

hello('一閃!'); //霹靂一閃!
```
※ 引数がない場合や、引数が2つ以上の場合は今回省いた`()`は必要です。

## 関数の呼吸　陸ノ型　即時関数！
`( 関数を定義 )(関数に渡したい引数);`のような記述です。
即時関数は今までのように`hello();`でわざわざ関数を呼びだなさくても、即時に実行されます。

```js
( hello = txt => console.log('霹靂' + txt) )('一閃!'); //霹靂一閃!
```

## まとめ
以上が、JavaScriptの関数の書き方一覧でした！
他にもこんな書き方ありますよ〜など意見ありましたらコメントいただけると助かります！
また、LGTMもいただけますと嬉しいです！(記事を書く励みになります！)
MSYS2 EXE配布用プログラム

MSYS2でコンパイルして、exeファイルは、出来たが、配布する時にDLLファイルの配布が面倒くさいので、MSYS2に付属している Pythonを使って、配布用フォルダーにDLL類を自動でコピーします。

#使い方
(1) main関数の__exePath__と__releasePath__を設定します。
(2) __Qt5__用に__setDeployQt関数__を作ったが、必要のない方は、main関数で、コメントアウトしてください。
(3) 後は、実行するだけで__MSYS2傘下__のDLLをリリース用のフォルダーにコピーします。
(4) このリリース用フォルダーを丸ごと圧縮して、配布すれば、解凍先で動くと思います。

#解説
MSYS2に付属の__LDDコマンド__を利用して、exeファイルからのリンクされたDLLを検索しています。
(1) MSYS2のフォルダーを変更している方は、getLdd関数の__msysPath__を変更してください。
(2) getLdd関数内では、__"/c/windows/"__フォルダー傘下のDLLをリストから外しています。


```pyRelease.py
# This Python file uses the following encoding: utf-8
import sys
import subprocess
import os
import shutil

def setDeployQt(exePath, releasePath):
    Deploy = "WinDeployQt.exe"
    #Deploy = "MacDeployQt.exe"

    result = subprocess.run([Deploy, "--libdir", releasePath, "--plugindir", releasePath, exePath], encoding="utf-8", stdout=subprocess.PIPE)
    print(result.stdout)

def getLdd(exePath):
    result = subprocess.run(["ldd", exePath], encoding="utf-8", stdout=subprocess.PIPE)
    resultList = result.stdout.split()

    msysPath = "c:/msys64"
    lddList = []
    for item in resultList:
        if ("/" in item):
            lowItem = item.lower()
            if ("/c/windows/" in lowItem) == False:
                fullPath = msysPath + lowItem
                if os.path.isfile(fullPath):
                    lddList.append(fullPath)

    return lddList

def uniList(ListA, ListB):
    ListC = []

    ListC = ListA
    for itemB in ListB:
        notFind = True
        for itemA in ListA:
            if itemB == itemA:
                notFind = False
                break

        if notFind:
            ListC.append(itemB)

    return ListC

def copyFileList(releasePath, lddList):
    for item in lddList:
        print("copy: ", item)
        shutil.copy2(item, releasePath)

def main():
    #setting
    exePath = "C:/work/hello/hello.exe"
    releasePath = "C:/work/hello/release"

    #create Folder
    if os.path.isdir(releasePath) == False:
        os.mkdir(releasePath)

    #copy exeFile
    shutil.copy2(exePath, releasePath)

    #Qt tool xxxDeployQt.exe
    setDeployQt(exePath, releasePath)

    #ldd command
    resultList = getLdd(exePath)

    #list deduplication
    lddList = []
    lddList = uniList([], resultList)

    #copy libFile
    copyFileList(releasePath, lddList)

if __name__ == "__main__":
    main()

```

環境設定により、完全な動作保証は、出来ていません。
crossでrosrustをビルドするときの msg のPath指定

最近RustでROSを使っていてクロスコンパイルしたいということがありました。
単純に`cross`つかってクロスコンパイルしたら`msg`のパス解決がうまくいかなくてエラーが出ました。

## どうすればうまくいったか
```shell
ROSRUST_MSG_PATH="/project/msgs" cross build --target arm-unknown-linux-musleabihf
```

## どういう経緯か

こんなディレクトリ構成です。

```plaintext
.
├── msgs
│   ├── common_msgs
│   └── std_msgs
├── src
│   └── main.rs
└── Cargo.toml
```

普通にホスト向けでビルドするときは

```shell
ROSRUST_MSG_PATH="$(pwd)/msgs" cargo build
```
とかやります。

`cross`をつかってクロスコンパイルするときには、`Cross.toml`に`ROSRUST_MSG_PATH`環境変数をビルド環境に渡すように指示を書きます。

```toml
[build.env]
passthrough = [
    "ROSRUST_MSG_PATH"
]
```

これでいけるかと思いきや、エラーが出ます。

```console
$ ROSRUST_MSG_PATH="$(pwd)/msgs" cross build --target arm-unknown-linux-musleabihf
...
   Compiling rosrust v0.9.5
error: proc macro panicked
 --> /target/arm-unknown-linux-musleabihf/debug/build/rosrust_msg-8eeb2498a88c50fd/out/messages.rs:3:9
  |
3 |         rosrust::rosmsg_include!(,IGNORE_BAD);
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = help: message: Package string needs to be in package/name format: 

error: aborting due to previous error

error: could not compile `rosrust_msg`

To learn more, run the command again with --verbose.
warning: build failed, waiting for other jobs to finish...
error: build failed
```

これは`cross`がDockerをつかってビルドするときに使用する環境とホスト環境とで、ソースツリーが置かれているディレクトリのパスが違っていることが原因です（まあ `pwd` の結果はそのまま使えないのは明かですね）。

じゃあどこにマウントされているんだと云うはなしですが、[`cross`のREADME](https://github.com/rust-embedded/cross#docker-in-docker)をよく読むとそれらしき記述があります。

> When running cross from inside a docker container, cross needs access to the hosts docker daemon itself. This is normally achieved by mounting the docker daemons socket /var/run/docker.sock. For example:
> 
> ```
  $ docker run -v /var/run/docker.sock:/var/run/docker.sock -v .:/project \
    -w /project my/development-image:tag cross build --target mips64-unknown-linux-gnuabi64
  ```
> 
> The image running cross requires the rust development tools to be installed.
> 
> With this setup cross must find and mount the correct host paths into the container used for cross compilation. This includes the original project directory as well as the root path of the parent container to give access to the rust build tools.

`/project` 以下にマウントしろっていっていますね。

というわけで、最終的にこうしたらうまくいきました。

```shell
ROSRUST_MSG_PATH="/project/msgs" cross build --target arm-unknown-linux-musleabihf
```
AI素人のポンコツエンジニアがG検定対策に合格した件について（G検定対策）【中編】 

#はじめに
　昨年（2020年）、日本ディープラーニング協会（以下JDLA）が運営するG検定に合格致しました。（下記の写真が合格した年度）

![general20203_regular.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681742/a55ccfa7-817f-f1e1-2f4b-90059b1280f9.jpeg)

当初は、AIに関しては「何となく」のイメージしか持っておらず、実際に「AIとは何なのか？」という漠然としたイメージしか持っていませんでした。そのため、AIに関しての現実的な認識を正確に把握していきたいと思い今回受験し、その結果無事に合格致しました。この記事では、私が実際にどのようにしてG検定を合格したのか、【前編】、【中編】、【後編】の3編に分けて解説していきたいと思います。構成は下記のようにしております。

<ul>
<li>【前編】：AI（機械学習・ディープラーニング）がそもそも何なのか理解したい初級者向け</li>
<li>【中編】：G検定の全容を把握したい中級者向け</li>
<li>【後編】：G検定を本格的に合格したい上級者向け</li>
</ul>

#そもそもG検定とは何なのか
　G検定とは、JDLAが主催する<b>ビジネスレベル（事業レベル）に相当する幅広いAIに関しての知識を証明する認定試験</b>となります。「AIって話題になっているけど具体的にはどのようなもの？」、「機械学習とかディープラーニングって何なのか？」、「私たちの生活・社会にとってAIは何の関係性・背景があるのか？」といったAIに関する歴史・技術・背景・法律・社会などを幅広いAI周りの知識の理解を目標としており、現在多数の主要IT企業も注目している認定試験でもあります。ちなみに、G検定の「G」はジェネラリスト（generalist）の頭文字から取ってきております。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681742/f12e92d1-cbb9-9cae-1590-c2448e04e6c4.png)


#本題
　今回は、【中編】という訳でG検定の概要に関する対策方法を、（前回の【前編】で行った）AIに関する大まかな理解を元にG検定の形式を話していきたいと思います。
　G検定の対策を行う上で、どのような範囲でどのような問題が出てきて、そしてどのような傾向があるかを大まかに理解するのでしたら、こちらの書籍を活用するのが一般的です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681742/2e9f9647-1a81-f7ff-7ede-07323d00dd84.png)

　こちらは通称「白本」と呼ばれる、JDLAが公式で出版しているG検定の公式参考書です。
G検定の土台となる部分はここから出てくると言っても過言ではありません。書籍には具体的に、下記のような内容が掲載されています。

<ol>
<li>人工知能（AI）とは</li>
<li>人工知能をめぐる動向</li>
<li>人工知能分野の問題</li>
<li>機械学習の具体的手法</li>
<li>ディープラーニングの概要</li>
<li>ディープラーニングの手法</li>
<li>ディープラーニングの研究分野</li>
<li>ディープラーニングの応用――産業活用</li>
<li>ディープラーニングの応用――法律・倫理・現行</li>
</ol>

　こちらの書籍は著者がJDLAを中心に執筆しているだけあって、G検定に関する各用語の解説（図解）がとても丁寧で分かりやすい特徴があります。また、冒頭にも触れましたがこちらの書籍はAI（機械学習・ディープラーニング）は勿論の事、技術構造や歴史的背景・研究内容・社会背景・産業活用・法律（倫理）などといった、G検定に関する幅広い基礎内容を網羅しており、G検定の大まかな形式を理解するうえでも参考となる書籍でもあります。特に、（【前編】お話したような）AIに関するとらえ方をある程度理解できている方にとってはとてもとっつきやすい構成になっております。

　しかし一方で、（ここまで解説してアレなんですが）実はG検定を合格するには「白本」では圧倒的に不十分です。なぜならば、「白本」に出題出てくる内容は実際のG検定の一部分でありかつ基礎的な部分――<b>要は知っていて当たり前だよね</b>――という前提である部分が多いからです。そのため、「白本」はあくまでもG検定の『概要』を理解する認識でとどめておかないと本番で痛い目をみます。それでは、「実際G検定本番を合格するどうすればいいのか？」その内容を次回の【後半】で語っていきたいと思います。

#終わりに
　次回の【後編】では、いよいよG検定に対する本格的な攻略方法について話していきたいと思います。また、余談ですが今回のG検定の経験を元に「G検定対策辞典」というサイトを開設いたしました。

https://www.gsite.tech

こちらはG検定に頻出の用語を掲載している辞書サイトです。良かったらぜひご活用してみて下さい。それではまた。