OmniAICreator/Qiita-1.07M huggingface dataset:
テストに関わる基礎知識

「知識ゼロから学ぶソフトウェアテスト 【改訂版】」を読んでの自分用メモです。気になったところだけ箇条書きにしています。


# ホワイトボックス手法
この手法は全てのソフトウェアテストの基礎となるもので、ソフトウェアテストの黎明期に盛んに研究された手法。これからも使う予定はないかもしれないがテスト手法の基礎を学んでおくことは非常に重要です。

ホワイトボックステストとは、**プログラムの論理構造が正しいかを解析するテスト**。


# どんなテスト手法が有効か
ホワイトボックステストは論理構造の正しさのみをテストするため、ソフトウェアの使用が間違っていることから起こるバグは発見できない。

ステートメントカバレッジは、全く役に立たないとまでは言わないが、非常に弱いテスト手法。

# 分岐のコードをチェックするテスト手法とは
ステートメントカバレッジでは、分岐条件の全てはカバーできない場合があります。そこで、より強力なカバレッジ手法である**ブランチカバレッジ**というものがあります。
ブランチカバレッジは、分岐コードに対してそれぞれの判定条件がTRUE、FALSEの結果を少なくとも一回ずつ持つようにテストケースを書きます。
網羅するという意味ではステートメントカバレッジより強いのですが、テストケースの数がかなり増える点が問題です。全てのソフトウェアに対して完全にブランチカバレッジを遂行するのは大変ですが、ブランチカバレッジをプログラム全体に対して使用しなくとも、十分な成果が得られることが証明されているからです。たとえばプログラムの全体からある部分をサンプリングし、ブランチカバレッジテストを実行してみることもできます。それによってプログラム全体の品質がある程度想像できるはずです。
なんですが、カバレッジテストは非常にコストがかかるテスト手法です。

**TDDの基本**
赤→緑→リファクタリング

赤…小さい動作しないテストを書く
緑…テストを通すコードを書く
リファクター…重複したコードの削除

まずテストが通るコードをどんな汚い形でも最小限の時間で実装できるものを書く。そしてそれをきれいに真っ当な形に成型するというのがTDDのリファクタリングです。（テスト担当者にはリファクタリングの知識は必要ない。なのでソースコードをきれいにしてメンテナンスしやすくするぐらいに理解しておけばいい）

# ブラックボックステストの基本
--同値分割法と境界値分析法--
同値分割法と境界値分析法とボックステストのなかでも基本中の基本であり、もっともよく使われる手法です。入力処理そして出力処理をソフトウェアが適切に行っているかをテストするのが同値・境界値テストです。

同値分割法
同値分割法とは、入力領域を「同値クラス」という部分集合に分割し、その部分集合に入る入力値を等価と見なす作業です。さっそく簡単な例をもとに説明しましょう。

<要求仕様>
入力A:1から999まで入力可能
入力B:1から999まで入力可能
出力C:A×B

これを（テストするとなった場合）考えなければならないのは、どのような数を入力すべきかです。そのために、まず入力値を二つの部分集合に分ける必要があります。一つは有効同値、もう一つは無効同値です。有効同値とはプログラムが期待する入力値です。今回の例では、入力A,Bともにプログラムは1から999が入力されることを期待しているので、有効同値は1から999です。無効同値はそれ以外のあらゆる値ということになります。（~0、1000~)

境界値分析法
同値分割法とセットで使われる。プログラムで「境界」と呼ばれる場所は常にバグが潜んでいるので、境界値近くは詳しくテストする必要があります。先ほどの例だと、1と999の周りの数値は非常にバグになりやすい入力値です。なぜならプログラム上は無効同値と有効同値の間に必ず条件文が必要になり、その分が正しくかけていないことあり得るためです。

**状態遷移テスト**
状態遷移テストとは、要は「状態」をモデル化してテストを行う手法といえます。まず、状態遷移は、大きく分けて状態と遷移の二つによって表現されます。
たとえば、あるアプリケーションが立ち上がっている状態を「状態A」とし、立ち上がっていない状態を「状態B]とします。状態Aから状態Bに移行するためにはアプリケーション終了遷移を経る必要があります。
状態遷移テストで見つかるバグ
・期待していない状態に遷移するバグこれは、分岐やswitch文が正しく書かれていない可能性がある
・遷移自体がない場合
このため、ある状態からある状態に遷移できないバグを発見できる

# 探索的テスト
…テスト手法の一つで、ソフトウェア機能を学習しながら、テスト設計とテスト実行を同時に行う。

探索的テストタスクの実行は五つに分けることが可能です。

1.ターゲットソフトウェアを決める
どれをテストするか決めること

2.機能をリストアップする
テストするべき機能をリストアップします。たとえば、
すべてのヘルプをチェック
すべてのメニューをチェック
すべてのデータ、インターフェイス、ウィンドウをダブルクリック

3.弱いエリアを見つける
ここでは危なそうな機能や操作をリストアップします。　
例：あまり使わない複雑に組み合わさったデータ入力をハンドルする機能
オペレーティングシステムにサイズが依存する機能（メモリが少ない状態、サイズの大きいファイル）

4.各機能のテスト及びバグの記録
上記の視点で各機能に対してテストを実行し、もし問題があればバグの報告を実施します。

5.継続的なテストの実行
例：もしそのソフトウェアがさまざまな環境で動作するのなら、環境を変えてテストを行う

<br>

**品質特性**とは「ソフトウェアが持つべき特性」で、機能的な側面と非機能的な側面の両方の属性を示したものです。
テストで重要な特性は機密性、信頼性、パフォーマンス。


**パフォーマンステスト**とは、ソフトウェアを設計もしくは企画する段階で設定されたソフトウェアの性能が期待された通り出ているかをチェックするためのテストです。
.NET4から.NET3.5のDLLを参照したときの挙動

## 構成
■プロジェクト1
対象のプラットフォーム：.NET Framework4
出力の種類：Windowsアプリケーション
プロジェクト2を参照設定する（プロジェクト2のDLLを参照しても結果は同じ）
■プロジェクト2
対象のプラットフォーム：.NET Framework3.5
出力の種類：クラスライブラリ

## 最初の想定
プロジェクト1では.NET4として動作し、プロジェクト2では.NET3.5として動作する。

## 検証
ハイフンに対するstring.IndexOfの挙動が.NET4と.NET3.5で異なるのでこれを使ってみた。

https://stackoverflow.com/questions/11467424/somestring-indexofsomestring-returns-1-instead-of-0-under-net-4


```C#:サンプル
string text = "\xAD\x2D";
int ret = text.IndexOf(text);
MessageBox.Show(ret.ToString());
```
上記を実行すると、.NET4の場合「1」が表示され、.NET3.5の場合「0」が表示される。


```C#:プロジェクト1namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var obj = new ClassLibrary1.Class1();

            string text = "\xAD\x2D";
            int ret = text.IndexOf(text); // ここでは「1」が取得される
            MessageBox.Show(ret.ToString());

            int ret2 = obj.GetIndex();
            MessageBox.Show(ret2.ToString());
        }
    }
}
```

```C#:プロジェクト2
namespace ClassLibrary1
{
    public class Class1
    {
        public int GetIndex()
        {
            string text = "\xAD\x2D";
            int ret = text.IndexOf(text); // ここでは「0」が取得されると思っていたが「1」が取得される
            return ret;
        }
    }
}
```

こうすれば、メッセージボックスは「1」「0」と表示されると思っていた。
けれども、実際には「1」「1」と表示される。

もちろんプロジェクト1の「対象のプラットフォーム」を「.NET Framework3.5」にすると
「0」「0」と表示される。

なんか壮絶に勘違いしてる模様 orz
rbenvでRubyをインストールしようとしてエラー

# rbenvでRubyをインストールしようとしてエラー

## 解決方法
```sh
brew install libyaml
```

## 発生したこと
rbenvでRubyをインストールしようとしてエラーになった。
以下のコマンドでRubyのインストールに挑戦

```sh
$ rbenv install 3.2.1
```


