OmniAICreator/Qiita-1.07M huggingface dataset:
データベースのクラスタリング

未経験からエンジニアになりたい人は、プログラミングから始める人が多いと思いますが、
エンジニアの仕事は、プログラミングだけではありません。そして、プログラミングだけでは、エンジニアになれません。同時にプログラミングが苦手でも、システム構成や開発の流れを理解するとエンジニアに近づきます！
今回はデータベースのクラスタリングについて更に詳しく調べてみましょう！
![インスタスライド_202302103.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23130/62e55cc9-5c03-78d3-36a1-2c4962204935.gif)


# クラスタリングとは
データ量の増加に伴いデータベースが巨大化

Webサーバは、負荷分散化で対応できるが、データベースは、負荷分散する事が難しい。

クラスタリングとは、複数のサーバでアプリケーションからは、1台のサーバの様に見せる技術である

# シェアードナッシング方式
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23130/d062a93f-2811-907a-3cb9-d1c7aec427d3.png)
複数のサーバ、複数のディスクにて処理を行う

更新処理が多い場合は、テーブル毎に分けて負荷分散する

# シェアードディスク方式
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23130/06981e4e-c50e-1855-edb5-df7fbe1a6535.png)
複数のサーバで１つディスクに対して処理を行う

参照処理が多い場合は、複数サーバーでデータをキャッシュさせて負荷分散する

# ディスクについて
データベースのディスクは高速で障害に強い必要がある

そのためRAID構成のディスクを使用

# まとめ
ークラスタリングは負荷分散機能

ーシェアードナッシングとシェアードディスク方式がある

ーディスクはRAIDを使う

# 最後に
未経験の皆さん、若手エンジニアの皆さん、勉強方法について悩みがあればなんでも気軽に質問して下さい！
これからも記事を書いていきますので、モチベーションアップのためフォロー、イイねお願いします。
コピペで動く、SwiftUIでapiからデータを取得して表示する方法

まずは外部APIからコメントデータを取得するために、URLSession を使用してAPIにリクエストを送信する必要があります。以下は、SwiftUIでURLSessionを使用して、外部APIからコメントデータを取得するための簡単な方法です。

```swift

import SwiftUI

struct Comment: Codable {
    var id: Int
    var name: String
    var email: String
    var body: String
}

class CommentLoader: ObservableObject {
    @Published var comments = [Comment]()

    init() {
        guard let url = URL(string: "https://jsonplaceholder.typicode.com/comments") else {
            print("Invalid URL")
            return
        }
        
        URLSession.shared.dataTask(with: url) { (data, response, error) in
            if let error = error {
                print("Error: \(error.localizedDescription)")
                return
            }

            guard let data = data else {
                print("Invalid data")
                return
            }

            do {
                let decoder = JSONDecoder()
                let comments = try decoder.decode([Comment].self, from: data)
                DispatchQueue.main.async {
                    self.comments = comments
                }
            } catch let error {
                print("Error decoding JSON: \(error.localizedDescription)")
            }
        }.resume()
    }
}

struct ContentView: View {
    @ObservedObject var commentLoader = CommentLoader()

    var body: some View {
        List(commentLoader.comments, id: \.id) { comment in
            VStack(alignment: .leading, spacing: 8) {
                Text(comment.name)
                    .font(.headline)
                Text(comment.body)
                    .font(.subheadline)
                Text(comment.email)
                    .font(.subheadline)
                    .foregroundColor(.gray)
            }
        }
    }
}
```

上記のコードは、 CommentというCodableな構造体を定義し、 CommentLoaderというObservableObjectを作成し、 ContentViewでCommentLoaderをインスタンス化し、 Listを使用して、コメントデータを表示しています。 CommentLoaderのinitメソッドでは、 URLSessionを使用して、APIからコメントデータを取得し、 JSONDecoderを使用してJSONを解析しています。 解析されたコメントデータは、 @Publishedを使用してCommentLoader内の commentsプロパティに公開され、 ContentViewに自動的に通知され、更新されます。


APIを使って他のサイトからデータを取得することができるよ。取得したデータをSwiftUIで使って表示することもできるんだよ〜。

データの取得には、URLセッションを使ってAPIリクエストを送信する必要があるんだ。リクエストが成功したら、レスポンスを解析して必要なデータを取り出し、SwiftUIで表示できるようにするんだ。

APIリクエストを送信するには、URLを指定する必要があるよ〜。URLは文字列で表現され、URL(string:)を使ってURLオブジェクトを作ることができるよ〜。

データを取得したら、SwiftUIで表示するために、取得したデータを解析して必要な情報を取り出す必要があるよ。JSONデータを取得した場合、SwiftにはJSONDecoderという便利なツールがあるので、それを使ってJSONを解析するといいよ〜。

解析したデータを、SwiftUIで表示するためには、ListやForEachを使って表示することができるよ〜。データが多い場合は、スクロール可能なリストを作ることもできるんだ〜。

まあ、あくまでも例外はあるけど、基本的にAPIを使って外部データを取得してSwiftUIで表示することは簡単だよ〜。ネット上にたくさんのAPIがあるから、興味があったらいろいろと試してみるといいよ〜。
enPiT BizSysD Workshop in Iwate に参加してきました

お疲れ様です。最近花粉症が酷すぎて頭痛がするようになりましたsukeです。

