OmniAICreator/Qiita-1.07M huggingface dataset:
メモ：ImageJ FijiでPythonを動作させるとjava.lang.IllegalArgumentExceptionが出る件とその解決(mac OS)

# はじめに
生命科学系を中心に，画像解析に用いられるオープンソースソフトウェア「[ImageJ Fiji](https://imagej.net/Fiji)」をmac OSにインストールし，Pythonで動作テストをさせた際，初っ端からJavaのエラーメッセージが表示され出鼻をくじかれてしまいました．
その解決について，ネット上に書かれたエントリが見つからなかったため，自戒と，もしかしたら誰かの役に立つかもと思いメモしておきます．

# 動作環境
- MacBook Pro Late2016
- mac OS Catalina 10.15.6
- Python 3.8.2

# エラーの概要
Fijiであらかじめ作成しておいたPythonのファイルを開き，動かすと…
![th_スクリーンショット 2020-10-10 20.41.54 21.05.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490117/ed907b8d-4249-fdbf-0e3a-183f0e5b5732.png)
Javaのエラーメッセージが出現します．
![th_スクリーンショット 2020-10-10 20.42.02 21.05.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490117/8de3dcc9-2413-98b3-dd39-7e61fae2037d.png)
エラーは以下のようなことが書かれており…

```
java.lang.IllegalArgumentException: Cannot create PyString with non-byte value
```

調べたところ，PyStringの引数に全角文字が含まれているときに出るエラーとのことでした．

# 解決方法（多分）
**動作させるPythonファイルのファイルパスに全角文字が含まれている**のが問題だったようです．
動作ファイルが含まれるフォルダ名をアルファベットに変更すると解決しました．簡単！

色々試してみたところ，今回のエラーに関係するのは
- 対象のファイル名
- 対象のファイルパスに含まれるすべてのフォルダ名
だと思われます．

画像ファイルは，Fijiで開きアクティブにしておけば全角文字を含んだファイルパスでも問題ないですが，パスをPython側で指定して開く場合，同様に全角文字が含まれないパスにする必要がありそうです．

念の為，ホームディレクトリの.localizedファイルを削除したりもしてみましたが，動作には関係ありませんでした．


# 感想
こんな簡単なところで躓くとは…どおりで誰も何も書いていないわけだよ！
Windows10 エクスプローラの右クリックのメニューに独自の項目を追加したい時

# エクスプローラの右クリックのメニューに独自の項目を増やしたい

Windows10 エクスプローラの右クリックのメニューに独自の項目を増やしたい場合は、

**[1]**「ファイル」に対する右クリックのメニューは、「HKEY_CLASSES_ROOT\\*\shell」にキーを新規追加、または、

「フォルダ」に対する右クリックのメニューは、「HKEY_CLASSES_ROOT\Folder\shell」にキーを新規追加して、

**[2]**「(既定)」の値に、任意の表示文字列を設定、例えば「test appを開く」など。

**[3]**メニュー横にアイコンを付けるなら、ここに「Icon」名の文字列値を追加して、アイコンの場所を指定、例えば「C:\Windows\System32\shell32.dll,23」など。

**[4]**この配下に「command」名のキーを追加、「(既定)」の値に、起動したいプログラムの場所を設定、例えば「D:\サンプル場所\test app (スペース有り)\test_app.exe "%1"」など。

* ※パスにスペースがある場合でも「""」は不要、一方で、スペースを含むパスの対策として%1には「""」が必要。
* ※パスに指定できる「%1」などの文字列(プレースホルダー)の詳細は、以下を参照。https://www.pg-fl.jp/program/winreg/classes.htm

ここでレジストリに追加した項目をまとめると、以下:

```
[HKEY_CLASSES_ROOT\Folder\shell\test_app]
@="test appを開く"
"Icon"="C:\\Windows\\System32\\shell32.dll,23"

[HKEY_CLASSES_ROOT\Folder\shell\test_app\command]
@="D:\\サンプル場所\\test app (スペース有り)\\test_app.exe \"%1\""
```

項目追加後の、レジストリエディタの様子、下図:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606924/d1636a22-c997-38ea-3607-9251c963628a.png)

すると、フォルダを右クリックした時のメニューには、下図のように「test appを開く」が追加されます。クリックすると、設定した「test_app.exe」が起動されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606924/5c1bdfbf-8554-8857-a073-e01dfa269f1e.png)

参考:
http://suyamasoft.blue.coocan.jp/Bat/CMD/ContextMenu/index.html
難読化されたメソッド名を特定する

Androidアプリを難読化して動かすと、例外が発生することがあります。
スタックトレースを見ても難読化により、どのメソッドで例外が発生したのかわかりません。
そんなとき、例外発生したメソッドを特定する方法です。

# 難読化
Androidでは、セキュリティやサイズ縮小を目的に以下の設定を行うことがあります。

```groovy:build.gradle
minifyEnabled true
shrinkResources true
```

この設定で動かしてみると、例外が発生することがあります。

# 難読化で例外発生して困ること

以下の実装があるとします。

```java:Calc.java
package com.example.myapplication;

public class Calc {
    public int divide(int param1, int param2) {
        return param1 / param2;
    }
}
```

```java:MainActivity.java
package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Calc calc = new Calc();
        int result = calc.divide(10, 0);
        System.out.println(result);
    }
}
```

これを実行すると、ゼロ除算で例外が発生します。

```:スタックトレース
Caused by: java.lang.ArithmeticException: divide by zero
    at b.a.a.a.a(:5)
    at com.example.myapplication.MainActivity.onCreate(:13)
    at android.app.Activity.performCreate(Activity.java:7009)
    at android.app.Activity.performCreate(Activity.java:7000)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
```

難読化により、例外発生したメソッド名が<code>b.a.a.a.a</code>となり、どこで例外発生したかわかりません。

# 難読化された文字列からメソッドを特定する

難読化前後のマッピングを見れるファイルがあります。
Androidのプロジェクトフォルダに移動し、検索欄で「mapping」と検索してみてください。
検索結果に「mapping.txt」が表示されます。このファイルを開きます。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224267/4463ec7e-6411-b2fd-e48e-3913b47dd41a.png)

例外発生したメソッド名<code>b.a.a.a.a</code>は、パッケージ名.クラス名.メソッド名で表現されています。
パッケージ名とクラス名（<code>b.a.a.a</code>）でmapping.txtを検索します。以下該当箇所がヒットします。

```:mapping.txt
com.example.myapplication.Calc -> b.a.a.a:
    3:3:void <init>() -> <init>
    5:5:int divide(int,int) -> a
```

マッピングを見ると、例外発生したメソッド名（<code>a</code>）が<code>divide</code>であることがわかります。
駆け出しエンジニアがSESを3年やった話

約3年半程前、未経験でIT業界に来てからのことをお話しようと思います

#そもそもSESって？
システムエンジニアリングサービスの略です
僕が未経験で入った会社は派遣会社だったので厳密に言えばSESと呼ばないかもしれませんが、ここではまとめてSESと呼んでしまいますｗ

#契約形態について
ひとえに人材会社と言っても、契約の結び方は複数あります
まずはこれについて簡単に見ていきましょう

###請負契約
請負契約では成果物が重要になります
成果物を納品できない場合は契約違反となってしまうため、かなりシビアです
しかし、その契約は会社間(人材会社<-->顧客会社)での契約のため、労働者としてはある意味関係ない契約です(労働者<-->人材会社間は時給や月給などの雇用契約を結んでいます)
しかし、プロジェクトがうまく行っていないと人材会社が労働者に違法な残業を強要したりすることがあるので、仕組みが整っていない会社でやってしまうととんでもないことになります

###準委任契約
一般的にSESと言えばこの準委任契約を指すことが多いようです
準委任契約では成果物の有無は関係ありません
もし仮に成果物を提供できなかったとしても契約違反にはなりません
準委任契約は特別な契約の結び方をしない限り瑕疵(かし)を問われることはないようです
準委任契約はひと月の労働時間で契約を結ぶこともあれば、そうでないこともあるようです
請負契約よりもシビアな感じではないので気軽に(?)契約できる、というのがメリットかもしれません

###派遣契約
派遣契約では派遣法があるため、労働者が守られる仕組みがある程度しっかりできています
派遣契約の場合、人材会社が顧客会社からいくら貰っているのかを知ることができます(というか人材会社は労働者へ契約条件を開示する必要があります)
このように会社間での契約が準委任契約なのか、派遣契約なのかでは結構違ってきます
ただし、派遣業を行うには資本金が2000万円以上あること、厚生労働省の許可を得ることなど、ハードルが結構高いです
労働者としては派遣契約のほうが良いですが、人材会社としてはできれば派遣契約以外で済ませたい…という思いがあるようです

#入社～上流工程の仕事に就くまで
僕が最初に入った会社では未経験を大量に雇い、ちょっと研修をした上で現場に派遣する…という戦略を取っていました
事業の拡大を狙った戦略らしく、毎月数十人採用していたっぽいです
この研修でCCNAを取得するとこまでいけました

ただ、研修が終わった後2ヶ月程待機期間があったのが微妙な感じでした
当時は実家暮らしだったので家で遊んでいるだけでよかったですが、もし一人暮らしとかしてたらかなりやばかったと思います

その後ネットワークに関する仕事をやっていたのですが、プロジェクトが終了するということで契約終了へ…
年明けからはまた別の研修を受けることになりました

