OmniAICreator/Qiita-1.07M huggingface dataset:
【 LINEBot 】この「漢方薬」が「どんな症状に効くのか」教えてくれませんか？　【 GoogleSpreadSheetAPI 】

#登録販売者の苦悩

登録販売者とは
かぜ薬や鎮痛剤などの一般用医薬品（第2類・第3類に限る）販売を行うための専門資格のこと。

私も登録販売者として5年間くらい勤めてきましたが、どうにも「漢方薬」が苦手でした
全て漢字で書かれているので覚えるのが大変です。（葛根湯くらいなら馴染みがあると思いますが）

#作成した動機

自分が苦手だった「漢方薬」の効果・効能を覚えるために単語帳として思いついたものが
今回作った「汎用型FAQBot」になります。

ラインに漢方薬の名前を打ち込むことで、その効果・効能を表示してくれます。

#意図しない付加価値

Google SpreadSheet をデータベースのように扱うため、使用目的が限定されず再利用できそうです。
また、Google SpreadSheet を編集するだけで内容を変更出来るので誰でも利用できる点も良いかと思います。

#動作見本

![qiita_01_01_改.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1792140/1e4ab99b-0a28-b3ae-b604-1eb37162f22a.gif)

#動作の流れについて

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1792140/b84970e4-643c-0546-f7db-b7fa536acb6c.png)

#使用したアプリケーション

<dl>
  <dt>・LINEBot</dt>
  <dt>・Node-RED</dt>
  <dt>・JavaScript</dt>
  <dt>・Google SpreadSheet API</dt>
  <dt>・Google SpreadSheet</dt>
</dl>

#Node-RED　全体構成

![nodered_01_01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1792140/d61b0702-1b64-4135-2500-4279be239907.png)

#Node-RED　各ノード詳細
「http in」ノード：ラインサーバーから送信されたメッセージを取得　
![nodered_01_02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1792140/41503445-3c19-2f60-9266-8ec0e1b193d2.png)
「function」ノード：受け取ったメッセージを格納
![function1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1792140/f25987f1-a8cc-dac1-b54c-d0ffe252ef97.jpeg)

```javascript
// LINEサーバーからの情報を「msg.line」に移動させる
msg.line = msg.payload;
// msg.payloadにメッセージ本体を入れる
msg.payload = msg.payload.events[0].message.text;

return msg;
```

「G Sheet」ノード：Google SpreadSheet API を使って予め用意した Google SpreadSheet から情報を2次元配列として取得
![nodered_01_04.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1792140/86e4dc4c-699a-7215-cf2f-09c10ad12ed0.png)
「function」ノード：受け取った2次元配列を格納したメッセージと突合させて条件に合致したものをメッセージとして代入する
![function2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1792140/5395162b-b3e3-3c2d-c179-bd36ed126d2c.jpeg)

```javascript
// msg.payloadの中にはスプレッドシート内容（2次元配列）が入っている
// 行ごとに、その行の1列目の文字がmsg.line.events[0].message.textと等しいかチェック
// もし等しければその行のインデックス数値が得られる（なければ-1）
const index = msg.payload.findIndex(rows => rows[0] == msg.line.events[0].message.text);
// 返信する言葉
let resultMessage = "見つかりませんでした";
// もしアイテムの単語が見つかればその説明文を返信する言葉に上書きする
if (index != -1) {
  resultMessage = msg.payload[index][1];
}
// 返信する言葉を代入し、payloadに戻す
msg.line.events[0].message.text = resultMessage;
msg.payload = msg.line;
return msg;
```

「ReplyMessage」ノード：メッセージをラインサーバーに返信
![nodered_01_06.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1792140/0bf47ace-fca2-5cf9-8b27-23b97a4abf80.png)

#作成所感

登録販売者の現役の方に感想を聞いたところ、お客さまの立場からであればこのままで良いが
登録販売者側が使うとしたら**「症状からどんな薬がお勧め出来るか」**を知れると良いとのことでした。
この制作物の最も優れた点は、Google SpreadSheet を API で参照しているので
**使用者側で容易にカスタマイズ出来る**という点だと考えています。
Emscripten で std::thread, pthread なマルチスレッドコードはブラウザでは 2021/07 時点実質使え無さそうなメモ

## 背景

std::thread や pthread でスレッド化している C/C++ コードを emcc で WebAssembly でブラウザで動かしたい.

## スレッド有効

`-s USE_PTHREADS=1` とすると有効になります.

## 情報

https://web.dev/webassembly-threads/

## 問題点

ただ, 現在の Firefox(2021/07/30 時点)や Chrome だと

SharedArrayBuffer is not defined エラーが出ます.

https://github.com/exokitxr/exokit-web/issues/1

どうもフラグで有効にしないと使えないっぽい...?

しかも, セキュリティ上の問題により, 制約が強くなります.

https://forest.watch.impress.co.jp/docs/news/1307629.html

SharedArrayBuffer 開発時に使うのが面倒になりそう...?
あと, Safari では SharedArrayBuffer 対応していません.


## そもそも WebAssembly の thread はまだ議論中 

https://github.com/WebAssembly/threads

WebAssembly 自体の(ネイティブ?) thread, まだ仕様として決まっているわけではありませんでした...

## 現状どうするか?

各種ブラウザに対応させたいなどとなると,
C++ で完結するのは諦めて, JavaScript 側で WebWorker あたりでタスクを建てて処理させるしかなさそうです...
Flutter Packageをカスタマイズする

こんにちわ、語学交換マッチングアプリ『CROSSER』の開発者です。:smile:
この『CROSSER』なのですが、FlutterとFirebaseを用いて開発しております。
今回は、Flutter Packageをカスタマイズする方法を記載していきたいと思いますので、このパッケージめっちゃいいけど！なんか惜しいな！！って時に是非参考にしてみて下さい!:clap:


#はじめに
語学マッチングアプリ『CROSSER』の概要についてはこちらを参照ください！

https://qiita.com/crosser202008/items/0ca7e9c190bc3dff7516


#今回書くもの
- Flutter Packageをカスタマイズして利用する方法

#使用するもの
- Git

#Flutter Packageカスタマイズ手順
①カスタマイズしたいパッケージのページにいく
今回はswipable_stackというパッケージをカスタマイズしていきます。
https://pub.dev/packages/swipable_stack

②VersionsページでカスタマイズしたいVersionのソースをダウンロードする。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1642184/2932e819-e707-fb1e-0828-28759028afaa.png" width=70%>

③ダウンロードしたソースをローカルに解凍する。

④解凍したソースを開く（私はVSコードで開発しているのでVSコードで行いました)

⑤パッケージで修正したい部分を修正する。

⑥gitにpushする。

⑦開発しているflutterアプリのworkspaceを開き、pubspec.yamlのdependenciesに追加する
以下のように追加します。

```
dependencies:
    swipable_stack:
       git:
         url: カスタマイズしてpushしたGitレポジトリーURL
```

⑧flutter pub get



#まとめ
- dependenciesにgitのurlを指定することができる。
- 今回はカスタマイズしたいFlutter Packageを修正したものを使用したが、オリジナルのパッケージもこのGitにあげれば読み込める。


言語交換マッチングアプリ『CROSSER』もよろしくお願いします。:two_hearts:
評価もいただけると嬉しいです！
iOS/Androidモバイル対応:iphone:
https://crosser.page.link/crosser
入力フォームを作る時の考慮

入力フォームを作成する際に考慮するポイントが色々とあったのでまとめてみた。
UIについては、取り扱う情報によって、考慮する範囲は変わってくるのと、正解はないと思うので、考え方を参考にしてもらえればと思う。

# どういう画面にするか考える

### 入力フォームに配置する項目に無駄のものはないか
- 入力項目の数は最小限に絞る  
氏名、年齢、性別など本当に全てが必要なのかを考慮し、できる限りミニマムに絞る
- 個人情報が必要かどうか  
    - 問い合わせなど、匿名でも良いものであれば個人情報は極力無くしておくと、個人情報流出のリスクを除外できる。
    - 個人情報を扱う場合はセキュリティ面での考慮も出てくるので、実装コストにも跳ねてくることを考慮しておくこと。

### フォームのUIはユーザが操作しやすいものになっているか
- 入力フィールドはLabelの横か下か  
    - 入力は通常、上から下に垂直に実施するのが自然なのでラベルの下が良い。
    - ラベルと入力フィールドが横並びだとみづらい。（ラベル名が長かったりするとさらにみづらくなる)
    - 参考記事 https://popinsight.jp/blog/?p=4113
- ラジオボタン or プルダウン
    - 項目が少ないなら、ラジオボタンで。（選択肢が少ないのであれば全て見せてしまった方がいちいちプルダウンを押させる必要がない)
    - 項目数が多ければ、プルダウンで
    - 参考記事 https://f-tra.com/ja/blog/column/2960

### 入力項目ごとの考慮
- 姓名の入力
    - 姓と名で2つのフィールドに分ける
        - メールの文面など何かで姓と名の間にスペースを入れたいときを想定して初めから別で保持していた方が良い。
        - 分けない場合ユーザによっては、姓しか入力してくれなかったりする人も出てきてしまい、データとして扱いにくくなってしまうため
