OmniAICreator/Qiita-1.07M huggingface dataset:
【Herokuより手軽】Renderでのデプロイ手順

## 【超簡単】Renderでのデプロイ手順

### 1. PostgreSQLのインストール
```bash
brew install postgresql@14
```

### 2. GemFileへの追記
GemFileに以下の内容を追加して、PostgreSQLを使用するためのGemを追加します。

```ruby
group :production do
  gem 'pg'
end
```

### 3. Gemのインストール
ターミナルで以下のコマンドを実行してGemをインストールします。

```bash
bundle install
```

### 4. render-build.shファイルの作成
render用の設定ファイルを作成。`bin`フォルダに`render-build.sh`ファイルを追加し、以下の内容を記述します。

```bash
#!/usr/bin/env bash
# エラーが発生した場合にスクリプトを停止
set -o errexit

bundle install
bundle exec rake assets:precompile
bundle exec rake assets:clean
bundle exec rake db:migrate
```

### 5. database.ymlの変更
`database.yml`ファイルを以下のように変更します。データベースの設定をPostgreSQLに変更します。

```yaml
default: &default
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  <<: *default
  adapter: mysql2
  username: root
  password:
  host: localhost
  database: アプリ名_development

test:
  <<: *default
  adapter: mysql2
  username: root
  password:
  host: localhost
  database: アプリ名_test

production:
  <<: *default
  adapter: postgresql
  url: <%= ENV['DATABASE_URL'] %>
```

### 6. Gemfile.lockの設定変更
以下のコマンドを実行して、Gemfile.lockにmac以外のOSサーバーにデプロイできる設定を追加します。

```bash
bundle lock --add-platform x86_64-linux
```

### 7. GitHubへプッシュ
コードをGitHubにプッシュします。

