OmniAICreator/Qiita-1.07M huggingface dataset:
【Android】Imageをブラー加工する方法【Jetpack Compose】

# はじめに

Imageをブラー加工したい場合ってあるよね。
xmlだと結構面倒で、Glide使ってる場合なんかは[wasabeefさん作のGlide Transformation](https://github.com/wasabeef/glide-transformations)を入れるとさっと実装できたりする。

僕が担当させてもらっているプロジェクトでは着々とJetpack Compose導入の準備をしていて、その過程でブラー加工をしなきゃいけない箇所があった。
xmlでやった時困った記憶があったのでかなりびびっていたのだけど、Composeではとってもシンプルかつ簡単に実装できたので紹介させて欲しい。

## Modifier.blurを使う場合

そもそも、ComposeにはModifierでブラー加工のAPIが用意されていて、これを使えば一発で実装できる。

■こんな感じ

```kotlin
Image(
    painter = painterResource(id = R.drawable.droid),
    contentDescription = null,
    modifier = Modifier
        .blur(16.dp)
        .wrapContentSize()
        .padding(horizontal = 16.dp)
)
```

ただ、これってそもそも現時点(2021/11/15)ではbetaだし、Android12向けに作られてるからsdkのバージョンを31まで引き上げなきゃいけない。
今みたいな導入時期では、僕みたいに**「sdkのバージョンはあげたくないけどブラーは実装したい」**っていうワガママさん結構いるんじゃないかと思う。

## Coilを使う場合

そんな時にはこれね。
xmlでGlide使ってたときは読み込みの時にブラーをかけてたな、ってのを思い出して、もしかしたらComposeのCoilにもあるんじゃないかと探してみた。
[あった](https://coil-kt.github.io/coil/api/coil-base/coil.transform/-blur-transformation/)。

使い方は超簡単で、rememberImagePainterのbuilderにTransformationを渡すだけ。

■こんな感じ

```kotlin
Image(
    painter = rememberImagePainter(
        data = "https://developer.android.com/images/brand/Android_Robot.png?hl=ja",
        builder = {
            transformations(
                BlurTransformation(
                    LocalContext.current,
                    16f
                )
            )
        }
    )
)
```

しかもこれすごいのが、ローカルの画像もブラー加工できちゃったりする。便利〜

■こんな感じ

```kotlin
Image(
    painter = rememberImagePainter(
        data = R.drawable.droid,
        builder = {
            transformations(
                BlurTransformation(
                    LocalContext.current,
                    16f
                )
            )
        }
    )
)
```

**Modifier.blurを使った場合とはぼかし具合が違う**ので、radiusの値をいじっていい感じに変えてあげようね。

# まとめ

- sdkのバージョンが31の人はModifier.blurを使えばブラー加工できるよ。
- 31未満の人はCoilのbuilderにTransformationを渡せば実装できるよ。

一応サンプル[ここ](https://github.com/KKusumi/BlurSample)に置いておくね。

Glide使ってる場合も似たような感じでできるんじゃないかしら。調べてないけど。
たしかComposeだとCoil推奨だった気がするから、特に理由なければCoil使った方が良さそうな気がするけどね。

おわり。
特定の条件でのみS3の画像URLでCORSエラーが発生する問題をなんとかする



##　要約
- S3に保存した画像URLに対してCloudFront経由でブラウザからアクセスする処理が2種類ある
  - 1つはHTMLのimgタグで呼び出す場合
  - もう1つはJavaScriptの`new Image()`などでImageElementを操作する場合
- S3とCloudFrontの両方で`Access-Control-Allow-Origin`Headerを正しく設定しているのにJavaScript上で操作する時にCORSエラーが発生したりしなかったりする現象が発生
- S3の画像URLを使用している場合、かつ、Chromeでブラウザのcacheが有効になっている場合、2度目のアクセス時に`Access-Control-Allow-Origin`Headerの付いていないキャッシュしたレスポンスをChromeが返すためCORSエラーが発生してしまう


## 問題が発生してたコード
- 次のように同じ画像URLに対してHTMLのimageタグで使用、かつJavaScript上でも同じ画像に対して処理を行おうとしていた

```html
<img src="https://hoge.cloudfront.net/fuga.jpeg">
```

```javascript
const image = document.createElement('img');
image.src = "https://hoge.cloudfront.net/fuga.jpeg"
```

しかし、JavaScript上のコードで次のようなCORSエラーが発生したりしなかったりする現象が発生した

> Access to image at 'https://hoge.cloudfront.net/fuga.jpeg' from origin 'https://hoge.cloudfront.net' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.


## S3やCloudFrontの設定の問題？
- 調べていたところ、S3やCloudFrontで`Access-Control-Allow-Origin`Headerが設定されていない場合のケースが出てきたのですが、既に設定済みだった
  - そもそもHTML上では問題なく使えているので、JavaScript上でだけ発生する理由が説明できない・・・
- ちなみに未設定の場合は次のように設定できる
  - https://qiita.com/b_a_a_d_o/items/2fa94f5e929b396a24ad
- `document.getElementById()`でHTMLの画像タグを取得してJavaScript上で使うようにしたら発生頻度は下がったようだったが、それでも人によっては発生したり発生し続けていて原因が突き止めずにいた

## そしてようやく原因を突き止める
- 後日調べ直してみて次の記事を発見
- **Chrome S3 Cloudfront: No 'Access-Control-Allow-Origin' header on initial XHR request**
  - https://serverfault.com/questions/856904/chrome-s3-cloudfront-no-access-control-allow-origin-header-on-initial-xhr-req
- S3の画像URLを使用している場合、かつ、Chromeでブラウザのcacheが有効になっている場合、2度目のアクセス時に`Access-Control-Allow-Origin`Headerの付いていないキャッシュしたレスポンスをChromeが返すためCORSエラーが発生してしまう模様
  - ChromeのDeveloper ToolでNetworkの`Disabled cache`がONの場合は発生しなかった
- crbugのissueはこれ？
  - https://bugs.chromium.org/p/chromium/issues/detail?id=741958

## 解決策という名の応急処理
- ブラウザ側の挙動の問題なので対応するのがなかなか難しい・・・
- 上記の記事ではAWS LambdaでHeaderを変更する関数を間に挟むようにして対処していたようだが、そのためだけのLamdaを用意するのは手間がかかるので別の方法を検討
- HTMLとJavaScriptで使用する画像URLが同じだとキャッシュされてしまうので、URLの末尾にランダムなクエリパラメーターを追加して使用すれば毎回別のURLになりキャッシュを利用されないのではと考えた
- 今回の場合はバックエンドサーバーからS3の署名付きURLを発行して使用しており、そこにオリジナルのクエリパラメーターを追加すると400エラーになってしまった
- S3の署名付きURLにはExire（有効期限）パラメーターがついており、1秒ごとに更新されるので、HTMLで使用される画像URLとは別にJavaScript上で使用する画像URLを1秒ずらして取得するようにして対応した
- 他に良い対応方法があれば教えてください :pray:
Outlookのメールをアーカイブするために、テキストファイルで保存したい


#メールファイルを「アーカイブ」したい
Gsuiteの利用もかなり浸透していますが、Microsoftのエコシステムを利用していてOutlookメールを外部とのコミュニケーションツールとして利用している会社も多いと思います。

そういった場合に相手とのやり取りとのエビデンスとしてメール内容をローカルにバックアップしたい需要はたまにあるのですが、Outlook画面からメールをデスクトップにドラッグするとOutlookアイテム（msgファイル）となってしまい、メタ情報を含んだままデータをアーカイブすることになります。
このままでは人に引き継ぐときや渡すときにメタ情報を含むためセキュリティ的な観点や、ファイルの扱いやすさからもちょっと気持ち悪いです。そこでmsgファイルをテキストファイルに変換するスクリプトを作成しました。

#コード
下のコードをメモ帳かなにかテキストエディタに貼り付けて「.vbs」で保存してください。

```vb:msg2txt.vbs
Dim fileTemp, txtMail, fileCurrent, objOutlook, msgTmp, fileTxt,msgRe,petternRe

Set txtMail = CreateObject("Scripting.FileSystemObject")
Set fileCurrent = txtMail.GetFolder(".")
Set objOutlook = CreateObject("Outlook.Application")

For Each  fileTemp In fileCurrent.Files
If LCase(txtMail.GetExtensionName(fileTemp.Name)) = "msg" Then
Set msgTmp = objOutlook.CreateItemFromTemplate(fileCurrent & "\" & fileTemp.Name)

'Outlook書式付きの改行削除
set petternRe = createObject("VBScript.RegExp")
petternRe.Global= True
petternRe.pattern = "\s" & vbcrlf 
msgRe = petternRe.Replace( msgTmp.body, "" )

Set fileTxt = txtMail.OpenTextFile(fileCurrent & "\" & txtMail.GetBaseName(fileTemp.Name) & ".txt", 2, True, -1)
fileTxt.WriteLine("送信者》 " & msgTmp.SenderName)
fileTxt.WriteLine("受信者》 " & msgTmp.To)
fileTxt.WriteLine("CC》 " & msgTmp.CC)
fileTxt.WriteLine("BCC》 " & msgTmp.Bcc)
fileTxt.WriteLine("件名》 " & msgTmp.Subject)
fileTxt.WriteLine("本文》 " &msgRe)
fileTxt.Close
Set fileTxt = Nothing
Set msgTmp = Nothing
End If
Next
Set petternRe = Nothing
Set fileTxt = Nothing
Set msgTmp = Nothing
MsgBox("書き出しました。")
```

#使い方
後はこのスクリプトファイルと、変換したいOutlookのメッセージファイルを同じフォルダに保存して、スクリプトファイルをダブルクリックしてください。同一ディレクトリにテキストファイルが生成されます。

良いメールライフを。
iOSで「拡大表示」の設定を行うとUIScreen.main.boundsのサイズが変わる

## TL;DR

- 「拡大表示」設定を行うと論理的な解像度( `UIScreen.main.bounds` )が一段階小さくなる
    - iPhone 8は320x568になる
- 「拡大表示」設定になっていても `UIScreen.nativeBounds.width / UIScreen.main.scale` で拡大表示ではないときの解像度と同じ画面幅を取得できる

| Device | bounds.width | nativeBounds.width | scale | nativeScale |
|:-:|:-:|:-:|:-:|:-:|
| 8 | 375 | 750 | 2 | 2 |
| 8(拡大) | 320 | 750 | 2 | 2.34375 |
| 13 Pro | 390 | 1170 | 3 | 3 |
| 13 Pro(拡大) | 320 | 1170 | 3 | 3.65625 |
| 13 Pro Max | 428 | 1284 | 3 | 3 |
| 13 Pro Max(拡大) | 375 | 1170 | 3 | 3.424 |

## 「拡大表示」とは

iPhoneの `設定-画面表示と明るさ-拡大表示-表示-設定` から変更できるもの。

画面の表示内容が大きくなったように見える。

https://support.apple.com/ja-jp/guide/iphone/iphd6804774e/ios

![screenshot.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594488/49436082-e299-1165-f0ff-74813ad3baa3.png)

この設定を行うと論理的な解像度が一段階小さくなり、引き伸ばされて表示されるようになっている。

プログラム的には `UIScreen.main.bounds` 等の数値が小さくなっている。

例えばiPhone 8は375x667だが、「拡大表示」にすると320x568とiPhone SE(1st)と同じになる。

## 元々の解像度がほしいときは

`nativeBounds` と `scale` を用いる。

```
let originalWidth = UIScreen.nativeBounds.width / UIScreen.main.scale
let originalHeight = UIScreen.nativeBounds.height / UIScreen.main.scale
```

### nativeBounds

ディスプレイの物理的解像度。iPhoneはHiDPIなので論理的解像度の倍の数値になっている
(iPhone 8なら750x667)

また画面が回転していても `width` と `height` が入れ替わらない。

https://developer.apple.com/documentation/uikit/uiscreen/1617810-nativebounds

### scale

デフォルトの論理的解像度に対する物理的解像度の比。
(iPhone 8なら2)

`scale` は「拡大表示」設定を行っていても変化しないため、「現在の論理的解像度に対する物理的解像度の比」を取得したい場合は `nativeScale` を用いる。

https://developer.apple.com/documentation/uikit/uiscreen/1617836-scale

| Device | bounds.width | nativeBounds.width | scale | nativeScale |
|:-:|:-:|:-:|:-:|:-:|
| 8 | 375 | 750 | 2 | 2 |
| 8(拡大) | 320 | 750 | 2 | 2.34375 |
| 13 Pro | 390 | 1170 | 3 | 3 |
| 13 Pro(拡大) | 320 | 1170 | 3 | 3.65625 |
| 13 Pro Max | 428 | 1284 | 3 | 3 |
| 13 Pro Max(拡大) | 375 | 1170 | 3 | 3.424 |
WSL - かんたんインストール方法

# WSL（Windows Subsystem For Linux）とは？
Windows上でLinux環境（UbuntuなどのLinux OS）を使用できるアプリケーション。
Windows上でLinux OSを構築し、その中でLinuxのシェル（Bash）、Linux実行ファイル・Linuxコマンドを扱えるようになる。

# 用途
* Mac（Linuxの派生OS）の経験があり、同じようなターミナル環境(bash, 最近はデフォルトでzsh)で作業したい。
* Linuxを触ってみたい。
* WindowsでBash, zshを使いたい。
* プログラミング・webサイト制作・Webアプリの開発がしたい。

# Step 1 - WSLのセットアップ
1. 管理者でPowerShellを開きます。（タスクバー左端Windowsアイコンを右クリック→「Windows PowerShell (Admin)」）
1. 下記を入力してエンターし、質問が出るのでYを入力すると、WindowsにてWSLが有効化されます。PCを再起動して下さい。

```
C:\Users\myname> Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
```

3. [WSL - Ubuntuをインストールする（Microsoft Store）](https://www.microsoft.com/store/productId/9NBLGGH4MSV6)
4. Ubuntuの初回起動時、Ubuntu用のユーザIDとパスワードを設定し、インストール完了です。

# Step 2 - Windows Terminalのセットアップ
Windowsのターミナルアプリは、標準のコマンドプロンプトがあるが、
「Windows Terminal」アプリはシェルの切替・色のカスタマイズ・タブの切替など利便性が高いです。
コマンドプロンプトだと起動時のシェルはWindowsのシェルですが、Windows Terminalは起動時のシェルを指定できます。
ターミナルでUbuntu環境（Bashというシェル）に入るためにも、Windows Terminalを使います。

* [Windows Terminalをインストールする（Microsoft Store）](https://www.microsoft.com/store/productId/9N0DX20HK701)

1. Windows Terminalを起動して、**Ctrl + ,** で設定を開きます。
1. 左側メニューバーの「スタートアップ」→「既定のプロファイル」でドロップダウンリストから「Ubuntu」をセットします。
1. 左側メニューバーを下にスクロールしてペンギンアイコンの「Ubuntu」を選択→「開始ディレクトリ」を **//wsl$/Ubuntu/home/ユーザー名/** に変更します。
1. 再起動してBashの起動を確認。

※各プロファイルでは、「全般」「外観」「詳細設定」タブがあり、
　そこで起動時のディレクトリ、フォントの色やサイズ変更、Windowの透明化などカスタマイズができます。

※開始ディレクトリが存在しない場合は手動で作成してください。
　（エクスプローラーの検索窓にC:\homeと打ち、そこに右クリックから新規ディレクトリを作成）

# セットアップ完了後
ターミナルでBashが開けたら、今後ローカルに様々なパッケージを導入するためにも、パッケージマネージャーをアップデートしておきます。
下記コマンドを実行。

```
$ sudo apt update
$ sudo apt upgrade
```
# WSLとWindows間でファイルへアクセスするには？
WSLからWindows　→　/mnt/cがWindowsのCドライブ。
WindowsからWSL　→　C:\wsl$\Ubuntu\　でアクセス可。「Ubuntu」部分は各ディストリビューション名によって変わる。

# 補足
* [WSLでDockerをはじめる方法](https://qiita.com/AppJapan/items/f379773ca6b89dd0ecb5)
flask_httpauthのDigest認証がうまくいかない

# WebAPIのテストサーバとしてFlaskをたてた
たてた。
ついでにDigest認証の機能も付けてみた

# うまくいかない
作られているハッシュ値はあっているはずなのに401で返ってくる

# クライアント側で接続を切る実装になっていた
通常（？）は

1. 初回の問い合わせ
1. 401で返ってくるのでその応答を使ってハッシュ値を作る
1. 再問合せ

だが、初回の問い合わせと再問合せの間に接続がきられていた。

flask_httpauthはnonceとopaque値をセッション基準で保存していて
再問合せがあった場合に、初回問い合わせと一致しているかどうか
確認しているようだ。

一方で、この確認そのものや、nonce、opaque値の生成は外部からコントロールできる。

# 追加コード

下記コードを追加した。
この例ではnonce値は固定の値を返すようにした。
nonceとopaqueの比較は常にOKが返るようにしている。
ハッシュ値の計算と比較は通常通り実行されるので、一応これでも問題ない。とおもう

``` python

tmp_nonce = ""
@auth.generate_nonce
def gen_nonce():
	tmp_nonce = "aaaaaaaaaaaa5004497ae5a9600b4b53"
	return tmp_nonce

@auth.verify_nonce
def ver_nonce(nonce):
	return True

@auth.verify_opaque
def ver_opaque(opaque):
	return True

```

# 後
https://flask-httpauth.readthedocs.io/en/latest/

自分で理解してからだとよくわかるんだけど、しっかりドキュメントに書いてあるね。
無効化ではなく、各々のサーバに適した管理をしてくれ・・・と書いてある
【Swift】平方根・累乗根を求める方法

Swiftで平方根・累乗根を求める方法。

## 平方根

```swift
let num = 100
//sqrtを使う方法
sqrt(Double(num))
//powを使う方法
pow(Double(num), 1/2)
```
sqrtは平方根の計算ができる関数。

## 累乗根

```swift
let num = 100
//powを使う方法(3乗根)
pow(Double(num), 1/3)
//powを使う方法(5乗根)
pow(Double(num), 1/5)
//powを使う方法(10乗根)
pow(Double(num), 1/10)
```
## Swiftのお役立ち情報

https://wagtechblog.com/programing/swift-iphone-application-school

https://wagtechblog.com/programing/swift-textbook.html
Couchbase Lite機能解説：ピアツーピア同期〜プログラミング構成と設定項目

## ピアツーピア同期プログラミング構成

Couchbase Liteのピアツーピア同期機能を利用するためには、`URLEndpointListener`クラスを利用します。

`URLEndpointListener`を初期化する際に、`URLEndpointListenerConfiguration`を使用して構成を実行します。

ここでは、Couchbase Liteのピアツーピア同期で行えることの理解を助けるため、`URLEndpointListenerConfiguration`で設定できる項目を紹介します。

## ピアツーピア同期設定項目

`URLEndpointListenerConfiguration`を使用して、リスナーを初期化するために使用できる構成オブジェクトを作成します。

#### `port`
リスナーがリッスンするポート。

ポートがnullまたはゼロの場合、リスナーは使用可能なポートを自動割り当てします。

#### `networkInterface`
IPアドレスまたはネットワークインターフェイス名の形式で指定する、リスナーが利用する使用するネットワークインターフェイス。

- ネットワークインターフェイスが指定されている場合、そのインターフェイスのみが使用されます。

- ネットワークインターフェイスが指定されていない場合、使用可能なすべてのネットワークインターフェイスが使用されます。


#### `disableTLS`
必要に応じて、`URLEndpointListenerConfiguration`の`setDisableTLS`メソッドを使用してTLS通信を無効にすることができます

`disableTLS`設定が「false」でない場合、クライアント証明書の認証が必要です。基本認証は、TLSの有無にかかわらず使用できます。


- `disableTLS`がtrueである場合： TLS通信が無効になっているとTLSのアイデンティティは無視されます。リスナーへの接続の際のURLスキームでは`ws://`を使用します。

- `disableTLS`がfalseまたは指定されていない場合: TLS通信が有効になります。。リスナーへの接続の際のURLスキームでは`wss://`を使用します。

アクティブなピアは、wss://URLスキームを使用してリスナーに接続します。


#### `tlsIdentity`
TLS通信に使用されるTLSアイデンティティ。

`disableTLS`がtrueで、`tLSIdentity`が設定されていない場合、自動生成された匿名の自己署名IDが使用されます。通信が暗号化されるため、非TLS通信よりも安全なオプションとして利用可能です。

自動生成された匿名の自己署名IDは、将来使用するために安全なストレージに保存されます。


#### `authenticator`
リスナーがクライアントの接続要求を認証するために使用するオーセンティケーター。認証を行う場合、次のいずれかに設定します。

- `ListenerPasswordAuthenticator`
- `ListenerCertificateAuthenticator`


#### `readOnly`
trueの時、プルレプリケーションのみを許可します。デフォルト値はfalseです。

#### `enableDeltaSync`
デルタ同期を有効化するフラグ（ただし、ピアツーピア同期のデルタ同期は、Sync Gatewayとのデータベースレベルのデルタ同期設定にも依存します）。デフォルト値はfalseです。



# 関連情報

https://docs.couchbase.com/couchbase-lite/3.0/android/p2psync-websocket.html#api-highlights

https://docs.couchbase.com/mobile/3.0.0-beta02/couchbase-lite-android/com/couchbase/lite/URLEndpointListener.html


https://docs.couchbase.com/mobile/3.0.0-beta02/couchbase-lite-android/com/couchbase/lite/URLEndpointListenerConfiguration.html
XCTestで許容精度付きで浮動小数点数の配列の比較を行う

## TL;DR
```CustomAssertion.swift
import XCTest

/// 浮動小数点数の配列同士を許容精度付きで比較する
func assertEqual<T: FloatingPoint>(_ lhs: [T], _ rhs: [T], accuracy: T, file: StaticString = #filePath, line: UInt = #line) {
    guard lhs.count == rhs.count else {
        XCTFail("\(lhs) is not equal to \(rhs)", file: file, line: line)
        return
    }
    for index in lhs.indices {
        XCTAssertEqual(lhs[index], rhs[index], accuracy: accuracy, "index: \(index)", file: file, line: line)
    }
}
```

## 背景
[XCTest](https://developer.apple.com/documentation/xctest)には様々なアサーションが用意されている。

そのうちの一つに[XCTAssertEqual(_:_:accuracy:_:file:line:)](https://developer.apple.com/documentation/xctest/2919914-xctassertequal)がある。
これは、二つの浮動小数点数の差が誤差(accuracy)に納まるか？をチェックするアサートである。

浮動小数点数の演算には誤差がつきものであり計算順序が異なる場合に厳密には一致しなくなるが、その誤差でテストが落ちてしまうことは煩わしいため用意されているアサートである。

しかし、このアサートは二つの浮動小数点数の比較のみ行えるアサートであるため、浮動小数点数の配列同士を比較に使用することは出来ない。

誤差を含む浮動小数点数の配列同士を比較する必要があったため今回カスタムアサーションを作成した。

## 方針
以下の条件を満たしたアサーションを作る

- 指定した誤差以内であれば許容する
- XCTestのアサーションのようにテストに失敗した行にエラーが表示される
- 一致しない要素がどれかわかりやすくする

### 指定した誤差以内であれば許容する
基本的には要素一つ一つを`XCTAssertEqual(_:_:accuracy:_:file:line:)`にかけていけば問題ない。
よって二つの配列の要素数が一致した場合に比較を行うようにする。

```impl1.swift
func assertEqual<T: FloatingPoint>(_ lhs: [T], _ rhs: [T], accuracy: T) {
    guard lhs.count == rhs.count else {
        XCTFail("\(lhs) is not equal to \(rhs)")
        return
    }
    for index in 0..<lhs.count {
        XCTAssertEqual(lhs[index], rhs[index], accuracy: accuracy)
    }
}
```

### XCTestのアサーションのようにテストに失敗した行にエラーが表示される
XCTestのアサーションが失敗したとき、コンパイルエラーのように失敗した行の右側にエラーが表示される。

カスタムアサーションでも表示されるようにする。
表示するためには`XCTFail()`と`XCTAssertEqual(_:_:accuracy:_:file:line:)`に`#filePath`と`#line`を渡してやればOK。

```impl2.swift
func assertEqual<T: FloatingPoint>(_ lhs: [T], _ rhs: [T], accuracy: T, file: StaticString = #filePath, line: UInt = #line) {
    guard lhs.count == rhs.count else {
        XCTFail("\(lhs) is not equal to \(rhs)", file: file, line: line)
        return
    }
    for index in lhs.indices {
        XCTAssertEqual(lhs[index], rhs[index], accuracy: accuracy, file: file, line: line)
    }
}
```
これで失敗したとき失敗した行にエラーが表示されるようになる

### 一致しない要素がどれかわかりやすくする
前記二つで要素が一致しなかった場合エラーが表示されるようになった。
しかし現状だとどの要素が一致していないのかが分かりづらい。そのためmessageにどのインデックスだったかを記録する

```impl3.swift
func assertEqual<T: FloatingPoint>(_ lhs: [T], _ rhs: [T], accuracy: T, file: StaticString = #filePath, line: UInt = #line) {
    guard lhs.count == rhs.count else {
        XCTFail("\(lhs) is not equal to \(rhs)", file: file, line: line)
        return
    }
    for index in lhs.indices {
        XCTAssertEqual(lhs[index], rhs[index], accuracy: accuracy, "index: \(index)", file: file, line: line)
    }
}
```

![screenshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594488/362064da-3b0b-edaa-0486-b455c52eda14.png)


これでどの要素が一致しないか？がわかるようになった。
タスクバーのクロームのアイコンにアカウントのアイコンが付随する件について

https://support.google.com/chrome/thread/4726878/%E3%82%BF%E3%82%B9%E3%82%AF%E3%83%90%E3%83%BC%E3%81%AE%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%A0%E3%81%AE%E3%82%A2%E3%82%A4%E3%82%B3%E3%83%B3%E3%81%AB%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%81%AE%E3%82%A2%E3%82%A4%E3%82%B3%E3%83%B3%E3%81%8C%E4%BB%98%E9%9A%8F%E3%81%99%E3%82%8B%E4%BB%B6%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6?hl=ja

結構調べる事が多いので解決策を表記する。

と思ったけど削除したら出てこなくなった気がするのでとりあえずメモ失礼いたします。
git push 反映されない 空コミット

# git push が反映されないないときの対処法1
- 空コミットをローカルレポジトリで積み上げて、pushすることで、解決する場合がある。
- コマンドライン

```
git commit --allow-empty
# コミットメッセージの入力
# 後ほど、このコミットは削除するため、適当に入力
git push
# pushが反映されたことを確認
git reset --hard HEAD~
git push --force
```
# 参考
- [git pushでリモートに反映されない時の対処方法](https://nyakanishi.work/what_to_do_when_git_push_doesnt_work_on_the_remote/)
[WIP] パッケージ管理システム一覧

# パッケージ管理システム一覧
- Unix
    - Redhat系
        - CentOS >>> rpm, yum
    - Debian系
        - Ubuntu >>> apt-get
    - BSD系
        - Debian
            - macOS >>> homebrew
- Java
    - Maven
- node.js
    - npm
- Python
    - pip
- Ruby
    - RubyGems
- Go
    - go get
- Javascript, HTML, CSS
    - bower
- .NET Framework
    - Nuget

# 参考
- [パッケージ管理システム(パッケージマネージャー)の種類(Windows, Linux, Mac)](https://urashita.com/archives/7781)
RLoginでU-bootのオペレーション

U-bootの処理は個別の設定を忘れたり、間違ったアドレスに書いて、bootをつぶしてしまわないように、処理をsetenv,saveenvで保存しておいて、runするようにしています。

ところがOnion OmegaなどU-bootにsaveenvがない環境があります。

また初期のU-bootにはrunコマンドがありませんでした。

このようなターゲットでは毎回コピペして処理していたのですが、RLoginのスクリプトを使う方法を思いつきました。

```
sputs("setenv ipaddr 192.168.0.100;setenv serverip 192.168.0.50;tftpboot 0x80020000 Onion_Omega.bin\r");
swait(30, "Omega>");
sputs("erase 0x9f020000 0x9f7fffff;cp.b 0x80020000 0x9f020000 $filesize;reset\r");
```

便利です。

メニューに登録したりショートカットにする方法はこちらを参考にしました。

https://qiita.com/mitazet/items/bd4d46e19a142bf09094

Linuxがすぐに起動してしまい、止めるタイミングが難しい場合には以下のスクリプトが有効です。

```
function uboot() {

// u-boot boot command select script

  dlg = dialog("Please choose the operation:", [ 0,0,360,180 ],
   [
    [ "radiotop", [ 30,10,300,20 ], "1: Load system code to SDRAM via TFTP." ],
    [ "radio", [ 30,30,300,20 ], "2: Load system code then write to Flash via TFT." ],
    [ "radio", [ 30,50,300,20 ], "3: Boot system code via Flash (default)." ],
    [ "radio", [ 30,70,300,20 ], "4: Entr boot command line interface." ],
    [ "button", [ 130,120,100,20 ], "OK", 0, "OnClickOk" ],
   ]
  );

// get id by add because of id use after

  chkid = dlg.add("check", [ 150,95,300,20 ], "reboot");
  dlg.open();
  dlg.center();
  dlg.show(1);
  dlg.wait();

}

function OnClickOk ( id ) {
  if ( (n = dlg.getradio(0)) >= 0 ) {
    if (dlg.getcheck(chkid) == 1) {
      sputs("reboot\r");
    }
    swait(600, "Please choose the operation:");
    sputs(substr(dlg.gettext(n), 0 , 1));
  }
  dlg.close();
}

menu(0, "uboot", "uboot");
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/ffcd3665-a72c-34b1-65cd-cad2b06c1c32.png)
情報処理技術者試験のデータベーススペシャリスト試験をただの資格勉強に終わらせずに「しっかり」と勉強する方法

この投稿は「[IT資格取得をテーマに学びをシェアしよう！【PR】Udemy](https://qiita.com/advent-calendar/2021/udemy)」のカレンダー2の15日目のポストです！今年もいくつかIT資格取得にトライしました。そのうちの一つの**情報処理技術者試験 データベーススペシャリスト試験** を「しっかり」と勉強する方法をご紹介します。データベーススペシャリスト試験のようなやや難易度が高い試験に対しては、ただ単に時間をかけて「資格試験用の勉強」をするのは勿体ないと思います。この機会（モチベーション）を利用して、普段お仕事でも経験できていないようなことを幅広く学ぶ活動にしてもらえたらなーと思いまして、自分がやったことをまとめます。（合格発表は12月17日ですね！）

## 情報処理技術者試験 データベーススペシャリスト試験
本試験は秋期の情報処理技術者試験として開催されています。高度区分に位置されていて、合格率も10%未満と、そこそこの難易度が高い試験です。試験名称通り、データ基盤を扱うデベロッパーを対象とした試験です。IPAのサイトから引用すると、こんなメッセージ。

> 企業活動を支える膨大なデータ群を管理し、パフォーマンスの高いデータベースシステムを構築して、顧客のビジネスに活用できるデータ分析基盤を提供するデータベース管理者やインフラ系エンジニアを目指す方に最適です。

https://www.jitec.ipa.go.jp/1_11seido/db.html

## 「しっかり」と勉強するとは？
合格を目指して勉強を進めますが、過去問や対策専門の教科書といったいわゆる「試験対策」だけではなく、この機会に今後も役立つ知識を身に付けるために周辺領域を学習していくことをおすすめします。ですので、4-5カ月かけてじっくり取り組み、データベーススペシャリストとして確固たる基礎を築くことをゴールとしています。資格試験対策本だけだと面白くないですからね、この機会に仕事では触れないちょっとニッチなことや、データベース界隈にある文化や、考え方などに触れてみるのが面白いところなのです。

## で、どんなルートがお勧め？
書籍やUdemyなどを利用しながら勉強していきます。普段自分が利用しないRDBを使いながら動かしながら学んでいきます。私が行った学習はこんな感じでした。

### その1. DB設計の基礎を改めて作る
データベース設計に関する全体像、物理設計、論理設計、少し特殊な設計（ツリー型のデータ構造）、パフォーマンスチューニングなどを学ぶことができます。

https://www.amazon.co.jp/dp/B00EE1XPAI

### その2. SQLの基礎を改めて作る
基礎と書いていますが、CRUDの書き方を学ぶわけではなく、ウインドウ関数やCASE文を使った中級のSQLの書き方を学びます。

https://www.amazon.co.jp/dp/B07GB4CNKP

2冊連続でミックさんの本を読むと、だいぶRDB脳がミックさんの考え方になじんできます。このあたりから、RDBやSQLってこんな深かったんだと脱線しそうになります。時間に余裕があれば、脱線しましょう。脱線こそが学びの面白いところです！番外編の「よりSQLを極める」の本を利用し、セルコー氏の考え方に触れていくのがお勧めの脱線先です。（ここで脱線してしっかりと試験勉強できなくても大丈夫です。翌年受験すればいいだけです。）

### その3. ERDの基礎を作る
ERDは書いて特訓するのが一番身に付きます。前述のミックさんの本にも書いていますが、ERDに関する設計を実務で積む機会っていうのはそれほどありません。本書（**楽々ERDレッスン (CodeZine BOOKS)** ）のようなレッスンをもとに学んでいくのが良いですね。ERDを書く練習にはdraw.ioなどのツールがおすすめです。（ちなみにサロゲートキーの考え方などは、前述の書と異なりますが、気にしない。）

https://www.amazon.co.jp/dp/4798110663

### 本筋. 試験対策
本筋の試験対策は、よくある参考書と過去問を中心に実施。（Amazonで検索するとたくさん出てきますので、省略します）

### 番外編. よりSQLを極める
さらにSQLについて詳しくなりたい場合は、ジョー・セルコー氏の書籍がお勧めです。ただ…このあたりの領域をはじめると沼にはまってしまいますので、データベーススペシャリスト試験の「周辺領域」としてはやりすぎなかなと思います。試験後にさらに自己研鑽を積むうえで手に取るのがよろしいかと思います。

https://www.amazon.co.jp/dp/B00SF6JN4U

https://www.amazon.co.jp/dp/4798114138

### 余談. Udemyのコンテンツは？
Udemyのおすすめコンテンツもお出ししたかったのですが、残念ながら無い様子。
今後情報処理技術者試験の高度に対応するコンテンツが出てくることに期待したいですね！
フォルダーのアクセス権

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめA～M](https://qiita.com/Keiji_otsubo/items/f3ddedee6793bf1576f8)


+ [レポート、ダッシュボードのフォルダーの権限](https://qiita.com/Keiji_otsubo/items/297ed802dbe4f88e017c)


# リード、 レポート公開フォルダー、パートナーユーザ
[公開レポートフォルダへのパートナーコミュニティユーザーアクセス](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000DfNNz)

リードの共有設定に関連している必要があります。Leadオブジェクトがパブリック読み取り/書き込みコミュニティの場合、セキュリティ上の理由から、ユーザーはレポートを実行できないという古い記事を読みました。これをプライベートに設定してから、パートナーコミュニティのユーザーロールまたはパブリックグループ用に特定の共有設定を作成することをお勧めします。 


# The sharing settings for this subfolder are derived from its root folder

+ [The sharing settings for this subfolder are derived from its root folder](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007AihNu)

:::note
According to Salesforce release notes (https://releasenotes.docs.salesforce.com/en-us/summer18/release-notes/rn_rd_folders_organize.htm):
 
You can only share the root folder. Subfolders inherit sharing properties from the root folder. To share folders with other users, you need Manage access.

Folder sharing is only at the root level. If you want to share a subfolder, you’ve gotta share its root folder. Everyone can see who has access to a subfolder, but if you want to change the sharing settings, you can do that at the root level. 

https://developer.salesforce.com/forums/?id=9062I000000QuyBQAS

共有できるのはルート フォルダーのみです。サブフォルダーは、ルート フォルダーから共有プロパティを継承します。他のユーザーとフォルダーを共有するには、「管理」アクセスが必要です。

フォルダー共有はルート レベルでのみ行われます。サブフォルダーを共有したい場合は、そのルート フォルダーを共有する必要があります。誰がサブフォルダーにアクセスできるかを誰でも確認できますが、共有設定を変更したい場合は、ルート レベルで変更できます。
:::
今までの振返り +α（算術計算，変数，リスト辞書 等）


# 今回の授業資料
<script async class="speakerdeck-embed" data-id="920a61eb1a9d41d0bacadeedb683db32" data-ratio="1.77777777777778" src="//speakerdeck.com/assets/embed.js"></script>

# 本日の内容
### 新しいpython3ファイルを作ろう．
エディタの新規作成はVS Codeにて，**Cmd/Control** を押しながら，**N**を押すと，作成できます．

### 上記で作ったファイルを「[本日の日付]_practice.py」という名前で「dalton_python」へ保存しましょう．
作成したファイルは，**Cmd/Control** を押しながら，**S**を押すと，作成できます．必ず拡張子.pyを忘れずに入れましょう．どんな種類のファイルかを明確にするためです．
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271604/08dd3e77-7118-7966-c84a-541e858b427b.png)

以下の練習問題からは，今保存したコメントアウトを活用しながら，書き進めていきましょう！

## 【練習1】 input()を用いた練習

```
input('お名前は？')
```
input()のみ（print()で表示の指示をしていない）ため，値を獲得する **処理** しか行っていない．

## 【練習2】 print()を用いた練習

「name」という変数を宣言し，print()で呼び出すと…


```
name = input('お名前は？')
print(name)
```
## 【練習3】 「[本日の日付]_practice.py」の実行
練習2のコードの内容で実行した結果…
![input_print.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271604/0904b168-0f07-2fff-32d0-36137b9c64dc.gif)

## 【練習】 コメントアウト
「**#**」を行頭につけると，その行のコードは実行されない．


|【windows】|Control + / |
|:-:|:--|
|**【Mac】**|**Command + /**|


#ディレクトリ構造
Desktopに「dalton_python」作ったのに，
・Desktopへ行けない
・「dalton_python」自体が見つからない
等の場合，山口をよんでください！

# これまでの演習

|演習番号|問題内容|
|:-:|:--|
|1|[計算してみよう(授業資料1 演習)](https://qiita.com/hakukikun/items/c6fa44ca0168894ecca1)|
|2|[複合代入演算子を用いた四則演算（授業資料3 演習）](https://qiita.com/hakukikun/items/9535d71e76a67d9844fd)|
|3|[python キャスト（授業資料3 演習）](https://qiita.com/hakukikun/items/592dd63ab74a863edee5)|
|4|[リストの要素同士の計算](https://qiita.com/hakukikun/items/44036f883ee19c681cf8)|
|5|[辞書型で自販機データを作ろう](https://qiita.com/hakukikun/items/8f8a1a58d0fe0ecab47a)|
Qiitaを始めた目的／経緯

# はじめての投稿

## 目的
Qiitaを始めた目的を明確にしたい。
- Qiitaって何[^whatsqiita]？
- 社内でトラブった際によくお世話になっているけど、
  これってタダで見れても良い情報なの[^q2]？と疑問が沸いた。のがきっかけ。

## モチベーション
- とっつきやすい技術情報を流通させて、少しでもIT技術者になるハードルを下げたい
- ITって難しそうだからという人でも、動作原理(のイメージ)を知って、ITやソフトで魔法のように何でも出来ると思う人→ソフトでもできないことを知ってほしい
- 雰囲気で設定できた→設定された内容がソースやコンフィグファイルを見て第3者に説明できるレベルの人を増やしたい など

## Qiitaのお勉強
###「HRT」を大切にしよう
>“あらゆる人間関係の衝突は、謙虚・尊敬・信頼の欠如によるものだ”
書籍『Team Geek――Googleのギークたちはいかにしてチームを作るのか』
書評<https://note.com/kawa1228/n/ne119f0eab17d>

### エンジニアにとって再利用性・汎用性の高い記事を書こう
>- エンジニアが興味を持つものではなく、エンジニアに有益な情報をもたらす記事を投稿
[Qiitaサポート>Qiita>ガイドライン](https://help.qiita.com/ja/articles/qiita-community-guideline)より引用
>- Qiitaへの要望や意見は[ご意見のリンク](https://qiita.com/feedback/new)か[サポート窓口](https://increments.zendesk.com/hc/ja/requests/new)まで

### 読み手にとって適切な表現を心がけよう
>不要な煽りは時に誤解や反発を招くことがあります。投稿前に間違いがないか、人を傷付けるような書き方をしていないかなど確認

→どうしても自分の意見への拘りが強いと、他の人がどう思うかまで気が回っていないことが多い。
自戒の念を込めて、投稿ボタンを押す前に落ち着いて見直そう

### みんなが読んでも理解できる記事を書こう
>Qiitaエンジニアにとって再利用性・汎用性の高い情報が集まる場をつくる事を目指しています。 そのためにも、一般的な名詞や用語、表現を用いて、自分以外の人が読んでも理解できる記事を書くことを心がけましょう

→第3者目線は大事。仕事に置いても、家庭においても、全ての人間関係に置いても。

(途中、時間切れ中断)





[^whatsqiita]:エンジニアに関する知識を記録・共有するためのサービス
2011年秋リリース当初は、"プログラマ向けのQ&Aサービス"
だったようだ。

[^q2]:はっきりとは言えない
Eclipse - インポートされたjavax.wsは見つかりません。を解決する

自分用メモ

#解決策
Tomcat10ではパッケージ名がjavax.wsからjakarta.wsに変更された。
import文を修正することでエラー解消できる

```java
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
```
web.xml でweb-app にエラーが表示される

自分用のメモ
Teratailの内容から引用

```
cvc-id.3: A field of identity constraint 'web-app-servlet-name-
 uniqueness' matched element 'web-app', but this element does 
 not have a simple type.
```
サンプルコードを参考にしながらWeb.xmlを記述した際、Eclipse上にて上のようなエラーが表示

#解決方法
###Eclipseの設定を変更
　[設定]＞[XML（Wild Web Development）]＞[検証及び解決]
　・[検証を使用可能にする]のチェックを外す
　・[検証を使用可能にする]をチェック、[スキーマ・ベースの検証を可能にする]を[なし]
Colabで始めるmmpose(2) [ボトムアップ型の手法で推論してみた編]

# 前の記事

こちらの記事の続きです。

https://qiita.com/okojoalg/items/0ac9a103a1364b06b151

# mmposeで別のモデルを使うには？

天下り的にチュートリアルを進めただけでは、別のモデルを使うにはどうしたらよいか、わかりませんね。
チュートリアルで扱ったトップダウン型の手法ではなく、ボトムアップ型のアプローチの推論を実践してみましょう。

以下のURLから、使いたいモデルを選択しました。
https://mmpose.readthedocs.io/en/latest/papers/backbones.html

今回はボトムアップ型の手法である「Associative Embedding + Higherhrnet on Coco」の中から、HigherHRNet-w48を選択しました。Archに設定ファイルへのリンクが、ckptに重みのURLがありますね。それぞれ、

* https://github.com/open-mmlab/mmpose/tree/master/configs/body/2d_kpt_sview_rgb_img/associative_embedding/coco/higherhrnet_w48_coco_512x512.py
* https://download.openmmlab.com/mmpose/bottom_up/higher_hrnet48_coco_512x512-60fedcbc_20200712.pth`

ですが、設定ファイルはclone済ですので、`configs/body/2d_kpt_sview_rgb_img/associative_embedding/coco/higherhrnet_w48_coco_512x512.py`の部分さえわかればよいのです。


``` python
pose_config = 'configs/body/2d_kpt_sview_rgb_img/associative_embedding/coco/higherhrnet_w48_coco_512x512.py'
pose_checkpoint = 'https://download.openmmlab.com/mmpose/bottom_up/higher_hrnet48_coco_512x512-60fedcbc_20200712.pth'
```

以上のように設定しました。また、ボトムアップ型の推論には以下の関数を使いますので、importしておきましょう。

``` python
from mmpose.apis import inference_bottom_up_pose_model
```

続いて、モデルをロードしての推論ですが、物体検出がない分、実は簡単です。

``` python
pose_model = init_pose_model(pose_config, pose_checkpoint)
pose_results, returned_outputs = inference_bottom_up_pose_model(pose_model, img, dataset=pose_model.cfg.data.test.type)

vis_result = vis_pose_result(pose_model,
                             img,
                             pose_results,
                             dataset=pose_model.cfg.data.test.type,
                             show=False,
                             out_file="posed_000000197388.png")

cv2_imshow(vis_result)
```

しっかりと推定されている結果が表示されますね！
![posed_000000197388.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630841/3fe02c39-a770-a4fe-6a49-674e961b7443.png)

皆さんはぜひ他のモデルでも試してみてくださいね。
トップダウン型の手法を使う場合で、物体検出モデルを変更したい場合はmmdetを触らないといけませんが、基本的に扱い方は同じです。以下のページから使用したい物体検出モデルの「Please refer to hogehoge for details.」から各モデルのGitHubのREADMEのページに飛び、そこから設定ファイルのパスとチェックポイントのパスを探してみてくださいね。

https://mmdetection.readthedocs.io/en/latest/model_zoo.html

次の記事では3D姿勢推定でも扱いたいと思います。
p5.js Web Editor上に気象庁の天気予報情報を表示してみる（HTTPリクエストには axios を利用）

以下の 2つの記事に書いていた内容を組み合わせてみた、という内容です。

- [気象庁公式の天気予報の情報を Node.js で取得し中身を検索する（ライブラリに Got を用いる） - Qiita](https://qiita.com/youtoy/items/c7dba010ab7d0763e879)
- [p5.js Web Editor上で axios を使った HTTPリクエスト（JSONPlaceholder から GET で情報取得） - Qiita](https://qiita.com/youtoy/items/8d9bea9063110b10ac46)

## 下準備
[p5.js Web Editor](https://editor.p5js.org/) で [axios](https://axios-http.com/) を使うため、ライブラリを CDN から読み込んでおきます。

詳細は、[上記2つ目の記事内の「p5.js Web Editor上で axios を使う」という部分](https://qiita.com/youtoy/items/8d9bea9063110b10ac46#p5js-web-editor%E4%B8%8A%E3%81%A7-axios-%E3%82%92%E4%BD%BF%E3%81%86)をご覧ください。

## 実装した内容
下準備が終われば、あとは sketch.js の中でプログラムを書くだけです。

気象庁の天気予報情報取得の話に関する詳細は、以下の記事をご覧ください。
　●気象庁公式の天気予報の情報を Node.js で取得し中身を検索する（ライブラリに Got を用いる） - Qiita
　　https://qiita.com/youtoy/items/c7dba010ab7d0763e879

今回、天気予報の情報を取得する地域（＝埼玉県北部）は適当に決めています。

以下が実装した内容です。
あと、p5.js上に情報を表示する部分の実装が、かなり適当な感じに...

```javascript
const url = "https://www.jma.go.jp/bosai/forecast/data/forecast/",
  areaCode = "110000"; // 埼玉
let publishingOffice = "",
  area0 = "",
  weathers = Array(3);

function setup() {
  createCanvas(400, 400);
  weathers.fill("");
}

function draw() {
  background(220);

  textSize(20);
  fill(0, 100, 150);
  text(`情報元： ${publishingOffice}`, 10, 60);
  textSize(16);
  fill(20, 20, 20);
  text(`地域： ${area0}`, 30, 90);
  fill(100, 120, 120);
  text(`天気（今日）： ${weathers[0]}`, 30, 120);
  text(`天気（明日）： ${weathers[1]}`, 30, 150);
  text(`天気（明後日）： ${weathers[2]}`, 30, 180);
}

async function keyPressed() {
  if (key === "g") {
    try {
      const response = await axios.get(`${url}${areaCode}.json`);
      const resData = response.data;
      console.log(resData);
      publishingOffice = resData[0].publishingOffice;
      area0 = `【埼玉県】 ` + resData[0].timeSeries[0].areas[0].area.name;
      const threeDaysWeather = resData[0].timeSeries[0].areas[0].weathers;
      console.log(threeDaysWeather);
      for (let i = 0; i < 3; i++) {
        weathers[i] = threeDaysWeather[i];
      }
    } catch (error) {
      console.error(error);
    }
  }
}
```

前の記事にも書いていますが、axios の処理で await を使っているので、それを含んでいる keyPressed() の部分は `async function` にしておいてください。

上記のプログラムを実行し、HTTPリクエストを実行するキー操作（gキーの押下）を行うことで、以下のように無事に情報を得ることができました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/p5js?src=hash&amp;ref_src=twsrc%5Etfw">#p5js</a> Web Editor上で、axios を使った HTTPリクエストの処理（GET）を行い、気象庁の天気予報情報を取得して、その内容をキャンバス上に表示してみた。 <a href="https://t.co/g7kyMkPae9">pic.twitter.com/g7kyMkPae9</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1459933187547619330?ref_src=twsrc%5Etfw">November 14, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
YouTubeの低評価が見れなくなったので推定するツール

Youtubeの仕様変更で低評価(dislike)が標準で非表示になって見れなくなったようなので取り急ぎで推定みたいなことをするコードをJavaScriptで書きました。


## インストール 

1. [Tampermonkey • Chrome](https://www.tampermonkey.net/) Chrome拡張機能 か [Greasemonkey](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/) for Firefox をインストールします.
2. ユーザースクリプトを [ここをクリック](https://github.com/yuis-ice/YouTube-Dislike-Estimator/raw/main/userscript/main.user.js) してインストールします。


![ShareX_ScreenShot_cf668d9c-e5f3-4128-9bb5-bd5d1ed9c347.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170548/0b094212-0d9b-cf59-39c9-4b3ffa2e1088.png)

## Github

[YouTube-Dislike-Estimator: Estimates the removed YT Dislike #BringBackDislikes](https://github.com/yuis-ice/YouTube-Dislike-Estimator)

## 仕組み

likes/views を計算して標準偏差ベースで色付けします。

動画を見るごとに動画の閲覧数といいね(高く評価)をスクレイピングしてローカルストレージに入れ、その後の計算に利用します。

データを消したい場合には _yt_dislike_estimator フィールドを削除すればデータは消えます。(F12でデベロッパーツールを開きアプリケーション、ローカルストレージへ進みフィールドを探します)

## 気づいてしまったこと

それについてのredditを見てたら、私がコードを書いている間に新しく投稿されていたレスで、"これのための拡張機能を作ったよ"といったものが投稿されており、いまさらかぁと思いつつどう実装されたのか興味があったのでリポジトリ [I-Demand-Dislikes/I-Demand-Dislikes](https://github.com/I-Demand-Dislikes/I-Demand-Dislikes) を見てみると
詳しくコードはまだ見てないのですがどうも面倒くさい実装をしなくともAPI経由すれば見れるらしい。完全にデータにクライアントサイドからアクセスできなくなったわけでもないようなので、もしかしたら私がよく調べなかっただけでHTMLのどっかにひっそり埋め込まれてる説すらあるかもしれないと思ってしまいました。あいにく過去の動画で画面をスクリーンショットなりhtmlなりで保存していたことがないので、それを確かめることはやりたくてもできなかったのが正直なところです。
やはりアーカイビングは大事だと再実感した経験でした。
NotionAPIが使えるようになるまで

# 概要

Notionのページを定期的に作成したり、更新したりするために使用する
NotionAPIの初期設定について紹介します


# 手順

## トークンの発行

https://www.notion.so/my-integrations

からAPIのトークン発行手続きを行います。

上記ページの「新しいインテグレーションを作成する」ボタンを押下

![2021-11-14_21h47_52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/7ce92bf4-1160-c28f-62e0-318abc07d107.png)

基本情報の名前に任意の名前を入力し、「関連ワークスペース」が導入を行いたいスペースになっていることを確認して、送信ボタンを押下


![2021-11-14_21h48_33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/6f9ced07-e727-67ef-7cc5-c5edeb6e05ff.png)

次の画面へ遷移すると、発行されたトークンを確認することができます。

:::note warn
このトークンが他人に漏れてしまうとAPIを利用してNotionに記述している内容を取得したり、
更新されてしまう可能性があるため流出しないように注意してください。
:::


「インテグレーションの種類」は「内部インテグレーション」を選択したままでOKです。
（誰でも使えるAPIを作成する場合等に「パブリックインテグレーション」を選択するようです）

## APIを使用したいページ(DB)にインテグレーションの招待

APIを使用したいページ(DB)に対して作成したインテグレーションの招待を行う必要があります。

![2021-11-14_22h00_33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/6a9a08d7-ace9-0700-beb5-c60c20690cef.png)

使用したいページやデータベースなどの画面の右上の「共有」ボタンを押下→「招待」ボタンを押下
→作成したインテグレーションを選択して「招待」ボタンを押下


# 動作確認

動作確認として /pages (POST)のメソッドを使用します。
このメソッドはDBまたはページを親としてその配下にページを作るメソッドです。

https://developers.notion.com/reference/post-page


テスト用のDBとして以下のようなDBを作成します。
![2021-11-14_23h23_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127686/7d458276-9de4-4838-60bf-42c5218f3139.png)

curlで以下のリクエストを投げて、エラーが返ってこなければOK

`secret_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` の部分は発行したトークン
`"database_id": "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"`の部分はDBのページを開くと
URLが `https://www.notion.so/{userName}/{databaseID}?v={viewID}`という形式になっているのでそこから取得します。 


DBの子ページを作成

```
curl --location --request POST 'https://api.notion.com/v1/pages' \
--header 'Authorization: Bearer secret_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' \
--header 'Content-Type: application/json' \
--header 'Notion-Version: 2021-08-16' \
--data '
{
    "parent": {
        "database_id": "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"
    },
    "properties": {
        "Name": {
            "title": [
                {
                    "type": "text",
                    "text": {
                        "content": "APIでページ作成テスト"
                    }
                }
            ]
        }
    }
}'
```

`properties.Name` は上図の例の列名が`Name`としているため`properties.Name`という名前にしています
`名前`としている場合は`properties.名前`とします。

```
...
    "properties": {
        "名前": {
            "title": [
                {
...
```



## トラブルシューティング

エラーメッセージ：

```
{"object":"error","status":404,"code":"object_not_found","message":"Could not find database with ID: XXXXXXXXXXXXXXXXXXXX."}
```

→ ページ(DB)に対してインテグレーションが追加されていることを確認してください。

# 他メモ等

## リクエスト上限について

https://developers.notion.com/reference/errors#request-limits

> Rate-limited requests will return a "rate_limited" error code (HTTP response status 429). The rate limit for incoming requests is an average of 3 requests per second. Some bursts beyond the average rate are allowed.

からリクエストの頻度の上限として、平均3回/秒(おそらく瞬間的に1秒以内に3回以上リクエストが行われる分には制限がかからず、定常的に1秒間に3回以上のリクエストが行われると制限される)の制限があり、それを超えるとレスポンスとして429が返ってくる模様

回避するにはループ的にAPIを呼び出すようなことをするのであれば少しスリープを入れる等の対応が必要になりそう
pythonにdlibをインストールしようとしてエラーが出た時の対処法(Windows)

pythonでdlibを使用するためにインストールしようとして、
色々つまづいたので対処法を残す。
スクショなど取り忘れたので画像一切なしです。すいません。
そのうち画像も用意します。

もしかすると不要な工程もあるかもしれないですがあしからず。

# 1. 環境
環境は以下の通り
・Windows 10 Home 64bit
・Anaconda 4.10.3
・python 3.8.8

# 2. CMakeのインストール
`pip install cmake`でインストールできる(らしい)。


自分はCMakeのサイトからインストーラーをダウンロードしてインストールした。
・[CMakeのダウンロードリンク](https://cmake.org/download/)

インストールするときに"Add CMake to the system PATH for all users"にチェックを入れる。

コマンドプロンプトかPowerShellで
`cmake --version`
を入力してバージョンが表示されたら正常にインストールできてる。
表示されなかったら、CMake/binにパスが通っているかなど確認してください。

# 3. VisualStudio2019のインストール
自分環境はすでにインストール済みだったので詳細は不明。
"C++によるデスクトップ開発"にチェックされていないといけないらしい。

VisualStudioでCMakeインストールしてたら、2のCMakeのインストールは不要な気がします...
詳しい方いたら教えて下さい...

# 3. dlibのインストール
AnacondaPromptで`pip install dlib`でインストールしようとしたらエラーが出て無理だった。

dlibのgithubの[ここ](https://github.com/davisking/dlib/issues/2439)のページ見てみたら、
よくわからないけど手動で入れてみろって書いてある。

Githubからソースコードダウンロードして適当に展開する。
・[リンク](https://github.com/davisking/dlib)

AnacondaPromptで展開したフォルダまで行き`python setup.py install`でインストールしてみる。
　-> やっぱりエラーが出てインストール出来ない。
　　 エラーを見てみるとCMakeでエラーになっていた。

改めて調べてみると[このページ](https://github.com/davisking/dlib/issues/2358)に
インストールするときに`--no DLIB_GIF_SUPPORT`を使用してビルドしろって書いてある。

先ほどのAnacondaPromptに以下のように入力。
`python setup.py install --no DLIB_GIF_SUPPORT`
問題なくインストールできた。これで無事にdlibが使用できるはずです。

# 4.最後に
ここまで調べるのに1時間近く使ってしまった。
もうちょっと調べる力をつけたい...
【初心者向け2021年最新版】M1 Mac + Java + IDEA + Apache Tomcat環境構築

ターミナルの作業は殆どなくて、基本はアプリインストールすれば環境構築できるはずです。
初心者にやさしい導入手順です。お役に立てたら嬉しいです。

## 1. JDK

[アクセス→Download Zulu Builds of OpenJDK](https://www.azul.com/downloads/zulu-community/?os=macos&architecture=arm-64-bit&package=jdk)

必要なバージョンを選び、アーキテクチャー必ず**ARM 64-bit**にしてください

あとはdmgダンロードのみ

![img](https://raw.githubusercontent.com/chihokyo/image_host/master/20210621024644.png)

ローカルに落としたらいつものようにインストールだけ

```bash
#下記のコマンドで確認できる
$ java -version   
```

## 2. IDEA

[すぐダウンロードできるIDEAのURL ](https://www.jetbrains.com/idea/download/download-thanks.html?platform=macM1)

アプリをインストールし、起動してください。

New Project　→ 何にも選ばずにNext押下　→　Next押下　→ Project Name適当に入力　→ Finish


> ここまではJava環境構築が終わるはずですが、WEB開発に不可欠なサーバとしてApacheも構築しましょう。


## 3. Apache Tomcat

詳細ページはこちら→ https://tomcat.apache.org/download-10.cgi

[すぐダウンロードできるApacheのURL](https://downloads.apache.org/tomcat/tomcat-10/v10.1.0-M1/bin/apache-tomcat-10.1.0-M1.zip)

### 3-1. 解凍

zipを解凍してから下記のコマンドを叩く

```bash
cd /解凍ファイル/apache-tomcat/bin
cd bin
ls -la *.sh
```

*.sh*を実行する権限が必要

権限がない場合、下記のコマンドで付与する

```bash
# 付与前
# -rw-r--r--@ 1 chin  staff  24814 Jun  8 14:26 catalina.sh
chmod +x *.sh
# 付与後
# -rwxr-xr-x@ 1 chin  staff  24814 Jun  8 14:26 catalina.sh
```

### 3-2 確認

*start.up*　叩く

*Tomcat started.* 出たら成功！

大体の流れは↓

![](https://raw.githubusercontent.com/chihokyo/image_host/master/20210620021704.png)

以上です。
Firebaseでやたらと再認証が要求される件

Qitta初投稿になります。モバイルエンジニアのEtsuwoです。

Firebase便利ですよね。
特にログイン周りを一挙に任せられる点がとても優秀だなーと感じています。
しかし、もうちょっと融通効かないかなーとか思ってしまう点もあります。
その代表が「再認証」がやたらと要求される点だと思っています。
セキュリティ的に仕方ないのかもしれませんが、しっかり考慮しないと普通に欠陥サービスになってしまうと間違いなしだと思うので記事にします。

# 再認証とは
Firebaseではセキュリティ的に重要な操作を行う際、最後の認証から一定時間以上経過していると「再認証」が求められます。
「本当にこの操作行って良いのか」or「本当に本人なのか」確認するためにもう一回ログインしろよってことですね。
再認証は最後の認証から**5分以上**経過している場合に、以下の処理を行う時に必要になります。

- メールアドレスの変更
- メールを使用しないパスワードの変更
- ユーザアカウントの削除

最後の認証から5分以上経過して以上の処理を行うと、`FIRAuthErrorCodeRequiresRecentLogin`のエラーが返ってきます。

# どうすれば良いのか
方針は二つあると考えています。

1. 再認証を求められる可能性がある処理を行う前に前もってユーザに再認証させる
1. `FIRAuthErrorCodeRequiresRecentLogin`が返ってくるたびに再認証させる

僕としては圧倒的に1がオススメかなと考えています。
なぜなら**5分**という時間がかなーり短く、場合によってはほぼ確定で再認証することになるからです。
例えば、ユーザ削除の処理を行う際に2の方針をとった場合、
ユーザ削除の処理を行う→再認証を求められて再認証処理→もう一回ユーザ削除処理
と3ステップ必要ですが、1の場合は、
再認証処理→ユーザ削除処理
と2ステップで済むので処理的にもユーザ体験的にも楽です。

なおユーザの再認証には`reauthenticate(with:)`メソッドを使用します。
以下はiOSでの使用例です。

```swift:reauthenticate.swift
let user = Auth.auth().currentUser
var credential: AuthCredential // 何らかのプロバイダで認証

user?.reauthenticate(with: credential) { error in
  if let error = error {
    // エラー処理
  } else {
    // 成功時の処理
  }
}
```

# 最後に
再認証を考慮し忘れるとかなりクリティカルな気がします。
実装によってはひどいことになるので気をつけましょう。

# 参考文献
[Firebaseでユーザ管理:iOS](https://firebase.google.com/docs/auth/ios/manage-users?authuser=0)
p5.js Web Editor上で axios を使った HTTPリクエスト（JSONPlaceholder から GET で情報取得）

使い道があるかは分からないですが、[axios](https://axios-http.com/) を使った [p5.js Web Editor](https://editor.p5js.org/) からの HTTPリクエスト（GET）を行う話です。

リクエストを送る先には [JSONPlaceholder](https://jsonplaceholder.typicode.com/) を用います。
![JSONPlaceholder.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/26d8abc8-d808-a807-1a3b-4bb0ea59f2f0.jpeg)

## p5.js Web Editor上で axios を使う
### ライブラリの読み込み
[axios の公式ドキュメントのイントロのページ](https://axios-http.com/docs/intro)に書かれている CDN上のライブラリを、p5.js Web Editor の index.html で読み込みます。
![CDN.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/deb10cad-1337-0d2b-1415-2c69062dfb1e.jpeg)

どちらでも OK です。

### リクエスト先の URL
冒頭で書いたとおり、JSONPlaceholder に対して　HTTPリクエストを送って、適当な情報を取得する形にします。
[JSONPlaceholder のガイド](https://jsonplaceholder.typicode.com/guide/)の最初のほうに書いてある、以下の URL を使うことにします。
 `https://jsonplaceholder.typicode.com/posts/1`

ちなみに、ブラウザでアクセスすると、以下の JSON が得られるのが確認できます。

```JSON
{
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
  "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
```

### axios による GETリクエストの処理
[axios の公式ページの Example](https://axios-http.com/docs/example) に書かれた、以下の部分の処理を用います。
![await.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/d9c226ed-ab94-d50c-9949-73c14ac6e85e.jpeg)

### JavaScriptのプログラムを書く
あとは、p5.js Web Editor上の sketch.js を編集します。
キーを押したら HTTPリクエストを実行する、という形にしてみました。

```javascript
const url = "https://jsonplaceholder.typicode.com/posts/1";

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220);
}

async function keyPressed() {
  if (key === "g") {
    try {
      const response = await axios.get(url);
      console.log(response);
    } catch (error) {
      console.error(error);
    }
  }
}
```

await を使っているので、それが含まれる `keyPressed()` の部分は `async function` にしてください。

プログラムを実行し、gキーを押すと、以下の結果を得られます。
![得られた結果.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/c0c3170a-9780-fa38-d25e-b974eb300af9.jpeg)

無事に JSON を取得できました。
Devil With Angel Heart～巡回畳み込み・直線畳み込み（予告編）

[<B>MATLAB/Simulink Advent Calendar 2021</B>](https://qiita.com/advent-calendar/2021/matlab) に参加予定です。


##・使用ツール
<dl>
  <dt>MATLAB</dt>
　<dd>－Image Processing Toolbox</dd>
<br>
  <dt>Photoshop</dt>
</dl>

##・処理結果
　テスト結果をちょい見せ
![heartsBokeh_pre.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2260243/9b8d34b8-977a-50f2-c9d2-016ef8e5167d.gif)



[<B>note</B>](https://note.com/leftbank/) にUpします。
【初心者向け】エイリアスの設定方法(.bashrc) Kali Linuxの場合

#エイリアスって何？

以下の記事を参照してください。

https://wa3.i-3-i.info/word1149.html

簡単にいうと、コマンドのショートカットみたいなやつです。
# 設定方法(`.bashrc`の場合)
`.bashrc`ファイルに次のように定義すればいいです。

    alias ll='ls -la'
# 設定方法(`.bash_aliases`の場合)
`.bashrc`ファイルに書き込んでもいいのですが、間違って消しちゃったりすると取り返しがつかないのでエイリアス専用のファイルを作ります。

    # ホームディレクトリに移動
    $ cd
    
    # .bashrcと.bash_aliasesがあるか確認。
    $ ls -la

    # エイリアスのコマンド追加
    # ファイル削除する際に聞いてくれるオプションです。
    $ echo "rm='rm -i'" >> .bash_aliases

    # エイリアスの有効化
    $ source .bash_aliases

    # エイリアスできてるか確認
    $ alias

    # 試してみる
    $ rm

これでいけるハズ、、、

# PC再起動したら、上記のエイリアスが無効になってた
どうやら、`.bashrc`ファイルの中に`.bash_aliases`を読み込む設定が記載されていないとダメっぽい、、

    # ホームディレクトリに移動
    $ cd

    # .bashrcの中身を確認
    $ cat .bashrc
    ...(略)
    if [ -f ~/.bash_aliases ]; then
       . ~/.bash_aliases
    fi
    ...(略)

ん？`.bashrc`ファイルの中に`.bash_aliases`を読み込む設定が記載されているはずなのに、なんでPC再起動するとエイリアスが無効になるの。

# Kali Linuxでは違う
どうやら、Kali LinuxのデフォルトシェルはbashではなくZSHだそうです。
以下の記事を参考にしました。

https://www.fixes.pub/linux/473430.html

そこで、`.bashrc`ファイルではなく`.zshrc`ファイルに次のif文を追記しました。

    $ vi .zshrc
    ...(略)
    if [ -f ~/.bashrc ]; then
       . ~/.bashrc
    fi
    ...(略)

これで、PC再起動してもエイリアスが有効になりました。

*Good luck*
【2021年11月最新】M1 MacbookでGitHub ssh接続する手順簡単まとめ

新しいパソコンに買い替えて、昔のやり方でうまくできなかったため、メモ用に書きました。

## ターミナル作業

```bash
cd ~
git config  --global user.name '名前'
git config  --global user.email '“メールアドレス”'
ssh-keygen -t ed25519 -C “メールアドレス”
# ２つの鍵生成までエンター叩き続ける
pbcopy < ~/.ssh/id_ed25519.pub
```

## Github側作業

公開鍵登録

**Settings　→  SSH adn GPC Keys →  New SSH key**

Title:端末がわかるように自由に命名

Key: `pbcopy < ~/.ssh/id_ed25519.pub` コピーされたものをそのままkeyに貼り付け

## 成功！！！
Arduinoの勉強　第1弾：Arduinoのインタフェース

# #Arduinoのインタフェース
##はじめに
ハードウェアの勉強のためにArduinoを復習も兼ねて参考教材に沿って，勉強する．細かな部分の理解までして，自在に扱えるようになることが目的である．その第1弾として，「Arduinoのインタフェース」を扱う．

## 概略図（Arduino Uno）
以下にArduino Unoの外観図と電子回路図及び端子名称図を示す．
![arduino_uno_R3-appearance.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/38e47779-fcf9-3fe2-9912-033450a25544.jpeg)

![Arduino_elec_circuit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/4c6bbaff-8e61-16e7-990e-da3c66b5f9b8.png)

![Arduino_pins.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/ffe6a299-7afa-7ea4-9b1a-2259638c1858.png)


## 用語の簡単なまとめ
- 汎用入出力（GPIO: General Purpose Input/Output）
    - 外部との入出力を制御できる端子（今でいうデジタル入出力を指す）
- AREF（Analog REFerence）
    - アナログ入力のために使う電圧を構成するために外部電源から所望の電圧を与えるために使うピン
        - （注） AREFピンに外部基準電圧源を接続した場合、デフォルトの設定のまま外部基準電圧源を使用すると、チップ内部で短絡(ショート)が生じ、Arduinoボードが損傷するかもしれない
- PWM（Pulse Width Modulation：パルス変調）
    - 擬似アナログ出力の方式
        - HIGH・LOWを周期的に切り替えて任意の電圧を作る（詳細は別記事で説明）
- IOREF
    - VCCと同じ．マイコン駆動電圧．UNOなら5V端子と同じ
- RESET
    - リセット端子．GNDと繋ぐとリセット
- I$^2$C
    - 通信方式の1つ（詳細は別記事で説明）
- シリアル通信
    - 通信方式の1つ（詳細は別記事で説明）

## 感想
学部4回生で研究なども忙しく投稿自体，久しぶりだが，また改めて整理のために投稿していく．ROSについてもまだまだ投稿するつもりであるが，今回からハードウェアの勉強としてArduinoについても再勉強することにした．Arduinoは使ったことはあるものの意外と細かなところまでは把握できていなかったと思っている．特に端子はデジタルとアナログの部分は知っているが使ったことのないその他のピンについて触れることで，故障となり得ることも学ぶことができた．より詳細な説明は次回以降にまとめていく．

最近，Twitterのアカウントを作成してそこにも投稿しているが，夢の実現のためにももっと技術と知識を磨かなければとまたモチベーションがさらに高まっている．落ち着いたら，一年で得られたことも整理のために逐次まとめていきたいと思う．

## 参考文献
- 電子部品ごとの制御を学べる！Arduino電子工作実践講座 改訂第2版 福田和宏 著 ソーテック社
- Arduino Help Center: What is the AREF pin for?   
(https://support.arduino.cc/hc/en-us/articles/360018922239-What-is-the-AREF-pin-for-)
WPFを今更触ってみたログ。(INotifyPropertyChangedの疑問解決用)

# はじめに

仕事で突然C#を使う必要が出てきたから、かんたんに触ってみた結果を勉強メモとして残しておく。

# 勉強していて感じた疑問点

* INotifyPropertyChangedで任意のタイミングで更新通知を飛ばす方法はどうするの？

https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.inotifypropertychanged?view=net-5.0

INotifyPropertyChangedの記事(上記)では呼び出し元の情報を使ってイベントを発行していた。
では呼び出し元以外からイベントを発行する必要がある場合、どのように通知を送ればよいのだろうか。

# サンプルアプリの作成

Formアプリしかまともに作ったことがなかったので、WPFでのタイマーの使い方の確認もついでに行う。

まずは一定期間内のクリックをカウントするためのモデルを作り、

https://github.com/mickie895/WPFSampleApp/blob/main/ClickCheckSample/Models/ClockCounterClass.cs

タイマーのインスタンスは別に作成した。
(注：初期化とともにTimer.Start()したらデザイナ上でもタイマーが動いてしまった。
修正方法は今後の課題としておく。)

https://github.com/mickie895/WPFSampleApp/blob/main/ClickCheckSample/Models/TaskClock.cs

次にこのモデルを操作するためのビューを2つ作り、メインウィンドウではこの2つを同時に表示するようにしておく。
(ClickPanel：クリック可能なボタンと、経過時間を表示するためのプログレスバーがある
Counter：前回の経過時間内にクリックされた回数と、総クリック回数を持つ)

https://github.com/mickie895/WPFSampleApp/tree/main/ClickCheckSample/View

課題は、ClickPanel上のクリックコマンドによる操作の結果をどうやってCounterに通知するか、である。

# PropertyChangedEventHandlerの使い方

MSDNには具体的な例が少なかったので自分で確認してみた。
結果、PropertyChangedEventHandlerの引数には、senderは表示を変更したいViewModl、EventArgsには変更したいイベントプロパティの名前を入れれば良いようであった。

今回の例であれば、ざっくり書くと次の絵のような方針でViewModel→Model→ViewModel→Viewと通知を送れば良い。

![INotifyPropertyChanged.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395414/9c514dac-519a-cd65-2fd3-85252e685403.png)

※ただし、原則としてModelがViewModelの参照を持ってはいけないため、ModelからViewModelへはイベントを発行する必要がある。

そしてClickViewModelがイベントを受け取ったとき、更新したいプロパティに対してイベントを発行する。
(プロパティ名を文字列として指定しなければいけないのが引っかかるが。)

# 今回のサンプルコード

今回確認に使ったコードは下記のアドレスに入れておいた。

https://github.com/mickie895/WPFSampleApp/tree/main/ClickCheckSample
インフラエンジニア学習1114 Linux

※Linuxでネットワーク起動できない対処法

#systemctl restart network
Job for network.service failed because the control process exited with error code. See "systemctl status network.service' and 'journalctl -xe" for details.
（ネットワークに起動できない）

#systemctl restart NetworkManager
（NetworkManager再起動で解消できます。）



※バックアップフォルダー作成
バックアップフォルダー作成コマンド：# mkdir bk
21H1がバックアップできる WindowsPEメディアを作り直す

Win10をバックアップしようと以前作ったWindowsPEメディアでブートしようとしたらFatal Errorでブート出来なくなっていた。
久しぶりにWinADKダウンロードサイトに行ったら、Win10のバージョン毎にしっかり分かれていたのでPEメディアを作り直し、無事バックアップできたので備忘録として残しておきます
##WindowsADKのアンインストール
既にADKが入っていたら、アンインストール
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436645/9744d17f-64b1-6709-31b2-86f865a88b6b.jpeg)

##21H1用のADKとアドオンをダウンロード
赤〇と青〇
![無題2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436645/2a8b5a82-f143-a045-f37a-544af0ca78db.jpeg)



あとは、
<https://qiita.com/SkyLaptor/items/204245cf6bb4fee5b19d>
でご紹介いただいている通りでOKです

##ご注意
2004版も
- USBメモリに焼くなら32Gbyteまでのものしか使えないので注意ください。
- ISOに出すなら、490MbyteくらいなのでCD-ROMでもいけます。