OmniAICreator/Qiita-1.07M huggingface dataset:
【GitHub】 "Your push would publish a private email address"の解決法

こんにちは！テックアカデミーのWebアプリコース卒業生の駆け出し高校生エンジニア「安田駿介」です。

今回は、「GitHubのプッシュ時 "Your push would publish a private email address"の解決法」というテーマで解説していきます。

#エラーの意味
プッシュをすると、GitHubで設定したプライベートメールアドレスが公開されてしまいます。

#エラーの原因
GitHubの設定で、そのEメールを公開しないという設定をしたからです。

確認方法としては、GitHub➔settings➔Emailsで、「Keep my email addresses private」というところがチェックになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1903726/a2475f79-e9f7-8d80-c8d1-4347ac0e4609.png)

このチェックを外せば、今回の問題は解決しますが、メールアドレスが公開されてしまうため、おすすめはしません。

なので、違う解決策を紹介していきます。

#解決策
１．git update-ref -d HEAD または git reset --soft HEAD^^
２．Emailの変更
３．保存してプッシュ

順番に解説していきます。

##１．git update-ref -d HEAD または git reset --soft HEAD^^
この動作は、commit を取り消す操作です。
これで、git add をした状態まで戻ります。

僕がネットで調べたら、git reset --soft HEAD^^ と実行すれば保存が解除されると書いてありましたが、僕の場合はそれではダメで、git update-ref -d HEADを実行したら、commitが取り消されました。

##２．Emailの変更
GitHub の Setting の Emails，Keep my email addresses privateの文章中に"<数字 8 桁くらい>+<ユーザ名>@users.noreply.github.com"みたいなアドレスがあると思うので，それをコピーします。

そして以下のコマンドで email の config を変更してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1903726/d812825e-a944-49dc-8ab4-7964ea209f17.png)

##３．保存してプッシュ
あとは、 add して commit して push をすれば、できるはずです。

#開発環境
・AWS
・Cloud9
・Ruby 3.0.0
・Rails 6.1.3.1
・GitHub
初心者フロントエンドエンジニアが開発時気をつけていること

Webサイトコーディングのお仕事を始めてから4年ほど経ちますが、「フロントエンドエンジニア」と名乗れるようになったのはここ2年くらいの私です。
「これからフロントエンドエンジニアとして働くぞ！」な方へ向けて、私が開発時に留意していることや気をつけたいことを自戒の念を込めて残していきます。

## デザインを受け取ってから開発に着手するまで
### 画像書き出しの設定を確認
XDでデザインをいただいた時に多いのですが、画像の書き出し権限が無い場合があります。
コーディング中にこれが発覚すると、デザイナーさんに依頼している間作業が止まってしまったり、タイムロスが発生する可能性もあります。
それを防ぐため、デザインデータをいただいた後なるべくすぐ確認するようにしています。

### 繰り返し使えるパーツを探す
個人的にはできるだけCSSを書く量を減らしたいので、繰り返し使える部分は共通パーツ化してしまいます。
お問い合わせボタンやリンク、記事サムネイルなどはなるべく一つのCSSで済むように設計します。
後からデザインに修正が入ったりした場合も、ひとつのCSSを修正すれば良いので手間を減らせます。
「色は違うが形は一緒」などの場合は、バージョン違いとして作成することが多いです。

### 全ページのデザインに目を通し、全体のレイアウトをおおまかに考える
全てのページで同じテンプレートを使用できる場合と、個別で調整が必要な場合が出てくると思います。
一つのテンプレートで済むのであれば一番簡単なのですが、調整が必要なものは早めに把握して設計することで後々崩壊を防ぐことにもなるのではと考えています。

## 開発
### とにかくファイル管理を楽にする
CSSやJSの設計手法はたくさんありますし、人それぞれ好みもあるかと思います。
ですが、**パーツや処理ごとにファイルを分ける**ことで触るファイルが分かりやすくなります。
後から開発にアサインされたり、担当が変わる場合もスムーズにできるのではないでしょうか。
私自身は普段、CSSは**FLOCSS**をベースに設計しており、JSも処理ごとにファイルを分けています。

### 適度にコメントアウトを入れる
どうしても一つのCSSファイルが肥大化してしまったり、JSもコード量が増えてしまったりすることがあると思います。
そういう場合は、他の人が見てもわかるようにコメントアウトを入れます。
特にJSは、「この関数は何をしているのか」が見てすぐ分かるコードの方が読みやすいなと思っています。
基本的に、自分以外の誰が見ても理解できるコードを書くよう心がけています。

### lintツールを入れる
私は元々面倒でlintを入れていなかったのですが、複数人で開発するようになってからはlintの重要性に気づきました。。
lintを導入することで、自分じゃ気づけなかった文法エラーやミスを減らすことができます。

### CSSやJS、画像の軽量化
これは公開後のサイトパフォーマンスに関わってくるので大変重要だと思います。
画像やCSSの圧縮は今では当たり前に行われているかと思いますが、そのほかにも使用していないCSSの記述を削除してくれるパッケージがあったり、webpを使うことで画像の容量を大幅に軽減することもできます。
そういったものを開発環境に組み込んでおくと、サイトの表示速度を早めてパフォーマンスを上げることにもつながります。

## さいごに
まだまだ開発に関して勉強中なので、他にも便利なツールややるべきことはたくさんあると思います。
こまめにそういった情報を集め、実際に使って試してみることで自分の知識・技術にも繋がってくるので、引き続き「もっと何かできないか」を探していきたいと思います。
Picture-in-Picture API と、 webkitPresentationMode の違いについて調べてみた

# これは何？

safari で、ビデオの Picture in Picture をするのに、２つのAPI

