OmniAICreator/Qiita-1.07M huggingface dataset:
なぜTypeScriptが流行っているのか？

- どんな人が使っている？　
  - JavaScript使える勢が多く使っている


- JSユーザーから見たメリット
  - 高度なオートコンプリート
  - リファクタリングしやすい
  - 大規模なプロジェクトに向いている
  - 型があると安全・安心
  - 学習コストが低い


- 時代にあっている
    - 「型を厳密に扱う」言語に対する関心が高まっている
    - Vue,ReactなどがTSサポートしだしている
    - いろんなエディターも対応している
    - Microsoft製なのでVSCodeで補完が強力
    - Nullable
[Rails6] Heroku上でCarrierwave(Rmagick) + fogを使いAWS S3にファイルをアップロードする

##最初に
HerokuでRailサイトを作る時ストレージを別途用意しなければなりません。
Herokuでは時間が立つとアップロードした画像ファイルなどが消えてしまうので
今回は対応策としてAWS S３を使います。
S3とAWSのアカウントは作成した前提ですのでまだ済んでいない方は以下を参照ください

S3の設定

https://qiita.com/miriwo/items/41e488b79fb58fa7c952

AWSアカウントの作成方法

https://miriwo.hatenablog.com/entry/2020/06/03/122128
##環境 
 Ruby 2.6.6
 Rails 6.0.3.6
 AWS S3の設定済
 Rmagick設定済
##Gem
Gemは以下を使います

```
gem "rmagick"
gem "carrierwave"
gem "fog-aws"
```

##モデル作成
画像をアップロードするモデルを作ります。
今回はユーザーに持たせるプロフィール画像を想定して作ります。

```
$ rails g model User name:string image:string

$ rails db:migrate
```

##Uploaderの設定
Uploaderクラスを作成します。 (Imageの所は好きに置き換えてください)

```
rails g uploader Image
```


作成されたら`image_uploder.rb`に以下を追加します。

```:app/uploaders/image_uploader.rb
include CarrierWave::RMagick
  
  if Rails.env.production?    
    storage :fog　　　　　　　　# 本番時にS3にファイルを保存する
  else
    storage :file             # 開発・テスト時にはローカルにファイルを保存する
  end

```

モデルとImageUploaderを関連付けるためにモデルに以下を追加します

```:app/models/user.rb
class User < ApplicationRecord
  mount_uploader :image, ImageUploader
end
```

##CarrierWaveの設定
Herokuで画像の保存先をAmazon S3に保存できるように設定する

```:config/initializers/carrierwave.rb
require 'carrierwave/storage/abstract'
require 'carrierwave/storage/file'
require 'carrierwave/storage/fog'

CarrierWave.configure do |config|
  if Rails.env.production?
    config.fog_provider = 'fog/aws'
    config.fog_credentials = {
      provider: 'AWS',
      aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'], #awsのIAMのアクセスキー
      aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],　#awsのIAMのシークレットアクセスキー
      region: 'ap-northeast-1' #バケットの作成で設定した地域(東京で設定した場合は左と一緒)
    }
    config.fog_directory = "ENV['AWS_BUCKET_NAME']" #バケット名
    config.cache_storage = :fog     # 本番時はS3にファイルを保存する
  else
    config.storage = :file          # 開発・テスト時はローカルにファイルを保存する
  end

end

```

##Herokuへの環境変数登録

```
$ heroku config:set AWS_ACCESS_KEY_ID="IAMのAccess key IDを入力"
$ heroku config:set AWS_SECRET_ACCESS_KEY="IAMのSecret access keyを入力"
$ heroku config:set AWS_S3_BUCKET="S3のバケット名を入力"
```
Herokuの環境変数の確認方法

```
$ heroku config
```
以上でHerokuにデプロイ後、画像を投稿してS3にバケット保存できました。
これで反映されない時はIAMのアクセスキーを再度発行して改めて環境変数を設定すると上手くいく場合もあるようです。

また今回は設定に1日中かかり、かなり試行錯誤して上手く実装することができました。

たくさん記事を見ましたので上手くいかない方は私が参照した記事も合わせて確認していただければと思います。

https://qiita.com/params_bird/items/dc2a3868f4a2caf0504c

https://qiita.com/newburu/items/e4c4a6242357c511c24c

https://qiita.com/yukiyukimiyaiwa/items/a9e0103c8342b81f6ac1
Amazon SNS の料金