### 8. Renderの公式ページへアクセス
[Renderの公式ページ](https://render.com/)にアクセスします。

### 9. GitHubとRenderの連携
アカウントを作成し、GitHubとRenderを連携します。

### 10. データベースの作成
RenderのダッシュボードでNewボタンをクリックし、PostgreSQLを選択してデータベース作成ページに移動。データベース名を入力してCreate Databaseボタンをクリックします。
またRegionは障害発生率が低いOhioに変更。

### 11. Web Serviceの作成
NewボタンからWeb Serviceを選択しWeb Service作成ページに移動します。

### 12.GitHubとの連携
ページ右側にあるGitHubアイコンからGitHubと連携を行い、使用するリポジトリを選択します。

### 12. アプリのデプロイや起動時のコマンド設定
Build Commandを`./bin/render-build.sh`に、Start Commandを`bundle exec puma -C config/puma.rb`に変更します。

### 13. 環境変数の設定
AdvancedからAdd Environment Variableをクリックし、環境変数を設定します。
- 1つ目: Keyに`RAILS_MASTER_KEY`、Valueに`config`フォルダの`master.key`ファイルの内容を記述します。
- 2つ目: Keyに`DATABASE_URL`、Valueにデータベース作成ページのInternal Database URLに書かれたURLを記述します。

### 14. Web Serviceの作成
最後にCreate Web Serviceボタンをクリックしてデプロイを開始します。

これで、Renderへのデプロイ手順が完了し、アプリケーションがデプロイされます。

---

この手順に従うことで、Renderを使用してアプリケーションをデプロイすることができます。
（C⇒B）配列メニュー〜指定の要素のカウント〜

今日もBランクを目指すためのメニューをこなす。
今日の問題はこれ
https://paiza.jp/works/mondai/array_utilization_primer/array_utilization_primer__count

---

 STEP: 1 指定の要素のカウント
・1 行目では、配列 A の要素数 N と整数 K が半角スペース区切りで与えられます。
・続く N 行では、配列 A の要素が先頭から順に与えられます。
・入力値最終行の末尾に改行が１つ入ります。
・文字列は標準入力から渡されます。
問題：配列 A に K がいくつ含まれるか出力しなさい。

---

・標準入力や改行の方法は以前やったのと同じ。
・1行目を半スペで分割し、Forループを何回するかがわかった
・配列を作成後、文字列と同じ文字がある要素の数を調べる

ポイントは、
・第1次配列の作成を含む操作方法に慣れること(⇒ここ苦手なので克服しよう）
・同じ文字がある要素の数を調べる関数を知っているかどうか

```
    // 自分の得意な言語で
    // Let's チャレンジ！！
    $first_line = trim(fgets(STDIN));
    $s = explode(" ",$first_line);
    $maxNum = $s[0];
    $target = $s[1];
    //配列作成
    $array =[];
    for($i=0; $i<=$maxNum-1;$i++){
        $factor = trim(fgets(STDIN));
        $array[] =$factor;
    }
    //配列から$targetを検索,結果を出力
    $result = array_keys($array,$target);
    echo count($result);
```
Nginxで設定が終わったら次にやること

Nginxの権限を変更しよう。

設定が完了したら、POSTメソッドでもエラーが出ないようにするために、下記のコマンドも実行しよう。

```bash
[ec2-user@ip-172-31-25-189 ~]$ cd /var/lib
[ec2-user@ip-172-31-25-189 lib]$ sudo chmod -R 775 nginx 

```

以下のコマンドを実行して、Nginx設定ファイルを起動して再読み込みしよう。
```bash
[ec2-user@ip-172-31-25-189 lib]$ cd ~
[ec2-user@ip-172-31-25-189 ~]$ sudo systemctl start nginx
[ec2-user@ip-172-31-25-189 ~]$ sudo systemctl reload nginx
```

Nginxの設定を変えたので、unicornの設定もそれに伴って変更しておく。

config/unicorn.rb
listen 3000を下記に変更。
```bash
listen "#{app_path}/tmp/sockets/unicorn.sock"
```
【flutter】カレンダーを作る

こんにちは！
最近は、
昼間は暑く、夜は寒くて、何を着ればいいか迷ってしまいますね〜
今回は、flutterでカレンダーを実装していきます。

# インポート
```dart:pubspec.yaml
environment:
  sdk: '>=3.0.6 <4.0.0'

dependencies:
  flutter:
    sdk: flutter

  table_calendar: ^3.0.9
  intl: ^0.18.1


```
packageをimportするために、pubspec.yamlに追記しましょう。
pub getを忘れずに！


# コード
```dart
import 'package:flutter/material.dart';
import 'package:table_calendar/table_calendar.dart';

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

  @override
  State<Calender> createState() => _CalenderState();
}

class _CalenderState extends State<Calender> {
  final DateTime _focusedDay = DateTime.now();
  CalendarFormat _calendarFormat = CalendarFormat.month;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("カレンダー")),
      body: TableCalendar(
        firstDay: DateTime.utc(2020, 1, 1),
        lastDay: DateTime.utc(2030, 12, 31),
        focusedDay: _focusedDay,
        calendarFormat: _calendarFormat,
        onFormatChanged: (format) {
          if (_calendarFormat != format) {
            setState(() {
              _calendarFormat = format;
            });
          }
        },
      ),
    );
  }
}

```


TableCalendarではfirstDay、lastDay、focusedDayが必須です。
firstDayとlastDayはカレンダーを表示する最初と最後の月の指定ができ、
focusedDayはデフォルトでフォーカスされて日付の部分に色が付きます。
また、CalendarFormatは月(month)、週(week)を選択できます。

# 実行例
![スクリーンショット 2023-11-06 15.17.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524120/34727208-fafe-83b2-ff78-8feab4ffd118.png)


# 最後に
ここまで読んでいただき、ありがとうございました！
いいねをくれると、スキップしながら喜びます:tomato:
Minecraftサーバー エラー解決

:::note warn
前の記事を見ていない人は見てから読んでください
:::

https://qiita.com/ikatakoch/items/2f744284df84ddb05cde

今回は、Minecraftサーバーで発生するエラーを5つ紹介します。
## Error occurred during initialzation of VM Initial heap size set to a larger value than the maximum heap size
1つ目は、Error occurred during initialzation of VM Initial heap size set to a larger value than the maximum heap sizeです
このエラーは、起動するときのコマンドに原因があります。(スペルミスなど)
メモリの最小値が最大値を超えている場合に起きます。
このエラーが発生した場合もう一度実行したコマンドを見直してください。
(❌な例)
```:コマンドプロンプト
java -Xmx2G -Xms1G -jar server.jar nogui
```
この場合は、`-Xmx2G`(最小値)が`-Xms1G`(最大値)を超えているのでエラーが発生します。
## **** FAILED TO BIND TO PORT!
2つ目はFAILED TO BIND TO PORTです
このエラーはポートが何かしらのアプリケーションやサービスに使われてる時、あるいは使用できない時に表示されます。
このエラーの原因はアプリケーション、サービスが使っている可能性が多いので、`server.properties`というフォルダから50行目あたりの`server-port`の値を`25565`以外の数値(26665,25670,26656など...)に変えてください。使うポートを変えることで、このエラーは解決できることが多いからです。
また、サーバーの多重起動などでも発生します。
タスクマネージャー(アクティビィティモニタ)から、同じコマンドが2個実行されていないかを確認してください！
## UnknownHostException
3つ目はUnknownHostExceptionです
先ほど説明した、`server-port`に存在しないポートまたは、無意味な記述がされていると発生します。
基本的には、1024から49512の番号を記述します。ただし、他のアプリケーションと重複する可能性が高いので、無意味に変えないことをお勧めします。
## To start the server with more ram
四つ目は、To start the server with more ramです。
このエラーは、サーバーを起動するためのメモリ割り当てが足りない場合に起きます。
1024M(1G)から1024M(1G)を指定すれば大概は治ります
## Unable to access jarfile
最後は、Error: Unable to access jarfile [ファイル名] です。
Unable to access jarfileは、指定したjarファイルが見つからない場合に表示されます。
ファイルの名前のスペルミスや、大文字小文字の間違いなどが原因です。
ファイルの名前を見直して、もう一度実行してください。
## 終わり
これでこの記事を終わります！
最後まで読んでいただきありがとうございました。
わかりにくい点などありましたら、コメント欄で教えてください。
## 引用
[Minecraft JapanWiki](https://minecraftjapan.miraheze.org/wiki)さん
[該当ページ](https://minecraftjapan.miraheze.org/wiki/サーバー/技術的情報集#エラーログ)
テレビやPS4のJavaScriptのログをPCに出力する方法


テレビやPS4のアプリの開発中には、JavaScriptのログをPCでチェックしたい場面があります。
そんなときに便利なのが、[console.re](https://console.re/)というツールです。

この記事では、簡単にそのセットアップと使い方を説明します。


### 使い方の手順

#### Step 1: ツールのダウンロード

```markdown
git clone https://github.com/kurdin/console-remote-server
```
上記のコマンドでソースコードをクローンします。

#### Step 2: ディレクトリに移動

```markdown
cd console-remote-server
```
クローンしたディレクトリに移動します。

#### Step 3: パッケージのインストール

```markdown
npm install
```
必要なパッケージをインストールします。

#### Step 4: ホストの設定変更

`.env.development`と`gulpfile.js`のファイルにあなたのローカルIPを設定します。

**.env.development**:
```plaintext
APP_CONNECT_HOST=http://[自分のローカルIP]:8088
```

**gulpfile.js**:
```javascript
host: '[自分のローカルIP]',
```

#### Step 5: コンソールサーバの起動

```markdown
npm run server
```
コンソールサーバを起動します。

#### Step 6: コンソールアプリの起動

新しいターミナルを開いて、以下のコマンドでコンソールアプリを起動します。

```markdown
npm start
```
すると、`http://[自分のローカルIP]:8090`でアプリが開きます。

#### Step 7: 必要なディレクトリに移動

開発ディレクトリに移動します。

#### Step 8: console.reパッケージのインストール

```markdown
yarn add console-remote-client
```
または
```markdown
npm install console-remote-client
```
パッケージをプロジェクトに追加します。

#### Step 10: コンポーネントにコードを追加

プロジェクトのローカル環境を起動し、ログを取りたいコンポーネントに次のコードを追加して、ローカルをリロードします。

```javascript
import consolere from 'console-remote-client';

consolere.connect({
  server: 'http://[ローカルIPアドレス]:8088',
  channel: '[任意のチャンネル名]',
  redirectDefaultConsoleToRemote: false,
  disableDefaultConsoleOutput: false,
});

console.re.log('test');
```

以上でセットアップは完了です。


TVのアプリ開発時にJavaScriptのログをPCで確認することができるようになります。
Agricultural waste in india - harisharandevgan

State of technology in agriculture in 2023. However, I can give you an overview of some of the technology trends and advancements that were shaping the agriculture industry as of my last update. Keep in mind that the field of agricultural technology is constantly evolving, and new developments may have emerged since then.

Precision agriculture: Precision agriculture continues to be an important trend, with technologies such as GPS, drones and remote sensing being used to optimize crop management, reduce input wastage and increase overall efficiency.

Automation and robotics: Agricultural robots and automated machines are becoming common, helping with tasks like planting, harvesting, and weeding. These technologies can increase productivity and reduce the need for physical labor.

IoT (Internet of Things): The use of IoT sensors and devices in agriculture allows farmers to monitor and collect data on various factors such as soil conditions, weather, and crop health. This data can be used to make informed decisions and improve crop yields.

Artificial Intelligence (AI): AI is being used to analyze large datasets, predict crop outcomes, and optimize resource allocation. Machine learning models can help farmers make more accurate decisions in areas such as irrigation, pest control and crop selection.

Sustainable farming practices: Technology is playing an important role in promoting sustainable agriculture by helping farmers adopt eco-friendly practices, reduce water and chemical usage, and manage resources efficiently.

Vertical farming and indoor agriculture: Urban farming technologies, including vertical farming and hydroponics, are being used to grow crops in controlled environments. This allows year-round production with less reliance on traditional outdoor farming methods.

Blockchain in supply chains: Blockchain technology is being used to increase transparency and traceability in the agricultural supply chain from farm to consumer to ensure the authenticity and quality of food products.

Biotechnology: Advances in biotechnology are leading to the development of genetically modified crops with improved resistance to pests, diseases, and adverse environmental conditions.

It is important to note that the adoption of these technologies may vary according to the region and the specific needs of the agricultural sector. For the latest information on technology in agriculture in 2023, I recommend consulting agriculture industry reports, government publications, and specialized agricultural technology websites and publications.
https://harisharandevgan.com/new-technology-in-agriculture-2023/
WordPressでJSONエラーが発生した理由と対応

## エラーが発生しだした経緯
ブログのページを多言語化しようとして、Bogoというプラグインをインストールしました。日本語ページを切り替えて、英語などのページを用意したい場合に便利なプラグインですが、このプラグインをインストールした後に急にエラーが発生するようになりました。

## 突然の「JSONエラー」
Bogoをインストール後、ブログ記事を修正してWordPressで保存ボタンを押すと「JSONエラー」で保存できない現象が発生しました。

最初はBogoが原因だと思っていましたが、直接の原因はBogoではありませんでした。

## 原因はWAF
直接の原因は、WAF（Web Application Firewall）でした。WAFで「クロスサイトスクリプティング（タグ1）からの防御...」と表示されているように、ブログの更新がクロスサイトスクリプティングの攻撃と誤認されてしまったようです。

簡単に解決する方法はWAFをOFFにすることですが、それはセキュリティ上避けたいところです。

そこで、WAFをOFFにせずにこの問題を解決する方法を探しました。結論として、自分のIPアドレスを除外パターンに加えるという方法に落ち着きました。

## IPアドレスを除外に加えておく
私はプロバイダ経由で接続しているため、IPアドレスは接続のたびに変わる可能性がありますが、フレッツのルータを使用しているため、頻繁に変わることはありません。

以下の手順でIPアドレスを除外リストに追加しました。

まず、.htaccessファイルに以下の内容を追加します。

ConoHa WINGの場合は、サイト管理→サイト設定→応用設定にあります。

```
<IfModule mod_siteguard.c>
  SiteGuard_User_ExcludeSig ip(xxx.xxx.xxx.xxx)
</IfModule>
```

xxx.xxx.xxx.xxxは、自分のIPアドレスを入力してください。IPアドレスはWAFの警告メッセージから確認できます。

## IPアドレスが変わった時の対処
プロバイダ接続だとIPアドレスが変わることがあります。そのため、IPアドレスが変わった場合は、除外設定を更新することを忘れないようにしましょう。

JSONエラーが再発生することで、IPアドレスの変更に気づくことができます。
Pythonで通常のChromeブラウザを全て閉じる方法

## 前置き
Seleniumのオプションである「--user-data-dir=」はご存じでしょうか。
これでChromeブラウザのUserDataフォルダまでのパスを通すと、ユーザープロファイルを使用することができます。つまり、Seleniumで通常時のブラウザのログイン状態が引き継げるといったものです。

スクレイピングするにあたって、これほど心強い機能はないのですが1つ弱点があります。
それは通常時のブラウザが立ち上がったままdriverを起動すると、エラーが発生します。
基本的にアクセスが拒否されましたと言われるはずです。

その為、driver起動時には毎度通常ブラウザを閉じる作業が必須でした。
そこで今回この通常ブラウザを閉じる作業を自動化しようと考えました。
便利ですしヒューマンエラー対策にもなりますしね。


## 注意事項
この方法はChromeにとって非正規で非推奨であるため、責任は負えません。
もし不具合が発生しても責任はとれないのでご了承ください。
Chromeにとっては予期せぬ終了として扱われるようなので、注意です!



## 方法
まずはbatファイルを作成します。
Pythonファイルと同じ階層に下記のファイルを作成してください。
```bat:chrome_finish.bat
taskkill /F /IM chrome.exe /T
taskkill /F /IM chromedriver.exe /T
```

方法としてはいたって単純で、今作成したbatファイルを実行するだけになります。
```python:example.py
import os
import subprocess

# ここでbatファイル実行
subprocess.Popen([fr"{os.getcwd()}\\chrome_finish.bat"])
```

これで今開いている全てのChromeブラウザは閉じたはずです。
また一応chromedriverも閉じるようにしてあります。

この後に起動すればOKです！
Rustにおけるスタックオーバーフロー: Trait実装の落とし穴

Rustの世界では、エラーが起きた時、しばしばコンパイラが友人のように寄り添ってくれます。しかし、ときにはコンパイラも頼りにならない状況に遭遇します。そう、スタックオーバーフローがその一つです。これは、プログラムが自らの終わりを告げる前に無限の深淵に落ちるかのような状況です。今日はそんなスリリングなバグとの戦いについて、実体験をもとにお話しします。

## スタックオーバーフローを引き起こすコード

さて、私が書いたRustのコードは以下の通りです。見た目は無害そうですが、内に秘めた力は想像以上です。

```rust
fn main() {
    let user_1 = User::default();
    println!("user_1: {}", user_1.username);
}

struct User {
    username: String,
    email: String,
}

impl Default for User {
    fn default() -> Self {
        Self {
            username: String::new(),
            ..Default::default() // ここで、あるべきではない再帰の旅が始まる...
        }
    }
}
```

この小さなコードを`cargo run`と共に実行すると、ターミナルは次のような不穏なメッセージを投げ返してきました。

```sh
$ cargo run

...
thread 'main' has overflowed its stack
fatal runtime error: stack overflow
zsh: abort      cargo run
```

## デバッグの挑戦

興味深いことに、スタックオーバーフローは私たちのスタックトレースを直接見ることを拒絶します。通常、エラーメッセージは犯人を指し示す手がかりを含んでいますが、スタックオーバーフローは犯人を隠します。このミステリーを解決するためには、`backtrace-on-stack-overflow`という名のルーペを使う必要があります。

### スタックトレースの活用

まずは、この便利なクレートを私たちのプロジェクトに招待します。

```sh
cargo add backtrace-on-stack-overflow
```

そして、`main`関数の序章に、以下の一行を加えることで、スタックオーバーフローが起きた際のバックストーリーを明らかにします。

```rust
unsafe { backtrace_on_stack_overflow::enable() };
```

### 再度の試行

これで準備は完了です。再び`cargo run`を叩いてみると、今度は犯人の足跡が明らかになります。

```sh
$ cargo run
...
Stack Overflow:
   0: backtrace::backtrace::libunwind::trace
             at /Users/mei/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.69/src/backtrace/libunwind.rs:93:5
      backtrace::backtrace::trace_unsynchronized
             at /Users/mei/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.69/src/backtrace/mod.rs:66:5
   1: backtrace::backtrace::trace
             at /Users/mei/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.69/src/backtrace/mod.rs:53:14
   2: backtrace::capture::Backtrace::create
             at /Users/mei/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.69/src/capture.rs:176:9
# これ以降、無限にループしてしまいます。
```

ここから先のスタックトレースを注意深く眺めると、`Default::default()` が再帰的に自分自身を呼び出しているのが分かります。これがスタックオーバーフローの真犯人です。`..Default::default()` が `User` 構造体の他のフィールドに対するデフォルト値の生成を試みるとき、`User` 自体のデフォルト実装を再帰的に呼び出してしまい、結果として無限ループに陥ってしまっていたのです。

## 解決への道

バグの正体が明らかになったので、修正は単純です。`User` 構造体のデフォルト実装を修正して、再帰的な呼び出しをなくすだけです。

```rust
impl Default for User {
    fn default() -> Self {
        Self {
            username: String::new(),
            email: Default::default(), // StringのDefault値
        }
    }
}
```

これで、`User::default()` を呼び出したときに再帰的な問題が解消され、`User` のインスタンスを安全に作成できるようになります。プログラムを再実行すると、今度はエラーなく実行されます。

## 学び
Rustにおいても再帰は慎重に扱うべきであるということ、そしてバグに直面したときには、適切なツールを使って深堀りすることの大切さです。

そして何より、エラーメッセージはただのガイドラインであり、時にはさらに深く掘り下げて真実を探究する勇気も必要だということを思い出させてくれました。プログラマーとしてのスキルを磨く旅は、このようなバグとの格闘を通じて続いていくのです。

~~ fin ~~

## 参考文献
https://qiita.com/reoring/items/b72d726ba305edc8a4b6
【Oracle Cloud】WindowsServerにインストールされたOracleDB(PDB)の起動と自動起動設定

# ◆取り上げているケース
下記のような環境での、OracleDBの停止起動について記載しています。
・OracleCloudのComputeを使用してWindowsServerを構築
・上記で構築したWindowsServer環境にOracleDatabaseをインストール
・OracleDatabaseをマルチテナントアーキテクチャ（CDB/PDBの形式）で運用する
<B>※マルチテナントの場合、起動時の操作については特に注意が必要です</B>



## ◆前段
OracleCloudでOracleDatabaseを使用する場合、手軽に利用できるようにするには、
・ADB（ADW/ATP）を利用する
・DBシステム（DBCS）を利用する
のいずれかになると思います。

ADBの場合、DB管理などはOracleCloudにお任せという状態になるので、DBを使用するだけならお手軽です。
DBCSの場合は、ADBよりは安価に利用できますが、LinuxサーバにインストールされたDBを使用することになります。Linuxは一般には馴染みが薄いため、サーバ利用という点ではハードルが上がります。

上記の理由から、
・UIがWindows-PCに近い、WindowsServerを構築
・構築したWindowsServer環境にOracleDatabaseをインストール
という、環境構成が求められる場合があります。

このような環境が求められた場合OracleCloudでは、
・Computeで、OSがWindowsServerのサーバを立てることで環境を用意。
・上記サーバに、個別でOracleDatabaseを用意してインストールする。
このような操作で環境構築を行うことになります。

尚、インストールするOracleDatabaseのライセンスは、OracleCloudの契約には含まれないので、注意が必要です。

このような環境の構築方法については、別途記載するものとし、
本記事では、このようなサーバを起動停止する場合の注意点を記載します。


## ◆サーバの起動停止
サーバ自体の起動停止は、他のComputeサーバと同じ手順で問題ありません。
手法としては、
・OCI-Webコンソール上で起動停止のボタンをクリックして操作
・OCI-CLIを使用して別環境から起動停止のコマンドを発行
の２点となります。

あえて気にする点を挙げるとすれば、
<B>『WindowsServerは、即時停止とはならない』</B>
という点です。
安全にOSが停止された状態でサーバを停止するようにするため、停止操作後に15分の待機時間が発生します。
これを回避するには、
・サーバ停止操作前に、手動でWindowsをシャットダウンしておく
・サーバ停止操作時に、強制的に停止するオプション操作を行う
という2つの方法があります。
強制停止は推奨される方法ではないので、事前に手動でWindowsをシャットダウンする方法がいいと思います。


## ◆OracleDBの起動停止
・OracleDBの停止
サーバが停止されれば、OracleDBも停止されます。
但、この場合の停止は強制停止に近いものになるので、OracleDBの停止操作による停止を行うことをお勧めします。

＝＝OracleDBのシャットダウンコマンド＝＝
```
SQL > SHUTDOWN IMMEDIATE
```

・OracleDBの起動
デフォルトでは、サーバ起動時に自動でOracleDBも起動します。
但、自動起動するのはCDBのみという点に注意してください。
PDBについては、個別で起動する必要があります。
OracleDBのサービスは起動しているのに、データが格納されているテーブルにアクセスできないような場合は、
CDBだけ起動していてPDBが起動していない状態になっていることがあります。


＝＝OracleDBのPDB起動コマンド＝＝
```
SQLPLUS / as SYSDBA
SQL> show pdbs
SQL> alter pluggable database all open;
```

OracleDBの起動停止を頻繁に行うことは少ない場合、
都度コマンドを実行する運用でも問題ないでしょう。
しかし、逆に実行頻度が少ないため、PDBが未起動の状態になっていることに気が付きにくいこともあります。

根本的な解決方法として、
OracleDB起動時にPDBも一緒に起動する方法があります。

＝＝OracleDBのPDB自動起動設定＝＝
※設定を行う場合は、PDBが起動した状態にある必要があります。
```SQLPLUS / as SYSDBA
SQL> show pdbs
SQL> alter pluggable database all save state;
```

## 最後に
先にも書きましたが、サーバ起動後PDB未起動に気が付かず、復旧に時間が掛かったことがあります。
可能であれば、PDBも自動起動するように対応することをお勧めします。
thread 'tokio-runtime-worker' has overflowed its stack みたいなやつが出たときのデバッグを簡単にする方法

# 解決方法

https://crates.io/crates/backtrace-on-stack-overflow Crateを使います。


```rust
fn main() {
    unsafe { backtrace_on_stack_overflow::enable() };
    // ... your code ...
}
```


# 参考
https://geo-ant.github.io/blog/2022/debug-stackoverflow-in-rust/
Goのループ変数キャプチャ(イテレータ変数キャプチャ)

```main.go
	s := []int{1, 2, 3}

	for _, i := range s {
		wg.Add(1)
		go func() {
			defer wg.Done()
			fmt.Println(i)
		}()
	}
	wg.Wait()
// 3
// 3
// 3
```

要素の分だけループを回してゴルーチンを起動するのは高速に行われるが、Printlnでそのインデックスを出力する頃には、ループが終了してしまっているため上記のような出力結果になってしまう。

下記のようにゴルーチンの自体にコピーを受け取る必要がある。

```main.go
	s := []int{1, 2, 3}

	for _, i := range s {
		wg.Add(1)
		go func(i int) {
			defer wg.Done()
			fmt.Println(i)
		}(i)
	}
	wg.Wait()

// 1
// 2
// 3
```
このミスやりがちと聞いたので、自戒を込めて。


## 参考記事
https://qiita.com/tamanobi/items/ced276961789d4943948
Nginxの導入でエラーが出たので、解決した。

Nginx(エンジンエックス)とは、Webサーバーの一種です。ユーザーのリクエストに対して静的コンテンツのみ取り出し処理を行い、動的コンテンツの生成はアプリケーションサーバに依頼します。

Nginxの導入でエラーが出ました。
導入時のエラーから解決までを書いていきたいと思います。

Nginxの設定ファイルを編集しようの箇所で、espキーと:wqを入力して保存しようとすると、エラーが出ました。

まずEC2内ターミナルでNginxの導入をしました。
```bash
[ec2-user@ip-172-31-25-189 ~対象アプリのディレクトリ]$ sudo amazon-linux-extras install nginx1

```

次に、Nginx設定ファイルの設定です。
/etc/nginx/conf.d/rails.conf
```bash
upstream app_server {
  # Unicornと連携させるための設定
  server unix:/var/www/リポジトリ名/tmp/sockets/unicorn.sock;
}

# {}で囲った部分をブロックと呼ぶ。サーバの設定ができる
server {
  # このプログラムが接続を受け付けるポート番号
  listen 80;
  # 接続を受け付けるリクエストURL ここに書いていないURLではアクセスできない
  server_name Elastic IP;

  # クライアントからアップロードされてくるファイルの容量の上限を2ギガに設定。デフォルトは1メガなので大きめにしておく
  client_max_body_size 2g;

# 接続が来た際のrootディレクトリ
  root /var/www/リポジトリ名/public;

# assetsファイル(CSSやJavaScriptのファイルなど)にアクセスが来た際に適用される設定
  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  try_files $uri/index.html $uri @unicorn;

  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app_server;
  }

  error_page 500 502 503 504 /500.html;
}
```

入力後に、escキー→:wqエンターキーで保存です。
しかし、ここでエラーが出て保存できませんでした。

エラーコードを読むと、

E45: 'readonly' option is set (add ! to override) 

こう書いてました。多分これが原因です。

解決策として、オーバーライドするために
```bash
escキー　▶　:wq!
```
末尾に「!」を入力することで強制的に上書き保存が可能です。


これで解決しました。
匿名化

匿名で悪いことをされる場合があるから、
web管理者は気をつけて運営しましょうね。

# 匿名でメールアドレスを取得

https://proton.me/mail

ProtonMailは何度も使えるスイス製の匿名のメールアカウントです。ProtonMailの優れた点は以下の通りです。

```
登録の際に個人情報を要求することはない
PrintonMailは厳格な個人情報保護法で知られるスイスに拠点を置いているため、ユーザーデータはスイスの個人情報保護法で保護される
IPアドレスは記録されない。特にVPNは必要ないが、セキュリティ強化のためにはVPNを使用するべき
エンド・ツー・エンドの暗号化が行われており、ProtonMailでさえも自分のメッセージにアクセスできない
オープンソースなので完全に無料で使用でき、ソースコードを自分で確認することもできる
モバイルアプリがあるため携帯電話でも使用可能
```

とのこと。

ただし、匿名メールサービスを利用する場合でも匿名VPNを使ってメールを送信した方が安全です。

なぜならばProtonMailのような匿名メールサービスでも当局に利用者のIPアドレスを提供しているからです。

# 匿名仮想通貨

https://vpncafe.net/wasabiwalet/

Wasabi WalletはWindows、Mac、Linuxに対応したビットコイン専用のウォレットです。

# 匿名でドメインを取得

Njalla

ドメインを Njalla 側に渡して管理してもらう。
なので仮に開示請求されても相手のドメインという言い訳ができるようだ。

https://njal.la/



支払いはビットコインでも可能。
匿名で支払いたい場合は、Wasabi Walletというビットコインウォレットがあります。

これを使えば多数の人のコインを混ぜ合わせる、coinjoinという方法を使って、どのアドレスの決済かわからなくすることができます。

vpsも匿名でやっているようだが、日本リージョンがあるか不明。


# 匿名vps (レンタルサーバー)

以下なら日本リージョンがあるみたい。

https://www.vpsserver.com/

以上

いや～時代は変わりますね。
GitHubとSSH接続する方法(Windows)

# はじめに
自身の備忘録として記録する

# SSHってなに？
簡単にいうと暗号通信で、サーバーを遠隔操作する仕組み。
通信データが暗号化される。

ウイルスバスターはPCをウイルスから守るように
SSHは通信を不正アクセスなどから守ることができる。

telnetというサーバーを遠隔操作の仕組みもあるが
こちらはSSHとは違い通信データが暗号化されない。

# GithubとのSSH連携はなぜ必要？
Githubを使用(認証)する方法の1つ

ローカルリポジトリに対しての操作だけで良ければ、SSHキーなどの設定は不要。

GitHub等のリモートリポジトリを利用する場合は、インターネットを経由する通信が発生。
言い換えると、通信回線の先にあるリポジトリとのやりとりが必要になる。

よって、その間の通信の暗号化を行わないとアカウントの乗っ取りなどの被害に遭ってしまう。

そのために設定が必要。


# 実施環境
Windows
Git Bash

mac windows linuxそれぞれで手法が異なるので注意
本記事ではwindowsを使用する。

# すでにSSHキーがPC内にあるか確認する
SSHキーがPC内に存在しているかどうかを確かめる。
何度か作成したことがあれば、複数個ある。

Git bashで下記コマンドを実行
(デフォルトのコマンドプロンプトではできない)

```:SSHキーがPC内に存在しているか確認する
$ ls -al ~/.ssh
```

**SSHキーを同じ名前で作成を進めてしまうと上書き扱いになってしまうので要注意**

# SSHキーを作成する

Git bashで下記コマンドを実行

```:SSHキーを作成する
ssh-keygen -t ed25519 -C "your_email@example.com"
```

-C "~"はコメントなのでコメントが特になければ、入力する必要はない。

```:SSHキーの名前を設定して生成する場合
ssh-keygen -t ed25519 -f file_name
```

ファイル名指定無しで生成した物と別途に生成したい時は
`-f file_name`で生成される鍵ファイル名を指定できる。

カレントディレクトリに生成されるので`cd ~/.ssh/`して事前に移動おくこと。

コマンドを実行すると、パスワードの設定を求められるので、
流れでパスワードの設定を行う。

# SSH agentを起動する
SSH agentは、秘密鍵を自動管理してくれる。常にカギを置いておくのではなく、
秘密鍵を必要な時にだけ、秘密鍵を利用してくれるツール。

```:SSH agentを起動
eval "$(ssh-agent -s)"
```

Agent pid 数字と表示される。

```:生成したSSHキーをSSHエージェントに登録する
ssh-add ~/.ssh/id_ed25519
```
`id_ed25519`は作成した先ほどSSHキーの名前が入る。

# GitHubにSSHキーを登録する

Git bashで下記を実行
```:公開鍵をコピー
clip < ~/.ssh/id_ed25519.pub
```
文字列がコピーされた。Cntl+vでペースト可能。

***～GitHubへ移動～***

1. GitHubのアカウントにログイン
2. 右上のアイコンから「Settings」
3. 左メニューの「SSH and GPG keys」
4. 「New SSH Key」
5. [title]へは鍵の名前、[Key]へは先ほどコピーしたものをctrl+vでペースト
6. 「Add SSH Key」
7. パスワードを求められるので入力して完了

# 接続テストをする
Git bashで下記を実行

```:正しくSSHが機能しているかを確認することができる
ssh -T git@github.com
```

正しく、接続できていればsuccessfullyと出る。


# 参考にしたサイト
https://youtu.be/5Vndfy68yho?feature=shared

https://youtu.be/nkqdhXSwEVs?feature=shared

https://docs.github.com/en/authentication/connecting-to-github-with-ssh/checking-for-existing-ssh-keys

https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent

https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account

https://docs.github.com/en/authentication/connecting-to-github-with-ssh/testing-your-ssh-connection

https://1978works.com/2022/12/07/how-to-connect-to-github-with-ssh-protocol-by-git-for-windows/#ssh-agent

https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/about-authentication-to-github

https://qiita.com/goldbook@github/items/575981f3ec0bc582ea24

https://qiita.com/probabilityhill/items/b5f390e13377ccd20a2b
Power BI workout - ビジュアルレベルのキャッシュ

"ビジュアルレベル キャッシュ"という用語は正式なものではないかもだが、それはレポート表示のパフォーマンスを向上させるための仕組みを指している。

ところで、この仕組みを理解しないままレポートのパフォーマンスを確認してはないだろうか？

データを投影するビジュアルは以下の流れで動作：
1. ビジュアルごとにDAXクエリを生成(クエリは必ずしも一つだけではない)
1. Power BI セマンティックモデル(データセット)に問い合わせ
1. 得られたデータを投影

ビジュアルに適用されるフィルタが変更されるたびに、以下の流れで動作：
1. ビジュアルごとにフィルタを含めたDAXクエリを生成(クエリは必ずしも一つだけではない)
1. Power BI セマンティックモデル(データセット)に問い合わせ
1. 得られたデータを投影

ただし、ビジュアルへの投影に使用したデータはキャッシュされ、再利用される。必要なときだけ Power BI セマンティックモデル(データセット)に問い合わせてその結果からビジュアルに投影するということだ。これは、同じ結果を得られる DAXクエリの評価を繰り返さない最適化戦略なのである。

# 動作を確認する
Power BI Desktop の Performance Analyzer で動作確認は充分だ。

https://learn.microsoft.com/en-us/power-bi/create-reports/desktop-performance-analyzer

ビジュアルにデータを投影するためセマンティック モデル(データセット)に問い合わせが行われる。
DAX クエリの結果が得られるまで 173ms を要し、そのうち DirectQuery による結果が得られるまで 170ms を要したという結果だ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/baa8ccbb-9aef-0506-e5be-7630a6620ddb.png)

次にフィルタを適用した。フィルタが適用された結果を得るために DAX クエリ 188ms そのうち DirectQuery 187ms を要した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/38bf96d3-e5c9-569a-5a92-111d67dce8e4.png)

次にフィルタの変更を適用した、ここでは適用されるフィルタがない状態に。
DAX クエリの評価はされなかったことを示している。DirectQueryも。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/12b64ec4-cac2-8c3e-cbd0-3a2ac4ef120d.png)
再び同じフィルタを適用した。
ここでも DAX クエリの評価はされなかったことを示している。DirectQueryも。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/9ce38f5c-0756-5f59-36b4-74a072410f1c.png)

# 思ったこと🙄
レポートユーザから表示パフォーマンスの改善要求があったということはさ、思いのほか深刻な状態かもしれない。ビジュアルレベルのキャッシュは常に動作しているはずなのにね。


# その他
https://powerbi.connpass.com/

- [Power BI 勉強会 - connpass](https://powerbi.connpass.com/)
- [Power BI Desktop を使い始めるには](http://qiita.com/PowerBIxyz/items/6c4735cb5b5712e70981)
- [Excel で Power Query を使い始めるには](http://qiita.com/PowerBIxyz/items/52e563037b855a099ca9)
私たち「組込屋（エンジニア）」はどこへ行く？（その５）展示会でリアルに会いましょう！　サポートの「中の人」と技術交流しましょう。

前回（https://qiita.com/Cente_mw/items/11b1cb2a73b3a42ba957 ）まで、「技術の空洞化」に対する対策として、我々ミドルウエア屋が出来る事を説明してきました。使えるミドルウェア、信頼できるミドルウェアを使って技術を補完しましょう。。というお話から、そのミドルウェアのライセンス形態において、ソースコードを開示してもらって将来に備えましょうという話題。
更には、PoC（評価の為の）ライセンスなどを利用して、早期にその製品の良否を判断して進めましょう、、というお話をしてきました。

さて、ミドルウェア屋の私が言うのも変ですが、ミドルウェア（ソースコード）の品質で判断できないものがあると思います。どんなに導入実績があっても、ユーザが多くても、自分がそれらの方々と同じに使えるのか？っというところ。まずは、PoCライセンスでお試しくださいというのが、私たちの回答です。その中には、ソースコードを実際に使ってみるという意味のほかに、「サポート」を使ってみてくださいという意味が非常に強くあります。

初めてミドルウエアを導入する際には「ここでエラーする」「ココが理解できない」「動作が不安だ」など、何かしら問題が発生すると思います（これはミドルウエアのバグもありますが、環境固有の問題であることが多いです）。これをどうやって解決するかと言うと、Centeミドルウェアでは「メールで問い合わせ」という方式でサポートを受け取ります。通常の営業日であれば24時間以内には一報を返せるような体制にしています。Botではなく人間なので、お盆休みや正月休み、時にはコロナでお休み、、何てこともあるかもしれませんがご容赦ください。純粋な「このミドルウェアを開発した本人」がメールサポートしています。お客様のなかで、このサポートを「ダイレクトサポート」と呼んでくださる方いて、そのお話を聞いて、それから私たちも「ダイレクトサポート」と言う様になりました。

はて、「ダイレクト」ではないサポートってあるんだろうか？　っという疑問が私たちにありまして、、、よくよく聞いてみると、同業者の中には、開発元が海外であったり開発エンジニアではない人がサポートしているので、「間接サポート」であることがあるんだとか。この場合、言葉の壁だったり、時間を要してしまったり、一般論しか回答してもらえなかったり、、、と、文化の壁も感じたそうです。

我々は、日本（場所はナイショですけど）時間で生活していますし、日本語を母国語としていますのでどんどん、日本語の曖昧さを含んだメールを送ってください。「言葉ではうまく説明できないけど、、、」と言うメールを頂いても「行間」を読みます！
実際、行間を読んで「もしかすると、＊＊＊かもしれませんが、＋＋＋＋な事はありませんか？」と返信することもあります。「確かに＋＋＋＋でした。解決しました。」という1回のメール往復でトラブル解決できることも少なくありません。
このように、メールでダイレクトにエンジニアと技術的に突っ込んだお話が出来る環境って良いと思いませんか？もうこの体制を20年もやってます。20年前は20～30才台だったエンジニアも、、、（以後、自粛）

ミドルウエアを使うユーザとして、ミドルウエアを作ったエンジニアと直接会話ができる機会として、もう一つ「各種技術展示会」があります。そういった展示会は来場者として皆さんのようなエンジニアを想定しているので、大抵各社のブースにエンジニアや技術について詳しい社員が立っています。タダでいくらでも話が聞けますし、各社が一か所に集まる貴重な機会なので技術を学ぶ場として積極的に利用してはいかがでしょうか。

さて、来る11月15日～17日に組込技術の大きな展示会がありますよね。EdgeTech+2023（https://www.jasa.or.jp/expo/ ）です。この展示会に「<b>ミドルウェア屋の開発・サポートをしている中の人</b>」がITbookテクノロジー Centeブースに立ちます。
もっと言うと、Qiita記事を書いている私もブースに居るかも？しれません。（展示会の情報は下記に書いておきます。）「Qiita見たよ」って言ってください！私の株が上がります。(笑)

技術的に困っている事、疑問を持っている事、ライセンスで不安に思っている事、なんでも結構です。
実際に展示会でリアル会話しませんか？　お待ちしています。

<h3>■展示会情報</h3>
展示会：EdgeTech+2023<br>
会　期：2023年11月15日(水)～17日(金)　10:00～17:00（※16日(木)は18:00まで）<br>
会　場：パシフィコ横浜　展示ホール<br>
ITbookテクノロジー Centeブース 小間番号：B-C08<br>


<h3>■今日の閑話</h3>
メールするにせよ展示会のブースで来場者対応するにせよ、お客様対応には、説明の流れ・礼儀正しさなどテクノロジーではない、それなりのスキルが必要です。しかし、エンジニア全員にそれを求めるのはちょっと酷だろうなと思っていて、本記事では「エンジニアがダイレクトに」と書いていますが、比較的それが得意なエンジニアを間に立てることがあります。それでもミドルウエアサポートの本質は「エンジニアレベルでの議論」だという軸足は変わりません。同僚エンジニアに相談する感覚でサポートをご利用いただければと思います。

Cente：
https://www.cente.jp/

お問合せはこちら：
https://www.cente.jp/otoiawase/
【VB.NET】TableRayOutPanelの使い方

## TableRayOutPanelとは
- HTMLのtableタグのように、表を作成できる。
- 列や行も自由に追加削除できる。
- セルには**1つ**のコントロールを埋め込むことが可能。
    - コントロールを埋め込む場合は、デザイナー画面でコントロールを選択し、オプションで"Dock"を"Fill"にする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/cda01ac5-7825-93c2-f0e7-2097d1bdcbfc.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/b1626c73-80b4-addc-5de5-a1cb5e089af0.png)

<br>

## TableRayOutPanelの注意点
1つのセルに対して1つのコントロールしか埋め込めない。

### 1つのセルに複数のコントロールを配置する方法
セルにPanelコントロールを埋め込み、その上にコントロールを置く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/f2870d9f-2395-7292-6831-65ef510442f3.png)

↓ 説明のイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/2bd1660c-9355-4575-04e6-91b08a05d431.png)

<br>

## TabIndexの設定
TabIndexを設定する場合は、**TableRayOutPanelに埋め込んだコントロール**に対してTabIndexを設定すると意図した動作になる。
例：TableRayoutPanelにPanelを埋め込み、その上にTextboxを配置している場合
- TableRayOutPanelのTabIndex：0 or 1
- PanelのTabIndex：フォーカスを移動したい順番で数字を振る。
- TextBoxのTabIndex：Panelに設定した数字より大きい数字を振る。（Panelより大きい数字を振ることでフォーカスが当たるのをあとにする。）

↓タブオーダーの例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3323019/8d90c81d-f19f-a396-d3e1-e32cf11eb058.png)
例：0.1.1
・TableRayOutPanelのTabIndex：0
・PanelのTabIndex：1
・TextboxのTabIndex：1

