OmniAICreator/Qiita-1.07M huggingface dataset:
clangでビルドしてlcovでカバレッジを取る方法

# 内容
- lcovはgcc用のライブラリなので、clangでビルドしたgcdaファイルをlcovでそのまま変換しようとすると以下のエラーがでる。

```terminal:
$ lcov -c -d ./build -o lcov.info
Capturing coverage data from ./build
Found gcov version: 7.5.0
Scanning ./build for .gcda files ...
Found 7 data files in ./build
Processing src/CMakeFiles/src.dir/my_thread.cpp.gcda
/home/xxxx/git-work/wsl-ci-env/build/src/CMakeFiles/src.dir/my_thread.cpp.gcno:version '402*', prefer 'A75*'
geninfo: ERROR: GCOV failed for /home/xxxx/git-work/wsl-ci-env/build/src/CMakeFiles/src.dir/my_thread.cpp.gcda!
```

このエラーを回避してカバレッジを取る方法の記事

# 参考
http://logan.tw/posts/2015/04/28/check-code-coverage-with-clang-and-lcov/
 
基本はこの方法で可能だが、そのままだとエラーがでるところがあったので少し修正している。

# 前提
- Ubuntu上での実行
- gcc と lcovの使い方は知っている

# 手順
## LLVMインストール
```terminal:
$ sudo apt install llvm
```

## llvm-gcov.shを以下の内容で作成する
```shell:llvm-gcov.sh
#!/bin/bash
exec llvm-cov gcov "$@"
```

`$ chomod +x llvm-gcov.sh` で実行ファイルにする

## --gcov-toolオプションで実行する
```terminal:
$ lcov -c -d ./build -o lcov.info --gcov-tool `pwd`/llvm-gcov.sh
Capturing coverage data from ./build
Found LLVM gcov version 6.0.0, which emulates gcov version 4.2.0
Scanning ./build for .gcda files ...
Found 7 data files in ./build
Processing src/CMakeFiles/src.dir/my_thread.cpp.gcda
...
Finished .info-file creation
```
SolidityのソースコードをRemixでサクッと共有する方法

## Remixで書いているコードを共有したくなった時は

Remixで作成しているコードをチーム内で共有したかったときにやり方を調べたので備忘録として残します。この記事ではgistを利用する方法と、base64にエンコードしたデータを利用する方法を紹介します。

## Gistを利用する方法

Settingでgithubのアクセストークンを保存します。

![Screen Shot 2022-02-03 at 23.27.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258956/1da6ae53-4bb5-b4b8-a0d7-e240bfa5ae46.png)

コントラクトファイルを右クリックし、Publish file to gistを選択します。

![Screen Shot 2022-02-03 at 23.31.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258956/5478462c-1eb9-6f92-2ab8-b0ab84eb20b8.png)

gistにコントラクトが発行できました。

![Screen Shot 2022-02-03 at 23.32.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258956/45180303-b8de-9ee4-1c00-6c729fdf0612.png)


このgistには[1cf345cca91903ebebfe6a33cfc77d9f](1cf345cca91903ebebfe6a33cfc77d9f)というキーが生成されているので、URLのパラメータとしてgist=1cf345cca91903ebebfe6a33cfc77d9fというように設定することで共有用リンクが生成できます。