[Amazon SNS の料金](https://aws.amazon.com/jp/sns/pricing/)

通常の使い方ではそれほど大きくならないところなので気にしないことも多いかもしれませんが、特に FIFO の料金、これを読んで理解できます？
僕はできませんでした。

## 共通の料金

具体的な料金は、すべて東京リージョンの2021年3月現在ののものです。

- Publish API リクエスト : 後述
- Publish 以外の API リクエスト : 100 万リクエストあたり 0.50 USD
- 配信 : 配信先の種別による。(ここではこの部分には触れません)

## Publish の料金

### 標準トピック

- 100 万リクエストあたり 0.50 USD
  - ペイロードが 64 KB を超える場合、64 KB ごとに 1 リクエストとしてカウントされる。
- Subscriber の数は関係ない。
- Publish 以外の API リクエストも含む最初の 100 万リクエストは無料。

![標準トピック料金](https://hirose-public.s3-ap-northeast-1.amazonaws.com/qiita/2021/04/15/ae2319d6-cdf7-4e3a-a220-7321b5dfaecb.png)

### FIFO トピック

FIFO トピックの場合は、Publish のリクエスト数だけでなく、そのトピックに対する Subscriber の数やペイロードデータ量に応じて加算した金額になります。Publish リクエスト自体の料金が標準トピックより安く見えますが、ペイロードデータのサイズや Subscriber の数に応じて高くつく計算。

- 100 万リクエストあたり 0.39 USD + (0.013 USD × Subscription 数)
  - ペイロードが 64 KB を超える場合でも、1 リクエストとしてカウントする。
- メッセージのペイロードデータ 1 GB あたり 0.0221 USD + (0.0013 USD × Subscription 数)
  - ペイロードデータのサイズは純粋に Publish した本文のサイズのみで、ヘッダ等は含まない。
  - Subscriber がフィルタリングポリシーを設定して受信するメッセージを絞っても、すべてのペイロードが課金対象となる。
- FIFO トピックへの Publish リクエストは、無料枠対象外。

![FIFO トピック料金](https://hirose-public.s3-ap-northeast-1.amazonaws.com/qiita/2021/04/15/c863aa25-6ac8-4e74-89f1-0068fc766088.png)

### 例

100 万回 Publish した場合の比較です。

|1 メッセージサイズ|Subscription 数|標準トピックの場合|FIFO トピックの場合|
|--:|--:|--:|--:|
|1 KB|1|0.50 USD|0.43 USD|
|1 KB|4|0.50 USD|0.47 USD|
|64 KB|1|0.50 USD|1.90 USD|
|64 KB|4|0.50 USD|2.19 USD|
|256 KB|1|2.00 USD|6.39 USD|
|256 KB|4|2.00 USD|7.43 USD|

※この他に、配信先によって配信料金およびデータ転送料金がかかります。
Google App Engine - デプロイ前に古いバージョンを削除する

（備忘メモ）

https://cloud.google.com/appengine/docs/standard/go/an-overview-of-app-engine#limits
1アプリケーション辺りバージョン数が非課金で15、課金ありで2１0を超えるとデプロイが失敗する為、CI(GitHub Actions)でデプロイ前に古いバージョンを削除する。

デプロイ前に件数が30件超えていたら直近デプロイ20件を残して削除する（Traficが割り当てられるものは除く）。

↓抜粋 （※gcloudのインストールや認証は割愛）

```yaml
jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest

    steps:
    (中略)
    - name: GAE delete old versions
      run: |
          ALL_NOTRAFIC_VERSIONS=$(gcloud app versions list --format="value(id)" --service=your_service --filter="traffic_split=0" --sort-by="~lastDeployedTime" --project=your_project)
          if test "$(echo "$ALL_NOTRAFIC_VERSIONS" | wc -l)" -gt 30; then
              DELETING_VERSIONS=$(echo "$ALL_NOTRAFIC_VERSIONS" |tail -n +21)
              gcloud app versions delete --quiet --project=your_project --service=your_service $(echo "$DELETING_VERSIONS")
          fi
```
Python3: A4 の PDF を A3 の PDF に変換

例えば 10ページの A4 の PDF を、５ページの A3 の PDF に変換します。

```py:pdf_a4_a3.py
#! /usr/bin/python3
#
#	pdf_a4_a3.py
#
#					Feb/1/2023
#
import  sys
import  PyPDF2
from PyPDF2 import Transformation
#
# ------------------------------------------------------------------
def pdf_merge_proc(pdf_reader1):
#	pages= pdf_reader1.getNumPages()
	pages= len(pdf_reader1.pages)
	nn_out = int((pages + 1) / 2)
	sys.stderr.write("pages = %d\n" % pages)
	sys.stderr.write("nn_out = %d\n" % nn_out)
#
	pdf_writer = PyPDF2.PdfWriter()
#
	for icount in range(nn_out):
		it = icount * 2
#		page_obj_a = pdf_reader1.getPage(it)
		page_obj_a = pdf_reader1.pages[it]


		page_obj_out = PyPDF2.PageObject.create_blank_page(width=1190, height=842)

		page_obj_out.merge_page(page_obj_a)

		jt = it + 1
		if jt < pages:
			page_obj_b = pdf_reader1.pages[jt]
			page_obj_b.add_transformation(Transformation().translate(595, 0));
			page_obj_out.merge_page(page_obj_b,expand=True);
#
		pdf_writer.add_page(page_obj_out)
#
	return pdf_writer
# ------------------------------------------------------------------
sys.stderr.write ("*** 開始 ***\n")
sys.stderr.write("PyPDF2.__version__ = %s\n" % PyPDF2.__version__)
pdf_in = sys.argv[1]
pdf_out = sys.argv[2]
#
pdf_file_in = open(pdf_in, 'rb')
pdf_reader1 = PyPDF2.PdfReader(pdf_file_in)
#
pdf_writer = pdf_merge_proc(pdf_reader1)
#
pdf_output_file = open(pdf_out, 'wb')
pdf_writer.write(pdf_output_file)
pdf_output_file.close()
pdf_file_in.close()
#
sys.stderr.write ("*** 終了 ***\n")
# ------------------------------------------------------------------
```

実行方法

```bash
./pdf_a4_a3.py file_a4_in.pdf file_a3_out.pdf
```

次のバージョンで確認しました。

```text
$ python --version
Python 3.10.7
```

```text
>>> import  PyPDF2
>>> PyPDF2.__version__
'3.0.1'
```

参考ページ
[Python3: A4 の PDF をマージして A3 にする](https://qiita.com/ekzemplaro/items/1dc2c0e191c158a468f0)
クロージャとは

#■クロージャ

クロージャとは、再利用可能なひとまとまりの処理です。
関数はクロージャの一種なので共通の部分がる。
関数ではfuncが必要だったり関数名がひつようだが
クロージャではオリジナルの書き方がある

へーーー
っでなんなのよこいつ！!!!!!


簡単に言うと
関数の中に関数を入れれる！ってのを短くかける
てきな感じ！


つまりどう言うこと？

まずはクロージャなしである関数を書いてみる！
あるbの関数をaの関数の中にいれたい

#■Int型のデータ2つを足し算した値を返すメソッドがあるとする。

``` swift
func a(n1:Int,n2:Int) ->  Int {
       return n1 + n2
}

a(n1: 2, n2: 3) 　結果　5
```




#■aメソッドの中身の足し算をかけ算にしたいとする。

引数で数字はカスタマイズできるけど
演算子は変えられへん。

つまり演算子変えたいだけやのにまた新しくメソッド作らあかん
長くなりそう…

``` swift
func b(no1:Int, no2:Int) -> Int {

         return no1 * no2
}

b(no1:2,no2:3)　 結果　6
```

できた！

このbのメソッドがやってる事はInt型2つを引数にしてreturnの結果を返り値Int型に持たせてる。

#■bメソッドをaメソッドに入れ込みたいとする。
つまり関数の中に関数を入れたい！

bメソッドを引数に渡したいから
同じ式のデータ型を作る。

こんな感じ

dメソッドのやってる事をデータ型に

```
(Int,Int) -> Int
```

よしこれを入れ込もう!
#■引数の3個目としてaメソッドに(Int,Int) -> Intを入れる。

``` swift
func a(n1:Int, n2:Int, opelation:(Int,Int) ->Int ) -> Int {

//3個目の引数の中身をn1,n2がInt型やから入れ込んでreturnで返す。
     return opelation(n1,n2)
}

func b(no1:Int, no2:Int) -> Int {

         return no1 * no2
}

//3引数にdメソッドの関数名入れる。
a(n1:2, n2: 3, d)

結果   6
```

やりたいのはこれ！
これをクロージャ使ったら短くなる。




#■クロージャの式
普通の関数をちょっと改造
消す物
>func
関数名

■{を先頭に持ってきて代わりにinを記入

```
{ (引数名:データ型,引数名:データ型) -> Int in 
    　　return 返したい結果
}
```


#■bメソッドをクロージャにすると
直接bメソッドクロージャをaメソッドに入れれるようになる。

``` swift
//これがクロージャ前
func b(no1:Int, no2:Int) -> Int {

         return no1 * no2
}

//クロージャ後
 {(no1:Int, no2:Int) -> Int in
         return no1 * no2
}

```

#■bメソッドクロージャをaメソッドに入れる。
結果は同じ6が返る

``` swift
a(n1:2, n2:3 , operation:{(no1:Int, no2:Int) -> Int in
         return no1 * no2
})

結果　6
```
これをどんどん短くかける。

#■短くしていこう型推論を使えばデータ型表示いらんくなる。

まずこちらのreturnをご覧ください
return opelationの中身はn1とn2です。
n1のデータ型はInt
n2もデータ型はInt型です。
returnで返してるデータ型が3っつめの引数と合致してるので
表示するまでもないでしょてきな感じ
ついでに3引数で返り値もIntって書いてるので省略できる。

``` swift
func a(n1:Int, n2:Int, opelation:(Int,Int) ->Int ) -> Int {

     return opelation(n1,n2)
}

 //省略したクロージャを入れ込む
a(n1:2, n2:3 , operation:{(no1, no2) in
         return no1 * no2
})
```

#■ついでにreturnも省略できる。
短いぞ！いい感じ！

``` swift
a(n1:2, n2:3 , operation:{(no1, no2) in
   no1 * no2
})
```

#■でももっともっと短くできる!!
(このパターンはあんまり使われないらしいです。短すぎて他の人見た時何してるか分かりづらいから)

クロージャの第一引数を　ドル0とする
クロージャの第二引数を　ドル1とする

``` swift
a(n1:2, n2:3 , operation:{(no1, no2) in
   no1 * no2
})

//$0と$1を使うとめっちゃ省略できる

a(n1:2, n2:3 , operation:{$0 * $1})

//もはやoperationと言う引数名も省略パターン
a(n1:2, n2:3 ){$0 * $1})

```
省略しすぎて分かりづらいらしい。
#■ちょうどいい省略はこんな感じらしい

``` swift
//よく見かける感じかと
a(n1:2, n2:3 ){(no1, no2) in
   no1 * no2
}
```


#■まとめ

これがクロージャ前

``` swift
func a(n1:Int, n2:Int, opelation:(Int,Int) ->Int ) -> Int {

//3個目の引数の中身をn1,n2がInt型やから入れ込んでreturnで返す。
     return opelation(n1,n2)
}


func b(no1:Int, no2:Int) -> Int {

         return no1 * no2
}

a(n1:2, n2: 3, d)

結果  6
```

■これがクロージャ後

``` swift
func a(n1:Int, n2:Int, opelation:(Int,Int) ->Int ) -> Int {
     return opelation(n1,n2)
}

a(n1:2, n2: 3){(no1, no2) in
    no1 * no2
}

結果  6
```

簡単に言うと
関数の中に関数を入れる時短くできるよーー!!!
これがクロージャ
Dockerのhttp_proxyで詰まった話

# 概要
proxy環境下でdockerを使うために設定をしていたとき、`http_proxy`,`https_proxy`がどうしても上手く読み込めてなかったので何をして何が原因で何をしたのかをここに残す。

# 設定時
DockerはLinuxシステムの環境変数にある`http_proxy`や`https_proxy`とは別に、専用のproxy設定を施す必要がある。
なので[このサイト](https://docs.docker.jp/config/daemon/systemd.html)を参考に設定をした。
そのときのconfファイルの設定内容はこんな感じ。(実際の接続先URLは載せるわけにはいかないので、例として架空のurlを用いる)

```shell:/etc/systemd/system/docker.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://aaaa:admin!@example.ad.jp:8080"
```

のように書き込んだ。
これで`docker pull イメージ名`を実行したところ以下のようなエラーが出力された。

```
Error response from daemon: Get https://registry-1.docker.io/v2/: proxyconnect tcp: dial tcp: lookup https on xxx.xxx.xxx.xxx:xx: no such host
```

# 解決策
`http://aaaa:admin!@example.ad.jp:8080`の`!`をURLエンコードしてやればよい。
どうやらLinuxにおいて`!(エクスクラメーションマーク)`は特別な意味を持つ記号で、通常の`'(シングルクォーテーション)`を用いたエスケープが効かないそうだ。

※`¥(円マーク)`でエスケープはできたがURLにそのまま残ってしまう↓

```
http://aaaa:admin¥!@example.ad.jp:8080
```

↑この場合PWの一部として円マークが認識されてしまう
※参考ページ: [bashに !' で event no found と怒られた理由を考えてみる - https://qiita.com/Qutjl/items/6e0056853c94011d245b](https://qiita.com/Qutjl/items/6e0056853c94011d245b)

URLなので`%21`のようにエンコードすればどうにかなるんじゃねと思い、やってみたところできてたっぽい
（この時上記に関係ないエラーが発生して、それを勘違いして最初はこの方法でもできてないと思った）
↓URLエンコードバージョン

```shell:/etc/systemd/system/docker.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://aaaa:admin%21@example.ad.jp:8080"
```

ちなみに`docker info`を実行することでDockerに関する情報が出力される。先ほどのProxy設定情報も出力される。

```shell
[root@hogehoge ~]# docker info
~中略~
HTTP Proxy: http://xxxxx:xxxxx@example.ad.jp:8080
HTTPS Proxy: https://xxxxx:xxxxx@example.ad.jp:8080
~中略~
```

エスケープしても上のように`username@password`が伏字になってしまうことがある。
しかし`systemctl show docker --property Environment`でProxy設定情報を確認すると

```shell
Environment=HTTP_PROXY=http://aaaa:admin%21@example.ad.jp:8080 HTTPS_PROXY=https://aaaa:admin%21@example.ad.jp:8080
```

このようにエクスクラメーションマークがエスケープされて登録されていることがわかる。
なぜ伏字になるのかは不明。
# 余談
上にも書いたが、URLエンコードで対応してもエラーが発生した。このエラーは以下のようなものだった

```
Get https://registry-1.docker.io/v2/: proxyconnect tcp: tls: first record does not look like a TLS handshake
```

上手くTLSのコネクションがはれていないのかなと思いググってみた。
すると以下のページに答えが載っていた。
[VagrantをProxy経由で利用する - https://qiita.com/daichannel/items/08e074a01e8ab41d52f7#docker](https://qiita.com/daichannel/items/08e074a01e8ab41d52f7#docker)

単純に`HTTPS_PROXY`に設定するURLのスキームを`http`にすれば良いだけだった。
（なぜhttpsではダメなのかは不明。これでいいのか感が否めない・・・）

```shell:/etc/systemd/system/docker.service.d/https-proxy.conf
[Service]
Environment="HTTPS_PROXY=http://aaaa:admin%21@example.ad.jp:8080"
```

# 余談2
今回は通常のURLエンコードでどうにかなったが、場合によっては`%`を2回続けないと反映されないらしい。
上記の`https-proxy.conf`を例にすると

```shell:/etc/systemd/system/docker.service.d/https-proxy.conf
[Service]
Environment="HTTPS_PROXY=http://aaaa:admin%%21@example.ad.jp:8080"
```

このようにエクスクラメーションマークを変換する際は`%%21`と%を2回続けると上手くいくこともあるらしい。
どうやらsystemctlでは**%ダブル**で`$`や`%`などの特殊文字をエスケープしているらしい(?)

参考ページ:https://forums.docker.com/t/proxy-settings-do-not-work-for-either-etc-default-docker-or-systemd-drop-ins/68891/17

# 結論
systemctlのconfファイルに用いる`!`はLinuxにおける通常のエスケープ方法が効かないことがわかった。
Linuxシステムにおいて`!`は扱いが特殊なので、そもそもURLなどに混ぜるべきではないと思った。
PHPのエラーを表示する

サーバによっては設定でエラーが表示されないようになっていることがある。
エラーを表示させるには以下のコードを追加する。

```php:コード
ini_set('display_errors', "On");
```

```php:使用例
<?php

// エラーを出力する
ini_set('display_errors', "On");

$a=1000;
$b=0;
 
$c=$a/$b; //０で割っているのでエラーが出る
```
Azure AD のグループ ベースライセンスって便利

#この記事について
ライセンスの割り当てについてよく耳にするようになったので、グループベース ライセンスの管理について簡単にまとめてみた。

#グループベース ライセンスって何？
Office365 のライセンスは、ユーザー単位なのでユーザー個々に割り当てる必要があるが、数百人から数千人になると大変。
また、ライセンスの中には Exchange、SharePoint、Teams など多くの製品が含まれており、管理方法によっては、部署や業務内容で割り当てたくないサービスがあったりもする。

グループ ベース ライセンスを利用すると、Azure AD 上のグループ (AADC で同期したグループもOK) にライセンスを割り当てることができ、割り当て時に一部のサービスを無効にするとかもできるので、管理が容易になる。

###要件
・Azure AD Premium P1 以上の有料または試用版のサブスクリプション
・Office 365 Enterprise E3、Office 365 A3、Office 365 GCC G3、Office 365 E3 for GCCH、Office 365 E3 for DOD 以上の有料または試用版のエディション

詳細は以下。
https://docs.microsoft.com/ja-jp/azure/active-directory/fundamentals/active-directory-licensing-whatis-azure-portal#licensing-requirements


#手順
####1. Azure AD に管理者アカウントでサインインし、[ライセンス] をクリック。
以下から直接アクセスも可能。
https://aad.portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/Licenses

>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1307699/cb111cef-0d14-ce9b-1822-aa7efd9b7d33.png)


###2. [すべての製品] をクリック。
>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1307699/90ea3354-689d-4e4f-94ae-97495d9a453a.png)

任意のライセンスをクリックすると、現時点で割り当てられているユーザーなどが確認できる。
>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1307699/83475780-65be-ae07-aa55-41ccd72f99bf.png)

###3. 割り当てたいライセンス (ここでは Microsoft365 E5) のチェックボックスをON にして [+ 割り当て] をクリック。
>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1307699/b7e0c9a7-358e-868a-e1d6-0379665b86c5.png)

###4. 割り当て対象となるグループを指定する。
>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1307699/94caa74b-e168-862a-c412-47079e38a576.png)

###5. [割り当てオプション] をクリックし、必要に応じて割り当てるサービスを選択する。
>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1307699/dea951f2-c5c6-ac39-707e-601dce80d592.png)

###6. [レビューと割り当て] をクリックし、内容問題なければ [割り当て] をクリック。
処理が完了すると、画面右上に以下のようなポップアップ表示がでる。
>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1307699/76f9c9d7-8627-85c8-45a8-1a40c58620c7.png)


#割り当てられた結果
しばらくすると、対象のライセンスをクリックすることで割り当て状態を確認できる。
赤枠の通り、割り当てパスが "直接" ではなく "継承済み" となりグループ名も表示される。 
>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1307699/87dfe22d-249e-5493-ab4f-00751ef45378.png)


