OmniAICreator/Qiita-1.07M huggingface dataset:
RubyonRailsの記録1

# はじめに
学習したことをまとめるために、自分用として書いてます。

## ブラウザに表示させるには
開発に必要なフォルダやファイルの準備をするにはコマンドを使う
**rails new アプリケーション名** でファイルを用意して**rails server** コマンドでサーバが起動します。

## トップページの作成
　トップページを作成するには、**rails generate controller home top** 
というコマンドをターミナルで実行します。
　すると**localhost:3000/home/top** のURLを持つ新しいwebページが作成されます。この際にhomeコントローラとtop.html.erbが作成されますが、同じ名前のコントローラがすでにある時は上記のコマンドは使えません。

## ビューとは
　ビューとはページの見た目を作るためのHTMLファイルです。コマンドでwebページを作成したらhomeフォルダと**top.html.erb** のファイルが作成されます。
　erbとは**HTMLなどの文章の中にRubyスクリプトを埋め込むためのファイル形式**になります。

## コントローラとは
 ページを表示するとき、Railsの中ではコントローラを経由してビューをブラウザに返しています。
　rails generate controller home topを実行したときに**home_controller.rb** というhomeコントローラのファイルが作成され、ファイルの中に**topメソッド** が追加されます。このコントローラ内のメソッドを**アクション** と言います。
　アクションは、**コントローラと同じ名前のビューフォルダから、アクションと同じ名前のHTMLファイルを探してブラウザに返す** 役割を持っています。

## ルーティングとは
　Rails内ではコントローラを経由してビューを返しますが、ブラウザとコントローラを繋ぐ役割を担うのがルーティングです。
　ルーティング→コントローラ→ビューという順で処理が行われています。ルーティングは**どのコントローラの、どのアクションで処理するかを決めるか** の約束事が書いてあります。
　ルーティングは**config/routes.rb**ファイルに定義され、**get "URL" => "コントローラー名#アクション名"** という文法で書かれます。

## localhost3000をトップページに変更するには
　localhost3000は後ろに(/○○)がないので対応するルーティングを書くには**get "/" => "home#top"** のように記載します。
　意味は**localhost3000のページの情報を取得したい時はhomeコントローラのtopアクションを呼び出し、ビューフォルダからtopアクションに対応するHTMLファイルを探してブラウザに返す** という意味です。
　



## リンクを作るには
リンクを作るには< a>タグ内のhref属性でURLを指定する必要があります。
そしてhrefの中にルーティングのURL部分と同じURLを記述することでリンク先を指定することができます。
　トップページへのリンクを作りたいときは
```top.html.erb
<a href="/">トップページへのリンク</a>
```
と記述します。するとリンクを押された際はroutes.rb内で取得したいURLと同じルーティングが探されます。


## 変数を使って表示させる
　index.html.erbのerb形式のファイルでは<%%>で囲むことでRubyのコードを記述することができ、変数の定義などに用います。埋め込むRubyのコードをブラウザで表示させたい場合には<%= %>を用います。
 ただし、変数の定義はビューファイル内ではなく、アクション内で定義するのが一般的です。
　アクション内で定義した変数をビューで使用するには「 @ 」を先頭につけることでビューファイル内で使うことができるようになります。






# データベースを使って表示
新規投稿をデータベースに保存して表示させるには次の工程が必要になります。
* 投稿を保存するテーブルを作成する
    * データベースに変更を指示するファイルを作成
    * データベースに変更を反映させる
* データベースにデータを追加する
    * newメソッドでPostモデルのインスタンスを作成(**new,save**)
* postsテーブルからデータの取得(**Post.all,post.content**)
* 


## データベースに変更を指示するファイルを作成
　まずは、マイグレーションファイルと呼ばれるデータベースに変更を指示するためのファイルを作成します。
　**rails g model モデル名（テーブル名） カラム名:データ型** のコマンドで作成できます。
実行すると二つのファイルが作成されます。
・app/modelsフォルダにモデルが定義されたファイル
・db/migrateフォルダにマイグレーションファイル

## データベースに変更を反映させる
データベースに変更を反映させるには**rails db:migrate** のコマンドを実行します。

## 投稿するデータ（post）インスタンスを作成する
新しくデータを保存するにはPostモデル（Postクラス）からPostインスタンスを作成
します。インスタンスを作成するには**newメソッド** を使用します。
　そして、作成したPostインスタンスをテーブルに保存するには**saveメソッド** を使います。

## 投稿データの表示
postsコントローラのindexアクション内の@postsに、Post.allで取得したデータを代入しましょう。ビューでは@postsに代入されている配列データをeach文で1つずつ変数postに代入し、投稿内容を繰り返し表示

## 参考文献
[Progate](https://prog-8.com/)
homebrewでインストールしたjava runtimeのパス設定がうまくいかない場合

HomebrewでインストールしたOpenJDKのパスは、
```
brew --prefix openjdk@11
```
コマンドで確認することができます。

上記のコマンドを実行すると、OpenJDKがインストールされている場所のパスが表示されます。出力されたパスを使って、シェルの設定ファイルにJavaへのパスを設定します。

zshを使っていると仮定すると、そのパスを.zshrcに追加するためのコマンドは次のようになります：
```
echo 'export PATH="$(brew --prefix openjdk@11)/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
```

ここまでできたら、
```
java -version
```
で

```
openjdk version "11.0.19" 2023-04-18
OpenJDK Runtime Environment Homebrew (build 11.0.19+0)
OpenJDK 64-Bit Server VM Homebrew (build 11.0.19+0, mixed mode)
```
のような表示を確認できるはず。
法務省登記所備付地図データの内容と使い道

今年から公開されたこのデータ、自身にとっては結構使いどころがあったりする

https://front.geospatial.jp/houmu-chiseki/

# データの内容

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346424/9c46f6f6-e96f-8481-ed40-90b5ef417aeb.png)

基本またXMLの変換だなぁーと、考えていたけれど、最近ありがたいことに使いやすい形に変更してくださっている（ありがたやありがたや・・・）

https://front.geospatial.jp/moj-chizu-shp-download/

かなり汎用性高い形式でとても嬉しい・・・
そろそろXML配布やめてGeoJSON統一いきませんかねぇ・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346424/27f616a4-8a77-ce48-7477-793dfb826f75.png)

こちらをダウンロード

地域にもよるし、筆数にもよるだろうけど、南アルプス市ではGeoJSONで199MB程度
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346424/c2624ddf-3e56-46e3-aadc-d41a27012b78.png)

シェープファイルでは227MB程度

早速QGISで展開

ESPGを合わせて
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346424/51215bfc-3092-3de6-a804-4fc8778f2fbd.png)

シェープファイルをドラッグアンドドロップで読み込み
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346424/9733173b-3704-2db8-c5f3-af8fdf4bce30.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346424/045b0d7b-29a2-5811-ef18-7fa762bc4ec6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346424/be3285ca-6f00-34b4-9aab-89f89aaf2f72.png)

属性情報を見てみると、ポリゴンそれぞれに番地が入っている（そのまま出すのは憚られる情報）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346424/1534047c-c87f-1d7b-38dd-372fa76d6978.png)

地図を見やすくしてみる
地理院タイルをグレースケールにして
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346424/ec8fb2d6-7c82-42b7-2f25-e9daccbb4ce4.png)

塗りつぶさず、かつ線を少し細くして
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346424/7fe75042-cc7c-3b12-8c32-282bdb1145b3.png)

多少見やすくなったかも
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346424/1b46bb09-7bdb-99f5-fedd-7789f4962c0a.png)

地物情報表示で見てみると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346424/03ee0c4e-8aa4-fb04-252f-77af75fe88f1.png)

バックネットにも地番があるとは。。。



# 使い道について
このデータが一般でも使えるのはとてもありがたい。
特に自身の分野では遊休農地対策にとっても便利。
IteratorをSQLで使う

SQLでiterateタグを使用したのでメモ

#### SQLの呼び出し

```java
List<String> historyList = Arrays.asList("A", "B", "C");
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("historyList", historyList);

return (CompanyBean) this.getSqlMapClientTemplate().queryForObject("PowerSql.selectContractPlanInfo", paramMap);
```
#### SQLの実行
```xml
<select id="selectContractPlanInfo" parameterType="java.util.Map" resultMap="HistoryMap">
    SELECT
        SERVICE_CODE
    FROM
        WSC.TB_MST_PT_HISTORY
    <iterate prepend="WHERE" property="historyList" conjunction="OR">
        SERVICE_CODE = #historyList[]#
    </iterate>
</select>
```

## 解説
|属性|説明|
|:--|:--:|
|prepend|SQL文に条件を追加する際の接頭辞を指定|
|property|繰り返し処理を行う対象のプロパティを指定|
|conjunction|各条件間の結合方法を指定します。ANDまたはORを指定することができる|

