OmniAICreator/Qiita-1.07M huggingface dataset:
Salesforce認定Platformアプリケーションビルダー試験の公式サンプル問題解説してみた-07

こんにちは

Salesforce認定Platformアプリケーションビルダー試験の公式練習問題があるのはご存じでしょうか。
Trailheadにフラッシュカードとして何度も解ける練習問題がございます。

https://trailhead.salesforce.com/ja/content/learn/modules/platform-app-builder-pt1/platform-app-builder-security-ui


今回はTrailhead

認定 Platform アプリケーションビルダー資格の受験準備: Fundamentals and User Interface (基本事項とユーザインターフェース)
ユーザインターフェーズについて

にある練習問題2問目をご紹介します

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

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

<iframe width="560" height="315" src="https://www.youtube.com/embed/GjCNiT5k7YI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


今回の内容はこちらです

![0002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/ebf4fe16-0ff2-f3f4-067b-736de8806c51.png)


正解はBです


ナビゲーションメニューはユーザでは削除はできないですが追加は可能です

そのため最小限のタブを表示させましょう


詳細はこちらのヘルプをご確認ください


Lightning アプリケーションビルダーの考慮事項

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

Lightning アプリケーションのナビゲーション項目を編集する場合、含める項目の数を検討してください。システム管理者がナビゲーションバーに含めた項目をユーザは削除できません。また、50 を超える項目がナビゲーションバーに含まれる場合、ユーザはナビゲーションバーをパーソナライズできません。たとえば、システム管理者が 32 個の項目をアプリケーションのナビゲーションバーに含めた場合、ユーザはさらに 18 個の個人項目を追加できます。ユーザは、ナビゲーションをパーソナライズして項目を追加または移動できますが、追加した項目の削除や名前変更はできません。
ECSとEKSを比べてk8sの世界観を理解する

ただのメモです。色々な基本的なことは書いてません。

k8sの説明書だと、コンテナの管理概念が多いですが、今回はそこから少し離れて別の視点で。
ALB/EC2な構成で、ECS/EKSを比べることで分かるk8sの考え方です。

## 目次

* ECSとEKSは、ほぼ同じALB/EC2構成に出来る。
* k8sの世界観は2階建て、それが大切。
* 論理構造を物理構造に変換するのが、Reconciliation Loop。
* ECS/EKSは、オーケストレーションとコレオグラフィとして対比できる。
* 一息で言うと
* ぼやき:EKS特有の抽象on抽象

## ECSとEKSは、ほぼ同じALB/EC2構成に出来る。

```
ALB ->  Listener -> Target groups -> Container On EC2 Instance 
```

EC2がFargateでもだいたい同じ。ECSとEKSは、このALB/EC2構成にほぼ差がありません。ALBの構成パターンなので当然です。だからこそ、コンテナの管理の部分が違う。という話になるのですが、今回はそこに行かず。

構成が同じだからこそ、考え方の違いが明白になるよねーというメモ。

**このようなALB/EC2構成を、この記事に限って、後に出る"論理"と対比して、"物理"的な構成と呼びます。** ※記事以外で、物理と呼ぶとインフラ屋さんに怒られるから注意

## k8sの世界観は2階建て、それが大切

ECSとEKSで対比することで、世界観の差を比べて行きます。

## ECSの世界観

まずは、ECSの世界観。

ECSのクラスター構造の概念
```
ECS Cluster -> Service -> Task
```
この概念は、ECSを知るという以外にあまり役に立ちません。

### Serviceが中心

アプリケーションサービスは、ECSにインテグレーションされてる物理構成(AWSサービス)の機能だけが使えます。構成もほぼ固定されています。といっても、ALB(ロードバランサー)/Scaling/Deploy等必要十分なものを備えており、Deploy戦略を切り替える等ある程度の柔軟さも担保されています。

これらはService毎に集中管理され、Serviceを中心に下記のような協調して行きます。
* スケーリングの定義に沿って、タスク数を増やしてく。(Scaling)
* Listener や Target gropsのInstanceの調整 (ALB/Deploy)

## k8sの世界観は2階建て

k8sの世界観は、2階建てになっています。
* アプリケーションサービスの論理的な定義
* アプリケーションサービスの物理的な構造 

前者の論理的な定義を構成する部品をResourceと呼びます。k8sの最初に習うPodやDeplymentやReplicaSetも全部Resourceです。

### 論理的な定義

ALB/EC2の物理構成を実現する場合、k8sでは↓のようなResourceを定義します。
```
Ingress -> Service -> Pods
```
※ ALB/EC2と比べやすいようにシンプルにしましたが、Deplyment/ReplicaSet等も実際には存在します。

### 物理的な構造

論理的な定義が、物理的な構造として実現されると、ALB/EC2構成になるわけです。
```
ALB ->  Listener -> Target groups -> Container On EC2 Instance 
```

## Reconciliation Loop 論理構造を物理構造に変換する

論理的な構造を、物理構造に変換するのが、k8sのコアコンセプトである、Reconciliation Loopです。
Reconciliation Loopは、公式説明等ではk8sのアーキテクチャが強く語られて分かりづらいことが多いですが、基本はこれ。

ちょっと正確にすると、個別のリResourceに対応するControllerが存在し、ControllerはResourceを参照しながら己の責務を果たします。具体的にControllerは下記のようなことをしていることが多いです。
* Resource通りになるように、物理的な実体を用意する。
* Resource通りになるように、別のResourceを定義(更新)する。

ALBの例で言えばこうなります。
```
1. EKS上で、IngressのResourceを定義する
2. 対応する"AWS Load Balancer Controller"が、Resourceを参照する。
3. Controllerは、Resource通りなるように、ALBをプロビジョニングする。
```
これららが、Resource毎に(場合によっては連鎖的に)発生し、最終的に論理定義->物理構造に変換されます。

## ECS/EKSは、オーケストレーションとコレオグラフィとして対比できる。

ECSとEKS(k8s)を対比すると下のようになります。

* ECS -> アプリケーションサービスは、Serivceによって集中管理される。Serivceに統合された機能のみ協調できる。
* EKS(k8s)-> アプリケーションサービスは、Controllerによって分散管理される。Resourceによる抽象化層があり、そこで協調させている。

この対比をみて、コレオグラフィという言葉ピンと来ました。
マイクロサービスの協調モデルの文脈で、オーケストレーションとコレオグラフィとして対比されるあれです。

* オーケストレーションは、指揮者にあたるサービスが存在し、個々のサービスを調整して、協調させて行きます。
* コレオグラフィは、個々のサービス毎に動作条件があり、動作後のフィードバック(所謂イベント)が媒体となり、別のサービスの動作条件になることで、協調して行きます。

ECSとEKS(k8s)の対比っぽいですね。
(実際、ECSのSerivceが直接操作してるわけではないはずなので、あくまでも概念的)


## 一息で言うと

k8sは、コンテナオーケストレーションサービスなんだけど、アーキテクチャ的にはコレオグラフィなマイクロサービスによって実現されています。結果、論理構造が抽象化されて、物理構造と分離しています。そのため汎用性や拡張性が優れてそう(簡単だとは言ってない)なんだ。って感じですね。

## ぼやき: EKS特有の抽象on抽象

素のALBなら出来る構成を、"AWS Load Balancer Controller"によって、実現できるか調べたりすることになり、もやっとします。

ALBって、ALBそのものが"抽象化されたロードバランサー"なのに、さらに抽象化を重ねてる感じがします。特にAWS内で完結するサービスの場合は、抽象on抽象ってどこまでの意義があるのでしょうか。今後が気になります。
【初心者向け】レビューしてもらう前にチェックすること


私も新卒の時そうだったが、自分がかいたコードや資料を
人にみてもらうことはドキドキもの。

そこで今日は特に技術なくても明日から実践できる、
これだけはまずはレビューしてもらう前にチェックすることを
かいてみた。

###### ■ コードレビューしてもらう前に、修正前と修正後で必ず差分をとるようにしよう。
 ・空白行やスペースだけの差分はないか
 ・不要なコメントやログ等ないか
 ・文字コード・改行文字が修正前・修正後で変わっていないか
 （特に修正前のプログラムをサーバーからダウンロード＋Windowsで修正等する場合は注意。）
       
###### ■ 仕様書等のドキュメントの誤字脱字の防止
小さな声でもよいので音読してミスをなくそう。

###### ■ ドキュメントの項番などはベタ書きでなく計算式で自動的に割り振れるようにする。
列追加した際に自動的に番号が変わるようにしておこう。

###### ■ レビューお願い前にプログラムがちゃんと動くことを確認しよう
当たり前だと思ってしまいがちだがコードを何度も修正を繰り返していくと、コンパイルが通らない/プログラムがちゃんと動作しない状態でコードレビューのお願いをしてしまう時がある。
気を付けよう。


上記が逆におろそかだと、
レビューしてもらう人に、（しょーもないミスばかりして。。。）と思われがち。
また、しょーもないミスでレビューしてもらう人の時間を使わせてしまう。。

また、不要な指摘を減らすためにも基本的には自分で一から資料・コードをつくるよりかは、過去作ったものからコピーしたものをベースとして修正しよう。
過去つくったものはすでに納品されているし、お客様がすでに使っているものだから
そっちの方が安全策。