<br>

## 参考サイト
https://dreamparadaisu.com/visualbasic_37/

https://githiroshi.hatenablog.com/entry/2019/06/08/145415

https://dobon.net/cgi-bin/vbbbs/cbbs.cgi?mode=al2&namber=33060&no=0&jump=1&KLOG=1
HomebrewでPython3をいれてみた：PATHとおらないよ

# HomebrewでPython3系をいれよう

MacのOSをアップデートしたらPython2系がごそっとなくなっていたので、HomebrewをインストールしてPyhon3系を入れることにしました。
苦戦した[Homebrewインストールの道のり](https://qiita.com/Yukidarusan/items/df8fe4fd24793ebd2c6c)をリンクしておきますのでよろしければ参考にしてください。

## Python3系を入れる前にｐyenvインストール
Homebrewのコマンドを利用してpyenvをインストールします。
pyenvはPythonのバージョンを実行内容によって変更することができるものです。
```py
brew install pyenv
```
下記の通りの表示でインストールが表示されます。
```py
==> Installing pyenv
==> Pouring pyenv--2.3.31.arm64_ventura.bottle.tar.gz
🍺  /opt/homebrew/Cellar/pyenv/2.3.31: 1,125 files, 3.4MB
==> Running `brew cleanup pyenv`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
```
正常にインストールが表示されたので、確認しましよう！
```py
yuunoMacBook$ pyenv -v
pyenv 2.3.31
```
バージョンが表示されたので無事Pyenvのインストールが完了しました。
PATHを通すために以下文言を追加します。
```py
echo 'eval "$(pyenv init --path)"' >> ~/.zprofile
echo 'eval "$(pyenv init -)"' >> ~/.zshrc
```
# Pyhon3系をインストール
現在インストールできるPython3系を確認します。
表示から「**3.12.0**」を選択することにします。
```py
[省略]
  3.12.0
  3.12-dev
  3.13.0a1
  3.13-dev
[省略]
```
インストールコマンドは以下です。
```py
pyenv install 3.12.0
```
正常終了を確認。
```py
Installed Python-3.12.0 to /Users/ユーザ/.pyenv/versions/3.12.0
```
:::note warn
ユーザには自身のユーザ名が入ります。
:::

では正常にインストールされているか確認
```py
MacBook$ pyenv versions
* system (set by /Users/ユーザ/.pyenv/version)
  3.12.0
```

今は「**system**」が有効になっているので変更します。
```py
pyenv global 3.12.0
```
変わっていることを確認します。
```py
MacBook$ pyenv versions
  system
* 3.12.0 (set by /Users/ユーザ/.pyenv/version)
```
では満を持してPythonコマンドを打ってみます！
```py
MacBook-Pro$ python --version
-bash: python: command not found
```
ん？？いやいやまてまて、、PATHが通っていないのかな〜確認しましょ。
```py
MacBook$ which python
-bash: which: command not found
```
うそーん。。。ガチャガチャ調べると。。。あれ？「~/.bash_profile」に書き込んでいる人もいるぞ
違いはなんだと、、、調べてみると
使っているshellによって書き込むファイルが違うようです。。。

* zshを使っている場合は~/.zshrcに、
* bashを使っている場合は~/.bash_profile

にそれぞれ書き込む必要があるようです。
じゃあ今回は何を使用しているのか調べましょう。
```py
MacBook$ echo $SHELL
/bin/bash
```
なので書き込んだファイル違うジャーンということで「~/.bash_profile」に書き込む。
```py
 echo 'eval "$(pyenv init --path)"' >>  /Users/ユーザ/.bash_profile
 echo 'eval "$(pyenv init -)"' >>  /Users/ユーザ/.bash_profile
```
:::note warn
権限がないユーザだと書き込めないため、先頭に「sudo」をつけて実行か、root権限ユーザに変更して実行してください。
:::

よし実行！！
```py
MacBook$ which python
```
うん何も表示されないなぜ？
あっソースファイル再読み込みしてなかった！！
ということで再読み込みを実施します。
```py
source ~/.bash_profile
```
3度目の正直！！！

```py
MacBook$ which python
/Users/sukek/.pyenv/shims/python
MacBook$ python --version
Python 3.12.0
```
無事にどちらのコマンドもPATHが通りました！
shellがどちらを使用しているかを確認しなければいけないということを知らず、
今回勉強になりました。
やっとPython3系インストールまでできたと涙がちょちょぎれます。

### 参考
以下サイトを参考にさせていただきました。

https://masanyon.com/m1-mac-python-env-pyenv/

https://anamorphosis.net/tech/pyenv%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6python%E3%81%AE%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E7%AE%A1%E7%90%86%E3%82%92%E8%A1%8C%E3%81%86/

https://zenn.dev/kenghaya/articles/9f07914156fab5
CKA対策vol.1

CKA対策記事vol.1です

## はじめにやること
kubectlコマンドを補完します。これをしておくと、kがkubectlのエイリアスになります。また、tabキーで予測変換を利用できるようになります。ほかにもnamespaceのデフォルト設定や、configのデフォルト設定などやっておくと便利な設定はいろいろありますが、最低限これだけはやっておきましょう。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/1e18a3e7-74af-160b-8fff-a4c715222b71.png)

