OmniAICreator/Qiita-1.07M huggingface dataset:
SPAの新規プロダクト開発におけるデザイナーさん、コーダーさんとの連携についての振り返り

## はじめに
今までのMPAの新規プロダクト開発では、デザイナーさんにデザインを作ってもらい、
それをコーダーさん（デザイナーを兼ねている場合あり）にHTML、CSSに落としてもらい、
エンジニアがWebアプリにHTML、CSSを当て込む　という流れでプロダクトの開発を行っていました。

SPAの新規プロダクト開発でも同じような流れ、役割分担でプロダクト開発をおこなっていったのですが、
WebアプリにHTML、CSSを当て込む段階で上手くいかず、負債になってしまったので、反省も込めてアウトプットしたいと思います。
（デザイン、HTML&CSSに落としてもらうところまでは上手くいっていました。）


## フォルダ構成や設計
CSSのフォルダ構成や設計は
```scss
- base(共通で利用するパーツのcss)
    -_button.scss
    -_modal.scss
- page(ページ単位)
    - auth
        - parts(ページ固有のデザイン)
            - _body.scss
    - style.scss（そのページで利用するパーツのcssを読み込むファイル。エントリポイント的なファイル）
```
のようになっていて、

Vue側では
```scss
- components
- pages
```
のような構成になっていました。

## 当て込み方
まず共通の部分を読み込むために
main.tsでbaseフォルダ以下のscssファイルをimportする形にして、
pages配下のコンポーネントではpartsフォルダ以下のscssをimportするようにしました。

componentsフォルダ配下のコンポーネントに関しては
コンポーネントに切り出したものの、切り出したHTMLがページ単位のCSSに依存していました。

Vueでは（おそらくReactでも）コンポーネント単位で閉じているので、親コンポーネントでimportしたCSSが子コンポーネントに適用されることは基本ありません。
（Scoped CSS は、子コンポーネントの一番上の要素には効いてしまうという話はあるにはあるのですが、、、）

ですので、components配下のコンポーネントでもpages配下のコンポーネントで読み込まれているCSSを再度importしなければいけませんでした。

結果的に当て込むことはできたのですが、かなり無理矢理な形になってしまいました。
負債になってしまった感覚がありました。

## 原因
モダンなフロントエンドフレームワークを使った開発でのコンポーネント指向の理解が浅かったです。

もっというと従来のWebアプリはHTMLファイル、JavaScriptファイル、CSSファイルとして分けるというような考え方（ファイルの種類別で分けるような）で、CSSにも設計があって、、、
というような考え方とコンポーネント指向の相性が良くなく、今回のようなことが起こってしまったのだと思っています。

HTNL&CSSの段階の設計（非コンポーネント指向）と、Vueの設計（コンポーネント指向）のギャップが当て込み時のオーバーヘッド、負債を作り出してしまったのではないかと思っています。

## どうやったら良かったのか
前提、デザインとHTML&CSSの部分は上手くいっていたのですが、アプリ側（自分側）の当て込みが上手くいかなかったので、そこに対する対応策を上げていきます。
先程あげたギャップをなくすための方法を考えてみました。

### デザインだけをやってもらい、コーディングからエンジニアが巻き取る
エンジニア側の負担が大きくなってしまうのと、エンジニア側のCSSの理解度に依存してしまうのがデメリットかなと思います。
（何もWebエンジニア全員がCSSが得意なわけではないので。。。）
（WebエンジニアがCSSを書くことにより、より負債になってしまう可能性もあるので。。。）

エンジニアのリソースとの兼ね合いもあるのかなと思っています。

### HTML&CSSをコンポーネントごとに閉じて設計をしてもらう
Webアプリの都合をコーダーさんに強いることになってしまうので、少し難しく感じる部分はあります。
ただしエンジニア側でコーディングまで巻き取れない、コーダーさんにコーディングしてもらわない物理的に無理！　という場合は、コンポーネント指向をコーダーさんに説明をし、それにそった設計をしてもらうようにしたほうが良いと思います。

### Utility FirstなCSSフレームワークを使う
WebアプリにHTML、CSSを当て込む時のコストを一番減らせるかつ、CSSの設計がアプリに影響しないのでメリットは多いと思います。
それとローンチ後にWebエンジニアがHTML、CSSを書かないといけない場合、CSSの設計などに縛られずに進めていけることもメリットだと思います。

デメリットとしてはコーダーの方でUtility FirstなCSSフレームワークを使いこなせる人が少なさそう、
コーディングするリソースがありかつUtility FirstなCSSフレームワークを使いこなせるWebエンジニアが少なさそう（もしコーディングまでWebエンジニア側で巻き取るとしたら）
というところだと思います。
（他にもTailwind CSSなどフレームワーク単位でのデメリットはあると思うのですが、、、）

ここ最近Tailwind CSSやChakra UI流行ってるな〜と感じてはいたのですが、その理由がわかった気がします。
モダンなフロントエンドフレームワークはコンポーネント指向が前提になっており、そうなった場合にUtility FirstなCSSフレームワークは相性が良いのだろうなと思っています。


## 最後に
新規プロダクトを開発するときにはデザイナーさんやコーダーさんと役割分担をすると思うのですが、
そのときにコンポーネント指向を考慮できていないとデザインをWebアプリに当て込む段階で苦労してしまう、負債になってしまうということを書いてきました。

そしてWebアプリに当て込む段階で苦労しないためにも、負債を残さないためにも、どうやったら良かったのかを振り返り３つの方法を考えてみました。
もっと良い方法もあるかと思いますが、もし何か参考になれば幸いです。
（もっとこうしたら良かったんじゃない？ということがあったらコメントで教えていただけると嬉しいです！）

ここまで記事を読んでいただきありがとうございました。
（NUROルーター）LAN内サーバーにアクセスしようとすると管理画面に飛ぶ

# 家でサーバー建てたけどLAN内から見れない
## 問題
 NUROルーター内でサーバーを建ててドメインを付けたけど、アクセスすると管理画面に行ったり"この接続ではプライバシーが保護されません(NET::ERR_CERT_AUTHORITY_INVALID)"って出る。
## 原因
 ドメイン(example.com)を名前解決すると、外部IPになる(12.34.45.67)。ルーターとしては自分宛て（192.168.0.1または外部IP)になってるし、内部からのアクセスだから管理画面を出そうということになり、表示。TLS/SSLとしてアクセスしてるとルーターは自分の証明書を返すので、ZTEの証明書≠ドメインの証明書となりエラー。
## 直し方
色々直し方があると思います。クライアント側のhostsに"ドメイン→サーバーローカルIP"だとか、自鯖にDNSサーバーをインストールとか。この解決法は
 - DNSサーバーを建てるのがめんどくさい人
 - hostsに書き込むのがめんどくさい人、
 - スマホとかでhostsいじれない人
向け。

![ダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1281879/a93eaea1-b6d4-5b12-6987-28c44b4ba9c3.png)


 1. 管理画面にアクセス
 1. アプリケーション/DNSサービス/ホスト名設定で開く
 1. ホスト名: サーバードメイン 
 1. IPアドレス: サーバーのローカルIP

でアクセスできます。他のルーターでもホスト名設定あったらできるんでしょうか。自宅にこれ以外ルーターがないので検証できないです。
【2023年02月版】EC2でUbuntu22.04でデスクトップでVScodeでJava開発メモ

# はじめに

- 一時的にVSCodeのJava開発環境ほしいな。。。そうだEC2しよう
- 目標
  - Ubuntu Desktop が動く
  - Chrome が動く
  - Git が動く（Ubuntuのデフォルトで動くので構築の必要なし）
  - VSCode が動く
    - VSCode 上でJava（Spring Boot + OpenJDK17) が動く
    - VSCode 上でGitが動く（VSCode上のターミナルでデフォルトで動くので構築の必要なし）
  - Mozc（日本語入力）が動く
  
# 構築方法

## EC2インスタンス作成〜SSHでの作業

- EC2でUbuntu22.04のサーバインスタンスをたてる、インスタンスタイプはメモリ8G以上を推奨(t3a.largeとか)
- セキュリティグループは、SSH(22)を利用する場所からのIPのみで通しておく
- SSHでの接続時に、`-L 3389:127.0.0.1:13389` のオプションをつける
  - configファイルで指定する場合は、`LocalForward 3389 127.0.0.1:13389`
- SSHでアクセスして、以下の作業を行う

```terminal
# デスクトップのインストール
$ sudo apt update
$ sudo apt upgrade -y
$ sudo apt install ubuntu-desktop
$ sudo apt install xrdp

# デスクトプのユーザを作成、ここではdev
$ sudo adduser dev
$ sudo usermod -aG sudo dev

# sudo 時のパスワードをなくす
$ sudo visudo
# %sudo の行を以下に変更する
%sudo   ALL=NOPASSWD:ALL
```

## リモートデスクトップのTerminalでの作業

- まずはSSHで接続する、3389ポートへのトンネルをあけるため
  - SSHのオプション `-L 3389:127.0.0.1:13389`
- リモートデスクトップで `127.0.0.1:13389` へ dev ユーザで接続する


### Chrome のインストール

- デスクトップの Terminal で以下の作業を行う

```terminal
$ wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
$ sudo apt install ./google-chrome-stable_current_amd64.deb
```

