OmniAICreator/Qiita-1.07M huggingface dataset:
if you encounter 'parser ModuleNotFoundError' when running NFStest on Jammy

## 問題 ##

[Ubuntu 22.04](https://releases.ubuntu.com/22.04/)で[NFStest-3.0](https://linux-nfs.org/wiki/index.php/NFStest)を動作させようとすると以下のエラーメッセージで実行できず。  

```
vagrant@ubuntu-jammy:~/NFStest-3.0/test$ ./nfstest_posix -h
Traceback (most recent call last): File
"/home/vagrant/NFStest-3.0/test/./nfstest_posix", line 27, in <module> from nfstest.test_util import TestUtil File
"/home/vagrant/NFStest-3.0/nfstest/test_util.py", line 60, in <module> from nfstest.nfs_util import NFSUtil File
"/home/vagrant/NFStest-3.0/nfstest/nfs_util.py", line 34, in <module> from nfstest.host import Host File
"/home/vagrant/NFStest-3.0/nfstest/host.py", line 33, in <module> from packet.pktt import Pktt File
"/home/vagrant/NFStest-3.0/packet/pktt.py", line 49, in <module> import parser ModuleNotFoundError: No module named 'parser'
vagrant@ubuntu-jammy:~/NFStest-3.0/test$
```
原因は、Python 3.10以降で、parseモジュールが削除されたため(参考：[Whatever happened to package 'parser' in Python 3.10?](https://stackoverflow.com/questions/73328659/whatever-happened-to-package-parser-in-python-3-10))。

## 対処 ##

NFStest-3.0の実行時のインタプリタとして、python 3.9を使用する。  
具体的には、pyenvを使用して対処する。pyenvは、実行環境のpythonのバージョンをコントロールすることができる。詳細は、[pyenv](https://github.com/pyenv/pyenv)を参照されたい。  
以下に、Ubunt 22.04でのログインshellがbashであるユーザへのpython 3.9を導入する手順を示す。

### Ubuntu 22.04へのpyenvのインストール ###

[pyenv](https://github.com/pyenv/pyenv)のREADME.mdの記載内容をUbuntu 22.04向けにサマライズする。

1. pyenvのインストール

		git clone https://github.com/pyenv/pyenv.git ~/.pyenv

2. shell環境の準備

	1. .bashrcの編集
	
			echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
			echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
			echo 'eval "$(pyenv init -)"' >> ~/.bashrc

	1. .profileの編集

			echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
			echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile
			echo 'eval "$(pyenv init -)"' >> ~/.profile
			
	1. 実行環境への反映
	
			exec "$SHELL"

3. pythonのビルド環境の準備

		sudo apt update -y; sudo apt install -y build-essential libssl-dev zlib1g-dev \
		libbz2-dev libreadline-dev libsqlite3-dev curl llvm \
		libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev

### Ubuntu 22.04へのpython 3.9のインストールと環境設定 ###

1. python 3.9のインストール

	以下のコマンドで、3.9の最新版をインストール。

		pytenv insatll $(pyenv install -l | egrep "^\s+3\.9" | tail -1)

2. python 3.9の有効化

		pyenv global $(pyenv versions | sed -nEe 's/.*(3\.9\.[[:digit:]]+).*/\1/p' | sort -V | tail -1)
		
3. pythonのバージョン確認

		python --version

### Ubuntu 22.04でのNFStest-3.0の実行 ###

1. NFStest-3.0のダウンロードと展開

		wget http://www.linux-nfs.org/~mora/nfstest/releases/NFStest-3.0.tar.gz
		tar -xzvf NFStest-3.0.tar.gz

2. NFStest-3.0の実行
   
        cd NFStest-3.0
		export PYTHONPATH=$PWD
		cd test
		sudo mkdir -p /mnt/t
		./nfstest_posix -s *server* -e *share*
プリザンターのスクリプトで用いるJavaScriptの演算子について

 # はじめに
プリザンターでスクリプト機能やサーバースクリプト機能を使うことがしばしばあります。その際、演算子を覚えきれないので、この記事にまとめようと思います。といっても、URLを乗っけるだけですが・・・

 # 参考にしているURL
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators

 # 等値演算子と同値演算子
等値演算子(==)は型が異なる場合には型の変換を試みてから比較を行うそうです。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Equality
同値演算子(===)は型が異なる場合、常に異なるものと判断するそうです。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Strict_equality

要約すると、===のほうが厳密に比較してくれるのでしょう(だから、名前が厳密等価演算子なのかな・・・？)
webpack.config.jsの内容

## 補足
当記事は[Shin Coding Tutorial](https://www.youtube.com/@user-hl9uv6cv7k)様のYoutube動画を参考に作成いたしました。

参考動画は[こちら](https://www.youtube.com/watch?v=ECc1EXnx7VQ)

## Webpackについて
WebpackはCSSやJavaScriptなどの複数のファイルをまとめる役割を持つモジュールバンドラーです。

本記事では、Webpackの設定ファイルであるwebpack.config.jsの記述について簡潔にまとめました。

## webpack.config.js

```javascript
module.exports = {
  entry: {
    bundle: "./src/index.ts", //バンドルしたいファイルのパス(複数指定可能)
  },
  output: {
    path: `${__dirname}/dist`, //バンドルしたファイルを出力するディレクトリのパス
    filename: "bundle.js", //バンドルしたファイルの名前
  },
  mode: "production", //本番モード(production)か開発モード(development)かの設定
  resolve: {
    extensions: [".ts", ".js"], //バンドルするファイルでts、jsファイルをインポートする際に拡張子を省略する設定
  },
  devServer: {
    static: {
      directory: `${__dirname}/dist`, //ローカルサーバーを立ち上げた時に参照するファイル
    },
    open: true, //ローカルサーバー立ち上げ時に自動でブラウザも立ち上げる設定
  },
  module: {
    rules: [
      {
        test: /\.ts$/, //TypeScriptファイルをコンパイルするよう指定
        loader: "ts-loader", // どのローダーを使うのかの指定(複数指定可能)
      },
    ],
  },
};
```
エンジニア転職してから1年間を振り返って


# はじめに
###  この記事で書くこと
他業種から [株式会社ネッコス](https://neccos.jp/) へエンジニア転職して1年が経過しました。

この1年で、
・学んだこと
・取り組んでよかったこと
・やりがいを感じたこと
・難しいと感じたこと
をゆるく書いていこうと思います。


### ネッコスって？

- LINE APIを用いた開発を行うシステム開発会社 です。
  

### 簡単な経歴

- エンジニアコミュニティに所属してプログラミングを学ぶ（3ヶ月）
- 知り合った方とチーム開発、個人開発をしていました（8ヶ月ほど）
- Railsの開発で副業を経験（2ヶ月）
- 株式会社ネッコスに入社（1年経過）

# 1年の業務

- 自然言語解析と連携したlinebot開発 (lambda ruby)
- xserverからAWSへのサーバー移管 (cakephp rds ec2)
- 中規模システムのインフラ担当 (cognito waf ecs  ecr aurola S3 Api Gateway cloudfront)
- 書店向けシステムの開発 (Rails ecs scheduled task)
- LIFF、LINE APIを用いたマップ検索システム開発　(Rails javascript ec2 rds)
- マッチングサービスのLINE Webhook部分の開発　(TypeScript DynamoDB)
- そのほかlaravel案件の機能追加や開発の進捗管理、マネジメント的なことなど

# 学んだこと

- 設計（設計の難しさを学びました..）
    - お客様の利用を想定した機能出し（業務フロー、デザイン）
    - システムでの制御を図にしてまとめること（ステートチャート、シーケンス）
    - 最適なDB設計、サーバー構成の検討
- エラー解消時の切り分け方法でどのように進めれば良いかということ
    - 例）決済サービスのwebhookが届かない
        1. 機能の概要、業務フローを理解すること
        2. 業務フロー図にまとめること
        3. 該当のソースコードを読んで処理の流れを理解すること
        4. シーケンス図にまとめること
        5. 決済リクエストが正常にされているか（ログの確認）
        6. 決済サービス内でログが残っているか
        7. webhookがサーバに届いているか(アクセスログ)
        8. プログラム側の処理が正常にできているか
- 開発時に最低限必要となってくる資料で何が必要なのかということ（一例）
    - DB設計、ER図
    - UI画面、デザイン
    - サーバー構成図
    - 環境情報
    - スケジュール
    - 要件定義・仕様
        - 業務フロー図
        - シーケンス図
        - ステートチャート図
        - ステータス一覧
    - 運用・リリース
    - テスト
- 要件により最適な使用技術、言語、適正なインフラサービスの選択が必要ということ
- 10GB以上のデータを使用してのデモ開発で、データの取得と取り扱い方(sql)
- お客様との認識合わせには開発前の資料準備などが大切だということ

# 取り組んでよかったこと

- 個人サービスの開発
    - 実務で学んだことのアウトプットで効率的に個人サービスの開発ができたことです。
    - 実務で気づかなかったLINE APIの活用法なども見つけられて、仕事に活かせることができました。
- 思い切ってこの案件をやらせてくださいと言って、ある程度の規模の開発案件を設計から開発、サーバー構築まで担当できたことです。（意見を聞いてもらえる会社）

# やりがいを感じたこと
- 依頼のあった企業との商談、要件ヒアリングから関わり、開発まで行うことができたこと。
- 開発したサービスが初めて多くの人に使われたという経験は嬉しかったので忘れないと思います。
  ユーザ数をちょくちょくのぞいていました。それと同時に不安もありましたが、エンジニアとしての自信もついたと思います。
- エラーの緊急対応でアサインされて対応できたこと
  エンジニアとして不具合を解決して役に立てたということで嬉しかったです


# 難しいと感じたこと

- AWS、サーバ、ドメイン周りの理解
    - サーバーの移管作業では必要な作業がわからず、ドメインの変更やデータの移動、手順がわからず苦戦しました。限られたメンテナンス時間の中で作業を行う緊張感もありました。
    - インフラ周りが原因で動作せず、どこが原因なのかについては調査が難しかったです。
    毎度ホワイトボードで教えていただきました。
    基本的なことだと思いますが具体的に以下のような箇所が影響して動かなかったりだったと思います↓
        - ドメイン
        - アプリケーションサーバ
        - セキュリティグループ
        - ファイルの権限
        - SSL証明書
- 慣れない言語での開発
    - 型のある言語での開発、これまで動的言語での経験しかなかった身からすると全然違い苦戦しました。
    - 初めてlaravelなどに触れた時は、railsでいうところの何に当たるかを置き換えて対応していました。
- 商談
    - 要望の聞き方、要件のヒアリングで漏れがないか、議事録で入るだけでやっとです。
- 体調面の管理
    - ずっと座り続けていたので、筋トレと運動は必須です。
    生活リズムを崩さないことも大事だと思います。

# 勉強会
- 毎週集まってわからないことを質問できる場がありました。
- 社内で簡単なLTを経験できました。LTをするとなると説明するための学習に身が入るのでよかったかも
- CTOから開発の歴史や変遷などの話も聞けたり、単純な技術以外でも理解の深められる場でした。
- どういったところから情報収集をしているのか、今後の開発の展望などが聞けたのも面白かったです。

# 今後の展望
- 色々なサービスの設計から実装までできるエンジニアになりたいです。
- AWSの中でも最適なサービスを選択してサービスを開発できるようになりたいです。

# 1年を通しての感想
異業種からの転職で実際のエンジニアとの関わりがなかった身からすると、「どんな人がどんな風に開発しているのだろう」と全てが新鮮な状態で転職してきたことを覚えています。

受託開発ということで案件ごとに全く異なるサービスの開発、お客様に関ることができ、多くの経験が積めたと思います。1年前の自分と比べて1番成長を感じたのはAWS周りの理解だと思います。案件ごとに新規開発とインフラの構築がありそれに関われたことがよかったのだと思います。

その他にも、LINE APIについての理解が深まり個人サービスまで作ることができたのはよかったです。良いアイデアが思いついたら何かサービスは作っていきたいと思っています。
Metasploitable2をM2 Macで起動する(UTM)

セットアップの参考動画：
https://www.youtube.com/watch?v=XwKuoGyZI_U

Metasploitable2について：
https://kaworu.jpn.org/security/Metasploitable

# [概要]
VirtualBoxはM2チップに対応していないため、UTMでMetasploitable2を起動する。そのために、Metasploitable2イメージをqcow2形式に変換する。

# [イメージの変換手順]
metasploitable2をダウンロード
DLページ：https://sourceforge.net/projects/metasploitable/

homebrewをインストール
```
% /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
※homebrewについて：https://zenn.dev/sawao/articles/e7e90d43f2c7f9

qemuをインストール
```
% brew install qemu
```
※qemuについて：https://qiita.com/seigot/items/6590cd23e406ca41bc13

metasploitable2のファイルがある場所に移動。
```
% cd [metasploitable2のファイルがあるパス]
```

lsコマンドで各種ファイルがあることを確認。
```
% ls
Metasploitable.nvram	Metasploitable.vmsd	Metasploitable.vmxf
Metasploitable.vmdk	Metasploitable.vmx
```

qcow2形式のイメージにコンバートする
```
% qemu-img convert -O qcow2 -c Metasploitable.vmdk MetasploitableM2.qcow2
```
特にレスポンスなく完了する。
「MetasploitableM2.qcow2」というファイルがフォルダ内にできる。

# [UTMのセットアップ]
エミュレータ「UTM」をダウンロードする(macOS)
https://docs.getutm.app/installation/macos/

UTM起動後、以下の手順で仮想マシンをセットアップする
```
・[始める]エミュレート
・[オペレーションシステム]その他
・[その他]ISO起動をスキップ
・[ハードウェア]メモリは1028mb（少なくていいと思われる）
・[ストレージ]ストレージサイズは2GB（こちらも少なくてよさそう）
・[共有ディレクトリ]デフォルトでOK
・[概要]仮想マシンの名前は「matasploitable」など管理しやすい名前でOK
　仮想マシン設定を開くにチェックする
```
以上で保存する。

続いて、仮想マシンの設定画面が開くはずなので以下の設定をする。
（開かなかったら仮想マシンを選んで編集する）
```
・IDEドライブ＞ドライブを削除　する
・QEMU＞UEFI起動　のチェックを外す
・ドライブ＞新規＞読み込む　から　先ほど生成した「MetasploitableM2.qcow2」を選択する
```
以上を保存し、マシンを起動する。

# [起動手順]
以降はUTMからmetasploitabe2を起動できる。ユーザ名、パスワードは共に「msfadmin」。metasploitable内でifconfigを叩いてIPアドレスを調べて、同端末（別で立てた仮想マシンでも可）から疎通がとれる。

よいハッキングライフを！

![スクリーンショット 2023-01-19 15.00.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087937/33af8970-a7d1-2b7f-ab0b-26eb9aa636c9.png)
【Ruby】Safe Navigation Operator &.


## Safe Navigation Operator &.

`&.`という演算子を使用してメソッドを呼び出すと、レシーバーがnilだった場合でもエラーが発生しなくなります。

```ruby
class Hoge
  def hoge 
    "hoge"
  end
end
```

```ruby
> hoge = Hoge.new
=> #<Hoge:0x000000010e850c78>
> hoge.hoge
=> "hoge"

> fuga = nil
=> nil
> fuga.hoge
NoMethodError (undefined method 'hoge' for nil:NilClass)

irb(main):010:0> fuga&.hoge
=> nil
```

## if文や条件分岐の書き換え

- if

```ruby
hoge = if fuga
  fuga.hoge
else
  nil
end

=> nil
```

- 三項演算子

```ruby
hoge = fuga ? fuga.hoge : nil

=> nil
```

- Safe Navigation Operator

```ruby
hoge = fuga&.hoge

=> nil
```

## 参考

https://docs.ruby-lang.org/ja/latest/doc/news=2f2_3_0.html
【TypeScript】コード内に出てくる「?」と「:」ってなに

プログラミング初心者です。
先人たちのコードを見ていて、下記のような記載がありました。

```php
aaa ? bbb : ccc;
```

調べてもよくわからず、有識者の方に聞いたら
なんてことはない、if文の省略系でした。

参考リンク
[【JavaScript】if文を1行で超簡単に書く方法](https://prograshi.com/language/javascript/if-ternary-operator/)
[JavaScriptのif文を省略したショートハンドの書き方いろいろ](https://black-flag.net/javascript/20210915-7126.html)
Node.jsのインストールが失敗した原因と解決方法

Vue.jsの学習のための環境構築中、Node.jsをインストールしようとした時にエラーが発生したので、その対応についてのメモ。

#### 実施していた環境構築
Node.jsのアップデートは頻繁に行われるため、バージョン管理ツールとして**nvm-windows**を利用した。

githubからnvm-setup.zipをダウンロードし、nvm-setup.exeを実行してインストールする。
[https://github.com/coreybutler/nvm-windows/releases](https://github.com/coreybutler/nvm-windows/releases)

インストールウィザードに従い、インストール先とシンボリックリンクを指定。

インストール完了後に、nvmコマンドを使ってNode.jsをインストールしようとすると、エラーが発生した。

## Node.jsのインストール

nvmコマンドからNode.jsをインストールするのに使用したコマンド↓
```bash
nvm install latest
```
バージョンを指定してインストールする方法↓
```bash
nvm install (バージョン)
```

## 発生したエラー

>**C:\Users\����\AppData\Roaming\nvm could not be found or does not exist.**

C:\Users\����\AppData\Roaming\nvmが見つからなかったか、存在しません。と言われた。

## 原因

C:\Userの中にあるディレクトリ(ユーザー名)が日本語だったことが原因だった。

そのせいでインストールしようとしても見つからないと言われていた模様。


※一度決めてしまったユーザー名を変更すると色々と面倒なことになるので、今回はユーザー名を変えず、別の方法で解決する。

**※※※ユーザー名はローマ字で付けた方がいいです。**

また、そもそもnvm-windowsインストール時のインストール先の指定を、初めからC:直下にしてしまえば問題は起きないと思われる。

## 解決方法

まずnvmフォルダをコピーして、名前の影響のないC:直下に置く。

次に、Windowsキーから環境変数を編集を押して、`NVM_HOME`の値を新しいパスに変更。(例：c:\nvm)

最後にコマンドを実行する。
```
nvm root [new path] 
```
(例：nvm root c:\nvm)

これでNode.jsのインストールが可能になった。



## おまけ

#### Node.jsバージョンの切り替え
複数のバージョンのNode.jsがインストールされている場合、切り替えることができる。

インストールされているバージョンの確認
```bash
nvm list
…↓結果
   19.4.0
 * 6.9.1 (Currently using 64-bit executable)
```
アスタリスク(*)がついているものが使用中のバージョン。

**バージョンの切り替え**
```bash
nvm use 19.4.0　←使用したいバージョン
…↓結果
  * 19.4.0 (Currently using 64-bit executable)
    6.9.1
```
バージョンの切り替えをする際、管理者権限が必要な場合があるらしい。
コマンドプロンプトを開く際に、「管理者として実行」を選べばOK。

<br>
<br>

参考記事：
https://qiita.com/akipon0821/items/eaeffe79221cfcd4d258
https://github.com/coreybutler/nvm-windows/issues/145
@Immutableと@Stableの使い分け

# 初めに
今回は、JetpackComposeで実装する上で割と重要な@Immutableと＠Stableアノテーションについて書いていこうと思います
### 本文
自分がどういうふうに使い分けてるかというと下記のようになります
利用するクラスが、絶対不変である場合は@Immutableアノテーションを付与。
内部にState等を保持していて絶対不変とは言えない場合は@Stableアノテーションを付与。

こうすることで、＠Immutableアノテーションの場合はcompose compilerが変更はないということを理解してrecomposeがスキップされるようになります。
逆に、＠Stableアノテーションをつけていると値の更新をcomposeに通知しながら、recomposeを減らしてUIの更新を行うことができます。

### 最後に
最近Jetpack Composeで実装している際にアノテーションのレビューをいただき自分が調べたものを備忘録的に残しておこうと思い書きました。
どなたかのお役に立てれば幸いです
Azure 仮想マシン Ubuntu Server 20.04 LTSの作成でハマる

# New-AzVm

Microsoft LearnでAzureを学習しています。
[演習 - Azure PowerShell でスクリプトを使用して Azure リソースを作成する - Training | Microsoft Learn](https://learn.microsoft.com/ja-jp/training/modules/automate-azure-tasks-with-powershell/6-exercise-create-resource-interactively)
でハマりました。

```powershell
New-AzVm -ResourceGroupName *****-********-****-****-****-************ -Name "testvm-eus-01" -Credential (Get-Credential) -Location "japaneast" -Image UbuntuLTS -OpenPorts 22 -PublicIpAddressName "testvm-01"
```
```
New-AzVM: The platform image 'Canonical:UbuntuServer:20.04-LTS:latest' is not available.
Verify that all fields in the storage profile are correct.
For more details about storage profile information, please refer to https://aka.ms/storageprofile
```

`-Image UbuntuLTS`が`Canonical:UbuntuServer:20.04-LTS:latest`を指すのがわかるけど、それが使えないってどういうこと？

# ポータルで見てみる
MarketPlaceにはそれらしき仮想マシンが存在
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116331/ac1b0f7f-d899-458f-e2a5-e3a7c0057d8a.png)

# 色々調べて
ARMの情報の通りにVMのソースイメージの指定のしかたを厳密にすれば特定のUbuntuのイメージを特定できることはわかりましたが、
初心者なのでまだあまりゴリゴリ書きたくない...

どうも、CanonicalによるLTS版の扱いに起因しているようです。
[Can't find ubuntu 20.04 with azure cli · Issue #13320 · Azure/azure-cli · GitHub](https://github.com/Azure/azure-cli/issues/13320)

# 解決策
上記Issueでの投稿を参考に、パラメータを変えて解消
~~ポータルから作成した時に気づいたけど、`-Name`と`-PublicIpAddressName`も合わせておかないとうまくいかないようです。~~
```powershell
New-AzVm -ResourceGroupName *****-********-****-****-****-************ -Name "testvm-jeast-01" -Credential (Get-Credential) -Location "japaneast" -Image "Canonical:0001-com-ubuntu-server-focal:20_04-lts:latest" -OpenPorts 22 -PublicIpAddressName "testvm-01"
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116331/7430e168-a99d-2411-b24d-8d441dc5b3f2.png)
[Android] [Kotlin] Spinnerの初期値項目を文字列で選択する方法

### はじめに
spinnerの初期値項目を設定するときにsetSelectionを使いますが、この引数は(position: Int)となっていて
ちょっとめんどくさいと思いました。
setTextみたいに入れて自動的にリストにある同名の項目を初期値設定にしたい方におすすめです。
javaでの方法があったので、kotlinにしてあげたものです。

### 
```.kt
val spinner: Spinner = findViewById(R.id.spinner)
spinner.setSelection(setSelection(spinner, "文字列"))

private fun setSelection(spinner: Spinner, item: String): Int {
        val adapter = spinner.adapter
        var index = 0
        for (i in 0 ≦ until < adapter.count) {
            if (adapter.getItem(i) == item) {
                index = i
            }
        }
        return index
    }
```
"文字列"の部分で自動検索し、同名の項目をSpinnerの初期値として表示します。
試してみてください！

参考記事
http://anadreline.blogspot.com/2013/07/spinner.html
IRCサーバ構築手順メモ

# はじめに
多くの企業の開発業務等においてはSlackやTeams等が当たり前に使われている中、ビジネスチャットツールの原点ともいえるIRCについて改めて勉強中のため、Linuxでの構築手順メモを備忘録として記載しておきます。

# IRCデーモンインストール手順(Ubuntu)

aptでngrcdをインストールする

```
$ sudo apt install ngircd
```

# IRC設定手順

```/etc/ngircd/ngircd.conf```を編集してサービス再起動

```
$ cd /etc/ngircd
$ sudo cp ngircd.conf ngircd.conf.org
$ sudo vi ngircd.conf
$ sudo /etc/init.d/ngircd restart
```

## 1) IRCサイト名設定項目

```ngircd.conf
;Name = irc.example.net
Name = irc.mzbot.jp　※任意のサイト名
```

## 2) サイト接続時の簡易認証パスワード設定項目

```ngircd.conf
;Password = wealllikedebian
Password = mzbot123 ※任意のパスワード
```

## 3) サイト情報設定項目

```ngircd.conf
;AdminInfo1 = Debian User
;AdminInfo2 = Debian City
;AdminEMail = irc@irc.example.com

AdminInfo1 = MZbot Administrator ※管理者説明
AdminInfo2 = http://www.example.com　※問い合わせ先情報
AdminEMail = admin@example.com　※問い合わせ先メールアドレス
```

## 任意) ウェルカムメッセージ設定

```/etc/ngircd.motd```を編集してサービス再起動

```
$ cd /etc/ngircd
$ sudo cp ngircd.motd ngircd.motd.org
$ sudo vi ngircd.motd
```

# 起動(再起動)手順

```
$ sudo /etc/init.d/ngircd restart
```

# 動作確認

以下からダウンロードしてngircとの接続を確認
http://limechat.net/

# 使用してみた感想
非常にシンプルなアーキテクチャ＆プロトコルであり良い意味で枯れているので、インターネットが使えない(クラウド利用がNG)等の特殊な環境における用途としての有用性は高いのだろうと思いました。
`nvim_open_win()` で作った `floating window` の border を表示したい

# はじめに

## その…なに…？

これを
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507143/e25126b6-e3da-5f39-7206-019d66488a42.png)

こうします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507143/d1934153-d360-f42c-faad-a9a8f39c8fb1.png)

## 環境

- OS
    - Windows10
- Neovim
    - 0.8.0 ( `winget` で配信されている `stable` )

# 解決方法

以下のように `FloatBorder` の `highlight` 指定を記述すると解決できます

```vim
" floating window そのものの色
hi! NormalFloat     ctermbg=249 ctermfg=46 guibg=#2F0B3A guifg=#D8D8D8
" floating window の border の色指定
hi! FloatBorder     ctermbg=249 ctermfg=46 guibg=#2F0B3A guifg=#D8D8D8
```

## `ctermbg=` …とかいろいろ色探すのめんどい

`hi! link` の後に記述するふたつめの `highlight-groups` にコピーしたい `highlight-group` を指定すると、簡単に設定できます

```vim
hi! link FloatBorder NonText
```

## 参考

https://github.com/hrsh7th/nvim-cmp/issues/748
FBXに別のモーションを適用するスクリプト

# 前提
・Blenderのバージョン：3.2.0
・FBX：骨・モーション・スキニングされたメッシュ
・モーション（BVH）：FBXと同じ名前・構造の骨データが入っている


# コード
```python:replace_motion.py
import bpy

fbx_path = "FBXへのパス"
bvh_path = "BVHへのパス"
output_path = "適用結果（FBX）へのパス"

# FBXをインポート
bpy.ops.import_scene.fbx(filepath=fbx_path)
bpy.ops.object.select_all(action='DESELECT')

# 元のArmatureデータを削除する(メッシュだけ残す)
bpy.ops.object.select_by_type(extend=False, type='ARMATURE')
bpy.ops.object.delete()

# BVHをインポート
bpy.ops.import_anim.bvh(filepath=bvh_path)

# メッシュのModifierにBVHのモーションを適用する
bpy.context.view_layer.objects.active = bpy.data.objects['mesh_object']
## (補足)スキニングがおかしくなる場合はメッシュを回転させてモーションに合わせる
## import math
## bpy.context.object.rotation_euler = ( math.radians(90.0), 0, 0 )
bpy.context.object.modifiers["Armature"].object = bpy.data.objects["bvh_object"]

# FBXにエクスポート
bpy.ops.export_scene.fbx(filepath=output_path, bake_anim_use_all_bones=False, bake_anim_use_nla_strips=False, bake_anim_use_all_actions=False)

```
Databricksでlibrosaを使う

こちらを読んで試してみようと思いました。

https://qiita.com/tom_m_m/items/91ba624dd8507bc0b746

マニュアルを読むと`pip install librosa`で行けるようです。

https://librosa.org/doc/latest/index.html

ところが、実際にやってみるとエラーに。

```
%pip install librosa
```

```py:Python
import librosa
```

```
OSError: cannot load library 'libsndfile.so': libsndfile.so: cannot open shared object file: No such file or directory
```

Databricksランタイムには`libsndfile`がインストールされていないのでインストールが必要というオチでした。

https://community.databricks.com/s/question/0D58Y00009Xjx9sSAB/issue-in-importing-librosa-library-while-using-databricks-runtime-engine-112

[initスクリプト](https://qiita.com/taka_yayoi/items/88cb46be00a175085f87)を作成します。

```py:Python
dbutils.fs.put("/cluster-init/scripts/librosa_init_script.sh","""
#!/bin/bash
apt-get --yes install libsndfile1
""", True)
```

クラスターでinitスクリプトを設定します。
![Screenshot 2023-01-19 at 16.47.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/c9b5afe8-a12d-309c-55ee-17a2cdc81214.png)

librosaも[クラスターライブラリ](https://qiita.com/taka_yayoi/items/9407356caadea3dfb47c)としてインストールしてしまいます。
![Screenshot 2023-01-19 at 16.47.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/23db97a3-50ea-3347-c18e-109fc6ad436c.png)

サンプルプログラムを実行します。

```py:Python
# Beat tracking example
import librosa

# 1. Get the file path to an included audio example
filename = librosa.example('nutcracker')

# 2. Load the audio as a waveform `y`
#    Store the sampling rate as `sr`
y, sr = librosa.load(filename)

# 3. Run the default beat tracker
tempo, beat_frames = librosa.beat.beat_track(y=y, sr=sr)

print('Estimated tempo: {:.2f} beats per minute'.format(tempo))

# 4. Convert the frame indices of beat events into timestamps
beat_times = librosa.frames_to_time(beat_frames, sr=sr)
```

無事動きました。
![Screenshot 2023-01-19 at 16.50.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/cb23e1a6-467a-fbbe-3160-245f01f5120f.png)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
JavaScript関数の5つの定義

JSに関数の記述いくつがあって，使い方を把握するように，ここに書いておきます．参考になれると幸いです．


<h5>①まず，通常の定義は</h5>


```javascript
    function exp(x1,x2){
    ...
    }
```

<h5>②即時実行関数式(定義すると同時に実行される)</h5>


```javascript
//場合によって，関数名を省略可能
const s1 = function(x){ return x*x};
s1(2)  //出力=4

//回帰の場合に，関数名が必要 
const s2 = function f1(x){ if (x <=1) return 1; else return x * f1(x-1);}
s2(4)  //出力=24

//即変数に値を与えるのも可能
const s3 = function(x){ return x*x}(3); //s3 = 9

//別の関数の引数にもなれる
function t(x){return x*x}
t(function(a,b){return a-b}(2,3))  //出力=1

```

<h5>③Arrow関数</h5>
Arrow関数は②の関数の簡潔化と思われる 


```javascript
//functionを省略 
var sum = (x,y) => {return x+y};
//関数体に，returnしか存在しない時，return を省略できる 
var sum = (x,y) => x+y;
//引数が１個のみ時，"()"を省略できる
var sum = x => x*x;
//注意，引数がない時，引数の"()"は必要
var sum x = () => 1; 
```

<h5>④可変長引数</h5>
関数の引数の数が特定しないとき，可変長引数(rest parameter)を使う


```javascript
//functionを省略 
function f(...r){
    for (let n of r){ consol.log(n)}
}
f(1,2,3,4,5,6) //1,2,3,4,5,6

//上記引数中の"..."は配列Arrayの"..."と同じものではない
//配列の"..."は，配列を自動分解するキーワードである 
var a = [1,2,3,4];
f(a);     //[1,2,3,4]
f(...a);  //1 2 3 4
```
<h5>⑤関数を値として変数として使う</h5>

```javascript
//functionを省略 
function fun1(r){
    return r + r;
}
var a = fun1(2);  //a = 4
var b = fun1;
b(2)             //4
fun1(2)         //4
```
アクセス制御について

## はじめに
おはこんばんにちは。キティちゃんです。最近、ハイキューというバレーアニメを久しぶりに見ました。試合シーンが特に熱く、1話があっという間に終わってしまいます。アニメは全部で4期まであり、音駒高校と戦う前のところで終わってしまっているので、そろそろアニメ化してほしいですね。それはさておき、本日はアクセス制御についての話をしたいと思います。

## きっかけ
診断のお仕事をしていて、アクセス制御の脆弱性がないかを調べるときに、よく躓いたりするので、まとめておきたいと思いました。また、まとめることで自分の仕事にもちゃっかり活かそうとしています。ついでに誰かのお役にも立てると嬉しいです。

## アクセス制御とは
ユーザがリソースにアクセスすることを許可、拒否したりすることです。本来アクセスが許可されていないはずのところにアクセスができてしまうと、それはアクセス制御の不備として脆弱性と判断されます。

## 例えば
オンラインバンクのサイトがあるとしましょう。オンラインバンクにはログイン機能があり、認証することで、送金であったり、口座情報を確認することができ、認証後の機能は、認可されたユーザのみが利用できます。しかし、アクセス制御がされていない場合、ログインしていないユーザ（未認可）が、ログイン後の機能を利用できてしまいます。これが、アクセス制御の問題です。

## 何が問題なのか？
アクセス制御がされていない場合、個人情報漏洩や、権限の悪用などセキュリティ上の問題に直結します。

## Webアプリ診断で当該脆弱性を疑うとき
よくあるパターンとしては、以下です。

1.URLにUserIDのような固有の値が含まれている
例）hxxps://hogehogevul/300/

2.送信するリクエストにUserIDが含まれている
例-1)　hxxps://hogehogevul?id=300&parm=hoge
例-2)　
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2319159/3a5f59ba-b842-dbda-ba39-79428d54a110.png)
3.Authorization: Bearer <token>　ヘッダを使用している

4.権限の異なるユーザ（Adminなど）のみがアクセスできるページ(URL)がある
例)　hxxps://hogehogevul/alluserlist/
　　 hxxps://hogehogevul/admin/test

5.送信するリクエストに権限を識別しているパラメータが含まれている
例）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2319159/cb14ac61-9389-ab74-348c-d66db0a76675.png)


## どのように確認をするのか
Burpなどのプロキシツールを使用して手動で確認をします。Vexなども含め診断ツールでは、アクセス制御の確認ができないため、手動にて確認する必要があります。
以下の手順にて、確認をします。

1.プロキシツールを使用し、UserIDなどの固有の値を保持するリクエストをInterceptする
2.該当するパラメータを他のユーザの値に変更する
3.Interceptを解除し、リクエストを送信する

改ざんした先のUserIDの方のデータが更新されているなど、本来権限のない操作ができていれば、アクセス制御の脆弱性となります。

<その他>
・Authorizationヘッダを使用している場合、Authorizationヘッダを削除し、Authorizationヘッダ以外のリクエスト内容をコピーし、未認証の状態でコピーしたリクエストを送信してみます。

・権限昇格の場合、一般ユーザで上位権限者のURLにアクセスをしてみます。

・パラメータで権限を判別している場合は、権限を判別しているであろう、パラメータの値を改ざんしてみます。


## こんな場合は、アクセス制御の不備とはならない
ログイン後、セッションIDを異なるユーザのセッションIDに変更する。
【理由】セッションIDでユーザを識別しているため、書き換えて異なるユーザの情報が見れるのはシステムの挙動としておかしくはないため。

セッションIDに限らず、ユーザを識別している値を変更して、変更したユーザの情報が見れるのは、システムの挙動としておかしくはないため、アクセス制御の不備とはなりません。

## 対策
アクセス元のユーザはログインされているか、該当ページへのアクセス権利はあるのか、パラメータはアクセス元のユーザであるのか、サーバー上で検証する必要があります。検証し、アクセスの条件を満たさなければ実行させず、エラー画面へ遷移させることが推奨されます。


## 終わりに
今回はアクセス制御について書きましたが、書いていても結構大変でした。それだけ、アクセス制御は見る範囲も多いというのもありますが、手動にて実施する必要があるからだと思います(たぶん)。今回の内容が誰かにお役にたつことを願います。ありがとうございました。



## 参考
・『第2章 アクセス制御』IPA　セキュアプログラミング講座
https://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/102.html

・『安全なウェブサイトの作り方 - 1.11 アクセス制御や認可制御の欠落』IPA 
https://www.ipa.go.jp/security/vuln/websecurity-HTML-1_11.html

・『脆弱性を見つけよう アクセス制御の不備編』
https://akaki.io/2017/intro_to_ethical_hacker_8

・『体系的に学ぶ 安全なWebアプリケーションの作り方 第2版』　著者：徳丸浩様

・『Webサービスの認可制御の不備によって起こる仕様の脆弱性と対策』株式会社Flatt Security様
https://blog.flatt.tech/entry/authorization_control_security
【Git】リベースの使い方が分かっていなかったのでメモ

## リベースとは？
マージではなく、コミット履歴を移動したり修正、削除したりすること
ただ、マージと似たような処理をすることになる

私も完全に理解はしていないので下のようなイメージで考えています。
（間違っていたらすみません）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884542/71731038-0f3f-7a3f-94d5-489a50e80567.png)

develop2の開発を進めていて、develop2の情報を保持したまま、develop1の情報を取り込みたい！となった時にリベースを使うと認識しています。
リベースする前はC5,C6となっていたコミットIDはリベースするとC5',C6'と変更される用です。
いろいろ理由はあるようです。↓
https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E6%A9%9F%E8%83%BD-%E3%83%AA%E3%83%99%E3%83%BC%E3%82%B9

### VSCodeで試してみる
実際にやってみたいと思います。

1\. develop1、develop2を作成
```
> git branch
*develop1
develop2
```
2\. それぞれに変更を加える
develop1↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884542/d1b47979-8021-1ff0-6752-237dbac9fe32.png)

