OmniAICreator/Qiita-1.07M huggingface dataset:
Scalatra3.0.0-M2を動かした

# 目的
Scalatra3.0.0-M2を動かすにあたり、`sbt new scalatra/scalatra.g8`したところ、動かない箇所がいくつかあったので忘備録。なおTwirlは要らないのとライブラリがConflictして動かなかったので全部削除している。

なおJettyPluginをContainerPluginに変更すると`jetty:start`は`container:start`に変わる。

## build.sbt
```scala
val ScalatraVersion = "3.0.0-M2"

// Scala3系に対応したので最新のScalaにしてみた
ThisBuild / scalaVersion := "3.1.3"
ThisBuild / organization := "com.ponkotuy"
// いつもの。おこのみで
ThisBuild / scalacOptions ++= Seq("-unchecked", "-deprecation")

lazy val hello = (project in file("."))
  .settings(
    name := "Photographic Indexer",
    version := "0.1.0-SNAPSHOT",
    libraryDependencies ++= Seq(
      "org.scalatra" %% "scalatra" % ScalatraVersion,
      "org.scalatra" %% "scalatra-scalatest" % ScalatraVersion % "test",
      "ch.qos.logback" % "logback-classic" % "1.2.3" % "runtime",
// Jettyが11にアップデートしたので対応する
      "org.eclipse.jetty" % "jetty-webapp" % "11.0.11" % "container",
// Jetty11はjakartaになったのでこちらもjavax.servletから変更
      "jakarta.servlet" % "jakarta.servlet-api" % "5.0.0"
    )
  )

// TwirlはConflictしていたのと使わないので一旦削除
// JettyPluginはJettyが9.x系なのでpluginを自作する必要がある
enablePlugins(ContainerPlugin)

val jettyRunner = "org.eclipse.jetty" %  "jetty-runner" % "11.0.11"

Container / containerLibs := Seq(
  jettyRunner.intransitive()
)
Container / containerMain := "org.eclipse.jetty.runner.Runner"
```

## ScalatraBootstrap.scala
```scala
import com.ponkotuy.app._
// javaxからjakartaに変わったので変更する
import jakarta.servlet.ServletContext
import org.scalatra._

class ScalatraBootstrap extends LifeCycle {
  override def init(context: ServletContext): Unit = {
    context.mount(new MyScalatraServlet, "/*")
  }
}
```

## CORS
多分CORSまわりがバグってる？ようで、Cross-Originのアクセスに必要なヘッダが付与されないので、自前で設定する必要がある。localhostだけ許可するみたいな要件だと、こんな感じのtraitを作って必要なハンドラに食わせる。
```scala
trait CORSSetting { self: ScalatraServlet =>
  val Localhost = "\\Ahttp://localhost(:\\d+)?\\z".r
  before() {    
    val origin = Option(request.getHeader("Origin"))
    if(origin.exists(Localhost.matches)) {
      response.setHeader("Access-Control-Allow-Origin", origin.get)
    }
  }
}
```

## plugins.sbt
たぶん書き換えしなくても動く
```scala
// Twirlは使わないので削除していい
// 4.2.4が最新なので一応
addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "4.2.4")
```
vue+aws amplifyのプロジェクトをviteで立ち上げたら表示が消えた(global is not defined)

作成日: 2022/08/30
### TL;DR
viteでdev serverを立ち上げてlocalhostにアクセスした時に`global is not defined`が出たらindex.htmlに`<script>window.global　= window;</script>`を追加する。

## 以下詳細
### 実行環境
```
aws-amplify@4.3.33
vue@3.2.37
vite@3.0.9
vitejs/plugin-vue@3.0.3
vitest@0.21.1
```

### 何があったのか
`npm init vue@latest`でviteを使用するプロジェクトを作成後に`npm run dev`をするとviteで開発用のサーバーが立ち上がり、本来は以下のような画面が表示されます。
![vite+vue3でプロジェクトを作ると最初に出てくる画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327331/522baf0c-b842-7e37-2919-3d979fd563f3.png "vite+vue3でプロジェクトを作ると最初に出てくる画面")

その後、aws amplifyを使用するために`npm install aws-amplify`して再び`npm run dev`するとviteのサーバーは問題なく立ち上がるものの、ブラウザは真っ黒になり、コンソールに以下のようなエラーが出ました。
```
Uncaught ReferenceError: global is not defined
    at node_modules/amazon-cognito-identity-js/node_modules/buffer/index.js (index.js:43:30)
    at __require2 (chunk-IKJM6GHQ.js?v=a6d83f4a:18:50)
    at AuthenticationHelper.js:5:24
```

![何も表示されなくなった画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327331/b2b8fa16-ab26-ec4d-e8c7-0592ad049748.png "何も表示されなくなった画面")


### なぜこうなるのか？
webpackの使用を想定した一部のライブラリではグローバルオブジェクトとして`global`が使用されていますが、viteでは定義していないので、別途`window.global`を定義する必要があるそうです。

https://stackoverflow.com/questions/72114775/vite-global-is-not-defined

### どう解決する？
`index.html`の中に以下を記述する。

```
  <script>
    window.global　= window;
  </script>
```
jsはjsで纏めたた方が綺麗そう？とは思うものの、index.html以外でちゃんと動作する場所が見つけられませんでした。

## 余談
windowとかglobalとかよくわからなかったので、ついでに調べてみました。

#### windowとは
ブラウザでjavascriptを実行した時に、グローバルなオブジェクトが所属するオブジェクトだそうです。例えば、varで変数を宣言すると、windowオブジェクトのプロパティとしてその変数にアクセスすることができます。

```
var test = 1;
window.test === test;
> true
```
(※letやconstで宣言されたものはブロックスコープで、windowオブジェクトのプロパティにはならない)

#### window.globalとは
MDNによると、

> Node.js で実行されるスクリプトの場合、 global と呼ばれるオブジェクトがグローバルオブジェクトになります。

だそうです。

https://developer.mozilla.org/ja/docs/Glossary/Global_object


https://nodejs.org/api/globals.html#globals_global

webpackのdev-serverがnodeをrequiredとしているので、
倣ってwebpackでもグローバルオブジェクトは`global`になっているものと考えられます(webpackのgithubを見てみたりしたものの、自分の知識ではどこで定義されてるのかはよくわかりませんでした。node側なんでしょうか)。
React入門 importを整理してみる

# この記事について
この記事は、Reactを書き始めた人なら感じるimportの多さを解決することを手助けするために書きました。
関数コンポーネントやApp.jsがこんな風に前半がごちゃついていませんか？
```
import { useState, useEffect } from 'react';
import Navbar from './components/Navbar';
import Feed from './components/Feed';
import VideoDetail from './components/VideoDetail';
import SearchFeed from './components/SearchFeed';
import ItemsList from './components/ItemsList';
....

const App = () => {
    return(
        <>App</>
    )
};
```

これをシンプルにしていきましょう！
あまり長々書いても仕方ないので、早速始めます！

# 完成図
```
import { useState, useEffect } from 'react';
import { Navbar,Feed, VideoDetail, SearchFeed, ItemsList } from './components'

const App = () => {
    return(
        <>App</>
    )
};
```

パッと見ても上部importが軽くなり、見やすくなりましたね。
では手順です。

#### 1. componentsフォルダ直下にindex.jsを作成
#### 2. index.jsに以下のように記述する
```
export { default as Navbar } from "./Navbar";
export { default as Feed } from "./Feed";
export { default as ChannelDetail } from "./ChannelDetail";
export { default as SearchFeed } from "./SearchFeed";
export { default as VideoDetail } from "./VideoDetail";
...
```

