OmniAICreator/Qiita-1.07M huggingface dataset:
React-Hook-Formの使い方（Part2：RHFとyupでバリデーション）🌟

## はじめに
Part1ではRHFの使い方。Part2でははRHFとyupを合わせて利用する方法を見ていきます。次回のPart3ではさらにMUIとの併用を見ていきます。

※これはpart2になります。part1は以下リンク
https://qiita.com/shunnami/items/98c0c03e3eb59b5c9c57

## パッケージインストール
```
yarn add yup hookform/resolvers
```

## yupの使いかた
RHFの使い方はpart1で勉強しました。あとはyupの使い方を理解すればすぐに合体させて利用することができます。またyup自体も使い方は簡単です。
すでに詳細な使い方を説明している記事があるので以下を参照してください。
※2ページ目まで読めば次の項目をスムーズに読むことが出来ると思います。

```
https://codezine.jp/article/detail/13518
```

## 組み合わせる
### yupの定義
まずは、バリデーションをyupで定義します。
yup.object().shapeに渡すオブジェクトのプロパティをpasswordにしています。これはregisterで登録したname属性にしてください。

```ts
import * as yup from "yup";
// スキーマ
const schema = yup.object().shape({
  password: yup
    .string()
    .min(4, "4桁以上必須")
    .max(20, "最大20桁")
    .required("必須です")
});
```
### useFormのオプションを設定する
useFormの引数に値を渡すことでオプションを設定できます。yupを利用する際にはuseFormのオプションを設定する必要があります。その設定に必要なのが冒頭でインストールしたyupResolverです。yupResolverの引数には先ほど定義したスキーマを渡します。

```ts
import { yupResolver } from "@hookform/resolvers/yup";

useForm<IFormInputs>({
    // useFormの引数にyupResolverを設定
    resolver: yupResolver(schema)
  });
```
### 全体のコードを確認
上記の2つの工程でyupバリデーションが実現できました。最後にコード全体を見てみます。RHF単体のときよりyupを組み合わせたほうがエラーメッセージがスマートに出し分けできます。

```ts
import { useForm, SubmitHandler } from "react-hook-form";

// yupを利用するなら以下をimportする
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";

// submitされる値の型定義
type IFormInputs = {
  password: string;
};

// submitをハンドリング
const formSubmitHandler: SubmitHandler<IFormInputs> = (data) => {
  console.log(data);
};

// スキーマ
const schema = yup.object().shape({
  password: yup
    .string()
    .min(4, "4桁以上必須")
    .max(20, "最大20桁")
    .required("必須です")
});

export default function App() {
  const {
    register,
    handleSubmit,
    watch,
    formState: { errors }
  } = useForm<IFormInputs>({
    // useFormの引数にyupResolverを設定
    resolver: yupResolver(schema)
  });

  return (
    <form onSubmit={handleSubmit(formSubmitHandler)}>
      <input {...register("password")} />
      {errors.password && (
        // errors.password.messageにはyupのスキーマで設定した値が入る
        <span style={{ color: "red" }}>{errors.password.message}</span>
      )}
      <br />
      <input type="submit" />
    </form>
  );
}
```
tsconfig.jsonについての基本的な説明

# tsconfig.jsonについての基本的な説明

TypeScriptを使用するプロジェクトではプロジェクトルートに**tsconfig.json**というファイルを作成する。
今回はこのファイルの基本的な役割と何ができるのかを記載していく。

## 基本的な役割
**プロジェクトで使用するTypeScriptに関する様々な設定をすることができるファイル。**
ファイル内には様々な設定をすることができ、その種類と内容は常にアップデートされているが、基本的には次の点を押さえておくといいとされている。

- どのファイルをコンパイルすべきか
- コンパイル結果をどのディレクトリに格納するか
- 出力するバージョンのJavaScriptは何にするか

## サンプルコード
サンプルコードは次のようになる。

```typescript
{
	'compilerOptions': {
		'lib': ['es2015'],
		'module': 'commonjs',
		'outDir': 'dist',
		'sourceMap': true,
		'strict': true,
		'target': es2015
	},
	'include': [
		'src'
	]
}
```


## 代表的なオプションの意味
### include
TypeScriptのコンパイラがTSファイルを探すフォルダを指定する。

### module
TypeScriptのコンパイラがTSコードをどのモジュールシステムにコンパイルするかを指定する。
具体的には`commonjs`, `systemjs`, `es2015`などを指定する。

### ourDir
生成するJSコードをどのフォルダに格納すべきかを指定する。

### strict
コードをチェックする際にその厳格さのレベルを決めるための設定。
strictを指定することによって全てのコードが適切に型付けされていることが強制される。
特に理由がない限り、TypeScriptの最大の特徴である静的型付けを活かすために設定すべき。

### target
TypeScriptのコンパイラがTSコードをどのバージョンのJSにコンパイルすべきかを設定する。
具体的には`ES5`, `es2015`など。


## create-react-appやcreate-next-appを使った場合
2021年10月時の最新バージョンではデフォルトでプロジェクトルートにtsconfig.jsonが作成されている。
必要に応じて中身を修正すればいいといった感じ。

## 公式
サポートされるオプションの最新の情報はTypeScript公式ドキュメントを参照。
設定できるキーワード名も記載されている。
http://bit.ly/2JWfsgY

## 参考にした資料
[Programming TypeScript: Making Your JavaScript Applications Scale](https://www.amazon.co.jp/Programming-TypeScript-JavaScript-Applications-English-ebook/dp/B07R86FL4K/ref=sr_1_12?dchild=1&keywords=typescript&qid=1635656010&sr=8-12)
Spring Boot Application を GoogleAppEngineへデプロイ

# 動機
安価に、WEBアプリケーション（Java11かつSpring Boot Application）をHTTPS環境へ置きたかった。
かなり、楽に環境が手に入る。

※当然課金は発生する。

# デプロイしたアプリ

|種類| Verion|
|:---------|----|
|Java|11|
|Spring Boot|2.5.6|

# やったこと
## 1. gcloud CLIインストール
## 2. settings.gradleへ追加
先頭へ追記

```gradle
pluginManagement {
    repositories {
        gradlePluginPortal()
        mavenCentral()
        // add mavenLocal() if you are using a locally built version of the plugin
    }
    resolutionStrategy {
        eachPlugin {
            if (requested.id.id.startsWith('com.google.cloud.tools.appengine')) {
                useModule("com.google.cloud.tools:appengine-gradle-plugin:${requested.version}")
            }
        }
    }
}
```

## 3. `com.google.cloud.tools:appengine-gradle-plugin` gradleへ追加

```gradle
plugins {
    id 'com.google.cloud.tools.appengine' version "2.4.2"
}

```

## 4. src/main/appengineへapp.yaml配置

```yaml
runtime: java11
env: standard
env_variables:
  SPRING_PROFILES_ACTIVE: "production"
```

`env_variables.SPRING_PROFILES_ACTIVE`は特に無ければ不要。


# 補足
## gradleプラグイン`com.google.cloud.tools:appengine-gradle-plugin`の`appengineRun`はJava8環境のみサポート

https://github.com/GoogleCloudPlatform/app-gradle-plugin/issues/375#issuecomment-632475565
【Python】pandas_datareaderで株価取得

## 概要
Pythonを使って株価データを取得します。
取得元は`Stooq`からとし、`pandas_datareader.stooq`を使うと日足データが得られます。
株価データの保存形式はCSVです。


## ソースコード

重要なのは、`GetStockPrice`の最後３行。
コマンドライン引数でデータ開始時刻と終了時刻は入力必須（YYYYMMDD形式）です。
オプションで銘柄と保存ファイルパスを指定してください。

```python:downloadStooq.py
import argparse
import pandas_datareader.stooq as web

from datetime import datetime


def main():
    args = Parse()

    GetStockPrice(args)

    return
    
    

def Parse():
    """
    Get CommandLine Arguments
    
    Note:
        Input Date: YYYYMMDD
    """

    parser = argparse.ArgumentParser()
    parser.add_argument("start", type=str)
    parser.add_argument("end", type=str)
    parser.add_argument("-b", "--brand", type=str, default="TSLA")
    parser.add_argument("-s", "--savePath", type=str, default="./stock.csv")
    args = parser.parse_args()

    return args



def GetStockPrice(args):
    """
    Get Daily Stock Price Between $start and $end

    Args:
        args (argparse): CommandLine Arguments
    """

    # str -> datetime
    start = datetime.strptime(args.start, "%Y%m%d")
    end = datetime.strptime(args.end,  "%Y%m%d")

    # データ読み込み＆保存
    data = web.StooqDailyReader(args.brand, start=start, end=end)
    reader = data.read()
    reader.to_csv(args.savePath)
    
    return


    
if __name__ == "__main__":
    main()
```

## 使い方（例）
```bash:bash
python downloadStooq.py 20210101 20210930 -b AAPL -s test.csv
```

## 詳細

GitHubに置いています。

https://github.com/khfkd/pandas_datareader
入門Power Automate Desktop：第四話「ファイル操作を自動化しよう」

# 自動化する作業
1. 格納先のディレクトリが存在するか確認する。
1. 格納先のディレクトリを作成する。
1. ダウンロードフォルダの中にtxtファイルがあるか確認する。
1. ダウンロードフォルダ内のtxtを格納先ディレクトリに移動する。
1. 移動したファイルをリネームする。

今回はダウンロードフォルダ内のtxtを任意の保存先にリネームして保存する作業を自動化してみます。

# 実際にフローを作る
## 0. 事前準備
目的が一目でわかる名前でフローを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/98c4aac3-93a2-325f-a027-3f7ac71a1a78.png)

