OmniAICreator/Qiita-1.07M huggingface dataset:
【注意!!】Railsのdeviseとviewファイルをhamlに変換する時の注意点

こんばんは
アロハな男、やすのりです！

今日はdeviseのビューファイルを修正している時に遭遇した躓きポイントについてお話していこうと思います。

ただ、前提が当てはまる人は参考にしていってね！！

##前提
Railsでアプリケーション作成中にGemの
_devise_を使用していて、更に_haml-rails_等で`html.erb`を`html.haml`に変換している人

##状況

<img width="400px" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699622/4bb5353c-cb4b-c213-084d-ee983c87e145.png">


_devise_の新規登録ページのビューファイルに名前の入力欄を追加したいと思いコード修正していました。

```ruby:views/users/registrations/new.html.haml
%h2 Sign up
= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
  = render "users/shared/error_messages", resource: resource
  .field
    = f.label :name
    %br/
    = f.text_field :name, autofocus: true
  .field
    = f.label :email
    %br/
    = f.email_field :email, autofocus: true, autocomplete: "email"
  .field
    = f.label :password
    - if @minimum_password_length
      %em
        (#{@minimum_password_length} characters minimum)
    %br/
    = f.password_field :password, autocomplete: "new-password"
  .field
    = f.label :password_confirmation
    %br/
    = f.password_field :password_confirmation, autocomplete: "new-password"
  .actions
    = f.submit "Sign up"
= render "users/shared/links"

```
ということで、:nameの欄を足してこれでバッチリだ！！
と、思っていたら...
<img width="400px" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699622/4bb5353c-cb4b-c213-084d-ee983c87e145.png">

...え？
何も変わってなくない？？あれ？？？

修正するビューファイル間違えたかな？と思って確認してみても間違いなく _registrations_ って書いてあるし...

<img width="1500
px" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699622/9a05c09f-fbac-c5cb-b3c7-bdbae3798fcb.jpeg">
あれ！？
なぜか、`new.html.erb`を参照してる！？
しかも参照先が`app/views/deviseregistrations/new.html.erb`になってるぞ！？

と、思いいろいろ調べて見ると原因が見えてきました。

##原因
僕のアプリケーションの構成上、deviseにUserモデルを持たせていたので、_devise_のビューファイルを生成する時に`$ rails g devise:views users`とコマンドを打っていたんですが、これが原因みたいです。
そもそも_devise_のモデルが`Userモデル`以外に無いのであれば、` $ rails g devise:views`だけで良かったみたいです。
※Userモデル以外というよりは、deviseのモデルが__1つだけ__の時と言う方が正しいかも？

##2つのコマンドの違いは？
生成されるビューファイルのディレクトリ構造が少し変わってしまいます。
具体的には`$ rails g devise:views users`とコマンドを打った場合は、

`app/views/users/`以下にディレクトリとビューファイルが生成されます。

一方、` $ rails g devise:views`とコマンドを打った場合は

`app/views/devise` 以下にディレクトリとビューファイルが生成されます。

_deviseディレクトリ_...

<img width="1500
px" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699622/9a05c09f-fbac-c5cb-b3c7-bdbae3798fcb.jpeg">

これだぁぁあああ！！

はい、ということでビューファイルを生成した段階でコミットしていたので、コミット履歴を削除してコマンドを打ち直した後に、新規ビューファイルのコードを修正してみました。

すると...

<img width="400px" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699622/304b08bf-5dcc-7f88-9cdd-b33b333053b6.png">

よしっ！！
名前の入力欄が加わってるぞ！！

<img width="800px" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699622/c66d1226-1e49-59a5-c825-94c41b027dbc.jpeg">

参照先もちゃんと`new.html.haml`になってる！！

##結論
_devise_のビューファイルを生成する時は、__基本__`$ rails g devise:views`でOK!!

皆さんも気をつけてね！！
【PowerShell】SharePoint Onlineからリスト情報を取得する

## はじめに
SharePoint Onlineのサイト～サブサイトの情報を取得するPowerShellです。
本当はリスト名・URLだけを取得したかったのですが、URLだけ取得しようとするとURLに値が入らず、取得できなかったため今回この方法に至りました。

取得方法がわかる方がいらっしゃいましたらコメントください:sob:


## 準備
- PowerShell Ver.5.0以上
    - インストールしている場合は、``$PSVersionTable``を入力してバージョンを確認してください。
- PnP PowerShell
- SharePoint Online Management Shell
- SharePoint Online Client Components SDK


## サンプル

```ruby:qiita.rb 
#サイトコレクションのURL
$SiteCollectionUrl = "任意のURL" 
#ログインユーザー
$username="任意のメールアドレス"

$Cre = Get-Credential -UserName $username -Message "パスワードを入力してください"
Connect-PnPOnline -Url $SiteCollectionUrl -Credentials $Cre

$web=Get-PnPWeb
Write-Host $web.Title "(" $web.ServerRelativeUrl ")に接続しました。"
Read-Host "続けるには Enter キーを押してください..." 

Get-PnPList
$Subs=Get-PnPSubWebs

ForEach($sub in $Subs){
    Get-PnPList  
$sub
}
```

必要であれば、以下を``Get-PnPList``の後ろに追記してください。

```
| Out-String -Width 5000
```

文字数制限により、``Get-PnPList``だけではURLまですべて取得できないことがあります。
必要であれば追記してください。
今回は5000にしていますが、ここは任意の数に変更してください。

## 参考URL

