OmniAICreator/Qiita-1.07M huggingface dataset:
VS Code でWSL2につなぐと Unexpected end of JSON input エラーが出るときの対処法

# 状態

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85205/86cdff1b-e147-cbda-8ade-4e4d7209f43d.png)

（ほぼ）全ての拡張機能が無効化され、新たに拡張機能を有効化（インストール）しようとしても `Unexpected end of JSON input` のエラーが出ます

# なぜ起きたか

わからないです。
何もしてないけど壊れました。

# 何が起きているのか

エラー文から推測するに、拡張機能なりVS Codeなりを管理しているJSONファイルの形式が壊れていそうです。
運が良ければJSONファイルの修正で済みそうですが、現状はエラーが出ているせいで拡張機能のインストールも出来ないしそもそも使えない状況なので、とりあえずどうにかしなければいけない状況です。

ただ、VS Codeを起動しただけでは影響はなく、WSLに繋いだ時だけ影響がありそうです。
（通常起動時↓）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85205/767f61fa-6b92-92fd-c905-7534d6e67f79.png)

（WSL接続時↓）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85205/3bc16d54-5837-ee2b-8f89-a3cc0973fa5a.png)

# WSL上のVS Code の拡張機能を管理しているjsonファイルを確認する

```
$ cd ~/.vscode-server-insiders/extensions/
$ cat extensions.json
```

ファイルサイズがでかいので全て乗せるのは省略しますが、とりあえずはJSONファイルが壊れていそうです。
流石に修正するのは困難かつ、拡張機能はインストールし直せば良いので、JSONファイルを消してしまいます。

```
$ mv extensions.json _backup.json
```
（消すと言いつつ消すのが怖い人）

# 再起動

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85205/3891c3d6-c227-92d4-5ff6-73aebb796f69.png)

拡張機能が正常に再インストールされました。
めでたしめでたし。

# まとめ

VS Codeはアップデート中とかに無理やり強制終了させてしまうとたまにファイルが壊れてしまうので気をつけないとですね。

もちろん積極的に強制終了させることは無いんですが、Windowsを再起動するタイミングでVS Codeを終了 → 終了したタイミングでVS Codeのアップデートが走る → アップデート中にWindowsを再起動させてしまう

これで簡単に壊れてしまいます。

気をつけなければ。

# 出典

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85205/8dfb4a61-95a6-c160-4987-225d9245ee85.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85205/f41eaf1e-bf0e-deeb-5817-13275a9b5baf.png)
https://chat.openai.com/share/1a46ee3b-86e1-4b11-b3a5-022025bcc2c1

チャットGPTやるなぁ
React 仮想DOM

# はじめに
Reactの特徴として，<ins>非常に高速に動く</ins>というものがあり，これを実現する概念として"仮想DOM"というものがある．この記事では，<ins>そもそも"DOM"とは何か</ins>，<ins>仮想DOMを利用しない従来の方法と仮想DOMを利用する方法の違い</ins>に触れながら，"仮想DOM"についてまとめる．

# DOMとは
DOMは"**Document Object Model**"の略で，仮想DOMに対して**リアルDOM**とも呼ばれる．
DOMは，HTML文書やXML文書などのドキュメントを<font color="green">木構造モデル</font>で表現し，プログラムから操作・利用することを可能にする仕組みである．
(通常のJavaScriptもHTMLの要素に対して，値を読み取ったり要素を増やすことができる．それはこの仕組みを利用して変更している．)

### DOMの木構造(ツリー構造)
DOMではドキュメントの各要素を抽出し，それを階層構造として扱うことで木構造モデルを表現する．この構造を<font color="green">ツリー構造</font>と呼び，抽出して各要素のことを<font color="skyBlue">ノード</font>と呼ぶ．

例えば以下のようなHTMLを記述したとする．
```HTML
<html>
<head>
    <title></title>
</head>
<body>
    <header></header>
    <main>
        <h1></h1>
        <p></p>
    </main>
    <footer></footer>
</body>
</html>
```
このように記述されているHTMLをブラウザは以下のような木構造モデルで扱う．
![tree_structure.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3133563/e3bae3d6-1fd2-3a52-653c-14ce5bc5bdf5.png)
ある特定のノードは他のノードと**親子関係**または**兄弟関係**になっている．
* 親子関係
html(親)↔︎head(子)，body(親)↔︎main(子)
* 兄弟関係
head↔︎body，header↔︎main↔︎footer

# 通常のレンダリング
Webアプリにおける「レンダリング」とは，指定したリソース(ここでいうHTMLファイルなど)をブラウザの画面に表示することで，従来のレンダリング方法としてDOMを利用している．

通常のレンダリングの流れ
１．HTMLからDOM木構造モデル，CSSからCSSOM木構造モデルを構築
２．DOMツリーとCSSOMツリーを利用して，画面表示に必要となるレンダリングツリーを生成する．
３．レンダリングツリーのレイアウト(レンダリングツリーが持つ各DOM要素の位置を決定)
４．実際に画面への描画処理を行う

:::note info
CSSOMは"CSS Object Model"の略で，DOMと似ていて，木構造モデルで表現できる．
:::

レンダリングには上記の4ステップが必要でかなり処理コストがかかる．JavaScriptによってHTMLに変更を加える場合は，さらにコストがかかってしまう．

# 仮想DOMとは
仮想DOMはリアルDOMの<ins>レンダリングコストが多くかかってしまう</ins>という問題を解決するために登場したものがで，その名の通りブラウザ上のDOMを抽象化した仮のDOMとして複製したものである．仮想DOMを利用する主な目的は，**効率的なUIの更新と再レンダリング**を実現することである．

# 仮想DOMを利用したレンダリング
仮想DOMを利用してレンダリングを行う場合，以下のような流れで行う．
１．HTMLから仮想的なDOM構造モデルを２つ構築する
２．JavaScriptによる操作を片方のモデルだけ行う
３．２つの仮想DOMを比較して，変更部分を探す
４．変更部分だけをリアルDOMに反映する
５．反映されたリアルDOMをブラウザがレンダリングする

![VDOMrendering.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3133563/f199552a-5f58-f08d-b482-b28324e95b10.png)

２つの仮想DOMのうち，片方だけJavaScriptの操作を行うことで操作前後のツリー構造モデルを作成することができる．この２つのツリー構造を比較することで，操作前後の**差分**を検出することができる．リアルDOMにはこの差分のみを反映すればよいので，再レンダリングをリアルDOMよりも低コストで行うことができる．

# まとめ
今回はReactの特徴の１つである"仮想DOM"についてまとめた．一般的には，リアルDOMよりも仮想DOMの方が高速にレンダリングができると言われているが，差分の検出も多くの処理が行われているため，差分が膨大になるとリアルDOMの方が高速にレンダリングできる場合がある．開発するアプリによって使い分ける必要がある．
NeptuneのBulk Loadでつまづいた件

# NeptuneのBulk Loadでつまづいた件（その1）

こんにちは。Ariaです。最近ルービックキューブにはまってます。（全然できない）

## 状況
Neptuneのbulk loadで`OUT_OF_MEMORY_ERROR`が出て困りました。

<dl>
    <dt>今回エラーが発生した手順</dt>
1.　Neptuneコンソール画面からノートブックを開く。

2.　Jupyterのセルで%loadコマンドを実行し、データを読み込みトライ。
3.　Load Failedと出たので、ターミナルから踏み台サーバにSSH接続し、以下コマンドでエラー内容を精査。
```
$ curl -X GET "https://your-neptune-endpoint:port/loader/{loaderId}?details=true&errors=true"
```
※エンドポイント、ポート、{loaderId}は適宜変更してくださいね
</dl>