develop2↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884542/72af56c1-3654-fac6-e4de-41ebb1d650a6.png)

test.txtは共通のファイルで中身は
```:develop1/test.txt
aaaaaaaa
bbbbbbbb
cccccccc
develop1
```
```:develop2/test.txt
aaaaaaaa
bbbbbbbb
cccccccc
develop2
```
となっています。

そのほかにdevelop1には`testDevelop1.txt`、develop2には`testdevelop2.txt`を加えています。

3\. develop2ブランチにリベースする
vscodeでリベースしていきます。
develop2ブランチに移動して、「・・・」からブランチ、ブランチのリベースを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884542/ba766abe-45b2-553c-2b78-ede4a0231853.png)

リベース先のブランチでdevelop1を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884542/05e0e44a-daf0-7982-76ad-47389fe5389f.png)

test.txtでコンフリクトが起きますが、解決してリベースが終了すると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884542/0e6b406d-7fbc-3956-6b1a-bf436ec59330.png)
develop2ブランチにtestDevelop1.txtが取り込まれました。

マージを繰り返すより、リベースをしていった方が、遡る際に手間が少なくなるようなので適切な場面で使用していきたいですね
aws-vaultの備忘録

aws-vaultについての備忘録です。

## インストール
```php
brew install aws-vault
```