こちらが[gistを利用する方法で作成した共有用リンク](https://remix.ethereum.org/?#gist=1cf345cca91903ebebfe6a33cfc77d9f)です。

## Base64にエンコードしたデータを使う方法

こちらは[データをBase64にエンコードできる外部サービス](https://www.base64encode.org/)を利用します。

![Screen Shot 2022-02-03 at 23.52.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258956/8f00e6f2-994d-ffbd-36f2-8577b299d0eb.png)

SolidityのコードをBase64形式にします。

![Screen Shot 2022-02-03 at 23.53.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258956/a6f0b5ad-362e-b069-5786-da151b1f991c.png)

こちらがこの方法で生成されたbase64のデータです。

```
Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4wOwoKY29udHJhY3QgQ29tcGF0ZUFiaUVuY29kZVBhY2tlZEFuZEJ5dGVzIHsKCiAgICBmdW5jdGlvbiBleGVjdXRlMSgpIHB1YmxpYyB7CiAgICAgICAgcmVxdWlyZSh0ZXN0MSgpKTsKICAgIH0KCiAgICBmdW5jdGlvbiBleGVjdXRlMigpIHB1YmxpYyB7CiAgICAgICAgcmVxdWlyZSh0ZXN0MigpKTsKICAgIH0KCiAgICBmdW5jdGlvbiB0ZXN0MSgpIHB1YmxpYyBwdXJlIHJldHVybnMgKGJvb2wpIHsKICAgICAgICByZXR1cm4ga2VjY2FrMjU2KGFiaS5lbmNvZGVQYWNrZWQoInN0cmluZyIpKSA9PSBrZWNjYWsyNTYoYWJpLmVuY29kZVBhY2tlZCgic3RyaW5nIikpOwogICAgfQoKICAgIGZ1bmN0aW9uIHRlc3QyKCkgcHVibGljIHB1cmUgcmV0dXJucyAoYm9vbCkgewogICAgICAgIHJldHVybiBrZWNjYWsyNTYoYnl0ZXMoInN0cmluZyIpKSA9PSBrZWNjYWsyNTYoYnl0ZXMoInN0cmluZyIpKTsKICAgIH0KCn0=
```

このbase64のデータをcode={base64のデータ}という形式で、URLのパラメーターとして設定することで共有用リンクが生成できます。

こちらが[base64を利用する方法で作成した共有用リンク](https://remix.ethereum.org/?#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4wOwoKY29udHJhY3QgQ29tcGF0ZUFiaUVuY29kZVBhY2tlZEFuZEJ5dGVzIHsKCiAgICBmdW5jdGlvbiBleGVjdXRlMSgpIHB1YmxpYyB7CiAgICAgICAgcmVxdWlyZSh0ZXN0MSgpKTsKICAgIH0KCiAgICBmdW5jdGlvbiBleGVjdXRlMigpIHB1YmxpYyB7CiAgICAgICAgcmVxdWlyZSh0ZXN0MigpKTsKICAgIH0KCiAgICBmdW5jdGlvbiB0ZXN0MSgpIHB1YmxpYyBwdXJlIHJldHVybnMgKGJvb2wpIHsKICAgICAgICByZXR1cm4ga2VjY2FrMjU2KGFiaS5lbmNvZGVQYWNrZWQoInN0cmluZyIpKSA9PSBrZWNjYWsyNTYoYWJpLmVuY29kZVBhY2tlZCgic3RyaW5nIikpOwogICAgfQoKICAgIGZ1bmN0aW9uIHRlc3QyKCkgcHVibGljIHB1cmUgcmV0dXJucyAoYm9vbCkgewogICAgICAgIHJldHVybiBrZWNjYWsyNTYoYnl0ZXMoInN0cmluZyIpKSA9PSBrZWNjYWsyNTYoYnl0ZXMoInN0cmluZyIpKTsKICAgIH0KCn0=)です。

こんなNFTのコントラクト作ったけどちょっと動かしてみて、みたいな場合に便利ですので、ぜひ試してみてください！
個人メモ 感覚で使わないようするKotlin文法まとめ

#目次

1. 目的
2. 何となくでやっていたこと，知らなかったこと
3. まとめ

##1. 目的

Kotlinの文法で，何となくで使っていたところをまとめました．


##2. 何となくでやっていたこと，知らなかったこと

``Any``‥すべてのクラスのスーパークラス，nullを許容するには**Any?**というスーパークラスが用いられる．

``Nothing``‥インスタンスが存在しないクラスのこと．関数で，Nothingがreturnされたら，returnされるものがない．Nothingは，すべてのクラスのサブクラスである．

``?``‥nullを許容するために型の後に必要なキーワードで，nullをデフォルトで代入することができないので，nullを許容するために型の後に付ける．関数の引数もデフォルトで，nullを与えることができないのでこのキーワードをつける必要がある．

``val``‥参照先のオブジェクトが，この変数を呼び出したときに必要である．変数の参照先のオブジェクトを利用することを知らなかった．

``lateinit``‥val変数の生成時に，参照先のオブジェクトが必要となりますが，変数の初期化が行えない場合は，lateinitを使って初期化を遅延することができる．このキーワードを利用すると，初期化時にnon-nullであることが担保されます．また，参照するには，必ず初期化が行われていることを確認する必要がある．(インスタンスとして，生成処理を行っているか)

``vararg``‥可変長引数を表現するためのキーワード，任意の長さの引数を渡すことができる．また，varargを用いて引数を表すと，配列型のオブジェクトとして参照することができる．

```kotlin
fun greet(vararg name: String) {
    if (name.isNotEmpty()) {
        println("Hello $name")
    }
} 
```

``inline fun``‥インライン関数として呼び出すことができる．目的としては，実行速度を向上できる，3つも特徴がある．呼び出す関数の内容に対する型情報が埋め込まれる，ラムダで行うループの処理を，returnで抜けることができる．(noinline, crossinlineで，非局所リターンを防止できる)，引数で与えたラムダの型が保存されることで，呼び出し時のコストが低下することで，実行速度が向上する．繰り返しの処理をする際に，inlineで呼び出すことで，3つの利点が得られる可能性がある．

``forEach``‥forのように，breakができない．return@forEachをしても，ループの処理が止まることはない．また，forは，{}以降の処理をループで実行しているが，forEachは，単にラムダの中の処理を繰り返し行っていることも違いの一つである．

**try-catch, throw**‥例外を投げる投げないを呼び出し先で決めることができる．スローされなかった例外は，try-catchまで伝播することができる．だから，それぞれの関数で，例外を投げなくてもよい．

``classがデフォルトで，public final``‥publicでのメリットは，暗黙的にゲッター,セッターを利用することができることが強みである．

``sealed class, enum の違い``‥シングルトンとして利用することもできる，個別のインスタンスとしても利用が可能であること．

``setter field``‥var で定義したプロパティをセッターを使って定義したいときは，fieldというキーワードを用いること．

``sort, sortedByの違い``‥sortは，リストに変更を加えて物を返し, sortedByは，リストを変更せずに戻り値のみを返す．

``class名を取得する``‥companion object で、Tag(変数)に対して，Example::class.java.simpleNameを代入することで，クラス名をTagとして取得することができる．

##3. まとめ

雰囲気で使わないように，よくわかっていないところを改めてまとめてみました．これまでの経験と知識が結びつくような勉強となったので，これから雰囲気で使わないようにわからないことを適宜調べながら使っていきます．
【個人開発】フリーランスを誹謗中傷や不正アクセスなどのトラブルから守る（かもしれない）メールフォーム開設するサービスをリリースした

フリーランスの方が仕事の依頼をSNSのDMやEメールアドレスで募集しているのをよく見かけるが、トラブルにあっているのもよく見かけるので、そういう方向けにメールフォームを開設するWebサービスをリリースしたら需要あるんじゃないかと思ってリリースした。


https://formbase.link


## DMやeメールのデメリット

※もちろんメリットもある。

* マルウェアや不快な画像などのファイルを添付される。
* 誹謗中傷・いやがらせにあう。
* Gmailなどのアカウントに利用しているメールアドレスを公開すると不正アクセスのリスクがある。

## 開発したサーピスの主な機能

* ユーザー登録してメールフォームを開設し実際にお問い合わせを受け取る。<br>→メールアドレスを隠蔽できる。
* メールフォームの入力項目を自由にカスタマイズする。<br>→ファイルを添付できなくする。
* ユーザーは差出人の個人情報を収集し、悪意のある差出人はブロックできるようにする。<br>→誹謗中傷・いやがらせを防止する。

## 技術選定

### フロントエンド

* Next.js
* React
* Redux Toolkit
* Material-UI

### バックエンド

* PHP
* laravel 8.*
* MariaDB

### インフラ

* Vercel（Next.jsのホスティング）
* Docker
* Docker Compose
* AWS（APIサーバー）
  * EC2
  * ELB
  * ACM（SSL証明書）
  * RDS
  * S3
  * Cloud Front
  * SES（メール通知）

インフラはもっと安価に構築できるが自身の学習も兼ねている（むしろそっちがメイン）

![formbase.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266668/b57512b2-c340-6637-20c4-42f9d29c3ad1.png)

##Formbaseの機能紹介

### ユーザー登録してメールフォームを開設し実際にお問い合わせを受け取る

ユーザー登録すると以下のようなメールフォームが生成されるので、生成されたメールフォームのURLを自身SNSに貼り付ける。
![FireShot Capture 009 - とらべえ@Formbase運営さん - Frombase - localhost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266668/32b1274b-89e6-81d1-0d68-a41b1c70856e.png)

送信されたメッセージは登録されたメールアドレスに通知される。差出人側にも送信内容を確認するメールが届くが、ユーザーのメールアドレスが差出人に知られることはない。
メッセージ内容を確認し、イタズラ目的でない信用できるクライアントであると判断した場合のみ、その後eメールでやり取りしてもらう想定。

### メールフォームの入力項目を自由にカスタマイズする

![FireShot Capture 010 - お問い合わせフォーム - フォーム - とらべえ@Formbase運営さんのユーザーページ - Frombase - localhost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266668/a6eb0c3b-c93f-dd69-b4b0-96fbc56800cd.png)

入力フィールドは複数作成することができ、それぞれ入力内容してもらいたい内容に応じて入力の形式や制御を設定することができる。
メールフォームには受付期間を設定することができ、期間限定のメールフォームの作成が可能。
また、メールフォーム自体も複数作成が可能。用途に応じてメールフォームを作成、それぞれ通知先のメールアドレスを変更できる。

### ユーザーは差出人の個人情報を収集し、悪意のある差出人はブロックできるようにする

ユーザー宛に送られたメッセージはユーザーページのコンバージョンから確認することができる。
![FireShot Capture 011 - テストメールさんのメッセージ - コンバージョン - とらべえ@Formbase運営さんのユーザーページ - Frombase - localhost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266668/bd26b0a2-d0fd-6f78-9c2f-42217579c020.png)

悪質な差出人であった場合はブロックを`メールアドレス`・`セッション`・`IPアドレス`でブロックできる。
![FireShot Capture 014 - テストメールさんのメッセージ - コンバージョン - とらべえ@Formbase運営さんのユーザーページ - Frombase - localhost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266668/02b38588-5fb2-7cdf-8417-395c682ad5af.png)

## 今後のアップデート（予定）

余裕があれば

* ソーシャルログイン
* 入力フィールドの種類を増やす
* コンバージョンの集計機能
* 顧客管理機能
* その他UIの改善

## 感想

Googleフォームでよくね？

[Twitter](https://twitter.com/torabe_torabe)
SRE導入「4大シグナル」

#【SRE導入「4大シグナル」】
SREチームで奮闘中です。
ユーザーが直接利用するシステムでは、これらの4つのメトリクスを計測することから始めよう。

##4大シグナル
###レイテンシ（リクエストを処理してレスポンスを返すまでにかかる時間）
- 処理に成功したリクエストのレイテンシと、失敗したリクエストのレイテンシを区別することは重要
- 単純にエラーをフィルタリングするのではなく、エラーのレイテンシも追跡することが重要

###トラフィック（システムに対するリクエストの量）
- システム固有の高レベルのメトリックで計測
- Webサービスの場合、毎秒の HTTP リクエスト数で計測
    - 静的なコンテンツか動的なコンテンツで区別する。

###エラー（処理に失敗したリクエストのレート）
- 明示的な場合（HTTPの500番台など）
- 暗黙的な場合（HTTP200の成功レスポンスが返されているが、内容に間違いがあるものなど)
- ポリシーによる場合（「レスポンスタイムを1秒以下にすると約束しているなら、1秒以上かかったリクエストはエラー」とするようなものなど）

※プロトコルのレスポンスコードからだけでは、あらゆる障害の状況を表現するには不十分。

###サチュレーション（アクティブなワーカー数）
- 最も制約のあるリソースに重点を置いて、システムの利用率を計測
    - メモリに制約があるシステムであればメモリ
    - I/Oに制約があるシステムであればI/O
- 多くのシステムでは、利用率が100%に達する前にパフォーマンスの低下が生じるので利用率のターゲットを必ず設定しておく


これらをモニタリングして、いずれかに問題が生じたとき、サチューションの場合は問題になりかかっているときに、人間が対応することができる状況ができていることが大事。

##参考
[SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム](https://www.amazon.co.jp/SRE-%E3%82%B5%E3%82%A4%E3%83%88%E3%83%AA%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%93%E3%83%AA%E3%83%86%E3%82%A3%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%83%AA%E3%83%B3%E3%82%B0-%E2%80%95Google%E3%81%AE%E4%BF%A1%E9%A0%BC%E6%80%A7%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%83%AA%E3%83%B3%E3%82%B0%E3%83%81%E3%83%BC%E3%83%A0-%E6%BE%A4%E7%94%B0-%E6%AD%A6%E7%94%B7/dp/4873117917/ref=cm_cr_arp_d_product_top?ie=UTF8)
HostOS:Mac ClientOS:Windowsにおけるリモート音声の取得について（TeamViewer使用）

# 結論
* HostOSがMacでClientがWindowsでもBlackholeとLadioCastを使ってTeamViewerを使えばWindows側でMacの音声を聴くことはできる。  
ただし、、、なぜか安定しない。。。。

* 試行錯誤中のため間違ってるところがあるかもしれない。

## 困っていたこと
* Mac でSerato DJ Proを動作させるために、音楽ライブラリをMacに移設したのだが、編集もMac上でやりたい。Windows機でitunesを動作させたくない（重いから）
* Macは外付けSSDとDJスペースに固定してるからあまり頻繁に動かしたくない。
* WindowsからMacに接続してWindows機で音楽聴きながらMac上のライブラリを整理すればいいんじゃないかと思ってTeamViewerを使ってリモート操作と同時に音声も転送できると思っていたらすんなりできなかった。

## 環境
* ホスト側
    * macOS Monterey 12.0.1  
     ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171559/e741ea6d-69e0-5f23-cdf6-9a2fbbb41ebc.png)
    * TeamViewer 15.26.5
* クライアント側
    * Windows 20H2  
     ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171559/64bb6409-fdc9-8e3d-a21f-c6c32daa3267.png)
    * TeamViewer 15.26.4


## 必要なソフトのインストール
* Mac側
    * Blackhole   
[Blackhole HP](https://existential.audio/blackhole/?pk_campaign=github&pk_kwd=readme) へ行き、emailや名前を入力して登録するとメールでダウンロードリンクが来るので2chのpkgをインストール する  
     ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171559/244323e6-cf84-ccbd-b019-223cff011d1c.png)  
■ダウンロード  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171559/1bd3a08f-33f4-c189-4bbb-23c66a2becd6.png)  

    * LadioCast  
    AppStoreからインストール   
     ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171559/514abbed-dcc7-5c67-c3f0-afd5f9a0d5ee.png)  

    * TeamViewer  
    [TeamViewer HP](https://www.teamviewer.com/ja/download/mac-os/)からダウンロードしてインストール、設定は割愛。

* Windows側
    * TeamViewer  
    [TeamViewer HP](https://www.teamviewer.com/ja/download/windows/)からダウンロードしてインストール、設定は割愛。

## 設定
* Mac側
    * Blackhole
        * Finderを開きアプリケーション→ユーティリティ→Audio MIDI設定  
        (ここの設定が怪しい)  
        複数出力装置を作成して図のようにする。MacBook Airのスピーカーを上に置いておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171559/431719dc-7a83-c5db-3783-87f7d43fa6eb.png)  

    * LadioCast  
        * 入力1にBlackholeを指定する。メインとAux1をONにする  
        * 出力 メインにBlackholeを指定する。
        * 出力 Aux1にBlackholeを指定する。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171559/447d6fe0-4798-d07f-04d3-39bb63248cf4.png)  
    * TeamViewer  
        * 音声設定を開く  
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171559/0d5e644b-11a9-74e3-6718-f2c010ff7554.png)  
(ここの挙動が怪しい)  
下記のどちらかの設定にしてTeamViewerを一度切断してから接続すると音声が拾える場合と拾えない場合がある。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171559/e97073f0-9a65-8b45-a41f-1abab9a42752.png)  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171559/5169a621-8d44-70cb-8f0f-a7e4df65a747.png)  