- Chrome の起動は、アクティビティ（画面左上部）からダッシュボード（画面下部）の `Chrome` アイコンをクリックする

### VSCodeのインストール

- デスクトップの Terminal で以下の作業を行う

  - Chrome を起動して、VSCodeのサイトへアクセス、Linuxのdebファイルをダウンロードする
  - Terminal を起動して以下の作業を行う
  
```terminal
# VSCodeのインストール（バージョンはダウンロードする日によって違う）
$ sudo apt install ./code_1.75.1-1675893397_amd64.deb
```

- VSCode の起動は、アクティビティ（画面左上部）からダッシュボード（画面下部）の `VSCode` を起動する
- Terminal から `code` を入力することでも起動できる

### OpenJDKのインストール

- デスクトップの Terminal で以下の作業を行う

```terminal
# OpenDKのインストール（apt search openjdkでインストールしたいバージョンをみつける）
$ sudo apt install openjdk-17-jdk
```

### mozcのインストール

- デスクトップの Terminal で以下の作業を行う

```terminal
$ sudo apt install ibus-mozc 
$ ibus restart 
$ gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'jp'), ('ibus', 'mozc-jp')]"
$ sudo apt install mozc-utils-gui
```

- mozc の起動は、システムメニュー（画面右上部）の `A` アイコンから起動する
- mozc utils の起動は、アクティビティ（画面左上部）からダッシュボード（画面下部）の `Mozc の設定` を起動する

### ポートの変更

- SSH(22) 
  - `/etc/ssh/sshd_config` から変更、その後 `sudo servicectl restart sshd`
  
- RDP(3389)
  - `/etc/xrdp/xrdp.ini` から変更、その後 `sudo systemctl restart xrdp`

### デスクトップの設定

ドックが表示されない場合、アクティビティから広げないといけないので、デフォルト表示するGNOME4に変更

`~/.xsessionrc` を修正する、なければ新規作成する

```~/..xsessionrc
export GNOME_SHELL_SESSION_MODE=ubuntu
export XDG_CURRENT_DESKTOP=ubuntu:GNOME
```
# さいごに

かんたんでしたね
[iOS] Widget経由でアプリが起動された回数ってどのように計測するん？

# 本記事について

「ロック/ホーム画面Widgetを経由でアプリが起動された回数」
をGoogle Analytics（GA）で計測する方法について紹介します。

### 環境

- SwiftUI
- Xcode: 14.2
- Deployment Taget: 14.5
- シミュレータ: 16.2

# 手順

この記事に全てが記載されています。
https://stackoverflow.com/questions/63697132/detect-app-launch-from-widgetkit-widget-extension

### step1
WidgetのViewに`.widgetURL("deeplinkのURL")`のモディファイアを追加

### step2 
（SceneDelegateのタイミングでプロジェクトを作成した人は）下記のsceneデリゲートメソッドを追加

```swift
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
   // URLContexts.first?.urlでdeeplinkのURLを取得できる
   // urlのプロパティでhostやqueryなど指定することができる
}
```

### step3
未起動、タスクがキルされた場合の考慮

step2のみだと、アプリのタスクがキルされた時には対応できない。
下記のようにSceneの起動時にもdeeplink経由したurlを取得することで、未起動、タスクがキルされた場合を考慮する。

```swift

func scene(
    _ scene: UIScene, willConnectTo session: UISceneSession,
    options connectionOptions: UIScene.ConnectionOptions
) {
 // connectionOptions.urlContexts.first?.urlで取得が可能
}
```

#### 注意点

step3の未起動、タスクがキルされた状態では、アプリは非アクティブ状態になります。その状態でGAイベントを送信すると、イベントを許可されないというSDK側の制限があります。

実際に下記のログが発行されます。

```xcodeのconsole.log
Cannot log screen view event when the app is not active
```

sdkを提供している公式githubのissueに解決策が記載されている。（応急処理レベルかも）
https://github.com/firebase/firebase-ios-sdk/issues/7577

下記で遅延を発生させて、処理を実行することで、正常にGAイベントが送信されます。

```swift
DispatchQueue.main.asyncAfter(deadline: .now() + 遅延時間) {
  // GAイベント送信処理
}
```

より適切な方法があれば、コメントいただけると幸いです。

以上です。

# 参考記事
- https://developer.apple.com/documentation/uikit/uiscenedelegate/3238059-scene
- https://developer.apple.com/documentation/uikit/uiscenedelegate/3197914-scene
- https://developer.apple.com/documentation/swiftui/view/widgeturl(_:)
- https://github.com/firebase/firebase-ios-sdk/issues/7577
- https://note.com/koogawa/n/n29ee3fcebfe0#TZD6e
- https://stackoverflow.com/questions/63697132/detect-app-launch-from-widgetkit-widget-extension
Power Apps のフォームコントロールの入力を複数ページに分割する


# はじめに

今回は、前回の以下の記事に続き、Power Apps のフォームコントロールの入力を複数ページに分割する方法について紹介します。

https://qiita.com/Takashi_Masumori/items/0f6c7e60787561d9a22c

上記記事ではフォームの入力をタブで分割しましたが、今回は、以下のように、入力項目が多いフォームを複数ページに分割して入力できるようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/78ca16a3-0ec2-86fc-81e9-4182ed929023.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/3b32f689-3fb5-d0e8-a314-15c45dfe6ab2.png)

# アプローチ

こちらは、実は非常に簡単です。
とりあえず、一つめのページを作成し (ページにラベルやフォームコントロールやボタンを追加し)、そちらを複製していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/78ca16a3-0ec2-86fc-81e9-4182ed929023.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/8b673a20-b48d-a528-1b49-66b3a7228cca.png)

フォームコントロールの [フィールドの編集] を選択し、各ページで入力させたい項目に変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/5ddd1e76-ba9b-b386-4360-7a5cc1957586.png)

そして、最後のページのボタンを [次へ] ではなく、[送信] みたいな感じにして、`[OnSelect]` プロパティを以下のように設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/638f15c0-de85-bfe8-2a12-42fbd1a14804.png)

実は、これで、複数のフォームコントロールのデータを一括で登録できるんです。

```
Patch(
    出張申請テスト,
    Defaults(出張申請テスト),
    Form3_1.Updates,
    Form3_5.Updates,
    Form3_6.Updates
)

```

データ登録を試してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/a08a2e9a-cbb4-0611-056d-dea9cf0edfac.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/b09125af-9424-db58-56b8-0ef424ccf24f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/d38352ae-cec6-1b4e-ccaa-5cf7c6309366.png)


無事にデータ登録出来ました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/e68a5a9b-b956-f56e-a541-0e86ed80b7eb.png)

※データ送信後のメッセージ表示やデータのクリアの処理などは割愛いたします
 Patch 関数を利用した際のメッセージの表示については以下の記事を参考になさってください

https://qiita.com/Takashi_Masumori/items/4e6662ae4d66eeab1252

# まとめ

今回は、Power Apps のフォームコントロールの入力をページを分けて分割する方法を紹介しました。
少し手間ですが、入力項目が多い場合、このようにした方が利用者にとっては優しいと思いますし、必要に応じて、このようなテクニックを利用することもご検討ください。
Fedoraにnode.jsをインストールする方法

①以下コマンドを実行
```
sudo dnf install nodejs
```

②「y」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3058458/4ed3c53d-154f-bc73-6e1c-01ed41c59862.png)

③「Complete」と表示（成功）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3058458/fe73bdf5-630c-0e0b-43d7-34d3aa1817cf.png)

④インストールされていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3058458/979666d7-50e1-2c06-8010-9f6bfb76a432.png)


[参考]
https://developer.fedoraproject.org/tech/languages/nodejs/nodejs.html
flaskでCSP(Content Security Policy)をflask-talismanで実装する方法

flaskで、簡単にcspの設定をできたので、以下に備忘録として書き記す。

## flask-talisman
flaskのドキュメントでflask-talismanを紹介していたので、flask-talismanでCSPの設定を行っていく。
## CSPの設定方法
flaskとflask-talismanのインストール
```cmd
pip install flask
pip install flask-talisman
```
以下、pythonファイル
```python
from flask import Flask
from flask_talisman import Talisman, ALLOW_FROM


app = Flask(__name__)

csp = {
    'default-src': [
        '\'self\'',
        #以下に読み込む必要のあるドメインを書いていく
        '*.qiita.com'
    ]
}
talisman = Talisman(app, content_security_policy=csp)


@app.route('/')
#CSPの設定を適用するところに以下のデコレータを設置
@talisman(frame_options=ALLOW_FROM, frame_options_allow_from='*')
def index():
    return '<h1>Hello World!</h1>'

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=10000)
```
## 実行結果
以下、PythonAnyWhereでHostingしたものをスクショした画像
![画像1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3052981/3f5dbc0b-cb7f-c956-9f9b-072048f53540.png)
この記事のコードで作成したflaskのサイト
https://hellouniverse4.pythonanywhere.com/
## あとがき
flaskでCSPの設定を行う方法を紹介した。筆者自身、思っていたよりも簡単に実装できて驚いている。今後もflaskライフを楽しんでいこうと思う。
## 参考記事
https://github.com/GoogleCloudPlatform/flask-talisman
https://msiz07-flask-docs-ja.readthedocs.io/ja/latest/security.html
IEからEdgeに強制切り替えされるのを解除する方法