(参考: Neptuneユーザーガイドより)
[Neptune DB インスタンスにデータをロードする](https://docs.aws.amazon.com/ja_jp/neptune/latest/userguide/bulk-load-data.html)
[Neptune Loader Get-Status errorLogs](https://docs.aws.amazon.com/ja_jp/neptune/latest/userguide/load-api-reference-error-logs-examples.html)
<br>

↓curlの出力結果
```
 (前略)

"errorLogs" : [
                {
                    "errorCode" : "OUT_OF_MEMORY_ERROR",
                    "errorMessage" : "Out of memory error. Resume load and try again.",
                    "fileName" : "s3://globi-neptune/full_data/edge/globi_interaction_edge_for_gremlin.csv",
                    "recordNum" : 0
                },

(略)
```

## 結論

上記結果のerrorMessageに"Resume load and try again"とある通り、**ノートブックで%loadコマンドを繰り返し実行した**。今回のケースの場合、3回目の%loadコマンド実行でLoad completedが表示され、データが全権取り込まれたことが確認できた。

```
Overall Status: LOAD_COMPLETED
Total execution time: 0:06:33
Done.
```

## 考察

+ （%loadコマンドが2回失敗したのは）NeptuneDBのクラスターの設定で、ケチって最大キャパシティーユニットを下げまくったのが原因かも。
+ loadの途中でエラーが出たことで、2回目のロードで重複が出ないか心配だったが、そこはNeptuneが賢くやってくれるようだった。

## 余談

データが全件取り込めたかどうかの確認は、次のgremlinクエリで簡単に確認できます。
```
%%gremlin
g.V().count()  // ノードの件数確認
g.E().count() // エッジの件数確認
```

Happy coding!
Git講習第3話「Gitのリポジトリ：プロジェクト管理の心臓部」

# この記事について
本記事は社内で実施したGit講習のスライドを元に作成された記事です。
Gitを使ってはいるものの、どういう構造になっているかとか仕組みについてはあまりわかっていないという方たちを対象にしています。
# 前回
https://qiita.com/sho_fcafe/items/1e9c4436e89d47fc4d1d
# イントロダクション
![スクリーンショット 2023-07-11 23.15.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/d6a38f9e-ed42-d7d7-7bf4-c2d3cae5a5f5.png)
Gitのインストールが完了した後輩ちゃんは先輩さんにリポジトリについて尋ねています。
今回はリポジトリについて詳しく見ていきましょう。
# リポジトリの種類
リポジトリにはローカルリポジトリとリモートリポジトリの２種類があります。
## ローカルリポジトリ
ユーザーの個々のコンピュータ上にあるリポジトリです。ここでは、ファイルの新規作成、編集、削除などの各種変更が行われます。
![スクリーンショット 2023-07-11 23.20.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/f8369fdf-d206-66d5-bafa-a42612d959e7.png)
## リモートリポジトリ
サーバー上に存在するリポジトリです。チームメンバーとコードを共有するために使われます。
![スクリーンショット 2023-07-11 23.22.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/5e3c1d4c-1ac5-cf41-1afb-3840b79ff1c4.png)
# 次回
第4話「Gitで作業開始：コミットからプルまで」へと続きます
https://qiita.com/sho_fcafe/items/68640ad3b90a99136bf0
Git講習第2話「Gitへの第一歩：準備とインストール」

# この記事について
本記事は社内で実施したGit講習のスライドを元に作成された記事です。
Gitを使ってはいるものの、どういう構造になっているかとか仕組みについてはあまりわかっていないという方たちを対象にしています。
# 前回
https://qiita.com/sho_fcafe/items/98f64d6cb352f380de50
# イントロダクション
![スクリーンショット 2023-07-11 22.26.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/f9b45688-4c9b-bfed-b64d-80fa7ee5750e.png)
Gitに興味を持った後輩ちゃん。今度はGitを使うための準備を先輩に教えてもらうようです。
# インストール
## macOSでコマンドを使ってインストールする
まずはGitがインストールされているか確認してみます。
下記のコマンドを実行してGitのバージョンが表示されない場合はインストールがされていません。
```bash
git --version
```
インストールがされていないようであればインストールをしましょう。
今回はhomebrewを使ってインストールをします。
### homebrewって？
macOS（またはLinux）用パッケージマネージャー。
パッケージマネージャーは、ソフトウェアのインストール、アップグレード、設定、削除といったプロセスを自動化し、管理するシステムのことです

homebrewもインストールされているか確認してみましょう。
下記のコマンドを実行してバージョンが表示されない場合はインストールがされていません。
```bash
brew -v
```
インストールがされていないようであればhomebrewをインストールします。
下記のコマンドを実行してください。
```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
これでhomebrewがインストールできたので、いよいよGitをインストールします。
下記のコマンドを実行してください。
```bash
brew install git
```
Gitがインストールされたことを確認するためにもう一度バージョン番号を確認するコマンドを実行してみます
```bash
git --version
```
私の環境では下記のように表示されました。
```
git version 2.37.0 (Apple Git-136)
```
これでGitのインストールが完了しました。
## SourceTreeでインストールをする
SourceTreeを使った場合のインストール方法も見てみましょう。
### SourceTreeとは
SourceTreeは、GitやMercurialなどのバージョン管理システムを視覚的に操作するためのクライアントツールです。SourceTreeはAtlassian社により開発され、ユーザーがコマンドラインを使用することなく、直感的にバージョン管理作業を行うことができます。

まずは下記からインストーラーを入手して実行してください
https://www.sourcetreeapp.com/
![スクリーンショット 2023-07-11 22.43.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/f5a63970-dfca-ea1c-c69c-1f5e8acb8e24.png)
![スクリーンショット 2023-07-11 22.44.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/d9bc6b1c-ba09-bad0-a558-8cac3ab51b1d.png)
これでインストール完了です。

# 次回
第3話「Gitのリポジトリ：プロジェクト管理の心臓部」へと続きます
https://qiita.com/sho_fcafe/items/20a7bc7c0e0922211bec
kaminariを利用したソート機能

今回はソート機能を作成しようと思い自分なりにまとめてみました

gemファイルに記載する

```
   gem 'kaminari'
```
bundle installは忘れず行いましょう

modelに追加します
```app/models/.rb
 scope :latest, -> {order(created_at: :desc)}  #新しい順に
     scope :old, -> {order(created_at: :asc)} #古い順に
 scope :star_count, -> {order(star: :desc)} #評価の多い順に
```

コントローラーに追加する

```controllers/games_controller.rb
 def index
    @books = Book.all
#ここから追加
  if params[:latest] #条件定義
      @books = Book.latest.page(params[:page]).per(10)
  elsif params[:old].present?
      @books=Book.old.page(params[:page]).per(10)
  elsif params[:star_count]
     @books = Book.star_count.page(params[:page]).per(10)
  else
      @games = Game.all.page(params[:page]).per(10)
  end
```
viewsの一覧ページに追加

```books/index.html.erb
 <h2>本のレビュー</h2>
///ここから追加
    <%= link_to '新しい順', books_path(latest: "true") %>
    <%= link_to '古い順', books_path(old: "true") %>
    <%= link_to '評価の高い順', books_path(star_count: "true") %>
```
７月のおすすめ本紹介「問いのデザイン」

月一でおすすめ本を紹介していくコーナー
今月は、こちら！

<img width="300" src="https://m.media-amazon.com/images/I/71SfZLI9fkL.jpg">

<a target="_blank" href="https://www.amazon.co.jp/dp/4761527439?&_encoding=UTF8&tag=osirukosan-22&linkCode=ur2&linkId=2e6c143fbf5ce74a08bb313bed9724a3&camp=247&creative=1211">問いのデザイン: 創造的対話のファシリテーション</a>


## 内容　出版社からのコメント
課題解決のためのチームの話し合いにおいて「良いアイデアが生まれない」「チームの一体感がない」と感じるとき、それはチームのメンバーやマネージャーの能力不足ではなく、チームで向き合っている「問い」がうまくデザインされていないからだ。
そもそも何を解決すべきなのか、「本当に解くべき課題」を正しく設定できなければ、その後、どんなにワークショップやファシリテーションの工夫を重ねても、根本的に解決の方向性がずれてしまい、関係者に「創造的な対話」は生まれない。
本書は、企業の商品開発・組織変革・人材育成などの複雑な課題解決の現場において、問題の本質を見抜き、解くべき課題を正しく設定し、関係者を巻き込み、課題解決のプロセスをデザインするための思考法・スキルについて体系化。
人とチームのポテンシャルを引き出し、組織や事業の創造性、イノベーションを促すための必読書。

## 感想

同じ状況、同じ課題を持っていても、「問いの設定」によって導かれる答えは変わってくる。
何かを思考する時、無意識に固定概念や関係性をいった要因によって思考が固定化されてしまう。
問いの形を変えることにより、この無意識に設定した固定化された状況を解し、想像的対話を対話を誘発することができる。

「問い」というシンプルな題の奥深さを知ることができました。
問いかけるか否かを悩むことはあっても、問いかけ方まで意識していない人は多く、
しっかりとした問いかけはその人の深さを表す指標にもなるように感じました。

私は社内の優秀なスクラムマスターの方からおすすめされて読みました！
読んでみて納得の良い本です。皆さんもぜひ読んでみてください！
pandas.DataFrame.loc(.iloc)でスライスを用いるときの注意点

# はじめに
pandas.DataFrame.loc(.iloc)で行の位置指定に用いるスライスは、通常のPythonのスライスと少し違うみたいです。公式ドキュメントにはもちろん書いてありますが、備忘録としてこの記事を書きました。
結論から言うと、行の位置指定のスライスでは、**左側(開始)と右側(終了)の両方の値を含む**範囲が指定されます。

# df.locとdf.ilocについて
pandasのdf.locまたはdf.ilocを用いると、任意の行、列の値を抽出することができます。
df.locでは行ラベルと列ラベルによる絞り込みを行い、
df.ilocでは行インデックス、列インデックスによる絞り込みを行います。
条件式とかも使えますが、ここでは触れません。

以下に例を示します。
```
# df.loc["行ラベル", "列ラベル"]
# df.iloc["行インデックス", "列インデックス"]

# DataFrame dfのnumber列とstring列を抽出する
# number列は左から1番目、string列は左から2番目の列とする

subset1 = df.loc[:, ["number", "string"]]
subset2 = df.loc[:, [0, 1]]
```

このように、df.locとdf.ilocではリストやスライスを用いて任意の行と列を抽出することができます。

# df.loc(df.iloc)でスライスを用いるときの注意点
列の位置指定にスライスを用いるときは、通常のPythonのスライスとして機能します。
しかし、行の位置指定にスライスを用いるときは、冒頭でも述べた通り**左側(開始)と右側(終了)の両方の値を含む**範囲が指定されます。

以下に、例を示します。
```
# DataFrame dfの1から3行目のnumber列とstring列を抽出する

subset1 = df.loc[0:2, ["number", "string"]]
subset2 = df.iloc[0:2, 0:2]
```

# 
雑な記事になってしまいましたが、以上です。
なぜ行と列でスライスの動き方が違うのかが気になるところなので、ご存じの方がもしいたら教えていただけるとありがたいです。
プロンプトエンジニアリング：テクニック早見表

# 目的

現状のプロンプトエンジニアリングの備忘録的なメモ。

# 早見表

| 手法 | 内容 | 例 |適用事例 |
|:-:|:-:|:-:|:-:|
|Zero-shot | 単なる質問  | 1+1は？  ||
|Few-shot  | 例を挙げて質問   | 1+1は2です。1+2は？  ||
|[Chain-of-Thought (CoT)](https://arxiv.org/abs/2201.11903)   | 質問と考え方と答えの例を挙げて質問、"Let's think step by step"で思考の過程を促す  |   |
|[Automatic Prompt Engineer (APE)](https://arxiv.org/abs/2211.01910)   |　CoTの派生、 "Let's think step by step"のような言葉を自動で探す。  |   |
|[Self-Consistency](https://arxiv.org/abs/2203.11171)   | CoTの派生、複数のCoTを使ってよいものをとる。 |   |
|[Generated Knowledge](https://arxiv.org/abs/2110.08387)    | Few-shotの派生、質問に対する例ではなく、知識や法則を挙げて質問  || LangChainのCSV AgentでCSVのヘッダーを質問文に組み込む  |
|[Tree of Thoughts (ToT)](https://arxiv.org/abs/2305.10601)   | 問題解決のための次のステップの生成とその実行  | | BabyAGIのTask Creation Agent  |
|[Retrieval Augmented Generation (RAG)](https://arxiv.org/abs/2005.11401) | 予め複数の知識を埋め込みベクタにしておき、質問された文から近い埋め込みベクタを探してきて、その文章と合わせて質問に回答する。  | | BabyAGIのContext Agent |
|[ReAct](https://arxiv.org/abs/2210.03629)   | 質問に対するタスクの実行に外部サービスを利用  | | LangChainのCSV AgentやBabyAGIのExecution Agent  |
|[Automatic Reasoning and Tool-use (ART)](https://arxiv.org/abs/2303.09014)  | ReActの派生  | |   |
|[Multimodal CoT](https://arxiv.org/abs/2302.00923)   | 画像を含めて質問（画像と質問文の埋め込みベクタを足すしてなんとかする）  | |   |

# 主要なテクニック

早見表からの主観的なまとめ？

* Promptに補足を入れる。例、考え方、答え方、法則や常識をPromptに入れる。
* 問題を分割して、問題を管理するPrompt（Agent）と小問題を答えるPrompt（Agent）を作る。
* 外部サービスとのインターフェースを作るようにPromptを作る。
* Promptを埋め込みベクタに変換して、他のPromptとの類似性を数値化して検索する。
* Prompt以外も埋め込みベクタに変換して、マルチモーダル化する。
* 複数のPromptのアンサンブル。

# プログラム的なテクニック

[LangChainにあるものから抜粋](https://langchain.com/features.html)

* Promptのテンプレートを作る。
* Promptの連鎖を作る。
* 大きなPromptを分割する。
* Promptの履歴、サマリー、Knowledge Graphを保存。
* デバッグ(Promptの詳細を出力。[Verbose=Trueとagent.agent.llm_chain.verbose=Trueをつける。](https://github.com/hwchase17/langchain/issues/912))

# 次の方向性

* 既存の手法のガイドラインの作成、どれを使うべきか？
* マルチモーダル化
* 評価メトリックスの作成
* データセットの構築
* 結果の説明、解釈、トレーサビリティ
* 問題領域に特化したドメイン適用

# 参考資料

* https://www.promptingguide.ai/jp
* https://python.langchain.com/docs/get_started/introduction.html
* https://github.com/yoheinakajima/babyagi
* https://blog.brainpad.co.jp/entry/2023/06/13/191635
【 React 】Recoilの使い方

最近Recoilの学習をし、useContextより簡単だと感じたため、備忘録も兼ねてまとめます。

# ステートの定義

ステートを定義する際は、`recoil`が提供する`atom`という関数を利用する。

<br>
<br>

**userState.js**
```react
import { atom } from "recoil";

export const userState = atom({
  key: "userState",
  default: { bool: true, name: "Hello" }
});
```

<br>

**key：** ステートを認識するための一意の値を設定

**default：** ステートの初期値

<br>
<br>

**グローバルステートの定義はこれだけでOK。**
useContextよりはるかに楽！！

<br>

# 状態管理の設定

Recoilで状態管理をできるようにするために、親コンポーネントを`RecoilRoot`というコンポーネントで囲う。
今回はApp.js全体で参照できるように、App.jsを囲む形で設定。

**App.js**
```react
import { createRoot } from "react-dom/client";
import { RecoilRoot } from "recoil";

import App from "./App";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
  <RecoilRoot>
    <App />
  </RecoilRoot>
);
```

<br>

# ステートの参照・受け渡し

定義したステートを参照するには、`useRecoilState`という関数を利用。
※今回はApp.js内ではこれらの値は使用しない。

```react
import "./styles.css";
import { useRecoilState } from "recoil";
import { userState } from "./store/userState";


export default function App() {
  // stateとセット関数の命名はこの時に行えば良い。
  const [state, setState] = useRecoilState(userState);

}
```

続いて、参照用のコンポーネントと更新用のコンポーネントを作成。

<br>

**参照用（Sample1.jsx）**

```react
import { useRecoilValue } from "recoil";
import { userState } from "./store/userState";

export const Sample1 = () => {
  const state = useRecoilValue(userState);

  console.log("Sample1 - 更新" + state.bool);

  return <p>{state.name}</p>;
};
```

この時、参照用ではステートの値だけ持って来れば良い。そこで利用するのは、`useRecoilValue`という関数。

<br>

**更新用（Sample2.jsx）**

```react
import { useSetRecoilState } from "recoil";
import { userState } from "./store/userState";

export const Sample2 = () => {
  const setState = useSetRecoilState(userState);

  const updateTrue = () => {
    setState({ bool: true, name: "Hello" });
  };

  const updateFalse = () => {
    setState({ bool: false, name: "Hello" });
  };
  console.log("Sample2 - 更新");

  return (
    <>
      <button onClick={updateTrue}>Trueに変更</button>
      <button onClick={updateFalse}>Falseに変更</button>
    </>
  );
};
```

この時、更新用ではステートを更新するセット関数だけを持って来れば良い。そこで利用するのは、`useSetRecoilState`という関数。

<br>

これらをApp.jsにインポートして確認してみる。
結果は以下の通り。


![スクリーンショット 2023-07-11 23.29.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/d70da78d-2112-c65a-d453-8a5330559082.png)


ここで試しにボタンをクリックし、ステートの値を更新してみる。

すると、コンソールの結果は以下の通り。
![スクリーンショット 2023-07-11 23.35.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/b421a5ca-1f11-542f-6c67-5f730e6df4e8.png)

すると見て分かる通り、コンポーネントの更新が`Sample1`しかされていないことが分かる。
これはRecoilの仕様であり、<font color="red">**更新関数のみを取得しているコンポーネントは、ステートが更新されても再レンダリングされない**</font>ようになっている。

**※注意点**
Sample2.jsxの親コンポーネント（今回でいうApp.js）が更新されれば、当然Sample２.jsxも更新されてしまう。
この場合はReact hooksの`memo`を利用して対策する必要がある。
Leetcode. 863. All Nodes Distance K in Binary Tree

https://leetcode.com/problems/all-nodes-distance-k-in-binary-tree/description/

## アプローチ
### DFS

```java
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    HashMap<TreeNode, TreeNode> hashMap;
    ArrayList<Integer> arrayList;
    HashSet<TreeNode> isVisited;

    public List<Integer> distanceK(TreeNode root, TreeNode target, int k) {
        arrayList = new ArrayList<>();
        isVisited = new HashSet<>();
        hashMap = new HashMap<>();
        createRoot(root);
        dfs(target, k);
        return arrayList;
    }

    public void createRoot(TreeNode root) {
        if (root.left != null) {
            hashMap.put(root.left, root);
            createRoot(root.left);
        }

        if (root.right != null) {
            hashMap.put(root.right, root);
            createRoot(root.right);
        }
    }

    public void dfs(TreeNode target, int k) {
        if (target == null || isVisited.contains(target)) {
            return;
        }

        if (k == 0) {
            arrayList.add(target.val);
            return;
        }

        isVisited.add(target);
        dfs(hashMap.get(target), k - 1);
        dfs(target.left, k - 1);
        dfs(target.right, k - 1);
    }
}
```
GraphQL初心者のためのバックエンド/フロントエンドのサンプルコード

そろそろGraphQLぐらい入れとくか…と思ったのですが、あれこれ作り込んだシステムに入れる時に意外と面倒というかどこから手をつければいいのかわからなかったというか**そもそもGraphQLってどういうものなのん？**　という状態でしたので、いったんシンプルな構成のサンプルを用意してみました。
似たようなことでお困りのかたがいらしたら参考になればと思います。

ちなみに基本のやり方をChatGPTに作ってもらった結果、バックエンドはExpress、フロントエンドはReactになりました。
Docker上で動くようになっています。

※Docker化と諸々の微調整については自分でやりました。

https://github.com/robitan/graphql-sample


# コードの解説
## バックエンド側について

バックエンドのベースはExpressです。ExpressのGraphQLプラグインを使用しています。

フィールドを増やすには、 `buildSchema` と `root` の内容をそれぞれ修正します。

GraphQLそのものとはまったく関係ないところですが、フロントエンドとバックエンドを動かすポートが異なるため、バックエンド側にCORSの設定を入れる必要があるという点が要注意ポイントです。

```js:backend/server.js
const express = require('express');
const cors = require('cors');
const { graphqlHTTP } = require('express-graphql');
const { buildSchema } = require('graphql');