https://kubernetes.io/ja/docs/reference/kubectl/cheatsheet/#bash

<br>
<br>

## Jsonで欲しいデータを出力する
欲しいデータを-oオプション(output)で出力し、jsonpath={.hoge.fuga.piyo}のようにして欲しいデータだけを指定します。

例：app=cassandraラベルのついたすべてのPodのversionラベルを表示したい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/3acb3686-46f2-54bd-cab0-f69a4e3d5d21.png)

https://kubernetes.io/docs/reference/kubectl/cheatsheet/#viewing-and-finding-resources

<br>
<br>

## static podを立てたい
podを立てたいノードの/etc/kubernetes/manifestディレクトリ配下にマニフェストファイルを配置すれば自動で立ててくれます

https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/#static-pod-creation


<br>
<br>

## Serviceで使うport 3種類まとめ
- nodePort
    - ノードに入ってくるときのポート番号
- port
    - Serviceに入ってくるときのポート番号
- targetPort
    - podに入ってくるときのポート番号
webアプリ(Rails)をDocker化する方法

# はじめに
今回は、既存のwebアプリ(Rails)をDocker化する方法をまとめてみました。
### 条件
- 今回は `Docker compose`を使用して環境構築します
`Docker compose`とは、複数のコンテナを効率的に操作する為のツールです。
- docker-compose up コマンドで rails severを起動し、`http://localhost:3000`でアクセスできるようにします