## 認証情報登録
```php
aws-vault add xxxxx
Enter Access Key ID: XXXXXXXXXXX
Enter Secret Access Key: XXXXXXXXXXX
```

## 初期設定
追加された[profile xxxxx]の下にMFAなどの情報を設定する。
```php:~/.aws/config
[profile xxxxx]
region=ap-northeast-1
output=json
mfa_serial=arn:aws:iam::XXXXXXXXXXXX:mfa/xxxxxxxxxx
```

## 接続方法
```php
aws-vault exec xxxxx
# 上記のコマンドを実行すると、aws-vaultで登録したキーチェーンのパスワードが求められる
# その後、MFAを入力する
Enter MFA code for arn:aws:iam::XXXXXXXXXXXX:mfa/xxxxxxxxxx:xxxxx

# 下記のコマンドを実行し、接続できているかを確認する（想定しているAWS環境なのかも合わせて確認）
aws s3 ls
```

## セッション期間を確認
```php
env | grep AWS_SESSION_EXPIRATION
```

## セッションが残っている場合
```php
unset AWS_VAULT
```
Discord.js これだけはするな！もしくは陥りやすい間違い集もしくはTips

## Discord.js 禁忌リスト

### なんでこれを書こうと思った？
初心者のときバカなことばっかりやってたからです