#ライセンスの付け替えも可能
付与するライセンスを変更 (E3 --> E5 など) にも対応可能。
ここでは M365 E5 から O365 E5 に変更してみる。
>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1307699/00a4bd88-1193-a490-73bf-321e7e9b865a.png)

結果が以下。
>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1307699/f9e5b187-eed0-66b9-ac27-ae820218f12a.png)
Q6.[Crypto] Classical Cipher

問題文から暗号文を3文字ずつずらすとflagがえられることが分かる。

>f → e → d → c
>s → r → q → p
>d → c → b → a
>z → y → x → w

手動でもできるが、与えられた暗号文が長いと面倒なのでプログラムを作る

```
CRYPT = "fsdz{Fdhvdu_flskhu_lv_fodvvlfdo_flskhu}"   # 暗号文
SHIFT = 3                                           # ずらす文字数

plain = ""

for letter in CRYPT:
  lcode = ord(letter)
  if "A" <= letter and letter <= "Z":
    lcode = (lcode - SHIFT - ord("A")) %26 + ord("A") 
  elif "a" <= letter and letter <= "z":
    lcode = (lcode - SHIFT - ord("a")) %26 + ord("a")
  else:
    lcode = lcode

  plain += chr(lcode)

print(plain)
```

上記コードを実行するとflagが得られる
**cpaw{Caesar_cipher_is_classical_cipher}**

