OmniAICreator/Qiita-1.07M huggingface dataset:
Snykを使ってPostgreSQL拡張機能pgAuditを脆弱性診断してみた

## はじめに

この記事は[Qiita Engineer Festa 2022](https://qiita.com/official-campaigns/engineer-festa/2022)への参加記事です。

Snykの脆弱性診断機能を用いて、OSSプロジェクトを診断してみます。
診断対象として、PostgreSQLの監査ログ拡張機能[pgAudit](https://github.com/pgaudit/pgaudit)を選びます。
自分がコントリビュートした[pgaudit.log_rows](https://github.com/pgaudit/pgaudit/pull/133)機能も含まれており、
脆弱性が検知された場合、他人事にできないので少しドキドキ。。。

## Snyk(スニーク)とは

- 安全で迅速な開発を支援する、デベロッパーファーストのセキュリティプラットフォーム
- コードの依存OSSやコンテナ/IaC(Infrastructure as Code)の脆弱性を見つけ、優先順位をつけ自動修正
- Gitや統合開発環境(IDE)、CI/CDパイプラインに直接組み込めるため、簡単に使用可能

※ 引用元: https://go.snyk.io/jp.html

## pgAuditとは

-  PostgreSQLで監査ログを取得するためのオープンソースソフトウェア
-  PostgreSQLの拡張機能として、C言語で実装されている
-  監査対象として設定した内容は、PostgreSQLログに混在して出力される
-  GitHubの[pgauditリポジトリ](https://github.com/pgaudit/pgaudit)

## Snykにサインアップ

- [Snyk Webサイト](https://snyk.io)の画面右上から`Sign up`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/9a6226ca-a2a6-f1c3-380b-ce2bb74b5d99.png)

- GitHubやGoogleアカウントを用いて、サインアップ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/a8d55876-ce5a-7971-d003-40ae3033f987.png)

## pgAuditはC言語で書かれているが、脆弱性診断可能か?

- Snykドキュメントを読むと、Snyk CLIでCプロジェクトのスキャン可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/3d77278b-7c3e-6a26-efbe-80f626f53367.png)

## Snyk CLIをインストール

- VS Codeのターミナルなどで、npmを用いてインストール
```
C:\snyk>npm install snyk@latest -g
```

- Snykバージョンを確認
```
C:\snyk>snyk --version
1.958.0
```

- Snykアカウントを用いて、Snyk CLIを認証
``` 
C:\snyk>snyk auth

Now redirecting you to our auth page, go ahead and log in,
and once the auth is complete, return to this prompt and you'll
be ready to start using snyk.
```

- ブラウザが開かれ、認証画面が表示されるので、認証ボタンを押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/bbe03c88-ec88-1c85-7c32-2deacb0a4cc1.png)

- VS Codeのターミナルで、以下表示される
```
Your account has been authenticated. Snyk is now ready to be used.
```

## cloneしたpgauditリポジトリに対し、`snyk monitor`を実行

- pgauditリポジトリをclone
```
C:\snyk>git clone git@github.com:pgaudit/pgaudit.git
C:\snyk>cd pgaudit
```

- pgauditをSnykに登録し、脆弱性(及びライセンス問題)を継続的に監視
```
C:\snyk\pgaudit>snyk monitor --unmanaged 

Monitoring C:\snyk\pgaudit (pgaudit)...

Explore this snapshot at https://app.snyk.io/org/mingchun.zhao/project/80b2c854-a408-4abc-b07c-9ee56f614aee/history/03fc148f-5176-42ef-b83a-e758b682ae14

Notifications about newly disclosed issues related to these dependencies will be emailed to you.
```

- 上記snapshotのURLを確認すると、pgauditに問題は存在しません、とのこと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/fdc5aabb-55a5-d4fe-e066-5e9b0cdc6758.png)

## Snykの脆弱性DB(Vulnerability DB)

安心したのも束の間、
Snykの脆弱性DBに、`Linux centos8 pgaudit package`の
[pgaudit vulnerabilities](https://snyk.io/vuln/centos%3A8%3Apgaudit)が存在していました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/5062d304-3d21-7cbd-1175-f2d2315f4cdd.png)

SQL Injectionの脆弱性もちらほら、どういうこと? 確認しなくちゃ。。。

## おわりに

Snykを使って、OSSのpgAuditに対し、脆弱性診断を行ってみました。
Snykが、pgAuditの脆弱性DBを管理していることに、少し驚きました。
EC2 x nginx ベーシック認証の掛け方

# EC2 x nginxのBasic認証の掛け方

apacheとnginxで掛け方が異なるので注意。

今回はnginxの方法(**nginxの今回の方法では.htaccessの作成は不要**）

参考記事

- ****[たった3分！ベーシック認証の付け方！【プログラミング】](https://nacchi.org/2019/03/23/how-to-set-basic-key/)****
- [.htaccessと.htpasswd作成サイト](http://www.htaccesseditor.com/#a_basic)
    
    このサイトの方法で.htpasswdに記入する記述を作成する

    
 ## .htpasswdの作成と**nginx.confに.htpasswdを使用したBasic認証の記述を追加する
[参考記事](https://dev.classmethod.jp/articles/amazon_linux_nginx_basic_auth/#:~:text=%E3%82%92%E8%A1%8C%E3%81%84%E3%81%BE%E3%81%99%E3%80%82-,.htpasswd%20%E3%81%AE%E4%BD%9C%E6%88%90,-%E8%AA%8D%E8%A8%BC%E7%94%A8%E3%81%AE)
 ### .htpasswdの作成
        
  EC2にssh接続して以下のディレクトリへ移動
        
  ```$ cd /usr/share/nginx/html/```
        
 さらに以下で.htpasswd作成
        
 ```sudo touch .htpasswd```
        
 `sudo vi .htpasswd` を使用し、上述のサイトで作った.htpasswdに記入する１行を貼り付け
        
### nginx.confの編集
        
 nginx.conf に basic認証 の設定を追記
        
  `sudo vim /etc/nginx/nginx.conf`
        
            server {
                listen 80;
                server_name localhost;
        
                #charset koi8-r;
        
                #access_log /var/log/nginx/host.access.log main;
        
               <--以下を追記-->
                auth_basic "basic authentication";
                auth_basic_user_file "/usr/share/nginx/html/.htpasswd";
               <--追記ここまで-->
        
                location / {
                    root /usr/share/nginx/html;
                    index index.html index.htm;
                }
 
        
* auth_basic ディレクティブは、basic認証時のメッセージダイアログに表示
* auth_basic_user_file ディレクティブは、先ほど作ったパスワードファイルの場所を指定
2022-06-24 PHP のコマンドラインアプリケーションにおいて、エラーが表示されない

<!-- Output copied to clipboard! -->

<!-----

Yay, no errors, warnings, or alerts!

Conversion time: 0.328 seconds.


Using this Markdown file:

1. Paste this output into your source file.
2. See the notes and action items below regarding this conversion run.
3. Check the rendered output (headings, lists, code blocks, tables) for proper
   formatting and use a linkchecker before you publish this page.

Conversion notes:

* Docs to Markdown version 1.0β33
* Sat Jun 25 2022 22:37:07 GMT-0700 (PDT)
* Source doc: 2022-06-24 PHP のコマンドラインアプリケーションにおいて、エラーが表示されない
* This is a partial selection. Check to make sure intra-doc links work.
----->


## 環境

* CentOS 7
* PHP 5.4

## 発生した問題

PHP のコマンドラインアプリケーションにおいて、エラーが表示されない

```console
$ php ./script.php
$ echo $?
255
```

exit code 255 は多くの場合、エラーが発生していることを示す。

## 解決方法

コード内で以下を指定する。

```php5
error_reporting(E_ALL)
ini_set('display_errors', 'on')
ini_set('log_errors', 'on')
```

## 解説

確認する箇所は以下の三点

1. "error_reporting" の値が "E_ALL" か
2. "display_errors" の値が "on" か
3. "log_errors" の値が "on" か
アルゴリズムパワーで最長ダジャレ問題を解く

ダジャレ力を磨くためには、日常に潜むダジャレを見つけ出す能力の成長が欠かせません。そこで、今回は文字列中からなるべく長いダジャレの文字列長を見つけ出すアルゴリズムについて考えます。

:::note info
この記事は Qiita Engineer Festa 2022 (https://qiita.com/official-campaigns/engineer-festa/2022) および Qiita Engineer Festa アルゴリズム強化月間 (https://qiita.com/official-events/55631b864217a4df857a) のために書かれました。
:::

# tl;dr
ある文字列 $S$ に登場する最長のダジャレの文字列長を求めるには動的計画法を用いれば良いです。愚直解法の計算量 $\mathcal{O}(|S|^5)$ と比べて、動的計画法を用いた場合は $\mathcal{O}(|S|^2)$ とかなり高速です。

# 最長ダジャレ問題
次のような問題を最長ダジャレ問題と呼ぶことにします。この問題の解法について考えます。

> ある文字列 $S$ の中に区間が重複することなく $2$ 回以上登場する部分文字列 $T$ の長さ $|T|$ の最大値を求めよ。

:::note info
「あるみかんのうえにあるみかん」のような文字列は答えが $5$ になります。
:::
:::note warn
「ふとんがふっとんだ」のような文字列は答えが $2$ ('とん' の部分) になってしまいます。一般的なダジャレの判定基準と異なることに注意してください。
:::


# 愚直な解法
文字列 $S$ の全ての部分文字列に対して区間が重複しない部分文字列の列挙を行い、文字列一致判定を行います。
ある部分文字列と区間が重複しない部分文字列の列挙に $\mathcal{O}(|S|^2)$ ほどの計算量がかかり、文字列一致の判定には $1$ 回あたり平均 $\mathcal{O}(|S|)$ の計算量がかかります。これを全部分文字列 $\mathcal{O}(|S|^2)$ 個に対して行います。
したがって、全体として $\mathcal{O}(|S|^5)$ の計算量がかかってしまいます。

:::note warn
時間計算量 $\mathcal{O}(|S|^5)$ というのは、現代の計算機であれば $|S|\leq 50$ 程度なら数秒のうちに計算できるというレベルの計算量です。
:::

# 高速な解法
動的計画法を使うと $\mathcal{O}(|S|^2)$ 程度の計算量で求められます。
部分文字列 $S_i, S_{i+1},...,S_{j-1}$ を $S[i: j]$ として表します。(Python のスライスと同じです)

:::note info
$\mathcal{O}(|S|^2)$ というのは、現代の計算機であれば $|S|\leq 5000$ 程度なら数秒のうちに計算できるというレベルの計算量です。
:::

$f_{i,j}$ を、 $S[i-d: i]$ と $S[j-d: j]$ が等しく、$[i-d:i)$ と $[j-d:j)$ が共通部分を持たないような $d$ の最大値とします。この $f_{i,j}$ を全てのありうる $i,j$ について求めて、その最大値をとったものがこの問題の答えとなります。

### 漸化式
$f_{i,j}$ を求める漸化式を作ります。
$i$ 文字目と $j$ 文字目が等しくて、$[i-f_{i,j}:i+1)$ と $[j-f_{i,j}:j+1)$ が共通部分を持たないなら、
$$f_{i+1,j+1}=f_{i,j}+1$$
のように更新できそうです。
$i$ 文字目と $j$ 文字目が等しくて、$[i-f_{i,j}:i+1)$ と $[j-f_{i,j}:j+1)$ が共通部分を持つなら、
$$f_{i+1,j+1}=f_{i,j}$$
です。そもそも $i$ 文字目と $j$ 文字目が等しくないなら、
$$f_{i+1,j+1}=0$$
となります。初期値は 0 としてよさそうです。

### Python コード
簡単のため、$i \lt j$ としています。得られる答えは同じです。
```python:longest_dajare.py
def longest_dajare(S):
  n = len(S)
  f = [[0] * (n + 1) for _ in range(n + 1)]

  for i in range(n):
    for j in range(i + 1, n):
      if S[i] == S[j] and j - f[i][j] >= i + 1: f[i + 1][j + 1] = f[i][j] + 1
      if S[i] == S[j] and j - f[i][j] < i + 1: f[i + 1][j + 1] = f[i][j]
      if S[i] != S[j]: f[i + 1][j + 1] = 0

  return max((max(fi) for fi in f))

print(longest_dajare("あるみかんのうえにあるみかん"))
# 5

print(longest_dajare("ああああああああ"))
# 4
```

漸化式の定義通りに書いているので少し冗長ですね。
# 更なる高速なアルゴリズムへ……
Longest Duplicate Substring (no overlapping) などで調べると同じような問題で議論している人たちを見つけることができます。もっと速いアルゴリズム $\mathcal{O}(|S|\log^2|S|)$も見つかっているようです。

# おわりに
今回は「最長ダジャレ問題」について扱いました。最初、Suffix Array と LCP Array で線形計算量になる気がしていましたが、区間の重複が出るのでボツになりました。（3000文字書いてから気付いて絶望した……。）結果的にパワー感がちょっと足りない感じになってしまいました。

「ふとんがふっとんだ」を「ふとん」に関するダジャレとして検出しようとするのは自然言語処理の分野になるのかなと思います。こちらが検出できた方がダジャレ検出っぽくはあるのですが……。
【SourceTree】ローカルリポジトリをGitHubの（リモート）リポジトリに登録しようとした話

ローカルにあるリポジトリをGitHubのリポジトリに登録してバージョン管理できたらいいな-と思い、SourceTreeで試した結果を記載します。
GitコマンドではなくUIで実行したかったので。。
# そもそも何がしたかったか？
文書をGitでバージョン管理したかったのが事の発端です。
こちらの書籍（[達人プログラマー ―熟達に向けたあなたの旅― 第2版](https://www.amazon.co.jp/dp/B08T9BXSVD/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)）を読んだ際、『すべての文書に対して、常にバージョン管理しなさい』と記載されておりました。
プログラムのソースはたしかにGitとかで管理したことあったけど、文書とかはGitで管理してなかったーーーーと思い、バージョン管理しようと思いました。

ということで、以前から使用したことのある（macに入っていた）GitHubとSourceTreeを使ってバージョン管理していこうと思いました。


# SourceTreeからリモートリポジトリ作成できない。。
SourceTreeから「既存のローカルリポジトリ追加」→「リモートリポジトリも作成する」とかやったらうまくいくかと思いましたがエラーが出ました。。

![スクリーンショット 2022-06-26 19.01.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480938/1ca7278d-bf11-e055-0c1c-e165cd0ab87c.png)
![スクリーンショット 2022-06-26 19.01.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480938/04de9808-0e71-09ce-8349-8df8aa5a8e77.png)

>message: Not Found
>
>https://docs.github.com/rest/reference/repos#create-an-organization-repository

# 結局どうしたか？
GitHub Desktopをインストールして「Add」→「Add Existing Repository」でGit管理したいリポジトリを追加。（今回だとOther＞Documents）
Git管理したいリポジトリを追加したら「Publish repository」をクリックする。（GitHubとSourceTreeの連携が必要だったような。。）


![スクリーンショット 2022-06-26 19.19.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480938/e2f420d8-2ef7-47fc-2de7-d6ea5860cb55.png)

そうするとGitHubのブラウザに追加されている！！（だが中身はない。。）

![スクリーンショット 2022-06-26 19.24.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480938/4a9087f5-e8ad-a2a9-c7e7-08eb0eb8d876.png)


リポジトリの中身（今回はDocuments）を反映したいので、SourceTree＞新規...のドロップダウンから「既存のローカルリポジトリを追加」でリポジトリを追加。

![スクリーンショット 2022-06-26 19.35.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480938/799179fd-5d02-aa9b-469a-08b1d829bb0c.png)

追加したリポジトリを開いてワークスペースからコミット→プッシュを実施すると、ブラウザ上のGitHubに反映される。

![スクリーンショット 2022-06-26 19.40.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480938/cf3f404b-f441-074a-b141-3af8b0107cae.png)

![スクリーンショット 2022-06-26 20.46.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480938/c695f9ae-52ec-54ec-768f-083b1b194348.png)

# まとめ
回りくどくなってしまいましたが、もっとシンプルな方法がありそう。。
cscの作法 その214

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

# 練習問題
証明書のファイルを読め。

# サンプルコード

```
using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Security.Authentication;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.IO;

namespace app
{
	public class test0 {
		private static void PrintCertificate(X509Certificate certificate) {
			Console.WriteLine("Subject: {0}", certificate.Subject);
			Console.WriteLine("Issuer: {0}", certificate.Issuer);
			Console.WriteLine("Format: {0}", certificate.GetFormat());
			Console.WriteLine("ExpirationDate: {0}", certificate.GetExpirationDateString());
			Console.WriteLine("EffectiveDate: {0}", certificate.GetEffectiveDateString());
			Console.WriteLine("KeyAlgorithm: {0}", certificate.GetKeyAlgorithm());
			Console.WriteLine("PublicKey: {0}", certificate.GetPublicKeyString());
			Console.WriteLine("SerialNumber: {0}", certificate.GetSerialNumberString());
		}
		public static int Main(string[] args) {
			string certPath = "certificate.crt";
			X509Certificate cert = X509Certificate.CreateFromCertFile(certPath);
			PrintCertificate(cert);
			return 0;
		}
	}
}


```

# 実行結果

```
>ca0
Subject: OU=None, O=Studio-Ephyra, L=Nagano-Shi, S=Nagano-Ken, C=Japan, CN=link.studio-ephyra
Issuer: OU=None, O=Studio-Ephyra, L=Nagano-Shi, S=Nagano-Ken, C=Japan, CN=link.studio-ephyra
Format: X509
ExpirationDate: 2032/06/20 19:26:56
EffectiveDate: 2022/06/20 19:26:56
KeyAlgorithm: 1.2.840.113549.1.1.1
PublicKey: 3082020A028202010096BA54960C5368E2C050D3AEB38E5C97F5413ADAA802FD58DF0DE46B954BCF11D5830F59E205B5B796B52AC6DBA09427FEEFE01B9489FC5695E11CE525EFE71B16187A9E5F71F4878993C257FFF9C65ED024BBE1E0FCC0EAF5C9DC125017B984C79C6FBD6D866BE8136297C0429A68FCE19C8C627554BC34EB1E28354962CFDCC7FEF5113A5351D936E197CC6949463A2C23C9890BE155B2010BA1892A8B1FAD75DEFABB6B19B52B36DB0E8C660993BE3DEBF8731EDB2B0F2F877410162838DDA2DEC65B6112C726C8AD55080EFC8D5D5F42532C90982FE303AFF288037DC6B58AEF9527EC46AFFDB6E138A54637D0C2D89692A137236AFA263FD40C1168D63B135C097D1FEA238D0460F0E05A5A61A091CA2AA40FF958D717C014B1210FFE5063A196BC782F4520F28D0C15F0C738654391B045FB78DD4351D21951F27996C445C17BB10A78E0CE4762FFE459A1C3CEB9A1648E95FF12CD1971673C45BFFE772689425573AD01C2EF2F0B76E3DAFAAA2D6FBBCB523A31A7ED60D3219E2BA4B2E2C5CED147E5AEB7EC227F2F7E65B754D171854509078AEE5F0F7DC809321B00961289D81F719B2B4F6CC7EDFF70D0D9771F55D38AB7BE9DE732BD2343655F17A239A5119197A9E25940CD1F9385706390E8344119A689F8B5D79FA767B2FA6298F99FDFCA6C85857C3A21D5975A387CFD0DC5D790976E5722918058910924010203010001
SerialNumber: 01

```


以上。
【Swift】オプショナルのアンラップ方法

# 強制アンラップ
```swift
var text: String? = "Hello world"

print(text!)

// Hello world
```

# guard
```swift
var text: String? = "Hello world"

guard let text = text else { return }

print(text)

// Hello world
```

# if let
```swift
var text: String? = "Hello world"

if let text = text {
    print(text)
}

// Hello world
```

# デフォルト値
```swift
var text: String? = "Hello world"

print(text ?? "")

// Hello world
```
🔰【初学者用】Ruby・Rails環境構築

# はじめに
今回もPC変えたときに困らないよう環境構築を載せておきます。
PCの環境構築はこちらから↓

https://qiita.com/hondano_gentuki/items/0cb7367f390e36f1a047

# 環境構築

## Ruby
### rbenv と ruby-buildのインストール
まずはRubyの土台となる、rbenvとruby-buildを、Homebrewを用いてインストールします。
Homebrewをインストールしていない方は上記のPC環境構築をご覧ください。
```Ruby:ターミナル
brew install rbenv ruby-build
```
続いてrbenvをどこからも使用できるようにします。
```Ruby:ターミナル	
% echo 'eval "$(rbenv init -)"' >> ~/.zshrc
```
続いてzshrcの変更を反映させます。
```Ruby:ターミナル	
% source ~/.zshrc
```
これでrbenv と ruby-buildをインストール部分は完成です。

###  readlineのインストール
ターミナルのirb上で日本語入力を可能にする設定を行うために、以下のコマンドでreadlineをインストールします。
```Ruby:ターミナル	
% brew install readline
```
先程同様、readlineをどこからでも使用できるようにします。
```Ruby:ターミナル	
brew link readline --force
```
readlineの設定はこれでかんりょうです。
### Rubyのインストール
webアプリ開発のRubyをインストールします。
```Ruby:ターミナル	
% RUBY_CONFIGURE_OPTS="--with-readline-dir=$(brew --prefix readline)"
% rbenv install 2.6.5
```
処理に時間がかかります。
Rubyのバージョンを指定します。
```Ruby:ターミナル	
% rbenv global 2.6.5
```
以下のコマンドで変更を反映。
```Ruby:ターミナル	
% rbenv rehash
```
ここまでできたらしっかりインストールされているか以下のコマンドで確認します。
```Ruby:ターミナル	
% ruby -v
```
Rubyのバージョンが表示されていれば完成です。

## Rails
### bundlerをインストール
まずはRubyの拡張機能を管理するためのbundler（バンドラー）をインストールします。
```Rails:ターミナル
% gem install bundler --version='2.1.4'
```
### Railsをインストール
```Rails:ターミナル
% gem install rails --version='6.0.0'
```
処理に時間がかかる場合があります。
### rbenvを再読み込み
```Rails:ターミナル
% rbenv rehash
```
ここまでできたらしっかりインストールされているか以下のコマンドで確認します。
```Rails:ターミナル
% rails -v
```
## Node.js
Railsを動かすためにはNode.jsが必要になります。Node.jsもHomebrewを用いてインストールします。
```Node.js:ターミナル
% brew install node@14
```
続いてパスを設定します。
```Node.js:ターミナル
% echo 'export PATH="/usr/local/opt/node@14/bin:$PATH"' >> ~/.zshrc
% source ~/.zshrc
```
ここまでできたらしっかりインストールされているか以下のコマンドで確認します。
```Node.js:ターミナル
node -v
```

## yarn
yarnはプログラム動詞の関係性を管理するという役割があります。
```yarn:ターミナル
% brew install yarn
```
インストールされているか確認します。
```yarn:ターミナル	
% yarn -v
```

これで完了です！お疲れさまでした！！

# 終わり
学習コストが高いため、初学者がこれらを「覚える必要はないかな。」と感じています。
PCを変えたときなどに見返したいと思います。
PCファンの回転数計測

# はじめに
PC用3pinファンの回転数信号を計測する方法を紹介します
(4pinファンでも計測可能なはず)

# 測定環境
マザーボード 　　 ：ASUS Z170-A
PCファンA    　　　    ：Nidec BETASL D07A-12PM 09A
PCファンB   　　 　   ：Hydro Series H55付属品(12V 0.15A)
オシロスコープ  　      ：GDS-1052-U

# 測定方法
回転数信号線をプルダウンして計測

__・PCファンA__
Arduino nanoの5V電源で駆動、プルアップも5V
⇒壊れても被害が小さい電源を使用し、回路が正常で計測できることを確認することが目的

![回路図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1977949/3faeed6b-ea6c-3911-512d-1ec8fc035e21.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1977949/035648c3-aed4-b3a8-a417-459a820be3cf.png)







__・PCファンB__
PC使用状態　12V駆動、プルアップ12V
BIOSで回転数をモニタ
⇒実使用環境で測定

※画像を取り忘れました
　Arduinoを取り外してプルアップ電源はSata12V、
　GNDはファンのGNDpinから取得


# 測定結果
__・PCファンA__
電源とプルアップも5Vのため、約5Vで波形が発生している
![A0005DS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1977949/ac161bf4-149f-1651-5bc9-3c260e9b49fe.jpeg)

__・PCファンB__
853RPM:29.02Hz
![DSC_2075.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1977949/4f8430f5-b7b3-181b-3c9e-9be0ec00bbeb.jpeg)


1584RPM:53.13Hz
![DSC_2071.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1977949/beda6859-3dce-fb76-d4fe-a139499dcf5d.jpeg)


### 測定結果一覧
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1977949/0d987cdc-ebd0-f2f1-2ad7-8fbfddb27459.png)

# 考察
PCファンBの測定結果から周波数は __秒間回転数__ の __2倍__ ということがわかる
つまり、 __1回転__ で __2パルス__ 出力されると考えられる

# マイコンでの計測
Arduinoであれば割り込み処理とタイマ関数を使用して、回転数(Rpm)を求められそうです
気が向いたら実験してみます

# 失敗したこと
プルアップせずに直接回転数信号線に接続したところ
パルス波形ではなく交流波形のようになってしまった
オシロの時間軸から周波数を算出することは可能だが、
立ち上がりor立下りで判定するマイコンなどでは正確な算出が難しいと考える
![A0004DS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1977949/38d8cdf6-d37e-33b2-a01f-2651c79e4f55.jpeg)
コマンド操作でWindowsの環境変数を設定する。

# はじめに
たまにしか設定しませんが、設定するとなった場合にどこから辿れば良いかを忘れてしまい、あたふたすることが多いので、`PowerShell`から環境変数を設定する方法をまとめておこうと思います。

# コマンドからの環境変数の一時設定
現在の設定を確認するコマンドは以下となり、「**$Env:[変数名]**」となります。

```powershell:現在の設定の確認
$Env:PATH
```

変数に値を追加するには「**=**」で設定を行います。

```powershell:変数へ値を挿入
$Env:TEST = "variable test"
```

また、以下のような書式で記載することで、指定した環境変数の後ろに所定の値を追加することも可能です。

以下は`PATH`に「**C:\Users\UserName\APL\bin**」を追加する場合の例。

```powershell:既存のPATH変数に追加
$Env:PATH += ';' + 'C:\Users\UserName\APL\bin'
```

再度設定の確認コマンドを実行し、指定の変数が追加されていることが確認出来たら完了です。

# コマンドからの環境変数の永続設定
現在の設定を確認するコマンドは以下となり、「**[System.Environment]::GetEnvironmentVariable('[変数名]' , '[User or Machine]')**」（User=ユーザ変数、Machine=システム変数）となります。

```powershell:現在の設定の確認（ユーザ変数の場合）
[System.Environment]::GetEnvironmentVariable('PATH' , 'User')
```

```powershell:現在の設定の確認（システム変数の場合）
[System.Environment]::GetEnvironmentVariable('PATH' , 'Machine')
```

既存の変数に所定の値を追加する場合、一時設定と同じような書式で記載することもできますが、長くなって見づらくなるので、ちょっと面倒ですが仮の変数を作って、結果を結合して作ります。

```powershell:既存のPATH変数に追加（ユーザ変数の場合）
$path = [System.Environment]::GetEnvironmentVariable('PATH' , 'User')
$path += ';' + 'C:\Users\UserName\APL\bin'
[System.Environment]::SetEnvironmentVariable('PATH' , $path , 'User')
```

```powershell:既存のPATH変数に追加（システム変数の場合）
$path = [System.Environment]::GetEnvironmentVariable('PATH' , 'Machine')
$path += ';' + 'C:\Users\UserName\APL\bin'
[System.Environment]::SetEnvironmentVariable('PATH' , $path , 'Machine')
```

再度設定の確認コマンドを実行し、指定の変数が追加されていることが確認出来たら完了です。

尚、システム変数の`PATH`に追加する場合は管理者権限が必要となるため、`PowerShell`を管理者モードで実行する必要があります。

一度`PowerShell`を閉じたのち、再度開き、先ほど設定した変数が消えていなければ成功です。

# おわりに
次に環境変数を設定する場合、自分が書いたこのページを見ながら設定することになると思うので、結局手間は変わりませんが、Windowsの構築をコマンドで行うような場合に使えそうです。

あまり`Windows`には詳しくありませんが、1から`Windows`を構築するようなことがあったら使ってみようと思います。
flutter で自作アニメーションを表示させる　Rive2（旧 Flare）

# 初めに
https://fireship.io/lessons/animated-navigation-flutter-flare/
このYoutubeを見てやってみようと思ったのですが、Flare→Riveに名前が変わっていたり、リンクが使えなかったり色々変わっていたので、その辺りを記述します。

Riveを使うと自分で作成したアニメーションをアイコンで利用できたり、ボタンでアニメーションを制御したりできます!

アニメーションの作成方法は、今までとほとんど同じようなので、解説は省きます。
他のサイト等を参考にしていただければと思います。

今回は下記のように単純に表示だけしてみます!
![](https://storage.googleapis.com/zenn-user-upload/77c52d39d5a9-20220626.gif)

# ◎アニメーションを作成と保存
## 作成
下記リンクからRive2へ飛べます。
アニメーションの作成方法は、省略します。
https://editor.rive.app/browser/158215/home
## 保存
作成後に、画面上部の保存のアイコンをクリック
![](https://storage.googleapis.com/zenn-user-upload/b2938ec9a66a-20220626.png)
「For newest runtime」をクリックすると、rivファイルがダウンロードされます。 
![](https://storage.googleapis.com/zenn-user-upload/287bd1ae89cc-20220626.png)

# ◎Flutterで表示させる
今回はシンプルに表示だけさせてみます!
## 作成したrivファイルを、flutterプロジェクトに追加・読み込みをする

１：flutterプロジェクト直下に``assets``ファイルを作成。(名前なんでOKです)
２：``pubspec.yaml``ファイルを編集し、作成したrivファイルに接続できるようにする。
``star.riv``の部分を自分の作成したファイル名に変更してください。
```
flutter:
  uses-material-design: true
  assets:
    - assets/star.riv
```
## riveのパッケージをインポートする
下記コマンドを、ターミナルで実行する
```
flutter pub add rive
```
[参考]
https://pub.dev/packages/rive

## アニメーションを表示させるコード
下記のコードで
``assets/star.riv``の部分を``assets/作成したrivファイル名``に変更だけしてコピペで表示ができます!

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

void main() {
  runApp(MaterialApp(home: SimpleAnimation()));
}

class SimpleAnimation extends StatelessWidget {
  const SimpleAnimation({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
        child: RiveAnimation.asset(
          'assets/star.riv',
        ),
      ),
    );
  }
}
```
# 終わりに
Twitterでも情報発信しておりますので、ぜひフォローお願い致します!
https://mobile.twitter.com/tatsuki_kt
DOMの親子関係等を整理してみた。

DOM操作に少し慣れてきたのですが、実際に書いてみると親子等の操作がまだよく理解できておらず、うまく動かないことが多いです。
そのため備忘録として投稿させていただきます。
````domFamily.html
<body class="first">
body=さらに先祖
    <div class="ancestor">
        ancientor=先祖
        <div class="parent">
            parent=親要素
            <div class="prev">prev=直前にある兄弟要素</div>
            <div class="base">
            base=主とする要素＜＝
                <div id ="ch1" class="child">chi1=子要素1</div>
                <div id ="ch2" class="child">chi2=子要素2</div>
                <div id ="ch3" class="child">chi3=子要素3</div>
            </div>
            <div class="next">next=直後にある兄弟要素</div>
        </div>
    </div>

    <script>
        //親が兄弟を取得
        let bros = document.querySelector(".parent").children;
        console.dir(bros);
        //親が自分を取得
        console.dir(bros[1]);
        //親の要素を取得
        let per = document.querySelector(".base").parentElement;
        console.dir(per);
        //前の兄弟を取得
        let bro1 = document.querySelector(".base").previousElementSibling;
        console.dir(bro1);
        //後ろの兄弟を取得
        let bro2 = document.querySelector(".base").nextElementSibling;
        console.dir(bro2);
        //子のリストを取得
        let chList = document.querySelector(".base").children;
        console.dir(chList);
        //子の最初を取得
        let firCh = document.querySelector(".base").firstElementChild;
        console.dir(firCh);
        //最後の子を取得
        let lasCh = document.querySelector(".base").lastElementChild;
        console.dir(lasCh);
        //先祖を取得
        let anc = document.querySelector(".base").closest(".ancestor");
        console.dir(anc);
        //さらに先祖を取得
        let anc2 = document.querySelector(".base").closest("body");
        console.dir(anc2);
    </script>
</body>
````
プログラマーなら因果と相関を見極めるべし。

## はじめに
<font color="Red">バグの理由がさっぱりわからない...</font>
理由を述べても<font color="Red">「それ、因果じゃなくて相関あるだけなじゃい？」</font>と言われる...
こんなことありませんか？

そんな駆け出しエンジニアのあなたは**因果と相関**を勉強すると良いかも？
論理的思考力を高めて、業務を効率よく進めましょう。

## 対象者
この記事は下記のような人を対象にしています。

- 駆け出しエンジニア
- プログラミング初学者
- 論理的思考力が弱い、と感じる人
- 理由を考えるのが苦手な人

## 結論
因果関係＝<font color="Blue">「完全にこいつのせいじゃん、これを改善すれば解決じゃん」</font>
相関関係＝<font color="Orange">「こいつと関係ありそう...これを修正すれば解決...かも...」</font>

## 因果関係とは
因果関係とは、理由がはっきりしている関係のことです。
下記に例を示します。

:::note
- サーバーが落ちたので、ホームページが表示されなくなった。
- CSSの記述を変更したら、文字が赤で表示された。
- 修正をデプロイしたら、エラーが出た。
:::

**Aしたら、Bになった**という構造です。
下記3点に気をつけましょう。

:::note
- Aの後にBが起きていること
- Aをしたら**必ず**Bになること(まぐれではなく、再現性があること)
- Aをしない時はBにならないこと
:::

上記の通り、何度も確認して再現性を取る必要があるため、世の中のほとんどの仮説は因果関係を証明できません。
「タバコを吸う人は早死にする」ことを何度もトライして証明するのは難しいですよね。
しかし、プログラミングの世界では、何度もトライすることが可能なので、再現性を確認して、因果関係を証明しましょう。

## 相関関係とは
因果関係を見つけられれば、バグ修正は完了ですが、世の中そんなに簡単にはいきません。
そんな時には**相関関係**を活用しましょう。
名前は難しそうですが、**関係ありそう感=相関**と覚えておけば良いです。

ちなみに、相関には「正の相関」と「負の相関」があります。

:::note
- 正の相関：一方が増えると、もう一方も増える。正比例の関係。
- 負の相関：一方が増えると、もう一方が減る。反比例の関係。
:::

相関関係の例は下記の通り。

:::note
正の相関：仕事ができる先輩は高いキーボードを持っている人が多い。
負の相関：作業効率が低い人ほど、残業時間が長い。
:::

**Aの場合、Bになる**という関係ですね。
因果関係とは異なり、AとBの時系列は気にしなくて良いです。

また、因果関係とは異なり、再現性も弱めなことがわかります。
高いキーボードを買ったからといって、あなたの仕事力がいきなり上がったりはしないですよね？
作業効率を上げたからといって、必ず残業時間が減るとは限りません。

上記のように、因果関係と比べると「関係あるかも？」くらいのノリです。

### 疑似相関に要注意
相関関係を検証する際、<font color="Red">疑似相関</font>という落とし穴に気をつけましょう。
ぱっと見はそう感がありそうですが、他の要因が絡んでいるため、解決にはつながらない、という罠です。
下記の例で理解してみましょう。

仮に、複数店舗で利用するシステムで、<font color="Red">「同時利用者数が多い店舗で、サーバーからの応答時間が長くなっている」</font>という報告がきたとします。
一見すると、相関がありそうな気がしますね。
この報告に基づいて、「同時アクセス数に制限をかける」修正をデプロイしましたが、<font color="Red">問題は解決せず。</font>

後日、別の目線で解析したところ、<font color="Blue">「利用開始してから長期間経っている店舗で不具合がある」</font>ということに気づきました。
検証を進めると、「運用期間が長い→DBのデータ量が増える→サーバー応答時間が長くなる」という関係が見えてきました。
結果、<font color="Blue">「定期的にデータを削除するスクリプトを実装」</font>することで問題を解決できました。

図にまとめると、下記の通りです。
![相関.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2157342/4e4253ad-1bf2-0bf6-8811-4a2f1180125f.png)


## おわりに
因果と相関についてまとめました。
STM32G031のI2Cからの入力でサーボ出力(Servo.h使用)


目的
I2Cのテスト

1 PWM
2 VDD
3 GND
4 シリアル出力

8 SWD
7 SWD
6 SDA
5 SCL

![o_con549.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/ca249d15-5734-93b4-03d0-f382009c52a9.jpeg)


![o_con550.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/e68fb5a7-3756-6c1f-5e99-6bcf04a3e830.jpeg)



```c++



//I2C_Servo_V2_031_1

#include <Arduino.h>
#include <Wire.h>
#include <HardwareSerial.h>
#include <Servo.h>

Servo fs90r;  // create servo object to control a servo

int val;           // variable to read the value from the analog pin
int servopin = 16; // pin used to connect the servo

//初期化
void setup()
{

  delay(3000); //not delete

  //シリアルの初期化
  Serial.setTx(PA2_ALT1);
  Serial.setHalfDuplex();
  Serial.begin(9600);

  //i2cの初期化
  Wire.setSDA(PA12);
  Wire.setSCL(PA11);
  Wire.begin(); //pa12 pa11
  Wire.begin(0x40);  //I2Cスレーブアドレスの設定
  Wire.onReceive(receiveEvent); //データが来ると呼ばれる関数

  fs90r.attach(servopin, 900, 2100); // attaches the servo on pin 9 to the servo object
                                     // Be careful to min and max values...

} //setup


//メインループ
void loop(){
} //loop


//レシーブイベント
void receiveEvent(int howMany) {

  int x = Wire.read(); //I2C受信データの読み込み

  char c_hex[] = {
      '0', '1', '2', '3', '4', '5', '6', '7',
      '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
  };
  
  char buf[] = { '[',c_hex[(x >> 4) & 0x0f], c_hex[x & 0x0f]  ,']', 0 };
  //
  //  char buf[] = { x, 0  };

  //I2Cスレーブの受信データの表示
  Serial.print( buf );
  //Serial.print( (char)x );

  val = map(val, 0, 256, 0, 180); // scale it to use it with the servo (value between 0 and 180, at 90,
                                   // motor is stopped)

  fs90r.write(val);                // sets the servo speed according to the scaled value

}//receiveEvent


```
[備忘録]Nuxt3でtsconfig.jsonにincludesを追加する場合の注意点

モノリポでサーバー側を別プロジェクト化していて、ファイルを共有する場合にtsconfig.jsonの修正でちょっとはまったので備忘録を残しておきます。

```
project
　packages
　　└　front
　　　　└　tsconfig.json
　　└　server
　　　　└　src
　　　　　　└　shared　// フロント／サーバー共用ファイル置き場
```

※前提として、nuxt.config.tsで`rootDir: 'src',`を指定しています

# はまったこと

tsconfig.jsonに`"include": ["./**/*", "../server/src/shared/**/*"]`を追加したところ、VSCodeで名前解決が出来なくなった

```project/packages/front/tsconfig.json
{
  // https://v3.nuxtjs.org/concepts/typescript
  "extends": "./src/.nuxt/tsconfig.json",
  "vueCompilerOptions": {
    "experimentalDisableTemplateSupport": true
  },
  "compilerOptions": {
    "jsx": "preserve",
    "typeRoots": ["./src/types"]
  },
  "include": ["./**/*", "../server/src/shared/**/*"]
}
```

# 原因

extendsしている`.nuxt/tsconfig.json`でincludeが定義されて入れ、上書きしてしまって型定義ファイル`nuxt.d.ts`のincludeが出来なくなっている

```project/packages/front/src/.nuxt/tsconfig.json
// Generated by nuxi
{
  "compilerOptions": {
    ・・・
  },
  "include": [
    "./nuxt.d.ts",
    "../**/*"
  ]
}
```

# 解決

tsconfig.jsonに`"files": ["./src/.nuxt/nuxt.d.ts"]`を追加し、Nuxtの型定義ファイルを直接読み込むようにする

```project/packages/front/tsconfig.json
{
  // https://v3.nuxtjs.org/concepts/typescript
  "extends": "./src/.nuxt/tsconfig.json",
  "vueCompilerOptions": {
    "experimentalDisableTemplateSupport": true
  },
  "compilerOptions": {
    "jsx": "preserve",
    "typeRoots": ["./src/types"]
  },
  "files": ["./src/.nuxt/nuxt.d.ts"],
  "include": ["./**/*", "../server/src/shared/**/*"]
}

```
API通信確認方法はThunderClientが便利

## なぜ記事を書こうと思ったか
  サービスの開発中にAPI通信が動作してるか確認する必要があった為、API通信確認方法の備忘録として残す為。

## おすすめのAPI通信確認方法
　おすすめのAPI通信確認方法としては、コードエディタにVScodeを利用している場合、VSCodeの拡張機能である「Thunder Client」をおすすめします。昔は「Postman」というサービスがAPI通信確認方法として利用されており、VScodeを使っていない場合は、利用するのもありだと思いますが、「Thunder Client」はVScodeで完結できる為、非常に便利です。

- [Postman API Platform | Sign Up for Free](https://www.postman.com/)

## 「Thunder Client」の導入方法と使い方
- 導入方法(インストールするだけですが笑)
VScodeの拡張機能を開き、以下のThunder Clientをクリックし、インストールを押して下さい。
<img width="1098" alt="スクリーンショット 2022-06-26 18 13 01" src="https://user-images.githubusercontent.com/75520329/175807625-2e8c9446-7da4-4759-ad2a-55338c9e628f.png">

- 使い方
1.拡張機能のマークの下に新しい雷のマークがあるので、クリックして下さい。
<img width="278" alt="スクリーンショット 2022-06-26 18 23 45" src="https://user-images.githubusercontent.com/75520329/175807806-224f469d-d5cc-4498-a116-41c898ed8c32.png">

2.「New Request」を押して下さい。
<img width="233" alt="スクリーンショット 2022-06-26 18 26 05" src="https://user-images.githubusercontent.com/75520329/175807944-5f045e45-abf5-4842-a89c-a9f22fbe3c86.png">

3.検索バーの下にあるHeadersタブをクリックして下さい。
<img width="1391" alt="スクリーンショット 2022-06-26 18 26 44" src="https://user-images.githubusercontent.com/75520329/175807945-4431c960-ebff-499e-9b33-cd3ee65c292a.png">

4.「Raw」のチェックマークにチェックを入れて下さい。
<img width="574" alt="スクリーンショット 2022-06-26 18 31 08" src="https://user-images.githubusercontent.com/75520329/175808100-61414129-32c3-4982-a040-62c1b4a55c30.png">

5.HttpHeadersにいらない情報がある為、全て削除して下さい。

6.HttpHeaderにcookieの値やX-CSRFtokenなど必要情報を入力して下さい。
　もしわからない場合は、API通信できているか確認したいURLに関連するURLをグーグルで表示し、デベロッパーツールを開いて下さい。「Network」タブを開き、⌘+Rを押し、RequestHeaderの中身を全てコピーして下さい。
<img width="1010" alt="スクリーンショット 2022-06-26 19 00 12" src="https://user-images.githubusercontent.com/75520329/175809070-1056df0a-cfa1-443e-b2b3-ac8a18060387.png">

7.コピーした内容をThunderClientのHttpHeaderに貼り付け、検索バーにURLを入力後、Sendをクリックして下さい。
その後、ステータスコードなどが表示されます。
<img width="1153" alt="スクリーンショット 2022-06-26 19 03 45" src="https://user-images.githubusercontent.com/75520329/175809167-ffc18a5d-5262-4335-8a0d-a8ada6620026.png">

## 最後に
　間違っている箇所があれば、ぜひ教えていただけると嬉しいです。
　読んで頂きありがとうございました。
超リアルなスマホ（iOS）のクローンを作る！

# スマホ（iOS）のクローン

## 今回作ったもの（開発中）
[iOSのクローン](https://mf3px.sakura.ne.jp/PhoneClone/#p4)
![20220626_184247.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/471258/6c5ad4a1-6f76-510e-348d-d152859a8144.gif)

## 製作物の特徴
- iOSの特徴を捉えた触れるUI
- YouTubeの簡単なアプリ
- ピアノ（実際に音が鳴ります）
- 投稿掲示板（PHP）
- ロック画面，設定画面
- 通知，アラートの機能
- 下のホームバー（黒色の細長いボタン）をクリックするとホーム画面へ
![JointPics_20220626_190051.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/471258/2fa09870-0f76-05ec-83d7-32bb038c6872.png)


## コードの解説

### HTML
概要は以下の通りです。

```HTML:index.html
<div id= "frame"> <!--フレーム-->
    <div id= "header"></DIV> <!--ヘッダー-->
    <div id= "notice"></div> <!--通知-->
    <div id= "alert" onclick= "closeAlert()"></div> <!--アラート-->
    
    <div class= "screen"></div> <!--スクリーン-->
</div>
```

### CSS
- 今回は省略します。
- 一部のデザインで、SwiperやMaterialize.cssも使用しています。

### JavaScrjpt
- ページ遷移に関しては、[CSSだけで作る簡単SPA](https://qiita.com/masa_mf3/items/512bc7ed652aacd45e5f)をご覧ください。

```JavaScript:JavaScript
// アプリ立ち上げ（ボタンを押した0.3秒後に開く）
function launchApp(hashName, num) {
    setTimeout( ()=> {
        location.hash = '#' + hashName;
    }, 300);
}

// ピアノの音も実際に鳴ります。
function pianoNote(note) {
    document.getElementById('sound-note-'+note).pause();
    document.getElementById('sound-note-'+note).currentTime = 0;
    document.getElementById('sound-note-'+note).play();
}
```

## 最後に
いかがでしたでしょうか。
今回の開発のほとんどがCSSでした。
今後、未開発のアプリも追加していこうと考えています。
読んでくださりありがとうございました！
テスト環境への反映

エラーがデバックをして確認しても永遠と解決されなかったのでググって解決したのでメモ。

マイグレーションファイルの内容を変更した場合

t.integer :content ⇒ t.string :content にしたときは開発環境には反映されてるけどテスト環境には反映されていない場合あり。

つまり、Rspecでテストを実行しても、Rspecではcontentに'content_01'を格納してるけどinteger型のままだからデフォルトで０が入ってしまいエラーが出る　「らしい」＜ここ重要！

正直まだ深掘りできていないところでもあります。

この場合は

```rails db:migrate:reset```
としてdbを削除、作成、migrateをする。

ちなみに

```rails db:migrate:reset```
はrails db:drop, db:create, db:migrateを一気に実行してくれる。
参考　https://qiita.com/pugiemonn/items/e237b73025d8db8545bf
数式を含む英文を翻訳するツールを作った話

## 作ったもの

[DeEqL --- 数式を含む英文を翻訳するツール](https://hooked-on-mas.github.io/DeEqL/)

<iframe width="560" height="315" src="https://www.youtube.com/embed/c2zF_QxhlFM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

使い方などツール自体の詳細は技術的な内容ではないので，Qiitaには載せず[こちら](https://hooked-on-mas.hatenablog.com/entry/2022/06/26/002728?_ga=2.94583961.4439452.1656160964-525354746.1602505894)に書いています．

## 動機

[DeepLは教師あり学習で学習を行っています](https://www.deepl.com/ja/blog/how-does-deepl-work)が，LaTeXコードを含んだ学習データがないのか，
数式を含んでいると上手く翻訳してくれないことが多々あります．
また，LaTeXコードを含んでいる英文を上手く翻訳できても，翻訳結果をコンパイルせずに読み取るのは時間がかかります．
そこで，数式を含んでいても上手く翻訳してくれて，かつコードから数式にコンパイルしてくれるツールが欲しかったので作りました．

## 実装内容

1. 入力されたテキストから数式の部分（`$`または`$$`で囲まれた部分）を検索
2. 検索された数式に対して，以下の処理を行う
    1. 数式に```\left```と```\right```，```{```と```}```のように，二つあって初めて機能する塊を"SWxx"で置換
    2. 数式に```,```または```.```が含まれる場合は，それを区切りとして2つの数式に分割
    3. 数式の部分を"EQxx"で置換
4. 置換後のテキストをDeepLで翻訳
5. 翻訳後のテキストの"SWxx"と"EQxx"の部分を元に戻す

### 「2.3 EQxxへの置換」について

冒頭で述べたように，DeepLは数式を含んでいると上手く翻訳してくれません．
そこで，数式を一度"EQxx"のように記号で置き換えることで，避けるようにします．
DeepLは大文字だけの単語を固有名詞と捉えるのか，英語のまま訳してくれます．

### 「2.2 ```,```または```.```の前後で分割」について

数式内に```,```または```.```がある状態で，その数式を記号として置き換えてしまうと，  
文章の区切りである```,```または```.```が消えてしまい，誤訳に繋がりかねません．  
例えば，以下の文です．
```
$a, b$ denote $A$ and $B$, respectively.
```
この文の数式を"EQxx"によって置換すると
```
EQ00 denote EQ01 and EQ02, respectively.
```
と置き換えられるので，文法の間違いが発生してしまいます．場合によっては，この文法間違いが誤訳に繋がってしまいます．そこで，```,```または```.```の前後で分割すると，
```
EQ00, EQ01 denote EQ02 and EQ03, respectively.
```
となり，正しく翻訳できます．

### 「2.1 SWxxへの置換」について

```\left```と```\right```，```{```と```}```の間に```,```があると，それぞれが別々の数式として分割されてしまいます．例えば，
```
$a_{i,j} denotes an element of matrix $A$.
```
の場合，
```
$a_{i$, $j}$ denotes an element of matrix $A$.
```
と分割されます．ここで，```{```と```}```は数式内にペアとして存在する必要があるため，エラーが生じてしまいます．
そこで，それらをSWxxの形で置き換えると，
```
$a_SW00 denotes an element of matrix $A$.
```
となり，この置換の後であれば「2.2 ```,```または```.```の前後で分割」を行ってもエラーを生じることはありません．

## 今後の課題

- 数式を含むPDFの翻訳
- バグの修正

その他，アドバイス・不具合などあればコメントいただけると，非常に嬉しいです．

## 参考にしたサイト

- [DeepL API Freeを使用して翻訳してみる - Qiita](https://qiita.com/yaju/items/bf4613393cd4ee402d17)

## 関連記事・ツール

#### ツール

- [Shaper | 論文翻訳支援アプリ](https://dream-exp.net/shaper/)
- [英字論文フォーマッタ](http://to-normal-code.herokuapp.com/to-normal-code)
- [Readable](https://readable.joisino.net/)

#### ツール作成記録

- [英語論文をフォーマットして翻訳する方法](https://qiita.com/satto_sann/items/7d4c8c6ec6fd761c4e54)
- [Google翻訳とPythonを使ってPDF論文を一発で翻訳する](https://qiita.com/kimisyo/items/916f58ac6571815851ff)

#### ツール集・組み合わせ

- [英語論文読みを爆速にする、超便利ツール集](https://qiita.com/bezilla/items/774d4c2c4564053f6445)
- [あなたはまだ英語論文を読む最良の方法を知らない](https://qiita.com/renesisu727/items/aa8925cf35d8a5c2ec39)
設計書の表記で感じた違和感

すごく違和感がある設計書の表記方法に出会ったので、
書いてみます。
特に技術的な内容ではありません。

違和感のある設計書の表記方法
※あくまでイメージです。

1 Aテーブルの取得
　　Aテーブルのデータを取得する。
　 　(1)取得件数が1件の場合は2を行う。
　 　(2)取得件数が1件以外の場合は3を行う。

2 〇〇処理
　 〇〇処理を行う。

3 △△処理
　 △△処理を行う。

基本的に現代のプログラミングは、構造化プログラミングの思想に従っているので、上記のようにジャンプされると、混乱を招いてしまうと感じました。
この場合だと、「1(1)で2の処理を行って、3の処理はするのだろうか？」
という疑問がでてきてしまいます。

自分なら下のように書きます...

1 Aテーブルの取得
　 Aテーブルのデータを取得する。

2 〇〇処理
　 Aテーブル検索結果が1件の場合、　　
　 〇〇処理を行う。

3 △△処理
　 Aテーブル検索結果が1件以外の場合、
　 △△処理を行う。


些細なことかもしれませんが、気になったので書いてみました。
今の現場で、最初のような表記をする方が一定数おり、
違和感を覚えている今日このごろです。
NotImplementedError: The operator 'aten::_slow_conv2d_forward' is not current implemented for the MPS device.

# エラー

MacBook上でGPUを使用してPytorchが使用できるようになったので試していたところ、以下のエラーが発生

```bash
NotImplementedError: The operator 'aten::_slow_conv2d_forward' is not current implemented for the MPS device.
```


pytorch(mps)のエラーはここにまとまっている

[General MPS op coverage tracking issue](https://github.com/pytorch/pytorch/issues/77764)

要するにまだ`Conv2d`は使用できないらしい。画像処理がほぼ封じられた形になる....

実用できるのは当面先になりそうか、、、
Apache SupersetでSSO Googleログインを設定

BIツールって高いので、とりあえずBIツール導入したいなら、サーバー代だけで導入できる[Superset](https://superset.apache.org/)が良い選択肢になると思います。そこで、会社で使う場合はSSOができると便利だと思います。Google Workspaceを使っているところも多いと思うので、GoogleでのSSOログインの設定方法のご紹介です。ドメインによる制限もかけられるようにしています。

# はじめに

まずドーン　[完成品](https://github.com/takezoux2/superset-with-sso)
SSOの設定してdocker-composeで一発起動にしています。サーバーで動かしたい場合も、そのまま使えます。ただ動かしたいだけなら、レポジトリのReadmeに添って動かして貰えばと思います。
この記事では、SSOの設定は基本は[公式ドキュメント](https://superset.apache.org/docs/installation/configuring-superset#custom-oauth2-configuration)に準じていますが、そのままだといくつもハマりポイントがあり動かないので、ハマったポイントをご紹介していきます。

# 1. superset_config.py

## AUTH_TYPE=AUTH_OAUTH

`AUTH_TYPE`に`AUTH_OAUTH`を設定します。公式だと、AUTH_OAUTHだけ書かれていてコピペするだけだとエラーになります。このエラーを無くすにはimportが必要ですが、初めて使うのにどこimportしろって感じです。
なので、ファイルの冒頭に
```python
from flask_appbuilder.security.manager import AUTH_OAUTH
AUTH_TYPE=AUTH_OAUTH
```
を追加しましょう

## OAUTH_PROVIDERS 

こちらもサンプルコピペでは動きません。SSOで使う対象の設定に合わせる必要があります。

* `name`をわかりやすいものに変える
* `client_id`,`client_secret`は自分のアプリの設定に変更
* `client_kwardgs`はSSOの対象によって違うので、後述のSecretManagerで必要になるパラメーターを取得できるscope設定をしてください。
* `xxx_url`ここもSSOの対象によって変わります。oauth系のライブラリのソースコード覗いて確認するのが早いかもです。

## AUTH_USER_REGISTRATION_ROLE

こちら、SSOで作成されたユーザーのデフォルト権限になります。サンプルは`Public`なので、そのままだとDashboardなどを見ることしかできないユーザーが登録され、誰もAdminへの昇格ができなくなります。
なので、初期は`Admin`で起動し管理者ユーザーを作成し、その後`Public`にしておきましょう。全員管理者で良いなら`Admin`のままでも良いですがｗ

## authlib

地味にドキュメントにはauthlibいるよと書かれています。これがないと動かないので、
```
pip install Authlib
```
を忘れないようにしてください。私のサンプルでは、`Dockerfile`内でinstallしています。



# 2. SecurityManager

ここで、OAuth Providerからユーザー情報の取得と、ドメインのチェックをしています。
ドメインチェックは公式ドキュメントには無いので、会社で使う際の参考にしてください。
[サンプル - custom_sso_security_manager.py](https://github.com/takezoux2/superset-with-sso/blob/master/config/custom_sso_security_manager.py)

## ユーザー情報の取得

SSOは、認証しAccessTokenの取得までは勝手にやってくれますが、ユーザー情報の取得はSSOの対象によって違っているため、独自に書く必要があります。
やっていることは、最終的にOAuthのuserinfoエンドポイントを叩いて、その情報からSupersetの登録に必要な情報を取り出しているだけになります。

## ドメインのチェック

Googleの場合、ドメイン情報がuserinfoエンドポイントから取得できるようになっているので、そのチェックも入れています。会社のGoogle workspaceのドメインのみ許可するようにしておけば、会社のアカウントを持っていない人は登録できなくなります。部外者がアクセスしてきても会社のGoogleアカウント持っていないと入れなくなるので、とりあえず使う際のセキュリティとして十分だと思うので、ご活用下さい。

## superset_config.pyへ設定

SecurityManagerを作ったら設定に反映が必要です。
superset_config.pyと同じディレクトリにファイルを置き
```python
from custom_sso_security_manager import CustomSsoSecurityManager
CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager
```
を設定してください。

# 注意

* AWSのGravity系のCPUのインスタンスではsupersetのDocker imageが対応しておらず、docker-composeがビルド失敗します。


# おわりに

以上がざっくりとした、設定の注意点です。

一般のBIツールは最低導入コスト200万円/年ぐらいは必要になって来ます。また、人数によって使用量も線形に増えていき、安くてViewerのライセンスだけでも月額2000円/人、Exploreクラスになると5000円/人程度は必要になってきます。そのため、PoCを行い、会社の説得、契約、社内への浸透をしていかないと行けないので、大変な道のりになると思うのでとりあえずBIツール入れてみたいならSupersetを使ってみても良いと思います。

ただし、やはり商用のBIツールのほうが、機能などが充実している＋サポートの料金も込みとなるので、非エンジニアも使うことを考えると商用のものを導入する選択肢は消すべきではないと思います。
【合格体験記】AWS SAA(C02)に合格するまでにやったこと

## はじめに
今日は、AWS SAA(C02)に合格したので、それまでにやったことをまとめます📝

## 前提
勉強を開始する前の状態は以下です。
- バックエンドエンジニア 2年半
- アプリケーションエンジニアとして、ECS,S3,RDSに関する最低限の知識はある状態
- ここ1,2ヶ月前からインフラ設計構築も担当し始める
- 2年半、すべてAWS環境で開発していたが、ガッツリ設計したことはない

## 学習時間
計100時間くらいです。

## 受験しようと思った経緯
大きく2つあります。
- エンジニアリングをする中で、アプリケーションレイヤーよりもインフラレイヤーで解決できそうな要件を実装することが多くなった
- SRE,DevOpsに興味があって、バックエンドエンジニアの幅を超えた業務を担当してみたくなった

おまけに会社から受験料が出るので、所属しているうちに受けてみようかなと！

## やったこと
#### AWS認定資格試験テキスト AWS認定 ソリューションアーキテクト-アソシエイト
- オレンジ本と言われている書籍を1周しました。
- 正直、全部は覚えていないですが、後で紹介する模擬試験でわからない部分を辞書的に検索して、暗記するようにしていました。

[amazonより](https://www.amazon.co.jp/dp/479739739X/ref=cm_sw_r_tw_dp_60YGYA8CCMA5RFG0P18F)

#### これだけでOK！ AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座
- こちらをメインで学習していました！とても勉強になりましたが、**46時間**は長い...笑
いわゆる普通のクラウドインフラ環境で仕事をしているので、オンプレミスとの接続、別アカウントとの連携、大規模アクセス対応等をハンズオン形式で学べてよかったです！
- セキュリティ、パフォーマンス改善等はアプリケーションエンジニアも意識すると思いますが、インフラレイヤーで解決できることもたくさんあるので、是非受験するかに関わらず見てほしいです！(ただ46時間は長い...)
- 模擬試験が3回付いていて、10日前解きました。

##### 模擬試験の結果
|模擬試験| 正答率| 合否 |
|--|--|--|
|1 | 75％ | 合格 | 
|2 | 73％ | 合格 |
|3 | - | - |

※3は事項で実施の模擬試験1と同じのためスキップ

[udemy](https://www.udemy.com/course/aws-associate/)

#### AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集（6回分390問）
- ひたすら問題を解きました。個人的に、問題慣れが合格のコツだと思います！
- 今は動くかわかりませんが、適当にスクリプトを書いて、間違えた問題だけ抽出して再度解いていました！

```javascript
document.querySelectorAll('.mc-quiz-question--container--3GZ4h').forEach(e => console.log(e.children[0].innerHTML + e.children[1].innerHTML))
```

##### 模擬試験の結果
|模擬試験| 正答率| 合否 |
|--|--|--|
|1 | 78％ | 合格 | 
|2 | 67％ | 不合格 |
|3 | 64％ | 不合格 |
|4 | 72％ | 合格 |
|5 | 72％ | 合格 |
|6 | 78％ | 合格 |

[udemy](https://www.udemy.com/course/aws-knan/)

#### AWS認定試験【ソリューションアーキテクトアソシエイト試験対策】
- これはおまけです。黒川さんのYoutubeのプレイリストです。
- スキマ時間や会社での休憩時間に1周しました。

[Youtube](https://youtu.be/c89BR3PQuI0)


## 結果
- 788点でした🙌
- 模擬試験で合格点が取れていれば、合格できるってことですかね！

![スクリーンショット 2022-06-26 16.41.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573011/df28d465-b327-abd8-2424-9a44be992e98.png)


## まとめ
- 数時間、数週間で合格とかいうブログが散見されるので、簡単な試験かと思ってましたが、私には結構難しく感じました...
- 試験への学習を通じて、実務で使えそうな知識を身につけることができたのが一番の収穫です！
- 資格を持っていると会社で自信を持って発言できるようになるので、まあお守りみたいなもんですね🐶
【Laravel×graphql(lighthouse)】アクセサの値を取得する際のアクセサが実行されるタイミング

## テーブル定義
```php: table
users
    id - integer
    first_name - string
    last_name - string
```

## アクセサの定義
```php: App/Models/User.php

/**
 * ユーザーのフルネームの取得
 *
 * @return string
 */
public function getFullNameAttribute()
{
    return "{$this->first_name} {$this->last_name}";
}
```

## タイプ
```graphql: User.graphql
type User{
  id: ID!
  first_name: String!
  last_name: String!
  fullName: String! ## キャメルケースでもスネークケースでも対応できる
}
```

## リゾルバ

```php: App/GraphQL/Queries/User.php
/**
* @param  null  $_
* @param  array<string, mixed>  $args
*/
public function __invoke($_, array $args)
{
  $users = User::get();
　　　　return $users;
}
```

## 実行タイミング
- 取得処理を実行後toArrayを行う
```php
User::get()->toArray();
```
-　取得処理を実行後対象の値を使用
```php
$user User::first();
$user->fullName;
```
- graphqlのデータ取得時
```graphql
query user{
  id
  first_name
  last_name
  fullName ## こちらを取得しようとしなければアクセサは実行されない
}
```

## 注意事項
- graphqlでのデータ取得時にはレコードごとにModelが実行される
例えば、アクセサにAPIのデータ取得処理や、重い処理を実装していた場合、get()やall()などで複数データを一気に取得する際、実行がレコード数になってしまうとレスポンス速度の低下が発生します。
graphqlでの取得時に対象のデータを取得しようとすると、レコードごとにModelが実行されるため以下のような処理を実行してもレコード分実行されてしまいました。
```diff_php: App/Models/User.php
+ public fullNames;
/**
 * ユーザーのフルネームの取得
 *
 * @return string
 */
public function getFullNameAttribute()
{
+   if(isset($this->fullNames[$this->id])){
+     // すでにfullNamesに値が存在したらデータをそのまま返却する
+     return $this->fullNames[$this->id];
+   }
    return "{$this->first_name} {$this->last_name}";
}
```

```diff_php: App/GraphQL/Queries/User.php
/**
* @param  null  $_
* @param  array<string, mixed>  $args
*/
public function __invoke($_, array $args)
{
+ // 先に必要なデータを取得して、ModelのfullNamesにセット
+ User::fullNames = $this->getFullNames();
  $users = User::get();
　　　　return $users;
}
```

## 対応策
ここからは上記のようなことが発生した際に自分が実装した対応策になります。
※　もっとうまい回避方法がある気がするのですが、一旦このような方法で実装しました。(有識者の方良い方法があればご教授いただければと思います。)
こちらの方法だと、リレーション先の取得などが使用できなくなるため必要な場合は、Arrayの中に含めて上げる必要があります。

```diff_php: App/GraphQL/Queries/User.php
/**
* @param  null  $_
* @param  array<string, mixed>  $args
*/
public function __invoke($_, array $args)
{
  $users = User::get();
+ //usersテーブルのカラムリストを取得
+ $columns = Schema::getColumnListing('users');

+ $userArray = [];

+ foreach($users as $key => $user){
+   // Userでの取得を単純な配列に変換(toArrayを使用するとそのタイミングでアクセサがレコードごとに実行されてしまうため注意)
+   foreach($columns as $column){
+     $userArray[$key][$column] = $user[$column];
+   }
+   $userArray[$key]['fullName'] = $userFullNames[$user->id];
+ }

-　　return $users;
+ return $usersArray;
}
```
【javascript】Reactでhtmlタグを取り除いて、文字だけ抽出する方法

## 背景
microCMSのapiで取得したhtmlで抜粋を作りたかったがhtmlタグが邪魔で文字数カウントができなかったので、
htmlタグをなくした文字列を取得したかった。
正規表現の記事ってあまり多くないので、他の方がCMSで文字列だけ抜き出したい！って時に役立つかなと思い初投稿してみました。

## match()メソッドを使う
### match()メッソドとは
正規表現に一致するものを配列で返す。

例：
```
const hoge = <p>来週の月曜日には、数量限定のグリーンビーンズの発送を予定しています。火曜日からローストビーンズを提供し ますが、数量に限りがありますので、お早めに。<br>
hoge.match(/。/g)
// 結果⇒["。","。"]
```
最後のgはオプションで、マッチしたすべての文字を返します。
(はじめ入れ忘れていて、先頭しかマッチしなかったなんて言えない…)

## コード
```
const hoge = <p>あ<br><br>か<br>い</p>
hoge.match(/[^\<\>]+(?=\<[^\<\>]+\>)|[^\<\>]+$/g);
// 結果⇒["あ","か","い"]
```

## 解説
正規表現の**肯定先読み**を使っています。
肯定先読みはある条件にマッチした前を見て、その前の文字列がもう一つの条件と一致するか判定します。

例えば　ある文字列の中で`javascript`の中の`script`を抜き出したいとすると
```
java(?=script)
```
となります。

これを<>で囲われたHTMLタグに応用すると

* マッチしたい文字列⇒ `[^\<\>]` (">","<"以外の文字列)
* 除外したい文字列⇒ `\<[^\<\>]+\>` ("<>"で囲われた文字列)


**肯定先読みの部分**
↓
```
[^\<\>]+(?=\<[^\<\>]+\>)
```
`+`は前の表現が一回以上繰り返す場合マッチするものです。

要するに、

まず

#### "<>"で囲われた文字列を探して

その後、
#### ">","<"以外の文字列が１回以上続いている箇所を検索

しています。

その後ろの
```
|[^\<\>]+$/g
```
は`|`は「または」という意味で
`$`は直前の表現が文字列の末尾にある場合マッチするもので

要するに、">","<"以外の文字列が文字列の末尾にあったらマッチするものです。

## 終わりに
初めての投稿でしたが、意外と時間がかからずかけました。

もし読んでくれた方で、わかりずらかったり、間違ってるところがあったらコメントで教えてい抱けると助かります。

正規表現は難しいですが、慣れてくると正規表現なしだと面倒になることも多いので、
億劫にならずに使う部分では、使っていきたいです。
[SELinux]無効化しているサーバでは有効化するには再起動が必要？

## 現在の状態

selinuxは無効になっています。

```
[root@localhost ~]# getenforce 
Disabled
```

## 無効化状態ではsetenforceコマンドでは変更できない

Disabled(無効化)状態ではsetenforceコマンドは無効化しているからってことで通らなかったのです

```
[root@localhost ~]# setenforce 0
setenforce: SELinux is disabled
```

```
[root@localhost ~]# setenforce 1
setenforce: SELinux is disabled
```

## 設定ファイルの変更

大人しく設定ファイルの変更をします。

```
vi /etc/selinux/config 
==========
SELINUX=disabled
↓
SELINUX=enforcing
==========
```

```
[root@localhost ~]# reboot
```

有効化されました。

```
[root@localhost ~]# getenforce 
Enforcing
```

## selinuxのログの話

SELinuxのログは `/var/log/audit/audit.log ` に出されています。
enforcing または、permissive の際の許可したログ等はこちらに吐き出されています。

## 勉強後イメージ

無効化→一時有効化は出来ないからrebootしないといけないのか。
特に稼働しているサーバではちょくちょく変えるのは難しいから決めておかないといけない。
LPIC 201 合格体験記

この記事ではLPIC 201の取得にあたっての流れや学習方法を紹介します。
LPICレベル１と比べると201は多少難易度が上がるものの、基本的にはレベル１と同様の学習方法で進めました。
LPIC101合格体験記：https://qiita.com/takasho9321/items/99099648631c06f3b52b
LPIC102合格体験記：https://qiita.com/takasho9321/items/b89f3cc5f21ccee9033f

# 目次
- [受験の経緯](#受験の経緯)
- [学習に使った教材](#学習に使った教材)
- [学習の期間と流れ](#学習の期間と流れ)
- [ping-tを2周して知識をインプット](#ping-tを2周して知識をインプット)
- [スピマスの問題集を2周実施](#スピマスの問題集を2周実施)
- [ping-tの模擬試験を実施](#ping-tの模擬試験を実施)
- [試験前日にスピマスの模擬試験を実施](#試験前日にスピマスの模擬試験を実施) 
- [本番試験](#本番試験)
- [試験の感想](#試験の感想)
- [教材のリンク](#教材のリンク)

# 受験の経緯
- Linuxの知識を獲得する為

# 学習に使った教材
- ping-t 問題集
- スピマス
- 実機でコマンドの動作確認

# 学習の期間と流れ
**1. 学習期間**
2021年10月上旬～2022年10月下旬


**2. 学習の流れ**

| 開始日 | 終了日 | 学習内容 |
|:-----------|:------------|:-----------------------------------------------------------|
| 2021/10/10  | 2021/10/21  | ping-tの最強WEB問題集を2周 　　　　　　　 |
| 2021/10/21  | 2021/10/21  | ping-tの模擬試験を1回　　　　　　　 |
| 2021/10/21   | 2021/10/22   | スピマスの問題集を2周         |
| 2021/10/22  | 2021/10/22   | スピマスの模擬試験を1回      |
| 2021/10/23   | 2021/10/23   | 本番試験で合格      |

# ping-tを2周して知識をインプット
ping-tの最強WEB問題集を2周やりました。
LPICレベル１と同様に知識の積み上げを目的として活用しました。
1周目の全体的な正答率は59%でした。
とにかく分からない用語はネットでググって理解を深めました。
それでも理解できない場合は、AWS上にEC2インスタンスのLinuxサーバを立ててコマンドの出力結果を確認しながら理解を深めました。
実機でコマンド叩いて実際の挙動を確認するのはイメージがつきやすくは覚えやすいと個人的に感じました。
2周目の正答率は73%とまずまずの正答率でしたが、体感の理解度は高く合格できる見込みはあると感じてました。

# ping-tの模擬試験を実施
模擬試験の正答率が95%とかなり高かった為、3日後に試験を申し込みました。
残り3日でスピマスの問題集と模擬試験を実施して試験に臨みました。

# スピマスの問題集を2周実施
正答率は63%ですが、これまでのLPICの学習の中ではスピマスの正答率が一番高かったです。
LPICレベル１同様に体感だと本番試験よりも難易度が高いと感じました。
スピマスの問題が試験にそのまま複数出題されたのでスピマスの問題集を最低でも1周実施しておくことを強くお勧めします。

# 試験前日にスピマスの模擬試験を実施
試験前日に最終確認としてスピマスの模擬試験を実施しました。
正答率は76%とかなり高かったです。
その為、正答率が6割超えていれば確実に合格できるかと思います。

# 本番試験
そしていよいよ本番試験。
択一式の問題がメインで、記述式の問題は8問ぐらいでした。(2021/10/23 時点)
ベンダー系の資格特有ですが問題文をちゃんと翻訳してくれないので分かりにくい部分は英語に直して読むといった工夫も必要になります。

個人的な体感の正答率は7割くらい。
結果は630点で正答率は7.8割と余裕を持って合格出来ました。

# 試験の感想
ping-tに比べると実際の試験問題の方が難易度が少し高いですが、スピマスと比べると難易度は低く感じました。
また、模擬試験の正答率がLPICの学習してきた中で正答率が一番高かったですが、試験の点数は一番低かったのでレベル２になって試験の難易度が少し上がったと感じました。
とは言えping-tとスピマスの内容が理解出来ていれば十分に合格できると感じました。
各コマンドや単語をきちんと理解しておくことが重要になります。
少しでも学習の参考になれば幸いです。

# 教材のリンク
ping-t：
https://ping-t.com/

Linux教科書 LPICレベル2 スピードマスター問題集 Version4.5対応 単行本（ソフトカバー）：
https://www.amazon.co.jp/Linux%E6%95%99%E7%A7%91%E6%9B%B8-LPIC%E3%83%AC%E3%83%99%E3%83%AB2-%E3%82%B9%E3%83%94%E3%83%BC%E3%83%89%E3%83%9E%E3%82%B9%E3%82%BF%E3%83%BC%E5%95%8F%E9%A1%8C%E9%9B%86-Version4-5%E5%AF%BE%E5%BF%9C-%E6%9C%89%E9%99%90%E4%BC%9A%E7%A4%BE%E3%83%8A%E3%83%AC%E3%83%83%E3%82%B8%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3/dp/4798151238/ref=pd_vtp_sccl_2_7/357-9086819-6362746?pd_rd_w=iaqpI&content-id=amzn1.sym.cbb45385-7b99-44b7-a528-bff5ddaa153d&pf_rd_p=cbb45385-7b99-44b7-a528-bff5ddaa153d&pf_rd_r=T73P4S04BP758H25DFYC&pd_rd_wg=WjC4J&pd_rd_r=8cdc3748-faa0-44c4-b924-ef8dfb6f4982&pd_rd_i=4798151238&psc=1