OmniAICreator/Qiita-1.07M huggingface dataset:
WindowsでEtherCATと通信してみる(1)


この記事は・・・同人誌になるかもしれません。主に同人誌向けのネタメモです。
何回か続きます。（多分）

## ■　開発の事前準備（Windows）

### ◇ Visual StudioのC++コンパイラをインストール

https://visualstudio.microsoft.com/ja/vs/features/cplusplus/
Community　2019 でOK。
※再起動が必要です。

### ◇ cmake のインストール
https://cmake.org/download/

### ◇ Npcap のインストール
https://nmap.org/npcap/
Npcap 1.50 installer

## ■　SOEMの環境構築

今回ご紹介するライブラリは、Simple Open Source EtherCAT Master (略してSOEM )という、ほぼ標準的な位置にありますライブラリを試したいと思います。
Githubより、以下のリポジトリをクローンしてきます。


git clone https://github.com/OpenEtherCATsociety/SOEM.git
cd SOEM
mkdir build
cd build
cmake .. -G "NMake Makefiles"
nmake



## ■ slaveinfoを試してみる。

slaveinfoを試してみたいと思います。Windowsで実行する際はクセがあります。

実行はコンソールで行いますが、権限などの関係で「Visual Studioに付属している Developer Command Prompt for VS 2019」を使用します。
※これはなぜ？　良く分からないけど、管理者権限よりも上の権限で実行されるみたいです。


![スクリーンショット 2021-09-01 011503.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12499/2c2355b6-4b6c-3940-62ac-6afd1c439ad2.png)


以下のディレクトリへ移動します。（linuxと書いてあるけど仕様みたい）

cd .\test\linux\slaveinfo\

ディレクトリの中にexeがあるいので、それを実行します。

.\slaveinfo.exe 

実行すると、警告ダイアログが表示されます。（権限が厳しくなった？）
はいを押すと実行されます。
![スクリーンショット 2021-08-31 222101_LI (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12499/de89265d-fdd5-d3de-20a2-378ad73dccb1.jpeg)

セキュリティ意識少し高い系なので、雑に隠しましたが、PCに接続されたNICが表示されます。

.\slaveinfo.exe  \Device\NPF_{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}

のように、後ろにNICを入力すると、そのNICカードに対して実行されます。

上手くいくと、以下のような出力がされます。

![スクリーンショット 2021-08-31 230423.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12499/2da561ed-4c56-dc34-c6fa-0b866809647a.png)

次回、もう少し詳しく。
Makeコマンドを使うための設定方法 (Windows10)

Windows10でMakeコマンドを使う必要があったため備忘録として記載します。

##Make 公式サイト
URL:http://gnuwin32.sourceforge.net/packages/make.htm

##手順
■公式サイトのDownloadから「Complete package,except source」(赤枠)をクリックする。するとページが切り替わりインストーラがダウンロードされる。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/aac7d83a-1da7-38be-a825-9485322f4d9d.png)

【インストーラ　⇓】
![画像2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/d0779e0c-e689-35b0-5db8-38dff4e4e6ed.png)

■インストーラをクリックすると、ウィザード画面が立ち上がる。
![画像3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/6ab2df0f-83ff-ae1b-f99b-b31316e6b536.png)

■同意して「Next」をクリックする。
![画像4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/9ef12f1e-cb10-534f-2e08-d863df6debaa.png)

■パスは忘れやすいのでメモしておくこと。
![画像5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/a029e962-f3e8-cfa7-6356-5ff0d6927797.png)

■デフォルトのままで「Next」をクリックする。
![画像6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/6e6faa10-0560-06ad-d3f6-ea52ebc8e4d6.png)

■デフォルトのままで「Next」をクリックする。
![画像7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/03a792a4-d756-da5e-756f-d1164daaa862.png)

■デフォルトのままで「Next」をクリックする。
![画像8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/27039d0f-a1e6-1984-a704-c404a8be7a91.png)

■「install」ボタンをクリックする。※インストールにかかる所要時間は約数秒で終了する。
![画像9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/df23b88f-82fd-d21e-c151-d01bff589f44.png)

■正常にインストール出来たら完了画面が表示される。
![画像10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/2174f0c0-415f-97a4-cfe4-48d4284fba84.png)

■環境変数の登録をして完了。以上です。
kaggle machine learning basic

kaggle のラーニングを受けて理解を深めるための記事
マシンラーニング初心者向け

使用データHousing Prices Competition for Kaggle Learn Users
https://www.kaggle.com/c/home-data-for-ml-course

まずは基本のデータ読み込み、モデル作成、予測、評価、投稿データ作成について

データ読み込み

まずは上記リンクからデータダウンロード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/935742/6bcb3d8b-4f8c-6ba1-3c69-cc3e5dc02e04.png)

test.csv  train.csvのみでまずは十分

使用ライブラリ
import pandas as pd
from　sklearn.model_selection import train_test_split
from　sklearn.ensemble import RandomForestRegressor
from　sklearn.metrics import mean_absolute_error


データの読み込み
X_full = pd.read_csv('train.csv', index_col='Id')
X_test_full = pd.read_csv('test.csv', index_col='Id')

X_test_full はあとで使うのでとりあえず放置

X_full で予測、評価まで実施

X_fullのなかからSalePriceをyに入れ込む、
これをトレーニングデータの予測値とする
y = X_full.SalePrice

予測データ作成
今回はお試しの予想なので、数値データの都合のいいものだけ抜き出し。

features = ['LotArea', 'YearBuilt', '1stFlrSF', '2ndFlrSF', 'FullBath', 'BedroomAbvGr', 'TotRmsAbvGrd']

この7つを抜き出し訓練データXとして使う
X = X_full[features]　
Featuresの中に7個の列名が入っているのでこれでXに抜き出されたデータ格納

X_train, X_valid, y_train, y_valid = train_test_split(X, y, train_size=0.8, test_size=0.2,random_state=0)

訓練データを分割して訓練データ、テストデータとする

モデル作成及びトレーニング
model = RandomForestRegressor(n_estimators=50, random_state=0)
model.fit(X_train, y_train)
preds = model.predict(X_valid)

ここでmodelとしているが名前は何でもいい、fit,modelの前の名前があっていればOK
今回はランダムフォレスト使用（なんでもいいがまずはお手頃な）
詳しい説明はこちら
https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html
n_estimatorsなどいろいろあるが、慣れたらここら辺のパラメータも使用

これでPredsの中に訓練データで学習したデータからテストデータのXを用いて予測したyが出力される。

※スコア評価
今回はMAEを使用、要は予想した値と実際の値を引いて、全データ足し合わせたやつ

mean_absolute_error(y_valid, preds)

これでだいたい24000くらい、いいか悪いかはおいておいてこの数字。
0になるのが一番いい予想

本当はいろいろな比較をして最終的なデータを使用するが、
今回はランダムフォレストの枝が50のデータで予測

Predictの部分を一番初めに入れた予測データに置き換え
preds_test = my_model.predict(X_test)

これがKaggleで要求されている提出フォーマット
output = pd.DataFrame({'Id': X_test.index,
                       'SalePrice': preds_test})
output.to_csv('submission.csv', index=False)

このCSVを提出すれば結果が出てくる。
AWS App Runner


# AWS App Runner

- インフラストラクチャを管理せずに高速でシンプルかつ安全な方法でコンテナ化されたWebアプリケーションのビルド、デプロイ、実行するためのマネージドなサービスです。
- **ソースコード**または**コンテナイメージ**を提供するだけで、App Runnerはアプリケーションを自動的に構築およびデプロイすることができます。

- App Runner は裏側で、Fargetが動いているらしい。


# ハンズオン

詳細な仕様の話に入る前に、それ程複雑な設定はないので、とりあえず触ってみると良さそうですです。
AmazonのharunobukamedaさんがGithubにhands-onをあげてくれているので、こちらを試してみると良いかと思います。

https://github.com/harunobukameda/AWS-App-Runner


# 動作

ハンズオンを実施いただいた通りですが、やることは、

- GitHubにアプリケーションコード（現在は、PythonとNode1.jsに対応）をpushするか、
- AmazonECRにコンテナイメージをpushする。

これだけで後はいい感じにApp Runnerが動いてくれます。

- 2022/10/28 追記

https://aws.amazon.com/jp/about-aws/whats-new/2022/10/aws-app-runner-support-php-go-dot-net-ruby-managed-runtimes/

# Auto Scalling

- リクエスト数に応じてスケールする。
- 同時リクエストの数が同時実行数の割り当てを超えると、AppRunnerはサービスをスケールアップします。
- アプリケーションが捌き切れなく、処理待ちのリクエストがどれぐらい溜まっているかにより、スケールアップします。（例えば、同時実行100にし、100リクエストがきたからといって、スケールアップするわけではない。）


