OmniAICreator/Qiita-1.07M huggingface dataset:
Laravel9 sail vscodeでデバッグする

#　はじめに 
LaravelとXdebugのバージョンが上がり、手順が変更になったので、整理しました。
以前の手順は以下を参照ください。

https://qiita.com/bummy/items/d20e292021332ba808bd

# 検証環境
* Laravel Framework 9.1.0
* Windows 10 Pro
* Visual Studio Code
* Docker Desktop for Windows
* PHP v8.1.2
* Xdebug v3.1.2

# Xdebugを設定する
.envファイルに以下の設定を追加します。

```.env
% SAIL_XDEBUG_MODE=develop,debug
```
# Sail起動

```terminal:PowerShell
% ./vendor/bin/sail up -d
```

# Xdebugが導入されていることを確認
```terminal:PowerShell
./vendor/bin/sail php -v
PHP 8.0.5 (cli) (built: May  3 2021 11:30:57) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.5, Copyright (c) Zend Technologies
    with Zend OPcache v8.0.5, Copyright (c), by Zend Technologies
    with Xdebug v3.0.4, Copyright (c) 2002-2021, by Derick Rethans
```
larave.testコンテナのPHPバージョンを確認することで、Xdebugがインストールされているか確認できます。
Xdebugが表示されていれば、問題なくインストールが完了しています。

# VSCodeに構成ファイルを追加する
```
{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for Xdebug",
            "type": "php",
            "request": "launch",
            "port": 9003,
            "pathMappings": {
                "/var/www/html": "${workspaceRoot}"}
        },
        
    ]
}
```

# VSCodeよりブレークポイントを設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1393249/4b09e3ee-c283-cecb-5167-a4e6614d1c34.png)
# VSCodeよりデバッグを開始
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1393249/568bd235-27a6-0382-8399-ead4ccf6dca4.png)
# ブラウザよりアクセス
URLに以下を追加してアクセスする。
?XDEBUG_SESSION_START=session_name
最初のURLに指定すれば、デバッグを停止するまでは、指定は必要ありません。
Flowを使う気がしない理由


今後はワークフロー、プロセスビルダーが改善されずに最終的にはFlowになるらしい。
そのためなのか、最近ではフローの質問も多いです。私は分からないので回答できないですね。

さて、私がフローを使う気がしない理由を並べていこうか。

 1. まずは、フローだけが使う気がしないのでないです。Apexでコードしか書けないので、基本的にはワークフロー、プロセスビルダーも使うことはほとんどありません。実務で困ることがないのが一番の理由です。Apexを知っていれば大概のことはできます。新たに覚える気力がないんですよね。他に覚えなきゃいけないことが多すぎます。(ただし、フローの質問がこれ以上増えてくると考えなければいけないです。回答できないのは辛い。）

2. 次に気になるのはApexのクラスのようにライブラリ化して使う回すことができない点ですかね。何か毎回１から作るので開発効率が悪そうです。（私の能力はもっと低いので余計に困ります）

3. Apexだと当然テストクラスを書きます。そのため変更した後は再度テストすることになるのですが、ちゃんとしたテストクラスを作っておけばテストが楽で品質もちゃんと担保できます。私の知る限りApex以外のツールではテストができない。私のように能力が低い場合はテストも自動化しておかないと開発効率が悪いですね。

4. フローを使ってみてびっくりしたのが関連先のオブジェクトのフィールドをコードで参照できない。例えばAccount.Nameみたいな書き方ができないんですよね。面倒くさい。階層が深いオブジェクト構造を使う場合にやる気が失せます。

5. どこで使われているかがすぐに分からない。メタデータの検索が必要とかなぁ。これはそのうち改善されるかな？
　
[画面フローが割り当てられているページの確認方法について](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000G4j6ISAR)

SFごめんなさい、単に年寄りでやる気が起きないだけですよ。回答できるレベルくらいにはなりたいものです。
fenced関連(PM2.x系)の情報(随時更新予定)

# エスカレーションについて
topologyがある場合には、１つのレベルのフェンシングが失敗すると次のレベルへ。１つのレベルのみの場合は、一旦失敗しリトライのフェンシングが実行される。
topologyが無い場合は、他のフェンシング可能なノードが有れば、そのノードからのフェンシング（エスカレーション)へ。他にフェンシング可能なノードが無い場合には、一旦失敗しリトライのフェンシングが実行される。

stonith-max-attemptsの回数を制御しているのは、フェンシングを依頼するcontrold側。
pcmk_xxxx_retriesをstonith-timetou内で回数管理して制御しているのはfenced側。

topologyが無い場合、disable-timeoutが有効(デフォルトは有効)になっている場合は、ETIMEに落ちてしまう為、エスカレーションしない。
※フェンスエージェントによっては、まだ、disable-timeoutが有効でも、ETIMEに落ちないものもあるかも。。。

# priority-fencing-delayについて
設定値の待ち時間は、フェンシングのタイムアウトの伸長には含まれていない。
base_delay/base_delay_maxは含まれている
topologyがある場合でも、無い場合でも、priority-fencing-delayの待ちが有効になるのは最初のフェンシング動作のみ(LEVEL1)で、以降のエスカレーションのフェンシングには有効にならない。
2ノードのみで有効で、3ノード以上は、no-quorum-policyの制御に従う。

# pcmk_host_checkパラメータ指定について
dynamic-list,static-list,statusが指定可能で、フェンシング時の指定ノードを決定する方法を指定する。
指定されていない場合は、他のパラメータやフェンスエージェントのサポートするアクションによって、以下の判断で自動的に設定される。
* pcmk_host_listパラメータが指定されている場合は、"static-list"として処理される
* pcmk_host_mapパラメータが指定されている場合も、"static-list"として処理される
* 上記が指定されておらず、フェンスエージェントがlistアクションをサポートしている場合は、"dynamic-list"として処理される。
* 上記が指定されておらず、フェンスエージェントがstatusアクションをサポートしている場合は、"status"として処理される。
* 上記全てに当てはまらない場合は、指定無し(PCMK__VALUE_NONE)として処理される。

# pcmk_host_list/pcmk_host_map指定について
pcmk_host_listは固定で、フェンシング対象とマッチングして、マッチングすればフェンシング可能なデバイスとして判断される。
pcmk_host_mapは、KVM/vSphereなどのVM上用のマッチングで、KVM/vSphere上のホスト名とフェンシング対象をマッチングさせる。マッチング時にlistコマンドも実行させて、マッチングさせる為に、pcmk_host_checkにdymanic-listも指定して、KVM/vSphere上の情報も含めてマッチングさせる方が良い。
pcmk_host_listは、pcmk_host_checkに指定なしか、static-listを指定した場合にしか有効にならない。

# DCノード故障からのフェンシングの移譲について
topologyがある場合で、DCをフェンシングする他ノードが存在する場合には、他ノードへフェンシングを移譲する。
この時、DCノードの故障からのフェンシングは移譲されたノードを起点として開始される
toplogyが無い場合は、常にDCノードが起点となって開始される。
DCノード故障ではない場合は、topologyの有無に関わらず、全てDCノードが起点となって開始される。
他ノードが複数存在する場合には、クラスタに参加した（クラスタがメンバーとして認識した）順が早いノードから選択される。
※topologyが無い場合のDCをフェンシングする場合も、今後のリリースでは、他ノードへフェンシングを移譲する動作に変更となる予定です。よって、topologyの有無に関わらず、DCをフェンシングする場合は、全て移譲となります。

# fece-agentsへのパラメータの引き渡し
fencedからfork後に標準入力より引き渡している
resource-agentとは異なる。

# fence_scsi/fence_mpath
unfencing(on)動作が可能なのは、対象ノードのみ。
unfencing動作は、probeよりも先に実行される。
他のSTONITHデバイスは、通常はreboot/offなどの動作は、対象ノード以外で実行できる所が異なる。
unfencing動作であっても、topologyが有る場合には、topologyに従って制御される

# Query処理
フェンシング実行前にクラスタを構成するノードのフェンシング可能なデバイス情報を取得する為に、フェンシングの基点となるノード(通常、DCノード、移譲される場合は、移譲先のノード)かQueryメッセージにより、他ノードへの探索依頼(Query)が送信される。
自ノードも含めて、Queryを受信したノードは、対象ノードがフェンシング可能なデバイスが自ノードに登録されているどうか確認し、フェンシング可能なデバイスを全てQueryの要求元に返す。
起点となるノードは、この情報を元にして、どのノードにフェンシングを依頼するか決定する。
複数からフェンシング可能な同じデバイスなどが選出される場合には、優先的に、より多くのデバイスを登録しているノードにフェンシングを依頼する。
全く同じデバイス数を登録している場合には、Query応答が早いノードから優先的にフェンシングを依頼する。
デバイスの選出は、VERIFY(monitor/list/status)が優先、その次に登録済(配置可能)のデバイスとなる。

