OmniAICreator/Qiita-1.07M huggingface dataset:
【NestJS】TypeORMのMigrationを実装する

#はじめに
TypeORMのMigrationについてのメモです。

NestJSに関するこれまでの記事については以下をご覧ください。

https://qiita.com/suzuki0430/items/d15c8642b46b57cdf91b

https://qiita.com/suzuki0430/items/697601370b078cc65fd6

https://qiita.com/suzuki0430/items/ac5ccc587e75a19bb567

https://qiita.com/suzuki0430/items/e4f8cabc61fc1fd41dcc

https://qiita.com/suzuki0430/items/465628e3f47a1d2311d6

https://qiita.com/suzuki0430/items/48bdcecd8f3b42e9cef6

実装したコードを確認したい方は以下よりご確認ください。

https://github.com/suzuki0430/car-api-nest

#実装
AppModuleの`synchronize`の設定がtrueだと、アプリケーションをデプロイしたときにDBのテーブルがEntityから自動的に生成されます。
Entityの状態がDBに同期されるため一見便利にみえますが、Entityのカラムを消したときにDBのカラムも消えてしまうため、誤ってPasswordのカラムを消してしまうなどのリスクがあります。

そのため、本番環境のデプロイ前になったら`synchronize: false`にして、マイグレーションファイルを元に手動でDBの状態を更新してあげるようにします。

TypeORMではDBに接続するための情報`type` `database` `entities`が必要となります。
Moduleにこれらの情報を記述しても読み込まれないので、`ormconfig.js`にそれぞれの設定を記述して`module.exports`してあげます。
開発環境`development`、テスト環境`test`、本番環境`production`で接続するDBの種類などが異なるので、switch文で設定を切り替えます。

```ormconfig.js
var dbConfig = {
  synchronize: false,
  migrations: ['migrations/*.js'],
  cli: {
    migrationsDir: 'migrations',
  },
};

switch (process.env.NODE_ENV) {
  case 'development':
    module.exports = Object.assign(dbConfig, {
      type: 'sqlite',
      database: 'db.sqlite',
      entities: ['**/*.entity.js'],
    });
    break;
  case 'test':
    module.exports = Object.assign(dbConfig, {
      type: 'sqlite',
      database: 'test.sqlite',
      entities: ['**/*.entity.ts'],
      migrationsRun: true,
    });
    break;
  case 'production':
    module.exports = Object.assign(dbConfig, {
      type: 'postgres',
      url: process.env.DATABASE_URL,
      migrationsRun: true,
      entities: ['**/*.entity.js'],
      ssl: {
        rejectUnauthorized: false,
      },
    });
    break;
  default:
    throw new Error('unknown error');
}
```

つぎに`package.json`の`scripts`へ以下を追記します。

```
"typeorm": "cross-env NODE_ENV=development node --require ts-node/register ./node_modules/typeorm/cli.js"
```

以下のコマンドでマイグレーションファイルが生成されます。

```
npm run typeorm migration:generate -- -n initial-schema -o
```

そして以下のコマンドでマイグレーションファイルを元にmigrate(DBテーブルの生成)が実行されます。

```
npm run typeorm migration:run
```

#参考資料

https://www.udemy.com/share/104SA43@5iHng3mXCUwhKvkqKp79zmFdmB999CLF2Bm6VZyebKenD1rjzDnn_4JeokhgumWA/
pythonのos.path.joinについてざっくりまとめる

### 本日のお題
本日のお題はpythonのos.path.joinです。

このコードは、パスを繋げて新しいパスを生成する役割を持っています。

djangoを学習していたところcssファイルの読み込み経路の設定でこのos.path.joinの知識が出てきたので、備忘録として残しておきます。
### 目次
- os.path.joinの文型
- 注意点１〜リスト型のパスの結合
- 注意点２〜/を含むパスについて

### os.path.joinの文型
os.path.joinの基本構文及び具体的な使用例は以下の通りです。
また、osモジュールはimportが必要です。

```python
# import
import os

# 基本構文
os.path.join("パス１", "パス2")

# 具体例
path = os.path.join( ("main", "project1/test1")
```
以下の例では、pathという変数に"main/project1/test1というパスが代入されています。

第一引数の下流に第二引数が連結されることに注意してください。
### 注意点１〜リスト型のパスの結合
リスト型のパスを結合する場合には、以下のように記述します。

```python
list = ["main", "project1", "test1"]
path = os.path.join(*list)
```
### 注意点２〜/を含むパスについて
os.path.joinには、"/main"などの先頭に/を含むパスをルートパスとして解釈してしまう、という性質があります。

これはなんとなく分かりますね。
ターミナルでのパス表記もルートディレクトリは/で表されているので。

/で始まるパスを結合した場合の具体例は以下になります。

```python
path = os.path.join("/main", "/project1", "/test1")

print(path) #結果："/test1"
```
このような場合はreplaceメソッドを用いて/を取り除いてあげることで、意図した通りのパスを取得できるようになります。

```python
list = ["/main", "/project", "/test"]
list = [dir.replace("/", "") for dir in list] # for inを用いて要素の/を全て削除
path = os.path.join(*list)
```
### 終わりに
以上がos.path.joinの使い方になります。
次回はこれを用いてcssファイル・画像ファイルの配置を指定していきます。
Selenium Gridの環境を構築する（docker-compose利用）

## クライアントも WebDriver もブラウザ本体もローカルで稼働する場合

macOS を利用している場合は、ChromeDriver などのドライバーを格納したディレクトリで以下のコマンドを実行して、実行可能にしてから使用する。

```bash
sudo xattr -d -r com.apple.quarantine chromedriver
```

Safari は WebDriver は不要で、Safari の設定で「開発」から「リモートオートメーションを許可」とするだけでよい。

Chrome や Firefox(geckodriver) を利用する場合は、WebDriver へのパスを指定する必要がある。

```java
System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");
ChromeOptions options = new ChromeOptions();
WebDriver driver = new ChromeDriver(options);
```

## クライアントはローカルで稼働し、 Hub と Node は Grid を構成するコンテナ内で稼働する場合

複数のコンテナが必要なので、docker-compose を利用するのが楽。
以下の yml がそのまま使える。
https://github.com/SeleniumHQ/docker-selenium/blob/trunk/docker-compose-v3.yml

```bash
docker-compose -f docker-compose-v3.yml up
```

Java でクライアントを利用する例。options は必要なものを設定する。最後の URL は Hub にアクセスできる URL を指定する。docker-machine を利用する場合、`docker-machine ip default`の IP アドレス を hosts に記載しておくと楽。RemoteWebDriver を利用する場合は、`webdriver.chrome.driver`のような webdriver のパスの指定は node 側に存在するため、クライアント側は hub の URL のみを指定すれば良い。クライアントのコード上は環境固有の情報がなくなってスッキリするが、ローカルで稼働させた場合よりもパフォーマンスが劣化する。

```java
DesiredCapabilities dc = DesiredCapabilities.chrome();
dc.setBrowserName("chrome");
dc.setPlatform(Platform.LINUX);
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless", "--disable-gpu", "--window-size=1024,768");
dc.setCapability(ChromeOptions.CAPABILITY, options);
WebDriver driver = new RemoteWebDriver(new URL("http://docker-machine:4444"), dc);
```

ブラウザで4444番ポートを開くと、Hubの下にぶら下がっているNodeを確認できる。
![スクリーンショット 2021-10-24 17.49.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376039/715d0469-f5a5-120f-300c-8b391d155b1a.png)


## クライアントはローカルで稼働し、 Hub と Node は standalone コンテナ内で稼働する場合

Hub と Node は standalone コンテナに入っているのでコンテナ一つを稼働すれば良い。

```bash
# docker-composeを用いない場合
docker run --rm -d -p 4444:4444 -p 7900:7900 --shm-size=2gb selenium/standalone-chrome:4.0.0-20211013
```

Java コードは Grid の例と同じ。

## （補足）Hub と Node を個別に起動する方法

```bash
# hubを起動する
java -jar selenium-server-4.0.0.jar hub
# nodeを起動する
# macOS の場合、Safari は webdriver のパスを指定する必要はない。portとmax-sessionsは適宜設定
java -Dwebdriver.chrome.driver=/path/to/chromedriver -Dwebdriver.gecko.driver=/path/to/geckodriver -jar selenium-server-4.0.0.jar node --hub http://localhost:4444/ --port 5555 --max-sessions 1
```

## （補足）コンテナを用いている場合に操作中の画面を参照する方法

7900 番ポートをブラウザで開くと参照できる(headless にしているとダメ)。macOS で docker-machine を使っている場合は以下のコマンドでコマンドでブラウザを開ける。

```bash
open http://$(docker-machine ip default):7900/
```
【Laravel】PHP環境からWebAPI(Laravel)へPOSTする

