OmniAICreator/Qiita-1.07M huggingface dataset:
webpack5で「Module not found: Error: Can't resolve "○○"」というエラーが解消しない場合の対処方法

最近、webpack ver.4 -> ver.5 にアプデした途端に、ビルドエラーが起きるようになったが、
原因がわかりにくかったのでメモ書き

# 背景
webpack4でWeb開発していましたが、
yarn audit で webpack4の脆弱性警告発生
脆弱性対応のためにwebpack4->webpack5 にアプデすることになった

# 問題
webpack のメジャーバージョンアップ ということで、以下の手順書を読みながら移行
https://webpack.js.org/migrate/5/

webpack.config.js で、loaderをuseに手動で変更する必要があった点などわかりにくいので注意
（options 引数が無い場合、loader は使えないらしい）
まあこの辺はビルドエラーメッセージに出てくるので恐らく大丈夫だと思います

一通りの手順を踏んだが、以下のエラーが発生（○○○には、ファイルパスが入ります）

```
Module not found: Error: Can't resolve "○○○"
```

What's?

# 解決方法
ググってみても、似た問題はたくさんヒットするが、解消できる記事は見当たらず

webpackの実行時のコンソールログを出しまくって解析
どうやら、「○○○」というファイルに記載されている型定義が読み込めていない模様

そのファイルをimport している箇所を検索して見比べてみると、
ファイルパスの末尾にスラッシュが入っているかどうかにバラつきがあった

```
import { ○○○ } from '○○○';
```

or

```
import { ○○○ } from '○○○/';    // ←この書き方だとNGの場合がある
```

末尾のスラッシュを除去すると、webpackのビルド成功

Why?

# 原因
原因は、webpack4では問題なかった import の書き方が、webpack5になったタイミングで問題になったこと

###### import の書き方の問題とは？
import するファイルのファイルパスの末尾にスラッシュを付けると、
webpack4 まではいい感じに型定義を探してきてくれたが、
webpack5 になると、必ず 「○○○/index.d.ts」 を探しにいってしまうようになった

パッケージのフォルダ構成次第で、○○○/index.d.ts に型定義が入っていないものがあると、そこでimport エラー
スラッシュを除去したファイルパスにすれば解消した
（もしくは、型定義ファイルindex.d.ts への正しいファイルパスを入れてもOK）

今回我々の例だと、kintoneのUIライブラリ（kintone-ui-component）でimport エラー
○○○/index.d.ts ではなく、その下に掘られたフォルダ内に型定義ファイルが存在していた

###### なぜこの問題がわかりにくいのか

まず、エラーメッセージが、OSSで「○○○の定義がありません」と出るので、
OSSに問題があるのでは？とyarn install し直したりキャッシュを削除したりNodeを入れ直したりといった
誤った対処方法を取ろうとしてしまいがち
OSSには問題がないので、上記対処方法をとっても解消しません

さらに、この原因をわかりにくくしている要因として、
最初にパッケージをimport した時点で問題ない場合、
その後のimport でファイルパスの書き方に問題があってもimportエラーが起きない（！！）
※webpackが一度型定義を読み込めたらそれを流用するためだと考えられる

ファイルパスの末尾のスラッシュ有無にバラツキがあると、ビルドが成功したりエラーになったり
実装状況や環境によって変化する


# まとめ
###### import文のファイルパスの末尾スラッシュは付けないのが正しいんだろう

webpack5にあげた途端に急にimportエラーでビルドエラーが起きるようになった件に対して、
import しているファイルパスの末尾スラッシュを除去すると解消するかも


同じお悩みを抱えて検索して来てくださった方のお役に立てればと思います
参考になったという方はGoodボタン押して頂けると嬉しいです
【AtCoder】ABC211をPython3で解説

ABC211の解説。

https://atcoder.jp/contests/abc211

## A - Blood Pressure
### 解説
平均血圧を式のとおりに実装すればAC。

$C = \frac{A-B}{3} + B$

### コード

```python
a, b = map(int, input().split())

print((a-b)/3+b)
```

## B - Cycle Hit
### 解説

$4$つの文字列のなかに、```H```、```2B```、```3B```、```HR```が$1$つずつあるか判定する問題。
各文字列をリストに入れて、それぞれを```count```してすべて1であれば、```AC```である。

また、リスト自体を比較するというやり方もある。

### コード1
```python
slist = list(input() for _ in range(4))

if slist.count('H') == 1 and slist.count('HR') == 1 and slist.count('2B') == 1 and slist.count('3B') == 1:
    print('Yes')
else:
    print('No')
```

### コード2

```python
slist = list(input() for _ in range(4))
alist = ['H', 'HR', '2B', '3B']

sort_slist = sorted(slist)
sort_alist = sorted(alist)

if sort_slist == sort_alist:
    print('Yes')
else:
    print('No')
```

## C - chokudai
### 解説

文字列```S```から8文字選び下線を引き、その文字が左から```c, h, o, k, u, d, a, i```になるものは何通りあるかという問題。

この問題は**DP（動的計画法）**を用いることで求めることができる。今回は、公式解説にそって解説をしていくので、事前にこちらの解説動画を御覧いただきたい。

AtCoder Beginner Contest 211 C問題 解説
→https://www.youtube.com/watch?v=Zu9S_kJ-7tk

見ていただいたものはC++という言語で書かれているが、それをPythonに翻訳したものが以下のコードとなる。動画でやっていることをそのまま再現したものとなっている。

途中で```copy()```というものが入っているが、これは、2次元リストの書き換えが起こらないようにしたものである。答えには影響がないので、特に気にする必要はない。

また、今回の問題は競プロ典型90問の8問目と全く同じ問題なので、そちらも確認しておくことをおすすめする。

### コード
```python
import copy

s = input()
lens = len(s)
dp = [[0]*9]*(lens+1)

for i in range(lens+1):
    dp[i][0] = 1

MOD = 10**9+7
t = 'chokudai'

for i in range(lens):
    dp[i] = copy.deepcopy(dp[i])
    for j in range(8):
        if s[i] != t[j]:
            dp[i+1][j+1] = dp[i][j+1]
        else:
            dp[i+1][j+1] = (dp[i][j+1] + dp[i][j]) % MOD

# 確認用コード
# print(dp)

print(dp[-1][-1])
```

## 編集後記
今回のC問題はコンテスト後に物議を呼んだ。
**理由は、競プロ典型90問の8問目と全く同じものだったからだ。**

問題はこちら。

https://atcoder.jp/contests/typical90/tasks/typical90_h

この問題を解いていた人と、解いていなかった人で、差が生まれてしまうではないか！と議論になっていた。そんなことにならないためにも、少しずつでもいいので典型90問を解いておくことをおすすめする。
$ git commit  *** Please tell me who you are.


```
$ git commit


*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'XXX@XXX.(none)')


```

##対処法

```
# ユーザー名を設定する
% git config user.name "{ユーザ名}"　
# メールアドレスを設定する
% git config user.email "{メールアドレス}"

```
「メアドや名前はカンマ入れない
【Google Cloud Day'21】「メルカリ流 Google Cloud のサポート活用術」を視聴して


メルカリ流 Google Cloud のサポート活用術
https://cloudonair.withgoogle.com/events/google-cloud-day-digital-21/watch?talk=d3-appdev-01
ビジネスで Google Cloud を利用する上で欠かせないサポート。本セッションでは Google Cloud のサポートサービスの概要と利用例をご紹介するとともに、メルカリにおける活用術を共有します。

<table>
	<tr>
		<th>切り口</th>
		<th>内容</th>
	</tr>
	<tr>
		<th>一般的なフェーズごとに求めるサポートの違い</th>
		<td></td>
	</tr>
	<tr>
		<th>Googleサポートの違い</th>
		<td></td>
	</tr>
	<tr>
		<th>メルペイの事例</th>
		<td>メルカリはメルペイを構築し始めたころにプレミアムサポートに入った。メルカリ側の要望はあったが、どうやって構築すればいいか決めかねていた。そこで現地に行ってMTGができたのがよかった。要望も出しやすかった。構想が固まってるとプレミアムサポートを使う意味がありそう。</td>
	</tr>
	<tr>
		<th>TAMについて</th>
		<td>Google内部の情報も積極的に共有してくれる。</td>
	</tr>
</table>

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/4af655bc-34aa-dee3-53f8-8d4d82d752b2.png)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/5ba84d88-c8f2-40ed-0dec-950ba8647903.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/c1ad1895-e819-8f5f-b1c8-3eef89a71509.png)
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/84fce654-2663-ea43-8ac0-7dea9acf3b4b.png)
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/9399a2f7-3658-8b69-020b-60577b1d7744.png)
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/08fbb9e0-3aa6-8908-9512-0a47a3066fe1.png)
【Google Cloud Day'21】「Citrix と Google のソリューションで、安全で快適なデジタルワークスペースを実現する」を視聴して

Citrix と Google のソリューションで、安全で快適なデジタルワークスペースを実現する
https://cloudonair.withgoogle.com/events/google-cloud-day-digital-21/watch?talk=d1-gl-25
"社員の生産性向上や優秀な人材の確保のため、リモートワーク環境の導入に代表されるように、社員の働きやすい環境を企業が整えことの重要性がさらに高まっています。このセッションでは、Citrix Cloud で提供されるソリューションが、Google Cloud、Chrome Enterprise、Google Workspace と連携し、安全で快適なデジタルワーク スペースを提供する例を紹介します。
"