- 生年月日の入力
    - プルダウン or 数字で入力
        - 個人的にはプルダウン派  
          数字での入力はシンプルだが、スマホも考慮するとタップで操作できるUIが良い。PC版のみ数字でスマホはプルダウンとするのも有りだと思う。
    - 選択値の範囲は100年
    - 初期値は利用するユーザ層に合わせると良いかも
    - 参考記事 https://parashuto.com/rriver/development/implement-responsive-date-picker

### 確認画面は必要か
- フォームの用途次第で要否を判断する
    - 簡易的な問い合わせや、入力項目が少ないものは確認画面は必要ないと判断しても良い
    - 講座の申し込みや、購入など金額が発生するものなどは確認画面があった方が良い

### 入力項目のバリデーションはフロント側かサーバサイド側か
- 基本は、フロントとサーバサイドの両方で行う
    - フロントで行うことはユーザビリティの向上になる
    - サーバサイドでのバリデーションは必須(実施しないとDB登録でエラーしたり、ゴミデータが増える)

# セキュリティ面

### XSS(クロスサイトスクリプティング)対策
######XSSとは
HTMLインジェクションとサイトをまたがった悪意のあるスクリプト(javascript)が実行されてしまうものをクロスサイトスクリプティングという
実際に見てみないとわかりづらいので、以下のサイトなどで具体例を見るとわかりやすい
https://www.websec-room.com/2013/03/14/567
######対策
htmlはサニタイズする
https://qiita.com/rana_kualu/items/11cd41de5f0364ba2ee8
今どきのフレームワークだと大抵デフォルトサニタイズが有効になっている。 
何らかの事情でサニタイズをオフにする場合は、第三者がスクリプトを埋め込む形になっていないか確認すること。
例えば、DBにhtml形式でデータを保持させておいて、それをフォームに表示させたい場合などに、サニタイズをオフにする場合がある。
そのような場合、サニタイズをオフした項目について、画面上からユーザーが入力できる項目になっていないことを確認する。



### CSRF対策
######CSRFとは
XSSと似ているが、攻撃を任意のサイトの処理を使うものということが、XSSとの違い。
例えば、twitterにログインしているユーザが、悪意のあるサイトAを開いてそこの罠リンク(twitterでツイートするもの)を押して意図しないツイートがされてしまうようなもの(ログイン情報を格納しているcookieが悪用される例)
######対策
CRSFトークンをhtmlに埋め込み、自身のサイト以外からpostなどをできなくしよう。
XSSとCSRFの違いは以下を参考にしました。
https://qiita.com/wanko5296/items/142b5b82485b0196a2da
Redisを使って排他制御を行う（タイムアウト考慮版）

:::note info
この記事は以下の記事の続きです。先に前の記事を読むことをお勧めします。
:::

https://qiita.com/penguinsan/items/198cddec3552cb522a4c

今回は前に投稿した上記記事の最後で指摘したロックがタイムアウトした場合に起こる問題を解消します。


# 1.仕組み

簡易版での問題はロックのタイムアウト時間より処理が長くなってしまった場合、その長くなってしまった処理が最後に自分のロックしたものでないキーを削除してしまうことで意図せずロックが解除されてしまうということでした。

なのでロックを解除する際に自分のかどうかを調べて、自分の獲得したロック出なかった場合は削除しないようにすれば解決します。

## 1.1.NG例