iterateはMyBatisのタグの1つであり、繰り返し処理を行うために使用される。
```xml
    <!-- property=Mapのkey -->
    <iterate prepend="WHERE" property="historyList" conjunction="OR">
        SERVICE_CODE = #historyList[]#
    </iterate>
```
上記は以下のようなSQLを生成していることになる
```xml
WHERE 
    SERVICE_CODE = 'A'
    OR
    SERVICE_CODE = 'B'
    OR
    SERVICE_CODE = 'C'
```
iterateタグを使用することで、動的な条件生成と条件の結合方法の柔軟性が得られる。
もしiterateを使用しないとListに要素が追加された時、手動で条件文を書かなければならなくて柔軟性に欠ける。
```java
//Dを追加
List<String> historyList = Arrays.asList("A", "B", "C","D",);
```
```xml
WHERE 
    SERVICE_CODE = 'A'
    OR
    SERVICE_CODE = 'B'
    OR
    SERVICE_CODE = 'C'
    OR
    SERVICE_CODE = 'D' <!-- 増えた分だけ追加する必要がある -->
```

## 終わり
動的にSQLを作成することができるので便利ですね:writing_hand:
週一でPython勉強会やってみる⑤

前回の続き

https://qiita.com/Waddy675/items/7da7d54b82f7c75b4121

来週からもう一人参加してくれる人が増えるみたいで嬉しいです。

## 関数
関数の書き方は**def**を使う。
```py
def hoge():
    print("banana")
```
これでhogeという関数を呼べば「banana」が表示される関数が爆誕。←意味ない関数だが・・・
()内に引数を書いたり、戻り値returnを書くことも可能。

とここで生徒が「同名の関数で引数違う場合はどうなる？」と質問。
つまり**オーバーロード**は使えるのかという話。
```py
def hoge():
    print("banana")

def hoge(str):
    print(str)

hoge() # ←①
hoge("apple") # ←②
```
これを実行すると①でhoge() missing 1 required positional argument: 'str'とエラーになる。
どうやら標準ではオーバーロードに対応していないらしい。とはいえやり方はあるようなので、知りたい方は他の記事へどうぞ。
ちなみに上の関数定義の順番を入れ替えるとエラーが②の位置で表示される。
※オーバーロードとオーバーライドは別物なので間違えないように。

さらに生徒から「引数にデフォルト値を設定できるのか」という質問が。
```py
def hoge(str = "banana"):
    print(str)

hoge() # banana
hoge("apple") # apple
```
デフォルト値は設定できるようだ。

引数とか戻り値に型指定できないのかという話も出た。
どうやら書けるが、あくまでヒント/アノテーションなので型を強制するものでないらしい。
ヒント無視して書いてもPython自体は動作してしまうので、そうなってしまうと防げない。。。

## まとめ
関数はfunc/functionではなく**def**。
オーバーロードは標準では使えない。
引数のデフォルト値は設定可能。
型指定ではなく型ヒントレベルでしかない。

これにて一通り基礎は抑えたかなと。
次回からはいよいよ実践？編でエクセルを弄っていく予定。

最近の悩み
色々な言語を触ってるとどう書けばいいか分からなくなるのは私だけでしょうか・・・
（失敗）Chromeのバージョンを自動で確認して通知する

# サマリー

Chromeの拡張機能でChromeのバージョンを記録しておき、バージョンアップされたら通知される機能を作りたかったが失敗した。
原因としては、

1. バージョンを取得するAPIが存在しない
1. タブに表示している内容を取得しようとしても、chrome://version は対象外

色々試したが、拡張機能では、実現できなかったことを記録に残すための記事。

# 背景

Seleniumを使ってChromeを操作させているプログラムを配布した際に、Chromeのバージョンアップにより、ChromeDriverの更新が必要になることが多々ある。エラーが出るたびに、イライラするので、事前にキャッチしておきたく、拡張機能による開発を検討した。

# 設計

1. Chromeを起動した際に、現在のChromeのバージョンを取得する★
1. 取得した結果と日付をlocalstrageに保存する
1. localstrageに保存された結果と異なる場合は、ポップアップで更新されたこととバージョンを表示する
1. localstrageに保存された結果と同一の場合は、なにもしない。
1. 拡張機能のボタンをクリックすると現在のバージョンと最後に確認した日付を表示する

# バージョンの取得

★印のところで２パターンで検討した。

1. Extensionで使用できるAPIを利用する
1. 「chrome://version」をスクレイピングする

起動時に実行するため、ChromeExtensionの中で「Event Page (Background Page)」
を使うことで、
※他には、「Content Scripts」「Browser Action (Page Action)」があり、実行するタイミングで変わる