<br>
ーーーーーーーーーーーーーー
↓全問Writeup執筆(予定)
[CpawCTF Writeup](https://qiita.com/parsley_irodori/items/bebde41ce1305d1edcd4)
苦しんで覚えるC言語（苦C）を読んだので、勉強になったページを記録しておく。

<h1>前提</h1>
**筆者**
筆者は、文系卒新人SEです。所属会社が開発側ではなく発注側になるため、プログラマではなく上流を主に担当しています。学生時代はプログラミングのプの字も知らなかったため、下流工程を全く知らないまま上流工程をやる羽目になった、というケースです。

**学習状況**
ExcelのVBAで簡単なツールを作った経験があります。
一般的なプログラミング言語を未履修のため、汎用性のあるプログラミング言語のいろはを学びたい、と考えています。

**学習目的**
「何か今すぐアプリを作れるようになる」ことよりも「プログラミングという概念の基礎を学ぶ」ことが主眼です。プログラミングにできることとできないことの境界線を把握したいです。「この作業はプログラマさんに依頼可能なのか？」を自力で判断できることが、直近の業務課題だからです。

Qiitaを書く理由は、アウトプットの練習です。

<h1>誰に向けて？</h1>
プログラミングがわからない！ けれどプログラマさんに指示を出さなきゃいけない！ という人に向けています。いるかどうか分かりませんが、私がそうなので。

あとはプログラミングするよりも、プログラミングというものの基礎ロジックを知りたい、という奇特な趣味を持っている方にも向けています。私がそうなので。

<h1>やること</h1>
苦しんで覚えるC言語（通称、苦C）というサイトが初心者向け、かつ原理的な部分から詳しく説明してくれている、と聞いたので読みます。

http://9cguide.appspot.com/index.html

復習用に、読んでいて役に立った内容をメモとして残します。

<h1>8進数と16進数の表記</h1>

社内の古いソフトで、こんな感じの命名を見たことがありまして、なんだろうなと不思議に思っていました。

>先頭に0をつけた数は、8進数として扱われます。
>例えば、0152､027､0756､030303 などは8進数です。

あとこれも。

>意外に良く使われるのが16進数で、これは先頭に 0x をつけて表します。
>例えば、0xFF､0xA7､0x912C､0xABCD などは16進数です。

10進数じゃないことを示す記号だったんですね。

<h1>浮動小数点方式</h1>

>浮動小数点方式
>実数値を、数値の並び(仮数部)と、小数点の位置(指数部)で表す方法。
>仮数部に、10の何乗などの値を掛け算して実数を表現する。
>巨大な数から極小の数まで扱え便利だが、計算は遅い。

名前だけ聞いたことがありました。整数の組み合わせで実数を表示できて便利、ということなんですね。

<h1>プロトタイプ宣言</h1>

これの話です。

>`#include`の正体
>実は、今まで使用してきた`printf`関数などのプロトタイプ宣言は、毎回先頭に書いていた、`stdio.h`ファイルの中に書かれていたのです。
>これが、`#include <stdio.h>`を書く最大の理由です。

デフォルトで使える関数、というものが一般化できたので、個人的にすごく腑に落ちた話なのですが、関数は基本的にすべて宣言をしなきゃいけなくて、それを`#include<*>`でやっていた、ということなんですね。
「最初から使えるよ」という謳い文句は、初心者にはなにやってるのか分からなくて応用きかせられないから苦手なんですが、ひとつ説明が見つかってありがたかったです。

<h1>char型</h1>
引用は省略して、要点は次の2つです。

1. C言語では、STRING型（文字を格納できるデータ型）は存在しない。
2. 半角1文字のみ格納できるCHAR型が存在するので、これを組み合わせて文字列処理を行う。

文字コードが決まっている（Aは68、Bは69など）ので、足し引きで処理できてしまう、というのが盲点でした。そりゃ文字を処理するにも数字に変換しなきゃいけないので、言われたらその通りなのですが、「AをBにする」という処理が「文字コードに1を足す」と読み替えられるんですね。

<h1>配列のメモリ割り当て</h1>

こういう原理的な話が知りたかったのでウキウキしながら読みました。

>実は、ここに、配列のトリックの全てが暴かれています。
>実は配列名は、配列の最初の要素のアドレスを表していたのです。
>各要素を参照する時に、[0],[1] と言った要素番号をつけましたが、この意味は、配列名のアドレス+要素番号のメモリを参照するという意味になるのです。

配列、なにも特殊なことはしていないんですね。
それと、配列のサイズを決めるというのは割り当てメモリの範囲を指定しているのと同義であることも分かりました。なるほど。

ついでと言ってはなんですが、アドレスの話が先にあったので「ポインタ」という概念がスムーズに理解できました。C言語未履修なので難しいと言われてもよくわかっていないのですが、それはそれ。

<h1>値渡しと参照渡し</h1>
VBAでプロシージャの話をすると、必ず出てきて説明のなかった「値渡し（ByVal）」と「参照渡し（ByRef）」の説明がありました。
説明が分かりにくいんで、噛み砕いてみます。
前提として、<b>変数</b>には「1.データが保存されているアドレス」と「2.保存されている数値」の2つの情報があります。関数に引数を渡すときに、変数を渡したいとして、1.と2.のどっちを渡すか、という違いが、値渡しと参照渡しの違いです。
簡単にいうと、直接保存されている数値を渡すのが「値渡し」で、アドレスを引数で渡して、受け取った側の関数がそのアドレスを覗いて数値を取得するのが「参照渡し」というわけです。
たぶん。

C言語には参照渡し機能はないとのことですが、ポインタを使うことで、理屈上は同じ処理が可能になっているということでした。C言語くらいしかポインタという概念が使われていない（表に出てこない）というのは、その他言語では、参照渡し機能が基本登載されているという意味というわけですね。

<h1>終わりに</h1>
アウトプットは大事、みたいな雑な感想で締めたいと思います。2章以降が全部読み切れていないので、書き足すかもしれないです。
連想配列について

初心者の方は連想配列（辞書的配列）を学ぶと「どこで使うんだろう」と思われる方が多いと思います。
今回はPHPを例にどこで使われているかの一例を紹介いたします。

```PHP
<?php
	// データベースからデータを取得する
	$sql = "SELECT id,date,text FROM mental ORDER BY id desc;";
	$stmt = $pdo->prepare($sql);
	$stmt -> execute();
	?>
	<table>
		<tr>
			<th>id</th>
			<th>日時</th>
			<th>メンタルの状態</th>
		</tr>
		<!-- HTMLテーブルの2行目以降で全てのレコードを表示 -->
        <?php while ($row = $stmt -> fetch(PDO::FETCH_ASSOC)) { ?>
            <tr>
                <td><?= $row["id"] ?></td>
                <td><?= $row["date"] ?></td>
                <td><?= $row["text"] ?></td>
            </tr>
        <?php } ?>
```

今回のサンプルは例外処理部分をカットしたものを掲載しています。実際作成したものは例外処理が入っています。こんな感じで使います。

SELECT文のカラム名が「*」だったのでカラム名をコーディングするように変更いたしました。
ある環境でstd::chronoが遅い

## 概要

CentOS7 + devtoolsetの環境だとstd::chronoが遅い。

これが本当にdevtoolsetが原因かは私には分からず。。



## やりたかったこと

C++コードの開発におけるベンチマークでは時間計測が重要です。これまでOpenMPやMPIで並列化したコードを作るときには、`omp_get_wtime()`や`MPI_Wtime()`関数で時間計測をしていました。しかし、開発したコードの運用は様々な環境で使うことを想定すると、OpenMPやMPIの使えない(使わない)環境でのコンパイルもできるようにすると思います。その時に、時間計測の関数もディレクティブで切り替えていました。もちろんラップした関数にしたりしますが。

C++11以降で`std::chrono`が登場し、HPC環境でも普及してきたので、これらの時間計測関数を`high_resolution_clock`で置き換えて統一したくなります。

しかし、実際にやってみると`std::chrono::high_resolution_clock`は1桁遅い。原因は`devtoolset`と予測していますが、私では特定できませんでした。情報共有の意味で記事にします。原因や思い当たる節のある方は情報提供いただけると嬉しいです。

## 問題の出る環境
CPU: Intel Xeon Gold 6248, and E5-1620 (実機確認の取れたもの)
CentOS 7 (3.10.0-1127.19.1.el7.x86_64)
devtoolset-9
g++(gcc) 9.3.1
icpc(icc) 2021.1

## 検証コード

以下のコードで時間計測を行います。
主にtimer呼び出しのコストを測っています。

```c++
#include <iostream>
#include <cstdlib>
#include <chrono>
#include <omp.h>

int main()
{
    using namespace std::chrono;
    constexpr int COUNT = 10000;
    
    //time by openmp
    double time_omp = 0.0;
    for(int i = 0; i < COUNT; ++i){
        double prev = omp_get_wtime();
        time_omp += omp_get_wtime() - prev;
    }    
    std::cout << "omp: " << (time_omp * 1.0e3) << "[ms]" << std::endl;
    
    //time by std::chrono    
    high_resolution_clock::duration time_chrono{high_resolution_clock::duration{0}};
    for(int i = 0; i < COUNT; ++i){
        auto prev = high_resolution_clock::now();
        time_chrono += high_resolution_clock::now() - prev;
    }    
    std::cout << "std::chrono: " << ((double)std::chrono::duration_cast<std::chrono::nanoseconds>(time_chrono).count() * 1.0e-6) << "[ms]" << std::endl;
    
}
```

## 計測結果

コンパイルオプションと実行結果は以下の通り

```
# CentOS7 + devtoolset-9(実機),
# icpc -qopenmp -O2
omp: 0.216007[ms]
std::chrono: 3.11031[ms]

# CentOS7 + devtoolset-9(実機),
# g++ -fopenmp -O2
omp: 0.26315[ms]
std::chrono: 3.14209[ms]

# Windows10 x64, Core-i7 10710U
# MSVC (Visual Studio 16.9.1) オプション割愛
omp: 0.1645[ms]
std::chrono: 0.1413[ms]

# Wandbox + gcc7.2.0
# g++ prog.cc -Wall -Wextra -O2 -march=native -I/opt/wandbox/boost-1.73.0/gcc-7.2.0/include -std=gnu++17 "-fopenmp"
omp: 0.428464[ms]
std::chrono: 0.366112[ms]
```

このようにCentOS7 + devtoolsetの環境だけ`std::chrono`が異常に遅い。

## さいごに

CentOS+devtoolsetの環境はそれなりに多いと思うので、他にも悩んでいる方はいそうな気がします。解決策などの情報提供があればとても嬉しいです。

## 解決策(追記：2021/4/20)
コメント欄にて @gnaggnoyil さんからの情報提供で解決策が見いだせました。
コンパイル引数に`-static-libstdc++`をつければdevtoolset環境でも新しいlibstdc++をリンクできるそうです。
g++だけでなくicpcでも有効です。
以下にテスト結果を示します。

```
# CentOS7 + devtoolset-9(実機),
#g++ -O2 -fopenmp
std::chrono: 3.09057[ms]
clock_gettime(CLOCK_REALTIME): 0.150057[ms]

# g++ -O2 -fopenmp -static-libstdc++
std::chrono: 0.166714[ms]
clock_gettime(CLOCK_REALTIME): 0.150091[ms]

# icpc -O2 -fopenmp
std::chrono: 3.11476[ms]
clock_gettime(CLOCK_REALTIME): 0.154761[ms]

# icpc -O2 -fopenmp -static-libstdc++
std::chrono: 0.166713[ms]
clock_gettime(CLOCK_REALTIME): 0.163851[ms]
```

やったね！
ShangriLa Anime APIを使ってみた

#はじめに
ShangriLa Anime APIを使ってみたので簡単な使い方と紹介をしたいと思います。
僕がJavaScriptを学習中にAPIを使ってみたいなと思い、どうせなら自分の好きなアニメ関係のAPIがないかと探していたら見つけました。
あくまで簡単な説明なので詳しい情報は[こちら](https://github.com/Project-ShangriLa/sora-playframework-scala)の本家様のgitで確認いただけたらと思います。

###使用しているもの
 - JavaScript
 - [ShangriLa Anime API](https://github.com/Project-ShangriLa/sora-playframework-scala)

#ShangriLa Anime APIとは
簡潔に言えばアニメの情報が受け取れるAPIです。
2014年から現在までの放送しているアニメのデータを年号別、季節別に指定して受け取ることができます。

###受け取れるデータ
 - アニメのタイトル
 - アニメ公式URL
 - Twitterアカウント
 
　 等々
他にもいろいろなデータが受け取れるので様々な使い道がありそうです。

###データ形式
```
[
 { "id": 1, "title": アニメタイトル1}
 { "id": 2, "title": アニメタイトル2}
 { "id": 3, "title": アニメタイトル3}
                .
                .
                .
]
```


#使用例

###2021年のアニメデータを受け取ってみる

```javascript
 //変数apiUrlに入れてるのがapiデータを受け取るURLになります
 const apiUrl = "http://api.moemoe.tokyo/anime/v1/master/2021";

    fetch(apiUrl)
    .then(response => {
        return response.json();
    })
    .then(data => {
        console.log(data);
    })
```
これで2021年のアニメデータが受け取れます
2020年のデータが欲しければURLの最後の2021のところを2020に変えてあげるだけで受け取れます。


###2021年の冬アニメのデータを受け取ってみる

```javascript
const apiUrl = "http://api.moemoe.tokyo/anime/v1/master/2021/1";


    fetch(apiUrl)
    .then(response => {
        return response.json();
    })
    .then(data => {
        console.log(data);
    })
```
指定してあげるURLの最後に /1 を入れてあげるだけですね。

|冬  |春  |夏  |秋  |
|---|---|---|---|
|1  |2  |3  |4  |
この表に書いてある通りの番号と季節が対応しています。
春にしたかったら 2 夏がよかったら 3 を入れてあげると受け取れます。

ちなみに、当たり前なのかもしれませんが
2021年のデータを受け取る時は

```
const apiUrl = "http://api.moemoe.tokyo/anime/v1/master/2021/";
```
にすると取得できません

```
const apiUrl = "http://api.moemoe.tokyo/anime/v1/master/2021";
```
/ をちゃんと消して上げないと取得できないので、僕と同じ勉強途中というかたはお気をつけて

僕はこのAPIを使ったアプリを作っているときにこれに苦しめられた模様、、、
buttonを使って受け取るデータを変えたい時とかね。

###2021年冬アニメのタイトル情報を受け取ってみる
上の二つは全てのデータを受け取っていましたが、最後にタイトルデータだけを受け取ってみます。



```javascript
const apiUrl = "http://api.moemoe.tokyo/anime/v1/master/2021/1";

    fetch(apiUrl)
    .then(response => {
        return response.json();
    })
    .then(data => {
//[]の中には受け取りたい配列の番号
        console.log(data[].title);
    })
```

受け取っていたdataの後ろに.titleとしてあげるとタイトルデータを受け取れます。
配列の番号を指定してあげないとタイトルデータだけを受け取ることはできないので、全てのタイトルデータを受け取りたい時はfor文とかを使って受け取る必要があります。

他にも受け取れるデータに書いたアニメの公式ホームページやらTwitterやらのデータも受け取ることができます。

季節まで指定してあげないと title　しか受け取れないみたいなので公式ホームページURLとかのデータを受け取りたい人は季節まで指定してあげてください。

#最後に
初心者の方や勉強中の方でもなるべくわかりやすいように書いたつもりですので,apiを使ってみたいなと思ってる方はぜひ使ってみてください。
特にアニメが好きな人は使ってて楽しいと思いますよ〜。
FlutterでFirebaseを使わずにプッシュ通知を実装したい

例えばiOSアプリをFlutterに移植する場合など、プッシュ通知の仕組みにFirebaseを採用していないことがあります。

基本的にFlutterではプッシュ通知を実装する場合にはFirebaseを利用するのが一般的で
情報を調べてもFirebaseMessagingを利用した方法以外見つからなかったのでそれ以外の方法を使った実装方法をメモしておきます。

Androidの場合はFirebaseを使ってください。
`Platform.isIOS`などを使って処理を切り分けると良いです。

## 記事の対象
iOSアプリなどでプッシュ通知を実装したことがあり、基本的なセットアップは理解している方

## flutter_apns
FireaseMessagingをベースに作成されたflutter_apnsを使います。

https://pub.dev/packages/flutter_apns

基本的に上記URLのREADMEを参照すれば実装できます。
`connector.configure`などは`main.dart`の`runApp`より前に呼べば大丈夫です。

### トークンの取得
flutter_apnsではtokenのパラメータが`ValueNotifier<String>`で定義されています。
なので、`connector.configure`などの初期設定と同時に以下のように処理すれば取得できます。

```dart
connector.token.addListener(() async {
    final deviceToken = connector.token.value;
    print("receive token: $deviceToken");
});
```

また、任意のタイミングで使いたい場合は以下のように記述してnullでなければ利用可能です。

```dart
final token = connector.token.value.toString();
```

### プッシュ通知受信時の処理
メモ程度に書いておくと、以下のような状態に対応しています。

**onResume**
アプリがバックグラウンドで起動中に受信した通知をタップしてForegroundに移動

**onMessage**
アプリが起動中にプッシュ通知を受信

**onLaunch**
アプリがタスクからも終了されているときに受信したプッシュ通知からアプリを起動

#### onLaunchを実装するときの注意
onLaunchはネイティブアプリと違ってmain.dartの**runAppより前に**処理が実行されます。
そのため、プッシュ通知のパラメータを受信してそのまま画面遷移を行ってしまうと
ルーティングが前後してしまうことがあります。 

受信したパラメータを一時保管し、任意のタイミングで利用するなどをおすすめします。
OFのアドオンofxShadertoyのかなり重要な修正（ShadertoyのC++へのポーティング）

***OFのアドオンofxShadertoyのかなり重要な修正***

openframeworksでShadertoyのコードで記述されたシェーダーを表示するためのアドオン
ofxShadertoyがある。https://github.com/tiagosr/ofxShadertoy
Tiago Rezendes氏によるものだが、2019年9月26日のバージョンで、その後、まだ
バージョンアップされていない。現在のShadertoyと完全互換でないため、Shadertoy.comに投稿されているシェーダーのすべてがopenframeworksで表示できるわけではない。
@quittardis もこれまで、以下のように、いくつか現行バージョンの近づける改良を試みているが、

https://qiita.com/quittardis/items/8cfdac9d7e560aa1cf02

https://qiita.com/quittardis/items/c12f137e8b8c5ab46913






今回は、Shadertoyの最大の特徴であるマルチパスシェーダー間のA,B,C,Dバッファを使った数値データ渡しの問題を扱う。
 現バージョンのofxshadertoyでは、たとえば、以下のコードは正常に表示できない。
https://shadertoy.com/view/4dcGW2


![out000028.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/288a0247-37b4-1034-83b7-5677eb13529d.png)　（↑　openframeworksで表示）


 また、下記リンクのシェーダーは表示できるが、キー操作でカメラを移動させようとしても
値が0.0-1.0の範囲でしか渡せないので、途中で移動が止まってしまう。
　
https://www.shadertoy.com/view/WldfW4

![out000040.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/b852b282-eb2b-db2d-ae6b-2e882b19d102.png)　（↑　openframeworksで表示）


　現行のofxshadertoyでは、バッファの数値が0.0-1.0になるが、Shadertoyでは、それ以上、あるいは以下のfloat値が渡せる。画像のバッファなので、0.0-1.0で十分なのだが、内部で保持される値が8ビットだと、256段階しか表せないので、floatの値の受け渡しには不十分である。内部の値をGL_RGBA32Fの指定で、23ビットにすることによってバッファ間にカメラの位置やマウスの位置などの値を渡すことができる。
  
***Buffer precisionを23bitにする***

以下のコードは、Shadertoy.cpp内のBufferAを作成するコードだが、


```
bool ofxShadertoy::makeBufferA(std::string const & text, ofTexture & outTexture) {
	if (!text.empty() && makeShader(text, bufAShader)) {
		bufAFbo.allocate(dimensions.x, dimensions.y);
		outTexture = bufAFbo.getTextureReference(0);
		return true;
	}
	else {
		if (bufAFbo.isAllocated()) {
			//bufAFbo.destroy();
			bufAFbo.clear();
		}
	}
	return false;
}

```

これを以下のように変更するか、追加する。

```
bool ofxShadertoy::makeBufferA(std::string const & text, ofFbo & outTexture) {
	if (!text.empty() && makeShader(text, bufAShader)) {
		bufAFbo.allocate(dimensions.x, dimensions.y, GL_RGBA32F);
		//outTexture = bufAFbo.getTextureReference(0);
		outTexture = bufAFbo;
		return true;
	}
	else {
		if (bufAFbo.isAllocated()) {
			//bufAFbo.destroy();
			bufAFbo.clear();
		}
	}
	return false;
}

```
変更箇所は、
 bufAFbo.allocate(dimensions.x, dimensions.y);　→　 bufAFbo.allocate(dimensions.x, dimensions.y, GL_RGBA32F);
で、"***GL_RGB32F***" を追加して、内部のデータを***float***で持つようにする。

以上の変更をA以外のB,C,Dバッファに関しても修正する。

***OF本体側の修正***
openframeworks側では、

shadertoy.makeBufferA2(shaderString, ***テクスチャ***);
->
shadertoy.makeBufferA2(shaderString, ***フレームバッファ****);

のように変更する。

この変更を加えた、https://www.shadertoy.com/view/WscyRM
のコードを実行し、以下のようにBuffer precisionが23bitsになれば、任意のfloat値を
Buffer間で受け渡しできる。
![out000019.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/c35e30ef-4e51-efc7-7fc0-3af7020e6629.png)

　上の図で、上記の変更を行っていない場合、Buffer precision:　は0になる。
RasPi4 購入先リスト

# まとめ
RaspberryPi4 8GBの価格と購入先の調査。
2021/04/15 調査

| サイト | 価格(円)+送料 | URL |
|:-:|:-:|:-:|
| DigiKey  | 8859 + 0 |https://www.digikey.jp/product-detail/ja/raspberry-pi/RASPBERRY-PI-4-MODEL-B-8G/1690-RASPBERRYPI4MODELB8G-ND/12159401|
| RS  | 9188 + 0 |https://jp.rs-online.com/web/p/raspberry-pi/1822098/|
| KSY  | 9185 + 550 |https://raspberry-pi.ksyic.com/|
| SwitchScience  | 10304 + 0 |https://www.switch-science.com/catalog/6370/|
| Amazon(LEOCOM) | 9100 + 0  |https://www.amazon.co.jp/%E6%AD%A3%E8%A6%8F%E4%BB%A3%E7%90%86%E5%BA%97%E5%95%86%E5%93%81-Raspberry-Model-element14%E8%A3%BD-%E6%8A%80%E9%81%A9%E3%83%9E%E3%83%BC%E3%82%AF%E5%85%A5/dp/B0891RC99L/ref=pd_lpo_147_t_2/355-8460749-6440508?_encoding=UTF8&pd_rd_i=B0891RC99L&pd_rd_r=c9a803a6-c261-479e-ac7d-219c4f4360c3&pd_rd_w=ywYu7&pd_rd_wg=VDL2F&pf_rd_p=43793539-bb55-42ca-a906-e224e71aa7fd&pf_rd_r=PBWEDH1TB4G95Q64YTS5&psc=1&refRID=PBWEDH1TB4G95Q64YTS5|


DigiKeyは10000円未満の注文の場合は日本の消費税は払わなくてよいので、最安で購入できますね。
SPSS ModelerでDb2の外部表経由でICOSのCSVデータを読む

安価なクラウド・ストレージであるICOS上のCSVをSPSS Modelerで読む実験をしました。
ICOSはSQL Queryという機能でSQLアクセスを可能にしていますが、SPSS ModelerではSQL Queryを今のところ（2021/4月現在）はサポートしていないのでDb2の外部表経由で読むこととします。

■テスト環境
Modeler 18.2.2
Db2 Warehouse on Cloud
IBM Cloud Object Storage

#1.外部表を読む
ModelerからDb2上に定義された外部表経由でICOS上のCSVを読みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/528f33df-8df9-7704-1c91-affb8c101792.png)

ICOS上のCSVファイルのDb2の外部表は以下の手順で作成できます。

https://qiita.com/kawada2017/items/8a0bbddd10aba11efec3

SPSSのDBインポートのノードで参照すると通常のユーザーテーブルとして参照できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/add2054e-f39c-f43e-e10e-994a52ba597f.png)

SQLプッシュバックも可能でした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/22f09bfa-ef78-77f2-c906-80a50bae94dd.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/a714306a-2eb6-a839-1824-b7b352b417c3.png)