実は既に前回のプログラムでも自分の獲得したロックかどうかの値はUUIDとしてロックキーに対応する値として入れてあります。
なので、ロックをリリースしている箇所[net.penguinsan.redis.MutexRedisService](https://github.com/penguinsan/redis_mutex/blob/main/src/main/java/net/penguinsan/mutex/MutexRedisService.java)の`releaseMutex`メソッドで以下のようにしてやればよいでしょうか？

```java
  public void releaseMutex(Mutex m) {
    final String objectKey = m.getObjectKey();
    try (Jedis r = this.jedisPool.getResource()) {
      String lockId = r.get(objectKey);
      if (lockId.equals(m.getLockId())) {
        r.del(objectKey);
        System.out.printf("delete key : lock_id=%s\n", m.getLockId());
      } else {
        System.out.printf("not delete key : lock_id expect=%s actual=%s\n", m.getLockId(), lockId);
      }
    }
  }
```

これだと最初のgetから次のdelまでの間にRedis側で値が書き換わってしまう可能性がある（間にRedisのコマンドが割り込む可能性がある）ので確実ではありません（大抵はうまくいってしまうかもしれませんが・・・）

## 1.2.正解例

getとdelの間にコマンドを割り込ませず判定するにはどうするか？
Luaスクリプトで上記と同じ判定を記述してRedis側で実行すれば間にコマンドを挟まれることなく実行できます。

```java
  public void releaseMutex(Mutex m) {
    try (Jedis r = this.jedisPool.getResource()) {
      r.eval(
            "local id = redis.call('GET',KEYS[1])\n"
          + "if id == ARGV[1] then\n"
          + "  redis.call('DEL',KEYS[1])\n"
          + "end\n",
            List.of(m.getObjectKey()), List.of(m.getLockId()));
    }
  }
```

Luaスクリプトに関しては詳しく説明しませんが、RedisにevalコマンドでLuaスクリプトと必要なパラメータを渡してやることでスクリプトに書かれた一連の処理をアトミックに実行することができます。

# 2.まとめ

上記のコードをもう少しまとめて書き直したものをgithubに公開してありますので参考にしてみてください。

https://github.com/penguinsan/redis_mutex_ex

Luaスクリプトを駆使すると分散処理系で各サーバーにユニークなIDを発行したり、いろいろなことができるので面白いです。
amplify auth で emailとpasswordだけでサインアップさせたい時

```yml
AliasAttributes: !Ref aliasAttributes
```
を消して

```yml
UsernameAttributes:
  - email
```

に変更した上で `amplify push` するとemailとパスワードのみでサインアップできるようになる

```yml
UsernameAttributes: !Ref aliasAttributes
```
でもいけるかもしれません。

※メモ用なので雑ですみません
感情を持ったAIを作ってみたい(0.5)

#今回は何をするの？
今回は前回の「感情を持ったAIを作ってみたい(0)の続きになります。
ですが、今回もコードは書きません。ポエムのようなものなので「はぁ〜ん、この人はこんなこと考えているのね〜」という感じで見ていただければ幸いです。

https://qiita.com/konanomono/items/7930a8daf319068c0b2b

###前回の話
前回は「深層強化学習」ならいけるのではないか？と考えましたが、それ以降YouTubeやネット上にある資料、Qiitaに投稿されている記事を見ながら勉強に励んでいました。

ですが、最近「Transformerすごいなぁ」「BERTいいなぁ」と思っており、仕組みについて熱心に調べていました。

###タバコを吸っていて思ったこと
前回の話で「Transformer」「BERT」を調べていると記載しましたが、感情を持たせたいと思っているうちに自分なりに色々と考え、「この仕組みならいけるかなぁ…」など結構考えているのですが、そもそも「Transformer」「BERT」は機械翻訳や自然言語処理の手法だということをタバコを吸っている時に思い出しました。

確かに、感情のデータを抽出するのには使用できる部分はありますが、私がやりたいのは「感情を持たせる」ことなので、手法的に間違いではないか…？と考え始めました。

Transformer、BERTについては下記からご覧ください。とても参考になる動画です。

https://youtu.be/50XvMaWhiTY

https://youtu.be/IaTCGRL41_k

###考えたこと
確かに手法を学ぶことはいいことなのでそこはいいのですが、そもそも実現するための手法が間違っていることに気づき、自身が作成していた案を再修正することになりました。

何を作りたいか？と問われると、簡単にいうと「ドラえもん」のようなものですね。

もっと細かくすると、「特化型AI」ではなく「汎用型AI」を作ることを目的としてこの研究を一人で始めたのを最近思い出しました。

勉強のアウトプット用に記事を書いていましたが、最近勉強に励みすぎて軌道がずれていることに素早く気づくことができていませんでしたね。(汗)

###案はどんなことを考えているの？
これについて気になる方もいるかもしれませんが、申し訳ありませんがそれは言えません。(理由的に図で示さないと、わからない方が多いと思いますので)

最近は、人間の声、目についての手法についても勉強しております。声について最近よく見ているものを下記に記載させていただきます。

https://qiita.com/Hiroshiba/items/b4daca0176af5fd352a2

#勉強について
###最近の勉強
最近は再度、「データの読み込み」「数学」「統計学」などを勉強し直していますね。パラメーターのチューニングについても学ばなければならないなとも考えてますね。
ネット上で調べればいくらでも出てきますが、従来のものだけでなく自分の考えたものを実現できるように細かく自身の研究の軌道を毎日修正するべきか否かを考えて行きたいと思います。

あとはいつもの挨拶で締めたいと思います。ここまで読んでいただき、ありがとうございました。(そろそろコードをあげたいです。。。)


#挨拶
どうも、組込みエンジニアとして、とある企業におります粉です。

・では、組込みエンジニアですがAIエンジニア、機械学習エンジニアとして転職したいので、自身でいろいろと勉強を行っております。

・さて、なんでAIエンジニアや機械学習エンジニアになりたいの？と疑問をもたれる方も多いと思いますので、簡単に説明させていただきます。
１、元はAIを作ってみたい、社会問題、労働に関してもっと働きやすい環境が必要なのではないか？と考えたため様々な課題をAIなどの先端技術でアプローチをかけてみたいと思い、AIエンジニアを目指しました。
２、ですが、今やっているのは組込みエンジニアのため、使用する技術、言語が違うといったことから、独学でやってみようと思いまして、最近勉強をはじめました。
３、転職を目指す、自身の夢を叶えたいという願いもありますので、こうやって学んだことを記事しています。

・いろいろとお話ししましたが、まずは、私よりも知識、技術が豊富な先輩方から多くのことを意見、修正点、アドバイスをいただけることを楽しみにしています。

・まだまだ新参者、理解が足りていない部分もあるので記事を書きながら、修正を繰り返して理解を深めれればと思っております。(AIを研究している企業や研究機関に転職したいです。

・こんな手法もあるぞ、やり方はこうだ！！などの意見も募集しております。
モックデータが生成できるサイトがめちゃ便利！


Mockaroo と言うモックデータを入手するのにとても便利なサイトを紹介。

https://mockaroo.com/

## max で 1000 レコードのデータが生成できる

1000 もあれば十分できしょ！

![Screen Shot 2021-07-31 at 20.43.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157574/377e57c9-8c6f-d176-cde4-0bd5f92a6a1e.png)

データ入力されていない割合も指定できる。ユーザーは意図せず入力しないこと多いからね。

## 生成できるデータの種類が豊富

ほぼほぼ困らない程度の種類があるのではないでしょうか。。すげっ。

![Screen Shot 2021-07-31 at 20.51.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157574/95a84e54-b039-6db1-deb6-47d0ac32566a.png)

## ダウンロードできるファイルの種類が豊富

![Screen Shot 2021-07-31 at 20.46.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157574/4a72a009-e742-960f-abc4-3cd3292dd25b.png)

## まとめ

使わない手はない！
どんな ipv6 アドレスが使われているのか調べてみた (2021-07-31 現在)

* 世の中のドメイン名をいくつかピックアップして、どんな ipv6 アドレスが割り当てられているか調べてみました。
* prefix (64-bit or 56-bit ?) のあとは、0 を続けて、最後の 16 bit をいろいろ変える、みたいなのが多いのかなぁ、と思い。
* 以下は prefix を除いた部分のみ書いています。
* facebook (group) の :face:b00c::* が光っていますね！

| domain name | address |
| --- | --- |
| cia.gov | ::184d |
| facebook.com | :face:b00c:0:25de |
| linkedin.com | ::14 |
| netflix.com | :(64-bit) |
| nict.go.jp | ::13 |
| ntp.nict.jp | ::2<br />::fff3<br />::fff4 |
| spotify.com | :: |
| wikipedia.org | ::1 |
| www.google.co.jp | ::2003 |
| www.google.com | ::2004 |
| www.instagram.com (alias) | :face:b00c:0:4420 |
| www.intel.com (alias) | ::b |
| www.nttdocomo.co.jp | ::1:c6 |
| yahoo.com | ::1:0<br />::1:1<br />::8000<br />::8001<br />::f000<br />::f001 |
「VBA を呼び出し」アクティビティでそれでも遭遇するエラー

## 皆もすなるQiitaといふものを、儂もしてみむとてするなり。

と言う訳で、こん＊＊は！はなっち！です。

★★★この記事はUiPathブログ発信チャレンジ2021サマー、7月31目の記事です。★★★

###振り返り
前回は、「VBA を呼び出し」アクティビティで遭遇するエラーについてまとめました。
で、.basファイルは"SJIS"で記述した、引数の属性もInteger型に対して、ロボもInt32型で定義した、これでもうバッチリですね！

###落とし穴はそこにある！
Int32型の変数を、「VBA を呼び出し」アクティビティのObject型経由で、VBAのInteger側に渡して処理をしていきます。
例えば、VBAのInteger側に渡された値が、固定値Xと、固定値X+3の間にある時、Trueを返すFunction関数を作成したとします。

こんな範囲チェックのFunction関数を用意しなくても、条件分岐アクティビティで実装できるぢゃん！とお思いでしょうが、そこは堪えて、お読みください。

Function関数のテストパタンとしては、
表 テスト時の値とその予想結果

|値　 |結果 |備考|
|:---:|:---:|----|
|X - 1|False||
|X |True|下限閾値|
|X + 1|True||
|X + 3|True|上限閾値|
|X + 4|False||

一通り、試験は合格する訳ですが、折角Int32型を使っているので、Int32型の最大値(Int32.MaxValue）を指定して試験してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/a076bb42-01ec-0820-44a8-91be42530bf4.png)
図1 Int32型の変数に、Int32.MaxValueを設定した

###Int32.MaxValueの場合、何が起こったか
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/47a5cb47-2d87-db5e-34ce-9067e4b1537d.png)
図2 実行時エラー

結果は「範囲外です」となりました。Int32型とInteger型。同じInt系の型ではないか？と首をかしげる方もいらっしゃると思いますが、ここがポイントなのです。

UiPathで、と言うか、.Netでの各数値系型の取りうる値を見てみましょう！

|型|最小値　　　　|最大値　　　　|
|--|-------:|-------:|
|Int16|-32,768|32,767|
|Int32|-2,147,483,648|2,147,483,647|
|Int64|-9,223,372,036,854,775,808|9,223,372,036,854,775,807|
|Long|-9,223,372,036,854,775,808|9,223,372,036,854,775,807|
|Single|-3.402823E+38|3.402823E+38|
|Double|-1.79769313486232E+308|1.79769313486232E+308|

巨大ですねぇ。

一方、VBAでの各数値系型の取りうる値を見てみましょう！

|型|最小値　　　　|最大値　　　　|
|--|-------:|-------:|
|Integet|-32,768|32,767|
|Long|-2,147,483,648|2,147,483,647|
|Single|-3.402823E+38|3.402823E+38|
|Double|-1.79769313486232E+308|1.79769313486232E+308|

これを見ると、Int32型のMaxValueは、Integer型には格納できない事が分かりますね。これが先の「範囲外エラー」に繋がるのです。

###どうしたらいいか？
対策は３つあると考えています。
１）Int16型を使用し、VBAのInteger型に十分格納できるようにする。
２）Int32型を使用し、VBAのLong型に変更し、ロジックで制御する
３）渡す値の範囲を予め決めてしまい、論理的に十分格納できるようにする。

１）、２）に関して言うと、.Netでの型定義と、VBAでの型定義が違うということを理解すれば、どちらを採用すべきか自ずと判断付きますね。

３）は、ロボ側で、その範囲を予め決めてしまい、それをVBA側の型で十分格納できるようにしてあげる方法で、実際にはMathクラスを駆使して、実装します。

例）どんな数が来ても、業務的な最小値２，最大値５とする。
代入アクティビティ
左辺：変数X(Int32型)
右辺：Math.Max(2, Math.Min(5, 変数X))

|変数X|計算式|評価|
|:--:|---------|---------|
|-1|Math.Max(2, Math.Min(5, -1))|5と-1の最小値(=-1)と2との最大値(=2)|
|0|Math.Max(2, Math.Min(5, 0))|5と0の最小値(=0)と2との最大値(=2)|
|2|Math.Max(2, Math.Min(5, 2))|5と2の最小値(=2)と2との最大値(=2)|
|4|Math.Max(2, Math.Min(5, 4))|5と4の最小値(=4)と2との最大値(=4)|
|5|Math.Max(2, Math.Min(5, 5))|5と5の最小値(=5)と2との最大値(=5)|
|6|Math.Max(2, Math.Min(5, 6))|5と6の最小値(=5)と2との最大値(=5)|

この処理結果を、「VBA を呼び出し」アクティビティのエントリメソッドのパラメーターに指定してあげれば、「範囲外です」と言うエラーは発生しません。

##おわりに
いかがでした？

「VBA を呼び出し」アクティビティのエントリメソッドのパラメーターに定義する型、
VBAとして定義する型についてまとめました。同じ系列の型でも、コンピューターの内部ではその長さと言うのを意識して使ってくれているのですね。どうせなら、一致した作りにしておいてくれれば...と思うのですがね(^^♪

そういう型と型の取りうる値の範囲を頭に入れつつ、正しく引数を指定し、正しく戻り値を処理し、業務効率化を進めてまいりましょう！

是非UiPathでのロボ開発の一助になればと思っています。

ありがとうございました！
[Go Snippet] "RANDOM USER GENERATOR" からの JSON を Unmarshal する


## 概要
[Random User Generator](https://randomuser.me/) というサイトで、ランダムなユーザー情報を取得できる JSON の API を提供している。

早速使ってみる。

[API はこの URL (https://randomuser.me/api)](https://randomuser.me/api) からアクセスできる。

## Unmarshal したい JSON の構造を調べる

```json
{
      "location": {
        "street": "9278 new road",
        "city": "kilcoole",
        "state": "waterford",
        "postcode": "93027",
        "coordinates": {
          "latitude": "20.9267",
          "longitude": "-7.9310"
        }
      }
}
```

この構造は、こう書ける

```go
type Location struct {
	Street      string `json:"street"`
	City        string `json:"city"`
	State       string `json:"state"`
	Postcode    string `json:"postcode"`
	Coordinates struct {
		Latitude  string `json:"latitude"`
		Longitude string `json:"longitude"`
	} `json:"coordinates"`
}
```

前もって構造体を定義していなくても、`type` 配下で別の `type` を直接書くこともできる。

その場合の、json タグは、`{}` で閉じた後であることに注意。

## コード

```go
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
)

type RespData struct {
	Results []Result `json:"results"`
	Info    Info     `json:"info"`
}

type Result struct {
	Gender   string   `json:"gender"`
	Name     Name     `json:"name"`
	Location Location `json:"location"`
	Email    string   `json:"email"`
}

type Name struct {
	Title string `json:"title"`
	First string `json:"first"`
	Last  string `json:"last"`
}

type Location struct {
	Street      string `json:"street"`
	City        string `json:"city"`
	State       string `json:"state"`
	Postcode    string `json:"postcode"`
	Coordinates struct {
		Latitude  string `json:"latitude"`
		Longitude string `json:"longitude"`
	} `json:"coordinates"`
}

type Info struct {
	Seed    string `json:"seed"`
	Results int    `json:"results"`
	Page    int    `json:"page"`
	Version string `json:"version"`
}

func main() {

	url := "https://randomuser.me/api/"
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("Error")
	}
	defer resp.Body.Close()

	// resp: Pinter to type Response
	// fmt.Println("Status", resp.Status)
	// fmt.Println("StatusCode", resp.StatusCode)

	body, _ := io.ReadAll(resp.Body)

	var data RespData
	_ = json.Unmarshal(body, &data)
	fmt.Printf("%v\n", data.Results[0])
	fmt.Printf("%v\n", data.Info)
}

```
「VBA を呼び出し」アクティビティの<<Object型>>

## 皆もすなるQiitaといふものを、儂もしてみむとてするなり。

と言う訳で、こん＊＊は！はなっち！です。

★★★この記事はUiPathブログ発信チャレンジ2021サマー、7月31目の記事です。★★★

###「VBA を呼び出し」アクティビティとは
「VBA を呼び出し」アクティビティは、Excel Application Scopeの配下で機能する、EXCEL-VBAで記述されたFunction 関数、Sub関数を呼び出すアクティビティです。これを使えば、EXCEL-VBAで組んだビジネスロジックなども転用できるわけです。ただし、注意点があります。それをちょいと説明していこうと思います。

###「VBA を呼び出し」アクティビティの設定
「VBA を呼び出し」アクティビティで設定する箇所は、４か所あります。
1）コードパスファイル名(図1では、"hogehoge.bas"。これは必須)
2）エントリメソッド名(図1では、"hogehoge"。これは必須)
3）エントリメソッドのパラメタ(図2では、{INHoge1,INHoge2}。これがエントリメソッドに指定された関数の入力パラメタとなる。図3参照)
4）出力値（図2では、Outhoge。Function関数での戻り値を受け取る変数）
です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/6f84e316-fe60-26f3-689a-42557365353e.png)
図1 「VBA を呼び出し」アクティビティ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/9b07b065-fe93-7391-ae54-c15d58856be9.png)
図2 「VBA を呼び出し」アクティビティのプロパティ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/fb399bb2-1ac2-e676-05ae-91f090252913.png)
図3 "hogehoge.bas"ファイルの"hogehoge"Function関数

実装した際の値は、以下の変数を用意し、変数の型を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/f8a587c6-7fb4-8fae-6ca1-21585df94236.png)
図4 ロボット上の設定値

"hogehoge.bas"ファイルの"hogehoge"Function関数は、2つの引数ともString型を想定しています。
が、ここではINHoge2をInt32として定義してみます（値は2）

###実行してみましょう！

型が違っても、図3のFunction関数の通りに、Hoge1とHoge2を、"/"で連結した結果を返していますね（図5 ロボットでの実行結果参照）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/9048749d-db13-4426-3cae-53fa06812c64.png)
図5 ロボットでの実行結果