# ヘルスチェック

- App runnerは、アプリケーションがリッスンしているポートでTCPヘルスチェックを実行します。


# セキュリティ

- インスタンスロール
 - 例えば、Apprunnerで動かしているアプリケーションが、S3からデータを持ってきたい場合など、IAMロールを作成する。

- AWS KMS キー
 - 作成時に、AWSが所有するキーを使用するか、別のAWS KMSキーを選択することが可能。
 
# ログとメトリクス

- ログ
 - イベントログ
 - デプロイログ
 - アプリケーションログ

- メトリクス
 - インスタンスレベルのメトリクス
 - サービスレベルのメトリクス

# カスタムドメイン

- デフォルトドメインをカスタムドメインと紐付けることが可能。
- 1日〜2日で反映される。

# 料金

- 開発や個人で利用する場合には、一時停止にしてコストを抑えることが可能。

# VPC 

- VPC でホストされているデータベースやその他のアプリケーションとサービスが通信できるようになります。

https://aws.amazon.com/jp/blogs/news/new-for-app-runner-vpc-support/

# その他参考URL

https://www.youtube.com/watch?v=8Tmf5J2hXT8
React Native(Expo)のiOSビルドでエラーになる件

# ExpoでiOSアプリをビルドするとエラー終了してしまう
実際に表示されていたエラーは以下。

```:ビルドを実行したコンソールに出るエラー
You can press Ctrl+C to exit. It won't cancel the build, you'll be able to monitor it at the printed URL.
✖ Build failed.
Standalone build failed!
```

```:Expoのダッシュボードで見れるビルドログのエラー
Error: xcrun exited with non-zero code: 1
    at ChildProcess.completionListener (/usr/local/turtle-js/node_modules/@expo/xdl/node_modules/@expo/spawn-async/build/spawnAsync.js:52:23)
    at Object.onceWrapper (events.js:418:26)
    at ChildProcess.emit (events.js:311:20)
    at ChildProcess.EventEmitter.emit (domain.js:482:12)
    at maybeClose (internal/child_process.js:1021:16)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:286:5)
    ...
```

# 原因
どうやら使用しているアイコンがガイドラインに沿っていない場合に出るエラーらしい。

# 対処
Expoのドキュメントに、Appleのガイドラインについての記載があるのでこれに従う。

https://docs.expo.dev/guides/app-icons/#ios
ファイアウォールについて備忘録

＊ファイアウォールとは
・外部ネットワークからのサイバー攻撃や不正アクセスを防ぐセキュリティ機能
・インターネットと自ネットワークの境界に設置し、外部からの攻撃を監視・制御する


＊３つのタイプ


　【パケットフィルタリング型】
（L3：ネットワーク層〜L2：データリンク層）

・通信パケットのヘッダを確認してフィルタリング
　⇨送信元アドレスや宛先アドレスなどをチェック
・仕組みはシンプルだがパケットを見ただけでは判別できない攻撃は防げない（例：バッファオーバーフロー攻撃など）
・その他のセキュリティ製品などと併用が基本



　【サーキットレベルゲートウェイ型】
（L6：プレゼンテーション層〜L4：トランスポート層）

・「トランスポート層」レベルの通信を監視・制御する方式
・コネクション単位の制御も可能
◎パケットフィルタリングよりも管理が楽



　【アプリケーションゲートウェイ型】
（L7：アプリケーション層〜L5：セッション層）

・従来のパケットフィルタリングより、より詳細に許可する通信を特定・制御する
・HTTP、SMTPなどのアプリケーションプロトコル毎に通信を制御する仕組み
・より高精度な制限のため処理に時間がかかったり、構築コストが高くなるリスクがある


＊ファイアウォールの３つの機能

〜送信元IPや宛先IPに応じた通信の許可・遮断

・ヘッダ部分に含まれる送信元情報、宛先情報を読み取り事前に設定したルールをもとに制御

■前に設定したルールに合致するもの以外は全て許可
■事前に設定したルールに合致するもの以外は全て破棄

上記いずれかで設定。
※最低限必要な通信以外は遮断するよう設定するのが基本


〜通信プロトコルに応じた通信の許可・遮断

・パソコンやサーバが通信の出入り口「ポート」の制御
※ポートとは通信プロトコル・サービス毎に「０〜655351」までの番号が割り振られている
　HTTP：80
　SSH：22
　SMTP（メール）：25

悪用されやすいポートをあらかじめ閉じておく。

〜監視・管理

・通過するまたは遮断する通信をログとして記録している。
・ログを監視・管理することで不正アクセスの実態調査や追跡などができる。
　⇨サイバー攻撃の未然・装置検知ができる

外部ツールを利用しログを解析することで事前に脆弱性対策を行い、セキュリティ攻撃を未然に防ぐ
LinkedIn Jobsに人材紹介会社からの求人広告をマーキングする


# 経緯
最近"LinkedIn Jobs"に仕事を探し、そこにはたくさんの人材紹介会社からの求人広告が載せている。たくさんの時間を使ってこれを飛ばすのは困るので、だからこのコードを作った。
このコードはJavaScriptで書かれて、外部ライブラリは使わない。Google Chromeに試したが、他のウェブブラウザが使われると思う。

# どうやって使うの
1. 変数"agentList"に人材紹介会社のリストを入れる

```javascript
let agentList = [
  "ADD YOUR LIST INTO HERE"
];

function highlightAgent() {
  document.querySelectorAll("a[data-control-name='job_card_company_link']").forEach(function(currentValue) {
    let name = currentValue.text.trim();
    let agentName = agentList.find(function(input) {return input === name});
    if (agentName !== undefined) {
      currentValue.style.backgroundColor = "#FF0000";
    }
  });
}

window.setInterval(highlightAgent, 5000);
```

2. "デベロッパーツール"の"Console"に上のコードを貼り付けてください(Google Chromeが使う場合)。マーキングのコードは毎5秒実行するので、次のページに押しても、5秒にはマーキングが見られる。

![highlightAgent01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232557/47f3f7e8-31f6-07ba-6e39-df044bdf547a.png)

次のページに押しても、コードは有効する。無効する時にはウェブブラウザの"再読み込み"を押してください。
Laravel 8 SQLite導入時のエラー備忘録  

##目的
Laravel8でSQLiteの導入時に複数回エラーが発生した。
解決策の備忘録として記載する。

##環境
Laravel v8.47.0 
PHP v7.4.18
Apache 2.4
Windows10 Pro

##事前情報
テーブル作成時にコマンド`php artisan migrate`は使用しない方法です。
SQLiteの細かい導入方法は割愛します。

#エラーの内容と対応
##画面が真っ白になった
![whiteout.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1378980/db076185-4c05-d55d-9584-d286f6713cd2.png)
###.envファイルのパス記述に半角スペースがあることが原因
DB_DATABASEは絶対パスで記述する必要があるのですが、パスの記述に半角スペースが含まれていることが原因でした。
![env.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1378980/b46fb70f-f6d4-f0da-97cf-3466f9ca1e51.png)
パスを""で囲うことで解決しました。

```php:.env
変更前
DB_DATABASE=C:/Program Files/Apache Software Foundation/Apache24/htdocs/laravel/work_status_management/database/database.sqlite

変更後
DB_DATABASE="C:/Program Files/Apache Software Foundation/Apache24/htdocs/laravel/work_status_management/database/database.sqlite"
```

##エラー文 ”could not find driver (SQL: PRAGMA foreign_keys = ON;)”
ドライバーが見つからないと言っています。
![WS000032.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1378980/96f82796-5f6e-81bd-500f-9c1283b537ca.jpeg)

###使用しているPHPのphp.iniのSQLiteドライバを有効にする
※Laravelの設定ファイルではありません。PHPの設定ファイルです。
![WS000033.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1378980/8d00a421-d832-f6ce-0bd5-ac333a1718b7.jpeg)

以下のようにコメントアウトを外して保存してください。

```php.ini
変更前
;extension=pdo_sqlite

変更後
extension=pdo_sqlite

※PHPのバージョンによっては以下のような記述の場合もあるとのこと
extension=php_pdo_sqlite　
```
設定後、Apacheを再起動

##エラー文 ”SQLSTATE[HY000]: General error: 1 no such table: sessions”
![SQLSTATE[HY000].png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1378980/aecb35e1-607a-e6fe-cc27-d20a0f2767a1.png)