### client.on("messageCreate")の濫用

```javascript
//長いのでカット!

client.on('messageCreate', async msg => {
    if(msg.content === "hello") {
        msg.reply("HELLO!");
    }
});
client.on('messageCreate', async msg => {
    if(msg.content === "good morning") {
        msg.reply("GM");
    }
});
client.on('messageCreate', async msg => {
    if(msg.content === "good afternoon") {
        msg.reply("Good afternoon!");
    }
});
client.on('messageCreate', async msg => {
    if(msg.content === "night") {
        msg.reply("Night");
    }
});
client.on('messageCreate', async msg => {
    if(msg.content === "apple") {
        msg.reply("Orange");
    }
});
```
バカみたいに重くなります。絶対にやめてください。

こうしてください
```javascript
client.on('messageCreate', async msg => {
    if(msg.content === "hello") {
        msg.reply("Hello!");
    }
    if(msg.content === "good morning") {
        msg.reply("Good morning!");
    }
    //以下同様
});
```
else if使わない人です、はい
Node.jsやってる人なら当たり前のことですが私は馬鹿でした

### client(v14)のmessageCreateイベントにはメッセージ編集イベントは飛んでこない
いつから変わったんでしたっけ。

### clientのmessageCreateのmessageの内容を取得したい場合はmessage.contentを使う