#2.外部表を含むUNION ALL VIEWを読む
ModelerからDb2上に定義された外部表を含むUNION ALL VIEWを読みます。
これによってアーカイブしたCSVとロードした最新データを透過的にアクセスできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/ad9d9c8a-2b60-4dcc-31c5-4cc48d3288fd.png)


外部表を含むUNION ALL VIEWはは以下の手順で作成できます。

https://qiita.com/kawada2017/items/a653fa7c5d745db510bf

SPSSのDBインポートのノードで参照すると通常のビューとして参照できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/42b978b7-0a7e-b933-003c-dde2aaec7f80.png)

やはり、SQLプッシュバックも可能でした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/5a65fe4a-645d-0e84-0469-597bd84afaad.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/6737fbed-e7e6-1efc-5614-2a7680c4aebd.png)

#3.外部表から実表をつくる。
最後に外部表から実表を作ってみます。
外部表のままだとパフォーマンスが悪い場合にRDBにテーブルとしてコピーするという方法です。RDBの容量を圧迫しないためにも必要な部分に絞ってコピーするのがよいでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/a41260ad-4f3a-ce81-f0c3-6d0439eb3a7d.png)

ICOS上のCSVからロードするのはDB管理者にお願いしなければならないことが多いと思いますが、外部表であれば、Modelerだけでコピーが可能です。