遭遇したエラー
```
To follow progress, use 'tail -f /var/folders/y6/8gm9y_b52xqd96_wyt_6vcph0000gn/T/ruby-build.20230318222613.14477.log' or pass --verbose
Downloading openssl-3.0.8.tar.gz...
-> https://dqw8nmjcqpjn7.cloudfront.net/6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
Installing openssl-3.0.8...
Installed openssl-3.0.8 to /Users/{UserName}/.rbenv/versions/3.2.1

Downloading ruby-3.2.1.tar.gz...
-> https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.1.tar.gz
Installing ruby-3.2.1...
ruby-build: using readline from homebrew

BUILD FAILED (macOS 13.0 using ruby-build 20230309)

Inspect or clean up the working tree at /var/folders/y6/8gm9y_b52xqd96_wyt_6vcph0000gn/T/ruby-build.20230318222613.14477.tKd9DC
Results logged to /var/folders/y6/8gm9y_b52xqd96_wyt_6vcph0000gn/T/ruby-build.20230318222613.14477.log

Last 10 log lines:
	Check ext/psych/mkmf.log for more details.
*** Fix the problems, then remove these directories and try again if you want.
Generating RDoc documentation
/private/var/folders/y6/8gm9y_b52xqd96_wyt_6vcph0000gn/T/ruby-build.20230318222613.14477.tKd9DC/ruby-3.2.1/lib/yaml.rb:3: warning: It seems your ruby installation is missing psych (for YAML output).
To eliminate this warning, please install libyaml and reinstall your ruby.
uh-oh! RDoc had a problem:
cannot load such file -- psych

run with --debug for full backtrace
make: *** [rdoc] Error 1
```
リストで指定要素を先頭に持ってくる（メモです）

リストで指定要素を先頭に持ってくる方法の一つです。マイメモとしてアップします。
```python:
from itertools import chain
import time
s = time.perf_counter()
x = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
q = 'g'
assert q in x
qi = x.index(q)
print(qi)
y = x[qi],x[:qi],x[qi+1:]
print(y)
z = list(chain.from_iterable(list(y)))
print(z)
e = time.perf_counter()
print(e -s)
```
結果
6
('g', ['a', 'b', 'c', 'd', 'e', 'f'], [])
['g', 'a', 'b', 'c', 'd', 'e', 'f']
0.00038519999998243293

終わり
PythonのSubProcessでPythonファイルを実行する

少し苦戦したのと、古い情報が多かったので備忘録として
# 方法
他のコマンドを実行するときと同様`subprocess.run()`を利用する。
以下、`subprocess.run()`が書かれたPythonファイルと同階層の`a.py`を実行する場合のプログラムを示す。また、各モジュールの`import`は省略する。
```Python
subprocess.run("Python3 a.py",shell=True)
```
`shell=True`がないとPythonインタプリタへのパス(環境変数)が通っていない状態なので、`shell=True`なしでやる場合には`Python3`の代わりにインタプリタへのパスを直接渡す。
sysモジュールの`sys.executable`には、インタプリタへの絶対パスが入っているので、これが利用できる。
```Python
subprocess.run([sys.executable,"a.py"])
```

ちなみに、先程書いたように`shell=True`なしではインタプリタへのパスが通っていないので、
以下のプログラムは実行するファイルが見つからずにエラーになる。
```Python
#エラー
subprocess.run(["Python3","main.py"])
```
psycopg2 で並行処理でSQLを実行する。

# 1. 実行環境

・PostgreSQL => 13.1
・Python => 3.10.5
・psycopg2 => 2.9.3

# 2. 実装

今回は逐次処理と並行処理でそれぞれpostgres側にsleepの処理を実行して、処理が終了するまでの時間を比較していきたいと思います。
（実用的ではないのはご了承ください）

```python:single.py
import pandas as pd 
import psycopg2
import datetime as dt

def sample_func_1(num):
    DSN = '接続情報'

    # num秒待つSQL。
    sql = """
            SELECT pg_sleep(%(num)s) ;
          """
    try:
        with psycopg2.connect(DSN) as conn:
            with conn.cursor() as cur:
                cur.execute(sql, {'num':num})
                print("done : ", num)
    except Exception as e:
        print(e)

def main():
    start = dt.datetime.now()
    sample_values = list(range(10))
    for v in sample_values:
        sample_func(v)
    print(dt.datetime.now() - start)
    
if __name__ == '__main__':
    main()
```
~~~
実行結果
done :  0
done :  1
done :  2
done :  3
done :  4
done :  5
done :  6
done :  7
done :  8
done :  9
0:00:45.949056
~~~

```python:multi.py
import pandas as pd 
import psycopg2
import threading
import datetime as dt

def sample_func_3(num):
    DSN = '接続情報'

    # num秒待つSQL。
    sql = """
            SELECT pg_sleep(%(num)s) ;
          """
    try:
        with psycopg2.connect(DSN) as conn:
            with conn.cursor() as cur:
                cur.execute(sql, {'num':num})
                print("done : ", num)
    except Exception as e:
        print(e)

def main():
    start = dt.datetime.now()
    sample_values = list(range(10))
    with ThreadPoolExecutor(max_workers=3) as pool:
        pool.map(sample_func_3, sample_values)
    print(dt.datetime.now() - start)
    
if __name__ == '__main__':
    main()
```

~~~
実行結果
done :  0
done :  1
done :  2
done :  3
done :  4
done :  5
done :  6
done :  7
done :  8
done :  9
0:00:18.342594
~~~

# 3. 結果
single.pyの結果が約45秒、multi.pyの結果が約18秒で処理時間が1/2以上速くなりました。
きちんと並行処理の恩恵を受けられていると思います。

しかしpostgresサーバに処理を投げているので、複雑な処理を同時に実行しようとするとpostgresサーバに負荷が掛かってしまいます。
なので単にスレッド数を増やせばいいというわけではなくなってくると思います。
GPT-3を使ったシェルスクリプトでコミットメッセージ作成を自動化しよう！

## はじめに
コミットメッセージって大切ですよね。
とはいえ毎回考えるの面倒じゃないですか？特に英語で書かなきゃいけない場合とかは考える手間がかかりますよね。この記事では、OpenAIのGPT-3を活用し、たった一つのコマンドでgit diffの出力から適切なコミットメッセージを自動生成する方法をご紹介します。
さらに、git hooksを利用して、コミットメッセージを完全に自動化する方法も解説します。この方法を取り入れることでより効率的に作業に集中できるでしょう。

## リポジトリ
https://github.com/akmhmgc/gpt-commit-message-generaror

## 手順

1. まず、GPT-3 APIを利用できるように、Pythonでopenaiパッケージをインストールします。

```sh
$ pip install openai
```

2. 次に、以下のシェルスクリプト`generate_commit_message.sh`とPythonスクリプト`generate_commit_message.py`を作成します。

generate_commit_message.sh:

```generate_commit_message.sh
#!/bin/bash

# GPT-3 APIキーを環境変数に設定
export OPENAI_API_KEY="あなたのAPIキー"

# git diffの出力をPythonスクリプトに渡す
git diff --staged | python3 generate_commit_message.py
```

generate_commit_message.py:

```generate_commit_message.py
import openai
import os
import sys

# 環境変数からAPIキーを取得
api_key = os.getenv("OPENAI_API_KEY")

# APIキーを設定
openai.api_key = api_key

# 標準入力からgit diffの出力を取得
diff_output = sys.stdin.read()

# GPT-3へのリクエストを作成
prompt = f"Given the following git diff output, suggest an appropriate commit message in English:\n\n{diff_output}\n\nCommit message:"
response = openai.Completion.create(
    engine="text-davinci-003",
    prompt=prompt,
    max_tokens=100,
    n=1,
    stop=None,
    temperature=0.7,
)

# コミットメッセージを取得して表示
commit_message = response.choices[0].text.strip()
print(commit_message)
```

```
Given the following git diff output, suggest an appropriate commit message in English:\n\n{diff_output}\n\nCommit message:
```