ではまた次のトピックで。
【メモ】FuelPHPでクエリビルダを使って、DBからデータ取得

ちょろっとFuelPHPを触らないといけない機会があったのでメモ。
本当にちょっと触っただけなので汚いかもしれないけど、一応これで取得できる。

##### 例

``` 
   $response = \DB::select('*')->from('user')
    ->where_open()
    ->where('id', '=', 1)
    ->and_where('shop_id', '！=', 123)
    ->and_where('status', 0)
    ->where_close()
    ->execute()->as_array();
```

##### メモ
- `select('*')`はSELECT文。`*`で全カラム取得できる。
カラム指定したい場合は、`select('カラム名1', 'カラム名2')`のようにする。
- `from('user')`はDBのテーブル指定。
- `where_open()`と`where_close()`の間にwhere文を書く。
- `where()`は基本1回だけっぽい。
- whereの真ん中の＝は省略可能。 `『=』『!=』『>』『<』`などは普通に使える。
- `as_array()`を最後に入れると配列で結果が返ってくるので便利。
Realmのfilter() vs Arrayのfilter() 処理速度比較

# 確認したいこと
* Swift で Realm を使っているが、どれだけ早いの？
* Realm で対応できないクエリを書きたいけど、どうするべきなの？
例えば Object に `List<String>` を持たせているときは単純には filter できない。
    ```swift
    class Person: Object {
        @objc dynamic var id: String?
        @objc dynamic var name: String?
        @objc dynamic var grade: Int?
        let classList = List<String>() // 特定のクラスをもつ Person の検索はできない
    }
    ```
    この場合 Array.filter() で検索するか、Results.filter()で検索するかどちらが良いか。

# 結果
* Realm の方が速いので Realm を使おう
* 複雑な Query でも頑張って Realm で対応しよう

# 実験
## 準備
### データの登録
Personオブジェクトを8000個くらい用意。
classListに入る授業名は20個程度用意し、一人複数個持つように設定。
こんな感じで。
```swift
Person(value: [
    "id": "000001", 
    "name": "Alice", 
    "grade": 3,
    "classList": ["Math", "English", "Japanese", "Chinese"],
])
```

### 検索したい授業名を用意
今回は時間を測るだけなので、全てを列挙したものを作成。
```swift
let classNameList = [
    "English",
    "Japanese",
    "Chinese",
     :
    "Psychology",
]
```
それぞれを履修している生徒の人数を取得していく。

### 時間を測る関数
時間を測る関数を作成する。
クロージャを渡せるようにしておく。
```swift
func evalFunc(f: () -> Void) {
    let start = DispatchTime.now()
    f()
    let end = DispatchTime.now()
    let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds
    let timeInterval = Double(nanoTime) / 1_000_000_000
    print("elapsed time: \(timeInterval) seconds")
}
```
## 実行
### Array.filter() を使う
単純にArrayにしてfilterをかけてやる。
contains()が使える。
```swift
evalFunc {
    let realm = try! Realm()
    let allPersons = Array(realm.objects(Person.self)) // 一旦 Array にする
    for className in classNameList {
        let persons = allPersons.filter({ p in p.classList.contains(className) })
    }
}
// Time to evaluate function: 1.733439875 seconds
```

## Results.filter() を使う
単純には実行できないのでString結合したフィールドを作成しておく。
```swift
class Person: Object {
    @objc dynamic var id: String?
    @objc dynamic var name: String?
    @objc dynamic var grade: Int?
    let classList = List<String>()
    @objc dynamic var classListStr: [String] = [] // 追加
}
```
classList を join して classListStr に入れる。
```swift
person.classListStr = person.classList.joined(separator: "|") // 適当な文字で区切っておく
// こんな感じになる
// "Math|English|Japanese|Chinese"
```

いよいよ評価。
```swift
evalFunc {
    let realm = try! Realm()
    for className in classNameList {
        let persons = realm.objects(Person.self).filter("classListStr CONTAINS '\(className)'")
    }
}
// Time to evaluate function: 0.024232959 seconds
```
速い。

# まとめ
```
Array: 1.733439875 seconds
Realm: 0.024232959 seconds
```

私の環境下、問題設定では Realm の方が断然速くなった。
ちょっと頑張ってでも、Realm で検索可能なフィールドを作る方が良さそう。
【コピペで出来る】slack bot を用いて掃除当番botを作ってみた！

# 目次
* なぜこのシステムを作ったのか
* 使用するツール
* 導入手順
* ソースコードの解説等
* 最後に


# 1. なぜこのシステムを作ったのか
みなさんも御用達のslack
とても便利ですよね。
slackでしていることが自動化できたら便利で、需要もあります。


そこで、うちは掃除当番が事務所で１週間おきに変わるのですが、毎度紙などで管理するのも面倒ですよね。
**今回は、slack bot を使った当番botを作っていきます。**

:::note info
**今回は利便性を向上するために、当番表に新しい人材を追加してもソースコードを変更することなく動き続けるbotの実現を目指します。**
:::


以下、今回の完成の例です。


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/3c091886-7167-b208-9321-03cb86df1872.jpeg" width=65%>


# 2.使用するツール
- Slack Incoming Webhook（slackに送信する仕組み）
- GoogleAppScript（開発環境）
- GoogleSpredSheet（当番表の管理）


# 3. 導入手順
まずslack Incoming Webhookの設定から行いましょう
[こちら](https://slack.com/services/new/incoming-webhook)にアクセスをし、Incoming Webhookインテグレーションの追加を押して、自動送信をしたいチャンネルを選択し、設定を保存を押しましょう。


各設定ができるので行いましょう。（名前やアイコン）


---


次に、GoogleSpreadSheetの作成を行なっていきます。
以下が完成版です。ソースコードをコピペして作りたい方は配置等も全く同じものを作ってください。


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/f13f7abe-961c-ee54-78b6-7670e9f2f972.jpeg" width=45%>



IDについてですが、以下のように個人個人に振り当てられており、メンバーIDをコピーで取得できます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/177893cc-2952-8ade-636c-f4a078ae97f8.jpeg" width=30%>


当番の文字列は当番である人の右に書いておきましょう。
ソースコード内で、その文字列を判定して次の人へ当番を移行させます。


---



その次に、GoogleAppScriptを書いていきます。
その際に必要となる、以下のWebhook URLをコピーしておきましょう。


![S__722747402.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/08216ca9-01eb-2cac-7447-41ccb0aa55c7.jpeg)

# 4. ソースコードの解説等

```javascript
function myFunction() {
 var obj = SpreadsheetApp.openById(''); //スプレッドシートのURLにあるidをコピペ
 var sheet = obj.getSheetByName(""); //スプレッドシートのシート名をコピペ（変えてなかったら"シート１"）
 var person=2
 var i = 2
 var current_touban

//当番表の人数を取得
 while(true){
   name = ""
   cell = "A"+ person
   name = sheet.getRange(cell).getValues()
   //console.log(name)
   if(name==''){
     person=person-2
     break
   }
   person++
 }
 console.log('人数は'+person+'人です')

//当番の入れ替え
while(true){
  cell = 'C' + i
  previous_touban = sheet.getRange(cell).getValues()
  if(previous_touban=='当番'){
    i = i - 1
    sheet.getRange(cell).setValue('') //前回当番の人を当番から外す
    if(i==person){ //当番表の一番下の行の人が前回当番だった場合１番上の人へ当番を移す
      sheet.getRange("C2").setValue('当番')
      current_touban =sheet.getRange("B2").getValue()
      break
    }
    else{ //当番を次の人へ移す
    sheet.getRange('C'+(i+2)).setValue('当番')
    current_touban=sheet.getRange('B'+(i+2)).getValue()
    break
    }
  }
  i++
}


 //送信内容の設定
 var options =
 {
   "method" : "post",
   "contentType" : "application/json",
   "payload" : JSON.stringify(
     {
       "username":"当番bot", //送信されるメッセージのbot名
       "icon_url":'', //ここでbotのアイコンにしたいものを定義
       "text" :"今週の担当は" + "<@" + current_touban +'>'+  " さんです", //<@ + slackのID + >でメンション
       link_names: 1
     }
   )
 };
UrlFetchApp.fetch("", options); //先ほどコピーしたwebhook URLをコピペ

}
```

その後、gasのトリガーを送信したい時間帯に設定し、完了となります。




# 5. 最後に
今回はslack botを使った当番botを作成しました！
参考になった、良い記事だと思えば、いいねお願いいたします！！
Databricks にて、変数値をストレージ上に区切りテキスト（CSV・TSV等）として保存する方法

## 概要

Databricks にて、変数値をストレージ上に区切りテキスト（CSV・TSV等）として保存する方を共有します。

次のような関数を定義して実行します。変数に含まれる最初と最後の改行を削除してから、`dbutils.fs.put` により書き込ます。Synapse Spark pool で実施する場合には、`mssparkutils.fs.put` で同様のことが実施できるはずです。

```python
import inspect
from pyspark.sql import DataFrame, SparkSession
from pyspark.dbutils import DBUtils

def put_files_to_storage(
    path,
    content,
    is_overwrite = True,
):
    # 最初の行と最後の行を削除
    content = inspect.cleandoc(content)
   
    spark = SparkSession.getActiveSession()
    dbutils = DBUtils(spark)
    return dbutils.fs.put(path, content, is_overwrite)
```

## 実行例
### 関数を定義

```python
import inspect
from pyspark.sql import DataFrame, SparkSession
from pyspark.dbutils import DBUtils


def put_files_to_storage(
    path,
    content,
    is_overwrite=True,
):
    # 最初の行と最後の行を削除
    content = inspect.cleandoc(content)

    spark = SparkSession.getActiveSession()
    dbutils = DBUtils(spark)
    return dbutils.fs.put(path, content, is_overwrite)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/acff9106-09a8-36c5-9894-c0500e21d2ca.png)

### 保存先のパスと区切りテキストのコンテンツを定義

```python
path = "file:/test/test.csv"

csv_data_rows = """
id,name,mail,weight, height
1,"user_aaa","user_aaa@test.com",53.5,180
2,"user_bbb","user_bbb@test.com",53.5,180
3,"user_ccc","user_ccc@test.com",53.5,180
"""
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/b72d9a4e-8f0c-cd24-d598-aa57cddf73fa.png)

