OmniAICreator/Qiita-1.07M huggingface dataset:
慣れないシェルコマンドを使ってみた【入門編】

# はじめに
業務を遂行してる時にシェルコマンドを使うことが多々ありますが、頻繫に使うコマンド以外のコマンドを勉強していきたいと思います。

## 慣れないシェルコマンド
#### bc（計算） 
計算をするためのコマンド
```shell
$ echo '1+1'
1+1
$ echo '1+1' | bc
2
```

#### sed（置換）
文字を置換するためのコマンド
```shell
$ echo キムイババパワー | sed 's/イ/い/'
キムいババパワー
$ echo キムイババパワー | sed 's/バ/ば/'
キムイばバパワー
# 全ての検索対象の文字列を置換したい場合は後ろにgを付ける
$ echo キムイババパワー | sed 's/バ/ば/g'
キムイばばパワー
# 検索文字を再利用したい時場合は&を使う
$ echo キムイババパワー | sed 's/ババ/&&/'
キムイババババパワー
# 検索対象の文字列を括弧で囲み、\1、\2・・・で呼び出す
$ echo キムイババパワー | sed -E 's/(キムイ)(ババパ)/\2\1/'
ババパキムイワー
# .は任意の一文字を意味する
$ echo キムイババパワー | sed -E 's/(キ..)(...)/\2\1/'
ババパキムイワー
```
#### 

#### sortとuniq（集計） 

```shell
# 辞書順に並べる
$ seq 5 | awk '{print $1%2 ? "奇数" : "偶数"}' | sort
偶数
偶数
奇数
奇数
奇数
```

```shell
# 重複を消す、重複する行は連続して並んでる必要がある
$ seq 5 | awk '{print $1%2 ? "奇数" : "偶数"}' | sort | uniq -c
      2 偶数
      3 奇数
```

```shell
# sortせず、uniqを使用した場合
$ seq 5 | awk '{print $1%2 ? "奇数":"偶数"}' | uniq -c
      1 奇数
      1 偶数
      1 奇数
      1 偶数
      1 奇数
```


#### xargs（一括処理）
```shell
# 1、2、3、4という名前の4つのディレクトリを作成
$ seq 4 | xargs mkdir
$ ls -d ?
1  2  3  4
# 1、2、3、4という名前の4つのディレクトリを削除
$ seq 4 | xargs rmdir
$ ls -d ?
ls: cannot access '?': No such file or directory
```

```shell
# 1、3という2つのディレクトリを作成
$ mkdir 1 3
# それぞれ2、4という名前に変更
$ seq 4 | xargs -n2 mv
$ ls -d 2 4
2  4
```

```shell
# -I オプションは渡されたデータを任意の位置の引数に展開
$ seq 4 | xargs -I@ mkdir dir_@
$ ls -d dir_*
dir_1  dir_2  dir_3  dir_4
```

# さいごに
個人的に慣れや流れでコマンドを使用している場合が多いですね。
ちゃんと理解して使いたいと思います。

# 参考
https://www.amazon.co.jp/1%E6%97%A51%E5%95%8F%E3%80%81%E5%8D%8A%E5%B9%B4%E4%BB%A5%E5%86%85%E3%81%AB%E7%BF%92%E5%BE%97-%E3%82%B7%E3%82%A7%E3%83%AB%E3%83%BB%E3%83%AF%E3%83%B3%E3%83%A9%E3%82%A4%E3%83%8A%E3%83%BC160%E6%9C%AC%E3%83%8E%E3%83%83%E3%82%AF-Software-Design-plus%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA/dp/4297122677
JWTってどういう仕組みなんだっけ

JWT (JSON Web Token)が、
データを JSON 形式で保持出来て、
内容の改ざんを検知することができるトークンであることはよく知られているかなと思います。
認証周りの機能で用いられていたり、ユーザーの情報などを保持するために利用されていることがあるので使う機会は多々ありますよね。

ただ JWT が実際にどのような仕組みで出来ているのかまではあまり気にしたこともない人もいるのかなと思います。今回はどのような仕組みで構成されているのかを少し見ていきましょう。

# 特徴
まず、特徴から見ていきましょう。
ざっと以下が挙げられる様です。
- 改ざんの検証をすることができる
- 暗号化前のデータが JSON 形式のオブジェクトである
- URL Safe である (GETパラメータのセパレータとして機能する ? = & が含まれない仕様)
- コンパクトにやり取りを行うことができる
- 署名に公開鍵と秘密鍵のペアを使用できる（SWTは共有鍵のみ）

先ほども出た改ざんの検証が出来ることや JSON 形式のオブジェクトであることに加えて、URL Safe であることやコンパクトであることも特徴であるみたいですね。
こういった特徴を持つ理由を仕組みから探してみます。