<table>
	<tr>
		<th>切り口</th>
		<th>内容</th>
	</tr>
	<tr>
		<th>会社概要</th>
		<td></td>
	</tr>
	<tr>
		<th>仮想クライアント</th>
		<td>HDXは独自開発のプロトコル</td>
	</tr>
	<tr>
		<th>citrix cloudの機能</th>
		<td></td>
	</tr>
	<tr>
		<th>citrix cloudとGoogle Cloudの構成</th>
		<td>CheomeBookとも連携可能。このときは、IAPを利用する。</td>
	</tr>
</table>

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/53b80aa7-b318-9ae6-368b-8ad204bfbb18.png)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/1d1d0a46-7d92-8e27-6c07-d046fcd49663.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/5526a069-47b5-84ba-4895-c53178fdec83.png)
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/17e9d1ac-0153-c177-e512-16b519ed1378.png)
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/e149f830-38be-4625-7e15-f2a00b2961cc.png)
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/eceda696-95d2-3d11-9286-7f49d229f9cb.png)
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/408eebbc-76a3-84c7-0aa3-c099c37cdff7.png)
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/a74c73e6-5862-bb6b-5d6a-f8d23c651e1a.png)
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/d952d784-35b3-9786-acf6-6203d1b2b00c.png)
Laravel用パッケージでArtisanコマンドを書く場合のテスト

# 発生事象
Laravel用のパッケージを書いていて、コマンドを追加したのでテストしてみるぞ～、と思ったら、以下のようなエラーメッセージが出た。

~~~ sampleTest.php
//テストはだいたいこんな感じ
class SampleTest extends \Orchestra\Testbench\TestCase {
    public function test_command(){
        $this->artisan('nice:easy')->assertExitCode(10);
    }
}
~~~

~~~
Symfony\Component\Console\Exception\CommandNotFoundException: The command "nice:easy" does not exist.
~~~

コマンドを認識していないようだ。

# 結論
ココを見ましょう。
https://orchestraplatform.readme.io/docs/testbench#section-custom-service-providers
https://orchestraplatform.readme.io/docs/testbench


> To load your package service provider, override the getPackageProviders()
 
おまえのパッケージのサービスプロバイダをロードするには、getPackageProviders() をオーバーライドせい、ということで、解決。


# 補足
## コマンド登録はパッケージのサービスプロバイダに書く
Artisanコマンドを提供するようなLaravel用パッケージを作成する場合、パッケージ側にサービスプロバイダを用意して、「この辺のクラスをArtisanコマンドに追加せよ」という情報を、利用側のLaravel本体に知らせる必要があります。

=>このへんの話
https://laravel.com/docs/8.x/packages#commands
https://readouble.com/laravel/8.x/ja/packages.html#commands

## パッケージ開発のテストには orchestral/testbench を使う
Laravel用パッケージを開発する場合、Testには
https://github.com/orchestral/testbench
を使いましょう。

=>このへんの話
https://readouble.com/laravel/8.x/ja/packages.html#a-note-on-facades


## FeatureTestですよ、という話

そもそもの話として、Artisanコマンド（Illuminate\Console\Command を継承したクラス）に対してUnitTestを書こうとすると、色々と面倒なことになる（何が面倒なのか書くのもめんどい）。

Artisanコマンドを書く場合は、責任の範囲を画面との入出力のみに限定し、それ以外の処理に関しては適切に移譲するように注意しする。

端的には、Illuminate\Console\Command を継承して作成するクラスは、ViewとControllerに相当するもの、と扱っておけばよい。（なので、Artisanコマンドに対するテストは、UnitTestでははなくFeatureTestです。）

## Commandのコンストラクタをオーバライドするなよ、という話
ちなみに、Illuminate\Console\Command を継承してクラスを作成する場合は __コンストラクタをオーバーライドしてはいけない__。

理由はこちら https://qiita.com/k-kurikuri/items/cec750ec3d21c6319253 

移譲先のオブジェクト生成は、handle()メソッドの先頭で行うようにしておくのが良いと思う。

~~~ SampleCommand.php
class TemplateList extends Command
{
    /** @var string $signature */
    protected $signature = 'big-na-otoko:do-it';
    /** @var string $description */
    protected $description = '将来なにかデカイことをやるコマンドです';
    /** @var NiceService $service */
    private $service;

    /**
     * @return void
     */
    public function handle()
    {
        try {
            $this->init();
        } catch (\Throwable $e) {
            $this->error($e->getMessage());
            return 1;
        }
        //以下に、入出力に関する処理とサービスの呼び出しなどを書いて適宜実装していく
    }

    /**
     * @return void
     */
    private function init(): void
    {
        $this->service = App::make(NiceService ::class);
    }
}
~~~

こんなノリで書いておけば、だいたい問題なくテストできるはず。
PostgreSQL

データベース起動

```
psql -U postgres
```

データベースバージョン確認

```
psql --version
```

# データベースの作成

```
CREATE DATABASE [database名] ;
```

ユーザ切り替え

```
\connect - <ユーザ名>
```

データベース表示

```
¥l
```

#macOS の場合 起動

```
brew services start postgresql
```

# 起動

```
$ rm -f /usr/local/var/postgres/postmaster.pid
$ brew services start postgres
```

# 停止

```
brew services stop postgresql
```

#下記エラー等発生時解決コマンド

psql: error: could not connect to server: No such file or directory

```
brew services restart postgresql
```



PostgreSQL のユーザーには、つぎの 3 種類があります。
一般ユーザー
DB 作成権限ユーザー
スーパー･ユーザー (DB 作成に加えて、ユーザー作成もできる)
config gem と dotenv-rails gem を共存させるときの ポイント

Rails での開発では、以下の2つのgemを使い分けたり、併用して設定情報を管理する方が多いかと思います。

- config gem  
  yaml 管理
- dotenv-rails gem  
  .env(及び環境変数) での管理

ですが、「設定情報を、 yaml に記載したのか、.env(及び環境変数)に記載したのか?」と分からなくなり手が止まる瞬間があります。
なので、最近は config gem を介して .env を参照するようにして、設定情報の参照先を一本化しています。
その中で、以下の 2 つのポイントのどちらかを押さえておかないとエラーになることを確認したので、共有します。

# 実行環境

- Ruby 3.0.0
- Rails 6.1.4

# 前提

読み込みの対象になる yaml と、.env ファイルは以下のものになります。

```yaml
# config\settings.yml
comment: これはテスト用アプリ

# .envに記載した環境変数 SAMPLE_API_KEY の内容を読み込む
sample_api_key: <%= ENV.fetch('SAMPLE_API_KEY') %>
```

```ruby 
# .env
# config\settings.ymlから参照される 
SAMPLE_API_KEY=sample_api_key
```

# 注意するポイント

次に示す 2 つプランのうちどちらかを守らないと、以下のようなエラーになります。

```sh
# エラー内容
(erb):2:in `fetch': key not found: "SAMPLE_API_KEY" (KeyError)
```

## プラン A：Gemfile で dotenv-rails gem を先に記述する

Gemfileにて、`dotenv-rails` gem を読み込んでから `config` gem を読み込むようにします。これだけでエラーを回避できます。

```ruby
# NG
gem 'config'

gem 'dotenv-rails'

# OK

gem 'dotenv-rails'