[PowerShellで表示が切れるのを防ぐ](http://saborin.hatenablog.com/entry/2016/12/13/232858 "PowerShellで表示が切れるのを防ぐ")
[PowerShell で、SharePoint Online の リストとアイテムの情報を書き出してみた](https://qiita.com/sharepointer/items/cf6040b44a3bdfb7bcfd "PowerShell で、SharePoint Online の リストとアイテムの情報を書き出してみた")
【Ruby】twitter-adsの中身を叩き切る

業務でtwitter-adsを使ってTwitterの広告配信管理画面のAPIを叩くことがあったのですが、
Ruby初心者過ぎてかなりしんどかったのでメモしておきます。

twitter-adsバージョンは7です。

## クライアントを生成する

これを作らないことには始まりません。

```ruby
require 'twitter-ads'

# initialize the client
client = TwitterAds::Client.new(
  CONSUMER_KEY,
  CONSUMER_SECRET,
  ACCESS_TOKEN,
  ACCESS_TOKEN_SECRET
)
```


## アカウントを取得する

githubのquick startをみると。

```ruby
# load the advertiser account instance
account = client.accounts('c3won9gy')
```

とありますが、そこに渡すID？はなんやねん。という話になります。
色々と調べていった結果、

```ruby
client.accounts.each do |v|
  p v.id
end
```

こういう感じでやったらそれらしいのが1件でてきたのでそこででてきたIDを渡してあげればいけました。


## アカウントが保持しているキャンペーン一覧をだす

上記で取得した、`account`を使います。

```ruby
account.campaigns.each do |v|
  p "====================="
  p v.id
  p v.reasons_not_servable
  p v.servable
  p v.deleted
  p v.created_at
  p v.updated_at
  p v.name
  p v.funding_instrument_id
  p v.end_time
  p v.start_time
  p v.entity_status
  p v.currency
  p v.standard_delivery
  p v.daily_budget_amount_local_micro
  p v.total_budget_amount_local_micro
  p v.to_delete
  p "====================="
end
```

こうやってやるとズラーっとキャンペーン一覧がでてきます。
（こうやって一個一個pせずに一行で全部の値を出す方法ご存じの方いたら教えて下さい・・・）

※ステータスが「削除済み」となっているキャンペーンについては出力されません。

特定のキャンペーンのみのオブジェクトを作りたい場合は、

```ruby
campaign = account.campaigns('1m5bbbb')
```

こういう感じで生成してあげて、（渡すIDは上記の`v.id`で出てきた値です）

```ruby
campaign.name
```

という感じでキャンペーン名が取得できます。


```ruby
campaign.name = "MADOKA"
campaign.save
```

ってやればキャンペーン名を変更できたりもします。幸せいっぱいですね。

## 広告グループを出力する

```ruby
account.line_items()
```

こちらも`account`が保持する広告グループを出力するので、`account`を使います。

これで広告グループの一覧が取得できます。
※ステータスが、「実行中」、「停止中」、「予約済み」、「おすすめ」のものがでてきます。


## テイラードオーディエンス一覧をだす。

これも`account`を使います。

```ruby
account.tailored_audiences.each do |v|
  p "==========="
  p v.id
  p v.name
  p v.list_type
  p v.audience_size
  p v.audience_type
  p v.metadata
  p v.partner_source
  p v.reasons_not_targetable
  p v.targetable
  p v.targetable_types
  p "==========="
end

```


ここまででなんとなく取得系の雰囲気はつかめてきました。

ここから更に実践的な使い方を書いていきます。

## 広告グループに紐付いているテイラードオーディエンスを出す。

広告グループは、

```ruby
line_item = account.line_items('1abcd')
```
で取得できます。


で、この取得した`line_item`で、

```ruby
line_item.targeting_criteria.each do |target|
  if target.targeting_type == 'TAILORED_AUDIENCE' then
    p account.tailored_audiences(target.targeting_value).name
  end
end
```

こんな感じになります。

## 広告グループに紐付いているテイラードオーディエンスの紐づきを解除する

```ruby
line_item.targeting_criteria.each do |target|
  if target.targeting_type == 'TAILORED_AUDIENCE' then
    target.delete!
  end
end
```

## 特定のテイラードオーディエンスを指定した広告グループに紐付ける

これがかなり手こずったのですが、

```ruby
tc = TwitterAds::TargetingCriteria.new(account)
tc.line_item_id    = '紐付け対象広告グループのID'
tc.targeting_value = '紐付けたいテイラードオーディエンスID(value)'
tc.targeting_type  = 'TAILORED_AUDIENCE' ここは固定でこれ入れればOK
tc.save
```

といった感じでした。

## 以上です

紐付けに関して。
TA（テイラードオーディエンス）を作成してもすぐには「準備完了」ステータスにならないので、
作成後、定期的にそのTAの様子をバッチで見に行って、ステータスが「準備完了」（targetable）になったのを確認して、紐付けっていうロジックを組む必要があります。

このSDKの使い方を理解するまでがくそしんどかったのですが、理解さえできれば後は書くだけなので楽しかったです。

今日はそんな感じです。


https://github.com/twitterdev/twitter-ruby-ads-sdk
C言語+MPIのtips（MPI_Reduce）

MPI_Reduce は「各プロセスの持つ同じ長さのデータを何らかの演算をして，その結果をあるプロセスに渡す関数」。

【目的】
一次元配列 my の和を求めることで MPI_Reduce の機能を知る。

【使用するもの】
open-mpi

【環境】
$ mpicc --version
Apple clang version 11.0.3 (clang-1103.0.32.29)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

【方法】

```C:reduce.c 
#include<stdio.h>
#include"mpi.h"

int main(int argc, char *argv[]){

  int my_rank, num_proc;
  int i, my[3], sum[3];

  MPI_Init(&argc, &argv);
  MPI_Comm_size(MPI_COMM_WORLD, &num_proc);
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

        for(i=0;i<3;i++) my[i] = i*4 + my_rank;
        printf("my_rank=%d, my[0]= %d, my[1]= %d, my[2]= %d\n",my_rank,my[0], my[1],my[2]);
        MPI_Reduce(my, sum, 3, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
        printf("my_rank:%d, sum[0]= %d, sum[1]= %d, sum[2]= %d\n",my_rank, sum[0], sum[1],sum[2]);

  MPI_Finalize();

  return 0;
}
```

【結果】
mpicc コマンドでコンパイル、mpirun コマンドでプロセス数を２にして実行。

```
$ mpicc reduce.c
$ mpirun -np 2 ./a.out
my_rank=0, my[0]= 0, my[1]= 4, my[2]= 8
my_rank=1, my[0]= 1, my[1]= 5, my[2]= 9
my_rank:1, sum[0]= 0, sum[1]= 0, sum[2]= 0
my_rank:0, sum[0]= 1, sum[1]= 9, sum[2]= 17
```

【考察（何が起きたのか）】
まずプロセス０と１でそれぞれ my[0]、my[1]、my[2]が生成される。
それぞれのプロセスでのfor文で値が格納される。
at プロセス０　my[0]=0*4+0=0、my[1]=1*4+0=4、my[2]=2*4+0=8
at プロセス１　my[0]=0*4+1=1、my[1]=1*4+1=5、my[2]=2*4+1=9

MPI_Reduceによって「my」が送信され「sum」が受信される。要素の数は「3」、データの型は整数（int）「MPI_INT」、操作は和を求めること「MPI_SUM」。
sum[0]=（プロセス０でのmy[0]）＋（プロセス１でのmy[0]）
sum[1]=（プロセス０でのmy[1]）＋（プロセス１でのmy[1]）
sum[2]=（プロセス０でのmy[2]）＋（プロセス１でのmy[2]）
結果はプロセス「0」へ送信される。プロセス１のsumは0のまま。

それぞれのプロセスでsumが表示されて終了。

【参考】
「mpi 並列プログラミング」と検索すると、より正確でより情報量の多い資料が見つかります。
GASのJDBCでCloudSQLのデータベースとやり取りする基礎

GASのJDBCでCloudSQLforMySQLのデータベースとやりとりする機会ががあったので備忘録に。

## 接続
この辺りはお決まりなので他の人の素敵な記事を参照してほしい。
▶️[GASのJDBCサービスでCloud SQLデータベースに接続をする方法
](https://tonari-it.com/gas-jdbc-connection-cloud-sql/)

以下のようなコードでDBに接続開始します。

```connection.js
var connName = 'DB接続名'; //Instance_connection_name
var userName = 'ユーザー名(rootとか)'; //user_name
var pw = 'パスワード'; //'user_password'
var dbName = 'DB名'; //database_name

var url = 'jdbc:google:mysql://' + connName + '/' + dbName;
var conn = Jdbc.getCloudSqlConnection(url, userName, pw);
```

## 接続以降の使い方

### SELECTするとき
```select.js
var sql = "SELECT name FROM sample_table WHERE id=?";
  var stmt = conn.prepareStatement(sql);
  stmt.setString(1, id);
  var results = stmt.executeQuery();
```
※変数"conn"は前章（JDBC接続）のコードに続けて書いている前提です。

SQLは特別な部分は特にない。
"?"は`setString(n番目の?, 入れる値)`などで後から値を入れられます。(1から始めます）
パラメータを入れるときのみprepareStatement()が必要になります。
で、executeQuery()で実行。

パラメータを入れない場合はstmt(statement)がないので、

```createStatement.js
var stmt = conn.createStatement();
var results = stmt.executeQuery(sql);
```
これで生成と実行をします。

executeQuery()の戻り値の型はJdbcResultSetというものです。
▶️[JdbcResultSetのリファレンス](https://developers.google.com/apps-script/reference/jdbc/jdbc-result-set)


#### 件数取得
件数取得はもっと簡単にできないものか……

```getNumItems.js
results.last(); //取得レコードの最後の行に移動
Logger.log(results.getRow()); //現在の行番号を取得してログに吐き出し
results.beforeFirst(); //最初の行に戻る
```

#### レコード件数の分だけ処理をする＆取得データをget
```action.js
while(results.next()){
  results.getString('name'); //SELECTで取ってきたデータを取得(カラム名から）
  results.getString(index); //番号から取得（１はじまり）
}
```

#### 特定行のレコードの中身を見る
特定行のレコードの中身を見る時はgetMetaData()を使います。
▶️[JdbcResultSetMetaDataのリファレンス](https://developers.google.com/apps-script/reference/jdbc/jdbc-result-set-meta-data)

```getRowData.js
while(results.next()){
  var metaData = results.getMetaData(); //特手行のデータがわかる
  var numColumn = metaData.getColumnCount(); //列数がわかる
}
```

### UPDATE・INSERT
UPDATE・INSERTも要領は同じですが、実行時に呼ぶ関数だけ違います。

```exeUI.js
var result = stmt.executeUpdate();
```

`Can not issue data manipulation statements with executeQuery().`
っていうエラーが出た時はここでexecuteQuery()をやってるはず。

### DELETE
使う予定がなくなったのでもしやることがあれば更新します……。

## リクエストがエラーになったとき
try-catchでエラーをcatchしたときにこんなの入れておけばエラー内容が綺麗に確認できます。

```error.js
catch(e){
  console.error("Type: " + e.name + "\n" +
                "File: " + e.fileName + "(行 " + e.lineNumber + ")\n" +
                "Message: " + e.message + "\n" +
                "StackTrace:\n" + e.stack;);
}
```

## 最後にclose()を忘れずに
だいじです。

```close.js
conn.close();
```

## さいごに
手探りでいろいろやってるので、気付きがあれば更新するかもです。

Tipsとかあればむしろ教えて欲しい。
FireAlpacaからSpriteStudioへ出力する方法

SpriteStudioが無料配布されていたので気になっていたついでに少し触ってみました。UnityやUE4にも対応しているらしいので今後使用するだろうということを前提に備忘録として残そうと思います。
**※必須：ツールでの変換にPhothoShopもしくはCLIP STUDIOなどが必要です！**

2020/11/12　追記
[ツールの配布ページ](https://github.com/SpriteStudio/PSDtoSS6/wiki)にFireAlpacaは変換フォーマットが違うから直接のコンバートはできません。と書いてあった。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501431/43d939b9-9331-a7cf-41c8-519205615a00.png)

なので**FireAlpacaで描いたイラストはPhotoShopやCLIP STUDIOなどを経由して保存**しなおせばSpriteStudioにインポートできる。
もしかしたら今後FireAlpaca単体で変換できるかもしれないが、フォーマットが違うと言われているので可能性は低いかもしれない。あまり期待しないでおこう。

ちなみにそれぞれのバージョンは以下を使用した。
FireAlpaca：2.3.18
PSDtoSS6：2.2.1

#事前準備
①[SpriteStudio](https://www.webtech.co.jp/spritestudio/)をDL＆インスコする
②[PSDtoSS6](https://github.com/SpriteStudio/PSDtoSS6/wiki)をDL＆インスコする（[参考サイト](https://www.webtech.co.jp/help/ja/spritestudio/guide/tool/psdtoss6/)）
③PSDtoSS6を実行したときに「VCRUNTIME140_1.dllが見つからない」と言われたときは[DLLファイル](https://support.microsoft.com/ja-jp/help/2977003/the-latest-supported-visual-c-downloads)をDL＆インスコする（[参考サイト](https://loumo.jp/archives/25069)）

#FireAlpaca編
###.psdに出力する
①レイヤー名はすべて半角文字にする
　全角文字だとPSDtoSS6変換時にエラーになる。
　※フォルダやクリッピング、テキストなどは対象外になるのでラスタライズや結合をしておく
②ファイル名も半角文字にする
　例）ss.psd
③.psd形式で保存する
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501431/2e403225-374e-9f25-3c59-7f8e745160d4.png)

#PhotoShop編
FireAlpacaで保存したイラストを開き、上書き保存する。

#PSDtoSS6編
①保存したpsdファイルをD&Dで追加し、出力フォルダなどを設定してコンバートする
↓簡単に設定したもの
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501431/b52f18ee-4e40-1a9c-5cb5-b822f6155b8b.png)

②変換が成功したらファイルが出力されているはず。今回はssaeとsspjの出力も含めたので4つ出力されていると思う。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501431/c34cedfa-857e-4302-b91e-4f1ea5e9e287.png)

#SpriteStudio編
①PSDtoSS6で出力したsspjのファイルをD&Dで突っ込めばFireAlpacaで描いたレイヤー別の状態が移行できていると思う。

やったね！

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501431/b55e39bc-cae9-bc89-f8a8-421dea4392fe.png)

#おまけ
※1　FireAlpaca上で追加したフォルダに関して
　PhotoShopを経由して上書き保存して変換するとフォルダが存在しないことになる。（フォルダの中身がそれぞれのレイヤーとして追加される）
※2　PhotoShop上で追加したフォルダに関して
　空レイヤーとして追加された。
INNER JOIN の DISTINCT が効かなくてハマった話

INNER JOIN で中間テーブルを経由してデータ取得するとき、DISTINCT をつけても重複が削除できなくてハマった話です

## データ
### Users ユーザー情報

| id | name |
|:-:|:-:|
| 1  | Bob  |
| 2  | Mary  |

### Tags タグ

| id | name |
|:-:|:-:|
| 1  | Engineer  |
| 2  | Leader  |

### Tag_Users ユーザー情報とタグの中間テーブル

| user_id | tag_id |
|:-:|:-:|:-:|
| 1  | 1  |
| 2  | 1  |
| 1  | 2  |
BobはEngineer
MaryもEngineer
BobはLeader というデータとします

## 最初に書いたSQL

Engineer または Leader のユーザーを取得する必要があり、以下のようなSQL文を書きました

```SQL
SELECT * FROM users INNER JOIN tag_users ON users.id = tag_users.user_id WHERE (tag_users.tags_id = 1 or tag_users.tags_id = 2);
```

### 表示された結果

| users.id | users.name | tag_users.user_id | tag_users.tag_id |
|:-:|:-:|:-:|:-:|
| 1  | Bob  | 1 | 1 |
| 1  | Bob  | 1 | 2 |
| 2  | Mary | 2 | 1 |

Bobが2人いますね

## 重複を削除しようと思って書いたSQL

```SQL
SELECT DISTINCT * FROM users INNER JOIN tag_users ON users.id = tag_users.user_id WHERE (tag_users.tags_id = 1 or tag_users.tags_id = 2);
```

### 表示された結果

| users.id | users.name | tag_users.user_id | tag_users.tag_id |
|:-:|:-:|:-:|:-:|
| 1  | Bob  | 1 | 1 |
| 1  | Bob  | 1 | 2 |
| 2  | Mary | 2 | 1 |

Bobが重複しているのでDISTINCTを追加したけどBobは減らなかった

## 本当に必要だったSQL

```SQL
SELECT DISTINCT users.* FROM users INNER JOIN tag_users ON users.id = tag_users.user_id WHERE (tag_users.tags_id = 1 or tag_users.tags_id = 2);
```

### 表示された結果

| users.id | users.name |
|:-:|:-:|
| 1  | Bob  |
| 2  | Mary |

OK

## 結論
取得する範囲をきちんと指定する
アプリ制作時に使って良かったツール

ちゃんと計画性を持って、作業に集中してアプリ制作に取り組みたい...
と、アプリ制作を始めて3,4年経った私は思い始めていました。
そこで作業環境を自分なりにいろいろと試したので、その結果を記録しようと思います。
以下、使用したツールごとに書いていきます！
ちなみに今回の作業で制作したアプリは[こちら](https://play.google.com/store/apps/details?id=com.satoshi.route_quiz)になります。

# [Figma](https://www.figma.com/)（デザイン）
以前は、アプリのシステムとUIを全て作り終えてから色やUIパーツの大きさなどを調整していました。
調整はすべて直接コードに書いて、変化を確認して...の繰り返しです。
これでは効率が悪いなとも思いつつ改善してこなかったので、今回はアプリの見た目を先に全て決めてしまってそこを目指してコードを書くという順番にしました。

そこで使ったツールが[Figma](https://www.figma.com/)です！

基本はUIのパーツを画面に配置していくという使い方なのですが、個人的にいいなと思った点は以下になります。

* ブラウザ版で気軽に始められる
* デザインを自分の端末にリアルタイムで反映できる
* アイコンなどを「アセット」として外部からインポートして使える

ネット上に使い方の記事がいくつか出ているので、詳しくはそちらを参照していただきたいです。

# [Bear](https://bear.app/)（メモ）
アプリのデザインが決まって、コードを書き始めた時に[Bear](https://bear.app/)を使い始めました。
BearはMac、iPad、iPhone用のアプリで、Markdown記法でメモを書けます。
見た目がとても好きで、編集もしやすいので使っています。
私は主にTODOリストとして使うことが多かったです。

# [Focus To-Do](https://www.focustodo.cn/)（時間管理）
こちらは、ポモドーロという時間管理テクニックを使えるアプリです。
Windows、Mac、Android版があるのは確認しました。（OSによって使い勝手は少しづつ違います。）
これは実際に使ってみると良さがわかるかと思います。
モバイル向けFlutterアプリをFlutterWeb対応するときに注意したいこと

# プロジェクトのルートディレクトリの名前
ハイフンが含まれているとエラーになる　名前に注意　つまりリポジトリ名に注意　アンダーバーにしよう

# Platform判定はできない
Platform.isIOSなどで判定しているところは動かないので、その前段階でkIsWebでWebかどうかを判定する

# FirebaseのWebアプリを設定しろ
https://firebase.flutter.dev/docs/installation/web

# モバイル向けのsecure_storageのパッケージは非対応
アプリ内にログイントークンなど持ちたいから[flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage)プラグイン使うと思うけど、Webでは非対応なので[shared_preferences](https://pub.dev/packages/shared_preferences)プラグインを使う

# APIRequestがエラーになる
CROSサポート（[参考](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/how-to-cors.html)）を有効にする必要がある。

開発でテストするなら以下のChrome extensionをインストールしたら解決できる
https://chrome.google.com/webstore/detail/cors-unblock/lfhmikememgdcahcdlaciloancbhjino/related?hl=ja

# Fileの扱いについて
そもそもパッケージが違うよ　Webではファイルパスでファイルに直接アクセスできないからon memoryで扱う
dart:io
dart:html

# Networkから画像が取得できる？？
できるけど、AuthHeaderが効かないから画像が取得できない場合もある
https://github.com/flutter/flutter/issues/57187

# カメラ使える？
まだ非対応です。
https://github.com/flutter/flutter/issues/45297
ただ、撮影した画像の取得やカメラロール（ギャラリー）からの取得はできます。
https://pub.dev/packages/image_picker_for_web

# WebサーバーないけどWebで公開して確認したい！
Github Page（https://pages.github.com/）使えます。
プライベートリポジトリでは無料プランだと使えません。

Bitbucketならプライベートリポジトリでもつかえます
https://support.atlassian.com/bitbucket-cloud/docs/publishing-a-website-on-bitbucket-cloud/
【Python】文字列を一斉置換する正規表現も使える関数を作った。

#はじめに
文字列を複数のパターンで置換する場合、↓ のような冗長なコードになりがちですよね。

```python
#例えば
# " <-> '
# abc...z -> *
# ABC...Z -> AA, BB, CC, ...,ZZ
#のような置換がしたい場合

text = "'abc'" + '"ABC"'

#パターン1
replaced_text = text.replace('"', '#').replace("'", '"').replace('#', "'").replace("a", "*"). ....... 

#パターン2
trdict = str.maketrans({'"': "'", "'": '"', "a": "*", "b": "*", .......})
replaces_text = text.translate(trdict)

#パターン3
import re
replaced_text = re.sub("#", '"', re.sub('"', "'", re.sub("'", '#', re.sub("[a-z], "*", re.sub("[A-Z]", "\\1\\1", text)))))

#etc...
```
また、パターン１、３のような置換方法の場合、置換は順を追って行われるため、置換後の文字が更に置換されたりなど予期せぬ置換が行われる可能性も考慮しなければなりません。
しかし、パターン３のように正規表現を使えないと多大で無駄な手間がかかってしまいます。

そんな不満を解消するべく、

**正規表現も使えて、
置換パターンを辞書でまとめて渡せて、
すべての置換を同時に行える**

関数を書きました。

#出来たもの

```python
import re
from typing import Dict

def replaces(text: str, trdict: Dict[str, str]) -> str:
    """
    IN:
        Source text
        Replacement dictionary
    OUT:
        Replaced text
        
    NOTE:
        You can use regular expressions.
        If more than one pattern is matched, 
        the pattern closest to the front of the dictionary takes precedence.
    
    EXAMPLE:
        text = "'abc'" + '"ABC"'
        replaces(text, {"'": '"', '"': "'", "[a-z]": "*", "([A-Z])": "\\1\\1"})
        
        ---> "***"'AABBCC'
    """
    return re.sub(
        "|".join(trdict.keys()), lambda m: next(
            (re.sub(pattern, trdict[pattern], m.group(0)) for pattern in trdict
             if re.fullmatch(pattern, m.group(0)))), text)
```

#使い方
第１引数：元の文字列
第２引数：置換用辞書 `{before: after}`
返り値　：置換後の文字列

```python
text = "'abc'" + '"ABC"'
trdict = {"'": '"', '"': "'", "[a-z]": "*", "([A-Z])": "\\1\\1"}
replaces(text, trdict)
# ---> "***"'AABBCC'
```
辞書内の複数パターンに一致した場合、前方のパターンが優先されます。
QiitaOrganizationのLGTM数をGASでSlackに通知する

この記事は移行しました！[最新の内容はこちら](https://naoqoo2.github.io/blog/QiitaOrganization%E3%81%AELGTM%E6%95%B0%E3%82%92GAS%E3%81%A7Slack%E3%81%AB%E9%80%9A%E7%9F%A5%E3%81%99%E3%82%8B/)をご覧ください😀

## やったこと

QiitaOrganizationのページからLGTM数を取得して

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56789/0764fbe8-966a-2d2a-fac1-1c2c3ac3beb9.png)

こんな感じで毎週Slackに通知。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56789/f3bff1f2-960d-a4fe-0b93-341725078c51.png)

## なぜやったのか

- 社内でQiitaを盛り上げたい、関心UP
- 投稿へのモチベーションUP
- いっぱい投稿が増えるといいな


## 実装メモ

- LGTM数は[feed](/feed subscribe https://qiita.com/organizations/sousei-tech/activities.atom)に含まれてなかったのでスクレイピングで取得
    - なぜかスクレイピングするとLGTMの後ろにsがつくっぽい。これは未解決。
- Slack通知はIncoming Webhookを使用
    - 設定こんな感じ ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56789/1edd93b9-0a99-a7af-5676-c6e63e46634a.png)
- LGTM数はスプレッドシートに記録される
    - こんな感じで日付とLGTM数が溜まっていく ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56789/5c1cab69-0e1f-433a-1e8e-5e678449eb14.png)

- 毎週実行はGASのトリガーでやってる。

## コード（GAS）

スプレッドシートからツール→スクリプトエディタを開く。
下記をコピペしてurlとwebhook_urlを書き換えればOK。

```
function notifyContributions() {
  const url = 'QiitaOrganizationのURL'; // 例： https://qiita.com/organizations/sousei-tech
  const webhook_url = "Incoming WebhookのURL"; // 例）https://hooks.slack.com/services/HOGE/FUGA/HOGA

  const response = UrlFetchApp.fetch(url);
  const html = response.getContentText();
  
  let contributions;
  // NOTE: HTML構成変わると動かなくなる。そのときはwebページをソース表示して該当箇所のHTMLを見つけて修正する。
  // NOTE: 2020/3/10時点 "likesCount":1096,
  const targetLeft = '"likesCount":';
  const targetRight = ',';
  let index = html.indexOf(targetLeft)
  // Logger.log(index);
  if (index !== -1) {
    let tmp = html.substring(index + targetLeft.length);
    index = tmp.indexOf(targetRight);
    if (index !== -1) {
      contributions = tmp.substring(0, index);
    }
  }
  
  const book = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = book.getSheetByName("シート1");

  const last_row = sheet.getDataRange().getLastRow();
  const before_contributions = sheet.getRange(last_row, 2).getValue();
  const target_row = last_row + 1;
  sheet.getRange(target_row, 1).setValue(new Date());
  sheet.getRange(target_row, 2).setValue(contributions);
  // Logger.log(before_contributions);
  
  const message = contributions + ' LGTM :tada: （前回から+' + (contributions - before_contributions) + '）' + "\n" + url;
  
// エラーで動かなくなったときはここでリターンして調査するとよい。(Slackへの通知をやめる)
//  Logger.log(contributions);
//  return;

  const jsonData = {
    "text" : message,
    "link_names" : 1,
  };
  const payload = JSON.stringify(jsonData);  
  const options = {
    "method" : "post",
    "contentType" : "application/json",
    "payload" : payload,
  };
  UrlFetchApp.fetch(webhook_url, options);
```

## おまけ

社員の投稿を通知したい場合はslackでfeedを購読しておけばOK！（これもGASで実装しようかと思っていた😅）
`/feed subscribe https://qiita.com/organizations/sousei-tech/activities.atom`

## さいごに

それではステキなQiitaOrganizationライフを。
Blender内from_pydata()を使用して点と線を登録する方法

#スクリプトを用いて頂点、辺を作成する
bpyのblender用pythonのライブラリを使用して頂点、辺を作成するコードは下記となります。こちらのコードはblenderを起動し、text editor内に貼り付けて実行しました。

```python:blender.py
import bpy

#points for 1st mesh
verts_1 = []
verts_1.extend([[-1,1,0],[1,1,0],[1,-1,0],[-1,-1,0]])

#points for 2nd mesh
verts_2 = []
verts_2.append([-2,2,0])
verts_2.append([2,2,0])
verts_2.append([2,-2,0])
verts_2.append([-2,-2,0])

#edges for 2nd mesh
edges_2 = []
edges_2.extend([[0,1],[1,2],[2,3],[3,0]])

#create new 1st mesh 
n_mesh_1 = bpy.data.meshes.new("new_mesh_1")
#create new object and link 1st mesh to object
ob_1 = bpy.data.objects.new("new_object_1",n_mesh_1)
#link object to scene
bpy.context.collection.objects.link(ob_1)

#update mesh data from given points
n_mesh_1.from_pydata(verts_1,[],[])
n_mesh_1.update()

#create new 2nd mesh 
n_mesh_2 = bpy.data.meshes.new("new_mesh_2")
#create new object and link 2nd mesh to object
ob_2 = bpy.data.objects.new("new_object_2",n_mesh_2)
#link object to scene
bpy.context.collection.objects.link(ob_2)

#update mesh data from given points
n_mesh_2.from_pydata(verts_2,edges_2,[])
n_mesh_2.update()

```
verts_1,verts_2は頂点XYZ座標を配列として格納します。
edges_2は頂点(verts_2の配列番号)を指定して辺の情報を格納します。
【エラー】Mysql2::Error: Specified key was too long; max key length is 767 bytes

エラーの忘備録
#エラー内容
`rails db:migrate`をした時に、以下のエラー文が出ました。（Mysqlのエラー）

```
Mysql2::Error: Specified key was too long; max key length is 767 bytes
```
`指定したキーが長すぎる`というエラーです。
テーブルに色々カラムを追加すると、キーの制限である767バイトを超えてしまうため
このエラーが起こってしまいます。

#原因

```ruby:config/database.yml
  default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock
```

`encoding: utf8mb4`という記述のためエラーが出ます。

#解決方法
`encoding: utf8`に書き換えます。

```ruby:config/database.yml
  default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock
```
utf8mb4とutf8の違いはいまいちわかっていないのですが、utf8mb4は1〜4バイト、utf8は1〜3バイトの文字が格納できるようです。そのためutf8だと、絵文字などは保存できませんが、代わりに容量が大きくなるのではないかな？と推測しました。

すでに`rails db:create`でデータベースを作成してしまっている場合は、

```
% rails db:drop
% rails db:create
```
か

```
% rails db:reset
```
で、もう一度データベースを作り直してあげる必要があります。

#おわりに
もし間違えている点などございましたら、ご指摘いただけましたら幸いです。
読んでいただきありがとうございました！
Windows標準機能で動画をキャプチャする

# 手順

1. キャプチャしたいウインドウをフォアグラウンドにする
2. `Win + G`でゲームのキャプチャを呼び出す
3. 録画を開始する(下図赤丸部分を押下)

![スクリーンショット (12).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526492/e5db062b-aa20-43f0-0a3c-9e1ad178e4d4.png)


# これプログラミングと関係ある？

Unityで作ったゲームをキャプチャするときに使ったので関係あるかな、と。
ChipWhisperer CW305 Artix7 XC7A100T にチュートリアル用AES回路をVivadoでコンパイルして書き込む

2021/06 追記

ChipWhisperer5.5.2を確認していたところ，いつの間にかAES周りのフォルダ・ファイル構成に変更が入っていたのを確認しました．
この記事の内容は5.3の頃に書かれたもので，内容が古くなっているので注意してください．
気が向いたらそれに合わせて修正しようと思いますが，基本的には取り込むソースコードとその階層関係に注意すれば特に問題ないと思います．

-----
CW305に自作回路を実装するための練習として．

## 環境

- Vivado2020.1

- ChipWhisperer 5.3.1

- CW305 XC7A100T

## Vivadoプロジェクトを作る

1. Vivadoを起動し，Quick Startから`Create Project >`を選択

2. 適当なProject NameとProject locationを設定する

3. RTL Project，Do not specify sources at this timeにチェック

4. Default Partは`xc7a100tftg256-2`を選択
(Artix7 XC7A35Tの場合は`xc7a35tftg256-2`)


## ソースコードを登録する
Verilogソースコードはここにある
`\chipwhisperer\hardware\victims\cw305_artixtarget\fpga`

以下の手順で次のソースコードを追加

- 追加するソースコード

    - `common` フォルダ
        - `board.v`
        - `cw305_top.v`
        - `usb_module.v`
        - `registers/registers.v`
    - `cryptosrc/aes_googlevault` フォルダ
        - `aes_core.v`
        - `aes_ks.v`
        - `aes_sbox.v`

- ソースコード追加手順
    1. `Add Sources`をクリックし，`Add or create design sources`にチェックしてNext
    2. ソースコードを選択してFinish

- 同様に，Constraintsも追加
    1. `Add Sources`をクリックし，`Add or create constraints`にチェックしてNext
    2. `common/cw305_main.xdc`を選択してFinish

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499982/adab3129-6331-fc81-24f2-6064774018de.png' width='600'>

## 合成する

1. Run Synthesis

2. Run implementation

3. Generate Bitstream

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499982/3a1dd368-6c6e-32ae-2eb8-4f80efe75694.png' width='600'>

## 書き込む

```python
import chipwhisperer as cw

scope = cw.scope()

bitstream = <PATH_TO_BITSTREAM_FILE>
target = cw.target(scope, cw.targets.CW305, bsfile=bitstream, force=True) # 書き込み
```
心理学的測定法 東京大学出版 田中義久先生

```{r}

#p.65 確認中

n=9

Njc=c(7,8,6,8,9,7,6,7,8)

rjc=c(2,3,2,4,2,3,2,2,3)

Sc=5;Sj=c(1,3,4,2,8,7,6,9,8)

xjc=Sj-Sc

alpha=0.1;beta=0.1

h=0.01

ite=10000

eta=0.0001

for(l in 1:ite){
  
alpha_pre=alpha;beta_pre=beta

da=sum((rjc/(1-pnorm(-alpha-xjc*beta))-(Njc-rjc)/(pnorm(-alpha-xjc*beta)))*(1-pnorm(-(alpha+h)-xjc*beta)-(1-pnorm(-alpha-xjc*beta)))/h)

Y=qnorm(1-pnorm(-alpha-xjc*beta))

db=sum((rjc-(1-pnorm(-alpha-xjc*beta))*Njc)*xjc*dnorm(Y)/(pnorm(-alpha-xjc*beta)*(1-pnorm(-alpha-xjc*beta))))

alpha=alpha+eta*da

beta=beta+eta*db

#print(sum(abs(alpha_pre-alpha)+abs(beta_pre-beta)))

loglik=sum(rjc*log(1-pnorm(-alpha-xjc*beta))+(Njc-rjc)*log(pnorm(-alpha-xjc*beta)))

print(loglik)

}

```


```{r}

#p.132 

mat=matrix(c(0,55.09,63.91,71.26,89,44.91,0,58.96,65.49,87.21,36.09,41.04,0,58.66,84,28.74,34.51,41.34,0,78.94,11,12.79,16,21.06,0),ncol=5)

diag(mat)=1

V=log10(mat)

u=V-t(V)

y=apply(u,2,mean)

S=10^y

u_hat=log(t(t(exp(-y)))%*%t(exp(y)))


```

```{r}

#p.172

P=matrix(c(0.5,0.2833,0.1667,0.0333,0.7167,0.5,0.2333,0.1167,0.8333,0.7667,0.5,0.2833,0.9667,0.8833,0.7167,0.5),ncol=4)

Z=qnorm(P)

W=(dnorm(Z)^2)/(P*(1-P))

njk=60

W_mat=-W*njk

diag(W_mat)=abs(apply(W_mat,1,sum)-diag(W_mat))

Z.=apply(W_mat*Z,1,sum)

W_mat_star=W_mat[1:(ncol(W_mat)-1),1:(nrow(W_mat)-1)]

Z.star=Z.[1:(length(Z.)-1)]

alpha_star=solve(W_mat_star)%*%Z.star

alpha_star=c(alpha_star,0)

```

```{r}

#心理学的測定法　田中良久著　東京大学出版

#p.185

#条件B

Z=matrix(c(0,-0.2,-1.5,-0.5,-2,0.5,0.133,-0.75,-0.3,-1.5,1.5,0.8,0.75,0.1,-0.5,2.25,0.3,1.875,0.4,0.25),ncol=4)

a=1;r=0;a_vec=c(a);r_vec=c(r);I_vec=c()

for(j in 1:(nrow(Z)-1)){

Y=Z[j,];X=Z[j+1,]

#C=cov(X,Y)/var(X)

C=(Y[2]-Y[1])/(X[2]-X[1])

a_pre=a

a=C*a

#I=mean(Y)-a*mean(X)

I=(X[1]*Y[2]-X[2]*Y[1])/(X[1]-X[2])

I_vec=c(I_vec,I)

r=r+a_pre*I

a_vec=c(a_vec,a)

r_vec=c(r_vec,r)

}

a_vec=round(a_vec,3)

r_vec=round(r_vec,3)

t=(t(Z)%*%a_vec+sum(r_vec))/nrow(Z)

tr=array(0,dim=dim(Z))

for(i in 1:nrow(Z)){
for(j in 1:ncol(Z)){

tr[i,j]=t[j]-r_vec[i]

}}

Za=array(0,dim=dim(Z))

for(i in 1:nrow(Z)){
for(j in 1:ncol(Z)){

Za[i,j]=Z[i,j]*a_vec[i]

}}




#条件D

#最小二乗法　Zに空欄がない場合

R=mean(Z)-apply(Z,1,mean)

t=apply(Z,2,mean)

#空欄がある場合

Z2=matrix(c(0.5,-0.5,-1.3,-2,NA,1.5,0.5,-0.3,-1,-1.7,2,1,0.2,-0.5,-1.2,NA,1.8,1,0.3,-0.4),ncol=4);Z2[5,1]=NA;Z2[1,4]=NA

dZ=array(0,dim=c(nrow(Z2),ncol(Z2)-1))

for(j in 1:ncol(dZ)){

dZ[,j]=Z2[,(j+1)]-Z2[,j]

}

t=c(0)

for(j in 1:ncol(dZ)){

vec=dZ[,j];vec=mean(vec[is.na(vec)!=T])

t=c(t,vec)

}

t=cumsum(t)

R=Z2

for(j in 1:ncol(R)){

R[,j]=t[j]-R[,j]

}






```
.NETとつくフレームワークが多すぎて混乱したので調べてみた


# はじめに

この記事は.NETに関する内容をまとめたものです。
私はよくゲームエンジンであるUnityを扱っています。Unityを扱う中で、C#について深くを調べていくと「.NET」という単語をよく見かけるようになりました。そこで、.NETという単語がどのような意味なのか、C#、Unityでのプログラミングにどのような役割を果たすのかを調べ、まとめました。

今後、Unityに絡めた内容で新たな記事を作成したいと考えています。(予定は未定)

この記事単独でも読めるように書きましたが、そのような背景があることを念頭に置いていただけますと幸いです。

## 記事を分けた理由
主に.NETとつく言葉が

+ .NET
+ .NET Core
+ .NET Framework

とたくさんあって紛らわしいことから「そもそも違いはなんだろう？」と思い、調べた。すると、構成的にも長さ的にも元記事に書くのが難しかったので独立した記事として書いた。

# ざっくりとわかったこと
.NETとはMicrosoftの考えた理念のことで、その理念を実現するためのフレームワークとして以下のようなものがあるということ

+ .NET Framework
+ .NET Core
+ Xamarin
+ .NET Standard
+ .NET 5(2020年11月リリース予定)

それぞれ

.NET Framework → Windowsアプリケーション向け

.NET Core → サーバーサイドをはじめとするクロスプラットフォーム向け

Xamarin → モバイル、OS Xアプリケーション向け

.NET Standard → 上記全ての.NETフレームワークに共通のライブラリ

.NET 5 → 上記全部をまとめて一つで扱えるようになる(つまり、この記事は無意味w)

と言った感じ

# そもそも.NETとは何か？
Microsoftが2000年に構想したMicrosoft.NETという概念(今でいうIoT)を実現するための開発プラットフォーム。

しかし、この意味ではほとんど死語で、現在では以下で説明する。NET Frameworkの略語として使われることがほとんど。
なので、調べるときは.NETFrameworkと調べた方が良い。

ただし、この記事ではあえて.NETと. NET Frameworkは区別する。
(そもそも私がこの記事を書く中で初めて知ったように、何も知らない人にとってみればその方が分かりやすいと考えたため)

## .NET関連のフレームワークの共通点
.NET関連のフレームワークには共通点がいくつもある。
巨大すぎて全てを把握するのはとても困難だが、一つだけ重要なことを挙げるとすると

<b>中間言語を生成して、その中間言語をコンパイルする仕組みを持つ</b>

ということだ。

これは以下のような仕組みで成り立つ

1. ソースコードから中間言語(Common Intermedia Language, CILと略される)を生成
2. CILをコンパイルする

この仕組みを <b>共通言語ランタイム(CLR)</b> という。

ソースコードには C#、F#、Visual Basic などを用いる。

この仕組みのおかげで例えばC#とF#で書かれたプログラムは原理上同じものとして協働させることができる。

ちなみにCLRを実現するための実装は各フレームワークごとに異なっている模様。

# .NET Framework

前述の.NET構想のうち、特にWindows向けアプリケーションを実行するためのCLRと便利なライブラリを提供するフレームワークのこと。

<b>Windowsでしか動かない(ここ重要)</b>

逆にWindows開発するなら使うことになる。
Windows用のAPIなども簡単に使うことができる。

# .NET Core
主にサーバーサイドやコマンドラインツールなどを開発するためのフレームワーク。クロスプラットフォームなこと、オープンソースであることなどが特徴。GUI開発には向いてない？

# Xamarin
スマートフォン開発を中心にクロスプラットフォームなGUIアプリケーションをするためのフレームワーク。
関連用語にMonoというものがある。

### なぜ、Xamarinだけ.NETとついていないのか？
元々はXamarinという別の企業が開発していたものだから。
現在はMicrosoftが買収している。

### MonoとXamarin
Monoは元々OSSとして.NET互換を目的として登場した。その後、Monoを含む様々な機能をパッケージしたフレームワークとしてXamarinという名前になった。

# 参考
[.NET Framework の概要 | Microsoft Docs]
(https://docs.microsoft.com/ja-jp/dotnet/framework/get-started/)

[.NET Core の概要.NET Core introduction - Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/core/introduction)
→これのページに飛ぶとタイトルが.NETの概要となっているのが最高に紛らわしい


[Xamarin とは - Xamarin | Microsoft Docs]
(https://docs.microsoft.com/ja-jp/xamarin/get-started/what-is-xamarin)

[知ってるようでしらない！.NETとは | アトオシ]
(https://itpropartners.com/blog/8439/)

[.NET Framework / .NET Standard / .NET Core とは何か？]
(https://blog.hiros-dot.net/?p=9086)

[.NET とか Mono とか Xamarin とかいったい何？ Microsoftのプロダクト？]
(http://hatappo.hatenadiary.jp/entry/2016/06/29/224930)

[.NET Core / .NET Framework / Xamarin / Monoの関係を整理する]
(https://ascii.jp/elem/000/001/156/1156721/)
【個人的備忘録】7-DoFのロボットアームの手先位置をMATLABで求めてみた

#What?
　手計算だと不安だったので，検算のために下図の７DoFのロボットアームの手先位置をMATLABで求めてみた．
ついでに有顔ベクトルも求めた．

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483686/9e43beb5-5a2d-661a-b975-a539ab064107.png)

#実行コード
```matlab

syms theta1 theta2 theta3 theta4 theta5 theta6 theta7
syms l1 l2 l3 l4

%手先位置ベクトル

%%回転行列
R1 = [cos(theta1), 0, sin(theta1);
    0, 1, 0;
    -sin(theta1), 0, cos(theta1)]

R2 = [1, 0, 0;
    0, cos(theta2), -sin(theta2);
    0, sin(theta2), cos(theta2)]

R3 = [cos(theta3), -sin(theta3), 0;
    sin(theta3), cos(theta3), 0;
    0, 0, 1]

R4 = [1, 0, 0;
    0, cos(theta4), -sin(theta4);
    0, sin(theta4), cos(theta4)];

R5 = [cos(theta5), 0, sin(theta5)
    0, 1, 0;
    -sin(theta5), 0, cos(theta5)]

R6 = [1, 0, 0;
    0, cos(theta6), -sin(theta6);
    0, sin(theta6), cos(theta6)];

R7 = [cos(theta7), -sin(theta7), 0;
    sin(theta7), cos(theta7), 0;
    0, 0, 1]

%%初期状態のリンクベクトル
l1 = [l1;
    0;
    0]
l2 = [0;
    0;
    -l2]
l3 = [0;
    l3;
    0]
l4 = [0;
    l4;
    0]

%%演算
L1 = l1
L2 = R1*R2*R3*l2
L3 = R1*R2*R3*R4*R5*l3
L4 = R1*R2*R3*R4*R5*R6*R7*l4

Pr = L1 + L2 + L3 + L4

%有顔ベクトル
%%初期状態の有顔ベクトル
a = [0;
    1;
    0]
b = [0;
    0;
    1]

%%演算
A = R1*R2*R3*R4*R5*R6*R7*a
B = R1*R2*R3*R4*R5*R6*R7*b
```
結果は手計算と同じだったので安心．
Firestoreでドキュメント(document)削除したけど、サブコレクション(subcollection)消えないって人へ

####Firebase/Firestoreを使って、SNSの投稿機能を実装しようとしていました。
※違うところはご指摘いただけると幸いです。

#####ところが、投稿(posts/{postId})を削除したのにサブコレクション(comments/{comment}が消えないじゃないか...
documentとsubcollectionの表記が雑ですみません。

そこで色々調べてみましたが...
・CloudFuctionsを使って削除する
・別途commentsのdocumentを取ってきて削除するメソッド書く
という記事ばかり。

CloudFuctionsは、あまり動作が重くなる等の理由で非推奨みたいです。

なのでTutorialを見たりしつつ熟慮の結果、

```
func delete(collection: CollectionReference, batchSize: Int = 100, completion: @escaping (Error?) -> ()) {
        collection.limit(to: batchSize).getDocuments { (docset, error) in
            
            guard let docset = docset else {
                completion(error)
                return
            }
            
            guard docset.count > 0 else {
                completion(nil)
                return
            }
            
            let batch = collection.firestore.batch()
            docset.documents.forEach {batch.deleteDocument($0.reference)}
            batch.commit { (batchError) in
                
                if let batchError = batchError {
                    completion(batchError)
                }
                else {
                    self.delete(collection: collection, batchSize: batchSize, completion: completion)
                }
            }
        }
    }
```
この関数でうまく動きました。
completionの部分は、ご自身の作りたいものに合わせて適用させてください。

自分のメモ用であり、誰か一人でもいいのでお役に立てれば思います。
[エラー]background-image: image-urlでSassC::SyntaxError

# background-image: image-urlでSassC::SyntaxError 

デプロイ前にcssに記述したbackground-imageを
下記のように記述したら SassC::SyntaxError となりました。

```
background-image: image-url("IMG_4335 (1).JPG");
```

原因は文字間にスペースがあったからでした。
初歩的なミスに随分時間を費やしてしまいました。。
[ServiceNow] 関連リストの内容を Excel にダウンロード

ServiceNow のリストの内容を Excel にダウンロードできる機能は、ユーザーから好評の機能のひとつかと思います。
但し、関連リスト上で、リストの項目部分を右クリックしても、エクスポートのメニューが出てこず、Excel ダウンロードができません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/756088/5de6df03-00e7-f362-2e05-a946294b4034.png)
関連リストの内容を Excel にダウンロードしたい場合は、一旦、関連リストをメインのリストとして開く必要があります。
その方法は、関連リストのクエリー表示部を右クリック（上の画面キャプチャで言えば、「タスク = INC0010080」の部分を右クリック）し、「新規ウィンドウを開く」選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/756088/ed7a4f4f-eb40-605c-a3e1-42a89479a7aa.png)
こうすると、別タブに関連リストの内容がメインのリストとして表示されるので、通常の項目部分を右クリックしてエクスポートを選ぶことで、Excel や CSV にデータをダウンロードできるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/756088/7986c63c-237c-6232-c452-2089070ce2b3.png)
以上です。
RaspbianにOP-TEEをビルドする

2020/8/31

# RaspbianにOP-TEEをビルドする
公式で提供されているOP-TEEのファイルシステム（buildroot）では、apt-get機能が搭載されておらず、開発環境として非常にやりづらい。
<br>そのため、ファイルシステムをRaspbianに変更する。

<br>

## 環境
- ホストOS：windows10 + VMware
- ゲストOS：Ubuntu20.04.1
- 動作確認用機器：Raspberry Pi 3B
- その他：USB-UARTケーブル(あると便利)

<br>

## RaspbianをmicroSDカードへ書込む
Raspbianのダウンロード、microSDカードヘの書き込みは[このサイト](https://sukiburo.jp/setup-raspberry-pi/#)を参考にした。

<br>

具体的な手順としては以下の通り。

- [こちら](https://www.raspberrypi.org/downloads/raspberry-pi-os/)のサイトからRaspbianのイメージファイル(Raspberry Pi OS (32-bit) with desktop)をダウンロード。

- `SD Formatter`でmicroSDを綺麗な状態にする。

- `balenaEtcher`でRaspbianをmicroSDカードに書込む

- この状態でopteeを組込むと`sudo`や`root`が使えなくなる不具合が発生したので、念のため以下の作業を推奨する。

    - Raspbianでラズパイを立ち上げてrootのパスワードを設定
    
    ```
    $ sudo passwd root
    ```

    - `/etc/sudoers`に追記
    
    ```diff
    # User Privilege specification
    root    ALL=(ALL:ALL) ALL
    + pi     ALL=(ALL:ALL) ALL　　　
    ```

<br>

<details><summary>USB-UARTケーブルでPCとラズパイを接続する場合</summary><div>

- `/boot/cmdline.txt`で`console=serial0,115200`の部分を削除

- `/boot/config.txt`で以下を追記

```diff
$ vim /boot/config.txt
+ dtoverlay=pi3-miniuart-bt
+ core_freq=250
```

</div></details>

<br>

## PCでRaspbain-OPTEEをビルド
- OPTEEのビルドは[この公式ドキュメント](https://optee.readthedocs.io/en/latest/building/devices/rpi3.html)に従い、ビルドをした。

- [RaspbianOS向けのOPTEEを提供しているgithub](https://github.com/benhaz1024/raspbian-tee)があり、サイトの方法に従いビルドしたがそのままでは動かなかった。

- 動作が確認できた構成
    - `boot`：公式opteeのboot(version 3.6.0)
    - `rootfs`：Raspbian + [Raspbian向けopteeのrootfs](https://github.com/benhaz1024/raspbian-tee)
    > Raspbian向けopteeのrootfsは公式opteeのrootfsで代替え可能だと思われるが、その場合はbuildrootを混在しないように注意した方が良いかもしれない

<br>

公式opteeはドキュメント通りでビルドする。特にエラーは出なかったのでここでは割愛。<br>microSDカードに書き込まれているRaspbianのbootを削除し、opteeのbootに書き換える。<br>以降はRaspbian向けopteeのビルド方法を説明する。

<br>

## クロスコンパイルツールのダウンロード
linaroでクロスコンパイルツール`AARCH64` と `AARCH32`をインストール。具体的には[このサイト](https://releases.linaro.org/components/toolchain/binaries/)から以下のものを入手する。
- gcc-linaro-aarch64-linux-gnu.tar.xz(version:6.5.0)
- gcc-linaro-x86_64_arm-linux-gnueabihf.tar.xz(version:6.5.0)

<br>

## Raspbian向けopteeのリポジトリをダウンロード

```
$ git clone https://github.com/benhaz1024/raspbian-tee
$ cd raspbian-tee
$ mkdir -p toolchain/aarch32/bin ← AARCH64を入れる
$ mkdir -p toolchain/aarch64/bin ← AARCH32を入れる
```

## config.mkのpathを変更
パスを確認。ダウンロードしてきたディレクトリ名を合わせるか、パスを変更する。

```
$ vim config.mk
必要に応じてパズを変更
```


## 依存関係のモジュールをインストール

```
$ sudo apt install libssl-dev bison flex make u-boot-tools python-dev
$ pip install crypto
```

## ビルドの実行
```
$ ./prepare-env.sh
$ make patch
$ make
```

## microSDへのコピー
```
$ blkid ← microSDの割り振りを確認
$ mount /dev/sdx /media/rootfs
$ sudo cp -r ./out/rootfs/* /media/rootfs
```

## PCとRaspberry Piへの接続(シリアル通信)
VMware上のUbuntuとラズパイでシリアル接続

```
$ sudo picocom -b 115200 /dev/ttyUSB0
```

その後、ラズパイの電源を入れるとカーネルのログが流れて、ターミナルが立ち上がる。

<br>

## 参考
- https://releases.linaro.org/components/toolchain/binaries/
- https://github.com/benhaz1024/raspbian-tee
- https://optee.readthedocs.io/en/latest/building/devices/rpi3.html
- https://www.raspberrypi.org/downloads/raspberry-pi-os/
Raspberry Pi3 用にOP-TEEをビルドする

2020/8/18

# Raspberry Pi3 用にOP-TEEをビルドする

## OP-TEEのビルド、実行の流れ
- ビルド自体はPCで行い、ビルドしたものをmicroSDカードに書き込み、ラズパイに差し込んで起動する

## ビルド環境
- Linuxでのビルドが推奨されているため、Windows10上でVitualboxを利用し、Ubuntu20.04.01でビルドを行った。

[^1]: Ubuntuの仮想ハードディスクは10GBじゃ足りなかったため、20GBで行った

- 詳細環境
    - Virtual Box：6.1.12
    - ホストOS：Windows10
    - ゲストOS：Ubuntu20.04.01
    - microSDカード：32GB


## ビルド手順

- i386アーキテクチャパッケージのインストールを有効にし、パッケージマネージャデータベースを更新

```
$ sudo dpkg --add-architecture i386
$ sudo apt update && sudo apt upgrade
```


- OP-TEEのビルドにはgit、pythonが必要

```
$ sudo apt install git
$ sudo apt install python
```

- 必要なパッケージをインストール

```
$ sudo apt-get install android-tools-adb android-tools-fastboot autoconf \
    automake bc bison build-essential cscope curl device-tree-compiler \
    expect flex ftp-upload gdisk iasl libattr1-dev libc6:i386 libcap-dev \
    libfdt-dev libftdi-dev libglib2.0-dev libhidapi-dev libncurses5-dev \
    libpixman-1-dev libssl-dev libstdc++6:i386 libtool libz1:i386 make \
    mtools netcat python-crypto python-wand unzip uuid-dev \
    xdg-utils xterm xz-utils zlib1g-dev
```

Android repoのインストール
- ディレクトリ、パスの設定

```
$ mkdir ~/bin
$ PATH=~/bin:$PATH
```

- Repoツールをダウンロードし、実行可能であることを確認

```
$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
$ chmod a+x ~/bin/repo
```

- gitのアカウント、パスワードを設定

```
$ git config --global user.name "Your Name"
$ git config --global user.email "you@example.com"
```

- OP-TEEソースファイルをダウンロード

```
$ mkdir -p $HOME/devel/optee
$ cd $HOME/devel/optee
$ repo init -u https://github.com/OP-TEE/manifest.git -m rpi3.xml
$ repo sync
```

[^1]: reposyncは時間がかかります

- ツールチェーンの作成

```
$ cd build
$ make (必要なら：-j2) toolchains
```

[^1]: 時間かかります

- OP-TEEのビルド

```
$ make
```

[^1]: 時間かかります

- imgファイルへの展開
- 表示された手順通りにSDカードへ書き込む

```
$ make img-help
```


OP-TEEのファイル構成（PC）

![dir.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423218/372b7040-26d4-9897-1641-6034a9fd8a93.png)



## 参考
ビルドの記事
- https://optee.readthedocs.io/en/latest/building/devices/rpi3.html
- https://www.youtube.com/watch?v=-IcC2b3AJdA&t=246s
- https://blog.crysys.hu/2018/06/op-tee-default-build-and-installation-on-the-raspberry-pi/
エミュレータ
- https://lepidum.co.jp/blog/2020-03-13/tee/
Flutter製アプリをAndroid向けにリリースしようと準備し始めたらエラーが止まらなかった

# やろうとしたこと
制作中だったアプリが一通り完成したため、Google Play Storeで公開するための準備を始めました。

# 起こった問題
ネット上の情報を頼りに作業を進めていくと、"Package name"を変更するタイミングが来るはずです。
私は

- app/build.gradle
- main/AndroidManifest.xml 
- debug/AndroidManifest.xml


の3箇所を変更しました。
しかし、この Package name を変更した直後からよくわからないバグが発生しました。

# 解決方法
結論からいうと`MainActivity.kt`の1行目の Package name を修正し忘れていました。
[この記事](https://qiita.com/osamu1203/items/6adfab47e562f5e7d03b)が参考になります。

# 最後に
あまり多くの人に起きるエラーじゃないかなとも思いましたが、自分は結構時間を溶かしてしまったので同じ問題を抱えた誰かに届くといいなと思っています。
品質分析をしてみてわかったテストの在るべき形

タイトルはUVERworldの「在るべき形」を聞いていたらこうなりました。影響されやすいタイプ。

お仕事でテストの品質分析をして報告書を書く、ということを始めてさせてもらったので、やってみて感じたこととかを書きます。

## 品質分析のセオリー

* **定量分析⇒定性分析の順で分析**
まずは確実に出せる数字を見て、それを根拠に定性的に問題の有無を判断していきます。異常な数値が出ているものをピックアップして深堀りしていき、問題の有無を調査します。

* **ステップ数は厳密な数字が出せるものではない**
ステップ数をカウントするツールによってばらつきがあるし、空行を含めるとかコメントを含めるとかによっても変化します。
また共通的な部品のステップ数をどう扱うかによっても変わってくるので、完璧に数字を出すのは、よほど事前の準備をしておかないと不可能。
規模感が把握できれば、正確さはおおよそで問題ないです。
自分は実行ステップ数でカウントしているが、それに限らず何らかの一定の基準で算出していればそれでいいと思っています。
算出の基準があれば、他と比べて異常なテスト密度、バグ密度の機能を素直に「怪しい」と言えるようになります。

* **ソースファイル⇔機能のステップ数の振り分け**
機能へのステップ数の振り分けは、機能ごとにソースの正しい役割分担ができていれば、そんなに苦労しない気がします。
自分が担当している案件は、かなりレガシー&フレームワークなし&設計思想もよくわからないって感じなので、これでかなり苦労しました。手作業で集計してコミットログを見ながら適度に割り振るというパワープレイをおよそ4時間も。。。

そもそも、ステップ数を基準に品質を判定する作業には、批判が多い(そんな単純化しても難易度が違いすぎて根拠のある数字になるわけがないetc...)。
なおさら、ステップ数にこだわりすぎるのは良くない。というかそこにこだわる意味はあまりありません。
あくまで客観的事実から取得できる情報(テスト密度、バグ密度など)は、根拠にはなるが品質を証明するまでの力はありません。この値を軸に、しっかり問題を洗い出し、(テスト仕様書などを)目で見る、(テスト担当者の声を)耳で聞くなどして、品質を証明していく作業が重要です。
そんな定性的な分析ほど経験や知見、勘所が重要に。まだまだ精進しなければ。。。

※PMからは定性分析良くできてるって褒められた、嬉しい。。。！

## 指標値と定量⇔定性分析のつながり

#### テスト密度

*テスト密度(件/KS) = テスト項目数(件) / ステップ数(KS)*

対象のステップ数あたりのテスト項目数を割合として算出します。

#### バグ密度

*バグ密度(件/KS) = バグ検出数(件) / ステップ数(KS)*

対象のステップ数あたりのバグ検出数を割合として算出します。


これら指標値の評価には、水準となる値が必要です。
結合テスト以降のフェーズであれば、IPAのソフトウェア白書に載っている数値が使えます。
単体テストは、公式な水準値というものはないと思う。企業ごとに内部で持っているものを使うような感じかな？

続いて、指標値の解釈の仕方も簡単に書きます。


* **テスト密度が高く、バグ密度も高い場合**
単純にバグが多い状態である可能性が高いです。設計、製造の品質面を疑う必要があります。

* **テスト密度が低く、バグ密度が高い場合**
テストが不十分なのにバグが多いということは、十分なテストをしたらさらに大量のバグが検出されるかもしれません。
かなりマズい状態です。早急に原因を突き止めましょう。

* **テスト密度が高く、バグ密度が低い場合**
高品質の状態であるか、テストの観点がずれているかのパターンが考えられます。実施されたテストの網羅性を確認しましょう。
十分にパターンを網羅したテストを実施してバグ密度が低いのであれば、高品質であると結論付けて問題ないです。

* **テスト密度が低く、バグ密度も低い場合**
単純にテストが足りていない状態である可能性が高いです。十分なテストを実施させてから、再度品質を判定しましょう。



## 品質分析の観点から見た「こんなテストはいやだ」
懐かしいネタをオマージュしていきます。

* **テストの粒度のばらつきが激しい**
担当者によってテストの粒度がバラバラになると、何が正しいのかわからなくなって全体的に深堀りしなくちゃいけなくて大変。プロジェクト内でテストフェーズごとの観点が共有されておらず、個人の知識、経験にゆだねられてしまうことなどが原因として考えられます。
テストを作るときにマトリクスを作るが、このマトリクスが人によってやっていることがバラバラ(よもやマトリクスなしでケースを作っている担当者もいた)。モデルを見せるなりマトリクスを作った段階でレビューをすることで、この段階から属人性を排除していかなければいけない。

* **検出したバグの詳細を担当者しか知らない**
テストのマトリクスであったり、障害一覧であったり、もちろんテスト仕様書も、テストをしている自分だけがわかればいいというものではありません。読み手に情報が過不足なく伝わるように資料の情報を記入する必要があります。これをおざなりにすると、後に品質分析の際にはバグの内容までチェックされることがあるので、そこで「何だこれは？」となってしまいます。問い詰められちゃうかもね。
ちゃんと情報が伝わるように資料が書けないのであれば、早いフェーズからでもエビデンスの取得を省かないほうがいいです。
何も情報が残っていないよりは、画面キャプチャが残っていたほうがまだ事象の確認ができます。(取る側も見る側もめんどくさいけど)

* **担当者によって品質にばらつきがある**
担当者の熟練度によって製造段階での品質に違いがあるというのはまあわかるが、テストの密度なんかはばらついてはいけないと思います。
「仕方ない」を乗り越えて、プロジェクト全体としての品質の向上を目指していく必要があります。属人化してはいけません。
⇒たとえば、熟練者が若手とペアとなり、品質面のサポートをする関係を組む(ライトなペアプログラミング的な)。熟練者同士でテストの粒度などについて合意を取り、ペアの若手にその意図を説明して、テストの序盤には多めにレビューを実施する。

## テストをする側として意識しておきたいこと

* マトリクスを作った段階で周囲と粒度を合わせる。レビューを受けたり、軽い相談のレベルでも誰かにそのマトリクスを見せる。
* 文章を書くときは、伝わりやすく簡潔に、情報が漏れなくダブりなく伝達できるように書く。そして客観的に振り返る。
* おおよその自分の担当した機能のステップ数を把握し、テスト密度、バグ密度などを自分で評価する癖をつけておく。
標準的な指標値を控えておき、それと照らし合わせて、「自分、テスト足りてなくない？」とか「ちょっとバグ出すぎじゃない？」とかの視点でテストができるようにしておく。
* 障害一覧は品質についての情報の宝庫にできるように、バグが出たらすぐに、ありありと情報を書いていこう。原因の区分などはしっかり考えて、最適なものを選択するようにしよう。適当にしない！


****
感じたことを感じたままに書いてみました。駄文もいいところ。
これからもこんな観点を持ち続けながら、テスト頑張っていこうと思います。
AWSからのアカウント停止メール！？

休み明けの月曜日
メールを開くとAWSから以下のようなメールが届いていた


>Dear Amazon Web Services Customer,
>
>Your AWS Account is about to be suspended. There is still an outstanding payment problem with your account, as our previous communications did not lead to successful payment of your past due AWS charges.
>～以下略～

英語はもっぱら駄目なのでGoogle先生に翻訳してもらうと

>アマゾンウェブサービスのお客様へ、
>
>AWSアカウントが停止されようとしています。以前の連絡ではAWSの延滞料金の支払いが成功しなかったため、アカウントには未解決の支払いの問題がまだあります。
>～The following is omitted～

朝っぱらから背筋が凍るメール
(以前からメールは来ていたが埋もれて気づけなかった。。。)

[AWSサポートセンター](https://console.aws.amazon.com/support/home#)に電話していつ頃に停止するか確認したところ、**滞納月の翌月中旬から下旬の間に停止します**との事。
期限はあったが、重大なトラブルの為、コンソール画面から支払いカードを確認し、総務に問い合わせると引き落とし先の口座に残金が無いかもしれないとのこと。
あまりの事態に前任者に連絡したところ、よくあることだから別のカードで対応していたと・・・

　
そんな管理で大丈夫かと思いながらも、口座への入金と別のカード情報を貰い、別のパターンで支払いができるかを調べてみて以下のことが分かった。
###AWSの支払い方法
####▼引き落とせるカードは『VISAカード』か『Masterカード』
　別のカードでの支払いをした際に、VISAでもMasterでもないカードで支払いをしようとしていた為、引き落としのエラーメールが届いてしまった。
####▼振り込みはできないが、『海外送金』は可能
　AWSはAmazonの会社の為、振り込みは海外送金での対応となる。
また以下の条件を満たした状態で[AWSサポートセンター](https://console.aws.amazon.com/support/home#/)連絡すると送金先の口座情報を教えてもらえるらしい。
・今までのAWSの使用料金が2000$を超えていること
・支払い滞納ではないこと
・送金はUS＄で送金すること　

　
　
今回の問題は、支払い滞納の為『海外送金』ができない。
詰んだと思っていたところ、口座へ入金したとの連絡がきたので支払いをしたところ無事に支払えた！
※午前中に入金し、すぐに支払いしてもエラーになる。
　数時間経ち午後に支払いができたので気を付けておくこと。


#まとめ
・支払い滞納によるアカウント停止は翌月の中旬から下旬にかけて停止される。
・引き落とせるカードは『VISAカード』か『Masterカード』
・『海外送金』はできるが、条件がある。
・カードに入金してもすぐに反映しない
Android11 SDK30でpackage名を取得できなくなった問題

最近Android11になってから動作しない問題がちょくちょく続いてます。
皆さんはどうでしょうか??

前置きが長かったですが、さくっと修正方法紹介します。
パッケージのアクセス方法がAndroid11から変更されたみたいです。

## 従来のコード

```
val packages: List<PackageInfo> = context.packageManager.getInstalledPackages(flag)
val packageNames: List<String> = packages.map { it.packageName }
```

## 追加
AndroidManifestに追加

``` 
<manifest package="com.example.game">
    <queries>
        <package android:name="com.example.store" />
        <package android:name="com.example.services" />
    </queries>
    ...
</manifest>
```

## 参考
https://developer.android.com/preview/privacy/package-visibility?hl=ja