OmniAICreator/Qiita-1.07M huggingface dataset:
venvで手軽にPythonの仮想環境を構築しよう

# はじめに

Pythonの開発を始める際、プロジェクトごとに独立した環境を作ることはとても重要です。
環境を分けずに複数のPythonプロジェクトを同じ環境で開発する場合、パッケージのバージョン衝突が発生する可能性があり、**予期せぬエラーや互換性の問題**が生じる可能性があります。
本記事では、そんな問題を解消してくれるvenvの概要と基本的な使い方について紹介します。

# venvとは
venvは手軽に仮想環境を作成・管理することができるツールです。
また、venvはPythonバージョン3.3以降の標準ライブラリとして提供されており、**バージョン3.3以降のPythonをインストール済みの方はvenvを別途インストールすることなく利用可能**です。

https://docs.python.org/ja/3/library/venv.html

# 使い方

## 仮想環境作成
プロジェクト直下に移動後、以下のコマンドを実行するとプロジェクト内に指定した仮想環境名のフォルダが作成されます。
venvと命名されることがよくあるので、迷ったら`python -m venv venv`で大丈夫です。
```console
python -m venv [仮想環境名]
```

## 仮想環境のアクティベート
次に、以下のコマンドを使って仮想環境をアクティベートします。
Linux, MacとWindowsでディレクトリ構成とコマンドが若干違うため分けて紹介します。

### Linux, Macの場合
```console
. [仮想環境名]/bin/activate
```

### Windowsの場合
```console
.\[仮想環境名]\Scripts\activate
```
※ `.`は作成した仮想環境へのパスを表しており、今回はプロジェクト直下にvenv環境があることを想定しています。
コマンドを実行している場所にvenv環境がない場合は`.`の部分のパスを適宜書き換えてください。


コマンド実行後、パスの前に[仮想環境名]が表示されれば環境がアクティブになっており、この状態で必要なパッケージをpip installしていくと自動的に仮想環境にインストールされます。

↓仮想環境がアクティブになっている
![スクリーンショット 2023-06-29 23.01.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3314085/293e57d5-04ca-759a-8f50-55bc998a3981.png)

:::note info
venv(仮想環境)フォルダはインストールしたパッケージが含まれているため、プロジェクトをgitでバージョン管理をする場合は.gitignoreに追記するのを推奨します。
:::

複数人で開発していると、使用しているパッケージの共有が必要になることがあります。
そんな際は以下のコマンドで仮想環境にインストールされているパッケージをファイルに書き出して共有できます。

インストール済みパッケージとバージョン書き出し
```console
pip freeze > requirements.txt
```

書き出したrequirements.txtを一括インストールする場合
```console
pip install -r requirements.txt
```

:::note info
**開発用と本番用でインストールするパッケージを分けたい**場合が出てくる場合があります。
その際は`requirements-dev.txt`のような別途ファイルを作成後、以下のように`-r requirements.txt`を入れ、`pip install -r requirements-dev.txt`を実行するとrequirements.txtも同時に一括インストールしてくれます。
```text:requirements-dev.txt
-r requirements.txt
black==23.3.0
flake8==6.0.0
```
:::

## 仮想環境のディアクティベート
仮想環境の使用を終了したい場合は以下のコマンドで仮想環境を抜けることができます。
```console
deactivate
```

# 補足: VSCodeで作成した仮想環境を使用する方法
作成した仮想環境をVSCodeのPython実行環境で使用する場合、インタープリターの選択が必要になります。
すでに選択されている場合は、Pythonファイルを開くと下の画像のように、VSCodeの右下にPython[バージョン]('[仮想環境名]': venv)が表示されます。
![スクリーンショット 2023-06-29 1.36.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3314085/38a1870d-b998-6175-1587-f8f40f6217b4.png)
仮想環境が選択されていない場合、仮想環境内シェルでMacの場合`which python`, Windowsの場合`where python`を実行すると実行用PythonのPATHが表示されるため、PATHをコピー後、Macの場合`CMD+shift+P`, Windowsの場合`Ctrl+Shift+P`を押下するとVSCode上部に検索ボックスが出るため、検索に`>Python: Select Interpreter`を入力 -> インタープリターの選択 -> インタープリター パスを入力... -> 入力ボックスにコピーしたPythonパスをペーストすると仮想環境のインタープリターが設定できます。

## 最後に
仮想環境を構築するツールは他にもありますが、今回は私が一番手軽だと思ったvenvをチョイスして記事を書いてみました。
今後も便利なものを紹介していきたいと思います。
ご拝読いただきありがとうございました。
【備忘録】Aristaコマンドまとめその1 Staticrouteの設定

# 概要
Aristaのスイッチを触る研修を受けたため、備忘録として記載する。


# モードの変更

Arista、CLI / bashの基本操作
`＞`なら一般モード。
`＃`なら特権モード。`enable`で変更できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/46d2ba48-9070-1bb1-d3fa-b56aa98a4676.png)


特権モードから、`configure`もしくは`contf t`で、コンフィグ変更モードになれる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/7b5843d0-8625-9039-7b61-57487f8cae35.png)

# 各種コマンド


設定モードから、interfaceでeth1を選択すれば、eth1の設定変更をする事ができる。左側のプロンプトが変わっている事に注目
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/3df6bf5c-6cb9-352a-1b89-4b3689e0a40c.png)

`show version`で、シリアル等各種情報を確認できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/ebc58208-4488-b352-afe5-bf9e886adc05.png)


`show running-config`で、現在の設定を見る事ができる。
sectionを後から指定する事で、各セクション（BGP）などの情報を見る事ができる。
また、Linuxがベースなので、`| grep` を実行する事も可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/83333408-7b34-beb7-bb99-2d0e8df09ead.png)

また、`bash`を入力すると、centosのプロンプトに移行する事ができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/0ac4b9a0-4302-e281-f00c-e9b1de702c96.png)


スイッチにdockerを入れて、サーバのように作る事もできたりするらしいが、
今回は割愛。とにかく、上記のようにスイッチをLinux（サーバ）として使う事もできる。


# VLANについて

VirtualLAN。
論理的に、1台のスイッチに独立した複数のLANを持たせる。LANを分ける事で、通信効率を上げるのが主な目的。

- アクセスポート。一つのVLANにだけ所属するポート。（一つのポートに一つのvlan。）ポートVLAN
untagのことでもある。
- トランクポート。複数のVLANにだけ所属するポート。タグVLAN。tagの事でもある。主にスイッチ同士をつなげるために使用する。


## SVI(VLANインターフェース)

これを設定すると、ルータとVLANを紐づいた仮想インタフェースが作成される。
VLANとSVIは別々に作成する必要がある。
以下画像ではVlan10を作成→interface vlan10を作成→interface vlan 10へのIP設定を行っている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/dca1d21b-b312-11ac-af26-bbaccb700d2a.png)


ちなみに、これらを削除するには、作成したコマンドの先頭に`no`をつける。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/fdc16732-2bc8-a4b4-9eee-fac95190f42a.png)

ルーティングの情報を見るには、`show ip route`を見れば確認できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1288524/113df86f-5243-15b0-20b3-140091228889.png)
闘魂Elixir ーー 取り込みたいHex(パッケージ／ライブラリ)がponchoプロジェクトでGitリポジトリにある場合に特定のディレクトリのみを取り込みたい

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>

<b><font color="red">$\huge{闘魂とは己に打ち克つこと。}$</font></b>
<b><font color="red">$\huge{そして闘いを通じて己の魂を磨いていく}$</font></b>
<b><font color="red">$\huge{ことだと思います}$</font></b>


# はじめに