gem 'config'
```

## プラン B：yaml ファイルでロードメソッドの実行する

gemfile での、記述の順番に配慮しなくても yaml 内で、`Dotenv::Railtie.load` を実行することで、エラーを回避して読み込みできます。
プランAと比べて、明示的に .env が参照されていることがわかるという利点があります。

```yaml
# <% Dotenv::Railtie.load %> を追加する
<% Dotenv::Railtie.load %>
comment: これはテスト用アプリ
sample_api_key: <%= ENV.fetch('SAMPLE_API_KEY') %>
```

---

それでは皆さん、安全で便利に設定情報を管理していきましょう。
【UiPath】invoke workflowの怖い話

# はじめに

この投稿は、RPAツール「UiPath」の ナレッジメモ の記事です。

UiPathのコミュニティ「UiPath Friends」が企画する「UiPathブログ発信チャレンジ2021サマー」の 26日目の投稿でもあります。

企画の内容は [**こちら**](https://note.com/shumpei_w/n/n651cbdbec4e8) 。カレンダーのURLは [**こちら**](http://u0u1.net/sUwZ) です。

https://twitter.com/ShumpeiWatanabe/status/1405168150736359427

# invoke workflowの罠

invoke workflowで、私が実際に経験した「怖い話（困った話）」を3つ紹介します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/80b402da-d14a-c76a-3559-529ced1df379.png)

思い出すだけで (((( ；ﾟДﾟ)))))))ｶﾞｸｶﾞｸﾌﾞﾙﾌﾞﾙｶﾞﾀｶﾞﾀ 

「ワークフローファイルを呼び出し (Invoke Workflow File)」アクティビティの公式説明はこちら

https://docs.uipath.com/activities/lang-ja/docs/invoke-workflow-file

高度に使用するための参考（公式）記事はこちら

https://www.uipath.com/ja/blog/developer/invoke-workflow-file-tips


# 罠1）DataTableは「呼び出し先での変更」の影響を受ける

これは有名な話ですが、

```
(;Д;)ヒィィ!
　引数に DataTable型を指定する場合、引数の方向が「In」に指定しても、
　呼び出し「先」で DataTable の中身を変更すると、
　呼び出し「元」の DataTable も変更される。
　（引数の方向が「In」なら、影響を受けないはずなのに）
```

という話です。
そもそも「Inで指定しておいて、何で変更するの？」というほうが怖いですけれども。

DataTable型に限らず、シリアライザブルではない型は、影響を受けてしまいます。
多分、以下の制約を受けているのだと思います。

:::note warn
UiPathの元になっている「C#やVB.NET」では、値そのものを（別の変数で）コピー（ディープコピー）したい場合に、オブジェクトをシリアライズし、それを別オブジェクトにデシリアライズする方法があるが、そのためには、シリアライザブルな型である必要があります。
:::

要するにin方向の引数でも、型によっては変更の影響を受けるということです。（値渡しではなく、参照渡しになってしまう。）


これを回避するには、以下のいずれかの方法があります。

:::note info
【回避方法】
　1）引数で「.copy」してデータテーブルの複製を渡す（※）
　2）分離で実行する
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/332518a3-66df-000f-9dc5-2a8875a76662.png)

※ .copy：データテーブルを複製。複製版を引数で渡すので、元のデータテーブルに影響が出ません


# 罠2）引数の「サイズ」が大きいとエラーになる

これはレアな話ですが、

```
(;Д;)ヒィィ!
　引数で返すデータのサイズが大きいと、フローの呼び出し完了時に
　大きすぎて処理できないエラーになることがある。

＜エラーメッセージ＞
RemoteException wrapping System.Exception: 
ジョブの実行結果を取得できませんでした。
メッセージが大きすぎて処理できなかったことが原因である可能性があります。
```

というものです。残念ながら、発生原因や再現方法が掴めていないのですが、その時のメモリ使用量と関係しているような気がします。（メモリの余裕がないときに、大きなデータを引数で返すとエラーになる？）


これを回避するには、以下の方法があります。

:::note info
【回避方法】
1）再起動、リトライしてみる
2）引数のデータサイズを減らしてみる（呼び出しを複数回にするなど）
3）フローを呼び出さず、同じフローで処理する（残念）
:::


# 分離実行の場合、シリアライズできない型は引数にできない

これもレアで、分離実行しないとお目にかからないです。

```
(;Д;)ヒィィ!
　フローを分離実行で呼び出す時に、
　引数の型でオブジェクトのシリアル化および逆シリアル化をサポートしていないものは
　引数に指定できない。例えば「UI ブラウザー、UI 要素」等が該当します。
```

誤って指定すると、参照したときに「NullReferenceException: オブジェクト参照がオブジェクト インスタンスに設定されていません。 」エラーになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/47a72c21-0920-916b-fe4a-6605cb798520.png)

これを回避するには「分離実行をしない」ように設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/24d8b36a-19d4-ba93-5ff0-02d01ee9c4c5.png)


# 終わりに

いかがでしたでしょうか。困った際の参考になれば幸いです。
この記事が参考になったら、 LGTMをお願いします。閲覧ありがとうございました。
【JavaScript】配列の操作（forEach map filter reduce）の使い方

#初投稿
アウトプットが苦手な自分が練習の一環として記事を書いてみる。


第一回目はJavaScript配列の操作（forEach map filter reduce）の使い方について書いていく。


# forEach

配列の各要素に対して関数を1つずつ実行するメソッド
※後述するmapやfilterと違い新しい配列を作成しない。

```javascript:forEach
const arr = [10, 20, 30, 40, 50];

arr.forEach(function(elm) {
    console.log(elm);
});
// 実行結果
// 10
// 20
// 30
// 40
// 50
```


# map
配列の各要素に対して関数を1つずつ実行し、戻り値を元に新しい配列を作成するメソッド

```javascript:map
const arr = [10, 20, 30, 40, 50];

const result = arr.map(function(elm) {
    return elm * 2;
});

console.log(result);
//　実行結果
// [ 20, 40, 60, 80, 100 ]
```

# filter
配列の各要素に対して関数を1つずつ実行し、戻り値を元に新しい配列を作成するメソッド

mapと違い、戻り値が「true」の要素のみで配列を作成する。
※作成した配列の値は関数実行時の要素の値が格納される。


```javascript:filter
const arr = [10, 20, 30, 40, 50];

const result = arr.filter(function(elm) {
    return elm > 29;
});

console.log(result);
// 実行結果
// [ 30, 40, 50 ]
```


# reduce
配列の各要素に対して関数を1つずつ実行し1つの値を取得するメソッド
~~※使ったことなかったので使い方を調べた~~

```javascript:reduce
const arr = [10, 20, 30, 40, 50];

const result = arr.reduce(function(a, b) {
    return a + b;
});

console.log(result);
// 実行結果
// 150
```

ソースを見ればなんとなくやっていることが分かるが念の為、実行時のイメージを作成。

| 関数実行回数 | a | b | 返り値 |
|:-:|:-:|:-:|:-:|
| 1回目 | 10  | 20  | 30 |
| 2回目 | 30  | 30  | 60  |
| 3回目 | 60  | 40  | 100  | 
| 4回目 | 100  | 50  | 150  | 

1回目のaには配列の最初の要素「10」が入り、bには次の要素「20」が入る。
2回目のaには1回目の返り値「30」が入りbには1回目のbの次の要素（今回は）「30」が入る。
以降は配列の要素分同じように繰り返し、最後の返り値の「150」がresultに代入される動きとなる。
PHP脳が故にJavaScriptでarray_pad的関数がなくて泣いてる君へ

# はじめに
こんにちは。SBI証券での投信積立にクレカが使用できるようになったので、対象の三井住友カードを申し込みました。
クレカで積立できるとポイントたまるのでお得です！皆様もぜひ！

さて、今回は、JavaScriptでPHPの`array_pad`をしたいときがあり、生み出したコードを共有します。
コピペで使えるので良ければ使ってくださいませ:pray:

# PHPの`array_pad`関数とは
配列が指定長に満たない場合、指定長まで指定の値で埋めることができる関数です。

リファレンスこちら↓

```console
$ php --rf array_pad

Function [ <internal:standard> function array_pad ] {

  - Parameters [3] {
    Parameter #0 [ <required> array $array ]
    Parameter #1 [ <required> int $length ]
    Parameter #2 [ <required> mixed $value ]
  }
  - Return [ array ]
}
```

## 使用例

```php
<?php
$array = [12, 10, 9];
$length = 5;
$val = 'hello';

$result = array_pad($array, $length, $val);
// [12, 10, 9, 'hello', 'hello'] 
?>
```

# JavaScriptでarray_padしたい！

```js
const array = [12, 10, 9]
const length = 5
const val = 'hello'

const result = [
    ...array,
    ...[...Array(length - array.length)].map(e => val)
]
// [12, 10, 9, 'hello', 'hello']
```

# 2021/07/26(月) 追記
**[コメント](https://qiita.com/akitkat/items/da74a6ab9abb40119d9f#comment-1927d83ceffe66d00f13)**をいただきまして、こちらの方がスマートで素敵なコードになります:pray:
ぜひこちらを使用してくださいませ！

>concat使うならスプレッド構文は不要でしたね。
>const result = array.concat(Array(length - array.length).fill(val));

```js
const array = [12, 10, 9]
const length = 5
const val = 'hello'

const result = array.concat(Array(length - array.length).fill(val));
```




# おわりに
いろいろやり方あると思いますが、個人的に一番シンプルにできた気がしてます :smile:

それでは！
Swiftによる依存関係逆転の原則

https://peaks.cc/books/iOS_architecture

10章のメモ

- 依存関係逆転の原則は`UseCaseOutputPort`によって実現
- Use Case が見ているのはあくまで「入出力のデータを受け取れるオブジェクト」であり、
Presenter の具体的なクラスではない

```swift
// インターフェイスアダプター(Controller / Presenter) -> Use Case

// Use Case(内)
protocol UseCaseOutputPort: AnyObject {
    func useCaseDidUpdate(value: Int)
}

protocol UsecaseInputPort {
    func update(something: Int)
}

final class UseCase: UsecaseInputPort {
    private weak var output: UseCaseOutputPort?
    init(output: UseCaseOutputPort) {
        self.output = output
    }

    func update(something value: Int) {
        // (値を使ったアプリケーション固有の処理)
        // (ここでは Entity 層の処理・データも使える)
        // Output 経由で Presenter へ通知(逆方向)
        output?.useCaseDidUpdate(value: value)
    }
}

// インターフェイスアダプター(外)
final class Presenter: UseCaseOutputPort {
    func useCaseDidUpdate(value: Int) {
        print("UI 更新(\(value))")
    }
}

final class Controller {
    private let useCaseInput: UsecaseInputPort
    init(input: UsecaseInputPort) {
        useCaseInput = input
    }

    func received(something value: Int) {
        // Input 経由でUse Case を呼び出し(順方向)
        useCaseInput.update(something: value)
    }
}