### 開発環境
- Ruby:3.2.2
- Ruby on Rails: 7.0.6
- Postgres: 12

:::note warn
事前にDockerのインストールが必要です
:::



### 1. リモートリポジトリ(docker-rails)をクローンしてローカルに持ってくる
```
$ git clone (docker-railsリポジトリのURL)
$ cd docker-rails
```

### 2. Dockefileを作成
```
$ touch Dockerfile
```
Dockerfileの中身を以下にする
```Dockerfile
# ベースイメージの選定
FROM ruby:3.2.2

# パッケージのインストールと更新
RUN apt-get update && apt-get install -y build-essential libpq-dev nodejs

WORKDIR /rails-docker

COPY Gemfile Gemfile.lock /rails-docker/

# Gemをインストールするコマンド
RUN bundle install

ADD . /rails-docker

```

### 3. docker-compose.ymlを作成
```
$ touch docker-compose.yml
```
```docker-compose.yml
# バージョンを選定
version: '3'

services:
# dbコンテナ
  db:
    image: postgres:12
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - postgresql-data:/var/lib/postgresql/data

# webコンテナ
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    ports:
      - '3000:3000'
    volumes:
      - '.:/rails-docker'
    depends_on:
      - db
volumes:
  postgresql-data:
    driver: local
```

