OmniAICreator/Qiita-1.07M huggingface dataset:
Oculus Quest で、モノを掴めるようにする

Unityで、Oculus Quest 用のコンテンツを作る際に、手っ取り早くモノを掴めるようにしたい時の方法です。

## 手順

1. [Oculus Integration](https://assetstore.unity.com/packages/tools/integration/oculus-integration-82022) をインポート
2. Oculus > SampleFramework > Core > AvatarGrab > Prefabs 内の「LocalAvatarWithGrab」を、ヒエラルキーに配置
3. 掴みたいオブジェクトに対して、Add Component で「OVR Grabbable」を追加
4. 掴みたいオブジェクトに対して、Add Component で「Rigidbody」を追加（「Use Gravity」にはチェックを入れておく）

## 解説

- LocalAvatarWithGrab 配下の「AvatarGrabberLeft」「AvatarGrabberRight」を見てみると、「OVR Grabber」がアタッチされていますが、これが「モノを掴むため」に必要なスクリプトになります
- そのため、LocalAvatarWithGrabを使わなくとも、好きな手のモデルに「OVR Grabber」をアタッチしてもOKです
- 一方で、「掴まれるモノ」として機能させるために必要なスクリプトが、「OVR Grabbable」になります

## 事例

- モノを掴めるようになると、色々と発想の幅が広がって楽しくなるので、ぜひやってみてください

### プレゼントを渡す

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">バレンタインが近いので、ユニティちゃんにチョコレートあげる練習してる。<a href="https://twitter.com/hashtag/Unity?src=hash&amp;ref_src=twsrc%5Etfw">#Unity</a> <a href="https://twitter.com/hashtag/unitychan?src=hash&amp;ref_src=twsrc%5Etfw">#unitychan</a> <a href="https://t.co/UhglKyeR7r">pic.twitter.com/UhglKyeR7r</a></p>&mdash; tamu (@tamusan100) <a href="https://twitter.com/tamusan100/status/1092011603048857600?ref_src=twsrc%5Etfw">February 3, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

※ このときは Oculus Rift 用に作成していますが、同じ方法です。

### ペットにエサを与える

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Oculus Quest向けにカメ育てるVR作り始めた。やはり手が使えるのは楽しい。<a href="https://twitter.com/hashtag/Unity?src=hash&amp;ref_src=twsrc%5Etfw">#Unity</a> <a href="https://twitter.com/hashtag/OculusQuest?src=hash&amp;ref_src=twsrc%5Etfw">#OculusQuest</a> <a href="https://t.co/f1ktgrfwjS">pic.twitter.com/f1ktgrfwjS</a></p>&mdash; tamu (@tamusan100) <a href="https://twitter.com/tamusan100/status/1132628734509428736?ref_src=twsrc%5Etfw">May 26, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
テスト駆動開発やってみた

## はじめに
私は、今までテスト駆動開発(TDD)をしらずにソフトウェア開発をしていました。
そして下記のような苦労がありました。

* バグを直そうとしたら、ほかのバグを埋め込んでしまった。
* どこにバグの原因があるかわからず、デバッグに長い時間をかけていた。
* コードをきれいにしたくても既存の振る舞いが変わってないか手動テストするのが大変だった。

TDDを導入することで、下記のメリットを享受できます。

* 安全なリファクタリングができるので、きれいで動くコードをかける。
* 自動テスト可能なコードをかける。

本記事は、私がTDDを実践して、これらのメリットを実感できた記録です。

またテスト対象の課題として[Fizz Buzz](https://ja.wikipedia.org/wiki/Fizz_Buzz)を選びました。
本記事で紹介する完全なコードは、 [GitHub](https://github.com/mei1161/LearnFizzBuzzCSharp) を参照してください。


## 開発環境
本記事で解説するコードは、下記の環境で開発しました。

<dl>
<dt>OS</dt>
<dd>Windows 10</dd>
<dt>テスティングフレームワーク</dt>
<dd>NUnit 3.10.1</dd>
<dt>IDE</dt>
<dd>Visual Studio 2019</dd>
<dt>CI</dt>
<dd>Circle CI</dd>
<dt>VCS</dt>
<dd>Git, GitHub</dd>
</dl>

## テストファーストでFizz Buzzを実装していく
まずは、テストを書いてテストが失敗することを確認してから実装を書いていきます。
Fizz Buzzのような簡単なプログラムでもストイックに一つ一つテストケースを追加していきました。

```C#:テストコード
[Test]
public void _Fizzが取得できる()
{
    var i = FizzBuzz.GetNum();
    Assert.That(i.ElementAt(2), Is.EqualTo("Fizz"));
}

[Test]
public void _Buzzが取得できる()
{
    var i = FizzBuzz.GetNum();
    Assert.That(i.ElementAt(4), Is.EqualTo("Buzz"));
}
[Test]
public void _FizzBuzzが取得できる()
{
    var i = FizzBuzz.GetNum();
    Assert.That(i.ElementAt(14), Is.EqualTo("FizzBuzz"));
}
```

## リファクタリング中にバグを発見
黄金の回転にしたがいテストがパスしてからリファクタリングをしようとしました。

### リファクタリング前
まず下記のコードは、テストをパスしています。　
※ リファクタリングに関係のない部分は省略しています。

```csharp:リファクタリング前
var i = 0;
while(i++<100)
{
  // Fizz Buzzの実装
}
```

### リファクタリング後(失敗)
`while` より `for` のほうがわかりやすいと思い下記のように書き換えました。

```csharp:間違ったコード
for(var i=0;i<100;i++) // 1から列挙しないといけないのに、0から列挙してしまってる。
{
  // Fizz Buzzの実装
}
```

簡単な書き換えだと思ったので振る舞いは変わらないと思いましたが、
テストを実行すると、テストが失敗したので変更したコードにバグがあることに即座に気づけました。

![test_failed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416392/ae767b47-cd62-e257-6cab-ecd2a25712fa.png)

### リファクタリング後(成功)

```csharp:リファクタリングが成功したコード
for(var i=1;i<=100;i++)
{
  // Fizz Buzzの実装
}
```

再度、テストを実行してバグが修正されたことを確認できました。

![test_passed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416392/62857c50-ed48-d044-a205-e12d17d83cca.png)


## CIでのビルド
ローカルでテストを実行した結果は、オールグリーンでしたが、GitHubにプッシュしたところCIでのビルドが失敗してしまいました。

![CircleCIでビルド失敗を検出](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416392/85bc409e-8c7d-60d1-5190-10eae72a1407.png)


原因を調べたところ、メソッド名で、ひらがなや漢字を使っているにも関わらず、`UTF-8`ではなく `Shift-JIS`で保存されていることが原因でした。
このようにローカルの環境だけでは、わからない問題も、CIで検知できました。

## 実行可能形式にする
テストコードから、Fizz Buzzの仕様を満たしていることを確認できたので、実行可能なコードを追加して完成です。

```csharp:エントリポイント
static void Main(string[] args)
{
    foreach(var i in FizzBuzz.GetNum())
    {
        Console.WriteLine(i);
    }
}
```

もし、テストファーストをせず最初から実行可能にしていたら副作用によりテストできないコードになっていたことでしょう。

## まとめ
私は、自分が思っているほど完璧ではなくミスをしてしまうということを改めて実感しました。
Fizz Buzzという単純な課題においても、TDDとCIの有用性を示せたと思います。

## 参考にした情報
* [[DO03] 50 分でわかるテスト駆動開発](https://www.slideshare.net/decode2017/do03-50)
* [NUnit と .NET Core による単体テスト C#](https://docs.microsoft.com/ja-jp/dotnet/core/testing/unit-testing-with-nunit)
Lambdaを使ってAmazon SNSからメールを飛ばしてみた

# なりゆき
lambdaでSNS叩いてメール送りたいんじゃ～～
~~今時メールかよ・・・と思いつつ~~

# 設定方法

### SNSトピック作成
[SNSトピック作成](https://ap-northeast-1.console.aws.amazon.com/sns/v3/home?region=ap-northeast-1#/create-topic)ページを開き、*名前*を入力後にトピックの作成を押下する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299739/98f46cc2-518d-624b-c907-b5417cb9bcc6.png)

### サブスクリプション作成
サブスクリプションの作成を押下する。
**※次の画面でARNを選択するので覚えておくこと。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299739/c1d8dcfc-cd97-4a73-8a61-b36047439ea0.png)


下記入力項目を入力し、サブスクリプションの作成を押下する。

|トピックARN|プロトコル|エンドポイント|
|:---|:---|:---|
|先ほどのARN|Eメール|受信メールアドレス|
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299739/efa5013e-eeb2-dfeb-8191-49a7e0fd5f44.png)

### サブスクリプション承認
エンドポイントに指定したメールアドレスに確認メールが送られてくるので、
**Confirm subscription**を押下する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299739/bc633c5d-fd66-8993-7b12-75f4e7ef6f69.png)

承認完了メッセージが表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299739/b1a5cd90-8984-b8fd-df97-03f675701a11.png)

ステータスが**保留中**から**確認済み**になっていることを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299739/f0600da0-386a-de05-f226-c4644a9e02c1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299739/1a629008-2ffb-914b-6edc-099596b68a41.png)

### Lambda関数作成
[Lambda関数作成ウィザード](https://ap-northeast-1.console.aws.amazon.com/lambda/home?region=ap-northeast-1#/create)を開く。

|関数名|ランタイム|実行ロール|ロール名|ポリシーテンプレート|
|:---|:---|:---|:---|:---|
|SendMail|Python3.7|AWSポリシーテンプレートから新しいロールを作成|SendMailUsingSNS|Amazon SNS 発行ポリシー|

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299739/cca74b4f-ebdd-55c9-24ee-6ba2ca27162d.png)

コードを入力して保存ボタンを押下する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299739/c217f5a1-4380-5eba-fb07-ea88eb109fd9.png)