// 円の構築
let useCase: UseCase = .init(output: Presenter())
let controller: Controller = .init(input: useCase)
// 処理開始
controller.received(something: 10)
```

『オブジェクト指向設計実践ガイド（Sandi Metz著）』より

依存オブジェクトの注入 (dependency injection)
https://github.com/noriyotcp/practical_object_oriented_design_in_ruby/blob/master/03_Managing_Dependencies/02.md

依存関係の逆転
https://github.com/noriyotcp/practical_object_oriented_design_in_ruby/blob/master/03_Managing_Dependencies/03.md
【個人的備忘録】Jetson Nanoに最新のVSCodeをインストールする方法

# Jetson Nanoのバイナリを入手する
下記のサイトでArm64のバイナリを入手
https://code.visualstudio.com/Download
# インストール
入手したファイルでVSCodeをインストールする

```
$sudo dpkg -i ~/Downloads/code_1.58.2-1626300392_arm64.deb 
```

# バージョン確認
```
$code --version
```
# 起動
```
$code
```
JMeter、API負荷テスト　やり方（GET、POST）備忘録

#まえがき
APIの負荷テストにApache JMeterを使用した
その使い方をまとめる。

#環境
Mac mini(M1, 2020)
Apple M1
macOS Big Sur ver11.4

#初期設定
binディレクトリの中にある「jmeter.bat」をテキストエディタで開き、編集する。

ここで設定をしておくとメニューは常に日本語表示となる。

```bat:日本語化設定（76行目付近）
set JMETER_LANGUAGE=-Duser.language="en" -Duser.region="US"
    　　　　　　　　　　　　　　　　↓
set JMETER_LANGUAGE=-Duser.language="ja" -Duser.region="JP"
```


#手順

##アプリ開き方
binディレクトリの中にある「ApacheJMeter.jar」をJavaLuncherで開く

##起動画面

![スクリーンショット 2021-07-26 10.42.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517291/685a71b9-f61b-ee10-7a83-a724302d9636.png)

##テスト計画
1.スレッドグループの作成
「テスト計画」を右クリック
「追加」→「Threads(Users)」→「スレッドグループ」を選択

2.HTTPリクエスト、ヘッダマネージャー作成
「スレッドグループ」右クリック
「追加」→「サンプラー」→「HTTPリクエスト」をクリック
「追加」→「設定エレメント」→「HTTPヘッダマネージャー」をクリック　**（GET通信のみの場合は必要ない）**

3.統計レポート、結果を表で表示を追加
「スレッドグループ」右クリック
「追加」→「リスナー」→「統計レポート」をクリック
「追加」→「リスナー」→「結果を表で表示」をクリック

![スクリーンショット 2021-07-26 10.42.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517291/b2522fbf-0aa9-66ae-4912-e74bdacb1480.png)



##スレッドプロパティ
![スクリーンショット 2021-07-26 10.44.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517291/32312fc6-2a06-2067-dd74-97ff0d773adb.png)


Ramp-Up期間=全リクエストの作成時間

テストの総回数 = 「スレッド数」×「ループ回数」
1秒あたりのテスト回数　= 「テストの総回数」÷「Ramp-Up期間(秒)」

例
1.Ramp-Up期間を100(秒)、スレッド数を10とすると、 JMaterは100秒かけて10スレッド分のリクエストを送信する

2.スレッド数を10、ループ回数を10とすると、JMaterは順番に10スレッド×10回分のリクエストを送信する

3.Ramp-Up期間を10(秒)、スレッド数を10とすると、JMaterは1秒間に1スレッド分のリクエストを送信する


##HTTPリクエスト
###GET
![スクリーンショット 2021-07-26 10.46.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517291/190981ef-5c3d-1b11-4f7e-bbacb8dcdf53.png)

###POST
![スクリーンショット 2021-07-26 10.49.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517291/30799d88-7de7-f1fc-7d2a-1b0706a365ff.png)

##HTTPヘッダマネージャー
###GET
必要なし

###POST
![スクリーンショット 2021-07-26 10.50.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517291/bd2c63bb-fb07-eaf5-0ae2-c32f30e4bf79.png)

##レポート
統計レポートや結果を表で表示などの結果をリセットしたい場合

「右クリック」→「消去」

==参考==
[Webアプリ開発エンジニアのための技術情報サイト[テックスコア]](https://www.techscore.com/tech/Java/ApacheJakarta/JMeter/index/)
[JMeterの簡単な使い方まとめ](https://qiita.com/digdagdag/items/8a4023ddc7d549fa8de8)
[【図解】はじめてでもわかるJMeterの使い方](https://tech-blog.rakus.co.jp/entry/2017/08/24/111332)
AWS DVA合格記(2021/07/26投稿)

# はじめに
もう随分前になりますが、過去にAWS試験について以下のような記事を書きました。

* [AWS 認定クラウドプラクティショナーを受験(合格)してきた話
](https://qiita.com/handy-dd18/items/c2b62ad58206e47f1345)
* [AWS 認定ソリューションアーキテクトアソシエイトを受験(合格)してきた話](https://qiita.com/handy-dd18/items/96a9f374a64663b10e24)

そこから今までに別のAWS試験も受けたりしましたが、先日開発系のサービスについての学習の意味も込めてデベロッパーアソシエイトを受験してきましたので、勉強した内容とかを書いていきます。


## 注意
今回は時間がなかったので、最短で学習して試験に合格するような内容になっています。
ちゃんと腰を据えて学びたいという方には向いてませんので、その場合は他の方の合格記をご参照ください。
(正直初学者向けではないかもしれません)


# 前提
DVA受験時の前提は以下の通りです。

* 一般的なIT、クラウドの知識は持っている
* 運用設計の思想は理解している
* 2年前にCPとSAAは取得済み
* 今年の2月にData Analyticsを取得済み
* 主要なAWSサービスの概要は理解済み
* 開発系のサービスの使用経験は一部のみ


# 受験結果
まずは受験結果ですが、スコアとしては867点と余裕をもって合格ができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440403/63948a8c-cc7a-a469-e0d6-ea23230c6179.png)

分野別に見ても全般的にコンピテンシーを満たしていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440403/be98b332-72f6-e4ed-1c78-d2e5d2b73383.png)


# 学習期間
本業が忙しいのもあったので申し込みから受験まで1週間で勉強しました。
時間はなかったですが、連休があったのでそこでブーストかけて実施しました。


# 学習内容
学習に使用したのは以下の2つです。

* [ポケットスタディ AWS認定デベロッパーアソシエイト](https://www.amazon.co.jp/%E3%83%9D%E3%82%B1%E3%83%83%E3%83%88%E3%82%B9%E3%82%BF%E3%83%87%E3%82%A3-AWS%E8%AA%8D%E5%AE%9A-%E3%83%87%E3%83%99%E3%83%AD%E3%83%83%E3%83%91%E3%83%BC%E3%82%A2%E3%82%BD%E3%82%B7%E3%82%A8%E3%82%A4%E3%83%88-%E3%82%A2%E3%82%BD%E3%82%B7%E3%82%A8%E3%82%A4%E3%83%88%E8%A9%A6%E9%A8%93%E3%83%9D%E3%82%B1%E3%83%83%E3%83%88%E3%82%B9%E3%82%BF%E3%83%87%E3%82%A3-%E5%B1%B1%E4%B8%8B%E5%85%89%E6%B4%8B/dp/4798063401/ref=tmm_hrd_swatch_0?_encoding=UTF8&qid=&sr=)
* [WEB問題集で学習しよう](https://aws.koiwaclub.com/)

順番としては以下のような流れです。

* ポケットスタディのテキストを1周する
* Web問題集を解く(1セクション7問で、7問全てが100%になるまで解いたら次のセクションへ...という風に解きました)
* Web問題集の本試験モードを解く(1回のみ)
* AWSの模擬試験を解く(1回のみ)
* 不足部分をポケットスタディで再学習・Web問題集で関連する問題を解く
* 本番

最初はWeb問題集だけでなんとかなるかなと思って数問解いてみたのですが、やはりサービスを使ったことがないとどういう風な設定が可能なのかもわからないので、思うように解けませんでした。

そこでポケットスタディを試しに買って読んでみたところ、実際のAWSコンソール画面やCloudformationのコードと説明がまとめて書いてあったので、サービスを触ったことがなくても大体のイメージができました。

もちろん実際にサービスを使ってみるのが最善なのですが、時間がなくサッと理解してあとは問題を解いて学習したいという方は上記のやり方がオススメです。
※AWSサービスは変わりゆくものなのでずっとこのやり方が通用するとは思ってません


# 試験の感想
DVA試験のセクション別に問題を見たとき、開発と展開についてはCode系などのサービスへの理解があれば解けるものが多いですが、セキュリティはAWSサービス全般に関わってくるものなので学習範囲が他のものに比べて若干広かったです。

リファクタリングとモニタリング・トラブルシューティングは特定のAWSサービスというよりはAWSが求めるベストプラクティスがちゃんと理解できていれば解けるものが多いので、AWSサービス単体で見るよりはベストプラクティスなども組み合わせて学習してみるとより理解が深まりやすいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440403/7ae7f9c1-8083-29af-b269-6483b9b13dc2.png)


この内容が誰かの参考になれば幸いです。
開発案

# 概要
個人的な開発したら楽しそうだと思った内容のメモ
もしアイデアあればコメントいただきましたら嬉しいです！
一緒に趣味程度で
開発してくれる方も募集してますのでコメント待ってます！


# TwitterのBOT(Lv.1 挨拶 ~ Lv.XX コマンドで任意の返信可能)
Twitterでフォローしてくれている人にBOTがリプする

**メリット**
リプがあるツイートにコメがつきやすくなる

## Lv.1 挨拶
Twitterでフォローしてくれている人が
「おはよう」とつぶやくと自動で「おはよう」のリプする

## Lv.XX コマンドで任意の返信可能
未定だけど、@xxxで「指定のコマンド」で内容読み取り作動させる
Unityにアタッチのボタンが表示されない


1.Visual Studio Tools for Unityのインストール
2.[Assets]-[Open C# project]

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555658/2b7fda63-039e-8952-1bed-a0bdf04a29bd.png)
Macでscp使ったらSSHのエラーが出た時

sshのポート番号を変えたサーバに繋ぐ時に遭遇したやつ

```bash
$ scp -p10022 -i server-no.pem shindev@255.255.255.255:/home/shindev/210726.sql.gz /Users/shindev/Desktop/210726.sql.gz
SSH protocol v.1 is no longer supported
```

ポート番号の指定を大文字にしたら通った

```bash
$ scp -P10022 -i server-no.pem shindev@255.255.255.255:/home/shindev/210726.sql.gz /Users/shindev/Desktop/210726.sql.gz
```

**おわり。**
Flutter VScode 個人的なコマンドなどの備忘録

<h1>Marketplace(拡張機能)でインストールしているライブラリ</h1>

<h3>Remove Comments</h3>
新規プロジェクトで最初にコメント整理するのに便利

<h3>Pubspec Assist</h3>
パッケージを追加するのが簡単で便利

`Remove Comments`と`Pubspec Assist`の使い方はこんな感じ
![quitta001.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223039/078c9411-2c6e-9940-47e2-2a93c53187ff.gif)


<h1>便利コマンド</h1>

<h3>コード自動整形</h3>

<strong>Mac【option + shift + F】</strong>
<strong>Win【alt + shift + F】</strong>
※この時、入力モードがローマ字入力になってないとダメかも

<h1>コメント</h1>
すぐに忘れてしまうのでメモしておく
[Rails]Twitterシェアボタンは超かんたんに実装できる

色んなサイトで見かけるTwitterのシェアボタン実は、超かんたんに実装できます。

まじですぐ実装できるので、記事が短くなりすぎてしまいそうで不安ですw

# こんな感じ

![スクリーンショット 2021-07-26 10.22.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1554142/3de3572b-269c-7b05-f9e6-2733d6637d60.png)

シェアボタンを押すとこんな感じで、Twitterに飛びます。

![スクリーンショット 2021-07-26 10.24.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1554142/ae9349f0-662b-d33e-40c7-870e7cf7f3da.png)

かんたんにシェアできるので便利ですね〜

[ポートフォリオサイト](https://oogiri-legendroad.com/)のせておきますので、どんどんシェアしてみてくださいｗｗ

https://oogiri-legendroad.com/

#開発環境

> ruby 2.6.3
> Rails 5.2.6

# さっそく実装

実装方法はビューで、TwitterのシェアためのURLにリンクを実装するだけです。

```erb:実装
<%= link_to "https://twitter.com/share?url=#{ request.url }&text=【テスト】%0a%0a#{ post.content }、シェアさいこう〜", target: '_blank' do %>
  <i class="fab fa-twitter" style='color: #3399FF;'></i>シェア