// Construct a schema, using GraphQL schema language
const schema = buildSchema(`
  type Query {
    hello: String
    hello2: String
  }
`);

// The root provides a resolver function for each API endpoint
const root = {
  hello: () => 'Hello, GraphQL!',
  hello2: () => 'Hello2, GraphQL!',
};

const app = express();

app.use(cors());
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true, // Enable GraphiQL for testing the API in the browser
}));

app.listen(3000, () => {
  console.log('GraphQL server running at http://localhost:3000/graphql');
});
```

## フロントエンド側について

フロントエンドのベースはReactです。GraphQLクライアントとしては一番有名なApolloが使われています。


バックエンド側で提供しているスキーマには `hello` と `hello2` いう名前のフィールドがありますが、フロントエンド側からは `hello` フィールドだけを取りに行かせています。

```react:frontend/src/App.js
import React from 'react';
import { ApolloClient, InMemoryCache, ApolloProvider, useQuery, gql } from '@apollo/client';

const client = new ApolloClient({
  uri: 'http://localhost:3001/graphql', // Replace with your server URL
  cache: new InMemoryCache()
});

const GET_HELLO = gql`
  query {
    hello
  }
`;

function App() {
  const { loading, error, data } = useQuery(GET_HELLO);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>[Error] {error.toString()}</p>;

  return (
    <div>
      <h1>{data.hello}</h1>
    </div>
  );
}