[Elixir](https://elixir-lang.org/)という素敵な関数型言語の話です。
[Elixir](https://elixir-lang.org/)のパッケージ（ライブラリ）は[Hex](https://hex.pm/)と呼ばれています。
パッケージ（ライブラリ）の取り込み方のオプションは、`mix help deps`で確認できます。

取り込みたい[Hex](https://hex.pm/)がponchoプロジェクトでGitリポジトリにある場合に特定のディレクトリ（つまりは[Hex](https://hex.pm/))のみを取り込みたいということが私にはありました。
他の人もそういうことがあるかもしれないので紹介しておきます。
そんなことをしたくなるのは、ほぼほぼ[Nerves](https://nerves-project.org/)界隈の人だろうと想像されます。
だってponchoプロジェクトなのですもの。

追記: 取り込みたい対象のHexが[Umbrella Projects](https://elixirschool.com/ja/lessons/advanced/umbrella_projects)に含まれている場合でも同じことをしたくなることがあるかもしれません。


# 取り込み例

こんな感じです。
TSL2561という光測定ができる部品の[Hex](https://hex.pm/)を取り込んでいます。

```elixir:mix.exs
  def deps do
    ...
    {:tsl2561,
       git: "https://github.com/NervesJP/sensor_hub_poncho.git",
       subdir: "tsl2561",
       targets: @all_targets},
  end
```

ポイントは`:subdir`オプションです。これでディレクトリを特定します。
`:subdir`オプションは[Elixir](https://elixir-lang.org/)のv1.13以上で使えます。
フルチェックアウトします。

v1.13未満でも使えるオプションは、`:sparse`オプションです。
こちらは[git-sparse-checkout](https://git-scm.com/docs/git-sparse-checkout)というGitのEXPERIMENTAL機能を使っているそうです。
[git-sparse-checkout](https://git-scm.com/docs/git-sparse-checkout)とは、


![スクリーンショット 2023-06-29 23.35.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131808/75abe2ac-63ed-210c-1ad7-68d24a36dd9f.png)


なのだそうです。


---

# さいごに

取り込みたい[Hex](https://hex.pm/)がGitHubにあり、しかもponchoプロジェクトであるため、特定のディレクトリ（つまりは[Hex](https://hex.pm/))のみを取り込む方法を紹介しました。
`:subdir`オプションか`:sparse`オプションを使います。

あー、最後に気づきましたが[Umbrella Projects](https://elixirschool.com/ja/lessons/advanced/umbrella_projects)でも同じことをしたくなることがあるかもしれません。

---


**闘魂**とは、  **「己に打ち克つこと。そして闘いを通じて己の魂を磨いていくことである」** との猪木さんの言葉をそのまま胸に刻み込んでいます。
知っているだけで終わらせることなく、実行する、断行する、一歩を踏み出すことを自らの行動で示していきたいとおもいます。
**アントニオ猪木さんのメッセージから元氣をもらったものとして、それを次代に語り継ぎ、自分自身が「闘魂」を体現するものでありたいとおもいます。**

---

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>
<b><font color="red">$\huge{１、２、３ ぁっダァー！}$</font></b>
DateTimeFormatter.formatで型「M/d」指定すると「01」でも「1」でも変換可能

## これは何

java.time.DateTimeFormatterのString->日付型の変換が結構柔軟で助かった話です！

型に「yyyy/M/d」と指定すれば、例えば日付が「01」でも「1」でも型変換してくれるようになります。

## 何がええんや??

「2022/1/1」と「2022/1/01」どちらも変換してくれて、「2022年1月1日」を表すようになります。

「yyyy/MM/dd」「yyyy/M/d」で分けて変換しないといけないのかなと思っていたのですが、「yyyy/M/d」だけで0埋めアリ/ナシ共に変換してくれるのが便利なところです。

[:contents]

## 公式

[https://docs.oracle.com/javase/jp/8/docs/api/java/time/format/DateTimeFormatter.html:embed:cite]

## 動作確認

以下テストで全てOKでした。


```kotlin
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.format.DateTimeParseException
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith

class DateTimeFormatterTest {

    private val formatter = DateTimeFormatter.ofPattern("yyyy/M/d")

    @Test
    fun `2022_01_01でOK`() {
        val result = LocalDate.parse("2022/01/01", formatter)
        assertEquals(LocalDate.of(2022,1,1), result)
    }

    @Test
    fun `2022_1_01でOK`() {
        val result = LocalDate.parse("2022/1/01", formatter)
        assertEquals(LocalDate.of(2022,1,1), result)
    }

    @Test
    fun `2022_01_1でOK`() {
        val result = LocalDate.parse("2022/01/1", formatter)
        assertEquals(LocalDate.of(2022,1,1), result)
    }

    @Test
    fun `2022_11_11でOK`() {
        val result = LocalDate.parse("2022/11/11", formatter)
        assertEquals(LocalDate.of(2022,11,11), result)
    }

    @Test
    fun `2022_11_011でOK`() {
        val result = LocalDate.parse("2022/11/011", formatter)
        assertEquals(LocalDate.of(2022,11,11), result)
    }

    @Test
    fun `2022_11_111(存在しない日付)での時フォーマットできない`() {
        assertThrows<DateTimeParseException> { LocalDate.parse("2022/11/111", formatter) }
    }

    @Test
    fun `202211111形式違いの時フォーマットできない`() {
        assertThrows<DateTimeParseException> { LocalDate.parse("202211111", formatter) }
    }

}
```

## より詳細な記事

[https://www.ne.jp/asahi/hishidama/home/tech/java/DateTimeFormatter.html:title]
【Kotlin】ByteBufferの単体試験で末尾の0Byte部分を無視する

## これは何？
* `java.nio.ByteBuffer`を用いてString生成する処理にて、部品化したクラスの単体テストで困ったことの解決

## 困りごと

```kotlin
    @Test
    fun hoge() {
        val byteBuffer = ByteBuffer.allocate(5) //Byte範囲割り当て
        byteBuffer.put("あ".toByteArray()) //ByteArray追加
        byteBuffer.flip()
        assertEquals("あ",String(byteBuffer.array())) //これでいけると思ったのだが...
    }
```

↓を参考に、ByteBuffer->ByteArray->Stringの順で変換すればassertできるのでは？と思って書いたところ、テスト失敗しました。

https://hacknote.jp/archives/4482/

![スクリーンショット 2022-08-11 0.18.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552268/6f30c961-1e8f-2e9c-6018-8d59c78a6473.png)


あらかじめ配置してるByteBufferのうち、ByteArrayが配置されていない(=ByteArray要素が0)の部分も含めてStringに変換されてしまっているため、Actualの方で欲しいString`あ`の後に不要な文字が変換されてしまっています。

参考までに、下記の記載でByteArrayの内容を出力できます。結果は`[-29, -127, -126, 0, 0]
`となっており、5Byteのうち末尾の2Byteが0になっています。

```kotlin
println(byteBuffer.array().contentToString())
```

## 案1 ByteArrayOutputStreamで取り扱う


```kotlin
@Test
fun hoge() {
    val stream = ByteArrayOutputStream()
    stream.write("あ".toByteArray()) //ByteArray追加
    assertEquals("あ",String(stream.toByteArray()))
}
```

## 案2 Charsets.decodeを使う

```kotlin
@Test
fun hoge() {
    val byteBuffer = ByteBuffer.allocate(5)
    byteBuffer.put("あ".toByteArray())
    byteBuffer.flip()
    assertEquals("あ",StandardCharsets.UTF_8.decode(byteBuffer).toString())
}
```

https://java.hotexamples.com/jp/examples/java.nio.charset/StandardCharsets.UTF_8/decode/java-standardcharsets.utf_8-decode-method-examples.html
[Unity]作成したシェーダが透明になる問題

個人的な備忘録のために記載

## 事象
UnityでURPに対応したシェーダを作ろうとしたとき、
下記ページの通りにやるとオブジェクトが透明になった。

[URP の基本的な Unlit シェーダー](https://docs.unity3d.com/ja/Packages/com.unity.render-pipelines.universal@14.0/manual/writing-shaders-urp-basic-unlit-structure.html "URP の基本的な Unlit シェーダー")

* 元々
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3492164/010e314f-158b-7681-a58b-8bea2806cdd3.png)

* 参考ページのシェーダからマテリアルを作成し適用した形
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3492164/201e7011-d4dd-ea2c-66cb-c60cae62b9a3.png)

## 解決方法
新規にURPのパイプラインアセットを作成して対応
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3492164/65bd7436-d46b-a915-e7eb-3dabfcfb5070.png)

## 原因
`` 3D(URP)テンプレート ``で作成したプロジェクトの
URPのレンダリング設定の``深度プライミングモード``が``自動``になっていたから

> プロジェクトタブ
> Assets / Settings / URP-HighFidelity-Renderer
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3492164/6aaf4108-a301-c6bd-da01-7aa943299aca.png)

## 詳細
詳細は調査中
【FPDI+TCPDF】PDFファイルの用紙サイズを取得する

phpで**PDFファイルの用紙サイズを取得したい**場面がありました。和文でのソースが見当たらなかったため、備忘録としてまとめます。

[【公式ドキュメント】 FPDI Manual](https://manuals.setasign.com/fpdi-manual/v2/the-fpdi-class/#index-3)
# バージョン
今回は以下の環境で動かしています。
この記事では、それぞれがインストール済みであることを前提とします。
- tecnickcom/tcpdf                 6.6.2
- setasign/fpdi                    v2.3.7
- setasign/fpdi-tcpdf              v2.3.0
- PHP 8.0.29

# サイズを取得する
サーバー上にあるPDFファイルの**用紙サイズ**は、以下で取得できます。
**wに用紙サイズの横幅が、hに縦幅がそれぞれmm単位**で格納されます。

```php
require (__DIR__ . '/vendor/autoload.php'); // composerを使用している前提

function getSizeOfPdf(){
    $pdf = new setasign\Fpdi\Tcpdf\Fpdi(); // 適宜編集してください
    $pdf->setSourceFile('/Path/To/PDF/File.pdf'); // サイズを取得したいPDFファイルへのパスを記載
    $tpl = $pdf->importPage(1);
    $size = $pdf->getTemplateSize($tpl);
    $w = $size['width'];
    $h = $size['height'];
    echo('(width, height)=(' . $w . ', ' . $h . ')');
}
```
なお、上記のコード例における`$size`を`var_dump`すると以下のようになっています。
> array(5) { 
["width"]=> float(160) 
["height"]=> float(207) 
[0]=> float(160) 
[1]=> float(207) 
["orientation"]=> string(1) "P" }

`$size['width']`と`$size['height']`に加え、`$size[0]`に横幅が、`$size[1]`に縦幅がそれぞれ格納されています。上記の例では横幅16.0cm、縦幅20.7cmです。

`$size['orientation']`は用紙のタイプです。'L'なら横長(Landscape)、'P'なら縦長(Portrait)です。

# 特定のファイルと同じサイズでページを作る
**サーバー上に存在するPDFファイルから、一部のページを切り出した新しいPDFファイルを作る**ことを考えます。このとき、単純に`new \Fpdi`しただけではファイルサイズが同じになるとは限りません。場合によってはコピー元のPDFファイルがはみ出たり、反対にページ内に余分な空白が生まれてしまう場合があります。

記事の前半で載せたコードを応用して、「**サーバー上のPDFファイルから一部のページを切り出し、用紙サイズを揃えて別のPDFに読みこむ**」という処理は以下で実現できます。

```php
require (__DIR__ . '/vendor/autoload.php'); // composerを使用している前提

function extractPageFromPdf(){
    $pdf = new setasign\Fpdi\Tcpdf\Fpdi(); // 適宜編集してください
    $pdf->setSourceFile('/Path/To/PDF/File.pdf'); // サイズを取得したいPDFファイルへのパスを記載
    $tpl = $pdf->importPage(1);
    $size = $pdf->getTemplateSize($tpl);
    $w = $size['width'];
    $h = $size['height'];

    $pdf = new setasign\Fpdi\Tcpdf\Fpdi('P', 'mm', array($w, $h));
    $pdf->AddPage();
    $pdf->setSourceFile('/Path/To/PDF/File.pdf');
    $tpl = $pdf->importPage(1);
    $pdf->useTemplate($tpl, 0, 0, $w, $h);
    $pdf->Output('/Path/To/New/PDF/File.pdf', 'F'); // 保存先のパスを入れないと上手く動きません
}
```
# 終わりに
**ページサイズを揃えて特定のページだけ切り出したい場面は意外と多い**のではないでしょうか？
ほとんど公式ドキュメントの焼き直しですが、参考になれば幸いです。
Next.jsの基礎知識を学ぶ

## はじめに
Next.jsがどのようなフレームワークであるのかを学び直したので、まとめていきます。

## Next.jsとは
Next.jsはReactのフレームワークで、サーバーサイドレンダリング（SSR）や静的サイト生成（SSG）などの機能を提供する、JavaScriptベースのフレームワークです。Next.jsは、Reactをベースにしており、Reactアプリケーションをより高度に開発するためのツールや機能を提供します。
Reactにプリレンダリングはありませんでした。

## なぜNext.jsが誕生したのか
Reactのみでは大規模なWebサイトの開発に向いていない。読み込み速度が遅くなってしまう。

## ReactとNext.jsの違い
Reactは初回読み込み時に真っ白な状態から画面がスタートし、そこから必要なJavaScriptやHTMLの読み込みが始まるため、なので、一気にHTMLやJavaScriptを読み込むため、動作が遅くなってしまう。
一方、Next.jsは最初の読み込み時にHTMLを読み込んでおき(プリレンダリング)必要なところだけ(ページ)をJavaScriptだけを読み込むので、動作が高速になる。最初に画面を生成しているのでSEO対策にもなる。Reactでは全てのJavaScriptを読み込むので、遅くなってしまう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/0172aa71-7ff9-8cca-fd0b-010fad4eb3d5.png)


## ReactとNext.jsのレンダリング手法の違い
Reactでは、クライアント側でHTMLを生成するCSR(SPA)を使用している。
Next.jsではサーバ側でHTMLを作成する。
⇨PCのスペックに頼らない画面レンダリングができる。

## プリレンダリングとは
プリレンダリングとは、簡単に言うと、先にHTMLのみを生成して画面に表示することでユーザー体験の向上になる。というものです。
Next.jsではSSR(Sever Side Rendering)とSSG(Static Site Generator)が使われます。


## SSGについて
SSGは、ビルド時にHTMLを生成しておき、ユーザーからのリクエストが来たら、すぐにレスポンスを返せるようにしておく手法です。

**〇メリット**
リクエストのたびにHTMLを再生成しないので、レスポンスが高速で行われることで、ユーザー体験が非常に高くなります。

**〇デメリット**
ビルドしてしまうと、情報の更新ができないので、頻繁に情報の更新される可能性のあるサービス(SNSなど)には向いていない。

**〇向いているサービス例**
ブログ、ドキュメント、ECサイトの商品ページなど

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/2a09822d-186a-f1d4-cafe-7280f8d9a78e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/891b9d49-ce73-6d7d-d426-80ca80341bf2.png)


## SSRについて
SSRは、ユーザーからリクエストが来るたびに、サーバー側でHTMLを再生して、レスポンスを返す手法です。

**〇メリット**
サーバー側でHTMLを再生成するため、情報の更新が頻繁に行われる可能性のあるサービス(SNSなど)に向いている。

**〇デメリット**
リクエストのたびに画面を再生成するため、レスポンスの時間がSSRに比べて時間がかかってしまう。

**〇向いているサービス例**
SNS、ユーザープロフィールなど

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/1c2b5da2-6e34-b685-41bb-99d1fcf5568a.png)

## Next.jsを使うメリット
以上の内容を踏まえて、Next.jsを使うことのメリットをまとめます。
・クライアントのPCに依存せずにレンダリングできる。
・直感的なルーティング設計ができる。(ここでは話していませんが...)
・ページ読み込み速度が向上する。
・SEO対策になる。


## 最後に
他にも記事を書いているので、良ければ見ていってください。

[基本設計について](https://qiita.com/hukuryo/items/97797a91d7e2ee0bcabc)
[Vue.jsとNode.jsでチャットアプリを作った](https://qiita.com/hukuryo/items/265c676d17fe21e75242)
[Next.js×TypeScriptでTODOアプリを作成する](https://qiita.com/hukuryo/items/ebeb26823f944f143b11)
テーブル全選択チェックボックスのClient Action

こちらの動画を参考にしながらテーブルに選択と全選択のチェックボックスを追加しましたが、一つシンプルにできるところがあったので紹介します。
（テーブルに選択と全選択のチェックボックス追加はこちらの動画を御覧下さい。）
https://www.youtube.com/watch?v=uP9vJVH8PsY

この動画ではAggregateのListをFor Eachしながら、全選択のVariable(BooleanVar)がTrueならIsSelectにTrueをセット、FalseならFalseをセットとしているのですが、それならIfを使わずにBooleanVarを直接入れればいいやん。というClient Actionになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254659/fa3a2752-e272-f461-6730-9e7b8eb81794.png)
私は選択削除の為にチェックボックスを使いましたが、最初Client ActionのFor EachでDeleteEntityのServer Actionを呼び出し、１つずつIdを渡して消すという処理にしてしまいました。すると動作はしますがこれ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254659/797d3ebe-3bb2-26ac-5fcc-d2037624fb40.png)
消えない波線、Performance WarningとSecutiry Warningです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254659/b59e0525-209a-d9f9-74f5-ff3428d53e15.png)
ここからWargingの提案に従い、Listで渡してのServer Actionにしていくわけですが、ここでもうひとつ。
動画ではAggreateにIsSelectを追加していまいしたが、私は誤ってEntityにIsSelectを追加していました。
本来EntityのAttributeは記録の為ですが、結果的にこれが設計の為のAttributeとして機能して約に立った気がします。
（2桁の年やパック10進数といういにしえ？の知識があるともったいない気もしてしまいますが）

またこれでWarningの提案に従えば、波線は消せるという認識が持てるようになりました。
（今ひとつこれとは別に消せない波線がありますが、それはまたにします。）
【SwiftUI】袋文字を作る(Textに外枠を付ける)

# はじめに
文字に外枠をつけることを袋文字って言うらしいです。
今回はそれをSwiftUIで実装してみます。

# サンプルアプリ
![simulator_screenshot_1F7CA1A8-B58D-4739-8C74-784E58B3EA37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/bf92942b-2bd1-e4b8-6ad9-725759e11f07.png)

# 実装
```swift
import SwiftUI

struct StrokeBackground: ViewModifier {
    private let id = UUID()

    private var strokeSize: CGFloat

    private var strokeColor: Color

    init(strokeSize: CGFloat, strokeColor: Color) {
        self.strokeSize = strokeSize
        self.strokeColor = strokeColor
    }

    func body(content: Content) -> some View {
        if strokeSize > 0 {
            strokeBackgroundView(content: content)
        } else {
            content
        }
    }

    private func strokeBackgroundView(content: Content) -> some View {
        content
            .padding(strokeSize * 2)
            .background(strokeView(content: content))
    }

    private func strokeView(content: Content) -> some View {
        Rectangle()
            .foregroundColor(strokeColor)
            .mask(maskView(content: content))
    }

    private func maskView(content: Content) -> some View {
        Canvas { context, size in
            context.addFilter(.alphaThreshold(min: 0.01))
            context.drawLayer { ctx in
                if let resolvedView = context.resolveSymbol(id: id) {
                    ctx.draw(resolvedView, at: .init(x: size.width / 2, y: size.height / 2))
                }
            }
        } symbols: {
            content
                .tag(id)
                .blur(radius: strokeSize)
        }
    }
}

extension View {
    public func stroke(color: Color, width: CGFloat = 1) -> some View {
        modifier(StrokeBackground(strokeSize: width, strokeColor: color))
    }
}
```

# 使い方
```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("テスト")
            .font(.system(size: 50, weight: .black))
            .foregroundColor(.yellow)
            .stroke(color: .black, width: 2)
    }
}
```

# おわり
いい感じになりました
Azure OpenAI Service申請について

Azure OpenAI Serviceを利用するにあたり、Azure OpenAIについてや申請する際に気を付けるべき点などを記載しています。
# 1. そもそもAzure OpenAI Serviceってなに？
Azure OpenAIは、Microsoft Azureクラウドプラットフォーム上で提供されるOpenAIのサービスおよびリソースのことを指します。</br>
OpenAIは、人工知能（AI）および機械学習（ML）の研究と開発を行っている企業であり、GPT-3という大規模な言語モデルを開発しました。

Azure OpenAIは、MicrosoftとOpenAIの提携によって実現されたもので、Azure上でOpenAIの強力なAIおよびMLモデルを利用するための統合プラットフォームを提供しています。</br>
これにより、開発者や企業はAzureのインフラストラクチャとサービスを活用しながら、OpenAIの高度な自然言語処理や予測モデルを利用することができます。</br>
Azure OpenAIを使用することで、テキスト生成、文章要約、機械翻訳、質問応答システム、感情分析など、さまざまな自然言語処理タスクに対して強力なAIモデルを利用することが可能です。</br>
また、Azureの他のサービスとの統合により、スケーラブルな環境でのモデルのトレーニングやデプロイメントもサポートされています。

# 2. Azure OpenAI Serviceを利用するには？
現在、Azure OpenAI Serviceは全員がアクセスできるものではなく、専用のフォームを利用した申請に通過した人の実がアクセスできる状態となっております。</br>
そのため、以下の手順に従って申請を行い承認を受ける必要があります。</br>

## 2.1. Azureサブスクリプションの作成
Azure OpenAI Serviceを利用するためには、Azureのサブスクリプションが必要です。</br>
そのため、サブスクリプションを持っていない方は以下リンクにて作成を行ってください。</br>
[Azureサブスクリプション作成](https://azure.microsoft.com/ja-jp/free/cognitive-services/)
</br>

## 2.2. Azure OpenAI Serviceへの申請
Azure OpenAI Serviceへ申請するには以下のリンクより申請を行ってください。</br>
なお、申請フォームは全て英語のため、英語が苦手な方などはGoogle翻訳を使用しつつ申請を行ってください。</br>
[Azure OpenAI Service申請フォーム](https://customervoice.microsoft.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR7en2Ais5pxKtso_Pz4b1_xUOFA5Qk1UWDRBMjg0WFhPMkIzTzhKQ1dWNyQlQCN0PWcu)</br>
![スクリーンショット 2023-06-29 224304.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3492974/e84a5627-4e09-b953-766d-967fd2493977.png)
申請後は承認された場合、約10日営業日以内にアクセス許可のメールが飛んでくるとアナウンスされます。（なお、私の場合は申請してから数時間でアクセス許可のメールが来ました。）</br>
</br>
なお、申請の際、<span style="color: red; ">以下に該当する方は申請が出来ないためご注意ください</span>。</br>
1. 企業アドレスではなく、個人メールアドレスのみ持っている方。(*1)
2. Azure OpenAI Serviceを使用したいAzureサブスクリプションと、企業メールアドレスを使用して作成したAzureサブスクリプションが一致していない方。(*2)
3. 日本Regionを使用したい方。（*3）

*1: gmail.com, hotmail.com, outlook.comなどの個人メールで申請した場合、申請が却下されます。</br>
*2: Azureサブスクリプションが一致していない場合、申請が却下されます。</br>
*3: 現在、北アメリカ、ヨーロッパ、アジア/オーストラリアの3Regionのみが利用可能です。</br>

申請が承認された後には、AzureにてOpenAI Serviceのリソースが作成可能となります。</br>
それでは良いOpenAIライフを！
Enumerable#sort_by の comparison of Array with Array failed (ArgumentError) というエラーはどのような場合に発生するか

# バージョン情報

```
$ ruby -v
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin22]
```

# 例

[Enumerable#sort_by](https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/sort_by.html) のブロックの評価結果が配列で、かつ配列の要素に nil を含む場合に "comparison of Array with Array failed" というエラーが発生する。

```rb
Pokemon = Data.define(:name, :type1_id, :type2_id)

# 例 1: OK
pokemons = [
  Pokemon.new(name: 'ジュナイパー', type1_id: 5, type2_id: 14),
  Pokemon.new(name: 'ゲッコウガ', type1_id: 3, type2_id: 16),
  Pokemon.new(name: 'フシギバナ', type1_id: 5, type2_id: 8)
]
pokemons.sort_by { [_1.type1_id, _1.type2_id] }.map(&:name)
#=> ["ゲッコウガ", "フシギバナ", "ジュナイパー"]

# 例 2: OK
pokemons = [
  Pokemon.new(name: 'ジャローダ', type1_id: 5, type2_id: nil),
  Pokemon.new(name: 'ゲッコウガ', type1_id: 3, type2_id: 16),
  Pokemon.new(name: 'バクフーン', type1_id: 2, type2_id: nil)
]
pokemons.sort_by { [_1.type1_id, _1.type2_id] }.map(&:name)
#=> ["バクフーン", "ゲッコウガ", "ジャローダ"]

# 例 3: NG
pokemons = [
  Pokemon.new(name: 'ジャローダ', type1_id: 5, type2_id: nil),
  Pokemon.new(name: 'ゲッコウガ', type1_id: 3, type2_id: 16),
  Pokemon.new(name: 'フシギバナ', type1_id: 5, type2_id: 8)
]
pokemons.sort_by { [_1.type1_id, _1.type2_id }.map(&:name)
# `sort_by': comparison of Array with Array failed (ArgumentError)
```

# 理由

ブロックの評価結果の配列に nil が含まれる場合、かつ nil と nil でないオブジェクトの比較が行われる際にエラーが発生する。例えば上記のコードでは、例 1 と例 2 の sort_by では nil と nil でないオブジェクトの比較は行われない。しかし例 3 の場合は行われる。

Enumerable#sort_by では値の比較時に <=> 演算子 (比較演算子) を使用する。この <=> は比較可能な場合は整数値を返し、不可能な場合は nil を返す。例えば nil と整数値は比較ができない。

[module Comparable (Ruby 3.2 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/class/Comparable.html) より

> self <=> other は
>
> - self が other より大きいなら正の整数
> - self と other が等しいなら 0
> - self が other より小さいなら負の整数
> - self と other が比較できない場合は nil
>
> をそれぞれ返すことが期待されています。


```rb
[5, nil] <=> [5, 8]
#=> nil

5 <=> 5
#=> 0

nil <=> 8
#=> nil
```

ちなみに true と false も比較できない。

```rb
false <=> true
#=> nil

[[2, true], [1, false], [2, false]].sort_by(&:itself)
# `sort_by': comparison of Array with Array failed (ArgumentError)
```

どうしても比較したいのであれば、比較可能なオブジェクト同士 (整数と整数など) で比較するように工夫するとよい。

```rb
pokemons = [
  Pokemon.new(name: 'ジャローダ', type1_id: 5, type2_id: nil),
  Pokemon.new(name: 'ゲッコウガ', type1_id: 3, type2_id: 16),
  Pokemon.new(name: 'フシギバナ', type1_id: 5, type2_id: 8)
]
pokemons.sort_by { [_1.type1_id, _1.type2_id }.map(&:name)
# `sort_by': comparison of Array with Array failed (ArgumentError)
pokemons.sort_by { [_1.type1_id, (_1.type2_id || 0)] }.map(&:name)
#=> ["ゲッコウガ", "ジャローダ", "フシギバナ"]

[[2, true], [1, false], [2, false]].sort_by(&:itself)
# `sort_by': comparison of Array with Array failed (ArgumentError)
[[2, true], [1, false], [2, false]].sort_by { [_1, _2 ? 1 : 0] }
#=> [[1, false], [2, false], [2, true]]
```
asdfを使ってrailsのプロジェクトを作るまで

何もない状態からrailsを使ってプロジェクトを立ち上げようとすると無限エラーが出ました
asdfを使っていたので、rubyもasdfで管理してその上でrailsのアプリケーションを作ってみようと思います。

### Railsアプリケーション作成失敗…
```terminal
rails new my_api --api
```
```terminal
Rails is not currently installed on this system. To get the latest version, simply type:

    $ sudo gem install rails

You can then rerun your "rails" command.
```
↑よく見るエラーです。ここで`sudo gem install rails`と打ち込んでも上記のエラーがまた表示されるのはよく聞きます。


バージョンを確認します
```
ruby -v

ruby 2.6.10p210 (2022-04-12 revision 67958) [universal.x86_64-darwin22]
```
2.6.10となっています


asdfでrubyの最新版をインストール
```
asdf install ruby latest
```
asdfでインストールされたrubyのバージョンを確認します
```
asdf list ruby

  3.2.2
```
asdfで最新のバージョンをインストールできました

再度rubyのバージョンを確認します
```
ruby -v

ruby 2.6.10p210 (2022-04-12 revision 67958) [universal.x86_64-darwin22]
```
変わりません
rubyのパスを確認します
```
which ruby

/usr/bin/ruby
```
自分のPCではnodeはasdfで管理されていたのでnodeのパスを確認します
```
which node

$HOME/.asdf/shims/node
```
パスが違うことがわかりました
.zshrcに参照するパスを記載します
```zsh
export PATH="$HOME/.asdf/shims:$PATH"
```

```
source .zshrc
```
```
which ruby

$HOME/.asdf/shims/ruby
```
パスを変更できました
rubyのバージョンを再度確認します
```
ruby -v

ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-darwin22]
```
3.22とあり先ほどasdfで確認したバージョンが反映されています
これで再度railsをインストールしてみます
```
sudo gem install rails

Successfully installed rails-7.0.5.1
Parsing documentation for rails-7.0.5.1
Done installing documentation for rails after 0 seconds
1 gem installed
```
インストールに成功したようです。バージョンを確認してみます
```
rails --version
Rails 7.0.5.1
```
バージョンもしっかり表示されたので、インストールされているようです。
これでrailsのプロジェクトを作成してみます
```
rails new my_api --api

...
...

Bundle complete! 6 Gemfile dependencies, 53 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
         run  bundle binstubs bundler
```
できたっぽいのでディレクトリを進めてサーバーを立ち上げます
```
cd my_api && rails s

=> Booting Puma
=> Rails 7.0.5.1 application starting in development 
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 5.6.6 (ruby 3.2.2-p53) ("Birdie's Version")
*  Min threads: 5
*  Max threads: 5
*  Environment: development
*          PID: 80282
* Listening on http://127.0.0.1:3000
* Listening on http://[::1]:3000
Use Ctrl-C to stop


```
railsの立ち上げに成功しました。
プロキシのお勉強～Cisco Secure Web Appliance～

# はじめに
アプライアンスとは？プロキシとは？というところから、実際に「Cisco Secure Web Appliance」で穴あけ(ホワイトリスト登録)作業や、ドメイン参加を行ったことについて、自分のお勉強＆備忘録として記載しました。

# Cisco Secure Web Applianceとは
世界最大手通信機器メーカーであるCisco社の「仮想アプライアンス」である(以下、WSA と略す)。
アプライアンスとは、特定のアプリケーション機能をあらかじめ組み込んであるコンピュータのことで、OSのインストールや各種設定、アプリケーションのセットアップ等の作業を行うことなく、設置して起動するだけでアプリケーションが利用可能となるもののこと。

WSAは、世界中でプロキシサーバとしての利用実績がある製品である。

# プロキシ(プロキシサーバ)とは
会社内など内部ネットワークにあるコンピュータの代理(proxy)として、インターネット上のコンピュータへ接続を行うコンピュータのこと。
端末がインターネットへ接続する際に、直接Webサイト等にアクセスするのではなく、プロキシへアクセスしプロキシが目的のサイトへ代理でアクセスして、受け取ったデータをブラウザに表示する。

![Qiita投稿用20230629_000000.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3319937/abd503c7-01c2-bb81-3e02-602533ed6f92.jpeg)


# プロキシを利用するメリット

### 匿名性を保てる
先ほどの図にもあるように、端末が直接外部のインターネットへとアクセスをしないため、IPアドレスなどの情報が接続先のWebサーバに残るリスクがなくなる。
プロキシ経由でのアクセスでないと、万が一悪意あるサイトにアクセスしてしまった場合、端末のIPアドレス情報を把握され、それをもとにサイバー攻撃を受ける可能性もある。
しかしプロキシを利用すれば、接続先に情報が伝わることはない。

### 接続先を制限することが可能
不正サイトや企業としてふさわしくないサイトなどに対して、URLフィルタリングをすることで、クライアントのアクセスを制限することができる。

### キャッシュ機能によるアクセスの高速化
キャッシュ機能とは、一度アクセスしたWebサイトの情報を一時的に保存する機能である。
この機能により、一度アクセスしたことのあるWebサイトに再度アクセスする際は、Webサーバとのファイルの受け渡しを省略できるため、アクセスが高速化する。
通常、キャッシュはデバイスごとの保存となるが、複数のデバイスで同じプロキシを利用している場合は、1つのデバイスが一度訪問したサイトをすべてのデバイスで高速に表示することができる。

### ログ取得
プロキシを利用すると、誰がどのサイトにアクセスしたかを「アクセスログ」として取得することが可能。業務に不要なサイトや、危険なサイトの閲覧防止に繋がり、セキュリティをより強化することができる。
また、サイバー攻撃が発生した際は、ログを解析することで、被害状況や不正アクセスの特定ができる。

# 接続先制限
WSAでは、”接続先のURLを指定したもの”と、”接続するユーザーをIPセグメント単位で指定したもの”を、それぞれ組み合わせて”アクセスポリシー”として管理することができる。
これにより、不要な接続先への制限を行ったり(ブラックリスト登録)、一部のユーザーに対してのみあるサイトのアクセスを許可したり(ホワイトリスト登録)することができる。

WSAをドメイン参加させADと連携することで、接続するユーザーを、ADのグループごとに制限することも可能となる。
WSAをドメイン参加させる際、指定するOUが**和名**だと、仕様によりドメイン参加ができない。英文字(1バイト文字)のみのOU名を指定してドメイン参加をする必要がある。
SARA-R410M LTEモジュールを使ってみた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/c494ab7f-2a60-8a1b-88d2-d0d00bafe342.png)

今回もご依頼を頂きまして、LTEモジュールを使用したシステムの開発をしています。

SARA-R410Mというモジュールを使用しているのですが、なかなか日本で開発を行っている記事が
少ないので、海外サイトを参考にしたり、メーカー（海外）とやり取りをしてなんとか開発している
状況です。

多くの人には参考にならないかもしれませんが、ニッチなニーズに向けて発信です！！
LTE通信を使用して何か開発をしたい方はお気軽にご相談下さい！

この記事では、yahooのWebサイトの情報取得方法を記載したいと思います。

## ハードウェア
1、SARA-R410M LTEモジュールピッチ変換基板
https://www.switch-science.com/products/6200?_pos=1&_sid=24717502e&_ss=r

2、NTB0104 レベルシフタ ピッチ変換済みモジュール
https://www.switch-science.com/products/2351?variant=42381923713222

3、ＦＴ－２３２ＲＱ　ＵＳＢシリアル変換モジュール
https://akizukidenshi.com/catalog/g/gM-11007/
※基板上にあるディップSWは、どちらもONにします。

## 回路図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/59ce7eb7-8bc8-3c45-97a3-b2b6909d557e.png)

## 使用方法
今回はArduinoIDEのシリアルポート通信を使用して、SARA-R410MにATコマンドを送ってみたいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/1702a294-1d00-cdfa-63ab-e4aa883d7b26.png)

```
//MNOをドコモ（20）に設定します
AT+UMNOPROF=20
>OK

//パラメータ保存
AT+CFUN=15
>OK

//モジュールをネットワークから登録解除する
AT+COPS=2
>OK

//APNの設定
AT+CGDCONT=1,"IP","APN名"
>OK
AT+UAUTHREQ=1,1,"ユーザー名","パスワード"
>OK

//自動設定
AT+COPS=0
>OK

//IPを取得できたか確認
AT+CGDCONT?
> +CGDCONT: 1,"IP","APN名","100.115.***.***",0,0,0,0

//名前解決できるか確認
AT+UDNSRN=0,"www.google.com"
> +UDNSRN: "142.250.206.196"

//HTTPプロファイルの設定
AT+UHTTP=0
>OK

AT+UHTTP=0,1,"yahoo.co.jp"
>OK

//ポートを80に設定
AT+UHTTP=0,5,80
>OK

//接続して情報をget.ffsに保存
AT+UHTTPC=0,1,"/","get.ffs"
> +UUHTTPCR: 0,1,1

//保存したファイルの中身確認
AT+URDFILE="get.ffs"
```

今回はとても簡単な使用方法を説明しましたが、このモジュールを使用すればIoT製品のデータを
LTEを使用してクラウドに送信したり、
写真データもクラウドに送信して、クラウド上で画像解析をして、モジュールに対して何らかのアクションを
するよう指示を出すこともできます！

色んなことができそうですね！！

何か開発依頼などございましたら、お気軽にご相談下さい。
Bootstrapで実装したハンバーガーメニューが開かない問題を解消する

## はじめに
Bootstrap(version v5.0.2)を使用して、[公式サイト](https://getbootstrap.jp/docs/5.0/components/navbar/)を参考にナビゲーションメニューを実装しました。

[公式のイントロダクション](https://getbootstrap.jp/docs/5.0/components/navbar/)に記載がある通りレスポンシブ用metaタグを追加し、
```html:HTML
<meta name="viewport" content="width=device-width, initial-scale=1" />
```
画面幅が小さくなると自動的にハンバーガーメニューの表示になるものの、
ハンバーガーメニューのアイコンをクリックしてもメニューが開かない・・・。

原因を調査してHTMLファイルを修正しました。

## 原因
**ハンバーガーメニューの実装に必要なjsライブラリ(jQuery)やpopper.jsを読み込んでいないこと**が原因でした。[公式のイントロダクション](https://getbootstrap.jp/docs/5.0/getting-started/introduction/#bundle)にもこれらの読み込みが必要との記載がありました。

## 解決法
下記コードを `</body>` タグの直前に記述しました。
```html:HTML
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
```
必要なファイルをCDNで読み込んでいます。

[公式のイントロダクション](https://getbootstrap.jp/docs/5.0/getting-started/introduction/#bundle)に記載がある方法（BundleとSeparate)で試したところ動かず、[こちらのサイト](https://pisuke-code.com/bootstrap-why-not-work-dropdown/)を参考にして記述したところ無事動きました。

## 参考サイト
[Bootstrapのドロップダウンが動かない時にありがちな２つの原因](https://pisuke-code.com/bootstrap-why-not-work-dropdown/)
[Bootstrap公式サイト](https://getbootstrap.jp/)
XAMPP（mac OS）のWebページを開けない問題に関する解決方法

問題１：
  画像の画面で、MySQL DatabaseがRunning,Apache Web Serverのところでstartをクリックしても、StatusがずっとStoppedの状態です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480732/0021435c-537f-7a80-99de-d866f52d46dc.png)

ブラウザのアドレスの空欄で、localhostを入力したら、表示できます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480732/033c98ba-7c30-cb82-dc7b-34caf2813330.png)


問題点１の解決:

（1）ターミナルを開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480732/4de03d30-ba56-7d6e-7156-34b6da358ace.png)

(２)コード1：sudo apachectl stopを入力して、returnキーを押す
   コード2：sudo /Applications/XAMPP/xamppfiles/xampp startを入力して、returnキーを押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480732/fec9265c-15f9-53b2-56f0-d4035a364e65.png)

(3)XAMPPを閉めて、もう一回開いて、Apache Web Serverのstartをクリックして、StatusがRunningになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480732/1fab1c3a-561b-8b00-53f9-02db401870d3.png)

<hr>
問題２：しかし、localhost/phpmyadmin/を入力したら、画像どおりエラーがでできました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480732/8e4db448-6301-283f-8eba-7744eebfc6df.png)

でも、先入力したデータベースのページにまだ入ることができないです。

問題点2の解決：

（1）Apache Web ServerのConfigureをクリックして、Port番号を確認して、私のが5050です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480732/443fe14a-2bfd-2288-a6bf-bd002bc1b5b1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480732/6d36f396-af0a-0d0f-a3b2-ed2e54e3f341.png)

(２)アドレス空欄で、localhost:5050/phpmyadmin/ を入力して、絶対に　:5050　を漏れないです。
(まだ開けないなら、先１番目のport番号を8080とかを変更して試してください)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480732/0db8138a-d8c3-12b0-8e41-4cb85a932857.png)

<hr>
問題3：
xamppのPHPファイルからデータベースと接続できない問題

コントロールパネルで、Apache Web ServerがRunning,MySQL Databaseのところでstartをクリックしても、StatusがずっとStoppedの状態です。

問題３の解決：
（1）Apache Web ServerのConfigureをクリックして、Port番号を確認して、3306から3307へ変更した
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480732/74789b28-8581-1862-79ff-8191afe04233.png)

(２)PHP設定
Applications/etc/php.int
以下の２行を見つけて、前の[;]を削除、保存

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480732/89006e14-f536-0903-313e-22c5dcf4835e.png)

phpページで入力したデータをデータベースの中に増えることができる。
[祝!]EC2 Instance Connect Endpoint経由でRDS(3389)に接続できた話

# 背景
Twitter でプロフィールエンジニアリング中の [@\_\_\_nix___](https://twitter.com/___nix___) です。

さて、

[EC2 Instance Connect Endpoint経由でRDSに接続してみた](https://dev.classmethod.jp/articles/how-to-connect-rds-instance-via-eic-endpoint/)

で一躍有名になった 「EC2 Instance Connect Endpoint経由でRDSに接続」 のお話でしたが、数日後には利用可能ポートが制限されてしまいました。

```
awscli.customizations.ec2instanceconnect.websocket - ERROR - {"ErrorCode":"InvalidParameter","Message":"The specified RemotePort is not valid. Specify either 22 or 3389 as the RemotePort and retry your request."}
```

「AWS はなんてことをしてくれたんだ！」

と界隈では落胆の空気が流れる一方で...

「RDSのポートを 3389 にすればRDSに接続できるんじゃね？」

![](https://storage.googleapis.com/zenn-user-upload/4d18df072fe4-20230629.png)

で、早速やってみた！

# 構築手順

## RDS と VPCエンドポイント用に SecurityGroup を準備
ここは省略しますが、クラメソさんの記事を参考にしてください。

## RDS を構築
もちろん 3389 ポートで。
![](https://storage.googleapis.com/zenn-user-upload/a014447b7640-20230629.png)

## VPCエンドポイントも構築
あと少しです。
![](https://storage.googleapis.com/zenn-user-upload/ea966bec4c78-20230629.png)

# 接続

## RDS のプライベートIPを調べる

```
host database-1.cluster-xxxxxxxx.ap-northeast-1.rds.amazonaws.com
172.31.0.118
```

## VPCエンドポイントのIDを調べる
これはAWSマネージドコンソールから取得してください。

## open-tunnel を実行
3389 を 13389 にポートフォアディングします。

```
/usr/local/bin/aws ec2-instance-connect open-tunnel --instance-connect-endpoint-id eice-xxxxxxxxxxxx --private-ip-address 172.31.0.118 --local-port 13389 --remote-port 3389 &
```

以下のメッセージが出ればOKです。

```
Listening for connections on port 13389.
```

## ドキドキの瞬間

```
mysql -u admin -h 127.0.0.1 -p -P 13389
Enter password:
[3] Accepted new tcp connection, opening websocket tunnel.
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 229
Server version: 5.7.12 MySQL Community Server (GPL)
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [(none)]>
```

ｷﾀ━━━━(ﾟ∀ﾟ)━━━━!!

# 編集後記

多分、最速記事。
だと思う...。

AWSさん的に都合の良い記事なのか？
ごめんなさいね。

:::note alert
悪い使い方はせずに正しく使おう！
:::
AWS EC2(Ubuntu)でapt updateができなかった話

最近やっとAWSを触るようになって、毎日が勉強

基本はt2.micro（AMIはAmazon Linux）のを使用しているが、訳あって「g4dn.xlarge」を使用することになり、せっかくなのでAMIも「Ubuntu」を使ってみることにした。

pythonの環境を作成するのに、apt updateを実行すると以下のエラーが

```
W: Failed to fetch http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/dists/focal-updates/InRelease  503  Service Unavailable
W: Failed to fetch http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu/dists/focal-backports/InRelease  503  Service Unavailable
W: Some index files failed to download. They have been ignored, or old ones used instead.
```

インターネットに接続できていないのかと思い、pingで確認するとちゃんと通る

調べてみると、そんなに多くはないが同じようなエラーの記事が見つかる

レポジトリのURLを変更すると解消するらしい

sudo vi /etc/apt/sources.list

最初の「http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu」　を
「http://archive.ubuntu.com/ubuntu」
に変更し、再度「sudo apt update」を実行


いけた。

詳細な原因は不明だ・・・
標準入力の備忘録

備忘録として書き散らしたものですのであまり参考にはなさらず、、、

# 3つのデータの入力

解答
```
n = gets

answer = n.split(" ")
puts answer
```
結果
```
11111111
2222222
333333
```

これで行ごとにデータを取得することができました！
テンプレートエンジンは素直にフロントフレームワーク(Vue,React,Svelteなど)を使わせて欲しいという話

## はじめに

こんにちは、初めての投稿になります。
フロントエンドエンジニアとして職務につき早7年目になります:sweat:

僕の周りでは徐々に`Nuxt3`を使った案件や、
`Vite+Vue3にAPIサーバとしてのLaravelを置く構成`が増えてきました。

ただ一方でLaravelのテンプレートエンジンであるbladeに、
**部分的にVueコンポーネントを採用するようなパターン**も依然として多くあります。

* **サーバとフロントを疎結合にしてSPA + APIの形式で構築する**
* **サーバサイドのテンプレートエンジンに乗っかる形でフロントを組み立てていく**

両方とも有力な選択肢だと思いますが、
今回は1人のフロントエンドエンジニアとしてどちらだと嬉しいかという観点でお話したいと思います。


:::note warn
以下の前提で話を進めます。
* プロジェクトに専属のフロントエンドエンジニアが1人はいる
* SPA用のフレームワーク(Vue/React/Svelteなど)を1つは習熟しており一から構築できる
:::



また個人的な意見を多く含んでいるためポエムとしてご鑑賞頂けたら幸いです。
それでは始めましょう！


## SPA + API開発のメリット

タイトル書いただけで何番煎じだよ・・と自分でも思っちゃったので、とりあえずChatGPTに聞いてみましょう。最近は困ったらこれです。
![スクリーンショット 2023-06-29 19.11.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/503677/a38a64da-f558-1a00-b845-917df47172ec.png)


ふむふむ、どれもUIUXを向上するのに非常に重要な要素ですね！
ですが今回はここに書かれていないものを1つ挙げたいと思います。

それは**フロントエンドの責務**に関することです。

サーバサイドのテンプレートエンジンに乗っかることが問題だと思う最大の理由は、
**フロントエンドの責務が極端に狭められてしまうこと**にあります。

どういうことかご説明する前に、
近年のフロントエンドフレームワークが持つ性質として、
`宣言的UI`というのがあるので簡単にご紹介します。

:::note info
宣言的UIとは
数式で表すと`UI = f(state)`
状態が変わればUIも変わることを端的に説明する文脈で用いられます。
:::

一方でこれは個人的な解釈ですが、
**状態をどれだけ大きなスコープで持てるかがUIへの影響度そのものに直結するとも言えます。**

どういうことかご説明します。

サーバのテンプレートエンジンに乗っかるということは、
**フロントエンドの責務がテンプレート部に限定されるということ**で、
同時に状態のスコープとしてもページ内に閉じられます。
それはページより外の状態にも、状態を変えるロジックにも基本的にアクセス権がないことを意味します。

一方でSPAにするということは、
**フロントエンドの責務を通信を除くアプリケーション全体まで拡げるということ**を意味します。

ルーティングやアプリケーション内の状態管理、ビジネスロジックなど含め、
通信を除いたあらゆる状態がフロントエンド側で制御することが出来るようになるため、UIに対する自由度に制限がありません。

・・・話していること難しいですか？
簡単に言っちゃうと、もっとフロントで好き放題やらせろということです。


## それでもサーバサイドテンプレートを使用したい場合は・・

### インタラクティブなUIはある程度諦めてください。

UIの状態の多くはサーバ由来の変数で判定することになり、
初回レンダリング以降の画面要素の更新は基本的に難しいです。

モダンなJSフレームワークであれば状態をランタイムで保持し
状態の変更をトリガーに画面要素を再レンダリングするのが当たり前なのですが、
それが出来ないため手続き的な対処を迫られます。

そこでは死んだ目をしながら、
要素を取得してクラスを当て替えするフロントエンドエンジニアが観測できるでしょう。


### 基本的におんぶに抱っこになりますが許してください。

サーバーサイドテンプレートを選んだ時点で、
下のお世話から何から何までサーバサイドにお願いすることになります。
(ページの用意、ルーティングの繋ぎ込み、テンプレート内で必要な変数の用意など)

それだけではありません、UI設計がサーバ実装に依存するリスクがあります。
例えばカレンダーのUIがあるとします。

月選択をするとURLにクエリが付いた状態でページリロードが走り、
サーバからは選択した月のデータが送られてくるという設計です。
![yokoyama.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/503677/e473022a-2e14-c3a8-c451-d88606d7b16d.png)


お客さんから「**毎回ページリロードするの見栄え悪いんだけど・・**」と言われても、
非同期で取ってくるような設計に変えるにはサーバ側の対応が必要です。
フロントは渡ってきた情報を加工することくらいしかしませんし出来ないのです。

そこではUIの理想と現実に葛藤するフロントエンドエンジニアが観測できるでしょう。


### フロントにあまり多くを望まないでください。

再三になりますが、
サーバのテンプレートエンジンに乗っかるということは、
フロントエンドの責務がテンプレート部に限定されるということです。
SPAと違い出来ることがそもそも少ないです。

そこではscopedの庇護下から離れ、日々グローバル汚染に怯えながら、
クラス名を考えるだけで精一杯なフロントエンドエンジニアが観測できるでしょう。


おわり。
ODMをdockerで試してみる

タイトルの通り、dockerを使ってODM(IBM Operational Decision Manager)を動かしてみます。以下の人向けです。

- ルールエンジンを手軽に動かしてみたい人
- ODMって聞いたことあるけど、触ったことない人
- できるだけ面倒な準備なしでODMを動かしてみたい人

# ODMとは？

- オンプレミスまたはクラウド上で、ルールに基づくビジネス上の意思決定を検出、取り込み、分析、自動化、管理するための包括的な意思決定の自動化ソリューションです。
- つまり、IBM製のルールエンジンです。
- 公式サイト：https://www.ibm.com/jp-ja/products/operational-decision-manager
- ドキュメント：https://www.ibm.com/docs/ja/odm/8.11.1
- Docker imageのドキュメント：https://hub.docker.com/r/ibmcom/odm/
- チュートリアル：https://github.com/DecisionsDev/odm-for-container-getting-started

# 前提知識

- Docker
- Linuxコマンド

# 環境
- Windows11 + WSL2(Ubuntu 20.04.5)
- Dockerインストール済み
- ブラウザはEdge

# 起動
https://hub.docker.com/r/ibmcom/odm/ の記述に従い、以下コマンドで動かします。これだけです。

```
docker run -e LICENSE=accept -p 9060:9060 -p 9443:9443  -m 2048M --memory-reservation 2048M  -e SAMPLE=true icr.io/cpopen/odm-k8s/odm:8.12
```

# 起動確認

ブラウザで http://localhost:9060/decisioncenter にアクセスしてみましょう。ログイン画面が出てきました！ユーザー名、パスワードともに`odmAdmin`でログインできます。

![odm-login.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327995/0f2c0a5d-ae5d-1f6e-c5f8-eec815bf6ade.png)



ログインするとライブラリのページに遷移します。Miniloan Service, Loan Validationの2つのサンプルプロジェクトがあるのがわかります。

![odm-library.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327995/5adb982c-b469-4f11-8b5d-3a0d5ac46d12.png)



# サンプルプロジェクト Miniloan Service を動かしてみる

サンプルプロジェクトを動かしてみましょう。まず、以下のGithubリポジトリから、`miniloan-test.xlsx`をダウンロードします。このファイルには、テストシナリオとあるべき結果が入力されています。

https://github.com/DecisionsDev/odm-for-container-getting-started/tree/master

ODMの画面に戻り、「Miniloan Service」 → 「メイン」をクリックし、「テスト」タブを選択。左上の＋ボタン（新規テストスイートボタン）をクリックします。

![odm-test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327995/399bdfd4-86ad-9bb4-075c-6a0c5c0dca99.png)

「シナリオ・ファイル」の下の「選択...」をクリックし、先ほどダウンロードした`miniloan-test.xlsx`を選択します。

![odm-test-suite.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327995/920abacb-56e2-0721-35ce-024e870cb5ff.png)

シナリオファイルに`miniloan-test.xlsx`が選択されました。この状態で、右上の「保存して実行」ボタンをクリックしましょう。「新規バージョンの作成」というウィンドウが出てきますので、「新規バージョンの作成」ボタンをクリックするとテストが実行されます。

![odm-exe.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327995/e9cd0154-db07-1838-49f8-76f2e3c6bf3c.png)


レポートを見てみましょう。「サンプルレポート」をクリックします。

![odm-executed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327995/69dff677-9c65-4bb6-de4e-e955db3c32bc.png)

すべてのテストが成功しているのがわかります。

![odm-result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327995/4684c3a8-920c-daa3-000a-8df759ee3354.png)

# まとめ

今回はODMをコンテナから簡単に起動し、テストを実行してみました。次回はルールを修正してみます。
【技術書メモ】アジャイルサムライ――達人開発者への道

# この記事は何？
[アジャイルサムライ](https://www.amazon.co.jp/%E3%82%A2%E3%82%B8%E3%83%A3%E3%82%A4%E3%83%AB%E3%82%B5%E3%83%A0%E3%83%A9%E3%82%A4%E2%80%95%E2%80%95%E9%81%94%E4%BA%BA%E9%96%8B%E7%99%BA%E8%80%85%E3%81%B8%E3%81%AE%E9%81%93-%EF%BC%AA%EF%BD%8F%EF%BD%8E%EF%BD%81%EF%BD%94%EF%BD%88%EF%BD%81%EF%BD%8E%EF%BC%B2%EF%BD%81%EF%BD%93%EF%BD%8D%EF%BD%95%EF%BD%93%EF%BD%93%EF%BD%8F%EF%BD%8E-ebook/dp/B00J1XKB6K/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=XBRSBQCCTWK&keywords=%E3%82%A2%E3%82%B8%E3%83%A3%E3%82%A4%E3%83%AB%E3%82%B5%E3%83%A0%E3%83%A9%E3%82%A4&qid=1688039764&sprefix=%E3%82%A2%E3%82%B8%E3%83%A3%E3%82%A4%E3%83%AB%E3%82%B5%E3%83%A0%E3%83%A9%E3%82%A4%2Caps%2C341&sr=8-1)を読んだ個人的な読書メモです

# どんな本か
アジャイル開発の入門書。
アジャイルな開発とはどんなものかが書かれている

# 何を学んだか
* アジャイル開発のおおまかな進め方
* アジャイル開発の用語
    * マスターストーリリスト
    * ユーザーストーリー
    * イテレーション（スプリント）
    * ベロシティ
* アジャイル開発における役立ちツール
  * インセプションデッキ
  * トレードオフ・スライダー
  * バーンダウンチャート
  * カンバンボード
  * リリースボード
  * ストーリーボード
* アジャイル開発におけるチームビルディング
* 顧客との向き合い方
    * 顧客とどのようにコミュニケーションを取るべきか
    * 顧客をどのようにプロジェクトに巻き込むか
    * 正直に話す、質問をする
    * 信頼貯金をつくること
    * 進捗を見える化し、期待をマネジメントすること
* 要件の決め方
    * 要件定義書はつくるべきものではない。つくるべきものは顧客が望むもの
    * できれば直接顧客と話す。
    * ユーザーストーリーを集める。
    * 文章は最後の手段。信頼しすぎない。
* スケジュールと見積もりの方法
    * スケジュールに問題が出たら、スコープを動かす。時間、期間、予算は動かないため。
    * 各ストーリーが何日で終わるかではなく、基準となるストーリーに対する相対見積もりをする
    * 実現の見通しが立たないときは、技術検証（スパイク）のストーリーを行う。
    * ストーリーを追加するときは、かわりに既存ストーリーをマスターストーリーリストから削ってもらうこと。
    * ベロシティを計測し、バーンダウンチャートでプロジェクトの終わりを可視化する。
* 危険を察知する方法
    * インセプションデッキ、ストーリーボード、バーンダウンチャート、リリースボードを使って進捗状況を可視化する。
    * プロジェクトで使う言葉をきちんと定義する。顧客の使う用語に合わせるのが大事。誤解を減らせる。


# 感想など
* 文章が非常に読みやすい。挿絵や文章に遊び心が感じられ、初心者でもサクサク読める。
* アジャイル開発に関する本だが、アジャイルでなくとも活かせる考え方が所々にあり、ソフトウェア開発に関わる人であれば読んで損はないと感じた。
* 顧客と開発の間で隠し事をせず、すべてを共有するというスタンスなので、その点は覚悟する必要がある。不都合な点があっても、正直になることが求められる。

# おすすめできる人
* アジャイル開発の進め方ついて知りたい人
* 開発における顧客とのコミュニケーションの取り方を知りたい人
HTMLとCSSの概要

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/d1b67457-6e2f-ebe4-200e-ebc61e9dd65b.png)

１：HTML（HyperText Markup Language）エイチティーエムエル（ハイパー テキスト マークアップ ランゲージ）
ウェブサイトに表示される情報を記載する言語です。
〇〇.htmlという名前のファイルに記述します（例：test.html）。

２：CSS（Cascading Style Sheets）シーエスエス（カスケーディング スタイル シート）
HTMLに装飾を加えるための言語です。
〇〇.cssという名前のファイルに記述します（例：style.css）。

３：拡張子
拡張子は、ファイルに書かれる言語の種類を識別するためにファイル末尾につける文字列です。
例えばhtmlのファイルを作成する場合は〇〇.htmlとなり、CSSの場合は〇〇.cssとなります。このように、言語ごとに拡張子が異なります。
JavaScriptの文字列あれこれ

# はじめに

これ↓に解説を付けただけです。ほぼ自分用。

https://www.instagram.com/p/CuCGNxmNLeV/

初学者なので、ご指摘あればぜひください。

# くっつける

`+`演算子でよし。

```jsx
"Hello" + " " + " World"; // Hello World
```

元画像には`String.concat(args)`が紹介されていますが、性能的にも代入演算子のほうがいいっぽいので、特に使う必要はない様子。

[String.prototype.concat() - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/concat#性能)

# 余分な空白を切り取る

`String.trim()`は、前後の余分な空白（インデントなど）を取り除く。

```jsx
"   Hello   ".trim(); // "Hello"
```

前半のみ取り除く場合は`String.trimStart()`、後半は`String.trimEnd()`で取り除くことができる。

```jsx
"   Hello   ".trimStart(); // "Hello   "
"   Hello   ".trimEnd(); // "   Hello"
```

# 繰り返す

`String.repeat(count)`で、カウント分繰り返す。

```jsx
"Hello".repeat(3); // HelloHelloHello
```

# 埋める

`String.padStart(length, char)`は、指定した文字数になるように文頭から埋めてくれる。

```jsx
"Hello".padStart(7, "#"); // ##Hello
```

文末から埋めたい場合は`String.padEnd(length, char)`を使う。

```jsx
"Hello".padEnd(7, "#"); // Hello##
```

# 切り取る・抽出する

## 一文字取り出す
一文字であれば、配列のようにブラケット指定が使用できる。
```jsx
"Hello"[4]; // o
```

`String.charAt(index)`で、指定したインデックスの文字列が抜き出せる。

例では、インデックスが4（＝5文字目）の`o`を抜き出していることがわかる。

```jsx
"Hello".charAt(4); // o
```

## 指定した部分を切り出す
`String.slice(start, end)`で、指定した部分を文字列として切り出せる。
注意点として、`end`**に指定したインデックスの文字は含みません。**

```jsx
"Hello".slice(1, 3); // el
```

`String.substring(start, end)`も同様に使える。

```jsx
"Hello".substring(1, 3); // el
```

~~また、`String.substr(start, length)` というものもある。
これは、**startで指定したインデックスから初めて、長さがlengthになる**ように文字列を切り出す。~~

この機能は現在非推奨になっている様子。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/substr

```jsx
"Hello".substr(1, 2); // el
```

`slice`と`substring`の違いについては以下がわかりやすかった。

[【JavaScript】sliceとsubstringの違い｜Webエンジニア Wiki](https://web-engineer-wiki.com/javascript/slice-substring/#:~:text=セットした時-,sliceとsubstringの2つの違い,-sliceメソッドと)

# 置き換える

## 大文字・小文字にする

`String.toLowerCase()`ですべて小文字になる。

```jsx
"Hello".toLowerCase(); // hello
```

`String.toUpperCase()`ですべて大文字になる。

```jsx
"Hello".toUpperCase(); // HELLO
```

## 指定した文字を置き換える

`String.replace(old, new)`で、指定した文字に当てはまるもののうち最初の要素を置き換える。

```jsx
"Hello".replace("l", "*"); // He*lo
```

`String.replaceAll(old, new)`ですべて置換する。

```jsx
"Hello".replaceAll("l", "*"); // He**o
```

# 分割する

`String.split(str)`で、指定した文字列を仕切り文字として分割する。
空文字を指定することで、1文字ずつに分解することもできる。

```jsx
"Hello".split(""); // ['H', 'e', 'l', 'l', 'o']
```

# 検索する

## 何文字目にあるか

`String.indexOf(str)`は、指定した文字列の**頭文字**が含まれる最初のインデックスを返す。
なければ`-1`を返す。

```jsx
"Hello".indexOf("o"); // 4
```

`String.lastIndexOf(str)`は、指定した文字列の**頭文字**が含まれる最後のインデックスを返す。
こちらもなければ`-1`を返す。

```jsx
"Hello".lastIndexOf("lo"); // 3
```

`String.search(str)`は、文字列と正規表現のどちらも使うことができる。
なければ`-1`を返す。

```jsx
"Hello".search("el"); // 1
```

## 含むかどうか

`String.includes(str)`は、指定した文字列が含まれているかどうかを判定する。

```jsx
"Hello".includes("e"); // true
```

より詳しく**正規表現**を用いる場合は、`Regex.test(str)`を使う。

```jsx
/[A-Z]/.test("Hello"); // true
```

## 先頭・末尾がその文字列か

指定の文字列で始まるかどうかは、`String.startsWith(str)`で検査できる。

```jsx
"Hello".startsWith("Hell"); // true
```

指定の文字列で終わるかどうかは、`String.endsWith(str)`で検査できる。

```jsx
"Hello".endsWith("ello"); // true
```