OmniAICreator/Qiita-1.07M huggingface dataset:
Flutter Webviewでソフトウェアキーボードで input[type=text] が隠れる不具合を解消（iOS）

# 概要
Flutterで側アプリ（WebView）内のテキスト入力にフォーカス時に現れるソフトウェアキーボードでテキスト入力が隠れる不具合を解消する方法です。
WebViewはwebview_flutter: ^3.0.1
※今のところiOSのみ確認済みです。

# Before
![before.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167934/f8274a79-713f-e24f-5aa7-8805cdeae9fe.gif)

# After
![after.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167934/ce076d3e-9055-285a-7194-b8f278575187.gif)

# 解決方法
WebView をラップしている Scaffold の resizeToAvoidBottomInset を false にします

```dart:webview.dart
@override
  Widget build(BuildContext context)  {

    return Scaffold(
      resizeToAvoidBottomInset: false,   // ← これを追加
      body:  
        WebView(
        //省略...
        )
    )
}
```

# 原因
body のスクロールだとこの不具合は起きないようですが
position: absolute や fixed の被ってくるもの高さ計算が入るものが影響していそうです。

# まとめ
webview_flutterのバージョンアップしてみたり、cssをなんども調整し何日も溶かしました凹
Flutterのソースコード１行で済んだので助かりました。。。:relaxed:

キャプチャ動画だとわかりにくいですがソフトウェアキーボードがもどる時に戻り終えた箇所がしばらく白くなる現象も直っています。

ちなみに画面はReactです。
Lenovo G500を在宅勤務で使い尽くす　

さて、手元の余っているG500がまだまだ使えることがわかりました。いまはメモリーも8GByteに増強し、ぼちぼち快適に動いています。また、これまではLubuntuを使ってたんですが、とりあえずUbuntuに変更。

ここでは、自分メモ用に、Ubuntuを在宅勤務で使い尽くす変更を残します。

# 接続先の日本語入力ON/OFFができるように変更

そもそも、キーボード自体をAliexpressで購入したUS配列のキーボードに変更しています。私の身の回りのキーボードはほとんど101キーボードにしています。

Ubuntu系でVMware horizon Clientとか、たぶんリモートデスクトップとかもですが使ってるとキーバインドがいろいろおかしくなることが多いです。

なので、とりあえず、

https://blog.ouvill.net/blog/2020-02-05--change-japanese-shortcut/

ここを見ながら、日本語をAlt + ~ で変更できるようにします。


# 接続先でswapしたctrlキーを使えるようにする

個人的に、HHK以外のキーボードでは、Aキーの隣はCtrlにアサインしないと気持ちが悪い私です。とりあえずこの辺を見ながら、ctrlキーを接続先に送信できるようにしました。

https://yaaamaaaguuu.hatenablog.com/entry/2019/11/28/002219
http://www.gentei.org/~yuuji/diary/2001/05/31/

~/.vmware/config について、

keymap.keycode.66  = 0x01d 

ってのはデフォルトのファイルに記載があるのですが、

xkeymap.keycode.66  = 0x01d 

ってのはなかったので追記したらうまく行きました。
cpxが更新されないのでfsで置き換えてみる

npm script で一部の素材ファイルやディレクトリをまるごとコピーするのに便利な cpx だが、すでに6年も更新されておらず、最近になって npm audit に警告がでるようになった。

https://www.npmjs.com/package/cpx

流石に6年放置は修正が期待できないので代替案を考えた。

以下は私のプロジェクトで利用しているスクリプト例（webfont用のファイルをコピーしている）
これをベースに書き換えを行ってみる。

```json
"font": "cpx -C \"./dev/assets/fonts/*\" \"./public/assets/fonts\"",
"watch:font": "cpx -C \"./dev/assets/fonts/*\" \"./public/assets/fonts\" -w",
```

### 1. cpコマンドを使う

```json
{
    "font": "cp -r ./dev/assets/fonts ./public/assets/fonts"
}
```

私がWindows派なのでなので却下（※）

※実はGowというものをインストールしているのでcpを含めたlinuxコマンドが使えるが、第三者の利用や環境が変わる可能性を考慮して却下。

https://qiita.com/jonghyo/items/655ce8fc97ae25e3b43d

### 2. fsモジュールを使う

```json
{
    "font": "node -e \"require('fs').cpSync('./dev/assets/fonts', './public/assets/fonts', {recursive: true}))\""
}
```

基本に立ち返りNode.jsの機能でやってしまえと。
ググるとよく [fs-extra](https://www.npmjs.com/package/fs-extra) を利用するケースが散見されるが、ただコピーするだけならこれで十分。

### wオプションの代替に onchange を使う

https://www.npmjs.com/package/onchange

マニュアルどおりに記載すれば良い

```json
{
    "watch:font": "onchange \"./dev/assets/fonts/*\" -- npm run font"
}
```

### 番外：コピーする前にdistディレクトリを削除する

`fs.cpSync` では上書きコピーするだけで、削除に対応できない。
source側で削除されたファイルに対応するには以下のように記述すれば良い。

```json
{
    "font": "node -e \"require('fs').rm('./public/assets/fonts', {recursive: true, force: true}, () => {require('fs').cpSync('./dev/assets/fonts', './public/assets/fonts', {recursive: true})})\""
}
```

ちょっとコマンドが長くなるのが気になるなら、外部ファイルから実行するか、コマンドを分けて順次実行しても良い。
以下は後者の例（[npm-run-all](https://www.npmjs.com/package/npm-run-all) の `run-s` を利用しても良い）

```json
{
    "prefont": "node -e \"require('fs').rmSync('./public_html/static/fonts', {recursive: true, force: true})\"",
    "font": "node -e \"require('fs').cpSync('./dev/_assets/fonts', './public_html/static/fonts', {recursive: true})\""
}
```
TypeORM QueryRunner.manager.query() と QueryRunner.query() の違い

### TypeORMにおける`QueryRunner.manager.query()`と`QueryRunner.query()`

TypeORMには、データベースに対してクエリを実行するための2つのメソッドがあります: `QueryRunner.manager.query()`と`QueryRunner.query()`。

#### `QueryRunner.manager.query()`
- 使用して、データベースに対してクエリを実行します。
- トランザクションに対して実行することもできます。
- トランザクションを使用していない場合は、自動的にトランザクションを開始します。
- 返されるPromiseは、クエリの成功または失敗にかかわらず、結果を返します。

#### `QueryRunner.query()`
- トランザクションを使用して実行します。
- トランザクションを使用していない場合は、エラーがスローされます。
- 返されるPromiseは、クエリの成功または失敗にかかわらず、結果を返します。

つまり、`QueryRunner.manager.query()`はトランザクションを使用するかしないかに関係なくクエリを実行でき、一方で`QueryRunner.query()`はトランザクションを使用してクエリを実行することが前提となっています。

また、`QueryRunner.manager.query()`はトランザクションを使用していない場合に自動でトランザクションを開始するのに対し、`QueryRunner.query()`はトランザクションを使用していない場合はエラーがスローされるため、トランザクションを使用したい場合には`QueryRunner.query()`を使用し、トランザクションを使用しない場合は`QueryRunner.manager.query()`を使用するようにすることが望ましいです。
Quick share / internal app sharing / 内部アプリ共有でaab、apkをURLで共有する

今まであった内部テストとは別に、internal app sharing upload pageというのがあるので共有しておきます。
aab/apkの突発的な共有が楽になるという感じだと思います


* 基本的にはinternal app sharingにアップロードする感じっぽい。
    * そのaab apkのパッケージ名の権限があるアカウントからしかアップロードできない
    * Release > Setup > Internal app sharingからUploaders and testers tabがあり、アップロードできるアカウントを追加できる。
* バージョンコードが重複しても大丈夫
* app bundle explorerなどに入らない
* なんの鍵で署名されていてもOK
* アップロードしたファイルのリンクを作ってくれる 
* リンクは60日で失効

Quick share / internal app sharing upload pageのページ

https://play.google.com/console/internal-app-sharing/

ドキュメント

https://support.google.com/googleplay/android-developer/answer/9844679?visit_id=638096138381699982-3536785906&rd=1

# アップロード

まず https://play.google.com/console/internal-app-sharing/ にアップロードしようとしてみます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27388/06002acf-0ae0-8a45-c6cf-5c7baf0f51e1.png)
アップロードしようとすると以下のように言われるので許可します。(内部テスト使ったことあるアプリなら大丈夫そうです。)

> xxxは内部アプリ共有の利用規約に同意していません。アカウント所有者に Play Console で利用規約に同意するよう依頼してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27388/ed3db5c1-73cf-5c58-a8a8-8fa56dd59f95.png)

アーティファクトの名前を入力する画面が出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27388/4ee813c2-9710-2e96-dbe3-c7059f9ac333.png)