function AppWrapper() {
  return (
    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>
  );
}

export default AppWrapper;
```

### 補足：フロントエンド側のGraphQLクライアントライブラリについて

GraphQLのクライアント側といえばApolloしか知らなかったので不安になっていちおう調べたのですが、個人的に最近の流行りを掴むならとりあえずココ、と考えている以下のサイトでもApolloが推されていましたので、現段階での一番初めの選択肢としてはやはりApolloということで間違いはないようです。

https://roadmap.sh/frontend

![スクリーンショット 2023-07-11 22.52.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210824/8fd10715-b5b5-9635-124f-d28bdaed5130.png)


ちなみにGraphQL関連**だけ**のロードマップもありました。

https://roadmap.sh/graphql

このあたりは本当に追いかけ始めるとキリがないですね…。
Deck.GLでPlateauの3DTilesを読み込んで建物をクリックして属性を表示したかった

## はじめに
タイトルどおりのことがやりたくて色々と試していたので記したいと思います

結論から言うと、現時点で3DTilesの地物に対してクリックはできるものの、属性値は簡単には取れませんでした
取れそうで、取れていないという状況です
おそらく現時点では難しいのかと思われます

## Deck.GLの実装
まず、属性値を取得するためのDeck.GL側の実装を用意しておきます
利用するレイヤーはTile3DLayer

https://deck.gl/docs/api-reference/geo-layers/tile-3d-layer

以下のようにpickableをtrueにしてあげる必要があります
※pickableがtrueだとエラーになるタイル（例えばGoogleのPhotorealistic 3D Tiles）があるので、このあたりは実装に注意が必要と思われますが、今回はPLATEAUのタイルを使うため、常にtrueを指定します

```javascript
const PLATEAU_TILE = 'https://s3-ap-northeast-1.amazonaws.com/3dimension.jp/13000_tokyo-egm96/13101_chiyoda-ku_notexture/tileset.json';
new Tile3DLayer({
    id: '3d-tiles-click-test',
    data: PLATEAU_TILE,           
    pickable: true,
    onClick: async info => {
        console.log(info);
    }
})
```

PLATEAUの3DTilesのデータは以下を参照しました

https://github.com/Project-PLATEAU/plateau-streaming-tutorial/blob/main/3d-tiles/plateau-3dtiles-streaming.md

## 一旦の結論
3DTilesの情報やGLTFの情報は取れるのですが、肝心の「クリックされた建物のデータ」がわかりません
3DTilesの情報は配列になって入っているので、配列のindexが分かれば…とも思ったのですが、ダメそうですね

CesiumJSでは取得出来るので、何が違うのか深く調べればわかるかもしれないのですが、一旦仕切り直したいと思います

今は属性表示用にベクトルタイルに変換して、透明にして重ねておくのが良いかもなあ…と思っています

ということで、現時点では無理そう
という結論になりました

何かご存じの方が居れば情報をいただけると大変助かります
なぜJavaScriptではなくTypeScriptを使うべきか？

## きっかけ
インターンシップ選考の面接のとき、面接官の方にJavaScriptをTypeScriptを使うメリットを教えてくださいという質問がありました。自分は今までモダンな技術を「みんな使っているから」という単純な理由で使用していた節があるため、その面接では思うような答えを出せませんでした...
そのため今後のために自分がなぜその技術を使うのかという理由づけをするために情報をまとめてみることにしました。
本記事では、なぜJavaScriptではなくTypeScriptを選ぶべきなのか、そのメリットについて詳しく解説します。また、サンプルコードを交えて具体的な使用例も紹介したいと考えています。
###  1. 静的型付けによるコード品質向上
JavaScriptは動的型付けの言語であり、コンパイル時に型チェックが行われないため、実行時にエラーが発生する可能性があります。(JavaScriptは実行時にデータ型を決める動的型付け:実行するまでエラーの存在に気付きにくく、バグが発生しやすい問題点を持っている)<br> その一方、TypeScriptではあらかじめ型を定義する静的型付けが使用されており、コンパイル時に型エラーを検出することができます。これにより、開発者はコードの品質を向上させることができます。以下に、TypeScriptの静的型付けの例を示します。
```ts:TypeScript
function add(a: number, b: number): number {
  return a + b;
}

console.log(add(5, "10"));  // コンパイルエラー: 型が不一致です
```

上記の例では、add関数に数値型の引数を渡していますが、誤って文字列型の値を渡しているため、TypeScriptのコンパイラはエラーを検出します。

### 2. IDEのサポート
TypeScriptは、静的型付けに基づく情報を活用して開発環境（IDE）が補完機能や自動修正機能を提供しています。IDEはコードの自動補完や型チェックなどの支援機能を提供するため、開発者はより効率的にコードを記述することができます。例えば、以下のコードを見てください。
```ts:TypeScript
const message: string = "Hello, TypeScript!";
console.log(mesage);  // コンパイルエラー: 変数が存在しません
```
上記の例では、変数名を誤って"mesage"と書いていますが、IDEは正しい変数名を補完してくれるため、タイプミスに気付きやすくなります。
### 3. 大規模プロジェクトでの保守性向上
TypeScriptは、型安全性の向上とコードのドキュメンテーション効果により、大規模なプロジェクトの保守性を高めます。静的型付けにより、コードの一部を変更した際に関連する他のコードへの影響を容易に把握できます。また、TypeScriptはJSDocコメントをサポートしており、関数やクラスのパラメータ、戻り値の型情報を明示的に記述することができます。
```ts:TypeScript
/**
 * ユーザー情報を取得する関数
 * @param {number} id - ユーザーID
 * @returns {Promise<User>} - ユーザーオブジェクトのPromise
 */