### ファイルの書き込み

```python
put_files_to_storage(path, csv_data_rows)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/24061b77-ae0e-9fd9-90cc-5a1ba8e48b0a.png)

### ファイルを確認

```python
file_content = dbutils.fs.head(path)
print(file_content)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/7fc23160-de98-2388-a95f-e56927594508.png)

### 本手順で作成したリソースを削除

```python
# ファイルを削除
dbutils.fs.rm(path, True)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/14cd84d0-6ca0-1573-cbb1-e7105776abb9.png)
シンボリックリンクの所有者・パーミッションを設定する

シンボリックリンク自体の権限設定について気にする必要があったのでメモ。

# TL; DR
所有者は `chown -h` で変える。
パーミッションは仕様上変えられない。変えることが必要な場面は無いはず。

# シンボリックリンクの所有者の変更
普通に chown で変えてみる。
```shellscript
$ ls -l ..
total 0
drwxr-xr-x. 2 user1 group1 21 Oct 28 11:28 test1
drwxr-xr-x. 2 user1 group1  6 Oct 28 11:28 test2
$ ls -l
total 0
lrwxrwxrwx. 1 user1 group1 8 Oct 28 11:28 symlink -> ../test2
$ sudo chown user2:group2 symlink
$ ls -l
total 0
lrwxrwxrwx. 1 user1 group1 8 Oct 28 11:28 symlink -> ../test2
```
変わってないやん。
```shellscript
$ ls -l ..
total 0
drwxr-xr-x. 2 user1 group1 21 Oct 28 11:28 test1
drwxr-xr-x. 2 user2 group2  6 Oct 28 11:28 test2
```
リンク先の `../test2` の所有者が変わったようです。
なんか、シンボリックリンク自体の所有者を変えたい場合は `-h` オプションが必要とのこと。
```shellscript
$ sudo chown -h user2:group2 symlink/
$ ls -l
total 0
lrwxrwxrwx. 1 user1 group1 8 Oct 28 11:28 symlink -> ../test2
```
変わってないやん。
ディレクトリの最後の / を書いちゃいけないらしい。きびしい。
```shellscript
$ sudo chown -h user2:group2 symlink
$ ls -l
total 0
lrwxrwxrwx. 1 user2 group2 8 Oct 28 11:28 symlink -> ../test2
```

# シンボリックリンクのパーミッションの変更
ということはこうかな？
```shellscript
$ sudo chmod -h 755 symlink
chmod: invalid option -- 'h'
Try 'chmod --help' for more information.
```
chmod には -h ないんかい。
`man chmod` より
```
       chmod  never changes the permissions of symbolic links; the chmod system
       call cannot change their permissions.  This is not a problem  since  the
       permissions  of  symbolic  links are never used.  However, for each sym‐
       bolic link listed on the command line, chmod changes the permissions  of
       the  pointed-to file.  In contrast, chmod ignores symbolic links encoun‐
       tered during recursive directory traversals.
```
シンボリックリンクのパーミッションというのは使用されることはなく変更の必要はない。 chmod コマンドはリンク先のパーミッションを変更する。とのこと

# なんで気にする必要があったのか
apache の設定ファイルで以下のようにするとシンボリックリンクを辿ってくれるようになる。
```apache
<Directory "/">
  Options FollowSymLinks 
</Directory>
```
下のようにすると、シンボリックリンク自体の所有者とリンク先の所有者が一致するときのみシンボリックリンクを辿る。こちらのほうがより制限された設定。
```apache
<Directory "/">
  Options SymLinksIfOwnerMatch