## 1. 格納先のディレクトリが存在するか確認する。
アクションから「フォルダーが存在する場合」をドラッグしてフローにドロップします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/55f0bd79-41e4-c519-d766-f907913f85e1.png)
アクションの設定画面が表示されるので、フォルダーパスに存在確認したいフォルダを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/ffee6cbc-a0f9-906e-b2fa-fd0dc4ac4321.png)
追加されるとこんな感じです。
※IFの条件を「存在しない」にしてますが、アクション名は「フォルダーが存在する場合」と表示されます。(わかりずらい。。。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/cf44d175-3f11-e585-791b-7263a9074b88.png)

## 2. 格納先のディレクトリを作成する。
アクションから「フォルダーの作成」をドラッグしてフローにドロップします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/9b0fd3c3-a84e-61c9-8281-bcc3acd26bd2.png)
アクションの設定画面が表示されるので、フォルダの追加場所とフォルダ名を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/a9acf1db-df77-8e52-b330-d0636864d6b1.png)
追加されるとこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/8dc38254-408d-a2db-b3a3-1ecf1968e940.png)

## 3. ダウンロードフォルダの中にtxtファイルがあるか確認する。
アクションから「ファイルが存在する場合」をドラッグしてフローにドロップします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/c8ea75dd-12d4-8f0b-a9f8-ce9e022ee94b.png)
アクションの設定画面が表示されるので、存在確認したいファイルを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/0da33f47-712c-8fab-f23f-115de9495f69.png)
追加されるとこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/241f047a-cade-e2e1-63f5-93a41edb2e20.png)

## 4. ダウンロードフォルダ内のtxtを格納先ディレクトリに移動する。
アクションから「ファイルの移動」をドラッグしてフローにドロップします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/27347c15-8118-f778-be61-72b02ee90aac.png)
アクションの設定画面が表示されるので、移動するファイルのパスと移動先のフォルダのパスを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/1a85634a-4e7a-977a-682f-0b0e287f2e74.png)
追加されるとこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/cd1ff2b0-5b4c-d532-5e10-039f7cc824ed.png)

## 5. 移動したファイルをリネームする。
アクションから「ファイルの名前を変更する」をドラッグしてフローにドロップします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/40e9057e-dfda-4781-c999-45f6669f2caf.png)
アクションの設定画面が表示されるので、変更対象のファイルパスを設定します。(今回は既存の名前に+日付を追加します)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/c9f1bd79-04b4-c0ef-4bea-c07980886a0d.png)
追加されるとこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/484fb57d-fcbf-d05b-7807-0bd1ccb548d8.png)

# 作成したフローを実行してみる
作成したフローを実行する。
実行後にマイドキュメント配下に「narou」ディレクトリが作成され、中に「narou_20211030.txt」の様に日付が追加されたファイルがあれば成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/e7b21c9d-bcf8-2b6b-0bf7-11a5d64feca6.png)
HS256のJWS署名検証テスト

# 環境
| | Version | 
|:----|:----|
|Java| 11|
|Spring Boot | 2.5.6|
|JUnit | 5.7.2 |