async function getUser(id: number): Promise<User> {
  // ユーザー情報を取得する処理
}

// 別の場所で関数を呼び出す
getUser(1).then((user) => {
  console.log(user.name);
});
```
上記の例では、getUser関数のパラメータや戻り値の型情報がJSDocコメントで明示されています。これにより、開発者は関数の意図や使用方法を把握しやすくなります。

# まとめ
本記事では、JavaScriptではなくTypeScriptを選ぶメリットについて解説しました。TypeScriptの静的型付けによるコード品質の向上、IDEのサポートによる効率的な開発、そして大規模プロジェクトでの保守性の向上が主なメリットです。これらの要素は、開発者がより堅牢で品質の高いコードを書くために不可欠な要素となります。TypeScriptの採用は、Web開発の現場でますます重要な位置を占めています。
今後はなぜその技術を使うのかをよく考えて使用するべきだと感じています。
固定長の配列を初期化する

# 概要

固定長の配列を初期化する

# 方法

`Array.new`を使う


## sample


```ruby
Array.new(5)
=> [nil, nil, nil, nil, nil]
```

初期値の設定
```ruby
# 第二引数に設定
Array.new(5, 0)
=> [0, 0, 0, 0, 0]

# block でも可
Array.new(3){ "foo" }
=> ["foo", "foo", "foo"]
```

2重配列
```ruby
# blockを応用して2重配列
Array.new(3){ Array.new(2) }
=> [[nil, nil], [nil, nil], [nil, nil]]
```


# 最後に

rubyだとあまり使わないだろうけれど、、、
`new`での初期化を覚えておくといざというときに便利かもしれない



# 追記

初期化した際のオブジェクト周りについて興味深いコメント頂いたので追加で調べて追記


引数で初期化する場合、オブジェクトが共通になっている
```ruby
arr = Array.new(5, [])
=> [[], [], [], [], []]

# オブジェクトに破壊的な変更を加えてみる
arr[0].push 1

arr
=> [[1], [1], [1], [1], [1]] # オブジェクトを共有しているのですべて変わる

# 一応は、破壊的な変更ではなく別のオブジェクトに差し替えれば変更の範囲を制限できる
arr[0] = [2]

arr
=> [[2], [1], [1], [1], [1]]

````

ブロックで初期化する場合は、別のオブジェクトになる
```ruby
 arr = Array.new(5){ [] }
=> [[], [], [], [], []]

arr[0].push 1

arr
=> [[1], [], [], [], []] # 変更したものだけ
```


配列を与えて初期化した場合は、オブジェクトが共通
```ruby
a = [[], [], []]
b = Array.new(a)
=> [[], [], []]

a[0].push 1 # aを変更すると

a
=> [[1], [], []]
b
=> [[1], [], []] # bも変わる
```

こういった挙動の差異はしっかり拾っていきたいところ
４ステップでLaravelで作ったウェブサイトをさくらサーバーで公開する

## 前提条件
* /home/\<User\>/wwwディレクトリが公開ディレクトリとする
    * つまり、https://\<User\>.sakura.ne.jp/を叩くと/home/\<User\>/www以下にアクセスできる
* /home/\<User\>/\<Project\>にLaravelのプロジェクトディレクトリをおく
* https://\<User\>.sakura.ne.jp/\<Project\>/を叩くとプロジェクトのサイトにアクセスできるようにする

## 方法
* さくらサーバーにアクセスする
```
$ ssh <User>@<User>.sakura.ne.jp
```

* Composerをインストールする
```
$ curl -sS https://getcomposer.org/installer | php
```

* Laravelのプロジェクトを立ち上げる
```
php composer.phar create-project laravel/laravel <Project>
```

* Laravelのpublicディレクトリのシンボリックリンクをwww直下に作成する
```
$ ln -s /home/<User>/<Project>/public /home/<User>/www/<Project>
```
簡単なQR作成サイト

# 簡単なQR作成サイト

こんにちは、みんな。 私はreactjs、nextjsを学習している初心者です。 そこで簡単にqrコードを生成してくれるサイトを試してみました。 皆さんも試してみてフィードバックをいただければ幸いです。

サイトのリンク：
https://kantan-qr.info/
GASで業務を自動化した話

# この記事のテーマ

この記事ではスプレッドシートとGASを利用して業務の自動化・効率化を行なった実例を紹介します。同じような業務で時短について悩んでいる方の参考になれば幸いです。

# 自動化した業務内容

調査対象のドメインのリストがあり、すべてのサイトを確認して以下の情報を表にまとめるという業務です。

- サイトタイトル
- サイトタイトルの日本語含有率
- ドメインにアクセスした時のレスポンスコード
- サイトの運営開始年

自動化することで、調査対象のドメイン1,000件に対して、1日１回上記の作業を毎日行えるようにするのが目的でした。

## 手作業で行なった場合の業務手順

1. ドメインにアクセスする
2. サイトタイトルをスプシにコピペする
3. サイトタイトルの日本語含有率を文字数の割合から概算する
4. chromeの開発者ツールからレスポンスコードを確認する
5. Wayback Machineでサイトの運用開始年を検索する

# 自動化する

それぞれの手順の自動化をGASのみで行いました。
利用した技術的要素は以下のようになります。

**スプレッドシートとGASの連携**

- SpreadsheetApp
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app?hl=ja

**GASでサイトデータを取得**

- UrlFetchApp
https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app?hl=ja

**GASでスクレイピング**

- Parser

以下のライブラリIDで検索したもの。（バージョン８を利用）
```
1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw
```
解説サイトがいくつかありましたが出所が不明でした。
「GAS スクレイピング」でググったら出てきたものです。

**サイトの運用開始年を検索**

- Wayback Machine API
https://archive.org/help/wayback_api.php

## 手順１：スプシから値を取得

A列のデータをすべて取得する処理です。
A列にドメインを入力しておくことで、ドメインのリストを取得できます。

```js
SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange("A1:A").getValues();
```

## 手順２：サイトデータを取得

curlのように、サイトに対してリクエストをする処理が１行で書けます。
事前にライブラリなどをインストールする必要もないのでGoogle様さまです。

```js
var response = UrlFetchApp.fetch(url)
```

## 手順３：スクレイピング

Parserライブラリをはじめは使っていたのですが、出所が不明な点、レスポンスデータの中から特定の文字列を切り出すだけの処理だった点から、自前で関数を作成しました。
（自前と言いつつ、ChatGPTさんです、、）

```js
function extractString(text, left, right) {
  var startIndex = text.indexOf(left);
  if (startIndex === -1) {
    return "";
  }
  startIndex += left.length;
  var endIndex = text.indexOf(right, startIndex);
  if (endIndex === -1) {
    return "";
  }
  return text.substring(startIndex, endIndex);
}
```

## 手順4：運営開始年を取得

Wayback Machineというサービスを利用します。


```js
var url = 'http://archive.org/wayback/available?timestamp=1990&url=' + domain
var response = fetch(url)
if(!response) {
  return ''
}
var contentText = JSON.parse(response.getContentText())
var startTimestamp = contentText.archived_snapshots.closest.timestamp
return startTimestamp.substr(0, 4)
```

## 手順５：スプシに出力する

セルを指定して値を引数に渡しています。

```js
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
sheet.getRange(cell).setValue(value);
```

以上です。
無料で効率的に開発ができてしまう、、GAS恐るべしでした。
Git講習第1話「競合から救済：Gitの力」

# この記事について
本記事は社内で実施したGit講習のスライドを元に作成された記事です。
Gitを使ってはいるものの、どういう構造になっているかとか仕組みについてはあまりわかっていないという方たちを対象にしています。

# イントロダクション
![スクリーンショット 2023-07-11 22.06.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/d6c4fffa-bd60-9fb0-9c14-5bf1f7a557af.png)
![スクリーンショット 2023-07-11 22.06.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/a87bc61f-168c-818c-1c8d-97bd0fbf21e9.png)
ファイル管理で悩んでいる後輩ちゃんが先輩に何か良い方法がないか尋ねたところ、Gitを使うといいよと教えてくれました。
ということで、初回の今回はGitってそもそも何？ということについて学びたいと思います。

# Gitとは
Gitは、バージョン管理システムと呼ばれるシステムの１種です。
バージョン管理システムは、チーム開発を行う時にチームメンバーが並行して作業を行い、それらを統合する手段を提供することで効率よくチーム開発が行えるようにするためのシステムです。
![スクリーンショット 2023-07-11 22.13.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/3b3f54f6-5185-7e9c-4b27-29b25a25b8d6.png)
https://git-scm.com/

## バージョン管理システムとは
バージョン管理システム（VCS）は、一連のファイルの変更履歴を記録・追跡するためのツールです。これは特にソフトウェア開発において重要で、開発者が以前のバージョンに戻したり、何が変わったかを確認したり、複数人での作業を協調することを容易にします。