1に関しては、Google Extensionで利用できるAPIがあると思っていたところ、存在しなかったです。
[APIドキュメント](https://developer.chrome.com/docs/extensions/)
2に関しては、「chrome://version」を開き、バージョンをスクレイピングで取得すればよいと考えた。
実際に、Extensionでも開いたページのリンクや画像を一括取得するものがあるので、対応可能と考えたが、調べたところ、Permissionの設定が必要であった。
その設定に追加できるプロトコルが、http、https、fileであり、「chrome://」を追加できなかった。
また、bookmarksは存在するが、versionの権限を追加することはできなかった。
[permissions](https://developer.chrome.com/docs/extensions/mv3/declare_permissions/)

# その他、調査が必要なこと

* localStorageの使い方。バックグラウンドでは使えない？
参考サイト
https://engineering.webstudio168.jp/2023/02/chrome-extension-background-localstorage/

* backgroundでの実行時に、JavaScriptのwindowオブジェクトを取得できない。→MessageAPIを使って受け取る方法？
参考サイト
https://zenn.dev/ellreka/articles/799632c02d1cb5

* window.navigator.userAgentDataでchromeのバージョンが取得できそう？
参考サイト 
https://developer.mozilla.org/ja/docs/Web/API/Navigator/userAgentData

# 参考ページ

https://qiita.com/sakaimo/items/416f36db1aa982d8d00c

https://zenn.dev/saiki_toshiki/articles/323baf68d85e1f

https://blog.ver001.com/chrome-extension-v3/

# まとめ

かんたんに作れると思っていたが、意外に難しく、現時点ではうまく行かなかったことを記録に残しておき、今後調査する。
背景を満たすだけであれば、なにかしらの方法があるかもしれない。また進捗があれば、更新することにする。
[ChatGPTが書きました] Mac OS13 へのanyenv設定: もう一度全てをやり直す (2023/05 時点)

**この記事はChatGPTによって制作されております。**

## はじめに
最近、私のPCが突然動かなくなり、新しいMacを手に入れることになりました。バックアップからの復元ができなかったため、久々に１から環境設定を行うこととなりました。**anyenv**の設定のときに少し躓いたので、Qiitaに手順の記録を残します。

## anyenvとは?
![anyenv logo](https://anyenv.github.io/assets/img/logo.png)

[anyenv](https://github.com/anyenv/anyenv)は、様々なプログラム言語のバージョン管理を一元化するためのツールです。rbenvやpyenv、nodenvなど、各種バージョン管理ツールをまとめて管理できます。各言語のバージョン管理ツールを一つずつインストールする必要がなくなるので、非常に便利です。

## anyenvの設定手順

以下に、私が新しいMacにanyenvを設定した手順を説明します。

### 1. Homebrewを用いてanyenvをインストール

まず、macOSのパッケージ管理ツールであるHomebrewを用いてanyenvをインストールします。以下のコマンドを実行します。

```
$ brew install anyenv
```

### 2. シェルにanyenvを設定

次に、シェルにanyenvを設定します。以下のコマンドを実行した後、表示される指示に従ってください。

```
$ anyenv init
```

ここで、manifestディレクトリが存在しない場合は以下の
警告が表示されます。私は、maifestディレクトリを作成してなかったので、警告を受けました。

```
ANYENV_DEFINITION_ROOT(/Users/username/.config/anyenv/anyenv-install) doesn't exist. You can initialize it by:
> anyenv install --init
```

### 3. インストールマニフェストディレクトリを初期化

上記の警告に従って、以下のコマンドを

実行してインストールマニフェストディレクトリを初期化します。

```
$ anyenv install --init
```

### 4. 必要な**envをインストール

次に、必要な各種バージョン管理ツール（**env）をインストールします。以下に、rbenv、pyenv、nodenvをインストールする例を示します。

```
$ anyenv install rbenv
$ anyenv install pyenv
$ anyenv install nodenv
```

### 5. ターミナルを再起動

最後に、ターミナルを再起動することで、インストールした**envが利用可能になります。

```
$ exec $SHELL -l
```

## まとめ

上記の手順を経て、新しいMacにanyenvを設定することができました。この記事が同じような状況にある方々の助けになれば幸いです。また、マニュフェストの初期化を忘れてエラーに遭遇したことが、anyenv設定時の注意点として共有できたことを嬉しく思います。新しい環境設定は頭を悩ませることが多いですが、それぞれの手順を一つずつ丁寧に進めていくことで、無事に完了することができます。

次回もまた、新しい発見や経験を共有できることを楽しみにしています。
element plus 無限ローディング

毎回やってるが、無限ローディングをしたい。

もう面倒なので element plus の無限ローディングを使う。
これを使いデータをポップアップ表示させることで、ページ間の移動がなくなり、
戻り先の設定をする必要がなくなるので楽。


まず、laravelは普通に読み出す。

laravel

```hoge.php

    public static function show(request $request)
    {

        $sql = User::query();//単数形 User

        $limit = 5;
        if(!empty($request->limit)){
            $limit = $request->limit;
        }

        $res = $sql
            ->paginate($limit);//ページは1から始まる

        return response()->json(['res'=> $res]);
    }

```


同じページを連続で読み出すので、ひたすらうざい。
ということで同じページは読み込ませないように。
readedUrlに一度読み出したpageを読み込ませないよう配列にツッコんでおく。


```hoge.vue

<template>

    <div class="infinite-list-wrapper">

        <ul
            v-infinite-scroll="load"
            class="list"
            :infinite-scroll-disabled="disabled"
            infinite-scroll-distance="0"
        >
            <li v-for="(v,key) in userData" :key="key" class="list-item">
                <div>
                    <a style="cursor:pointer">{{v.id}} {{v.name}}</a>
                </div>
            </li>
        </ul>

        <p v-if="loading" style="background-color: red;">Loading...</p>
        <p v-if="noMore">すべて読み込みました</p>
    </div>

</template>





<script lang="ts" setup>
import {  reactive,computed, ref ,onMounted } from 'vue'


const axiosUrl = ref(`/users/show`)
const userData = ref(reactive([]))

const loading = ref(false)
const noMore = ref(false)
const disabled = ref(false)


//同じページを読み込ませない
const readedUrl = reactive<string[]>([]);




const load = () => {
    loading.value = true
    setTimeout(() => {
        getUserShow()
        loading.value = false
    }, 200)

}


const getUserShow = () => {

    if (!readedUrl.includes(axiosUrl.value)) {
        readedUrl.push(axiosUrl.value);

        console.log("ページを読み込みます" + axiosUrl.value);
        axios.post(axiosUrl.value)
            .then(response => {
                if(response.data.res.next_page_url != null){
                    axiosUrl.value = response.data.res.next_page_url;
                    userData.value.push(...response.data.res.data);
                } else {
                    disabled.value = true
                    noMore.value = true
                }
            })
            .catch(error => {
                // エラーを処理する
                disabled.value = true
                noMore.value = true
                console.error(error)
            })
    }
}



</script>

<style>
.infinite-list-wrapper {
    height: 50%;
    text-align: center;
}
.infinite-list-wrapper .list {
    padding: 0;
    margin: 0;
    list-style: none;
}

.infinite-list-wrapper .list-item {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 150px;
    background: var(--el-color-danger-light-9);
    color: var(--el-color-danger);
}
.infinite-list-wrapper .list-item + .list-item {
    margin-top: 10px;
}
</style>


```
【備忘録】気象庁の震度データからPMTilesを生成する方法

# はじめに

本記事では、気象庁が公開している、[地震月報(カタログ編)の震度データ（1919～2020年）](https://www.data.jma.go.jp/eqev/data/bulletin/shindo.html)から、[PMTiles形式](https://github.com/protomaps/PMTiles)のデータを生成する方法について説明します。

## PMTilesの特徴
- 単一ファイル形式のタイルデータ
- 地球規模のタイルマップの保存
- S3 のようなストレージとHTTP Range Requestsのみを使用

https://protomaps.com/blog/pmtiles-v3-hilbert-tile-ids

# PC環境
OS：Windows 10 Pro
CPU：Intel(R) Core(TM) i7-9700
メモリ：32GB

# 前提条件
- 下記の気象庁のサイトより地震月報(カタログ編)の震度データや震度観測点一覧を取得済みであること。

https://www.data.jma.go.jp/eqev/data/bulletin/shindo.html

- 下記の変換ツールを用いて、震度データや震度観測点一覧を読みやすい形式（GISデータ）に変換済みであること。

https://github.com/shi-works/jma-earthquake-data-converter

- WSL（Ubuntu-20.04）がインストール済みであること。
- [tippecanoe](https://github.com/felt/tippecanoe)がインストール済みであること。
- Windows 10へのtippecanoeのインストール方法は以下のとおりです。

https://gist.github.com/ryanbaumann/e5c7d76f6eeb8598e66c5785b677726e

※ただし、`git clone https://github.com/mapbox/tippecanoe.git`の箇所を`git clone https://github.com/felt/tippecanoe.git`への変更が必要です。
- tippecanoeのバージョンはv2.23.0です。

# FlatGeobufからPMTilesを生成
- FlatGeobufからPMTilesの生成には[feltのtippecanoe](https://github.com/felt/tippecanoe)を使用します。
- WSLを起動して、以下のコマンドを実行します。
- FlatGeobufは以下から取得できます。
- 震源データ
`https://pmtiles-data.s3.ap-northeast-1.amazonaws.com/jma-earthquake/hypocenter_convert.fgb`,51.6MB
- 震度データ
`https://pmtiles-data.s3.ap-northeast-1.amazonaws.com/jma-earthquake/shindo_convert.fgb`,453.8MB
- 使用するFlatGeobufは以下のとおりです。
hypocenter_convert.fgb：震源データ
shindo_convert.fgb：震度データ
```
tippecanoe -o hypocenter_convert.pmtiles -r1 -d1 -pf -pk -P hypocenter_convert.fgb
tippecanoe -o shindo_convert.pmtiles -r1 -d1 -pf -pk -P shindo_convert.fgb
```
- tippecanoeのオプション
-r1：低ズームレベルでのポイントの自動削除を行わない
-d1：すべてのズームレベルで間引き処理を無効にする
-pf：地物数制限を無視する（1タイルあたり200,000フィーチャに制限しない）
-pk：ファイルサイズ制限を無視する（1タイルあたり500Kバイトに制限しない）
-P：並列読み込み
ただし、下記の記事によると、-Pオプションが有効なのは、GeoJSONSeqのみのようです。

https://qiita.com/Kanahiro/items/ceeb20c158b4c70b62b6

# 生成したPMTilesの確認
- 生成したPMTilesの確認には、[PMTiles Viewer](https://protomaps.github.io/PMTiles/)が便利です。
- PMTilesをドラッグ&ドロップすると、フィーチャが地図上に表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205045/7cde89fd-e705-cdb5-a56e-15f51fd843be.png)

# PMTilesの配布
- 上記の方法で作成した、PMTiles形式の震源データ及び震度データは、以下のGitHubにて配布しています。

https://github.com/shi-works/jma-earthquake-data-converter

## デモサイト
- PMTiles形式の震源データ及び震度データは、MapLibre GL JSで作成した、デモサイトにて閲覧ができます。

https://shi-works.github.io/jma-earthquake-data-converter/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205045/d28312d8-3817-81d6-9ce1-aaad8abd49ba.png)

# 参考情報

https://qiita.com/Kanahiro/items/ceeb20c158b4c70b62b6

https://github.com/protomaps/PMTiles

https://github.com/felt/tippecanoe
クラスを別ファイルに自動で移す方法【C#】【自動リファクタリング】


今回はC#の自動リファクタリングの話をしていきます。

例えばこんな感じで、何かクラスを書いた場合を考えてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355359/4fe79852-b79f-dd03-1f48-560929ba3ae6.png)
同じファイルの中に、クラスなどインターフェイスなど、ためしで書いた場合です。

こんな感じで、１つのファイルに複数のクラスやインターフェイスを書いた場合、
実際は別のファイルに書き出したいという場合は、通常はコードを切り取って、
新しいファイルを追加してコードを移す必要がありますが、
自動リファクタリング機能を使えば、これを一撃でファイルに移動させることができます。

まず、これ抜き出したいクラス選択して、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355359/d22f385a-0b7d-cf71-9c9c-190c67a9f7ec.png)

Ctrlとドットを押すと、「型をProduct.csに移動」というのが出てくるので、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355359/55b96363-c62d-bbdf-2255-2664493c094d.png)
これ押したら、元々のファイルから消えて、
新たに作成されたProduct.csファイルに入ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355359/b74b560e-67c9-3d59-e2bf-673455da2c16.png)

IEntityインターフェイスも同様の方法でIEntity.csファイルに移動します。
Ctrl+ドットじゃなくても、選択して「クイックアクションとリファクタリング」を選択してもらってもいいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355359/be40eec5-0d69-2c93-8462-aec6f9c6b437.png)

これで型をIEntity.csに移動ってやると、これも別ファイルにしてくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355359/d6bb9a0b-bbc0-9412-faea-3326a14d15c7.png)

別フォルダーが良かったよって言う場合は、後で移してもらって、名前空間調整しますかって聞かれるので、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355359/f3183849-9deb-51de-1435-4bc6545789f9.png)
別フォルダーなどに移動してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355359/d5c77b4f-4dd0-5d97-7c37-e40b7a4368ad.png)