</Directory>
```
これが設定されていてシンボリックリンクを使いたかったのです。
これはパーミッションは関係ないけどパーミッションも合わせないといけないのかと思って `chmod -h` なんてコマンドを創り出してしまった。

私の事象ではページは開けるのにCSSが適用されていないって感じでした。
つまりこの設定は直接参照した場合であって、PHPがシンボリック越しにファイル読み込もうとした場合は特に問題ない模様。これも気をつけないといけないですな。
ROS2プログラミング基礎_1-1: hello_node

## はじめに
ROS2のプログラミングの勉強（基礎編）とし実施したことをまとめて残していきます．
このページでは全体の流れを最も簡単なプログラム（ノード） hello_node の実行を例にして示します．

## 環境
・PC: Panasonic Let's Note CF-FV
・OS: Windows11 Pro (64bit)
・VirtualBox: 6.1.38 (Ubuntu20.04.5, GUI環境)
・ROS: ROS2 Foxy

ここまでの環境構築については下記参照
・Windows PCにVirtualBox＋Ubuntuを導入
https://qiita.com/pez/items/a3ef1855f7e1e0ed3dfd
・ROS(ROS2 Foxy)をインストール
https://qiita.com/pez/items/1df36628524ff40a3d93


## 1. ワークスペース作成
```ruby:
$ cd
$ mkdir -p ~/＜ワークスペース名＞/src/
```
今回は ＜ワークスペース名＞は hello_ws にすることにします．

## 2. パッケージ作成
```ruby:
$ cd ~/hello_ws/src
$ ros2 pkg create --build-type ament_python --node-name ＜ノード名＞ ＜パッケージ名＞
```
今回は ＜ノード名＞ は hello_node
＜パッケージ名＞ は hello
にすることにします

## 3. プログラミング
#### 1. package.xml ファイルの編集
※エディタは自分の好きなものを使えばよい．下記は emacs を使う場合．
　vi package.xml でもいいし nano package.xml でもよい．
```ruby:
$ cd ~/hello_ws/src/hello
$ emacs package.xml
```
自作パッケージを一般公開するときには変更する必要があるが，今回は特に何もしません．

#### 2. setup.py ファイルの編集
```ruby:
$ cd ~/hello_ws/src/hello
$ emacs setup.py
```
23行目を確認
ノード名=パッケージ名.ノード名:main
となっている必要がある．今回パッケージを作成する際に --node-name のオプションを付けているので自動的に下記のようになっています
```ruby:
entry_point={
    'console_scripts': [
        'hello_node = hello.hello_node:main' 
    ],
},
```
よって今回何もする必要はありませんが，もし１つのパッケージに複数のPythonファイルがある場合はそのファイルごとにエントリポイントを指定しなければならないので setup.py を必ず変更する必要があります．

#### 3.ソースコード作成
本来ここでソースコードを作りますが，ここではパッケージ作成時に自動的に作られている hello_node.py をそのまま利用することにします．
中身を確認するため開きます．
```ruby:
$ cd ~/hello_ws/src/hello/hello
$ emacs hello_node.py
```
print文で Hi from hello. と表示するだけであることが分かると思います．


## 4. ビルド
ワークスペース名直下のディレクトリ以外はビルドできませんのでそうでない場合は移動します
初めてビルドしたとき build, install, log ディレクトリが作成されます
```ruby:
$ cd ~/hello_ws
$ colcon build
```
成功すると小さな別ウィンドウで 'colcon build' succesfull と表示されます

## 5. 設定ファイルの反映
アンダーレイ設定ファイル（ROS2システムの設定）を反映させます
```ruby:
$ source /opt/ros/foxy/setup.bash
```
オーバーレイ設定ファイル（自作ワークスペースの設定）を反映させます
```ruby:
$ source ~/hello_ws/install/setup.bash
```

上記２つのコマンドは .bashrc に記述しておくと便利です
自作パッケージが増えるとオーバーレイ設定ファイルも増えていきます
```ruby:.bashrcの編集
$ emacs ~/.bashrc
```
source /opt/ros/foxy/setup.bash
source ~/hello_ws/install/setup.bash

の２行を追加する

```ruby:
$ source ~/.bashrc
```
と入力するとオーバーレイ設定ファイルがいくら多くなっても一度で反映させることができます

## 6. ノードの実行
```ruby:
$ ros2 run hello hello_node
```
ros2 run <パッケージ名> <ノード名>
で実行できます．

Hi from hello.

と表示されたら成功です．

## 7. 練習
hello_node.py を編集して別の表示がされるようにしてみましょう．
下記を行う必要があります．

　1.hello_node.pyの中身を編集して保存
　2.ビルド
　3.設定ファイルの反映
　4.ノードの実行
【Linux】trコマンドとは？

trコマンドとは？
=====================
⇒指定した文字を置換・削除するコマンド。

### 書式
```
tr [オプション] [文字列１] [文字列２]
```
オプションの指定がない場合、文字列１を文字列２に置換する。

#### オプション
| オプション | 動作 |
|------------|-----------------------------|
| -d | 指定した文字列１を削除する。|
| -s | 文字列１で指定した文字が連続した場合、１文字に置き換える。 |

### 使用する主な文字クラス
| 文字クラス | 説明 |
|------------|-----------------------------|
|[:alpha:]|英字|
|[:lower:]|英小文字|
|[:upper:]|英大文字|
|[:digit:]|数字|
|[:alnum:]|英数字|
|[:space:]|スペース|

以下使用例
```
cat file1 | tr -s [:digit:]
```
ここでは、file1内の連続した数字を1文字に置換している。
プログラミング言語の年収ランキングを作って気づいたこと4つ



## プログラミング言語の年収ランキングを求人票から作成した

サイトは以下の通り

https://flamevalue.short-tips.info/ranking.html

サムネイルはこんな感じ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1678228/16cf4f1d-3f33-8a1d-6b07-e250554c7d3e.png)


## なんで作ったの？:純粋に強さ比べがしたい

<img src="https://s3-ap-northeast-1.amazonaws.com/cdn.bibi-star.jp/production/imgs/images/000/234/348/lqip.png?1547703502">

こんな子供っぽい動機でもいいじゃないか。

強いものに憧れるもんだろう。


## 注意事項:年収だけが技術の優劣を決める要素ではない

当然ながら、年収だけが技術の優劣を決める要素ではありません。

- 求人数やGithubのフォロー数などは代替性の基準になりますし

- リモート率はその言語で使用する職場の柔軟性の基準にもなりうるでしょう

ですので、「年収が低い=その技術は必要ない」と考えるのはあまりに短絡的ですし、浅はかですよね。

あくまで一つの基準としてお受け取りください

詳しい内容は以下サイトからお願いします。

https://pm.short-tips.info/who/language_ranking.md

## 作ってみて気づいたこと

### 最新の技術,流行し始めた技術ほど年収が上がる

- Rust(IT)

- Copilot

- kubernetes

これらの技術はつい1,2年ほど前から急速に流行してきましたね。（体感ですが）


### 希少性があっても古い言語は年収が低い

- Cobol

銀行系のシステムだといまだに名前が出るそうです。

古い言語であるのは間違い無いですが、これだけ古いとできる人が減って希少性が上がり年収が増える...と思っていた時期もありましたが。

理由は不明ですが、古い言語は年収が低い傾向にあるそうです。（知っている人いたら教えて詳しい人）

それでも社会に必要とされてる技術であるのは間違い無いですね。


### 使用者が多数いる技術ほど年収が下がる

- Java 

この言語が上位に入る所をみたことがありません。

正直できる人が多すぎて、いくらでも代わりが効いてしまいそうですね。

Javaの詳しい動きを知っている人とかなら違うのかも...


### web系は年収が高い(賛否両論)

- Ruby on Rails

- Flask

webフレームワークは覚えているだけで年収が上がる傾向にあると思います。

Googleという基盤(インフラ)が重宝され続ける限り、整備され続ける限りwebフレームワークは不滅です。（私見あり）

- Apache Tomcat

これはwebフレームワークと言えるかわかりませんが、まぁweb系の技術であるのは間違いないでしょう。



### 組み込み系or低級言語は年収が低い傾向(賛否両論)

- C言語

- C++

これらの言語は組み込み系で使われることがあるそうですが、ランキングの上位に入ったところはみたことないです。

自分はC言語やったことありますが、入門書やった後で何をすればいいかわからなくなってしまいました。

あるいは、careerJetのサイトよりも高く買ってくれるサイトがあるかもしれませんね。


## まとめ

以上茶番みたいな内容でした。

改めてまとめるとこんな感じですかね

- 最新の技術,流行し始めた技術ほど年収が上がる

- 使用者が多数いる技術ほど年収が下がる

- web系は年収が高い(賛否両論)

- 組み込み系or低級言語は年収が低い傾向(賛否両論)

「プログラマーが知るべき97のこと」でも書いてあったと思いますが、

**一年に一度は新しい言語を学ぼう**というのは良い教訓かもしれませんね。
【Proxmox】WebUI でログインできなくなった【PVE の GUI でパスワードが通らない】

## Proxmox VE で "Login failed. Please try again"

> クラスタを組んでいる PVE（[Proxmox VE](https://ja.wikipedia.org/wiki/Proxmox_VE_%28%E4%BB%AE%E6%83%B3%E5%8C%96%E3%83%97%E3%83%A9%E3%83%83%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%29)）の管理画面にブラウザでアクセスすると、**ログイン画面は表示されるもパスワードが通らずログインできなくなった**。
>
> SSH 接続はできるし、`passwd` で再設定しても WebUI からはログインできない。
>
> ![Proxmox VE Login Error Login failed. Please try again](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78776/b4dcb826-e917-77d6-d225-7fc4a1ca5afa.png "Proxmox VE Login Error Login failed. Please try again")

## TL; DR <sub><sup>（今北産業）</sup></sub>

1. クラスターを組んでいた場合、<font color=darkorange>**落ちているノード（マシン）がないか確認**</font>してください
1. PVE は、クラスターの `Quorum`（[定足数](https://ja.wikipedia.org/wiki/%E5%AE%9A%E8%B6%B3%E6%95%B0)）が足りない場合、GUI（WebUI）からのログインは、できない仕様でどうしようです
1. 落ちたマシンをすぐに復旧できない場合、定足数を減らしてみるか、クラスターを取り消す必要があります

## TS; DR <sub><sup>（確認、変更と取り消しの仕方）</sup></sub>

まず、WebUI を表示しているマシンに SSH 接続して以下を試します。

```shell-session:定足数の確認
$ pvecm status | grep Expected\ votes
Expected votes:   2
```

上記の場合、最低限必要なノード数は 2 つということが確認できます。次に、現在の参加数を確認します。

```shell-session:現在の参加数の確認
$ pvecm status | grep Nodes
Nodes:            1
```

上記の場合、参加中のノード数は 1 つということが確認できます。

この時、単純に `pvecm status` と打つと、おそらく `waiting for quorum ...` と表示されていると思います。これは、メイン・ノードを決定するのに必要なノード数が足りていないからです。

このような場合は、定足数を変えるか、クラスターを削除します。

```shell-session:定足数を1に設定する
$ pvecm expected 1