enPiTについては[前回の記事](https://qiita.com/shosuke447/items/10cb02ccf99377098e1f)を見てみてください。

本記事では岩手県立大学アイーナキャンパスで開催されたenPiT BizSysD Workshopに参加して感じたこと、得た学びを共有しようと思います。

今回のワークショップに参加したのは北海道から沖縄までの計9校ですが、私が所属する筑波大学のenPiTと他大学のものではカリキュラムから、重視している点まで大きく差異がありました。私のチームではプロダクトのクオリティを上げることよりもチーム開発における心理的安全性の確保や、チームをどのように円滑に回すことができるかという点に重きをおいて約半年間のプログラムに取り組みました。そのため、結果としてチーム開発賞という賞を受賞させていただくことができました。一方で、他のチームではプロダクトのクオリティを優先していると感じることが多かったです。サービスについてもWebアプリだけでなくネイティブアプリを作成しているチームがあったり、実際に地元の企業と連携をして街の課題を解決するプロダクトを制作したチームもありました。

筑波大学のenPiTでは、「価値」を検証するということを重要視している点から、ユーザスコープが大学生になることが多かったですが、他大学の発表では、小学生や特定の地域に住む人々といったように、大学生という枠に縛られない開発をしていました。その点において、自分達がコアユーザになり得ない場合に価値を重視した開発を進めていくためのノウハウはおそらく自分達の開発体験では得られなかったもののひとつであると感じました。また、実際のいわゆる仕事としての開発では他の企業や役所といったような自分達とは別のステークホルダとの兼ね合いが重要視される場合もあります。筑波大学のenPiTではその点においても他大学とは異なる色を持っているように思えます。一方で、そういったしがらみに捉われることなく、純粋にアジャイル開発やスクラムの手法を学ぶことによって実際の現場においても既存の枠組みに捉われすぎることのない開発を進めていくことができるようにも感じます。

また、今回は背景の違う多くの人とenPiTという共通点を通して接することができ改めて感じたこととして、一人ひとりの得意を活かしきれるかどうかが使用されるプロダクトを作るために必要なことであるということです。例えば、完成度の高いプロダクトでも、それを伝えることができなければ注目されないし、その逆もまた然りであるということです。

以上をまとめると、チームで何かをするときに意識したいことは、心理的安全性の確保と、チームとしてのパフォーマンス向上の両方を見込める得意領域の活用です。
バッシバシに"バッシング"するぜ！！ in Azure Tech Hackathon

# 今回の内容

今回は、Azure Tech Hackathonにおいて、自分がチームリーダ兼開発リーダを務めた制作物、「**バッシバシに"バッシング"するぜ！！**」についてご紹介いたします！

# Azure Tech Hackathonについて
顔認証やバーコード読み取りなどの画像認識に注目したハッカソンです。今回はクラウドサービスである**Azure** の **custom vision** を使用しました。

https://connpass.com/event/269487/

# 「バッシバシに"バッシング"するぜ！！」　とは
## 本システム
AI×IoTによる中間バッシングを支援するWebアプリとなります。


## そもそもバッシングとは
飲食店の業務である「バッシング(退席後に空いたお皿を下げること)」のことです。

## コンセプト
本Webアプリのコンセプトは、
「**画像認識で、適切なタイミングでバッシングを**」です。

本Webアプリによって、
飲食店側　・・・　回転率の向上 ＋ 自然な追加オーダー ＋ 従業員の最適配置 ＝ **売上の向上**　
お客様側　・・・　不快でないタイミング ＋ 迷惑でないタイミング ＝ **満足度の向上**
を実現します。

具体的なストーリーに関しては以下のサイトをご覧ください。🙇

https://protopedia.net/prototype/3684




# システム概要図・構成図
![概要図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2544613/f35331c4-51e2-1601-d92c-acf74df5337b.png)

![システム概要図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2544613/e98c2d4b-0c20-c138-c39c-85decbc57968.png)

![システム構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2544613/21df2e11-a2de-6c4d-8d28-27561ba8bbb7.png)


# バッシングを行うためのタイミングの計り方
バッシングを適切なタイミングで行うために、
- テーブルごとの皿の状況の把握
- テーブルごとの盛り上がり状況の把握

を行います。
これらを把握することにより、**空のお皿がある　＋　盛り上がっていない状況が、そのテーブルの適切なバッシングを行うためのタイミング**となります。
![各種機能.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2544613/df3f9178-2028-7b26-ae5b-f924af6f1caf.png)


# 実際の画面
実際のWebアプリの画面となります。
![Webアプリ画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2544613/1673ca4c-d592-9b5d-d401-800676c4295e.png)
テーブルごとに空のお皿の検出(+枚数) ＋ 人の笑顔(+人数)を検出できます。
今回は、

そのテーブルに2枚以上の空皿がある ＆ そのテーブルに笑顔の人がいない ＝ そのテーブルは盛り上がっていない

という判定をしております。
そのため、Webアプリの画面のテーブル①は<font color="red">**赤く表示**</font>されている、ということになります。

店員側はこのテーブルの赤い表示を確認することにより、今どのテーブルにバッシングに行くべきかを決定することができます。


# まとめ
今回の作品は、**最優秀賞**をいただくことができました。
本システムが、今後発展される<font color="red">**飲食DX**</font>に貢献できることを願います。

最後に一言・・・
**バッシバシにバッシング決めていくぜ！！🔥**

# 関連サイト
https://protopedia.net/prototype/3684
Error:warning: using `<img>` could result in slower lcp and higher bandwidth. use `<image />` from `next/image` instead to utilize image optimization.

デプロイエラー
```
warning: using `<img>` could result in slower lcp and higher bandwidth. use `<image />` from `next/image` instead to utilize image optimization.
```
のエラーが発生したときの解決法

.eslintrc.jsonに以下の設定を記入
```
{
  "rules": {
    "@next/next/no-img-element": "off"
  }
}
```
【APIテスト】VS CodeのREST ClientでAPIテストする

環境メモ
⭐️macOS Monterey
⭐️Python 3.11.1
⭐️Django 4.1.6
⭐️Visual Studio Code 1.75.0 ←Mac OS版
⭐️Docker desktop 4.11.1 ←Mac OS版

## 1.環境構築
下記で、環境を作成する

https://qiita.com/nonkapibara/items/32b4bbdc5510e2db0586

## 2.VS Codeにプラグイン`REST Client`をインストールする
VS Code上から拡張機能を検索しREST Clientをインストールする。
REST ClientはVS CodeからAPIリクエスト送受信できます。
![スクリーンショット 2023-02-18 17.59.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/b28522cc-666b-0ace-9886-157fa562a921.png)

## 3.APIリクエストを送信する

拡張子`.rest`のファイルを作成します。
ここでは、book.restという名前にしました。


```book.rest
POST http://127.0.0.1:8000/non/books/ HTTP/1.1
content-type: application/json

{
    "xxx": "xxx",
    "xxx": "xxx",
    "xxx": "xxx",
    "xxx": "xxx"
}
```

URLとヘッダー情報と送信Jsonを入力し、Send Request をクリックすると、送信する
![スクリーンショット 2023-02-18 18.12.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/a7a14722-2a22-16d0-4f64-ae6f7098f261.png)

![スクリーンショット 2023-02-18 18.16.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/aeb46ee4-f8e7-9d18-09fb-b38682235328.png)

完成！！

## APIリクエスト失敗した時
![スクリーンショット 2023-02-18 18.18.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/894c570c-c829-a338-b990-2ffe4552d883.png)

DjangoはPOSTでCSRFを外す必要があるので
関数の上に`@csrf_exempt`を追記します。
特定のページだけCSRF機能を外します。

まず、インポートします。

```
from django.views.decorators.csrf import csrf_exempt
```

![スクリーンショット 2023-02-18 18.22.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/62af820b-9085-5e30-adf3-8f69af97cb52.png)

![スクリーンショット 2023-02-18 18.28.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/b5b76373-1476-3aaf-2ae4-67a5c292ff00.png)

完了！




ブラウザ上でAPIを叩くことができるTalend API Testerは、こちらの記事に記載してます。

https://qiita.com/nonkapibara/items/9c86341be4c21b73c5aa
Kotlinで書いたGradleプラグインをビルド時に呼び出せるようにする

今回の記事はこの記事の続きです。

https://qiita.com/takagimeow/items/7471d87fb5e9db76b5ae

`AndroidApplicationComposeConventionPlugin`というクラスを**build-logic/convention/src/main/kotlin/com/takagimeow/myapplication/AndroidApplicationComposeConventionPlugin.kt**に作成しました。

```md
- build-logic
    - convention
        - src
            - main
                - kotlin
                    - com/takagimeow/myapplication
                        - AndroidApplicationComposeConventionPlugin.kt
```

`package`の記述はありません。

内容としては特に何もないです。単純に`extension`の値を表示するだけのプラグインとなっています。

```AndroidApplicationComposeConventionPlugin.kt
import com.android.build.api.dsl.ApplicationExtension
import org.gradle.api.Project
import org.gradle.api.Plugin
import org.gradle.kotlin.dsl.getByType

class AndroidApplicationComposeConventionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            pluginManager.apply("com.android.application")
            val extension = extensions
                .getByType<ApplicationExtension>()
            println("extension: $extension")
        }
    }
}
```

これを本家のアプリをビルドしたときに呼び出したいので、まずは**build.gradle.kts**にて登録します。

```build.gradle.kts
...
gradlePlugin {
    plugins {
        register("androidApplicationCompose") {
            id = "com.takagimeow.myapplication.android.application.compose"
            implementationClass = "AndroidApplicationComposeConventionPlugin"
        }
    }
}
```


そして、ルートディレクトリに存在する**settings.gradle.kts**にて`includeBuild("build-logic")`を呼び出します。

```settings.gradle.kts
pluginManagement {
    includeBuild("build-logic")
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}
...
```

よし！ビルドを実行！。。。してみたのですが、Buildツールウィンドウに`extension: extension 'android'`が表示されませんでした。

どうしたものかと悩んでいたのですが、ひとつ仮説を立てました。
これはプラグインなので、ビルド対象のモジュールの**build.gradle.kts**の`plugins {}`に呼び出したいプラグインを記述しないといけないのではないかと。

なので、`id("com.takagimeow.myapplication.android.application.compose")`を**app**モジュールの**build.gradle.kts**に追加してみました。ここで渡す値は、先ほど`register()`を呼び出したときに設定した`id`の値です。

```build.gradle.kts
...
plugins {
    ...
    id("com.takagimeow.myapplication.android.application.compose")
}
...
```

再度ビルドしてみた結果、みごと表示されました！

```shell
> Task :build-logic:convention:compileKotlin UP-TO-DATE
> Task :build-logic:convention:compileJava NO-SOURCE
> Task :build-logic:convention:pluginDescriptors UP-TO-DATE
> Task :build-logic:convention:processResources UP-TO-DATE
> Task :build-logic:convention:classes UP-TO-DATE
> Task :build-logic:convention:inspectClassesForKotlinIC UP-TO-DATE
> Task :build-logic:convention:jar UP-TO-DATE
...
> Configure project :app
extension: extension 'android'
```
家庭用ルーターに繋いだHDDが不調なのでSSDに移行した話

家庭用の無線LANルーターに2TBの外付けHDDを繋いで、昔リッピングしたMP3や資料、学生時代の作品とかを保存しているのだけど、ちょっと調子がおかしい。
1TBも容量を使っていないので、1TBの外付けSSDに移行することに決めました。

最初は、ルーターが認識するかどうかを試して、HUBを使ったらHDDもSSDも両方とも認識してフォーマットもできたので、このまま移行できると思っていたのですが、これがなかなかうまくいきませんでした。

# 繰り返す再起動、そして認識しない

学生時代に作ったAVIとかの動画ファイルを移行したところまではよかったみたい。
その後が問題で、ちょっと大きなファイルを移行するとルーターが落ちる。
パワー負けしてるのかわかりませんが、とにかく再起動、ネットワーク認証の連続で一向に作業が進まない。
最終的にHDDもSSDも認識しないようになりました。
HDDはルーターに直接接続すれば認識するみたいですが、なにか壊れたのかな？

困り果てました。

ルーターはストレージをXFSというファイルシステムでフォーマットしている。
WindowsやMacで認識させられるか？
怪しいサイトの情報ばかりでどれも手をつけたくない。

色々方法を探っていたところ、ラズパイを使った方法を紹介している記事を見つけました。
我が家にはネットワークエミュレーターの実験のために買ったライズパイがあるので、それで試してみようと思いました。

https://zenn.dev/kounoike/scraps/89b10846ea2b26

https://aquasoftware.net/blog/?p=1462


# ラズパイを使った方法その1 OpenMediaVaultを使う

[OpenMediaVault](https://www.openmediavault.org/)をラズパイにインストールして、NASとして認識させるという方法です。
ということでOpenMediaVaultのマニュアルにしたがってインストールをしていくことにします。

OSはRaspberry Pi OSなので、Debianのやり方で行けるはず・・・ダメでした。

最終的にわかったのは、ラズパイでOpenMediaVaultを使う場合は、OSはRaspberry Pi OS Liteでないとだめということでした。
OSの入れ替えはしんどい。

詰んだ。


# ラズパイを使った方法その2 そのままマウントしてしまえば・・・？

XFSは一応Linuxで認識できるはず。
そんなことを思いました。

OpenMediaVaultとか小難しいことしなくてもいいかも。
ラズパイはWindowsからリモートデスクトップできるように設定していたので、早速HDDとSSDを繋いでみると認識してた。
これで移行ができる。

ということでラズパイのデスクトップ上で移行をしていたのですが、やっぱり何個かエラーが出ていて、ファイルが復旧できなさそうなのがいくつもありました。
仕方ないというかなんというか。

ああだこうだ思いつつ3日かけて移行しました。
思いの外HDDの調子は悪かったみたいです。

さぁルーターにSSDを繋いでみるか。
認識しない・・・。

ここからがまた面倒なところです。


# ルーターが認識しないので

USB HUBや中間の延長ケーブルの問題かといろいろ切り分けを行ったのですが、全くわかりませんでした。
てこでもSSDを認識しません。

考えた挙げ句、移行に使ったラズパイにSambaを入れてファイルサーバー化することにしました。
もうここまで来ると気持ちも適当になっています。

```
sudo su -
apt install samba
cp /etc/samba/smb.conf /etc/samba/smb.conf.orig
wget https://raw.githubusercontent.com/tomgoodsun/centos8_lamp_configs/master/config/etc/samba/smb.conf -O /etc/samba/smb.conf
# /etc/samba/smb.confのwebmasterの部分をpiに変更

chown -R pi:pi /media/pi
chmod -R 777 /media/pi
cat << EOS >> /etc/samba/smb.conf

[ssd]
        comment = Public Stuff
        path = /media/pi/<メディア名>
        public = yes
        browsable = yes
        writable = yes
        guest ok = yes
        printable = no
        write list = +staff
        inherit permissions = yes
EOS
systemctl restart smbd
```

で、できたのがこちら。
![qiita_20230302_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131218/1e1b6810-87dc-4c45-0106-58e7d7544a33.png)


## 参考

https://note.com/hitoshiarakawa/n/n93ed26b7dca2

https://github.com/tomgoodsun/centos8_lamp_configs/blob/master/03.Samba%EF%BC%88Windows%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E5%85%B1%E6%9C%89%EF%BC%89%E3%81%AE%E8%A8%AD%E5%AE%9A.md

# 移行してみて

SSDだとやっぱり速いですね。
と言うより、冗長化を考えてNASを買おうか迷ったんですが、値段に見合うほど使わないので、渋ったというのがあります。
やるなら以下のようなもので、自作かなぁとか。

https://amzn.asia/d/8DhWcXa

https://amzn.asia/d/3kxo9cn

消えたファイルたちは帰ってこないので、みなさんも対策はなにかしておいたほうがいいかも。
Typescriptをとにかくサクッと快適に始めるセット

TypeScriptの環境を作るとき、Dockerで作ることもありますが、
Dockerを使わずにサクッと自動コンパイルするところまで作りたいことも多いので、備忘録。

## 必要なパッケージのインストールと初期化
```bash
yarn
yarn add typescript
yarn add -D ts-node ts-node-dev
npx tsc --init
```

## 監視するファイルを作成
srcディレクトリを作成し、配下にindex.tsを配置
```bash
src/index.ts
```

## tsconfig.jsonの記載
```json
{
  "compilerOptions": {
    "target": "es2022",  // コンパイル時に出力するJavaScriptのバージョンを指定する
    "module": "commonjs",  // モジュールの種類を指定する
    "sourceMap": true,  // ソースマップを出力するかどうかを指定する
    "esModuleInterop": true,  // CommonJSモジュールとESモジュールの間での相互運用性をサポートする
    "moduleResolution": "node",  // モジュールの解決方法を指定する
    "forceConsistentCasingInFileNames": true,  // 大文字小文字の一貫性を保つ
    "strict": true,  // 厳密な型チェックを有効にする
    "skipLibCheck": true,  // ライブラリの型チェックをスキップする
    "rootDir": "./src",  // TypeScriptファイルのルートディレクトリを指定する
    "outDir": "./dist",  // コンパイルしたJavaScriptファイルを出力するディレクトリを指定する
    /* JavaScript Support */
    "allowJs": true,  // JavaScriptファイルをコンパイルできるようにする
    "baseUrl": "./",  // 相対モジュールを解決するためのベースディレクトリを指定する
    "paths": {  // パスの別名を指定する
      "#/*": ["src/*"]
    }
  },
  "include": ["src/**/*"]  // コンパイルするファイルを指定する
}
```

## package.jsonにscriptを追記
```json
  "scripts": {
    // 省略
    "dev": "ts-node src/index.ts",
    "dev:watch": "ts-node-dev --respawn src/index.ts"
  },
```

これで、`yarn dev:watch`とすると自動コンパイルが走って、
コマンドラインに出力される。
【APIテスト】Talend API TesterでAPIテストする

環境メモ
⭐️macOS Monterey




# 1.Talend API Testerとは
Talend API Testerとは、ブラウザ上でAPIを叩くことができるGoogle Chromeの拡張機能です。

# 2.インストールする

下記より、Chromeに追加するボタンを押して、インストールする
Talend API Tester - Free Edition
https://chrome.google.com/webstore/detail/talend-api-tester-free-ed/aejoelaoggembcahagimdiliamlcdmfm
![スクリーンショット 2023-02-18 16.38.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/ea5a8508-1b05-d066-84ad-9fc00f46ce10.png)

# 3.使ってみる

## 3-1.Talend APIを起動する
![スクリーンショット 2023-02-18 17.15.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/ed96bcd3-d480-9303-e83d-ece89792f31a.png)

## 3-2.新規プロジェクトを作成する
![スクリーンショット 2023-02-18 17.13.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/d757ec4c-d2b5-508b-168c-f570169b2a33.png)

## 3-3.新規リクエストを作成する
![スクリーンショット 2023-02-18 17.18.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/8411c176-9a4c-3204-8ff1-d26eb78be657.png)

![スクリーンショット 2023-02-18 17.29.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/202a81f9-4142-2c19-e627-3ac09f636c33.png)

`Content-Type`
`application/json`

入力したら、Sendボタンを押す

![スクリーンショット 2023-02-18 17.33.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/2abfd1ed-b3c2-b790-b224-970c61826953.png)

完了！
DataSpiderSDKで利用するHyperledgerFabricのライブラリの選定

前回からHyperledgerFabricのアダプタ製造について検討を進めていますが、アダプタを実装するにあたり適用するFabricのJavaライプラリの選定と経緯について紹介したいと思います。

## Hyperledger Fabricのライブラリ
Hyperledger Fabricのライブラリについては、数多くの先輩方が情報を配信してくださっています。
ここでは、私自身が理解した内容を紹介したいと思います。
Javaライブラリは大きく2種類が存在ます。

### Hyperledger Fabricのライブラリの種類
+ https://github.com/hyperledger/fabric-gateway-java.git
Jarファイルの配布URL
https://mvnrepository.com/artifact/org.hyperledger.fabric/fabric-gateway-java

+ https://github.com/hyperledger/fabric-sdk-java.git
Jarファイルの配布URL
https://mvnrepository.com/artifact/org.hyperledger.fabric-sdk-java/fabric-sdk-java

## それぞれのライブラリの定義
それぞれのライブラリは、fabric-gatewayは高レベル、fabric-sdkは低レベルと定義されているようです。
fabric-gatewayはfabric-sdkと少し距離があり、私たちと距離が近いように思えます。
fabric-gatewayの場合、アプリケーション開発者の負担を軽減する高レベルの抽象化を備えており、チェーンコードの操作、実行を直感的に把握でき実装できる構造になっているように感じます。
一方で、fabric-sdkは、利用者の管理およびチェーンコードのメタ情報の収集など、その他Fabric全体の諸機能をカバーし目的の機能を実現するための関数が用意さているようです。

## サンプルコードの紹介
### fabric-gateway
fabric-samplesに含まる、application-gateway-javaがfabric-gatewayを用いたチェーンコードを制御するまでのロジックのサンプルコードです。
* ソースコード
https://github.com/hyperledger/fabric-samples/tree/main/asset-transfer-basic/application-gateway-java

### fabric-sdk
lkoliskoさんが作成した、fabric-sdkを用いた利用者の制御、およびチェーンコードを制御するまでのロジックのサンプルコードです。
* ソースコード
https://github.com/lkolisko/scratch/tree/master/hyperledger/fabric-sdk-java-scratch

## 次回は
[Heperledger Fabric Explorerの構築](https://qiita.com/dataspider-fan/items/afd00f75b59792f034a3)について紹介したいと思ます。
GitBashのオートアップデート2023

gitforwindows.org をつらつらと見たりするのも悪くはないのですが、、もっと楽をしたい。
（clink の clink update/ 本家でない絶賛更新中な方なやり方）

```bash
$ git version; git update-git-for-windows
git version 2.39.2.windows.1
Git for Windows 2.39.2.windows.1 (64-bit)
Up to date
```

【引用元】

https://qiita.com/thankkingdom/items/14d1346b25def557c1af

google.com/search?q=git update-git-for-windows
google.com/search?q=gitbash+autoupdate
Apacheの設定ファイルhttpd.confの基本設定およびコンテンツに関する主なディレクティブ

●Apacheの設定ファイルhttpd.confの基本設定およびコンテンツに関する主なディレクティブ
・Listen　[IPアドレス:]ポート番号　リクエストを受け付けるIPアドレスとポート番号(デフォルト80)を指定
・User　ユーザ名|ユーザID　httpd子プロセスの実行ユーザを指定
・Group　グループ名|グループID　httpd子プロセスの実行グループを指定
・DocumentRoot　ディレクトリ名　ウェブで公開するHTMLを保存する最上位のディレクトリを指定
・DirectoryIndex　ファイル名　インデックスとして返すファイル名を指定(複数可)
・Alias　ディレクトリ　パス　指定の「ディレクトリ」へアクセスがあった場合、「パス」で指定したファイルやディレクトリを参照させる
・UserDir　ディレクトリ名|disabled　一般ユーザの公開ディレクトリを指定
・ErrorDocment　エラーコード　ファイル名|文字列|URL　エラー発生時の処理を指定
Java　文字列（String）同士の比較

Javaでは、int型とString型では比較する際に違いがある。

・int型　　　「==」
・String型  「equals」

上記の二つで比較します。
実際に「equals」を使ってみます。

```
public static void main(String[] args){

    String name = "林";
    if(name.equals("林"){
        System.out.println(name);
    }
}

```
　[説明]
・１行目で変数nameに「林」を代入
・２,３行目は「もしname変数が「林」なら、変数name(林)を出力する
animation gif削減テスト 800x800 100MB -> 200x200 6.8MB

とあるanimation gifが100MBを超えていて貼り付けづらい(800x800 100MB)
例えばQiitaやはてなブログは画像UPサイズの制限が10MB.

## optimize

imagemagickで下記の最適化をすると22.5MBになった

```
magick .\vis.gif -layers optimize out.gif
```

## resize

サイズが800x800なのが厳しいので最低限必要な200x200にリサイズ

```
magick .\vis.gif -resize 200x200 200.gif
```

9.8MBになり、これならQiitaでも貼れる

普通に貼るとこうなる。サイズ指定はできない

![200.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12309/ee58e00e-0356-eb9d-84a2-98e37a6797bf.gif)

URLをimgタグに書き換えて大きく(800x800)表示。ボヤける...

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12309/ee58e00e-0356-eb9d-84a2-98e37a6797bf.gif" width=800 height=800>

## resize & optimize

* resize & optimize => 6.8MB

```
magick .\vis.gif -resize 200x200 -layers optimize 200optimized.gif
```

![200optimized.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12309/60b1b815-14e5-d67e-80cf-1d123d3e0e20.gif)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12309/60b1b815-14e5-d67e-80cf-1d123d3e0e20.gif" width=800 height=800>

変わらず。サイズを収めることはできたので良し

## その他、試したけれどダメだった削減方法

* imagemagickで減色
  * 画質劣化が激しい＆サイズはほぼ減らない
* 最適化サイト 50MBに収まるよう(400x400)リサイズしてUP. 31MBになったが今回の要望(10MB)に合わない
  * あとアップロードは待つのでできるなら避けたい
2つの列をキーにして、2つのDataframeの片方にしかない情報からNanを補完する

# 何がしたいか
とあるシステムがエラーを吐いたときに、そのerr_codeと、どのsystemがエラーを吐いたか、そしてそのエラーに対するdescriptionがなにかを記録したDataframeが生成されるとします。 
しかし、このDataframeのdescriptionは穴抜け(`None`)になっている場合があります。 
そこで、リファレンスとなるdf2(err_codeとsystemとdescriptionが完璧に記述されていて、`None`が無いDataframe)を使って補完します。


# コード
```python
import pandas as pd

df1 = pd.DataFrame(
    data={'err_code': ['A000', 'B000', 'A000'], 
          'system': ['a', 'a', 'c'],
          'description': [None, None, 'this error is sytax error of c']}
          # df1は他に列がある計測データ
)

df2 = pd.DataFrame(
    data={'err_code': ['A000', 'B000', 'A000', 'A000'], 
          'system': ['a', 'a', 'b', 'c'],
          'description': ['this error is sytax error', 'this error is value error',
                          'this error is sytax error of b', 'this error is sytax error of c']}
          # df2は辞典のような(リファレンスとなる)データ
)

## 列1と列2のdtcとsystemが一致するもののみを抜き出す
# まずはerr_codeとsystemで一意となるように合体させる
df3 = pd.merge(df1, df2, how='left', on=['err_code', 'system']) 

# 次に、fillnaを使って、descriptionが無い列をdf2のdescriptionで補完する
df3['description_x'].fillna(df3['description_y'], inplace=True)
```
Math.NETのベクトルをMemoryPackでシリアライズする

## 概要
Math.NETのベクトル```Vector<T>```と行列```Matrix<T>```を高速なシリアライザである![MemoryPack](https://github.com/Cysharp/MemoryPack)で扱う方法についてまとめました。

## 動作条件と注意点
本記事は.NET Standard2.1版のMemoryPackが使用される.NET 5および.NET 6での動作確認をしています。
.NET 7ではCS8987によりコンパイルエラーが出ます。

## コード
![公式のCustomFormetterの書き方](https://github.com/Cysharp/MemoryPack#customformatter) に則り```Vector<T>```を```T[]```として（つまり密ベクトルとして）シリアライズできるようにラッパー、フォーマッターを実装します。

```csharp
using MathNet.Numerics.LinearAlgebra;
using MemoryPack;

// シリアライズ前にFormatterを登録します(Vector<double>をシリアライズ可能にする)
MemoryPackFormatterProvider.Register(new VectorFormatter<double>());

var v = Vector<double>.Build.Random(5);
var s = new Sample(v);

var bin = MemoryPackSerializer.Serialize(s);
var val = MemoryPackSerializer.Deserialize<Sample>(bin);

Console.WriteLine(s);
Console.WriteLine(val);
Console.ReadLine();

// Vector<T>を含むシリアライズ対象クラス
[MemoryPackable]
public partial class Sample
{
    [MemoryPackAllowSerialize]
    public Vector<double> X { get; set; }

    [MemoryPackConstructor]
    public Sample(Vector<double> x)
    {
        X = x;
    }

    public override string ToString()
    {
        return X.ToVectorString();
    }
}

// Vector<T>をシリアライズするためのWrapper
[MemoryPackable]
public partial class SerializableVector<T> where T : struct, IEquatable<T>, IFormattable
{
    [MemoryPackIgnore]
    public readonly Vector<T> Data;

    [MemoryPackInclude]
    T[] source => Data.ToArray();

    [MemoryPackConstructor]
    SerializableVector(T[] source)
    {
        Data = Vector<T>.Build.DenseOfArray(source);
    }

    public SerializableVector(Vector<T> data)
    {
        Data = data;
    }
}

// カスタムフォーマッター
public class VectorFormatter<T> : MemoryPackFormatter<Vector<T>> where T : struct, IEquatable<T>, IFormattable
{
    public override void Deserialize(ref MemoryPackReader reader, ref Vector<T>? value)
    {
        if (reader.PeekIsNull())
        {
            value = null;
            return;
        }

        var wrapped = reader.ReadPackable<SerializableVector<T>>();
        value = wrapped?.Data;
    }

    public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, ref Vector<T>? value)
    {
        if (value == null)
        {
            writer.WriteNullObjectHeader();
            return;
        }

        writer.WritePackable(new SerializableVector<T>(value));
    }
}
```

## 行列は？

ベクトルの時と同様に```Matrix<T>```を```T[,]```とみなしてラッパーとフォーマッターを作成すればシリアライズが可能です。疎行列の場合には別途工夫が必要になると思います。
自作WEBアプリをリリースするまでに必要な工程って？

# 免責事項
本記事は概念的解説を目的としており、実用上のセキュリティリスクは考慮していません。
記事の内容を参考にした結果生じたトラブルや損害について、当方は一切の責任を負いかねますので、自己責任で十分に注意して行ってください。

# まえがき
私は大学時代にプログラミングにハマり、デスクトップアプリやフレームワークを使ったWEBアプリ開発を趣味でよくやっていました。
しかし、ネットでアプリ開発の情報を漁ってもlocalhost（自分のPC）上で動かすところまでしか解説しているサイトが無く、「結局このアプリはどうやったら公開することができるのだろう？」とずっと疑問でした。

現在SaaS開発エンジニア２年目の私が大学生の頃の自分に向けて教えてあげる気持ちで、ざっくりリリースまでに必要な工程をまとめてみたいと思います。

# おおまかな流れ（WEBアプリの場合）
1. サーバを用意する
1. アプリをデプロイする
1. 自分のドメインを取得する
1. ルーターのポート解放を行う

## 1. サーバを用意する
これはオンプレ（非クラウド）環境での想定です。
サーバーというとエンタープライズ向けのXeonやEPYCなどを積んだバケモンスペックPCをイメージする方がいるかもしれませんが、WEBアプリであれば余っているノートPCやラズパイのようなシングルボードコンピュータ程度で十分です。
サーバーなので24時間起動しっぱなし想定なので、なるべく省電力なマシンが理想です。

このサーバー上で開発したバックエンドシステムを動かします。

サーバーは日常使いのPCとは異なり、モニターやキーボード、マウスを接続する必要がありません。
※必要がないだけで別にあっても良い

ではどのようにサーバー上での作業を行うのかというと、開発端末からSSH接続ということをしてリモートで操作を行います。
また、サーバ上での直接の作業は極力減らしたいので、アプリの自動起動(systemd)設定なども行いたいです。
さらに、DHCPでIPの自動割り当てをしている場合はプライベートIPを固定化する必要もあります。
こういうサーバー向けの設定を行うにはLinux系のOSが向いています（windowsみたいにアプデで勝手に再起動とかしないし）。
個人的にはUbuntuあたりがユーザーフレンドリーで初心者にオススメです。

## 2. アプリをデプロイする
サーバーを実際に稼働させるには自分で作ったシステムをデプロイする必要があります。
デプロイの手法にはいろいろやり方がありますが、個人開発レベルであればGitHubから直接clone（ダウンロード）して動かすのがシンプルでおすすめです。

一応GitHubについて解説をしておくと、ソースコードをクラウドに保存しておけるサービスです。
バージョン管理等も容易になるので、使い方を覚えておいて損はないと思います。

開発したプログラムを予めGitHubに上げておき、本番環境（サーバ）にログインしてGitHubから持ってくるわけです。
GitHubの操作はすべてCLI（コンソール上のコマンド）で完結するので楽ちんです。

ソースコードを持ってきた後は、ビルドするなりしてアプリを実行するわけですが、開発環境とは変えるべき設定があります。
それはBindするIPアドレスです。
開発環境では恐らく"localhost"や、"127.0.0.1"としていたかと思いますが、これをサーバーのプライベートIPアドレスにする必要があります。
一方でポート番号はなんでも大丈夫です（後述するポート開放のタイミングでポートフォワーディングを行うため）。

ちなみに実はこのタイミングで、同じLAN環境にあるマシンからであれば、サーバーで起動しているWEBアプリにアクセスが可能になります。
`http://{サーバのプライベートIP}:{ポート番号}`でアクセスできます。

## 3. 自分のドメインを取得する
ドメインとは`google.com`や`yahoo.co.jp`みたいなやつです。
これを取得し、自分が使用している回線のグローバルIPを紐づけることでURLがわかりやすくなります。
これには月々数百円程度のお金がかかりますが、自分で好きな名前を付けることができます。
あと「自分のドメインを持ってる」とちょっと嬉しい気持ちになります。

ドメインを取得できるサービスとしては[Cloudflare](https://www.cloudflare.com/ja-jp/E)や[AWS Route53](https://aws.amazon.com/jp/route53/)あたりが有名だと思います。
個人的にはCloudflareが安くておすすめです。

## 4. ルーターのポート解放を行う
これは一般的な家庭用ルーターでも設定できるハズです。
設定方法はメーカーによってさまざまなので、詳細な方法は記述できませんが、主にやることは一つです。
それは**ポートの穴を空ける**こと。

ポートは言わば外部からの入口です。
通常、ルーターは外部からの侵入を防ぐため全てのポートが閉じています。
そのため、公に自分のIPアドレスがバレたとしても、入口がないのでネットワークに侵入することが不可能なわけです。

一方でWEBサーバーは外部からの入口を作らなければ、サイトにアクセスがあってもルーター側でブロックされてしまい、アプリまで届きません。
そのため、それ専用の入口を一つ空ける必要があります。

この入口用ポート番号は用途によって慣習的決まりがあり、httpであれば80番、httpsであれば443番となっています。
例えばhttpの場合は、外部からの80番ポートに対するアクセスを許可してあげればいいわけです。

ただし、入口用の穴を空けるだけではサーバーまでリクエストが届きません。
なぜならば、ルーターはまだLAN内における「どの端末のどのポート」にリクエストを転送すればいいのかわからないためです。

そのため、80番に対するリクエストが来た場合は「このサーバーのこのポートに転送してくれ」ということも併せて設定する必要があります。
ちなみにこれを専門用語で「ポートフォワーディング」や「IPマスカレード」と呼びます。

イメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/582097/6271bdc7-bca9-c261-84d7-c4bc14a8a65e.png)

これでインターネットから自分のWEBアプリにアクセスができるようになります。

# まとめ
以上がWEBアプリリリースまでに最低限必要な流れです。
もちろん、これ以上にやったほうがベターな設定はたくさんあります。
httpsを使えるようにするためにSSL証明書を発行したり、負荷軽減のためにリバースプロキシ（nginx）を立てたり etc

ただ、これだけでも一応アプリのリリースは可能ですし、ゴールまでの道のりが把握できるだけでも見える景色は変わるハズです。
WEBアプリのリリース工程が知りたい方の一助となれば幸いです。
【Laravel】外部キー制約削除でエラー。をいい加減やめたい。

 
初心者による初心者のための備忘録です。

　

LaravelにてDBを操作する時に使うマイグレーションですが
　

外部キー制約でエラーが出て、なかなか進まん！という私のような方もいるかと思います。
　

ある程度慣れてきてから公式ドキュメントを見ると書いてあったりするんですけど・・・。それが初心者の我々にとっては読み解くのすら難しい:frowning2:

　
ってことでなるべく自分向けに、わかりやすく。

 
　


【開発環境】
Laravel5.8
　

【起きるエラー】

他のテーブルのカラムとひも付けたい。と思って外部キー制約をつけて
```
php artisan migrate
```
と叩いても
　

SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL: alter table `problems` add constraint `problems_drills_id_foreign` foreign key (`drills_id`) references `drills` (`id`) on delete cascade on update cascade)

のように、外部キーを付けたマイグレーションファイルの部分でエラーが返ってきてしまう。


　
#### 【よくやるミス（私はだいたいコレのどれか）】
　


##### ●スペルミスはないか？

例えば外部キーを設定しようとしているカラム名と、外部キー制約のところのカラム名が違う。
```
$table->bigInteger('users_id')->unsigned();
〜
〜
//外部キー制約
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade');
```

上の`users_id`と下のforeign()の中の`user_id`が不一致パターン。

　


##### ●マイグレーションの順番がおかしくないか？

マイグレーションはどうやら日付順（作成日順）に読み込まれるようなので
「まだできていないテーブル」のカラムに向けた外部キーをつけようとしてもエラーになる。


```
例えば
$table->foreign('category_id')->reference('id')->on('category')
のように
```
商品テーブルのcategory_idと、カテゴリーテーブルのidをひも付けようとしても
（この場合）カテゴリーテーブルが先に出来てないと「え、ドコとひも付けるん？」となる。
 


ちなみに上記のエラーはこのパターンでした。


この場合はマイグレーションファイル名の**日付部分**を商品テーブル作成のマイグレーションファイルよりも**前の日付**にしてあげる


　

#### 【よくわかってないけどコレでいける！】

作成時（migrate実行時）でエラー出るのは私の場合、上記のどちらかなんですが

問題は`migrate:rollback`を実行したとき:frowning2:

　
ここでしょっちゅうつまずく。軽い恐怖症。

　

私はイマイチ分かってはいないんですが（汗）外部キー制約付けたいカラムに対して下記のように書けばエラーなく通るようになりました:relaxed:

```
//onDelete('cascade')とonUpdate('cascade')があるといける

$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade');
```
　

※公式ドキュメント
https://readouble.com/laravel/5.8/ja/migrations.html
　
　


コレで`rollback`も`fresh`も怖くないぜ！と思いたい・・・。
VSCode拡張機能を作りこむ手順

VSCodeでカーソル行のファイル文字列を使って既定のアプリで開くことができたら便利かと思いアドバイスをいただきながらも無事思った機能ができました。
そのとき拡張機能作成の手順を整理しました。

## 欲しかった機能
VSCodeでカーソル行のファイル文字列を使って既定のアプリで開きたい。

```sample.txt
C:\tmp\test.xlsx
C:\tmp\サンプル.txt
"C:\tmp\サンプル.txt"
```
例えばsample.txtのようなものを開いていたら
test.xlsxの行でF1を押すとExcelでファイルが開かれる
サンプル.txtの行でF1を押すとtxtに関連付けられたファイルが開く機能です。


## 実現方法
どうやら拡張機能に類似の機能があったようですがこれから自身で開発ができるように拡張機能を自作してみました。

以下は欲しかった機能を実現したときの最短経路です。

### STEP0 とりあえずまねる
[Visual Studio Codeの拡張機能を一通り触って自分用に公開するまで](https://qiita.com/567000/items/c4cf825fb30e3e247285)

こちらを参考させていただきました。
そうするとテキストを選択したときの情報が取得できています。

残る機能は以下の３点になります。
1.関連付けたアプリケーションで開く
2.選択せずに現在行の情報を取得する
3.ショートカットキーで実行する

### STEP2 関連付けたアプリケーションで開く
ググってみると openというライブラリが使えそうでした。

まず以下のコマンドを実行します。そのあとVSCodeを立ち上げなおします。
```
npm install open
```
package.jsonのdependenciesにopenが追加されることを確認しましょう。
この記載がないとデバッグはできても。パッケージ化したときにコマンドが組み込まれず拡張機能が動作しませんでした。

以下のように書き換えます。
``` src/extention.ts
import * as vscode from 'vscode';
import * as openPath from 'open';

export function activate(context: vscode.ExtensionContext) {

	console.log('Congratulations, your extension "open-defaultapplication" is now active!');

	let disposable = vscode.commands.registerCommand('open-defaultapplication.helloWorld', () => {

		let editor = vscode.window.activeTextEditor;
		if (!editor) {
			vscode.window.showWarningMessage('No active text editor found!');
			return;
		}
		let text = editor.document.getText(editor.selection);
        vscode.window.showInformationMessage("length:" + text.length);
		openPath(text);
	});
	context.subscriptions.push(disposable);
}
export function deactivate() { }

```

選択した文字列でアプリが起動しました。

### STEP 3 選択せずに現在行の情報を取得する
ググったところ以下のように書き換えれば行けそうです。
ダブルクォーテーションも取り除きます。

```
let text = editor.document.getText(editor.selection);
↓
let text = editor.document.lineAt(editor.selection.active.line).text.replace(/\"/g, "");
```		

### STEP4 ショートカットキーで実行する
keybindingsの部分を書き加えることで実現できました。
これでf1キー,f2キーと順番に押すとファイルが開きます。

```package.json
抜粋です。
  "activationEvents": [],
  "main": "./out/extension.js",
  "contributes": {
    "commands": [
      {
        "command": "open-defaultapplication.helloWorld",
        "title": "Hello World"
      }
    ],
    "keybindings": [
      {
        "command": "open-defaultapplication.helloWorld",
        "key": "f1 f2",
        "mac": "shift+cmd+x"
      }
    ]
  },

```

### STEP5 パッケージ化する
README.mdをちゃんと書きます。
面倒な場合はREADME.mdの3行目あたりを削除します。
これをしないと次のパッケージ化の工程でエラーがでます。

以下のコマンドを実行します。
```
npm install -g vsce
vsce package
```
作成されたvsixファイルをvscodeでインストールすればVSCODEに導入完了です。

### STEP6 もっと機能をつくりこむ
目的の機能が実現できましたのでまとめはここまでとします。
※helloWorldがソース内に残っていますが最小手順とするためそのままです。

ここまではいろいろなコードをつなぎ合わせて実現できました。
皆さん、どうやって目的の機能を作っているんでしょうか？
「vscode-api」を見て使えそうな機能を探すのでしょうか？
https://code.visualstudio.com/api/references/vscode-api

いい情報お持ちでしたら教えてください。

ここからは類似の拡張機能をしばらく学びます。

アドバイスいただいた時の質問はこちら
[[Q&A] VSCodeでカーソル行に記述したファイルを開きたい - Qiita](https://qiita.com/devcat14z/questions/df973de279e6c99d1955)

### 追記
ここを学ぶのが王道だと感じました。英語のページも探すのが大切だと最近気づきました。

https://code.visualstudio.com/api
kUTType~ was deprecated in iOS 15.0. Use UTTypeImage instead.の対応方法

# kUTType〜 was deprecated in iOS 15.0. Use UTTypeImage instead.　 の対応

こんにちは。
久々の投稿になります

業務でちょっと調べて日本語記事があまり見当たらなかったので書いておこうと思います。誰かの役に立てば幸いです。

 
## ざっくり
iOS 15.0から、kUTTypeが廃止され、UTTypeが代わりに使用されるようになりました。
現在`MobileCoreServices`を使ってkUTTypeImageとかkUTTypeMovieとかを使っているところはwarningが出ると思います。
その対応をした時にwarning通りにするとErrorになったのでその時の対応を書きます。

## 説明しないこと
`Uniform Type Identifiers`に関しては説明しません。
旧来の`MobileCoreServices`は何をやっているのかとかは説明しません。

## どんなwarning？
以下のwarningが出ます。

![スクリーンショット 2023-03-01 23.12.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403613/892bf65c-48c5-0de4-a315-02487c5b05d6.png)

で、単純に変更してもErrorになります。そんな簡単にはいかないですねw

![スクリーンショット 2023-03-01 23.13.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403613/32b6af2a-9557-7e03-09e5-e1fbdb455a05.png)

そのほかにも

`UTTypeCreatePreferredIdentifierForTag` の実装や、`UTTypeCopyPreferredTagWithClass`などでも　deprecatedでwarningになります。

## 対応方法

`UniformTypeIdentifiers`の利用が推奨になったのでそれを使っていきます。
以下`UniformTypeIdentifiers`の説明はこちらに載っていましたので引用します。

https://qiita.com/yosshi4486/items/b8d1ff757d8986b1f2b1


実装は以下の感じです。

``` Swift 

import UniformTypeIdentifiers

...

myImagePickerController.mediaTypes = [ UTType.image.identifier ]



```

上記のような感じで実装できるようになりました。　

`UTTypeCreatePreferredIdentifierForTag`などは


``` Swift 
extension URL {
    func mimeType() -> String {
        let pathExtension = self.pathExtension
        if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as NSString, nil)?.takeRetainedValue() {
            if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() {
                return mimetype as String
            }
        }
        return "application/octet-stream"
    }

... 
```

上記の実装が

``` Swift 
extension URL {
    func mimeType() -> String {
        let pathExtension = self.pathExtension
        if let type = UTType(filenameExtension: pathExtension) {
            if let mimetype = type.preferredMIMEType {
                return mimetype as String
            }
        }
        return "application/octet-stream"
    }

...

``` 

このように簡潔に書けるようになりました。

より簡潔にかけるので素晴らしいですね！

## まとめ

こういった細かな変更などはちゃんとキャッチしてかなければならないねと、改めて学んだ内容でした。
具体的な内容は公式を読むのが一番なのでこれはメモ要素を含めたまとめ記事とさせていただきます。
同じような対応で力になれたら幸いです。

ではまた！

### 参考

https://developer.apple.com/documentation/uniformtypeidentifiers

https://developer.apple.com/documentation/uikit/uiimagepickercontroller/1619173-mediatypes

https://stackoverflow.com/questions/69332404/whats-the-library-should-i-import-for-uttypeimage-which-is-the-replacement-of

https://stackoverflow.com/questions/69540672/ios15-uttype-deprecations-for-url-extension
HTML基礎

# 必修tag　覚えておきたい<タグ>
- h：見出し
- br：改行
- p：段落
- a：ハイパーリンク
- img：画像
- ul > li：箇条書きリスト
- ol > li：順序リスト
- div：意味を持たないブロック要素タグ
- span：意味を持たないインライン要素タグ
## VScode画面
![スクリーンショット 2023-03-01 23.43.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/ac0522c0-cde0-bdd3-41c7-230c1bd0512d.png)
## Live Server画面
![スクリーンショット 2023-03-01 23.47.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/f03770d8-bbe8-588e-0300-c242f9ff7e7d.png)
## 「sample.htmlへ」を押すと
![スクリーンショット 2023-03-01 23.49.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/bb58b299-4d3a-b19c-fc4b-72aed6014770.png)
Python全く分からん自分のアウトプット　その7

7日目：今日はProgateを進める前に、少しGoogleColaboratoryを触ってみた。
色々調べて使ってみた感じその場で動きを見れたから、最初はColabでやってみるのがいいかもしれない。



◎以下調べたこと、疑問に思ったこととかのメモ◎


メソッド・・・目的を達成するために決められたやり方、方法、方式。らしい。要はオブジェクトに対して操作できるリモコン部分ってとこ？

def・・・関数の作成に使うやつ。definitionの頭文字3文字を使った略称。

関数・・・なんとなくで考えてたけど、関数とは「インプットされた値をもとに、決められた処理を実行してくれるプログラムの部品」ということみたい。

__init__():・・・インスタンスメソッド発動！！

script.py・・・プログラムの実行部分(今回)
menu_item.py・・・MenuItemクラスの定義部分(今回)

import モジュール名・・・別ファイルに移して呼び出せる。Pythonコース3でもやったところ。つまりHTMLとCSSみたいなもの？

from モジュール名 import クラス名・・・モジュール内の指定したクラスを直接読み込むことができる。モジュール名はファイル名で、「.py」の部分はいらない。要するにデッキからサーチできるってことか？

self・・・インスタンス自身を指す慣用句。前回の復習。

round()・・・四捨五入で表示される。「print(round(number))」って感じ。

input・・・ユーザーがキーボードに入力したデータを受け付けるための関数。こっちは標準入力として用意されている。入力を受け取る。

if文には「：(コロン)」を忘れずに！！！


----------------------------------------------------------------------

Pythonコース4が終了。最後以外は復習もあったからなのか思ったよりスムーズにできた。
最後の演習はめっちゃ答え見た。見まくった。
最終演習は大体その章の応用として出題されているから、そこで全然分からなかったということは基礎がまだまだできていないことの証明なので、基礎をしっかりと固めていくのが現状の課題。焦らずやっていこう。
次は最後のPythonコース5なので出来れば最終演習まで通しでやろうと思う。ていうかやる。
flutterのriver_podで躓いたところ：futureとは？？AsyncValueとは？？


## hogeFutureProvider.futureのfutureとは??
```dart
final hogeProvider = FutureProvider.autoDispose.family<HogeResult, String>(
        (ref, String from) async {
  final hoge = await ref.watch(hogeProvider.future); ← このfutureってなんや??
});
```


### 結論：非同期で値を確実に知りたい時にasync・await・futureのセットで使用する
nodeでいう、async-awaitがflutterでは、async-await-futureとなってる。
```dart
final hogeProvider = FutureProvider.autoDispose.family<HogeResult, String>(
        (ref, String from) async {
  final hoge  = await ref.watch(hogeProvider.future);
       //↑このhogeで確実に非同期で取得した値をセットしたいときに使用する。
});
```



## AsyncValueとは？？

### maybeWhen(loadingとerrorとdataが取ってこれる)で取ってこれるということ
ちなみにAsyncValueのデータの中身だけ欲しい場合、
→.futureをつけると中身のデータだけ取得できる
Docker コンテナが起動しない マウント系のエラー

## 概要

- docker-compose.yamlを自分でいじったあとdocker-compose upしたらマウント系のエラーが発生したので解決までの経緯をまとめる。

## 問題発生までの経緯

- docker-compose.yamlのvolumesをいじった。
- 下記コマンドを実行してコンテナを起動した。

    ```
    docker-compose up
    ```

## 問題

- 下記のエラーが出てコンテナが起動しない。

    ```
    unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type'
    ```

## 問題解決までの経緯

- 下記の記事を参考に確認したところvolumesで指定したファイルがホストPCに存在しなかった。

https://qiita.com/hanakok/items/6bfcfbb8b7b4df877178

- その代わりファイル名と同じディレクトリが作成されていた。
- 参考文献にある通り、`$ docker-compose up`した際にvolumesがホストPCに無かった場合ディレクトリを自動で作ってくれるらしい。
- 自動で作成されたディレクトリを削除した。
- マウントするファイルを設置した。
- `$ docker-compose up`を実行した。
- 同じエラーがでて解消されない。
- `$ docker-compose down`を実行してボリュームを削除した。
- `$ docker-compose up`を実行した。
- 問題は解決した。

## 参考文献

https://qiita.com/hanakok/items/6bfcfbb8b7b4df877178
AndroidStudioでbuild-logicモジュールのbuild.gradle.ktsが正しく認識されない

AndroidStudioで、とある開発中のプロジェクトに**build-logic**モジュールを作成しました。

ディレクトリの構造は次のとおりです。

```md
- build-logic
    - convention
        - src
          - main
            - kotlin
              - com
                - takagimeow
                  - app
        - build.gradle.kts
    - gradle
    - gradle.properties
    - settings.gradle.ts
```

そして、作成した**build.gradle.kts**を開くと次のようにハイライトされていない状態で表示されていました。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577119/3833692d-6df2-5c3b-a0b9-f9bd3add75e8.png)

画面上部に表示されている`Add to standalone scripts`を試しにクリックしてみたところ、`org/gradle/tooling/BuildException (java.lang.NoClassDefFoundError: org/gradle/tooling/BuildException)`というエラーも赤色で表示されてしまいました。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577119/66899fa7-18f1-9168-e002-4e3ed2c906eb.png)

本来想定していたのは、次のように通常の**build.gradle**と同じようにシンタックスハイライトが実行されている状態でした。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577119/0d95e061-5187-7fe5-3df1-bceb01acc7e4.png)

色々試してみたところ、その上の階層にある**settings.gradle.kts**に**build.gradle.kts**が存在する**convention**モジュールがインクルードされていないことに気づきました。

なので、試しに`include(":convention")`を末尾に追加して、`Sync Project with Gradle Files`を実行しました。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577119/e77a2750-7c55-e08f-2a4b-ef96c89fdff3.png)

そして実行完了後、再度**build.gradle.kts**を開いてみると今度はちゃんとシンタックスハイライトがされた状態で表示されるようになりました。

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577119/723c79f2-0a74-4cec-bec8-3edead35587d.png)

しかし、見ての通りまだ赤く表示されたエラーは消えていないことがわかります。
これを解決するために、一度ウィンドウを閉じて、Android Studioを再起動させてプロジェクトを開き直しました。

するとこれが功を奏してエラーも表示されなくなりました。

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577119/3c1e49a0-772d-8319-752e-9d4f2f706d67.png)
㊗️初投稿🎉 『不動産営業マンがエンジニアになる話』

 <h1>ご挨拶</h1>