2023/2/14以降に、IEを開こうとすると強制的にEdgeが開くようになりました。
Visual Studioで細かいjavascriptを扱っているとどうしてもChromeやedgeではなくIEの方がデバッグをし易かったりします。
（手持ちの環境では、Javascript内でプログラムスクリプトを追加/削除するとVisual Studioではデバッグで行ズレを起こすので）


# 原因
このアドオンが原因です。

![img01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284238/27e0adf1-c372-3f3b-8b85-c28f8e3428e2.png)

# 解消方法
このアドオンは画面上から、無効にすることができません。
そのため、AutoRuns(インストール不要)を利用から削除します。

-1. Microsoftサイトからダウンロード
AutoRunsはMicrosoft製品なので安心してご利用できます。
https://learn.microsoft.com/ja-jp/sysinternals/downloads/autoruns

-2. zipファイルを解凍
-3. Autoruns64.exeを管理者モードで実行
![img02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284238/fd20c676-d0e4-7af1-4729-0bf221176ecd.png)

-4. IETOEdge BHOのチェックボックスを外す
![img03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284238/a8bdcd7f-2407-59d0-fdf5-552f9b4e8bc5.png)

-5. PCを再起動
-6. 完了
UbuntuのWiresharkで"pcap: network type XXX unknown or unsupported"が表示された時の対処方法

Ubuntu 20.04にWiresharkを`apt install wireshark`でインストールすると、古いバージョン3.2.3が入ります。例えば、`tcpdump`で取得した5GCのパケットを、このバージョンで確認しようとすると、`pcap: network type XXX unknown or unsupported`と表示されることがあります。
確認するだけなら、代わりにWindows10に最新のWiresharkを入れれば簡単ですが、他の使い方として例えば、Ubuntuで[5G Trace Visualizer](https://github.com/telekom/5g-trace-visualizer)から呼び出してプロトコルシーケンスをSVGに変換する場合は困ります。
この場合、最新のソースからビルドする他に、PPAからインストールする手があります。なお、PPAはUbuntu公式で承認されたパッケージの配布ではないので、そのことを理解した上で、使用は自己責任になります。

## 現状のWiresharkをアンインストール

現状の古いWiresharkを`apt remove`や`purge`でアンインストールします。

## PPAのWiresharkをインストール

```
add-apt-repository ppa:wireshark-dev/stable
apt update
apt install wireshark
```

2023.02.19時点で、Ubuntu 20.04にはバージョン3.6.7がインストールされました。

## おまけ情報

### 5G Trace VisualizerはIPv6のloopbackアドレスを処理できない

`::1`を含むpcapは処理できないようです。

### UERANSIMのRRC/RLSの確認にはrls.luaが便利

[UERANSIM](https://github.com/aligungr/UERANSIM)のRRC(Radio Resource Control)とRLS(Radio Link Simulation Protocol)を確認する場合、[Wireshark Dissector for Radio Link Simulation Protocol from UERANSIM](https://github.com/louisroyer/RLS-wireshark-dissector)がお薦めです。[UERANSIM/tools](https://github.com/aligungr/UERANSIM/tree/master/tools)にもあります。

## 主な変更履歴

- [2023.02.19] 初版。
Stormworks ビークルLua入門 第０章　環境構築

Stormworksでモニタへの描画やレーダーなどの計算で欠かすことのできないLua Scriptですが、プログラミングを初めてする人へのチュートリアルが今までほぼ無かったので書いてみました。
そのため「StormworksでLua使ってみたいけどプログラミング良くわかんないよ～」という人向けの記事になってます。
この章ではプログラミングを始める前段階、環境構築について取り扱います。これをしておくと後々便利なので、環境に慣れる意味も込めて今のうちからやっておきましょう。

:::note alert
いきなりモニタでボタンを作ったり、レーダーで追跡しようとしたりするのは手ぶらで富士山に登ろうとするぐらい危険と困難に満ちています。まずは足元を固めるためにLua Scriptの基礎から勉強しましょう。
:::

# 1. はじめに
まずは環境を整えましょう。ゲーム内のエディタを使ってLuaを記述しようとするのは足でコントローラーを使うような縛りプレイです。

:::note warn
ここではWindowsマシンでVisual Studio Code(以下、VSCode)を使った説明となります。
それ以外の環境については私の方では用意していないので対象外となります。
:::

# 2. 開発環境のインストール
下記のリンクからVSCodeをインストールしてください。

 https://code.visualstudio.com/

VSCodeのインストールが完了したら起動して、Stormworks向けの拡張機能(Stormworks Lua with LifeBoatAPI)をインストールしましょう。
>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157493/42e04499-1a7b-026e-78dc-de05f7383278.png)
>1. 拡張機能のウィンドウを開きます。
>2. 検索欄に「Stormworks」と入力します。
>3. 拡張機能をクリックします。
>4. 右のメインウィンドウに出てきた「インストール」ボタンをクリックします。

以上で環境のセットアップについては完了です。VSCodeの言語を日本語にしたい方はこちらのリンクが参考になるかと思います。ここでは日本語表記の画像を使用します。

https://www.javadrive.jp/vscode/install/index4.html

# 3. VSCodeおよび拡張機能の使い方
Stormworks Lua with LifeBoatAPI(以下、拡張機能)にはマイコン内のLuaスクリプトに対する支援機能が多く盛り込まれています。
・input/output等の関数の事前定義によるシンタックスエラー表示の防止
・独自のライブラリによるコーディング支援
・コードの圧縮による文字数削減
・onDraw関数を使ったモニタ表示のエミュレータ
などの機能があります。詳細については、拡張機能のページ確認してください。

まずはプロジェクトの作成を行いましょう。
何もファイルを開いていない状態でF1を押すとこのようなポップアップが出るかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157493/7fe9f280-679b-168e-46e9-d7105de63e7a.png)
この検索欄に「Stormworks」と入力すると拡張機能のコマンドが出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157493/754f88db-7da9-715d-e070-079ce332c7ff.png)
これらのうちの「New Microcontroller Project」を押すと、プロジェクトを立ち上げるフォルダ選択を要求するポップアップが出てきます。自分の好きなフォルダを選択しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157493/442c8828-1552-9f6a-3d6e-8a3ed99a89be.png)


:::note warn
プロジェクトは選択したフォルダ内に直接作られます。既にファイルがあるフォルダ内にプロジェクトを作るのではなく、新しいフォルダを作成してそのフォルダを選択しましょう。
:::
:::note alert
選択したディレクトリのファイルパスに日本語などの2byte文字が含まれていると正しく動作しません。アルファベット等の1byte文字のみで構成したフォルダを使用しましょう。
✕　D:\ストワLua\プロジェクト１
◯　D:\Stormworks_Lua\Project_1
:::

「フォルダを選択」ボタンをクリックするとウィンドウの下側に色々出るかと思います。このタブが閉じるか、このような表示になったらプロジェクトは作成完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157493/67e39550-ef8b-91e6-9aa0-f0a96dc0be23.png)

ただし、このままではプロジェクトを閉じて再度開く際に手間がかかるので、プロジェクトを「ワークスペース」として保存しましょう。ウィンドウ左上に表示されている「ファイル」タブから「名前を付けてワークスペースを保存」をクリックしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157493/1cc37545-c43c-7b07-f30f-8ad81121d6df.png)
するとこのような画面が出てきますので、そのまま「保存」ボタンを押しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157493/4fad1f20-aecd-e53b-4548-81f75e08de06.png)

これで次にプロジェクトを開く際に今さっき保存した~~.code-workspaceファイルを開くだけでプロジェクトを開けるようになります。

# 4. おわりに
以上で (環境構築)～(プロジェクト作成) の手順は終了です。お疲れ様でした！

かっこいいエディタでなんか打ち込んでるだけでプログラマになった気分になれますよね。**ね！**
次回(第１章)では実際にLua Scriptを使ったプログラミングを行っていきます。
「Qiita ストック カテゴリ 削除」で検索

長らくやり方が分からず放置していたQiitaのストック記事の削除方法を伝授します。

1. まずは右上のアイコンから`ストックした記事`をクリック
![スクリーンショット 2023-02-19 10.10.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191313/2952131e-35a8-9227-4d58-bd048d62cdc3.png)

2. 左の`カテゴリー`欄から削除したいカテゴリーをクリックし遷移先の右上に表示される`カテゴリーを削除する`を選択
![スクリーンショット 2023-02-19 10.09.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191313/e08989c1-6321-c4c0-48b1-12da8c6f892e.png)

簡単ですが以上です！
手作り Ajax による遷移なし自律更新型ブラウザソース

# 要求

- OBS のブラウザソースとして使える
- リアルタイムにサーバー上の情報を取得し、反映する
- その更新の際に、遷移（一回画面が白くなる）を伴わない

# 実装

　というようなものが必要そうだという感じになったので、以下の仕組みにより実現しました。

- JavaScript で、ある更新処理を毎秒走らせ続ける
- 更新処理の中では以下の操作を行う
  - 必要な要素をすべて `document.getElementById` で取得する
  - それらの `INNERHTML` もしくは `src` を書き換える