の部分がプロンプトになっています。もっと良いメッセージがあるかもしれないのでお好みでどうぞ。
また、今回は適当にtoken数を100としていますがもう少し増やした方が良いかもしれません。
APIキーには、[OpenAIのAPI Key](https://platform.openai.com/account/api-keys)を使用してください。

3. シェルスクリプトとPythonスクリプトを同じディレクトリに保存し、シェルスクリプトに実行権限を与えます。

```sh
$ chmod +x generate_commit_message.sh
```

4. これで、git diffの出力からコミットメッセージを自動生成できるようになりました。シェルスクリプトを実行するだけで、GPT-3が生成したコミットメッセージが表示されます。

```sh
$ ./generate_commit_message.sh
```

5. 使ってみる
試しに以下のようなファイルを追加してみて、メッセージを自動生成してみます。

```test.txt
Hello world
```

```sh
$ ./generate_commit_message.sh
"Add 'Hello world' to test.txt"
```
良さげなメッセージが生成されましたね！🎉
今回はdiffの例がよくなかったかもしれませんが、使ってみた分にはとても便利でした！

## さらに楽をしたい場合
更に、git hooksを利用して、コミットメッセージの自動生成を完全に自動化する方法を説明します。

1. まず、.git/hooksディレクトリに移動します。

```sh
cd .git/hooks
```

6. 次に、`prepare-commit-msg`ファイルを作成し、以下の内容を追加します。この内容は、先ほどの`generate_commit_message.sh`と同じです。

```prepare-commit-msg
#!/bin/bash

# GPT-3 APIキーを環境変数に設定
export OPENAI_API_KEY="your_api_key_here"

# git diffの出力をPythonスクリプトに渡す
git diff --staged | python3 generate_commit_message.py
```
2. `prepare-commit-msg`ファイルに実行権限を付与します。

```sh
chmod +x prepare-commit-msg
```

3. 先ほどの`generate_commit_message.py`ファイルは、適切な場所（例えば、プロジェクトのルートディレクトリ）に置いておき、`prepare-commit-msg`ファイル内で正しいパスが指定されていることを確認してください。

これで、git commitを実行する度に、自動的にGPT-3がコミットメッセージを生成して設定してくれます。ただし、必要に応じて手動でメッセージを調整することを忘れずに行ってください。また、GPT-3 APIの利用にはコストがかかるため、利用料金に注意してください。

## 最後に
これで、GPT-3を活用したコミットメッセージの自動生成と、git hooksによる完全な自動化ができるようになりました。この方法を取り入れることで手間をかけずに、より効率的に作業に集中できるようになりました！
Material2でのJetpackComposeのTopAppBarでタイトルを中央に配置したい

# はじめに
現在、多くのアプリケーションではMaterial2でのandroidアプリ開発が行われているかと思います（2023年3月現在）。
しかし、最近Material3という、よりオシャなandroidアプリ開発に欠かせないテーマが出てきており、今回はMaterial2でのTopAppBarのタイトル配置方法を紹介していきます。

# Material2のTopAppBarの仕様
```kotlin:TopAppBarコンポーネント
@Composable
fun TopAppBar(
    modifier: Modifier = Modifier,
    backgroundColor: Color = MaterialTheme.colors.primarySurface,
    contentColor: Color = contentColorFor(backgroundColor),
    elevation: Dp = AppBarDefaults.TopAppBarElevation,
    contentPadding: PaddingValues = AppBarDefaults.ContentPadding,
    content: @Composable RowScope.() -> Unit
) {
    AppBar(
        // 省略
    )
}
```
このように、`TopAppBar`は`AppBar`のラッパーになっていることがわかります。
ここで注目したいのが、最後の引数の`content`が`RowScope`になっていることです。
詳しくは割愛しますが、`RowScope`では`Modifier.align(Alignment.CenterHorizontaly)`のように、水平方向に中央揃えすることができないため、トップバーのタイトルを中央に配置するためには`RowScope`内で工夫して配置する必要があります。

Material3では、標準で、タイトルを中央に配置するComposableが用意されたため、簡単に中央配置を実装する事が可能となります。
詳しくは[こちら](https://qiita.com/Nabe1216/items/0823dc7ebfb5d616f9c1)の記事が参考になるかと思います。

# 実装
実際にMaterial2でのトップバータイトルの中央配置方法が以下のようになります。
```kotlin:中央配置TopAppBar
TopAppBar {
    Spacer(modifier = Modifier.weight(1f))
    Text(text = "CenterHorizontalyTitle")
    Spacer(modifier = Modifier.weight(1f))
}
```
`TopAppBar`が`RowScope`になっているため、タイトルを`Spacer`で挟み込んで、その`Spacer`を`weight（1f)`に設定することで、タイトルを中央配置する事が可能となります。
`Modifier.weight`は画面上の表示する比率を調整するもので、今回だと、`Text`コンポーネント以外の余白を埋めるような`Spacer`の配置となります。
以上がMaterial2でのトップアップバーのタイトルの中央配置方法でした。
Git コマンド 業務でつかう主なもの

# 業務で使うGitコマンドをまとめました
前提：Git Bushを使用しています。
親ブランチ：main
子ブランチ：sagyou_branch

# mainブランチを最新にする

・mainブランチをチェックアウトする。※mainの場合は省略
```git
$ git checkout main
```
・main最新化
```
$ git fetch
$ git pull
```
### 最新にしたmainブランチを作業ブランチに取り込む
・作業ブランチチェックアウト
```
$ git checkout sagyou_branch
```
・mainブランチに取り込む
```
$ git merge --no-ff main
```
・マージした作業ブランチ反映
```
$ git push
```

# mainから作業ブランチを切る時
・mainブランチをチェックアウトする
```
$ git checkout main
```
・ブランチ最新化
```
$ git pull
```
・作業ブランチ作成
```
$ git checkout -b sagyou_branch
```
・作業ブランチをリモートリポジトリに反映
```
$ git push -u origin sagyou_branch
```

### 作業ブランチ削除
・作業ブランチからブランチ削除できないので、mainをチェックアウト
```
$ git checkout main
```
・ローカルリポジトリの作業ブランチ削除
```
$ git branch -d sagyou_branch
```
・リモートリポジトリの作業ブランチ削除
```
$ git push origin --delete sagyou_branch
```

### コード修正後のローカルからリモートにプッシュまでの一連コマンド
・修正後のファイルをステージングする
```
$ git add ファイルパス
```
・ステージングしたファイルをコメントを残してローカルにコミットする
```
$ git commit -m "アプリのどこどこを実装"
```
・リモートにpush
```
$ git push
```
Java_HashMapを作る

paizaラーニングforTEAM Java入門編
レッスン9の#02

```Java:9-#02
// Hashmapを作る

// Javaを使ってHashmapの作成、代入、表示といった基本機能を試す
import java.util.HashMap; // Hashmapを使う場合にインポートする必要がある

public class Main {
    public static void main(String[] args) {
        // 配列のおさらい
        String[] enemyArray = {"スライム", "モンスター", "ドラゴン"};
        // 配列のデータを出力_インデックスを指定して配列の要素を出力
        System.out.println(enemyArray[0]);
        System.out.println(enemyArray[1]);
        System.out.println(enemyArray[2]);
        
        System.out.println("---");
        
        // HashMapの具体例
        // HashMapでは、まとまったデータをインデックスではなくキーで指定
        // Hashmapはオブジェクトを生成して利用する
        HashMap<String, String> enemyMap = new HashMap<String, String>(); // <>内でキーのデータ型と値のデータ型をクラスで指定
        enemyMap.put("ザコ", "スライム"); // キーと対応する値(データ)のセット_このセットをエントリーという
        enemyMap.put("中ボス", "ドラゴン");
        System.out.println(enemyMap.get("中ボス")); // キーを指定してHashmapのエントリーの値を取り出す
        
        enemyMap.put("ザコ", "モンスター"); // エントリーを上書き
        System.out.println(enemyMap.get("ザコ"));
    }
}
```
ダビンチ nano w 校正エラー

### 校正エラー
前までの記事で、気になっていたのだけどほっといたことがありました。
それは校正がエラーになることです。
XYZprintのダッシュボードから校正＞開始しても
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2959912/ba9f0479-d811-c400-f99d-269dde49605d.png)

こんなエラーが出てしまって失敗します。MACでもやってみたり、USB接続でやったりマスキングテープを貼ってからやったりもしてみましたが、ダメでした。

### 例の白いボタン
![nano002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2959912/a9599587-c84e-8ca7-5d09-6e970f97a161.jpeg)
初めの記事でよくわからなかったこの白いボタンです。これが何か押し下げられて、押し下げると下からちっちゃなプラスチックの棒みたいのが飛び出すのですが、いったんこれがなんだかわからないでいました。
ふと思い立って、これを押し下げてから　校正開始すると…　うまくいきました！動きもさっきまでと違って、ポイントごとにZを下に下げてなにかチェックしてる様子です。
いや、そんなことどこかに書いてあった？とんと記憶にないのだけど…公式youtubeでもマニュアルでも触れられてないし…どこかにあったのだけど見落としたのか…？？

そしてこんな感じの画面が出ます。

### 調整指示
![nano校正.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2959912/6500aa06-17b3-e836-896e-2f6155baa729.jpeg)
校正チェックが成功するとこんな感じの画面がでます（画面は公式のyoutubeからの切り抜きです）。３つのダイアルっぽいものを指示の回数回せとということのようです。（継続ックって…）
ノッチ数の意味が？？？はじめは回すとカチッってするのを数えるのかな、と思ったのですが
ご注意のところに1周（360度）＝つまみ4ノッチ　とあるので、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2959912/dd5b793e-823a-6277-2e5b-fc4216cbe471.png)
こういう意味かな？と解釈して回しました。 0.5は45度分ということですが、まぁだいたいしかできませんがこんなもんかな、って感じで。
終わったら「続行」を押すともう一回チェックをしてくれて、今度は水平だと言って貰えました。ノッチの解釈はあってたっぽいです。

### 残るはZ軸オフセット
残る疑問はZ軸オフセットです。公式youtubeなどによればノズルとプラットフォームの間に名刺が一枚入るか入らないかぐらい…ということなのですが、そんなもんじゃなくガバっと空いてるんですよ。クレジットカード3枚分くらい。でもおとといはそれで一応印刷できたし、よくわかりません。そもそも公式でやってるような位置にヘッドが来ないし、Ｚ軸オフセットのボタンを押しただけだとヘッドはそれまでの任意のところにいるので一回上か下かにヘッドを動かしてやらないとそれっぽい高さに来てくれません。
これもそのうちわかるといいのですが…