## はじめに
PHP製のアプリケーションAからアプリケーションB(PHP7.3・Laravel6.3)のWebAPIに対してPOSTリクエストを送信することを想定します。
異なるアプリケーションからWebAPIを叩く方法を初めて実装したので、実施した内容を整理しようと思います。

## 環境
- PHP
  - V 5.6
  - V 7.3
- Laravel(6.4)

## クライアント側の実装
クライアント側(リクエスト送信側)ではPHP5.6を使用したアプリケーションです。  
こちら側で、Laravel製のアプリケーション(PHP7.3 / Laravel6.4)のWebAPIを叩くメソッドを実装します。
今回、WebAPIを叩くために、PHPの標準機能である「curl」をしようします。

```php:request.php
$base_url    = 'https://xxx.xxx.xxx.xxx';   // アプリケーションBのドメイン
$destination = 'api/hoge';                  // アプリケーションBのAPIのパス

$header = [
  'Content-Type: application/json',         // json形式のデータをpostするので必要
];

$params = [
  'hoge' => 'hoge',
  'fuga' => 'fuga'
];  // 対象APIへのリクエストパラメータ

$curl = curl_init();                                                // curlの初期化
curl_setopt($curl, CURLOPT_URL, $base_url.$destination);            // curlするURL
curl_setopt($curl, CURLOPT_POST, TRUE);                             // POSTメソッド指定
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($params));  // parameter クエリ文字列にエンコードしてpost
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);                    // HTTPヘッダー
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);                  // 証明書の検証を無効化
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);                  // 証明書の検証を無効化
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);                   // 返り値を文字列に変更
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE);                   // Locationヘッダを追跡

$output= curl_exec($curl);      // curlの実行・レスポンス
$result = json_decode($output); // JSONを連想配列にパース

curl_close($curl);  // コネクションを閉じる

```

## APIサーバ側の実装
アプリケーションAからcurlでPOSTリクエストされるAPIの実装を行います。

```php:hogeApi.php
$dataJsonString = file_get_contents(‘php://input’);
// リクエストデータを加工
$dataList = [];
foreach (explode(‘&’, $dataJsonString) as $data) {
    $tmpList = explode(‘=’, $data);
    $key = $tmpList[0];
    $val = $tmpList[1];
    $dataList[$key] = $val;
}
```

### 注意点
リクエストパラメータについて、APIで処理するために連想配列に加工することを目標とします。
Larvelのrequestヘルパー関数では、postされたパラメータを受け取ることができませんでした。
また、PHPの標準関数である$_POSTでも受け取れません。  
そこで、上記のように、***file_get_contents***関数を使用して、POSTデータを受け取ります。

### file_get_contentsについて