$ # すでに Expected votes 数のノードが参加している場合は
$ # Unable to set expected votes: CS_ERR_INVALID_PARAM エラー
$ # になります。
```

```bash:クラスターを削除する（連携データも消えるので取り扱い注意）
systemctl stop pve-cluster corosync
pmxcfs -l
rm /etc/corosync/*
rm /etc/pve/corosync.conf
killall pmxcfs
systemctl start pve-cluster
```

:::note warn
上記の「連携データも消える」というのは、クラスター間で分散していたデータが消えるということです。

つまり、落ちているノードが保持していたイメージやデータは消えます（厳密には、このノードからはアクセスできなくなります）。

本来クラスターをやめるときは、すべてのノード間でデータを同期してから止めるのが正しい方法です。そのため、落ちているノードを起動させないと定足数に満たない場合は正常にクラスターを止めることができないということになります。

上記の処理は強制的に「クラスターをなかったことにしている」ので、（定足数に必要なマシンが飛んだなど）よほどの緊急事態でない限り、クラスターを強制削除するのはオススメできません。

まずは、落ちているノードを起動することに注力した方が良いと思います。
:::

### 参考・関連情報

- [Separate node without reinstall](https://pve.proxmox.com/pve-docs/pve-admin-guide.html#pvecm_separate_node_without_reinstall) | Admin Guide | PVE Docs @ pve.proxmox.com
- [Proxmox VE 6 - Removing cluster configuration](https://forum.proxmox.com/threads/proxmox-ve-6-removing-cluster-configuration.56259/#post-259203) @ forum.proxmox.com
- [Proxmox VE - Login failed. Please try again.](https://forum.proxmox.com/threads/proxmox-ve-login-failed-please-try-again.55488/page-2#post-437733) @ forum.proxmox.com
Javascript Lookup項目Details取得//Lookup項目に値設定 

	//Lookup項目Details取得
	if (Xrm.Page.data.entity.attributes.get("fieldname").getValue() != null) {
	   var CustomerId = Xrm.Page.data.entity.attributes.get("fieldname").getValue()[0].id;
	   var CustomerName = Xrm.Page.data.entity.attributes.get("fieldname").getValue()[0].name;
	   var CustomerType = Xrm.Page.data.entity.attributes.get("feildname ").getValue()[0].entityType;
	}


	//Lookup項目に値設定
	var formContext = executionContextObj.getFormContext();
	var loginUserId = Xrm.Utility.getGlobalContext().userSettings.userId;
	loginUserId = loginUserId.replace('{', '').replace('}', '');
	var loginName = Xrm.Utility.getGlobalContext().userSettings.userName;
	　
	var systemUserLookUp = new Array();
	systemUserLookUp[0] = new Object();
	systemUserLookUp[0].id = loginUserId;
	systemUserLookUp[0].name = loginName;
	systemUserLookUp[0].entityType = "systemuser";

	formContext.getAttribute("new_lookupuser").setValue(systemUserLookUp);
opencv.js の独自ビルド

## スリムな opencv.js がほしいので
wasmで動作している opencv.js ですが、ファイルサイズが大きいのがイマイチです。自分の使う機能だけを入れたシェイプアップ版を作りたくなりました。

## いや、公式がビルドした opencv.js ファイルをほしいという場合
こちらで説明されています。

https://qiita.com/puku0x/items/8b71efa61fce72e22188

## (1) dockerでなるべく簡単にビルドする
見つけたのは下記の記事。

https://qiita.com/YuukiToriyama/items/747df5721536373be76a

サクッとビルドは終わったのですが、できあがったopencv.jsを使用してテストしたところ、なんだかエラーが出てうまくいきませんでした。
具体的には、**"Uncaught TypeError: cv.imread is not a function"** が発生します。

## (2) うごくビルドを作るには？
下記を見ると、**emsdk 1.39.15** を使うとうまくいくよ、とあります。

https://stackoverflow.com/questions/67190799/how-to-include-cv-imread-when-building-opencv-js

## (1) と (2) を組み合わせる
下記のようにしたところ、cv.imread() も問題ないバージョンが作れたようです。
皆さんの情報に感謝。
```
mkdir build_opencvjs
cd build_opencvjs/
git clone https://github.com/opencv/opencv.git
cd opencv/
docker run --rm --workdir /code -v "$PWD":/code "trzeci/emscripten:1.39.15-upstream" python ./platforms/js/build_js.py build
```
Get LoginUser details with javascript 

	/**
	* ログインユーザーの管理者フラグの取得
	*
	*/
	function LoginUser() {
	    debugger;
	    var manageflg = false;
	    var loggedInUserId = Xrm.Utility.getGlobalContext().userSettings.userId;
	    loggedInUserId = loggedInUserId.replace('{', '').replace('}', '');
	    var globalContext = Xrm.Utility.getGlobalContext();
	    var globalUrl = globalContext.getClientUrl();
	    var req = new XMLHttpRequest();
	    req.open("GET", globalUrl + "/api/data/v9.1/systemusers(" + loggedInUserId + ")?$select=new_manage_flg", false);
	    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
	    req.setRequestHeader("Accept", "application/json");
	    req.setRequestHeader("OData-MaxVersion", "4.0");
	    req.setRequestHeader("OData-Version", "4.0");
	    req.onreadystatechange = function () {
	        if (this.readyState === 4) {
	            req.onreadystatechange = null;
	            if (this.status === 200) {
	                var data = JSON.parse(this.response);
	                var userexecutive = data.new_manage_flg;
	                if (userexecutive == 1) {
	                    executiveflg = true;
	                }
	            } else {
	                Xrm.Utility.alertDialog(this.statusText);
	            }
	        }
	    };
	    req.send();

	    return manageflg;
	}
M1 Mac (Apple Silicon, M1 PRO, 2021) にPandasGUIを導入

# はじめに
M1Macで，pandasguiを普通に``pip install pandasgui``で入れようとすると，PyQt5（依存関係の描画ライブラリ）のインストールでエラーが吐かれる．
PyQt5のインストール方法を調べたところ，brewでインストールして参照すると上手くいくようなのでそのように導入．

なお，anaconda環境での実施とします．

# PyQt5のインストール
以下を参照ください．

https://zenn.dev/eisukeito/articles/530313bdb4d42a#gui%E9%96%8B%E7%99%BA%E7%94%A8%E3%81%AEqt5%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB

手順は至ってシンプルで，
1. brewでインストール
1. インストールしたsite-packagesをanaconda環境のsite-packagesにリンクを貼る
以上です．
この際，PyQt5のPythonバージョンに合わせて，適宜conda環境を作成します．（元々同じPythonバージョンであれば不要）


## PandasGUIのインストール
あとはconda環境に入って，普通に``pip install pandasgui``を叩けばインストール完了です．

## 終わりに
以下のコードでPandasGUIの挙動を確認できます．
```python:hoge.py
import pandas as pd
import pandasgui as pdgui

alldata = pdgui.datasets.all_datasets
pdgui.show(**alldata)
```
![Screen Shot 2022-10-28 at 11.21.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203543/cfc8cf5d-5550-7148-b9f1-dad19d790b11.png)

pdgui.showには，``kwd=df``の形式で複数のDataFrameが渡せるようです．

基本的に素晴らしいんですが，私の環境では複数カラムを選択して，ドラッグしても1つのカラムしかボックスに入らない．．．（例えば，y軸に複数カラムをドラッグ，Pivotメソッドに複数Value指定など）
Windows版だとそんなことはないので，バグなのでしょうか．これさえ解決してくれたら最高です．．
【Unity】公式プロジェクトから、デザインパターンを学んでみよう(Part 0)