たったこれだけです！
あとは[完成図](#完成図)のようにimport側でまとめて呼び出すことができます。

以上、Reactのimport部分を整理してみる。でした！
Pythonの便利技と注意点:print編

[目次に戻る](https://qiita.com/yuta-sanjyo/items/416b05f8498df1ed3f49)

# intを格納した変数を文字列と一緒に表示する技
```py:+記号を使うとエラーが出る
>>> num = int(input('How many do you have?'))
How many do you have?3

>>> print('You have ' + num + '.')
Traceback (most recent call last):
  File "<pyshell#46>", line 1, in <module>
    print('You have ' + num + '.')
TypeError: can only concatenate str (not "int") to str
```
```py:,でつなげるとエラーは出ない。但し、各項目ごとに自動でスペースが入る
>>> print('You have', num, '.')
You have 3 .
```

[目次に戻る](https://qiita.com/yuta-sanjyo/items/416b05f8498df1ed3f49)
MacのターミナルでGoogleドライブ下のjpgファイルをpngファイルにする方法。

# はじめに
初めてのQitta投稿です。
Googleドライブに保存してあるjpg画像をpng画像に変換してみたので、ここにまとめます。

# 動作環境
Model Name: Mac mini
Chip: Apple M1

# ツリー構成
(実際のツリー構成とは異なります。)
> ホームフォルダ/
>├ Google Drive/
>　|└　その他のパソコン
>　|└　マイドライブ
>　|　　　└　画像
>　|　　　　　　└file1.jpg
>　|　　　　　　└file2.jpg
>　|　　　　　　└file3.jpg

# (1)ImageMagickのインストール
パッケージ管理システムHomebrewを操作するコマンド「brew」を使って、ImageMagickをインストールします。

    brew install imagemagick

ImageMagickは、UNIX系OSのフリーのグラフィックソフトです。フォーマットやサイズ変換、画面ショットの作成などのグラフィック処理に重宝されます。

# (2)ディレクトリの移動

    % cd ~/    #ホームフォルダに移動する
    % cd "Google Drive"/マイドライブ/画像    #作業対象のフォルダに移動する

「Google Drive」のように、空白文字を含むフォルダを扱う場合、ダブルクォーテーションで囲みます。

    % ls    #カレントフォルダにあるファイルを表示する
    file1.jpg    file2.jpg    file3.jpg
# (3)拡張子の変換
ImageMagickは、magickコマンドにサブコマンドを指定して処理を行います。
今回は、convertサブコマンドを使います。convertサブコマンドは、イメージのフォーマットやサイズなどを変換したりフィルタリングしたりするコマンドです。

    % magick convert *.jpg file.png    #jpgの拡張子を持つ画像ファイルをまとめてfile.pdfという名前で保存する
    % ls
    file-1.png    file-2.png    file-3.png
    % rm *.jpg    #元のjpg形式の画像ファイルを削除する

### 参考資料
・大津 真(著)『エンジニアなら知っておきたいｍａｃＯＳ環境のキホン―コマンド・Ｄｏｃｋｅｒ・サーバなどをイチから解説』
https://www.kinokuniya.co.jp/f/dsg-01-9784295015031
【MySQL】DELETEとTRUNCATEのざっくりとした違い

はじめに
--
ポートフォリオ作成中に、DBの中身を確認したり弄ったりすることが多いのですが、データを削除するコマンドを調べると"truncate table ~"が出てきました。
MySQLのコマンドに対しての知識が皆無だった時の自分がこのコマンドを見たときは、「イメージだとdeleteって単語を使いそうだけど違うのか」となんとなく疑問に思いながら、"truncate"を使っていました。

デリケートなDBを扱うコマンドをなんとなくで使ってるのも恐ろしいなと思ったので、調べたことを備忘録として残そうと思います。

DELETEとは
--

> DELETE は、テーブルの行を削除する DML ステートメントです。
> [公式ドキュメント](https://dev.mysql.com/doc/refman/5.6/ja/delete.html)より引用

上記の文章の通り、deleteはテーブル内のデータの行を指定して削除することが可能なようです。
そして、もちろん選択範囲をテーブル内全てにすることで削除することが可能です。

~~~mysql
#全レコードを削除
DELETE FROM "テーブル名";

#usersテーブル内の全レコードを削除
DELETE FROM "users";
~~~

~~~
#色々なコマンド(whereやupdateなど）を使って条件を絞って削除することができる
DELETE FROM "テーブル名"　WHERE "主キー項目(PK)" = "値"　;

#usersテーブルのidが10の行を削除
DELETE FROM "users"　WHERE "id" = "10"　;
~~~
※主キーについての説明は[こちら](https://wa3.i-3-i.info/word1991.html)

またDELETE文はコミット前であればロールバックが可能です。

TRUNCATE TABLEとは
--
TRUNCATE TABLEは条件指定など行わず、テーブル内のデータを全て削除します。
確実にテーブル内を全削除するので、"TRUNCATE"ではなく、"TRUNCATE TABLE"までで1セットみたいですね。
（公式ドキュメントの見出しもTRUNCATE TABLE 構文って書いてあったので）

ただ削除するだけなら、全部DELETE使えばいいじゃんってなるかもしれませんが、もちろん理由がありました。
それは、"DELETE"よりも"TRUNCATE TABLE"の方が早く削除ができることです。
なので全データを削除する際には"TRUNCATE TABLE"が推奨されているようです。

> 切り捨て操作はテーブルを削除して再作成するため、特に大きなテーブルの場合は、行を 1 つずつ削除するよりはるかに高速です。
> ※[公式ドキュメント](https://dev.mysql.com/doc/refman/5.6/ja/truncate-table.html)より引用

注意点は、ロールバックが行えないことです。

> 切り捨て操作は暗黙的なコミットを発生させるため、ロールバックできません。
> ※[公式ドキュメント](https://dev.mysql.com/doc/refman/5.6/ja/truncate-table.html)より引用

~~~
#テーブル内のデータを削除
TRUNCATE TABLE テーブル名;

＃usersテーブル内のデータを削除
TRUNCATE TABLE users;
~~~

僕が全データを削除するコマンドを探していたので最初に"DELETE"ではなく、"TRUNCATE TABELE"の記事がヒットしたんですね！

終わりに
--
本番環境で間違えてコマンドを叩いてデータを削除したらと考えるだけで恐ろしいですね。

今は使う場面が限られていたので"TRUNCATE TABLE"のみを叩けば問題なかったのですが、
将来のことを考えるとしっかりコマンドを全体的に理解するべきだと感じました。

参考
--
https://dev.mysql.com/doc/refman/5.6/ja/truncate-table.html
UnityUI/ListView


# これがわかりやすかった。

https://anz-note.tumblr.com/post/162593484961/unityuitableview%E3%81%A3%E3%81%BD%E3%81%84listview%E3%82%92%E3%81%A4%E3%81%8F%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F

# その他

https://zenn.dev/daichi_gamedev/articles/2109cbfea057ad

https://www.am10.blog/archives/340

https://tech.pjin.jp/blog/2016/08/30/unity_skill_3/
MetaMaskにRinkeby(テスト用ネットワーク)イーサリアムを入金してみた

開発で必要になったので、Rinkebyテストネットワーク用イーサリアムを入金してみました。そのときの手順をリマインダ的に記事にします。

## MetaMaskの準備
今回はPC(Windows)からChrome拡張機能のMetaMaskをつかいました。
画面の「Download for (Chromeマーク)」をクリック。
![metamask01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88747/e0af2bf0-02a9-7cd6-4da2-586917077054.png)
chromeウェブストア画面になったら「Chromeに追加」をクリック。ウォレット作成の際にパスワードを設定します。さらにそのあとリカバリーフレーズ(12個の英単語からなる)がMetaMask側から提示されますので、これをメモして厳重に保管します。
![metamask02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88747/37728214-d258-bd88-7395-0e5352796bdb.png)
MetaMaskの準備ができました。
ここにテスト用イーサリアムを入金します。上の画面の赤く塗りつぶした部分がウォレットのアドレスになりますので、それをコピーしておきます。

## Rinkebyテストネットワーク用イーサリアムの入金
https://rinkebyfaucet.com/ を開きます。
![rinkebyfaucet01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88747/211c3318-4a4d-a91d-d8d5-fdc8a0b1376a.png)
このページでテスト用のイーサリアムをリクエストできます。
「Enter Your Wallet Address(0x...) or ENS Domain」の枠に、先ほどコピーしたMetaMaskウォレットのアドレスを貼り付け、「Send Me ETH」をクリック。私が実行したときは数秒で、MetaMaskに入金されました。

## MetaMaskで入金を確認
MetaMaskで入金を確認します。画面右上あたりに「イーサリアムメインネット」という記載があります。今はメインネット用イーサリアムの残高が表示されているので、これをRinkebyテスト用ネットワークに切り替えます。
下の画面の赤丸をクリックすると、ネットワーク切り替えメニューが開きます。
![metamask03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88747/2e4a201a-0f72-1966-4283-73e5995af7c2.png)
デフォルトでは、テスト用ネットワークに切り替えられませんでした。切り替えられるようにするために、まず上の画面の「表示・非表示テストネットワーク」をクリックします。
![metamask04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88747/9d2cab5f-7a6d-07f5-1e2e-39b124527ea2.png)
MetaMaskの設定メニューが開かれるので、
「テストネットワークを表示」のスイッチをオフからオンに変更します。そのうえでもう一度画面右上のネットワーク切り替えメニューを開くと、
![metamask05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88747/e2d6d389-5094-4023-2f9b-4ad7ba1c9d11.png)
テストネットワークが選択できるようになったので、「Rinkebyテストネットワーク」を選択すると、0.1 RinkebyETHが入金されていることを確認できました！

MetaMask、Rinkebyの画面は2022/8/31現在のもので、変更される可能性があります。特にRinkebyテストネットワークは近々終了するとのことで、新しい「Goerliテストネットワーク」をつかうのがよいかもしれません。
TypeScript で型安全な 日付型を作る

# はじめに

`2022-08-30` のような文字列を `/\d\d\d\d-\d\d-\d\d/` という正規表現を満たす型として表現出来ないかで悩んでいたところ、同僚から [TypeScript: Type Safe Date Strings](https://javascript.plainenglish.io/type-safe-date-strings-66b6dc58658a) という記事を教えてもらったので、この記事を参考に型安全な日付型を実装してみました。

# 日付を構成する要素を型で表現する

日付は、`年` , `月`, `日` という要素に分解できるので、まずはこれらを型で表現することを試みます。

## `年` , `月`, `日` 型

TypeScript は [Template Literal Types](https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html) をサポートしており、`${}` で リテラルのUnion型を展開することが出来ます。

`年` は上位２桁について(200年に限定すると) `19 | 20` 、 下位２桁は `00 ～ 99` 、それぞれの桁は `0-9` であるため、Template Literal Types を使い以下のように定義出来ます。

```typescript
type d = 1|2|3|4|5|6|7|8|9|0;
type YYYY = `19${d}${d}` | `20${d}${d}`;
```

`年` 型とほぼ同様に、`月` 、 `日` 型も以下のように表現できます。

```typescript
type oneToNine = 1|2|3|4|5|6|7|8|9;
type MM = `0${oneToNine}` | `1${0|1|2}`;

type DD = `${0}${oneToNine}` | `${1|2}${d}` | `3${0|1}`;
```

# Day型を作る

Date型はオチがあるので、まずは Day型を作ります。

```typescript
class Day {
  static isDayString(day: string): day is DD {
    return !!day.match(/\d\d/)
  }

  private _day: DD | undefined

  constructor(day: string) {
    if (Day.isDayString(day)) {
      this._day = day
    }
  }
}
```

[Type Guard](https://typescript-jp.gitbook.io/deep-dive/type-system/typeguard#yznotype-guard) を使い、`day: string` を `DD` 型に絞り込みますが、`DD` 型は [Template Literal Types](https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html) で展開され、 `01` ～ `31` までのリテラルのUnion型が定義されました。

筆者のVSCode上でも展開された状態で表現されています。

![Screenshot 2022-08-31 002852.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18977/080ec107-5b7c-d0d3-4ac7-641e6a9b8b93.jpeg)

# Date型を作る

ここまで来たらオチがわかったかもしれませんが、ひとまずDay型と同様にDate型を作ってみます。

```typescript
export type DateYMDString = `${YYYY}-${MM}-${DD}`;

export class Date {
  static isDateYMDString(date: string): date is DateYMDString {
    return !!date.match(/\d\d\d\d-\d\d-\d\d/)
  }

  private _date: DateYMDString | undefined

  constructor(date: string) {
    if (Date.isDateYMDString(date)) {
      this._date = date
    }
  }
}
```

上記のコードでコンパイルなどは通ると思いますが、IDE上で入力すると、突然CPUが唸り声をあげるかもしれません。

![Screenshot 2022-08-31 003945.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18977/c8beaab1-c26b-03dd-7fe7-f2cd6bc517c2.jpeg)

IDE上ではDay型と同様に  [Template Literal Types](https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html) で `1900-01-01` ～ `2099-12-31` まで、 75000近くのリテラル型が展開されました。

# 実用上使えるか

常識的な感覚だと、75000近くのリテラル型が展開されるのは多く感じますし、TypeScript側でも 100'000 までしかサポートされていないということです。
`1900-01-01` ～ `2099-12-31` まで200年近くしか対応できていないのに、上限に近づいているということで、  [Template Literal Types](https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html) で型安全な日付型を作るのは、実用的な面でいうと厳しいと感じました。

また、別の方法などありましたら、コメントいただけると幸いです。
開発者が知っておくと便利なlinuxコマンド

開発していてよく使うorたまに使うコマンドを集めました。
一部linuxコマンドから外れるものもありますが便利なので加えてます。ご容赦を:pray:

### 通信
#### `ssh` 
暗号化通信するコマンド

よく使うオプションは`-i` `-p`


```shell
ssh -p 4649 -i .ssh/hogehoge.pem ec2user@10.254.142.33

# ssh <ログインするユーザー名>@<アクセス先IP>
# アクセスする際の認証ファイル`-i`
# ssh接続デフォルトのポート(22)以外を指定
```

### 権限

#### `chmod` 権限の変更

```shell
chmod 600 hoge.pem
ls -la
# -rw-------@
```
`600`で所有者**のみ**read+write権限を設定する
EC2などのpemキーなどの認証ファイルをセキュアにする設定する時によく使う

アプリケーションのログファイルに関するエラー(`permission denied`)の時は逆に権限を広くする

```shell
chmod -R 777 ./storage
# -Rでフォルダ内全ファイルの権限設定
```


### 日時確認
`2022年 8月30日 火曜日 22時55分31秒 JST`みたいに日時を表示できます。

```shell
$ date
```

### ファイル監視

#### `less` リアルタイムでファイル表示(単体)
ファイル内容を1画面分ずつ表示するコマンド
オプションをつけることでリモート環境のログファイルを監視する時とかに役立つ

```shell
less laravel.log
```
ファイル出力中に`shift F`でファイル監視モードに入れる(ctr C で監視解除)
最初から監視モードで開きたい時は下記

```shell
less +F laravel.log
```


#### `tail` ファイル末尾表示
ファイルの末尾(デフォで10業)を表示

`-f`オプションででファイル監視できるが、lessのように監視モードの切り替えができない
ただ、複数ファイルの監視をしたい時は時には以下のようにして使える

```shell
tail -f *log
```

### コマンド実行

#### `cron` 定期実行

```shell
# 編集
crontab -e

# 左から 分/時/日/月/曜日 で設定
*/3 * * * *  sh date.sh

# 設定の確認
cron -l
```
インストール方法などは[こちら](https://qiita.com/ponsuke0531/items/3e82df8bd8412983cb33)を参考に

設定しても実行されない時は下記コマンドで再起動

```shell
sudo systemctl restart cron
```

#### 一定間隔でコマンド実行
cron設定するほどでないケースで繰り返し実行したい時に便利


```shell
watch -n 5 date
# 5秒間隔で日時表示
```

### ファイル操作

#### mv ファイル移動
タッチパッド操作での移動が煩わしいケースではmvが便利

```shell
mv ./*.png ./images/
# カレントディレクトリの.pngファイルをimagesフォルダへ移動

# カレントディレクトリの全ファイルをimagesフォルダへ移動
mv ./* ./images/
```
#### `zip` ファイル圧縮
フォルダ指定してファイル圧縮する。

```sh
zip -r [output file name] [target folder]
# ex) zip -r abc.zip ./abc

```
#### `unzip` ファイル解凍

```shell
unzip [file name]

# 解凍先を指定
unzip [file name] -d [target folder]
```

### インストール

#### brew
開発者ならお馴染みの`homebrew`
端末にデフォルトで備わってないコマンドをインストールするときにも使える

```
brew install tree
```
php-alpine 3.16でiconvを利用する

# はじめに
alpine3.13から3.16にアップデートする際にハマったので備忘録を作成。

alpine3.13ではiconvに不具合がありソースからインストールしていた。
https://blog.bagooon.com/?p=1516

```
RUN apk add --no-cache --virtual .build-deps \
        make \
        gcc \
        g++ \
    && curl -SL http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.15.tar.gz | tar -xz -C ~/ \
    && rm /usr/bin/iconv \
    && mv ~/libiconv-1.15 ~/libiconv \
    && ~/libiconv/configure --prefix=/usr/bin \
    && make \
    && make install \
    && rm -Rf ~/libiconv \
    && apk del .build-deps
 
ENV LD_PRELOAD /usr/bin/lib/preloadable_libiconv.so
```

この不具合が解消されているため、alpine3.16では別の方法で対応する必要がある。

# 設定の変更について
alpine3.16では事前にiconvが有効になっているため、自前でインストールする必要は無くなりました。
https://github.com/docker-library/php/issues/1272


`RUN docker-php-ext-install iconv`が記載されていて下記エラーが出ている場合、既にインストールされている可能性があります。  
```
#17 125.8/usr/src/php/ext/iconv/iconv.c:197:25: error: '_libiconv_version' undeclared (first use in this function)
#17 125.8   197 |                         _libiconv_version >> 8, _libiconv_version & 0xff);
#17 125.8       |                         ^~~~~~~~~~~~~~~~~
#17 125.8 /usr/src/php/ext/iconv/iconv.c:197:25: note: each undeclared identifier is reported only once for each function it appears in
#17 125.8 /usr/src/php/ext/iconv/iconv.c: In function '_php_iconv_appendl':
#17 125.8 /usr/src/php/ext/iconv/iconv.c:97:15: warning: implicit declaration of function 'libiconv'; did you mean 'zif_iconv'? [-Wimplicit-function-declaration]
#17 125.8    97 | #define iconv libiconv
#17 125.8       |               ^~~~~~~~
#17 125.8 /usr/src/php/ext/iconv/iconv.c:363:29: note: in expansion of macro 'iconv'
#17 125.8   363 |                         if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
#17 125.8       |                             ^~~~~
#17 125.9 make: *** [Makefile:208: iconv.lo] Error 1
```
インストール済みかチェックする場合、`docker run コンテナ名 php -m | grep iconv`を実行してインストール済みか確認する事ができます。

# ICUデータの入れ替え
alpine3.16から、ICUデータが２分割されて、`en` or `full`となりました。 　
デフォルトは、`en`となっているので、自前でfullをインストールする必要があります。  
インストール自体は、apkを利用できます。
下記実行しenを削除。fullをインストールします。
`RUN apk del icu-data-en && apk add icu-data-full`

https://wiki.alpinelinux.org/wiki/Release_Notes_for_Alpine_3.16.0#ICU_data_split
https://github.com/docker-library/php/issues/1302

# おわりに
原因究明、情報提供してくれた同僚に感謝。
コンテナサイズを小さくするため、icu-data-fullがデフォルトでインストールされることは今後無いかと思います。  
`RUN apk del icu-data-en && apk add icu-data-full`は必須で記載することになりそうですね。
[Unity]オブジェクトをフリック操作で飛ばす方法

今回は3D空間でフリック操作でオブジェクトを飛ばす実装についてです！

:::note info
使用PC： MacBook Pro (13-inch, M1, 2020)
OSバージョン: 11.5.2
Unityバージョン：2021.3.2f1
:::

# 実際にプレイすると
![フリック最終_AdobeExpress.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/cadc0817-b773-1fa8-745f-2af215c1d1c3.gif)

# unityの設定
サンプルの動画では
①Plane
②Cube
③Material(赤色)→Cubeにつける
をアセットとして使用しています。

Cubeには`Rigidbody`をAdd Componentしています。

# コード全文
```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FlickScript : MonoBehaviour
{
    public float powerPerPixel;
    public float maxPower;
    Vector3 touchPos;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            touchPos = Input.mousePosition;
        }else if (Input.GetMouseButtonUp(0))
        {
            Vector3 releasePos = Input.mousePosition;
            float swipeDistanceY = releasePos.y - touchPos.y;
            float powerY = swipeDistanceY * powerPerPixel;
            float swipeDistanceX = releasePos.x - touchPos.x;
            float powerX = swipeDistanceX * powerPerPixel;

            if (powerX < 0)
            {
                powerX *= -1;
            }
            if (powerY < 0)
            {
                powerY *= -1;
            }

            if( powerX > maxPower)
            {
                powerX = maxPower;
            }
            if (powerY > maxPower)
            {
                powerY = maxPower;
            }

            GetComponent<Rigidbody>().AddForce(new Vector3(powerX * swipeDistanceX, 0, powerY * swipeDistanceY), ForceMode.Impulse);
        }
    }
}
```

Cubeにスクリプトを貼り付けします。

# 以上
【Ubuntu Server 22.04.1】ターミナル上でWiFi接続

# 経緯
下記の記事を参考にし、M1MacにUTMでUbuntuServerをインストールしたものの、ネットワーク接続ができずにaptもpingもできずに困ったため

https://oopsoop.com/ubuntu-on-mac-using-utm/

# ターミナル上でWiFi接続

etc/netplan/50-cloud-init.yamlを開く

```
$ sudo vi /etc/netplan/50-cloud-init.yaml
```

[SSID]と[PASSWORD]を置き換えて、下記のように編集する
[]は残さないように。

``` bash:/etc/netplan/50-cloud-init.yaml
network:
    ethernets:
        eth0:
            dhcp4: true
            optional: true
    version: 2
    wifis:
        wlan0:
            dhcp4: true
            optional: true
            access-points:
                [SSID]:
                    password: "[PASSWORD]"
```

変更の適応

```
$ sudo netplan apply
```

うまく行かないときのデバッグコマンド

```
$ sudo netplan --debug apply
```

# 参考

https://itc.tokyo/linux/settings-wifi-on-terminal/

https://nosubject.io/raspberry-pi-cui-ubuntu-server-wifi-configuration/
intとIntegerとAutoboxingとIntegerCache

バズった(´・ω・｀)

### こんにちは、Javaおじさんのシキムです。


40才目前で、プログラム工学に興味を持ったので本や記事で読んだ難しい話を
咀嚼して簡単な言葉で語りたいと思います。

-----
今回は、こちらのおじさん初のバズりツイートのコードについてです。

https://twitter.com/sikimuOji/status/1564279451151581184

なんでオブジェクト型を==しているんだとか、127と128で結果が違うんだっていう話でなんかめっちゃ盛り上がっております。

このなんで？に対して、AutoboxingとIntegerCacheを使ってちょっと解説してみたいと思います。

# Autoboxingっていう便利な奴 #
Javaを使っているとおなじみ、ArrayList<T>やクラスHashMap<K,V>などがあります。
とっても便利なもので、 **オブジェクト型** なら、キーにも値にも指定することができます。

たとえば、int型であれば以下のようにArrayListを作ることができます。
```java
ArrayList<int> list = new ArrayList<int>();
```
嘘です。できません。
これはint型は、プリミティブ型と呼ばれる参照ではない値を示す型だからです。(詳しくは調べてね)

でも、int型だってキーにしたいことがあります。そんな時に使われるのがInteger型です。
これは、**ラッパークラス**とか言われるものでザックリ説明するとint型の値を１つだけ持ったクラスです。
これを使うことで先ほどのコードも動くようになります。
```java
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(Integer.valueOf(1));
list.add(Integer.valueOf(2));
```
うん、、、int型使えるって言ってもこれはちょっと面倒くさい。。。

そんな時に、いよいよ登場！！**Autoboxing**機能！！

https://docs.oracle.com/javase/jp/8/docs/technotes/guides/language/autoboxing.html

こちらも、ざっくりお話しするとラッパークラスだってわかっているからコード書く時にはint型みたいに書いておけばコンパイル時によきに計らうという機能です。

先ほどのコードも、コンパイル時にAutoBoxing機能が働くため以下のコードでも同じ挙動となります。
```java
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
```

ラッパークラス超便利ですね。

ほかにも、
```java
Integer a = 1000;
Integer b = 1000;
if(a >= b)return true;
```
なんて書いたとしても、コンパイル時に
```java
Integer a = Integer.ValueOf(1000);
Integer a = Integer.ValueOf(1000);
if(a.intValue() >= b.intValue())return true;
```
と変換してくれるので戻り値がtrueになります。
では、これはどうでしょうか？
```java
Integer a = 1000;
Integer b = 1000;
if(a == b)return true;
```
これも、trueが戻り値となりそうですが、実際はa==bはfalseとなってしまいtrueが返ってくることはありません。
Autoboxingは、プリミティブ型とそのラッパークラスが変更しないとコードとして成立しない場合に自動的に動作します。(詳しくは調べてみてね)
そのため今回は、そのままオブジェクト型==オブジェクト型の判定として行けるためAutoboxingは機能しなかったようです。

だから、ツイートで、どちらも128が格納されているがIntegerとしては別のオブジェクトなのでfalseとなっていたわけです。

# Integerの気遣いという罠 #
じゃあ、なんで127は大丈夫なのかっていうことに関しては以下をご覧いただきたい。

https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Integer.html#valueOf-int-

このメソッドは通常、渡されたintを新しく作ったIntegerオブジェクトに入れて返すのですが、なんと頻繁に使われる数字は**あらかじめIntegerオブジェクトを作っておくよ**と気遣いをもった処理を行ってくれるのです。

このため、127ではどちらもキャッシュされているIntegerオブジェクトが渡されるので参照比較もtrueとなっていました。


# 今回のツイートはおじさんの勘違いへの備忘録だったのである #
どんな時でもAutoBoxingがされると思っていました。でも、実際にはただのオブジェクト参照同士の判定になってしまう。
しかし、小さい値では動いてしまうのでテスト中は大丈夫だが本番で大きな数字になると急にfalseとなって原因究明が遅れそう。

こ～んな感じの懸念があってのツイートがまさかのバズったというわけです。






もし、間違った情報が混じってたらごめんなさい(´・ω・｀)

以上です。
Google Meetでアバター化する方法(ソフトインストール不要)

# 概要
業務でのミーティングでGoogle Meetを使うことがよくあります。
その際に以下の理由でアバター化したいと思い、やってみました。
- 顔を出したくない
- はっちゃけたい
- イメチェンしたい

# 用語定義
- アバター化
  - 自身の動きや表情に連動した2Dや3Dのアバターを自身の見た目の代わりとして使用すること
- 仮想カメラ
  - PC内部に用意した映像ソースをWebカメラの様に出力したもの

# 調査
## 仮想カメラ作成
Web会議ツールでアバター化するためには仮想カメラを作成する必要があります。
仮想カメラを作成するツールはOBSが一般的でしょう。しかし、OBSを使用する為にはPCへのインストールが必要であり少し面倒です。

## アバター化
Vtuber戦国時代の昨今、アバター化するためのツールは様々あります。
[Animaze](https://store.steampowered.com/app/1364390/Animaze_by_FaceRig/?l=japanese)、[VTube Studio](https://store.steampowered.com/app/1325860/VTube_Studio/?l=japanese)、[Luppet](https://luppet.appspot.com/)などです。
その中でもAnimzeはプリセットのアバターが豊富だったり仮想カメラ機能が組み込まれていたりと有力でした。
しかし、Mac非対応のため使用できる環境が限られてしまいます。

# 使用するツール
## [Screen Capture Virtual Camera 🎥](https://chrome.google.com/webstore/detail/screen-capture-virtual-ca/jcnomcmilppjoogdhhnadpcabpdlikmc)
[こちら](https://github.com/uttk/screen-capture-virtual-camera)にて公開されているツールをChromeウェブストアにて私が公開したしたものです。(Manifest V3への対応が少し面倒くさかったです。)
PCの画面全体やChromeのタブをGoogle Meetにカメラとして出力することができます。
作成された[uttkさん](https://twitter.com/uttk_dev)に大感謝します。
Google Meetが使用する関数をオーバーライドすることで挙動を変えています。このテクニックは他のツールでも応用が効きそうです。

## [Kalidoface 3D](https://3d.kalidoface.com/)
アバター化することができるWebアプリです。
プリセットのアバターが多くて使いやすいです。背景を変えたりもできます。
VRMを読み込むことができお気に入りのアバターになることができます
また、[2Dバージョン](https://kalidoface.com/)もあります。Live2Dの方が好みの方はこちらを使うのもありです。
作成された[Richさん](https://twitter.com/yeemachine)に感謝を込めてコーヒーを送っておきました。

# 手順
準備として[Screen Capture Virtual Camera 🎥](https://chrome.google.com/webstore/detail/screen-capture-virtual-ca/jcnomcmilppjoogdhhnadpcabpdlikmc)をChromeに追加しておきます。

1. [Kalidoface](https://3d.kalidoface.com/)を開く
ページを開き、右下のカメラボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413932/2fcbe8e7-248d-fca7-35fd-670c2457b68a.png)
数秒後にアバターが自身の動きに連動して動き出せばOKです。
動き出さない場合は他のソフトがWebカメラを使用している可能性があります。考えられるソフトを切ってページ再読み込みしましょう。

2. [Google Meet](https://meet.google.com/?hs=197&pli=1&authuser=0)を開く
3. Meetの設定でカメラを「Screen Capture Virtual Camera 🎥」に変更する
4. 表示された「共有する内容を選択する」ダイアログでKalidofaceのタブを選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413932/4db6b6ff-1520-555f-b54a-cb723382c116.png)
5. 以上！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413932/ca3bfc6a-6101-a3f1-b096-b1ae4c01ac94.png)
ちなみにこのアバターは[コトブキヤオリジナル3Dモデル](https://www.kotobukiya.co.jp/product-title/original-3d-model/)の「監督ちゃん」です。私がセットアップを担当したので愛着があります。

# 終わりに
私はWeb会議ではビデオをオンにして顔を見せる派です。その方が表情や仕草などが伝わり、より円滑なコミュニケーションできるためです。
これらのノンバーバル情報は会話の際に感情や意図の伝達に言葉よりも大きな影響を与えることが知られています(要出典)。
しかし、顔を出したくない人の気持ちも分かります。
そこで、Web会議におけるアバター化がこの両者の歩み寄りをサポートし、より良いコミュニケーションができると考えています。
【AWS認定】スコアレポートの確認方法

# はじめに
試験を受けた後は、合格であれ不合格であれ、自分がどれくらい得点できたのかが気になるものです。
AWS認定試験の結果は [AWS認定](https://www.aws.training/Certification) のページから確認できるのですが、少々わかりづらいと感じたため、本記事ではスコアレポートの確認方法を掲載します。
（初回受験時、スコアレポートが反映されていないと思って私はAWSに問合せてしまいました・・・。）

# スコアレポート表示手順
## 1. 受験する
まずはAWS認定試験を何かしら受けてください。話はそれからです。

## 2. 受験日から5営業日待つ
私はピアソンVUEによるオンライン受験の経験しかありませんが（[体験談](https://qiita.com/TakuyaSuzuki/items/a6bd9efd8a61d3f1bdbc "【怒りを昇華】AWS・ピアソンVUEなどの問合せ先リンク集＆オンライン試験当日にトラブった話")）、受験後には「5営業日以内に、AWS認定アカウントで試験結果が確認できるようになったことを通知するEメールが送信されます。」と表示されました。（私の元にそのメールは届きませんでしたが・・・。）

## 3. 認定アカウントへのサインイン
 [AWS認定](https://www.aws.training/Certification)のページより試験の申込み時に使用したアカウントでサインインします。

## 4.「試験履歴」へ移動してスコアレポートをダウンロードする
画面上部 __「試験履歴」__ から受験履歴（統一されていないのね）を確認し、「スコアレポート」欄の「ダウンロード」をクリックすることで試験結果を確認できます。（下図参照）
![AWS認定_試験履歴.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2566746/b9f17800-2a14-6549-2534-c604f8c283b1.png)

# 注意点
認定アカウントへサインインした後に表示される「ピアソンVUE試験の管理」ボタンからのページ遷移後にも「受験履歴」という紛らわしいページがあり、なおかつ「スコアレポートを表示」というリンクまであったので、私はそれに惑わされました。（当該リンクは現在表示されなくなっているようです。）

# おわりに（余談）
スコアレポートがなかなかダウンロードできない場合は、[AWS認定の問合せフォーム](https://support.aws.amazon.com/#/contacts/aws-training/) から状況を確認してみるのもアリです。

今回この記事の作成に際してQiitaに初めて画像アップロード機能を使用しましたが、画像の保存先はAmazon S3でした。流石AWS。

# 関連ページ
https://qiita.com/TakuyaSuzuki/items/a6bd9efd8a61d3f1bdbc
Alibaba CloudのPolarDBの徹底分析(3)_PolarDBとRDSの料金編

# 前提
PolarDBはストレージとコンピュートを分離したアーキテクチャを持っています。CPU、メモリ、ディスクが相互の制約から解放され、コンピュートとストレージを別々のリソースプールとして管理・割り当てられるため、リソースの断片化を大幅に減らし、全体的なリソースの利用率を向上させることが可能です。 
また、コンピュートとストレージのモデルが異なるため、よりターゲットを絞ったカスタマイズや最適化を行い、リソースあたりのコストを削減することも可能です。

以下の記事でRDSとPolarDBのコストを理論的に分析しましたが、今回は実際に同じデータベース構成、テストデータ、テスト方法で、両者の価格とパフォーマンスを計算していまます。

https://qiita.com/dennis_wang/items/2b92122841817a2657dd


# 料金の比較
- データベーススペック：
    - 本番環境でよく使われている「8コア、32G、500Gストレージ」
- データセットとテスト方法：汎用的なsysbenchのOLTPテストケース（--oltp-tables-count=10 --oltp-table-size=500000 ）
- 性能指標：
    - QPS（Query per Second）
    - TPS（Transaction per Second）

また、RDS(MySQL)もPolarDB(MySQL)も、読み取り専用ノードを追加することで水平方向にスケールアウトする機能を持っています。 
PolarDBはノード数が増えてもストレージコストを追加する必要がないという違いがありますので、以下のように読み取りノード1台から3台までの構成を比較検討してみます。

| cluster構成 | PolarDB料金 | RDS(MySQL)料金 | PolarDB性能(QPS) | RDS性能(QPS) | PolarDB性能向上 | 千ドルごとの性能指標(PolarDB vs RDS)|
| --- | --- | --- | --- | --- | --- | --- | 
|1 priary + 1 read-only | 944+310=1254 | 893+121=1014 | 53879 | 18625 | 290% | 42965 vs 18367   |
|1 priary + 2 read-only | 1416+310=1726 | 1014+921=1935| 66626 | 26357 | 250% | 38601 vs 13621 |
|1 priary + 3 read-only | 1888+310=2198 | 1014+921*2=2856| 80268 | 43087 | 186% | 36518 vs 15086 |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/8cf4efca-b960-bc91-fddc-d91f24bb5d7b.png)

:::note info
- 料金:
  - 月単位、computing + storageの合計になります。
  - 料金は時間とともに変わりますので、利用する時に実際の料金をご確認ください。
- polardbストレージ料金：
  https://www.alibabacloud.com/help/ja/polardb-for-mysql/latest/storage-pricing
:::


# まとめ
- 1 priary + 1 read-onlyの構成はPolarDBはRDSより2割程度高いですが、RDSの三倍弱性能になります。
- read-onlyの台数増えれば増えるほど、RDSはPolarDBより割高になってしまう。
- PolarDBはmaster slaveの構成が不要であったり、5分程度リードレプリカが利用できたり、スケールアップやスケールダウンも5分程度終わりますので、スケーラビリティはRDSよりはダントツ的に優れています。
- ということで、本番環境では性能面や可用性やメンテナンス面など総合的に考えると、なるべくPolarDBを使ったほうがよいでしょう。
nvmを使った際に、グローバルパッケージはどこに保存されるのかを確認したかったのでメモ


# どのバージョンのnpmを使っているかの確認

まず、以下のコマンドでnpmのバージョンを切り替えます
```
nvm use {npmのバージョン}
```

コマンドを実行した後は、自動的にnvmによって、このフォルダ直下のファイルが読み込まれます。
```
~/.nvm/versions/node/{npmのバージョン}/
```



任意のnpmのバージョンに対応した、グローバルパッケージの一覧は以下で確認ができます。

```
npm -g list
```

トップレベルのパッケージだけ利用したい場合は、以下で調べられます
```
npm list --depth=0 -g
```

# パッケージの保存場所について

ここで、導入済のパッケージ郡は、libフォルダ下のnode-modulsフォルダにパッケージが保存されてます。
```
~/.nvm/versions/node/{任意のバージョンのフォルダ}/lib/node-modules
```

以下のコマンドで調べることができます
```
npm list -g | head -1
```

# グローバルパッケージの保存場所を変更したい場合

ちなみに、npmのグローバルパッケージのインストール場所を変えるには、
~/.npmrcファイルへ、prefixを記述すればいいみたいです。

```
prefix=/{任意のpath}
```

例えば, 「.hoge」フォルダに保存した場合は、

```
prefix=~/.hoge
```

新しく設定した場所のbinのパスを$PATHに追加するのを忘れずに行います。

```
export PATH=~/.hoge/bin:$PATH
```

# そもファイルがない場合は？

自分の場合は、そもそも~/.npmrcがありませんでした。
そのため、どこに.npmrcが作られるかを調べる必要があります。
```
npm config ls -l | grep config
```

上記コマンドで検索をかけると、以下の場所のnpmrcを読み込むようだとわかりました。
※この場合、自分でファイルを新しく作る必要がありました。

```
; "default" config from default values
globalconfig = "~/.nvm/versions/node/v16.14.0/etc/npmrc"
userconfig = "~/.npmrc"
; "cli" config from command line options
```
.htaccessのRewriteRule,RewriteCondで理解に苦しんだ事のメモ

転送設定でおなじみのRewriteRuleとRewriteCond。
何回やっても翌月にはわからなくなるので意味不明ハマりポイントだけメモ。

# RewriteCondの「-f」はオプションではない。

RewriteCondの書き方でググるとこういう説明が出てくる。

 >RewriteCond %変数名(テスト文字列) 条件パターン(正規表現) [フラグ]

出典： https://weblabo.oscasierra.net/apache-rewritecond-base/

これでパッと分かることは、
・RewriteCondがif文で引数の１つ目と二つ目を比較する。
・１つ目の引数がターゲットになるURLのパターンで組み込み変数でホストやドキュメントルートが使える。
・２つ目の引数に条件になる正規表現を書く。

で、今回ハマった実例がこれ。

```
RewriteCond %{DOCUMENT_ROOT}/$1.webp -f
```

jpegの画像をwebpに変えるタスクでググっていたら出てきたものです。

え、どういう意味？ってなりました。

まあたぶん、$1.webp までが引数の１つ目になるターゲットURLですね。
で、それに-fオプションがついている？

・・とLinuxコマンドのように読んでしまいましたが、全然違いました。
「-f」は.htaccess独自の正規表現の代わりになる関数的なものらしい。

> -d	ディレクトリが存在する場合は true
> -f	ファイルが存在する場合は true
> !	否定

出典：https://www.webdesignleaves.com/pr/html/htaccess.html

他にも色々あったけど、こういう感じで正規表現の代わりに使える。
だから上の例だと

```
%{DOCUMENT_ROOT}/$1.webp 
```

に該当するパスにファイルが存在していたらif条件がtrueになって、次に現れるRewriteRuleが実行されるという意味になる。

# RewriteCondに$1があるのに対応するカッコがない。

さっきの例でターゲットのURLに$1って書いてあるけどこれは何が代入されるのでしょうか？
この$1は正規表現で検索条件の一部をカッコ()でくくって、その中身を置換結果にもってくる（キャプチャ）ための$1です。

が、この行に()はありません。
じゃあ$1には何が入るの？%{DOCUMENT_ROOT}に関係する何か？

全然違いました。

なんとこの後の行で出てくるRewriteRuleにあるカッコから巻き上げてキャプチャしてきます。

```
RewriteRule (.*)\.(jpe?g|png)$ $1.webp [T=image/webp,E=accept:1]
```

はい、ここで１つ目の引数のURLを2つめの引数のURLに置換しています。
で、この１つ目の(.*)の部分が上の行のRewriteCondに代入されるんですね。
リフレクションで定数を取得する(C#)

# リフレクションで定数を取得する

リフレクションで定数を取得したかったのですが、調べてもなかなか見つからなくて苦労したので覚書です。
同じく探している人の目に留まれば幸いです。


## IsLiteral プロパティを参照する

定数は `FieldInfo` オブジェクトの `IsLiteral`プロパティ が `true` になるので、これを参照すれば定数が取得可能です。

https://docs.microsoft.com/ja-jp/dotnet/api/system.reflection.fieldinfo.isliteral

```csharp
// Constants クラスの定数を取得する
foreach (FieldInfo field in typeof(Constants).GetFields(BindingFlags.Public | BindingFlags.Static))
{
    if (field.IsLiteral)
    {
        Console.WriteLine($"{field.Name}:{field.FieldType.Name}:{field.GetRawConstantValue()}");
    }
}
```

始めに、定数が含まれているクラス(例では`Constants`) から `GetFields`メソッド で `public` かつ `static` なフィールドを取得し、その中で `IsLiteral`プロパティ が `true` となっているものだけを抽出するだけでした。
定数の値は `FieldInfo` オブジェクトの `GetRawConstantValue`メソッド で取得できます(`object?`型になるので、必要に応じてキャストが必要です)。
(これだけのことを調べるのに結構な時間かかってしまいました……)


## おまけ サブクラスを含む定数クラスから全ての文字列定数を列挙する

以下のようなメソッドを作りたくて調べてました。
あまり必要なケースは無いと思いますが、必要な方の参考になりましたら。

指定したクラスとそのサブクラスに含まれている文字列定数を全て列挙し、Key = 定数名(識別子名)、Value = 定数値(文字列) となるディクショナリを返すメソッドです。

```csharp
private static Dictionary<string, string> CreateConstantsDictionary(Type type)
{
    return type.GetFields(BindingFlags.Public | BindingFlags.Static)
        .Concat(
            type.GetNestedTypes()
                .SelectMany(sub => sub.GetFields(BindingFlags.Public | BindingFlags.Static))
        )
        .Where(field => field.IsLiteral)
        .Where(field => field.FieldType == typeof(string))
        .ToDictionary(
            field => field.Name,
            field => (string)field.GetRawConstantValue()!
        );
}

```
Ubuntu20.04にて、DNS周りについてまとめ。

# はじめに

Ubuntu20.04にて、DNS周りについてまとめ。

# 最終更新日
2022年8月30日

# 環境の情報

OS
Ubuntu20.04

# 注意

最新の状態を確認して下さい。

# 参考さまはこちら
https://manpages.ubuntu.com/manpages/trusty/ja/man5/resolv.conf.5.html
https://yo7612.com/2021/12/29/post-0-111/
https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html
https://man.archlinux.org/man/resolved.conf.5
https://wiki.archlinux.jp/index.php/Systemd-resolved
https://atmarkit.itmedia.co.jp/fnetwork/dnstips/010.html
https://takuya-1st.hatenablog.jp/entry/2022/03/10/155657
https://www.freedesktop.org/software/systemd/man/resolved.conf.html
https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html
https://manpages.debian.org/experimental/systemd/systemd-resolved.service.8.en.html

Ubuntuサーバー徹底入門 
https://amzn.asia/d/eRJyUa1


# 調べたこと

## DNSサーバー
名前解決する。
ホスト名とIPアドレスとを相互に変換する。

## リゾルバ
resolver
プログラム。
ライブラリみたいなもの。
ドメイン名を元にIPアドレスの情報を検索したり、
IPアドレスからドメイン名の情報を検索する、名前の解決（name resolution）を行う。


## a.comにアクセスすると、どんなことが起きるのか？

指定されたホスト名のipアドレスが知りたい。
↓
リゾルバに「名前解決してほしいよー」と言う。
↓
/etc/resolv.confに書かれている
DNSサーバーに聞く。
↓
各DNSサーバー（色々あるけど、ここでは割愛）と協力して、ipアドレスを見つける。
↓
リゾルバへ返す。




## /etc/resolv.conf

ファイル。
名前解決（ホスト名からIPアドレスを調べること）の設定を行う。



## resolv.confのnameserver
コンピュータが名前解決に使う。
DNSサーバのIPアドレスを書く。


## resolv.confのoptions
レゾルバの内部の変数を変えられる。


## resolv.confのedns0
DNSの拡張のサポートが有効になる。
RFC2671で規定されている。


## systemd-resolved 
DNSのリゾルバ（DNSのクライアント）を制御するための仕組み。



## $ systemd-resolve --status
詳細な状況表示をが確認できる。

```
Global
       LLMNR setting: no                  
MulticastDNS setting: no                  
  DNSOverTLS setting: no                  
      DNSSEC setting: no                  
    DNSSEC supported: no                  
  Current DNS Server: 127.0.0.1           
         DNS Servers: 127.0.0.1           
          DNS Domain: home                
                      net                 
          DNSSEC NTA: 10.in-addr.arpa     
                      16.172.in-addr.arpa 
                      168.192.in-addr.arpa
                      17.172.in-addr.arpa 
```


## resolv.confに、nameserver 127.0.0.53が最初から、書かれている理由

「systemd-resolve」が「127.0.0.53」のTCP53番ポートで待ち受けているため。
統計検定1級対策 各分布の特徴の覚え方1 分布一覧編

『[統計検定1級対応 統計学](https://www.amazon.co.jp/%E6%97%A5%E6%9C%AC%E7%B5%B1%E8%A8%88%E5%AD%A6%E4%BC%9A%E5%85%AC%E5%BC%8F%E8%AA%8D%E5%AE%9A-%E7%B5%B1%E8%A8%88%E6%A4%9C%E5%AE%9A1%E7%B4%9A%E5%AF%BE%E5%BF%9C-%E7%B5%B1%E8%A8%88%E5%AD%A6-%E4%BA%8C%E5%AE%AE%E5%98%89%E8%A1%8C/dp/448902150X)』で紹介されている以下の分布について、
期待値・分散・その他特徴の覚え方などをまとめました。
数学的に厳密でないところは目をつぶっていただければと思います。


- 基本的な離散分布（8個）
離散一様分布、ベルヌーイ分布、二項分布、ポアソン分布、超幾何分布、幾何分布、負の二項分布、多項分布

- 基本的な連続分布（10個）
連続一様分布、正規分布、指数分布、ガンマ分布、ベータ分布、コーシー分布、対数正規分布、ワイブル分布、ロジスティック分布、多変量正規分布

- 標本集計・検定用分布（3個）
$\chi^2$分布、$t$分布、$F$分布


以下の表記を用います；
- pdf: 確率密度関数
- ${\rm i.i.d}$: 互いに独立に同一分布に従う
- $E[X]$: $X$の期待値
- $V[X]$: $X$の分散


# 分布一覧・まとめ
各分布のpdf、期待値、分散等を一覧にしました。
特に、期待値・分散については<b>覚えやすくするための工夫をまとめています</b>。
まずは「何を表す確率か」と期待値・分散を覚えて、
残りは定期的に読み返したり書き写したりして頭に入れていければと思います。
![分布一覧](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783705/8ace7792-13e1-21b4-3dc2-53d4cd2a9149.png)
<!--
表
表
表
表
表
表
表
表
表
表
表
表
表
表
表
表
表
表
表
表
表
表
-->

<b>書式の凡例</b>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783705/28207fd2-71bb-dba3-1330-7a3196bcbe13.png" width="500px">

<b>Notation</b>
標本平均をbarで表しています；Xbar$=\bar{X}=\frac{1}{n}\Sigma_{i=1}^n X_i$
不変分散をu<sup>2</sup>で表しています；u<sup>2</sup>$=\frac{1}{n-1} \Sigma_{i=1}^n (X_i-\bar{X})^2$
フォントの都合でnと$\pi$が識別困難です、注視お願いしますm(__)m




## 分布同士の関係

薄黄と水色の分布6つを整理するとこうなります。
分布一覧の「何を表す確率か」から自然と導ける関係性です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783705/1a644dfa-27a0-48af-5de5-28cb01c60905.png" width="400px">


また分布一覧にも記載がありますが、下記の関係も試験ではよく使います。
覚え方は…別途まとめようか検討中です。
- $Bin(n,p) \rightarrow Po(\lambda) \hspace{5pt} (\lambda=np一定で n \rightarrow \infty) $
- $Bin(n,p) \rightarrow N(np, np(1-p)) \hspace{5pt} (n \rightarrow \infty) $
- $HG(N,M,n) \rightarrow Bin(n,p) \hspace{5pt} (p=M/N一定で N \rightarrow \infty) $
- $Exp(\lambda)$のpdfは$Po(\lambda)$の確率関数から導ける


「分布同士の関係をまとめる」と言うともっと網羅度の高い、複雑な図を作る方もいますが、
個人的には最低限これぐらいの内容が覚えられていれば、試験対策としては十分かなと思います。
複雑な図は、作る分には良いのですが見返しても覚えられないので。。




## 無記憶性・再生性
<b>無記憶性・再生性を持つ分布の覚え方</b>
- “薄黄”は無記憶性を、“水色”は再生性を持つ
- “水色”の他、$N$と$Po$も再生性を持つ

です。
なお、“薄黄”の3つの分布のうち、
$Ber$は試行に繰り返し要素が無いため通常は無記憶性を持つとは言いませんが、
覚えやすくするためにその辺は無視でお願いします。


<b>各分布が無記憶性を持つ理由の覚え方</b>
$Geo$と$Exp$が無記憶性を持つのは、
- ベルヌーイ試行が成功する確率は直前のベルヌーイ試行の結果に依らないから
- ポアソン事象が発生する確率は直前のポアソン事象発生有無に依らないから

ベルヌーイ試行やポアソン事象の定義（分布一覧参照）から自明ですね。


<b>各分布が再生性を持つ理由の覚え方</b>
- “水色”の3つについてはいずれも “黄色”の和が従う分布だから
例）$Bin(n,p)$は$Ber(p)$に従う$X_i$の和$S_n=\Sigma_{i=1}^n Xi$が従う分布である。
$S_n$と$S_m$が共に${\sim}Bin$なら$S_n+S_m (=S_{n+m})$も当然${\sim}Bin$
- $N$については「正規分布の線形結合は正規分布」だから
- $Po$については、時刻に依らない変数の和は時刻に依らないから
例）平均発生回数が時刻によって変化しない事象が2つあったとする。
一方は1秒当たり平均2回、一方は1秒当たり平均5回発生するとする。
2つの事象の発生回数の和は1秒当たり平均7回で、
この平均発生回数は時刻によって変化しない。




#### 期待値・分散を定義から計算する練習も必要
試験では定義に基づいて計算する問題も出題されます。
上の方で「他の分布から導けるものも多い」と書きましたが、
定義に基づいて期待値・分散を導出する練習もしておきましょう。




# 参考
（準備中・・・）
各分布についての補足事項などを別記事にまとめようかと検討中。
ご興味がある方はLGTMやフォローなどいただければと思います（励みになります）。
DeFi -Web3で注目の技術③-

# はじめに
IT×ビジネスという視点で週1本記事を投稿しています。
もし興味のある方は下のリンクから他の記事も見ていただければ幸いです。
 [@7_inai_](https://qiita.com/7_inai_)

本記事では、Web3で注目の技術③としてDeFiについてまとめます。
Web3については[こちらのリンク](https://qiita.com/7_inai_/items/c441008bb0849908fbc6)からご確認ください。


# DeFiとは
DeFi(ディーファイ)とは、Dedentralized Financeの略で __分散金融__ という意味があります。
ここでの __『分散」__ とはどういう意味なのでしょうか？

# 分散についてもっと詳しく
分散金融の「分散」とは`中央管理者がいない`ことを表しています。従来の金融は、銀行・証券会社・生命保険会社等が中央管理者として、金融仲介の役割を担っていることが普通でした。
しかし、DeFiではこれらの中央管理者がいないため、ブロックチェーン上に取引履歴を記録し、取引履歴の精査や正しいかの判断を行うのはあくまでもユーザーです。
また、中央管理者がいないために、__送金時やローンの契約時に必要な手数料が最小限(もしくは無料)__ になります。

# DeFiのメリット
- 低コストかつ即日
DeFiでは人による手続きではなく、プログラムによる手続きが中心のため、人件費がいらないだけでなく、手続きに関する時間が短縮できます。
- 世界中どこでも利用可能


# DeFiのデメリット
- 自己責任
通常は、金融機関が中継しているため、トラブル時は金融機関が責任を負ってくれますが、DeFiでは中央管理者がいないため、サービスによって起きたトラブルは全て自己責任になります。
- 資産価値の不安定さ
DeFiは円やドルのような自国通貨ではなく暗号資産を使用します。まだまだ暗号資産は「投資」ではなく「投機」の対象として考える人も多く、価値の変動が激しいため、もちろん急増する可能性もありますが、バブルのように暴落可能性もあります。


# 終わりに
DeFiはメリットが大きい反面、デメリットにも要注意する必要があります。「投資をしない」ことで有名な日本人ですので、DeFiが広く認識されるのもまだまだ先のことになるかも知れません。
最後までお付き合いくださりありがとうございました。
zig を make 代わりに使う最初の一歩

1. Zig言語の `zig` コマンドは、ビルド関連の機能が詰まったスイスアーミーナイフである
1. その一環として make 系の機能を持っている
1. `build.zig` が Makefile に相当する
1. `.step` でターゲットを作れる
1. `addSystemCommand` で、シェルコマンドを実行するサブコマンドを作れる
1. `zig build --help` で実装したStepを一覧表示できる
1. Zig言語はまだ情報が少ないので、ここまで調べるまでも結構苦労した


# build.zig の例

```zig
// build.zig
const std = @import("std");

pub fn build(b: *std.build.Builder) void {
    const hw_step = b.step("hw", "prints the hello world");
    {
        hw_step.dependOn(&b.addSystemCommand(&.{ "echo", "Hello" }).step);
        hw_step.dependOn(&b.addSystemCommand(&.{ "echo", "世界!" }).step);
    }

    const fb_step = b.step("fb", "fizzbuzz");
    fb_step.makeFn = fizzbuzz;

    const doall_step = b.step("fbhw", "do all");
    doall_step.dependOn(fb_step);
    doall_step.dependOn(hw_step);
}

fn fizzbuzz(_: *std.build.Step) !void {
    const stdout = std.io.getStdOut().writer();

    var i: u8 = 1;
    while (i <= 100) {
        if (i % 15 == 0) {
            try stdout.print("FizzBuzz\n", .{});
        } else if (i % 3 == 0) {
            try stdout.print("Fizz\n", .{});
        } else if (i % 5 == 0) {
            try stdout.print("Fizz\n", .{});
        } else {
            try stdout.print("{d}\n", .{i});
        }
        i += 1;
    }
}

```
GOLangでフィボナッチ数を計算した


## はじめに
直近Go言語を勉強していますが、なんか数学問題を解けてみまたいため、[フィボナッチ数](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0)を計算できるロジックを作成しました。

## 環境
window 10
VSCode


## Target
以下の結果を出力する
``` 
フィボナッチ数：(0,1,1,2,3,5...)
```

簡単に回帰関数を利用して、作りました。

```go:package.go
package main

import "fmt"

func fibonacci() func(x int) int {
	return func(x int) int {
		if x < 2 {
			return x
		}
		f := fibonacci()
		return f(x-2) + f(x-1)
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f(i))
	}
}
```

実行結果：

```
0
1
1
2
3
5
8
13
21
34
```

結果ができましたね。しかし、計算量が
```math
O(2^n)
```
だった。
根本的になおしました。

```go:package.go
package main

import "fmt"

func fibonacci() func(x int) int {
	return func(x int) int {
		a, b:= x%2, 1
		for i := 0;i < x/2; i++{
		  a += b
		  b += a
		}
		return a
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f(i))
	}
}
```

これで良さそうですね。
計算量が
```math
O(n)
```
になりました。良さそうですね。

### 以上
scopeとmoduleの使い分け

# はじめに
使い分けが曖昧になることが多かったので記事にまとめてみました！


scope
---
* URLは指定のパスにしたい、かつファイル構成は変更したくないときに使用する
* URIパターンのみをカスタマイズしたいときに使用する

| Prefix Verb | URI Pattern         | Controller     |
| ----------- | ------------------- | -------------- |
| articles    | /admin/articles     | articles#index |
| new_article | /admin/articles/new | articles#new   |


**URI Patternのみadminが付加されており、app/controllersディレクトリ配下のコントローラである**


module
---

* module(scope module)はURLのパスは変更したくない、かつファイル構成は指定したい時に使用
* Controller#Actionのみ変更したい時に使用

| Prefix Verb | URI Pattern   | Controller           |
| ----------- | ------------- | -------------------- |
| articles    | /articles     | admin/articles#index |
| new_article | /articles/new | admin/articles#new   |

**コントローラーの前にadminが付与されている**
【Azure DevOps】コミットされたブランチごとにデプロイ先の環境を切り替える

アプリケーション開発では開発環境、ステージング環境、本番環境など複数の環境を用意します。
Azure DevOpsでCI/CDを行う場合もデプロイ先を切り分けたいので簡単な方法を検討してみます。

ベースとなる環境（今回は本番環境と仮定）の作成は以下記事を参照してください。
今回は本番に加えてステージング環境を作って、Reposのstagingブランチにコミットがあった際にステージング環境にデプロイされるようにします。

https://qiita.com/Yosuke_Sakaue/items/aad936218dde42411bb2

## WebApp for Containerを作成する（ステージング用）
本番と同じなので割愛します。

## Reposでブランチを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/5054eee1-0ff3-420f-7dd3-f2fd3d9ad697.png)

## Releasesを作成
新しくReleasesを作成し、トリガーのBuild Branch filtersに作成したstagingブランチを設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/9394ee29-f53f-ec27-84e8-1751ac0fd385.png)

Stageは本番ではないのでWebAppのデプロイスロットは使わず直接運用スロットへデプロイし、再起動をしています
デプロイ先はもちろん新規で作成したWebAppを指定します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/2afee20d-5c71-5030-520e-a35cbb08b9dd.png)

ACRは本番環境と共有（実際には分けたほうが良いかもしれない）するので、タグとして分かりやすいように`$(Build.SourceBranchName)`でブランチ名を付与しています
タグを一意にする方法については以下記事参照

https://qiita.com/Yosuke_Sakaue/items/4e1692596b456b74b697

https://docs.microsoft.com/ja-jp/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml

## stagingブランチでyamlファイルを修正
トリガーにstagingを追加
```
trigger:
  - master
  - staging
```
コンテナタグにブランチ名を付与
```
  - task: Docker@2
    displayName: Build and push an image to container registry
    inputs:
      command: buildAndPush
      repository: $(imageRepository)
      dockerfile: $(dockerfilePath)
      containerRegistry: $(dockerRegistryServiceConnection)
      tags: |
        $(tag)-$(Build.SourceBranchName)
```

変更をコミットし、新しいReleasesがトリガーされ、WebAppが更新されればOK
stagingで問題なければmainにプルリクエストを出し、マージすれば本番のPipelineがトリガーされる

以上
Type definition error: [simple type, class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor]

# CRUDでいうところのUPDATEで常に失敗するようになった（Spring Data Jpa使用）

以下、ログ画像![スクリーンショット 2022-08-30 21.46.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1246495/296fae3b-1b40-57c2-f3a6-e948d0d8d428.png)

## 結論:Entityに@JsonIgnoreProperties({"hibernateLazyInitializer"}) を追加

# 参考:[Spring Data JPA で hibernateLazyInitializer を Jackson が JSON シリアライズできなくてエラーになる](https://qiita.com/niwasawa/items/9735d5dc4a4a71e84ccd)


## 以下は余談

最初は`Type definition error`という部分から型違いが原因かとおもったのだけど合わせても一向にエラーがでるので

~~~
through reference chain: com.smd.api.entity.TodoEntity$HibernateProxy$KRg8OCOW["hibernateLazyInitializer"])] with root cause
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.smd.api.entity.TodoEntity$HibernateProxy$KRg8OCOW["hibernateLazyInitializer"])
~~~
No serializerとか言ってる部分が原因かなと追求したら先ほどの記事にいきついた

参考記事を上げてくださった方に感謝を！
AWS Cloud Map を CDK で 作成したりを繰り返していたら、Service   already exists って言われた時

# 現象
```
Service [srv-xxxxxxxxxxxxxxxx] already exists
```
みたいなエラーが出ますが、Management Console から何を削除しようにもどこに何があるかわからなかったので、[aws-cli servicediscovery](https://docs.aws.amazon.com/cli/latest/reference/servicediscovery/index.html#cli-aws-servicediscovery)の出番でした。

# 手順

私は以下のようにして、リソースを削除しました。

## 1. サービスに紐づくインスタンス一覧を取得

サービスを削除する前に、登録してあるインスタンスを削除する必要があるようでした。

ですので、[list-instances](https://docs.aws.amazon.com/cli/latest/reference/servicediscovery/list-instances.html) コマンドに、エラー分にあったservice idを`--service-id`オプションに渡して、インスタンス一覧を表示します。

```console
$ aws servicediscovery list-instances --service-id srv-xxxxxxxxxxxxxxxx
```
以下のようにインスタンスの一覧が返ってきます。（ここでは便宜上１件）

```console
{
    "Instances": [
        {
            "Id": "xxxxxxxxxxxxxxxxxxxxxxx",
            "Attributes": {
                "AVAILABILITY_ZONE": "ap-northeast-1c",
                "AWS_INIT_HEALTH_STATUS": "UNHEALTHY",
                "AWS_INSTANCE_IPV4": "10.2.1.253",
                "ECS_CLUSTER_NAME": "Cluster",
                "ECS_SERVICE_NAME": "Service",
                "ECS_TASK_DEFINITION_FAMILY": "TaskDefinition",
                "REGION": "ap-northeast-1"
            }
        }
    ]
}
```

## 2. インスタンスの登録を解除

[deregister-instance](https://docs.aws.amazon.com/cli/latest/reference/servicediscovery/deregister-instance.html)コマンドを使用します。

レスポンスのJSONの中の`Instances.Id`の値を`--instance-id` 引数に渡し登録を解除。

```console
$ aws servicediscovery deregister-instance --service-id srv-xxxxxxxxxxxxxxxx　--instance-id xxxxxxxxxxxxxxxxxxxxxxx
```

以上で登録解除できたはずです。

## 3. サービスを削除

`list-instances`でも使用したservice idで[delete-service](https://docs.aws.amazon.com/cli/latest/reference/servicediscovery/delete-service.html)コマンドを使用してサービスが削除できます。

```console
$ aws servicediscovery delete-service --service-id srv-xxxxxxxxxxxxxxxx
```

以上です。