主要なVCSには2種類があります。一つ目は中央集権型（例：Subversion）で、全ての変更が一つの中央リポジトリで管理されます。二つ目は分散型（例：Git）で、各ユーザーが完全なリポジトリのコピーを持ち、独立して作業できます。

# GitHub
GitHubはWebサービスで、Gitのリモートリポジトリを保存、共有、公開する場所を提供します。
それに加えて、GitHubは、コードレビュー、プロジェクト管理、バグトラッキングなど、コラボレーション機能も提供しています。
つまり、GitHubはGitを基盤とし、それを拡張したものと言えます。
Gitを基盤としたWebサービスにはGitHubの他に下記のようなサービスがあります。

GitLab
https://about.gitlab.com/

BitBucket
https://bitbucket.org/

Backlog
https://backlog.com/

# 次回
第2話「Gitへの第一歩：準備とインストール」へと続きます
https://qiita.com/sho_fcafe/items/1e9c4436e89d47fc4d1d
パスを繋げたいだけなのに…E325: ATTENTION

Mysqlを使いたい。ターミナルで使いたい。
けど、毎度`cd /Applications/MAMP/Library/bin`
で移動して、`./mysql -u root -p`で起動するのは面倒だ。
ショートカットしたい。ってことでパスを繋ぐことにした。

`vi .bash_profile`で編集じゃ！おや…

したらこれだ↓
```
terminal
E325: ATTENTION
Found a swap file by the name ".bash_profile.swp"
          owned by: なまえ   dated: 金  2 12 09:50:53 2021
         file name: ~なまえ/.bash_profile
          modified: YES
         user name: なまえ host name: pcのなまえ-MacBook-Air.local
        process ID: 31215
While opening file ".bash_profile"
             dated: 金  7 07 00:04:05 2023
      NEWER than swap file!

(1) Another program may be editing the same file.  If this is the case,
    be careful not to end up with two different instances of the same
    file when making changes.  Quit, or continue with caution.
(2) An edit session for this file crashed.
    If this is the case, use ":recover" or "vim -r .bash_profile"
    to recover the changes (see ":help recovery").
    If you did this already, delete the swap file ".bash_profile.swp"
    to avoid this message.

Swap file ".bash_profile.swp" already exists!
[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort: 

```

ざっくり言ってしまうと、`.bash_profile`が以前の編集途中で強制終了したか何かでその途中のが残っとるよー！というものらしい。
そんで編集するかい？消すかい？などのいろいろオプションがでてきたのである。

そんな強制終了なんてターミナルさんに冷たいことをした覚えは記憶はないのだが、注意されてるのでやってしまったのでしょう泣

そんなわけで修正開始。
初めてすぎてなんのこっちゃ？な問題なのでrecoverオプションを選択でどんなものか見てみた。

```
terminal
Swap file ".bash_profile.swp" already exists!
".bash_profile" 2L, 41B
Using swap file ".bash_profile.swp"
Original file "~/.bash_profile"
E308: Warning: Original file may have been changed
Recovery completed. You should check if everything is OK.
(You might want to write out this file under another name
and run diff with the original file to check for changes)
You may want to delete the .swp file now.


Press ENTER or type command to continue
```

このような文言が出てきて、これらはおそらくrecover完了しましたというものだろう。

```
vim
export PATH="~/.rbenv/shims:/usr/local/bin:$PATH"
eval "$(rbenv init -)"
$ source ~/.bash_profile
~                                            中略
:wq    
```

enterでvimに入る。みた感じ特に修正することはなさそうなので`:wq`そのまま保存っと！

```
export PATH="~/.rbenv/shims:/usr/local/bin:$PATH"
eval "$(rbenv init -)"
$ source ~/.bash_profile
~                                            中略 
E45: 'readonly' option is set (add ! to override)
```

これまたなんおこっちゃな文言が…
`E45: 'readonly' option is set (add ! to override)`

これは権限がどうたこうたらで、保存するには`！`をつけて強制上書きしてね！ってことになった。ってことで`:wq!`で実行。

すると保存はできたらしい。再度パス繋ぐぞということで、`vi .bash_profile`を実行。

```
E325: ATTENTION
Found a swap file by the name ".bash_profile.swp"
中略
```

またかよ！！！

いろいろ調べた結果、
`Swap file ".bash_profile.swp" already exists!`ここが問題らしい。

`ls -la`で編集履歴の参照

`-rw-r--r--   1 なまえ  staff  12288  2 12  2021 .bash_profile.swp`見つけた！

`rm .bash_profile.swp`こいつで削除。

このあと`vi .bash_profile`で入ってみると、できたー。
`exit`でターミナル落として再起動したあと、パスが通せてました。


まとめ
`.bash_profile.swp`なるものは以前の操作で何かしら強制終了したため、バックアップとして編成されたファイルになる。
`.swp`を削除しないとファイルの編集に繋げられない。

いやー、一歩間違えると散々な目に遭いそうでターミナル怖い。笑
初めての記事でもっと怖い。笑




引用元
https://ysklog.net/server/1349.html
https://www.linuxmaster.jp/linux_blog/2020/01/vivimreadonly.html
https://qiita.com/hiroyukiwk/items/01d7f7ada20adffe5c74
【Next.js】ページの変更ごとに処理する方法【AppRouter】

AppRouterでは`router.events`はサポートされていません。

以下の方法でページの変更ごとに処理を行うことができます。

```js:app/_components/navigation-events.js
'use client'
 
import { useEffect } from 'react'
import { usePathname, useSearchParams } from 'next/navigation'
 
export function NavigationEvents() {
  const pathname = usePathname()
  const searchParams = useSearchParams()
 
  useEffect(() => {
    const url = `${pathname}?${searchParams}`
    console.log(url)
    // URLが変更された際に実行される処理
  }, [pathname, searchParams])
 
  return null
}

```

上記を`layout.js`に記述します。

```js:app/layout.js
import { Suspense } from 'react'
import { NavigationEvents } from './components/navigation-events'
 
export default function Layout({ children }) {
  return (
    <html lang="en">
      <body>
        {children}
 
        <Suspense fallback={null}>
          <NavigationEvents />
        </Suspense>
      </body>
    </html>
  )
}
```
【Laravel】DBから取得したbooleanをtrue/falseに変換する$casts

テーブルのカラムの型をboolean(true/false)で定義しているとします。
登録されているレコードの値を取得すると、以下のように0か1で返ってきます。
※DBはMySQL

```php
$post = Post::first()
$post->is_draft // => 1 or 0
```

取得した値を基に条件分岐させたい場合、
一々、0をfalseに、1をtrueに変換させる処理が必要になります。
この処理を都度追加するのは正直だるいですね。
これを解決してくれるのが **$casts** になります。

使い方は対象のモデル内で$castsを以下のように定義して、型を指定してやるだけです。

```php
protected $casts = [
    'is_draft' => 'boolean',
];
```

これだけで自動的にbooleanに変換してくれます。
冒頭で説明した同じコードを実行した場合、出力結果がちゃんとbooleanに変換されるようになりました。

```php
$post = Post::first()
$post->is_draft // => true or false
```

上記はbooleanに変換していますが、
指定する型を変えれば、カラムの型によらず変換してくれるようになります。


### 参考

https://readouble.com/laravel/10.x/ja/eloquent-mutators.html

https://rapicro.com/laravel_cast_boolean/?utm_source=pocket_saves
【SwiftUI】ヘルプテキストを表示する方法

# はじめに
macアプリには、カーソルを合わせるとヘルプテキストが表示する機能があります。この記事では、これを実現させるhelpの使い方を紹介します。

# やり方
1. helpを表示したいViewにhelp(_:)を追加
2. help(_:)の引数にhelpの内容を記述

```swift
struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .padding()
            .help("Hello, world!")
    }
}
```

# おわりに
テキストにカーソルを合わせてしばらくすると、helpの内容が表示されることが確認できます。この記事が参考になったという方は、いいねとフォローしていただけると嬉しいです😆

# 関連リンク
https://developer.apple.com/documentation/swiftui/view/help(_:)-4y7cy
配列を特定数ずつに区切る

# 概要

配列を特定の数ずつに分割したい

環境：Ruby 3.2


# 方法

each_sliceってのがあった。


## sample
```ruby
# 中身を確認
(1..10).each_slice(3) {|a| p a}
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
[10]

# 配列にして分割されているか確認
(1..10).each_slice(3).to_a
=> [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

# 返却はEnumerator
(1..10).each_slice(3).class
=> Enumerator


```
M5Atom でクリックを検知する

## 本記事について

M5AtomLite, M5AtomS3でのボタンクリックイベントの使い方をまとめる

## 前提

https://qiita.com/Teach/items/b076ea85aad8c4edae84

## 資料