こんな感じで同じファイルに複数クラスがある場合は、こんな感じで、ファイルに移してみてください。
ターボワープを使用してhtml&javascriptで作ったアプリをexe化する

<h1>exe形式の実行ファイルを<a href="https://turbowarp.org/">turbowarp</a>を使って作ってみた。(初記事)</h1>
どうもこんにちは、最近あだ名メーカー使ったら「国士無双のカリスマ店員」て出てきた人です。
今回は、最近ターボワープを使ってプロジェクトをexe化していた時に気付いたことを実験し、記事にしました。<br>
さて、本編へ行きたいと思います。
ちなみに今回は、html&javascriptで作ったアプリケーションをexe化していきます。
<h2>方法</h2>
1,ターボワープを開きeditorを起動します。<br>
2,最初からあるスプライトを消してから、パッケージ化を選択します<br>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3360352/638f6993-7fad-23bd-1645-6aad84be6166.jpeg">
3,パッケージ化画面に来たら、アプリの名前を入力します<br>
4,「大きな緑の旗を表示せずに自動でプロジェクトを始める」のチェックボックスにチェックを押します<br>
5,「Electron Windowsのアプリケーション(32bitまたは64bit)」にチェックをいれて、パッケージ化を実行します

ダウンロードできたzipファイルを解凍し、
C:\Users\ユーザー名\Downloads\プロジェクト名\resources\app
を開きます
そこに、[index.html]のfileがあるはずですから、そこのHTMLファイルを自作したwebアプリケーションアプリに置き換えます。

そしたら完成です。
C:\Users\ユーザー名\Downloads\プロジェクト名\にある、[プロジェクト名.exe]を押せば実行できます。

https://www.youtube.com/watch?v=dX-ZmAUq5tw

<iframe width="560" height="315" src="https://www.youtube.com/embed/dX-ZmAUq5tw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

↑実際にやった動画です。
テスト95

```vb
Sub test()

'Excelで使う場合、以下の参照設定をしておく
'Microsoft  Outlook 16.0 Object Library

'注意点として「連絡先」は個人で使う用のアドレス一覧
'「アドレス帳」は組織で使うアドレス一覧
'業務で特定のアドレスを検索したい場合は、
'通常はアドレス帳から検索する...φ(･ω･*)ﾒﾓﾒﾓ

Dim Addr As String

Addr = "テスト"

If Check_Address(Addr) = False Then

    MsgBox "指定のアドレスが見つかりませんでした。"
    End
    
End If

Stop

End Sub

Public Function Check_Address(ByVal Addr As String) As Boolean

Dim ol As Outlook.Application
Dim myNameSpace As Namespace
Dim myAddressList As AddressList
Dim myAddressEntries As AddressEntries
Dim myAddr As AddressEntry
Dim oExUser As ExchangeUser

Check_Address = False

On Error Resume Next

Set ol = GetObject(, "Outlook.Application")

If ol Is Nothing Then

    Set ol = CreateObject("Outlook.Application")

End If

On Error GoTo 0

'---------------------------------------

Set myNameSpace = ol.GetNamespace("MAPI")
Set myAddressList = myNameSpace.AddressLists("Offline Global Address List")
Set myAddressEntries = myAddressList.AddressEntries

For Each myAddr In myAddressEntries

    Set oExUser = myAddr.GetExchangeUser

    If Not oExUser Is Nothing Then
    
        If oExUser.PrimarySmtpAddress = Addr Then
    
            Debug.Print ("メールアドレス：" & oExUser.PrimarySmtpAddress)
            Check_Address = True
            Exit Function
            
        End If
    
    End If
    
    
Next

End Function
SQLの高みへ！分析(window)関数について(Bigquery)


## 概要
ただ、書けるから、より書けるにステップアップ！
そのため忘れないようにメモ程度に投稿します！
 
### そもそもwindow関数とは
何らかの条件で並んでいるデータに対して、特定の範囲のデータのみ参照できるようにする機能が用意されており、これをWindowと呼んでいます。

### 集合関数との違い
集合関数ではGROUP BYの同じカラム値をもつ全行を一つに集計しますが、分析関数では集計対象となる行の範囲を任意で指定できます。関数に続くOVER句でこの範囲指定を行います。集合関数と分析関数は基本同じ名前なので、よく使う一般的な集合関数は後ろにOVER句をつけれれば、分析関数になる

## OVER句について

◇指定可能な３種類
partition by
order By
window 

分析関数
```sql
SELECT id, item, COUNT(*) OVER (PARTITION BY item)
FROM test_orders ORDER BY id;

ID  item  COUNT(*)OVER(PARTITIONBYITEM)
-------------------- -----------------------------
A  Apple    4
B  Banana   2
C  Banana   2
D  Apple    4
```

#### PARTITION BY
列単位で複数の集計をする関数 
「カラム１」と「カラム１＆カラム２」の在庫を1つの表に抽出可能
```sql
SELECT DISTINCT
 CODE	AS 'コード'
,name	AS '名前'
,SUM(カラム3) OVER(PARTITION BY CODE,name)	AS "総在庫_name"
,SUM(カラム3) OVER(PARTITION BY CODE)	AS "総在庫_code"
 FROM テーブル
```



##  LAG関数，LEAD関数
指定したカラムの行の前後のデータが得られます。

```sql
 number,
  LAG (number, 1) OVER (ORDER BY date) AS lag_data,
  --LEAD()内で，参照するカラム名とずらす行数を指定
  LEAD (number, 1) OVER (ORDER BY date) AS lead_data 

number, lagdata, lead_data
----------------------------
100,     null,      200,
200,     100,       300,
300,     200,       400,
```

以上です。
ありがとうございました。
Azure Static Web Appsを試す

### GitHubのレポジトリを作成

とりあえず動かすことが目的なので過去と同じシンプルなファイルを用意しました。[Azure App Serviceへの継続的デプロイを試す](https://qiita.com/k-kimino/items/d8376d76abd8f3242017)を参照。

### Azure Static Web Appsを作成

以下の設定値でStatic Web Appsを作成します。
![CreateStaticWebApp2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3322105/37dab6c6-2e9c-8543-07e0-beb3cf1d5b29.png)

デプロイが完了するとURLが表示されるのでそちらにアクセスすると構築したWebサイトにアクセスできます。

### まとめ

静的WebアプリであればAzure Static Web Appsを使って簡単にホスティングできてしまいます。
[ドキュメント](https://learn.microsoft.com/Ja-jp/azure/static-web-apps/overview)を参照すると、Static Web Appsは静的アセットをWebサーバから切り離し、世界各地の分散したポイントから提供されるため高速で、APIエンドポイントはAzure Functionsを介して提供するというあたりが特徴です。リソース作成の際にリージョンを指定したよな？と思ったのですが、これはAPIが単一リージョンとなりそこに関係するようです。

### 参考
[App Service Static Web Apps の仕組みを探る（非公式）](https://blog.shibayan.jp/entry/20200521/1590056371)
(2023/5) Electron + Next.js(Typescript) + Chakra UI でデスクトップアプリを作成する！

## ■環境
・windows11
・Node.js (v18.12.1)
・Nextron (8.19.2)

## ■Nextronとは
Electron + Next.jsのビルドの諸々の設定を行ってくれるライブラリ。
これを使わないと、割と最初の設定が面倒らしい。

https://github.com/saltyshiomix/nextron

## ■Electron + Next.jsのプロジェクト作成
```
npx create-nextron-app my-app --example basic-typescript
cd my-app
npm install nextron@latest
npm run build
npm run dev
```

デスクトップアプリが起動しました！
Devtoolもちゃんと使えてます。
![スクリーンショット 2023-05-11 234743.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1206850/5ad7f373-39b6-371d-7b57-c556e1fa76cd.png)

## ■Chakra UIの導入

https://fwywd.com/tech/next-chakra-ui


### 1.Chakra UIに必要なパッケージのinstall
```
npm install -D @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^4
npm install -D @chakra-ui/icons /*アイコンも利用したい場合はこちらもinstall*/
```

### 2. ChakraProviderのセットアップ
・pages配下に_app.tsxを作成
_app.tsx: すべてのコンポーネントの初期化に使われるコンポーネント

```react
import { ChakraProvider } from '@chakra-ui/react';
import { AppProps } from 'next/app';

export default function App({ Component, pageProps }: AppProps): JSX.Element {
    return (
        <ChakraProvider>
            <Component {...pageProps} />
        </ChakraProvider>
    );
}
```




### 3. Chakra UI のButtonコンポーネントを置いてみる

```react 
import React from 'react';
import Head from 'next/head';
import Link from 'next/link';
import { Button, Stack } from '@chakra-ui/react';