* Web 標準： [Picture-in-Picture API](https://www.w3.org/TR/picture-in-picture/)
* webkit 独自: [webkitPresentationMode](https://developer.apple.com/documentation/webkitjs/htmlvideoelement/1631913-webkitpresentationmode)

が利用できるので、その違いについて調べてみた。

# とりま使い方

## Picture-in-Picture API

ボタンクリックに応じて　　toggle するようなケースだと、以下のようなスニペットになる。

```js
if (document.pictureInPictureEnabled) {
  if (document.pictureInPictureElement) {
    document.exitPictureInPicture();
  } else {
    videoEl.requestPictureInPicture();
  }
}
```

* document.pictureInPictureEnabled
    * Picture-in-Picture APIが使えるかどうかを返す boolean
* document.pictureInPictreElement
    * PinP になっている要素があれば true
* [video element].requestPictureInPicture()
    * 該当のビデオ要素を P2P 表示する　
* document.exitPictureInPicture()
    * P2P表示の解除

あとイベントとしてはビデオ要素に対し

* enterpictureinpicture
* leavepictureinpicture

を、それぞれ PinP になったとき/解除されたときに発火してくれる

## webkitPresentationMode

PresentationMode では、 `inline`, `picture-in-picture`, `fullscreen` と 3 つの表示モードを切り替えられる。スニペットで書くと以下のような感じ

```js
if( 
    videoEl.webkitSupportsPresentationMode && 
    typeof videoEl.webkitSetPresentationMode === "function"
  ) {
  btnInline.onclick = () => {
    videoEl.webkitSetPresentationMode("inline")
  }
  btnPinP.onclick = () => {
    videoEl.webkitSetPresentationMode("picture-in-picture")
  }
  btnFullscreen.onclick = () => {
    videoEl.webkitSetPresentationMode("fullscreen")
  }
}
```

全て video要素に対する API となっており、

* webkitSupportsPresentationMode
    * presentation mode に対応しているかを返す boolean
* webkitSetPresentationMode()
    * ビデオ要素に対し、presentation mode を設定する。指定できる値は `inline`, `picture-in-picture`, `fullscreen`

なので、 `webkitEnterFullscreen` と `Picture-in-Picture API` をがっちゃんこしたような仕様となっている。

イベントに関してはモードが変化した際

* webkitpresentationmodechange

を発火してくれるので、この中で、 `webkitPresentationMode` を参照してモードを判定する。スニペットで書くと、

```js
videoEl.onwebkitpresentationmodechanged = () => {
 console.log( videoEl.webkitPresentationMode )
 // `inline` or `picture-in-picture` or `fullscreen`
}
```

といった感じ

## 違い

基本的な動作は一緒だが、以下の違いがある

* 対応する iOS のバージョンが違う
    * `Picture-in-Picture API` の対応は比較的新しく、 [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Picture-in-Picture_API) によると Mobile safari では、　13.4 以降。一方 `webkitPresentationMode` は [9.0 以降](https://developer.apple.com/documentation/webkitjs/htmlvideoelement/1631913-webkitpresentationmode)
* fullscreen にも対応
    * 仕様の紹介のところで書いたように、 `picture-in-picture` 以外にも `fullscreen` に対応している。もちろん、 fullscreen 用途であれば [webkitEnterFullscreen](https://developer.apple.com/documentation/webkitjs/htmlvideoelement/1633500-webkitenterfullscreen) を使えば良いが、 `webkitpresentationmodechanged` で、フルスクリーンが解除されたことをイベント検知できるのは嬉しいところ（ iPhone safari だと、 現状(iOS15) W3C Fullscreen API に対応していないし。あと、 `webkitEnterFullscreen()` を使った場合も、上のイベントは発火してくれる）
* iOS simulatorで Picture-in-Picture API はオフになっている
    * iOS simulator だと、 `document.pictureInPictureEnabled` が false を返し、この API を動かすことはできない。一方、 webkitPresentationMode であれば、メソッドを呼ぶことはできる（ただし、simulator の safari が固まってしまうので、実質的には使えない

てなところ。
Hasuraでテーブルを作成しCRUDの操作までやるで（2/4）

## はじめに

以下のゴールを達成するため、本日は Hasuraの query と mutation を使った基本的な CRUDの操作をやります。

今回は、テーブルを作成し、データをInsertするところまでやっていきます。

## 最終的なゴール

以下のような構成のアプリを作ることです。

![スクリーンショット 2021-10-18 17.27.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/e8a9a2e1-2723-4fec-77ef-be3b9eefdd81.png)

### 目的

- 仕事で使っている技術のキャッチアップと復習
- 使う可能性がある技術の理解度向上

## テーブルを作成する

前回は、Hasuraのアカウント作成からDB作成までやりました。

では、早速、テーブルを作っていきます。

Create Tableをクリック

![Schema_-_Data___Hasura.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/45929ec2-7b24-fd27-1e06-e925a1c87c79.png)

### 試しにユーザーに関する情報「Users」というテーブルを作ります

テーブル作成の経験があれば、違和感ないと思います。

![Add_Table_-_Data___Hasura.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/2be8d6cd-acb8-ba16-966d-54dcc3bb9ba7.png)

赤枠以外は、何も変えてません。

このまま、Add Tableします。

## 新設したusersテーブルにデータを追加

無事、テーブルができたら、実際にデータを追加していきましょう。

![Insert_-_users_-_Data___Hasura.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/89e3579e-1eab-02fe-40a7-82edf10a901d.png)

`id`と`created_at`は自動的に割り振られるので、`name`だけ適当にデータを入れます。

### Insertしたデータの確認

Browse Rowsすると、Insertしたデータが格納できます。

![Browse_-_users_-_Data___Hasura.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/9aa9de0f-19c2-8f89-13ba-0da48d92fd9b.png)

できましたね！:relaxed:

次回は、このデータに対して、GraphQlで `query`や`mutation`を書いて、データを操作していきます！

## アウトプット100本ノック実施中

https://qiita.com/ryosuketter/items/713474dbd009870e4103
rakeファイルをRSpecでテストする

##環境
Ruby 3.0.2
Rails 6.1.4.1

##設定

```spec/rails_helper.rb
...
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }
...
```

```spec/rake_helper.rb
require 'rake'
require 'rails_helper'

RSpec.configure do |config|
  config.before(:suite) do
    Rails.application.load_tasks
  end

  config.before(:each) do
    Rake.application.tasks.each(&:reenable)
  end
end
```

spec下にファイルを作成し、いつものようにテストを書いていく。

```spec/lib/tasks/XXXXX_spec.rb
require 'rake_helper'

describe 'XXXXX:XXXXXXX' do
  ...
end
```

##注意

rake_helper.rbの```require 'rails_helper'```を書いてなかったりrails_helperの設定をしていないと下記のエラーになる。

```
Failure/Error: Rails.application.load_tasks

NameError:
  uninitialized constant Rails
```

##参考

https://qiita.com/aeroastro/items/c97bd26ce8b8818b6bed
[2次元累積和] 平面上の任意の長方形の範囲にある点の数え上げ


2次元累積和を利用して平面上にある点の個数の数え上げ問題を解く。

## 問題

2次元平面上に複数の点が存在する。
iが[4,7]かつjが[3,7]の長方形の範囲（黄色の範囲）に存在する点の数を求めよ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102448/8238c07a-5004-c8f2-f005-16bd8beb0cc5.png)

## 1次元で考える

x軸上に複数の点が存在する。
{4, 6]の範囲に存在する点の数を求めよ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102448/26299ac6-e518-a10f-ea32-01074363c1a8.png)

この問題を解くにはまず配列に点を格納する。配列をAとする。

```
A = [0 0 0 1 1 0 1 1]
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102448/c7903a19-df34-5b5d-416d-0c5c4703c811.png)

次に累積和を計算する。このときの配列をSとする。
0からiまでの合計をS[i+1]に格納することとする。

```
S[i+1] = A[0] + A[1] = ... + A[i]
S = [0 0 0 0 1 2 2 3 4]
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102448/8531fb8a-aab7-b72b-b5cd-5eb0ab507969.png)


xが[i,j]の範囲に存在する点の個数は下記の式で求めることができる。

```
A[i..j]の合計 = S[i+1] - S[j]
3から6にある要素の合計 = S[7] - S[4] = 3 - 1 = 2
```

## 考え方を2次元に拡張

問題の2次元座標を2次元配列上にマッピング。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102448/b47e5894-89e8-57b4-e587-4d12d131ee4f.png)

2次元平面上で累積和を計算する。下記のDPを使って計算が可能

```
S[i+1][j+1] = S[i+1][i] + S[j][i+1] - S[i][j] + A[i][j]
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102448/e7fa7305-37f3-612b-495b-b33eec0866d2.png)


1次元と同じように累積和から任意の範囲を計算する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102448/8e52d2c3-4db3-8781-02a2-8c4ed0cc492f.png)


S[8][8]は平面全体の点の個数となる。
S[4][8]は黄色の範囲における点の個数。
S[8][3]は赤色の範囲における点の個数。
S[4][3]は黄色と赤色のが重なる範囲の点の個数。

よって今回の問題は下記の式で解くことができる。

```
S[8][8] - S[4][8] - S[8][3] + S[4][3] = 6 - 2 - 1 + 1 = 4
```

## 実装

```cpp
// 2次元配列matrixから累積和配列を作成する。
for (int i=0; i<n; i++) {
    for (int j=0; j<m; j++) {
        // 累積和配列はDPを使って構築することが可能
        sum[i+1][j+1] = sum[i+1][j] + sum[i][j+1] - sum[i][j] + matrix[i][j];
    }
}

// i>i2且つj>j2のとき、[i,j]と[i2,j2]の範囲にある合計は下記で計算可能。
int area = sum[i+1][j+1] - sum[i+1][j2] - sum[i2][j+1] + sum[i2][j2];
```

## 関連問題

[典型90 081 - Friendly Group（★5）] (https://atcoder.jp/contests/typical90/tasks/typical90_cc)
PHPでアルゴリズム体操〜クイックソート編〜

## はじめに
完全に乗り遅れてますが、今話題のクイックソートをPHPで実装してみます。
PHPに組み込みのsort関数があるのはもちろん知ってます。

## クイックソートの概要
クイックソートというのはソートのアルゴリズムの１つで、他のソート法より計算量が少なく高速にソートを行えます。（厳密には他のソート法と同じ計算量になる場合もあります。）
クイックソートのロジックについては調べれば分かりやすい説明がたくさん出てくるので、今回書いたコードの簡単な手順をざっくりまとめておきます。

1. 配列の要素が１つの場合は、それを返す。
1. 配列の中からピボット（軸となる要素）を適当に決める。
1. その要素より大きいグループと小さいグループに分ける。 （ピボットと同じ大きさのものはどちらかに）
1. 各グループで1,2,3を再帰的に繰り返す。
1. 4の結果を小さいグループ、最初のピボット、大きいグループの順に並べる。


ところでPHP組み込みのsort関数は、どうやら内部クイックソートを行っているようです。
>注意: PHP の大半のソート関数と同様、sort() は » Quicksort でそれを実装しています。 ピボットは、既にソート済みの部分に対して時間的に最適なところを選択します。 しかしこれはあくまでも内部の実装の話なので、これに依存したコードを書いてはいけません。

[PHP: sort - Manual ](https://www.php.net/manual/ja/function.sort)より

## 実行環境
PHP 8.0.11

## 実際にやってみた

```php
/**
 * quick sort
 * @param array<int, int> $numbers
 * @return array
 */