[M5Unifiedへの移植のポイント ボタンについて](https://docs.m5stack.com/ja/quick_start/m5unified/migration#%E3%83%9C%E3%82%BF%E3%83%B3%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)

ここに乗ってる。

M5AtomについているボタンはBtnAとして扱われる。(M5AtomS3の場合には画面がそのままボタンになってて押せる)

https://docs.m5stack.com/ja/api/m5unified/m5unified_appendix#%E3%83%9C%E3%82%BF%E3%83%B3%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

## M5AtomLite　での実装サンプル

```main.cpp
#include <M5Unified.h>

void setup()
{
  auto cfg = M5.config();
  M5.begin(cfg);

  Serial.println("Start App");
}

void loop()
{
  M5.update(); // update button state

  if (M5.BtnA.wasClicked())
  {
    Serial.println("Button A was clicked");
  }
}

```

`M5.update()`でボタン状態を更新する必要がある。

クリック = 押して離した時。

## M5AtomS3 での実装サンプル

![IMG_5483.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/bd788e9e-03b2-c81a-706c-b1454e790a35.jpeg)

ボタンを押したら1ずつ COUNT を増やしていくプログラム

```main.cpp
#include <M5Unified.h>

uint32_t count;
bool redraw = false; // 再描画フラグ

void onClickBtnA()
{
  count++;
  redraw = true;
}

void setup()
{
  auto cfg = M5.config();
  M5.begin(cfg);
  USBSerial.begin(115200);
  M5.Display.setTextSize(2);
  USBSerial.println("Start App");
  count = 0;
  redraw = true;
}

void loop()
{
  M5.update();

  if (M5.BtnA.wasClicked())
  {
    onClickBtnA();
  }

  if (!redraw)
  {
    return;
  }

  M5.Display.setCursor(0, 0);
  M5.Display.printf("COUNT: %d\n", count);
  USBSerial.printf("COUNT: %d\n", count);
  redraw = false;
}

```

ポイントは　`onClickBtnA()` 内で `M5.Display` を使わず再描画フラグを立てるだけにしているところ。
これによって描画内容とボタンを押した時のロジックを分離することができる。
Script DebuggingでVisual StudioのデバッガーからUnityアプリにアタッチできるようにする


## デバッグ -> プロセスのアタッチ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1771055/4d01ad29-13ac-31b8-b96c-2b118c84dd6c.png)

## 検索 -> アタッチ

![スクリーンショット 2023-07-11 212604.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1771055/bf25babe-58c0-dd62-7264-a22f5035e2db.png)
【Java】JavaScriptファイルの最適化を助けるClosure Compiler Maven Pluginの設定ガイド【Maven】

JavaのWeb開発でJavaScriptの部分も担当している皆さん、こんにちは。今日は、JavaScriptファイルの結合や最小化を行うためのツール、Closure Compiler Maven Pluginの設定方法について解説します。この記事は、Mavenを使用してWeb開発を行っている方々、特にビルドプロセスの最適化に興味がある方々に向けて書いています。

# Closure Compiler Maven Pluginとは

過去にはminify-maven-pluginやyui-compressor-pluginといったツールがありましたが、これらの更新はすでに停止しており、最近の環境ではエラーが発生しています。これに対し、Closure Compiler Maven PluginはGoogleのClosure Compilerを使用してJavaScriptファイルを処理するために設計されており、JavaScriptファイルのビルドプロセスをより効率的に行うことが可能です。

https://blutorange.github.io/closure-compiler-maven-plugin/

# 出力ファイル名のカスタマイズ

このプラグインのデフォルトの設定では、出力ファイルの名前は元のファイル名に ".min" が追加されます。しかし、出力ファイル名に ".min" を追加せずに元のファイル名を保持したい場合がありますよね。そのための設定方法を解説します。

まず、`outputFilename` の設定を "#{path}/#{basename}.#{extension}" に変更します。これにより、出力ファイルの名前は元のファイル名と同じになります。以下に、その設定例を示します。

```xml:pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<build>
    <plugins>
        <plugin>
            <groupId>com.github.blutorange</groupId>
            <artifactId>closure-compiler-maven-plugin</artifactId>
            <version>2.25.0</version>
            <configuration>
                <!-- Base configuration for all executions (bundles) -->
                <baseSourceDir>${project.basedir}/src/main/resources</baseSourceDir>
                <baseTargetDir>${project.build.directory}/classes</baseTargetDir>
            </configuration>
            <executions>
                <!-- Process all files in the "includes" directory individually-->
                <execution>
                    <id>default-minify</id>
                    <configuration>
                        <encoding>UTF-8</encoding>
                        <sourceDir>static/app</sourceDir>
                        <targetDir>static/app</targetDir>
                        <includes>
                            <include>**/*.js</include>
                        </includes>
                        <excludes>
                            <exclude>**/*.min.js</exclude>
                        </excludes>
                        <skipMerge>true</skipMerge>
                        <closureEmitUseStrict>false</closureEmitUseStrict>
                        <closureLanguageOut>STABLE</closureLanguageOut>
                        <outputFilename>#{path}/#{basename}.#{extension}</outputFilename>
                    </configuration>
                    <goals>
                        <goal>minify</goal>
                    </goals>
                    <phase>generate-resources</phase>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
```

この設定は `skipMerge` が `true` に設定されている場合（つまり、各ファイルが個別に処理される場合）のみ有効です。`skipMerge` が `false` に設定されている場合（つまり、すべてのソースファイルが一つの大きなファイルにマージされる場合）は、`outputFilename` は固定の名前を指定する必要があります。

# まとめ

以上が、Closure Compiler Maven Pluginの紹介と出力ファイル名のカスタマイズ方法についてのガイドです。この設定を活用して、JavaScriptファイルの結合と最小化をより効率的に行いましょう。JavaScriptの開発を行っている皆さんの開発効率が上がることを願っています。
PowerShellで環境変数を取り扱う（現在のコンソール）

PowerShellで環境変数を取り扱う場合のメモ

## ドキュメント

[about_Environment_Variables](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_environment_variables)

公式ドキュメントに環境変数についての資料が用意されており、ここを確認すればOK。

## 環境変数を参照する

[環境変数の構文](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_environment_variables?#using-the-variable-syntax)

PowerShellで環境変数にアクセスするには下記の記述でアクセスできます。

```powershell
$Env:<variable-name>
```

下記は環境変数PATHを表示してみた例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/f49cf607-614e-a910-9b65-88c8e4dcfa66.png)

ちなみに環境変数PATHはセミコロン（;）で区切られて連続しているので見づらいかと思うので、
下記のようにセミコロンでsplitして表示すると人間には見やすいと思います。

```powershell
$env:PATH -split ";"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/e83756ca-ce8f-8147-c650-3a94cc8e8327.png)

## 環境変数を作成・更新する（現在のコンソール）

```powershell
$Env:<variable-name> = "<new-value>"
```

参照する際は`$Env:<variable-name>`ででアクセスできましたが、`= "<new-value>"`で新しい環境変数を作成できます


下記は環境変数Fooに値Barを設定して生成し、値HelloWorldに更新したケース

```PowerShell
$Env:Foo = "Bar"

$Env:Foo

$Env:Foo = "HelloWorld"

$Env:Foo
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/1c875bd9-fb86-8277-9755-b1a869fba6ee.png)

## 環境変数を削除する（現在のコンソール）

環境変数は空の文字列を設定できないため、$null　または　空の文字列設定すると環境変数は削除されます。

```powershell
# 空文字を設定するパターン
$Env:<variable-name> = ""

# $nullを設定するパターン
$Env:<variable-name> = $null
```

下記は環境変数Fooを生成して、Get-Memberコマンドレットで環境変数が生成されている事を確認した後に、空文字を環境変数Fooに渡して環境変数を削除。

その状態で、Get-Memberコマンドレットを実行して、環境変数Fooが削除された事を確認している。
（環境変数Fooが削除されているので、Get-Memberコマンドレットで存在しないオブジェクトを指定した状態になってエラーになっている）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/359ef9c1-85c9-0106-473e-4c7ade15da4d.png)

## Itemコマンドレットを使用しても環境変数は更新できる（現在のコンソール）