追加されるとこんな感じになります。右のコピーボタンからリンクがコピーできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27388/fd6c3b71-f491-f628-9786-01399751dceb.png)

# ダウンロード

Google Playで権限があるアカウントを選択しておいて、以下のコマンドを実行します。URLはコピーしたものです。

> adb shell am start -a android.intent.action.VIEW  -d "URL"


ちなみに、Google Play consoleの設定で、権限が必要かどうかは設定することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27388/58646a5c-6ebe-e41e-89fd-7d603f547b0a.png)


Google PlayでInternal app shareingをやったことがなければ以下のようにダイアログが出ます

設定にあるPlay Store versionを連打すると開発者モードになれて、そこでInternal app shareingを有効にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27388/7f322c6c-0254-33e0-caa0-99fa75283415.png)


もう一度URLを開くと、インストールページが開けます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27388/d1c1d240-03be-14da-962f-2252ea8168d5.png)
VBA閉じる際に空のエクセルを残さない

:::note info
VBAから自BOOKを閉じる際に
ThisWorkbook.Closeを実行すると空のエクセルが残り、
Application.Quitを実行すると他の開いているエクセルも閉じてしまう事への対策
:::

```vb:vba
Option Explicit

' 終了処理
Private Sub UserForm_Terminate()

    Dim word As Variant
    Dim task As Variant
    Dim excelProcessCount As Integer
    ' Wordを起動
    Set word = CreateObject("Word.Application")
    ' Word VBAのTasksコレクションを調べる
    For Each task In word.Tasks
        If task.Visible And InStr(task.name, " - Excel") > 0 Then 
            ' エクセルが実行中だったらカウントする
            excelProcessCount = excelProcessCount + 1
        End If
    Next task
    word.Quit
    Set word = Nothing

    ' TASKから他のエクセルがないか調べ2つ以上なら自身BOOKを閉じる。以下ならエクセルを閉じる
    If excelProcessCount > 1 Then
        ThisWorkbook.Saved = True
        ThisWorkbook.Close
    Else
        Application.Quit
    End If
    
End Sub
```
[Python] Selenium タイムアウトエラー時にリトライ

# 該当エラー
selenium.common.exceptions.TimeoutException: Message: timeout: Timed out receiving message from renderer: 600.000

# リトライ（再試行）ロジック

```python
        retry_count = 3
        for retry_time in range(retry_count):
            try:
                # Selenium code that might raise TimeoutException
                # selenium.common.exceptions.TimeoutException: Message: timeout: Timed out receiving message from renderer: 600.000
                
                selenium_execute() # <= selenium 処理を記述
                break
            except TimeoutException:
                print(f'Attempt {retry_time + 1} failed')
                if retry_time == (retry_count - 1):  # If the last retry
                    raise Exception('All retries failed')
                continue

```
Shader Graph Error "_Time"

# Shader error in 'Master': redefinition of '_Time' at line 144 (on d3d11)

# 現象
Unity Shader GraphのSubgraphを作成し"Time"というプロパティを宣言すると"_Time"というReferenceが動的に設定されるのだが、"_Time"は元々Unity側が定義しているためエラーが出る。

https://docs.unity3d.com/jp/460/Manual/SL-BuiltinValues.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/1e216ecf-daf0-d704-8d6b-9650b659769a.png)

# 対応
プロパティ名を"TotalTime"に変更することで対応した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/5f95560d-024d-e430-a313-0c38e6aeebc9.png)


その他には以下のような対応ができるそう(未検証)

https://forum.unity.com/threads/redefinition-of-_time-when-including-lighting-hlsl-in-custom-function-for-shader-graph.1215608/

https://answers.unity.com/questions/1653036/shadergraph-custom-function-undeclared-identifier.html
EC-CUBE 2.13系をDockerで動かすときのメモ

2.13.5をDockerで動かすときのメモ


```
// git clone
git clone https://github.com/EC-CUBE/ec-cube2.git
cd ec-cube2
git checkout refs/tags/eccube-2.13.5


// 2.17のdocker関連ファイルを取得
(
CURRENT_DIR=$(pwd)
cd /tmp
git clone --depth 1 https://github.com/EC-CUBE/ec-cube2.git
cd ec-cube2
cp -r dockerbuild ${CURRENT_DIR}/
cp Dockerfile ${CURRENT_DIR}/
cp docker-compose.yml ${CURRENT_DIR}/
cp docker-compose.pgsql.yml ${CURRENT_DIR}/
cp docker-compose.mysql.yml ${CURRENT_DIR}/
cp docker-compose.dev.yml ${CURRENT_DIR}/
cp eccube_install.sh ${CURRENT_DIR}/

rm -rf /tmp/ec-cube2
)

// composer1系を利用
sed -i "" 's/composer:2.2/composer:1.10/g' Dockerfile

// 2.13系ではcomposer.lockがないのでコメントアウト
sed -i "" 's/COPY composer.lock/#&/g' Dockerfile

// インストールは別途行うので不要
sed -i "" 's/.*wait-for-pgsql\.sh/#&/g' docker-compose.pgsql.yml
sed -i "" 's/.*wait-for-mysql\.sh/#&/g' docker-compose.mysql.yml

// ビルド
export TAG=5.4-apache
docker build -t ec-cube2 --no-cache --pull \
--build-arg TAG=${TAG} \
--build-arg GD_OPTIONS="--with-freetype-dir=/usr/include --with-jpeg-dir=/usr/include" \
--build-arg EXT_INSTALL_ARGS="gd zip mysql mysqli pgsql mbstring" \
--build-arg APCU=apcu-4.0.11 \
--build-arg FORCE_YES=--force-yes \
./

// タグ付け
docker tag ec-cube2 ghcr.io/ec-cube/ec-cube2-php:${TAG}

// 起動(pgsql)
docker-compose -f docker-compose.yml -f docker-compose.pgsql.yml -f docker-compose.dev.yml up

// 起動(mysql)
docker-compose -f docker-compose.yml -f docker-compose.mysql.yml -f docker-compose.dev.yml up

// ブラウザで開く
open https://localhost:4430/install/
```

## トラブルシュート

### mysqlを利用する場合

mysqlを利用する場合、↓の対応が必要
https://qiita.com/cs_sonar/items/d90b8e291c5ea5e2cc4b

### apt-getでのエラー

apt-get updateで以下のようなエラーが出る場合
```
Err http://security.debian.org jessie/updates/main amd64 Packages
```

apt-get update前に以下を追記する
```
RUN echo "deb http://archive.debian.org/debian/ stretch main" > /etc/apt/sources.list \
    && echo "deb http://archive.debian.org/debian-security stretch/updates main" >> /etc/apt/sources.list
```
GA4接続したGoogle Optimizeは従来型スニペットが使えない

:::note warn
Google Optimizeは2023年9月30日をもってサービス終了となりました。
:::

ほとんどの方には関係のない話ですが、GoogleAnalytics4に接続したGoogleOptimizeではanalytics.jsをOptimizeタグとして認識しません。

その昔、GoogleOptimizeがリリースされた頃はoptimize.jsおよび同期タグが存在せずanalytics.jsをスニペットとして非同期的に利用していました。
具体的には以下のような形でrequireで呼び出します。

```HTML
<style>.async-hide { opacity: 0 !important} </style>
<script>(function(a,s,y,n,c,h,i,d,e){s.className+=' '+y;h.start=1*new Date;
h.end=i=function(){s.className=s.className.replace(RegExp(' ?'+y),'')};
(a[n]=a[n]||[]).hide=h;setTimeout(function(){i();h.end=null},c);h.timeout=c;
})(window,document.documentElement,'async-hide','dataLayer',4000,
{'OPT_CONTAINER_ID':true});</script>
        
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'GA_MEASUREMENT_ID', 'auto');
ga('require', 'OPT_CONTAINER_ID');
</script>
```

https://support.google.com/optimize/answer/6262084?hl=ja

私の場合はHTMLに直書きしたanalytics.js（Optimize用途）とは別にGTMからもanalytics.jsを吐き出していたので、その状態でUAに接続したOptimizeコンテナでは以下のWarningが出ていました。

![e1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147689/0028e6ce-f9b0-12ad-ba6a-5cd260ee82ab.png)

あくまでWarningだったので利用できる状態だったのですが、 **GA4に接続したOptimizeコンテナではError扱い** になってしまい、Optimizeエディタが操作できません。

![e2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147689/557357bf-8c7d-64d0-1142-86a50f9fc3be.png)

というわけで、GA4利用においてはoptimize.jsへの切り替えが必須となります。

### 同期タグ

```HTML
<script src="https://www.googleoptimize.com/optimize.js?id=OPT_CONTAINER_ID"></script>
```

https://support.google.com/optimize/answer/9692472?hl=ja&ref_topic=6197443