# ●シリーズ
- [【Unity】公式プロジェクトから、デザインパターンを学んでみよう(Part 1:単一責任の原則)](https://qiita.com/kiku09020/items/f250a06634e51ec2e204)
- [【Unity】公式プロジェクトから、デザインパターンを学んでみよう(Part 2:開放・閉鎖の原則)](https://qiita.com/kiku09020/items/bfcf01511dc385c797ac)






# ●はじめに
- Unityを利用しながら、デザインパターンについての理解を深めようと思います。
- **筆者はデザインパターンを知らないです**。本記事を書きながら学んでいきます。先人方からすれば、低質な記事だと思いますが、ご了承ください…。
- 本記事に間違いなどがあれば、コメントからご教授お願いします。

また、内容が結構ボリューミーなので、デザインパターンごとに記事を投稿させていただきます。
今回の記事では、簡単な概要と、役に立ちそうなサイトや記事を紹介するだけです。






# ●該当のプロジェクトについて
## ○リポジトリ
↓こちらのリポジトリから、Unityの公式のプロジェクトがダウンロードできます。

https://github.com/Unity-Technologies/game-programming-patterns-demo


↓また、こちらのサイトの中から説明のPDFをダウンロードできます。(※全て英語です)

https://resources.unity.com/games/level-up-your-code-with-game-programming-patterns

## ○内容
- プロジェクトの内容は、こんな感じです
    1. **SOLID原則**
    1. **Factory Method**
    1. **ObjectPool**
    1. **Singleton**
    1. **Command**
    1. **State**
    1. **Observer**
    1. **MVP**

<br>

- SOLID原則のフォルダ(フォルダ番号:1~5)は、スクリプトのみです。
- それ以降のフォルダ(フォルダ番号:6~12)は、シーンやGameObjectが含まれていて、ゲームを実行して挙動を実際に操作できます。
- General, ScriptTemplatesフォルダはほぼ無関係です。素材とかが入ってます。

※ **スクリプトやシーン内のテキストは全て英語**なので、Google翻訳を駆使して、解読頑張りましょう！！！






# ●デザインパターンについて、簡単な概要
※僕もちょうど昨日、デザインパターンという存在を知ったので、あんまりしっくりしてないところがあります…。すっごいゆるふわな説明になるので、ガチガチな記事が読みたい方はブラウザバックしてください！


## ○SOLID原則
- 5つの原則の総称がSOLID原則。
- **クラスとか関数の拡張がしやすくなったり、コードの可読性を高めるための原則**　です。
- 以下にめちゃくちゃ簡単な説明つけときます。正直自分でも全然分かってないです。
- 詳細な説明は、後日投稿予定の各記事に記載します。

### ① 単一責任原則(SingleResponsibility)
- **1つのクラスに、色んな機能を詰め込みすぎたらダメ**っていう原則。
- 例えば、「Player」クラスじゃなくて、[PlayerAction],[PlayerAudio],[PlayerAnimation]みたいに、**細分化すればバグも少なくなったり、分担作業もしやすくなる**。

### ② 開放・閉鎖原則(OpenClosed)
- **拡張には開放的で、変更には閉鎖的に対応しろ**っていう原則。

### ③ リスコフの置換原則(Liskov Substitution)
- **子クラスは、親クラスができることは必ずできるようにしろ**っていう原則。

### ④ インターフェース分離原則(InterfaceSegregation)
- **細分化して、必要な関数だけ実装しろ**っていう原則。

### ⑤ 依存性逆転原則(DependencyInversion)
- **クラスは、そのクラスよりも下のクラスに依存するな**っていう原則。
- **抽象(インターフェース)に対して依存するようにするべき**　らしい。

<br>

**以下製作途中です**

## ○Factory Method


## ○ObjectBool


## ○Singleton


## ○Command


## ○State


## ○Observer


## ○MVP



# ●さいごに



- 次: [【Unity】公式プロジェクトから、デザインパターンを学んでみよう(Part 1:単一責任の原則)](https://qiita.com/kiku09020/items/f250a06634e51ec2e204)

# ●参考サイトなど
- [Level up your code with game programming patterns
](https://resources.unity.com/games/level-up-your-code-with-game-programming-patterns)
- [イラストで理解するSOLID原則](https://qiita.com/baby-degu/items/d058a62f145235a0f007)
- [C#の設計の基本【SOLID原則】まとめ](https://unity-yuji.xyz/object-oriented-code-design-solid/)
- [デザインパターン「Factory Method」](https://qiita.com/shoheiyokoyama/items/d752834a6a2e208b90ca)
WSL+nvm(+node+npm)のインストールでエラったときの解決法

WSLでnvmをインストールしたいけど、
ぜんぜんできなかったのでメモ。

# 結論
```
sudo curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | sudo bash
```
sudoれ！


# 発生したエラー
```
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash
~ ナイショ ~
node:net:361
    err = this._handle.open(fd);
                       ^

Error: EINVAL: invalid argument, uv_pipe_open
    at new Socket (node:net:361:24)
    at createWritableStdioStream (node:internal/bootstrap/switches/is_main_thread:78:18)
    at process.getStdout [as stdout] (node:internal/bootstrap/switches/is_main_thread:148:12)
    at console.get (node:internal/console/constructor:209:42)
    at console.value (node:internal/console/constructor:337:50)
    at console.log (node:internal/console/constructor:376:61)
    at evalScript (node:internal/process/execution:87:5)
    at node:internal/main/eval_string:27:3 {
  errno: -4071,
  code: 'EINVAL',
  syscall: 'uv_pipe_open'
}
node:internal/modules/cjs/loader:959
  throw err;
  ^

Error: Cannot find module '\\wsl$\Ubuntu-22.04\node_modules\npm\bin\npm-cli.js'
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:956:15)
    at Function.Module._load (node:internal/modules/cjs/loader:804:27)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:17:47 {
  code: 'MODULE_NOT_FOUND',
  requireStack: []
}
Could not determine Node.js install directory
=> Close and reopen your terminal to start using nvm or run the following to use it now:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
```
Chrome の自作拡張機能をインストールする

ちょうどよい手順の記事がなかったので手順のシェアと備忘のため

## 1. 拡張機能設定画面を開く
[chrome://extensions/](chrome://extensions/)

## 2. デベロッパーモードをオンにする
 ![スクリーンショット 2022-10-28 11.20.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61095/150c31e3-d0d0-3c9b-c36a-952e39a5ed22.png)

## 3. 画面にドロップ

拡張機能のフォルダをそのまま画面にドロップするとエラーが無ければ拡張機能のページにドラッグ&ドロップでインストールされます


拡張機能のフォルダの構成は以下のように `manifest.json` を含むファイルです

```
.
└── src  <==== これをドロップすれば良い
     ├── manifest.json
     ├── style.css
     └── script.js
```
【データ基盤構築/BigQuery】WINDOW関数を使用して、コンテンツ公開日から7日間のPV数を抽出する

# 今回の課題
コンテンツ毎に、コンテンツを公開してから7日間の合計PV数を算出した。
実装する過程で、下記のような不具合が発生してしまった。

WINDOW関数内のORDER BY句に`release_date`を指定してしまっていたことによって、
コンテンツ公開日から7日間のPV数を正しく算出できなかった。

コンテンツ毎に`release_date(公開日)`は、特定の日が一日しか存在しないため、
WINDOW関数内で`release_date`でソートしても、公開日から何日経っているのかを把握できなかったことが原因だった。
## 使用したクエリ
ORDER BY句で`release_date`を指定してしまっているので、うまくソートできていない。
```SQL
select
    date            -- ページビューが発生した日
    , user_type     -- '新規ユーザー' or '再訪ユーザー'
    , release_date  -- 公開日
    , page_title    -- コンテンツ名
    , sum_pageviews -- PV数
    , sum(sum_pageviews) over (partition by page_title, user_type order by unix_date(release_date) range between current row and 6 following) as sum_pageviews_7days -- 公開後7日間のPV数
from
    `テーブル名'
```

## 解決したクエリ

```SQL
select
    date            -- ページビューが発生した日
    , user_type     -- '新規ユーザー' or '再訪ユーザー'
    , release_date  -- 公開日
    , page_title    -- コンテンツ名
    , sum_pageviews -- PV数
    , sum(sum_pageviews) over (partition by page_title, user_type order by unix_date(date) range between current row and 6 following) as sum_pageviews_7days -- 公開後7日間のPV数
from
    `テーブル名'
where
    date = release_date
```

最初のクエリから修正した点は、
* WINDOW関数内のORDER BY句で`date`カラムを指定するように変更した。
* WHERE句で`date = release_date`でフィルタリングした。
というところ。

上記の２つを組み合わせることよって、
**`release_date(公開日)`から、dateが何日間経過したか**というところを表現することができる。

※WHERE句の`date = release_date`が無ければ、7日間移動合計の値が抽出されてしまうので注意
ROS2+Turtlebot3 動作テスト(gazeboシミュレーション) SLAM／Navigation

## はじめに
TurtleBot3をROS2で動かした際の忘備録(2)です
本ページはgazeboを使ったシミュレーションです．実機については下記別記事参照
https://qiita.com/pez/items/1d3d15b3911d5dab1702

【下記の状態からを想定しています】

・ホストPCにVirtualBox＋Ubuntuが導入済み（下記別記事参照）
https://qiita.com/pez/items/a3ef1855f7e1e0ed3dfd
・ホストPCにROS(ROS2 Foxy)がインストール済み（下記別記事参照）
https://qiita.com/pez/items/1df36628524ff40a3d93

・TurtleBot3のシミュレーション関連のパッケージのみ未導入


## 環境
##### ホストPC (Panasonic Let's Note CF-FV)
・OS: Windows11 Pro (64bit)
・VirtualBox: 6.1.38 (Ubuntu20.04.5, GUI環境)
・ROS: ROS2 Foxy

##### ロボット
・TurtleBot3 waffle pi (Raspberry Pi 3B+)
　または
・TurtleBot3 burger (Raspberry Pi 3B+)


## シミュレーション関連パッケージ導入
ワークスペース作成
```ruby:
$ cd
$ mkdir -p ~/turtlebot3_ws/src/
```
TurtleBot3(シミュレーション)関連パッケージのインストール
※ソースコードからビルド
```ruby:
$ cd ~/turtlebot3_ws/src
$ git clone -b foxy-devel https://github.com/ROBOTIS-GIT/turtlebot3_simulations.git
$ cd ~/turtlebot3_ws
$ colcon build --symlink-install
```
設定反映
```ruby:
$ cd ~/turtlebot3_ws
$ source install/setup.bash
```



## シミュレーションを実行してみる
※立ち上がるまで時間がかかる場合があります
```ruby:
$ ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py
```

このコマンドの「turtlebot3_world.launch」の部分を下記のように変えると
それぞれロボットの周囲にデフォルトで用意される環境が変わります

・turtlebot3_empty_world.launch.py
  地面だけあって他に何もない空間

・turtlebot3_house.launch.py
  家の中を模擬したような空間（注：非常に重い，ノートパソコンでは辛いかも）


gazeboが起動できたらキーボードからの操作を試してみる
※別のターミナルを立ち上げて実行
```ruby:
$ ros2 run turtlebot3_teleop teleop_keyboard
```
または
```ruby:
$ ros2 run teleop_twist_keyboard teleop_twist
```


## SLAMのシミュレーション
※gazeboシミュレーターの中にturtlebot3が立ち上がってる状態で行います

```ruby:
$ ros2 launch turtlebot3_cartographer cartographer.launch.py use_sim_time:=True
```
立ち上がったらキーボード操作（teleop_keybord)などを使って動かしてみましょう
周辺地図の作成ができたら成功です

地図の保存
```ruby:別のターミナルにて
$ ros2 run nav2_map_server map_saver_cli -f ~/map
```
※mapの部分は任意の名前でOK，「~/」を入れるとホームディレクトリ直下に保存される


## ナビゲーションのシミュレーション
※SLAMで地図が保存された後を想定しています

ナビゲーションノードを立ち上げる
```ruby:
$ ros2 launch turtlebot3_navigation2 navigation2.launch.py use_sim_time:=True map:=$HOME/map.yaml
```
※map.yaml の部分はmapを保存した時の「自分でつけた名前」.yaml とする．

操作方法
1.「2D Pose Estimate」ボタンをクリック
2. 現在ロボットのいる位置をクリックして緑色の矢印をロボットが向いている方向に合わせる
3.「Navigation2 Goal」ボタンをクリック
4. ロボットを移動させたい位置をクリックして緑色の矢印を最終的にロボットに向かせたい方向に合わせる

ロボットが目的地に動いたら成功

### 備考
このナビゲーション，動かないことが結構あるようです．下記に気を付けるとうまく動く可能性が高まる気がします．

・現在のロボットのいる位置と方向はなるべく正確に合わせる（操作方法の２）
・操作方法の２と３の間に Teleop などでゆっくりロボットを動かしてみる
・操作方法の４の前に Teleop などロボットに動作指令を送るノードは全て落としておく
・目的地はあまり遠くに設定しない
Retrieve Entity Record With JavaScript


Dynamics2011よく使っていたデータの取得方法

	function GetEntityDetails() {
	    var result = new Array();
	    
	    var lookupFieldId = "";
	    if (Xrm.Page.getAttribute("new_entity").getValue() != null) {
	        lookupFieldId = Xrm.Page.getAttribute("new_entity").getValue()[0].id;
	    }

	    if (lookupFieldId != "") {

	        var field1Value = "";
	        var field2Value = "";

	        //医療機関のオブジェクト取得
	        XrmServiceToolkit.Rest.Retrieve(lookupFieldId, "new_entityNameSet", null, null, function (result) { entityName = result; }, XrmServiceToolkit.Common.ShowError, false);

	        if (!IsNull(entityName.field1)) {
	            result[0] = entityName.field1;
	        }
	        
	        if (!IsNull(entityName.field2)) {
	            result[1] = entityName.field2;
	        }
	    }
	}



//*****************************************************参考
//https://www.patrickschadler.com/retrieve-entity-xrmservicetoolkit/
var cols = ["name", "value1"];
var retrievedCampaign = XrmServiceToolkit.Soap.Retrieve("campaign", campaignId, cols);

if (retrievedCampaign.attributes["name"] != undefined) {
var name = retrievedCampaign.attributes["name"].value;
}

	//取得項目確定
	XrmServiceToolkit.Rest.Retrieve(product[0].id, "new_productSet", "new_category", null, function (result) { productresult = result }, XrmServiceToolkit.Common.ShowError, false);
	var category = productresult.new_category != null ? productresult.new_category.Value : null;
	if (category == 1) {
	    // 定期非常勤の場合
	    Xrm.Page.ui.tabs.get("tab_approach_t").setVisible(true); //
	}
1行メモ

## 1行メモ

* `メモ.vbs`

```vb
WScript.CreateObject("WScript.Shell").SendKeys "{kanji}"

Dim Input
Input = InputBox("メモを入力してください。")

If Input = "" Then
	WScript.Quit
End If

set fso = CreateObject("Scripting.FileSystemObject")
set f = fso.OpenTextFile("メモ.txt", 8, True)
f.WriteLine(Now & ", " & Input)
f.Close
```

![aa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/4a55c760-131d-ecd5-da6e-bfd57f613066.png)

![スクリーンショット 2022-10-26 105636.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/8831f056-999b-e821-51b2-5c8238f8ab7f.png)
初心者によるatcoder(1回目)：001 - Print 5+N

10/28の演習記録です。
ご意見やいいねをいただけると喜びます。

【演習問題】
https://atcoder.jp/contests/math-and-algorithm/tasks/math_and_algorithm_a

【問題文】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950639/a7addd86-2dc0-d96d-3c93-6e76c7a7013c.png)


【ソースコード】
```
apple = 5
 
mikan = input()
mikan_int = int(mikan)
#input()はstr型のためint型に変換した。
 
if 1 <= mikan_int <= 100:
  print(apple + mikan_int)
else:
  print("不正な値です")

```
【結果】

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950639/d33046bb-4a60-6733-3ede-8580bf485930.png)

【感想】
input()がstr型で出力されと知らず、以下のエラーが出たため
int型に変換が必要である事が分かった。
```
TypeError: unsupported operand type(s) for +: 'int' and 'str'
```
参照ページ：https://note.nkmk.me/python-input-usage/
WordPress REST APIをDockerでサクッとテストする

ニィロウで本天井ぶちかましたので初投稿です。

## 事の発端
自動作成した記事をWordPressに下書き投稿する機能を業務で開発しました。
(一から十まで自動作成するのではなく、後から人の手が入ることを前提としたシステムです。)

テストするために~~ぶっ壊してもいい~~テスト用のWordPressが欲しいんですが、WordPressって用意するの面倒臭そうじゃないですか？

～定例MTGにて～
僕「開発用のWordPress貸してもらえないかなぁー(怠惰)」
弊社のｽｩﾊﾟｴﾝｼﾞﾆｨｱ「コンテナでテストできませんか？」
僕「できます(反射)」

やっべ。

## ゴール
![image-20221021101342052.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1065089/33b934d6-449f-77a8-75a8-11af87b6965b.png)
栓抜きにも見えますね、このピクトグラム。

## コンテナ作る
### Python側

Dockerfileで作りました。
(OS確認するまでUbuntuだと思ってたのは内緒)

```bash
# cat /etc/*release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
(中略)
# cat /etc/debian_version 
11.5
# python --version
3.10.7
```

WordPressに関連する処理の内容は、

1. 画像をメディアライブラリにPOSTする
2. 記事を下書き状態でPOSTする

の2つです。

### WordPress側
#### ビルド
[こちら](https://docs.docker.jp/compose/wordpress.html)の通りにディレクトリやらyamlを作って`docker compose up -d`します。

`http://localhost:8000`にアクセスして、言語設定とアカウント設定を行ってインストール。

#### アプリケーションパスワードの設定
WordPress REST APIを利用するにはいくつか認証方法がありますが、今回は一番手っ取り早いアプリケーションパスワード認証で行きました。
ボックスに入力した文字列はKeyで、ValueとなるパスワードはWordPressが自動で作ってくれます。

![image-20221025095739215.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1065089/606d8500-9d7f-f12f-59ef-059e2ee613ed.png)

作ったパスワードにはもう二度と会えないので、恋人との思い出よりも大切にしまっておきましょう。
忘れてしまったら~~新しい恋~~再設定が必要になります。

ちなみに、Basic認証を掛けていると設定できなかったです。
2人は相容れない存在なのかな‥‥不倶戴天なのかな‥‥悲しいね‥‥。

これでコンテナの準備は完了です。
簡単ですね。これだからDockerはやめられねぇ。

## 2コンテナ間で通信できるようにする

ここのためにこの記事を書いたといっても過言じゃない。

結論を言うと`http://gateway.docker.internal:8000/wp-json/wp/v2/posts`を使います。
(もちろん画像の方は`/wp-json/wp/v2/media`です)

たったこれだけの文字列に出逢うために2日かかりました。

始めは「`http://localhost:8000/wp-json/wp/v2/posts`で行けるっしょwwwww」とか思っていたんですよこの人。
何考えてるんですかね？

ここでいうlocalhostは当然ホストマシンから見たlocalhost、つまりホストマシンなわけで。
WordPressが動いているコンテナではないです。

小見出しのように**2つのコンテナ間で通信する方法**を調べていたせいで、中々辿り着くことができませんでした。
WordPressのコンテナを**ホストOS上で動く1つのプロセス**と考えることで、ようやく正しい検索ができた次第です。

## 始末

`docker-compose down --volumes`しましょう。

`--volumes`でデータベースも消去します。
次回起動時に投稿内容などを確認したい場合は`--volumes`を外すだけ。

## おわりに

理解が浅いと調べ方すら分からないものですね。
色々な情報がネット上に存在する時代だからこそ、ソレを扱う人間が勉強する意義は増しているんだなあ

ラップトップ抱えた原始人にならないよう、これからも精進していきとうございます。

## 参考

非常に助かりました。有難うございます。

[Dockerのコンテナの中からホストOS上のプロセスと通信する方法](https://qiita.com/ijufumi/items/badde64d530e6bade382#%E3%81%9D%E3%81%AE6gatewaydockerinternal-%E3%82%92%E4%BD%BF%E3%81%8620220213%E8%BF%BD%E8%A8%98)
pyenv install --listでPython3.10以降が出てこない

# 起きた症状
pyenvを使ってPython3.10以降を利用したくなったので、pyenv install --list を実行したが、3.10-devまでしか出てこない。

brew pyenv uninstall
brew install pyenv　

をやってもダメだった

# 結論
brew以外で別に古いpyenvが存在しており、それが有効だったためbrew経由でインストールしても、そのpyenvは機能せずだった。


# 環境
- M1 MacbookPro
- OS:13.0（22A380）

# やったこと
- 古いpyenvのuninstall
    - 参考：https://qiita.com/yasudadesu/items/1177aa93229e7c4b7a45
- brew側のpyenvも念のためuninstall
- 再度brew経由でinstall
- PATHを通す
    - 参考：https://zenn.dev/unsoluble_sugar/articles/283ebf698c307c
- 必要な前提環境の再インストール
    - 参考：https://github.com/pyenv/pyenv/wiki#suggested-build-environment
    - 参考：https://zenn.dev/moru3_48/articles/94d01b0ed2a91e
    - やってみたところopensslも古い方が入っていたので、古い方をuninstall

# なんでこれが起きたのか
古いやつがなんで入っていたのかよくわからない。。。
考えられる原因として旧IntelMacから設定を引き継いで移行させてしまったので、それによって旧IntelMacでの設定とM1Macの設定が競合しちゃっていた可能性か…？
銀行システムの現場で使われる用語集

銀行向けの開発案件に参画していたときに見聞きした用語のメモです。
これから銀行システムに携わる方のお役に立てればと思います。

# システム編
|用語|解説|
|:-|:-|
|勘定系|銀行における基幹システム。入出金や決済などの処理を行う。|
|CRM|Customer Relationship Management。顧客情報を管理するシステム。|
|統合ATM|金融機関が保有するATMを相互に接続するネットワークシステム。|
|全銀システム|国内の金融機関同士の資金決済を行うネットワークシステム。|
|日銀ネット|日本銀行と取引金融機関との間の資金決済を行うネットワークシステム。|
|CAFIS（キャフィス）|Credit And Finance Information Switching system。<br>クレジットカードを中心としたキャッシュレス決済を行うシステム。|
|SWIFT（スウィフト）|Society for Worldwide Interbank Financial Telecommunication。<br>国際銀行間の送金・決済を行うネットワークシステム。|
|ANSER（アンサー）|Automatic answer Network System for Electronic Request。<br>PCなどで銀行取引を行うことができる共同利用型のネットワークシステム。|
|コアタイム|平日日中時間帯に稼働する銀行間決済システム。|
|モアタイム|平日夜間や土日祝日に稼働する銀行間決済システム。|

# 法令・制度編
|用語|解説|
|:-|:-|
|休眠預金|最終取引日が2009年以降であり、10年以上取引がない預金。預金保険機構が管理する。|
|睡眠預金|休眠預金に該当せず、長期間利用されていない預金。金融機関が引き続き管理する。|
|マル優|障害者等の少額預金の非課税制度。元本350万円までに対する利子が非課税。|
|マル特|障害者等の少額公債の非課税制度。元本350万円までに対する利子が非課税。|
|FATCA（ファトカ）|外国口座税務コンプライアンス法。顧客が米国納税義務者であるかの確認等を金融機関に求めている。|
|CRS|共通報告基準。外国の金融機関に保有する口座を利用した脱税・租税回避を防止するための国際基準。|
|実特法（じっとくほう）|「租税条約等の実施に伴う所得税法、法人税法及び地方税法の特例等に関する法律」。当法の規定により、口座開設時に居住地国等を記入した届出書の提出が必要となっている。|
|犯収法（はんしゅうほう）|犯罪による収益の移転防止に関する法律。本人確認が必要な取引や確認事項が定められている。|

# 預金種類編
|用語|解説|
|:-|:-|
|貯蓄預金|銀行が定めた金額以上の残高があると、普通預金よりも金利が高くなる預金。|
|当座預金|手形や小切手の決済に使われる預金。|
|通知預金|引出しの2日前に銀行への通知が必要な預金。普通預金より金利が高いため、まとまった資金の運用に有利。|
|定期預金|預け入れ期間をあらかじめ指定して利用する預金。普通預金より金利が高い。|
|積立定期預金|毎月決まった日に積立を行う定期預金。|
|納税準備預金|納税に充てることを目的とした預金。普通預金より金利が高く、利息は非課税。|
|別段預金|金融機関が一時的に預かっている資金を保管するための預金。|
|外貨預金|日本円を外国の通貨に換えて預ける預金。外貨定期預金や外貨普通預金がある。|
|総合口座|普通預金と定期預金をまとめた口座。普通預金の残高が不足した場合に、自動借り入れを利用できる。|

# その他
|用語|解説|
|:-|:-|
|EyeQue（EQ）|番号カードを発券するシステム・機械のこと。|
|ATM|Automatic Teller Machine。現金自動預払機。現金の入出金や振込などを処理する機械。|
|STM|Store Teller Machine。税公金など払込票の取り扱いが可能なATM。|
|UBT|Universal Banking Terminal。営業店窓口やバックオフィスで使う端末。|
|SBT|Super Banking Terminal。営業店窓口やバックオフィスで使う端末。|
|OCR|Optical Character Reader。手書きの文字や印刷された文字を、テキストデータに変換する機能。|
|eKYC|electronic Know Your Customer。オンライン上で本人確認を行う仕組み。|
|元帳（もとちょう）|現金勘定元帳。現金取引を管理・記録しているシステム上の台帳のこと。|
|店科口（てんかこう）|「店番号」「科目」「口座番号」（口座を特定する3つのキー項目）のこと。|
|CIF（シフ）|Customer Information File。顧客情報（氏名、住所、生年月日など）のこと。|
|名寄せ|同一顧客に紐づけられる複数のデータを単一のデータに統合すること。|
|センターカット|振込などの大量の処理を、業務時間外に一括で実行すること。|
|役席|銀行での管理職のこと。|
|テラー|銀行の窓口で接客を行う担当者のこと。|
|再鑑|ある人が行った作業を、別の人が確認すること。ダブルチェック。|
|単鑑|ある人が行った作業を、作業者自身が確認すること。シングルチェック。|
|ハイ|ハイカウンター。顧客は立ったままで、現金の入出金や振込などの業務を行う。|
|ロー|ローカウンター。顧客を椅子に座らせ、口座開設や運用相談などの業務を行う。|
|BO|バックオフィス。後方。書類のチェックや端末への入力などの事務作業を行う。|
|MC（MS）|magnetic stripe card。磁気ストライプカード。|
|IC|integrated circuit card。ICチップを搭載したカード。磁気ストライプカードよりもセキュリティ性が高い。|
|TB|telephone banking。電話で残高照会・振込などの取引を行うことができるサービス。|
|FB|firm banking。企業のPCから振込などの取引を行うことができるサービス。|
|IB|internet banking。個人のPCやスマホから銀行取引を行うことができるサービス。|
python configparser 

## INIファイル読み込み

```IPInfo.ini
[Server1]
IP=192.168.0.123|192.168.0.456
[Server2]
IP=192.168.0.78|192.168.0.90
```

```py
import configparser

# 設定ファイルのパス
CONF_FILEPATH = 'IPInfo.ini'
config = configparser.ConfigParser()
config.read(CONF_FILEPATH, 'UTF-8')

# 書き方1
config_svr1 = config['Server1']
svr1_IP = config_svr1['IP']

'''
# 書き方2
svr1_IP = config['Server1']['IP'] 
'''

print("svr1_IP: " + svr1_IP) 

```
参考文献

http://trelab.info/python/python-configparser%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E8%A8%AD%E5%AE%9A%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%82%80/


## for文でセクション周回
sectionメソッドでセクションを取得できる。
```py
for section in config.sections():
  print("セクション: " + section )
  print("IP: " + config[section]['IP'] ) 
```
リモート先で立ち上げたdockerへ直接ssh接続するときのconfigの書き方

EC2上のdockerコンテナを立ち上げたときに、dockerコンテナへsshしたいことがありました。
その時、ssh configにどのような記載をすればいいのだろう・・・？となったので、
書き方を共有します。
EC2へssh接続するときの参考にもなると思います。

操作端末はwindows、sshに使うクライアントはgit for windowsのものを使用します。
```
Host EC2
    HostName {EC2_ipadress}
    User ubuntu
    IdentityFile C:\Users\*****\.ssh\EC2_ssh_key.pem
    CheckHostIP no
    ControlMaster auto
    ControlPersist  600
    IdentitiesOnly yes
    ForwardAgent yes
    RemoteForward 22 127.0.0.1:22
    ServerAliveInterval 60
    ServerAliveCountMax 3
Host EC2_docker
    HostName 127.0.0.1
    User root
    Port {docker_port}
    IdentityFile C:\Users\****\.ssh\docker.pem
    ProxyCommand C:\Program Files\Git\usr\bin\ssh.exe -W %h:%p EC2
```
paiza.ioでelixir その20

# 概要
paiza.ioでelixirやってみた。
defprotocol使ってみた。

# 参考にしたページ

https://qiita.com/gr8distance/items/04a0c43fff4c1619cb8c

# サンプルコード

```

Etna.sum(["hello", "world", "!!"])
|> IO.puts
Etna.sum([%{age: 20}, %{age: 30}, %{age: 40}], fn m -> 
    m.age 
end)
|> IO.puts
Etna.include?([1, 2, 3], 2)
|> IO.puts
Etna.include?([1, 2, 3], 7)
|> IO.puts
Etna.compact([1, nil, nil, 5, 6])
|> IO.inspect

```

# 実行結果

```
helloworld!!
90
true
false
[1, 5, 6]


```

# 成果物

https://paiza.io/projects/RZALIRsVIEsSD9ZaiAQ7_g

以上。
Firebase Remote configでアプリのバージョン指定を使う

# はじめに
Firebase上で設定値を変更できるFirebase Remote configですが、一律の設定値を設定するだけでなく、アプリの条件によって該当するものだけを設定することも可能です。
設定できる条件は以下に記載されています。

https://firebase.google.com/docs/remote-config/parameters?hl=ja#condition_rule_types

そこで、アプリのバージョンによって設定値が変わるものを設けようと思ったのですが、グレーアウトされていてどうにも設定ができなかったので、設定方法について説明します。
![スクリーンショット 2022-10-28 9.58.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687960/8a120609-2ac6-23ff-e233-5e4063383771.png)

# 設定方法
まず`アプリ`の項目で、アプリを選びます。
![スクリーンショット 2022-10-28 10.06.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687960/a5ad8433-2b31-60ed-042b-e7d0be89756d.png)

アプリを選んだ後は、バージョンのグレーアウトが解けているので、自由にバージョンを指定することができます。
![スクリーンショット 2022-10-28 10.04.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687960/3ea1fff5-7f69-cc17-15d6-1e6796ec0f87.png)

# 最後に
設定方法に関してはわかっていれば簡単ですね。
よくみると、バージョンの欄に「バージョン別にターゲットとするアプリを選択してください」という説明があります。