<% end %>
```

これだけで、実装完了です。
これだけでは、少しわかりにくいので、解説していきます。

####URL

まず、リンクの遷移先とツイートに入ってるURL部分を見ていきます。

ツイート内のURL部分は`url=#{ request.url }`

```rb:
# request.urlにシェアボタンを設置したページのURLが入る
link_to "https://twitter.com/share?url=#{ request.url }
```

####ツイート本文

次にツイートの本文部分を見ていきます。
ここは、ツイートしたい内容によって、任意の文字列、カラムなんかを指定してアレンジができます。

ツイート本文は`&text=`

今回は、
`文字列`　
`改行`
`post.content` `文字列`
でツイートを構成しています。

```rb:
# %0a%0aが改行
# カラムを使う場合は#{ }の中に入れる
&text=【テスト】%0a%0a#{ post.content }、シェアさいこう〜"
```

####target: '_blank'

これは`link_to`のオプションでつけることにより、リンク先を別タブで開けるようになります。

####シェアリンク

最後に表示されているリンク部分のデザインです。
Twitterなので、FontAwesomeのアイコンを使って、青くしています。

```rb:
<i class="fab fa-twitter" style='color: #3399FF;'></i>シェア
```

# まとめ

思ったとおり、短い記事になりましたw

実際この記事読んでもらったら、変更点はツイートの本文ぐらいなので、実装は5分以内にできるんじゃないでしょうか。

さくっと、Twitterシェアボタン実装してみてください！
composer のコマンドを勉強してみた

composer は Laravel インストールする時に使った事はあるけれど、特に意識することなく（何も考えずに）使ってました・・・
そんな中、Laravel の carbon パッケージを調べる事があり、ふと「このcarbonってバージョンいくつなんだろう」と疑問に思った事が composer のコマンド使ってみたきっかけです。
備忘録的な意味合いが強いのですが、誰か、何かの役に立てばうれしいです。


###パッケージの一覧を表示する
```
composer show -i
You are using the deprecated option "installed". Only installed packages are shown by default now. The --all option can be used to show all packages.
～～～　略　～～～
monolog/monolog                           2.2.0     Sends your logs to files, sockets, inboxes, databases and various web services
nesbot/carbon                             2.46.0    An API extension for DateTime that supports 281 different languages.
～～～　略　～～～
```

いろいろと出力されました。carbon のバージョンは 2.46.0 のようです。

###composer update と composer install
よく`composer update`は**本番環境では実行しない事！**なんてことを聞きますが何でですかね？あまり知らなかったのですが、今回調べた事を記します。

まずは`composer update`と`composer install`の対比表

|実行コマンド  |対 composer.json  |対 composer.lock  |
|---|---|---|
|composer install  |参照のみ  |参照のみ  |
|composer update  |参照のみ  |**書き込みあり**  |

　
　
**composer install の動き**
1. composer.lock が存在すればファイル内に記されたパッケージのバージョン情報を取得する
2. composer.json ファイル内に記載されたパッケージを**composer.lockに記されたバージョン情報に従って**パッケージのダウンロード・インストールを行う
`composer.lock`と`composer.json`は読み込みのみ
　
　

**composer update の動き**
1. composer.json ファイル内に記載されたパッケージとバージョン情報に従ってダウンロード・インストールを行う
2. インストールしたパッケージ情報で**composer.lock を更新する**
`composer.lock`は書き込み
　
　
`composer.lock`はチーム内などで共有し、必要のないパッケージのバージョンアップを行わない為に使用されます。これを使用する事で意図しないバージョンアップによる不具合、コンフリクトを防ぎます。
その`composer.lock`を**`composer update`では更新します**。
なので、通常の流れでは



1. 開発環境で`composer update`を実行
2. `composer.lock` `composer.json`ファイルを共有
3. 本番環境で共有した`composer.lock`を使用して`composer install`を実行

という事になるのかな？？



実際に本番環境で`composer update`を行って、意図しないバージョンまでアップデートされ、その結果、稼働してたシステムが動かなくなったというケースを見たことがあります。
　
　
　
とりあえずこんなところで
勉強中なので必要があれば、追記、修正していきます。
Laravel8 API Resource Queryの効率化

# Laravel8 API Resource Queryの効率化
Laravel8のリレーションシップのQueryをDebugしてみたところ
レコードごとのQueryを実行していたのでQueryを効率化する方法について調べました。
（前提はUserとPostの1:N関係）
まずはLaravelのLoadigの種類について調査

## Lazy Loading（怠惰な読込み）
LaravelのデフォルトのLoading方式だが、N+1問題を起こすLoading方式

### ※N+1問題とは
https://qiita.com/massaaaaan/items/4eb770f20e636f7a1361#n1%E5%95%8F%E9%A1%8C%E3%81%A8%E3%81%AF

### Lazy LoadingのSQL例

#### Routeの例

```php:api.php
use App\Http\Resources\PostCollection;
use App\Models\Post;

Route::get('/posts', function () {
    return new PostCollection(Post::all());
});
```

#### SQL実行例

```sql:postの例
SELECT * FROM posts;

SELECT * FROM users WHERE id = 1;
SELECT * FROM users WHERE id = 2;
SELECT * FROM users WHERE id = 3;
...
```
## Eager Loading（熱心な読込み）

#### Routeの例

```php:api.php
use App\Http\Resources\PostResource;
use App\Models\Post;

Route::get('/posts', function () {
    $posts = Post::with(['users']);
    return PostResource::collection($posts->paginate(50))->response();
});
```

