OmniAICreator/Qiita-1.07M huggingface dataset:
C#からPDFにキーワードを埋め込みたい

PDFにキーワードを埋め込みたいと思ったので、メモ。
ついでに、TitleとAuthorも更新してみた。ソースコードの解説は、見たらわかると思うので特に書かない。

#PdfSharp

今回の開発環境はVisual Studio 2019。
[ツール]-[NuGetパッケージマネージャー]-[ソリューションのNuGetパッケージの管理]から、Pdfsharpをインストールする。

```C#:using
using PdfSharp.Pdf;
using PdfSharp.Pdf.IO;
```

上記の宣言をしておいて、あとはこんな書き方か

```c#:PdfDocumentOpenMode.Import
private void button1_Click(object sender, EventArgs e)
{
    PdfDocument document = new PdfDocument(); // 保存用の空のPDF
    PdfDocument doc = PdfReader.Open(@"E:\work\sampledata.pdf", PdfDocumentOpenMode.Import);

    document.Info.Title = "sampledata";
    document.Info.Author = "foo";
    document.Info.Keywords = "サンプル sample";

    foreach (PdfPage page in doc.Pages)
    {
        document.AddPage(page);
    }
    doc.Close();
    document.Save(@"E:\work\sampledata2.pdf"); // 保存
    document.Close();
}
```

こんな書き方（どちらがあるべき姿なのかは知らない）

```c#:PdfDocumentOpenMode.Modify
private void button1_Click(object sender, EventArgs e)
{
    using(PdfDocument doc = PdfReader.Open(@"E:\work\sampledata.pdf", PdfDocumentOpenMode.Modify))
    {
        doc.Info.Title = "sampledata";
        doc.Info.Author = "foo";
        doc.Info.Keywords = "サンプル sample";
        doc.Save(@"E:\work\sampledata2.pdf"); // 保存
    }
}
```

#Pdfium
Pdfiumでも試してみた。
同じようにNuGetからPdfiumを検索し、Pdfium.Net.SDKをインストールする。

```c#:Pdfium.Net.SDK
using Patagames.Pdf.Net;

private void button1_Click(object sender, EventArgs e)
{
    PdfCommon.Initialize(); // とりあえず初期化
    using (PdfDocument doc = PdfDocument.Load(@"e:\work\sampledata.pdf"))
    {
        doc.Title = "sampledata";
        doc.Author = "foo";
        doc.Keywords = "サンプル sample";
        doc.Save(@"e:\work\sampledata2.pdf", Patagames.Pdf.Enums.SaveFlags.RemoveUnusedObjects); // 保存
    }
}
```

もちろんどちらも、設定だけでなく参照もできたし、Keywordsに日本語も通った。