以下のように外部表をDBインポートノードで読んで、DBエクスポートノードで実表に書き出します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/7a11bd4c-5446-d931-19db-65f54ea199cc.png)

以下のようにCREATE TABLE文とINSERT-SELECT文が実行されて、外部表から実表へのコピーが作れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/74cd3967-a038-05d5-cfb2-a8d95ade32ee.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/a701a7ca-86f4-9ce3-ae0d-1bc672d8751e.png)
JavaScriptでの複数キー入力受付

## はじめに
ブラウザ上で動くゲームを作りたい！という時に必要になる、複数キー入力受け付けコードサンプルです。備忘録として載せておきます。

##コード
controllerを連想配列として用意しているのはキーの同時押し等に柔軟に対応するためです。

```javascript:controller.js
const controller = {};

const showController = () => {
    const elem = document.getElementById("debug-controller");
    let controllerStr = "";
    Object.keys(controller).forEach(key => {
        controllerStr += `${key}:${controller[key]} \n`;
    });
    elem.innerText = controllerStr
}

document.addEventListener('keydown', (event) => {
    console.log(`keydown:${event.code}`);
    controller[event.code] = true;
    showController();
});

document.addEventListener('keyup', (event) => {
    console.log(`keyup:${event.code}`);
    controller[event.code] = false;
    showController();
});
```