###.envファイルの以下記述を更新して保存する。
![WS000041.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1378980/30e9ee0c-cd40-462e-00b9-4aaa49dd0767.jpeg)

初期値だとエラーになってしまったので、記述を変更した。

```php:.env
変更前
SESSION_DRIVER=database

変更後
SESSION_DRIVER=file
```


##まとめ
エラーの調査を進める中で、色々な方が同じようなエラーの解決方法をネットにあげてくれていたのですが、自分の環境に合うものがなかなか見つかりませんでした。

同じような境遇に方に少しでもお役に立てることができれば嬉しいです。
コンストラクタとは？

コンストラクタとはインスタンスを作成したタイミングで実行されるメソッドのこと。
つまりインスタンスの初期状態を自由にいじることができるということ。


実際にコンストラクタを入れて初期状態を定義したコードが以下の通りです。

```

    class CustomerCard {
        int id; 
        String name;

    // **コンストラクタで初期値を設定**
    CustomerCard() {
            this.id = 0001;
            this.name = "tarou";
        }
    }

    class CustomerManager {
        public static void main(String[] args) {
            CustomerCard out = new CustomerCard(); //インスタンス作成
            System.out.println(out.id); //idを出力
            System.out.println(out.name); //名前を出力
        }
    }

```

実行した結果が以下の通りです。

```
0001
tarou 

```

このように、メンバー変数に初期状態としてデータをセットすることができます
fatal: unable to access SSL certificate problem: unable to get local issuer certificate

### 原因
pyenv upgradeしようとしたら
これ実行しろと言われて、実行したらエラー

```
git -C /home/linuxbrew/.linuxbrew/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow
```



### エラー内容
```
[ec2-user@ip-172-31-19-171 .pyenv]$ brew upgrade pyenv
Error: 
  homebrew-core is a shallow clone.
To `brew update`, first run:
  git -C /home/linuxbrew/.linuxbrew/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow
This command may take a few minutes to run due to the large size of the repository.
This restriction has been made on GitHub's request because updating shallow
clones is an extremely expensive operation due to the tree layout and traffic of
Homebrew/homebrew-core and Homebrew/homebrew-cask. We don't do this for you
automatically to avoid repeatedly performing an expensive unshallow operation in
CI systems (which should instead be fixed to not use shallow clones). Sorry for
the inconvenience!
```

### 一時的解決

```
git config --global http.sslVerify false
```

man-in-the-middle？攻撃されるぽので、すぐに以下で、戻した方が良いみたい

```
git config --global http.sslVerify true
```
React Hook Formで動的にフォームを増やす。

フォーム系のライブラリはいくつもありますが、動的なフォームは記法でつまづきがちなポイントだと思います。
今回は際レンダリング数が少なく、かなり使われ出しているReact Hook Formの動的なフォームのサンプルです。

## まずは動的でないフォーム

こんな感じでOKだと思います。

```tsx
interface sampleFormInterface {
  firstName: string
  lastName: string
}

const SampleComponent: React.FC = () => {
  const {
    register,
    handleSubmit,
  } = useForm<sampleFormInterface>()

  const onSubmit = (data: unknown) => {
    console.log(data)
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        placeholder="Basic usage"
        {...register('firstName'}
      />
      <input
        placeholder="Basic usage"
        {...register('lastName'}
      />
    </form>
  )
}
```

useFormというフックを使って、使う関数やプロパティを準備しています。

種類も多いので、今回の記事ではドキュメントを置いておきます。