ちなみに、Pdfiumは無償で使えそうですが、Pdfium.Net.SDKは有償みたい。
[Simple pricing for everyone](https://pdfium.patagames.com/Purchase/)
Laravel mixでgoogle fontsが適用されなかった

Laravel mixでgoogle fontsを使うときにapp.scssにこう書くと

```scss:resources/sass/app.scss
@import url('https://fonts.googleapis.com/css2?family=M+PLUS+1p:wght@100;300;500&display=swap');
```

<br>
ビルドされた時に「；」で改行されて、cssで読み込まれなくなる

```css:public/css/app.css
@import url(https://fonts.googleapis.com/css2?family=M+PLUS+1p:wght@100;

300;500&display=swap);@charset "UTF-8";
```

<br>
なので「@100」とかのサイズ指定をやめてこう書くと読み込まれる

```scss:resources/sass/app.scss
@import url('https://fonts.googleapis.com/css2?family=M+PLUS+1p&display=swap');
```

<br>
デメリットとして100みたいな指定ができなくなる。

```css
font-size: 100;　#使えない
font-size: 1rem; #使える
```
<br>
もちろん通常通りに、HTMLにlinkとして読み込む分には普通に使える

```html
<link href="https://fonts.googleapis.com/css2?family=M+PLUS+1p:wght@100;300;500&display=swap" rel="stylesheet">
```
ArduinoをWindows PCからPythonで操作するためのTOOL : Ardipy

#Ardipy
Arduinoには標準でfirmata arduinoが用意されています。
ただ、このfirmataは速度が遅い問題があることや、Pythonとのインターフェースが不十分な状況です。
また、firmataはいろいろな方式に対応しようとしているため、I2Cなどの通信などを行う場合に重く
使いづらいため、独自FWとPythonドライバを作ってみました。

Ardino+Pythonで Ardipy

I2C, SPIのUSB変換とPythonドライバはAardvarkという機器が標準でサポートしていますが
価格と入手性が悪いため、Arduinoを使った簡易検査装置として使う事が目的としています。

##Ardipyソースコード
Arduino Uno スケッチ(Arduinoで動作するFW)
https://github.com/Nomisugi/Ardipy/blob/master/Ardipy01.ino

Pythonインターフェース(Arduino　FWをPCからコントロールするPython Driver)
https://github.com/Nomisugi/Ardipy/blob/master/Ardipy_Driver.py

firmataと違い、Ardipyは軽さを重視しているためArdino UNOで使うことを前提とし
それぞれのポートは最初から役割を決められています。画像が使える端子です。
![arduino-transparent.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506495/f011d7b9-ef27-8e47-34c4-1a93d3d4c08b.png)

注意点として PORT0,1 (TXD, RXD)ポートはUSB端子とUART通信で使用するため
使うと動作が停止します。Sample.py
ArdipyはPCとArduinoが常にUART通信を行う事が前提のため、このポートは使えません。

##Ardipy使い方
(1)Arduino UnoにArduino IDEを使いArdipy01.inoを書き込み
(2)Arduino UnoとPCを接続して、WindowsPCがUARTポート認識していること
(3)PythonにpySerialをインストール
(4)Pythonでサンプルコード実行

```Python:Sample.py
    from Ardipy_Driver import Ardipy

    ar = Ardipy()
    #Search for Arduino Uno UART
    ar.autoConnect()

    #I2C Check
    val = ar.i2cRead_word(0x40, 0x00)
    print(val)

    #AD Check
    val = ar.adRead(0x00)
    print(val)

    #Port Check
    light = True
    
    ar.portOut_bit(2, 0)
    i = ar.portIn_bit(3)
    print(i)

    for j in range(10):
        light = not light
        if( light ):
            ar.portOut_bit(2, 1)
        else:
            ar.portOut_bit(2, 0)
        time.sleep(1)

```

実際に動作しているかは、Arudino UnoのTX RXのLEDを確認してみてください。
またはArdinoのポート2にテスタを当てて確認してください。
今後はArdipyを使ったセンサー制御や各種GUIを作っていきます。
簡単なセンサー制御や簡単に制御機器をテストすることに使えると思います。
Kotlinプロジェクトでどこまでキーを隠蔽化できるか（その3：ProGuardの利用）

Kotlinを使ってAndroidアプリを作った際に、NCMBのアプリケーションキーとクライアントキーをどこまで隠蔽化できるのか試しています。[前回はC++を使ってコンパイル、隠蔽化する方法を試しました](https://qiita.com/goofmint/items/09c78dcf1fd664b85a37)。今回は難読化を実現するProGuardを使ったらどうなるのか試しています。

## ProGuardについて

[ProGuard](https://www.guardsquare.com/proguard)はAndroid Studio標準で使えるコードの圧縮、最適化、難読化を行うライブラリです。今回は特にオプションを指定せず使ってみました。

## デバッグ環境でも適用する

デフォルトではリリースビルドでのみProGuardが適用されるので、デバッグ環境でも使えるようにします。app/build.gradleを編集します。

```
android {
    // 省略
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        // 追加
        debug {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}
```

`proguard-rules.pro` は特に編集していません。

## Android SDKを導入する

次にNCMBのAndroid SDKを導入します。これは[イントロダクション (Android) : クイックスタート | ニフクラ mobile backend](https://mbaas.nifcloud.com/doc/current/introduction/quickstart_android.html)に沿って進めてもらえば問題ありません。具体的には次の手順を行います。

1. GitHubのリリースページからSDKをダウンロードして展開
2. NCMB.jarをapp/libsディレクトリに入れる
3. app/build.gradle の編集
4. app/src/main/AndroidManifest.xml の編集

## コードを修正する

MainActivity.kt を修正します。まずSDKを読み込みます。

```kotlin
import com.nifcloud.mbaas.core.NCMB;
```

そしてNCMBを初期化します。 `YOUR_APPLICATION_KEY` と `YOUR_CLIENT_KEY` はそれぞれ書き換えてください。

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    NCMB.initialize(this.getApplicationContext(),"YOUR_APPLICATION_KEY","YOUR_CLIENT_KEY");
    // 省略
}
```

これで完了です。

## ビルドする

後は普段通りAndroidアプリをビルドします。

## jadx-guiで見る

jadx-guiで見た内容です。

![ScreenShot__2021-11-05_14_41_17.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/3b6da317-09ab-2a68-d0c9-11b9ca62e385.jpeg)


難読化される際にメソッド名は書き換わっています。しかしキー自体は文字列なので、そのまま出力されています。 `NCMB.initialize` が本来のメソッドなので、それを探しても見つからないという点がちょっとしたメリットですが、キー自体は露呈してしまうので、多少面倒くらいにしかならなそうです。

## まとめ

ProGuardはコードの難読化、最適化ツールなので、キーの隠蔽化という目的には適していません。[隠蔽化するのであればC++を使った方法](https://qiita.com/goofmint/items/09c78dcf1fd664b85a37)が良さそうです。
Kubernetesで使うimageをctrコマンドでロードする（containerd）

## 背景

containerdをCNIとして動作させるKubernetesクラスタをオフラインで構築・使用する際、イメージをロードするところで少しハマったので共有します。

インターネット接続できる環境ならスムーズにいくと思うのですが、自分の場合はプロキシ経由のためイメージがpullできず、一旦別PCでローカルにイメージを落とし、それをロードすることにしています。

前提として、Kubernetesで使用するイメージ（kube-apiserverなど）は、

```
# crictl images
```
で見えるようになっている必要があります。
（crictlはkubeadmとかのインストール時に同時に入ってきます）


しかし、containerd付属の管理ツールであるctrでそのままロード（import）しても出てきません。

```
# ctr images import kube-apiserver.tar.gz
unpacking k8s.gcr.io/kube-apiserver:v1.22.1 (省略) ...done

# crictl images
IMAGE                                 TAG                 IMAGE ID            SIZE

```

## 対処法

namespaceにk8s.ioを指定してロードします。

```
# ctr -n k8s.io images import kube-apiserver.tar
...

# crictl images
IMAGE                                 TAG                 IMAGE ID            SIZE
k8s.gcr.io/kube-apiserver             v1.22.1             f30469a2491a5       130MB
```

ローカルでビルドしたイメージをロード（import）してk8sで使いたい場合も同様で、ネームスペースを指定してやればk8sで使えます。

crictlでイメージをロードできるようにしてくれれば使いやすいのですが、イメージロードはCRIが持つべき機能ではない、ということで実装されていないようです。
ReadWriteOnceとReadWriteMany

#accessModes攻略
GCP環境で、K・8・Sに追加でDISKを設定することがあったとします。
そのときにaccessModesというものを設定する必要があります。
設定できる値は以下です。

ReadWriteOnce…単一Node読み書き可
ReadOnlyMany…複数Node読み可
ReadWriteMany…複数Node読み書き可

判定が見た目通りではないので、注意が必要です。

設定はPod単位かと思いきや、Node単位なのです。
そのため、「ReadWriteOnce」といっても同一Nodeからであれば、複数のPodからアクセス可能です。
※Kubernetes v1.22 から単一Podからのアクセスを許可するReadWriteOncePodが追加されました。
参考：
https://kubernetes.io/docs/concepts/storage/persistent-volumes/

#２択
尖った性能の永続ディスク(Persistent Disk)からは「ReadWriteOnce」のみしか設定できません。
Many系を設定したい場合は、オールラウンダーな「Filestore」を使います。

Many系は複数のノードからの接続も可能にする万能設定です。
ノードをマルチゾーン設定した場合にも正しく動かす場合に要求されます。

設定自体は「Persistent Disk」も「Filestore」もあまり変わりません。
リュウとケンの関係と言って差し支えないでしょう。

```PersistentDisk.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: sample-pv
spec:
  capacity:
    storage: 100Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: log
  gcePersistentDisk:
    pdName: pd001
    fsType: ext4
--- 
apiVersion: v1
kind: PersistentVolumeClaim
metadata: 
  name: sample-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: log
  resources:
    requests:
      storage: 100Gi
```

```Filestore.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: sample-pv
spec:
  capacity:
    storage: 1T
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: log
  # GCPコンソールで設定された値を記載
  nfs:
    server: "xxx.xxx.xxx.xxx"
    path: "/xxx"
--- 
apiVersion: v1
kind: PersistentVolumeClaim
metadata: 
  name: sample-pvc
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: log
  resources:
    requests:
      storage: 1T
```

ただし、コストがPersistent Diskと比べてかかります。
標準とプレミアムの２種類のモードがあり、安価な標準タイプでも1TBスタートですので、ご注意を。

現場からは以上です。
[積分を用いて自然対数log(a)の近似値を求める。] 数値計算入門、数値積分、シンプソン公式、自然対数、C言語、Cプログラミング

2021/11/5投稿
#0.メニュー#
[1.対数関数logと積分の関係](#1対数関数logと積分の関係)
[2.数値積分、近似公式](#2数値積分、近似公式)
[3.Cでの計算コード](#3Cでの計算コード)
[4.計算結果](#4計算結果)


####logについて####
:::note info
自然対数を $\log$ としその底は $e=2.7182818 \cdot\cdot\cdot $　とする
:::


#1.対数関数logと積分の関係#
$\log(x)$の微分は次のように与えられる

```math 
\frac{d}{dx}\log(x) = \frac{1}{x}
```
従って次のような関係式が得られる

```math 
\log(a) = \int_{1}^{a} \frac{dx}{x} 
```

上式の右辺を数値積分で計算することを考える


#2.数値積分、近似公式#
###積分区間を離散化###
``` math 
\space\space\space x_k := x_0 + k\Delta x\\
```

###図###
![数値積分.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/834214/89054fc6-558b-42bc-dfeb-a31fd5530ab9.png)


###シンプソンの公式###
``` math 
\int_{x_{k-1}}^{x_{k}} f(x) dx \simeq \frac{\Delta x}{6} 
\Bigl( 
f(x_{k-1})
+4f\Bigl( x_{k-1}+\frac{\Delta x}{2} \Bigl)
+f(x_k)  
\Bigl) \\
```

上の公式を区間$x=[x_0,x_N]$に適用する

``` math 
\int_{x_0}^{x_N} f(x) dx = \sum_{k=1}^N \int_{x_{k-1}}^{x_{k}} f(x) dx \\
\simeq 
\sum_{k=1}^N \frac{\Delta x}{6} 
\Bigl( f(x_{k-1})+4f\Bigl(x_{k-1}+\frac{\Delta x}{2}\Bigl)+f(x_k) \Bigl)
```
$f(x) = 1/x$を適用すると次のような近似公式を得る
###自然対数の近似公式###
``` math 
x_k := 1 + k\Delta x \space\space\space N = \frac{a-1}{\Delta x}\\
\log(a) \simeq \sum_{k=1}^N \frac{\Delta x}{6}
 
\Bigl( \frac{1}{x_{k-1}} + \frac{4}{x_{k-1}+ \frac{\Delta x}{2}} + \frac{1}{x_k} \Bigl)
```





#3.Cでの計算コード#
```c:mylog.c
#include <stdio.h>
#include <math.h>

// logの近似値を計算する

// xの整数n乗を返す関数
double zpow(double x, int n){
    double re = 1.0;
    int i;
    for (i = 1; i <= n; i++){
        re *= x;
    }
    return re;
}

// nの階乗
double fac(int n){
    double re = 1.0;
    int i;
    for (i = 1; i <= n; i++){
        re *= (double)i;
    }
    return re;
}

// 自作対数関数 シンプソン積分
double mylog(double a){
    int N = 1000, k;
    double re = 0.0, h = (a - 1.0)/((double)N), x_k, x_k_1;
    for(k = 1; k <= N; k++){
        x_k_1 = 1.0 + ((double)k - 1.0)*h;
        x_k = 1.0 + ((double)k)*h;
        re += (h/6.0)*(1.0/x_k_1 + 4.0/(x_k_1 + 0.5*h) + 1/x_k);
    }
    return re;
}

// main関数
int main(void){
    // 変数宣言
    double val, a = 30.0, mylog_val;
    //
    // 数値計算
    mylog_val = mylog(a);
    printf(" a := %lf \n", a);
    printf(" log(a) = %.16f\n", mylog_val);
    // 絶対誤差
    printf(" Error: %.16f", fabs(log(a) - mylog_val));
    //
    return 0;
}
```


#4.計算結果#
今回は$\log(30)$の近似値を計算してみた
cのmathライブラリーの組み込み関数logで計算した値
との絶対誤差も計算してみたよ
####精度上の注意####
:::note info
因みにこの記事には載せていないがほかの値で計算してみた結果
$\log(a)$の$a$の値を大きくするほど精度が悪くなる
$a=30$で計算したが、この精度はあくまでも一例に過ぎない。
:::

###積分区間を100分割したとき###
```
 a := 30.000000
 log(a) = 3.4012114387474641
 Error: 0.0000140570853087
```
およそ4ケタぐらい一致
もっと分割数を増やしてみよう

###積分区間を1000分割したとき###
```
 a := 30.000000
 log(a) = 3.4011973831349214
 Error: 0.0000000014727659
```
今度は8ケタぐらい一致!!
さらに分割数を増やしてみよう


###積分区間を10000分割したとき###
```
 a := 30.000000
 log(a) = 3.4011973816622989
 Error: 0.0000000000001434
```
oh...12ケタも一致している!!!
ただし、計算に数秒くらいかかった。
それにしても組み込み関数のlogではどんなアルゴリズムで計算しているのか気になる......


###End###
Kotlinプロジェクトでどこまでキーを隠蔽化できるか（その1：逆コンパイルを試す）

NCMBではアプリケーションキー、クライアントキーの2つを使ってmBaaSとのデータ送受信を行います。この2つのキーを漏洩させないようにしなければいけません。とはいえ、デコンパイルが容易なAndroidアプリ（apkファイル）の場合、キーを何らかの形で隠す必要があるでしょう。ここでいう漏洩というのは、GitHubなどにAPIキーを載せないという話ではなく、Google PlayなどからDLされたAPKファイルでコードを閲覧できないようにする話になります。

今回はまず、コード中にキーを記載して作成したapkファイルをデコンパイル（逆コンパイル）してみます。なお、今回はmacOSを使っています。

## jedコマンドは使えなくなっています

macOSではdex2jarを使ってdexからclassファイルにするのが基本だったようですが、Big surには対応していません。 `com.googlecode.d2j.DexException: not support version.` というエラーが出ます。

[Releases · DexPatcher/dex2jar](https://github.com/DexPatcher/dex2jar/releases)版を使うことでdex2jarまでは動くのですが、classファイルからjavaファイルへの変換に必要なjedコマンドが利用できませんでした。

```
==> Downloading https://varaneckas.com/jad/jad158g.mac.intel.zip
######################################################################## 100.0%
Error: This cask does not run on macOS versions newer than Mojave.
```

解決策としては `jadx` を使うのが良いようです。

```
$ brew install jadx
```

インストール後、 `jadx-gui` を実行します。

```
$ jadx-gui
```

## apkファイルを見る

実行するとウィンドウが立ち上がるので、Android Studioで作成したapkファイルを指定します。なお、apkxファイルの場合は一旦zipに拡張子を変更後、伸張した中にあるapkファイルを指定します。

![](https://cdn-ak.f.st-hatena.com/images/fotolife/m/mbaasdevrel/20211025/20211025175601.jpg)

そうすると、コードが見られるようになります。もちろん、その中にはコードにハードコーディングしたアプリケケーションキーとクライアントキーが確認できます。

## 注意点：Unityの場合

Unityの場合、Unity自体でコードを難読化処理を行っているようで、ぱっと見ではキーは確認できませんでした。

## まとめ

コードの中にキーをハードコーディングしてしまうと、キーを容易に閲覧できてしまいます。これは大きな問題でしょう。次回以降、このコードを隠蔽化する方法を考えて、試していきます。
iOS15でのジオフェンシングの異常について

#iOS15でのジオフェンシングの異常について
iOS14まで正常に動いていたジオフェンシングが、
iOS15以降、正常動作していないケースがありました。
「iOS15での端末再起動後、アプリ起動するまで、ジオフェンスを検知しない」問題があるようです。

日本語での該当記事が見つからないため、
とりあえずレベルですが、検証してみました。

(2021/12/21 追記)
事象は、iOS15.1,15.2のリリース版では正常なため、修正されたようです。

##海外記事
[ios15 geofencing not working]で検索すると、
いくつかのアプリで、iOS15＋ジオフェンシングの組み合わせで問題があり、
掲示板などで多少、会話がなされているようです。
内容的には、以下のような共通点があります。

- iOS14までは問題なく、iOS15では問題がある
- 端末再起動後、アプリを起動しないとジオフェンスが有効にならない
- iOS15.0.2でも直っていない

[Geofencing problems with iOS15.01]
https://discussions.apple.com/thread/253247480

[Geofencing and iOS15.]
https://www.reddit.com/r/iOSProgramming/comments/q4l4mb/geofencing_and_ios15/

##検証
過去に、ジオフェンシング検証用のアプリを作成していたため、
今回の検証は、それを使用しました。
位置情報取得権限は、「常に許可」で検証しています。

###アプリ起動中のジオフェンス検知

| OSバージョン | 端末 | 結果 |
| --- | --- | --- |
| iOS14.8.1 | iPhone SE (第2世代) | OK |
| iOS15.1 | iPhone XS Max | OK |
| iOS15.2 beta1/2/3 | iPhone 7 | OK |
| iOS15.2 | iPhone SE (第2世代) | OK |
| iOS15.3 beta1 | iPhone 7 | OK |

問題ありませんでした。

###端末再起動後、端末ロック解除状態

| OSバージョン | 端末 | 結果 |
| --- | --- | --- |
| iOS14.8.1 | iPhone SE (第2世代) | OK |
| iOS15.1 | iPhone XS Max | OK |
| iOS15.2 beta1/2/3 | iPhone 7 | NG |
| iOS15.2 | iPhone SE (第2世代) | OK |
| iOS15.3 beta1 | iPhone 7 | OK |

[iOS15.2 beta]のみ異常でした。
端末再起動後は、おかしくなるとの事前情報だったため、
[iOS15.1]でも異常を期待していましたが、修正されたのかも知れません。
[iOS15.2 beta]で異常な理由は不明です。
beta版だからなのか、デグレなのか。

###アプリ起動＞バックグラウンド/タスクキル

| OSバージョン | 端末 | 結果 |
| --- | --- | --- |
| iOS14.8.1 | iPhone SE (第2世代) | OK |
| iOS15.1 | iPhone XS Max | OK |
| iOS15.2 beta1/2/3 | iPhone 7 | OK |
| iOS15.2 | iPhone SE (第2世代) | OK |
| iOS15.3 beta1 | iPhone 7 | OK |

問題ありませんでした。
[iOS15.2 beta]の端末再起動後でも、
ジオフェンシングアプリを起動後は、問題ないようです。

##まとめ
ネット情報と手元の検証結果からの推測になりますが、
「iOS15での端末再起動後、アプリ起動するまで、ジオフェンスを検知しないジオフェンスを検知しない」問題は、
[iOS15.0.0-15.0.2]のバージョンで発生し、
[iOS15.2 beta]でも再発生しているため、
今後も注意が必要のようです。

| OSバージョン | 端末再起動後にジオフェンスを検知するか |
| --- | --- |
| iOS14.8.1 | OK |
| iOS15.0.0 | NG?（ネット情報より） |
| iOS15.0.1 | NG?（ネット情報より） |
| iOS15.0.2 | NG?（ネット情報より） |
| iOS15.1 | OK |
| iOS15.2 beta1/2/3 | NG |
| iOS15.2 | OK |
| iOS15.3 | OK |
Sửa tủ lạnh quận 12 Limosa

Sửa tủ lạnh quận 12 Limosa là một trong những dịch vụ cực kỳ uy tín, chất lượng, được phát hành bởi Trung tâm điện lạnh Limosa. Chúng tôi sở hữu đội ngũ thợ giỏi được đào tạo bài bản và giá cả dịch vụ rẻ hơn mặt bằng chung của thị trường.
Website: https://limosa.vn/sua-tu-lanh-quan-12/					
Phone number: 19002276
Address: Hiệp Thành 10, P. Hiệp Thành, Quận 12, TPHCM

Social network:
https://www.podomatic.com/podcasts/suatulanhquan12limosa
https://www.woddal.com/suatulanhquan12limosa
https://www.allmyfaves.com/suatulanhquan12
https://issuu.com/suatulanhquan12limosa
http://onlineboxing.net/jforum/user/edit/136500.page
https://www.deviantart.com/suatulanhquan12
https://gitlab.com/suatulanhquan12limosa
https://app.gumroad.com/suatulanhquan12
http://www.koinup.com/suatulanhquan12limosa/
https://ro.pinterest.com/suatulanhquan12limosa/_saved/
https://trello.com/suatulanhquan12limosa
https://www.scoop.it/u/suatulanhquan12limosa
https://ub.com.vn/f/members/suatulanhquan12.393896/
https://www.turnkeylinux.org/user/1618432
https://www.codecademy.com/profiles/suatulanhquan12limosa
https://www.eventbrite.com/u/679691848553#profile-following
https://www.quora.com/profile/Limosa-S%E1%BB%ADa-t%E1%BB%A7-L%E1%BA%A1nh-Qu%E1%BA%ADn-12
https://unsplash.com/@suatulanhquan12limosa
https://public.tableau.com/app/profile/suatulanhquan12limosa
https://www.atlasobscura.com/users/2537e9b6-949c-4ce2-af98-1a258153e22d
https://500px.com/p/suatulanhquan12limosa
https://getpocket.com/@96bT4AzTg7c70p08e3d5b7ad07pbg54e885gs1rIkif61cQ1b1b34AHbW44yz3di?src=navbar
https://hubpages.com/@suatulanhquan12limosa
https://www.hatena.ne.jp/suatulanhquan12limosa/config
https://www.plurk.com/suatulanhquan12limosa
https://www.diigo.com/profile/suatulanh_quan12
https://profile.hatena.ne.jp/suatulanhquan12limosa/
https://devpost.com/suatulanhquan12limosa
https://www.intensedebate.com/people/suatulanh_q12
ViewModelでAssistedInjectをするときは拡張関数を作ると便利


ViewModelの初期化時にFragmentから値を渡したいときにAssistedInjectを使いますが、ボイラープレートが増えてしまって非常に煩わしかったりします。そんなとき、以下のExtensionを作ると非常に便利です。

```kotlin
inline fun <reified T : ViewModel> Fragment.assistedViewModel(
    crossinline viewModelProducer: (SavedStateHandle) -> T
) = viewModels<T> {

    @Suppress("UNCHECKED_CAST")
    object : AbstractSavedStateViewModelFactory(this, arguments) {
        override fun <T : ViewModel> create(
            key: String,
            modelClass: Class<T>,
            handle: SavedStateHandle
        ) = viewModelProducer(handle) as T
    }
}
```

使い方は簡単でVewModelにFacotryを定義しつつ、上記Extensionを使ってInjectする感じです。

```kotlin:HogeFragment.kt
@AndroidEntryPoint
class HogeFragment : Fragment() {

    @Inject
    lateinit var factory: HogeViewModel.Factory

    private val viewModel: HogeViewModel by assistedViewModel {
        factory.create(it)
    }
}
```

```kotlin:HogeViewModel.kt
class HogeViewModel @AssistedInject constructor(
    @Assisted private val savedState: SavedStateHandle
) : ViewModel() {

    @AssistedFactory
    interface Factory {

        fun create(savedState: SavedStateHandle): HogeViewModel
    }
}
```

argmentsの値を渡したいときでもFactoryのcreate関数をよしなに書けばうまく動かせます。
Hilt便利！！！
Uncaught Error: If you want to use Reanimated 2 then go through our installation と言われたときの対処法

## 手元の状況
シミュレータを`npx react-native run-ios`で立ち上げた時にsuccessfullyとconsoleに出るものの、画面がレンダリングされると下の画像のようなエラーが出てしまい、キャッシュの削除や`pod install`を試みたが、一向に解消されなかった。恥ずかしながら半日近く潰してしまったのでメモ。


![Simulator Screen Shot - iPhone 13 - 2021-11-05 at 15.29.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1789530/e3545bd8-62ab-452e-3b75-8ca6b277bf7c.png)

## 対処法
とてもシンプルだが、debuggerを立ち上げていたことが原因だった。
`cmd + d`で`stop chrome debugger`を選択。再度シミュレータを起動で正常に起動した。

### 参考にした記事
https://github.com/PedroBern/react-native-collapsible-tab-view/issues/168
【PowerShell】カスタムリストの選択肢列の項目を更新する

Sharepoint カスタムリストの選択肢列の項目を **PnP.PowerShell** を使って更新する方法です。

---

## 関連ページ

**PnP.PowerShell** の使用方法は以下を参照してください。

- [【PowerShell】PnP.PowerShell を使用して SharePoint Online のリストを操作する](https://qiita.com/MakotoIshikawa/private/bdad2292c9078f1709fa)

---

## 選択肢列の項目を更新する

文字列の配列を指定して、選択肢列の項目を更新します。

```powershell:Update-Choices.ps1
<#
.Synopsis
   選択肢更新
.DESCRIPTION
   選択肢の項目を更新します。
#>
function Update-Choices {
    [OutputType([string])]
    Param (
        # XML 文字列
        [Parameter(Mandatory, Position=0)]
        [string] $Xml,

        # 選択肢項目の配列
        [Parameter(Mandatory, Position=1)]
        [string[]] $Items
    ) Begin {
        [xml]$SchemaXml = $Xml
        $Choices = $SchemaXml.CreateElement("CHOICES")
    } Process {
        $Items | % {
            $element = $SchemaXml.CreateElement("CHOICE")
            $element.InnerText = $_
            $Choices.AppendChild($element) | Out-Null
        }
    } End {
        $SchemaXml.Field.AppendChild($Choices) | Out-Null
        $SchemaXml.OuterXml
    }
}
```

### 列を新規追加する場合

```powershell
$ListName = 'List1'

# 列新規追加
$Field = Add-PnPField -List $ListName -DisplayName '果物' -InternalName Fruit -Type Choice -AddToDefaultView
$OuterXml = Update-Choices $Field.SchemaXml @('りんご', 'バナナ', 'みかん')
Set-PnPField -List $ListName -Identity $Field.Id -Values @{ SchemaXml = $OuterXml } -UpdateExistingLists
```

### 既存の列を更新する場合

```powershell
$ListName = 'List1'

# 選択肢更新
$Field = Get-PnPField -List $ListName -Identity Fruit

## 選択肢クリア
[xml]$SchemaXml = $Field.SchemaXml
$SchemaXml.Field.CHOICES.RemoveAll()
[string] $Xml = $SchemaXml.OuterXml.Replace('<CHOICES></CHOICES>', '')

$OuterXml = Update-Choices $Xml @('ぶどう', 'メロン', '梨')
Set-PnPField -List $ListName -Identity $Field.Id -Values @{ SchemaXml = $OuterXml } -UpdateExistingLists
```

---

# 参考サイト

- [Cannot update a option to a choice field · Issue #1846 · pnp/PnP-PowerShell · GitHub](https://github.com/pnp/PnP-PowerShell/issues/1846)
Laravel + LighthouseなGraphQLサーバで新しいスキーマを追加する手順

GraphQL便利ですね！もっと設計したいです。
Laravelで[Lighthouse](https://lighthouse-php.com/)を使った実装を進めていて、新しいスキーマを追加する手順についてまとめました。

今まで多くのスキーマを追加してきましたが、基本的には　`テーブル === モデル === スキーマ`という対応をしています。
そうすることで実装に一貫性をもたせ、スキーマ追加までを手早く行うことができます。
その際の手順についてまとめました。

Sail環境の場合には`php`を`sail`に置き換えてください。

# 1. サーバサイド
1. モデル＋マイグレーション作成
1. スプレッドシート
1. シーダー


## 1.1. モデル＋マイグレーション作成

```console
$ php artisan make:model Post -m
```

```php:2021_11_05_111111_create_posts_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePostsTable extends Migration {

	/**
	 * Run the migrations.
	 *
	 * @return void
	 */
	public function up() {
		if ( Schema::hasTable( env( 'DB_TABLE_PREFIX' ) . 'banks' ) ) {
			return;
	}
		Schema::create('posts', function ( Blueprint $table ) {
			$table->id()->comment( 'ID' );
			$table->string( 'code' )->nullable()->comment( '検索用コード' );
			$table->string( 'name' )->nullable()->comment( 'ポスト名' );
			$table->timestamps();
			$table->softDeletes( 'deleted_at' )->comment( '削除日時' );
		});
		DB::statement( "ALTER TABLE banks comment 'ポスト'" );
	}

	/**
	 * Reverse the migrations.
	 *
	 * @return void
	 */
	public function down() {
		Schema::disableForeignKeyConstraints();
		Schema::dropIfExists( 'posts' );
		Schema::enableForeignKeyConstraints();
	}
}
```

## 1.2. スプレッドシート
Googleスプレッドシートにテストデータを作成しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47327/ffbfe181-b025-b6cd-902e-d7db3f1b05f2.png)


[GSS API](https://gss-api.vercel.app/) を使ってテストデータをJSON化をします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47327/be3b9589-396f-a55f-46d0-d4891c4dee58.png)

```json:/database/seed/Posts.json
[
  {
    "ID": "1",
    "code": "1",
    "name": "投稿タイトル1",
    "created": "2021-11-05 06:09:51",
    "modified": "2021-11-05 06:09:51"
  },
...
```

## 1.3. シーダー
シードクラスを作成して読み込みを行います。

```php:/database/seeders/PostSeeder.php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class BankSeeder extends Seeder {

	/**
	 * Run the database seeds.
	 *
	 * @return void
	 */
	public function run() {
		\App\Models\Post::factory( 10 )->create();
	}
}

```


ここまでできたらマイグレーション等の実行をして試しておきます。

# 2. GraphQL（Lighthouse）
サーバサイドのGraphQLを作成します。

1. スキーマ
1. Query
1. Mutation


## 2.1. スキーマ

```graphql:/graphql/schemas/post.graphql

"投稿"
type Post {
  id: ID!
  "コード"
  code: String
  "投稿タイトル"
  name: String
  "非表示"
  invisible: Boolean
}
```

## 2.2. Query
Queryを書きます。

```graphql:/graphql/query/post.graphql
extend type Query @guard {
  "投稿一覧取得"
  Posts: [Post!]! @paginate(type: CONNECTION)
  "投稿取得"
  Post(id: Int! @eq): Post @find
}
```

## 2.3. Mutation
Mutationを書きます。

```graphql:/graphql/mutation/post.graphql
extend type Mutation @guard {
  "投稿入力"
  mutationPost(input: InputDailyDrivingReport @spread): Post @upsert
}

input InputPost {
  "ID"
  id: ID
  "コード"
  code: String
  "投稿タイトル"
  name: String
}
```

上記でサーバサイドの実装が完成します。
【初心者向け】gRPCとは

##はじめに
REST APIとGraphQLは分かるようになってきて、もう一つAPIの設計で有名なのがgRPCということで、gRPCについて調べてみました。
公式サイトは[こちら](https://grpc.io/)
![grpc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933058/7365609d-2420-9d78-905f-6426aa314d32.png)


##gRPCとは？
RPCを実現するためにGoogleが開発したプロトコルです。
まず、RPCが何なのかを知っておく必要がありますね。

RPCとは、Remote procedure call の略で遠隔手続き呼出しのことです。
分かりやすくいうと、**ローカルのメソッドを実行するのと同じような感覚でリモートサーバのメソッドを実行**できるようになるみたいです。
なので、REST APIのようにパスやメソッドなどを指定する必要がなく、関数と引数を指定することで動作させます。

![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f33333636382f39666338653238302d653138322d363930322d373836342d3633393233383264363461352e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933058/7ca4d0d8-c955-2029-95d8-b89d78125038.png)

##特徴
**★IDL（インターフェース定義言語）を使ってAPI仕様を .proto ファイルとして定義**
protoファイルと呼ばれるIDL(Interface Definition Language)にAPI仕様を記述します。
言語に依存しないIDLで先にインタフェースを定義することで、様々なプログラミング言語の実装を生成できるというメリットがあります。


**★データ量を少なくかつ高速で送信できる**
Protocol Buffers と呼ばれるものを使ってデータをシリアライズして送信します。
シリアライズすることで高速でデータを送信できるようになります。
またHTTP/2が使えるので高速で通信が可能となっています。
[そろそろ知っておきたいHTTP/2の話](https://qiita.com/mogamin3/items/7698ee3336c70a482843)


##終わりに
ここまで見るとgRPCの概要がざっくりと分かりました。
具体的な書き方は扱いませんでしたが、特徴を少しでも分かっておくだけでも面白いですね。

##参考
[gRPCって何？](https://qiita.com/oohira/items/63b5ccb2bf1a913659d6)
[いまさらだけどgRPCに入門したので分かりやすくまとめてみた](https://qiita.com/gold-kou/items/a1cc2be6045723e242eb)
Sync Gatewayデプロイメント：ファイルディスクリプタ設定

※ Couchbase Mobile(Couchbase Lite, Syncgateway)に関する記事について、[こちら](https://qiita.com/yoshiyuki_kono/items/6a5bbad1b02196a25417)も、参照ください。

## 概要
Sync Gatewayで使用可能なファイルディスクリプタの最大数を増やすことは、Sync Gatewayが開くことができるソケットの最大数、したがってSync Gatewayがサポートできるエンドポイントの最大数に直接影響します。

これには、（Sync Gatewayの設定のみではなく）OSのパラメーターを調整する必要があります。

※ここでの説明は、OSとしてCentOSを前提としています。

ここでの設定は単なる例であり、ユースケースに合わせて調整する必要があります。

## OSのファイルディスクリプタ制限変更

ここでは、すべてのプロセスで使用できるファイルディスクリプタの最大数を増やす方法を紹介します。

/etc/sysctl.confファイルを編集します。次の行を追加します。

```BASH
fs.file-max = 500000
```

次のコマンドを実行して、変更を適用します。

```BASH
$ sysctl -p 
```

`-p`オプションにより、再起動後も変更が持続します

## Sync Gateway設定のファイルディスクリプタ制限変更

Sync Gatewayのファイルディスクリプタの最大数を構成します。

構成ファイルの`maxFileDescriptors`プロパティを変更します。

```JSON
{
  "maxFileDescriptors": 250000,
  "databases": {
    "todo": { ... }
  }
}
```

## Sync Gatewayサービスのファイルディスクリプタ制限変更

### systemd設定の場合
`/usr/lib/systemd/system/sync_gateway.service`には、`LimitNOFILE=65535`というハードコードされた制限が指定されています。

これを増やすには、sync_gateway.serviceファイルを目的の値に編集して、サービスを再起動します。

## プロセスのファイルディスクリプタ制限変更

systemdの外部でSync Gatewayを実行している場合は、次の手順を使用します。

1. 1つのプロセスで使用できるファイルディスクリプタの最大数の`ulimit`設定を増やします。

```BASH
$ ulimit -n 250000
```

2. 再起動後もulimitの変更を保持するには、`/etc/security/limits.conf`に次の行を追加します。

```BASH
* soft nofile 250000
* hard nofile 250000
```

3. 次のコマンドを実行して、変更を確認します。

```BASH
$ cat /proc/sys/fs/file-max
$ ulimit -n
```

上記の両方のコマンドの出力値は「250000」になるはずです。


## OSのTCPキープアライブ設定変更

Sync Gatewayで使用可能なファイルディスクリプタの最大数を増やしても、「too many open files (開いているファイルが多すぎます)」というエラーが表示される場合は、TCPキープアライブパラメーターを調整する必要があります。

### 問題を理解する
モバイルエンドポイントとの接続においては、クライアントが接続を閉じることなく、ネットワークから突然切断される場合があります。

デフォルトでは、これらの接続は、Sync Gatewayプロセスのtcp/ipスタックによってデッドであることが検出され、約7200秒（2時間）後にクリーンアップされます。このような接続が蓄積されると、Sync Gatewayで「開いているファイルが多すぎます」というエラーが表示される可能性があります。

### 影響関係を確認する

エラーが表示された場合に、次のコマンドを使用して、Sync Gatewayとの間に確立された接続の数を数えることができます。

```BASH
$ lsof -p <sync_gw_pid> | grep -i established | wc -l
```

上記の方法で確認した値がファイルディスクリプタの最大制限に近い場合は、ファイルディスクリプタの最大制限をさらに高くするか、TCPキープアライブパラメータを調整して、デッドピアがソケットを開いたままにする時間を短縮します。

TCPキープアライブ設定の調整には欠点がないわけではなく、tcp/ipスタックがより頻繁にキープアライブパケットを送信するため、システム全体のネットワークトラフィックの量が増加することに注意が必要です。

### TCPキープアライブ設定変更手順

TCPキープアライブ設定を調整するためには、次の行を/etc/sysctl.confファイルに追加します。

```BASH
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 60
net.ipv4.tcp_keepalive_probes = 20
```

これは次のように解釈されます。

- キープアライブルーチンは、最初のキープアライブプローブを送信する前に、最初に10分（600秒）待機します。
- プローブを1分（60秒）ごとに再送信します。
- ACK応答が20回連続して受信されない場合、接続は切断済みとしてマークされます。

この例では、デッドピア接続がハングアップする時間が（デフォルトの約2時間から）約30分に短縮されます。

さらに時間を短縮するために、`tcp_retries2`の値を減らすことができます。次の行を/etc/sysctl.confファイルに追加します。

```BASH
net.ipv4.tcp_retries2 = 8
```

変更をアクティブにして再起動後も保持するには、次のコマンドを実行します。

```BASH
$ sysctl -p
```



## 関連情報

https://docs.couchbase.com/sync-gateway/3.0/os-level-tuning.html

参照：[Glass Onion Blog - Increasing ulimit and file descriptors limit on Linux](https://glassonionblog.wordpress.com/2013/01/27/increase-ulimit-and-file-descriptors-limit/)
仮想マシンのクローンとテンプレート

## オートスケール
オートスケールは自動で仮想マシンをクローンするというイメージ

## スケールアウト
同じ仮想マシンを複製して、横展開して負荷分散すること

## クローンの使い所
アクセスが増えてきたので、WEBアプリケーションサーバを2台にして負荷分散する、その際に既存のWEBサーバと同じサーバを構築する

## テンプレートの使い所
例えば企業などで社員の仮想マシンを100台作る、といった場合
→仮想マシンを1台作成→テンプレート化（仮想マシンはなくなる）→テンプレートを使って大量生産

### 注意点
テンプレートの設定が間違っていると全ての設定が間違えたことになるため、注意が必要
・データストアのアンマウント忘れ
・不要ファイルの削除漏れ

## カスタマイズ仕様
デプロイするときのルール

## Windowsサーバーのテンプレート作成

![スクリーンショット 2021-11-05 11.54.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/42288665-9999-b75e-c708-1e9b3ff50a19.png)

![スクリーンショット 2021-11-05 11.55.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/0abd6c4f-a79b-4e57-35c5-361f102ef04e.png)

![スクリーンショット 2021-11-05 11.38.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/913ad991-ae30-b01e-f182-d0acb32f6916.png)

新規セキュリティID（SID）の作成はチェックをつける（Windowsだけの項目・Linuxはない）
理由はSIDが重複するとドメイン環境下で不具合が発生するから（もちろんドメイン環境下で使わないなら不要ではあるが、現実ほとんどあり得ない）

```
複数展開する際にはSIDを再生成(変更)する必要がある
Sysprep(初期化プログラム)にてSIDを変更させる
※C:\Windows\System32\sysprepフォルダー配下に保存されています。
```
チェックを入れておくことで、自動でやってくれる

![スクリーンショット 2021-11-05 11.46.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/74fd33c9-920e-71da-f1a8-865b0a8a1322.png)

![スクリーンショット 2021-11-05 11.46.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/25d38033-6039-49b1-ce40-5b8f550f5106.png)

![スクリーンショット 2021-11-05 11.48.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/f805c5d1-6d82-7231-043b-8f9a36f0104f.png)

![スクリーンショット 2021-11-05 11.49.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/5fd50575-c787-0f80-7689-71fffac77a0a.png)

管理者として自動ログインはWindows Serverでは非推奨
（セキュリティがガバガバ）

![スクリーンショット 2021-11-05 11.51.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/dc604068-4d39-c64b-21a3-668b8d5477d9.png)

![スクリーンショット 2021-11-05 11.52.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/bf0e2980-c442-5e03-a076-23f5b33e45cd.png)

ここでスクリプトを指定しておくと、このタイミングで自動でスクリプトが実行される
主に設定するコマンドが多いかもしれない

![スクリーンショット 2021-11-05 11.53.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/870c0fc6-55a3-8f53-9e66-e9a9fd80085a.png)

![スクリーンショット 2021-11-05 11.53.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/1e274bc8-3bf5-1e39-d8bf-860126883971.png)

## 仮想マシンの実態とは？

![スクリーンショット 2021-11-05 12.11.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/ea8a44b2-3cc2-66e0-c778-02f4595f0ef0.png)

データストアを見ると、わかるが、ただのファイルである、それを実行しているだけ。
vMotion

## 前提

ホストの設定でvMotionにチェックが入っていないと使えない
vkernelの設定に追加する
![スクリーンショット 2021-11-05 14.19.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/72e3ebd0-dc24-50ce-58db-b3ef783e3a55.png)

## vMotionとは
仮想マシンを稼働させた状態（ホット状態）で他のESXiホストに移行、移動する機能
![vMotion-520x324.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/2647b714-7bce-7b31-fb19-3bbf237c9831.png)

![vMotion.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/1707ddf3-e44a-5821-365a-0cc580346edb.png)

- ストレージvMotion
    - 仮想マシンを稼働したまま(Hot状態)他のデータストアに移行する機能
- シェアドナッシングvMotion（クロスホスト）
    - 仮想マシンを稼働したまま(Hot状態)他のサーバ、ストレージに移行する機能
    - ホストvMotionとストレージvMotionを同時に行うこと

### マイグレーション
移行、移転、移住、移動、乗換などの意味
ソフトウェアやシステム、データなどを別の環境に移転したり、新しい環境に切り替えたりすること

### ユースケース
計画されたアップデート、メンテナンス
AというESXiホストがアップデートされるからホスト上の仮想マシンをvMotionを使ってBというホストに移動させよう！

## 手順
仮想マシンをvMotionで移行
![スクリーンショット 2021-11-05 14.32.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/20f72899-14b7-d376-cb4c-3a81086fbf94.png)

12から11へ移行する
![スクリーンショット 2021-11-05 14.32.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/8a1a7063-4a51-a16f-9a49-addce4f9601b.png)

互換性のチェックは行う
![スクリーンショット 2021-11-05 14.33.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/c1e5f621-612c-998d-faf9-c948d550f30a.png)

11に移行した
![スクリーンショット 2021-11-05 14.36.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/172a898a-2291-3a31-4234-c443f3fba6e6.png)

ストレージも同様（NFS01からNFS02へ移行）
![スクリーンショット 2021-11-05 14.37.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/56ef5e6a-4f89-d7e0-2704-87e8387e426b.png)
AWSで別アカウントの管理コンソールにロール切り替えで簡単に行き来する

###1.統括するアカウントを準備
IAMユーザーを作成

###2.統括されるアカウントにIAMロールを作成

####ロール名
下記にしておく
arn:aws:iam::xxxx:role/administrator-for-external-access-role
作成の際はユースケースはEC2でOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469267/d1881580-8f51-2604-0158-0e05ca37c0ec.png)

####アタッチするポリシー（一例）
Billing
AdministratorAccess

####信頼関係

**信頼されたエンティティ：**
ロールを引き受けることができるようにしたい統括するアカウントで準備したIAMユーザー
**条件：**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469267/b4ad034b-3085-c0b2-88bd-09d5063a551b.png)

####リンク
下記の部分のリンクに統括するアカウントにログインした状態でアクセスするとロール切り替えができる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469267/107f2b2c-662e-9739-0daa-7144c486aca8.png)

3.ロール切り替えの設定
統括するアカウントにログインした状態で下記にアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469267/807cb94d-6fe2-1e10-e263-fc9a44149eb0.png)
下記の画面に移動するので必要事項を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469267/a1293356-f620-71a1-5d11-933e2f8ad521.png)

**アカウント：**
12桁の番号
**ロール：**
「administrator-for-external-access-role」等ポリシー名
**表示名：**
「ロール履歴」以下に表示される
分かりやすくプロジェクト名が良い
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469267/6ea95a4e-a291-f59c-7890-f270bdfa0621.png)

以上、うろ覚えの為手順に抜け等あるかもです。
選択したキューを止めるキューを作る ADX２ロボット

#なぜ作ったか？
ADX2で音を止める時に、特定のキューのみ止めたい時があります。

#ADX2で音を止める方法
ADX2では
キューを再生したプレーヤーに対してStopを呼べば止められます。

実際、音を止める必要がある場面はそれほど多くないです。

ループの音を管理するプレーヤーを用意して、再生とかでもよいのですが、
基本、再生しかしないシステムにしておくことで、めったに使わない停止を呼ばなくても済ませることができそうです。

# どんな音を止めるのか？

特にループのキューを止める時が多い。
再生時にループがどうか判断するのはなかなか難しいのと
プレーヤーをループ再生を止めるためだけに特別に用意して管理するのは
面倒（どのプレーヤーで、何が鳴っていたかとかなかなか難しい）
なので、キューを止めるキューを作り、
これを呼んでもらうことが多いです。

止めたい音を止められるので、便利です。
（まぁ、再生中の全部の同じ名前のキューの音が止まることになりますが）

# コード
https://gist.github.com/tatmos/86886f94183857fabb1a38fcf314fea9

#実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96808/0e399534-29d3-1291-47a0-a7e4f4c98362.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96808/013ef24b-205c-9401-9661-d7e786680b68.png)


選択したキューをアクショントラックに持つ
ストップアクションを呼ぶキューができます。
sparse_categorical_crossentropyとMIoUの共存

#この記事について
　今回はsparse_categorical_crossentropyを使用した際に評価指標としてMIoUを使用する方法を紹介します。

また、以下のサイトを参考にしております。
サイトによるとtf2.2,tf2.3,tf2.4で問題ないようです。

参考:(https://github.com/tensorflow/tensorflow/issues/32875)
#sparse_categorical_crossentropyとMIoU
　sparse_categorical_crosentropyは多クラス分類に使用される損失関数ですが、評価指数としてMIoUを使用するとエラーが発生してしまうことがありました。確認すると、入力の型が一致していなければならないそうです。

#解決方法
以下のコードを使用することで解決することができます。

```
class UpdatedMeanIoU(tf.keras.metrics.MeanIoU):
  def __init__(self,
               y_true=None,
               y_pred=None,
               num_classes=None,
               name=None,
               dtype=None):
    super(UpdatedMeanIoU, self).__init__(num_classes = num_classes,name=name, dtype=dtype)

  def update_state(self, y_true, y_pred, sample_weight=None):
    y_pred = tf.math.argmax(y_pred, axis=-1)
    return super().update_state(y_true, y_pred, sample_weight)
```
djangoで退会処理の取り消し機能を実装してみる

今回のお題
-
今回は、djangoアプリに退会処理の取り消し（＝アカウントの復旧）機能を実装してみます。

少し調べてはみたものの自分の求めているものが見つからなかったので、とりあえず自分で考えたものを残しておきます。

退会処理そのものについてご存じない方は以下の記事をどうぞ。

https://qiita.com/keishi04hrikzira/items/02a83d85f1ef1b7c5f5d

目次
-
- 今回実装したい機能
- 実装方針
- 実装例
- まとめ

今回実装したい機能
-
今回実装したい機能の仕様は以下の通りです。

- 専用のページにユーザー情報を入力するとアカウントが復旧される。
- 指定されたアカウントが退会済みでない場合には、エラーメッセージが表示される。
- アカウント復旧に関しては権限やログインなどは必要としない。

実装方針
-
以下、今回の実装方針を述べておきます。

- 入力するユーザー情報は`メールアドレス`と`ユーザー名`(将来的にはパスワードに変えたい）。
- ユーザー情報を入力するフォームは`ModelFormクラス`ではなく`Formクラス`を用いる（ModelFormだとユーザーモデルの一意性制約が邪魔になるため）。

フォーム云々の部分に関しては後述します。

実装例
-

まずはフォームを実装します。

```python:forms.py
from django.core.exception import ObjectDoesNotException

class UserActivateForm(Form):
  username = form.CharField(
    label="ユーザー名",
    max_length=30
  )
  email = form.EmailField(
    label="メールアドレス",
  )

  # 入力内容に不備がないかどうかの検証
  def clean(self):
    cleaned_data = super().clean()
    username = cleaned_data.get("username")
    email = cleaned_data.get("email")
    # ユーザー名をもとにユーザー情報を取得できるのかを検証
    try:
      target = CustomUser.objects.get(username=username)
    except (ObjectDoesNotExist):
      raise forms.ValidationError("入力されたユーザー名が間違っています")
    # メールアドレスが正しいかどうかの検証
    if target.email != email:
      railse forms.ValidationError("入力されたパスワードが間違っています")
    # そのユーザーが退会済みかどうかの確認
    elif target.is_active:
      raise forms.ValidationError("このアカウントを復旧する必要はありません")
    return cleaned_data
````
cleanメソッドの中身は3段階に分かれています(cleanメソッドについては[こちら](https://qiita.com/keishi04hrikzira/items/20ffc49844c9a6ec3731)をどうぞ)。

最初のユーザー名の取得の部分だけifではなくtryで条件分岐をかけていますが、これはテーブルに登録されていないユーザー名を入力されるとその時点で`get(username=username)`が失敗してエラーになるからです。

このときに発生するエラーをキャッチして`ValidationError`を返しています。

ちなみに、このときに実際に発生するエラータイプは`DoesNotExist`というものでキャッチしているのはその親クラスである`ObjectDoesNotExist`になるのですが、`DoesNotExist`の方はimportの経路がわからなかったので諦めました。

それから`Modelform`ではなく`form`クラスを採用している理由ですが、これはユーザーモデルのユーザー名に設定されている一意性制約が邪魔になるからです。

ユーザーモデルをもとにしてModelFormクラスを作成した場合、そのフォームに対して`is_valid()`メソッドを用いた時点で一意性制約が発動してしまいます。

しかしフォームの値というのは`cleaned_data`を経由しないと取り出せない＝`is_valid()`メソッドを使わざるを得ないので、ユーザーモデルのバリデーションとは無縁なフォームを新たに用意しているというわけです。

では、フォームが用意できたところでビューを作ります。

```python:views.py
def activate(request):
  if request.method == "POST":
    form = UserActiveForm(request.POST)
    if form.is_valid():
      username = form.cleaned_data.get("username")
      target = CustomUser.objects.get(username=username)
      target.is_active = True
      target.save()
      return render(request, "home.html")
    else:
      return render(request, "active.html")
```

フォームのユーザー名を使って復旧対象のユーザーを探しているだけなので、そこまで難しくないですね。

以上で実装は完了です。

まとめ
-
これでとりあえずはアカウント復旧が行えるようになりました。

今後の目標としてはパスワードを使ったり、登録済みのメールアドレスにワンタイムキーを送ったりして認証できるようにするところですね。

また、今回はフィールドの数が少ない、フォームの内容を保存する必要がないなどの条件が重なったためFormクラスでもそこまでコードが増えなかったという面があります。

もしフィールドの数が多かったりフォームの内容を保存する必要性があったりするのであれば、なるべくはModelFormクラスで完結できる方法を探した方が良いかもしれません。
Firebase × Next.js : Vercel でビルドした時だけinvalid-api-keyエラーが出る時の対処法

## 使用環境

・MacOS BigSur（11.5.2）
・VScode（1.59.1）
・Node.js   (16.1.1）
・React（17.0.2）
・Next.js（11.1.0）
・Firebase(9.1.2)

## はじめに

まず前提の共有ですが、Next.jsでFirebaseのサービス（Auth, Firestore, Storage等）を利用してプロジェクトを作成していました。

さらにNext.jsの諸々の恩恵を得るためにVercelにデプロイにすることにしました。

そして、FirebaseのAPIキーなど諸々の設定を行っていざデプロイという時に下記のビルドエラーが起きました。

```bash
Error [FirebaseError]: Firebase: Error (auth/invalid-api-key).
…以下略
```

調べてもこの環境とエラーに直接該当する情報がなかったため、記事を書くことにしました。

マイナーなエラーかもしれませんが誰かの役に立つことを願っています。

## 結論/解決策

さて、まずは結論からです。

**”コードベースのみでなくVercel側での環境変数の設定が必要”**でした。

詳しく説明しますと、

まずVercelの自分のプロジェクト>Settings> Environment Variables に飛びます。
![スクリーンショット 2021-11-05 14.08.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/711874/bbef07f9-a75b-799f-896b-bd2bb4377be8.png)

そこで、Add Newの入力欄でNAMEとVALUEに設定したい環境変数を入力しAddします。
以下はこの記事の本題であるAPI KEYを設定する例です。
![スクリーンショット 2021-11-05 14.19.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/711874/b5147727-9175-ef07-af98-39503834e2ef.png)


これができたら、そのページの下部に設定した環境変数が追加されています。
![スクリーンショット 2021-11-05 14.27.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/711874/9390cfbc-21a8-6791-afcb-802ad0f56ed2.png)


確認できたら再度デプロイをしてください。



ちなみに、おそらくFirebaseをNext.jsに接続するやり方を学習している方は`.env.local`ファイルを作成して以下のようにNEXT_PUBLIC_で設定しているかと思います。（ここができてないと同じくエラーになります）

```tsx
//firebase.ts(js)

const firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STOTAGE_BUCKET,
  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
};

export const app = initializeApp(firebaseConfig);
```
参考: 

- [Environment Variables - Next.js Document](https://vercel.com/docs/concepts/projects/environment-variables)

- [Zennでのスクラップメモ](https://zenn.dev/hiro__dev/scraps/87e3e70fc82b50)

## 最後に

まとめると、

1. API KEYに間違えはないか？ console.log(firebaseConfig.apiKey)でコンソールに出力されることを確認する
2. firebaseConfigや.env.localの設定に間違えはないか？綴りミスなどに気をつける
3. 上記の通りVercel側で環境変数の設定をしているか？

この点をチェックすると良いかと思います。

何か本記事において疑問点や誤りなどありましたらお気軽にコメントください。
スナップショット

![スクリーンショット 2021-11-05 13.41.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/d304ec34-52f3-3a8e-237f-76e5eafb9d12.png)

仮想マシンにおける静止点を作成する
マスタファイル（vmdkファイル）をロックする
デルタファイル


上記メモリのスナップショットをチェック入れると「電源ON」の状態で静止点作成
スナップショットをチェック入れないと「電源OFF」の状態で静止点作成
例えばメモリ搭載量4GBの仮想マシンであれば、4GB多くストレージ容量を必要とする

![スクリーンショット 2021-11-05 14.00.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/7e12f8c6-653c-09f0-3521-193b487b4f2c.png)

![スクリーンショット 2021-11-05 14.00.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/b9b6ff79-b2ff-3d5d-3203-49aa9818b2d5.png)

![スクリーンショット 2021-11-05 14.03.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/65fe5ab5-d233-c72b-7bd3-8dd836c432a2.png)

デルタファイルが作成された
![スクリーンショット 2021-11-05 14.04.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/6fa106f5-fb44-9c68-c9d8-4fd8a519029b.png)

## テスト
デスクトップに「検証用」というフォルダを作成する

![スクリーンショット 2021-11-05 14.06.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/fb84cd0a-6d40-2dad-da7a-74a4ce3b4a23.png)

![スクリーンショット 2021-11-05 14.06.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/9cb86c54-f7f3-72c0-66e5-bf7618ac36ff.png)

![スクリーンショット 2021-11-05 14.06.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/c7e42a53-9820-d903-5f6f-2a57e1c99e86.png)

確認すると「検証用」というフォルダが消えている
![スクリーンショット 2021-11-05 14.09.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/01a8dc0a-874a-521e-c862-df0d2fb2feab.png)

## 注意点
スナップショットは不要になったら必ず消す
マージに時間がかかるため、放置していたら、放置していた分だけ時間がかかってしまう
KENRO チュートリアルコース

# はじめに
セキュリティ学習のサービスを探していたところ、一部無料になった「KENRO」を見つけました。
そこで、このサービスで脆弱性の基礎を学びたいと思います。

# KENROとは
「KENRO」はWebエンジニアのセキュアコーディング習得を支援するSaaS型eラーニングサービスです。
「資料に目を通して三択問題のテストを受けるだけ」という一般的なeラーニングとは異なり、攻撃者が用いる手法を体験する「ハッキング演習」や、脆弱なソースコードを修正する「堅牢化演習」を通じて、より実践的なトレーニングを一元的に受講できます。
https://flatt.tech/kenro
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2217966/3a3b0a14-ece1-5ab9-513c-9982f4df373e.png)

# チュートリアルコース
KENROの学習コンテンツの流れとしては大きく3つに分類されます。

- テキスト
- ハッキング演習
- 堅牢化演習

演習環境をこちらで事前準備する必要もないし、説明が簡潔で「挫折ポイント」が少ないように感じました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2217966/05ba5849-b205-7b91-bff0-1a2a8a5e8084.png)
そして、「堅牢化演習」により、セキュアコーディングの知見も深めることができるのが素晴らしいと思いました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2217966/eb988fd9-8488-f936-7c0d-456c5ca47187.png)

## コラム: Docker を利用したアプリケーションの起動
ソースコードをローカル環境で動かすために、Dockerを使うことが推奨されてます。
僕は[Docker]を使用経験が浅かったので「KENRO」に記載されているコラムが助かりました。

1. Docker（外部リンク） が動作する環境を準備する。
2. 配布ファイル中の Dockerfile というファイルを用いて Docker イメージをビルドする。
3. ビルドした Docker イメージを起動する。

例えば Docker が動作する環境であれば、ダウンロードしたソースコード中の`Dockerfile` という名前が存在するディレクトリ内で、以下のコマンドを実行することにより、 Web アプリケーションを起動できます。

    docker run -e PORT=8080 -p 8080:8080 -it $(docker build . -q)

また、起動したアプリケーションは `http://localhost:8080` から閲覧できます。

*To Be Continued...*

[Docker]:https://codezine.jp/article/detail/12830
ターミナルでマウスをクリックすると変な文字が入力される場合の対処法

日本語での情報が皆無だったので、自分用メモ書も兼ねて。

##  現象

ターミナルを操作中にマウスでクリックやホイール操作をすると、以下のような変な文字が挿入されてしまう。

キーボード操作は問題なくできる。

```
$ 64;124;15M64;124;15M65;119;14M64;121;15M64;121;15M64;121;15M64;121;15M64;121;15M64;121;15M65;121;15M65;121;15M65;121;15M65;121;15M65;121;15M65;121;15M65;121;15M65;121;15M65;121;15M65;121;15M65;121;15M65;121;15M64;121;15M64;121;15M64;121;15M64;121;15M64;121;15M64;121;15M64;121;15M64;121;15M64;121;15M64;121;15M65;121;15M^C
```

## 解決法

何らかの原因で、vimなどのアプリケーションで用いられるマウスイベントを取得するモードになってしまっているのが原因。

ターミナルにてresetコマンドを実行すれば良い。

```
$ reset
```


## 参考
https://apple.stackexchange.com/questions/329785/when-i-click-on-my-terminal-strange-characters-appear
「.env」ファイルでの環境変数設定

Pythonにおいて、```.env``` ファイルを読み込んで環境変数を設定する方法をまとめておく。
```.env``` ファイルは、***python-dotenv***モジュールを使用することで読み込むことができる。
```.env``` でパラメータを指定することで、ハードコーディングを回避し、再利用性を高く保つことができるメリットがある。

# 使い方
####1. python-dotenvモジュールのインストール
次のように、```pip```コマンドを使用して***python-dotenv***モジュールをインストールすることができる。

```
$ pip install python-dotenv
```

####2.「.env」ファイルを作成する
例として、以下の```.env```ファイルを作成した。

```:.env
DATABASE_NAME = sample.db
```

####3.「.env」ファイルを読み込む
そして、```.env```ファイルを読み込むには、```load_dotenv()```を使用する。これを実行することで、```.env```ファイルに記述された情報が環境変数に設定される。また、環境変数の値を取得するには```getenv(<環境変数名>)```を使用する。もし、該当する環境変数が存在しない場合は、Noneが返される。

```python
# 使用するモジュールをインポート
from dotenv import load_dotenv
import os

# .envから環境変数を読み込む
load_dotenv()

# 環境変数を参照
DATABASE_NAME = os.getenv('DATABASE_NAME')
print(DATABASE_NAME)    # 「sample.db」が表示される
```
R言語とExcelを用いた重回帰分析の方法1

重回帰分析とは、多変量解析のうち複数の説明変数と一つの目的変数が量的なデータの場合に用いることができる解析手法です。

量的データとは数値の大きさや間隔(差)に意味があるデータです。
例えば、身長や体重などが当てはまります。

例えば、下図のように座高、体重、足の大きさから身長を予測するときに重回帰分析を使います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2253181/b8d0739e-2b8b-7530-58bd-a7cf9dd48ac8.png)

この時、重回帰分析によって目的変数(身長)を予測するために導出された式を「重回帰式」と呼びます。
また、データを式に表すことを「回帰する」と言います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2253181/e4d8205a-afb3-501f-73f2-ee377dc212a0.png)

上式によって身長は予測できます。xiは各説明変数で、aiは各説明変数の傾きです。a0は切片です。
ちなみに係数や定数項はモデルパラメータと呼ばれます。

今後、重回帰分析で行うことをまとめました。

無相関検定(R言語)・・・相関係数、統計量t0、散布図

重回帰分析(Excel)・・・重回帰式の導出、重回帰式の検定、
　　　　　　　　　　　　決定係数、偏回帰係数の検定、
　　　　　　　　　　　　多重共線性(マルチコ)、残差グラフ、
　　　　　　　　　　　　標準偏回帰係数

さらに重回帰分析で行うことを図にまとめると下図のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2253181/a090461e-1855-3e21-c43d-80cb5f9f52d4.png)