```javascript
client.on('messageCreate', async msg => {
    if(msg === "hello") {
        msg.reply("Hello!");
    }
});
```
これだと実行されません
messageオブジェクトの中身はJSONだったはずなので
なおreplyとかは生のmessageオブジェクトじゃないとダメです

### var濫用禁止
```javascript
var option = "";

//...
{
    const option = "";
}


//...
```

どこでも禁止。
地獄絵図になります
改変されちゃこまるclientとかplayerはconstが定石。

### audioPlayerはMaxListenerの設定必須（必須じゃありません）
setMaxListenersはイベントのリスナーの数制限です…一切関係ないです…

本当は何もせずにも動いてくれるはずなんですが私の環境ではなぜか聞こえなかったので…。
もし同じようなことに遭遇された方がいたときのために一応。
```javascript
const player = createAudioPlayer({
    behaviors: {
        noSubscriber: NoSubscriberBehavior.Pause,
    },
});
//ここ
player.setMaxListeners(100);
```
100にしてるのは気まぐれのはずです
もちろんもっと下げてもOK

### YouTubeのサムネイルの取得
YouTubeのサムネイルの構成は以下のようになっています
```
https://img.youtube.com/vi/id/hqdefault.jpg
```
hqdefault.jpgに関してはクオリティです
オプションは何個かありますがDiscordで使うならhqdefaultで十分
idは
```
https://youtube.com/watch?v=//ここ
https://www.youtube.com/watch?v=//ここ
```
です
覚えておくと便利かも

### messageCreateにbotかどうか判断させる
```javascript
if(msg.author.bot) {return;}
```
をつけてください。でないとBot自身が送信したメッセージにBotが応答しつづける、みたいな事が起きてしまいます。

### repl.itで音楽Botを作る方法

```bash
npm install tweetnacl prism-media
```

本来sodiumやsodium-nativeなどの暗号化パッケージを入れるのですがrepl.itの場合はなぜかフリーズしてしまったためtweetnaclを使います。
prism-mediaを入れるのは@discordjs/voiceを入れたときに入らないからです。音楽再生用のパッケージのため、入れないとエラーが走ります。

現状はこれで動いてますね。

### repl.itでパッケージがインストールできなくなった場合
```bash
rm -r node_modules
```
でnode_modulesを削除します。
そのあと
```bash
npm install
```
を実行すれば治るはずです。
### 追記について
やる気が出次第どんどん追加します
Growiの更新をIFTTTを使ってMattermostに通知する

弊社ではGrowiがポータルサイトとして機能していますが、Mattermostが一番社員に伝わる媒体なので、イベントが発生した時に各ユーザが操作せずとも自動でMattermostに通知が飛ぶようにしてみました。

※Growiでは通知機能がSlackAPIを使う方向のようで、Webhookは将来的に廃止されるとなっています。


# 環境
Growi：5.8.1
Mattermost：7.7.0

# 連携の流れ

```plantuml
autonumber
Growi -> IFTTT : e-mail
IFTTT -> Mattermost : Webhook
```

# Growiの設定
1. `外部ツールへの通知`→`Global notification`→`通知設定の追加`から設定画面を開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985470/d5410001-ddae-920d-2ea9-4b37aac19d07.png)

2. トリガーパス、通知先、トリガーイベントを指定して`更新`ボタンを押し、設定を反映します。
    - ＜トリガーパス＞
    通知したいページのパスを指定（`/*`ですべてのページが通知対象になります）
    - ＜通知先＞
    `Email`
    - ＜✉＞
    `trigger@applet.ifttt.com`
    - ＜トリガーイベント＞
お好みに合わせて（CREATE,EDIT,LIKE,POSTを選択してみました）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985470/b0feb26b-9f60-e62b-f5c2-cb69d042f649.png)


# Mattermostの設定
1. `統合機能`→`内向きのウェブフック`で、`内向きのウェブフックを追加する`から設定を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985470/f3fa19a5-f63c-f63d-d263-22ec9151cc3a.png)
設定画面見て適当に設定できそうなので細かいことは省略しちゃいますが詳細は下記を参照ください。
https://developers.mattermost.com/integrate/webhooks/incoming/
2. Webhook用のURLが生成されるので、次項のIFTTTの設定で利用します。

