OmniAICreator/Qiita-1.07M huggingface dataset:
【Elasticsearch】KibanaにプラグインAnalyze UIを入れてみる

# はじめに
Elasticsearchにおけるアナライザーで、単語がどのように分割しているか調べるときどうしてますか？
以前はKibanaのコンソール経由でリクエストし調査していたのですが、限界を感じたので今回はAnalyze UIというプラグインを入れて直感的に操作したいと思います。

# 環境
OS：Amazon Linux 2
Elasticsearch7.5.0
Kibana7.5.0

# プラグイン
今回インストールするKibanaのプラグインです。たまにバージョンが飛んでいるのでご注意ください。
https://github.com/johtani/analyze-api-ui-plugin/

# インストール
## コマンドでインストール
Kinabaがあるサーバにインストールします。

```shell:
$ sudo /usr/share/kibana/bin/kibana-plugin --allow-root install https://github.com/johtani/analyze-api-ui-plugin/releases/download/7.5.0/analyze_api_ui-7.5.0.zip
```

## インストールディレクトリ確認
OSによってインストール先が違いますが、インストール先を見てみます。

```shell:
$ ls -tlr /usr/share/kibana/plugins
```

## Kibanaリスタート
リスタートしないと読み込んでくれないので注意

```shell:
$ sudo systemctl restart kibana.service
```

## プラグイン一覧確認

```shell:
$ sudo /usr/share/kibana/bin/kibana-plugin --allow-root list
analyze_api_ui@7.5.0
```

## Kibanaにアクセス
ブラウザでKibanaを見てみます。
http://(Kibana URI)/app/analyze_api_ui

メニューにこのようなアイコンがあればインストール成功です。
<img width="238" alt="Kibana-6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442996/15cd7d9f-a028-af70-e815-6ed29489b2a8.png">

# 使ってみる
あとはUIに従って使ってみるのみです。タブメニューの紹介だけしておきます。

**Analyzer**：アナライザー名を指定して調査できます。
**Custom Analyzer**：char_filter/tokenizer/filter名を指定して組み合わせを調整できます。これから新しく作るアナライザーに便利です。
**Field**：インデックスマッピングのフィールド名を指定してアナライザーが調査できます。
**Compare Analyzers**：アナライザー名を複数指定して結果を見るときに便利そうです。

<img width="887" alt="Kibana-5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442996/8dfd3335-37e3-f3ee-ea80-8f97bb6200f6.png">

# さいごに
今までなんとなくだったchar_filter/tokenizer/filterが、どのように機能しているかを理解し一歩も二歩も距離が短くなった気がします。
アナライザーの見直しにもとても役立ちました。
他にも良いプラグインがあれば、導入していきたいです。
coc.nvim で Vue.js を使う。


:::note alert
Vue2 対応です。Vue3 ではやったことがなくわかりません。
:::

## 前提
以下のものは既にインストールされているものとします。

1. npm パッケージ
1.1. prettier
1.2. eslint
2. Vim プラグイン
2.1. coc-nvim 

## インストール

```
:CocInstall coc-prettier
:CocInstall coc-eslint
:CocInstall coc-vetur
```

### ◯ 補足

extention の一覧を表示する。

```
:CocList extensions
```

extention をアンインストールする。

```
:CocUninstall coc-eslint
```

