OmniAICreator/Qiita-1.07M huggingface dataset:
chart.jsが表示されない現象について

# エラー内容について

ポートフォリオを制作するにあたって、データを視覚的に見れるようにするためにChart.jsを使用しました。
実装し確認をしていると、グラフが表示されない時があり、更新した場合表示されるという現象が起きました。
その時の失敗の理由について書いていきたいと思います。

（フレームワークはRuby on Railsを使用しました。）

# 解説
### 問題のあったコードについて
様々なページでグラフを表示させたいため、部分テンプレートでChart.jsを利用したグラフの実装を行いました。
```js:_line_graph.html.erb
<canvas id="line_graph"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
var ctx = document.getElementById('pie_graph');
  var myChart = new Chart(ctx, {
          type: 'pie',
          data: {
            // ここに表示させたいグラフの内容を記述する。
          },
          options: {
          }
      });
</script>
```
この中に記述されている、
```js:_line_graph.html.erb
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
```
が共通化したページに記述されていることが原因でchart.jsが表示されない現象が起きていました。

### 何故そのような現象が起きたのか？
原因はTurbolinksの、headタグはマージしbodyタグは差し替えることで画面遷移が起きたように見せかける仕様の為でした。
そのため,
```js:_line_graph.html.erb
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
```
がbodyタグに記述されているため、内部的には置き換えられるだけで、実際にscriptタグを読み込んで貰えていなかったので起きてしまったようです。

### 解決方法
```js:application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>hoge</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
  </head>

  <body>
  </body>
</html>
```
application.html.erbのheadタグの中にscriptタグを移動しました。
こうすることでscriptタグをTurbolinksが読み込んでくれるため画面遷移後に更新を行わなくてもグラフを表示できるようになります。
php artisan migrate実行時のエラー

php artisan migrate

   Illuminate\Database\QueryException 

  could not find driver (SQL: select * from information_schema.tables where table_schema = ****** and table_name = migrations and table_type = 'BASE TABLE')


試すこと：

```php artisan cache:clear```

`php artisan config:clear`

`php -m`
（pdo_mysqlが入ってるかどうかを確認する）

参考記事：
(Laravel)マイグレーション時、could not find driver のエラー
https://hara-chan.com/it/infrastructure/docker-laravel-migration-could-not-find-driver/#could_not_find_driver

最後解決
https://qiita.com/kaicho15to18/items/649d2865ca9098e498eb


関係ファイル
.env
config/database.php
/etc/php.ini
Laravelで「Expected name to be a non-empty string.」というエラーが発生した件のメモ