```php:PostResource.php
<?php

namespace App\Http\Resources\Post;

use Illuminate\Http\Resources\Json\JsonResource;
use App\Http\Resources\UserResource;

class CustomerResource extends JsonResource
{
    /**
     * Transform the resource collection into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'users' => UserResource::collection($this->whenLoaded(relationship:'users')),
        ];
    }
}
```

#### SQL実行例

```sql:postの例
select * from `posts` where `users`.`user_id` in (1, 2, 3)
```

## 結論
レコード数分のQueryが1Queryにまとまるのでその分のSqlの接続数が減り、
アプリケーションのパフォーマンスが上がります。
API Resourceのほうには適応したほういいでしょう。
wpa_supplicantのビルド手順(ラズパイ)

# wpa_supplicantのビルド手順(ラズパイ)
自分用のメモとして作成しました。

1. ソースコードを落とす
    * [wget https://w1.fi/wpa_supplicant/wpa_supplicant-2.9.tar.gz]
1. 解凍
    * [tar -zxf wpa_supplicant-2.9.tar.gz]
1. 移動
    * [cd wpa_supplicant-2.9/wpa_supplicant]
1. configファイルをコピー※設定値はREADMEファイルで調べること今回はそのまま使用
    * cp defconfig .config
1. libnがないと言われたら下記をインストール
    * sudo apt-get install libssl-dev libnl-genl-3-dev libreadline-dev libncurses5-dev libdbus-1-dev
1. make実行
    * make
1. wpa_supplicantができる(wpa_cli/wpa_passphsdeもできる)

# ビルドしたwpa_supplicantの起動方法
* 起動してるwpa_supplicantをkill
    * sudo killall wpa_supplicant
* 起動する(DEBUGLog入り)
    * sudo ./wpa_supplicant -B -ddt -f /home/***/supplicant_log/wpasupplicant1.log -c/etc/wpa_supplicant/wpa_supplicant.conf -iwlan0 -Dnl80211,wext
* ヒント
    * manを見ると停止方法とかが書いてあるみたい
カート機能②カートに入れる　同一商品は個数のみ更新する

<h2>はじめに</h2>
カート機能を作成中です。
　”今回はカートに入れる”とカートに入るようにします。
同一商品の場合には、個数のみが更新されるようにします。

<h3>前提条件</h3>
ここで登場するテーブル・モデルは、
Customer
Item
Cart_item　です。←(CustomerとItemの中間テーブルになる。）
（Cartモデルを作成している記事が多いですが、Cartモデルは作成していません。）

＊ログインしなくても商品の閲覧はできるが、カートには入れられない。


<h2>View 個数を選択してカートに入れる</h2>

```
＃関係するところのみ抜粋
 <%= form_with model:@cart_item,url:cart_items_path,method: :post,local:true do |f| %>
 <%= f.hidden_field :item_id, value: @item.id %>
 <%= f.hidden_field :customer_id, :value => current_customer.id %>
 <%= f.select :quantity,[1,2,3,4,5,6,7,8,9,10],{include_blank: '個数選択'},required:true%>&emsp;
 <%= f.submit 'カートに入れる' ,class: 'btn btn-success btn-sm'%><% end %>        
```

<h6>hidden_fieldとは何？</h6>

複数のWebページ間でデータの受渡しを行う際に利用されます。
hiddenなので画面上には表示されません。
今回だと、カートの画面にcustomer_idとitem_idを渡しています。

<h5>エラーの記録：個数選択　無しで、カートに入れる　は出来ないようにしたいのに</h5>

f.selectで、required:trueにしてますがこれは"入力必須"ということです。
しかしながら、"個数選択"のままカートに入れるボタンを押すことができ、nil~のようなエラーが出てきてしまいます。
モデルファイルのバリデーションでもpresense trueにしてて、数字のみ受け付けるようにしてたのですが、
nilで進んでしまい、nil~のエラーがでてました。
<h6>解決策</h6>
マイグレーションファイルでnil falseにしたら解決しました・・・

<h2>コントローラー</h2>

```perl:cart_item_controller.rb
def create
      @cart_item = CartItem.new(params_cart_item)
      @cart_item.customer_id=current_customer.id
      @cart_items=current_customer.cart_items.all
        @cart_items.each do |cart_item|
          if cart_item.item_id==@cart_item.item_id
          new_quantity = cart_item.quantity + @cart_item.quantity
          cart_item.update_attribute(:quantity, new_quantity)
          @cart_item.delete
          end
        end
    
        @cart_item.save
        redirect_to cart_items_path,notice:"カートに商品が入りました"
    end

 private
  def params_cart_item
    params.require(:cart_item).permit(:quantity, :item_id,:customer_id)
  end
```

<h4>解説</h4>
```@cart_item = CartItem.new(params_cart_item)```
本の投稿と似てます。
Cart_itemの新規投稿。
ストロングパラメーターで、個数、item_id、customer_idを受け取っています。
```@cart_item.customer_id=current_customer.id```
この記述は不要だったかもしれません。というのも、個数選択のviewで同じような定義をしてるからです。
```@cart_items=current_customer.cart_items.all```
ここで、カートに入っているものを取り出しています。

<h6>問題は次！同じ商品をまとめる記述</h6>
```@cart_items.each do |cart_item|```
カートの中身を一個ずつ取り出して、
```if cart_item.item_id==@cart_item.item_id```
もし、同じ商品が存在していれば、
```new_quantity = cart_item.quantity + @cart_item.quantity```
今の個数に足す　それを、new_quantityに代入。
```cart_item.update_attribute(:quantity, new_quantity)```
cart_itemモデルのquantityをnew_quantityに更新するよ　という意味らしい。
```@cart_item.delete```
同一商品に関しては、個数だけ更新できたら後はオサラバ

<h4>参考にさせていただきました</h4>
以下の記事に感謝です:fist:
同じ商品がカートに入った場合、個数のみ更新されるよう記述できました。

https://qiita.com/hiroki-ume/items/969cbf5ed4b7c906aad0

https://railsdoc.com/page/model_update_attribute
mayaでDeadLineを使ってみる１

機会があったので、mayaで DeadLine submitterを使って何ができるのかを試してみる。


- submitterのインストール

割愛。

とりあえず　SubmitJobToDeadline　で呼び出せる　sbumitterのオプションを読み解いてみる

Job Descripton
-

- Job Name
ジョブの名前。
ファイル名にした方が良いらしい。

- Comment
ジョブに関するコメント。

- Department
ジョブの分類。


Job Scheduling
-

- Pool

- Secondary Pool

- Group
処理に使用する workerグループの指定。

- Priority
ジョブの優先順位の指定。数字が大きい方が先の処理される。
**戦争の原因になるので、よほどのことがない限りは一律50にしておいた方がいい。**
例)自分のタスクだけ優先順位を上げる。 -> 戦争

- Machine Limit
同時に使用するworker数の指定。
**これも戦争の原因になりそうなので、ルールの指定が必要。**
例)ヘビーなタスクを全マシン使用して数日間占有　-> 戦争

- Concurrent Tasks

- Task Timeout

- Minimum Task Time

- Enable Auto Task Timeout

- Limit Group

- Dependencies
親となるjobを指定

- Machine List
処理に使用するマシンのリスト。
**Groupを指定してる場合は、そのGroupに属しているマシンを選択しないとジョブが開始されない。**

- On Complete
job終了時の挙動。
nothing そのまま
archive アーカイブ送り
delete  削除

- Machine List is a Blacklist
Machine Listをブラックリストとして使用。
Machine Listに指定されているマシンは処理に使用しない。

- Sbumit As Suspended
サブミット直後のjobのステータスを サスペンドにするか否か

- Close on Submission 

- Precache assets for AWS

Render Options
-

- Frame List
レンダリング設定で連番レンダリングが指定されている場合に編集可能。
レンダリングするフレームを設定

- Frame Per Task


AdditionalFrameOptions
-

- camera
使用するカメラを指定

- Project Path
mayaのプロジェクトパス。
ネットワーク上からアクセスできる場所を指定。

- Output Path
処理の成果物を格納するフォルダ。
ネットワーク上からアクセスできる場所を指定。

- Maya Build
処理するmayaの指定。 32 or 64 bit

- submit Maya Scene File
シーンファイルをサブミットする？
ネットワーク上に保存してなくても飛ばせる？

- Use MayaBatch Plugin
True の時は
Plugin=MayaBatch　が使用される
Falseの時は
Plugin=MayaCmd　が使用される

- Ignore Error Code 211

- Strict Error Checking


- startup script
use MayaBatch Plugin == True 時に使用可能。
実行されるタイミングは、サブミットしたファイルが展開された後。
ファイル選択ダイアログにてpythonファイルが指定できるようになっているが、**実際には　mel で souce $filePath;  で実行されるので、事実上はpython非対応？。**
スクリプトファイルをネットワーク上からアクセスできる場所に格納しておかないと、ワーニングが出る。無視して実行するとエラーになる。

- Command Line Args
use MayaBatch Plugin == False 時に使用可能。

- Deadline job Type
Deadlineに処理させるジョブのタイプ
今回は　Maya Render Job / Maya Script Job / Alenbic Export Job を検証予定


Maya Render Job
-

- Threads