* [Using coc extensions - neoclide/coc.nvim](https://github.com/neoclide/coc.nvim/wiki/Using-coc-extensions)

## 設定 - prettier

`:Format` で prettier が実行されます。

```vim:~/.vimrc
command! -nargs=0 Format :call CocAction('format')
```

* [coc.nvim の CocAction ってなんだ？ - Qiita](https://qiita.com/domodomodomo/items/c5e199b5363ebd6e354f)

## 設定 - eslint

eslint は coc-eslint をインストールするだけではダメで、設定が必要になります。

### Step 1.

設定ファイルを開きます。プロジェクト関係なしに全体に設定を反映させたい場合は、`:CocConfig` を使います。 `~/.vim/coc-settings.json` に設定が書き込まれます。

```
:CocConfig
```

プロジェクトごとに設定をしたい場合は、`:CocLocalConfig` を使います。 `ワークスペースフォルダ/.vim/coc-settings.json` に設定が書き込まれます。

```
:CocLocalConfig
```


ワークスペースフォルダは、VScode で言う所のワークスペースのようなものらしいです。詳細は、以下をご確認ください。

> VSCode と違って vim はワークスペースをサポートしていません。これに対して coc.nvim では、開いているファイルの位置からワークスペースフォルダを探索します（訳注: だいぶ意訳しました）。
> Unlike VSCode vim doesn't have workspace support. The solution is resolve workspace folders from opened files.
> [Using workspaceFolders - neoclide/coc.nvim](https://github.com/neoclide/coc.nvim/wiki/Using-workspaceFolders)


### Step 2.

`"vue"` を追記します。

```~/.vim/coc-settings.json
{
  "eslint.filetypes": ["javascript", "vue"],
}
```

### ◯ 補足 1

`:set filetype?` で確認したものを追記しています。

* [Find what filetype is loaded in vim - Stackoverflow](https://stackoverflow.com/questions/2779379/find-what-filetype-is-loaded-in-vim/2779390)

### ◯ 補足 2

自分の環境ではなぜか tsserver が勝手にインストールされてエラーを履いてくることがあるので `false` にしています。

```~/.vim/coc-settings.json
{
  "tsserver.enable": false
}
```


<!--

`.eslintignore` を置く場所は workspaceFolders に置く必要があります。workspaceFolders は以下のコマンドで確認が可能です。

```
:CocList folders
```

* [Using workspaceFolders - neoclide/coc.nvim](https://github.com/neoclide/coc.nvim/wiki/Using-workspaceFolders)

-->
ConoHaVPSのCentOS7.4にDocker/Docker-composeをインストールした【備忘録】

## 概要

今さらながらConoHaVPSにDockerとdocker-compose入れて運用したくなったので色々調べつつインストールした。
備忘録以外の何物でもないです。

## 現状の確認

### 古いdockerが入っているか確認

```
$ sudo yum list installed | grep docker
Repodata is over 2 weeks old. Install yum-cron? Or run: yum makecache fast
docker.x86_64                      2:1.13.1-63.git94f4240.el7.centos @extras
docker-client.x86_64               2:1.13.1-63.git94f4240.el7.centos @extras
docker-common.x86_64               2:1.13.1-63.git94f4240.el7.centos @extras
```

### 入っていたのでアンインストール

入れた記憶ないけど入ってたので削除する。

```
$ sudo yum remove docker docker-client docker-common
```

## Docker CEのインストール

### リポジトリを使ってインストール 

```
# 必要なパッケージのインストール
$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2

# stable （安定版）リポジトリをセットアップ
$ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
```

### インストール可能なバージョンの確認

```
$ yum list docker-ce --showduplicates | sort -r
```

### インストール

```
$ sudo yum install -y docker-ce docker-ce-cli containerd.io
```

### Dockerの起動

```
# サービス起動
$ sudo systemctl start docker

# サービス登録
$ sudo systemctl enable docker

# 起動確認
$ docker info
```

## docker-composeのインストール

最新バージョンは[こちら](https://github.com/docker/compose/releases)で確認。

### インストール/permission変更

```
$ sudo curl -L https://github.com/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

$ sudo chmod +x /usr/local/bin/docker-compose
```

### バージョン確認

```
$ docker-compose --version
```

## `sudo`なしで`docker`コマンドを使えるように

```
# dockerグループ作成
$ sudo groupadd docker

# ログインユーザーをグループに追加
$ sudo gpasswd -a $USER docker

# リスタート
$ sudo systemctl restart docker

# 再ログインで反映
```
Flutter エラー 「Could not find the correct Provider」

FlutterのProviderで同じところで何度もハマったので備忘録として。

##Could not find the correct Providerのエラーでハマったら…

```dart:main.dart
void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(builder: (context) => hogeBloc()..nextPage()),
        ChangeNotifierProvider(builder: (context) => fooBloc()..nextPage()),
        //←←←ここに追加するProviderを記載する
      ],
      child: MyApp(),
    ),
  );
}

```

## 参照
Flutter公式 : [Simple app state management](https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#changenotifierprovider)
ilasmでstack machine その7

#概要

ilasmでstack machineやってみた。
俺言語、コンパイラを考えてみた。
3段階です。
１回目をハンドコンパイルしてみた。


#10 a=1


```
    pushi   1
    set     a

```

#30 b=a%15


```
loop:
    get     a
    pushi   15
    %
    
```

#40 #=b=0*120


```
    if      fizzbuzz
```

#50 b=a%5


```
    get     a
    pushi   5
    %
```

#60 #=b=0*140


```
    if      buzz
```

#70 b=a%3


```
    get     a
    pushi   3
    %
```

#80 #=b=0*160


```
   if      fizz
```

#90 ?=a


```
    get     a
    call    printi
```

#100 #=a<100*30


```
tugi:
    get     a
    pushi   100
    if<     loop
```

#110 #=255



```
    jp      ext
```

#120 ?="fizzbuzz "



```
fizzbuzz:
    push    "fizzbuzz"
    call    prints
```

#130 #=180



```
jp      tugi
```

#140 ?="buzz "



```
buzz:
    push    "buzz"
    call    prints
```

#150 #=180



```
    jp      tugi
```

#160 ?="fizz "



```
fizz:
    push    "fizz"
    call    prints
```

#180 a=a+1


```
tugi:
    get     a
    pushi   1
    +
    set     a
```

#190 #=30

```
    jp      loop

ext:
    ret
```
    
以上。
分析関数（Window関数）を利用してmysql8.0でROW_NUMBER取得 

# 分析関数（Window関数）を利用してmysql8.0でROW_NUMBER取得

## Mysql8にデーター移行して行数取得でエラー
mysql5.6で問題なかった下記のSQLがmysql8.0で行数取得でエラーが発生。

```
set @row:=0;
select * 
from 
    (select `id`, @row:=@row+1 as row 
    from `table_a` 
   where `status` = 1 
      and `table_a`.`deleted_at` is null 
      order by `published_day` desc
   ) st 
where `id` = ? limit 1

```
## Mysql8で実行時エラー内容
```
local.ERROR: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'row from `table_a` where `status` = 1 and
```

## エラー調査
最初はMysql8で下記の書き方が問題なると思い、「Mysql8+row」で調べたら「Window関数」に関する内容が多かった。
```
@row:=@row+1
```
ソースを「Window関数」に書き換えて再実行してもエラーは解消されなかった。

```
select * 
from 
   (select `id`, ROW_NUMBER() OVER (ORDER BY published_day DESC) AS row
   from `table_a` 
   where `status` = 1 and 
      and `table_a`.`deleted_at` is null 
      order by `published_day` desc
   ) st 
where `id` = ? limit 1
```

## エラー原因
Mysql8から「row」が予約語として追加されたのが原因でした。


原因が分かったので下記にソースを変更して再実行したらエラーは解消されました！！

```
select * 
from 
   (select `id`, ROW_NUMBER() OVER (ORDER BY published_day DESC) AS row_num 
   from `table_a` 
   where `status` = 1 and 
      and `table_a`.`deleted_at` is null 
      order by `published_day` desc
   ) st 
where `id` = ? limit 1
```

## 「Window関数」に関して

[1] 基本となるWindow関数
Window関数は、"OVER (PARTITION BY ...)" or "OVER (ORDER BY ...)" をつけて使用します。
OVERの前にくるのは、Window関数に限らず、従来の集約関数（SUM, COUNTなど）でも可能です。
集合関数は後ろにOVER句をつけれれば、分析関数になる。

[2] ROW_NUMBER()
ROW_NUMBER関数は、その名の通り取得した行（レコード）の番号を表示します。
Widnow関数内のORDER BY句で指定されたカラムの順番に沿って、「1」から番号が割り振られます。なお、ROW_NUMBER関数は括弧の中に変数を指定する必要はありません。

従来のMySQLでは行番号を出力する場合に手間がかかっていましたが、ROW_NUMBER()を使えば簡単に取得することができます。

[3] よく使われる関数 ： SUM, COUNT, AVG
「Window関数」にはSUM, COUNT, AVGの便利な関数もあり今後機会があったら使いたいと思います。
![スクリーンショット 2020-01-07 16.49.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274686/524c4b7c-8ae8-fd24-5868-0836643c9b04.png)

## 参考サイト
https://wpchiraura.xyz/mysql-80-reserved-word-list/
https://qiita.com/kakuka4430/items/8c66e743800fcb8bc040
Terraform x GCP で、IAM権限を全削除してしまった

我が社では最近GCPを使っています。

初めはWEB画面でポチポチ設定していたのですが、規模が大きくなってきたのでTerraformを導入することにしました。

とりあえず、直近で必要なサービスアカウントをTerraformで作ることにします。

```terraform

resource "google_service_account" "logagg" {
  account_id = "logagg-fluentd"
  display_name = "logagg-fluentd"
  description = "fluentd が Cloud Pub/Sub にデータを挿入するためのアカウント"
}

resource "google_project_iam_policy" "pubsub-publisher" {
  project = "my-project"
  role = "roles/pubsub.publisher"
  members = [
    "serviceAccount:${google_service_account.logagg.email}"
  ]
}
```

`terraform apply` → `yes` を実行！

# ドーン！！

**誰もGCPの画面にログインできなくなりました。**

特権管理者になって確認すると、全員のIAM権限が削除され、terraformで作ったサービスアカウントの権限だけが残っていました。

なお、吹っ飛んだのはテスト環境だったので実損はありませんでした。

# 何が起こったの？

Terraformの[google_project_iam_policyのドキュメント](
https://www.terraform.io/docs/providers/google/r/google_project_iam.htm)には、以下のような説明があります。

> **google_project_iam_policy**: Authoritative. Sets the IAM policy for the project and replaces any existing policy already attached.
>
> **google_project_iam_binding**: Authoritative for a given role. Updates the IAM policy to grant a role to a list of members. Other roles within the IAM policy for the project are preserved.

私訳

> **google_project_iam_policy**: 権限。プロジェクトのIAMポリシーを設定し、既にアタッチされている既存のポリシーを置き換えます。
>
> **google_project_iam_binding**: 指定したロールについての権限。
IAMポリシーを更新して、メンバーのリストにロールを付与します。プロジェクトのIAMポリシー内の他のロールについては現状維持です。

つまり、
`google_project_iam_policy`を使うと「プロジェクトの全IAM権限をTerraformで管理する」ということになり、Terraform外の設定は全て破棄されます。

今回のように既にIAMの設定がある場合は `google_project_iam_binding` を使うべきだったのです。

# むすび

ドキュメントは読みましょう。
[Android] Serviceクラス（bindService）

##Serviceとは
ダウンロードなどの処理時に、UI操作を阻害しないようにするため、Activityとは別に動作させることができる。
startService()とbindService()の2種類がある。今回はbindServiceについて記す。

・**startService**
　Activityが破棄されても、stopSerivceかstopSelfによって明示的に終了するまで続く。

・**bindService**
　バインドしているActivityがなくなると破棄される。

##使い方
Serviceを継承したクラスを作り、クライアント側から呼び出すことで使用できる。
まずクライアント側クラスは以下の通りである。
Mainctivity.java

~~~java
public class MainActivity extends AppCompatActivity {
    // 起動するServiceのBinder
    BindService.MyBinder binder;

    // ServiceConnectionオブジェクト
    private ServiceConnection conn = new ServiceConnection() {

        // Service接続成功時のCallback
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            binder = (BindService.MyBinder) service;
        }

        // Service異常切断時のCallback
        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 起動用Intent
        final Intent intent = new Intent(MainActivity.this, BindService.class);

        /*ServiceをBound状態にする。インスタンスがなければ作成を要請する。
         *また、Serviceと通信するためのIBinderインターフェースはシステムからコピーされたものが渡される。
         */
        bindService(intent, conn, Service.BIND_AUTO_CREATE);

        //バインドを解除する。この時、条件によってはServiceも終了する。
        unbindService(conn);

}
~~~

次にService側クラスの基本構造は以下の通りである。
**AndroidManifestに登録しなければ使えないので気を付けて頂きたい。**
BindService.java

~~~java
public class BindService extends Service {
    // onBind()で返すBinder
    private MyBinder binder = new MyBinder();

    //最初のbindService呼び出しのみ、システムにIBinderインターフェースを渡すために呼ばれる。
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    /*Serviceのインスタンスがない状態で、クライアントがstartServiceまたはbindServiceを呼んだ時に
     *Serviceのインスタンス生成で呼ばれる。すでにインスタンスが存在している場合は呼ばれない。
     */
    @Override
    public void onCreate() {
        super.onCreate();
    }

    /*インドしているクライアントが「全て」いなくなったとき。そのためunbindServiceが呼ばれても、
     *ほかにバインドしているクライアントが存在した場合、onUnbindは呼ばれない。
     */
    @Override
    public boolean onUnbind(Intent intent) {
    }

    //バインドされたクライアントがなくなって、onUnbindが呼ばれたあとに呼ばれる
    @Override
    public void onDestroy() {
    }
}
~~~

AndroidManifest.xml

~~~xml
<application
    <service android:name=".BindService"/>
~~~

##サンプルの実装と結果
本記事では以下の記事のサンプルと同じものを作ってみた。（コードは割愛）
http://javait.hatenablog.com/entry/2015/12/15/235135

以下のようにうまくいった。
![スクリーンショット (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506451/67628b7d-cd9d-d2a4-4983-c0d0026f98a1.png)

##困ったところ
**AndroidManifestへの登録**を忘れていたが、それ以外は特になかった。

##感想
参考サイトには使わなかったメソッドもあったので、またの機会に使ってみたい。


##参考URL
サンプル
http://javait.hatenablog.com/entry/2015/12/15/235135

Serviceの詳しい説明
http://ria10.hatenablog.com/entry/20121110/1352537601
Unityメモ：UnityでMicrosoft TeamsにIncoming Webhookを使って自動投稿したい

# コードだけバーン

```c#:sample.cs
////////////////////////////////////////////////////////////////////////////////
//
// Light Wings GameProject
//
// (C) 2009 Light Wings GameProject.
//
// https://github.com/LightWings-GameProject
//
////////////////////////////////////////////////////////////////////////////////

using System;
using System.Text;
using UniRx;
using UnityEngine;

/// <summary>
/// Microsoft Teams の Incoming Webhook
/// </summary>
public class MicrosoftTeamsIncomingWebhook
{
	class PostData
	{
		public string text; // 投稿内容
		public string username; // user名
	}

	/// <summary>
	/// Webhook に対してメッセージを送信する
	/// </summary>
	/// <param name="url">IncomingWebhookで取得したURL</param>
	/// <param name="username">ユーザ名</param>
	/// <param name="text">投稿文</param>
	/// <returns>投稿リクエストのストリーム</returns>
	public static IObservable<string> Post(string url, string username, string text)
	{
		PostData data = new PostData();
		data.username = username;
		data.text = text;
		string json_data = JsonUtility.ToJson(data);
		byte[] postBytes = Encoding.UTF8.GetBytes(json_data);

		return ObservableWWW.Post(url, postBytes);
	}
}
```
```
The MIT License (MIT)
Copyright (C) 2009 Light Wings GameProject.
```

# 不満な点
* Teamsは画像投稿に対応していない
* [Teamsはメンションに対応していない](https://stackoverflow.com/questions/48574994/mention-via-incoming-webhook-in-ms-teams/48575997)

# 参照
[UnityからSlack投稿する](https://qiita.com/iwaken71/items/bbc5bde1f0eb05a2a9b0)
[Microsoft TeamsにC#で投稿](https://qiita.com/07JP27/items/93d777024f65219f03d5)
[【MS Teams】Incoming Webhook経由で画像を送信する方法](https://qiita.com/m_hama123/items/c40c8f5271ca03fc57e9)
[Microsoft Teams に PowerShell で投稿してみる](https://qiita.com/miyamiya/items/ccae505b8e97b5b532a7)
【Laravel】何をやっても.envが反映されない時の対処法(備忘録)

# 事象
Laravelの.envやconfigを変更した際は、下記のコマンドを実行して変更を反映させるのが一般的ですが

```console:console
    php artisan cache:clear
    php artisan config:cache
```
これらを実行しても.envやconfigの内容が反映されない場合は下記のファイル削除を行うと解決します。

# 結論

```console:console
    rm -f bootstrap/cache/config.php
```

# 追記
今回の事象が発生したのは、.envへの値読み込みをコントローラ上で行っていたプロジェクトで発生しました。
そもそも、.envを直接コントローラやビュー等で参照するのがマズいらしく、envの値を参照する際は、必ずconfigファイルを挟んで行わなければならない。
ちょっとお兄ちゃん？否定のフラグは絶対作らないでって言ったよね？

（CV: 渡部恵子）

## 普通のフラグ

```php
<?php
$is_a = true;

if($is_a){
    // Aだったら
    var_dump('Aでした');
} else {
    // Aじゃなかったら
    var_dump('Aではありませんでした');
}
```

## 否定のフラグ

```php
<?php
$is_not_a = true;

if($is_not_a){
    // Aじゃなかったら
    var_dump('Aではありませんでした');
} else {
    // Aじゃない、じゃなかったら
    var_dump('Aじゃない、ではありませんでした'); // 脳内変換（あぁ、要するにAだったのね）
}
```

否定のフラグはfalseだった場合に「notのフラグのfalseだからつまりtrueってことか？」っていう脳内変換が必要になります

例だと「Aじゃない、じゃない」というフラグなので「こんなフラグ誰も作らないでしょ」と思うかもしれません
実際には「未入金かどうか」を「is_not_payment」とかやっちゃうパターンがあるあるです
こうしてしまうと「is_not_paymentがfalseだから未入金じゃない、つまり入金済みってことか」みたいな脳内変換が発生します
この場合は「入金済みかどうか」のフラグ「is_payment」みたいにしてあげると後々嬉しいことが多いです

## まとめ

否定のフラグを作ってしまいそうになったら肯定のフラグに作り直しましょう
【A-Frame】VRコンテンツの作り方

# はじめに
社内制作でVRコンテンツを作成しました。
細かいコンテンツ作成などは置いておき、VRっぽいものを作るまでの流れが簡単だったので紹介します。

# 環境
**OS** : Windows 10 Pro
**エディター** : VSCode

# 実装
1.　A-Frameの読み込み

```html
<html>
  <head>
    <script src="https://aframe.io/releases/1.0.3/aframe.min.js"></script>
  </head>
  <body>
  </body>
</html>
```
2.　オブジェクトの配置

```html
<html>
  <head>
    <script src="https://aframe.io/releases/1.0.3/aframe.min.js"></script>
  </head>
  <body>
    <a-scene>
      <a-box position="0 1.17 -3.9" rotation="0 0 0" color="#ff0000"></a-box>
    </a-scene>
  </body>
</html>
```
この時点で下記のように出力されます。
※PCで確認しているので、スマホなどで確認するとすでにジャイロセンサーなど取得して、空間上にオブジェを配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19460/f7fe95fc-b794-7063-b3ef-a73339a6eae2.png)

画像にテクスチャーを張ったり、3Dオブジェクトを配置したりできるので、試してみてください。
詳細は↓↓公式サイト↓↓
https://aframe.io/

3.　A-Frame Inspector
値を変更して毎度、確認するのが面倒なので、A-Frame Inspectorを開いて（win:`ctrl + alt + i`）直接オブジェクトの配置やサイズ感を決めるとやりやすいかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19460/9798fdee-4deb-7f47-bcf6-daa4e2f702e2.png)


※端末のOSのバージョンによって、センサーの取得状況が違うため、要実機検証が必要です。

実際にA-Frameで作ったサイトは↓こちら↓
http://www.hol-on.co.jp/greetingsite/newyear/2020/?utm_source=qiita

以上
【Python】変数の型変換

#変数の型
変数の型と表記しているが、厳密にはデータの型である。
ただし、データは変数に格納され、扱われるので、変数の型と表現したい。
変数の型は、**type(変数名)**で確認することが出来る。
本記事ではデータの型変換（＝**キャスト**）について紹介する。

```python:type.py
a="1"
b=1
print(type(a)) #output=str
print(type(b)) #output=int
```

上例のように同じ１でも**数字**として扱うか、**数値**として扱うかで**PC内部での扱われ方も変わる**。
上例は一例にすぎず、type関数を使うと**int**、**str**、**list**や**DataFrame**など様々な結果が返ってくる。

#型変換
型変換を行うことによって、演算を行うことが出来るようになる。
例えばテキストデータを読み込んだデータが文字型として扱われおり、そのデータを使って算術計算を行いたい場合に型変換は必須である。（他にも型変換を用いる機会は多々存在する。）

**変換方法は関数名（変数）**である。
★単一変数（listやtuple出ない場合）

| 関数       |       意味 | 
|:-----------------|:------------------|
| str(変数)             | 変数をstr型(文字)に変える |
| int(変数)             | 変数をint型(整数)に変える | 
| float(変数)             | 変数をfloat型(小数)に変える |

```python:type.py
a="1"
b=1
print(type(a)) #output=str
print(type(b)) #output=int
c=str(b)
print(type(c)) #output=str
```

★list、tupleの場合

| 関数       |       意味 | 
|:-----------------|:------------------|
| list(tuple)             | tuple型をlist型に変える |
| tuple(list)             | list型をtuple型に変える | 

#map関数の利用
listやtupleなどの全ての要素の型を変換したい場合に使うことが出来る。
map関数の記述方法は、**map(適用したい関数,適用したいlist/tuple)**である。

```python:type.py
l=[1,2,3,4]
print(type(l[0]),type(l[1]),type(l[2]),type(l[3])) # output = 全てint
l_n=list(map(str,l)) # mapを適用後変数の型がmap型になるので、それをlist型キャストする必要がある。
print(type(l_n[0]),type(l_n[1]),type(l_n[2]),type(l_n[3]),) # output = 全てstr
```
serverless-prune-pluginでLambdaのバージョンを整理する

ちょくちょく忘れるので忘備録

## インストール

```
$ npm i -D serverless-prune-plugin
```

## serverless.yml

```yaml
plugins:
 - serverless-prune-plugin

custom:
  prune:
    automatic: true
    number:3
```

customの方を設定してないと、`sls deploy`で消えない。

## CLIから手動削除

```
# 直近3バージョンを残してすべて削除
$ sls prune -n 3

# helloのLambda関数を直近3バージョンを残して削除
$ sls prune -f hello -n 3

# ドライラン。削除予定の数が見れる
$ sls prune -n 3 -d

```
壊れた Ubuntu ディスクが残っていて Ubuntu の再インストールができない時の対処

# 結論

起動時に F2 を押して BIOS のセットアップに入って、DVD 以外のメディアの boot device をすべて disable にして起動しなおす。これで Install Ubuntu のメニューが出るようになりました。

USB メモリの場合も、同様に USB 以外の device をすべて disable にして起動しなおせば、Install Ubuntu のメニューが出るようです。

もちろんですが、再インストール後は、boot device を enable に直しておく必要があります。

# 状況

Ubuntu 18.04 LTS で確認しました。

DVD や USB メモリに iso を書きこんで、そのメディアからブートしたとしても、Ubuntu がインストールされている HDD が接続されていると、"Install Ubuntu" のメニューがでないまま、Ubuntu が起動してしまうことがあるようです。

BIOS の設定方法は、BIOS によって異なります。私の環境では、BIOS の基本設定の画面では boot device の優先順位しか変えることができなくて、どうするのかと思ったら Advanced の設定のほうでは、boot device を disable にすることができました。

# 再インストールの手順

Ubuntu 18.04LTS desktop の場合、起動して Ubuntu のデスクトップ画面が出たとき、デスクトップに Install Ubuntu 18.04 LST というアイコンが置かれています。これをダブルクリックすることで、通常のインストール時と同じ手順で再インストールできるようです。

破壊された Ubuntu を泣く泣く修復している現場からは以上です…

# 参考

- https://884yuu.com/archives/669
- https://qiita.com/tfukumori/items/cbcd4d961d1740fca69d
Dockerfile内におけるGitの秘密鍵のこと

## 背景
開発環境での作業時、Docker使ってプライベートリポジトリcloneした時に、秘密鍵見れちゃうのがとても気になって。とりあえず色々調べてみたのでその結果を書いてみる。

## 参考サイト
- [コピーしてrmしてない？大丈夫？](https://megalodon.jp/2019-0408-2216-38/https:/www.kimoton.com:443/entry/20190111/1547192587)

- [BuildKitについて](https://medium.com/nttlabs/docker-v18-09-%E6%96%B0%E6%A9%9F%E8%83%BD-%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%83%93%E3%83%AB%E3%83%89-%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3-9534714c26e2)

## やったこと

以下の2つの対応をしてみた。

### 1. マルチステージビルド

- 何故？

	docker history で不要なステージが表示されないようにするため
  
- やり方、方法

	as で中間成果物を保存して、最後にそこからコピーすることで、中間成果物の内容が見れない模様

```
# syntax = docker/dockerfile:experimental
FROM ruby:2.5 as intermediate

# 処理諸々
[・・・]

# マルチステージビルド
FROM ruby:2.5
COPY --from=intermediate / /
```

- 注意点

	COPY前までに行った作業(ex. bundle install)で何かしらディレクトリに変更があった場合、対象ディレクトリをしっかりCOPYする必要がある。
↓
	最初、/root /root のみを対象にしていたのだが、bundle install で /usr/local/bundle にインストールされるので、COPY対象外で、gemがないよと怒られた。

- 確認
![docer-history.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117388/1c78fc79-6d85-ed6c-346b-e8eda04b09fb.png)

### 2.  BuildKitの利用
- 何故？

	`~/.ssh/id_rsa` などの秘密鍵をコンテナ内に残さないようにするため
  
- やり方、方法

	`--mount=type=secret,id=ssh,target=/root/.ssh/id_rsa git clone` オプションをつけてgit cloneする


```
 # Git
 ARG SSH_PRIVATE_KEY
 RUN mkdir /root/.ssh/
 RUN touch /root/.ssh/id_rsa
 RUN echo "${SSH_PRIVATE_KEY}" > /root/.ssh/id_rsa
 
 RUN touch /root/.ssh/known_hosts
 RUN ssh-keyscan -t rsa github.com >> /root/.ssh/known_hosts
 RUN chmod 600 /root/.ssh/*
 
 # プロジェクトclone
 WORKDIR /root/
 RUN --mount=type=secret,id=ssh,target=/root/.ssh/id_rsa
 RUN git clone [プロジェクト]
 RUN rm /root/.ssh/id_rsa #→ rm しないと残ったままっぽい
↓
$ docker build -t yaga0429/ruby-chromedriver --build-arg SSH_PRIVATE_KEY="$(cat ~/.ssh/id_rsa)" --no-cache
```

- 確認
![docker-run.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117388/3b047688-8f66-d397-a002-153e5fb9a8d4.png)

## まとめ
ECRとかでimageをプライベートに管理してたりすると、あんま気にならないのかな。
その辺はいまいちわからんけど、なんとなくスッキリしたのでオーケー。
まぁやってみたので忘れないうちに。
aws cliでセキュリティグループにICMPのルールを追加するときのPortの意味

aws cliでセキュリティグループにICMPのルールを追加するとき、`FromPort`、`ToPort`には０、６５５３５でも指定しておけば良いのかなと思ったらエラーになった。

```
$ aws ec2 authorize-security-group-ingress --group-id sg-xxxxxxxx --ip-permissions IpProtocol=icmp,FromPort=0,ToPort=65535,IpRanges='[{CidrIp=999.999.999.999/32,Description="Example"}]'

An error occurred (InvalidParameterValue) when calling the AuthorizeSecurityGroupIngress operation: ICMP code (65535) out of range
```

０、０にしたらエラーにはならなかったけど、プロトコルが`エコー応答`として登録された。プロトコルは`すべて`で登録したい。

調べてみたところ、ICMPのルールを追加するときの`FromPort`、`ToPort`にはICMP codeを指定するらしい。

[authorize-security-group-ingress — AWS CLI 1.16.311 Command Reference](https://docs.aws.amazon.com/cli/latest/reference/ec2/authorize-security-group-ingress.html)

０はエコー応答なのね。

[Internet Control Message Protocol - Wikipedia](https://ja.wikipedia.org/wiki/Internet_Control_Message_Protocol#%E9%80%9A%E7%9F%A5%E3%81%AE%E7%A8%AE%E9%A1%9E)

`すべて`を指定したい時は−1を指定すれば良いようなので、`FromPort`、`ToPort`に−1を指定したら、`プロトコル`:`すべて`で無事登録された。

```
$ aws ec2 authorize-security-group-ingress --group-id sg-xxxxxxxx --ip-permissions IpProtocol=icmp,FromPort=-1,ToPort=-1,IpRanges='[{CidrIp=999.999.999.999/32,Description="Example"}]'
```

大量のIP許可設定とかやる時はCLIがやっぱり便利。
laravel-adminでcheckboxをDBに保存

`larave-admin`はお手軽にさらっと管理画面を作れて便利です。
大まかな使用方法は他の記事にお任せするとして`checkbox`、`multiselect`などをDBに保存するにはひと手間必要なので備忘録的メモです

公式に記述があります。二つあるようですが今回はデータをカンマ区切りで登録する方法です。
https://laravel-admin.org/docs/#/en/model-form-fields


```php5
class Post extends Model

    public function getTagsAttribute($value)
    {
        return explode(',', $value);
    }

    public function setTagsAttribute($value)
    {
        $this->attributes['tags'] = implode(',', $value);
    }
}
```
そのまま引用しています。`get[elements]Attribute`と`set[elements]Attribute`をoverwriteしています。

マイグレーションはtextかvarcharあたりで

```php5
            Schema::create('post', function (Blueprint $table) {
                $table->bigIncrements('id');

                $table->text('tag');
                $table->timestamps();
                $table->softDeletes();

            });
```

これでDBにはカンマ区切りで保存されます
【備忘録】Airflowでload_examplesをFalseにしてもExampleを出してきやがる問題について

# airflow複雑すぎてわからない問題。

ただでさえconfig要素が多いのに、airflowで最初に直面するのがload_examplesをFalseにしても
TutorialのDAGが消えてくれない問題があります。

結構鬱陶しいのに、なかなか解決しないので、ここに備忘録として記録します。

# 解決策:resetdbしろ

https://stackoverflow.com/questions/43410836/how-to-remove-default-example-dags-in-airflow
こちらに解法が載っていました

`resetdb`しろとのこと。

これで無事に治ることを確認しました。
EC2を利用して、RailsアプリをAWSにデプロイする途中、nokogiriがインストール出来なかった時の解決方法（初心者）

EC2を利用して、RailsアプリをAWSにデプロイする途中、nokogiriがbundle install出来なかったので、今後の忘備録として。
AWSのcloud9上で開発しており、ローカルでのHomebrewは使用しておりません。

production環境設定後、secret_key_base用の乱数を生成時に躓きました。

$ rake secret

以下のエラー文

```
An error occurred while installing nokogiri (1.10.7), and Bundler cannot continue.
Make sure that `gem install nokogiri -v '1.10.7' --source 'https://rubygems.org/'` succeeds before bundling.
```
エラーに書いてあるように、
$ gem install nokogiri -v '1.10.7'
してみましたが、解決せず。


当初はnokogiriの保存場所、バージョンが違うのかとこちらの記事を参考にしていましたが、解決しませんでした。
https://qiita.com/yuki_uchida/items/3089d4e6bc9c8113c581

再度こちらの記事を参考にgemを再インストールしたところ解決しました。
https://qiita.com/taki4227/items/754a2f6ac27595b37dab#comments
$ rbenv exec bundle install --path vendor/bundle
AOPが不要だと考える理由

AOP(ライブラリによるProxy生成型)が不要だと考える理由を書いてみます。

# AOPの用途

AOPの用途といった場合、以下のようなものが挙げられると思います。

* ログ出力
* トランザクション処理
* 例外処理
* 認証処理

以下、それぞれのケースに対して、なぜAOPが不要だと考えるのかを記述します。

# 一般的にAOPの利用を想定するケース

## ログ出力

アプリケーションのログとは定型なパターンで出力するものではなく、アプリケーションの意味ある単位で固有の情報(例えばログインに成功/失敗した等)を出力するものです。
AOPによる定型的な出力では、出力タイミングと出力する情報の観点でこのニーズに対応できません。

なお、ログではなくメトリクスについては後述します。

## トランザクション処理

トランザクション制御をAOPで行う場合、メソッド単位でのトランザクションスコープの制御になります。
単純なケースではこれでも問題ないかもしれませんが、処理順序やスコープの範囲に工夫が必要なケースではこれでは融通が利きません。

リソースのスコープ管理は、Loanパターン等で明示的に行う方が融通が利きます。

記述の簡略化という観点では、メソッドにAOP用の属性を定義するのと比較して、ヘルパーや言語のイディオムを使ったLoanパターン等の記述が面倒と言うほどのことはありません。
それよりもリソース管理のスコープ制御に融通が利く方がよほどメリットがあります。

## 例外処理＆認証処理

こういった処理はAOPを使って行うようなものではありません。
本当に妥当な前後処理であれば、それはランタイムのグローバルハンドラを使ったり、フレームワークのフィルタ機構や拡張ポイントを使って行うべきものです。

昔のフレームワークでは拡張ポイントが不十分でAOPにより無理矢理拡張ポイントを作ってこれらの処理を行っていたケースもありますが、今のフレームワークが対応していないとしたら、それのフレームワークが(検閲削除)なだけです。

# その他のケース

## 黒魔術用途

RESTクライアントやDataAccessor等、interfaceのコントラクトから実装を生成するタイプのライブラリがあります。
これらについてもAOPに含めて話をする場合がありますが、それらはAOPとは別物として扱うべきだと考えます。

## メトリクス

「ログ」ではなく「メトリクス」の出力については、唯一AOPの使用が妥当だと考え得るケースになります。

「ログ」はアプリケーションの意味ある単位で意味のある情報を出力するため非定型なものですが、「メトリクス」については定型的に出力した情報の集計結果から意味を見いだすものなので、AOPによる定型的な出力という対応が妥当な判断となりえます。

# うさメモ

っというわけで「基本的にAOPは不要」っというのがワイの考えじゃ( ˙ω˙)
OMC Log Analyticsの設定方法と使い方 - Linux編 -

Oracle Management CloudのLog Analyticsは、OSやMiddleware,Databaseなどの様々なログを集約して横断的に分析することができるサービスです。
ここでは、実際にLinuxの代表的なログの取得するための設定手順、基本的な分析手法について紹介します。

- 左上のメニューアイコンからログアナリティクス-> ログ管理 -> エンティティを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/f06d237f-a11e-def7-feb0-2314b346d1a5.png)

- 新規アソシエーションをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/266b56e4-bd4a-6d56-ee6b-7c790953dfde.png)

- エンティティタイプをHost(Linux)に選択してエンティティの追加をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/2deddae7-3a49-cd65-c533-e035a8af138d.png)

- エンティティ登録したHostが選択可能になっているのでチェックして選択をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/19ec8ed8-5d8e-412d-fe80-6c0a39406a83.png)

- 続行を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/7d6007d8-7325-3aa3-4548-5da56a84f140.png)

- Linux Secure LogsとLinux SysLogs Logsを選択して一番下の続行ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/21c0efe7-bdbc-5eb5-c4e1-b9d6581f9679.png)

- エンティティの関連付けをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/01710e8e-60f7-540f-bd4b-5d7fd0f17ec6.png)

- これでCloud AgentがOSの２つのログファイルを収集する設定が完了 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/c9e8cdf8-2b1e-a57b-2386-df6efca1533c.png)

- Cloud Agentをインストールしたopcユーザは/var/logディレクトリのログファイルへのアクセス権限がないので、以下コマンドで参照権限を付与する

```
$ sudo setfacl -m u:opc:r /var/log/messages*
$ sudo setfacl -m u:opc:r /var/log/secure*
```
- Log Analyticsの画面にSyslogとSecureLogが表示されたら設定はOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/3abfc121-6fde-48be-34a6-92e9edb91163.png)

##ログ・エクスプローラを使ってみる
Lableのフィールドをグループ化基準にドラッグ&ドロップ。右側の円グラフがラベリングされたログのタイプでグループ化される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/1cc14b04-2869-4e18-bcd8-24cd4b925fff.png)

- ビジュアライゼーションからヒストグラム付きレコード選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/7fb78233-d589-225b-3316-f5e461875af7.png)

- 時系列でのログの出力状況
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/b09387cd-4dcb-c7ea-7435-6e9787e3e36e.png)

- ビジュアライゼーションからクラスタを選択するとログがクラスタリング(分類化)される。
  潜在的に問題のあるレコードやまれにしか発生しないレコードなど対象レコードの特定が簡単になる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/5a2b8abe-db3a-8e6d-c543-3b31944e3991.png)

Cloud Agentは定期的に更新分のログレコードをOMCに送信し、ログデータは常に最新に近しい状態になります。今回はLinuxの基本的なログを取り込む設定をしましたが、これ以外にもLog Analyticsには予め用意されたログ・パーサーが準備されています。

対応可能な[ログパーサーの一覧](https://docs.oracle.com/cd/E83857_01/paas/management-cloud/logcs/box-log-sources.html)


ここにない独自のログフォーマットの場合は、カスタムパーサーを自分で作成することで同様にログを取り込んで分析可能です。下記に、手動でのログ取り込みの方法やカスタムパーサーについて紹介しています。

Oracle Management Cloud関連の情報は[こちら](https://qiita.com/western24/items/1e44bfcaa77f3251a263)
Gitコマンド備忘録

# Gitコマンド備忘録

gitのコマンド忘れては調べての繰り返しでいい加減めんどい。
ここに調べに来る~~←覚えろよ~~

## git config系

ここの値はグローバルとローカルに設定ができます。

```
git config --global [プロパティ名] "[設定する値]"
```

```
git config [プロパティ名] "[設定する値]"
```

ローカルで設定しない場合、グローバルの設定が自動的に反映されるので個人的な情報を記載する場合は注意が必要です

### 名前

```
git config user.name "hogehoge"
```

### メール

```
git config user.email "hogehoge@gmail.com"
```

## 開発前

### リモートリポジトリ取得

```
git clone [URL]
```

## ミスった系

### addの取り消し

```
git reset HEAD^
```
ステージング状態を戻すイメージが正確

### commit後メッセージ修正

```
git commit --amend -m "メッセージ"
```
上記の場合だとメッセージのみ変更してcommitしなおす
`-m`はコメントつけるよーってやつ

##作業中

### 変更内容を同期したい

```
git pull (ブランチ名)
```
リモートのmasterとローカルのmasterの同期はブランチ名(master)いらない
~~空気を読んでくれて日本人みたい~~

### ブランチ切り替えたい

```
git checkout (ブランチ名)
```
マスターで作業しちゃダメ!!めっちゃ怒られるから!

### 新規作成・編集したファイルを確認
```
git status -w
```
現在のディレクトリからファイルへの相対パスを確認
`-w`つけると空白と改行コードを無視した変更を確認

### ファイル内容をどれくらい変更したか確認
```
git diff --stat -w
```
`+`とか`-`で記述されてるあれね

### 特定ファイルのどこを変更したか確認
```
git diff -- ファイルの相対パス
```
コード単位で変更確認

### 最近のcommitの履歴を見たい
```
git log
```

## gitについて

### バージョン確認

```
git --version
```

### アップデート

```	
git update-git-for-windows
```
AirflowのmetadataStoreDBをGCPのCloudSQLで使う話

# はじめに

Airflowを使ってバッチ処理だったり、CI/CDとかって何かうまいことできないのかなと、
試行錯誤しているこの頃です。
可用性の高い構成を考えた時、一番安くて簡単なのがGCPのCloudSQLに任せてしまうという方法があります。
この時に必要なノウハウについてまとめました。
まぁ、CloudComposer使いなよ。って話なんですが、少しでも安く済ませたいので、
実験してわかったことをまとめたいと思います。

# まずはGCP-CloudSQLにDBインスタンスを作成する

GCPの左側の欄からSQLを選択し、インスタンスを立ち上げます。
<img width="957" alt="SQL選択画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145843/48ee8a38-df2e-219d-6fba-6ef339589d4e.png">

ここでPostgreSQLを選択し、順番にしたがって行けばインスタンスが立ち上がります。

<img width="712" alt="SQL画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145843/94624886-7f5c-b9d4-3fb2-58f4c9ce1e6f.png">

# ユーザを登録&DB作成

Airflowから接続するためにはAirflowの専用DBを作成する必要があります。
ユーザ＞ユーザを作成でpostgreSQLのユーザを作成することができます。
ユーザ名で`airflow`と入力し、passwordにとりあえず`root`と入力しておきましょう。
(外からアクセスされることはありませんので大丈夫です。)
<img width="890" alt="ユーザを登録" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145843/d54b16be-43dc-aea8-59d1-5fba0d97b6cc.png">

またDBも同様に設定しましょう。
データベース＞データベースを作成から作成できます。
名前を`airflow`としましょう。

# 外からのアクセスを許可する

Airflowを立ち上げる管理用のMasterNode(VMインスタンス)に静的アドレスを付与して
CloudSQLに接続できるIPをそれだけに設定します。

静的アドレスを設定するには、
VPCネットワーク＞外部IPアドレス＞静的アドレスを予約
でできます。あとはMasterNodeを指定するだけでOKです。
(静的アドレスは使用先を指定さえしていれば無料で使用可能です)

そのあと、SQL側で当該のIPを許可します。

SQL>接続＞パブリックIP＞ネットワークを追加で、許可するネットワークを追加できます。
名前と予約できた静的アドレスを入力し、許可します。
これでMasterNodeからPostgreSQLを読むことができます。
(CeleryでWorkerNodeを立てる場合でも同様の手順を踏んで許可してあげてください)

# airflow.cfgをいじる

ひとまずSQLiteで`airflow initdb`までできた状況を想定してます

`airflow.cfg`をいじって接続先DBをSQLiteからPostgreSQLに変更します。

[core]設定の`sql_alchemy_conn`を以下のように書き換えます。

```
sql_alchemy_conn = postgresql://airflow:[password]@[DBインスタンスIP]/airflow
```

このあと`airflow initdb`を再度行い、成功すれば大丈夫です。
あとは勝手にairflowデータベースにmetadataを貯めていってくれます。

# さいごに

実はこの方法でなくても接続する方法はあったりするかもしれません。
まぁでもわかりやすいのはこちらだと思うので、こちらを選択しました。

これからもAirflow関連記事をメモ書きとしてQiitaに投稿していきます。
よろしくお願いいたします。
OpenCV で保存する時にエラーが出た

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

#問題発生
　OpenCVを使い始めたばかりの頃、

```python
#ファイル読み込み
img = cv2.imread('./img.jpg')

###処理###

#ファイル出力
cv2.imwrite('./output', img)
```

　とすると、ファイル出力時に以下のエラーが出ました。

```
cv2.error: OpenCV(4.1.1) C:\projects\opencv-python\opencv\modules\imgcodecs\src\
loadsave.cpp:662: error: (-2:Unspecified error) could not find a writer for the
specified extension in function 'cv::imwrite_'
```

#解決
　出力時に拡張子を付け忘れていたのが原因だったようです。

```
#ファイル出力
cv2.imwrite('./output.jpg', img)
```

　と、拡張子を付けると無事出力できました。

　ちなみに、出力は以下の形式に対応しているようです。

```
jpg, jpeg, jpe, jp2, png, webp, bmp, pbm, pgm, ppm, 
pxm, pnm,  sr, ras, tiff, tif, exr, hdr, pic, dib 
```

#おわりに
　気づいてしまえば笑ってしまうような問題でしたが、発生した時はけっこう悩みました。
　特に簡単な見落としこそ無くせるように精進していきたいです。

　ご覧いただきありがとうございました。

#参考URL
http://blog.livedoor.jp/airyglyph0000/archives/3969423.html
http://lang.sist.chukyo-u.ac.jp/classes/OpenCV/py_tutorials/py_gui/py_image_display/py_image_display.html
SHT30を使ってみた

スイスのセンサーメーカーのSensirionのSHT30なモジュルが手に入ったのでmruby on YABM(BCM/mips)で使ってみました。

![写真（2020-01-06 18.53）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/03ecdde7-73f2-8fd8-25bc-749553d018d8.jpeg)

このチップは単発測定と周期的連続測定ができます。以下は単発測定で気温と湿度を取得しています。

```ruby
SHTADDR = 0x44

class SHT3x
  def init yabm
    @y = yabm
  end
  def chkcrc dat
    crc8 = 0xff
    for i in 0..1 do
      crc8 = crc8 ^ dat[i]
      8.times {
        if crc8 & 0x80 == 0x80 then
          crc8 = crc8 << 1
          crc8 = crc8 ^ 0x31
        else
          crc8 = crc8 << 1
        end
      }
    end
    if (crc8 & 0xff) == dat[2] then
      return true
    else
      return false
    end
  end
  def getStatus
    @y.i2cwrite(SHTADDR, 0xf3, 0x2d)
    delay(@y, 100)
    arr = @y.i2creads(SHTADDR, 3)
    return (arr[0] << 8) | arr[1]
  end
  def getCelsiusAndHumidity
    while @y.i2cchk(SHTADDR) == 0 do
      delay(@y, 1)
    end
    @y.i2cwrite(SHTADDR, 0x24, 0x00)
    delay(@y, 500)
    while 1 do
      arr = @y.i2creads(SHTADDR, 6)
      if arr then
        break
      end
      delay(@y, 1)
    end
    t = -4500 + 17500 * ((arr[0] << 8) | arr[1]) / 65535
    h = 10000 * ((arr[3] << 8) | arr[4]) / 65535
    return t, h
  end
end
```

mruby on YABMではfloatが使えないので、整数で計算しています。100倍で計算して小数点以下2桁を計算しています。温度の計算式を[mathcha.io](https://www.mathcha.io/)で書いてみました。

![math-20200111-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/07c1ab5b-39b5-ab23-2c53-cbec06dad117.png)
![math-20200111-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/061bede6-7bde-50a3-85bd-b56c7bf56df8.png)
![math-20200111-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/ff0b2de7-5f19-961d-bfa6-8c6372fa5f69.png)
![math-20200112.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/67ae6357-4608-7d6d-cc33-d9e17c8be16e.png)


1000倍にして四捨五入しようとしたらオーバーフローしてダメでした。100倍でも今は寒いのでオーバーフローしないだけかもしれないので、念のために60度(39321)の計算もさせてみましたが、大丈夫でした。これ結構危険ですね。^ ^;

そもそも昔はセンサーなどの組み込みで使われるチップの処理はfloat無しに処理できることが常識でしたが、最近のチップはfloatの計算式がデーターシートにのっていたりします。

小数点で扱うときは文字列にします。pointstrはpが整数値で、cが小数点以下の桁数になり文字列を返します。

```ruby
def pointstr(p, c)
  if p == 0 then
    return "0." + "0" * c
  elsif p.abs < 10 ** c
    l = c - p.abs.to_s.length + 1
    s = p.to_s.insert(p < 0 ? 1 : 0, "0" * l)
    return s.insert(-1 - c, ".")
  else
    return p.to_s.insert(-1 - c, ".")
  end
end
```

chkcrcは計算できることは確認しましたが、使っていません。

crcは大きなデータを処理する場合はテーブルを使った実装が一般的ですが、このチップの場合は2バイトなので素直に計算で良いと思います。

2015年くらいに作られた新しいチップのようで、データの処理が非常に簡潔です。

ThingSpeakにデータを投げて安定度を見たいと思います。

このチップ、なんと日本語のデーターシートが用意されていました。
画像ファイルについてしまった[ ]を取り除く

# はじめに
画像ファイルを複数登録するときに、multipleを使うと簡単に実装できます。
が、（自分の環境だけなのか）保存されるデータに含まれる画像ファイル名に
[ ]がついてしまい、実際に保存されている画像ファイル名を齟齬が生じ
エラーとなる自体が発生していました。
そこで、Model側にこれを取り除くメソッドを追加しましたが、同じような環境で
困っている方はご利用ください
~~最近、某プログラミングスクールではこれの影響なのかmultipleを使わないようにと
御達しが出たようですね。~~

# 前提条件
 ItemモデルはImagesを複数持つアソシエーションが組まれていること

# コード

```ruby:app/models/image.rb
class Image < ApplicationRecord
  belongs_to :item, optional: true
  validates_presence_of :item
  mount_uploaders :image_url, ImageUploader

  def image_path
    return '' if self.image_url[0].try(:file).nil?
    if Rails.env.production?
      self.image_url[0].url.gsub(/%5B%22/, "").gsub(/%22%5D/, "")
    else
      self.image_url[0].file.file.sub(/.*public/,'').sub(/\["/,'').sub(/"\]/,'')
    end 
  end
end
```
今回はS3に画像を保存するようにしており、本番環境とローカルでは指定する画像パスが異なってくるので
production?を使って分岐させています。

# 使い方

```ruby:app/controllers/items_controller.rb
 def show
    @item = Item.find_by(id: params[:id])
    @image_path = @item.images.map{|img| img.image_path}
 end
```
paramsで渡されたidのアイテムを@itemに格納し、@itemのimagesに対して
modelで作成したimage_pathメソッドを実行して[ ]を削除したパスを@image_pathに
格納して使えるようにします。
あとはビュー側でimage_tagに@image_path[n]とすれば格納したパスを
取り出すことができます。@image_pathは配列になっていることに注意です。


# おわりに
細かいことですが、私は最初Controllerに[ ]を取り除く処理を書いていましたが、メンバーが
MVCモデルの法則に則ってModelにメソッドを書き直してくれました。
開発の基準をしっかりと把握していないと他のメンバーに迷惑をかけてしまいますね・・・猛省
Datadogで通常時データが存在しないメトリクスのアラート回復を上手く検知させる方法

通常時データがないメトリクス、例えば、エラーログが出現した場合にアラートを出すなどの場合です。
より正確には検知はできるのですが、アラート回復が上手く検知できなかったので小細工をした記事になります。

## 読む前に

そのうちDatadogがよろしく検知してくれるようになるかもしれないので、この方法は将来使う必要があるかどうかはわかりません。
また、私が知らないだけでもっと良い方法がある可能性があります。
ご存知の方は是非情報をいただければと思います。

## 何をしたいか

とあるソフトウェアモジュールのログで、特定のログが出ている間は動作が不安定になることが分かりました。
根本対策が少々困難なモジュールで、かつ、発生するのは極稀なため、根本対応をするまでの間は特定のログが出現したらモジュールの再起動をするという運用で急場を凌ぐことにしました。

そこで、Datadogで特定のログをカウントしたメトリクスを作成し、それを元にアラートを出すようにしました。

## 何をしたか

Datadog Logsの `Generate Metrics` を使用して特定ログ出現のメトリクスを作成しました。
その後、作成したメトリクスを元にMonitorを作成しました。

## 何が起きたか

特定ログが出現した場合、上手くアラートが発生しました。
その後モジュールを再起動し、特定ログが出現しなくなりました。
しかし、アラートが回復しませんでした。
色々オプションなどを付けてみたり、fillをいじったりしましたが上手く回復を検知できませんでした。

## どう解決したか

普段データが存在しないことがうまく回復を検知できない原因ではないかと推察し、データが存在しないところが `0` になるようにMonitorのメトリクス定義（Define the metric）クエリに小細工を行いました。
具体的には下記のようにしました。

```
メトリクス a: 特定ログのメトリクス
メトリクス b: 常にデータが存在しているメトリクス

Express these queries as: a+(b/b)-1
```

Datadogは賢いので、 `a+(b-b)` とすると、 `a` として勝手にクエリを修正してしまうので、勝手に修正されないような式になっています。
これを行ったところ、回復を上手く検知することができ、無事アラートが回復しました。

`読む前に` でも書きましたが、この方法はちょっとアレがナニなので、もっと良い方法がありましたら教えていだけると助かります。
Python OpenCV (-215:Assertion failed) !_src.empty() エラーについて


#解決方法
ファイルの指定先を絶対パスにする。

```python:readcv.ipynb
'img = cv2.imread(r'C:\Users\ユーザー名\Anaconda3\envs\pytorch04gpu\Lib\site-packages\cv2\data\画像ファイル名.jpg')'
```

#概要
pythonにて画像認識のプログラムを読み込んだ際に
(-215:Assertion failed) !_src.empty() in function 'cv::cvtColor'というエラーが出た。

「Color」と書かれているので色が関係しているのかと思いきや違った

#原因
    img = cv2.imread('画像ファイル名.jpg')

ファイルのパス指定が出来ておらずファイルを認識していないという意味のエラー
haml-railsでerbファイルをhamlに変換する方法

個人アプリ開発において新しく立ち上げる度に何度も調べてしまうので備忘録として残す。

## 結論
このgemをGemfileに記述

```:Gemfile
gem "haml-rails"
```

bundle installを実行

```:ターミナル
$ bundle install #bundle でも可
```

下記コマンドを実行し、erbファイルをhamlに変換。

```:ターミナル
$ rails haml:erb2haml
```

元のerbファイルを削除するかどうかを聞かれる。不要な場合はyを選択。

```:ターミナル
Would you like to delete the original .erb files? (This is not recommended unless you are under version control.) (y/n)
y
Deleting original .erb files.
--------------------------------------------------------------------------------
Task complete!
No .erb files found. Task will now exit.
```


## hamlで開発を行う事の利点とは
hamlはdivタグ自体を書く必要がなく、また各タグを閉じる必要もない為、コード量の削減、簡略化ができる。rubyも使用可。
インデントによる管理である事から、誰が書いても似たような構造になり、可読性が高い。
逆にインデントが少しでもずれるとすぐエラーを吐くため慣れるまでが大変。

rails newを叩く際にデフォルトで生成されるerbファイルはhtmlとほとんど同じ記述で書けて且つ、rubyも実行できる。
ただhamlと違いタグ1つ1つに対しての閉じタグが必要になる為、コードが冗長になりやすい。
学習し始めのうちは視覚的に理解しやすいので使うのも有り。

## まとめ

爆速で開発を行いたいのであれば時間が掛かっても少しずつhamlに慣れていくのが良いであろう。
似たような書き方でslimというのもあるが、基本的な書き方はhamlと変わらず、2020年1月現在ではhamlの方が若干使用比率が高いようなので、現場に合わせ必要に応じて学ぶと良いのではないだろうか。
Laravel 6-Passport APIの主キーとしてのUUID

### Laravel 6 - UUID as Primary Key for Passport API



**チュートリアルを続けたくない場合は、このチュートリアルと同じ機能を備えたhttps://github.com/JamesHemery/laravel-uuidをいつでも使用できます**

**If you don´t want to follow the tutorial, you can always use https://github.com/JamesHemery/laravel-uuid which has the same functionality as this tutorial**

laravelをインストールする

Install laravel

ユーザーテーブルの移行の変更

modify users table migration

```
$table->uuid('id')->primary();
```

パスポートをインストールする

Install Passport

移行を実行する

run migrations

composer laravel / dbalをインストールします

composer Install laravel/dbal

テーブルを変更する新しい移行を作成する

create a new migration to change table

```
Schema::table("oauth_access_token",function (Blueprint $table){
            $table->string("user_id")->change();
        });
```

移行を再度実行します

run migrations again

ユーザーモデル内に、以下を追加します

Inside the User Model, add the following

```
use Illuminate\Support\Str;


class User extends Authenticatable
{
    use HasApiTokens, Notifiable;

    public $incrementing = false;  //No more autoincrement field

    protected static function boot()
    {
        parent::boot(); // TODO: Change the autogenerated stub
		//Generate a new UUID when creating a new registry
        self::creating(function ($model){
            $model->id = (string) Str::uuid();
        });
    }
    ....
}
```

この部分を他のモデルで再利用可能にしたい場合は、特性を作成できます

If you want to make this part reusable for other models, you can create a Trait

`app \ Traits \ HasUuid.php`にファイルを作成します

create a file in `app\Traits\HasUuid.php`

```
<?php
namespace App\Traits;

use Illuminate\Support\Str;

trait HasUuid{

    public function getIncrementing()
    {
        return false;
    }

    protected static function boot()
    {
        parent::boot(); // TODO: Change the autogenerated stub

        self::creating(function ($model){
            $model->id = (string) Str::uuid();
        });
    }

}
```

モデルでは、「HasApiToken」の横に新しい特性「HasUuid」を追加できます

In the model, next to `HasApiToken` you can add the new trait `HasUuid`

```
class User extends Authenticatable
{
    use HasApiTokens, Notifiable, SoftDeletes, HasUuid;
    ....
```

残りは、APIの作成方法に関する以前のチュートリアルに従うことができます

The rest you can follow my previous tutorials on how to create an API
SQLでよく使う構文

#SQLの記載方法
- 値や文字列はシングルクオーテーションかダブルクオーテーションで囲う。どちらを使ってよいが、比較的シングルクオテーションを使われているケースが多い。
- テーブル名やカラム名、フィールド名はバッククオテーションで囲う（[バッククオテーションは必須ではない](https://php1st.com/1184)）



#SQLの基本
```SQL
SELECT 抽出したい列名 FROM テーブル名 WHERE 検索条件
```

#表示

```SQL
-- 1行の全列の値を表示（contentsテーブルのIDが10のレコードの全列を表示）
SELECT * FROM contents WHERE id = 10
```

#更新

```SQL
-- 行と列を指定して項目の値を更新（contentsテーブルのIDが10のレコードのflagを1に変更）
UPDATE contents SET flag = 1 WHERE id = 10
```

# 削除

```SQL
-- 抽出した行を削除（contentsテーブルのitem1の行を削除）
DELETE FROM contents WHERE name = 'item1'

-- 全行削除（contentsテーブルの全行を削除）
DELETE FROM contents

-- 抽出した列を削除（contentsテーブルのnameの列を削除）
ALTER TABLE `contents` DROP COLUMN `name`
```
【随時更新】shaderでよく使う計算

自分用にまとめてます
思いついたら更新していく


# よく使う計算


## テクスチャカラーの値から小数点第一位のみ取得

テクスチャカラーの値なので 0 ~ 1 の幅という想定

```
float color.r = TextureColor.r;
color.r = floor(color.r * 10) / 10;
```
一度10倍してから整数のみを返すfloor関数を呼び出す
その後、10で割る
ゴリ押しなのでもっといい方法を知りたい



## 「0 ~ 1」 → 「-1 ~ 1」 に変換

```
x = y * 2 - 1
```

- y = 0 の時 
   - 0 * 2 - 1 = -1
- y = 0.5の時
   - 0.5 * 2 - 1 = 0
- y = 1の時
   - 1 * 2 - 1 = 1

他の値でも同じように置換したい場合は
x = y * 2 - yの最大値
と考える


## 「-1 ~ 1」 → 「0 ~ 1」に変換

```
x = y * 0.5 + 0.5
```

- y = -1の時
   - -1 * 0.5 + 0.5 = 0
- y = 0 の時 
   - 0 * 0.5 + 0.5 = 0.5
- y = 1の時
   - 1 * 0.5 + 0.5 = 1

他の値でも同じように置換したい場合は
x = y * 0.5 + (yの最大値 * 0.5)
と考える


## 「 1 」に変換

```
x = y * 0 + 1.0f
```

全てのカラーを白にしたい場合


## 「 0 」に変換

```
x = y * 0
```

カラーを黒にしたい場合


## 頂点から入力されたUV座標を 「移動」 「拡大縮小」 する

```
uv = float2(
  (inputUV.x - uvPosition.x) * 0.5f / uvSize + 0.5f,
  (inputUV.y - uvPosition.y) * 0.5f / uvSize + 0.5f
);
```


## 色の平均値を求める

ただの平均の求め方
平均を求めてくれる関数があった気がするけど思い出せない

```
averageColor = (R + B + G) / 3
```


## Flip処理

```
uv.x = abs(input.uv.x * 2 - 1);
```

UV座標を -1 ~ 1 に変換して絶対値を求める
するとUV座標が 1 ~ 0 ~ 1 に変換されていく


## テクスチャの着色

```
fixed lum = Luminance(outColor.rgb); 
outColor.rgb = lerp(_BlackColor.rgb, _WhiteColor.rgb, lum);
```

lumはグレースケール化しているだけなので
以下の計算方法でも同じカラーを取得できる

```
outColor.rgb = dot(outColor.rgb, fixed3(0.3, 0.6, 0.1));
```


# よく使う関数


## abs

絶対値を返す
割と使いやすい

```
y = abs(x)
```

## sqrt

平方根を返す
極座標計算などで使える

```
y = sqrt(x)
```


## sin

sin波を返す
cosの方が使いやすい

```
y = sin(x)
```


## cos

cos波を返す
アルファフェードはこっちの方が使いやすい

```
y = cos(x)
```


## wrapのrepeatを使わずにrepatする

入力された値に対して 1.0 で割った結果のうりあまりを返す

```
uv = frac(uv);
```



## wrapのrepeatを使わずにrepatしながら間隔を一定に開けたい

x = 入れたい値
fmodでxの値で割ったあまりを返してくれる

```
uv = fmod(uv, x);
```



# ブレンドモード

## 加算

```
OutColor = A + B
```


## 減算

```
OutColor = A - B
```


## 乗算

```
OutColor = A * B
```


## スクリーン

```
OutColor = 1 - ((1 - A) * ( 1 - B))
```


## マスク画像を元にAとBの画像をブレンド

```
OutColor = lerp(A, B, Mask);
```


## マスク画像の特定のカラーチャンネルのみにスクリーン合成をベースに画像を合成

```
OutColor = lerp(A, 1 - ((1 - A) * ( 1 - B)), maskChannel)
```


# アニメーション


## uvスクロール

```
uv.x += _Time.y * uvScroll.x * uvVector.x
uv.y += _Time.y * uvScroll.y * uvVector.y
```

## 波形を利用したフェードインフェードアウト

sin波かcos波を利用してフェードアニメーションを行う
sin波だと0スタートの[-1 ~ 1]
cos波だと1スタートの[-1 ~ 1]
y = x * 0.5f + 0.5f の計算式を利用して[0 ~ 1]に変換する

```
alpha *= cos(_Time.y * fadeTime) * 0.5f + 0.5f
```


# 色

## 簡易的にグラデーションをつくる

右へのグラデーション

```
color.rgb = uv.x;
```

左へのグラデーション

```
color.rgb = 1 - uv.x;
```

上へのグラデーション

```
color.rgb = uv.y;
```

下へのグラデーション

```
color.rgb = 1 - uv.y;
```
[Bootstrap]グリッド内で画像を中央寄せする方法

#結論

「img」に「class="mx-auto d-block"」を付与する。

```
<div class="row">
  <div class="col">
    <img class="mx-auto d-block" src="×××">
  </div>
</div>
```

#画面(before)

グリッドシステムで1つのrow内で真ん中に空白を作り左右のグリッド内で画像を表示させています。
グリッドに対して画像が左寄せになるので、これを中央寄せにします。

![miggiyose.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561934/0dcb94ab-4525-b5a8-c900-78ab23c85c7b.png)


#画面(after)

![migi-ok.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561934/093dac3c-7218-305a-345c-7c573e063378.png)
STOPPEDになってから1時間以上経過したECSタスクの起動ログを確認する

# TL;DR
CloudTrailイベント履歴から、RunTask APIの実行結果を参照します。

# 概要

ECSのコンソールで確認できるECSのタスク実行結果は、1時間以内のものに限られています
（それ以上昔の実行結果の表示は保証されない）  
夜間のバッチ処理が失敗していたときなど、すぐに気がつけなかったときは困ります。CloudTrailから証跡を確認しましょう。

# 手順

基本的にCluodTrailの公式ドキュメントに沿う形で進めます。  
https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/view-cloudtrail-events-console.html

1. CloudTrailのコンソールを開きます。  
https://ap-northeast-1.console.aws.amazon.com/cloudtrail/home

2. イベント名 `RunTask` で絞り込みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96286/fad4e8af-ed86-b0fa-c0e9-b3a0afba7e09.png)

3. 目当てのイベントを見つけたら `イベントの表示` でAPIの実行結果を参照します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96286/b899925b-4adf-9ffe-f98d-70882b354cd9.png)

以上です。
VSCodeで自作モジュールimport時のエラー表示(unresolved import 'hoge')が消えない

## はじめに
VSCodeでの開発時(Python3)、実行ファイルと同階層に配置している自作モジュールのimportエラーがどうしても解消できず、地味～にハマったので対策を共有。結論を先に書くと、単なるオートコンプリートの設定漏れでした。。。

## 環境設定
- Windows10(64bit)
- Visual Studio Code 1.41.1
- Python 3.7.3(64bit)

## 発生事象
- 実行ファイルと同階層に配置した自作クラスをimport時、「unresolved import」エラーが消えない
- 表示上はエラーが出ているが、プログラムを実行すると問題なく動作する
![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285378/0e4a9018-a3e1-cb47-776d-381099637cb7.png)

## 対策
ワークスペースの設定(settings.json)に「python.autoComplete.extraPaths」を追加、
自作モジュールがあるフォルダのPathを記述すればOK。今回の例は以下のとおり。

```settings.json
{
    "python.autoComplete.extraPaths": ["./src/get_tweet_data"]
}
```

## 参考記事

- [VSCodeでなぜか「unresolved import」が出る時の対処法|趣味グラマのブログ](https://blog.mrym.tv/2019/08/vscode-python-unresolved-import/)
- [Visual Studio CodeのPython開発環境でオートコンプリートを有効化する|MIRAIUM](https://miraium.com/python-with-vscode/)
- [Enable python intellisense for Visual Studio Code.|Qiita](https://qiita.com/null_Y_K/items/b208a0049d1acd4a3ead)