# topology
Level(index)で複数の段階的なフェンシングを設定可能。
devicesにカンマ区切りで複数のデバイスを指定すると、１レベルでand実行(必ず実行)する。
```
    <fencing-topology>
      <fencing-level devices="fence-xxxx1" index="1" target="rh85-01" id="fl-rh85-01-1"/>
      <fencing-level devices="fence-xxxx5" index="2" target="rh85-01" id="fl-rh85-01-2"/>
      <fencing-level devices="fence-xxxx2" index="1" target="rh85-02" id="fl-rh85-02-1"/>
      <fencing-level devices="fence-xxxx3,fence-xxxx4" index="1" target="rh85-03" id="fl-rh85-03-1"/>
    </fencing-topology>
```
[自分メモ] Gulp4 構築手順

新規プロジェクトを構築する際のGulp4のインストール手順

## 前提ステータス
```
$ gulp -v

CLI version: 2.3.0
Local version: Unknown
```

```
$ node -v

v16.10.0
```

## 初期設定
とりあえずpackage.jsonを作る

```
npm init -y
```

```js:gulpfile.js
const { src, dest, watch } = require("gulp");
const sass = require('gulp-sass')(require( 'sass'));
const postcss = require("gulp-postcss");
const autoprefixer = require("autoprefixer");

//ベンダープレフィックスを付与する条件
const TARGET_BROWSERS = [
  'last 2 versions',//各ブラウザの2世代前までのバージョンを担保
  'ie >= 11'//IE11を担保
];

const compileSass = () => src("htdocs/scss/style.scss") 
.pipe(sass({ outputStyle: "compressed" }))
// ▼圧縮しないver 
// .pipe(sass({ outputStyle: "expanded" }))
.pipe(
  postcss([
      autoprefixer({
          cascade: false,
          grid: true
      })
  ])
)
.pipe(dest("htdocs/css"));

const watchSassFiles = () => watch("htdocs/scss/*/*.scss", compileSass); exports.default = watchSassFiles;
```
Gulpファイルはこんな感じ

## Gulpをローカルインストール
```
npm install -D gulp

// Local version: 4.0.2になる
```

## モジュールのインストール(今回使うもの一式)
```
npm install gulp sass gulp-sass gulp-postcss gulp-autoprefixer --save-dev
```

## Gulp起動
```
npx gulp

[14:32:29] Starting 'default'...
[14:32:29] Starting 'compileSass'...
[14:32:30] Finished 'compileSass' after 250 ms
[14:33:24] Starting 'compileSass'...
```
scssファイルを保存する度にコンパイルされていればOK
UnityにNew Relic Agent（iOS）を導入してみる。

# はじめに

New RelicのMobile Agentは、正式にはUnityをサポートしてません。ただし、iOSのSDKはあるので、それらを組み込んでみた方法の記録と結果です。

## 確認したバージョン
以下のバージョンで確認してます。バージョンが異なると、設定項目や方法が異なる可能性があります。
- Unity
  - 2020.3.26f1
- Xcode
  - 13.2.1


## 導入方法
### XCFramework agentの導入
1. [ここ](https://docs.newrelic.com/docs/release-notes/mobile-release-notes/xcframework-release-notes/)から、最新版のXCFramework agentをダウンロードする
1. ダウンロードしたファイルを解凍すると、NewRelic.xcframeworkというアーカイブが現れ、これをそのまま、Unityの ``Assets/Plugins/iOS/``のフォルダにコピーする
1. コピーした先の「NewRelic.xcframework」の中の以下のフォルダを残して**それ以外は削除**
（衝突によりビルドエラーになるので）
　　1. ios-arm64_armv7
　　1. ios-arm64_i386_x86_64-simulator
1. 　Unity Editor上で、**ios-arm64_armv7**の中にある、**NewRelic.framework**を選択して、**CPU** を**ARM64**に設定して、**Add to Embedded Bin**にチェックを入れる ![Arch選択](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184924/843afc00-5771-32b3-f327-6684888a3779.png)
1. 　**ios-arm64_i386_x86_64-simulator**の中の**NewRelic.framework**も同様の設定を行う。ただし、CPUは**X86**。

### UnityAppControllerのオーバーライド
すでに、オーバーライドしたクラスを作成済みの場合は、本ステップはスキップ。未作成の場合、以下のようにして作成する。
1. **Assets/Plugins/iOS**のフォルダに**AppController.mm**を作成
1. 以下のコードを貼り付ける
```objc
#import "UnityAppController.h"

@interface AppController : UnityAppController
@end

@implementation AppController
+(void)load
{
    extern const char* AppControllerClassName;
    AppControllerClassName = "AppController";
}

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
	//TODO add any code you want.
	return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
```
補足：**AppControllerClassName**にこの作成したクラス名を設定して、上書きすることで、本クラスが**UnityAppController**の代わりに読み込まれるようになる。また、**didFinishLaunchingWithOptions**のメソッドの中で、親クラスのメソッドを呼び返す。

### XCFramework agentの初期化
1. 前の項目で追加した、**AppController.mm**を開く
1. ファイルの先頭の方に以下のimport文を追加
    ```objc
    #import <NewRelic/NewRelic.h>
    ```
1. didFinishLaunchingWithOptionsのメソッドに以下のようなNewRelicの初期化を追加（superでベースクラスのメソッドを呼び出す前に追加）
    ```objc
    [NewRelic startWithApplicationToken:@"<appToken>"];
    ```
### ビルドスクリプトの追加（スキップ）
NewRelicの導入手順だとビルドスクリプトがあるが、今回は以下の理由により導入はスキップ。
- 手動でXcodeのプロジェクト側にスクリプトをコピーする以外の方法が見当たらない
- スクリプトを導入しなくても、ある程度動作する
もし、よい方法があれば、コメント等で教えて貰えれば助かります!

## 動作確認
簡単な動作確認では、クラッシュやアプリの起動、Unityからのhttpリクエストなどのデータは取得されNewRelicに送られるようです


# 参照
[Unityで、UnityAppControllerを上書きする方法](https://qiita.com/enpel/items/56f4e0f90d6bd27d026b)
[Unity](https://unity.com/ja)
[NewRelic](https://newrelic.com/)
プログラムからpemファイルを使用したssh接続が出来ない

## 事象内容
プログラムからssh接続するような処理でPrivateKeyにpemファイルを設定していたが、以下のようなエラーが出た

```
ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain
```

## 解消法
色々調べたところ、権限変更と秘密鍵登録をすればいけた

```
$ chmod 600 ~/.ssh/hoge.pem
$ ssh-add ~/.ssh/hoge.pem
```
DeepL APIの動くサンプル~無料アカウントでも4つ以上のPDFファイルを翻訳~

# 想定読者
1. 論文サーベイ時などで、英語PDFを概要をさっと把握するために機械翻訳をかけて母語で大量に流し読みしたい人
1. 開発者向けAPIをとりあえず使えればOKの人。※この記事は開発者向けではない

# これは何
DeepL のAPIでPDFファイルを翻訳する最低限の手順が書かれているもの
実行可能なColaboratoryつき
https://colab.research.google.com/drive/1pa66KsBYggvNuZNWXYY2xkgwcT1xJcD0?usp=sharing

# 前提
DeepLの無料アカウント（ブラウザ版）では、月に翻訳可能なファイル数が３つまで。有償アカウントにしても750円のプランでは5つまで、2500円でようやく20まで。5000円で100ファイルまで可能
https://www.deepl.com/ja/pro?cta=header-pro-button/

一方の開発者向けAPIでは、500,000文字まで無料とファイル数とは違う数え方をしている。非常に気合の入ったサーベイ論文でもない限り、３ファイルで500,000文字はいかないので、こっちのほうが翻訳可能な量が多い。さらに有償版でも月630円+1文字あたり0.0025円とブラウザ版よりも小回りがきいて使い勝手が良さそう

ちなみにブラウザ版と開発者APIを併用（ログインするとAPI,ログアウトするとブラウザ版）もできるので、500,000文字+3ファイルは無料で試せる。大変太っ腹でありがたい

# 事前準備
開発者カウントの無料登録を行う。本人名義でのクレジットカード登録が必要なので手元に用意しておく
https://www.deepl.com/ja/pro#developer

登録後、アカウントページでDeepL APIで使用する認証キーを入手する
https://www.deepl.com/ja/pro-account/summary

翻訳の設定でPDFの翻訳をONにする
https://www.deepl.com/ja/pro-account/translationSettings

翻訳したいファイル（pdf）をダウンロードしておく

# 実行
Colaboratoryのサンプルを開き、自分のGdriveにコピーしておく（重要）
https://colab.research.google.com/drive/1pa66KsBYggvNuZNWXYY2xkgwcT1xJcD0#scrollTo=4sOxFnCQwQeT

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108572/362380b1-f348-3fc7-318e-b9d1b9c2fa9a.png)

一番上のセルを実行する（再生ボタンをクリックすればOK）。最初だけちょっと時間がかかる（）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108572/dbea67e8-f903-eff5-c708-1e31cb2fd5c7.png)

するとテキスト入力フォームが出てくるので、DeepL APIで使用する認証キーを入力する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108572/43b58ac8-6c5c-d303-5853-3644a6542346.png)

左のフォルダアイコンをクリックするとColaboratoryにファイルアップロードできる画面が開く。ここにダウンロードしておいたPDFファイルをアップロードする（ドラッグすればOK）。初回アップロード時は警告がでるが気にせずOKを押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108572/6e1712ae-9fd4-227f-35ac-f57013176698.png)

