OmniAICreator/Qiita-1.07M huggingface dataset:
TomcatをWindowsサービスとして登録

## 環境
・WindowsServer2022(AWSのEC2を使用)
・ApacheTomcat9.0.68
・JDK 8u351

## JDKインストール
Tomcatを動作させるためにはJDKが必要なのでJDKのインストールを行います。(JDK：Javaで開発を行うために必要なソフトウェアをまとめたパッケージ)
①自端末に[Oracleの公式サイト](https://www.oracle.com/java/technologies/downloads/#jdk19-windows)からJDKのインストーラーをダウンロードします。なお、ダウンロードにはOracleのアカウントの作成が必要だったので作成しました、無料です。(バージョンは8u351のものをダウンロード)

②インストール先(EC2)にモジュールをコピーします。(デスクトップ)

③インストーラーをダブルクリックしてインストーラーを行います。インストール先のみ(Cドライブはいかに「java」というフォルダを作成し、そこを指定しました。)![スクリーンショット 2022-11-07 230527.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823786/472d0c2c-43cf-d515-15ce-75dd60042031.png)

④環境変数を設定します
pathとJAVA_HOMEの環境変数を下記のように追加します。(JAVA_HOMEは新規作成)
![スクリーンショット 2022-11-07 230829.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823786/43a0ebe7-88b0-229e-ba3a-bfe62eef8be7.png)
![スクリーンショット 2022-11-07 230916.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823786/980dfc12-d1e4-8c9a-bd68-49764ffa6b8e.png)

⑤Javaのバージョン確認
最後にコマンドプロンプトを開きjavac -versionコマンドを実行しjavaのバージョンが表示されればOKです

![スクリーンショット 2022-11-07 231834.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823786/8369bf2f-f63c-a426-ad4f-4797ea960045.png)


## Tomcatインストール
①自端末にTomcatを[公式ページ](https://tomcat.apache.org/download-90.cgi)からダウンロードしてきます。バージョンは9系の最新のものを選択しました。

Windows版(zip形式のものを選択)
![スクリーンショット 2022-10-30 220410.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823786/2bea40b0-2617-98b5-8073-2e10484e79c0.png)

②インストール先(EC2)にモジュールをコピーします。(デスクトップ)

③モジュールを解凍(Cドライブ直下に「tomcat」フォルダを作成し、そこに解凍します。

![スクリーンショット 2022-11-07 223613.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823786/6cec1ad2-ea9e-4b03-4837-5abfde3db005.png)
)

④環境変数を設定します
pathとCATALINA_HOMEの環境変数を下記のように追加します。(CATALINA_HOMEは新規作成)
![スクリーンショット 2022-11-07 232329.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823786/dad066c1-28be-846a-90be-041c4d358350.png)

(CATALINA![スクリーンショット 2022-11-07 232247.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823786/1c543204-eb5a-c28f-9631-ed5ed4cfeb40.png)

⑤ひとまず手動実行できるか確認します
「C:\tomcat\apache-tomcat-9.0.68\bin\startup.bat」をダブルクリックで実行し、コマンドプロンプトが現れます。しばらく待ち、「Server startup」と表示されれば起動完了です。ブラウザを開いて「http://localhost:8080」を入力するとTomcatのスタートページが表示されました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823786/af7eb5f1-4e0a-9da6-1172-1ee8503cf410.png)

⑥Windowsサービスとして登録する
コマンドプロンプトを開き、Tomcatのインストール先まで移動します。
「service.bat install」コマンドを実行するとWindowsサービスに登録されます！
![スクリーンショット 2022-11-07 233702.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823786/47f5db7a-81f2-1cd5-e496-6cf62f7de8d5.png)

![スクリーンショット 2022-11-07 233858.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823786/ee46e318-3e58-dd71-7690-b1abebd290e3.png)



## 参考サイト
https://eng-entrance.com/java-install-jdk-windows
https://eng-entrance.com/java-servlet-tomcat-install
デプロイ後に発見したJavaScript難読化の落とし穴

# はじめに
この間、Webサービスの追加機能デプロイ時に **「[uglifyjs-webpack-plugin](https://www.npmjs.com/package/uglifyjs-webpack-plugin)」** というNode.jsのライブラリを使ってJavaScriptの難読化を行なったところ不具合が発生しました。
しかし原因はライブラリでもバージョンのズレなどでもなく、「ソースコードの難読化」自体にありました。
この記事では、**「JavaScriptの難読化」** に潜む落とし穴とその対策についてお話しします。
私自身考えもしなかった落とし穴でしたので、皆様もぜひ参考にしてください。

# ソースコードの難読化とは
[なぜ、JavaScript を難読化する必要があるのか？](https://www.agtech.co.jp/blog/2021/12/need-for-obfuscation)
こちらの記事がとても参考になりますので、分からない方はご一読ください。

ソースコードの難読化とは、**処理内容を変えず、とにかく読みづらくすること**です。
言っていることそのまんまな気がしますが、具体例を見ていきましょう。
```javascript:javascript
function sum(nums) {
  let result = 0;
  nums.forEach(num => result += num);
  return result;
}
```
このコードは誰が見ても **「数値の和を求める関数」** で、このままではWebサービスのユーザーに簡単に理解されてしまいます。
そこで一般的には、ライブラリなどを用いて以下のように難読化を行います。
```javascript:javascript(難読化後)
function s(n) {
  let r = 0;
  n.forEach(m => r += m);
  return r;
}
```
このように、変数名や関数名、クラス名を意味のない文字列にすることで、
ぱっと見で理解できないソースコードに変換することを難読化といいます。（ざっくり）

# 落とし穴
一見すると、難読化で不具合が発生することは無いように見えます。
しかしあります。**変数名や関数名、クラス名を変えられて困ること**が1つだけあります。

そうです、**その名前の文字列で参照する瞬間**です。
特に動的な言語では名前の文字列を使用することがあると思います。
私が実際にこの落とし穴にハマった時は、このようなコードを書いていました。
```javascript:javascript
// 実際のコードとは異なります
class User {
  // 略
}

if ( (typeof user == 'object') && (user.constructor.name == 'User') ) {
  // 略
}
```
「TypeScript使えー」とか「文字列で判断するなー」とかは一旦置いておいて、
まさに先ほど言った通り **クラス名を文字列を用いて比較** しています。

難読化前は、`user`変数は`User`クラスのインスタンスで、
`user.constructor.name`は`"User"`を返します。

しかしこのコードを難読化すると下のようになります。

```javascript:javascript(難読化後)
// クラス名がUserではない！！
class U {
  // 略
}

if ( (typeof u == 'object') && (u.constructor.name == 'User') ) {
  // 略
}
```
**これが落とし穴です。**
そうです、難読化後の`u.constructor.name`は`"U"`を返すのです。
それはもう難読化前後で挙動が違うわけですね。

## なぜこのようなコードを書いたか
実は、JavaScriptにclassの概念はありません。
classを書いているのは全て見せかけで、実際は全て関数やobjectに翻訳されます。
```javascript:javascript
class User {}

let user = new User();

console.log(typeof User); // => function
console.log(typeof user); // => object
```
そのためJavaScriptでは、そのインスタンスのクラスを判断するには以下のように書きます。
```javascript:javascript
class User {}

let user = new User();

console.log(user.constructor.name); // => User
console.log(user.constructor.name === 'User'); // => true
```
この`constructor`の文字列比較が良くありません。
左辺はソースコードの難読化によって異なる結果を返すからです。

## ではどうすればよいか
結論としては、**難読化するなら文字列で比較するな**ということです。
原因が分かれば当たり前な答えですが、全く考えもしなかった昔の私に言いたいアドバイスでもあります。

今回の例で言えば、以下のように変えることで落とし穴を回避することができます。
```javascript:javascript
class User {
  // 略
}
// == 'User' を == User.name に変える
if ( (typeof user == 'object') && (user.constructor.name == User.name) ) {
  // 略
}
// またはconstructor自体で比較
if ( (typeof user == 'object') && (user.constructor == User) ) {
  // 略
}

// 継承元のconstructorも全て調べられる[2022/11/08追記]
if ( user instanceof User ) {
  // 略
}
```
# 最後に
この記事では私が遭遇したソースコード難読化の落とし穴を紹介しました。
本来であればTypeScriptを用いたり開発ルールを設けたりで回避できるものなので、
皆様もこれを機にぜひ注意してください。
python グラフ描画の配列引数でのエラー

## 背景
配列の1個目の要素の違いにより、エラーになるケースがあり理由を調査する。
下記のケースで、配列の1個目が文字列の時はエラーが発生する。
エラー
~~~
TypeError: 'value' must be an instance of str or bytes, not a float

~~~
strでfloatではない気がするがなぜなのか調査する。

## うまくいく例 (1)
```py
import matplotlib.pyplot as plt
import numpy as np

test_fig = plt.figure()
ay1 = test_fig.subplots()
list1=[1,2,3,4,5,6]
list2=[np.nan, np.nan, np.nan,"80", "40", np.nan]
ay1.scatter(list1 ,list2, c="orange")
test_fig.savefig("save_filename.png")
```

## うまくいく例 (2)
```py
test_fig = plt.figure()
ay1 = test_fig.subplots()
list1=[1,2,3,4,5,6]
#list2=[np.nan, np.nan, np.nan,"80", "40", np.nan]
list2=[8, np.nan, np.nan, np.nan, 4, np.nan]
ay1.scatter(list1 ,list2, c="orange")
test_fig.savefig("save_filename.png")
```
## エラー例
```py
import matplotlib.pyplot as plt
import numpy as np

test_fig = plt.figure()
ay1 = test_fig.subplots()
list1=[1,2,3,4,5,6]
list2=["80",np.nan, np.nan, np.nan, "40", np.nan]
ay1.scatter(list1 ,list2, c="orange")
test_fig.savefig("save_filename.png")
```

エラー
~~~
TypeError: 'value' must be an instance of str or bytes, not a float
~~~

## 調査中
どうやらnp.nanがfloat型の様で、strが最初で2個目がfloat(nan)だとエラーになる？？

```py
import numpy as np

list2=[np.nan, np.nan, np.nan,"80", "40", np.nan]
print(type(list2[0]))
print(type(list2[1]))

list3=["80",np.nan, np.nan, np.nan, "40", np.nan]
print(type(list3[0]))
print(type(list3[1]))
```
~~~
<class 'float'>
<class 'float'>

<class 'str'>
<class 'float'>
~~~
【Perl初学者】正規表現

# 目次
- 正規表現とは
- 現場での活用方法

# 正規表現とは

通常の文字列と特別な意味を持つ文字を組み合わせることで
**先頭がABで始まり末尾がDEで終わる**
**Aで始まり３文字から５文字の数字が続く**
などの条件に一致するすべての**文字列**を表すパターンを作成することができる。
基本的には文字列を扱う方法なんですね。

# 現場での活用方法

送られてきた引数の中身が正規表現でパターン化した内容と合っているかどうかの比較の際に使用します。
例えば**Takopaは（iphoneまたはAndroid）を使用しています**というように表現することができる。
正規表現を使用していない場合、iphoneと一致しながらAndroidと一致するか...プログラムをしていく必要があります。
正規表現は可読性(コードの読みやすさ)をあげるメリットがあるんですね。

もうひとつ例があげます。
入力された文字列が携帯電話番号かどうかを確かめる方法について
正規表現だと
^0[789]0-[0-9]{4}-[0-9]{4}$
携帯電話が070,080,090の３種類があるので,このような記述にしました。表現内に使われている^,[],{},$は文字列の設定などができる特殊あいみを含んでいる記号です。
話が長くなってしまったのでよく使われる正規表現一覧をこちらの記事に書きました。[よく使われる正規表現一覧](https://qiita.com/takopa/items/abaebb2b6c738acbe792)
WEB×マニュアル×書き方

先日パソコンのデータが紛失してしまい、バックアップをとっていないデータが、かなり無くなってしまいました。今までGitHubに公開せずに利用していたコードなどもなくなってしまい、1から調べなおさないとコードが書けなくなりました。まだ、分かりやすく書かれているサイトや動画はときはいいのですが、自分が書いたコードが使いたい場面も多いです。

バックアップをしっかりしていなかったことをものすごく後悔しました。そこで、今一度、自分が見ても、分かるようにWEB上に自分のコードや調べたことをまとめる必要があると思いました。よくエンジニアに言われる「アウトプットが大事」「他人が見ても分かるよう書く」ことが、本当に大事だということに改めて気づかされました。

実際書き始めるにあたって、参考にするものとしては、マニュアル、手順書、レシピなどです。これらの書き方やルールについてまとめようと思います。

今回の調べ方としては「マニュアル　書き方　コツ」で検索して、ヒットした動画を上から3本見たものの内容から生かせそうなものをピックアップしました。
ちなみに一番参考にしたサイトは以下のURLの動画です。
https://www.youtube.com/watch?v=qLFjwtMpBbE

3つの動画に共通して最初に説明があったことは、「マニュアル作成を行う目的をはっきりさせる」ということです。例えば新人のアルバイトに教える時間を短縮することや部下に業務の引継ぎがしやすくなるなど様々な目的があります。今回の場合は「久しぶりの時や初見の人でも再現が取れるように書く」ということが目的だと思っています。
そのためには、見る人が変わる前提で設計されているべきです。使う言葉や図も誰が見ても分かるように共通したもの、自分の記事を引用やコピペされたとしても、理解できるようにまとめる必要があると考えました。また、一回で完成させるのではなく、改定や改正を前提に作成していくということです。Web上でよく見られる最終更新日のようなものも記載するようにしたいと思います。

具体的なルールとしては、まず三つ考えています。
1概要と詳細を記載すること
2画像や図を入れること
3穴埋め形式でパターン化すること

タイトルは「WEB×マニュアル×書き方」

概要では、1前提知識、2材料、3全体の目次、4目的、5日付、6文字量、７読む時間などを記載しましょう。
今回の場合
1、特になし　２，メモ帳、ペイント、Twitter、Qiita垢　３，詳細7つ　４，マニュアルの型作成　5、22/11/07（1回目）　6、1600字　7、5分

詳細では、図のように一つ一つスクリーンショットやコードの変化が分かるように、すべてに画像を乗せておくべきだと考えました。
1、情報を集める
2、情報をまとめる
3、図を用意する
4、文章で説明する
5、推敲
6、公開
7、反省


１、Webでの検索方法とブックマークのＵＲＬを記載して、上から3つぐらいをコピペして知識を蓄えます。約30分はかかると思います。
![マニュアル3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606732/9c9f5ac0-f1cf-449a-e58d-3406f9d94b11.png)

2、紙に箇条書きなどでまとめるほうがいいです。色をつけたり分類分けしたり色々試してみたいと思います。個人的にはここが一番重要だと考えています。
![マニュアル4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606732/d7543bbe-6fbe-7d81-9f3f-4a8938ae956e.png)

3、必要がある画像の数を先に決める（7工程以下）にするというルールを継続してみたいと思います。これをオーバーする場合は記載する工程で省くか、別のレシピやマニュアルを参照してくださいという方法で別のページ上に誘導することをおすすめします。
![マニュアル5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606732/fb78d48e-b0a8-6984-4be4-19ff4c3a7480.png)

４、誰が見ても分かるように図やコードに解説を入れましょう。
![マニュアル2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606732/863d9570-48ec-cd90-0e65-8b930bc835ee.png)

５、コツコツと
![マニュアル6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606732/48cdc274-7b16-1917-040e-4fbf0f9ccaf6.png)

６、積み重ねて
![マニュアル7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606732/b621d985-57c4-8421-40c3-e22c4e9b6698.png)

７、繰り返して
![マニュアル8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606732/7c0c3fec-85c7-75e8-2a3b-34ea639ac7a7.png)

まとめでは、最終的な結論をはっきりと述べるようにしましょう。
1概要と詳細を記載すること
2画像や図を入れること
3穴埋め形式でパターン化すること

の3つがマニュアル作成では大切だと考え実践してみましたが、１は詳細がハッキリとしていないと感じました。テーマにもよりますが、「水100mlを入れ中火で５分加熱」ぐらい具体的に書けるようにしたいです。２の図に関しても時間がかかりすぎないように効率よく準備できるツールや方法を見つけたいです。３に関してはコツコツと積み重ねて繰り返して、練習してパターンが見つかると信じています。

感想や反省も適当に書きましょう。

結論・・・読みづらすぎるので、他の人が書いた参考になるサイトやマニュアルから勉強してください。
【Perl初学者】よく使う正規表現一覧

# 目次
- [パターンマッチ](#パターンマッチ)
- [置換](#置換)
- [正規表現文字](#正規表現文字)
- [文字列のクラス](#文字列のクラス)
- [文字列の集合](#文字列の集合)
- [量指定子](#量指定子)
- [正規表現のオプション](#正規表現のオプション)
- まとめ

# パターンマッチ

|  | 意味 |
|:-:|:-:|
|   　　　=~　　　  |  文字列と正規表現を比較する際に使う 例 Takopa =~ /^T\w{5}$/ |
| 　　　( )　　　  |  対象の文字列と()の中身がマッチした場合に,()の中身を取得する(グループ化)  |
|  　　　/ /　　　  |  対象の文字列を`/`から`/`までの正規表現で比較する  |

# 置換

|  | 意味 |
|:-:|:-:|
|    　s　    |  文字列を置換　例　s/パターン/置換文字列/  |
|    $1    | グループ化した部分を$1に格納できる  |

# 正規表現文字

|  | 意味 |
|:-:|:-:|
| 　\d　  | 0~9の文字  |
| 　\D　  | 0~9以外の文字  |
| 　\w　  | a~z,A~Z,0~9,_（アンダーバー）  |
| 　\W　  |  a~z,A~Z,0~9,_以外 |
|  \s  | スペース, tab文字, 改行などの空白文字  |
| 　\S　  | スペース, tab文字, 改行以外  |
| 　　.　　  | 改行を除くすべての文字  |

# 文字列のクラス

|  | 意味 |
|:-:|:-:|
| 　[　]　  |　[]内のどれか一つにマッチした場合 例) `p1, q1, r1 -> [pqr]1 #どれも当てはまる` |

# 正規表現のオプション
| 1 | 2 |
|:-:|:-:|
| 　　s　　  |  改行を.にマッチさせる |
| g  | マッチしたすべての文字列を置換する  |

# まとめ

正規表現は覚えることが多く現場で使われているのは基本複雑な書き方になっているので、１つ１つの意味を読み解いていくのが大事だと思う。
関数をラップする関数を返す関数の型のメモ


なんのこっちゃというタイトルですが

既存の関数の前後にログを仕込んだ新しい関数を作ったりなど、既存関数のシグネチャを保ったまま、新しい関数を作成したい場合があります。

その場合の型定義のメモです。

## サンプル

``` ts
function withXxxx<T extends any[], U>(
  func: (...args: T) => U
): (...args: T) => U {

  return function (...args: T) {
    return func(...args);
  };
}
```

既存関数の引数を `T extends any[]` で表し、戻り値を`U` としてそれをそのまま返すようにすれば良いです。

(ラップした関数から既存関数の名前が消えてしまうのがデメリットですが..)

### 実際の例

前後にログを仕込む関数の場合

``` ts
function withLogging<T extends any[], U>(
  name: string,
  func: (...args: T) => U
): (...args: T) => U {
  return function (...args: T) {
    try {
      console.log(`${name}:begin`, ...args)
      const returnValue = func(...args);
      console.log(`${name}:end`, returnValue)
      return returnValue;
    } catch (e) {
      console.error(`${name}:error`, e)
      throw e;
    }
  };
}

// ２つの引数を加算する関数
function sum(left: number, right: number): number {
  return left + right
}

// 可変長引数の引数を加算する関数
function sumAll(...args: number[]): number {
  return args.reduce((p, c) => p + c)
}

// 共に元の関数と同一の型定義
const sumLog = withLogging("sum", sum)
const sumAllLog = withLogging("sumAll", sumAll)

console.log(sumLog(4, 2))
// sum:begin 4 2
// sum:end 6
// 6

console.log(sumAllLog(1,2,3,4,5,6,7,8,9,10))
// sumAll:begin 1 2 3 4 5 6 7 8 9 10
// sumAll:end 55
// 55
```


複数の関数をつなげると処理が追いにくくなるので、使用する場面は限られるかもしれないですが
覚えておくと何かの役に立つと思います。
多言語FizzBuzzチャレンジ15日目:Elixir

## これまでのまとめ
https://qiita.com/tenteko/private/fc52f7aec63ba5f67854

https://qiita.com/tenteko/private/ca9813f0982370d0c901

https://qiita.com/tenteko/private/bc808ba59f6993019045

https://qiita.com/tenteko/private/74aa4c422196cb5cdeac

https://qiita.com/tenteko/private/ea22bd19360333f9ca85

https://qiita.com/tenteko/private/ec2f7c2f99229a55a7aa

https://qiita.com/tenteko/private/237556777f5c5546af6e

https://qiita.com/tenteko/private/264e4aca8a2ee6761a6c

https://qiita.com/tenteko/private/6e86fa0eeed9d24805ab

https://qiita.com/tenteko/private/f32baaf43fe0217b7fc7

https://qiita.com/tenteko/private/b44e1e5bfc91f6f3a52f

https://qiita.com/tenteko/private/333b9697c03561fb6158

https://qiita.com/tenteko/private/667f5f69eda60f221912

https://qiita.com/tenteko/private/eff296000ecbc7b43f07

## 本日のお品書き
Elixirさん。名前がときめきますね…。
F#の時も思いましたが、関数型言語に不慣れすぎてちょっと身構えてしまいますね。

## FizzBuzz
```elixir:fizzbuzz.exs
# 匿名関数をfizzbuzzに割り当てている
fizzbuzz = fn(x) ->
  # switchやcaseに相当する。もっと上手なやりかたもありそうだが…。
  cond do
    # 剰余の計算は%ではなくrem
    rem(x, 15) == 0 -> IO.puts "FizzBuzz"
    rem(x, 3) == 0 -> IO.puts "Fizz"
    rem(x, 5) == 0 -> IO.puts "Buzz"
    true -> IO.puts x
  end
end

# 匿名関数に引数を与える際は.(x)らしい。このドットが何者なのか、調べてもわからず。
# パイプを使うと関数感ありますね（個人的感想）
1..100 |> Enum.map(fn(x) -> fizzbuzz.(x) end)
```

## おまけ
Onlineでの良い実行環境を見つけられなかったため、今回はDockerで環境を構築しました。

```dockerfile
FROM elixir
COPY ./fizzbuzz.exs /
CMD ["elixir", "fizzbuzz.exs"]
```

```shell
docker build -t elixir:fizzbuzz .
docker run --rm elixir:fizzbuzz
```
【MapLibre GL JS】ラスタータイルを表示する

## はじめに
この記事は#30DayMapChallenge2022 7日目の記事です。
テーマはRasterです。
MapLibre GL JSを使ってラスタータイルを表示してみます。

![image](https://raw.githubusercontent.com/tjukanovt/30DayMapChallenge/main/images/flyers/30dmc-2022.png)

https://30daymapchallenge.com/

## タイルとは
タイル状の地図データのこと
ズームレベルを大きくするとタイルの数が増える

地図の配信配信方式には、XYZ方式とWMSがあり、XYZ方式がデファクトスタンダードになっている
- あらかじめタイル状に分割したデータを配信する方式（XYZ方式）
![image](https://maps.gsi.go.jp/help/image/method_tile.png)

- 地図表示のリクエストがある度にその範囲をサーバ側で切り抜いて配信する方式（WMS：Web Map Service）
![image](https://maps.gsi.go.jp/help/image/method_wms.png)

タイルの形式には、ラスタータイルとベクトルタイルがある

出典：[国土地理院ウェブサイト](https://maps.gsi.go.jp/development/siyou.html)

## ラスタタイルとは
地図の内容をピクセルごとの色情報（＝画像）として格納する
色や太さなどのスタイルを変更することができない

## ベクトルタイルとは
地図の内容をテキストとして格納する
地物の種類に応じてスタイルを設定することができる

![image](http://maps.gsi.go.jp/help/image/vt1.png)

出典：[国土地理院ウェブサイト](http://maps.gsi.go.jp/development/vt_expt.html)


## 地図表示
ラスタータイルを表示してみます。
[地理院タイル](https://maps.gsi.go.jp/development/ichiran.html)から、好きなタイルを選びます。
今回は、標準地図を選択しました。

```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>サンプル</title>
    <meta name="description" content="サンプルです">
    <link href="style.css" rel="stylesheet">
    <!-- MapLibre -->
    <script src='https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.js'></script>
    <link href='https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.css' rel='stylesheet' />
</head>
<body>
    <div id="map"></div>
    <script src="main.js"></script>
</body>
</html>
```

```style.css
body {
    margin: 0;
    padding: 0;
}
#map {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 100%;
}
```

```main.js
var map = new maplibregl.Map({
    container: 'map',
    style: {
        version: 8,
        sources: {
            rtile: {
                type: 'raster',
                tiles: [
                    'https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png',
                ],
                tileSize: 256,
                attribution:
                    "地図の出典：<a href='https://www.gsi.go.jp/' target='_blank'>地理院タイル</a>",
            },
        },
        layers: [
            {
                id: 'raster-tiles',
                type: 'raster',
                source: 'rtile',
                minzoom: 0,
                maxzoom: 22,
            },
        ],
    },
    center: [139.68786, 35.68355], // 中心座標
    zoom: 13, // ズームレベル
});
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/c8f4b57c-79e9-f35a-dd7f-e626eb0554c4.png)

地理院地図（ラスタータイル）を表示できました！

開発者ツールを開き、「ネットワーク」タブを見てみると
タイルが画像で配信されているのが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/b5f35fb3-282f-21d9-f7b7-ac6013bfd8a3.png)



## 参考文献
https://maps.gsi.go.jp/development/siyou.html

http://maps.gsi.go.jp/development/vt_expt.html

https://maplibre.org/maplibre-gl-js-docs/example/map-tiles/
PyTorchでIoUを求める (torchmetricsのiouモジュールは廃止済)

# 概要

Semantic Segmentationを実施する際、IoU (Intersection over Union)を計算すると思います。

2021年末迄は`torchmetrics.functional`からで、`iou`モジュールをインポートすれば計算できていたのですが、バージョンアップにより`jaccard_index`に変更になっています。[^1]

このことに気付かず最初少し苦戦したので、記事として記録しておきます。

公式ドキュメント: https://torchmetrics.readthedocs.io/en/stable/classification/jaccard_index.html


[^1]:https://github.com/Lightning-AI/metrics/pull/662/commits/2e96b03de0e0b3a8ddb5010df1df9f5e3197238b

# Jaccard Indexとは

IoUと定義は全く同じです。ある集合とA, 別の集合Bのjaccard indexを$J(A,B)$としたとき、

```math
J(A,B)=\frac{|A \cap B|}{|A \cup B|}
```
と計算されます。

下記サイトが実装例も記載されており、分かりやすいです。

https://mieruca-ai.com/ai/jaccard_dice_simpson/

また、英語ではありますが、Wikiも掲載しておきます。

https://en.wikipedia.org/wiki/Jaccard_index

# 実装例

## UNetの構築

UNet (バックボーン: Resnet18)を用いて、Semantic Segmentationを行います。

Unetは、`segmentation_models_pytorch`ですでにモジュールとして準備されていますので、今回はこちらを使用します。

また、NNの構築にはPyTorchLightningを使用します。

3チャネルの画像を入力するとし、計12クラスのセグメンテーションを実施します。

なお、ここでは必要なライブラリをすでに読み込んでいて、dataloaderも作成後のコードから記載しています。

```python
# segmentation_models_pytorchモジュールの読み込み

import segmentation_models_pytorch as smp

# UNetの構築

class Net_resnet18(pl.LightningModule):
    def __init__(self, in_channels=3, n_classes=12):
        super().__init__()
        
        self.unet = smp.Unet("resnet18", in_channels=in_channels, classes=n_classes, encoder_weights="imagenet")
        
    def forward(self, x):
        return self.unet(x)
    
    def training_step(self, batch, batch_idx):
        x, t = batch
        y = self(x)
        loss = F.cross_entropy(y, t)
        self.log("train_loss", loss, on_step=True, on_epoch=True)
        self.log("train_acc", accuracy(y.softmax(dim=1), t), on_step=True, on_epoch=True)
        return loss
    
    def validation_step(self, batch, batch_idx):
        x, t = batch
        y = self(x)
        loss = F.cross_entropy(y, t)
        self.log("val_loss", loss, on_step=True, on_epoch=True)
        self.log("val_acc", accuracy(y.softmax(dim=1), t), on_step=True, on_epoch=True)
        return loss
    
    def configure_optimizers(self):
        return torch.optim.Adam(self.parameters())
        
```

## 学習実行

上記で定義したUNetをインスタンス化し、学習実行します。

PyTorchLightningの実装に関しては、[こちら](https://qiita.com/ground0state/items/c1d705ca2ee329cdfae4)の記事が分かりやすいです。

```python

pl.seed_everything(0)
net_resnet18 = Net_resnet18(n_classes=12)
trainer = pl.Trainer(max_epochs=30, gpus=1, deterministic=False)
trainer.fit(net_resnet18, train_loader, val_loader)

```

## IoUの計算

`torchmetrics.functional`から`jaccard_index`をインポートし、計算します。

なお、functionalからのインポートであれば、特にjaccard_indexをインスタンス化せずともクラスメソッドとして使用できるので、便利です。

```python

from torchmetrics.functional import jaccard_index

# validation_loaderのデータから、目標値と予測値を計算
y, t = predict(net_resnet18, val_loader, device="cpu")

print("pixel accuracy: ", accuracy(y, t))
print("IoU: ", jaccard_index(y, t, num_classes=12))

```
python備忘録２

制御構文
-
- 繰り返し(for,while)
- 条件分岐(if)
- iterable object -> 反復可能なオブジェクト
```rb
# 10回繰り返す
for i in range(10):
    print(i)
# 012345...9
# 配列アクセス
names = ['佐藤君','金子さん','宮台君']
for i in range(3):
    print(names[i])
# -> 佐藤君　金子さん　宮台君
for i in range(3):
    print('{}さん'.format(names[i]))
```
- len関数を使うと楽よ～
- リストの要素数に応じたプログラムになるよ
```rb
for i in range(len(names)):
    print('{}さん'.format(names[i])
```
- enumerate()をイテラブルに渡すと(要素番号、要素)が返ってくる
```rb
for i, name in enumerate(names):
    message = '{}番目: {}さん'.format(i, name)
    print(message)
    # 0番目: 佐藤さん 1番目: 鈴木さん 2番目: 高橋さん
```
- zip() 複数のイテラブルオブジェクトを受け取り、要素のペアを順番に返す
```rb
names = ['Python', 'Chainer']
versions = ['3.7', '5.3.0']
suffixes = ['!!', '!!', '?']

for name, version, suffix in zip(names, versions, suffixes):
    print('{} {} {}'.format(name, version, suffix))
# -> Python 3.7 !!  Chainer 5.3.0 !!
```
条件分岐(if)
-
```rb
# if の条件を満たす場合
a = 1
if a > 0:
    print('0より大きいです')
else:
    print('0以下です')
# -> 0より大きいです
```
while
-
- 条件を満たす限り処理が行われるよ
```rb
count = 0

while count < 3:
    print(count)
    count += 1
# -> 0 1 2 
count = 0
# trueの限り処理が実行される
while True:
    print(count)
    count += 1
    
    if count == 3:
        break
# -> 0 1 2
```
関数
-
```rb
def double(x):
    print(2 * x)
#関数の実行
double(3)
# -> 6
```
クラス
-
- オブジェクト指向
```rb
# クラスの定義
class House:
    # __init__()メソッド インスタンス化した自分自身
    def __init__(self, name):
        self.name_plate = name
```
```rb
# クラスの定義
class House:

    # __init__() の定義
    def __init__(self, name):
        self.name_plate = name

    # メソッドの定義
    def hello(self):
        print('{}の家です。'.format(self.name_plate))
```
- 二つのインスタンスを作成して、hallo()メソッドを呼び出す
```rb
sato = House('佐藤')
suzuki = House('スズキ')

sato.hello()   # 実行の際には hello() の引数にある self は無視
suzuki.hello() # 実行の際には hello() の引数にある self は無視
- > 佐藤の家です。　スズキの家です。
```
継承
-
- クラスを定義したら、その一部を使ったり、新しい機能をつけ足したりしたくなる。
- これを実現する
- Omochiクラスを定義して、そのクラスを継承した新しいクラスSachanクラスを作る場合
```rb
class Omochi:
    def __init__(self):
        self.a = 1
        self.b = 2
l = Omochi()
l.a
# -> 1
l.b
# -> 2
```
継承してみる
```rb
class Sachan(Omochi):
    def sum(self):
        return self.a + self.b
```
```rb
# sachanクラスをインスタンス化
c = Sachan()
c.a
# -> 1
c.b
# -> 2
# sumメソッド実行
c.sum()
# -> 3
```
- 親クラスのメソッドを呼び出すにはsuper()を使って子クラスから親クラスを参照する必要がある
```rb
class Sachan(Omochi):

    def __init__(self):
        # 親クラスの `__init__()` メソッドを呼び出す
        super().__init__()
        
        # self.c を新たに追加
        self.c = 5
    
    def sum(self):
        return self.a + self.b + self.c

# インスタンス化
c = Sachan()
c.sum()
# -> 8
```
python 備忘録

```rb
#複数代入
a, b, c = 1, 1.5, 'sachan0v0'
#文字列(str)の足し算
name1 = 'sachan'
name2 = '0v0'
name1 + name2  # 'sachan0v0'
```
文字列操作
```rb
name = 'sachan'
# 小文字に変換
name.lower()
# 大文字
name.upper()
# format
name1 = 'sachan'
name2 = 'こんにちは！'

'{} さん！はじめまして！{}'.format(name1, name2)
```
浮動小数点
- as_integer_raito()メソッド
- 浮動小数点 -> 比
- ```rb
    0.5.as_integer_raito()
    # -> (1,2) 1/2
    ```
複合データ型
-
リスト：配列　要素の変更が可能
```rb
#リスト
list = [5,7,8,9,10]
print(list)
# -> [5,7,8,9,10]

len(list) #要素数確認
list[0]   #先頭要素にアクセス
list[1] = 20 # ２番目の要素を書き換え
list[-1]     # -> 10 最後の要素にアクセス　連結データ
# スライス　リストから一度に複数の要素を取り出す
list[0:2]  #  開始位置：終了位置
list[:]    #　全部取り出す
```
リストへの追加 append()
```rb
# 空のリスト用意
array = []
# 空のリストに要素を追加
array.append('omochi')
array.append('konnichiwa')
array
# -> ['omochi', 'konnichiwa']
```
タプル
-
中の要素を途中で変更できない
```rb
#　タプルの定義
array = (3, 4, 5, 6)
# error
array[0] = 10
```
辞書
-
- dict型のkeyvalueストア
- {}で定義　アクセスはdict.key()
- 上書き可能
```rb
# 辞書を定義
scores = {'Math': 90, 'Science': 75, 'English': 80 }
# key が Math の value にアクセス
scores['Math'] 
# キーのリスト
scores.keys()
# -> dict_keys(['数学', '理科', '英語'])
# 値のリスト
scores.values()
# -> dict_values([90, 75, 80])
SAP ABAP Platform 1909, Developer Edition（docker hub）が提供終了になっていた話

[SAP ABAP Platform 1909, Developer Edition（dockerhub）をopenSUSE Leap 15.3（EC2）で起動してみる](https://qiita.com/SAITO_Keita/items/d826c66d0853282f4b9c)

上記記事で、ABAPのDeveloper Editionをdocker hubからダウンロードして、起動するまでの手順をやってみましたが。

提供終了となってしまったようです。

`SAP ABAP Platform 1909, Developer Edition`をインストールする際に確認する [ブログ記事](https://blogs.sap.com/2021/02/15/sap-abap-platform-1909-developer-edition-available-soon/) をみると。

2022年にはいってから雲行きが怪しそうな投稿がされており。
dockerイメージも利用できなくなっていましたが。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/663565b9-d5ff-e397-4d0a-932687fa2bb5.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/29980866-7aaf-035e-8eaa-0981ac7a4a7d.png)

そして10月13日にブログ記事更新され、ブログの記事名も`SAP ABAP Platform 1909, Developer Edition: No Longer Available`になっていました。

なお[SAP Cloud Appliance Library](https://cal.sap.com/)からのデプロイはまだ有効なようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/89978cb4-d505-09bd-f8d0-f0bb77096e1a.png)

今現在、`SAP ABAP Platform 1909, Developer Edition`を用意するためには、`CAL`経由から`Google Cloud Platform`, `Microsoft Azure`, `Amazon Web Services`のいずれかにデプロイする形になるかと思います。

## 総評

ABAPをさわりたい時にdockerで開発環境が用意されるのは、SAPもこんな時代がきたのかといった感はありましたが。
提供終了となってしまい残念です。

色々とありそうですが、なんとか復活してほしい所です。
データウェアハウス層について整理してみた

## データウェアハウス層とは

データレイクにある生データを加工したものが置かれている場所

例：自社ECサイトの売上に付け加えて、サイト外での販売、自社外のWebサイトでの販売などの他の売上も結合したデータがある場所

## DWH層を作る手順

### データクレンジング

データクレンジングとは、データの欠損を埋めたり、重複削除や名寄せを行うこと

名寄せとは、複数のデータベースの中から、氏名、住所、電話番号等の情報を手がかりにして、同じ人物や同じ企業のデータを1つにまとめること

データクレンジングは、オリジナルのデータで複数のデータソースを統合できない場合に実施する

理想は大元のデータソースを修正すべきなので、一時的な処置として行う


:::note info
データレイクでは絶対に行わない
:::

### スタースキーマの作成

スタースキーマとは、データベース内のデータを整理することで、理解や分析がしやすくなった多次元データモデルのこと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673036/18c38805-f465-be34-eb3c-e4f10109a7de.png)
引用元: [スタースキーマとは](https://www.databricks.com/jp/glossary/star-schema#:~:text=%E3%82%B9%E3%82%BF%E3%83%BC%E3%82%B9%E3%82%AD%E3%83%BC%E3%83%9E%E3%81%A8%E3%81%AF,%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82)

データクレンジング後に行う

ファクトテーブルとディメンションテーブルを作成する

- ファクトテーブルとは、イベントの発生ごとに一行で表現したテーブル
- ディメンションテーブルとは、分析の切り口となる属性値を表現したテーブル

7W3Hの形で、属性を洗い出すことでディメンションテーブルは作成可能


### 共通指標

部署横断して問題が起きないように、部署間で同じ認識の指標を作ること

作成方法

- 作成したスタースキーマを使う
- モニタリングしたい指標は何なのか明確にして、ディメンションを使い集計

部署横断の共通指標はデータウェアハウス層で管理し、部署によって用途が異なるデータはデータマート層で管理する

## ポイント

### ****DWH層のデータを分析用DB(DWH製品)に置くべき****

- DWH製品はBIツールや表計算ソフトに参照されるように設計されているが、逆はそうではないため

### DWH層で共通指標を集計すべき

- 部署や部門ごとに指標の捉え方が異なるのは日常茶飯事
- DWH層で共通指標を集計しておけば、今後の部署横断可能なデータ活用が容易になるため

### 早すぎる最適化に注意

- データ活用が進んでいない段階でDWH層を作ることはできない
- なぜなら、共通指標を作る事ができないから
- 上記の場合はデータソースからデータレイク、データレイクからデータマートの両端を充実させ、データ活用を進めた後にDWH層を作る
---
## 参考文献
- [データスキーマとは：databricks社](https://www.databricks.com/jp/glossary/star-schema#:~:text=%E3%82%B9%E3%82%BF%E3%83%BC%E3%82%B9%E3%82%AD%E3%83%BC%E3%83%9E%E3%81%A8%E3%81%AF,%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82) 
- [『実践的データ基盤への処方箋』ゆずたそ  (著), 渡部 徹太郎 (著), 伊藤 徹郎 (著)](https://www.amazon.co.jp/%E5%AE%9F%E8%B7%B5%E7%9A%84%E3%83%87%E3%83%BC%E3%82%BF%E5%9F%BA%E7%9B%A4%E3%81%B8%E3%81%AE%E5%87%A6%E6%96%B9%E7%AE%8B%E3%80%9C-%E3%83%93%E3%82%B8%E3%83%8D%E3%82%B9%E4%BE%A1%E5%80%A4%E5%89%B5%E5%87%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%83%BB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%BB%E3%83%92%E3%83%88%E3%81%AE%E3%83%8E%E3%82%A6%E3%83%8F%E3%82%A6-%E3%82%86%E3%81%9A%E3%81%9F%E3%81%9D/dp/4297124459)
初めてのreact3

## 要素のレンダリング
jsxでReact要素を作成していくことは前回見た。
その要素を如何にしてdomにレンダリングしていくのか、、、

htmlファイルにdiv要素を作る。
index.html
```
<div id="root"></div>
```
属性idをrootとする。
この中にreact要素を詰め込んでいく。

まずはreactにdom要素を読み込ませて、それをレンダリングしていく。
index.js
```
const root = ReactDOM.createRoot( 
  document.getElementById('root') 
); 
const element = <h1>Hello, world</h1>; 
root.render(element);
```
ReactDOM.createRoot()でdom要素を取ってきてrootという変数に入れる。
その変数にroot.render()でjsxで書いたelementという要素をレンダリングしていく。

react要素はイミュータブル、不変である。

## 参考
https://ja.reactjs.org/docs/rendering-elements.html
初めてのreact2

## JSXとは
JSXはjavascriptの構文拡張したもの。
```
const element = <h1>Hello, world!</h1>;
```

JSXはreactの要素を作成。
その要素をDOMにレンダリングする。
DOMとは「Document Object Model」の略だ。直訳すると、「ドキュメントを物として扱うモデル」になる。プログラムからHTMLやXMLを自由に操作するための仕組み。
レンダリングとは↓
https://qiita.com/sasakiki/items/91dcc8b50d7a61ce98bc
簡単に言うとリソースをブラウザ画面に表示する。

JSX内に{}を使用することでjs式を埋め込める。
```
const fruit = 'りんご'; 
const price = 100; 
const quantity = 5; 
const element = <h1>{fruit}を{quantity}個買うと{price * quantity}円です</h1>;
```
関数も可能
```
function formatName(user) { 
  return user.firstName + ' ' + user.lastName; 
} 
const user = { 
  firstName: 'Harper', 
  lastName: 'Perez' 
}; 
const element = ( 
  <h1> 
    Hello, {formatName(user)}! 
  </h1> 
);
```

JSXはなぜhtmlを含めることができるのか？
それはコンパイルされているから。
```
const element = ( 
  <h1 className="greeting"> 
    Hello, world! 
  </h1> 
);
```
↑これが↓のようにコンパイルされている。
```
const element = React.createElement( 
  'h1', 
  {className: 'greeting'}, 
  'Hello, world!' 
);
```


しかしReact.createElementを全てに書くのは面倒なので、JSXでhtmlを含める形式で書いている。

## 参考
https://ja.reactjs.org/docs/introducing-jsx.html
https://tech-blog.rakus.co.jp/entry/20210521/react
ラストのまほう　第19話『グラフィックスコンテキストとカメラ』


ステージやプレイヤーキャラクターを描画するときは、現在のカメラの位置を反映した場所に描画しなければなりません。そのためには、ステージを描画する関数やキャラクターを描画する関数に、現在のカメラの位置の情報を渡す必要があります。このとき、単にカメラの位置を引数に渡して伝播するのではなく、**グラフィックスコンテキスト**としてさまざまな情報をまとめて伝播する設計がよく使われています。今回も自力でそれを定義しておきましょう。

# グラフィックスコンテキスト

グラフィックコンテキストには以下のように、描画位置と`dx`, `dy` と、アニメーションで使う用の現在のフレーム数、それからデバッグ描画をするかどうかというフィールドをもたせました。

```rust 
#[derive(Clone, Copy, Default)]
pub struct Graphics {
    pub frame_count: u32,
    pub debug: bool,
    pub dx: i32,
    pub dy: i32,
}
```

それから、画像を描画するメソッドをこのグラフィックスコンテキストに生やします。このとき、グラフィックコンテキストの描画位置を反映させるようにします。


```rust
impl Graphics {
    pub fn draw(&self, image: &Image, x: i32, y: i32, flags: u32) {
        image.draw(x + self.dx, y + self.dy, flags);
    }

    ...
}
```

このグラフィックスコンテキストを作るときは、プレイヤーキャラクターの位置に応じた値で初期化します。

```rust
let player_center = self.player.center();
let dx = wasm4::SCREEN_SIZE as i32 / 2 - player_center.x.floor() as i32;
let dy = wasm4::SCREEN_SIZE as i32 / 2 - player_center.y.floor() as i32;
let graphics = Graphics {
    frame_count: self.frame_count,
    debug: self.debug,
    dx,
    dy,
};
```

これで、`graphics.draw`メソッドで画像を描画すれば、プレイヤーキャラクターがどう動き回っても、プレイヤーキャラクターが画面の中心に来るようになります。

# カメラのブレの演出

これを応用すると、ダメージを受けたときなどに画面をブレさせる演出もできそうです。ゲーム全体を表す構造体 `GameScene`に、画面の振動の量を表すフィールド`vibration`を付け加えます。

```rust
#[derive(Clone)]
pub struct GameScene {
    ... 

    vibration: i32,
}
```

それから、この `vibration` を　振り幅にして、振動自体は `f32::cos`で算出することにしました。`f32::cos(self.frame_count as f32))`だとちょっと振動するスピードが早すぎた感じがしたので、`0.5`をかけて振動のスピードを遅くしています。このあたりは好みの問題なので好きに調整するといいと思います。

```rust 
let graphics = Graphics {
    frame_count: self.frame_count,
    debug: self.debug,
    dx: dx + (self.vibration as f32 * f32::cos(self.frame_count as f32 * 0.5)) as i32,
    dy,
};
```

また、振り幅をだんだん小さくすることで、やがてもとの状態に戻るようにします。ここでは毎フレーム`1`づつ減らすようにしましたが、半分づつにしていくような方法もあるかなと思います。このあたりもお好みです。

```rust 
self.vibration = i32::max(0, self.vibration - 1);
```

今回のゲームでは、ダメージブロックに触れるとプレイヤーキャラクターが吹っ飛びますが、そのときにこの画面が振動する演出を使っています。



# 次回予告

Rustはライフタイムや借用が難しいといわれますが、次回は私も少しライフタイムで戸惑った話です。

https://qiita.com/hiruberuto/items/774c4872de472294cfea
[python] マルチスレッドを利用して自動化の時間を短縮する -Pool-

# はじめに
多量のデータを扱う場合、どうしても応答時間が長かったりする。
    ネットに接続するとき、0.1秒ほどはかかってしまうが、Webスクレイピングのように無数のurlに接続してデータを取り出す場合はその0.1秒が積み重なってものすごい長い時間になる。
ここではマルチスレッド`Pool`を利用して自動化の時間を短縮することをまとめた。

# 環境
window 10
python 3.7.8 

# Code
```python
import requests
import time

# 開始時間
start_time = time.time()

# 100個分urlを用意した
url_list = [f'https://finance.yahoo.co.jp/quote/{x}.T' for x in range(5000, 5099)]

def get_data(url: str):
    data = requests.get(url)
    return data.status_code
```
## 普通モード
```python
result = map(get_data, url_list)
print(list(result))

run_time = time.time() - start_time
print(run_time)
```
```terminal
[404, 404, 200, 404, 404, 404, 404, 200, 200, 200, 200, 200, 200, 200, 404, 200, 404, 200, 200, 200, 200, 200, 404, 404, 404, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 404, 200, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 200, 200, 404, 404, 200, 404, 200, 404, 200, 200, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404]
15.092657089233398
```
## マルチスレッド
```python
from multiprocessing.dummy import Pool as ThreadPool

# スレッド４つ
pool = ThreadPool(4)

result = pool.map(get_data, url_list)
print(list(result))

run_time = time.time() - start_time
print(run_time)
```
```terminal
[404, 404, 200, 404, 404, 404, 404, 200, 200, 200, 200, 200, 200, 200, 404, 200, 404, 200, 200, 200, 200, 200, 404, 404, 404, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 404, 200, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 200, 200, 404, 404, 200, 404, 200, 404, 200, 200, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404, 404]
4.0459582805633545
```

# まとめ
普通モード（スレッド１つ）：約15秒
マルチスレッド（スレッド４つ）：約４秒

４つのスレッドを利用したことによって処理速度が約４倍になったことが見える。
urlのように、応答時間が不明、もしくは長い場合に活用するとよいと思われる。

私は実際にpandasで異なる条件で検索していくとき、マルチスレッドを利用してデータを取り出すまでの時間をかなり短縮している

# 関連
https://qiita.com/junzai/items/6cdbf69c02712eb65a58
Why decentralized exchange is the best business idea for budding startups?

In the crypto industry, many business people have a huge interest in a centralized crypto exchange platform. They think it is one of the finest business ideas in the crypto market. 

In this post, I'm going to reveal the trending business idea in the crypto space - Decentralized exchange.  It helps you to earn more profits than a centralized exchange 

## Still, you didn’t get it clearly, Let me explain in detail

In every industry, specific business models have been sensational topics for a period of time. It doesn’t mean it is the best one of all, it has its own followers and demands in the particular time period. The time changes the demand and interest among the people also change.

In the same way, the crypto industry is one of the most active and highly competitive industries in the world, As a newbie having the aim to start a business in the crypto market 

Being trapped in the centralized crypto exchange is not great you should break out of your boundaries and come up with the latest business idea. So you can create your phenomenal place in the crypto field.

When speaking of the latest and trending business ideas, you can choose Decentralized exchange. It overcomes all the drawbacks of a centralized exchange. It is a p2p trading platform, where people can easily swap their digital assets without any interruption. 

Also, it has a high-end security mechanism. Generally, there will be no fees for trading in the decentralized exchange which is the main reason to attract users to the DEX platform. Besides, there are many revenue-making ways in the decentralized exchange. 

By considering these notable reasons, starting a decentralized exchange can help you to impress a new set of crypto audiences and it assists you to reap an ample amount of profits.

I hope, now you got knowledge of the decentralized exchange.

## Now you may ask, how can I get started?

As a business startup, choosing a decentralized exchange is a sure sign of success. But in addition to these, you should develop your Decentralized exchange with advanced functions and features. 

Is there any finest development method available in the market?

Of course, the [decentralized exchange script](https://www.coinsclone.com/decentralized-exchange-script/) will fulfil your need at a budget-friendly cost. 
It is the pre-coded decentralized exchange software that compiles the features of popular decentralized exchanges. Therefore, obtaining this premium script will help you in every aspect to produce fine quality decentralized exchange at ease of time.
FATAL Template not found: /src/node_modules/@nuxtjs/google-adsense/dist/templates/plugin.mjsエラーが発生する


# 環境
 - Nuxt.js
 - Cloud Run
 - Cloud Build
 - [@nuxtjs/google-adsense](https://www.npmjs.com/package/@nuxtjs/google-adsense)

# エラーメッセージ
Nuxt.js製のWebサービスに変更を加えて、プッシュしたらCode Buildがコケていた。
Code Buildでのビルド時のエラーメッセージ
```
Step #0 - "Build":  FATAL  Template not found: /src/node_modules/@nuxtjs/google-adsense/dist/templates/plugin.mjs
Step #0 - "Build": 
Step #0 - "Build":   at normalizeTemplate (node_modules/@nuxt/kit/dist/index.mjs:76:13)
Step #0 - "Build":   at addTemplate (node_modules/@nuxt/kit/dist/index.mjs:60:20)
Step #0 - "Build":   at Object.addPluginTemplate (node_modules/@nuxt/kit/dist/index.mjs:420:93)
Step #0 - "Build":   at setup (node_modules/@nuxtjs/google-adsense/dist/module.cjs:92:11)
Step #0 - "Build":   at ModuleContainer.normalizedModule (node_modules/@nuxt/kit/dist/index.mjs:614:29)
Step #0 - "Build":   at async ModuleContainer.addModule (node_modules/@nuxt/core/dist/core.js:239:20)
Step #0 - "Build":   at async ModuleContainer.ready (node_modules/@nuxt/core/dist/core.js:55:5)
Step #0 - "Build":   at async Nuxt._init (node_modules/@nuxt/core/dist/core.js:478:5)
Step #0 - "Build": 
Step #0 - "Build": 
Step #0 - "Build":    ╭────────────────────────────────────────────────────────────────────────╮
Step #0 - "Build":    │                                                                        │
Step #0 - "Build":    │   ✖ Nuxt Fatal Error                                                   │
Step #0 - "Build":    │                                                                        │
Step #0 - "Build":    │   Error: Template not found:                                           │
Step #0 - "Build":    │   /src/node_modules/@nuxtjs/google-adsense/dist/templates/plugin.mjs   │
Step #0 - "Build":    │                                                                        │
Step #0 - "Build":    ╰────────────────────────────────────────────────────────────────────────╯
Step #0 - "Build": 
Step #0 - "Build": error Command failed with exit code 1.
```

# 考察
 - エラー内容からGoogle Adsenseのnpmパッケージが怪しい感じ
 - Nuxt.js公式の[Google Adsenseプラグインのアップデート](https://github.com/nuxt-modules/google-adsense/commit/f1f3723bbb649c8f0dd4c3c36155698752cd9597)が記事執筆時点の1日前に行われていたのでますます怪しい(v2.1.0)
 - GithubのIssuesには同様の問題は立っていなかった

# 対処法
暫定措置としてプロジェクト直下の``package.json``のバージョンを前のバージョンに固定化したら、エラーが解消した。

Before
```
    "@nuxtjs/google-adsense": "^2.0.0",
```

After
```
    "@nuxtjs/google-adsense": "2.0.0",
```
【OpenCV】２つの画像の類似点の座標(X,Y)をndarray形式の変数に格納する【Python】

[参考文献:opencv画像をマッチングする](https://wonderfuru.com/opencv%E3%81%A7%E7%94%BB%E5%83%8F%E3%83%9E%E3%83%83%E3%83%81%E3%83%B3%E3%82%B0%E3%82%92%E3%81%99%E3%82%8B/)
# はじめに
[前回のQiitaの記事](https://qiita.com/matttchan/items/0bf30b808b267222d881)ではAkazaのおかげで特徴点マッチングを実現することができた。今回は、その特徴点の座標を取得し、より数学的に画像を扱えるように加工していく。

# 環境
OS : Ubuntu 20.04 LTS
Python : 3.8.10
OpenCV-Python : 4.6.0

# 特徴点の詳細データを取得
前回のプログラムの続きから説明します。前回のプログラムに関する記事はこの記事の「はじめに」に書かれています。
```python
kp1,des1 = detector.detectAndCompute(gray_image1,None)
kp2,des2 = detector.detectAndCompute(gray_image2,None)

bf = cv2.BFMatcher()
matches = bf.match(des1,des2)
matches = sorted(matches,key = lambda x:x.distance)
#　追加ここから 
for x in range(len(matches[:20])): 
    print(kp1[matches[x].queryIdx].pt)
    print(kp2[matches[x].trainIdx].pt)
    image1list.append(kp1[matches[x].queryIdx].pt)
    image2list.append(kp2[matches[x].trainIdx].pt)
    print("---------------------------------------------")
# 追加ここまで
```


**では一行ずつ説明していきたいと思います。**
## 1.for文のmatchesについて
みなさんに嫌がらせをします。この星の数を数えてください。（しなくていいです）
<img width="700" alt="southerncross.jpg (187.9 kB)" src="https://img.esa.io/uploads/production/attachments/17340/2022/11/05/129397/7de89325-44b9-4317-9972-98b23b51f9a7.jpg">
この答えはほぼ無限にありますよね。実は特徴点マッチングでも同じことが言えて、特徴点は無限にあります。
無駄に多くの特徴点を捉えるとプログラムの動作を重くしたり、人間が理解しにくくさせたりするので厄介です。今回は”２０”という値を設定しましたが、これはあくまで**私が理解しやすい数値**です。
```python
for x in range(len(matches[:20])): 
```
みなさんが開発するときに適宜数字を変えて開発を進めてください。

## 2.kp1[],kp2[]について
K~P~(乾杯）のノリではありません。（多分、K~P~は３年後は死語）
kp1は[des1,des2]で処理された類似点データをもとに座標やサイズなどのデータを取り出しやすくするための変数という感覚で捉えてください。
```python
print(kp1[matches[x].queryIdx].pt)
print(kp2[matches[x].trainIdx].pt)
```
`x`という変数には`for`で繰り返された回数の数字が代入されています。したがって`matches`のx個目を取得しています。
次に`.queryIdx`と`.trainIdx`についですが、これは元画像と比較対象画像のデータを取得するOpenCVの変数です。(detectAndComputeで処理されたキーポイントのインデックスです)

百聞は一見に如かず、どんな値が帰ってくるのかを実際に見てみましょう
```python:画像を読み込んで処理する例
print(matches[0].distance)
print(matches[0].trainIdx)
print(matches[0].queryIdx)
print(matches[0].imgIdx)
```
```python:結果
# -----出力-----
121.76616668701172
214
207
0
```
## 3. [~queryIdx].ptのptってなんですか？
keypointオブジェクトは以下の属性を持っています。
* pt：キーポイントの座標(ヒント：**タプルで(x,y)が戻り値**として返ってきます）
* size：キーポイント周辺の重要領域の直径
* angle：計算されたキーポイントの方向（計算できない場合は -1 ）
* response：最も強いキーポイントが選択されたときの応答
* octave：キーポイントが抽出されるオクターブ（ピラミッドの階層）
* class_id：オブジェクトクラス
pt以外今のところまだ使ったことがないので、使い次第、上のリストにヒントを追記していきます。

これも百聞は一見に如かず、例を見てみましょう
```python:画像を読み込んで処理する例
print(kp1[0].pt)
print(kp1[0].size)
print(kp1[0].angle)
print(kp1[0].response)
print(kp1[0].octave)
print(kp1[0].class_id)
```
```python:結果
# -----出力-----
(60.0, 129.0)
31.0
276.7517395019531
0.001297724898904562
0
-1
```
## 4.最後にndarrayに変換！
ndarrayは`numpy`の変数の一つです。プログラムの先頭にインポートすることをお忘れなく...
```python
import cv2
# 追加ここから
import numpy as np
# 追加ここまで
```
**次に必ず**プログラムの先頭らへんに`image1list`と`image2list`というリストを準備しておきましょう。

理由は、`for`のプログラムで処理したタプルの座標データを二つの`image{}list`リストに.appendしているからです。全体プログラムを見てみてください
最後にPythonのリストをndarrayに変換するため**for文の外**で以下のプログラムを実行するだけです。
```python
resultbefore = np.array(image1list,dtype=float)
resultafter = np.array(image2list,dtype=float)
```
長い記事を読んでいただきありがとうございました。
貫徹。
【Flutter】「Error: Method invocation is not a constant expression.」のエラー解決

## 初めに
Dart言語を用いた、フレームワーク「Flutter」でのネイティブアプリ開発の時に起きたエラーです。備忘録としてメモ書きしておきますので、誰かの参考になればと思います。


##現状の問題
以下のようにコードを実行すると、`Error: Method invocation is not a constant expression.`というエラーが出てきます。


```mappage.dart
import 'package:flutter/material.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

class MapPage extends StatefulWidget {
  const MapPage({Key? key}) : super(key: key);
=================
コード省略
=================

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: SafeArea(
      child: Column(
        children: [
          const TextField(
            decoration: InputDecoration(
              border: OutlineInputBorder(),
            ),
            onSubmitted: (value) async {
              CameraPosition result = await serchLatLng(value);
              _controller.animateCamera(CameraUpdate.newCameraPosition(result));
            },
          ),
          Expanded(
            child: GoogleMap(
              markers: _markers,
              initialCameraPosition: _initialPosition,
              onMapCreated: (GoogleMapController controller) async {
                await getCurrentPosition();
                _controller = controller;
                setState(() {
                  _markers.add(
                    Marker(
                        markerId: const MarkerId('3'),
                        position: currentPosition.target,
                        infoWindow: const InfoWindow(title: '現在地')),
                  );
                });
                _controller.animateCamera(
                    CameraUpdate.newCameraPosition(currentPosition));
              },
              myLocationEnabled: true,
              myLocationButtonEnabled: true,
            ),
          ),
        ],
      ),
    ));
  }
}
```

![スクリーンショット 2022-11-07 21.19.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2842980/84f008d1-6fa3-651a-e51d-984ef583fd7e.png)

## 問題
色々調べてみましたが、全然解決策が出てこず、苦戦していました。
結論から言うと、とても簡単なエラーでした。TextField()理由は、<b>親Widgetにconstが入っていたものが原因</b>となっていました。

## 解決策
TextField()の前にconstを取り除くことで、簡単にエラーが解消されました。


```mappage.dart
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: SafeArea(
      child: Column(
        children: [
          TextField(
            decoration: InputDecoration(
              border: OutlineInputBorder(),
            ),
            onSubmitted: (value) async {
              CameraPosition result = await serchLatLng(value);
```

ぜひ、同じ境遇でお困りの方は、参考にしていただければと思います。
【LINE】LINE通話でPixel Buds Proから音が聞こえない時の対処法

さっき会社を出た時、イヤホンしてライン通話したらスマホからおもいっきり音が出て恥ずかしかったのでメモがてら投稿。

# 現象
スマホとイヤホンのペアリングができているのにLINE通話でスマホ本体から音が聞こえる。
電話アプリからの通常通話はイヤホンから音が聞こえる。

# 環境
デバイス:Pixel7
OS:Android 13
LINEバージョン:12.18.2
イヤホン:Google Pixel Buds Pro

# 対処法
設定 > アプリ > LINE > 権限 > 付近のデバイス

上記の設定を「許可」にする。
Visual Stuido Code: TypeScript のコードをクラス図にしてくれる拡張機能 

# 背景
typescript のコードを理解しようと、既存コードから UML を起こしていこうとした。

待てよ？自動化ツールがあってもいいんじゃね？と思い検索してみたところ、Class図ならありました。

ってことで、備忘録兼、ちょっとした紹介。

# 出来ること
- typescript のソースから、Class Diagram を描いてくれる。
    - *.png に出力可能
        - Tool->Export<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/44a741e8-ac97-3273-98ad-479acf37728d.png)

- Class Diagram を好みに変形可能
    - Tool->Snap
- private 化していいものに private 付加
    - Tool->Refactor

- 図から、コードへジャンプ<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/f962e83a-ba79-51a9-ca89-90fe0cb14bfd.png)


# 拡張機能
https://marketplace.visualstudio.com/items?itemName=AlexShen.classdiagram-ts&ssr=false#overview

# 実行例
https://github.com/microsoft/vscode-azure-account/blob/c465c17c86c9ffeb1543a3e5372993eb0a56de0e/src/azure-account.api.d.ts

azure-account.api.d.ts を変換してみるとこんな感じ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/c11d8cc7-b194-5528-7c2f-601fdbc49471.png)

# 使い方
インストールしたら・・

- VS エクスプローラー上で、ファイルかフォルダに対して、右クリックメニューの[show diagram] を実行<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/0052d855-79b6-be66-eb8e-ba827c1f0095.png)

- 対象ファイルを編集中に、右上にあるアイコンをクリック<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/3566ae14-40e9-8652-06a2-b0ec32785b16.png)

コードを更新して、保存する事で、自動で図も更新してくれるので結構便利

:::note warn
ファイルに保存しないと反応しない。

- 保存しないままアイコンクリックしても以前のまま（Classが無ければ No class was found)
- CTRL + N で貼り付けて、AutoDetect で typescript になってアイコンが出ても、未保存だと、エラー
:::
    
# あとがき
kotlin にも対応してくれるないかなぁ
Mac+VSCodeでkeybinding.jsonを編集してWord単位でカーソル移動する

# keybinding.jsonを開く
`⌘K` + `⌘S` でキーボードショートカット一覧を表示。
右上のファイルマーク（`キーボードショートカットを開く(JSON)`） をクリック。
# keybinding.jsonを編集
```keybinding.json
// 既定値を上書きするには、このファイル内にキー バインドを挿入します
[
    {
        "key": "ctrl+n",
        "command": "cursorWordPartRight",
        "when": "editorTextFocus"
    },
    {
        "key": "ctrl+p",
        "command": "cursorWordPartLeft",
        "when": "editorTextFocus"
    },
]
```
# 参考
https://qiita.com/BlueSilverCat/items/efba044e66a2be10e3d3
https://qiita.com/akitaaa/items/8ccc5949171dee22f951
https://qiita.com/keitean/items/04727aeb673d1822107e