[React Hook Form | register ](https://react-hook-form.com/api/useform/register)

## useFieldArrayを使って動的に増やせるようにする。

配列対応させるにはuseFieldArrayを使います。
useFieldArrayのnameに配列名(例えばsampleForm)を設定して、
inputのresisterに`sampleForm.${index}.firstName`のような形で設定します。

```tsx
interface sampleFormInterface {
  firstName: string
  lastName: string
}

const SampleComponent: React.FC = () => {
  const {
    register,
    handleSubmit,
    control, // 追加
  } = useForm<sampleFormInterface>()

  // 追加
  const { fields, append } = useFieldArray({
    control,
    name: 'sampleForm',
    keyName: 'key', // デフォルトではidだが、keyに変更。
  })

  const onSubmit = (data: unknown) => {
    console.log(data)
  }

  // 追加
  const addInputForm = () => {
    append({ firstName: '', lastName: '' })
  }

  return (
    <>
      <form onSubmit={handleSubmit(onSubmit)}>
        {/* 変更　*/}
        <ul>
          {fields.map((field, index) => (
            <li key={field.key} className="flex space-x-5">
              <input
                {...register(`sampleForm.${index}.firstName`)}
                placeholder="苗字"
              />
	      <input
                {...register(`sampleForm.${index}.lastName`)}
                placeholder="名前"
              />
            </li>
          ))}
        </ul>
      </form>
      <button
        className="p-2 rounded-full bg-yellow-400"
        onClick={addInputForm}
      >
        追加ボタン
      </button>
    </>
  )
}
```

ネストさせたい場合は、
useFieldArrayのnameに`sampleForm.${index}.nestedArray`のように設定して、
inputのresisterにsampleForm.${index}.nestedArray.${nestedIndex}.firstNameのような形で設定すればOKです。
【死闘】Visual Studio Code で Django の環境構築

環境：Windows、Python3.8、Anaconda使用
　「djangoのツボとコツがゼッタイにわかる本」で環境構築を始めたものの書籍に記載されている通りに動かず、結局インターネットで調べながら構築した。

・詰まった時の状況
　様々な記事を漁って見たが、condaがVSCodeにおいて認識されずエラーが出る。

・解決方法
　 Anacondaが先にインストールされていたことが原因だった。環境変数のpathに¥Users¥Username¥anaconda3,¥Users¥Username¥anaconda3¥Library¥bin の二つを追加することで解決。またこれで解決しない場合はVSCodeのターミナル設定を変更する必要がある。
FlutterのGridViewでグリッドレイアウトを作りたい時のメモ

FlutterのGridViewでグリッドレイアウトを作りたい時のメモ
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407895/0d904c99-2a4c-0de2-bf93-5f8f2d731884.png' width=200 />

参考リンク：
https://api.flutter.dev/flutter/widgets/GridView-class.html
https://flutter.ctrnost.com/basic/layout/gridview
https://flutternyumon.com/how-to-use-listtile
特に難しいところはないが、
・Columnの中にGridViewを置きたい場合はExpandedでラップする（ここで1時間ほど溶かしたのでメモ）
・GridViewの子要素はCardでなくても、TileでもContainerでも何でもいい
・グリッドの縦横比を変えたい時は、childAspectRatioを設定する、黄金比（約1.618）にしたらいい感じにキレイw
・scrollDirectionはデフォルトでAxis.vertical、横スクロールに変えたい場合はAxis.horizontalにする

```dart
            Expanded(
              child: GridView.count(
                crossAxisCount: 3,
                childAspectRatio: 1.618,
                mainAxisSpacing: 0.0,
                crossAxisSpacing: 0.0,
                scrollDirection: Axis.horizontal,
                children: [
                  Card(
                    child: Padding(
                      padding: const EdgeInsets.all(10.0),
                      child: Text('お薬手帳'),
                    ),
                    color: Color(0xffddeedd),
                  ),
                  Card(
                    child: Padding(
                      padding: const EdgeInsets.all(10.0),
                      child: Text('血圧手帳'),
                    ),
                    color: Color(0xffddeedd),
                  ),                
                ],
              ),
            ),
```
Highlight job ads posted by job agent in LinkedIn Jobs

# Reason to write this
When I look up jobs in "LinkedIn Jobs", I found that there are so much ads posted by job agent. I used so much time every day to filter out these ads. Therefore I wrote this code.
This code is written by pure JavaScript and no 3rd library is used. I tried it on Google Chrome only and it seens that can work on other browser.

# How to use the code
1. fill your agent list into variable "agentList"

```javascript
let agentList = [
  "ADD YOUR LIST INTO HERE"
];

function highlightAgent() {
  document.querySelectorAll("a[data-control-name='job_card_company_link']").forEach(function(currentValue) {
    let name = currentValue.text.trim();
    let agentName = agentList.find(function(input) {return input === name});
    if (agentName !== undefined) {
      currentValue.style.backgroundColor = "#FF0000";
    }
  });
}

window.setInterval(highlightAgent, 5000);
```

2. paste the code into "Console" of "DevTools" (assume that you are using Google Chrome). The highlight function will be run in every 5 seconds, so you can see result at most 5 seconds after you press next page. 

![highlightAgent01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232557/a5d9c7a4-0ca3-9df7-04ac-bc86d4f9f492.png)

It is in active when you press next page, unless you press "reload" of browser.
作成したAndroidアプリのプロジェクトをGitHubで管理

# 環境

- Android Studio: Arctic Fox 2021.3.1

# 前提

- GitHub にサインアップ済みで、repo, gist, read:org 権限を持つ token を作成済み
- Android Studio でAndroidアプリのプロジェクトを作成済み
 - https://qiita.com/yiwa81/items/fd6559cc4a790058542f

# 手順

- VCS > Enable Version Control Integration を選択
- Git を選択
- Git > GitHub > Share Project On Github を選択
- 必要事項を入力
 - Repository name: 適宜
 - Private: 非公開にしたいときはON
 - Remote: origin
 - Shared by: アカウントを指定
  - アカウントを設定してない場合、以下で追加
   - Add account > Log In With Token
   - repo, gist, read:org 権限を持つ token を入力
- Share を選択
- Add Files for Initial Commit の画面で Commit
【Ruby on Rails】よく使うrails dbコマンド集

## Railsでよく使うrails dbコマンド
```
$docker-compose run --rm api bin/rails db:create
```
DBを作成する　

```
$ docker-compose run --rm app bin/rails db:migrate
```
マイグレーションファイルの内容をDBに反映させる。


```
$ docker-compose run --rm app bin/rails db:seed
```
seed.rb内で記述した内容をDBに投入する。
firebase デプロイ変更されない時の対応

# 問題認識

```
firebase deploy
```

firebaseにデプロイを試みたところ、


```
✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/xxxxx/overview
Hosting URL: https://xxxxx.web.app
```

デプロイは成功しているのにURLを開くと何も変更が反映されない
![ダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1572216/ef9db027-606c-659f-35a0-d64955c84555.png)

# 仮説

__firebase init時にbuildではなく、publicを指定したのではないか疑惑・・・__
→　buildフォルダは作成済
→　firebase.jsonでhostingはbuildになっている

検討はずれ:frowning2:

# 解決策

__原因、__

```
Webページが更新されたとき、古い CSSや画像のキャッシュのせいなどで、何らかの表示が乱れていた。
```

__解決策、__

```
Chromeのキャッシュを完全に削除する手順
Chromeの設定 [ ︙ ] をクリック
[その他のツール] > [閲覧履歴の消去] を選択
閲覧履歴の消去パネルが開くので、任意の [期間] を選択
[キャッシュされた画像とファイル] をチェック
[閲覧履歴データを消去する] ボタンをクリック

```
無事、firebaseにデプロイできました:relaxed:

***

余談として、Chrome のキャッシュクリアのショートカット

Chrome には、「スーパーリロード」と呼ばれる、キャッシュを破棄して再読み込みを行うための、特別なリロードが存在します。この操作で、そのリロードしたページから直接参照されている外部ファイルは、Chromeに残っている古いキャッシュを削除できます。

```
// Mac のキャッシュクリアのショートカット
Command + Shift + R


// Windows のキャッシュクリアのショートカット
Ctrl + Shift + R (もしくは　Shift + F5）
```
スイッチに対応するAPI、ついつい冪等性を忘れてちゃう問題

下記スイッチの画像をご覧ください。

![スクリーンショット 2021-08-27 17.32.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83424/ac88736e-c5ee-d885-5573-90d94e65968f.png)

上段のスイッチはOFF、下段はONです。
OFFのスイッチをクリックするとONに変更、ONのスイッチをクリックするとOFFに変更されます。

スイッチをクリックした際にスイッチの状態を反転させるAPIを実装します。
テーブルスキーマは下記の通り。スイッチごとにIDを持っており、ONの場合はenabled=1、OFFの場合はenabled=0とします。

```console
switches
+--------------------------+-------------------+------+-----+---------+----------------+
| Field                    | Type              | Null | Key | Default | Extra          |
+--------------------------+-------------------+------+-----+---------+----------------+
| id                       | bigint            | NO   | PRI | NULL    | auto_increment |
| enabled                  | tinyint(1)        | NO   |     | 0       |                |
+--------------------------+-------------------+------+-----+---------+----------------+
```

このような仕様の場合、どのようなAPIを実装しますか？

# パターン１ トグル

パターンの1つとしてトグルのように振る舞うAPIが考えられます。

```
PUT /toggle_switch/:id
```

toggle_switchという名前の通り、指定したidのenabledを反転させます。
スイッチなので、現状がONならOFF、OFFならONにすれば良いのです。ONからONやOFFからOFFという操作はありません。
この仕様を考慮するとこの実装で問題なさそうですが、利用者が混乱する挙動をすることがあります。

それが下記のパターンです。
APIへのリクエストはネットワークの不調などを考慮してレスポンスがない場合に再送するようにしていることがあります。
下記では1回目のリクエストがタイムアウトしたためリクエストを再送していますが、サーバーでは両方のリクエストが正常に処理されるため、スイッチがOFF→ON→OFFと更新されてOFFになってしまっています。

![スクリーンショット 2021-08-31 10.51.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83424/88719106-3482-f90c-a173-b1031305ed9e.png)

システム的にはデータと画面描画が一致しており問題はないのですが、利用者としてはONにしたつもりなのにOFFのままなのでユーザービリティが良くないですよね。

この事象はこのAPIが冪等性がないために発生しています。
冪等性を持ったAPIの場合はどうなるかパターン2でみてみましょう。

# パターン２　更新後のON/OFFを明示的に指定する

パターン2では冪等性を持たせたAPIを考えます。
下記はONとOFFでエンドポイントを分けています。呼び出すエンドポイントによってONになるのかOFFになるのか明確であり、何度呼び出しても同じ結果になるので冪等性を持っています。

```
PUT /switch_on/:id
PUT /switch_off/:id
```

または、エンドポイントは1つで、パラメーターで変更後のON/OFFを指定するパターンも考えられます。
こちらも指定するパラメーターによってONになるのかOFFになるのか明確であり、冪等性を持っています。

```
PUT /switch/:id
params
  enable: boolean
```

今回のAPIの場合、パターン１の例と同じタイムアウト＆再送した場合は下記のように動作します。

![スクリーンショット 2021-08-31 11.18.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83424/7af6d1d4-f717-9c1a-de92-c7ec18a0cb63.png)

パターン1とは異なり、最終的にONになります。
こちらの場合、利用者が混乱することもなく、システム的にも問題ありません。

# まとめ

APIは冪等性がある方が良いとよく言われているものの、スイッチなどの場合ついついパターン1で実装してしまうこともあると思います。
しかし、パターン２のように冪等性のあるAPIで実装した方が適切な挙動をしてくれることが多いので、APIを実装する前に一呼吸おいて冪等性を忘れず考慮するようにしましょう。
ReactにおけるuseState色々

# はじめに
ReactにおけるuseStateを用いたデータの更新方法をまとめました！

# 1. 文字列の更新
```tsx
import { useState } from 'react'

export default function Component() {
  const [name, setName] = useState('文字列')

  return (
    <div>
      <h1>{name}</h1>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
    </div>
  )
}
```

# 2. オブジェクトの更新
```tsx
import { useState } from 'react'

export default function Component() {
  const [user, setUser] = useState({ id: 1, name: '単一オブジェクト' })

  return (
    <div>
      <h1>{user.name}</h1>
      <input
        type="text"
        value={user.name}
        onChange={(e) => setUser({ ...user, name: e.target.value })}
      />
    </div>
  )
}
```

# 3. オブジェクト配列の更新
```tsx
import { useState } from 'react'

export default function Component() {
  const [users, setUsers] = useState([
    { id: 1, name: '配列のオブジェクト１' },
    { id: 2, name: '配列のオブジェクト２' },
    { id: 3, name: '配列のオブジェクト３' },
  ])

  return (
    <div>
      {users.map((user, i) => (
        <div key={user.id}>
          <h1>{user.name}</h1>
          <input
            type="text"
            value={user.name}
            onChange={(e) =>
              setUsers((prevUsers) => {
                prevUsers[i].name = e.target.value
                return [...prevUsers]
              })
            }
          />
        </div>
      ))}
    </div>
  )
}
```

# 4. チェックボックスの更新
```tsx
import { useState } from 'react'

export default function Component() {
  const [checked, setChecked] = useState(false)

  return (
    <input
      type="checkbox"
      checked={checked}
      onChange={(e) => setChecked(e.target.checked)}
    />
  )
}
```
[続] CSVを読み込もう

# CSVデータを読み込もう

前回、頑張ってCSVファイルを読み解いた
[CSVを読み込もう](https://qiita.com/chobirinu/items/a6fe3d2f6821b1aa5b06)

でも追伸で書いた通りなんかデータがおかしい。
調べていくと実際はこんなファイルだった。

```csvs
ItemName1,　ItemName2,ItemName3　,ItemName4,
0,AN000012,東京　　　　　　,埼玉　　　　　　　　,
1,AN000022,東京　　　　　　,神奈川,千葉 　　　　,
```
んー基本カンマで区切られていると思いきや、不正っぽいデータがあるなぁ・・・

<br>
ん！？これ、データに相当する行は固定長ファイルよね？多分。
でもヘッダーは普通のカンマ区切り・・・でもないな。
固定長っぽいけど固定長ではない感じ。また２行目以降のデータ数とは異なる・・・
<font color="Red">しれっとこんなデータを作るんじゃないよ・・・・</font>
<br>
# 取り込み
こんな感じの処理を考えてみた。

```cs
static Encoding encoding = Encoding.GetEncoding("Shift_JIS");

struct CsvRecord
{
    public string ItemName1;
    public string ItemName2;
    public string ItemName3;
    public string ItemName4;
}

private static DataTable CreateDataTable()
{
    DataTable dataTable = new DataTable();

    // 型付DataTable作成
    dataTable.Columns.AddRange(
        new DataColumn[]
        {
            new DataColumn("dtField1", typeof(Int32)),
            new DataColumn("dtField2", typeof(string)),
            new DataColumn("dtField3", typeof(string)),
            new DataColumn("dtField4", typeof(string)),
        });
     return dataTable;
}

private static List<CsvItem> GetCsvData(string targetFile)
{
    List<CsvItem> result = new List<CsvItem>();

    using (System.IO.StreamReader sr = new System.IO.StreamReader(targetFile, encoding))
    {
        // ヘッダ相当の行を空読み
        sr.ReadLine();

        CsvItem temp;
        byte[] byteArray;

        while(!sr.EndOfStream)
        {
            byteArray = encoding.GetBytes(sr.ReadLine());
            temp = new CsvItem();

            // 0バイト目から1バイト分切り出して文字列化
            temp.ItemName1 = encoding.GetString(byteArray, 0, 1).Trim();
            temp.ItemName2 = encoding.GetString(byteArray, 2, 8).Trim();
            temp.ItemName3 = encoding.GetString(byteArray, 11, 16).Trim();
            temp.ItemName4 = encoding.GetString(byteArray, 28, 16).Trim();

            result.Add(temp);
        }
    }
    return result;
}

public static DataTable ReadData(string targetFile)
{
    // 型付DataTable作成
    var resultDataTable = CreateDataTable();

    // CSVファイル読み込み
    List<CsvItem> CsvItems = GetCsvData(targetFile);

    foreach (CsvItem csvItem in CsvItems)
    {
        // DataRow化してDataTableに追加
        resultDataTable.Rows.Add(
            csvItem.ItemName1,
            csvItem.ItemName2,
            csvItem.ItemName3,
            csvItem.ItemName4
        );
    }
    return resultDataTable;
}
```

最終的にDataTableで処理する必要があったのでこういう風になりました。

# 最後に
「CSVファイル」という言葉に踊らされないように気を付けましょう。
手動テストのカバレッジ測定をするための、ちょっとした工夫(.NET + Visuau Studio)

## はじめに

Visual Studio Enterpriseや、AxoCoverを利用するとカバレッジ測定を行うことができます。しかし、ユニットテストを実行した結果のカバレッジを測定する前提となっているため、気軽に使うことができません。

ちょっと工夫をすることで、画面を表示して`手動テストのカバレッジ測定`を行うことが可能です。

## 概要

* ユニットテスト内でフォームを起動し、それを手動テストするだけです。

## 手順

### ①テスト対象として下記のようなフォームを作成します。

![AxoCover12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276579/54f8e200-15ca-1978-bfd2-7c9a3979db8f.png)


```csharp
using System;
using System.Windows.Forms;

namespace TestTargetExeForm
{
    public partial class TestTargetForm : Form
    {
        public TestTargetForm()
        {
            InitializeComponent();
        }
    // 以下省略

```

### ②ソリューションにテストプロジェクトを新規追加し、フォームを起動するだけのテストケースを作成します

```csharp
namespace ManualTest
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void ManualTest()
        {
            // Show form, and test manualy
            TestTargetExeForm.Program.Main();
        }
    }
}
```

### ③テストエクスプローラーからフォームを起動するテストケースを実行します(AxoCoverを使っています)

![AxoCover11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276579/45c17570-aa0a-499f-163e-17fea2ee2cf9.png)


* プログラムが起動するので、手動でテストを行います。

  * 数値にそれぞれ「1」と「2」を入力
  * ＋ － × ÷ を1回ずつ選択してから計算ボタンを押す
  * 操作終了後、プログラムを閉じる

![AxoCover12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276579/54f8e200-15ca-1978-bfd2-7c9a3979db8f.png)

### ③カバレッジ測定結果

プログラムが終了すると自動的にカバレッジ測定結果が収集されます。

* テストランナー(AxoCover)での結果表示

メソッド毎のカバレッジ率が測定されます。計算ボタン(button1_Click)の分岐網羅率は76.92%でした。


![testrunner2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276579/b19dacf2-214d-5e3c-4b02-e29f5c462c9a.png)

ソースコードレベルでのカバレッジを確認するため、右クリックしてソースを確認します。

赤色、黄色になっている行が分岐を網羅できていないコードです。

  * 数値の空白チェックコードが実行されていないことが一目瞭然です

![testrunner3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276579/b44927c5-55c8-c989-4685-d50d57d5ac46.png)


## 参考ページ

[AxoCover](https://github.com/axodox/AxoCover)

[カバレッジ測定ツール AxoCover をVisual Studio 2019で利用する方法](https://qiita.com/murasuke/items/cf377988fbbe3bd14db2)
古いMySQLをAWS RDSに移行した時に引っかかった点

10年ぐらい前のシステムのAWS化に際し、
オンプレミス上のMySQLをAWS RDSに移行しました。
移行作業の中で何点かハマりポイントがあったので書き記します。

# 環境
## 既存環境
* MySQL5.2
## 新環境
* AWS RDS
* MySQL5.7

# ポイント1　テーブル名が大文字小文字が区別されるようになる。

https://dev.mysql.com/doc/refman/5.6/ja/identifier-case-sensitivity.html

> Unix では、lower_case_table_names のデフォルト値は 0 です。Windows では、デフォルト値は 1 です。OS X では、デフォルト値は 2 です。

MySQLでSQLにテーブル名を書く時、大文字小文字を区別するかどうかは、`lower_case_table_names`のパラメータに依存します。

どうも今回対象としたシステムは最初Windowsで動かしていたみたいで`lower_case_table_names`が1になっていました。
RDSの同パラメータのデフォルト値はゼロです。
既存のSQLはWindows上で開発してたようでテーブル名の大文字小文字が統一されておらず、
結構な数のSQLが動作不良を起こしました。

これについては、SQLの方では直しきれなかったのでパラメータの方を変更してます。

なお、`lower_case_table_names`RDSのMySQLが5.6未満だと0以外選べないので注意が必要です。

# ポイント2　ファンクションが移行できない。

ファンクションと一部のストアードプロシージャが移行に失敗しました。
ファンクションにはSUPER権限が必要ですが、RDS上のユーザーにはこの権限が提供されていません。
従って、ファンクションを作るDDLが通りません。

https://dev.mysql.com/doc/refman/5.6/ja/create-procedure.html

> CREATE PROCEDURE および CREATE FUNCTION には、CREATE ROUTINE 権限が必要です。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/rds-mysql-functions/

> SYS アクセス (SUPER 権限) は提供されていません。MySQL DB インスタンスでバイナリログが有効になっている場合は、DB インスタンス用に作成するカスタム DB パラメータグループで log_bin_trust_function_creators パラメータを true に設定します。

以上から`log_bin_trust_function_creators`をtrueにして、
RDSを再起動するとファンクションのDDLが通るようになりました。

ポイントは以上です。
上記２点を修正したところ、無事移行完了し安定して動くようになっています。
基本情報技術者試験勉強0831

本日の積み上げ結果
基本情報技術者試験勉強
令和31年春過去問
パーフェクトラーニング(午後対策)

JIS Q 27000:2014(情報セキュリティマネジメントシステム－用語)における"リスクレベル"の定義はどれか。　結果とその起こりやすさの組合せとして表現される，リスクの大きさ

社内カンパニー制　事業分野ごとの仮想企業を作り，経営資源配分の効率化，意思決定の迅速化，創造性の発揮を促進する。

IETF インターネットで利用される技術の標準化を図り，技術仕様をRFCとして策定している組織。

ハニーポット　侵入者やマルウェアの挙動を調査するために，意図的に脆弱性をもたせたシステム又はネットワーク。
GitHubのリポジトリを作るときに参考にしたサイト

## GitHubのアカウント管理について
- [複数のgitアカウントを使い分ける](https://zenn.dev/taichifukumoto/articles/how-to-use-multiple-github-accounts)
    - includeIf　は rootフォルダ(~)直下じゃないと効かなそうなので注意

[GitHub アカウントへの新しい SSH キーの追加](https://docs.github.com/ja/github/authenticating-to-github/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account)

> 業務で良く使うアカウントは、globalにアカウント情報を設定する。(~/.gitconfig)

## リポジトリ作成
- [Githubに新規リポジトリを追加](https://qiita.com/sodaihirai/items/caf8d39d314fa53db4db)
    - => HTTPSのパスワード認証はGitHub非推奨で使えなくなっているのでSSH接続でやる必要がありそう
    - => `git remote add origin [リモートリポジトリ情報]` をSSHの情報で行う
- SSHでのgitへの接続
    - そのままだとSSHの秘密鍵が登録されておらず以下のように怒られる

```
ERROR: Repository not found.
fatal: Could not read from remote repository.
```

- 
    - ssh-addで登録が必要(複数登録可能)
    - ``` $ ssh-add -l ``` で現在登録されている内容を確認
    - ``` $ ssh-add -K <秘密鍵のパス> ``` で登録可能
    - gitのアカウント設定でSSHの公開鍵を登録していることが前提
        - 参考：[GitHubでssh接続する手順~公開鍵・秘密鍵の生成から~](https://qiita.com/shizuma/items/2b2f873a0034839e47ce)
        - ```pbcopy < <公開鍵のパス>```
- SSHの登録しても同じエラーが出る場合
    - アカウントを複数利用しているため発生している可能性
    - アカウントの確認 ```$ git config --local --list```
    - ssh configファイルに振り分け設定を行う
        - 参考：[GitHubを複数のアカウントで利用するためのメモ](https://qiita.com/BlueEventHorizon/items/f9d81e3659ebce9e1ffc)
        - Hostでドメインを設定すると、そこを見に行くので ``` Host github.com.private ``` みたいなのを作って、remoteのSSH用URLをそれに合わせて登録する


- [gitリポジトリの命名規則](https://zenn.dev/iwatos/articles/cb79814a4b31ed)
    - 命名規則は存在しないが、ケバブケース（小文字の英数字を利用、単語区切りは-を利用）が推奨される

- [readme-md-generatorを使ってリッチなREADME.mdをお手軽に作ってみませんか?](https://qiita.com/okumurakengo/items/1c2549f96de90eacb597)
- [[Git] .gitignoreの仕様詳解](https://qiita.com/anqooqie/items/110957797b3d5280c44f)

## httpsで接続してしまったのをSSHに変えたい
- [gitのremote urlを変更する(レポジトリ移行時)](https://qiita.com/minoringo/items/917e325892733e0d606e)
    - ```git remote set-url origin {new url}```
    - fetchは変わるけどpushが変わらない
    - ``` git remote set-url --push origin {new url}``` で変更できた
    - URLの確認方法は ```$ git remote -v```
AWS EC2 に Docker Compose で nginx + certbot (Let's Encript) + Redmine + MySQL 入れてみた（5/5 引用・謝辞）

__↓ 1/5 はじめに__

https://qiita.com/ax_kazz/items/59e15728139a6768bbdf

__↓ 2/5 Docker, Docker Compose など基盤構築__

https://qiita.com/ax_kazz/items/816fe535aa3cf402d004

__↓ 3/5 Nginx, Certbot 導入と SSL 証明書の取得・更新__

https://qiita.com/ax_kazz/items/f837e237e968db3d3ab3

__↓ 4/5 MySQL, Redmine の構築__

https://qiita.com/ax_kazz/items/1285534b46aeb307d7e0

[前回記事](https://qiita.com/ax_kazz/items/1285534b46aeb307d7e0 "引用・謝辞")の続きです。

# 課題

## 手順がスマートじゃない。

Redmine + MySQL の導入のみ記事[^1] や、SSL証明書 + Nginx を簡単に導入できるようなイメージを利用した記事[^2] もありましたが、セキュリティやイメージのメンテナンス継続性など、諸々の事情で見送っていった結果、これに落ち着いてしまいました。

[^1]: 一番面倒なSSL証明書について、触れられていない。

[^2]: イメージのメンテナンス継続力やセキュリティ上の担保が不明。


そのため、手順がかなり面倒（わかりにくい）です。
正直このレベルであれば EC2 土台にそのまま実装してもいいと思います。

でもそうすると、この記事の存在意義が問われてしまうので、学んだ記録として残しておくことにしました。

# 引用・参考・謝辞

一部の引用については、記事途中にて引用元のリンクを掲載していますが、一連の記事作成をするあたり、全体の流れなどを参考にした記事について、こちらに掲載します。

http://kikei.github.io/server/2020/07/11/redmine.html

https://qiita.com/tu-kun/items/a8aa0926b090b7cccc9d

そのほか、先人達の各種お知恵を拝借しました。
これらの記事があったからこそ、目的の環境構築と記事作成ができました。感謝感謝。
Androidアプリの新規プロジェクト作成

スマホ、タブレット向けのAndroidアプリの新規プロジェクト作成方法。Java言語使用。

## 環境

- Android Studio: Arctic Fox 2021.3.1

## 手順

- File > New > New Project を選択
- Phone and Tablet, No Activity を選択
- 必要事項を入力
 - Name: 適宜。大文字で始まる必要あり。
 - Package Name: 適宜。
 - Save location: 適宜。
 - Language: Java
 - Minumum SDK: デフォルトで API 21 Android 5.0(Lollipop)
なんとなく使っていたアロー関数を改めて調べてみました

# はじめに
普段何気なく使っているものでも原理を理解しないまま使ってしまっていることが多く、今回改めてアロー関数の理解を深めてみました。

# アロー関数って何？

下記矢印のような記号を使った省略記法。

```jsx
const sayHello = (name) => {
	console.log("hello" + "," + name);
};

sayHello(Taro);
//出力結果　hello,Taro
```

本来の関数リテラルだと下記のように書く。

```jsx
const sayHello = function(name){
	console.log("hello" + "," + name);
};

sayHello(Taro);
//出力結果　hello,Taro
```

# アロー関数を使うと良いこと

関数リテラルをより簡略に記述できる。

# 関数リテラルとは？

functionではなく変数に代入する形で関数を定義したもの。

先程のこれ。

```jsx
const sayHello = function(name){
	console.log("hello" + "," + name);
};

sayHello(Taro);
//出力結果　hello,Taro
```

# 関数リテラルってなにがいいの？

関数名をつけなくていいため一度きりの処理を定義するときに楽。

普段仕事でfunctionを使わないようにしているという記事もあったので今後は関数リテラル（関数式）で書くのが主流になるのか・・


参考記事：
[JavaScript の デコレータ の使い方 - Qiita](https://qiita.com/kerupani129/items/2b3f2cba195c0705b2e5)


ようするに一度しか処理で利用しない関数（再利用しない）にいちいち関数名をつけたくない。なぜなら同じ関数名を誤ってつけると処理が上書きされるから。また、どうせ名前ないなら短い記述でシンプルにかけるからいいよねってことだと理解。

### リテラルって？

> リテラルとはプログラム上で数値や文字列など、データ型の値を直接記述できるように構文として定義されたものです。 たとえば、"と"で囲んだ範囲が文字列リテラルで、これは文字列型のデータを表現しています。

```jsx
// ""で囲んだ範囲が文字列リテラル
const str = "こんにちは";
```

```jsx
true; // => true
false; // => false
```
参考記事：
[データ型とリテラル](https://jsprimer.net/basic/data-type/)

# 先程の関数リテラルをより省略してみる

`省略後`

```jsx
//functionと()を省略
//{}を省略
const sayHello = name => console.log("hello" + "," + name);

sayHello(Taro);
//出力結果　hello,Taro
```

`先程のコード`

```jsx
const sayHello = function(name){
	console.log("hello" + "," + name);
};

sayHello(Taro);
//出力結果　hello,Taro
```

# mapやreduceでも使われるアロー関数

通常の書き方

```jsx
let numbers = [1, 2, 3, 4, 5];

const doubleNum = numbers.map(function(number){
	return number * 2;
};
```

省略後

```jsx
let numbers = [1, 2, 3, 4, 5];

const doubleNum = numbers.map(number => number * 2);
```

シンプル！

# まだまだ奥が深いアロー関数

今回は触りの部分だけをまとめましたが、通常関数とアロー関数ではthisを使える使えないの違いがあったり、prototype, argumentsのありなしがあったりと奥が深い。アロー関数を用いた関数式で定義された変数はthisの参照先が異なるためクラスメソッドとしては使えないなど。

参考記事：
[【JS】アロー関数のthisの挙動（プロトタイプとクラスの違い） - クモのようにコツコツと](https://www.i-ryo.com/entry/2020/02/18/063604)

引き続き研究を続けたいと思います。
AtCoderログ：0098 - ABC 216 A

# 問題

https://atcoder.jp/contests/abc216/tasks/abc216_a

## 問題文
> 実数 $X.Y$ が与えられます。ただし $Y$ はちょうど $1$ 桁です。
> ・$0 \le Y \le 2$ ならば、$X-$
> ・$3 \le Y \le 6$ ならば、$X$
> ・$7 \le Y \le 9$ ならば、$X+$
> と出力してください。

## 制約
> ・$1 \le X \le 15$
> ・$0 \le Y \le 9$
> ・$X$ と $Y$ は整数

# 回答
## 回答1 (AC)
小数は小数点以下1桁なので、10倍すれば整数演算に持ち込むことが出来ます。コードは以下のようになりました。

```C++:abc216a-1.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  float r;
  cin >> r;

  int z, x, y;
  z = (int)(r*10);
  x = z/10;
  y = z%10;

  string add = "";
  if ( y<=2 ) {
    add = "-";
  } else if ( y>=7 ) {
    add = "+";
  }

  cout << x << add << endl;
}
```

# 調べたこと
## [AtCoder の解説](https://atcoder.jp/contests/abc216/tasks/abc216_a/editorial) → [公式解説](https://atcoder.jp/contests/abc216/editorial/2467)
string 型変数を使った回答が紹介されていました。

# リンク
## 前後の記事
- 前の記事 → [AtCoderログ：0097 - ABC 216 に参加しました](https://qiita.com/RoadLynton/items/744eddfc48b9fc1d9c29)
- 次の記事 → [AtCoderログ：0099 - ABC 216 B](https://qiita.com/RoadLynton/items/faa58e3479f57cd5536a)
PHPでオートロード（spl_autoload_register）処理を行う

#はじめに
PHPでクラスファイルを読み込んでいくと、気づいたらrequire_onceがたくさん羅列している状況に。。
これを改善する為、オートロード処理を行います。

#今回の設定
たとえば、以下のようなディレクトリ構造のとき。

```
hoge/
├ ClassA.php
├ ClassB.php
├ ClassC.php
└ Main.php
```

ファイルを読み込んでいくとrequire_onceがたくさん。

```php:Main.php
<?php

require_once('./ClassA.php');
require_once('./ClassB.php');
require_once('./ClassC.php');

```

そこでオートロードを行います。
オートロードを行うことで、newしたいクラスを毎度requireする必要がなくなります。

#オートロード処理
まず、Main.phpと同じhogeディレクトリに`Autoload.php`を作成します。

```
hoge/
├ ClassA.php
├ ClassB.php
├ ClassC.php
├ Autoload.php
└ Main.php
```

続いてAutoload.phpに処理を書いていきます。

```php:Autoload.php
<?php

class Autoload
{
    private $directories = array();
    
//newしたいクラスを探すディレクトリを登録します。
//今回の場合はhogeディレクトリが引数に入ります。
    public function registerDirectory($dir)
    {
        $this->directories[] = $dir;
        return;
    }

//未定義のクラスが呼ばれると、loadClass（コールバック関数)が呼ばれる処理です。
    public function register()
    {
//spl_autoload_register関数は、未定義のClassAが呼ばれた場合、"ClassA"を探しにいくよっていう関数です。
        spl_autoload_register(array($this, 'loadClass'));
    }

//引数には未定義のクラス名が入れられます。
//$filepathについては、今回の場合だとhogeディレクトリのパスが$dirに当てはまるイメージです。
    public function loadClass($className)
    {
        foreach ($this->directories as $dir) {
//ClassAを探す場合は右のようになります。　$filepath = hoge/ClassA.php;
            $filePath = $dir . '/' . $className . '.php';
            if (is_readable($filePath)) {
                require $filePath;
                return;
            }
        }
    }
}
```

次はMain.phpを修正します。

```php:Main.php
//require_once('./ClassA.php');
//require_once('./ClassB.php');
//require_once('./ClassC.php');
require_once('./Autoload.php');

$loader = new Loader();
//__DIR__はマジック定数といい、フルパスが入ります。
$loader->registerDirectory(__DIR__);
$loader->register();

```

これで、たとえMain.phpでClassAやClassBがnewされても、オートロード処理によってファイルを探しにいってくれます。
見栄え的にもすっきりしました。
今度はcomposerでオートローダーを入れることも試してみたいと思います。

###参考
- [「__FILE__」や「__DIR__」などPHPのマジカル定数を活用しよう](https://helog.jp/php/magical/)
- [【図解】phpのautoloaderとは？使用例と概要を説明。](https://mrkmyki.com/%E3%80%90%E5%9B%B3%E8%A7%A3%E3%80%91php%E3%81%AEautoloader%E3%81%A8%E3%81%AF%EF%BC%9F%E4%BD%BF%E7%94%A8%E4%BE%8B%E3%81%A8%E6%A6%82%E8%A6%81%E3%82%92%E8%AA%AC%E6%98%8E%E3%80%82)
【pandas】DataFrameでifっぽいことをやる

## locを使って、特定の条件であれば値を追加したい

下記のようなDataFrameのnameカラムがひらがなのみ、カタカナのみだった場合、kindカラムに「ひらがな」「カタカナ」と文字列を入れたい。

```
   id   name
0   1  あいうえお
1   2  かきくけこ
2   3  サシスセソ
```
を

```
   id   name  kind
0   1  あいうえお  ひらがな
1   2  かきくけこ  ひらがな
2   3  サシスセソ  カタカナ
```

このように修正したい

## コード

ひらがな・カタカナの正規表現にあてて、trueだった場合値を入れるような形

```python
import pandas as pd
import numpy as np
import re

df = pd.DataFrame(
    data={
        'id': [1, 2, 3],
        'name': ['あいうえお', 'かきくけこ', 'サシスセソ']
    }
)

pattern = re.compile('^[\u3040-\u309F]+$')
df.loc[df['name'].str.match(pattern), 'kind'] = 'ひらがな'

pattern = re.compile('^[\u30A0-\u30FF]+$')
df.loc[df['name'].str.match(pattern), 'kind'] = 'カタカナ'
print(df)
```

pandas.DataFrame.locびドキュメントは[こちら](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.loc.html)
【kintone】 DOMで添付ファイル数を取得する

## 【注意】
kintoneではDOM操作はお勧めできない。
→アップデートでクラス名などが更新される可能性あるため。
ただし[kintone JavaScript API](https://developer.cybozu.io/hc/ja/articles/360000361686-kintone-JavaScript-API-%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88-%E4%B8%80%E8%A6%A7) 内で添付ファイルを取得できないイベントがあるため仕方なく利用する場合もある。

## 添付ファイル数を取得する

**PC版**

```Javascript:PC
//<div class="plupload_file_name" title=""></div>

//countに添付ファイル数を入れる
var count = document.getElementsByClassName('plupload_file_name').length;
```

**モバイル版**

```Javascript:モバイル
//<div class="forms-file-preview-caption-name-gaia"></div>

//countに添付ファイル数を入れる
var count = document.getElementsByClassName('forms-file-preview-caption-name-gaia').length;
```


※参考にした質問
[添付ファイルの無し判定](https://developer.cybozu.io/hc/ja/community/posts/360018052623-%E6%B7%BB%E4%BB%98%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E7%84%A1%E3%81%97%E5%88%A4%E5%AE%9A)
UIStackViewを使ってViewを比で分割したい

## やりたいこと
![memo_1630333626.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1477548/fd31da3a-9345-bb83-dc61-5d9443be2b4c.jpeg)
↑のようなイメージでViewを比で分割したい

## 環境
Xcode 12.5.1
Swift 5.4.2

## UIStackViewの準備
```swift
import UIKit

class ViewController: UIViewController {
    
    let topView: UIView = {
        let view = UIView()
        view.backgroundColor = .red
        return view
    }()
    
    let middleView: UIView = {
        let view = UIView()
        view.backgroundColor = .yellow
        return view
    }()
    
    let bottomView: UIView = {
        let view = UIView()
        view.backgroundColor = .black
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        //UIStackViewの設定
        let stack = UIStackView(arrangedSubviews: [topView, middleView, bottomView])
        stack.axis = .vertical
        stack.alignment = .fill
        stack.distribution = .fillEqually
        stack.translatesAutoresizingMaskIntoConstraints = false
        
        //viewに追加
        view.addSubview(stack)

        //制約を追加
        [
            stack.topAnchor.constraint(equalTo: view.topAnchor),
            stack.leftAnchor.constraint(equalTo: view.leftAnchor),
            stack.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            stack.rightAnchor.constraint(equalTo: view.rightAnchor)
        ].forEach { $0.isActive = true }
         
    }
    
}
```
<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1477548/c1aa81a5-a55b-8f1d-38f5-9bd5bdcc91a7.png">
↑実行するとこんな感じ，これを比率で分けたい

## それぞれのViewの高さの制約をいじってみた
```swift
        [
            stack.topAnchor.constraint(equalTo: view.topAnchor),
            stack.leftAnchor.constraint(equalTo: view.leftAnchor),
            stack.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            stack.rightAnchor.constraint(equalTo: view.rightAnchor),
            // 高さの制約を追加
            topView.heightAnchor.constraint(equalTo: stack.heightAnchor, multiplier: 1/6),
            middleView.heightAnchor.constraint(equalTo: stack.heightAnchor, multiplier: 2/6),
            bottomView.heightAnchor.constraint(equalTo: stack.heightAnchor, multiplier: 3/6)
        ].forEach { $0.isActive = true }
```
高さの制約を追加し，stackViewのdistributionをfillEquallyからfillに変更
上のコードではmultiplierパラメータのところで高さの比を1:2:3に設定
※当然ながらmultipilerパラメータの値の合計が1になっていないと制約が無視されて表示されます．
<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1477548/005c3156-ded9-4d77-c88b-32df9a174b57.png">
いい感じにできました．
## 最後に
```swift
extension UIStackView {
    func divide(by ratio: [CGFloat], baseHeight: NSLayoutDimension) {
        translatesAutoresizingMaskIntoConstraints = false
        for (view, element) in zip(arrangedSubviews, ratio) {
            view.heightAnchor.constraint(equalTo: baseHeight,
                                         multiplier: element/ratio.reduce(0, +)).isActive = true
        }
    }
}
```
関数にしてみました．　
もっと良い書き方あるよっていう方は教えていただけると幸いです！ありがとうございました！
Firebase メールアドレスとパスワードで新規登録、ログイン機能　(復習)

# 今回の内容

* Firebase メールアドレスとパスワードで新規登録、ログイン機能を使った時の復習です。

##コード

* `import Firebase`を忘れないようにしましょう。

```Swift:import
   import Firebase
```

##新規登録機能

```Swift:新規登録機能
    func signUp(emailString:String, passwordString:String){
        
        Auth.auth().createUser(withEmail: emailString, password: passwordString) { (result, error) in
            
            if error != nil { print(error.debugDescription) return } 
            
        }
        
    }
```

##ログイン機能

```Swift:
    func login(emailString:String, passwordString:String){
        
        Auth.auth().signIn(withEmail: emailString, password: passwordString) { (result, error) in
            
            if error != nil{print(error.debugDescription) return}
        
        }
            
    }
```

#終わり
ご指摘、ご質問などありましたら、コメントまでお願い致します。
Automation 360の画像認識アクション

# はじめに
今度は、画像認識アクションを使ってみます。

# 画像認識パッケージの基本的な使い方
使い方の説明は以下。
https://docs.automationanywhere.com/jp-JP/bundle/enterprise-v2019/page/enterprise-cloud/topics/aae-client/bot-creator/commands/cloud-image-recognition-action.html

(1) 画像を探す範囲を指定する。
(2) その範囲の中で、探す対象となる画像を指定する。
という形をとります。

ここで(2)の探す画像を
予め用意した画像ファイルで指定するのが「ウィンドウで画像を検索」、
探す対象の画像を画面内(ウィンドウ内)から指定するのが「ウィンドウでウィンドウを検索」、
になります。

簡単な例でGoogle Mapのとある範囲でワイナリーを探してみます。
ここでは「画像認識: ウィンドウでウィンドウを検索」を使います。
まず(1)にあたる探す範囲を指定。
対象のウィンドウを選択し、「領域をキャプチャ」で範囲を指定。
![gmap1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632535/8d928fb4-5c0c-d91d-ffec-affacb039a19.png)

次に、「ターゲット画像をキャプチャ」で探したい画像を画面上からキャプチャします。
ここではワイナリーのマークをキャプチャします。
![gmap3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632535/a7795c63-578a-569b-c4cc-cab8ae85cac5.png)
小さい画像だとなかなか範囲指定が難しいです。


# 一つの使用例

![gmap2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632535/45c93523-9299-18e9-7594-d635fd400b4a.png)

これで、指定範囲でワイナリーを見つけたら、そこをクリックします。

# オプションの指定
「検出回数」というのが最初わかりませんでした。
どうやら、探す対象画像が複数回検出されたときに、一致があったとみなす機能のようです。
上の例で指定した探索範囲にはワイナリーが３個あります。
検出回数が１～３のときは、一致でのアクションが走りますが、検出回数を４にすると見つからない、というエラーになります。

検出回数を１～３と変えるとクリックする場所も変わるので、何回目に見つかったかを意識してアクションを起こしているようです（ただ、どういう方向で探索しているのかはWeb上では不明でした）。

「検出回数」はなかなか使い所が難しそうですが、１Km四方に１０個以上学校があるところをしらみつぶしに探す、なんて事には使えるかもしれません（ほぼ冗談）。

「一致率」という部分も気になるので、これはまた別の記事で書いてみたいと思います。

# おまけのひとこと
改めて確認してみると「検出回数」ってAutomation Anywhere V11からありますね。
全くノーマークでした。
Linuxのブートシーケンスって？

#はじめに
エンジニア一年生です。
Linuxがどのように起動していくのか気になったので、ざっくりとまとめました。


##ブートシーケンスとは
ブートシーケンスとは「PC電源投入後から起動するまでの流れ」のこと。
Unix系OSで広く使われてきたSysV initとsystemdの例を示す。

![スクリーンショット 2021-08-31 21.59.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969534/7f2c7a22-db46-411d-d74e-77143690dde8.png)


SysV initでは、電源を投入するとBIOSが起動する。BIOSはHDDの先頭領域にある`MBR`内のブートローダーをメモリに読み込み、起動させる。ブートローダーはHDDに保存された/boot以下の圧縮されたカーネルコードを読み込む。カーネルは自身を解凍して初期化を行い、1番目のユーザープロセスである`init`を生成する。initが起動すると/etc/inittabファイルを読み込み、サービスを起動する。

systemd(最近のプログラム)はBIOSの代わりに`UEFI`が、1番目のユーザープロセスはinitではなく`systemd`が採用されている。

※BIOSではディスクの先頭のMBR内のブートローダーを起動するが、UEFIではNVRUM(Non Volatile RAM:不揮発性メモリ)に設定された優先順位に従って、ディスクのEFIパーティションに格納されているブートを起動する。

### BIOSとは
PCのハードウェアに組み込まれている不揮発性メモリに格納されたプログラム。
ディスクの先頭ブロック(MBR:Master Boot Record)に書き込まれたブートローダーをメモリにロードする。MBRパーティション形式に基づく、古いブート形式である。

### UEFIとは
UEFIブートエントリで指定されたEFIシステムパーティション中のブートローダをメモリにロードするプログラム。BIOSに代わるファームウェア規格で、大容量ディスク(GPT)への対応、セキュリティの強化など、機能が拡張している。GPTパーティション形式に基づく、新しいブート形式である。

### ブートローダーの役割
BIOSから呼び出されてカーネルをメモリに読み込んでカーネルに制御を渡す。


## パーティション形式について

### MBRとは
MBR(Master Boot Record)は古くからあるパーティション形式。

- 2TB以下
- 最大4個までパーティションを分けれる
- どのマザーボードでも使用可能

パーティションの作成、削除、変更が行えるコマンドはfdisk。

### GPTとは
GPT形式(Globally Unique Identifler partition Table)は比較的新しいパーティション形式。

- 2TB以上(最大8.5ZB)
- 最大128個までパーティションを分けれる
- マザーボードがUEFIに対応している必要がある

パーティションの作成、削除、変更が行えるコマンドはgdisk。
fdiskはGPT形式のハードディスクに対応していない。


参考: https://pc-kaizen.com/difference-between-mbr-and-gpt