### 4. database.ymlを編集する

```database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: postgres
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  <<: *default
  database: myapp_development
```

### 5. コンテナを作成し、起動する
docker image を作成します
```
$ docker-compose build
```
コンテナの作成、起動する
```
$ docker-compose up -d
```

### データベースの作成
先ほどつくったコンテナの中に入る
```
$ docker-compose exec web bash
```

Railsのデータベースを作成する
```
$ rails db:create
$ rails db:migrate
$ exit
```
### 6. ブラウザで`http://localhost:3000`にアクセスする
設定が完了したので、アプリを起動して確認します。
```
$ docker-compose up
```
`http://localhost:3000`にアクセスして。アプリがきちんと表示されれば完了です！
M2 Mac で Evolution Gym の環境構築


# はじめに

Apple Silicon 環境(Rossetaモード)で Evolution Gym の環境構築する方法の1つとして共有します。
基本的には公式の導入の仕方に従います。

https://github.com/EvolutionGym/evogym

# 手順

### 1. TerminalをRossetaモードで実行する

https://blog.looseknot.jp/mac/m1mac_terminal_rosetta.html

以下の操作は Rossetaモードで実行したTerminalで行います。

### 2. miniconda3をインストール

MacOS x86_64用の miniconda インストールします
```
mkdir -p ~/miniconda3
curl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -o ~/miniconda3/miniconda.sh
bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3
rm -rf ~/miniconda3/miniconda.sh
~/miniconda3/bin/conda init zsh 
source ~/.zshrc
```