function Home() {
  return (
    <React.Fragment>
      <Head>
        <title>Home - Nextron (with-typescript)</title>
      </Head>
      <div>
        <p>
          ⚡ Electron + Next.js ⚡ -
          <Link href="/next">
            <a>Go to next page</a>
          </Link>
        </p>
        <img src="/images/logo.png" />
        <Stack spacing={4} direction='row' align='center'>
          <Button colorScheme='teal' size='xs'>
            Button
          </Button>
          <Button colorScheme='teal' size='sm'>
            Button
          </Button>
          <Button colorScheme='teal' size='md'>
            Button
          </Button>
          <Button colorScheme='teal' size='lg'>
            Button
          </Button>
        </Stack>
      </div>
    </React.Fragment>
  );
};

export default Home;

```


下記のエラーが発生。
```
Server Error
SyntaxError: Named export 'motion' not found. The requested module 'framer-motion' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'framer-motion';
const { motion, useIsPresent } = pkg;
```

どうやらChakra UIのVersionに相性の問題があるっぽい。

https://github.com/chakra-ui/chakra-ui/issues/7166


私の別プロジェクトでしているバージョンにpackage.jsonの設定を変更することで、とりあえず正常に動くようになりました...!
```
"@chakra-ui/icons": "^2.0.15",
"@chakra-ui/react": "^2.4.6",
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"framer-motion": "^6.5.1",
```

![スクリーンショット 2023-05-12 014647.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1206850/b767e174-e9e6-e92a-7941-a011f9a8b868.png)
RubyKaigi 2023 参加レポート「Load gem from browser」

この記事は [【RubyKaigi 2023連動イベント】みんなでRubyの知見を共有しよう - Qiita](https://qiita.com/official-events/4d2a9eed42dbe0a4af21) の参加記事です。

https://qiita.com/official-events/4d2a9eed42dbe0a4af21

## 追記

スライドが公開されていたので、ぜひそちらもご覧ください！

https://twitter.com/ledsun/status/1657563077280419840?t=nJGH0tAjVk_drnqaU4mRVg&s=19

また発表内容にあった`require_relative`を試していそうなブランチを見つけたので載せておきます。

https://github.com/ledsun/ruby.wasm/tree/enable_requlie_relative

## はじめに

あっというまにRubyKaigi 2023最終日ですね。
最終日のセッションの中から以下のセッションについてまとめます。

## Load gem from browser

https://rubykaigi.org/2023/presentations/ledsun.html#day3

現在、ブラウザでRubyを使えるようになったが、CRubyと同様に`require`を使うことができません。

JavaScriptが似たような歴史を歩んでいるため、歴史を振り返り、

- 依存関係をバンドルする
- ↓その後
- 動的に依存関係を解決（[Import Maps](https://developer.mozilla.org/ja/docs/Web/HTML/Element/script/type/importmap)でモジュール解決）

ようになったことを挙げました。

このうち、発表者の`@ledsun`さんは「Rubyのスクリプト言語らしさ」を挙げ、バンドル等なしですぐに実行できる点から「動的に依存関係を解決」する方法で拡張できないかを考えたそうです。

Rubyには

- `require`
- `require_relative`

があり、`require`ではJavaScriptの`Import Maps`と同様に依存解決を行うように、
`require_relative`では、現ファイルのパスをスタックに入れ、相対的な解決を実現しているそうです。

また、将来的に[UNPKG](https://www.unpkg.com/)のような（ungem的な）ものを用意し、デプロイ時のインストールなどの手間を減らし、
「ブラウザで開発するのにRubyが選ばれる未来」をつくれたらとのことでした。

## さいごに

ブラウザで開発するのにRubyが選ばれることで、黒い画面から始めなくてもRubyを触れる状態ができると、より多くの人にRubyを触ってもらえそうで、いいなと共感しました。
記念すべき第一回投稿！

# 自己紹介
### 仕事:necktie:
- 大学卒業後、中堅SIerに入社し、今年で3年目の駆け出しエンジニアです！
- 主に基幹系のシステムのリプレイスを行っています。
### 趣味:surfer_tone1:
- スポーツ全般
    スケボー、スキー、サーフィン、サッカー...
- 読書（恥ずかしながら読書が好きになったのはつい最近です、、）
    技術書籍、投資関連
- 別荘建築
    友人とともに土地を購入し、自分たちで別荘を建築しようとしています！
    （ちなみに現在は地均しが終了したところです）
# 記事を投稿する目的
### 文章能力の向上:fire:
恥ずかしながら僕は文章を書くのがとても苦手です、、
しかし負けず嫌いの僕はどうにかこの弱点を克服したいと思っていました。
そんな矢先、会社の先輩に __文章能力＝アウトプットの量だ！__ とアドバイスを頂き、本投稿に至りました！
今後は週1投稿を目標に活動していきます！

### 転職活動を見据えたポートフォリオの作成:speaking_head:
エンジニアたるもの自分のスキルアップのために転職を見据えて行動すべきだと僕は考えています！
そのため、転職活動の証として今後は投稿していこうと思います！
### 知識の定着:writing_hand_tone2:
脳の構造的にインプットした知識をアウトプットすることでやっと自分の知識として定着するものらしく、
学んだ知識を自分のものにするためにも投稿を行います！
### 今後の投稿内容:book:
上記の目的に属した内容を投稿していこうと考えています！
具体的には
- 最近読んだ技術書の解説、感想の投稿
- 学んだ知識のアウトプットをする投稿
- 使用してみたツールのレビューを行う投稿
...
# さいごに
興味があれば今後も読んで頂き、指摘や不明点等を教えて頂けると幸いです！

最後まで読んで頂きありがとうございました！
備忘録：VRChatのVPMリポジトリを作る方法

# はじめに

VRChatのパッケージシステム「[VPM](https://vcc.docs.vrchat.com/vpm/)」を配布するためのリポジトリを作る上で行った作業の備忘録です。

# 使うもの

VRChatが用意している2つのGitHubテンプレートを使用します。

* https://github.com/vrchat-community/template-package
* https://github.com/vrchat-community/template-package-listing

## template-package

実際に作成したパッケージ本体を管理するテンプレートです。
基本的にREADMEに書いてあるとおりに作業を進めればOKです。

パッケージングからやりたい場合は、こちらの記事が参考になります。

* https://qiita.com/hoke946/items/dde24d2f5ab29206d5b0


各種定義ファイルを変更したらGitHubへPush。
正しく設定されていればGitHub Actionsが実行され、自動的にTagが打たれてReleaseが行われます。
また、作成したパッケージを配布するためのWebページも自動生成されます。

この`template-package`から作成したリポジトリで配布するアセットは1つに絞った方が良さそうです。
複数個のアセットを管理する場合はそれぞれ個別に`template-package`からリポジトリを作ったほうがいいです。

そしてこれらパッケージをまとめて1つのVPMリポジトリで管理するためのテンプレートが`template-package-listing`です。（`template-package-listing`をメインのVPMリポジトリとして配布するなら、`.github/workflows/build-listing.yml`は消しちゃってもいいかも）


## template-package-listing

リポジトリのrootにある`source.json`に定義された内容で複数のパッケージをまとめて管理できるVPMリポジトリを作ってくれるテンプレートです。
`template-package`でアセットごとにリポジトリを作ってビルドし、最後にこの`template-package-listing`でリスト化して1つのリポジトリで配布するのが良さそう。

これもREADMEに書いてあるとおりに編集しPushすればGitHub Actionsが走ってWebページがつくられます。
JavaシステムでSQL実行

今の現場のJavaのシステム開発でSQLを実行して、データ取得をする処理のメモ。

### Javaファイル
javaからSQLを実行する。引数にSQLのWHERE句で使用するための値を格納したMapをセットする。
実際のSQLはPowerSql.xmlに書いてあるのでそのファイルの特定のidを指定する。
下記はPowerSql.xmlのidがselectContractPlanInfoのSQLを指定している。
```Company.java
public CompanyBean selectContractPlanInfo(String companyCd,String contractPlanCd) {
  Map<String,Object> paramMap = new HashMap<>();
  paramMap.put("companyCd",companyCd);
  paramMap.put("contractPlanCd",contractPlanCd);
  paramMap.put("openDate",OpenDate)

  return (CompanyBean) this.getSqlMapClientTemplate().queryForObject("PowerSql.selectContractPlanInfo",paramMap);
}
```
SQLの処理は以下。
```PowerSql.xml
<resultMap id="ContractPlanBean" class="jp.cp.softbank.wep.bean.CompanyBean">
    <result column="CLASS_KIND" property="kind">
    <result column="CLASS_CD" property="code">
    <result column="CLASS_NAME" property="name">
