OmniAICreator/Qiita-1.07M huggingface dataset:
共通鍵暗号・公開鍵暗号とは？

## まず暗号化・復号化とは？

インターネットでパブリックなネットワークにデータを転送するためには、
第三者に見られないようにデータを`暗号化`することが必要です。
以下のようにすることで安全にデータを置くうることが出来ます。

1. 送信する前にデータを暗号化
2. 暗号化したデータを送信
3. 受信したデータを復号化

## 共通鍵暗号

- 概要
暗号化と復号化に同じ鍵を使う暗号方式

- 流れ
1. 送信者は共通鍵でデータを暗号化
2. 送信者は受信者にデータを送信
3. 受信者は受け取ったデータを共通鍵で復号化

- メリット
	- 暗号化・復号化の処理速度が早い

- デメリット
	- 鍵が外部に漏れてしまうと、簡単に中身を見られてしまう
	- データをやり取りする相手毎に鍵が必要で管理する鍵が膨大になる

## 公開鍵暗号

- 概要
暗号化と復号化で違う暗号方式

- 流れ
1. 受信者は自分の秘密鍵を使って公開鍵を作成
2. 受信者は作った公開鍵を送信者に送る
3. 送信者は公開鍵でデータを暗号化
4. 送信者は暗号化したデータを受信者に送る
5. 受信者は受け取ったデータを秘密鍵で復号化

- メリット
	- 公開鍵が漏れてしまっても、復号化出来ないので機密性が確保出来る
	- 復号するためには、相手の人数に関わらず秘密鍵1つでよい


- デメリット
	- 暗号化・復号化の処理速度が遅い

## 参考