function quickSort(array $numbers): array
{
    // 要素数が１つの場合は並び替え不要
    if (count($numbers) < 2) {
        return $numbers;
    }
    // 先頭の要素をピボットとして取り出す。
    $pivot = array_shift($numbers);

    // 初期化
    $left = [];
    $right = [];

    // 要素の大きさがピボット以下のものと大きいものとでわけっこ
    foreach ($numbers as $num) {
        if ($num <= $pivot) {
            $left[] = $num;
        } else {
            $right[] = $num;
        }
    }
    // それぞれで再帰的に処理を繰り返す
    $left =  quickSort($left);
    $right = quickSort($right);
    return array_merge($left, [$pivot], $right);
}
```

一応テストも

```php
public function testQuickSort(): void
{
    $this->assertSame(
        [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
        quickSort([9, 1, 8, 2, 7, 3, 6, 4, 5, 10])
    );
    $this->assertSame(
        [2, 3, 3, 4, 4, 5, 5, 6, 7, 10],
        quickSort([3, 4, 5, 2, 7, 3, 6, 4, 5, 10])
    );
}
```

```
OK (1 test, 2 assertions)
```

無事通りました。

ちなみにピボットをどのように選択するかで、計算量が変わってくるようです。
今回は先頭の要素をピボットにしてますが、計算量を考慮したときにどうやら悪手みたいですね。他のピボットの選択方法としては、

- 配列から要素を複数ランダムに選び、それらの中央値をピボットにする
- ランダムに選ぶ（人為的に最悪ケースになるのを防げる）

等があるようです。
また、与えられた配列を処理の前にランダムに並び替えることによって計算量が最悪のケースになる可能性を抑えることもできるようです。

PHPのsort関数では、この辺りの最適化もやってくれているようですね。

※参考：[クイックソート - Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88)



## さいごに
組み込み関数への感謝を忘れない。
簡単にSSHでAWSサーバーに接続する方法

#SSH を使用して接続するには

macはターミナル、winの場合はTera Termを使います。

まずはpemファイルの権限の変更が必要です。
600が推奨されてます。フル権限だとエラーが出ます。

```terminal:ターミナル
chmod 600 /path/to/my-key-pair.pem
```
chmodコマンドで権限を変更します。

その後、下記のsshコマンドでアクセス出来ます。

```terminal:ターミナル
ssh bitnami@xxx.xxx.xxx.xxx -i /path/to/my-key-pair.pem
```
簡単に説明すると、
ssh ユーザ@サーバIP -i pemファイルのパス
画像ビューワー、ボタン操作、JSONで保存　＃メモ


WSLで実行する場合は下記参照
https://dev.classmethod.jp/articles/wsl-x-window/

```

# -*- coding: utf-8 -*-
import cv2
import glob
import json

target = "target/*.png"
print("target:"+target)

data_BasePath = sorted(glob.glob(target))
print("target:"+target)

data_BasePath = sorted(glob.glob(target))
print("image Num:"+ str(len(data_BasePath)))

yesno_dict={}
# for idx_inter, data_BasePath_png in enumerate(data_BasePath): 
idx_inter = 0
while True:
    data_BasePath_png = data_BasePath[idx_inter]
    # 入力画像のロード
    img = cv2.imread(data_BasePath_png)
    img = cv2.resize(img, (img.shape[1]*4, img.shape[0]*4))
    cv2.imshow("input", img)

    k = cv2.waitKey(0)
    if k == 27:         # wait for ESC key to exit
        break
    elif k == ord('y'): 
        imgbool = "1"
    elif k == ord('n'): 
        imgbool = "0"
    elif k == ord('p'): 
        idx_inter = idx_inter - 2
    else:
        idx_inter = idx_inter - 1

    print([data_BasePath_png, imgbool])
    yesno_dict[data_BasePath_png] = imgbool
    idx_inter = idx_inter + 1

print(yesno_dict)

cv2.destroyAllWindows()

tf = open("myDictionary.json", "w")
json.dump(yesno_dict, tf)
tf.close()

```
Windows10でssh使うときに"Bad owner or permissions on"と表示される問題の対処法

#状況
windows10からubuntu serverにconfigファイルを作成してSSH接続しようとすると以下のメッセージが出た．

```
Bad owner or permissions on C:/users/***/.ssh/config
```

#結論
configファイルに別アカウントのアクセス権限が存在し，削除したら解決した．

#詳細
configファイルを右クリック→プロパティ→セキュリティタブ→詳細設定→継承の無効化→画像の上の項目を選択→自分以外のアカウントを削除
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146295/9a2551ce-d386-21f4-5e73-d9488dc565d0.png)
これで動いた

#このメッセージが起こりそうな人
使用しているパソコンが共用のもので他の人のアカウントもあるとき．

#参考
[openssh windows bad owner or permissions](https://stackoverflow.com/questions/49926386/openssh-windows-bad-owner-or-permissions)
[読書記録]コンサル一年目が学ぶこと

約3時間をかけてざっくり読み終えた一冊。
職歴10年以上の私にとっては、当たり前のことが並んでるように見えるが、
中にはできていなく再考する価値があるものもあったので、読んでよかったです。

## 1. 話す技術

結論から話す。PREP法：

* Point : 結論
* Reason : 理由づけ
* Example : 具体例
* Point : 結論の繰返し

報告書、メール、会話、会議の運営、すべて結論から。

Talk Straight（端的に話す。率直、簡潔に話す。）

数字とロジックで語る。

相手の理解度を推し量りながら話す。

相手の期待値を把握し、相手の期待を超え続けることがビジネスの基本。
ときには、相手の期待値を下げる期待値マネジメントも必要。

## 2. 思考術

アプローチ、考え方、段取りの部分を最初に考え、合意を取る。

ロジックツリーを使いこなす。

事実、解釈、アクションを区別する。
空・雨・傘の論理：「黒っぽい雲が出てきたので、雨が振り出しそうだから、傘を持っていったほうがいい」

仮説思考。仮説、検証、フィードバックのサイクルを高速で回す。

常に自分の意見をもって情報にあたる。

本質を追求する思考。情報ではなく、本質を提示する。

## 3. ディスクワーク技術

議事録：決定事項、課題、TODO

パワポ：One slide, One message.

エクセル、パワポは、作成スピードが勝負。

最終成果物から逆算して、作業プランを作る。

コンサル流検索式読書術：読書目的の明確、重要な部分だけ読む、なるべく多くの文献を広く浅く当たる。

仕事の速さを2倍3倍にする重点思考：余計なことをやらない。

課題管理表：番号日付、タイトル、課題の内容、解決の方向性、ステータス、担当、期限

## 4. ビジネスマインド

Valueを出す。他人に貢献することを仕事のゴールにする。

しゃべらない会議は出るな。会議で発言しない人の価値はゼロ。

「時間はお金」と認識する。

プロフェッショナルとして振る舞う。

スピードと質を両立する。時間をかけて完璧なものを目指すよりも、とにかく早く作る。

コミットメント力を学ぶ。一度約束したことは、何があってもやり遂げる。

師匠を見つける。言語化できない暗黙知の部分を師匠から徹底的に真似よ。

フォロワーシップ：リーダーの提案をサポートするために周りを巻き込み、必要なことを考え、自主的に動く。

プロフェッショナルのチームワーク：全員がそれぞれの価値を発揮して、プロジェクトに貢献する。
GA4でサイト内のリンククリックイベントを計測する

# 背景
Google Analytics 4 で自動収集されるイベントの`click`では、[公式ドキュメント](https://support.google.com/analytics/answer/9216061?hl=ja&ref_topic=9756175) にある通り、離脱クリックのみが計測される。
つまり、GTMを配信しているページ間のリンククリックは`click`では収集できず、ヘッダーとフッターどちらにもリンクを貼った場合など、page_viewイベントだけではどちらのリンクからの遷移かがわからない。

そこで、サイト内のリンクをクリックしたイベントをGA4で計測できるよう、GTM側でイベント`in_domain_click`を作成した。
idも紐づくので、配置したリンクごとに集計ができるようになった。

GA4, GTMいずれもまだまだ勉強中で、もっとよい方法があればコメントよろしくお願いします。

## 作業

手順は以下のとおり。なお、GA4タグはすでに公開済みとする。

1. イベントのトリガーを作成
1. イベントのタグを作成
1. 作成内容をプレビュー

## イベントのトリガーを作成

GTMの管理画面に入り、トリガー > 新規より、クリックイベントをトリガーとして保存する。
今回はすべてのリンククリックを対象とした。

![スクリーンショット 2021-10-18 17.31.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890544/53e7dbd9-cc87-2c3b-af7c-ba51d4f908b0.png)

## イベントのタグを作成

GTMの管理画面に入り、タグ > 新規より、GA4イベントタグを保存する。
各種設定については以下のとおり。

* 設定タグ：GA4設定タグの名称
* イベント名：任意（もともとあるイベント名と重複しないほうが良い）
* イベントパラメータ
    * link_url: リンク先のURL
    * link_text: リンクのテキスト内容
    * link_id: リンクのid
* トリガー：上記で作成したトリガー

![スクリーンショット 2021-10-18 17.34.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890544/78120e42-30d6-951e-17c0-b088ad7eaf66.png)


## プレビュー

以下をプレビューで確認したのち、GTMを公開する。

* Link Click時に Tagsタブで タグが発火しているか
* Link Click時に Variableｓタブで `Click ID`, `Click Text`, `Click URL`が取得できているか


# GA4でイベントを確認

UIがよく変わるので 2021/10現在。

レポート > ライフサイクル > エンゲージメント > イベント　から設定したイベント名があることを確認。
イベント名をクリックすると、イベントパラメータも参照できる。
Swift URLで、日本語URLに対応する

# 概要

URLが表現された文字列をSwift URLクラスにする場合、

```swift
let url = URL(string: "https://qiita.com")
```

のような書き方をすると思います。
これでURLの処理をしていくことになります。

しかし、日本語が含まれるURL、例えば、
総務省のWikipedia https://ja.wikipedia.org/wiki/総務省
なんかだと、

```swift
let url = URL(string: "https://ja.wikipedia.org/wiki/総務省") 
print(url) // nil
```

このように日本語のURLはnilになります。
なので、これを日本語URLに対応するようにします。

## URLComponentsで日本語URL対応する

日本語URL対応のためURLComponentsを使います。

https://developer.apple.com/documentation/foundation/urlcomponents

ドキュメントにも書いてありますが、URLComponentsの`path`や`query`などのプロパティは、パラメータをセットするとそれぞれのコンポーネントに合わせたパーセントエンコーディングをしてくれます。

もともとのURL文字列からの各種コンポーネント取り出しは`NSRegularExpression` を使っての正規表現でがんばります。
以下はpathやqueryに対応したコードになります。
正規表現でグループ化したコンポーネントは`NSTextCheckingResult.range(at:)`でそれぞれ取り出し、URLComponentsのhostやpathに渡してます。

```swift
extension URL {
    init?(urlString: String?) {
        guard let urlString = urlString,
              let regex = try? NSRegularExpression(pattern: #"^(.+?)://(.+?):?(\d+)?(/[^\?]*)\??(.*)?$"#, options: .init()),
              let ret = regex.matches(in: urlString, options: .init(), range: .init(location: 0, length: urlString.count)).first
        else {
            return nil
        }
        var component = URLComponents()
        if let range = Range(ret.range(at: 1), in: urlString) {
            component.scheme = String(urlString[range])
        }
        if let range = Range(ret.range(at: 2), in: urlString) {
            component.host = String(urlString[range])
        }
        if let range = Range(ret.range(at: 4), in: urlString) {
            component.path = String(urlString[range])
        }
        if ret.range(at: 5).length > 0,
           let range = Range(ret.range(at: 5), in: urlString) {
            component.query = String(urlString[range])
        }

        if let url = component.url {
            self = url
        } else {
            return nil
        }
    }
}
```

こうすることで、パーセントエンコーディングされたURLが作成でき、処理が可能になります。
fragmentなどには対応していないので、各自アレンジしてください。

```swift
let url = URL(urlString: "https://ja.wikipedia.org/wiki/総務省") 
print(url) // https://ja.wikipedia.org/wiki/%E7%B7%8F%E5%8B%99%E7%9C%81
```
【Qiita】Qiitaの記事作成

###概要
Qiitaでアウトプット!!
と思ったのですが、そもそもQiitaって独自の書き方があるんだ…とのことで
自分なりにこの件についてまとめてみました。
 （＊あくまで最低限の部分。）

###目次
* まずはここから（Qiitaガイドライン）
* Markdown記法とは
* 目次
* 見出し
* 文字の装飾
* コードの挿入
* 表
* 参考記事について
    * リンク（URL）
    * 引用

###まずはここから（Qiitaガイドライン）
[Qiitaガイドライン](https://help.qiita.com/ja/articles/qiita-article-guideline)
（結局公式ページが一番強い説）

###Markdown記法とは

>「書きやすくて読みやすいプレーンテキストとして記述した文書を、妥当なXHTML（もしくはHTML）文書へと変換できるフォーマット」として、2004年にジョン・グルーバーにより作成された。
(Wikipediaより引用 https://ja.wikipedia.org/wiki/Markdown)

＝　マークアップ言語「Markdown」におけるテキスト文書の書き方やルール。
htmlのタグも使えて、覚えなきゃいけないルール自体は至ってシンプル。

[Markdown記法 チートシート](https://qiita.com/Qiita/items/c686397e4a0f4f11683d)


###目次
方法：　- を使用。 
　　　　tabを使うと、階層構造にできる。

記述方法

```
- まずはここから（Qiitaガイドライン）
- Markdown記法とは
- 見出し
- 目次
- 文字の装飾
- コードの挿入
- 表
- 参考記事について
    - リンク（URL）
    - 引用
```

表示

- まずはここから（Qiitaガイドライン）
- Markdown記法とは
- 見出し
- 目次
- 文字の装飾
- コードの挿入
- 表
- 参考記事について
    - リンク（URL）
    - 引用



###見出し
方法：　#を使用。
    \#の数によって、見出しの大きさが変わります。


記述方法

```
#見出し1
##見出し2
###見出し3
####見出し4
#####見出し5
######見出し6
```

表示

#見出し1
##見出し2
###見出し3
####見出し4
#####見出し5
######見出し6


###文字の装飾
####イタリック（斜体）
**\*(アスタリスク)**もしくは**_(アンダーバー)**1個で文字列を囲む

記述例
\*hello\*

表示例
*hello*

####太字
**\*(アスタリスク)**もしくは**_(アンダーバー)**2個で文字列を囲む

記述例
\*\*hello\*\*

表示例
**hello**

####打ち消し線
**~(チルダ)**2個で文字列を囲む

記述例
\~\~凡ミス\~\~

表示例
~~凡ミス~~




###コードの挿入
コードを載せたいときは、バッククォーテーション3つ(｀｀｀)で囲む 

記述方法

\`\`\`
date “+%Y/%m/%d (%a)”:
2021/10/18 (Mon)
 \`\`\`

表示


```
$ date “+%Y/%m/%d (%a)”
2021/10/18 (Mon) 
```



###表
方法：
①「 | 」で囲んで、ヘッダーを作成
 ②次の行で、「 : 」の位置で左寄せ、右寄せ、中央寄せを決定         
③「 | 」で囲んで、テーブル内容を作成

記述方法

```
|     　中央寄せ　     |　     　　右寄せ| 左寄せ　　　    |
|:----------------:|------------------:|:-------------------|
| Aaa             |              Aaa |        Aaa        |
| Bbb           |            Bbb |       Bbb       |
| Ccc             |              Ccc |        Ccc        |
```


表示
|     　中央寄せ　     |　     　　右寄せ| 左寄せ　　　    |
|:----------------:|------------------:|:-------------------|
| Aaa             |              Aaa |        Aaa        |
| Bbb           |            Bbb |       Bbb       |
| Ccc             |              Ccc |        Ccc        |





###参考記事

リンク（URL）
方法：　[表示させたい文字列](移動先のurl) 

記述方法

```
[ITmediaNEWSのページ](https://www.itmedia.co.jp/news/)
```

表示
[ITmediaNEWSのページ](https://www.itmedia.co.jp/news/)



引用
方法：　> を使用  。
　　　　>>　を使用すると二重引用。
 二重引用から引用に戻すには、改行が一回必要。


記述方法

```
>引用
>>二重引用
>まだ二重引用の状態

>二重引用の解除
```

表示
>引用
>>二重引用
>まだ二重引用の状態

>二重引用の解除




###まとめ
あくまで自分の記録用の意味合いが強いですが、とりあえずQiitaデビューとして最低限のところをまとめてみました。 
私のような初心者の方のお役に立てたら幸いです…。
 もっと見やすい記事にする方法もあるようなので、随時レベルアップ・追記していければと思います。 これでQiitaに投稿できるぞー！！
キーワード検索とタグ検索機能の両立

#前提
キーワード検索機能
GeekSalon教材7-1

タグ検索機能
https://qiita.com/MandoNarin/items/5a5610a40c66f77d6c10

以上を実装済み

#コード

```posts_controller.rb
def index
  @posts= Post.all
  @tags = Tag.all
  @posts = @posts.where("body LIKE ? ",'%' + params[:search] + '%') if params[:search].present?
  #もしタグ検索したら、post_idsにタグを持ったidをまとめてそのidで検索
  if params[:tag_ids].present?
    post_ids = []
    params[:tag_ids].each do |key, value| 
      if value == "1"
        Tag.find_by(name: key).posts.each do |p| 
          post_ids << p.id
        end
      end
    end
    post_ids = post_ids.uniq
    #キーワードとタグのAND検索
    @posts = @posts.where(id: post_ids) if post_ids.present?
  end
end
```

以上で完成。
#おまけ
ちょっとリファクタリングしてみる
ロジックは同じ

```posts_controller.rb
def index
  @posts= Post.all
  @tags = Tag.all
  post_ids = []

  @posts.where!("body LIKE ? ",'%' + params[:search] + '%') if params[:search]

  if params[:tag_ids]
    params[:tag_ids].each do |key, value| 
      Tag.find_by(name: key).posts.each { |p| post_ids << p.id } if value == "1"
    end
    post_ids.uniq!
    @posts.where!(id: post_ids) if post_ids.present?
  end
end
```
だいぶ短く、わかりやすくなった！

####軽く解説
気になる方はググってみてください！

- ""とnilは偽と判断されるため、.present?は不要
- パラメーターを``" "``(スペース)などで送る場合は.present?は必要
- ``[]``(空配列)は真と判断されるのでpost_ids.present?は必要
- if文は後ろに置ける。（end不要）
- ネストはなるべく浅くする
- ``do end``は``{}``と同じ
- ``<<``は配列の要素の追加
- !が後ろにつくメソッドは破壊的に変数を変更できる
- 変数の定義は最初にまとめて置いた方がわかりやすい
そのバックアップ、リストアしたことありますか？

## リストアできないバックアップはしてないのと一緒
「バックアップは重要です」
よくいわれますよね。
様々な手段でバックアップしていると思います。システム、ソースコード、データなどなど。
でも、それリストアしたことありますか？
##防災訓練の時に一緒にリストア テストやっちゃいましょう
クラウドならリストアの練習にも大きな費用はかかりません。以外と思った通りのリストアできないバックアップって少なくないですよ。また、リストアの手順は属人化しないように。あなただけがリストアできるみたいなことはバックアップにならないこと説明されなくてもわかりますよね。
##RPO、RTOをあわせて考える
技術者ではない人に、RPOとかRTOとか言っても通じないと思いますが、「目標復旧時点」「目標復旧時間」という言葉をつかってしっかり説明しましょう。その上で、**無理しない**RTO、RTO設定ししましょう。とちらも短くするにはそれなりに費用がかかります。
##地理的冗長も考える
バックアップを同一ビルに保存するとかしていないですよね？ビル火事になったらどうなるのか考えてましょう。このあたりも、技術者ではない人にも説明しておくべきことです。もちろん、ビル火災中にも止まらないようにするには、それなりの予算をかけたシステム構成が必要です。
JavaScriptのclass

# はじめに
初学者です。
基本は備忘録

# classってなに？
よく例えられるのは設計図
class(設計図)からinstance(設計図をもとに作った物)を生成する

# JavaScriptにおけるclass
*JSにおけるclassはコンストラクター関数をclass表記で書けるようにしたもの*
すでにある機能を簡単に書けるようにしたものをシンタックスシュガーという

---
*class*

```js
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  hello() {
    console.log('hello ' + this.name);
  }
}
```

*コンストラクター関数*

```js
function Person(name, age) {
    this.name = name;
    this.age = age;
}

Person.prototype.hello = function() {
  console.log('hello ' + this.name);
}
```
classとコンストラクター関数は表記方法は違うが、やっていることは同じ
*ES6からclass表記が主流なので基本的にはclassを使う*

# インスタンスの作り方

new演算子を使ってインスタンスを生成する

```js
class Person {
  constructor(name, age) {
    this.name = name,
    this.age = age
  }
}

const tom = new Person('Tom', 18);
```

# インスタンスってなにがいいの？
*コードの量が少ない*
*メソットはprototypeの参照先をコピーして全てのインスタンスで使い回せるので余計なメモリを消費しない*
**メソット定義方法**

```js
class Person {
  constructor(name, age) {
    this.name = name,
    this.age = age
  }
  
  hello() {
    console.log('hello ' + this.name)
  }
}
```
コンストラクターと同じスコープに記述する



# クラス継承
他のクラスのプロパティーとメソットを継承すること

```js
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  hello() {
    console.log('hello ' + name)
  }
}

//extendsでPersonを継承できる(prototypeも含めて継承する)
class Japanese extends Person {
  constructor(name, age, gender) {
    //引数を固定thisはデフォルトでJApaneseのthisを固定
    super(name, age);
    this.gender = gender;
  }

  hello() {
    console.log('konnichiwa ' + this.name)
  }

  bye() {
    console.log('konnichiwa ' + this.name)
  }
}

const bob = new Japanese('Bob', 18, 'male')
console.log(bob)
//superはclass専用(superがないとエラー)
//superが実行されるとPersonのconstructor
//部分が実行される。その後Japanese専用のプロパティが実行
//prototypeの継承はextendsによって実現されている
```

# super

継承元の関数を呼び出すためのキーワード
*superは大抵の場合classのconstructor内で継承元のconstructorを呼び出す際に使われる*
制約がある
~~1つ前のコードのclass Personがある程で書いてます~~

```js
class Japanese extends Person {
  constructor(name, age, gender) {
  this.gender = gender;
  super(name, age);
  //superの前にthisを参照することはできない。この場合エラーになる
  }
  
  hello() {
    //継承元のメソットを呼び出すこともできる
    //メソットとして呼ぶ場合はthisを先に参照していても問題はない
    super.hello();
    console.log('ハロハロー')
  }
}

```

# おわりに
JavaScriptにおけるclassが内部で何をしているのか知りたい場合はコンストラクター関数を学ぶとわかります。
Linux Essentialsを受験した話

##はじめに
Linuxの基礎知識が本当に付いているのかを確認するべく、受験してきた。
巷ではLPIC1の受験方法についての記述はあるが、Essentialsの記述はなかったので、備忘録として書く
（正直のところ、Linux Essentialsなんてお遊びだーなんて言う人もいると思う。そういう人は読み飛ばしていただきたい）

##自己紹介
・文系出身のインフラ屋
・PCはyoutubeを見るものという認識でしかなかったが、大学でレポートを書く程度には触れるようになった

##勉強方法
**[Ping-t](https://ping-t.com/)でひたすら問題を解きまくる**
これに尽きる。
答えの解説に問題と回答の詳細も記載されているので、解説を読みつつ間違いを正す為の繰り返し演習が一番暗記の為の定着化につながる。

##試験までの流れ
####①試験日を決める。
今回、受験日は3週間後と決めた。
####②ピアソンvueのアカウントを作成する
ピアソンvueのアカウントを作成していない場合は、作成が必要。
####③作成したアカウントから[ピアソンvue](https://wsr.pearsonvue.com/testtaker/signin/SignInPage/LINUXPROFESSION?locale=ja_JP)へログインし、試験日と会場を選択し、試験代支払い方法を入力し予約。
試験費用：11000円の支払い。
####④試験まで問題を解く。
Ping-tの問題は、解いた後**未出題・ミス・ヒット・コンボ**の4種類に分類され、それぞれ問題演習時にチェックを付けて重点的に演習することが出来る。
筆者の場合、未出題から攻めていき、未出題→ミス→ヒットの順でコンボ数をひたすら増やす作戦で行った。
未出題がなくなっただけで結構メンタルやられた（こんなにもわかってないことがあるのかと思うと...（以下略））
模試は受験日５日前くらいから解き初め、8割超えするよう調整した。

##結果
合格しました。
試験結果の詳細は以下の通り。

>あなたのスコア：630
合格ライン　　：500
結果　　　　　：pass

##感想
これは暗記ゲーだってよく言われていたが、言われていた意味がわかった気がした。（確かに暗記ゲー）
暗記ゲーだからやっても意味ない、ではなく、やってよかったと思う。
自分がわかったつもりになっていた箇所があったので、その復習にもなった。
次は101と102を受験するので、そちらも受験次第レポートを書いていこうと思う。
Sync Gateway機能解説：JavaScriptによる処理のカスタマイズとインポートフィルター



## JavaScriptによる処理のカスタマイズ

### 概要

Sync Gatewayは、同期プロセスのカスタマイズのために、JavaScript関数の使用をサポートしています。


### 登録例

次の例は、JavaScript同期関数を設定するさまざまな方法を示しています。
この例ではSync関数を指定する例を示していますが、JavaScript関数を用いるインポートフィルター等の他の設定にも、同じアプローチが適用されます。

#### ローカルファイル

以下のようにローカルファイルを指定することができます。
このケースでは、関数が定義されている、外部ファイル（`sync.js`）を指定しています。
複数台ノードでSync Gatewayをクラスターとして構成している場合には、それぞれのノードで同じ（内容の）ファイルが参照できる必要があります。

```JSON
curl -X PUT 'http://localhost:4985/db1/_config' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data-raw '{
         "sync": "/opt/couchbase-sync-gateway/sync.js" ①
      },
    }
}'
```

#### HTTPSエンドポイント

このケースでは、プロビジョニングするJavascript関数への解決としてHTTPSエンドポイントを指定します

```JSON
  curl -X PUT 'http://localhost:4985/db2/_config' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data-raw '{
         "sync": "https://localhost/sync/func2" ②
      }
   }
}
```

外部Javascript関数がHTTPSエンドポイントでホストされている場合は、適切なサーバーのCA証明書を登録する必要があります（テストの目的で、認証をスキップすることができます。`unsupported.remote_config_tls_skip_verify`を`true`に設定すると、セキュリティチェックが回避されます。）

#### Sync Gateway設定内のインラインJavaScript関数

このケースでは、Sync Gateway設定の内部（インライン）に、JavaScript関数を含めます。

インライン関数として定義されるJavaScriptプログラムは、バックティック（``）のペアで囲まれている必要があります（JSONデータとして管理される、Sync Gateway構成における独自の構文）。


```JSON
curl -X PUT 'http://localhost:4985/db3/_config' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data-raw '{
         "sync": `function(doc,oldDoc, meta){ if (doc.published) { channel("public");} }`
      } ③
   }
}
```



## インポートフィルター

### 目的

大量のデータを含むクラスターの場合、最初のインポートプロセスが完了するまでにかなりの時間がかかることがあります。
インポートフィルターを使用すると、プロセスをより効率的にすることができます。

### 設定解説

```JSON
//
{
  //  ... may be preceded by additional configuration data as required by the user ...
  "databases": {
    "getting-started-db": {
      "bucket": "getting-started-bucket",①
      "import_docs": true,
      "num_index_replicas": 0, 
      "import_filter": `
        function(doc) {
          if (doc.type != "mobile") { ②
            return false
          }
          return true
        }`,
      "sync": `function (doc, oldDoc) {
        if (doc.sdk) {
          channel(doc.sdk);
        }
      }`
    }
  }
  //  ... may be followed by additional configuration data as required by the user ...
}
//
```

- ①インポートフィルターを設定するバケット名。
- ②「type」プロパティが、「mobile」に等しいをドキュメントのみをインポートします。



## 参考情報

https://docs.couchbase.com/sync-gateway/3.0/import-filter.html
VMware Site Recovery Manager & vSphere Replication 検証

<font color="blue">**VMware Site Recovery Manager(SRM)**</font>と<font color="purple">**VMware vSphere Replication**</font>を使用した、サイトリカバリの基本動作を確認した際の手順です。

* Site Recovery Manager：8.4.0
* vSphere Replication：8.4.0.3
* vCenter Server：7.0 U1

# 検証構成
SRMの保護サイト → リカバリサイトにおけるリカバリテストが目的となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251519/ff731d87-fcff-0aab-5a96-75365ab76479.png)

# vCenter リンクモードの構成
* SRMの検証にあたり、vCenter リンクモードの構成が必要
（リカバリサイトのvCenterのデプロイ時の「ステージ2」にて「既存のSSOドメインへの参加」を選択して実施）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251519/73304b09-3309-baf5-8015-0c993591828e.png)

# SRM 仮想アプライアンスの展開とvCenterの登録
* ISOファイルよりSRM仮想アプライアンスのインストールと、管理コンソール（https://fqdn:5480  adminユーザ) よりvCenterの登録を実施
* 登録にあたり、vCenterとはNTP等による時刻同期が必須
* 保護サイトと同様、リカバリサイトにもSRMアプライアンスを展開する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251519/b96aebe6-0a38-762e-bf8e-2836eef4f359.png)

# vSphere Replication Management Server（VRMS）の展開とvCenterの登録
* <font color="red">**VRMSの展開先は vCenter管理環境を指定**</font> (参照：[検証構成図](#検証構成)）
* VRMS管理コンソール（https://fqdn:5480 adminユーザ) より、vCenterを登録

# SRM 初期設定：サイトのペアリング

* 前提として、保護及びリカバリサイトのSRMにてvCenterが登録済みである事
* vSphere Client > SRM（保護サイト） > 新規サイトペアにて、リカバリサイトのvCenterとペアリングする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251519/adad7f3b-2dc9-c27c-9895-87c680b04aab.png)

# SRM 初期設定：保護グループの作成

* SRMより、レプリケーションの設定と合わせてリカバリ対象の仮想マシンのグループである保護グループを作成
* レプリケーションの設定には、ターゲットサイト及びデータストア、又RPO（目標復旧ポイント）等が含まれる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251519/809c7065-0854-f7fb-ce61-0b51a3431958.png)

# レプリケーションの開始と確認
* レプリケーションが開始されると、リカバリサイトに仮想マシンが展開され、同期中を示すアイコンと共に、電源操作等は無効化されて表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251519/050f692a-76e8-6696-4f82-ec212ea79393.png)

# SRM 初期設定：リカバリプランの作成
* 保護グループを指定して、リカバリの方法となるリカバリプランを作成する
* リカバリプランでは、サイト間のリカバリの方向と、保護グループ、NWマッピングを指定する
* 「リカバリの手順」にて、詳細な動作を確認可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251519/b467605b-0580-efde-2d16-8669bcd82cb3.png)

# SRM リカバリプランのテスト
* リカバリプランのテストにより、リカバリプランの動作の確認が可能
* テストの実施により、リカバリサイトの仮想マシンがPower Onされ、操作が可能となる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251519/7399c1a3-26cd-2b21-993c-5172f98f2a03.png)
VSCodeで”パッケージがマッチしない”エラー

VSCodeでJavaを使っていたら、パッケージがマッチしないエラーが発生したので備忘
#やりたいこと
パッケージ名がマッチせずにエラーが発生
設定したフォルダをソースパスに設定する

```
package a.b.c.interfaces.Sample;