## まとめ
中途半端な状態だが一旦音声が取得できるようになったので、ここまでにしておく、、、
MySQLユーザーの作成と権限追加（MySQL8.0）

# したいこと

- 初期で作成されるroot（master）ユーザー以外に新規でユーザーを作成し、運用を分けたい。

# How To

1. CREATEステートメントでUSERを作成
2. GRANTステートメントで権限を付与

の2ステップ。

# GRANTステートメントで付与できる権限について

多すぎるので、公式リファレンスを参照。

https://dev.mysql.com/doc/refman/8.0/ja/grant.html#:~:text=%E8%A1%A8%C2%A013.11%C2%A0GRANT%20%E3%81%8A%E3%82%88%E3%81%B3%20REVOKE%20%E3%81%AB%E8%A8%B1%E5%8F%AF%E3%81%95%E3%82%8C%E3%82%8B%E9%9D%99%E7%9A%84%E6%A8%A9%E9%99%90


# 基本構文

基本構文については以下の通り。

## ◾️ ユーザー作成

```sql
CREATE '{user名}'@'{host名}' IDENTIFIED BY '{password}';
```

- user名とhost名の組み合わせにより、同じユーザー名であっても接続元のhostによって権限を変えることができる。

## ◾️ 権限付与

```sql
GRANT {付与したい権限名} ON {データベース名}.{テーブル名} TO 'user名'@'{host名}';
```

- 付与したい権限名はカンマ区切りで複数指定可能。
- データベース名やテーブル名は「*」によりワイルドカード指定が可能。

# やってみる

## ◾️ 読み取り専用（カラムレベルのSELECT）権限を持ったユーザーの作成

ユーザーの作成〜権限付与。

```sql
CREATE USER 'readonly'@'%' IDENTIFIED BY 'readonly';
GRANT SELECT ON hogehoge.* TO 'readonly'@'%';
```

どのような権限が付与されたかどうかは `SHOW GRANTS` ステートメントで確認できます。

```sql
SHOW GRANTS FOR 'readonly'@'%';
```

以下のような結果が返ってきます。

```sql
# Grants for readonly@%
'GRANT USAGE ON *.* TO `readonly`@`%`'
'GRANT SELECT ON `hogehoge`.* TO `readonly`@`%`'
```

```
'GRANT USAGE ON *.* TO `readonly`@`%`'
```

 とありますが、USAGEというのは何も権限がない状態のことらしいです。

なにも権限がない状態を与えた上で、

```
'GRANT SELECT ON `hogehoge`.* TO `readonly`@`%`'
```

により、SELECT権限が与えられていることを示しているみたいですね。

## ◾️ 全権限を持ったユーザーの作成

```sql
CREATE 'root'@'%' IDENTIFIED BY 'root';
```

```sql
GRANT ALL ON *.* TO 'root'@'%';
```

- ALLで全権限付与になります。
- `*.*` で意味合い的には`{全てのデータベース}.{全てのテーブル}`となるのでグローバルな権限を持てます。

## ◾️ 既存ユーザーから同様の権限をもったユーザーを作成したい場合

これは応用です。察しの良い方はお分かりかと思いますが、`SHOW GRANT`ステートメントで対象ユーザーに権限を付与したときのGRANTステートメントの構文が返ってくるので、権限付与の際にその構文のTOで指定するユーザーを変更し、実行してやれば良いです。

```sql
# Grants for readonly@%
'GRANT USAGE ON *.* TO `readonly`@`%`'
'GRANT SELECT ON `hogehoge`.* TO `{user名を変更}`@`%`' // この構文をコピーして実行する
```

# 参考

