OmniAICreator/Qiita-1.07M huggingface dataset:
Fletアプリにプログレスバーを付ける

# はじめに

[Flet](https://flet.dev)、すごく便利です。
クロスプラットフォームなアプリを作れるのはもちろんですが、ちょっとしたローカルデスクトップアプリを作るときにも十分実用的です。この記事では、Fletアプリでプログレスバーを実装する方法をかんたんに記載します。

### Note
PythonやFletはインストールされている前提となります。
記事内のコードは以下の環境で動作確認しています。
- Windows 10 
- Ubuntu Desktop 22.04.2 LTS
- Python 3.10.4

## やりたいこと

![screen.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65963/3ed5f425-ec74-171d-83d7-cfd1731b83d3.gif)


- 実行前
![screen0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65963/f2a6b917-80ed-98c2-df88-17198c105b3e.png)


- 実行中（これ！）
![screen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65963/c86fc5d9-b795-2c32-ad9c-33ded60006bc.png)

- 実行後
![screen2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65963/8143c77f-ca24-db64-961e-114393782fa5.png)


超シンプルですね。
ファイルを指定して何らかの処理を実行するだけのアプリです。

:::note info
上記のスクリーンショット画像では背景色が黒ですが、背景色は実行する環境（OS）のアピアランス設定に依存します。
:::

フローを箇条書するとこんな感じでしょうか。

- ファイルを指定する
- **[実行]** ボタンをクリックする
- **プログレスバーが表示される**
- 処理後に「**完了!**」と表示され、**プログレスバーが非表示**となる

## コード

```python
import flet as ft
from pathlib import Path
import time


def do_something():
    time.sleep(5)

def main(page):
    dir_path = ft.TextField(label="ファイル", autofocus=True)
    done = ft.Column()
    
    # プログレスバーの設定
    progress = ft.ProgressBar(width=400, color="pink", bgcolor="#eeeeee")

    def btn_click(e):
        # プログレスバーを表示する
        page.add(
            progress
        )
        
        # 何らかの処理
        do_something()
        
        # プログレスバーを非表示にする
        page.remove(progress)
        
        # 完了メッセージ
        done.controls.append(ft.Text(value="完了!"))
        
        page.update()
        dir_path.focus()
        
    page.add(
        dir_path,
        ft.ElevatedButton("実行", on_click=btn_click),
        done,
    )

ft.app(target=main)
```

コードも超シンプルです。プログレスバーの書式設定も直感的にわかるかなと思います。

実際にはもっとあれこれ処理を書くことになると思いますが、簡易なものであればこのコードの `do_something()` を書き換えるだけで使いまわしが利きそうです。

これなら、重い処理をするアプリにプログレスバーを実装するのもかんたんですよね。

# おわりに

今回はデスクトップアプリとして（不定な）プログレスバーを実装する簡易なサンプルを紹介しました。
これをWebアプリにすることもできるというのがまたすごいところですね。正直、個人的にはもっと何年も前に欲しかったライブラリです。

最初はFletについて、ChatGPT Plusでも色々やってみようと思ったんです。でも全然ダメでした。まだ新しいライブラリなので、Chat GPTには情報がないようです。しれっとFlaskのコードを出してきたりしましたからね。

公式のドキュメントもQiitaの記事も、とてもわかりやすくて助かりました。

# 参考
https://qiita.com/NasuPanda/items/48849d7f925784d6b6a0

https://flet.dev/docs/controls/progressbar/
[Swift] 単色の CIImage を生成する方法

## 概要 

単色の CIImage を生成したい、という場面に遭遇したことがあったので、その際の知見を共有したいと思います。 


## 使うもの 


- [`CIImage(color:)`](https://developer.apple.com/documentation/coreimage/ciimage/1437947-init) 

これだけです。

## やり方 

```swift 
CIImage(color: someCIColor)
``` 

「ってやればいいんやろ、なんでこんなことで記事書くの？ｗ」 って思ったそこのあなた、ここがハマりポイントです。 

初期化しただけではサイズが 0 x 0 の画像が表示されてしまいます。 
(extent.size を print してみると、CGSize(width: 0, height: 0) が出力される)

なので、例えば 1920 x 1280 の単色の画像を生成したい場合は、 


```swift 
CIImage(color: someCIColor)
    .cropped(
        to: CGRect(
             origin: .zero,
             size: CGSize(
                 width: 1920,
                 height: 1280
             )
        )
    )

```

という風にクロップしてやる必要があります。不思議ですね👀 
(extent.size は .zero になってるけど実は .infinity な大きさなのかな？)


## 余談 

UIGraphicsImageRenderer を使って単色の UIImage を生成する方法もありますが、これは上記のやり方と比べると生成に要する時間が長いです。
GM6020を使う (PWM)

ハマったというか沼ったのでその記録

## 用意するもの
- GM6020
- Arduinoボード
    - 今回はArduino NanoとXIAO RP2040で試した。
- ジャンパー線
- 24Vを供給できる電源
    - https://akizukidenshi.com/catalog/g/gM-00409/
- 電源をXT30で引き出すための配線一式
    - https://akizukidenshi.com/catalog/g/gK-06998/##
- ハンダゴテ
- パソコン

## 配線方法
電源の方はなんかいい感じに繋ぐ。電源つけてLEDが緑色に付けばOK。

信号線は公式ドキュメントを参考にしてArduinoボードにジャンパー線等を使って配線する。(PWMピンはArduinoのデジタルピンだったら多分どこでもいい。)

![Screenshot 2023-05-13 at 11.48.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/c2ed6910-5fc4-04fe-1204-e23b68e529bb.png)



## プログラムを書き込む
Arduino IDEを下記からダウンロードしてインストールする。(2.0でもなんでもいい)

https://www.arduino.cc/en/software

このリポジトリをクローンする。(code > Download zipでダウンロードできる)

https://github.com/TakanoTaiga/GM6020_controller_by_RP2040

PWMフォルダの中にPWM.inoというファイルがあるのでそれをダブルクリックして開く。

開いたらファイルの先頭らへんにこのような記述があるので`D2`の部分を環境に合わせて適宜変える。XIAOだったら`D2`など、Arduino系だったら`2`とか数字を書く。
```c++
#define GM6020_PWM D2 // <-ここを適宜変える
```

ボードやシリアルポートを設定したらスケッチを書き込む。

## 動かす
その前に
モーター裏側のDIPスイッチの1~3番どれかをONにする。全部OFFだとモータは動かない。

![Screenshot 2023-05-13 at 12.02.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/237c7279-19f0-16ff-7bef-54bda38d65d6.png)

Arduinoを接続すればモータが回転し出すはず。(以下はモータが回っている様子の静止画)

![IMG_6563 Medium.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/25dad7a5-9faa-9c95-8c1c-7b1e0b028123.jpeg)
[Fresh 1.1.4~] twind v1を使用する方法

Fresh v1系では、twind v1 (Tailwind v3)を使用するためにファイルを手動で書き換える必要があります。

# Fresh

FreshはDeno社が作成・公開しているフロントエンドフレームワークです、

https://fresh.deno.dev/

# twind v1

[twind](https://twind.style/) は [Tailwind CSS](https://tailwindcss.com/) をJavaScriptから生成するようにしたものです。
SSRと組み合わせることで、転送量を小さくしつつ高速化することができます。

Freshには組み込みのtwindサポートが付属しています。ただし、これはtwind v0系に対するサポートです。twind v0ではTailwind 2.0(古いバージョン)にしか対応しておらず、Tailwindの最新の機能を使うことはできません。
Tailwind 3.x系(最新版)を使うには、twindをv1に切り替える必要があります。

Fresh v1.1.5には、一部のファイルを手動で書き換えることにより、twindをv1にアップグレードできる機能が実装されていますので、紹介したいと思います。

# ファイルを書き換えてtwind v1に対応する

freshプロジェクトを生成する際に、twindを使用するかどうかプロンプトで聞かれると思います。
その際に生成される`twind.config.ts`はtwind v0系列向けのファイルなので、これを書き換える形で対応していきます。

### main.ts

まず`main.ts`内のimport文、`$fresh/plugins/twind.ts`を`$fresh/plugins/twindv1.ts`に書き換えます。

```diff_tsx:main.ts
- import twindPlugin from "$fresh/plugins/twind.ts";
+ import twindPlugin from "$fresh/plugins/twindv1.ts";
```

### twind.config.ts

続いて、`twind.config.ts`を以下のように書き換えます。

```diff_tsx:twind.config.ts
- import { Options } from "$fresh/plugins/twind.ts";
+ import { Options } from "$fresh/plugins/twindv1.ts";
+ import { defineConfig, Preset } from "https://esm.sh/@twind/core@1.1.3";
+ import presetTailwind from "https://esm.sh/@twind/preset-tailwind@1.1.4";
  
  export default {
+   ...defineConfig({
+     presets: [presetTailwind() as Preset],
+   }),
    selfURL: import.meta.url,
  } as Options;
```

以上で完了です。

なお、おそらくimport文の`@twind/core@1.1.3`のところは、`$fresh/plugins/twindv1.ts`の内部で使用している@twind/coreとバージョンを合わせた方が良いと思います。（記事執筆時点では@1.1.3です。）

## Tailwind CSSのドキュメント

twind v0系を使用している場合、Tailwind CSSのドキュメントは[v2系](https://v2.tailwindcss.com/docs)を見る必要がありました。

https://v2.tailwindcss.com/docs


上記の手順を使用してtwind v1に切り替えた場合、Tailwind CSSは[v3系のドキュメント](https://tailwindcss.com/docs/installation)を見る必要があります。

https://tailwindcss.com/docs/installation

## まとめ

- Fresh v1系でtwind v1 (Tailwind v3)を使用するには、`main.ts`と`twind.config.ts`を手動で書き換える必要がある。

なお、今後Freshのメージャーアップデートのタイミング(Fresh 2.0)で、デフォルトがtwind v1に切り替わる予定のようです。

自分で書いていてバージョンがややこしかったので表にします。

|Freshのバージョン|対応するtwindのバージョン|対応するTailwind CSSのバージョン|
|--|--|--|
|v1.0系|v0系<br>(ただしFresh v1.1.4以降、ファイル手動書き換えでtwind v1に対応)|v2系<br>(twind v1を使用している場合はv3系)|
|v2.0系(予定)|v1系|v3系
AWS FISがEC2インスタンスのディスクフル実験をサポート

# はじめに
AWS のアップデートでAWS Fault Injection Simulator(AWS FIS)に新たな実験が追加されていました。

https://aws.amazon.com/jp/about-aws/whats-new/2023/04/aws-fault-injection-simulator-amazon-ec2-instance-disk-fill/

EC2のルートボリュームのdisk full状態をシミュレートできるようです。

AWS FISについては公式ドキュメントを参照ください。

https://aws.amazon.com/jp/fis/

# 試す
実際に実験テンプレートを作成し、実験を行って確認してみます。

## 前提
- EC2インスタンス(t2.micro)にアタッチされているEBSに対し、ディスク容量が90%となった場合を想定した実験を行う
- ディスク容量はCloud Watch Agentを導入し、モニタリングする 
    - 実験前のルートボリューム使用率は20%前後で推移しているよう
    - ![image_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/2e331178-81ca-6a5a-17a2-2f735e7e287b.png)

## 実験テンプレートの作成
実験テンプレートは「AWS FIS」→「実験テンプレートの作成」を選択して作成します。

### アクションの設定
- Disk Full実験のアクションタイプは「SSM」、ドキュメントは「aws:ssm:send-command/AWSFIS-Run-Disk-Fill」となります。
- その他パラメータは以下です。
    - Document ARN ：ドキュメントのARN、自動入力されている。
    - Document Parameters：ドキュメントに渡すパラメータ。下記のパラメータをjsonで記載する。
        - DurationSeconds：負荷をかける時間
        - InstallDependencies：必要な依存関係をinstallするか
        - Percent：ルートボリュームに何%までの負荷をかけるか
    - Document Version ：ドキュメントのバージョン。無記入でOK
    - Duration：SSM Commandをモニタする期間

```json:例
{"DurationSeconds":"600", "InstallDependencies":"True","Percent":"90"}
```
![image_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/0896dff3-1fb4-8b8f-f6a7-55beb3718be2.png)


### ターゲットの設定
上記アクションを作成すると、「Instance-Target-1」というターゲットが作成されていると思います。
「ターゲットの編集」から、負荷をかけるインスタンスを選択します。
ターゲットメソッドをリソースIDとし、対象のインスタンスIDを選択しました。

![image_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/ed621c6b-3147-6c2d-805f-5c3a0e6a2960.png)


後はロールを自動作成し、実験テンプレートを作成します。

## 実験の実施

AWS FISのコンソールから実験を開始できます。
上記で作成した実験テンプレートを選択し、「実験を開始」を押下します。
![image_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/53912666-ef5b-5c05-0845-be882fb3b195.png)


実験開始後、CloudWatchを確認すると90%に到達していることが分かります。
![image_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/2331d419-5c47-b6f1-0b0d-8083887932c8.png)

約10分後、実験が終了しメトリクス値が元に戻っていました。

# おわりに
簡単ですが、追加された実験を試してみました。
EC2ルートボリュームのディスクフル状態を確認したい場合は利用したいと思います。
crontabでユーザ環境変数を反映したい

# はじめに

ユーザ環境変数を参照するプログラムを作りcrontabで実行しようとしたところ、環境変数が未定義でエラーとなってしまいました...。crontabでジョブを実行する場合は、ユーザの環境変数が反映されないようです。これは結構盲点で困りました...
何とか解決できたので、本記事で「crontabを使う際にもユーザ環境変数を反映する方法」をご紹介します。

:::note info
動作確認OSは Ubuntu 22.04 のみですが、少なくともDebian系のディストリビューションであれば本記事の内容が使えると思います。
:::

# crontabでユーザ環境変数が反映されない現象の確認

まずはユーザ名 ``user`` で定義されている環境変数を確認してみます。

```
$ env
SHELL=/bin/bash
HOSTNAME=0996dae4f85d
PWD=/home/user
LOGNAME=user
HOME=/home/user
LS_COLORS=rs=0:di=01;34:ln=01;...(出力省略)
TERM=xterm
USER=user
SHLVL=2
PATH=/usr/local/sbin:/usr/local/bin:..(出力省略)
MAIL=/var/mail/user
_=/usr/bin/env
OLDPWD=/
```
全部で12個の環境変数があります。
```
$ env | wc -l
12
```

次にcrontabでも同様に``env``を実行してファイル出力して確認してみましょう。
``crontab -e``で以下の1行を追加します。

```
* * * * * env > /home/user/env_crontab.txt
```

最大1分待って出力結果を見てみます。

```
$ cat ~/env_crontab.txt
HOME=/home/user
LOGNAME=user
PATH=/usr/bin:/bin
SHELL=/bin/sh
PWD=/home/user
```

あれ？  **環境変数は12個あるはずなのに、crontab経由で実行した場合は5個しか環境変数がありません。** これはどうしたものか...

# 解決策

次の手順で解決できました。
* (1) ユーザ環境変数をexportするスクリプトを作成する
* (2) 作成したスクリプトをcrontabの主ジョブを実行する前に``source``コマンドで反映する

以下に具体的に説明します。

## (1) ユーザ環境変数をexportするスクリプトを作成する

まずはユーザ環境変数を読み込むためのスクリプトを作成します

```
env | grep -v LS_COLOR | awk '{ print "export " $0 }' \
> /path/to/export-env
```
念のため確認すると、``export``コマンドで環境変数を設定するスクリプトができています。
```
$ cat /path/to/export-env
export SHELL=/bin/bash
export HOSTNAME=0996dae4f85d
...（出力省略）
export MAIL=/var/mail/user
export _=/usr/bin/env
```

スクリプトが動くかを以下のコマンドで確認し、何も表示されなければOKです。

```
source /path/to/export-env
```

:::note info
``/path/to/export-env``を作る際に``grep -v``で``LS_COLOR``の環境変数出力を除外しているのは、今回試した環境だと``LS_COLOR``の値に「;」が含まれていて、``source /path/to/export-env``コマンドを実行するとエラーになるためです。このエラーは``LS_COLOR``の値をダブルクオートで囲むと無くなりますが、「``LS_COLOR``は使わない」前提で``grep -v``で回避しています。
:::

## (2) 作成したスクリプトをcrontabの主ジョブを実行する前に``source``コマンドで反映する

``crontab -e``で次の2行を追加します。

```
SHELL=/bin/bash
* * * * * source /path/to/export-env && env > /home/user/env_crontab.txt
```

* 1行目 : ``SHELL=/bin/bash``
    * crontabのデフォルトはshで実行されてsourceコマンドが使えないため、bashを使うように変更します
* 2行目
    * メインのコマンドを実行する前に``source /path/to/export-env``を追加します

## 結果確認

最大1分待って出力結果を見ると、ユーザ環境変数と（``LS_COLOR``以外は）おおよそ同じになっていることを確認できます。

```
$ cat /home/user/env_crontab.txt
SHELL=/bin/bash
HOSTNAME=0996dae4f85d
PWD=/
LOGNAME=user
HOME=/home/user
TERM=xterm
USER=user
SHLVL=0
PATH=/usr/local/sbin:/usr/local/bin:..(出力省略)
MAIL=/var/mail/user
OLDPWD=/
_=/usr/bin/env
```
## [参考] /etc/environment に追加する方法

実は上のようのことをしなくても``/etc/environment``に次のコマンドでユーザ環境変数を追加すると簡単に解決します。

```
env | sudo tee -a /etc/environment > /dev/null
```

ところがこのやり方だと全ユーザに``user``（今回の場合）の環境変数が設定されてしまうため、あまりおすすめできないです。（特に複数ユーザで環境を使っている場合はこの方法は避けた方がいいです）

# 参考情報

https://www.baeldung.com/linux/load-env-variables-in-cron-job
SalesforceのHelp(SalesforceConnect制限、XXチーム、大規模プラットフォームイベントの制限）


#### SalesforceConnect
ポイント①：1時間あたりのCallOutは2万回（緩和はサポートに要相談）
ポイント②：1時間あたりの新規に取得できる行は10万（レポートなどを使わない選択をすればこの制限は撤廃可能だが、ポイント①の制限はいずれにせよ撤廃されない。）

https://help.salesforce.com/s/articleView?id=sf.platform_connect_general_limits.htm&type=5

上記制限に関する理解。
（１）以下ですが、Unlimited Editionでは、1時間あたり2万回CallOutできる（＝つまり利用者がSalesforceConnectの画面を2万回開ける）と理解しましたが、認識あってますか？SalesforceConnect画面を1回開くと、1度CallOutされる認識です。
> o Enterprise Edition、Performance Edition、および Unlimited Edition では、1 時間あたり 20,000 個の OData コールアウト。制限の緩和が必要な場合は、サポートケースを作成します。
　→Yes

（２）以下２つの制限ですが、CallOut数ではなく、CallOutした結果の行数に対しての制限と理解しましたが、あってますでしょうか。
> 1 時間あたりに SOSL 検索および Salesforce 検索で取得される新しい行の最大数。 100,000 
> この制限は、大量データの外部データソースには適用されません。  
> 1 時間あたりに取得または作成される新しい行の最大数。 100,000 
> この制限は次には適用されません。 
> • 大量データの外部データソース 
> • 検索結果としてのみ取得され、開いたり編集されたりしない行 
> • その他、以前に取得された行
例えば、1時間あたり2万人がSalesforceConnectの画面を開き（＝CallOutを行い）、その際に1人あたり新規に6件ずつ取得していた場合、1時間あたり12万件の行数となるため、制限に抵触。
　→Yes（補足：あくまでも「新規」に取得された最大行数の制限。以前に検索結果として表示させたデータを再表示する場合にはカウント対象外。Salesforce Connect で接続先のデータを Salesforce 側で初回表示させる件数の上限が 1 時間に 10 万件まで。）

> （３）以下を読むと、「大量データの外部データソース」であれば、レポートなどが使えなくなるものの、1時間10万行という制限は撤廃されますが、以下を使ったとしても1時間あたり2万回のコールアウト制限は変わらないのでしょうか？ 
> [Salesforce Connect — カスタムアダプタでの高データボリュームの考慮事項] 
> https://help.salesforce.com/s/articleView?id=sf.apex_considerations_high_data_volume.htm&type=5 

→Yes（2万回のコールアウトの制限は継続）

#### XXチームの権限
ポイント①：所有者が任意のユーザに共有ボタンから権限付与した場合、所有者が変われば任意のユーザへも付与した権限がはく奪されるが、取引先チームの場合、Optionではく奪するか否かが選べる。
ポイント②：取引先チームの権限付与は、所有者、および上位ロール

・取引先チームなど追加できるのは、所有者、およびその上位ロール
・所有者が変わった場合、標準機能では基本的に所有者が付与した権限がはがれるが、取引先チームなどの場合には、剥がすか否かOptionで指定できる。
※ちなみにApexSharingで付与した権限は所有者が変わっても剝がれない。

>所有者の変更時に取引先を持つ取引先チームメンバーを保持するには、[現在の取引先チームをそのまま使用する] を選択します。 
>チームを削除するには、このオプションを選択解除します。 
このアクションは、Salesforce システム管理者、取引先所有者、またはロール階層内のそれより上位のユーザが追加したチームメンバーにのみ適用されます。 
>[現在の取引先チームをそのまま使用する] が選択されている場合でも、グループベースのアクセス権を持つユーザが追加したチームメンバーは削除されます。 
>取引先所有者の変更時に商談を持つ商談チームメンバーを保持するには、[移行される商談を持つ商談チームをそのまま使用する] を選択します。チームを削除するには、このオプションを選択解除します。


https://help.salesforce.com/s/articleViewid=sf.account_owner_transfer.htm&type=5


#### 大規模プラットフォームイベント

https://developer.salesforce.com/docs/atlas.ja-jp.platform_events.meta/platform_events/platform_event_limits.htm

前提：Salesforce側でフローやApexなどイベントを生成する。ESBはCometDを使い、それをリスン(subscribe)し、後続処理に進む前提とする。 
イベント配信とイベント公開の差が分からないため、ご教示ください。
（制限は、どこの処理を指しているのでしょうか？） 

（１）【イベント配信】以下は、Salesforceで作成されるプラットフォームイベントの1レコードに対する制限であってますか？ 
ex)1時間あたり、2つのCometDにバスから配信、10件プラットフォームイベントを生成したら10としてカウント。＝イベント配信 

>イベント配信: 配信され、すべてのクライアントで共有されるイベント通知のエンタイトルメント。(CometD および Pub/Sub API クライアント、empApi Lightning コンポーネント、イベントリレーにのみ適用されます。) 

→Yes

（２） 【イベント公開】以下は、Salesforceで作成されるプラットフォームイベントの1レコードに対する制限であってますか？ 
ex)1時間あたり、2つのCometDにバスから配信、10件プラットフォームイベントを生成したら20としてカウント。＝イベント公開 

> イベント公開: 公開されるイベント通知の 1 時間あたりの最大数。(Apex、Pub/Sub API とその他の API、フロー、プロセスビルダープロセスなど、すべての公開メソッドに適用されます。)

→Yes

イメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/450298/5cd69336-dde0-afde-a7a7-9a80110716f5.png)
AWSのLambdaに関数を作成する：S3を更新したとき、キャッシュクリアを自動で行う

AWSのS3を更新した際にCloudFrontのキャッシュクリアを自動で行う関数をLambdaに作成します。

<b>Lambda</b>とは
AWSの公式ドキュメントによると「サーバーをプロビジョニングまたは管理せずにコードを実行できるようにするコンピューティングサービス」とあります。
要約すると、AWSの他のサービスをトリガーとしてクラウド上に定義したプログラムを実行するようにできるサービスです。
今回は「S3の更新」がトリガー、「CloudFrontのキャッシュのクリア」がプログラム（関数）になります。

以下、作業の流れを記述します。

1.AWSのLambdaに移動し、「関数の作成」をクリック
![スクリーンショット (168).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/33cdc84c-0e70-2a2e-8792-fa0821a4f11b.png)

2.関数の情報を入力します。今回は関数名を「remove-cache」とします。今回関数はPythonで記述しますのでランタイムは「Python3.9」を選択し、アーキテクチャは「arm64」を選択します。
![スクリーンショット (169).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/8fefe180-bcb6-1ac3-f2ea-be888e52a446.png)

3.まだ何も設定されていない関数ができます。左にある「トリガーを追加」をクリックします。
![スクリーンショット (170).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/e59342e1-69ba-c540-f01c-43c9b73cae4c.jpeg)

4.S3を選択し、自動キャッシュクリアを適用したいバケットを入力します。イベントタイプは「すべてのオブジェクト作成イベント」を選択します。その他の項目はそのままで、最下部のチェックボックスにチェックを入れ「追加」をクリックします。
![スクリーンショット (171).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/5539013b-3932-ac22-fe6b-184ae4f11e6c.png)

5.S3と関数の紐づけができました。
![スクリーンショット (172).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/fc153319-a700-b5ae-aea3-a8e544f75c12.jpeg)

6.ページ下部のタブから「設定」を開き、「ロール名」のリンクをクリックします。
![スクリーンショット (173).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/73dcf212-57bf-aa10-a38e-378b910e83b8.jpeg)

7.「CloudFrontFullAccess」を選択します。これで関数のロールにポリシーがアタッチされ、関数がS3を参照できるようになります。
![スクリーンショット (174).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/4e2944f3-2325-2f5d-ab9d-823dcee35353.png)

8.Lambdaに戻り、「コード」のタブからキャッシュクリアのコードを記述します。【対象のディストリビューションID】は、CloudFrontで確認してください。
![スクリーンショット (175).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/15b02649-5f10-ea29-5e5a-a6ad34425986.png)
```
from __future__ import print_function

import boto3
import time

def lambda_handler(event, context):
    client = boto3.client('cloudfront')
    invalidation = client.create_invalidation(DistributionId='【対象のディストリビューションID】',
        InvalidationBatch={
            'Paths': {
                'Quantity': 1,
                'Items': ['/*']
            },
        'CallerReference': str(time.time())
    })
```

9.「Test」をクリックし、正常に動作すると「Execution results」が作成されます。CloudFrontでもキャッシュクリアが行われたことが確認できます。
実際にS3を更新してみても同じくキャッシュクリアが確認できれば成功です。（CloudFront>ディストリビューション>ディストリビューションID内の「キャッシュ削除」タブから確認できます。）


上記を適用したサイト
https://www.owl-light.net/
遷移ボタンを作るコードの仕組みを知る（前編）

# はじめに
こんにちは。Qiita株式会社で主に[Qiita Zine](https://zine.qiita.com/)の記事制作を担当しています。非エンジニアです。記事やサイトは見るのも作るのも好きで、そこからHTMLやCSSに興味を持って調べるなどして、少し勉強しています。

## ボタンを作ってもらう
さて今回は、サイトを見ていると大抵ある遷移ボタンのデザインがどのような仕組みでできているのかを調べます。Chat GPT先生にコードを教えてもらって、そのコードをいじって、仕組みを知るという流れ。

# HTMLのコードを教えてもらう
私「シンプルでかっこいい遷移ボタンを教えて」
Chat GPT「どうぞ」

```index.html
<html>
<head>
  <style>
    /* スタイルの設定 */
    .transition-button {
      display: inline-block;
      padding: 10px 20px;
      background-color: #000;
      color: #fff;
      text-decoration: none;
      border-radius: 4px;
      transition: background-color 0.3s ease;
    }

    .transition-button:hover {
      background-color: #333;
    }
  </style>
</head>
<body>
  <!-- ボタンの表示 -->
  <a href="遷移先のURL" class="transition-button">遷移する</a>
</body>
</html>
```

## どのような見た目か表示させる
シミュレーションサイトで上のコードを入力し、どのような見た目になるか教えてもらいます。こちら。
![コード.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3003649/c5410393-6957-7fc5-046b-2886b882ab58.jpeg)

指定した「シンプルでかっこいい」、なかなか的を射ていますね。もう完成で良いやと思ってしまいますが、それでは勉強にならないので変更してみます。

## コードを見てみる
### （雑談）
少し話が逸れますが、これまで記事を作るときはすでにあるコードの中身を変更しながらだったので、指定している内容は分かるけれど大枠はなんとなくしか分からないです。例えば上のコードも、 `<style>`タグの中にCSSで見るコードを入れているのはなぜ、って。こちらはのちのち勉強します。

## `display` って何
さっそく何を意味するのか分からないプロパティが。`display`て何。調べてみるとCSSで使われるプロパティの1つで、大まかに言うと要素の表示形式を決めるものだそう。（参考：[サルワカ](https://saruwakakun.com/html-css/basic/display)）

で、今回の値は`inline-block`。これも調べると、まず`block`と`inline`という値があって、それらが組み合わさっているような内容ですね。「横に並べるボタンないから`block`だけでも良いんじゃないの？」と思ったので、`inline-block`を`block`に変更してみます。するとこうなった。
![テスト.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3003649/84705555-b6dd-1518-3a0c-b994a1948c8d.jpeg)
超横長、これはダメだ。`inline-block`に戻します。


## `padding`
続いては`padding`。これは分かるぞ、上下左右の「何か」を変更するプロパティだ。けれどどこが変わるのかは分からない。上下の余白かな、そしたら今回変更しても分からないんじゃ...？と思いつつも、変更してみます。違いが分かりやすいように大袈裟に。

`10px 20px`を`50px 20px`に。
![テスト２.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3003649/0542afb4-a9b3-6eea-777a-e4b817226493.jpeg)
なるほど、ボタンの上下幅を指定していたのか。ということは`20px`を変更したら、横幅が変わるということ。実際変更したらその通りでしたので、見た目は割愛。


## 色の指定
色指定の仕組みは理解していますのでまとめて。

`background-color`は背景色を、`color`は文字色を指定するもの。せっかくなので変更します。[色コードを紹介してくれているサイト](https://www.colordic.org/)へ行き、「どれが良いかな...もうすぐ夏じゃん、海へ行きたい」と思ったので、海っぽい色をチョイス。

darkturquoise`#00ced1`にしました。ついでにテキストも変更。
![テスト4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3003649/fb6d8c74-fd60-91cd-75d1-12ead3fb8695.jpeg)

海を見たくなりました。

## 前編おわり
長くなるので前編後編に分けます。後編書いたらリンク貼ります。
useStateとは

useStateとは、ReactのHooksの1つで、関数コンポーネントで状態を管理するためのものです。
状態（state）とは、コンポーネントが内部で保持するデータであり、文字列、数値、真偽値、配列など様々な型の値を保持することができます。

useStateは2つの値をもっており、一つが現在の状態の値を表す変数です。2つ目が状態を更新するための関数です。この関数を呼び出すことで、新しい状態の値をセットすることができます。

例えば以下のように、ボタンをクリックするたびにcountの値が1ずつ増加するというプログラムだった場合はこのように記述します。

```jsx
import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  function handleIncrement() {
    setCount(count + 1);
  }

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleIncrement}>+1</button>
    </div>
  );
}
```

ここではuseStateの初期値に0を渡しています。
そして、setCount関数を呼び出すことで、countの変数の値がプラス1されるというものです。またhandleIncrement関数はbuttonが押されてたときに呼び出されます。

このように、useStateを使うことで、状態を管理することができます。
Reactの仮想DOMを使って、実際のDOMと比較して状態の差分を計算し、差分だけページを更新することで、Reactの特徴である動的なUIなどを作成することができます。ですので、useStateを使用しない場合は、このようなReactの特徴を活かすことが難しくなります。
RaspberryPiとWindowsPC/スマホをSambaでファイルを共有する

ハードディスクのマウント設定は[ここ](https://qiita.com/akeyi2018/items/493ebed0dbf9d008d7ed)
### sambaのインストール
RaspberryPiにSambaをインストールする
```terminal
$ apt install samba
```

Sambaの設定ファイルを編集する（元に戻せるようにバックアップを作成しておく）
```terminal
$ sudo cp /etc/samba/smb.conf /etc/samba/smb.conf_bk
$ sudo nano /etc/samba/smb.conf

# 設定ファイルに以下を追加
[pi]
path= /mnt/hdd
read only = No
guest ok=Yes
force user = pi
```

[pi] :共通フォルダ名
path: HDDのマウント位置
guest ok: ゲストユーザのアクセスを許可する
force user:強制的にpiというユーザでアクセスする

---
### Samba起動状態を確認し、再起動します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/d7f52f87-91aa-8d5a-ef5f-ddc896593985.png)

Active: active(running)になっていたら動いている状態になります.
以下のコマンドで再起動する

```terminal
 $ sudo systemctl restart smbd
```
### WindowsPCからアクセスする
ネットワークドライブの割り当て

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/036277e6-8909-bc81-784a-fae3cf10369e.png)

以下のようにフォルダにアクセスできれば、成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/b55741b1-f66c-92a4-1df2-7873a485edca.png)

スマホの場合は、以下のようになっていればOK

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/092f98ae-a60f-006a-5ba5-13c834681269.png)

### ユーザパスワードでログインさせる
<b>※上記の設定だとセキュリティがスカスカなので、sambaにアクセスするユーザを登録します。
```terminal
# samba設定ファイルを変数して、guest ok = Noにする
$ sudo nano /etc/samba/smb.conf
guest ok=No
# ユーザを登録する（Linuxに存在するユーザでないとエラーになるので注意）
pi@raspberrypi:~ $ sudo pdbedit -a pi
new password:
retype new password:
# Sambaを再起動する
sudo systemctl restart smbd
```
スマホとの共有は以下がお勧めです。

https://nj-clucker.com/explorer-app-file-manager/
required program bossac not foundエラー

# 事象

`west flash`を実行したときに`FATAL ERROR: required program bossac not found; install it or add its location to PATH`というエラーが発生する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109634/6047a7ba-6e23-d667-a872-8fd33a749964.png)

# 原因

bossacがZephyrの依存ツール群に含まれていない。（bossacのインストールが必要）

# 解決方法

1. BOSSAの最新をインストールする
[shumatech/BOSSA/releases](https://github.com/shumatech/BOSSA/releases)にある最新の.msiをインストールする。（例えば、bossa-x64-1.9.1.msi）

1. `west flash -r bossac --bossac="C:\Program Files (x86)\BOSSA\bossac.exe" --bossac-port="COMx"`を実行する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109634/d873510e-e729-4dd4-157f-d5ea06c523cc.png)

# 参考

* [Enabling BOSSAC on Windows Native [Experimental]](https://docs.zephyrproject.org/latest/develop/flash_debug/host-tools.html#enabling-bossac-on-windows-native-experimental)
Androidタブレットで展示したい！Page Slideshowをつくりました！

p5.jsで作った作品例を展示する機会をいただきましたので、Androidタブレットで展示をするためのアプリとWebページをまるまる切り替えるスライドショーを作りました。
（アプリのロックは[App pinning](https://support.google.com/android/answer/9455138?hl=ja)を使う前提程度のものです。）

# 全画面表示のブラウザアプリのテンプレート
https://github.com/shibomb/kioskBrowserAndroid

（今のところ）ソースに固定で記述されたURLをフル画面で表示するだけです。
AndroidStudio Kotlin

# 画像やWebサイトをスライドショーするサイトのテンプレート
https://github.com/shibomb/page-slideshow

（今のところ）ソースに固定で記述された複数のURLのWebページを、一定間隔で表示切り替えします。

**サンプル**

https://page-slideshow.pages.dev/

VisualStudioCode Vue3 Vuetify3

---
MIT LICENSE
Copyright (c) 2023 shibomb
Googleドキュメントを自動で複製するGASスクリプトをChatGPTにつくらせた記録

# 概要
もともとこういう楽ちん系のスクリプトはよく作っていたんですが、それもGPTにやってもらうことが増えました。
出来上がり自体はまあまあ便利なので、投げた質問と合わせて記録しておきます。

# 準備するもの
* Googleアカウント
* ChatGPTアカウント

# 投げた質問

## 最初の指示
![2023-05-13_09h56_44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215128/bb8328bf-b9a8-5cbf-aa71-7fc385e945ef.png)

## ちょっとカスタマイズ
![2023-05-13_09h56_54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215128/d5fb3e57-c38e-ae93-1d5c-30eb5b07afac.png)

![2023-05-13_09h57_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215128/3517b71e-b166-01bd-2f94-df6f1e177bfe.png)

## リファクタリングぽいこと
![2023-05-13_09h57_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215128/5c2b8501-4628-745b-a210-d3de7247c601.png)


# できあがりスクリプト

```javascript
const TEMPLATE_ID = 'テンプレートファイルのIDをここに入力';
const DESTINATION_FOLDER_ID = '複製先のフォルダのIDをここに入力';

function copyAndReplaceDocument() {
  const template = DriveApp.getFileById(TEMPLATE_ID);
  const newDocumentFile = duplicateFile(template);
  moveFileToFolder(newDocumentFile, DESTINATION_FOLDER_ID);
  copyFilePermissions(template, newDocumentFile);
  replaceDateInDocument(newDocumentFile);
  logNewDocumentUrl(newDocumentFile);
}

function duplicateFile(file) {
  return file.makeCopy();
}

function moveFileToFolder(file, folderId) {
  const destinationFolder = DriveApp.getFolderById(folderId);
  destinationFolder.addFile(file);
  DriveApp.getRootFolder().removeFile(file);
}

function copyFilePermissions(srcFile, destFile) {
  const viewers = srcFile.getViewers();
  viewers.forEach(viewer => {
    destFile.addViewers(viewer);
  });

  const editors = srcFile.getEditors();
  editors.forEach(editor => {
    destFile.addEditor(editor);
  });
}

function replaceDateInDocument(file) {
  const doc = DocumentApp.openById(file.getId());
  const body = doc.getBody();
  const currentDate = Utilities.formatDate(new Date(), 'JST', 'yyyy/MM/dd');
  body.replaceText('{{作成日付}}', currentDate);
}

function logNewDocumentUrl(file) {
  const newDocumentUrl = 'https://docs.google.com/document/d/' + file.getId();
  Logger.log('新しいドキュメントのURL: ' + newDocumentUrl);
}

```

# 終わりに

この使い方は、どちらかというとエンジニアじゃなくて営業系のマネージャーとかでエクセル使いこなしてる人がやったらいいと思うんですよね。

# おまけ

作成させてる動画を上げてみました。

https://www.tiktok.com/@engineerwadkn/video/7232570894512622849
アダルトサイトソクミルのAPIクライアントgem "ruby_sokmil" を公開しました

# はじめに

https://qiita.com/dugabot0/items/734b145f7e884f3cd17e

こちらの記事で、アダルトサイトDUGAのAPIクライアントgem、"ruby_duga"を作成、公開したことをご報告しました。

ついでにアダルトサイト[ソクミル](https://www.sokmil.com/av/?ref=header&affi=20131-001&utm_source=sokmil_ad&utm_medium=affiliate&utm_campaign=20131-001)のAPIクライアントgemを公開したので、ご報告したいと思います。

https://rubygems.org/gems/ruby_sokmil

# 使用方法

https://github.com/dugabot0/ruby_sokmil

## インストール

    $ gem install ruby_sokmil

## 利用例

```ruby
require 'ruby_sokmil'

cli = RubySokmil.new(api_key: "YOUR_API_KEY", affiliate_id: "YOUR_AFFILIATE_ID")
response = cli.item(keyword: "杉原杏璃", category: 'idol')
response.body[:result][:items].map {|x| x[:title]}
=>
["Last Kiss ～杉原杏璃ファイナルイメージ 杉原杏璃",
 "東京アンリ 杉原杏璃",
 "となりのアンリ 杉原杏璃",
 "白珠杏蜜 杉原杏璃",
 "アンリ先生 杉原杏璃",
 "フェアリー・テール 杉原杏璃",
 "なまアンリ、ゆめアンリ 杉原杏璃",
 "アンリの日記 杉原杏璃",
 "必撮！まるごと☆杉原杏璃2",
 "杏乳 杉原杏璃",
 "ヤングマガジンDVD 透覗 See Through Mode 杉原杏璃",
 "杏limited 杉原杏璃",
 "亜細亜の恋 杉原杏璃",
 "夢の世界へ 杉原杏璃",
 "杏璃～夏ものがたり 杉原杏璃",
 "じーっとみつめて･･･ 杉原杏璃",
 "必撮！まるごと☆杉原杏璃",
 "ボクのアンリ 杉原杏璃",
 "アンブロシア ～美味しいアンリ 杉原杏璃",
 "みすど mis＊dol 杉原杏璃2",
 "杏Lover 杉原杏璃",
 "みすど mis＊dol 杉原杏璃",
 "本当にデカップ 杉原杏璃",
 "杏Sweet 杉原杏璃",
 "杏璃色 杉原杏璃",
 "「杏蜜」 ～An-mitsu～ 杉原杏璃"]
```

<sub>メインの使い方は`category: 'av'`です。各自試してみてください。</sub>

環境変数に`SOKMIL_API_KEY`、`SOKMIL_AFFILIATE_ID`を指定すれば、`RubyDuga.new`の際に、`api_key`、`affiliate_id`を指定する必要はありません。

クライアントに渡すリクエストパラメータ、レスポンスフィールドの詳細については[Sokmil](https://sokmil-ad.com/member/api)の「WEBサービス」を参照してください。

商品検索、メーカー検索、レーベル検索、シリーズ検索、ジャンル検索、監督検索、出演者検索に対応しています。

レーベル検索とシリーズ検索はDATABASE_ERRORが返ってくるので、ソクミルのサーバー側で動いてない気がしています。

```ruby
require 'ruby_sokmil'

cli = RubySokmil.new(api_key: "YOUR_API_KEY", affiliate_id: "YOUR_AFFILIATE_ID")
response = cli.item(keyword: "杉原杏璃", category: 'idol')
cli.item(args)      # 商品検索
cli.maker(args)     # メーカー検索
cli.genre(args)     # ジャンル検索
cli.director(args)  # 監督検索
cli.actor(args)     # 出演者検索
```

# さいごに

ご要望、不具合などがありましたら、ここかGitHubでお願いします。
SPN重複について調べてみた。

SPNが重複していることが職場であった件を調べてみたら記事を見つけたので、忘備録としてメモ。
重複したのはコンピュータ、ドメインに参加できていない。

１　環　境
（１）　Windows2012以降
（２）　ActiveDirectoryが機能している。
（３）　ドメイン管理者の権限をもっている。

２　原因の推定（解決策）
（１）ＳＰＮの重複
　　　コンピュータにＳＰＮ名が複数登録されたため、コンピュータをサーバで特定する必要がある。
　　（特定後、重複したＳＰＮの削除 or 重複が発生したコンピュータを一旦削除し、登録する必要がある。）
（２）端末名を誤ってドメインに参加したため、重複が起きている
　　　（端末をＩＰアドレス等から特定し、ホスト名の変更、ドメインの再加入、誤って登録した際に記録された
　　ＳＰＮの削除。）
　　　


単純な重複を見つける方法
コマンドプロンプトを起動して以下のコマンドを入力
```setspn -X```
上記の重複から関連づけられているアカウントを検索
```setspn -L computername```

ADに参加したコンピュータのIPアドレスを調べる方法はこちらＩＰアドレスから逆引きして登録された端末を特定する。
Powershell
```Get-ADComputer -Filter "computername" -Properties * ```

結　果
ドメインサーバにログイン後、setspn -Xを入力するも目的のコンピュータの重複は表示されなかった。
しかし、setspn -L "computername"コマンドで確認すると、複数のSPNが確認できた。
ADに参加した端末を確認した結果、ＩＰアドレスに問題はなかった。

その後、ActiveDirectory管理ツールを起動し、そこから端末の属性エディターに
あるSPN内の重複部分を削除、その後、端末のリセットを行い無事端末リセット完了した。
[Docker]Dockerの概要

# Dockerとは?
Dockerを一言で表せば、「データやプログラムを隔離できる」仕組みのことを言います。パソコンとサーバーは複数のプログラムが動いています。例えば、パソコンではExcelやWordなどのソフトウェアがあり、サーバーにはApachやMySQLといったソフトウェアが存在します。これらのプログラムをそれぞれの環境に隔離することができます。また、これらのデータやプログラムなどを隔離したものをコンテナと呼びます。

通常、コンテナはそのコンテナの中にあるデータだけを利用できますが、別のコンテナの中にあるデータや、Dockerホストのデータを利用することはできません。コンテナはファイルやディレクトリを隔離するだけではなく、プロセスやネットワークなども隔離してくれます。隔離性を高めることには、Dockerホストなど周辺環境への依存度を低下させるなど、様々な利点があります。

# Dockerの仕組み
Dockerを使うにはいくつかの制限があります。それは、WindowsでもMacでもDockerを使うことが可能ですが、Linuxが必要になることです。これはDockerはLinux OSを使うことを前提に開発されているため、別途Linux環境が必要になります。
また、Dockerを使うにもまずは、Docker Engineをインストールしなければなりません。このエンジンはコンテナの作成や移動を実現してくれます。

(イメージ図)
![Docker.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790379/643e4137-13e4-af02-5596-1b7fe235a679.png)


# コンテナとイメージ
コンテナの作成する時には、コンテナの素となるイメージを作成します。イメージを素にエンジン上に複数のコンテナを配置することが可能です。また、逆も然りでコンテナからイメージを作成することができます。このメリットは、もし複数のコンテナを作ってそのコンテナ分改造を加えたい場合は、すべてのコンテナに対して手を加える必要があります。しかし、コンテナからイメージを作成できることによって、コンテナから新しいイメージを作成した後に、そのイメージを元に改造した複数のコンテナを複製できるため、大量のサーバーを作る作業が格段に楽になります。

(イメージ図)
![Dcoker_image-ページ2.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790379/f44a2203-efcb-c6fd-3ec4-d8b010bc5d60.png)

イメージは一から作ることもできますが、よく使われるイメージはDocker Hubにすでに作成されたイメージを配布しているため、そこから利用するのが一般的です。またコンテナは、自分でカスタムすることもできます。

https://hub.docker.com/

## Dockerのライフサイクル
Dockerのコンテナは長く使うのではなく、作っては捨てるという使い方が一般的です。

作成 => 起動 => 停止 => 破棄  (ライフサイクル)

1つのコンテナそのまま使い続けるのではなく、どんどんアップデートされたソフトウェアを入れていき、新しいバージョンのコンテナに乗り換えていきます。前述した通り、一つずつコンテナを改良していくのではなく、新たなイメージを作成した後にアップデートしたコンテナを複数作成していきます。

### データの保存
前述通り、コンテナはライフサイクルがあり、作っては捨てるのが原則であると説明しました。では、捨てたコンテナのデータはどうなるのでしょうか?当然コンテナを破棄すると中身のデータは消えてしまいます。そこで、データを削除しないように、大概はDockerをインストールしている物理的なマシーンのディスク(HDDやSSD)にデータを書き込むことが一般的です。このデータをディスクに書き込むことを、「マウント」と呼びます。


# Dockerの始め方
上述した通り、Dockerを使うには、Linux OSとDocker Engineの2つの環境が必要です。WindowsやMacを使っている人がDockerを使うには、2つの方法があります。

まず一つはデスクトップ版のDockerを使う方法です。これは、Docker EngineとLinux OSがパッケージになっているものをWindows版とMac用に提供しているサービスのことで、このソフトを入れることによってDockerの環境を簡単に構築できます。

https://www.docker.com/products/docker-desktop/

2つ目は独自のPCに仮想環境を構築した後に、Docker EngineとLinux OSをそれぞれインストールして環境構築する方法になります。仮想環境には、Virtual BoxやVMwareといったソフトウェアなどがあります。

# 参考

Docker & Kubernetesのきほんのきほん   マイナビ出版

https://www.ogis-ri.co.jp/otc/hiroba/technical/docker/part7.html
4日間連続で記事を投稿しての振り返り

# 結論
4日間投稿しただけでも自分に変化がありました。

# はじめに
5/9～5/12まで4日連続でQiitaに記事を投稿してきました。
この記事で5日連続になります。
- 5/9

https://qiita.com/76r6qo698/items/0e09996dcf6446ab5d0d

- 5/10

https://qiita.com/76r6qo698/items/a32f8fda3594f5952b71

- 5/11

https://qiita.com/76r6qo698/items/c4232925b53834b65c58

- 5/12

https://qiita.com/76r6qo698/items/30470bcaf585ab1e54eb

# 振り返り
記事を投稿し続けてみようと5/9から今日まで1記事づつ投稿してきたわけですが、それだけでも自分に変化がありました。

### 記事のネタを探すようになった
何か記事になるようなことはないか探しながらPC作業をするようになりました。自分にとって少しでも学びになることがあったかという観点で探すようにしています。

### 記事を投稿する対する抵抗がなくなってきている
記事を投稿する前は、どうしても投稿に対しての不安・抵抗が出てきます。
私の場合、以下の点で投稿への抵抗が出ていたと思います。
- あくまで人1人が書いた記事だし、調べれば同じような内容でよりクオリティの高い記事がすぐに見つかるだろう。
- 浅い理解のまま投稿してそうで、正確性を欠いているかもしれない。
- よりよい解決策が他にもあるだろう。

ただ、毎日連続となるとそうもいってられなくなりました。
結果的に抵抗感は少しずつなくなってきているように感じます。

# これから
連続投稿を続けるように頑張ります。
100日間連続を目標に、そうでなくても100記事書くことをやり抜きたいです！
PowershellでCannot index into a null arrayというエラーが出た

# 背景

powershellで配列を使用してコードを作成していました。
ファイルの中身は以下の通りです。


```join.ps1
@('私の出身は',$todouhuken[0],'です') -join ""

$todouhuken = @(
'tokyo'
'yamanashi'
'shizuoka'
)
```

実行すると以下のエラーが出ました。

```
Cannot index into a null array
```

直訳すると「null 配列にインデックスを付けることはできません。」という内容。
nullなんて使っていないぞ、、、


# 原因と対処法

どうやら変数で定義されていない配列を書いているのが原因のようです。先に配列を書いていないから認識されない、当たり前でした。

そこで配列の定義を前に移動させます。これで認識されるはず。。

```join.ps1
$todouhuken = @(
'tokyo'
'yamanashi'
'shizuoka'
)

@('私の出身は',$todouhuken[0],'です') -join ""
```

実行結果が以下の通り、配列で定義した中身が出ました。０番目が一番前ですのでtokyoが表示されます。
```
私の出身はtokyoです
```

# 雑感
変数、配列を先に定義しないと後ろでは認識されないということを認識しました。
基本的なことですが、再度頭に入れていきたいと思います。
AtCoderで上限ぴったりのコードを提出する

AtCoderでマヨビームの荒らし（ด้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้ (・ω・) ด็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็.)を使って上限(524288文字)ぴったりの提出をしてみました。上の荒らしは一つ182文字だと思っていたのですが、AtCoder上では535文字でした。いろいろ計算して、下の提出をしました。
https://atcoder.jp/contests/abs/submissions/41332949
Makefileで関数・マクロをcallするときに前スペースが入ってしまう

当たり前かもしれないがわからなかった

# 結論

:o: callするときは、以下のように書く
```
$(foreach NUM,$(NUMS),$(eval $(call MACRO,$(NUM))))
```

:x: 以下のように書いてはいけない (引数に前スペースが入ってしまう)
```
$(foreach NUM, $(NUMS), $(eval $(call MACRO, $(NUM))))
                                            ^
```
(引数以外に前スペースはあってもいいが、統一感出すためについでに消している)

# 経緯

以下のようなMakefileを書いた

```
NUMS = 1 2

define BUILD
build/foo-$(1): src/foo-$(1).cpp
	g++ $$^ -o $$@
endef

$(foreach NUM, $(NUMS),$(eval $(call BUILD, $(NUM))))
```

`make foo-1`と打ってみると以下のように何も実行されなかった

```
Makefile:8: 警告: ターゲット 'build/foo-' のためのレシピを置き換えます
Makefile:8: 警告: ターゲット 'build/foo-' のための古いレシピは無視されます
make: *** ターゲット 'build/foo-1' を make するルールがありません.  中止.
```

`make -np`で確認すると以下のように、スペースが入っているようだった

```
1: src/foo- 1.cpp # foo-と1の間にスペースが入っている
#  暗黙ルールの探索は行われませんでした.
#  修正時刻がチェックされることはありません.
#  ファイルは更新されていません.
#  実行するレシピ (ファイル 'Makefile', 8 行目):
	g++ $^ -o $@
```

最初は、マクロ内で`build/foo-$(trim $(1))`とやったり、`call`関数内で`$(call BUILD,$(trim $(NUM)))`とやったりした(こちらは無意味だった)が、以下のスペース削除に落ち着いた
```
$(foreach NUM,$(NUMS),$(eval $(call BUILD,$(NUM))))
```

もちろん、`make foo-1`の実行結果は期待通りになった

```
g++ src/foo-1.cpp -o build/foo-1
```

# 余談

上の事象を再現しようとして、以下のようにしていた

- ディレクトリ構成 (Makefileとソースコードを同じディレクトリ直下においた)
    ```
    test/
    　├ foo-1.cpp
    　├ foo-2.cpp
    　└ Makefile
    ```
 - Makefile (前スペースあり)
    ```
    NUMS = 1 2
    
    define BUILD
    foo-$(1): foo-$(1).cpp
    	g++ $$^ -o $$@
    endef
    
    $(foreach NUM, $(NUMS),$(eval $(call BUILD, $(NUM))))
    ```

`make foo-1`の実行すると、警告はでるが、コンパイルはしてくれる
```
Makefile:8: 警告: ターゲット 'foo-' のためのレシピを置き換えます
Makefile:8: 警告: ターゲット 'foo-' のための古いレシピは無視されます
g++     foo-1.cpp   -o foo-1
```
(コンパイルしてくれるのはいいが、再現できないので困っていた)

# 参考

- https://tex2e.github.io/blog/makefile/functions (改めて確認すると、ちゃんと前スペース削除していた)
Databricks REST APIリファレンスページができました！

Databricksでは外部からDatabricksのさまざまな機能を利用できるREST APIが公開されています。

今回(1月ですが)、AWS/GCP向けにDatabricks REST APIリファレンスページが公開されました！

https://docs.databricks.com/api-explorer/workspace/introduction

![Screenshot 2023-05-13 at 8.29.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/d2889607-c1fb-b57c-9d7d-f5504535ca00.png)

左上でクラウドプロバイダーやワークスペースレベルのAPIかアカウントレベルのAPIかを選択します。検索も可能です。

ドリルダウンしていくと、APIのエンドポイントやサンプルを確認できます。
![Screenshot 2023-05-13 at 8.32.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/035d0d03-d021-be34-4c0b-ddd88b6892f8.png)

CI/CDなどのオペレーションの自動化には欠かせないREST API、ぜひご活用ください。

なお、Azure DatabricksのAPIリファレンスはこちらとなります。

https://learn.microsoft.com/ja-jp/azure/databricks/dev-tools/api/latest/


### Databricksクイックスタートガイド

[Databricksクイックスタートガイド](https://www.amazon.co.jp/dp/B09V1YXFVQ/)


### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
ダークモードで色が変化するcssの書き方



# ダークモードで色が変化するCSSの書き方

ダークモードとライトモードをサポートするウェブサイトの作成は、ユーザー体験を向上させる効果的な方法の1つです。ここでは、それぞれのモードで色が変化するCSSの作成方法を説明します。

## 1. 通常のライトモード用のCSSを書く

まずは、通常時（ダークモード非対応またはダークモードがオフの場合）のCSSを定義します。例えば、以下のように背景色を白、文字色を黒に設定します。

```css
body {
    background-color: #fff;
    color: black;
}
```

## 2. ダークモード時のCSSを書く

次に、ダークモード時のCSSを定義します。これはメディアクエリ `(prefers-color-scheme: dark)` を使用して実装します。このメディアクエリは、ユーザーのシステムがダークモードを選択している場合にのみ適用されます。

```css
/*ライトモード用css*/
body {
    background-color: #fff;
    color: black;
}

/*ダークモード用css*/
@media (prefers-color-scheme: dark) {
    body {
        background-color: rgb(17, 24, 39);
        color: white;
    }
}
```

この設定では、背景色を深い青色、文字色を白に設定しています。

---

これらのCSSを適用することで、ユーザーのシステム設定に応じてウェブサイトの色が自動的に切り替わります。ユーザーは自分の視覚的な好みやニーズに合わせて、最適な体験を得られます。

ただし、この方法はユーザーのシステム設定に依存します。ウェブサイト内でユーザーが明示的に配色を切り替えられる機能を提供する場合は、JavaScriptなどを使用して制御する必要があります。
ST7735(パラレル)で遊ぶ4(コマンド一覧)(1か月から3か月の長期記事)ATM0177B5


目的
解析する為にこコマンド一覧を調査


いろいろ
俺もいみふめいで、わけわかめ
はじめて見た
でも、必要


![o_cop521.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/a9bcda2d-9742-90ee-5a41-c174ec145de9.jpeg)

![o_cop522.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/f5f25ee5-1243-2965-27c6-294b86cb638e.jpeg)

![o_cop523.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/6ed2460c-025d-2b34-5828-74c69ea93c48.jpeg)
HTMLとREACTの属性の名前の違い

React（及びNext.js）では、JavaScriptの予約語や命名規則に関連していくつかのHTML属性の名前が変更されています。以下に、HTML属性とそれに対応するReact属性の一覧を示します：

HTML属性 | React属性
--- | ---
class | className
for | htmlFor
tabindex | tabIndex
readonly | readOnly
colspan | colSpan
rowspan | rowSpan
contenteditable | contentEditable
maxlength | maxLength
minlength | minLength
accesskey | accessKey
autocomplete | autoComplete
autofocus | autoFocus
novalidate | noValidate
spellcheck | spellCheck
srcset | srcSet
crossorigin | crossOrigin
datetime | dateTime

また、Reactではinlineスタイルは文字列ではなくJavaScriptのオブジェクトとして提供され、CSSプロパティの名前はキャメルケースで記述されます。例えば：

```jsx
<div style={{backgroundColor: 'blue', height: '100px'}}></div>
```

これらはHTMLとReactで属性名が異なる例の一部で、他にも多くのReact固有の属性があります。これにはイベントハンドラ（onClick、onSubmitなど）や特殊な属性（key、refなど）が含まれます。詳細な情報はReactの公式ドキュメンテーションで見つけることができます。
RubyKaigi 2023 参加レポート「Revisiting TypeProf - IDE support as a primary feature」

この記事は [【RubyKaigi 2023連動イベント】みんなでRubyの知見を共有しよう - Qiita](https://qiita.com/official-events/4d2a9eed42dbe0a4af21) の参加記事です。

https://qiita.com/official-events/4d2a9eed42dbe0a4af21

## はじめに

執筆時点（2023/05/12）で開催中のRubyKaigi 2023に現地組として参加しております！
本日も面白いセッションがいくつもありました！
その中の以下のセッションについてまとめます。

## 追記

スライドが公開されていたので、ぜひそちらもご覧ください！

https://twitter.com/mametter/status/1658324122391437313?s=20

## Revisiting TypeProf - IDE support as a primary feature

https://rubykaigi.org/2023/presentations/mametter.html#day2

現状、TypeProfがうまく使われないことの考察から始まり、新しくIDEサポートを重視してつくっているTypeProf v2のデモを見せながらTypeProf v2の実装について話していました。
デモでは、VS Code上でメソッドや定数の定義ジャンプ、ifでのnilガード等がありました。

現在のTypeProf（v1）は、もともとRubyに型推論を入れることを目指し、推論の速度・不完全なコードでの動作は別にしていたようです。
しかし、実際に必要とされているのはIDEサポートで、推論の速度・不完全なコードでの動作が重要でした。

そこで、TypeProf v2の目標を「~10K, ~100K LOCの中規模プロジェクトでは、0.1秒以内に解析できる」にし、新しい解析アルゴリズム等を使い開発しているようです。

推論時間を短縮するために、新しい解析アルゴリズムでは全体のデータフローグラフから変更があった部分だけを更新する差分更新を採用しています。
（詳しい解析アルゴリズムは後日スライド等が公開されると思うので、そちらをご確認ください）

それによって、TypeProf v2自身のコード（7000行程度）では変更時に0.1秒を切る速度で解析ができるようになっているそうです！
（まだ、未実装の部分もあるようなのでパフォーマンスが変わる可能性もあるとのことでした）

## さいごに

他の言語を触っているとRubyのIDEサポートが充実していると良いなと思うタイミングは多々あるので、TypeProf v2でよりRubyを楽しく書けるようになるといいなと思います。
Prismaのschema定義で、DBのカラム名はsnake_caseだけど実際に使う時はcamelCaseにしたい人へのライフハック

# 結論
`prisma-case-format`を使おう！
https://github.com/iiian/prisma-case-format
ってちょっと色々すっ飛ばしましたが、この題名だけみて結論だけ知りたい人は多分このリポジトリ見たらざっくりわかると思うのでこれだけでわかる人は「いいね」だけ気持ち押してくれればこの後ぜーーーーんぶすっ飛ばして「最後に」だけ流しよみしてくれればOKです。

ちょっとこれだけ見ても・・・って人は読み進めてもらえると大体わかると思います。

# 前提
DBの設計するときって大体は・・・
Table名・カラム名共にsnake_caseで書くことが多いと思います。これは、DBによって大文字小文字の判別をしないため判読性にかけるという理由からsnake_caseにするという一説があります。（無論諸説＆慣習あり。）
けど、Typescript使ってる人って割と、classはPascalCase、変数名などはcamelCaseで書きたい人も一定数いるはずで、一貫した記法をしようとすると結構厄介だったりします。
ここではその厄介をできる限り解消したい人へのTipsです。

# そもそもsnake_caseのカラム名をcamelCaseに変換したい時の書き方
https://www.prisma.io/docs/concepts/components/prisma-schema/data-model
公式を見ろ！というのは投げやりなので、ちゃんと説明します。

以下のような書き方で、`@map("hoge_hoge")`という書き方でmapに記載された方でカラム名が設定されます。
同時に、`@@map("huga_huga")`の書き方でテーブル名がマッピングされます。
```
model Users {
  id             String         @id @default(uuid())
  name           String
  email          String
  createdAt      DateTime       @default(now()) @map("created_at")
  updatedAt      DateTime       @updatedAt @map("updated_at")

  @@map("users")
}
```
これによって、このmodelを呼び出す時は、、、
```
const prisma = new Prisma.client()

const exec = async () => {
    const users = await prisma.users.findMany() // これの戻り値が定義された通りのキャメルケースになります。
}
```

ここで声を大にして言いたいです。
<b>この`@map`と`@@map`書くのめんどくさくね？！</b>

これが一つや二つなら手直しでもいいのですが、複数あると面倒ですよね？（面倒でないと思う人はこの先ほぼ無駄になるかも...）

# 面倒だと思う人はこれを使おう！
てれれってれー、`prisma-case-format`。
例えば先ほどのusersについて・・・・
```
model Users {
  id             String         @id @default(uuid())
  name           String
  email          String
  createdAt      DateTime       @default(now())
  updatedAt      DateTime       @updatedAt
}
```

と描いてあるmodelを先ほどのprisma-case-formatを噛ませると
```
model Users {
  id             String         @id @default(uuid())
  name           String
  email          String
  createdAt      DateTime       @default(now()) @map("created_at")
  updatedAt      DateTime       @updatedAt @map("updated_at")

  @@map("users")
}
```

に自動で変換されます。私のリポジトリでは`prisma generate`する前に以下のコマンドを実行します。（`package.json`のスクリプトで定義してます。）
```
prisma-case-format --file prisma/schema.prisma && prisma format && prisma generate
```

こうすることで自動でsnake_caseでTable定義をつくり、実際に`@prisma/client`を使う時はcamelCaseで使えるようにしています。

# 最後に
めんどくさいと思っていることは大体の場合は世界の誰かも同じようにめんどくさいと思ってるものですね・・・。
先人の知恵とツールに感謝してリポジトリにスターをつけた後、感謝の正拳突き1024回をしたのちに使用しましょう（感謝とスターは本当にしますが、正拳突きは冗談です。）
2023/5/13主にITとかセキュリティの記事

狙われるネットバンク利用者 - 銀行装うメールやSMSに警戒を
https://www.security-next.com/146026

分散型データベース「OpenTSDB」にコマンドインジェクションの脆弱性
https://www.security-next.com/146020

ドローン情報基盤システムで情報漏洩の不具合 - 修正するも再発
https://www.security-next.com/145879

県関連サイトが改ざん被害、外部サイトに誘導 - 静岡県
https://www.security-next.com/146008

「Git」にセキュリティアップデート - 複数脆弱性を修正
https://www.security-next.com/146046

サーバがランサム被害、影響など調査 - シークス
https://www.security-next.com/146034

大量のインテル製品に脆弱性 ～CPUや「Intel Unite」など広範囲の製品に影響(5/11)
https://forest.watch.impress.co.jp/docs/news/1499521.html

IT/OTセキュリティで問われるのは専門性--ClarotyのバルディCEO(5/11)
https://japan.zdnet.com/article/35203470/

機密情報の公開を防ぐGitHubの有償セキュリティ機能、無償で提供開始(5/11)
https://news.mynavi.jp/techplus/article/20230511-2675998/

東アジアのDLPソフトウェア会社を狙ったAPTグループ「Tick」のサイバー攻撃とは？(5/11)
https://ascii.jp/elem/000/004/136/4136018/?rss

年間5人に1人が被害に遭っている…｢サイバー攻撃に狙われやすい個人パソコン｣の共通点(5/10)
https://president.jp/articles/-/68982

ゼロトラストでも活躍、日本企業の3割が使う「SASE」とは何か(5/8)
https://active.nikkeibp.co.jp/atcl/act/19/00470/040700001/

HPに不正アクセス　三重県立総合医療センター、書き込みされる(5/11)
https://news.yahoo.co.jp/articles/19164e5406eb0380e346c491a1f49944cbfd3f9f?source=rss

マイナカードで誤交付　不安への配慮が足りない(5/11)
https://mainichi.jp/articles/20230511/ddm/005/070/072000c

4月のフィッシング被害報告、Amazonを偽るメールが増加 - 前月比1.5万増(5/11)
https://news.mynavi.jp/techplus/article/20230511-2676404/

最もみんなが使うパスワードとは(5/9)
https://note.com/y_hamasan/n/n307a75510010

「個人情報なんて気にしない」、スマートシティー実現には潔さが必要なのか(5/11)
https://eetimes.itmedia.co.jp/ee/articles/2305/11/news126.html

中国製港湾クレーンは「スパイツール」…米下院、中国対抗法案を発表(5/11)
https://www.epochtimes.jp/2023/05/150168.html

社内不正被害の4割以上が「退職者による情報の持ち出し」(5/11)
https://news.yahoo.co.jp/articles/c918cca003b2eb60a0dac14127e55a5e1cf9de4b?source=rss

業界別AIの活用方法をご紹介！AIの定義やできることは？(5/11)
https://sogyotecho.jp/industry-ai/

あれもれも摘発対象に、中国が「反スパイ法」をパワーアップした本当の狙い(5/10)
https://news.nicovideo.jp/watch/nw12550874

ブロックチェーン協会がSECカストディルールの改正案に意見、コインベースやa16zらも難色示す(5/11)
https://www.neweconomy.jp/posts/313290

情報通信ネットワークにおけるサイバーセキュリティ対策分科会（第5回）開催案内(5/18予定)
https://www.soumu.go.jp/main_sosiki/kenkyu/cybersecurity_taskforce/02cyber01_04000001_00240.html

「最後の特需」去り厳冬期のパソコン市場、収益性低下の影響は顧客にも(5/12)
https://xtech.nikkei.com/atcl/nxt/column/18/00989/050800116/

「機械学習なんだから簡単でしょ？」、データサイエンティストが直面する社内の誤解(5/12)
https://xtech.nikkei.com/atcl/nxt/column/18/02408/042400003/

農水省が4月中にもChatGPT利用　中央省庁の先陣切り実業務で使うワケ(5/11)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/020800017/042800886/

ChatGPTのノウハウ獲得を急げ　企業が相次ぎ補助制度を導入(5/11)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/020800017/042800887/

「巨大AI実験を6カ月停止せよ」　リスクを巡る議論の遅れに警鐘(5/11)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/020800017/042800888/

給与デジタル払いはブームになるか　一斉参入のPayPay・楽天らの勝算(5/11)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/020800017/042800889/
Flutter WebView 4.2.0サンプル

```
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

void main() {
  runApp(
    const MaterialApp(
      home: WebViewApp(),
    ),
  );
}

class WebViewApp extends StatefulWidget {
  const WebViewApp({super.key});

  @override
  State<WebViewApp> createState() => _WebViewAppState();
}

class _WebViewAppState extends State<WebViewApp> {
  late final WebViewController controller;

  @override
  void initState() {
    super.initState();
    controller = WebViewController()
      ..loadRequest(
        Uri.parse('https://flutter.dev'),
      );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter WebView'),
      ),
      body: WebViewWidget(
        controller: controller,
      ),
    );
  }
}
```
【攻略】ジョジョの奇妙なRails スターダストユーザー管理機能

おれをこの檻から出すな。
まだユーザー管理機能を実装してねぇんだからな。

## 1.deviseを使ったユーザー管理機能の実装
こんなおれにも　吐き気のする「gem」はわかる！！
まずは「devise」をインストールすることから始めるか。

### 1.1. deviseのインストール

オラァァ！

```
gem 'devise'
```
### 1.2. ユーザーモデルの作成
おめーの「モデル」はユーザー情報をどのカラムにぶち込めばいいか見えねえしわからねえ・・・
だから　おれがユーザーモデルを作成する！

```
rails generate devise User
```

### 1.3. データベースへのマイグレーション
オララララオラ裁くのは おれの『マイグレーション』だッ───！！

```
rails db:migrate
```
### 1.4. ビューのカスタマイズ
おれのスタンドは脳の針を正確に抜き
ユーザーがより使いやすいビューを作成する・・・・・・・・・・

```
rails generate devise:views
```
これで、app/views/deviseディレクトリにビューが生成される。カスタマイズして、ユーザー管理機能を完成させてやろうじゃあねぇか

## 2. ユーザー新規登録・ログイン・ログアウト機能
ハミング！次に、ユーザーが新規登録、ログイン、ログアウトできる機能を追加する

### 2.1. 新規登録フォームの作成
新規登録フォームは、`app/views/devise/registrations/new.html.erb`にある。必要に応じてカスタマイズしろ。

### 2.2. ログインフォームの作成
ログインフォームは、`app/views/devise/sessions/new.html.erb`にある。必要に応じてカスタマイズしろ。

### 2.3. ログアウトリンクの設置
ログアウトリンクは、適切な場所に設置しよう。例えば、`app/views/layouts/application.html.erb`のヘッダー部分などが良いだろう。以下のコードを貴様のファイルに追加しろ。

```
<% if user_signed_in? %>
  <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
<% else %>
  <%= link_to "ログイン", new_user_session_path %>
  <%= link_to "新規登録", new_user_registration_path %>
<% end %>
```
これで、ログイン状態に応じて、ログイン・新規登録・ログアウトのリンクが表示されるようになるぞ！
なに？表示されてない？それじゃあてめーは 地獄の底で寝ぼけな！！

# まとめ
フン！やるな・・・花京院
ところでおまえ決済機能好きか？とくにAPIとのかけひきを！・・・・・・・・
手に汗にぎるよなあッ！オラアッ！
TextBox への貼り付け時に改行コードを調整

Windows Forms の TextBox へクリップボードから貼り付ける際、改行コードが CR+LF でないと改行が表示されません。

貼り付け時に改行コードを調整して対処しました。

```cs
public class MyTextBox : TextBox
{
    public static string NormalizeNewLine(string s)
    {
        return s.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", "\r\n");
    }

    protected override void WndProc(ref Message m)
    {
        const int WM_PASTE = 0x302;
        if (m.Msg == WM_PASTE)
        {
            try
            {
                var t = Clipboard.GetText();
                Paste(NormalizeNewLine(t));
                return;
            }
            catch { }
        }
        base.WndProc(ref m);
    }
}
```

# 参考

https://stackoverflow.com/questions/15987712/handle-a-paste-event-in-c-sharp