OmniAICreator/Qiita-1.07M huggingface dataset:
Grafana/Prometheus/Lokiで自宅ネットワークの監視基盤を作る

# 背景・モチベーション
  自宅ネットワークのサーバ数が10台を超え、ノード、コンテナの監視がしたい
  datadogの無料プランを利用していたが、利用枠が不足した
  このため、オンプレで稼働する監視基盤構築のためPrometheus/Grafana/Lokiを利用する

# 構成
  - 監視対象: Linuxサーバ(Debian/Ubuntu/CentOS) および MacMini
             　　　　一部、室温センサーなどの情報をExpoterterで取得する
  - 監視基盤: Grafana/Prometheus/Lokiのクラスタをdocker-compose上で実行

## Prometheusとは
  Pull型の監視用ツール
  Kubernetesと関連が強く、おそらく大量のマイクロサービス化されたコンテナを対象として想定されている
  いわゆるエージェント型で、監視対象(サーバ)にExporterと呼ばれる
  メトリック、トレース、ログのトレース以外の部分の監視が対象
  PromQLというクエリ言語でデータが取れる
  Expoter側で情報にラベルを付与可能
  ラベルごとにデータを集計できたりする
## Grafanaとは
  可視化ツール
  ElasticStackのKibanaに相当する(ElastaicsearchがLoki/Prometheusに相当？)
  バックエンドにElasticsearch/CloudWatchLogs/Datadogなどを設定できる
  ダッシュボード作れる
## Loki とは
　ログに相当するもの
　Fluent-bitのOutputで簡単に連携が可能
　CloudWachLogs/Elasticsearchのような各行データを保持する
## Exporterとは
  監視対象に設定するエージェントのようなもの
　Exporterは1サーバに1つではなく、監視のスコープ毎に個別に設定する
　ExporterにはPrometheusからhttpでリクエストが送信され、監視対象の情報を返す
  基本的にはPlain/text形式で下記の形式で情報を返す
　Apache/Nginx/Haproxyなどは大体アドオンでExporter形式の情報を集約可能
　datadogエージェントも実は内部的にこれが動いてる？
　Gitlabのオンプレ版にはExpoterterが内蔵されていて、configで有効化可能
　サーバサイドの情報はHELP、TYPE、実際の値(下記例)で記載するとPrometheus側でデータ取得してくれる
　TPYPEにはcounter、gauge、histogram、summaryがある
```
# HELP temperature this is bedroom temperature
# TYPE temperature counter
temperature{room="bedroom",device="bme280"} 19.63
```
## 監視基盤構成
  下記、docker-compose.ymlで設定する
　prometheus/lokiについては、データ保持をローカルストレージで行うため、ストレージ領域をVolume共有している
　※ docker-composeの起動時にデータがリセットされないため
  Grafanaについてはdashboards
#### docker-compose構成
``` docker-compose.yml
version: '3'
services:
  prometheus:
    image: prom/prometheus
    container_name: prometheus
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
      - ./prometheus/storage:/prometheus
    ports:
      - '9090:9090'
    dns:
      - 8.8.8.8
  loki:
    image: grafana/loki
    container_name: loki
    volumes:
      - ./loki/storage:/loki
    ports:
      - 3100:3100
    command: -config.file=/etc/loki/local-config.yaml
  grafana:
    image: grafana/grafana
    container_name: grafana
    environment:
      - GF_INSTALL_PLUGINS=marcusolsson-treemap-panel
    ports:
      - "3000:3000"
    volumes:
      - "./grafana/datasources:/etc/grafana/provisioning/datasources"
      - "./grafana/dashboards:/etc/grafana/provisioning/dashboards"
```


## 参考文献
  入門 Prometheus ―インフラとアプリケーションのパフォーマンスモニタリング
　https://www.amazon.co.jp/%E5%85%A5%E9%96%80-Prometheus-%E2%80%95%E3%82%A4%E3%83%B3%E3%83%95%E3%83%A9%E3%81%A8%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E3%83%91%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%B3%E3%82%B9%E3%83%A2%E3%83%8B%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0-Brian-Brazil/dp/4873118778
「2022年に向けての抱負」のふりかえり

昨年末に下記のようなことを書きました．

https://qiita.com/zacky1972/items/9c9236a302964155756d

下記をあげていました．

1. NxにPelemay技術を応用したPelemay Backendを作りたい
1. evisionにPelemay技術を応用したい
1. Elixirで人工衛星画像処理システムを実装したい
1. 複数の環境下のテストを自動化するastestingを作りたい
1. ARMとRISC-Vを推して消費電力あたりの性能を追求したい
1. https://dev.to/zacky1972 に英語技術情報を蓄積していきたい

それぞれ，ふりかえっていこうと思います．

# NxにPelemay技術を応用したPelemay Backendを作りたい

これについては，無事年内にプロトタイプができました．

https://github.com/zeam-vm/pelemay_backend

このプロトタイプを踏まえて，2023年1月に第64回プログラミング・シンポジウムで発表します．プロトタイピングで得られた考察を踏まえて，より堅牢な作りに生まれ変わる予定です．

# evisionにPelemay技術を応用したい