その研修では資格こそ取らなかったものの、Linux、ESXi、NSX、NetAppなど、幅広い勉強をすることができました
今思うとこの研修を受けていなかったら絶望的な人生を歩んでいたかもしれませんｗ

この研修が終わった直後、ネットワークの設計、構築の仕事をすることになります
これこそが人材会社がやりたかったこと(低スキル・低単価から、高スキル・高単価)への第一歩だったみたいです

ここからはトントン拍子でした
1年はネットワークの設計、構築をやった後に次はサーバー、ストレージの設計、構築の仕事を約1年
その後は、もっとレイヤーの高い仕事がやりたかったため、別の会社へ転職し、アプリケーション開発の世界へ…
ここで、俗に言うSESの闇を垣間見ることになります

#5次受け上等！準委任契約一筋の会社へ
個人的には給料が貰えれば何次受けでも関係ねーじゃんってスタンスでした
ただ、極限の下請け会社と、ある程度大きい派遣会社では全く考えが違う、ということがわかりました
まず、極限の下請け会社にはお金がなく、今日を暮らすのが精一杯で、契約を少しでも逃したら会社がまずい、というような状態でした
そのような場所では、契約先である顧客会社の言うことは絶対。ただし、顧客会社も極限の下請けなのでビジネス上有利である立場を利用して好き放題言ってきます

僕はそういうごたごたを聞きたくないから人材会社を選んだのに、結果的には手間が増えてしまいました(フリーランスになったほうがよほど良かった、と当時は思いましたｗ)
更に、そのような会社には良い人材がいません
この会社の状況を変える人、技術スキルが高い人、営業スキルが高い人、、、とにかくお金を稼げる人がいません
お金が無く、お金を稼げる人もいないのにお金を稼ごうとするとひずみが起こり、崩壊していきます

開発未経験で前職より高い給料で採用してくれたことには感謝していますが、すぐに転職活動を始めたため結局その給料は半年分くらいしか貰えませんでしたｗ

しかもこの会社では準委任契約であったため、自分がいくらで契約しているのかどころか契約条件を知ることすらできませんでした
そうすると現場で何かを頼まれても、契約条件を知らないのですぐに返事をすることができません(というか準委任契約の場合業務指示は自社から出るはずなんだけど…)
明らかに誰にとっても得になってないですよね…

このように準委任契約はお手軽な分、会社の仕組みがしっかりしていないと成立しません

人材会社はこれを認識していないととんでもないことになります
たちが悪いことに、人材会社は人間を現場に送っていれば利益は出るので中々倒産しないんですよねｗ(財務状況は見せられたものではない可能性もありますがｗ)
だから今でもそういう会社が残っているのだと思います


#そして現在…
今は自社開発の会社に勤めています
まだ入社したばかりなのでどのような会社なのかはいまいち分かっていませんが…ｗ

#まとめ
契約方法としてあえて準委任契約を選ぶ会社には何か理由がありますので注意しましょう
未経験であれば派遣業の会社を選択することをおすすめします
未経験で自社開発の会社に行こうとしているのであればその会社の規模、扱っている技術、技術力の高さ(その会社の人がイベントに登壇しているかどうか)などをしっかり見極めたほうが良いです
自社という小さいコミュニティ内で技術力の有る無しを語ってもあまり意味がないからです

ちなみに、仕事の勉強を家でし始めたのはここ1年くらいの話です
勉強をする前に、まずはしっかり休むこと。勉強はしたくなったらすれば良いです
やりたくないことをやるのが一番毒ですから！
【tips】vuetifyでmdiが使えない場合の対処法

# 概要
vuetifyでハンバーガメニューに変更するとどうも3本線(ハンバーガーが表示されなかった。)


# 解決法

```sh
// これだけではダメ
import Vuetify from 'vuetify'

// これを追記する
import "vuetify/dist/vuetify.min.css"
```

通常のimportに加えて、下記のものをimportすることで解決する。
あまり解決策が見つからなかず時間を使ってしまったので、原因等は調査不足ですが同じく困っている人の助けになれたら幸いです。
AtCoder 生活　95日目