投資用不動産会社で営業と宅建しかやっていない男(28)が、未経験からエンジニアになる話です。<br>
2023年3月に現職を退職、そして3ヶ月間でエンジニア未経験転職を狙う。<br>
<br>
下記のスケジュールを理想とし、活動していきます！<br>
アウトプットして成長スピード上げていきますので、ご指導よろしくお願いします！！
<br>
<br>
▼スケジュール<br>
2023年2月末：退社<br>
2023年3月上：過去通ったプログラミングスクール復習（2021.10~12）<br>
2023年3月中：ポートフォリオ作成開始<br>
2023年4月上：転職活動本格始動（ポートフォリオの質向上とスキルアップは継続する）<br>
2023年5月中〜6月：エンジニアへ！！
[memo] プログラミング系の遊び？

# プログラミング系の遊び？

遊びというか、学習法というか。

## Hello world

単に、文字列を出力するだけのプログラム。

開発環境の動作確認、開発手順を確認するため、あるいはより複雑なプログラムを作るための第一歩として作成する事が多い。

https://ja.wikipedia.org/wiki/Hello_world

## FizzBuzz問題

数字を1から順番に繰り返して、以下の出力を得るプログラムを作る

* 3の倍数（ただし5の倍数でない）なら "Fizz"
* 5の倍数（ただし3の倍数でない）なら "Buzz"
* 15の倍数なら "FizzBuzz"
* それ以外の場合にはその数値そのもの