# コード
**※TOPIC_ARNは各自のARNを入力**

``` lambda_function.py
import boto3

def lambda_handler(event, context):
    client = boto3.client('sns')

    TOPIC_ARN = 'arn:aws:sns:*:*:*'     
    msg = 'Pythonからの\nテストメール'
    subject = 'ててて！ててて！て～て～♪'
     
    response = client.publish(
        TopicArn = TOPIC_ARN,
        Message = msg,
        Subject = subject
    )
     
    return response
```

# 終わり
あとは適当にトリガーを設定したらメールが飛びます。
lambdaの中で色々と呼び出して処理した結果をメールに添付することもできます。

# 参考情報
boto3公式ドキュメント
[client.publish](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sns.html#SNS.Client.publish1)
クラスメソッドさん
[boto3を使ってAmazon SNSへpublishしてみた](https://dev.classmethod.jp/cloud/publish_to_sns_using_boto3/)
Leetcode #252: Meeting Rooms

```swift
func canAttendMeetings(_ intervals: [[Int]]) -> Bool {
    let intervals = intervals.sorted { $0[0] < $1[0] }
    for i in stride(from: 1, to: intervals.count, by: 1) {
        if intervals[i][0] < intervals[i-1][1] {
            return false
        }
    }
    return true
}
```
git stash コマンドは君が思ってる以上に便利だぞ

気が向いたら追記していきます

# 作業中のファイルを一旦退避したい

```sh
git stash
```

ファイルがHEADの状態（最新のコミットの状態）に書き換わります
git管理されていないファイルは退避されません

# 退避したファイルを元に戻したい

```sh
git stash pop
```

# git管理されていないファイルも含めて退避したい

```sh
git stash -u
```

# 退避したstashの一覧を確認したい

```sh
git stash list
```

退避の名前は、HEADコミットのコメントになっています

# 退避したstashの一覧を詳しく確認したい

```sh
git stash list -p
```

ファイル差分まで含めて表示されます

# 名前をつけて退避したい

```sh
git stash save 名前
```

`git stash list` したときにこの名前で表示されます
名前は日本語でもオーケーです
以下のように表示されるようになります

```
stash@{0}: On <branch>: 名前
```

# 一部のファイルだけを退避したい

```sh
git stash —- filename
```

`-` を２つです。その後にスペースを入れ、退避したいファイル名またはディレクトリ名を書きます（いくつでも）

# 名前をつけて、一部のファイルだけを退避したい

```sh
git stash push -m 名前 —- filename
```

`push` というサブコマンドを使います
実はここまで出てきた多くのコマンドは `git stash push -***` の短縮系

# 退避したstashを削除したい

```sh
git stash drop stash@{xxx}
```

xxxには、 `git stash list` で表示される番号を指定
Node-red入門×IoT

全体記事参照：「Node-RED超入門」
https://qiita.com/makaishi2/items/5c7b1b6a72b6938cf3d2

### 前提

IBM Cloudのアカウント登録とIBM Cloud上でNode-REDのサービスを作るところまで
その前の手順については、他の資料を参考として下さい。

IBM Cloudアカウント登録
https://qiita.com/KenichiSekine/items/249d2ff691b6565fb127

###概要
Node-REDはIBM英国Hursley研究所のメンバーを中心に開発されています。Bluemix（IBM社が提供するPaaS）でしか動かないものだと勘違いされている方もいらっしゃいますが、Node-RED自体はオープンソースソフトウェアであり、Node.jsが動く環境であればどこでも動かせます。

Bluemixなどのクラウド上で動かすこともできれば、ローカルのPCやRaspberry Piでも動作させることが可能です。後述しますがNode-REDはBLE（Bluetooth Low Energy）や各種センサープロトコルに対応したプラグインが豊富で、よりエッジ側（IoT的に言うとThings、つまりモノに近い方）で動作させるのも面白いです。

インストール
npm install
前述の通りNode.jsが動く環境であれば動作します。

```
$ npm i node-red
$ node node_modules/node-red/red.js
```

### 画面は大きく以下の領域に分かれています。

パレット
フローエディタ
コンソール
デプロイボタン

###①パレット

Node-REDでは、処理の単位それぞれがアイコンになっており、それらは「ノード」という名前で呼ばれています。
「パレット」はNode-REDで利用可能な「ノード」の一覧表です。
Node-REDでは、ノードを追加で増やすこともできます。その場合、パレットに表示されるノードの数も増えることになります。

###②フローエディタ

Node-REDのノードは1つないし複数の入力と出力を持ちます。(片方しかないものもあります)ノード間を線で連結することで、「あるノードの出力を別のノードの入力とする」ことが可能です。このようなノード間のつながりを編集するのが、画面中央のフローエディタです。
また、ノードは通常、各ノード固有の属性を持っています。ノードの属性もまた、フローエディタ上で設定する(より正確にいうと、フローエディタ上のノードをダブルクリックして編集・設定する)ことになります。

###③コンソール

コンソールは、情報を表示する画面ですが、２つのタブを持っていて、それぞれ別の意味があります。
まず、左側の「情報」タブですが、フローエディタ上で選ばれているノードなどオブジェクトの属性、ヘルプ文書などを表示する画面となっています。
右側の「デバッグ」タブはデバッグ情報を表示する画面です。Node-REDではデバッグ情報の出力も、デバック用のノードを経由して行われます。デバッグノードの送られたメッセージがこの画面から出力されることになります。

###④デプロイボタン

画面領域ではないのですが、重要な要素なので説明します。画面上の「デプロイ」の領域をクリックすると、フローエディタ上の変更が保存され、修正が有効になります。

###Node-REDでの開発手順
Node-REDでの開発は、次のような手順で行われることになります。

必要なノードをパレットからフローエディタにドラッグアンドドロップで生成する
フローエディタ上で、ノード間を線で結んで処理のつながりを表現する
各ノードの属性を設定する
デプロイボタンでデプロイを行い、変更を保存する
テストの実施
最初のNode-REDアプリ
それでは、以上のことを念頭において、最初の簡単なNode-REDアプリを作ってみたいと思います。
内容としては、
「Web上のイメージデータを入力としてWatson VRで画像認識を行い結果をデバッグ画面に表示する」
ものとします。

###事前準備
アプリで使うWatson VRのサービスと、そのサービスの資格情報(VRの場合はAPI Key)を事前に作成、入手する必要があります。
具体的な手順については、IBM Cloudの基本 -サービスの作成から資格情報の取得まで-を参照して下さい。

###ノードの配置

パレットから以下のノードをフローエディタにドラックアンドドロップします。
「入力」から「inject」
「出力」から「debug」
「機能」から「function」
「IBM Watson」から「Visual Recognition」
フローエディタに配置すると、injectノードはtimestampに、debugノードはmsg.payloadに名称が変わりますので、注意して下さい。

###実践編

node-red-dashboardでチャート表示IoTアプリ作成
https://qiita.com/kuraoka/items/2e14bc2fefb9b0183cc7

Node-REDにダッシュボードを追加してセンサーデータを可視化する
https://qiita.com/takeyan/items/fff5e8d64da25220a0c0

ノードREDライブラリ
https://flows.nodered.org/?num_pages=1

Node-RED事始め
https://qiita.com/joeartsea/items/93e8483a31292067c654
gitのエイリアス設定方法を端的にまとめた

git コマンドのエイリアス（別名）に関する以下のコマンドをまとめました

- エイリアスの設定
- エイリアスの削除
- エイリアスの一覧を見る

以降では、`git status` を `git st` と打てるようにするエイリアスの設定として書いています。
適宜読み替えてください

# マシン全体に反映

`/etc/gitconfig` に追記される

```sh
# 設定
$ git config --system alias.st status

# 削除
$ git config --system --unset alias.st

# 一覧
$ git config --system —-list | grep ^alias\.
```

# ユーザに反映

`~/.gitconfig` に追記される。マシン設定より優先

```sh
# 設定
$ git config --global alias.st status

# 削除
$ git config --global --unset alias.st

# 一覧
$ git config --global --list | grep ^alias\.
```


# リポジトリだけに反映

`.git/config` に追記される。ユーザ設定より優先

```sh
# 設定
$ git config alias.st status

# 削除
$ git config --unset alias.st

# 一覧
$ git config --list | grep ^alias\.
```
WordPressで記事のソートUI

いつもお世話になっております。

Wordpressの記事一覧画面で、見出し部分をクリックして記事をソートをするUIの実装を考えています。
仕様は以下のような感じです。

・WordPressの管理画面の投稿一覧のようなイメージ
・現在のソートキー項目に▼を表示
・二度押しで降順、昇順変更
・並び替え後、ページャーでページ遷移可能

ソートボタンを実装するケースは見つけましたが、現在のソートキーも表示するような例は見つけることができませんでした。

皆さまお知恵を拝借願えませんでしょうか。
javascript~ヘルスケアwebサービスを自分で作る医者の日記~

```
getRandomImage() {
      const images = [
        'img/seven.png',
        'img/bell.png',
        'img/cherry.png',
      ];
      return images[Math.floor(Math.random() * images.length)]
    }

    spin() {
      this.img.src = this.getRandomImage();
    }
  }
```

return は関数自体の返り値を返すの意味がわからなかったが、わかってきた。

```
this.img.src = this.getRandomImage();
```
上のgetRandomImage();そのものが、配列の要素つまり画像ファイル等に置き換わる

それによって、代入が可能になる、ということか。

もしreturnがなければどうなるのか？？？
Leetcode #350: Intersection of Two Arrays

Solution 1: Hash table

```swift
func intersect(_ nums1: [Int], _ nums2: [Int]) -> [Int] {
    var dict = [Int: Int]()
    for num in nums1 {
        if let value = dict[num] {
            dict[num] = value + 1
        } else {
            dict[num] = 1
        }
    }
    var answer = [Int]()
    for num in nums2 {
        if let value = dict[num] {
            answer.append(num)
            dict[num] = value - 1
            if value == 1 {
                dict.removeValue(forKey: num)
            }
        }
    }
    return answer
}
```

Solution 2: Two-pointer

```swift
func intersect(_ nums1: [Int], _ nums2: [Int]) -> [Int] {
    let nums1 = nums1.sorted()
    let nums2 = nums2.sorted()
    var answer = [Int]()
    var i = 0
    var j = 0
    while i < nums1.count && j < nums2.count {
        if nums1[i] == nums2[j] {
            answer.append(nums1[i])
            i += 1
            j += 1
        } else if nums1[i] > nums2[j] {
            j += 1
        } else {
            i += 1
        }
    }
    return answer
}
```
Leetcode #704: Binary Search

```swift
func search(_ nums: [Int], _ target: Int) -> Int {
    var start = 0
    var end = nums.count - 1
    while start <= end {
        let mid = start + (end - start) / 2
        if nums[mid] == target {
            return mid
        } else if nums[mid] > target {
            end = mid - 1
        } else {
            start = mid + 1
        }
    }
    return -1
}
```
Leetcode #788: Rotated Digits

```swift
func rotatedDigits(_ N: Int) -> Int {
    var count = 0
    for i in stride(from: 1, through: N, by: 1) {
        var num = i
        var validCount = 0
        while num > 1 {
            let digit = num % 10
            num /= 10
            if digit == 0 || digit == 1 || digit == 8 {
                continue
            }
            if digit == 2 || digit == 5 || digit == 6 || digit == 9 {
                validCount += 1
            } else {
                validCount = 0
                break
            }
        }
        if validCount > 0 {
            count += 1
        }
    }
    return count
}
```
AtCoder Beginner Contest 007 D - 禁止された数字

# AtCoder Beginner Contest 007 D - 禁止された数字

桁DPというらしい。

https://abc007.contest.atcoder.jp/tasks/abc007_4

ある数以下の数で条件を満たす数が何個あるか調べる関数funcを作れば、func(b)-func(a-1)が答えとなる。そのため、そうした関数を作れば良い。

例えば、556で考える。桁を左から順番にみていって、最初のループでは0~500の中に条件を満たす数が何個あるか考える。400~499は全部条件を満たす。他の数は余事象を取れば良いので、0~99、100~199、201~299、301~399の4つの範囲に関してはそれぞれ$10^2-8^2$個の条件を満たす数があるとわかる。残りの500~556について何個条件を満たす数があるかは次のループに回す。

ただ、ある桁の数字が4か9だった場合は、本来だったら後に回すはずであった数（例えば、468だったら400~468の69個）は必ず4, 9を含む。なので、それらの69個を全て加えてしまい、ループを抜ける。


```python

def dfs(s):
    flag=0
    s = str(s)
    ret=0
    for i in range(len(s)):
        if flag:
            break
        d=len(s)-i-1
        keta=int(s[i])
        if keta in [4,9]:
            ret+=int(s[i:])-keta*(10**d)+1
            flag=1
            print(ret)
        if 5<=keta:
            ret+=(keta-1)*((10**d)-(8**d))
            ret+=10**d
        else:
            ret+=keta*((10**d)-(8**d))
    return ret

def c(a, b):
    return dfs(b)-dfs(a-1)

```
【上級編】micro:bitで戦車を操縦する

## はじめに
この記事はmicro:bitで戦車を操縦するための開発手順を初級・中級・上級に分けて紹介しています．使用機材や開発ステップは[まとめ]()で紹介しています．

＊まとめの記事を読んではじめられた方は，戦車の車体を制作してから，この記事を読むと良いでしょう！
#### 前回まで
- [序章](https://qiita.com/kikpond15/items/d6ca1e1372ba787ab08b)
- [初級編はこちら](https://qiita.com/kikpond15/items/b938f3165208aa3444b0)
- [中級編はこちら](https://qiita.com/kikpond15/items/d2e27f4ff9c57cc3f8b7)

## 上級編
[中級編](https://qiita.com/kikpond15/items/d2e27f4ff9c57cc3f8b7)では，ボタンを使って無線通信で前進・後退させるプログラムを作りました．上級編では，ボタン＋加速度センサーを使って戦車を前後左右自由に操縦出来るようにプログラムを作ってみたいと思います．

### 送信側
まずは，[中級編](https://qiita.com/kikpond15/items/d2e27f4ff9c57cc3f8b7)で作ったプログラムを元に，加速度センサーをどうやって使うかみてみましょう．加速度センサーのブロックは，メニューの「入力」に入っています．センサーと一緒にメニューの「論理」から「0　＜　0」と書かれたブロックを出してみましょう．
![スクリーンショット 2019-08-02 20.37.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191122/9ad962f3-690b-855a-c556-c3fb6ba5f899.png)
この二つのブロックを合体させ，数字や文字をこのように変えます．![スクリーンショット 2019-08-02 20.42.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191122/b8a570e5-21c2-08b9-d6e0-fef5ca98552b.png)

これでこのブロックは，**「加速度Y(縦方向の傾き)が-700よりも小さくなったとき」**という条件になりました．加速度の傾きは-1023〜1023の間で変化し，micro:bitを前に倒すとYの傾きはマイナス側に大きくなり，後ろ側に倒すとプラス側に大きくなります．横方向に倒すと同じくXの傾きが変化します．

この条件を使って，micro:bitを前に倒したときに"forward"を送り，後ろに倒したときに"back"を送るプログラムを作成します．そして，右旋回，左旋回はAボタン，Bボタンを押したときに条件を変更します．
![スクリーンショット 2019-08-02 20.17.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191122/40d648af-4229-be17-242c-b840e87a69da.png)

ついでに倒したときの表示も付け加えてみました．これでちゃんと条件式の中に入っているか確認することが出来ます．"stop"を送るときの条件は，**「傾きが-700よりも大きく，かつ傾きが700よりも小さいとき」**となっています．このように条件式自体を**「かつ」**というブロックで合体させることもできます．
"cw"と"ccw"は時計周り，反時計周りの意味です．

### 受信側
受信側のプログラムも[中級編](https://qiita.com/kikpond15/items/d2e27f4ff9c57cc3f8b7)のプログラムを元に改良していきます．![スクリーンショット 2019-08-02 21.11.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191122/00094a2a-ad0f-2c79-b021-ccabd3b41354.png)
![スクリーンショット 2019-08-02 21.12.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191122/430d7ffb-7779-1f1c-1c90-0cf1daae5209.png)

少し長いですが，こんな感じで作ってみましょう．旋回するときのタイヤの回転方向を考えてみると，タイヤは左右で逆方向に回転しますね．前進・後退のときと旋回のときで，デジタル出力する端子が違っているのが確認できると思います．

## チャレンジ
それでは，最後のチャレンジです．最後は左右の旋回を**左右にカーブ**するように変更してみましょう．旋回は，その場でタイヤを左右逆方向に回転させることで車体の角度を変えることが出来ます．それに対しカーブは，左右のタイヤの回転方向は同じですが，回転するスピードを左右で別にする事で曲がる事が出来ます．回転スピードを制御しているプログラムはどこでしょうか？また，左右のスピードを変えるためには回路も少し変更する必要がありますね．[回路図](https://qiita.com/kikpond15/items/f4d37de5061c0b8a9e21)や以前のプログラムを見直して頑張ってみて下さい！


## 参考・関連

- [序章](https://qiita.com/kikpond15/items/d6ca1e1372ba787ab08b)
- [初級編はこちら](https://qiita.com/kikpond15/items/b938f3165208aa3444b0)
- [中級編はこちら](https://qiita.com/kikpond15/items/d2e27f4ff9c57cc3f8b7)
- [回路図はこちら](https://qiita.com/kikpond15/items/f4d37de5061c0b8a9e21)
JavaのScannerはどれほど遅いのか？

こちらでJavaのScannerが非常に遅いと言う話題が出たので、どれぐらい遅いか測ったので簡単に報告です。

[Python, Java, C++の速度比較](https://qiita.com/Lily0727K/items/26d3e68d66a6a641b010#comment-619415eee26a2abcb767)

##結果

|data数=100万 |実行時間| 
|:----------|:------------|
|JavaのScanner|714 msec|
|自前Scanner|24 msec|
|倍率|29.75|

自前の簡素なScannerに比べて、JavaのScannerは、だいたい３０倍近い時間がかかってます。
競技プログラミングではSannerは使わない方が良さそうですね。

以下に比較に使ったコードを載せます。

#JavaのScannerをそのまま使った版

```java
import java.util.*;
import java.io.*;
import java.util.stream.*;

public class ScannerTest {
    public static void main(String[] args) {
        long t0 = System.currentTimeMillis();
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] d = new int[n];
        for (int i = 0; i < n; i++) {
            d[i] = sc.nextInt();
        }
        long t1 = System.currentTimeMillis();
        System.out.println("n = " + n );
        System.out.println((t1-t0) + " msec");
        int sum = IntStream.of(d).sum();
        System.out.println("sum = " + sum);
    }
}
```

##自前のなんちゃってint値読み込みScanner版

```java
import java.util.*;
import java.io.*;
import java.util.stream.*;

public class ScannerTest3 {
    static class MyScanner {
        byte[] bytes;
        int pos = 0;
        int len;
        InputStream inputStream;
        MyScanner(InputStream is){
            try{
                inputStream = is;
                bytes = new byte[1024];
                len = Math.max(0,inputStream.read(bytes));
                pos = 0;
                return;
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        private byte getNextByte() throws IOException {//throws ArrayIndexOutOfBoundsException
            if( pos >= len ){
                len = Math.max(0,inputStream.read(bytes));
                pos = 0;
            }
            byte result = bytes[pos++];
            return result;
        }
        int nextInt() throws IOException {
            int result = 0;
            byte v;
            while(true){
                v = getNextByte();
                if( v != ' ' && v != '\n' && v != '\r'){
                    break;
                }
            }
            while(true){
                if( v == ' ' || v == '\n' || v == '\r' ){
                    break;
                }
                result *= 10;
                result += (int)v - (int)'0';
                v = getNextByte();
            }
            return result;
        }
    }
    public static void main(String[] args) throws Exception{
        long t0 = System.currentTimeMillis();
        MyScanner sc = new MyScanner(System.in);
        int n = sc.nextInt();
        int[] d = new int[n];
        for (int i = 0; i < n; i++) {
            d[i] = sc.nextInt();
        }
        long t1 = System.currentTimeMillis();
        System.out.println("n = " + n );
        System.out.println((t1-t0) + " msec");
        int sum = IntStream.of(d).sum();
        System.out.println("sum = " + sum);
    }
}
```
[Java] `for文`内で宣言した変数を`for文ブロック`の外で使えない件

```java
  int classNum = 3; // クラス数
  int stuNum = 4; // 生徒数

  for (int i = 1; i <= classNum; i++)
  { // 3回繰り返す
      System.out.println(i + "クラス目");

      for (int j = 1; j <= stuNum; j++)
      { // 4回繰り返す
          System.out.print(j + "人目の成績を入力してください: ");
          sum += input.nextInt();
          int allStuNum = i * j;  ← こ↑こ↓
          avg = sum / allStuNum;  ← こ↑こ↓
      }
  }
```

12行目`int allStuNum = i * j;`,13行目`avg = sum / allStuNum;`をforブロックの外で使おうとすると
「変数が見つからない」エラーになるって話

![](https://drive.google.com/uc?export=view&id=1rcPp9sEkW4QA8VYiAjeQx5jeXRZiGD__)

## 所感
多分常識過ぎて、だからどんな入門書にも書いてないポイントなんでしょうけど、
知ってないと自分みたいに for文内の変数 `i`,`j`,`allStuNum`をいざ再利用しようとした時、困惑することになる．
Android で撮ったカメラ画像をKinesis Video Stream でプレビューする



https://docs.aws.amazon.com/ja_jp/kinesisvideostreams/latest/dg/producer-sdk-android.html
こちらをベース実施したところ、10分くらいでできました。一応メモ。

# 流れ
* Cognito のUser Poolを作成
* Cognito のID Pool を作成
    * Kinesis Video Streamのロールをアタッチ
* githubから、AndroidのサンプルコードをClone
    * AmazonKinesisVideoDemoApp をAndroid StudioでOpenする。
* awsconfiguration.json でCognitoのID情報を入力
* 下記の補足の箇所を修正
* Androidのサンプルアプリを実行
    * アカウントを新規作成
    * キャプチャ開始
* Kinesis Video Stream のMedia previewを確認

### 補足
Androidのコードで、リージョン情報の更新が必要

``` java:KinesisVideoDemoApp.java
    // public static Regions KINESIS_VIDEO_REGION = Regions.US_WEST_2;
    public static Regions KINESIS_VIDEO_REGION = Regions.AP_NORTHEAST_1;
```
pandas データを可視化

#グラフ化したい！！
## 円グラフを作成したい

必要なライブラリーをimportしよう！！

```python
import matplotlib as mpl
import matplotlib.pyplot as plt
```

おそらく出来てない、、、。強引に作成してみた。是非時間のある時に学習して綺麗にしたい。

```python
# 特徴量について調査して件数を確認した
df0 = df[df['Species'].isin([0])]
df0c = df0.count()
print(df0c)
df1 = df[df['Species'].isin([1])]
df1c = df1.count()
print(df1c)
df2 = df[df['Species'].isin([2])]
df2c = df2.count()
print(df2c)

# x = ['setosa', 'versicolor', 'virginica']　# ラベルの名前を直接入れる
x = list(iris.target_names) # 問１の内容を真似た
y = np.array([50,  50, 50]) # 50件ずつ存在しているので強引に入れた

# 下記は良くわからないけど、消すと年グラフが表示されなくなるので残す。
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.pie(y, labels=x, autopct="%1.1f%%")

plt.show()
```


## 箱ひげ図
https://qiita.com/y__sama/items/9676f148a66c16d8f47c

こちらを参考にした。これで列を指定して箱ひげ図が書けた。

```python
df.sepal_length.plot.box()
```

## バイオリン図
https://stats.biopapyrus.jp/python/violinplot.html

色々調査したけど、上記のやり方が一番分かりやすかったし、移植しやすかった。


## 箱ひげ図とバイオリン図の違い
http://yyhhyy.hatenablog.com/entry/2016/08/20/220000
箱ひげ図はデータの存在範囲が分かりやすく、最大値や最小値が分かる。ただ、バラツキが分かりにくい。
バイオリン図はどの値が多いかや少ないかが視覚的に分かりやすいという特徴がある。
【Sinatra】ルーティング

こちらの続きで、
https://qiita.com/gussan-dayo/items/00b7b5a84cb67c8376ae
ルーティングにいて見ていきます。

※参考
http://sinatrarb.com/intro.html

#Routes

In Sinatra, a route is an HTTP method paired with a URL-matching pattern. Each route is associated with a block:

Sinatraでは、ルートはURLマッチングパターンとペアのHTTPメソッドです。それぞれのルートはブロックと結び付けられています。と書かれています。


```.rb
get '/' do
  .. show something ..
end

post '/' do
  .. create something ..
end

put '/' do
  .. replace something ..
end

patch '/' do
  .. modify something ..
end

delete '/' do
  .. annihilate something ..
end

options '/' do
  .. appease something ..
end

link '/' do
  .. affiliate something ..
end

unlink '/' do
  .. separate something ..
end
```

最初にマッチしたルートの情報が呼び出されます。

例えば、

```myapp.rb
require 'sinatra'

get '/' do
  'Hello world!'
end
```
では　http://localhost:4567/　
を開くと画面にHello world!と表示されます。

##ルート情報の追記

ルート情報を追記してみます。

```myapp.rb
# myapp.rb
require 'sinatra'

get '/' do
  'Hello world!'
end

get '/hello/' do
    'Hello '
end
```
次に、http://localhost:4567/hello 
にアクセスしてみます。
おっとエラーが出ました。

![スクリーンショット (52).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203857/900c7f67-4935-81d7-6a6c-086a7d13ba5c.png)

http://localhost:4567/hello/
のように、helloの後に　/　が抜けていたのが原因でした。

次に、

```myapp.rb
# myapp.rb
require 'sinatra'

get '/' do
  'Hello world!'
end

get '/hello' do
    'Hello '
end
```

として、サーバをもう一度立ち上げ直し、http://localhost:4567/hello
に接続すると、うまく接続出来ました。

##名前付きルート

名前付きのルート情報について見てみましょう。


``` myapp.rb
require 'sinatra'

get '/' do
  'Hello world!'
end

get '/hello/:name' do
    "Hello #{params['name']}!"
end
```

```get '/hello/:name' do ```のように[:変数]とすることで、URLに任意の変数を持たせることが出来ます。
paramsハッシュでnameを取得することが出来ます。

http://localhost:4567/hello/ruby
に接続すると、nameにrubyという文言が入ります。

また、こう記述することも出来ます。

``` myapp.rb
require 'sinatra'

get '/' do
  'Hello world!'
end

get '/hello/:name' do
    "Hello #{params['name']}!"
end

get '/hello2/:name2' do |n|
    "Hello #{n}!"
end
```
ここでは、新しくルート情報を追記しました。

繰り返し構文の変数を使用しても、ルートを表示出来るます。

##ワイルドカード
ワイルドカードもルーティングに含めることが出来ます。

``` myapp.rb
require 'sinatra'

get '/say/*/to/*' do
    # matches /say/hello/to/world
    params['splat'] # => ["hello", "world"]
end
  
get '/download/*.*' do
    # matches /download/path/to/file.xml
    params['splat'] # => ["path/to/file", "xml"]
end
```

こちらもparams['splat']でルート情報を取得することが出来ます。

正規表現にもマッチさせることもできます。

```myapp.rb
get /\/hello\/([\w]+)/ do
  "Hello, #{params['captures'].first}!"
end
```

こちらも繰り返し構文で表現することが出来ます。

```myapp.rb
get %r{/hello/([\w]+)} do |c|
  "Hello, #{c}!"
end
```

##まとめ
ルーティング用のファイル名っていまのところ何でも？良さそうです。
わくわくしますね～
Unity+XcodeでTestFlightへアップロードしようとしたときにはまった話

## はじめに
普通にビルドすればアップロードされると信じていたが、
悉くはじかれたのでそのときに上げられるようにした対策を残しておく

## 環境
- Xcode10.3
- Unity2018.2.20f1

## 起こった現象

~~```**ITMS-90428: Invalid Swift Support**~~
~~```~~
~~というエラーが返ってくるという報告が上がりました。~~
~~調べてみたところ、どうやらこの症状は様々な対処法があるようです。~~
~~下記に対処方法があるサイトを列挙しておきます。~~
~~- https://forums.developer.apple.com/message/342607#342607~~
~~- https://developer.apple.com/library/archive/qa/qa1881/_index.html~~
~~- https://stackoverflow.com/questions/53214530/invalid-swift-support-files-dont-match-xcode-10-1~~
~~- https://qiita.com/daikon/items/b2824649484f812fd62c~~
~~- https://stackoverflow.com/questions/32526526/invalid-swift-support-files-don-t-match?rq=1~~
~~・・・etc~~
~~さて今回私が1週間はまった内容はこのどのサイトの事象でもありませんでした。~~
~~結果からいいますと~~
~~XcodeのBuildSettingで~~
~~**EMBEDDED_CONTENT_CONTAINS_SWIFT**を**<font color="#FF0000">NO</font>**に変更するです。~~
~~下記にEMBEDDED_CONTENT_CONTAINS_SWIFTについて記載がありますが、端的に言うとビルド後に標準Swiftファイルを含めないようにする機能っ~~ぽいです。~~
~~https://kitoko552.hatenablog.com/entry/20160118/1453120577~~

~~そもそも怒られていたのがSwiftFolderがないとかdoes not matchだとか言われていたので、入れなければいいんじゃないの？が発端です。~~
~~上記の方法で一旦はアップロードできましたが、別のエラーが返ってこないかが心配ではあります。~~
~~アップロードするまでの方法を書きます。~~

2019/09/18更新
対応方法が違いました。
上記の方法でアップロードした場合iOS10,11でクラッシュするようになりました。
原因はSwift(今回はLineSDK)を使用しているのにSiwftSupport folderがなく動作できないことが原因のようでした。
(試しにSwiftを含めたipaは動作しました。)

最終的に成功した対応方法といたしましては
provisioningprofileを**Add-Hoc**から**App-Store**に変更するが正しい修正でした。
この修正で、ビルド時にSwiftSupoportフォルダが作成されて、正常に動作するようになります。
↓
懸念点としましては、容量がほぼ倍になること
2019/06から200MBまでならモバイル通信でダウンロードができるのでそれ以下にできれば・・・

この修正で提出が正常にできたため、一旦は事なきを得ました。
もし同現象で困っている方がいらっしゃいましたら一度この方法でお試しください。


```
[PostProcessBuild(任意の数値)]
public static void ChangeXcodeProject(BuildTarget buildTarget,string path)
{
    if(buildTarget != BuildTarget.iOS)
    {
        return;
    }
    // Xcodeのプロジェクト情報を取得します。
    var proj = new PBXProject();
    string projectPath =path+"foo.xcodeproj/bar.pbxproj"
    proj.ReadFromString(File.ReadAllText(projectPath));
    string targetGuid = proj.TargetGuidByName("foo");
    ~~
    略
    ~~
    // EMBEDDED_CONTENT_CONTAINS_SWIFTをYESにする
    {
        proj.SetBuildProperty(targetGuid, "EMBEDDED_CONTENT_CONTAINS_SWIFT", "NO");
    }
    //設定したデータを書きこむ
    File.WriteAllText(projPath, proj.WriteToString());
}
```

下記に色々やったことの手法をメモ書き程度ですが残しておきます。

- ipaファイルの中身を確認する
unzip < App name >.ipa

- zipコマンドでipa化する
zip -r < new app name >.ipa Payload < folder name >
*folder nameは任意

- MacOSでコピーした際に発生するDS_Storeファイルの削除
これがあると
ITMS-90430: Invalid Swift Support - The file .DS_Store doesn’t
がでるので削除する。
```
ls- a 
```
このコマンドで確認できる。
```
find . -name ".DS_Support" | xargs rm
```
これで特定のカレントディレクトリ以下のフォルダの中身を消せる
webarenaでubuntu

#概要

webarenaでubuntu18.04やってみた。


#入ってないコマンド(残念)

```
aptitude
ruby
java
node
php
apache
vsftpd
mysql
bind
sendmail
postfix
startx
```

#入ってるコマンド（ラッキー）

```
python
nano
ss
```

#コントロールパネルの「セキュリティグループ」の設定を使って、ポートを開放

```
tcp:22,22,ip4:自分のIPアドレス/32
tcp:80,80,ip4:0.0.0.0/0
```

#パッケージのサーチ

```
dpkg -l | grep hoge
apt-cache search hoge
```

#パッケージのインストール

```
sudo apt-get install hoge
```


以上。
Dockerで、すぐにDBを試せるdocker-compose.ymlを作ったよ

急にDBにアクセスして、SQLとか打ちたくなる時があるよね
(そんなことはないよね)

すぐにいろんなDBのコンテナを起動して、
試せる`docker-compose.yml`を作成したから、
よかったら、使ってみてね。

## docker-compose.yml

```:docker-compose.yml
version: '3'
services:
  mongo:
    image: mongo:4.1.13
    volumes:
      - ./mongo:/data/db
    ports:
      - "50011:27017"
    environment:
      MONGO_INITDB_DATABASE: sample_mongo
      MONGO_INITDB_ROOT_USERNAME: mongo
      MONGO_INITDB_ROOT_PASSWORD: mongo
  postgres:
    image: postgres:12
    volumes:
      - ./postgres:/var/lib/postgresql/data
    ports:
      - "50012:5432"
    environment:
      POSTGRES_DB: sample_postgres
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
  mysql:
    image: mysql:8.0.17
    volumes:
      - ./mysql:/var/lib/mysql
    ports:
      - "50013:3306"
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_DATABASE: sample_mysql
      MYSQL_ROOT_PASSWORD: mariadb
  mariadb:
    image: mariadb:10.4.7
    volumes:
      - ./mariadb:/var/lib/mysql
    ports:
      - "50014:3306"
    environment:
      MYSQL_DATABASE: sample_mariadb
      MYSQL_ROOT_PASSWORD: mariadb
```

## GitHub

https://github.com/tubutubumustard/database_docker.git

## 終わり

`mongo`は触ったことないから触ってみようかな
Google Cloud Next 19 in Tokyo

6月のAWS Summit続いてパブリッククラウドのイベント参加しました。
会社は"行くなら有給取って行け"とのことなので、私は8月30日のみの参加となりました。

# イベント概要

**Google Cloud Next 19 in Tokyo**

日程：2019年8月30日（火）～9月1日（木）
会場：ザ・プリンス パークタワー東京、東京プリンスホテル

会場は2箇所に分かれおり、会場間は徒歩もしくは無料シャトルバスでの移動となります。

##参加方法

事前に[公式ホームページ](https://cloud.withgoogle.com/next/tokyo)にて参加登録をします。
開催日の数日前にQRコード等が記載された受講票がPDFで届きます。
当日、印刷した受講表を持参して受付に提示します。
もしくは専用アプリをダウンロードしてQRコードを提示します。

##会場設備等

####ネット環境
会場専用のWi-Fiが用意されていました。
Expo会場が中心なのか、接続が切れる場所もありました。
会場内通路にはいくつかベンチ型の椅子と電源が用意されていましたので、ちょっとした仕事もできますが、たいへん混雑していました。

####飲食
Expo内を中心に飲み物が提供されています。
水やお茶、清涼飲料水、コーヒー等豊富な種類が用意されていましたが、お昼過ぎには水のみになっていました。
また、お昼時や夜の一部のセッションに参加するとお弁当が頂ける様です。


####Google Cloud認定資格取得者専用ラウンジ
Google Cloud認定資格取得者のみが利用できるスペースです。
ラウンジの入口で認定証の提示が必要になります。

ラウンジ内には専用Wi-Fiや椅子、電源、飲食物が用意されていたようです。
ラウンジ外の椅子はほぼ満員のため資格取得者にとっては有難い環境かと思います。

ノベルティとしてバックパックや認定バッジがもらえるようです。

私は資格を取得していないので利用できませんでした・・・。


####専用公式アプリ
スケジュールの更新や会場の変更、製品情報やその他イベントに関わる情報をリアルタイムで受け取ることができます。
イベント期間中の予約スケジュールの確認や、セッションへの参加時のQRコードの提示、参加セッションのアンケート回答等も行えます。


####Expo会場
最新のクラウド技術を体験できるGoogle Cloudのデモブースや、
クラウドを使って独自のサービスを展開するスポンサーブースが展開されています。
また、会場エリア内の2箇所では誰でも聴講可能なオープンセッションが実施されています。
Expo会場内では飲み物の配布スペースや、少しですが端末の充電設備もありました。

##基調講演・セッション
###基調講演
7月31日（水）および8月1日（木）午前に基調講演が実施されました。

- 4月に米国で開催されたGoogle Cloud Next '19で発表された
オンプレミスやマルチクラウド環境でアプリケーションを一元的に管理する「Anthos」や、
既存アプリケーションを容易にAnthosの環境へ変換できる「Migrate for Anthos（発表時の名称はAnthos Migrate）」の
ベータ版サービスの提供について

- 同じく4月のGoogle Cloud Next '19において2019年中の提供開始が発表されていた、
Microsoftに関する2つのマネージドサービス「Cloud SQL for Microsoft SQL Server」と
「Managed Service for Microsoft Active Directory」を近日中に日本で提供を開始

- サーバーレスプラットフォームの「Cloud Run」の提供を
東京、サウスカロライナ（米国）、ベルリンの3リージョンで新たに開始


###ブレイクアウトセッション
7月31日（水）および8月1日（木）午後にブレイクアウトセッションが実施されました。

1セッション40分程で様々なテーマについての講演が実施されています。
事前に公式HPから予約をすることで受講が可能です。
人気のセッションは早い時期から満席になるので、興味のあるセッションは早めに予約することをお勧めします。
予約をしていなくても席の埋まり具合によって当日の参加が可能ですが、
開演前に当日受講希望者の列に並ばなければならず、空き状況によっては参加できない可能性もあるのでやはり予約でお勧めです。

講演資料は後ほどアップロードされるとのことですが、どこにあるのかは現状不明。（YouTube・・・？）

私が参加して、参考になったのは以下のセッションです。

######Google Cloud ネットワーキングのすべて
- 大阪リージョンが開設されたことにより、日本国内でマルチリージョンを実現可能
可用性が99.9%→99.99%

- PrivateGoogleAccess
オンプレミス環境からGCPサービスへ、Cloud InterconnectやCloudVPN経由してPrivateIPで接続が可能

- Kuberbetesの不可分散がロードバランサーよりも効率的に
XサーバーにGitデプロイ環境を構築する

参考：
http://vdeep.net/git-push-deploy
http://wiwi.pw/blog/2.html

# Gitのインストール
Xサーバーには元々Gitバージョン1.8がインストールされていますので割愛。
バージョン2以上を使いたい場合は別途インストール作業が必要です。

#SSHでサーバーに接続しよう
Xサーバーのコントロールパネルから秘密鍵ペアを作成して、ローカルの任意の場所に保存しましょう。

# ssh config
```
Host xsrv
  HostName sv****.xserver.jp
  Port 10022
  User *******
  IdentityFile ~/.ssh/*******.key
  ServerAliveInterval 60
```
接続してみる

```
ssh xsrv
```
パスフレーズを聞かれるので入力すると繋がりました。
ただ、このままだとgit push 等するたびにパスフレーズの入力を求められ、
非常に面倒なので対策します。

```shell

eval `ssh-agent` #ssh-agent起動
ssh-add -k ~/.ssh/*******.key #秘密鍵のパスを指定
```
これで、エディタを再起動するまでは一回目の入力だけで、
通常通りgit pushができます。
【wordpress】GCPのwordpress with nginxのアップロード上限を増やすには、.htaccessではなくphpとnginxの設定を書き換える

## wordpressが無料で運用できるらしい
今やweb界のヒーロー村上さんの記事を読みました。
[1時間で出来る！最強のWordPress環境構築(永久無料)](https://qiita.com/ryuta69/items/dbb0db5cf7099b7a7cc4)
~~放置~~ 所有しているwordoressブログもサーバーを移行したい！無料で運用したい！GCP触ってみたい！ということで、サーバー移行を決めました。

村上さんの記事の通りに進め、問題なくサーバー構築はできました。
**既存ブログ移行にあたって、アップロード上限に引っ掛かり、ブログ移行ができない**罠にハマったので、備忘録として書いておきます。

## 前提
* 村上さんの記事に沿ってGCP上にwordpress環境を構築
    - [1時間で出来る！最強のWordPress環境構築(永久無料)](https://qiita.com/ryuta69/items/dbb0db5cf7099b7a7cc4)
* **「All-in-One WP Migration」**プラグインを用いて既存ブログのデータをエクスポート

## ハマったところ
<img width="704" alt="スクリーンショット 2019-08-02 19.45.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233332/8643e6b3-4dd5-53b2-1d7e-85275ae92b71.png">
**「All-in-One WP Migration」**プラグインから、エクスポートしたブログデータをインポートしようとしたところ、最大アップロードサイズが64MBまでとあり、アップロード上限を超えてしまっていました。

## 解決方法
php側, nginx側それぞれのアップロード上限を128MBに変更することで解決。

[GCPで建てたインスタンスのコンソール](https://console.cloud.google.com/compute/needsbilling?success_path=%2Fcompute%2Finstances%3Fhl%3Dja%26project%3Dco-links%26folder%26organizationId&project=co-links&folder&hl=ja&organizationId)から`SSHログイン`し、下記を追記します。

```
# php側のアップロード上限を変更
$ sudo vim /opt/bitnami/php/etc/php.ini
# 下記追記
; PHPが受けられるPOSTデータの上限を128MBに変更
post_max_size = 128M
; アップロードファイル上限を128MBに変更
upload_max_filesize = 128M

# nginx側のアップロード上限を128MBに変更
$ sudo vim /opt/bitnami/apps/wordpress/conf/nginx-app.conf
# ファイルに追記
client_max_body_size 128M;

# php-fpm再起動
sudo /opt/bitnami/ctlscript.sh restart php-fpm

# nginx再起動
sudo /opt/bitnami/ctlscript.sh restart nginx
```

## ポイント
多くのwordpressに関する設定周りの記事に書かれている、`.htaccess`は、**apacheに関する設定を記載するファイル**です。
参考：
[.htaccess ファイルとは何か/その使い方](https://httpd.apache.org/docs/2.4/ja/howto/htaccess.html)

今回インストールしているwordpressは、「wordpress with **nginx** and ssl certified by bitnami」 であり、**webサーバーにnginxを採用していますので、.htacessファイルに設定を記載しても効きません。**
nginxの設定ファイルは `/opt/bitnami/apps/wordpress/conf/nginx-app.conf`にあるようです。

## まとめ
nginx側とphp側それぞれでアップロード上限を設定し直すことで、無事ブログの移行を完了することができました。
はじめ、`.htaccess`にそれらの設定を記載していたのですが、[.htaccess ファイルとは何か/その使い方](https://httpd.apache.org/docs/2.4/ja/howto/htaccess.html)を読んで、思い至りました。
勉強になりました。

間違いなどありましたら、コメント欄か[twitter](https://twitter.com/MuggyTeaa)でお知らせ頂けたら嬉しいです〜
勉強用にコンソール時計を作った

一定時間間隔で実行するプログラムの書き方を学ぶために作ってみました。

```clock.py
import time
import threading
import datetime


def timekeep():  # インターバル用関数
    time.sleep(1)  # 毎秒更新


def get_today():  # 時間取得

    today = datetime.datetime.today()
    value = (today.year, today.month, today.day,
             today.hour, today.minute, today.second)

    return value


def clock():  # 時計本体
    test_tuple = get_today()
    print("\r%s" % str(test_tuple), end='')  # 出力を上書きする


funcs = [timekeep, clock]  # 関数リスト
threads = []
current_time = time.time()

while(True):  # 無限ループ。funcsに関して並行処理。timekeep関数終了時までclock関数は実行されない
    for func in funcs:
        t = threading.Thread(target=func)
        t.start()
        threads.append(t)
    for t in threads:
        t.join()

```

以上
python 2.7.x を pyenv でインストールした時にエラーが出た場合の対処

## 状況
macOS Mojave で pyenv を使って python2.7.x をインストールした時に下記のエラーが出た場合の対処方法。

```
Installing Python-2.7.16...
python-build: use readline from homebrew
ERROR: The Python zlib extension was not compiled. Missing the zlib?

Please consult to the Wiki page to fix the problem.
https://github.com/pyenv/pyenv/wiki/Common-build-problems


BUILD FAILED (OS X 10.14.6 using python-build 20180424)

Inspect or clean up the working tree at /var/folders/ml/r0_f1xbn5yl2fwql2wzczcf80000gn/T/python-build.20190802192417.48871
Results logged to /var/folders/ml/r0_f1xbn5yl2fwql2wzczcf80000gn/T/python-build.20190802192417.48871.log

...

```

## 参考

- https://github.com/pyenv/pyenv/wiki/Common-build-problems


## 解決方法

```
$ brew install readline xz
$ sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /
```
pkg ファイルのバージョンは macOS のバージョンに合わせて読みかえる必要があります。また、最新の情報については参考 URL を参照する必要があります。
Jenkinsで画面の背景に色をつける

# やりたいこと
jenkins画面の背景に色をつけるぞ！

# 設定の手順
### Jenkinsの管理 > グローバルセキュリティの設定

マークアップ記法を↓こうする。
![変更前.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295558/b03e0fd9-e070-9d3c-6ea3-723a22efed13.jpeg)
↓↓↓
![変更後★.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295558/7c2f44ef-9b0e-a027-859e-792e36d7c2b3.jpeg)



### Jenkinsの管理 > システムの設定 画面

システムメッセージに↓の内容を入れます

```
<style type="text/css">
  body {background-color: #f4ffff}
</style>
  
<h1><font color="#3e62ad">テスト環境です</font></h1>
<hr>
```
↓↓↓
これでこうなる
![画面全体.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295558/fa13c0fc-e45a-dca3-1979-01fd422627eb.jpeg)
EasySaveのデータディレクトリ関連で詰まったこと

# この記事で言っていること
- EasySaveの設定でSetting → Rantime Settings → DirectoryをDataPathにした場合、データディレクトリはexeファイルが置いてあるフォルダではなく、`[ゲームフォルダまでのパス]/[ゲーム名]_Data`になる。  
- EasySaveのfilePathは**絶対パスで指定**される。(なので`./hoge/save.es3`みたいに書くとNotFoundって言われる)  
  
# はじめに  
　UnityでゲームのデータをEasySaveで永久セーブしてPC向けにビルド後ロードする際、２つほどしくじりをしました。 
この２つは原因が分かってしまえばくだらないことなんですが、備忘録的に残しておきます。  
  
# EasySaveのデータディレクトリ  
　EasySaveには、データディレクトリを変更する機能があります。Window → Easy Save 3 → Setting → Rantime Settings → Directoryから変更できます。  
　これはデフォルトだとpresidentDataPathになっているのですが、ゲームのフォルダと関係ない奥深くのフォルダを汚すのも気が憚られたため、DataPathに変更しました。  
　私はてっきりexeファイル直下がデータディレクトリだと思い込み、そこにセーブフォルダを置いたのですが、本当は`[ゲームフォルダまでのパス]/[ゲーム名]_Data`がデータディレクトリであり、この中にセーブフォルダを入れないと、当然ながら見つかりません。このせいでデータが見つからず時間を取られました。

# filePathの指定  
　EasySaveにはパスを指定してセーブ、ロードする機能があります。例えばこんな風に。  
  
```c#
string filePath = "/save/savedata.es3";
var saveData = ES3.Load<int[,]>("sampleKey", filePath);
```
  
　このfilePathですが、**絶対パスで指定**され、更に上のようにDirectoryをDataPathにしている場合、カレントディレクトリは`[ゲームフォルダまでのパス]/[ゲーム名]_Data`にいる扱いになり、filePathの最初に結合されます。  
　これがどういうことかというと、filePathは本当は`[ゲームフォルダまでのパス]/[ゲーム名]_Data/save/savedata.es3`となっているわけです。なので、`./save/savedata.es3`みたいに相対パスで探そうとすると`[ゲームフォルダまでのパス]/[ゲーム名]_Data/./save/savedata.es3`となり、いざビルドして実行した際に強制終了してわけも分からず原因を探し回ることになります。 

# 参考リンク  
- [簡単にセーブ＆ロード&暗号化が実装できるEasy Save【Unity】【アセット】【Easy Save】](http://kan-kikuchi.hatenablog.com/entry/EasySave)  
- [Unityで取得できるパス一覧](https://qiita.com/consolesoup/items/19fed212d4ef2bd1e1dd)
Icarus Verilogの導入とAND回路のシミュレーション

#概要
マイコンばっか触ってきたけど唐突にFPGAに手を出したくなったのでVerilogHDLを学ぼうと思い、コンパイラと波形シミュレータの環境を整えたのでその備忘録

#開発環境の導入
Windows版もあるようだが、情報が少なかったのでUbuntu 18.04LTSに導入する。
ターミナルを開いてaptから"iverilog"と"gtkwave"をインストールする。

```
sudo apt install iverilog
sudo apt install gtkwave 
```

#AND回路の実装
適当なディレクトリに移動してVimを用いて以下のファイルを作成する

``` verilog:and.v
module AND(
        input wire in0,
        input wire in1,
        output wire out0
        );
        assign out0 = in0 & in1;
endmodule
```

#テストベンチファイルの作成
今回はFPGAには書き込まず、シミュレータ上で動作確認を行うため、以下のようなテストベンチファイルも用意する

``` verilog:and_test.v
module ANDTEST;

reg a, b;
wire c;

AND and_instance(a, b, c); //オブジェクト指向感

initial begin
        $dumpfile("and_test.vcd");
        $dumpvars(1, ANDTEST);
        
        a = 0; b = 0;
        #10 a = 1;
        #10 a = 0; b = 1;
        #10 a = 1;
        #10 a = 0; b = 0;
        #10 $finish;
end

endmodule
```

#コンパイル
以下のコマンドを入力する
```iverilog -o [出力ファイル名] -s [トップモジュール名] [.vファイルの羅列]```
```-o```オプションを省略すると出力ファイルは```a.out```になる。```-s```オプションは省略可能だが、省略せずにトップモジュールを明示したほうが良さげである。

```
iverilog -o andtest -s ANDTEST and_test.v and.v
```

#vcdファイルの作成
以下のコマンドを実行し、```and_test.v```内で指定したファイル名である```and_test.vcd```が出力されたか確認する。

```
vvp andtest.out
```

#波形の確認
ターミナルに以下のコマンドを入力する。得られた波形を確認すると```c = a & b```という回路を実装できていることがわかる。

```
twinwave + and_test.vcd
```
![Screenshot from 2019-08-02 19-24-44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328420/9a5443d9-4199-f290-1b4d-caf3344543cd.png)




#参考にしたサイト
1. http://cellspe.matrix.jp/zerofpga/icarus.html
1. http://altmo.html.xdomain.jp/src_00/2015_0110/verilog-hdl_base_04.html
1. http://cas.eedept.kobe-u.ac.jp/~arai/Verilog/
ふと思い立って、フィボナッチ数列を求めてみた。

フィボナッチ数 - wikipedia
https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0

「要素数len個のフィボナッチ数列を作る」となると、普通に書くとこんな感じ。

```javascript
const fibo1 = (len=0)=>{
  const fib = [];
  for (let i = 0; i < len; i++) {
    fib[i] = (i<2)?i:fib[i-2]+fib[i-1];
  }
  return fib;
}
```

再帰で書くと1ライナーになる。

```javascript
const fibo2 = (len=0, a=0, b=1, arr=[])=>(len<=0)?arr:fibo2(len-1, b+a, arr[arr.length]=a,arr);
```

forEachを使うとこう。

```javascript
const fibo3 = (len=0)=>{
  const fib = [...Array(len)];
  fib.forEach((e,i,arr)=>{
    arr[i] = (i<2)?i:arr[i-2]+arr[i-1];
  });
  return fib;
}
```

mapを使っても1ライナーで書ける。

```javascript
const fibo4 = (len=0)=>[...Array(len)].map((e,i,arr)=>arr[i]=(i<2)?i:arr[i-1]+arr[i-2]);
```

問題は元の配列とmapで作られる配列の2オブジェクトが必要になってしまうという点。

試しに実行時間計測をしてみたが、

```javascript
const time = (loopcount, func, len)=>{
  const start = Date.now();
  while(loopcount-- > 0)
    func(len);
  console.log(Date.now() - start);
}

// chromeの開発者ツールで実行
time(1000000,fibo1,1000); //  7577
time(1000000,fibo2,1000); // 18639
time(1000000,fibo3,1000); //  7124
time(1000000,fibo4,1000); // 10273
```

forEach < for文 < map < 再帰

の順で実行時間が長かった。

forEach、結構速いな。
Kubernetes Meetup Tokyo #21 - Cloud Native CI/CD 参加メモ

## はじめに

[Kubernetes Meetup Tokyo #21 - Cloud Native CI/CD - connpass](https://k8sjp.connpass.com/event/138375/)に参加してきました。
今回のテーマはCI/CDです。

## セッション

### 1. Argoプロジェクト最新動向

資料：https://www.slideshare.net/DaisukeTaniwaki/20190725-argo-project-latest-news
登壇者：DAISUKE TANIWAKI ([@dtaniwaki](https://twitter.com/dtaniwaki)), Preferred Networks, Inc.

[Argoプロジェクト](https://argoproj.github.io/)の概要や仕組みから最新動向まで紹介がありました。
ArgoプロジェクトとはOSSのKubernetes関連のツール群をサポートするプロジェクトです。
以下のツールがサポートされています。

- Workflow
  - Kubernetesネイティブのワークフローエンジン
- Events
  - Kubernetesのためのイベントベースの依存管理ツール
  - Slackにこのメッセージが来たらk8sクラスタを作るみたいなことができる
- CD
  - GitOpsのためのKubernetesネイティブCDツール
  - コミットに合わせてデプロイやロールバックができる
  - UIでInit ContainerやSide Carの状態も確認できる
- Rollouts
  - BlueGreenやCanaryなどのストラテジーでPodをデプロイできるOperator
  - ストラテジー以外はほぼDeploymentsと変わらない

メインで紹介されていたArgo CDはGitOpsとの相性やUIの使い勝手が良さそうだと感じました。  
Preferred Networksでも導入予定のようです。

### 2. GitOpsでも秘匿情報をバッチリ扱う⽅法、SealedSecretとは？

資料：https://speakerdeck.com/amaya382/how-to-manage-credentials-on-gitops
登壇者：Ryuichi Ito ([@amaya382](https://twitter.com/amaya382)), SAKURA internet Inc.

GitOpsでは、Gitリポジトリにmanifestファイルと一緒に秘匿情報（Secretリソース）も含めてしまいます。
SealedSecretsという仕組みを使うことでGitOpsでも秘匿情報を扱えるようになります。  

使い方はkubesealというCLIでSecretsリソースを暗号化するとSealedSecretsというCRDが作られるので、
そのファイルをGitレポジトリにpushするだけ。
CDツールで自動的にSecretsリソースに復号化されるので、PodからはSecretsとして参照します。

GitOpsに特化しているためシンプルで扱いやすい反面、
helmやkustomizeなどのテンプレートエンジンとの相性が悪いという欠点もあります。

helm secretsやkustomize secretsといったテンプレートエンジンに特化したツールもあるので、
そちらも検討の余地がありそうです。

### 3. コロプラが実践しているSpinnakerを用いたデプロイ戦略

資料：https://speakerdeck.com/govargo/deploy-strategy-with-spinnaker-at-colopl
登壇者：Kenta Iso ([@go_vargo](https://twitter.com/go_vargo)), COLOPL, Inc

コロプラでのmanifest管理方法やSpinnakerでの運用方法を紹介。

Spinnakerにはhelmでインストールする方法とhalyardでインストールする方法がありますが、
コロプラではカスタマイズをするためにhalyardでインストール。
パラメータのチューニングや、Clouddriver・EchoのHA化、RedisのMaster/Slave構成を行っています。

## おわりに

GitOps関連の発表が多く、課題や周辺ツール、ワークアラウンドまで非常に参考になりました。
以前はCDツールといえばSpinnakerという印象でしたが、Argo CDも試してみたいですね。

## 関連レポート

- [【参加メモ】Kubernetes Meetup Tokyo #21 - Cloud Native CI/CD - Qiita](https://qiita.com/lastis/items/6a6eef1f021fde5d124b)
- [Kubernetes Meetup Tokyo #21 - Cloud Native CI/CD に行ってきた | To Be Decided](https://www.kaitoy.xyz/2019/07/26/k8s-meetup-tokyo-21/)
- [Kubernetes Meetup Tokyo #21 - Cloud Native CI/CD 参加レポート - 透明度50%](https://translucens.hatenablog.jp/entry/2019/07/29/024436)
Machine Learning Production Pitch #3に参加しました

Machine Learning Production Pitch #3 の参加報告
https://machine-learning-pitch.connpass.com/event/137974/

ハッシュタグ [#mlpp](https://twitter.com/hashtag/mlpp)
募集枠通り、100人弱くらい来ていたと思う

他のまとめ記事
https://www.hirayuki.com/zakki/machine-learning-production-pitch-2

# ABEJA PlatformでMLOpsの課題を解決する

話し手はABEJA 取締役の人（営業みたいなことやってる、と自称）。
最初に「ABEJAを知ってる人ー？」と聞いたら、会場の8割ぐらいが手を上げていた。

・顧客には製造・物流・小売が多い
・社員数70人
・エンジニアの採用をすごいプッシュしていた

### ABEJA Insight For Retail
・小売り向け。カメラで来店者の分析をするSaaS（属性・リピート・etc）
・カメラの設置から入る。配線など、泥臭いこともやる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299048/69c22969-6731-33b0-1724-8671b79f6de4.png)

ABEJA Insight For Retailをやっていた時の悩み
・動画データの取得遅延
・動画解析の遅延
・解析結果の真値チェック
・複数モデルの安定稼働
→これを解決するためのプラットフォームを作った

### ABEJA Platform

AI開発基盤となるPaaS

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299048/8f9c162c-3d4e-4df6-8192-d6d746126024.png)

Webアノテーションツールも含まれている。
次はアノテーションの自動化を目指している（AIがアノテーションを仮付けして、人間がそれを修正）


# 富士通研のAI基盤の話

富士通研究所は富士通とは別会社。
研究成果を富士通（通称：本体）に収める。

本体への技術移転が大変。特にAIエンジニアはシステムに明るくないのでツライ。
→AI基盤（個別環境構築なしにAI技術を使える環境）を作ろう

はじめはk8sをそのまま公開する形だった

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299048/aa965607-7f5c-7b44-a570-a527c1a58c5c.png)

→k8sの学習コストが高すぎて、AIエンジニアから批難多数
→WebAPIをかませて、使いやすくした

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299048/aff1c216-3cae-99b2-5d3c-07bf3a239be9.png)

それでもいきなり使うのはつらいので、ジョブのテンプレート的なのを作って、カタログ化している
（＊＊やりたい人は、こんな入力で投げてね、みたいなの）
サーバは3,40台くらい入れてる
知見の蓄積にはnootbookを使っている
情報共有はissue

はやらせるために、社内ハンズオンをやった
10回、70人が参加
→ユーザ数176人になった
さらにハンズオンでAI研究者にDockerを覚えてもらった（すごい）

### 苦労話
・電源ショートでk8sサーバ全滅
・コンテナ駆逐コンテナ
・GPUを抱えたままにする人がいる
詳細は https://qiita.com/kuromt_/items/8cd8eed8ae99e50e11e6 にて

# Rekcurd Update & Demo

LINE時代に使ったソフト。まだ開発に参加している。
https://github.com/rekcurd/rekcurd-python
「Rekcurdは絶対にはやる！」と、途中で終わってしまわないようにコントリビューションを続けているとのこと。

RekcurdはML Opsのデプロイ部分（Serving Model）を担当するOSS。
世の中にServing Modelのツールは大量に出てきているが、ほとんどk8sを事前知識として要求していて、ハードルが高すぎる
→だからAIエンジニアでも使いやすいRekcurdを作った

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299048/9ae9d03f-b7fb-746a-1102-a5c0a7ff0c0b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299048/d030d32b-09ab-a227-cff2-559c4c0da8c4.png)

# kubeflow/katib

ML Opsのトレーニング部分を担当するOSS。
Auto-MLフレームワーク。
ハイパーパラメータチューニングを簡単化。
値と結果を一覧化・グラフ化して、どう制度が良くなったのかを可視化できる。

v2を出した。
v1はcloud nativeでない（要素が一つ落ちると復旧がツライ）ので、作り直した。
CDRにデータソースをまとめて、クラッシュに強くしている。

ハイパーパラメータチューニングだとジョブを大量に投げるが、それにk8sのetcdが耐えられるのかは要検証。

Q. KubeFlowは流行るのか？
A. わかりません
競合もたくさん出てきていて、今後どれが流行るかは見通せない
（KAMONOHASHI https://kamonohashi.ai/ の名前も出てきた！）


# 会について
イベントの共催してくれる人・企業を歓迎しているらしい。
[Slack](https://join.slack.com/t/machinelearningpitch/shared_invite/enQtNjI5ODI0NDY5ODEyLWY1YWRmNDY2ZTczZjM0ZjU3M2VhMGU4OGFlOGY3NDY1NmU0NTFlNmQxOGM1YTAxNjcxZmJmODM5NzQwYTRlZjE)を公開しているので、ぜひ参加を！とのこと。

まずはSlackに入ってみようかな。