OmniAICreator/Qiita-1.07M huggingface dataset:
Markdown を数式対応した GitHub 風のデザインの PDF に変換する

# 概要
Markdown ファイルを vscode の拡張機能 `Markdown PDF` で pdf や html に変換できるが，以下の問題点がある．本記事ではこれらを解決する方法を紹介する（先人たちの記事の内容をまとめただけです）．

* 数式が使えない（ \$ で囲った文字列）
* デザインが気に入らない（GitHub に近づけたい）

# 数式に対応
参考：[VSCode の Markdown で数式を表示して PDF 化する - Qiita](https://qiita.com/1gy/items/5b1f3c772b6da43cc13e)
1. vscode の拡張機能である `Markdown+Math` と `Markdown PDF` をインストール
2. `Ctrl + Shift + P` でコマンドパレットを開いて `Extensions: Open Extensions Folder` を入力して拡張機能フォルダを開く
3. `markdown-pdf-x.x.x/template/template.html` を次のように変更する（私の環境で一番上のディレクトリ名は `yzane.markdown-pdf-1.4.4` だった）


```html:markdown-pdf-x.x.x/template/template.html
<!DOCTYPE html>
<html>
<head>
<title>{{{title}}}</title>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
{{{style}}}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/katex.min.css" integrity="sha384-9eLZqc9ds8eNjO3TmqPeYcDj8n+Qfa4nuSiGYa6DjLNcv9BtN69ZIulL9+8CqC9Y" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/katex.min.js" integrity="sha384-K3vbOmF2BtaVai+Qk37uypf7VrgBubhQreNQe9aGsz9lB63dIFiQVlJbr92dw2Lx" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/contrib/auto-render.min.js" integrity="sha384-kmZOZB5ObwgQnS/DuDg6TScgOiWWBiVt0plIRkZCmE6rDZGrEOQeHM5PcHi+nyqe" crossorigin="anonymous"></script>
<script>
  document.addEventListener("DOMContentLoaded", () => {
    renderMathInElement(document.body, {
      delimiters: [
        { left: "$$", right: "$$", display: true },
        { left: "$", right: "$", display: false },
      ]
    });
  });
</script>
</head>
<body>
{{{content}}}
</body>
</html>
```

# GitHub 風にする
参考：[MarkdownをGitHub風のPDFに変換する - Qiita](https://qiita.com/tkms0106/items/37c17c1a559611266d03)
1. vscode の拡張機能である `Markdown PDF` をインストール
2. [このリポジトリ](https://github.com/sindresorhus/github-markdown-css)から `github-markdown.css` をダウンロードする
3. 2 でダウンロードした CSS ファイルで `.markdown-` をすべて空文字に置換する
4. `Ctrl + ,` で設定を開いて `markdown-pdf.styles` と入力し，3 の CSS ファイルのパスを指定する
Gyazoに画像をアップロードするnpmパッケージを作った

一応公式?の[gyazo-api](https://github.com/shokai/node-gyazo-api)パッケージがありますが更新止まってて型定義も無さそうなので自分が使いやすいように[Gyazo API Docs](https://gyazo.com/api/docs)を元にTypeScriptで書き直しました。
あと折角なのでnpmの学習も兼ねてパッケージとして公開しました。

# wrap-gyazo
```
npm i wrap-gyazo
```
+ [リポジトリ](https://github.com/s-n-1-0/wrap-gyazo)


# はじめに
[Gyazo Applications](https://gyazo.com/oauth/applications)でアプリを登録してください。

# ユーザーからの承認(任意)
ユーザーごとのアクセストークンがいらない場合、この項目はスキップしてください。

0 .  [Gyazo Applications](https://gyazo.com/oauth/applications)でclient_id, secret_id,Callback URLを取得します。
1 . 以下のコードで承認用リンクを生成します。

```typescript
import {GyazoAdmin} from 'wrap-gyazo';
const gyazoAdmin = new GyazoAdmin({
  clientId:"***************",
  redirectUri:"***************",
  clientSecret:"***************"
});
const authUrl = gyazoAdmin.makeAuthorizeURL();
/**
 * authUrl = {url:string,state:string}
 */
```

CSRF対策としてstateを使うことをGyazo APIは推奨しています。
stateの生成にはuuidv4を使用しています。

2. (2) ユーザーに生成したリンクをクリックさせます。
    1. Callback URLのクエリパラメータに"code"と"state"が渡されるので取得します。
    2. stateが生成したものと一致するか確認します。
    3. 以下のコードでcodeからアクセストークンを取得します。

    ```typescript
    const accessToken =  await gyazoAdmin.getAccessToken(code);
    ```

# アップロード
### 準備
+ 前の項目で取得したユーザー用のアクセストークンか[Gyazo Applications](https://gyazo.com/oauth/applications)にある自分用アクセストークンを用意してください。
+ 画像データを読み込んでおいてください(base64またはBuffer,Blob->base64変換は後述)。

### Gyazoにアップロード
```typescript
//base64
const uploadRes = await gyazoAdmin.uploadBase64(accessToken,base64);
//buffer
const uploadRes = await uploadBuffer(accessToken,imageData,"png")
```
※CORSポリシーで弾かれるのでブラウザから上のコードは実行できません。

### File/Blob->Base64 変換(おまけ、ブラウザのみ)
```typescript
import {readAsDataURL} from 'wrap-gyazo';

const base64 = await readAsDataURL(file);
```

# おわりに
どちらかというとラッパーの実装よりnpmパッケージの作成に手こずりました。
とりあえずできて良かったです。

最後に参考にさせていただいた[Gyazo API Docs](https://gyazo.com/api/docs)と先行パッケージ[gyazo-api](https://github.com/shokai/node-gyazo-api)様、「[npmパッケージ公開の手順](https://qiita.com/ShinKano/items/3e9f7813ff37379dd7ff)」のShinKano様に感謝します。
もし何かあればコメントや直接プルリクエストをお願いします。
Container Engine for Kubernetes (OKE)のLoadBalancerサービスをフレキシブル・シェイプで作成する

# はじめに
[以前、OKEのLoadBalancerサービスの設定を確認した時](https://qiita.com/dingtianhongjie/items/9ff6bf91f1be0824754e)は、特に何もオプションを指定しなかったので、OCIのロードバランサーは帯域が固定の[動的シェイプ](https://speakerdeck.com/ocise/ociji-shu-zi-liao-rodobaransa-gai-yao?slide=12)としてデプロイされていました。

このシェイプは古い仕様のロードバランサーなので、今回は帯域の最小と最大を指定する[「フレキシブル・シェイプ」](https://speakerdeck.com/ocise/ociji-shu-zi-liao-rodobaransa-gai-yao?slide=11)の作成方法を確認したいと思います。

# 環境確認
Kubernetesクラスタ、LoadBalancerのエンドポイントになるPodは事前に作成済みです。

```
$ kubectl get node
NAME          STATUS   ROLES   AGE    VERSION
10.0.10.152   Ready    node    2d1h   v1.21.5
10.0.10.187   Ready    node    2d1h   v1.21.5
10.0.10.253   Ready    node    2d1h   v1.21.5

$ kubectl get pod -L run
NAME    READY   STATUS    RESTARTS   AGE   RUN
nginx   1/1     Running   0          65m   nginx
```

# LoadBalancerのデプロイ
## マニフェスト

フレキシブル・シェイプを指定するには、マニフェストで annotations を指定します。
フレキシブル・シェイプ以外にも指定できる annotations は、[こちら](https://github.com/oracle/oci-cloud-controller-manager/blob/master/docs/load-balancer-annotations.md)に書かれています。

今回用意したマニフェストは以下になります。
マニュアルにもサンプルが書かれていますが、マニュアル通りのマニフェストだとエラーになりました。
「oci-load-balancer-shape-flex-min」と「oci-load-balancer-shape-flex-max」で指定する値はダブルクォーテーション「"」で囲う必要があります。


https://docs.oracle.com/ja-jp/iaas/Content/ContEng/Tasks/contengcreatingloadbalancer.htm#flexible

```flex-lb.yaml
apiVersion: v1
kind: Service
metadata:
  name: flex-nginx-lb
  labels:
    run: nginx
  annotations:
    service.beta.kubernetes.io/oci-load-balancer-shape: "flexible"
    service.beta.kubernetes.io/oci-load-balancer-shape-flex-min: "10"
    service.beta.kubernetes.io/oci-load-balancer-shape-flex-max: "50"
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 80
  selector:
    run: nginx
```

## LoadBalancerのデプロイ

マニフェストをapplyしてLoadBalancerをデプロイします。

```
$ kubectl apply -f flex-lb.yaml 
service/flex-nginx-lb created
```

少し待って、確認します。

```
$ kubectl get svc
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
flex-nginx-lb   LoadBalancer   10.96.251.231   152.70.204.12   80:30990/TCP   95s
```

OCIのコンソールでも確認すると、フレキシブル・シェイプでロードバランサーが作成されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/a6d57fba-0034-2f30-72ef-4584057ecf34.png)

最小帯域幅、最大帯域幅も annotations で指定した値になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/c5af674d-c5df-ea4a-f2db-3e2b5d864a25.png)

## 疎通確認
LoadBalancerの External-IPにアクセスして、疎通を確認します。

```
$ curl 152.70.204.12 |grep nginx!
<title>Welcome to nginx!</title>
<h1>Welcome to nginx!</h1>
```

# 削除
Kubernetes上でLoadBalancerを削除すると、OCIのロードバランサーも削除されます。

```
$ kubectl delete -f flex-lb.yaml 
service "flex-nginx-lb" deleted
```
AtCoder Beginner Contest 013をやった(Java)

AtCoder Beginner Contest 013 をやった。
今年もよろしくおねがいします！
今年は頑張って緑に入りたいです！！まだ茶色にすらいないですが。。。
※C問題のちに追記予定。

##[A](https://atcoder.jp/contests/abc013/tasks/abc013_1)
単純に場合分けをしてあげた。

```Java
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        // Your code here!
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        if(str.contains("A")){
            System.out.println(1);
        } else if(str.contains("B")){
            System.out.println(2);
        } else if(str.contains("C")){
            System.out.println(3);
        } else if(str.contains("D")){
            System.out.println(4);
        } else if(str.contains("E")){
            System.out.println(5);
        }
    }
}
```

##[B](https://atcoder.jp/contests/abc013/tasks/abc013_2)
もうちょっと考えればもっといいロジック浮かびそうだけど、とりあえず小さな方に10を足してあげて差分がどちらのほうが小さいかを判定してあげればよし。

```Java
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        // Your code here!
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int b = sc.nextInt();
        
        int ans = 0;
        int bignum = 0;
        if(a < b){
            ans = b - a;
            bignum = a + 10;
            if(ans <= bignum - b){
                System.out.println(ans);
            } else {
                System.out.println(bignum - b);
            }
        }else if(b < a){
            ans = a - b;
            bignum = b + 10;
            if(ans <= bignum - a){
                System.out.println(ans);
            } else {
                System.out.println(bignum - a);
            }
        }
    }
}
```

いつかC問題もJavaで解きたいな(n回目)。
Vue.jsのv-bindを使ってclass属性を書き換える

##はじめに
v-bindについて学んでいきましょう。

##v-bindとは

v-bindとは要素に含まれる属性を動的に設定・変更することが出来る設定方法です。

##実際に例を見てみましょう

```html:HTML
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <title>Document</title>
</head>

<body>
    <div id="app">
        <h1 v-bind:class="type">表示</h1>
        <!---------------------------------------------------
        ↑<h1 v-bind:class="type">表示</h1>の構文は、
        <h1 :class="type">表示</h1>⇦に省略も可能。
        ---------------------------------------------------->
    </div>
    <style>
        .error {
            color: red;
        }

        .success {
            color: aquamarine;
        }
    </style>
    <script>
        let app = new Vue({
            el: "#app",
            data: {
                type: "success"
            }
        });
    </script>
</body>

</html>
```
##解説

初めに、**el: "#app"**でHTML内のid名appにアクセスしています。

次に、script内の**data: { type: "success" }**と連携している部分を見ていきます。

・　dataの中のtypeは**h1タグ内のv-bind:class="type"**と連携しています。

・　dataの中のsuccessは、style内の**.success**と連携しています。

もっと細かく解説していくと、

**data: { type: "success" }**としていることで今回の場合、
styleタグ内ではで文字の色のみを指定しているので、
**typeというクラスが当たっている文字の色はstyleの中の.successで指定されている色ですよ！**ということを表しているのです。
もし、**"success"**の部分を**"error"**に変更した場合は、文字の色が赤色になります。
また、style内の.successや.errorのcssを色々いじってみると便利さが分かると思います。

## おわり

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

また別の記事でお会いしましょう〜👋
Node.jsからC言語で書いた関数（引数に構造体の配列）を呼ぶ

Node.jsからC言語で書いた関数を呼び出したい。
関数は引数に構造体の配列のポインタを取る。
Node.jsからref-array-napi等を使って呼び出そうにも引数の構造体の配列を上手く渡せなくてsegmentation fault的エラーが出る。
以下のやり方でできたメモ。

参考：https://stackoverflow.com/questions/33110354/nodejs-ffi-create-array-of-struct

```c:C言語のライブラリ側
typedef struct my_handle my_handle;

typedef struct my_xy{
  double x;
  double y;
} my_xy;

my_handle *my_new(const my_xy *data, uint32_t data_count) {
  for (int i = 0; i < data_count; ++i) {
    printf("%f, %f",data[i].x, data[i].y);
  }
  /* 割愛 */
  return NULL;
}
```

これをmylib.so(またはdll)として出力して関数my_newをNode.js側から呼び出したい。
my_newの引数dataは構造体の配列。

そのためには

```js:Node.js側
const ffi = require('ffi-napi');
const ref = require('ref-napi');
const StructType = require('ref-struct-napi');

var my_xy = StructType({
  x: ref.types.double,
  y: ref.types.double,
});

var buf = [];

var v0 = new my_xy;
var v1 = new my_xy;
v0.x=0.1;v0.y=0.2;
v1.x=1.1;v1.y=1.2;

buf.push(v0.ref());
buf.push(v1.ref());

var buf = Buffer.concat(buf);

const mylib = ffi.Library('./mylib.so', {
  'my_new': ['pointer', ['pointer', 'uint32']],
});

var handle = mylib.my_new(buf, 2);

```

Node.jsで実行してみると以下の結果。

```
0.100000, 0.200000, 1.100000 1.200000
```

のはず。

##追記
もっと自然な方法があった…

```js:Node.js側
const ffi = require('ffi-napi');
const ref = require('ref-napi');
const StructType = require('ref-struct-napi');
const ArrayType = require('ref-array-napi');

var my_xy = StructType({
  x: ref.types.double,
  y: ref.types.double,
});
var my_xy_array = ArrayType(my_xy);

var buf = new my_xy_array(2)

var v0 = new my_xy;
var v1 = new my_xy;
v0.x=0.1;v0.y=0.2;
v1.x=1.1;v1.y=1.2;

buf[0] = v0;
buf[1] = v1;

const mylib = ffi.Library('./mylib.so', {
  'my_new': ['pointer', [my_xy_array, 'uint32']],
});

var handle = mylib.my_new(buf, 2);

```
KUSANAGI 8 の yum アップデートでエラーになったときに試す手順

KUSANAGI 8 で久しぶりに yum アップデートしたところ、エラーでうまく動かなかった場合の対応策です。

## 前提

こちらの記事は KUSANAGI **8** 向けの記事です。
KUSANAGI **9** 向けではありません。

確認方法として、

```bash
kusanagi --version
```

を実行して、 `KUSANAGI Version 8.` からはじまるバージョンであれば対象になります。

## 問題の切り分け

### HTTP Error 404 が表示される

下記のようなエラーが発生した場合は、ネットワークの問題です。

```bash
[Errno 14] HTTP Error 404 - Not Found
```

たまにあるのが、アップデートを取得する接続先のサーバーがダウンしているケースです。
これが意外と気が付きにくい。。。
この場合は時間をおいて、再度挑戦してみてください。

いくら時間をおいても上記のエラーが発生する場合には、そもそもサーバーのネットワーク設定が間違っている可能性があるので、curl などで調査するところから始めてください。

### アップデート途中でエラー文字が表示される

下記のようなエラーが発生した場合は、依存するリポジトリを追加指定する必要があります。

```
Error: Package: kusanagi-php7-7.4.21-1.noarch (kusanagi)
           Requires: libonig.so.105()(64bit)

エラー: パッケージ: kusanagi-php7-7.4.25-1.noarch (kusanagi)
           要求: libicudata.so.69()(64bit)
```

このあとのアップデート再挑戦の項目を試してください。

## アップデート再挑戦

### 1. yum アップデート

#### アップデートに失敗したとき再チャレンジするときのコマンド

```bash
yum clean all
yum update kusanagi
yum update --enablerepo=remi,remi-php56
```

#### 長期間（数ヶ月や数年）アップデートしていないようなときのコマンド

1回ではすべて適用できないかもしれないので、何度か試してアップデートがなくなったことを確認してください。

```bash
yum clean all
yum update --enablerepo=remi,remi-php56
```

### 2. サーバー再起動

yum アップデートしただけでは、サーバーで稼働中のサービスにアップデートは反映されません。
アップデートを反映するためにサーバー再起動を行ってください。

yum アップデートで例えば Nginx がアップデートされた場合、Nginx サービスをリスタートする必要があります。
どのサービスをリスタートすればよいかは、アップデートされたモジュールに依存します。
また、一部モジュールは再起動しないといけないものもあります。
手っ取り早くかつ確実なアップデートの適用方法はサーバー再起動です。

上記の切り分けができる方は、下記コマンド例でサービスの再起動も可能です。

```bash
# Nginx 再起動
kusanagi nginx

# PHP7 再起動
kusanagi php7

# 現在有効なサービスを再起動
kusanagi restart
```

## ※注意

アップデート作業により不具合が起きても責任は取れませんのであしからず。
万が一元に戻せるようきちんとバックアップを取って作業しましょう。

## 参考

KUSANAGI 8 更新情報
https://kusanagi.tokyo/archives/tag/kusanagi8/

KUSANAGI 8 FAQ
https://kusanagi.tokyo/faq/

KUSANAGI 8 コマンド
https://kusanagi.tokyo/document/command/
年末年始にTV見ながらTwitter眺めてた時に、いちいちリロードするのめんどいのでChrome拡張作ってみた

年末年始ひまだったのでずっとTV見ていてTwitterで世間のリアクションも併せて見ていたんですが、Twitterには自動で更新してくれる機能がなく画面リロードするのがめんどくさいのでChrome拡張で勝手に画面リロードするようにしてみました。

# Chrome拡張作成

今回は以下のようなディレクトリ構成で作成します

- chrome-extension-reload
  - manifest.json
  - content.js

マニフェストファイルはTwitterの最新タグを開いてる時だけ動くように`f=live`を指定しています。
matchesの部分を変えればいろんな場面で使えるようになります。

```manifest.json
{
    "name": "Auto Reloader",
    "version": "1.0.0",
    "manifest_version": 2,
    "description": "auto reload per 15 sec.",
    "content_scripts": [
        {
            "matches": [
                "https://twitter.com/*f=live"
            ],
            "js": [
                "content.js"
            ]
        }
    ]
}
```

実際に実行されるJavascriptファイルです。
15秒後にリロードするだけです。

```content.js
(function () {
    setTimeout(() => location.reload(), 15000);
})();
```


# Chrome拡張アップロード

[chrome://extensions/](chrome://extensions/)を開いて、`パッケージ化されていない拡張機能を読み込む`から作成したディレクトリを選択します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/7b8c4c1b-d6a7-3518-3e79-79c997b596b4.png)

　↓こんな感じで自作の拡張機能が追加されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/ce3c5db0-4ec3-03bb-13c8-4606dbabd563.png)


あとはTwitterで最新タブを開くと勝手にリロードされるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/295d10dd-1c3a-2848-d710-e73d7c672920.png)

# 参考

https://developer.chrome.com/docs/extensions/mv3/getstarted/
CSRF対策と書き方

#CSRF対策とは
クロスサイトリクエストフォージェリ（CSRF）とは、Webアプリケーションに存在する脆弱性を利用した攻撃手法です。
例えば、何かECサイトやSNS等でログインをしたまま、別のサイト閲覧を行うと、その閲覧したサイトにアクセスした事で本人の意図しない処理が行われてしまう事があります。そこから個人情報やクレジット等の情報が盗まれるという被害に発展します。

####実際の対策方法
laravelではフォーム作成時にこのCSRF対策を記載していないとエラーが発生します。認証画面時にはCSRF対策は必須という事です。
以下のようなコードを記載する事でlaravelのbladeでは簡単にこのCSRF
CSRF対策が行えます。

```
<form action="" method="post">
@csrf
</form>
```
もしくは

```
<form action="" method="post">
{{ csrf_field() }}
</form>
```


CSRF対策は忘れずに行いましょう！
emacs+eglotでgoplsのロードが重い問題に対処した

単純なのだが、引っかかったためメモとして残す

# 1. 問題

- emacsでLanguage Server Protocolクライアントであるeglotを使用し、Go言語のserverとしてgoplsを使用した
- 設定した状態のemacsで`.go`ファイルを開くと、ものすごく重い 

以下のようなエラーがでてくる

```
Error in menu-bar-update-hook (imenu-update-menubar): (jsonrpc-error "request id=2 failed:" (jsonrpc-error-message . "Timed out"))
```

# 2. 原因
eglotがプロジェクトルートを正しく探すことができていなかった。今回の場合はこのようなメッセージがでていた。

```
[eglot] Connected! Server `gopls' now managing `go-mode' buffers in project `~'.
```

ホームフォルダ直下を全て探しにいっていたため、時間がかかっていた。

# 3. 解決策
プロジェクトルートを設定すればよい。今回の場合はプロジェクトルートがホームディレクトリになっていた。次のページに記述があるように、eglotはproject.elを用いてプロジェクトルートを探しているようだ。

https://glassonion.hatenablog.com/entry/2019/05/11/134135

よって、goファイルがある場所で

```
git init
```
なりをして、gitのファイル構成を作成してしまうのが簡単と思われる。
GCP（Google Cloud Platform）を使いサーバーレスでWEBサービスを作ってみた。

## サービス概要

### プロニチ（プログラミング新聞社）

https://pronichi.com/

定期的にバッチを走らせはてな、Qiita、Twitter、connpassからAPIを通してデータを取得
取得したデータをまとめてWEBサイト・画像にて公開した。

こだわりとしてはCloud Run+BigQueryを利用したサーバーレス構成なところ。完全従量課金にしたので初期のアクセスが少ない場合はほぼ無料でサイトを公開することができる。
データベースにBigQueryを使った理由は更新系はバッチ系以外ない、キャッシュすればデータベース参照する必要がない。従量課金で初期費用がかからずSQL構文が使える点、Pandasで加工したデータを簡単に追加できる点などなど

## システム構成

Python3系

**パッケージ**

（こう見るといろいろ使ってた？

```
google-cloud-bigquery==2.6.2
google-cloud-logging==2.2.0
google-cloud-storage==1.36.0
Flask==1.1.2
Flask-Caching==1.9.0
Jinja2==2.11.2
tweepy==3.10.0
numpy==1.18.4
pyarrow==2.0.0
pandas==1.2.0
python-dotenv==0.15.0
pdfkit==0.6.1
imgkit==1.0.2
wkhtmltopdf==0.2
requests==2.25.1
feedparser==6.0.2
Japanera==0.1.1
Pillow==8.1.0
```

## GCP構成図

**定期的なバッチ実行**

1. Cloud SchedulerからCloud Runを毎時実行
2. 各種APIを実行
3. 実行結果をBigQueryに保存
4. 実行結果をHTML・画像出力しCloud Storageに保存

![プロニチ処理 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59264/d18de935-c24c-4153-e5bf-ba8243f346f7.png)

**WEBサイト閲覧**

1. pronichi.comにアクセス
2. サイト内画像はCloud Storage参照
3. サイト内記事はCloud Runが起動、基本はキャッシュを利用
4. キャッシュが存在しない場合はBigQueryから参照、キャッシュを作成

![プロニチ処理.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59264/29e5eb7d-7017-8c6c-fc1f-1e13b1858073.png)

### まとめ

まとめたんですがAWSに移行予定
データが増えてきてBigQueryの参照に費用が発生しはじめたため。
AWS App RunnerとAmazon Aurora Serverlessを使った構成にするつもり
移行後にまた記事にしたいと思います。
Railsプロジェクトの始め方

#Railsプロジェクトの始め方
##Railsプロジェクトの作成
    rails new プロジェクト名
##データベースの設定
database.yml

    default: &default
        adapter: postgresql
        username: ユーザ名
        password: パスワード
        host: localhost
        database: データベース名

##Vue導入
    rails webpacker:install:vue
マウスをできるだけ使いたくないあなたに捧ぐおすすめサービス3選


本日はタイトルの通り、マウスを極力使いたくないと考える人々におすすめのサービスを3つご紹介したいと思います。
マウスを使うのってちょっとした1動作ですが同じ作業を繰り返す時などになると、その1動作にかかる時間や、押すべき場所をしっかり押そうとするストレスって案外馬鹿にならないですよね。

それでは早速参りましょう。

## この記事を書こうと思った経緯
最近転職をして、仕事でMacを使うようになり、できるだけマウスを使わずに効率的に操作する方法を模索していました。そんな中で見つけたオススメのサービスをシェアしようと思い記事を書きました。


## その1 [Rectangle](https://rectangleapp.com/)
この[Rectangle](https://rectangleapp.com/)はズバリ一言で言うと<strong>「ウィンドウの大きさと位置を簡単に調節できるサービス」</strong>です。

option key ＋ control key　＋(様々なキー)　の組み合わせでウィンドウを大きくしたり小さくしたり(画面の2/3や1/3というサイズのバリエーションがある点に感動)、端っこや中心に寄せたりと様々操作できます。
ディスプレイ間の移動も上記のキーで行えるので外付けディスプレイを用いて作業する方はとても快適に作業できます。
下記がディスプレイ操作キーの一覧になります。
![スクリーンショット 2022-01-01 20.05.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227633/7eb3d739-6d0e-3548-f5d7-f2639f6c62c4.png)

実際に操作する様子がyoutube上に2分ほどの動画で見つかりましたので参考にしていただけますと幸いです。
URL:https://www.youtube.com/watch?v=AaZiA43Jm90


## その2 [Rearrange Tabs](https://chrome.google.com/webstore/detail/rearrange-tabs/ccnnhhnmpoffieppjjkhdakcoejcpbga?hl=ja)

このRearrange Tabsは<strong>ブラウザ上のタブの順序をキーボードだけでスイスイ入れ替えられるサービス</strong>です(Chromeの拡張機能の為Chrome上でしか使えません。）

shift key ＋ control key ＋(← or →)でタブの順序を入れ替えられます。
調べ物をしていたり、調べた内容をスプレッドシートなどに打ち込んだりしている内に、気づいたら大量のタブが並んでしまう事ってありますよね。それを並べ直すのは面倒臭いから新しいうウィンドウを出し続けて、今度はウィンドウだらけという経験がある方もいらっしゃるかと思います。

このサービスを使えば頻繁に行き来するタブ同士を、隣合う様に並べ替えるのがとても楽になりますので、調べ物をする際やweb商談で複数タブを行き来してデモをする際に便利です。

ご参考動画：https://www.youtube.com/watch?v=A1X3geKtF8A


## その3 [Vimium](https://chrome.google.com/webstore/detail/vimium/dbepggeogbaibhgnhhndojpepiihcmeb?hl=ja)
このVimiumは一言で言うとたくさんのショートカット操作が行えるサービスです。(これもChromeの拡張機能なのでChrome上でしか動作しません。)
それらのショートカット操作キーの中でも一番重宝するものを挙げるとするならば、
<strong>webページ内の全てのリンクへのショートカットキーが表示される操作キー</strong>です。
Vimiumを有効にした状態で「f」または「Shift ＋ f」を押すと下記の様にありとあらゆる押下可能なリンクへのショートカットキーが画面上に浮かび上がります。

![スクリーンショット 2022-01-01 20.40.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227633/45787525-e5fa-2da3-6020-3a778243f61e.png)

なんとしてもマウスを使うまいとtabキーを連打してwebページ上のリンクを行き来していた日が懐かしいですね。
ちなみにVimiumはいつでも画面右上のChromeの設定からOFFにできますので、(もちろん上の他のサービスも)慣れるまでON/OFF切り替えたい方はこちらからどうぞ。
![スクリーンショット 2022-01-01 20.54.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227633/0b6b7fe9-2c1e-ab95-df0a-dab223fd96d1.png)



### 終わりに
以上「マウスをできるだけ使いたくないあなたに捧ぐおすすめサービス3選」でした。自分が「やだな。面倒臭いな。もっとこういうこと出来たらな。」と感じるものって、調べてみると案外ソリューションが見つかります。便利サービスを創ってくれた先人達と、雑なワードで検索しても、そんなサービスをいつも教えてくれるgoogleに感謝です。
外部共有ストレージへのマルチパス構成

#1.ストレージへのマルチパス構成
マルチパス構成を行うことで、サーバ側に、[サーバ]-[ストレージ]間の複数の経路を一本の経路として認識させることができます。また、マルチパス構成を組むことでケーブルやモジュールの故障が発生した場合の可用性が担保され、[サーバ]-[ストレージ]間のディスクアクセスを継続することが出来ます。

#2.設定方法
今回はCentOS7上でFiberChannelを使ってマルチパス構成を行います。

まず、device-mapper-multipathがインストールされていることを確認します。

```shell
#インストール確認コマンド
rpm -qa |grep "device-mapper-multipath"
#インストールコマンド
yum install device-mapper-multipath
```

device-mapper-multipathのコンフィグを生成するために以下のコマンドを実行するか、```/usr/share/doc/device-mapper-multipath-X.X.X/multipath.conf```を```/etc/```配下にコピーします

```shell:コマンド実行する場合
mpathconf --enable
```

```shell:コンフィグファイルをコピーする場合
cp /usr/share/doc/device-mapper-multipath-X.X.X/multipath.conf /etc
```

コンフィグファイルの中身を編集し、**devices**内に、各ストレージごとに決まった**device**設定を追加します。`vendor`へメーカー名、`product`に、製品名を設定し、後はデフォルトのパラメータを設定すれば、大体認識するかと思います。
※正しく設定をおこなう場合は各製品のマニュアルを確認しましょう。

また、複数の外部共有ストレージを利用したり、ローカルディスクもマルチパスに追加されてしまう場合は、**blacklist**にwwidを追加し、マルチパスを利用するストレージを制限します。

なお、**defaults**内の`find_multipaths yes`は自動的にマルチパス可能なストレージを見つけてマルチパス構成を組んでくれます。

```shell:multipath.conf
defaults {
	user_friendly_names yes
	find_multipaths yes
}
#ストレージごとにデバイスを追加します。
devices {
	device {
		vendor			"<ベンダー名>"
		product			"<製品名>"
		#ここから ｝までの設定はデフォルトのコンフィグをコピー
		path_grouping_policy    multibus
		path_checker        readsector0
		path_selector       "round-robin 0"
		hardware_handler    "0"
		failback        15
		rr_weight       priorities
		no_path_retry       queue
	}
}
#マルチパス構成を制限するときにwwidを記載し、wwidを持つストレージのみをマルチパスとして構成を組みます。
blacklist {
  wwid <WWIDを記述>
}

```

最後に、サーバを再起動させ、以下を実行し、マルチパス構成が組まれているのか確認します。

``` 
multipath -ll
```

` /dev/mapper/`配下にmpathaが現れています。*df -h*コマンドを実行すると、複数のデバイスがマッピングされていることがわかります。
あとは、`/dev/mapper/mpatha`に*parted*コマンドや*fdisk*コマンドでパーティションを切り、 *pvcreate*コマンドで物理ボリュームを作成するなど、ローカルディスクと同等の設定をしていきます。

#3.参考URL
RHEL(RedHat Enterprise Linux)などのマニュアルを見るとより細かい設定方法が確認できます。

https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/dm_multipath/mpio_setup
【画像処理】Numpyで大津の二値化(判別分析法)

Numpyで画像の二値化を実装してみます。

まず、二値化する画像を読み込み、グレースケール画像に変換します。

```python
original_image = plt.imread(image_name)
if np.issubdtype(original_image.dtype, np.floating):
  original_image = (original_image * 255).astype(np.uint8)
gray_image = (0.2116 * original_image[:,:,0] + 0.7152 * original_image[:,:,1] + 0.0722 * original_image[:,:,2]).astype(np.uint8)
plt.imshow(gray_image, cmap='gray')
```

![GrayImage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/81c1c921-681d-6dbc-ea20-3b7924bd3375.png)

任意の閾値で二値化をする関数を実装してみます。これは`numpy.where`を用いると簡単に実装できます。

```python
def thresholding(image, threshold):
  return np.where(image <= threshold, 0, 255)
  
threshold_image = thresholding(gray_image, 128)
plt.imshow(threshold_image, cmap='gray')
```

![ThresholdImage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/8002840f-26e3-ba88-b45d-e8d6e84888dd.png)

---

次に大津の二値化(判別分析法)を実装してみます。

大津の二値化ではクラス間分散$\sigma_b^2$とクラス内分散$\sigma_w^2$の比である分離度$\frac{\sigma_b^2}{\sigma_w^2}$が最大になる閾値で二値化を行います。

黒画素クラスの平均と分散を$m_1$と$\sigma_1^2$、白画素クラスの平均と分散を$m_2$と$\sigma_2^2$とし、黒画素クラスと白画素クラスの所属する画素数をそれぞれ$\omega_1$、$\omega_2$とすると、クラス間分散$\sigma_b^2$とクラス内分散$\sigma_w^2$はそれぞれ以下のようになります。

```math
\sigma_w^2=\frac{\omega_1\sigma_1^2+\omega_2\sigma_2^2}{\omega_1\omega_2} \\
\sigma_b^2=\frac{\omega_1\omega_2(m_1-m_2)^2}{(\omega_1+\omega_2)^2}
```

全分散$\sigma_t^2$は閾値によらず一定で、クラス間分散$\sigma_b^2$とクラス内分散$\sigma_w^2$と以下のように関係にあります。

```math
\sigma_t^2=\sigma_w^2 + \sigma_b^2
```

このことから分離度$\frac{\sigma_b^2}{\sigma_w^2}$は次のようになり、クラス間分散$\sigma_b^2$が最大のときに分離度$\frac{\sigma_b^2}{\sigma_w^2}$も最大になることがわかります。

```math
\frac{\sigma_b^2}{\sigma_w^2}=\frac{\sigma_b^2}{\sigma_t^2-\sigma_b^2}
```

実装としては、すべての閾値に対してクラス間分散$\sigma_b^2$を計算して、クラス間分散$\sigma_b^2$が最大となるとき閾値で二値化を行います。クラス間分散$\sigma_b^2$の分母は一定なので、実装では計算を省略します。

```python
def otsu_thresholding(image):
  between_class_variance = np.zeros(256)
  for i in range(np.min(image), np.max(image)):
    class1 = image <= i 
    class2 = ~class1
    average1 = np.average(image[class1])
    average2 = np.average(image[class2])
    num1 = np.count_nonzero(class1)
    num2 = np.count_nonzero(class2)
    between_class_variance[i] = (num1 * num2 * (average1 - average2) ** 2)
  threshold = np.argmax(between_class_variance)
  return np.where(image <= threshold, 0, 255)

plt.imshow(otsu_thresholding(gray_image), cmap='gray')
```

![OtsuTresholdImage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/437fe3ab-5788-fc77-f2ad-e7700286eab7.png)

---

実装したコードはGoogle Colaboratoryに置いてあります。

https://colab.research.google.com/drive/1sb4rKCdRmlmdedMyex0MqHHCO3UXxeFM?usp=sharing
【matplotlib】x軸を上下に、y軸を左右に表示する2つの方法

# 概要
matplotlibでグラフのx軸を上下に、y軸を左右に表示する2つの方法を紹介します。Google Colabで作成したコードは、[こちら](https://colab.research.google.com/drive/1nnKZ0DXImdfJKt2TstkNityHk8RAX7Ns?usp=sharing)にあります。


# 方法
1. [twinx](https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.twinx.html#matplotlib-axes-axes-twinx)、[twiny](https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.twiny.html#matplotlib-axes-axes-twiny)を使い表示する方法
1. [secondary_xaxis](https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.secondary_xaxis.html#matplotlib-axes-axes-secondary-xaxis)、[secondary_yaxis](https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.secondary_yaxis.html#matplotlib-axes-axes-secondary-yaxis)を使い表示する方法

:::note warn
注意
matplotlib.axes.Axes.secondary_xaxis、matplotlib.axes.Axes.secondary_yaxisは、matplotlibのversion3.1では、バグがある可能性があります。
バグの事例の1つに、https://github.com/matplotlib/matplotlib/issues/15621があります。
:::


## 1.　twinx、twinyを使い表示する方法
```Python:twinx、twinyを使い表示する方法
import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
ax1 = fig.add_subplot(111)

x = np.arange(0, 5, 0.1)
y = np.sin(x)

# 1軸目
ax1.plot(x, y)
ax1.set_xlabel('x')
ax1.set_ylabel('y')

# 2軸目（twinyを使い、y軸を共通にして同じグラフを書く）
ax2 = ax1.twiny()
ax2.plot(x, y)
ax2.set_xlabel('x')

# 2軸目（twinxを使い、x軸を共通にして同じグラフを書く）
ax3 = ax1.twinx()
ax3.plot(x, y)
ax3.set_ylabel('y')

plt.show()
```
出力結果
![Unknown-40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1599258/4f6cc06b-5aa3-b4d4-1413-c7b9ef23f340.png)


## 2.　secondary_xaxis、secondary_yaxisを使い表示する方法
```Python:secondary_xaxis、secondary_yaxisを使い表示する方法
import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
ax1 = fig.add_subplot(111)

x = np.arange(0, 5, 0.1)
y = np.sin(x)

# 1軸目
ax1.plot(x, y)
ax1.set_xlabel('x')
ax1.set_ylabel('y')

# 2軸目（secondary_xaxisでx軸を上に追加）
ax2 = ax1.secondary_xaxis('top')
ax2.set_xlabel('x')

# 3軸目（secondary_yaxisでy軸を右に追加）
ax3 = ax1.secondary_yaxis('right')
ax3.set_ylabel('y')

plt.show()
```
出力結果
![Unknown-41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1599258/51747936-1173-0005-8a93-aae21f613e19.png)


# 補足
一般的な使い方は、twinx、twinyは、**別々のグラフを表示するとき**に使うと思います。
secondary_xaxis、secondary_yaxisは、**別々の単位をグラフに表示するとき**に使うと思います。また、任意の位置に複数の単位の軸を置くこともできます。詳しくは、私の記事で恐縮ですが、[【matplotlib】 グラフの任意の位置に、複数の単位の軸を表示する方法](https://qiita.com/yusuke_s_yusuke/items/96cd6aba3aaa30b9c3f3)を参照してください。

# まとめ
x軸を上下に、y軸を左右に表示したい場合は、基本的には**secondary_xaxis、secondary_yaxisを使う**と良いと思います。

# 参考資料
* [matplotlib.axes.Axes.twinx](https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.twinx.html#matplotlib-axes-axes-twinx)
* [matplotlib.axes.Axes.twiny](https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.twiny.html#matplotlib-axes-axes-twiny)
* [matplotlib.axes.Axes.secondary_xaxis](https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.secondary_xaxis.html#matplotlib-axes-axes-secondary-xaxis)
* [matplotlib.axes.Axes.secondary_yaxis](https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.secondary_yaxis.html#matplotlib-axes-axes-secondary-yaxis)
【備忘】GKEにAPIをデプロイしてみる【Java】

# GKEにAPIをデプロイする
## 経緯
仕事でJavaで作成したAPIをGKEにデプロイしてくださいと言われた際に、色々やってデプロイしたのでその時の記憶を備忘として載せます。

##　前提
・Mavenプロジェクトで作成したアプリであること(違う場合は都度読み替える必要あり)
・デプロイする対象のワークロードが存在すること
・Cloud SDKのインストールを済ませていて対象のプロジェクトの認証が済んでいること
(参考：https://qiita.com/Quasar9/items/c5c633078ae091328260)
・Dockerのインストールが済んでいること


## デプロイしたいAPI
```java:Sample4Controller.java
@RestController
@RequestMapping("/sample4")
public class Sample4Controller {

	@GetMapping("/hoges")
	public ResponseEntity<SampleResponse> getHogeResponses() {
		SampleResponse response = new SampleResponse();
		
		List<Hoge> hogeList = new ArrayList<>();
		hogeList.add(new Hoge("1", "hoge1", "explanation1"));
		hogeList.add(new Hoge("2", "hoge2", "explanation2"));
		response.setHogeList(hogeList);
		
		return new ResponseEntity<>(response, new HttpHeaders(), HttpStatus.OK);
	}
}
```

```java:SampleResponse.java
@Data
@NoArgsConstructor
public class SampleResponse {
	private List<Hoge> hogeList;
}
```

```java:Hoge.java
@Data
@AllArgsConstructor
public class Hoge {
	private String id;
	private String name;
	private String explanation;
}
```

## GKEへデプロイする方法
次の2つが主な手順となる。
・DockerイメージをContainer Registryに登録する
・Container Registryに登録したイメージをワークロードのデプロイメントに指定する

### DockerイメージをContainer Registryに登録する
今回はJibを使ってDockerイメージを作成する。
使い方としてはpomに下記を追加する。

```xml:pom.xml

			<plugin>
				<groupId>com.google.cloud.tools</groupId>
				<artifactId>jib-maven-plugin</artifactId>
				<version>2.8.0</version>
				<configuration>
					<allowInsecureRegistries>true</allowInsecureRegistries>
					<to>
						<image>asia.gcr.io/project-id/test:tag</image>
					</to>
					<container>
						<environment>
							<TZ>Asia/Tokyo</TZ>
							<LANG>C.UTF-8</LANG>
						</environment>
					</container>
				</configuration>
			</plugin>			
```

下記の部分はContainer Registryのパスを指定する。
また、:の後はイメージのタグを任意の名称でつける。

```xml
<to>
　　<image>asia.gcr.io/project-id/test:tag</image>
</to>
```
:の前の部分は下記画像の赤枠をコピーすればよい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727502/8f80796a-5f60-8270-0f83-ee4a6d61ec2c.png)


Jibの設定をしたら下記のコマンドを実行してイメージの作成&Container RegistryへのPUSHをする。※

```
mvn compile jib:build
```

下記オプションでタイムアウト値も設定できる。

```
-D jib.httpTimeout=80000
```

こんな感じになれば成功
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727502/c34b9c33-ceff-79db-1977-e1584ee0d7ad.png)

Container Registryを見てimageがPUSHされているかを確認する。

※ コマンドを実行した際にエラーがあった場合、認証情報を確認する。
また、下記のコマンドを実行してDockerにContainer RegistryにPUSHするための認証情報を設定する。

```
gcloud auth configure-docker
```

### Container Registryに登録したイメージをワークロードのデプロイメントに指定する
ここまでの手順でContainer Registryにimageの登録が済んでいるので、デプロイ対象のワークロードを選択してデプロイメントにimageを設定して保存する。

```yml
    spec:
      containers:
        image: <imageのpath>:<tag名>
```

変更を保存すれば最新のイメージでワークロードが更新される。

### ロードバランサを作成して公開する
Kubernetes Engine >> ワークロード >> 対象のワークロードを選択 >> 公開タブをクリック >> 任意のPORTを指定してサービスタイプをロードバランサを選択して公開をクリック 

上記で作成されたIPとPORTとAPIで指定したEnd Pointに対してリクエストを送ってレスポンスが返れば成功。

下記はブラウザを直接たたいた例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727502/5835dc5b-578b-a820-c2e1-c44fd826c944.png)
【備忘】Cloud SDKインストール

# Cloud SDK備忘
仕事でCloud SDKを触ってみたので、プライベートPCに入れて使ってみました。

##　Cloud SDK とは
GCPをローカルでコマンドライン操作するためのツールです。
AWS CLIのGCP版だと考えております。

## さっそくInstallしてみる
### 0.環境
Windows10

### 1.インストーラをダウンロード
下記のリンクをたたいてインストーラをダウンロードします。
https://dl.google.com/dl/cloudsdk/channels/rapid/GoogleCloudSDKInstaller.exe?hl=JA

インストーラを実行、デフォルトで進む
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727502/a07e4655-739a-0fe1-6320-026f8d0c5dbd.png)

まあまあ長いです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727502/92cd63c5-81fb-6cb3-716a-38564cb75fd5.png)

インストールに成功するとコマンドプロンプトが立ち上がります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727502/3125404c-1db7-66c1-d0ef-9ac3b857fc28.png)

### 2.コマンドプロンプトで設定
ログインを要求されるのでYを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727502/993e2611-2e64-2b5f-6e41-4ac7ce21b3f9.png)

ログインするアカウントを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727502/d6806ec7-91ed-626e-6f93-e2d0d15e3878.png)

許可します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727502/99a9842b-bb6a-c345-ae46-238e37ac429b.png)

認証成功
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727502/bef56400-ea5a-8cf7-b8cc-ed276d7a48d9.png)

続いてコマンドプロンプトでプロジェクトを選択します。僕は既にプロジェクト作っていたので既存プロジェクトを選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727502/f2c3361f-d955-c86b-8ba7-b9feefce6c63.png)

## おまけ
下記コマンドで認証アカウントを確認できる

```
gcloud config configurations list
```

アカウント切り替えは下記のコマンド

```
gcloud config configurations activate <アカウント名>
```

認証情報の追加する場合は下記のコマンド

```
gcloud auth login
```
amdgpu 21.40 で RDNA2 で HIP(CUDA っぽいの)が動くようになりました(experimental)

## 背景

AMD GPU で GPGPU(CUDA ぽいの)ができる ROCm がいつまで経っても RDNA/RDNA2 対応しておらんかった...

しかし, 最近 Cycles X が AMD HIP で RDNA2 で動かせるようになる(まずは Windows で)という記事があり, HIP 再訪することにしました.
 
https://code.blender.org/2021/11/next-level-support-for-amd-gpus/
https://code.blender.org/2021/04/cycles-x/

(ちなみに buggy OpenCL driver とあるのは AMD のことでしょうね :smiley: )

Linux では, 21.40 でついに対応し始めったっぽい?

https://www.amd.com/en/support/kb/release-notes/rn-amdgpu-unified-linux-21-40-1

admgpu 入れると rocm 関連のパッケージも入ります.

いままでは rocm 用(GPUGPU 用)と, OpenCL/OpenGL などのグラフィックスドライバの SW スタックは別でした.

https://amdgpu-install.readthedocs.io/en/latest/install-overview.html

21.40 から OpenCL あたりも rocr(ROC runtime) で動くようになります(ついでにいうと OpenCL も完全? OSS なスタックとなる).

ROC は Radeon Open Compute の略かしら?

### upgrade

Linux では cuda repo とは異なり, amdgpu-install では(現時点では)アップグレードは対応していません.
amdgpu-uninstall してパッケージをアンインストールしておき, amdgpu-install の deb を再インストールで対応となります.
 
## HIP とは

NVIDIA で言う CUDA みたいなのです(CUDA API 互換のライブラリとかを提供)
内部的には C/C++(LLVM に変換できるコンパイラがあれば rust なども) を GCN/RDNA ISA などで動くようにしていますので, 
特に CUDA API にこだわらなければ, より汎用な C/C++ コードを GPU で動かせると思います. 

いろいろ紆余曲折あったようですが, 最近では binary(fat binary)を comgr/rocr で動くように統一されてきたっぽい.


2020 年後半以降の HIP, HIP clang compiler について
https://qiita.com/syoyo/items/240a1b08cb72f1ea6fbe

最近ではやっと `hipcc` も apt で入る感じになってきました.

## 仕組み

AMD のサイトとかにまともな資料無いっぽいので推定ですが, こんな感じでしょうか...
(VEGA or later)

```
  HIP app   |  OpenCL app とか
            |
    |       |    |
    |/      |    |/
+-----------+-----------+
| hip.bc    |  oclc.bc  |    device library bitcode(`/opt/rocm/amdgcn/bitcode`)    
+-----------------------+  
| rocr/rocclr           |    (common) runtime
+-----------------------+
| amdgpu(former amdkfd) |    kernel driver
+-----------------------+
```

## 動かす.

`amdgpu` ドライバ(最近は apt meta package 形式)を入れているとします.

```
$ sudo apt install roc-dev
```

で hipcc など入れます.

あとはコンパイルするだけです!

`square` サンプルを動かしてみます.

https://github.com/ROCm-Developer-Tools/HIP/tree/develop/samples/0_Intro/square

```
info: running on device AMD Radeon RX 6800
info: allocate host mem (  7.63 MB)
info: allocate device mem (  7.63 MB)
info: copy Host2Device
info: launch 'vector_square' kernel
info: copy Device2Host
info: check result
PASSED!

```

Voila!

これで RDNA2 で Vulkan/OpenGL などでレイトレしたりレンダリングしたり, マイニング(OpenCL)したりしつつ, GPGPU(HIP)もできるようになります!

## pytorch-rocm は...?

残念ながら最新 docker image でも gfx1003 が有効になっていないっぽく seg fault(HIP compile 失敗)しました.
ソースコードから gfx1003 有効にしてビルドすればいけるかもしれません.

しかし, Radeon VII で試したところ, 結局のところ pytorch-rocm は使い物にならないままのようですので(GPU のカーネルコンパイルが激遅 + GPU のほうが遅い),期待しないほうがいいでしょう.
(pytorch CUDA の API や書き方に合わせて無理やり動かしているので, 非効率)

HIP(C/C++) で, 自前で機械学習ライブラリ(MIOpen, ROCblas, ...)を叩いたほうがよさそうです!

## HSA はどうなる?

不明. HIP に統一されていくのでしょうか...

## RT core はどうなる?

ISA 自体はあるっぽいので, うまく叩けば使えるかもしれませんが, OptiX のように簡易に使える API は提供されていません.
とりあえずは Vulkan 経由になるでしょうか(HIP sample に Vulkan interop の例があります)

ただ, RDNA2 の HW raytracing(texture unit)の性能自体そんなに良いわけではないので, 無理して使っても性能でないでしょうから, RDNA3 など次期アーキテクチャに期待でしょうか.

## Intel dGPU はどうなる?

Intel Xe ではどうなるでしょうか. Intel は OpenCL コンパイラをきちんとメンテしている感じがしますが... SYCL とかになるのかな?
puppeteerでポップアップタブがロードし終わるのを待つ

# はじめに
本質的には解決していません。私が利用している範囲ではこれ十分だったので記事にしました。
解決策をご存じの方は是非コメントをお願いします。

# 問題
puppeteerを利用していてリンクをクリックした際にポップアップするタブがロードし終わるまで待ちたいのに待ってくれません。
[スタックオーバーフローの質問](https://stackoverflow.com/questions/50119325/in-puppeteer-how-to-wait-for-pop-up-page-to-finish-loading) に対する2回答を参考に実装しても、前者はロードを待ってくれず、後者は移動先のセレクターを指定しなければいけません(これは使い回し辛い!)

# 解決方法

```js
const [popup] = await Promise.all([
    new Promise((resolve) => page.once('popup', resolve)),
    page.click(selector)
]);

const popup_page = popup as Page;
await popup_page.reload({waitUntil: 'networkidle0'}); // waitUntilはそれぞれでご指定ください
```
【Git】git diffで差分を確認したとき、改行も差分に含まれる！

# はじめに
Git/GitHubについて勉強していたときに、表題の件について知らずに数時間ハマってしまいました。
同じことにハマってしまった人のため + 知識の言語化のため本記事を書きました。

# 起こったこと
```:index.html
<p>sample1</p>
```
上記のファイルをcommitした後、2行目に

```:index.html
<p>sample2</p>
```

を追加した後、git diffで差分を確認したところ、

```:zsh
@@ -1 +1,2 @@
-<p>sample1</p>
\ No newline at end of file
+<p>sample1</p>
+<p>sample2</p>
\ No newline at end of file
```
上記のように表示されました。
「-\<p>sample1\</p>って1行目を削除していないのは何故???」「しかも+\<p>sample1\</p>と、もう一度1行目を書いたことになっている」ということで、いろいろ調べて数時間をつぶしてしまいました。


# 改行も差分に含まれる
そもそも認識が間違っていたのですが、-\<p>sample1\</p>というのは**一行目が削除されたということではなく**、一行目が編集された(=差分がある)という意味でした。
つまり、2行目の\<p>sample2\</p>を追加する際、1行目の終わりで改行を追加したため、1行目も編集したことになっていました。

```:index.html
<p>sample1</p>"改行"
<p>sample2</p>
```

つまり、

```:zsh
@@ -1 +1,2 @@
-<p>sample1</p> #1行目を編集したという意味
\ No newline at end of file
+<p>sample1</p> #1行目に文("改行")を追加
+<p>sample2</p> #2行目に文(<p>sample2</p>)を追加
\ No newline at end of file
```
ということです。

# 改行を差分に入れたくない場合
原因は分かったのですが、1行目は意味的には何も変わらないですし、差分で表示されるのは個人的に違和感を感じます。
対策としては初めから文の最後に改行を入れておけば、行を追加する際も最後の行に改行を入れる必要はなく、差分にも表示されることはありません。

# 参考記事
- [gitにおける改行の扱い](https://teratail.com/questions/234739?link=qa_related_pc)
GitHubについて

※とある駆け出し未熟者エンジニアの備忘録です。
#GitHubとは
gitで管理しているコードをWeb上で保存できるようにするツールです。
チームで開発をする際にメンバー間でコードを共有するのに使われます。

#####主なメリット
①コードの共有。チームで共有したり、世界のエンジニアたちのコードが見れる。
②コードのレビュー。本当に実装できるコードなのか、問題がなければプルリクエストと呼ばれる機能で、自分が変更、追記したコードを開発元のコード(開発者のローカルリポジトリ)に取り込める
③オープンソースソフトウェアに参加。無料でソースコードが公開されていて、誰でも使っていいよというサービス。
#####豆知識
クリス・ワンストランスさんがweb上でコードを共有するツールとして、このGitHubを開発したそうです。

#####他のツール
GitHubと似たツールとして
backlog、gitlab、bitbacket等があります。
Blockly Menu作成(2)

# Blockly Menu作成(2)
前回（[Blockly Menu作成(1)](https://qiita.com/tkhr68000/items/ba6bbdea33f80a886f1b)）に続けて、googleのガイドを参照して作成していこうと思います。
[Google for Education > Blockly > Guides > Get Started](https://developers.google.com/blockly/guides/get-started/web)

# Toolboxのカスタマイズ
Toolboxをカスタマイズしていきます。
[Google for Education > Blockly > Guides > Toolbox ](https://developers.google.com/blockly/guides/configure/web/toolbox)

## XML形式
XML形式での書式に変更します。

```xml
<xml id="toolbox" style="display: none">
  <block type="controls_if"></block>
  <block type="controls_whileUntil"></block>
  <block type="controls_repeat_ext"></block>
  <block type="logic_compare"></block>
  <block type="math_number"></block>
  <block type="math_arithmetic"></block>
  <block type="text"></block>
  <block type="text_print"></block>
</xml>
<script>
  var workspace = Blockly.inject('blocklyDiv',
      {toolbox: document.getElementById('toolbox')});
</script>
```

## Category設定
上記をカテゴリーにまとめた表示にしてみます。

```xml
<xml id="toolbox" style="display: none">
  <category name="Control">
    <block type="controls_if"></block>
    <block type="controls_whileUntil"></block>
    <block type="controls_repeat_ext"></block>
  </category>
  <category name="Logic">
    <block type="logic_compare"></block>
    <block type="math_number"></block>
    <block type="math_arithmetic"></block>
  </category>
  <category name="Text">
    <block type="text"></block>
    <block type="text_print"></block>
  </category>
</xml>
<script>
  var workspace = Blockly.inject('blocklyDiv',
      {toolbox: document.getElementById('toolbox')});
</script>
```


## 変数や関数カテゴリ
組み込み済みの変数や関数カテゴリーも追加します。


```xml
  <category name="Variables" custom="VARIABLE"></category>
  <category name="Functions" custom="PROCEDURE"></category>
```

## まとめ
今までの変更をまとめたHTMLを作成します。

```html:index.html
<!DOCTYPE html>
<html lang="ja">

<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width,initial-scale=1">
	<title>Blockly Sample</title>
	<script src="../blockly/blockly_compressed.js"></script>
	<script src="../blockly/blocks_compressed.js"></script>
	<script src="../blockly/msg/js/en.js"></script>
</head>

<body>
	<p>Blockly toolbox</p>
	<div id="blocklyDiv" style="height: 480px; width: 600px;"></div>
	<xml id="toolbox" style="display: none">
		<category name="Control">
			<block type="controls_if"></block>
			<block type="controls_whileUntil"></block>
			<block type="controls_repeat_ext"></block>
		</category>
		<category name="Logic">
			<block type="logic_compare"></block>
			<block type="math_number"></block>
			<block type="math_arithmetic"></block>
		</category>
		<category name="Text">
			<block type="text"></block>
			<block type="text_print"></block>
		</category>
		<category name="Variables" custom="VARIABLE"></category>
		<category name="Functions" custom="PROCEDURE"></category>
	</xml>
	<script>
		var workspace = Blockly.inject('blocklyDiv',
			{ toolbox: document.getElementById('toolbox') });
	</script>
</body>

</html>
```

toolboxのxml化、カスタマイズまでできるようになりました。
[お正月記事]ActiveRecord::ConnectionNotEstablished: Can't connect to local MySQL server through socket 

##背景

```
docker-compose run backend rails db:migrate
```
をしようとしたところ
[+] Running 1/0
 ⠿ Container renote_mysql_1  Running                                      0.0s
rails aborted!
ActiveRecord::ConnectionNotEstablished: Can't connect to local MySQL server through socket '/run/mysqld/mysqld.sock' (2)
/app/bin/rails:10:in `<top (required)>'
/app/bin/spring:15:in `<top (required)>'
/app/bin/rails:3:in `load'
/app/bin/rails:3:in `<main>'

Caused by:
Mysql2::Error::ConnectionError: Can't connect to local MySQL server through socket '/run/mysqld/mysqld.sock' (2)
/app/bin/rails:10:in `<top (required)>'
/app/bin/spring:15:in `<top (required)>'
/app/bin/rails:3:in `load'
/app/bin/rails:3:in `<main>'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
のエラーが出て入力できず。

##解決

```
mysql -u root -p
```
とかしてmysqlに入れるか、mysqlのstatusはrunningになっているか等の確認をしていたのですが、結論としては.envファイルがありませんでした。

```
git  clone
```
すると最初は.envファイルはなくなり自分で作らないといけないそうです。
.envファイルを作るアプリケーションディレクトリに作り、元の.envファイルの中身をコピペすると解決しました。
最適化数学まとめ(2.2 ニュートン法)

#ニュートン法とは
ニュートン法とは端的に言えば、ある関数を2次近似することで関数を最適化する手法です（ここでは関数の極値を求めるものを扱う）。2次近似とは、ある関数のテイラー展開を2次の項までで表したものです。
今回は１変数のニュートン法について考えます。

##１変数のニュートン法
前提として、1階導関数だけではなく2階導関数も計算できるものとします。
ある関数$f(x)$を$x$軸上の点$\bar{x}$周りの点$\bar{x}+\Delta{x}$でテイラー展開すると以下のようになります。（$\Delta{x}=|x-\bar{x}|$,$x$は求めたい値）

$f(\bar{x}+\Delta{x})=f(\bar{x})+f'(\bar{x})\Delta{x}+\frac{1}{2}f''(\bar{x})\Delta{x^2}+\ldots\ldots(1)$

$\ldots$以降は３次以上の項であり、$\Delta{x}$が小さい場合に急速に小さくなるため、３次以降の項は無視します。
(1)の2次までの項の極値を求めるために、$\Delta{x}$で微分して$0$と置くと以下のようになります。

$f'(\bar{x})+f''(\bar{x})\Delta{x}=0\ldots(2)$

(2)を$\Delta{x}$について解くと、$\Delta{x} = -\frac{f'(\bar{x})}{f''(\bar{x})}\ldots(3)$
となります。
(3)より、解$x$の近似値は$x=\bar{x}-\frac{f'(\bar{x})}{f''(\bar{x})}\ldots(4)$
となります。
解$x$の近似値が一定の範囲に収束するまで(4)を反復する方法をニュートン法と呼びます。
反復計算をいつ止めるかについては、以下を参照してください。
[いつ反復計算をやめるべきか？](http://ri2t.kyushu-u.ac.jp/~watanabe/RESERCH/MANUSCRIPT/KOHO/CONVERGE/converge.pdf)
具体的なアルゴリズムは以下の通りになります。
>procedure Newton($f'(x),f''(x)$)
1.$x$の初期値を与える。
2.$\bar{x}\leftarrow x$と置き、次のように$x$を更新する。
$x\leftarrow\bar{x}-\frac{f'(\bar{x})}{f''(\bar{x})}$
3.ステップ2に戻り、これを$|x-\bar{x}|<\delta$となるまで繰り返す。
4.$x$を返す。
（金谷、2005、p.86）

pythonでは、[SciPy](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.newton.html)というライブラリを使うと簡単に実装できます。


```python:Newton.py
from scipy import optimize
#f(x)=x^2-2の0地点を求める(x=√2)
f = lambda x : x**2 - 2
optimize.newton(f,0)
#出力
1.414213562373095
```

#参考にしたもの
「これなら分かる最適化数学」（金谷、２０１５）
[SciPy](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.newton.html)
[機械学習のためのニュートン法 (1 変数から多変数まで)](https://differencia.jp/notes/newton/)
[二分法・ニュートン法・勾配降下法をPythonで理解する](https://qiita.com/maskot1977/items/2d409313e52e353e580d)
[いつ反復計算をやめるべきか？～収束判定基準の設定方法～](http://ri2t.kyushu-u.ac.jp/~watanabe/RESERCH/MANUSCRIPT/KOHO/CONVERGE/converge.pdf)
EDAツールについて

#EDAとは
探索的データ分析（Explanatory Data Analysis）とは、データサイエンティストがデータに対する理解を深めるために用いる手法です。主にデータの可視化を通して各種統計量や欠損値、外れ値などを見つけます。
今回はEDAに関するツールで便利なものがあったのでまとめます。

##pandas-profiling
今回はkaggleの[titanic](https://www.kaggle.com/c/titanic/data)のデータを使います。

インストールに関しては[こちら](https://github.com/pandas-profiling/pandas-profiling)を参照

```python
import pandas as pd
import pandas_profiling as pp
```

```python
train_df = pd.read_csv('train.csv')
```

```python
pp.ProfileReport(train_df)
```
出力結果は長くなるので[こちらの記事](https://qiita.com/h_kobayashi1125/items/02039e57a656abe8c48f)を参照してください。

pandas-profilingの問題点として、結果が出力されるまでに時間がかかる点が挙げられます。今回のデータでは自分の環境では28.3sかかりました。より大きなデータとなったときに計算がなかなか終わらない可能性があります。
この問題は[Minimal mode](https://pandas-profiling.github.io/pandas-profiling/docs/master/rtd/pages/big_data.html)を使うことで部分的に解決できます。

```python
pp.ProfileReport(train_df,minimal=True)
```
これにより、実行時間は４分の１ほどでデータの変数（Variables）の部分まで取り出すことができます。

##AutoViz
インストールは[こちら](https://github.com/AutoViML/AutoViz)
pandas-profilingと似ていますが、各変数の対応関係も自動で可視化してくれるので便利です。（＊DataFrame型だと読み込めないので注意）

```python
from autoviz.AutoViz_Class import AutoViz_Class
AV = AutoViz_Class()
autoviz = AV.AutoViz('train.csv')
```


![output.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397323/4baa2d9d-8d11-4018-386c-5d316fb3b1ef.png)

![output1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397323/c4f6b27a-9e1e-8603-9df3-6c2dbe7f118e.png)


![output2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397323/9e7f4d3b-27ed-e187-e070-7027dd6642c2.png)


![output3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397323/31f93b23-1fe9-e39d-09a5-6eab4fc39a25.png)

![output4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397323/3c15ced6-9bd2-9432-2379-6d68d156c3ce.png)


![output5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397323/b692a033-9412-1fb1-8ffb-5e7a9b38c39c.png)

##sweetviz
[インストール](https://github.com/fbdesignpro/sweetviz)先

```python
import sweetviz as sv
report = sv.analyze(train_df)
report.show_notebook()#notebook上で表示
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397323/4908070a-c9b2-e8f7-9961-c189b25b3de3.png)
ほとんどpandas-profilingのVariablesと同じです。
sweetvizの良い点は、学習データとテストデータを目的変数を設定して比較できることです。

```python
compare_report = sv.compare([train_df, "Train"], [test_df, "Test"], "Survived")#trainデータとtestデータを比較　目的変数はSurvived
compare_report.show_notebook()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397323/66931fb2-e212-702a-da6a-60ef0cefef1f.png)

##参考サイト
[pandas-profiling](https://github.com/pandas-profiling/pandas-profiling)
[Autoviz](https://github.com/AutoViML/AutoViz)
[sweetviz](https://github.com/fbdesignpro/sweetviz)
[【Pythonメモ】pandas-profilingが探索的データ解析にめちゃめちゃ便利だった件](https://qiita.com/h_kobayashi1125/items/02039e57a656abe8c48f)
[【EDA】Sweetvizの紹介 (+pandas-profilingとの比較)](https://qiita.com/YuyaOmori/items/647531f1428de37d92c4)
[【Autoviz】機械学習EDAの便利ツールをPythonで試してみる](https://hazimenoippo-hawaii.com/datascience-ml-eda-3rd/)