###なんで？
EXCEL-VBAで開発を行った方は実行できてしまった事にビックリされた事と思います。わたしもそうでした。結構いけるぢゃん！ってね。

これには、訳がありそうです。

図2の「エントリメソッドのパラメーター」部分をマウスオーバーすると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/1a4bdf6e-d6f2-f140-6f63-cee2212527e1.png)
図6 「エントリメソッドのパラメーター」の説明
が表示されます。そうなんです。「VBA を呼び出し」アクティビティがエントリメソッド名を呼び出す際に準備されている変数は30個であり、その属性はObject型なのです。

###Object型
Object型はしらべてみると、
".NET クラス階層のすべてのクラスをサポートし、派生クラスに下位レベルのサービスを提供します。 これは、全 .NET クラスの基本クラスであり、型階層のルートです。"
と記載されています。型階層のルートと言うことは、他の属性の頂点にいるもので、なんでも受け取ってくれる型なんでしょう。

ロボ側で、Object型で定義した変数は、「エントリメソッドのパラメーター」に指定するとそれはそのままObject型として扱われるようですね。図4のように、Int32型で定義した変数では、それはInt32型の属性を持ってますよ！ってのをObject型に教えてあげつつ、扱われる…的な。

実際に、「VBA を呼び出し」アクティビティが図3のFunction関数を呼び出す際に、その引数の属性の定義に合わせて属性変換(CType：Convert Type）してくれるのでしょう。

###戻り値、出力値は？
「VBA を呼び出し」アクティビティの出力値の型がObject型なので、Function関数の戻り値は、型を定義したとしても、ロボとしてはObject型で受け取ります。例えば、Function関数の戻り値が配列であっても、ロボとしてはObject型で受け取り、その後使用する際に、属性変換(CType：Convert Type）し、扱い易くする必要はありますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/65b1e24e-58b8-091d-2b7a-bdc85265be44.png)
図7 配列文字列型のFunction関数の戻り値を属性変換の例

###お作法
Object型がやってくれるから！と思っていても、ロボを作成する上では、Function関数で定義された型をエントリメソッドのパラメーターに指定していきましょう。他の方があとで見返した時に、あれ？属性が違うな。。。と、訝しがる事必至ですから。



##おわりに
いかがでした？

Object型って、あるのは分かっていますが、どんな時に使うんだろうねって感じの人もいらっしゃると思います。しっかり理解していただいて、美しいロボを作成してまいりましょう！


是非UiPathでのロボ開発の一助になればと思っています。

ありがとうございました！
Node-REDで郵便番号から住所情報を表示するbotを作成

<h2>目的</h2>
郵便番号の7桁を入力すると、それに対応する住所と読み方を表示する。

<h2>製作の理由</h2>
申請書類に住所や住所のカナを記載する業務がある。
読み方を郵便局のホームページから検索すると<font color="#ff45000">県、市、それ以下読み方がバラバラに表示されるため簡単にコピー&ペーストができない。</font>
更に複数の住所情報を調べる必要があるのに、郵便局のホームページでは最初の画面に戻されてしまうため作業に手間がかかる。

また申込の意思確認で住所を正しく伝えなければならない事があり、その読み方が誤っていると再度確認して折り返すように言われてしまう。
常に持ち歩いているスマホからでも簡単に調べられると効率が良いと感じ、今回<a href="https://nodered.org/">Node-RED </a>とLINEBOTを使用して作成した。

利用したAPI：<a href="http://zipcloud.ibsnet.co.jp/doc/api">Zipcloud</a>

<h3>動作①7桁の数字で郵便番号を入力した場合</h3>
![存在する住所を入力.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/bc91f6c1-7d0a-1d8d-a22e-2f920929ad24.png)
住所と読み方がメッセージに表示される。

<h3>動作②7桁の数字以外の入力をした場合</h3>
![桁数が間違っている.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/fa809262-c740-1d2d-a519-54235eec87cc.png)
7桁の数字を入れるようにメッセージが表示される。
「Yahoo」の様に文字を入れても同様。

<h3>動作③存在しない郵便番号を入力した場合</h3>
![存在しない住所を入力.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/ff785159-6f5c-d97d-1a58-dc6801bd8d17.png)
情報が存在しないメッセージが表示される。

<h2>フロー</h2>
![全体のフロー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/ece8e581-7a4a-cc43-aa16-b8b6467ea5a3.png)
<h3>①7桁の数字を判別する</h3>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/6d575013-50a9-d78e-24d3-1fdca8c79904.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/8588f2f6-3a5a-11bf-e954-2e9a3d991076.png)
chzipcodeというパラメータを設定し、それを100倍する事で001-0010の様な住所も判別できるように設定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/db01296f-b1f1-3168-7bbd-2bcc3ed5051c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/95f5a8a3-ed6e-674c-9989-87ce099cea7c.png)
chzipcodeの値が1000000～1000000000の間の数値になっていれば、住所を探しにAPIへデータを送信する。
しかしと<font color="#ff45000">数字が7桁であると素直に判定に利用した方がバグにならないはず。</font>
もっとスマートなやり方があれば教えてほしい。

<h3>②住所の存在をチェックする</h3>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/5289f36e-b3a4-5606-d333-536318d46244.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/376aec29-fc7c-59a1-bf55-2cdf471ed9c0.png)
resultsがnullであれば、住所が存在しないメッセージをLINEに返す。
存在していれば住所とカナを表示する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/ff6c98ae-8950-0983-224b-481dc37fb997.png)