public class SampleController {

}
```

#エラー内容
java(536871240)

#調査
java(536871240)でググる

#原因
想定していたディレクトリ以外でソースパスに設定されている

#解決策
VSCodeのエクスプローラーで該当ディレクトリの親ディレクトを右クリックで

- Remove Folder to Java Source Path

を選択し、該当ディレクトリを右クリックして

- Add Folder to Java Source Path

を選択することで、ソースパスとして設定されエラーが無くなる。

#参考

https://teratail.com/questions/287130
Nuxt.jsを触ってみた

Vue.jsすら触ったことのない私が、案件でNuxt.jsを使うことになりました。
実際に触ってみた所感を残したいと思います。

## 今回の案件の概要
- TOPページと、下層に記事コンテンツを複数ページ作成
- 記事コンテンツのレイアウトは全て同じ

## コンポーネントを組み合わせて作る
Pugで開発をしていた時もヘッダーやフッター・頻出するボタン等はコンポーネント化して使用していましたが、今回はほとんど全てのパーツをコンポーネント化し、それを組み合わせてページを作っています。

```example.vue
<template>
  <div>
    <OrganizationHeader />
    <main class="main">
      <section class="contents">
        <article class="article">
          <!-- 記事タイトルを表示するコンポーネント -->
          <OrganizationArticleHead :page-title="page.articleTitle" />
          <section class="article__main">
            <p>
              {{ page.introText }}
            </p>
          　　　　<!-- 記事の見出しを取得して目次を作るコンポーネント -->
            <MoleculesToc :page-toc="page.toc" />
          　　　　<!-- 記事の本文 -->
            <nuxt-content :document="page" :page-data="page" />
          </section>
        </article>
      </section>
      <!-- おすすめ記事を表示するコンポーネント -->
      <OrganizationRecommend :page-slug="page.slug" />
    </main>
    <!-- パンくずリストを表示するコンポーネント -->
    <OrganizationBreadcrumb :link-data="breadcrumbData" />
  </div>
