OmniAICreator/Qiita-1.07M huggingface dataset:
Djangoでbitflyerの収支管理アプリを作ってみる（02_02.ログイン画面を作る②。）

前記事のようなやつ

Djangoでbitflyerの収支管理アプリを作ってみる（02_01.ログイン画面を作る。）
https://qiita.com/redmeteor777/items/1b974f15ac8b0e87a17d

ある程度記事数書き上げたらまとめる予定。
後記事へのリンクとか。

前記事の最後に生やした草を刈り取って、入力フィールドを埋めていきます。

まずloginディレクトリの中に、フォームを作成するためのファイル、[forms.py]を作成します。
そして、作成した[forms.py]に入力フォームについての関数を書いていきます。

```forms.py
from django import forms

class LoginForm(forms.Form):
    user_id = forms.EmailField(
                        label='user_id',
                        max_length=30,
                        min_length=8,
                        required=True
                        )

    password = forms.CharField(
                        label='password',
                        max_length=30,
                        min_length=8,
                        required=True
                        )
```

formsをimportして、入力フィールドを記述しました。
EmailFieldは「メールアドレス形式」のみ入力できるフィールドを作成します。
CharFieldは「テキスト形式」の入力が可能なフィールドを作成します。

---
ビュー関数の定義
---

次にビュー関数を定義します。

```views.py
from django.shortcuts import render
from django.http import HttpResponse
from .forms import LoginForm

def login(request):
    params = {
        'title': 'Login_Form',
        'message': 'input your e-mail and pass.',
        'form': LoginForm()
    }

    if (request.method == 'POST'):
        params['message'] = \
            'メールアドレス：' + request.POST['user_id'] + \
            '<br>パスワード：' + request.POST['password']
        params['form'] = LoginForm(request.POST)

    return render(request, 'bfmonitor/login.html', params)

def registration(request):
    return HttpResponse("Hello, World!!!!!")

```

変更したのは以下の3点。

1.
from .forms import LoginForm
直前に作ったLoginFormをimportします。

2.
paramsの作成
テンプレートに渡す引数として使う、params変数が準備されています。

3.
POSTが要求された場合の処理を記述しています。
GETが来てもPOSTが来てもそれぞれ処理をできるように、準備している感じですね。

---
HTMLファイルに変数を埋め込む！
---

前回草を生やしたファイルを編集しないと、今回も草が生えてしまいます。
というわけで、index.htmlを編集していきましょう。

```index.html
{% load static %}
<!doctype html>
<html lang="ja">
<head>
    <meta charset="uth-8">
    <title>{{title}}</title>
    {% comment %} <link rel="stylesheet" type="text/css"
        href="{% static 'login/css/style.css' %}" /> {% endcomment %}
</head>
<body>
    <h1>{{title}}</h1>
    <p>{{message|safe}}</p>
    <form action="{% url 'login' %}" method="post">
        {% crsf_token %}
        {{ form }}
        <input type="submit" value="click">
    </form>
</body>
</html>
```

草刈り完了です。

最後にurlpatternを修正しましょう。

```urls.py
urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', login.login, name='login'),
    path('registration/', login.registration),
]
```

name='login'

と追記することで、きちんとページの中身を読み込みに行ってくれるはずです。

ではサーバーを起動して確認してみましょう。

```
>python manage.py runserver
```

ログイン画面にアクセスして表示を確認します。

```
http://localhost:8000/login/
```

入力フォームが表示されれば完成です！
お疲れ様でした！人類の勝利です！！

やっと画面1個できた！！！

…と言っても、入力用のフィールドが表示されるようになっただけです。
データを送ることもできないし、送ったデータを照合するデータベースもないです。

~~というわけで、次回はユーザー登録画面を作っていきます！~~

次回はtableタグとかつけて体裁を整えます！！！
RailsのDEPRECATION WARNINGを消す

## 事象
Railsのバージョンを5から6にアップグレードしたら、尋常ではない量のDEPRECATION WARNINGが出てしまった。

```

DEPRECATION WARNING: Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1. To continue case sensitive comparison on the `:カラム名` attribute in `モデル名` model, pass `case_sensitive: true` option explicitly to the uniqueness validator. (called from block (3 levels) in <main> at /***/spec/factories/***.rb:6)
```
Rails6からUniqueness validatorの仕様が変更されたことによる警告だった。

