OmniAICreator/Qiita-1.07M huggingface dataset:
Dockerイメージを対話的に削除する

気がつくと古いDockerイメージがたまってくるので、対話的に削除するシェルスクリプトを作成。`docker image prune`または`docker system prune`と合わせて使うと便利かもしれない。

```shell
#/bin/bash

for image_str in $(docker images --format "{{.Repository}}:{{.Tag}}_{{.ID}}")
do
  while true
  do
    id=${image_str#*_}
    image=${image_str%_*}
    tag=${image##*:}
    read -p "${image}    delete? (y/n/a):" yn
    case $yn in
      [yY]*)
        if [ ${tag} = "<none>" ]; then
          docker rmi ${id}
        else
          docker rmi ${image}
        fi
        echo "deleted"; echo ""; break ;;
      [nN]*)
        echo "not deleted"; echo ""; break ;;
      [aA]*)
        echo "abort"; echo ""; exit ;;
    esac
  done
done
```

```shell-session:実行例
$ ./docker-image-cleaner.sh
sotoiwa540/qiita-checker:1.1    delete? (y/n/a):n
not deleted

python:3-alpine    delete? (y/n/a):n
not deleted

python:3    delete? (y/n/a):n
not deleted

websphere-liberty:18.0.0.4-kernel    delete? (y/n/a):n
not deleted

sotoiwa540/qiita-checker:<none>    delete? (y/n/a):y
Untagged: sotoiwa540/qiita-checker@sha256:d63ae4540f58c350193c8c636068e4caf72e00feb779fc626f6fd0adfbd98286
Deleted: sha256:2dfc9b8592bba73fc50ae4217df19e4e89b272c50f32b7491d03a9febc17e3ec
Deleted: sha256:17e767783cad1be9e2c81baf4e073cab51737c93503326114a7cfcf3cab68c11
Deleted: sha256:271a6c0d66359aec911a079c67039f5c79568e5c65a2d4a4d592ed212113fab9
Deleted: sha256:9ed64b9fca76020a3eb153a27a66088a38d4174d05ad4425ff7e79b9be1992f9
Deleted: sha256:8a46f8cc49d88d47db4cade46c82ab962da5a027e5e41702936e258b6c1a686d
deleted

busybox:latest    delete? (y/n/a):y
Untagged: busybox:latest
Untagged: busybox@sha256:7964ad52e396a6e045c39b5a44438424ac52e12e4d5a25d94895f2058cb863a0
Deleted: sha256:3a093384ac306cbac30b67f1585e12b30ab1a899374dabc3170b9bca246f1444
Deleted: sha256:683f499823be212bf04cb9540407d8353803c25d0d9eb5f2fdb62786d8b95ead
deleted

$
```
win10でバーチャルボックスでubuntuを使用してます

win10 本体はwifiで接続してます

本体のネットワーク接続を off で

バーチャルボックスのみネットワーク接続を on にしたいです

web検索してもわかりません

ですので、ご回答よろしくおねがいします
【c#】型制約を用いてEnumからDictionaryデータを作成する汎用メソッドを作ってみた

#概要

c#側でWebAPIを用いて外部サービスにアクセスしようとした時に、クエリに渡す文字列を直打ちするのはIDEのIntelligenceも聞かなく誤入力が起きると予想しました。なのでDictionary<Enum,string>の形にして、stringの部分にEnumを文字列にしてから小文字に変換したものを入れようと考えましたが、Enumを作るごとにDictionaryを直打ちするのは大変なので汎用的メソッドを作ってみました。

C#のバージョンはEnumの型制約がC#7.3以上でないと使えないので7.3以上を想定しています。

```c#

public enum Filter
{
    All,
    Closed,
    Members,
    Open,
    Organization,
    Public,
    Starred,
}

//Enumを作るごとにこれをコピペして中身を書き換えるのは大変
private static Dictionary<Filter, string> Filters = new Dictionary<Filter, string>
{
    {Filter.All, "all"},
    {Filter.Closed, "closed"},
    {Filter.Members, "members"},
    {Filter.Open, "open"},
    {Filter.Organization, "organization"},
    {Filter.Public, "public"},
    {Filter.Starred, "starred"},
};

```

#実装

まずEnum.GetValuesでEnumに限定したT型の要素を取ってきます。
そのままだとobject型なのでOfType<T>でT型に変換して、KeyにTを、ValueにT型を文字列にしてさらに小文字に変換したものを渡して終了です。

```c#:EnumExtend.cs

public static Dictionary<T, string> CreateEnumDictionary<T>() where T : Enum
{
    var values = Enum.GetValues(typeof(T));
    return values.OfType<T>().ToDictionary(key => key, value => value.ToString().ToLower());
}

```


#参考
https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/keywords/where-generic-type-constraint
kurbernetesで本番環境構築を目指す - ネットワークセキュリティ編 -

# はじめに
docker+kubernetesでwebアプリケーションが動く環境がとりあえず構築したのはいいけれども、ネットワーク的に安全なのか不明だったので調査しました。

### システム構成
システム構成はこんな感じです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/271751/05ded075-8340-ff97-6df5-12518b5a5f13.png)

# 1. IPアドレスとポート開放状況
外部から接続可能なIPアドレスとどのポートが解放されているか調べます。

#### 1.1 結果
- 外部公開されているIPは4つでした。
    - ingress : webサーバー手前の負荷分散
    - kubernetes関連API : kubernetesを動作するのに必要なもの
    - node A : node１つ目
    - node B : node２つ目
- 外部公開されているTCPポートもおおむね期待値通りだが、ingressが不要なポートを開放しすぎています。（443だけでいいのに。）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/271751/1c2c839b-e840-8769-db2c-7921fd9bfb10.png)

- serviceとpodはそれぞれ直接通信できないし、ingressへのhttp通信はどうやってpodにアクセスしているのかよくわかりませんでした。
- nodeについてはsshの対策はする必要があるものの、直接は攻撃できなさそうです。
- dockerやkubernetes経由で攻撃されるところを防ぐ必要が大いにありそうです。

#### 1.2 調査方法

ping, route, ifconfig, nmapを駆使して調べました。

ping

    $ ping 10.146.0.4
    10.146.0.4 に ping を送信しています 32 バイトのデータ:
    要求がタイムアウトしました。
    要求がタイムアウトしました。
    要求がタイムアウトしました。
    要求がタイムアウトしました。```

nmap 

    $ nmap -P0 34.85.112.**
    Not shown: 998 filtered ports
    PORT     STATE  SERVICE
    22/tcp   open   ssh
    3389/tcp closed ms-term-serv```

ifconfig

    Node A ~ $ ifconfig
    cbr0: flags=4419<UP,BROADCAST,RUNNING,PROMISC,MULTICAST>  mtu 1460
        inet 10.52.1.1  netmask 255.255.255.0  broadcast 0.0.0.0
        ・・・
    docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 169.254.123.1  netmask 255.255.255.0  broadcast 0.0.0.0
        ・・・
    eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1460
        inet 10.146.0.4  netmask 255.255.255.255  broadcast 10.146.0.4
        ・・・
    lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        ・・・

# 2. 対策
思ったよりも外からアクセスできる状態になっていなかったので、特にありません。pod間通信を制御しようと思ったらNetwork Policyを使ってやるみたいだけど、今はやらないでおきます。
本当に本番環境作ろうと思ったら、手前にwafとかips・idsとか入れないとだめなんでしょうね。
【C#】文字列中の数字の順に並べ替える方法

「第3番」や「4位」など文字列中に数字が含まれる値のリストがある時、文字列中の数字を使って配列やリストを並べ替えたい時が稀にありますが、そのまま文字列でソートすると「文字コードの順」にソートされてしまいます。
そこで今回は、「文字列中の数字の順に配列やリストを並べ替える方法」を紹介します。


# コード

* LINQを使って3段階で処理をしています。
 1. 最初のSelectメソッドで、listから得られた名称（Name）に加えて、名称中の数値部分（Index）という値の2つを保持した匿名クラスを作ります。
 2. 次にOrderByメソッドを使い、作成した匿名クラスの数値部分（Index）を使って昇順でソートします。
 3. 最後に再びSelectメソッドを使い、匿名クラスの名称（Name）部分だけを抽出して、名称（Name）部分からなるリスト（IEnumerable）を作ります。
* もっとスッキリした書き方が他にもあるかもしれません...

```c#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Samples
{
    class OriginalSort
    {
        /// <summary>
        /// ソートする配列。
        /// </summary>
        List<string> titles = new List<string> { "第17番", "第1番", "第2番", "第16番", "第5番" };

        /// <summary>
        /// 「第1番→第2番→第5番→第16番→第17番」というように、文字列中の数字の順に並べ替える。
        /// </summary>
        public void Sort()
        {
            // {Name,Index}という匿名クラスのリストを作り、Indexに従ってソートする。
            var list = titles.Select(title => new { Name = title, Index = ToInt(title) })
                .OrderBy(title => title.Index).Select(title => title.Name);

            System.Console.WriteLine("[結果]" + string.Join("→", list));
        }

        /// <summary>
        /// 引数の文字列から数値部分だけを抜き出して返す。
        /// </summary>
        /// <param name="txt">「第3番」や「4位」など、数値部分を含む文字列。</param>
        /// <returns>抜き出された数値部分。</returns>
        public int ToInt(string txt)
        {
            return int.Parse(Regex.Replace(txt, @"[^0-9]", ""));
        }
    }
}
```