校正と言い、Z軸オフセットと言い、よくこんな状況で一応一度は印刷できたというのが驚きです。

### 参考
XYZpriningジャパン公式のプリント前設定youtube

<iframe width="560" height="315" src="https://www.youtube.com/embed/A5AOFySj7xA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
AWS Certified DevOps Engineer - Professional(DOP-C02)を受験してみた

# AWS Certified DevOps Engineer - Professional(DOP-C02)を受験してみた

## はじめに

この記事では DOP-C02 を受験してみた感想や反省を書きます。
主な内容としては実際に受けてみてもっとhogehoge 勉強しておけばよかったとかここ勉強しておいてよかったなということを書きます。誤りなどがあれば書き直していく予定です。

なお、内容につきましては2023年3月17日時点の調査内容で記載しております。あらかじめご了承ください。

## アジェンダ

- DOP-C02とは
- 試験に挑むまでにやったこと
- 実際に受けてみての印象
- 反省
- 対策

## DOP-C02とは

タイトルにもある通り、AWS Certified DevOps Engineer - Professionalの改訂版第二版です。
試験ガイドは[こちら](https://d1.awsstatic.com/ja_JP/training-and-certification/docs-devops-pro/AWS-Certified-DevOps-Engineer-Professional_Exam-Guide.pdf)を参照してください。

試験時間が180分(長い)、問題数は75問で択一選択と複数選択問題の2種類があります。
なお、複数選択に関してはだいたいが2択以上3択以下という感じです。

## 試験に挑むまでにやったこと

- 実際にサービスに触る
- BlackBelt online seminarの視聴
- 各サービスのドキュメントを読む
- AWS公式ハンズオン

直近でSAP-C02を受験したこともあったのですが、あまり特殊なことはしていません。
とりわけほかと違うことといえば、実際にサービスを触ったことです。

直近でSAP-C02の問題を解いており、数日前にギリギリで落ちていたという状態でした。
また、新しい試験方式ということもあって、改訂前の模擬試験を解くということはしませんでした。
※実はその2週間前にDOP-C01の試験を受けてギリギリで落とされています。

ちなみにSAP-C02の時は公式模擬試験を解いていたんですが、想定していたものと全く違うものが出たように感じたのとあまり参考にならなかったというのが所感です。
※あえてフォローするなら解き方や速読の練習にはなりました。

## 実際に受けてみての印象

- これ？SAP-C02か？みたいな印象
- 当然ながらCodeシリーズがしっかり出る(現時点でPreview版のCode Catalystを除く)
- 開発で認証といったらCogniteですよね。わかります。
- で、出た〜Config監査系〜
- またかよorganizations、そしてControlTower（Solution Architect Organizationsじゃん！）
- お決まりのRTOとRPO、復旧までにかかる時間
- Jenkinsおじさん、クビ？

とりわけ印象に残ったのはSAP-C02か？みたいな気持ちになったことと以前にもましてちゃんとCodeシリーズを出すんだなぁというところです。また、DevOpsなので開発という印象がありつつも、復旧スピードなどのソリューションアーキテクトのような部分も見受けられました。
なお、DOP-C01ではJenkinsもいたような気がしましたが、今回の試験で霊圧が完全に消えました。

## 反省

- 改訂前の模擬試験を解いておいたおうが良い思う
    - とはいえ、直近までたくさん解いていたので大体の問題は答えと導出手順を覚えているのであまり練習にならない。
    - 何問か解いていたら受かっていたかというとそうでもない
- 試験ガイドのサービスを全部コンソールで見なかった
    - 開発ツールはコンソールで見たどころかハンズオンでパイプラインを組むことまでやった
    - AWS Config で実際にルール検出をやってみた
    - SCPに触ってAmazon Chime　を無効化してみた
    - 見るものは見たが全部ではない
- Jenkins
    - 前回出てきた気がしたので警戒したけどぶっちゃけこの試験においては知らなくても別によかった
- 復旧までにかかる時間で解き方を見失った
    - 端的に言えば、わからなくなったという感じ
- Codeシリーズ
    - 落ちているハンズオンを全部やるようなイメージで望んでおけばよかったかなと
    - あんまり時間かけていると次の試験をうけるタイミングでCodeCatalystも出てきちゃうかもしれない

## 対策

- 改訂前の模擬試験を解く
    - 答えと導出手順がわかっていても解く
- Codeシリーズはハンズオン
    - 実際に自分で構成図を書いて構築する練習
- 復旧時間(RTOとRPO)
    - 各サービス、特にAuroraなどをマルチリージョンにした時の復旧時間やDR対策について考えてみる
    - Route53で切り替え？ELB（ALB　or NLB）で切り替え？　リージョン？、AZ単位の切り替え？何が適切？

## まとめ

SAP-C02の問題演習をやっていれば、わりと得点を稼げていたのではという印象を受けました。
例えば、OrganizationとControlTowerの使いどころ(複数アカウントにおける権限管理、ガードレール)やアカウントの復旧スピード(RTO RPO)、リソースの自動回復などです。
そういうプロフェッショナルな側面を持ちつつも、Codeシリーズの深い知識を問うような感じかなと思います。

また、わかっていても実際に経験したことがないとある程度答えに辿りつけないような難易度まで到達しつつあるのかなという印象も受けました。
多くの人は追加されたサービスの数に惑わされますが、本当にヤバイのは深い経験がないと回答に辿り着けないという問題があるということです。
もちろん、名前にプロフェショナルという名前がついているので当然と言えば、当然です。

次を申し込もうと思いましたが、ハンズオンなどをしてもう少し経験を積んでから再挑戦しようかなと思います。
※もしかすると他の専門知識に時間を使った方がよかったのではと思うような感じもある。
※1ヶ月は置いておこうかなと思います。

## おまけ

得点は704点でした。
【問題解決】ThinkPadの音が出なくなった

# 問題発生
ThinkPadの音が出なくなりました。
原因はファンクションキーでした。
![IMG20230318211904.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3255462/a586475d-1659-03a2-6e9a-951e60696936.jpeg)
# 原因
**F1がONだった。
※「F1」キーが光っていた**
F1: オーディオの消音/解除
https://support.lenovo.com/sv/ja/videos/vid500090-thinkpad-function-keys-fn-key-with-f1-to-f12-keys-overview
# 解決方法
**F1をOFFにします。**
ただ私の場合は、FnLockが有効でファンクションキーを操作できない状態だったので、
まずFnLockを解除しました。
**「Esc」キーと「Fn」キーの同時押しでFnLockを解除します。
そして「F1」キーを押せば、「F1」キーが消灯します。**
ThinkPadから音が出るようになりました。
[ React ] useStateを使用して配列に追加する方法

## 完成コード
配列にオブジェクト追加する実装です。（テキスト入力　→　追加ボタン押下　→　配列にオブジェクト追加）
以下、コードの解説していきます。
```react:sample.jsx
import React, { useState } from "react";

const AddSampleArray = () => {
  const [str, setStr] = useState("");
  const [arr, setArr] = useState([]);
  const newMemo = { id: arr.length + 1, memo: str };
 
  const addArrBtn = (e) => {
    e.preventDefault();
    if (!str) return;
    setArr([...arr, newMemo]);
    setStr("");
  };

  return (
    <>
      <input
        type="text"
        value={str}
        onChange={(e) => setStr(e.target.value)}
        placeholder="入力する"
      />
      <button onClick={addArrBtn}>配列に追加する</button>
    </>
  );
};

export default AddSampleArray;
```

## １.入力エリア作成
入力エリア、配列に追加するボタンを作成します。

```react:sample.jsx
import React from "react";

const AddSampleArray = () => {

  return (
    <>
     <input
        type="text"
        placeholder="入力する"
      />
      <butto>配列に追加する</button>
    </>
  );
};

export default AddSampleArray;
```

## ２.useStateで現在の配列と新しい配列の状態を管理する準備
useStateを呼びだして➀と➁を定義します。
あと、inputタグに以下の記述を追加して➀のuseStateを使用して状態管理します。

```react:sample.jsx
import React, { useState } from "react";

const AddSampleArray = () => {
  const [str, setStr] = useState("");  //➀入力されたデータを管理
  const [arr, setArr] = useState([]);  //➁オブジェクトを追加する配列の状態を管理
  const newMemo = { id: arr.length + 1, memo: str }; //arrに追加するオブジェクトを定義　※idは無くてもOK

   return (
    <>
      <input
        type="text"
        value={str}   //更新されたstrを受け取る
        onChange={(e) => setStr(e.target.value)}   //onChangeによってsetStrを呼び出してstrを更新
        placeholder="入力する"
      />
      <button>配列に追加する</button>
    </>
  );
};

export default AddSampleArray;
```
## ３.ボタン押下時の処理を実装
buttonタグにOnClickイベントを登録して配列に追加する関数を呼び出します。

```react:sample.jsx
import React, { useState } from "react";

const AddSampleArray = () => {
  const [str, setStr] = useState("");
  const [arr, setArr] = useState([]);
  const newMemo = { id: arr.length + 1, memo: str };
  
  //配列にnewMemoオブジェクトを追加するボタン
  const addArrBtn = (e) => {
    e.preventDefault();  //ブラウザのデフォルト動作（ページリロード）をキャンセル
    if (!str) return;  //入力が無い場合に処理を終わらせる
    setArr([...arr, newMemo]);  //オブジェクトを新しい配列を生成
    setStr("");  //入力エリアの文字を削除
  };

  return (
    <>
      <input
        type="text"
        value={str}
        onChange={(e) => setStr(e.target.value)}
        placeholder="入力する"
      />
      <button onClick={addArrBtn}>配列に追加する</button> 
    </>
  );
};

export default AddSampleArray;
```

以上、ReactでuseStateを使用し配列に追加する方法でした。
【Swift】Imageについて

# はじめに
Swiftを始めるとUIKitを扱うことがあります。その中でも初期から学ぶ内容の
UIImageの画像の読み込みと表示についてまとめていきたいと思います。


## 準備
UIImageを使って画像を読み込み、UIImageViewで表示する方法については

まず、プロジェクト内に画像ファイル（例: "sampleImage.png"）を追加してください。その後、以下のコードを使って画像を読み込み、UIImageViewで表示します。

以下は、簡単なサンプルコードです。

~~~Swift:swiftCopy code
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // 画像ファイルの読み込み
        let image = UIImage(named: "sampleImage.png")

        // UIImageViewの生成
        let imageView = UIImageView(image: image)

        // UIImageViewのサイズと位置を調整（必要に応じて）
        imageView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)

        // UIImageViewをViewに追加
        view.addSubview(imageView)
    }
}
~~~