# 仕組み
JWT は、Header (ヘッダ)・Payload (ペイロード)・Signature (署名) と大きく 3 つの要素からなる文字列となっています。各要素は、ドット(.)で結合されて 1 つの文字列として扱われます。
```JS
// ヘッダ.ペイロード.署名 から成る 1 つの文字列になっている
abaA1.BBaa2.ABBAa3
```
次は各要素の詳細を見ていきましょう
以下の画像は[jwt.io](https://jwt.io/)から引用したものです。
先述した JWT の 3 つの構成にリアルな値が入ったサンプルになっています。
![jwt-decode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100759/9dcbd984-e134-ab67-2184-b55f2e1db4a0.png)
各要素の中に定義されている項目のことは **クレーム (Claim)** と呼びます。
クレームには必須のものや任意のもの、独自に定義できるものがあり、各クレームに保持させたい情報を入れて扱う形となっています。
アプリケーションからユーザーの情報などを JWT に持たせることがあると思うのですが、そういった重要な情報は主にペイロードの部分に格納されています。

次に各要素の中身を見ていきましょう
## ヘッダ（HEADER）
ヘッダは、主にメタ情報となるものが含まれる場所になっています。具体的には以下のキーを含めることが可能です。

- `alg`：署名の際に使用されるアルゴリズム
- `typ`：トークンのタイプ
- `cty`：ペイロードのメディアタイプ
- `kid`：署名に使う鍵の ID

上記の画像だと、`HS256` というアルゴリズムで署名を行い、 `JWT` というトークンのタイプであることがヘッダから分かりますね。
最終的には base64UrlEncode されます。

## ペイロード（PAYLOAD）
ペイロードは、実際にアプリケーションで活用される情報が含まれます。具体的には以下のキーを含めることが可能です。

- `iss`: JWTを発行した者(サーバー)の識別子
- `sub`: JWTの主体となる識別子
- `aud`: JWTを利用する側(クライアント)の識別子
- `exp`: 有効期限の終了日時
- `nbf`: 有効期限の開始日時
- `iat`: 発行日時
- `jti`: 一意な識別子
- `typ`: コンテンツタイプの宣言

この他にも id だったりメールアドレスだったり持たせたければキーバリューの形で持たせることが出来ます。
こちらも最終的には base64UrlEncode されて文字列の一部となります。

## 署名（SIGNATURE）
署名は、JWT の改ざんを検証する際に使用される文字列になります。
署名の文字列は、JWT のヘッダに付与されているアルゴリズムとシークレットキー(署名の際に使用される鍵のこと。今回の画像では共通鍵を利用しているがその他にも公開鍵・秘密鍵を用いるやり方もある)を利用して署名のための文字列を生成します。
この部分が特徴にも挙がっていた `改ざんの検証をすることができる` というところですね。
ヘッダとペイロードを base64UrlEncode した上でドットで繋げて、HMACSHA256 のアルゴリズムにシークレットキーと共に渡すことで署名をしている様です。
そうして作られたハッシュ値を他の要素と同様に base64UrlEncode して、文字列の一部とします。

# 検証ってどの様に行われるのか
JWT が大体どういう構成から成っているのかというところは概ね知ることが出来たと思います。
最後に、特徴の一つであった `改ざんの検証をすることができる` ところはどの様に行われるのかというところを見ていきましょう。
大まかには以下のような流れになります。
![スクリーンショット 2023-03-31 2.15.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100759/fc8cd02a-8124-9370-99ab-183d332f9980.png)

まず、ヘッダ・ペイロードに関しては base64UrlEncode されているだけなので、decode を行います。
そして最初に kid が一致するのかなどの確認を行う様です。ヘッダに関しては暗号化されているわけではないので改ざんすることも可能です。なので大事なのは次の署名の検証になります。
JWT を構成する ３ つの部分の内の 1 つである署名部分は、シークレットキーを用いてハッシュ化されています。ハッシュ値は不可逆なので復号化をすることは出来ません。
なので、送り元と同様にヘッダー・ペイロードをエンコードした上でシークレットキーを用いてハッシュ値を再生成します。そしてそれを送られてきたハッシュ値と突き合わせて一致していれば改ざんされていない、という検証を行う様です。

# おわり
以上になります。
なんとなくでも理解の一助になれば幸いです。
ポートフォリオ　SlowlyBife(Unity・C#)

# はじめに
こんにちは、24卒のしんたろーです。
インターン経験はなく、去年の夏休み頃からC#とUnityを勉強し始めました。
今回ポートフォリオを作成したので、紹介していこうと思います。

# 目次
[・制作したポートフォリオ](#制作したポートフォリオ)
[・制作した背景](#制作した背景)
[・SlowlyBife制作の詳細](#slowlybife制作の詳細)
[・SlowlyBifeの概要](#slowlybifeの概要)
[・注目してほしい部分](#注目してほしい部分)
[・このゲームの改善ポイント](#このゲームの改善ポイント)
[・ポートフォリオを制作して感じたこと](#ポートフォリオを制作して感じたこと)
[・最後に](#-最後に)

# 制作したポートフォリオ
今回はバイクゲームを作ってみました。

ここから遊べます
↓
[SlowlyBife](https://shintaro0403.github.io/SlowlyBife/)
![2023-03-28_18h00_25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3304843/26725ce0-29d3-82a0-ae7e-87e117b05409.png)

Slowly+Bike+Lifeの造語です。

# 制作した背景
昔から「GTOの鬼塚」や「こち亀の本田」など、バイクに乗っているキャラが好きで、私はバイクに憧れていました。

しかし、時代的にもコスパ的にも中々嚙み合わず、結局バイクの免許は諦めて、車の免許を取得しました。

「でもバイクで運転してえ」

この気持ちが大きくなった私は、


**現実での実現が難しいなら、Unity内で実現しよう！**

と思い、SlowlyBifeの制作を始めました。

私だけでなく、Z世代の男性の中にはバイクを運転したいけど中々難しいという方が多いと思います。

そういった方にぜひおすすめしたいです。

# SlowlyBife制作の詳細
- 作成期間 **：** 20日ほど
- 使用技術 **：** Unity、C#
- PC版にした理由 **：** 大画面で楽しんで欲しいから
- ターゲット層 **：** 20代のバイクに乗っていない男性(バイクに憧れがある）


# SlowlyBifeの概要
SlowlyBifeは名前の通り、ゆったりとしたツーリングを楽しむためのゲームです。

レースや記録などは一切ありません。

**では、なぜそのようにしたのか？**

『それはドライブする理由の多くは、「気分転換」と「運転が好きだから」が大半だからです。』
　　　　　　　　　　　　　　　　　　　　　　　　       **＊パーク24株式会社さん調べ** 



**そこで私は、何も考えずただただゆったり運転することが、人々の求めているものではないかと考えました。**

このアンケートはドライブが対象ですが、ツーリングも当てはまると思っています。


よって、バイクをテーマにしながらゆったりとしたゲームを今回制作しました。


# 注目してほしい部分

**①音**
**②一人称視点による没入感**
**③広大なフィールド**
**④わかりやすい操作**

## ①音
ツーリングを感じられる壮大かつ癒される環境音・迫力満点のバイクの走行音など、音は慎重に選びました。

また、タイトル画面で流れるBGMは、【ミドルテンポ】で田舎感を表現しているものを採用。

【アップテンポの存在であるバイク】と【スローテンポの存在であるSlowly】の二つの存在ををうまくまとめ上げています。

## ②一人称視点による没入感
視点移動は、スラスラ快適に行えるよう制作しました。

走行中に、広い景色を楽しんでほしいです。
## ③広大なフィールド

SlowlyBifeは二つの広大なフィールドで遊ぶことが出来ます。



**地形の大きさ** 
- ステージ1 (2000×2000)
- ステージ2 (1500×1500)

## ④わかりやすい操作

- バイクの操作は、Wで前進のみ。(Spaceキーでエンジン音は鳴らせるが、鳴らさなくても発進可能）

- 視点移動＆進路変更はマウスで可能。

- シーン遷移はボタンを押すだけで簡単に行える。

操作＆プレイ動画は[こちら](https://youtu.be/N0G86s7sETc)から

# このゲームの改善ポイント

- やりこみ要素の追加（バイクの追加や排気音を奏でたりできるような機能の追加）

- 景色のクオリティアップ

- 運転のリアル度のアップ（モデルの細かい調整や車体を倒して曲がることが出来るように）

- チーム機能の追加（ツーリング仲間のようなのを実現）

# ポートフォリオを制作して感じたこと

ポートフォリオ制作を通して、制作物を人に遊んでもらうまでの状態にするためには多くの過程が存在することを学んだ。

今回はWebGLビルドでGithubに公開したが、公開するまでに圧縮形式のエラーやサンプラー数超過のエラー、ファイルサイズオーバーによるエラーなど様々なエラーに遭遇した。

公開するまでに遭遇した様々なエラー解決していく中で、Unity内での作業がゲーム制作だと思っていたところから、Unity内での作業は全体の中でのほんの一部であり、全体を意識して制作する必要があることを学ぶことができた。

まだまだ多くのことを勉強していきたいと感じた。

# 最後に

最後まで読んでいただきありがとうございました。

私自身、今はUnity/C#と並行してblenderを学んでいます。

3Dモデルまで自作できるようになりたいです。
自分で作ったコードとChatGPTで作ったコードを比べてみた

# 概要
今回初めてGoogleAppsScriptを利用して、GoogleDrive内にあるcsvファイルを読み込んでグラフ化するスクリプトを作成してみました。
そのあとに今話題のChatGPTにスクリプトを作成してもらい比較してみました。

**自分で作成したスクリプト**

``` Javascript
function createChart() {
  
  // シートを取得
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  // セルの値を取得
  var folder_id = sheet.getRange("B1").getValue();
  // フォルダを選択
  var folder = DriveApp.getFolderById(folder_id);
  var files = folder.getFilesByType(MimeType.CSV);

  while (files.hasNext()) {
    var file = files.next();
    var csv = file.getBlob().getDataAsString();
    var csvData = Utilities.parseCsv(csv);
    var sheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet();
    var range = sheet.getRange(1, 1, csvData.length, csvData[0].length);
    range.setValues(csvData);
    var chart = sheet.newChart().asBarChart().addRange(range).setPosition(1, 3, 0, 0).build();
    sheet.insertChart(chart);
    sheet.setName(file.getName());
  }
}
``` 

**ChatGPTが教えてくれたコード**
``` Javascript
function createChartsFromCSVs() {
  var folderId = "YOUR_FOLDER_ID_HERE";
  var folder = DriveApp.getFolderById(folderId);
  var files = folder.getFilesByType(MimeType.CSV);
  while (files.hasNext()) {
    var file = files.next();
    var sheetName = file.getName().replace('.csv', '');
    var csvData = Utilities.parseCsv(file.getBlob().getDataAsString());
    var headers = csvData[0];
    var data = csvData.slice(1);
    var chartSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName) || SpreadsheetApp.getActiveSpreadsheet().insertSheet(sheetName);
    chartSheet.clear();
    chartSheet.appendRow(headers);
    data.forEach(function(row) {
      chartSheet.appendRow(row);
    });
    var chartBuilder = chartSheet.newChart();
    chartBuilder.setChartType(Charts.ChartType.LINE);
    chartBuilder.addRange(chartSheet.getRange(1, 1, data.length+1, headers.length));
    chartBuilder.setPosition(5, 5, 0, 0);
    var chart = chartBuilder.build();
    chartSheet.insertChart(chart);
  }
}

```
# 処理の中身は
見比べてわかる通りほぼ差がありませんでした...
どちらも以下の処理を実行しています。
1\.指定したフォルダIDからフォルダ情報を取得
2\.フォルダ内のCSVファイルの情報を取得
3\.各ファイルをループしながら以下の処理を繰り返す
4\.csvを読み込んで、チャートの種類、データ範囲、位置を設定
5\.チャートをビルドし、シートに挿入

# 結果
自分でこのスクリプトを作成するあたり以下の事を行いました。
- GoogleAppsScriptでグラフ化を自動で出来るの調査
- 公式サイトでフォルダ情報、ファイル情報の取得方法などを調査
- コーディング方法を調べながらコーディング
- デバッグして、動作確認して不備があれば修正

上記の事に2時間弱かかりました。
ChatGPTであれば、アカウントの登録して、以下の言葉を入力して完了です。
10分ほどしかかっていません。

# 終わりに
GASの場合は、ChatGPTでベースを作成して、細かい個所を修正していくという方法が作成しやすいと思いました。
数値の数え方について

# はじめに
最近、基礎の足りなさを実感することが多く、基本情報技術者の本を勉強してますが、その中で数値の数え方についてまとめてみました。

### 10進数
10進数とは、<b>値が<font color="red">10</font>になるときに桁が1つ上がる表記法</b>です。
※日常で使っている表記法
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961058/d2380f94-a0fb-3115-53ad-34db6bf4fb22.png)

### 2進数
2進数とは、<b>値が<font color="red">2</font>になるときに桁が上がる表記法</b>です。
![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961058/049762d4-de2e-ce79-f947-d7fa6b7cc033.png)

### 16進数
 16進数とは、<b>値が<font color="red">16</font>になるときに桁が上がる表記法</b>です。
![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961058/fd83b1a1-71d1-9877-79c5-6a3aa6a026ca.png)


## 基数変換
数値の表記法を変換することができます。
下記の例のような計算方法があり、試験のためには覚えるべきですが、

#### 10進数 → 2進数
![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961058/252525af-b211-3386-c598-8c46ee1703ff.png)


#### 16進数 → 10進数
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961058/8933544c-2d4a-16e7-1fd1-cd4a4447a99b.png)

小数点以下など全て計算するにはものすごく手間がかかります。

PHPの場合、下記の関数を提供してくれてます。
```php
// (PHP 4, PHP 5, PHP 7, PHP 8)
// 数値の基数を任意に変換する
base_convert(string $num, int $from_base, int $to_base): string

// 10進数 → 2進数
echo base_convert(243, 10, 2);
11110011

// 16進数 → 10進数
echo base_convert('3EFD.A14', 16, 10);
66050580

// 2進数 → 16進数
echo base_convert('10111001', 2, 16);
b9
```

# さいごに
昔、日常と同じくなぜ10進数を使わないのかと思ったこともありましたが、
コンピュータの処理的に電気が流れる=1、電気が流れない=0で表した方が好都合だったためだそうです。
あと、本には載ってませんが、良く使われる表記法で8進数もあります。
0~7で表記する数値の数え方で代表的な使い方としてはLinuxの権限があります。

実装となると一つずつ表記法を計算したりすることはないと思いますが、知識の土台として積み重ねていきたいですね。

以上です。

# 参考
https://www.amazon.co.jp/%E3%80%90%E4%BB%A4%E5%92%8C%EF%BC%95%E5%B9%B4%E5%BA%A6%E3%80%91-%E3%81%84%E3%81%A1%E3%81%B0%E3%82%93%E3%82%84%E3%81%95%E3%81%97%E3%81%84-%E5%9F%BA%E6%9C%AC%E6%83%85%E5%A0%B1%E6%8A%80%E8%A1%93%E8%80%85-%E7%B5%B6%E5%AF%BE%E5%90%88%E6%A0%BC%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8%EF%BC%8B%E5%87%BA%E3%82%8B%E9%A0%86%E5%95%8F%E9%A1%8C%E9%9B%86-%E9%AB%98%E6%A9%8B-%E4%BA%AC%E4%BB%8B/dp/4815618410/ref=asc_df_4815618410/?tag=jpgo-22&linkCode=df0&hvadid=622963848842&hvpos=&hvnetw=g&hvrand=6095404569894053001&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009537&hvtargid=pla-1943804713646&psc=1&th=1&psc=1

https://www.php.net/manual/ja/function.base-convert.php
Pythonをアップデートしてもバージョンが変わらない原因と解決法

私はあるときからしばらく、最新バージョンのPythonをインストールしたにもかかわらずコマンドラインで``python -V``と入力してバージョンを確認すると、バージョン番号が変わっていないという現象に悩まされました。この記事では、この現象の原因と解決法を紹介します。

## 原因

この現象の原因は、環境変数のPATHにありました。PATHとは、コマンドラインで実行可能なプログラムの場所を指定するための設定です。PATHには、複数のプログラムの場所が順番に並んでいます。

コマンドラインで``python``と入力すると、PATHに登録されたプログラムの場所から順番に探して、最初に見つかった``python.exe``という名前のプログラムを実行します。

しかし、自分で意図的にインストールしたPythonだけでなく、他のソフトにPythonが同梱されていることがあります。たとえば、Inkscapeには、Pythonが同梱されています。私の場合は、これが原因でした。

Inkscapeをインストールするときに、PATHにInkscapeのディレクトリーが追加されます。そして、InkscapeのPATHが通常のPythonのPATHよりも上に設定されることがあります。

この場合、コマンドラインで``python``と入力すると、最初に見つかるのはInkscapeに同梱された古いバージョンのPythonです。そのため、アップデートしたにもかかわらず、バージョン番号が変わっていないように見えます。

この状態では、``python.exe``のパスを直接指定して実行しない限り、Inkscapeに同梱された古いPythonが実行されてしまいます。

## 対処法

この現象を解決するためには、環境変数のPATHの順番を修正する必要があります。Windowsの場合の具体的な手順は、次のとおりです。

まず、``Win + s``でWindows Searchを開き、``path``と入力します。

![Windows Searchに「path」と入力した状態のスクリーンショット。検索結果として［システム環境変数の編集](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420120/32e55924-9900-c257-fc70-9261146c7a6a.png)

［システム環境変数の編集］を開き、下部にある［環境変数(N)…］をクリックします。

![システムのプロパティ］というタイトルのウィンドウのスクリーンショット。下部に［環境変数］というボタンがある。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420120/45dd13ea-ee8a-3091-341a-8358655f0edc.png)

表示されたウィンドウの［ユーザー環境変数］または［システム環境変数］の``Path``を選択し、［編集］ボタンをクリックします。

![［環境変数］というタイトルのウィンドウのスクリーンショット。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420120/9dd7209e-e851-0c52-0966-64d231c0560f.png)

Pythonのディレクトリーが含まれる項目を探して選択し、［上へ］ボタンで上へ移動します。

![環境変数の編集画面。いくつかのパスが表示されている。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420120/6ff9f786-d13d-4a1b-cb14-27d3b36753e7.png)

## まとめ

この記事では、Pythonをアップデートしたにもかかわらず、コマンドラインでバージョンを確認するとバージョン番号が変わっていないという現象の原因と対処法を紹介しました。

原因は、環境変数のPATHに他のプログラムに同梱された古いバージョンのPythonが登録されていることでした。対処法は、PATHの順番を並べ替えて最新バージョンのPythonを優先させることです。

この記事が皆さんのお役に立てば幸いです。
Web Speech APIを使った音声合成によるお知らせサービス

# はじめに
Webエンジニアを目指して、RubyやRailsをいじってます。
今回は、初めてWebアプリを作りました。改善点などがありましたらご指摘いただけると幸いです。

# 今回作成したWebアプリ
[informer](https://sh-informer.com/posts/new)

# 開発背景
プログラミングにハマってから、PCを使う時間が増え視力の低下や目の疲れを感じるようになりました。共感していただける方もいるかと思いますが、一度ハマると楽しくてずっとやってしまう、そんな日があります。しかし、その次の日の目の疲れは尋常ではありません（私だけかもしれませんが）。

これは良くないと思い、１時間おきぐらいに目を休めたいと考えました。そこで、設定した時間に音を鳴らせばいい、ただアラームだと止めるのが面倒くさいということで音声を読み上げるという形式のサービスを作ろうと思いました。

# サービスの概要
読み上げるテキストと時間を設定すると、その時間に設定したテキストを読み上げます。
![スクリーンショット 2023-03-31 0.58.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3303899/5399692b-dd13-f847-7a8a-27776b99b6ff.png)

# 終わりに
結果的にRailsよりもJavaScriptがメインの実装となりました。

また、デプロイまで実際に手を動かしたことでアプリ開発の難しさを痛感しました。普段何気なく使っているサービスにはエンジニアの方々の努力が隠れていたことに気づき、感謝とともに大きな尊敬を感じました。そんなかっこいいエンジニアになることを目指して、これからも研鑽を重ねていきたいと思います！

このサービスが多くの人の目の救世主になれば幸いです。最後まで読んでくださりありがとうございました！

# 参考
・[Webページでブラウザの音声合成機能を使おう - Web Speech API Speech Synthesis](https://qiita.com/hmmrjn/items/be29c62ba4e4a02d305c)
そういえばSwift5.7から型消去いらなくなったよねという話

## はじめに
Swift5.7から`Self`または`associated type`を持った`protocol`が型として定義できるようになりましたね！
これによって今まで型消去のテクニックを使って実装していた部分がよりシンプルに書けるようになりました。

## そもそも型消去って何よ
### `associated type`を持った`protocol`が型として定義できないとは
Swift5.7未満では`associated type`を持った`protocol`を型として定義できませんでした。
どう言うことか実際に処理として表現してみます。

```swift
protocol Repository {
    associatedtype Entity
    func fetch() -> Entity
}

struct SampleEntity {
    let text: String
}

class SampleRepository: Repository {
    typealias Entity =  SampleEntity
    func fetch() -> Entity {
        return SampleEntity(text: "")
    }
}
```

上記では`Repository`が`associated type`を持った`protocol`として定義されています。
では、実際に`Repository`を型として定義しようとするとどうなるか見てみましょう。

```swift
// Repositoryはassociatedtypeを持っていて型として定義できないためエラーが出る
var repository: Repository = SampleRepository()
```

上記のように`Repository`を変数の型に指定しようとするとエラーが出てしまいます。
このような場合、型消去のテクニックを使うことでエラーを回避しつつ、上記でやりたかったことを実現することが出来ます。

### 型消去テクニックを使って解決してみる
では、上記のコードを型消去のテクニックを使って実装してみましょう。

```swift
struct AnyRepository<Entity>: Repository {
    typealias Entity = Entity

    private let _fetch: (() -> Entity)

    init<T: Repository>(_ repository: T) where T.Entity == Entity {
        _fetch = repository.fetch
    }

    func fetch() -> Entity {
        return _fetch()
    }
}

var repository: AnyRepository<SampleEntity> = AnyRepository(SampleRepository())
repository.fetch()
```

`Repository protocol`を直接型に定義しないで、`AnyRepository`というものを噛ませているのがわかると思います。
`AnyRepository`はイニシャライザで`Repository`に準拠したクラスを受け取り、そのクラスが持つ`Repository`に準拠している関数を`AnyRepository`で変数に保持しておきます。
そして、`AnyRepository`の`fetch`関数等が呼ばれた際に保持していおいた関数を呼び出すことで、イニシャライザで代入したクラスの処理を実施出来ます。

`AnyRepository`は`protocol`ではないため、型としても問題なく定義できます。
`Repository`を`AnyRepository`に変換してしまうことで、元の`Repository`を型として定義することなく使うことが出来ます。

## 型消去を使わない方法
ここまで読んでいたいだら薄々勘づいているかと思うのですが、型消去をするために`AnyRepository`等といったボイラープレートコードを毎回用意するの面倒じゃないですか？
面倒だと思った方でかつSwift5.7以上を以上を使用している方がいらっしゃいましたらご安心ください、Swift5.7以降では型消去のテクニックを使わずに実装できます。
ようやくここから本題です。

### どうやって型消去を使わずに実装するの？
至って簡単です、下記のように定義しましょう。

```swift
var repository: any Repository = SampleRepository()
```
これで終わりですか？
はい、終わりです。
`associated type`を持った`protocol`を型として定義する際に、型の前に`any`を付けてあげるだけです。
`AnyRepository`等を作成する必要もありません。
~~本題より型消去の話の方が長い。~~

## 終わりに
型消去を現時点で使っている箇所は上記でリファクタリングすることでボイラープレートを削減でき、見通しも良くなるので検討の余地ありかなと思います。

## 参考文献
- [swift-evolution/0309](https://github.com/apple/swift-evolution/blob/main/proposals/0309-unlock-existential-types-for-all-protocols.md)
- [平常心で型を消し去る](https://academy.realm.io/jp/posts/tryswift-gwendolyn-weston-type-erasure/)
- [型消去を用いたSwiftによるリポジトリパターンの実装 - AnyType](https://naoty.hatenablog.com/entry/2016/03/11/160000)
EC2にEFSをマウントするまで試す

# はじめに

SSAの勉強を通してEFSについて学びましたが、使ったことはなかったので実際にEC2にマウントするところまでやってみました。

# EC2にマウントするまで

## ネットワークを作成

今回はVPCを1つ、サブネットを1つ作成し、1AZで構築します。

注意点として、VPCのDNS設定で、「DNS解決」と「DNSホスト名」の2つを有効化しておく必要があります。

![vpc-01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302427/420e1dd1-3a2f-466f-6e20-c91b97673768.png)

EC2にインターネット越しにSSHでアクセスする場合はインターネットゲートウェイをアタッチし、ルートテーブルで`0.0.0.0/0`のターゲットにインターネットゲートウェイを指定しておきましょう。

![vpc-02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302427/42102d6d-960f-4cde-ae8c-f683e5f3c2bc.png)

## セキュリティグループを作成

EC2用とEFS用の2つのセキュリティグループを作成します。

### EC2用

|ルール|タイプ|プロトコル|ポート範囲|ソース|
|:--|:--|:--|:--|:--|
|インバウンド|SSH|TCP|22|自端末のIPアドレス|
|アウトバウンド|すべて|すべて|すべて|0.0.0.0/0|

EC2用にはEFSに特別必要な設定項目はありません。

### EFS用

|ルール|タイプ|プロトコル|ポート範囲|ソース|
|:--|:--|:--|:--|:--|
|インバウンド|NFS|TCP|2049|EC2用のセキュリティグループ|
|アウトバウンド|すべて|すべて|すべて|0.0.0.0/0|

EFS用では、EC2からの受信を受け付けるため、nfsのポート2049のインバウンドを許可しておきます。

## EC2を作成

t2.microなどのインスタンスタイプで適当に作成します。セキュリティグループは先程作成したものを使用し、後でSSH接続できるよう、パブリックIPとキーペアを設定しておきます。

## EFSを作成

今回の本題です。

EFSのマネジメントコンソールから「ファイルシステムの作成」を選択し、「カスタマイズ」から詳細設定画面を開きます。

![efs-00.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302427/f868587c-6b89-9c27-d393-86f889be8869.png)

今回は安価に作成するため、ストレージクラスは「1ゾーン」にし、EC2と同じAZを指定します。また、自動バックアップは無効化しておきます。

![efs-01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302427/24443c01-d592-71cd-4e1e-04697d90247f.png)

ネットワークアクセス画面ではさきほど作成したEFS用のセキュリティグループを指定します。

![efs-02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302427/76e5417c-c3ee-46c4-085a-8706f8affa44.png)

これでEFSが作成できました。

![efs-04.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302427/e2076f2a-781e-3d47-f5d1-72540c408a02.png)

## EC2でEFSをマウント

SSHでEC2にログインし、EFSのDNS名を使ってマウントします。

マウントのコマンドはEFSの画面でアタッチをクリックすると、コマンドが表示されます。

![efs-05.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302427/62448e18-ced0-8f52-bf31-54654d05be58.png)

![efs-06.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302427/01a8f7ac-4d94-15cc-f364-32846899344f.png)

マウント先のディレクトリを作成し、コマンドをコピペするとマウントできます。

```sh
sudo mkdir -p /mnt/efs
sudo mount -t nfs -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport <EFSのDNS名>:/ /mnt/efs
```

# 料金

EFSの使用料金は、基本的にはストレージ使用量＋データへのアクセス量で決まります。また、ストレージ使用量はストレージのタイプによって異なります。

https://aws.amazon.com/jp/efs/pricing/

今回は1ゾーンストレージを使用したので、1GB使用すると1月当たり0.192USDかかります。安いですね。

# おわりに

めっちゃ簡単！！！！

題材としては気楽にできてちょうどいいので、今度CLIやSDK使った場合も試したい。
【Ruby on Rails】number_to_currencyの使い方

number_to_currencyの使い方メモ
これを直訳すると、数値から通貨へということらしい。

``` ruby
<span class="gorira"><%= number_to_currency(cart_item.price_total, unit: "¥", strip_insignificant_zeros: true) %></span>
```

第一引数に金額 cart_itemモデルに合計金額を表示させるためのprice_totalメソッドを書いたのでそれを上では使用
第二引数に通貨の単位 $とかも使えるらしいけど、日本なので¥とした
第三引数に小数点の非表示化 defaultはfalseになるが非表示としたいので、trueにする
LaTeXソースコードの\inputを展開し、1つのファイルにする方法

# 具体的に解決したい問題
LaTeXにおいて、例えば以下のような`\input{hoge}`を含む`main.tex`を1つのファイルに展開したい。

```latex
...
\maketitle

\input{introduction}
\input{proposed_method}
\input{evaluation}
\input{conclusion}
...
```

# 解決策

`latexdiff`コマンドの`--flatten`オプションを活用する。

```bash
latexdiff --flatten main.tex main.tex > flatten.tex
```

`latexdiff --flatten main_before.tex main_after.tex > diff.tex`で`\include{hoge}`を含めたファイル間の差分を強調したTeXファイルを出力できるが、`main_before.tex`と`main_after.tex`に同じファイルを指定することで、差分がないためそのまま展開されたTeXファイルが出力できる。
ChatGPT を使って、Rust言語を勉強します。関数 篇

#### 質問1: Rust言語の関数を教えてください。

#### 回答1:

---
Rustでは、fnキーワードを使用して関数を宣言します。Rustの関数は、関数名、引数、戻り値を含む構文で書かれます。引数と戻り値の型は、必ずしも明示的に指定する必要はありません。Rustのコンパイラが、変数やリテラルの型から型推論を行うためです。

以下は、Rustの基本的な関数の例です。

```rust
fn add_numbers(x: i32, y: i32) -> i32 {
    x + y
}

fn main() {
    let result = add_numbers(10, 20);
    println!("The result is {}", result);
}
```

上記の例では、add_numbersという名前の関数が定義されています。この関数は、2つのi32型の引数を受け取り、それらを加算して、結果をi32型で返します。main関数では、add_numbers関数を呼び出し、結果を表示します。

Rustの関数には、以下のような特徴があります。

・　関数は、他の関数内で定義することができます。
・　関数には、可変個の引数を取ることができます。
・　関数には、デフォルト引数を指定することができません。
・　関数は、戻り値をreturnキーワードを使用して明示的に返すことができます。ただし、最後に評価された式が暗黙的に返されるため、returnキーワードを使用する必要はありません。
・　関数の引数と戻り値は、必ずしも明示的に型を指定する必要はありません。Rustの型推論機能により、コンパイラが自動的に型を推論します。
・　関数の引数には、所有権を明示的に移動させるmoveキーワードを使用することができます。これにより、引数が関数内で新しい所有者になることを示します。
・　関数の引数には、参照を取ることができます。参照は、値を借用するためのポインタのようなものです。参照は、&キーワードを使用して定義されます。
・　関数の戻り値には、参照を含むことができます。参照を返す関数は、参照が指す値を変更することができます。参照を含む戻り値は、&キーワードを使用して定義されます。

---

#### 質問2: Rust言語の関数の使い方を教えてください。

#### 回答2:

---
Rustの関数を使うには、以下のような手順を踏みます。

関数を定義する。
関数を呼び出す。
以下は、具体的な例です。

```rust
// 関数の定義
fn add_numbers(x: i32, y: i32) -> i32 {
    x + y
}

fn main() {
    // 関数の呼び出し
    let result = add_numbers(10, 20);

    // 結果の表示
    println!("The result is {}", result);
}
```

上記の例では、add_numbersという関数を定義しています。この関数は、2つの引数を受け取り、それらを加算して、結果を返します。main関数では、add_numbers関数を呼び出し、結果をresult変数に代入しています。そして、println!マクロを使用して、結果を表示しています。

Rustの関数には、以下のような使い方ができます。

・　関数を複数回呼び出すことができます。
・　関数の引数には、変数やリテラルを渡すことができます。
・　関数の戻り値を変数に代入することができます。
・　関数の戻り値を直接表示することができます。
・　関数を他の関数内で定義することができます。

また、Rustの関数は以下のような特徴があります。

・　引数や戻り値の型を明示的に指定する必要はありません。Rustの型推論機能により、自動的に型を推論します。
・　最後に評価された式が、自動的に戻り値となります。つまり、returnキーワードを省略することができます。
・　関数の引数には、参照を取ることができます。参照は、値を借用するためのポインタのようなものです。
・　関数の引数には、所有権を移動することができます。これにより、呼び出し元の変数が関数によって所有権が奪われます。
・　関数の引数には、デフォルト値を設定することができません。しかし、オプション型を使用することで、値が指定されていない場合の代替値を設定することができます。

---

#### 質問3: Rust言語の関するのサンプルを教えてください。

#### 回答3:

---
以下に、Rustの関数のサンプルコードをいくつか示します。

1. 引数として文字列を受け取り、その文字列を表示する関数

```rust
fn print_string(input_string: &str) {
    println!("{}", input_string);
}

fn main() {
    let my_string = "Hello, Rust!";
    print_string(my_string);
}
```

この関数は、print_stringという名前の関数で、input_stringという名前の引数を受け取ります。input_stringは文字列スライスの参照であるため、&str型を持ちます。関数内では、println!マクロを使用して、引数で受け取った文字列を表示します。

2. 2つの整数を受け取り、それらを乗算した結果を返す関数
```rust
fn multiply_numbers(x: i32, y: i32) -> i32 {
    x * y
}

fn main() {
    let result = multiply_numbers(10, 20);
    println!("The result is {}", result);
}
```

この関数は、multiply_numbersという名前の関数で、2つの引数を受け取り、その積を計算して返します。main関数では、multiply_numbers関数を呼び出し、結果をresult変数に代入し、表示します。

3. 2つの整数を引数に取り、それらの和を計算し、和が偶数ならtrueを、奇数ならfalseを返す関数

```rust
fn is_sum_even(x: i32, y: i32) -> bool {
    let sum = x + y;
    sum % 2 == 0
}

fn main() {
    let result1 = is_sum_even(10, 20);
    let result2 = is_sum_even(15, 20);
    println!("Result 1: {}", result1);
    println!("Result 2: {}", result2);
}
```

この関数は、is_sum_evenという名前の関数で、2つの引数を受け取り、その和が偶数か奇数かを判定します。和が偶数の場合はtrueを、奇数の場合はfalseを返します。main関数では、is_sum_even関数を2回呼び出し、結果を表示します。

以上のように、Rustの関数は引数を受け取り、戻り値を返すことができます。関数の定義方法や呼び出し方は、上記の例を参考にすることができます。

---
ModuleNotFoundError: No module named 'encodings'が止まらない

# 色々やったら以下のエラーが止まらない

```
ModuleNotFoundError: No module named 'encodings'
```

# 対象
Conoha VPSでDjango + Apache + WSGI + pyenv +Python venvでWeb開発をしている。

Conoha VPSは最初はシステムpythonを使う状態のテンプレートを提供しているのだが、これをpyenvを用いたpythonの仮想環境にしようとした。

# 結論
今回の原因は、rootからpyenvを使ってpython環境を構築したことだった

実は、お恥ずかしいことにあまり把握していなかったのだが、インストールしたパッケージは作成したvenv/lib/python3.X/site-packagesに保存されるが、pythonにもとから入っているencodingsなどは、元の/root/.pyenv/versions/3.9.0の中にある

試すとわかる

```
Python 3.9.0 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import encodings
>>> encodings.__file__
'/root/.pyenv/versions/3.9.0/lib/python3.9/encodings/__init__.py'                                   >>>
```

そのため、このrootディレクトリにあるencodingsはapacheには読み込めないという感じ。

ユーザーアカウントでpyenvをinstallして、仮想環境を作成したら上手くいった
AWS学習ステップを使用した構築のお勉強②

# はじめに
そういえば基本的なサーバの仕組みとか構築って知識だけあってやったことないなあと思いました。。（上の方に言うと驚かれますがマジでオンプレ触ったことないです）

そこで見つけたル〇コンさん。（Twitter[こちら]("https://twitter.com/RubiconLink" "ルビコンさんのTwitterプロフィール")）
直接お会いしたことないので名前はお伏せしますが、おそらく素晴らしいお方。
しかもなんと、AWS学習ステップ大全 AWS構成図集というのを無料で配布しているではありませんか！！
これは活用するしかない！！ということでAWS構成図集をお借りしてお勉強していきます！！

# AWS学習ステップ大全 AWS構成図集とは
こんな方にオススメだそうです。今の僕にピッタリ。
* AWSを勉強したいので、オススメの学習ステップを教えて欲しい
* AWSはEC2/RDS/ELBなど多すぎて、どれを組み合わせたらいいか分からない
* 簡単な構成から難しい構成まで、難易度別に構成図を知りたい
* HTTPSや独自ドメインなどは実装しつつ、なるべくお金がかからない構成が知りたい
* 転職応募時に「未経験なのにレベル高い」と刺さるレベルの構成を知りたい
* ポートフォリオと一緒に提出する構成図の参考例が知りたい
* 学んだスキルが現場で通用するのか＝実際の現場ではどういう構成が多いのか知りたい

# 今回は②だよ！
前回作成したものにドメインを導入します！！
IPベタ打ちではなくexample.comみたいな感じでアクセスできるようにします！！
アーキテクチャはAWS構成図②を参照！！

# ドメインの取得
[お名前.com]("https://www.onamae.com/")でドメインを取得しましょう！！
なんでもよかったら無料で取れます！！

# ホストゾーンの作成（Rotue53）
DNSサービスにはRoute53を使用します！！
AWS完結の方が連携が楽なんでいいですね。
（まあ実案件は色々あってそうはいかないんですけどね笑笑）

赤のところに先ほど取得したドメイン名を記載します
![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3138153/0337a76f-5a6e-b281-d23b-f0f4887281f3.png)

#レコードの登録
NSレコードをネームサーバとして登録します！
NSレコードを選択すると画面右に値が表示されるのでコピーします。
![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3138153/414254ea-d77c-59cc-9ac8-56ffe631f8be.png)

これをお名前.comのネームサーバ情報として入力します！
![3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3138153/bacd3d46-909f-1d69-d0d0-57856df9bb3b.png)

# EC2のIPアドレスを固定する
そういえばElastic IPを設定していませんでした。
これを設定しないとEC2を再起動するたびにIPアドレスが変わってしまいます。笑笑
ネットワークボーダーグループはEC2を立てたリージョンを選択してください
![4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3138153/e7ff4b1f-58a2-4568-291a-6f6d77e2ee74.png)

作成したEC2に関連付けします。
![5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3138153/a19f80bd-398f-93ff-a40b-2d194b549a28.png)

# レコードを作成
先ほど設定したIPアドレスとレコードを紐づけます。
値にIPアドレスを記入しましょう。
![6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3138153/1b928ef8-bffe-fc2f-bde8-76318985eb45.png)

# 名前解決だ
紐づけたドメイン名でウェブ検索してみましょう。
![7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3138153/0bab09bc-e63e-55b2-8047-359b3758db84.png)

# おわり
今回はこけるような部分は無かったですね、
しいて言うならネームサーバが登録されるまで時間がかかることくらいでしょうか、
ホットパッチのデスクトップエクスペリエンス（プレビュー）

### 概要
ホットパッチのデスクトップエクスペリエンスがプレビューで利用できるようになったようです。本機能はWindows Server 2022のAzure Editionにて利用可能な機能です。Server Coreについては以前からプレビューが発表されていたのですが、この度デスクトップエクスペリエンスでもプレビューで使えるようになったとのことです。
ホットパッチはリブートせずにOSのパッチアップデートを適用させる機能なので、運用環境への影響を抑えつつも最新のセキュリティパッチを適用できるので、セキュリティの重要性が益々増してきている昨今で非常に重要な機能ではないでしょうか。プレビューイメージの入手など詳細はMicrosoftのブログもご参考ください。

参考：[Hotpatching is now available in preview for Windows Server VMs on Azure with Desktop Experience](https://techcommunity.microsoft.com/t5/windows-server-news-and-best/hotpatching-is-now-available-in-preview-for-windows-server-vms/ba-p/3797924)
git stashで特定のファイルをstashする方法

情報が古いです！！！！
2014年時点のGitを使用していて、特定のファイルをstashしたかったのですが、現在使用できるコマンドが使えなくて困っていたので、もし自分と同じ境遇の人は少しでも参考になればと思います。

### 手順

- `git stash`して全部のファイルを保存
- `git stash show`でスタッシュしたファイルの一覧を表示して特定にファイルを探す
- `git checkout stash@{0} ファイルパス/ファイル名`を指定して特定のファイルを戻す
- なぜかステージングエリアにファイルがいた。コミットしたくないので、ワーキングディレクトリに戻す
    
```
git reset HEAD ファイルパス
```
    

- `git checkout stash ~`のコマンドは実行後もスタッシュにファイルが残ったままなので不要な場合は削除

```
// stash@{番号}はgit stash listで確認できる
git stash drop stash@{番号}
```

#### 余談
untrackedのファイルも大量に出てたので、untracked出したくない場合は、`git status -uno`で非表示にできる

untrackedのファイルも削除したい場合は、`git clean -df`を使用

### 参考
[https://kentana20.hatenablog.com/entry/2014/07/05/172717](https://kentana20.hatenablog.com/entry/2014/07/05/172717)
Wear OSのウォッチフェイスをGoogle Playで公開するまでのあれこれ

# はじめにCM
私の過去記事をご覧頂いた方にはおなじみですが、FF14のゲーム内で流れているエオルゼア時間がいつでもWear OS搭載のスマートウォッチで確認できるウィッチフェイスをGoogle Playでリリースしました。
(無料です！)

[Simple Eorzea](https://play.google.com/store/apps/details?id=jp.rainyvillage.wearos.watchface.simpleeorzea&hl=ja)
![heroimage.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2066798/816379f7-0f51-bd63-f042-69d5874efd1d.jpeg)

# ここから本題
ところでこのウォッチフェイスをGoogle Playでリリースするまでに様々な躓きやトラブルがありました。
ここはQiitaなので、そういった情報を共有できればと思います。

## 開発での躓き
### レイアウトの作成
はじめに、下図のようにAndroid StudioのXMLビジュアルエディターでウォッチフェイスのデザインレイアウトを頑張って作りました。
![layout.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2066798/48b3a4f6-1c63-ecd9-b6b6-e591b1732f07.jpeg)
エミュレーターでも確認してこれでバッチリだと思ったんですよ。
ところがウォッチフェイスの切替画面で見たとき驚愕の事態が。
![Screenshot_20230415_100719.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2066798/45c83f48-a67a-fdeb-8cda-6272d3811c49.png)
~~**なにこれ？**~~

はい、原因はテキストサイズを「sp単位」(OSのシステムテキストサイズ基準で相対的にサイズが決まる単位)で指定したためです。
かといってWear OSデバイスごとに画面の縦横px数は異なるのでpx単位で指定するわけにも行かず積みになりました。

結局このXMLはほとんど破棄して、1つだけ置いたViewに対してCanvas内でゴリゴリ計算しながら描画する実装にしました。
(Android StudioでWatch Faceプロジェクト作成時に生成されるサンプルコードもCanvasに描画する実装になっていました)

## Google Playの審査での躓き
### リジェクト1回目

さて、なんとかウォッチフェイスが完成したのでApp bundleを作成してGoogle Playの審査に提出しました。
待つこと半日、ありがたくないリジェクト(否承認)を知らせる下記の内容を含むメールが届きました。

> 問題が見つかりました。 Wear のスクリーンショット
> Wear OS のスクリーンショットに 1 つ以上の問題（下記を参照）があります。
> Wear OS のスクリーンショットに透明な背景やマスキングが含まれています。

マスキングも半透明にした覚えもないけどな…と思いながらよくよく提出したスクリーンショットを眺めていると
![Screenshot_20230415_131002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2066798/d043b8c2-6945-990a-cc51-cda047273781.png)
エミュレーターで撮った**丸形デバイスのスクショ、余白透明になってない…？**

というわけで背景を黒にしてJPEG形式で再提出しました。

### リジェクト2回目

待つこともう半日、もう一度リジェクトメールが届きました。

> お客様のアプリアイコンは、ウォッチフェイスに表示される画像を正確に表していません。
> Wear アプリの品質に関するガイドライン について
> Wear アプリの品質に関するガイドラインに準拠していない Wear OS アプリは承認されません。

~~…あっ、そんなルールがあるんですね。
(適当にウォッチフェイス名を書いた画像をアプリアイコンとして提出していました)~~
**ガイドラインなど公式ドキュメントはちゃんと読みましょう。**

# さいごに
というわけで皆様がWear OSのウォッチフェイスを開発する際の一助になれば幸いです。
Let's happy watch face hacking!
AWS CLIを使った環境構築からS3作成&ファイルアップロードまでの手順

# AWS CLIでS3バケットを作成する方法

## 前提条件

- AWS CLIがインストールされていること。
- AWSのアクセスキーとシークレットアクセスキーを持っていること。

## 手順

### 1. AWS CLIの設定を行う

AWS CLIを使用する前に、アクセスキーとシークレットアクセスキーを設定する必要があります。

```
$ aws configure
```
このコマンドを実行すると、AWSアクセスキーID、シークレットアクセスキー、リージョン、出力形式の入力が求められます。これらを入力してください。

### 2. S3バケットを作成する

以下のコマンドを使用して、S3バケットを作成することができます。
```
$ aws s3api create-bucket --bucket my-bucket --region ap-northeast-1
```
ここでは、`my-bucket`という名前のS3バケットをap-northeast-1リージョンに作成しています。必要に応じて、バケット名とリージョンを変更してください。

### 3. バケットへのアクセス許可を設定する

作成したバケットにアクセスするためには、以下のコマンドを使用してアクセス許可を設定する必要があります。

```
$ aws s3api put-bucket-acl --bucket my-bucket --acl public-read
```

このコマンドでは、`my-bucket`という名前のS3バケットにパブリックリードアクセスを許可しています。必要に応じて、バケット名とアクセス許可を変更してください。

### 4. ファイルをアップロードする

作成したバケットにファイルをアップロードするには、以下のコマンドを使用してください。

```
$ aws s3 cp ./file.txt s3://my-bucket/file.txt
```

このコマンドでは、カレントディレクトリの`file.txt`を`my-bucket`という名前のS3バケットにアップロードしています。必要に応じて、ファイル名とバケット名を変更してください。

以上で、AWS CLIでS3バケットを作成し、ファイルをアップロードする方法の説明を終わります。
ファブレス or ファウンドリ

# はじめに
毎週1本様々な技術に関する記事を投稿しています。
もし興味のある方は下のリンクから他の記事も見ていただければ幸いです。
 [@7_inai_](https://qiixta.com/7_inai_)

IT技術とは少し異なりますが、この記事では半導体製造業のビジネスモデルとして挙げられる「ファブレス」と「ファウンドリ」について記載します。

# ファブレスとファウンドリ
### ■ファブレス
ファブレスとは、fabrication facility lessの略で、__工場を持たない会社__ を意味しています。
製品の設計・販売・マーケティング等製造以外の分野に特化し、製造は他の企業に委託します。こうすることで、ファブレス企業は、__設備投資や設備維持のための負担とリスクを保有せず__ に製品を生産することができます。
`代表的な企業：Apple、キーエンス、任天堂`


### ■ファウンドリ
ファウンドリ(foundry：鋳造所)とは、__他社からの委託を受けての生産__ を専門とするメーカーのことです。特に半導体メーカーやファブレス企業からの委託を受けることが多く、様々な企業の製品をまとめて生産するため、__生産コストを抑える__ ことができます。また、生産技術に集中して投資を行えるため、技術の水準が高く、安定した生産を行うこともできます。
`代表的な企業：TSMC、Intel`

# 半導体業界との関係性
ファブレスとファウンドリは、主に半導体業界で使用される言葉です。では、なぜ半導体業界ではそのようなビジネスモデルが一般的なのでしょうか？
その理由は、`製品の開発サイクルが短く、生産設備の投資に莫大なコストがかかるという半導体業界の特徴に対して、ファウンドリ企業/ファブレス企業による分業が非常に適している`からです。
もう少し詳しく説明します。半導体の製造には特定の専門的技術が必要とされます。そのため、技術者や製造設備を揃えるだけでも、難易度が高く多くのコストが必要となります。また、技術的な進化が早いことから開発サイクルも短くなるので、製造設備を整えることのリスクも非常に大きなものになります。そこで考えられた方法が、ファウンドリ企業とファブレス企業の分業です。ファウンドリ企業は製造に集中することで、技術的にもコスト的にも半導体の製造要件を満たしやすくなり、ファブレス企業は開発/設計に集中することで、製造に関するリスクを抑えて高品質の製品開発を行えます。

# 終わりに
今回は、ファウンドリとファブレスという「分業」を手段としたビジネスモデルを紹介しましたが、半導体業の他にも様々な業界が「分業」を行っています。
例えば、自動車産業では自動車メーカーが車のデザインや設計を考え、細かな部品は他のサプライヤー企業に委託しています。またIT企業では、ハードウェアの製造とソフトウェアの製造を分けて開発を行うことが多々あります。
このように、「分業」というビジネスモデルは多くの業界で採用されています。最近では「長所を生かす」という文脈の言葉を多くの場面で耳にしますが、ビジネスモデルという概念で見ても「長所を生かした」分業がより進められていくかもしれません。

最後までお付き合いくださりありがとうございました。
Excelファイルのテキストを書式やフォントを維持したまま置換する方法

# はじめに
Excelでは置換をしたときにセルの一文字目の書式と同じ書式になってしまうという特性があります。
今回はセル内の文字の書式やフォントを維持したまま置換する方法を紹介します。
引用元：https://ja.extendoffice.com/documents/excel/3760-excel-find-and-replace-preserve-formatting.html#a1

## 今回やりたいこと
Excelの仕様と今回やりたいことをまとめると図のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335781/683620e2-bdad-f0f8-a4c3-3e7c37b70b25.png)

## 実際のやり方
### ボタンの作成
まずボタンを作成し、ボタンをクリックしたときにマクロが実行されるようにします。ボタンを作成するには、開発ツールバーの[フォームコントロール]にある[ボタン]を選択し、ワークシート上にボタンを描画します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335781/afccd2b3-7b06-6be2-e8ec-d2e57c002ef4.png)

このマクロをボタンに割り当てるには、ボタンを右クリックし、[マクロの割り当て]を選択し、ソースコードを記入したプロジェクトシートまたはモジュールを選択しOKを押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335781/2081f061-15ec-a322-2bfd-5466fc09b3f4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335781/77b729c0-f40f-9a8b-7d61-bf1c0cfaedc7.png)

### コード例
マクロに導入するコードはこちらです。
```vba:CharactersReplace
Sub CharactersReplace(rng As Range, findText As String, ReplaceText As String, Optional MatchCase As Boolean = False)
  'Update20230419
    Dim I As Long
    Dim xLenFind As Long
    Dim xLenRep As Long
    Dim K As Long
    Dim xValue As String
    Dim M As Long
    Dim xCell As Range
    xLenFind = Len(findText)
    xLenRep = Len(ReplaceText)
    If Not MatchCase Then M = 1
    For Each xCell In rng
        If VarType(xCell) = vbString Then
            xValue = xCell.Value
            K = 0
            For I = 1 To Len(xValue)
              If StrComp(Mid$(xValue, I, xLenFind), findText, M) = 0 Then
                xCell.Characters(I + K, xLenFind).Insert ReplaceText
                K = K + xLenRep - xLenFind
              End If
            Next
        End If
    Next
End Sub

Sub Test_CharactersReplace()
    Dim xRg As Range
    Dim xTxt As String
    Dim xCell As Range
    On Error Resume Next
    If ActiveWindow.RangeSelection.Count > 1 Then
      xTxt = ActiveWindow.RangeSelection.AddressLocal
    Else
      xTxt = ActiveSheet.UsedRange.AddressLocal
    End If
    Set xRg = Application.InputBox("範囲を選択してください:", "書式を保持したまま置換する", xTxt, , , , , 8)
    If xRg Is Nothing Then Exit Sub
    Call CharactersReplace(xRg, "たちつてと", "なにぬねの", True)
End Sub

```

各行の説明は引用元を参照し、正確に理解できていないため割愛します。
使い方は至ってシンプル。
下から二行目の”たちつてと”が置換対象文字列。”なにぬねの”が置換後の文字列となりますので、実行前に書き換えていただければ完了です。
```
Call CharactersReplace(xRg, "たちつてと", "なにぬねの", True)
```

### 導入結果
実際に動かしてみます。
”たちつてと”が書式とフォントを維持したまま”なにぬねの”に置換されれば成功です。

ボタンを押下してB27を範囲選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335781/8a65bd3b-69ad-ba21-6d1f-b2ee5ffd4cdd.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335781/fb7fb228-0ee0-29e4-35ab-d0d87fe42d33.png)

”たちつてと”の書式とフォントを維持したまま”なにぬねの”に置換することが出来ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335781/8f2bbc99-4458-7723-7c91-d9b40ccf7bcb.png)
PokeAPIを使用してAndroidアプリを作成 ～環境構築編～

# はじめに
はじめまして、フリーランスエンジニアのモブ太郎です。
Javaのバックエンド開発を主に担当しています。
フリーランスをしているので、基本的にはメインとなるJavaの案件を受けがちですが、たまにAndroidやPythonなどの案件も頂くことがありました。
自分的にも最新の技術や様々な言語を触りたいと思っているのでありがたい限りです。
そんな自分の備忘録のためでもあり、何から始めたらいいかわからない方の参考になればなと思いQiitaに記事を書こうと思いました。

この記事は、PokeAPIを使用してポケモン図鑑を表示するAndroidアプリを作成するための環境構築編になっております。
なぜAndroidで作成するかというと以下の理由があります。
* 自分のパソコンがMacではないため、Swiftが使えない（いつかSwiftで開発してみたい）
* アプリ開発は実装してすぐに画面に反映されるので楽しい
* 自分はiOSではなくAndroid保有者のため

今回はAndroid Studioで作成しますが、いつかはSwiftだったりFlutterなどで開発をしたいと思っております。

# PokeAPI とは
PokeAPIとは、ポケモンに関する様々なデータが取得できるAPIです。
図鑑番号、名前、タイプ、画像、高さ、重さ　etc.
（[公式サイト](https://pokeapi.co/)）

**使用方法**
以下のURLの最後にポケモンの図鑑No or 名前(英名)を指定することで情報を取得できます。
ピカチュウだとこんな感じです。
```
https://pokeapi.co/api/v2/pokemon/25
https://pokeapi.co/api/v2/pokemon/pikachu
```
# 環境構築をしよう
- Gitの環境構築
Gitは絶対必須ということはないのですが、エンジニアの仕事では大体Gitを使っていたりポートフォリオとしてもGitは使えるので覚えていて損はないと思います。
以下にGitの環境構築のリンクを貼っておきます。

https://www.sejuku.net/blog/73444

- Android Studioの環境構築
今回はAndroidアプリで作成するのでAndroid Studioをインストールしましょう。

https://codezine.jp/article/detail/15981

# 最後に
今回はPokeAPIを使用したAndroidアプリ開発の環境構築を行いました。
環境構築は初心者の方は結構躓くと思いますが、ここを乗り越えれば結構楽です！（多分）

つたない文章だったと思いますが、ここまで見ていただきありがとうございます。
次回、設計編でお会いしましょう。
コマンドプロンプトとパワーシェルでフォルダをひとつずつ圧縮／ＺＩＰファイルを解凍する

全てのフォルダをひとつずつ圧縮
```bat
for /d %%f in (*) do (powershell -command "Compress-Archive -Path %%f -DestinationPath %%f.zip")
```

<br>
<br>

ＺＩＰファイルををまとめて解凍
```bat
for %%f in (*.zip) do (powershell -command "Expand-Archive -Path %%f -DestinationPath %%~na/../")
```
vscodeで、JavaScriptだけでなくNode.jsとしても構文チェックをできるようにする

## 最初の状態
Node.jsのソースをvscodeで開くと、例えばメソッドの終わりの中かっこを消すと赤線が出てファイルも赤く表示されるが、未定義の変数に対して代入しようとしても、赤線も何も表示されずファイルも赤くならない。

この状態だと、Node.jsを実行してからじゃないとエラーに気づけない。

## 解決方法
- まずは、npmからeslintをインストール
※ESLintは、「JavaScript のための静的検証ツー」
```
sudo npm install -g eslint
```

- vscodeでも拡張機能として、ESLintをインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179803/799e8f8a-22aa-af48-0bc2-3817764e5c9f.png)

- eslintを使えるようにするために、設定ファイルを作成(.eslintrc)
① ecmaVersionはサポートしたいesのバージョン。常に最新にする
②envの中は、es6をtrueにして、サポートを広げる。nodeのtrueは、これをしないとNode.jsとして扱ってくれない。requireを書いたら未定義エラーが出る。これを書いたらNode.jsの開発でもエラーが出なくなる。
③「 "no-undef": "error"」は、未定義の変数を使おうとしたら赤線を表示するようにしている。これがないと赤線が表示されずエラー扱いにならない
```json:eslintrc
{
    "parserOptions": {
        "ecmaVersion": "latest"
    },
    "env": {
        "es6": true,
        "node": true
    },
    "rules": {
        "no-undef": "error"
    }
}
```

★このように、自分でカスタマイズしていくイメージ

## 感想
特にNode.jsはブラウザで動く通常のJavaScriptとは違ってサーバーを起動するので、ちゃんとエラー処理しとかないとエラーになってサーバが落ちるので注意。
try-catchで囲っていれば大丈夫かもしれないが、APIによっては再実行しすぎると制限が来る場合もあるので、自分が個人で運用してるシステム的にはただいつでも再実行したらいいってわけでもない状況なので慎重に対応しています。

## 参考記事
https://runebook.dev/ja/docs/eslint/rules/no-undef

https://stackoverflow.com/questions/42706584/eslint-error-parsing-error-the-keyword-const-is-reserved
クレヨン風の地図

## はじめに

クレヨンで書いたような地図を作ってみたくなり、国土地理院の[最適化ベクトルタイル](https://github.com/gsi-cyberjapan/optimal_bvmap)と [Mapbox GL JS](https://github.com/mapbox/mapbox-gl-js)（[Maplibre GL JS](https://github.com/maplibre/maplibre-gl-js) も可）で実装してみました。

![クレヨン日本.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2842832/9a26250e-82b0-9ac1-9606-3f301313695b.png)
![クレヨン東京.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2842832/45b86455-477a-f426-330b-8f40ac8dadcf.png)
![クレヨン岳南.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2842832/6d2a00be-da11-1ef6-1655-03d115245165.png)

### デモサイト

https://mghs15.github.io/crayon-style-map/

以下は手書き地図記号付き

https://mghs15.github.io/crayon-style-map/?style=style-with-icon

## 実装方法

スタイルで `line-pattern` を用いて実現します。これで画像をラインに沿わせて表示させることができるようになります。シームレスなパターンを表示するには、画像の幅は２の累乗とした方が良いです。

```JavaScript
{
  "type": "line",
  "source": "v",
  "id": "hoge",
  "source-layer": "WL",
  "layout": {},
  "paint": {
    "line-width": 6,
    "line-opacity": 1,
    "line-pattern": "sky"
  }
},
```

なお、`line-pattern` で参照する文字列は、画像は Map インスタンスで取り込んでおく必要があります。本当は sprite 形式で取り込んだ方が通信時のオーバーヘッドを抑えられますが、今回は簡易的に画像を１枚ずつ読むことにします。

また、取り込むのは最初に利用される時とします。参照した画像データがないときに発火する `styleimagemissing` という便利なイベントがあります。これを利用して、このイベントが起きた時（つまり、スタイルで最初に利用される時）に、`loadImage()` で画像を読み込み、`addImage()` でスタイルで使えるように登録します。

```JavaScript
map.on('styleimagemissing', (e) => {
  const crayon = e.id;
  map.loadImage(`./crayon/${crayon}.png`, (error, image) => {
    if(error) throw error;
    if(!map.hasImage(crayon)) map.addImage(crayon, image);
  });
});
```

## パターン用画像の準備

パターン用の画像は簡易的に準備しました。

Windows の「ペイント」ツールでクレヨン風の線を引けるので、これを PowerPoint に取り込んで、トリミングと背景の透過を行います。トリミングの大きさは結構適当です。上で、「画像の幅は2の累乗とした方が良い」と書きましたが、今回の場合は、適当でも見栄えは悪化しませんでした。

なお、`line-pattern` では、色を変えることはできないので、必要な色の分だけ、画像を作っておきます。とりあえず、ペイントのパレットにあった内から12色分くらい作りました。

![crayon-paretto.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2842832/04ab4631-be7e-f2ec-3919-692642e99698.png)


水面だけ、ポリゴンの塗りつぶし用パターンを作成しました。これは、地理院の最適化ベクトルタイルでは、一部のズームレベル帯でポリゴンのみで海岸線を表現しているからです。

ポリゴンの外周をラインとして表示させるテクニックもありますが、この場合、下記の画像のように、ポリゴンに切れ目があると目立ちます。地理院の最適化ベクトルタイルの水面データは、適宜分割されているようですので、関係ないところに線が入ってしまい、かっこ悪いです。そのため、水面だけクレヨン風の塗りつぶし表現とすることにしました。

![crayon-wa-line.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2842832/38d069fe-0a00-e60e-8e90-afb9aa396610.png)


塗りつぶしの場合、ラインのパターンと違い、きっちり作らないと敷き詰めた際に境界が目立ってしまいます。これをなくそうとすると、ペイントと PowerPoint だけでは厳しいです。今回はある程度で妥協しました。


## スタイリングの工夫点

* クレヨンなので、線が細くなりすぎないようにし、また地物の種別毎にあまり太さを変えないようにしました。一方、等高線はうるさくなりすぎるので、色を薄く、太さも補足しています。
* 鉄道は縞々模様（旗竿）を採用しました。クレヨンで書いた線の上に、通常の白色の点線を重ねています。実際クレヨンでこんな細かい芸当は難しいだろうと思いましたが、思いのほかしっくりくるほか、引き締まって見えます。
* 建物は、通常のスタイルで薄く塗りつぶしてみました。建物一つ一つはそんなに大きくないため、普通のべた塗でもあまり違和感は感じないです。

## レポジトリ

https://github.com/mghs15/crayon-style-map

## 最後に

手軽に作りましたが、思ったよりクレヨン感が出ていて満足しています。塗りつぶしは今回は色々と妥協しましたが、例えば、クレヨン線画の上から水彩絵の具を塗った時のようなイメージで、良い感じの表現が工夫できそうな気がします。

## 参考

https://docs.mapbox.com/mapbox-gl-js/style-spec/
【Linux】ファイル名のみを取得する方法

## ファイル名のみを取得
ファイル名のみを取得するには以下のコマンドを実行します。
```zsh
basename /path/to/file
```

```zsh
$ basename /home/user/sample/sample.txt
sample.txt
```

また以下のように実行すると拡張子を除いた部分を取得できます。

```zsh
$ basename /home/user/sample/sample.txt .txt
sample
```
PowerAutomate: Mail の転送を判断付きで行う。

# 背景

社内では、無駄と思えるMail転送文化がまだあります。
ってことで、以前作った、Teams 転送を Mail に応用しよう、というお話

https://qiita.com/baku2san/items/f6cfd62ab95fa2e306d4

# 概要
基本は、以前のTeams用フローをコピーして、以下を変更する程度

1. Trigger を mail 受信へ
    - [新しいメールが届いたとき (V3)](https://learn.microsoft.com/ja-jp/connectors/office365/#%E6%96%B0%E3%81%97%E3%81%84%E3%83%A1%E3%83%BC%E3%83%AB%E3%81%8C%E5%B1%8A%E3%81%84%E3%81%9F%E3%81%A8%E3%81%8D-(v3)) へ
        - 送信者とかメールタイトルでフィルターはしておく必要有。例えば、【公文】みたいなものとか。
1. Message 内容を Mail 用へ: body/content → body へ
    - 前<br><code>@{replace(triggerOutputs()?['body/body/content'],decodeUriComponent('%0A'),'')}</code>
    - 後<br><code>@{replace(triggerOutputs()?['body/body'],decodeUriComponent('%0A'),'')}</code>
1. 転送判断用のAdaptive Card はお好みに合わせて修正。とはいえ、今回はこのまま。


# あとがき
意外にあっさり流用出来たんで、記述は省略。
【JavaScript】Qiitaトレンドのプロフィール画像をマウスオーバーした時にプロフィールをツールチップで表示する

### 【概要】
Qiitaトレンドのプロフィール画像をマウスオーバーした時に、マウスオーバーしたユーザのプロフィールをツールチップで表示します。
開発者ツールのコンソールでコードを実行することで実現します(Chromeの拡張機能にした方がよかったかも)。

### 【環境】
Google Chrome

### 【コード実行時の注意点】
Qiitaトレンドのプロフィール画像領域や、ツールチップに表示するユーザ画面のプロフィール領域はCSSクラス名で取得しています。
そのCSSクラス名はおそらく自動生成されているため、今後下記コード内で定義しているクラス名を変更する必要がある可能性があります。

### 【コード】

#### 準備用
```javascript
const importScriptArray = [
  "https://code.jquery.com/jquery-3.6.4.min.js",
  "https://unpkg.com/@popperjs/core@2",
  "https://unpkg.com/tippy.js@6",
];

const fragment = document.createDocumentFragment();
for (importScript of importScriptArray) {
  const script = document.createElement("script");
  script.src = importScript;
  fragment.appendChild(script);
}

document.body.appendChild(fragment);
```

#### メイン処理
```javascript
$(function () {
  // Qiitaトレンドのプロフィール画像領域のクラス名
  const profileImageClass = ".style-j198x4";
  $(profileImageClass).mouseover(function () {
    callTippy(this);
  });
});

function callTippy(profileImageElement) {
  tippy(profileImageElement, {
    content: "Loading...",
    onShow(instance) {
      fetch($(profileImageElement).attr("href"))
        .then(function (response) {
          return response.text();
        })
        .then(function (data) {
          // ツールチップに表示するユーザ画面のプロフィール領域のクラス名
          const userProfileClass = "style-y3rr1o";

          // ツールチップに表示するhtmlの作成
          const parser = new DOMParser();
          const doc = parser.parseFromString(data, "text/html");
          const userProfile = doc.getElementsByClassName(userProfileClass)[0];
          const profileHead = doc.head;
          const tooltipContent = document.createElement("html");
          tooltipContent.append(profileHead);
          tooltipContent.append(userProfile);

          instance.setContent(tooltipContent);
        })
        .catch((error) => {
          instance.setContent(`Request failed. ${error}`);
        });
    },
  });
}
```

### 【実行手順】
#### 1. [Qiitaトレンド](https://qiita.com/)を開く
ログインしてない場合で説明します。ログインしている場合のリンク先は、添付画像とは別の画面表示になっています。
ただし、ログインしている場合も同様の手順で実行できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121997/6296b4c9-7861-ca4e-f670-db2dd998f5c8.png)

#### 2. 開発者ツールを起動し、コンソールタブを開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121997/9abf63f8-5a96-e268-a649-edfbaf84cebe.png)

#### 3. 準備用のコードをコンソールに貼り付けて実行する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121997/88e2ed7a-43c9-5e00-e2ec-a23fcb02cbcd.png)

#### 4. メイン処理のコードをコンソールに貼り付けて実行する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121997/f54f70e4-345f-0b8e-5345-8ae7a91a338f.png)

### 【実行結果】
プロフィール画像をマウスオーバーすると、プロフィールがツールチップで表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121997/e74e952b-6d57-222d-97be-99ed41a12176.png)

### 【参考サイト】
[Tippy.js](https://atomiks.github.io/tippyjs/)
VPCエンドポイントまとめ

# VPCエンドポイント概要
プライベートサブネットに設置して使用するAWSサービスと通信するためのエンドポイント

:::note
インターネット（インターネットゲートウェイ）経由で通信せずとも、特定のAWSサービス（S3・CloudWatchなど）を接続したい場合に使用
:::

* アクセス負荷に応じて自動スケール

### インターフェース型（Private Link、インターフェースエンドポイント）
実態はENI（セキュリティグループを設定する。）
* 料金は有料
* AZごとに設置必要あり
* ECRやCloudWatchが対象

### ゲートウェイ型
ルートテーブルに自動設定される
* 料金は無料
* S3やDynamoDBが対象
Cloudflare Tunnel (cloudflared) の管理をローカルから Cloudflare 側に移行する

# 目的

以下の内容で発表があったものになりますが、ローカルで管理している設定をCloudflareで管理している設定へ、シームレスに移行できるか確認します。

- [驚くほど簡単に使えるTunnel](https://blog.cloudflare.com/ja-jp/ridiculously-easy-to-use-tunnels-ja-jp/)

> この考えから、これまでターミナルで最大14個のコマンドを必要としたトンネルの作成を、たった3つの簡単なステップで、Zero Trustのダッシュボードから直接行えるようになったことを、本日発表いたします。
...
本日のリリースにより、ユーザーは設定ファイルやトークンをローカルで管理する必要がなくなりました。これからはお客様がZero Trustダッシュボードで提供した入力に基づいて、Cloudflareがお客様に代わって管理します。
...
現在、ローカルで管理している設定をCloudflareで管理している設定へ、シームレスに移行するためのツールを構築中です。数週間後にはご利用いただけるかと思います。

# 移行

ダッシュボードからローカル管理の Cloudflare Tunnel を `Configure` します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/6aacecbb-6d2a-6f4b-c95a-bd556a50e45f.png)

移行に関する注意書きをよく読んでから、 `Start migration` に進みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/ff5e375d-5524-fcee-ac33-aeadeee9b5da.png)

> khayama-tunnelの移行
khayama-tunnelはローカルに設定されたトンネルであるため、ゼロトラストダッシュボードから管理することはできません。
ただし、ダウンタイムを引き起こすことなく、そのイングレスルールをダッシュボードから管理するように移行することができます。構成ファイル上の他の構成は移行されず、ローカルで行った変更はダッシュボード上に反映されません。
トンネルの移行が不可逆であることを忘れないようにしてください。

ローカル管理情報から読み込んできた設定に間違いがないかを確認して進めます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/9575551d-bae0-b66a-62fc-222ba6912db7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/9b2cdc20-590b-c54a-1a14-800fbe01f97b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/740d4654-87c9-4521-80ff-2906b257532f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/19eca47e-c3f1-8254-9118-b00002d07a30.png)

最後に移行は不可逆だが、本当に移行するか？と聞かれるので確認して `Migrate tunnel` します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/a3070a00-4b70-e6e0-6645-a8874624fd0a.png)

その後は「Tunnel successfully migrated!」と画面右上に即時表示があり、移行完了です。

晴れて、UI から確認・編集できるようになりました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/803f3179-2803-ae9f-1af6-a1dd2ebbfa76.png)

以上。