**参考**
[Rails 6.0でDeprecatedになるActive Recordの振る舞い3つ](https://blog.kamipo.net/entry/2019/05/15/152652)

しかし、Uniqueness validatorを使っている箇所すべてで警告が表示されるので、RSpecを流すと実行結果がとんでもないことになる。
他にもいくつか警告が表示されていたが、自分のアプリではいずれも問題ないことが確認できた。
その時点で警告は無意味となり、あまりにも見づらいので非表示にしたい。

## 対応
不要な警告がログに出力されないよう、`config/application.rb`に以下コードを追加した。

```ruby

ActiveSupport::Deprecation.silenced = true if Rails.version == '6.0.2'
```

これで、当該アプリのバージョンが`6.0.2`なら、DEPRECATION WARNINGが出力されなくなる。

今後Railsをアップグレードする際も、当該バージョンでdeprecatedになったものの確認がすべて完了してから非表示にしたいので、`6.0.2`と直に書いている。
`6.0.2` -> `6.0.3`に上げて新たな警告が出ていれば、内容を確認(対応)後にこちらも`6.0.3`に書き換えていく。
rails db:migrate でエラーが起きる時の対処法

今回は、マイグレーションをした時の対処法についてみていきます。

```
$ rails db:migrate
-- create_table(:movies)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::DuplicateTable: ERROR:  relation "movies" already exists
```

このようなエラーはすでに、同じ「movies」というテーブルが存在していますよ。っていう意味なので、moviesテーブルを削除してあげてれば問題ないです。

##すべきこと
1.ターミナルで以下のように入力してあげる。

```
$ rails db
``` 

2.#が出てくるので、その横に\dと入力してあげる

```
# \d
```

3.テーブルがたくさん出てくるので該当のテーブルを削除してあげる。(今回は、moviesテーブルを削除する)

```
# drop table movies;
```

4.再び,マイグレコマンドを入力する

```
$ rails db:migrate 
```

これで、マイグレーションがうまくいきます。

もし、間違えているところがあればコメントしていただけると幸いです。
また、いいねを頂くと励みになりますのでよろしくお願い致します。
Blender2.8で面が選択できなくなった

試しにここに記事を書いてみたかったので書いてみます。

<h2>問題</h>
<p>Blender2.81でEdit Modeでポリンゴメッシュの面選択だけができなくなってしまいました。</p>

<h2>結論</h>

<p>ビューポートオーバーレイ設定の「メッシュ分析」を一度ONにしてOFFに戻したら治りました。<br>
理屈はわからず…　（だめじゃん！）</p>
![面選択できなくなった時にオンオフしてみるところ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243980/4e846257-c9fa-63f8-2de3-34f712229e9f.jpeg)
ログ監視

##サーバーログを監視する
本番、検証、開発、どれでもですが
APサーバーのserver.log的なファイルに、ログがどんどん書かれるわけで
モジュールが正常に動いているかなど、外から見えないシステムの動きを監視するために
リリースするたびにログを監視する作業がありますよね

その際、まぁTeraTermなどでlinuxサーバーに接続して、ログファイルを見るわけですが
どのコマンド使う？って話です

##王道のtail
まぁこれでしょ
`tail -f ファイルパス`
たとえば

```
tail -f /asd/asdasdasd/asdasdasd/server.log
```
みたいな
これで上書きされるファイルをリアルタイムで監視できます

##新時代のless
いまどきtailは情弱
`less +F ファイルパス`
たとえば

```
less +F /sdd/sdsdsd/sdsdsd/server.log
```

これで`tail -f`と同じ機能
`Ctrl + C`で更新しなくなる
なんなら

```
less /sdd/sdsdsd/sdsdsd/server.log
```
を実行したあとに`shift + f`(大文字のF)打てばいい

んで、Grep的なことができる

更新しないモードの時に`&`を入力すると、入力欄が出てくる
そこに「完全一致」ワードまたは「qqq | eee」と入力すればOR検索
大文字小文字を区別するので正確にタイプしよう

また、`&`を入力後に`!`を入力すれば、not-matchモード(不一致検索)になる


わざわざログファイルをローカルにダウンロードして、サクラエディタでGrepなんてしなくても、その場で検索できるのだ

しかも自動更新しないモード中なら、Bキーで上ページ、Spaceキーで下ページ、Gキーで一番上まで、Shift + Gキーで一番下まで
一気に飛べる

lessはtailの上位互換といっても過言ではないとおもう


##Windowsなら
Power-Shellを起動しよう
winキー + XキーからのAキーでできるはず

んで

```
Get-Content -wait -tail 10 -encod UTF8 -path パス
```
ここの10の部分は最初に取得する行数です、`tail -f`は指定しないと初期で10なので10って書いてみました
Python学習ノート_006


第４章のサンプルコードは下記のようです。

- ポイント
 - リストの長さはlen()で計算して、forループにインデックスの上限値として使える
 - printにコンマで区切った複数の値の間に１スペースがあるため、それを回避する方法は文字列の連結で１つ文字列として出力する

```python:sample04.py
scores = [60, 50, 60, 58, 54, 54,
          58, 50, 52, 54, 48, 69,
          34, 55, 51, 52, 44, 51,
          69, 64, 66, 55, 52, 61,
          46, 31, 57, 52, 44, 18,
          41, 53, 55, 61, 51, 44]

length = len(scores)

for i in range(length):
    print("テストの案 #" + str(i),"のscore:",scores[i])

high_score = max(scores)
max_list = []
for i in range(length):
    if scores[i] == high_score:
        max_list.append(i)
        
print("テストの総数：",length)
print("最高の点数：",max(scores))
print("最大値のインデックス：",max_list)
```

- 出力結果  
![サンプル４の出力結果の一部](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551056/9884a42e-d41a-df2a-451a-ad61359bafc7.png)
Ubuntu18.04 でWifiが認識されなかった問題を解決した方法

# はじめに
新しく購入したパソコン（IdeaPad C340）にUbuntuを入れたらWifiが使えない問題が発生して解決に苦労したので備忘録として残しておきます。

ちなみに問題が発生した環境は下記のとおりです。

PC : IdeaPad C340 (14)
型番 : 81TK001FJP
OS : Ubuntu 18.04.3 LTS

あと`$ lspci -nnk`の出力結果は下記になってました。（Networkのみ抜粋）

```
00:14.3 Network controller [0280]: Intel Corporation Device [8086:02f0]
	Subsystem: Intel Corporation Device [8086:0034]
	Kernel driver in use: iwlwifi
	Kernel modules: iwlwifi
```

# 解決した方法

色々と試したのですが、Secure Bootを無効化した状態で下記ページのように linux-firmware をバージョンアップしたらwifiが認識されて使えるようになりました。

*Intel Wifi Card not working on Ubuntu*
https://askubuntu.com/questions/1180765/intel-wifi-card-not-working-on-ubuntu

ちなみに、
`# apt update`と`# apt install linux-firmware`を予め実行していたのですが、wgetで取得してこないと18.04では解決できるバージョンまで上げれないみたいです。


## アップデートしたら使えなくなった

※2020.03.23 追記
サボってたアップデート`#apt update & apt upgrade`を実行したらまたWifiが認識されない現象が発生しました。orz...

詳しい原因はわかってないですが、どうもLinuxカーネルのバージョンとWifiドライバのバージョンに不整合があってドライバの読み込みがちゃんとできてないっぽいです。

結論から言うと、カーネルのバージョンを`5.3.0-28-generic`で起動したら認識するようになりました。

#### 以下、この結論に至った過程

1. デュアルブートしてるWindowsとかからWifiドライバのメーカー、バージョンを特定
→「Intel(R) Wireless-AC 9560」ってやつでした。

1. [Intelのページ](https://www.intel.co.jp/content/www/jp/ja/support/articles/000005511/network-and-i-o/wireless-networking.html) から対象のドライバをダウンロード
→iwlwifi-9000-pu-b0-jf-b0-34.618819.0.tgz をダウンロード＆解凍
（Intelのドライバはiwlwifi-***って名前のファイルを使用するみたい）

1. 取得したドライバ(**.ucode)を`/lib/firmware`に配置
→同じファイル名のやつがあったのでとりあえずバックアップ

1. 再起動したけどWifi認識しないままなので、`/lib/firmware`から2.で取得したドライバ(ucode)以外のファイル（iwlwifi-**のやつ）を全削除

1. 再起動してdmesgを確認したらucodeのバージョンがminimum〜maximumの間に無いから読み込めません的なエラーが出てた
（4.で削除する前は別のエラー（startできません的なやつ）だったので、この辺からバージョン不整合で別のドライバを読み込んでると推測）

1. Linuxカーネルを4.18まで下げて再起動したらWifi認識してくれた！！
けど、マウスカーソルが動かないという致命的な問題が...( ；∀；)

1. 最新は`5.3.0-42-generic`だったので、この間のバージョンでインストール済みのやつを順に調べたらWifiを認識する最新バージョンが`5.3.0-28-generic`でした。


ホントは最新カーネルで読み込むドライバをちゃんと指定してやるべきだと思うんですが、やり方がわかんなかったので誰かわかる人いたら教えてくださいm(_ _)m
vagrant template

```
Vagrant.configure("2") do |config|
  config.vm.box = "centos/7"
  config.vm.hostname = "base"
  config.vm.network "private_network", type: "dhcp"
  config.vm.network "forwarded_port", host: 9092, guest: 9092
  config.vm.network "forwarded_port", host: 3306, guest: 3306
  config.ssh.insert_key = false
  config.vm.provider "virtualbox" do |v|
    v.memory = 4096
    v.cpus = 4
  end
end
```
AtCoderで緑色になるまでにやったこと

初投稿です。
今年の7月から競技プログラミング(AtCoder)を始めて、
12/28に行われたAGC41でついに緑色(rating: 800~)になりました！！
年末までに緑色になるというのを目標としていたため、ギリギリ滑り込めてよかったです。
<img width="1164" alt="スクリーンショット 2019-12-29 14.39.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473300/2e4c248e-86a0-3d06-f2aa-cd4a904aee21.png">
このような記事は腐る程あるとは思いますが、緑色になって嬉しくなったので、
緑色になるまでにやったことを書いていきたいと思います。

##1. 自分の背景
私は私大の電気電子工学修士卒で、特にプログラミングに慣れ親しんでいた訳ではありません。
授業でC言語の授業、研究でPythonを少し触った程度です。
今年の4月から半導体回路の設計、評価をする会社に就職しました。
私のいる部署ではプログラミングをする業務はありません(Excelマクロくらいは触ります)。

そんな私がプログラミングを本格的に始めたのは今年の7月ごろです。
というのも、会社での研修が終わり、7月から部署に配属され業務を始めたのですが、
・自分が思っていた業務と違う。
・先輩たちが鬼忙しそう。
・業務があまり好きになれない。
といった理由から早くも転職を視野に入れはじめ、
プログラミングだったらどこでも仕事できるという安易な考えから、プログラミングの勉強を始めました。

プログラミングの勉強を進めていくうちに、AtCoderという競技プログラミングの存在を知り、
・ゲームのような感覚でプログラミングが勉強できる。
・自分のプログラミングの実力が数値化される。
・またその数値化された実力(ratingのこと)で転職活動を行うことができる。(AtCoder Jobs)

ということに惹かれて、競技プログラミングのコンテストに参加するようになりました。

##2. 現在の実力
<img width="974" alt="スクリーンショット 2019-12-30 14.54.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473300/fdb1596e-e406-f916-9a59-d9c8ae35a99d.png">

19/12/28現在でAtCoderのコンテストには19回参加しました。
AtCoderのコンテストに始めて参加したのは19/7/20に開催されたABC134(AtCoder Beginner Contest 134)なので、緑色になるまでに大体５ヶ月かかりました。
最近のコンテストのパフォーマンスは900~1000くらいだと思います。
DFSやBFS、2分探索、簡単なDPなどはコンテストで使いこなせる実力です。
計算量改善も簡単な少しはできるかなって程度です。
数学に関しては強くないです。AtCoderの参加者の中では平均的だと思います。
また、他の競技プログラミングのコンテスト(CodeForceなど)には出たことがありません。

##3. 緑色になるまでにやったこと
###問題をたくさん解く
他の記事でも書かれていますが、問題をたくさん解くことは緑色になることに必要です。
その理由としては、
・競技プログラミング初心者の人は問題をたくさん解いて標準入出力に慣れる必要があるため。
・色々な種類の問題に触れて、自分の知識を増やすため。
があると考えています。

私が始めたばかりの頃は標準入出力が思うようにできなくて、
A問題、B問題でも時間がかかっていたなんてことがあったので、
問題をたくさん解いて標準入出力に慣れることは必要かと思います。

問題をたくさん解くことで徐々に解法が見えてくるようになります。
例えば、N＝10**8などの問題で全探索するとTLEしてしまうから二分探索してみよう、とか
N=50兆なので、規則性を見つけたり、定式化するだとかの計算量的なアプローチを学ぶ、
bit探索で書いたら簡単にコードを書くことができる、といったことは色々な種類の問題に触れることにより初めて得られる知識だと思います。(特に初心者や、情報系出身でなくてアルゴリズムの勉強をしたことがない人)
なので、緑になりたい人はたくさん問題を解きましょう。
(問題を解いた数(AC数)、累計得点(Point rated sum)とRatingには相関があります。リンクは<a href="https://saba-kpr.hatenablog.com/entry/2019/12/18/044028" target="_blank">こちら</a>)

###コンテストに参加するときに目標を決める
私は年内に緑色になると決めてからは、「パフォーマンスを○○出す」考えてコンテストに参加していました。
そしてそのパフォーマンスを出すために、「C問題は○分までに解いて、D問題は時間内に解けたら何位に入れるなー」ということを考えていました。
特に初心者のときには、C問題までしか解けなくても、回答スピードが早ければある程度の順位、パフォーマンスを獲得できます。
なので、目標とするRatingがある人はコンテスト毎に目標を立てて、問題を解くスピードを意識しながらコンテストに参加しましょう。

##4. これからやること
これからやること、やりたいことは３つ程度あります。
・水色を来年の7月までに達成する。
・Kaggleに参加してsoloでブロンズメダルを獲得する。
・転職活動のためにポートフォリオを作る。

１つはAtCoderでRatingを1200まで上げて水色になりたいと思っています。
水色のレベル感としては、アルゴリズム力的には十分で会社でも戦力になる？らしいので、
競技プログラミングを始めてから1年となる7月までに水色を達成したいと思っています。
ただ、水色パフォーマンスをまだ１回しか出してないのでもっと時間がかかりそうです。
なので、蟻本を読み始めようかなと思っています。

また、最近はData Scienceの方にも興味があるため、Kaggleの方にも手を出しています。
今はCourseraでKaggleに関する講義を受けていて、コンペにも参加しています。
とりあえずメダルを一つくらい欲しいと思っているので、4月までにsoloでブロンズメダルを獲得したいと思っています。

あと、転職活動のためにポートフォリオを作りたいと思っています。
一度ポートフォリオ的なものを作りましたが、最近は競技プログラミングとKaggleをやっているため触れられていません。
転職活動をするにはおそらく必須だと思うのでぼちぼちやっていきたいと思っています。
ログイン機能に関わるsessionについて（ステートレスとステートフル含む）

#####sessionとは
セッションとは、一連の処理の始まりから終わりまでを表す概念のこと。
セッションという定義は広く、さまざまなところでセッションという用語が使われる。

「なるほど。わからん。」

#####・セッションを理解するにはまずステートフルとステートレスを知る必要がある。

ステートフルとは、あるリクエストをしたら、レスポンス（対応や反応、応答内容等）が変わるもの。特に、それ以前のやり取りの状況（ステート）によって回答が変わるもののこと。

ステートレスとは、あるリクエストをしたら、必ず同じ結果になるもの。それまでのリクエスト・レスポンスのことは一切考えず、今来たリクエストを額面通りに受け取って回答するもののこと。

具体的な例で考えてみる。

#####のび太とドラえもんのやりとりがステートフルだった場合

の「ドラえもん来週テストだから暗記パンだして」

ど「今在庫切れで入荷待ちなんだよ。テストまでには間に合うはず」

の「明日テストだよ。例の物は？」

ど「はい。でも自分で勉強しないと成長しないよ」

#####このやりとりのように「WEBブラウザ（のび太）」と「WEBアプリケーション（どら）」間ではリクエストとレスポンスのやりとりをして処理している。
次のステートレスの場合と比べるとわかりやすい。


#####のび太とドラえもんのやりとりがステートレスだった場合

　の「ドラえもん来週テストだから暗記パンだして」

　ど「今在庫切れで入荷待ちなんだよ。テストまでには間に合うはず」

　の「明日テストだよ。例の物は？」

　ど「例の物ってなあに」

　の「…」


このようにステートレスでは**前回のやりとりを保存していない**ため例の物というデータがなければレスポンスすることはできない。

上の二つの例を比べてわかるように、前のやりとりを記憶しているステートフルの方がWEBアプリケーションを利用する上で都合がいい。
しかし、WEBは基本的にステートレスである。ステートフルにするために使用するのがsessionだということ。

**※ステートレスであることにもメリットがありますがここではセッションについての説明なので省かせていただきます**

#####sessionを使用することによって生じるデメリットもある。
・sessionはサーバー側にメモリの空間を作るため、アクセスするユーザーの増加に比例してサーバー側のメモリを圧迫してしまう
・ハッカーにsessionによって作られたサーバー側にある重要なデータ（住所。クレカ番号など）が奪われる危険性がある

以上の理由からsessionの使用はあまり好まれない傾向にあるらしい

また、セッションと一緒に考える必要があるクッキーについても書いていきたい。

今日もいい勉強したな！

認識に間違いがあれば教えていただけるとありがたいです。
【忘備録】Minimum Covariance Determinantを使用したマーケットの異常探知


# Minimum Covariance Determinant or MLEで求めた共分散行列による異常探知比較

飛んだ値に思いっ切り引きずられるのを避けるためにも、マーケットデータと相性良いメソッドかと

```python

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
from sklearn.covariance import EmpiricalCovariance, MinCovDet
from sklearn.covariance import EmpiricalCovariance

warnings.filterwarnings('ignore')

plt.style.use('seaborn-darkgrid')
plt.rcParams['axes.xmargin'] = 0.01
plt.rcParams['axes.ymargin'] = 0.01

```

ReadDFに週次の各種マーケットリターン(為替、株、債券etc)


```python
# ルックバック過去50週間リターンを用いて算出

ts_out = pd.DataFrame()
for date in ReadDF.dropna(axis=0)[50:].index:
    x = ReadDF[:date][-50:]
    x = (x/x.std()).dropna(axis=0)
    
    mcd.fit(x[:-1])
    anomaly_score_mcd = mcd.mahalanobis(x[-1:])
    
    mle.fit(x[:-1])
    anomaly_score_mle = mle.mahalanobis(x[-1:])
    
    out = pd.DataFrame([anomaly_score_mcd, anomaly_score_mle]).T
    
    out.columns = ['mcd', 'mle']
    out.index = [date]
    
    ts_out = pd.concat([ts_out, out], axis=0)
```

```python
fig = plt.figure(figsize=(15, 10), dpi=80)
out = pd.DataFrame(ts_out/ts_out.std())  # 規格化
sns.set_palette("hls", len(out.columns))
ax1 = fig.add_subplot(1, 1, 1)
ax1.plot(out, alpha=0.6)
plt.legend(out.columns)
plt.show()
```

![Anomaly.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509334/7831fe69-a5a0-7265-3a8d-bb200b5dcc85.png)
DockerfileのRUNやCMDをBashのログインシェルで実行させる

または、sdkman, rbenv, nvmなどのパッケージマネージャをDockerfileやコンテナで動かす方法について。

# TL;DR

Dockerfileの`RUN`がbashかつログインシェルで動いてほしいとき

```dockerfile:Dockerfile
SHELL ["/bin/bash", "-l", "-c"]
```

Dockerfileの`CMD`や、`docker run`に渡したコマンドがbashのログインシェルで動いてほしいとき

```dockerfile:Dockerfile
RUN echo '#!/bin/bash\nexec /bin/bash -l -c "$*"' > /entrypoint.sh && \
    chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
```

# 経緯

諸事情でJava, Gradle, Ruby, Node.jsをそれぞれ指定されたバージョンでインストール済みのコンテナイメージを作る必要があった。
apt-getなどOS標準のパッケージマネージャで過去のバージョンを指定してインストールしたり、個別にインストールするのが面倒に感じたため、sdkman, rbenv, nvmといったバージョンマネージャをDockerfile内でインストールして使うことにした（いろいろあって結局使うのをやめたが……）。

しかしこれらのツールは、Dockerfile内ではうまく動作しなかった。
なぜならsdkmanなどのバージョンマネージャは

- bashを前提としているものがある(関数やsourceコマンドなど)
- `.bashrc`で初期化スクリプト(PATHの設定など)が実行される

つまり、動作にはbashかつログインシェルで実行される必要がある。一方、Dockerfileの`RUN`命令はデフォルトで

- `/bin/sh -c`の引数として実行される
- bashでもログインシェルでもないため`.bash_profile`や`.bashrc`が実行されない

# 解決策

[`SHELL`命令](https://docs.docker.com/engine/reference/builder/#shell)を使うとDockerfile内の`RUN`がどのシェル+引数によって実行されるかを指定できる。

```Dockerfile
SHELL ["/bin/bash", "-l", "-c"] 
```

また、`ENTRYPOINT`命令で`CMD`や`docker run`に渡したコマンドを実行するプロセスを指定できる。これは以下のシェルスクリプトを実行させると大抵の場合うまくいくという結論に達した。

```bash:/entrypoint.sh
#!/bin/bash
exec /bin/bash -l -c "$*"
```
```dockerfile
ENTRYPOINT ["/entrypoint.sh"]
```

## `ENTRYPOINT`の指定について
上の`entrypoint.sh`はずいぶん回りくどく感じると思うので、いくつか他にも試して問題があったケースを挙げておく。

### `SHELL`と同じ指定をした場合

```Dockerfile
ENTRYPOINT ["/bin/bash", "-l", "-c"]
```

`-c`オプションが引数を1つしか受け取らないため、`CMD`や`docker run`でコマンドをまとめて1つの文字列として渡す必要があり、かなり面倒。

### shebangでログインシェルを指定して`exec`だけで実行させた場合

```bash:/enrtypoint.sh
#!/bin/bash -l
exec $*
```

`exec`コマンドの第１引数には実行ファイルを指定する必要があるため、関数やbash組み込みのコマンドが実行できない。
`sdk`, `rbenv`, `nvm`はそれぞれ関数として実装されているため実行できなかった。
Qiitaで画像投稿時に、![error]()となるから、対応してみた。 2019年12月

過去例を検索したら、2015年12月の記事ですが「どうやらデフォルトの画像アップロード容量の上限は月間2MBまでで、1件でも投稿すると100MBに拡張される仕様らしい。」ということらしいです。
https://qiita.com/unsoluble_sugar/items/f61be798972883e44877

しかし、私は2019年11月中に1回投稿済みなのに、12月にどうも2MBを超えてしまったらしい（ググったけど、どうやって確認するかがわかりませんでした。）ので、この記事を投稿してどうなるか試してみます。

以上です。
【AWS IoT】モノにアタッチされていない証明書を削除する

# 目的
AWS IoTにおいて、モノにアタッチされていない証明書を削除する。
不要な証明書を大量に作成してしまった場合用。


# クラス

```Python
import boto3

class CertKiller():

    def __init__(self):
        # AWS IoTを操作するクラスをインスタンス化
        self.client = boto3.client('iot')
        
        return

    
    def delete_not_attached_cert_all(self):
        '''
        モノにアタッチされていない証明書を削除
        '''
        # 証明書情報のリストを取得
        list_cert = self.get_list_cert()

        # モノにアタッチされていない証明書を削除
        for cert in list_cert:
            self.__delete_not_attached_cert(cert)

        return


    def get_list_cert(self):
        '''
        証明書情報のリストを取得
        '''
        list_cert = self.client.list_certificates(pageSize=100)['certificates']

        return list_cert 


    def __delete_not_attached_cert(self, cert):
        '''
        証明書がどのモノにもアタッチされていなかった場合、削除
        '''
        # 証明書情報を取得
        cert_arn = cert['certificateArn']
        cert_id = cert['certificateId']

        # 証明書をアタッチしてあるモノの一覧を取得
        thing_attached_cert = self.client.list_principal_things(principal=cert_arn)['things']
        print(cert_arn, thing_attached_cert)

        # 証明書がどのモノにもアタッチされていなかった場合、削除
        if len(thing_attached_cert) == 0:
            self.__delete_cert(cert_arn, cert_id)
        else:
            pass

        return


    def __delete_cert(self, cert_arn, cert_id):
        '''
        証明書を削除
        '''    
        # 削除前に無効化する必要がある
        self.client.update_certificate(certificateId=cert_id, newStatus='INACTIVE')

        # 削除前にポリシーをデタッチする必要がある
        self.__detach_all_policy(cert_arn, cert_id)

        # 削除
        self.client.delete_certificate(certificateId=cert_id, forceDelete=False)
        print('{} has been deleted.'.format(cert_arn))

        return


    def __detach_all_policy(self, cert_arn, cert_id):
        '''
        証明書にアタッチされている全てのポリシーをデタッチ
        '''    
        # 証明書にアタッチされているポリシーのリストを取得
        list_policy = self.client.list_attached_policies(target=cert_arn)['policies']

        # デタッチ
        for policy in list_policy:
            policy_name = policy['policyName']
            self.client.detach_policy(policyName=policy_name, target=cert_arn)

        return
```

# 実行
```Python
cert_killer = CertKiller()
cert_killer.delete_not_attached_cert_all()
```

# 備考
* もし使用いただける場合は自己責任でお願いします。
* デバイスにアタッチされている証明書が削除される心配はありません。  
（[delete_certificate() ](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/iot.html#IoT.Client.delete_certificate)で forceDelete=Falseとしているため）
* モノにアタッチされていない=不要　とは限らないと思いますので、  
複数名でAWS IoTを使用している場合は、削除前に他のユーザーに確認を取ると良いと思います。


# 感想
めちゃめちゃ初心者なので、本当に些細なことでもご指摘・コメント等いただけますと幸いです。


# 参照
[Boto 3 Documentation](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/iot.html#IoT.Client.list_attached_policies)
Vue Packageのversionの違いによるエラーを解消する


##背景

LaravelにVueを導入し、いざ

```
$npm run dev
```
のコマンドを実行したものの


```
Vue packages version mismatch:

- vue@2.6.10 (C:\xampp\htdocs\hoge\node_modules\vue\dist\vue.runtime.common.js)
- vue-template-compiler@2.6.11 (C:\xampp\htdocs\hoge\node_modules\vue-template-compiler\package.json)

This may cause things to work incorrectly. Make sure to use the same version for both.
If you are using vue-loader@>=10.0, simply update vue-template-compiler.
If you are using vue-loader@<10.0 or vueify, re-installing vue-loader/vueify should bump vue-template-compiler to the latest.
```

このようなエラーが出て、実行ができなくなってしました。
エラーの原因が明確に表示され、解決方法も
vue-loader@>=10.0であればアップデートするだけだと
書かれているので簡単に解決できるのですが、vue-loaderやらvue-template-compiler
をなんだかあまり理解してないと
少しどうすればいいのかわからない部分もあったので記録として残しておきます。

##解決方法

上記にある

```
- vue@2.6.10
- vue-template-compiler@2.6.11
```
のバージョンの違いがあるとエラーになってしまうので
これを同じバージョンのする必要があります。

片方のバージョンを下げるのは更に手間がかかってしまうので
この場合だと、前者のほうをアップデートしました。
以下のコマンドでサクッと実行することができます。

```
$npm i vue
```

これで

```
$npm run dev
```

でのエラーを解決することができました。


npm関連のエラーに関しては以下の公式npmサイトを見れば非常に参考になるかと思います。

https://www.npmjs.com/package/vue
javascriptで複数の変数に同じ値を代入する方法

#はじめに
vue.jsでフォームの値を取得し、フォームのデータを作成。
最後にdataのプロパティの初期化処理をしたんですが、空文字の『""』を何度も代入するということをやっていました。
これだと取得するデータが増えるとものすごく単調な気がして嫌ですね。。

```javascript:main.js

this.newTitle = "";
this.newContent = "";
this.selected = "";
```

下記のように変更いたしました。

```javascript:main.js

this.newTitle = this.newContent = this.selected = "";

```

vue.jsではある処理をしてvueインスタンスにあるdataを初期化するという処理をよくすると思うんですが（多分。。）このようにすれば簡潔にかけるので良さそうですね。
javascriptに限る話ではないかもですが。
SlackにQiitaのデイリーランキングっぽいものを投稿するやつ

GASを使って、定期的に特定のSlackチャンネルにQiitaのストック数ランキングをPOSTするやつです
mohikanにいる人は、#qiita_top10_dailyみたいなやつを想像してもらえれば

Gsuite Developer Hubでプロジェクトを作り、以下のスクリプトをぶちこみます

``` javascript
function myFunction() {
  const slackToken = `${SLACK_TOKEN}`;
  const slackChannelId = `#${SLACK_CHANNEL}`;
  const slackApp = SlackApp.create(slackToken);
  const dateMargin = -3
  const createdAt = Moment.moment().add(dateMargin, "d").format("YYYY-MM-DD");
  const apiUrl = "https://qiita.com/api/v2/items"
  const query = "?page=1&per_page=100&query=stocks%3A%3E6+created%3A%3E" + createdAt;
  const options = {};
  var limit = 10;
  var res = UrlFetchApp.fetch(apiUrl + query);
  var json = JSON.parse(res.getContentText());
  var message = Moment.moment().format("YYYY-MM-DD");
  json = json.sort(function(a, b) {
    return b.likes_count - a.likes_count;
  });
  if (json.length < limit) {
    limit = json.length;
  }
    slackApp.postMessage(slackChannelId, message, options);
    for (i = 0; i < limit; i++) {
    message = "[" + (i + 1) + "] <" + json[i].url + "|" + json[i].title + ">";
    slackApp.postMessage(slackChannelId, message, options);
  }
}
```

SLACK_TOKEN と SLACK_CHANNELは適宜変更
トークンは`slack apitoken`などでググれば出てくるかと

dateMarginで、検索する記事の作成日を、「3日前から」にしています
当日や1日前では、スパム記事のようなものが多く微妙でした

状況に応じて、Slack書き込み用のライブラリを追加
Resources > librariesから追加できる
Find a Libraryに`M3W5Ut3Q39AaIwLquryEPMwV62A3znfOO`で出てくるはず

追加したら一旦テスト実行

POSTが確認できればOK
失敗した場合はトークンか、チャンネル名か、ライブラリを見直すと吉

実行を確認できたら、編集 > 現在のプロジェクトのトリガー
進んだページでトリガーの追加、実効間隔を設定して保存すれば終了です

あとは設定した間隔で実行されていることを確認すればおわりです

✌️
毎日のごはんを楽に記録する Part3

#はじめに
前回投稿した[毎日のごはんを楽に記録する Part2](https://qiita.com/kaji-tan/items/0abefd64410396dd7eec)の続きです。
今回は***「最近何食べた？」とSlackに書き込むと、過去2週間の夕食で食べたものリストを
botが返してくれる機能***を作ります。

#動作フロー
1. slackで「最近何食べた？」などの特定フレーズをOutgoing webhookでGAS(Google Apps Script)へ通知する。
2. [Part2](https://qiita.com/kaji-tan/items/0abefd64410396dd7eec)で作成したスプレッドシートの内容から、晩ごはんのリストを抽出する。
3. Slackに投稿するときに見やすい形にする。
4. Slackへ投稿する。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545683/a0a9d109-0af0-0e83-1608-46bdc19c9a0a.png)


#できるようになったこと
slackで「最近何食べた？」とつぶやくと、過去2週間の晩ごはんリストをbotが返答してくれる。

#関連箇所のコード抜粋
```Java:main.gs
//リスト出力要請があったらSlackへ出力
function ansEatList(){
  
  //必要情報の取得
  var today = new Date();                                                     //現在日付を取得
  var currentday = Utilities.formatDate(today,"JST","yyyy/MM/dd");            //日付を切り出し
  
  //listシートを指定
  var url = "https://docs.google.com/spreadsheets/d/XXXXXXXXXXXXXXX/edit#gid=0";
  var SpreadSheet_Input = SpreadsheetApp.openByUrl(url);
  var Sheet_Input = SpreadSheet_Input.getSheetByName("list");
  
  //最終行取得
  var lastrow = Sheet_Input.getLastRow();
  
  //さかのぼる期間を設定(とりあえず2週間)
  var startday = new Date(today.getYear(), today.getMonth(), today.getDate() - 14);
  
  //startdayからcurrentdayまでの晩御飯を取得して配列に格納する
  //格納用配列宣言
  var array = []; //date, menu
  
  for(var i = 2; i <= lastrow; i++){
    //まずD列の日付を見て対象期間かを判断する
    var setday = Sheet_Input.getRange(i, 4).getValue();  
    
    if(setday >= startday){
      //F列の分類を見て晩御飯かを判断する
      var setmenutype = Sheet_Input.getRange(i, 6).getValue();

      //晩御飯と判断して日付とメニューを配列へ格納する
      if(setmenutype.match(/晩/) || setmenutype.match(/夜/) || setmenutype.match(/夕/)){
        var setmenu = Sheet_Input.getRange(i, 2).getValue();
        var setday2 = Utilities.formatDate(setday,"JST","MM/dd");  
        var content = [setday2, setmenu];
        array.push(content);
        
      }else{
        //晩御飯でなければ何もしない
      }
    }else{
      //対象期間外なので何もしない
    }
  }
  
  //配列の中身を整えてSlackへ投稿
  var ret = "直近2週間の晩ごはんリストです。\n" + array.join("\n");
  postSlack(ret);
}
```


#得た知識
1. Outgoing webhookからの投稿は、トークンで見分けることができる。<br>
[参考サイト:SlackのOutgoing WebHooksとGoogleAppsScriptで簡単な会話botを作ってみた](https://qiita.com/pistaman/items/a542119ea28871960477)
2. 2次元配列の連結にはarray.joinが便利
3. 日付の比較にも演算子が使える
4. 2週間前の日付を取得するには、以下のように書けばよい。 <br>

```Java:date.gs
var startday = new Date(today.getYear(), today.getMonth(), today.getDate() - 14);
```
#追記
[Part4](https://qiita.com/kaji-tan/items/4b04d29121b27d3fd0ac)はこちらです。
meson で cmake プロジェクトを subproject として使う

## 背景

* ビルドシステムに meson を使っている
* submodule などで使う依存ライブラリが cmake しか対応していない

cmake の add_subdirectory のように, meson からも cmake プロジェクトを読み込んで利用したい.

## 方法

cmake のモジュールがあるのでこれを使います.

https://mesonbuild.com/CMake-module.html#cmake-subprojects
https://github.com/mesonbuild/meson/blob/master/mesonbuild/modules/cmake.py

### 変数をセットしたい

Is there any way to set cmake CACHED variable? #6345
https://github.com/mesonbuild/meson/issues/6345

`set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)` 相当もできます(meson cmake module ドキュメントにはちらっと書かれているだけでみおとしがち)
[エラーコード 0xC1900101 - 0x30017] Windows 7 を頑張って Windows 10 にアップグレードした話

# 概要
Windows 7 から Windows 10 へアップグレード中に**黒い画面から進まなくなる現象**が発生した場合，**BIOS の設定で Virtualization Technology を Disabled に**すればうまくいくかもしれない．

```:端末情報
製品名: dynabook R731/38DK
旧OS: Microsoft Windows 7 Professional
新OS: Microsoft Windows 10 Pro
```

# 詳細
[Windows 7 のサポートは2020年1月14日に終了](https://support.microsoft.com/ja-jp/help/4057281/windows-7-support-will-end-on-january-14-2020)する．しかし，実家の PC が Windows 7 のままだったので，下記を参考に Windows 10 へのアップグレードを試みた．

- [まだ可能！Windows 10 への無償アップグレード方法【2019年版】 – Hacker's High](https://hackers-high.com/windows/upgrade-windows10-for-free/)

正常にアップグレードが進むと思われたが，1回目の再起動の後，黒い画面から一向に進まなくなった．マウスを動かすとポインタは現れるので端末そのものがフリーズしているわけではなかったが，一晩放置しても変化は無かった．
そこで，電源ボタン長押しで端末を強制終了してアップグレードを取りやめ，電源ボタンを押して端末を再起動した．すると再び黒い画面から進まなくなったので，もう一度電源ボタン長押しで端末を強制終了し，再び端末を起動した．今度は画面に

>コンピュータに対する変更を元に戻しています...

というメッセージが表示され，しばらくすると Windows 7 が起動した．ログインすると次のエラーメッセージが表示された．

>0xC1900101 - 0x30017
BOOT操作中にエラーが発生したため、インストールはFIRST_BOOTフェーズで失敗しました。

![Windows 10 をインストールできませんでした](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478774/20101866-7ac7-745e-ce50-270e18152644.jpeg)

いろいろ調べて試した結果，BIOS の設定で **Virtualization Technology** という項目を **Disabled** に変更したら無事に Windows 10 へアップグレードすることができた．

![BIOS 画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478774/05b3abf3-fb57-b067-c127-acf1b30feb14.jpeg)

Windows 10 へアップグレード後，上記の設定を最初の状態 VT-x Only に戻したが，本記事執筆時点で特に問題は生じていない．

# 参考
- [【0xC1900101-0x30017】Windows10　イ ンストール中にエラーになる - マイクロソフト コミュニティ](https://answers.microsoft.com/ja-jp/windows/forum/all/0xc1900101-0x30017windows10-%E3%82%A4/fd7cb53b-d16e-4f81-a820-d4954fbdcb83)
bits/stdc++.hを入れたら「/usr/local/include/bits/stdc++.h:57:10: fatal error: 'cstdalign' file not found」が表示されてしまう

タイトルの通りです。
Macでbits/stdc++.hを導入してタイトルエラーが出てきた場合の対処法をメモします。

```bash
macbook:cpputil dynaonda$ g++ -std=c++14 main.cc 
In file included from main.cc:1:
/usr/local/include/bits/stdc++.h:57:10: fatal error: 'cstdalign' file not found
#include <cstdalign>
         ^~~~~~~~~~~
1 error generated.
```

# 対処方法

1. `stdc++.h`を下のリンク2からダウンロードします。
2. `/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1`にコピーします。
    3. インクルード先を変更しているならそちらにもコピーします。

これで解決しました。

# リンク

1. https://www.quora.com/The-header-file-“bits-stdc++-h”-is-not-working-on-my-OSX-How-to-make-it-work
2. https://gist.github.com/frankchen0130/9ac562b55fa7e03689bca30d0e52b0e5#file-stdc-h
Qiitaの投稿記事内でページ内リンクや目次リンクを行う方法

Qiita初心者で、Markdownを完全に理解していない人向けに、目次を作成し、目次が各章の文章にリンクされる方法を記載します。

結論から先に言うと、下記の黒いコードボックスのとおり書くと、ページ内リンクする目次が出来上がる。そのため、面倒な方は黒いコードボックスをコピペしていただき、内容を修正し、使用していただければ問題ありません。

- []の内容は何でもいい。記載した内容は目次一覧に表示される。
- ()の内容は各章の名前と同じにする必要あり。同じにすると目次と各章がリンクする。
　　※下の例で言うと、「#1. はじめに」と「(#1-はじめに)」を同じにする
　　※若干記載が異なるのは、ルールがあり半角スペースを「-」で表示するため

- 「#1. はじめに」以降の記載は、各章のタイトルを自由に記載すればいい。



```


#目次
[1.はじめに](#1-はじめに)
[2.内容い](#2-内容い)
[3.内容ろ](#3-内容ろ)
[4.内容は](#4-内容は)
[5.おわりに](#5-おわりに)

#1. はじめに
#2. 内容い
#3. 内容ろ
#4. 内容は
#5. おわりに

```
#目次
[1.はじめに](#1-はじめに)
[2.内容い](#2-内容い)
[3.内容ろ](#3-内容ろ)
[4.内容は](#4-内容は)
[5.おわりに](#5-おわりに)

#1. はじめに
#2. 内容い
#3. 内容ろ
#4. 内容は
#5. おわりに





#最後に

以上です。不明点や間違っている点があればコメントでおしらせください。
初心者のためのswift、Xcodeで画面遷移をする方法（アウトプット& 復習用)　

今回はxcodeでの画面遷移についてです
この情報はよく出回っていることだと思いますが、自分なりに書きました！
「なんで遷移するのか？」や、「なんでこのコード必要なの？」、などの説明は
この記事で説明しておりません！
画面遷移方法の一つを紹介する記事となっています！

<h1>Modalによる遷移</h1>

まずは最初にMainStorybordに遷移先のViewcontrollerをおきます！
（右上の十字マークのところから持ってきます）

次にcommand + N を押してCocoa Touch Classを選択します
<img width="747" alt="スクリーンショット 2019-12-29 20.36.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558816/0a701437-45a4-d86b-25da-84d4a8b28337.png">

その次に遷移先のviewcontolloer.swiftの名前を変更します。
私は適当に次の遷移先なのでNextViewControllerにしました！
SubClassは今回はUIViewControllerですので、そこも注意してください！

<img width="510" alt="スクリーンショット 2019-12-29 20.18.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558816/a106dcf7-1f59-1eb7-e4b2-4ef716d6fe50.png">

今回はボタンを押したら遷移するものとして
mainstoryboardの最初のviewcontrollerにボタンを起きましょう
自分はボタンの名前をNEXTにしました！
そしたらボタンをControl を押しつつ次の画面に引っ張って持っていきます。

 <img width="865" alt="スクリーンショット 2019-12-29 20.47.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558816/a05a804b-0a0f-b13e-64cc-1906f1ebee6c.png">

このようなことを言われるので、Present modallyを選びます！
showなど他のものもありますので、そちらは調べてみてください！
<img width="751" alt="スクリーンショット 2019-12-29 20.49.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558816/d18e27c4-9d19-f45b-2026-dc36483a2b6a.png">

すると、先ほどはviewControllerの間になかった矢印が出てきました！
これによりとりあえずボタンを押すとNextViewControllerには
遷移することができるようになりました！ビルドして試してみてください！
<img width="635" alt="スクリーンショット 2019-12-29 20.49.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558816/90542549-4351-7d80-54ab-ae80ae66526a.png">

ですが、このままでは戻ることができないので
今回はボタンで最初の画面に戻れるように
NextViewcontrollerにボタンを置いてみましょう！
わたしはボタンの名前を戻るに変更しました！
<img width="550" alt="スクリーンショット 2019-12-30 12.51.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558816/6b2500c9-d9d7-eef7-0063-3f6648830b8f.png">

そしたら、戻るボタンをIBActionでNextViewcontroller.Swiftのこーどに紐付けます！
下のこんな感じになってればOKです！

<img width="586" alt="スクリーンショット 2019-12-30 12.53.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558816/8c124abf-bab0-8427-4d64-0dee0eeb2492.png">
しかし、これではただ紐付けが、行われただけですので戻るボタンが押されても
元の画面に戻ることはできません！
なので、コードで少しこのように書いてみましょう。

<img width="643" alt="スクリーンショット 2019-12-30 13.03.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558816/c9e3fba8-1b11-9449-9c9b-51a8c56a156b.png">

書き終わりましたら、一回ビルドして
次の画面に遷移するか、元の画面に戻るか確かめてみてください。
どうですか？以外にも簡単に画面遷移ができましたよね？

今回はswift, Xcodeでの画面遷移方法の一つを紹介しましたが
他にも遷移する方法は他にもありますので、調べてみてください！

最後までありがとうございました！
クラスとオブジェクトの復習

```Python
class Enemy:
    def __init__(self, name):
        self.name = name
    def attack(self):
        print(str(self.name) + 'は勇者を攻撃した')

e1 = Enemy('スライム')
e1.attack()

enemies = []
enemies.append(Enemy('ガーゴイル'))
enemies.append(Enemy('ドラゴン'))
enemies.append(Enemy('魔人'))

for e in enemies:
    e.attack()
```

```:実行結果
スライムは勇者を攻撃した
ガーゴイルは勇者を攻撃した
ドラゴンは勇者を攻撃した
魔人は勇者を攻撃した

```
Nuxt.js graphQL の勉強素材

# 誰向けなの？？？
- Nuxt.js使ってなんかしてみたい
- GraphQLってなに？
- RESTなAPIを卒業したい

って人たち向けの記事です。勉強するときはググれば色々な記事が出てくるのですが、良さげな資料がまとまってる記事があると便利かなと思って作成しました。筆者本人がど初心者なので表記のミス等は許してください...!


# 背景
筆者が
- フロントエンド: Nuxt.js
- バックエンド: Rails
- API: apollo(GraphQL), Axios

で開発するプロジェクトに参加するために勉強する必要がありました。

今の世の中、色々なところに素晴らしい勉強素材があるので本当に助かります...

## Nuxt.js

### 概念
[REFFECT](https://reffect.co.jp/vue/nuxt-js-first-step)
さんの記事を色々と読みました。軽い演習もできます。この記事以外にもそもそものvue.jsの勉強素材もたくさんあり、非常に分かりやすくおすすめです。

### 演習
[FusicTechBlog](https://tech.fusic.co.jp/posts/2019-08-24-2019-08-25-rails-nuxt-graphql-todoapp/)
さんの記事内に書かれているtodoアプリの制作を行いました。これにはgraphQLの知識なども必要なので最後にやるといいかもしれません。

## GraphQL
一番理解するのが難しく感じました。そして今もそこまで理解できていない気がします。

### 概念
[公式ドキュメント](https://graphql.org/learn/)
がわかりやすく書かれています。英語もそんなに難しいものではないので気合いで読みました。

[blog.kymmt.com](https://blog.kymmt.com/entry/graphql-simple-queries-and-mutations-in-rails)
クエリの書き方やTypeの書き方等、飛ばされそうな細かい説明も書いてありとても助かりました。

[こちらの記事](https://qiita.com/sukechannnn/items/b2168d7214992e5d37bf)
Rails側でどのようにgraphQLを使うのかについて書かれています。

### 演習
[FusicTechBlog](https://tech.fusic.co.jp/posts/2019-08-24-2019-08-25-rails-nuxt-graphql-todoapp/)
先ほどNuxt.jsのところでも紹介した記事の前編です。RailsサイドでGraphQLを実装します。

## Axios
### 概念
[こちらの記事](https://qiita.com/ksh-fthr/items/2daaaf3a15c4c11956e9)
が図付きで説明されており、Axiosがどういうことをするために存在しているのかなどを理解しやすいです。

# 終わりに
まだまだ勉強途中ですが、上記の記事を読んだり演習することで最低限の知識くらいは得ることができた気がします。同じような境遇の方がいましたら参考にしていただけると嬉しいです。
パフォーマンスのために生まれたPHP Excel拡張機能xlswriter 1.3.3がリリースされました！

xlswriterは、Excel 2007+ XLSXファイルからデータを読み取り、複数のシートを挿入し、テキスト、数値、数式、日付、チャート、写真、ハイパーリンクを書き込むために使用できるPHP C拡張です。

以下の機能があります。

###### I.書き込み

100％互換性のあるExcel XLSXファイル
-完全なExcel形式
-セルの結合
-ワークシート名を定義する
-フィルター
-チャート
-データの検証とドロップダウンリスト
-ワークシートPNG​​ / JPEG画像
-大きなファイルを書き込むためのメモリ最適化モード
Linux、FreeBSD、OpenBSD、OS X、Windowsで実行
-32ビットおよび64ビットにコンパイル
-FreeBSDライセンス
-唯一の依存関係はzlibです

######次に、読みます

-データを完全に読み取る
-カーソル読み取りデータ
-データ型による読み取り
-xlsxからCSV

＃ベンチマーク

テスト環境：Macbook Pro 13インチ、Intel Core i5、16GB 2133MHz LPDDR3メモリ、128GB SSDストレージ。

#####エクスポート

> 2つのメモリモードで100万行のデータをエクスポートできます（1行あたり27列、データタイプは文字列、文字列の長さは19）

-通常モード：時間のかかる「29S」、メモリのみ「2083MB」が必要です。
-固定メモリモード：52Sのみ、メモリ<1MBのみ。

#####インポート

100万行を超えるデータ（単一行、1列、データ型はINT）

-フルボリュームモード：「3S」には時間がかかり、「558MB」のメモリのみ。
カーソルモード：時間のかかる「2.8S」、メモリのみ「<1MB」。

＃クイックスタート

##エクスポート

```php
$excel = new  \Vtiful\Kernel\Excel(['path' => '/home/viest']);

// fileName 会自动创建一个工作表，你可以自定义该工作表名称，工作表名称为可选参数
$filePath =  $excel->fileName('tutorial01.xlsx', 'sheet1')
    ->header(['Item',  'Cost'])
    ->data([
        ['Rent',  1000],
        ['Gas',  100],
        ['Food',  300],
        ['Gym',  50],
    ])
    ->output();
```

##インポート

```php
$excel = new \Vtiful\Kernel\Excel(['path' => './tests']);

$filePath =  $excel->fileName('tutorial.xlsx')
    ->header(['Item', 'Cost'])
    ->output();

$data = $excel->openFile('tutorial.xlsx')
    ->openSheet()
    ->getSheetData();

var_dump($data); // [['Item', 'Cost']]
```

# XLSXtoCSV [通常モード]

### 適用シナリオ

-より多くのxlsxファイルフラグメントを統合処理のために1つのCSVファイルにマージします。
-xlsxファイルは、タスク処理速度よりも速く追加されます。ファイルが非同期でCSVに変換された後、より効率的なツール（たとえば、データベースツールがCSVを直接インポートする）で処理できます。

### 例

#### demo.php

```php
$excel = new \Vtiful\Kernel\Excel(['path' => './tests']);

$filePath = $excel->fileName('tutorial.xlsx', 'TestSheet1')
    ->header(['String', 'Int', 'Double'])
    ->data([
        ['Item_1', 10, 10.9999995],
    ])
    ->output();

$fp = fopen('./tests/file.csv', 'a');

$resultBoolOne = $excel->openFile('tutorial.xlsx')
    ->openSheet()
    ->putCSV($fp);

$resultBoolTwo = $excel->openFile('tutorial.xlsx')
    ->openSheet()
    ->putCSV($fp);
```

#### file.csv

```csv
String,Int,Double
Item_1,10,10.9999995
String,Int,Double
Item_1,10,10.9999995
```

#Xlsx移行CSV [コールバックモード]

このアプリケーションシナリオは従来のモデルと似ていますが、上位レベルの企業はコールバック関数を使用してデータを処理し、xlsxを使用してデータをフィルター処理し、csvに書き込むことができます。

# ドキュメントの他の機能を見る

[https://xlswriter-docs.viest.me](https://xlswriter-docs.viest.me)

# 倉庫住所

GitHub：[https://gitee.com/viest/php-ext-xlswriter](https://gitee.com/viest/php-ext-xlswriter)

PECL：[https://pecl.php.net/package/xlswriter](https://pecl.php.net/package/xlswriter)

# 終わり

それがあなたを助けるなら、私に星をください
【Terraform】no matching Route53Zone found

Terraform で自動生成されていないホストゾーンを参照している時に出るエラーです。

```
data "aws_route53_zone" "main" {
  name = "example.com"
}
```

新規作成する場合は、resource を使う必要があります。

```
resource "aws_route53_zone" "main" {
  name = "example.com"
}
```
関数の復習

指定した数が、正の数か負の数か判定する関数

```py
def discri(a):
    if a > 0:
        return str(a) + 'は正の数です。'
    elif a == 0:
        return str(a) + 'はゼロです。'
    else:
        return str(a) + 'は負の数です。'

print(discri(15))
print(discri(0))
print(discri(-24))
```
15と0とｰ24を判定。
1-star seed search（ポケモン剣盾ツール）でHRESULT からの例外：0x8007007E を解決した話

「1-star seed searchでエラーが出て動かない。開発者さんのページの対処法を試しても無理…」という依頼がきた。
開発者さんが提示されている環境（Win64bit，.Net framework 4.6）にも問題はないのに，
確かにプログラムは動かない。
でも私に専門的な知識はない！！というところから試行錯誤のうえ解決できたので備忘録。

#やりたいことと解決法
 1-star seed search（ポケモン剣盾のツールらしい？）で発生するエラー HRESULTからの例外：0x8007007Eを解決したい。
→最新版のvisual C++ランタイムをインストールすればよい。
＊2019/12/30現在：(https://support.microsoft.com/ja-jp/help/2977003/the-latest-supported-visual-c-downloads)

#解決に至るまでの詳細
##問題が起きているPC
TOSHIBA Dynabook B350/56BR
OS:win10（win7をアップグレードしている）
.NET framework 4.7.2
→この間換装したやつ。（換装についてはこちら：[起動しないPCのクローンSSDをつくる](https://qiita.com/ayareily/items/e3c3fdde4bb85c9f1f05)）

##試行錯誤
###0.エラーメッセージ
DLL 'OneStarCalculaterLib.dll'を読み込めません。指定されたモジュールが見つかりません。（HRESULTからの例外:0x8007007E)

###1.依存関係を調べる
検索していくと，.dllには依存関係がある…ということがわかってきた。
たぶんここに何かある…気がするので調べるしかない。
Dependency Walkerを使用して調べることに。
**（依存関係は原因を調べるためのツールなので、解決策とは無関係です）**

参考：Dependency Walker(http://www.dependencywalker.com/)

###2..NET framework4.8を更新プログラムとしてインストール
依存関係を調べたところ，どうも原因が.NET frameworkが関係していそうだということがわかった。
.NET frameworkをいろいろな方法でインストールしてみたが，どれもいまいち依存関係のエラーはなくならない。
同じバージョン(4.7.2)で…と思ってこだわっていたが，もうどうしようもないのでwin10の更新プログラムとしてインストールすることにした。
該当する更新プログラムはKB4486153。

再び依存関係を調査したところ，少し減っていることが判明。
だがまだエラーで動かない。
エラーは同様（HRESULT からの例外：0x8007007E）。
どこがエラーを起こしているのかDependency Walkerで調べてみると，どうもvisual C++あたりも怪しそう。

###3.Visual C++ランタイムをインストール
インストールされているVisual C++を調べてみると，2008までしかない。
これだと新しいプログラムを入れたときにまた何か起きそうなので，とりあえず片っ端からインストールすることに。
ダウンロードできる場所が窓の杜にまとまっていて，とても助かった。
（ここを使いました：[【無料】アプリケーション向けランタイムのソフト一覧 - 窓の杜](https://forest.watch.impress.co.jp/library/nav/genre/arc/runtime_runtimeapp.html)）
もうリンク切れのものもあったので，それは諦めた。
リンクが繋がっているものはx64，x86ともにインストール。
結局2008〜2019まで全部入れた。
（2015〜2019までは一つにまとまっているようで，一括で入れました）
**→ランタイムは下位互換性があるから最新版を入れると不要との助言あり**

###4.動いた
再びDependency Walkerで検証。
だいぶエラーが減ったので，「もう私の知識では限界ゾ」と思いつつ動かしてみる。
と，無事動いた。

#最後に
専門的知識ゼロ，Google先生に頼り切りでしたがなんとか動いたのでヨシ！というところ。
これを解決するのに丸2日くらいかかっております。
おそらく専門の方からするとずいぶん無理やりやっているような感じなのではないかと。
もしかすると.NET frameworkのインストールいらないのでは？とも思うけどよくわからない…。

参考になる方がいらっしゃれば幸いです。
selenium/pythonだってAzure DevOps pipelineでヘッドレス実行したいよね？そうだよね？

本投稿は[Azure DevOps Advent Calendar 2019](https://qiita.com/advent-calendar/2019/azuredevops)の21日目の投稿になります。

DevOpsを推進するうえで重要な要素となる自動化ですが、様々な方法が考えられますし、組織に応じて導入を進めていく必要があります。組織のカルチャーを無視してコンセンサスが得られない状況で独自のツールが乱立してそれが運用に与える効果を測ることができればいいなと考えているsasukehです。皆様いかがお過ごしでしょうか？

巷では、seleniumを使って自動化という記事がかなりの数上がってくるようになりました。その効果もあり、WebのE2Eテストをseleniumで自動化するというかたも増えてきているように思えます。Test Driven Developmentもめちゃくちゃ重要でソフトウェアを検証、計測することで、その開発が正しい方向を向いているかの指標となります。なので、TDD始めましょう！というのは簡単だけど、じゃあどうすればいいの？という目的はわかったけど、手段がわからないという状況にいる方もいるのでは？と思います。とくにAzure DevOpsを使ってSeleniumでUIのテスト自動化したいけど、やっぱりagentにGUIが必要で、CLIは向いてないよね？みたいな解釈をしているかたがいらっしゃいますが、実は、seleniumには、headless実行と呼ばれる、GUIなしで実行する方法があります。また、Screenshotも取れるので、ZipでまとめてBlobでアップロードする方法もあります。

今年の初め頃に社内のチームメンバーとハッカソンしたときのコードなりtipsがあったのですが、なかなか公開できていなかったので、今日これをまとめようと思います。

# はじめる前に
pythonでseleniumを動かすTipsについては、Qiitaの記事をいくつか参考にすれば実行できると思いますので、今回は、Azure DevOps Agent（Microsoftが提供するHosted Agent）に対してSeleniumを実行する環境を整えるという内容にします。
また、Windows/Linux Agentでの例については、はまりどころが少ないと思うので、Mac Agentを使った例を紹介したいと思います。

<!-- 追加項目：Agentのタスクの指定方法 -->

# pipelineでのタスクについて
Agentに対していくつかのパッケージをインストールする場合には、Bashのスクリプトを経由し、brewでパッケージをインストールすることができます。また、caskを使うことでchrome driverなどをインストールすることができます。

実際のタスクは、下記の図のように、Agent jobにbash scriptを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55285/5e0f50b6-9f2b-541e-4c9d-62a529dc2502.png)

Bash Scriptは、Fileを指定する方法とインラインでスクリプトを用意する方法があります。
Azure DevOpsをブラウザーから使うユーザーは、ブラウザから編集することができ、ソースコード管理をしている場合、リポジトリから、このスクリプトを参照させることができます。

# 実際のスクリプトについて
```bash
echo "=============== Install apps ===============" # 手順1
brew update
brew tap caskroom/cask 
brew cask upgrade
brew cask install chromedriver
brew cask install xquartz 
brew cask install google-chrome
brew cask upgrade
brew cask list 

echo "=============== load X process ===============" # 手順2
sudo launchctl load -w /Library/LaunchAgents/org.macosforge.xquartz.startx.plist

echo "=============== install python dependency ===============" # 手順3
pip3 install -r $(System.DefaultWorkingDirectory)/_work/s/requirements.txt

```

<!-- 追加項目：手順1の説明 -->
<!-- 追加項目：手順2の説明 -->
<!-- 追加項目：手順3の説明 -->
一行が長く改行したいとき

```
s = 'aaaaaaaaaaaaaaaaa' \
    + 'bbbbbbbbbbbbbbbbbbb'
```
頭に「+」があるとエラー
末尾に「\」を入れて次の行に続くと伝える。

もしくは、

```
s = ('aaaaaaaaaaaaaaaaaaaaa'
    + 'bbbbbbbbbbbbbbbbbbbbbb')

x = (1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
    + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1)
```
と()で囲む。

インデントはスペース4つ
Zynqberryを入手したら最初に行う10のステップ(後編)

Raspberry Pi形状のZYNQボード「Zynqberry(ジンクベリー)」でUbuntu18を使うための手順の続きです。
# OSインストール後の各種設定
## 無線LANの使用
2019年12月以降に出荷されたZynqberryスタータキットには、ElecomのWDC-150SU2Mが付属しています。2019年11月以前はGW-USNANO2Aでした。

WDC-150SU2MをARMの組み込みLinuxで使うにはUbuntu 14(wpasupplicatを使っていた)ではだめで、Ubuntu 18にアップグレードしてnmcliを使う必要があります。
WDC-150SU2Mの場合は以下の手順でドライバを使用可能にします。

```
insmod /lib/modules/4.9.0-xilinx-00027-g9c2e29b/kernel/drivers/8188eu.ko
```

この状態で
```nmcli device wifi```
と入力すると、検出されたWifiの一覧が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/4f3edaca-3673-da51-f08e-2c564716c13a.png)

無線LANを有効にするには、USB LANアダプタを挿し、

```
nmcli device wifi connect [SSID] password [パスワード]
```

を入力します。
これでZYNQのLinuxから無線LANが使えるようになります。

`ip a`コマンドで見てみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/6a83e6b2-3c18-e877-306a-5a05de68a367.png)

## sttyで画面のサイズを変えよう
TeraTermの画面を大きくしてUSB(COMポート)経由で操作していると、emacsやtop、psなどのコマンドの出力が乱れます。それだけではなく長いコマンドを打ってBackSpaceで編集するだけでも画面が乱れます。**SSHでログインした場合には乱れませんが、組み込み開発ではやはりCOMポートは便利なので。**

なぜ乱れるのかというと、COMポート経由では端末の画面サイズをOSに知らせることができないためです。

TeraTermのサイズは[設定(S)]->[端末(T)]で確認でき、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/99fe31f3-23e9-5726-dcb6-9ed625c3a496.png)
sttyコマンドを使ってLinuxに現在の端末のサイズを教えます。

```
stty cols 146
stty rows 34
```
これで画面の乱れはなくなります。

## SDカードの第一パーティションの中身を見るには
第一パーティションにはデバイスツリーなどが入っています。
この中身をLinuxで見るには、
```mount /dev/mmcblk0p1 /mnt/```
で見れます。
/etc/fstabに書いてしまってもいいでしょう。

```:/etc/fstab
# UNCONFIGURED FSTAB FOR BASE SYSTEM
/dev/mmcblk0p1 /mnt
```

## ツールのインストール
組み込みシステムらしい様々なことを試すには、デバイスツリーコンパイラやGCCが必須です。以下のコマンドでインストールします。gitで配布されているモジュールをインストールするためにもgitは必要でしょう。

```
apt install device-tree-compiler
apt install gcc
apt install git
```

# FPGAをコンフィギュレーションするには
Zynqberryのカーネルは4.9なので/dev/xdevcfgが使えます。/dev/xdevcfgを使うのが便利です。

```
cat bitstrem-file-name.bit > /dev/xdevcfg
```

# デバイスツリーをいじるには
様々なデバイスの実験をするには、デバイスツリーの書き換えが必要です。

まず、現在のデバイスツリーからソースを作ります。

```
dtc -I dtb -O dts /mnt/devicetree.dtb > /mnt/devicetree.dts
```
そして、編集したあと。

```
dtc -I dts -O dtb /mnt/devicetree.dts > /mnt/devicetree.dtb
```
でバイナリに戻します。

# USBメモリを参照するには
Zynqberry + Ubuntu18はUSBメモリを使用できます。
以下のようにマウントすることで/mntフォルダにUSBメモリの中身が現れます。

```
mount -t vfat /dev/sda1 /mnt/
```
# jupyterを起動するには

```
jupyter notebook --allow-root &
```
で起動でき、http://zynqberry:8080/ でアクセスできます。
numpy pandas matplotlib seaborn scikit-learn plotlyが使えるのででPythonの練習もばっちりです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/f7543ba8-086a-6314-2976-4d5eb6dda7a5.png)

# 最後に
私はZynqberryをRasPiケースに入れ、かれこれ1年以上自宅サーバとして活用しています。VPNをはったり、DDNSに通知したり、cronで定期的にルータをチェックしたり・・。
最近ではMySQLとPHPを入れてデータベースアプリを作る練習にも使っています。

ZynqberryのARMは666MHz動作のデュアルコアなので、ネットワーク管理や簡単なデータベースアプリ程度であれば、十分なスペックのサーバとして利用できます。

最近はLinuxカーネルを4.19にアップデートする準備をしていますが、xdevcfgが使えないのでどうしたものかと悩んでいます。
【AWS】サービス一覧をまとめてみた

●初めに
SAA受験でAWSのサービスを学習したので、備忘としてまとめたいと思います。

●EC2

●Lambda
△what
インフラを一切気にすることなく、アプリケーションコードを実行できるコンピュータサービス
　-実行基盤はAWSが管理
　-AWSサービスと連携可能
　-コード実行時間に対しての従量課金

△why
ビジネスロジックのみに集中できる
→インフラを考慮しなくて良い為

オートスケール可能
→イベントの発生頻度に合わせて自動でスケール

△how
コード
→JavaScript（Node.js）,JAVA

メモリ
→Node.jsは128MB,JAVAは512MB

タイムアウト
→Node.jsは3秒,JAVAは15秒
→最大60秒

実行環境
→それぞれが隔離されたコンテナで実行
コメントアウト

```Python
print('#######')
# test
"""
test
test
test
""""
print('#######')
```

複数行にわたってコメントする場合は、

```Python
"""
test
test
"""
```

の様に"""で囲う。

```Python
#A pple price
a_p = 100
```
pythonではコメントを上に書く事が多いらしい。
MacからRPAのBot編集、実行をしてみた with Automation Anywhere A2019 Community Edition

Automation Anywhereの次世代RPA、A2019ですが、マルチOSを売りにしています。
ただ、今まで個人的にMacを今まで使ったことが無かったこともあり、本当にMacで使えるのか想像がつかず。

ということで、MacBook Airを買ってきて、実際にやってみました。
（この記事もMacで書いてます。）

#試した環境
Automation Anywhere A2019 Community Edition
Surface Pro Model 1796
MacBook Air 2019
Google Chrome (Mac)

#使用したBot
[Ryokoさん](https://twitter.com/RPA_Journey) が考えた、鳥獣戯画のカエルに波動拳を撃たせるBotをAutomation Anywhereで作ったものを使用。
Mac上でGoogle Chromeをインストールし。Control Rooom(サーバー)にログインした図。
こんなBotを使います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490870/d0d8ef73-bdbe-1724-ff8e-a6fc46920754.png)

#機器の構成

| 機器/役割       |    概要    |
|:-----------------:|:------------------:|
| Control Room (サーバー)| Botの管理・実行スケジューリング等に使う。A2019 Community Editionの場合、機能制限されたものをAutomation Anywhereがクラウドで提供。|
| Surface Pro（Attended Bot Runner)|ロボットが実際に実行される環境。|
| MacBook Air (Bot Creator)|ロボットを開発する環境。|


Botのソースファイル自体はControl Room上に格納されます。

#試した手順
1. Macを買う
2. Google Chromeをインストールする
4. Surfaceを起動。A2019 Community Editionにログインし、BotAgentをインストールしてAttende d Runnerとしてサーバーに繋がれた状態にしておく。
5. Mac側のGoogle ChromeでA2019 Community Editionにログインし、予め作っておいたBotを実行する。

#実行処理の流れ
図を描いてみました。
こんな感じで、Mac上で編集されたBotはクラウド上にあるControl Roomに格納され、
実行指示を出すとControl Room上に格納されたBotが実行環境であるBot Runnerにダウンロードされ、実行されます。
実行環境側で今まで使用したことがないコマンドがあれば、そのコマンド自体もBotのソースファイルと一緒にダウンロードされて、実行されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490870/6fe2c70c-fd83-34be-117b-1b7727c24376.png)

#試した結果
実際実行するところをビデオで撮影しておきました。
左がSurface Pro、右がMacBook Airです。
[![A2019で作成したBotをMacBook Airから実行する](http://img.youtube.com/vi/-J3Juap2_88/0.jpg)](http://www.youtube.com/watch?v=-J3Juap2_88)

上記の他に、実際にMacでBotの開発は可能なのか？というのも試してみました。
現在、macOS用のBot Agentはリリースされておらず、macOS上のアプリケーションの自動化は出来ませんが、Windows OSの入った実行機を別に用意しておけば、開発自体は出来そうです。
ただ、実行機として設定したWindows PCを横に置くか、リモートデスクトップで繋いで切り替えながら作業する必要があります。
（Recorderやローカルファイルの選択、Windowの選択といった項目は、Macで開発していても、実行環境のWindows PC側でダイアログが出る。）

#まとめ
MacBook AirからBotの実行（実行指示）を出して、 Windows PC上でBotを実行させることが出来ました。

MacでのBot開発についても実行機（Windows)を用意しておけば充分出来る感触でしたので、
今度気が向いたらそちらの実験＆レポートもまとめてみたいと思います。