</template>

<!-- データの受け渡し -->
<script>
export default {
  props: {
    breadcrumbData: {
      type: Object,
      default: () => {}
    },
    page: {
      type: Object,
      default: () => {}
    }
  }
}
</script>

<!-- cssファイルの読み込み -->
<style lang="sass">
@use '~/assets/sass/style'
</style>

```

今回の記事コンテンツは、後述する**Nuxt Content**を利用して制作しましたが、記事本文となるMarkdownファイルにページ固有の情報を持たせています。
記事タイトルやmeta情報で使用するdescription、keywords等の情報をpropsにて`page`で取得し、各コンポーネントへ渡しています。

## Nuxt Contentで記事作成
Nuxt.jsで記事やブログを作成するための機能、Nuxt Contentを導入しました。
記事の中身となる部分をMarkdownファイルで作り、meta情報に入れるdescriptionやkeywordsなどをこのファイルに記述します。

```example.md
---
title: Nuxt Contentで記事作成
description: Nuxt Contentで記事作成のディスクリプション
slug: example
metaKeywords:
  - Qiita
  - 例文
  - 初心者
---

<h2>見出し</h2>
<p>
  HTMLタグも使えるし、Markdown記法も使えます
</p>
<div class="article__img">
  <atoms-picture :src="'./assets/images/img_001.jpg'" :width="740" :height="450" alt="" ></atoms-picture>