### 3.Evolution Gym の導入

Evolution Gym を取得し、conda で仮想環境を構築します。
```
git clone --recurse-submodules https://github.com/EvolutionGym/evogym.git
cd evogym
conda env create -f environment.yml
conda activate evogym
```

次に Evolution Gym を Python から呼び出せるようにするためビルドしますが、あらかじめ cmake をインストールしないとビルドに失敗します。

```
pip install cmake
python setup.py install
```

ここまで正常に実行できれば、環境構築は終了です。
最後に以下で動作確認をします。

```
python examples/gym_test.py
```

![スクリーンショット 2023-11-06 12.43.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388185/3db2f56a-f535-a753-7337-090109949bef.png)
特定のパス配下でALEの設定を変更したい


NeovimでALEを使っていて、特定のワークスペース配下でALEの設定を変更したかった。
この記事では、特定のワークスペース配下でrubocopのexecute pathを変える。

```
/path/to/my_workspace/** → この場合のみALEの設定を変更したい
それ以外 → ALEのデフォルト設定
```

ALEでは、buffer変数を定義することで、そのbufferでの設定を変更できる様。

https://github.com/dense-analysis/ale

そのため、autocmdを用いてbufferを開いたときにbuffer変数を定義するようにした。

最終的に、以下のような設定になった。

```lua
local my_group = vim.api.nvim_create_augroup("MyGroup", { clear = true })
vim.api.nvim_create_autocmd({ "BufNewFile", "BufRead" }, {
  group = my_group,
  pattern = vim.fn.expand("$MY_WORKSPACE_PATH") .. "**",
  callback = function(event)
    vim.api.nvim_buf_set_var(event["buf"], "ale_ruby_rubocop_executable", "path/to/rubocop")
  end,
})
```

## Refs

- https://github.com/dense-analysis/ale
Unityでmodalを作る

やりたい事、Prefabでモーダルを作っておく。呼ぶだけでモーダルが出るようにする。モーダル側にある閉じるボタンやOK、キャンセルなどはコールバック関数で持ってこれるようにする。

Modal自体はGUIで普通にcanvas上で作ってprefabにしておく。

ModalManagerというクラスがついてる、modalPrefをprefabにしておく。
```
modal = Instantiate(modalPref).GetComponent<ModalManager>();
modal.onOpen += modalOpen;//モーダル側からのコールバック
modal.onClose += modalClose;//モーダル側からのコールバック
```
こんな感じにできたら良いなと思いました。

ModalManagerに入れておくと良いのが、
```
//ModalManager内
public delegate void EventHandler();
public event EventHandler onClose;
public event EventHandler onOpen;
```
この宣言をしておく、そして、これを親側のクラスにコールバックしたい時は、
```
//ModalManager内
onOpen();
```
とかしておく。これをprefab内でクリックなどに結びつけておけば問題ない。

これをするとprefabは追加されるが、うまくいかない部分が出てくる。自分の任意のcanvas内に配置がされない。ので

```
modal.transform.SetParent(canvas.transform,false);
```
をする。この時２つ目の値がfalseなのだが、例えばウインドウサイズに合わせてキャンバスのサイズを変えてる場合などに、倍率がおかしくなってしまうのでその機能をオフにしている

次のモーダルの方は、画面いっぱいに広げたいので、

```
//ModalManager内
public void open()
{
    GetComponent<RectTransform>().anchorMin = Vector2.zero;
    GetComponent<RectTransform>().anchorMax = Vector2.one;
    GetComponent<RectTransform>().offsetMin = Vector2.zero;
    GetComponent<RectTransform>().offsetMax = Vector2.zero;
}
```

としておく、これで完成です。
```
//MainManager
modal = Instantiate(modalPref).GetComponent<ModalManager>();
modal.transform.SetParent(canvas.transform,false);
modal.open();
modal.onOpen += modalOpen;
modal.onClose += modalClose;
```

でモーダル側は
```
public class ModalManager : MonoBehaviour
{

    public delegate void EventHandler();
    // イベントを宣言
    public event EventHandler onClose;
    public event EventHandler onOpen;


    public void setData()
    {

    }
    
    public void open()
    {
        GetComponent<RectTransform>().anchorMin = Vector2.zero;
        GetComponent<RectTransform>().anchorMax = Vector2.one;
        GetComponent<RectTransform>().offsetMin = Vector2.zero;
        GetComponent<RectTransform>().offsetMax = Vector2.zero;
    }
    public void close()
    {

    }


    public void onClickBG()
    {
        Debug.Log("BG CLICK");
        onOpen();
    }
    public void onClickClose()
    {
        Debug.Log("CLOSE CLICK");
        onClose();
    }

}
```
publicにしているのでタイトルや本文のデータなどを入れることができる状態にしている。こんな感じの概要でUnityでのモーダルを作れた。
【ChatGPT】を無料版→有料版へと、クレカなしでもほかの方法でアップグレードします。


　どうも、カーブミラーです。

　今回は、ChatGPTアプリ（同時にweb版も）、クレカなしでアップグレードします。しかも家計にやさしく。別に裏道の紹介ではありませんよw

:::note info
本記事はChatGPTの無料版から
有料版へのアップグレードを扱
っております。あしからず。
:::
　ようやく
　　ChatGPT Plusに
　　　加入しました。

　ようやくぅ？
　　とか言わないでください。

　これまでは、
　　加入したくても
　　　クレジットカードがなくて
　　　　できませんでした。

　そう、私は、
　　クレジットカードを
　　　持たない人です。

　以前はあったけど、
　　若気の至りで、
　　　ちょいと借金になりました。

　たいした額ではない。
　　とはいえ、借金には違いない。

　借金返済は、
　　ちと大変でした。

　それはともかく、
　　クレジットカードは
　　　持たない方が、と判断。
　　　　今に至ります。
***
　それもともかくw
　　本題です。

