OmniAICreator/Qiita-1.07M huggingface dataset:
Googleデジタルマーケティング＆Eコマース：シーズナリティ

# はじめに

”Googleデジタルマーケティング＆Eコマース プロフェッショナル認定証"　の受講が完了しました(2022/3/3)。私がこのコースから得られた素晴らしい体験を、テーマごとに分割して、わかりやすくご紹介しています。興味を持たれた方は、是非下記を受講してみてください。

https://jp.coursera.org/professional-certificates/google-digital-marketing-ecommerce

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/8957baaf-ce73-a2a4-19cd-72db89b6874f.png" width="800">

# シーズナリティ

シーズナリティは、シーズンマーケティングとも呼ばれ、四半期または年単位で

- 特別な祝日
- イベント
- 天候の前後

にEコマースのトラフィックが規則的かつ予測可能に変動することを指します。

Eコマース業界では、売上が増加する時期や減少する時期を判断するために、シーズナリティを利用しています。

シーズナリティは、

- オンシーズン
- オフシーズン

の2つに分けられます。

### <font color="MediumBlue">オンシーズン</font>

オンシーズンは、天候やイベントの影響により、顧客が商品を購入する可能性が高い時期です。オンシーズンの間、企業は最も経済的な利益を得ることが期待できます。

- 例えば、気温の変化が激しい国では、ある時期には他の時期よりも人気のある衣料品があります。サンダルもそうです。一年中履く人もいるが、一般的には暖かい季節に購入され、履かれます。この時期、サンダル業界は好景気と呼ばれる急激な景気拡大を経験するため、オンシーズンと呼ばれます。

しかし、オンシーズンは季節の変わり目だけとは限らない。休日や特別なイベントは、Eコマースサイトへのトラフィックを増やすのに大きな役割を果たします。

- 例えば、花屋業界を考えてみましょう。母の日を祝う国々では、母親への贈り物として花を購入するのが一般的です。世界的に見ても、母の日に先立つ1週間は、花屋業界にとって最も忙しい1週間となります。これは、母の日がすべての国において花の栽培の最盛期に当たるわけではないにもかかわらず、それらの国で祝祭日を祝うために花を購入することが一般的であることが重要です。

### <font color="MediumBlue">オフシーズン</font>

オフシーズンは、お客様が購入に時間をかける傾向がある時期で、特に大口の商品を購入する場合は、その傾向が強くなります。また、オフシーズンは、サイトのトラフィックや収益が比較的低くなる時期でもあります。

- サンダル業界の例に戻りましょう。冬の間は、厳しい気候のため、人々はサンダルを履くことが少なくなります。この時期は、一般的に業績が悪化したり、活動しなくなる時期と考えられ、これをスランプと呼びます。

ここで重要なのは、オフシーズンだからといって、ビジネスが何もできないわけではない、ということだ。それどころか、オフシーズンは、ビジネスがオフシーズンのマーケティング戦略に集中できる、1年で最も価値のある時期の1つなのです。

# オフシーズンのマーケティング戦略

オフシーズンのマーケティングの目的は、オンシーズンに顧客を直接サイトに誘導する強力なブランド認知を構築することで、あなたのビジネスを競合他社より一歩先に進めることです。ここでは、いくつかのアプローチを紹介します。

### <font color="Darkcyan">データベースを成長させる</font>

オフシーズンは、新しいコンタクトをターゲットにし、新しいオーディエンスを惹きつける時期です。業績が低迷しているときに追加のキャンペーンを行うのは奇妙に聞こえるかもしれませんが、オフシーズンにデータベースを拡大することは重要です。新しいキャンペーンがコンバージョンにつながれば、顧客情報を入手でき、その情報をもとにオンシーズンに新たなプロモーションを展開することができるのです。

### <font color="Darkcyan">ソーシャルメディアでの存在感を高める</font>

ピーク時に多くの顧客を獲得するためには、認知度を高める必要があります。そのための方法のひとつがソーシャルメディアです。 この時間を利用して、顧客と交流し、ソーシャルメディアへの投稿、魅力的なコンテンツを作成しましょう。これにより、年間を通して顧客やリードとつながりを保つことができます。

### <font color="Darkcyan">質の高いコンテンツを作る</font>

優れたコンテンツは、時間、労力、創造性を使って育成し、記憶に残るようにする必要があります。多くの場合、どれだけの人がそれに接し、どれだけコンバージョンにつながったかで測られます。そうすることで、あなたのビジネスは他と一線を画すことができます。

- サイトのブログ機能を活用し、興味深く、示唆に富む記事を書くことができます。これは、オーディエンスがつながりを感じられるコミュニティを構築するのに役立ちます。
- その記事に関連する追加製品への興味も喚起します。例えば、スポーツは市民をグローバルにつなぐ趣味です。サッカーアパレル会社が、オフシーズンにプロスポーツ選手のキャリアについてインタビューを行い、投稿することができます。この記事は、企業にとって興味深いストーリーを共有する絶好の機会になるでしょう。
- 現在行われているジャージの割引プロモーション販売に顧客を引き付け、オンシーズンに自社ブランドが記憶されることにつながります。

### <font color="Darkcyan">あまり人気のない商品があれば、サイトで宣伝する</font>

人気のない商品に目を向けることで、人気商品の売上減少による収益減を取り戻すことができるため、オフシーズンにビジネスの利益を確保するための素晴らしい方法なのです。そのために、企業はあまり知られていない商品をホームページで紹介したり、その商品のマーケティング・キャンペーンを行ったり、クリエイティブなブランディングを展開したりします。

### <font color="Darkcyan">地理的セグメンテーションを活用する</font>

地理的なセグメンテーションとは、顧客の物理的な場所に関してグループ化することを指します。業界によっては、オンシーズンとオフシーズンが異なる時期や場所で発生することがあるため、これは重要なポイントです。

- サンダル業界の例を思い出してください。サンダルは寒さのために不況かもしれませんが、ブーツはオンシーズンを迎えています。地理的なセグメンテーションを使って、様々な靴を販売するビジネスでは、世界の暖かい場所にいる潜在顧客にはサンダル、涼しい場所にいる潜在顧客にはブーツをターゲットにすることになるかもしれません。
LINE CTF 2023 Writeup

# LINE CTF 2023 Writeup
https://score.linectf.me/challenges

LINEがCTFを開催すると聞いて興味本位で参加。
めちゃくちゃ難しくて1問しか解けなかったです。
ちなみに順位は160位/477位でした。
## 目次
- Welcome(1pt)
- baby-simple-gocurl(100pt)
- 最後に
## Welcome(1pt)

discordの#announcementで2023/03/25の8時59分に答えが張られました。

![welcomeflag.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982234/72cf204c-ee05-72e0-5d2b-e967078e7ccc.png)
```LINECTF{e305dbd3a5893f92701ef9d125a9f77b}```
## baby-simple-gocurl(100pt)

まず、問題文から
「http\://34.146.230.233:11000/flag」にflagがありそうなので
飛んでみるとこのようなメッセージが。

```{"message":"You are a Guest, This is only for Host"}```

Hostじゃないと見れないみたいです。main.goの中身を見てみましょう。

```diff_go
	r.GET("/flag/", func(c *gin.Context) {
		reqIP := strings.Split(c.Request.RemoteAddr, ":")[0]

		log.Println("[+] IP : " + reqIP)
		if reqIP == "127.0.0.1" {
			c.JSON(http.StatusOK, gin.H{
				"message": flag,
			})
			return
		}

		c.JSON(http.StatusBadRequest, gin.H{
			"message": "You are a Guest, This is only for Host",
		})
	})
```

つまり、クライアントIPが「127.0.0.1」であればflagが出るようです。

IPアドレスを偽装してアクセスする方法は思いつかなかったのでおとなしく
「http\://34.146.230.233:11000/」に飛ぶとこんな感じのサイトが。

![baby1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982234/2689940b-964c-05b3-19a4-f23de173d360.png)

Welcomeの後に自分のグローバルIPアドレスが来ます。

試しにここで「http\://34.146.230.233:11000」と入力してcurlすると

```Welcome, <sapn id=\"client-ip\">34.146.230.233</sapn>\r\n            <br/>\r\n```

なぜかIPアドレスがURLのIPアドレスと全く同じなことがわかります。

ローカルホストの「127.0.0.1:8080」ならいけるのでは?と思い
「http\://127.0.0.1:8080/」を入力してcurlすると(ここに至るまでかなり苦戦した)

```Welcome, <sapn id=\"client-ip\">127.0.0.1</sapn>\r\n            <br/>\r\n```

いけそうです。じゃあ、「http\://127.0.0.1:8080/flag/」で・・・

```Something Wrong```

だめでした。

main.goの中身に弾くコードがあるか見てみます。

```diff_go
        if c.ClientIP() != "127.0.0.1" && (strings.Contains(reqUrl, "flag") || strings.Contains(reqUrl, "curl") || strings.Contains(reqUrl, "%")) {
			c.JSON(http.StatusBadRequest, gin.H{"message": "Something wrong"})
			return
		}
```

ここだけ見ると問題はなさそうですが実は「c.clientIP()」はその前に書き換えられています。