</div>
<p>
  .md内でコンポーネントも使用できます
</p>
```

## ディレクトリ構成が（割と）複雑
Pugなどで開発する時に比べると、ディレクトリ構成が複雑だなという印象でした。

```
.nuxt      // Nuxt.jsを利用するためのファイル
assets　　　　　　　　　　// cssやjsonファイルを格納
components // コンポーネントファイルを格納
content    // 記事本文となるMarkdownファイル
dist       // 納品用ファイル
layouts　　　　　　　　// サイト全体のベースファイル
pages      // TOPや下層のベースファイル
src        // 画像を格納
static     // 最適化した画像などを格納
store　　　　　　　　　　　　// jsonファイルを利用する時のstoreの設定ファイル
```

ディレクトリ構成が少々複雑な分、ファイルの所在が分かりやすくなり管理がしやすいかと思います。

## 感想
最初はコンポーネント化やデータの受け渡しなど、やり方を理解するまでにかなり時間がかかってしまいました。
ですが、ある程度理解してくると開発がとても楽しくなり、またNuxt.jsで開発したい！と思えました。
いろんなサイト制作に活用できそうなので、また機会があれば導入してみたいです。
VirtualBox でドラッグドロップできないと言われたのでスクリプト書いた

# プロローグ

「また、つまらない記事に筆を執ってしまった」

# ドラッグドロップできない

Aさん「Win7、VirtualBoxで使えるようにしてくれて助かってるよ」
わたし「どうも」

Aさん「そのVirtualBoxのエラーで困ってて」
わたし「どうしましたか？」

Aさん「ドラッグドロップしようとするとエラーで止まってね」
わたし「はい。」

Aさん「いつもPC再起動して治すんだけど、それもダメになってね」
わたし「…。」

Aさん「治せる？」
わたし「エラー画面見れます？」

# 現象

VirtualBoxを利用していて、ホストからゲストへドラッグドロップしようとしたら、下記のようなエラーが出ました。

```
終了コード :
VBOX_E_IPRT_ERROR (0x80BB0005)
コンポーネント:
GuestWrap
インターフェース:
IGuest {?????????-????-????-????-????????????}
```

# アップグレードしてみる

わたし「VirtualBoxのバージョン古いですね、アップグレードしてみましょう。」
わたし「それで無理だったら、諦めてフォルダ共有とかでお願いします。」


# ん？赤くね？

数分後…

わたし「無理でしたね、諦めましょうか。フォルダ共有はこのPDFの方法で試してください。」

エクスプローラーを開き、ドキュメントフォルダを開こうと…

わたし「（ん、待てよ？赤くね？Cドライブ）」
Aさん「なんかCドライブ赤いんだよね、まずいんかな？」
わたし「…」

# 原因が発覚

結論。原因は、VirtualBoxの想定していないレベルでの「ドラッグドロップの大洪水」。

ホストOSのWin10には、ドラックドロップのキャッシュが`%userprofile%\AppData\Local\Temp\VirtualBox Dropped Files`にある。これが過度に膨張してCドライブを圧迫していた。

キャッシュが削除されないというVirtualBoxのバグなのかもしれない。レガシーに時間を割くのは時間が惜しい。そのため深く検証はしない。

# 未来のために

「きっと、また同じ理由で呼ばれる。」そう確信した私は、下記のコマンドを含むバッチを作成した。

```batch:clear_drag_n_drop_cache_of_virtualbox.cmd
del /s /f /q "%userprofile%\AppData\Local\Temp\VirtualBox Dropped Files"
```

キャッシュクリアするだけなので平常時に使っても何ら問題ないはず。今の状況を説明し、同じ現象が起きたらこれを使うように指示。実際に目の前で利用させて、使いやすさを確認の後にグッバイした。

# 環境

### 確認済みの環境

- ゲスト Windows 7
- ホスト Windows 10

### その他の環境

- Windows全般がゲストの時に発生？
- おそらくホストOSは何でも良さそう

# まとめ

この記事を書いてるとき、VirtualBoxのサーバーが落ちていた。
なんて間の悪いことか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134703/6fbde85c-70db-3f06-b6bd-43804e3e1422.png)

**Excelsior!**
Macでファイルを簡単かつ迅速に解凍する方法

ZIPは、情報の保存と転送を容易にするファイルアーカイブおよびデータ圧縮形式です。 ただし、アーカイブに保存されているファイルを表示して使用するには、MacでZIPファイルを開く必要があります。つまり、ファイルを通常のフォルダーに抽出する必要があります。

Macでzipファイルを開く方法はいくつかありますが、CommanderOneが最も便利です。 次の記事では、ZIPアーカイブに関する興味深い情報と、Macでファイルを解凍する方法に関するいくつかの方法を集めました。 読書をお楽しみください。

ZIPファイルとは何ですか？
-
ZIPファイルは、さまざまなアーカイバが使用する一般的な圧縮形式です。 ZIP拡張機能は、特にPKZIPソフトウェアで使用するために、1989年にPKWAREの創設者であるPhilKatzによって開発されました。基本的に、アーカイブは大文字で書かれていますが、これはDOSシステムの元々の制限によるものです。

このようなアーカイブには、さまざまな圧縮度のデータが含まれている場合があります。 ZIP形式で使用されるファイル圧縮テクノロジの利点は、情報が失われないことです。アーカイブには、1つと複数のファイルまたはディレクトリの両方が含まれています。最もよく使用される圧縮アルゴリズムはDeflateです。

必要に応じて、ZIPアーカイブをMacでファイルを解凍するモジュールに接続できることは注目に値します。この場合、ユーザーはEXE拡張子を持つ単一の実行可能ファイルを受け取ります。 Windows、macOS、Linuxなどのオペレーティングシステム、および無料のプラットフォームは、通常、この形式をサポートしています。

このテクノロジーは一般的に認識されており、最も人気のあるアーカイブ方法のトップに含まれています。これは、バックアップ、圧縮、およびデータ交換機能を実行する多数のアプリケーションで使用できます。より革新的な技術を考慮に入れても、現時点では、説明されているアーカイブ形式は依然として適切です。

Macコンピュータでファイルを解凍する方法
-
アーカイブを受け取った場合、MacでZIPファイルを開いてそれが何であるかを確認し、アーカイブの内部コンポーネントを抽出する方法を疑問に思うかもしれません。 組み込みのアーカイブユーティリティのおかげで、MacでZIPファイルを開くのは非常に簡単です。 アーカイブユーティリティを使用してMacでZIPファイルを開く方法を見てみましょう。
1. ZIPファイルが配置されている宛先フォルダーに移動します。
![ывы.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740997/0ca565b5-5dc9-e922-a138-3e1b04cdaa94.png)
2.アーカイブユーティリティはデフォルトでMacに統合されています。 したがって、事前に検索して開く必要はありません。
3.このzipファイルをダブルクリックして、Macでファイルを解凍します。
4. macOSに組み込まれているアーカイブユーティリティは、ZIPアーカイブを開き、ファイルを抽出します。ファイルは通常、.zipファイル拡張子なしでZIPアーカイブと同じ名前のフォルダーに配置されます。
![678.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740997/07fd8d34-7f8b-8869-7b71-c48027ebcd9a.png)
また、ファイルを解凍するには、Macユーザーは.zipアーカイブを右クリックし、コンテキストメニューから[開く]を選択する必要があります。 さらに、サードパーティの解凍Macユーティリティをインストールしている場合は、[プログラムから開く]を選択して、別のアーカイブツールを選択できます。
通常のコマンドラインユーザーの場合は、ターミナルを介してMacでzipファイルを開くと便利な場合があります。 ターミナルでunzipコマンドを使用して、アーカイブZIPファイルを解凍できるため。

1.ターミナルアプリケーションを起動します。 Finder>アプリケーション>ユーティリティ>ターミナルに移動すると見つけることができます。
2.zipファイルをデスクトップに移動します。 そうでない場合は、ターミナルにも場所を入力する必要があります。 これを行うには、cdコマンドを使用して、ZIPフォルダーを含むフォルダーに移動します。
3. unziparchive.zipと入力します。
4. MacでZIPファイルを解凍するには、Enterキーを押します。 ダブルクリックと同様に、アーカイブの非圧縮コピーが現在のフォルダに作成されます。
MacでZIPファイルを開くためにサードパーティのソフトウェアを使用する利点
-
圧縮または解凍タスクを実行できる組み込みツールがあると、間違いなくはるかに便利です。 しかし、組み込みのMac解凍ツールは理想的ではありません。 生産性に関しては非常に不便ないくつかの非常に重要な欠点があります。 まず第一に、それらは完全に互換性がないので、異なるファイル拡張子を扱うことになると不利な点が指摘されます。 これは間違いなくこの点で大きな問題です。

今のところ、Mac用のネイティブzipプログラムは、拡張子が.zipのファイルのみを解凍します。 これは重大な欠陥であり、他の拡張機能に対してオープンなサードパーティのツールを使用する必要があります。 確かにZIPファイルは日常的に見られる最も一般的なファイルですが、状況によっては他のファイルを操作する必要があり、ファイルを解凍する方法だけでなく、重要な問題が発生する場合もあります。 Macだけでなく、他のアーカイブ形式の処理方法も。
![963.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740997/dbf459f7-027c-4cb2-e23c-18888964466d.png)
たとえば、[Commander One](https://mac.eltima.com/archiver-mac.html) –強力なファイルマネージャーであり、Mac用のZIPエクストラクターです。このunzip for Macソリューションのおかげで、Macでopen.zipを開くだけでなく、ファイルやフォルダーをさまざまなアーカイブにパックして、アーカイブのコンテンツを調べることができます。 それを抽出せずに。 さらに、この機能はCommander Oneにすでに実装されているため、アーカイブをパスワードで保護する場合は、ターミナルを開く必要はありません。 さらに、このアプリは、オンライン接続のサポート、組み込みのターミナル、MTPおよびiOSデバイスとの連携など、他の便利な機能を誇ることができます。
Cloud Shellの環境でNodeバージョンを14に更新してみた

Cloud Shell環境に用意しているNodeのバージョンは12だったので、14に更新したくて、ネット上でやり方を調べてできましたが、ハマったことをメモします。

## Node 情報確認

```bash
>node --version
12.14.1