```html:controller.html
<!DOCTYPE html>
<html>

<head>
    <title>アクションゲーム-controller-</title>
    <script src="/static/js/controller.js"></script>
</head>

<body>
    <h1>キーの状態が表示されます</h1>
    <div id="debug-controller"></div>
</body>

</html>
```

実際に動かしたサンプルサイトは[こちら](https://action--game.web.app/game/controller.html)

後はsetInterval等でフレームごとにcontrollerを参照すればゲームを作ることができると思います。

## 解説
document.addEventListener()でキー入力の受け付けを行っています。("keydown"がキーが押された時、"keyup"がキーから指が離れたときになります)

## 追記(2021/04/15)
コメントでevent.keyよりもevent.codeを使ったほうが良いとのご指摘を受け、該当部分を修正しました、ありがとうございます！
R/Shiny + leaflet で地図上にマップキーとメモを書く

# はじめに

R/Shiny + leaflet で地図上にメモを残す機能を実装してみた。実装したのは以下の機能。
- マップ上を選択すると、キーが一時的に配置。
- 置きたい位置で [Place] を押すと、置いたキーの緯度経度をテーブルに登録。
- 表示されるモーダルにメモを記入し、モーダルの [OK] を押すとメモ付きのキーが固定。
- キーを選択すると、ポップアップにメモを表示。
- キーを選択して、[Delete] を押すと削除。

# ソースコード

具体的なコードは以下。

```r:mapkey.R
library(shiny)
library(leaflet)
library(leaflet.extras2)

ui <- fluidPage(
  leafletOutput(outputId="map", height="400"),
  actionButton(inputId="place", label="Place"),
  actionButton(inputId="delete", label="Delete"),
  tableOutput(outputId="table")
)

server <- function(input, output, session){
  r <- reactiveValues(
    i=0,
    id=NULL,
    lat=NULL,
    lng=NULL)
  
  ### Map display
  output$map <- renderLeaflet(expr={
    leaflet() %>% addTiles() %>% setView(lng=135, lat=35, zoom=9)
  })

  ### Place a marker temporarily
  observeEvent(
    eventExpr=input$map_click,
    handlerExpr={
      leafletProxy(mapId="map", session=session) %>%
        clearShapes() %>%
        addMapkeyMarkers(lng=input$map_click$lng, lat=input$map_click$lat, layerId = "marker")
    }
  )
    
  ### Fix a marker and write memorandum
  observeEvent(
    eventExpr=input$place,
    handlerExpr={
      r$i <- r$i + 1 # marker id
      r$lat <- append(r$lat, input$map_click$lat)
      r$lng <- append(r$lng, input$map_click$lng)
      r$table <- data.frame(r$lat, r$lng)
      r$table$index <- c(1:r$i) # rownames(r$table)
      
      output$table <- renderTable(expr={
        r$table
      })
      
      showModal(
        ui = modalDialog(
          textInput(inputId="content", label="Message:"),
          footer = actionButton(inputId = "set_content", label = "OK"),
          easyClose = TRUE
        )
      )
    }
  )
  
  ### Remove modal when clicking "OK" button
  observeEvent(
    eventExpr=input$set_content,
    handlerExpr={
      leafletProxy(mapId="map", session=session) %>%
        addMarkers(lng=r$lng, lat=r$lat, layerId=sprintf("%d", as.integer(r$i)), popup=r$content())
      removeModal()
    }
  )
  
  ### Getting marker id which is selected
  observeEvent(
    eventExpr=input$map_marker_click,
    handlerExpr={
      r$id <- input$map_marker_click$id
      # p <- input$map_marker_click
      # print(p)
    }
  )
  
  ### Delete a marker when clicking "Delete" button
  observeEvent(
    eventExpr=input$delete,
    handlerExpr={
      leafletProxy(mapId="map", session=session) %>% 
        removeMarker(layerId = r$id)
      r$id <- NULL
      r$lat <- NULL
      r$lng <- NULL
    }
  )
  
  
}

shinyApp(ui, server)
```

上記を実行した結果が以下の GIF のようになる。簡易的に作成したため修正点は多々あるが、ここまでとする。

![mapkey.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769545/b98c2167-ca4a-8b6c-2c2f-7e6b65ebffc9.gif)
GitHub Pages を使ってサイトを公開する方法

# Github Pagesとは
GitHub公式ページによると、
`GitHub Pages` は、GitHubのリポジトリから HTML、CSS、および JavaScript ファイル を直接取得し、任意でビルドプロセスを通じてファイルを実行し、ウェブサイトを公開できる静的なサイトホスティングサービスです。
PHP、Ruby、Python などのサーバーサイド言語はサポートしていません。

与えられるURLは，
`http://アカウント名.github.io/リポジトリ名`
となります。

# Github上で新しいリポジトリを作成する
Github上で新しいリポジトリを作成します。

わからない方は以下の記事で確認できます。
[リポジトリの作成方法](https://qiita.com/momo1010/items/87d8762792cb57b88efb)

ここでは、公開するリポジトリ名は、 `mysite` とします。

# Githubへローカルリポジトリをプッシュする
公開したいファイルをローカルPCで作ります。

コマンドラインを開いて、そのファイルがあるディレクトリまで移動して以下を実行すると、ローカルリポジトリからリモートリポジトリへプッシュが完了します。

```
git init
git add 追加するファイル名
git commit -m "コミットメッセージ"
git remote add origin https://github.com/アカウント名/mysite.git
git push origin master
```

# Github Pagesの設定をする
先ほどGithub上で作成したリポジトリへ移動し、 `Setting` → `GitHub Pages` に移動します。そして　`Source` の中を `None` から　`master branch` に変更します。

これにより、 `https://[ユーザー名].github.io/mysite/` のURLで公開することができました。
もし、エラーが発生した際は、 `https://[ユーザー名].github.io/mysite/ファイル名` のURLで公開されています。

公開されるまでに少し時間がかかる場合があります。
【Pandas】データベーステーブル読込み時のメモリエラーを回避する

※"データベース" とはPostgreSQL（またはAmazon RedShift）を指しています。

# TLDR

pyscopg2のサーバーサイドカーソルを併用してデータを読み込んでいく必要がある。
（※PostgreSQL限定）

サーバーサイドカーソル、クライアントサイドカーソルについては下記記事が大変参考になる。
[PythonとDB: DBIのcursorを理解する](https://qiita.com/knoguchi/items/3d5631505b3f08fa37cc)

# 事象

pandasでは、一度にメモリに乗り切らない巨大なデータを一定量ごとに読み込んで逐次処理するための`chunksize`オプションが用意されている。

しかし、巨大なDBテーブルの読み込みに`chunksize`を指定してもメモリエラーが発生するケースがあった。

```python
>>> import pandas as pd
>>> engine = get_engine()

# 10,000行テーブルの読込み(成功)
>>> small_df = pd.read_sql_table('small-table', con=engine)
>>> len(small_df)
10000

# chunksize を指定して10,000,000行のテーブル読込み(失敗)
>>> large_df = pd.read_sql_table('large-table', con=engine, chunksize=10000)
$ Killed  # メモリエラーで強制終了
```

# 解決方法

psycopg2の名前付きカーソル(= サーバーサイドカーソル)を使用する。

```python
import psycopg2
import pandas as pd

def get_psycopg2_connection():
    ...

con = get_psycopg2_connection()

# サーバーサイドカーソルの定義
cursor = con.cursor('large-table-cursor')
cursor.execute('SELECT * FROM "larget-table" ;')

while True:
    rows = cursor.fetchmany(10000)
    if len(rows) == 0:
        break

    # カラム一覧を取得
    columns = [desc.name for desc in cursor.description]

    # データフレームに格納
    df = pd.DataFrame(rows, columns=columns)

con.close()
```

# 備考

`read_sql_table`/`read_sql_query`関数では`chunksize`を指定してもクライアントサイドカーソルが使われていると思われる（ソースコードレベルでの確証なし）。

Amazon RedShiftのドキュメントによると、巨大なテーブルに対してカーソルを使用することは推奨されていない。
※結果セットを一時的にリーダーノードに保持するため

参考: [カーソルを使用するときのパフォーマンスに関する考慮事項](https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/declare.html#declare-performance)
RSpec単体テストコードのexpected [] to includeの解決方法

RSpec単体テストコードのときたまにこのようなエラーを起こしてしまうことがある。

```:ターミナル
Failures:

  1) ShippingAddress 配送先の情報として、郵便番号が必須であること
     Failure/Error: expect(@userpurchases.errors.full_messages). to include ("Post code can't be blank")
       expected [] to include "Post code can't be blank"
     # ./spec/models/shipping_address_spec.rb:12:in `block (2 levels) in <top (required)>'

  2) ShippingAddress 配送先の情報として、都道府県が必須であること
     Failure/Error: expect(@userpurchases.errors.full_messages). to include ("Prefecture_id can't be blank")
       expected [] to include "Prefecture_id can't be blank"
     # ./spec/models/shipping_address_spec.rb:18:in `block (2 levels) in <top (required)>'

  3) ShippingAddress 配送先の情報として、市区町村が必須であること
     Failure/Error: expect(@userpurchases.errors.full_messages). to include ("Municipality can't be blank")
       expected [] to include "Municipality can't be blank"
     # ./spec/models/shipping_address_spec.rb:23:in `block (2 levels) in <top (required)>'

  4) ShippingAddress 配送先の情報として、番地が必須であること
     Failure/Error: expect(@userpurchases.errors.full_messages). to include ("Address can't be blank")
       expected [] to include "Address can't be blank"
     # ./spec/models/shipping_address_spec.rb:28:in `block (2 levels) in <top (required)>'

  5) ShippingAddress 配送先の情報として、電話番号が必須であること
     Failure/Error: expect(@userpurchases.errors.full_messages). to include ("Phone_number can't be blank")
       expected [] to include "Phone_number can't be blank"
     # ./spec/models/shipping_address_spec.rb:33:in `block (2 levels) in <top (required)>'