```diff_go
	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", gin.H{
			"a": c.ClientIP(),
		})
	})
```

Burp Suiteでリクエストの1行目を見ると実はこのようになっています。

```GET /curl?url=http://127.0.0.1:8080/&header_key=&header_value= HTTP/1.1```

ここで私はmain.goのコードも踏まえて以下のように推測しました。

curlを行って結果取得

→「/」で「c.clientIP()」を書き換え

→「/curl/」で(「?」は「/」と同じようにみている?)「c.clientIP()」が「127.0.0.1」と同じか判断

→ほかにもいろいろあるけど特に問題なければ結果表示

ここでもだいぶ苦戦。

どうやらHTTPヘッダに「X-Forwarded-For:127.0.0.1」を「Accept-Encoding」の前に入れると

「c.clientIP()」が優先的に「127.0.0.1」と判定するようです。

したがって以下の手順でflagを獲得しました。

1.「http\://127.0.0.1:8080/flag/」と入力してcurlする

2.Brup Suiteで以下のように「X-Forwarded-For: 127.0.0.1」を入力して、送信する

![baby2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982234/7991e935-07ea-3c15-879e-244499378336.png)

3.flagゲット

![babyflag.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982234/e70e2579-c7d3-ee38-c4a8-ae97ff9e8e16.png)

```LINECTF{6a22ff56112a69f9ba1bfb4e20da5587}```

推測なので間違っている可能性がありますが参考までに。

## 最後に
今まで初心者向けじゃない外部CTFの問題は1問も解けなかったので、今回のCTFで1問解けて良かったです。
JavaScript のブラケット表記には少し注意しよう

# JavaScript のブラケット表記 とは
オブジェクトのプロパティに `obj["prop"]` のようにアクセスする方法のことです。

```js
const user = {
  name: "John",
  age: 30,
  isAdmin: false
};

console.log(user.name); // ドット表記
console.log(user["name"]); //ブラケット表記
```

# 静的解析での警告
[Gitlab の静的解析機能](https://docs.gitlab.com/ee/user/application_security/sast/)で静的解析を行ったところ、次のような警告が出ました。

```json
{
      "message": "Improper Control of Generation of Code ('Code Injection')",
      "description": "Bracket object notation with user input is present, this might allow an attacker to access all properties of the object and even it's prototype, leading to possible code execution.",
      "severity": "Medium",
      "location": {
        "file": "apps/frontend/src/xxxx.ts",
        "start_line": 14
      }
}
```

この警告は簡単に言うと **ブラケット表記を使うと、悪意のあるユーザから任意のプロパティにアクセスされてしまう可能性があるよ！** というものです。

# 具体例
ユーザが自分の情報について任意の項目名と値で登録できる機能がある場合、下記のような実装だと他のプロパティを書き換えられてしまいます。（そんな実装するかいな！と思うかも知れませんが。）

```js
const user = {
  name: "John",
  age: 30,
  isAdmin: false
};

// ユーザから入力を受け取る
const customField = prompt("Input custom field name.")
const customValue = prompt("Input custom value.")

user[customField] = customValue;
```

この例だと、ユーザが項目名を `name` にすると、既存の `user.name` の値を上書きされてしまいます。

# 対策
### 十分にバリデーションを行う
すでに存在するキーは禁止するなど、十分にバリデーションを行うことで回避します。

```js
if (user.hasOwnProperty(customField)) {
  alert('その項目名は利用できません')
} else {
  user[customField] = customValue;
}
```

### キー名をユーザに指定させない
```js
const user = {
  name: "John",
  age: 30,
  isAdmin: false,

  // キー名はこちらで指定したものにしておく
  customField: {
    name: "",
    value: "",
  }
};

// ユーザから入力を受け取る
const customField = prompt("Input custom field name.")
const customValue = prompt("Input custom value.")

// ドット表記でアクセスして代入する
user.customField.name = customField;
user.customField.value = customValue;
```

# まとめ
静的解析を実行したときに警告が出たので、どのような場合に危険なのか、気になったので調べてみました。
結論としては、**ユーザから受け取った任意の値でプロパティにアクセスしていなければ問題なさそうです。**
【全3回】AWSで静的サイトを公開する　②HTTPで接続

第1回はドメイン取得まで行いました
https://qiita.com/mugihara/items/551e7b0d2367400e1ed3
今回はHTTPで接続を行います。
※AWSアカウントの取得および公開予定のHTMLファイル等の作成は完了している前提です。

<b>HTTP通信とは</b>
WebブラウザやWebサーバーなどのクライアントとサーバー間でデータを転送するためのプロトコル。
WebブラウザがWebページを表示するために使用される。Webブラウザは、ユーザーが入力したURLを解析し、WebサーバーにHTTPリクエストを送信する。Webサーバーは、HTTPレスポンスを返し、WebブラウザはHTTPレスポンスを受け取り、HTML、CSS、JavaScriptなどのコンテンツを表示する。

つまり、今回の工程によってブラウザがAWSのS3（ストレージ）にHTTPで接続してファイルの情報を確認できるようにする≒ブラウザでサイトが見えるようにする
というところまでできるようになります。

1.AWSのS3で「バケットを作成」をクリック。
![スクリーンショット (119).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/6a854a83-5071-5a99-19da-c476af0a885c.png)

2.バケット名に取得したドメインを入力し、作成。
![スクリーンショット (121).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/293f7f55-125e-173c-d772-d4bd59f875b4.png)

3.HTMLファイル等をアップロードする。（HTMLファイルはファイル名を「index.html」とすること）
![スクリーンショット (122).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/4c178636-8150-371d-848e-cf39e5b18599.png)

ここまででS3バケットへのファイルのアップロードが完了しました。
次にS3の公開設定に移ります。

4.バケット内の「プロパティ」タブに移動し、下部にある「静的ウェブサイト」の「編集」をクリック。
![スクリーンショット (123).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/59e28f22-0f80-f8f8-913c-db4ec3d4c716.png)

5.「インデックスドキュメント」の欄に「index.html」、「エラードキュメント」の中に「error.html」と入力し、「変更の保存」をクリック。（エラードキュメントは作成、アップロードしていなくても問題ありません、記入だけしておいてください）

6.バケット内の「アクセス許可」タブに移動し、ブロックパブリックアクセス（バケット設定）」の編集ボタンをクリック。
![スクリーンショット (124).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/c9f385cd-409f-cc03-4526-e15a38e79df4.png)

7.チェックをすべて外して保存。（確認画面が開かれたら「確認」と入力）
![スクリーンショット (126).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/62fa8348-28ba-c063-30d4-5c7f811353ec.png)

8.「アクセス許可」タブ内の「バケットポリシー」の「編集」をクリック。するとバケットポリシーを入力する画面になります。
![スクリーンショット (127).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/078380c4-fd38-14ee-00c0-49b2960fe0b8.png)

9.以下の記述を貼り付けます。
```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::owl-light.net/*"
        }
    ]
}
```
※"Resource"のS3::より後は自身のドメインを記入してください。
※AWSの公式ドキュメントを参照しています。うまくいかない場合はこちらが更新されていないか確認してください。
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/HostingWebsiteOnS3Setup.html

10.「プロパティ」タブに移動し「静的ウェブサイトホスティング」の中のhttp://　で始まるURLをクリック。無事サイトを確認できればOKです。
![スクリーンショット (128).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3276718/278fbf03-8a89-add0-3c85-55b860325499.png)


ここまででサイトのHTTP接続は完了しました。
第3回ではHTTPSでサイトを公開します。
秋月電子のSoCで遊ぶメモ。

Wi-SUNのドングル、最低でも１万して、遊びで買うには敷居が高いですよね。
先週、Twitterで、なんとWi-SUNのボードが乗ったSoCが売っているとの情報が出ていたので、昼休みに買ってきました。

Wi-SUNとは、スマートメーターなんなの情報を引っこ抜くために必要な通信規格で、日本オリジナルのようです。

先駆者がＳｏＣの起動イメージを公開してくれていたので、
それを手元のRHEL8でコンパイルを通すまでのメモ書きです。
ひろみつさん、感謝です。

https://github.com/bakueikozo/buildroot_am3352_aki

コンパイル環境とライブラリの準備
yum install gcc-c++
yum install perl
yum install openssl-devel

menuconfigを使うなら、こちらも
yum install ncurses-devel

ソースの入手
git clone https://github.com/bakueikozo/buildroot_am3352_aki.git

cd して
make akiduki_am3352_defconfig
make
食事に行く

output/imagesのsdcard.img をｄｄで焼く
dd if=./sdcard.img of=/dev/sda
当然ですが、/dev/sda　の中身は全部消えますので、
消してもいいSDのデバイスにあわせて書き換えてください。

言わずもがなですが。
AWS Summit Tokyoにエントリー完了した？Googleカレンダーに一括で登録しよう

AWS Summit Tokyoがもうすぐ開催されますね！今回も盛りだくさんのセッションが用意されていて楽しみですね。とりあえず色々なセッションに登録はしたものの、それぞれをGoogleカレンダーに登録するのって結構面倒じゃないですか？


そんなあなたのために、今回は一括でGoogleカレンダーに登録できるブックマークレットを作りました。これで、カレンダー登録もラクラク、AWS Summit Tokyoを余すことなく楽しめる（はず）です


## まずAWS Summit Tokyoのマイページを開きます
以下のページからログインして、マイページにアクセスしましょう。
   https://jpsummit.awsevents.com/public/mypage/top/plain
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59148/a50830c2-1cab-2591-610d-157d61588e04.png)