- [公開鍵、共有鍵、秘密鍵、SSLってなあに？](https://www.dcom-web.co.jp/lab/etc/what_are_public_keys_shared_keys_secret_keys_and_ssl)
- [共通鍵暗号と公開鍵暗号に必要な鍵の数](https://sites.google.com/site/ryouheivision/home/qing-baosekyuriti/gong-tong-jian-an-haoto-gong-kai-jian-an-haoni-bi-yaona-jianno-shu)
Rails: rake taskを良い感じに書く方法


# 良い感じ = 以下の二点

1. テストしやすいこと
    * 工数削減のため
1. （ある程度は）エンジニア間での書き方が統一できること
    * 例えば`dryrun`の指定方法が書き手によってまちまちだと、商用でのtask実行時に事故が起きる可能性もあるので統一可能であればした方が良い
    * ログのフォーマットが統一されていないと作業効率が悪い


などなど



# コード

```ruby:lib/tasks/issue_6885.rake
require_relative 'helpers/all_user_name_update_helper.rb'

namespace :issue_6885 do

  desc 'これはサンプルです'
  task all_user_name_update: :environment do
    helper = AllUserNameUpdateHelper.new

    helper.main
  end
end
```


```ruby:lib/tasks/helpers/all_user_name_update_helper.rb
require_relative 'rake_helper_template'

class AllUserNameUpdateHelper < RakeHelperTemplate
  NEW_NAME = 'bar'

  def main
    template do |logger|
      all_users = get_all_user
      logger.info("対象ユーザー数: #{all_users.size}")

      if all_users.blank?
        logger.info('対象ユーザー数が0件だったため処理を終了します')
        return
      end

      all_users.each { |user| update_name(user, NEW_NAME) }
    end
  end

  private

  def get_all_user
    User.all
  end

  def update_name(user, new_name)
    user.update!(name: new_name)
    user
  end
end

```

```ruby:lib/tasks/helpers/rake_helper_template.rb
class RakeHelperTemplate
  # 標準出力も行う
  def make_logger(log_file_path)
    logger = ActiveSupport::Logger.new(log_file_path)
    stdout_logger = ActiveSupport::Logger.new(STDOUT)
    broadcast_logger = ActiveSupport::Logger.broadcast(stdout_logger)
    logger.extend(broadcast_logger)
    logger.formatter = Logger::Formatter.new
    logger
  end

  # ログファイル名はtask名と同じにする（コロンは使わない方が良いので置換する）
  # rakeタスクの実行以外から呼び出されるケース（例: spec）を考慮しておく
  def make_log_file_path
    task_name = Rake.try(:application)&.top_level_tasks&.[](0)&.gsub(':', '_') || Rails.env
    log_file_name = "#{task_name}.log"
    Rails.root.join('log', log_file_name)
  end

  def template
    log_file_path = make_log_file_path

    # 明示的に文字列のfalseを渡さない限りは必ずdryrunにする
    is_dryrun = ENV['is_dryrun'] != 'false'

    logger = make_logger(log_file_path)
    logger.info("Start. is_dryrun: #{is_dryrun}")

    ActiveRecord::Base.transaction do
      yield(logger)
      raise ActiveRecord::Rollback if is_dryrun
    end

    logger.info("Finish. log_file_path: #{log_file_path}")
  end
end
```

# 実行例
```console:dryrunにする場合
$ is_dryrun=false bundle exec rake issue_6885:all_user_name_update
I, [2020-09-27T13:33:27.229764 #13040]  INFO -- : Start. is_dryrun: true
I, [2020-09-27T13:33:27.556890 #13040]  INFO -- : 対象ユーザー数: 1
I, [2020-09-27T13:33:27.755933 #13040]  INFO -- : Finish. log_file_path: /app/log/issue_6885_all_user_name_update.log 
```

# ポイント

1. .rakeファイルはhelperクラスを呼び出すだけにして、rakeのDSL？的なお作法を気にせずに普段書き慣れているclassのメソッドをテストするようにした
    * 参考: [Qiita - RailsでRakeタスクをシンプルかつ効果的にテストする手法](https://qiita.com/aeroastro/items/c97bd26ce8b8818b6bed)
2. yieldを使って`dryrun`, `logger`（の一部）を共通化し、rake taskを作成するたびに毎回定義しなくても済むようにした
    * mainメソッド（名前は何でも良い）には極力そのtaskの処理フローだけを定義するようにし、個別具体的な処理はテストしやすい粒度で別メソッドに切り出すようにする

テンプレートにしてしまえばall_user_name_update_helper.rbのようにやりたいことに集中できる！`(^○^)`


# 所感
* rake taskの書き方は久々に書くと忘れてるのでこの記事は実は備忘録的な意味合いもあったり
* yieldは正直わかりにくいので使いたくない派だけど、テンプレートのように毎回書いたり読んだりしないものであれば良いかなという考え
* 他にも良い感じの書き方あるよという方いたら教えてください！
Dart の reduce は使わない方がいい

Flutter を触っていて、 Javascript と同じように List の `reduce` を使おうとしたらハマったので、皆さんも気をつけましょう。

こちらの記事のコードは [DartPad](https://dartpad.dev/) で試せます。
書いている時点のバージョンは `Flutter 1.22.0-12.1.pre Dart SDK 2.9.3` です。

## 要約

- Dart の `reduce` は要素が一つの場合、そのまま値を返す。
- Dart の `reduce` は List の要素の型と結果の型が変わる場合は使えない。


## Dart の reduce
ドキュメントは[こちら](https://api.dart.dev/stable/1.10.1/dart-core/List/reduce.html)になります。
早速実行してみましょう。

``` dart
void main() {
  List<int> test = [6, 9, 13];
  print(test.reduce((acc, element) {
    return acc + element;
  }));
}
```
Console には `28` と表示されました。これぐらい単純ならちゃんと動きます。

## ブラックジャックの例
ブラックジャックの得点計算を例にします。各カードの得点は以下のようになります。

- 2~10 : 数字の点数
- J,Q,K : 10点

(A の得点については本題と関係ないので省略)

では、 `reduce` を使って点数を計算します。

``` dart
void main() {
  List<int> test = [6, 9, 13];
  print(test.reduce((acc, element) {
    if (element > 10) {
      return acc + 10;
    }
    return acc + element;
  }));
}
```
Console には `25` と表示されました。うまく動いていそうです。

## ハマるケース
ではどんなケースでうまく動かないのか。それは K 一枚のケースです。

``` dart
void main() {
  List<int> test = [13];
  print(test.reduce((acc, element) {
    if (element > 10) {
      return acc + 10;
    }
    return acc + element;
  }));
}
```
Console には `13` と表示されました。List の要素が一つの時はそのまま値を返すようです。

## 正しいやり方
この問題に対処するには `List.fold` を使います。ドキュメントは[こちら](https://api.dart.dev/stable/1.10.1/dart-core/List/fold.html)

``` dart
void main() {
  List<int> test = [13];
  print(test.fold<int>(0, (acc, element) {
    if (element > 10) {
      return acc + 10;
    }
    return acc + element;
  }));
}
```
Console には `10` と表示されました。

## 結論

実際、最初のケースのように `reduce` の内部で特別な処理をしなければ問題はないです。
しかし、メンテナンスを通して特別な処理が入ることも考えられるので、(個人的な意見ですが)一律で `fold` を使うようした方がいいです。

## おまけ
`reduce` は List の要素の型と結果の型が変わる場合は型エラーになります。
以下の例では List の要素が `int` で結果の型が `double` になります。

``` dart
void main() {
  List<int> test = [6, 9, 13];
  print(test.reduce((acc, element) {
    return acc + (element / 2); // 型エラー！
  }));
  print(test.fold<double>(0, (acc, element) {
    return acc + (element / 2); // エラーになりません
  }));
}
```
Install docker, docker-compose for debin10

# 目的
- インストール
    - docker
    - docker-compose
- docker data　保存先ディレクトリを移動する




# Install docker

- uninstall olds

```shell
sudo apt-get remove docker docker-engine docker.io containerd runc
sudo apt-get update
```


- setup repository

```shell
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    gnupg2 \
    software-properties-common

curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -

sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/debian \
   $(lsb_release -cs) \
   stable"
```


- install docker

```
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
```




# Install docker-compose

- install compose

```shell
sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# インストール後にdocker-composeコマンドが失敗した場合は、パスをチェックします
# また、パス内の /usr/bin やその他のディレクトリへのシンボリックリンクを作成するなど
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
```




# no sudo 

- sudo 無しで実行可能とする

```shell
sudo groupadd docker
sudo gpasswd -a $USER docker
```



# docker data ディレクトリ移動
- /etc/default/docker

```shell
# ファイル末尾に追加. -g の後に、docker data 保存先ディレクトリを指定
OPTIONS="-g /opt/docker"
```



- /lib/systemd/system/docker.service

```shell
# option file 読み込み
EnvironmentFile=/etc/default/docker

# ExecStart 行の末尾に $OPTIONS を追記
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock $OPTIONS
```


- realod

```shell
sudo systemctl daemon-reload
sudo systemctl restart docker
```




# 参考サイト
https://docs.docker.com/engine/install/
https://mebee.info/2020/04/13/post-8593/
https://www.codeflow.site/ja/article/how-to-install-and-use-docker-on-debian-10
https://qiita.com/DQNEO/items/da5df074c48b012152ee
Unity LearnのCreate with Codeの出来が良い

<h2>前書き</h2>
一応、エンジニア的には業務系のシステムを主にやってきたのですが、スキルの幅を広げるために`Unity`に手を出してみました。
学習用コンテンツというのは、各サービスで力を入れているとは思いますが、アカウント登録のみの無料で利用できる内容としては非常によくできていると思ったので、簡単にご紹介です。
内容について詳細な解説はしていませんので、悪しからず。

<h2>参照先</h2>
[Unity Learn](https://learn.unity.com/)
[Unity Learn - Create with Code](https://learn.unity.com/course/create-with-code)
[Unity](https://unity.com/)


<h2>概要</h2>
Unity Editer上でのゲーム作成を通してプログラミングの基本を学べる内容。
全体を通して行うと36.5時間と非常に長いのですが、主に解説動画の視聴なので作業としての時間はそんなに長くありません。

<h2>おススメな点</h2>
- プログラム未経験者でも独学で進めれられる内容。
    - 難易度としてさほど高くなく(おそらくターゲットとしては小中学生)、コードを記述する量も多くない。
    - 数分～10分程度の動画視聴後、すぐに説明内容を実装する⇒動作確認する、という流れが良くモチベーションを保ちやすい。
- 理解できなくてもそのまま書けば動くものができる。
    - もちろん、理解できた上で動かせているのが理想ですが、ひとまずは動くものを作って、いろいろ動かしているうちに理解する、という方法も「あり」だと思うので。
- 3Dで動くものができる。
    - 往年のBASICプログラマーとしてはLOCATEとPRINTでCUIでゴリゴリ書いた時代が懐かしいのですが、簡単なベクトルで立体が動くと楽しいです。
    - 説明動画内で使っていないアセット(要するにゲームを構成する部品)も用意されているので、ちょっとした変更でオリジナル感がだせる。
    - 使用するアセットは低ポリゴンのものがほとんどなので、低スペックPCでもある程度いけそう。
    - 低ポリゴンでもちゃんとモーションが付いている。

<h2>少し残念な点</h2>
- 基本的に英語の内容のみ。
    - とはいえブラウザの翻訳機能を使えば大筋は理解可能と思います。
    - 説明動画はほとんど英語のキャプションが付いているのですが、キャプションがデフォルトでONになっている動画となっていない動画がある。
    - 動画内でかなり具体的に説明しているので、動画の内容が理解できていないと難易度が上がる。
- 総量が多い。
    - 一通りの事を盛り込むとある程度の量になってしまうのは仕方がないですが。
    - 単純計算で、毎週末1日使って約1カ月かけてじっくりやる、程度の気構えがあった方が良い。
    - 内容のうち「Prototype」と「Quiz」だけに絞ればだいぶサクサク進められますが、習熟度を高めるために「Challenge」はやったほうが良い。
    - 「Lab」の位置付けが微妙。コンセプトデザインから入るので、デザインをどう実装していくか(プロトタイピング)というお手本にはなる。ので知って損はないのですが、初心者向けとしてはなくてもいいと思える内容。

<h2>気づいた点</h2>
- Visual Studio Community よりVisual Studio Codeを使う方が動作が軽くなるので良い。
    - Unityバージョン2020.1ではメニューから「編集」⇒「環境設定」⇒「外部ツール」から「外部のスクリプトエディター」に「Visual Studio Code」を選択すればO.K.
![unity_preferences.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/68c771c4-42b5-8318-ce1e-ffa725cc64bd.png)

    - Visual Studio Code側に「C#」拡張機能を追加しておくと入力候補もある程度きちんと出るので便利。
![vscode_CSharp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/ee205243-fa5b-7dcb-3e48-0999ef7dbc7c.png)
- 推奨Unityバージョンが2018.4(LTS)系と少し古いのですが、2020.1系でもアセットはそのままインポートできる。
    - アセットをプロジェクトにインポート後は
![Unity_PackageManager_MyAsset.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/57a3ada1-9202-acbb-c042-0545982f6f32.png)
    - コンソールにエラーがたくさん出ますが、
![Unity_Console_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/5cf0fabf-cc52-7f48-98b2-95d8192f0808.png)
    - パッケージマネージャーで「In Project」に入っているパッケージを全部最新化して(パッケージ名の右側に上矢印があるものは新しいバージョンがある)から、
![Unity_PackageManager_InProject.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/2ab1980e-3c71-0cab-f5ac-72bb316b9e8c.png)
    - Unity Editerを一旦閉じて、開きなおしてから一度実行すると、大体エラーはなくなる。
![Unity_Console_NoError.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/d9c31138-78e3-2f6d-c12e-f04ab569630f.png)
    - 実行不可となるエラーが残るようなら、エラーメッセージを元に対処。エラーメッセージを元にGoogleで検索して対処します。

<h2>後書き</h2>
出回ってるツールの公式コンテンツってのは、お勧め機能や最新機能に寄ったものが多いと感じていたのですが、こういった初心者向けのコンテンツもあるんだな、というのはいい発見でした。
公式コンテンツがこれだけのクオリティだと、外部からやれることも減るんじゃないかという気もしますが、いいコンテンツが増えると独学でできることも増えるので、個人的にはどんどんやってほしいですね。
【Golang】Go言語基礎 Goroutineとは？

本日はgoroutineについて勉強しましたのでここでアウトプットさせて頂きます！
##Goroutineとは？
Goroutineとはgoステートメントで関数を指定することで、並行実行されるものです！

まずは普通の関数を書いてみます。

```go

package main

import (
	"fmt"
	"time"
)

func goroutine(s string) {
	for i := 0; i < 5; i++ {
		time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}

func hoge(s string) {
	for i := 0; i < 5; i++ {
		time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}

func main() {
	goroutine("world")
	hoge("hello")
}
```

```
実行結果
world
world
world
world
world
hello
hello
hello
hello
hello
```
これは、普通に上から関数が0.1秒ごとに実行されているだけですね。

これを並行実行するためには、**関数名の前にgoを付けるだけで並行実行できます。**

```go

(同じなので省略)

func main() {
	go goroutine("world")
	hoge("hello")
}
```

```
実行結果
hello
world
world
hello
world
hello
hello
world
world
hello
```

並行実行しているので出力が混じった状態になります。
このように goステートメントを指定するだけで並行実行が簡単に実現できます。

ここで、timeの部分をコメントアウトしてみるとどうなるでしょうか？

```go

package main

import (
	"fmt"
)

func goroutine(s string) {
	for i := 0; i < 5; i++ {
		//time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}

func hoge(s string) {
	for i := 0; i < 5; i++ {
		//time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}

func main() {
	go goroutine("world")
	hoge("hello")
}
```

```
実行結果
hello
hello
hello
hello
hello
```

timeの部分をコメントアウトすると、helloしか出力されなくなりました。
これは、並列処理でgoroutineスレッドが生成されても、先にmain関数の処理が終わってしまったため、
goroutine関数が実行されずに終わってしまったからです。

このように**gorutineの処理が終わらなくてもプログラムのコードは終了してしまう**ということを覚えておきましょう。

ではこれを避けるためにはどうすればよいか？

**sync.WaitGroup**というのを使います。

##sync.WaitGroup

```go

package main

import (
	"fmt"
	"sync"
)

func goroutine(s string, wg *sync.WaitGroup) {
	for i := 0; i < 5; i++ {
		fmt.Println(s)
	}
	wg.Done()
}

func hoge(s string) {
	for i := 0; i < 5; i++ {
		fmt.Println(s)
	}
}

func main() {
	var wg sync.WaitGroup
	wg.Add(1)
	go goroutine("world", &wg)
	hoge("hello")
	wg.Wait()
}
```

このように```wg```という変数を宣言して```wg.Add(1)```で一個の並列処理があるということを記述し、
goroutine関数へ```wg```のアドレスを引数で渡してあげます。

そして、```wg.Wait()```と書いてあげることで、gorutine関数の```wg.Done()```が呼ばれるまで処理が終わるのを待ってくれます。
このように書くことでgoroutine関数が実行されずに処理が終わってしまうことを回避することができます。

ちなみに、```wg.Add(1)```でgoroutineの処理が終わるのを待っているので、 ```wg.Done()```をコメントアウトするとエラーになります。
```wg.Add```したら```wg.Done()```を呼び出して処理が完了したことを示す必要があります。

またgoroutine関数は以下のように書くこともできます。

```go

func goroutine(s string, wg *sync.WaitGroup) {
	defer wg.Done()
	for i := 0; i < 5; i++ {
		fmt.Println(s)
	}
}
```
deferステートメントを使うとその関数の処理が終わった後にwg.Done()が実行されるので、このように書くこともできるのです。


##最後まで読んでいただきありがとうございます！
間違いや感想などありましたらコメントいただけると嬉しいです！！
Ansible Core の service モジュールをAIX で確認


Ansible 2.9 ドキュメントの [Service](https://docs.ansible.com/ansible/2.9/modules/service_module.html) モジュールを眺めていると、

>「Notes : For AIX, group subsystem names can be used.」

という記載を見つけたので試してみます。

このモジュールは、galaxy collection ではなく、Core モジュール (Ansible Core チームがメンテナンス)です。

参考：[Module Maintenance & Support](https://docs.ansible.com/ansible/latest/user_guide/modules_support.html)

Ansible の Core モジュール一覧：https://github.com/ansible/ansible/tree/devel/lib/ansible/modules

serviceモジュール本体：[service.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/service.py)
抜粋
> class AIX(Service):
    """
    This is the AIX Service (SRC) manipulation class - it uses lssrc, startsrc, stopsrc
    and refresh for service control. Enabling a service is currently not supported.
    Would require to add an entry in the /etc/inittab file (mkitab, chitab and rmitab
    commands)
    """

=> スタート、ストップ、リフレッシュ ができそうですね。

----

#### 環境
・AIX:
AIX 7200-03-02-1846 
(hostname : test )

・Anslbe 実行環境：
Mac
Ansible バージョン 2.9.9

---

#### 準備


1) ansible.cfg

```ansible.cfg
[defaults]
inventory = ./inventory
private_key_file = ~/.ssh/id_rsa
interpreter_python=/usr/bin/python
```

2) inventory

```
[test]
XX.XX.XX.XX    <=対象サーバーのIPアドレス
```


3) service.yml

```service.yml
---
- hosts: all

  tasks:
   - name: Stop service group mail, if started
     service:
        name: mail
        state: stopped
```


---


#### 実行

まずは、現在の mail グループの状態を確認

```
$ ansible test -m command -a "lssrc -g mail"
test | CHANGED | rc=0 >>
Subsystem         Group            PID          Status
 sendmail         mail             4981148      active
```

=> sendmail サービスがアクティブ状態です。


service.yml を実行します。

```
$ ansible-playbook service.yml

PLAY [all] ***********************************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************************
ok: [test]

TASK [Stop service group mail, if started] ***************************************************************************************
changed: [test]

PLAY RECAP ***********************************************************************************************************************
test                   : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

$
```

通りました！

では確認。

```
$ ansible test -m command -a "lssrc -g mail"
test | CHANGED | rc=0 >>
Subsystem         Group            PID          Status
 sendmail         mail                          inoperative

```

=> mailグループのsendmailサービスは"inoperative"状態です。

Coreモジュールのservice モジュールでAIXサービスのmailグループの停止処理が確認できました。


----



#### まとめ

・Ansible の Coreモジュールである service モジュールは、AIX のグループ単位のサービスでサービスモジュールの一部の処理が可能(当文書では mail グループのストップのみを確認)




以上です。
勉強メモ6_仕事で利用するかもしれないAPI関連URLのメモ

★1　PHP入門
　https://www.scollabo.com/banban/php/index.html

★2　郵便番号検索API
　
http://zipcloud.ibsnet.co.jp/api/search?zipcode=2500011

★3 webAPIの説明

https://qiita.com/busyoumono99/items/9b5ffd35dd521bafce47
【Springframework】プロキシサーバー利用時のRestTemplateによるHTTPリクエストのエラー対応

# 概要
プロキシサーバーを利用してインターネットにアクセスするネットワーク環境下でSpringのRestTemplateを利用して、外部のAPIにリクエストを送信しようとしたところエラーが発生しました。

普段開発する環境ではプロキシサーバーを利用しておらず調査に時間がかかったので、今回対応した方法をメモしておきます。

# 発生した事象
プロキシサーバーを利用してインターネットにアクセスするネットワーク環境下で`RestTemplate.exchange`を利用して外部APIを利用してGETリクエストをしたところ下記のエラーが発生。

ただし、同じAPIをブラウザ(Chrome)でアクセスした際にはレスポンスがきちんと返ってきている状況でした。

### エラーメッセージ
```java

org.springframework.web.client.ResourceAccessException: I/O error on GET request for "{targetURL}":
 Connection refused: connect;
 nested exception is java.net.ConnectException: Connection refused: connect
```

### イメージ図(ネットワーク環境)
![proxy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584011/ef19a19c-0156-fb88-d676-3bec68840d03.png)

# 原因
ブラウザはホストサーバーのプロキシ設定を利用していたため、インターネットアクセス時にはプロキシサーバーを経由してアクセスできていましたが、SpringBootアプリケーション側ではリクエスト時にプロキシサーバーを経由できていませんでした。

SpringBootアプリケーション側では明示的に設定ファイルや実行時引数でプロキシ設定を行わないとプロキシサーバーをいけないようです。

# SpringBootアプリケーションでプロキシ設定をする方法
### 1. System.setPropertyの利用

```java
// このケースではプロキシサーバーとして webcache.example.com:8080 を利用
// httpsの場合はhttps.proxyHost, https.proxyPortを利用します

System.setProperty("http.proxyHost", "webcache.example.com");
System.setProperty("http.proxyPort", "8080");
```

### 2. JVM起動時の引数として指定
Springアプリケーションの実行時引数として指定します

```java
java ./application.jar -Dhttp.proxyHost=webcache.example.com -Dhttp.proxyPort=8080
```

### 3. RestTemplateのインスタンス作成時factoryを利用して設定
1,2の方法だとシステム全体に影響を与えるので、影響範囲を限定したい場合にはこちらの方法を利用します。

```java
//ここでプロキシ設定を行う
Proxy proxy = new Proxy(Type.HTTP, new InetSocketAddress(PROXY_SERVER_HOST, PROXY_SERVER_PORT));

// RestTermplate用にプロキシ設定をするClientHttpRequestFactoryを用意する
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setProxy(proxy);

RestTemplate restTemplate = new RestTemplate(requestFactory);
// こちらのRestTemplateを利用してHTTP(S)通信を行う
```

# 参考リンク
* [RestTemplate による HTTP 通信の際に発生する様々なエラー (例外) を処理する]
(https://qiita.com/niwasawa/items/8647e8891954a88373be)
* [Java ネットワークとプロキシ](https://docs.oracle.com/javase/jp/7/technotes/guides/net/proxies.html)
* [Proxies With RestTemplat](https://www.baeldung.com/java-resttemplate-proxy)
* [Spring の RestTemplate のプロキシ設定](https://tc.hatenablog.com/entry/2014/06/13/221451)
30日でできるOS自作入門　第1～4日目の疑問点と回答

以前30日でできるOS自作入門という本を購入した。
本を読み進めながらちまちまとOSを作っているが、写経だけだと頭に入らないので引っかかったところなどを書いていくことにした。

<span style="font-size:large;"><strong>1日目</strong></span>
install.batを作成し、imgファイルをインストールしようとするとimgtol.comが動作しない。
64bitパソコンなので16bitのimgtol.comは互換性がないのだった。
qemuもうまく動かなかったのだが、同様の理由だろうか？
代わりに、フリーソフトのimageburnなどのソフトを使用してCDやUSBメモリに焼こうとしたが、ファイルが壊れていると表示されてうまくいかない。
原因は、imgファイルをCD向けのフォーマットとして認識しようとするが、作成したimgファイルはフロッピーディスク用のフォーマットになっているからであった。

解決策
Oracle VM VirtualBoxを使用する。
作成したimgファイルを仮想マシン上でFDDにマウントすればOK。
VirtualBoxの使い方はこちらを参考にした。
<a href="https://blog.binfish.jp/os/hello-world/" target="_blank" title="「30日でできる! OS自作入門」はじめました">「30日でできる! OS自作入門」はじめました</a>

<span style="font-size:large;"><strong>2日目</strong></span>
理解しやすい章。
Makefileのところは本筋からそれるので、さっさと付属ファイルのhelloos5から完成品をコピペしてくるのが吉。（細かく理解するのは後からでいいと思う）
ブートセクタは0x7c00～0x7dffに読み込まれる。

<span style="font-size:large;"><strong>3日目</strong></span>
p.55　アドレスを0x200進めると書いてあるが、0x20しかADDしてないよ？誤植？

<strong><span style="color:#FF0000">→</span></strong>ESの値は16倍で解釈されるので0x200の1/16である0x20でよい。

p.53「0x8000～0x81ffの512バイトにはあとでブートセクタの内容を入れようかな」
p.59「今のプログラムだと、ブートセクタの先頭がメモリの0x8000番地にくるような感じでディスクをメモリに読み込み終わっていますので」
ブートセクタは0x7c00に読み込まれてるんじゃなかったっけ？0x8000っていったいどこから出てきたの？

<strong><span style="color:#FF0000">→</span></strong>ポイントは0x8000番地に"くるような感じで"
実際には0x8000～0x81ffの512バイトにはブートセクタは<span style="color:#FF0000">入っていない。</span>
計算が楽なので、フロッピーのimgファイルの0x0000とメモリの0x8000を合わせたかった。
わざとブートセクタ分の512バイトをあけて、その続きの0x8200番地からはフロッピーの第2セクタ以降のデータを詰めた。
ちょっと筆者の説明が足りなかった。
<a href="http://hrb.osask.jp/wiki/?cmd=read&amp;page=qa_log%2F0007&amp;word=0x8000" target="_blank" title="0x8000のQ&amp;A">0x8000のQ&A</a>

<span style="font-size:large;"><strong>4日目</strong></span>
[ESP+4], [ESP+8]という番地が出てくるが、+4や+8になるのはC言語の仕様であり、筆者が意図してやったことではない。
staticは大量のデータを代入する際にRESB命令ではなく、まとめてDB命令で代入することでメモリ消費を防ぐために使っているらしい。
unsginedは正の整数を表す。今回は輝度の設定なので、0～255の数値を扱うのに適したunsgined型を使用。

p.87 <code>io_out8(～～, rgb[ ] / 4);</code>と、なぜか4で割っている。
これは今使っている画面モードだと、輝度が0～255の256段階ではなく、64段階になっているかららしい。
別の画面モードに変えれば /4 はいらなくなる。

CLI…割り込み禁止命令
R,G,Bの値を3連続で読み書きするので、邪魔が入らないようにする。

p90,91で新登場のIN,OUT命令の説明がない。
<strong><span style="color:#FF0000">→</span></strong>よく読むとp.88のC言語の説明の時に書いていある。

VRAMの番地 = 0xa0000 + x + y*320　の式はどうやって作られた？
それぞれの画素のデータが

```
番地 　　(x,y)
0xa0000 (0,0)
0xa0001 (1,0)
0xa0002 (2,0)
...
0xa0319 (319,0)
0xa0320 (0,1)
0xa0321 (1,1)
```
のように横一列ずつ順番に管理されているため。
<br>
p.93 第7節 「四角形を描く」のところで何度もエラーに悩まされた。
原因はboxfill8関数内の

```c
for (y= y0; y<=y1; y++) {
    for (x= y0; x<=x1; x++)
        vram[y* xsize + x] = c;
}
```
を

```c
for (y= y0; y<=y1; y++) {
    for (x= y0; x<=x1; x++) { //<-
        vram[y* xsize + x] = c;
    } //<-
}
```
と書いていたこと。
C言語のこと詳しくないけど、なんでこれがエラーになるのかが分からない。
ネストされていても、forの｛｝は必要そうな気がするのだけど。
誰か理由を教えてください。。。

とりあえずOS自作5日目以降をまた頑張ろう。
Tensorflowが動かない！

新しいノートPCに機械学習環境を一からセットアップして
いざ動かそう！って時に動かなかった…

色々と調べてみると結構設定がめんどくさかったです。
経験者からすればなんて事はないと思いますが
初心者だとなかなかハードル高い現象でしたので
メモ書きとして残します。

###PC環境
OS：Windows10 home 64bit
環境：Anaconda Navigator 
　　　Jupiter Notebook
GPU：Nvidia GTX1650

###初期設定
普通に[Anaconda Navigator](https://www.anaconda.com/products/individual)をインストール
この辺りは多くの情報がありますのでさほど難しくなかったです。

GPU用のCUDAやcuDNNのセットアップも実施していますが
そこは割愛します。(別途メモ書き予定)

###仮想環境作成
仮想環境を作成して作成した環境からコマンドプロンプトを立ち上げて必要分をインストール
`pip install tensorflow`や`pip install keras`等々のCNN作成に必要な物を
セットアップしました。

###現象
自分で真似して作ったプログラム
[CNNによる学習データ](https://qiita.com/bobrock/items/6ba346c6d1f777667a5b)
こいつのライブラリ関係を走らせてみるとエラー発生。

```Python:cnn.ipynb
import keras
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers.convolutional import MaxPooling2D
from keras.layers import Activation, Conv2D, Flatten, Dense,Dropout
from sklearn.model_selection import train_test_split
from keras.optimizers import SGD, Adadelta, Adagrad, Adam, Adamax, RMSprop, Nadam
from PIL import Image
import numpy as np
import glob
import matplotlib.pyplot as plt
import time
import os
```

エラーとしては
Using TensorFlow backend.
ERROR:root:Internal Python error in the inspect module.
Below is the traceback from this internal error.

文献としては結構出ていましたが具体的にどうしたのかを読み解くのに時間が掛かりました。
参考としては[Github](https://github.com/tensorflow/models/issues/8047)のエラー報告を見て四苦八苦しました。

###結果
Microsoftが配布しているVisual Studio 2015、2017 および 2019の再頒布プログラムが
インストールされていない為、動作する事が出来なかったようです。

Pythonからこの世界に入ると他の言語に触れることがないので
C++がないといかんなんて知らなかったです。

[Microsoftサポート](https://support.microsoft.com/ja-jp/help/2977003/the-latest-supported-visual-c-downloads)から
再頒布可能パッケージなる物をダウンロードしてインストールしたら動きました。

###まとめ
こういう世界はやり方が多数あるので
動けば正解と思いますが、初学者から見るとやはりどの手順が正解なのかを求めてしまいがち
１つ１つトライ＆エラーしかないですがそれにしてもわかりにくいと思う今日この頃です。

せめて残しているメモ書き位は自分自身でも振り返った時に混乱しない様に
分かりやすい手順を残さなければと思ったり思わなかったり…

以上です。
Codewars おすすめ勉強ツール


# はじめに

今回は、最近使い始めた勉強ツールの紹介です。
プログラミングスキル向上のため`codewars`(https://www.codewars.com/) を始めたので、簡単にですが、まとめていきます。

# Codewarsとは

開発スキル向上のための、コーディング道場(与えられた問題を解く)です。

他にも似たようなツールはありますが、`codewars`は、用意された問題をただ解いていくのではなく、 他のユーザが問題を作成し出題することができ、他の人の回答の中からユーザ投票で選ばれたベストプラクティスなども見る事が出来るのが特徴です。これによって、他の人がどのようにコードを書いたのか、様々なアプローチ方法を知ることができスキルの向上に努めることがきます。

### Kata

`codewars`ではkataと呼ばれるものが、問題を指しています。今では約4000以上ものKataが準備されています。

8kyu（8級）から1kyu（1級）までのランクに分かれた問題を解くことができ、解くことによって自分のkyuを上げていくことができます。

Kataを開くと、このようなページに飛び、左に問題文、右上にソースコード、右下にテストコードがあり、TESTボタンを押すと、実際にテストをすることができます。ATTEMPTを押すと、コードが提出され、正誤判定が行われます。その後、正解であれば下にも載せているのですが、他人のコードを見ることが可能となります。

(この画像の例は偶数の時にEvenを返し、奇数の時は、Oddを返すという問題です。)
![スクリーンショット 2020-09-27 18.23.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640758/39eeb3e9-d90e-fe07-71a8-1a282cf8b2a4.png)

### Kumite
他のユーザーと競い合って、より良いコードを目指そうとするモード。

Kataしかやっていないので、詳しくはわからないですが、中上級者向けのものに思います。

### コミュニテイ
`codewars`のコミュニティは活発でそこで質問したり、議論したりと積極的に活用していくことによって、問題解決の手助けとなります。

![スクリーンショット 2020-09-27 16.26.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640758/8c259430-2acf-87fd-6b70-76e4a4857ee1.png)

このように問題ごとに、議論する掲示板(Discourse)があり、他の人の解答やBestPracticeな解答をみたければ、Solutionsに行けば見ることができます。

![スクリーンショット 2020-09-27 16.32.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640758/83ae3bd9-4ca7-26d1-8477-cff42eacfd4f.png)

また、いつ作られた問題なのか、どれぐらい解かれているのか、何の言語で解かれているのか等、可視化されており、個人的に、正答率やどの言語が使われているのか見るのが面白いと感じています。

### 対象言語
codewarsでは対象になっている言語は30以上あり、人気の言語はもちろん他のあまりなじみのない言語まで使うことができます。

対応している言語一覧
![スクリーンショット 2020-09-27 13.52.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640758/c5d2233b-546b-6568-9082-4de5b49b2e6e.png)

# まとめ

`codewars`は他人とのコードの比較ができる事が魅力。 リファクタや知らなかった書き方等勉強になりますし、最初は難しいかもですが、処理速度も気にして問題を解けるようにしていきたいです。
毎日1～2題でも良いので、継続的にKataを解いていきたいと思います。


参考

https://github.com/codewars/codewars.com/wiki
Outlookアプリでメール送信時にCtrl+Enterキーを押した時に出るダイアログを表示させる

デスクトップ版のOutlookでメールを送信する際に「Ctrl+Enter」を押すと
「Ctrl+Enterキーを押しました。Ctrl+Enterキーをメッセージ送信のショートカットとして使用しますか？
　今後このメッセージを表示しない（チェックボックスで選択可）」とダイアログボックスが出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175699/2ec3af18-2406-3a3d-946e-885a9ad90463.png)

そこで「今後このメッセージを表示しない」へチェックを入れると、文字通り、以降このダイアログボックスは出てこなくなります。

先日、チェックボックスにチェックを入れてしまったけれど、またダイアログを出したいというユーザーが現れました。特に設定等もなかったので、マイクロソフトに問い合わせたところ、レジストリの書き換えが必要のよう。
>キー : HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\Outlook\Preferences
種類 : REG_DWORD
名前 : CtrlEnterSends
値 : [いいえ] を選択した場合は 0、[はい] を選択した場合は 1

>CtrlEnterSends に設定できる値
0 : Ctrl+Enter をメッセージ送信のショートカット キーに指定しない
1 : Ctrl+Enter をメッセージ送信のショートカット キーに指定する
2 : Ctrl+Enter キーでダイアログを表示する

今回は、「2」へ変更することで、再度ダイアログボックスが出るようになりました。みなさん むやみにチェック入れたりしないようにしましょうね。
Rust備忘録：crossで、ローカル上のクレートを使ってるアプリのコンパイル

# 状況
UbuntuからWin64向けにDLLを作成しようと[cross]でコンパイルしてみたが、相対パスで指定したローカル上のクレートが**見つからない**と怒られた。

# 注意
この記事の内容は**しょうもないミス**を繰り返さないための備忘録です。内容も**しょうもない**です。

# 解法
[cross]には指定したイメージを用いてコンパイルする機能があるため、必要なクレートを含んだイメージを作成し、そのイメージを使ってコンパイルする。

# イメージの準備

Win64へクロスコンパイルするときは次のようになる。

```dockerfile
FROM rustembedded/cross:x86_64-pc-windows-gnu

COPY ./クレートA /project/クレートA
COPY /home/develop/libs/クレートB /project/クレートB
```

コピー先のprojectとは[cross]がコンパイル対象を設置するフォルダである。[cross]はこの中であんなことやこんなことをしてるのだ。

もちろん`FROM`はコンパイル先に合わせて適宜変更すること。コロン（：）以下をtargetと一致させればよい。（と経験則から思ってるだけ。要確認）

あとは`docker build`してイメージを作る。ここではイメージ名を`saikyou-img`とする。

# Cross.tomlを作成
**Cargo.toml**ではない。そして**.cargo/config**でもない。

私は**Cross**.tomlだと気がつかず、ずっとCargo.tomlを変更して数時間ほど悩んでいた。

ということで、Cargo.tomlと同じ場所にCross.tomlを作成する。内容は次の通り。

```toml:Cross.toml
[target.x86_64-pc-windows-gnu]
image = "saikyou-img"
```

これで[cross]のコンパイルに`saikyou-img`が用いられるようになる。

# それでもクレートが見つからないと言われる
まず、私のように**Cargo.toml**を書き換えていないか確認しよう。イメージの指定は**Cargo.toml**ではなく

### Cross.toml

だからな？


それでも違ったら、コンパイル時に吐かれるエラーから、**コンパイラが参照しているパスに本当にクレートがあるか**を確認してほしい。

これはイメージからコンテナを作成し、lsして確認するとわかりやすい。

どうして、そんなパスの食い違いが起こるかは、例えば

```toml:Cargo.toml
[dependant.クレートA]
path = "../../../../../my-libs/クレートA"
```

なんてあったら、実際にコンテナ内で参照されるのは`/my-libs/クレートA`だ。projectディレクトリから4回上にあがってもルートディレクトリで止まりっぱなしだからだ。

ということで、クレートのコピー先は`Cargo.toml`の内容も吟味して設置しなくてはならない。



あとは、わからん。自力でガンバ！頑張る君はかっこいいぞ！

# 最後に
誰かが、こんなしょうもないミスを避けられたり、何時間もかけずに解決できたのなら幸いです。

どうか私みたいに、こんなしょうもないミスで何時間も消費しませんように。



[cross]:https://github.com/rust-embedded/cross
Teams内で作られるPower Apps「環境」について調べてみた

Microsoft Ignite 2020で発表になったTeams環境でのPower Appsアプリ作成機能ですが、新しいProject Oakdaleでの環境とCDSとの差がどこにあるのか簡単に調べてみました。

#■Power Appsアプリ作成
**・Teamsでテーブルを作成して、アプリケーションを作成して共有します。**
サンプルで顧客管理アプリを作りました。
![Power-Apps-Microsoft-Teams00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140547/50db6b18-9ad3-0892-bb88-72c64405fa37.png)

**・テーブルは適当ですがこんな感じです。**
![Power-Apps-Microsoft-Teams0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140547/82ea1869-70e1-f27a-bc80-07677c9712e7.png)

**・`[Teamsに公開]`ボタンから指定のチームのチャンネルを選び共有します。**
![-2-Power-Apps-Microsoft-Teams000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140547/81c3cd49-b713-10de-a5a1-e688654b47e5.png)

**・指定チームのチャンネルタブにアプリが追加されます。**
![-2-一般-全社員-Microsoft-Teams0000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140547/3c9a48ab-b941-544a-b1da-b5a2b8e86d5b.png)


#■環境を調べてみる
**・Teams環境は、どこにあるのか?**
Teamsには[環境]へのリンクが見当たらなかったので、Power Appsから見てみます。

メニューバー右上の`[歯車マーク]`から`[管理センター]`へ移動します
![Power-Apps.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140547/9059e4f8-097c-625b-55df-59619faaa074.png)

**・ここにTeamsのチーム名の環境が出来ていました。**
![CDSの環境メニュー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140547/14942446-c6fc-caed-9326-6a7e1c352873.png)

**・名前をクリックして環境を開きます。**
![Power-Platform-admin-center02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140547/7efd1682-297a-4c5e-2403-6c47bd3b9909.png)

**・CDS環境と比べると`[環境のオープン]` `[サンドボックスに変換]` `[コピー]`がないのがわかります。**(下記はCDS環境のメニューです）
![Oakdale環境でのメニュー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140547/d82c53fe-23af-ee3a-e9dd-c321a02332ab.png)

比べてみるとTeams環境ではCDSの「運用」状態で環境が作成されている様です。Oakdale環境ではサンドボックス環境に出来ないと思われるので、データに問題があったときに、一旦アプリを使えない様にする場合、何か手を考えなくてはならないかもしれません。

バックアップもきちんと取られていました。
![Power-Platform-admin-center2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140547/65aa7b7a-cd6d-c12f-f0a0-b9900a19c021.png)

試しにバックアップも戻してみましたが、、、、、
![Power-Platform-admin-center4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140547/adf414f6-f925-3e91-b980-272a34f9ff0e.png)
![Power-Platform-admin-center6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140547/5bd3fcff-5b91-ed26-87f7-45e6f23f68d1.png)

エラーがててしまいます。
![Power-Platform-admin-center6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140547/058dfc13-6d9f-3e86-63a6-88bef5050a26.png)
このまま再読み込みすると、きちんとバックアップのタスクはきちんと進んでいて、元通りに戻せたので、私の環境の問題かもしれませんが、機能的には全く問題ありません。


**・容量をチェックしてみます。**
左メニューから`[キャパシティー]`を選ぶと概要には通常のCDS環境が表示されていますが、タブにある`[Microsoft Teamsのキャパシティ使用状況]`を選ぶと、Teamsに作成した環境の容量が確認できます。
![Power-Platform-admin-center8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140547/da6d2bf1-6568-bcf1-7617-9e0812a2b281.png)
容量が２GBですが、初期設定時で１GBの容量が使われています。
残り容量の1GBで使えるレコード数の目安はデータインポート機能がないと、ちょっと試せないので、次回のアップデートに期待です。先日の吉田さんのYoutubeでは、レコード数は最大100万行とのことでしたので、かなり使えると期待しています。

個人的には先日、社内アプリを軽い気持ちで、複数テーブルの消去というカスタマイズをしていた際に、誤ってテーブルを全て消す、、、、、という冷や汗ものの💦大失態をしてしまったのですが、CDS環境で運用していましたので、バックアップも取られていて、サンドボックス環境に変換してから、サクッと元に戻せたので、Oakdaleにも同じバックアップがついていないか、とても気になっていたので試してみました。
Pythonによる素数判定

pythonを使った100以下の素数判定を３種類のやり方で実装してみました。
また、それぞれかかった時間も表示しました。

① print以外の組み込み関数を使わない(timeは除く）

```python

import time
n = 2

t1 = time.time()
while n <= 100:
    div = 0
    m = 1
    while m <= n:
        if n % m == 0:
            div += 1
        m += 1
    if div == 2:
        print(n)
    n += 1
time = time.time() - t1
print("time:{}".format(time))
```
実行結果

2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
0.007971048355102539



② １つずつ確認していく方法

```python
import time

def ma(n):
    sosu_list = []
    t1 = time.time()
    for n in range(2,n + 1):
        div = 0
        for m in range(1,n + 1):
            if n % m == 0:
                div = div + 1
        if div == 2:
            sosu_list.append(n)
    print(sosu_list)
            
t1 = time.time()
ma(100)
time = time.time() - t1
print("time:{}".format(time))
```
実行結果
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
time:0.0027151107788085938

③ エラトステネスの篩

```python
import time

def eratosu(n):
        sosu_list = []
        false = []
        for i in range(2,n+1):
            if i not in false:
                sosu_list.append(i)
                for j in range(i*i,n+1,i):
                    false.append(j)
        return sosu_list
    
t1 = time.time()
print(eratosu(100))
time = time.time() - t1
print("time:{}".format(time))
            
```

実行結果
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
time:0.0005650520324707031

①,②はtimeを比較すると基本的にあまり大きく変わりませんでした。ただ、②の方法は時々③に近いスピードが出ていて安定しませんでした。それに比べて③のプログラムはこの中で最も高速であるという結果が得られました。エラトステネスのふるいというアルゴリズムなのですが、とても効率的で計算量が少なかったためでしょう（wikiを参考にしたのでリンクを貼っておきます）

同じ結果を出力するプログラムでも、違う考え方で実装してみるのは考え方が深まって楽しいのでこれからも続けていきたいですね。

[エラトステネスの篩 Wikipedia](https://ja.wikipedia.org/?curid=147374"wiki")
Arduino - TB6612FNG(SparkFun ROB-14450)の制御方法

## 動機
SparkFun ROB-14450は小さく、2つのDCモーターを制御できるので重宝しているのだが、東芝のTB6612FNGのデータシートが少しわかりにくかったので駆け出しでも理解できるようにまとめた。

# ピンの役割
![symbol.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197942/112fddc9-7821-49c6-7765-fb17fe15829e.png)
1. VM - DCモーターの電源。最大13.5Vまで対応。一番下に許容動作範囲表を貼っておく。
2. VCC - ドライバ制御の電源。最大5.5Vまで対応。一番下に許容動作範囲表を貼っておく。
3. GND - VMとVCCのグランド
4. A01 - 1つ目のDCモーターのプラスを接続する。
5. A02 - 1つ目のDCモーターのマイナスを接続する。
6. B01 - 2つ目のDCモーターのプラスを接続する。
7. B02 - 2つ目のDCモーターのマイナスを接続する。
8. GND - VMとVCCのグランド
9. PWMA - 1つ目のDCモーターの回転速度の制御
10. AIN2 - 1つ目のDCモーターの制御
11. AIN1 - 1つ目のDCモーターの制御
12. STBY - モータードライバの制御の準備
13. BIN1 - 2つ目のDCモーターの制御
14. BIN2 - 2つ目のDCモーターの制御
15. PWMB - 2つ目のDCモーターの回転速度の制御
16. GND - VMとVCCのグランド 

- 同じGNDが3つあるがどれを使ってもよい。

## Arduinoでの制御
モーターの回転は付け方でそれぞれ変わると思うので前後左右の移動のプログラムから各自変更してほしい。
左右のモータは回転速度を同じにしていても実際は微妙に違う場合があるのでテストしながら確認する。

```io
// Arduino Nano
const int STBY = 3;     // モータードライバの制御の準備
const int AIN1 = 4;     // 1つ目のDCモーターの制御
const int AIN2 = 5;     // 1つ目のDCモーターの制御
const int BIN1 = 6;     // 2つ目のDCモーターの制御
const int BIN2 = 7;     // 2つ目のDCモーターの制御
const int PWMA = 9;     // 1つ目のDCモーターの回転速度
const int PWMB = 10;    // 2つ目のDCモーターの回転速度
void setup() {
    pinMode(STBY, OUTPUT);
    pinMode(AIN1, OUTPUT);
    pinMode(AIN2, OUTPUT);
    pinMode(BIN1, OUTPUT);
    pinMode(BIN2, OUTPUT);
    digitalWrite(STBY, HIGH); // スタンバイ
    pinMode(PWMA, OUTPUT);
    pinMode(PWMB, OUTPUT);
}
void loop() {
    // 前進（後進は全て逆にする）
    digitalWrite(AIN1, HIGH);
    digitalWrite(AIN2, LOW);
    digitalWrite(BIN1, HIGH);
    digitalWrite(BIN2, LOW);
    delay(1000);
    // 右回り（左回りは逆）
    digitalWrite(AIN1, LOW);
    digitalWrite(AIN2, HIGH);
    digitalWrite(BIN1, HIGH);
    digitalWrite(BIN2, LOW);
    delay(1000);
    // 回転速度を設定（0～255）まで
    analogWrite(PWMA, 50);
    analogWrite(PWMB, 50);
}
```

## H-SW 制御ファンクション
![ScreenShot_20200927203741.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197942/0e6f0a8c-31e6-9b7c-60a3-6608910fb10b.png)


## 許容動作範囲 (Ta = -20～85°C)
![ScreenShot_20200927193550.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197942/e0d5658c-8224-8fbe-743c-16fb47934a28.png)

## 最後に
自分はBCMをRaspberry Piのピン番号を基準として指定していたので動作せず、行き詰ってテスターを使ってようやく原因が分かった。
ArduinoはGPIOを基準に指定することを忘れないでほしい。
これから挑戦する人は同じようなトラップにかからないように願う。

## リファレンス
https://toshiba.semicon-storage.com/jp/semiconductor/product/motor-driver-ics/brushed-dc-motor-driver-ics/detail.TB6612FNG.html
https://componentsearchengine.com/part-view/ROB-14450/SparkFun
FCRN-DepthPrediction　深度推定

https://github.com/iro-cp/FCRN-DepthPrediction/issues?q=output
これで画像の深度を測定してみた。
ソースコードはこちら
https://colab.research.google.com/drive/19AsH-ILw5-hggEmVCLFPzdHDIcwsz77U?usp=sharing
FuelPHP Input::post 第2引数

Input::post には第2引数を設定でき、目的の要素が見つからなかった場合に返す値を設定できる。
これによって空かどうかなどの条件式を書く必要がなくなる。

```example.php
$number = \Input::post('number', 0);
//numberが見つからなかったら0を返す
```
GitHub Desktopでのローカルリポジトリの作成でエラー


【GitHub Desktopでのローカルリポジトリの作成でエラー】

①GitHub Desktopを起動

②Git管理したいフォルダをGitHub Desktopに追加。フォルダ をGitHub Desktopへドラッグ＆ドロップ。

③Add Local repositoryウィンドウが表示されるので、Create a repositoryをクリック。
クリックミスで、下の青いボタンのAdd repositoryを押してしまった。

【解決方法】
①ローカルリポジトリが対象よりもかなり広い範囲をリポジトリとしてしまっていたので、一度リポジトリの設定を消して作り直した方がよい。
.android というフォルダの一つ上のフォルダを突き止めて、そこから .git という隠しフォルダを削除することでリポジトリの設定を消す。

②.android というフォルダを探すためには、左のファイル一覧から適当なファイルを右クリックして "Show in Explorer" を選べばその場所が Explorer で開かれるので、そこからたどる。

④.android というフォルダの一つ上のフォルダに .git という隠しフォルダがある。隠しフォルダを見えるようにするにはこちら https://www.google.com/search?q=windows+%E9%9A%A0%E3%81%97%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80+%E8%A1%A8%E7%A4%BA を参照する。

⑤.git という隠しフォルダを見つけたら、それを削除するとファイルに影響を与えずにリポジトリの設定を消せる。これでもうリポジトリではなくなる。
あとは、正しいフォルダをもう一度ドラッグアンドドロップして Create a repository すればできる。
KaggleのNotebooksを、Google Cloud AI Notebooksで実行する際のつまずきポイントと対策

# 背景

- Kaggleでデータ分析したい！でも、KaggleのKernelだと計算リソースが足りず訓練時間がかかりすぎる・・・
- 計算リソースをアップグレードするため、Google Cloud AI Notebooksへ移行するリンクがあるのだが、移行が難しい！
- 移行リンクを紹介した後、移行のつまずきポイントと対策をまとめる

# 移行リンク

![コメント 2020-09-27 195726.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/749233/657c5bb7-aedc-43e7-7463-8a587a2dffb7.png)


# つまずきポイントと対策

## GPUを追加した環境を新規作成できない

### 症状

- エラーメッセージ"Quota 'GPUS_ALL_REGIONS' exceeded. Limit: 0.0 globally."が出る。

### 対策方針

- GPUを使うためには、GCPの割り当て制限数を引き上げないといけない。
- 制限数は、全域("all regions")と各リージョンの二種類について、引き上げる必要がある。

### 手順

- "IAMと管理" > "割り当て" 画面を開く
- 検索窓から、"gpu"で検索する★(gpuと検索しないと、GPUs(all regions)が出てこない！)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/749233/beea97f6-c715-1034-fe62-32d28f32e307.png)


## 既存のNotebooksへ移行する際、既存Notebooksの検索が終わらない

### 症状

- 下記画面のまま検索が終わらない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/749233/b3c61365-08a4-f19d-d1fc-55be8bb809bc.png)

### 対策方針と手順

- 検索条件"Environment: KaggleGPU"を消すと、作成済みのノートブックインスタンスが無事表示される。
- 表示されたインスタンスを選択すれば、Kaggleのノートブックをインスタンスで無事表示できる。

## デフォルトの初期化スクリプトを実行すると、Notebooksを停止した時に更新したデータが消えてしまう。

### 症状

- ノートブックインスタンスを停止すると、移行したはずのノートブックが消えてる！
![コメント 2020-09-27 201535.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/749233/1b065262-6e52-d29d-62f9-1624f0b5fc0f.png)

### 対策方針と手順

- 実は、Notebooksのデータ永続化用のボリュームは、"/home/jupyter"にアタッチされているのだが、移行された"imported"ディレクトリは、"/home/imported"に作成されてしまうため消える。
- つまり、作業用のデータは、"/home/jupyter"以下に置くようにすればよい。

### 手順

- 作成された"imported"ディレクトリを"/home/jupyter"以下に移動する。
- GCP上のノートブック内で、移行時に自動生成された初期化スクリプトの"KAGGLE_INPUT_PATH"の値を変更する。
ネットショップの会員管理（データベース）ー午後

応用情報技術者平成28年秋期 午後6

ファイル：2016h28a_ap_pm_qs.pdf

参照：
https://www.ap-siken.com/kakomon/28_aki/pm06.html

メモを簡単に記載します。
詳細の分析は、上記リンクをご参照くだいますようよろしくお願いします。

１、図2中のc，dに入れる適切な字句又は式を答えよ。なお，表の列名には必ずその表の別名を付けて答えよ。
ｃは合計ですね。
SUM(t4.商品単価×t4.個数)（私の答え）
→
SUM(t4.商品単価＊t4.個数)（参考答え）

本当は、＊ですね。×は答えとしては間違いはないけど、やっぱり＊を使いましょう。


＜＜過去の購入済み商品分類一覧を表示するSQL文＞＞
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/23d44919-ee8d-b441-da33-abb96c5dd3f5.png)

２、図3中のe～hに入れる適切な字句又は式を答えよ。なお，表の列名には必ずその表の別名を付けて答えよ。
gは　goukei >= 50000ですね。

当月の購入金額の合計が5万円以上であれば翌月の初めから月末までは特別会員　という説明がありますので。
ただ　以上　とは、＞＝　ですよ。

goukei > 50000（私の答え）
→
goukei >= 50000（参考答え）


＜＜会員種別判定処理＞＞
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/4410cff1-07d8-4455-b5c5-9d4c3f80c2b5.png)


３、〔会員種別の履歴の確認〕について，(1)，(2)に答えよ。
（１）追加するエンティティとの間に多対1の関連をもたせる既存のエンティティのエンティティ名を答えよ。
会員ですね。

（２）追加するエンティティに含めるべき属性名を全て答えよ。なお，主キーや外部キーであることを示す下線は付けなくてよい。
属性は、下記が必須ですね。
　会員番号
　会員種別
　適用日時

（私の答え）
会員種別の履歴ID
会員番号
会員種別
適用日時
→
（参考答え）
会員番号
会員種別
適用日時

会員種別の履歴IDは、必須ではないですね。


下記の主キーでいいですね：
会員番号
_______

適用日時
_______

会員種別



＜＜ER図＞＞
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/ce363892-eae1-3a97-3154-ceedcda09c2a.png)
SenseHAT でプログラミング教育用ゲーム

で、[また](https://qiita.com/atorii/items/e35212b2aae1c558c27c)ゲームを作ったので投稿します。楽しくなってきた。

最近流行りの、子供向けプログラミング教育用ゲームを作ってみました。
指定された場所へ移動するための経路を指示（プログラミング）するというあれです。
橙から青へ移動します。が、動かすだけだと縦横一直線になるので、障害物（緑）もつけてみた。

こっちは完全に逐次処理なので、イベントハンドラは使っていません。
ただ、慣性で動かす、というのはアリかも。

一応、小学生の娘は気に入ってくれた。ヨカッタ。
これでプログラミング学習ができるかは未検証。。

![IMG_5736.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238815/6f646841-564f-2545-56c2-12255b8db61b.jpeg)

```python
from sense_hat import SenseHat
from time import sleep
from random import randint

sense = SenseHat()
sense.clear()

red = (255, 0, 0)
blue = (0, 0, 255)
yellow=(255,255,0)
purple=(128,0,128)
green=(0,255,0)
indigg=(75,0,130)
orange=(255,128,0)
black=(0,0,0)

sense.set_rotation(0)

num_disturbs = 20

# スタートブロック（橙）をランダム設定
row_init=randint(0, 7)
col_init=randint(0, 7)
color_init=orange
sense.set_pixel(col_init, row_init, color_init)

# ゴールブロック（青）をランダム設定
row_target = randint(0, 7)
col_target = randint(0, 7)

# ゴールがスタート位置と同じにならないようにする
while row_target == row_init and col_target == col_init:
    row_target = randint(0, 7)
    col_target = randint(0, 7)

color_target = blue
sense.set_pixel(col_target, row_target, color_target)

# 妨害ブロックをランダム設定
disturbs = list()
for i in range(0,num_disturbs):
    while True:
        row = randint(0, 7)
        col = randint(0, 7)
        if row == row_init and col == col_init:
            continue
        if row == row_target and col == col_target:
            continue
        duplicated = False
        for j in disturbs:
            if col == j[0] and row == j[1]:
                duplicated = True
                break
        if duplicated:
            continue
        disturbs.append((col, row))
        break

color_disturb = green
for i in disturbs:
    sense.set_pixel(i[0], i[1], color_disturb)

# 移動方向をプログラミング
# 中ボタンで完了
commands = list()
set_com=True
while set_com:
    for event in sense.stick.get_events():
        if event.action == "pressed":
            if event.direction == "middle":
                set_com = False
            else:
                commands.append(str(event.direction))

row=row_init
col=col_init
color=red

# プログラミングした通りに、スタートブロックから動かす（赤）
for com in commands:
    sense.set_pixel(col, row, black)
    sense.set_pixel(col_init, row_init, color_init)
    if com == "up":
        row = row - 1
    elif com == "down":
        row = row + 1
    elif com == "left": 
        col = col - 1
    elif com == "right":
        col = col + 1
    elif com == "middle":
        row = row_init
        col = col_init
    if row > 7: row = 7
    if row < 0: row = 0
    if col > 7: col = 7
    if col < 0: col = 0
    sense.set_pixel(col, row, color)
    sleep(0.5)
    disturbed = False
    for i in disturbs:
        if col == i[0] and row == i[1]:
            disturbed = True
            break
    if disturbed:
        break

# 成否を判定
if row == row_target and col == col_target:
    sense.show_letter("O")
else:
    sense.show_letter("X")

sleep(3)
sense.clear()
```
HMSのプッシュ通知の実装説明（サーバー側）

# 前書き

[前章（HMSのプッシュ通知の実装説明（Android側））](https://qiita.com/Rei_2020/items/6210b169d1577371d588 HMSのプッシュ通知の実装説明（Android側）)ではHMSのプッシュ通知のAndroid側の実装について説明しました。本章ではサーバー側の実装について説明します。

# サーバー側の実装
サーバーでやることはたった２つだけです。

1. プッシュサーバーからアクセストークンを取得すること
2. プッシュサーバーにプッシュ通知を送ること

もっと具体的にわかりやすく説明すると、以下の２つのAPIを順番に叩くだけで、実装が完了します。

|順番|API|URL|説明|
|:---:|:---|:---|:---|
|1|アクセストークン取得|https://oauth-login.cloud.huawei.com/oauth2/v2/token|－|
|2|プッシュ通知送信|https://push-api.cloud.huawei.com/v1/[appId]/messages:send|[appId]はAppGallery ConnectのMy AppsのApp informationのApp IDです|


## プッシュサーバーからアクセストークンを取得

こちらはPOSTMANのスクリーンショットです。API実装経験がある方なら、これだけですぐ理解できると思います。

![access_token.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/0ce0c1d6-b010-9edf-027b-86d201807f10.png)

リクエストボディにAppGallery Connectに書かれているApp IDとApp secretを載せ、APIを叩けば、アクセストークンが返ってきます。

### リクエスト
API：https://oauth-login.cloud.huawei.com/oauth2/v2/token
メソッド：POST
Content-Type：application/x-www-form-urlencoded

リクエストボディ：

|キー|値|
|:---|:---|
|grant_type|“client_credentials”で固定|
|client_id|AppGallery ConnectのMy AppsのApp informationのApp ID|
|client_secret|AppGallery ConnectのMy AppsのApp informationのApp secret|

### レスポンス
Content-Type：application/json;charset=UTF-8

|キー|値|
|:---|:---|
|access_token|アクセストークン|
|expires_in|アクセストークンの有効期限（秒）|
|token_type|Bearerで固定|

## プッシュサーバーにプッシュ通知を送信
![push_token_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/c4e36b9c-a9da-ec13-b05e-f3c972c21268.png)
![push_token_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/4ef5f698-25dc-b0cf-a064-1da879b42cdf.png)

リクエストヘッダーに先ほど取得したアクセストークンを載せ、リクエストボディにプッシュ通知内容を載せ、APIを叩けばよいです。

### リクエスト
API：https://push-api.cloud.huawei.com/v1/[appid]/messages:send
[appid]はAppGallery ConnectのMy AppsのApp informationのApp IDです

メソッド：POST
Content-Type：application/json

リクエストヘッダー

|キー|値|
|:---|:---|
|Authorization|アクセストークン|

リクエストボディ：
JSONになります。パラメータが多すぎるので、オフィシャルサイトをご参照ください。
https://developer.huawei.com/consumer/jp/doc/HMSCore-References-V5/https-send-api-0000001050986197-V5

## AppGallery Connect

App IDとApp secretはAppGallery Connectに載っています。

![AppGallery Connect - My apps.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/f287684e-15d8-438b-b364-69771090dbb0.png)


# まとめ
サーバー側の実装は、プッシュ通知の送信部分に関しては、この２つのAPIの使い方さえ押さえれば、難しいことではないでしょう。

# 参考
* オフィシャルのデモ（クライアント）：[https://github.com/HMS-Core/hms-push-clientdemo-android](https://github.com/HMS-Core/hms-push-clientdemo-android)
* オフィシャルのデモ（サーバー）：[https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Examples-V5/server-sample-code-0000001050986079-V5](https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Examples-V5/server-sample-code-0000001050986079-V5)
Laravelのクエリビルダの中にCASE文を使いたい場合の書き方

laravel 7.0
PostgreSQL 12.2

下記コードのようにselectRaw()を使うことで、クエリビルダの記述中に生SQL文を使うことが可能です。

例）
Usersテーブルにgender_idというカラムがり、gender_idの値から性別を文字列に変換して取得したいと思った場合の処理。


```
$result = $users->select('name')
                  ->selectRaw("(CASE gender_id WHEN 0 THEN "男性" WHEN 1 THEN "女性" END) AS gender")
                  ->get();
```

データとしては下記のようになります。
<table>
<thead><th>name</th><th>gender</th></thead>
<tbody>
<tr><td>山田太郎</td><td>男性</td</tr>
<tr><td>山田花子</td><td>女性</td</tr>
</tbody>
Pythonでフォルダ内の～.xlsxの中身をHTMLに出力する

# やりたいこと
フォルダ内に大量にExcelで作ったファイルがありどれがどれかわからないようになったときに「一つずつ調べるのはだるいな」という気持ちになりません？
そこでフォルダ内の～.xlsxのファイルすべての頭のほうだけHTMLにして出力してやります。
![やりたいこと.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213259/8d3edc3b-d794-2ff1-61e7-af9db0d44707.png)

これで探しているファイルがどれかわかって手間も多少は省けるはず…
# 利用するライブラリなど
Windows 10上でPython 3.8で実行しています。

<dl>
<dt>os</dt>
<dd>フォルダ移動のために利用</dd>
<dt>glob</dt>
<dd>フォルダ内のファイルを調べるために利用</dd>
<dt>io</dt>
<dd>ファイルへの書き込みのために利用</dd>
<dt>pandas</dt>
<dd>.xlsxの読み込み・HTMLへの変換</dd>
<dt>webbrowser</dt>
<dd>出力したHTMLをブラウザで開くために利用</dd>
</dl>

# ソースコード
ソースコードは以下の通りです。

```python:
import glob
import io
import os
import webbrowser
import pandas as pd

folder = input('フォルダパスを入力してください\n')
os.chdir(folder)

files_in_folder = [i.lstrip('.\\') for i in glob.glob("./*")]
xlsx_in_folder = [i for i in files_in_folder if i.endswith('.xlsx')]  # .xlsx終わりだけ残す

with io.StringIO() as s:
    s.write('<!DOCTYPE html>\n<html lang="jp">\n<head>\n\t<meta '
            'charset="UTF-8">\n\t<title>.xlsxサマリ</title>\n</head>\n<body>\n')
    s.write('<h1>.xlsxサマリ</h1>\n')

    # .xlsxを読み込んで頭5行・頭3列をhtmlにしたものを出力--ここから
    for i in xlsx_in_folder:
        s.write('<br>\n')
        s.write(i)  # ファイル名
        s.write(pd.read_excel(i, header=None, usecols=[0, 1, 2]).head().to_html(header=None, index=None))
    # .xlsxを読み込んで頭5行・頭3列をhtmlにしたものを出力--ここまで

    s.write('</body>\n</html>')
    output = s.getvalue()

with open("output.html", mode='w', encoding='utf-8') as f:
    f.write(output)

webbrowser.open("output.html")

```

# 出力
こんな感じでHTMLが出力され、既定のブラウザで開かれます。
![memo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213259/6cc0dbbb-61ec-6548-8905-9f5d8bc61bdf.png)
macbook上にSeleniumとChromeDriverをインストールする

pythonは入っている前提で

##seleniumをインストールする
```
pip install selenium
```
これはかんたん

##Chromedriverをインストール
Chromeを使って操作したいので、ドライバーをインストール

```
brew tap homebrew/cask
brew cask install chromedriver
```
<font color="red">2021/01/12　caskによるinstallは禁止されたようなので、動かない場合はcaskを省略してください</font>
インストールに成功すると「ここに入れたよ」というパスが表示されるのでメモっておく
自分の場合は「/usr/local/bin/chromedriver」

##あとはゴリゴリpythonに書いていく

```
import time
from selenium import webdriver

driver = webdriver.Chrome('/usr/local/bin/chromedriver')
driver.get('https://www.google.com/')
time.sleep(5)
driver.close()
```
sample.pyというファイル名にして

```
python sample.py
```
を実行すると、Chromeが起動してGoogleが表示されるはずです

##chrome driverのアップデート
ブラウザとchromedriverのバージョンが一致しない場合などに使います
chrome driverのバージョンをアップデートしたい場合は

```
brew reinstall chromedriver
```
これでいけます


##chrome driverのアップデートを自動化する
webdriver_managerを使います

```
pip install webdriver-manager
```
webdriver-managerをインストールしたらプログラムを書き換えます
▼before▼

```
import time
from selenium import webdriver

driver = webdriver.Chrome('/usr/local/bin/chromedriver')
driver.get('https://www.google.com/')
```

▼after▼

```
import time
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get('https://www.google.com/')
```
これでプログラム実行時に勝手にchrome driverがアップデートされます