```



expected[]to includeというエラーが出ており要するにうまくデータを持ってこれていない。
原因としてはdescribeの記述や各exampleのモデル名が間違っている可能性がある。
単体テストコードはモデルファイルのバリデーションがうまく機能しているかどうかのテストなのでモデルファイルと同じ記述にする必要がある。

```ruby
RSpec.describe UserPurchases, type: :model do
  before do
    @user_purchases = FactoryBot.build(:user_purchases)
  end

  it '配送先の情報として、郵便番号が必須であること' do
    @user_purchases.post_code = nil
    @user_purchases.valid?
    expect(@user_purchases.errors.full_messages). to include ("Post code can't be blank")
  end
  it '配送先の情報として、都道府県が必須であること' do
    @user_purchases.prefecture_id = 0
    @user_purchases.valid?
    expect(@user_purchases.errors.full_messages). to include ("Address is invalid. Include hyphen(-)")
  end
  it '配送先の情報として、市区町村が必須であること' do
    @user_purchases.municipality = nil
    @user_purchases.valid?
    expect(@user_purchases.errors.full_messages). to include ("Municipality can't be blank")
  end
  it '配送先の情報として、番地が必須であること' do
    @user_purchases.address = nil
    @user_purchases.valid?
    expect(@user_purchases.errors.full_messages). to include ("Address can't be blank")
  end
  it '配送先の情報として、電話番号が必須であること' do
    @user_purchases.phone_number = nil
    @user_purchases.valid?
    expect(@user_purchases.errors.full_messages). to include ( "Phone number can't be blank")
```


この場合テストしたいモデルファイル名はuser_purchases.rbなので
RSpec.describe UserPurchasesとし、
モデル名を@user_purchasesに変更した。
データを取れていない場合は大抵このような理由が多いようだ。
kali linux 2021.1を日本語化する。

##インストールできたらまずは日本語化
kali linuxをインストールできたらまずは日本語化しましょう。

使用環境
ホストOS：Mac
仮想化：VirtualBox
仮想OS：kali linux 2021.1

##流れとやること
ログイン
↓
ターミナルを開く
↓
１．日本語化関連のパッケージをインストール
２．日本語表示にする
３．キーボードを日本語のやつを選ぶ
４．タイムゾーンを日本に設定
↓
リブート（再起動）
リブートはこまめにやったほうがいいかも・・・。

##やってみる

１．日本語化関連のパッケージをインストール
```sudo update-locale LANG=ja_JP.UTF-8
```まあまあ時間かかる・・・。

２．日本語表示にする
```sudo dpkg-reconfigure locales
```
「ja_JP.UTF-8 UTF-8」を選ぶ
※Spaceでチェックを入れて、Enterで決定
※その後の画面でもja_JP.UTF-8 UTF-8を選ぶ

３．キーボードを日本語化
設定（Setting）からキーボード（Keybord）を選ぶ
![VirtualBox_Kali-Linux-2021.1_ver2_15_04_2021_16_18_48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1273608/fad09d2a-887b-65ad-8d55-9b75984ea4d8.png)

レイアウト(Layout)のタブを選ぶと、英語が設定してるのがわかる
![VirtualBox_Kali-Linux-2021.1_ver2_15_04_2021_16_20_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1273608/15ddfc08-d744-38ed-b3f9-708793e2cbf1.png)

日本語を追加して、英語は削除しておく。
![VirtualBox_Kali-Linux-2021.1_ver2_15_04_2021_16_21_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1273608/bdb10930-9da0-84e4-c721-60d3a690441e.png)


![VirtualBox_Kali-Linux-2021.1_ver2_15_04_2021_16_21_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1273608/6b618dc9-96ea-fb5b-87b2-24cb747b6c48.png)

４．ついでに時間（タイムゾーン）も設定
右上の時間表示を右クリック（トラックパッドだと２本指タップ）
んでプロパティを開く。
![VirtualBox_Kali-Linux-2021.1_ver2_15_04_2021_16_33_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1273608/4aac558b-9316-6482-68b8-d31785204425.png)
タイムゾーンに「japan」を入れて選ぶだけ
![VirtualBox_Kali-Linux-2021.1_ver2_15_04_2021_16_33_19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1273608/a51da5ba-dba2-7e5c-8437-600b4b996c4e.png)
閉じるのじゃ。
![VirtualBox_Kali-Linux-2021.1_ver2_15_04_2021_16_33_33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1273608/b0cf0e6d-a516-3130-2d01-8d348f7bb59f.png)

おしまい。
Azure Machine Learningで簡単にデプロイする

最後に、出来上がったモデルをデプロイしましょう。

# モデルの登録

登録はすでにされていると思いますが、行っていない場合は以下のように対象のモデルファイルを登録しておきます。

``` register_model.pl
from azureml.core import Workspace
ws = Workspace.from_config(path=".file-path/ws_config.json")
model = run.register_model(model_name='baye_model',
                           model_path='log/bayes_model.bayes)
print(model.name, model.id, model.version, sep='\t')
```

# エントリスクリプトの構成

推論用のエントリスクリプトを以下のように作ります。
initでモデルのロード、runで推論というようにすればよいと思います。
ここではカスタムクラスのBNEstimatorというものにBayesServerモデルの内容をラップしています。
特にScikitLearnのモデルだからどうとか、インターフェイスを気にするところは特にありません。
jsonで与えられた引数と戻り値をjsonに戻すというくらいです。

``` score.py
import json
import joblib
import numpy as np
from azureml.core.model import Model

# Called when the service is loaded
def init():
    global model
    model_path = Model.get_model_path('bayes_model')
    model = BNEstimator(model = model_path)

# Called when a request is received
def run(raw_data):
    # Get the input data as a numpy array
    data = np.array(json.loads(raw_data)['data'])
    # Get a prediction from the model
    predictions = model.predict(data)
    # Return the predictions as any JSON serializable format
    return predictions.tolist()
```

# デプロイ用スクリプト

デプロイはノードを設定して、モデルを指定してdeployを行う感じです。

``` deploy.pl
from azureml.core import Workspace
ws = Workspace.from_config()
from azureml.core.model import InferenceConfig
classifier_inference_config = InferenceConfig(runtime= "python",
                                              source_directory = '.',
                                              entry_script="score.py",
                                              conda_file="env/bs_env.yml")
from azureml.core.compute import ComputeTarget, AksCompute
cluster_name = 'aks-cluster'
compute_config = AksCompute.provisioning_configuration(location='eastus')
production_cluster = ComputeTarget.create(ws, cluster_name, compute_config)
production_cluster.wait_for_completion(show_output=True)
from azureml.core.webservice import AksWebservice
classifier_deploy_config = AksWebservice.deploy_configuration(cpu_cores = 1,
                                                              memory_gb = 1)
from azureml.core.model import Model
model = ws.models['bayes_model']
service = Model.deploy(workspace=ws,
                       name = 'classifier-service',
                       models = [model],
                       inference_config = classifier_inference_config,
                       deployment_config = classifier_deploy_config,
                       deployment_target = production_cluster)
service.wait_for_deployment(show_output = True)
```

# 参考


* [Azure Machine Learning を使用した機械学習モデルのデプロイ](https://docs.microsoft.com/ja-jp/azure/machine-learning/how-to-deploy-and-where?tabs=python)