</resultMap>

<select id="selectContractPlanInfo" parameterClass="java.util.Map" resultMap="ContractPlanBean">
    SELECT 
        "-" AS CLASS_KIND
        PLN.ELECT_POWER_PLAN_CD AS CLASS_CD
        PLN.ELECT_POWER_PLAN_NM AS CLASS_NAME
    FROM
        AA11.TB_MST_PLAN_CTRL
    WHERE
        CTRL_ELECT_POWER_PLAN_CD = PLN.ELECT_POWER_PLAN_CD
    AND
        CTRL.CONTRACTOR_TYPE_CD='01'
    AND
        CTRL.PROVIDER_CD=#powerCompanyCd#
    AND
        CTRL.ELECT_POWER_PLAN_CD=#contractPlanCd#
    AND
        #openDate.time#
</select>
```
## 解説
#### 結果をマッピング
1〜5行目のresultMapはMyBatisによるマッピングの定義。SQLの実行結果をJavaオブジェクトにマッピングする。
例をあげるとAA11.TB_MST_PLAN_CTRLテーブルのCLASS_KINDカラムの値はCompanyBeanオブジェクトのkindプロパティにセットいる。
```xml
                                    <!-- class=Beanを指定 -->
<resultMap id="ContractPlanBean" class="jp.cp.softbank.wep.bean.CompanyBean">
    <!--column=テーブルのカラム名 property=Beanにセットされているプロパティ名 -->
    <result column="CLASS_KIND" property="kind">
    <result column="CLASS_CD" property="code">
    <result column="CLASS_NAME" property="name">
</resultMap>
```
#### selectタグ
parameterClass="java.util.Map"と指定された場合、クエリやステートメントにはjava.util.Mapクラスのオブジェクトが渡される。Company.javaで引数にしていたparamMapが渡されるということ。
resultMap="ContractPlanBean"は上記のresultMapの定義を指定しているので、結果をマッピングすることができる。
```xml
<select id="selectContractPlanInfo" parameterClass="java.util.Map" resultMap="ContractPlanBean">
```
#### SQL
#powerCompanyCd#や#contractPlanCd#、#openDate#は、paramMapのキーのことを指している。実行後にキーに該当する値がセットされる。上記でparameterClass="java.util.Map"にしたからこそparamMapを使用することができる。
```xml
    SELECT 
        "-" AS CLASS_KIND
        PLN.ELECT_POWER_PLAN_CD AS CLASS_CD
        PLN.ELECT_POWER_PLAN_NM AS CLASS_NAME
    FROM
        AA11.TB_MST_PLAN_CTRL
    WHERE
        CTRL_ELECT_POWER_PLAN_CD = PLN.ELECT_POWER_PLAN_CD
    AND
        CTRL.CONTRACTOR_TYPE_CD='01'
    AND
        CTRL.PROVIDER_CD=#powerCompanyCd#
    AND
        CTRL.ELECT_POWER_PLAN_CD=#contractPlanCd#
    AND
        #openDate.time#