## 次のブックマークレットを叩きます（URLから、コンソールから実行どちらでも可）
```

javascript:(function() {
    function createGoogleCalendarLink(startDate, endDate, title) {
      const startTime = startDate.toISOString().replace(/-|:|\.\d+/g, '');
      const endTime = endDate.toISOString().replace(/-|:|\.\d+/g, '');
  
      const encodedTitle = encodeURIComponent(title);
  
      return `https://www.google.com/calendar/render?action=TEMPLATE&dates=${startTime}%2F${endTime}&text=${encodedTitle}`;
    }
  
    const listItems = document.querySelectorAll('.ss_mypage_application_document li');
    const regex = /(\d+)月(\d+)日\(.{1}\)\s+(\d+):(\d+)-(\d+):(\d+)（(\d+)分）(?:<br>)*(.*?)(?:<br>*)/is;
    const currentYear = new Date().getFullYear();
  
    listItems.forEach((listItem) => {
      const content = listItem.innerHTML;
      const match = regex.exec(content);
  
      if (match) {
        const [_, month, day, startHour, startMinute, endHour, endMinute, duration, title] = match;
        const startDate = new Date(currentYear, month - 1, day, startHour, startMinute);
        const endDate = new Date(currentYear, month - 1, day, endHour, endMinute);
      
        const link = createGoogleCalendarLink(startDate, endDate, title);
  
        const anchor = document.createElement('a');
        anchor.href = link;
        console.log(link);
        anchor.target = '_blank';
        anchor.textContent = link;
  
        listItem.appendChild(anchor);
      } else {
          console.log(content, match);
      }
    });
  })();
  
```


## 各予定部にGoogleカレンダーに登録できるリンクが発行される
それぞれぽちぽち登録してあげてください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59148/00bdbf7c-dd19-b5fb-0857-8e1447fdd8c2.png)

リンククリックしたらGoogleカレンダーの新規イベント生成画面（入力後）が表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59148/9362899f-df34-19f1-6af5-3005f966edc6.png)


これで、AWS Summit Tokyoの予定をGoogleカレンダーに登録することができました
Pythonでファイルを（改行取り除いて）高速に読み込みたい！

# はじめに
Pythonで複数行のファイルを読み込む方法はたくさんあり，どの方法が早いのかを調べました．
（Wikipediaのタイトルを全部読み込んで色々としたい時に，気になったのでまとめました！）

# TL;DR
ファイル全体を読み込んでsplitlinesする[方法２](#2-ファイル全体を読み込んでsplitlinesする)が一番早い


# 方法たち
1,000,000行のファイルを読み込む．文字列の長さは多くても30くらい．
## 1. 一行ずつ読み込み，改行をreplaceする
```python
def func1(file_path):
    lines = []
    with open(file_path, "r", encoding="utf-8") as f:
        for line in f:
            lines.append(line.replace("\n", ""))
    return lines
```
## 2. ファイル全体を読み込んでsplitlinesする
```python
def func2(file_path):
    lines = []
    with open(file_path, "r", encoding="utf-8") as f:
        lines = f.read().splitlines()
    return lines
```
## 3. 各行をリストにして，rstripで改行を消す
```python
def func3(file_path):
    lines = []
    with open(file_path, "r", encoding="utf-8") as f:
        for line in f.readlines():
            lines.append(line.rstrip())
    return lines