　このような、JavaScript を用いた非同期通信による遷移なし更新は **Ajax（Asynchronous JavaScript + XML）** と呼ばれます。世の解説記事にはライブラリを用いたものが多いですが、本記事では必要最小限の JavaScript により実装してみました。

# 例

　実際に作った例はデモにするには複雑過ぎ、かつ更新が高頻度過ぎるので、簡単な例として天気予報を自動更新するブラウザソースを考えます。API の取得には `fetch` を用います。

```html:test.html
<p>現在時刻（これは内部のデータを参照しています）</p>
<p id="date">date text</p>
<p>今日の気象庁の予報です</p>
<p id="forecast">forecast text</p>
<script>
    var url = "https://www.jma.go.jp/bosai/forecast/data/overview_forecast/130000.json";
    fetch(url).
    then(response => response.json()).
    then(data => document.getElementById("forecast").innerHTML = data['text']);
    setInterval(function() {
        var date = new Date();
        document.getElementById("date").innerHTML = date;
        var hour = date.getHours();
        var minute = date.getMinutes();
        if (hour == 0 && minute == 0) {
            fetch(url).
            then(response => response.json()).then(data => document.getElementById("forecast").innerHTML = data['text']);
        }
    }, 1000);
</script>
```

　これを開くと（直接 html を開いても、ローカルサーバーとして起動しても、どちらでも構いません）、以下のようになるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288125/d9c8bc59-431e-5107-1cd6-519b2a467af7.png)

　`setInterval(hoge,1000)` で更新を毎秒走らせます。
　時刻は内部データを取得し、更に `0` 時 `0` 分であった場合は気象庁の API にアクセスし、当日の天気予報を取得します。

　これらの更新処理は画面遷移を伴わずに行うことができるため、オーバーレイ素材としてブラウザソースで貼り付けても、他の配信素材を邪魔することなく必要な情報だけを付記することができます。

　自分の配信画面に日替わりの天気予報を載せたい人という奇特な人がいたらこれを使ってください。html ファイルを作って上のソースをコピペしたらいけるはずです。

# API の整備が必要

　今回は気象庁の API を利用させていただきましたが、実際には、自分の Web アプリを利用する、または、他人の Web アプリから API で情報を取得することが多いと思われます。

　前者ならば当然、そのための WebAPI、具体的には json を返す仕組みが必要です。

　後者にも罠があって、多くの WebAPI は、セキュリティの問題上、オリジンが異なる JavaScript からの直接のリクエストを認めていないようです。

　以下のようなエラーが出る場合です。

> Access to fetch at 'https://hogehoge' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

（参考：[APIを使用したいが、CORSで使用できない](https://teratail.com/questions/182185)）

## この場合のエラー処理

　この場合、参考記事で言う「踏み台」となる仕組みが必要です。

　上のエラーの要点を日本語に直すと「要求された側に `Access-Control-Allow-Origin` っていうヘッダーがない！」というものになります。私の場合は、`Django` でローカルサーバーを立てて、同一内容のリクエストを送って、取得した情報をヘッダーつきで返すようにすれば解決しました。

　例なので、「全部許可」（`*`）にしていますが、本来ならばこれは許可したアプリ等に限定するべきものです。

```python
def api_step(request, param):
    url = f'https://api.example.com/{param}'
    from django.http import JsonResponse
    res = JsonResponse(requests.get(url).json())
    res['Access-Control-Allow-Origin'] = '*' # ここが重要
    return res
```
【Solidity】(tips) for文の中のcontinue,breakについて

今回はfor文の中のcontinue,breakについて下記します。
for文はループ処理として使用されます。
そのfor文の中で使用されるcontinueとbreakには下記の役割があります。
continue：ループ内の次の反復処理にスキップする
break：ループを抜ける

では、下記のsample関数を実行するとcheck1,check2,checkNumはそれぞれどのような値になるでしょうか。

```
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract Sample {
    string public check1;
    string public check2;
    uint public checkNum;

    function sample()public {
        for(uint i; i<10 ;i++){
            if(i==3){
                continue;
            }
            check1 = "check1";
            
            if(i==5){
                break;
                check2 = "check2";
            }
            checkNum = i;
        }
    }
}

```
答えは下記となります。
check1:"check1"
check2:""
checkNum:4
GKEでPersistentVolumeClaimを作成してもPendingで PersistentVolumeが作られない

# はじめに

以下の書籍を読んでいてうまくいかない箇所があったのでまとめます

https://amzn.asia/d/cFiXMKl

# 問題

```
$ kubectl apply -f volumesources/bookinfo-pvc.yaml
```

PVCを作ると自動でPVの割り当てが行われるとのことでしたが以下のコマンドをするとうまく行っていませんでした

```
$ kubectl get pv
何も表示されない

$ kubectl get pvc
Pendingから変わらない
```

# 解決方法

https://tkzo.jp/blog/use-persistent-volumes-in-gke/#i-3

こちらの記事を読んでディスク作成してからPVCとPVを作るyamlを作成しました

```yaml:/volumesources/bookinfo-pvc2.yaml 
apiVersion: v1 
kind: PersistentVolume 
metadata: 
  name: bookinfo
spec: 
  capacity: 
    storage: 200Mi
  accessModes: 
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: cache 
  gcePersistentDisk: 
    pdName: bookinfo
    fsType: pd-balanced
--- 
apiVersion: v1 
kind: PersistentVolumeClaim 
metadata: 
  name: bookinfo-pvc
spec: 
  accessModes: 
    - ReadWriteOnce
  storageClassName: cache 
  resources: 
    requests: 
      storage: 200Mi
```

またapplyでdiskがないと怒られたので以下のコマンドで確認しました
間違ったリージョンで作成していたのが原因だと気づけました


```
gcloud compute disks list --project cloudnative-cicd-218

NAME                                      LOCATION                   LOCATION_SCOPE  SIZE_GB  TYPE         STATUS
bookinfo                                  northamerica-northeast1-b  zone            10       pd-balanced  READY
gke-cluster01-default-pool-a7ff5e82-25ch  northamerica-northeast1-b  zone            100      pd-balanced  READY
gke-cluster01-default-pool-a7ff5e82-5bpk  northamerica-northeast1-b  zone            100      pd-balanced  READY
gke-cluster01-default-pool-a7ff5e82-7b47  northamerica-northeast1-b  zone            100      pd-balanced  READY
```

# おわりに

とりあえず作成はできましたが、その後の手順ですこしPVC周りを手直しする必要がありそうです

# 参考

https://tkzo.jp/blog/use-persistent-volumes-in-gke/#i-3
GitとGitHubを基本からまとめてみた【トラブル時のコマンド】

## 余計なファイルをコミットしてしまって『ignore』したい時

Gitの管理を削除するなら
```
git rm --cached <ファイル名>
echo '<ファイル名>' >> .gitignore
```
ファイルを履歴から消すなら



## 参考サイト
[Gitでトラブったときに時に使えるコマンド13選](https://www.youtube.com/watch?v=hUYUld6aEmc)
【Solidity】(tips)三項演算子に関して

三項演算子はif　～　elseを一文で書きたいときに使う演算子です。

【三項演算子の書き方】　→ 条件式　？　条件が真の値　：　条件が偽の値

下記hello関数の場合、20以下の数字を渡すと"Ohayo"が返され、20より大きい数字を渡すと "Konnichiha"が返されます。
if else文より簡潔にビジュアルでわかりやすいので、状況に応じて積極的に使っていきたいです。

```
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

contract Sample{
    //
    function hello(uint _x)public pure returns (string memory){
        return _x >20 ? "Ohayo" : "Konnichiha";  
    }
}
```
※上記コードの動作確認はwebブラウザであるRemix IDEを使用
令和最新版FletがWindowsで動かない

# 症状

Fletでスタンドアローンアプリを作ろうとするとエラーが出る。
```
(base) (venv) PS > flet pack main.py      
Please install PyInstaller module to use flet pack command: cannot import name 'decode' from 'PyInstaller.utils.win32.versioninfo' (C:\Users\...\PycharmProjects\myflet\venv\lib\site-packages\PyInstaller\utils\win32\versioninfo.py)
```

# エラーの出た環境

* pyinstaller==5.8.0
* flet==0.3.2及びflet==0.4.0
* Windows（Windows11 64bitで問題を確認した）

# 解決方法

* 問題はpyinstallerの更新にFletが追い付いていないこと。そこで令和旧世代版pyinstaller（pyinstaller==5.7.0）にダウングレードする。
  ```
  > pip install -U pyinstaller==5.7.0
  ```
* もう一度トライ
  ```
  (base) (venv) PS > flet pack main.py
  Updating Flet View version info C:\Users\...\AppData\Local\Temp\71ad1c64-0828-4ba6-932e-877610594e7e\flet\flet.exe
  （省略）
  22846 INFO: Building EXE from EXE-00.toc completed successfully.
  Deleting temp directory: C:\Users\...\AppData\Local\Temp\71ad1c64-0828-4ba6-932e-877610594e7e
  ```
  きちんと動いた

Windowsだけの問題だと思います。

# 問題の原因

Fletに問題がある
* エラーの発生個所  
  ```Python:flet\__pyinstaller\win_utils.py
  from PyInstaller.utils.win32.versioninfo import decode
  ```
  PyInstaller 5.7.0から5.8.0への変更時にversioninfoのdecode関数の名前がread_version_info_from_executableに変更になったため、関数が存在しないとのエラーが発生している。下記のコミットの影響
  https://github.com/pyinstaller/pyinstaller/commit/f57e15ae14d2370cba7a14cfae97d2c29b5c8154
* こうすれば動く
  ```Python
  # from PyInstaller.utils.win32.versioninfo import decode
  from PyInstaller.utils.win32.versioninfo import read_version_info_from_executable as decode
  ```
  GithubにIssueがあった。flet==0.4.1で直るらしい。
  https://github.com/flet-dev/flet/issues/1031
[エラー解消]ActiveRecord::PendingMigrationError


すぐに解決はできたが、備忘として。

```ruby:エラー内容
ActiveRecord::PendingMigrationError

Migrations are pending. To resolve this issue, run: rails db:migrate RAILS_ENV=development
```


# 解決方法
何となく英文で分かりますよね。
原因は、db:migrateし忘れていたことによるエラー。
カラム作成したらすぐに`**rails db:migrate**`しよう。

migrateでもエラーの場合は、DBが作られているか確認が必要。
作られていなかったら、
`**rails db:create**`で作成してから`**rails db:migrate**`する。


データベースを作成した際は、使用しているDBアプリに反映しているか確認しておくこと。（私の場合はSequel Pro）
【ギター】Pythonでギタリストたちのためにチェンジアップを練習できるアプリを作ったっピ【基礎練習】

# チェンジアップ練習用のアプリ

楽器を演奏していると4分、8分、16分、と様々なリズムでクロマチック練習したくなるものです。私は通常6弦の5→6→7→8フレット、5弦の5→6→7→8フレット、...1弦の5→6→7→8フレットの計24フレットを行きと帰りで48回(ワンセット)弾くクロマチック練習をしています。チェンジアップを練習するにあたって、4分、8分、16分など様々なリズムで練習したくなり、アプリを作ってみました。自分でやると、どうしても偏りが出てしまうのではないか、という懸念があったり、PCがランダムに次の拍を自動で指定してくれたら便利なのになぁ...と思ったりして作りました。ワンセット弾き終わるころに時間を自動で計算して次に弾くべきリズムを提示します。なお、使用にあたってはメトロノームが必須です。任意のbpmで練習できます。

# ダウンロード

githubの方にアップしました。
アクセスすると即座にダウンロードが開始されます。

https://jikao1919.github.io/test/guitar/dist.zip

# 使い方

zipファイルを解凍してフォルダの中の適当な位置においてください。
distの中のrhythm.exeという実行ファイルがアプリケーションになります。

実行すると、ディフェンダーによってPCが保護されるかもしれませんが、続行をクリックして実行してください。

するとコマンドプロンプトが起動し、ゲームモードを選択します。hardでは6連符が入るので、早いリズムでは難しくなります。自分はいつも遅めのbpmで、ハードモードでやっています。

次にリズムを選択します。お好みで選んでください。私の場合は70ぐらいで練習しています。

最後に繰り返し回数です。何回指板上を行ったり来たりするか、何セット行うかを選択します。自分はいつも20ぐらいでやっています。

# もともとのPythonコード

実行ファイル化する前のパイソンコードを添付しておきます。
ウイルスじゃないですよ...。

```:python
from random import random
import tkinter
import random

# 難易度選択
nanido = input('難易度選択!Hard(h) or Easy(e)')

# bpm入力
bpm = input('bpm=?')

# 繰り返し回数を入力
kurikaeshi = input('繰り返し回数')

# 表示テキスト・表示時間のリスト作成
mytxts = ['4分音符', '8分音符', 'シャッフル', 'スウィング', '16分音符', '3連符', '2拍3連']
mytimes = [int(2880000/int(bpm)), int(1440000/int(bpm)), int(1440000/int(bpm)), int(1440000/int(bpm)), int(720000/int(bpm)), int(960000/int(bpm)), int(1920000/int(bpm))]

if nanido == 'h' :
    mytxts.append('６連符')
    mytimes.append(int(480000/int(bpm)))


# Window表示を関数として定義
def hyouji(mytxt, mytime):
    root = tkinter.Tk()
    # テキストを表示させる
    w = tkinter.Label(root, text=mytxt, font=("normal", 20))
    w.pack()
    # 決まった時間後に閉じる
    root.after(mytime,lambda: root.destroy())
    # 継続して表示
    root.mainloop()

def deter(idx_pre) :
    idx = mytxts.index(random.choice(mytxts))
    while idx_pre == idx :
        idx = mytxts.index(random.choice(mytxts))
    return idx

# 表示
display_pre = ''
idx_pre = -1
for num in range(int(kurikaeshi)) :
    idx_pre = deter(idx_pre)
    hyouji(mytxts[idx_pre], mytimes[idx_pre])
```

# Pythonをダウンロードすれば、もっと自分好みにカスタマイズできます。

最後に、Pythonをダウンロードしてコードをコピペすれば、もっと練習の幅が広がるかなと思います。この機会にPythonデビューされては如何。
Excel メジャーじゃないけど知っておくと便利な小技3選

# 目的

職場でExcelをこねこねしているときによく使うショートカットキーやコマンドを紹介します。

# alt + ~~
## alt + アンダーライン付きローマ字

検索と置換を例にあげますが、**alt + D**で検索へ**alt + T**でオプション画面へ遷移することができます。
アンダーラインが引いてあるローマ字系はalt + xxxで操作可能です。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837411/1c59a7bc-9024-f4e7-3a1f-21e2dac345d7.png)

## ctrl + A → alt + H + O + I

こんなシートがあったとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837411/9bed1833-97bf-7168-de1a-37808cbb1727.png)