これについては，[A-STEPトライアウト](https://zacky1972.github.io/blog/2022/03/29/sar-apps.html)の研究成果として，ElixirConf US 2022に下記のような発表をしました．

https://youtu.be/RkMzCQm-Ws4

株式会社オーイーシーに技術移転し， @RyoWakabayashi さんが次のような素敵記事を書いて，引き継いでくださいました！

https://qiita.com/RyoWakabayashi/items/45a7daccf064b8720ad0

https://qiita.com/RyoWakabayashi/items/60d0aec59d7d6cc65f9c

https://qiita.com/RyoWakabayashi/items/1a83c962ae03791a988c

https://qiita.com/RyoWakabayashi/items/ef858baebecf84028a14


# Elixirで人工衛星画像処理システムを実装したい

これについては，下記研究成果を得ました．

https://zacky1972.github.io/blog/2022/03/29/sar-apps.html

下記のようなプロジェクトを立ち上げ，より発展させようとしています．

https://zacky1972.github.io/blog/2022/03/04/sar-data-processing-satellites.html

# 複数の環境下のテストを自動化するastestingを作りたい

この抱負の元となった下記記事からは，その後，発展させる余裕がありませんでした．

https://qiita.com/zacky1972/items/c8410e6cc3bb76b4b437

# ARMとRISC-Vを推して消費電力あたりの性能を追求したい

ARMについては，下記のような研究プロジェクトを立ち上げました．

https://zacky1972.github.io/blog/2022/03/03/nx-accel.html

RISC-Vについても水面下で研究を進めてきました．不甲斐ないため，なかなか表に出せる状況にならないのが申し訳ないです．

# https://dev.to/zacky1972 に英語技術情報を蓄積していきたい

2022年1月中は熱心に記事を書いていたのですが，その後，少し気持ちが離れてしまいましたね...

https://dev.to/zacky1972/

# まとめ

「2022年に向けての抱負」について，それなりに有言実行を果たせたようです．
ショートカットキーでXfceのパネルを開閉する

# 経緯
Xfceではマウスポインタを画面端に接触させることでワークスペースを移動できる。
この機能を気に入っていたが、隠れているパネルを開く際の動きと競合してしまう。
そこで、競合を避けるためにパネルの開閉をキーボードで操作したいと考えた。

# 方針
`xfconf-query`を使用してパネルの設定の`パネルを自動的に隠す`のプロパティを書き換えるシェルスクリプトを作成する。
このシェルスクリプトにキーボードショートカットを割り当てて目的の操作を実現する。

## xfconf-query
Xfceは設定オプションをXfconfに保存している。Xfconfの内容は`設定マネージャー > 設定エディター`で見ることができる。
`xfconf-query`はこのXfconf内の設定にアクセスするためのCLIツール。今回は主にこのツールを利用して実装を進めていく。

# 環境
- Manjaro 22.0 Sikaris
- Xfce4.18

# パネルの開閉
今回はパネル1を開閉することにする。
まずは以下のコマンドを実行してパネルが現れることを確認する。
```shell:パネルを表示させる
$ xfconf-query -c xfce4-panel -p /panels/panel-1/autohide-behavior -s 0
```
このコマンドでは、`-c`オプションで`xfce4-panel`チャネルを指定し、`-p`オプションで`/panels/panel-1/autohide-behavior`プロパティを指定、`-s`オプションで値に`0`を設定している。
このコマンドが行なっていることは、GUIの設定画面でパネルの`パネルを自動的に隠す`の項目を`しない`に設定していることに対応する。
`panel-1`の数字の部分がパネルの番号によって異なるので、操作したいパネルに応じて数字を書き換える必要があることに注意。

逆にパネルを閉じたい場合は先程のプロパティに2を設定すれば良い。（&rarr;`パネルを自動的に隠す`を`常に`に設定）
これでマウスポインタがパネル上にいないなければパネルは自動的に隠れる。
```shell:パネルを隠す
$ xfconf-query -c xfce4-panel -p /panels/panel-1/autohide-behavior -s 2
```
ショートカットキーでパネルの開閉を切り替えたいため、これらのコマンドをシェルスクリプトにまとめる。
今回は`/usr/bin/`に`myPanelSwitcher`というファイル名で作製した。
```shell:myPanelSwitcher
#! /usr/bin/bash

nowConf=`xfconf-query -c xfce4-panel -p /panels/panel-1/autohide-behavior`
if [ $nowConf -eq 0 ]; then
  xfconf-query -c xfce4-panel -p /panels/panel-1/autohide-behavior -s 2
else
  xfconf-query -c xfce4-panel -p /panels/panel-1/autohide-behavior -s 0
fi
```
以下のコマンドで実行権限を与える。
```shell
$ chmod +x /usr/bin/myPanelSwitcher
```
ターミナルで`myPanelSwitcher`を実行すると交互にパネル1の表示&rlarr;非表示(`パネルを自動的に隠す`:`しない`&rlarr;`常に`)が切り替わるはずである。

# ショートカットキーの割り当て
最後に先程のシェルスクリプトにショートカットキーを割り当てる。
`設定マネージャー > キーボード > アプリケーションショートカットキー`に新しい項目を作成する。
左下の`追加`を押すとポップアップが現れる。コマンドに`myPanelSwitcher`を入力して`OK`。
するとまた新しいポップアップが開くので設定したいショートカットキーを押す。

これで登録したショートカットキーを押せばパネルが開閉するようになる。

# 追加の設定
以上で当初の目的は達成したが、使い勝手を良くするためにいくつか追加の設定をする。
## パネル表示時のウィンドウ最大化
画面端に接触しているパネルが表示されているときにウィンドウを最大化すると、パネルの幅の分だけウィンドウが表示される領域が狭くなってしまう。
そこで、パネルの設定から`パネルをウィンドウの上に置く`にチェックを入れておくと、パネルが表示されていてもウィンドウを最大化したときにパネルに重ねてウィンドウを表示することができる。
`パネルを自動的に隠す`の設定項目で`しない`を選択しておかないとチェックが入れられないので注意。

## パネルが隠れ始めるまでのラグ
パネルを閉じるときに、シェルスクリプトで設定を変更してから隠れるまでラグが生じる。
このままでは使いづらいので、ショートカットキーを押したらすぐにパネルが隠れるようにする。
まずテキストエディタで`~/.config/gtk-3.0/gtk.css`を開く。（ファイルがない場合は作成する）
以下の内容を書き込んで保存する。
```css:~/.config/gtk-3.0/gtk.css
* {
  -XfcePanelWindow-popdown-delay: 0;
}
```
ターミナルで以下のコマンドを実行してxfce4-panelをリセットして変更を適用する。
```shell
$ xfce4-panel -r
```

## パネルが閉じるスピード
パネルが閉じるときのスピードを設定することができる。
以下のコマンドでは100msかけて閉じるように設定している。末尾の数字を変えれば任意のスピードに設定できる。
```shell
$ xfconf-query -c xfce4-panel -p /panels/panel-1/popdown-speed -s 100
```
パネルが開くときのスピードも変更したかったが、こちらは設定項目が見つからなかった。

# 参考
- [Xfce - ArchWiki](https://wiki.archlinux.jp/index.php/Xfce)
- [xfce:xfconf:xfconf-query [Xfce Docs]](https://docs.xfce.org/xfce/xfconf/xfconf-query)
- [xfce:xfce4-panel:preferences [Xfce Docs]](https://docs.xfce.org/xfce/xfce4-panel/preferences)
- [xfce:xfce4-panel:theming [Xfce Docs]](https://docs.xfce.org/xfce/xfce4-panel/theming)
Outlook VBAのmoveメソッドで移動できないアイテム対応（エラーハンドリングで処理をスキップ）



Outlook の[クリーンアップツール](https://support.microsoft.com/ja-jp/office/%E3%82%A2%E3%82%A4%E3%83%86%E3%83%A0%E3%82%92%E6%89%8B%E5%8B%95%E3%81%A7%E6%95%B4%E7%90%86%E3%81%99%E3%82%8B-ecf54f37-14d7-4ee3-a830-46a5c33274f6)を使ってメールのアーカイブをしようとしたところ、うまく保管出来ない（移動元のフォルダにメールが残ってしまう）事象が発生。
クリーンアップツールを何度試してもメールは移動せず、手動でやろうにも対象ユーザーのフォルダ構成が広大すぎたので、Outlook VBAで振り分けマクロを作成することに。

フォルダ内アイテムの移動にはMoveメソッドを利用したが、それで移動できないアイテム種別と対応について記載。

# 移動できないもの

検知した範囲では以下。

- 会議出席依頼
- [送信済メッセージの修正・取り消し通知](https://support.microsoft.com/ja-jp/office/%E9%80%81%E4%BF%A1%E3%81%97%E3%81%9F%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%92%E5%8F%96%E3%82%8A%E6%B6%88%E3%81%99-%E3%81%BE%E3%81%9F%E3%81%AF%E7%BD%AE%E3%81%8D%E6%8F%9B%E3%81%88%E3%82%8B-35027f88-d655-4554-b4f8-6c0729a723a0)
   - 送信側が**移動-アクション-メッセージの編集/取り消し**を実行した際の受信側通知


おそらく他にもあるが、途中でエラー全部をスキップするようにしたため、未調査。



# 対応

## アイテムのタイプを調べて処理を飛ばす

対象アイテムのTypeNameがMailItemでない場合に、Gotoで処理を飛ばします。

```
sub
    For itemIndex = sourceFolder.Items.Count To 1 Step -1
        ' check the type of the item at the given index
        If TypeName(sourceFolder.Items.Item(itemIndex)) <> "MailItem" Then
            ' skip this item, since it is not an email
            GoTo Skipitem
        End If

        Set email = sourceFolder.Items.Item(itemIndex)
        email.Move destinationFolder
    Skipitem:
    Next

end sub

```

この方法で会議出席依頼は処理をスキップ出来たのですが、送信済メッセージの修正・取り消し通知は「このクラスはサポートされていません」のエラーで動作せず。
該当のアイテムはOutlook VBAで処理できないようです。
※エラーメッセージの詳細・情報ソースは失念しました。発掘出来たら追記。


## エラーハンドリングを使って、エラーが出たら処理を飛ばす

上記のアイテムや、ユーザー環境の未知のエラーに対応するため、エラーが出たら全部処理を飛ばす方法で回避。
前述のコードに追記しているので、メールアイテムの種類を確認してスキップする処理入れてありますが、おそらく不要。

記述順序の通りの処理順序とならないので混乱しそうですが、エラーが出た際は以下のような動作。

1. On Error GoTo ErrorHandlerでErrorHandler:に飛ぶ
2. Resume Skipitem でエラーを無視してSkipitem:に飛ぶ
3. NextでForに戻る

```
sub
    On Error GoTo ErrorHandler ' エラー発生時にErrorHandlerラベルにジャンプするように設定

    For itemIndex = sourceFolder.Items.Count To 1 Step -1
        ' check the type of the item at the given index
        If TypeName(sourceFolder.Items.Item(itemIndex)) <> "MailItem" Then
            ' skip this item, since it is not an email
            GoTo Skipitem
        End If

        Set email = sourceFolder.Items.Item(itemIndex)
        email.Move destinationFolder

    Skipitem:
    Next
    On Error GoTo 0 ' エラー処理を解除する

    ErrorHandler:
    If Err.Number <> 0 Then
        ' エラーが発生した場合に実行する処理を記述する
        Resume Skipitem ' エラーが発生した処理をスキップし、Skipitemラベルにジャンプする
    End If

end sub


```


# そのほか

自身の環境ではなく、ユーザーの環境へ導入すると導入・実行・削除をこちらの手でやらないといけないのでめんどくさいです。
まずはクリーンアップツールや手動でも対応してもらい、それでも対応しきれない場合にやってもらうのがおすすめです。




# 参考

https://support.microsoft.com/ja-jp/office/%E3%82%A2%E3%82%A4%E3%83%86%E3%83%A0%E3%82%92%E6%89%8B%E5%8B%95%E3%81%A7%E6%95%B4%E7%90%86%E3%81%99%E3%82%8B-ecf54f37-14d7-4ee3-a830-46a5c33274f6



https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/on-error-statement
Android の Geofence で気をつけること

もう年末ですが、今年とある機能の開発で戦った Android の Geofence について [Android Advent Calendar 2022](https://qiita.com/advent-calendar/2022/android) に書こうと思います。試しに動かすと動いちゃうんですよね。コイツは。でも少し深く掘って見ると様々な障害点が見つかります。

# Geofence とは

https://developer.android.com/training/location/geofencing?hl=ja

事前に設定した領域からの出入りをイベントとして処理を行うことができます。

:::note info
さらに Google Play 開発者サービスを利用の [Activity Recognition Transition API]( https://developers.google.com/location-context/activity-recognition) を利用すると、行動の様子（歩く・走る・止まる・乗り物）も含めてイベントにすることができます。が、今回は一旦位置情報だけの話。
:::

# 立ちはだかる壁たち

Geofence を本格的に動かすと様々な問題に出会うことになります。

## 登録数の上限

登録できる数に上限があります。登録時にエラーが返されます。

https://developer.android.com/training/location/geofencing?hl=ja

> 単一ユーザー デバイスでは、1 つのアプリで作成できるジオフェンスは 100 個までです。マルチユーザー デバイスでは、1 つのアプリで作成できるジオフェンスはデバイス ユーザーあたり 100 個までです。

## いつのまにか消える

「いつのまにか」というのは半分冗談で、ドキュメントを見落としていると何もしてないのに動かなくなります。 [必要な場合にのみジオフェンスを再登録する](https://developer.android.com/training/location/geofencing#re-register-geofences-only-when-required) の章を読みましょう。

特にデバイスの再起動は要注意です。 `ACTION_BOOT_COMPLETED` を受信して再登録するようにしましょう。

## 発火しない

GPS 以外にも様々な情報を利用するため、 GPS だけでなくデータ通信が必要です。

Android の OS 設定から、位置情報サービスの設定を確認すると、 GPS 以外にも様々な項目が ON/OFF できることがわかります。特に、領域に入った・出たという情報は、「Google ロケーション履歴」が必要そうです。これらが依存していると考えられるため、モバイルネットワークや Wi-Fi に接続された環境が必要です。

実機を持ち運んでテストするためには基本的には SIM が必要です。

## Foreground Service が立ち上がらない

Geofence は、バックグラウンドから Foreground Service を立ち上げることができる例外の一つに指定されていますが、 **バッテリーの最適化を無効** にする必要があります。

[Exemptions from background start restrictions](https://developer.android.com/guide/components/foreground-services?hl=ja#background-start-restriction-exemptions) の *The user turns off battery optimizations for your app.* は AND 条件です。両方を満たしていないと `startForeground` に失敗します。

さらにバッテリーの問題というのは端末の開発側にとってもホットなネタなようで、おそらくメーカーによって様々なカスタマイズが仕組まれています。基本的に 
Geofence で Foreground Service を立ち上げる機能を利用する場合は、各メーカーのあらゆる省電力設定はオフにすることになります。

## Geofence で立ち上がった Foreground Service で BLE の Scan ができない

さらに Geofence で立ち上がった Foreground Service で BLE の Scan を行いたかったのですが、ここにも制約があります。空の `ScanFilter` は画面が消えている状態だと利用できません。何かしら条件を加えましょう。 Service UUID あたりがオーソドックスな方法かと思います。

## 画面が消えた状態をデバッグしたい

Android には Doze モードという状態があり、その状態になると一部の機能が制限されます。

https://developer.android.com/training/monitoring-device-state/doze-standby?hl=ja

`adb` のコマンドを利用して、端末を強制的に Doze モードにしてデバッグできます。

## Google Play の審査

バックグラウンドの位置情報権限には、特殊な申請が必要です。

最初に何もせずにマニフェストファイルに `<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />` を書くとリジェクトされてメールが来ます。それをよく読んで対処していきましょう。

また、 Play Console の「ポリシー」→「アプリのコンテンツ」中に「機密情報にかかわる権限と API」という項目があります。こちらは [Play Console のバックグラウンドでの位置情報のページ](https://support.google.com/googleplay/android-developer/answer/9799150?hl=ja) の内容をよく読んで記入しましょう。申請を通しに行く作文力が求められます。

# まとめ

* https://developer.android.com/ を読み込みましょう
* [Play Console のバックグラウンドでの位置情報のページ](https://support.google.com/googleplay/android-developer/answer/9799150?hl=ja) を読み込みましょう
* 各メーカー・端末の省エネ設定については実機で調べましょう
Listagg(リスタッグ)関数まとめ

# Listagg関数とは...
指定した列の複数行の値を連結して1行にまとめることができる集計関数。
デリミタ(区切り記号)を指定することで、カンマ区切りなどでまとめることができます。
※戻り値は文字型

# 書式
```sql
LISTAGG(連結したい列, 'デリミタ') WITHIN GROUP (ORDER BY 連結順の基準列) 別名
```

　　**引数**	　　　　　　　　　　　　　　　　　　　　　　　**説明**
連結したい列	　　　　　　　　　　　　　　連結にしたい列名を指定。
デリミタ	　　　　　　　　　　　　　　　　連結にする際の区切り記号を指定。
連結順の基準列	　　　　　　　　　　　　　連結するときの順番を決める基準列を指定。

# 使用例
**サンプルデータ**
```sql
INSERT INTO listagg_sample (name, department, salary) VALUES
('高木', '営業部', 400,000),
('高橋', '開発部', 350,000),
('山田', '営業部', 390,000),
('佐藤', '管理部', 420,000),
('伊藤', '開発部', 340,000);
```

例）部門毎に名前をカンマ区切りで連結したい場合。
※名前の並び順は給料の高い順
```sql
select department, LISTAGG(name, ',') WITHIN GROUP (order by saraly desc nulls last) name from listagg_sample order by department;
```

実行結果

**department**	　　　　　　　**name**
管理部　　　　　　　　　　佐藤
営業部　　　　　　　　　　高木,山田
開発部　　　　　　　　　　高橋,伊藤
[AUTOSAR] Interview with AUTOSAR Regional Spokesperson Japan(11/23/2022)

# はじめに
AUTOSARの日本地域代表の後藤さんのインタビューを聞いて印象に残った内容、感想を残しておく。
[デンソーの後藤さんが就任した記事](https://monoist.itmedia.co.jp/mn/articles/2205/06/news029.html)
[AUTOSARインタビューページ](https://www.autosar.org/news-events/detail?tx_news_pi1%5Baction%5D=detail&tx_news_pi1%5Bcontroller%5D=News&tx_news_pi1%5Bnews%5D=182&cHash=98ad65ae795bf1e0a3c781149e841e09)

# 内容、感想
* 後藤さんの紹介、経歴、趣味など
* AUTOSARのキーとなる特徴について
* 日本ではどうやってAUTOSARを使っているか
* AUTOSARに対してどう貢献するか、リージョナルスポークスパーソンは日本ではどういう役割を持つか
* リージョナルスポークスパーソンとしてこれからどう活動していくか

他のAUTOSAR関連のセミナーに出席したときにTOYOTAの方がおっしゃっていたことと同じように、日本はAUTOSARへの対応スピードが遅い、ただ、使う範囲は広がってきているということでした。
AUTOSARのメリットや、開発者が意識するポイントなどを述べられていたり、
今後のリージョナルスポークスパーソンとしての活動について、
JASPARとの連携や、ユーザのリアルな声をよく聞いて、AUTOSARに反映させていくことを述べられていました。

これはインタビューだったので仕様の話はなかったですが、
セキュリティや機能安全のAUTOSARとしての対応の仕方や、
APの仕様についても確認していきます。
技術者としてはIVI系のドメインコントローラの開発ができるスキルを身につけていく必要があると思いました。
（AUTOSAR APの仕様としても対応していきたいとのことでした）
また、AUTOSAR仕様について意見があれば発信、反映できるように、仕様をチェックする意識を持って読み進めていけたらと思います。
特に侵入検知系はまだまだ仕様が成熟していないと思うので、積極的に声をあげていきたいと思います。

AUTOSAR20周年おめでとう。
Linux　ISOからファイルの抽出

# はじめに
Microsoftが実施しているMark of the Web（略称MoTW）により，直接Officeファイルをメールに添付しても，規定でマクロがブロックされるようになった．それにともない，ISOファイルやVDIファイルを使用する攻撃手法が確認されるようになったため，今回はisoファイルの3つの解析方法について備忘録を残す．

# ISOファイルのマウント
まず，マウントポイントディレクトリの作成を行う．
~~~ruby:mkdir
$ sudo mkdir /mnt
~~~
ディレクトリの作成が終わったら，コマンド一つで終了．
~~~
$ sudo mount -o loop PaymentInvoice.iso /mnt
$ ls /mnt/
~~~

# 7zを使用する方法
一番楽かもしれない．
~~~
$ 7z x PaymentInvoice.iso
~~~

# isoinfo コマンド
~~~
$ sudo apt install genisoimage
~~~

isoinfoコマンドは，isoファイルの中身をリスト表示してくれるものだが，
ファイルの抽出も可能．
取り敢えず，isoファイルに何が入っているかを表示．
~~~
$ isoinfo -i PaymentInvoice.iso -l
~~~
下記のコマンドでファイルの抽出を行う．
~~~
$ isoinfo -i PaymentInvoice.iso -x MD5SUM.TXT > MD5SUM.TXT
~~~

:::note warn
警告
iso9660フォーマットでない場合，できないため上2つのやり方が主に使用するやり方と思われる．
:::
クリップボードの魔法を知る

# お前は今までしたコピペの数を覚えているか
覚えていないくらいCtrl+C,Vは皆さん使っていると思います。  
Command+C派閥の方も同様です。  
  
クリップボードはコードや文章のコピー、スクショの確保などを行うことができます。
あることが当たり前で、この機能が存在しない世界線は想像できません。  

Windowsネイティブアプリでクリップボード周りの実装を行った際、アプリやOSはいろいろ頑張ってくれていたんだと実感したので、こちらに書いてみます。

# 貼り付け動作はアプリ次第
## デモ
chromeからwordおよびwindows10のメモ帳にhtmlを貼り付けた際の動作を見てみましょう  
![mainwindow.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595099/2832d721-a567-8e44-aef5-2ad43fe8bb80.gif)
wordではアイコン画像の表示やリンクの生成、フォントサイズの再現が行われていますが、メモ帳では文字のみの表示となっています。
## クリップボードの中身
ツールを使って、クリップボードの中身を見てみましょう。  
今回使うツールはこちら [クリップ見え窓](https://www.officedaytime.com/clipmm/)
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595099/bafddcfd-bb2d-08b8-ad66-8264d70e641e.png)
クリップボード内は各フォーマットごとに要素が格納されています。
HTMLの場合は以下のようなデータが格納されています。
![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595099/9eeb7153-f95a-bf04-3247-61bf4e7e95d1.png)
一方、TEXTは以下のようになっています。
![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595099/e607bc4a-fed5-c204-7323-04377373523c.png)
察するに、メモ帳はこのTEXTのみ対応していて、それを読み取って表示しているようですね。

## クリップボードをリッチにしたいあなたに
ネイティブアプリ内で独自の要素をクリップボード操作したい場合、Windows APIでは以下のようなAPIが用意されています。  
[SetClipboardData](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setclipboarddata)  
[GetClipboardData](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclipboarddata)  
気になる方は遊んでみてください。
# まとめ
何気ないコピペ操作の裏側では日々、このようなやり取りが行われていたのです。  
皆さんも色々遊んで見てください。興味深いクリップボードデータが見れるかもしれません。
Windowsおじさんで申し訳ありません。
# おまけ
自分が使っているCtrl+C,X,V以外のクリップボード操作についてまとめます。

* Windows+V  
  クリップボード履歴を表示し、過去にコピーや切り取りをしたテキストや画像が新しい順に一覧表示できるようになります。
* PrintScreen  
  画面全てのスクリーンショットをクリップボードに格納します。
* Alt+PrintScreen  
  アクティブウィンドウのみのスクリーンショットをクリップボードに格納します。
* Windows+Shift+S  
  画面上任意の領域のスクリーンショットをクリップボードに格納します。

・・・ほとんどスクショやないかい。  
では、良いお年を。
VSCodeでPythonモジュールインポート

1.VSCodeの中でCtrl + Shift + @コマンドからターミナルを起動
2.pip3 install モジュール名
詳しくは以下URL
https://torusblog.org/vscode-library-install-after/

また参考になったサイト
https://net-newbie.com/2020/01/23/vscode-conda-not-found/
vanillaEssences.index

　[Angular, React, Vue, ...]といったframework for (JavaScript|TypeScript)がすっかり普及してしまったが，ES6以前は，以下のようなcodeで拵えたObjectを生成していた．
　廃れゆく伝統工芸のような気もするが，糖衣構文の意味が判らなくなってしまうのも癪なので，適宜書き進める．

```
function Example() {
};

/**
 * https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/new
 */
var app = new Example();

/**
 * inherite
 */
ExampleEx.prototype = new Example();
function ExampleEx() {
};
```

　performanceに影響があるものの，私は以下の記法を用いてきた．改めるつもりはない．

```
/**
 * @param {name: ""} lop
 */
function Person(lop) {
  this.name = lop.name;
  this.rx = (function() {
  }).bind(this);
}
```
Wasabiのバケットを複製（バックアップ）する

# 概要
S3互換のストレージサーバーとして[wasabi](https://wasabi.com/)を使っています。運用中のサービスのバケットを別のバケットに移行したいという出来事があり、以降作業を行いました。wasabiに関する記事が少なかったので、作業手順をまとめます。

# 大まかな流れ
1. 新しくバケットを作成する。
1. aws cliで既存バケットのオブジェクトを新しいバケットに複製する。

# 前提
- aws cliがインストールされていること
- wasabiをすでに運用していること

# 手順
## 新しくバケットを作成
1. 右上の`CREATE BUCKET`を選択する
    ![スクリーンショット 2022-12-31 12.34.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634748/0837328d-220f-3de7-4328-356e7760af29.png)

1. 各情報を入力・選択する
    Select Regionはサービス提供を行う地域に近いものを選択する。
    Quick Setupは必要に応じて選択する。これは別のバケットの設定を引き継ぐことができる設定である。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634748/1644a2c5-7bd1-50b8-a65b-397147870c13.png)

1. 必要な機能をオンにする
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634748/c617304c-2d9f-32b0-2cea-46fcff54a044.png)

1. 確認後`CREATE BUCKET`を選択
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634748/63fde681-74c4-f3d5-3bd4-a62391991194.png)

    これでバケットの作成ができました。
    あとはポリシーなどを複製元と合わせて終わり。


## aws cliで既存バケットのオブジェクトを新しいバケットに複製
実行コマンドのテンプレートは以下です。
```sh
s3 sync --region <リージョン名> s3://<複製元バケット名> s3://<複製先バケット名> --endpoint-url=https://s3.<リージョン名>.wasabisys.com --copy-props metadata-directive
```

例）　リージョン：ap-northeast-1、複製元バケット名：origin、複製先バケット名：copy
```sh
s3 sync --region ap-northeast-1 s3://origin s3://copy --endpoint-url=https://s3.ap-northeast-1.wasabisys.com --copy-props metadata-directive
```

### 説明
- `s3 sync --region <リージョン名> s3://<複製元バケット名> s3://<複製先バケット名>`はs3を操作する時の記述と同一です。
- `--endpoint-url=https://s3.ap-northeast-1.wasabisys.com`でバケットのエンドポイントがwasabiであることを明示しています。
- AWS CLI v2の内部でタグに関する機能を使用する場合があり、Wasabiがタグ機能に対応していないため、`An error occurred (NoSuchTagSetError) when calling the GetObjectTagging operation: There is no tag set associated with the bucket.`というエラーが発生することがあります。それを回避するためにタグ機能を無効にする`--copy-props metadata-directive`オプションを付与しています。

# 参考
- [AWS CLI での高レベル (S3) コマンドの使用](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-listing-buckets)
- [Wasabi で AWS CLI を使用する方法](https://wasabi-support.zendesk.com/hc/ja/articles/115001910791-Wasabi-%E3%81%A7-AWS-CLI-%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95)
- [S3でBucketまるごとコピーする方法](https://qiita.com/as_a_mix/items/90fcc1b349b85de6312d)
csvデータをPythonで転置（行と列を逆にする）する方法


```python:
import pandas as pd
df = pd.read_csv("読み込みたいディレクトリ", encoding="shift_jis")
df.T.to_csv("書き込みたいディレクトリ", encoding="shift_jis")
```
注）
ディレクトリはフルパス
エンコーディングはサクラエディタなどでデータの文字情報を調べること
Dockerのデータ管理について

Dockerを使って以下のような動きができるコンテナを作成したいと思うことがありました。
1. dockerイメージ のビルドの過程でファイルが生成される。
2. 一部のファイルを外部からマウントして、コンテナ内部から参照できる。
3. 起動したら何らかの処理を実行して終了する。

想定しているのは、開発用のdockerです。
imageのビルド時に必要なファイルの生成を行い、その後コンテナの外部にあるファイルを参照しつつ、dockerコンテナを起動し何らかのプロセスを実行します。

# サンプルのdocker
サンプルとして以下のリポジトリを作成しました。
https://github.com/naokomada/batch_container

# サンプルの実行方法
1. https://github.com/naokomada/batch_container をcloneする。
2. `docker-compose build`
3. `docker-compose up`

# サンプルの動作説明
データ保持と、処理実行について細かい動作を説明します。
主に以下のファイルについての説明となります。
- `Dockerfile` (サンプルで使用するファイルのコピーをしています。)
- `docker-compose.yml` (volumes, commandの設定をしています。)
- `batch_files/lsla.sh` (commandに指定して、作成したディレクトリの内容を表示するに使っています。)

## docker のデータ保持について

サンプルの中では以下の4つのパターンでディレクトリを作成します。

1. Dockerfileの処理中に作成（`dirdockerfile/`）
2. volumeとして作成（`dirvol/`）
3. 元々存在するディレクトリをbind（`dirbind/`）
4. 存在しないディレクトリをbind（`dirbind_after/`）

作成方法について、以下の内容が参考になります。

dockerのストレージについて
https://matsuand.github.io/docs.docker.jp.onthefly/storage/

それぞれ作成方法の違いにより、挙動が異なります。

1. Dockerfileの処理中に作成（`dirdockerfile/`）
    - ボリュームとしてデータが保持されます。
    - 匿名ボリュームになります。
    - docker-compose down により削除されます。
2. volumeとして作成（`dirvol/`）
    - ボリュームとしてデータが保持されます。
    - サンプル中のdocker-compose.ymlの設定内容に基づいて名前つき（named）として作成されています。
    - docker-compose down をしてもデータが維持されます。
3. 元々存在するディレクトリをbind（`dirbind/`）
    - バインドマウントとしてデータが保持されます。
    - docker-compose.ymlでsourceにした、ホストマシン上のディレクトリがdockerコンテナの内部から参照できます。
    - ディレクトリの所有者や参照権限は、ホストマシン上で元々設定されていた内容が維持されます。
4. 存在しないディレクトリをbind（`dirbind_after/`）
    - バインドマウントとしてデータが保持されます。
    - docker-compose.ymlでsourceにした、ホストマシン上のディレクトリがdockerコンテナの起動時に生成されます。
    - ディレクトリの所有者や参照権限は、root権限になります。

なお、以下のように使い分けできます。
- dockerコンテナの外部にあるファイルを編集し、dockerコンテナ内で起動するプロセスに渡して実行させたい場合
    - 3. の方式で実行すれば実現できます。
- dockerイメージの内部でファイルを作成・更新し、dockerコンテナ内で起動するプロセスに渡して実行させたい場合
    - 1. の方式で実現できます。また、複数コンテナでファイルを共有したいなら2.で対応できます。

4.のケースについては注意が必要だと思います。このケースの場合、dockerコンテナの動作時に生成されたファイルについて、権限設定が意図しない状態になり編集できなくなる可能性もあります。


## dockerコンテナ起動時の動作

### 起動と同時に処理を実行したい場合

サンプル内では以下のように実行することで、docker-compose upで処理が行われます。

```docker-compose.yml
services:
  batch_container:
    command: sh ./lsla.sh
```

以下のように書き換えることで、docker-compose upでコンテナを起動後、シェルのAttatchをして処理をすることもできます。
または、`docker-compose exec batch-container sh ./lsla.sh` のように実行できます。
```docker-compose.yml
services:
  batch_container:
    tty: true
    command: sh -c "/bin/sh"
```
【C# EPPlus】Excelに複数行まとめて書き込む方法

# はじめに
エクセルファイルに複数行まとめて書き込む方法を説明します。
使用するライブラリはEPPLUSです。

データ量が多い場合に1セルずつ書き込むと、処理が重たくなります。
そのため、1回の書き込みで複数行まとめて書き込むことで、速度の向上が見込めます。
もちろん、1行ずつ書き込むことも可能です。

# 概要
カンマ区切りの文字列をエクセルの1行として書き込みます。
カンマで区切られた文字列の値が1セルに書き込まれます。

デフォルトでは区切り文字はカンマですが、区切り文字を変更することも可能です。
タブ区切りの文字列を書き込む方法も説明します。

# 説明

```c#
class Sample
{
    static void Main(string[] args)
    {
        FileInfo newFile = new FileInfo("sample.xlsx");

        using (ExcelPackage package = new ExcelPackage(newFile))
        {
            // ワークシートを1枚追加
            ExcelWorksheet sheet = package.Workbook.Worksheets.Add("書き込み対象のシート名");
 
            // エクセルの1行目に書き込むデータ
            string inputData1 = "A1, B1, C1, D1, E1";
            // A1セルを先頭に1行書き込む
            sheet.Cells["A1"].LoadFromText(inputData1);
 
            // エクセルの3行目、4行目に書き込むデータ
            string inputData2 = "A3, B3, C3, D3, E3\nA4, B4, C4, D4, E4";
            // A3セルを先頭に2行書き込む
            sheet.Cells["A3"].LoadFromText(inputData2);

            // タブ区切りのデータ
            string inputData3 = "A6\tB6\tC6\tD6\tE6";
            // タブ区切りの文字列を書き込む場合は、delimiterを指定する（A6セル：R1C1形式で範囲指定）
            sheet.Cells[1,6].LoadFromText(inputData3, new ExcelTextFormat() {Delimiter='\t'});

            // 保存
            package.Save();
        }
    }
}

```

### 出力結果
![スクリーンショット 2022-12-31 13.29.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2300329/bc894c24-12b0-0e41-91ee-3f9ae3b99c39.png)
参加したCalendarの集計（作業中）

現在、鋭意集計中。　

定数P(perticipant)＝記事数＊（投稿者-1）　投稿者が全員、他の投稿にいいねした場合の数　
定数S(subscriber)=記事数*（購読者-1)    購読者が全員、他の投稿にいいねした場合の数（投稿者が購読者になっていることを想定）

|日|表題|投稿数|投稿予定者数|購読者|いいね|定数P|定数S|投稿題|Views|いいね|ストック|
|:----|:----|:----|:----|:----|:----|:----|:----|:----|:----|:----|:----|
|12月1日|開発とビジネス・経営の境界線 by NewsPicks Advent Calendar 2022 https://qiita.com/advent-calendar/2022/newspicks| |8|17| | | | | | | |
|12月1日|Java Advent Calendar 2022 https://qiita.com/advent-calendar/2022/test_01| |1|5| | | | | | | |
|12月2日|数値計算 Advent Calendar 2022 https://qiita.com/advent-calendar/2022/numerical_analysis| |46|9| | | | | | | |
|12月2日|Twitterを活用して作ってみた Advent Calendar 2022 https://qiita.com/advent-calendar/2022/twitter-develop| |2|3| | | | | | | |
|12月3日|RPA（ロボティック・プロセス・オートメーション） Advent Calendar 2022 https://qiita.com/advent-calendar/2022/robotic_process_automation|30|22|33|91|630|960|いつか来た道　 https://qiita.com/kaizen_nagoya/items/7eb8adc0da4b6b1385af|220|5|0|
| |FreeBSD Advent Calendar 2022 https://qiita.com/advent-calendar/2022/freebsd|23|12|18|56|253|391|FreeBSD on Dockerを探しはじめて https://qiita.com/kaizen_nagoya/items/b131393c49747e1b31c2|415|2|0|
|12月4日|Unity Advent Calendar 2022 https://qiita.com/advent-calendar/2022/unity|62|56|127|268|3410|7812|Unityと箱庭 https://qiita.com/kaizen_nagoya/items/7ae193df6efa1d2f2ba0|571|2|0|
| |ROS Advent Calendar 2022 https://qiita.com/advent-calendar/2022/ros|5|6|16|16|25|75|ROSと箱庭 https://qiita.com/kaizen_nagoya/items/d3bddcff32f14605c57b|205|4|3|
|12月5日|Rust Advent Calendar 2022 https://qiita.com/advent-calendar/2022/rust|48|49|287|162|2304|13728|初めてのRUST https://qiita.com/kaizen_nagoya/items/dd8f5e3b218d48fb79e1|969|1|0|
|12月6日| | | | | | | | | | | |
|12月7日| | | | | | | | | | | |
|12月8日| | | | | | | | | | | |
|12月9日| | | | | | | | | | | |
|12月10日| | | | | | | | | | | |
|12月11日| | | | | | | | | | | |
|12月12日| | | | | | | | | | | |
|12月13日| | | | | | | | | | | |
|12月14日| | | | | | | | | | | |
|12月15日| | | | | | | | | | | |
|12月16日| | | | | | | | | | | |
|12月17日| | | | | | | | | | | |
|12月18日| | | | | | | | | | | |
|12月19日| | | | | | | | | | | |
|12月20日| | | | | | | | | | | |
|12月21日| | | | | | | | | | | |
|12月22日| | | | | | | | | | | |
|12月23日| | | | | | | | | | | |
|12月24日| | | | | | | | | | | |
|12月25日| | | | | | | | | | | |
Google Colaboratory MeCab インストール & 辞書指定

## インストール

mecab と mecab-python のインストール
```
!apt install aptitude
!aptitude install mecab libmecab-dev mecab-ipadic-utf8 git make curl xz-utils file -y

!pip install mecab-python3
```

```
!cat /etc/mecabrc
```

設定状況を確認

```
;
; Configuration file of MeCab
;
; $Id: mecabrc.in,v 1.3 2006/05/29 15:36:08 taku-ku Exp $;
;
dicdir = /var/lib/mecab/dic/debian

; userdic = /home/foo/bar/user.dic

; output-format-type = wakati
; input-buffer-size = 8192

; node-format = %m\n
; bos-format = %S\n
; eos-format = EOS\n
```

dicdir確認

## mecab-python で確認

```
import MeCab

tagger = MeCab.Tagger()
text = "日本のSNS、混乱に備えを　マスク氏のTwitterはどこへ"
print(tagger.parse(text))
```

オプションなしで利用できることを確認


## 辞書指定
デフォルトとは別の辞書を使いたい場合は別途インストール

```
!pip install unidic
!python -m unidic download


Successfully installed plac-1.3.5 unidic-1.1.0
download url: https://cotonoha-dic.s3-ap-northeast-1.amazonaws.com/unidic-3.1.0.zip
Dictionary version: 3.1.0+2021-08-31
Downloading UniDic v3.1.0+2021-08-31...
unidic-3.1.0.zip: 100% 526M/526M [00:31<00:00, 16.7MB/s]
Finished download.
Downloaded UniDic v3.1.0+2021-08-31 to /usr/local/lib/python3.8/dist-packages/unidic/dicdir
```

最後にインストールした辞書のパスが表示されるので確認する。
辞書のパスを指定して利用する　。
/etc/mecabrcを書き換えてもいいがちょっと面倒なので。。。

```
import MeCab

tagger = MeCab.Tagger('-d /usr/local/lib/python3.8/dist-packages/unidic/dicdir')
text = "日本のSNS、混乱に備えを　マスク氏のTwitterはどこへ"
print(tagger.parse(text))
```

## 辞書のアップデート

辞書をアップデートしたい場合は辞書のコンパイルから行う方が良さそう。
アーカイブを左メニューのファイル部分にアップロードしてこんなコマンド実行。

```
!tar xvzf mecab-ipadic-2.7.0-20070801.tar.gz
!cd mecab-ipadic-2.7.0-20070801 && configure –with-charset=utf8 –prefix=/usr
!make
!make install
```

アップデートするCSVを展開したディレクトリに配置して以下のコマンドで辞書をアップデート。

```
!make clean all
!make install
```
vscodeで編集したjupyternotebookのexportエラー対処法

# 事象
- vscode上で編集したnotebookをPDFでexportしようとしたところ下記のエラーが発生。

```
> /opt/anaconda3/bin/python -m jupyter nbconvert /tmp/2039761f-2452-48f4-a2b9-fe06cfd385e4/work.1.ipynb --to pdf --output tmp-239FhAqS20h2565.html --output-dir /tmp --debug
error 12:46:37.424: Export failed [Error: [NbConvertApp] Searching ['/root/.vscode-server/bin/e8a3071ea4344d9d48ef8a4df2c097372b0c5161', '/root/.jupyter', '/opt/anaconda3/etc/jupyter', '/usr/local/etc/jupyter', '/etc/jupyter'] for config files
[NbConvertApp] Looking for jupyter_config in /etc/jupyter
[NbConvertApp] Looking for jupyter_config in /usr/local/etc/jupyter
[NbConvertApp] Looking for jupyter_config in /opt/anaconda3/etc/jupyter
[NbConvertApp] Looking for jupyter_config in /root/.jupyter
[NbConvertApp] Looking for jupyter_config in /root/.vscode-server/bin/e8a3071ea4344d9d48ef8a4df2c097372b0c5161
[NbConvertApp] Looking for jupyter_nbconvert_config in /etc/jupyter
[NbConvertApp] Looking for jupyter_nbconvert_config in /usr/local/etc/jupyter
[NbConvertApp] Looking for jupyter_nbconvert_config in /opt/anaconda3/etc/jupyter
[NbConvertApp] Looking for jupyter_nbconvert_config in /root/.jupyter
[NbConvertApp] Looking for jupyter_nbconvert_config in /root/.vscode-server/bin/e8a3071ea4344d9d48ef8a4df2c097372b0c5161
[NbConvertApp] Converting notebook /tmp/2039761f-2452-48f4-a2b9-fe06cfd385e4/work.1.ipynb to html
[NbConvertApp] Notebook name is 'tmp-239FhAqS20h2565'
[NbConvertApp] ERROR | Notebook JSON is invalid: Non-unique cell id '99b3287b-2872-4144-a7c1-e30e0ba29a5c' detected. Corrected to '93b153e5'.
〜〜〜中略〜〜〜
error 12:55:35.573: If you have not installed xelatex (TeX) you will need to do so before you can export to PDF, for further instructions please look https://nbconvert.readthedocs.io/en/latest/install.html#installing-tex. 
To avoid installing xelatex (TeX) you might want to try exporting to HTML and using your browsers "Print to PDF" feature.
```
# 原因
- 別のnotebookをコピーして編集していたことで、cell idがuniqueでなくなることが原因とのこと。

# 解消方法
- 別のnotebookをコピーするのをやめるか、新しくnotebookを作成して、そこにコピペすることで解決する。

# ソース
https://github.com/jupyter/notebook/issues/6001

https://stackoverflow.com/questions/66746193/notebook-validation-failed-jupyter

# ハマったこと
- PDFでexportしようとすると、以下のエラーでる。
```
error 12:55:35.573: If you have not installed xelatex (TeX) you will need to do so before you can export to PDF, for further instructions please look https://nbconvert.readthedocs.io/en/latest/install.html#installing-tex. 
To avoid installing xelatex (TeX) you might want to try exporting to HTML and using your browsers "Print to PDF" feature.
```
- xelatexのinstallを促されるので、再インストールしたりとめちゃくちゃハマった。
- エラーをよく読めば、最初の方で'Notebook JSON is invalid: Non-unique cell id'が出てるので、最後のエラーと関係ないところを疑うべきで、落ち着いてエラー読もうねと思った。
- issueはたてられてるようなので、最新バージョンでは解消しているかもしれない。

以上
p5.js でテキストを描画してからピクセル操作で色を変える

この記事では、「p5.js でテキストを描画して、そのテキストが描画されている部分のみピクセルを操作する」ということを試します。

https://twitter.com/youtoy/status/1609032055291281408

このお試しを行う理由は、以下の記事で使われている「テキストを分解する演出」を、p5.js上で独自処理で行うためです。

●JSでクリエイティブコーディング - テキストを分解しパーティクルにする演出 - ICS MEDIA
　https://ics.media/entry/221216/

## プログラム
まずは、プログラムを掲載します。開発は、p5.js Web Editor上で行っています。

```javascript
let pg;

function setup() {
  createCanvas(450, 350);

  pg = createGraphics(width, height);
  const d = pixelDensity();
  pg.textSize(60);
  pg.fill(0, 102, 153);

  pg.text("描画のテスト", 40, 100);
  pg.text("描画のテスト2", 10, 250);  
  
  pg.loadPixels();

  const wholeImage = 4 * (width * d) * (height * d);
  const pink = color(255, 102, 204);

  for (let i = 0; i < wholeImage; i += 4) {
    if (pg.pixels[i + 3] > 0) {
      pg.pixels[i] = red(pink);
      pg.pixels[i + 1] = green(pink);
      pg.pixels[i + 2] = blue(pink);
      pg.pixels[i + 3] = alpha(pink);
    }
  }
  pg.updatePixels();
}

function draw() {
  background(220);

  image(pg, 0, 0);
}
```

処理結果は、以下の通りです。
テキスト描画時は、テキストの色を `pg.fill(0, 102, 153);` という緑・青の成分のみにしていますが、その後、テキストが描画されているピクセルのみピンクになるように色を変えているため、以下の結果となります。
![処理結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/713a645a-7608-155a-9ab0-d81a8ec955f4.png)

### プログラムの補足
ピクセル操作の部分の元にした内容は、「[p5.js公式の pixels](https://p5js.org/reference/#/p5/pixels)」の内容です。
![p5.js公式の pixels](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/759e610e-7e2b-3331-1a14-a73859503b65.png)

元の内容は、キャンバスの上半分をピンク色にするという内容でしたが、自分の作ったものでは「文字が書かれた部分をピンク色にする」という内容です。

処理の流れは以下のとおりです。

1. [createGraphics()](https://p5js.org/reference/#/p5/createGraphics) で作成した p5.Rendererオブジェクトに文字を描画（※ テキストの色は、青っぽい色）
1. 表示するキャンバス領域のピクセル数よりも密度の高い描画が行われているかもしれないため、[pixelDensity()](https://p5js.org/reference/#/p5/pixelDensity) で密度を取得
1. [loadPixels()](https://p5js.org/reference/#/p5/loadPixelsloadPixels)で、p5.Rendererオブジェクトのピクセルを取得
1. 上で取得した p5.Rendererオブジェクトのピクセルを見ていき、「アルファがゼロでないピクセル ＝ テキストが描画されている部分」を判定
1. テキストが描画されている部分については、色をピンク色になるようにピクセルの値を変更
1. [updatePixels()](https://p5js.org/reference/#/p5/updatePixels) で、ピクセル操作の結果を反映

その結果、p5.Rendererオブジェクトにテキストを描画した後、そのテキストの色をピクセル操作で変更することができました。

## その後のお試し
その後、文字が描画された領域で、なおかつ特定の行のみの色を変える、という内容を試しました。テキストが縞模様になっているのが分かるかと思います。

https://twitter.com/youtoy/status/1609040646773575681

## 【追記】 その後のお試し2
冒頭で、実現したいこととして書いていた「テキストを分解する演出」、その第一段階も作成できました。

https://twitter.com/youtoy/status/1609047436248637442

## 【追記】 その後のお試し3
さらに、分解演出の逆のバージョンや、画像＋テキストを分解するものも試作してみたりしました。

https://twitter.com/youtoy/status/1609061714175356929

https://twitter.com/youtoy/status/1609129068557111298
[AUTOSAR] Impressions from the Web Summit(11/23/2022) について

# AUTOSARイベント

https://www.autosar.org/news-events/detail?tx_news_pi1%5Baction%5D=detail&tx_news_pi1%5Bcontroller%5D=News&tx_news_pi1%5Bnews%5D=183&cHash=e9dfdc1122b5140f200f7ccef86f61ba

AUTOSARイベントの「Impressions from the Web Summit」にて、Youtubeに挙がっているRinat Asmusさんが話されていた内容です。
Youtubeの文字起こし機能で文章に起こして、
翻訳サイト「DeepL」に突っ込んで、日本語的におかしいところを修正しました。
レナートさんはBMWの人らしいですね。

結論としては、このyoutubeのインタビューだけでは何も新しい情報はなかったです。


# インタビュー内容

>レナート会長、Autosarについて、またあなた方の活動について教えてください。

私たちは、自動車産業全体の課題に取り組むとともに、自動運転やB2Bといったソフトウェアのトピックもコミュニティの一部として扱っており、20年近い歴史を誇ります。
このようなコミュニティはとても誇りに思います。
通常、新興企業や他の技術系企業は私たちのことを知らないし、私たちの技術が彼らの車に搭載されていることも知りません。

>20年前に設立されたとのことですが、20年前と今とでは、ビジネスの原則が少し変わってきていると思います。


20年前を想像して、自動車業界のマネージャーにマーチャントリクエスト？を見たことがあるかと尋ねると、彼はただ単に「何ですか」と言うだけでした。

>サステナビリティをどのように実現するか。

皆さんもご存知かもしれませんが、現在、私たちはすでにすべてのインバーターや充電システムの一部となっており、ハードウェアやハザードの技術に応用しています。
エレクトロビット、ベクター、ETASのようなプラットフォーム企業が、C言語の実装を行うことができる、最も埋め込み型で認証された方法です。
Autosarはすでに組み込み用のホットなプラットフォームを提供しています。自動運転のためのプラットフォームで、後ろにあるAdaptiveプラットフォームはC++ベースのAPIです。
現時点では、Rustバインディングも考えています。
また、自動運転というエコロジーの考え方は規制されなければなりませんし、例えばプラトーニングのために何時に運転をするかなど、大きな影響を与えます。

>もし私が開発者で、オートモーティブの世界に入りたいとしたら、どのようなプログラミング言語を学べばよいのでしょうか。

まず第一に、私たちはあなたのアプリケーションを高く評価します。
第二に、あなたはC言語のような信頼性の高いものから始めたら良いでしょう。
オートモーティブは一般的にリソースに苦労していますし、バックエンドの開発者を連れてくるのは大変な仕事です。
【車輪の再発明】Enum.reduceを使ってEnum.all?を作ってみよう

Enum.all?を作ってみましょう

# ルール
　・第一引数のlistの中身がすべてtrueならtrueそれ以外はfalse
　　・判定式
　　　・nilはfalse
　　　・nil以外かつ、boolean以外はtrue
　・第二引数は、判定式を指定できる、未指定の場合は上記の判定式になる

# 作ってみよう

```Elixir
defmodule Hoge do
  def all?(list, fx \\ &judgement/1) do
    list
    |> Enum.reduce(true,  fn x, acc -> fx.(x) and acc end)
  end

  defp judgement(x) when is_boolean(x), do: x
  defp judgement(x) when is_nil(x), do: false
  defp judgement(_), do: true
end
```

# 実行してみる

```Elixir
Hoge.all?([true, 1, "s"])
|> IO.inspect()
```

```Elixir:実行結果
true
```

```Elixir
Hoge.all?([true, nil, true])
|> IO.inspect()
```

```Elixir:実行結果
false
```

```Elixir
Hoge.all?([true, 1, false])
|> IO.inspect()
```

```Elixir:実行結果
false
```

```Elixir
Hoge.all?([2, 4, 6], fn x -> rem(x, 2) == 0 end)
|> IO.inspect()
```

```Elixir:実行結果
true
```

```Elixir
Hoge.all?([2, 4, 5], fn x -> rem(x, 2) == 0 end)
|> IO.inspect()
```

```Elixir:実行結果
false
```
はじめての Zoom Meeting SDK - Web - 通話中にブラウザを閉じてしまった編

Zoom Meeting SDK for Web で利用、通話中に稀にブラウザを閉じてしまって接続が数分残ってしまうことがあります。
そのような際にブラウザ側で提供可能な「beforeunload」(イベント)をトリガーすることで切断処理を活用しやすくなります。
SDKクライアントの生成後通話前に以下のようにリスナーを実行するといった方法が考えられます。

```javascript
  let zmClient = ZoomMtgEmbedded.createClient();

  window.addEventListener("beforeunload", function(event) {
    zmClient.leaveMeeting();
    console.log("leaveMeeting");
    event.returnValue = "";
  });
```

<h2>■ 関連記事</h2>

https://marketplace.zoom.us/docs/sdk/video/web/

https://qiita.com/yosuke-sawamura/items/de69e73e47335cd61d68

https://qiita.com/yosuke-sawamura/items/df6eb3b4bc2f11ba281f

https://qiita.com/yosuke-sawamura/items/dfb1e862c8882e5afb58
wslでelixir その8

# 概要
wsl(wsl2じゃない)で、elixirやってみた。
練習問題やってみた。

# 練習問題
shellを実装せよ。

# 方針
system使う
stream使う
io使う
エラーで抜ける

# サンプルコード

```
Stream.iterate(0, &(&1 + 1))
|> Enum.map(fn n ->
	input = IO.gets("sh(#{n})> ")
	{result, 0} = System.shell(input)
	IO.puts result
end)


```

# 実行結果

```
sh(0)> pwd
/home/user/elixir

sh(1)> ls
fizzbuzz
forth
fwup_1.9.1_amd64.deb
hello_nerves
nama_server
world
zundoko

sh(2)>
```

以上。
【Unity】Addressables の全アドレスを定数宣言するクラス

# 概要
```Addressables```の```Addressable Name```と```Path```を全て宣言するクラスを生成できるクラス```AddressDefineCreator```を作りました。
アドレスの入力ミスを防ぎ利便性を高められます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/cca10999-bfef-6410-556b-d4fa9f50b336.png)

# 使い方

メニューバーから```Tools``` → ```Addressables``` → ```Open Address Define Creator``` を選択すると```AddressDefineCreator```が表示されます（ファイルが無い場合は保存先指定ダイアログが表示されます）。
```Build Addressables And Update Address Define```ボタンを押すと Addressables ビルドが走って```AddressDefine```クラスが生成されます。
```Update Address Define```ボタンを押すと```AddressDefine```クラスが生成されます。

※上部の```Addressable Asset Settings```は、右下あたりをトリプルクリップすると```Addressables Groups```が開く配置になっています。

### 一部を定義から除外する方法

```Ignore Groups```に```Addressables Groups```の名前を入れると、そのグループの定義クラスは生成されません。
```Ignore Address Words```に文字列を入れると、その文字列が含まれる```Addressable Name```は定義されません。
```Ignore```のリストに入れるグループ名や文字列は```Mirrored Infomations```からコピペすると楽です。
```Update Address Frequent Words```ボタンを押すと、```Addressable Name```によく登場する文字列が列挙されます。

※```Mirrored Infomations```は```Addressables```の情報を表示しているだけなので、編集しても元通りになります。

# コード

下記2つのコードをEditorフォルダに入れてご利用ください。

https://github.com/yamara-mh/CodeStorage/blob/main/Codes/Editor/ScriptBuilder.cs

https://github.com/yamara-mh/CodeStorage/blob/main/Codes/Editor/AddressDefineCreator.cs

[ScriptBuilderの使い方はこちら](https://qiita.com/Yamara/items/fab57f758e68ef6423c1)

上記のコードから下記のようなクラスが生成できます。

``` AddressDefine.cs
namespace Addressables
{
    public static class AddressDefine
    {
        public static class BuiltInData
        {
            public const string ResourceObject = "ResourceObject";
        }
        public static class DefaultLocalGroup
        {
            public const string prefab1 = "prefab1";
            public const string prefab2 = "prefab2";
            public const string audioClip = "audioClip";
        }
    }
}
```

# 備考

Addressable のビルド時に```AddressDefine```ファイルを生成したかったのですが実装できませんでした。実装方法をご存知の方がいましたら教えていただけると助かります。
【Unity】メタプログラミングを簡単に行えるクラス

# 概要
```StringBuilder``` から着想を得て、メタプログラミング（コードを生成するコード）を簡単に行えるクラス```ScriptBuilder```を作りました。
機能不足な点があると思うので、コメントで改善案をいただけると助かります。

# コード
Editor ファイルに入れてご利用ください。

https://github.com/yamara-mh/CodeStorage/blob/main/Codes/Editor/ScriptBuilder.cs

# 仕様紹介
全ての関数はメソッドチェーンで記述できます。

|関数名|機能|
|-|-|
|Append()|文字列を追加します。<br>第2引数の```removeInvalidChars```を```true```にすると、変数名に使えない記号等を文字列から省きます。<br>第3引数の```padRight```の値を増やすと、右側を空白埋めします。|
|AppendLine()|文字列を追加し、改行します。|
|NewLine()|改行します。|
|OpenBrace()<br>CloseBrace()|```{```、```}```の代わりに利用すると、インデント（字下げ）の自動挿入が機能して生成されるコードが見やすくなります。また双方の使用数から記述漏れを発見しやすくなります。|
|UsingDirectives()|```using```ディレクティブを簡潔に記述できます。|
|Namespace()|```namespace```を明示的に記述できます。|
|Comment()<br>Summary()|コメント・ドキュメントコメントを簡潔に記述できます。|
|Clear()|```ScriptBuilder```が保持する値を消します。|
|WriteToFile()|ファイルに書き込みます（ファイルが無ければ生成・既にファイルがある際は上書き）。|
|SingleIndent()|インデントを1段追加します（自動挿入には影響しません）。|
|Remove()<br>InvRemove()<br>Pop()<br>PopSingleIndentLength()<br>PopIndnetLength()|文字列を削除します。<br>主に使用するのは```Pop()```と```PopIndentLength()```になるかと思います。<br>```Pop()```は最後から```n```文字消す関数です。<br>```PopIndentLength()```は現在のインデントの段落分の文字を消す関数です。|

# 使用例

https://qiita.com/Yamara/items/54cb73fdf3ca5ec2af75
Pythonの勉強

# 目的
Pythonの知識を習得するため、わかりにくい点やノウハウなどを蓄積していく。

# 内容
## 辞書型とリスト型の使い分け
辞書型では、キーで検索できるため、キーに対応した値を出力できる。
一方、リスト型では、キーで検索できない。
``` Python
#リスト型
l = [
    ['apple', 100],
    ['banana', 200],
    ['orange', 300],
]
#辞書型
fruits = {
    'apple': 100,
    'banana': 200,
    'orange': 300
}
print(fruits['apple'])
```
```
#出力結果
100
```

## 関数のdefault引数の注意点
default引数でリストを呼び出す際、１回目の呼び出しで、空のリストが返され、値が入る。
ただし、２回目の呼び出しでは、空のリストではなく、値の入ったリストが呼ばれ、値が追加される。

２回目で空のリストが返されないのは、引数lにリストの先頭のアドレスが入っているためである。
１回目の呼び出しで、リストの先頭アドレスに値が入り、
２回目の呼び出しで、先頭アドレスを指したまま（リストに値が入った状態）で、先頭の次のアドレスに値が入る。
``` Python
def test_func(x, l=[]):
    l.append(x)
    return  l

r = test_func(100)
print(r)

r = test_func(100)
print(r)
```
```
#出力結果
[100]
[100, 100]
```
関数を呼び出す度に空のリストを返したい場合は、
以下のように、Noneとifを用いる。
``` Python
def test_func(x, l=None):
    if l is None:
        l = []
    l.append(x)
    return  l

r = test_func(100)
print(r)

r = test_func(100)
print(r)
```
```
#出力結果
[100]
[100]
```
useEffectの基本的な書き方

<h1>概要</h1>

今回はReact hooks の種類の一つである <b>useEffect</b> の基本的な使い方についてまとめた記事になります。
useEffectが主に使われるシーンとして、下記の2点が上げられます。

1 uesEffectは主にサイトを開いた時に自動で処理を走らせる際に使われる

2 useEffectはWebAPIデータの取得を行う際などに用いられることが多い

3 UI以外の処理で主に使用される



<h1>useEffectの書き方</h1>
useEffectの基本的な書き方。

<b>useEffect(()=>{}) </b>

今回はブラウザ上に作成したボタンをクリックするとブラウザ上とコンソール画面で
カウントが +1 ずつサれる処理の記述になります。

```jsx
import React, { useState, useEffect } from "react";

const Counter: React.FC = () => {
  const [count, setConst] = useState(0);


  useEffect(() => {
    console.log("useEffect");
  });
  return (
    <button
      onClick={() => {
        setConst((prevCount) => prevCount + 1);
      }}
    >
      {count}
    </button>
  );
};

export default Counter;
```


<h5>【処理の結果】</h5>

ボタンを押すと画面上で+1ずつカウントされる。
コンソール上では「useEffect」の文字と、その横でカウントの数値が+1ずつされます。

<h5>【useEffect部のコード解説】</h5>
<b>↓4,5,6行目</b>

```jsx
  useEffect(() => {
    console.log("useEffect");
  });
```
useffectにコンソール上での文字列を出力する簡単な処理を書いています。
<b>console.log("コンソール上に出力したい文字を書く")</b>

<h1>マウント時のみuseEffect内の処理を行う</h1>

```jsx
import React, { useState, useEffect } from "react";

const Counter: React.FC = () => {
  const [count, setConst] = useState(0);

  // useEffect(()=>{})  が基本の型
  useEffect(() => {
    console.log("useEffect");
  }, []);

  return (
    <button
      onClick={() => {
        setConst((prevCount) => prevCount + 1);
      }}
    >
      {count}
    </button>
  );
};

export default Counter;
```
<h5>【第2引数に空の配列を指定したuseEffect部のコード解説】</h5>

```jsx
const Counter: React.FC = () => {
  const [count, setConst] = useState(0);

  // useEffect(()=>{})  が基本の型
  useEffect(() => {
    console.log("useEffect");
  }, []);
```

上のコードの最後の行にある

<b>}, []);</b>

にuseEffectでいう第2引数を設定しています。
今回は空の配列を設定しており、マウント時のみ処理が走る設定を行いました。

マウンド：最初にコンポーネントがDOMに出力される処理。
　　　　　（最初に画面が読み込まれた際に走る処理）


<b>参考記事</b>

https://de-milestones.com/react-mount-rendering/


<b>今回の参考にした動画</b>

https://www.youtube.com/watch?v=McEbOBmtvYs



今回は、useEffectの簡単な書き方についてまとめました。

今後、第2引数の書き方やクリーンナップ関数の書き方の記事も出していこうと思いますので、
よろしくお願いします。
IT未経験からのキャリアチェンジを実現 Pathfinderプログラムを調べてみた


IT未経験でもSalesforceのスキルとCRMのビジネススキルを学び、資格を取得できる場をオンラインで無償提供し、キャリアチェンジを支援するPathfinderプログラムを調べてみました

今回の内容は動画でも公開しています

https://www.youtube.com/watch?v=mYiDJ3N5zqI


詳細記事はこちらに出ている記事をご確認ください

IT未経験からのキャリアチェンジを実現！無料学習でリスキリング　Pathfinderプログラムの魅力とは？
https://www.salesforce.com/jp/blog/2022/07/jp-pathfinder-program-interview.html/


Pathfinderプログラムで未経験から企業の
DX（デジタルトランスフォーメーション）を担うIT人材へ！
https://www.salesforce.com/jp/company/careers/pathfinders/?d=cta-blog-promo-1

2023年2月〜プログラム開始　(第三期生) 募集要項
https://go.pardot.com/l/373542/2022-07-08/6nsmnc


### Pathfinderプログラムはどのようなプログラムか？
2018年に米国においてSalesforceとDeloitteが共同でスタートしたDX人材育成プログラム
日本版「Pathfinder」は2021年より開始されています


### Pathfinderプログラムで何を学べる？
CRMやSalesforceの知見を短期間で習得できるよう構成されているようです
期間中はSalesforce認定アドミニストレーター試験受験などがプログラムとしてあるようです


### プラグラム期間はどれくらい？

プログラムの期間は約5か月のようです
Phase1は約3か月間がります

Phase1の内容

・Salesforceの技術コンテンツとデロイトのビジネススキルトレーニングに焦点を当てた構造化されたカリキュラム
・Salesforce認定アドミニストレーター資格試験を受験

Phase2は約2か月間がります

Phase2の内容
キャリア開発に向け、実務に近い形式で「要件定義～設計～開発・テスト～デモ発表」までを行います


なお、Phase1の期間内に実施するSalesforce認定アドミニストレーター資格試験に合格しないとPhase2には進めないようです

2021年度はPathfinder受講者の7割が2回以内にSalesforce認定アドミニストレーター資格に合格しているようです

Phase3の内容
キャリアサポート
キャリアカウンセリングやレジュメレビューなどでPathfinder受講生をサポートするようです

なお、Pathfinderプログラムのキャリア開発支援は就業を約束するものではないようです


###  応募資格
2023年1月16日までPathfinderプログラムの第三期生の応募がされています
その応募資格には以下のように記載されています

https://go.pardot.com/l/373542/2022-07-08/6nsmnc

・就職活動中・転職・再就職を検討中の方（2024年/2025年卒業予定の学生含む）就職、転職意向がなく自社に導入されたSalesforceを活用するために学習されたい方は対象外となります。Salesforce 管理コースをご利用ください。

・自習時間(週15時間程）の確保、講義時間(週2回<主に月曜日/火曜日 18:00-19:30>)の確保。合同自習時間(週1回 主に水曜日)の確保出来る方。講義はリアルタイムでの参加を推奨しておりますが、アーカイブ動画での参加も可能です。なお、Phase1で実施予定の試験対策では、平日の日中(午後半日)に試験対策講義が1〜2回予定されており、その動画、資料の共有はありません。


この応募資格を見る限りIT未経験の方や現在学生の方も応募資格があるようですね


### 応募の前に

応募に際しては、学習内容のレベル感を確認のため、事前課題（お試し受講）を実施することがすすめられています
まずはTrailheadアカウントを発行して
Get ready for Pathfinder!　というTraimixに挑戦することがすすめられていますね

https://trailhead.salesforce.com/ja/users/jpartners/trailmixes/get-ready-for-pathfinderjp


いかがでしたでしょうか

IT未経験でも挑戦できる素晴らしいプログラムですね
【PHP】イミュータブルな実装って何が美味しいの？

## はじめに
保守的性の高いコードの書き方を調べているとイミュータブルなオブジェクトに関する話題を見つけました。

## 調べてみる
### （そもそも）ミュータブルとは
- mutableは、可変という意味
- インスタンス(オブジェクト)の状態を変更できるインスタンス(オブジェクト)
- 想定していない更新が起こる可能性があるためイミュータブルより安全性が低い

### （本題の）イミュータブルとは
- immutableは、不変という意味
- インスタンス(オブジェクト)の状態を変更できないインスタンス(オブジェクト)
- 変数に対して再代入をすることができないため、想定していない更新を防ぐことができる。ミュータブルより安全度が高い


## 書いてみる
```Sale.php
class Sales {
    private $price;

    public function __construct(int $price){
        $this->price = $price;
    }
    public function getPrice(): int {
        return $this->price;
    }
    public function setPrice(int $price): void{
        $this->price = $price;
    }
}

$payment1 = new Sales(100);
echo $payment1->getPrice(); // 100
$payment2 = $payment1->setPrice(200);
echo $payment1->getPrice(); // 200
```

↑`$payment2`への代入で`$payment1`の値が書き換わっていることが分かる。setPriceメソッドのようにオブジェクトの状態を変更できるメソッドのことを「破壊的なメソッド」という。

イミュータブルなオブジェクトの実装では、この破壊的なメソッドによる代入を防ぐため、
セッターで値を入れる際は、新しいインスタンスを作成する。↓
```Sales2.php
class Sales2{
    private $price;

    public function __construct(int $price) {
        $this->price = $price;
    }
    public function getPrice(): int {
        return $this->price;
    }
    public function setPrice(int $price): self {
        return new self($price);
    }
}

$payment1 = new Sales2(100);
echo $payment1->getPrice(); // 100
$payment2 = $payment1->setPrice(200);
echo $payment1->getPrice(); // 100
```

↑`$payment2`への代入で`$payment1`の値が書き換わらなくなった。
これで意図しない代入により途中で値が書き換わっていることを恐れずに済む。