### 非同期タグ
```HTML
<script async src="https://www.googleoptimize.com/optimize.js?id=OPT_CONTAINER_ID"></script>
```

https://support.google.com/optimize/answer/10106536?hl=ja&ref_topic=6197443

#### 非同期タグにアンチフリッカーを追加する場合
```HTML
<style>.async-hide { opacity: 0 !important} </style>
<script>(function(a,s,y,n,c,h,i,d,e){s.className+=' '+y;h.start=1*new Date;
h.end=i=function(){s.className=s.className.replace(RegExp(' ?'+y),'')};
(a[n]=a[n]||[]).hide=h;setTimeout(function(){i();h.end=null},c);h.timeout=c;
})(window,document.documentElement,'async-hide','dataLayer',4000,
{'CONTAINER_ID':true});</script>
```

https://support.google.com/optimize/answer/7100284?hl=ja&ref_topic=6197443


optimize.jsに切り替えると無事エラーが解消されます。

![e3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147689/ba0aa7c5-0617-a7cf-708a-d370029d96ea.png)


自社サイトやクライアントのサイトでanalytics.jsをOptimizeタグとして利用している場合には注意が必要ですね。
javascriptでid属性やclass属性を制御する

## ■状況
もともと、バックエンドばかりを担当していた。
フロントも任されることになり、javascriptで制御をする必要があった。
情報はあったが、ばらけているのでシェアしたいと思った。

## ■ソース
ボタンの活性・非活性の制御をもとに、id属性とclass属性の例をあげる。

### idの場合

この場合だと、１つのhtml要素しか制御できない。

```javascript
<button type="button" id="download-button">ダウンロードする</button>


<script>
    // ボタンの表示・非表示を切替える
    const id = "download-button";
    const downloadButton = document.getElementById(id);
    if(isFileDownloadable === false){
      downloadButton.disabled = true;
    } else {
      downloadButton.disabled = false;
    }
</script>
```

### classの場合

複数の同名のhtml要素を制御できる

```javascript
<button type="button" class="download-button">ボタン1</button>
<button type="button" class="download-button">ボタン2</button>
<button type="button" class="download-button">ボタン3</button>

<script>
  // ボタンの表示・非表示を切替える
  const name = "download-button";
  //　getElementsByClassNameで取得すると配列として格納される
  let buttons = document.getElementsByClassName(name);
    for(let i=0;i<buttons.length;i++){
      if(isFileDownloadable === false){
        buttons[i].setAttribute("disabled", true);
      } else {
        buttons[i].removeAttribute("disabled");
      }
    }
</script>
```
SSIMオートエンコーダでMVTecADのボトルを学習

# SSIMを構築して結果を確認した

ここでMVTecのbottleを使用してSSIMオートエンコーダでの検証を行う。
https://www.mvtec.com/company/research/datasets/mvtec-ad

# 前回はMVTecADのタイルを使用した
しかしながら、結果は上手く復元することが出来ず判別には利用できそうにもない。
ここで、改めてMVTecソフトウェア社の論文から参照すると

・提供されるデータはオブジェクト系とテクスチャ系に分けられる
・テクスチャ系とは木目やタイルなど同じ系統だが分布がランダムなものを示す
・オブジェクト系とは工業製品等の同じ位置で撮影されるようなデータを示す。
・SSIMオートエンコーダはテクスチャ系には弱い

とある。


ではオブジェクト系ではどうなるのかをここで検証する。


正常の入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3079535/dba9cc28-2984-cdc9-e1b3-e6fefe057153.png)


異常の入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3079535/63279073-7fc0-af99-bfaf-9569cfbd723d.png)


とする。
googlecolabのGPUを使用するので、グレースケール変換して実行する。

## 結果
図の見方
縦軸　上から入力、出力、差分となっている
横軸　枚数　となっている

### 正常

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3079535/5c3d7ef4-76c3-4ba2-ebd5-83968dc0145b.png)



### 異常

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3079535/f1ba1b6e-c520-76f5-08a3-8631d6487543.png)


## 結果
ものすごい薄いので画像を０，１にしてみる。
 sabun = cv2.threshold(sabun, 45, 255,cv2.THRESH_BINARY)
この一文を追加してみる。
重要そうなのは閾値

### 正常

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3079535/7d998965-19d1-d09e-82a8-813c3d787833.png)


### 異常

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3079535/405ca579-182d-4630-48fe-3da40cb9eb61.png)

これをみると異常と正常の出力がいかに違うかが分かると思う。
後は１の画素数とかを調べれば閾値がだせる。

しかしながら細かいものとか(下図の左から二番目の画像は中心に異常個所があるが、うまく取り出せていない。
異常が大きい箇所ではくっきりと形状が分かるくらいにはなっている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3079535/5709d4c2-89bb-81f3-9742-4a9115f41c43.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3079535/4f8a201b-fa90-a490-48ec-db48d6903e44.png)
【React】クローンしたコードでのエラー

AWS codecommitからクローンしたコードで
`モジュール 'react' またはそれに対応する型宣言が見つかりません。ts(2307)`と出力される

* 原因
node_modulesがフォルダ内に存在しないため
pushする際、node_modulesは除外するように設定しているため、クローンした際含まれていないことになる

* 解決策
npm installを実行し、node_modulesを追加する

この後
```typescript
 <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
........
```
に赤い波線がでて、`モジュール 'reactまたはそれに対応する型宣言が見つかりません`と問題が出力された場合

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884542/4894a62a-8722-9df3-5051-2854b4327cc8.png)
赤〇のところをクリックして、`バージョンの選択`、`node_modules\typescript\lib`を選択することでエラーは出力されなくなった。
Javascript初心者の勉強ログ（クイズゲーム編 前編）

# はじめに
こんにちは！

フロントエンジニアになって４ヶ月。
そろそろ職場にも慣れてきたので、本格的にJavaScriptの勉強を始めたいと思っています。

今まで、プログラミング学習アプリや本などで基本的な文法は学習していたのですが
実際コードを書いて何かを作ったことはありませんでした。
（業務でも過去のコードを流用したり修正したりすることはあっても
自分で1から書くことはなかった...）

簡単なものからチャレンジしつつ、
一人前のフロントエンジニアになれるようにスキル向上を目指します。

その学習の記録をQiitaに残していこうと思います。
私と同じように、「JavaScriptの基本文法は学習したけど、次何したら良いのかわからない」
と感じている人の参考になれば嬉しいです。