極端ですがこんなに無駄があるシートでもctrl + Aで全選択を実施後に、**alt + H + O + I**で列の幅を自動調整することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837411/e5ebd735-fad2-233e-44bc-44659ef8ba48.png)

## 3D集計

下記のように複数のシートの同じセルに値が入っているファイルがあったとします。
今回は20枚同じ内容のシートを作成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837411/7b168e0e-dfb0-3e5d-fbd6-6d8f87aec794.png)

全シートのC3セルに入力された値を合計したいときに3D集計を利用します。

SUM関数で計算したいシートの最初(sheet2と仮定)を選択し、SHIFTを押しながら計算したい最後のシートを選択します(画像ではsheet0)。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837411/a15a1f93-5712-5062-e5ea-547830c07190.png)

上記の例では **=SUM(Sheet2:Sheet0!C3)** と入力するだけで指定したセルの値の合計を表示できます。

### シートが増えた時

- 計算したい最初のシートの前に**START**
- 計算したい最後のシートの後に**END**

このように上記のSTARTとEND内でシートを追加していき、計算式を以下のように書き換えます。

**=SUM(START:END!C3)**

実際に97枚シートを作成しましたが、STARTとENDの範囲内なので計算できています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837411/635b140d-beeb-c33c-f7ef-f912585b7cf5.png)
M1 Macで node-sqlite3 が動作しない

nodejsのversionを14から16に変えた際にsqlite3が以下のようなエラーが発生するようになった。
```
Error: Cannot find module '[..]/node_modules/sqlite3/lib/binding/napi-v6-darwin-unknown-arm64/node_sqlite3.node'
```

stackoverflowの以下の記事のやり方で解消したので方法を記載する。