　今回のきっかけは
　　以下のニュースを
　　　見てのものです。
[「Google Play」のアプリやアプリ内コンテンツなどを「PayPay」で決済可能に](https://about.paypay.ne.jp/pr/20231026/02/)
***

　契約時のプロセスを見よう。

　あっ、言っておきます。
　　今回の内容は、
　　　アプリからの
　　　　契約なので、
　　　　　アプリにログインを
　　　　　　しておいてください。
***
　OpenAIでは、
　　支払いは、
　　　クレジットカードのみと
　　　　決まっています。

　しかし、
　　アプリは、
　　　どこから
　　　　ダウンロードしますか？

　Google Playか
　　Apple Storeですよね。

　だから、
　　そこ経由での支払いを
　　　すれば、いいわけです。

　注意！
　　私はAndroidスマホユーザー
　　　なので、Apple Storeでの
　　　　決済については、
　　　　　何も知りません。

　ただ、
　　それほどの違いはない
　　　と考えてはいます。
　　　　管理する側は、
　　　　　面倒なことは
　　　　　　考えません。たぶんw
***
　では、手順を説明します。

　今回は、スクショ付き。

　まずは、
　　メインメニューを開きます。

　そこから
　　Subscriptionをタップ。
![Screenshot_20231103-173027~2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/40af3404-012c-def7-08ab-0ae1d5a022f7.png)

　すると、
　　次の画面が現れます。

　少しすると、
　　下部に、ボタンが現れます。
　　　これをタップ。
![Screenshot_20231012-000501.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/4be42308-af5c-ffd0-1d75-3718bd8e9fc3.png)

　ここで、
　　Google Playの
　　　[お支払いと定期購入] が
　　　　表示されます。
![Screenshot_20231104-090834~2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/b507b679-df38-26e4-2522-550f2c610b0a.png)

　ここで、
　　支払い方法を選ぶわけです。

　人によっては、
　　アプリは無料版だけ、
　　　という人もいて、
　　　　支払い方法が限られている
　　　　　こともあります。
　　　　　　（自分のことですw）

　クレジットカードが
　　なくても、大丈夫です。

　QRコード決済なんかを
　　使えるならば、
　　　画面下部に、
　　　　選択肢が出ています。
　　　　　たぶん白黒の図と文字だけ。

　選択して、
　　上部の選択肢から、
　　　方法を選ぶだけです。

　ここ、スクショ、撮り忘れましたw
　　すでに、PayPayが登録した
　　　あとのスクショです。

　このあと、
　　購入を継続するか、
　　　尋ねてきます。

　私は、念のため、
　　毎月の支払い時に
　　　お知らせしてもらうことに
　　　　しました。

　無意識に、
　　お金を吸われない
　　　ようにするためです。
　　　　家計管理は
　　　　　しませんとねw

　あとは、
　　実際に
　　　使ってみてください。
***
　ちなみに、
　　家計にやさしい部分は、
　　　20米ドルの支払いではなく、
　　　　2860円固定の支払いに
　　　　　なります。

　2023年11月2日午後8時35分
　　現在の三井住友銀行の
　　　リアルタイム為替レート
　　　　によると、
　　　　　20米ドルは
　　　　　　3008.70円です。﻿

　ところが、Google Play経由だと、
　　2860円固定。なのです。

　ここで、132円ほどの開き。
　　年間 1584円の差。

　もちろん、
　　今後、円安ドル高が
　　　進行すれば、この差は
　　　　広がっていくことでしょう。

　そうなれば、
　　同じ額でも、違いは
　　　開いていきます。

　だからなんだ、と言われれば
　　何も、と言うしかない。

　すでに、
　　クレジットカードでの
　　　支払いをしているユーザーは
　　　　切り替えることも
　　　　　面倒でしょうし、
　　　　　　円高に転じるかも
　　　　　　　しれません。

　各人の判断に任せます。
　　こればかりは、
　　　私に決定権がありませんから。
***
　これからも
　　できるだけ、
　　　無料版を中心に
　　　　書いていきます。

　今回は、ここまで。
製作精彩的Statement of Purpose


在追求[海外實習](https://www.apexcharity.org/news/3/87)機會時，一份出色的[英文履歷](https://www.apexcharity.org/news/3/91)（[CV](https://www.apexcharity.org/news/3/88)）是至關重要的，但更重要的是你的[Statement of Purpose](https://www.apexcharity.org/news/3/90)（SoP）。SoP是你向潛在雇主或教育機構展示自己的機會，因此它應該能夠引人入勝，讓你脫穎而出。本文將分享一些建議，幫助你製作一份精彩的Statement of Purpose。

1. 認識Statement of Purpose的重要性

在著手製作你的SoP之前，首先要理解它的重要性。一份出色的SoP可以突顯你的目標、動機和適應性，有助於你在眾多申請者中脫穎而出。它不僅是一份文件，更是你個人故事的體現，讓對方更深入地了解你的專業和個人素質。

2. 瞭解所申請的領域和機構

在撰寫SoP之前，深入了解你所申請的領域和機構是至關重要的。了解他們的價值觀、目標和文化，並確保你的SoP能夠與其相契合。請確保你的目標和理想與所申請的機構相輔相成，這樣你的申請才能更具說服力。

3. 突顯你的獨特性

SoP應該突顯你的獨特性和優勢。不要只是列出你的學術和專業背景，還應該分享你的經驗、成就和價值觀。請思考你的獨特賣點，並在SoP中展現出來。這有助於讓你在眾多申請者中脫穎而出。

4. 關注你的目標和動機

SoP應該清晰地表達你的目標和動機。請誠實地談論你為什麼選擇這個領域或機構，以及你希望實現的目標。你的動機應該引人注目且有說服力，讓讀者能夠理解你的決心和承諾。

5. 精簡和校對

最後，確保你的SoP內容精簡而有條理。不要使用冗長的句子或過多的詞語。同時，務必多次校對和修改，以確保語法和拼寫無誤。一份充滿錯誤的SoP可能會給對方留下不好的印象。

總之，製作一份引人入勝的Statement of Purpose需要時間和努力，但它是你在海外實習或申請機會中成功的關鍵。請記住以上的建議，並在撰寫SoP時盡力展現出你的獨特性、動機和承諾，這將有助於你實現你的目標。
Google Chrome のサードパーティー Cookie の廃止



+ [Google Chrome のサードパーティー Cookie の廃止が Open CTI に影響を与える可能性](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007Pgi4zSAB)

https://help.salesforce.com/s/articleView?id=000396744&type=1



+ [Google ending third-party cookies in Chrome](https://www.cookiebot.com/en/google-third-party-cookies/)
このブログ投稿では、Chrome でのサードパーティ Cookie の終了に関する影響、誤解、現在および将来において同意が準拠した追跡のプラットフォームとなる理由について考察します。

他には影響を受ける製品はないのかと思い、ざっくり調べてみると...

+ [Chrome の SameSite に関する変更と Account Engagement](https://help.salesforce.com/s/articleView?id=000381318&type=1)

:::note
ユーザセキュリティを改善するために、Chrome はサードパーティの Cookie 機能を停止する可能性のあるデフォルトで保護されたモデルに移行します。2020 年 7 月 14日以降、ブラウザがデータを Account Engagement に送信するためには、すべてのサードパーティ Cookie には SameSite 属性が設定され、かつ、HTTPSが使用されているサイト​である必要があります。

​この変更は、Account Engagement でプロスペクトを追跡する能力に影響を与える可能性があります。 Account Engagement は、変更後も追跡が機能し続けるように、サードパーティ Cookie に SameSite 属性を付与する更新作業を行っています。ただし、貴社が Account Engagement で追跡しているサイトが HTTPS を使用しない場合は、トラッキングが期待どおりに動作するようにそれらを HTTPS に変換する必要があります。
:::

+ [3rdパーティークッキーの規制とPardotでの対応（1stパーティークッキーの活用）](https://sfdctechsite.com/2022/02/21/pardot_cookie/)
Juliaをwindows7 で使う場合のconda

いまさら必要があってwindows7にインストールしたけどやっぱり古いものだと環境問題が付きまとうので備忘録

```
julia> using Pkg
julia> Pkg.update()
julia> Pkg.add("Conda")
julia> Pkg.build("Conda")
julia> import Conda
julia> Conda.update()
```

通常はjuliaをインストールした後以上のコマンドを実行するがCondaはそのままだとエラーを起こすのでminicondaを自分でインストールする。
https://repo.anaconda.com/miniconda/
python3.9は7では使えないので3.8以下を選ぶ。ちなみに自分はMiniconda3-py38_4.10.3がエラーの起きない最新版だった。
そのフォルダのパスをjuliaで以下のように設定する。

```
julia> ENV["CONDA_JL_HOME"]=raw"path\miniconda" 
julia> ENV["CONDA_JL_CONDA_EXE"]=raw"path\miniconda\Scripts\conda.exe"
```
なおminicondaのバージョンでconda.exeの場所は変わり、_conda.exeのような似た名前のファイルもあるので注意。
そのごPkg.add("Conda")以下を実行すればエラーがminicondaが原因だった場合問題なく完了できる。

また以下のような設定は.juliaにconfig/startup.jlを作って書いておけば保存できる。
```
julia> ENV["PYTHON"]=""
julia> ENV["JULIA_SSL_CA_ROOTS_PATH"]=""
```


いろいろ試してみたが、古いものを使っている限りエラーは付きまとうのでバージョンを指定するのが一番早い。あとメモリが足りなくなるエラーも多いので構築時にほかのプログラムは閉じるべき。
```
#PlotsでおきたGR_jllのエラーの場合
]add GR_jll@0.72.8
```
おまけ
```
#一応これでもCondaを指定できるが今回は1.9.1までしか選べなかった。
Pkg.add(Pkg.PackageSpec(;name="Conda", version="1.9.1"))
```
後から考えるとCondaも指定すればエラーなかったかも
[Tailwind CSS IntelliSense] django-htmlでクラス名が補完されない

## Context

- Djangoを使ったウェブアプリ開発
- VS Codeでコーディング
- Tailwind CSS IntelliSenseで、CSSのコーディングを効率化したい

## Issue

django-htmlファイルでTailwind CSS IntelliSenseの補完が効かない。cssファイルでは問題なく機能している。

## Solution

空の`tailwind.config.js`ファイルをプロジェクト直下に置く。

ディレクトリ構成によってはこのファイルがトリガーされない場合があるから、形式的にこのファイルを一番上に置くと作動する?
本質的な解ではないけど、これで保管されるようになった。

stack overflowの[こちらのポスト](https://stackoverflow.com/questions/76663138/tailwind-css-intelisense-not-workin-in-vscode-while-working-on-django-html-page)を参照。
WKWebViewのWKWebsiteDataStoreを削除する方法

## 要件
WKWebViewのLocalStorageに設定している値をアプリ起動時やアカウント切り替え時などにネイティブ側で削除したい。

## Data Store Record Types
https://developer.apple.com/documentation/webkit/wkwebsitedatarecord/data_store_record_types

## 削除方法
参考：WebCacheCleaner.swift
https://gist.github.com/insidegui/4a5de215a920885e0f36294d51263a15

```WebViewModel.swift
/// WebViewのDataStoreの値を初期化する
private func cleanWKWebsiteDataRecord() {
    // Cookieデータを削除
    HTTPCookieStorage.shared.removeCookies(since: Date.distantPast)
    
    // WKWebsiteDataStoreからWebサイトデータを取得
    WKWebsiteDataStore.default().fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes()) { records in
        records.forEach { record in
            // 特定のデータレコードを削除
            WKWebsiteDataStore.default().removeData(ofTypes: record.dataTypes, for: [record], completionHandler: {})
        }
    }
}
```

## 確認方法
```WebViewModel.swift
/// ローカルストレージの値をデバッグ出力する
private func printLocalStorageValue() {
    webView.evaluateJavaScript("localStorage.getItem('hoge-key')") { result, error in
        if let error = error {
            print(error)
            return
        }
        print("hoge-keyの値: \(result ?? "nil")")
    }
}
```