OmniAICreator/Qiita-1.07M huggingface dataset:
VisualStudio2019 + OpenCV4.1.1 + CUDA10.1 + VideoCodecSDK10.0 の環境構築

# VisualStudio2019 + OpenCV4.1.1 + CUDA10.1 + VideoCodecSDK10.0 の環境構築

## 環境構築

### 参考

- <https://qiita.com/Susumu0417/items/c0823f6649d2dddc1679>
- <https://nln.jp/wp/archives/5974>
- <https://takap-tech.com/entry/2021/06/03/215015>

### ダウンロード・インストール

- OpenCV 4.1.1
  - <https://opencv.org/releases/page/3/>
      - Windows
          - opencv-4.1.1-vc14_vc15.exe
- opencv_contrib 4.1.1
  - <https://github.com/opencv/opencv_contrib>
      - Tag
          - 4.1.1
              - Code
                  - Download ZIP
                      - opencv_contrib-4.1.1.zip
- CUDA Toolkit 10.1 Update 2 Download
  - <https://developer.nvidia.com/cuda-toolkit-archive>
      - <https://developer.nvidia.com/cuda-10.1-download-archive-update2>
          - Windows
          - x86_64
          - 10
          - exe[local]
              - cuda_10.1.243_426.00_win10.exe
- NVIDIA VIDEO CODEC SDK 10.0
  - <https://developer.nvidia.com/video-codec-sdk-archive>
      - <https://developer.nvidia.com/designworks/video_codec_sdk/downloads/v10>
          - Video_Codec_SDK_10.0.26.zip
              - C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v10.1 にコピーする
                  - Video_Codec_SDK_10.0.26/Interface/ to include
                  - Video_Codec_SDK_10.0.26/Lib/ to lib
- CMake Latest Release (3.22.1)
  - <https://cmake.org/download/>
      - cmake-3.22.1-windows-x86_64.msi
          - Add CMake to the system PATH for all users
          - 環境変数
              - PATH
              - C:/Program Files/CMake/bin
- Visual Studio Community 2019

### OpenCV モジュール生成

- CMakeでOpenCVをビルドするソリューションファイルを生成する
  - cmake-gui 起動
      1. ソースコード
          - E:/Program/OpenCV/opencv/sources
      1. ビルドバイナリ
          - E:/Program/OpenCV/build
      1. Configure
          - Visual Studio 16 2019
          - x64
          - Use default native compilers
          - Finish
      1. Check
          - BUILD_EXAMPLES : ON
          - BUILD_PERF_TESTS : OFF
          - BUILD_TESTS : OFF
          - INSTALL_CREATE_DISTRIB : ON
          - OPENCV_ENABLE_NONFREE : ON
          - OPENCV_EXTRA_MODULES_PATH : E:/Program/OpenCV/opencv_contrib-4.1.1/modules
          - WITH_CUDA : ON
          - WITH_OPENGL : ON
      1. Configure
      1. Check
          - WITH_NVCUVID : ON
      1. Configure
      1. Check
          - CUDA_ARCH_BIN : 6.1
              - <https://developer.nvidia.com/cuda-gpus>
                  - Geforce GTX 1070 Ti
          - CUDA_ARCH_PTX : 6.1
          - CUDA_TOOLKIT_ROOT_DIR : C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v10.1
      1. Configure
      1. Generate
- OpenCVをビルドする
    - E:/Program/OpenCV/build/OpenCV.sln
        - ビルドエラー
            - E:\Program\OpenCV\opencv_contrib-4.1.1\modules\cudacodec\src\precomp.hpp
                - #include "../src/cap_ffmpeg_api.hpp"
                    - 4.2.0以降なくなっている

### TODO

- OpenCV4.4.0で再構築
Go/gRPCコード生成の変更について


結構時間が経っているのですが、Go/gRPCでのサーバー開発において、2020年にコード生成の方法が変更されました。
最近gRPCを利用し始めた方は特に気にされる必要はありませんが、以前からGoでgRPCサーバーを構築していて
生成プラグインを入れ替えてないけどそろそろ更新しとくかーといった際に役立ちそうな情報として記事にしておきます。

