OmniAICreator/Qiita-1.07M huggingface dataset:
Heroku で pyzbar を使う

## はじめに
pythonのpyzbarを使ってQRコードを読み取るアプリをHerokuでデプロイしようとしていたところ、
import Errorでハマったので備忘録

## 環境
- Heroku
- python 3.9.1
- pyzbar 0.1.8


## 概要
pyzbarはzbarのラッパーのためライブラリが必要。
ubuntuではlibzbar-devをインストールすれば使えるよう。
Windowsでやっていたから気付かなかった。

## 1. Buildpackを追加
Herokuからheroku-buildpack-aptというbuildpackが公開されている。
デプロイ時にAptfileに書かれているパッケージをインストールしてくれる。

また、heroku-buildpack-zbarというbuildpackもあるよう。
こちらはデプロイ時にzbarをインストールしてくれるらしいが未確認。

今回はaptを使っていく。

## 2. Aptfileを作成
```text:Aptfile
libzbar-dev
```
これだけでデプロイ時に勝手にやってくれる

## 3. デプロイ
通常通りにデプロイすればこんな感じでインストールしてくれる

```git.log
remote: -----> Apt app detected        
remote: -----> Detected Aptfile or Stack changes, flushing cache        
remote: -----> Updating apt caches        
remote:        Hit:1 http://archive.ubuntu.com/ubuntu focal InRelease        
remote:        Hit:2 http://apt.postgresql.org/pub/repos/apt focal-pgdg InRelease        
remote:        Hit:3 http://archive.ubuntu.com/ubuntu focal-security InRelease        
remote:        Hit:4 http://archive.ubuntu.com/ubuntu focal-updates InRelease        
remote:        Reading package lists...        
remote: -----> Fetching .debs for libzbar-dev        
remote:        Reading package lists...        
remote:        Building dependency tree...        
remote:        The following additional packages will be installed:        
remote:          libmagick++-6-headers libmagick++-6.q16-8 libmagick++-6.q16-dev        
remote:          libmagick++-dev libv4l-0 libv4lconvert0 libzbar0        
remote:        The following NEW packages will be installed:        
remote:          libmagick++-6-headers libmagick++-6.q16-8 libmagick++-6.q16-dev        
remote:          libmagick++-dev libv4l-0 libv4lconvert0 libzbar-dev libzbar0        
remote:        0 upgraded, 8 newly installed, 0 to remove and 9 not upgraded.
```

## ハマりポイント
#### その1
Herokuではsudoもaptも使えない。
だから```heroku run bash```でターミナルに入ってもできない。

#### その2
インストールするパッケージはlibzbar0ではなくlibzbar-dev。
最初に見た記事ではlibzbar0だったためここで躓いた。


## Git push時に変更がなくてもPushしたい
```bash
git commit --allow-empty -m "commit without change"
git push
```
これで空のコミットを生成できる。
[Unity]2020.2.2f1 問題⇒対応関連（書きかけ）

備忘です。
掲題のバージョンのunityであった困ったことの対処方法を上げていこうと思います。
原因は置いておいて、問題と対処策だけ書いていこうかと。

適宜更新

・Resourceファイル存在するのにも関わらず、ロードに失敗する。
　⇒対象のResourceフォルダとAddressableAssetsDataフォルダがある場合は
　　AddressableAssetsDataをフォルダ選択してReimportする。

・ゲームをビルドしたときだけ謎のエラーが出る。（プレイしたときは出ない）
　＜エラー内容＞
ArgumentException: The Assembly System.Runtime.CompilerServices.Unsafe is referenced by YZY.dll ('Assets/Plugin/XXX/YZY.dll'). But the dll is not allowed to be included or could not be found.
　⇒Assets/Plugin/XXXのフォルダに「System.Runtime.CompilerServices.Unsafe.dll」を入れる。そのあとにUnityの画面から、「Unsafe.dll」を選択して、Select platforms for plugin の項目から、Any Platformのチェックを外した後に、Standaloneに設定する。
![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353494/4208b49e-11d0-7117-382f-7f4f4f69fc45.png)


・ToggleGroup（1つのToggleしかOnを許さない状態）
　ToggleGroupに所属しているToggleをOnにしたまま、GameObjectのSetActiveでFalse⇒Trueを行うと、「Toggle.isOn = true」の処理が行われてしまう。onValueChangeももちろん発生する。
　対処１：SetActiveでFalse設定するときに、ToggleGroupから外して、ActiveになったときにToggleGroupに追加
　対処２：
【Rails】 gem kaminari（初心者向け）

はじめに
---
WEBサイトの下部の方には必ずと言ってもいいほど、ページを表す数字が並んでいるかと思います。
最近自身のポートフォリオの作成で使用したので、自身の備忘録として、またこれから実装する初心者の方の参考になればと思い投稿していきたいと思います。
※何らかの表示するビューが出来ている程で進めさせていただきます。

開発環境
---
ruby 2.6.3
Rails 5.2.4.4


見本はこのようなものです
---
今回私自身が作成したのは下のタイプのもので、bootstrapやcssなどを使用しカスタマイズしております。デフォルトは上のタイプのもので、数字と英語が組み合わさったものになります。
![スクリーンショット 2021-02-12 1.06.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/942338/07378c36-a31a-7775-3de5-3a50eef236f7.png)

![スクリーンショット 2021-02-12 0.56.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/942338/e6ea8dad-7e4a-99dd-e5c8-af8be110388f.png)

kaminariとページネーション
---
実装の前に少しだけ説明します。
kaminariとはgemの名称で、ページネーションとは大量の情報を指定した数ごとに分割をし、それぞれのページへ遷移しやすくするためのリンクのことです。
ページネーションがないと、一つの画面に大量の情報が全て掲載されることになり、それを毎回読み込むのは大変...見る方も大変です！
そんな問題を解決する便利なアイテムというわけです。
前置きが長くなりましたが、実装を進めていきたいと思います。


gemのkaminariをインストール
---
以下の通り、Gemfileへの記述を加え忘れずにbundle installしてください。

```Gemfile.
gem 'kaminari'
```
```terminal.
bundle install
```
<br>
コントローラの記述を変更する
---
Userモデルを例にして、一覧画面にユーザー情報が掲載されているとします。

```users_controllers.rb
#元々の記述はこのような形だと思います。
def index
 @users = User.all
end

#最後のper()の部分が一画面に表示させる件数（今回は10件）
#デフォルトですと、id = 1から順番に取得されます。
def index
 @users = User.all.page(params[:page]).per(10)
end

# このように、orderの後に何で取得をするか条件を加えることも可能
# 下記の記述ですと、最新User10件を取得
def
 @users = User.all.page(params[:page]).per(10).order(created_at: "DESC")
end
```
<br>
ビューに記述を加える
---
画面に表示をさせるものの最後に、paginate @users (コントローラーで記述したインスタンス変数)を設定すれば完成です。
※ただし、指定した件数未満だとページネーションは表示されないので注意が必要です。

```index.html.erb
<% @users.each do |user| %>
  <%= user.name %>
  <%= user.age %>
  <%= user.address %>
<% end %>
<%= paginate @users %>
```
<br>
日本語表記に変えたい場合
---
①以下の記述を加えます。
こちらは、次に出てくる日本語化をしてくれるja.ymlファイルを読み込むための記述です。

```config/application.rb
config.i18n.default_locale = :ja
```
②config/locales/ja.yml
上記の階層に合わせて、ja.ymlファイルを作成します。
このja.ymlというのが、日本語化をしてくれるファイルになります。
最初、最後の部分を日本語でなく、記号やFont Awesomeの絵文字なんかに変えても対応可能です。

```ja.yml
ja:
  views:
      pagination:
        first: '最初'
        last: '最後'
        previous: '前'
        next: '次'
        truncate: '...'
```

最後にサーバーを起動すれば、ビューにて確認ができるかと思います。



終わり
---
今回は以上になります。
私自身もプログラミング初心者ですが、同じ様な立場の方に少しでも参考になれば幸いです。
また、もし内容に誤りなどがございましたら、ご指摘いただけますと幸いです。
エトワーニュ集会宣伝用看板の導入