- Submit Render Layers As Separate Jobs
レンダーレイヤー毎にjobを分解してサブミットする。
分解されたジョブは指定したジョブ名をDependenciesとして、　ジョブ名 + レイヤー名でサブミットされる

- Override Layer Job Settings
レンダーレイヤー毎にジョブの設定を細かく行うか否か。
行う場合は別ダイアログが開く。

- Submit Cameras As Separate Jobs
カメラ毎にjobを分解してサブミットする

- Ignore Default Cameras
デフォルトカメラ(top / left / front / persp) を使用しない

- Enable Local Rendering

- Render Hair Frames





参考
https://forums.thinkboxsoftware.com/t/mayabatch-usersetup-py/13237

https://bonnishcg.hatenablog.com/entry/2019/06/02/012849

https://docs.thinkboxsoftware.com/products/deadline/10.1/1_User%20Manual/manual/app-maya.html?highlight=maya

https://support.indyzone.jp/hc/ja/articles/360014758451-%E3%82%B8%E3%83%A7%E3%83%96%E3%81%AE%E6%8A%95%E5%85%A5-MayaBatch
jestでfirebase-adminのauth().verifyIdToken()をモックする

環境
TypeScript, Node(Hapi)

###コード

```ts
import admin from "firebase-admin";

const decoded = adimn.auth().verifyIdToken(token);
```
このverifyIdToken(token)で返すデータをJestでモックしたかった。

###テスト

```test.ts
let spy: jest.SpyInstance;

afterEach(() => {
  spy.mockRestore();
});

test("テスト", () => {
  const admin = require("firebase-admin");
  const mockVerifyIdToken = jest.fn().mockResolvedValue({ uid: "uid" });
  const mockAuth = jest.fn().mockReturnValue({ verifyIdToken: mockVerifyIdToken });
  spy = jest.spyOn(admin, "app").mockReturnValue({ auth: mockAuth });
})
```

複数のテストで違う値を返したかったのでspyOnを使いました。

これで

```ts
const decoded = adimn.auth().verifyIdToken(token);
```
の部分は`{ uid: "uid" }`を返しました。

--- 
ちゃんとは読んでないけど参考

https://stackoverflow.com/questions/67748989/how-to-mock-external-dependency-in-typescript-using-jest
【学習録】Linux-DB システム構築/運用入門- part1【63日目】

# ふくだ学習録とは？
ふくだが学習したことの備忘録。
目に見える形で残すことによってやる気を出す個人的な作戦です。
他人に見せるように書いているわけではないので、すごく読みにくいです。