## 備忘
- 2022/10/16くらいからLaravel開発環境で突然「Expected name to be a non-empty string.」というエラーが発生し、artisanコマンドがいっさい実行できなくなった。
- 調べていくとCI/CDで実行している`composer update`の結果「vlucas/phpdotenv」というライブラリのアップデートが行われたことがわかった。（v5.4.1 => v5.5.0）
- [GitHub](https://github.com/vlucas/phpdotenv/commit/4c165455a670005a05edbdf97a5590aa3e4936ec#diff-2eedf850c12a444af660cf1ff97e8449b140a2be8646c2c857a7f95afc195cc7R62)を見ると、AdapterRepository.phpに環境変数名の空チェックロジックが追加されていることがわかった。
- env()メソッドに渡す環境変数名が空の場合、いままではスルーされていたが、例外をスローするようになっていた。
- 環境変数名が空の場合はenvを呼ばないように修正した。（そもそも変数名が空になることがあることは置いておく）


```
// キーが空の場合はenv()にて例外が発生する。
// 前バージョンでは`echo('')`と同じ挙動だった。
$key = '';
echo(env($key));
```
エラー内容
```
In AdapterRepository.php line 65:
                                           
  Expected name to be a non-empty string.
```
unity vrm

```package.json
{
  "dependencies": {
    "com.vrmc.vrmshaders": "https://github.com/vrm-c/UniVRM.git?path=/Assets/VRMShaders#v0.104.2",
    "com.vrmc.gltf": "https://github.com/vrm-c/UniVRM.git?path=/Assets/UniGLTF#v0.104.2",
    "com.vrmc.univrm": "https://github.com/vrm-c/UniVRM.git?path=/Assets/VRM#v0.104.2",
    "com.vrmc.vrm": "https://github.com/vrm-c/UniVRM.git?path=/Assets/VRM10#v0.104.2",
  }
}

```
【Python】spinboxの初期値を設定する

＜初めに＞
comboboxの初期値を簡単に設定することができたから
spinboxも出来ると思ったら…とんでもなくやり方が違ったので書いておきます

＜やりたいこと＞
Treeviewの列をダブルクリックしたときに
spinboxの初期値にTreeviewデータを入れたい
（理想↓）
①任意の列を指定したら…
![spinbox_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2021763/5d30facf-ef85-7bf0-eb72-9456b9dbc5db.jpeg)
②自動でspinboxの初期値が入力されるようにしたい…
![spinbox_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2021763/6e4b1dbd-3786-6f74-d2ab-22451e862834.jpeg)
＜これがやりたい理由＞
CSVからTreeview作成しているんだけど
中身を修正するときにspinboxが0から始まるのではなく、
指定した列の値が初期値として入っていたら修正したりする人がやり易いかな～
と思って…(;'∀')
別に０からでもいいんだけど！（笑）

＜理想が現実になったコード＞
```php
# Treeview_1 ダブルクリック時のイベント
def Treeview_1_Double(event): 
    # 選択した行を取得
    selected_item = Treeview_1.selection()[0]
    # 値の取得
    values_0 = Treeview_1.item(selected_item)['values'][0]
    values_1 = Treeview_1.item(selected_item)['values'][1] 
    values_2 = Treeview_1.item(selected_item)['values'][2] 
    #テキストボックスの中身を削除
    Treeview_1_textbox_0.delete(0, tk.END)
    Treeview_1_textbox_1.delete(0, tk.END)
    # テキストボックスに値を代入
    Treeview_1_textbox_0.insert(tk.END,values_0) 
    Treeview_1_textbox_1.insert(tk.END,values_1) 
    intVar.set(values_2)
#表示するCSV設定
upno = 1
with open('csvパス', 'r', encoding = "utf_8") as f:
    reader = csv.reader(f, delimiter=',', quotechar='"')
    for cells in reader:
        if upno != 1:#csvデータの1列目colを読み込まない為にif入れています
            Treeview_1.insert("","end",values=(f"{cells[0]}",
                              f"{cells[1]}", f"{cells[2]}"))
        upno = upno + 1
#イベント発生トリガー
#ダブルクリックした列のデータをEntryに入れるイベントが発生する
Treeview_1.bind("<Double-1>", Treeview_1_Double)
#Treeview選択した値を格納する欄
Treeview_1_textbox_0 = tk.Entry(frame_move, width=5, font=("MSゴシック","15"))
Treeview_1_textbox_1 = tk.Entry(frame_move, width=20,font=("MSゴシック","15"))
intVar = tk.IntVar(value=0)
Treeview_1_spinbox = tk.Spinbox(frame_move, from_=0, to=100, 
                                increment=1,wrap=True, textvariable=intVar,
                                 width=5, font=("MSゴシック", "15"))#time
```
これで、やっと理想が現実になりました(;^ω^)
コピペしたときに、変数とか違ってたらごめんなさい！！！！！！！

＜ちな、コードが長いので簡単に書くと…＞
```php
#ダブルクリック イベント関数-------------------------------
def Treeview_1_Double(event): 
    # 選択した行を取得
    selected_item = Treeview_1.selection()[0]
    # 値を取得
    values_2 = Treeview_1.item(selected_item)['values'][2] 
    # 取得した値を「intVar」にセットする
    intVar.set(values_2)
#----------------------------------------------------------
#イベント発生トリガー
#ダブルクリックした列のデータをEntryに入れるイベントが発生する
Treeview_1.bind("<Double-1>", Treeview_1_Double)
#ダブルクリックする前は0に設定しておく（これが無いとエラー出るのでね…）
intVar = tk.IntVar(value=0)
Treeview_1_spinbox = tk.Spinbox(frame_move, from_=0, to=100, 
                                increment=1,wrap=True, textvariable=intVar,
                                 width=5, font=("MSゴシック", "15"))#time
#frame_move=表示するウィンドウ変数
#from_=spinboxの最小値
#to=spinboxの最大値
#increment=ボタン押したときの幅
#Wrap=最小値のときに↓ボタンを押すと最大値までスキップする（逆も行ける）
#textvariable=spinboxの初期値
#width=spinboxの横サイズ
#font=spinboxの文字フォント、文字の大きさ
```
spinboxの動きだけ書くとこんな感じです…。
この動作を詳しく知りたい人は「ウェジェット関数   tk.IntVar」と検索するべし…！

＜最後に＞
最近、やったことをQiitaに乗せるようにしてみたけど
記事を書くのに時間がかかる…次回は適当に書こうっと…(・_・;)
AccessのVBAでランタイム起動判定

# 概要

まず、AccessにはMicrosoft365に含まれるような **『通常版』** と そうでない **『ランタイム版』** の2種類がある。
また、 **『通常版では動作するが、ランタイム版だと動作しない』** といった挙動の違いもある。

『ランタイム版で開いたら警告 or Accessを即終了してシステム使用不可』
といったことをしたい。

その為にランタイムで起動しているか判定。

# やり方

```vb
If SysCmd(acSysCmdRuntime) Then
    Debug.Print "らんたいむで開いたな！"
End If
```

```SysCmd()``` はAccessにあらかじめ用意されている関数。
```acSysCmdRuntime``` はAccessにあらかじめ用意されている定数。

つまり、標準機能でランタイム起動判定できる。

# バージョン

Windows 10 Pro 21H2 OSビルド 19044.2130
Microsoft Access for Microsoft 365 MSO (バージョン 2209 ビルド 16.0.15629.20196) 32 ビット
【GAS】Googleドライブ：特定アカウントの共有ドライブへのアクセス権一括付与

# はじめに
本記事は、Google Workspaceを利用している組織のシステム管理者が、
Googleドライブの共有ドライブにおいて、特定アカウントのアクセス権を
一括で付与する手順について説明します。

# 実行結果
![execlog.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529154/88c371a0-b179-52f8-a81c-0ce3f7a52923.png)
※上図および本記事に登場する団体・名称・ID等はすべて架空のものです。

# 事前準備
1. 対象のすべての共有ドライブ対し、システム管理者（スクリプト実行者）を
「管理者」として追加します。<br>
[[Google Workspace管理コンソール]](https://admin.google.com/) → [アプリ] → [Google Workspace] → [ドライブとドキュメントの設定] → [共有ドライブの管理] → 対象の共有ドライブの[メンバーを管理] → システム管理者のアカウントを入力 → [管理者]を選択 → [共有]
![AdminConsole.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529154/479f2f91-745a-575f-244b-3de85fc2739c.png)

2. 新しいスプレッドシートを作成し、Apps Scriptに「Drive API」を追加します。<br>
[[Googleシート]](https://docs.google.com/spreadsheets/) → [新しいスプレッドシートを作成] → [拡張機能]タブ → [Apps Script]→
サービス[+] → [Drive API] → [追加]
![AppsScript.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529154/a89e2e01-9c08-25dd-a948-fa05258c444f.png)

3. 上記で作成したシートに、アクセス権を設定する共有ドライブ一覧を作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529154/99d8e600-0775-f7b8-5353-0ff0db8a1f1f.png)
共有ドライブ一覧は、私の書いた以下の記事なども参考にしてください。
[【GAS】Googleドライブ：共有ドライブID一覧出力](https://qiita.com/o-_-o/items/ce08ee77f8f59d43efe8)

# スクリプト
定数「req_body」の値として、以下の情報を入力してください。
　- role: 対象アカウントの役割（アクセス権の種別）[[注]](#注)
　- type: アカウント種別
　- value: 対象アカウントのメールアドレス
初回実行時はプロジェクトへの承認が求められますので、許可してください。

```javascript:script.gs
const act_sheet = SpreadsheetApp.getActive().getActiveSheet();
const array = act_sheet.getDataRange().getValues();
const req_body = {
  "role" : "reader",  // organizer, fileOrganizer, writer, reader
  "type" : "user",    // user, group, domain, anyone
  "value": "xxx@hogehoge.com" // Email address
};
const query_param = {
  "sendNotificationEmails" : false,
  "supportsAllDrives" : true
};

function myFunction() {
  array.shift();

  try{
    for (let i in array) {
      let drv_id = array[i][1];
      let drv_name = array[i][0];
      Drive.Permissions.insert(
        req_body, drv_id, query_param
      );
      console.log("Permission added : " + drv_name)
    }
  } catch (err) {
    console.log (err);
  }
}
```
# 参考
- Permissions: insert  |  Drive API  |  Google Developers
https://developers.google.com/drive/api/v2/reference/permissions/insert

- Roles  |  Drive API  |  Google Developers
https://developers.google.com/drive/api/guides/ref-roles

- The Gift of Script: Set permissions on a Shared drive
https://www.pbainbridge.co.uk/2021/06/set-permissions-on-shared-drive.html

- 【GAS】Googleドライブ：共有ドライブID一覧出力
https://qiita.com/o-_-o/items/ce08ee77f8f59d43efe8

# 注
Googleドライブにおける役割（アクセス権種別）の英語と日本語の対応は以下のとおりです。
詳しいアクセス権の内容については、参考にもあげた[Googleのリファレンス](https://developers.google.com/drive/api/guides/ref-roles)をご確認ください。

|English|日本語|
|---|---|
|organizer|管理者|
|fileOrganizer|コンテンツ管理者|
|writer|投稿者|
|reader|閲覧者|
クラウドネットワークを学ぶ④ ローカルVCNピアリングについて

# はじめに
OracleCloud勉強中の筆者が、特に理解しづらいと感じているNetworkまわりの話を平易に読み解いていきます。
今回はローカルVCNピアリングについて

# 概要
ローカルVCNピアリングは同じリージョン内の2つのVCNを接続する仕組みです。

# 説明
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727269/2193ec70-1a61-bc87-6021-3456ed392517.png)
この図のように、同一リージョン内で異なるVCNの間でVCNピアリングを用いて通信することができます。
インターネットやオンプレミスネットワーク経由の通信は不要です。

# 参考ページ
・ローカルピアリングについて
https://docs.oracle.com/ja-jp/iaas/Content/Network/Tasks/localVCNpeering.htm

# 最後に

今回はリージョン内のVCN間で通信するための手段として
「VCNピアリング」についてお伝えしました。
次回からは、オンプレミスからOCIへのマイグレーションについての投稿を予定しています。
RecyclerViewでAdapterにnullを入れた方がいい話

# 初めに
今回は、`RecyclerView`実装時にレビューをいただいて指摘された内容に疑問が残っていたので調べたものをまとめていこうと思います。
### 本文
自分が頂いたレビューは***RecyclerViewのAdapterにonDestroyViewでnullを入れてあげて***と言った内容でした。
ではなぜ、そうする必要があるのかですが、`Activity`よりも長生きしてしまう可能性があるからです。
そうするとメモリーリークが発生してしまいます。
明示的に`null`を入れてあげる事でメモリが解放されメモリリークの発生を防ぐことができます。
`Adapter#onAttachedToRecyclerView(RecyclerView)`
`Adapter#onDetachedFromRecyclerView(RecyclerView)`
`Adapter#onViewAttachedToWindow(ViewHolder)`
`Adapter#onViewDetachedFromWindow(ViewHolder)`
`Adapter`には上記4つのコールバッグがあり、`onViewDetachedFromWindow`が呼ばれないため、解放作業がされません。
`onViewAttachedToWindow`とペアになっているため、`onViewDetachedFromWindow`が呼ばれていないと`onViewAttachedToWindow`を再度呼び出したときにメモリの確保が先にされてしまっているため、メモリリークが起こります
### 最後に
自分がレビューで指摘されたときになんでだろうと思い調べたものをまとめさせていただきました
何かのお役に立てれば幸いです
to_iの挙動を確認する

## 環境
Ruby2.6

## はじめに
to_iは文字列を数値型（Integer）に変換するメソッドです。to_iの変数にイレギュラーな値がセットされた場合、どのような挙動を示すのか、動作確認してみました。

## 動作確認
- 元々数値である変数にto_iしても、元の木阿弥です。
- プラマイ符号がある場合は、プラマイ符号が取れます。
- float型の文字列に対してto_iした場合は、小数点以下が取れます。

```test.rb
puts "123".to_i         # => 123
puts 123.to_i           # => 123
puts "-123".to_i        # => -123
puts "-0".to_i          # => 0
puts "+123".to_i        # => 123
puts "123.0".to_i       # => 123
puts "123.9".to_i       # => 123
puts "0.5".to_i         # => 0
```

- このような変数は0に変換されます。例外に飛ばされることはありません。
```test.rb
puts "aaa".to_i         # => 0
puts "".to_i            # => 0
puts ''.to_i            # => 0
puts nil.to_i           # => 0
```

- このようなヘマはあまり考えられないとは思いますが、配列やハッシュに対してto_iをしてしまった場合は、エラーになります。例外処理を設定している場合は例外に飛びます。
```test.rb
puts [1,2].to_i                     # => undefined method `to_i' for [1, 2]:Array (NoMethodError)
puts [].to_i                        # => undefined method `to_i' for []:Array (NoMethodError)
puts {"うどん" => "300円"}.to_i      # => syntax error
```

- 数値とアルファベットが混在した文字列に対してto_iをした場合、文字列の先頭が数字であれば、先頭の数字の分だけが変換されます。いっそのこと、0を返してくれてもよさそうな気がしますが、なぜかこのような仕様になっています。
```test.rb
puts "123aa".to_i       # => 123
puts "123aa11".to_i     # => 123
puts "1a2a3".to_i       # => 1
puts "aaa3".to_i        # => 0
```

- 数値の前後にブランクが含まれる場合も、先頭の数字の分だけが変換されます。中途半端な仕様のような印象ではありますが、このような仕様になっているようです。
```test.rb
puts "  1".to_i         # => 1
puts "1   ".to_i        # => 1
puts " 8  2 ".to_i      # => 8
```

- アンダーバーは区切り文字として使えるため、数値の真ん中にアンダーバーがある場合でも変換してくれます。中途半端な個所にアンダーバーがあったとしても問題ありません。
- 金額で使われるカンマは区切り文字として認識されません。単なる文字列が紛れ込んでいると認識されてしまいます。金額を計算する場合は、カンマを省いてやる必要があります。Rubyには金額を扱う型（VBでいうCurrency型）というのは存在していません。
```test.rb
puts "123_123".to_i     # => 123123
puts "1231_23".to_i     # => 123123
puts "123,123".to_i     # => 123
```
SouceTreeのアップデートに失敗したときの対処法

# 結論
最新版のインストーラーを実行する

# 起動しなくなるまでの経緯
1. SouceTreeのアップデート通知が来ていたので、実行した。
1. 少し待つとエラーが発生し、アップデートは失敗となった。
1. 一度SouceTreeを終了した
※再起動したときにアップデートを実行してくれないかと期待したため
1. 再度SouceTreeを起動しようとしたが、何も応答がない

# 環境
- OS
    - Windows10Pro
- SouceTree
    - 3.4.8?

# sourcetree.log(一部抜粋)
```
ERROR [2022-10-18 10:03:34,329] [1] [Sourcetree.Installer.Squirrel.Utils.UpdateHelper] [Log] - Unable to complete update
System.MissingMethodException: メソッドが見つかりません: 'Void SharpCompress.Readers.IReaderExtensions.WriteEntryToFile(SharpCompress.Readers.IReader, System.String, SharpCompress.Readers.ExtractionOptions)'
   場所 Squirrel.ReleasePackage.<>c__DisplayClass15_2.<ExtractZipForInstall>b__1()
   場所 Squirrel.Utility.<>c__DisplayClass8_0.<Retry>b__0()
   場所 Squirrel.Utility.Retry[T](Func`1 block, Int32 retries)
   場所 Squirrel.ReleasePackage.<>c__DisplayClass15_0.<ExtractZipForInstall>b__0()
   場所 System.Threading.Tasks.Task.Execute()
--- 直前に例外がスローされた場所からのスタック トレースの終わり ---
   場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   場所 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   場所 Squirrel.UpdateManager.ApplyReleasesImpl.<>c__DisplayClass7_0.<<installPackageToAppDir>b__0>d.MoveNext()
--- 直前に例外がスローされた場所からのスタック トレースの終わり ---
   場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   場所 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   場所 Squirrel.Utility.<LogIfThrows>d__43`1.MoveNext()
--- 直前に例外がスローされた場所からのスタック トレースの終わり ---
   場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   場所 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   場所 Squirrel.UpdateManager.ApplyReleasesImpl.<ApplyReleases>d__2.MoveNext()
--- 直前に例外がスローされた場所からのスタック トレースの終わり ---
   場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   場所 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   場所 Squirrel.UpdateManager.<ApplyReleases>d__10.MoveNext()
--- 直前に例外がスローされた場所からのスタック トレースの終わり ---
   場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   場所 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   場所 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   場所 Sourcetree.Installer.Squirrel.Utils.UpdateHelper.<DownloadAvailableUpdates>d__27.MoveNext()
ERROR [2022-10-18 10:03:34,380] [1] [SourceTree.Notifications.NotificationsManager] [Log] - Unable to set owner as parent is not visible or non-existent
2022-10-18T15:13:37: LogHost: Initializing to normal mode
```

# 推測
インストーラーを起動したことで、見つからなかったメソッドが同梱されたDLL等を入手できたので起動するようになったのではないか

# 最後に
結局どうして起動するようになったのかはわからないままだが、解決策だけを共有しておく
apacheで負荷テスト

# はじめに
負荷テストを実施する際の備忘録です。
使用ツール：apache
テスト対象：AWS EC2インスタンス（Wordpress、EC-CUBE）

# テストのコマンド
ab -n リクエスト数　-c 同時発行数 URL
vmstat -t 2

# テスト結果
t2.microだと、１つのCPUが張り付くと耐えられない（OSプロセス自体もハングしてしまうため、システムとして応答できなくなる）ことが判明。また、同時発行数は１CPUだと8程度までいくとCPUが100%となり十分に動かない。

| インスタンスタイプ | 総リクエスト数 | 同時発行数 | CPU最大値 | 結果 |
| --- | --- | --- | --- | --- | 
| t2.micro | 10 | 1 |  6 | 〇 |
| t2.micro | 10 | 2 | 45 | 〇 |
| t2.micro | 10 | 3 | 61 | 〇 |
| t2.micro | 30 | 3 | 67 | 〇 |
| t2.micro | 30 | 4 | 75 | 〇 |
| t2.micro | 50 | 5 | 77 | 〇 |
| t2.micro | 50 | 8 | 100 | × |
| t2.medium | 50 | 10 | 100 | 〇 |
| t2.medium | 60 | 20 | 86 | 〇 |
| t2.medium | 100 | 30 | 86 | 〇 |

# 参考文献
https://qiita.com/flexfirm/items/ac5a2f53cfa933a37192
https://qiita.com/toshihirock/items/0e0b20064730469e93e6
PyCon JP 2022 day1 Pythonに上級テクニックは要らない（そして正しい付き合い方）

現地参加したPyCon JP 2022のセッションのまとめ4本目です。

今回は、Day1の「Pythonに上級テクニックは要らない（そして正しい付き合い方）」です。

# 動画
<iframe width="560" height="315" src="https://www.youtube.com/embed/-Tbaedxz_4c?start=7554" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

# スライド
- http://slides.hirokiky.org/pyconjp2022.html#1

# スピーカー
- 清原弘貴さん
  - 株式会社ゼンプロダクツ
    - 代表取締役

# 内容まとめ
- テクニックを過剰に使いすぎず、可読性・メンテナンス性の高いPythonコードを書くには、というお話

## テクニックとは
- 例
  - デコレータ
  - Context Manager
  - ジェネレーター
  - 型ヒント
  - など
- これらは学ぶと使いたくなる、使っていくべきもの
- しかし、過剰に手を染めすぎると可読性もメンテナンス性も下がる

## 理想としては
- 要件に合わせた意図を、プログラムという形で読みやすく記述できればいい
- テクニックは上手く隠蔽されているべきである

## テクニックを使う場の見極め
### 手元のテクニック
- 仕事で書く自分の範囲
### チームのテクニック
- 仕事のプロジェクトで書く中心部分
### 世界のテクニック
- 広く使われる・根底になるライブラリーやフレームワーク

## 内包表記
- 単純な場合は使おう
- しかし、二重の内包表記は避けた方がいい。ループで良い。
  - 「内包表記の方が速い」が、その速度差を意識すべき場でないことがほとんど

## 外部や未来への影響
- 重要なのは、**外部との関わり**である
- 外部の関数やモジュールに影響がないなら好きにすればいい
- テストの書きやすさやモデルの設計こそが重要
- 最初は、プロジェクトやフレームワークの指示に従い学ぶ

## なぜクラスにするのか？
- 辞書やタプルで十分な場合もある
  - その方がテストしやすい
- 「ユーザーという辞書」のような概念があったり、共通した形を期待する関数が多い場合はクラスにする

## あんまり使ってほしくないもの
- `global`・`local`
  - モジュールのグローバルな状態に依存
- `subprocess`
  - 外部環境への依存

## 基底クラス
- 1回継承させる程度が良い
- 例えば、`BaseBackend`・`FoobarBackend`など

## 「間を書き換えたい」は危険
- 「長い処理のここだけ書き換えたいからクラスを継承させる」というのは危険
- 重複したコードでも2つ程度なら良い
  - `DRY(Don't Repeat Yourself)`の原則からは外れるので、難しいラインではあるけど

## 継承やクラスの意図が重要
- OK
  - ビジネス上の処理のフローが決定していて、それを基底クラスとして決めた
- NG
  - 継承すれば書き換えられるから、基底クラスにしておいた

## まとめ
- テクニックは積極的に学ぶべきだが、要らないなら無理に使わなくても良い
- しかし、使っていかないと学べないのも確か
- 受け身に使える文法は多くて良いが、能動的に使うときは見極めよう
  - 練習で作って失敗しておこう
- 実は「テクニック」よりも関数の設計やモジュールの分割などが重要
- 学ぶには作って経験すること、テストを書くこと、他人のコードを読むことが大事

# 感想
- 内包表記使うかループを使うかは、私も悩んだことがあります。
- そして、他の言語でもこういうことあるなと思いました。
- テストコードが書きにくいということは、設計や実装に改善点があると思うので、そういう時にしっかり考えたいですね。
iOSアプリ配信時の流れ

## 前書き
2年前くらいにiOSアプリ開発した際にアプリ配信するまでの流れをすんなり理解できず、
いろいろ調査してまとめた資料を公開してみようと思い立ちました。

## 本題
資料といっても1枚絵にまとめた俯瞰図です。
個人で調べてまとめたものなので誤りがあるかもしれません。
また、配信方法に関してはよく変更されるようなので正確な情報は公式ページを参考にしてください。

![iOSアプリ配信方法俯瞰図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488612/a62af872-5b79-476d-3694-20951ce38aa0.png)


#### 用語補足
* Apple Developer Program(ADP)：個人または企業が登録可能なメンバーシップ

* Apple Developer Enterprise Program(ADEP)：企業のみが登録可能なメンバーシップ

* Apple Developer：アプリ開発に必要な機能を提供する無料Webサービス（ADP/ADEP必須）

* Apple ID：Apple社が提供するサービスを利用するのに必要なアカウントID

* App：iOSアプリケーション

* App ID：アプリ識別に使用される文字列、Team IDとBundle IDまたはワイルドカードで構成される

* Bundle ID：アプリ識別に使用される一意の文字列

* UDID：Unique Device Identifier、iOS端末に固有のID

* Provisioning Profile：開発者や端末とアプリを紐づけるバイナリファイル

* App Store Connect：App Store または TestFlight で配信するアプリを管理する無料Webソリューション（ADP/ADEP必須）

* MDM：Mobile Device Management、多数のデバイスを一元管理しアプリ配信も可能なサービス。
Apple社ではなく複数の一般企業が提供している。

* ABM：Apple Business Manager、DEPとVPPの機能を包括したApple社提供の無料サービス。
MDMと連携することで効果を発揮する。

* DEP：Device Enrollment Program、購入したデバイスの登録や設定を効率化するサービス

* VPP：Volume Parchase Program、AppStore上のコンテンツを一括購入するためのサービス

* TestFlight：開発者内部または外部の一般ユーザ向けにベータ版アプリをテストする際に利用するサービス
リーダブルコード

リーダブルコード  
書籍：https://www.amazon.co.jp/リーダブルコード-―より良いコードを書くためのシンプルで実践的なテクニック-Theory-practice-Boswell/dp/4873115655

本書籍は読みやすいコードの書き方について書かれている。
読みやすい変数名の付け方や関数の書き方等、迷われたことがある方は読んだ方が良い。
どこかの記事ではリーダブルコードを読んだことが無いエンジニアはエンジニアでは無いと
書かれていたので、エンジニアであれば一度は読んでおきたい書籍である。

優れたコードとは  
優れたコードとは、理解しやすいコードである。
本書では、読みやすさを「他の人が最短時間で理解できる」と定義している。
ここでの「他の人」は半年後の自分も含まれている。

名前に情報を詰め込む  
名前は短いコメントである。
良い名前を付けることができれば短時間で多くの情報を伝えることができる。
理想は、名前を見ただけで情報を読み取れるようにすることである。

明確な単語を選ぶ  
多くの情報を伝えることができる単語を選ぶ必要がある。
例えば、getは明確な単語ではない。getPage()という関数があったとしても、ページをどこから取ってくるのかが明確ではない。
インターネットからページを取ってくるのであればFetchPage()やDownloadPage()の方が明確である。
このように、より多くの情報を伝えることができる単語を選ぶべきである。

汎用的な名前は避ける  
tmp,retval,fooのような名前を付けるのは良くない。
「明確な単語を選ぶ」でも書いたように、tmpからは明確な情報がほとんど伝わってこない。
コードを読む人が短時間で理解できるように、エンティティの値や目的を表した名前を付けるべきである。

しかし、tmp,retval,fooに関してそれ相応の理由があれば使用しても良い。
例えば、「生存期間が短くて一時的な補完が最も大切な変数」であればtmpを使用しても良い。

名前に情報を追加する  
名前は出来るだけ具体的に付けた方が良い。
そのため、絶対に伝えたい情報があれば単語を変数名に追加する。
例えば、16進数の文字列を持つ変数には"hex"を名前に追加する。

名前の長さを決める  
変数名の長さを決めるのはスコープの大きさである。
スコープが小さければ、変数は短い名前でも良い。
理由は、コードを理解するのに必要な情報がそばにあるからである。
スコープが大きければ、長い名前を付けて多くの情報を読み手に伝えた方が良い。

コメント  
コメントの目的は書き手の意図を読み手に知らせることである。
コメントは簡潔かつ正確に書く。

コメントするべきではないこと
コメントを読むとその分だけコードを読む時間が無くなる。
つまり、コメントにはそれだけの価値を持たせるべきである。

価値のないコメントとは
コードからすぐに分かることをコメントに書かない。
ひどい名前の変数はコメントを付けるのではなく、名前を変えるべきである。
自分の考えを記録する
コードを理解するためのコメントだけでなく、大切な考えも記述する
コードに欠陥があるときにコメントを書いておく。

TODO：あとで手を付ける
FIXME：既知の不具合がある
HACK：あまりきれいじゃない解決策
といったものがある。
読み手の立場になる
プロジェクトを知らない人に、コードがどのように見えるかを想像することが重要である。

質問されそうなことを想像する
コードを客観的に見て、疑問に思うところがあればコメントを付ける。
ハマりそうな罠を告知する
コードを客観的に見て、「どんな風に間違えて使う可能性があるか」を自問自答する。
コードを使うときに直面する問題を前もって予測しコメントを付ける。
全体像が把握できるコメントを付ける
新しくチームに入った人が全体像を把握するために、
「このファイル、クラスはアプリケーションの○○機能である」とコメントを付ける。
コードが読みやすくなるように変数を使う  
変数を適当に使うと、コードは読みにくくなってしまう。
適当に使うとは、例えば以下の三点である

変数が多いと変数を追跡するのが難しくなる
変数のスコープが大きいとスコープを把握する時間が長くなる
変数が頻繁に変更されると現在の値を把握するのが難しくなる
不要な変数を削除する  
now = datetime.datetime.now()
root_message.last_view_time = now
このnowを使う意味は無い。理由は以下である。
・ 複雑な式を分割していない
・ より明確になっていない。datetime.datetime.now()のままでも理解できる
・ 一度しか使ってないので重複コードの削除になっていない
つまり、nowという変数がなくてもコードは理解できる。

変数のスコープを縮める  
変数のことが見えるコード行数をできるだけ減らすことが大切である。
たくさんの変数が見えてしまうと、一度に考えなければならない変数の量が増えてしまう。
変数のスコープを1/2に縮めることができれば、スコープに存在する変数の数は平均して1/2になる。

変数は一度だけ書き込む  
変数を操作する場所が増えると、現在値の判断が難しくなる。
そのため、「変数は一度だけ書き込む」ことを意識した方が良い。
永久的に変更されない変数は扱いやすい。
constやfinalなどのイミュータブルにする方法を使えばコードを理解しやすくなる。

感想  
本記事はリーダブルコードの一部しか紹介していない。
優れたコードを書きたいのであれば、リーダブルコードを読むことをお勧めする。
私はまだまだ知識不足なので、コードを書くことで手一杯である。
少しずつ本書に書かれていたことを意識していき、優れたコードを書けるように成長していきたい。
まずは、本記事に書いたことを意識してコードを書こうと考えている。
名前の付け方に関しては、英語の知識が無さすぎるので英単語も勉強していこうと思う。
UbuntuのCPU, GPU情報を確認する

# はじめに
本記事をご覧いただきありがとうございます。
この記事では、Ubuntuを用いてハードウェアのスペックを確認する方法を紹介します。

# CPUの確認

```
$ nproc
8
```

# GPUの確認

```
$ lspci | grep -i nvidia
01:00.0 VGA compatible controller: NVIDIA Corporation GP102 [TITAN X] (rev a1)
01:00.1 Audio device: NVIDIA Corporation GP102 HDMI Audio Controller (rev a1)
02:00.0 VGA compatible controller: NVIDIA Corporation GP102 [TITAN X] (rev a1)
02:00.1 Audio device: NVIDIA Corporation GP102 HDMI Audio Controller (rev a1)
```


# RAMの確認

```
$ free -g
               total        used        free      shared  buff/cache   available
Mem:              62           3          27           7          31          50
Swap:              1           0           1
```
【Laravel + Vue + Vue Router + Vuex】iphone標準のリマインダーみたいなTODOアプリをSPAとして作ってみた ①作成背景とアプリ概要

Laravel+Vue+Vue Router+Vuexを使って、iphpne標準のリマインダーのようなTODOアプリを作りました。
この記事では、TODOアプリを作るに至った理由を記載していきます。

## ■TODOアプリ制作の背景
### ①導入
多忙な現代人にとって、日々のTODO管理は業務を遂行する上で必要不可欠です。
つまり、アナログ・デジタル問わずTODOを管理するシステムが効率的・生産的になればなるほど、
現代人の生産性は向上していきます。
そのため、様々なTODOアプリが世の中には多く存在し、多くの人に利用されています。

### ②問題点
しかし、一方で様々なTODOアプリがあるため、操作性の違い、機能の違いといった
アプリごとの使いやすさが異なっています。
アプリごとに操作性や機能が異なるということは、それぞれのアプリごとに操作性や機能を覚えていかなければいけないということを意味します。
生産性・効率性を高めるためのTODOアプリに対して、そのアプリを使うこと自体の手間が発生することは、結果的に生産性や効率性を低くしてしまっていると予測されます。

### ③今回のアプリ開発で実現したいこと
そこで、汎用的な操作性と機能性を備えたTODOアプリを作ろうと考えました。

### ④汎用的な操作性の定義
汎用的な操作性とは何でしょうか？
今回の開発では、汎用的な操作性とは多くの人が一度は使ったことがあるアプリに操作性が近いことと、定義付けました。

多くの人が使用したことのあるアプリとして、LINEをベースにしました。
LINEは、日本人のスマホ・ケータイ所有者の81.6%が使用しているアプリだからです。
以下は2022年にNTTドコモで行われたSNS利用率調査の結果です。

SNS利用率調査
[調査対象：全国・15～79歳男女・スマホ・ケータイ所有者対象・複数回答・n=6,587]
![sns20220516_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852556/14a9dd33-46a8-a60e-4d8e-090c35d54837.png)
出典：2022年一般向けモバイル動向調査

### ⑤汎用的な機能性の検討と競合比較
次に汎用的な機能性を考えます。
まずは競合比較として、iphoneリマインダー、GoogleTodoリスト、Todo（タスク管理アプリ）の機能を調査しました。
その結果、機能としてはiphoneリマインダーが一番多くの機能を備えていることが判明しました。

#### ■主な機能の競合比較
| 機能/アプリ名 | iphoneリマインダー | GoogleTodoリスト | ToDo（タスク管理アプリ）|
|:-----------:|:------------:|:------------:|:------------:|
| Todo追加       |〇|〇|〇|
| リスト追加     |〇|〇|〇|
| 子リスト追加       |✕|〇|✕|
| フッター<br>メニュー         |✕|✕|✕|
| 全Todo表示       |〇|✕|〇|
| 今日の<br>Todo表示    |〇|✕|✕|
| 期限有り<br>Todo表示    |〇|✕|〇|
| 期限切れ<br>Todo表示    |〇|✕|✕|
| 検索機能    |〇|✕|✕|
| 並び替え    |〇|〇|〇|
| Todoスワイプ<br>操作（編集）    |〇|✕|✕|
| ピン止め    |〇|〇|✕|
| 繰り返し    |〇|〇|〇|
| 日付・時刻選択    |〇|〇|〇|
| 画像添付    |〇|✕|〇|
| 優先度付け    |〇|✕|✕|
| 場所選択    |〇|✕|〇|
| 実行済表示    |〇|〇|〇|

#### 3.第三者の意見

また、第三者の意見として、iphone標準リマインダーを使用している知人に聞き取り調査を行いました。
その結果、機能性としてはリマインダーで満足しているが、以下の点が改善されるとより使用しやすいとの回答を得ました。
①子リスト（カテゴリーなど、リストの子要素）を追加したい
　※GoogleのTodoリストでは使用できる機能です。
②検索ボックスについて、トップ画面ではなく、各リストごとのページに欲しい
③スマホで操作を行うため、リスト切り替えを画面下部でも行えるようことが望ましい

以上より、上記意見を踏まえて、iphone標準リマインダーの機能をベースに、操作性をLINEっぽく、
誰でも簡単に操作できるように、改良していく方向性を固めました。


## ■TODOアプリの概要
前述の分析から、iphone標準リマインダーを参考にし、以下のような機能を持ったTODOアプリを作成することにしました。
画面全体のデザインはLINEとiphone標準リマインダーをミックスしたデザインを目指します。
・TODO追加
・リスト追加
・全てのTODO表示
・今日のTODO表示
・日時指定ありのTODO表示
・期限切れのTODO表示
・検索機能
・並び替え機能
・リスト機能
・TODOスワイプによる編集操作
・タスクピン止め
・TODOの繰り返し
・優先度付け
・日付・時刻選択
・画像・場所の選択
・カテゴリー機能（子リスト機能）
・フッター機能（画面下部での操作性向上）
・新規登録・ログイン・ログアウト・退会機能

作成背景とアプリ概要は以上です。
次の②では実際に作成したアプリについて、開発環境や開発時にこだわった点、今後の課題を記載していきます。
②は以下の記事から↓

[Laravel + Vue + Vue Router + Vuex】iphone標準のリマインダーみたいなTODOアプリをSPAとして作ってみた ②開発環境と開発時にこだわったこと](https://qiita.com/takuma-k/items/292ea083735c6f2dc6c7 "Laravel + Vue + Vue Router + Vuex】iphone標準のリマインダーみたいなTODOアプリをSPAとして作ってみた ②開発環境と開発時にこだわったこと")
unityアニメーションIdle switch

```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class Animation : MonoBehaviour
{
    private Animator anim;
    bool play = false;
    public InputAction playerControls;
    private float leftClick;

    private void OnEnable()
    {
        playerControls.Enable();
    }

    private void OnDisable()
    {
        playerControls.Disable();
    }

    void Start()
    {
        anim = GetComponent<Animator>();
    }

    void Update()
    {
        leftClick = playerControls.ReadValue<float>();
        if (Input.GetMouseButtonDown(0) || Input.GetKeyUp(KeyCode.P) || Input.GetKeyUp(KeyCode.Space) || leftClick==1)
        {
            play = !play;
        }

        if (play) 
            anim.SetBool("isPlay", true);
        else
            anim.SetBool("isPlay", false);
    }
}
```
unityオブジェクト360度回転


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

public class Rotation : MonoBehaviour
{
	public enum RotationAxis
	{
		All,
		Y,
		X,
		Z
	}

	public RotationAxis axis;
	public float speedRot = 0.3f;

	void Update ()
	{
		float rot = Time.deltaTime * speedRot;

		switch( axis )
		{
			default:
			case RotationAxis.All:
				transform.Rotate( new Vector3( rot, rot, rot ) );
				break;

			case RotationAxis.X:
				transform.Rotate( new Vector3( rot, 0f, 0f ) );
				break;

			case RotationAxis.Y:
				transform.Rotate( new Vector3( 0f, rot, 0f ) );
				break;

			case RotationAxis.Z:
				transform.Rotate( new Vector3( 0f, 0f, rot ) );
				break;
		}
	}
}
```
【Javascript/正規表現】HTMLのテキストドキュメントからcolor属性を排除

# はじめに
仕様くん 「下のファイルから color: xxx; の部分だけ抜いといて〜」
私 「...（なんか難しそう）」
仕様くん 「でも```<style>...</style>```の中からは抜いちゃダメだよ」
私 「...（絶望）」

※わかりやすくするためにhtml形式で書いてますが、用意されていたのはテキストファイル形式でした。

```html
<h1 style="color:blue">あいうえお</h1>
<p style="font-weight:600; font-size:14px;"><a style="color:red;">かきくけこ</a></p>

<style>
h1, p, a {
  color: #fff;
}
</style>
```

# 実装
```javascript
// 引数でテキストファイル受け取り
function(str) {

  // テキストファイル内で「<style>」が何文字目に出るかを保持
  let startIndex = str.indexOf("<style>");

  // テキストファイル内の<style>以降を保持
  let styleDoc = str.slice(startIndex);
  
  // 「color: xxx;」をテキスト内で空文字置換
  let removeColorDoc = str.replace(/(?<!-)color:(.*?);/g, '');

  // 置換したファイルから、<style>より前を取得
  let removeColorHtmlDoc = removeColorDoc.slice(0 , startIndex - 1);

  // 置換したファイルの<style>より前部分と、元ファイルの<style>移行を合体
  let removeColorStyleDoc = removeColorHtmlDoc + styleDoc;
}
```

# 正規表現の中身
```javascript
// 「color: xxx;」をテキスト内で空文字置換
let removeColorDoc = str.replace(/(?<!-)color:(.*?);/g, '');
```
### 否定的先読み
 ```(?<!-)color```は、否定的先読みという手法で、例えば```background-color: ```は引っ掛けず、```color: ```だけを引っ掛けようとしています。

### gオプション
末尾の```g```はgオプションというものです。通常```replace```を使うと、対象の文字列がいくつあっても最初にマッチした文字列しか置換できません。gオプションを使うと、その縛りが解消され、全ての```color: xxx;```を置き換えてくれます。
# 結果
```<style>```より前部分から、```color:xxx;```の表記が消えました！！
めでたい。
```html
<h1 style="">あいうえお</h1>
<p style="font-weight:600; font-size:14px;"><a style="">かきくけこ</a></p>

<style>
h1, p, a {
  color: #fff;
}
</style>
```
:::note
この例に沿って書くと、例えば ```color: transparent;``` なども全て消し飛びます。「色変更は消したいけどtransparentは残したい」などの要望の場合、現状のJavascriptでは難しそうです。
:::

# 終わりに
正規表現、なかなか使いこなせるようになれませんが、良い勉強になりました。

# 参考
[先読みと後読みを使ったパターン](https://www.javadrive.jp/regex-basic/writing/index2.html)
[[JavaScript]正規表現(gオプション,iオプション)](https://qiita.com/yuichir43705457/items/6503f257f1d81e9239e3)
【GAS】Googleドライブ：共有ドライブID一覧出力

# はじめに
本記事は、Google Workspaceを利用している組織のシステム管理者が、
Googleドライブにおける共有ドライブのID一覧を出力する手順について説明します。

# 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529154/ae048d33-979e-3f3a-7b13-e48237321e04.png)

※上図に登場する団体・名称・ID等はすべて架空のものです。

# 事前準備
1. 出力対象のすべての共有ドライブ対し、システム管理者（スクリプト実行者）を
「管理者」として追加します。<br>
[[Google Workspace管理コンソール]](https://admin.google.com/) → [アプリ] → [Google Workspace] → [ドライブとドキュメントの設定] → [共有ドライブの管理] → 対象の共有ドライブの[メンバーを管理] → システム管理者のアカウントを入力 → [管理者]を選択 → [共有]
![AdminConsole.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529154/479f2f91-745a-575f-244b-3de85fc2739c.png)

2. 出力先のスプレッドシートを作成し、Apps Scriptに「Drive API」を追加します。<br>
[[Googleシート]](https://docs.google.com/spreadsheets/) → [新しいスプレッドシートを作成] → [拡張機能]タブ → [Apps Script]→
サービス[+] → [Drive API] → [追加]
![AppsScript.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529154/a89e2e01-9c08-25dd-a948-fa05258c444f.png)

# スクリプト
Apps Scriptから下記のスクリプトを実行します。
初回実行時はプロジェクトへの承認が求められますので、許可してください。

```javascript:script.gs
const act_sheet = SpreadsheetApp.getActive().getActiveSheet();
let drv_list, drv_info, drv_token;
let array = [];

function myFunction() {
  array.push(["共有ドライブ", "ID"]);

  // Drive APIから共有ドライブのリストを取得、pageTokenがある限り繰り返し
  do {
    drv_list = Drive.Drives.list({
      maxResults: 100,
      pageToken: drv_token,
      useDomainAdminAccess: true
    });

    // 共有ドライブのリストから共有ドライブ名、IDを取得
    for (let i = 0; i < drv_list.items.length; i++) {
      drv_info = drv_list.items[i];
      array.push([drv_info.name, drv_info.id]);
    }

    drv_token = drv_list.nextPageToken;
  } while (drv_token);

  // 配列をGoogleシートに反映
  act_sheet.clear();
  act_sheet.setFrozenRows(1);
  act_sheet.getRange(1, 1, array.length, array[0].length).setValues(array);
}
```
# 参考
- Drives: list  |  Drive API  |  Google Developers
https://developers.google.com/drive/api/v2/reference/drives/list
LPC812MAXと温度,STTS751で液晶温度計 (Mbed)(AQM0802A)


x mbed2リビジョン144
x リビジョンの変更ができる人むけ


x 昔、秋月で売っていた温度センサーSTTS751
代用品は、S-5851A。(おもにアドレスの違い)


目的
AQM0802Aで遊ぶ
適当にあつたI2C温度センサーを使用


![o_cop143.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/58f883fe-f52c-434c-d16c-3586e2dff8b2.jpeg)



I2C_LCD_751_812_1



```c++


#include "mbed.h"

//STTS751 0x39
#define ADDR        (0x72) //  address
#define ADDR_LCD    (0x7C) //  address

//       SDA    SCL
I2C i2c(A4, A5); //812

//10の割り算 0から1028までは、正しい。主に0から999
#define DIV10(n) ((n*205)>>11)

char    tempval;        //温度
char    data_read[6];   //i2cバッファー

//液晶初期化配列
char INIT_com[]= {0x0,0x38,
                  0x0,0x39,
                  0x0,0x4,
                  0x0,0x14,
                  0x0,0x70,
                  0x0,0x56,
                  0x0,0x6C,
                  0x0,0x38,
                  0x0,0xC,
                  0x0,0x1,
                  0x40,0x41
                 };

//液晶のクリア
char INIT_cls[]= {0x0,0x1};

//メイン関数
int main()
{

    //液晶の初期化
    for(int ii=0; ii<11; ii++) {
        i2c.write(ADDR_LCD, &INIT_com[ii*2], 2);
        wait_ms(2);
    }//for

    //無限ループ
    while (1) {

        //液晶のクリア
        i2c.write(ADDR_LCD,INIT_cls,2);
        wait_ms(2);

        //初期化
        //set address 0
        i2c.write(ADDR, "\000", 1); //addres 0

        //温度の読み込み
        // Read temperature register
        i2c.read(ADDR, &tempval,1);

        //tempval = 21; //debug

        //液晶に出力
        // Display result
        data_read[3] = 0;
        data_read[2] = '0' + tempval - ( DIV10(tempval) * 10 ); //1の桁
        data_read[1] = '0' + DIV10(tempval);                    //10の桁
        data_read[0] = '@';
        i2c.write(ADDR_LCD, data_read,3);

        //1秒待つ
        wait_ms(1000);

    }//while

}//main



```


おまけ



![o_cop165.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/2e7cf746-978f-24dd-fac5-dff860e1ccbd.jpeg)
nRF Connect SDK:USB(NCS 2.x+)

# 過去記事
過去にもUSB CDC ACMに関する記事を書いています。

https://qiita.com/yoshihiro0709/items/bfa57777513e5c0d1a8c

が、残念ながらNCS 2.xになってからこのサンプルコードは使えなくなりました。
ということで改めてまとめていきます。

# NCS 2.xで動かす
正直なところVSCodeになってから色々と簡単になった気がします。あれほど使うの嫌がっていたのに(笑)
でもnRF SDKのプロジェクトはまだまだ残っているので、そんな簡単にSegger Embedded Studioを捨てることはできません。
## SES時代は非公開サンプルだったが・・・
VSCodeになってからは公開サンプルとして普通にUSB CDC ACMは選択できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/e6cd16dd-b21a-5f02-a212-a53b27f44a7b.png)
## 対応ボードがない・・・？
いざビルドの設定をしようと思ったらCompatible boardsの一覧にはnRF52シリーズがない！
のですが、Nordic boardsやAll boardsで選んであげれば普通に使うことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/12055fde-d2c8-bf21-bd79-0687bf5a85ff.png)
## デバッグ
コンパイルが終わったらデバッグで動かしてみましょう。いつの間にかデバッグも使いやすくなっていますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/98302254-b55f-0130-281c-8789f65eafb8.png)
TeraTermを起動して文字を入力すると、ちゃんとエコーバックが返ってきます。
(ローカルエコーをONにしているので2文字ずつ表示されています)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/dcdc8f65-ec70-f4ca-d1da-eabe4ee2f527.png)

::: note
VSCodeでもターミナル接続はできますが、あえてTeraTermを使っているのはVSCode上のターミナルはログ出力に使うためです。
:::

# 総括
あれ、コード1文字もいじらなくても動いちゃった・・・。そりゃサンプルだからね！
旧版からの変更点はapp.overlayが追加され、DeviceTreeにcdc_acm_uart0が追加された点です。
``` app.overlay
/*
 * Copyright (c) 2021 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

&zephyr_udc0 {
	cdc_acm_uart0 {
		compatible = "zephyr,cdc-acm-uart";
	};
};
```

また、以前のprj.confで設定していたいくつかの項目は消滅しました。
``` prj.conf
CONFIG_STDOUT_CONSOLE=y
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_DEVICE_PRODUCT="Zephyr CDC ACM sample"
CONFIG_LOG=y
CONFIG_USB_DRIVER_LOG_LEVEL_ERR=y
CONFIG_USB_DEVICE_LOG_LEVEL_ERR=y
CONFIG_SERIAL=y
CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_UART_LINE_CTRL=y
```

::: note
上記prj.confはサンプルコードそのままを抜き出していますが、実はこの中にも要らない設定がいくつか混じっています。
:::
Unity AndroidアプリでFirebase Crashlyticsを使うのにハマった話

# この記事について
UnityでAndroidアプリにFirebase Crashlyticsを利用する際、ハマった部分をまとめました。

# バージョン
Unity 2021.3.11f1
firebase unity sdk 9.6.0

# 事象
[Firebaseドキュメント](https://firebase.google.com/docs/crashlytics/get-started?platform=unity&hl=ja)に沿ってアプリを作成し、実行したところ、`adb logcat`でなんかエラーが出た:boom:
（ビルドのタイミングで出て欲しい:sweat_drops:）

```
10-17 15:19:00.821 17474 17552 E firebase: Failed to read Firebase options from the app's resources. Either make sure google-services.json is included in your build or specify options explicitly.
```

# いきなり結論
Unity 2020.1以降では[Firebaseドキュメント](https://firebase.google.com/docs/crashlytics/get-started?platform=unity&hl=ja)通りのやり方ではFirebaseは動かない:bangbang:
Unity 2019を使ってね、と[Firebase blog](https://firebase.blog/posts/2020/08/firebase-compatibility-with-unity-20201
)では言っている。

# Unity 2020.1以降での作業
前提として、[Firebaseドキュメント](https://firebase.google.com/docs/crashlytics/get-started?platform=unity&hl=ja)の作業は完了しているものとします

### Unity 2020.1以降でFirebaseを使えるようにする

ビルド設定 -> プレイヤー設定でプレイヤーを開く
プレイヤー -> 公開設定で

- カスタムメイン Gradle テンプレート
- カスタム Gradle プロパティテンプレート

へチェックボックスを入れる


`Assets/Plugins/Android/mainTemplate.gradle`の末尾に以下を追記する

```
android {
    sourceSets {
        main {
            def unityProjectPath = $/file:///**DIR_UNITYPROJECT**/$.replace("", "/")
            res.srcDirs += (unityProjectPath +  '/Assets/Plugins/Android/Firebase/res/values/google-services.xml')
        }
    }
} 
```

`Assets/Plugins/Android/gradleTemplate.properties`の末尾に以下を追記する

```
android.useAndroidX=true
android.enableJetifier=true 
```

### Crashlyticsを使えるようにする追加作業

ビルド設定 -> プレイヤー設定でプレイヤーを開く
プレイヤー -> 公開設定で

- カスタムランチャー Gradle テンプレート
- カスタムベース Gradle テンプレート

へチェックボックスを入れる

`Assets/Plugins/Android/baseProjectTemplate.gradle`の`allprojects.buildscript.dependencies`に以下を追記する

```
// Add the Crashlytics Gradle plugin.
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.2.0'
```

`Assets/Plugins/Android/launcherTemplate.gradle`の末尾に以下を追記する

```
// Apply the Crashlytics Gradle plugin
apply plugin: 'com.google.firebase.crashlytics' 
```

### 最後に
Assetフォルダへ`google-services.json`の配置確認（私の環境ではいつの間にか消えていました）
**Unityを再起動**（大事:bangbang:）

# 参考
https://firebase.blog/posts/2020/08/firebase-compatibility-with-unity-20201
AWS EC2 インスタンスタイプの一括自動更新

# TODO
 * EC2のイベント対応で夜間に自動停止・起動
 * インスタンスタイプを夜間に自動更新

# 内容

## tag
  * Key=Schedule, Value= [1:予約あり, 0:予約実行完了]
  * オプション
    例）t3.microに変更
    Key=InstanceType, Value=t3.micro

## EventBridge
  * 例）毎週木曜日0時に処理
  cron(0 15 ? * WED *)

## Lambda

```python:lambda_handler Python3.9
import boto3
import json
import pprint

def lambda_handler(event, context):
    cnt = 0
    log_msg = []
    task_tag = 'Schedule'

    client = boto3.client('ec2')
    reservations = client.describe_instances(
        Filters=[{
            'Name': f'tag:{task_tag}',
            'Values': ['1']
        }]
    )

    for reservation in reservations['Reservations']:
        for instance in reservation['Instances']:
            cnt = cnt + 1
            new_instance_type = ''
            inst_id = instance['InstanceId']
            instance_type = instance['InstanceType']
            state_name = instance['State']['Name']

            for tag in instance['Tags']:
                if tag['Key'] == 'InstanceType':
                    new_instance_type = tag['Value']
                    break

            log_msg.append(f"{inst_id}, {state_name}, {instance_type}, {new_instance_type}")

            if state_name == 'running':
                response = client.stop_instances(InstanceIds=[inst_id])
                log_msg.extend(response)
                
                #停止まで待機
                waiter = client.get_waiter('instance_stopped')
                waiter.wait(InstanceIds=[inst_id])

            #インスタンスタイプ変更があると処理
            if new_instance_type and new_instance_type != instance_type:
                response = client.modify_instance_attribute(InstanceId=inst_id, Attribute='instanceType', Value=new_instance_type)

            #重複処理防止のため、処理完了とのタグ値更新
            response_tag = client.delete_tags(
                Resources=[inst_id],
                Tags=[{'Key': task_tag, 'Value': '1'}],
            )
            response_tag = client.create_tags(
                Resources=[inst_id],
                Tags=[{'Key': task_tag, 'Value': '0'}],
            )
            log_msg.extend(response_tag)

            response = client.start_instances(InstanceIds=[inst_id])
            log_msg.extend(response)

    log_msg.append(f'instance count: {cnt}')
    pprint.pprint(log_msg)

    return {
        'statusCode': 200,
        'body': json.dumps('ok')
    }

```

# 参考
 * https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html
 * [boto3でEC2インスタンスサイズ変更（を自動化）](https://qiita.com/s-katsumata/items/e1c6c39d1da58a104401)
ksqlDBで顧客ロイヤリティプログラムを試してみた(その２)

### 概要
今回は[前回](https://qiita.com/Alex-hiro/items/ebf049d7905649ef2a79)の続きとして、マテリアライズドビューについてみていきたいと思います。

### マテリアライズドビューの説明
以下は前回作成したsales_totalというマテリアライズドビューです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128268/ff71a92a-6809-982b-82fa-42115535ff39.png)

これは顧客が費やした金額でグループ化する単純な例となっています。400ドル以上を費やす人はゴールドの顧客、300ドル以上はシルバー、200ドル以上はブロンズです。その他はまだどの報酬レベルにも達していません。 このクエリは、単純な「ユーザーごとの合計」要約テーブルを作成し、ユーザーの合計を価格帯にグループ化し列を追加します。

### マテリアライズドビューのルックアップをしてみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128268/4f755bdb-2e93-e015-8935-3e2bbcbdd17e.png)
以下が上記クエリに対する結果です。
ここでは、"kris"はまだREWARDを得るステージに達していないことが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128268/61e55f5f-179d-2114-12e3-f14c1c1ab1d5.png)

次に"kris"が犬を買ったというシナリオを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128268/3e64147e-fba3-31b8-d477-8e538e871919.png)
この時点で、もう一度先ほどのマテリアライズドビューを実行してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128268/79dd194c-f968-65e4-36f2-62be7fb32bf1.png)
以下がその結果です。この段階で"kris"はSILVERレベルのステージに達したことが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128268/c80e8c68-381f-9f6c-d14d-f2304f6527ee.png)

この例では、ユーザーが購入するたびにリアルタイムでユーザーのREWARDレベルが更新されるテーブルがありますので、そのデータをユーザーのアカウント設定ページにストリーミングしてアプリでREWARDレベルをリアルタイムで確認することができるようにするなどアイデア次第で比較的簡単に早くリアルタイム処理の機能を実装できるのではないかという感想をもちました。

今回も最後までお読み頂きましてありがとうございまいた。
密結合と疎結合について調べてみる

最近、資格の勉強をしていると「密結合」「疎結合」なる単語が良く出てくるので改めて調べてみる。

## 密結合と疎結合の概要
* ***密結合***
1. 他と結びつきが強く依存する構造
1. 独立性が弱い
1. プログラム、コンポーネント同士が***密接に結合していて分離すると動かない***状態

* ***疎結合***
1. 他と結びつきが弱い構造
2. 独立性が強い
2. ***プログラム、コンポーネント同士の結びつきが弱い***状態


↓の画像でそれぞれどういう状態なのか確認する
![feature07_img02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884542/9469e255-b9fd-644a-a7f1-f95a8a4fe6fa.jpeg)
参考：https://www.hitachi-solutions.co.jp/belinda/sp/special/feature07/

左側が密結合になっていて、右側が疎結合の状態になっている。
上記で示した概要に沿って確認してみる。


* 密結合
1. 他と結びつきが強く依存する構造
「販売」に着目して、真っすぐな線で繋がっているのは「購買」「管理会計」である。
繋がっているために「販売」を変更してしまうと、「購買」と「会計管理」にも影響を及ぼしてしまう。

2. 独立性が弱い
どの項目も他の項目と結びついているために独立性が弱くなっている。

3. プログラム、コンポーネント同士が密接に結合していて分離すると動かない状態
仮に「販売」の項目を「管理会計」から引き離すとすると、「管理会計」は「販売」と連携しているため、動かなくなる。
さらに、「管理会計」が動かなくなると、結びついている「生産」「購買」も動かなくなってしまう。

* 疎結合
1. 他と結びつきが弱い構造
どの要素も他の要素と結びついておらず、「仕分けHUBソリューション」だけに結びついている。
そのおかげで、一部のみ変更しても全体のテストはしなくても済む。

2. 独立性が強い
見ての通り、それぞれの要素が独立している。

3. プログラム、コンポーネント同士の結びつきが弱い状態
 見ての通り、それぞれの要素同士は結びついておらず、独立している。

## どちらにすべき？？
小規模なものや高速な処理が必要な場合は***密結合***
常にアップデートするものや自由度を高めたい場合は***疎結合***
（ただし、システム間の連携が難しく、コストが高くなることが多いそう）
Package.xml(マニフェスト)ファイルの書き方

コーディングを伴う開発の際に```/manifest/package.xml```の書き方を忘れがちのため備忘録として記載。
※VSCodeの機能を元に作成しています。
#サンプル
```package.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <!-- Apexクラス -->
    <types>
        <members>*</members>
        <name>ApexClass</name>
    </types>
    <!-- Visualforceコンポーネント -->
    <types>
        <members>*</members>
        <name>ApexComponent</name>
    </types>
    <!-- Visualforceページ -->
    <types>
        <members>*</members>
        <name>ApexPage</name>
    </types>
    <!-- Apexトリガー -->
    <types>
        <members>*</members>
        <name>ApexTrigger</name>
    </types>
    <!-- LWC(Lightning Web Component) -->
    <types>
        <members>*</members>
        <name>LightningComponentBundle</name>
    </types>
    <!-- 静的リソース -->
    <types>
        <members>*</members>
        <name>StaticResource</name>
    </types>
    <version>55.0</version>
</Package>
```
## その他マニュフェストファイルのサンプル
[公式](https://developer.salesforce.com/docs/atlas.ja-jp.api_meta.meta/api_meta/manifest_samples.htm)を参照
> - 標準オブジェクト
> - すべてのカスタムオブジェクト
> - 標準選択リスト項目
> - カスタム項目および標準項目
> - 標準オブジェクトのリストビュー
> - パッケージ
> - セキュリティ設定
> - 割り当てルール、自動レスポンスルール、エスカーレーションルール
> - 共有ルール
> - 管理コンポーネントへのアクセス

https://developer.salesforce.com/docs/atlas.ja-jp.api_meta.meta/api_meta/manifest_samples.htm
誰でも書き込み出来るよう 666 や 777 にしたいとかを chmod -R じゃなく、必要なパスに対してのみ行うやつ。

多分こんな感じでよさそう。

```bash
find dir ! -perm /o=w -exec chmod a+w {} +
find dir ! -perm /o=x -type d -exec chmod a+x {} +
```
Gentle intro: How is a 12-word mnemonic phrase created?

記録用なので英語のまま。
気が向いたら日本語にしようと思っていますが、たぶんしません。

Note: this post is rather specific to a 12*-word phrase.
Note: be aware that terminology in cryptography and BIP can be messy - so always ask questions.

1. Generate the entropy
    - An entropy, a Greek term not specific to cryptography, is simply a randomly generated number that is unlikely to be re-generated
    - Often 128-256 bits in length.
        Ex:`11011010010000101100101111001001110010000111111000010010100000001100001101001100101001011110011111001000010001010110000101111111`
2. First conversion using BIP0039
    - W/o going into detail on what a BIP39 is, there exists a [pre-determined BIP39 wordlist](https://github.com/bitcoin/bips/blob/master/bip-0039/english.txt) consisting of 2048 words. Each word is represented by the number in which the words are alphabetically ordered starting with 1..2048 ("abandon".."zoo")
    - In binary, a set of 11 bits represent any number between 0 and 2047 (in relative terms, think array index)
        2 ^ 11 = 2048
       
    
    
    - Therefore, 128 / 11 = 11R7, and 11 words can be derived from the wordlist.
3. Checksum for the 12th word
    - As an extension of the remainder 7, we see that it only needs 4 more bits to  complete the typical 12 word phrase that a mnemonic is often recognized as. These last 4 bits are what is referred to as the checksum. (3 bits for a 256 bit entropy)
    - The entropy, as a parameter of type binary, is handed to a hash function such as SHA-256, which converts it into a hexadecimal (a sequence of characters consisting of 0-9 and A-F) 
    Ex:`ced25fa131e86640ffc9517b590f84877e40ad20f7f1ae88707ec79945d0d454` 
        Each character in the hexadecimal can be represented as a binary of length 4 (i.e. 0000-1111 because 2 ^ 4 = 16 and len([0..9]) + len([A..F]) = 16)
    - The first character of the hexadecimal, after being converted back to a binary, is then added to the entropy and its remainder of 7 bits to complete the 12th word in the mnemonic phrase
        - There seem to be several ways to construct the 4 bits, but the important thing to know for now is that the hexadecimal, which is essentially the SHA-256 version of an entropy, is always used to generate the checksum

Also good to look up: `brain wallet`
【Swift】Alamofireでasync/awaitを使う

# はじめに
「alamofire async」で検索すると`withCheckedThrowingContinuation`を使ってasyncを使用している記事が多く出てきますが、実は標準でasync/awaitを使えるみたいです。
今回はそのやり方を紹介できたらと思います。

# やりかた
### String
```swift
let response = await AF.request(url, method: .get, headers: headers).serializingString().response
switch response.result {
case .success(let data):
    print(type(of: data)) // String
case .failure(let error):
    print(type(of: error)) // AFError
}
```

### Data
```swift
let response = await AF.request(url, method: .get, headers: headers).serializingData().response
switch response.result {
case .success(let data):
    print(type(of: data)) // Data
case .failure(let error):
    print(type(of: error)) // AFError
}
```

### Decodable
```swift
let response = await AF.request(url, method: .get, headers: headers).serializingDecodable(StatusesShow.self).response
switch response.result {
case .success(let data):
    print(type(of: data)) // StatusesShow
case .failure(let error):
    print(type(of: error)) // AFError
}
```

### カスタムレスポンス
カスタムレスポンスの作成方法は[こちら](https://qiita.com/SNQ-2001/items/4771cf3a91f6470bbc14)
```swift
let result = await AF.request(url, method: .get, headers: headers).serializingResponse(using: TwitterDecodableResponseSerializer<StatusesShow>()).value
switch result {
case .success(let data):
    print(type(of: data)) // StatusesShow
case .failure(let error):
    print(type(of: error)) // TwitterError
}
```

# おわり
日本語の記事が1つも見つからなかったので意外と知られてないかも？？

https://github.com/Alamofire/Alamofire/releases/tag/5.5.0
Box for Salesforceのアカウント設定

どこから設定するんだろうと探してみました。あっこれだろう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/b64fc09b-8513-f333-58e0-0984b1debed2.png)

しかし、言語設定が出てこないなぁ。

もう一度プロファイルを見てみると、また同じような設定がある。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/af35833d-2eec-3409-f7f4-40e2829c080d.png)

やっと言語設定が出てきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/7ca2075b-b25e-9f4f-4dc4-3bc671ec4f90.png)