```

# 雑な予想
- 方法1の```replace```は各行の文字列を検索する＋置き換えるから一番遅そう．無駄も多い
- 方法2は，全体読み込んで，```splitlines```で改行を検索するから，方法1と同じくらい？for文使ってないから少し早いかも？
- 方法3は，```rstrip```で場所(末尾)を指定して取り除いてるから，一番早そう

# 結果
- 方法1 : 0.513
- 方法2 : <b>0.249</b>
- 方法3 : 0.492
となり，圧倒的に<b>方法2</b>が早かった．

# 最後に
なぜ方法2が一番早いんだ？？？よくわからないです(;´･ω･)

## 自分用メモ
ページ内リンクは
```[方法２](#2-ファイル全体を読み込んでsplitlinesする)```みたいに，空白はダッシュに置換，ピリオドは無視する
クラウドサービスの分類 (IaaS,PaaS,SaaS)

IaaS,PaaS,SaaSは全てクラウドサービスだが、提供するサービスの範囲が異なる。

・SaaS(Software as a Service)
 サービスやソフトウェアを提供。 例：Gmail,Slack,Zoom

・PaaS(Platform as a Service)
 OSやデータベース等のミドルウェアを提供。　例：Heroku

・IaaS(Infrastructure as a Service)
 サーバーやネットワーク環境を提供。　例：AWS EC2


SaaS- 提供範囲は狭く自由度は低いが、ユーザーは簡単にサービスを利用できる。
　　　　　　　　　　　　　　　　　　
PaaS- 提供範囲　中、自由度　中

IaaS- 提供範囲が広く自由度は高いが、ユーザーが自分で構築する部分が多い。


参考サイト
https://www.nec-solutioninnovators.co.jp/sp/contents/column/20220729_saas.html
（NECソリューションイノベータ　　SaaSとは？意味や読み方、代表例をわかりやすく解説）
https://www.itmanage.co.jp/column/saas-paas-iaas/
（アイティーエム　　SaaS,PaaS,IaaSとは？クラウドサービス定義の違いを比較し読み方や意味などを解説）
タワーデフェンスゲーム　Unity 敵の機能　1/10　初期時点に移動し待機するようにする

# 概要
敵機能の実装を行います。
今回は敵が初期位置に移動し待機する機能を実装します。

以下gifアニメは　初期時点を動かしてオブジェクトがそれに追従している様子です。

![Enemy1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/0b0f0219-4529-1219-ca2a-19843d96394e.gif)


続き

https://qiita.com/RYA234/items/2632c67fffcc4ce4e07a

# 開発環境

IDE:Rider
Unity:2020.3.42(LTS)
OS:Windows10

# 実装のポイント

Vector3.MoveTowardsメソッドを使って点の座標に敵オブジェクトが移動するようにします。
Waypointに該当する点を取得するメソッドを追加します。

# コード部分

```diff_c_sharp:Waypoint.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

// 座標を定義しているクラス、オブジェクトにアタッチする
public class Waypoint : MonoBehaviour
{
    // Start is called before the first frame update
    [SerializeField] private Vector3[] points;
    public Vector3[] Points => points;

    void Start()
    {
    }
    private void OnDrawGizmos()
    {
        for (int i = 0; i < points.Length; i++)
        {
            if (i < points.Length - 1)
            {
                Gizmos.color = Color.yellow;
                // 隣接する２点間の距離を引く
                Gizmos.DrawLine(points[i], points[i + 1]);
            }
        }
    }

+    public Vector3 GetWaypointPosition(int index)
+    {
+        return points[index];
+    }
}
```

```diff_c_sharp:Enemy.cs
using System;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    [SerializeField] private float moveSpeed = 3f;
    [SerializeField] private Waypoint waypoint;
    public Vector3 CurrentPointPosition => waypoint.GetWaypointPosition(_currentWaypointIndex);
    private int _currentWaypointIndex;

    private void Start()
    {
        _currentWaypointIndex = 1;
    }

    private void Update()
    {
        Move();
    }

    private void Move()
    {
        Vector3 currentPosition = waypoint.GetWaypointPosition(_currentWaypointIndex);
        transform.position = Vector3.MoveTowards(transform.position, currentPosition, moveSpeed * Time.deltaTime);
    }
}

```



# 参考

Vector3.MoveTowards

https://docs.unity3d.com/ja/current/ScriptReference/Vector3.MoveTowards.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/aeaa42e7-e4f3-2644-b2f9-9b3efc85b3b0.png)


Section4 13

https://www.udemy.com/course/learn-how-to-create-a-2d-tower-defense-game-in-unity-2020/learn/lecture/22898166#content

github コミット分

https://github.com/RYA234/2DTowerDeffenceMyLearning/commit/887710e4f761f9ead874005c8d977c4144f80b5f


章まとめ

https://qiita.com/RYA234/private/6d878a7958a3c760c8af
【Ruby】意外と便利？？methodsメソッドの話

Rubyではオブジェクトに対して呼び出せるメソッド一覧を`methods`で取得できるのですが、このメソッドがデバックする際などに意外と便利でおすすめだよって話です🔥

シチュエーションに合わせて、`private_methods`や`instance_methods`などの類似メソッドも交えながらまとめてみました。

## 概要
### `methods`
- **対象オブジェクトに対して呼び出せるメソッドの一覧**を、シンボル配列の形で返却します。
### `private_methods`
- **対象オブジェクトに対して呼び出せるprivateメソッドの一覧**を、シンボル配列の形で返却します。
### `instance_methods`
- **対象クラスのインスタンスに対して呼び出せるメソッドの一覧**を、シンボル配列の形で返却します。
:::note info
全てデフォルトではスーパークラスや基底クラス(Objectなど)のインスタンスメソッドも返却されます。
:::

## サンプルコード

以下のコードはこのサンプルコードを前提に記述しています。

```ruby
class SuperSample
  def super_sample; end
	private; def private_super_sample; end
end

class Sample < SuperSample
  def sample; end
  private; def private_sample; end
end
```

## 使い方
### オブジェクトが応答できるメソッドを全て取得したい

`methods`の結果に`private_methods`の結果を加えることで取得できます。

```ruby
sample = Sample.new
sample.methods + sample.private_methods
# => [:sample, :super_sample, :private_sample, :private_super_sample, :to_json, :to_s,....]
```

### オブジェクトが応答できるprivate以外のメソッドを全て取得したい

`methods`を使って取得できます。

```ruby
sample = Sample.new
sample.methods
# => [:sample, :super_sample, :to_json, :to_s,....]
```

### 基底クラスのインスタンスメソッドを除いてて取得したい

基底クラスのインスタンスメソッドを`methods`の返却値から除くことで取得できます。

```ruby
sample = Sample.new
sample.methods - Object.instance_methods
# => [:sample, :super_sample]
```

### 対象オブジェクトのインスタンスメソッドのみを取得したい

スーパークラスのインスタンスメソッドを除くことで取得できます。

```ruby
sample = Sample.new
sample.methods - sample.class.superclass.instance_methods
# => [:sample]
```

また対象オブジェクトのクラスに対して、`instance_methods`を引数`false`指定で使用しても取得できます。

```ruby
Sample.instance_methods(false)
# => [:sample]
```

## 参考
- [instance method Object#methods](https://docs.ruby-lang.org/ja/latest/method/Object/i/methods.html)
[SQLServer]初心者向け：NULLとは　

# NULLの扱いについて

## 初めに
今回は**NULL**についての理解を目標
簡単なSELECT文の記述について

## 目次
**NULLとは**

**テーブルの用意**

**IS NULL を用いて、NULLを選択する**

**IS NOT NULLを用いて、NULLを除外できる**

**最後に**

## NULLとは
NULLとは大体以下のように定義されていることが多い。

**「何も存在しない」、「何も示さないということ」である**。

なぜ、NULLという概念が必要かを考えてみよう。
例として以下の図書館の本の貸し出しを考えてみよう。

Aの本を、C君が借りるという場合、
借りている人、貸出日、返却日は**一意的**に決まるだろう。

しかし、

Bの本は誰も借りていない場合、
借りている人も貸出日も返却日も存在しない。

この場合、以下のようなテーブルであらわされる。

|  本  | 貸りている人   | 貸出日  |  返却日 |   
| ---- | ---- | ---- | ---- |   
|  Aの本  |  C君  |  2022/1/1  |  2022/17  |    
|  Bの本  |  NULL  |  NULL |  NULL  | 

何もないということが、**NULL**の概念である。

## テーブルの用意

今回は以下のSQL文を実行してみました。

テーブル定義

```sql:CREATE文
CREATE TABLE LIBRARY(
	Id INT NOT NULL IDENTITY(1,1) PRIMARY KEY
	,BookName NVARCHAR(50) NOT NULL
	,Name NVARCHAR(50) 
	,LendDate DATE
	,ReturnDate DATE
	,UpdateDate Date
);
```

```sql:INSERT文
INSERT INTO LIBRARY VALUES('A','加藤','2023/03/04','2023/03/11','2023/03/01');
INSERT INTO LIBRARY VALUES('B','佐藤','2023/03/05','2023/03/12','2023/03/01');
INSERT INTO LIBRARY VALUES('C','山田','2022/03/03',NULL,'2023/03/01');
INSERT INTO LIBRARY VALUES('D','篠田','2022/03/04',NULL,'2023/03/01');
INSERT INTO LIBRARY VALUES('E',NULL,NULL,NULL,'2023/03/01');
INSERT INTO LIBRARY VALUES('F',NULL,NULL,NULL,'2023/03/01');
INSERT INTO LIBRARY VALUES('G','本返さない太郎','2022/02/13',NULL,NULL);
INSERT INTO LIBRARY VALUES('H',NULL,NULL,NULL,'2023/03/01');
```
```sql:SELECT文
SELECT * FROM LIBRARY
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3296700/799c6724-c9b3-b3af-f8ee-aff5a4bde4e9.png)


## IS NULL を用いて、NULLを選択する


```sql:本を借りている人を探すSELECT文
SELECT * FROM LIBRARY WHERE [Name] IS NULL
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3296700/d7c4345a-e651-a506-cc3c-9e3891b118ee.png)

## IS NOT NULLを用いて、NULLを除外できる


```sql:本を借りている人を探すSELECT文
SELECT * FROM LIBRARY WHERE [Name] IS NOT NULL
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3296700/b1de187a-e0c8-4adf-f835-c4c471c32bef.png)

## 最後に
SQL文は何度も練習することが大事だと思いました。
次はNULLに対処するのみの記事を書いてみたいと思いました。
Windows環境：`NamedTemporaryFile`で作成したファイルを再度openすると、`PermissionError`が発生する

# 環境
* Python3.11.2
* Xubntu 22.04
* Windows11 Pro 22H2


# やりたいこと
tempfileモジュールを使って一時ファイルを作成したいです。


```python:sample.py
import tempfile
    

def write_hello_file(file_path:str) -> None:
    print(f"{file_path=}")
    with open(file_path, mode="w") as f:
        f.write("hello")

        
with tempfile.NamedTemporaryFile() as f:
    write_hello_file(f.name)

```


```
$ python sample.py
file_path='/tmp/tmp83qptmm7'
```

# 起きたこと
Windowsで実行すると、`PermissionError`が発生しました。

```

PS > python sample.py
file_path='C:\\Users\\admin\\AppData\\Local\\Temp\\tmpnlbu7s17'
Traceback (most recent call last):
  File "C:\Users\admin\Documents\study\20230328\sample.py", line 11, in <module>
    write_hello_file(f.name)
  File "C:\Users\admin\Documents\study\20230328\sample.py", line 6, in write_hello_file
    with open(file_path, mode="w") as f:
         ^^^^^^^^^^^^^^^^^^^^^^^^^
PermissionError: [Errno 13] Permission denied: 'C:\\Users\\admin\\AppData\\Local\\Temp\\tmpnlbu7s17'
```


# 何が原因か

`NamedTemporaryFile`で作成したファイルを2回openしたときの動きは、プラットフォームによって異なるからです。

>Whether the name can be used to open the file a second time, while the named temporary file is still open, varies across platforms (it can be so used on Unix; it cannot on Windows). 

https://docs.python.org/ja/3.11/library/tempfile.html#tempfile.NamedTemporaryFile


# どのように解決したか
`TemporaryDirectory`で一時ディレクトリを作って、そのディレクトリに一時ファイルを作成しました。

```python        
with tempfile.TemporaryDirectory() as str_temp_dir:
    write_hello_file(f"{str_temp_dir}/temp.txt")

```


```
PS > python sample.py
file_path='C:\\Users\\admin\\AppData\\Local\\Temp\\tmp9qgjr91l/temp.txt'

```

以下のサイトのように、`NamedTemporaryFile(delete=False)`を指定して自分で一時ファイルを削除する方法もあります。
ただし、この方法だと一時ファイルを削除し忘れる恐れがあるので、採用しませんでした。


https://www.tssol.net/blog/2019/12/14/permission-error-errno-13-permission-denied-in-python-on-windows/
【React】表を作る

## Reactで表を作る
今回はReactで表を作って表示させます。
HTMLと同じようにTableタグなどを使って作成していきます。

## やってみる
```typescript:table.tsx
import React from 'react';

function Table(props) {
  const dataArray = [
      { name: '田中', age: 25, city: '東京' },
      { name: '高橋', age: 30, city: '大阪' },
      { name: '佐藤', age: 35, city: '北海道' },
  ];
  
  return (
    <table>
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
          <th>City</th>
        </tr>
      </thead>
      <tbody>
        {dataArray.map((item, index) => (
          <tr key={index}>
            <td>{item.name}</td>
            <td>{item.age}</td>
            <td>{item.city}</td>
          </tr>
        ))}
      </tbody>
    </table>
  );
}
```
簡単な表ですが、npm startで実行してみると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884542/9e9a51e3-7867-eb39-2901-e3a34311c19f.png)
このような表が表示されます。
`th`タグにcolorやbackground-colorなどを指定すると文字色や背景色を変えることができます。
利用しているAWS Configルールを一覧で取得したい

# 1.はじめに
エンジニアとしてAWSを利用していると、お客様（非エンジニア）とのギャップに気づくことが多々あります。
エンジニアとしては「コンソールから見れば済むのに」という内容も、お客様にとってはパラメータシートなど資料に起こして管理したいと思うこともあるようです。

今回は、AWS Configを一覧で取得しようと思います。
※プログラム歴が浅く、コード上の改善案があればコメント頂けると幸いです:sunny:


# 2. 本記事の内容
いくつかの参考記事をベースにPythonのBotoCoreを使い
サービス上限緩和の状況をJSON形式で一覧として取得します。


# 3.  実装内容
 ``describe_config_rules()``APIを使い、ルール一覧作成


# 4. 参考
 - [Boto3 Docs 1.20.4 documentation - Config -](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/config.html#id116)
 - [AWS Docs - Configが有効であることを確認する -](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/gs-cli-verify-subscribe.html)


# 5. 実装詳細
### 5-1. ソース
```python:
import boto3

region='ap-northeast-1'

### config rule一覧取得
config_rules_list = boto3.client('config', region_name=region).describe_config_rules()
tmp_result_config_rules = config_rules_list

if 'NextToken' in tmp_result_config_rules:
    while 'NextToken' in tmp_result_config_rules:
      next_token = tmp_result_config_rules['NextToken']
      tmp_result_config_rules = boto3.client('config', region_name=region).describe_config_rules(NextToken=next_token)
      config_rules_list['ConfigRules'].extend(tmp_result_config_rules['ConfigRules'])

with open('config_rules_list.txt', 'a') as f:
    print(config_rules_list, file=f)
```

### 5-2. Configルール一覧結果イメージ
'ConfigRuleName'はルール名です。
'ConfigRuleArn'はルールのARNです。
'ConfigRuleId'はルールに一意に割り当てられるIDです。同じマネージドルールでも複数デプロイできるので、そういったときは末尾の識別子が違うものがデプロイされます。 
'Owner'は、AWS or CUSTOM_LAMBDAが表示されます。マネージドルールの場合はAWS、カスタムルールの場合はCUSTOM_LAMBDAです。
'SourceIdentifier'はマネージドルールの場合は固定のルール識別子、カスタムルールの場合はLambdaのARNが表示されます。
'InputParameters'はルールごとのパラメータが表示されます。
'MaximumExecutionFrequency'は定期評価をするルールで設定されるものです。デフォルトは24時間です。
'ConfigRuleState'はルールの状態です。ACTIVEは利用可能な状態です。

```text:
{
    'ConfigRules': 
        [
            {
                'ConfigRuleName': 'access-keys-rotated', 
                'ConfigRuleArn': 'arn:aws:config:ap-northeast-1:＊＊＊:config-rule/config-rule-＊＊＊', 
                'ConfigRuleId': 'config-rule-＊＊＊', 
                'Source': 
                    {
                        'Owner': 'AWS', 
                        'SourceIdentifier': 'ACCESS_KEYS_ROTATED'
                    }, 
                    'InputParameters': '{"maxAccessKeyAge":"90"}',
                    'MaximumExecutionFrequency': 'TwentyFour_Hours',
                    'ConfigRuleState': 'ACTIVE'
            }, 
～略～
```

ルールによっては、他にも要素が表示される場合があります。
マネジメントコンソールには表示されないものも多いので、リファレンスを確認することをおすすめします。

# 6. まとめ
一回のAPI実行では全件取得できず、nextpagetokenを指定する様にループ処理を実装しないといけない点が初心者には難しかったです。
適合パックでデプロイされているルールも、この処理で取得できます。

エクセルファイル化する処理を追加するなどして、より利用しやすくすると良いかもしれません。

AWS Configはかなりやりこみ要素の強いサービスだと思います。
元々はクラウドガバナンスを効かせたり、構成を管理したりするためのサービスですが、Configルール自体を管理できないような煩雑な状態になってしまわないように気をつけたいです。


# 補足
ルール一覧はdescribe_config_rules()で取得できますが、AWS Config自体の設定値は別APIが必要になります。
※通常は、特に引数もなく実行できるので簡単に取得できます

1. ``describe_delivery_channels()``は、AWS Configの配信設定（S3バケットやSNSトピック）の取得
1. ``describe_configuration_recorders()``は、AWS Configの一般設定の取得
ESXi仮想マシンのホットバックアップ

仕組みをあまり理解していなかったので「[ghettoVCB](https://github.com/lamw/ghettoVCB)」などでおそるおそるやっていましたが、
ようはスナップショットを作成してディスク書き込みを差分ディスクに逃がしている間に、
実体となるディスクイメージを取得してしまえば良いだけのことみたいですね。

手動でのホットバックアップ手順
とりあえず自分用にメモ

①スナップショットが無い状態で構成情報をダウンロードする
HOSTNAME.vmx
HOSTNAME.vmxf
HOSTNAME.vmdk
HOSTNAME.vmsd
HOSTNAME.nvram

②スナップショットを作成する

③ディスクイメージをダウンロードする
HOSTNAME-flat.vmdk

④スナップショットを削除する

※ディスクイメージのダウンロードは、SSHコンソールを有効にしたうえでtar.gzなどで固めてから転送したほうが良いと思います。


仕組みが判ってしまえばそんなに怖いものでもないですね(？)
Amazon Linux 2023がついにリリース

# はじめに
Amazon Linuxをご存じでしょうか？
Linuxディストリビューションと言うと、RHEL(Red Hat Enterprise Linux )が一番有名だと思いますが、有償なためサポートを必要としない（けど、セキュリティアップデートはして欲しい）場合、RHELのソースからビルドされたRHELのクローンとしてCentOSを使っていたという方は多いと思います。ご存じの通りCentOSはRHEL8以降のクローンパッケージは作らないと発表されており、残念ながらRHELに対し互換性の高いディストリビューションは無くなる傾向にあります。Amazon LinuxはAWSがメンテナンスしているRHEL系のディストリビューションです。RHELに完全互換を目指している訳ではありませんが、無償で5年間のメンテナンスを受けられるOSとしては検討の価値はあると思います。

# Amazon Linux 2023とは
Amazon Linux 2023は初代Amazon Linuxが2010/9にリリースされて以来、Amazon Linux 2に次ぐ、3世代目のAmazon Linuxです。
Amazon LinuxはRed Hat社が出資する開発プロジェクトFedoraをベースに作られています。なので、RHELに似ていますが、RHELのクローンと言うわけではありません。よって、市販のパッケージソフトウェアでRHEL対応となっているのもが動かない可能性は十分あります。特に、Kernelに深く関与するマルウェア対策ソフトや、特定のバージョンのランタイムライブラリを必要とするパッケージなどは動かない可能性が高いです。逆に言えば、dockerやOSSのアプリ基盤として利用する分にはAWSのサポートも受けられセキュリティパッチも提供されるので商用利用にも耐えられると思います。

# Amazon Linux 2023の特徴
- 5年間のサポート
2年ごとに新しいメジャーバージョンが発行され、それぞれ5年間のサポートが受けられます。（UbuntuのLTSに似てますね)
2年間は機能改善を含む標準サポート、残りの3年はセキュリティパッチ提供を行うメンテナンスサポートを無償で受けることができます。ただし、AWSのテクニカルサポートを得るためにはAWSデベロッパーサポート以上（29.00 USDまたは利用料の3%の大きい方)が必要です(サポートはいつでも無償プランに戻せます)。
- RHEL9に似た構成
  どちらもFedora 34をベースにしていますが、Amazon Linux 2023はFedra 35,36のコンポーネントを取り込んだりしているのであくまでも似た構成になります。
- RHELよりは攻めた構成
　RHELのメンテナンスポリシーとしては基本的にランタイムライブラリのバージョンアップは行わず重要な問題が新しいバージョンで修正された場合はバックポートパッチと言う形で今のバージョンに対して同じ個所を修正するアプローチを取っています。しかし、Amazon Linuxでは標準サポート期間について以下の様に記載があります。確認は取れてないのですが、Ferora側でライブラリのバージョンが上がったら上げる可能性があると思います。なのでライブラリアップデートを含むときはアプリのリグレッションテストをしっかりした方がよさそうです。
>これらのリリースには、Python や Java などの最新の言語ランタイムが含まれる場合があります。

# まとめ
市販のパッケージソフトウェアを使う場合は、対応OSの縛りがあるので難しいかもしれませんが、AWS上でアプリ基盤として利用するのであれば、Amazon Linux 2023は良い選択だと思います。

# 参考
[Amazon Linux 2023 – 長期サポート付きのクラウド最適化 Linux ディストリビューション](https://aws.amazon.com/jp/blogs/news/amazon-linux-2023-a-cloud-optimized-linux-distribution-with-long-term-support/)
[AWS サポートのプランの料金](https://aws.amazon.com/jp/premiumsupport/pricing/?nc=sn&loc=3)
GPT-5が登場しました【RWKV】

「RWKV」は、TransformerレベルのLLM性能を備えたRNNです。高性能、高速推論、VRAMの節約、高速学習、無限の文脈長、自由な埋め込みを実現しています。下記リンクから試すことができます

https://huggingface.co/spaces/BlinkDL/Raven-RWKV-7B

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127414/fc347352-29d0-4708-75f5-a826a675cf43.png)

Attention is All you need vs Recurrent is All you need
【TestCafe】TestCafeで変数をまとめる方法

## ctxオブジェクトを使って変数をまとめる
TestCafeでE2Eテストを行うコードを書いていると同じ文字だったり、数字を使ったりすることがあります。
TestCafeではctxオブジェクトを使うと、それらを変数としてまとめることができ、とても便利です。
また、メンテナンスも楽になります。

## まとめてみる
例えば、下のようなテストコードがあるとします。
極端な例ですが、要素1,2,3がすべて`test`を持っているとすると、毎回記述しなければなりません。
これを変数に置き換えてあげることで、変数の値のみを変えるだけで済みます。
```typescript:test1
fixture `Example`
  .page `https://www.example.com`;

test('test1', async t => {
  await t
    .expect("要素1").eql('test')
    .expect("要素2").eql('test')
    .expect("要素3").eql('test')
});
```

***変数を使う***
```typescript:test1
fixture `Example`
  .page `https://www.example.com`;

test('test1', async t => {
  t.ctx.value = 'test';
  await t
    .expect("要素1").eql(t.ctx.value)
    .expect("要素2").eql(t.ctx.value)
    .expect("要素3").eql(t.ctx.value)
});
```
読書感想文的なもの#6学びを結果に変えるアウトプット大全

# この本を選んだ経緯
###

以前投稿した#5「読書感想文的なもの#5やる気に頼らず「すぐにやる人」になる３７のコツ」に続いて今回はこの本を選びました。

シンプルにタイトルに惹かれたことと、
アウトプットが苦手な自覚が大いにありますのでそれを
改善したいという思いがあり購入に至りました。

# どのような方にオススメの本なのか
###
__インプットばかりで全くアウトプットできていない人、、、
自己成長をどんどんしていきたい人、、、__
###

こう言った方はぜひ読んでいただきたい本です！

いかに効率の悪い勉強方法をしていたのかと思い知り、同時にアウトプットの重要性が非常に良くわかる本だと感じました。

アウトプットの重要性とインプットの効果を最大限に引き出すための方法や継続するための
コツなどが書かれており、自己成長したい人は本書を強くお勧めします。

###
# 基本原則
###

インプットは読む、聞く。アウトプットは話す、書く、行動する。
書いて覚える、声に出して覚えるようにするだけで、運動性記憶として記憶することができる。運動性記憶は記憶に残りやすい。
インプットしても、その情報を何度も使わないとすぐに忘れてしまう。脳に入力された情報は前頭葉の海馬に仮保存されるが、保存期間は2週間程。インプットしたら、2週間で3回以上アウトプットすると記憶に残りやすくなる。
インプットとアウトプットの黄金比は3対7。(コロンビア大学のアーサー・ゲイツの研究)
アウトプットしたあとはフィードバックを行い行動を修正する。なぜうまくいった？なぜ失敗した？次はどうする？を考える。

###
# 基本原則
###
圧倒的に結果を出す人の行動力

# まとめ
###
内容は「アウトプット」に関する情報がこれでもかというくらいにまとめられていました。

私に足りないものは「アウトプットの量」ということは自覚はありましたが、アウトプットの重要性を再度理解できました。
間違いなく、 
### アウトプットしたほうが成長できる！

アウトプットして、改善して、情報を取得してを繰り返して成長を繰り返していきたい！
誰からも必要とされる人になりたい！

上記のことを改めて強く感じた一冊でした！

気になった方はぜひこの本を読んでみてください。


拙文最後までお読みいただきありがとうございました！
###
https://www.amazon.co.jp/s?k=%E5%AD%A6%E3%81%B3%E3%82%92%E7%B5%90%E6%9E%9C%E3%81%AB%E5%A4%89%E3%81%88%E3%82%8B%E3%82%A2%E3%82%A6%E3%83%88%E3%83%97%E3%83%83%E3%83%88%E5%A4%A7%E5%85%A8&adgrpid=51991315343&hvadid=649133955532&hvdev=c&hvlocphy=1009250&hvnetw=g&hvqmt=e&hvrand=8203651491838341709&hvtargid=kwd-677416073992&hydadcr=3639_13652366&jp-ad-ap=0&tag=googhydr-22&ref=pd_sl_5e358ami40_e
z^8=1「zのn乗=1 解に隠された美しい性質」をWolframAlphaとsympyでやってみたい。

WolframAlphaで図がでます。
ｚの105乗＝1をページ下で実行しました。

オリジナル

https://youtu.be/Kyo9eZVVU2g

# WolframAlphaで
複素解で「根をもっと表示」でした。根は8個です。
複素平面上の根 がでます。

https://www.wolframalpha.com/input?i=z8%3D1&lang=ja

English版(ページ右上のサインインをautomaticからEnglishにします。)
Roots in the complex plane

https://www.wolframalpha.com/input?i=z8%3D1

# sympyで計算
①私の環境は,pycharmです。
②よく聞くのは、Jupyterです。

```python
from sympy import *
var('z')
print("#",solve(Eq(z**8,1)))
ans=solve(Eq(z**8,1))
print("#",len(ans),"個")
for x in solve(Eq(z**8,1)):
  print("#",x)
# [-1, 1, -I, I, -sqrt(2)/2 - sqrt(2)*I/2, -sqrt(2)/2 + sqrt(2)*I/2, sqrt(2)/2 - sqrt(2)*I/2, sqrt(2)/2 + sqrt(2)*I/2]
# 8 個
# -1
# 1
# -I
# I
# -sqrt(2)/2 - sqrt(2)*I/2
# -sqrt(2)/2 + sqrt(2)*I/2
# sqrt(2)/2 - sqrt(2)*I/2
# sqrt(2)/2 + sqrt(2)*I/2
```

③web上で、上記のソースをコピー貼り付けでも、できました。
黒背景の右上に、マウスを移動すると、コピーマークが発生します。
計算時間は約1分です。資源の無駄使い。ごめんなさい。



https://live.sympy.org/

# sympyで作図
勉強中

# おまけ
別の形
Alternate forms

https://www.wolframalpha.com/input?i=z8-1&lang=ja

English版

https://www.wolframalpha.com/input?i=z8-1

```python
from sympy import *
var('z')
print("#",factor(z**8-1))
# (z - 1)*(z + 1)*(z**2 + 1)*(z**4 + 1)
```

# WolframAlphaで、ｚの105乗＝1
105乗は、＾(ハットマーク)が必要でした。8乗は、不要でした。

https://www.wolframalpha.com/input?i=z%5E105%3D1&lang=ja

# 参考

https://magazine.techacademy.jp/magazine/22382


いつの日か勉強したい。

https://www.youtube.com/watch?v=gAsCeuonWpU&t=0s
【圧縮センシング】複素数に対応したOrthogonal Matching Pursuitの紹介

# 0. はじめに
圧縮センシングとは、観測したデータがスパースなベクトルの線形写像としてモデリングできる場合に、**そのスパースなベクトルを観測データから探索する技術**です。
Orthogonal Matching Pursuit(OMP)は、圧縮センシングの代表的なアルゴリズムです。
Pythonでは、sklearnにてOMPが提供されています[1]。しかし、**データ型がRealである必要**があります。
本稿では、**データ型が複素数であっても動作するOMPのPythonプログラム**を紹介します。
尚、今回実装したOMPのアルゴリズム詳細を知りたい方は、文献[2]の"The Naive Implementation of OMP"を参照ください。

# 1. OMPプログラム
複素数に対応したOMPのプログラムを示します。
```omp.py
import numpy as np

# y = A * x
def omp(A,y,n_sparse):
	r = y.copy()
	L = []
	L0 = A.shape[0]
	L1 = A.shape[1]
	X = np.zeros(L1,dtype=complex)
	vacancy = np.zeros(L0,dtype=complex) 
	A1 = (A.T).copy()
	
	for k in range(n_sparse):
		p = np.argmax(np.abs(np.dot(np.conjugate(A1),r)))
		L.append(p)
		if k == 0:
			A0 = A1[p].copy()
			IAA = 1./(np.dot(np.conjugate(A0),A0.T))
		else:
			A0 = np.vstack((A0,A1[p]))
			IAA = np.linalg.inv(np.dot(np.conjugate(A0),A0.T))

		IA = np.dot(IAA,np.conjugate(A0))
		z = np.dot(IA,y)
		r = y - np.dot(A0.T,z)
		A1[p] = vacancy 
	i = 0
	for idx in L:
		X[idx] = z[i]
		i = i + 1
	MSE = np.sum(np.abs(y - np.dot(A,X)))
	if DEBUG == 1:
		print(A1[p]) 
		print(A[:,p]) 
		print(np.sum(np.abs(A.T-A1)))
		print(np.dot(A,X))
	return MSE, X, L
```

# 2. テスト
## 2.1 テスト用のプログラム
テスト用のプログラムを示します。
プログラムでは、観測データの生成やOMPによる正解データの推定、元の正解データと推定したデータのグラフ表示を行います。尚、今回の正解データは、512要素の内、3要素のみが非ゼロの複素数であるスパースなデータとしました。
```test.py
import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import make_sparse_coded_signal

n_components, n_features = 512, 100
n_nonzero_coefs = 3

# generate the data
# y = Xw
# |x|_0 = n_nonzero_coefs
y, X, w = make_sparse_coded_signal(
    n_samples=1,
    n_components=n_components,
    n_features=n_features,
    n_nonzero_coefs=n_nonzero_coefs,
    random_state=0,
    data_transposed=True,
)

w = np.zeros(w.shape[0],dtype=complex)
w[10] = 1.0+1j*0.5
w[100] = -0.5+1j*1.0
w[200] = 0.5-1j*0.5
(idx,) = w.nonzero()

y = np.dot(X,w)

# plot the sparse signal
plt.figure(figsize=(8, 12))
plt.subplot(2, 2, 1)
plt.xlim(0, 512)
plt.title("Real Part of Sparse signal")
plt.stem(idx, w[idx].real)
plt.subplot(2, 2, 2)
plt.xlim(0, 512)
plt.title("Imaginary part of Sparse signal")
plt.stem(idx, w[idx].imag)

from omp import omp as myomp
MSE, coef, idx_r = myomp(X,y,n_nonzero_coefs)

plt.subplot(2, 2, 3)
plt.xlim(0, 512)
plt.title("Real Part of Recovered signal")
plt.stem(idx_r, coef[idx_r].real)
plt.subplot(2, 2, 4)
plt.xlim(0, 512)
plt.title("Imaginary Part of Recovered signal")
plt.stem(idx_r, coef[idx_r].imag)
plt.show()
```
## 2.2 実行結果
プログラムを実行すると(python test.py)、以下のグラフが表示されます。
グラフの上段は、元の正解データのReal（左）とImaginary（右）をプロットしたものです。
グラフの下段は、ompで推定したデータのReal（左）とImaginary（右）をプロットしたものです。
ompで推定したデータが正しく復元できていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2756450/7cb25c39-ed2e-ed7b-d793-185d6c99ccad.png)

# 3. まとめ
複素数のデータ型に対応したOMPのプログラムを紹介し、正しく動作することを示しました。

# 参考文献
[1] https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.OrthogonalMatchingPursuit.html
[2] https://wnt.sjtu.edu.cn/papers/conf/vtc13-hufeizhu-efficient.pdf
読書感想文的なもの#5やる気に頼らず「すぐにやる人」になる３７のコツ

# この本を選んだ経緯
###
__めんどくさいことって全部後回しにしちゃいますよね・・・__
###
いきなりどうしたのって感じですが、みなさんどうでしょう？

めんどくさいことを、ちゃっちゃと片付けてしまえる人って本当にかっこいいなと思います。
同居人がキビキビ動けるタイプなのですが、
私の怠惰さにちょこちょこプンプンしております。。。本当にごめんなさい。。。

なんでそんなにキビキビ動けるんだろうと純粋に気になって聞いてみたら
「なんも考えずにとりあえず一旦動いてみればなんとかなるもんよ」
そんな答えが返ってきました。

適当、、、と一瞬思ったのですが、この本を読んだ後だと「だからキビキビ動けるんだなぁ」と思うようになりました。

#### 僕も同居人のようにすぐに動ける人になりたい！！！！！！

そう思ったので(ガチ)、色々本を探してこの本を見つけ出しました。

ということで、
以前投稿した#4「人のために頑張りすぎて疲れた時に読む本」に続いて今回はこの本を選びました。


# どのような方にオススメの本なのか
###
__新しく何かを習慣づけたい人、、、
全ての面倒くさがりな人、、、__
###

こう言った方はぜひ読んでいただきたい本です！

すぐやる人・できる人たちは無意識に本書のメソッドの内容ができているんだな、と気づく事ができました。
そういった人たちのように、自然体でやるべきことをこなせるようになりたい人は本書を強くお勧めします。

###
# 仮決め・仮行動でよしとする
###

動けない人の特徴として
「ちゃんと決めてから動いたほうが良い」
といった心理があるのではないかと思います。私もそうです。

無計画は何も成果は出ないと思いますが、
「考えすぎ」というのがむしろ行動できなくなっている原因でもあります。

>すぐ行動できるようになるためには「量」→「質」という順番を意識する事が大切です。

上記のように第一に行動の「量」を意識してその後に「質」を意識するのがポイントとのこと。
これができていないので、私はすぐに行動できないのだと感じました。

そう言った時に「__仮決め・仮行動__」というシステムが力を発揮すると紹介されています。

>筋トレを始めたいが、ジムに通うのと、自宅でのトレーニングのどちらが良いか
ウェアやシューズも筋トレ補助アイテムもいるかなぁ

もし上記のように迷ったなら、とりあえず動きやすい服装に着替えて、
少なくても筋トレをしてみましょう！的なことが書いてあります。

これをしたとして「スクワットが5回しかできなかった」としても、
#### それは失敗ではなく「行動して得られた成果」です！
###
もう一度言います。
#### 失敗ではなく「行動して得られた成果」です！
もし当初の予想と少し違うのならば、少し軌道修正すればいいだけの話です。

一歩踏み出すことで側座核が刺激されて、ドーパミンが出ますし、
自分の肌感覚といったフィードバックも得られるので今後の決断などをしやすくなります。

※側座核が刺激されるとドーパミンが出ます。このドーパミンは意欲を掻き立てたり、楽しいと感じるものなので行動力につながります。

最初は躊躇すると思いますが、意外にもダメージは小さいです。
ただ実際にやってみないとわからない事だと思いますので、これは是非ご自身で試していただきたいです！

# まとめ
###
今回は数あるメソッドの内のほんの一部をご紹介しましたが、
他にもさまざまなメソッドが本中で紹介されています。
>新たに習慣づけたいことは、すでにに定着している習慣にくっつける
結果に振り回れるそうな時は、「打率」で考える

など・・・

気になった方はぜひこの本を読んでみてください。

何か自分に合うメソッドがあってそれを取り入れる事ができれば、
自分軸を構築して、なんでもかんでもイエスマンで気を使いまくって
疲弊していく状況から脱する事ができるかもしれません！


拙文最後までお読みいただきありがとうございました！
###
https://www.amazon.co.jp/s?k=%E3%81%99%E3%81%90%E3%81%AB%E3%82%84%E3%82%8B%E4%BA%BA%E3%81%AB%E3%81%AA%E3%82%8B37%E3%81%AE%E3%82%B3%E3%83%84&adgrpid=128688935229&hvadid=651301387159&hvdev=c&hvlocphy=1009250&hvnetw=g&hvqmt=e&hvrand=9029772339746080895&hvtargid=kwd-1637970755268&hydadcr=13870_13515197&jp-ad-ap=0&tag=googhydr-22&ref=pd_sl_6q0uypp8vf_e
【Rails】ページネーションkaminari導入方法

# ページネーションとは

投稿一覧などにすべて投稿されてたものが表示されると、読み込みに時間がかかってしまうため、
ページネーション機能を使って、1つのページに表示される数を制限し、重くならないようにしていこうと思います！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111780/47d5aea7-cecf-bbe7-6174-95866eaf579c.png)
こんな感じのものを作る。

## メリット
・読み込みが速くなる！


# kaminariをインストールする
早速使えるように設定していきましょう。
ページネーションと使うには「kaminari」とうgemファイルを使っていきます。


```php:Gemfile
:
:
gem 'kaminari','~> 1.2.1'     #最後尾に記述
```
bundle installインストールしていきます。

```php
$ bundle install   #大事です
```

kaminariの設定ファイルを作成します。
```php
$ rails g kaminari:config
```
kaminariがページャで利用するテンプレートを作成します。
```php
 $ rails g kaminari:views default
```
以上で使えるように設定完了です。

## 使い方

使い方についてです。
## まずコントローラー
```php
def index
    @books = Book.all
  end
````
下記のように変更
```php
def index
    @books = Book.page(params[:page]).per(5) #5件だけ表示できます。
  end
```

## 次にビュー
`<%= paginate books %> `を記述する

```php
<% books.each do |book| %>

:
:

<% end %>
<%= paginate @books %>      #これを記述すると表示されます。
```

これでOK！
Ruby で正規表現の連結（連接、concatenation）

# 本題に入る前に

Ruby では [Regexp.union](https://docs.ruby-lang.org/ja/latest/method/Regexp/s/union.html) を使用すると正規表現のORによる結合を簡単に実現できます。
（ORによる結合には、「union」「和」「[選択](https://zenn.dev/mo_ri_regen/articles/regular-expression-3basic-operations)」「[選言](https://ja.wikipedia.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE#%E5%AE%9F%E7%94%A8%E7%9A%84%E8%AA%AC%E6%98%8E)」などの呼び方もあります。）

```ruby:union.rb
a = /[Ff]iz+/
b = /buz+/i
c = Regexp.union(a, b)

p 'fiz'.scan(c)      # => ["fiz"]
p 'BUZZZZ'.scan(c)   # => ["BUZZZZ"]
p 'FizzBuzz'.scan(c) # => ["Fizz", "Buzz"]
```

# 正規表現の連結 (concatenation)

では、あるパターンの後に別のパターンが続くような正規表現はどうでしょうか。
Ruby の正規表現には他の正規表現を埋め込むことができるそうなので、上記はこれにより実現できます。
（このような連結の操作は、「concatenation」「連接」などの呼び方もあります。）

```ruby:concat.rb
a = /[Ff]iz+/
b = /buz+/i
c = /#{a}#{b}/

p 'Fizz'.scan(c)     # => []
p 'buzzFizz'.scan(c) # => []
p 'FizzBUZZ'.scan(c) # => ["FizzBUZZ"]
```

参考：

https://qiita.com/jkr_2255/items/005464c54d5cbb24521e

> 二重引用符の文字列リテラルと同様に、正規表現中でも変数展開が可能ですが、与えたものは#to_sで展開されます。
> そして、Regexp#to_sでは、「返される文字列は他の正規表現に埋め込んでもその意味が保持されるようになっています」。

# 余談（AND演算について）

正規表現の基本の演算にはAND演算（正規言語の積集合を取る演算）は含まれておらず、簡単な表記でこれを実現することはできませんが、言語によっては肯定的先読みアサーションで実現できるようです。以下の例では `/[Ff]iz+/` と `/buz+/i` の両方に部分一致するかどうかを判定しています。

```ruby:intersection.rb
a = /[Ff]iz+/
b = /buz+/i
c = /\A(?=.*#{a})(?=.*#{b}).*/

p c =~ 'Fizz'                 # => nil (マッチせず)
p c =~ 'BUZZ'                 # => nil (マッチせず)
p c =~ 'fizz BUZZ'            # => 0 (マッチ)
p c =~ '1 2 Fizz 4 Buzz Fizz' # => 0 (マッチ)
```

https://qiita.com/n4o847/items/dbcd0b8af3781d221424

# まとめ

```ruby
# 正規表現の和
union = Regexp.union(a, b)
# または
union = /#{a}|#{b}/

# 正規表現の連接
concat = /#{a}#{b}/

# 正規表現の閉包（0回以上の繰り返し）
closure = /#{a}*/

# 正規表現の積（部分一致）
intersection = /\A(?=.*#{a})(?=.*#{b}).*/
# 正規表現の積（全体一致）
intersection = /(?=\A#{a}\z)(?=\A#{b}\z).*/

```

# おわりに

同じ内容の記事がなさそうだったので書きました。
mysqlclientがインストールできない！！！なんで！！！

## 環境
os : Ubuntu 22.04
python : 3.10

## 事象

↓コマンドで仮想環境を作成して、その中にmysqlclientをダウンロードしたら、、、

```terminal
$ python -m venv venv
```

こんなエラーが出てインストールできない！！！:rage:

```terminal
(venv)$ pip install mysqlclient

Collecting mysqlclient
  Using cached mysqlclient-2.1.1.tar.gz (88 kB)
  Preparing metadata (setup.py) ... error
  error: subprocess-exited-with-error
  
  × python setup.py egg_info did not run successfully.
  │ exit code: 1
  ╰─> [16 lines of output]
      /bin/sh: 1: mysql_config: not found
      /bin/sh: 1: mariadb_config: not found
      /bin/sh: 1: mysql_config: not found
      Traceback (most recent call last):
        File "<string>", line 2, in <module>
        File "<pip-setuptools-caller>", line 34, in <module>
        File "/tmp/pip-install-lq7x6sfi/mysqlclient_a658ec6c7a7f4cfdbaa28115071bf8c3/setup.py", line 15, in <module>
          metadata, options = get_config()
        File "/tmp/pip-install-lq7x6sfi/mysqlclient_a658ec6c7a7f4cfdbaa28115071bf8c3/setup_posix.py", line 70, in get_config
          libs = mysql_config("libs")
        File "/tmp/pip-install-lq7x6sfi/mysqlclient_a658ec6c7a7f4cfdbaa28115071bf8c3/setup_posix.py", line 31, in mysql_config
          raise OSError("{} not found".format(_mysql_config_path))
      OSError: mysql_config not found
      mysql_config --version
      mariadb_config --version
      mysql_config --libs
      [end of output]
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
error: metadata-generation-failed

× Encountered error while generating package metadata.
╰─> See above for output.

note: This is an issue with the package mentioned above, not pip.
hint: See above for details.
```

## 原因

必要なパッケージをインストールしてないだけだった。。。。:crying_cat_face:

怒ってごめん。。。:crying_cat_face:

```terminal
sudo apt-get install python3-dev default-libmysqlclient-dev build-essential
```

必要なパッケージをインストールしたらダウンロードできた:relaxed:

```terminal
(venv)$ pip install mysqlclient
Collecting mysqlclient
  Using cached mysqlclient-2.1.1.tar.gz (88 kB)
  Preparing metadata (setup.py) ... done
Using legacy 'setup.py install' for mysqlclient, since package 'wheel' is not installed.
Installing collected packages: mysqlclient
  Running setup.py install for mysqlclient ... done
Successfully installed mysqlclient-2.1.1
```

備忘録的なね:fist:
【要約】DB設計のアンチパターン

# はじめに

https://www.amazon.co.jp/%E9%81%94%E4%BA%BA%E3%81%AB%E5%AD%A6%E3%81%B6DB%E8%A8%AD%E8%A8%88-%E5%BE%B9%E5%BA%95%E6%8C%87%E5%8D%97%E6%9B%B8-%E5%88%9D%E7%B4%9A%E8%80%85%E3%81%A7%E7%B5%82%E3%82%8F%E3%82%8A%E3%81%9F%E3%81%8F%E3%81%AA%E3%81%84%E3%81%82%E3%81%AA%E3%81%9F%E3%81%B8-%E3%83%9F%E3%83%83%E3%82%AF/dp/4798124702

第7章；論理設計のバッドノウハウ
を要約しました

# 1. 非スカラ値

スカラ値・・・1つのセルには1つの値のみが含まれること
スカラ値でない場合、第一正規系を満たしていないことになる。

* 配列型
    * 安易に配列型を採用するのではなく、第一正規化を確保することを優先すべき
    * 配列型は柔軟なデータ型ではあるが、細心の注意が必要
* スカラ値の基準
    * 意味的に分割できる限りは、なるべく分割した方が良い（後で、分割は大変だが結合は楽なため）
    * 例）名前や、メールアドレスなど分割して保持
        * 高橋健二 ・・・ 「高橋」「健二」
        * `test@gmail.com`・・・「test」「gmail.com」

# 2.単一参照テーブル

同じ構造のテーブル同士を1つのテーブルにまとめても良いのか？

![スクリーンショット 2023-03-26 22.41.01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536974/7539a6c2-9b19-7e4c-b64f-05fadf0307f2.jpeg)

1つのレコードがある時は、会社名、あるときは、都道府県を著しています。

利点よりも欠点の方が多いのが実際の所。

## 利点

* マスタテーブルの数が減るので、ER図やスキーマがシンプルになる
* コード検索のSQLを共通化できる

## 欠点

* 必要とされる列長はコード体系によって異なるため、大きめの可変長文字列型を取る必要がある
* 種類が多いため、レコード数が増えるのでパフォーマンスに影響を与える
* 上の例で言うと、コードタイプを間違えて検索しても、エラーが出ずにバグに気づきにくい
* ER図としての可読性が下がる

# テーブル分割

1. 水平分割・・・レコード単位のテーブル分割
1. 垂直分割・・・列単位のテーブル分割

## 水平分割

SQLのパフォーマンス低下が起きる原因は、ストレージに対するI/Oの増大です。
そのためアクセス量を減らすことでパフォーマンスが改善さえます。

例えば、年度毎に水平にテーブルを分割することで、データ量を減らすことが出来る

**しかし**

欠点もあるので、分割はする事は原則禁止です。

1. 欠点: 分割する意味的な理由が無い
2. 拡張性に乏しい
    * 分割するなら、分割した全てのデータをまとめて検索しないことが前提になる
3. パフォーマンス改善をしたいなら代替え手段がある
    * パーティション機能を利用すれば良い。データ量を1/nに減らすことが出来る

### パーティションの種類

* レンジパーティション
    * キー項目の範囲で指定する
    * 例）日付毎に分ける
* リストパーティション
    * 任意の値リストを指定することで分割する
    * 例）都道府県ごと
* ハッシュパーティション
    * ハッシュ関数を利用することで分割が可能
    * 不連続なデータを均一に分割する際に使用する

## 垂直分割

集約で代替えが可能

## 集約

1. 列の絞り込み
1. サマリテーブル

### 列の絞り込み

* **データマート**
    オリジナルのテーブルから、分割するのではなく
    参照した列だけで構成した、小規模なテーブルを作成する。
    DWHなどでよく使われる手法

### サマリテーブル

事前に必要な情報だけ集約したテーブルを作成しておく。
例）全社員の平均年齢だけをもったテーブル

# 不適切なキー

1. 主キー、外部キーなどデータベース機能で設定されるもの
1. テーブルの結合条件で使用される列

この2つのキーには、可変長文字列を使ってはいけない。
なぜなら、
* キーは不変性であること
    * コロコロと変わる値をキーにはしない
* 固定長との混合
    * キーには固定長が望ましい

# 同じ役割のテーブルが2つ存在する

なぜ、このようなことが起こるのか？

それは、元々別システムで扱っていたが、システム統合によって同じドメインを扱うようになった場合です。

### どのような悪影響があるか？

例えば、同じデータ構造の2つのテーブルで一部異なるデータが入っている場合。
全てのデータから情報を得るためにはテーブルを結合する必要があります。
そして、結合はコストが高い処理です