#用意するもの
* エトワーニュのUnityプロジェクト
* Signboard.unitypackage([配布](https://drive.google.com/drive/folders/1C7LrCQ_LojcX1gxY9WA28u0pHO3YpGrL))

#導入

1. Signboard.unitypackageをエトワーニュのプロジェクトにインポートする
2. ProjectのAssets>SignboardにあるプレハブをHierarchyに入れる(Signboard_left、Signboard_backも同様)
 ![Prefab_dnd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1099239/4f4f6b15-dd55-7c0d-81df-20ca97944edd.png)
3. 看板の位置・角度を調整する(スケールを弄っていないエトワーニュならそのままでOK)
4. HierarchyにあるSignboardを対応するボーンの位置にドラッグアンドドロップする
<br>![Signboard_dnd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1099239/288603e6-dfda-14e4-18fa-a4725a6449c7.png) 

>**例**
>右手用(Signboard)なら
`Etoigne>Etoigne_bone>hips>spine>chest>shoulder.R>upper_arm.R>hand.R`
左手用(Signboard_left)なら
`Etoigne>Etoigne_bone>hips>spine>chest>shoulder.L>upper_arm.L>hand.L`
背中用(Signboard_back)なら
`Etoigne>Etoigne_bone>hips>spine>chest`


この手順を行うことによって、看板を手に持った状態(背中についた状態)になる。
<br>![ultimate_sign_etoigne.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1099239/fbb4c9f2-ad57-0189-dff9-ba7e6742b5b5.png)
これはやりすぎ

## 看板の出し入れ
このまま別のアバターとしてアップロードしても良いが、以下に記述した方法を使うと普段のアバターで看板の出し入れができるようになる。
VRCSDK2ではハンドサインにアニメーションを割り当てる方法、[Emoteswitch](https://booth.pm/ja/items/1242826)があるが、Emoteswitchのほうがお手軽。
VRCSDK3では[Radial Inventory System V2](https://booth.pm/ja/items/2278448)、[Avatars 3.0 CustomSet](https://booth.pm/ja/items/2435856)等を使用することで行える。

詳しいことはここで書くと長くなりそうなので各自調べるor詳しい人に聞くor私([@Sak_Bey](https://twitter.com/Sak_Bey))に聞くなどしてほしい
公式ドキュメントを読む！vol.1(React Native [TouchableOpacity])

### はじめに
こんにちは〜
私の大学もやっと春休みに入りました🙌
今春の目標は `開発(React Go Docker/Kubernetes)` & `Qiitaをたくさん活用する` なのですが．
後者に関して，たくさん記事をかけたらなと考えております！

最近はReactNativeでモバイルアプリを作ったり，様々なAPIを使っているのですが，とにかく<font color="MediumVioletRed">**公式ドキュメントが読めない**💦</font>のです．
時間がかかるし，，，英語だし，，．と避けてきたのですが，いつまでもそんなことをしている訳にもいかないので，**Qiitaに公式ドキュメントを読んだ備忘録を書く**ということを目標に頑張って行きたいと思います！

### TouchableOpacity
今回はTouchableOpacityに関して読んでいきたいと思います．
公式ページは[こちら](https://reactnative.dev/docs/touchableopacity)です．
簡単に言うと，Viewコンポーネントにインタラクションを加えるWrapperのようです．
早速詳しく読んでいきましょう！

### 内容
ページに遷移すると以下のようにあります．

> A wrapper for making views respond properly to touches. On press down, the opacity of the wrapped view is decreased, dimming it.

**Viewコンポーネントに触れた時に正確に反応するようにするWrapperで，押下した際に，Opacityが薄くなります．**

こんな感じでしょうか🤔
１発目から雑に解釈していますが，こんな感じで進めていきます🙇‍♂️💦

> Opacity is controlled by wrapping the children in an `Animated.View`, which is added to the view hierarchy. Be aware that this can affect layout.

**OpacityはViewの階層構造で追加された小要素の`Animated.View`をWarpすることで制御されます．レイアウトに影響を及ぼすので注意してください．**

難しいです．．． in は何にかかっているのでしょうか．

#### Example

```
import React, { useState } from "react";
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";

const App = () => {
  const [count, setCount] = useState(0);
  const onPress = () => setCount(prevCount => prevCount + 1);

  return (
    <View style={styles.container}>
      <View style={styles.countContainer}>
        <Text>Count: {count}</Text>
      </View>
      <TouchableOpacity
        style={styles.button}
        onPress={onPress}
      >
        <Text>Press Here</Text>
      </TouchableOpacity>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    paddingHorizontal: 10
  },
  button: {
    alignItems: "center",
    backgroundColor: "#DDDDDD",
    padding: 10
  },
  countContainer: {
    alignItems: "center",
    padding: 10
  }
});

export default App;
```
こんな感じでテストコードがありますね🤔
確かに`PressHere`を押すとカウントが増えて，Opacityが薄くなってます．

#### Reference

今度はReferenceをみていきましょう！
最初に思ったのが，Exampleに`onPress`とあるのに，Referenceにはないやん！と言うことです💫
どう言うことでしょうか．．．

よくみると，
> Inherits <font color="SkyBlue">TouchableWithoutFeedback Props.</font>

とありました．
なるほど，[TouchableWithoutFeedback](https://reactnative.dev/docs/touchablewithoutfeedback#props)を継承していたんですね😄

ページをみると，ありました！

> `onPress`
Called when the touch is released, but not if cancelled (e.g. by a scroll that steals the responder lock). The first function argument is an event in form of PressEvent.

**タップしてそれが離された瞬間に呼び出されます,ただし取り消されなければ(例えばタップしながらスクロールしたり)．**

確かにタップしながらスクロールするとカウントアップされませんでした．
Typeはfunction で RequiredはNo とありますね🤔

TouchableOpacityに戻りますが，今回はonPressしか使わなかったので，割愛します🙇‍♂️

### 終わりに

`TouchableOpacity` はユーザビリティを上げる際に頻繁に使えそうですね！
私のアプリでも使っていきたいと思います！

下手くそな翻訳に付き合っていただいてありがとうございました🙇‍♂️
これからも色々なドキュメントを読んでいこうと思うので，よかったらお付き合いください！
ご指南・ご指摘は，ジャンジャン待っています！色々教えていただけたら，幸いです💦

それでは！
cloud9　環境構築

メモです。参考にしないでください。

cloud9環境構築

#gitの設定

##EC2のボリュームの変更。
AWSから
EC2
インスタンスを選択し、『アクション』
『ボリュームの変更』１０→１５にする

##PHPのメモリ上限の変更

```
# 念のためシステムの設定ファイルをバックアップ
$ sudo cp --backup=numbered -f /etc/php.ini /etc/php.ini

# PHPのメモリ拡張
$ sudo sed -i -e "s/memory_limit = \(.*\)/memory_limit = -1/g" /etc/php.ini

# 結果確認
$ php -i | grep memory_limit
# -> memory_limitが-1になっていれば成功
```
##プロジェクトを作成
$ cd ~/environment
$ composer create-project --prefer-dist laravel/laravel プロジェクト名 "5.*"
googleスプレッドシートあれこれ（時間）


経過時間を計算する際の問題。
HH:MM:SSで入力された内容同士を計算するのは
そのまま計算してしまえば良いのだけれど、
ある決められた時間からの相対時間を計算して出力したいとき、
そのままの文字列だと正しく計算してくれないので、
**VALUE関数を使います**

```javascript
=VALUE("60:00:00")-SUM(A1,A2)
```

このように入力することで、
相対時間を計算することができるようになります。
VALUEの引数に上限に設定したい時間などを入れると、
オーバーしてるのか許容範囲内なのか判断することができるので、
結構使う場面は多いかもしれません。

- - -





ついでに入力した内容が時間表記ではない場合に、
条件付き書式のカスタム書式を*ISERROR関数*を使うことで、
判定をさせることが可能です。
あとは背景を赤色などにすれば、
視覚的にミスを把握することが可能です。
以下はサンプルですが、
**"空白ではなく、エラーだった場合"**のセルを指定するカスタム数式です。
よければお使いください。

```javascript
=AND(A1<>"",ISERROR(DATEVALUE(A1)))
```


それでは、
ありがとうございました。
JamfでVPN未接続時だけWebサイトのアクセスを制限する方法（未検証）

クライアントコンピュータ（Mac）に対して、VPNが未接続の時だけWebサイトのアクセスを制限する方法についてメモ的意味合いで記録します。案として、理論的にはいけそうじゃないかと考えています。おそらくMacのシステム環境設定で直接VPNの設定を施せばもっと簡単に実現できると思われますが、クライアント用のアプリを使ってVPNに接続する場合は一工夫必要になります。

# 本記事が対象としている環境
- クライアントコンピュータ：Mac / macOS Big Sur
- VPNクライアントアプリ：FortiClient
- MDM：Jamf Pro


# Jamf Proでの作業

#### 拡張属性を追加
VPN接続しているかどうかをifconfigコマンドで確認して、Yes/Noの値を返すスクリプトで拡張属性を追加。

#### Smart Computer Groupを作成
上記拡張属性でNoになっているコンピュータ（VPN未接続のコンピュータ）のグループを作成

#### 構成プロファイルのペイロードを作成
ペアレンタルコントロールのペイロードを作成。
内容はWebサイトのアクセス制限。
Scopeに上記Smart Computer Groupを指定。

#### ポリシーを作成
Maintenanceペイロードを利用し、インベントリ情報をアップデートするポリシーを作成。
トリガーをCheck-inに指定。
ScopeはVPN利用端末全部になるよう調整。



# クライアントで実行するスクリプトを作成
### スクリプトの概要
シェルスクリプトを作成。
このスクリプトのもっとも重要な任務は、VPN接続状態が変わったら、強制的にJamfのCheck-inを実行させること。具体的なコマンドは以下。

```sh
jamf policy
```

ただし、頻繁にそのコマンドを実施するのはサーバの負担が大きいため、一度実行されたら、次にVPN接続状態が変わるまでは1秒ごとに何もせず待機させる。待機させるコマンドは以下。数字は秒数。

```
sleep 1
```

Check-inのコマンドが一度実行されたかどうかは、フラグとなるファイルの有無で判定するようにする。VPN接続したタイミングではファイルを作成し、切断したタイミングではファイルを削除する。
ファイルを作成するコマンドは以下。

```
touch (ファイルパス)
```
ファイルを削除するコマンドは以下。オプション -f は強制的に実行する。

```
rm -f （ファイルパス）
```

スクリプトはコンピュータが稼働している間は永続的に走らせる必要があるため whileループで実行する。ループの中でVPN接続しているかどうかのif条件分岐、さらにファイルの有無のif条件分岐をネストした形にする。内容は以下のようにする。

1. VPN接続時にフラグファイルがなければ、Check-inのコマンドを走らせたら、その直後にフラグファイルを作成する。
2. VPN接続状態でフラグファイルがある間はただひたすら待機するのみ。
3. VPN接続が切れたら、フラグファイルが存在している場合のみCheck-inのコマンドを実行し、その後すぐにファイルを削除する（rm -f ファイルパス）。
4. VPN未接続状態で、フラグファイルがない間はただひたすら待機するのみ。
5. 次にVPN接続する時はまた 1 の手順に戻る

####その他のスクリプトに必要なコマンド
ifconfigコマンドで出力される情報から、VPN接続時だけ表示される'ppp0'をgrepで抜き出す。これを変数vpncheckに格納。

```
vpncheck=`ifconfig | grep 'ppp0'`
```
次に、フラグファイルの有無を確認するにはファイルが格納されるフォルダに対してlsコマンドを実行し、その結果に対してgrepを実行してファイル名で絞る。これらを | でつないただコマンドを変数fileに格納する。ここではひとまずフラグファイルの保存場所を「/private/var/tmp/」としている。

```
file=`ls /private/var/tmp/ | grep 'vpnflag'`
```

初めてスクリプトが実行されるタイミングは、コンピュータ起動直後のため、そのタイミングではVPN接続はされていない。よって、スクリプト冒頭で、前回コンピュータ使用時のフラグファイルが残っていればそれを削除しておく。

```
rm -f /private/var/tmp/vpnflag
```

###スクリプト全体
whileループ内の処理はフローチャートにすると以下のようになる。
![Untitled Diagram (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570497/ad480065-fad6-d75d-faa2-eca7c5a27963.png)


そして、ここまでの内容をスクリプトにまとめると以下のようになる。

```sh
#!/bin/sh

vpncheck=`ifconfig | grep 'ppp0'`
file=`ls /private/var/tmp/ | grep 'vpnflag'`

rm -f /private/var/tmp/vpnflag

while :
do
  if [ $vpncheck="" ]; then
    if [ $file="" ]; then
      sleep 1
    else
      jamf policy
      rm -f /private/var/tmp/vpnflag
      sleep 1
    fi
  else
    if [ $file="" ]; then
      jamf policy
      touch /private/var/tmp/vpnflag
      sleep 1
    else
      sleep 1
    fi
  fi
done

exit 0
```

これであとは、Launchdを利用し、コンピュータ起動直後にこのスクリプトファイルを実行するよう仕込めばうまくいくのではないかと考えているが、まだ検証できていない。
UnityIAPでAndroidのReceipt情報などを持ってくるときの注意点

# tl; dr
```cs
public static void ProcessReceipt(Product item)
{
    var receipt = Jsonをデシリアライズする処理(item.receipt);

    var payload = Jsonをデシリアライズする処理(receipt.String("Payload"));

    // json    Google によって提供される文字列にエンコードされた JSON
    // signature    Google によって提供される JSON パラメーターの署名
    var json = payload.String("json");
    var sig = payload.String("signature");
```


# 言いたいこと
諸悪の根源: https://docs.unity3d.com/ja/current/Manual/UnityIAPPurchaseReceipts.html

`Product` の `receipt` には JSON 文字列が入ってくるが、それをJSONとして解釈したとき `Payload` をキーとして引っ張ってこれる文字列は JSON 文字列であり、これをさらに JSON として解釈したとき……

1. `json` キーで取り出せる文字列が INAPP_PURCHASE_DATA に相当する JSON 文字列である(さらにこれをJSONとして解釈せねばならない)
2. `signature` キーで取り出せる文字列は INAPP_DATA_SIGNATURE に相当する文字列である

インターネットのどこを見ても説明が分かりづらい(具体的にProduct.receiptにどのような文字列が入り込むのか、そこまで具体的に挙げて説明しているサイトが見当たらないので)。

`JSON.stringify` した文字列を JSON に文字列として入れ込むの、好き過ぎじゃないですか。どこまでも入れ子して運用してる現場、沢山あるんだろうか……恐ろしい……。
【Red Hat OpenShift Administration対策】(2)Openshift上のRBACの仕組み

Red Hat openshift Administration試験(EX280)の勉強記事二回目です。
前回、認証機能であるHTPasswdアイデンティティプロバイダーの概念と設定手順について書きました。
今回は認可機能であるRABCについて書きます。

# Openshift上のRBACポリシーについて
Openshiftでは、認可(あるユーザーがどのオブジェクトにどのアクセス権を持っているのかを決めること)機能は、RBAC(Role Based Access Control)ポリシーによって定められます。
RBACとは、人によってはあまり聞き慣れない用語かもしれませんが、グループやユーザーをあるロール(役割)に所属させ、ロールにどのような操作を許可するか設定することによってアクセス権を制御する仕組みのことです。

Openshiftでは、まずロールを「クラスターロール」と「プロジェクトロール」に分かれており、それぞれに対しアクセス権が定められたいくつかのデフォルトロール(cluster-adminなど)が用意されています。

![20210206_Openshift上のRBACの仕組み.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684500/b8d790ca-ce8d-6367-1baa-c79a9b91c18a.jpeg)

新しくロールを定義することもできるようですが、EX280の範囲では考慮しないことにします。
これらのデフォルトロールに対し、グループまたはユーザーを割り当て(バインディング)することによって、Openshift上の操作権限の管理が行われます。

# Openshiftのユーザーの種類
Openshiftのユーザーは、大きく3種類に分けられます。
(1)一般ユーザー、(2)システムユーザー、(3)サービスアカウントです。

(1)一般ユーザーはシステムユーザーおよびサービスアカウントに該当しないユーザーです。

(2)システムユーザーは、Openshift構築時にシステムが自動作成するアカウントです。system:admin、system:anonymous(認証が行われなかった場合に適用されるゲストアカウント)などがあります。

(3)サービスアカウントは、プロジェクト作成時にプロジェクト単位で生成されるシステムユーザーアカウントです。プロジェクト単位のアクセス制限を行うために使用されます。system:serviceaccount:project1:user1などがあります。


# グループやユーザーのロール割り当て
グループやユーザーのロール割り当てをする際は、以下のコマンドのヘルプを見ればだいたいわかります。

```
oc adm policy -h
```

クラスターロールの操作を行う場合はadd-cluster-role-to-user/groupなどのコマンドを使い、ローカルロールの操作を行う場合はadd-role-to-user/groupなどのコマンドを使うことになります。ローカルロールの操作を行う場合は、oc project1などのコマンドを使って、対象のプロジェクトにスイッチしてからローカルロールの操作を行いましょう。

例として、次の状況を考えます。
・app1プロジェクト上にdevグループを作成する。devグループはapp1プロジェクトのedit権限を持っている。
・devグループにはuser1とuser2が所属している。
・user1はapp1プロジェクトのadmin権限を持っている。

まず、app1プロジェクトを作成します。以下のコマンドはクラスター管理者(例えばkubeadminなど)で実行します。

```
oc new-project app1
oc project app1
```

次に、devグループを作成し、user1とuser2をdevグループに所属させます。
コマンドを忘れたらoc adm -hでヘルプを見ましょう。

```
oc adm groups new dev
oc adm groups add-users dev user1
oc adm groups add-users dev user2
oc get groups
```

RBACポリシーを変更する場合はoc adm policy -hを見て必要なコマンドを実行すれば良いです。
今回の場合は以下のようになります。

```
oc adm policy add-role-to-group edit edit
oc adm policy add-role-to-user admin user1

```

# プロジェクト作成権限の削除
クラスター管理者以外がプロジェクトを作成できないように設定する場合、以下のコマンドを実行します。

```
oc adm policy remove-cluster-role-from-group self-provisioner system:authenticated:oauth
```

以下コマンドを実行して、self-provisionerロールがバインドされているグループやユーザーがないことを確認します。

```
oc get clusterrolebinding -o wide | grep self-provisioner
```
iOSでGoogle Mobile Ads SDKを8にするとMediation Test Suiteのビルドが通らなくなるのでダメだ

タイトルの通りで、Google Mobile Ads SDKのバージョンを8.0.0にするとMediation Test Suiteのビルドができなくなる。バージョンを下げるしか回避策はない。ダメだ。
マルチAZでCronクラスタを構築する（サンプルコードあり）

# 概要
シングルEC2で動いているCronバッチサーバを冗長化したいが、サーバーレス化する時間がない・・・
そんな時に既存のアプリ資産やCron資産を流用できるよう、EC2でマルチAZ Cronクラスタを構築したという話です。

# 環境
マルチAZ EC2（2台）
Linux（CentOS6,7かAmazonLinux,AmazonLinux2を想定）

# Cronのクラスタ機能
最近のCron（cronie）には実はアクティブ－スタンバイクラスタを実現するための機能が備わっています。
今回はその機能を使います。
ですがこれはあくまで、2台あるサーバのどっちでCronを動かすか、という判断をするための機能があるだけで、

- ハートビート通信
- フェールオーバ制御
- クラスタ仮想IP

といったHAクラスタに付きまとう種々の機能は無いので、このへんを作っていきます。
ただ、年１くらいで発生するAZ障害を考慮すると、普通のHAクラスタと異なり、ハートビート通信が途切れることを前提に考える必要があります。なので基本EC2間の通信に依存した判定は行わず、それぞれが独立して動く必要があります。

なお、Cronクラスタ機能については詳しいサイト様があるので詳細は割愛します。（ありがとうございます！）

- [Multi-AZに対応した高可用Cronサーバを構築する](https://dev.classmethod.jp/articles/construct-multi-az-nized-cron-server/)
- [cronのクラスタリングサポート（CentOS7）](https://mitomasan.hatenablog.com/entry/2015/08/26/000616)

# 構成
今回は以下のような構成で作ります。
![Cronクラスタ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464775/26518684-3284-61e8-e5ab-d665d5f44e5a.png)

- CronクラスタのためにCron領域（/var/spool/cron）をEC2間で同期、もしくは共有する必要があるので今回はEFSで共有化します。
- ハートビート通信を行います。今回はping疎通と、AZ障害を考慮してインターネット疎通も行います。（AZ障害時はEC2間でping通信ができなくなるので、自身がインターネットに出れるか？を正常or異常の判断に使おうという考えです）
- クラスタ仮想IP（EIP）をフェールオーバ時に移動させます。そのため、各EC2にはローカルIPを2つ振ります。1つは自サーバ専用のEIP用、2つ目はクラスタ仮想EIP用です。これにより、アクティブ機がインターネットに出る際のIPを常に固定できます。外部接続先があるシステムでは、これは重要な要件です。

# ハートビート通信
今回実装するハートビート通信のロジックを簡単に書くと以下です。
※クラスタペアの相手サーバのことをピアサーバと呼ぶことにします。

１．ピアサーバのローカルIPへPing
↓
２．ピアサーバのグローバルIPへPing
↓
３．１も２も失敗した場合、インターネットに出れるかをチェック（googleなど信頼性が高い公開サイト、念のため2か所使う）
↓
４．３がNGだった場合、自サーバ側のAZ障害と判断してスタンバイに降格する。
↓
５．３が問題なかった場合、ピアサーバ側の障害と判断して自サーバがアクティブに昇格する。

# フェールオーバ処理
フェールオーバ処理は以下の流れで行います。
スタンバイからアクティブへの昇格を例にします。上の構成図を見ながらだと分かりやすいと思います。

１．ピアサーバのプライマリローカルIPへ、ピアサーバ専用のEIPをアタッチします（EIPをセカンダリローカルIPからプライマリへ移動）
この時点でクラスタ仮想IPは一時的に無くなります。
![FO1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464775/4e67d0b5-9558-8a52-3309-58a4ef5f7c88.png)

２．自サーバのプライマリローカルIPへ、クラスタ仮想EIPをアタッチします。
![FO2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464775/ddaf4636-6875-c8e9-7d89-9f46314978f2.png)

３．自サーバのセカンダリローカルIPへ、自サーバ専用EIPをアタッチします。
![FO3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464775/26803aac-97be-da69-8418-1746bf004d02.png)

４．最後に```crontab -n <自サーバ名>```と実行し、Cron実行サーバを切り替えて完了です。

なぜこんなEIP付け替えをわざわざやるのか？と思われるかもしれません。
それは、EC2のルーティング設定が、外部発信時に常にプライマリローカルIP（のNIC）を使うようになっているためです。
なので使いたいEIPは常にプライマリ側にアタッチしておく必要があるのです。

# 両サーバで同じバッチが同時に動いてしまうことはないの？
可能性としてはゼロではないと思います。
ただcronieの機能は、```/var/spool/cron/.cron.hostname```の内容を見て実行サーバを判断するというものです。
なのでここをEFS共有しておけば両サーバが同一ファイルをチェックすることになるので理論上、両サーバがアクティブとなる（同じバッチが同時に動く）ことは無いといえます。

# サンプルコード
[GitHub](https://github.com/rabiusagi/cron_cluster)に上げておきます。
サンプルコードでは、上に書いたハートビート処理やフェールオーバ処理、他にも信頼性を上げるための細かいチェック処理を入れています。
Cronで5秒間隔くらいで実行するイメージでいます。
よろしければ参考にしてください。
シェルの書き方が拙いところはご容赦ください・・・。

# まとめ
クラスタ制御をゼロから開発するのは思ったより苦労しました。
皆様のお役に立てることを祈ってます。
でもとっととサーバーレスへ移行しましょう！（台無し
【Ruby】ソケットをプロミスキャスモードにする

# メモ

- 原理的には以下ページの通りに行う。 `setsockopt` を呼び出して、その時に `PACKET_ADD_MEMBERSHIP` オプションとそのオプションに必要な `struct packet_mreq` のデータを渡せば良い。
[Man page of PACKET](https://linuxjm.osdn.jp/html/LDP_man-pages/man7/packet.7.html)
- `struct packet_mreq`はCの構造体であるが、[参考リンク](https://kure.hatenablog.jp/archive/category/setsocopt)の通り色々と調べたところ、Rubyから渡す場合は構造体のメンバのデータを順番に並べた文字列を渡せば良さそう。
- 例えば、 `mr_ifindex` はインターフェース番号(int=4Byte)なので、Rubyの文字列の一文字のデータはCのchar1つに変換されるよう（動作的にそう見えるが厳密には違うかも）なので、インターフェース番号を加えた4文字の文字列を渡せば良い。下記の `mr_ifindex` メソッドであれば、例えば、インターフェース番号が `1` だったら `"1000"` が返る。
- `ETH_P_ALL` はとりあえず全てのプロトコルを対象とした番号(0x0003)をネットワークバイトオーダーに変換(htons)した値を指定。
- 実行には root 権限が必要。

# サンプルコード

```ruby
require "socket"

SOL_PACKET = 0x0107 # bits/socket.h
PACKET_ADD_MEMBERSHIP = 0x0001 # netpacket/packet.h
PACKET_MR_PROMISC = 0x0001 # netpacket/packet.h
ETH_P_ALL = 768 # htons(ETH_P_ALL), linux/if_ether.h

# @return [Integer]
def if_name_to_index(if_name)
  Socket.getifaddrs.find do |ifaddr|
     ifaddr.name == if_name
  end&.ifindex
end

# int(4Byte)
#
# @return [String]
def mr_ifindex(if_name)
  [[if_name_to_index(if_name)].pack("c")].pack("a4")
end

# unsigned short(2Byte)
#
# @return [String]
def mr_type
  [PACKET_MR_PROMISC].pack("S")
end

# unsigned short(2Byte)
#
# @return [String]
def mr_alen
  [0].pack("S")
end

# unsigned short(1Byte * 8)
#
# @return [String]
def mr_address
  [0].pack("C")*8
end

# https://linuxjm.osdn.jp/html/LDP_man-pages/man7/packet.7.html
# struct packet_mreq {
#  int            mr_ifindex;    /* インターフェース番号 */ 4Byte
#  unsigned short mr_type;       /* 動作 */ 2Byte
#  unsigned short mr_alen;       /* アドレスの長さ */ 2Byte
#  unsigned char  mr_address[8]; /* 物理層のアドレス */ 1Byte * 8
#};
#
# @return [String]
def mreq(interface)
  mr_ifindex(interface) + mr_type + mr_alen + mr_address
end

mreq = mreq("eth0")

sock = Socket.new(Socket::AF_PACKET, Socket::SOCK_RAW, ETH_P_ALL)
sock.setsockopt(SOL_PACKET, PACKET_ADD_MEMBERSHIP, mreq)
```

# 参考
https://kure.hatenablog.jp/archive/category/setsocopt

Ruby Raw Socket on Linux (ruby 1.9.3, linux x86_64) https://gist.github.com/k-sone/8036832
【UiPath】ParallelアクティビティでDelayとThrowを並べるとタイムアウトの代用はできるのか？

## 概要
UiPathでは、一部のアクティビティはTimeoutプロパティを持っておらず、
そこで固まるとエラーにもならず処理がその場で止まってしまうということが起こりえます。

それを回避する策として、ParallelでDelayとThrowを並べる方法が以下で紹介されていますが、
これは本当に有効なのか？というところを確認してみます。

* [timeoutプロパティを持たない-アクティビティの使用法について](https://www.uipath.com/ja/resources/knowledge-base/timeout%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%82%92%E6%8C%81%E3%81%9F%E3%81%AA%E3%81%84-%E3%82%A2%E3%82%AF%E3%83%86%E3%82%A3%E3%83%93%E3%83%86%E3%82%A3%E3%81%AE%E4%BD%BF%E7%94%A8%E6%B3%95%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)

## 検証
Timeoutプロパティを持たない「Excel Application Scope」にParallelを並べて、
途中で処理を打ち切ってタイムアウトできるかを検証します。

### Excelを開く
まず、A1セルからF1048576セルまで<b>=NOW()</b>で埋め尽くした重いExcelを用意し、
UiPathでそのExcelを開くだけのワークフローを作ります。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/1c83b3dc-3da0-a268-b66a-feddb3e3ffbe.png)|
|:--|

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/7b028c15-8f5e-e06b-bf10-983a35688f4e.png)
結果がこちら。20秒ぐらい開くのにかかっています。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/4563446d-b439-4742-5768-04a5427728ff.png)|
|:--|

### DelayとThrowを並べる
念のためこちらも単体で動作確認します。
Delayは5秒、ThrowはTimeoutExceptionをスローさせ、わかりやすいようにTryCatchで囲んでログを出します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/d43b776f-2322-2034-2bcc-b18a6ef39aa8.png)

結果がこちら。ここまでは想定通りですね。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/627338a7-20ac-6be3-a7a7-babd8b7d14f5.png)|
|:--|

### Parallelで並べる
問題はここから。作った2つのシーケンスをParallelで一つにまとめます。
Parallelの条件プロパティには忘れずにTrueを設定。
これでExcelを開くのに5秒以上かかったらエラーをスローするワークフローを作ったつもりですが…。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/ccdbe120-345d-3f77-47cb-c37c4c900513.png)

結果がこちら。
残念ながら普通にExcelを20秒弱かけて読み込んだだけで終わってますね。エラーも出ていません。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/c0a98bde-6f3e-567e-e071-72ca31c45086.png)|
|:--|

### デバッグモードで動きを見る
低速ステップを使って動きを見るとこんな感じです。（※倍速再生）

![6xmce-ndc3k.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578020/6c6e2818-3140-66da-5e65-c1f2f0ad63c5.gif)

## 結論
結論として、ParallelでDelayとThrowを並べてもタイムアウトの代用にはならないようです。
環境によるのかもしれませんが…。

なぜこうなるのか？というところですが、
以下の記事でParallelの動きについて解説されています。
厳密な並列処理は今のところ難しいようですね。

* [並列 (Parallel) アクティビティについて](https://www.uipath.com/ja/blog/developer/about-parallel-activities)


## 動作環境
- UiPath Studio Pro 2020.4.3 Community License
 - UiPath.Excel.Activities 2.6.3
 - UiPath.System.Activities 19.8.0
- Microsoft Excel 2013
rubyで変数とメソッドの定義 

**hash　文字列**
hash = {“key” => “value”, “key2” => 80}
hash[“key”]
hash[“key”] = “update”
hash[“add”] = “add”

**hash　シンボル**
hash = {:key => “value”, :key2 => 80}
hash = {key: “value”, key2: 80}
hash[:key]

**普通**
def fefefe(name, age)
　puts “#{name} #{age}” 
end

fefefe(“沖田”, 25)




**キーワード引数**
def fefefe(name:, age:)
　puts “#{name} #{age}” 
end

fefefe(name: “沖田”, age:25)
ChromebookにHomebrewをインストールする方法

# 内容
ChromebookのLinux環境(Crostini)にHomebrewをインストールする方法です。
なお、x86系CPUの機種が対象です（ARM系CPUは対象外）

# 環境
- Asus Chromebook C425TA
 - インテル® Core™ m3-8100Y  
- Google Chrome OS
 - バージョン: 88.0.4324.109（Official Build）（64 ビット）
- Debian GNU/Linux 10 (buster)

# 事前準備
必要なpackageをインストールしておきます。

```
$ sudo apt-get update && sudo apt-get -y install build-essential curl file git
```

# インストール
```
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

上記コマンドを実行するとインストールするディレクトリを聞かれます。

```
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
==> Select the Homebrew installation directory
- Enter your password to install to /home/linuxbrew/.linuxbrew (recommended)
- Press Control-D to install to /home/rshibasa/.linuxbrew
- Press Control-C to cancel installation

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

[sudo] password for rshibasa: 
```
パスワードの入力をすると`/home/linuxbrew/.linuxbrew `に、Ctrl+Dで入力を終了すると自身のホームディレクトリ以下にインストールされる。
[FAQ](https://github.com/Linuxbrew/brew/wiki/FAQ)によると`/home/linuxbrew/.linuxbrew`以下にインストールされることを前提としているパッケージ（バイナリ）もあるのでホームディレクトリにはインストールしない方がいいようだ。

パスワードを設定していない場合には以下のコマンドで設定する。

```
$ sudo passwd $USER
```

# PATHの設定

インストールが終了すると最後に次の作業を指示してくれる。
使っているシェルやbrewのインストール先によって異なるので、インストーラーの出力した内容に従う。

```bash:例
==> Next steps:
- Add Homebrew to your PATH in /home/rshibasa/.profile:
    echo 'eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv)' >> /home/rshibasa/.profile
    eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv)
```

# 動作確認

`brew doctor`を実行して`Your system is ready to brew.`と出力されれば問題なし 

```
$ brew doctor
Your system is ready to brew.
```

# sudoのPATHを修正しておく
この状態のままだとbrewでインストールしたコマンドを`sudo`で実行した際に`command not found`になってしまう。`/etc/sudoers`を編集してbrewへのPATHを通しておく。

```
$ sudo visudo
```

`secure_path`にbrewのPATHを追加する。

```text:変更前
Defaults    secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
```

```text:変更後
Defaults    secure_path="/home/linuxbrew/.linuxbrew/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
```

brewのPATHの調べ方

```
$ echo $(brew --prefix)/bin
/home/linuxbrew/.linuxbrew/bin
```

以上の作業でCrostiniでもbrewが使えるようになりました。
[Mac]  PC本体の更新(アップデート後のエラー)について

##pcのスペック

・**MacOS BIG Sur**
最近更新してバージョン11.2.1
・**VScode**
バージョン:1.53.1
　　
　　
プログラミングの学習をするに当たって、
**VScode**を使用しているのですが、

**PC本体の更新**をする際に、毎回と言っていいほど、
VSコードの右下あたりに
　　
<h4>「gitをダウンロードしますか？」と出て来ます。

**ダウンロードも何も現在進行形で使っています。**
　　

定期的に最新の状態に保ってくれているのはすごく有難いんですが、
その本体更新後に毎回出てくる文字が邪魔なんで**解決法**を書いていきます。（＊自分の場合の解決方法です)


　　
　　

もし、gitやその他、エラーが起きたら、本体のバージョンUpに伴って、
**コマンドラインツール**とのパスがうまく通っていない可能性があリます。
(恐らく環境構築あたり)

なので、
**Gitの場合**
<h3>xcode-select --install


をターミナルで打ってあげて、
**最新のソフトウェア**に更新してあげると、直る可能性が高いです。

**自分の場合はこれで邪魔な記述が出て来なくなります！**
GitHub Actionsを用いて定期的にIssueを作成する方法


## これは何

- [GitHub Actions](https://docs.github.com/ja/actions)で Issue を定期的に作成するための YML ファイルの定義を記載する
  - 定期的に手動で Issue を作成する場合など少しだけ手間を減らすことが出来る :muscle:

### 使用する Actions

https://github.com/actions-ecosystem/action-create-Issue

## 設定

- GitHub レポジトリはすでに作成している前提で記載します

### ディレクトリの作成

- GitHub Actions の設定ファイルは `.github` フォルダ以下に記載します

```bash
cd path/to/repository
mkdir -p .github/workflows
```

### YML ファイルの作成

```bash
touch .github/workflows/create_issue.yml
```

### 設定を記述

- 今回は月曜日の 09:00(JST)に定期的に Issue を作るように設定してみる
  - GitHub Actions の cron 定義は[こちら](https://docs.github.com/ja/actions/reference/events-that-trigger-workflows#scheduled-events)を確認ください :pray:

```yml
name: Create an issue on Monday 09:00 (JST)

on:
  schedule:
    - cron: '0 0 * * 1'

jobs:
  create_issues:
    runs-on: ubuntu-latest
    steps:
      - name: Get today and tomorrow date
        id: date
        run: |
          echo "::set-output name=tomorrow::$(date "+%Y/%m/%d" -d "1 day")"
      - name: Create an issue
        uses: actions-ecosystem/action-create-issue@v1
        with:
          github_token: ${{ secrets.github_token }}
          title: '【${{ steps.date.outputs.tomorrow }}】定期タスク'
          body: |
            ## To do
            + [ ] 準備

          labels: |
            Routine
```

記述がおわったら master(main)ブランチに commit & push しておきましょう。

## References

https://docs.github.com/ja/actions
【Android】Spock ADBが便利だったのでご紹介

Android Studio（IntelliJ IDEA）のプラグイン「Spock ADB」がAndroid開発において便利だったのでご紹介したいと思います。

https://plugins.jetbrains.com/plugin/11591-spock-adb

# インストール
インストールに関しては、一般的なプラグインと同様にAndroid StudioのPluginsから検索してインストールできます。
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995/93adbb80-19cc-239b-5608-ba8cc6a68da4.png width=400 />

インストールが完了すると、サイドバーに「Spock ADB」の項目が追加され、Viewが表示されます。
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995/a0167dd8-1c74-a3c7-fedd-0aaa6435cc18.png width=400 />

# 機能
上記のスクショを見てもらえれば何となく分かるかと思いますが、端末・アプリに対していくつかの操作をすることが出来ます。
以降、簡単に説明します。

---
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995/8e11e6a8-7f7d-7cd8-6aa9-069c14e99541.png width=400 />
現在表示しているActivityやFragmentがわかります。（予想）
初っ端からアレですが、ここの機能はうまく動かないようで [issue](https://github.com/WahdanZ/SpockAdb/issues/2#issuecomment-660598374)も立っていました。（そのため実際に動かせないため「予想」としております‥）

---
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995/cc339ee1-c175-8e7f-90b0-bc82d7a65ba0.png width=400 />
アプリのデータ消去・アンインストール・停止などが可能です。データ消去して再起動、とかは開発する上で度々行う操作かと思うので、それがワンクリックでできるのは便利ですよね。

---
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995/cc472a19-911f-9e24-adb9-b9d767be7a76.png width=400 />

Wi-FiのON/OFF、モバイルデータ通信のON/OFFの切り替えができます。

---
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995/98a2881e-28d1-b4b5-d152-d7ecaf500c5b.png width=400 />

パーミッションの付与・拒否を操作できます。

---
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995/b4b491fc-d211-bb20-10c3-18b6944376bd.png width=400 />

開発者向けオプションの項目を操作できます。

- 「アクティビティを保持しない」
- 「タップを表示」
- 「レイアウト境界を表示」
- 「ウィンドウアニメーションスケール」
- 「トランジションアニメーションスケール」
- 「Animator再生時間スケール」

開発者向けオプションの画面を開くのがわりと面倒だったので、これもワンクリックでできるようになって楽ですね。

---
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995/89f636ca-ac3e-f39b-fdfd-9607da6623e9.png width=400 />

テキスト入力ができます。
ただ、マルチバイト文字（日本語など）は使えないようです。

# まとめ

「Spock ADB」について簡単にご紹介をしました。
Android Studioからポチッとするだけで各種操作ができるので、便利だなと思いました。

ソースコードはGitHubで公開されているので、それぞれの処理がどのように行われているかと確認してみるのも面白いかもしれませんね。
https://github.com/WahdanZ/SpockAdb
kiroさんとgaoryuさんのファシリテーション対談メモ

# イベント概要
https://faciliview.connpass.com/event/204041/
株式会社アトラクタの原田 騎郎(kiro)さんにgaoryuこと高柳さんがファシリテーションについて色々聞いてみようというイベント。
# 何でファシリテーション学びたいの？
- ソフトウェア開発がここ20年でアジャイルになったからkiroさんはいやいや学んだ。朝からひたすら実験できると思ってたのにファシリテーションも学ぶの？面倒くさいというのが正直な感想(kiroさん)
- 一人ではソフトウェアを作らなくなってきた(作れなくなってきた)
- 分業をはじめ、黙々と昔はやっていたが、それができなくなってきた

# ファシリテーションって何だろう？
- ファシリテーションはテクニックではあるけど、ファシリテーションが大事なスキルなのかは微妙
  - こうなんじゃない？やってみたら？位の感覚でいいとkiroさんは思っている
  - 究極のファシリテーションは全て委ねることだったが、それができないのが難しい
- kiroさんはファシリテーションで失敗量が多い自信はある
  - ファシリテーションは、対話や議論が促進されることを目指すと思っている
  - 多くの人は活発かつ適切に意見が交わすことが難しいため、活性化エネルギーが必要
  - 活性化エネルギーを下げる活動がファシリテーション
- ファシリテーションの最初は観察。反射するための何かを出して、観察のための動きを作る工夫をgaoryuさんはしている。
    - 自分が動くと観察できない
    - 完全に中にいては観察できない。完全に外から見ても観察できない。
- 誰かに声を掛けたらその人から上手く話が回ってくる、チームの思考が回ってくるようなのが理想。

# 上手く回っている場と上手く回っていない場の違いはなんだろう？
  - 上手く回っていない場では、関係性(人間と人間の関わり、ヒエラルキー)がよくない。個人が如何に自由に動けるかが違いでは？(gaoryuさん)
  - 上司と部下の関係性は絶対にあるから上司と部下がいる場なら上手く回らない？(kiroさん)
  - そんなことはない。個人が個人と向き合えるかができればよい気がする。上司と部下の話なら、上司と部下の以前の状態に戻せるようなイメージ(gaoryuさん)
  - でも上司と部下の関係は消えないはず。その場では以前の状態に戻せるようなイメージはないはじ(kiroさん)
  - 確かにそうかもしれない。言語化の限界がありそう。(gaoryuさん)
  - 結局、どんな場でも一番観察しなきゃいけないのは自分。何を観察しないといけないかはセルフモニタリング。自分の機嫌が良いかどうか。自分の機嫌が悪い時を観察できるようになればいい。皆の機嫌は？何をやられると怒る？に繋がる。(kiroさん)
  - めっちゃムカついているな俺、こいつ俺のコト怒らせるのどうやってるんだ？とかは考える(gaoryuさん)
  - 失敗するのは最高って言ってるけど、何は失敗したくないの？とか観察すると面白い(kiroさん)
  - 自分の感情の琴戦ギリギリを攻める研修を受けるという手もある。あまりやるべきでないけど。(gaoryuさん)

# バイアスの話
- 自分のバイアスは少ないと思っているバイアスがあるのが怖い
- 認知バイアスは消せないので、あることを理解しつつ相手に助けてもらえないといけない

# ファシリテーションをどう教えるか？
- ファシリテーションスキルがあることは悪くない。でも、ファシリテーションこうしましょうと教えることはない
- 機嫌が悪くなった相手とのやりとりすることが大事。怒らせることで実りある議論になる。
  - でも組織ががちでぶっこわれる時もあるので注意
- 機嫌が悪いって言えるようになれると良い関係性を築けている。
- 場を読まずに質問できるスキル、場を凍らせる質問をできるスキルは大事(新人にファシリテーションやらせる)
- 人間はどこまでいっても感情の生き物。論理を受け入れられることはあまりない。(勿論、論理で判断しないといけないことはあるけど)
- ファシリテーションは結局、とにかくチームをよく見ることに尽きるくらいに思っている。

# 機嫌と付き合う
- チームの機嫌を知るために、今日の気分はどう？とデイリースクラムで聞いてみる。
- PJは凄くネガティブな話をしないといけない場面が来る。そこで機嫌を良くしておかないとネガティブに耐えられない。ネガティブをポジションに言える場が必要。
- NPS(機嫌)上げるのは仕事としては大事だけど卑怯な手で簡単に上げられるので注意。研修のサマリで、今日良かったことを言語化させれば、NPS上げられる。後は昼においしいもの食べる。おやつにアイス食べるとか、いいコーヒーを飲むとか。
- チームに気軽に聞けない時は自分の機嫌がよくない。何を怖がっているのか分かる必要がある。役割を持てば怖くなくなることもある。
- 「～やったら恥ずかしい」は、最悪。判断基準を横に投げてる。

# gaoryuさんが印象的だった研修
- gaoryuさんは研修をして怒られた経験がある「こんなもの知りたくなかった」と言われた。でもそれって最高の研修だったんじゃない、とgaoryuさんは満足してる。

# gaoryuさんがファシリテーションを学ぶにあたって気を付けていること
- 理論を覚えれば覚えるほど使えなくなる感覚があるので、gaoryuさんは意図的に理論を勉強するのを抑えている。
- 答えを知らないことで素直な気持ちを出せる気がする。相手が欲しい答えをついつい探してしまう
- 外部規範に合わせない
- 自分が感じたことをそのまま口に出せるようにする練習が大事

# その他
- 失敗は痛いから普通は嫌だ。ただ、好きにやって面白くこけるのは楽しい。
- ファシリテーションに限らず、大事だと思わないと学べないし学べない。
- 好奇心が大切。楽しんで失敗する。楽しんで新しいことに取り掛かる。
- 自分たちが気付くからファシリテーションなんてやらなくていい。でも、ファシリテーターはその場にはいなきゃいけない。
- 他人を観察するなら若いやつを観察すると面白い。おじさんを観察しようとは思わない。
zoomのミュート切り替えボタンをM5 ATOM Liteでつくってみた




[M5StickCPlusでZoomのミュート&ビデオのON/OFFボタンを作る](https://qiita.com/Toshiki0324/items/d0ef77b266cbee57ec05)の記事をみて[M5 ATOM Lite](https://www.switch-science.com/catalog/6262/)を使ってMAC用にミュート切り替えボタンを作ってみました。
M5 ATOM Liteは、ボタンひとつとLEDぐらいしかありませんが、1000円でBluetoothとWifiがついたマイコンです。千石通商やマルツからも手に入ります。

なお、WinとMACはZOOMのショートカットのキーアサインが違います。(Win Alt + A, MAC Command + Shift + A)
まあ、MACはスペースでPush To Talkができるんですが...


# 環境構築

[M5Core Quick Start - Arduino Mac](https://docs.m5stack.com/#/en/quick_start/m5core/m5stack_core_get_started_Arduino_MacOS) に従って環境を構築します。
シリアルポートは、`tty.SLAB_USBtoUART`でなくて`/dev/tty.usbserial-xxxxxx`の形式でした。
`(2) Search M5Stack , find it and click Install`ではなくて、M5Atomを検索してください。

`Tools->Board->M5Stack-Core-ESP32`ではなくて、`Tools->Board->M5Stick-C`のほうがよいようです。(ほかだとビットレートを下げないと書き込みが失敗する)

## 追加ライブラリ

スケッチ-ライブラリをインクルード-ライブラリを管理から、`FastLED`で検索してインストールをしてください。

[ESP32-BLE-Keyboard](https://github.com/T-vK/ESP32-BLE-Keyboard/releases)より、最新版のESP32-BLE-Keyboard.zipをダウンロードして、スケッチ-ライブラリをインクルード-.ZIP形式のライブラリをインストールから、さきほど落としたzipファイルを指定してインストールします。

# ソースコード

IDEのソースが書いてあるところに以下をコピーペーストします。"AtomKeyboard"はMACから見えるBluetoothデバイスの名前になります。長すぎるとMACから見えませんので注意してください。
エディターの上部のレボタンで検証して、→ボタンで書き込みます。
書き込みでタイムアウトとかでる場合は、ATOM LiteとのUSB-Cを抜き差しします。

```c
#include <M5Atom.h>
#include <BleKeyboard.h>

BleKeyboard bleKeyboard("AtomKeyboard");
bool blestate = false;

void setup() {
  Serial.begin(115200);

  M5.begin(true, false, true);
  M5.dis.drawpix(0, 0x00f000); // init red

  Serial.println("Starting BLE work!");
  delay(20);
  bleKeyboard.begin();
  delay(20);

  M5.dis.drawpix(0, 0x001000); // dark red
}

void loop() {

  if (bleKeyboard.isConnected()) {
    if (!blestate) {
      blestate = true;
      Serial.println("BLE connect");
      M5.dis.drawpix(0, 0x001000);    // dark red
    }
    delay(100);
    if (M5.Btn.isPressed()) {
      Serial.println("Sending key...");
      M5.dis.drawpix(0, 0x0000f0);    // blue
      bleKeyboard.press(KEY_LEFT_SHIFT);
      bleKeyboard.press(KEY_LEFT_GUI);
      bleKeyboard.write('a');
      delay(100);
      bleKeyboard.release(KEY_LEFT_GUI);
      bleKeyboard.release(KEY_LEFT_SHIFT);
    }
     M5.dis.drawpix(0, 0x100000);    // dark green
  } else {
    if (blestate) {
      blestate = false;
      M5.dis.drawpix(0, 0x001000);    // dark red
    }
  }

  delay(100);
  M5.update();
}
```

おそらく以下のようにすればWINに対応したショートカットキーになるとおもいます(未確認)。

```
      // sending key
      bleKeyboard.press(KEY_LEFT_ALT);
      bleKeyboard.write('a');
      delay(100);
      bleKeyboard.release(KEY_LEFT_ALT);
```

# 動作確認

ツール-シリアルモニタで、`Starting BLE work!`とでているか確認します。
出ていなかったらATOM Liteのサイドボタンでリセットするか、USB-Cの抜き差しをします。

MACの設定からBluetooth設定を出して、AtomKeyboardと表示されているか確認をして接続します。

接続できるとシリアルモニタで、`BLE Connect`とでます。ATOM Liteのボタンを押すと、`Sending key...`と表示されます。
ここまでくれば動いているので、実際にzoomで試しましょう。
【RealSense】RGB画像でクリックした位置の取得

RealSenseのカメラ画像上でクリックした点に対応した３次情報を取得するプログラムです

```Python:GetClickPoint.py
# coding: utf-8
import pyrealsense2 as rs
import numpy as np
import cv2

def get_click_point(event,x,y,flags,param):
    global depth_frame

    if event == cv2.EVENT_LBUTTONDOWN:

        if x>=640:
            return

        depth = depth_frame.get_distance(x, y)
        point = np.array([x,y,depth])
        if depth==0 :
            print("ERROR: cannot get depth data ! ")
            return 

        x=point[0]
        y=point[1]
        z=point[2]

        x,y,z=rs.rs2_deproject_pixel_to_point(color_intrinsics, [x, y], z)

        print("point:",[x,y,z])

pipeline = rs.pipeline()
config = rs.config()
config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)
config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)

print("Start streaming")
pipeline.start(config)

cv2.namedWindow('RealsenseImage', cv2.WINDOW_AUTOSIZE)
cv2.setMouseCallback('RealsenseImage',get_click_point)

while cv2.waitKey(1)<0:

    frames = pipeline.wait_for_frames()
    depth_frame = frames.get_depth_frame()
    color_frame = frames.get_color_frame()

    color_intrinsics = color_frame.profile.as_video_stream_profile().intrinsics

    depth_image = np.asanyarray(depth_frame.get_data())
    color_image = np.asanyarray(color_frame.get_data())

    depth_colormap = cv2.applyColorMap(cv2.convertScaleAbs(depth_image, alpha=0.03), cv2.COLORMAP_JET)
    images = np.hstack((color_image, depth_colormap))

    cv2.imshow("RealsenseImage",images)

```

RealSenseのRGB画像を左クリックするとその3次元位置情報が出力されます

![Screenshot from 2021-02-11 23-47-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/0f5209cf-2723-4cbc-06d1-d4c3987ebefc.png)
sin波を作る

```sin.py

import wave
import numpy as np
from matplotlib import pylab as plt
import struct

a = 1     #振幅
fs = 44100 #サンプリング周波数
f0 = 440  #周波数(ラの音にあたります)
sec = 5   #秒
voice=[]

#サイン波を生成
for n in np.arange(fs * sec):
    s = a * np.sin(2.0 * np.pi * f0 * n / fs)
    voice.append(s)

#tは時間方向での離散値．voiceの長さをサンプルレートで切っているので，サンプル数分の配列になってます．
t = np.arange(0, len(voice))/fs

#サイン波を表示
plt.plot(t,voice)
plt.xlim([0,0.01])#範囲指定0秒〜0.01秒
plt.show()
```
実行は以下のコマンドで行います．

```
$ python sin.py
```
#出力結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101426/09295201-e0dc-369a-9527-5f518d28cb27.png)

440Hzは   １秒間に４４０回振動しているという意味なので，
       0.01秒間に4.4回振動しますね．

さて，周波数を変えるとどんな関数になるでしょう？

参考
https://qiita.com/MuAuan/items/ef4da6167d13cbf56e78
MacBig Sur環境でのXcode、CLTについて

環境 Mac BigSur

毎週末に参加させていただいている勉強会での出来事。
Visual Studio Codeで作業をしており、いつものように内容をGithubにコミットすると、

##エラーが発生し動かない!

以前にも同じ問題が発生し苦戦したために理由はすぐに予想ついたが、XcodeとCLTのバージョンが異なっているためにバグが起こっているよう。そこで思い出したのだが、数日前にXcodeをアップデートしてしまっていた。

##CLTとは?

CLTとはCommand Line Toolsの略で、キーボードで命令や操作をするプログラムのことである。本来ならXcodeのバージョンと紐付けされていて、XcodeのアップデートをするとCLTのバージョンも上がる。

```
$ brew --config
```

にてバージョンを確認すると、やはりXcodeとCLTのバージョンが異なっている。。

##参考にしたリンク

・[MacをBig SurにするとHomebrewでCTLについてのWarningが出ることへの対処法](https://code-graffiti.com/big-sur-and-homebrew-warning/#toc2)
・[Downloads for Apple Developers](https://developer.apple.com/downloads/index.action)

1つ目のリンクは以前この問題が起きた際に知人に送ってもらったリンクなのだが、ここに全て書いてある。

Downloads for Apple DevelopersのサイトでXcodeと同じバージョンのCLTをダウンロード、インストールでVisual Studio Codeを再起動。コミットできるようになり問題解決!

## 最後に

Xcodeのアップデートは30分近くかかり今回の作業が毎回必要になるため、次回のアップデート実行はSwiftに手を出す時ですかね。。
CarrierWaveで表示する画像のサイズを考えた時のノート

## これは何？
画像を扱うアプリを練習で作っていました。そのときに、以前からしっかり調べたいと思っていた、解像度と画像の関係について調べたノートです。

[![Image from Gyazo](https://i.gyazo.com/87f5e07f58d29a4969e3109d9562bd94.gif)](https://gyazo.com/87f5e07f58d29a4969e3109d9562bd94)

実際に実装する際の足掛かりとしてまとめているだけなので、コードはほとんど書いていません。参考記事をまとめたノートにとどまっています。

## PCよりスマホの方が画像を大きく作成しないといけない理由

- **フルHD（1920 x 1080px）**...　一般的なオフィスで使われているPCの画像サイズ。13インチのノートPCだと、これより解像度が小さいこともある。

- **4K（3840 x 2160px）**... フルHDの四倍の解像度。同じ画面サイズでもフルHDの四倍の密度でピクセルが密集している状態

参考記事：[4Kテレビは2Kや8K、ハイビジョンやフルハイビジョンとどこが違うの？](https://corporate.wowow.co.jp/features/henai/2518.html)

`iPhone`は6plus（2014年発売）の時点で、すでにフルHDに対応していて、`Retina`ディスプレイというディスプレイを採用してからは、同じサイズのディスプレイでも二倍の解像度で画像が表示されるようになっています。

`iPhone`ではなくても、４Kやそれ相応に高解像度のスマホは珍しくありません。

参考記事：
[スマホ時代に最適な画像のサイズや新常識](https://bindup.jp/camp/design/graphic/14927)


## 等倍サイズの画像は、高解像度のディスプレイだとぼやける

例えば、100 x 100pxの画像をブラウザで表示するときは

```
size: '100x100'
```
を指定して、**画像サイズと同じサイズ**でブラウザで表示させるのが通常ですが、`iPhone`のような高解像度ディスプレイのスマホでは、これらの画像はぼやけて見えます。

## 対策

対策は至って単純で、**画像を200 x 200px**と二倍サイズで作成し、

```
size: '100x100'
```

で表示することです。
しかし、それだと通常の解像度を利用しているディスプレイで、不必要にページが重くなることは否めません。

そのため、

```
<img src="img/photo01.jpg" srcset="img/photo01.jpg 1x,img/photo02.jpg 2x" alt="sample photo">
```

このように`srcset`属性で表示する画像をディスプレイの解像度ごとに変える書き方もあります。
ここでは、コードの意味する内容なのど詳しい解説は、参考にしたこちらの記事に譲りたいと思います。

[Retinaディスプレイでブログやウェブサイトの画像をぼやけさせない方法](https://tcd-theme.com/2019/04/retina-display.html)

## CarrierWaveでの画像表示の最適解？

[![Image from Gyazo](https://i.gyazo.com/ea19172eaad82500069427875afd57ae.png)](https://gyazo.com/ea19172eaad82500069427875afd57ae)

ところで、`CarrierWave`にはいくつか画像リサイズのオプションがあります。使用頻度が高そうなものとしては、`resize_to_fit`と`resize_to_fill`でしょうか。

今回作っていたアプリでは、画面上では**400 x 400px**で表示させるという仕様になっていたので、実際で表示することを考えるならは**800 x 800px**で画像を作成した上で、画面上では**400 x 400px**で表示するのが良さそうです。

さらに言えば、`srcset`属性で表示する画像を出し分けるのが良さそうでした。
今回は練習用のアプリなので、これ以上の実装はしませんでしたが、

Railsで`srcset`属性を使い画像を出し分ける処理を書いていた人もいたので、実際に同様のアプリを作ることがあるなら、こちらを参照したいと思います。

[image_tagでsrcset属性を使いたいときのTips（carrierwave）](https://qiita.com/yuuuking/items/e398e07d6b66529a9d68)

### 追記：単純に２倍なら良い、というものでもないらしい
その後、「単純に２倍じゃないんだよー」というご指摘とともに、以下のリンクをいただいたので、忘れない様に貼り付けておきます。

[「えーと、画像は全部2倍で作ればOKなんだよね？」を卒業しよう](http://un-tech.jp/display-resolution/)
JavaでSQLのConnectionを書くときにはまったこと

# 起きたこと
Java7から採用されたtry-with-resources文を使用してSQLのストアド呼び出しをしようとしたときにエラーが発生した。

## 環境

### OS

Windows 10

### JavaVersion
jdk-15.0.2

### JDBC
sqljdbc_9.2

### SQL Server
2019

## エラーになったコード

```java:sqlcall.java
public Connection calltest() {
		String connectionUrl = "jdbc:sqlserver://localhost:1433;"
				+"databaseName=TESTDB;"
				+"user=TestUser;"
				+"password=*******;"

		try (Connection connection= DriverManager.getConnection(connectionUrl)){
			return connection;
		}catch (SQLException e) {
			e.printStackTrace();
		}
		return null;

	}

```

```java:別class

		sqlcall call = new sqlcall();
		con = call.calltest();
		cs = con.prepareCall("{call dbo.sp_TESTA(?,?)}");


```

### エラーメッセージ

` com.microsoft.sqlserver.jdbc.SQLServerException: 接続は閉じられています。
  at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:234)
  at com.microsoft.sqlserver.jdbc.SQLServerConnection.checkClosed(SQLServerConnection.java:1217) 
  at com.microsoft.sqlserver.jdbc.SQLServerConnection.prepareCall(SQLServerConnection.java:3808) 
  at com.microsoft.sqlserver.jdbc.SQLServerConnection.prepareCall(SQLServerConnection.java:3416) `



# 原因
公式に以下のように記載されていました。

>次の例ではtry-with-resources文を使用して、java.sql.Statementオブジェクトを自動的に閉じます。

```java:引用

public static void viewTable(Connection con) throws SQLException {

    String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES";

    try (Statement stmt = con.createStatement()) {

      ResultSet rs = stmt.executeQuery(query);

      while (rs.next()) {
        String coffeeName = rs.getString("COF_NAME");
        int supplierID = rs.getInt("SUP_ID");
        float price = rs.getFloat("PRICE");
        int sales = rs.getInt("SALES");
        int total = rs.getInt("TOTAL");
        System.out.println(coffeeName + ", " + supplierID + ", " + price +
                           ", " + sales + ", " + total);
      }

    } catch (SQLException e) {
      JDBCTutorialUtilities.printSQLException(e);
    }
  }

```

try-with-resources文のメリットである自動でclose処理を行ってくれるという部分を知らずに
Connectionタイムアウトを疑って接続周りについて調査に時間を取られました。


# まとめ
Connection処理を各classで呼び出す際にはとても便利ですが、共通処理として使おうとしたときは
少し考えないといけないかもしれません。
今回はtry-with-resources文を使用しないようにして回避しました。


# 参考文献

[try-with-resources文](https://docs.oracle.com/javase/jp/8/docs/technotes/guides/language/try-with-resources.html)
そうだ、SQLを勉強しよう⑦

#はじめに
SQLでも関数が使えることを知りました。当たり前なのかもしれませんが、Rubyを学んでいたことをなぞっている感覚になります。Rubyでは、メソッドと呼んでいた学習内容です。
やはり、ここでも引数をどう与えるかが、大事なようです。
関数は使用するDBMSによって、記述が異なるようです。
##関数

###文字列の長さを取得したい
```sql
LENGTH(文字列を表す列名)
-- =>文字列の長さを表す数値
```
###余計な空白を除去したい
```sql
TRIM(文字列を表す列)
-- =>左右から空白を除去した文字列

--左側の空白を除去したい場合は…
LTRIM(文字列を表す列)

--右側の空白を除去したい場合は…
RTRIM(文字列を表す列)
```
頭のLRはleftとrightです。

###文字列の一部を置換したい
```sql
REPLACE(置換したい文字列, 置換する前の文字列, 置換後の文字列)
```
引数の内容と順番が重要です。

###文字列を連結したい

```sql
CONCAT(文字列, 文字列)
```
関数を使わずに、`||`でも同様の処理が可能です。

##まとめ

|関数名|役割|
|---|---|
|LENGTH|文字列の長さを数値で表す|
|TRIM|左右から空白を除去した文字列|
|REPLACE|文字列を置換する|
|CONCAT|文字列を結合する|


TRIMは、トリミングってことですね。
Tensorflow Object Detection API でモデルの評価

###手順

・検証データはpipeline.configのeval_input_readerに記述しておきます。

```:pipeline.config

eval_input_reader {
  label_map_path: "/content/drive/My Drive/signate/label_map.pbtxt"
  shuffle: false
  num_epochs: 1
  tf_record_input_reader {
    input_path: "data/eval.tfrecords"
  }
}
```

・トレーニングと同じ「model_main_tf2.py」をチェックポイントディレクトリ（トレーニングで生成されたもの）に追加して、実行。
＊GPUありでの実行のみサポートしています。

```python

python object_detection/model_main_tf2.py \
   --pipeline_config_path="my_model_dir/pipeline.config" \
   --model_dir="/content/drive/My Drive/signate/checkpoint" \
   --checkpoint_dir="/content/drive/My Drive/signate/checkpoint" 
```

###出力

こういうのがプリントされます。

 >Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.011
 Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.037
 Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.002
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.000
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.007
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.016
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.022
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.076
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.128
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.000
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.070
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.168

IoUの意味についてはこちら：
[【IOU】 Object Detection の性能指標【I/U】](https://qiita.com/john-rocky/items/eacf17648cfb778d8eff)

 >precision:正解と予測したもののうち、実際正解だったものの割合
recall：実際の正解のうち、正解と予測できたものの割合

チェックポイントディレクトリに検証イベントファイルが生成され、Tensorboardで使用できます。
トレーニング後でも評価できますし、トレーニング中に別のターミナルでトレーニング・チェックポイントにアクセスして実行すると、
トレーニングによって新しいチェックポイントが生成されるのを待って、最新のチェックポイントで同時評価していくことができます。

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)