[前回](https://qiita.com/flandrescarlet237/items/4fc3d6ef3eee976be380)

#95日目
HHKB プログラミングコンテスト 2020に参加しました。

![スクリーンショット 2020-10-10 22.41.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606053/00476d57-c336-c42a-55d9-2124d88784b3.png)

##[HHKB プログラミングコンテスト 2020](https://atcoder.jp/contests/hhkb2020)

###A

```c++

#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0;i < (n);i++)
using namespace std;
using ll = long long;
using pii = pair<int,int>;

const int INF = 2e9;

int main(){
    char s,t;
    cin >> s >> t;
    char a = t-32;
    if(s == 'Y')cout << a << endl;
    else cout << t << endl;
}

```

###B

```c++

#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0;i < (n);i++)
using namespace std;
using ll = long long;
using pii = pair<int,int>;

const int INF = 2e9;

int main(){
    int h,w;
    cin >> h >> w;
    vector<string> s(h);
    rep(i,h)cin >> s[i];
    ll ans = 0;
    rep(i,h){
        rep(j,w){
            if(s[i][j] == '#')continue;
            else{
                if(i+1 != h){
                    if(s[i+1][j] == '.')ans++;
                }
                if(j+1 == w){
                    if(s[i][j+1] == '.')ans++;
                }
            }
        }
    }
    cout << ans << endl;
}

```

###C

```c++

#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0;i < (n);i++)
using namespace std;
using ll = long long;
using pii = pair<int,int>;

const int INF = 2e9;

int main(){
    int n;
  	cin >> n;
    vector<bool> flag(n+1);
    int num = 0;
    rep(i,n){
        int a;
        cin >> a;
        flag[a] = true;
        while(true){
            if(flag[num] == false){
                cout << num << endl;
                break;
            }
          	else num++;
        }
    }
}

```


###最後に
D問題が全然わからなかった。
久しぶりの更新。
最近学校やらバイトやらスクールで時間をうまく取れなくて疎かになってきてしまった。
最近なかなか解けなくなってきてしまったので、もっとうまく時間をとって励んでいきたい！
Webサービスをアプリ化しない理由

Webサービスをアプリ化しない理由について


かれこれ10年近くWebサービスを個人開発してきていまして、Webサービスって、そこそこ利用されはじめると、悩みますよね。アプリ化について。

そろそろアプリ化したほうがいいんじゃない？と。うちもいよいよじゃない…と。

そんな感じで考えることも多かったのですが、昨今のアプリ業界の動向、WebサービスのSEO（集客施策）においては、「安易なアプリ化」はプラスよりもマイナスが多いよね。と、結局なりまして。

せっかくなので、なぜそう考えるに至ったのかを共有してみます。


##誰向けの記事なのか
対象となるのはこのような人達を想定しています


+ Webサービスを運営していている人
+ アプリ化は必須だと思っている人


#安易にアプリ化しないほうがいい理由について
WebサービスのSEO、アプリ業界の動向の2つの視点から説明したいと思います。



#WebサービスのSEOへの悪影響


インターネットでサービスを提供する以上、どのように集客するのかを無視することはできません。

ソーシャル経由だけでもビジネスは展開できますが、よりスケールさせたい場合、検索エンジン（Google）への施策は必須になります。潜在顧客の開拓とか。

いわゆるSEOなんですが、業界的に嫌われているイメージもありますけれど、（わたしが言いたいのはGoogleをハックする的な小手先の技術ではなく、もっと全体の最適化のはなしです。）このSEOはアプリ化と相性が悪いんですよね。

Googleがなにを評価しているのかは非公表ですが、サイト内でのユーザーの行動、被リンクやソーシャルシグナルなども重要な指標であると専門家にも分析されています。わたしも実感として同じように感じます。

ところが、Webサービスをアプリ化することで、Googleはアプリ内での行動を把握できなくなりますし、今まで評価されていた重要な情報がGoogleに伝わらなくなる可能性もでてきます。


いろいろ考えている時期に、SEOの専門家がピンポイントの記事を書いてくれて、モヤモヤしていた部分が腑に落ちました。
https://webtan.impress.co.jp/e/2020/08/25/36969


昨今のGoogleは、もはや技術者じゃないときちらんと対応できないところも多いのですが、そもそもGoogleがどうやって情報を得ているのか、Googleができないことはなんなのか？などWebサービス運用者にとって最低限知っておかなければいけないことも増えてきています。


あらたな集客チャネルとしてアプリ化を進めたのにもかかわらず、検索エンジンの評価が下がって集客力を失っては、そもそもなんのための施策なのかわからなくなります。

わたしが運営している[名付けポン](https://pon-navi.net/nazuke/)というWebサービスでは、多い時期で月間700万PVほどが検索エンジンからあったため、SEOへの懸念は無視できませんでした。

**SEOの悪影響があるかも？、というのが1つめの理由**です。







#アプリ業界の動向

アプリの開発者ではないため詳しくはないのですが、アプリ利用率とプラットフォームの台頭について、ちょっと気になっています。



##昨今のアプリ利用率について
ユーザーのアプリ利用の実態をまとめた「[App Ape モバイルマーケット白書 2019](https://ja.appa.pe/reports/whitepaper-mobilemarket-2019/)」によると、日本のスマホユーザーが所持するスマホアプリは約82個、利用するアプリ数は25個というデータが発表されています。

3分の2のアプリは使われていないということです。
https://lab.appa.pe/2019-08/app-ape-mobile-market-white-paper.html



利用されているアプリは約30%ですが、このなかにはLINE、Instagram、Twitterなどそうそうたるサービスが一定枠をおさえている状況を考えると、自社のサービスがこれらに加われるのかを冷静に評価する必要があります。




##スーパーアプリとミニアプリの台頭

アプリ市場の最先端を走る中国では、2016年後半から、スーパーアプリという新しいアプリプラットフォームが誕生しています。

スーパーアプリとは、すでに大ヒットしているアプリがプラットフォームとなり、外部のアプリを提供する仕組みです。

わかりやすくいえば、LINEの1機能としてアプリを開発ができ、LINEの機能として提供することができます。この場合LINEがスーパーアプリ、LINE用に開発されたのがミニアプリ（ミニプログラム）となります。

（[LINEミニアプリ](https://www.linebiz.com/jp/service/line-mini-app/)はすでに提供がはじまっています。）



メリットは、すでにLINEを利用していれば、インストール不要ですし、開発したアプリを使ってもらいやすく、逆に削除されにくくなります。


WeChatがスーパアプリのはしりと言われていますが、そのWeChatの利用経路は約70%以上がミニアプリ経由によるものという調査データもあり、スーパーアプリ導入のメリットは認知されています。

（[こちらが詳しいです。](https://saichat.jp/line/mini-app/)）


WeCha以外にも、アリババ、百度、バイトダンス（TikTok）もスーパーアプリを導入していますので、日本のアプリ市場への影響もあるでしょう。


どのプラットフォームで開発するべきなのか？も、今後考えなくてはならない状況になりそうだということですね。

単純な興味もありますけれど、プラットフォームとの相性など考えることも増えますね。

既存プラットフォームであるAppleやGoogleもこのまま黙ってはいないと思いますがどうなるんでしょうか。



ということで、**アプリで戦えるのか？というのが2つめです。**



#アプリでしかできないことがあるのか？

SEOとアプリ市場の動向でつらつら書いてきましたが、**一番重要なのは、アプリでしか実現できないことがあるのかどうか**だと思っています。

「Webがメイン」で「アプリはおまけ程度」なら工数含めてマイナスが多いかなと。

アプリでしか提供できないものがあり、それが**「ユーザーにとって価値（なくてはならない機能）になるのかどうか」だけで判断**すると、すんなり納得できるというか、なんとなく客観的にみれたりしました。

それでもなおアプリ化必須だとなれば踏み切るタイミングなのかなと。
aws初学者がCIDR表記を調べてみて

##概要
自分は、aws初学者ですが、以下調べていくと知見が深まりました。
調べれば分かる事なので、答えは書いてませんので、悪しからず。
（他 調べるべきキーワードのご指摘があると幸いです:yum:）

##CIDR
CIDR(Classless Inter-Domain Routing)
別名: classless addressing

①IPアドレスとは？
②プライベートIPアドレス、グローバルIPアドレス
③（IPv4）のクラスAクラスBクラスC
④ネットワーク部、ホスト部
⑤なぜ、Classless
⑥プレフィックス
⑦サブネットマスク
⑧CIDR表記とサブネットマスク表記

〜おまけ〜
[香川県、ネット・ゲーム規制条例のパブコメを地元メディアに全件公開　記載IPアドレスに疑問の声も]
(https://www.itmedia.co.jp/news/articles/2004/14/news077.html)
Mixed Content（混在コンテンツ）エラーの解決方法


railsでアプリケーションを開発。本番環境(heroku)にデプロイしたがなんか見た目が違う...となりました。
解決はしましたが、新しい発見があったため記録として残しておきます！
# 問題発生の経緯
デプロイをしたがビューが崩れている
↓
アセットファイルをコンパイルしてない！
↓
```rails assets:precompile RAILS_ENV=production```を実行
↓
再度デプロイ。「これで大丈夫なはず！」
↓
直ってませんでした......。

# 原因
結論から言うとコンパイルの問題ではなく外部ページがHTTPのページだったことが原因でした。(コンソールにちゃんと```This request has been blocked; the content must be served over HTTPS.```と書かれていましたが確認しておらず反省です。)
httpsで読み込まれているのに対して、httpのものを読み込もうとするとエラーになるとは知らず新しい発見でした！

# 解決策
httpsであれば問題ないとのことだったのでhttpで読み込まれていたパスをhttpsに変えてみたが対応していませんでした...
今回はリセットCSSを外部から読み込んで使おうと思っていたため、外部から読み込むのではなくreset.cssとしてファイルを作成することで解決しました。

## 参考記事
https://qiita.com/Kouch/items/5089fb36694c6e467a3a
https://www.transnet.ne.jp/2016/02/28/rails%e5%88%9d%e5%ad%a6%e8%80%85%e3%81%8c%e3%81%a4%e3%81%be%e3%81%9a%e3%81%8dcolnr%e3%80%8c%e3%82%a2%e3%82%bb%e3%83%83%e3%83%88%e3%83%91%e3%82%a4%e3%83%97%e3%83%a9%e3%82%a4%e3%83%b3/
Rails datetime型からdate型のマイグレーションの書き方

**「このカラム`datetime`じゃなくて`date`でよさそう」**

日付をあつかうから`datetime`にしてたけど、よくよく考えてみると「時間」は必要ないよねーとなったとき、`date`に変換したくなりますよね。

# 今回のゴール

- Bookモデルは発売日`released_at(datetime)`をもっている
- マイグレーションをして`released_on(date)`にしたい


# 環境

- Rails 6.0.3
- psql (PostgreSQL) 12.4


# changeをつかったdatetime→dateの変換

```ruby
def change
  rename_column :books, :released_at, :released_on
  change_column :books, :released_on, 'date USING CAST(released_on AS date)'
end
```

# `db:rollback`できますか？

これでよしよし、`git commi..`、**と、ちょっとまってください！**

マイグレーションは巻き戻る（rollback）ことを考慮しておきましょう。

前述のマイグレーションをrollbackできるかを確かめてみましょう。

```console
$ rails db:rollback

== ..... : reverting ========
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:


This migration uses change_column, which is not automatically reversible.
To make the migration reversible you can either:
1. Define #up and #down methods in place of the #change method.
2. Use the #reversible method to define reversible behavior.
```

## なにがエラーになったのか

- `change_column`でロールバックしたとき、以前の型情報がわからないから元に戻せないから

`'date USING CAST(released_on AS date)'`で型を変換できたものの、**「変換前の型の情報」**が抜け落ちてしまったため、ロールバックに失敗してしまいました。

これを解決するためのひとつの方法として**up/downをつかった方法**に書きかえてみましょう。

# up/downをつかった方法

```ruby
def up
  rename_column :books, :published_at, :release_on
  change_column :books, :release_on, 'date USING CAST(release_on AS date)'
end

def down
  rename_column :books, :release_on, :published_at
  change_column :books, :published_at, 'timestamp USING CAST(published_at AS timestamp)'
end
```

こうすることによって、

- `db:migrate`では`up`の`datetime -> date`が実行される
- `db:rollback`では`down`の`date -> datetime`が実行される


# おまけ：PostgreSQLで`datetime USING CAST`はエラーになる


```ruby
change_column :books, :released_at, 'datetime USING CAST(released_at AS datetime)'
```

```console
PG::UndefinedObject: ERROR:  type "datetime" does not exist
LINE 1: ...released_at" TYPE datetime USING CAST(published_at AS datetime)
```

Rails世界の`datetime`は、PostgreSQL世界では`timestamp`になるという話でした :sweat_smile:
VSCodeでコメントアウトするためのショートカットキー

## 結論。「Ctrl + /」でOK

コメントアウトしたい範囲を選択し、「Ctrl + /」とする。
既にコメントアウト済みの箇所を元に戻す場合も同様に「Ctrl + /」でOK。

ちなみに選択領域にコメントアウト行と非コメントアウト行が混在する場合は「全行コメントアウト」され、既にコメントアウトされている行にもさらにコメントアウトのシンボル（例えばPythonだったら#）が追加される。

## 所感

今までVSCode上でのコメントアウトは「Ctrl+K,Ctrl+C」、外すのは「Ctrl+K,Ctrl+U」でないと出来ないと思っていたので、まさか「Ctrl + /」というもっと簡単にできるショートカットキーがあるとは想像しておらず、知ったときには驚いた。
[Linux便利コマンド] deltaを入れてみる

## 環境

![](https://img.shields.io/badge/centos-7.7.1908-<COLOR>)

## 概要

diffをしたいと思ったときにデフォルトのものだと色もつかないし表示が見にくかった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219776/51448575-8d20-e8dc-7c76-b59bb7b60d16.png)

調べたところcolordiffなるものがあることが分かりました。
https://qiita.com/trapple/items/6657b903bf027464e70d

これだけでもよさそうでしたが、deltaというrust製のものを使用すればさらに見やすくできそうだったのでこちらを検討してみました。
https://wonderwall.hatenablog.com/entry/rust-delta

## deltaインストール

```shell
cargo install git-delta
```

## deltaの設定

```shell:.gitconfig
[core]
  pager = delta
[interactive]
  diffFilter = delta --color-only
```

これにてgit diffをした際にdeltaが反映されるようになりました

設定を諸々調整

```shell:.gitconfig
[delta]
  diff-so-fancy=true
  keep-plus-minus-markers=true
  minus-emph-style="bold 94 89"
  plus-emph-style="bold 29 29"
  hunk-header-style="omit"
  line-numbers=true
```

## 結果

#### git diffの見た目

before
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219776/598a1289-3a2e-b54f-3e68-66af6795f9b2.png)

after
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219776/b1447a58-2dd8-5aaf-d057-2530fcc15b5c.png)

### 通常のdiffの見た目

gitではない場合のdiffもdeltaコマンドで置き換えることができるためこれで見やすくなりました

before
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219776/feae16c3-6492-0a52-14ec-be5d8d0445dd.png)

after
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219776/e28452cb-c5b3-d250-7b6d-00088b777586.png)
Laravel

# routesの設定
ここではRouteファサードのgetというメソッドに、2つの引数を渡しています。
Route::getの第一引数には、URLを文字列で渡します。
第二引数には、どのコントローラーで何のメソッドを実行するのかを文字列で渡します
![スクリーンショット 2020-10-10 13.40.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663122/0b6cd4df-c233-3180-2618-ae8c2844866f.png)
# controller作成
$ docker-compose exec workspace php artisan make:controller ○○Controller
でdocker利用したコントローラーが作成できます。
ちなみに、
Laravelでコントローラーのひな形を作成するためのコマンドそのものはphp artisan make:controller コントローラー名となります。
laravelを旧バージョンでインストール

既存プロジェクトではなく
新規プロジェクト作成に関して

```
composer create-project laravel/laravel:^7.24 [プロジェクト名]
```

#参考
- [Laravelのバージョンの指定方法](https://senooken.jp/post/2020/04/10/)
VagrantでOracleLinux(7.x)にDockerをセットアップする



# 目的

VagrantでOracleLinux(7.x)を立ち上げて、ついでにDockerのインストールと起動までやりたい。
(ホストはWindows10 HomeEdition。Vagrant、VirtualBoxはセットアップ済み)



# Vagrant Boxの情報を調べる

以下のサイトで確認。Oracle Linux Vagrant boxのURLを確認。

Oracle Linux Vagrant boxes
https://yum.oracle.com/boxes/

今回はOracle Linux 7.x想定なので
https://oracle.github.io/vagrant-projects/boxes/oraclelinux/7.json
を使用する。

# Oracle Linux へのDockerのインストール情報を調べる

Oracle Linux DockerではDocker-docs-jaに翻訳があるが、1.13.RCであり、現在はYumリポジトリの設定が異なりこの部分は参考にならない。
https://docs.docker.jp/engine/installation/linux/oracle.html

Dockerマニュアル(英語)のインストールマニュアルをみるとLinuxのディストリビューションの章からOracleLinuxがなくなっている。
https://docs.docker.com/engine/install/


以下blogにOracleLinuxのOracle yum repositoryの設定について言及がある。

A Simple Guide to docker installation on Oracle Linux 7.5 [Updated Oct 2019]
https://blogs.oracle.com/blogbypuneeth/a-simple-guide-to-docker-installation-on-oracle-linux-75


2020/10時点では、上記Boxで取得したOracleLinuxのyum repositoryの設定として「ol7_latest」「ol7_addons」がデフォルトで有効であり、特に追加で設定変更は不要であった。上記blogにある「ol7_UEKR4」は無効のままでも問題なかった。


# Vagrantfile

 Vagrantfileの例

```ruby
Vagrant.configure("2") do |config|
  config.vm.box = "oraclelinux/7"
  config.vm.box_url = "https://oracle.github.io/vagrant-projects/boxes/oraclelinux/7.json"
  config.vm.network :forwarded_port, id: "ssh", guest: 22, host: 2210
  config.vm.provider "virtualbox" do |vb|
   vb.memory = "8196"
  end
  config.vm.provision "shell", inline: <<-SHELL
i=1; while [ $i -le 10 ]; do echo $i;yum -y --disablerepo=* --enablerepo=ol7_addons,ol7_latest  install docker-engine;if [ $? -eq 0 ];then break;fi;i=$(expr $i + 1);done
systemctl start docker.service
systemctl enable docker.service
SHELL
end
````

ちょっと説明。

* ```config.vm.network :forwarded_port, id: "ssh", guest: 22, host: 2210```
    * SSHポートフォワーディングを22→2210で設定。ホストのlocahostに2210ポートでssh接続。
* ```vb.memory = "8196"``` 
    * 割り当てメモリを8GBに。お好みで。
*  ```i=1; while [ $i -le 10 ]; do echo $i;yum -y --disablerepo=* --enablerepo=ol7_addons,ol7_latest  install docker-engine;if [ $? -eq 0 ];then break;fi;i=$(expr $i + 1);done```
    * 「yum -y docker-engine」 だけでよいはず。ここでは、yumのupdateに時間がかかるので必要なレポジトリのみに絞る。また一度ではなぜか成功せず何度かやると成功することがあったので、成功するまで（リトライ上限10回）繰り返しとした。
*  ```systemctl start docker.service```　　
* ```systemctl enable docker.service```
    * Dockerサービスの起動と自動起動の有効化

# Vagrant 起動

```
> vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'oraclelinux/7'...
<中略>

> vagrant ssh

Welcome to Oracle Linux Server release 7.8 (GNU/Linux 4.14.35-2025.400.8.el7uek.x86_64)

The Oracle Linux End-User License Agreement can be viewed here:

  * /usr/share/eula/eula.en_US

For additional packages, updates, documentation and community help, see:

  * https://yum.oracle.com/

[vagrant@localhost ~]$ sudo su -
[root@localhost ~]# docker version
Client: Docker Engine - Community
 Version:           19.03.11-ol
 API version:       1.40
 Go version:        go1.14.7
 Git commit:        78418d7
 Built:             Tue Aug 18 22:46:21 2020
 OS/Arch:           linux/amd64
 Experimental:      false
<以下略>

```
Ruby Leet文字列に変換

# はじめに
こちらは学習メモです。

# Leetとは？
たとえば、「Warez」という語を leet で表記すると、「W@rez」や「W4r3z」などとなるように、一部のアルファベットを形の似た数字や記号などに変化させること。

今回は、Rubyで以下のように変換します。

##### アルファベット⇄記号変換表

|アルファベット| 記号|
|:------:|:------|
|A |６|
|B| ８|
|C|５|
|D |３|
|E |１|

入力された文字列に対してLeetで文字を変換する。その後、文字列を出力する。

# コード

```
word = gets.chomp.split('')
word.each do |w|
  case w
  when 'A'
    print '6'
  when 'B'
    print '8'
  when 'C'
    print '5'
  when 'D'
    print '3'
  when 'E'
    print '1'
  else
    print w
  end
end
```
入力例

```
ABKTED
```

[実行結果]

```
68KT13
```

# 解説

```
word = gets.chomp.split('')
```
・1行目では入力された文字を一文字ずつ区切って配列にし、word変数に代入
　　getsメソッド：　入力を一行ごとに「文字列」で受け取る。
　　chompメソッド：　文字列の改行を取り除く。
   　　splitメソッド：　文字列を分解して配列にする。

```
word.each do |w|
```

・word変数の要素をw変数に代入する
　2行目以降はcaseによって一致判定・文字の入れ替えを一文字ずつ行っています。
ubuntu20.04/debian10+apacheでgitサーバ(smart http)

何か下書き一覧に「3 month ago」とか書かれていた(笑)
せっかく書いたのだから放置しておくのもなんですし、もう20.10も出る頃ですので、その前に公開しておきましょう。

* [FreeBSD12.1+apacheでgitサーバ(smart http)](https://qiita.com/katsuko0303/items/3d6fa7d422caf5367b95)

前回(？)の続きです。

まぁ、自分が使うのは主にFreeBSDか、ubuntuかdebianなんで、この際ubuntu/debianでも試してみようかと。

## 環境

* VirtualBox on ubuntu20.04
* ubuntu server 20.04

前回と同様、インストールしてネットワークが接続てきているところまで設定し終わっている事を前提とします。

## 設定

```
sudo apt install apache2 git
```

なんかgitは最初から入っていたようなのだけど、気の所為かもしれないので念の為。

ubuntuの場合、「`/etc/apache2/sites-available`」ディレクトリ以下にホストの設定を書くのが流儀みたいなので、デフォルトの設定をコピーして設定します。

```
sudo cp -v /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/000-myhost.conf
```

コピーした後、編集。

```
<VirtualHost *:80>  

    # もともと書かれてあったものは、そのまま。

    SetEnv GIT_PROJECT_ROOT /var/www/git
    SetEnv GIT_HTTP_EXPORT_ALL
    ScriptAlias /git /usr/lib/git-core/git-http-backend
    <Location /git>  
        AuthName "Git Repository"
        AuthType Basic
        AuthUserFile /etc/apache2/git.passwd
        Require valid-user
    </Location>
</VirtualHost>
```

パスワードファイルを作成します。

```
sudo htpasswd -c /etc/apache2/git.passwd katsuko
```

CGIモジュールと、先のホスト設定ファイルを有効にします。
(デフォルト設定のホストファイルを無効にします)

```
sudo a2enmod cgi
sudo a2dissite 000-default
sudo a2ensite 000-myhost
```

レポジトリの作成。

```
sudo mkdir -p /var/www/git
sudo git init --bare --shared /var/www/git/project.git
cd /var/www/git/project.git
sudo git update-server-info 
sudo chown -R www-data:www-data .
```

サーバの再起動。

```
sudo systemctl restart apache2
```

------------
## Debian 10 (Buster)の場合

**上と一緒。**

いや手抜きじゃなくて。
まぁ、debianの場合rootで作業するので、その場合は「`sudo`」は要らない、という点ぐらいは察してください。
【Ruby】ハッシュテーブルの順番を逆にしたい

#はじめに
たとえば、`reputation = {very_bad: '最悪', bad: '悪い', good: '良い', very_good: '最高'}`みたいなハッシュテーブルがあったとして、その順番を`{very_good: '最高', good: '良い', bad: '悪い', very_bad: '最悪'}`のように後ろから並べたい。

#やり方
```
pry(main)> reputation.to_a.reverse.to_h 

 #=> {very_good: '最高', good: '良い', bad: '悪い', very_bad: '最悪'}
```

これだけです。

一応説明すると、`reverse`っていう配列の順番を逆にするメソッドを使いたいんだけど`reputation`はhashなので使えない。なので一度`to_a`でhashを配列に変換して`reverse`した後、そのままだと配列のままなので`to_h`で元の戻す、ということです。


#あとがき
「gemの`enum_help`を使ってラジオボタンの表示は日本語表記に、内部ではint型で処理したい。評価が低い方から数字も低い方を割り当てたい、しかしラジオボタンの表示は評価が高い方から表示したい。」という場面で必要でした。
普通enum使うときってvalueが数字になるはずだから並べ替えやすいんですが、enum_help使うと上に書いたようなhashを渡すことになるので「どうやって並べ替えるんだ…」ってなりました。

記事にすることもないような気がしますが、僕のような初心者だと`to_s`や`to_i`は使っても、`to_a`とかは使う機会が少なくて詰まることがあると思うので少しでも誰かの役に立てば。
Laravelのファイル、フォルダの役割ついて

【概要】
----------------------------------------
<b>1.Laravelのファイル</b>

<b>2.Laravelのフォルダ</b>




1.Laravelのファイル
----------------------------------------
備忘録として残しておきます！
.editorconfig:エディタに関する設定ファイルです
.env:動作環境に関する設定ファイルです
.gitignore:Gitに関するファイルです
.artisan:php artisan serve(localhost:8000)等のコマンドです
.styleci.yml:コードチェッカーのファイルです
.composer.json:composerを利用関係です
.package.json:Javascriptのパッケージ管理ツールであるnpm利用関係です
phpunit.xml:テストプログラム関係です
server.php:サーバー起動時のプログラム関係です
webpack.mix.js:Javascriptのパッケージツールで使用
yarn.lock:yarnのパッケージマネージャが使うアプリが入っています
<br>
2.Laravelのフォルダ
----------------------------------------
app:アプリケーションのプログラムがまとめられています。アプリケーションを作成する際はここにscrpitファイルを作ります。User.php（ユーザー認証設定),Http(アプリケーションにアクセスした際に処理をし、Controllerファイルがあります。）
bootsrap:アプリケーションを起動する際に一番最初に処理が行われます。
config:設定関連ファイルです
database:データベース関連ファイルです
public:JavascriptやCSSなどブラウザで検証ツールで見れる部分になります
resources:リーソスファイルであり、テンプレートファイル等があります
routes:ルーティング設定はここになります。web.phpがrubyでいうroutes.rbファイルにあたります。このフォルダの中身には、api.php.channels.php、console.phpがあります
storage:ログファイルが保存されます
tests:単体テスト
vendor:フレームワーク（ここではLaravel）のプログラムが入っています。
<br>
MacでUSBのフォーマットの色々



[Mac のディスクユーティリティで利用できるファイル・システム・フォーマット - Apple サポート](https://support.apple.com/ja-jp/guide/disk-utility/dsku19ed921c/mac)

[MacのディスクユーティリティでWindowsコンピュータ用にディスクをフォーマットする - Apple サポート](https://support.apple.com/ja-jp/guide/disk-utility/dskutl1010/mac)

[Mac のディスクユーティリティで利用できるパーティション方式 - Apple サポート](https://support.apple.com/ja-jp/guide/disk-utility/dsku1c614201/19.0/mac/10.15)

## フォーマット

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62413/992fb759-4751-4bdc-ec2d-26940cfd6cd4.png)


WindowsやUbuntuで利用する場合は、MS-DOS(FAT)かExFAT

### Apple File System（APFS）：
- macOS 10.13 以降で使用されているファイルシステム。

### Mac OS 拡張：
- macOS 10.12 以前で使用されているファイルシステム。

### MS-DOS（FAT）および ExFAT：
- Windows との互換性があるファイルシステム。

Windows で使用するディスクをフォーマットする場合は、以下の Windows 互換ファイル・システム・フォーマットのいずれかを選択します。

- MS-DOS（FAT）： `32 GB 以下`の Windows ボリュームに使用します。

- exFAT： `32 GB を超える` Windows ボリュームに使用します。

**つまり、USBのサイズによりフォーマット形式も選択する必要ある。**

MS-DOS(FAT)かexFATの二択である。

## パーティション`方式`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62413/07c3aee1-e95e-fedd-7e24-64b181a53600.png)

- GUID パーティションマップ：
    - すべての Intel プロセッサ搭載 Mac コンピュータには、このオプションを選択します。

- **マスター・ブート・レコード**：
    - MS-DOS（FAT）または exFAT としてフォーマットされる Windows パーティションには、このオプションを選択します。

- Apple パーティションマップ：
    - `古い PowerPC プロセッサ搭載` Mac との互換性を保つには、このオプションを選択します。

**`マスターブートレコード`を使っておけばよい。**

## おまけ

コマンドラインでやるならこれ　

ディスク名: `disk1s1` = diskNsM
N: デバイス識別子
M: パーティション番号

```Bash

# device確認
$ diskutil list

/dev/disk0 (internal):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                         251.0 GB   disk0
   1:                        EFI EFI                     314.6 MB   disk0s1
   2:                 Apple_APFS Container disk1         250.7 GB   disk0s2

/dev/disk1 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      APFS Container Scheme -                      +250.7 GB   disk1
                                 Physical Store disk0s2
   1:                APFS Volume Macintosh HD            191.0 GB   disk1s1
   2:                APFS Volume Preboot                 46.6 MB    disk1s2
   3:                APFS Volume Recovery                510.4 MB   disk1s3
   4:                APFS Volume VM                      3.2 GB     disk1s4

/dev/disk2 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *7.7 GB     disk2
   1:                 DOS_FAT_32 WINDOWS USB             7.7 GB     disk2s1
   2:                 DOS_FAT_32 UEFI_NTFS               524.3 KB   disk2s2

# ディスクの消去. デバイス識別子を指定
$ diskutil eraseDisk MS-DOS UNTITLED /dev/disk2

```

[MacOSX上でISOファイルからインストールUSBディスクを作る - re:inventing the wheel](https://blog.eksy.tokyo/post/create-bootable-usb-from-iso-file/)

```Bash
# 焼き込み
$ sudo dd if=Win10_2004_Japanese_x64.iso of=/dev/rdisk2 bs=1m

* ~は使えない。フルパスか相対パスで書く。
```


## まとめ

毎回忘れるのでメモ。

- 32GB以下の場合: MS-DOS(FAT)
- 32GB以上のUSBの場合: exFAT

- 方式は常に：マスターブートレコード

以上
YouTubeの配信枠バグでホロライブの配信が取得できず困っている件(未解決)

## 概要
今日20時の下記配信が検索クエリに登場しなかったし、しない。

[【#姫森ルーナ誕生祭】３Ｄライブでみんなと一緒に誕生日をお祝いなのら！【姫森ルーナ/ホロライブ】](https://www.youtube.com/watch?v=kAWOhajaCNo)

YouTubeサイトの上部検索欄からの検索でも該当配信が出てこないので、配信枠バグであることは間違いなさそうなのだが、それに伴ってなのかAPIの検索結果内に登場しない。
最近同時接続数(videosのliveStreamingDetails.concurrentViewers)の取得を始めたので結構困る。


## 詳細
[サイト](https://holo.lisvir.jp/)用に下記検索クエリを実行し結果を収集しているのだが、対象配信が登場しない。

```
https://www.googleapis.com/youtube/v3/search?key={APIキー}&maxResults=50&part=snippet&eventType=live&type=video&q=%E3%83%9B%E3%83%AD%E3%83%A9%E3%82%A4%E3%83%96%7Chololive
```

同時間帯に配信していたホロスターズの配信は当然取得できたのと、今までもこれで大丈夫(ホロジュールの配信中と一致)していた、が今回はダメだった。
念のために以下のワード(qパラメータ)で取得を試みたが、いずれも対象配信を含まない結果となった。

q=Luna Ch. 姫森ルーナ
q=姫森ルーナ
q=UCa9Y57gfeY0Zro_noHRVrnw

eventType=liveを含まないリクエストの場合、該当チャンネルの既に配信完了した配信・動画を含んでいるので、チャンネルIDをqに指定するのは対象チャンネルの情情報を取得するのは間違ってなさそう。

```
https://www.googleapis.com/youtube/v3/search?key={APIキー}&maxResults=50&part=snippet&type=video&q=UCa9Y57gfeY0Zro_noHRVrnw
```

## その他分かってること
配信が開始する前に実行したchannelIdを指定した取得だといたっぽい。
が、今実行するといない。どういうことなのか。

```
https://www.googleapis.com/youtube/v3/search?key={APIキー}&maxResults=3&part=snippet&order=date&channelId=UCa9Y57gfeY0Zro_noHRVrnw
```

## とりあえず
YouTube Data APIのサポートに問い合わせようにも、Stack Overflowに書けと案内されている。
やってみるか。。。

何かが返ってきたら後日談を書くかも。書かないかも。
【メモ】BeautifulSoup4の使い方(3) class_で記事の見出しを表示

前回はfind_allを使って見出しを表示したが、今回はclass_を使って見出しを表示する。また、Yahoo！Japanをスクレイピングすることにした。

In[1]BeautifulSoupとRequestsをimportする

```:In[1]
from bs4 import BeautifulSoup
import requests
```

In[2]RequestsでYahoo！Japanのurlを取得し、テキストを表示する

```:In[2]
toget_url =requests.get("https://www.yahoo.co.jp/")
toget_url.text
```
In[3]BeautifulSoupとhtml.parserで解析

```:In[3]
soup = BeautifulSoup(toget_url.text,"html.parser")
```
ここまでは変数とurlを変えたこと以外は前回と同じだ。

In[4]class_=をもとにfind_allで検索

```:In[4]
heading =soup.find_all(class_="TRuzXRRZHRqbqgLUCCco9")
```
デベロッパーツールでYahoo！Japanの見出しを調べたところ"TRuzXRRZHRqbqgLUCCco9"が見出しで使われていることがわかった。class_で検索するときは_（アンダーバー）を忘れないようにする。

In[5]for文で回して内容を表示

```:In[5]
for heading_name in heading:
    print(heading_name)
```

これで見出しが表示できた。
kintone-rest-api-clientでゲストスペースを動的に判定してみる

# はじめに
kintone-rest-api-clientはとても便利ですが、kintone.api.url()を使うような感覚で、
動的にゲストスペースかどうかの判定が今の所できません。
自社用のカスタマイズであれば問題ないですが、配布を目的としたプラグインなどの場合に少々問題があります・・・。
なので動的に判定できるようにしてみます。

# 実装
早速実装していきます。
今回はレコード一括取得を例に進めていきます。

```Javascript
    function getAllRecords(){
        return new Promise(async (resolve, reject)=>{
            const guestSpaceId = await checkGuestSpace().catch(err=>{showErrorMsg(err)})
            const prop = guestSpaceId ? {guestSpaceId} : {};
            let client = new KintoneRestAPIClient(prop)

            const params = {
              app: kintone.app.getId(),
              query: kintone.app.getQueryCondition()
            };

            client.record.getAllRecordsWithCursor(params).then(function(resp) {
              console.log(resp);
              resolve(resp)
            }).catch(function(err) {
              console.log(err);
              reject(err)
            });
        })
    }

    async function checkGuestSpace(){
        const currentUrl = kintone.api.url('/k/v1/app', true);
        if(currentUrl.indexOf('guest') > -1){
            const appId = kintone.app.getId();
            const guestSpaceId = await getGuestSpaceId(appId)
            return guestSpaceId;
        } else {
            return false;
        }
    }

    async function getGuestSpaceId(appId){
        const appInfo = await getAppInfo(appId)
        const guestSpaceId = appInfo.spaceId
        return guestSpaceId;
    }

    function getAppInfo(appId){
        return new Promise ((resolve, reject)=>{
            const body = {
              'id': appId
            };
            kintone.api(kintone.api.url('/k/v1/app', true), 'GET', body, function(resp) {
              resolve(resp)
            }, function(error) {
              reject(error)
            });
        })
    }
```

## ゲストスペースかどうかを判定する
kintone.api.url()を使って、適当なAPIを叩いてURLを取します。
「guest」が含まれているかどうかを判定基準としています。

```Javascript
const currentUrl = kintone.api.url('/k/v1/app', true);
if(currentUrl.indexOf('guest') > -1){
```
ゲストスペースであった場合は、ゲストスペースIDを取得します
（kintone-rest-api-clientでは、ゲストスペースで使用する場合ゲストスペースIDを指定する必要があります）
アプリ情報取得APIでアプリ情報を取得し、ゲストスペースIDを取り出します。

ゲストスペースIDが取得できたらguestSpaceIdプロパティを設定、なければ何もしないといった感じです。

```Javascript
const prop = guestSpaceId ? {guestSpaceId} : {};
```

# 最後に
とりあえずぱぱっと書きましたが、レコード一括取得以外でも使えるように工夫が必要ですね。
コードの書き方などご指摘大歓迎ですm(_ _)m
MacでWindows10 ブートUSBの作り方




## コマンドラインでやるならこれ　

### 1. デバイス名の確認

ディスク名: `disk1s1` = diskNsM
N: デバイス識別子
M: パーティション番号

```Bash

# device確認
$ diskutil list

/dev/disk0 (internal):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                         251.0 GB   disk0
   1:                        EFI EFI                     314.6 MB   disk0s1
   2:                 Apple_APFS Container disk1         250.7 GB   disk0s2

/dev/disk1 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      APFS Container Scheme -                      +250.7 GB   disk1
                                 Physical Store disk0s2
   1:                APFS Volume Macintosh HD            191.0 GB   disk1s1
   2:                APFS Volume Preboot                 46.6 MB    disk1s2
   3:                APFS Volume Recovery                510.4 MB   disk1s3
   4:                APFS Volume VM                      3.2 GB     disk1s4

/dev/disk2 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *7.7 GB     disk2
   1:                 DOS_FAT_32 WINDOWS USB             7.7 GB     disk2s1
   2:                 DOS_FAT_32 UEFI_NTFS               524.3 KB   disk2s2

```

## 2. フォーマット

```
# ディスクの消去. デバイス識別子を指定
$ diskutil eraseDisk MS-DOS UNTITLED /dev/disk2
```


## 3. 焼き込み
[MacOSX上でISOファイルからインストールUSBディスクを作る - re:inventing the wheel](https://blog.eksy.tokyo/post/create-bootable-usb-from-iso-file/)

```Bash
# 焼き込み
$ sudo dd if=Win10_2004_Japanese_x64.iso of=/dev/rdisk2 bs=1m

* ~は使えない。フルパスか相対パスで書く。
* disk2ではなくrdisk2の方が高速 (らしい
```

## おまけ. boot tools

- on Mac
    - [UNetbootin - Homepage and Downloads](https://unetbootin.github.io/)
    - [balenaEtcher のダウンロードと使い方 - ｋ本的に無料ソフト・フリーソフト](https://www.gigafree.net/system/os/Etcher.html)
- [Rufus - The Official Website (Download, New Releases)](https://rufus.ie/)
特定の既存ブランチに切り替える

# コマンド
```terminal
$ git branch | grep 'ブランチ名' | xargs -I{} git checkout {}
```

- `git branch`
    - Gitブランチ表示

- `| grep 'ブランチ名'`
    - 特定のブランチ名で検索

- `| xargs -I{} git checkout {}`
    - 取得ブランチでそのまま切り替える
Reactの開発環境をDockerで作る。イメージの作成→コンテナ起動→DockerHubにpush

#動機
React/Reduxの開発環境をDockerで作成した際の備忘録。

#環境
>macOS Catalina 10.15.5
>Docker version 19.03.13
>docker-compose version 1.27.4

#Dockerfile

```Dockerfile
From node:latest
WORKDIR /usr/src/app
RUN npm install -g create-react-app
```

#docker-compose

```yml:docker-compose.yml
version: '3'
services:
 node:
  build:
   context: .
   dockerfile: Dockerfile
  tty: true
  environment:
   - NODE_ENV=production
  volumes:
   - ./:/usr/src/app
  command: sh -c "cd project_name && yarn start"
  ports:
   - "3000:3000"
```

|項目 |意味 |
|---|---|
|version|docker-composeのversion|
|services|構築サービス|
|build|Dockerfileのディレクトリとファイルを指定|
|tty|コンテナを起動し続けるかを決定|
|environment|環境変数を設定|
|volumes|ローカルのディレクトリが接続(マウント）する作業ディレクトリを指定|
|command|コンテナないで実行するコマンド|
|ports|外部に対して公開するポート|

###NODE_ENV
動作環境を設定する
本番環境:production
開発環境:development

###command


#イメージのbuild
```
docker-compose build
```

#アプリケーションの作成
```
docker-compose run --rm node sh -c "create-react-app project_name"
```
```docker-compose run```で先ほど作成したイメージを起動し、sample-projectでアプリケーションを作っていきます。runはコンテナを一度だけ起動する。

Redux、Expressライブラリのインストールします。

```
npm install redux --save
npm install react-redux --save
npm install express --save
```

インストール確認

```
npm list --depth=0
```

#コンテナの起動
```
docker-compose up -d
```
バックグラウンドで起動。

#コンテナの停止

```
docker-compose down
```
オプションに-vをつけると、Compose ファイルの `volumes` セクションの名前付きボリュームを削除する。

#Command
###動いているコンテナの確認
```
docker-compose ps
```

###コンテナの削除
```
docker rm <コンテナID>
```

###イメージの削除
```
docker rmi <イメージID>
```

#Docker hubへpush

###docker imageにタグづけする

```
docker tag <baseのimage名> <DockerhubID>/<image名>:タグ名
```

###Dockerhubへのログイン

```
docker login
```

###docker hubにpush

```
docker push <DockerhubID>/<image名>:タグ名
```

これでDockerhubのレポジトリに<DockerhubID>/<image名>が追加される。


#自動ビルド設定
GitHubと連携する手順を示す。事前にGitHubにレポジトリを用意する必要がある。

Dockerhubから対象のrepositoryを選択 → 「Builds」 → 「Link to GitHub」
![スクリーンショット 2020-10-11 9.39.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148800/97bc9cb5-24c8-0245-5fdd-ec16c2a9b5ab.png)

連携するRepositoryを選択
![スクリーンショット 2020-10-11 9.41.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148800/56ddb516-ceef-fd4a-6915-b5c40b18b9dc.png)

Repositoryを選択すると下の選択画面が開く。AUTESTをOffにすると自動ビルドされないので、それ以外を選択。REPOSITORY LINKSはお好きに。BUILD　RULESは自動ビルドの詳細設定。デフォルトでよければこれで。
作成当初はSave and Buildがいいっぽい。
![スクリーンショット 2020-10-11 9.47.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148800/223eb2bb-4296-efe7-5fde-aaadee17ce62.png)

これでGitHubにpushされると、DockerHubは自動ビルドになる。
Git developブランチにマージされたlocalブランチを削除する

# コマンド
```terminal
$ git branch -r --merged develop | grep "ブランチ名" | cut -d "/" -f2- | xargs -t -I{} git push --delete origin {}
```

- `git branch -r --merged develop`
    - developブランチにマージされたリモートブランチ表示

- `| grep "ブランチ名"`
    - 特定のブランチ名で検索

- `| cut -d "/" -f2-`
    - 最初に出現するスラッシュまでの文字列を除外

- `| xargs -t -I{} git push --delete origin {}`
    - 洗い出したブランチを削除する
Ruby 四則演算

# はいじめに
学習用のメモになります

# 四則演算とは？
四則演算とは、足し算・引き算・掛け算・割り算のことをいいます。 ワークシート上やマクロの中でも四則演算は使われています。 四則演算は下記のような記号を使って計算式を作ります。

# 四則演算

基本的な四則演算を行うための演算子は次の通りです。

|演算子| 内容|例|
|:------:|:------|:------|
|*| 乗算 |5 * 3
|/|除算|8 / 2
|+| 加算|3 + 6
|-| 減算|5 - 2

また四則演算以外にも次の演算子が用意されています。

|演算子| 内容|例|
|:------:|:------|:------|
|%| 剰余 |5 ％ 3
|**|べき乗|5 ** 2

剰余は演算子の左辺を右辺で割った余りです。「5 % 3」の剰余は「2」となります。
べき乗は演算子の左辺を右辺の値で累乗した値です。「5 ** 2」は「25」となります。
ホットリンク保護の仕組み

# 概要
直リンク（ホットリンク）を制御し、外部へのデータ転送を抑制し、サーバーに大きな負担が掛からないようにします。
お客様のサイト上でファイルへのアクセスができるサイト名(ドメイン名)を指定することができます。

Tencent Cloud VODでは、動画の再生許可を制御するためにホットリンク保護を提供しています。ホットリンク保護が有効になった後、Tencent Cloud CDNノードは再生要求に含まれるキー情報をチェックし、承認された要求にのみ動画データを返す。このスキームはプレーヤーに特別な要件はなく、VODのプレーヤーSDKと一般的なプレーヤーの両方に適用できます。

# 種類と機能

VOD ホットリンクプロテクションは、参照元とキーに基づいてホットリンクを防止することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633185/20fb8c23-b585-790d-e30e-7a17e3081ab8.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633185/7c3a6725-2002-163f-74a7-6d630f562e92.png)

# 参照元ホットリンク保護

HTTP に基づくリファラー機構は、再生リクエストヘッダのリファラーフィールドを通してリクエストソースを識別します。指定したドメイン名をブロックリストまたは許可リストに追加することができ、それに基づいてCDNノードが認証を行い、再生リクエストを許可または拒否します。

# キーホットリンク保護

これにより、動画の再生制御パラメータを QueryString の形式で動画の URL にスプライシングすることができます。CDN ノードは、URL に含まれる再生制御パラメータを確認し、それに応じて動画の再生を制御します。現在、キーホットリンクプロテクションでは、「有効期限」「視聴者数」「動画再生時間」を、対応するパラメータ（「有効期限」「再生許可IP数」「プレビュー時間」）で制御することができます。

- 有効期間制御

動画URLの有効期限を指定します。要求された動画URLの有効期限が切れている場合は、動画を再生することができません。このように、動画URLに有効期限を設定することで、悪意のあるユーザーが他のWebサイトにURLを転送して長期利用することを防ぐことができます。

- 視聴者数制御

これは、動画のURLにアクセスできる視聴者の数を指定します。同じプライベートネットワーク内にないデバイスは、一般的にパブリックIPが異なります。URL での再生を許可する IP の数を制限することで、URL にアクセスできる視聴者の数を指定することができます。これにより、悪意のあるユーザーがURLを他のWebサイトに転送して無制限に配信することを防ぐことができます。

- 動画再生時間の制御

これは、有料ではないユーザーのためにプレビューを実装するために、動画 URL 内のプレビュー期間 (例: 動画の最初の 5 分間) を指定します。
Ubuntu 20.04デスクトップでChrome日本語入力不可時の対処例

Ubuntu20.04デスクトップでChrome日本語入力ができない/できなくなった場合について、いくつか実証実験的な切り分けができたので共有します。

##今北三行
+ [New!]**もしiBusとfcitxの両方を導入しており、各々別の入力切替方法にしているなら、その切替キーバインドのトグル(例、[Ctrl]+[Space]→[右Alt]→[Ctrl]+[Space])を試す**
+ [Google Chrome等で検索して導かれた先](https://www.google.com/intl/ja_jp/chrome/)にあるもの、すなわち**deb版をdeb -iして導入**
+ **snap版すなわちapt版はだめ**

##本記事の前提(こだわり)
+ **lxdeを使用**している。**他のデスクトップ環境は未検証**
+ USキーボードを使用している
+ 他のデスクトップ・アプリケーションでは日本語入力ができている
+ chrome / chromium **だけ**できない
+ **.cacheをtmpfsに移したときに著しく**おかしい

##確認を行った環境
```
$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="20.04.1 LTS (Focal Fossa)"
(略)
PRETTY_NAME="Ubuntu 20.04.1 LTS"
(略)

$ fcitx --version
fcitx version: 4.2.9.7

$ ibus version
IBus 1.5.22

$ mozc --version
Command 'mozc' not found, did you mean:
(略)

$ ばーじょんMozc-2.23.2815.102+24.2.oss
```
mozcのバージョンは「ばーじょん」と打って変換する際の変換候補に出ます

##要点
+ snap版すなわちapt版は(筆者環境では)対処療法が発見できなかった。**削除した**
+ その際の.cacheフォルダは~/snap/chromium/common/.cacheである。**削除した**
+ [Google Chrome等で検索して導かれた先](https://www.google.com/intl/ja_jp/chrome/)にあるもの、すなわち**deb版をdeb -iして導入した**
+ その場合のデフォルトの.cacheフォルダは~/.cache/google-chromeである。現在これをtmpfsにmountして使用している
+ ごくたまに、英語日本語の切り替えが**うまくいかないことがある(後述)。が、tipがあり、実用上は問題ない**
+ .cacheをtmpfsに移しても、移さなくても、安定動作している
+ **.cache on tmpfs時の起動爆速感**は、ぜひお勧めしたい
+ **ibusでもfcitxでも同様**(筆者環境では)

##参考
本質的には以上。以下は参考情報。
###筆者のchrome起動オプション
```
/usr/bin/google-chrome-stable --proxy-server="ipaddress:port" --renderer-process-limit=1 %U
```
###筆者のchromeバージョン
```
$ google-chrome-stable --version
Google Chrome 86.0.4240.75
```
###筆者のchrome .cache
```
$ df -lha |grep chrome
tmpfs           1.0G   32M  993M   4% /home/dk4130523/.cache/google-chrome
```

###just a tip
####うまくいかないことがある(後述)。が、tipがあり云々とは
chrome上で日本語入力ができなくなった場合、次の手順でこれまで100%正常状態に復帰しています(筆者環境では)。

1.　chromeを落とさない。**落とすだけ無駄**です
2.　**本記事冒頭の今北産業の第1行**を行ってみる。効果がなければ3.に進む
3.　デスクトップ・パネル上のキーボード・アイコンをクリックして**[あ]**(=日本語入力状態)に切り替える
4. 次のどちらかを試す
4.1　念のため、**chromeで新規タブ**を1つ立てる。そこで[Crtl]+[Space]などして、実際に日本語入力と変換を試します。**入力と変換ができることを確認する**
4.2　**他のアプリケーション**(例、LXTerminal)で日本語入力を試す。[Crtl]+[Space]などして、実際に日本語入力と変換を試します。**入力と変換ができることを確認する**
5.　**そのまま**chromeの、それまで作業していたchromeタブに戻ります

###読者からの手紙
1. .cacheをtmpfsに移す具体的な手順を教えてください
2. 他にもtmpfsに移してうまうましているアプリケーションが存在する匂いがします
3. そこまでして.cacheをtmpfsに移す動機は。[素で十分高速の豆腐](https://www.amazon.co.jp/dp/B08CRQ33X8/)では

###筆者からの返信
1. 次回記事で書くかも
2. **snapから入れた**spotify、ソースからビルドして入れたJDim(と、2chproxypl)、**wineで動かしている**PDIC英辞郎など。次々以降小出しにするかも
3. 「[豆腐がすぐに悪くなることと掛けたつもり](https://ja.wikipedia.org/wiki/%E9%85%A2%E8%B1%86%E8%85%90)かい？おーい山田君、若旦那の座布団ぜんぶ取っ払っちゃって」🐾💟
Rubyのエラーが出ている原因の見つけ方について


##前書き
よく出てくるエラー文を翻訳しなくてさっと確認する方法を解説してみました！




##(ArgumentError) 引数エラー
このエラーが出た時は、文字通り引数についてのエラーになります。
例えば、引数の数があっていない時や値が正しくない時出たりします。

下記のようなエラー文が出たとします。

```ruby:一部分を記載
arguments(given 2, expected 0)
```
訳すと、
引数（与えられた　2, 期待される　0)
極端な例ですが、渡す引数が2で
受け取る側が引数がない状態なのでエラーが出てますよ

みたいな感じになります。
(ArgumentError) これが出た時は、(given,expected)を探してみてください！




##(NameError)名前エラー
名前に関するエラー。
変数名やメソッド名に間違いがある時にでる。
定義した時の名前が間違っているか、メソッドを呼び出した時の名前が間違っている可能性があります。

```ruby:一部分を記載
undefined local variable or method  '〇〇' 

```
訳すと、
未定義のローカル変数またはメソッド
〇〇の変数orメソッドに注目してみましょう！

did you mean?(もしかして）
と提案してくている場合も多いのでここもチェック！


##(NoMethodError)ノーメソットエラー
メソットに関するエラー。
実行しようとしたメソットの呼び出し時の名前が間違っているか、メソッドが定義時の名前が間違っている可能性がある時にでる。

```ruby:一部分を記載
test.rb:2in '〇〇'
```

これはエラーが出ている部分を教えてくれいるので、この部分のメソッドを確認して見よう！

ノーメソッドエラーにも下記の記載があったらチェック！
did you mean?(もしかして）



##まとめ
とりあえずエラー文が出た時は、翻訳かけれましょう。
それで意味が分かれば見えてくる部分があると思います。

出てきた意味をググってみたら解決方法が見つかる場合もありますので！


エラーが出た時こそ、成長のチャンスです。
って思えるように頑張ります！
Unity ML-Agents で好奇心を持つエージェントを使ってみた

好奇心をもったエージェントは、学習することで高速でぐるぐるまわることができるようになりました。
コードは[こちら](https://github.com/machidyo/RollerBall)。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/07ebabe3-56a0-6dee-ff3a-1959f60bb211.gif" width="512" />

# 好奇心とは？
好奇心（curiosity）とはどういう定義だという話ですが、ここでは未知の状態に訪れた報酬のことを言います。
定義してしまうと、好奇心も一つのパラメーターですね。

そして、結果的に好奇心ありとなしでは、圧倒的に学習スピードが異なります。
残念ながら今回のテストでは好奇心のないエージェントはほぼ学習することがありませんでした。

# やったこと
* エージェントがぐるぐる半時計周りに1周するごとに報酬を与える
* エージェントが偶然一周するのはなかなか難しい（言い換えると偶然周ることもある）

# 結果
オレンジ：好奇心あり、ブルー：好奇心なし
![bandicam 2020-10-10 18-53-04-767.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/24bdb429-c332-f802-5475-0f16f5c0ff20.jpeg)

## 学習曲線
好奇心ありだと途中からの学びが全然違いますね。
学習なしでも周ることがあるので、ものすごい時間をかければ学習できる可能性はあります。
![bandicam 2020-10-10 18-53-31-448.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/e1465f0e-f1c5-cafa-af41-0ad5ef017b06.jpeg)

## 好奇心による平均累積報酬グラフ
今回はぐるぐる回るだけの単純な環境なため、あるポイントから好奇心による報酬が減っていることがわかります。
![bandicam 2020-10-10 18-54-03-917.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/451d1528-f9dd-e624-a414-86b58f7f4a71.jpeg)

# その他
最初は進める方向を3軸に方向に設定していたのですが、学習が全然進まずうまくいきませんでした。
結局XZの平面に固定することでうまく学習するようになりました。
3軸から2軸に変更したのは、私自身が操作してぐるっと回そうとしたときに、難しすぎると感じたからです。
エージェントが機械的に操作する場合も同じで、難しすぎるといかに好奇心があっても学習が難しいらしく、
ある程度操作できる状態にすることで解決できました。
【PHP】Valitronを用いたvalidation実装

php初心者の頃はよくわからなかったけど使っていくうちに使いやすさに惚れたバリデーションライブラリです。

##環境
・PHP 7.3.18
・composerインストール済み
##導入
composerを用いてインストールします。
(公式github：https://github.com/vlucas/valitron#installation)


```
php composer.phar require vlucas/valitron
```
##実装
・入力フォーム等でPOST送信がされた際に以下実行
・$_POST送信で送られてきたname属性を指定します。

```php
$v = new \Valitron\Validator($_POST);
//'required'で入力必須項目を指定、message()にてエラー時の出力文字を指定します
$v->rule('required', ['name', 'nameKana', 'phoneNumber', 'emailAddress'])->message('※{field}が未入力です。');
$v->rule('required', 'agreement')->message('※{field}の同意にチェックを入れてください。');
$v->rule('required', 'gender')->message('※{field}を選択してください。');

//上記'required'部分をemailにすることでメールアドレスの指定も可能
$v->rule('email', 'emailAddress')->message('※{field}を正しく入力してください。');
//'regex'で数字を指定
$v->rule("regex", "phoneNumber", "/\A0[0-9]{9,10}\z/")->message('※{field}を正しく入力してください。');

//validationエラー時、上記で指定したname属性部分を予め日本語にしておけば日本語で出力されます。
$v->labels([
  'name' => 'お名前',
  'nameKana' => 'フリガナ',
  'emailAddress' => 'メールアドレス',
  'gender' => '性別',
  'phoneNumber' => '電話番号',
  'agreement' => '個人情報保護方針'
]);
```

```php
//上記続き
if ($v->validate()) {
  //バリデーションOK時の挙動(送信確定画面に遷移等)
}else{
  $errors = $v->errors();
  //バリデーションNG時の挙動(再入力画面に遷移等)
}
```
validationエラー時、$errorsは配列で返ってくるのでhtml側でforeachで回して表示します。
【初心者でもわかる】URLなどの長い文字がブロック要素からはみ出る時の対策

#どうも7noteです。URLがはみ出ちゃってデザインが崩れた方必見。

どうも7noteです。
この記事は以下へ引っ越しました。

https://naruweb.com/coding/break-all/
CI/CD Docker コンテナのモニタリング

##起動中コンテナのリソース消費状況を表示
```
$ docker stats --no-stream
CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
a5ed2facaadd        webcentos           0.00%               2.398MiB / 12.37GiB   0.02%               1.31kB / 0B         0B / 0B             2
e3a96695d263        docker_mysql_1      0.12%               187.5MiB / 12.37GiB   1.48%               1.05kB / 0B         0B / 0B             27
cc761f675b3b        docker_nginx_1      0.00%               4.309MiB / 12.37GiB   0.03%               956B / 0B           0B / 0B             2
```

##フォーマットして表示
```
$ docker stats --no-stream --format "{{.Name}},{{.MemPerc}},{{.CPUPerc}}"   #コンテナ名, メモリ使用率, CPU使用率
webcentos,0.02%,0.00%
docker_mysql_1,1.48%,0.12%
docker_nginx_1,0.03%,0.00%
```

##監視バッチ
###1分毎に実行して使用率閾値(80%)を超過したら通知メッセージを飛ばす
```
#!/bin/bash

# 閾値(%)
LIMIT=90

# コンテナのSTATS取得
CHECK_STATS=$(docker stats --no-stream --format "{{.Name}},{{.MemPerc}},{{.CPUPerc}}") #コンテナ名, メモリ使用率, CPU使用率

while read row; do
  name=`echo ${row} | cut -d , -f 1`     #コンテナ名
  memPer=`echo ${row} | cut -d , -f 2`   #メモリ使用率
  memPer_i=`echo ${memPer%%.*}`
  cpuPer=`echo ${row} | cut -d , -f 3`   #CPU使用率
  cpuPer_i=`echo ${cpuPer%%.*}`
  
  # メモリ使用率閾値チェック
  if [ $memPer_i -ge $LIMIT ]; then
     message="Container：${name} Memory alert ${memPer}"
     curl -X POST --data-urlencode 'payload={"channel": "#alert", "username": "admin", "text": "${message}"}' <webhook URL>
  fi

  # CPU使用率閾値チェック
  if [ $cpuPer_i -ge $LIMIT ]; then
     message="Container：${name} CPU alert ${cpuPer}"
     curl -X POST --data-urlencode 'payload={"channel": "#alert", "username": "admin", "text": "${message}"}' <webhook URL>
  fi
done < echo "$CHECK_STATS"
```