[https://dev.mysql.com/doc/refman/8.0/ja/grant.html](https://dev.mysql.com/doc/refman/8.0/ja/grant.html)

[https://dev.mysql.com/doc/refman/8.0/ja/show-grants.html](https://dev.mysql.com/doc/refman/8.0/ja/show-grants.html)
Raspberry Pi の64-bitと32-bitで、パフォーマンスはどのように変わるのか？ (メモ置き場)

[64-bit 版 Raspberry Pi OS が正式リリース](https://www.raspberrypi.com/news/raspberry-pi-os-64-bit/)となりました。アーキテクチャーの違いでどのくらい差が出るのかを確認した内容です。

## 検証環境

**共通**

- Raspberry Pi 4 Model B 4GB
    - microSD: SDSQUAR-032G-GN6MN (32GB/A1)
    - ベンチマークプログラム: [姫野ベンチマーク](https://i.riken.jp/supercom/documents/himenobmt/)

この条件下で、Raspberry Pi OS 32-bit / 64-bit それぞれで姫野ベンチマークをコンパイル＆実行した結果を比較しています。
姫野ベンチマークは、CPUだけでなくメモリ帯域にも負荷がかかる(ような)ベンチマークテストプログラムとして選択しました。

## 結論

- 64-bit バイナリーは、32-bit バイナリーより約22%の性能向上が見られた。
- kernel が 64-bit でも、バイナリーが 32-bit では性能向上は見られない。

## 記録

### 準備: 姫野ベンチマークのコンパイル

```console
curl -O https://i.riken.jp/wp-content/uploads/2015/07/himenobmt.c.zip
unzip himenobmt.c.zip
lha x himenobmt.c.lzh
make
strip bmt
```

### 結果

MFLOPS 値

| OS ↓ / Binary → | 32-bit | 64-bit |
|--------------------|-------:|-------:|
| **32-bit**         | 845.7  | (n/a)  |
| **64-bit**         | 842.5  | 1041.3 |

CPU 時間(秒)

| OS ↓ / Binary → | 32-bit | 64-bit |
|--------------------|-------:|-------:|
| **32-bit**         | 3.89  | (n/a)   |
| **64-bit**         | 3.90  | 3.16    |

#### OS:32-bit / Binary:32-bit

```console
$ uname -a
Linux rpi4 5.10.92-v7l+ #1514 SMP Mon Jan 17 17:38:03 GMT 2022 armv7l GNU/Linux
$ file bmt
bmt: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, BuildID[sha1]=3cca5983b37adc126bc2067566cfa6359bfdc59d, for GNU/Linux 3.2.0, stripped
$ ./bmt
mimax = 129 mjmax = 65 mkmax = 65
imax = 128 jmax = 64 kmax =64
cpu : 3.894290 sec.
Loop executed for 200 times
Gosa : 1.688699e-03
MFLOPS measured : 845.735474
Score based on MMX Pentium 200MHz : 26.208103
```

#### OS:64-bit / Binary:64-bit

```console
$ uname -a
Linux rpi4-64 5.10.92-v8+ #1514 SMP PREEMPT Mon Jan 17 17:39:38 GMT 2022 aarch64 GNU/Linux
$ file bmt
bmt: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=b9d3262c0ca7837e7cc7b1fb887412788927e0c5, for GNU/Linux 3.7.0, stripped
$ ./bmt
mimax = 129 mjmax = 65 mkmax = 65
imax = 128 jmax = 64 kmax =64
cpu : 3.162630 sec.
Loop executed for 200 times
Gosa : 1.688752e-03
MFLOPS measured : 1041.392512
Score based on MMX Pentium 200MHz : 32.271228
```

#### OS:64-bit / Binary:32-bit (参考)

32-bit バイナリーが実行できるように armhf(32-bit)のglibcをインストール。

```console
$ uname -a
Linux rpi4 5.10.92-v8+ #1514 SMP PREEMPT Mon Jan 17 17:39:38 GMT 2022 aarch64 GNU/Linux
$ sudo apt install -y libglib2.0-0:armhf
```

```
$ uname -a
Linux rpi4 5.10.92-v8+ #1514 SMP PREEMPT Mon Jan 17 17:39:38 GMT 2022 aarch64 GNU/Linux
$ file bmt
bmt: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, BuildID[sha1]=3cca5983b37adc126bc2067566cfa6359bfdc59d, for GNU/Linux 3.2.0, stripped
$ ./bmt
mimax = 129 mjmax = 65 mkmax = 65
imax = 128 jmax = 64 kmax =64
cpu : 3.909045 sec.
Loop executed for 200 times
Gosa : 1.688699e-03
MFLOPS measured : 842.543179
Score based on MMX Pentium 200MHz : 26.109178
```

## 考察

(WIP) いい考察、だれかお願い。

## おわりに

とはいえ、コンパイルし直しただけで、パフォーマンスが上がると思わないこと。「私の環境ではこうでした」という程度で。

EoT
MASM32からmsvcrtを使ってみた

#MASM32からmsvcrtを使ってみた

```printf.asm
comment *
ml /c /coff /Fl /Sa printf.asm
link /subsystem:console printf
*
includelib kernel32.lib
includelib msvcrt.lib

.386
.model flat

ExitProcess proto stdcall :DWORD
printf proto c :VARARG

.const
fmt	db	'hello, world %.20f', 0dh, 0ah, 0
num	dq	3.1415926535897932384626433832795

.code
_start:
	invoke	printf, addr fmt, num
	invoke	ExitProcess, 0

end _start
```

```dev.bat
@echo off
path %path%;C:\masm32\bin
set LIB=C:\masm32\lib
cmd
```

##実行例
![m.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257554/8c0c94cf-0a6b-6e25-76ad-4dbf1f0cb00c.png)
DjangoでiCalendar(.ics)ファイルをダウンロードする方法

## はじめに
こんにちは、reimeiです。
先日Djangoで開発しているwebアプリケーションにてDBに保存しているスケージュールをiCalendarファイルに書き出して返す処理を実装しようとした際、つまづいたので共有しようと思います。

## 解決策
▼とりあえず、必要なライブラリをインストール

```bash
$ pip3 install ics
```

▼実装例

```python
from ics import Calendar, Event
import arrow
import os
from django.http import HttpResponse

def download_icalendar_file(request):
    calendar = Calendar()
    event = Event()
    event.name = "飲み会"
    event.begin = arrow.get("2022-2-3 20:00:00", "YYYY-MM-DD HH:mm:ss") \
            .replace(tzinfo='Asia/Tokyo')
    event.end = arrow.get("2022-2-3 23:30:00", "YYYY-MM-DD HH:mm:ss") \
            .replace(tzinfo="Asia/Tokyo")
    calendar.events.add(event)

    with open('calendar.ics', 'w') as f:
        f.write(str(calendar))
    with open('calendar.ics', 'rb') as f:
        response = HttpResponse(f.read(), content_type="text/calendar")
        response['Content-Disposition'] =\
            'inline; filename=' + os.path.basename('schedule.ics')
        os.remove('schedule.ics')
        return response
```

## 解説
必要なライブラリをインポートしている。

```python
from ics import Calendar, Event
import arrow
import os
from django.http import HttpResponse
```
<br>
カレンダーやイベント情報の設定を行っている。
`event = Event()` 以下を繰り返し実行すると複数のイベント情報を持つカレンダーを作成することができる。
時間は何もせずに設定すると世界標準の時間になってしまうので時差を計算するか以下のようにタイムゾーンを変更するなどの処理を行う必要があるので注意。

```python
calendar = Calendar()
event = Event()
event.name = "飲み会"
event.begin = arrow.get("2022-2-3 20:00:00", "YYYY-MM-DD HH:mm:ss") \
        .replace(tzinfo='Asia/Tokyo')
event.end = arrow.get("2022-2-3 23:30:00", "YYYY-MM-DD HH:mm:ss") \
        .replace(tzinfo="Asia/Tokyo")
calendar.events.add(event)
```
<br>
calendar.icsという名前のファイルにカレンダー情報を書き込んでいる。

```python
with open('calendar.ics', 'w') as f:
    f.write(str(calendar))
```
<br>
カレンダーファイルをクライアントに返すためのレスポンスの設定を行っている。
また、作成したschedule.icsが残り続けると邪魔なので削除も行っている。
▼メディアタイプには `text/calendar` という形式があるらしい(今回初めて知った)

https://www.iana.org/assignments/media-types/text/calendar

```python
with open('calendar.ics', 'rb') as f:
    response = HttpResponse(f.read(), content_type="text/calendar")
    response['Content-Disposition'] =\
        'inline; filename=' + os.path.basename('schedule.ics')
    os.remove('schedule.ics')
    return response
```

あとはurls.pyでリンクを設定したり、そのリンクをtemplateに貼り付ければ完成！

## 最後に
今回DjangoでiCalendarファイルをダウンロードする機能を実装していた際、躓いたが日本語の記事が見つからなかったのでまとめてみました。
また、今回紹介した解決方法よりも良い方法をご存知の方は教えていただきたいです！
(特にレスポンスの設定をいじっているあたり)
【Unity】InputFieldの入力タイプを指定する

UnityのInputFieldでテキストコンテンツのタイプを指定する方法についてです。

Inspector > Content Type から選べます。

![Screen Shot 2022-02-03 at 22.58.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399610/def76833-f64c-5a2f-fb94-f7a2343a669a.png)

各項目については公式をご確認下さい。

https://docs.unity3d.com/ja/2018.4/ScriptReference/UI.InputField.ContentType.html

以上となります。
vue-carouselでページネーション部分のスタイルを変更する


[vue-carousel](https://www.npmjs.com/package/vue-carousel)はVueアプリケーションでカルーセルを実現するためのライブラリです。
## 問題
カルーセルのpaginetionのmargin-topが広すぎるので狭くしたいと考えました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/4bde2474-7e1f-7fc1-205d-230a23c5bf50.png)

先人の記事を検索してみるとDev toolsでクラスを特定してそれをセレクタにしてスタイルを適用すれば良いとのこと。
それに倣ってDev toolsで対象部分のクラスを特定してstyleタグの中で以下のように記載しましたが、反映されません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/df83bf1b-a90d-dbc4-4d98-8f2ecb3e31ca.png)

```css
.VueCarousel-dot-container{
  margin-top: 0px;
}
```

Dev toolsで適用されているスタイルを確認するとセレクタが`element.style`と、タグ内にベタ書きされており、そちらが優先されているようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/cf131723-2d09-6217-4d6a-ba45abf79591.png)

## ソースを見てみる
[本家リポジトリ](https://github.com/SSENSE/vue-carousel)のコードを見てみます。
該当部分は[Pagination.vue](https://github.com/SSENSE/vue-carousel/blob/master/src/Pagination.vue)ですね。styleがバインドされているようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/c7a19e69-190a-3bb8-a1e1-1b1f4ac4835d.png)
dotContainerStyleを見てみます。ありました！margin-topです。どうやらcarousel.paginationPaddingによって動的に設定されるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/d21dd3ec-e1fa-49dc-5bb8-9558589002dc.png)

carouselはPagination.vueにinjectされており、[Carousel.vue](https://github.com/SSENSE/vue-carousel/blob/master/src/Carousel.vue)を指しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/5c397dbe-0af7-ac8d-05f0-856bb0620141.png)


Carousel.vueでpaginationPaddingを探します。Propsの中にありました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/eb3eec01-a5b5-5126-ea97-a83f5bbbc23c.png)

つまりpaginationPadding propsに対して数値を与えて上げるとその２倍の数値がVueCarousel-dot-containerのmargin-topになるんですね。

```html
<carousel :paginationPadding="5">
  <slide v-for="imageUrl in imageUrls" :key="imageUrl">
    <img :src="imageUrl" class="w-full h-full">
  </slide>
</carousel>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149212/764010c9-3850-9aa7-c722-c9f12aa75524.png)



## まとめ
paddingとmarginが連動するなんて考えもしなかったでござる。
【TypeScript】返却値と変数の型指定について【React】

## はじめに
　本記事は、プログラミング初学者が、学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。
　そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。
　間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。

##返却値と変数の型指定について

###返却値の型指定
ReactにおいてTypeScriptを用い、返却値の型を指定するには以下のように記述します。


```Sample.tsx
import React from 'react';

export const Sample = () => {
  // `(num: number)`の後ろに`: number`とすることで型を指定
  const getTotalFee = (num: number): number => {
    const total = num * 1.1;
    return total;
    // 実行ボタンをクリックすると1100が返却される
  };

  // 以下の記述で数値以外を渡すようにするとエラーとなる
  const onClickSample = () => {
    console.log(getTotalFee(1000));
  };

  return (
    <>
      <p>返却値の型指定<p>
      <buton onClick={onClickSample}>実行</button>
    </>
  );
};
```


```App.tsx
import React from 'react';
import { Sample } from './Sample';
 
export default fanction App() {
  return (
      <Sample />
  );
} 
```

###変数の型指定
ReactにおいてTypeScriptを用い、変数の型を指定するには以下のように記述します。

```Sample.tsx
import React from 'react';

export const Sample = () => {
  const getTotalFee = (num: number) => {
    const total = num * 1.1;
    return total;
    // 実行ボタンをクリックすると1100が返却される
  };

  const onClickSample = () => {
    let total: number = 0;
    // totalに数値以外を代入するとエラーとなる
    total = getTotalFee(1000)
    console.log(total);
  };

  return (
    <>
      <p>変数の型指定<p>
      <buton onClick={onClickSample}>実行</button>
    </>
  );
};
```


```App.tsx
import React from 'react';
import { Sample } from './Sample';
 
export default fanction App() {
  return (
      <Sample />
  );
} 
```
Access denied for user 'root'@'localhost'と出た場合の対処法

rails sでブラウザを開いたときにエラーが発生。


<br>
・エラー内容
![2d42fad8fec8caa6dc24815ac636c909.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1962714/47240b6a-39bb-da8e-68d4-d721bb82a49d.png)


<br>
・原因
MySQL接続時のユーザーをきちんと指定できてない


<br>
・解決策
以下のように自分の環境におけるパスワードを設定します。

/config/database.yml

```
default: &default
  username: dbuser
  password: dbpass
```

非常に簡潔な内容でしたが以上でOKです。

<br>

開発環境
mac OS バージョン11.6

Rails 6.1.4.4
Ruby 3.0.0
MYSQL 0.5

エディタ
Cloud9
MBTiles ベースのベクトルタイルサーバを systemd でサービス化する

MBTiles ベースのベクトルタイルサーバを systemd でサービス化した際の作業の記録です。使用したのは Raspberry Pi OS です。

![social preview image](https://repository-images.githubusercontent.com/445690045/0fcd3cef-90e5-4bac-a30c-c6ddc684a6df)

## MBTiles ベースのベクトルタイルサーバ
https://github.com/optgeo/kagami/blob/main/serve.rb

```ruby
require './constants'
require 'sqlite3'
require 'sinatra'

DB = SQLite3::Database.new(PATH)

def get_tile(z, x, y)
  tile_row = 2 ** z.to_i - y.to_i - 1
  tile = DB.execute <<-EOS
SELECT tile_data FROM tiles WHERE \
zoom_level=#{z} AND tile_column=#{x} AND tile_row=#{tile_row}
  EOS
  tile[0] ? tile[0][0] : 404
end

get '/zxy/:z/:x/:y.pbf' do |z, x, y|
  content_type 'application/vnd.mapbox-vector-tile'
  response.headers['Content-Encoding'] = 'gzip'
  get_tile(z, x, y)
end
```

このプログラムを `rake host` で呼べるようにしています。

## systemd でサービス化するのに実行したコマンド
```zsh
sudo systemctl edit --force --full optgeo.kagami
sudo systemctl start optgeo.kagami
sudo systemctl status optgeo.kagami
sudo systemctl enable optgeo.kagami
```
上記第一行を実行すると、エディタが立ち上がるので、次のように入力しています。

```
[Unit]
Description = optgeo.kagami
After = basic.target

[Service]
Type = simple
ExecStart = bash -c 'cd /mnt/hdd/kagami; rake host'
Restart = always

[Install]
WantedBy = multi-user.target
```

`sudo systemctl enable optgeo.kagami` を実施した段階で、サービス化されるので、その後はリブートしたら自動的にベクトルタイルサーバが立ち上がることになります。

## 追記: nginx でリバースプロキシする
Raspberry Pi OS で nginx 使っている場合には、たとえば `/etc/nginx/sites-available/default` あたりで次の設定をして、`sudo nginx -s reload` すれば OK です。

location, proxy_pass が作業のキーワードになります。

```
server {
  listen 443 ssl http2;
  server_name ...;
  root ...;
  ssl_certificate /etc/letsencrypt/live/.../fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/.../privkey.pem;
  ssl_dhparam dhparam.pem;
  add_header Strict-Transport-Security "max-age=15768000; includeSubdomains";
  add_header Access-Control-Allow-Origin * always;
  location /kagami/zxy {
    proxy_pass http://localhost:8002/zxy;
  }
}
```

## 情報源
https://zenn.dev/tantan_tanuki/articles/7e619bd96e5fd9

ありがとうございます。
【Flutter】in_app_purchaseのrestorePurchasesメソッドをAndroidで使った場合の注意点

# はじめに
本記事は、Flutterの公式の課金ライブラリである [in_app_purchase](https://pub.dev/packages/in_app_purchase) の `restorePurchases` メソッドを、Androidで使った際のハマリポイントをご紹介します。

# `restorePurchases` メソッドとは :mag:

いわゆる「復元処理」の際に使えるメソッドで、未消費の課金データを取得できます。

https://github.com/flutter/plugins/blob/a5b97ea9b37283167968755387e6ee4cc5f268d1/packages/in_app_purchase/in_app_purchase/lib/in_app_purchase.dart#L208

Android側の実装は下記のところで行っています。

https://github.com/flutter/plugins/blob/a5b97ea9b37283167968755387e6ee4cc5f268d1/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform.dart#L178

ちらっと中身を見てみると、Androidで `BillingClient` を使ったことがある人は見たことがあるであろう `queryPurchases` が使われているだろうことがわかります。

```dart:in_app_purchase_android_platform.dart
// 138行目
responses = await Future.wait([
    billingClient.queryPurchases(SkuType.inapp),
    billingClient.queryPurchases(SkuType.subs)
]);
```


# ステータスが `PurchaseStatus.restored` に上書きされて返却される :warning:

そんな `restorePurchases` メソッドですが、意図的なのかバグなのかわかりませんが、通知される `PurchaseDetails`（購入情報のクラス）のステータスがすべて `restored` となっています。

↓ `status` に `PurchaseStatus.restored` を上書きしている箇所

https://github.com/flutter/plugins/blob/72dff1b4342676f3b4b6fc9a7fb810140dcf7477/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform.dart#L205

Androidの場合、消費アイテムの後払い購入が可能なため、 `restored` になっていると、

- **購入が成功したもの（ `purchased` ）が復元されたのか**
- **後払いのもの（ `pending` ）が復元されたのか**

が判断付かないことになってしまいます。

`in_app_purchase` の作り上、`restorePurchases` メソッドを呼んだ場合と、通常の購入フローで使う `buyConsumable` メソッドを呼んだ場合どちらも `purchaseStream` にイベントが流れてくるようになっているため、本来あるべきステータスで処理ができず問題になるケースもあるでしょう。

# InAppPurchaseAndroidPlatformAdditionの `queryPastPurchases` メソッドを使う :rocket: 
上記の問題を回避しつつ復元を行う場合、InAppPurchaseAndroidPlatformAdditionの `queryPastPurchases` メソッドが有効です。

https://github.com/flutter/plugins/blob/a5b97ea9b37283167968755387e6ee4cc5f268d1/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart#L72

コードを見てみるとわかりますが `restorePurchases` メソッドとほぼ同じようなコードになっています。
主な違いとしては、

- **ステータス（ `status` ）を上書きしていない（※ 重要）**
- **`QueryPurchaseDetailsResponse` を返却する**

というところでしょうか。

ステータスが上書きされていないので、購入が成功したもの（ `purchased` ）なら報酬の付与、後払いのもの（ `pending` ）ならその旨をUIで表示する、といった処理が可能となります。 :thumbsup: 

# まとめ
`restorePurchases` メソッドではステータスが `restored` に上書きされること、その代わりとして InAppPurchaseAndroidPlatformAdditionの `queryPastPurchases` メソッドが使えることをご紹介しました。

この記事がなにかの参考になれば幸いです。
Seleniumで複数のウィンドウハンドルを扱うときに現れるout of indexエラーを回避する方法

#はじめに
seleniumでウィンドウ切り替え時に生じるエラーに対する対処

#エラー内容
out of index
とか色々

#エラー原因
![.png](https://qiita-image-store.s3.amazonaws.com/0/365928/895627a2-c41f-38bf-f110-d7fbd010bd8f.png)
seleniumで新しいウィンドウを開いたときのフロー
ウィンドウを開いた順にハンドルを取得できればよいが, たまにランダムな順番にハンドルを取得する.

同様の報告が以下にされています.
[PythonでSelenium\_ウィンドウの切替え失敗とその対処について \- アウトプットして苦悩する](http://atc.hateblo.jp/entry/2018/08/07/%23_Python%E3%81%A7Selenium_%E3%82%A6%E3%82%A3%E3%83%B3%E3%83%89%E3%82%A6%E3%81%AE%E5%88%87%E6%9B%BF%E3%81%88%E5%A4%B1%E6%95%97%E3%81%A8%E3%81%9D%E3%81%AE%E5%AF%BE%E5%87%A6%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)

#対処
新しくウィンドウを開いたとき, window_handlesでウィンドウ情報をこれまでのウィンドウ情報リストに結合させ, 重複を消すようにしている. そうすると, ウィンドウを開いた順番にハンドルを取得できる. ウィンドウを閉じた際は連動してハンドルを消す必要があるのでご注意を.

```python
from selenium import webdriver

#対処後追加した関数
def controlled_handles(controlled_handles):
    all_handles = driver.window_handles
    controlled_handles.append(all_handles)
    controlled_handles = sorted(set(controlled_handles), 
                                key=controlled_handles.index)
    return controlled_handles

driver = webdriver.Ie(r"/path/to/IEDriverServer")
driver.get('http://www.something.com')
handles = driver.window_handles #対処後追加

#対処前
#all_handles = driver.window_handles
#driver.switch_to.window(all_handles[1])

#対処後
handles = controlled_handles(handles)
driver.switch_to.window(handles[1])
・
・
・
driver.quit()
controlled_handles.pop(-1) #対処後
```
#まとめ
ウィンドウを開いた順番にハンドルを取得させるようにしてエラーを回避した.
Maya Sketchfab Exporterを試してみた

# 背景

MayaからSketchfab向けにfbxをExportする場合に、Maya Sketchfab Exporterを使うと良いと書いてあったので、実際に試してみた、という趣旨の記事になります。

https://sketchfab.com/exporters/maya

# 環境

- Windows10
- Maya2022
- Maya Sketchfab Exporterv2.6

# ダウンロード

- Exporterのダウンロード
    - https://github.com/sketchfab/maya-exporter/releases/tag/v2.6

[Window]>[Settings/Preferences]>[Plug-in Manager]から、fbxmaya.bundle (Mac OS X) or fbxmaya.mll (Windows)があるか確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/ed8a83e9-aadc-67a1-ef9a-70586e84c1cb.png)

# 手順

- [Custom]>[Sketchfab Icon]をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/42e40fb6-77bb-6415-45d2-c33a9e9c7b99.png)

- 最初の場合は、[Settings]>[Sketchfab settings]を選択
    - API tokenを入力してSave
        - https://sketchfab.com/settings/password
        - ここからAPI tokenを取得
    - Tagは適当に入力
- 記入
    - Model name:
    - Description
    - Tags
    - Private (チェックおすすめ)
    - Publish immediately (チェック)
    - Upload to Sketchfabをクリック
    
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/bc607152-421f-c87c-8b6a-0208fb09a6c6.png)


# 無事Sketchfabに書き出しできました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/772f0a7a-1420-3cf7-d76f-ec6fec5c2590.png)

## 余談

Mayaからfbx書き出しとほぼ同じScaleとMeshになりました。Textureがどうなるかはまだ試していないです。
Googleフォームで送信されたデータを使いやすいJSONに変換する

Googleフォームで送信されたデータを、単純なJSONデータに変換するスクリプトです。フォームの「質問」をキーとして、回答をバリューとしたオブジェクトです。

```json:変換されたJSON
{
  "記述式は？": "記述式です。",
  "段落は？": "段落です。",
  "ラジオボタンは？": "ラジオボタン1",
  "チェックボックスは？": [
    "チェックボックス1"
  ],
  "プルダウンは？": "プルダウン1",
  "均等目盛は？": "1",
  "選択式（グリッド）は？": {
    "行1": "列1",
    "行2": null
  },
  "チェックボックス（グリッド）は？": {
    "行1": [
      "列1"
    ],
    "行2": null
  },
  "日付は？": "2022-02-03",
  "時刻は？": "22:00"
}
````

- `チェックボックス`の値は配列です。
- `選択式（グリッド）`は、行名をキー、列名をバリューとするオブジェクトです。
- `チェックボックス（グリッド）`は、行名をキー、列名の配列をバリューとするオブジェクトです。

スクリプトはこちらです。

```javascript
// 権限を付与するために一度だけ実行する。
function runOneTimeForAuthorization() {
  FormApp.getActiveForm();
}

function getRows_(item, type) {
  if (type === 'GRID') return item.asGridItem().getRows();
  if (type === 'CHECKBOX_GRID') return item.asCheckboxGridItem().getRows();
  throw 'invalid type: ' + type;
}

// フォーム送信時のトリガーとして登録しておく。
function onFormSubmit(e) {
  const items = {};
  e.response.getItemResponses().forEach(itemResponse => {
    const item = itemResponse.getItem();
    const response = itemResponse.getResponse();

    const type = item.getType().toString();
    if (type.includes('GRID')) {
      const rows = getRows_(item, type);
      const grid = {};
      for (let i = 0; i < rows.length; i++) {
        grid[rows[i]] = response[i];
      }
      items[item.getTitle()] = grid;
    } else {
      items[item.getTitle()] = response;
    }
  });
  // Google Workspace だとフォームを送信した人のメールアドレスを取得できる。
  handleResponse_(items, e.response.getEditResponseUrl(), e.response.getRespondentEmail());
}

// メイン処理。今回はログ出力するだけ。
function handleResponse_(items, url, email) {
  console.log(JSON.stringify(items, null, 2));
  console.log(url);
  console.log(email);
}
```

- `runOneTimeForAuthorization()`は、スクリプトエディター上で一度だけ実行します。そうしないと、権限が付与できずに、フォーム送信時のトリガーが失敗します。
- `onFormSubmit()`を、フォーム送信時のトリガーとして登録します。
- `handleResponse()`に、JSONを使った処理（例えばメール送信）を書きます。よく使うので、回答を編集するためのURLも取得しています（ただしフォームの設定で回答の編集を許可しておく必要があります。このURLを知っている人は誰でも回答を編集できるので注意してください）。Google Workspaceで作ったフォームだと、フォームを送信した人のメールアドレスを取得できます。

[FormApp](https://developers.google.com/apps-script/reference/forms/form-app)のデータ構造をすぐに忘れてしまうので作りました。ご自由にお使いください✨
【Ruby】条件演算子

※初心者向け
※アウトプット練習の為
※学習の復習

開発環境
rails 6.0.4.4
ruby 2.6.5


##問題内容
3桁の正の整数を入力します。その整数の「百の位・十の位・一の位の和」について、
10の倍数（0,10,20,30...）からの差が
・2以内であるときは"True"
・それ以外は"10の倍数との差は○です"
と表示されるようにしましょう。

**出力例：**
near_ten(117)→True
near_ten(123)→10の倍数との差は4です
near_ten(111)→10の倍数との差は3です
0も10の倍数に含むものとします。

百の位・十の位・一の位の和が6などの時に、「10の倍数との差は6です」と出力せずに、「10の倍数との差は4です」と10の倍数から近い方の差を出力するようにしてください。


##解答

```ruby
def near_ten(num)
  total = (num/100) + (num/10 % 10) + (num % 10)
  remainder = total % 10
  if remainder <= 2 || remainder >= 8
    puts "True"
  elsif remainder <= 5
    puts "10の倍数との差は#{remainder}です"
  else 
    puts "10の倍数との差は#{10 - remainder}です"
  end
end
```

**解説**
(num/100) + (num/10 % 10) + (num % 10)によって、百の位・十の位・一の位をそれぞれ足し合わせています。

num/100（百の位）
2桁の整数を100で割った値が百の位になります。
num = 117の場合、num/100 つまり117/100は1.17となります。
Rubyでは整数同士（integer型）の計算だと返り値は整数になるので、小数点以下は切り捨てられて「1」になります。
そのため、百の位の取得は、3桁の数字を100で割るだけで可能となります。
よって、百の位は「1」となります。

num/10 % 10（十の位）
2桁の整数を10で割り、その値を10で割った際の余りが十の位になります。
num = 117の場合、117/10は11.7になります。整数同士は小数点以下の計算は行わないので、11になります。
11 % 10 は、11を10で割った際の余りを計算結果として返します。百の位の計算と同様に、小数点以下の計算は行わないので、余りは1となります。
よって、十の位は「1」となります。

num % 10の場合（一の位）
2桁の整数を10で割った際の余りが一の位になります。
num = 117の場合、117 % 10 は、117を10で割った際の余りを計算結果として返します。百の位の計算と同様に、小数点以下の計算は行わないので、余りは7となります。
よって、一の位は「7」になります。

8行目のelseのポイントは、「百の位・十の位・一の位の和が6または7に該当する場合は、10から差し引いて、10の倍数との差分を導出する必要がある」という点です。
AWSとAzureの予約アドレスについて

#予約アドレスとは？
AWSやAzure側で利用する為あらかじめ確保されるプライベートアドレスです。
ユーザが設定を行わなくても自動で確保されます。
利用できず不思議に思った方もいるのではないでしょうか。
AWSもAzureもそれぞれに予約アドレスが存在します。
各サブネットCIDRブロックの最初のIPアドレス4つと最後のIPアドレスは使用できません。

#予約アドレス比較一覧

|    |  AWS  |  Azure  |
| ---- | ---- | ---- |
|  x.0  |  ネットワークアドレス  |  ネットワークアドレス  |
|  x.1  |  VPC ルーター用  |  デフォルトゲートウェイ  |
|  x.2  |  リゾルバ  |  予約  |
|  x.3  |  予約  |  予約  |
|  x.255  |  ブロードキャストアドレス<br> （VPCでは利用されない為予約） |  ブロードキャストアドレス  |


上記のように利用・予約されるようです。



####参考

[VPC とサブネット](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/VPC_Subnets.html)
[プライベート IP アドレス](https://docs.microsoft.com/ja-jp/azure/virtual-network/ip-services/private-ip-addresses)
[Azure仮想マシンのIPアドレスが勝手に変わる? ～その原因と対策を図解～](https://blog.trainocate.co.jp/blog/azure-ip)
大域脱出 (Non Local Exits) について調べた

Rubyの[timeout.timeoutのソースコード](https://github.com/ruby/ruby/blob/master/lib/timeout.rb#L36)に、[Kernel.catch](https://docs.ruby-lang.org/ja/latest/method/Kernel/m/catch.html) が使われていた。これはrubyで大域脱出するために使用されるメソッドである。

大域脱出について(恥ずかしながら)あまりよく知らなかったのでまとめた。


## 大域脱出とは

> 構造化プログラミングの考え方では、 goto 文のように、ブロック構造を無視して制御を移すのはよくないとされる。しかし、アルゴリズムによってはそういう書き方をしたい時もある。例えば、多くの言語では、 return 文を実行すると、繰り返しブロックの中であっても直ちに関数の実行を終了して呼び出し元へ戻る。
>
> 大域脱出(Non-local exits)は、それを一般化して、複数回の繰り返しや関数呼び出しが重なっていても、すべて終了して最初に設定したところまで戻る。

⏫[プログラミングドキュメント、制御構文](http://web.sfc.keio.ac.jp/~hattori/prog-theory/ja/7.html)より


## Pythonの場合

大域脱出は言語レベルでサポートされていない。
実装方法は例えば以下が考えられる。

(1) for-else構文を使用する

```python
for i in range(3):
    print("i = {}".format(i))
    for j in range(3):
        print("    j = {}".format(j))
        if (i, j) == (1, 2):
            break
    else:
        # for loopがbreakされることなく最後までiterateされた場合のみここが実行される
        continue
    break
```

(2) ループの箇所を関数に切り出し、大域脱出の代わりにreturnする

```python
def iterate_until(x, y):
    for i in range(3):
        print("i = {}".format(i))
        for j in range(3):
            print("    j = {}".format(j))
            if (i, j) == (x, y):
                return

iterate_until(2, 3)
```


(出力はいずれも以下)

```
i = 0
    j = 0
    j = 1
    j = 2
i = 1
    j = 0
    j = 1
    j = 2
```

</details>


## Rubyの場合

Rubyの場合、`Kernel.#catch`を用いて、catch-throwで大域脱出を行うことができる。
(例外処理のbegin-rescueとは別のもの。Javaだと、try-catchで例外処理なので混合しないこと)

ref. `module function Kernel.#catch`。
https://docs.ruby-lang.org/ja/latest/method/Kernel/m/catch.html

```ruby
result = catch do |tag|
  for i in 1..2
    for j in 1..2
      for k in 1..2
        throw tag, k
      end
    end
  end
end

p result #=> 1
```

なお、大域脱出は複数のメソッドコールを跨ぐことができる。


## 他の言語の場合

深ぼって調べていないが、ざっと関連記事のリンクを貼っておく。

- Javaは大域脱出の言語レベルでサポートされている(?)。ref. https://shoutm.hatenablog.com/entry/2013/01/02/205328
- Goは大域脱出の言語レベルでサポートされておらず(?)、panicを用いて大域脱出をするらしい。
EC2でRayクラスタ作成時にディレクトリをマウント

Rayクラスタ作成用コンフィグファイル（YAMLファイル）で、ファイルマウントの指定ができる。**但し、リモートマシン側（Rayクラスタを起動するマシン上）のディレクトリは`/home/ray`を指定することはできない。**なので`/home/ray/files`というように指定してあげる必要がある。

```yaml
file_mounts: {
#   "/path1/on/remote/machine": "/path1/on/local/machine",
    "/home/ray/files": "/home/hogehoge/ray"

}
```
EC2でRayクラスタ作成時に、Jupyter Notebookのパスワード設定

Rayクラスター用コンフィグyamlファイルの`head_setup_commands: `欄に以下の行を追加する。

```yaml:Rayクラスター用コンフィグ
# Custom commands that will be run on the head node after common setup.
head_setup_commands: 
    - sudo apt-get install -y python3 python3-pip
    - sudo pip3 install jupyter
    - sudo jupyter notebook --generate-config -y # パスワード設定用のコンフィグファイルを生成
    - echo "c.NotebookApp.password='sha1:***'" | sudo tee /home/ray/.jupyter/jupyter_notebook_config.py # コンフィグファイルにパスワードを設定。「sha1:***」がパスワード。teeコマンドにはsudo要
    - nohup sudo jupyter notebook --ip=* --port=8888 --allow-root >> jupyter.log 2>&1 & # Ray立ち上げ時にjupyter notebookが邪魔しないようにnohupでコマンドを実行し続けるようにする。「nohup ＜中略＞ >> jupyter.log 2>&1 &」が該当箇所。「--ip=*」は送信元IPを無制限、「--port=8888」はJupyterをポート8888番で利用、--allow-rootはsudoでの実行を許可、という意味。
    - sudo pip3 install awscli
```

これでJupyterログイン時にパスワードの入力を求められるようになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619163/dd128feb-b1a6-e0c7-47d7-1e7c5cd7bf55.png)

`sha1:***`の部分にはハッシュ値を入れる。下記コマンドでPython3を利用して任意の文字列からハッシュ値を生成できる。

```bash:ハッシュパスワード
$ python3 -c 'from notebook.auth import passwd;print(passwd())'
Enter password:
Verify password:
sha1:***********************************
```
Java SE8 Sliverの資格を取得して

#Java SE8 Sliverとは
 私は先日「Java SE8 Sliver」というOracle社が提供する、Javaの開発者向けの資格を取得した。このJava Silverとは、プログラミング言語Javaの技術レベルをOracle社が認定する資格で、正式名称は「Oracle Certified Java Programmer, Silver SE 8」である（ちなみにこのSE8はJavaのバージョンを指し、現在はSE8とSE11がある）。このJava Silverは中級者を対象としたものであるが、それ以外にも初級者向けのBronze、上級者向けのGoldなどがある。

　この「Oracle Certified Java Programmer」はJavaアプリケーション開発のためのプログラミング知識や、さまざまな状況への対応能力を有していることを客観的に証明できるものとなっている。つまり、このJava Silverと言う資格の取得にはプログラミングにおける「最低限動作可能な」コードだけでなく、「拡張性、可読性がともに高い」コーディング能力が求められるのである。

#取得までにかかった時間
 私がこの資格の取得のためにかかった時間は、おおよそ40〜50時間だった。しかし、これは前提としてJavaの知識がある程度ある前提でのものであるため、Java未経験者が一からこの資格を取るためには、それ以上の時間がかかると思われる（少なくとも計１００時間以上）。というのも、そもそもが開発者向けの資格であるため、Javaの特徴でもあるクラスやメソッドをある程度理解していないと話にならないのである。

#使用した教材
　私が使用した教材は、基本的には下記の２つである。

・黒本（徹底攻略Java SE 8 Silver問題集[1Z0-808]対応）
・紫本（オラクル認定資格教科書 Javaプログラマ Silver SE 8 ）

　これらの教材の使い分けとしては、黒本が教科書で紫本は参考書といったような形とした。その理由としては、黒本の内容が試験問題に準ずるものであるため、基本的に黒本を繰り返しやっていけばいいこと、またその黒本で用意されている問題の解説が充実しているため、分からない部分があっても基本的にそれを理解できれば問題ないことが挙げられる。ただそれでも分からなかった場合のみ、補足として紫本を使用していくといった形をとった。

#学習の進め方
　学習の進め方としては、基本的には黒本の内容を各章ごとに順番に繰り返していった。１週目は分からなかった問題に関して考え方の部分やポイントとなる部分をその問題の箇所に記入して、２週目以降に確認して思い出していきながら定着させていく方法をとった。その理由としては、この資格試験の出題傾向として、その性質上非常に細かい部分が問われるケースが多いため（変数やインスタンスの型など）、そういった見るべきポイントを正確に限られた時間で見れるようになるためには繰り返し行なっていくのが一番であると考えたため、こうした地道ながらも確実な方法をとった。
【bash】指定した範囲内から数字をランダムに取り出す

# 目的
bashでランダムに数字を取り出したかっただけです。

# コード
```bash
shuf -i 1-30 -n 1
```
`shuf`コマンドを使う。
`-i 1-30`で1~30までの範囲を指定。
`-n 1`で取り出す個数を1つに指定。

## 例
```bash
for i in $(seq 1 10); do
    NUM=`shuf -i 1-30 -n 1`
    echo $NUM
done
```
出力

```
4
20
23
1
28
11
3
24
22
12
```

# 終わりに
組み込み変数の`$RANDOM`を使うより分かりやすいですね。:kissing_cat:
もしもAWS CloudWatchLogsをKMS暗号化して、KMSキーを無効化したら


###はじめに
ご無沙汰です。
AWSでサポートに問合せた結果、AWS側で修正対応することになりましたのでメモ残しておきます。

###事象について
CloudWatchLogsのKMS暗号化方法については公式ドキュメントにあります。
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/encrypt-log-data-kms.html

公式ドキュメント通りステップ4まで実施して、結びつけたCMKを無効化すればログは見れないと思ってました。(復号化できないため)



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/645781/37f9fa07-97c3-43a0-d5f3-bded769b9c79.png)

だけどログ見えてるやん～～～てなってました。

###AWSサポートに問合せしてみた

```【問合せ】
【問合せ１】
ー中略ー
CloudWatch Logsのロググループに設定済みKMSキーを無効化しましたが、
CloudWatch Logs上でログに確認ができている状況です。
サポート側でも動作検証お願いします。
```

```【回答】
【回答１】
ー中略ー
CloudWatch Logsサービスの動作仕様として、結果整合性によりKMSキーを無効化してから、
その失効がロググループに適用されるまでに最大1時間かかる場合がある。
KMSキーの無効化から最大で1時間経過すると、当該キーで暗号化されたログイベントは表示されず、
また、そのKMSキーに関連付けられたロググループにログイベントを送信できなくなる。
1時間以上経過した後でも、引き続きログが取得できるようだったら教えてくれ！
```

###検証してみた
AWSサポートの回答通り、1時間待ってみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/645781/37f9fa07-97c3-43a0-d5f3-bded769b9c79.png)

まだログ見えてるよ～～～

###もう一回AWSサポートに問合せしてみる

```【問合せ】
【問合せ２】
再度KMSキーを無効化し、1時間以上経過しましたが
CloudTrailのログがCloudWatch Logs上で確認できる状況です。
CloudWatchLogsのマネジメントコンソール上ではKMSキーを無効化した場合でも
ログは確認可能なのでしょうか？
```

###～～～～３ヶ月後～～～～

```【回答】
【回答２】
ロググループに関連づけていたKMSキーを無効化した後も、
1時間を超えてログ出力(PutLogEventアクション)の実行と
直近のログイベントの確認が可能である場合があることが確認できた。
前伝えたのは確認不足で間違っていた！すまなかった！

また、担当部署にて上記の説明に従った動作、
(KMSキーを無効化してから1時間以内に失効がロググループへ適用される動作)となるよう、現在修正に取り組んでいる。
しかしながらこちらの修正の成否や時期については現時点でお伝えすることが叶わないことご了承ください。
```

結果的に修正してもらえるようです。

###KMSキーを無効化したらログは見えないのか

**結論なります。**
ただ時間がかかります。(3時間くらい経ったら取得不可になりました)
ちなみにKMSキーを有効化したら即時反映されました。

以下がエラーメッセージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/645781/80db5fe3-004a-248d-6444-74db57a670ca.png)

以上です。読んでいただきありがとうございました。
【 システム開発の種類3つ 】

転職活動中、業界の用語などに新しく出会うことも多く、忘れないために備忘録として書きます。

# そもそもシステム開発とは？
プログラミング言語を用いてシステムを開発すること。
そして、開発するシステムには`「オープン系」`、`「汎用系」`、`「Web系」`の3種類があります。
以下それぞれについて簡単にまとめました。

## オープン系
■`業務系アプリケーションを開発`
↪︎企業ごとの専門性を高め、様々なメーカーやOSなどのデバイスや各種機材を組み合わせて、様々なネットワークを活用してオーダーメイドで行う開発のこと。

使われる言語 : Unix / Linux / Java

## 汎用系
■`汎用機で使用するシステムを開発`
↪︎汎用機とは、大型のコンピュータのことです。1980年代ごろまではコンピュータと言えば、ほぼ汎用機のことを指していました。汎用機の使用には専門的な知識が必要です。
汎用機での開発は、金融機関や保険会社など大量のデータを扱う大規模なシステムに用いられています。

使われる言語 : COBOL(事務処理用に開発された言語)

##Web系
■`Webアプリケーションを開発`
↪︎ECサイトやSNSを主に開発。オープン系とは違い、さまざまなユーザーが訪れ、利用します。
そのため、高速処理な言語を用いる。

使われる言語 : PHP / Java / Javascript / Ruby

#まとめ
①`Web系とは、SNS等の一般人向けのシステム開発`
②`オープン系とは、企業向けのシステム開発`
③`汎用系とは、金融機関や保険会社のような大量のデータを扱う大規模なシステム開発`

以上、ざっくりとまとめてみました。
【1日10行コーディング】〜Google Map APIと向き合う〜

## 概要

### 1日10行コーディングとは

まず、1日10行コーディングというのは、1日10行でいいから新しいコード書こうよって感じのやつです(雑)
(1日1記事とか1機能とかだと続かない気がしてしまってる...)

### 実装するもの

最終的に作りたいのは自分でピンを立てた店のアイコンとかを自由に変えられたり、カテゴリごとにアイコン変えたりとかするものが作りたいという気持ち。Google Map my place??とかいうのに近いというか多分おんなじようなのになると思う。

ただ、今日はその前の前の前の前段階くらいのとりあえずマップを表示するページを作ろうと思います。

## 手順

https://www.javadrive.jp/google-maps-javascript/charset/
とりあえずこちらの手順を参考にAPIキーの取得とかをします。
資料古かったのでスクショとかは微妙にあてにならなかった。

1. Google Maps PlatformページのCreating API keys手順に従ってAPIキーを生成する。(https://developers.google.com/maps/documentation/javascript/get-api-key)

2. HTMLにすべてをベタ書きする

```html
<!DOCTYPE html>
<html lang="en">
<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>俺のいきつけ</title>
    <style>
        /* Set the size of the div element that contains the map */
            #map {
            height: 400px;
            /* The height is 400 pixels */
            width: 100%;
            /* The width is the width of the web page */
            }
    </style>
    <script>
        function initMap() {
            // The location of Uluru
            const uluru = { lat: -25.344, lng: 131.036 };
            // The map, centered at Uluru
            const map = new google.maps.Map(document.getElementById("map"), {
                zoom: 4,
                center: uluru,
            });
            // The marker, positioned at Uluru
            const marker = new google.maps.Marker({
                position: uluru,
                map: map,
            });
        }
    </script>
</head>
<body>
    <!--The div element for the map -->
    <div id="map"></div>

    <!-- Async script executes immediately and must be after any DOM elements used in callback. -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=APIキー&callback=initMap&libraries=&v=weekly"
      async
    ></script>
</body>
</html>
```

3. ブラウザで動作確認

![スクリーンショット 2022-02-03 21.28.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83409/ec3b1f71-d951-c455-4030-33b824ecface.png)
無事表示できた！

### ちょっと困ったこと

請求先みたいなのがないとちゃんと表示されないみたいだったからクレカの登録をしました。

終わり。
行列の転置と90°回転

行列$A$の転置と90°回転を求める。

```math
A = \begin{bmatrix}
1 & 2 & 3 \\
4 & 5 & 6 \\
7 & 8 & 9
\end{bmatrix}
```


```python
A = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
```


# 90°回転
結論

```python
rotate = lambda A: [list(x)[::-1] for x in zip(*A)] 

rotate(A) # [[7, 4, 1], [8, 5, 2], [9, 6, 3]]
```

# 転置
結論

```python
transpose = lambda A: [list(x) for x in zip(*A)]

transpose(A) # [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
```

# 結論
zipは便利
【mod_security】mod_securityの設定ファイルとログファイルの場所

#はじめに
EC2にApacheとmod_securityをインストールして、いろいろ動作確認しています。途中経過を記事にしていきますが、最後にきれいに記事にする予定です。

#mod_securityのログファイル
```
/var/log/httpd/modsec_audit.log
```

Apacheと連動して動作するので、/var/log/httpdに存在するのかも。

#mod_securityの設定ファイル
```
/etc/httpd/conf.d/mod_security.conf
```

#おわりに
今回は、これだけです。では、また。