[環境プロバイダーと Item コマンドレットの使用](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_environment_variables?#using-the-environment-provider-and-item-cmdlets)

`$Env:<variable-name>`で環境変数の操作をしてきましたが。

下記のようにItemコマンドレットを利用して、それぞれ環境変数を操作できます。

- Get-Item で環境変数へアクセス
- New-Item , Set-Item で環境変数の生成
- Remove-Item で環境変数の削除


```powershell
New-Item -Path Env:\Foo -Value 'Bar'

Get-Item -Path Env:\Foo

Get-Item -Path Env:\Foo | Get-Member -MemberType Properties

Remove-Item -Path Env:\Foo

Get-Item -Path Env:\Foo | Get-Member -MemberType Properties
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/82650d0a-0d2d-218e-b941-6009d86bc00c.png)

## 環境変数を永続的に設定する

ここまでで説明した環境変数の設定について、全部、現在のコンソールと記載していましたが。

ここに記載している設定方法では、現在のコンソールに対して環境変数を追加、変更、削除できる方法となりあす。

このため設定変更したコンソールを閉じた場合、設定が消えてしまいます。

PowerShellで永続的な環境変数設定を行いたい場合は下記のいずれかで設定を行います。

- 起動プロファイル（$Profile）で環境変数を起動時に毎回設定するようにする。
- SetEnvironmentVariable メソッドを使用して永続的な設定を行う

なおこちらの方法については、別記事にて説明します。

## 総評

PowerShellで環境変数を扱う際は、Envといったキーワードを知っていれば特に戸惑う事もないかと思います。
モダンアクティビティを使ってみた(Excel編Part6～セルの幅も調整してほしいぜよ～)

## はじめに
①本記事は、2023年7月開催の「UiPathブログ 発信チャレンジサマー」の11日目のブログです。
ブログの詳細、参加方法については以下のブログを参照ください。

https://note.com/shumpei_w/n/nd082bdf28853

②このブログ情報は、2023/7時点の情報です。
③UiPathはCommunity Edition、Versionは2023.6.1を使用しています。

## セルに貼り付けしたけれど...
データテーブルを格納、処理終了段階でいざExcelへ貼り付け！

しかし、処理が終わってファイルを開いてみると...なんかしっくりこない。
データが間違っているわけではない。何か違和感...よく見るとセルが...狭い。
手で修正するのは別にいいんだが、でも面倒。
そういう時に役立つアクティビティはないだろうか...？

## 範囲を自動調整アクティビティ
「範囲を自動調整」アクティビティは、指定のセルの範囲を調整することが可能なアクティビティです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/170a463c-0799-a06b-57f4-504555676a08.png)

## やってみよう
あるExcelのシートを追加(Sheet3とします)して、適当に入力した値に合わせて調整しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/dbd28de1-24d9-4908-e994-fc36d17bac50.png)
早速「範囲を自動調整」アクティビティを使ってみましょう。
「ソースを選択」の部分は、対象のシート名を指定します。
ここでは"Sheet3"を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/e48768fe-23b8-a3a2-fc79-cf98c906f9df.png)
列と行のチェックは、つけたままで行きましょう。
動かしてみると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/172dc46a-6767-94c5-b82c-ace52eb036d7.png)
おお、自動で揃えてくれている！
ちなみに、調整する際は格納しているセルのデータが長いほうに合わせてくれているようですね。
### 列のみチェックの場合
以下の場合、列だけチェックした場合はどんな感じか見てみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/bdd3a226-52db-3693-a886-4ff01c81cd25.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/369c8b0c-f155-ec39-617a-348a72b7b607.png)
結果は...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/29ae01ea-e8e7-73aa-4a95-1b181c724d14.png)
列だけきれいに調整されました。
この時は、行にチェックが入っていないので行の調整はしていません。

### 行のみチェックの場合
以下の場合、行だけチェックした場合はどんな感じか見てみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/bdd3a226-52db-3693-a886-4ff01c81cd25.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/455ee491-59b3-85f7-268f-4f01f46a76a3.png)
結果は...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/e1020b4f-4215-f2a1-aa93-8255faf42980.png)
行のところ、間隔が狭くなっていますね。
この時は、列にチェックが入っていないので列の調整はしていません。

つまり、　
<b>列のみチェック     ：列だけ調整
行のみチェック        ：行だけ調整
列・行ともにチェック ：行も列も調整</b>
ということですね！

## まとめ
セル幅の調整は、設定もそこまで難しくないので使いやすそうな感じがしました。
皆さんも使ってみてくださいね！
最後までお読みいただきありがとうございました。
💭はじめてのMySQL クエリ

***:cherries:学んだことを随時まとめてく:cherries:***
<font color="MistyRose">間違っている点があれば是非教えていただきたいです<font>

# クエリとは
データベースや情報システムに対して情報を取得したり、データの追加・更新・削除を行ったりするために使用される命令や要求のこと

# SELECTクエリ
まさに<font color="CadetBlue">データベースや情報システムに対して情報を取得</font>するものがSELECT文（よく使う）
```sql
/* 基本書式。WHERE, GROUP BY, HAVING, ORDER BYは任意。*/
SELECT フィールド名(データベースから取得したいデータの列（カラム）に対して指定される名前)
FROM テーブル名
WHERE 条件
GROUP BY 集計項目
HAVING 集計項目に対する検索条件
ORDER BY ソート項目
```

# SELECT文の評価順序
記述した順に上から処理されないそう
:sunflower:[参考:SELECT文の評価順](http://www.code-magagine.com/?p=4718)

- FROM
<font color="Thistle">クエリの実行元となるテーブルを指定します。FROM句はクエリの最初に評価されます。</font>

- ON
<font color="Thistle">JOIN句と一緒に使用され、テーブル間の結合条件を指定します。ON句はJOIN句の直後に評価されます。</font>

- JOIN 
<font color="Thistle">複数のテーブルを結合するためのキーワードです。JOIN句はFROM句の後に評価されます。</font>

- WHERE
<font color="Thistle">データのフィルタリング条件を指定します。WHERE句はFROM句とJOIN句の後、そしてGROUP BY句の前に評価されます。</font>

- GROUP BY
<font color="Thistle">データをグループ化するためのキーワードです。GROUP BY句はWHERE句の後に評価されます。</font>

- HAVING
<font color="Thistle">GROUP BY句と一緒に使用され、グループ化されたデータに対するフィルタリング条件を指定します。HAVING句はGROUP BY句の後に評価されます。</font>

- SELECT
<font color="Thistle">抽出するカラムや式を指定します。SELECT句はHAVING句の後に評価されます。</font>

- DISTINCT
<font color="Thistle">SELECT句と一緒に使用され、重複する値を除外して一意の値のみを抽出します。DISTINCTキーワードはSELECT句の前に評価されます。</font>

- ORDER BY
<font color="Thistle">抽出したデータの並び順を指定します。ORDER BY句はSELECT句の後に評価されます。</font>

- TOP (LIMIT)
<font color="Thistle">抽出するデータの制限を指定します。TOP句（またはLIMIT句）はORDER BY句の後に評価されます。</font>

# INSERTクエリ
レコードの挿入
```sql
INSERT INTO テーブルA
(カラム1, カラム2, ...) 
SELECT (カラム1, カラム2, ...) 
FROM テーブルB;
```

# UPDATEクエリ
レコードの更新
```sql
UPDATE DB名.テーブル名 
SET カラム名1=値 [, カラム2=値 ...] [WHERE 条件];
```

#DELETE
レコードの削除
```sql
DELETE FROM DB名.テーブル名 [WHERE 条件];
```

***
.:blossom:参考:blossom:*.
[基本クエリの書き方](https://www.wakuwakubank.com/posts/321-mysql-basic/)
[SELECT文の評価順](http://www.code-magagine.com/?p=4718)
[SELECT文の評価順序の話](https://qiita.com/suzukito/items/edcd00e680186f2930a8)
ブートストラップフレイムワークとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/62fa3b6a-1dc6-ba6d-dac6-1446eedd25f1.png)
１：ブートストラップ　フレイムワークとは
　ウェブ開発においてよく使用されるフロントエンドのフレームワークです。ブートストラップは、HTML、CSS、およびJavaScriptを使用して、レスポンシブでモバイルフレンドリーなウェブサイトやウェブアプリケーションを迅速に構築するための２つセットを提供します。

２：ブートストラップフレームワークは以下のような主な特徴を持っています。
①グリッドシステム：レスポンシブなデザインを実現するために、ブートストラップは柔軟なグリッドシステムを提供します。これにより、Webページを簡単に複数の列に分割し、異なる画面サイズに合わせて配置やレイアウトを調整することができます。

②プリスタイルドコンポートネント：ブートストラップには、ボタン、ナビゲーションバー、フォーム、モーダルウィンドウなど、よく使用されるコンポーネントのスタイルが事前に定義されています。これにより、デザインやスタイリングに時間をかけずに、一貫性のある見た目と感触を持つウェブ要素を迅速に作成できます。

③JavaScriptプラグイン：ブートストラップは、さまざまなインタラティブな要素や動作を追加するためのJavaScriptプラグインも提供しています。例えば、ドロップダウンメニュー、モーダルウィンドウ、スライダー、アラートなど、さまざまな機能を簡単に追加することができます。

④カスタマイズ可能性：ブートストラップは、テーマやスタイルのカスタマイズが容易であり、自分のウェブサイトやアプリケーションに合わせて見た目や振る舞いを調整することができます。変数やスタイルシートのオーバーライド、テーマの選択など、柔軟なカスタマイズオプションがあります。

ブートストラップフレームワークは、開発者が効率的かつ一貫性のあるウェブプロジェクトを構築するために強力なツールとして広く利用されています。