OmniAICreator/Qiita-1.07M huggingface dataset:
【Gradle】Kotlin DSLで型安全なアクセサーを定義する

# 型安全なアクセサーとは？

### `build.gradle`を[Kotlin DSL](https://docs.gradle.org/current/userguide/kotlin_dsl.html)で記述するとき

* プラグインやビルドスクリプト(buildSrc)内での定義を、**型チェック&IDEA補完付き**で呼べる
* 依存関係の`implementation`や`api`もその一つ
* build時にgradle内部で**自動生成**される

```build.gradle.kts
plugins {
    id("myplugin")
}

// myExtensionのとこ
myExtension {

    propHoge.set("hoge")
    propFuga.set("fuga")

}

dependencies {

    // CustomConfigのとこ
    customConfig("org.example:foo")

}

tasks {
    // mytaskのとこ
    mytask {                                  
        inputHoge.set("fuga")
    }
}
```

# なぜやりたい？

### 型安全アクセサーなしだと...

```build.gradle.kts
plugins {
    id("myplugin")
}

// 記述が増える...
configure<MyExtension> {
    propHoge.set("hoge")
    propFuga.set("fuga")
}

dependencies {

    // 文字列なの...?
    "customConfig"("org.example:foo")

}

tasks {
    // 記述が増える...
    tasks {
        named<MyTest>("myTask") {
            inputHoge.set("fuga")
        }
    }
}
```

### Kotlin DSLの意味がない

* `customConfig`が文字列になってしまうのは、保管が効かなかったり型安全でない
* タスク設定などの型宣言が必要になって記述量が増える

**「せっかくのKotlin DSL！もっとシンプルにしたい！」**

# やり方

### 手順1.buildSrcなどでプラグインを用意

今回は`buildSrc/src/main/kotlin/myplugin.gradle.kts`にビルドスクリプトを追加し、それを読み込みます。

```myplugin.gradle.kts

// myExtension {...}の部分
abstract class MyExtension {

    abstract val propHoge: Property<String>
    abstract val propFuga: Property<String>

}

val myExtension: MyExtension = extensions.create("myExtension", MyExtension::class.java)

// customConfig("org.example:foo")の部分
val customConfig: Configuration = configurations.create("customConfig")

// tasks { myTask {...} } のとこ
abstract class MyTask : DefaultTask() {

    @get:Input
    abstract val input: Property<String>

    @TaskAction
    fun run() {

        println("Hello World!")

    }

}

tasks.register("myTask", MyTask::class)
```

### 手順2.【重要】プロジェクトでプラグインをロード

プロジェクトのビルドスクリプト`build.gradle.kts`にプラグインを追加します。

**「`plugins {...}`内じゃないと型安全アクセサーは動きません！！」**

* OK：`plugins {...}`
* NG：`apply`

※プラグイン自体は動きます

```build.gradle.kts
// OK
plugins {

    // ファイル名がmyplugin.gradle.ktsなら
    // gradle.ktsを抜いた、mypluginの部分
    id("myplugin")

}

// NG
apply(plugin = "myplugin")
```

# 最後に

**「手順2」はよく見ないと引っかかります。**

みなさんも気を付けてください。

また、外部プラグインを追加する際も`apply`ではなく`plugins {...}`でないとうまく型安全アクセサーは動きません。ただ`Kotlin Gradle`プラグインは`apply`でもいいらしい...。なぜでしょうか？

# 参考

### Gradle Kotlin DSL
https://docs.gradle.org/current/userguide/kotlin_dsl.html#type-safe-accessors

### Gradleプラグイン
https://docs.gradle.org/current/userguide/custom_plugins.html

### StackOverFlow
https://stackoverflow.com/questions/73396834/custom-configuration-dependency-declaration

# 宣伝

### X（旧Twitter）

技術に関する投稿をしています。

https://x.com/Gora65535
「sympyのEq」を調べた。

# DOC
sympy.solvers.solvers.solve(f, *symbols, **flags)
Algebraically solves equations and systems of equations.
https://docs.sympy.org/latest/modules/solvers/solvers.html#sympy.solvers.solvers.solve


# Eqにsubs
```python
from sympy import *
var('m,n,a,b',real=True)
eq1=Eq(m,n)                     ;print("#",eq1)
eq1=Eq(m,n).subs({m:2,n:4})     ;print("#",eq1)
eq1=Eq(m+a,n+b).subs({m:2,n:4}) ;print("#",eq1)
# Eq(m, n)
# False
# Eq(a + 2, b + 4)
```

# Eqに*2
できませんでした。
```python
from sympy import *
var('m,n,a,b',real=True)
eq1=Eq(m,n)                     ;print("#",eq1)
eq1=Eq(m,n)*2                   ;print("#",eq1)
# Eq(m, n)
# TypeError: unsupported operand type(s) for *: 'Equality' and 'int'
```

？？？ 他にいい方法がありますか？？？ 
？？？ ユーザー定義関数がありますか　汎用性があると助かります。？？？
```python
from sympy import *
var('m,n,a,b',real=True)
eq1=Eq(m,n)                     ;print("#",eq1)
eq1=Eq(eq1.lhs*2,eq1.rhs*2)     ;print("#",eq1)
# Eq(m, n)
# Eq(2*m, 2*n)
```

# =0
(参考) 以下のコメント欄

https://qiita.com/mrrclb48z/items/1537f9fcf671e0948dcc#:~:text=06%2015%3A51-,more_horiz,-%E3%82%84%E3%82%8A%E6%96%B9%E3%81%AF%E8%89%B2%E3%80%85

```python
from sympy import *
var('a,b,x',real=True)
print("#",solve( Eq(a*x+b,0),x ) )
print("#",solve(    a*x+b   ,x ) )
print("#",solve(    a*x+b      ) )
# [-b/a]
# [-b/a]
# [{a: -b/x}]
```
自作キーボードを設計しているはなし - 1 - コンセプトと試作、遊び

自作キーボードを設計しましょう。

自作キーボードのキットを組み立てた次のステップはそう、自作キーボードの設計ですね。
このキットのキーボードお気に入りだけど、ここをこうしたいとか、あれをそうしたいとか、色々出てくるのが人間の性です。

なので、つくりましょう。
設計しましょう。

:::note info
この記事は、筆者が自作キーボードを設計しているはなしについて、ダラダラと書いているだけの記事です。誰かの役に立つことがほぼないような、散文詩みたいなことしか書いていないので、役立つ記事が読みたいヒトは次回ご期待ください。
:::

# まずはコンセプトから

設計するには、コンセプトが必要です。
アーキテクチャとか設計思想とかと言い換えても、まあ意味は通じます。

どういうのをつくりたいかなあと自分に問いかけます。

私の場合は、

- キー数は多いほうがいいな
- レイヤ切り替えとかでキーの同時押しをしなくても、片手でキー入力をしたい
- テンキーほしい
- プリントスクリーンキーほしい
- アローキーほしい

といったところでした。

それぞれの要望の背景としては、オンラインゲームをする上で、右手はマウス、左手をキーボードとするため、ほぼすべてのキーが左手片手で簡単に押せるほうが望ましい、です。
後、ゲームで数値を入力することがあるのでテンキーはあったほうが打ちやすい、コーディングするからアローキーで移動したい、HomeとEndも使う、とも思いました。

ちまたの流行りは省キーキーボードだと思うので、そこから全力で逆行する道を選ぶことになりました。

じゃあ、普通の市販の100%キーボードを使っていろよという言葉が聞こえてきますが、**分割** にはしたいというわがままがあります。
じゃあ、テンキーパッドと2分割キーボード使っていろよという言葉も聞こえてきました。もっともです。

もっともですが、それだと自作キーボードを設計しなくてもよくなってしまうのが大問題です。
私は自作キーボードを設計したいのです。

なので、内なる声は無視して、コンセプトに「分割キーボードにする」を追加して設計にとりかかりました。

# 試作する

といっても、電気回路わからん、自作キーボードも素人には、なんのガイドもなく、設計することはできません。