# 実行結果

* OriginalSort#Sort()を実行すると、以下のように文字列中の数字の順に並べ替えた結果が得られます。

```
[結果]第1番→第2番→第5番→第16番→第17番
```
[Travis CI] ビルドに成功しているのにバッジが build unknown のまま

**:warning: DEPRECATED (2019.07.06) :warning:**
CI環境として自前のDockerイメージを指定出来るCircle CIなどのツールの方が有用と判断したため本記事は有用性を失っている。

---

Travis CIのダッシュボードからビルド情報を確認すると、ビルドが成功していてもバッジが `build unknown` になっている。

<img width="536" alt="Screen Shot 2019-01-27 at 23.37.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/336527/060a166a-5942-aaa6-039e-439f583bae23.png">

しかし、バッジをクリックして表示される画像のURLへ飛ぶと `build passing` と書かれたバッジが表示される。

<img width="649" alt="Screen Shot 2019-01-27 at 23.46.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/336527/f8a41d43-6bb6-e4cc-0bbf-0d1f4693cd14.png">

<img width="500" alt="Screen Shot 2019-01-27 at 23.56.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/336527/0b475945-1d33-ed75-799a-b80064763f8c.png">

設定に不備があるのかと疑ってしまうが、ビルド結果がバッジに反映されていないだけである（1分以上要しているだろうか）。
HTML&CSS中級編を終えて