もともとは英語圏でのパーティーや、バス内で行われるゲームだが（日本でいう山手線ゲームとかしりとりみたいな位置づけ？）、プログラムを書けるかどうかを判断するのに課題として使われることがあるという噂がある。

https://ja.wikipedia.org/wiki/Fizz_Buzz

ちなみに "Fizz" は炭酸水などのシュー、シュワーという音を示す。カクテルのジン・フィズなどのフィズと同じもの。
"Buzz" は虫の羽音や機械の低音のうなり、ざわめきなどを示す。派生語にブザー(buzzer)やバズワード(buzzword)等がある。

## Quine（クワイン）

自身のソースコードを出力するプログラム。

https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AF%E3%82%A4%E3%83%B3_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)

## コードゴルフ

特定の目的のプログラムを、可能な限り短いソースコードで書く競技。
レギュレーションはさまざまだけど、一般的には（標準出力に）正しい結果さえ出力されれば、エラーが起きても（標準エラー出力に出力される、終了コードが0でない、コケるなど）気にしないことが多い。

https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%BC%E3%83%89%E3%82%B4%E3%83%AB%E3%83%95

## 言語の実装

コンパイラやインタプリタなどを実装する。
よく作られるのは比較的簡易な言語であることが多いが、複雑な言語を作る人もいる。

