OmniAICreator/Qiita-1.07M huggingface dataset:
【Gatsby.js】jsonファイルのデータをGraphQL経由で取得する

この記事ではjsonファイルからGraphQL経由でデータを取得し、ページ内で利用する方法を紹介します。

jsonファイルを元に、複数ページを生成する方法を知りたい場合は昨日書いた以下の記事を参照。
[【Gatsby.js】単一のjsonファイルを元に複数のページを生成する - Qiita](https://qiita.com/d0ne1s/items/7cc9fde889e8f23b5b90)

## jsonファイルを配置
```zsh
$ mkdir src/data
$ touch src/data/events.json
```
```src/data/events.json
[
  {
    "title": "Gatsby勉強会",
    "date": "2020/10/01"
  },
  {
    "title": "React勉強会",
    "date": "2020/11/01"
  },
  {
    "title": "JavaScript勉強会",
    "date": "2020/12/01"
  }
]

```

## プラグインをインストール
```zsh
$ yarn add gatsby-transformer-json gatsby-source-filesystem
```
```gatsby-config.js
module.exports = {
  plugins: [
    `other-plugin-hoge`,
    //追記↓
    `gatsby-transformer-json`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `data`,
        path: `${__dirname}/src/data/`,
      },
    },
  ],
}
```

## クエリを作成
`gatsby develop`で開発サーバーを起動し、http://localhost:8000/___graphql?query にアクセスしGraphiQLを開く。
まずはroot?に`allEventsJson`という項目が追加されていることを確認。

`allEventJson > edges > node`を開き、`title`と`date`にチェックを入れてクエリを発行。

## データを使いたいページ内で、データを取得
ここでは`src/pages/events.js`というページでデータを利用します。

```zsh
$ touch src/pages/events.js
```
```jsx:src/pages/events.js
import React from "react"
import { graphql, useStaticQuery } from "gatsby"

export default () => {
  const data = useStaticQuery(graphql`
    query {
      allEventsJson {
        edges {
          node {
            date
            title
          }
        }
      }
    }
  `)
  const events = data.allEventsJson.edges
  return (
    <div>
      {events.map(e => (
        <div>
          <h2>{e.node.title}</h2>
          <p>{e.node.date}</p>
        </div>
      ))}
    </div>
  )
}
```
## 結果
![ 2020-09-25 12.10.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/2c9383fa-47e3-259f-45c1-b9b9a3ba559c.png)

## 参考
- [GatsbyJSでのクエリデータの扱い（静的生成後の記事一覧のランダム表示） – エビスコム](https://ebisu.com/note/gatsbyjs-querydata/)
- [Gatsby+GraphQLでJSONデータを読み込みReact bootstrapテーブルで表示 - Qiita](https://qiita.com/atomyah/items/0f2bf570d1dc008d1ba8)
- [GatsbyのStaticQueryをどこで使うか - Qiita](https://qiita.com/ttakatech/items/d3ae347f2ecf38cdc21d)
[DockerToolbox] コンテナのポートに接続できない

本記事は Docker Toolbox を対象としています。**Docker for Windows は対象外**

# コンテナに接続できない

Python + Flask でAPIサーバを開発するため、Dockerコンテナ上で4000番ポートに開いた開発サーバに接続したい。Dockerの設定は以下の通り。

```Docker:docker-compose.yml
version: "3"
services:
  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    container_name: "backend"
    ports:
      - "4000:4000"
    volumes:
      - "./backend/:/app"
  ...他のサービス...
```

`Dockerコンテナ：ポート4000 <=> Dockerホスト：ポート40000`　と繋がっています。

## 環境
- Windows 10 Home 64bit
- Docker version 19.03.1

Windows 10 Home では Hyper-V が使用できないため DockerToolbox 経由でインストール

- [[公式] Install Docker Toolbox on Windows](https://docs.docker.com/toolbox/toolbox_install_windows/)
- [[Qiita] Windows環境にDocker Toolboxをインストールする](https://qiita.com/KIYS/items/8ac37f6757a6b7f84569)

## 原因
Linuxカーネルを提供する仮想環境（VirtualBox）が間に挟まっているため、DockerホストはVirtualBoxでありWindows（ホストOS）とは別物。
`Dockerコンテナ：4000 <=> Dockerホスト：40000 <=未接続=> Windows：4000`　とホストOSまで繋がっていない。  
詳しくは [[Qiita] Dockerを活用するためのネットワーク関連操作のおさらい](https://qiita.com/osuo/items/16fd61c7479bd7ef041a) が参考になりました。

# 解決手法
VirtualBox と Windows 間に適切なポートフォワーディングを設定します。

1. VirtualBox マネージャーを開き、仮想マシンを選択して設定を開く
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440643/b6d2e638-cc8d-c694-51e3-728b3ed123e0.png" width="500">

2. ネットワーク＞高度＞ポートフォワーディングを選択
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440643/7843c795-18fd-e9ce-6e54-af12391f3e10.png" width="500">

3. ポートフォワーディングを設定
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440643/18556e03-f980-6671-24af-4690f8b222f1.png" width="500">
これで`Dockerコンテナ：4000 <=> Dockerホスト：40000 <=> Windows：4000`と無事に接続できました。
RaspberryPi Raspbian 32bit ヘッドレスインストール

# 起動用 SD カードの作成
Raspberry Pi Imager で簡単作成 (Windows/macOS/Ubuntu)

> Use Raspberry Pi Imager for an easy way to install Raspberry Pi OS and other operating systems to an SD card ready to use with your Raspberry Pi:
> https://www.raspberrypi.org/downloads/

GUI でお好きなイメージを。

![Screen Shot 2020-09-25 at 11.29.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82774/859aea6f-6d17-ca91-9248-384091273ed5.png)

![Screen Shot 2020-09-25 at 11.29.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82774/3d44833f-df52-9377-d966-17bf3702399c.png)

# 初回起動時 SSH 有効化
私の環境では、 /Volumes/boot が SD カードの root です。
空の ssh ファイルを作成。

```bash
~ ❯❯❯ cd /Volumes/boot
/V/boot ❯❯❯ touch ssh
/V/boot ❯❯❯ ls -la ssh
-rwxrwxrwx  1 user1  staff  0 Sep 25 11:04 ssh
```

# 初回起動時 Wi-Fi 有効化
wpa_supplicant.conf に Wi-Fi の情報を記載。

```bash
/V/boot ❯❯❯ touch wpa_supplicant.conf
/V/boot ❯❯❯ vi wpa_supplicant.conf
/V/boot ❯❯❯ cat ./wpa_supplicant.conf
country=JP
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
    ssid="Your-SSID"
    psk="your-password"
}
```

SD カードを raspberry pi に挿入し、電源 ON

# SSH 確認
Raspberry Pi の wifi の mac address を事前に確認しておくといいかも。 私は DHCP でアドレス配布しているルータから mac address で IP address を逆引きします。

```
Router#show ip dhcp binding | i 01dc.a632
192.168.0.14    01dc.a632.abcd.ef       Oct 02 2020 11:36 AM    Automatic  Active     Vlan1
```

Raspberry Pi OS のデフォルトクレデンシャルは pi/raspberry

> The default user is pi, and the password is raspberry. You can add users and change each user's password.
> [https://www.raspberrypi.org/]( https://www.raspberrypi.org/documentation/linux/usage/users.md#:~:text=User%20management%20in%20Raspberry%20Pi,and%20change%20each%20user's%20password.)

```bash
~ ❯❯❯ ssh pi@192.168.0.14
pi@192.168.0.14's password:
Linux raspberrypi 5.4.51-v7l+ #1333 SMP Mon Aug 10 16:51:40 BST 2020 armv7l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Sep 25 03:45:02 2020 from 192.168.0.6

SSH is enabled and the default password for the 'pi' user has not been changed.
This is a security risk - please login as the 'pi' user and type 'passwd' to set a new password.
```

# ユーザ pi のパスワード変更
```bash
pi@raspberrypi:~ $ passwd
Changing password for pi.
Current password:
New password:
Retype new password:
passwd: password updated successfully
```

# 環境

```zsh
~ ❯❯❯ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.15.6
BuildVersion:	19G2021
```

```bash
pi@raspberrypi:~ $ lsb_release -a
No LSB modules are available.
Distributor ID:	Raspbian
Description:	Raspbian GNU/Linux 10 (buster)
Release:	10
Codename:	buster
pi@raspberrypi:~ $ cat /proc/device-tree/model
Raspberry Pi 4 Model B Rev 1.2
```
【Swift】iOS14.0から追加されたWidgetKitを簡単に実装する方法

私の理解力が足りないのか
iOS14で追加された、WidgetKitを実装する際に遠回りをしてしまったので、
シンプルにWidgetKitをとりあえず実装してみたい！！という方々向けに、
最低の最低限(ノーアウト満塁からゲッツー崩れの1打点)だけまとめました。

詳しく知りたい方は公式のサンプルを..
https://developer.apple.com/documentation/widgetkit/building_widgets_using_widgetkit_and_swiftui

#環境
- Xcode: 12.0
- Swift5

#手順
####1. SwiftUIでプロジェクトを作成
WidgetはSwiftUIで作成しますので、storyboardを選択しないよう注意！
![スクリーンショット 2020-09-25 11.20.12のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656690/a29a378e-2515-ac13-7499-c0122e77d74c.png)

####2.WidgetExtensionを追加
a.File > New > Targetを選択
![スクリーンショット 2020-09-25 11.23.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656690/c555f151-3d60-3400-bae5-1a53f75cc04f.png)

b.右上のテキストボックスに、Widgetと入力しWidgetExtensionを検索・選択し、Next!
![スクリーンショット 2020-09-25 11.24.03のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656690/3876e6d5-d2f7-0658-4fe4-6f8e06bc717d.png)

c.ProductNameを入力し、Finish!!
![スクリーンショット 2020-09-25 11.24.34のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656690/62373522-ba03-247e-6d7f-82747aaac7a0.png)

以下のようにWidgetExtensionを追加することができました!
![スクリーンショット 2020-09-25 11.25.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656690/41d0a277-755d-4d4c-f3c0-e24ade7c1372.png)

#動作
![widget2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656690/0d52e843-085b-ed65-dd38-69e6a61d6fb8.gif)

#備考
userDefaultsを使用してデータの受け渡しとうする際に、
AppGroupを使用したりする必要がありますが、それらの方法は
後ほど追記するか、別途記事にしたいと思っております。

**0929追記**
記事にしました！
[【Swift】WidgetKit使用時に、入力された文字をUserDefaults経由でWidgetに表示する方法](https://qiita.com/yajima_tohshu/items/bf1a38bf3b1c2215b12e)
CIでテストするときとかにKubernetesで全部のPodがREADYでRunningになるまで待つヤツ


CIですべてのPodの準備ができたことを確認してからテストを実行したかった時に使いました。
kubectlでnamespace内のすべてのPodに対し、READYがn/nになってRunningになるまで待ちます。

```
$ kubectl -n dev-test get pod
NAME                        READY   STATUS             RESTARTS   AGE
aaaaaaaaaaaaaaaa            1/1     Running            0          16m
bbbbbbbbbbbbbbbb            1/3     Running            0          16m #これが3/3になるまで待つ
cccccccccccccccc            0/1     Pending            0          16m #PendingがRunningになって1/1になるまで待つ
dddddddddddddddd            1/1     Running            0          16m
```

以下のようにして準備ができるまでsleepを続けます。

```
k8s_namespace=<your namespace>
while :; do
    [ "$(kubectl -n ${k8s_namespace}  get pod --no-headers | awk -F' *|/' '$2 != $3 || $4 != "Running"')" == "" ] && break
    sleep 3 && echo "wait all pod status to be READY and Running"
done
```

以上。
ReactNativeのexpoでヘッダーをデフォルトで消す

![wlekf.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135794/f3399f00-242c-c209-19b1-cfed4ec835ee.png)


上のHomeのヘッダー消したい


```
<HomeStack.Navigator screenOptions={{ headerShown: false }}>
```

これでできた

![l;;;.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135794/2231d037-dd59-3b70-e0bb-b8fab51eac37.png)
Laravel/ui のインストール

#インストール
Laravel 6 からcssフレームワークが分離したため、別にダウンロードが必要です。

##laravel/uiのダウンロード
"1.x" で最新版がインストールされますので、必ず入力しましょう。

```
$ composer require laravel/ui "1.x" --dev
```

最初、以下のコマンドでダウンロードしたため、スカフォールド生成時にエラーが発生しました。注意してください。

```
$ composer require laravel/ui:^1.0 --dev //最新版ではないのでエラーを吐きます注意してください。
```

##基本的なスカフォールドを生成

ui系

```
$ php artisan ui bootstrap
$ php artisan ui vue
$ php artisan ui react
```

autu系
Reactで実装する場合

```
$ php artisan ui bootstrap --auth
$ php artisan ui react --auth
```

Vueで実装する場合

```
$ php artisan ui bootstrap --auth
$ php artisan ui vue --auth
```

CSSの出力
JavaScriptの出力

```
$ npm install
$ npm run dev
```
RuboCopエラーについて


### Def〜endまでで、10行内に収めないといけないルールがある

違反すると、以下のようにエラーが発生する

```:Rubocop
Metrics/MethodLength: Method has too many lines
```

### 条件を短く収めるルールがある
Def〜endまでで、ifの条件分岐が長すぎる、
「hogehoge.user.personalize_infos.empty?」などが長すぎる場合などに
以下のようにエラーが発生する

```:Rubocop
Metrics/AbcSize: Assignment Branch Condition size
```

回避方法としては、
条件の一部を別のdefとして作成し
renderで呼び出すようにする。


### ガード節の後には空行を必ず入れる

処理の対象外とする条件を関数やループの先頭に集め、早めに return や continue/break で抜ける方法です。ネストを減らし異常系と正常系の処理がわかりやすくなるメリットがあります。

下記の記事を参照！
https://qiita.com/ryosuketter/items/30b329b24c6dde3ae639

```:Rubocop
Layout/EmptyLineAfterGuardClause: Add empty line after guard clause.
```
【2020年秋版】kotlinx.serializationで配列のJson文字列をパース

# バージョン
kotlin: 1.4.10
kotlinx:kotlinx-serialization-runtime: 1.0-M1-1.4.0-rc

# ちょっと前まで使えてたのにストライクスルー
　さてこの周辺は目まぐるしく更新されていて、**あら新しいバージョンあるじゃない**とばかりにGradleを触っちゃうとすぐにIntelliJに怒られる昨今、皆様いかがお過ごしかってコロナで大変なんだよな。みんなそう俺もそう。誰だってそう。

　そんな自分らしさの檻の中でもがいてるあなたと私のために、今現在の情報を残しておこう、と。いつまで使えるのかわかんないけどね。
# 取り敢えずbuild.gradle

```build.gradle
buildscript {
    ext.kotlin_version = '1.4.10'
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
    }
}

plugins {
    id 'org.jetbrains.kotlin.jvm' version "$kotlin_version"
    id "org.jetbrains.kotlin.plugin.serialization" version "$kotlin_version"
}
```

　こうやってkotlinのバージョンを1.4.10にすると、kotlinx-serialization-runtimeもバージョンをあげないといけなくて、rcとか付いてるけど今んとこはこれしかないのかな。

```build.gradle
dependencies {
    implementation 'org.jetbrains.kotlinx:kotlinx-serialization-runtime:1.0-M1-1.4.0-rc'
}
```

　kotlinを書くようになってもbuild.gradle.ktsは馴染まないんだよな。ここだけはGroovyなのよね。kotlin-stdlibとかkotlin-reflectとかは省略してます。

# 使い方
　まずデータクラス。なんかオーバーライドしたらどう？　って言ってくるけど、へいへい言うなりになるのもよし、無視するのもよし。よしなに。

```sample1.kt
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class Container(
    @SerialName("Id")
    val id: String,
    @SerialName("Names")
    val names: Array<String>,
    @SerialName("State")
    val state: String,
    @SerialName("Mounts")
    val mounts: Array<Mounts>,
)

@Serializable
data class Mounts(
    @SerialName("Source")
    val source: String,
    @SerialName("Destination")
    val destination: String,
)
```

　ほんでメインクラス。`Container.serializer().list`が使えなくなってる。
　サンプルはDockerにコンテナの情報よこせとやっている。一文字の適当な変数名とか誰かに怒られるかも知れないが、怒られたら謝ればいい。人生はそんなもんだ。

```sample2.kt
fun main(args: Array<String>) {
    val o = RestTemplate().getForObject("http://localhost:2375/containers/json?all=true") as String

    Json { isLenient = true; ignoreUnknownKeys = true }
        .decodeFromString(ListSerializer(Container.serializer()), o)
        .forEach { println(it) }
}
```

　RestTemplateだからあれだ、```org.springframework:spring-web:5.2.9.RELEASE```これか、うん。spring-data-rest-coreも必要だったかな。ま、いいや。HTTPで取るだけならもっとオサレな方法があるのかね。fuelとか？

　~~ま、本筋じゃないからそこはいいや。~~

　**試しにfuel使ってみたらめっちゃ素敵やん。自分でExtension functions書く必要なかった。最高かよ。ありがとう、世界のみんな。**

```build.gradle
implementation 'com.github.kittinunf.fuel:fuel:2.3.0'
```

```sample3.kt
fun main(args: Array<String>) {
    val (_, _, result) = "http://localhost:2375/containers/json?all=true".httpGet().responseString()

    result.success {
        Json { isLenient = true; ignoreUnknownKeys = true }
            .decodeFromString(ListSerializer(Container.serializer()), it)
            .forEach { println(it) }
    }
}
```
　「fuel使うならfuel-jsonで良くね？」とか思ったかも知れないが、**その通りである。**でも記事の趣旨的に仕方ないんだ。本当は知らなかったんだけどプライドが許さないからそれは内緒なんだ。知ってたけど敢えてと言い張る方針でいきます。

# 以上でござる
　`Json.nonstrict`も`Json.parse`も打ち消し線バーンだもんな。
　ちょっと前まで使ってた奴に打ち消し線が出ると、アクティブに更新されてる感じがするわけで、そういうのを見ると嬉しくなっちゃうタイプなら、僕だってそう誰だってそうなんだ。
Sassの@mixinの基本について解説してみた

##mixinとは
通常であれば、一つ一つ細かく分けて書いていかなければならないものを、まとめて記述することができます。

##通常の書き方との比較

```qiita.scss
//通常
.contact {
 background-color: blue;
 color: fff;
 height: 50px
 width: 200px
}

.share {
 background-color: blue;
 color: fff;
 height: 50px
 width: 200px
}

//mixinを使用
@mixin style {
 background-color: blue;
 color: fff;
 height: 50px
 width: 200px
}

.contact {
 @include style
}

.share {
 @include style
}

```
このように記述することで、通常のcssと全く同じ記述をすることが可能です。

##最後に
mixinを使い、一つにまとめて記述することで、より可読性の高いコードを書くことができます。また、後からやっぱり背景色を赤にしたいとなったときにも、mixinの値のみを変更すればincludeで呼び出した他のコードにも影響を与えることができるのでとても便利ですね。
今回紹介したのはmixinのほんの一部の機能で、他にも引数をもたせることができたりと、できることは沢山あるので、この記事をきっかけにmixinを使ってみようと思って頂けたら幸いです。今回の記事は以上になります。最後まで読んでいただき、ありがとうございました！
PHPUnitでスローされた例外をテストする

# 結論
以下のように書こう🍄

```
    /**
     * @test
     * @return void
     */
    public function insertHoge_異常_{エラー内容}()
    {
        // スローを期待する例外の内容
        $this->expectException(例外クラス);
        $this->expectExceptionMessage(例外メッセージ);

        $param = 不正な値;

        // 例外をスローするテスト対象メソッド
        $this->reportService->insertHoge($param);
    }
```

# 事例
```
    /**
     * @test
     * @return void
     */
    public function addRecord_異常_外部キー不正()
    {
        $this->expectException(Exception::class);
        $this->expectExceptionMessage('a foreign key constraint fails');

        $id = 'invalidId';

        $this->reportService->insertHoge($id);
    }
```

### Tips
- `expectExceptionMessage()`による例外メッセージ検証は、部分一致で判定できる
- timestampの値を観点にしないテスト等、<br>
観点に含まれない無いが実行タイミングによって変化する値を含むエラーメッセージの検証を行う場合は便利

例）
　上記事例のテスト実行時に返却される例外メッセージ全文

```
'SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`hoge_db`.`hoge_table`, CONSTRAINT `user_id_foreign` FOREIGN KEY (`id`) REFERENCES `users` (`id`)) (SQL: insert into `hoge` (`id`, `updated_at`, `created_at`) values (0, 2020-09-25 11:31:05, 2020-09-25 11:31:05))'
```
コマンドによるディレクトリ・ファイル移動等の基本操作備忘録

#用語
カレントディレクトリ・・・現在作業中のディレクトリ
パス・・・ディレクトリ/ファイルの場所を示す
相対パス・・・呼び出し元ファイルから参照ファイルまでの階層構造
絶対パス・・・ルートディレクトリから特定ファイルまでの階層構造
ルートディレクトリ・・・ディレクトリツリーの一番大元に位置するディレクトリ

#ファイル・ディレクトリ操作
touch・・・ファイルを作成

```
touch hoge.txt
// hoge.txt作成
```
mkdir・・・ディレクトリ作成

```
mkdir hoge
// hogeディレクトリ作成
```

mv・・・ファイルを移動する

```
touch hoge.txt
// ファイル作成
mkdir hoge
// ディレクトリ作成
mv hoge.txt hoge
// hoge.txtをhogeディレクトリに移動
```

rm・・・ファイル削除

```
touch hoge.txt
// hoge.txt作成
rm hoge.txt
// hoge.txt削除
```

cat・・・ファイルの中身をCUIに表示

```
cat hoge.txt
// <p>Hello world.</p>
```

cp・・・ファイル/ディレクトリのコピー

```
cat hoge.txt
// <p>Hello world.</p>
cp hoge.txt hogehoge.txt
// hoge.txtと同じ内容のhogehoge.txtを作成
cat hogehoge.txt
// <p>Hello world.</p>
```

rmdir・・・空のディレクトリ削除

```
mkdir hoge
// hogeディレクトリ作成
rmdir hoge
// hogeディレクトリ削除
```

rm -r・・・ディレクトリを中身ごと削除

```
mkdir hoge
// ディレクトリ作成
touch hoge.txt
// hoge.txt作成
mv hoge.txt hoge
// hoge.txtをhogeディレクトリに移動
rm -r hoge
// hogeディレクトリ及びhogeディレクトリ内のhoge.txtをまとめて削除
```

cd・・・ディレクトリ移動

```
cd hoge/hogehoge
// カレントディレクトリからhogeディレクトリ内のhogehogeディレクトリに移動
cd ..
一階層上のディレクトリへ移動
ｃｄ ~
ホームディレクトリへ移動
```

ls・・・カレントディレクトリのファイル一覧を表示

```
ls
 ⇨hoge
 ⇨hoge.txt
 ⇨hogehoge.txt
// hogeディレクトリ、hoge.txt、hogehoge.txtが存在
```

pwd・・・カレントディレクトリの位置を表示

```
pwd
⇨/home/ec2-user/environment
// environmentまでの階層を表示
```

#あとがき
権限やアプリインストールのコマンドを引き続き学習していきたい。
文系がslackbotを作ってみたので、手順をまとめる（202008時点)


slackBot作成の流れをまとめる（2020年08月時点)

# 目的
slackやbotkitは基本敵に英語で書かれているが、
その仕様はここ数年で結構変わっており、過去の日本語の記事が使えない事が多かったのでここにまとめる。
ちゃんと理解するならリファレンスを読もう。
（２０２０年８月仕様なので、また変わるかもしれない。注意されたし）

# 使うもの
slack
　・・・これがないと始まらない。
slackAPI
 ・・・ここでbotの本体と権限付与とかするページ。
botkit(4.n)
 ・・・botのアプリ作成を手助けしてくれるスゴいツール。0.n系と仕様がそれなりに違うので注意されたし


# 基本的なbotの動き
一般的なAPIを使ってる時と動きは同じ。
slack→APPの部分とAPP→slackの部分で大きく切り分けられる。

## slack→APP
slack上でEvent（※１）が発生した際にそれを検知し、アプリに既定の電文を送信する。
（※２：method毎に指定された引数を設定してslackに送信することで、外部からslackに干渉することができる）
## APP⇒slack
受け取った電文を元に、APP内でmethod(※２)の引数を設定し、slackに電文を送信する。
（※１：slackで何かが動作する際には同時に「Event」というものが発行される）


#　slackでbotを作ってみる
## 作るもの
botにmentionを飛ばしたら「hello]と回答するbot

## １．botの皮を作る。
botの本体を作成して、Tokenを発行する。

リンク先が非常にわかりやすいのでこれに沿ってやれば大丈夫。
ただし画面がちょっと古かったり、ツールは古くなってるので使わない方が吉。
⇒[Slack の ボット に OAuth で 権限を追加する](
https://azriton.github.io/2017/06/01/Slack%E3%81%AE%E3%83%9C%E3%83%83%E3%83%88%E3%81%ABOAuth%E3%81%A7%E6%A8%A9%E9%99%90%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B/)

【備考】
今回のケースで必要な権限スコープはBot Token Scopeのapp_mentions:readだけです。
権限スコープはTOKENをとったあとでも追加できるので、とりあえず１個だけ作ってやるのがいいと思います。

＜追記＞2020/11/05
一回目でも普通にインストールボタンを押すとできるようになったらしい。楽ですばらしい。

## ２．認証情報をコピーする
SlackAPIのBasicInformationタブにあるSIGHING_SECRETと
OAuthのタブにあるBotTokenをコピーする。
（今回はAuthTokenは不要。ユーザー代理で何かさせるときは必要になる）

## ３．Botkitでアプリ部分を作る
slackからapp_mentionが飛んで来た時の処理を書く。
以下の折り畳み部分をコピペする。
（javascriptで書くことになるので、少し学んで置くと吉）

<details>
<summary>サンプルプログラム</summary>
<div>

```javascript
const { Botkit } = require('botkit');
const { SlackAdapter, SlackEventMiddleware } = require('botbuilder-adapter-slack');

var sSecret = YOUR_SIGNING_SECRET
var bToken = YOUR_BOTTOKEN

const adapter = new SlackAdapter({
    clientSigningSecret: sSecret,
    botToken: bToken,
	redirectUri:""
});

adapter.use(new SlackEventMiddleware());

let controller = new Botkit({
    adapter: adapter
});

controller.on("app_mention", async(bot,message) =>{
	await bot.reply(message, "hello");
});
```
</div>
</details>

トークン等の設定部分と最後のcontroller.onの部分以外はすべてコピペでOK。
（備考：基本的にTOKEN情報はプログラム内に記載せずに、環境変数に入れるのが一般的なので、
　運用時には環境変数に入れて実行しよう）

追記メモ：
botkit導入手順
git cloneでgithubからbotkitを持ってくる。
npm install　でbotkitをインストールする。
npm install --save botbuilder-adapter-slack　でslackbuilderをインストールする。
node xxxx.jsで実行


# ４．サーバーを建てる
何でもいいのでサーバーを建てる。
短時間で良いのならばngrokで良いと思う。お金かからないし。
参考：[ngrokが便利すぎる](https://qiita.com/mininobu/items/b45dbc70faedf30f484e)

# APPとslackを繋ぐ
APPとngrokを動かした状態で、slackapiの「Event Subscription」タブにあるRequestURLに
ngrokのアドレス＋エンドポイントを記載するとVerifiedと出るのでセーブする。

これでslackで作ったbot宛にメンションをとばせば、helloと返ってくる。

終わり。

## 自分用メモ
外部鯖で動かすときのメモ
１．npmをインストールする
yum install nodejs
２．gitをインストールする
yum install git
３．githubの手順に沿ってやる
４．firewallのポートの穴をあける。
４．ちゃんとteratermとか使って操作する。（ターミナルは使っちゃだめ）
＜企画・計画・設計＞　リスクは絶えず変化する

先ず最初に行う事、それは、これから**開発・運用するサービス・機能のEOL（End of Life）を真っ先に決める**ことです。これまで私たちはこのEOLを決めることなく、一度開発したもの（サービス・機能）を未来永劫使うという姿勢で運用・保守を続けてきました。その根底には数億円の開発費用をかけたのだから・・・という思いがあったのでしょうし、従来の開発手法であるW/Fでは本当に必要な機能に対して、担保的（実現するために期間がかかるので、その期間で発生するであろうと予測（保険的な要求）した機能やサービス）な要求が膨れ上がり費用が高騰していく傾向にありました。また、多重請負での費用高騰も否めません。ですから、これだけの開発投資をしたのだから、投資回収をしたいあまり、陳腐化しても改修して使い続けるというのが現状です。保守改修費用がどれだけかかっているか冷静にみてみると、**使用年数が長く成れば、当初投下した開発費用をはるかに超えたものになっているのではないでしょうか？その保守改修費用は、新たなサービス・機能を開発することよりも優先され、結局は補修改修費が、市場をリードする最新のサービスや機能を開発する機会を奪ってしまっている懸念もあります。EOLを決めない事が最大のリスク**となります。
EOLを決めた後に何をすべきでしょうか？
現時点で想定できるリスクを全て洗い出します。ここで全てというのは、今時点で思いつくものとしてください。**JIT（Just in Time）でリスクを洗い出す**ことで、過剰なリスク出しを抑制できます。未来永劫起こるか否か分らない全てのリスクを出すことは非現実的です。実際に起きた事象（事故）を参考にするケースでも、自社への適合性を考えると要件過多になる傾向は否めませんので、あくまでも参考程度に留めるという姿勢が必要です。
リスクの洗い出しの基本は**ステークホルダー全員参加により議論運営はでタイムボックスストーミング**で実施します。タイムボックスストーミングは一つのテーマを決められたタイムボックス（例えば15分・20分・30分）で議論し、その後議論を客観的に振返り議論の改善点を見いだし（5分程度）、リフレッシュ（5分）を一クールとし、複数クール（2回～3回程度）を実施する方法です。この方法は議論が迷走することを抑制し、必要事項に集中する効果があり、テーマについて効率よく議論し結果を導き出すことが出来ます。
あくまでも参考ですが、リスクの観点として、抑えるべき点を列挙します。
**・ビジネス制約**
**・技術制約**
**・品質制約**
**・主な機能**
**・インフラストラクチャー**
**・セキュリティ**
**・ガバナンス**
**・運用課題（既存運用だけでなく、新規運用における教育・トレーニングも含める）**
**・市場優位性**
**・ROI**
**・SLAとEOLの条件**
**・リカバリー・復旧の要件（SLAとEOLに影響される）**
などですが、組織や業態によってはさらに観点を増やしたり、変更する必要があります。
これが、洗い出されたら、**夫々の因果関係と重要度（同列評価は認めず、必ず順位付けする）**を明確にし、それらを状況変化が直ぐに分かる様に可視化します。この**可視化はVeriSMにおけるマネジメントメッシュ（ここではあえてリスクマネジメントメッシュと呼びます）**と同等なものにすべきです。
この可視化されたリスクマネジメントメッシュは一定期間（理想はリアルタイムです）ごとに進行中のプロジェクトが置かれている現状に合わせて、更新し、プロジェクト遂行・継続・かじ取りの意思決定の指針と使用します。
こうすることで、絶えず変化するリスクへ対応した手法を手にする事ができます。
全てのリスクを徹底的に洗い出して扱うのではなく、**JITの思想をベースにリスクに向かい合う姿勢**が大切です。
１. Koa2を使ってWebページを作成しよう 〜環境構築編〜

## はじめに
今回初投稿です。
私たちは卒業研究で[Web版のお薬手帳](https://www.medice-note.vxx0.com/)を作りました。
その際、Koaを利用したWebアプリ開発の資料が少なく困ったため、投稿することにしました。

## 概要
当ページでは、Koa2を使ったWebページ作成に必要な環境を構築します。
開発ツールは[WebStorm](https://www.jetbrains.com/ja-jp/webstorm/)を使用します。
最終的には簡単なメモアプリの作成を予定しています。Webアプリを作成する順番を1から説明していくのでよろしくお願いします。

## Node.jsの導入
KoaはNode.js上で動作するフレームワークです。なので、**実行環境にNode.jsの導入**が必要となります。
まずは、[nodejs.org](https://nodejs.org/ja/)にアクセスし、Node.jsをインストールしてください。基本的には推奨版と記載されているバージョンを利用すると良いようです。
今回は推奨版の12.18.3を利用します。
インストーラーを起動したら、設定変更の必要がない場合はインストーラーの指示にしたがって進めてください。

### インストールの確認

コンソールで以下のコマンドを実行
`node -v`
以下のように表示されたらインストール成功
`v12.18.3` 　

## WebStormを使って設定ファイルを作成
まずはWebStormでプロジェクトを作成。
プロジェクト名はkoa2testとしてください。

次に利用する外部パッケージなどを記載する設定ファイルを作成。
コンソールで以下のコマンドを実行。
`npm init -y`

すると、`package.json`というファイルが作成されるので、以下の通り2点を変更。

### 1. scripts内を以下のように変更

```package.json
{
  "scripts": {
    "start": "node ./index.js"
  }
}  
```

### 2. license以下の行を次のように変更
※ "license": "ISC" の後にカンマを付けないとエラーになるので注意！

```package.json
{
  "license": "ISC",
  "dependencies": {
    "koa": "^2.12.0",
    "koa-ejs": "^4.3.0",
    "koa-router": "^8.0.8",
  }
}
```

package.jsonの変更後、以下のコマンドを実行。
`npm install`

これにより、package.jsonのdependenciesに記載したパッケージが`/node_modules`ディレクトリに保存され、プログラム内で使用することができるようになります。


## * 利用ライブラリの説明
* **koa**
Node.js用のWebフレームワーク。
expressでは非同期処理時に複雑なコードが必要でしたが、Koaではgenerator関数が実装されており、コードを簡潔に書けるようになりました。
Koa2では加えてasync/awaitが実装されて、さらに直感的に書けるようになっています。

* **koa-ejs**
ビューのレンダリングミドルウェア。
クライアントに送信するHTMLを動的に生成するために使用します。
固定の内容を表示するだけなら不要ですが、あとで追加すると構成が分かりづらくので、すでにインストールしておきます。

* **koa-router**
名前の通りルーティングに使用します。
アクセスされたURL毎に処理を振り分ける事ができ、振り分け先の処理で各種処理やビューのレンダリングを行うことで、ルーティング機能を実現しています。

## まとめ
以上で最低限の環境構築は完了です。
今は一から説明しているためKoa2らしさはあまり出てませんがこれから使っていきます。
次の投稿ではHello World! と表示するコードを書いていきたいと思います。
初めてのDialogflow 入門編

# Dialogflowとは

誰でも簡単にAIと対話するシステム（チャットボット）が作れることが大きな特徴です。
その他の特徴についても、簡単に特徴を箇条書きしていきます。  

- UI上で作成出来るため、コードを書く必要が無かったり、非エンジニアでも手を出し易い
- 開発スピードが早い
- Googleの技術（音声認識・音声合成・自然言語処理・感情解析）を使うことが出来る
- テキスト入力や音声入力などに対応している
- 外部サービスへの連携が簡単（Google Assistant、Facebook Messenger、Slack、Line、Skype...）

# 簡単なチャットボットの作成

「食べ物が欲しい」と聞くと、botが「はい、ハンバーガーです!」と返すようにセッティングしていきます。

## アクセス
まずはDialogflowにアクセスします。
アクセスし、ログインを済ませたらまずはAgentを作成します  
![createAgent.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544661/a4154f52-d17e-c7f4-d44f-8890c5514646.png)
![createAgent2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544661/ab355c44-b956-374c-1496-05bc1efe67c2.png)  

## Entity
次にEntityを作成します。
Entityとは「単語」や「用語」のことで、EntitiesにはIntents(要求や質問)に出てくる単語をカテゴリ単位で蓄積していきます。
また、DialogflowはIntentsの内容をEntitiesで判断して答えを返します。

カテゴリからEntitiesを選択し、CREATE ENTITYをクリックします。
![Dialogflow 2020-09-23 11-17-26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544661/db253a8b-2641-fa03-1689-43cda1ad4614.png)

次にEntityに名前を付けます。ここでは「food」とします。
次に「Value(値)」と「Synonym(類義語)」を入力していきます。
類義語として登録したものはみな同じ値として認識されます。
最後に「SAVE」します。
![Dialogflow 2020-09-23 18-14-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544661/820fc6b1-ef01-394d-800a-06186a87a496.png)

## Intent
最後にIntentを作成します。
Intentとはユーザの「要求」や「質問」をため込んでいく場所になります。
ユーザが何かを書いたり読んだりすると、エージェントの最も適切なインテントとマッチングします。
![Dialogflow 2020-09-24 10-41-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544661/c94e8142-4ed6-b136-a729-7665f5431b53.png)

ここでは「food-intent」とします。
次にTraining phrasesに「食べ物が欲しい」と追加します。
![Dialogflow 2020-09-24 16-33-08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544661/1ab2fca7-db48-3454-d091-12cf3d9f7bcd.png)

「食べ物が欲しい」と入力すると文字の背景色が変わってEntityと自動で紐づいたのが確認できると思います。
![Dialogflow 2020-09-24 16-33-41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544661/1cf41580-630e-4c78-a124-7b583cd5ec2b.png)

続いてResponseの設定です
レスポンスに「はい、ハンバーガーです。」と書いてIntentの設定も完了です。
SAVEボタンをクリックし、AIに学習させましょう。
![Dialogflow 2020-09-25 10-46-40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544661/5fc2859c-cdaa-3927-09cb-97c52c8cf421.png)

## 確認
最後に上手く出来たかどうかを確認します。
マイクボタンをクリックし、「食べ物が欲しい」と言ってみてください。
![Dialogflow 2020-09-25 10-55-35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544661/85b88e44-81a7-6ea3-7d31-d25cd011c968.png)

自分が喋った内容「食べ物が欲しい」
レスポンス「はい、ハンバーガーです。」
Intentは「food-intent」
となってるのが確認出来るかと思います。
他にも「食品が欲しい」や関係の無い質問なども試してみてください。

![Dialogflow 2020-09-25 10-56-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544661/6cce88c7-57f2-cfa5-38fe-5905246d91bc.png)

# 最後に
以上で入門編を終わります。
次回はもっと複雑なbotにチャレンジします
FizzBuzz問題を解いてみよう！

【概要】
----------------------------------------
<b>1.結論</b>

<b>2.FizzBuzz問題とは何か</b>

<b>3.どのようにプログラムするのか</b>

<b>4.ここから学んだこと</b>



1.結論
----------------------------------------
<b>eachメソッドとif..elsifを組み合わせ</b>よう！
<br>
2.FizzBuzz問題とは何か
----------------------------------------
結論としては、コードが書けないプログラマー志願者を分けるために作られたプログラムです。

具体例としては、
<b>(i)1~100の数字を出力する際に、
(ii)3の倍数は”Fizz"
(iii)5の倍数は"Buzz"
(iv)15の倍数は"FizzBuzz"
を表示させる</b>

というプログラムです！
基本的なことが理解できているかを試せる問題として有名です！
<br>

3.どのようにプログラムするのか
----------------------------------------

今回は使用する言語は"Ruby"になります。

```ruby
def fizz_buzz
  num = 1 #---❶
   (1..100).each do |i| #---❷
    if num % 15 == 0 #---❸
      puts "FizzBuzz"
    elsif num % 3 == 0
      puts "Fizz"
    elsif num % 5 == 0
      puts "Buzz"
    else
      puts num #---❹
    end

    num = num + 1 #---❺
  end
end

fizz_buzz
```
❶まずここでnumに"1"を代入しないとどの変数のどの値からか、わかりません。今回は1~100なので"1"を代入しています。

❷"2.FizzBuzz問題とは何か"で説明した(i)を満たすには、繰り返し処理＋条件が必要です。ここは"4.ここから学んだこと"に後述しますが、each以外のメソッドでもコーディングできます。

❸"2.FizzBuzz問題とは何か"で説明した(ii)~(iv)を満たすための条件式です。倍数の場合分けは、剰余演算子を利用して3/5/15の倍数を判別しています。注意としては3の倍数の条件式からコーディングしてしまうと、"15"の数字が出た際に"3の倍数"の条件で認識されてしまいます。プログラムは<b>上から下</b>に読み込まれるのが基本なので、一度条件に当てはまると以降のプログラムは無視されます。
剰余の書き方については自分の記事でも紹介しているので、探す手間が省けます！
<a href="https://qiita.com/taka_no_okapi/items/b9acd75060ae4df2bdd1">剰余とべき乗（冪乗）の演算子</a>

❹"2.FizzBuzz問題とは何か"で説明した(i)で"1~100"を表示させるので倍数以外の条件も出力します。なので条件以外数字はそのままの数字を出力するようにしています。

❺これがないと、”1”以降の数字を生み出せません。eachに1~100と書いてあっても"1"を100回出力する繰り返し処理になってしまいます。"num += 1" でもOKです。

<br>
4.ここから学んだこと
----------------------------------------
❷の部分は
繰り返し処理メソッドと条件の式(100以下)を組み合わせればいけるのではと思いwhileメソッド使ったところ動きました。

```ruby
while num <= 100 do
```
いろいろ検索していたところ、
繰り返し処理は下記URLのようにたくさんの方法がありました！自分が知っていたのはtimes/each/whileメソッドでした。また条件をどう組み込むかもメソッドによって違います！

参考にしたURL:
<a href="https://www.javadrive.jp/ruby/for/index1.html">while文</a>
<a href="https://qiita.com/setsuna82001/items/ea80e134d5f01e05a8f3">いろいろな方法で1から100までを出力する</a>

<br>
Scoopのインストール



#Scoopとは
Windows用のコマンドラインパッケージマネージャー。


Chocolateyと比較したメリット
- アンインストールをScoop上のみで完結できる
- UACポップアップが無い

#インストールの前提条件
- Windows PowerShell 3以上
- .NET Framework 4.5以上

#インストール手順
##1. PowerShell を起動する。
※[Win]または[Win]+[s]で、検索ボックスに「powershell」と入力すれば起動できる）

##2. ポリシー設定変更
ローカルの PowerShell スクリプトを実行できるように、PowerShell 実行ポリシーを Restricted から RemoteSigned に設定する。

```powershell:PowerShell
PS C:\> Set-ExecutionPolicy RemoteSigned -scope CurrentUser -force
```

##3. インストールスクリプトを実行する
get.scoop.sh を Invoke-WebRequest でダウンロードして invoke-Expression で起動する。
※ iwr : Invoke-WebRequest のエイリアス
※ iex : invoke-Expression のエイリアス

```powershell:PowerShell
PS C:\> iwr -useb get.scoop.sh | iex
```

#4. Scoopのディレクトリ構成
デフォルトでは、ユーザーディレクトリ下にScoopのディレクトリが作成されます。
%UserProfile%/.config/
%UserProfile%/scoop/

#参考文献
- [全Scoopコマンド解説 その１ ～使用頻度（高）～](https://qiita.com/nimzo6689/items/1ab33380366e324c0b84)
- [全Scoopコマンド解説 その２ ～使用頻度（中）～](https://qiita.com/nimzo6689/items/0fb3e918248866c2c23e)
- [全Scoopコマンド解説 その３ ～使用頻度（低）～](https://qiita.com/nimzo6689/items/53c63439f56ccd2d38c1)
- [Scoopを使ったWindows環境構築のススメ - Super!!](https://qiita.com/Dooteeen/items/12dc8fb14042888113d0)
- [Scoopを使ったWindows環境構築のススメ - Hyper!!!](https://qiita.com/Dooteeen/items/c55223c26a42776f7101)
- [Scoop で利用できる Bucket の解説（`scoop bucket known` 限定）](https://qiita.com/nimzo6689/items/5ead753169dbad72e4eb)
- [scoop bucket を作成する](https://blog.haniyama.com/2018/03/12/scoop-bucket/)
Windows10でローミングの感度を上げる方法

無線LANのローミング確認で切り替わりが悪い時に変更すれば切り替わりがスムーズになります。

#手順
①　Windows+Rを押下する。

②　[control]と入力する。
　　※コントロールパネルを開いてもよし

③　[ネットワークとインターネット]を選択する。
　　　※表示がカテゴリの場合。

④　[ネットワークと共有センター]を押下する。

⑤　画面左にある[アダプターの設定の変更]をクリックする

⑥　該当のNICで右クリックする。

⑦　[プロパティ]を押下する。

⑧　[構成]を押下する。

⑨　[詳細設定]のタブをクリックする。

⑩　[ローミングの積極性]を選択する。

⑪　値を[5:最高]へ変更する。
　　※感度を下げる場合は価を下げる

⑫　[ok]を押下する。

以上
VPC エンドポイントへのアクセス許可は SourceIp ではなく VpcSourceIp を利用する

# 概要
VPC エンドポイントを設定した AWS サービスへの IP アドレスによるアクセス許可は SourceIp ではなく、VpcSourceIp を利用する必要があります。

# 詳細
## 前提条件
S3 の特定のバケットに対して VPC エンドポイントを利用していると仮定します。

その S3 に対しては次のようにパブリックなアクセス許可を与えています。

```json
{
    "Version": "2012-10-17",
    "Id": "Policy156583539788",
    "Statement": [
        {
            "Sid": "Stmt156583536527",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::bucket/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "0.0.0.0/0"
                }
            }
        }
    ]
}
```

この設定ではすべての IP アドレスからの GetObject を許可しています。

## VpcSourceIp の指定
この状態で VPC 内のインスタンスなどからこのバケットにアクセスしようとしても Access Denied になります。

VPC エンドポイントへのアクセス許可（およびアクセス制限）に SourceIp は使えないからです。

> VPC エンドポイントを介した Amazon S3 へのリクエストに、IAM ポリシーの aws:SourceIp 条件を使用することはできません。これはユーザーとロールの IAM ポリシー、およびバケットポリシーに適用されます。ステートメントに aws:SourceIp 条件が含まれる場合、値は指定した IP アドレスまたは IP アドレス範囲に一致しません。

ref: https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/vpc-endpoints-s3.html　

その代わり、[VpcSourceIp](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-vpcsourceip) を利用します。

> リクエスト実行元が Amazon VPC エンドポイントを使用するホストである場合、aws:SourceIp キーは使用できません。代わりに、aws:VpcSourceIpなどの VPC 固有のキーを使用する必要があります。

ref: https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_condition-keys.html

```json
{
    "Version": "2012-10-17",
    "Id": "Policy1565835397817",
    "Statement": [
        {
            "Sid": "Stmt1565835396529",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::bucket/*",
            "Condition": {
                "IpAddress": {
                    "aws:VpcSourceIp": "0.0.0.0/0"
                }
            }
        }
    ]
}
```

これで VPN エンドポイントを経由した VPC 内からのアクセスを許可することができます。

# SourceIp と VpcSourceIp の併用

VPC 内に加えて、外部からもアクセスを許可したい場合は次のように SourceIp と VpcSourceIp のアクセス許可を二つ列挙します。

```json
{
    "Version": "2012-10-17",
    "Id": "Policy1565835397817",
    "Statement": [
       {
            "Sid": "Stmt156583539651",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::bucket/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "0.0.0.0/0"
                }
            }
        },
        {
            "Sid": "Stmt1565835396529",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::bucket/*",
            "Condition": {
                "IpAddress": {
                    "aws:VpcSourceIp": "0.0.0.0/0"
                }
            }
        }
    ]
}
```
xcodeでアプリのアイコンを設定できない

【問題】
アプリのアイコン画像をドラッグして設定しようとするが、設定されない。
画像サイズは合わせてある。

【原因】
xcodeの中央エディターから画像を設定しようとしていた。
Finderからドラッグすれば設定できた。

アホみたいなミスだけど、アイコン変更は滅多になく
次もやらかすと思うのでメモしておく。

![スクリーンショット 2020-09-25 11.01.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295432/b134cd3b-ecc6-f7f5-fa8e-97240f4d626a.png)
Windows10にて外付けHDD/USBメモリ/SDカードで「ファイルは大きすぎて、対象のファイルシステムに入りません」対処法


FAT32のストレージデバイスで
「対象のファイルシステムに入りません」エラーの対処法。
容量が4GB以上の大容量ファイルを外付けHDD/USBメモリなどにコピー場合に、
このエラーが発生します。

#手順

①　[エクスプローラー]を開く

②　該当のストレージデバイスを右クリックする。

③　[フォーマット]を押下する。

④　ファイルシステムにて[NTFS]を選択する。

⑤　[クイックフォーマット]のチェックを外す。

⑥　[開始]を押下する。

⑦　フォーマット完了まで待つ。

⑧　完了後、データをコピーする。

以上
Railsプロジェクトを作成したあとにActiveRecordを使わないようにする

`rails new`するときに`--skip-active-record`オプションを付けなかった場合から付けた場合への差分です。

Railsプロジェクトを作成したあとに、DBを使わなくなった場合などの参考に。

Railsバージョン6.0.0.3

```diff:.gitignore
- # Ignore the default SQLite database.	
- /db/*.sqlite3	
- /db/*.sqlite3-journal	
- /db/*.sqlite3-*


- # Ignore uploaded files in development.	
- /storage/*	
- !/storage/.keep
```

```diff:Gemfile
- # Use sqlite3 as the database for Active Record	
- gem 'sqlite3', '~> 1.4'


- # Use Active Storage variant	
- # gem 'image_processing', '~> 1.2'	
```

```diff:Gemfile.lock
省略
```

```diff:app/javascript/packs/application.js
- require("@rails/activestorage").start()
```

```diff:app/models/application_record.rb
削除
```

```diff:bin/setup
- # puts "\n== Copying sample files =="	
- # unless File.exist?('config/database.yml')	
- #   FileUtils.cp 'config/database.yml.sample', 'config/database.yml'	
- # end	


- puts "\n== Preparing database =="	
- system! 'bin/rails db:prepare'	
```

```diff:config/application.rb
- require 'rails/all'
+ require "rails"
+ # Pick the frameworks you want:
+ require "active_model/railtie"
+ require "active_job/railtie"
+ # require "active_record/railtie"
+ # require "active_storage/engine"
+ require "action_controller/railtie"
+ require "action_mailer/railtie"
+ # require "action_mailbox/engine"
+ # require "action_text/engine"
+ require "action_view/railtie"
+ require "action_cable/engine"
+ require "sprockets/railtie"
+ require "rails/test_unit/railtie"
```

```diff:config/database.yml
削除
```

```diff:config/environments/development.rb
- # Store uploaded files on the local file system (see config/storage.yml for options).	
- config.active_storage.service = :local


- # Raise an error on page load if there are pending migrations.	
- config.active_record.migration_error = :page_load	


- # Highlight code that triggered database queries in logs.	
- config.active_record.verbose_query_logs = true	
```

```diff:config/environments/production.rb
- # Store uploaded files on the local file system (see config/storage.yml for options).	
- config.active_storage.service = :local	


- # Do not dump schema after migrations.	
- config.active_record.dump_schema_after_migration = false	
```

```diff:config/environments/test.rb
- # Store uploaded files on the local file system in a temporary directory.	
- config.active_storage.service = :test	
```

```diff:config/initializers/wrap_parameters.rb
- # To enable root element in JSON for ActiveRecord objects.	
- # ActiveSupport.on_load(:active_record) do	
- #   self.include_root_in_json = true	
- # end
```

```diff:config/storage.yml
削除
```

```diff:db/seeds.rb
削除
```

```diff:package.json
-  "@rails/activestorage": "^6.0.0",
```

```diff:test/test_helper.rb
-  # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.	
- fixtures :all	
```

実際にrails newしたものの差分です。
https://github.com/hid3h/diff-rails-active-record/pull/1/commits/725b4147da5b94db4d5f5ded0c7bf5c27c3d4489
【rails】enumのレコード登録数をバリデーションで制限する方法

## はじめに
開発を行っているとenumを使って、データを分ける場合があると思います。
enumで分けたデータに対してそれぞれレコードの登録数を制限する実装をしたのでメモとして残しておきます。

## 開発環境
Rails 6.0.3
Ruby 2.7.1

## テーブル
今回は下記のようなUsersテーブルを想定しています。
性別(sex)はenumでman/femaleのどちらかしか選択できないようにしています。

|name|sex(enum)|
|---|---|
|ユーザー1|man|
|ユーザー2|female|


## レコード数を制限する方法
models/user.rbにメソッドを作成し、man/femaleそれぞれのレコード数を確認して、もし制限数(10件)を超えていればエラーを追加します。
`on: :create`を記載しないと毎回バリデーションが適用され、編集できなくなってしまうので忘れないよう！
(私はここに気づかず編集の際にエラーが発生してしまいました。)

```user.rb
class User < ApplicationRecord
  REGISTER_LIMIT_COUNT = 10 # 定数として登録数を管理

  enum sex: { man: 0, female: 1 }

  validate :limit_user_register_count, on: :create  # 作成したメソッドでバリデーション

  def limit_user_register_count
    if self.sex == "man" && man.count >= REGISTER_LIMIT_COUNT # enumがman かつ manのレコード数が制限を超えている
        errors.add(:user, "man count is over") # エラーを追加
    elsif self.sex == "female" && female.count >= REGISTER_LIMIT_COUNT
        errors.add(:user, "female count is over")
    end
  end
end
```

## Rspecでバリデーションを確認する方法

```user_spec.rb
require 'rails_helper'

RSpec.describe Guide, type: :model do
  context 'データを11個以上登録する場合' do
    before { create_list(:user, 10, sex: 'man') } # manのデータをを10人分作成

    it 'エラーメッセージを返すこと' do
      man = build(:user, sex: 'man') # 11人目をbuildする(バリデーションがかかるのでcreateは不可)
      man.valid?                     # validすることでcreateしようとしてvalidationが走り、エラーが追加される
      expect(man.errors[:user]).to eq('man count is over')
    end
  end
end
```

```factories/users.rb
FactoryBot.define do
  factory :user do
    name { Faker::Name.name }
    sex { 0 }
  end
end
Caused by SSLError("Can't connect to HTTPS URL because the SSL module is not available.")でハマったときの話

# はじめに
Webスクレイピングの練習のために
サンプルコードを入手してスクレイピングを試したところ
例外が発生してドハマりしたので事象と解決方法をメモする

# 事象
[【Python】スクレイピングで株価データを取得する](https://non-dimension.com/kabuka-scraping/)を参考にして
スクリプトを実行したところ↓↓のエラーが発生して処理が進められなかった。
PCも工場出荷状態に戻した直後だったので結構焦る。

```:スクリプト実行結果のエラーメッセージ
requests.exceptions.SSLError: HTTPSConnectionPool(host='***.co.jp', 
port=443): Max retries exceeded with url: / (Caused by SSLError("Can't 
connect to HTTPS URL because the SSL module is not available."))
```

# 環境
anaconda 1.9.12
python 3.8.3

# 解決方法
参考：https://stackoverflow.com/questions/54135206/requests-caused-by-sslerrorcant-connect-to-https-url-because-the-ssl-module

環境変数に以下のパスを入れたら直った。
```:環境変数
%USERPROFILE%\Anaconda3
%USERPROFILE%\Anaconda3\scripts
%USERPROFILE%\Anaconda3\Library\bin
```
具体的にはこんな感じ。
![スクリーンショット 2020-09-25 105532.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/5805b5c8-a800-72b3-6495-f8204ff1e4c6.png)

## おわりに
今さら振り返ると、python実行環境はanaconda3なのに、vscode上からpythonを起動したから
anacondaでインストールしたパッケージが参照されなかったのかなぁ…なんて思った。
ともかく、問題解決してよかった。
教師あり学習2　ハイパーパラメーターとチューニング(1)

[Aidemy](https://aidemy.net/)　2020/9/30
#　はじめに
　こんにちは、んがょぺです！バリバリの文系ですが、AIの可能性に興味を持ったのがきっかけで、AI特化型スクール「Aidemy」に通い、勉強しています。ここで得られた知識を皆さんと共有したいと思い、Qiitaでまとめています。以前のまとめ記事も多くの方に読んでいただけてとても嬉しいです。ありがとうございます！
　今回は、教師あり学習の二つ目の投稿になります。どうぞよろしくお願いします。

＊本記事は「Aidemy」での学習内容を「自分の言葉で」まとめたものになります。表現の間違いや勘違いを含む可能性があります。ご了承ください。

今回学ぶこと
・ハイパーパラメータについて
・ロジスティック回帰、線形SVM、非線形SVMのハイパーパラメータ

#ハイパーパラメータ
##ハイパーパラメータとは
・ハイパーパラメータとは、機械学習モデルの中で、__「人が調整しないといけない領域（パラメータ）」__のこと。モデルの種類によってパラメータは異なる。（次項以降で個別に見ていく）
・ハイパーパラメータを人為的に調整することを__チューニング__という。
・モデル構築時にパラメータをチューニングすることができる。（方法は後述）

#ロジスティック回帰のハイパーパラメータ
##パラメータ　C
・ロジスティック回帰のハイパーパラメータの一つに__C__というパラメータがある。（初期値1.0）
・Cは__「教師データにどれだけ忠実に境界線を引くか」__の指標になる。すなわち、Cの値が高ければ全ての教師データを分類できるような境界線を引くが、過学習に陥りやすいと言える。
・__model=LogisticRegression(C=1.0)__ のようにして指定する。

##パラメータ penalty
・__penalty__というパラメータは、__「モデルが複雑になりすぎた際に、特徴量（L1）か全体の重み（L2）を減らして適切に汎化されるようにするもの」__である。
・LogisticRegressionの引数に__penalty=L1__　のように指定する。

##パラメータ　multi_class
・__multi_class__というパラメータは__「複数のクラス分類を行う際の挙動」__を示している。
・ロジスティック回帰では、二項分類では「クラスに属するか/属さないか」の挙動である__ovr__と指定する。多項分類では「どれくらい属する可能性があるか」の挙動である__multinomial__と指定する。

##パラメータ　random_state
・__random_state__は__「データの処理順を決める乱数のseed」__であり、これを固定することでデータの処理順（＝学習の結果）も固定される。

#線形SVMのハイパーパラメータ
##各パラメータ
・__C__：内容も使い方も同じ。ただし、Cの値が変化するとロジスティック回帰よりも正解率に大きな影響が出る。
・__penalty__：ロジスティック回帰と同様。
・__multi_class__：線形SVMでは__ovr__と__crammer_singer__を指定できる。基本的にはovrの方が結果が良くなる。また、二項分類の時はこのパラメータを設定する必要はない。
・__random_state__：線形SVMでは、サポートベクターの決定時にもこの値が影響を及ぼし、結果が若干変わることがある。

#非線形SVMのハイパーパラメータ
##パラメータ　C
・__C__：内容も使い方も同じ。ただし、ペナルティはCの値を調整することで行われる。

##パラメータ　kernel
・__kernel__は、非線形SVMの処理の要である__「非線形分類を線形分類に直す」動作に使われるカーネル関数を指定する__パラメータ。指定できるのは「rbf」「poly」「linear」「sigmoid」「precomputed」の５つだが、デフォルト値であり正解率の高い「rbf」を使うことが多い。
・「rbf」「poly」は立体投影、「linear」は線形SVMと同じ動作（のため使うことはほぼない）、「sigmoid」はロジスティック回帰モデルと同じ動作、「precomputed」はデータが既に整形済みの時に使う。

##パラメータ　decision_function_shape
・__decision_function_shape__は、multi_classと同様に、データがどのクラスに属するかを決めるときの挙動を示す。指定できるのは「ovo」と「ovr」である。
・ovoは、クラスを２つで１つの組み合わせにして、その全ての場合に対して各データを二項分類するやり方である。ovrはデータをそのクラスに属するかを（直接）分類する。ovoの方が計算量が多いので、動作が重くなりやすい。

##パラメータ　random_state
・__random_state__：非線形SVCでは、乱数生成器を別に作成しなければならない。

```python
import numpy as np
from sklearn.svm import SVC
#乱数生成器の作成
a = np.random.RandomState()
model = SVC(random_state = a)
```
#まとめ
・モデルの中で人為的に調整をしなければならないパラメータを__ハイパーパラメータ__といい、モデルの種類によって設定すべきハイパーパラメータは異なる。
・ロジスティック回帰、線形SVMのハイパーパラメータには__「C」「penalty」「multi_class」「random_state」__がある。
・非線形SVMのハイパーパラメータには__「C」「kernel」「desicion_function_shape」「random_state」__がある。

今回は以上です。ここまで読んでくださりありがとうございました。
scanメソッド問題

##問題
任意の文字列で
"hi"がいくつあるか数えてその数を出力するメソッドを作りましょう。

##出力例
count_hi('abc hi ho') → 1
count_hi('ABChi hi') → 2
count_hi('hihi') → 2

##scanを使う
scanは、対象の要素から引数で指定した文字列を検索して配列として返すメソッドです。

##scanの使い方
正規表現と使う場合がほとんどですが、正規表現でなくても文字列を検索して配列として返したい場合にも使うことができます。

記述方法は、オブジェクト.scan(正規表現)という書き方をします。

##問題の回答

```qiita.rb
def count_hi(str)
  puts str.scan("hi").length
end
```
引数strにscanメソッドを使用する。
今回は"hi"がいくつあるかを数えたいので、文字列の長さと配列の長さを調べるためのメソッドであるlengthメソッドを用いて出力する。
【git】リモートブランチをローカルブランチにcheckoutするコマンド

### はじめに
チーム開発をおこなっているとリモートにあるブランチをローカルに持ってきて開発したい時があると思います。
その方法を備忘録として書きました。

### リモートブランチをローカルブランチにcheckoutする方法

まず最新のリモートブランチを情報をローカルに反映させるために、fetchを行います。

```:ターミナル 
$ git fetch
```

リモートを含め、全てのブランチを確認。

```:ターミナル 
$ git branch -a
* develop                                   // 現在のブランチ
  remotes/origin/HEAD -> origin/develop     // remotesがあるものはリモートブランチ
  remotes/origin/develop
  remotes/origin/feature/create_user
  remotes/origin/feature/update_user
  remotes/origin/feature/delete_user
```

そして、リモートブランチをローカルにcheckoutすると、リモートブランチの情報をローカルに作成することができます。

```:ターミナル 
$ git checkout -b ブランチ名 origin/ブランチ名

// ex) remotes/origin/feature/create_userを作成したい場合のコマンドは下記の通りです。
$ git checkout -b feature/create_user origin/feature/create_user
```

### 終わりに
その他にもGitに関する記事を書いていますので良かったら見てみてください。
[gitの使い方(git init 〜git push)](https://qiita.com/shungo_m/items/b73ff5b1ec6d69bb5c50)
[gitのブランチ作成〜リモートへの登録(git checkout ~ git push -u origin)](https://qiita.com/shungo_m/items/4bbcbcbd3d7aea40b21e)
[【git】ブランチ名の変更方法(ローカル、リモート)](https://qiita.com/shungo_m/items/4218e70751375b4bfeec)
[【git】作業ブランチを間違えた場合(変更内容を違うブランチへ持っていく方法)](https://qiita.com/shungo_m/items/1839a2d95b7eddf24e8a)
Excel VBAからCDOを使用してメール送信

# 最初にやること

CDOを参照をさせます。

ツール-参照設定でMicrosoft CDO for Windows 2000 Libraryにチェックを入れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156294/68782ece-bd8b-f9aa-feaf-a1e95fb0fb48.png)

# プログラム

activesheetの
B1に送信先メールアドレス
B2に題名
B3に本文
が記入されているものとします。

``` VB
Option Explicit

 Sub SendMail()
    Dim objCDO As New CDO.Message
    With objCDO
        With .Configuration.Fields '設定項目
            .Item(cdoSendUsingMethod) = cdoSendUsingPort '外部SMTP指定
            .Item(cdoSMTPServer) = "mail.server.name" 'SMTPサーバ名
            .Item(cdoSMTPServerPort) = 25 'ポート№（メールサーバーごとに変更）
            .Item(cdoSMTPConnectionTimeout) = 60 'タイムアウト
            
            .Item(cdoSMTPAuthenticate) = cdoBasic 'SMTP認証
            .Item(cdoSMTPUseSSL) = False 'SSL指定
            .Item(cdoSendUserName) = "sender ID" '送信ユーザー
            .Item(cdoSendPassword) = "password" '送信パスワード
            .Item(cdoLanguageCode) = CdoCharset.cdoShift_JIS  '文字セット指定
            .Update '設定更新
        End With

        .BodyPart.Charset = "utf-8" '本文の文字セット指定
        .From = "sender@address" '送信者アドレス
        .To = cells(1,2) '受信者
        .Subject = Cells(2, 2).Value '題名
        .TextBody = Cells(3, 2).Value '本文
        .Send '送信
    End With

    Set objCDO = Nothing
End Sub
```

# おわり
Inkscapeをプレゼンスライドのイラスト作成に使用する設定&技術集

PowerPoint依存から脱出する試み。PowerPointでもっとも依存度が高いと思われる「作図」を[Inkscape](https://inkscape.org/)で実施する。作図を効率よく行うために、Inkscapeに施すべき設定&操作技術を集める。

# 設定項目

## パレット

[Inkscapeでカスタムの色パレットを登録する方法](https://web.plus-idea.net/on/inkscape-custom-color-palettes/)

PowerPointを使っていて、一番おろそかになるところ。顧客のフォーマットに合わせてください、ということになるので、いつまでたっても色彩センスが磨けない。

## デフォルトフォント

[【忘備録】Inkscapeでデフォルトのフォントを設定する手順](http://degitekunote.com/blog/2014/09/24/inkscape-default-font-setting/)

案外、フォント設定で悩んでPowerPointに出戻ってしまうので、デフォルトフォントは重要である。

## 複数ページサポート

[Inkscape multiple pages support](https://sourceforge.net/projects/inkscape-pages/?source=navbar)

Inkscapeはデフォルトでは1ファイル複数ページをサポートしない。これはSVGの規格に起因する制限のようだ。プラグインで複数ページを扱うことにより、「1ドキュメントに必要な画像をひとまとめにする」ことができる。

## 用紙のA4横設定

[Inkscape ページを縦から横に変えてみよう](https://gazocustomize.com/inkscape-page-lengthside/)

InkscapeはデフォルトではA4縦のページ設定になっている。通常は横長と思われる、スライドへの貼り込みを考えた時に画面の無駄が多いので、設定する。

# 作業テクニック

## 画像読込

[画像を読み込む／書き出す](http://inkscapedesign.web.fc2.com/basic/image.html)

PowerPoint使用者が何気に便利だと感じるのが、イラストを検索して、手軽に使用できること。個人的に、イラストは紙に手描きしたものをスキャンしたほうが早いので、読み込みさえできれば問題ない。

## シェイプの配置

[スナップで正確に配置](http://inkscapedesign.web.fc2.com/medium/snap.html)

PowerPointでやってしまいがちな、「感覚的な配置」を矯正する。もちろんPowerPointでもできるが、PowerPointは「作ったスライドをPowerPoint上でスライドショーするので、1枚のスライドに収めるための微調整」を行ってしまいがち。ブラウザベースでのスライドショー用にSVGを作るのであれば、拡大縮小は直感的に操作できる。微調整に時間をかける必要はない。

# Inkscapeの設定を集める背景

仕事柄、プログラミング演習テキストや、解説スライドを作ることが多い。これまで会社標準ということでPowerPoint、Wordを使ってきたが、版管理、及びドキュメント間のフォーマット統一が難しい。サクッと作ってサクッと研修にもっていけることに加えて、後程の再利用も意識しなければいけない。

## 研修ドキュメントでのOffice製品の使いどころと、別ツール置き換え時の課題

1. Excel:演習データの整理
2. PowerPoint:解説スライド
3. Word:演習ドキュメント

このうち、ExcelはVBAマクロという実行時の要素があるので、なかなか代替しにくい面がある。単に表示できれば良いという問題ではないのが辛い(とはいえ、[JupyterLab](https://jupyter.org/)とかでやった方がいいんじゃないのか、と思うときもあるが)。
というわけで、2.、3.の文書の内容を解体する。

1. 演習テキスト
   - 解説文書
   - ソースコード
   - 画像
2. 解説スライド
   - 箇条書き
   - 画像
   - ソースコード

Word、PowerPointの一番のストレスは「ソースコードをソースコードとして認識しない」ということ。とにかく体裁を整えるのが苦痛。基本的にはasciidocで置き換えた方が幸せになれる。
ただし、asciidocで唯一最大の障害は、画像の扱いだと思う。

スライド解説は、読ませるのではなく、「見せる(魅せる)」ことが目的。結局のところ、PowerPointは「お絵描きツール」なのだ。だからこそ生き残っている。それは否定しないが、プログラマとしては"X as Code"にできるところはやりたい。Picture as Codeになれば、"X as Code"の技術が応用できる。

とはいうものの、[Inkscape Slides](https://inkscape.org/~doctormo/%E2%98%85inkscape-slides)とかはちょっとやりすぎだと思う。プレゼンを楽に実施し、スライドを楽に管理したいのであって、「そのツールがないと作業できない」という状況は避けたい。
TerraformでError: Failed to get existing workspaces: AccessDenied: Access Deniedが出力された際

## エラー内容
```
terraform init

Initializing the backend...

Error: Failed to get existing workspaces: AccessDenied: Access Denied
    status code: 403, request id: *********, host id: ******************************
```

## 設定
```
provider "aws" {
  region = "ap-northeast-1"
  profile = "hogehoge"
}
```

## 試したこと
- 下記記事をもとに、コマンドを実行
  - https://qiita.com/akashixi/items/889f43562d16fd2f9367

```
$ AWS_PROFILE=hogehoge terraform init
```

## それでも上手くいかない
下記のコマンドを実行して、生成されたファイルを削除することで上手くいくようになりました。

```
$ rm -r .terraform/
$ terraform init
```

## 原因と思われること
おそらく、profileの設定を行わずにterraform initした際の設定が残っており、そちらを参照していたから
発生していたエラーなのかなぁと思っています。