そこで出てくるのがサリチル酸さん([https://twitter.com/Salicylic_acid3](https://twitter.com/Salicylic_acid3))の「自作キーボード設計ガイド Vol1 設計入門編」[https://booth.pm/ja/items/4410329](https://booth.pm/ja/items/4410329)です。

これに従えば、自作キーボードがひとつ出来上がるという、夢のような書です。

まずはこちらを見ながら、100%キーボードの右側部分（テンキーとかPrtScrとかHomeとかあるあたり）をつくってみることにしました。
この際言ってしまえば、Navpad 1.0([https://shop.yushakobo.jp/products/3685](https://shop.yushakobo.jp/products/3685))みたいなキーボードです。

というか、これで良くないか……？

という気づきは気にせず、作業を進めます。

流れはガイドに従います。
設計してみての気づきとかは、別記事にまとめる予定ですので、今は詳細を避けます。

うんうんとうなりながら、設計をし、はじめての基板rev.0.0.1を発注したけど、大ポカで動かない硬い板を手に入れ、修正をしたrev.0.0.2にて、無事動くキーボードをゲットしました。

テンキーとして動くので、文句なしです。

ただ勝負はこれからでした。

# 遊び

夢はいつのまにか、60%分割キーボードとテンキーをセットにした3分割キーボードセットへと切り替わっています。
60%キーボードとテンキーをUSBで個々につなげばいいので、後は60%キーボードをつくればいいじゃんとか思いますけど、それじゃあつまらない。
どうせなら、変なことしたい、変わったことをしたい、面白いことをしたい……ということで、使うUSBケーブルは1本の3分割キーボードを構想します。

手元にはPro Microをさせば動くテンキーの基板がありますので、まずはここから始めます。

秋月からMCP23017というI2C通信のIOエキスパンダを買います。

つまり、IOエキスパンダをProMicro代わりに積んだ基板と、普通にProMicroを積んだ基板をつなげば、動くのではないかという発想です。

そのためにはファームウェアの設計が当然必要となりますので、これからそれをがんばっていきます。
(20230906現在、IOエキスパンダを動かせていません)

なので、次の記事は、上で言った「ガイドを見て設計した上での気づき」の記事か、「IOエキスパンダをProMicroとQMKで動かせたよ」の記事になる予定です。

トラブルなければ、キー部6%([https://keeb.connpass.com/event/293046/](https://keeb.connpass.com/event/293046/))に参加する予定ですから、そこで、テンキー同士の基板をつないだキメラキーボードをおひろめできたらいいなと思っています。
が、進捗やばいです。
IOエキスパンダが動きません。

とにかく、これからも色々書いていく予定です。

Discordの自キ温泉街案内所に進捗スレッドを立てているので、興味ある方はそちらもどうぞ。
「左右分割60%と40%分のテンキーをつくる」というスレッドです。
そちらで様々な人にアドバイスもいただいているので、そういうアドバイスを取り入れた記事で、誰かの自作キーボード設計に多少でも役立つことが夢です。

以上、まずは自作キーボードを設計しているはなしの1回目でした。

次はもう少し役立つ記事を書こうと思いますので、よろしくお願いします。
【Tableau】改行を置換する方法

# はじめに
こんにちは。
今回はTableauで改行を置換する方法を2点ご紹介します。
※Ver2022.3を使用

# その① REGEXP_REPLACE関数 + 正規表現
改行コードの正規表現(\r、\n、\r\nなど)を置換する場合はREGEXP_REPLACE関数を使用します。
以下のようなテストデータをExcelで用意しました。
![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2192521/9a5bf4a5-c1cc-17f9-9203-592d26d60042.png)

こちらの改行をハイフン(-)に置き換える場合、このような計算フィールドを作成します。 

    REGEXP_REPLACE([値(置換前)],'\n','-')

作成した計算フィールドに「改行置換(正規表現)」というタイトルを付けて、Tableau上で表示してみます。
結果を見てみると、正常に置き換えできていました。
![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2192521/ff751b24-d8e7-4914-fd3f-9b517d00f80b.png)

# その② REPLACE関数 + ASCIIコード
参照先のDBによっては、**REGEXP_REPLACE関数が使用できない**ことがあります。
(私が遭遇したケースだと、IBM DB2に接続した際に使用できませんでした。使用可能なDBは[こちら](https://help.tableau.com/current/pro/desktop/ja-jp/functions_functions_additional.htm)に記載されています。)
その場合は、CHAR関数を用いて改行をASCIIコード(改行のコードは「10」)で指定し、REPLACE関数で置換します。
先ほどと同様に改行をハイフンに置き換えてみます。計算式は以下のようになります。

    REPLACE([値(置換前)],CHAR(10),'-')    


こちらの計算フィールドには「改行置換(ASCIIコード)」をいうタイトルをつけてTableauで表示してみます。
正常に改行の置換ができていますね。
![003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2192521/3590b785-289f-7362-b4c3-4603b406a9d5.png)
なお、**REPLACE関数で改行コードの正規表現は置換できない**ようなのでご注意ください。
REPLACE関数とCHAR関数の組み合わせを使用しましょう。

# おわりに
今回はTableau初心者向けの小ネタとして、改行を置換する方法をお伝えしました。
データソースによってREGEXP_REPLACE関数の使用可否が異なるので、ご自身の環境に合わせて使い分けましょう。

以上となります。
最後までご覧いただきありがとうございました。

# ご案内
株式会社ジールでは、初期費用が不要で運用・保守の手間もかからず、ノーコード・ローコードですぐに手元データを分析可能なオールインワン型データ活用プラットフォーム「ZEUSCloud」を提供しております。
ご興味がある方は是非下記のリンクをご覧ください：
https://www.zdh.co.jp/products-services/cloud-data/zeuscloud
extends(継承)その１

# クラスの継承

```java
class Parents {
    public String fieldA = "field A";
    public String methodA() {
        return "method A";
    }
}

class Child extends Parents {
    public String fieldB = "field B";
    public String methodB() {
	    return "method B";
    }
}
```
ChildクラスはParentsクラスのフィールドやメソッドを継承元の親から引き継いで自分自身で定義しているような動作を行える

```java
class Child {
    //Parentsクラスをコピーしている
    public String fieldA = "field A";
    public String methodA() {
	    return "method A";
    }

    public String fieldB = "field B";
    public String methodB() {
	    return "method B";
    }
}
```
継承を活用することで、このように共通のデータ（フィールド）や処理（メソッド）を親クラスにまとめて定義することができる

###  継承の特徴　オーバーライド
子クラスで親クラスと同一のメソッドを定義するとオーバーライド(親クラスのメソッドを子クラスで再定義)できる

```java
    // 親クラスのメソッドをオーバーライドする。
    @Override
    public String methodA() { 
        return "method A in Child";
    }
```
```
@Override
メソッドをオーバーライドさせるという使命を持たせることができる
```
利点
・メソッド名の誤記などを防止できる
・オーバーライドしたつもりができていなかった、といったうっかりミスを事前に防ぐことができ予期せぬバグの防止になります。


### その１の結論
・継承とは親クラスのフィールドやメソッドを子クラスで再利用するための便利な方法


参考書籍
すっきりわかるJava入門

メソッドをオーバーライドする時にOverrideアノテーションをつけるべき理由
https://qiita.com/NagaokaKenichi/items/9ee033e218f08aa605a4


## is-a関係
継承関係（「である」の関係）を表す言葉です。たとえば、
「動物は生物である」、「哺乳類は動物である」といった表現に使用されます。

たとえばですが、「A is-a B」は「AはB（の一種）である」ことを示します。
is-a関係は、クラス間の関係（継承関係）で上位と発生し、上位となる抽象的なクラスをスーパークラスといい、下位の具体的なクラスをサブクラスといいます。
「スチュワートの定理(英: Stewart's theorem）」を調べた。sympyで。

**＞Mが辺の中点のとき、この式は中線定理の式に一致する。**　
　勉強中です。証明は,垂線の補助線を引くらしい。後日sympyで公開予定。

# wikipediaで

https://ja.wikipedia.org/wiki/スチュワートの定理

https://www.deepl.com/ja/translator#ja/en/語呂合わせ
https://www.deepl.com/ja/translator#ja/en/他になかったですかね？ (以下より)

https://en.wikipedia.org/wiki/Stewart%27s_theorem

# mathworldで

https://mathworld.wolfram.com/StewartsTheorem.html

# sympyで
[wikipediaの「Stewart's theorem#Proof」より](https://en.wikipedia.org/wiki/Stewart%27s_theorem#Proof)
＊m＊nで、cos(θ)の消去です。
```python
from sympy import *
var('θ,a,b,c,d',real=True,positive=True)
var('m,n'      ,real=True,nonnegative=True)
eq_cmd=Eq(c**2,m**2+d**2-2*m*d*cos(θ)   )
eq_bnd=Eq(b**2,n**2+d**2-2*n*d*cos(pi-θ))
# 
eq    =Eq(eq_bnd.lhs*m+eq_cmd.lhs*n,factor(eq_bnd.rhs*m+eq_cmd.rhs*n) )
print("#",eq)
print("#",eq.subs({m+n:a}))
# Eq(b**2*m + c**2*n, (d**2 + m*n)*(m + n))
# Eq(b**2*m + c**2*n, a*(d**2 + m*n))
```

上と同じです。代入して、cos(θ)の消去です。
```python
from sympy import *
var('θ,a,b,c,d',real=True,positive=True)
var('m,n'      ,real=True,nonnegative=True)
eq_cmd=Eq(c**2,m**2+d**2-2*m*d*cos(θ)   )
eq_bnd=Eq(b**2,n**2+d**2-2*n*d*cos(pi-θ))
# 
eq    =eq_bnd.subs({θ:solve(eq_cmd,θ)[0]})
eq    =Eq(eq.lhs*m+n*c**2,(eq.rhs*m+n*c**2).factor())
print("#",eq)
eq    =eq.subs({m+n:a})
print("#",eq)
# Eq(b**2*m + c**2*n, (d**2 + m*n)*(m + n))
# Eq(b**2*m + c**2*n, a*(d**2 + m*n))
```

# 過去問"スチュワートの定理"でサイト内検索
「大学入試数学問題集成」様 サイト内

https://cse.google.com/cse?cx=a8908fbc24340ebc5&q=%22%E3%82%B9%E3%83%81%E3%83%A5%E3%83%AF%E3%83%BC%E3%83%88%E3%81%AE%E5%AE%9A%E7%90%86%22&oq=%22%E3%82%B9%E3%83%81%E3%83%A5%E3%83%AF%E3%83%BC%E3%83%88%E3%81%AE%E5%AE%9A%E7%90%86%22&gs_l=partner-web.12..0i4i37i512j0i512l3.2437.2437.0.8409.1.1.0.0.0.0.201.201.2-1.1.0.csems%2Cnrl%3D10...0....1.34.partner-web..0.1.201.qTFutxIhECE

＞一致する結果はありません

https://www.google.com/search?q=site%3A%2F%2Fkamelink.com++%22%E3%82%B9%E3%83%81%E3%83%A5%E3%83%AF%E3%83%BC%E3%83%88%E3%81%AE%E5%AE%9A%E7%90%86%22&sca_esv=562321783&rlz=1CAUHAM_enJP1038JP1038&sxsrf=AB5stBjSI3rOGa421zet1vBwjrbRiCWy1w%3A1693737706640&ei=6mL0ZJbUJrXi2roPn8-g4AY&ved=0ahUKEwiW8eLSoI6BAxU1sVYBHZ8nCGwQ4dUDCA8&uact=5&oq=site%3A%2F%2Fkamelink.com++%22%E3%82%B9%E3%83%81%E3%83%A5%E3%83%AF%E3%83%BC%E3%83%88%E3%81%AE%E5%AE%9A%E7%90%86%22&gs_lp=Egxnd3Mtd2l6LXNlcnAiMnNpdGU6Ly9rYW1lbGluay5jb20gICLjgrnjg4Hjg6Xjg6_jg7zjg4jjga7lrprnkIYiMgQQIxgnSKgyUKMXWNAscAF4AJABAJgBhQGgAeMCqgEDMC4zuAEDyAEA-AEBwgIHECMYsAMYJ-IDBBgBIEGIBgGQBgE&sclient=gws-wiz-serp

　＞21年 兵庫医大 医 3
　＞数学I
（＞「大学入試数学問題集成」様 未登録）


https://www.google.com/search?q=site%3A%2F%2Fmathmathmass.exblog.jp+%22%E3%82%B9%E3%83%81%E3%83%A5%E3%83%AF%E3%83%BC%E3%83%88%E3%81%AE%E5%AE%9A%E7%90%86%22&rlz=1CAUHAM_enJP1038JP1038&oq=site%3A%2F%2Fmathmathmass.exblog.jp+%22%E3%82%B9%E3%83%81%E3%83%A5%E3%83%AF%E3%83%BC%E3%83%88%E3%81%AE%E5%AE%9A%E7%90%86%22&aqs=chrome..69i57j69i58.15341j0j4&sourceid=chrome&ie=UTF-8

＞site://mathmathmass.exblog.jp "スチュワートの定理"との一致はありません。
LeetCodeのSimplify Path解いてみた

# 始めに
LeetCodeで解いた問題をアウトプットしてさらに理解を深めていく目的で投稿してます。
解説が間違っていたり、さらに良い解法などあればバシバシご指摘お願いします

それでは行ってみよう


## 問題
https://leetcode.com/problems/simplify-path/description/

タイトルにもあるが今回は**Simplify Path**という問題を解いていく
Unix系の絶対パスを簡略化するアルゴリズムを組む。
難易度はmediumなのである程度の考察力が必要になる。
とは言えmediumの中でもそれほど難易度は高くない気もするので人によってはすんなり解けるかも？
ちなみに私は回答に40分近くかかり、実際のコーディング面接等ではかなり厳しいように感じたのでまだまだレベル上げが必要。


## 問題の考察
まずこの問題を解く上で必要な考察としてスタックを使って解こうとと思った人は勘が鋭い。
前に適切な括弧の判定という問題をやったので、これって前にやった問題に似てる？
と思い、スタックを使うという考えに至った。
正直、この手の問題をやったことない状態でいきなりスタックを使おうと思う人はかなりセンスがあると思う。少なくとも自分は無理

他に考慮すべき点は以下となる
- どんな文字をスタックに追加すればいいのか？
- どんな時にスタックから削除すれば良いのか？

ではまず、**どんな文字をスタックに追加するか？** ですが
```
/home//foo/
```
上記を例にするとhome,foo(ディレクトリ)の部分をスタックに追加してあげよう。

続いて**どんな時にスタックから削除するのか？** 
これは「..」が来た際は直前のディレクトリは省略が可能なのでpopができる。
```
/home/foo/../
↓ fooが省略
/home
```


## 解法
### 前準備
省略したディレクトリを入れるstackを用意し、split関数を使い「/」区切りでsegmentsに代入
path = "/a/b/c/../../d/"
segments = ['', 'a', 'b', 'c', '..', '..', 'd', '']
/区切りにするとsegmentsは上記のようになる。

```python
def simplifyPath(self, path: str) -> str:
    stack = []
    segments = path.split("/")
```

### segmentsをループし、適切な処理をする。
考察パートで話した**どんな時にスタックから削除すれば良いのか？**
これは以下の条件で達成できる
```python
# 既にstack内にディレクトリが含まれる かつ 「..」が含まれる場合
if stack and segment == "..":
    stack.pop()
```

次に**どんな文字をスタックに追加すればいいのか？**
segments = ['', 'a', 'b', 'c', '..', '..', 'd', '']の　場合、
a,b,c,dがstackに追加される。
要はディレクトリ部分をstackに追加していけば良い。
```python
elif segment not in [".", "", ".."]:
    stack.append(segment)
```


最後にstackを「/」で連結していけばOK
このコードの計算量はO(N)です。
以下はコード全体です
```python
def simplifyPath(self, path: str) -> str:
    # 前処理は省略
    for segment in segments:
        if stack and segment == "..":
            stack.pop()
        elif segment not in [".", "", ".."]:
            stack.append(segment)

     return "/" + "/".join(stack)
```


### これまでのまとめ
これまでの処理をまとめると以下のようになる
- 絶対パスを/区切りでstackで管理
- homeやfooなどのディレクトリはstackに追加していく
- 「..」など一階層上を指す場合、1つ上の階層を削除(stackをpopする)
- 最後はstackを/で連結すれば完了


# 感想
やっぱりEasyと比べると難易度は高い...
当面の目標はMediumが問題なく解けるレベル感まで持っていく必要がありそう。
まだまだ道のりは長い
Dockerコンテナ内のコマンド履歴を永続化してfzfで検索する

:::note alert
`docker-compose`コマンドはEOLになったCompose V1のコマンドで、非推奨となっています。当記事は現在の開発環境がCompose V2に移行できてないためCompose V1での記載になっています。ご注意ください。詳しくは下記の記事をご確認ください。
:::

https://qiita.com/zembutsu/items/d82b2ae1a511ebd6a350

# 概要

### Dockerコンテナ内のコマンド履歴永続化

開発で`docker-compose exec containername bash`でコンテナ内でコマンドを打つことが多くあり、`docker-compose down`でコンテナを削除するとコマンド履歴が消えてしまい、「前回打ったあのコマンドなんだっけ？」と再度調べることが多かったので、コマンド履歴が消えないようにしたかった。

### fzf導入

CLIで標準入力されたテキストを受け取り、キー入力されたテキストでインクリメンタルにあいまい検索できる便利ツール。
パイプでつないでいろいろな使い方ができるが今回は`history`コマンドで出力されるコマンド履歴をfzfで絞り込めるようにします。

![fzf.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655119/9e9aac89-2f1e-70a6-ca39-9e5078055d4e.gif)


https://github.com/junegunn/fzf

# 環境
Docker version 20.10.14
Bash
PHP8.1
apache

### ディレクトリ構成

```bash
├── mysql
├── php
│   └── Dockerfile
└── phpmyadmin
└── docker-compose.yml
```

# コマンド履歴を永続化するためvolumesを設定

### docker-compose.yml

phpコンテナの部分に以下追記。

```yml
services:
  php:
    volumes:
      # bashコマンド履歴を保存するための設定
      - bashhistory:/commandhistory
```

services: の下に以下のvolumesを定義。

```yml
# bashコマンド履歴を保存するための設定
volumes:
  bashhistory:
    name: bashhistory_product1 # コンテナごとにユニークになるような名前にする
```

# Dockerfileでfzfインストール、コマンド履歴を保存する設定を記述

### Dockerfile

```Dockerfile
FROM php:8.1-apache
# fzf インストール
RUN apt-get update && apt-get install -y \
    fzf

ARG USER_NAME=hoge
ARG USER_ID=1000
ARG GROUP_ID=1000

# ローカルユーザーをベースに新しくユーザー作成する
RUN groupadd -o -g ${GROUP_ID} ${USER_NAME} \
    && useradd -om -u ${USER_ID} -g ${GROUP_ID} ${USER_NAME} \
    && chown ${USER_NAME}:${USER_NAME} /var/www/html

# bashコマンド履歴を保存するための設定
RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \
    && mkdir /commandhistory \
    && touch /commandhistory/.bash_history \
    && chown -R ${USER_NAME} /commandhistory \
    && echo "$SNIPPET" >> "/home/${USER_NAME}/.bashrc"

RUN SNIPPET="select-history() {\n\
    # コマンドの実行履歴をfzfで選択し、コマンドラインへ書き込む\n\
    READLINE_LINE=\"\$(HISTTIMEFORMAT='' history | awk '{ \$1 = \"\";print}' | fzf --query \"\$READLINE_LINE\")\"\n\
    # カーソルをコマンドラインの右端に移動\n\
    READLINE_POINT=\$#READLINE_LINE\n\
    }\n\
    # シェル関数にキーボードショートカット Ctrl-R を割り当てる\n\
    bind -x '\"\\C-r\": select-history'" \
    && echo "$SNIPPET" >> "/home/${USER_NAME}/.bashrc"

WORKDIR /var/www/html
# 作成したユーザーに切り替える
USER ${USER_NAME}
```

```bash
docker-compose build --no-cache
docker-compose up -d
docker-compose exec php bash
```

再ビルドしてコンテナ上げて、コンテナ内に入り、`ctrl + R` を押すとfzfでのhistory絞り込みができるようになっている。
`docker-compose down`してコンテナを削除してもコマンド履歴が消えないようになっている。

ちなみにローカルの.bashrcに上記の`select-history()`を追記してfzfインストールすればもちろん同じようにローカルでも使えます。

## 参考にさせていただいた記事など
.bashrc 記述する`select-history()`はSoftware Dwesign2023年02月号「最強の開発環境探求の道」から引用させて頂きました。

https://gihyo.jp/magazine/SD/archive/2023/202302

https://code.visualstudio.com/remote/advancedcontainers/persist-bash-history

https://qiita.com/P-man_Brown/items/f2d137a801e4d6bcf6be
ファイルの文字コード変換コマンド

メモ

# nkfコマンド

## 参照
[ターミナルで文字コードを変換！](https://shuntanote.com/2020/04/22/convert-charcode/#:~:text=Mac%20%E3%81%A7%E6%96%87%E5%AD%97%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AB,nkf%E3%80%8D%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E4%BD%BF%E3%81%84%E3%81%BE%E3%81%99%E3%80%82)
ユニークの項目に値を自動埋める時のコツ

時々たくさんのダミーデータを作る時、またはテストデータを作る時に、ユニークの項目がある場合は、ちょっと困ると思う場合もあります。

その時は下記のコードを使ってください

項目名=String.valueof(DateTime.now()).right(7);//right,leftは桁数によって入れます、もちろんテキストではない場合は他の型に変えよう
Tableauで地理的レイヤーを使ってみた

### はじめに
Tableauに地理的レイヤーという機能があったのでどんなもんなのか使ってみました。
[TableauPublic 新規エリア開拓ダッシュボード](https://public.tableau.com/app/profile/tsubasa.suzuki/viz/_16938057653620/sheet0?publish=yes)

・　マップに重ねて、支店の位置をマークで表示したい
・　表示するだけで、操作は出来ないようにしたい
・　マークごとに表示・非表示を切り替えたい
といった用途には結構便利な気がします。

**二重軸との違い**
二重軸でも似たような事ができましたが、
・　二重軸なので重ねられるのは2つまで
・　レイヤーコントロールが使えない
理由がない限りは地理的レイヤーでいいとよいかと。

**備考**
マップ・色を重ねるという性質上、カラーパレットに透明色を追加しておくと汎用性が上がると思います。
（色分けをブール式の条件によって行う場合、該当しない部分は下の階層の色を透過したいケースなど）
[ナレッジベース 色の凡例に "透明" を追加する方法](https://kb.tableau.com/articles/HowTo/how-to-add-transparent-to-the-color-legend?lang=ja-jp)

これは二重軸でも地理的レイヤーでも使えます。


以上です！
paiza.ioでelixir その251

# 概要
paiza.ioでelixirやってみた。
MatchThree、やってみた。

# 参考にしたページ

https://github.com/nemo-855/MatchThree/tree/main


# 実行結果

```
[🟡] 🔴  🔴  🔵  🟢 
 🟡  🟢  🟢  🔴  🟡 
 🔴  🔵  🟡  🔵  🔴 
 🟡  🔵  🔵  🔴  🟡 
 🔵  🔴  🔴  🟢  🟡 
 🟢  🔴  🟢  🟢  🟢 
Input x: 
Input y: 
Input y: 
 🟡  🔴  🔴  🔵  🟢 
 🟡  🟢  🟢  🔴  🟡 
 🔴 [🔵] 🟡  🔵  🔴 
 🟡  🔵  🔵  🔴  🟡 
 🔵  🔴  🔴  🟢  🟡 
 🟢  🔴  🟢  🟢  🟢 
Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving direction: Input drop moving
```


# 成果物

https://paiza.io/projects/_V6i771esfJ7sAo_4XAr1A


以上。
Pardot 未解決

[Pardotの質問と回答をまとめに戻る](https://qiita.com/Keiji_otsubo/items/a3ccd1370697dd914723)

+ [MC Account Engagement error 'your request cannot be completed due to a security error'](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007GHKqC)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/19de6bb0-0f05-1f6d-533f-62c36139a11f.png)


+ [Session Issues with Browser session in Pardot](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007GHL0D)
+ [Help with passing the Source URL or Value to Pardot field via form handler](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007H8PI9)
+ [How do you get to the Pardot or Marketing Cloud Account Engagement App?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007H9sCf)
+ [In Pardot, the email shows the merge fields and not the actual email that is sent, how can we get the actual email to show in the response?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007MXXHW)
+ [Pardot では、メールには差し込み項目が表示され、送信される実際のメールは表示されません。実際のメールを応答に表示するにはどうすればよいでしょうか?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007MXXHW)
+ [HTML Emails Showing Blank](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007bKyGV)


+ [MC Account Engagement error 'your request cannot be completed due to a security error'](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007GHKqC)
+ [固有の QR コードを Pardot 自動応答機能と統合する方法は?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007cmIJQ)
+ [Account Engagementフォームからの登録者をCRMレポートで反映させる方法](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007akb4v)

+ [見積オブジェクトを Pardot と同期するにはどうすればよいですか?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007ifsTx)



# メールの開封追跡※社内メンバー以外の追跡をしたい

+ [【未解決】フィルターメール追跡が機能しない:内部メールの開封を実際に確実に除外するために実行できる他の手順はありますか?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007ZBWeA)

+ [メールの開封追跡※社内メンバー以外の追跡をしたい](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007bKz6l)

:::note
Marketing Clou なら、クリックされたPCのドメインを見て内部かどうかを判断できるようでです。

https://salesforce.stackexchange.com/questions/257821/conditionally-display-open-tracking-pixel-for-cc-bcc-email-addresses
:::

# Outlook 予約ページと Pardot フォーム ハンドラーの統合

+ [Outlook 予約ページと Pardot フォーム ハンドラーの統合](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007ifmyw)
CDNを深く理解してみる

## 概要
「CDN」という言葉をよく耳にするが、どのような物で、何をしてくれる物なのかの理解が欠けているような気がしている。
また、普段の開発において、利用しているのかもしれないが、知らず知らずのうちに利用していて、根本的な理解ができていないように感じる。

本記事では上記を踏まえ、CDNについて調べたことを備忘録として残す。
あくまで、個人の備忘録として読んでいただければと思う。

## 学習きっかけ
某メディア企業が出版している本を読んだ際に、「CDN」絡みの内容とともに、図解の記載もあったが、理解がいまいちできなかったため。

## CDNとは
「CDN」とは、「Contents Delivery Network」(コンテンツ デリバリー ネットワーク)の略称。
単純に訳すと、「コンテンツを配達するネットワーク」という意味になる。

例えば、WEBアプリケーションを開発して、WEBサーバにデプロイした場合、このWEBサーバも「CDN」になるってことなのだろうか...?

「コンテンツを配達するネットワーク」といっても、言葉の意味が大きすぎるので、もっと深堀する必要がありそう。

## CDNの定義
何はともあれ、「CDN」に関してのWEBサイトは数多く存在しているため、とりあえず見てみよう。
※数あるWEBサイトの中から以下のWEBサイトを取り上げた理由は特にありません。

> CDNとは、Web上で送受信されるコンテンツを効率的に配送するために構築されたネットワーク。
> また、これを利用して顧客企業のコンテンツを高速に配信するサービス（CDNサービス）。

参照元: https://e-words.jp/w/CDN.html

> CDN（Contents Delivery Network）とは、数多くのキャッシュサーバーなどで構成されたプラットフォームを用いることにより、Webサイト上のコンテンツを迅速にエンドユーザーに届けるための仕組みです。

参照元: https://www.ntt.com/bizon/glossary/e-c/cdn.html

> CDNとは「Content Delivery Network（コンテンツデリバリーネットワーク）」の略で、ウェブコンテンツを効率的かつスピーディーに配信できるように工夫されたネットワークのことです。

参照元: https://www.kagoya.jp/howto/it-glossary/web/cdn/

上記内容を踏まえて、以下のように理解した。
- 特定のサーバのことを指すのではなく、ネットワークの仕組みのことを指す
- CDNの仕組みによって、キャッシュサーバーなどを利用して、WEB上のコンテンツを効率よく配信できる

こう考えると、公開されているWEBサイトには、CDNの仕組みが必要不可欠のように思える。

では、「CDN」の仕組みはどのようになっているのだろうか。

## CDNの仕組み
CDNの仕組みを理解するうえで、インターネットの基本的な仕組みを簡単に記載する。
例えば、普段の生活において、分からないことがあり、「wikipedia」で調べるとする。
この場合の一連の流れを図に示すと以下になる。(詳細は割愛します)
![インターネットの仕組み.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3316319/458e9452-52ac-fca6-cc65-76f358fb1088.png)

しかし、wikipediaで何かを調べようとする人はたくさんいる場合、ウィキペディアサーバへの問い合わせが多くなり、ウィキペディアサーバへの負荷がかかってしまう。
負荷が大きくなると、応答速度が遅くなったり、画面が表示できないことがある。
![インターネットの仕組み_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3316319/7b0004d4-b7a9-ad04-0462-e383c0efa5ed.png)

ここで、CDNの仕組みを取り入れると、以下のようになる。
![インターネットの仕組み_DNS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3316319/76f96d79-a7b8-a639-cbb5-0a41517075ab.png)
ウィキペディアサーバへのアクセスの前に、キャッシュサーバを配置する。
このキャッシュサーバが、ウィキペディアサーバが持つウィキペディアの情報を一定期間保持しており、
ウィキペディアの情報がある場合は、その情報を渡す。
ウィキペディアの情報がない場合は、ウィキペディアサーバから情報をもらい、また一定期間保持する。

## まとめ
「CDN」とは何か、どのような仕組みなのかについて、調べた結果を備忘録的にまとめてみた。
だいぶ簡易的にな説明にはなったものの、「CDN」に関してのだいたいのことは理解できたと思う。
また、仕事でAWSのCloudfrontを使用した経験があるが、今回の調べで「CDN」サービスであるということを知った。
ちゃんとした知識がなかっただけで、知らないうちに「CDN」のサービスを利用していたんだなぁ...

だいぶざっくりな内容なため、間違いなどがあれば、コメントで教えていただけると幸いです。
SeleniumのChromeDriverバージョンエラー

# 課題
Seleniumを利用していたら次のエラーが発生するようになりました。

`selenium.common.exceptions.SessionNotCreatedException: This version of ChromeDriver only supports Chrome version 114. LATEST_RELEASE_116 doesn't exist`


# エラーの原因
Seleniumのバージョンが古いため

# 対策
1. Seleniumのバージョンをチェック<pre>pip show selenium</pre>
1. Seleniumのバージョンが4.11.2より古い場合はSeleniumをバージョンアップ<pre>pip install selenium --upgrade</pre>
1. コードを次のように修正
<pre>from selenium import webdriver
from selenium.webdriver.chrome.service import Service

service = Service()
options = webdriver.ChromeOptions()
driver = webdriver.Chrome(service=service, options=options)
</pre>

以上
Rune AudioでRadikoを聴く

Volumio3になり、妙に重くて使い勝手も悪くなったので、Rune Audio(rAudio 1)に乗り換えました。

それに伴い、今まで使っていた [volumio_jpradio](https://github.com/Trunkene/volumio_jpradio) が使えなくなったので、Rune Audio用の手順をQiitaにまとめておくことにします。

といっても、ほぼ [burro](https://burro.hatenablog.com/entry/2019/02/16/175836) さんの手順を Arch Linux・Rune Audio用に修正しただけです。

# 事前準備

システムの最新化と、Gitの追加をしておきます。
```bash
$ pacman -Syu
$ pacman -S git
```

# セットアップ
Pythonの仮想環境を準備します。
```bash
$ pacman -S python-pip
$ pacman -S python-virtualenv
$ virtualenv -p /usr/bin/python3 ~/radio
```
仮想環境radioの中にradiko中継サーバーをセットアップします。
```bash
$ source ~/radio/bin/activate
$ pip install django
$ git clone https://github.com/burrocargado/RadioRelayServer.git
$ cd RadioRelayServer/
$ python manage.py migrate
```
プレイリストの場所が標準のMPDと異なるので、場所を変更します。
```bash
$ vi settings/config.py
```
```Python:config.py
RADIKO_PLAYLIST_URL='http://127.0.0.1:9000/radiko/{}'
RADIKO_PLAYLIST_FILE='/srv/http/data/playlists/00_radiko.m3u'
```
空のプレイリストファイルを予め作成して書き込み許可を与えておきます。
```bash
$ touch /srv/http/data/playlists/00_radiko.m3u
$ chmod 666 /srv/http/data/playlists/00_radiko.m3u
```
動作チェック
```bash
$ python manage.py runserver 0.0.0.0:9000
```
プレイリストに 00_radio が表示されていれば(ライブラリの更新が必要かも)、中に入って放送局を選択。放送が聞ければOKなので、Ctrl+Cで停止しておく。

# Systemdで自動起動を設定
起動用スクリプトを作成します。
```bash
$ cd ~
$ mkdir bin
$ cd bin
$ vi radio_relay
```
```bash:radio_relay
#!/bin/bash
ENV_NAME=radio
VIRTUALENV_PATH=$HOME/$ENV_NAME
source $VIRTUALENV_PATH/bin/activate
cd $HOME/RadioRelayServer
python manage.py runserver 0.0.0.0:9000
```
実行権限を付けておきます。
```bash
$ chmod +x radio_relay
```
設定ファイルを作成します。
```bash
$ sudo vi /etc/systemd/system/radio_relay.service
```
```ini:radio_relay.service
[Unit]
Description=Radiko Relay Service
After=network.target

[Service]
ExecStart=/root/bin/radio_relay
Restart=always

[Install]
WantedBy=multi-user.target
```
設定を読み込ませます。
```bash
$ systemctl daemon-reload
```
設定を読み込ませます。
```bash
$ systemctl start radio_relay
$ systemctl status radio_relay
```
プレイリストから放送が聴ければ、自動起動を設定します。
```bash
$ systemctl enable radio_relay
```
再起動して、完了。

https://github.com/Trunkene/volumio_jpradio

https://burro.hatenablog.com/entry/2019/02/16/175836
Macの Dockのアイコンで Teams の新着を赤丸で表示する設定 

Macの Dockのアイコンで、Teams に新着があっても赤丸が表示されなくて微妙に気付きづらかったが
Teamsの設定で通知のスタイルをMacに変えたら赤丸が付くようになった
 

![image](https://github.com/YumaInaura/YumaInaura/assets/13635059/cde51f01-e944-4e8d-8a1d-df25d9d45e17)

![image](https://github.com/YumaInaura/YumaInaura/assets/13635059/6c2158ed-791d-4a09-8486-04cc85973441)


# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura
SassC::SyntaxError: Error: Incompatible units を解決する

## はじめに
rails6で開発してる時に以下のようなエラーが発生しました。

```
SassC::SyntaxError: Error: Incompatible units
```

これの解消方法です。

## 環境
`Ruby 2.7.6`
`Ruby on Rails 6.1.6.1`
`node 16.20.1`
`sassc 2.4.0`

## Incompatible units
これが発生するscssの記述は以下です。

```scss
width: min(100% - 3rem, 960px);
```

エラーの内容は互換性の単位で比較しようとしていることです。
上記のscssはrailsのフロントで記載しており、sasscでコンパイルすることで発生する課題のようです。

エラーを解消するためには以下のいずれかで書き直します。

```scss
width: #{min(100% - 3rem, 960px)};
```

```scss
width: unquote("min(100% - 3rem, 960px)");
```

コンパイラに文字列として認識させることで対応できます。
CORSとは？

この記事は備忘録とする。

blocked by CORS policy:というエラーに出くわすため、記事を書こうと思いました。

Q.CORSとは??

CORS = Cross-Origin Resource Sharing→「オリジン間リソース共有」

リソース共有・・・データなどを共有。
オリジン・・・URL
EX
URL: https://www.udemy.com:445

https://・・・スキーム、ルール。
udemy.com・・・ドメイン。
445:ポート番号。APPに対して部屋を割り振られてる感覚でOK。


別のオリジン間でもリソース共有できることが、CORSと呼ぶ。
→リソース共有すると、エラー。
基本的(デフォルト)には、**同じオリジン間でしかリソースのやり取りを許可していない**
→「同一生成元ポリシー」と言う

→つまり、デフォルトでは同じドメインでしか共有できない。

じゃあ、なぜCORSはあるの？？
それはドメインやポート番号共通、オリジンが同一の場合のみPage遷移できるルールを設けることでセキュリティ対策になるからである。

EX.
小学生がスマホをつかっている。→エロサイト閲覧→別サイト（課金サイト)へ遷移→課金迫る。
※エロサイトのオリジンと課金サイトのオリジンは異なる前提。

といった流れが生じにくくなる。デフォルト時では同一オリジンでなければ遷移されないから

しかし、開発者にとってはふべん

ではどうすれば良いか？？ーサーバ側で許可する

"Access-Control-Allow-Origin"を使って許可する。

**"Access-Control-ALlow-Origin"** : "https://www.udemy.com:445"
Unity AR を Android でとりあえず実機デバッグできるようにする

# はじめに
Unity AR のテンプレートそのままに、とりあえず実機（Android）で動くことを確認するまでの手順のまとめです。

# 環境
Windows 10 22H2（ビルド 19045.3324）
Unity 2022.3.8f1
Unity Hub 3.4.2

# 手順
## テンプレートから AR プロジェクトを作る
AR 用のテンプレートがあるので、それを選択してプロジェクトを作成します。
実機の Android バージョンにもよると思いますが、Android 11 以降の端末で動作させる場合は、「エディターバージョン」が `Unity 2020.1` 以降のものになっていることを確認してください。
`Unity 2019.4` では Gradle の設定を変更する必要が後で生じます。[^1]

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1843472/cc645fd4-3011-7a18-1acc-9e11fe60405e.png)
今回は、`Unity 2022.3.8f1` で話を進めます。

## テンプレートのシーンを開く
設定済みのシーンが `BlankAR` として `Assets/Scenes` の中に用意されています。
それを開き、確認用に Cube などを置きましょう。
（下の画像のシーンは、テスト用に Cube を追加済みです。）
![無題2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1843472/0cf06013-17a3-f1b9-a1bb-5bca370f45a7.png)

## XR Plug-in Management の設定
`Edit` → `Project Settings` で Android のタブを開き、 `Google ARCore` にチェックを入れます。
（Android で動かすために必要？）
![無題4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1843472/6f481970-048e-6d52-6c03-4a676a1c5c87.png)

## ビルドターゲットの変更
`File` → `Build Settings` で `Switch Platform` を押下。
![無題3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1843472/2be7ff69-8808-9f4c-4ae3-2a3c89e486fb.png)
すると再ロードが走るので、下記のように `Build` や `Build And Run` が使えるようになるまで待ちます。
![無題5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1843472/88208d2a-dc2b-bf73-9e60-db3e4fe904a0.png)
ここまでで、PC 側の設定は終了です。

## Android で開発者モードを有効にする
端末によって多少異なるようですが、設定画面から端末情報にアクセスし、「ビルド番号」を７回タップすると開発者モードになります。

## Android の USB デバッグを有効化する
開発者モードに変更後、設定画面に「開発者向けオプションが追加されているはずです。
その項目をタップ後に遷移した画面で、「USB デバッグ」という項目を ON にします。

## PC と Android を USB で接続する
PC と Android を USB でつなぎます。
Android が使用できる（ロック状態でない等）こと、USB が「ファイル転送モード」になっていることを確認して下さい。
（ファイル転送モードについては、Android 側の通知画面に出ると思います。）

## Unity で Build And Run
PC側に戻り、Unity で `File` → `Build Settings` で `Build And Run` を押下。
するとビルドが行われ（時間はかかると思います）、Android 側で実行されるはずです。

## Android の開発者モードを解除する
確認が終わり、Android の開発者モードを解除したい場合は、「開発者向けオプション」最上部にある「ON」という項目をタップして「OFF」にすることで解除できます。

# 参考
Unity 側環境構築
[[Unity]秒で作れるAR環境](https://qiita.com/Pancetta/items/0dfc0c5bd399f6c63a67)（2023年9月5日 最終閲覧）
[UnityでAndroid向けにbuildして実機で動作確認する方法](https://qiita.com/tak001/items/045e6a0bd86628d59cfe)（2023年9月5日 最終閲覧）

Android 11 向けビルドに関して
[Unity を使用して Android 11 向けにビルドする](https://developers.google.com/ar/develop/unity-arf/android-11-build?hl=ja)（2023年9月5日 最終閲覧）

Android 開発者モードに関して
[https://appllio.com/android-development-mode-settings](https://appllio.com/android-development-mode-settings)（2023年9月5日 最終閲覧）

[^1]:「参考」のセクションにある、[Unity を使用して Android 11 向けにビルドする](https://developers.google.com/ar/develop/unity-arf/android-11-build?hl=ja)をご参照ください。
Chromeでローカルで起動しているアプリにローカルのプロキシを通すときの方法

# TL;DR;

Windowsでは、こんな感じで指定します。

run-chrome-with-proxy.batなどのバッチファイルを作り、中身を下記のような内容にします。読み替え方を後述します。ローカルにある、ポート番号8081のプロキシサーバを使い、ローカルにあるアプリにChromeからアクセスする場合です。

````batch
"C:\Program Files\Google\Chrome\Application\chrome.exe"  --proxy-server="127.0.0.1:8081" --proxy-bypass-list="<-loopback>" 
````

# 概要

## 利用シーン

Chromeで、ローカルで動かしているプロキシサーバを経由させ、ローカルで動かしているアプリ（開発中のものなど）にアクセスするときの方法です。

Windowsで動かしているChromeでプロキシを設定するとき、標準的に提要されているUIでは、システム側の設定を変更に行きますが、このページで紹介している方法では、結果として、特定のウインドウだけ設定を変えることができて便利です。

## この記事執筆時点のバージョン

下記を利用しています。

- Chrome 116.0.5845.141 (Official Build) （64 ビット） (cohort: Stable) 
- Windows 11 Pro

# 方法

## Chromeの実行ファイルへのパスを確認する

Chromeで、以下のURLを指定します。

````
chrome://version/
````

Chromeで、以下のような画面が確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65002/02870bc1-afed-7042-1a2c-6a19112abf15.png)

「実行ファイルのパス」をコピーしておきます。

## 起動用のバッチファイルを編集する

冒頭のものと少々異なりますが、おすすめは、実験用のプロファイルフォルダも別にしておくことです。

バッチファイルはこうなります。

```
%①Chromeのバイナリへのパス%　%②proxyのオプション% %③プロファイルのオプション%
```

①は、「実行ファイルのパス」を使います。

②は、このように指定します。

````
 --proxy-server="127.0.0.1:8081" --proxy-bypass-list="<-loopback>" 
````

2つのオプションがありますが、それぞれ、

```
--proxy-server="ホスト:ポート番号"
```

の組でプロキシを指定します。

そのあとの設定、

```
--proxy-bypass-list="<-loopback>" 
```

ですが、ここで、"-"記号で、「プロキシをつかわな」「くない」を指定しています。

詳しいオプションは、[こちらのサイト](https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/proxy.md#bypass-rule_subtract-implicit-rules)の「Bypass rule: Subtract implicit rules」にあります。

さらに、実験用のプロファイルフォルダも別に指定します。

※下記の、「(権限がある、お好きなディレクトリ)」は、エクスプローラから作成しておきます。

```
--user-data-dir="C:\\(権限がある、お好きなディレクトリ)"
```

全体として、例えばWindowsのユーザアカウントがSampleUserであり、TestChromeProfileフォルダに情報を保存したいケースを考えると、以下のようになります。

アカウントの「SampleUser」や、フォルダの「TestChromeProfile」は、適宜読み替えてください。

```
""C:\Program Files\Google\Chrome\Application\chrome.exe" --proxy-server="127.0.0.1:8081" --proxy-bypass-list="<-loopback>" --user-data-dir="C:\\Users\SampleUser\TestChromeProfile"
```

## 確認

下図は、上記のバッチファイルで起動したChromeで、【設定を加えたChrome】-->【ローカルで動かしているZAP [(Zed Attack Proxy)](https://www.zaproxy.org/)】-->【ローカルで動かしている[Owasp WebGoat](https://owasp.org/www-project-webgoat/)】 に接続している様子です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65002/a5caad00-6f45-9996-3620-19288a00e7e5.png)

ZAPのウインドウで、指定したプロキシを経由していることを確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65002/f0954904-f5a3-d421-0bdc-134996c87c97.png)


# おわりに

この記事では、Choromeでローカルで起動しているアプリにローカルのプロキシを通すときの方法について紹介しました。
The "force data soql query" command has been deprecated. Use "data query" instead.

おそらく最近インストールするとCLIがsfdxからsfに変わったみたいですが、トレイルヘッドの記述は前のバージョンのままかもしれませんね。

+ [Use Visual Studio Code for Salesforce Development Challenge](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007AlNv7SAF)
+ [sfdx force:data:soql:query --query SELECT Id, Name, Active__c FROM Account WHERE Active__c = 'Yes'](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007DjmdoSAB)


:::note alert
As per the challenge I need to execute "SELECT Id, Name, Active__c FROM Account WHERE Active__c = 'Yes'" using "SFDX:Execute SOQL Query with Currently Selected Text" option but I get an error:


sfdx force:data:soql:query --query The "force data soql query" command has been deprecated. Use "data query" instead.

(node:34816) Warning: Deprecated environment variable: SFDX_JSON_TO_STDOUT. Please use SF_JSON_TO_STDOUT instead.
:::

:::note
Try this

```
sf data query --query SELECT Id, Name, Active__c FROM Account WHERE Active__c = 'Yes'
```


https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_old_new_command_mapping.ht
:::


# 古い回答

+ [Trouble with SFDX: Execute SOQL Query with Currently Selected Text](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000C3yaOSAR)
ズーム

// X軸の最小値と最大値を設定
let minXValue = 10.0 // 例: データの最小値
let maxXValue = 20.0 // 例: データの最大値
chartView.xAxis.axisMinimum = minXValue
chartView.xAxis.axisMaximum = maxXValue

// チャートの更新
chartView.notifyDataSetChanged() // または chartView.invalidate()


// X軸のズームレベルを設定
let zoomLevel = 5.0 // 例: ズームレベル
chartView.zoom(scaleX: CGFloat(zoomLevel), scaleY: 1.0, x: 0, y: 0)
Android Intent

1. Use Explicit Intent to start another Activity
From StartActivity.kt to start LocalMusicActivity.kt
```kotlin
val intent = Intent(this@StartActivity, LocalMusicActivity::class.java)
startActivity(intent)
```
* If this error happened in Logcat.
> android.content.ActivityNotFoundException: Unable to find explicit activity class {com.example.simplemusic/com.example.simplemusic.activity.LocalMusicActivity}; have you declared this activity in your AndroidManifest.xml, or does your intent not match its declared <intent-filter>?

Remember to declare the activity in AndroidManifest.xml
```xml
<activity android:name="com.example.simplemusic.activity.LocalMusicActivity" />
```
2. Pass data with Intent using Bundle directly
```kotlin
val intent =
    Intent(this@StartActivity, LocalMusicActivity::class.java)
val bundle = Bundle()
bundle.putString("action", "play")
bundle.putInt("count", 10)
intent.putExtras(bundle)
startActivity(intent)
```
In the target Activity
```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
  
    val bundle = this.intent.extras
    Log.d(
        "Intent data",
        "name: ${bundle?.getString("name")}, action: ${bundle?.getString("action")}, count: ${
            bundle?.getInt("count")
        }"
    )
// ...
```
Output
>name: null, action: play, count: 10

3. Pass data with Intent
```kotlin
val intent =
    Intent(this@StartActivity, LocalMusicActivity::class.java)
intent.putExtra("action", "play")
intent.putExtra("count", 10)
startActivity(intent)
```
The same result as the last one. It will create a bundle auto.
```java
public @NonNull Intent putExtra(String name, @Nullable String value) {
    if (mExtras == null) {
        mExtras = new Bundle();
    }
    mExtras.putString(name, value);
    return this;
}
```
【脱WordPress #1】Astro+React+CloudFlareで完全無料の技術ブログ作成した


初投稿です。
WordPress から Astro への移行が非常に良かったという話です。

[Astro で作成したブログ](https://m-lab-tech.com/)

## 技術ブログにとって WordPress は完全にオーバスペック

WordPress の利点と限界。

### WordPress 利点

- ユーザーフレンドリー
  WordPress は使いやすいインターフェイスを持っているため、技術的背景がない人でも簡単に使えます。
- 豊富なプラグイン
  WordPress は豊富なプラグインを提供しており、様々な機能を簡単に追加できます。
- テーマ
  多種多様なテーマがあり、ウェブサイトの外観を簡単に変更できます。

### 限界

- パフォーマンスの問題
  大量のプラグインや複雑なテーマを使用すると、サイトのパフォーマンスに影響が出る場合があります。
- 継続的なメンテナンス
  WordPress サイトは定期的なメンテナンスが必要であり、更新しないとセキュリティのリスクが高まります。
- ホスティングコスト
  そこそこの性能のホスティングを必要とします。

以上ことから、脱 WordPress を決意しました。

## SSG（静的サイトジェネレーター）

### SSG とは

SSG（静的サイトジェネレーター）はウェブページを事前に生成し、静的 HTML ファイルとしてサーバー上に保存します。これにより、データベースへの問い合わせなど動的な処理が不要になり、ウェブサイトのロード時間が短縮されます。

今回作成したブログの LightHouse スコアはこちらです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552182/0eb2b591-fd8b-a47e-1be2-bae172bf86fd.png)

### SSG 利点

- 高速なロード時間
  静的ファイルはデータベースからのデータの取得などの動的なプロセスが必要ないため、ロード時間が速くなります。
- 低いセキュリティリスク
  動的コンテンツがないため、SQL インジェクションや XSS 攻撃といったセキュリティリスクが低減します。
- 簡易なメンテナンス
  セキュリティ更新やパッチの適用が必要なサーバーサイドのソフトウェアが少ないため、メンテナンスが簡単です。
- マークダウンによる記述
  マークダウンで記述できるので、普段使用しているエディターを使って記事の作成が可能です。また、Git によるバージョン管理が可能となります。

### SSG の比較

- Astro
  言語：JavaScript
  特徴：
  コンポーネントベースのアーキテクチャで、React や Vue などの異なるフレームワークを組み合わせて使用できます。
  高いパフォーマンスと SEO 最適化が重視された設計。
  パーシャルハイドレーションが特徴的で、必要な部分だけを動的に読み込むことができる。

- Hugo：
  言語：Go
  特徴：
  ビルド速度が非常に速い。
  マークダウンや他のデータ形式を HTML へ変換する力強いテンプレートエンジン。
  豊富なテーマとプラグインのエコシステム。

- Jekyll：
  言語：Ruby
  特徴：
  GitHub Pages と連携が良く、GitHub 上で簡単にホスティングできます。
  マークダウンと Liquid テンプレートエンジンのサポート。

## 完全無料の実現方法

### ホスティング費用

完全無料と言うと聞こえは悪いかもしれません。また、無料ならではの制限等を疑う人もいるかもしれません。
ですが、CloudFlare Pages を利用することで無料で静的ファイルをホスティングできます。

### ドメイン費用

次に問題なってくるのは、ドメイン料金かと思います。CloudFlare Pages が自動で設定するドメインについては無料で使用できます。ですが、カスタムドメインの場合はドメイン料金が発生します。

裏技的な方法ではありますが、レンタルサーバーやドメイン業者から登録時に特典としてもらえる永久無料のドメインを利用できます。この入手したドメインを Pages のカスタムドメインとして設定することで、完全無料での運用が実現できます。

## 次回

想像以上に長くなってしまったので、「Astro を使用した効率的なブログのビルドとカスタマイズ」については次の機会に投稿します。

もし良ければ、[X の方フォローして頂けると嬉しい。](https://twitter.com/MakimaWork)
コマンドで一括置換する方法

前提: MacOS

gitで管理している場合、以下の通り。

```
git grep -l '検索文字列' | xargs sed -i '' 's/検索文字列/置換文字列/g'
```

gitで管理していない場合は、以下の通り。

```
grep -rl '検索文字列' /path/to/directory | xargs sed -i '' 's/検索文字列/置換文字列/g'
```
wslでelixir その47

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

# サンプルコード

```

defmodule Push do
	defstruct [:item]
end

defmodule Pop do
	defstruct []
	use Cizen.Request
	defresponse Item, :pop_event_id do
		defstruct [:item, :pop_event_id]
	end
end

defmodule Stack do
	use Cizen.Automaton
	defstruct [:stack]
	use Cizen.Effects
	alias Cizen.Event
	alias Cizen.Filter
	@impl true
	def spawn(id, %__MODULE__{stack: stack}) do
		perform id, %All{effects: [
			%Subscribe{event_filter: Filter.new(fn %Event{body: %Push{}} -> 
				true 
			end)},
			%Subscribe{event_filter: Filter.new(fn %Event{body: %Pop{}} -> 
				true 
			end)}
		]}
		stack
	end
	@impl true
	def yield(id, stack) do
		event = perform id, %Receive{}
		case event.body do
			%Push{item: item} ->
				[item | stack]
			%Pop{} ->
				[item | tail] = stack
				perform id, %Dispatch{
					body: %Pop.Item{item: item, pop_event_id: event.id}
				}
				tail
		end
	end
end

defmodule Main do
	def main do
		use Cizen.Effectful
		use Cizen.Effects
		handle fn id ->
			perform id, %Start{
				saga: %Stack{stack: [:a]}
			}
			item_event = perform id, %Request{
				body: %Pop{}
			}
			%Pop.Item{item: item} = item_event.body
			IO.puts(item)
			perform id, %Dispatch{
				body: %Push{item: :b}
			}
			perform id, %Dispatch{
				body: %Push{item: :c}
			}
			item_event = perform id, %Request{
				body: %Pop{}
			}
			%Pop.Item{item: item} = item_event.body
			IO.puts(item)
			item_event = perform id, %Request{
				body: %Pop{}
			}
			%Pop.Item{item: item} = item_event.body
			IO.puts(item)
		end
	end
end


```

# 実行結果

```
$ iex -S mix
Erlang/OTP 25 [erts-13.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit:ns]

Compiling 1 file (.ex)
Generated testcizen app
Interactive Elixir (1.13.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Main.main
a
c
b
:ok
iex(2)>
BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
       (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution
a

```

以上。
Aiven for PostgreSQL® 15の発表

<font color="Grey">*[Announcing Aiven for PostgreSQL® 15](https://aiven.io/blog/announcing-aiven-for-postgresql-15)の翻訳です。*</font>

2023年2月3日

# PostgreSQL® 15向けAivenを発表

AivenはPostgreSQL®バージョン15をデータインフラにもたらします。主な改善点と新バージョンの入手方法をご覧ください。


10月のリリースからわずか3ヶ月で、AivenはPostgreSQL® 15をリリースすることができました。新バージョンは、ローカルおよび分散環境でのワークロード管理をより効率的にし、より良い開発者エクスペリエンスを提供する、豊富な新機能とパフォーマンス強化を備えています。


## リリースハイライト


### ソートのパフォーマンスと圧縮率が向上


[PostgreSQL Global Development Group](https://www.postgresql.org/about/news/postgresql-15-released-2526/)によると、PostgreSQL 15の新しいアルゴリズムはメモリ内ソートとディスク上ソートの両方で25～400%の性能向上をもたらします。新しいウィンドウ関数も `SELECT DISTINCT` 問い合わせの並列実行と同様に性能を向上させます。


### 開発者向け機能


SQL 標準の `MERGE` コマンドが PostgreSQL 15 に追加され、条件付きで `INSERT`、`UPDATE`、`DELETE` を行えるようになりました。


また、正規表現で文字列を検査できるようになりました。正規表現には `regexp_count()`、`regexp_instr()`、`regexp_like()`、`regexp_substr()` があります。


集計関数がマルチレンジのデータ型に拡張された。


### その他の変更点


* PUBLICスキーマはデフォルトでは書き込み可能ではなくなりました。
* 論理レプリケーションにおいて、PostgreSQL 15はパブリッシャの行フィルタリングと列リストを提供するようになりました。
* クラスタまたは個々のデータベースのデフォルトとしてICU照合順序を設定できるようになりました。
* 一意制約とインデックスがNULL値を区別できないものとして扱えるようになりました。
* 外部キーの `ON DELETE SET` アクションが指定された列にのみ影響するようになりました。


これらやその他の新機能の詳細については、[PostgreSQLのWebページ](https://www.postgresql.org/about/news/postgresql-15-released-2526/)を参照してください。


## PostgreSQL 15を始めよう


これらの機能を利用するには、PostgreSQL 15にアップグレードしてください。すでにAiven for PostgreSQLを使用している場合は、[インプレースアップグレード](https://aiven.io/blog/postgresql-major-version-in-place-upgrades-supported-on-aiven)を実行して最新バージョンに移行できます。



Aivenと私たちのサービスに関する最新ニュースや、オープンソース全般に関するちょっとした情報を入手するには、[月刊ニュースレターを購読](https://aiven.io/newsletter)してください！Aivenに関する日々のニュースは、[LinkedIn](https://www.linkedin.com/company/aiven/)と[Twitter](https://twitter.com/aiven_io)のフィードでご覧いただけます。


サービスのアップデート情報を知りたい方は、[変更履歴](https://aiven.io/changelog)をご覧ください。
cscの作法 その444

# 概要
cscの作法、調べてみた。
練習問題、やってみた。

# 練習問題
TextBoxを配列で扱え。

# 方針
new TextBox[5]する。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/721d7aa1-f13d-8742-0541-5e1a70e3ade4.png)

# サンプルコード

```
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Data;

namespace App
{
	public partial class Form1: Form {
		TextBox[] textBoxs;
		public Form1() {
			Text = "TextBox";
			ClientSize = new Size(300, 300);
			textBoxs = new TextBox[5];
			for (int i = 0; i < this.textBoxs.Length; i++)
			{
				textBoxs[i] = new TextBox();
				textBoxs[i].Name = "TextBox" + i.ToString();
				textBoxs[i].Location = new Point(30, 10 + 30 * i);
			}
			Controls.AddRange(this.textBoxs);
			Button button1 = new Button();
			button1.Location = new Point(100, 250);
			button1.Text = "test";
			button1.Click += new EventHandler(button1_Click);
			this.Controls.Add(button1);
		}
		private void button1_Click(object sender, EventArgs e) {
			string str = "0: " + textBoxs[0].Text + " 1: " + textBoxs[1].Text + " 2: " + textBoxs[2].Text + " 3: " + textBoxs[3].Text + " 4: " + textBoxs[4].Text;
			MessageBox.Show(str);
		}
		[STAThread]
		public static void Main() {
			Application.Run(new Form1());
		}
	}
}



```

以上。
改めて検索システムの基礎をまとめてみる

# 目的
普段から検索に関する仕事に関わっていますが、検索システムについて深く知るためにインプットしたものをアウトプットとして投稿します。

# 検索システムとは
検索システムとは一般的には蓄積された情報データの中からユーザが探したい情報を効率よく探し出して、ユーザに表示させるシステムです。例としてGoogleが開発しているChromeが該当します。私達が検索したいことを検索インターフェースに入力し、すぐに検索したいページが一覧で表示されると思います。この流れは普段私達が使うWEBサービス(ECサイト、SNS)でも同じ流れです。

## ユーザが検索システムを使用する流れ

- ユーザは探したい情報を見つけるためにUIに単語を書いていきます．

普段から私達は以下の画像のように検索したい単語を入力していると思います．
![search-engine.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469304/0767378a-5705-848f-05cd-fe00137d5402.png)
上記の画像はユーザが東京のホテルを探したいときにインターフェースに「東京 ホテル」と入力します．この入力単語はクエリとして検索エンジンに問い合わせをします．すると検索エンジンは対象となるドキュメントを複数レスポンスしてユーザに結果を表示します．
ざっくりとした感じですが，ユーザが使用する検索システムの流れになります．

# 全文検索
検索システムは、情報の種類や検索の目的に応じて、さまざまな形で実装されています。本記事ではよく聞く全文検索エンジンについて紹介していきます．
全文検索とは複数のドキュメントから特定の文字列を検索する技術です．
例えば以下の画像ように検索インターフェースに対してユーザが「東京のホテルを探したい」と入力するとします．
ユーザが入力した文字列はクエリと言います．
![text-analyzer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469304/ec34b097-45db-3735-b290-c00ab40ccb63.png)
入力した文字列をテキスト解析し，分解します．分解した1つ1つの文字をタームと言います．
分解したタームを元に検索エンジンに保存されているドキュメントを探し出して，その結果をユーザにレスポンスします．
この処理の流れをクエリ処理と言います．

# インデクサーとは
インデクサーとはWEB上に存在するウェブサイトなどの情報を収集し，収集したデータをインデックスとして検索エンジンに保存する役割をもつコンポーネントです．
以下の画像がインデクサーの役割の一例となります．
![indexer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469304/e32d36fa-d7c4-a199-dea7-b96a7e637028.png)

WEB上に存在するWEBサイトをクローラーが収集してきます．その収集したデータをindexerはキーワードやフレーズなどを解析して検索エンジンにindexとして保存する役割を持ちます．

# Elasticsearch
Elasticsearchとは高速検索を可能とする，分散型の検索エンジンです．Elastic社が中心になって開発を行っています．Elasticsearchの特徴としては以下があります．
- スケーラブル
- 分散型であるため，大量のデータを並行して処理が可能
- 高可用性

ElasticsearchはECサイトを始めとした多くのプラットフォームで採用されています．多くのユーザを抱えていて大量の検索クエリを処理する必要がある場合で，非常に高いパフォーマンスを発揮します．

### Elasticsearchの使用例
- メルカリ

https://engineering.mercari.com/blog/entry/20220311-97aec2a2f8/

- モノタロウ

https://tech-blog.monotaro.com/entry/2022/12/23/093000

- dely

https://tech.dely.jp/entry/tetsugaku_of_elasticsearch

# まとめ
本記事では検索システムの基礎についてまとめてみました．まだまだ自分の知らないことが多いので改めて勉強をしていけたらと思いました．

# 参考文献
https://www.lambdanote.com/collections/ir-system