* Lisp 系
    * MAL(Make a Lisp) - GitHub: [kanaka/mal](https://github.com/kanaka/mal)
    * Pure Lisp - wikipedia: [純LISP](https://ja.wikipedia.org/wiki/%E7%B4%94LISP)
    * orelang - Qiita: [プログラミング言語を作る。１時間で。](https://qiita.com/shuetsu@github/items/ac21e597265d6bb906dc)
* Brainf*ck や whitespace などの[難解プログラミング言語](https://ja.wikipedia.org/wiki/%E9%9B%A3%E8%A7%A3%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E8%A8%80%E8%AA%9E)、あるいはその派生言語など


## わざと複雑な（読みにくい）コードを書く

* [IOCCC](https://www.ioccc.org/) - The International Obfuscated C Code Contest（国際難読化Cコードコンテスト）
* [Rubyによる超絶技巧プログラミング](http://id.nii.ac.jp/1001/00095382/) リンク先の pdf を開く
* [JSFuck](https://en.wikipedia.org/wiki/JSFuck)

https://ja.wikipedia.org/wiki/IOCCC

## 〇〇を〇〇言語で作ってみた系

Qiita やその他ブログなどで、誰かが作った（比較的簡単な）プログラムを、別の言語でも作ってみて公開する。

例えば以下のようなものがあった

* カフェでプログラミングしてる風（でも何もやっていない）〇〇言語コード
* マイナンバーのチェックデジットを計算
* 〇〇言語で[湯婆婆](https://qiita.com/tags/%e6%b9%af%e5%a9%86%e5%a9%86)を実装してみる
* 〇〇言語でスンドコキヨシを書いてみる
* などなど

あるいは、既存のゲームやアプリなどを実装するというものもある。

* テトリス
* マインスイーパー
* パックマン
* などなど

アルゴリズム系では

* フィボナッチ数列
* エラトステネスの篩
* YコンビネータとかZコンビネータ
* などなど

## 競技系プログラミング

省略
正六角形を数える

次のような問題を考えます。

### 【例題１】下の図形の各点を頂点とするような正六角形はいくつあるか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1922159/f1d6e96b-bd6e-9b79-883c-75bfe610ba6e.png)

手で書いて数えても何とかなりそうなのでやってみます。

#### 一辺が１の正六角形

一辺が１の正六角形の一つを示します。よく見ると正六角形の中心が赤の点で示される内側の点であることに気が付くと思います。従ってこれは7個あることが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1922159/5a98abe6-604a-fc1f-d9e8-b56a5e16adaa.png)

#### 一辺が２の正六角形

これは最初の図を見れば明らかに１つです。

従って、合計8個が答えと考えてしまいますが、**実は違います**。

#### 正六角形の頂点以外の点で出来る正六角形

最初の図で正三角形のメッシュが書いてあるので、ごまかされるかもしれませんが。必ずしもこの線に沿う必要はありません。下の図の赤い正六角形のように辺のの途中の点を結んで正六角形が出来ます。**答えはこれを足して9個となります**。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1922159/e0e184fd-2c1a-4c73-d96d-39eb429c2c10.png)

### 【例題2】同様に一辺がnである場合、正六角形はいくつあるか？

例題１の解法を踏まえて、一辺がnである場合を考えます。

1. 辺の長さがkの正六角形（外側の正六角形と同じ向き）がいくつあるか
1. その長さがkの正六角形の辺上に頂点を持つ正六角形がいくつあるか

これをそれぞれ掛け合わせて答えを出します。

#### 1. 辺の長さがkの正六角形がいくつあるか

上の「一辺が１の正六角形」で示したように。

* 一辺が１の正六角形の数は一つ内側より中の点の数
* したがってkの正六角形は(n-k)内側より中の点の数

一般に一辺がmの正六角形の内部の点の数は[中心つき六角数(hex number)](https://mathworld.wolfram.com/HexNumber.html)と呼ばれ以下の式で表されます。

```math
h_m = 3m^2+3m+1
```

この数列は[OEIS A003215](https://oeis.org/A003215)でも示されるように、$1, 7, 19, 37, 61, 91, ...$となります。

#### 2. 長さがkの正六角形の辺上に頂点を持つ正六角形がいくつあるか

例題１で長さが2のでは2個でしたので推測できますが、以下のように辺の長さの数だけ辺上に頂点を持つ正六角形があることが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1922159/8adf33dd-e5ba-9d05-caeb-7fec0b8e0554.png)

### 正六角形の総数

この2つを合わせると正六角形の総数$H_n$は以下のようになります

```math 
\displaystyle H_n = \sum_{k=1}^{n}k*h_{n-k} \\
```

これをプログラムにすると以下のようになります。出力は分かりやすいように、総数と、各大きさの六角形の数をリストで表示するようにしました。

```python 
def numHex(n):
  return 3*n**2+3*n+1

def numHexAll(n):
  ret, ans = [], 0
  for k in range(1,n+1):
    h = numHex(n-k)
    ret.append([k,h])
    ans += k*h
  return ans, ret

for n in range(1,8+1):
  print(n, numHexAll(n))
# 1 (1, [[1, 1]])
# 2 (9, [[1, 7], [2, 1]])
# 3 (36, [[1, 19], [2, 7], [3, 1]])
# 4 (100, [[1, 37], [2, 19], [3, 7], [4, 1]])
# 5 (225, [[1, 61], [2, 37], [3, 19], [4, 7], [5, 1]])
# 6 (441, [[1, 91], [2, 61], [3, 37], [4, 19], [5, 7], [6, 1]])
# 7 (784, [[1, 127], [2, 91], [3, 61], [4, 37], [5, 19], [6, 7], [7, 1]])
# 8 (1296, [[1, 169], [2, 127], [3, 91], [4, 61], [5, 37], [6, 19], [7, 7], [8, 1]])
```
（開発環境：Google Colab）

この考え方はProjet Euler, Problem 577 Counting hexagonsを解くのに役に立ちます。
LINE WORKS のAPIトークンをボタンひとつで発行する

## JWT認証のトークンをサクッと取得したい

LINE WORKS APIを実行するためのトークンを検証等で使いたいが
コード書かずにサクッと取得したい方のための便利ツールです。

JWT認証のAccess Tokenについて公式ドキュメントは[こちら](https://developers.worksmobile.com/jp/reference/authorization-sa?lang=ja)

#### 実行イメージ

「トークンを発行する」ボタンを押したらいつでもAccess Tokenを取得できる
<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727469/2144b007-5139-53cd-c86d-5488279bc04b.png">

## 必要なもの
* Googleアカウント（無償でもOK）
* LINE WORKS Developers Consoleへのアクセス権限を持つID


## 事前準備

### 1. LINE WORKS Developersから認証情報をコピー

LINE WORKS Developers へアクセスして、アプリを新規追加します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727469/9442be87-7f4e-4c47-188f-0594ad5e3023.png)

 「アプリの説明」に任意のテキストを入力します
 「**Client ID**」をコピーしてメモしておきます
 「**Client Secret**」をコピーしてメモしておきます
 「Redirect URL」に任意のURLを入力します
 「**Domain ID**」をコピーしてメモしておきます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727469/c7e30934-0ac4-ee83-8361-a65d66b15ee6.png)


「**OAuth Scopes**」の管理にて、とりあえずすべてのScopeを選択して保存します。
*Scopeは利用範囲に応じて狭めてください

<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727469/f46623fe-61cf-657d-d3e9-d5287989f1ab.png">

「**Service Account**」をコピーします
「**Private Key**」の発行ボタンを押してkeyファイルをダウンロードします 

<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727469/f82383a7-b690-8320-7902-7395645f5766.png">

### 2. GASの設定

Google Sheetの[LINE WORKS便利ツールをコピー](https://docs.google.com/spreadsheets/d/1TyvRvWeLlLifDeeHovdtzAqNHxdg9KbizBvRqzhai_A/copy#gid=1141509122)します

シート「jwtGenerator」を開き、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727469/0fb6d93e-d883-106b-64b6-c5cb05950690.png)
「事前設定」のフィールドに先ほどコピーした
* **Client ID**
* **Client Secret**
* **Service Account**
* **Private Keyのファイル名** _(「private_2023xxxxxxxx.key」というような名称)_
* **OAuth Scopes**はそのまま
* **Domain ID**
を、それぞれ入力します

#### Private KeyファイルをDriveにアップロードする
つぎに、先ほどLINE WORKS Developers Consoleからダウンロードした
**Private Keyファイル**を、「LINE WORKS 便利ツール」と同じGoogle Driveのロケーションに配置します。

ロケーションへの移動の仕方は以下

<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727469/a5f2f2a8-c8f1-ed33-bc6b-d72517e65222.png">

ドラッグ＆ドロップで.keyファイルをアップロード


<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727469/ed63759c-63ce-93b5-83b2-9d3bc9d15141.png">

### 3. token発行のテスト

jwtGeneratorシートにもどり、
「トークンを発行」ボタンを押します

<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727469/2144b007-5139-53cd-c86d-5488279bc04b.png">

Access Token と Refresh Tokenに何やら文字列が表示されたら、テスト成功
以後はボタン押せばいつでもTokenを再発行できます
なおAccess Tokenの有効期限は24時間です

文字列がなにも表示されない場合は、
手順を最初から見直してみてください。



-----------------------------------

LINE WORKSの標準機能では出来ないあれやこれやを解決するLINE WORKS便利ツール
今後はこんなツールを予定しています

* ユーザを一括削除したい
* 組織を一括追加したい
* グループを一括追加したい
* ID名を一括変更したい
* メッセージを一斉配信したい
* 監査ログを自動保存したい
* SNSのコメントやメッセージをLINE WORKSへ通知したい
etc...

今後なにかご要望があればお知らせください
作ってみるかもしれないです。