# HS256の署名検証
## 仕様
[OIDC 1.0 IDTokenValidation](https://openid-foundation-japan.github.io/openid-connect-core-1_0.ja.html#IDTokenValidation)

HS256のID Tokenは、`client_secret`を鍵として用いて署名されている。

# やり方
ここ（[JSON Web Signature (JWS)
 Example JWS using HMAC SHA-256](https://openid-foundation-japan.github.io/draft-ietf-jose-json-web-signature-14.ja.html#HS256Example)）をお手本にするのが良さそう。

# コード

```java
@Slf4j
@SpringBootTest
public class JWTSignatureVerifyTest {
    // TODO 調達したsecretで置き換えてください。
    @Value("${spring.security.oauth2.client.registration.dummy.client-secret}")
    private String secret;

    @Test
    public void test() throws NoSuchAlgorithmException, InvalidKeyException {
        // TODO 調達したHS256署名されたIDトークンで置き換えてください
        String idToken = "dummy";
        var signatureStart = idToken.lastIndexOf(".") + 1;
        var bodyEnd = idToken.lastIndexOf(".");

        var headAndBody = idToken.substring(0, bodyEnd);
        var signature = idToken.substring(signatureStart);

        var jwtInput = headAndBody.getBytes(StandardCharsets.UTF_8);
        String algo = "HmacSHA256";
        SecretKeySpec sk = new SecretKeySpec(secret.getBytes(), algo);
        Mac mac = Mac.getInstance(algo);
        mac.init(sk);
        log.info("headAndBody:{}", headAndBody);
        byte[] mac_bytes = mac.doFinal(jwtInput);

        byte[] encoded = Base64.getEncoder().encode(mac_bytes);

        log.info("original signature:\t{}", signature);
        var encodedString = new String(encoded);
        log.info("encodedString:\t{}", encodedString);
        var encodedStringReplaced = encodedString.replaceAll("\\+", "-").replace("/", "_").replaceAll("=");
        log.info("encodedString replaced:\t{}", encodedStringReplaced);
        Assertions.assertThat(encodedStringReplaced).isEqualTo(signature);
    }
}

```

## 最後の方の`.replaceAll("\\+", "-").replace("/", "_")`について
[rfc7515 appendig-C](https://datatracker.ietf.org/doc/html/rfc7515#appendix-C)に詳しくある。

## 最後の方の`replaceAll("=","")`について
[rfc7515 appendig-C](https://datatracker.ietf.org/doc/html/rfc7515#appendix-C)に詳しくある。
Base64エンコーディングすると、規定長にするために`=`がパディングされる。

# 参考資料
[JavaでHMAC-SHA256を計算する](https://kaworu.jpn.org/java/Java%E3%81%A7HMAC-SHA256%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B)
[JSON Web Signature (JWS)
 Example JWS using HMAC SHA-256](https://openid-foundation-japan.github.io/draft-ietf-jose-json-web-signature-14.ja.html#HS256Example)
[Auth0 validate-json-web-tokens](https://auth0.com/docs/security/tokens/json-web-tokens/validate-json-web-tokens)
[oauth2login-advanced-idtoken-verify](https://spring.pleiades.io/spring-security/site/docs/current/reference/html5/#oauth2login-advanced-idtoken-verify)
[JSON Web Token (JWT)
Algorithms ](https://openid-foundation-japan.github.io/draft-ietf-oauth-json-web-token-11.ja.html#Algorithms)
condaでLEfSeを導入するときに注意すること

前回、[QIIME2をjupyterhub上で動かす記事](https://qiita.com/FlaskSakaguchi/items/28d41b4fa3964282a9f6)を書いてから早いもので約10ヶ月が経過しました。QIIME2の更新も(そして我々の解析も)順調に進んでおり、前回の記事のバージョンも古くなっています。今回、2つのサンプルグループの違いを検出する解析が必要になったため、LEfSeの作業環境を追加することにしました。この件に触れた記事も見当たらないので、記事化しておきます。誰かの役に立つといいのですが、主に自分へのメモ書きです。
# インストールで問題だった点
LEfSeについては[公式サイト](https://huttenhower.sph.harvard.edu/lefse/)をご覧ください。GUIで利用するのであれば[Galaxy](http://huttenhower.sph.harvard.edu/galaxy/)でネット越しに利用すれば、なんの問題もありません。[統合TV](https://togotv.dbcls.jp/en/20190412.html)や[youtube等](https://www.youtube.com/watch?v=w-ZVxR4J8DI)が参考になるのではないでしょうか。自分は前述のように開設したjupyterhub上で実行したいので、ローカルに実行環境を作ることにしました。公式にも[github](https://github.com/SegataLab/lefse)にも
`$ conda install -c bioconda lefse`
とだけ書かれています。しかしこれだけでは上手くインストール出来ませんでした。
上記の環境で試しても、新規に作成したconda環境でも、仮想マシンに新規インストールしたOS環境でも、さらっとエラーになりますので、conda環境の中の問題と推定しました。しばらく悩みましたが、以下のようにすると解消します。
まずLEfSeが要求するパッケージの準備
`$ conda search -c bioconda lefse --info`
で表示される依存するパッケージのうち、biom-formatとrpy2の2つ以外はmainチャンネルのもので構いませんが、biom-formatとrpy2の2つはconda-forgeチャンネルのものを指定する必要がありました。

```
$ conda install -c conda-forge biom-format rpy2
$ conda install -c bioconda lefse==1.1.2
```
これで最新のLEfSe 1.1.2となります。
注意点としては、LEfSe 1.1.2のpython要求性が >=3.7 のため、QIIME2-2021.2以前ではLEfSeのバージョンを下げる必要があります。

# QIIME2のアップデート
~~仕方ないので、~~せっかくなのでQIIME2をアップデートします。conda環境を新たに作ってサービスの設定を修正するだけの簡単(?)な作業です。
まずSSH等でサーバにログインし、rootに権限昇格したところから始めます。

```
(base) # wget https://data.qiime2.org/distro/core/qiime2-2021.8-py38-linux-conda.yml
(base) # conda env create -n qiime2-2021.8 --file ./qiime2-2021.8-py38-linux-conda.yml
(base) # conda activate qiime2-2021.8
(qiime2-2021.8) # conda install -c conda-forge jupyterhub jupyterlab biom-format rpy2
(qiime2-2021.8) # conda install -c bioconda lefse==1.1.2
(qiime2-2021.8) # vim /usr/local/sbin/jupyterhub-startup.sh
```

```/usr/local/sbin/jupyterhub-startup.sh
#!/bin/bash

QIIME=qiime2-2021.8

# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/opt/miniconda3/bin/conda' 'shell.bash' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/opt/miniconda3/etc/profile.d/conda.sh" ]; then
        . "/opt/miniconda3/etc/profile.d/conda.sh"
    else
        export PATH="/opt/miniconda3/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda initialize <<<

cd /var/local/jupyterhub
conda activate $QIIME
/opt/miniconda3/envs/$QIIME/bin/jupyterhub -f /etc/jupyterhub/jupyterhub_config.py
```
```
(qiime2-2021.8) # systemctl restart jupyterhub.service
```


これで終了となります。

# 終わりに
今回はLEfSeの導入とQIIME2の更新を行いました。教訓としてエラーの内容はよく読む必要があるということです。特にスクロールで流れてしまうようなエラーは注意深く最初の方の出力まで確認しないと、今回のようにしばらく悩むハメになります。
入門Power Automate Desktop：第二話「基本操作とノウハウを身に着けよう」

# 基本画面の解説

## フロー一覧の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/79fb6e49-60cb-d8c1-0a6c-576c93f82a83.png)
① 新しいフローを作成します。
② Power Automate Desktopの自動起動や設定を行います。
③ フローを実行します。
④ フローの編集を行います。
⑤ リネームなどの他編集を行います。

## フロー編集画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/dbd9cb8b-f43e-0fa6-06a6-44a8515e04c6.png)
① 各アクションの選択メニューです。(パーツ選ぶ画面)
② アクションを並べてフローを作成する画面です。(パーツ並べる画面)
③ フローで定義・設定した変数・UI要素・画像の参照メニューです。(パーツへの設定値を参照する画面)
### 変数画面
変数にはアクションの追加により生成された変数が表示されます。
また前回の実行時点で最終的に格納されていた値も表示されるので、デバッグにも使えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/4b681548-6ee7-fc5f-5ba2-791260e30220.png)

### UI要素画面
ブラウザやアプリの自動化のために追加したUI要素の一覧が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/c9490e00-3dcf-d624-9044-8cf878db6d94.png)


# ノウハウ

## サブフローを活用して処理を分割する
最初から存在する「Main」フローはC言語などでのMain関数に該当します。
サブフローはC言語などでの関数追加に該当し、他フローから呼び出して利用する事が出来る機能です。

### 1. サブフローの追加
画面中央の「サブフロー」から既存のサブフローの確認や新規追加が行えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/8ee7122c-c612-ff2a-3014-41266751c26f.png)
### 2. サブフローの呼び出し
アクションから「サブフローの実行」をドラッグしてフローにドロップします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/9e466d2b-dcc7-0216-7093-15b5bb70e9d5.png)
呼び出すサブフローを聞かれるので、任意のサブフローを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/08376631-69b5-d5ef-fcca-c1474386e780.png)
フロー上ではこんな感じで反映されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/293b3284-769e-17be-a63d-be90c695ca76.png)

## 誤実行対策としてフロー開始時に起動確認を行う
誤って実行すると困るフローであれば、起動確認を得るようにしましょう。
(そのうえで間違えてYESを押したら諦めましょう)

### 1. ダイアログの追加
アクションから「メッセージを表示」をドラッグしてフローにドロップします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/974832f0-48a0-da8b-c87d-3cc4c19beac9.png)
### 2. ダイアログの設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/cae90471-4d21-499a-77d0-68acce5f08d0.png)
① ダイアログのタイトル
② ダイアログ内のメッセージ
③ ダイアログのアイコン
④ ダイアログに表示されるボタンの種類です。(起動確認なら「はい - いいえ」でいいと思います。)
⑤ ダイアログは最前面にあった方が見落としがないので、有効にしましょう。
⑥ ダイアログで選択した内容が格納されます。(この後のIFでこの値を確認します)
### 3. 実際に表示されるダイアログ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/66b713cb-1272-9166-f516-d316158db00b.png)
### 4. ダイアログの回答を確認
アクションから「If」をドラッグしてフローにドロップします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/ed8432e2-debd-61e3-7844-0e383b47aff9.png)
### 5. ダイアログの回答確認を設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/78110fe7-f0fa-bd38-f238-c46cc7bef315.png)
① {x}からフロー内の変数を選択できるので、ダイアログで設定した変数を選択します。
② 比較条件です。今回は「はい」ボタンを押したか確認したいので＝を選択します。
③ 変数に何が入ってて欲しいかを設定します。ここでは「はい」ボタンを押下した際に入る「Yes」を設定します。

下記の様に追加されるのでIFの中に実行したいアクションを追加していきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/5f71a06c-e5b5-5f4f-3354-32a2dfd8bcaa.png)
rails6 bootstrap5導入方法

#はじめに

railsチュートリアルを進めるに当たってbootstrap3を導入することがあるのですが、２周目でローカル環境で進めていることもあり、bootstrap5を使用してみようと思い、導入できるようになるまでの備忘録です。
詳しいことは分かりませんが色々な記事を参照して自分にできそうな方法で導入しました。

railsチュートリアル同様、gemを入れてsassにインポートするやり方です。

#筆者の環境

`Macbook Air(M1, 2020)`
`macOS Big Aur バージョン11.4`

`ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [arm64-darwin20]`
`Rails 6.1.4.1`

#①gemを入れる
bootstrap3では’gem bootstrap-sass’を入れていましたが、bootstrap5では２つ入れるそうです。

```ruby:Gemfile
gem 'bootstrap', '~> 5.1'
gem 'jquery-rails'
```

#②cssファイルをscssに変更する
こちらはrailsチュートリアル同様に行いました。

#③importする

railsチュートリアル同様custom.scssを新しく作り,一番上に次のように記述します。

```custom.scss
@import "bootstrap";
```

```
@import "bootstrap-sprockets";
@import "bootstrap";”
```
このようにrailsチュートリアルでは書かれていますが、

```
@import "bootstrap-sprockets";
```

こちらの部分でSyntaxErrorが出てしまい動きませんでした。

#他にも

・bootstrapファイルをダウンロードしてそれを参照する方法
・htmlファイルにbootstrapのHP情報等を記載して読み込む方法
・yarn,npmなどを使う方法

などがあるようでした。
EJB・EJB3・JPAの関係性

### 導入

hibernate-toolsでリバースエンジニアリングする際に「EJB3」「JPA」「POJO」らへんの単語がでてきたが、関係性がちゃんと理解できなかったので記事にまとめる。

---
### まず結論（EJB・EJB3・JPAの関係性）

・EJB3は「EJBの上位互換」
・EJBでは「POJOを使えない」 EJB3から「POJOを使える」
・JPAは「EJB3でPOJOを使うために利用されているもの」。JPA単体では１つの技術として独立しており、**EJB3がJPAという技術に依存している**関係性

---
### JPA

　「JavaでORMを使うための仕様」

・Java Persistence API
・Java標準のORMの**仕様(specification)**
・**実装(implementation)**が別で提供されている。Springはデフォルト実装として「Hibernate」を利用する。
https://stackoverflow.com/questions/41902856/spring-boot-jpa-hibernate-as-default
・Beanクラスにある下記のようなアノテーションがJPAで定義されているもの

```
import javax.persistence.Entity;

@Entity
public class SampleBean {
　　　　　　public String field1;
　　　　　　public int field2;
}
```

---
### Hibernate

　「JPA(仕様)の実装」

・沼なのでここでは詳しい説明割愛
・**JPAの実装**ということだけ理解しておけばとりあえずいい。

---
### EJB(Enterprise Java Beans)

　「エンタープライズアプリケーション用の仕組み/フレームワーク」
　　もしくは
　「EJBコンテナに登録するオブジェクト(POJOと対極にあるもの)」
　　を指す
　「**POJOが使えない(=EJBを利用する)フレームワーク**」

> ■ EJBとはどんな仕組み？
> EJBコンテナと呼ばれるところにオブジェクトをプールし、そのコンテナからオブジェクトを取り出して物理的に離れたところにあるオブジェクトにアクセスできるようにする仕組み
> http://lasaya.blog129.fc2.com/blog-entry-17.html

・このフレームワークを使うにあたり、オブジェクトは一定の決まりに従って実装する必要がある（フレームワーク側で用意されたインタフェースをimplementsする必要があったりなど）
＝＝こういう「**フレームワークに縛られた実装/コーディング**」をする必要がないものが「**Plain(単純な)** Old Java Object(POJO)」と呼ばれる。

---
### EJB3

　「POJOを使えるEJB」

・**EJB2までは**「javax.ejb.EntityBeanインタフェースをimplmentsしたBeanクラス」のように**フレームワークに縛られた状態にあった**。
・「**Bean1つ定義するたびに毎回javax.ejb.EntityBeanインタフェースに沿って実装するのだるくね？**」という流れで**EJB3ではPOJOとして扱えるようにアップデートされた**。
　＝EJB2まで＝
　　javax.ejb.EntityBeanインタフェースをimplments
　＝EJB3＝
　　**JPAの**@Entity(javax.persistence.entity)等の**アノテーションをつけるだけでOK**

https://stackoverflow.com/questions/8952730/how-does-ejb-and-jpa-relate

---
### まとめ（EJB・EJB3・JPAの関係性）

・EJB3は「EJBの上位互換」
・EJBでは「POJOを使えない」 EJB3では「POJOを使える」
・JPAは「EJB3でPOJOを使うために利用されているもの」。JPA単体では１つの技術として独立しており、**EJB3がJPAという技術に依存している**関係性

---
### 自分用MEMO

・hibernate-toolsのreverse engineeringでEntityクラスを自動生成する時に「ejb3」というオプションがある。この意味は「(ejb3で利用している)JPA・Hibernateのアノテーション等を利用してEntityクラスを生成するかどうか」である。Spring Data JPA等のJPAを利用するアプリケーションの場合はこいつを「true」に設定する必要がある。

https://github.com/hibernate/hibernate-tools/blob/master/ant/src/main/java/org/hibernate/tool/ant/Hbm2JavaExporterTask.java#L41
Chromeでハードウェアアクセラレーションを部分的に利用する

# はじめに
Chromeでデフォルトで有効になっているハードウェアアクセラレーションだが、不具合が多い。
描画がカクついたり、ノイズが走ったり、マルチディスプレイ環境で描画がおかしくなることが多々ある。
場合によっては、Chrome自体が強制終了することもある。
無効にすると、CPU使用率が無駄に上がり、特にYoutubeをはじめとした動画再生などは再生開始時や高画質再生でカクつきの原因になったり、PC全体の動作を重くすることもある。
これらに対して、ハードウェアアクセラレーションを部分的に有効とすることにより、動画再生に限って快適性を追求することができた為、残すこととした。

※ ただし、2021年10月31日現在の設定である為、将来的にChromeがこれらの不具合を解消する可能性も否定できない。

下記の作業上で何かしら不具合が発生しても、自己で責任を負うものとする。
ハードウェアアクセラレーションは、CPUの負荷を下げ、GPUの負荷を上げる為、GPUの発熱に繋がる。
ゲームや動画編集程とはいかないはずだが、GPUに負荷を与えることで何かしら不具合が生じても、当方は責任を取らない。
GPUに負荷を与える行為をしていない場合、一度GPU周りを掃除してから行うことを推奨する。

# 参考環境
Windows10 Professional
Chrome (95.0.4638.54 Official Build 64bit)
Geforce RTX 2070

# 設定
目指すところは、ハードウェアアクセラレーションをビデオデコード周りのみ、有効にすることとなる。
だが、気の利かないことに、このような設定はチェック一つではできない。
ハードウェアアクセラレーションを全体として有効にし、余分なところをそぎ落としていく必要がある。

まず第一に、Chromeの設定、システムから「ハードウェア アクセラレーションが使用可能な場合は使用する」を有効にする。
これにより、ハードウェアアクセラレーションが全体的に有効になる。
![settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520911/5ae90d41-aed9-0b98-9d19-8c1aff025840.png)

次に、アドレスバーに「chrome://flags」を入力する。
設定からはいじれない項目が列挙される。
この時、上のエディットボックスに、gpuと入力すると、いくつかの項目と共に、
・Accelerated 2D canvas
・GPU rasterization
・Enables Display Compositor to use a new gpu thread.
・Out-of-process 2D canvas rasterization.
という4つの項目が列挙されていると思う。
確証は無いし、修正されることもあると思うが、これらの機能が描画周りの不具合や不安定を引き起こす原因となっている。
(少なくとも、この2年間程はバグっている。)
その為、これらの横にあるプルダウンから、「Disabled」を選択し、これらのハードウェアアクセラレーションを無効化にする。
![flags.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520911/7576f248-5ea8-aef9-cb24-8ff096b63476.png)

これらを設定したら、Chromeを再起動する。

# 設定の確認
再起動後、アドレスバーに「chrome://gpu」を入力する。
GPUの設定が列挙される。
「Graphics Feature Status」にいろいろと書かれているが、この時、
「Canvas」が「Software only. Hardware acceleration disabled」
「Canvas out-of-process rasterization」が「Disabled」
「Rasterization」が「Software only. Hardware acceleration disabled」
となっており、
「Video Decode」「WebGL」「WebGL2」が「Hardware accelerated」となっていれば、設定がうまくいっていると言える。
![gpu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520911/1a72f0ed-9b3d-8583-85bc-e01b59c25b97.png)

※ 「Compositing」が「Hardware accelerated」となってしまうが、これは設定で無効にする方法がわからなかった。

# 動作確認
Youtubeなどをはじめとした動画再生を行い、スムーズに再生でき、その他のシーンでは描画周りの不具合が無いことを確認する。
恐らく、動画の再生開始がスムーズになったり、4kなどの高画質の動画がカクつきなく、CPUのファンが回転し始めたりせずに再生できるようになっていることと思う。
(ただし、回線状況によっては、バッファリングやシークに時間がかかり、再生がとぎれとぎれになることもあると思う。
 4k画質はスループットが安定して50Mbps以上が出ることが望ましい。)
代わりに、タスクマネージャの詳細表示や、CPUID HWMonitorなどをはじめとした、GPUの使用状況を確認できるツールでは、動画再生時にGPUの使用率が上がっていることも確認できると思う。

この時、何か動画再生でノイズが走ったり、Chromeの挙動がおかしくなるようなことがあれば、グラフィックボードのドライバーの不具合であったり、Chromeの不具合が発生している可能性がある。
最悪な場合、ブルースクリーンでPCが再起動することも考えられる。
そのような症状が、ドライバーを更新したり、Chromeを更新して治らない場合、ハードウェアアクセラレーションをオフにしたほうが良い。
(潜在的なグラフィックボードの不良も考えられる。)

# 最後に
これらの設定は、Chromeの更新によって不要となる可能性がある。
しかし、これらの機能の更新や不具合修正は一切Chrome側から通知されることは無い。
その為、定期的に設定を戻し、挙動を確認してみることを推奨する。
VBA ユーザーフォーム 

## ブック本体の非表示
```vb
Option Explicit
Private Sub CommandButton1_Click()
'Window本体の表示・非表示
  
  'メモ
  '---------------------------------
  '全BookのWindow
  'Application.Visible = True
  '---------------------------------
  'ThisWorkbookのWindowのみ
  'Windows(ThisWorkbook.Name).Visible = True
  '---------------------------------


  If Windows(ThisWorkbook.Name).Visible = True Then
    Windows(ThisWorkbook.Name).Visible = False
  Else
    Windows(ThisWorkbook.Name).Visible = True
  End If

End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
'[X]ボタン押下時にWindow本体を表示にする
    Windows(ThisWorkbook.Name).Visible = True
 End Sub

```

## コンボボックス / リストボックス
### イニシャライズ
```vb
Private Sub UserForm_Initialize()

  'UserFormが表示される際に実行
  '処理

End Sub
```

### アイテム追加
```vb
'コンボボックス
'①単体追加
UserForm1.ComboBox1.AddItem "aaa"
'②配列追加
Dim cmbList()
cmbList = Array("bbb", "ccc")
UserForm1.ComboBox1.List = cmbList
'③Range範囲追加
UserForm1.ComboBox1.RowSource = Worksheets("Sheet1").Range("A1:A3").Address(External:=True)
```

```vb
'リストボックス
With UserForm1.ListBox1
  .ColumnCount = 2
  .ColumnWidths = "20;80"
  .List = Worksheets("Sheet1").Range("A1:B3").value
End With
```

### アイテム取得
```vb
  '値の取り方
  Dim cmbValue As String, listValue As String
  cmbValue = UserForm1.ComboBox1.Text
  listValue = UserForm1.ListBox1.Text
  MsgBox (cmbValue & vbTab & listValue)
```
Xilinx FPGA > MIG > Zynqには使う必要はないのだろう

### 動作環境

```
Windows 10 Pro (21H1) 
PYNQ-Z1 (Digilent) (以下、PYNQと表記)
Cora Z7
Vivado v2017.4 (64-bit)
Vivado v2019.1 (64-bit)
Vivado v2020.1 (64-bit)
```

## MIG

MIGはDDRコントローラとして使われると理解している。

### FPGAプログラミング大全 第2版 p550

ArtyのBoard情報からMIGを使用する例が掲載されている。

同じことをZynqですると、Board情報にはSDRAMの選択は出てこない。
SPARTAN7では選択できる。

### ACRi: MIG を使って DRAM メモリを動かそう (1)

https://www.acri.c.titech.ac.jp/wordpress/archives/6048

この例では(Zynqではなく)FPGAからDRAMを制御する方法としてMIGが使用されている。

### 疑問 > MIGはどういう時に使う?

Vivadoを使っていて、ZynqでDDRを操作するときにそもそもMIGがBlock Designに出てこない。
CPUコアがないFPGAのBlock Designや、MicroBlazeを使うBlock DesignではMIGを使っている例はブログなどにある。

ZynqではDDRコントロールは入っていてMIGは使わない、ということなんだろうか。


### その他、MIGの使用例

- [ＴＫ８０／ＢＳのシンセシステムを復活／拡張したい～ その４１ ＦＰＡＧシンセの調整、動作確認](http://jun-machinery.ddo.jp/accuracy/computer/tk80_reboot3/tk80_reboot_41.html)
- [Artix-7でのMIGエラー](https://www.living-in.tokyo/post/2017/06/artix7-mig-error/)
- [Xilinx Memory Interface Generator (MIG) による DDR2 SDRAM のアクセス](https://dora.bk.tsukuba.ac.jp/~takeuchi/?電気回路/HDL/Xilinx%20Memory%20Interface%20Generator%20(MIG)%20による%20DDR2%20SDRAM%20のアクセス)
    - Note: サイトにときどきつながらない
- [FPGAの部屋 > MIG](https://marsee101.blog.fc2.com/blog-category-80.html)
- [Zynq のベアメタル・アプリケーションによるキャッシュの操作3（ACPポート2）](http://fpga.blog.jp/archives/cat_561491.html)
- [Zynq Development Report](https://indico.cern.ch/event/802703/contributions/3337275/attachments/1819350/2975012/ZynqSakamoto.pdf)
    - Zynqのブロック図の中に「Memory Interfaces」がある。これがMIGに対応するものなのだろう。
- https://stackoverflow.com/questions/68377806/how-to-write-data-from-fpga-to-ddr3-memory-without-ps-logic/68422697#68422697
    - > On the other hand, if the DDR is correctly pinned out to PL, then you can use the Xilinx Memory Interface Generator (MIG) IP core to build the PL-side logic to interface with it
【学習記録⑫】transitionコンポーネントを用いてアニメーションを作ってみる！

# はじめに
Vue.jsを最近勉強し始めたので学んだ文法などを備忘録としてメモしていこうと思います。
今回は`transition`コンポーネントを用いてアニメーション（簡単なフェードイン、フェードアウト）を作ってみようと思います。

## transitionコンポーネント
Vue.jsでアニメーションを実装する際は組み込みコンポーネントである`transition`コンポーネント、もしくは`transition-group`コンポーネントを用いて実装します。

https://v3.ja.vuejs.org/guide/transitions-overview.html

### 基本的な使い方
基本的な使い方としては以下のようにアニメーションさせたい部分を`tranasition`コンポーネントで囲み、`name`属性へ任意の値を入れます。

```vue:exampleTemplate.vue
<template>
  <transition name="任意の値">
    <div></div>
  </transition>
</template>
```

その後、上記で付けた「任意の値」を用いて以下のクラスを作成します。

* [任意の値]-enter-from
* [任意の値]-enter-active
* [任意の値]-enter-to
* [任意の値]-leave-from
* [任意の値]-enter-active
* [任意の値]-enter-to

以下は「任意の値」を`fade`としたときの例です。

```vue:exampleStyle.vue
<style scoped>
.fade-enter-from {
  /* 処理 */
}
.fade-enter-active {
  /* 処理 */
}
.fade-enter-to {
  /* 処理 */
}
.fade-leave-from {
  /* 処理 */
}
.fade-leave-active {
  /* 処理 */
}
.fade-leave-to {
  /* 処理 */
}
</style>
```

これらのクラスを`トランジションクラス`と言い、それぞれの意味や発火時については以下のドキュメントが参考になります。

https://v3.ja.vuejs.org/guide/transitions-enterleave.html#%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B7%E3%82%99%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%AF%E3%83%A9%E3%82%B9

## 以上を用いてサンプルを作ってみる
以上を用いて、サンプルコードを書いてみます。
内容としては`おはようボタン`というボタンをクリックすると`Good Morning!`という文字がフェードインしてくるものとします。

### サンプルコード

```vue:Morning.vue
<template>
  <button @click="show = !show">おはようボタン</button>
  <transition name="fade">
    <div v-if="show">{{ greetMessage }}</div>
  </transition>
</template>

<script>
export default {
  data() {
    return {
      greetMessage: "Good Morning!",
      show: true,
    };
  },
};
</script>

<style scoped>
.fade-enter-from {
  opacity: 0;
}
.fade-enter-active {
  transition: opacity 0.5s;
}
.fade-enter-to {
  opacity: 1;
}
.fade-leave-from {
  opacity: 1;
}
.fade-leave-active {
  transition: opacity 0.5s;
}
.fade-leave-to {
  opacity: 0;
}
</style>
```

```vue:App.vue
<template>
  <morning></morning>
</template>

<script>
import Morning from "./components/Morning.vue";

export default {
  components: {
    Morning
  },
};
</script>
```
## 結果
以下のように挨拶文がフェードイン・フェードアウトしていることが分かります。
![greeting.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538249/f5f730e8-639b-d111-7e8b-804b98dc985b.gif)

# おわりに
今回は`transition`コンポーネントを用いたアニメーション作成の学習を行いました。
次回は`Animate.css`を用いて色々なアニメーションを実装してみたいと思います。
【Python】ノイズを含む信号を２値化する

# 目的
オシロスコープで観測した波形等のノイズを含む信号を２値化する。

# 課題
ノイズの影響により、変化のタイミングや変化の回数が正しく求まらない。
![img_hein_nashi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499277/d20342fe-6d6d-d3d8-4460-36576c5fb44b.png)

# 解決策
移動平均でデータを平滑化してから２値化する。

# コード
```python:
import numpy as np
import matplotlib.pyplot as plt

# 時間行列
t = np.linspace(0,10,100)

# 真値
y_true = np.sin(t) + 1/3*np.sin(3*t) + 1/5*np.sin(5*t)

# 観測値（真値＋ノイズ）
y_obs = y_true + np.random.randn(100)*0.3

# 平均化に使用する行列
num = 5 # 移動平均に用いる個数
k = np.ones(num)/num # 平均化に使用する行列の重み。移動平均なので均等

# 観測値を移動平均
y_fil = np.convolve(y_obs, k, mode='same')

# 移動平均を２値化（0より大きければ1，0以下であれば0）
y_bin = np.zeros(len(y_fil))
y_bin[y_fil>0] = 1

# グラフ化
fig, ax = plt.subplots()
ax.plot(t, y_true,'r') # 真値
ax.plot(t, y_obs,'k-') # 観測値
ax.plot(t, y_fil,'b--') # 移動平均
ax.plot(t, y_bin,'g-.') # 二値化
ax.legend(['真値','観測値','移動平均','二値化'], prop={"family":"MS Gothic"})

# グラフを保存
fig.savefig("img.png")
```

# 結果
![img_hein_ari.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499277/34f1c636-c136-43c4-66d8-fd4e47674fc6.png)
SELinux に初めて出会ったときのはなし(chrony が起動しない)


## 要するに

* chronyd が起動できなくなった
* ls -Z で関連ファイルの権限設定に問題があることが分かった
* 権限には気をつけていたが，Z オプションで見られるSELinux が定める権限は知らなかったのでびびった

## 経緯

構築環境のサーバ(RHEL) で，時刻同期のためのサービス chrony が起動しなくなりました．

```
[root@ipXXXX ~]# systemctl status chronyd
● chronyd.service - NTP client/server 
  Loaded: loaded (/usr/lib/systemd/chronyd.service; enabled; vendor preset: enabled)
  Active: failed (Result: exit-code) since XX XXXX-XX-XX JST; 17s ago
 ... (code=exited, status=1/FAILURE)

...
Oct 09 hh:mm:ss ip-XXXX systemd[1]: Could not open configuration file /etc/chrony.conf
...

Oct 09 hh:mm:ss ip-XXXX systemd[1]: Failed to start NTP client/server.

...
```

/etc/chrony.conf ファイルが開けないとのことなので，権限まわりを確認してみるとこんなかんじ．


```
[root@ipXXXX ~]# ls -l /etc | grep chrony 
-rw-r--r--.   1  root    root     XXXX Oct 9 hh:mm chrony.conf
-rw-r-----.   1  root    chrony   XXXX Aug 12 hh:mm  chrony.keys
```

これだけ見ても問題なさそうだったので，これだけでは解決できなかった．
後日`ls` コマンドの`-Z` オプションを知り，

```
# ls -laZ /etc/chrony.conf
```

こう叩いてみると，

```
-rw-r--r--. root  root  unconfined_u:object_r:user_tmp_t:s0 /etc/chrony.conf
```

こうなっている．
正常に動いているサーバと比較してみると，この`unconfined_u`に問題がありそう．正しくは`system_u`となっていてほしいところ．

## 解消法

ls コマンドの “-Z” オプションは，ファイルに対してSELinux (外部からファイルへのアクセスを制御するモジュール) で設定されているユーザとかロールの情報を表示する．

どうもこの，ユーザが`unconfined_u`になってしまう現象は，ファイルを他の端末から適当にコピーしてくると起こってしまったりする模様． 見に覚えがありすぎる．

これをSELinux の定めるデフォルトに戻すため，次のコマンドを実行．

```
# restorecon -F /etc/chrony.conf
```

数分待って，chrony のステータスを確認．

```
[root@ipXXXX ~]# systemctl status chronyd
● chronyd.service - NTP client/server 
  Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
  Active: active (running) since Fri ... JST; 6s ago
```

動いてくた．
ちなみに`restorecon -F` を実行した直後は，まだステータス確認しても`could not open lockfile /var/run/chronyd.pid` というエラーが出ていた．pid ファイルの作成に時間が必要だったのかな．

## 教訓

権限むずかしい．．．

![Admin2x.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532781/2afea92d-e7c2-e318-a2dc-8ef63532e20d.png)
Bulmaで長い文字列が原因でレイアウトが崩れるときの対処方法

CSSフレームワークの[Bulma](https://bulma.io/)を使用した際に長い文字列が原因でレイアウトが崩れるときの対処方法です。

## 対処方法

```css:css
.text-break {
  word-break: break-word;
}
```

text-breakクラスを長い文字列が入る親要素に追加します。

## CodePenのデモ
上が長い文字列が原因でレイアウトが崩れている様子で、下が長い文字列があってもレイアウトが崩れていない様子です。

<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="RwZKWbW" data-editable="true" data-user="kwtuku" 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/kwtuku/pen/RwZKWbW">
  bulma-text-break</a> by kwtuku (<a href="https://codepen.io/kwtuku">@kwtuku</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
Xcodeで生成したバイナリ内に含まれているファイルパスの情報を取り除く方法

# 概要

Xcodeでライブラリを生成した際に、バイナリ内にファイルパスの情報が含まれており自分のユーザー名などの情報が見れてしまうということがあった。
それはあまりよろしくないということで、ファイルパスの情報を取り除く方法を記載する。

# バイナリ内にファイルパスの情報が含まれないようにする方法

Xcodeの設定の`Generate Debug Symbols`をNoに変更する

# バイナリ内のファイルパス確認方法

以下のコマンドを使用することで、バイナリ内にユーザー名などがあるかが分かる。
↑の変更後に生成したバイナリで以下のコマンドを打ってユーザー名が引っかからなければOK！

```
strings [バイナリ] | grep [ユーザー名]
```
```
hexdump -C [バイナリ] | grep [ユーザー名]
```
pythonのlambda関数についてまとめてみた

今回のお題
-
今回は、pythonのlambda関数について取り上げます。

例によって自分用のメモです。

目次
-

- lambda関数概要
- 基本的な使い方
- 引数の渡し方のパターン

lambda関数概要
-
まずは、lambda関数とはそもそも何ぞやという話から始めます。

一旦は能書きから入りますが、イメージが湧かなければ一度飛ばした後に次項の具体例をみた上で戻ってきていただいても構いません。

ざっくりと言うと、lambda関数とは名前をつけずに定義できる関数のことを言います。

JavaScriptの無名関数に近いですね。

欠点としては、名前がつかないので複数回使いまわせない、それからpythonの場合は1行でしか書けずif文なども使えない、などがあります。

しかし一度別の箇所で定義したものを呼び出して、と言う手間を省けるので一度しか使わない関数を扱う場合にはコードがスッキリしますし、とりわけ関数の戻り値を別の関数の引数として使いたい場合には大変重宝します。

では、基本的な使い方を見ていきましょう。

基本的な使い方
-

```python
# 公式
lambda x, y: (x / y)
# lambda 変数: 戻り値 の形で関数を定義
```
lambda関数は他の関数の引数として用いることで真価を発揮します。

以下の例を見てください。

sorted関数のkeyとしてlambda関数を用いています。

sorted関数は第一引数のリストを昇順に並べ替えます。

もしkey=の形で関数を指定した場合は、リストの各要素にkey関数を適用させた戻り値で順番が決まります。

今回はlambda関数を用いて各要素を3で割った余りを返すようにしたので、引数として与えたリストが「3で割った余が小さい順」に並べ替えられます。

```python:lambda関数の実験
list = [10, 5, 18]

print(sorted(list)) # [5, 10, 18]

print(sorted(list, key=lambda x: x % 3)) # [18, 10, 5]
```
なお、sorted関数のkeyはあくまで戻り値を使って並び替えの基準を提供するだけです。
元のリストを書き換えたり、新しいリストを返したりするわけではないのでそこは注意してください。

引数の渡し方のパターン
-
あまりないのですが、lambda関数に引数を渡すケースがあるのでそれに関してもまとめておきます。

```python
print((lambda x: 2 * x)(10))
# 出力：20
```
関数の引数として、lambda関数の戻り値を使いたいと言う場合には

```python
(lambda 変数: 戻り値)(引数)
```
と言う書き方をします。

また、他の関数の戻り値がlambda関数になるような場合にも似たような書き方をします。

```python
def hoge(a):
  if a == 10:
    return lambda x: 2 * x

print(hoge(10)(3))
# 出力：6
```
hogeの後の一つ目の括弧はhoge関数に引数を渡すためもの、二つ目は戻り値のラムダ関数に引数を渡すためのものと考えるとわかりやすいですね。

終わりに
-
以上でlambda関数の解説を終わります。
書き方が独特なので早く慣れていきたいですね。
JNIでNullableなint値を受け取り、jobjectからint値に変換する方法

# 概要

JNIを使用したAndroidのアプリをKotlinで作成しているとき、JNIの関数にNullableのKotlinのInt値を渡したいということがあった。
Nullableでない値を渡す場合であればネイティブ側でjintとして受け取るところなのだが、Nullableの場合だとエラーが発生してjintは使用できなかった。
そのため、Nullableな値をネイティブ側でjobjectとして受け取った後にjobjectからint値に変換するということを行ったのでその方法を記載する。

# JNIでjobjectからint値に変換する方法

以下のようにすることでjobjectをint値に変換することができる。

```cpp

// JNI関数の定義はKotlin側の別の場所で以下のように定義されている
external fun sampleFunc(value: Int?): Int

// ネイティブ側のコード
// サンプルなので関数名は適当かつ、int値を返すだけのコード
JNIEXPORT jint JNICALL
con_example_app_sampleFunc(JNIEnv *env, jobject nullableValue) {
    if (nullableValue != nullptr) {
        auto intClass = env->FindClass("java/lang/Integer");
        auto intValueMID = env->GetMethodID(intClass, "intValue", "()I");
        auto intValue = env->CallIntMethod(nullableValue, intValueMID);
        return intValue
    }
    return -1;
}
```

また、今回はKotlinのInt値が渡したが応用として`CallIntMethod`を`CallFloatMethod`や`CallBooleanMethod`などの別の関数にすることでFloat値やBool値の場合でも同じような事ができる。
入門Power Automate Desktop：第一話「まずは環境構築」


# Power Automate Desktopって何？
天下のMicrosoftが作ったRPAツールです。
導入・学習コストが低いので業務のちょっとしたことを自動化する際に利用すると良いでしょう。
またWindwos11で標準搭載されるので、Windows環境の標準自動化ツールになりそう？

# Power AutomateとPower Automate Desktopの違い
Power Automate(以下クラウド版)はクラウドフローのRPAツールです。
様々なWebサービスと接続するコネクタが豊富で、スケジュール実行や様々な条件をトリガにした実行が可能です。
Power Automate Desktop(以下デスクトップ版)はPower Automateがデスクトップ向けに特化したRPAツールです。
ファイル操作やWeb操作、アプリケーションの操作が可能です。

纏めると起動とサービス結合に特化したクラウド版、端末操作に特化したデスクトップ版となります。

# デスクトップ版の有償版と無償版の違い
Power AutomateとPower Automate Desktopの両方があっても、デスクトップ版が無償だとできないことがあります。

| 機能 | 無料 | 有料 | 説明 |
| --- | --- | --- | --- |
|クラウド フローの実行|×|〇|デスクトップ版単体ではスケジュール実行が行えず、フローの起動はユーザーが▶ボタンで実行するしかありません。<br>一方クラウド版ではスケジュール実行やメール受信などをトリガにして起動することが出来ます。<br>つまりクラウド版のフローをスケジュール実行して、クラウドフローからデスクトップ版フローを呼び出すことでPower Automate Desktopの完全自動起動が実現できるのです。|
|作成したフローの共有|×|〇|信じられないことですが、無償版では作成したフローを他人に渡すためにエクスポートすることが出来ません。<br>作成したフローはアカウントに紐づいているので、別のPCでも同じアカウントでログインすれば作成したフローを利用する事は可能です。|

# インストール手順

https://flow.microsoft.com/ja-jp/desktop/

上記のページを一番下に「無料でダウンロードする」を押下する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/34578e77-39da-6e77-f163-e46e1101fe86.png)
遷移先の「Download the Power Automate installer」リンクからインストーラーをダウンロードする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/dba460a8-b3ca-b29b-99f8-c06ba3cca092.png)

何も考えずに「次へ」を押下。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/ac9aabf3-0eb9-b309-af2d-fd5ad1b54cac.png)

一番下の同意のチェックを入れて「インストール」を押下。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/f8bb077e-2e10-0f01-23cc-adc8b7dadb40.png)

自動化で使うブラウザの拡張機能を有効する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/feaa302a-924e-efca-929c-4e1e16c282c5.png)

メールアドレスを要求されるので「MSアカウント」を入力してサインイン。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/d6c259d8-0889-ff00-fbab-c4bbfcf88864.png)

スクロールのほぼ一番下にある「日本」を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/84a37a6f-79a3-1a31-750e-5fd4693aa7ac.png)

この画面までくればインストールは完了です！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/347b1644-b2f0-ea6c-ac62-3a7eaf1c50be.png)
AtCoderのテストケースをDropboxからスクレイピング

atcoder過去問のテストケースはDropboxに保存されていて，Dropboxの仕様上一部のテストケースを一括ダウンロードできないことが知られている↓
https://ut0s.netlify.app/2019/08/atcoder-testcase-downloader/

以下のコードを実行すると，Wolfram言語でABC問題のテストケースを一括ダウンロードします．

###コード(仮)
```wolfram:
session = StartWebSession[];
WebExecute["OpenPage"->"https://www.dropbox.com/sh/arnpe0ef5wds8cv/AAAk_SECQ2Nc6SVGii3rHX6Fa?dl=0"];
links = WebExecute["PageHyperlinks"];
abcProblems = Select[StringContainsQ[#, "/ABC" | "/abc"] &]@links;
Function[link,
  WebExecute["OpenPage" -> link];
  WebExecute[
    "ClickElement" ->
        First@WebExecute[session,
          "LocateElements" ->
              "CSSSelector" -> ".dig-Button-icon-left-wrapper"]];
  Pause@2;
] /@ abcProblems;

```
Gatsbyでの画像表示方法

# 画像の用意
* `src/images`ディレクトリに画像ファイルを保存する。
    * 今回は、Qiitaのロゴ画像を使用する。
        * ダウンロード元 - https://help.qiita.com/ja/articles/others-brand-guideline
        * `src/images/qiita.ping`で保存

# 書き方    
```src/components/ExampleComponent.jsx
import React from 'react';
import QiitaIcon from '../images/qiita.png';

const ExampleComponent = () => (
  <div>
     <img src={ QiitaIcon } alt="Qiita" />
  </div>
);

export default ExampleComponent;
```

# 参考サイト
* [入門者でもわかるGatsbyでの画像の設定方法](https://reffect.co.jp/react/gatsby-image-understand-for-beginner)
Androidでキーボードを閉じられたのを検知する方法

# 概要

AndroidのEditTextを入力時、戻るボタンを押してキーボードを閉じたときに特定の処理を行いたいことがあった。
そのため、Androidで表示されているキーボードが閉じられたのを検知する方法を記載する。
言語はKotlin

# キーボードが閉じられたのを検知する方法

以下のようにすることで、キーボードが戻るボタンで閉じられたのを検知できる。

```kotlin
// EditTextを継承したクラスで以下を定義
override fun onKeyPreIme(key_code: Int, event: KeyEvent): Boolean {
    if(key_code == KeyEvent.KEYCODE_BACK && evnet.action == KeyEvent.ACTION_UP) {
        // TODO キーボードを閉じたときに実行したい処理を書く
    }
    return super.onKeyPreIme(key_code, event)
}
```
iOS14で非推奨となったUITableViewCellのtextLabelプロパティ等の対応（iOS13対応含）

## 経緯
iOS14でUITableViewCellのtextLabelプロパティ等が非推奨（Deprecated）になりました。代わりに、`defaultContentConfiguration`等を使用するのですが、こちらはiOS13非対応のため、現状iOS13以前に対応しているアプリだと使えません。

Xcodeが助け舟を出してくれますが、念の為解決方法をメモしておきます。

## 対応方法
```swift
// クラス名は任意。TableViewControllerを使わない場合、親クラスはUITableViewDataSource
class TableViewController: UITableViewController {

    let itemArray = ["A", "B", "C"]

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        itemArray.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // withIdentifierは任意
        let cell = tableView.dequeueReusableCell(withIdentifier: "ToDoItemCell", for: indexPath)
        if #available(iOS 14.0, *) {
            // iOS14以降の推奨
            var content = cell.defaultContentConfiguration()
            content.text = itemArray[indexPath.row]
            cell.contentConfiguration = content
        } else {
            // iOS13以前
            cell.textLabel?.text = itemArray[indexPath.row]
        }
        return cell
    }
}
```

## 結果

（これまでと変わりません）
![スクリーンショット 2021-10-31 11.30.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505421/e5d8d621-bdb0-35e4-fa81-6eeb983aed12.png)

## 参考
https://developer.apple.com/documentation/uikit/uilistcontentconfiguration
Hyper-V , VMWare pro にある Windows10 を Windows11 にアップグレードしてみる

# Windows11 にアップグレードしてみる
新しいデザインになった Windows11 すこし触ってみたくなり。仮想環境 Hyper-V , VMWare pro に入れてみました。
とりあえず Windows11 の要件で大きく話題になっているのが下記２つ。以外とメンドクサイことがわかりました。

Windows11の要件（ほかにもあるが、下記が特に厄介）
　・UEFI/セキュアブート（boot）
　・TPM1.2/2.0

PC互換性の確認をしてみると・・・やっぱり・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44540/913c5062-5752-7200-43da-454ef957674c.png)

# Hyper-V にある Windows10 を Windows11 にアップグレード
そもそも 既存のWindows（ここでは Windows10） から アップグレード する場合、仮想マシンの世代は [第２世代](https://docs.microsoft.com/ja-jp/windows-server/virtualization/hyper-v/plan/Should-I-create-a-generation-1-or-2-virtual-machine-in-Hyper-V) であることが必須です。UEFI/セキュアブート（boot） の指定は、第２世代 のみ指定できます。

世代の変更は基本的に変更できませんが、やり方は[色々ありそう](https://kakkoyakakko2.hatenablog.com/entry/2020/01/12/003000)ですｗ（そのうち検証してみます）

## 仮想マシンの世代が第２世代の場合
仮想マシンを停止し、設定画面を開き ”セキュリティ”タブを開きます。
下記の箇所をチェックすると。
　・セキュアブートを有効にします にチェック
　　　→ UEFI/セキュアブート（boot） が有効化
　・トラステッド プラットフォーム モジュールを有効にする にチェック
　　　→ TPM1.2/2.0

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44540/b5a589ce-0efc-ef87-f50a-e4dee89bef1c.png)

チェック後にWindowsを起動し PC互換性 で確認してみると Windows11 動作に問題のないことがわかる。
そのまま WindowsUpgradeにて Windows11 が落ちてくるのを待つか自分で導入する。

## 新規に Windows11 をインストールする方法
仮想マシンの世代を ”第２世代”にすれば問題なしです。
気つける点で言えば「Press any key boot from CD or DVD......」で何かキーを押すことね。

参考リンク
　・[Hyper-V 仮想マシンにWindows 11をインストールする方法](https://www.billionwallet.com/windows11/windows11-hyper-v-virtual-machines/)
　・[Windows11は7のプロダクトキーでも認証できるのか](https://www.nichepcgamer.com/archives/windows11-can-be-activated-with-a-windows7-81-and-10-product-key.html)

# VMWare pro にある Windows10 を Windows11 にアップグレード
まずこちらも 「UEFI/セキュアブート（boot） が有効化」されていることを確認します。
たぶん気にせず作っている場合は、BIOSモードになっています。

## UEFI で起動しているか確認
「msinfo32」コマンドを[実行](https://freesoft.tvbok.com/tips/efi_installation/gpt_or_mbr.html)して、UEFI 起動しているのか レガシー BIOS なのかを確認します。

UEFI 起動している場合は、次のステップに進みます。
レガシー BIOS で起動している場合は、"mbr2gpt /convert /disk:0 /allowFullOS" コマンドを使って レガシーBIOSモードをUEFIモードへ変更 する必要があります。
下記の記事にもありますが、非推奨なのでスナップショット取るとかバックアップすることを勧めます。
　・[VMware仮想PCのレガシーBIOSモードをUEFIモードへ変更](https://horaku.shonanwalker.com/post-2876/)

## VMWare のオプションを確認
VMWare 仮想マシン編集をクリックし "オプション" タブの 詳細を確認する。
下記のようになっていれば、ヨシ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44540/59061a57-0b3d-fa85-a7ff-aa518cff11a2.png)

## 仮想マシンの暗号化
暗号化しないとTPMが選択できないので、暗号化する。ちょっと時間がかかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44540/a95be8bf-d73c-ca61-0989-3a144f449f1a.png)


## TPMを追加する
上記の 仮想マシンの暗号化 を設定すると TPM が選択できるようになるので追加する。
これで Windows11 の要件は満たした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44540/16cc6633-8314-80e8-e86d-c9ba29befc01.png)


参考リンク
　・[Tips:VMware仮想PCのレガシーBIOSモードをUEFIモードへ変更](https://horaku.shonanwalker.com/post-2876/)
　・[Tips:Windows11 VMware仮想PCにvTPMを組み込む](https://horaku.shonanwalker.com/post-2872/)

# 非対応CPU+TPM+セキュアブート回避
非対応CPU+TPM+セキュアブート回避 ができるらしい。また試してみます。
　・[Windows11 非対応CPU+TPM+セキュアブート回避の簡単まとめ（手っ取り早く導入する最強編）](https://www.broadcreation.com/blog/news/86520.html)
Androidでアプリ起動時にEditTextにフォーカスがあたらないようにする方法

# 概要

Androidでアプリ作成時にアプリ起動時にEditTextにフォーカスがデフォルトであたっていた。
そのため、特定の端末ではアプリ起動時にキーボードが表示されてしまうという現象が発生した。
この現象を修正するために行った、起動時にEditTextにフォーカスがあたらないようにする方法を記載する。
アプリを作成する際に使用していた言語はKotlin

# アプリ起動時にEditTextにフォーカスがあたらないようにする方法

AndroidのLayoutのxmlでEditTextの親のレイアウトに以下のコードを追加する。
こうすることでアプリ起動時にEditTextにフォーカスはあたらなくなる。

```xml
android:descendantFocusability="beforeDescendants"
android:focusableInTouchMode="true"
```
[macos][swift]管理者でプロセス実行

```swift
import Foundation

let sudo = Process()

// ls を実行してみる
// -S: パスワードを端末ではなく標準入力から読み込む
sudo.launchPath = "/usr/bin/sudo"
sudo.arguments = ["-S", "/bin/ls"]

// パイプを設定
let stdin = Pipe()
let stdout = Pipe()
sudo.standardOutput = stdout
sudo.standardError = stdout
sudo.standardInput = stdin

// 実行
sudo.launch()

// パスワードの末尾には改行が必要
let password = "password"
let passwordWithNewline = password + "\n"

// パスワードを標準入力へ書き込み
stdin.fileHandleForWriting.write(passwordWithNewline.data(using: .utf8)!)
try? stdin.fileHandleForWriting.close()

// 終了まで待機
sudo.waitUntilExit()

// 標準出力を取得
if let data = try? stdout.fileHandleForReading.readToEnd(),
   let output = String(data: data, encoding: .utf8) {
    print(output)
}
```
Google Apps Script発のHTTPリクエストはどのIPアドレスから発信されるのか？

## 動機

* Google Apps Script (GAS) のスクリプトから、`UrlFetchApp` を使って外部サイトにリクエストを送ることができる。
* このリクエストが、どの IP アドレスから発信されているか確認した。
  *  より詳しくは、利用しているのが所属機関が契約している Google Workspace for Education なので、契約先に固有の IP アドレスから発信されているのかを知りたかった。

## 結果
* GASのスクリプトから発信されるリクエストは `{IPアドレス}.gae.googleusercontent.com` のようなIPアドレスから来ていた。
  * `{IPアドレス}` の部分には、IPアドレスが入るスクリプトを実行した Google Apps Engine の `107.178.192.0/18` のサーバIPアドレスが入る模様。例：`107.178.192.1.gae.googleusercontent.com`

* というわけで、GASのリクエストの発信元の IPアドレスから、所属機関の Google Workspace 上のスクリプトであることを見分けるのは諦め気味。14ビットのサブネットブロックの限定された範囲内に納まっていてくれれば…などとも思うが、日を措いて再試行してみるしかないかなぁ。

### 参考
* Whois に当たったところ、このIPアドレスは ARIN に登録されており、netname は `GOOGLE-CLOUD`、コメントには "The IP addresses under this netblock are in use by Google Cloud customers" の記載がありました。

* 自分で書いたスクリプトを固定IPから発信したい場合は[こちらの記事](https://qiita.com/suzutatsu/items/8a54ba628e52c6be71aa) などを参考されたし。
  * [GCFから外部へのHTTPリクエストを固定IPにする](https://qiita.com/suzutatsu/items/8a54ba628e52c6be71aa)
AndroidのEditTextからフォーカスを外す方法


# 概要

AndroidのEditTextで入力を確定したあともフォーカスがそのまま残ることがあった。
入力確定後はEditTextからフォーカスは外れてほしい。
そのためAndroidでEditTextからフォーカスを外す方法を記載する。
言語はKotlin

# フォーカスを外す

以下のコードを入力確定時のイベントで実行するようにすることでフォーカスが外れるようにすることができる。

``` Kotlin 
val parent = parent as View
parent.isFocusable = true
parent.isFocusableInTouchMode = true
parent.requestFocus()
```