## 以前の生成方法
GoでgRPCサーバーのコード生成をする際、
元はprotocプラグインとして[golang/protobuf](https://github.com/golang/protobuf)を使用していました。

この際にはこのようなコマンドでコード生成を行なっていました。

```bash
$ protoc -I . \
    --go_out=plugins=grpc:.
    --go_opt=paths=source_relative \
    ./helloworld.proto 
```

このコードから生成される`<Service>.pb.go`に必要な全てのコードが入っていました。

## protocプラグインの変更

2020年3月より、まず
[protocolbuffers/protobuf-go](https://github.com/protocolbuffers/protobuf-go)のv1.20.0のリリースとしてGoのシリアライズコード生成プラグイン(`protoc-gen-go`)が独立しました。

更に2020年10月に[grpc/grpc-go](https://github.com/grpc/grpc-go/tree/master/cmd/protoc-gen-go-grpc)の`cmd/protoc-gen-go` v1.0.0でサーバースタブ生成プラグイン(`protoc-gen-go-grpc`)が独立しました。

そのため現在、.protファイルからgRPCサーバースタブを生成する際には下記のようなコマンドを打つことになります。

```bash
$ protoc -I . \
    --go_out . \
    --go_opt paths=source_relative \
    --go-grpc_out . \
    --go-grpc_opt paths=source_relative \
    ./helloworld.proto
```

以前1ファイルにまとめられていたコードも`<Service>.pb.go`と`<Service>_grpc.pb.go`に分かれて生成されます。

## 下位互換性の無い変更

また、これに伴い以前のprotoc-gen-goで生成したスタブとの間に下位互換性を崩す変更が入っています。

gRPCスタブを生成するとサービス実装用の`<Service>Server`インターフェイスが生成され、
またそのインターフェイスの前方互換性の為の`Unimplemented<Service>Server`構造体が生成されます。  

```go
type GreeterServer interface {
	SayHello(context.Context, *HelloRequest) (*HelloReply, error)
}

type UnimplementedGreeterServer struct {
}

func (UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) {
	return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented")
}
```

これは`<Service>Server`インターフェイスの実装構造体に`Unimplemented<Service>Server`をembedすることで
実際にインターフェイスのメソッドを満たさなくても実装可能とする為の仕組みですが、全てのメソッドの実装後にembedを外してしまうと、サービスを追加した際などにエラーとなってしまいます。

こうした事例が多かったからなのか、
`protoc-gen-go-grpc`では`mustEmbedUnimplemented<Service>Server`のようなプライベートメソッドがインターフェイスに追加されており、
これにより`Unimplemented<Service>Server`のembedが強制されるようになりました。  

```go
type GreeterServer interface {
	SayHello(context.Context, *HelloRequest) (*HelloReply, error)
	mustEmbedUnimplementedGreeterServer()
}

func (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {}
```

[実際のコード](https://github.com/grpc/grpc-go/blob/master/examples/helloworld/helloworld/helloworld_grpc.pb.go#L52)

このため、`Unimplemented<Service>Server`を外すような実装をしている場合、`protoc-gen-go-grpc`でのコード生成に切り替えた途端にインターフェイス実装が崩れてしまうことになります。

この問題を回避する方法も用意されており、[protoc-gen-go-grpcのReadme](https://github.com/grpc/grpc-go/tree/master/cmd/protoc-gen-go-grpc)に記載されています。
`protoc-gen-go-grpc`のオプションとして`require_unimplemented_servers=false`を指定することで
`mustEmbedUnimplemented<Service>Server`を生成しない下位互換性を維持したコード生成が可能になっています。

```bash
$ protoc -I . \
    --go_out . \
    --go_opt paths=source_relative \
    --go-grpc_out . \
    --go-grpc_opt paths=source_relative \
    --go-grpc_opt require_unimplemented_servers=false \
    ./helloworld.proto
```
【画像処理】NumpyでMedianフィルター

NumpyでMedianフィルターを実装してみます。
Medianフィルターはある画素について、その画素と近傍画素の中央値を出力するフィルターです。ノイズ除去などに利用されます。

まず、使用する画像を読み込み、グレースケール画像に変換しておきます。

```python
original_image = plt.imread(image_name)
if np.issubdtype(original_image.dtype, np.integer):
  original_image = original_image / np.iinfo(original_image.dtype).max
gray_image = 0.2116 * original_image[:,:,0] + 0.7152 * original_image[:,:,1] + 0.0722 * original_image[:,:,2]
plt.imshow(gray_image, cmap='gray')
```

![GrayImage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/f568a6a2-1308-a3d3-b537-234c8368ccda.png)

ノイズを付与します。

```python
from numpy import random

noise_image = gray_image.copy()
noise_image[random.choice([True, False], size=noise_image.shape, p=[0.05, 0.95])] = 1.0
plt.imshow(noise_image, cmap='gray')
```

![NoiseImage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/e03a56b1-7fc2-b364-49d4-60e92780ef8e.png)

ノイズを付与した画像にMedianフィルターを適用します。

```python
def median_filter(image, size=(3, 3), boundary='edge'):
  pad_image = np.pad(image, ((int(size[0] / 2),), (int(size[1] / 2),)), boundary)
  shape = (image.shape[0] - size[0] + 1, image.shape[1] - size[1] + 1) + size
  strides = image.strides * 2
  strided_image = np.lib.stride_tricks.as_strided(image, shape, strides).reshape(shape[0], shape[1], size[0] * size[1])
  return np.apply_along_axis(lambda a: np.median(a), 2, strided_image)

median_image = median_filter(noise_image)
plt.imshow(median_image, cmap='gray')
```

![MedianImage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/14b145ac-cfb4-ffab-086b-f657d159abd1.png)

---

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

https://colab.research.google.com/drive/1vRJSCWqOCaFC6Udc2ws98AU9mlJcQWhM?usp=sharing
Heroku（PostgreSQL）のDBリセット方法

# はじめに
プログラミング初学者の[@kat_log](https://twitter.com/kat__log "Twitter")と申します。

Heroku（PostgreSQL）で間違えたレコードを登録した時など、DBを一旦リセットする方法の共有です。
（学習中のため、自分へのメモ的な意味もあります💦）

# 結論
下記コマンドの実行で可能です。

```
heroku pg:reset DATABASE
```

その後、

```
heroku run rails db:migrate
```

にて再びマイグレートできます。

# おわりに
お読みいただきありがとうございました。
自分と同じく初学者の参考になれば嬉しいです。
一緒に頑張っていきましょう〜😄
JavaScript  while文とfor文について(初学者向け)


|　No　|     目次     |
|:--|--------------|
|　1　|はじめに        |
|　2　|for文とwhile文           |
|　3　|for文を使ってループ処理を行う場合|
|　4　|while文を使ってループ処理を行う場合|
|　5　|お約束|
|　6　|おわり　　　　　　　　　　　|

##はじめに
同じような処理を毎回書いていると、はっきり言って効率が悪いです。
そんな時に繰り返し処理をしてくれるのがfor文とwhile文です。
とても便利ですが、少し怖い部分もありますので、
**繰り返し処理を行う際に絶対に意識するお約束**についても解説していきます。

##for文とwhile文

0から10までの数字が表示されるプログラムをfor文を使った場合とwhile文を作った場合の2種類のケースを紹介します。

どちらを使ってもこちらのように表示できます↓


---------------------------------------
![スクリーンショット 2021-12-30 18.32.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1784356/fbc488c3-038e-87d0-74e5-cbeee3e51e7c.png)
---------------------------------------

##for文を使ってループ処理を行う場合



HTMLはこのようになっています↓


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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>for</title>
</head>

<body>
    <script src="for.js"></script>
</body>

</html>
```
JavaScriptはこのようになっています↓

```qiita:JavaScript
for (let i = 0; i < 11; i++) {
    document.write(i + '<br>');
}
```

仕組みを見てみましょう↓

```qiita:仕組み
// ------------------------------------
// for(初期化; 繰り返し; 更新処理){
//    繰り返したい処理
// }
// ------------------------------------
```

それでは、**解説**をしていきます。

for (初期化; 条件; 更新処理;) と記載します。

初期化は、ループをカウントする変数を基本的に定義します。

ここで定義した変数はその for 文内でしか使えません。

条件は、どこまでループするのかを定義します。

この条件が満たされればループは終了します。

又、満たされなければ無限にループを続けます。

変化は、1回ループが完了する毎に実行されます。

現在は、10より大きい値が出力されていませんので正しくwhile文の条件式を処理し終了したことがわかります。

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


##while文を使ってループ処理を行う場合

HTMLはこのようになっています↓


```qiita:HTML

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>while</title>
</head>

<body>
    <script src="while.js"></script>
</body>

</html>
```
JavaScriptはこのようになっています↓

```qiita:JavaScript
let i = 0;
while (i < 11) {
    document.write(i + '<br>')
    i++;
}
```

仕組みを見てみましょう↓

```qiita:仕組み
while (条件式) {
  実行する処理;
}
```
それでは解説していきます。

whileのカッコ内にある条件式が正（true)の間はwhile内の処理を繰り返し実行します。
条件式が誤り(false)になった場合にはwhile文を抜けて次の処理に移ります。
又、for文と同じで10より大きい値が出力されていませんので、
正しくwhile文の条件式を処理し終了したことがわかります。

##お約束


**⚠️ i++のように数値を増やす処理を絶対に書き忘れないようにしてください**

「i++」という後値インクリメントを使い、変数の値を一ずつ増やします。
書き忘れると無限にループが起こり、パソコンに負担がかかり、
最悪の場合パソコンがクラッシュします。
**必ずtrueがfalseになる(更新処理が終わる)ようにしましょう。**
それでも無限ループが起きた際にはブラウザを**強制終了**しましょう！

##おわり

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

また他の記事でお会いしましょう〜👋
blackで始める妥協のないPythonコードフォーマッティング

タイトルで言いたいことは終わりました。Pythonのコードフォーマッターであるblackの紹介です。

https://github.com/psf/black

Any code style you like, as long as it's **black**. コードのスタイリングは十人十色になりがちです。コードフォーマッターを導入してみたものの、ちょっと自分が使いやすいようにカスタマイズするとか。このblackは妥協のないただ一つのコードフォーマットスタイルを手に入れようというフォーマッターです。PEP8にのっとり、カスタマイズできない（独自ルールが作成できない）フォーマット機能を提供するようで、さまざまなプロジェクトで使用されている様子です。潔い。悩みたくないからこれで良い感があります。

> The following notable open-source projects trust Black with enforcing a consistent code style: pytest, tox, Pyramid, Django Channels, Hypothesis, attrs, SQLAlchemy, Poetry, PyPA applications (Warehouse, Bandersnatch, Pipenv, virtualenv), pandas, Pillow, Twisted, LocalStack, every Datadog Agent Integration, Home Assistant, Zulip, Kedro, and many more.
The following organizations use Black: Facebook, Dropbox, KeepTruckin, Mozilla, Quora, Duolingo, QuantumBlack, Tesla.

https://github.com/psf/black#note-this-is-a-beta-product より。

## Visual Studio Codeで利用する

まずはpipでインストールする。

```console
> pip install black
```

コマンドラインで実行するとこんな感じ。

```console
> black main.py
All done! ✨ 🍰 ✨
1 file left unchanged.
```

毎度コマンドをたたくのも面倒なので、Visual Studio Code でファイル保存時に、自動的にフォーマットが行われるようにします。ユーザー設定から。

`python.formatting.provider` を `black` に設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34410/30e5f2fa-8d01-cd6c-9f76-a312d46bbd52.png)

`editor.formatOnSave` をチェックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34410/d508c367-7c7e-9bac-e119-4a816f9a3018.png)

これでOK！コードフォーマット自体の設定が無いので、ここから自分に合うようなカスタマイズをする必要はもちろんありません。潔くて良い！（２回目）
Laravel ってなに？

## 勉強前イメージ

聞いたことはある
プログラム的なやつ？

## 調査

### Laravel とは？

ララベル と読み、PHPのフレームワークになります。
フレームワークというのは、
システム開発をする際に必要となる機能などがまとまったものになります。
PHPのフレームワークは他にもCakePHP等があります。

### Larabel の特徴

- MVCモデルの採用

model,view,controllerに分けられて、
それに伴い開発を進めます。
MVCモデルの使用で、どこに何を書くかが明確になり開発が進めやすくなります。

- Composerでパッケージ管理

Composerというパッケージやライブラリを管理するツールで
LaravelはComposerで管理されます。
Composerを使うことで依存性の解決や必要なライブラリがあればインストールされます。

- データベースの操作が安易

Eloquent ORMとMifrationというのが備わっているので
データの扱いを柔軟にし、データベースの管理を安易になっています。

- 機能やプラグインの開発が盛ん

比較的新しく人気があるため、
新機能のバージョンアップやプラグインの開発も盛んです。

- 処理速度は速くない

多機能が故に処理速度が比較的ゆっくりな傾向があります。

- コードが複雑化しやすい

自由度の高さはありますが、自由が故にコードが複雑化しやすいデメリットがあります。
最初の設計に注意する必要があります。


## 勉強後イメージ

聞いたことあったけど、PHPのライブラリなんだ・・・
CakePHPの横並びのようなやつ。

## 参考

- [Laravelとは何？Laravelの11個の特徴と使う際の注意点を紹介](https://www.acrovision.jp/career/?p=2776)
- [PHPフレームワーク11選紹介！使用するメリットデメリットなど多数解説](https://www.fenet.jp/dotnet/column/%E8%A8%80%E8%AA%9E%E3%83%BB%E7%92%B0%E5%A2%83/php/7812/)
[Go] slack-go/slackによるメッセージ一括削除

普段からGoogle CalendarとSlackを連携して使っていて、新規予定作成時にSlack通知がくるように設定しています。ところが、この通知が溜まってくると全体のメッセージ数を圧迫してきます。

そこでSlackAPIを用いて、指定したチャンネル・タイトルの投稿を一括削除することにしました。折角なので、楽にPythonではなく、勉強がてらGoを用いて実行してみることに。Slack APIの仕様変更もあり、あまり情報がなかったので、まとめてみました。

# 0.環境
- Go: 1.16.3
- slack-go/slack: 0.10.1

# 1.APIトークンの取得
以前使われていたトークンは「レガシートークン」と呼ばれているようです。新しいトークンはアプリを作成した上で、必要な権限を設定する必要があります。[^1]

[^1]: 参考: https://risaki-masa.com/how-to-get-api-token-in-slack/

今回は、このように設定しました。
<img width="400" alt="権限設定" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214822/e41a7c19-121b-3b4c-ea91-693942211470.png">

# 2.slack-go/slackのインポート
タイトルにもあるように[slack-go/slack](https://github.com/slack-go/slack)を使用しました。GoでのslackAPI操作を効率的に行うことができます。

今回は、下記パッケージをインポートしました。そして、案の定パッケージインポートでつまづきました。

```Go
import (
	"flag"
	"fmt"
	"strings"
	"time"

	"github.com/slack-go/slack"
)
```

下記、サイトにて問題点を解決できました。問題点はモジュールモードとGOPATHモードでの扱い方を区別せずに取り組んでしまってことのようでした。

[Golangのパッケージ完全に理解した - くろのて](https://note.crohaco.net/2019/golang-package/)

# 2.クライアントの生成
slack-go/slackでは、Client構造体をトークンを用いて生成し、そこから操作を始めます。

今回は実行引数でトークンを渡すようにしました。

```Go
// Get access token from args
flag.Parse()
tkn := flag.Arg(0)
api := slack.New(tkn)

```

# 3.ChannelIDの取得

まずは、削除したい投稿があるChannelIDをチャンネル名称から見つけ出します。引数として独自の構造体を渡しますが、この渡し方がスマートな方法なのかどうかは分かりません。

```Go
func check(e error) {
	if e != nil {
		panic(e)
	}
}

func get_calendar_channel(api *slack.Client) string {
	var result string
	calender_name := "calendar" // Target name of channel

	prm := slack.GetConversationsParameters{}
	channels, _, err := api.GetConversations(&prm)
	check(err)

	// Find channel
	for _, c := range channels {
		if strings.Contains(c.Name, calender_name) {
			result = c.ID
		}
	}
	return result
}

```

# 4.メッセージの特定と削除
最後に、該当のChannelIDに対して該当するメッセージを特定し、DeleteAPIを呼びます。APIの呼び出し上限を超えてしまわないように1秒間のSleepを入れています。

```Go
chn_id := get_calendar_channel(api) // Get target channel id

// Get message list
prm := slack.GetConversationHistoryParameters{ChannelID: chn_id, Limit: 1000}
res, err := api.GetConversationHistory(&prm)
check(err)

delete_title := "hogehoge" // Target title name to delete
var cnt int

for _, m := range res.Messages {
	for _, att := range m.Attachments {
		if att.Title == delete_title {
			_, _, err := api.DeleteMessage(chn_id, m.Timestamp)
			check(err)
			time.Sleep(1 * time.Second) // To escape the api limit
			cnt++
		}
	}
}
fmt.Println(cnt, "messages were deleted")
```
処理プロセスとしては以上です。

# 躓いたポイント
-  [slack-go/slackのドキュメント](https://pkg.go.dev/github.com/slack-go/slack@v0.10.1)には、各メソッドの説明がほぼない
    - ver0.10なので仕方ない点ではありますが、今回用いた各メソッドの説明は最低限のみでした
    - それぞれの引数の意味を知るためには、公式SlackAPIドキュメントから、slack-go/slackが呼ぶ先のAPI仕様を確認する必要がりました
- `GetConversationHistoryParameters`メソッドの上限は1000件
    - 1000より大きい数値を実行すると、デフォルトの100件に戻されます


---
以上となります。Goは勝手にシンプルなコードにならざるを得ない点が気持ち良いですね。全体コードは[こちら](https://github.com/daikichidaze/slack-operation/blob/main/main.go)に公開しています。
[メモ] AWXで VMware動的インベントリを使用する

AWXでVMwareの動的インベントリを使用した時のメモ

#### 認証情報を設定する

1. AWXで``リソース``から``認証情報``を選択
1. ``追加``ボタンをクリックして、``認証情報タイプ``を``VMware vCenter``にしてホスト情報、ユーザー名、パスワードなど情報を記入して他も適当に記入、保存する

#### 認証情報を設定する

2. 適当なインベントリにソースを追加して先ほど追加した認証情報を選択、ソース変数でインベントリの構成を設定する。

※ 下記の例では
仮想マシン名をホスト名として設定
タグとOS種別ごとにグループ化
パワーオンになっているマシンのみを対象にする
各ホストにansible変数を設定する

```yaml:
hostnames:
 - 'config.name'
with_tags: True
keyed_groups:
 - key: tags
   separator: ''
 - key: config.guestId
   separator: ''
with_nested_properties: True
filters:
 - summary.runtime.powerState == "poweredOn"
compose:
 ansible_host: 'guest.ipAddress'
 composed_var: 'config.name'
 ansible_user: "'ansible'"
 ansible_connection: "'ssh'"
 ansible_become: yes
```
GPG Agent Forwarding

## 概要
GPG Agent の Forwarding をした時の手順ログ。ほぼ自分用メモ。

## 1. local machine 側の作業
```~/.gnupg/gpg-agent.conf
# 追記
# なくても大丈夫そうだが念のため
extra-socket $HOME/.gnupg/S.gpg-agent.extra
```

```sh
$ gpgconf --reload gpg-agent
$ gpgconf --list-dir agent-extra-socket
/Users/kino-ma/.gnupg/S.gpg-agent.extra  # ローカル側のソケット
```

## 2. remote machine 側の作業

```sh
gpg --export <KEY_ID> | ssh remote gpg --import - 
```

```sh
$ gpg --edit-key <KEY_ID>

gpg> trust

Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)

  1 = I don't know or won't say
  2 = I do NOT trust
  3 = I trust marginally
  4 = I trust fully
  5 = I trust ultimately
  m = back to the main menu

Your decision? 5

gpg> save
Key not changed so no update needed.
$ gpg -k
```

権限があれば、以下を追記する。

```ssh
# /etc/ssh/sshd_config
StreamLocalBindUnlink yes
```

```sh
$ gpgconf --list-dir agent-socket
/run/user/1001/gnupg/S.gpg-agent # リモート側のソケット
```

## 3. local machine
`~/.ssh/config`

```ssh
Host remote
    HostName remote.example.com
    RemoteForward <REMOTE_SOCKET> <LOCAL_SOCKET>
    ExitOnForwardFailure Yes
```

```sh
local$ ssh remote
remote$ gpg -K
remote$ gpg --sign -a <<< "hello"
```

## うまくいかないとき
```
systemctl --user mask gpg-agent.service gpg-agent.socket gpg-agent-ssh.socket gpg-agent-extra.socket gpg-agent-browser.socket
```

や

```
rm -rf <REMOTE_SOKCET>
```

## 参考
- https://mlohr.com/gpg-agent-forwarding/
- https://superuser.com/a/884602
- https://wiki.gnupg.org/AgentForwarding
カメラ映像をマインクラフト内でリアルタイム描画

#はじめに
　前回マイクラ内に任意の画像をピクセルアート化するプログラムを作成しました。
　そこで今回は描画する対象をカメラ映像に置き換えて、カメラ映像をリアルタイムでマイクラ内に再現しようと思います。

https://qiita.com/konishi0125/items/5d3e73bed86a2f2db6dd

#開発環境
Windows 11
Mincraft JE 1.12.2
Forge 1.12.2
Raspberry Jam Mod 0.92
Python 3.9.9

#カメラ映像の取り込み
　自分のPCにはカメラが付いていないため、Android端末をつないでその映像を取り込みます。
Androidカメラ映像の取り込みはDroidCamAppを使いました。

https://play.google.com/store/apps/details?id=com.dev47apps.droidcam&hl=ja&gl=US

#マイクラへの映像受け渡し
　映像の取り込みはOpenCVのVideoCaptureを使います。取り込んだ映像の1フレームは1枚の画像となるため、それをマイクラのピクセルアート化プログラムに渡し、マイクラ内で描画します。

```Python:
import cv2

#カメラの起動
camera = cv2.VideoCapture(1)

while True:
    ret, frame = camera.read()  # フレームを取得
    frame = Image.fromarray(frame) #pillowで操作できるように変換

    #各ピクセルに対応したマイクラ内ブロックに変換
    im = pic2map.resize_picture(frame, map_size, brightness)
    im_color = pic2map.to_color(im, color_convertor)
    im = np.array(pic2map.patting(im_color))

    #ブロックの配置
    for i in range(map_size):
        for j in range(map_size):
            #余白は白のウール
            if im[i,j] == 255:
                mc.setBlock(corner[0] + j, corner[1], corner[2] + i, block.WOOL.id, 0)
            #ウールなどブロックidと種類idを持つブロックの設置
            elif im[i, j] > 1000:
                id1, id2 = divmod(im[i, j], 100)
                mc.setBlock(corner[0] + j, corner[1], corner[2] + i, int(id1), int(id2))
            #その他ブロックの設置
            else:
                mc.setBlock(corner[0] + j, corner[1], corner[2] + i, int(im[i, j]))
    #qの入力で終了
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 撮影用オブジェクトとウィンドウの解放
camera.release()
cv2.destroyAllWindows()
```

#結果
　以下のようにカメラので取り込んだ映像をマイクラ内でピクセルアート化することができました。
<img width="400" alt="スクリーンショット 2021-12-30 170136.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552590/12c49696-ae3c-ed0c-d153-e470d0a49d8b.png">
<img width="400" alt="スクリーンショット 2021-12-30 170207.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552590/9b41f0fb-7e78-c756-3a82-18f9421946c9.png">
<img width="400" alt="スクリーンショット 2021-12-30 170336.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552590/526ba690-e86c-c226-5b0d-f3a71bd0179f.png">
<img width="400" alt="スクリーンショット 2021-12-30 170301.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552590/00a2c61d-c089-369e-4a55-a03a15cbc43f.png">

#終わりに
　カメラ映像をリアルタイムでマイクラ内に描画するプログラムを作成しました。以前に作った任意の画像をマイクラ内にピクセルアート化するプログラムを流用できたため、その画像をカメラで取り込んだに置き換えるだけで完成しました。これにより短時間でできました。機能を小分けにして汎用性を高める便利さを感じました。
Pythonでランダム文字列を数値化する

# 背景・目的
- とある作業で、文字列を数値化する必要があったので作業ログとして残します。
- IDのように英字が含まれる文字列に対して、分散化したいため、一度数値に変換してして余りを求めたいと考えました。

# 結論
- 一度バイト配列に変換してから、int型に直す。

# 内容
## 文字列をバイト配列に変換

- コード

```
string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890@`:*/?"
print("byte[] {0}".format(string.encode('utf-8')))
```

- 結果

```
byte[] b'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890@`:*/?'
```

## バイト配列から数値に変換
- コード
    - int.from_bytesを利用する。
    - パラメータには、バイト配列と、byteorderを渡す。
        - byteorderの説明は以下の通り。

> byteorder 引数は、整数を表すのに使われるバイトオーダーを決定します。 byteorder が "big" なら、最上位のバイトがバイト配列の最初に来ます。 byteorder が "little" なら、最上位のバイトがバイト配列の最後に来ます。ホストシステムにネイティブのバイトオーダーを要求するには、 sys.byteorder をバイトオーダーの値として使ってください。

- bigとlittleが指定可能らしい。
    - これらはエンディアンの指定で、ビッグエンディアンは、左から大きい値（8桁なら128、64、32・・・1のように）。リトルエンディアンは、左から小さい値（8桁なら、1、2、4・・・128）となるようだ。

```
string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890@`:*/?"
print("numeric {0}".format(int.from_bytes(string.encode('utf-8'), byteorder='big')))
```

- 結果

```
numeric 3758001799418605191197857118323574174346338316370081010955161214851720350686724878846949519162920740126535318039925868075538283434967887497638995678921760193831907135
```

## コード全体
```
import os
import sys

LIST =["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890@`:*/?"]


def generate_string2numberic(string):
    print("byte[] {0}".format(string.encode('utf-8')))
    print("numeric {0}".format(int.from_bytes(string.encode('utf-8'), byteorder='big')))

def main():
    for line in LIST:
        print("string {0}".format(line))
        generate_string2numberic(line)

if __name__ == '__main__':
    main()
```

# 考察
- 他にもっと良い方法があるかもしれないが、現時点で思いつく方法をメモしておきます。


# 参考
https://docs.python.org/ja/3/library/stdtypes.html

https://grapebanana.com/python-encoding-utf-8-7161/

https://qiita.com/mski_iksm/items/bb0aa375c952c2d7b91a
FastAPIでBearerトークンを抽出する

小ネタ。

FastAPIで`Authorization: Bearer {token}`のようにヘッダで送られてくるトークンを使って認証したい場合に、トークン取得処理の自前実装が不要になる。

# コード

`Depends`を使ってDIチックに処理できるので嬉しい

```python:dependencies.py
from fastapi import Request, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials


async def get_bearer_token(
    request: Request,
    authorization: HTTPAuthorizationCredentials = Depends(HTTPBearer())
) -> str:
    token = authorization.credentials
    return token
```

`await bearer(request)`としている部分は、`HTTPBearer`クラスの`__call__`が該当処理。
ソースコード: [fastapi/http.py at master · tiangolo/fastapi](https://github.com/tiangolo/fastapi/blob/3efb4f7edff99fdc12802a85ae9d140ec4772497/fastapi/security/http.py#L113-L133)
Julia: Memcached のデータを削除 (Delete)

```julia:mcached_delete.jl
#! /usr/bin/julia
#
#	mcached_delete.jl
#
#					Dec/30/2021
# --------------------------------------------------------------------
using Memcache
# --------------------------------------------------------------------
println(stderr,"*** 開始 ***")
key_in = ARGS[1]
println(key_in)
#
mc = MemcacheClient("localhost", 11211)
#
delete(mc,key_in)
#
#
println(stderr,"*** 終了 ***")
# --------------------------------------------------------------------
```
Julia: Memcached のデータを更新 (Update)

```julia:mcached_update.jl
#! /usr/bin/julia
#
#	mcached_update.jl
#
#					Dec/30/2021
# --------------------------------------------------------------------
using Memcache
using JSON
# --------------------------------------------------------------------
println(stderr,"*** 開始 ***")
key_in = ARGS[1]
population_in = ARGS[2]
println(key_in,'\t',population_in)
#
mc = MemcacheClient("localhost", 11211)
#
try
	str_json = get(mc,key_in)
	println(str_json)
	unit_aa = JSON.parse(str_json)
	unit_aa["population"] = population_in
	today = Libc.strftime("%F", time())
	unit_aa["date_mod"] = today
	str_json_new = JSON.json(unit_aa)
	println(str_json_new)
	set(mc,key_in,str_json_new)
catch
end
#
println(stderr,"*** 終了 ***")
# --------------------------------------------------------------------
```
Julia: Memcached のデータを読む (Read)

```julia:mcached_read.jl
#! /usr/bin/julia
#
#	mcached_read.jl
#
#					Dec/30/2021
# --------------------------------------------------------------------
using Memcache
using JSON
# --------------------------------------------------------------------
println(stderr,"*** 開始 ***")
#
mc = MemcacheClient("localhost", 11211)
#
set_keys = ["t1731","t1732","t1733","t1734","t1735","t1736","t1737",
	"t1738","t1739"]
#
for kk in set_keys
	try
		str_json = get(mc, kk)
#		println(typeof(str_json))
		if typeof(str_json) == String
			unit_aa = JSON.parse(str_json)
			print(kk, '\t', unit_aa["name"])
			print('\t',unit_aa["population"])
			println('\t',unit_aa["date_mod"])
		end
	catch
#		println("*** error ***")
	end
end
#
println(stderr,"*** 終了 ***")
# --------------------------------------------------------------------
```
Julia: Memcached のデータを作成 (Create)

text_manipulate.jl はこちら
[Julia: text ファイルの crud](https://qiita.com/ekzemplaro/items/5c7f674ee034a33e2553)

```julia:mcached_create.jl
#! /usr/bin/julia
#
#	mcached_create.jl
#
#					Dec/30/2021
# --------------------------------------------------------------------
using Memcache
using JSON

include("text_manipulate.jl")
# --------------------------------------------------------------------
function data_prepare_proc()
    dict_aa = Dict()
#
    dict_aa = dict_append_proc(dict_aa,"t1731","金沢",54961,"2013-6-21")
    dict_aa = dict_append_proc(dict_aa,"t1732","輪島",18395,"2013-2-16")
    dict_aa = dict_append_proc(dict_aa,"t1733","小松",36874,"2013-5-14")
    dict_aa = dict_append_proc(dict_aa,"t1734","七尾",47512,"2013-3-9")
    dict_aa = dict_append_proc(dict_aa,"t1735","珠洲",78691,"2013-9-4")
    dict_aa = dict_append_proc(dict_aa,"t1736","加賀",25387,"2013-1-21")
    dict_aa = dict_append_proc(dict_aa,"t1737","羽咋",81546,"2013-6-23")
    dict_aa = dict_append_proc(dict_aa,"t1738","かほく",45291,"2013-12-26")
    dict_aa = dict_append_proc(dict_aa,"t1739","白山",74839,"2013-11-15")
#

    return  dict_aa
end
# --------------------------------------------------------------------
println(stderr,"*** 開始 ***")
#
dict_aa = data_prepare_proc()
mc = MemcacheClient("localhost", 11211)
#
for key in collect(keys(dict_aa))
	unit_aa = dict_aa[key]
	str_json = JSON.json(unit_aa)
	set(mc,key,str_json)
end
#
println(stderr,"*** 終了 ***")
# --------------------------------------------------------------------
```

作成したデータの確認方法

```text
$ telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
get t1731
VALUE t1731 3 59
{"name":"金沢","population":54961,"date_mod":"2013-6-21"}
END
quit
Connection closed by foreign host.
```
Go(Gorm)+MySQLなDocker環境でdial tcp connection refusedが発生した際の対処法


## エラー内容

`docker-compose up`時に以下のエラーが発生しました。

```terminal
[error] failed to initialize database, got error dial tcp 172.19.0.2:3306: connect: connection refused
```

## 原因
docker-composeで`container_name`を指定していなかったため

## 対処法

### Before

docker-compose.yml

```yml
version: "3.9"
services:
  backend:
    build: .
    ports:
      - 8000:8000
    volumes:
      - .:/app
    depends_on:
      - db

  db:
    image: mysql:5.7.22
    restart: always
    environment:
      MYSQL_DATABASE: ambassador
      MYSQL_USER: root
      MYSQL_PASSWORD: root
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - .dbdata:/var/lib/mysql
    ports:
      - 33066:3306
```

main.go

```go
var DB *gorm.DB

func Connect() {
	var err error

	DB, err = gorm.Open(mysql.Open("root:root@tcp(db:3306)/ambassador"), &gorm.Config{})

	if err != nil {
		panic("Could not connect with database!")
	}
}
```

### After

docker-compose.yml

`container_name: godockerDB`を追加

```yml
version: "3.9"
services:
  backend:
    build: .
    ports:
      - 8000:8000
    volumes:
      - .:/app
    depends_on:
      - db

  db:
    image: mysql:5.7.22
    container_name: godockerDB # 追加
    restart: always
    environment:
      MYSQL_DATABASE: ambassador
      MYSQL_USER: root
      MYSQL_PASSWORD: root
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - .dbdata:/var/lib/mysql
    ports:
      - 33066:3306
```

main.go

`godockerDB`を指定

```go
var DB *gorm.DB

func Connect() {
	var err error

	# container_nameを指定
	DB, err = gorm.Open(mysql.Open("root:root@tcp(godockerDB)/ambassador"), &gorm.Config{})

	if err != nil {
		panic("Could not connect with database!")
	}
}
```

## 参考
https://stackoverflow.com/questions/57566060/panic-dial-tcp-127-0-0-13306-connect-connection-refused?newreg=105ca01eddd149d4b863abf5bf287c5b
【Vue.js】Vuetify3でv-menuを使う

## 概要
Vuetifyでドロップダウンのメニューを実装する場合に、v-menuを使うことがあると思います。Vuetify2だと、[Vuetify.js 2.2のMenu, Tooltipコンポーネントについて](https://qiita.com/rubytomato@github/items/9bd8dc197f9ab406bead)の記事で、紹介されているような実装で実現できるのですが、Vuetify3だとVuetify2と同じ実装では動作しません。ということで、Vuetify3でv-menuをどう実装すれば良いのかというのをメモ書きします。
なお、この記事を書いた2021年12月時点でVuetify3はアルファ版ですので、今後仕様が変わる可能性があることご留意ください。

## 対応方法
[こちら](https://next.vuetifyjs.com/en/components/menus)のドキュメントに、Vuetify3のv-menuの実装が記載されています。Vuetify2との違いは、templateの実装で`<template v-slot:activator="{ props }">`となっていて`v-slot:activator`にpropsが設定されています。そして、このpropsはメニューを開くドロップダウンのボタンで、`<v-btn color="primary" dark v-bind="props">`のようにbindします。

## 実装サンプル
メニューの表示部分を実装サンプルとしてのせます。クリックした時のアクションの実装は、特にVuetify特有のものでは無いので割愛します。


```vue
<template>
  <v-spacer />
  <v-menu>
    <template v-slot:activator="{ props }">
      <v-btn icon v-bind="props" color="blue-lighten-5">
        <v-icon>mdi-dots-vertical</v-icon>
      </v-btn>
    </template>
    <v-list
      style="position: absolute; left: -100px; z-index: 999"
      color="white"
    >
      <v-list-item>
        <v-list-item-title>
          <div @click="transferTop" role="button">トップ</div>
        </v-list-item-title>
      </v-list-item>
      <v-list-item>
        <v-list-item-title>
        　　　<div @click="transferCategory" role="button">
         　　　カテゴリー管理
        　 </div>
      　 </v-list-item-title>
      </v-list-item>
      <v-list-item>
      　　<v-list-item-title>
      　　　　<div @click="logout" role="button">
        　　ログアウト
        </div>
　　　　　　　　　　　　　　</v-list-item-title>
     　　</v-list-item>
    </v-list>
  </v-menu>
</template>
```

メニューは、以下のようなイメージで表示されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32098/b80590c5-0724-fa97-7fc7-b9662d6ac97d.png" width="150px" />
「MySQLでデータベース作成」と「PHPでデータベース記録」。（8日目）

Kotlinのスマホアプリ（クライアント）が、ほぼ完成したので、サーバ側で受信したデータを記録する為、データベースを作成していきます。

サーバは、契約済みのロリポップを使用。

#前回の記事

Kotlinで地図アプリ（ゴミ拾いアプリ）作成。（7日目）

https://qiita.com/fix/items/79afbea4d8c44c5a1f9c

##一週間でやった事


* **GoogleMap APIを使い、地図＋位置情報を表示**
* **移動に合わせて、マップがスクロール**
* **ゴミの種類を「大・中・小」にわけ、ボタンアイコンを作成**
* **ボタンにイメージアイコンを作成**
* **ボタンタップ後、サーバー側へHTTPS（GET）でデータを送信（BASIC認証）**
* **送信前に確認ダイアログを表示**
* **送信後、地図上にアイコンを表示**
* **アイコンタップで、種別/時間を表示**
* **サーバー側でBASICに認証**
* **サーバー側でPHPを使いGETデータ記録テスト**


#ロリポップサーバでデータベースを作成

ログインし、会員ページからデータベースを作成
![イメージ7454.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/503948/19f79710-520a-1ca1-ea67-b93f2f8a2a00.jpeg)

https://user.lolipop.jp/?mode=mysql


#ロリポップサーバへSSHでログイン

既に作成済みなの省略。

詳細は公式サイトの情報は、ネットの情報を参照。

希望があれば、PuTTYを使った公開鍵方式でのログイン方法を紹介しますが、ネット情報を見た方が早いかもです…。

https://lolipop.jp/manual/user/ssh/



#自動ログイン設定

MySQLへのログイン時、毎回、コマンドを打つのが面倒なので、.my.cnfを作成。

##SSHで接続し、ホームディレクトリに「.my.cnf」を作成

```ssh:SSH(ssh.lolipop.jp)
$ touch $HOME/.my.cnf
$ chmod 600 $HOME/.my.cnf
$ vi $HOME/.my.cnf
```

##.my.cnfを編集

```conf:.my.cnf
[client]
host=（ホスト）
database=（データベース名）
user=(ID)
password=(PASS)
```

mysql コマンドを叩いてログインテスト

```ssh:SSH(ssh.lolipop.jp)
$ mysql -u (ID)
```

上手くいけばmysqlへのログイン

![イメージ7453.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/503948/ca4f7933-c73a-b56b-82c5-31995351f441.jpeg)



# テーブル作成

データベースの選択

```ssh:SSH(ssh.lolipop.jp)
$ mysql > use (データベース名);
```

テーブル作成（日時、ゴミの種類、緯度、経度）

```ssh:SSH(ssh.lolipop.jp)
$ mysql >  CREATE TABLE GPS (
  DATE DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  type int(1) DEFAULT 0,
  latitude double DEFAULT 0,
  longitude double DEFAULT 0
);
```

終了

```ssh:SSH(ssh.lolipop.jp)
$ mysql > quit;
```


#サーバ側で、HTTP GETで受信したデータをPHPでデータベースへ保存


```php:index.php
<?php
define('HOSTNAME', '(ホスト)');
define('DATABASE', '(データベース名)');
define('USERNAME', '(ID)');
define('PASSWORD', '(PASS)');
if(isset($_GET['DATA']) && $_GET['DATA'] != ''){
    try {
        $db  = new PDO('mysql:host=' . HOSTNAME . ';dbname=' . DATABASE, USERNAME, PASSWORD);
        $db->query('use '.DATABASE);
        $stmt = $db->query('INSERT INTO GPS VALUES ('.$_GET['DATA'].')');
        $databases = $stmt->fetchAll(PDO::FETCH_COLUMN);    
        echo 'OK';
    }
    catch (PDOException $e) {
        echo 'Connection failed: ' . $e->getMessage();
    }
}
else{
    echo "NG";
}
?>
```


スマホアプリから位置情報を送信し、記録できるのを確認して終了。

※スマホ側では、送信したデータが正常に記録されたかどうかチェックコードも追加
※$_GET['DATA']は、スマホ側でMySQLのデータフォーマットに合わせた形式を作成


#今後の課題

* **WEB上で、GoogleMapを表示(HTML,CSS,JavaScript)**
* **MySQLのデータを読み込み地図上にマーカー表示(JavaScript,php,Node.js)**
* **WEBフレームワークのBootstrap上で、GoogleMap表示**
BPMに合わせてオブジェクトを点滅させる（HDRP/lit編）

#HDRPでオブジェクトを点滅させたい

させたいですよね。

最初はHDRP/litの_EmissiveIntensityをスクリプトから操作して点滅させようとしましたが、値は変わるのにGameViewに反映されませんでした。
あきらめて、_BaseColorで点滅させられるように作りました。
EmissiveColorを前もって明度の高い色（白）にしておけば、
ぴかぴか点滅してくれます。

色はスクリプト上でいじります。
インスペクタ―で設定できるのはBPMだけです。


```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EmissionBlinking : MonoBehaviour
{


    private Material material;
    private float length = 1.0f;

    public int bpm = 120;
    

    void Start()
    {
        material = GetComponent<Renderer>().material;
    }

    void Update()
    {
        float span = bpm / 60;　//1秒に何ビートか？
        float val = Mathf.PingPong(Time.time * span * 2f, length); //BPMの拍に合わせて点灯させるために *2 する

        Color color = new Color(1.0f - val * val, 0f, 0f); //RGBで任意の色にする

        material.SetColor("_BaseColor", color);
    }

}

```



プログラミングなんてできねえ！
と思いながら始めたC#学習も、なんとかかんとか触りだけはこなせました。

よい映像制作につながるように来年もがんばります。
ルーティングについて

#ルーティングとは
あるアドレスにアクセスをした際、どの処理を行うのかを管理しているのがルーティングです。
laravelのroutesのweb.phpにこのルーティングのコードを記載していきます。

```php:web.php
Route::get('/new', 'BookController@new')
```
例えば、このようなルーティングがあったとします。
https://～newというアドレスにアクセスをした場合、BookController内で定義されているnew(@以降の記述)というメソッドの処理が行われます。

つまり『〇〇のアドレスにアクセスをしたらば□□という処理が行われる』という事です。

#####書き方
route::get(アドレス名、コントローラー名＠メソッド名)

Web上で展開されているページはすべてこのweb.phpでルートが記載されております。
フルオンチェーンNFTもどきをSymbolで作成してみる。

SymbolのテストネットでフルオンチェーンNFTを作る方法を解説します。

# この記事で解説しないこと

- トークンの作成方法
    - ウォレットで作成してください

- NFTデータのエンコード方法
    - Base64でエンコードしてください



# テストネット


https://sym-test.opening-line.jp:3001/chain/info

# アカウント準備

```js
alice = sym.Account.generateNewAccount(sym.NetworkType.TEST_NET);

"https://testnet.symbol.tools/?recipient=" + alice.address.plain() +"&amount=10"
```

# データ分割

Base64でエンコードされたNFTデータを分割してmessagesという配列に格納します。

```js
nftdata = "UGGUGUUAUUAAUGGUUU";
let messages = [];
for (let i = 0; i < nftdata.length / 3; i++) {
    messages.push(nftdata.substr(i * 3, 3));
}
console.log(messages);
```

今回はサンプルとして"UGGUGUUAUUAAUGGUUU"という文字列を3文字ずつに分割しています。
直接RawDataを扱いたい場合はこちらの記事を参考にしてください。

https://qiita.com/monakaJP/items/9d7b040ec145dec2e3f8


# トランザクション作成

配列の数だけトランザクションを作成して、アグリゲートトランザクションに集約させます。

```js
createTx = function(publicAccount,message){
  return sym.TransferTransaction.create(
    sym.Deadline.create(epochAdjustment),
    publicAccount.address,
    [],
    sym.PlainMessage.create(message),
    networkType
  );
}

aggregateArray = Array();
for(message of messages){
　　　tx = createTx(alice,message);
  aggregateArray.push(tx.toAggregate(alice.publicAccount));
  
}
console.log(aggregateArray);

aggregateTx = sym.AggregateTransaction.createComplete(
  sym.Deadline.create(epochAdjustment),
  aggregateArray,
  networkType,[]
).setMaxFeeForAggregate(100,0);

```

今回はaliceがalice自身にNFTデータを送信するトランザクションにしています。
一般的にNFTはメタデータにNFT本体のハッシュ値を記録しますが、今回は改ざんできないトランザクションメッセージ内にNFTデータを記録します。


# 署名＆アナウンス

トランザクションに署名して、ネットワークに通知します。

```js
signedTx = aggregateTx.signTransactionWithCosignatories(
alice,[],generationHash);

txRepo.announce(signedTx);

"https://testnet.symbol.fyi/transactions/" + signedTx.hash;


```

##### 結果

https://testnet.symbol.fyi/transactions/7424D1B4521BAAA55A6FCF64B3A35F60A2F12933EE6B824D82394C5B8ECC7B84
Firebase Local Emulator Suite を.NET SDK で利用する

[FirebaseのEmulator](https://firebase.google.com/docs/emulator-suite)をJavaScriptのSDKを使って利用する方法はネット上に豊富にあるのですが、
.NETのSDKを使ったやり方はあまり情報が無かったので記事にしました。
Emulatorの構築方法についてはこの記事では割愛させていただきます。

基本的には環境変数を設定してから呼び出す流れでいけるはずです。
実際にやってみたのは以下２つ。

 - Cloud Firestore
 - FirebaseAdmin Auth


# cloud Firestore
```
// 環境変数にemulatorへの向き先を設定
Environment.SetEnvironmentVariable("FIRESTORE_EMULATOR_HOST", "localhost:8080");

var firestoreDb = new FirestoreDbBuilder()
{
    // 何でも良さそう？　エミュレータ起動時に指定したproject名にしておけば安心
    ProjectId = "testproj",
    // エミュレータへの接続を強制しておけば安心
    EmulatorDetection = Google.Api.Gax.EmulatorDetection.EmulatorOnly,
}.Build();
```

# FirebaseAdmin Auth
```
// 環境変数にemulatorへの向き先を設定（ローカルでデフォルト設定ならlocalhost:9099）
Environment.SetEnvironmentVariable("FIREBASE_AUTH_EMULATOR_HOST", "localhost:9099");

FirebaseAdmin.FirebaseApp.Create(new FirebaseAdmin.AppOptions()
{
    // でたらめで良いので何らかのCredentialを指定する
    Credential = Google.Apis.Auth.OAuth2.GoogleCredential.FromAccessToken("mocktoken"),
    // エミュレータ起動時に指定したproject名
    ProjectId = "testproj",
});
```

# 番外編
非公式のGoogleCloudStorageエミュレータ、[fake-gcs-server](https://github.com/fsouza/fake-gcs-server)への接続はこんな感じ。
.NETから使う際は起動時に`-external-url`で自身のURLを引数指定してやる必要がある模様。
[gitのexsamples](https://github.com/fsouza/fake-gcs-server/tree/main/examples/dotnet)に.NETから呼び出す用のDockerファイルが用意されているので、それを使えば手っ取り早い。

```
var client = new StorageClientBuilder()
{
    // URLはフルで指定
    BaseUri = "http://localhost:5678/storage/v1/",
    // 認証無しで接続
    UnauthenticatedAccess = true,
}.Build();
```
【Rails】モデルにインスタンスメソッドを定義する方法

##モデルにメソッドを定義する理由
モデルに書くのはvalidatesやbelongs_to,has_manyなどだけでなく、メソッドも定義できる。

もちろんモデルを使わなくても小さいサービスであればコントローラーでも全然問題ないが、
理由として少し大きなサービスになってくると、すぐにコントローラーのコード量が増えてしまうからである。（ファットコントローラー）

その時は理解できても、数ヶ月後にコードを見返すと何のコードなのかわからなくなってしまう可能性がある。

##例を交えて解説

```user_controller.rb

def index
  @user = User.find(1)
  @my_age = @user.too_young ⬅️
end
```
このtoo_youngがインスタンスメソッドというもので、モデルで書いたメソッドを
コントローラーで呼び出している。

```user.rb

class User < ApplicationRecord
  validates :username, presence: true
  validates :email, presence: true 

  #ここがインスタンスメソッド
  def too_young
    if self.age >= 20  #20歳以上の場合
       return "大人です！" 
    else  #20歳以下の場合
       return "子供です！"
    end
  end 
end
```
too_youngメソッド内に「self」というものがある。
この「self」は何かというとusers_controller.rbで定義された@userのこと。

@userというインスタンスに対して「.(ドット)」で繋げてインスタンスメソッドを呼び出す時、インスタンスメソッド内では「self」が使え、self＝呼び出し元のインスタンス(@user)となる。

``インスタントメソッド内のselfは省略可能``。

##インスタントメソッドとは
インスタンスメソッドとは、作成したインスタンスから実行出来るメソッドのこと。
initializeメソッドでインスタンス変数に代入し、情報を保持している。

インスタンスメソッドは、このインスタンスごとに保持している情報を使って処理を書くことが出来る。

インスタントメソッドとは別にクラスメソッドがあるが、使い分けは``クラスメソッドは全体で扱う``べき情報を扱い、``インスタンスメソッドは個々で扱う``べき情報を扱うことを認識しておけばいい。

##参考記事
[Railsのモデルに書いたメソッドってどうやってコントローラで使うの？](https://qiita.com/leavescomic1/items/99f32f45cd04035f146c)
[【Ruby】 たい焼きで理解するオブジェクト指向におけるクラスの概念](https://pikawaka.com/ruby/class)
[【Ruby基礎】クラスメソッドとインスタンスメソッドの違いについて簡単にまとめてみた](https://techtechmedia.com/class-instance-method/)
超シンプルなVF・Apexのページネーション

カスタマイズ性重視。
例外処理も抜きで、超シンプルなページネーションのサンプルコードです。

## 完成品
![スクリーンショット 2022-01-08 11.44.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690075/29f9ac62-2a2f-784c-491a-571fd5d343a0.png)


## VFコード
```
<apex:page controller="pagination">
    <h1>ページネーション練習用</h1>
    <apex:form>
        <apex:dataList value="{!accResults}" var="acc">
            <p>{!acc.Name}</p>
        </apex:dataList>
        
        <div>
            <apex:repeat value="{!pageNumList}" var="pageNum">
                <apex:commandLink action="{!goClickNumPage}" value="{!pageNum}" style="margin-left:10px;">
                    <apex:param value="{!pageNum}" name="clickNum"/>
                </apex:commandLink>
            </apex:repeat>    
        </div>

        <apex:commandLink action="{!goPrevious}" value="前へ"/>
        <apex:commandLink action="{!goNext}" value="次へ" style="margin-left:10px;"/>
    </apex:form>
</apex:page>
```

## Apexコード
```
public with sharing class pagination {
    private Apexpages.StandardSetController ssc ;
    public List<Account> accResults {get; private set;}

    public pagination() {
        List<Account> accList = [SELECT Name FROM Account];

        this.ssc = new Apexpages.StandardSetController(accList);
        this.ssc.setPageSize(5);

        this.accResults = ssc.getRecords();
    }
    
    public List<Integer> getPageNumList(){
        List<Integer> resultList = new List<Integer>();
        Decimal totalRecordSize = (Decimal)this.ssc.getResultSize();
        Decimal endPageNumDec = totalRecordSize.divide(this.ssc.getPageSize(), 0, System.RoundingMode.UP);
        Integer endPageNum = (Integer)endPageNumDec;

        for(Integer i=1; i<=endPageNum; i++){
            resultList.add(i);
        }
        return resultList;
    }
    
    public void goClickNumPage(){
        String strClickNum = Apexpages.currentPage().getParameters().get('clickNum');
        Integer clickNum = Integer.valueOf(strClickNum);

        this.ssc.setPageNumber(clickNum);
        this.accResults = this.ssc.getRecords();
    }
    
    public void goPrevious(){
        this.ssc.previous();
        this.accResults = ssc.getRecords();
    }
    public void goNext(){
        this.ssc.Next();
        this.accResults = ssc.getRecords();
    }
}
```


## 参考文献
- https://developer.salesforce.com/docs/atlas.ja-jp.230.0.apexcode.meta/apexcode/apex_pages_standardsetcontroller.htm
- https://gren-dken.hatenablog.com/entry/2013/12/30/231614
オブジェクトから特定の型のメンバだけを抽出する型関数を作る

※PickFromValueTypeの実装をコメントで教えていただいたものに変えました。感謝

オブジェクトから特定の型のメンバだけを抽出する型関数が必要になったのでメモ。
オブジェクトから関数だけ抜いたりできる。
vuexの型付けをするときとかに使えそう。

```.ts
/**
 * 指定した型のvalue一覧をunion typeにして返す
 */
type ValueOf<T> = T[keyof T]
/**
 * valueの型を指定し、Targetのvalueの中でその型に一致するkeyの一覧をunion typeとして返す
 */
type KeysFromValueType<Target, Type> = ValueOf<{[key in keyof Target]: Target[key] extends Type ? key : never}>
/**
 * valueの型を指定し、Targetのvalueの中でその型に一致するkeyのみをPickした型を返す
 */
type PickFromValueType<Target, Type> = {[key in keyof Target as Target[key] extends Type ? key : never]: Target[key]};


const obj = {
    id: 0,
    name: '名前',
    func(){},
    asyncFunc(){
        return new Promise(resolve => setTimeout(resolve,100))
    }
}

// number型の値をもつkeyだけ抜き出す
type numbersKey = KeysFromValueType<typeof obj,number> // => "id"
// 関数型の値を持つkeyだけ抜き出す
type FuncKeyOfObj = KeysFromValueType<typeof obj,Function> // => "func" | "asyncFunc"
// 非同期関数だけを抜き出す
type AsyncFuncKeyOfObj = KeysFromValueType<typeof obj,(...args:unknown[]) => Promise<unknown>> // => "asyncFunc"

// numberだけをPickする
type numbers = PickFromValueType<typeof obj,number> // => { id: number }
// 関数型だけをPickする
type Funcs = PickFromValueType<typeof obj,Function> // => { func: () => void, asyncFunc: () => Promise<unknown> }
// 非同期関数だけをPickする
type AsyncFuncs = PickFromValueType<typeof obj,(...args: unknown[]) => Promise<unknown>> // => { asyncFunc: () => Promise<unknown> }
```

もっと良い書き方あるかも
以上
FIRESTORE INTERNAL ASSERTION FAILED: Failed to open DB: Internal: Failed to open LevelDB database atのエラー

## なぜこのエラーが出たのか
自分の場合はiOSバージョンのサポート切りを行う際に、なぜかFireStoreにアクセス出来なくなりました。
色々調べても解決方法出てこなかったので、記録として残します。

## 問題の切り分け
色々試行錯誤しましたが、
一度も使ったことのないシミュレータでビルドしてみると、問題なく起動できました。

## 解決策
シミュレータのキャッシュが悪さしてそうなので、キャッシュを消してみました。
一応自分がやったコマンド載せますが、キャッシュの消し方は調べてみてください。
削除処理は一歩間違えるとやばいので。。。

`rm -rf ~/Library/Developer/Xcode/iOS\ DeviceSupport/* `

キャッシュを消すと、問題なくビルドできるようになりました！
よかった！
【Ruby のまずいコード】漢字を数える

# お題

引数として与えられた文字列中の漢字の個数を数えて返すメソッドを書いてください。
同じ漢字が複数回出てきてもそれぞれカウントします。
文字列は UTF-8 であるとします。

# コード

```rb
def kanji_count(str)
  str.scan(/[一-龥]/).count
end
```

# 講評

「すべての漢字」を表す正規表現として `[一-龥]` は使えません。これでは Unicode の漢字の一部分しか拾えません。

Unicode では，漢字がいくつものブロックに分かれて収録されていますが，そのうちの最も基本的なものが「CJK 統合漢字（CJK Unified Ideographs）」と呼ばれるブロックです。
CJK 統合漢字のブロックは，Unicode バージョン 1.0 のとき，「一」で始まり「龥」で終わっていました。
`[一-龥]` という正規表現はその時代（30 年前！）の名残でしょう。

# 改善

「すべての漢字」を表す文字クラスは `\p{Han}` と書けます。これを使うのが簡単です。

```rb
def kanji_count(str)
  str.scan(/\p{Han}/).count
end
```

なお，特定範囲の文字の個数を数えるのに [String#count](https://docs.ruby-lang.org/ja/master/method/String/i/count.html) というメソッドがあります。
これを使うと，たとえば `a`〜`z` および `A`〜`Z` の個数を数えるのは

```rb
str.count("a-zA-Z")
```

のように書けます。
（ベンチマークテストはしていませんが）`scan` して `count` するよりも速いと思います。

ただ，`String#count` は正規表現が使えません。これで漢字を数えようとすると，Unicode 上のすべての漢字の範囲を調べて書く必要があり，少々面倒です。
API Gatewayで特定のリソースのみ、IP制限する方法

#はじめに
`メンテナンス性も考慮した`、API Gatewayの一部のリソースのみIP制限する方法についてまとめました。

#前提条件
例として、`hoge1`,`hoge2`,`fuga1`,`fuga2`の4つのリソースを作成するとします。
作成する際、`IP制限あり`の`hoge1`,`hoge2`の手前に`restriction`をつけます。
対して、`IP制限なし`の`fuga1`,`fuga2`の手前には`free`をつけます。

実際にIP制限する際に楽になりますので、説明した通りに作成しましょう。

![スクリーンショット 2021-12-30 16.42.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/da8da80e-b16a-9c2a-d3ce-4af7bab8f0aa.png)

###4つのURL
`IP制限あり`

- `https://~/prod/restriction/hoge1`
- `https://~/prod/restriction/hoge2`

`IP制限なし`

- `https://~/prod/restriction/fuga1`
- `https://~/prod/restriction/fuga2`

#リソースポリシーで、一部のみIP制限する
左の`リソースポリシー`をクリックしましょう。

![スクリーンショット 2021-12-30 16.49.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/4d12ef89-7487-88a6-12c2-bd4bd8778433.png)

以下をコピペします。
`ステージ`は、`prod`とします。
`<account-id>`は、文字通りAWSアカウントIDです。
`<api-id>`は、apigatewayのIDになります。（下記画像の赤線箇所です。）

![スクリーンショット 2021-12-30 16.53.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/83225f8c-32e8-7fda-ae21-287ac27402ab.png)



```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": "execute-api:Invoke",
      "Resource": "arn:aws:execute-api:ap-northeast-1:<account-id>:<api-id>/prod/*/*/*"
    },
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "execute-api:Invoke",
      "Resource": "arn:aws:execute-api:ap-northeast-1:<account-id>:<api-id>/prod/*/restriction/*",
      "Condition": {
        "NotIpAddress": {
          "aws:SourceIp": ["111.111.11.11/32", "222.222.22.22/32"]
        }
      }
    }
  ]
}
```

#リソースポリシーの解説

上の`Allow`では、全てのapiを許可しています。

下の`Deny`では、`/prod/*/restriction/*`としており、`restriction`配下のリソースである`hoge1`と`hoge2`のみIP制限できます。

手前に`restriction`をつけることで、
**今後、IP制限したいリソースやIP制限しなくないリソースが出た際に、
`リソースポリシーを修正する必要はなく、メンテが楽なため、
最初に、restriction`と`free`をつけるとよいと思います。**

ちなみに、`restriction`配下のGETメソッドのみIP制限したい場合、以下のようにGETをつけるとよいです。
↓
`/prod/GET/restriction/`

その他、リソースポリシーの一般的なユースケースはこちらが参考になります。

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-resource-policies-examples.html#apigateway-resource-policies-source-ip-address-example

#すべてのリソースをIP制限する場合
ちなみにすべてのリソースをIP制限する場合は、以下のとおりです。

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": "execute-api:Invoke",
      "Resource": "arn:aws:execute-api:ap-northeast-1:<account-id>:<api-id>/prod/*/*/*"
    },
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "execute-api:Invoke",
      "Resource": "arn:aws:execute-api:ap-northeast-1:<account-id>:<api-id>/prod/*/*/*",
      "Condition": {
        "NotIpAddress": {
          "aws:SourceIp": ["111.111.11.11/32", "222.222.22.22/32"]
        }
      }
    }
  ]
}
```