アップロードしたファイルにカーソルをあわせると3点リーダーが出現し、そこをクリックするとパスをコピーという表示が出てくる。そこをクリックするとこのファイルのColaboratory上のファイルパスがコピーされる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108572/7ea0f2e6-b216-adc1-a8ac-046092af37ae.png)

2番目のセルを実行する。するとまたテキスト入力フォームが出てくるので、さきほどコピーしたファイルのパスを入力する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108572/e16e328d-4640-2a8a-be19-8b9a19c64e67.png)

3番目のセルを実行する。でDeepL APIが正常に実行できたかを確認。document_idとdocument_keyが表示されればOK

数分から10分くらい待ってから、4番目のセルを実行。実行後にファイルの箇所の更新っぽいアイコン（下の図の中段の真ん中のアイコン）をクリックすると、元のファイル名 + translate.pdf というファイルができる。このファイルを3点リーダーからダウンロードをクリックすると翻訳済みにPDFがダウンロードできる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108572/6e1712ae-9fd4-227f-35ac-f57013176698.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108572/7ea0f2e6-b216-adc1-a8ac-046092af37ae.png)

もしダウンロードしたPDFがひらけない場合は5番目のセルを実行。まだ翻訳中の場合や、翻訳可能文字数上限にひっかかっていた場合にそのことがわかる

文字数上限に引っかかった&もっとDeepLを使いたい人は有償版の利用を検討するのが良いと思います。
上記のColaboratoryを有償版でも使う場合はURLを変更する必要がある点にご注意を
商談商品を使った積上げ計算


質問　：　[積み上げ集計項目について【消されています】](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000G4inD)

せっかく商談商品のNameには商品名が入っているのに、積上げ計算では使えないようです。
あああ、何で。

調べてみると同じ質問/回答がありますね。

+ Opportunity Productsで**ワークフローとフィールドの更新を作成して、製品名でテキストフィールドを更新します**。これを行う唯一の目的は、カスタムフィールドに商談商品名を入力して、ロールアップサマリー基準で使用できるようにすることです。

[Opportunity Product Information Roll-Up Summary](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000A8HimSAF)

しかし、このご時勢ではワークフローというわけにもいかんでしょう。私なら一切迷わずApexトリガの一択しかありませんが、質問者さんからはフローでというご指定だ。

さっぱり分からん。　

しかし、作ってみたら動きました。めんどくさい。

何で、フローでは　Product2.Nameとか関連先を直接参照できない？Nameも使えん。　嫌がらせか。

![flow 商品名取得.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/54a8ba0f-8a9b-d0c8-7964-8dbe1e72bcc3.png)


こんな感じで更新できました。

![できた.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/13c59dfd-6d53-0536-97f5-1af875a203ef.png)

# 税ありで集計しているのを税抜きにする

+ [標準オブジェクト商談（Opportunity）オブジェクトの金額（Amount）フィールド  こちらが商談商品の合計金額に紐づいているのは  理解しているのですが、    こちらの設定を変えることは可能なのでしょうか？    詳細をいいますと  現在、税込み表記しているのを税抜き表記にしたいだけなのです。    クライアントのご意向もあり  あくまで金額（Amount）フィールドに表記したいとのことです。  ](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000PW82r)

:::note
古い投稿ですが、このAmount項目の動作は変えることができないと回答されています 

Nope,It is not possible to change the behaviour of Amount as it standard functionlity of the Salesforce. 

https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000A7zJ5SAJ

以下の提案によれば、商談商品側で細工するしかないですね。 
例えば、商談商品側で税込みで入力した単価を自動化処理で税抜きに更新するなど... 

(カスタム項目を追加して消費税額を分けてしまうなど...) 

That is totally normal.  Opportunity Amount is this weird datatype, like an editable Currency field that "converts" into a Read-Only Roll-Up Summary Field once you add Opportunity Product Line Items.  

You need to your Flow to update the standard Opportunity Product: TotalPrice
 field (that is what the Opportunity:Amount field is aggregating) 
https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000H2XkLSAV
:::
k3s(v1.22.7+k3s1)構築

# rke2環境構築
今回研究で使用する環境構築をしたのでまとめてみた．
    
# k3s環境構築

### マシンスペック
最低要件が以下にあるのでそれを満たす．

https://rancher.com/docs/k3s/latest/en/installation/installation-requirements/resource-profiling/

ハイパーバイザー上(ESXi)にVMを3つたてた．1つがマスターノード，残りをワーカーノードにした．それぞれのマシンスペックを以下に示す．
1. マスターノード
    - CPU:2コア
    - メモリ:8GB
    - ディスク:16GB

2. ワーカーノード
    - CPU:2コア
    - メモリ:4GB
    - ディスク:16GB
まずはこれを見る
https://rancher.com/docs/k3s/latest/en/quick-start/

マスターノードは以下のコマンドを打つ

```
curl -sfL https://get.k3s.io | sh -
```

ワーカーノード
マスターノードのIPアドレスをmyserverに，マスターノードの`/var/lib/rancher/k3s/server/node-token`をmynodetokenに埋め込み以下を実行する．

```
curl -sfL https://get.k3s.io | K3S_URL=https://myserver:6443 K3S_TOKEN=mynodetoken sh -
```




# 用語解説
ノード = 装置(VM,PM)
ユーザがマスターノードにk8sのコマンドを打つ．それらの命令をマスターノードがワーカノードに命令する．
言い換えるとユーザが1つのVM(マスターノード)に命令を行い，それをもとに他のVM(ワーカノード)に命令を行う．
rke2 : k8sのディストリビューションである
herokuでよく使うコマンド一覧


### ログをターミナルに表示する

```
heroku logs -t
```

### herokuにpush

```
git push heroku master
```

### herokuでマイグレーション

```
heroku run rails db:migrate 
```

### サイトをメンテナンス状態にする

```
heroku maintenance:on --app アプリ名
```

### メンテナンス状態終了

```
heroku maintenance:off --app アプリ名
```

### DB確認

```
heroku pg:info --app アプリ名
```
Geth ローカルでのテストネットワーク構築