<h2>終わり</h2>
初めてLINEBOTとAPIを利用したプログラムを作ったが、変数の定義が簡単である事に驚いた。
かなり古いプログラムを経験してきたため、宣言をしなくても使えてしまうので戸惑ったが慣れるとこちらの方が便利だと思う。
この機能を普段申請書類を出してくれるメンバーに渡したところ、便利なツールとの評価を得られた。
HTTPステータスコード

# HTTPステータスコードとは
HTTPレスポンスと一緒に返ってくる番号のこと。
HTTPメソッドで通信が行われる時必ずステータスコードと一緒にレスポンスが
返される。

***重要!! これはおさえましょう。***


|ステータスコード|意味|
|--|--|
|200|正常です。|　
|400|リクエストに誤りがあります。|
|404|　そんなものありません。|　
|500　|サービス側のミスです。|



知っておいた方がいいものです。

|ステータスコード|意味|
|--|--|
|204|データとして返すものがありません|
|302|リダイレクトします。|
|304|キャッシュ使ってます。|
|401|認証できないので見せられません|
|403|アクセス権がない|
AWS日記29 (Amazon VPN)

# はじめに
今回は Amazon Client VPN を試します。
AWSドキュメントの[クライアント VPN の開始方法](https://docs.aws.amazon.com/ja_jp/vpn/latest/clientvpn-admin/cvpn-getting-started.html) の手順で進めました。



# 準備
少なくとも1つのサブネットとインターネットゲートウェイを持つVPCの準備。

今回は CloudFormation を利用し、準備しました。
使用したテンプレートは[Github](https://github.com/tanaka-takurou/cloud-formation-templates/blob/master/vpc_for_vpn/template.yml)に。


# サーバーおよびクライアント証明書とキーの生成
AWSドキュメントの[相互認証](https://docs.aws.amazon.com/ja_jp/vpn/latest/clientvpn-admin/client-authentication.html#mutual)の手順に沿って生成しました。

# クライアント VPN エンドポイントを作成する

 - Amazon VPC コンソール から クライアント VPN エンドポイントを作成する
![step2-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586707/8eea8568-f4f0-8598-2bf8-6a07ec1eb2aa.jpeg)


 - 各証明書のARNを指定

![step2-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586707/674fa7d5-2433-82be-cefb-a4a484cb69f3.jpeg)



# クライアントの VPN 接続を有効にする

 - Amazon VPC コンソール から 関連付けを選択
![step3-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586707/54ba2a50-6994-d27a-659a-479299a11b15.jpeg)


 - 関連付けるVPC、サブネットを指定

![step3-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586707/bdf8b06f-d8b7-edca-658f-f50ec0b498cc.jpeg)


# クライアントのネットワークへのアクセスを承認する


 - Amazon VPC コンソール から 受信の承認を選択
![step4-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586707/078f439c-0aff-41bc-1875-a79e0b36994d.jpeg)

 - アクセスを許可するネットワークの CIDR を入力

![step4-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586707/d4446efa-1a06-4466-eec7-489c701fe4be.jpeg)


# クライアント VPN エンドポイント設定ファイルをダウンロードする

 - Amazon VPC コンソール から 設定ファイルをダウンロード
![step6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586707/242e22d6-b06b-bb76-0f55-ab730bf88b16.jpeg)


# クライアント VPN エンドポイントに接続する
[AWS Client VPN download](https://aws.amazon.com/jp/vpn/client-vpn-download/)から AWS が提供するクライアントをダウンロードし、設定ファイルを指定して接続しました。

![step7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586707/66ee9232-1990-0650-5b7c-09bbbf535b5a.jpeg)


### 接続履歴の確認

 - Amazon VPC コンソール から 接続タブを選択

![vpn-status-history.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586707/cf6b2805-e7bb-c0eb-ca95-7a6270264a5f.jpeg)



# 終わりに
Amazon Client VPN を試しました。
サイト間のVPN ( AWS Site-to-Site VPN ) も今後試してきたいと思います。 


<details><summary>参考資料</summary><div>

[AWS Client VPN とは?](https://docs.aws.amazon.com/ja_jp/vpn/latest/clientvpn-admin/what-is.html)
クラスの属性に対する加算・減算代入演算子(+=, -=)の振る舞いを定義したいとき

例として以下のクラスを定義する。

```example.py
class Example:
    def __init__(self) -> None:
        self.num: int = 0
```

加算・演算代入演算子を利用する際も、属性に定義されているsetterが呼びだされる。
これを利用して振る舞いを定義できる。

プロパティを用いて書き直すと

```example.py
class Example:
    def __init__(self) -> None:
        self.__num: int = 0
    @property
    def num(self):
        return self.__num
    @num.setter
    def num(self, value):
        self.__num = value
```
self.__numに対して演算した際の、setterの様子を見てみる。

```example.py
example = Example()
example.num = 2
example.num += 1
```
`examaple.num = 2`の場合、setterの引数`value`には、右辺の`2`が入る。

`example_num += 1`の場合、setterの引数`value`には、計算後の値(ここでは`3`)が入る。
もちろん`self.__num`の値はsetterの`self.__num = value`の行で代入されるまでは計算前の値になっている。
これを利用して、valueを代入する前のself.__numの値とvalueの値を比較することで、
加算・減算代入を場合分けして振る舞いを定義できる。

```example.py
    @num.setter
    def num(self, value):
         if value < self.__num:  # 成立するのは加算代入をしている場合。ただし通常の代入でも成り立つ可能性はある
            pass  # += のときの振る舞い
        elif value > self.__num:  # 成立するのは減算代入をしている場合。ただし通常の代入でも成り立つ可能性はある
            pass  # -= のときの振る舞い
        self.__num = value
```
フォルダと拡張子を指定してフォルダ内のファイルを別の１つのフォルダにコピー

##はじめに
サーバーに存在するサブフォルダを含む大量のファイルをローカルの１つのフォルダにダウンロード（コピー）して処理したい時が割とある。
フォルダごとに同一名のファイルが存在する場合はコピーする際に上書きされる可能性がある。
また、フォルダのデータ全てをコピーするのではなく、特定の拡張子のファイルだけコピーしたい場合が結構ある。
そんな課題を解決するためのGUIを作成した。

##仕様
![cpygui.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499277/d91a1469-1937-7ec4-8f11-d3fcce0676a2.png)

・上下２つの「フォルダを選択」ボタンで「コピー元フォルダ（1行目）」と「コピー先フォルダ（2行目）」を選択する。
・3行目にコピー対象の拡張子を「.」抜きで入力する※最大5つ
・「実行ボタン」でコピー処理が実行される
・コピー先のファイル名はコピー元のディレクトリを起点とした相対パスのパス文字がアンダーバーに変換された名前が付けられる

##コード

```python
import PySimpleGUI as sg
import os
import re, shutil
import pathlib

INPUT_BOX_SIZE = 5
HEADER_ROW = 1
INI_EXT_LINE = 2
MAX_NUM_EXT = 5

####　関数
# ファイル名変換関数
def name_savefile_dirname(path ,org_dir):
    file_path = path.replace('/', os.sep) #パスの区切り文字を統一
    org_path = pathlib.Path(org_dir)
    sub_path = pathlib.Path(file_path)
    file_name = sub_path.relative_to(org_path) # 指定ディレクトリ基準のファイルの相対パスを取得
    return str(file_name).replace("\\","_") #パスの区切り文字をアンダーバーに変換

# ファイルコピー関数
def copy_files(org_dir, save_dir, target_ext):
    file_list = [] #コピーするファイルのリスト
    filepath_list = [] #コピーするファイルパスのリスト
    for dirpath, dirnames, filenames in os.walk(org_dir): #コピー元のディレクトリを基準にtarget_extで指定した拡張子のファイルをリスト化
        for file in filenames:
            for ext in target_ext:
                m = re.search(re.escape(ext), file) #指定した拡張子のファイルを探す
                if m :
                    file_list.append(file) #ファイル名をリストに追加
                    filepath_list.append(os.path.join(dirpath, file)) #コピー元ファイルのパスをリストに追加

    for i in range(len(file_list)):
        save_file_path = os.path.join(save_dir, name_savefile_dirname(filepath_list[i], org_dir)) #コピー先ディレクトリ名とコピー元ディレクトリを付けたファイル名を結合
        shutil.copy2(filepath_list[i], save_file_path) #ファイルをコピー
        print(save_file_path)

####　GUI
#  セクション1 - オプションの設定と標準レイアウト
sg.theme('Dark Blue 3')

layout = [
    #1行目
    [sg.InputText('コピー元フォルダ',enable_events=True,), sg.FolderBrowse('フォルダを選択', key='folder_from')],
    #2行目
    [sg.InputText('コピー先フォルダ',enable_events=True,), sg.FolderBrowse('フォルダを選択', key='folder_to')],
    #3行目
    [sg.Text('拡張子(ex:csv)', size=(15, 1)),sg.InputText('csv', size=(INPUT_BOX_SIZE, 1)),
     sg.InputText('xlsx', size=(INPUT_BOX_SIZE, 1)),sg.InputText('', size=(INPUT_BOX_SIZE, 1)),
     sg.InputText('', size=(INPUT_BOX_SIZE, 1)), sg.InputText('', size=(INPUT_BOX_SIZE, 1))],
    #4行目
    [sg.Submit(button_text='実行ボタン')]
]

# セクション 2 - ウィンドウの生成
window = sg.Window('ファイルコピー', layout)

# セクション 3 - イベントループ
while True:
    event, values = window.read()

    if event is None:
        print('exit')
        break

    if event == '実行ボタン':
        # フォルダのパスを抽出
        path_from = values['folder_from']
        path_to = values['folder_to']
        
        # 入力がある場合コピー対象とするように拡張子をリスト化
        ext_list =[]
        for i in range(MAX_NUM_EXT):
            if not len(values[INI_EXT_LINE+i].strip())==0:
                ext_list.append("." + values[INI_EXT_LINE+i].strip())
        
        # コピー関数実行
        copy_files(path_from, path_to, ext_list)

        # ポップアップ
        sg.popup("終了～")

# セクション 4 - ウィンドウの破棄と終了
window.close()
```
3.11(標準) パレート分布

## 答案

Xの期待値は

```math
\begin{align}
\mathbb{E}_{X\sim f_X}[X]&= \int_\alpha^\infty\frac{\beta\alpha^\beta}{x^\beta}dx\\
&= \beta\alpha^\beta\int_\alpha^\infty x^{-\beta}dx\\
&= \beta\alpha^\beta\left[-\frac{1}{\beta-1}x^{-(\beta-1)}\right]_\alpha^\infty\\
&= \frac{\alpha\beta}{\beta-1},\ \ (1<\beta)
\end{align}
```

と，期待値は1<betaの時のみ発散せずに解が求まる．分散は．

```math
\begin{align}
\mathbb{E}_{X\sim f_X}[X^2]&= \int_\alpha^\infty\frac{\beta\alpha^\beta}{x^{\beta-1}}dx\\
&= \beta\alpha^\beta\int_\alpha^\infty x^{-(\beta-1)}dx\\
&= \beta\alpha^\beta\left[-\frac{1}{\beta-2}x^{-(\beta-2)}\right]_\alpha^\infty\\
&= \frac{\alpha^2\beta}{\beta-2},\ \ (2<\beta)\\
Var(X)&= \frac{\alpha^2\beta}{(\beta-2)(\beta-1)^2}
\end{align}
```

今，Y=log Xなる変換を行うと，

```math
\begin{align}
F_Y(y)&= P[Y\leq y]\\
&= P[\log X\leq y]\\
&= P[X\leq e^y]\\
&= \int_\alpha^{e^y}f_X(x)dx\\
\therefore f_Y(y)&= f_X(e^y)\frac{d e^y}{dy}\\
&= \frac{\beta\alpha^\beta e^y}{\exp\{y(\beta+1)\}}\\
&= \beta\alpha^\beta\exp(-\beta y)
\end{align}
```

ここで，

```math
\beta=\frac{1}{\beta},\ \alpha=e^y
```

を代入すると，

```math
f_Y(y)=\frac{1}{\sigma}\exp(-\frac{y-\mu}{\sigma})
```

## 参考文献

- 『[現代数理統計学の基礎](https://www.kyoritsu-pub.co.jp/bookdetail/9784320111660)』(久保川達也　著)
iPhoneでlocalStorageが消える

[CodePen上で、localStorageを使って遊んでいた](https://codepen.io/kob58im/pen/yLMNMNK)ところ、パソコンのChromeでは保持できてるのにiPhoneでは保存したlocalStorageのデータがたびたび消える現象が起きた。


試した感じだと、サイトを行き来するとすぐに消えてしまうっぽい。

(iPhoneの) Chromeアプリを落として再度開くと消える。

発生したversion: iOS版Chrome 92.0.4515.90

この辺の絡み？
https://www.torimochi.jp/871/

参考用
https://www.google.co.jp/search?q=javascript+localstorage+%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3
文章の読みにくい部分を指摘してくれるアプリを作った


こんにちは！[クフルダモノーツ](https://khufrudamonotes.com/biography)の[Yoshito Kimura(k1mu)](https://yoshito.khufrudamonotes.com/)です！


タイトルそのままです。
「**文章の読みにくい部分**」に色を付けて指摘してくれるウェブアプリを作りました。

https://readability-checker.khufrudamonotes.com/

#作った動機
…読みやすい文章を書くのって大変だと思うんですよ。
ついつい「という」とか「こと」とか使っちゃうし、細かくチェックするのも面倒だし。

だから、以前から「**読みにくい部分をチェックしてくれるアプリがあったら便利なのにな…**」と思っていました。

そして、最近「あれ？今なら自分で作れるかも」と感じてやってみたら…、できました。笑


![ScreenShot-720219183135.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486558/b975caa2-ba3b-e567-cb00-78aea4d53731.png)

おまけで「**読みやすい文章の書き方紹介**」や「**採点機能**」もあります。
(採点機能はエンタメ要素なので、あまり真に受けないでください。)

個人的にはかなり重宝しているので、よかったら使ってみてください。(๑˃̵ᴗ˂̵)و

https://readability-checker.khufrudamonotes.com/

#ちなみに…
法律の条文を入れてみたら-2532点とかになりました笑

![公文書等の管理に関する法律.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486558/6d6eeb3a-1498-2a30-c381-85ebe18ea71d.png)
rails エラーメッセージ・フラッシュメッセージ

##記事投稿画面
```posts/new.html.erb
<%@posts.errors.full_messages each do |message|%>・・１

<%=message%>・・エラーメッセージを表示
<textarea><%=@post.content%></textarea>・・直前の投稿内容を表示
```
・・１配列@posts.errors.full_messagesから要素を一つずつ取り出して変数messageに代入
#####＊注意点 
newアクションで@postが定義されないとエラーになる
###Userモデルの作成
カラム名：name　データ型：stringであるUserモデルの作成

```
$rails g model User name:string email:string
```
###投稿が空のときにエラーメッセージはどうなるのかターミナルで確認

```
$rails console //コンソール（入力・出力の機能を備えた装置の機能）の起動
>post=Post.new(content:")//contentが空であるPostインスタンスの作成
>post.errors.full_messages
=>[] //保存失敗前にはからの配列が入っている
>post.save 
=>false //作成したPostインスタンスをPostテーブルに保存=>失敗
>post.errors.full_messages
=>[contentを入力してください]//保存失敗後にはエラーメッセージの配列が入っている
```
##フラッシュメッセージ
フラッシュメッセージ・・ページ上に一度だけ表示されるページ
アクションで変数flash[:notice]に文字列を代入すると、flash[:notice]をビューで使える。
<%if flash[:notice]%>フラッシュメッセージが存在するときのみ表示
amplify vue の フォームのカスタマイズの公式ドキュメントが間違っている

amplify vue の フォームから電話番号を消したいと思い、フォームのカスタマイズを公式ドキュメント通りに実装しようとしたら動作せずとても困った。

```vue
<amplify-sign-up
  slot="sign-up"
  username-alias="email"
  :form-fields.prop="formFields"
></amplify-sign-up>
```

引用元:
https://docs.amplify.aws/ui/auth/authenticator/q/framework/vue#customization

公式だと`:form-fields.prop="formFields"`のように記述してあるのだが`:formFields="formFields"`と書くと動く。

```vue
<amplify-sign-up
  slot="sign-up"
  username-alias="email"
  :formFields="formFields"
></amplify-sign-up>
```

以下の質問を見つけて解決できた。
https://www.gitmemory.com/issue/aws-amplify/amplify-js/5363/811567032

[armen](https://www.gitmemory.com/armenr)さん、ありがとう。
SQL Server 2017 Expressの操作

#概要
SQL Server 2017 Expresの基本的な操作について記載しています。

#環境

|パラメータ |値|
|---- |-----------|
|OSのホスト名|SQL|
|インスタンス名|SQLEXPRESS|
|認証方法|Windows認証|
|データベース名|test|

#操作

## SQL Server 2017 構成マネージャの設定変更

SQL Server 2017 Expressはデフォルト値として、TCP/IPの通信が
無効となりますので、有効に変更します。


1.PowerShellを管理者で起動する。

2.以下コマンドでTCP/IPを有効とする。
※ManagedComputer[@Name='SQL']の箇所はOSのホスト名を入力する。
※ServerInstance[@Name='SQLEXPRESS']の箇所はインスタンス名を入力する。

~~~

$wmi = New-Object 'Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer'
$tcp = $wmi.GetSmoObject("ManagedComputer[@Name='SQL']/ServerInstance[@Name='SQLEXPRESS']/ServerProtocol[@Name='Tcp']")
$tcp.IsEnabled = $true
$tcp.Alter()

~~~

3.SQL Serverのサービスを再起動する。

~~~

Restart-Service -Name 'MSSQL$SQLEXPRESS'

~~~

4.SQL Serverに接続する。

「sqlcmd」コマンドを使用してSQL Serverに接続する時に
SQLEXPESSのインスタンス名を明示的に指定する必要があります。


~~~

sqlcmd -S localhost\SQLEXPRESS


~~~

5.データベースを作成する。

~~~

create database test;

GO

~~~

6.データベースのバックアップをする。

※SQL Server Management Studioでバックアップスクリプトを作成したときのコマンドとなります。


~~~

BACKUP DATABASE [test] TO  DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL14.SQLEXPRESS\MSSQL\Backup\test.bak' WITH NOFORMAT, NOINIT,  NAME = N'test-完全 データベース バックアップ', SKIP, NOREWIND, NOUNLOAD,  STATS = 10
GO


~~~

7.データベースのリストアをする。

※SQL Server Management Studioでリストアスクリプトを作成したときのコマンドとなります。


~~~

USE [master]
RESTORE DATABASE [test] FROM  DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL14.SQLEXPRESS\MSSQL\Backup\test.bak' WITH  FILE = 1,  NOUNLOAD,  STATS = 5

GO


~~~
CodeSignal - firstDuplicateにチャレンジ

コーディングしなさすぎてコーディングを忘れたエンジニアがコーディングを思い出すためにコーティングします。
今回は、アメリカのコーデイング練習サイトCodeSignalの問題「firstDuplicate」を解いていきます。
サイトによると、この問題はGoogleの面接で出されたようです。

##問題

```
a = [2, 1, 3, 5, 3, 2]
```

上のような数値の配列が渡されるので、左から見ていって最初に重複した数値を探します。
最初というのは、上の例なら、左から見ていくと3の重複が最初に検知できるので、答えは3です。

たしかに2も重複していて、1個目の2は配列の冒頭で登場しますが、2個目の2が出てくる前に3の重複が見つかるので、答えは2ではありません。

もし配列の中に重複した数値がなければ-1を返します。

制約：
1 ≤ a.length ≤ 10^5
⇨配列の要素数は1以上10,000以下
1 ≤ a[i] ≤ a.length
⇨配列内の数値は1以上、配列の要素数以下
たとえば[2, 2]なら、配列の要素数は2なので、中の数値も2以下（1か2）になります。
[2, 9]や[160, 3]はなしです。


##考え方・解説
まず最初に思いつくのは、ブルートフォースです。
ブルートフォースとは、力技で問題を解くことを意味し、単純な考えでいいけど計算量が多くなるのがデメリットです。

a = [2, 1, 3, 5, 3, 2]であれば、まず最初の数値2を基準にし、その後の値1, 3, 5, 3, 2と比較し、重複が見つかればその位置のindexを変数に格納します。
2個目の2はindex5で見つかるので、5を変数に格納します。
次に1を基準にし確認し、重複なし。
3を基準にし、index4の位置で重複が見つかります。そしたら変数の5よりももっと早いindexで重複が見つかったので、変数を4に書き換えます。
同じ要領ですべての値を確認し終えたあと、変数の格納されているindexを使って、a[変数]のようにして、配列から値を取り出せばOKです。

この方法は、普通に答えを目で探すときの方法と同じ要領だと思うので、簡単に思いつくのですが、ベストではありません。
なぜなら、ネステッドループ(ループの中にループがある状態)になるので、計算量が多くなるからです。
そこでなんとかループを一個できないかと考えると、すでに見た数値を別の集合体に突っ込んで、ループで見ていく数値がその集合体の中にあるか確認する方法が思い浮かびます。

もし既に見た（集合体の中にある）のであれば、その値が答えです。
なぜなら既に集合体にある＝今回が2回目の登場なので、その値は重複しており、かつ一番最初に検知した重複になるからです。

Javaで書くとこんな感じです。
集合体は別に順番を持っていなくていいし、重複を許可しない方が無駄が少ないので、HashSetを使用しています。

```Java:solution.java
int firstDuplicate(int[] a) {
    HashSet<Integer> seen = new HashSet<>();
    for (int i=0; i<a.length; i++){
        if (seen.contains(a[i])){
            return a[i];
        } else {
            seen.add(a[i]);
        }
    }
    return -1;
}
```
コードの説明
forで配列の要素を一つづつチェックしています。
もしその要素の文字をHashSetの中で検索し、もし初見であれば、HashSetに突っ込みます。
逆に、すでにHashSetの中に存在している場合はそれが2回目の登場なので答えとして返却します。



##学んだこと
要は、ブルートフォースはベストではないので、どうやって別の解き方を考えるかがキーだと思います。
その場合、ネステッドループをなくし、ループを一つにする方法があります。

ループを一つ減らしたいと言うことは、ループで確認する値と突き合わせるのは、過去にループで見た値しかありません。（ループが一個しかないので、ネステッドループのように先の配列の値を検索することはできない）

そのため、過去にループで見た値をどこかに格納しておかなければいけません。そこで集合体を利用します。
とはいえ、過去に見た値をすべて集合体に突っ込んだらそれは結局ネステッドループしてるようなものなので、集合体をもっとスマートにしたいです。
そのため、JavaのHashSetのような重複を許さない集合が利用できます。
集合の要素が少なければ、その分検索も早くなります。
rails バリデーション

##バリデーション
バリデーションとは・・不正なデータがデータベースに保存されないようにデータベースをチェックする仕組み。バリデーションに引っかかった場合（不正なデータの場合）にはデータベースには保存されない。
##バリデーションの例
Postモデルのバリデーション

```models/post.rb
class Post<ApplicationRecord
validates :content,{presence:true}
       #検証するカラム名　　　検証する内容
end
```
=>contentカラムが存在しているか

```models/user.rb
class User<ApplicationRecord
validates :email,{uniqueness:true}
       #検証するカラム名　　　検証する内容
end
```
=>emailで新たにユーザー登録できないようにするためにemailの重複がないか
lower_boundとupper_boundを直感的に理解した気になりたい(降順の配列に使いたい)

lower_bound, upper_bound、結局どっちを使えばいいの？ってなる場面が多かったので、メモがてらに書いてみる。この記事では直感的にlower_boundやupper_boundが使いこなせるようになることを目指す。例えば、

```cpp
vector<int> v = {40, 20, 20, 19, 1};
```

と降順に並ぶ配列に対して41, 40, 39, 21, 20, 19, 18, 2, 1, 0などをkeyとしたとき、lower_bound, upper_boundをどう使えばいいのか、そしてそれがどこのイテレータを返すのかがすぐ分からない人に向けての記事になる。あくまで一つの覚え方であることには留意してほしい。

###注意事項(よまなくてもいい)
前提として、今回使うコンテナはvectorである。また、配列はすでにsort済みであるとする。C++11からsort済みでなくてもある基準を満たしていればlower_boundやupper_boundを使うことはできる( 参考：https://cpprefjp.github.io/reference/algorithm/lower_bound.html )が、今回は無視する。

#昇順の配列に対する使い方

```cpp
vector<int> v = {1, 1, 1, 2, 2, 3, 3, 3, 5};
```

に対して使ってみる。例えば2をkeyとして二分探索するには、単純に

```cpp
lower_bound(v.begin(), v.end(), 2);
upper_bound(v.begin(), v.end(), 2);
```

とかけばよい。そして、これらは何を返すだろうか。次のように考えるとわかりやすい：

**keyを割り込ませて、残りを右にずらしたとき、配列はsortされたままであるような位置のイテレータを返す。そして、lower_boundはそのような位置の中で一番左(ゆえにlower)、upper_boundは一番右(ゆえにupper)の位置を返す。**

次の図をみればわかると思う(key = 0, 1, 2, 3, 4, 5, 6)。
key = 0のとき
![スライド1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1384496/81ffd0f9-4342-3cfe-3f9b-6c2184b352e9.jpeg)

key = 1のとき
![スライド2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1384496/97a35e34-6f79-be2b-6abc-205a944c74a3.jpeg)

key = 2のとき
![スライド3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1384496/a2c7203c-b07f-af9e-dc13-25707637e905.jpeg)

key = 3のとき
![スライド4.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1384496/37f672d1-4e0b-611d-f27b-734e71735ebb.jpeg)

key = 4のとき
![スライド5.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1384496/c3f045fc-a778-45cd-d6b7-4d9cecdeaf8e.jpeg)

key = 5のとき
![スライド6.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1384496/104f9a9e-1afd-04e5-90ab-29e4aba58a87.jpeg)

key = 6のとき
![スライド7.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1384496/d18894c2-a2a4-95c4-e2aa-851dac19e393.jpeg)

gif
![lower_bound, upper_bound.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1384496/c76da44a-b8c1-92d4-6823-1654ca0d2d46.gif)

言い方を簡潔にすれば、**sort済みの配列の順序を崩さないようにkeyを入れるとき、最左(または最右)でどこに入れられるかを返す**ということである。
この覚え方の利点は、「以上」「より大きい」といった言葉に頼らずにすむのでv.end()がいつかえってくるか？など直感的にわかり、しかもlowerやupperという名前も理解に結びつく。更に、降順の配列にもlower_boundやupper_boundを使うことができるようになる。

#降順の配列に対する使い方
```cpp
vector<int> v = {5, 3, 3, 3, 2, 2, 1};
```

に対して使ってみる。例えば2をkeyとして二分探索するには、

```cpp
lower_bound(v.begin(), v.end(), 2, greater<int>());
upper_bound(v.begin(), v.end(), 2, greater<int>());
```

とかけばよい。第四引数は、「配列がどのようにsortされているか？」をlower_bound, upper_boundに伝える役目を果たしている(ここでは、greater、つまり>なので降順)。デフォルトでは昇順であることを想定している。前章を踏まえれば、**降順の配列の順序を崩さないようにkeyを入れるとき、最左(または最右)でどこに入れられるかを返す**のがわかる。とすれば、key=2のときはlower_boundはv[4]のイテレータを返し、upper_boundはv[6]のイテレータを返す、ということが容易にわかる。
1周目ーrailsチュートリアル第1章

#目次
[1.はじめに](#1-はじめに)
[2.大まかな流れ](#2-大まかな流れ)
[3.用語のまとめ](#3-用語のまとめ)
[4.感想](#4-感想)
[5.おわりに](#5-おわりに)

#1. はじめに
前回の続きです。

https://qiita.com/ak-matsu/items/b6396db660c776ad5870

progateのweb開発パスをクリアしようと思ったらHTML中級編は有料であることが判明。
そのままrailsチュートリアルへ進み、このタイトルとなります。
どのように記事をまとめればいいのか、迷走中。

自分の勉強、方向性はチュートリアルを1周後、プロゲートやrailsの有料サポートを受けるか考え中。
railsチュートリアルでは、どこまで理解したのかグラフ化できるようなサポートもあるようで
さらっと流れを掴んだあとに有料へするか否かを決めます。

https://railstutorial.jp/chapters/beginning?version=6.0

#2. 大まかな流れ
- hello worldをローカルサーバで表示
- git/githubの操作
- herokuへデプロイ
- これらの一連の操作、環境はcloud9（AWS）で行う。

#3. 用語のまとめ
#4. 感想
github,AWS,herokuはある程度触っておかないと少しむずかしい、敷居が高い印象。

cloud9設定時にrootユーザーでログインすると、
IAMユーザーへ変更するようにと警告が出てしまうが、
チュートリアルをよく見るとrootで問題ないとのことでそのまま進める。
自分のローカルPCで環境変数などの書き換えをせず、
Ruby、rails、herokuのインストールなどを
全てcloud9（ブラウザ）上で完結できてしまい、感動を覚える。

無事にアプリケーションまでインストール設定とローカルサーバの立ち上げまで完了。
それらのソースコードをgit/githubにてバージョン管理。

半年間ではGitHubDesktopでしか操作をしておらず、
コマンドライン上での操作は結構、新鮮であった。
branchではなく、

```
checkout -b　ブランチ名
```
とブランチが作成されるので
今までのGitHubDesktopのような流れをイメージすると少し工程が違い少々手間取った。
branchでもいけるが何が違うのだろうか？

最後の演習も
ローカルサーバーのデータ変更、herokuへのデプロイもコマンドであり手間取ったが
なんとか初日は終えることができたので、満足である。


##復習書きなぐり
ruby,railsをインストール後
アプリケーションの作成
rails _6.0.3_ new hello_app

ローカルサーバを立ち上げてwebブラウザへアクセスできるか試す。
rails server(rails s　と省略可能)

ローカルPC環境：3000port
cloud9：クラウドワークスペース上のウィンドウをクリック

MVCは後述。既にイメージは掴めている。

###git/github 後ほど別途まとめる。
```
Gitでパスワードを一定時間保持するように設定する
$ git config --global credential.helper "cache --timeout=86400"

リポジトリの再初期化
$ cd ~/environment/hello_app    # Just in case you weren't already there
$ git init

プロジェクトの全ファイルをリポジトリに追加
$git add -A

Gitにプロジェクトのファイルを追加すると、最初はステージング（Staging）という
一種の待機用リポジトリに置かれ、コミットを待つ。

現在のステータス確認
$git status

commitを使い、ステージングエリアで待機している変更を本格的にリポジトリに反映させる。
$ git commit -m "Initialize repository"

web上のGitHubで作成後、pushするとweb上のgithubへディレクトリなどが反映される。
$ git remote add origin https://github.com/<あなたのGitHubアカウント名>/hello_app.git
$ git push -u origin master

```

###ここからよく使う場面
```
ブランチの方法
$ git checkout -b 【ブランチ名】

$ git branch
  master
* 【ブランチ名】

変更があればstatusで確認。
$ git status

commit -aですべてのファイルをへの変更を一括でコミット
$ git commit -a -m "変更した点を記述する"

margeにてmasterブランチへ変更点をmargeする
$ git checkout master
$ git merge ブランチ名

merge後はブランチを削除
$ git branch -d ブランチ

$git push
これを実行することによりGitHubのコントリビューションを更新することができる
通称、草を生やす。
```


herokuも同様にpushするとデプロイ上の画面も変更される
ローカルサーバのgitを更新してからではないとherokuのデータも反映することができない。

```
$git push heroku master
```


#5. おわりに
次回は第2章へ続く

https://qiita.com/ak-matsu/items/e8a6fa4f654b9d82994b
踏み台サーバーを経由したプライベートサーバーへの接続

#はじめに
ローカルから踏み台サーバーを経由して、プライベートサーバーにSSHログインする方法について説明します。

※ 各サーバはSSHサーバーの設定が終わったと想定します。
※ 以下の内容は、macOS環境に基づいて作成されています。

#ssh
SSH(Secure Shell)はリモート先のホストPCに接続するために使用されるインターネットプロトコルです。

意味どおりセキュリティシェルですね。

シェルで接続するので、基本的にはCLI上で作業をすることになります。

基本ポートは22番です。

###動作方式
サーバーに接続するときにパスワードの代わりにキーを提出する方式です。

SSH鍵は公開鍵（public key）と秘密鍵（private key）となります。

鍵を生成すると公開鍵と秘密鍵が作られます。

このうち秘密鍵はローカルに、公開鍵はリモートマシンに位置しなければなりません。

SSHでログインするとSSH Clientがローカルの秘密鍵とサーバーの公開鍵を比較し、2つが一致するかを確認します。

###SSH鍵の生成
macOSはOpenSSHを基本として含んでいるため、ssh-keygenを使って簡単に鍵を作成することができます。

```bash
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/{username}/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
```

生成された鍵を確認するとid_rsaとid_rsa.pubがあります。

```bash
$ ls -al ~/.ssh
total 16
drwx------   4 user  staff   128  6  7 15:07 .
drwxr-xr-x+ 31 user  staff   992  6  7 15:05 ..
-rw-------   1 user  staff  1876  6  7 15:07 id_rsa
-rw-r--r--   1 user  staff   403  6  7 15:07 id_rsa.pub
```

id_rsaは秘密鍵、id_rsa.pubが公開鍵です。

権限を見ると秘密鍵はユーザのみが読み書きでき（600）、公開鍵は他のユーザも読むことができる権限（644）を持っています。

接続したいPCに公開鍵を登録しておくと、以降SSHにアクセスする際に秘密鍵と比較して認証します。


公開鍵をサーバーに登録する方法は色々ありますが、ここではssh-copy-idを使います。

```bash
$ ssh-copy-id -i [user]@[server IP]
```

まず、踏み台サーバーに接続するため[user]と[server IP]に踏み台サーバーのことを書きましょう。

登録が終わったら踏み台サーバーに〜/.ssh/authorized_keysが生成されます。

終わったら、SSHを通じてログインしましょう。

```bash
$ ssh [user]@[server IP]
```

###ssh-agent
ローカルから踏み台サーバーの接続は成功しました。

では、プライベートサーバーまでは？

先と同じくssh-copy-idを使ってプライベートサーバーに公開鍵を生成します。

```bash
$ ssh-copy-id -i [user]@[プライベートサーバーのIP]
```

生成が終わったら、またローカルから踏み台サーバーに接続して、プライベートサーバーへログインしましょう。

当たり前ですが、踏み台サーバーには秘密鍵がないのでプライベートサーバーへにログインできません。

ここでssh-agentが必要となります。



一応ssh-agentに秘密鍵を登録すると、サーバーを経由する時、いちいちサーバに秘密鍵を登録する必要がありません。

サーバーにログインする時、ssh-agentが秘密鍵を持って一緒に転送されるためです。

ローカルから秘密鍵をssh-agentに登録します。

```bash
$ ssh-add -K ~/.ssh/id_rsa
```

登録した秘密鍵を確認します。

```bash
$ ssh-add -l
```

####踏み台サーバーを経由してプライベートサーバーに接続
ssh-agentに秘密鍵を登録しましたら、さっそく試してみましょう。

-Aオプションを追加してサーバーにログインします。

```bash
$ ssh -A [user]@[プライベートサーバーのIP]
```

-Aオプションを追加すると、ssh-agentを対象サーバーに転送します。

これによって、ローカルから踏み台サーバーを経由してプライベートサーバーに接続することができます。

###ssh-config
リモート先の情報を.ssh/configに登録すれば、サーバー名でログインできます。

```bash
Host bastion
  Hostname aaa.aaa.aaa.aaa
  Port 22
  User username
  IdentityFile ~/.ssh/id_rsa
  ForwardAgent yes

Host private
  Hostname bbb.bbb.bbb.bbb
  Port 22
  User username
  ProxyCommand ssh -W %h:%p bastion
```
踏み台サーバーにForwardAgentを追加すると、ログインする際にssh-agentを転送することができます。

sshコマンドの-Aオプションですね。

あとプライベートサーバーにログインする時、踏み台サーバーを経由する必要があるため、ProxyCommandを追加します。

さて、サーバー名でログインしましょう。

```bash
$ ssh private
```

これで簡単にサーバー名を入力することでログインできるようになりました！