```

## 終わり
SLQを実行する処理でした。他のシステム開発ではどのような処理になっているのか気になりました:hushed:
(2) HTB: Snoopy 'Seasonal Machine'に挑戦しました - 5/12/2023 

(2) HTB: Snoopy 'Seasonal Machine'に挑戦しました - 5/12/2023 

https://www.hackthebox.com/achievement/machine/240308/541

こちらはHardに分類されています。結果は４日かけてしまっています。数時間やったのですが、初めのとりかかりが全く未知の世界のように感じたので２，３日放置しました。DNSやネットワーク系を再度勉強させられました。まあどちらかというとCVE脆弱性というより設定ミスを突いているようなマシーンであったように思います。

ハッピーハッキング
Markdown(マークダウン)記法 メモ書き

---
# Markdown(マークダウン)記法 メモ書き
マークダウン記法のメモ書きを残す。

## 見出し
### 見出しの記述例(htmlでいうh1タグとか。6段まで)
    # h1
    ## h2
    ### h3
    #### h4
    ##### h5
    ###### h6

### 見出しの表示例(htmlでいうh1タグとか。6段まで)
# h1
## h2
### h3
#### h4
##### h5
###### h6

## 箇条書きリスト
ハイフンなど(-、+、*)で箇条書きリストになる。

### 記述例
     - リスト
         - リスト
             - リスト
             - リスト
         - リスト
     - リスト
     - リスト

### 表示例
 - リスト
     - リスト
         - リスト
         - リスト
     - リスト
 - リスト
 - リスト
gitで署名付きcommitが突然できなくなったときの解決方法 (備忘録)

# 問題内容
これまで [`git` で署名付き `commit`](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt--Sltkeyidgt) ができていたのに, 突然できなくなることがたびたびある. 
(だいたい `brew upgrade` した後のタイミング)

```console
$ git commit -S -m 'Hello'
error: gpg failed to sign the data
fatal: failed to write commit object
```

# 解決方法
`gpg-agent` を以下のように再起動する.

```console
$ gpgconf --kill gpg-agent  
```

# 参考
https://www.gnupg.org/documentation/manuals/gnupg/Invoking-GPG_002dAGENT.html

# 環境
- GPG: 2.3.8
- Git: 2.33.0
- macOS: 13.3.1
【Tableau Tips】棒グラフの中で最大値だけ強調する方法3選

## はじめに
次のようなよくある棒グラフがあったとき、どの棒が最大値か一目で分かるようする3つの方法を共有したいと思います。

▼よくある棒グラフ（サンプルスーパーストア）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2601070/0d4de30d-349d-3dac-d934-0632e52e6451.png)

## 方法①:RANK関数を使う
RANK関数を使うと、Vizの範囲内におけるランキングを算出できます。

▼合計売上に対してRANK関数を付与したものをラベルに入れてみました。合計売上順にランキングのラベルが振られていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2601070/be2e02d0-5d9d-dbed-ee69-8561e360cdb3.png)

計算フィールドで、合計売上に対してRANK関数が1を返す（つまりランキング1位）計算式を作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2601070/5d648083-7207-8f5f-2aef-698f300fc1a0.png)

この式は、「ランクが1位かどうかという真偽値（Yes or No）」を返します。つまり、Rankが1のとき"真"、それ以外は"偽"を返すので、これをマークの色に配置することで、真偽で色を変えることが出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2601070/27eed0ff-daad-07b2-3ab3-86321adc1e92.png)

## 方法②:WINDOW_MAX関数を使う
WINDOW関数は、Viz内の集計結果を返す関数です。このWINDOW関数の中で、Viz内の最大値を返すWINDOW_MAX関数を利用します。

まずマークの[色]メニューに、SUM(売上)を配置し、[シェルフで編集]を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2601070/af113e3a-f9dc-8f4b-2900-a2271fe97df3.png)

次に、以下の計算式を記載します。これは、ウィンドウ内の合計売上の中で、最大値のとき"真"を返し、それ以外は"偽"を返すという働きをします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2601070/07e70214-86cb-c692-bf24-2e34c893f60a.png)

これで、最大値のみ色を変えることができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2601070/cce20f42-99ac-40a7-d50f-355155daacc7.png)

## 方法③:簡易表計算を使う
この方法は、計算フィールドを使いません。ただ、行っていることは、方法①（RANK関数を使う）こととほぼ同じです。

#1 対象のメジャー（今回は合計売上）を、マークの[詳細]に入れる。
#2 #1のピルを右クリックし、[簡易表計算]→[ランク]を押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2601070/841a3ec6-4ee4-511b-da70-26c016ce19b5.png)
#3 #2のピルを右クリックし、[シェルフで編集]を押し、以下計算式を記載する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2601070/a6f2f35d-5058-7856-8f74-2e51b3cd7d32.png)
#4 このピルを、マークの[色]に入れる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2601070/69c582ff-ef3e-46a1-a869-7e22980e4ae3.png)

## おわりに
最大値だけ強調する方法を3つ共有しました。
どの方法も、計算プロセスは同様だと思いますので、自分に合った方法を使ってもらえたらと思います。
goのO/RマッパーGORMを使用する時、構造体の変数名に数字を付けるとどうなる

goのO/Rマッパー、GORM。
構造体とDB間で、いい感じにデータを変換してくれます。
普通のコードを普通に書いていても、普通に実行してくれるので、最高です！

## GORMがテーブル、カラムをマッピングする仕組み
[公式ドキュメント](https://gorm.io/ja_JP/docs/conventions.html)によると、
>GORMは構造体名をテーブル名としてsnake_casesのように複数形にします。構造体 User の場合、対応するテーブル名は規約により users となります。

>規約に従い、データベースのカラム名はフィールド名のsnake_caseを使用します。

テーブル名もカラム名も基本スネークケースで自動的に変換されるとのことです。

例えば、
```
type User struct {
  ID        uint
  FirstName string
  LastName  string
}
```
のような構造体の場合
```sql:users
-------------------------------
| id | first_name | last_name |
-------------------------------
```
のテーブルと自動的にマッピングしてくれます。

## 構造体の変数名に数字を付けると
例えば、実例は存在するか不明ですが、２つのFirstNameを持つことになったので、末尾に数字を付けて区別するとします。
```
type User struct {
  ID            uint
  FirstName2023 string
  FirstName2024 string
  LastName      string
}
```

この場合
```sql:users
------------------------------------------------------
| id | first_name_2023 | first_name_2024 | last_name |
------------------------------------------------------
```
のテーブルと自動的にマッピングされそうですが、実際は
- `FirstName2023`と`first_name_2023`
- `FirstName2024`と`fitst_name_2024`

は自動マッピングされません。そして困るのはエラーにもならないので、原因不明のまま時間ばかり過ぎてしまうことになります・・・

## 解決策
はちゃんと用意されています。
>column タグか NamingStrategy を利用することでカラム名を上書きできます。

出典元：[GORM 規約](https://gorm.io/ja_JP/docs/conventions.html#%E3%82%AB%E3%83%A9%E3%83%A0%E5%90%8D)

今回の例でいうと
```
type User struct {
  ID            uint
  FirstName2023 string `gorm:"column:first_name_2023"
  FirstName2024 string `gorm:"column:first_name_2024"
  LastName      string
}
```
と構造体のフィールドに`column`タグを付けることで、目的のテーブルとちゃんとマッピングできるようになります。

## 番外編
構造体名とテーブルがうまくマッピングされない場合もちゃんと解決策が用意されています。
```
func (User) TableName() string {
  return "custom_table_names"
```
のようにテーブル名を返すメソッドを用意し、目的に合ったテーブル名を返すことで実現できます。

## 公式ドキュメントは正義
公式ドキュメントに使用方法が記載されているので、隅々から読んでいたら困ることはないでしょう。

実際ライブラリを使う時に、必要なところだけ読んで雰囲気で使う癖がありました。イレビュラーなケースに遭遇して初めてその問題解決方法を調べるわけです。Google検索でサクッと解決できる場合もあれば、時間をかけてやっと公式ドキュメントにたどり着くこともあります。

もちろん、それぞれメリット・デメリットがあるので正解はありません。公式ドキュメントを一度熟読していると知識はもちろんのこと見方まで変わりそうなので、一度試してみたいですね。
【環境構築/Snowflake】SnowSQLをインストールしてから、使用できるようにするまでにつまづいたエラーについて

# 今回の課題
`$ brew install snowflake-snowsql --cask`コマンドでSnowSQLをインストールし、
`$ snowsql -v`コマンドを実行したところ、以下のエラーが発生してしまったので解決する。

### エラー1
```
$ snowsql -v
zsh: command not found
```

### エラー2
```
$ snowsql -v
We were unable to create or write to the ../snowsql_rt.log_bootstrap. Make sure you have permission to write to the log file's parent folder or to modify the location of the log file specified in the SnowSQL log_file configuration option. See docs: https://docs.snowflake.com/en/user-guide/snowsql-config.html#log-file
Observed error: [Errno 13] Permission denied: '/Users/snowsql_rt.log_bootstrap'
```
エラーメッセージは、以下の不具合をお知らせしてくれていた。
```
./snowsql_rt.log_bootstrap を作成または書き込むことができませんでした。
ログファイルの親フォルダに書き込む権限があるか、
SnowSQL log_file 設定オプションで指定されたログファイルの場所を変更する権限があることを確認してください。
```




# 解決した方法
## エラー１の解決方法
### エイリアスを設定する
zshを使用するにあたって、パスが通っていないため、
`.zshrc`にエイリアスを設定してパスを通す必要があるようだった。

`vi`コマンドを実行して`.zshrc`ファイルに以下を追記した。
```
$ vi ~/.zshrc
```
```.zshrc
alias snowsql=/Applications/SnowSQL.app/Contents/MacOS/snowsql # ファイルにこちらを追記
```
`.zshrc`ファイルの`alias`は、コマンドの別名(エイリアス)を定義するための設定のこと。

以上のように`.zshrc`ファイルを設定して、CLIにて以下のコマンドを実行すると、
```
$ snowsql -v
```
以下のコマンドが実行されるようになるというイメージ。
```
$ /Applications/SnowSQL.app/Contents/MacOS/snowsql -v
```

これが**エイリアスを設定する**ということ。

以上のように進めたうえで、
改めてsnowsqlのバージョンを確認すると、バージョンが表示されるようになった。
```
$ snowsql -v
Version: 1.2.10
```

これで、**エラー１**は解決できた！


## エラー２の解決方法
### デフォルトのログファイルの保存場所を変更する
デフォルトのファイルのログファイルの保存先が`../snowsql_rt.log`になっているが、
`~/.snowsql/snowsql_rt.log`にする必要がある様子。


以下の記事を参考に`vi`コマンドを実行して、
`.snowsql`ディレクトリの`config`ファイルのlog_file部分を変更して、
`~/.snowsql/snowsql_rt.log`にログファイルが保存されるように設定をした。
```
$ vi ~/.snowsql/config
```
```config
# main log file location. The file includes the log from SnowSQL main
# executable. #log_file  = ../snowsql_rt.log        # ここをコメントアウトし、
log_file = ~/.snowsql/snowsql_rt.log                # こちらの行を追加する
```

※参考記事

https://note.com/shohey_tech/n/n481baa6e236f


# おまけ
## `.zshrc`とは
zshの設定ファイルのこと。
このファイルを編集することで、zshの動作をカスタマイズすることができる。

具体的には`.zshrc`ファイルには、以下のような内容が含まれる。

* シェルのエイリアスやショートカットコマンドの定義
* 環境変数の設定
* PATHの設定
* プロンプトの設定
* 起動時に自動実行されるコマンドやスクリプトの設定

これらの設定でzshシェルの動作や環境をカスタマイズすることで、
作業の効率を向上させたり、使いやすさを向上させたりすることができる。

# まとめ
以上のように、発生したエラーを解決することができた。

snowsqlのパスを通すにあたって、自分のmacではzshを使用していたので、`.zshrc`ファイルでエイリアスを設定する必要があった。
bashを使用している場合は、`.bash_profile`ファイルで設定をする必要があり、使用しているシェルによって設定ファイルが異なるということを学ぶことができた。
ハッキングラボの環境構築2023 Kail-Linux インストール編

ハッキングラボを読んでいます。発売当初と異なる部分があり、少し困ったので書いておきます。

# 対象範囲
Kail-Linux DL ~ Virtual box へのインポート(P39~43)

# Kail-Linux DL
[こちら](https://www.kali.org/get-kali/#kali-virtual-machines)からVirtual-Box向けをDLする。
[7-zip](https://sevenzip.osdn.jp/)を使って解凍する。

# virtual boxにインポート
[公式ドキュメント](https://www.kali.org/docs/virtualization/import-premade-virtualbox/)を見ながらインポートする。

# 起動時の注意
ハッキングラボに書いてあるuser nameとpasswordでは入れませんでした。私の場合、こちらで入ることができました。
user name: kali
password: kali
参考 [Kali's Default Credentials(公式)](https://www.kali.org/docs/introduction/default-credentials/)

# 最後に
まだ読み始めたばかりなので、このやり方で不具合あるかもしれません。その場合は随時修正していきます。また、間違っている部分あればご指摘いただけると大変助かります。
HSPでサクッと一人称視点カメラを作る

プログラミング初心者です、備忘録として書き記しておきます
プラグインはhgimg3

# 方針
カーソルをウィンドウ中央に固定し、ウィンドウ中央からのカーソル移動量をカメラ角度に加算・減算してあげる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3298587/879d747e-d763-bffd-41f5-978eb7ef809e.png)
# 注意点
mouse命令で設定する座標はディスプレイ上での座標なため、現在のウィンドウ位置、ウィンドウ枠の大きさを考慮して設定する必要がある

例)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3298587/60ba5c1f-7b2d-7741-b355-27690cef79ba.png)
# コード
視点操作のみのサンプル
y方向の視点角度を制限してないのでマウスを上下に動かし続けるととバク転・前転のような視点に…
~~~HSP:FirstPerson.hsp
#include "hgimg3.as"

hgini

;カメラ初期位置、初期角度
selpos : objset3 0,-6,0 
selcang : objset3r 0,0,0

;床作成
addmesh mdpl,32,32,16,512,512,2
regobj obpl,mdpl

;箱作成
setcolor 255,0,0
addbox mdbx,16,16
repeat 32
regobj obbx,mdbx
x=rnd(32) : z=rnd(32)
bx=x*16-(256-8) : bz=z*16-(256-8)
selpos obbx : objset3 bx,-6,bz
color
loop

;感度
sens=0.005

*main

    winposx=ginfo(4) : winposy=ginfo(5)  ;ウィンドウ左上位置
	winw=ginfo(12)  : winh=ginfo(11)     ;ウィンドウ横幅・縦幅(枠あり)
	winactw=ginfo(10) : winacth=ginfo(13);ウィンドウ横幅・縦幅(枠なし)
	
	zureh=(winactw-winw)/2 ;サイドの枠の厚さ
	zurev=(winh-winacth)-zureh ;上側のずれ

	centerx=winposx+zureh+(winactw/2) ;マウス中央位置=ウィンドウ左上位置+枠サイズ+ウィンドウ幅/2
	centery=winposy+zurev+(winacth/2)
	
	x=mousex : z=mousey 
	
	mdx=winactw/2-x : mdz=winacth/2-z　;カーソル移動量観測
	
	mouse centerx,centery　;カーソルを中央に固定
	
	selcang : objgetfv angle　;カメラ角度に反映

	angle(1)+=sens*mdx
	angle(0)+=sens*mdz
	
	objsetfv angle

hgdraw
hgsync 20
goto *main

~~~
# その他
d3moduleを用いた一人称視点カメラの例: 
http://hsp.tv/play/pforum.php?mode=pastwch&num=81890
Bardで問題を解いてみた

Bardでつぎの問題を解いてみた(2023/5/13)。
```
$x$と$y$を加えたら$10$になった。また、$x$と$y$の差は$2$である。
$x$と$y$の値を求めたい。
```
Bardの解答はつぎである。
方程式 x+y=10 と x−y=2 を解くには、置換法を使用できます。x+y=10 の式から y を解くと、y=10−x となります。この式を x−y=2 の方程式に代入すると、x−(10−x)=2 となります。これは、2x−10=2 と書き直すことができます。両辺に 10 を加算すると、2x=12 となります。両辺を 2 で割ると、x=6 となります。この値を y=10−x に代入すると、y=10−6=4 となります。したがって、x=6 と y=4 です。
勉強メモ_Pythonライブラリについて(人工知能プログラミング03回)

# はじめに
* 情報系の学部に所属する学生です。
* 人工知能プログラミングの授業で与えられたコードがよくわからなかったのですが、ライブラリを全部調べたら意外と分かったのでそのメモを残します。
* 正確さに欠ける点もあると思いますが、ご了承ください。

# Tensorflowについて
[こちら](https://udemy.benesse.co.jp/data-science/ai/tensorflow.html)のサイトを参考にしました。
* Googleが開発した機械学習用ライブラリ
* ニューラルネットワークの構築、訓練のシステムを作成するのに優れている。
    * データの読み込み、前処理、計算、上体、出力処理にテンソル(多次元配列のようなもの？)を用いる。
    * 分散学習ができるためどんな環境でも扱える。
* 問題点
    * 分散学習の実行によって障害が起こる可能性がある。(Fault Toleranceで障害を防いでいる。)
    * ハードウェアの性能もある程度必要。

Tensorflowってテンサーフローかと思ってました（笑）正しくはテンソルフローですね。

# Kerasについて
[こちら](https://keras.io/ja/)のサイトを参考にしました。
* Pythonで書かれたTensorflowまたはCNTK、Theano上で実行可能な高水準のニューラルネットワークライブラリ
* 容易に素早くプロトタイプの作成が可能。
* CNNとRNNの両方をサポートしている。

# 環境
Google Colaboratory

## ライブラリのインポート
```python:import
from tensorflow import keras
from tensorflow.keras import initializers as Init
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Activation,  Dense, Dropout, Flatten
from tensorflow.keras.layers import BatchNormalization
from tensorflow.keras.regularizers import l1, l2, l1_l2
from tensorflow.keras.datasets import mnist
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.optimizers import SGD, Adam
import numpy as np
```
とりあえずkerasのインポート、kerasの各機能をインポート
* initializers
    どうやら重み変数などを初期化するためのkerasライブラリ
* Sequential
    Sequentialモデルのひな形のようなもの。`.add`メソッドでレイヤーの追加、`compile`で学習処理の設定、`fit`メソッドでモデルの訓練が行える。
* Activation
    層を生成するライブラリ。使用すると出力に活性化関数を適用できる。
* Dense
    層を生成するライブラリ。使用すると全結合層を生成する。
* Dropout
    入力にドロップアウトを適用できる。ドロップアウトとは訓練時にランダムにユニットを欠落させること。過学習の防止に役立つ。
* Flatten
    入力を平坦化（配列の次元を全部同じに）する。
* BatchNormalization
    各バッチごとに前の層の出力を正規化（使いやすいいい感じの形にすること？）する。
* l1,l2,l1_l2
    正則化に用いる。
* mnist
    手書き数字のデータセット。
* to_categorical
    整数のベクトルを2値クラスの行列へ返還する。[Keras Documentation](https://keras.io/ja/utils/#to_categorical)の例がわかりやすい。
```python
# Consider an array of 5 labels out of a set of 3 classes {0, 1, 2}:
> labels
array([0, 2, 1, 2, 0])
# `to_categorical` converts this into a matrix with as many
# columns as there are classes. The number of rows
# stays the same.
> to_categorical(labels)
array([[ 1.,  0.,  0.],
       [ 0.,  0.,  1.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.],
       [ 1.,  0.,  0.]], dtype=float32)
```
教師信号をone-hotラベルに変換するのに便利！
* SGD
    確率的勾配降下法を実装する。
* Adam
    最適化アルゴリズムの一つ。今回は使われていない。
Arch LinuxにBraveをインストールする

インストールしたての、ほぼまっさらのArchにBraveをインストールしたときのメモです。

[このリンク](https://snapcraft.io/install/brave/arch)通りにしましたが、必要なパッケージが多くて、割と面倒くさかったので残しておきます。

エラーを出して、pacmanでインストールしてということを繰り返したので、その手間を少しでも減らせればと思います。

※再現したら必ず成功するとは限りません。間違っていたらすみません。

# インストール手順


まずこのあたりをインストールします。
```zsh
sudo pacman -Syu \
fakeroot \
go \
go-tools \
python \
python-build \
python-installer \
python-setuptools \
python-docutils\
gcc \
pkgconf \
make \
autoconf \
base-devel
```

次に`snap`をインストールします。

```zsh
git clone https://aur.archlinux.org/snapd.git
cd snapd
makepkg -si
```

エラーが出たら、おそらくパッケージが足りていないので`pacman`でインストールしてください。

```zsh
sudo systemctl enable --now snapd.socket
sudo ln -s /var/lib/snapd/snap /snap
```

しばらく待ってから、次のコマンドを実行します。

```zsh
sudo snap install brave
```

おそらく、スタートメニューにまだbraveが表示されていないと思いますが、再起動すると表示されると思います。
【Streamlit】ウィジェット(チェックボックス/セレクトボックス/テクストボックス/スライダー)

# ウィジェットとは

UI(ユーザーインターフェース)
各機能のパーツ。

# チェックボックス

チェックボックスにチェックが入ったら、画像を表示する。という機能を作ります。

```py:
if st.checkbox('画像を表示'):
    img = Image.open('sample.jpg')
    st.image(img, caption='Super Mario', use_column_width=True)
```

通常時

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/34ccf210-98e2-5c78-8e76-010c7497086d.png)

チェックを入れる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/acb314b8-5661-0258-9dad-d604da93eff3.png)

# セレクトボックス

```py:
option = st.selectbox(
    'あなたの誕生月は？',
    list(range(1, 13))
)

'私の誕生月は', option, 'です。'
```
結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/927ddd1c-1fa5-7921-1fff-8b53fc3a8007.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/163ba3b3-126f-b84e-1551-4d571188f43e.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/24b7ee4b-75e9-676f-45bf-bab6681cf43a.png)

これだけでセレクトボックスが簡単に生成できました。
変数の値も選択した項目に合わせて変化します。

```py:
option = st.selectbox(
    'あなたの教科は？',
    ['国語', '数学', '英語', '理科', '社会']
)

'私の好きな教科は', option, 'です。'
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/fc57b3a6-8505-8eb9-5dbb-a0b659f91c34.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/34d6fb07-e5de-71c4-3f4d-fa42204f0f50.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/71c31944-529e-9499-780d-4da80ceeca7d.png)


# テキストボックス

```py:
text = st.text_input('あなたの好きな料理は？')

'私の好きな料理は', text, 'です。'
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/56f4ca6b-6a72-5e48-ad76-cd7f998172e0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/8e6b03ed-4056-f462-f0c6-3b7d9c74e832.png)

# スライダー

```py:
# 第二引数(最小値、最大値、初期値)
age = st.slider('あなたの年齢は？', 0, 100, 10)

'私の年齢は', age, '歳です。'
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/f3d675b3-2be1-dc34-8c0c-a9d00076b14d.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/4a96a5a1-ddd1-96c2-d828-ddd655408f8b.png)