>which node
/usr/local/nvm/versions/node/v12.14.1/bin/node
```

## nvmでの更新が失敗

```bash
>nvm install 14
nvm: command not found

```

## 解決策
同じ問題に遭遇した人はstackoverflowにもいました。
その方の解決策を参考にしました。
[How to update node version on Google Cloud Shell](https://stackoverflow.com/questions/67865856/how-to-update-node-version-on-google-cloud-shell)

```
>source /google/devshell/bashrc.google
>nvm install 14
```

上記でNodeのバージョンを14に更新できました。
Raspberry piへのTensorFlowのインストール (モルカーを画像認識で判別したい！)

#本記事の内容
- Raspberry PiにpipでTensorFlow 1.14をインストールする (モルカーを画像認識で判別したい！)

画像認識の仕組みをラズベリーパイで実現しようとしています。
モルカーを画像認識で判別したいと思っています。出来たら可愛いなあと。

まずはTensorFlowをRaspberry piにインストールします。

尚、pipでインストールできるのは、1.14までの様です。
1系の最新版である、1.15.Xをpipでバージョン指定してインストールしようとしてもエラーになりました。
1.15をインストールしたい場合は、ソースからビルドする方法で自前でインストールする必要がありそうです。

#実施環境
- Windows 10
- TeraTarm Version 4.9.4
- Raspberry Pi 2 Model B
- PLANEX 無線LAN子機 GW-USNANO2A ※Raspberry Pi 2はWi-Fi通信モジュールがないため、無線LAN子機をUSBに接続しWi-Fi通信を行う。
- 家庭内の無線LANネットワーク環境にて実施

#手順の流れ 
1. TeraTarmでsshログインする
2. Pythonの仮想環境の作成とTensorFlow1.14のインストール

## 1. TeraTarmでsshログインする

WindowsにてTeraTarmを起動して、ラズパイにSSH接続する。

## 2. Pythonの仮想環境の作成とTensorFlow1.14のインストール

今回インストールを行うTensorFlowの1.14が対応しているPythonのバージョンは、2.7系、3.3系～3.7系のみのようでした。
![99.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/2b372437-15b4-b31f-90cb-bfa6b369a40b.png)
※画像の黄色い塗りつぶしがLinux系のPython3.7で対応しているTensorFlow。


私のラズパイにはPython3.9を新たにインストールしていますが、ここではプリインストールされていた3.7系を利用し仮想環境を作成することにします。

仮想環境はpiユーザのホームディレクトリで作成する

	pi@raspberrypi:~ $ /usr/bin/python3.7 -m venv --system-site-packages ./venv


仮想環境のアクティベート

	pi@raspberrypi:~ $ source ./venv/bin/activate


	
仮想環境のPythonのバージョン確認

	(venv) pi@raspberrypi:~ $ python -V
	Python 3.7.3


pipのアップグレード

	(venv) pi@raspberrypi:~ $ pip install --upgrade pip



tensolflowのインストール

	(venv) pi@raspberrypi:~ $ pip install tensorflow==1.14.0
ログが結構流れ最終行にSuccessfully installedのメッセージが表示される。

	Successfully installed absl-py-0.14.1 astor-0.8.1 cached-property-1.5.2 cachetools-4.2.4 gast-0.2.2 google-auth-1.35.0 google-auth-oauthlib-0.4.6 google-pasta-0.2.0 grpcio-1.41.0 h5py-3.4.0 importlib-metadata-4.8.1 keras-applications-1.0.8 keras-preprocessing-1.1.2 markdown-3.3.4 opt-einsum-3.3.0 protobuf-3.18.1 pyasn1-0.4.8 pyasn1-modules-0.2.8 rsa-4.7.2 setuptools-58.2.0 tensorboard-2.0.2 tensorflow-1.14.0 tensorflow-estimator-1.14.0 termcolor-1.1.0 typing-extensions-3.10.0.2 wrapt-1.13.2 zipp-3.6.0


tensolflowがインストールされた事を確認する。

	(venv) pi@raspberrypi:~ $ pip list
	Package              Version
	-------------------- -----------
	～途中省略～
	tensorboard          2.0.2
	tensorflow           1.14.0
	tensorflow-estimator 1.14.0
	～途中省略～

tensorflow 1.14.0がインストールできた。
手順は以上。まずはTensorFlowのインストール迄ブログに載せます。


以下の画像は今テスト中の画像認識の状況。詳しくはまた別途。
![物体検知テスト.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017667/636c52d2-2461-7bef-197b-7422bf44c9c5.png)

中央に写っているタンポポという種類のモルカーと左端のボーダーコリーの人形だけAIに学習させた状態で、画像認識のアプリを動かした様子です。この2つはちゃんと認識されていますが、右側のモルカーはまだ学習させていないので、何なのか認識できていません。
モルカーの形状や色の違いも判別出来ていて嬉しい。精度向上に向けて試行錯誤中。


# 参考文献
本記事の作成に当たり、以下の情報を参考にさせて頂きました。
- [pip での TensorFlow のインストール](https://www.tensorflow.org/install/pip?hl=ja)
- [tensorflow 1.14.0](https://pypi.org/project/tensorflow/1.14.0/#files)
ManjaroをアップデートしたらNFSが動かなくなった話

## 経緯

何ヶ月か前に自宅サーバのManjaroを更新した際にそれまで機能していたNFSでのファイルへのアクセスができなくなった。当時は原因がわからずsshfsで代用していたのだが、最近になって新たに購入したMacbookから手軽にアクセスするため、改めてNFSの復旧を試みた

## 状況

- 自宅サーバのOSは Manjaro Linux 4.19.208-1
- 数ヶ月前にそれまでできていたNFSへの接続ができなくなった
- `systemctl status nfs-server`や`exportfs`ではとくにエラーは出ていない
  そのため当初はvpnやFWなどネットワーク関係の問題を疑っていた

## 結論
下記のManjaroのフォーラムに上がっており、この通りにカーネルを5.4にアップデートしたら治った。
[My nfs-server not working since last update - Support / Network - Manjaro Linux Forum](https://forum.manjaro.org/t/my-nfs-server-not-working-since-last-update/77263)

## 原因究明（?）までの道のり

試したことは以下の通り
結局解決につながったわけではないが、半日かかって何も進歩がないというのも癪だったのでせめてもの自己満足としてここにアウトプットしておく。

なお、以降の例ではDNSサーバーのipを`192.168.1.2`、ドメイン名を`nfs.home.example.net`としている。

### クライアント側のエラーの確認

```
$ sudo mount -t nfs4 nfs.home.example.com:/srv/nfs /mnt/nfs  -v                      
```

`Permission denied` や `Connection refuse`といった漠然としたエラーでクライアント側では原因が検討がつかなかった。

とはいえ、動かなくなったきっかけはサーバーのバージョンアップだったため、クライアントの問題ではないとは思っていたので、特に掘り下げずに先に進んだ。

### サーバ側のエラーや設定の確認

前述のように`systemctl`や`exportfs`ではとくにエラーは出ていないため、この時点ではサービス自体の問題はないと判断。VPNやDNS,FWなど、ネットワーク関係のの設定ミスにあたりをつける。


### ネットワークの経路の確認

sshは通じているのでルーティングには問題ないはずだが念の為Pingで確認。

```
$ping nfs.home.example.com
$ping 192.168.1.2
```

ipでもドメインでも問題なく通じた。

### クライアントからポートの確認

ここでやっとポートの確認をした。

```
nmap -p 2049 192.168.1.2                                                                                                                                                              ±[main]
Starting Nmap 7.92 ( https://nmap.org ) at 2021-10-16 15:44 JST
Nmap scan report for 192.168.1.2
Host is up (0.00027s latency).

PORT     STATE  SERVICE
2049/tcp closed nfs

Nmap done: 1 IP address (1 host up) scanned in 0.05 seconds
```

ポートへはアクセスできない。
ということでFWの設定ミスと判断し、FWの設定を確認した

### ファイヤーウォール（nftables）の確認

```:/etc/nftables.conf
#!/usr/bin/nft -f
# 中略
table inet filter {
  chain input {
    type filter hook input priority filter
    policy drop
    # 中略
    tcp dport { 111, 2049 }  accept
    udp dport { 111, 2049 }  accept
    # 中略
  }
  chain forward {
    type filter hook forward priority filter
    policy drop
  }
}
~
```


FWは設定を見た限り問題ないように見える（`nfs`に必要な`2049`と`111`のポートを`UDP`、`TCP`それぞれで受け入れている）
念の為`nftables`を止めて再度外部からのポートへの問い合わせをしたが結果は変わらず。

### 内部からのポートの確認

ここに来てとうとうサーバー自体が機能していないのではないかと疑い始める。
エラーも出てないのにそんなことはないだろうと思いつつ内部からポート確認

```
ss -atn | grep 2049 
# 何も出力なし。
```

案の定ポート自体が開いていないという状態。

ここに来てようやく自分の設定の問題ではないと確信し、Manjaroの不具合報告を探して見つけたのが先に載せたページ。そこにあった通りカーネルを更新したら解消した。

## 反省
- バージョンアップに伴う不具合は他にも同じ事例が出ていないか早めにフォーラムを確認するべき
- Archwikiに頼りすぎない
    - ManjaroはArch系なので大概のことはArchwiki通りでなんとかなるが、Manjaro固有の問題もあるので。
- エラーがないからといってちゃんと機能しているとは限らない
    - 今回は流石にレアケースだと思うが、ポート確認など他の手段でも確認できるようにしておく
    - 特に今回は設定ファイルを検証することに非常に時間をかけてしまっていたので、先にポートを確認しておけば設定の問題ではないことはすぐに分かったはず。

## 余談

結局Macbookの方でNFSへの接続はユーザーIDが違う問題があり、まだできていなかったりする。先は長そう。
vue.js

ほぼ備忘録のように書いていいます。

## v-for
```
<ul>
	<li v-for=“item in items” :key=“item.message”>{{ item.message }}</li>
</ul>
```
itemsの中身を順番にitemの変数に格納する。

```
v-for=”変数 in オブジェクト”
```
## v-if
```
<div v-if="type === 'A'">
  A
</div> <div v-else>
  Not A/B/C
</div> 
```
“type === ‘A’”を評価し、 正の場合v-ifのブロックの内容を表示
負の場合v-elseのブロックを表示

```
v-if=“変数・式”
```
## v-on
```
<div id="app">
  <button v-on:click="onClick">ボタン</button>
</div>
```
イベントをトリガーにしてメソッドや指揮を実行する

```
v-on:イベント名="メソッド名または式"
```
## v-model 
``` 
<input v-model="message”>
<p>Message is: {{ message }}</p>
```
input要素に入った内容を定義した変数に入れ表示させる

```
v-model=“変数”
```
## v-bind
```
<template>
  <input v-bind="{ type:'text', maxlength: 3 }">
</template>
```

``` 
 <input type="text" maxlength="3">
```
要素に対してプロパティを適用します。

***
     
## 参考
https://qiita.com/ota-meshi/items/ffa875daa9ebc9fc57c0
https://johobase.com/vue-js-v-on-directive/
https://jp.vuejs.org/v2/guide/list.html
https://jp.vuejs.org/v2/guide/conditional.html
https://jp.vuejs.org/v2/guide/forms.html
【Power Apps】LookUp関数を利用してラベルに特定レコードのフィールド値を表示する

当初`Filter`関数を用いて表を表示させたアプリを作成していました。UI変更でラベル入力値を用いてテーブルの値をFilterできないか、と苦心していました。が、比較項目の型を統一するというのは筋が悪そうだと諦め（テーブルはレコード型になる）、テーブルではなくラベルに表示できないかという観点で調べました。

### Filter以外にもSearchやLookUpもある

結果、たどり着いたのはMS Learnでした

https://docs.microsoft.com/ja-jp/learn/modules/author-basic-formula-tables-records-powerapps/5-lookup-return-record

※2020/11まで、とありますので参照時期によっては最新のLearnをご確認ください。

この教材の中に構文

```PowerApps
LookUp(collectCustomerInvoices, ID =3).Amount
```

がありましたので、こちらを参考に解決することができました。（値比較で数値に変換が必要な場合は`Value`関数を用います）


技術ブログやDocsのリファレンス検索で行き詰まった場合はLearnに立ち返るのがいいのかもしれません。

https://docs.microsoft.com/ja-jp/powerapps/maker/canvas-apps/functions/function-filter-lookup


### 実際の使い方

Label1とLabel2の形式は日付型で一致しています。

![スクリーンショット 2022-09-29 145405.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1469675/dc41a9b1-6976-a775-41f6-b16ae08359d4.png)

|プロパティ|式|
|--|--|
|Label1.Text|LookUp(Table,ID=nn,開始日)|
|Label2.Text|Today()|
|Label3.Text|"開始前です"|
|Label3.Visible|If(DateDiff(Label1.Text,Label2.Text)<0,true,false)<br>※上の例ではDateDiff(Label1.Text,Label2.Text)の結果は-4になります。開始日が到来したら非表示になります|

![スクリーンショット 2022-09-29 164547.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1469675/c5b508dc-f2d2-525a-d6e9-a4ad17dabef5.png)

|プロパティ|式|
|--|--|
|Label1.Text|LookUp(Table,ID=nn,終了日)|
|Label2.Text|Today()|
|Label3.Text|"既に終了しています"|
|Label3.Visible|If(DateDiff(Label2.Text,Label1.Text)<0,true,false)<br>※上の例ではDateDiff(Label2.Text,Label1.Text)の結果は-3になります。終了日前は非表示。|