このコードでは、UIImage(named:) を使って画像ファイルを読み込んでいます。その後、読み込んだ画像を引数にしてUIImageViewを作成しています。UIImageViewのサイズや位置はframeプロパティを使って調整できます。最後に、addSubview()メソッドを使って、作成したUIImageViewをViewに追加しています。

このサンプルコードを実行すると、指定した画像ファイルが読み込まれ、指定した位置とサイズで表示されます。

# 終わりに
いろいろとSwiftのことについてまとめていく予定です。まだ始めたばかりという形でも気軽にコメントしてください
【考察】GPT-4はどのように画像まで処理できるようになったのか？【ChatGPT】

# 背景
- 本日3月18日地点では、GPT-4はChatGPT Plus(有料プラン)でのみ解禁されています
- GPT-4の一番の目玉はマルチモーダル性で、画像付きで自然言語の質問をすることができます。
- しかし、ChatGPT Plusでの解禁はテキストの部分のみで、画像処理を試すことはできません
- さらに、GPT-4は論文を公開したが、そこにはデータに関する記載はありませんでした
  - これは意図的なものと思われます。そのため、どのようなデータを用いて、画像とテキストを扱ったかは不明です。しかも、このまま公表されないことすらあり得ます。

# 目的
はやり仕組みが気になりますよね！
どうやって画像処理まで出来るようになっているのか！
この記事では、私が個人的に「多分こういう風に動いているだろうな」と思っていることを文章化します。
基本的にモデルの構造についてです。データをどういう風に集めたとかは、分かりようもないので気にしません
また、別の解釈や議論、追加の情報などあればコメントいただけると幸いです。
正式な発表などあれば、冒頭にリンクを差し込む予定です。

## GPT-4の画像処理とは
見飽きたかもしれませんが、OpenAIのGPT-4のページから画像を拝借します。
ざっくり言うと、
ユーザー「この画像は何がおかしい？」
GPT-4「iPhoneは本当はLightningケーブルを使うのに、VGAケーブルが刺さってるよ！」
という感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404462/378a778a-7f7e-fa4d-bffd-012b967e7c91.png)
ソース：https://www.axion.zone/gpt-4/

# [考察]どのように動作させているのか

## 背景知識
今回は3ステップで情報を整理し、考察します。

- GPT系列の思想
- GPT3の仕組み
- ViTの仕組み
ここを整理してから、結論に進みます。

## GPT系列の思想
多くの解説記事があるため、簡単にふれます。

まず、GPT-2や3というのは、「Fine Turningしなくてもあらゆるタスクの問題が解ける大規模モデルを大規模なデータから構築する」というのが基本的なモチベーションです。
この点、逆に言うと、**あまりモデルの構造自体にはモチベーションがありません。**
実はGPT-2とGPT-3は、若干の違いはあるものの、基本はただTransformerを大量に連結させ続けた、というシンプルな構造をしてます。
この点から、**「GPT-3とGPT-4においても、Transformerの数を増加させただけ、モデルに特別な構造は追加されていないだろう」** と想像できます。

## GPT-3の仕組み
世界一簡潔な図でGPT-3を記述します。
左から文章(文字群)が入ってきて、Word Embeddingで各文字が特徴量になり、各文字の特徴量がTransformerに入力されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404462/152c36ec-fbeb-af8a-2bd2-78e3275ac032.png)

※厳密には、各文字の特徴量ではないです。理解のためシンプルにしてあります。

Transformerが何かはどうでも良いです。
大事なのは、こういった **(ある単語が)ベクトル化されたものがTransformerに入力されれば処理できる** ということです。

## ViTの仕組み

ところで、Vision Transformerというものがあります。Transformerで画像処理してみた、という研究です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404462/b43793d7-579a-e061-2eaa-df6662a28121.png)

簡単に言うと
- 画像をパッチに分解します
- 画像を一列に並び変えて特徴量にします
- 1dのベクトルになったのでTransformerに突っ込んで分類などのタスクを解きます
という感じです。ざっくりなので、細かいところは違うかも知れません。

ここで大事なのは、 **画像をパッチに分解してTransformerに投入しても高い精度でタスクを解ける** ということです。
個人的には感覚的にちょっと不思議(パッチに画像を分けるというのがなんとも美しさに欠ける)気がするのですが、とはいえ、画像をTransformerに入力する方法がわかりました。

## まとめます。
あらためて、以下の仮定を立てます。

①あまりモデルの構造自体にはモチベーションがありません。GPT-3とGPT-4においても、Transformerの数を増加させただけ、モデルに特別な構造は追加されていないだろう

②ベクトル化されたものがTransformerに入力されれば処理できる

③画像をパッチに分解してTransformerに投入しても高い精度でタスクを解ける

もう結論はシンプルですね。推定されるGPT-4の構造は以下の感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404462/bba10ee9-8221-c1a9-fb16-f251f47af848.png)

雑な図ですね笑
入力されてきているデータが画像かテキストかくらいは、一目瞭然なので、そこをIFで分岐させるのはそんなに難しくないでしょう。ですので、入り口だけはさすがにTextとImageで処理が異なるかと思いますが、Transformerの入力直前では、Text由来かImage由来かは関係なく、同じベクトル状態でTransformerに投入されていると思います。

また、この構造だと、「テキスト→画像→テキスト」というフォーマットもサポートできます。
例えば、「この画像にうつっているのは何？　(( 画像 ))　左にあるのはコーヒーカップでその右側にあるやつ」
みたいなケースですね。ベクトル化してしまえば全部同じ、ということです。

# 最後に
以上は、基本的に想像です。これまでの傾向から、恐らくそうだろうと思って書いてはいますが、真実は公開されていないため不明です。
その点、ご了承ください
重回帰分析における独立変数の正規化は必要か?

測定単位の異なる（例えば，Kg, m, cm など）説明変数を用いて重回帰分析する場合に，まえもってそれぞれの説明変数を正規化（例えば平均0，標準偏差1とか最小値，最大値を0,1の範囲に収めるとか）すべしと言われ，そのままそれに従って分析するということがまま見られるが，4バイト実数でプログラムされていたはるか古の状況じゃないのだから，そんなことをする必要はサラサラないのではないか?
それぞれの独立変数が従属変数にどのような影響を与えるかは標準化偏回帰係数によって評価しないといけないのではあるが，正規化しない元のデータを用いた分析結果から標準化偏回帰係数は計算できる。予測のための元の変数を用いた分析と，標準化した変数で標準化偏回帰係数を求める分析を2回する必要はないのだ。独立変数だけ標準化して，従属変数はそのままというやり方もあり，支離滅裂。

ChatGPT に問答を試みたが，のらりくらりで一向にらちがあかない。
[Shopify] GraphqlAPIでmetafieldsにメディアを新しくアップロードする