[How to get node-sqlite3 working on Mac M1?
](https://stackoverflow.com/questions/72553650/how-to-get-node-sqlite3-working-on-mac-m1)

```bash
# sqlite3をアンインストール
npm uninstall sqlite3
# arm64でbuildするように指定する。
npm install sqlite3 --build-from-source --target_arch=arm64 --fallback-to-build

```

バイナリコンパイル用のパッケージである node-pre-gyp が
インストール時にARM64としてコンパイルせず、実行時にARM64用のモジュール「napi-v6-darwin-unknown-arm64」が見つからずエラーになってしまう問題があるらしい。
よく間違える演算子




```diff_ruby:演算子
a = b       　　 # a に b を代入する
a == b        # a と b が等しい
a != b        # a と b が等しくない
a < b         # a が b よりも小さい
a > b         # a が b よりも大きい
a <= b        # a が b 以下である
a >= b        # a が b 以上である
```

よく代入と等しい、未満、以下の記述を間違えてしまいがち。
この癖早く直そ。
[pip] サクッと理解！！！pipの管理パッケージを一括で最新バージョンにアップデートする！！！

# 爆速で行きますよ

## ほい！サクッと！
```zsh
pip freeze | sed -E 's/(.*)==.*/\1/g' | xargs -n1 pip install -U
```
## サクッと説明していきます！
`pip freeze`コマンドでインストール済みのパッケージのリストを取得します。
次に`sed`コマンドでパッケージ名のみを抽出して、`xargs`コマンドを使って、1つずつパッケージをアップグレードします。

## 具体的には?
`sed -E 's/(.*)==.*/\1/g'`の部分で、パッケージ名のみを抽出しています。
正規表現部分の意味は以下の通りです。

`(.*)`: 任意の文字列を表すグループ
`==`: ==という文字列
`.*`: ==の後ろの任意の文字列
`\1`は正規表現で指定された最初のグループを参照するためのものです。

例えば、`django==3.2.7`というパッケージがある場合、`sed`コマンドによってdjangoという文字列が抽出されます。
最終的には、`xargs -n1 pip install -U`によって、各パッケージがアップグレードされます。

## 参考
- [【 xargs 】コマンド――コマンドラインを作成して実行する](https://atmarkit.itmedia.co.jp/ait/articles/1801/19/news014.html)
- [sed コマンド【使い方 まとめ】](https://tech-blog.rakus.co.jp/entry/20211022/sed)
特定条件のみに呼応するプログラムの作成

今日のアウトプット

問題.
今日の曜日を表示するコードをDateクラスを使用して記述せよ。
出力内容は、「月曜日です」。
ただし、金曜日だった場合だけ「今は日金曜日」と表示内容にすること。

```ruby:ヒント
# Dateクラスとは?
# Rubyの標準機能。Dateクラスを使うには以下一文を記述。
require "date"

# 次に、Dateクラスを用いて「今日の曜日」を取得する場合は以下のように記述。
# wdayは曜日を0(日曜日)から6(土曜日)の整数で取得できるDateクラスに用意されているメソッド。
day = Date.today.wday

# 曜日に合わせた数字が出力され、木曜日だと4が出力されることになる。
puts day
```

```ruby:解答
require "date"　#Dateクラスをライブラリから呼び出し

day = Date.today.wday #wdayメソッドを用いて曜日を0（日曜日）から6（土曜日）の整数にしたときの「今日」の値を取得。
days = ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"] # 配列daysを定義し、日曜日（0番）〜土曜日（6番目）まで文字列を格納。

if day == 5　 #条件分岐
  puts "#今日は#{days[day]}。"
else
  puts "#{days[day]}"
end

```
wdayは曜日を0(日曜日)から6(土曜日)の整数で取得することができるDateクラスに用意されているメソッドということで、
私は勘違いしてday = Date.today.wdayを記述すれば整数指定したら取得できるものかと思ってたら、配列にしないとなのね！！
【SAP HANA SQLScript】SAP DBTech JDBC: [7]: feature not supported: parameter is not allowed without alias

# エラー
Could not execute 'CREATE OR REPLACE PROCEDURE foo'
SAP DBTech JDBC: [7]: feature not supported: parameter is not allowed without alias: ****: line 144 col 7 (at pos 3410)

# 解決策
ストアドプロシージャの引数をテーブルに突っ込むときに、AS で別名をつける。

# 例
```SQL

CREATE PROCEDURE foo(
    IN aaa INT
) AS BEGIN

# NG
data =
    SELECT :aaa -- エイリアスがついてないのでエラー（らしい）
    FROM dummy;

# OK
data = 
    SELECT :aaa AS "ALIAS" 
    FROM dummy;
```

HANAScript特有なのか、ストアドプロシージャ共通の仕様なのかはわかりません。
The `setup.py py2exe` command line interface is deprecated and will be removed in the next major release.

# setup.pyが使えなくなった
https://laboratory.kazuuu.net/converting-a-py-file-to-an-exe-executable-in-python-using-py2exe/

https://bogamp.hatenablog.com/entry/2022/12/10/072750

これらの文献を参考に、pythonファイルを実行ファイルに変換しようとしましたが、タイトルの通りエラーが出てしまいました。
どうやら`setup`は使えなくなった模様。

そこで、

https://github.com/py2exe/py2exe/blob/master/README.md

https://github.com/py2exe/py2exe/blob/master/docs/py2exe.freeze.md

こちらの記事を参考に、新しい`freeze`メソッドを用いた変換の手順を記していきます。

# freezeの使い方

1. 変換したいファイルを用意する。ここではtest.pyとします。

2. 変換用のpythonファイルを作成していきます。名前はおそらく何でもいいのですが、今回は仮にsetup.pyとします。

    ```:python
    from distutils.core import setup
    import py2exe
    
    py2exe.freeze(console=['test.py'])# 変換したいファイル名
    ```

3. test.pyとsetup.pyをどこか適当なディレクトリのフォルダ内に安置します。このとき、変換用の2ファイルと同一階層内に別のフォルダがあると、
    
    ```
    error multiple top-level packages discovered in a flat-layout py2exe
    ```

    というエラーが出現するようです(詳しくは未確認)。私の環境では変換用に新たに1つフォルダを作成し、その中に2ファイルを移動させることで回避できました。

4. setup.pyを実行。

5. フォルダ内にdistという新しいフォルダが作成されるので、その中を確認するとexeファイルが生成されている。


# setupはもう使えないが、簡単にexe化できる。

小さなファイルであれば所要時間もほとんど変わらず変換できそうです。
Docker の実験（その８：Dockerfile のオプション）

[その７：イメージの作成](https://qiita.com/intrajp/items/9bf5e4cc5893d9c95da8)のつづき。

前回作成した Dockerfile では、まだ不十分なところがあるので、少し仕上げていく。

EXPOSE を入れないと、イメージを受け取った人がどのポートで立ち上がるのかがわからないので、Dockerfile に記述することが重要である。
HEALTHCHECK 
例えば、立ち上げている nginx コンテナの IP アドレスが 172.17.0.2 であり、それを、monitoring というコンテナから監視する場合、イメージ作成時に使用する Dockerfile には、以下のように記述するとよい。

--interval=DURATION （デフォルト30秒）
--timeout=DURATION（デフォルト30秒）
--start-period=DURATION（デフォルト0秒）
--retries=N （デフォルト 3）

（一例）
```bash
HEALTHCHECK --interval=5s CMD ping -c 1 172.17.0.2
```

（ローカルホストの監視の一例: curl の -f オプションは、結果だけを返す）
```bash
HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1
```

上記は、docker run でも使用できる。
--health-cmd を使える。
この様な監視には、busybox イメージからコンテナを作成するのがいいだろう。

```bash
$ docker run -dt --name tmp --health-cmd "curl http://localhost" --health-interval=5s busybox sh
```

ENTRYPOINT は、ランタイムでのコマンドの上書きを防ぐ。

（一例）
```bash
ENTRYPOINT ["/bin/ping"]
```

WORKDIR を使うと、コンテナは、そこに誘導される。

EMV を使うと、Dockerfile のメンテナンスが楽になる。

（一例）
```bash
ENV NGINX 1.2
RUN curl -SL http://example.com/web-$NGINX.tar.gz
```

環境変数をコンテナ作成時に渡すことができる。

```bash
$ docker run -dt --name env02 --env USER=testuser busybox sh
```

以下のような INSTRUCTION がある。

CMD | ENTRIPOINT | ENV | EXPOSE | LABEL | ONBUILD | USER | VOLUME | WORKDIR

[その９：コンテナを Container Registry に登録する](https://qiita.com/intrajp/items/f5bd729027bc4c8e691b)につづく。
【VSCode】駆け出しが知るべきショートカット集

# はじめに

Mac用です

超基本的なものは省きました

基本的なカーソル移動は矢印キーではなく、Emacsキーバインドでやりましょう（私の場合はKarabinerで独自のコマンドモードを作成してます）

## ファイル操作

### ファイルを開く

VSCodeを起動したら、ファイルを開くためには以下の操作を行います。

```
コマンド + O

```

この操作により、Finderでファイルを選択することができます。

### ファイルを閉じる

ファイルを閉じるためには、以下の操作を行います。

```
コマンド + W

```

### アクティブなファイルパスをコピー

```
コマンド + k → p
```

### Finderでアクティブなファイルを表示する

```
コマンド + k → r
```

### アクティブなファイルを新しいVSCodeウィンドウで開く

```
コマンド + k → o
```

---

## カーソル操作

カーソルの移動に関するショートカット

### 選択行の移動

地味便利

```
オプション + 矢印キー
```

### 選択行の削除

```
コマンド + シフト + K
```

### 選択行のコピー

```
オプション + シフト + 矢印キー
```

### 選択行の下に行を挿入

```
コマンド + Enter
```

### 対の括弧にジャンプ

```
コマンド + シフト + ¥
```

### 任意の場所を複数選択

```
オプション + クリック
```

### 同じ文字列を複数選択

```
コマンド + D
```

### 矩形選択

```
コマンド + オプション + シフト + 矢印キー
```

---

## 検索・置換

テキストの検索・置換に関するショートカット

### 置換

```
コマンド + オプション + F
```

### ワークスペース全体の置換

普通の置換とコマンドが結構違うから覚えにくい。。

```
コマンド + シフト + H
```

---

## ビュー操作

ウィンドウの切り替えやタブの操作に関数ショートカット

### サイドバーの開閉

```
コマンド + B
```

### エディターのグループ内分割トグル

エディターを左右に分割できる

```
コマンド + K → コマンド + シフト + ¥
```

### クイックオープンウィンドウを開く

画面上部に開く入力窓でファイルを開いたり、指定した行にジャンプしたりする事が出来きます

```
コマンド + P
```

### タブ移動

```
コマンド + オプション + 矢印キー
```

### コマンドパレットを開く

VSCodeの機能を検索できる

```
コマンド + シフト + P
```

### エクスプローラーを開く

画面左のファイルアイコンのやつ

```
コマンド + シフト + E
```

---

## エディター操作

テキストの編集に関するショートカット

### サジェスト（予測変換）

Spotlight検索等と被るときはOFFにしないとだめ

```
コントロール + スペース
```

### ブロックコメントの切り替え

```
シフト + オプション + A
```

### コードの折りたたみ

コードを折りたたむためには、以下の操作を行います。

```
オプション + コマンド + [

```

### コードの展開

コードを展開するためには、以下の操作を行います。

```
オプション + コマンド + ]

```

### フォーマットする

```
シフト + オプション + F
```

### 定義にジャンプ

```
F12
```

---

## デバッグ機能

デバッグに関するショートカット

### ブレークポイントを切り替え

```
F9
```

### 開始・続行

```
F5
```

### ステップイン

```
F11
```

### ステップアウト

```
シフト + F11
```

### ステップオーバー

```
F10
```

### 止める

```
シフト + F5
```

### ホバーを表示

```
コマンド + k → コマンド + i
```

---

## まとめ

以上、macOSで利用することができるVSCodeのコマンド集について紹介しました。これらの操作を覚えることで、より効率的にコードを編集することができます。
Jestでテストしようとしたら、Jest: Failed to parse the TypeScript config...エラーが出た話

`remix-auth-strategy-template`からリポジトリを作成して、remix-auth用の独自のプラグインを作成していた。

https://github.com/sergiodxa/remix-auth-strategy-template

そして、テストを実行しようとしてエラーが発生した。

```shell
node ➜ /workspaces/remix-auth-jwt (main) $ npm run test

> remix-auth-strategy-template@0.0.0 test
> jest --config=config/jest.config.ts --passWithNoTests

Error: Jest: Failed to parse the TypeScript config file /workspaces/remix-auth-jwt/config/jest.config.ts
  Error: Debug Failure. False expression: Non-string value passed to `ts.resolveTypeReferenceDirective`, likely by a wrapping package working with an outdated `resolveTypeReferenceDirectives` signature. This is probably not a problem in TS itself.
    at readConfigFileAndSetRootDir (/workspaces/remix-auth-jwt/node_modules/jest-config/build/readConfigFileAndSetRootDir.js:150:13)
    at readConfig (/workspaces/remix-auth-jwt/node_modules/jest-config/build/index.js:210:18)
    at readConfigs (/workspaces/remix-auth-jwt/node_modules/jest-config/build/index.js:406:26)
    at runCLI (/workspaces/remix-auth-jwt/node_modules/@jest/core/build/cli/index.js:230:59)
    at Object.run (/workspaces/remix-auth-jwt/node_modules/jest-cli/build/cli/index.js:163:37)
```

テストを実行した時の`node`のバージョンは`v18.14.0`だった。`npm`は`9.3.1`。

解決策を探していたら次のIssueを見つけた。

https://github.com/microsoft/TypeScript/issues/49257

提案されていたのは、`typescript`と`ts-node`を最新版にアップデートすることだった。

```shell
$ npm install --legacy-peer-deps --save-dev typescript@latest ts-node@latest
```

アップデート後にテストをもう一度してみると、今度は成功した。

```shell
node ➜ /workspaces/remix-auth-jwt (main) $ npm run test

> remix-auth-strategy-template@0.0.0 test
> jest --config=config/jest.config.ts --passWithNoTests

 PASS  test/index.test.ts (18.315 s)

Test Suites: 1 passed, 1 total
Tests:       1 todo, 1 passed, 2 total
Snapshots:   0 total
Time:        20.576 s
Ran all test suites.
```

ちなみに、作ってたのはこれ。

https://github.com/takagimeow/remix-auth-jwt
例外が発生しました: TclError bad argument "333333333333333333333333333333333333333333333333333333333

# 謎のエラーに遭遇。

```
例外が発生しました: TclError
bad argument "33333333333333333333333333333333333333333333333333333333333333333333333
```

ええええ...
何だこれ...

# 書いていたコード

十分に再現可能なため、一部だけ書きます。

```:python
interval = input("インターバル秒数")
interval = 1000*interval
```

ユーザーにインターバル秒数を`input`で書き込ませ、それをミリ秒に変換するものです。
先ほどのエラーは`input`にて3を入力した際に生じるエラーでした。2を入れたときは、2222222222222222222222....とエラーが変わっていました。

# 原因の特定と修正

デバッグしていたら、`interval`のデータ型が目に入りました。`string`型になっていました。`int`型に修正して正確に動きました。

```:python
interval = input("インターバル秒数")
interval = 1000*int(interval)
```

## 連番の謎

調べてみたところ、文字列に対しても乗算が定義できるようです。
ABC＊4なら、ABCABCABCABCになるとのこと。エラーでは1000桁の連番が出力されてしまったようですね。。。

https://www.javadrive.jp/python/string/index6.html


データ型には気を付けよう!
LogicException  : Laravel v6 is only compatible with doctrine/dbal 2, in order to use this feature you must require the package "doctrine/dbal:^2.6".

## エラー内容
LogicException  : Laravel v6 is only compatible with doctrine/dbal 2, in order to use this feature you must require the package "doctrine/dbal:^2.6".


## 解決方法
このエラーは、Laravel 6がdoctrine/dbal 2としか互換性がなく、別のバージョンを使用しようとしているために発生しています。解決するには、以下の手順を実行してください。

1. composer.jsonファイルを開きます。
2. "require"セクションで、"doctrine/dbal"のバージョンを"^2.6"に変更します。
3. コマンドラインでcomposer updateを実行し、変更を反映します。
4. Laravelアプリケーションを再起動します。
これで、Laravelアプリケーションがdoctrine/dbal 2.6を使用するようになり、エラーが解決されるはずです。

doctrine/dbalがcomposer.jsonファイルに記載がない場合は、以下コマンドを実行してください。

```
composer require "doctrine/dbal:2.*"
```
何故Javaは敬遠されるのか？

# 何故かJavaは敬遠される！？
筆者はIT業界に努めて17年ほどです。
SESとして働きに出ることが多かったのですが、近年はWebエンジニアとして
PHP(Laravel)を使った開発が多くなってきています。
そんな開発現場ですが、プログラミング言語の話題に上がると

- 「Javaはわからない」
- 「Javaって難しいんでしょ？」
- 「環境構築がなぁ・・・」

なんて話をよく聞きます。
私はJavaの方が経験した期間が長かったので、特にそういった苦手意識は無いのですが
Laravelの現場でもそういった話を聞くので、
「フレームワークの特性や、コードの書き方は結構似ているところが多いのに、何でみんな苦手なんだろう？」
と思ってしまうのです。
今回はそのギモンについて、私が思っていることを書いていきます。
（注：Java嫌いな人を論破したいわけではありませんｗ）


## 原因その１：インフラ構造上、難しいと思われがち
PHPの環境、所謂LAMP環境ですがこれを構築するのはそこまで難しくありません。
対してJavaの環境を作るためにはApache(もしくはNginx)からTomcatに繋ぐ構築が必要になります。
加えてJVMを動かすため、JAVA_HOME等のPATHを通すことも必要です。
構築にひと手間いるから難しい、と感じている人が多いのでしょうか？

#### 　=>Apacheが２つに分かれたと思えばそんなに難しくない
PHPはApacheと関連するモジュールをインストールすればすぐ動きます。
Javaの場合はWebサーバをApache、アプリケーションサーバ(サーブレットコンテナ)をTomcat、とすることでそれぞれにかかる負荷を分散しています。
加えて、JVM上で動くのでTomcatの中でメモリのコントロールが可能です。
PHPの場合、全てをApacheに依存しているのでメモリのコントロールもApacheプロセスで行う必要があります。
(iniファイルや.htaccess等に設定を記述して制御します)
小さいシステムではどちらでも良いですが、アクセス数が多い、あるいは１度のリクエストが重い時などは
Javaの環境があるとコードで制御しやすいです。

## 原因その２：フレームワークが多すぎ＆フレームワーク毎に書き方が変わるので難しいと感じる
Struts、Spring、Play、そしてそれらの亜種(SAStrus、Grails)など、フレームワークの数が多く
学習コストが高いと感じている人が多いのでは？と勝手に思っています。

#### 　=> 確かに難しいが、結局MVC。
確かに。確かにそれぞれのフレームワークで環境は異なります。
同じJavaでもControllerの書き方が違ってたり、サーブレットマッピングのやり方も異なります。
でもMVCであることに変わりはありません。本質的なところを理解できれば場違いなほど難しい！ということは無いはず。
但し、後述の内容と組み合わせて、より複雑さは増します（笑

## 原因その３：ライブラリ管理が２種類。maven？gradle？なんだそれは。
今のJava開発環境で主流のライブラリ管理はmavenかgradleの２種類かなぁと思ってます。
Javaを採用している事業会社だと、技術もレガシーになりがちなので比較的mavenが多い印象。
このライブラリ管理とフレームワークの組み合わせで「環境が整わない」「実行時エラーが多発」
などがあり、結果Javaが難しく感じてしまうのでは？という印象があります。

#### 　=> ライブラリ管理なんてどの環境でもやってる。
Laravelならcomposer、pythonならpip、goならgo get(今だとgo install？)、rubyならgemと
いった感じで、どの言語環境でもライブラリ管理は付き物です。
それがJavaの場合２種類あるよ、というだけ。

## 原因その４：そもそもIDEのセットアップむずくね？eclipse動かないし、動いても重い
eclipse単体はJavaのコードを書けるようなIDE(統合環境)ですが
プラグインも多く、何をインストールすれば良いのやらわかりません。
うまくいってもインストールしたプラグインが多すぎて動作が重いです。

#### 　=> 確かにVSCodeなどで開発している人にとってはセットアップ面倒ですね。
ただ、間違えてほしくないのはVSCodeは「エディター」止まりであって「IDE(統合環境)」では無いということです。
とは言うもののVSCodeもかなり拡張機能が優秀で、ほぼIDEに近いシロモノなのですが。
eclipseのセットアップが面倒であればpreiadesからall-in-oneパッケージ拾ってインストールすればいいし
動作の重さはJVMの設定をeclipse.ini弄ってコントロールすればいいだけです。

## 他にも細々としたモンがいくつかある！
まぁ、上記に書いたこと以外にも
- アプリケーションサーバはTomcat以外にもある(JBoss(悪名高い)とか、Glassfishとか、変わったところではWebSphereとか)
- DBの接続が面倒(JDBCドライバ探してコネクション設定してetcetc...)
- コンパイル言語である。静的型付け。

とかとか。

## ここまで書いておいて何だけど、dockerがあるじゃないか！
環境構築の面倒さを色々書いてみたけど、最近ではJVMが入っているdockerコンテナも多数あるので
それ使って環境構築したらいいのでは？と思う次第なのです。
eclipseとかが難しくて嫌ならJetBrains産のIDE使いましょうｗ

## まとめ
いかがでしょうか？Javaは敬遠されがちだけど、冷静になってみると
（多少、学習コストはかかると思いますが）他の開発言語とそんなに極端に変わるものではないと思います。
もちろん、最初は少数でいいからサクっとサービス作りたい！というのであれば
簡単に環境構築でき、動的型付けなPHPなどのスクリプト言語を使えば良いと思います。
但し、本格的にどっしりとした（つまりセキュリティ面やパフォーマンス面を意識したプログラミングをする場合）開発を行うのであれば
Javaの環境を候補に挙げるのも良いと思いますよ。

ここまで読んで頂き、ありがとうございました。
nodejsでパラメータストアの値をいい感じに取り出す方法

SSMのgetSSMParametersを使って複数のパラメータを取得する時、ちょっとごにょごにょしなくちゃいけないんですが、思ったよりキレイなコードになったので、lambdaのサンプルコードを載せておきます。

```javascript
const AWS = require("aws-sdk");
AWS.config.update({ region: "ap-northeast-1" });
const SSM = new AWS.SSM();

const getSSMParameters = async(names) => {
    const result = await SSM.getParameters({Names: names}).promise();
    return names.map(name => 
        result?.Parameters?.find(el => el.Name === name)?.Value
    );
};

exports.handler = async (event) => {
    const [url, stranger, user, nickname, avatar] = await getSSMParameters(['url','stranger','user','nickname','avatar']);
    const response = {
        statusCode: 200,
        body: {url, stranger, user, nickname, avatar},
    };
    return response;
};
```
【C++】Ford-Fulkerson法の実装

# Ford-Fulkerson法とは
グラフの最大流を求める問題を解くアルゴリズムです。やっていることはdfsの繰り返しですが、「逆辺」を考慮に入れなければなりません。最大流とは、
- グラフ$G=(e,v)$において、$s$から$t$に向かって最大でどれだけの量のフローを流せるかを求める

という問題のことです。今回の記事では詳しい説明を省略します。
**Ford-Fulkerson法**は以下の手順で行います。
1. $G$に、$e$の逆辺を追加する。(逆辺を$e^{-1}$で表します)
1. $f(e)<=c(e)$を満たす辺と、$f(e^{-1})>0$を満たす逆辺のみで構成されるグラフ(このようなグラフを**残余グラフ**と呼びます)で、$s$から$t$に向かってdfsをし、パスを見つける。答えにパスの流量を加算する。
1. そのようなパスが存在しなくなるまで、2を繰り返す。

逆辺とは、$e=${$a,b$}に対しての$e^{-1}=${$b,a$}のことです。$e$が$f$のフローを持っている状態のとき、逆辺は$f$の容量を持っているとします。逆辺の容量は「$e$においてどれだけフローを押し戻せるか」をあらわしていると理解すると分かりやすいと思います。
この手順で最大流が求まる証明は、蟻本を読むか、賢い人がブログで解説しているのでそちらを参照してください。

# 実装例
初期変数として
```cpp
struct edge { int to, cap, rev; }; //辺の構造体 to:行き先, cap:容量, rev, 逆辺の位置
vector<edge> G[MAX_V]; //辺の隣接リスト表現
bool used[MAX_V]; //dfsで調べたか
```
を定義しておきます。辺を追加する操作を以下のように実装します。
```cpp
void add_edge(int _from, int _to, int cap){ 
	edge e = { _to, cap, G[_to].size() }; G[_from].push_back(e);
	e = { _from, 0, (int)G[_from].size() - 1 }; G[_to].push_back(e);
}
```
逆辺の位置をvectorの現在の最後尾で管理しています。これにより$e$の逆辺には
```cpp
G[e.to][e.rev]
```
でアクセスすることができます。
dfsで$s$から$t$へのパスを求める操作を以下のように実装します。ある$e$において、元の容量から流量を引くことで、残りの容量を管理します。こうすることで、残余グラフにおける辺と逆辺を1つの条件で発見することができます。
```cpp
int dfs(int v, int t, int f) {//sからtへ移動可能ならそのルートの最大流量を返し、不可能なら0を返す。
	if (v == t) return f; //到達した
	used[v] = true; //調べ終わった
	for (int i = 0; i < G[v].size(); i++) {
		edge& e = G[v][i];
		if (!used[e.to] && e.cap > 0) { //残余グラフの辺のみ
			int d = dfs(e.to, t, min(f, e.cap));
			if (d > 0) {
				e.cap -= d; //残り容量はd減少
				G[e.to][e.rev].cap += d; //逆辺の容量はdだけ増加する
				return d;
			}
		}
	}
	return 0; //到達できない
}
```
このdfsで、$s$から$t$へのパスが1つ見つかるか、パスが存在しないことが分かります。
これをパスが存在しなくなるまで、以下のように繰り返します。
```cpp
int max_flow(int s, int t) {//最大流を求める
	int flow = 0;
	while (true) {
		memset(used, 0, sizeof(used));
		int f = dfs(s, t, infi);
		if (f == 0) return flow;
		flow += f;
	}
}
```
# 計算量
dfsでフローが1のパスしか見つからないことが永遠に繰り返されると、dfsの繰り返し回数は最大で$F$回です($F$:考えうる流量の最大値)。dfsは$G$が一直線の有向グラフの場合$|E|$かかります。
従って、Ford-Fulkerson法の計算量は$O(F|E|)$となるのですが、よく考えると
- dfsでフローが1のパスしか見つからないことが永遠に繰り返される
- $G$が一直線の有向グラフ

というのは両立しないので、実はここまでの計算量はかからず、$O(F|E|)$で危なそうな程度なら通ることが多いようです。

# 補足 : 色々な問題ケース
上の実装は最もシンプルなケースを考えたもので、
- 頂点に容量はなく、入ってくる流量と出ていく流量は等しい
- グラフは有向グラフ
- 流れの元となる点$s$(ソース)と流れの終点$t$(シンク)はそれぞれ1つ
- 辺に対する最小流量は全て$0$

という条件で考えました。これらの条件が満たされないグラフに対して、少し工夫することで今回紹介した実装をそのまま使うことができます。
## 1. 頂点に容量がある場合
頂点で容量があるということは、その頂点内に辺が存在してそこに容量上限まではフローが流れるということです。
頂点$v$の容量を$c$とすると、頂点$v$を容量$0$の頂点$v_{in}$と$v_{out}$に分けて、$v_{in}$と$v_{out}$をつなぐ容量$c$の辺を追加すれば、同じ状態にできます。もともと$v$に入ってきていた辺は$v_{in}$につなぎ、$v$から出ていた辺は$v_{out}$からつなげばよいです。

## 2. 無向グラフの場合
無向グラフは双方向の有向グラフと考えることができるので、無向辺$e$=($a,b$)を、2つの有向辺$e_1$={$a,b$}と$e_2$={$b,a$}に分けて追加すればよいです。一見辺の合計容量が倍になってしまうように感じますが、向きが逆なため、最大でも$c$しか流れないことが分かります。

## 3. 複数のソース・シンクがある場合
例えば複数のソース$s_1,s_2,s_3...$があり、それぞれの最大流出量が決まっているなら、新たに別の点$s$を作成して、$s$からすべてのソースに対してそれぞれの最大流出量分の容量を持つ辺を追加することで、$s$をただ1つのソースとして問題を解くことができます。シンクに関しても同様です。

## 4. 辺に最小流量の条件がある場合
辺$e$が容量$c(e)$および最小流量$b(e)$によって、$b(e)≦f(e)≦c(e)$で条件付けられていた場合を考えます。この不等式は$f^{'}(e)=f(e)-b(e)$とすることで、$0≦f^{'}(e)≦c(e)-b(e)$となり、最小流量の制限がないケースに帰着できます。