# IFTTTの設定
1. `If This`の`Add`で`Email`を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985470/1e56bdd5-00c9-856b-0685-d3101b37c810.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985470/0c3ff7d9-6c4a-6b04-7f32-5727a5d92bfc.png)

2. `choose a trigger`で`Send IFTTT any email`を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985470/0c88fb22-ada6-d777-7d8f-fc014b5d8776.png)

3. `Then That`の`Add`で`Webhook`を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985470/0dae5d9c-b1bf-2df2-00ca-39ff703c82b2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985470/fad7d99e-286e-9229-2007-f27ff541c822.png)

4. `Make a web request`でWebhookの設定を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985470/5080ab7c-7d15-20aa-7db1-84fbe65bd721.png)
    - ＜URL＞
    Mattermost側で生成したWebhook用のURLを指定
    - ＜Method＞
    `POST`
    - ＜Content Type＞
    `application/json`
    - ＜Additional Headers＞
    ※設定しませんでしたがご自由にカスタマイズを。
    - ＜Body＞
    `{"text": "{{Subject}} \n {{Body}}"}`　※左記のように設定してみましたがご自由にカスタマイズを。

5. 設定を適用して有効化します。

以上で設定は完了なので、Growiで編集などして動作確認してみましょう！
【備忘録】VroidStudioで作ってBlenderで編集したモデルをテクスチャごとUnityへインポートする

# 環境
Unity 2019 4.38f
Blender 2.91.2
VRoid Studio 1.19.0 製品版（ベータ版でも同じだと思う）