# 何を作るのか
とはいえ、いきなり自分でスラスラかけるわけもなく。
まずはYoutubeでJavaScriptの解説をしている方の動画を参考にしながらコーディングしていこうと思います。
今回はセイト先生という方が解説している「クイズアプリ」を作ってみることにしました！
参考：[セイト先生のWeb・ITエンジニア転職ラボ【JavaScript超入門講座】基礎文法だけでクイズゲームのアプリを開発！](https://www.youtube.com/watch?v=fAluwAmHrws)

ただ、せっかくクイズアプリを作るなら、フロント関連の内容にしたいと思い、
クイズ内容はオリジナルにしています。

前編では動画を参考にベースを作り、
後編で解答の解説を入れるなど
アレンジできたらなーと思っています。

## 見た目
![スクリーンショット 2022-12-26 15.36.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982270/5ac6dc1f-d610-3423-bb3b-4370fdbd9726.png)
あくまでJavaScriptの学習なので見た目はこだわっておらずアレですが、
最終的にはいい感じに仕上げたいです。

（動画ではスタイルを当てるのにBootstrapを使用していますが、
後々、色々アレンジを加えることを考えて今回は使用していません。）

質問文の前に「問題１.」とかも入れたいですね。


# 今回のコード
コードの解説は参考の動画を見ていただければ、わかりやすく解説してくださっているので、ここでは省略します。



<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="ExpNoOX" data-user="n-ogata" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/n-ogata/pen/ExpNoOX">
  Untitled</a> by nao (<a href="https://codepen.io/n-ogata">@n-ogata</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## 今回の学習ポイント
コーディングを始める前に設計をする！

**画面設計図**
見た目の設計図。
私の場合、デザイナーさんからFigmaなどを使ってデータをもらいます。
機能や動きなどの詳細が書き込まれています。

**フローチャート**
プログラムのロジックと処理の流れを書く。
プログラミングを書くうえでとっても大事な工程だと思います。
動画では書き方までは解説されていないので、
私は[ざっくりわかる！プログラミングのためのフローチャートの書き方](https://eng-entrance.com/programming_flowchart)を参考にしてみました。

## 今回使ったアレコレ
**メソッド？プロパティ？**
- document.getElementsByTagName('タグの名前')
タグの名前を取得する

- document.getElementById('id名') 
指定したid属性がついている要素を取得する

- .textContent
そのHTMLが持っているテキスト情報を取得する

- .addEventListener('イベント名', イベントが起こった時に実行する処理）
クリックされたら〜する、など

- window.alert('アラートに表示させるテキスト');
アラートウィンドウを表示する

- .length
文字列：文字数の長さを取得する
数値：基本的には使えない。文字列と連結すると長さを取得できるようになる
配列：配列の要素数を取得する
参考：[【JavaScript入門】lengthで文字列や配列の長さを取得する方法](https://www.sejuku.net/blog/22120)

- e.target
e：イベントのオブジェクト
イベントはいろんな情報を持っており、それをオブジェクトとして持っている。
target：イベントのオブジェクトの中にある情報のうち、そのイベントが起こった要素

## コーディングのコツ
:::note info
- 同じコードが出てくる時は変数・定数にする
- HTMLのオブジェクトを変数に入れるときは、変数名に＄をつける
- 何回も出てくる処理は一つにまとめる（リファクタリング）
　ループ処理（while文）などを使ってコードをまとめ、関数として定義する。
コメントでどんな処理をしているのか説明をつけておくとわかりやすくなる。
- どんなケースでも対応できるように柔軟性を持たせる
- 配列の中にはオブジェクトも配列も入れることができる
:::
OpenSSHの踏み台経由での接続用config Windows10, VSCode, RemoteSSH

# 環境
### Windows端末
Windows10
OpenSSH_for_Windows_8.1p1, LibreSSL 3.0.2
VSCode Version 1.74.3
VSCode extension Remote - SSH v0.94.0 

### 踏み台サーバー
Debian GNU/Linux 10 (buster)

# ~/.ssh/config

``` config
Host jumpserver
    Host your.jumpserver.host
    User youruser
    port 22
    IdentityFile yourpath/.ssh/id_rsa
    PubkeyAuthentication yes

Host * !jumpserver
    User youruser
    port 22
    ProxyCommand ssh -F yourpath/.ssh/config -W %h:%p jumpserver
```

- yourがつく部分を書き換えてください。
- IdentifyFileはIdenti**ty**Fileとタイポしがちなので注意
- IdentiryFileのセパレーターは/でもかけます。configファイルを違うOSで使いまわすことは少ないと思いますがスラッシュで書く方が汎用性が高いと思われます。
スラッシュ：`C:/yourpath/.ssh/id_rsa`
バックスラッシュとダブルクオーテーション囲み：`"C:\yourpath\.ssh\id_rsa"`
- `Host * !jumpserver`はjumpserver以外のホストへの接続に以下の設定を適用することになります。github.comなどは外したいこともあると思うのでその場合は`Host * !jumpserver !github.com`などとスペース空けで書けばOKです。
- ProxyCommandの部分は次のように`ProxyJump your.jumpserver.host`で書くこともできます。cmdやPowerShellからsshする場合はどちらでも特に問題ないです。ただ、pythonを利用してProxyJumpを書いたconfigでSSHしようとすると自動で補完されるProxyCommand内で-FオプションのパスがセパレーターなしになってしまうためProxyCommandで明示的に指定しています。
```
ProxyCommand("ssh -F yourpath.sshid_rsa config -W host:22 your.jumpserver.host") 
returned nonzero exit status: ソケット以外のものに対して操作を実行しようとしました。

```
- `ProxyJump jumpserver`とするとハングしてしまったので、ここでは名前解決できる形式で記載する必要があります。

# cmd, Powershellでのコマンド
```
ssh your.host.ip.or.hostname
```
シンプルにこれだけです。うまくいかない場合は`-v`をつけてログを確認して進めると原因がわかりやすいです。

いろいろ試しているうちに`:22`とポート番号を指定してコマンドを実行していたら以下のようなエラーが出てきました。
```
> ssh your.host.ip.or.hostname:22

channel 0: open failed: connect failed: Name or service not known
stdio forwarding failed
kex_exchange_identification: Connection closed by remote host
```

# はまったポイントのメモ等
- `Permission denied (publickey).`のエラーはパスの指定ミスが原因でした。最後に/configや/id_rsaが抜けていたり、スラッシュやバックスラッシュに注意。
- VSCodeで設定するRemote SSHのConfig Fileはスラッシュ形式`C:/yourpath/.ssh/id_rsa`で書く必要があります。Windowsのエクスプローラーからコピペするとエラーが出てしまいます。
- Windowsではドット始まりでも隠しフォルダにはならない。
- portは指定ておく方が安心です。
- 今回は使いませんでしたが[OpenSSHの公式ドキュメント](https://man.openbsd.org/ssh_config)によるとMatchを使ってもホストを指定できるようです。


以上です。SSHでてこずるとかなりストレスを感じると思うので誰かの助けになれば幸いです！
Wordpressの更新で「ファイルをコピーできませんでした。」エラーが出る原因

# 発端
WordPressの更新で「ファイルをコピーできませんでした。」というエラーが出たので、オーナーかパーミッションだろうと高をくくって色々していたんですが一向にエラーが消えなくて小一時間ハマった話です。
![wp_error_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93880/9e61371e-2723-afaf-41f9-532e68b87bf6.png)
# 環境
CentOS7 + PHP7.4 + nginx + php-fpm
# 原因
何回もオーナーやパーミッションを変更してちょっと疲れ始めたときに、そもそもここで動いているPHPってちゃんとnginxオーナーで動いてるのか？と疑問を持ちました。

nginxのオーナー
```/etc/nginx/nginx.conf
user  nginx;
worker_processes  auto;
```

大丈夫ですね。

で、今回はPHPはPHP-FPMが動いているのでphp-fpmの方も見ます。

```/etc/php-fpm.d/www.conf
  ～中略～
; RPM: apache user chosen to provide access to the same directories as httpd
user = apache
; RPM: Keep a group allowed to write in log dir.
group = apache
```

apacheやん!! nginx+php-fpmなのにapache・・・ダメダメでしたorz

ということでnginxに修正します。
```/etc/php-fpm.d/www.conf
  ～中略～
; RPM: apache user chosen to provide access to the same directories as httpd
user = nginx
; RPM: Keep a group allowed to write in log dir.
group = nginx
```

そしてphp-fpmを再起動
```
# systemctl restart php-fpm
#
```

そして再度プラグインを更新
![wp_ok_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93880/0acd1544-5a5e-8ec1-8012-0cae5b8fde87.png)

やっと更新できた・・・。

久しぶりに触ってコロッと忘れていたんですが、このサイトは元々Apacheで動いていたものを移植したのでした。
そのことが頭からすっぽり抜けてしまっていたのでこんなことになったという顛末でした・・。

しょーもない原因でハマったのですが、また忘れそうなので備忘として書いておきます。
PHPバージョンアップについての覚書


PHPをXAMAPP上でバージョンアップするには
結局のところXAMPPをバージョンアップしないといけない

1) XAMPPサイトでダウンロード（Windows・Mac・Linuxの3バージョン）

https://www.apachefriends.org/jp/index.html

2)削除前にphp.iniの設定は保存しておく。(ほかのファイル名で）

3）元のXAMPPのフォルダで「uninstall...exe」というのがあるのでそれを実行するか
なければ、XAMPPから始まるファイルごと削除　（必要ならバックアップをしてください）

4）ダウンロードしたものを解凍して実行、ドライブ直下におく　WindowsはCでもDでもOK

5)　終わったら、php.iniの設定を元のファイルの設定に戻す

6）私の環境の場合、COM関数が必要だったので、ないとエラーを起こす
　（Fatal error: Class COM not found in ～）
　=>詳しくはこちらを確認してください（ありがとうございます！）

https://b.0218.jp/20130110131343.html

まあ要するに、phpの仕様で、php.iniのDynamic Extensionsのところに`extension=php_com_dotnet.dll`を追加しないとだめ、ということ。

7）これにて終了。コマンドスクリプトで、`php -v`して出てきたらOKです。
　もし出てこないなら、環境変数にphpのフォルダパスを追加しないといけない。（私の場合はなくても大丈夫だった）

なんかあればまた追記します。
pythonデータセットインポート（範囲の指定の方法）

## 必要なデータを作成する。
エクセルファイルや、CSVファイルからデータを読み込んでもよいが、
今回は、データの作成から行ってみます。
架空のアイドルチームと髪の毛の色のデータを作成していきます。
```python
list1=[["purple","yellow","red"], ["indigo","Light blue","pink"], 
       ["black","red","black"],["white","bright green","gold"],
       ["pink","purple","green"],["skyblue","pink","green"]]
index1 = ["チーム1", "チーム2", "チーム3","チーム4","チーム5","チーム6"]#行
columns1 =["1人目", "2人目", "3人目"]#列
dataset = pd.DataFrame(data=list1, index=index1, columns=columns1)

dataset
```
以下のように出力されます。
||1人目|2人目|3人目
|-|-|-|-|
チーム1|purple|yellow|red
チーム2|indigo|Light blue|pink
チーム3|black|red|black
チーム4|white|bright green|gold
チーム5|pink|purple|green
チーム6|skyblue|pink|green

## データの前処理いろいろ
ここで、分割するときに、ilocで指定する際に、iloc[〇,△]
〇は、行の指定を行い、△は列の指定を行う。
```python
X = dataset.iloc[:3,:].values
```
今回〇を「：3」、△を「：」とすることで、
〇は、最初の１行目から３行目までのデータを取得し
△は、「：」ですべての行のデータを取得することを意味している。

出力結果は以下のようになりました。
||1人目|2人目|3人目
|-|-|-|-|
チーム1|purple|yellow|red
チーム2|indigo|Light blue|pink
チーム3|black|red|black
```python
X = dataset.iloc[:-1,:].values
```
「最初から最後の１つ手前（チーム5）まで取得できます。」
||1人目|2人目|3人目
|-|-|-|-|
チーム1|purple|yellow|red
チーム2|indigo|Light blue|pink
チーム3|black|red|black
チーム4|white|bright green|gold
チーム5|pink|purple|green

```python
X = dataset.iloc[2:,:].values
```
「チーム3から最後まで取得することができます。」

||1人目|2人目|3人目
|-|-|-|-|
チーム3|black|red|black
チーム4|white|bright green|gold
チーム5|pink|purple|green
チーム6|skyblue|pink|green

# 今回の重要なこと

ここで、「:3」で最初から３つめまで、「:-1」で最初から最後を抜かしたところまで、
「2:」でチーム３から最後まで取得できることがわかりましたが、途中から途中までのデータを取得するには
と疑問に思いました。
今回のケースでは、チーム2、チーム3、チーム4、チーム5だけ取得したい場合の書き方については、
```python
X = dataset.iloc[[1,2,3,4],:].values
```
このように、[〇,△]の〇のなかにさらに、[]を入れ指定したい行を選択するとよい
（※ただし、先頭は、０から数えるため注意）
（※ほかに良い方法あり、記事の下部「追記２」に記載）

||1人目|2人目|3人目
|-|-|-|-|
チーム2|indigo|Light blue|pink
チーム3|black|red|black
チーム4|white|bright green|gold
チーム5|pink|purple|green

## まとめ
行を指定する際に、行の途中から途中までを取得したい場合には、
X = dataset.iloc[[1,2,3,4],:].values
[行,列]の行にさらに[]を入れ、２重構造にすれば、指定することができます。

追記）
Python形式でのコードチャンクがpythonのコードと
認識するためには、「```python」と書くことで認識をできました。
また、出力結果は、「|」を用い、表現することもできました。

追記２）
```python
X = dataset.iloc[1:5,:].values
```
上記のように、iloc[〇,△]にあたる〇の部分において、
1:5のようにすると、取得したい、
チーム2、チーム3、チーム4、チーム5の情報を得ることが可能になる。
Go言語オーバーライド例

**やりたいこと**
親structを取り込み子struct側のメソッドでオーバーライドさせます。

**親のみ**

```golang
// maing.go
package main

import (
	"fmt"
)

type Parent struct {
	NameParent string
}

func main() {
	c := Parent{"親"}
	c.Method()
}

func (p *Parent) Method() {
	fmt.Println(p.NameParent)
}
```

**結果**
親

**親を取り込みオーバーライド**
Parentをembeddedフィールドとして取り込み、Methodレシーバで値を操作する。

```golang
// main.go
package main

import (
	"fmt"
)

type Parent struct {
	NameParent string
}

type Child struct {
	Parent // embedded
	NameChild string
}

func main() {
	// 親の値を取得
	p := GetParent()
	// 親の値を子が取り込む
	c := Child{Parent: p, NameChild: "子"}
    // オーバライドのほうが呼ばれる
	c.Method()
}

func GetParent() Parent {
	p := Parent{"親"}
	return p
}

// 使われない
func (p *Parent) Method() {
	fmt.Println(p.NameParent)
}

// オーバーライド
func (c *Child) Method() {
	c.NameParent = "変更した親"
	c.NameChild = "変更した子"
	fmt.Println(c.Parent.NameParent + "の" + c.NameChild)
}

```

**結果**
変更した親の変更した子
バーチャルライツについて（更新）

内容が古く当時の状況とは変化があること、技術的内容との連関も薄れてきてしまった（特定の個人・組織の技術的影響力が落ちた）為、一旦記事内容を非公開としたいと思います。以後本記事の内容については、@aomicreateまで直接ご連絡をください。（鍵アカウントですが、DMは開放しています）
JANコードのチェックデジットを計算する


     JANコードのチェックデジットを計算する

    protected function calculateCheckDigit($code)
    {
        // JANコードの前12桁を取得
        $checkCode = substr($code, 0, 12);
        $sum = 0;
        for ($i = 0; $i < strlen($checkCode); $i++) {
            // 奇数桁は1、偶数桁は3をかけて足す
            $sum += (($i+1) % 2 == 0 ? 3 : 1) * $checkCode[$i];
        }
        // 総和の下1桁の数字を10から引く、10なら1の位は0なので、下1桁をチェックデジットとする
        $CheckDigit = (10 - $sum % 10) % 10;
        // チェックデジットが一致しない
        if ((int)$CheckDigit != (int)substr($code, 12, 1)) {
            return false;
        }
        return true;
    }
Pythonでフォルダ名やファイル名を一括変更

# 全てのファイルやフォルダの名前の後ろに文字を加える
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165847/64ff9abc-4a99-ad73-3f0a-64bfc4b29701.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165847/4c56f160-aafb-1b7b-2173-fed3b78406c9.png)

```python
import os
dir_path = "./dirname"
dir_list = os.listdir(dir_path)
for i in range(len(dir_list)):
    new_file_name = dir_list[i] + "様"
    os.rename(os.path.join(dir_path,dir_list[i]),os.path.join(dir_path,new_file_name))
```
# ファイル名やフォルダ名から特定の文字だけを変更・削除

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165847/4c56f160-aafb-1b7b-2173-fed3b78406c9.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165847/64ff9abc-4a99-ad73-3f0a-64bfc4b29701.png)

```python
import os
import glob

before_word = "様"
after_word = ""

files = glob.glob('*'+ before_word +'*')
for before_file_name in files:
    after_file_name = before_file_name.replace(before_word,after_word)
    os.rename(before_file_name,after_file_name)
```

もっといいやり方があったら教えてくださいm(_ _)m
【GoogleChrome】特定のブックマークフォルダ内のURLを一括コピーする

# したいこと
Chromeの特定のブックマークフォルダ内にある全てのURLを一覧的にコピーする（エクスポート機能を使わずに）。
# 方法
1. ブックマークマネージャにアクセス
    * `chrome://bookmarks`  にアクセス
    * `Ctrl`+`Shift`+`O` を押下
    * 右上の「︙」 > 「ブックマーク」 > 「ブックマークマネージャ」
2. 該当のブックマークフォルダを開く
2. Ctrl+Aを押下
2. Ctrl+Cまたは右クリックからコピー
2. 完了
PL-900：顧客ケース スタディ - TruGreen

この投稿はMicrosoft PL-900の受験に向けた勉強資料をMS Learnページを参考にして作っています。
一発合格に向けて頑張りましょう！

[顧客ケース スタディ - TruGreen][MS-Learn]

[MS-Learn]: https://learn.microsoft.com/ja-jp/training/modules/introduction-power-automate/3-customer-case-study-trugreen

## TruGreen がすべてのデジタル変換に着手
* TruGreenは、お客様に「live life outside」に必要なものを提供するというTruGreenの取り組みの一環として、Microsoftと提携している
→　この目標への一歩として、Power Automateを含むMicrosoft Power Platformを統合してお客様にプロアクティブで予測的なサービスを提供すること

デジタル変換戦略の情報に関しては以下を参照
<img src="https://learn.microsoft.com/ja-jp/training/modules/introduction-power-automate/media/trugreen-info-graphic.png" />

* より良いサービスを提供するために、新しい人工知能対応仮想エージェントボットをノーコードで構築　→　Power Virtual Agents
→　お客様の日常的な要求の処理を容易にし、お客様の意図に基づいてアクションを実行するため
* 必要なバックエンドデータの公開および操作にPower Automateを使用
* Microsoft Power Platformでコネクタの一部を使用し、従来のデータソースに接続した
    * その結果、ノーコードで初期プロトタイプを2日で作れた！
* コネクタのAPIを持っていないシステムはデスクトップフローを使用
    * カスタマーサービス側が手動で操作していた画面上での作業をRPAを介して自動化することができた
    →　顧客満足度とビジネス価値を向上し続けるための最初のステップにすぎない
    (発展可能なことがもっとあるということ！)

:::note info
フローの2つのタイプとPower Automateの開始方法に関するデモ ビデオ
[Power Automateのフローと開始方法について][MS-Learn2]

[MS-Learn2]: https://learn.microsoft.com/ja-jp/training/modules/introduction-power-automate/4-power-automate-action
:::
[AWS学習]VPC（ネットワーク）

## VPC（Virtual Private Cloud）
ネットワーク環境を提供しているサービス

・AWS上に、利用者ごとのプライベートなネットワーク空間を提供
・外部ネットワークと接続も可能

## VPCを構築するステップ
### 1.VPCの作成
・リージョンを選択
・ネットワーク空間の範囲（CIDRブロック範囲）を指定する

例） 10.0.0.0/16

### 2.サブネットの作成
・サブネット　＝　VPCを分割したモノ
・サブネットごとにサーバーの役割/機能に応じて作ることが望ましい
・1つのAZを指定する（複数のAZにまたがって作成できないため）
・「故障に備えた設計で障害を回避」を実現するため、サーバーを各AZに冗長的に配置するのが一般的

### 3.ゲートウェイの作成
ネットワーク間の通信を中継する仕組みの総称

#### IGW（インターネットゲートウェイ）
インターネットとの出入り口になるゲートウェイ

#### VGW（バーチャルプライベートゲートウェイ）
オンプレミスとVPNや専用線で通信するためのゲートウェイ

### 4. ルートテーブルの設定
ルートテーブルによって、パブリックサブネットかプライベートサブネットかが決まる
ルートテーブル内のlocal設定は変更・削除不可。
→ VPC内のサブネットであればサブネット間の通信は可能

#### パブリックサブネット
インターネットとのアクセスを**許可する**サブネット
ルートテーブルにデフォルトゲートウェイ（送信先：0.0.0.0/0）が**適用されている**

#### プライベートサブネット
インターネットとのアクセスを**許可しない**サブネット
ルートテーブルにデフォルトゲートウェイ（送信先：0.0.0.0/0）が**適用されていない**

### 5. NAT（Network Address Translation）インスタンスの作成
プライベートサブネット内からインターネットにアクセスするための設定
例） プライベートサブネット内に作成したDBのバージョンアップを行いたい場合

#### NATインスタンスの仕組み
・実態はEC2インスタンス
1. プライベートサブネット内のEC2インスタンスからトラフィックを受け付ける
1. 受け付けたEC2インスタンスのプライベートIPアドレスを変換
1. NATインスタンスがインターネットへアクセスする

#### 送信元/送信先チェック
・EC2インスタンスは、デフォルトで流れてきたトラフィックがを自身のIPアドレス宛かチェックして、宛先が自身のIPアドレスでなければトラフィックを破棄する。
・NATインスタンスとして利用するにはこの機能をOFFにする必要がある

#### トラフィック
一定時間内にネットワーク上で転送されるデータ量のこと

## AWSのグローバルIPアドレスの種類
### Public IP
動的なグローバルIPアドレス
EC2インスタンスが起動した際にランダムに割り当てられる

### Elastic IP
固定のグローバルIPアドレス
アカウントに割り当てられる


## VPCが提供するファイアウォール機能
セキュリティグループとNACLがある

### セキュリティグループ
・インスタンス単位で適用
→ 各インスタンスには少なくとも1つのセキュリティグループを適用する必要がある
・デフォルトルール
インバウンド：全て拒否 → どこからのアクセスも受け付けてない状態
アウトバウンド：全て許可
・**ステートフル**
→戻りのトラフィックについて追加で設定が **不要**

### ネットワークACL（NACL）
・サブネット単位で適用
・デフォルトルール
インバウンド：全て許可
アウトバウンド：全て許可
・**ステートレス**
→戻りのトラフィックについてインバウンド/アウトバウンドの設定で許可しておく必要がある

### 用語
#### インバウンド
アクセス制御
受信
送信先のIPアドレスとアクセスを受け付けるポート番号のアクセスを許可

#### アウトバウンド
アクセス制御
送信
送信先のIPアドレスとアクセス先のポート番号へのアクセスを許可

#### ステートレス/ステートフル
こちらの記事がイメージつきやすかったので参照
[ステートレスとは](https://qiita.com/mtakehara21/items/efcbbc3ba58a62c10eb6)

## VPCピア接続
2つのVPCを接続する機能。
VPC間でVPCピア接続を確立させると、双方のVPCに **PCX** （ゲートウェイに相当するもの）が作成される

### VPCピア接続の制限
1. 接続するVPC同士が、同じリージョンの存在すること
1. プライベートネットワークアドレス空間が重複していないこと
1. 1:1の接続であること

A <-> B <-> C
の場合、AからCへの接続はできない。
したい場合あ、A <-> Cへピア接続させる必要がある

### 参考書籍
[合格対策 AWS認定ソリューションアーキテクト －アソシエイト](https://amzn.to/3XeEAjW)
今度の壁はphpMyAdminのログインだった --20年(？)ぶりにLinuxをいじってみる05

全8回の5 → [1](https://qiita.com/Kokusui/items/ba1aa8fa736dc2321e24)|[2](https://qiita.com/Kokusui/items/7ac23b2314898fef6181)|[3](https://qiita.com/Kokusui/items/757277b4e1fb28a3e476)|[4](https://qiita.com/Kokusui/items/9c0d50e3b782b1410a4c)|5|[6](https://qiita.com/Kokusui/items/701594d849fb7524f4ba)|[7](https://qiita.com/Kokusui/items/b6bfb6da52fdf16241a6)|[8](https://qiita.com/Kokusui/items/60fdbdf42fed2045e4f4)

やっとPHPインストールまで辿り着いた。
```
$ sudo dnf -y install php
```
からの
```
$ php -v
PHP 8.0.20 (cli) (built: Jun  8 2022 00:33:06) ( NTS gcc x86_64 )
Copyright (c) The PHP Group
Zend Engine v4.0.20, Copyright (c) Zend Technologies
    with Zend OPcache v8.0.20, Copyright (c), by Zend Technologies
```
でお決まりの
```
$ sudo systemctl restart httpd
```
で無事起動完了。
これ、`phpinfo()`で見るとServerAPIがFPM/FastCGIになっている。
モジュール版じゃあないんだね。
ググったんだがモジュール版をCGI版にする方法はたくさん見つかるんだが逆がない。
とりあえずそのまま。

ついでに
* php-gd
* php-mysqlnd
* mariadb
* mariadb-server
まではインストールできた。ここまでのスペック：
* Rocky Linux 9.0
* php 8.0.20
* MariaDB 10.5.16

さてphpMyAdminをインストールするにあたり、dnfではできない(みたい？)なので、
```
$ cd /var/www/html
$ sudo wget https://files.phpmyadmin.net/phpMyAdmin/5.2.0/phpMyAdmin-5.2.0-all-languages.tar.gz
$ sudo tar zxvf phpMyAdmin-5.2.0-all-languages.tar.gz
$ sudo rm phpMyAdmin-5.2.0-all-languages.tar.gz
```
までやって設置完了。そしてアクセスすると
> パスワードなしログインは設定 (AllowNoPassword 参照) によって禁止されています

という無慈悲なメッセージ。これについても調べたところ、挙動に関しては[こちら](https://qiita.com/mighty-n/items/8ec2bd5c140eee83d9b0)、対処法に関しては[こちら](https://nakatakeworks.jp/%E3%80%90phpmyadmin%E3%80%91%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89%E3%81%AA%E3%81%97%E3%81%A7%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%99%E3%82%8B/)を参考に。
```
$ cd /var/www/html/phpMyAdmin/
$ sudo cp config.sample.inc.php config.inc.php
```
と設定ファイルのバックアップをとっておいてから
```:config.inc.php:
// 変更前
$cfg['Servers'][$i]['AllowNoPassword'] = false;

// 変更後
$cfg['Servers'][$i]['AllowNoPassword'] = true;
```

とやってApacheを再起動、無事パスワードなしでログインができた。

さてログインしたら赤表示その1：
> 設定ファイルに、暗号化 (blowfish_secret) 用の非公開パスフレーズの設定を必要とするようになりました。

もう一度```config.inc.php```をいじる羽目に。
```:config.inc.php
/**
 * This is needed for cookie based authentication to encrypt password in
 * cookie. Needs to be 32 chars long.
 */
$cfg['blowfish_secret'] = ''; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
```
入れる文字列はなんでもよいので住所でもローマ字で入れてやろうかしらんと思ったらうまくいかない。直訳すると「32文字文字の長さが必要」とあって、実は32文字より多くても少なくてもダメというのがわかった。文字数数えるのめんどくさいわ。

赤表示その2：
> $cfg['TempDir'] (/var/www/html/phpMyAdmin/tmp/) にアクセスできません。phpMyAdmin はテンプレートをキャッシュすることができないため、低速になります。

これについては```config.inc.php```で```$cfg['TempDir'] = '/tmp/'```と書き換えるパターンと、phpMyAdmin/の権限を変える方法の2通りがあるようだが、phpMyAdminのディレクトリごと権限をApache.Apacheに書き換えて対応。

なんとかエラーメッセージが消えて一安心。
ネットワークが外へ出ていけない！ --20年(？)ぶりにLinuxをいじってみる04


全8回の4 → [1](https://qiita.com/Kokusui/items/ba1aa8fa736dc2321e24)|[2](https://qiita.com/Kokusui/items/7ac23b2314898fef6181)|[3](https://qiita.com/Kokusui/items/757277b4e1fb28a3e476)|4|[5](https://qiita.com/Kokusui/items/42ee26d7e8ad1a114b12)|[6](https://qiita.com/Kokusui/items/701594d849fb7524f4ba)|[7](https://qiita.com/Kokusui/items/b6bfb6da52fdf16241a6)|[8](https://qiita.com/Kokusui/items/60fdbdf42fed2045e4f4)

さて次はPHPのインストールなのだが…。
```
$ dnf info php
repo 'baseos' のメタデータのダウンロードに失敗しました : Cannot prepare internal mirrorlist: Curl error (7): Couldn't connect to server for https://mirrors.rockylinux.org/mirrorlist?arch=x86_64&repo=BaseOS-9 []
```
いろいろググったところ、CentOSだとリポジトリが使えなくなっててアクセス不能、という記事は見つけた。でも最新のRockyLinuxなんだけど…。
そもそもサーバーは生きてるんだろうかということで
```
$ ping mirrors.rockylinux.org
ping: connect: ネットワークに届きません
```
あれ？
```
$ nslookup www.google.com
Server:         192.168.10.10
Address:        192.168.10.10#53

Non-authoritative answer:
Name:   www.google.com
Address: 142.251.42.196
Name:   www.google.com
Address: 2404:6800:4004:821::2004
```
DNSは生きているらしい。
```
$ tracepath www.google.com
 1:  送信失敗
     Resume: pmtu 128000
```
これはなんだ？
アクセス元のPCからpingを打ってもtracertしてもちゃんと繋がる。
試しにルーターのIPを打ってみると
```
$ tracepath 192.168.10.10
 1?: [LOCALHOST]                      pmtu 1500
 1:  192.168.10.10                                         0.424ミリ秒 到達しました
 1:  192.168.10.10                                         0.343ミリ秒 到達しました
     Resume: pmtu 1500 hops 1 back 1
```
行ける。ということはルーターの設定か…？ とも思ったが別のマシンからだと普通に行けるんだからそうではなさそう。
いろいろ調べまくっていたら
```
$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.10.0    0.0.0.0         255.255.255.0   U     100    0        0 enp4s0
```
あ、これはうっかり。デフォルトゲートウェイが本当にデフォルトのままでしたとさ[^1]。
```
$ sudo nmcli connection modify enp4s0 ipv4.gateway "192.168.10.10"
$ sudo systemctl restart NetworkManager
$ ping -c 3 www.google.co.jp
PING www.google.co.jp (172.217.161.35) 56(84) bytes of data.
64 バイト応答 送信元 nrt12s23-in-f3.1e100.net (172.217.161.35): icmp_seq=1 ttl=116 時間=1.09ミリ秒
64 バイト応答 送信元 nrt12s23-in-f3.1e100.net (172.217.161.35): icmp_seq=2 ttl=116 時間=1.64ミリ秒
64 バイト応答 送信元 nrt12s23-in-f3.1e100.net (172.217.161.35): icmp_seq=3 ttl=116 時間=1.18ミリ秒

--- www.google.co.jp ping 統計 ---
送信パケット数 3, 受信パケット数 3, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 1.090/1.302/1.638/0.240 ms
```
ふう。
[^1]:前回IPアドレスを固定にしたときのエラーを回避してそのままだったというオチ。よくよく考えたら、インストール時に設定しておけばよかったんだな。
Apacheを起動してもブラウザから見られないという罠 --20年(？)ぶりにLinuxをいじってみる03

全8回の3 → [1](https://qiita.com/Kokusui/items/ba1aa8fa736dc2321e24)|[2](https://qiita.com/Kokusui/items/7ac23b2314898fef6181)|3|[4](https://qiita.com/Kokusui/items/9c0d50e3b782b1410a4c)|[5](https://qiita.com/Kokusui/items/42ee26d7e8ad1a114b12)|[6](https://qiita.com/Kokusui/items/701594d849fb7524f4ba)|[7](https://qiita.com/Kokusui/items/b6bfb6da52fdf16241a6)|[8](https://qiita.com/Kokusui/items/60fdbdf42fed2045e4f4)

Webサーバーはインストール時にApacheを(どうせNginxとか使わないし)入れていたので、まずはhttpd.confをいじってServerNameをIPアドレスにしておく。
```
$ sudo systemctl start httpd
```
行けたかな？
```
$ systemctl status httpd
● httpd.service - The Apache HTTP Server
     Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
     Active: active (running) since Mon 2022-12-05 20:17:14 JST; 4min 25s ago
       Docs: man:httpd.service(8)
   Main PID: 2001 (httpd)
     Status: "Total requests: 0; Idle/Busy workers 100/0;Requests/sec: 0; Bytes served/sec:   0 B/sec"
      Tasks: 214 (limit: 74497)
     Memory: 38.4M
        CPU: 186ms
     CGroup: /system.slice/httpd.service
             ├─2001 /usr/sbin/httpd -DFOREGROUND
             ├─2002 /usr/sbin/httpd -DFOREGROUND
             ├─2003 /usr/sbin/httpd -DFOREGROUND
             ├─2004 /usr/sbin/httpd -DFOREGROUND
             ├─2005 /usr/sbin/httpd -DFOREGROUND
             └─2006 /usr/sbin/httpd -DFOREGROUND

12月 05 20:17:14 localhost.localdomain systemd[1]: Starting The Apache HTTP Server...
12月 05 20:17:14 localhost.localdomain httpd[2001]: Server configured, listening on: port 443, port 80
12月 05 20:17:14 localhost.localdomain systemd[1]: Started The Apache HTTP Server.
```
行けたね。
あとは`/var/www/html/`に適当にファイルを置いてブラウザからアクセス。

…拒否られた。
調べてみたら[これ](https://qiita.com/S-Masakatsu/items/63b9e0e7a869d2aafc4b)か。

> デフォルトのファイアウォールの設定では、Webサーバーへのアクセスは許可されません。
そのため、Apacheを起動しただけでは外部からアクセスはできないので、ファイアウォールの設定を変更し、80番ポートのアクセスを許可します。
ファイアウォールの設定では、`firewall-cmd` コマンドを使います。

```
$ sudo firewall-cmd --permanent --add-service=http
success
$ sudo firewall-cmd --reload
success
```

<img src="https://drive.google.com/uc?id=1H5YNCE2HPhiiGyASnwdAu0YncObbHMtM" alt="スクリーンショット" width="400">

できた。
う～ん、こんなに面倒だったかな～。覚えてないや。

------
追記。これを忘れてた。
```
$ sudo systemctl enable httpd
```
MAAS（Metal-As-A-Service）でデプロイしたUbuntuを通常のKVM環境に移したときに変えた設定

一般的にマシンイメージをそのまま移行する際に必要になるデバイスまわりなどの設定は置いといて、下記2点について設定変更が必要となりました。
忘れそうなのでメモメモ📝

- 時刻同期（`/etc/systemd/timesyncd.conf`）
時刻同期先がMAASサーバになっているので再設定。

- aptプロキシの無効化（`/etc/apt/apt.conf.d/90curtin-aptproxy `）
MAASサーバがプロキシ指定されているので、下記のようにコメントアウト。
```
#Acquire::http::Proxy "http://192.168.0.1:8000/";
```
Lightning Login の有効化


[Lightning Login の有効化](https://help.salesforce.com/s/articleView?id=sf.security_ll_enable.htm&type=5)

Lightning Login を有効化すると、パスワードを使用しないログインによってユーザの速度、利便性が向上し、セキュリティが強化されます。Lightning Login を有効化し、必要な権限をユーザに割り当てたら、ユーザに対して、このパスワードを使用しないログイン機能に個別に登録するように促します。



# 参考資料

+ https://sfdcpenguin.com/blog/lightning-login-what-is-it-and-how-do-i-use-it/

+ https://automationchampion.com/2021/01/17/two-factor-authentication-in-salesforce-via-lightning-login/
Azure Administrator(AZ-104)：Azure での ID とガバナンスの管理「Azureサブスクリプション」

Microsoft Learnを用いたMicrosoft Azure Administrator(AZ-104)の試験内容をまとめる投稿です。
この投稿ではMicrosoft Learnで学ぶ内容をできるだけ簡潔にまとめております。
Azureの勉強を一から始め、AZ-900取得後の資格としてAZ-104取得を目指している方の参考になれば幸いです。
※AZ-900の内容は本投稿では省略しております。再度復習したい方は下記をご参照ください。
[Azure Fundamentals(AZ-900)：試験合格に向けた学習内容のまとめ](https://qiita.com/fsd-jume/items/e4ec76959adb547ac5e8)

## 今回の学習内容
**◆「Azureサブスクリプション」**
◇対応するMicrosoft Learn ラーニングパス
[AZ-104:Azure での ID とガバナンスの管理](https://learn.microsoft.com/ja-jp/training/paths/az-104-manage-identities-governance/)
◇対応するモジュール
[Azure サブスクリプションを実装する](https://learn.microsoft.com/ja-jp/training/modules/configure-subscriptions/3-implement-azure-subscriptions)

※前回の投稿は下記から確認できます。
[Azure Administrator(AZ-104)：Azure での ID とガバナンスの管理「Azureリージョンペア」](https://qiita.com/fsd-jume/items/74c8f56f269d9f1f8fd2)

## Azureサブスクリプション
### Azureサブスクリプション
・すべてのリソースがサブスクリプションに属する
⇒サブスクリプション単位のリソースへのアクセス制御が可能
・サービスの課金はサブスクリプションごとに実施
⇒請求/支払いの方法を設定可能
・クラウドサービスをプログラムで操作する場合に、サブスクリプションIDが必要な場合がある

### Azureサブスクリプションの構成
・1つ以上のAzureアカウントとリンクしている
　-必ず1つの管理者アカウントが存在
　-管理者アカウント以外のAzureアカウントはアクセス権を付与される形でリンク
・Azure AD(テナント)と信頼関係がある = 認証で使用可能
　-1つのAzure AD(テナント)は複数のサブスクリプションと信頼可能
　-複数のAzure AD(テナント)は1つの同じサブスクリプションと信頼不可
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851723/d7560625-c05f-7477-0eb5-af67de6566a3.png)

### Azureサブスクリプション使用時の考慮事項
**◆必要なAzureアカウントの種類を検討**
・ユーザがサブスクリプションとリンクさせるAzureアカウントを検討
・リンク可能なAzureアカウント
　-Azure ADアカウント(職場または学校のアカウント)
　-Azure ADで信頼された個人のMicrosoftアカウント

**◆複数のサブスクリプションを検討**
・部門や用途によって異なるサブスクリプションと支払いオプションを設定
・ユーザに複数のサブスクリプションをリンク可能

**◆共有サービスを専用のサブスクリプションにすることを検討**
・共有サービス用のサブスクリプションでリソースを共有
⇒すべての共通ネットワークリソースがまとめて課金され、他のワークロードと分離可能
例：Azure ExpressRoute、Virtual WANなど

**◆リソースへのアクセスを検討**
・すべてのサブスクリプションをAzure ADと関連付け可能
⇒ユーザ/サービスはリソースアクセス前にAzure ADで認証

## 次の学習内容
**◆Azureサブスクリプションの取得方法**

https://qiita.com/fsd-jume/items/7fa8e96bef77a85b7e36

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/6eda24728c9c03c36bc3
クロス集計表を作成する2＊1_度数(SPSS Modeler データ加工逆引き11-6)

# クロス集計表を作成する（2＊1_度数の集計表）

![スクリーンショット 2023-01-18 18.06.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/a87e4839-e845-08e1-0d8e-e686ed0a40f6.png)

## 1.想定される利用目的

・データ理解のためのレコード度数分布確認
・固定帳票の作成


## 2.サンプルストリームのダウンロード

https://github.com/yoichiro0903n/blue/blob/main/cross_tabulation2_1f.str?raw=true

## 3.サンプルストリームの説明

![スクリーンショット 2023-01-10 15.21.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/d748b9ea-0847-f6cb-ddfc-d1fb5985793a.png)

a.入力するデータは以下の通りです。
![スクリーンショット 2023-01-10 15.25.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/6a3ee1b3-3395-601f-47bd-e9d72d72bb77.png)

b.[再構成]ノードを以下のように編集します。[年代]を[再構成フィールド]に移して[値フィールド]はブランクのまま[数値フラグを作成]を選択します。
![スクリーンショット 2023-01-10 15.29.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/e68b0fb5-255e-6124-0cab-9a3a20f91f20.png)

[プレビュー]します。
![スクリーンショット 2023-01-10 15.30.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/d5834502-325b-2327-7472-2144c0d1e3ca.png)

c.[レコード集計]ノードを以下のように編集します。
![スクリーンショット 2023-01-10 15.26.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/da840b78-8522-30d5-b677-8c9881a67af0.png)

d.[ソート]ノードを以下のように編集します。
![スクリーンショット 2023-01-10 15.26.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/f8efb2a1-949a-2bd8-0188-6dd2628da1fc.png)

[デーブル]ノードを実行します。
![スクリーンショット 2023-01-10 15.27.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/952f262b-1132-9fa2-3a6a-3571bb4f803b.png)

#### 注意事項

[再構成]ノードで列に展開するメンバーが表示されないときは前方でデータ型の[値の読み込み]を実行します。
フィールド名は適宜[フィルター]ノードで変更します。

## 4.参考情報

####  SPSS Statistics Custom Tablesと連携して多重クロス集計を作成する

https://www.ibm.com/blogs/solutions/jp-ja/spss-stats-tips-06/

####  カテゴリ値を列に展開してIDで集約　縦持ちを横持ちへ

https://qiita.com/416nishimaki/items/2519553c7cce0fc0b0e0

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/private/4bf813e6cba84b2a1008
Axios メモ

Axiosに関するメモです。

主に、requestからaxiosに書き換える場合を想定しています。

requestとrequest-promiseはdeprecatedになってから久しいので、使っては駄目。
もし利用しているコードがあったら速やかにテストを書いて、別のモジュールに載せ替えて元のコードは捨てること。


# ライブラリリンク

## request
This package has been deprecated
https://www.npmjs.com/package/request

## request-promise
This package has been deprecated
https://www.npmjs.com/package/request-promise

## Axios
Promise based HTTP client for the browser and node.js
https://axios-http.com/


# Request リクエスト

基本的にはドキュメントが全て。
下記に記載するのはあくまでメモなのでそのまま利用しないこと。

基本的には特に難しいことはなくて、ライブラリをインストールしたらコードの先頭で読み込みして下記のようにするだけ。


`axios(config);`

ドキュメントには`axios.post`などの記載があるが、基本的にはエイリアスなのでconfigの設定を覚えておけば問題ない。


# config コンフィグ

axiosでリクエストするには、このconfigの設定を正しく行うことが全て（と個人的に思います）。

https://axios-http.com/docs/req_config

主なものを記載。
※必須と記載したものはあくまでも`axios(config)`の記述方法の時に必須となること。

## url
必須
フルで記載しても良いが、baseURLと一緒に使っても良い。

## method
リクエストメソッド。
getの場合は不要（defaultがget)
リクエストメソッドは、実際にはAPIサーバーがどのメソッドを受け入れるかで違うので、データを取得するだけでも`post`ということはあり得る。

## headers
リクエストヘッダー

```
headers: {}
```

APIサーバーにより必要なヘッダーを指定。

## data
データ

```
data: {}
```

基本的にはここにリクエストする際に必要なデータを乗せることになる。


# Response レスポンス

https://axios-http.com/docs/res_schema

レスポンススキーマを参照。

```
{
  data: {},
  stasus: 200,
  headers: {},
  config: {},
  request: {}
}
```

上記のような感じで、データは`data`の中に入ってくる。
デフォルトはJSONなので、よしなにパースしてJSのオブジェクトに変換して利用する。


# 利用例

Exampleを参照。
https://axios-http.com/docs/example

axiosというか、他のライブラリも大体同じと思うが、基本的にはNode.js(JS)の場合は非同期リクエストになるので、レスポンスはPromiseが戻ってくる。

基本的にはPromiseチェーンではなくて、`async/await`で良いと思う。

下記はドキュメントをそのまま記載しているが、基本はそのまま使える。
（エラー処理はAPIサーバーの仕様により対応する必要はある。）


```
async function getUser() {
  try {
    const response = await axios.get('/user?ID=12345');
    console.log(response);
  } catch (error) {
    console.error(error);
  }
}
```

# テスト

テストを書くには、APIサーバーに接続する部分と、データを準備する部分、最終的にリクエストをする部分とだいたい3つの関数に分けると良いかと思う。

テストには`Jest`などを利用する。
https://jestjs.io/ja/