metafieldsにあるfile_referenceに新しくファイルをアップロードしたい人向けの備忘録

## 前提
 - ファイルを既にどこかS3とかに置いておいて、外向きのURLを取得しておいてあること


## クエリ
```graphql
mutation fileCreate($files: [FileCreateInput!]!) {
  fileCreate(files: $files) {
    files {
      ... on MediaImage {
        id
      }
    }
    userErrors {
      message
    }
  }
}
```
## 解説
fileCreateは[File]を返す一方で、metafieldsはMediaImageを要求する。
MediaImageはFileをimplementsしているため、こんな感じでクエリを書くことでMediaImageのIDがもらえる。



### 参考
https://shopify.dev/docs/api/admin-graphql/2023-01/mutations/fileCreate
https://shopify.dev/docs/api/storefront/2023-01/objects/MediaImage
Docker ComposeでSQLPadを起動する（with ClickHouse）


## SQLPadとは

>SQLPad は、SQL クエリを記述して実行し、結果を視覚化するための Web アプリです。Postgres、MySQL、SQL Server、ClickHouse、Crate、Vertica、Trino、Presto、Pinot、Drill、SAP HANA、Snowflake、BigQuery、SQLite、TiDB などを ODBC 経由でサポートします。

参考：[Introduction to SQLPad](https://getsqlpad.com/en/introduction/)
## yaml設定

以下の設定を使用すると、Docker Composeを使用してSQLPadを起動できます。
検証用のClickHouseコンテナの設定もセットにしています。

```yaml:docker-compose.yaml (or compose.yaml)
version: '3'
services:
  sqlpad:
    image: sqlpad/sqlpad:latest
    container_name: sqlpad
    restart: always
    ports:
      # イメージのデフォルトは3000
      - 3000:3000
    environment:
      # 認証を無効化する
      SQLPAD_AUTH_DISABLED: true
      # ユーザーのロールを定める（admin or editor）
      SQLPAD_AUTH_DISABLED_DEFAULT_ROLE: admin
      # ログレベルの定義
      SQLPAD_APP_LOG_LEVEL: info
      SQLPAD_WEB_LOG_LEVEL: warn
    volumes:
      - ./data:/var/lib/sqlpad

  clickhouse_test:
    image: yandex/clickhouse-server
    container_name: clickhouse_test
    hostname: clickhouse_test
    restart: always
    # ports:
    #   - "9000:9000"
    #   - "8123:8123"
    volumes:
    - ./click-data/var/lib/clickhouse:/var/lib/clickhouse
    - ./click-data/var/log/clickhouse-server:/var/log/clickhouse-server
    - ./click-data/etc/clickhouse-server/users.d:/etc/clickhouse-server/users.d
```

volumes設定を使用して、ホストマシンの./dataディレクトリとコンテナ内の`/var/lib/sqlpad`ディレクトリをマウントします。これにより、SQLPadのデータベースファイルと設定ファイルがホストマシンのファイルシステムに保存されます。

## コンテナ起動

yamlを配置したディレクトリで以下を実行する。

```bash
docker-compose up -d
```

## アクセス確認

以下にアクセスする。

- http://localhost:3000


## ClickHouseに接続

SQLPadからClickHouseに接続してみましょう。

New connection を選択します。

![new-connection-settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518403/42558089-fb04-0483-b8af-4fc24e33fdb2.png)

今回は検証環境のため以下の設定で接続します。

![clickhouse-settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518403/81e2e1be-ee8a-ed9a-9251-4af3fc4d48da.png)

- **Connection name**
    - コネクションの名前を自由に指定できます。

- **Driver**
    - ドライバーを選択します。今回は`ClickHouse`を選択します。

- **Host**
    - DBがあるホストを指定します。（コンテナの場合、同じネットワーク内であればサービス名でもOKです）

- **HTTP Port(optional)**
    - DBのHTTPポートを指定します。ClickHouseのデフォルトは8123です。

- **Username (optional)**
    - DBのユーザー名を指定します。

- **Password (optional)**
    - 上記ユーザーのパスワードを指定します。

- **Database Name (optional)**
    - 接続したいDB名を指定します。


TEST で接続確認を行うことができます。save で設定を保存します。

![clickhouse-connection-test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518403/e87430b3-f055-1b8a-e47e-003c0efe19cd.png)

以下のように情報が確認できればOKです。

![clickhouse-initial-connection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518403/2667a0d7-3717-88e9-fd0d-f446568edcc2.png)

デモは以上です。


## まとめ

SQLPadをコンテナで構築し、ClickHouseへアクセス確認を行うところまで実施しました。サポートされているDBの種類も豊富なので活用できそうです。
【Swift】Peripheryで不要なコードを見つけてビルド時間を短縮する

# はじめに
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">使ってないソース検出ツールでめっちゃ出た<br>これで消しまくってビルド時間短くなってほしい<a href="https://t.co/Z1o9juPNAt">https://t.co/Z1o9juPNAt</a></p>&mdash; 崎山圭@iOSエンジニアで工学博士でiOSプログラミング個人講師 (@sakiyamaK) <a href="https://twitter.com/sakiyamaK/status/1635101115086962689?ref_src=twsrc%5Etfw">March 13, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

崎山さんのツイートを見て、[Periphery](https://github.com/peripheryapp/periphery)というものの存在を知りました。
めっちゃ良かったので記事にしておきます。

https://github.com/peripheryapp/periphery

# インストール
今回、私はHomebrewを使用してインストールしました。
```
brew install peripheryapp/periphery/periphery
```


# Xcodeでスキームを作る
① プロジェクトを選択します
② 「General」を選択します
③ 「+」を選択します
![スクリーンショット 2023-03-18 20.19.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/65a59e9e-0fd0-3556-078d-858cddec2457.png)

④ 「Other」を選択します
⑤ 「Aggregate」を選択します
⑥ 「Next」を選択します
![スクリーンショット 2023-03-18 20.22.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/5aebf80e-5219-a553-3edc-1c064a6f2110.png)

⑦ 「Product Name」を`Periphery`にします
⑧ 「Finish」を選択します
![スクリーンショット 2023-03-18 20.26.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/ecf352f4-cecb-5fd7-7f61-bfe54fd33f82.png)

# Run Scriptを作成する
① プロジェクトを選択します
② 先ほど作成した「Periphery」ターゲットを選択します
③ 「Build Phases」を選択します
④ 「+」を選択します
⑤ 「New Run Script Phase」を選択します
![スクリーンショット 2023-03-18 20.33.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/2cbe3bce-3ad6-d8f3-6105-be03d7a322a6.png)

⑥ 以下のスクリプトをコピペします(引数の値は各自変えてください)
```shell
periphery scan --project periphery-sample.xcodeproj --schemes periphery-sample --targets periphery-sample --format xcode
```
![スクリーンショット 2023-03-18 20.39.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/afb7b351-fc47-8ed4-7690-f465fbd74533.png)

# 実行方法
使用していない関数を追加しました。
これに警告が出たら成功です。
![スクリーンショット 2023-03-18 20.42.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/14b3fbb1-4bcc-c9f0-1815-8ac79fe168a4.png)

① スキームを選択します
② 「Periphery」を選択します
![スクリーンショット 2023-03-18 20.42.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/225ec8e3-dc66-0611-11e1-f546e3f53559.png)

③ ビルドします
![スクリーンショット 2023-03-18 20.44.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/a5dc6998-9ca3-d134-e015-c26c9bb797a8.png)

警告が表示されました！
![スクリーンショット 2023-03-18 20.45.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/96697ae8-d84b-512a-3d19-ceeb5d5e31bb.png)

# おわり
Peripheryめっちゃ気に入りました！！
スプレッドシートで再帰関数を作る

## 名前付き関数

スプレッドシートで名前付き関数が使えるので再帰関数も作れるよっていうお話です。

---

## 適当な例

### 階乗

$$
6! = 6 \cdot 5 \cdot 4 \cdot 3 \cdot 2 \cdot 1 = 720 
$$

みたいなやつです。
スプレッドシートにも一緒の関数があるので作る必要はないですが、下記のような感じで作れます。
FACTだと名前がかぶって怒られるので適当な関数名で。

FACT_OWN(n)

```
=IF(n=1, 1, n*FACT_OWN(n-1))
```

![階乗.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2888091/517d949a-b0d0-b731-6201-d760e2cac5fc.png)

---

### 素数

素数を判定する関数。
もっといいやり方ありそうですが。
素数を判定する関数

ISPRIME(n,k)

```
=IF(k<1, FALSE, IF(k = 1, TRUE, AND(MOD(n,k)<>0, ISPRIME(n,k-1))))
```
素数を取得する関数
GETPRIME(n)

```
=IF(n<2,"",SPLIT(REDUCE("",SEQUENCE(n-1,1,2,1), lambda(res, cur, IF(ISPRIME(cur, INT(SQRT(cur))), res&","&cur, res))),","))
```

![素数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2888091/8d96f161-f61a-7110-5192-5b179e80f49e.png)


---

### フィボナッチ数

普通に再帰関数でやると３０ぐらいからできませんね。
たぶん、アルゴリズムを改善すればいけるかもですが、ここは一般解に逃げます。
（再帰関数関係なくなっちゃいましたが）

```math
a_n = \frac{1}{\sqrt{5}} \left\{ \left(\frac{1+\sqrt{5}}{2}\right)^n - \left( \frac{1-\sqrt{5}}{2} \right)^n \right\}
```

![fibonacci.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2888091/35501ba2-f2fc-f19a-a397-8be8ca156003.png)

むむむ、大きい項の値がおかしいですね。
なんでだろう。だれか教えてください。

ちなみに再帰関数で計算している方は、#ERROR!の箇所で
「この数式の計算中に計算の上限に達しました。」
というエラーメッセージが表示されています。

---

## さいごに

こんかいは簡単な紹介だけでした。
いろいろできそうな可能性を感じますが、計算の上限とか制限もありそうですね。
でも再帰関数の計算も割と早いので、スプレッドシートでできるものはGASでやるよりいいかもしれないですね！

---

## 参照

[名前付き関数の作成と使用](https://support.google.com/docs/answer/12504534?hl=ja)
【 Java 】Spring解体新書 8章MyBatisで詰まった話

## ■はじめに
今回話す内容はこちらの[Spring解体新書](https://www.amazon.co.jp/%E5%BE%8C%E6%82%94%E3%81%97%E3%81%AA%E3%81%84%E3%81%9F%E3%82%81%E3%81%AESpring-Boot-%E5%85%A5%E9%96%80%E6%9B%B8%EF%BC%9ASpring-%E8%A7%A3%E4%BD%93%E6%96%B0%E6%9B%B8%EF%BC%88%E7%AC%AC2%E7%89%88%EF%BC%89-Spring%E8%A7%A3%E4%BD%93%E6%96%B0%E6%9B%B8-ebook/dp/B08XPBPH9C)の8章Mybatisのところになります。

今章まで特に詰まることなく進めてきていたのに、ここのエラーで1週間程度詰まってしまったので、もし同事象で悩まれている方がいたらと思ってログを残します。


## ■達成したいこと
8章の8.2.1 insertにおいてコンパイルエラーなく、アプリケーションが実行できることをゴールとしております。


## ■詰まった箇所
テキストに従って、pomやsql、Mapperとどんどんファイルを作成していくと思います。
今回そんな中、UserServiceImplクラスでUserMapperを呼び出した段階で以下エラーが発生しました。
エラー内容は以下です。
```java:コンソール
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userServiceImpl': Unsatisfied dependency expressed through field 'mapper': No qualifying bean of type 'com.example.repository.UserMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.repository.UserMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
```
Springの公式曰く1行目のエラーが、
**依存関係チェックが有効になっているにもかかわらず、Bean が他の Bean または Bean ファクトリ定義で指定されていない単純なプロパティに依存している場合にスローされる例外** とのこと。

2行目のエラーが、**BeanFactory定義が見つからない Bean インスタンスを が要求されたときにスローされる例外**とのこと。。
[▶︎参照したSpring公式](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/UnsatisfiedDependencyException.html)

要は、アノテーションの設定ミスかな？？と思いテキストと照らし合わせてみたものの全く一緒。書き間違いなんてなく、コピペまでしたけど変わらずエラーでした。

## ■解決方法
こんだけ調べて解決方法がこんなこと??とはなりますが、pom.xmlでMybatisのライブラリのバージョンを上げただけで解決できました。

「■参照サイト」にリンク先の回答者のコメントを見ると、
「Java17ではサポートされていない可能性があることに気づいた！！そこでmybatisのバージョンあげたら問題は解決されたよ〜」みたいなことを書いていたので藁にもすがる思いでコメントを信じ、バージョンを上げてmeven installすると、、あら今までのエラーが嘘のように出なくなりました。

:::note warn
試行錯誤中に、SpringBootApplicationに@MapperScanを付けて明示的にすることで解決するかも??というサイトを見たので試したところ、「■参照サイト」のリンク先で話されてるエラーが出て、ググったらそれっぽいのが見つかって解決に至ったという流れです。
間接的解決なのかなと思いますが、根本解決は今じゃなくていいかな〜と思ったのでスルーしてます。
:::

## ■反省点
回答者のコメントにあった**Java17では**という文言にハッとして、解体新書のJavaバージョンを見たところ8でした。
エラーのQAとかでよく言語のバージョンやライブラリのバージョンを書いているのを見るのに、なんで自分はエラー文言ばかりにとらわれてしまったんだろう、、、と反省しました。。

## ■参照サイト
https://stackoverflow.com/questions/75136845/property-sqlsessionfactory-or-sqlsessiontemplate-are-required-the-problem-i

https://qiita.com/NagaokaKenichi/items/058a7243bd2948de7553
contabo VPSのWireGuardにPeerを追加してみた


参照サイト
https://wiki.debian.org/WireGuard?action=show&redirect=Wireguard#Alternative_C_-_Import_by_reading_a_QR_code_.28most_secure_method.29
http://ubuntuyome.blogspot.com/2011/03/omg-ubuntu-ubuntu-qr.html

# クライアント用秘密鍵・公開鍵を生成する
03フォルダにそれぞれ秘密鍵・公開鍵が生成される
```
mkdir ~/wireguard/03
cd ~/wireguard/03
wg genkey | sudo tee client.key
sudo cat client.key | wg pubkey | sudo tee client.pub

```

# クライアント用設定ファイルを生成する
```conf:client.conf
[Interface]
PrivateKey = (clientPrivateKey3)
Address = 10.0.0.4/32
DNS = 8.8.4.4

[Peer]
PublicKey = (serverPublicKey)
AllowedIPs = 0.0.0.0/0
Endpoint = x.x.x.x:51820

```

# クライアント用設定ファイルのQRコードを生成する
```
qrencode -o client.png < client.conf
```

# クライアント用QRコードをWireGuardクライアントに読み込む





# サーバー設定をする
Peerを追加する場合は、下記コマンドでWireGuardを停止した状態で追加しないと
設定が消されてしまうようです。
```
sudo wg-quick down wg0
```


```conf:/etc/wireguard/wg0.conf(追記)
[Peer]
PublicKey = (clientPublicKey3)
AllowedIPs = 10.0.0.4/32
```
```
sudo wg-quick up wg0
```
contabo VPSにWireGuardをインストールしてみた


参照サイト
https://gihyo.jp/admin/serial/01/ubuntu-recipe/0614
https://mirahouse.jp/n10/blog/2020/vpn-wireguard/


# WireGuardをインストールする
```
sudo apt install wireguard
```

# サーバー用秘密鍵・公開鍵を生成する
```
wg genkey | sudo tee /etc/wireguard/server.key
sudo cat /etc/wireguard/server.key | wg pubkey | sudo tee /etc/wireguard/server.pub
```

# クライアント用秘密鍵・公開鍵を生成する
今回はPC用とスマホ用に2つ作る
01と02フォルダにそれぞれ秘密鍵・公開鍵が生成される
```
mkdir ~/wireguard/01
cd ~/wireguard/01
wg genkey | sudo tee client.key
sudo cat client.key | wg pubkey | sudo tee client.pub

mkdir ~/wireguard/02
cd ~/wireguard/02
wg genkey | sudo tee client.key
sudo cat client.key | wg pubkey | sudo tee client.pub
```


# サーバー設定をする

クライアントに割り当てたVPN用IPアドレスをAllowedIPsに設定する
サブネットマスクは/32でないとエラーになるという情報があったので
その通りにした。
PostUp/PostDownはWireGuardの起動/終了時に実行するコマンド
iptablesのフォワーディングの設定を追加しているので
スマホ > WireGuardサーバー > インターネット
という経路が利用できるようになる。

```conf:/etc/wireguard/wg0.conf

[Interface]
PrivateKey = (serverPrivateKey)
Address = 10.0.0.1
ListenPort = 51820
SaveConfig = true
PostUp = iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -o %i -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -o %i -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
PublicKey = (clientPublicKey1)
AllowedIPs = 10.0.0.2/32

[Peer]
PublicKey = (clientPublicKey2)
AllowedIPs = 10.0.0.3/32
```

また、sysctl.confを編集してパケットのフォワードを許可する
行頭の # を消してコメントを解除する
```conf:/etc/sysctl.conf
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1  
```

設定を反映させる
```
sysctl -p
```

# クライアント設定をする
[Interface]
DNSはサーバーがアクセス可能なDNSを指定する
(指定しないとインターネットにアクセスできなかった)

[Peer]
AllowedIPs = 0.0.0.0/0を指定することで
クライアントのすべての通信をWireGuard経由にする
EndpointにはサーバーのIPアドレスとListenPortを指定する
```conf:client1
[Interface]
PrivateKey = (clientPrivateKey1)
Address = 10.0.0.2/32
DNS = 8.8.4.4

[Peer]
PublicKey = (serverPublicKey)
AllowedIPs = 0.0.0.0/0
Endpoint = x.x.x.x:51820

```
```conf:client2
[Interface]
PrivateKey = (clientPrivateKey2)
Address = 10.0.0.3/32
DNS = 8.8.4.4

[Peer]
PublicKey = (serverPublicKey)
AllowedIPs = 0.0.0.0/0
Endpoint = x.x.x.x:51820

```

# サーバーでWireGuardを起動する
```
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
```

# クライアントでVPN接続し、サーバーで接続状態を確認する

```
sudo wg
```
<img width="400" alt="wg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/46e70933-bac9-1864-05dd-f2e86feae7d1.png">

# 検証する
WireGuard無効の時は、フリーwifiのアドレスが表示される
<img width="400" alt="ip1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/bc31e200-5658-1646-c259-3cb44795fdc1.png">

WireGuard有効の時は、contabo VPSのアドレスが表示される
<img width="400" alt="ip2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/638339aa-269b-f173-a38c-f84b0913caf5.png">
英英辞書から単語の定義をスクレイピングしてみた


参考サイト
https://excel-ubara.com/excelvba4/EXCEL_VBA_401.html
https://powervbadesktop.com/web0/

英検準1級の勉強を始めたので英英辞書から単語の定義を取得するVBAを組んでみた。

# WebDriverにwebページの指定をする
```
Const dictionaryURL As String = "https://www.oxfordlearnersdictionaries.com/definition/english/"

Set Driver = New Selenium.WebDriver

targetUrl = dictionaryURL & word

Driver.AddArgument "headless"
Driver.Start "Chrome"
Driver.Get targetUrl
```

英英辞書はoxfordを使う
oxfordの辞書は
https://www.oxfordlearnersdictionaries.com/definition/english/
の後に単語を付ければいいので
```
dictionaryURL & word
```
で指定している

<img width="400" alt="dictionary" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/a803266b-34de-3ee0-b2b3-8bc0abd66121.png">

```
Driver.AddArgument "headless"
```
上記指定でChromeをバックグラウンドで実行できる


# ディベロッパーツールでタグを特定する

## 単語の定義をドラック > 右クリック > 検証

<img width="400" alt="dictionary" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/ac204bc4-3a32-8945-ceef-e25a19a3fa8c.png">

## タグを確認する

class="def"であることが分かる

<img width="400" alt="dictionary" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/9d80889e-8fc5-585a-9e6a-83214ac6696b.png">


# タグを指定して要素を特定する



```
Dim defElements  As WebElements
Dim defs As String
Dim defCnt As Integer
Dim ans As Integer

Set defElements = Driver.FindElementsByClass("def")
    
'すべての説明を結合する
For defCnt = 1 To defElements.Count
    defs = defs & defCnt & vbCrLf & defElements.Item(defCnt).Text & vbCrLf
Next


ans = InputBox("入力する定義を選択してください" & vbCrLf & _
                        "99=全ての定義を入力する" & vbCrLf & vbCrLf & _
                        defs)

Select Case ans
    Case 99
        Cells(ActiveCell.Row, columnEngDesc).Value = defs
    Case Else
        Cells(ActiveCell.Row, columnEngDesc).Value = defElements.Item(ans).Text

End Select

```

```
Set defElements = Driver.FindElementsByClass("def")
```
上記でdefクラスの要素に絞り込む


```
For defCnt = 1 To defElements.Count
    defs = defs & defCnt & vbCrLf & defElements.Item(defCnt).Text & vbCrLf
Next
```
すべての定義を結合する


```
ans = InputBox("入力する定義を選択してください" & vbCrLf & _
                        "99=全ての定義を入力する" & vbCrLf & vbCrLf & _
                        defs)

Select Case ans
    Case 99
        ActiveCell.offset(0,1).Value = defs
    Case Else
        ActiveCell.offset(0,1).Value = defElements.Item(ans).Text

End Select
```

<img width="400" alt="dictionary" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/33644ef8-1900-d4d8-2fff-4b53b294643e.png">

結合した定義をinputboxで表示しどの定義を取得するか番号を入力してもらう
99を入力した場合はすべての定義を入力する
githubのpersonal access tokenの有効期限が切れたので更新してみた


参考サイト
https://style.potepan.com/articles/34189.html

githubからpersonal access token有効期限切れメールが来たので更新(再作成)をしてみた。

<img width="800" alt="mail" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/1addf808-cd2a-3c07-d27b-3ea5697b7aa7.png">

# githubでpersonal access tokenを再作成する
## menu > settingをクリック

<img width="200" alt="01" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/83bc4316-2bf8-a7be-3980-77a4c2f6c85c.png">

## Developer settingsをクリック

<img width="400" alt="02" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/604a7290-16cd-d86f-2e6d-241f43fd98e9.png">


## Personal access tokens > tokens(classic) > (更新したいトークン名)をクリック

<img width="400" alt="03" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/67a53f85-7de8-c48b-1099-a634fb648795.png">


## Regenerate tokenをクリック

<img width="400" alt="04" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/ecc814d9-a581-bfbc-0c93-a1d3f3ebaef5.png">


## 有効期限日を設定 > Regenerate tokenをクリック

<img width="400" alt="05" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/e3521665-bc2b-4c82-bd63-3a4932a9dc64.png">

## 新しいtokenが表示されるので保存する

<img width="400" alt="06" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/fcc8e57a-710c-02af-799b-b8430bb3ab31.png">


# eclipseのpersonal access tokenを更新する

## 証明書の変更をクリックする

<img width="400" alt="11" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/c53d1b89-eb3c-8bb6-d1b2-91c19ffa55fc.png">


## ユーザー名/personal access tokenを入力する

<img width="400" alt="12" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/77faedbe-9b9b-b36a-96b5-6c3b1f88c529.png">

問題なくコミットできたのでこれで問題ないと思われる。
contabo VPSにEclipseをインストールしてみた


参照サイト

https://takilog.com/ubuntu-eclipse-develop/

https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/eb-cli3-install-linux.html

Python環境を構築するためにEclipseをインストールする

# EclipseをHPからダウンロードする

# Eclipseをインストールする
```
mkdir eclipse
cd eclipse/
tar -xvzof ~/Downloads/eclipse-inst-jre-linux64.tar.gz
./eclipse-inst

```

# PyDevをインストールする
Help > Install new software

<img width="400" alt="newinstall" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/e90bd087-e02b-0af7-ad17-2646ef9ab07a.png">

Add

<img width="400" alt="newinstall2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/539780e8-db79-9c59-b997-eb8157e053ec.png">

PyDevのリポジトリを登録

<img width="400" alt="addrepository" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/37ff994e-76ae-bd66-8172-5873f0c6ab4c.png">

PyDevにチェックを入れる > Next

<img width="400" alt="newinstall3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/95eec648-c53b-e648-1b8c-cea166deaed4.png">

Next

<img width="400" alt="newinstall4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/3f7c0f03-e81c-b12d-35f5-3fd14b011e18.png">

I accept > Finish

<img width="400" alt="newinstall5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/89ad36ae-9030-65d2-57ec-ce07c439ea6a.png">


# PyDevパースペクティブを開く

Window > Perspective > Open Perspactive > other

<img width="400" alt="openperspective1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/eea5aa88-2c2a-a625-731f-4d59f5cf86df.png">

PyDev

<img width="200" alt="openperspective2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/7f5eba02-256b-84f2-de49-2b59a6cdc349.png">


# インタープリタを追加する

Window > Preferences 

<img width="400" alt="preference1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/83569200-46e2-d755-1fbc-cb9f7914f9cc.png">

PyDev > Interpreters > Python Interpreter

<img width="400" alt="preference2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/902a29b3-ea01-e2e3-4bc7-3bbcf5f811b4.png">

New > Choose from list

<img width="400" alt="preference3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/84402051-f09e-a2ac-a118-71591f5ac9ee.png">

インタープリタを選ぶ

<img width="400" alt="preference4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/d5cb58e8-5c13-a08c-58ff-3540eeb3657e.png">

パスを通す

<img width="400" alt="preference5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/1dc95c1c-9f86-96c3-db7c-b5350176acfd.png">

インタープリタが追加された

<img width="400" alt="preference6" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99234/a7c5614c-60b4-8232-868a-893919f899f3.png">


# pipをインストールする
```
$ curl -O https://bootstrap.pypa.io/get-pip.py
$ python3 get-pip.py --user
```