# 概要
- VRoid Studio ( https://vroid.com/studio ) で3Dモデルを作成、.vrmファイルとしてエクスポート
- Blenderでモデルとテクスチャ改修
- Unityへインポート

この流れで作業をやりたかった話。
誰かの解決策になればいいなと思って書き記します。

# VRoid Studioって
VRoid Studioとは、ヒト型アバターを手軽に作成できる**無償で商用・非商用利用**できる非常にありがたいソフトです。

これはモデル制作の面でとても楽なのですが、エクスポートの種類が **.vrmエクスポート**、**VRoid Hubへアップロード**、**3Dプリント向けエクスポート**の３種類しかありません。（おそらく）
Blenderでポリゴンやテクスチャをいじるにはちょっと優しくないです。

# VRoidからBlenderへモデルを移植
まず、Blenderで.vrmファイルを扱えるように、Blenderへアドオンをインストールします。
**VRM Addon for Blender**: https://github.com/saturday06/VRM-Addon-for-Blender
ver2.83以降のBlenderに対応しています。

これをインストールすると、Blenderのファイル>インポートにVRMの項目が出ますので、そこからVRoid Studioでエクスポートした.vrmファイルを読み込めます。

# 3Dモデルを編集したい人向けの話
VRoid Studioで制作したモデルをそのままUnityで使用したい人はここを読み飛ばしても大丈夫かと思います。

VRoid Studioからそのままインポートした3Dモデルには、問題点がいくつかあります。

- パーツすべてがひとつなぎのオブジェクトとしてまとめられてしまっている
このままでは編集できないので、オブジェクトを分離します。
    - 分離したいオブジェクトを選択、編集モードへ
    - Pキーを押してマテリアルで分割
    VRoid Studioから持ってき3Dモデルには既にマテリアルが割り当てられているので、マテリアルから分割するのが楽です。

- 重複頂点がある
VRoid Studioから持ってきた3Dモデルにはいくつか重複頂点と呼ばれるものがあり、見かけ上は面がつながっているように見えても実は……ということがよくあります。
VRoid Studioでテクスチャの切れ目になっている部分にこれがよく見られると思います。
    - Aキーでオブジェクトを全選択
    - Mキーを押して距離でマージ、もしくは上タブのメッシュ>クリーンアップ>距離でマージ
正直これをやっても変な頂点は存在するので、根気よくやっていくことが大事。

# BlenderからUnityへモデルを移植
ここでも、Unity上で.vrmファイルを使用できるように、Unityへパッケージをインポートします。
**UniVRM**: https://github.com/vrm-c/UniVRM/releases
ver2020.3 LTS以降のUnityに入応しています。

Blender上で.vrm形式としてエクスポートし、それをUnityにインポートします。

.fbxファイルでエクスポートしてからUnityへ流すのを紹介しているサイトをよく見かけましたが、そうするとそもそもテクスチャ情報が内包されていなかったり、Unity側でテクスチャ（マテリアル）の再設定が必要と非常に面倒でした。

# おわり
正直、自分が確認していないだけで.vrmファイルにも不都合な点があるかもしれません。
特に、自分はアーマチュアや表情を使用しないモデルの使い方をしていたので、そのあたりはバッサリカットしています。

テクスチャ・マテリアル周りの非常に面倒な設定をすっ飛ばしてモデルを使用できるのでとても楽でした、というお話。
[C#] OfficeのCOMオブジェクトを取得後に、キャストエラー


Officeの修復、ライセンス再認証にて解決しました。

Office Home And Business 2019 (クイック実行版、法人向け)にて、プロダクトキーを再認証していたのが原因だったのかもしれません。
単純に、Officeが壊れていた可能性もありそうですが。


1. Windowsの設定から、アプリ一覧、Officeを選択し、変更。
2. **オンラインから修復** のような選択肢を選び、修復。
3. 修復終了後に、ライセンスキーを再入力。
4. 動きました!

*****
以下、症状殴り書き。
```
using pp = Microsoft.Office.Interop.PowerPoint;
using Microsoft.Office.Core;

private static void GetShapeRange(Action<pp.ShapeRange> callback)
{
    pp.Application? app = null;
    pp.DocumentWindow? win = null;
    try
    {
        // COMオブジェクトの取得。
        // オブジェクト自体の取得は出来ているが、キャストエラー。
        // Common.GetActiveObject()内部でprogID, clsIDがPowerPointと一致しているがキャストエラー
        // PowerPointで確認。
        // 別ののCOM(Excel)取得アプリケーションでもエラー出ていたので、
        // おそらくExcelやWordなども駄目かと思われる。
        app = (pp.Application)Common.GetActiveObject("PowerPoint.Application");

        win = app.ActiveWindow;
    }
    catch (Exception exp)
    { }
    finally
    {
        if (win != null)
            Marshal.ReleaseComObject(win);
        if (app != null)
            Marshal.ReleaseComObject(app);

        win = null;
        app = null;
        GC.Collect();
    }
}

internal static class Common
{
    internal static object GetActiveObject(string progID)
    {
        Guid clsid;
        try
        {
            NM.CLSIDFromProgIDEx(progID, out clsid);
        }
        catch (Exception)
        {
            NM.CLSIDFromProgID(progID, out clsid);
        }
        NM.GetActiveObject(ref clsid, IntPtr.Zero, out object obj);
        return obj;
    }
}
```
Power BI Paginated Report （ページ分割レポート）で Power BI Dataset ソースとする際の注意点と回避策としてXMLA エンドポイントを利用する

## はじめに


[Power BI 共有データセットを基づいて改ページ調整されたレポートを作成する](https://learn.microsoft.com/ja-jp/power-bi/paginated-reports/report-builder-shared-datasets) の通り、ページ分割されたレポート(Paginated Report)では、Power BI Datasetをソースにすることができます。

しかし、以下の対応データソースページに記載の制限事項を考慮する必要があります。

![2023-01-19-15-52-35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/1223c8b5-b4dd-775f-2772-95c66986f2d7.png)

![2023-01-19-15-53-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/406a7a1c-d624-eadd-ca17-25aaaad4f7c0.png)

引用：https://learn.microsoft.com/ja-jp/power-bi/paginated-reports/paginated-reports-data-sources


## 準備

1 XMLA エンドポイントの設定確認

私の環境ではPower BI Premium Per Capacity ではなく、Premium Per User環境を使っているので、テナント設定のページの Premium Per Userのデータセットのワークロード設定を読取 or 読み取り、書き込みの状態にしておく必要があります。

![2023-01-19-15-55-16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/918e1516-359f-7d34-22f6-ed4bdce6ed5f.png)


2 XMLAエンドポイントの確認

対象のデータセットが存在するワークスペースにて、設定->Premiumから確認します

![2023-01-19-16-03-49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/5712b12d-89fa-1108-d316-38b3e2a70f97.png)


## 手順

1.Power BI Report Builder を起動して、Azure Analysis Services を選択します。

![2023-01-19-16-04-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/2ee6ffe6-c6ab-6a21-07d5-c3edab32fd8a.png)


2.Build を選択します。

![2023-01-19-16-04-45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/0019a2b5-881d-7934-c1d6-b4566a56b186.png)


3.サーバー名にコピーした XMLA エンドポイントの値を入れます。

![2023-01-19-16-05-51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/3b30baea-a621-62f0-6942-09971192bf72.png)


4.データベースを選択しようとするとサインインが走るので、サインインしてデータベースを選択します。

![2023-01-19-16-07-55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/1ee86682-4850-9157-f586-e783a9fc3f7e.png)


5.Credentials タブにて「 Do not use credentials 」をチェックしておきます。

これは冒頭の対応データソースページの案内にしたがっています。これがないと、 Report Builder 内のデータセットの追加がうまくいきません。

![2023-01-19-16-10-35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/0db677d1-692d-7e3b-1c68-9eda25eac28d.png)

うまくいかないときのエラー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/9ec2e33d-905d-25cf-facf-953625919681.png)




あとは、通常のデータセットに接続した差異の手順で続ければOKです。


## その他参考

https://learn.microsoft.com/ja-jp/power-bi/enterprise/service-premium-connect-tools#connecting-to-a-premium-workspace
SDKを使わずにNode.jsからAzure IoT HubへMQTT接続する

MQTT.jsでIoT Hubに接続したときのメモです。

# 準備

とりあえずテストしたかったので無料プランを利用しました。デバイス作成までは以下が参考になりました。

- [Azure IoT Hub に Mosquitto™ から MQTT なげてみる](https://qiita.com/narutaro/items/1a16ff1321f5044afaf0)

認証はSAS(Shared Access Signature)を利用しました。

# 接続に必要な情報

AzureポータルからIoT Hubのリソースを表示し、必要な情報を取ってきます。（一部伏字にしています）

①ホスト名
②デバイスID
③主キー

- 概要ページ
    - ①ホスト名は[IoT Hubの名前].azure-device.netというフォーマットです。

![iothub-info1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116301/80589988-c940-88ad-afd0-b1a9f203ed62.png)

- デバイス管理 > デバイス > 詳細
    - ②デバイスIDはデバイス作成時に指定したものです。
    - ③主キーはデバイスの詳細から確認できます。

![iothub-info2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116301/d5abe661-9cde-49e2-0955-6845693dd697.png)

# Node.jsパッケージのインストール

mqttとcryptをインストールします。

```bash
$ npm init
$ npm install mqtt crypto
```

# テスト

## コード

トピックをPublishするプログラムです。
動かす際はHOST・DEVICE_ID・PRIMARY_KEYを前述の情報に書き換えてください。
トピック名はデフォルトで「devices/[デバイスID]/messages/events/」が使えます。
コード内のgenerateSasTokenメソッドはAzureのサンプルコード([https://learn.microsoft.com/ja-jp/azure/iot-hub/iot-hub-dev-guide-sas?tabs=node](Shared Access Signature を使用して IoT Hub へのアクセスを制御する))をそのまま用いています。

```javascript:publisher.js
const mqtt = require('mqtt');
const crypto = require('crypto');

//接続に必要な情報
const HOST = ホスト名;  //①ホスト名
const DEVICE_ID = 'dev0';  //②デバイスID
const PRIMARY_KEY = 主キー;  //③主キー

const API_VERSION = '2021-04-12'; //APIバージョン

//SASトークンを生成するメソッド(Azure公式のサンプルより)
const generateSasToken = (resourceUri, signingKey, policyName, expiresInMins) => {
  resourceUri = encodeURIComponent(resourceUri);

  // Set expiration in seconds
  var expires = (Date.now() / 1000) + expiresInMins * 60;
  expires = Math.ceil(expires);
  var toSign = resourceUri + '\n' + expires;

  // Use crypto
  var hmac = crypto.createHmac('sha256', Buffer.from(signingKey, 'base64'));
  hmac.update(toSign);
  var base64UriEncoded = encodeURIComponent(hmac.digest('base64'));

  // Construct authorization string
  var token = "SharedAccessSignature sr=" + resourceUri + "&sig="
    + base64UriEncoded + "&se=" + expires;
  if (policyName) token += "&skn=" + policyName;
  return token;
};

//SASトークンを生成
const token = generateSasToken(HOST, PRIMARY_KEY, null, 60);
//MQTT接続のオプション
const mqttOptions =   {
  username: `${HOST}/${DEVICE_ID}/api-version=${API_VERSION}`,
  password: token,
  clientId: DEVICE_ID
}
//接続
const mqttClient = mqtt.connect(`mqtts://${HOST}:8883`, mqttOptions);
//接続できたらPublishして終了
mqttClient.on('connect', () => {
  console.log('connected to MQTT Broker');
  mqttClient.publish('devices/dev0/messages/events/', JSON.stringify({msg: 'hello'}), { qos: 1 });
  mqttClient.end();
});
//エラー処理
mqttClient.on('error', (err) => {
  console.error(err);
});
```

## 動作確認

上記のプログラムを実行するとトピックがPublishされます。

```bash
$ node publisher.js
```

PublishしたトピックがIoT Hubで受信できているかはAzure CLIで確認しました。
成功すると以下のように受信した内容が表示されます。

```powershell
> az iot hub monitor-events --hub-name ${IoT Hubの名前}
Starting event monitor, use ctrl-c to stop...
{
    "event": {
        "origin": "dev0",
        "module": "",
        "interface": "",
        "component": "",
        "payload": "{\"msg\":\"hello\"}"
    }
}
```
GCP Compute Engine ブラウザSSHの切断問題

# 1. 問題
GCPのCompute Engineって、ブラウザのSSHで接続するのがお手軽かと思います。

ここで問題が、、、
「なぜかすぐ切断される！」

この問題の解決（逃げ）策です

# 2. 原因
Googleの公式サイトの「既知の問題」には

https://cloud.google.com/compute/docs/ssh-in-browser?hl=ja
> 断続的な切断。現時点では、接続の存続時間に関する特定の SLA は提供されていません。ターミナル ウィンドウを長期間開いたままにする場合は、tmux や screen などのターミナル マルチプレクサを使用してください。

とあります

# 3. 解決策
公式サイトのアドバイス通りtmuxを使いましょう！

tmuxとは、複数のターミナルを起動できるようになります。
この機能を使い、サーバー内部で、SSHで接続したターミナルとは **"別の"** ターミナルを起動。
切断を受けた際は、この別のターミナルに再接続することで、再開が可能です

（切断されないのが一番なんですけどね。。。）

### インストール
私はCentOSを使っています
OSに応じてインストール方法は変えてください
```
yum -y install tmux
```

### 使い方
別のターミナルを開始
```
tmux
```

切断を受けた際、再接続
```
tmux a
```

以上です
FESS で Redmine チケットの返信をクロールする

チケット本文はこちら [FessのデータストアクロールでRedmineのチケットを検索する](https://qiita.com/szk0u/items/4a1f655a519d912c4a9f "Redmine Ticket") を参考にしました。


チケットの返信のクロールも同じくデータストアからクロールします。

:::note alert
注意
スクリプトで指定する url はチケット本体と同じにしてはいけません
:::

# データストアのクロール設定
* ハンドラー名「DatabaseDataStore」を指定
## パラメーター

---
    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/bitnami_redmine? 
    useUnicode=true&characterEncoding=UTF-8
    username=XXXXXX
    password=XXXXXX
    sql=select i.id as id, i.subject as subject, notes, j.id as jid, DATE_FORMAT(j.created_on,'%Y-%m-%dT%H:%i:%s.00Z') AS last_modified_dt, p.id as project_id from issues i, journals j , projects p Where i.id = j.journalized_id and i.project_id NOT IN(6,12,34,62,80,129) and j.notes != '' and p.id=i.project_id and p.status=1
---
* url=は環境に合わせてください
* チケットの返信（編集：コメント）は、Table journals の notes に入ってます
* 日付は created_on
* Notes が空ではないこと
* 特定のプロジェクトIDは除外

## スクリプト

---

    url="https://xxx.xx.xx.xx/redmine/issues/" + id + "#note-" +jid
    host="https://xxx.xx.xx.xx/"
    site="https://xxx.xx.xx.xx/redmine/issues/"
    title="【Redmine - Ticket Reply】" + id + " : " +subject
    content=notes
    cache=notes
    digest=notes
    anchor=
    content_length=content.length()
    last_modified=last_modified_dt
    timestamp=last_modified_dt

---

* timestamp に返信の作成日を指定します。
* jid は journal の id でチケットの返信番号とは異なります。
    * （jid はかなり大きな値になります）
* 検索結果から飛ぶとチケットの頭から開きます。

:::note warn
注意：
1. FESS のインデックスは、スクリプトの url= で指定する値に基づいて作成されていると思われる
2. インデックスはユニークで重複は許されない
3. インデックスが同じ値（文字列）になる場合、あとからクロールされた情報で上書きされる
4. データストアのクロールで、Redmine チケットは
url="https://172.25.85.74/redmine/issues/" + id
として指定している。（id はチケット番号）
5. チケットへのリプライも同じ指定にしていると、直近にスケジュールされたクロール情報で上書きされてしまうことになる
6. これを避けるためには url 指定を別のものにしなければならない
...
ARPとは

# ARPがどのタイミングで使われ、何の目的で使われるのかを具体的に知りたい

>ARP（Address Resolution Protocol）は、`IPアドレスからネットワーク上のMACアドレスを求める`ためのプロトコル。「アープ」と呼ばれる。

>　イーサネット上の機器間の物理的な通信では、`IPアドレスではなく、機器固有のMACアドレスという物理アドレスが使われる`。そこで`IPアドレスから宛先のMACアドレスを調べる処理が必要`になる。

### どのような振る舞いをするか
>・データの送信側のコンピューターは宛先IPアドレスのMACアドレスを問い合わせる`ARPリクエストを、セグメントのコンピューターにブロードキャスト`する。
・このリクエストに対して、`指定されたIPアドレスを持っているコンピューターはMACアドレスを送信側に通知`する(ARPリプライ)。
・これにより`送信元はMACアドレスを入手し、イーサネット上で通信が可能`になる。
>
>　この手順を都度行っているとネットワークがARPの通信で占拠されてしまう。そこで`各マシンがそれぞれIPアドレスとMACアドレスの対応を記録したARPテーブルを持ち`、それを参照して送信する。またMACアドレスは変わらないが、IPアドレスはしばしば変更されることがあるため、ARPテーブルは一定時間が経つとクリアされ、できるだけ最新の状態を保つ工夫がされている。

https://business.ntt-east.co.jp/bizdrive/word/arp.html

データリンク層ではMACアドレスを使って通信されるのか。
各マシンがARPテーブルを持っているらしい。どんな機械が持っているのだろうか？

### 使われる場面
>イーサネットのハードネット同士は、`MACアドレスにより通信相手を指定`しますが、`TCP/IPの通信では相手の指定にIPアドレス`を使います。つまり、この両者を対応づける仕組みが必要です。`IPパケットを相手に届けるため、コンピューターはIPアドレスの中のネットワークアドレスを見て、その転送先を決定`します。このとき、転送先のネットワークアドレスが自分のものと同じであれば、その相手は自分と同じネットワークにあり、物理的にイーサネットなどで繋がっていると判断できます。こう判断できたら、コンピューターは続いてIPアドレスからMACアドレスを導き出す動作を実行します。また、相手の別のネットワークにある場合は、その`IPパケットを次のルーターに引き渡さなければなりません`。この時は、ルーターのIPアドレスからMACアドレスを得る必要があります。これらの動作にARPと呼ばれるプロトコルが使われます。ARPによりIPアドレスからMACアドレスを得た後は、コンピューターはそのMACアドレスを宛先に指定したイーサネットフレームを使って、IPパケットを相手コンピューターに送り届けます。

イーサネットフレーム内のIPアドレスを見て同じネットワークかどうかを判断。
ARPによりipアドレスに紐づいているmacアドレスを照し、目的のコンピューターへ送る

同じネットワーク内なら直接MACアドレスを使って通信すればいいかなと思うが、その場合相手のMACアドレスを知っておく必要がある。

まずは全体からどのLANなのかを調べる必要があるのかな。

### 動作概要
>ARPにはブロードキャストが使われています。IPアドレスをMACアドレスに変換したいコンピューターは、`ネットワークに対して「IPアドレス　***.***.***.***を使っているコンピューターはありませんか？」との問い合わせをブロードキャスト`します。これを`ARPリクエスト`といいます。ブロードキャストなので、ARPリクエストは`物理的に繋がっている全コンピューターに届きます`。各コンピューターはそれを自分のIPアドレスと比較して異なっていれば無視します。一方、同じIPアドレスを使っている`コンピューターは、自分が使っている旨を返答`します。これを`ARPリプライ`と言います。ARPリプライは、`ARPリクエストを発したコンピューターに向けて直接返送`します。この時、送信元アドレスに自分のMACアドレスが入るため、相手は応答したコンピューターのMACアドレスを知ることができます。

https://www.sbcr.jp/product/4797386677/

ARPリクエストを送るたびにLAN上でブロードキャストをするのか。
ARPを記憶するテーブルはどのように記憶されるのだろうか？

わざわざ対応表で調べなくても送り元のMACテーブルは記憶されていないのか？
IPアドレスを一つ噛ませなくてもよさそうだけどな。

# 感想
とりあえずIPパケットを送信するためにARPを使うのか。
まだまだ知らないことがたくさんある。

↓は編集前書いていたものです。

# ARP（Addless Resolution Protcol)
```IPアドレスとMACアドレスの関連付け```を行う。

### MACアドレスとは?
p44 ```コンピュータのNIC(Network Interface Card)に焼き付けられている物理的なアドレス```。

# ARPの処理の流れ
同じネットワークにいるコンピュータのものだったら、そのIPアドレスをARPに問い合わせ(ARPリクエスト)
、その応答結果（ARPリプライ）を```ARPテーブル```と呼ばれるメモリ上のテーブルに登録し、その情報をもとにフレームを作ります。

また異なるネットワークに求めるIPアドレスだった場合は、```デフォルトゲートウェイ```のMACアドレスをARPで問い合わせてフレームを作成する。

### 出典
https://www.sbcr.jp/product/4797386660/

# ARPの動作概要
ARPには```ブロードキャスト```が使われています。
IPアドレスをMACアドレスに変換したいコンピュータは、ネットワークに対して任意のIPアドレスがあるか問い合わせ行う。
その際に```ブロードキャスト```を行う。これを```ARPリクエスト```という。

その中からそのIPアドレスを持つコンピュータから返答が返ってくる。これを```ARPリプライ```という。
ARPリプライは、```ARPリクエストを発したコンピュータに直接返送```する。

### 出典
https://www.sbcr.jp/product/4797386677/

# ブロードキャストとは
同一ネットワーク内の全てのホストに対して、```一斉に同じデータを送信すること```

### 出典
https://gihyo.jp/book/2020/978-4-297-11781-8
先輩SEの小言～居酒屋のトイレ風～

異業種からSEに転職活動中、スクールの講師や、知り合いのSEに教えてもらったことをなんだか大切と思ってまとめてみました。勉強に疲れたのでちょっと小休止に（おい）
あるあるですか？


# 一流エンジニアこそGoogle先生と親友
常に新しいことを取り入れていくことが大事。知らないことよりも、分からないことがあったときに調べられないことの方が問題。磨け検索力。

# 聞くなら最初に聞け
調べてもわからなかったことは早めに聞く。分かったふりして
仕事されても困る。

# 「その子、殺しておいて」にビビるな
そのコード、動かないようにしておいて

# 「死んでる」のはお前じゃない。コード。
それ動いていないよ

# コピペは偉大。むしろやれ。
ミスをするのは人間。タイピングはミスのもと。ミスしない方がかっこいいぞ

# でもブラインドタッチも必要だからな
GUIだけで仕事はできない。議事録も意外と多いんだよ（横文字多いし）

# 何十年後もお前のコードは見られている
誰かが書いたコードに手を加えることはたくさんある。読みやすいコードを。誰に見られても恥ずかしくないコードを。

# 技術力より適応力
結局はチームで動く。人柄は大事。

# 現場に勝る勉強はない
実際の現場に出ると死ぬ気で調べる。言葉で説明する方が野暮なこともある。
TypeScript + Mapbox-GL-JS① 環境構築 ~ 地図の表示

シリーズ化しました (更新:2023/2/9)
[① 環境構築 ~ 地図の表示](https://qiita.com/onk/items/864bf80d66afda9fb57e)
[② 地図のスタイルの変更](https://qiita.com/onk/items/362876cbce29dc2fdaf0)
[③ 円のプロット・ラベルの表示](https://qiita.com/onk/items/ba0cb9e79fd481ea0576)
[④ 軌跡の可視化 - 基本編](https://qiita.com/onk/items/7c528bf4d7791049666b)
[⑤ 軌跡の可視化 - アニメーション編](https://qiita.com/onk/items/e37232f52ea4d2244856)
[⑥ 軌跡の可視化 - Space Time Cube編](https://qiita.com/onk/items/77687712aec730e40046)

# 概要
TypeScriptとmapbox-gl-jsを使って地図を表示する方法のメモです。

## デモ
![01a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2902914/64fc7dae-24e8-4aa3-a69f-1ffc54cf4973.png)


## 開発環境
- macOS Monterey 12.0
- vscode v1.72.0
- npm v8.15.0
- typescript v4.1.3

# 事前準備
## mapboxアカウントの作成
https://account.mapbox.com/auth/signup/

## アクセストークンの取得
https://account.mapbox.com/access-tokens/

# 開発
## mapbox gl js のインストール
```
npm i -D mapbox-gl @types/mapbox-gl
```

## コード
### main.ts
```ts
import mapboxgl from 'mapbox-gl';

mapboxgl.accessToken = /* your token */;

window.addEventListener('load', () => {
    const map: mapboxgl.Map = new mapboxgl.Map({
        container: 'map',
        style: 'mapbox://styles/mapbox/streets-v11',
        center: [139.7670516, 39],
        zoom: 5
    });
});

```

### index.html
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="style.css">
    <script src="main.js"></script>
    <title>Document</title>
</head>
<body>
    <div id="map"></div>
</body>
</html>
```

### style.css
```css
body {
    margin: 0;
    padding: 0;
}
#map {
    position: fixed;
    width: 100%;
    height: 100vh;
    overflow: hidden;
}

.mapboxgl-control-container {
    display: none;
}
```

# 参考
- [Mapboxで地図を表示してみた](https://qiita.com/Haruka-Ogawa/items/7ddbf42e4a7b71a9158c)
- [Vue3 + TypeScript で Mapbox GL JS を使って マップ を表示する サンプル](https://www.harubears.com/ja/tech-ja/vue-js-ja/vue3-typescript-mapbox-gl-gs-generate-map/)
- [npm : @types/mapbox-gl](https://www.npmjs.com/package/@types/mapbox-gl)