### 今読んでいる本
[Linux-DB システム構築/運用入門 (DB Magazine SELECTION)](https://www.amazon.co.jp/dp/4798120723)

# Chapter01 論理ボリュームマネージャ（LVM）を活用する

### 論理ボリュームマネージャ（LVM）とは
物理的なディスク追加などによるパーティション領域の増減ではなく、割り当てられたパーティション領域を論理的に増加/減少などできるようにする機能。

### LVMを作成して、アプリケーションから使えるようにする方法
下記手順が必要。

1. LVM用のパーティションを作成（fdlsk）
2. 物理ボリュームの作成（pvcreate）
3. ボリュームグループの作成（vgcreate）
4. 論理ボリュームの作成（ivcreate）
5. ファイルシステムの作成（mkfs）とマウント(mount)

#### 1. LVM用のパーティションを作成（fdlsk）
まずはパーティションを作成する。パーティション作成には、LVMのコマンドではなく「[fdisk](https://www.atmarkit.co.jp/ait/articles/1803/01/news034.html)」というディスク管理用のコマンドを用いる。

#### ハードディスクのジオメトリーとは？
[ハードディスクドライブの基礎知識](http://archive.linux.or.jp/JF/JFdocs/hdd-intro.html)

# 今日の一言
面白い！
filename-yyyymmddの形式で退避したS3をAthenaで日付条件クエリ

# はじめに
OSのログをS3へ退避する際、
とりあえず貯めとけ精神でOS上でログローテされたまま保存しますよね。

そうすると後々、
ある月のログに対してAthenaでクエリかけたい...ってときに苦しみますよね。

でもHive形式に作り替えるのも面倒ですよね。
※Athenaでのパーティション分割：https://docs.aws.amazon.com/ja_jp/athena/latest/ug/partitions.html

そんなときは、検索に時間かけても良いからゴリ押しでクエリをかけましょう。

#0. S3の構造
- バケットURL：s3://secure-log-athena-test/secure/
- オブジェクト：

>
secure
secure-20210701
secure-20210702
secure-20210703
secure-20210704
secure-20210705
secure-20210706
secure-20210707
・・・

#1. サンプルDDL
- `テーブル名`, 'バケット名URI' 部分は各S3バケットのURIに置き換えてください。

```sql
CREATE EXTERNAL TABLE `テーブル名`(
  `month` string COMMENT '',
  `day` string COMMENT '',
  `time` string COMMENT '',
  `host` string COMMENT '',
  `cmd` string COMMENT '',
  `user` string COMMENT '',
  `etc` string COMMENT '')
ROW FORMAT SERDE
  'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
  'input.regex'='^(\\S+) +(\\S+) +(\\S+) +(\\S+) +(\\S+) +(\\S+) +(.+)$')
STORED AS INPUTFORMAT
  'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  'バケット名URI'
TBLPROPERTIES (
  'has_encrypted_data'='false',
  'transient_lastDdlTime'='1622793925')
```

# 2. クエリ
- "DB名", "テーブル名" 部分は各S3バケットのURIに置き換えてください。

```sql
SELECT *
FROM "DB名"."テーブル名"
WHERE "$path" LIKE '%secure-202107%'
        AND cmd LIKE '%sudo%'
        AND user NOT LIKE '%pam_unix%'; 
```

# おわりに
・運用等で定期的に検索をかける必要がある
・クエリに時間をかけたくない(お金もかけたくない)
そんなときは腹を括ってS3の構造と退避スクリプトに向き合いましょう。
AtCoderログ：0035 - ABC 087 B

# 問題

https://atcoder.jp/contests/abc087/tasks/abc087_b

## 問題文
> あなたは、$500$ 円玉を $A$ 枚、$100$ 円玉を $B$ 枚、$50$ 円玉を $C$ 枚持っています。 これらの硬貨の中から何枚かを選び、合計金額をちょうど $X$ 円にする方法は何通りありますか。
> 同じ種類の硬貨どうしは区別できません。2 通りの硬貨の選び方は、ある種類の硬貨についてその硬貨を選ぶ枚数が異なるとき区別されます。

## 制約
> ・$0 \le A,B,C \le 50$
> ・$A+B+C \ge 1$
> ・$50 \le X \le 20,000$
> ・$A,B,C$ は整数である
> ・$X$ は $50$ の倍数である

## 収録されている問題セット
- [AtCoder に登録したら次にやること](https://qiita.com/drken/items/fd4e5e3630d0f5859067) ([第04問](https://qiita.com/drken/items/fd4e5e3630d0f5859067#%E7%AC%AC-4-%E5%95%8F--abc-087-b---coins-200-%E7%82%B9))
- [AtCoder Beginner Selection](https://atcoder.jp/contests/abs)

# 回答 
## 回答1 (AC)
それぞれの硬貨の枚数 a, b, c を受け取った後、それぞれの枚数をループで回し、合計額が x 円になるかを確認していきます。コードは以下のようになりました。

```C++:abc087b-1.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  int a, b, c, x;
  cin >> a >> b >> c >> x;
 
  int answer = 0;
  for ( int i=0; i<=a; i++ ) {
    for ( int j=0; j<=b; j++ ) {
      for ( int k=0; k<=c; k++ ) {
        if ( 500*i+100*j+50*k==x ) {
          answer += 1;
        }
      }
    }
  }

  cout << answer << endl;
}
```

## 回答2 (AC)
回答1の無駄な処理を削りましょう。$500$ 円硬貨が i 枚、$100$ 円硬貨が j 枚のとき、残金は rest = x-500*i-100*j 円なので、この金額が $50$ 円硬貨で支払われるかをチェックすることで、回答1の一番内側のループをなくすことができます。rest が (1) 0 円以上、(2) 50*c 円以下、(3) 50の倍数、であるときに、rest は $50$ 円硬貨で支払うことが可能です。コードは以下のようになりました。 

```C++:abc087b-2.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  int a, b, c, x;
  cin >> a >> b >> c >> x;
 
  int rest, answer = 0;
  for ( int i=0; i<=a; i++ ) {
     for ( int j=0; j<=b; j++ ) {
       rest = x-500*i-100*j; 
       if ( 0<=rest && rest<=c*50 && rest%50==0 ) {
         answer += 1;
       }
     }
  }

  cout << answer << endl;
}
```

回答1の計算回数は abc 回であったのに対し、回答2の計算回数は ab 回になっており、c 倍の高速化が実現できています。

## 回答3 (AC)
回答2では、使用する $500$ 円硬貨の枚数を 0 から a までループさせていましたが、x 円を支払うのに使用する硬貨の最大枚数は x/500 枚なので、ループする範囲は 0 から min(a,x/500) で良いことがわかります。同様に $100$ 円硬貨の枚数も 0 から min(b,(x-500*i)/100) でループさせれば十分です。コードは以下のようになりました。

```C++:abc087b-3.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  int a, b, c, x;
  cin >> a >> b >> c >> x;
 
  int rest, answer = 0;
  for ( int i=0; i<=min(a,x/500); i++ ) {
     for ( int j=0; j<=min(b,(x-500*i)/100); j++ ) {
       rest = x-500*i-100*j; 
       if ( 0<=rest && rest<=c*50 && rest%50==0 ) {
         answer += 1;
       }
     }
  }
  cout << answer << endl;
}
```

# 調べたこと
## [AtCoder に登録したら次にやること 第04問](https://qiita.com/drken/items/fd4e5e3630d0f5859067#%E7%AC%AC-4-%E5%95%8F--abc-087-b---coins-200-%E7%82%B9)
回答1と同じ方針でした。

## [AtCoder の解説](https://atcoder.jp/contests/abc087/tasks/abc087_b/editorial) → [コンテスト全体の解説](https://img.atcoder.jp/arc090/editorial.pdf)
回答1と同じ方針でした。

# リンク
## 問題セットのまとめ
- [AtCoderログ：0032 - 「AtCoder に登録したら次にやること」のまとめ](https://qiita.com/RoadLynton/items/be2bb98e5d0c0f30628b)

## 前後の記事
- 前の記事 → [AtCoderログ：0035 - ABC 211 に参加しました](https://qiita.com/RoadLynton/items/50b726125c1004d99b02)
Laravel、プロキシサーバーの対応【個人用メモ】

本番環境での原因特定に苦労したので、
次同じ状況ですぐに反応できようように。


[url]https://readouble.com/laravel/6.x/ja/requests.html

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346005/98f8fd8a-d6ab-db84-e635-bef4741e94a6.png)
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346005/875c704a-9529-6ce2-7036-504dc6784d93.png)
do-whileとwhileを間違えるとどうなるか

## はじめに
Incrementsのnara_sakiです。Qiita広告の企画営業をしています。文系ビジネス職ですが「実際に自分でも手を動かしてみたい！」という思いから、プログラミングを勉強しています。

今は、ハーバード大学が無償提供している「CS50 for Japanese: コンピュータサイエンスの入門」を受講しています。

https://cs50.jp/

本記事は自分が学んだことの備忘録です。
Week1（C）の課題で、do-while/whileの違いを実際のコードで体感したので、備忘録として残しておきます。

## do-while/whileの違い
### do-while
1. プログラムを実行する
2. プログラム実行後、条件をチェックする

do-whileでは、条件をチェックする前にプログラム実行されるため、条件の合致に関わらず最低1回はプログラムが実行される。

### while
1. 条件をチェックする
2. 条件に合致する場合、プログラムを実行する

whileでは最初に条件がチェックされるため、条件に合致する場合のみプログラムが実行される（合致しない場合はプログラムは実行されない）。

## 実例：do-while/whileの使い方を間違えるとどうなるか
CS50の課題でループ処理をする際、whileではなくdo-whileを使ったところ、期待する結果が得られませんでした。
実際の問題は載せられないため、簡略化した例を残しておきます。

例：実行したいプログラム

1. ユーザーに手持ちの現金（yen）を入力させる（0円を入力された場合は、1円以上が入力されるまで繰り返す）
1. 100円のりんご（apple）を最大何個買えるか計算し、最大個数を出力する

### whileの場合
* yen >= 100 の場合、appleの最大個数が出力される
* yen < 100 の場合、りんごは1個も買えないのでappleの個数は0と出力される

```c
#include <stdio.h>
#include <math.h>

int main(void)
{

// ユーザーに手持ちの現金を入力させる
    int yen;
    do
    {
        yen = get_int("yen: ");
    }
    while (yen < 1);

    int apple = 0;
    while (yen >= 100)
    {
        yen = yen - 100;
        apple++;
    }

// りんごの最大個数を出力する
    printf("%i\n", apple);
}
```

### do-whileの場合
* yen >= 100 の場合、appleの最大個数が出力される
* yen < 100 の場合、お金が足りないのでりんごは1個も買えないはずだが、appleの個数が1として出力されてしまう（条件のチェックをする前に処理を行ってしまうため）


```c
#include <stdio.h>
#include <math.h>

int main(void)
{

// ユーザーに手持ちの現金を入力させる
    int yen;
    do
    {
        yen = get_int("yen: ");
    }
    while (yen < 1);

    int apple = 0;
    do
    {
        yen = yen - 100;
        apple++;
    }
    while (yen >= 100);

// りんごの最大個数を出力する
    printf("%i\n", apple);
}
```

## 最後に
実際の問題はこちらです。

https://cs50.jp/x/2021/week1/problem-set/cash/

実際の開発現場では、do-whileはあまり使われずwhileを使うことが多いようですが、今回の課題を通して両者の違いがよくわかりました。

実際に手を動かしながら勉強すると、理解度も深まる気がします。
Raspberry Piで水やりをIT化にしましょう

###背景###
最近家のベランダでスイカとレモンを田植えています。在宅勤務で毎日の朝一水やりをするのはやや面倒だと思います。また、連続の外出日には水やりを止めることになりますので、リモートで水やりをできるIoT仕組みを作ったらどうと思い始めました。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/bb4dace0-3161-fde9-c213-6289f1af0556.png)


完成品は以下になります。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/a4d9e2a8-4cb2-45a9-40fe-c9dc106d4d5f.png)


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


###準備するもの###
* ラズベリーパイ3 x 1
* Arduino ELEGOO UNO R3 x 1
* Arduino USB コード x 1
* 湿度センサー x 1
* ブレイブボード　x 2
* マイクロウォーターポンプ x1
* ポケットバテッリー
* 単3形乾電池 x 4
* プラスチックケース x 2
* ボウル x 1
* ゴムパイプ x 1
* 5v リレー x 1
* ジャンパワイヤ　オス-オス 複数
* ジャンパワイヤ　オスーメス 複数

![IMG_9483.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/c2727b5f-a85e-c645-de1a-4d34754f2d3f.png)

ブレイブボード2枚を用意したのは、ワニクリップはないからです。またメスーメスのジャンパワイヤがあれば、配線はもっとシンプル化にできます。


###成果###
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/ff197703-3d37-a2d2-9147-37916a1c11c4.png)

![IMG_0060.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/fc470cf8-50e1-c96c-781b-a6dadc8a94c3.png)

###ハードウェア###

####配置####
![IMG_9460.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/e317cba4-4ffd-3701-c16f-d546958d2e77.png)


※図にある湿度センサーは土に挿入する状態になります。

####ロジック####

ポケットバッテリーからラズベリーパイに電源を供給します
単3電池からマイクロウォーターポンプに電源を供給します

リレーのOPEN,CLOSEから、マイクロウォーターポンプのON,OFFをコントロールしています。
ラズベリーパイのGPIO 21からリレーのOPEN CLOSEをコントロースしています。

Arduinoは湿度センサーから土の湿度を図ます
ArduinoはUSBを経由でラズベリーパイに湿度情報を送信します




###ソフトウェア###

####ロジック####
#####インフラ側ロジック#####
ラズベリーパイ側はngrokを利用し、イントラネットの浸透がおこなっています

#####サーバーロジック#####
ラズベリーパイはサーバー側として動作します
ラズベリーパイ側はflaskを利用し、GPIO 21をコントロールするapiを提供します
ラズベリーパイ側はgrpc サーバーストリングを利用し、クライアント側に湿度を送信します

#####クライアント側ロジック#####
flutterを利用して、iosアプリを開発します


####サンプルコード####

#####ngrok#####
ngrokでイントラネットの浸透をします

```
# flaskサーバーのポートは5000になっています
./ngrok http 5000

# 湿度grpcサーバー側のポートは5000になっています
./ngrok tcp -region jp 50051
```

#####ラズベリーパイ#####

[iot_project_server](https://github.com/xu1718191411/IoT/tree/main/iot_project_server "iot_project_server")

#####Arduino#####
[arduino](https://github.com/xu1718191411/IoT/blob/main/sketch_jun15b.ino "arduino")


#####Flutter#####
[iot_project_app](https://github.com/xu1718191411/IoT/tree/main/iot_project_app "iot_project_app")

###課題###
* 電源長時間供給
ポケットバッテーリーは数時間しか続けられないため、業務化にするためにわ、バッテーリーだけではなく、一般的な家庭用電源につながる必要があります。現在では、家のスイカはベランダーに置いてあるため、家の電源とどうやって繋がっていくことをあらかじめ考えることが必要です。

* 複数植物対応
いまは一つのボルトから一つの植物に水やりしか対応できないため、一つのボルトから複数の植物に水やりできるように改善する必要があります。

* 安全なスレッド対策
いまは、GPIOを管理するスイッチ変数はメモリに保存されています、もし同時複数のクライアントからリクエストが来たら、メモリに保存されてあるスイッチ変数は同時に変更されてしまいますので、あらかじめスレッドロックをかけるようにしなければなりません。

###感想###

中国のIT業界では最近「内巻」ということばは流行っておりまして、それは一つの分野に対して、参戦する人は多くなって、しかも皆技術のボルトネックからさらに伸ばさないため、みんなさん知恵で勝負するより、時間と体力で勝負することにしています。