# 目次
[1.はじめに](#1-はじめに)
[2.Gethのインストール](#2-インストール)
[3.テストネットワークの起動](#3-テストネットワークの起動)
[4.Gethネットワークに接続する](#4-テストネットワークに接続する)


# 1. はじめに
GethをインストールしたWindowsPCにて、テストネットワークを起動する方法を記載する。
利用しているバージョン
- Geth 1.10.17-stable

# 2. インストール
以下のサイトから、Windowsのインストーラを取得し、インストールする。

https://geth.ethereum.org/downloads/

gethコマンドへのパスを通す。
```
C:\Program Files\Geth
```

# 3. テストネットワークの起動

__① データディレクトリの作成__

```
> mkdir [データディレクトリ]
```

__② Genesisファイルの作成__

書籍の内容をもとに、以下のように作成した。
```json:genesis.json
{
  "config": {
    "chainId": 15,
    "homesteadBlock": 0,
    "eip150Block": 0,
    "eip155Block": 0,
    "eip158Block": 0,
    "byzantiumBlock": 0,
    "constantinopleBlock": 0,
    "petersburgBlock": 0,
    "istanbulBlock": 0,
    "berlinBlock": 0
  },
  "nonce": "0x0000000000000042",
  "timestamp": "0x0",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "extraData": "",
  "gasLimit": "0x8000000",
  "difficulty": "0x4000",
  "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "coinbase": "0x3333333333333333333333333333333333333333",
  "alloc": {}
}
```

__③ Gethネットワークの初期化__
```
geth --datadir [データディレクトリ] init [genesis.jsonファイル]
```

__④ 起動時のアカウントアンロックのためのパスワードファイル作成__
各アカウントのパスワードを列挙したテキストファイルを格納

※起動時のアカウントアンロックはセキュリティ的にNGなので、テスト時のみ設定

__⑤ Gethネットワークの起動__
実際は改行なし。
```winbatch
geth 
  --networkid [ID数字]
  --nodiscover
  --maxpeers 0
  --datadir [データディレクトリ]
  -mine
  --miner.threads 1
  --miner.etherbase=%runuser%
  --http 
  --http.addr "0.0.0.0" 
  --http.port 8545 
  --http.corsdomain "*" 
  --http.api "admin,db,eth,debug,miner,net,shh,txpool,personal,web3"
  --allow-insecure-unloc
  --unlock [0,...] 
  --password [パスワードファイル]
  2> [logファイル]
```

* --mine 起動時にマイニングを有効にする 
* --http～ PRCサーバを有効にしてリモートからコマンド実行できるようにしている
* --unlock 起動時にアンロックしておくアカウントの番号を列挙(--allow-insecure-unlocを付けないとエラーになる)

__⑥ ログファイルをtailで監視する__
前述のコマンドでログファイルが出力されるので、Power Shellコマンドでログを監視する。
```powershell
> get-content -path [logファイル] -Encoding UTF8 -Wait -tail 100
```

# 4. テストネットワークに接続する
以下のコマンドで、RPCサーバにてGethネットワークに接続し、コマンドを実行できるようにする。
```winbatch
> geth attach rpc:http://127.0.0.1:8545
```
Selenium4のEdgedriverでデフォルトのダウンロードフォルダを変更する

# はじめに
以前、`msedge_selenium_tools`を使うやり方の記事を書いたけど、selenium4でもできるらしいのでそちらに乗り換え。

# 準備
## Edgedriverをダウンロード
PCにインストールされてるEdgeに対応するバージョンのEdgedriverをダウンロードしておく
https://developer.microsoft.com/ja-jp/microsoft-edge/tools/webdriver/

## ライブラリのインポート
```
pip install selenium
```
※以下はMicrosoft公式のマニュアル。日本語翻訳は機械翻訳がアレなので英語版で読むのを推奨
https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/?tabs=python


# やり方
`experimenal_options`に辞書型で色々変数が入っているみたいっぽいので、その値を上書きしてやる形で指定するっぽい。
```py
#%%
#ライブラリのインポート
from selenium import webdriver
from selenium.webdriver.edge.service import Service
from selenium.webdriver.edge.options import Options

#パラメータの準備
driverpath='./edgedriver/msedgedriver.exe'
prefs={"download.default_directory": "c:\\users\\username\\downloads"}

#設定
service = Service(executable_path=driverpath)
options = Options()
options.experimental_options["prefs"]=prefs

#driverの立ち上げ
driver = webdriver.Edge(service=service,options=options)
 
#urlに遷移
driver.get('https://www.bing.com/')

#driverの終了
driver.quit()
```


# おわりに
Microsoftの公式マニュアルをサクサク読みこなせるような、行間を読む力が欲しい。
EdgeじゃなくてもChromeでも同じようなことができるとは思う。

# おまけ
たまに、ボタンを押すと画面上にポップアップのように出てきて、その要素上の要素を触りたいのに、なぜか指定できない場合がある。そういう時は、iframeをスイッチする必要があるかもしれないので、`driver.switch_to`でうまいことする。

```py
from selenium import webdriver
from selenium.webdriver.edge.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

#webdriverの立ち上げ
service = Service(executable_path=driverpath)
driver = webdriver.Edge(service=service,options=options)

#トップページに遷移
driver.get(url)

#要素を待ってボタン押下
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "要素ID")))
driver.find_element(By.ID, "要素ID").click()

#iframeを待ってスイッチ
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.NAME,"<iframe>名")))
driver.switch_to.frame(driver.find_element(By.NAME,"<iframe>名"))

#要素の入力
driver.find_element(By.NAME,"<iframe>上の要素名").send_keys("hogehoge")   
```

# 補足
2022/05/16 19:28 driverを立ち上げるときにexecutable_pathを直接指定するとWarningが出るので、Serviceを使う方法に変更
Apple M1 macOS Montereyでpowerline-shellを導入する

# はじめに
Apple M1を搭載したMacBook Airにpowerline-shellを導入したかったが、
[公式のREADME.md](https://github.com/b-ryan/powerline-shell)通りに手順を踏んでもインストールが失敗してしまうことから本記事を投稿するにあたった。

# 目次
<!-- タイトルとアンカー名を編集 -->
- [はじめに](#はじめに)
- [目次](#目次)
- [インストール時のエラー](#インストール時のエラー)
- [対処](#対処)
- [参考文献](#参考文献)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# インストール時のエラー
Apple M1を搭載したMacBook Airにpowerline-shellを導入したかったが、macOS Montereyバージョン12.0.1に標準インストールされたPython3でpowerline-shellをインストールしようとすると、以下のエラーによりインストールできなかった。

```sh
running install
error: can't create or remove files in install directory

The following error occurred while trying to add or remove files in the
installation directory:

    [Errno 13] Permission denied: '/Library/Python/3.8'

The installation directory you specified (via --install-dir, --prefix, or
the distutils default setting) was:

    /Library/Python/3.8/site-packages/

This directory does not currently exist.  Please create it and try again, or
choose a different installation directory (using the -d or --install-dir
option).
```

<a id="#Chapter2"></a>
# 対処
pyenvを使用しPython 3.9.12をインストールし、setup.pyを実行する

<a id="#reference"></a>
# 参考文献
- [powerline-shell](https://github.com/b-ryan/powerline-shell)
- [M1 Mac に powerline-shell を導入する](https://zenn.dev/warugaki/scraps/355f79151e3b46)
jQuery で ダークモード設定時に画像をすり替える

## はじめに

ちょっと凝ったダークモードを設定して、ユーザーにより良いWeb体験を提供します。

## 一般的には

```style.css

// MDNより転載

@media (prefers-color-scheme: dark) {
  .day.dark-scheme   { background:  #333; color: white; }
  .night.dark-scheme { background: black; color:  #ddd; }
}

@media (prefers-color-scheme: light) {
  .day.light-scheme   { background: white; color:  #555; }
  .night.light-scheme { background:  #eee; color: black; }
}
```

とか

```puutin.html
<picture>
<source media="prefers-color-scheme: dark" src="nightpuutin.jpg">
<img src="moonpuutin.jpg">
</picture>
```

とかやるらしいのですが・・・・

ユーザーが今すぐ簡単に切り替えられない、という大問題があります。

一般消費者アンケート調査において

OSのダークモード設定だけに頼っていいですか？

とお伺いしたものの、デザイン見てから判断したいので、Webで動的に変更したい

というご意見が比較的多めでした。


## Webサイトに設定画面を作ってみましょう。

あえて、設定画面の具体的なつくり方は、ここでは申しません。

cookieやLocalstrageに保存できるものを作るとよいでしょう。

### しかし、設定画面を実行する上で、以下のスクリプトが必要となります。

```mql.js
/*
Usage

mql(undefined | "" | "default") - OS Setting
mql("Light") - Light mode
mql("Dark") - Dark mode

*/

function mql(cook) {
	var mql = window.matchMedia('(prefers-color-scheme: dark)').matches,
		_body=$('body');

	if(cook === undefined || cook == "" || cook == "default") {
		if(mql) {
			_body.removeClass('Light');
			_body.addClass('Dark');
		} else {
			_body.removeClass('Dark');
			_body.addClass('Light');
		}
	} else if(cook == "Dark") {
		_body.removeClass('Light');
		_body.addClass('Dark');
	} else {
		_body.removeClass('Dark');
		_body.addClass('Light');
	}


	// imgタグを書き換える
	$('img').each(function() {
		var t=$(this);
		if(t.data('darksrc') !== undefined) {
			// 初回のみ
			if(t.data('tmplightsrc') === undefined) {
				t.data('tmplightsrc', t.attr('src'));
				t.data('tmpdarksrc', t.data('darksrc'));
			}
		}
	});

	// 画像を動的にライト、ダークで書き換える
	// <img src="light.jpg" data-darksrc="dark.jpg">
	$('img').each(function() {
		var t=$(this);
		if(t.data('tmpdarksrc') !== undefined) {
			t.attr('src', t.data(
				_body.hasClass('Dark')
				? 'tmpdarksrc'
				: 'tmplightsrc'
			));
		}
	});
}
```

#### 使い方は
- mql(undefined 等);
- mql("Light");
- mql("Dark");

#### CSSの書き方
```style.scss
body.Dark {
  element {
    //ダークモード時
  }
}

body.Light {
  element {
    // ライトモード時
  }
}
```

#### imgタグの書き方
```sample.html
<img src="ライト.jpg" data-darksrc="ダーク.jpg">
```

## さいごに

この方式を用いることで、OS設定によるダークモードに対応していない
ブラウザ(Windows用Firefoxが現状対応していません）でも
ユーザー操作によってダークモードに設定することができます。

更に、必要に応じてライトモードとダークモードの画像を簡単にすりかえられるようにすることで
ユーザーの体験向上を図ることができます。
CLI編集覚書

# 返り値を常に表示したい
`return: 127`のような感じで想定

## 工程
- プロンプトを設定しているファイルを編集する
- 表示関係を設定している環境変数を見付ける
- 表示コマンドを差し込む

## git-sdk-64の場合
- `C:\git-sdk-64\etc\profile.d\git-prompt.sh`
- `$PS1`
- ```return: "'`echo ${PIPESTATUS[@]}`'```
    - ```'`シングルクオーテーション-バッククォートで囲まれた部分(ここ)は表示時にコマンドとして処理される`'```

## zshの場合
- `~/.oh-my-zsh/thesis/*.zsh-theme`
- `PROMPT`
- `return: %?`

## cmdの場合
触りたくないので知らん
つよつよエンジニアになりたかったらプログラミング言語とフレームワークの本は買うな！

プログラミングの勉強するぞ！と思ったときにとりあえず本を買う人がいると思いますが、やめましょう。
今どきの言語やフレームワークはWeb上で始め方を書いてくれていることが多いので、本を買う前にまずWebで調べてみましょう。

簡単に買うべき本と買うべきでない本を書いておきますので、参考にしてください。
（買うべきでない本に入っている本を書いてる人ゴメンナサイ）

# 買うべき本

Web上にリファレンス等がないもの（書籍ベースで広まっているもの　等）

- 開発手法
  - アジャイルサムライ
  - 等
- 思想的な話
  - リーダブルコード　⇒　おすすめ
  - DDD （ドメイン駆動設計）
  - 等

最近は開発手法とか思想的な話もWebで調べれば誰かがまとめてたりするので、要約だけで良いのであれば買わなくても良いかもしれません。
ただ、その要約があっているかどうかは自己判断になるため注意が必要です。


# 買うべきでない本

公式リファレンスがWeb上にあり、最新がWeb上にあるもの
特にWeb系の言語やフレームワークは頻繁に更新されるため、本を買うべきではないです
少し前に発行された本を写経していたら最新バージョンではDeprecatedになってたとかあるので。。

- プログラミング言語入門
- フレームワーク入門



# おすすめ勉強法

- 作りたいもの１から（環境構築から）作ってみる
  - よくあるのはTODO
    - 画面がシンプルだけど、DBのCRUD（Create/Read/Update/Delete）までの一連の流れを体験できるため
  - 個人的にはナンバープレース（数独）がおすすめ
    - TODOリストより条件により表示を変えたり、解法アルゴリズムを組んだりと少し高度なプログラミングが必要になるため
    - 言語やフレームワークごとの使用感だけでなく処理速度なんかも実感できる
- どうやって実現するのかを検索する
  - <font color="red">英語から逃げない！</font>
    - StackOverFlowやGitHub Issuesなんかは英語が多い
    - 最新情報は大体英語で出てくるので若いうちから英語に慣れておくと数年後に楽になる
  - 困ったら公式リファレンスを見る
    - 最初のうちは見方が分からないかもしれないが、続けていけばだいたいのリファレンスを読めるようになる

言語とかフレームワークを新しく勉強する際は毎回決めたものを作ってみるようにすると、言語ごとの違いとかが明確になって良いので是非これは試してみて欲しいです。


# まとめ

公式リファレンスがWeb上にあるものはそこを見ましょう！
作りたいものを作って分からないところがあればWebで調べて、を繰り返していけば環境構築やプログラミング力だけでなく問題解決力も身につくので、ぜひ実際にプログラミングをしてください。

いろいろ書きましたが、一番はプログラミングを楽しむことだと思うので、プログラムを書くことを好きになってください＾＾
LaravelでgroupBYして、エラーが起きた際の解決方法

<h2>背景</h2>
Laravelでtableをselectする際に重複したカラムを絞り込みたいと思って、groupByを使った。
そしたら以下のようなエラーが

```
SQLSTATE[42000]: Syntax error or access violation: 1055 'laravel-shortcut.Tags.admin_id' isn't in GROUP BY

```

<h2>解決方法_1(推奨)</h2>

__→SELECT部分にGROUP化するカラムをちゃんといれる__

例えば、以下のようにする

```
Tag::select('id', 'name')
    ->groupBy('id')
    ->get();
```


以下のようにワイルドカードを使うとエラーが出る
```
Tag::select('Tags.*')
    ->groupBy('id')
    ->get();
```

<h2>解決方法_2</h2>

__→config/database.phpを修正する__

以下のように書く

```laravel:config/database.php
            'strict' => true,
            //追記
            'modes'  => [
                // 'ONLY_FULL_GROUP_BY',
                'STRICT_TRANS_TABLES',
                'NO_ZERO_IN_DATE',
                'NO_ZERO_DATE',
                'ERROR_FOR_DIVISION_BY_ZERO',
                'NO_ENGINE_SUBSTITUTION',
            ],
　　　　　　//追記
```

このように書くことで、SELECTで書いたものだけをGROUPBYさせようとする、やつを無効にできる
AIトレードシステムのＭＴ４埋め込み（４）

https://qiita.com/EasyCording/items/af9aa9fe5d1371f45433

Jupyterでアプリ開発をするのも、そろそろ限界になってきたので、少しファイルを分割、再編している。
FastAPIのフォルダ体系について、プラクティス的なものがあり、これに見習ってみる。

https://camillovisini.com/article/abstracting-fastapi-services/

同時にQiitaでフローを書くべくMermaidを検討した。
しかしながら、調べていると、もっと良いモノが見つかった。

[platuml](https://plantuml.com/ja/)

# FastAPIのアプリケーション

フォルダの構成はこんな感じ・・・

```plantuml
@startwbs
* app
** config
*** database session
** models
*** sqlarchemy model
** routers
*** api routes
** schemas
*** pydantic models
** services
*** business login
** utils
*** service result
@endwbs
```

# シーケンス図
こんなのも書けるんですね・・・（書き方は、全くの我流です。）
```plantuml
@startuml
MT4 -> API: GET(/getlasttime/)
API -> App: get_last_time
App -> DB: gettime
MT4 <-- DB: time(m1,m5,m15)
MT4 -> API: POST(/gettick/)
API -> App:add_forex
App -> DB: select_forex_by_name
MT4 <-- DB: response
@enduml
```

# 状況
　今週のEURUSDですが、PIX2PIXの予想に反して、さらに下落トレンドが継続中です。おかげさまで、資産が完全に溶けました。このアルゴリズムですが、まだ使いこなしに難があり、まさにＡＩ自動トレーニングの強化学習を取り入れなくてはならない状況です。

# 訓練と推論
　ひとまずJupyterLab-Desktopを使っていましたが、モジュール化が必須になり、VSCODEにてリファクタリングしています。

# alembic
* システム開発においても、やはり自己の成長目的があります。今回も何か新しい技術要素を獲得するというのが、もう一つのテーマであり、データベースのマイグレーションについて取り組みました。
* Djangoならmigrateがフレームワークに含まれていますし、Ruby　Railsなら、Railsが勝手にやってくれます。しかしながら、FASTAPIについては、それに伴うものはありません。
* PYDANTICのスケマと、sqlalchemyのモデルを合わせてmigrationしてくれるような、優れたものは無いのでしょうか・・・

# Api-token
* 業務で使う、MlopsのWEB-API開発には、やはりモデル特定のAPI-TOKENの導入が必須です。場合によってはユーザーとモデルの二重認証が必要かもしれません。まずはFastApiに認証機能を追加する方法を習得しようと思います。この際にauth2のようなことにも、着手します。

# ML-Flow
* モデル毎の精度などを管理するために、機械学習フローを学ぼうと思います。現状ではOSSのML-FLOWが良いのではないかと思います。

この先も、FXトレードを片手間にしつつ、ITエンジニアとしての独立のため、ひそやかに独学を進めていきます。 

* RailsによるWebアプリ開発
* React + FastAPIによるアプリ開発
* React-nativeによる、モバイルアプリ開発
* Goによる、BACKEND開発
文字サイズ変更ボタンというガラパゴス的因習

(2022/4/6) タイトルを変更させていただいた。**ガラパゴスゾウガメは絶滅させてはならない**。進化の神秘を我々に教えてくれる種族であり、地球上から貴重な生物の種がいなくなることは非常に悲しいことである([一人ぼっちのジョージ](https://ja.wikipedia.org/wiki/%E3%83%AD%E3%83%B3%E3%82%B5%E3%83%A0%E3%83%BB%E3%82%B8%E3%83%A7%E3%83%BC%E3%82%B8)、ご冥福を)。このタイトルはガラパゴス化の一種であることを強調するために付けたものであったが、あまりにも不適切であった。現存するすべてのガラパゴスゾウガメの皆様に**お詫び申し上げたい**所存である。

## 謎のボタン

少なくない日本企業・組織のwebページに、文字サイズ変更ボタンが付いているのは皆さんご覧になったことがあるだろう。**あんなのが付いている海外webページを見たことが無い**。早く廃止すべきというのはwebデベロッパーなら誰でも思うことだろう。今回はそんなありふれた問題を愚痴る記事である。

## 不要な理由

### そもそもブラウザでフォントサイズを変更できる

これは最近見過ごされがちなことである。昔のIEみたいに堂々と表示されているわけじゃなくて、設定の奥深くに隠れているからね。でも今でも有効だ。[古いデータだが、いじっている人は数%いる](https://medium.com/@vamptvo/pixels-vs-ems-users-do-change-font-size-5cfb20831773)。ブラウザのフォントサイズを変更しても設定が適用されないのはよくある問題だ。原則論として、ユーザーがフォントサイズを変更したのが反映され、かつ破綻しないようにCSSを組む必要がある。

### ページの表示倍率を変更できる

でも、最近のユーザーは、むしろページ全体の表示倍率を変更することの方が多い。文字が見づらいなと思ったユーザーの大多数が、`ctrl + ;`で画面を拡大するはずだ。世の中には逆に`ctrl + -`で縮小表示するという奇特な方もいらっしゃる。そんな時にページの表示が崩れる（昔ながらの`float`レイアウトならよくある）のは避けたいところだ。

## これまでで見た最悪の文字サイズ変更ボタン

このページを見て、記事を書くことを決意しました。

https://www.jacar.go.jp/modernjapan/p01.html

試しにボタンを押して欲しい。全く動作しないだろう。ボタンの下にカーソルを合わせると指マークになるので、これで文字サイズが大きくなる…と思いきゃ、トップページに移動してしまう。ここまでくると怪奇現象である。

ソースを見ると`<!DOCTYPE html>`が宣言されているなど、頑張ってHTML5で書こうとしているにもかかわらず、不適切なマークアップが散見される。ナビゲーションを`<aside>`で括っていたり、`<main>`や`<article>`ではなく`<section>`を酷使している。`<body>`内に`<style>`が入っているとか…`<script>`で`txt`ファイルを読み込むなんて初めて見たぞ。そして、ボタンは`<img>`というのがとどめだ。

このページは相当古いらしく、`<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">`なんて書かれている。アンカーを付けるために`<a>`要素を用いていたり、時代を感じさせる。スクリプトも随所壊れているなど、問題山積だ。

セマンティクスを改善しようにも、ツッコミどころが多すぎる。このページを提供している「[アジア歴史資料センター](https://www.jacar.go.jp/)」さんの名誉のために行っておくと、メインページの方はちゃんと今どきのHTMLのようなので安心したい。
macOS MontereyでPHPとApache

macOS MontereyではPHPが標準バンドルされなくなってしまいました。
なので、インストール...したところApacheも手入れしなければいけなかったのでメモ書き。

# 1.Homebrewのインストール
まっさらのOSの場合を想定してまずはHomebrewをインストール。
Homebrewのサイトでインストールするためのコマンドをコピーできます。
```
$/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

# 2.PHPをインストール
Homebrewのインストールが完了したら、引き続きPHPをインストールします。
入っていない筈ですが、一応PHPのバージョンチェックのコマンド。
```
$php -v
```
Command not foundが表示されると思います。
（もし自前で既にPHPを入れていた場合は現行のバージョンが表示されます）

インストールできるphpパッケージを確認します
```
$brew search php
```

いくつかPHPのバージョンが表示されるので、使いたいバージョンをインストール。
今回は8.0をインストールすることにします。
```
$brew install php@8.0
```

# 3.PHPのパスを通す
HomebrewでインストールしただけではPHPは使えず、パスを通してあげる必要があります。
今回は現行Macの標準になっているZshにパスを通します。
```
$echo 'export PATH="/usr/local/opt/php@8.0/bin:$PATH"' >> ~/.zshrc
```

これでターミナルを再起動するとパスが通ってPHPのコマンドが使える様になります。
早速インストールバージョンの確認。
```
$php -v
PHP 8.0.17 (cli) (built: Mar 18 2022 09:45:09) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.17, Copyright (c) Zend Technologies
    with Zend OPcache v8.0.17, Copyright (c), by Zend Technologies
```
といった様に表示される筈です。

# 4.Apacheのインストール
引き続きHomebrewでApacheをインストールします。
```
$brew install httpd
```

インストールが完了したら、Mac標準のApacheを停止します。
基本的には勝手に起動していると思いますが、動いているか確認するには
```
$ps -ax | grep httpd
```
で確認。
```
  131 ??         0:07.12 /usr/sbin/httpd -D FOREGROUND
  627 ??         0:00.02 /usr/sbin/httpd -D FOREGROUND
25953 ??         0:00.01 /usr/sbin/httpd -D FOREGROUND
39787 ttys002    0:00.00 grep httpd
```

/usr/sbin/httpd -D FOREGROUNDのような表示があれば動いています。
ちなみにapachectlで停止使用とすると
```
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using MacBookPro.local. Set the 'ServerName' directive globally to suppress this message
httpd (no pid file) not running
```
というエラーが出て停止できません。
今回は
```
$sudo -s launchctl stop /System/Library/LaunchDaemons/org.apache.httpd.plist 
$sudo -s launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist 
```
で停止させます。
ちなみに下はMacを起動したときに自動でApacheを起動させなくするコマンドです。
再度psコマンドで確認するとApacheが停止していると思います。

# 5. インストールしたApacheの起動
インストールと標準Apacheの停止が完了したらHomebrewでインストールしたApacheを起動します。
```
$brew services start httpd
```
psコマンドで起動していることを確認します。

# 6.Apacheの設定
これまでは/etc/apache2/httpd.cnfを編集してApacheの設定をしていましたが、Homebrewでインストールされた設定ファイルを編集します。
ファイルの場所は/usr/local/etc/httpd/httpd.cnfです。

以下の点を追加・修正します（バージョン等によって行は異なる可能性があります）
* 52行付近　Listen 8080の下にListen 80を追加
* 181行付近　行頭の#を削除してrewriteモジュールを有効にする
* 181行付近 LoadModuleの記述が並ぶ最後に以下を追記
　LoadModule php_module /usr/local/opt/php@8.0/lib/httpd/modules/libphp.so
　\<IfModule php_module>
  　AddType application/x-httpd-php .php
　\</IfModule>
* 225行付近　行頭の#を削除して、www.exsample.com:8080をlocalhost:80に書き換える
* 248行付近　必要に応じてDocumentRootを変更（今回は/Library/WebServer/Documentsに設定）
　またその直後にある<Directory "/usr/local/var/www">も同じディレクトリに書き換える
* ファイル末尾に追記
 \<IfModule php_module>
  PHPINIDir /usr/local/etc/php/8.0/
 \</IfModule>
ここまで記述したら保存してApacheを再起動する（ここはapachectlでOK）
```
$sudo -s apachectl restart
```

エラーなく起動し、所定のディレクトリに置いたphpinfo.phpをブラウザで確認できれば設定完了です
```php:phpinfo.php
<?php
    phpinfo();
?>
```
プログラミングスクールでコピーアプリのデプロイまで行ったけど

プログラミングスクールでコピーアプリのデプロイまで進みましたが、そこから進めません。
今回は短く話したいと思います。
# push出来ない
herokuというサービスを使っているのですが、herokuにプッシュ出来ない状況が続いています。
pushすると、いくつかの参照がpush出来ないというエラーが出ます。```cannot push some refs...```

調べても、解決できません。調べると、色々出てきて試しましたが、push出来ません。
# あともう少しなのに
あともう少しでカリキュラムが終わり、カリキュラムの課題に移れるというところでエラーが出てしまう。
メンターの人に聞いても解決できず、困っています。土曜日にメンタリングがあるためその時に聞くことにはしていますが、原因が全く分かりません。

# これがデプロイの難点
デプロイが初めてなので、戸惑っていますが、これがデプロイの難しいところなのでしょうね。

※追記（2022年4月6日）
昨日、カリキュラム通りにコードを修正したら、無事デプロイ出来ました。
コピーアプリもあとは機能の追加・修正をするだけとなりました。
SAPインストール時のホスト名ルール

アルファベットから始まること（数字、ハイフン始まりはだめ)
利用可能な文字は下記。
　アルファベット:  [A-Z],[a-z]
　数字：        　[0-9]
　特殊文字:       -(ハイフン)
※要注意
　_ (アンスコ)、　. (ピリオド)などは使えない。

ABAP Platformの場合さらに以下の制約事項あり。
・最大文字数は13文字。（R/3 4.5までは8文字でした)
・ホスト名にFQDNを設定しない。（当然ですが）
・Windowsの場合、S-[0-9]xxxxx(S-12345など)の名称はだめ。
・Oracle/Windowsの場合は、Note.849423の制限追加。
　→最大文字数が12文字に制限される
・Case Sensitive（大文字と小文字を区別する）Windowsの場合でも。特に名前解決に注意。

備考
・HANADBのホスト名が小文字のため、ルールとして小文字にそろえるほうが望ましいと思っている。


--
611361 - Hostnames of SAP ABAP Platform servers
849423 - Length of hostname for ABAP installation on Windows/Oracle
[SAP Help Potal:SAP HANA Platform > SAP HANA Server Installation and Update Guide >    Parameter Reference > hostname](https://help.sap.com/products/SAP_HANA_PLATFORM/2c1988d620e04368aa4103bf26f17727/a11bb836086748ae98d7d4bc1efdc79f.html?locale=en-US)
【Blue Prism】ウィンドウサイズを取得する

# はじめに
特定のウィンドウが開いているか？
あるいは、
スクリーンショットを取得したいとき、対象の画面が開いているか？
などを確認したいと思ったことはありませんか？

この記事では、Blue Prismでのウィンドウのサイズ（高さ、幅）の取得方法をご紹介します。

# 前提
バージョン
Blue Prism v6.8.0

# オブジェクトスタジオ

読み取りステージを用意します。
![オブジェクトスタジオ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626430/08f2f278-d27f-ffa4-6701-9043861990d7.jpeg)

読み取りステージで、下図のように指定します。
- 要素：Win32モードでスパイしたウィンドウ
- データ：ウィンドウ属性を取得
- 保管先：高さ、幅、それぞれのデータアイテム
- 属性名の値：高さ取得のアクションでは、"Height"
　　　　　　幅取得のアクションでは、"Width"
![読み取りステージ_Height_枠あり.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626430/bc2a1838-e231-1d9d-e7ce-d0626653e924.jpeg)
![読み取りステージ_Width_枠あり.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626430/c1bd10fe-300c-11a2-14c4-709e4477a21f.jpeg)

### 確認用ウィンドウ
ここでは、テキストボックスにウィンドウの高さと幅を出力する簡易的なウィンドウを作成し、どのような値を取得できるか確認を行います。
![フォーム.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626430/af71109a-8525-3c89-ee66-e635e53d764a.jpeg)

### サイズの取得
オブジェクトを実行し、高さ400、幅500のウィンドウのサイズを取得すると、
データアイテムに、高さ401、幅501が取得できたことがわかります。
![オブジェクトスタジオ_取得後.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626430/52fe1164-7390-d212-bd59-76bf082cc079.jpeg)

# まとめ
* ウィンドウのサイズを取得するには、読み取りステージで、高さ、幅のそれぞれのアクションで、**ウィンドウ属性の取得** を指定し、属性名の値に **"Height"**、**"Width"** を指定します。

# 注意点
* Blue Prismで、取得した高さと幅は、実際のサイズより1ピクセル大きい値となります。
vuejs画面表示時にマスタッシュ{{}}が見える

# Vuejs画面表示時にマスタッシュ{{}}が表示されるのを解消する
```html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>test</title>
  <style>
    [v-cloak] { opacity: 0; }
  </style>
</head>

<body>
  <div id="app" v-clock>
    <h1>{{ hoge }}</h1>
  </div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
new Vue({
  el: '#app',
  data: {
    hoge: 'テスト',
  }
})
</script> 
</body>
</html>

```

# 原因
vueがコンポーネントのインスタンスを初期化する前にブラウザがhtmlを表示するから

# v-clock
v-clockはコンポーネントのインスタンス初期化・データバインディングが完了するとDOMから消える。
なのでその間cssで非表示にすることでユーザーから状態を隠すことができる。

clockの意味はマントとか覆い隠すものという意味だそうです
PowerAutomateDesktop で無限ループ処理をする際にメモリを大量消費する問題の対処法

# 問題

「ホットフォルダ上にファイルが入った際に特定の処理を行う。」

というような内容をPowerAutomateDesktop上で行おうとすると、下記のような内容になる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277650/9ca72128-d3fe-07bf-8261-84ad2284cb71.png)

しかし、実際に実行すると10分程度放置するだけでメモリ量が500MBほど跳ね上がり、そのまま放置しているとPCがフリーズ状態になってしまう。
# 解決法

フローをもう一つ作成する。内容は以下の通り。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277650/d64f64c9-f2e2-b8de-64f7-6d5b320342c7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277650/d5963858-f8e5-27e7-212e-cd45eb368b75.png)

毎回フローを停止する処理を追加することで、メモリが増える問題を回避することが出来る。
TrueNASのVM利用時のホストとのストレージ共有の話

TrueNAS(TrueNAS CORE, TrueNAS SCALE)にはVM機能も統合されており大変便利なのだが、実際に使ってみたらちょっと躓いた点があるので記録しておく。当然、NAS自体がストレージサーバとしてNFSやSMBを提供しているのだが、これをVMから見ようと思ったら一手間必要だったというお話。TrueNASのフォーラムに断片的なヒントはあったが、若干の前提知識・エスパー力が必要な気がしたのでここに書いておく。

※COREにはjail、SCALEにはDockerもあるため使い分けも必要。この点については筆者は適切な知識を持っている自信がない。

そもそもjailやDockerを使う場合は起動前に構成を変更してホスト側のデータ領域をマウントしてしまうのが手っ取り早くて良さそうなのだが、VMにデバイスを追加しようとするとDiskやRaw Fileが候補となるため、単純にLAN内にクライアントPCを増やしてNFSやSMBを参照するのとはだいぶ状況が違ってきそうで逆に不便そうなので、この選択肢は排除した。

まず、実際にVMを立ち上げて外部ネットワーク接続できる状況にする……というか、普通にVMを設定して有効なNICをアサインすれば、ホストとのNICをVMも共有しているような状況（同じハブにつながっているような状況？）になり、外部ネットワークへの接続は普通に行えるようになる。しかし**ここでホストの提供しているNFSやSMBを見に行こうとすると何故かつながらない**。これが今回の問題である。

やるべきことはわかってしまえば簡単で、まずホスト側のネットワーク設定を開き、Bridgeインターフェイスを1つ用意する。ホストネットワークと異なるサブネットにする必要がある（同じにしようとするとエラーする）ので適当なIPを割り当てる。Bridgeメンバーとしては、とりあえず何も考えずに余っているNICを割り当てたらうまくいった。他の方法は未調査。もちろん、NFSやSMBをマウントできるNICやIPを限定している場合はそちらも調整しておく必要がある、はず（試してない）。

次にVMのデバイス設定から先ほど追加したBridgeのNICを追加する。その後、VMを起動すれば追加したNICが見えるので、そこにBridgeインターフェイスと同じサブネットのIPを割り当てる。これでNFSやSMBのサーバとしてBridgeインターフェイスのIPを指定すれば無事にホストのストレージが見えるようになる。NICが余計に増えてしまったが、これで普通にクライアントPCを追加するのとあまり変わらない感覚でVMが使えるだろう。

……速度については、何か分かれば追記ということで……。
cscの作法 その96

# 概要
cscの作法、調べてみた。
アイコンエディタやってみた。

# 参考にしたページ

https://lets-csharp.com/making-icon-editor/

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/fb447494-3f07-3da1-3ac2-d81f9a000b7f.png)

# サンプルコード

```


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

public class PictureBoxEx : PictureBox {
	public PictureBoxEx() {
		this.Click += PictureBoxEx_Click;
	}
	private void PictureBoxEx_Click(object sender, EventArgs e) {
		Form1 f = (Form1) FindForm();
		this.BackColor = f.CurColor;
	}
}

public class Form1 : Form {
	Panel panel1;
	PictureBox pictureBox1;
	ColorDialog colorDialog1;
	Button button1;
	Button buttonColor;
	PictureBoxEx[,] pictureBox = new PictureBoxEx[32, 32];
	PictureBoxEx CreatePictureBox(int i, int j) {
		int size = 10;
		PictureBoxEx box = new PictureBoxEx();
		box.Size = new Size(size, size);
		box.Location = new Point(size * i, size * j);
		box.Parent = panel1;
		box.BorderStyle = BorderStyle.FixedSingle;
		return box;
	}
	Color curColor = new Color();
	public Color CurColor {
		get {
			return curColor;
		}
		set {
			curColor = value;
			pictureBox1.BackColor = value;
		}
	}
	public Form1() {
		Text = "icon editor";
		ClientSize = new Size(500, 400);
		colorDialog1 = new ColorDialog();
		panel1 = new Panel();
		panel1.Location = new Point(40, 40);
		panel1.Width = 320;
		panel1.Height = 320;
		this.Controls.Add(panel1);
		pictureBox1 = new PictureBoxEx();
		pictureBox1.Size = new Size(20, 20);
		pictureBox1.Location = new Point(420, 20);
		this.Controls.Add(pictureBox1);
		for (int row = 0; row < 32; row++)
		{
			for (int column = 0; column < 32; column++)
			{
				PictureBoxEx box = CreatePictureBox(column, row);
				pictureBox[column, row] = box;
			}
		}
		CurColor = Color.Black;
		button1 = new Button();
		button1.Location = new Point(400, 150);
		button1.Size = new Size(50, 20);
		button1.Text = "save";
		this.Controls.Add(button1);
		button1.Click += button1_Click;
		buttonColor = new Button();
		buttonColor.Location = new Point(400, 50);
		buttonColor.Size = new Size(50, 20);
		buttonColor.Text = "Color";
		this.Controls.Add(buttonColor);
		buttonColor.Click += buttonColor_Click;
	}
	private void button1_Click(object sender, EventArgs e) {
		Bitmap bmp = new Bitmap(32, 32);
		for (int row = 0; row < 32; row++)
		{
			for (int column = 0; column < 32; column++)
			{
				bmp.SetPixel(column, row, pictureBox[column, row].BackColor);
			}
		}
		SaveFileDialog dlg = new SaveFileDialog();
		dlg.Filter = "アイコン| *.ico";
		if (dlg.ShowDialog() != DialogResult.OK)
			return;
		Icon icon = Icon.FromHandle(bmp.GetHicon());
		Stream outStream = new FileStream(dlg.FileName, FileMode.Create, FileAccess.Write);
		icon.Save(outStream);
		outStream.Dispose();
		bmp.Dispose();
		icon.Dispose();
	}
	private void buttonColor_Click(object sender, EventArgs e) {
		if (colorDialog1.ShowDialog() == DialogResult.OK)
			CurColor = colorDialog1.Color;
	}
	[STAThread]
	public static void Main() {
		Application.Run(new Form1());
	}
}




```

以上。
AWS CLI SSM接続時のエラー【 [SSL: CERTIFICATE_VERIFY_FAILED]】対処法メモ

# 0.問題
　気ままに更新ボルベルトでーす。今日はEC2にSSMを使って接続をしようとしていたらエラーが出たのでメモしていきます。
　やろうとしていたことは以下です。
 * IGを作成したVPCにEC2を立ち上げる。なお、VPCはDNSホスト名とDNS解決を有効とする。
 * EC2にSSM接続を許可したポリシーをアタッチする(AmazonSSMManagedInstanceCoreというポリシー)
 * aws cliから下記コマンドでssm接続を試みる
 ```
 aws ssm start-session --target "インスタンスID"
 ```
 上記手順でSSM接続しようとしたところ下記のエラーが発生
```
SSL validation failed for https://ssm.ap-northeast-1.amazonaws.com/ 
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)
```

# 1.解決策(一時しのぎ)
　結論、```--no-verify```のオプションを追加すると接続ができるようになりました。
　Warninngは出るんですけどね。([参考サイト](https://genzouw.com/entry/2019/05/07/085327/1437/))


# 2.エラーの原因
 [AWSの公式サイト](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-troubleshooting.html#tshoot-certificate-verify-failed)にトラブルシューティングがありました。下記に記載します。
>これは、企業が認定機関 (CA) に設定されており、プロキシの証明書が自己署名されているなどの要因により、AWS CLI がプロキシの証明書を信頼していないことが原因です。これにより、AWS CLI はローカル CA レジストリにある企業の CA ルート証明書を検索できません。
この問題を解決するには、ca_bundle 設定ファイルの設定、--ca-bundle コマンドラインオプション、または AWS_CA_Bundle 環境変数を使用して、AWS CLI に企業ファイル .pem の場所を指示します。

企業ファイル.pem？？確かに社内環境からssm接続を試みていましたが、、、
試しに自宅の私用pcから同じEC2にssm接続を試みると接続ができました。
企業ファイル.pemとは聞いたことがないですが、情シスの人とかに聞けば場所を教えてもらえるのかな?

# 3.今後
引き続きAWSの勉強を継続していきまーす。なんだかつまるところは大体社内環境が原因な気がします。
AWSエンジニアの方って大変ですね、、僕もまだまだ見習いですが少しずつ学んだことをメモしていきます。

勉強中の方やAWSお詳しい方はぜひぜひコメント頂けると嬉しいですー
(一人で勉強し続けるのってモチベーション保つのが大変ですね、、)
Laravel キュー

# 概要
通常のWebリクエスト中に実行するのでは時間がかかり過ぎるタスクがある場合、
バックグラウンドで処理したい仕事を**キュー**へ投入する。

（キュー：逐次入出力が繰り返されるデータを一時的に蓄えておくためのデータ構造）

Laravelはそれ用のジョブクラスが作成できる。

# ジョブ作成
全てのキュー用ジョブは `app/Jobs` ディレクトリ配下に配置する。

```
php artisan make:job HogeProcess
```

で生成されたクラスは `Iluminate\Contracts\Queue\ShouldQueue` インターフェース を実装する。

# クラス構造
`handle` メソッドのみを持つ。
これはジョブがキューにより処理される際に呼び出される。

`handle`メソッドでは依存関係をタイプヒント(型宣言)できる。

```php
namespace App\Jobs;

use Illuminate\Contracts\Queue\ShouldQueue;

class HogeProcess implements ShouldQueue
{
  protected $hoge;

  /**
   * ジョブインスタンス作成
   */
  public function __construct(Hoge $hoge)
  {
    $this->hoge = $hoge;
  }

  /**
   * ジョブの実行
   */
  public function handle(HogeProcesser $hogeProcessor)
  {
    // ジョブ実行処理
  }
}
```

# ジョブの失敗
ジョブを失敗した場合`fail`メソッドを呼び出す。

```php
public function handle()
{
  // 処理

  // ジョブ失敗
  $this->fail();
}
```

# 参考
[Laravel 8.x キュー](https://readouble.com/laravel/8.x/ja/queues.html)
[待ち行列，キュー(queue)](http://www.cc.kyoto-su.ac.jp/~yamada/ap/queue.html)
with に Jetpack Compose を導入して半年が経ちました

## はじめに

with で Android エンジニアをしている [石田](https://qiita.com/maxfie1d) です。with の Android 版アプリ (以下、with-android) では Jetpack Compose 1.0 がリリースされる数か月前より導入の準備を開始し、2022年3月現在で導入して半年が経過しました。

この半年間でのアップデートを簡単にまとめるのがこの記事の目的です。Jetpack Compose をプロダクトに導入済みの方もそうでない方も、何かの参考にしていただければ幸いです。


## Compose への移行度

with-android では 新規機能の UI には原則 100% Compose を使用するルールにしています。また、既存機能についても隙間時間で地道に Compose 化を行ってきました。「リファクタリング: Compose化」というラベルを付けて管理しています。
￼
![Pasted Graphic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56635/1b1faa93-cb0c-067b-06d1-6af7a44de0bb.png)

その成果として、この半年間でレイアウトの XML は **648個** から **595個** に減少し **約8% がCompose に移行** されました。このペースで行くと、完全移行まであと **6年** ほどかかる計算です。先は長いです。

![# of XML.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56635/c15bc24b-1661-4cb5-c1a4-33c34616f60d.png)
￼
ちなみに Composable 関数(Preview 関数は除く) の数は 300個 でした。数が多いですが、これは Compose になって UI を容易に分離でき、再利用性が高まったことの表れだと考えることができます。

![# of Composable.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56635/c3ca2d95-9b6d-5f46-5a8b-9fdd94410785.png)


[こちらの記事](https://qiita.com/maxfie1d/items/af14f33de6d5bae28b35)を参考にすると、Compose への移行度を簡単に調べられるので読者の方のプロジェクトでも試しに計測してみてください☺️


## ガイドラインの作成

Compose のコードの書き方を チームで統一したいので、簡易的なガイドラインを Wiki に作成して認識を合わせています。例えば、引数は 1つ 1つ 改行して末尾にはカンマ([Trailing commas](https://kotlinlang.org/docs/coding-conventions.html#trailing-commas))を必ず付けましょうとか、Preview 関数は可能な限り書きましょう、といったルールを定めています。特徴的なところでいうと、UI の分割の方針は [Atomic Design](https://uxdaystokyo.com/articles/glossary/atomic-design/) を基本としながらも、敢えて厳密には従わず柔軟にやってよいというルールにしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56635/2804d1c2-94cf-fd97-29df-55216c205213.png)



## メンバーの意見

Compose 導入当初は Compose のコードを書けるのは 私 1人でしたが、現在ではチーム全員が自信を持って Compose のコードを書けるようになりました。メンバーに聞いた Compose 導入の感想を載せておきます。

> **メンバー: A**
> 大規模なアプリへの導入も簡単に出来ますし、Preview 機能である程度確認できるので実機確認する頻度が減って便利でした！


> **メンバー: B**
> ✅ Activity/Fragment から UI が切り離された(印象を受ける)のが良かった
> ✅ 全部 Kotlin で書けるの良い。XML でのプロパティ名は何だ？と調べなくて良い
> ✅ View ごとに ID を振らなくて良い
> ✅ リストが(RecyclerViewに比べて)簡単に実現できるのは感動した 
> ✅ Preview がとても楽
> ✅ アニメーションが楽で良い
> ⚠️ (Vim使いなので) UI のコードを書くときに空行を入れる文化がないのが少しつらい(コーディング時、前後の空行へのジャンプをよく使っていた)

> **メンバー: C**
> ✅ Preview を見ながら動作のコードを書けるのがとっても楽に感じます！
> ✅ パラメーターによって複数の Preview が見えるのもすごくいい！
> ✅ State という概念が素晴らしい
> ⚠️ 9-patchを使うのが少し難しい


## Compose で困ったこと

Compose はかなり安定していて、謎のクラッシュ等は今のところ皆無です。しかしながら、 TextField 周りでキーボードがちらついて表示される等の不具合が存在するようです。これらの不具合は 1.2.0 で改善されるようです[^1][^2]。そこで、1.2.0 が出るまでは TextField を使わず、やむを得ず Compose の中でテキスト入力が必要な場合は EditText を AbstractComposeView でラップして使っています。

[^1]: https://kotlinlang.slack.com/archives/CJLTWPH7S/p1643380005750559
[^2]: https://kotlinlang.slack.com/archives/CJLTWPH7S/p1643448940454849


## Compose 導入のこれから

半年間の間で Compose が Android アプリ開発において大活躍してくれることは確認済みです。これからの半年~1年の間ではさらなる Compose 化を進めつつ、最近安定になった compose-navigation 等も含め、よりモダンな Android 開発にシフトしていく予定です。