[未来電子テクノロジー](https://www.miraidenshi-tech.jp/intern-content/program/)でインターンをしているtsuyoshi514です。

#背景画像の使用
1.背景画像の指定
背景画像を使うにはまず使いたい背景画像を指定しなければなりません。そこで使用するのが、**background-image**というプロパティです。**background-image:url();**のように使ってきます。この()の部分に画像のURLを選択すると画像が表示されます。

2.背景画像の大きさ
そして次は背景画像の大きさですが、こちらは**background-size**を使用することで調整することができます。ただ大きさが合わないと画像が繰り返されることになるので、それを回避するためにbackground-size:cover;を使用することをおすすめします。

#要素の透明化や文字の間隔
1.要素の透明化
要素の透明化はその名の通り選択した要素を透けさせることができます。透明化させるためには**opacity**を使用します。こちらの数値は0.0～1.0まであり、数値が低くなるほどどんどん透明になっていきます。
2.文字の間隔
はい次は文字の間隔についてです。文字の間隔を指定するためには**letter-spacing**を使用します。こちらは数値を大きくすればするほど文字の間隔も大きくなります。

#インラインブロック要素と複数クラスの選択のやり方
1.ブロック要素からインラインブロック要素へ
aタグのようなブロック要素には高さや幅を指定できず不便な時があります。そこで使用するのが**display**です。displayを使用することで高さや幅を指定することができるようなります。

2.複数クラスを選択する方法
そしてこれは効率化の話ですが、複数クラスの選択の方法です。これはものすごく簡単で、"hh gg"のように**間にスペースを付けるだけ**で複数クラスを選択することができます。

#カーソルがのった時のcssやテキストの位置、角を丸める方法について
1.カーソルがのった時のcssの指定
カーソルに乗った時に変化を起こすために**hover**というセレクタを使います。これを利用することでカーソルがのった時のcssを指定することができ、変化を起こすことが可能です。

2.テキストの位置
そしてテキストの位置を指定するためには**text-align**というプロパティを使用します。これを使用することでテキストの位置右、中央、左のいずれかに指定することが可能になります。

3.角を丸くする方法
そして次は送信ボタンなどの角を丸くする方法です。これは**border-radius**というプロパティを使用します。これも数値を指定することでどれだけ角を丸くするかを指定することが可能になります。

#Font Awesomeを使用したアイコン
今回はFont Awesomeを使用してアイコンを指定します。Font Awesomeは、以下の手順で使用することができます。手順としてはFont AwesomeのCSSファイルを読み込み、spanタグにfaクラスとfa-アイコン名クラスを指定することで簡単にアイコンを使用することができます。

#opacityとrgba
opacityには選択した要素を全て透明化してしまい、うまくいかないことがあります。そこで利用すると便利なのが**rgba**です。**rgba**を使用するとその色だけを透明化させることができるので、テキストなどが一緒に透明化することがありません。数値は0～1で選択することが可能です。

#文字の太さの指定と相対的な数値の指定
1.文字の太さの指定
文字の大きさの指定には**font-weight**を使用します。文字を太くしたい場合には**bold**、普通の太さにしたい場合は**normal**を指定しましょう。
2.相対的な大きさの指定
相対的な数値を指定するためには数値を%で表すと相対的な数値にすることが可能です。レイアウトを整える上でとても便利になります。

#基準位置の変え方などについて
positionを使用することで要素同士を重ねたり、基準位置の変更したりすることが可能になります。例えば、position:absolute;を使用する要素同士を重ね合わせることが可能となります。またposition:relative;では要素の基準位置を変更することができます。

#要素の固定の仕方
スクロールしても要素を固定するためにはposition:fixed;を使用します。これを使って数値を指定するとその位置で固定することができます。また、要素の重なりの順番を指定するためにはz-indexを使用します。これはpositionと併用必須なことに注意が必要です。
Windows環境のVagrantに、Ubuntuデスクトップ環境を構築する


もともとUbuntuデスクトップ環境を使っていたのですが、Vagrantに乗っけられると便利だなと思ってやってみました。

# 環境
ホストOS:Windows10 64bit
ゲストOS:Ubuntu-18.04
VirtualBox：5.2.24
Vagrant：2.2.3

#事前準備
Vagrant、VirtualBoxをインストールしておいてください。

# Ubuntu環境を作る

```bash
vagrant init bento/ubuntu-18.04
```

# GUI用にVagrantファイルを編集する

GUIを使うために、Vagrantファイルを修正します。

編集前

```bash
  # config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
  #   vb.memory = "1024"
  # end
```

編集後

```bash
  config.vm.provider "virtualbox" do |vb|
    vb.gui = true
    vb.memory = "4096"
    vb.cpus = 2
    vb.customize [
      "modifyvm", :id,
      "--vram", "256",
      "--clipboard", "bidirectional",
      "--accelerate3d", "on",
      "--hwvirtex", "on",
      "--nestedpaging", "on",
      "--largepages", "on",
      "--ioapic", "on",
      "--pae", "on",
      "--paravirtprovider", "kvm",
    ]
  end
```

# Ubuntuを起動して、いろいろ設定する

VagrantのコマンドでUbuntuを起動して、SSHします。
しばらく時間がかかるので待ちます。

```bash
vagrant up
vagrant ssh
```

sshでUbuntuに接続できたら、まずは日本のパッケージリポジトリを追加

```bash
wget -q https://www.ubuntulinux.jp/ubuntu-ja-archive-keyring.gpg -O- | sudo apt-key add -
wget -q https://www.ubuntulinux.jp/ubuntu-jp-ppa-keyring.gpg -O- | sudo apt-key add -
sudo wget https://www.ubuntulinux.jp/sources.list.d/xenial.list -O /etc/apt/sources.list.d/ubuntu-ja.list
```

次にパッケージを更新

```bash
sudo apt-get update
sudo apt-get upgrade
```

で、Ubuntuデスクトップをインストール。すごく時間がかかります・・・

```bash
sudo apt-get install ubuntu-desktop
```

終わったら、rebootして、VirtualBox側で、コンソールを表示。
![image](https://qiita-image-store.s3.amazonaws.com/0/132118/d4a833b3-5d6f-f9d8-2a28-9c0501d12640.png)

無事できました。あとは日本語化だな。

# 参考
このあたりのページを参考にやってみました。

[WindowsにVagrantとVirtualBoxを使ったUbuntu GUI開発環境を構築する](https://techracho.bpsinc.jp/anekawa/2017_12_25/50414)
[Windows環境にVagrant+Ubuntuデスクトップ環境をインストール](https://qiita.com/mhagita/items/8f339106c3b48eb098ca)
[Ubuntu14.04 + GUI を vagrantを使って弄りたい](https://qiita.com/kayo-tozaki/items/50ec737f01561f0ece81)
SPA（Vue.js）でGooleMapAPIを導入する方法

インスタンスのcreated時にライブラリを読み込み、destroy時にgoogleオブジェクトを空にしてあげると下記のエラーは回避できる。
`You have included the Google Maps JavaScript API multiple times on this page. This may cause unexpected errors.`

SPA実装していてindex.htmlにscriptタグを書きたくない人はこれで良い。

```vue:GoogleMap.vue
<template>
  <div id="map"></div>
</template>
<script>
import { GOOGLEMAP_API_KEY } from "@/common/config";
export default {
  name: "GoogleMap",
  data() {
    return {
      map: null,
      mapPosition: {lat: 35.658034, lng: 139.701636}
    };
  },
  methods: {
    loadJS(src) {
      const ref = window.document.getElementsByTagName("script")[0];
      const script = window.document.createElement("script");
      script.src = src;
      script.async = true;
      script.setAttribute('id', 'google-map');
      ref.parentNode.insertBefore(script, ref);
    },
    initMap() {
      this.map = new google.maps.Map(document.getElementById('map'), {
        center: this.mapPosition,
      });
    },
  },
  created(){
    this.loadJS(`https://maps.googleapis.com/maps/api/js?key=${GOOGLEMAP_API_KEY}&callback=initMap`)
    window.initMap = this.initMap;
  },
  destroyed(){
    const oldTag = document.getElementById('google-map')
    oldTag.parentNode.removeChild(oldTag);
    window.google = {}
  }
};
</script>
```

余談: BiSHは良いぞ〜
bashで補完しようとしたときに`dyld: Library not loaded`と出たときの対処

`brew upgrade`したあとに、bashでTabキーを叩いて補完しようとしたら、以下のようなメッセージが出てくるようになった。

```shell-session
$ vim REdyld: Library not loaded: /usr/local/opt/readline/lib/libreadline.7.dylib
  Referenced from: /usr/local/bin/awk
  Reason: image not found
ADME.md
```

awkを単体で起動すると同じメッセージが出てくる。

```
$ awk 
dyld: Library not loaded: /usr/local/opt/readline/lib/libreadline.7.dylib
  Referenced from: /usr/local/bin/awk
  Reason: image not found
Abort trap: 6
```

ここでエラー吐いてるawkは、homebrewではいったgawkの模様。

```shell-session
$ which awk
/usr/local/bin/awk
$ ls -l /usr/local/bin/awk 
lrwxr-xr-x  1 miminashi  admin  28 10 17 20:43 /usr/local/bin/awk -> ../Cellar/gawk/4.2.1/bin/awk
```

`brew uses --installed`で、gawkを参照しているformulaがあるかどうかチェック。

```shell-session
$ brew uses --installed gawk
translate-shell
```

試しにいれた特にいらないやつだったので、gawkは動かなくても困らない。
gawkを`brew unlink`することにした。

```shell-session
$ brew unlink gawk
Unlinking /usr/local/Cellar/gawk/4.2.1... 39 symlinks removed
```

シェルを立ち上げなおすと、bashの補完で出ていたメッセージが出ないようになった。

参考: [Homebrew の依存関係を表示する方法](https://yu8mada.com/2018/06/08/how-to-list-homebrew-dependencies/)

# 2019-01-29 追記

gnuplotも同じエラーを吐いていたので、

```shell-session
brew upgrade readline
```

したらエラーは出なくなった。
ヨドバシカメラでMacBookAirの充電に使える、充電ケーブルを探す。物理的世界の互換性の問題があって、なかなか0.5メートルが見つからない。膨大なラインナップするがある。だけどデジタルのサービスやソフトウェアも、結局は現実世界の、限界の中に存在する。エンジニアも生物的な人間だし。

ヨドバシカメラでMacBookAirの充電に使える、充電ケーブルを探す。物理的世界の互換性の問題があって、なかなか0.5メートルが見つからない。膨大なラインナップするがある。だけどデジタルのサービスやソフトウェアも、結局は現実世界の、限界の中に存在する。エンジニアも生物的な人間だし。

# 僕は、iPhoneやMacBookの充電器がしたいだけなんだけれど、ヨドバシカメラの果てしないラインナップの中から、ケーブルを探している。専門コーナーの店員さんでさえも、隣のお客さんと、これはtype cに見えるけど違うかもねみたいな話をしている。混沌としたケーブルの互換性の世界。 

ケーブルの端子に掛け算で、逆側のケーブルの端子の数だけ、商品があると思うと、これは膨大なアイテム数になるよね。そこにケーブルの長さや、ちょっとした機能の違いも入ってくる。

思うに、ケーブルそのものよりも、このラインナップ数を用意することにお金のほとんどは使われている気がする。商品開発的な話で。

これは靴や洋服の世界にも言えるよな。靴の代金のほとんどは、膨大なラインナップを用意するために使われているんじゃないだろうか。

# ケーブルの場合は、いろいろな部品をジョイントさせることで、カスタマイズ性を高めることもできるだろうけど、現実的な制約として、部品の数が多いほど脆弱性もますので、単純にはうまくいかない。

そしてヨドバシカメラが役立つことになる。商品の掛け算の数だけ、商品を用意して、出来上がったものの中から、選んでもらうと言う仕組み。毎回、すごい世界だなと思い知らされるぜ。

アップル純正でも、変換ケーブルがあるけど、それを純正じゃないケーブルと合わせて使ったら、全然充電が進まなかったりして、だけどアップル純正では短いケーブルはなかったりして、なかなか難しい。

最近物理世界でも、デジタルの世界でも、現実的なラインナップや、リソースの制約と言うものを常に感じ続ける日々だ。だけどもう受け入れてきた。完璧なサービスやラインナップも存在しない。僕らは、神様じゃないから、現実的な制約の中で生きている。

デジタルやネットの世界は無限だと思うかもしれない。物理世界の制約は超えられると思うかもしれない。だけど現実的に、僕ら現実的制約のある人間が作っているサービスやソフトウェアは、常に現実的な限界と言う制約を課されている。

# エンジニアだって肉体を持つ限界的生物だし、リソースも有限だし、サーバーだって地球の電気を使っているし、メモリだって無限じゃないし、デジタルの世界でできる事は、物理世界よりも掛け算がしやすいとは言え、やはり可能性よりも不可能性のほうがはるかに膨大にあるのだ。

なので僕らは常に、ユーザ努力を強いられる。本当にやりたいことのために、現実的制約を超えて、自由に翼を固め課せられる日は、一体いつやってくるのだろう。だけど最初から自由な翼があったら、きっと退屈で死んでしまうかもしれない。

と、こんなことを話していたら、ヨドバシカメラで並ぶ列を間違えて、いつまでも進まないと思っていたら、レジじゃなくて総合案内に並んでいた。この事件と、現実的制約を結びつけてうまく語りたいけれど、何も思い浮かばないので、スキップする。

ところで僕は、ようやく0.5メートルのMacブックエアに使える充電ケーブルタイプcを見つけて、レジへと向かう。最近は、スマホの決済で支払いができるレジが本当に多くて、クレジットカードよりもはるかに現実的制約を超越しているんだぜ。

ヨドバシカメラでMacBookAirの充電に使える、充電ケーブルを探す。物理的世界の互換性の問題があって、なかなか0.5メートルが見つからない。膨大なラインナップするがある。だけどデジタルのサービスやソフトウェアも、結局は現実世界の、限界の中に存在する。エンジニアも生物的な人間だし。 https://t.co/ljkJoUCG6F

![image](https://user-images.githubusercontent.com/13635059/51802417-4a12f400-228d-11e9-8b0a-86a13f904f80.png)








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
チームキックオフミーティングまとめ

# 概要

「あれ〜？あの資料どこだっけなぁ...」とならないようにキックオフの時にやったことをまとめておく。
やったことは基本的に以下の通り。

0. アイスブレイク（開始前5分〜開始後5分の10分程度）
1. 案件概要説明
2. チーム指針説明
3. ドラッカー風エクササイズ（チーム毎）
4. チーム内施策を考えてみよう（チーム毎）

ほぼ個人的メモ（とは言いつつも他だとどんなことやってるのか知りたい）

# 前提

チーム指針、ドラッカー風エクササイズの内容については事前に整理してきておいてもらう。

# 時間

時間は6〜7人のチームで2時間前後。

---

以下、案件名と個人名は伏せて、ほぼそのまま転記。
補足は ***Bold+Italic*** で入れていきます。

---

# ◯◯案件社内キックオフミーティング

実際の開発期間は2ヶ月に満たないぐらいですが、よろしくお願いします！
という事でキックオフミーティングをやりたいと思います！
ワークショップもあるよ！

***この案件はラボ契約+アジャイル（1Sprint/2Week）です。***

## ミーティングアジェンダ

1. 案件概要説明（◯◯：担当者名）
2. チーム指針説明（◯◯：担当者名）
3. ドラッカー風エクササイズ（Android/iOSに分かれて実施）
4. チーム内施策を考えてみよう（Android/iOSに分かれて実施）

時間は1時間30分〜2時間ぐらいになります！ちょっと長めだけど付き合ってね！

***案件概要はプロジェクトマネージャーから説明してチーム指針はPLまたはEMから説明するのが望ましい***

## 案件概要説明（15分）

どんな案件かざっくり概要を◯◯さんが説明してくれるよ！
耳かっぽじって良く聞くんだよ！

***ドキュメントでの説明は基本的に行わず、必要があればホワイトボードに書くなりして説明を進めてもらう。言葉・身振り手振りで説明するのが大事。ドキュメントを読み上げるだけなら「これ見といて」で十分。***

## チーム指針説明（15分）

各チーム共通の指針について◯◯の方から説明します！
お茶でも飲みながらゆるっと聞いてね！

***チーム指針については事前に整理して展開しておく。そこをベースにルールではなく、想いを伝える。後は多分メンバーが受け取ってくれると思う。そこは信じろ。***

## ドラッカー風エクササイズ（60分）

事前に以下のことを考えてきてもらったと思うんだ！  

1. 好きなこと
2. 得意なこと
3. 苦手なこと
4. 仕事のスタイル
5. 自分が大切にしている価値観
6. 各メンバーに期待すること（Android/iOS分かれて実施）
7. 各メンバーから期待されていると思うこと（Android/iOS分かれて実施）
8. どんなエンジニアになりたいか
9. この案件で何を得たいか

***アプリ開発案件だったため、AndroidとiOSに分けた。Webシステムならフロントエンド・バックエンド・設計とかで分けても良いと思う。9の「この案件で得たいこと」に関しては基本的に無くても良い。***

これをチーム内で共有しながらお互いのことを理解していこう！
今回のプロジェクトはチーム力が試されるからね、ここは重要だよ！お互い理解して気持ちよく仕事ができるように努力と改善を積み重ねていこう！
ドラッカー風エクササイズのやり方を説明するよ！

***ドラッカー風エクササイズのやり方はググってください。（そこそこ大きいホワイトボードと）付箋があればできます。***

1. 各自考えてきた上記内容を付箋に書くよ(｀・ω・´)大体10分ぐらいでよろしくだよ！
2. AndroidはAさん→Bさん→Cさん→Dさん、iOSはAさん→Bさん→Cさん→Dさんの順で、1から9まで順番に発表していくよ(｀・ω・´)  
Aさん「1は〜」Bさん「1は〜」Cさん「1は〜」Dさん「1は〜」→Aさん「2は〜」Bさん「2は〜」Cさん「2は〜」Dさん「2は〜」って感じだよ！  
***チーム内の若い順から発表していくと良いと思う。若ければ若いほど自分の言葉を出した後に他の人の聞ける環境にするのが経験則的に良い印象がある。***
3. 発表している最中に割り込んで話を途切れさせたりするのは厳禁だよ(´・ω・｀)そういう人がいたら役割関係無く注意しよう！
4. 発表が終わったら「それってこういうこと？」って深掘りしたり「それわかるー！」って同意は大いに結構！どんどんやっていこう！ただ、脇道にそれ過ぎないようにね(｀・ω・´)  
***各チームの一番おじじがファシリテーターになると良いと思うよ。***
5. 9まで発表が終わったら個々の特性が見えてくると思うんだ！そうしたらそれをチームの特性として整理してみよう！Androidチームはこういう特性を持ったチーム！iOSチームはこういう特性を持ったチーム！っていう感じだね(｀・ω・´)個々の特性もチームの特性も良し悪しではないからね！ありのーままのーってやつだね！  
***あんまり考えすぎないのがコツ。「特に特徴は無い」でも良い。自分達を言葉に表せればOK。***
6. 各チームで特性を考慮して、チームとして大事にする価値観を1つ決めよう！何か行動や発言する時にその価値観を考えた上でのことかどうか、行動や発言の指針となるよ(｀・ω・´)もちろん個々の価値観を踏まえた上で決めてね！そうじゃないと誰かが犠牲になる不幸なチームになってしまうよ！  
***1つじゃなくても良い。ただ、最低1つは欲しい。***

これで良いチームができた！ってわけじゃなくて、チームを作っていくスタートが切れたという感じです。良いチームになるかどうかはこれからです、一緒に皆が自然体でクリエイティブに仕事ができる良いチームを作っていきましょう(｀・ω・´)
あ！ドラッカー風エクササイズの結果はPlannerで保存しておくよ！2週に1回ぐらい自分のも含めメンバーの内容も見返すと良いと思う！
苦手なことが苦手じゃなくなってきたとか、仕事のスタイルが変わってきたとかあったら適時チームでドラッカー風エクササイズをやり直すのもお勧めしておくよ！

***Teams使ってるのでPlannerですが、Trelloとかでも良いと思います。見返すことのできる形にしておくのが良いかと。***

## チーム内施策を考えてみよう（10分 + 10分）

チームの特性がわかったところでそのチームでどんな施策（取り組みや厚生）をやってみたいか考えてみよう！実現できることでもできないことでも良いよ(｀・ω・´)  
ただし、施策には必ず理由を伴わせること！理由は「個人」ではなく「チーム」として考えよう。「うちのチームはこういう特性があるからこういう施策したら良いと思う！」ってのが理想ですね！あまりに考えすぎて案が出てこないのも問題なので、そういう時は「何となくだけどこういう施策や厚生があった方が働きやすいと思う！」でも良いよ！  
各チーム10分で考えてお互いのチームで発表してみよう！自分達では考えもしなかった素晴らしいアイディアや観点が見つかるかもしれないね(｀・ω・´)

***勢いと数が大事。ここで出た意見やアイディアは持ち帰って実現できそうなものは実現させてみる。***
Windowsサーバーのシャットダウン時にPowerShellでSlackに通知する

業務で使用している開発サーバを[GCE（Google Compute Engine）](https://cloud.google.com/compute/)に移行する事になりました。

料金を抑えるため[プリエンプティブインスタンス](https://cloud.google.com/compute/docs/instances/preemptible)で運用していますが、プリエンプティブインスタンスは24時間稼働するとプリエンプト（強制的にシャットダウン）されるほか、任意のタイミングでプリエンプトされる事もあります。
※詳しくは[＜プリエンプティブ インスタンスの制限＞](https://cloud.google.com/compute/docs/instances/preemptible?hl=ja#limitations)を参照。

いつの間にかサーバーが落ちている！という事がたまにあるので、シャットダウンのタイミングでSlackに通知する事にしました。

---

## Slack APIの準備

外部からSlackにメッセージを送るには、「Incoming Webhooks」を利用します。

1. Slackの左上のメニューから「Slackをカスタマイズ」をクリックし、次のページで
≡Menu ⇒ App管理を開く（或いは、https://***.slack.com/apps/manage　を開く）
![01.png](https://qiita-image-store.s3.amazonaws.com/0/196121/a2ec767a-4c14-4f1c-ed28-ca114292e877.png)

2. 「カスタムインテグレーション」→「Incoming Webhooks」をクリック
![02.png](https://qiita-image-store.s3.amazonaws.com/0/196121/e1f557b8-cad2-c9d5-c827-092f26977d37.png)

3. 【設定を追加】をクリック
![03.png](https://qiita-image-store.s3.amazonaws.com/0/196121/1518bc4e-e060-cc81-5f5d-f048eaee9543.png)

4. チャンネルを選択し、【Incoming Webhook インテグレーションの追加】をクリック
![04.png](https://qiita-image-store.s3.amazonaws.com/0/196121/25cfb63a-1ef9-f8fb-f87f-6f421402e1f8.png)

5. 「Webhook URL」をコピーしてテキストエディタに貼り付けておく
![05.png](https://qiita-image-store.s3.amazonaws.com/0/196121/5b347718-0d55-7076-5383-93ff905057fd.png)

6. 名前やアイコンはデフォルトではこうなっているので、
![06.png](https://qiita-image-store.s3.amazonaws.com/0/196121/237171cd-8f48-1ba7-5b35-0ca362e0b012.png)
変えたければ少しカスタマイズする。
![06b.png](https://qiita-image-store.s3.amazonaws.com/0/196121/6fdc8cc4-6b99-9f48-1ed4-1bf228ebd022.png)


## PowerShellスクリプトの準備

Incoming Webhookの設定ページにも記載がありますが、メッセージを送るにはJSON形式でPOSTするだけです。
![07.png](https://qiita-image-store.s3.amazonaws.com/0/196121/865397a6-205d-79f7-c257-c06478b8dd3b.png)

今回はWindowsサーバーから送信するので、PowerShellを使います。
以下をコピーし、サーバーの任意の場所に保存します。拡張子は「.ps1」です。
せっかくなので、メッセージは引数で受け取るようにしました。
※ $webHookURL には上でコピーしておいた「Webhook URL」を設定します。

```ruby:SlackNotifycation.ps1
# 引数必須設定
Param(
	[parameter(mandatory=$true)][String]$Arg1
)

# ★ここにIncoming Webhooksの「Webhook URL」を記載
$webHookURL = "https://hooks.slack.com/services/*********/"

# メッセージをエンコーディング
$enc = [System.Text.Encoding]::GetEncoding('ISO-8859-1')
$payload = @{
	text = $enc.GetString([System.Text.Encoding]::UTF8.GetBytes($Arg1));
}
$body = ConvertTo-Json $payload

# Slackに通知
Invoke-RestMethod -Uri $webHookURL -Method Post -Body $body
```


## サーバーでシャットダウン時のタスクを設定する

通常の「タスクスケジューラ」ではシャットダウンタスクは作成できません。
以下の手順でグループポリシーに追加します。

1. [ファイル名を指定して実行]（Winキー＋R）で`gpedit.msc`と入力し実行
2. 左側のツリーから[コンピュータの構成]-[Windowsの設定]-[スクリプト（スタートアップ/シャットダウン）]を選択
3. 右側の[シャットダウン]をダブルクリック
![S1.png](https://qiita-image-store.s3.amazonaws.com/0/196121/8b761fda-2baf-79c7-6cf6-6806abacdb41.png)
4.「PowerShellスクリプト」タブで【追加】をクリックし、.ps1ファイルを指定する。スクリプトのパラメーターにメッセージを入力する。
![S2.png](https://qiita-image-store.s3.amazonaws.com/0/196121/72d1a015-ab42-e527-7119-8f2579af9564.png)


## 実行結果

以下のようにSlackに通知されれば成功です！
![Result.png](https://qiita-image-store.s3.amazonaws.com/0/196121/25643ea7-dbdc-534c-bbfd-2dea119fefcf.png)
Arduinoで加速度センサ情報を取得する。~I2C通信接続確認編~

加速度センサを使って、ある振動の周波数分析を行い、
振動の固有振動数を調べる。

そのために、
Arduinoで加速度センサの生値をロギングするところから始めます。

##使用するボード・センサ
・Arduino Nano V3.0 ([SaintSmart社製](https://www.amazon.co.jp/%E3%82%B5%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%EF%BC%88SainSmart%EF%BC%89-Nano-3-0-%E4%BA%92%E6%8F%9B%E3%83%9C%E3%83%BC%E3%83%89-for-Arduino/dp/B00761NDHI))
※プロセッサはATmega 328P(older version)なのでArduino IDE>ツール>プロセサでこれを選択すること。

・3軸加速度センサ ([HiLetgo社製](https://www.amazon.co.jp/HiLetgo-3pcs-GY-521-MPU6050/dp/B07CVFW6BN/ref=sr_1_2?ie=UTF8&qid=1548574681&sr=8-2&keywords=%E5%8A%A0%E9%80%9F%E5%BA%A6%E3%82%BB%E3%83%B3%E3%82%B5+%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB)）
※加速度センサはピンソケットははんだ付けされてないので、
自分ではんだ付けします。

##Arduinoとセンサの接続
接続の配線は以下の通りです。

![Arduino加速度センサ接続.png](https://qiita-image-store.s3.amazonaws.com/0/272931/3d102b3c-234f-f2cf-8aa5-ca768e94b90e.png)


##Ardino IDE設定

![Arduino IDE設定.png](https://qiita-image-store.s3.amazonaws.com/0/272931/2162118c-6823-2b74-d529-87084c340292.png)


##I2C通信の接続確認
Arduino↔加速度センサモジュール間のデータの通信はI2C通信を用います。
I2C通信の特徴
「基準となるGNDを共有するデバイス同士をクロック(SCL)とデータ(SDA)の２線だけで
双方向の通信が可能」

0x75のレジスタにアクセスすると、固定値0x68を返すはずなのだが、、、、
何故か、72を返してくる.....
とりあえず、接続できたで良し？？？
いろいろ調べてみたが、原因わからない。わかる方教えてください。
<img width="578" alt="スクリーンショット 2019-01-27 23.23.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/272931/46ac79da-8c59-f7e4-c35b-434939c5cb61.png">

次回[Arduinoで読んだセンサー値をシリアルプロッタでプロットしてみる](https://qiita.com/VoyagerC/items/104c6e25ea987336f7b5)
vue-svg-loaderを使って画像をcomponent化させる

以前にvue-svg-loaderを使ったことがあったので、知見として記事を書こうと思いました。

### vue-svg-loaderをインストール

```js
npm i -D vue-svg-loader

or

yarn add --dev vue-svg-loader
```

### 基本設定
次にvue-svg-loaderの設定です。

#### Vue CLI
vue cliの場合は以下のコードをwebpackに記入します。

```js
module.exports = {
  chainWebpack: (config) => {
    const svgRule = config.module.rule('svg');

    svgRule.uses.clear();

    svgRule
      .use('vue-svg-loader')
      .loader('vue-svg-loader');
  },
};
```

#### Nuxt.js
vue cliの場合は以下のコードをnuxt.config.jsに記入します。

```nuxt.config.js
module.exports = {
  build: {
    extend: (config) => {
      const svgRule = config.module.rules.find(rule => rule.test.test('.svg'));

      svgRule.test = /\.(png|jpe?g|gif|webp)$/;

      config.module.rules.push({
        test: /\.svg$/,
        loader: 'vue-svg-loader',
      });
    },
  },
};
```

これで基本的な設定は終了です。

#### 実際にvueファイルで使用する
実際に使用するにはcomponentと同じような使い方で、importで画像のパスを指定して、componentsにimportしたcompoent名を記述します。
最後に使用したい部分にcomponentを追加すると、実際にsvgの画像が描画されます。

```vue
<template>
  <nav>
    <a href="https://hogehoge.com/">
      <SampleLogo />
    </a>
  </nav>
</template>
<script>
import SampleLogo from './assets/images/sample_image.svg'

export default {
  name: 'Sample',
  components: {
    SampleLogo,
  },
};
</script>
```
【R】基本統計量を求める

データの分布状況を知るための、「基本統計量」を求める方法です。
この程度の処理であればExcelを使っても求められますが、こういった基本的な処理からRに慣れておくのが良いかもしれません。

# 解析に使うデータ

* 以下のデータは、ある山の東側（east）と西側（west）で測定した葉のサイズ（mm^2）です。

```leaf_size.csv
east,west
4632.4,4159.1
3481,3844.4
3267.8,3135.0
3130.9,2837.2
3108,2801.2
2575.4,2587.8
4556.9,5180.1
4343.5,3635.9
4130.3,2651.1
2824,2642.7
```

# データの読み込み

* [【R】データの読み込み](https://qiita.com/nkojima/items/131fdce3a22ccc1760b4)にも書いていますが、復習を兼ねてこちらにも書いておきます...

```r:Rのコンソール
> # leaf_size.csvを読み込んで、"leaf_size"という名前のデータフレームに格納する。
> leaf_size <- read.table("C:\\leaf_size.csv", header=TRUE, encoding="CP932", sep=",")
> leaf_size
     east   west
1  4632.4 4159.1
2  3481.0 3844.4
3  3267.8 3135.0
4  3130.9 2837.2
5  3108.0 2801.2
6  2575.4 2587.8
7  4556.9 5180.1
8  4343.5 3635.9
9  4130.3 2651.1
10 2824.0 2642.7
```

# 基本統計量を求める

* 以下で使用している関数に対して、データフレームを丸ごと投げることはできません。
* そのため、eastとwestの各列に対してmean関数を実行しています。
 * east列：leaf_size$east
 * west列：leaf_size$west

## 最小値、最大値、中央値

```r:Rのコンソール
> # 最小値
> min(leaf_size$east)
[1] 2575.4
> min(leaf_size$west)
[1] 2587.8
> # 最大値
> max(leaf_size$east)
[1] 4632.4
> max(leaf_size$west)
[1] 5180.1
> # 中央値
> median(leaf_size$east)
[1] 3374.4
> median(leaf_size$west)
[1] 2986.1
```

## 平均値、標準偏差、不偏分散

```r:Rのコンソール
> # 平均値
> mean(leaf_size$east)
[1] 3605.02
> mean(leaf_size$west)
[1] 3347.45
> # 標準偏差
> sd(leaf_size$east)
[1] 749.3615
> sd(leaf_size$west)
[1] 850.4945
> # 分散
> var(leaf_size$east)
[1] 561542.6
> var(leaf_size$west)
[1] 723340.8
```

# 複数の列の基本統計量を求める

* sapply関数を使うことで、複数の列の基本統計量を求めることができます。
* sapply関数は第一引数にデータフレームそのものを指定できるだけでなく、「leaf_size[1:2]」のように基本統計量を求めたい列を指定することも可能です。

```r:Rのコンソール
> sapply(leaf_size, mean)
   east    west 
3605.02 3347.45 
> sapply(leaf_size, sd)
    east     west 
749.3615 850.4945 
> sapply(leaf_size, var)
    east     west 
561542.6 723340.8 
> sapply(leaf_size, min)
  east   west 
2575.4 2587.8 
> sapply(leaf_size, max)
  east   west 
4632.4 5180.1 
> sapply(leaf_size, median)
  east   west 
3374.4 2986.1 
```
Javaでシステム情報を取得するライブラリ「OSHI」

# 概要
Javaでシステム情報を取得できるOSHIというライブラリについてのメモです。

## Sigarとの違い
システム情報を取得するライブラリとして他にSigarがありますが、下記の点でOSHIの方がいい感じです。

- SigarはDLLなどのネイティブなバイナリが必要だが、OSHIの場合は不要
- SigarはWindows版の場合、Java9以降では使用できない（JVMがクラッシュする！）が、OSHIは問題なく使用可能


# インストール
```build.gradle
dependencies {
    compile group: 'com.github.oshi', name: 'oshi-core', version: '3.13.0'
}
```

# 使ってみる
OSHIで取得できる情報を適当に抜粋して紹介します。右のコメントは私の環境での出力結果です。

## OS情報
```java
var si = new SystemInfo();
var os = si.getOperatingSystem();
// OSの種類
System.out.println(os.getFamily());  // macOS
// バージョン
System.out.println(os.getVersion().getVersion());  // 10.14.2
// メーカー
System.out.println(os.getManufacturer());  // Apple
// 何ビットか
System.out.println(os.getBitness());  // 64
// コードネーム
System.out.println(os.getVersion().getCodeName());  // Mojave
```

## CPU情報
```java
var si = new SystemInfo();
var hard = si.getHardware();
var cpu = hard.getProcessor();
// 物理プロセス数
System.out.println(cpu.getPhysicalProcessorCount());  // 4
// 論理プロセス数
System.out.println(cpu.getLogicalProcessorCount());  // 8
// 名前
System.out.println(cpu.getName());  // Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz
// 識別子
System.out.println(cpu.getIdentifier());  // Intel64 Family 6 Model 70 Stepping 1
// ベンダID
System.out.println(cpu.getVendor());  // GenuineIntel
// コンテキストスイッチ数
System.out.println(cpu.getContextSwitches());  // 130336
// ロードアベレージ
System.out.println(cpu.getSystemLoadAverage());  // 2.65576171875
```

## メモリ情報
```java
var si = new SystemInfo();
var hard = si.getHardware();
var memory = hard.getMemory();
// トータルメモリ容量
System.out.println(memory.getTotal());  // 17179869184
// トータルスワップ容量
System.out.println(memory.getSwapTotal());  // 1073741824
// ページサイズ
System.out.println(memory.getPageSize());  // 4096
// 使用可能容量
System.out.println(memory.getAvailable());  // 5858844672
```

## USBデバイス
```java
var si = new SystemInfo();
var hard = si.getHardware();
var usbs = hard.getUsbDevices(false);
for(var usb : usbs) {
    // 色々あるのでとりあえずマウスに絞ってみる
    if(usb.getName().contains("Mouse")) {
        // 名前
        System.out.println(usb.getName());  // USB Laser Mouse
        // メーカー
        System.out.println(usb.getVendor());  // Logitech
    }
}
```

## センサー
```java
var si = new SystemInfo();
var hard = si.getHardware();
var sensor = hard.getSensors();
// CPU温度
System.out.println(sensor.getCpuTemperature());  // 48.75
// CPU電圧
System.out.println(sensor.getCpuVoltage());  // 3.63
// CPUファンスピード
System.out.println(Arrays.toString(sensor.getFanSpeeds()));  // [2159, 2000]
```

## その他

多いので全部は紹介できないですが、上記以外にもファイルシステム情報、ディスク情報、プロセス情報、サウンドカード情報、電源情報などなど、様々な情報を取得することができます。

# 参考リンク

- https://github.com/oshi/oshi
[cocoa][swift]作譜用言語PL/0 構文に対する分析子の作成

<p>有名な『Algorithms + Data Structures = Programs』の後半を独立して誕生した『COMPILERBAU:』を翻訳した『翻訳系構成法序論』を今の電子計算機環境で取り組んでみた。</p>

<p>使用するプログラミング言語Swiftを選択したのだが、コンパイラの実装には少々向いていない部分があるので、まずは、一文字読み込んで処理するサンプルを記述してみた。</p>

<pre><code>import Foundation
 
let parser = Parser()
</code></pre>

<pre><code>import Foundation
 
class Parser {
    var ch: Character = "\0"
    var lineString: String = ""
    
    init() {
        readChar()
        S()
    }
    
    func readChar() {
        lineString = readLine()!
        ch = lineString[lineString.index(lineString.startIndex, offsetBy:0)]
        lineString = String(lineString.suffix(lineString.count - 1))
    }
    
    /*
     開式記号に対応する手続き。
     */
    func S() {
    }
}
</code></pre>

<p>それでは、教科書のサンプルコードを記述してみよう。</p>

<p>以下の約束事があるとする。</p>

<pre><code>A="x"|"("B")".
B=AC.
C={"+"A}.
</code></pre>

<p>これは以下のようになる。</p>

<pre><code>x
(x)
(x+x)
((x))
((x+(x+x)))
</code></pre>

<p><これを実装してみると以下となる。/p>

<pre><code>/* 分析子 */
class Parser {
    var ch: Character = "\0"
    var lineString: String = ""
    
    init() {
        print("\(#function)")
        readChar()
        A()
    }
    
    func A() {
        //print("\(#function)")
        if ch == "x" {
            readChar()
        }
        else if ch == "(" {
            readChar()
            A()
            while ch == "+" {
                readChar()
                A()
            }
            if ch == ")" {
                readChar()
            }
            else {
                error()
            }
        }
        else {
            error()
        }
    }
 
    func readChar() {
        if lineString.count <= 0 {
            lineString = readLine()!
        }
        ch = lineString[lineString.index(lineString.startIndex, offsetBy:0)]
        lineString = String(lineString.suffix(lineString.count - 1))
        print(ch)
    }
    
    func error() {
        print("error: \(#function)")
        exit(-1)
    }
}
</code></pre>

<p>ここまでは、約束事を愚直にコードで処理しているという感じだ。</p>

ソースコード
GitHubからどうぞ。<br />
<a href="https://github.com/murakami/workbook/tree/master/mac/pl0">https://github.com/murakami/workbook/tree/master/mac/pl0</a> - GitHub<br />

【関連情報】
<a href="https://cocoa-kanto.connpass.com/event/117577/">Cocoa.swift 2019-02</a><br />
<a href="https://cocoa-kanto.connpass.com/">Cocoa.swift</a><br />
<a href="https://www.facebook.com/groups/cocoa.kanto/">Cocoa勉強会 関東</a><br />
<a href="https://mosa.connpass.com/">MOSA</a><br />
<a href="http://www.bitz.co.jp/weblog/">Cocoa練習帳</a><br />
<a href="https://qiita.com/m_yukio">Qiita</a><br />
Juliaの配列をFFIで渡す

準備
----
今回はC++で生成した共有ライブラリをJuliaから呼び出す形で実験します。

```cmake
cmake_minimum_required(VERSION 2.8)
add_library(myffi SHARED
  ffi.cpp
  )
set_target_properties(myffi PROPERTIES PREFIX "")
```

共有ライブラリはcmakeで生成します。以下でのべるC++コードは`ffi.cpp`として保存します。
ビルドした共有ライブラリはそのままだとJuliaが見つけられないと思うので`LD_LIBRARY_PATH`で指定してください。

```
cmake .
make     # これでmyffi.soができるので、これを探せるようにする
LD_LIBRARY_PATH=$PWD julia main.jl
```

ポインタで渡す場合
-----------------

[Calling C and Fortran Code](https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/index.html)を参考に実装します。

```cpp
extern "C" {

void make_twice_ptr(int n, float *p) {
  for (int i = 0; i < n; ++i) {
    p[i] *= 2.0;
  }
}
}
```

これをJuliaから呼び出します：

```jl
a = ones(Float32, 2, 3)
ccall((:make_twice_ptr, "myffi"), Cvoid, (Int32, Ptr{Float32}), 2*3, a)
println(a)
```

JuliaからFFIを`ccall`で呼び出すとき、Julia側で一旦変換が実行されてから渡されます。

> Array{T,N}
When an array is passed to C as a Ptr{T} argument, it is not reinterpret-cast: Julia requires that the element type of the array matches T, and the address of the first element is passed.

とある通り、Julia側の配列型のアドレスをポインタにするのではなく、データの最初の位置を指すポインタに変換されてわたされるのでこれでちゃんと動作します

```
Float32[2.0 2.0 2.0; 2.0 2.0 2.0]
```

構造体として渡す場合
---------------------

[Embedding Julia](https://docs.julialang.org/en/v1/manual/embedding/index.html)を参考に実装します。

```cpp
#include <julia/julia.h>

extern "C" {

void make_twice_array(jl_value_t *ptr) {
  if (jl_is_array_type(ptr) != 0) {
    std::cerr << "This is not an array." << std::endl;
    return; // TODO Error handling
  }
  auto array = reinterpret_cast<jl_array_t *>(ptr);

  if (array->elsize != sizeof(float)) {
    std::cerr << "This is not a float array." << std::endl;
    return; // TODO Error handling
  }

  float *data = reinterpret_cast<float *>(array->data);
  for (size_t i = 0; i < array->length; ++i) {
    data[i] *= 2.0;
  }
}
} // extern C
```

```jl
b = ones(Float32, 2, 3)
ccall((:make_twice_array, "myffi"), Cvoid, (Any,), b)
println(b)
```

こちらは`Any`として渡してしまって、C++側でJuliaのAPIを使用して型を判定して`reinterpret_cast`で変換します。JuliaのAPIはイマイチどこにドキュメントがあるか分からなかったので`/usr/include/julia/julia.h`にインストールされたヘッダーをそのまま見て書いてます。

最後に
---------

課題

- C++の例外をJuliaに渡す部分
- Juliaのパッケージの一部としてC++の拡張機能を配布する方法

今回のコードは以下に置いておきます：
https://github.com/termoshtt/julia_ffi_example
脳波を機械学習で判別することを考えたときの注意点

# はじめに
今回は機械学習で脳波を判別することを考えた際に感じた注意点について紹介していみたいと思います。

なお、実装例等の紹介ではなく、考え方や概念の紹介となります。

こちらも参照してください
[データマイニングの観点から見る脳波判別](https://qiita.com/shu3051/items/b50116fa2da7da9fd92a)

# 機械学習の落とし穴
落とし穴というとすごく悪い言葉に聞こえ、根拠はあるのかという話になりますが、今回の話は脳波関連に関する機械学習を行った経験に基づいた話となります。根拠を示すような情報やデータがあるわけではありません。

世間一般で言われているディープラーニングの特質として「特徴量を自動的に抽出する」ことがあると思います。

ただ、これはあくまでも画像処理や音声処理といった「人間が五感で分かる」事に関するデータに対することだと思います。

五感で分からないデータ（売上情報や位置情報のようなビックデータ）に対しては必ずデータを学習させる前に「可視化」を行って

有効な特徴が抽出できるか分析を行っているはずです。

この分析作業はあくまでも人の手で行われていると思います（これを専門に行っている方々をデータサイエンティストというと思います）。

ディープラーニングはどんなとデータでも特徴量を自動的に抽出して、それを判別すると考えて闇雲に検証を進めると思わぬ落とし穴にハマる可能性があります。

# 可視化の重要性
データを可視化するとは、本来は多次元である解析対象のベクトルを3次元以下に落として、データ分布を確認することです。

詳しくは「主成分分析」「次元削減」「t-SNE」等で検索してみてください。

脳波データは電極ごとの電位やそれらの周波数成分などが特徴量になると思います。

可視化を行うことで、データが判別可能か、分布が重複していて判別不可能かがある程度分かります。

とはいえ、画像や音声のデータもそのまま何かしらの形でベクトルに落として、可視化しても分布から得られる情報は少なく

ディープラーニングが行う特徴の抽出を行って、初めて判別が可能になると思います。

ただ、音声や画像は人間が五感で判別が可能であり、音声波形をグラフにしたら、違いは見ればわかるようなものが多いと思います。

また、ディープラーニングもといニューラルネットワークは、人間の脳を模して造られてる学習アルゴリズムであるため、人間が見分けられることは大前提としてあると思います。

得られた脳波データはグラフに示したときに違いがあるかどうかが分かれ目だと思います。

グラフに差異があれば、自動的に抽出される特徴がある可能性が高くなります。

# まとめ
- ディープラーニングはどんなデータでも自動的な特徴抽出を行うわけではない可能性がある
- 脳波データはまずは可視化を行って、差異が分かるか確かめる
- 可視化で差異が無いとき(分布が重複している)は、波形をグラフ化して差異を確かめる(時間軸、周波数軸など)
- グラフ化して差異が出るなら、何かしらの機械学習を用いることで判別が可能である可能性がある


# 最後に
今回は機械学習で脳波を判別することを考えた際に感じた注意点について紹介していみました。

「無いものは、いくら探しても見つからない」が「無いことを証明するのも難しい」が全てだと思います

願わくは、脳波を判別しうる特徴量を模索するために機械学習を行っている皆さんの助けとなれば幸いです。

コメント欄に要望やご意見などいただけると幸いです。
brew cask で「Error: Cask 'filezilla' is unavailable: No Cask with this name exists.」エラー発生

# 背景

いつからか、 brew cask で以下のエラーが発生

#エラー内容

```
$ brew cask list
Error: Cask 'filezilla' is unavailable: No Cask with this name exists.
```

# 解決方法
`Caskroom`下の`filezilla`を削除
念の為、`filezilla`下には何もないことを確認した

```
$ pwd
/usr/local/Caskroom
$ rm -rf filezilla
```
Backlog記法をMarkdownに変換したい

## TL;DR

次ののブックマークレットをお試しください。
→　[Backlog記法をMarkdownへ変換する.min.js（GitHub）](https://github.com/Soten-Bluesky/bookmarklets/blob/c8b36a04a7010ed76655a2cd09f55a180f21027a/Backlog%E8%A8%98%E6%B3%95%E3%82%92Markdown%E3%81%B8%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B.js/Backlog%E8%A8%98%E6%B3%95%E3%82%92Markdown%E3%81%B8%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B.min.js#L1)

- 行頭をクリックするとメニューが表示されます
- その中から「Copy line」を選択するとコピーできます
- URIエンコード済みなので、ブックマークに登録してからご利用ください

## 全社的にMarkdownをメインに使っていきたい

何かしらの歴史的な理由から[ヌーラボ社のBacklog](https://backlog.com/ja/)でBacklog記法を使ってきたものの、「やっぱりMarkdownで仕事がしたくなったぞ」という時の手助けになればとBacklog記法からMarkdownへの変換を*手助けする*ブックマークレットを用意しました。

テスト数の不足から完全な置き換えは保証できませんが、ほぼほぼ置き換えることができます（150程度のWikiや課題詳細で確認）。

## でも、これまでのBacklog記法はどうするの？

結局のところこれが問題です。

Backlog記法とMarkdownでは非順序リスト以外互換性がほとんどありません。プロジェクトの設定を変更しただけでは業務に支障がでてしまいます。

そんな時

- とりあえずよく使うページや課題だけでも変換できればOK
- 新しいプロジェクトからMarkdownにして、横断的に使っているプロジェクトは手分けして置き換えしていけば解決できそう
- ある程度課題詳細の内容のフォーマットが決まっているためBacklog APIを使って全置換してしまえばよさそう

といったケースをお手伝いできるかもしれないのが本コードです。

元のJSはこちらに置いてあります。
→　[Backlog記法をMarkdownへ変換する.js（GitHub）](https://github.com/Soten-Bluesky/bookmarklets/blob/master/Backlog%E8%A8%98%E6%B3%95%E3%82%92Markdown%E3%81%B8%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B.js/Backlog%E8%A8%98%E6%B3%95%E3%82%92Markdown%E3%81%B8%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B.js)

Backlog APIなどで利用する場合は、一番外側のIIFEに渡している第二引数を取り出してご利用ください。



## 最後に

BacklogでMarkdownが使えるようにできれば、Backlogを利用していない職場から中途入社してきた方の学習コストも削減できますし、Markdownをサポートしている数々のアプリケーションと同じ記法で記述・連携できて一石二鳥です。
もしまだあなたの現場でBacklog記法が利用されていて、Markdown記法に切り替えられそうな見込みがある場合はぜひぜひ切り替えていっていただければと思います。

MarkdownでよりよいBacklogライフをお楽しみください。

### ご注意

- ご利用は自己責任でお願いいたします
- ミスったらまずいページや課題詳細は必ずプレビューを行ってください
- Backlog記法とMarkdownはできることに違いがありますから、そこも含めて検討したほうがが良さそうです
    - たとえば、BacklogでのMarkdownはHTMLを無視されるので、文字色が変更できません
        - 非アクセシブルではありますが、文字色が重要な現場では慎重にご検討ください
- BacklogのMarkdownならではの記法やルールも存在するため、本コードで変換したものがMarkdownサポートをしているGitHubなどの各種サービスでもそのまま使えるわけではないことにご注意ください
GuardDutyの有効化

#1. はじめに
ここでは、GuradDutyの有効化や基本的な機能を触ってみた際の様子をご紹介します。

#2. GuardDutyの有効化
実はこれ、「GuardDutyの有効化」ってボタンを押すだけなんですよね。すごい。
簡単すぎてスクショ取り忘れました。。。

#3. GuardDutyのコンソール
コンソールの主な画面を見ていきます。

###結果画面
出力されているログはサンプルです
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254738/f94f5b49-fda4-916b-9e46-a42840ad7ff5.png)


###設定画面
GuardDutyの有効化、無効化などができるようです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254738/68380823-6b8e-dc51-db62-10ae759e299c.png)

#4. GuardDutyの料金（2019年1月現在）
約1ヶ月の無料トライアル期間が設定されているため、ありがたく使用させていただきました。
基本はエンタープライズ向けのサービスだと思いますが、それを考えてもかなりお手軽な料金だと思います。
https://aws.amazon.com/jp/guardduty/pricing/


#5. サンプルログの出力
「設定」→「結果サンプルの生成」から、GuardDutyのログのサンプルを出力させられます。

試しに一つ見てみましょう
ログを選択すると、右横のペインから詳細が見られました。
表示方法は画面右上から選べるようです。

####Trojan:EC2/PhishingDomainRequest!DNS
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254738/9273bdc5-d8ab-881c-2af0-b7d41ede1499.png)

この検出結果がどのようなものか知りたい場合は、ユーザーガイドを参照すれば良さそうです。

GuardDuty の Trojan 検索タイプ
https://docs.aws.amazon.com/ja_jp/guardduty/latest/ug/guardduty_trojan.html

様々なタイプが紹介されていますね。これ読むのも楽しそうです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254738/3f285111-5a45-3693-8bf0-8b2e096b5d61.png)


#6. CloudWatchへの通知
GuardDutyの「設定」を見ると、次のような項目があります。
Cloud Watch Event(CWE)に通知を飛ばしているようですね。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254738/f87adab4-b7b1-810e-29b3-38c4b995a2ec.png)

早速CloudWatchのコンソールで見てみましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254738/b010687e-6a08-656a-c444-3e3e8ab5d27d.png)

イベント→ルール→ルールの作成と進みます。
こんな感じで「GuardDuty」の「GuardDuty Finding」をトリガに、ターゲットとなる動作を実行できるようです。
Lambda関数が実行できるので、かなり自由度が高そうですね。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254738/070583cc-bed8-8aa4-f2a8-f24b6d3e58bc.png)

詳細は割愛しますが、SNSで通知飛ばせるようにしてみました。アイディアが平凡ですみません、、、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254738/cf8284f4-623d-8379-b94a-9aff3b7c3adf.png)


#7. おわりに
圧倒的な速さでいわばIDSが導入できるのは圧巻でした。ボタン押すだけ？信じられないですね。
CloudWatch Event越しにLambda関数の実行もできるなど、GuradDutyのイベントトリガで様々なタスクが自動化できそうです。

では、GuardDutyのログが出るまで待ちます。
RubyでURLエンコーディングする方法

[自分のブログ](https://yuya-tequila.hatenablog.com/entry/2019/01/27/213953)の転載記事です。

## 結論
URLの中で使用する文字列をエスケープするときには`URI.encode_www_form`メソッドを使用しよう。

## 調べたこと
最近、株価を分析するwebアプリを個人開発しています。
その中で、銘柄名でGoogle検索したときの結果をスクレイピングしたくなりました。

銘柄名と証券コードはStringでDBに登録済みなので、簡単に持ってこられます。
ですが持ってきた文字列をそのままクエリストリングに入れてしまうと、うまく検索できないことがありました。  

```ruby
search_url = "https://www.google.co.jp/search?hl=jp&gl=JP&q=日本M&Aセンター"
```
<img width="935" alt="スクリーンショット 2019-01-27 22.23.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/222253/e0fadc81-e6fa-14ab-0d45-603df5efeb7f.png">
欲しい結果は取得できていますが、検索ワードが"日本M"で途切れています。
"&"が正しくエスケープできていないのかと思い、調べてみたところ、以下の方法でできました。  

```ruby
require 'uri'

query = URI.encode_www_form(q: '日本M&Aセンター')
=> "q=%E6%97%A5%E6%9C%ACM%26A%E3%82%BB%E3%83%B3%E3%82%BF%E3%83%BC"

search_url = "https://www.google.co.jp/search?hl=jp&gl=JP&"
=> "https://www.google.co.jp/search?hl=jp&gl=JP&"

search_url += query
=> "https://www.google.co.jp/search?hl=jp&gl=JP&q=%E6%97%A5%E6%9C%ACM%26A%E3%82%BB%E3%83%B3%E3%82%BF%E3%83%BC"

```
<img width="935" alt="スクリーンショット 2019-01-27 22.22.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/222253/7a3a1a9b-0ceb-4b50-c3dc-08ab0c2b7e90.png">
上記のURLを打ち込むと、"&"が正しくエスケープされているのがわかります。他の文字はエンコード前の文字に戻っていますが。

## 失敗したケース
ちなみに調べている中で最初に出てきた方法は`URI.encode`を使う方法だったのですが、そのやり方では正しくエスケープされませんでした。

```ruby
require 'uri'

search_url = "https://www.google.co.jp/search?hl=jp&gl=JP&q="
=> "https://www.google.co.jp/search?hl=jp&gl=JP&q="

search_url += "日本M&Aセンター"
=> "https://www.google.co.jp/search?hl=jp&gl=JP&q=日本M&Aセンター"

URI.encode search_url
=> "https://www.google.co.jp/search?hl=jp&gl=JP&q=%E6%97%A5%E6%9C%ACM&A%E3%82%BB%E3%83%B3%E3%82%BF%E3%83%BC"

```
最終的に生成された文字列を見比べてみると、"&"がエスケープされていないことがわかります。

```ruby
# "M&A"が"M%26A"になっている。
success_url = "https://www.google.co.jp/search?hl=jp&gl=JP&q=%E6%97%A5%E6%9C%ACM%26A%E3%82%BB%E3%83%B3%E3%82%BF%E3%83%BC"

# "M&A"が"M&A"のまま。
failure_url = "https://www.google.co.jp/search?hl=jp&gl=JP&q=%E6%97%A5%E6%9C%ACM&A%E3%82%BB%E3%83%B3%E3%82%BF%E3%83%BC"
```

[Ruby 2.6.0 リファレンスマニュアル](https://docs.ruby-lang.org/ja/latest/class/URI.html#S_ENCODE)によると、`encode`メソッドはobsoleteとのことなので、今後は使用しないほうがよいかもしれません。
RDEC: Integrating Regularization into Deep Embedded Clustering for Imbalanced Datasets

# はじめに
本来、論文や数式を全く読めない私が、論文内の図示だけを見て、 「これは凄そうだ！」 と直感的に感じてワクワクしたため、メモとしてココに残す。
あまりのワクワク感から論文の全文を日本語に翻訳したが、著者に無断で翻訳後の論文を公の場で公開することや図示を引用することは著作権に抵触するらしいので、この場では公開しない。
あくまで個人の趣味利用でPrivate Gitなどを利用してワキワキ楽しむだけのレベルとする。

# 読み込んだ論文
AMCL 2018で発表された論文。
**http://www.acml-conf.org/2018/ACML%202018%20Main_Home.html**

**RDEC: Integrating Regularization into Deep Embedded Clustering for Imbalanced Datasets**
**http://proceedings.mlr.press/v95/tao18a/tao18a.pdf**

Yaling Tao yaling1.tao@toshiba.co.jp
Kentaro Takagi kentaro1.takagi@toshiba.co.jp
Kouta Nakata kouta.nakata@toshiba.co.jp
Corporate R&D Center, Toshiba Corporation, Kawasaki, Japan
Editors: Jun Zhu and Ichiro Takeuchi

# ポイント

- 不均衡データのための正則化ディープエンベデッドクラスタリング (RDEC)
- 不均衡なデータのごく少数派のクラスに適切な重心を置いて、物凄くうまく分類できる
- クラスタリング手法
- ディープラーニングとの組み合わせ
- 正則化項あり
- 2018.11 時点で最高のパフォーマンス (state-of-the-art)
- 異常検知分野で猛威を振るうに違いない
- 私に機械学習の実装スキルがあれば即座に再現実装してみたいのですが。。。数式読めない時点でかなりダメね。。。
- MNISTデータセットによる分類精度は **`98.41％`**、 MNISTから派生した非常に不均衡なデータセットによる分類精度は **`85.45％`** で、現在の最善の結果よりも **`8％`** 近く高い
- 日本語訳を公開してもいいか？ なんて、TOSHIBAさん相手に聞く勇気なんて全く無いです。。。

# おわりに
せめて私に力があれば。。。
NAT環境におけるFTPS接続について

## 実現したい事
クライアントからFTPSリバースプロキシサーバ経由でFTPサーバにデータをアップロードする

## 環境
クライアント -- ファイアウォール -- FTPSリバースプロキシサーバ -- FTPサーバ

・FTPSリバースプロキシサーバとFTPサーバはプライベートIPの環境
・クライアントのリクエストは、ファイアウォールの宛先NATの機能で、FTPSリバースプロキシサーバのIPをグローバル→プライベートに変換する
・FTPSの接続方式は、explicitでパッシブモードである


## 直面したトラブル
FTPSの接続構成は制御用とデータ用と2つに分かれる
クライアントは制御用ではグローバルIPアドレス：21/tcpに接続しに行くが、
データ用ではプライベートIPアドレス：パッシブモードで指定したポート番号に接続しに行き、
ファイアウォールでブロックされ接続できなかった。
パッシブモードはFTPSリバースプロキシサーバがクライアントに接続先のIPアドレスとポート番号を伝えるが、
デフォルトでは、接続先のIPアドレスは、FTPSリバースプロキシサーバのプライベートIPになる


## 解決策
FTPSリバースプロキシサーバ で、パッシブモードの接続先のIPアドレスをグローバルIPで指定する
[Unity]Android Studio 3.1.2 によるAndroidネイティブプラグイン作成

# Androidネイティブプラグインの作り方

ネットを検索すればプラグインの作り方について書かれたサイトは沢山見つかりますが、どれも古い情報だったためか、すんなりと作成できなかったので、簡単にまとめてみます。

## UnityPlayerActivityを継承したクラスを使ったプラグイン

[ここ](https://qiita.com/tempura/items/5e7992896c0faba08da3)にあるように、プラグインの作り方にはいくつか方法があるのですが、今回はUnityPlayerActivityを継承したクラスを使う方法について書いていきます。

1. Android Studio のプロジェクトを新規作成して、Android Libraryモジュールを追加
2. Unityのclasses.jarをlibsにコピー（classes.jarの場所は[公式ドキュメント](https://docs.unity3d.com/ja/current/Manual/AndroidUnityPlayerActivity.html)を参照）
3. UnityPlayerActivityを継承したjavaクラスを追加
4. プラグインにclasses.jarを含めないようにするため、gradleに

```
android.libraryVariants.all { variant ->
    variant.outputs.each { output ->
        output.packageLibrary.exclude('libs/classes.jar')
    }
}
```

を追加

## Unityでビルドしようとするとclasses.jarのモジュールが競合してしまう

検索すると、大体上記の方法にたどり着くのですが、手順4でclasses.jarを除外することができません。（おそらく、gradleのバージョンが上がって、dependenciesに`implementation fileTree(dir: 'libs', include: ['*.jar'])`と記述されているからだと思われます。以前は`compile～`とかだったみたい。正しい情報を知りたい方はGradleの公式ドキュメントを見てください。）

色々調べた結果、implementation用のディレクトリの他にコンパイル時だけ参照するライブラリ用のディレクトリを追加し、そこにclasses.jarを置きます。そして、depencenciesにcompileOnlyでそのディレクトリを指定してやることで、classes.jarを含まないaarを出力することができました。

1. Android Studio のプロジェクトを新規作成して、Android Libraryモジュールを追加
2. compile_onlyディレクトリを新規作成し、Unityのclasses.jarをそこに配置
3. UnityPlayerActivityを継承したjavaクラスを追加
4. gradleのdependenciesに`compileOnly fileTree(dir: 'compile_only', include: ['*.jar'])`を追加

例

```
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    compileOnly fileTree(dir: 'compile_only', include: ['*.jar'])

    implementation 'com.android.support:appcompat-v7:27.1.1'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
```

## まとめ

classes.jarはcompileOnlyで追加する！
他の細かい手順は省略・・・（検索すれば大体わかるはず）