[公式]([https://www.php.net/manual/ja/function.file-get-contents.php)

- 生のPOSTデータを取得する方法です。
- 何故生のPOSTデータを取得する必要があるのか？
  - 通常のPOSTデータはKeyとValueの組み合わせによる連想配列の形式となるが、  
  JSON形式に変換することで文字列のみとなり、標準の「$_POST」では形式が合わず取得が出来なくなるためと思われます。


## 最後に
PHPの標準機能である***curl***と***file_get_contents***をもちいて、アプリケーション間の処理の受け渡しを実装することができました。
【JavaScript】関数とオブジェクト⑨　コンストラクター関数


#はじめに

Udemyの[【JS】ガチで学びたい人のためのJavaScriptメカニズム](https://www.udemy.com/course/javascript-essence/)の講座の振り返りです。

前回の記事

https://qiita.com/nao0725/items/5e2a32592870be7b3436

#目的

* 関数とオブジェクトについての理解を深める

#本題
###1.コンストラクター関数

* コンストラクター関数とは新しく**オブジェクトを作成する**ための雛形となる関数のこと。
* new演算子を使用する。

`````js
const b = new A();
`````

* newでオブジェクトを作成すること(new A())を**インスタンス化**という
* newで作成したオブジェクト(b)のことを**インスタンス**という

###例1

インスタンス化

```js
// 関数を定義
// 普通の関数と区別するために大文字で定義する
function Person(name,age){
  // 格納したいプロパティを定義
  this.name = name;
  this.age = age;
}
// new演算子を用いてインスタンス化
const a = new Person("武田", 30);
console.log(a);
`````

````実行結果.
Person {name: '武田', age: 30}
age: 30
name: "武田"
[[Prototype]]: Object
``````

`````js
// 他のオブジェクトも生成
const b = new Person("双葉", 25);
const c = new Person("風間", 28);
``````
ブラウザ上で確認すると以下の通り

````実行結果.
b
Person {name: '双葉', age: 25}
c
Person {name: '風間', age: 28}
``````

オブジェクトとして生成される

テンプレート化されたオブジェクトを使いまわしできる

今日はここまで！

#参考にさせて頂いた記事

* [【JS】ガチで学びたい人のためのJavaScriptメカニズム](https://www.udemy.com/course/javascript-essence/)
GASでChatworkを利用した問合せボット

![20211024-00.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145508/43f29b1d-7785-716a-e72a-3ea382e7e9be.jpeg)

「第6章 スプレッドシートで問合せボットをつくる」を試してみました。

「Google Apps Script」と「Chatwork」で問合せボットが作成できます。

質問する時は単語をスペース（半角でも全角でもOK）で区切って投稿します。
自然文（話し言葉）を解析する機能は実装していません。

参考書籍

[Google Apps Scriptのツボとコツがゼッタイにわかる本](https://ameblo.jp/ak09z/entry-12705878538.html)
[Unity] UnityでFirebase AuthのGoogle認証をする方法の個人的メモ

## はじめに
UnityでFirebase AuthのGoogle認証を実装する方法が煩雑すぎたので、備忘録も兼ねてまとめます。
対象のプラットフォームはAndroid (とiOS?) です。

## 使用するツール
Unity 2021.1.14f1
external-dependency-manager 1.2.166
google-signin-plugin 1.0.4
Firebase SDK

## google-signin-unityの導入
1. [google-signin-unity](https://github.com/googlesamples/google-signin-unity/releases)をインポート
2. `PlayServiceResolver/` と `Parse/Plugins/` の `Unity.Tasks` と `Unity.Compat` を削除
3. [external-dependency-manager](https://github.com/googlesamples/unity-jar-resolver)をインポート
4. `GoogleSignIn\Editor\m2repository\com\google\signin\google-signin-support\1.0.4\`  内の `.srcaar` を全て `.aar` に置換  
   Unity Editorから `google-signin-support-1.0.4` の設定を以下のように変更  
   参考:
   https://github.com/googlesamples/google-signin-unity/issues/106  
![pibrary-for-unity-fixed - Auth Scene - Android - Unity 2021.1.14f1 Personal _DX11_ 2021_10_24 17_56_27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/897118/431eb7d7-fceb-bee5-b6a5-67b293bff14b.png) 
5. `Assets/External Dependency Manager/Android Resolver/Resolve (or Force Resolve)` からResolverを実行

## Firebase Authの導入
1. FirebaseコンソールからFirebase SDKパッケージをダウンロード
2. `dotnet3/FirebaseAuth.unitypackage` をインポート
3. `Parse/Plugins/` の `Unity.Tasks` と `Unity.Compat` を削除
4. `Parse/Plugins/dotNet45/` の `Unity.Tasks` と `Unity.Compat` の設定を以下のように変更  
   ![pibrary-for-unity-fixed - Auth Scene - Android - Unity 2021.1.14f1 Personal _DX11_ 2021_10_24 17_56_21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/897118/a82ac354-901e-84cb-2000-013924277581.png)
5. `Assets/External Dependency Manager/Version Handler/Update/`を実行
6. Unity Editorを再起動

## おわりに
私は以下の方法でFirebase Authとgoogle-signin-unityを有効化できました。以下にgoogle-signin-unityの導入例を載せておきます。
https://github.com/Harineko0/google-signin-unity-example
https://github.com/Harineko0/pibrary-for-unity-fixed
RAIDログ（ディスク冗長化とは無関係なやつ）

## はじめに

「RAIDログ」って聞いて、何をイメージしますでしょうか？
恥ずかしながら、僕はディスク冗長化（RAID0とかRAID10とか）の仕組みの中で出力されるシステムログのことだと思っていました。
しかしながら、プロジェクトマネジメントの中で用いられるリスクなどの管理手段のことでした。
日本語ではあまり検索しても情報見つからなかったので、同じような誤解を持っている人が減るように、記事に残したいと思います。

# RAIDログとは？

RAIDとは、リスク（Risks）、仮定（Assumptions）、課題（Issues）、依存関係（Dependencies）、それぞれの頭文字になります。
「ログ」とはいいつつ、アクセスログやシステムログのようなものとは、タイプが異なります。
RAIDログは、プロジェクト管理の中で、リスク・仮定・課題・依存関係を認識し追跡するために用いることができます。

RAID要素のそれぞれについて、以下に概要を説明します。

### リスク（Risks）
こちらは、日本でも割とよく用いられるリスクマネジメントで使われている単語と同等です。
人的、システム的、あらゆる面で、ネガティブな影響を与える可能性のある要素になります。

例）

* 悪意ある外部の攻撃者によるシステム停止
* うっかりミスによる機密データの漏洩
* 盗難による資産の損失

### 仮定（Assumptions）
プロジェクトを成功に導くと想定される事柄になります。
「想定される」なので、ネガティブな結果になる可能性もあります。
Actionと定義されている情報もありました。

例）

* 品質を上げるため、検査項目を増やす
* 顧客満足度を上げるため、納期を短縮する

### 課題（Issues）
プロジェクトの中で発生した問題事項になります。
こちらも、プロジェクトマネジメントの中でよく聞く単語になります。
リスクが、まだ未発生のものに対し、こちらはすでに発生しているもの、あるいは発生することが確定したものになります。

例）

* 予想よりも多くのアクセスが発生しているため、Webページでタイムアウトが頻発している
* クラウドサービスのコストが、見積もりよりも大幅に超過している

### 依存関係（Dependencies）
プロジェクトの結果に影響を与える、または、影響を受ける外部要素（作業や契約など）。
全体的な計画を立てる上で重要になります。

例）

* プロジェクトの完了が、次の契約を受けるための前提条件になっている
* プロジェクトで利用する別プロジェクトで作成中のモジュール

# RAIDログはどのようなときに有効？

なんとなく、RAIDログがどんなものか、イメージいただけたかと思います。
それでは、どのように使うものなのでしょうか？

現在、プロジェクト管理をされている方でRAIDログをご存知なかった方も、それぞれの要素は既知感があると思います。
それぞれ、プロジェクト管理の中では重要なものばかりです。
すでにこれらの要素を適切に管理できている状況下では、無理に追加する必要はないかと思います。日本語で情報が少ない要因の一つかも知れません。

一方、RAIDログでは、これらを一元的に管理することで、見通しを良くすることができます。
個別で行っている場合、例えば、課題の解消に時間がかかった際に、依存関係への考慮が疎かだと外部に影響を与えてしまうことがあります。
また別の例では、仮定を進めていく中で、新たなリスクが生じていたが、リスクアセスメントへの反映が漏れることもあります。
一箇所でまとめて管理することで、RAIDそれぞれの関係性においても適切にアップデートすることが可能になります。

## どのように使うか？

RAIDログとしての、規定のテンプレートはありません。
いくつかインターネット上で見つかった例を貼っておきます。

![Screenshot at Oct 24 17-24-16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/f770715b-a8d8-2abe-b5d2-8626062e79fe.png)
<引用：　https://www.groupmap.com/map-templates/raid-log/>

![Screenshot at Oct 24 17-24-57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/2edbf3be-2854-947c-a44f-15fa9330ef39.png)

<引用：　https://citoolkit.com/articles/raid-log/>


既定のテンプレートがないということは、自分好みに変えてもいいということです。
僕自身は、一つのスプレッドシートで、RAIDそれぞれ別シートのままで集約するところから始めてみようと思います。

この記事が、僕のように、「RAIDログ」というワードを知らなかった人の何かの役に立てば幸い :)
Firebase Hosting + React Router でURL変化後にF5しても画面表示できない場合の対応

# React RouterによるURL制御後、F5を押すとなぜか白くなる
ログを見ると、全リクエスト（js,cssまでも）のレスポンスがindex.htmlの内容に・・・。

## firebase.jsonの内容
firebase.jsonのhosting > rewritesの内容は、以下の通り。
なお、rewritesの内容は、存在しないファイルやパスへのアクセス時に参照される。

```
   "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ],

```

## つまり・・・
どうやら、画面遷移後の再表示時のJSファイルのアクセスなどが、firebase.jsonのrewritesの動作対象になったようだ。

## 原因
1. URLが変化
1. rewritesにより、ページのコンテンツは/index.html
1. しかし、index.htmlから参照していたJSファイルへのパスは`相対パス`。
1. これにより、そのページからJSファイルを相対アクセスし、404が発生
1. そのJSファイルアクセスに対して、`rewrites`が動作。
1. JSファイルのリクエストに対するレスポンスもindex.htmlへ・・・

# 対応
## 対応前package.json
```
"homepage": ".",
```

## 対応後package.json
```
"homepage": "/",
```

# firebase.json
特に変更なし。
【LWC】refreshApexで画面の更新

#保存ボタン押下後に画面を更新する
LWCではレコードの更新時にlightning-record-edit-formを使えば画面を再描画してくれますがlightning-inputやlightning-datatableを使ってレコードを更新したときは画面は再描画がされません。強制的に画面をリロードさせたり、手動でリロードるのはUI的に良くないです。
調べたところLWCには標準でrefrshApex()という@wireを介してプロビジョニングされたApexデータを更新できます。

#refreshApexのインポート
他の標準で用意されている関数と同様にインポートします。

```javascript
import { refreshApex } from '@salesforce/apex';
```
#レコードのupdate後にrefreshApexでキャッシュを更新

```javascript
import { LightningElement, wire, api } from 'lwc';
import getHotAccount from '@salesforce/apex/AccountTableViewController.getHotAccount';
import updateAccount from '@salesforce/apex/AccountTableViewController.updateAccount';
import { refreshApex } from '@salesforce/apex';

export default class RefreshData extends LightningElement {
  @api recordId;
  rate = 'Hot';

  @wire(getHotAccount, { rate: '$rate'})
  wiredAccount;

  handleClick(event) {
    updateAccount({
        rate: 'Hot'
    })
    .then(() => {
      console.log('success');
      return refreshApex(this.wiredAccount);

    })
    .catch((error) => {
        this.message = 'Error received: code' + error.errorCode + ', ' +
            'message ' + error.body.message;
    });
}
}
```
今回はRatingが'Hot'の取引先の種別を'Prospect'にします。updateAccountのあとにrefreshApex(this.wiredAccount)でキャッシュを更新します。
ボタンを押すとレコードが更新され、画面の表示も'Proapect'に変更されます。

参考までにHTMLファイルも載せておきます。

```html
<template>
  <lightning-card>
  <template if:true={wiredAccount.data}>
      <template for:each={wiredAccount.data} for:item="acc" for:index="idx">
          <div key={acc.Id} class="slds-m-bottom_medium">
              <p>{idx}. {acc.Name}</p>
              <p><lightning-formatted-text value={acc.Name}></lightning-formatted-text></p>
              <p>種別：<lightning-formatted-text value={acc.Type}></lightning-formatted-text></p>
              <p><lightning-badge label={acc.Rating}></lightning-badge></p>
          </div>
      </template>
      <lightning-button label="Mark all as Prospect" onclick={handleClick}></lightning-button>
  </template>
</lightning-card>
</template>
```

#注意点
refreshApexは@wireで取得したデータでのみ使用できるので、例えばconnectedCallback内でApexを呼び出して取得したレコードの更新を再描画するには工夫が必要になるようです。また機会があればそちらも調べてみたいと思います。
Microsoft OpenHack DWH 参加レポート

# はじめに
2021.9.6から3日間開催されたOpenHack for Modern Data Warehousingに参加してきました。
その参加レポートです。

# OpenHackとは
Microsoftが主催する参加型のイベントです。
[Microsoft OpenHack](https://openhack.microsoft.com/)
『OpenHack』とある通り、自分たちで手を動かして与えられた課題をクリアしていく形式のイベントです。
今回のテーマは『Data Warehouse』でした。
Azure環境を使って、データウェアハウスの開発、実装、運用をします。
普段はオフラインで開催しているイベントだそうですが、今回初めてオンラインでの開催でした。
今後も同じ内容で定期的にOpenHackを開催されるそうなので、課題の内容については非公開となっています。ネタバレしない程度にイベントの概要や学んだことを書きます。

# イベント内容
4〜5人ずつでチームになり与えられた課題を1つずつクリアしていきます。課題は実務に近い内容となっており、全部で7の課題がありました。最後まで進められたチームは過去ほとんどいないそうです。
1つのチームにMicrosoftのコーチがついてくれて、アドバイスを貰いながら進めていきます。コーチは答えを教えてはいけない、というルールがあるため、自分たちで考える必要があります。

* 実務に沿った課題
* チームでの開発
* コーチは答えを教えていけない

といったところが、このOpenHackの大きな特徴です。
Microsoftのコーチによるミニセッションもいくつか用意されており、かなり豪華で濃い3日間でした。

# 参加した感想
結論から言うと自分はこのイベントに参加してよかったです。
よかったと感じた点をいくつかあげてみます。

* Azure製品の事が理解できる
* 自分で実際に手を動かすことによって、経験を伴った知識が身につく
* チームで協力して作業ができるので、スキルレベルにばらつきがあってもお互いをフォローできる
* オンラインなので参加しやすい

以前は東京での開催が主だったようですが、今回からオンラインでの開催になり、参加のハードルがかなり下がったのはとても良いと思いました。
オンラインはコミュニケーションが取りづらいというデメリットもありますが、自分のチームに関してはコーチがお昼休みに雑談の時間を作ってくれたため、他の参加者の方とも話ができたのでよかたったです。

あとは大枠の趣旨とは外れますが、知らない技術を学ぶ上での質問力や、スケジュール管理力なども試すことが出来て勉強になりました。

Azure製品のツールの特性や操作方法の知識以外にも、データ分析のアーキテクチャなどの概念的なところの理解も深められて良かったです。

# 学んだこと
イベントで学んだ知識についてまとめます。
※普通に検索すれば出てくる情報ではありますが、ここに載せてるツールを使った課題なんだな、と軽くネタバレになるかもです。もし今後イベント参加予定で、まっさらな状態で受講したい人は見ないほうがいいかもです。

## そもそもAzureとは
Microsoftが提供するクラウドサービスの総称です。
Azure Portalから操作ができます。

## Azure Portalとは
Azureのサービスを統合的に管理するためのツールです。

## ストレージサービスについて
データレイクに適しているツールは主に2つあります。

* [Azure Blob Storage](https://docs.microsoft.com/ja-jp/azure/storage/blobs/storage-blobs-introduction)
* [Azure Data Lake Storage Gen2](https://docs.microsoft.com/ja-jp/azure/storage/blobs/data-lake-storage-introduction)

Azure Blob Storageは、パスにスラッシュをいれて疑似的にディレクトリを表現しているが、実態はディレクトリ構造ではない。
Azure Data Lake Storage Gen2は、通常のファイルシステムと同様の階層型でフォルダ・ファイル管理ができる。
などの違いがあります。

## データ分析サービスについて
データ分析するためのツールは主に3つあります。

* [Azure Data Factory](https://docs.microsoft.com/ja-jp/azure/data-factory/introduction)
    * データ統合に特化したツール
* [Azure Databricks](https://docs.microsoft.com/ja-jp/azure/databricks/scenarios/what-is-azure-databricks)
    * ビッグ データ分析に特化したツール
* [Azure Synapse Analytics](https://docs.microsoft.com/ja-jp/azure/synapse-analytics/)
    * データ統合、エンタープライズ データ ウェアハウス、ビッグデータ分析が1つになった分析サービス

## データ分析・活用におけるデータ階層化の考え方
データクレンジングの進行度によってデータを階層化しようという考え方のこと。
[Medallion Architecture](https://databricks.com/notebooks/delta-lake-cdf.html) という。

1. ブロンズ → 何も加工していないRawデータ
2. シルバー → IT部門の人がみて綺麗な形のデータ
3. ゴールド → ユーザが見やすいデータ

# おわりに
OpenHack形式のイベントに初めて参加したので、かなりドキドキでした。が、いざ参加するとMicrosoftのコーチの方に親切に教えてもらったり、他の参加者の方々に助けてもらいながら課題を進めることができました。
Azure製品の事やデータウェアハウスの知識がつくのはもちろん、他の参加者の方と一緒に作業したりとかなり刺激をうけました。参加してよかったです。
次回は2021年11月24日～26日に開催されます。
[OpenHack Modern Data Warehouse](https://www.microsoftevents.com/profile/form/index.cfm?PKformID=0x12569983abcd#RegisterLink)
気になっている方はぜひ参加してみてください。
PowerBIでスクレイピング

# 概要

wikipediaのデータのスクレイピングをPowerBIでやってみます。
コードレスでAIでデータ取得をしてくれます。

ここもみてほしいです。[My BLOG](https://ten-hope.com/101/)

# 取得データ

今回はWikipediaから、[世界の人口](https://en.wikipedia.org/wiki/List_of_countries_and_dependencies_by_population)を取得してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684662/6b4bf2b2-5c8b-68e2-9954-66ea87e7a591.png)


# 取得方法
新規ファイル作成から、「別のソースからデータを取得する」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684662/52271e50-f399-70d0-1272-bbd44f4fb902.png)

次に、データ取得で「その他」→「Web」を選択して、「接続」ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684662/2aa40be9-65c0-a0d2-b18a-83f9a5125808.png)

ここで、URLにWikipediaの人口のURL
https://en.wikipedia.org/wiki/List_of_countries_and_dependencies_by_population
をURLを貼り付け、「OK」ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684662/d6fafd07-92e4-0e65-4af7-e9642bb7069d.png)


HTMLのテーブルの「Soveregn states and　＊＊＊」にチェックを入れて、「例を使用してテーブルを追加」をクリックします。（「読み込み」でもデータ取れますがここでは「例を使用してテーブルを追加」でやってみます。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684662/40f8a3b5-27e4-89bf-f1b6-1f7212bb6bbb.png)

列1の１行目に「china」と入力して「ABC China」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684662/aca5cd83-ede2-b0ea-ff2a-548d260ec32b.png)

2行目くらいまで選択して入力するとAIが行を察して表を作ってくれます。(United State以降自動で入力されます）
以降、列２も人口を選択すると自動入力してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684662/e09221cb-a735-a1a2-8e1c-e58a7b9fa595.png)

AI賢いですね。
SwiftのAssociated valuesなEnumをクロージャとして扱える話

# 概要

SwiftのEnumは[first-classな型](https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html)となっていて、ざっくりいうと[処理をクロージャとして表現できるため、パラメータとして渡したり、戻されたり、実行時に構築](https://stackoverflow.com/questions/599978/what-is-a-first-class-type)したりができます。

Associated valuesなEnumを用意し、クロージャとして扱って関数の引数として表現することでそれを確認できるようにします。

[出典](https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html)、実例、応用例がまとまってたほうが良いと思うのでまとめています。

# 実例

## シンプルなStringだけ

まずはシンプルな具体例としてつぎのようなDummyActionを用意します。

```swift
enum DummyAction {
    // let action: DummyAction = DummyAction.action1("dummy")のように使う
    case action1(String)
}
```

これを関数dummyFunctionAに渡せるかを試します。

```swift
func dummyFunctionA(
    embed: @escaping (String) -> DummyAction
) {
    print(embed)
}

dummyFunctionA(DummyAction.action1) // これが実行できればいい
```

`dummyFunctionA(DummyAction.action1)`がコンパイルできて実行できることで、
Enumの値`DummyAction.action1`は`(String) -> DummyAction`として表現できることがわかりました。

こんなコードで何が嬉しいの、という感じなのでもう少し話を抽象的にします。

## ジェネリクスを使って抽象的にする

さきほどはStringだけでしたが、DummyActionのcaseにIntも増やして試します。

```swift
enum DummyAction {
    case action1(String)
    case action2(Int) // 増えた
}
```

`dummyFunctionA`関数についてもIntでもいけるようにしたくなります。そのため、引数StringとしていたところをジェネリクスによりValue型としてみる例は次のとおりです。

```swift
func dummyFunctionB<Value>(
    embed: @escaping (Value) -> DummyAction
) {
    print(embed)
}
```

利用例は下記

```swift
dummyFunctionB(embed: DummyAction.action1)
dummyFunctionB(embed: DummyAction.action2)
```

上記によって`DummyAction.action1`や`DummyAction.action2`も`(Value) -> DummyAction`のクロージャとして表現できることがわかりました。

さらにジェネリクスでDummyActionをRootとするとつぎのようにできます。

```swift
func dummyFunctionC<Root, Value>(
    embed: @escaping (Value) -> Root
) {
    print(embed)
}
```

もちろん、これらのコードはただ確認したかっただけでこの関数は特に有用ではありません。

# 応用例

実際Enumをクロージャとして扱うことで何が嬉しいのか、ということを書いておきます。

## CasePathの例

https://github.com/pointfreeco/swift-case-paths

省略をたくさんしますが[The Composable Architecture](https://github.com/pointfreeco/swift-composable-architecture)からも利用される[CasePath](https://github.com/pointfreeco/swift-case-paths)ライブラリはこれまで述べてきたことを応用し、Structに対するKeyPathのような、Enumに対するCasePase型を使えるようにしてくれるライブラリです。

説明のためざっくりとですが、CasePath型はつぎのように定義されています。

```swift
public struct CasePath<Root, Value> {
    private let _embed: (Value) -> Root
    private let _extract: (Root) -> Value?
    ... 
}
```

そして、先程の関数`dummyFunction`のようなものはオペレーターを用意しています。

```swift
prefix operator /
public prefix func / <Root, Value>(
  embed: @escaping (Value) -> Root
) -> CasePath<Root, Value> {
  .init(embed: embed, extract: extractHelp(embed))
}
```

DymmyActionを利用した例としてはつぎのようにできる、というわけです。

```swift
let casePath: CasePath<DummyAction, String> = /DummyAction.action1

// DummyAction.action1("dummy")と同じことができる。Rootを取り出せる。
let action1: DummyAction = casePath.embed("dummy")

// action1から結果としてOptional(Value)を取り出せる。
let string: String? = casePath.extract(from: action1)
print(string) // Optional("dummy")
```
統計検定のクセであるラスパイレス指数・パーシェ指数を言語化して明瞭化しよう

「普通に」統計の学習をしてたときには聞いたことも触れたこともなかった
<B>「ラスパイレス指数」と「パーシェ指数」</B>ですが、
統計検定では過去数回この両方とも出ちゃっています。

そして、ラスパイレス指数・パーシェ指数のどちらも定義式を知らないと解けない仕様となっていたので、
とりあえず公式だけ覚えたよ！という方も少なくないはずです

ここでは、もちろん定義式の確認から、「結局どういう意味？」部分も自分なりの言葉で書いていきます
（多少の厳密性を書く可能性もあるため、定義式を覚えておくことを優先しましょう）

# ラスパイレス指数

パーシェ指数もそうですが、そもそも経済学に用いられることがほとんどで、
商品などの取引量を考慮した、物価の変化をみたいときに使います。

## 定義式
$$P_L = \frac{\sum_{i=1}^{n}p_{ti} q_{0i}}{\sum_{i=1}^{n}p_{0i} q_{0i}} *100$$

$p_{ti}$: 比較年の価格 (price)
$p_{0i}$: 基準年の価格
$q_{0i}$: 基準年の数量 (quantitive)

この式からわかるように、
<B>ラスパイレス指数は主に「価格」に関心があり、比較したい年の数量はどうでも良いんです。</B>

## 噛み砕くと？
分母は基準年の総取引量（単位は「価格(¥とか$とか)」）が入ります。
分子は「今年の価格で基準年と同じだけの数量を買うとした場合」の総取引量が入ります。
つまり、この比率を使っているわけなので、
<B>基準年の数量を基準として、基準年に比べてどのくらい比較年は価格が推移したのか？</B>を考えることができます

もう少し噛み砕くと、
基準年くらいの数量を今買いたいとしたら、当時の何倍のお金が必要になる？って感じかと。

比較年は例えば現在の年数などをターゲットとする場合、うまくデータを集められてないケースなどもあるため、このラスパイレス指数などは役立つことになります。

#パーシェ指数
では、クセの二つ目パーシェ指数へ。

式もほとんど変わらず、基準年を軸とするか比較年を軸とするか？くらいです。
サクサクいきましょう！

## 定義式
$$P_L = \frac{\sum_{i=1}^{n}p_{ti} q_{ti}}{\sum_{i=1}^{n}p_{0i} q_{ti}} *100$$

$p_{ti}$: 比較年の価格 (price)
$p_{0i}$: 基準年の価格
$q_{ti}$: 比較年の数量 (quantitive)

今度は「基準年の数量」には関心のない数式となっています。

## 噛み砕くと？
分母は「比較年の数量分」を基準年の価格で購入するとした時の総取引量
分子は比較年の総取引量となります。

つまりは、
<B>比較年の数量を基準として、基準年に比べてどのくらい比較年は価格が推移したのか？</B>
であり、もっと噛み砕けば、
今の数量を基準年の価格で買うとしたら、何倍のお金が必要なのか？　となります

やや似たようなニュアンスになるのは式からも当然の流れだとは思いますが、
- 「昔の数量だけ買いたい」ならラスパイレス指数
- 「今と同等の数量だけ買いたい」ならパーシェ指数
をみると便利です。


# ちょこっとコーディング
式自体は純粋にsum関数とかのレベルのため、調べた感じpythonでライブラリや関数が用意されている感じはなさそうでした
なので、dataframeを自分で作り、自分でラスパイレス指数とパーシェ指数を計算してみるという自作自演を行います

コードの説明等は省略します

```
import numpy as np
import pandas as pd


rng = np.random.default_rng()

# 基準年の価格
p0 = rng.integers(100, 1000, size=100)
# 比較年の価格
pt = rng.integers(110, 1200, size=100)

# 基準年の数量
q0 = rng.integers(10, 45, size=100)
# 比較年の数量
qt = rng.integers(11, 50, size=100)

data = pd.DataFrame({'p0': p0, 'q0': q0, 'pt': pt, 'qt': qt})
display(data.head())

# 基準年の数量 * 基準年の価格
sum00 = sum(data['p0'] * data['q0'])
# 基準年の数量 * 比較年の価格
sum0t= sum(data['p0'] * data['qt'])

# 比較年の数量 * 比較年の価格
sumtt = sum(data['pt'] * data['qt'])
# 比較年の数量 * 基準年の価格
sumt0= sum(data['pt'] * data['q0'])

print('ラスパイレス指数は', np.round(sum0t/sum00, 3)*100, '%')
print('パーシェ指数は', np.round(sumtt/sumt0, 3)*100, '%')
```
![スクリーンショット 2021-10-24 17.27.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865635/5ad555e5-9878-05d6-3f5d-388fb0f3286e.png)

ってな感じです〜
ま、これくらいなら自作でどうにかなりますな。

# 今回参考にさせていただいた記事
毎度たくさんの記事に助けられております
[32-5. さまざまな指数](https://bellcurve.jp/statistics/course/18454.html)
[パーシェ指数とラスパイレス指数の違いについてわかりやすく解説](https://www.management-consultant.info/?p=443)
M5Stamp C3にMicroPythonを入れてみる

2021年10月21日(木)スイッチサイエンスから Espressif ESP32-C3搭載の[M5Stamp C3](https://www.switch-science.com/catalog/7473/)が
販売になりました。

MicroPython v1.7 の最新ソースには ESP32-C3 のポートが含まれているので、ビルドしてM5Stamp C3に入れてみました。

# ビルド

### ESP-IDF 環境の用意

ESP32-C3 用の MicroPython をビルドするには ESP-IDF 4.3.1 以上が必要です。以下のサイトに説明されている手順に従って ESP-IDF 環境を用意します。

https://docs.espressif.com/projects/esp-idf/en/v4.3.1/esp32/get-started/index.html#installation-step-by-step

ざっくり書くと

```bash
mkdir -p ~/esp
cd ~/esp
git clone -b v4.3.1 --recursive https://github.com/espressif/esp-idf.git
cd ~/esp/esp-idf
./install.sh
```

開発環境を有効化するには、以下で環境定義します。

```bash
. $HOME/esp/esp-idf/export.sh
```

以後は以下で `alias` 定義しておけば `get_idf` で環境定義できます。

```bash
alias get_idf='. $HOME/esp/esp-idf/export.sh'
```

### MicroPython ファームウェアコードのビルド

最新の MicroPython ソースを取得します。

```bash
git clone https://github.com/micropython/micropython.git
```

MicroPython コードのフリーズ(コンパイル)環境をビルドします。

```bash
cd micropython  # MicroPython のソースコードのフォルダ
make -C mpy-cross
```

ESP32-C3 用ファームウェアをビルドします。

```bash
cd ports/esp32
make submodules
make BOARD=GENERIC_C3
```

### ファームウェアビルドのトラブルシューティング

私の環境ではビルド時に以下のエラーが発生しました。

```
[653/1276] Generating x509_crt_bundle
FAILED: esp-idf/mbedtls/x509_crt_bundle /Users/inachi/work/pico/micropython/ports/esp32/build-GENERIC_C3/esp-idf/mbedtls/x509_crt_bundle 
cd /Users/inachi/work/pico/micropython/ports/esp32/build-GENERIC_C3/esp-idf/mbedtls && /Users/inachi/.espressif/python_env/idf4.3_py3.7_env/bin/python /Users/inachi/esp/esp-idf/components/mbedtls/esp_crt_bundle/gen_crt_bundle.py --input /Users/inachi/esp/esp-idf/components/mbedtls/esp_crt_bundle/cacrt_all.pem -q
gen_crt_bundle.py: Invalid certificate in /Users/inachi/esp/esp-idf/components/mbedtls/esp_crt_bundle/cacrt_all.pem
Invalid certificate
ninja: build stopped: subcommand failed.
ninja failed with exit code 1
make: *** [all] Error 2
```

原因と対処法は以下に情報がありました。

https://github.com/espressif/esp-idf/issues/7631#issuecomment-934212224

この情報に従い、`cryptography` をダウングレードします。

```bash
pip install -U cryptography==3.4.8
```

この対処をした後は、ファームウェアのビルドに成功しました。

### ファームウェアの書込み

M5Stamp C3 のUSB シリアル変換用のチップが WCH CH9102 なので、ドライバのインストールが必要かもしれません。私の場合は以下の Mac 用ドライバをインストールしました。

[https://github.com/Xinyuan-LilyGO/LilyGo-T-Call-SIM800/files/7037260/CH9102_Mac_Driver.zip](https://github.com/Xinyuan-LilyGO/LilyGo-T-Call-SIM800/files/7037260/CH9102_Mac_Driver.zip)

M5Stamp を USB ケーブルで繋いで、ビルドしたディレクトリから以下を実行します。

```bash
make BOARD=GENERIC_C3 PORT=<M5Stamp C3が繋がっているシリアルポート>　erase
make BOARD=GENERIC_C3 PORT=<M5Stamp C3が繋がっているシリアルポート> BAUD=<ボーレート> deploy
```

※ PORTのデフォルトは `/dev/ttyUSB0` 、BAUDのデフォルトは `460800` 。

※　Mac でのシリアルポートは `/dev/cu.wchusbserial〜` でした。

以上で、MicroPython のインストールは終了です。

軽く試していたところでは内蔵の NeoPixel も Wi-Fi も使えています。

![IMG_5560.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/1e77c1f0-b555-7359-9f7e-8df2051b82c2.jpeg)
コマンドチートシート（自分用）

# コマンド集

## Git

- remoteブランチを参照
```git remote show origin```

- remoteブランチで削除済&ローカルに参照が残っているブランチを表示
```git remote prune --dry-run origin```

- remote削除済ブランチのローカル参照を削除
```git remote prune origin```

- remoteブランチの参照を削除
```git branch --unset-upstream```

- ローカルブランチとリモートブランチを紐づける
``` git branch --set-upstream-to=origin/ブランチ名```
もしくは
``` git branch -u origin ブランチ名 ```

- 紐づいてるブランチの確認
``` git branch -vv ```

- カレントディレクトリ以下を指定コミット番号の状態に復元する
```git restore -s [コミット番号]```

- カレントディレクトリ以下を一括リセット
```git restore .```

- untracked fileを削除前に確認
```git clean -n```

- untracked fileを削除
```git clean -f```

- ブランチ派生元変更(リベース)
```git rebase [派生元] [派生先]```

## Docker

- ボリューム確認
```docker volume ls```

- ストレージ確認
```docker system df```

- ビルドキャッシュ削除
```docker builder prune```

- コンテナプロセス確認
```docker top ```

- ローカルからコンテナへコピー
```docker cp [ファイル] [コンテナID]:/ ```

- コンテナからローカルへコピー
```docker cp [コンテナID]:/[ファイル] ./ ```

## Docker-compose

- ビルドと立ち上げ
```docker-compose up -d```

- コンテナ終了と削除
```docker-compose down```

- 全削除(コンテナ、イメージ、ボリューム)
```docker-compose down --rmi all --volumes --remove-orphans```

- コンテナスタート
```docker-compose start```

- コンテナ終了
```docker-compose stop```

- コンテナに入る
```docker-compose exec [コンテナ名] bash```

- 情報
```docker-compose ps```

## Vue-cli

- コンテナ内でプロジェクト生成  
```vue create -n --merge [プロジェクト名]```

## その他


随時更新予定
【Flutter, Firebase】Googleログインでアカウント選択画面が省略される

## 何が起きたか
Flutterで実装したアプリでFirebaseのAuthenticationで実装したGoogleログインを行う際に、どのGoogleアカウントでログインするかのアカウント選択画面が表示されず、前回ログインしたGoogleアカウントでログインされてしまいました。
(アカウント選択画面とは↓の画像の画面です)
![ezgif.com-gif-maker.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263659/980e4b39-7edd-a56f-f384-43809f4f6425.png)

アカウント選択画面は、そのアプリで初めて表示する際は表示されるのですが、ログアウトして二回目以降のログインの場合はアカウント選択画面が表示されませんでした。

## どうやって解決したか
FlutterアプリでのFirebaseのAuthenticationでログアウトするコードはこちらです。

```
FirebaseAuth.instance.signOut();
```
しかしこれでは、**最後にどのGoogleアカウントでログインしたかというキャッシュ情報**までは削除されないため、次回ログインしようとした時にキャッシュ情報からアカウント選択画面が省略されてしまいます。
なのでログアウトする際は下記のコードのように、GoogleSignInクラスsignOutメソッドを実行して、キャッシュ情報を削除する必要があります。

``` AuthHelper.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';

class AuthHelper {
  /// ログアウトする
  static Future<void> logout() async {
    // Googleは別個でログアウトしないと次にログインするときにアカウント選択が表示されない
    final googleSignIn = GoogleSignIn();
    if (await googleSignIn.isSignedIn()) {
      await googleSignIn.signOut();
    }

    return FirebaseAuth.instance.signOut();
  }
}
```

こちらのコードのようにログアウトすると、Googleログインするたびにアカウント選択画面が表示されるようになります。

以上です。
【Android】明日から使いたい DroidKaigi 2021 の実装

#DroidKaigi 2021
先日 [DroidKaigi 2021](https://droidkaigi.jp/2021/) が行われました。

3日間開催でTimetable(タイムテーブル)は以下です。
・[DroidKaigi 2021 タイムテーブル] (https://droidkaigi.jp/2021/timetable/)

DroidKaigi では多くの発表がありました。
その発表の中から **明日から使える実装** を2つ紹介します。
ViewModel と Lifecycle の技術にピックアップして選出しました。

#lifecycleScope.launchWhen**** で表示データを更新
アプリがバックグラウンドの状態でデータを更新させたくない時に使えるのが以下です。
・lifecycleScope.launchWhenStart
・lifecycleScope.launchWhenResume
を利用することで非同期処理の結果を更新させることで、画面回転やメモリリークに強いアプリを目指せます！
ライフサイクルに準拠したアプリ開発が大切です。
↓のような実装が一例です。

```kotlin:TestActivity.kt
class TestActivity: AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        lifecycleScope.launchWhenStarted {
            // ViewModelからの更新をする
        }
    }
```

紹介されたセッションの動画のリンクを記載しておきます
・[マルチデバイス対応で考慮すべきポイント] (https://www.youtube.com/watch?v=lTi9PUwjifE&list=PLaOdaBFokChw6PA-uCyvhWUP6VLYnmHdd)
・[Master of Lifecycle] (https://www.youtube.com/watch?v=C6HeJzqJqRI&list=PLaOdaBFokChyTGmFMqa5yEZAZ_7_wjaNL)

#SavedStateHandleでアプリの状態を保持
画面回転でも破棄されないViewModeでActivityやFragmentの破棄されてしまうデータを保持させるのに良いです！
↓のような実装が一例です。

```kotlin:TestViewModel.kt
class TestViewModel(
    private val savedStateHandle: SavedStateHandle
):ViewModel {
    private val _savedId = mutableStateOf<UiState>(UiState.Initial)

    init {
        savedStateHandle.setSavedStateProvider("[KEY]") {
            _savedId.value.toBundle()
        }

        savedStateHandle.get<Bundle>("[KEY]")?.let {
            _savedId.value = it.toUiState()
        }
    }
}
```

紹介されたセッションの動画のリンクを記載しておきます。
・[プロダクトレベルで必要となる Jetpack Compose テクニック] (https://www.youtube.com/watch?v=_5vP-NIRUCM&list=PLaOdaBFokChw6PA-uCyvhWUP6VLYnmHdd)
・[Master of Lifecycle] (https://www.youtube.com/watch?v=C6HeJzqJqRI&list=PLaOdaBFokChyTGmFMqa5yEZAZ_7_wjaNL)

#最後に
今回紹介したのは発表された内容のごく一部です。
3日間のセッションの動画一覧が↓のTwitterにまとまっています。
興味があるものを見て知識を増やしてAndroid開発力を高めていきましょう！

https://twitter.com/DroidKaigi/status/1451157310668087300?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Etweet
特定のコードがあるリポジトリを自動でウォッチする

## はじめに

たまに、「こういうコードがあるリポジトリをウォッチしておきたい」と思うことがあったので、それを自分なりに自動化してみました :robot: 

### 環境

- macOS Big Sur バージョン 11.6
- curl 7.64.1
- Homebrew 3.2.16
- jq-1.6

### 準備

#### Homebrew のインストール

```zsh
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

#### jq インストール

```zsh
brew install jq
```

#### GitHub のアカウントの作成

https://github.com/signup?source=login

#### GitHub の個人アクセストークンを取得

https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token

## 特定条件のコードがあるリポジトリをウォッチ

```zsh
GITHUB_USER="{GitHub のユーザー名}"
GITHUB_TOKEN="{GitHub の個人アクセストークン}"

QUERY="{コードの検索条件}"
PER_PAGE="{1ページあたりの結果数}"

# 特定条件のコードを検索して、それが含まれているリポジトリを取得する
curl -u "$GITHUB_USER:$GITHUB_TOKEN" \
  "https://api.github.com/search/code?q=$QUERY&per_page=$PER_PAGE" | \
  jq -r '.items[] | .repository | .full_name' | \
while read -r name; do
  # リポジトリをウォッチする
  curl -u "$GITHUB_USER:$GITHUB_TOKEN" \
    -X PUT \
    -H "Accept: application/vnd.github.v3+json" \
    "https://api.github.com/repos/$name/subscription"
done
```

### 条件の例

```zsh
# ファイルの中に「androidx.core:core-splashscreen」が存在
# ファイル名が「build.gradle か build.gradle.kts」
QUERY='androidx.core%3Acore-splashscreen+filename%3A"build.gradle+build.gradle.kts"'

# ５つ
PER_PAGE="5"
```

## おわりに

直接リポジトリを検索したり、ウォッチではなくスターをつけたり、他にもいろんなやり方があるので、ぜひお試しください。

もしよろしければ、おすすめの自動化をコメントいただけると嬉しいです :blush:

## 参考

### jq マニュアル

https://stedolan.github.io/jq/manual/v1.6/

### GitHub API

#### Search code

https://docs.github.com/ja/rest/reference/search#search-code

https://docs.github.com/ja/search-github/searching-on-github/searching-code

#### Search repository

https://docs.github.com/ja/rest/reference/search#search-repositories

https://docs.github.com/en/search-github/searching-on-github/searching-for-repositories

#### Watch

https://docs.github.com/ja/rest/reference/activity#set-a-repository-subscription

#### Star

https://docs.github.com/ja/rest/reference/activity#star-a-repository-for-the-authenticated-user
pandasでハマった話


Pythonには配列系が4種類あって、それぞれ使い方が微妙に異なるため、非常に混乱する。

- list
- numpy.ndarray
- pandas.core.series.Series
- pandas.core.frame.DataFrame


最近、ハマった例は以下の通り。


```python
>>> import pandas as pd
>>>
>>> df = pd.DataFrame()
>>> df['x'] = [10, 11, 12]
>>> df
    x
0  10
1  11
2  12
>>>
>>> 10 in df.x
False
>>> 10 == df.x[0]
True
>>> 10 in df.x.tolist()
True
>>> 10 in df.x.to_numpy()
True
>>> type(df.x)
<class 'pandas.core.series.Series'>
```

Series型に対する`in`は、値の存在チェックではなく、インデックスの存在をチェックする。
元々のPythonの文法の意味を変えてしまっているのでは。

https://stackoverflow.com/questions/49393053/using-in-operator-with-pandas-series/49393472

DataFrameとSeriesの使用パターン

```python
import pandas as pd

df = pd.DataFrame()
df['i'] = range(10,15)
df['x'] = range(5)
df['y'] = list('abcde')
df.set_index('i', inplace=True, drop=False)
df

df[0:2]  # 行番号 (2は含まない)
df['x']  # 列名 (Series)
df[['x']]  # 列名
df[['x','y']]  # 列名
df.loc[10]  # インデックス
df.loc[10:12]  # インデックス (12を含む)
df.iloc[0]  # 行番号
df.iloc[0:2]  # 行番号 (2は含まない)

df.x[10]  # インデックス
df.x[0:2]  # 行番号 (2は含まない)
df.x.loc[10] # インデックス
df.x.loc[10:12] # インデックス (12を含む)
df.x.iloc[0] # 行番号
df.x.iloc[0:2] # 行番号 (2は含まない)
```

https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.loc.html

https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.iloc.html

https://pandas.pydata.org/docs/reference/api/pandas.Series.loc.html

https://pandas.pydata.org/docs/reference/api/pandas.Series.iloc.html
Pythonの再試行処理を関数化する

『たまに失敗するが、その場合は成功するまで再試行させたい』という処理がある
例

* ネットワークに接続する処理
* Seleniumで要素を取得する処理

など　　

### 世の中の人々は再試行処理をどうしているのか

#### Googleの公式ドキュメント

[指数バックオフの実装例](https://developers.google.com/analytics/devguides/reporting/core/v3/coreErrors?hl=ja)

```python
import random
import time
from apiclient.errors import HttpError

def makeRequestWithExponentialBackoff(analytics):
  """Wrapper to request Google Analytics data with exponential backoff.

  The makeRequest method accepts the analytics service object, makes API
  requests and returns the response. If any error occurs, the makeRequest
  method is retried using exponential backoff.

  Args:
    analytics: The analytics service object

  Returns:
    The API response from the makeRequest method.
  """
  for n in range(0, 5):
    try:
      return makeRequest(analytics)

    except HttpError, error:
      if error.resp.reason in ['userRateLimitExceeded', 'quotaExceeded',
                               'internalServerError', 'backendError']:
        time.sleep((2 ** n) + random.random())
      else:
        break

  print "There has been an error, the request never succeeded."
```

処理が失敗する毎に待ち時間を増やして再実行していく方式のことを指数バックオフと言うらしい　　
ネットワークに負荷をかけないためにも、このやり方を使ってみるのがよさそう。　　
上記のPython2の実装例を参考に、Python3での汎用的な関数として実装し直してみた。

```python
import random
import time
from typing import Any, Callable


def main():
    try_until_success(sometime_fail)


def sometime_fail():
    """一定の確率でExceptionが発生する処理"""
    n = random.random()
    if n > 0.7:
        print("成功！")
    else:
        raise Exception("失敗...")


def try_until_success(f: Callable) -> Any:
    """成功するまで試行する(最大5回)
    エラーが発生した場合、待機秒数を指数関数的に増やして再試行

    Args:
        f (Callable): 失敗する可能性のある関数

    Raises:
        Exception: 5回試行して全て失敗した場合は続行不可能とみなす

    Returns:
        Any: fの実行に成功した際の戻り値
    """
    for n in range(0, 5):
        try:
            result = f()
            return result
        except Exception as e:
            print(e)
            wait_time = (2 ** n) + random.random()
            print("{:.1f}秒待機して再試行します...".format(wait_time))
            time.sleep(wait_time)
    raise Exception("5回試行しましたが、全て失敗しました...")


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

関数で定義する程ではない処理を渡したい場合はラムダ式を使うと良い

```python
import requests


def main():
    f = lambda: requests.get("https://www.google.co.jp")  # noqa: E731
    res = try_until_success(f)
```
rdma-core-35.0-1.fc33.i686 の削除(fedora33から34へのupgrade)

###はじめまして
初投稿です。 おてやわらかに願います。　デスクトップにfedoraを使っています。

###ながれ
fedora33(x86_64) から fedora34 への upgrade で rdma-core-35.0-1.fc33.i686 の存在により止まりました。その対処メモです。
wine を削除、依存関係で2つの i686.rpm パッケージを削除、その結果 rdma-core-35.0-1.fc33.i686 を削除、fedora34 に upgrade できました。

###おそらく もしかしたら

- 以前、 fedora32(x86_64) から33へオンラインアップデート(というのでしょうか)された
- そのfedora32 で既に wine をインストールされていた

場合に関係あるかもしれないおはなしです。



### fedora34 へ upgrade を実行するも

```
$ sudo dnf system-upgrade download --refresh --releasever=34

   <中略>

 問題: rdma-core-35.0-1.fc33.i686 は下位アーキテクチャがあります
  - rdma-core-35.0-1.fc33.x86_64 はdistupgradeレポジトリーに属していません
  - インストール済パッケージの問題 
```
と表示され止まりました。( --skip-broken を試すも、同じ結果)そこで rdma-core-35.0-1.fc33.i686 を消すために wine などをアンインストールしました。

```
$ sudo dnf erase wine -y                                                   
$ sudo rpm -e libibverbs-35.0-1.fc33.i686 libpcap-14:1.10.1-1.fc33.i686 　　　#依存関係
$ sudo rpm -e rdma-core-35.0-1.fc33.i686
```
###改めて34へアップデート

```
$ sudo dnf system-upgrade download --refresh --releasever=34
$ sudo dnf system-upgrade reboot
```
無事にシステムの upgrade が完了しましたら
(ログイン画面からのデフォルトが GNOME に戻っていました。右下の歯車マークから LXDE (自分の場合)を選び直します)

```
$ sudo dnf install wine -y 
```

/home/{USER}/.wine を削除せずにいたためか33までに wine でインストールしていたソフトたちはスタートメニューからすぐに使えました。

--allowerasing オプションはシステムファイルを削除するような趣旨のダイアログが見え今回は怖くてやめました(SSなしスミマセン)

取り急ぎ(?)(もう fedora35 がリリースされますね...)



###おまけ
削除したいパッケージ(今回は「`rdma-core-35.0-1.fc33.i686.rpm`」)

以下で依存関係の一覧に、システムでない別のパッケージ(今回は`wine`)を見つけました。

```
$ sudo rpm -e 削除したいパッケージ名.i686.rpm
```

以下で同居していることも確認、
今回は、別途用意した仮想環境へクリーンインストールしたfedora34にそもそも「削除したいパッケージ名.i686.rpm」が存在しないことも確認し、

```
$ sudo dnf list installed | grep 削除したいパッケージ名

削除したいパッケージ名.i686.rpm
削除したいパッケージ名.x86_64.rpm
```

###お礼と感想
お読みいただきありがとうございました。

さらっと解決されてしまうQiitaの先輩方がこわくて下書きの山を作っています。
[Rails] current_user.idとは

##初めに
####なぜこの記事を書きたかったのか
**このidはどこから来たのか知りたかったから、深堀りしたい。**


####環境
**・Macbook Air (Retina, 13-inch,2019)
・プロセッサ 1.6GHz デュアルコアIntel Core i5
・メモリ　8GB 2133 Mhz LPDDR3
・MacOS Big Sur　バージョン 11.5.2**


####記事の目次
**１）どこから来た？**
**２）どんな機能があるの？**
**３）どういうときに使うの？**
**４）最後に**

##どこから来た？
####アプリケーションへ遷移するとき、自動的に付与される。

##どんな機能があるの？
**今現在、アプリケーション内を操作しているユーザーを識別するためにパソコンが自動的に付与させる。**
**イメージはアプリケーション内に入るユーザーにクリアファイルを強制的に渡してくれる。アプリケーション内にデータを保存したときそのファイルの中に入れることができる。**


##どういうときに使うの？
**付与されているIDを使って遷移先の制限や行動を制限させる設定をすることができる。**
####(例えば)
**・新規登録/ログインでcurrent_userに情報を付与後、ログイン者と未ログイン者の区別ができる。**
**・都度ユーザがアプリケーション内に行ったことを結びつかせることができる。**

##最後に
**新規登録/ログイン機能を追加したときにいきなり出てきて、”こういうものだから気にしなくて良い”と納得してしまったけど、アプリ内のユーザを区別するために必要な基本知識なので言語化して記憶に定着させたかった。****自分なりに言語化させて、悩んでたこと(テーブルのカラムに対してどうやって別の情報を付与すればいいか悩んでた)が解決できそうな気がして、ちょっと光が見えてきた！**

**ここまで読んでくださいましてありがとうございました！**
初心者、見えている石に気づかずつまづく

# はじめに
月一でアウトプットを出そうと心がけているのですが、今月は忙しかったのでただの駄文です。

# 失敗物語
### 昔の自分と今の自分
数年前。私はyoloのデモを見て、物体検出AIそのものではなく画像の上に四角形や文字を描く手法に興味を抱いた。
yoloの公式サイトにあるこの画像で。
![yolo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520216/a1d4332e-fc64-2009-f456-42f427596d32.png)
往年のBASICには`LINE`や`CIRCLE`といったコマンドがあり、それを使って拙いCGを描いたことがある。それゆえにAIではなく、バウンディングボックスの出力形式でもなく、イマドキの言語であるPythonにおける図形描写に興味が移ってしまったのだった。

そして今。OpenCVを知ってからはそれを使った小物を作って公開している。

  - [OpenCVでリサイズ・モザイク・顔検出、ときどき象印](https://qiita.com/mo256man/items/c570c645153cae122196)
  - [OpenCVで日本語フォントを描写する　を関数化する](https://qiita.com/mo256man/items/82da5138eeacc420499d)
  - [OpenCVで透過画像を扱う　～スプライトを舞わせる～](https://qiita.com/mo256man/items/f7524dd34718a01fb3df)
  - [投影変換で画像を変形する　～モニタ画面をハックする～](https://qiita.com/mo256man/items/27d0a44071aee5f06933)
  - [OpenCVでラスタースクロールする](https://qiita.com/mo256man/items/a8d6f9276896bffb723f)
  
などなど。いくつかの投稿については多くのLGTMをいただき、たいへんありがたいことである。

### Python講座にて
会社のPython講座に参加した。openpyxlによるExcel操作などを経て、第4回となる今回はとうとうディープラーニング。
『ゼロから作るDeep Learning』を買って分類器を作って、分類以外の活用方法が思いつかなくてそれ以来ずっと放置していた自分に活を入れるいい機会だ。

画像分類のネタは**柿ピー**。柿の種とピーナツ、そして製造業ゆえ異常検知を想定して割れた柿の種も含めた3種類を分類するというもの。真面目過ぎず不真面目すぎず、いい塩梅の題材だ。
会社でAIを活用するにあたり「AIがこう言ってます、なぜそう判断したのかはわかりません」では上司を納得させることはできない。今回の講座は短時間だがGradCAMでAIがどこを注目しているのか可視化することも含んでいる。

最初に用意された画像は多くなく、kerasの`target_size`も小さく取っていた。
これで得られたAIは数少ないテスト画像の中では正しい答えが得られたが、GradCAMはAIが画像端など対象物と無関係な場所を注目していることを示していた。これではよろしくない、次はデータ拡張だ。

講師はCNNのプログラムとは別に画像を回転したり反転したりして画像を水増しするプログラムを用意していた。
画像データをリストにぶっこむ直前にメモリ上で画像水増しをすればいいじゃんというのは教える立場にない者の無責任な考え。これは勉強会だから、実際に回転したり反転したりした画像が作られたことを確認し、そのうえでさっきと同じプログラムを走らせるのが常道だ。

だが水増しの段階でエラーが出たという声が複数上がった。水増しされた画像を保存する`cv2.imwrite()`の行で。
そして、声を上げることはしなかったが、実は私にもエラーが起こっていた。

### 俺はパソコンに詳しいんだぜ
講師は受講者のためにPython導入方法の詳細な資料を用意していた。Pythonをインストールするときはパスを通すのを忘れないようにせよ。pipで必要なライブラリをインストールするにあたり会社からではプロキシで弾かれるのでこれこれこういう対策をせよ。講座で使うプログラムや画像はCドライブの直下にml（マシンラーニング？）というフォルダを作ってそこに入れよ。等々。
C:\ml というフォルダを作れという指示の意図はわかる。OpenCVは（Windowsでは）`cv2.imread()`や`cv2.imwrite()`で日本語パスを使うと文字化けしてしまいエラーになるおそれがあるからだ。

だが私はそれに従わなかった。WindowsXPの時代ならともかく、Windows10はデスクトップであっても日本語パスになることはない（ユーザー名が日本語ならその限りではないが、当社ではそのようなことはない）。
講師が指示する理由を理解していて、それに従う必要がないことも理解していて。
それなのにエラーになるのか。
この私が。
大人気記事『[OpenCVで日本語フォントを描写する　を関数化する](https://qiita.com/mo256man/items/82da5138eeacc420499d)』を著したOpenCV大好きマンのこの私が！

私は目を皿のようにしてエラーメッセージを確認し、またフォルダを確認する。そして気づいた。
![folder.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520216/a4bc2cc3-3c35-27ab-bf1d-16b4f38994b9.gif)
（[OpenCVでマウスイベントを取得する　～GUIな集中線ツールを作る～](https://qiita.com/mo256man/items/3a9e67cb5b9fe32839f0) で作りました）

**フォルダ名が日本語になってるー！** さんざん半角パスだから問題ないとか言ってて、これがオチ？！
講師は共用の「Python講座」フォルダの中の「第4回」フォルダに前述の資料と「python_img」サブフォルダを置いていた。一連の画像やプログラムはサブフォルダに入っている。
講座が始まる前に資料に目を通し、「python_img」サブフォルダを C:\ml の下に置けというのが講師の意図だったのだろう。
しかし私はそれを理解せず、「第4回」フォルダをそのままデスクトップに置いてそこで作業していたのだった。

これは恥ずかしい。なぁにが「[初学者を脱しつつある者を襲う贅沢な悩み](https://qiita.com/mo256man/items/f81b7106184474e2a197)」だ。
お前なんて初心者だ。ノービスだ。野比のび太だ。初心忘るべからず！

# 終わりに
驕ってはならないというお話でした。
それにしても文章ばかりの記事は読む気がしないな。~~関西弁で娘と語りあうスタイルにすればよかったか。~~
ディレクトリとフォルダとプロジェクトの違い

# 記事執筆のキッカケ

とある講師がフォルダを「プロジェクト」と呼んでいて詳細を調べてみた

# 結論

<dl>
<dt>共通の意味</dt>
<dd>ファイルを分類するための容れ物、複数のファイルを保管する場所</dd>
<dt>ディレクトリ</dt>
<dd>UNIXやLinuxなどのCUIではディレクトリと呼ぶ</dd>
<dt>フォルダ</dt>
<dd>WindowsやMacなどのGUIではフォルダと呼ぶ</dd>
<dt>プロジェクトフォルダ</dt>
<dd>プログラムを作成する際の作業フォルダ<dd>
</dl>

# 参考記事

- https://uxmilk.jp/27546
- https://toshihiko-kato.com/general/705/#Project&SceanFolder