OmniAICreator/Qiita-1.07M huggingface dataset:
vimの基本について

## はじめに
本日は「vimtutor」をやってみたので、vimの基本操作を自分なりにまとめてみました。

Macを持っている方ならFinder→アプリケーション→ターミナル
の順でターミナルを開いてそこに「vimtutor」と入力するだけでできるのでオススメです！

~~25から30分と書いてありますが、初学者の私は1時間以上かかりました~~


## 基本操作

###### モード
vimにはモードが複数ある。

- ノーマルモード
起動した時のモード。移動やコピーなどができる。escで入れる。

- インサートモード
ノーマルモードからiで入れる。文字を追加したり編集したりできる。

- コマンドモード
:や/で入れる。終了したり、保存したりできる。

- ビジュアルモード
範囲選択してコピペや削除ができる。


##### カーソル移動



|  コマンド | 実行結果 | 
|:----------:|:------------:|
| h    |左へ移動| 
| j    |下へ移動|
| k    |上へ移動|
| l    |下へ移動|
| 0 | 行の先頭に移動|
|G | ファイルの最下行に移動する
数値+G|数値の行に移動
gg|先頭行に移動
%|(,),[,],{,}の上でタイプすると対になる文字へ移動



##### vimを終了するには

| コマンド | 実行結果 |
|:-------:|:-------:|
|:q! | 変更を破棄|
|:wq |変更を保存 |


::: note warn
:を忘れない！
:を押してコマンドモードにしないとqが押せないです。
:::


##### 削除

| コマンド | 実行結果 |
|:-------:|:-------:|
|x | カーソル位置の文字を削除|
|dw| カーソル位置から次の単語まで削除|
|de| カーソル位置から単語の末尾まで削除|
|d$| カーソル位置から行の末尾まで削除|
|dd| 行全体を削除|


::: note warn
dwをタイプしようとしてddをタイプしてしますと全部消えるので注意！
:::

##### 文字の挿入

| コマンド | 実行結果 |
|:-------:|:-------:|
|i | カーソル位置に追加|
|a | 行末に追加|

##### その他

| コマンド | 実行結果 |
|:-------:|:-------:|
|2w| モーションを繰り返す| 数字はくりかえす数値
|u | 前回の動作を取り消す|
|U | 行全体の動作を取り消す|
|CTRL-R| 取り消しの取り消し|
|CTRL-G| ファイルでの位置とファイルの詳細を表示する|
/+語句|語句を検索



## 終わりに
vimの習得には慣れが必要なので、とにかく使って覚えていきたいと思います。
またコマンドはまだまだたくさんあるので、使いたい動作があったらその都度調べて覚えていきます。
[Angular]テスト jasmineのspyOnについて

#### spyOnの概要

①spyOnは、特定オブジェクトのメソッドを「スパイ」つまり「監視」するために使用される。
　・メソッドがどのように呼び出されたか
　・何回呼び出されたか
　・どのような引数で呼び出されたか
　など動作を監視することを指す。
②and.●●()などspyOnをメソッドと組み合わせて使用することで、
 スパイしたメソッドの振る舞いや返り値を含めた制御(ダミー)等ができます。


#### spyOn(オブジェクト,method).and.●●()の●●一覧

| method                  | describe                                                        |
| ------                  | --------                                                        |
| callThrough()           | スパイされたメソッドが呼ばれると、実際の実装を呼びます。　　　　　　　　 |
| returnValue(value)      | スパイされたメソッドが呼ばれると、指定した値が返される。　　　　　　　　 |
| returnValues(...values) | スパイされたメソッドが呼ばれると、指定した値のリストから次の値が返される |
| throwError(value)　　　 | スパイされたメソッドが呼ばれると、エラーがスローされる。 |
| callFake(fn)            | スパイされたメソッドが呼ばれると、提供した関数が代わりに実行される。 |
| stub()                  | スパイされたメソッドが呼ばれても、何もしない。 |
toHaveAttributeで要素の属性をチェックする

フロントエンドのテストにおいて要素の属性をチェックする必要があり、`jest-dom`の`toHaveAttribute`について調べたので簡単に記録しておきます。

## jest-domとは？

jest-domは、jestのカスタムマッチャー（アサーションメソッド）を提供するライブラリです。DOM要素に対するテストをより宣言的に、読みやすく、そして保守しやすくできるようです。

https://github.com/testing-library/jest-dom

## toHaveAttributeとは？

指定したDOM要素が特定の属性と値を持っているかどうかを確認できるメソッドです。

https://github.com/testing-library/jest-dom#tohaveattribute

### 実装例

同じテキストを持つが、異なるページに遷移するケースです。

```HTML
<a href="https://example1.com">詳しくはこちら</a>
<a href="https://example2.com">詳しくはこちら</a>
<a href="https://example3.com">詳しくはこちら</a>
```

```javascript
const links = await findAllByText("詳しくはこちら");

expect(links[0]).toHaveAttribute("href", "https://example1.com");
```

これによって、指定したhref属性に正しいURLが値として渡されているかを確認することができます。

### エラーメッセージの例

ケースによってエラーメッセージがどのように変わるか気になったので試してみました。

- その要素自体がundefinedだった場合

``` javascript
expect(undefined).toHaveAttribute("href", "https://example1.com")

expect(received).toHaveAttribute()

received value must be an HTMLElement or an SVGElement.
Received has value: undefined
```

- その要素が指定した属性を持たない場合

``` javascript
expect(element).toHaveAttribute("type", "submit") // element.getAttribute("type") === "submit"

Expected the element to have attribute:
  type="submit"
Received:
  null
```

- その要素が指定した値を持たない場合

``` javascript
expect(element).toHaveAttribute("href", "https://example.com") // element.getAttribute("href") === "https://example.com"

Expected the element to have attribute:
  href="https://example.com"
Received:
  href="https://example1.com"
```
目次

# Bedrock x Claude3

https://qiita.com/cyberBOSE/items/0e41fb7bcee6b7965d09

https://qiita.com/cyberBOSE/items/89ff1e91f99eb79f83bc

https://qiita.com/cyberBOSE/items/b202a43498b678414e3a

# Amazon Bedrock APIで始めるLLM超入門

https://qiita.com/cyberBOSE/items/0c7aab6d67c9112466e2

https://qiita.com/cyberBOSE/items/4523b46882332d033554?1

https://qiita.com/cyberBOSE/items/a42dfdd3f3103cf76245?1

https://qiita.com/cyberBOSE/items/a331ed830ed1859a198d?1

https://qiita.com/cyberBOSE/items/5cdec3580eb22b567d39?1

https://qiita.com/cyberBOSE/items/836dca81c090b1194f55

https://qiita.com/cyberBOSE/items/f6ccdb5d0e02cb5684a7

https://qiita.com/cyberBOSE/items/e0546a78c99e945988a0

https://qiita.com/cyberBOSE/items/fd65de9f857d36180fa5

# Titan Embeddingsでベクトル入門

https://qiita.com/cyberBOSE/items/fb96dcfcae78d5d788e9

https://qiita.com/cyberBOSE/items/1977a87a67857db7e6fd?1

https://qiita.com/cyberBOSE/items/aaf64c73f4da7e4cdb43

https://qiita.com/cyberBOSE/items/1d48b64110b46199c7d8

https://qiita.com/cyberBOSE/items/3660e36eccbe0e354c27

https://qiita.com/cyberBOSE/items/35fd2aed5a42b963ccb6

# Knowledge base for Amazon Bedrock, Agents for Amazon Bedrock

https://qiita.com/cyberBOSE/items/73cfc485bd7ddee8613a

https://qiita.com/cyberBOSE/items/b59b6763f24dded7743c

https://qiita.com/cyberBOSE/items/cc0a7434b4b7b27ce6de

https://qiita.com/cyberBOSE/items/e8c2d0207d03b6934a1c

https://qiita.com/cyberBOSE/items/5a0a32a34561aedc0e9e

https://qiita.com/cyberBOSE/items/14cf7024ea42ec1fb4be

https://qiita.com/cyberBOSE/items/4a09d4593b44bb5ac49f

https://qiita.com/cyberBOSE/items/86a39cb933f1df162e07

https://qiita.com/cyberBOSE/items/4a12e49e49790662468c

https://qiita.com/cyberBOSE/items/538e79ef1210929ba73a

# LINEからのBedrock呼び出し

https://qiita.com/cyberBOSE/items/3eb6945cd40d415ae71c

https://qiita.com/cyberBOSE/items/4a09d4593b44bb5ac49f

https://qiita.com/cyberBOSE/items/86a39cb933f1df162e07

# 他

https://qiita.com/cyberBOSE/items/9286fac198c248c721b9

https://qiita.com/cyberBOSE/items/5efac74f1b4fa77b2e09

https://qiita.com/cyberBOSE/items/d84ecc7d4ee1b5f62d89

https://qiita.com/cyberBOSE/items/8681183c38e970ac6869

https://qiita.com/cyberBOSE/items/63bc13710c9ae58d95f9

https://qiita.com/cyberBOSE/items/843208f919e95791b725
iphone内の写真をリサイズ（バッチ処理,グーグルフォトに反映）

iphoneで写真をたくさん撮ると、iphone本体のメモリとgoogleフォトの容量をどんどん使ってしまいます。（PC等のメイン環境に高画質画像を保存したら）リサイズで半分くらいのサイズにしてしまいましょう。

tips
・iphoneの通常の写真をgoogleフォトにアップロードすると、拡張子は**JPG**になる。
・iphoneのデフォルトアプリ「ショートカット」を使ってリサイズした画像の拡張子は**jpeg**になる。
・googleフォトではjpgとjpegは分けて検索出来る。

・iphoneの中では、jpgとjpegは区別されていないように見える。
## 処理フロー
4032x3024サイズで撮影した写真を半分のサイズ(2016x1512)に変換します。縦画像と横画像それぞれ判別して処理します。

iphoneのデフォルトアプリ「ショートカット」はバッチ処理など多彩な処理が可能。以下の流れで処理する。
１．iphone内の写真フォルダから、拡張子（**JPEG**）、日付が指定範囲、横幅が2016ピクセルより大きいものを抽出。
２．抽出された写真から処理対象を選択。選択した写真を1枚ずつループ。
３．選択した画像をJPEGに変換（このとき、圧縮される）
４．分岐処理で幅が高さより大きいときは、
４－１．圧縮した画像を幅2016、高さ自動にリサイズ。
４－２．リサイズした画像を保存。
５．分岐処理で横長でない画像の時は、
５－１．圧縮した画像を幅1512、高さ自動にリサイズ。
５－２．リサイズした画像を保存。
６．分岐処理（IF)終了。
７．ループ処理終了。
８．選択した元画像を削除。

## プログラムの記述
コード記述をブロック言語で行う必要があり、ブロックを探したり、変数を指定する作業がとにかく面倒。
以下、出来上がりイメージ。

![temp2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520250/d617da57-6f68-3b77-6991-367bcef5de8c.jpeg)


## 試運転
先ずは、最初に全て選択をオフにして、２，３枚の写真でテストする。
画像削除時は問い合わせがあるので、削除しないことも可能。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520250/4fe471a1-a9e8-a8f6-721e-9ff3f03cb863.png)


上手く行ったら、ショートカットアプリの権限を大きくしてやる。

設定から、ショートカットを選んで
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520250/a8d5c78d-56cd-d431-dece-541fc3362ed4.png)
多量のデータを削除することを許可、をオンにする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520250/a603de7a-afee-6b8c-07f1-0844ecdcb99a.png)

自動ロックがかかると処理が中断するので、「画面表示と明るさ」から自動ロックを5分or解除にしておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520250/7fb5bf2d-d98d-bf75-006b-34aa30c18ba7.png)


## 実運用
１．必要に応じ元画像をバックアップ
２．この記事で作成したバッチを実行
３．iphoneのgoogleフォトを起動（クラウドにリサイズした画像を自動的にアップロード）
４．googleフォトで同じ画像が2枚あることを確認し、情報で1まいは拡張子がJPG、もう一枚はjpegであることを確認
５．googleフォトの検索窓でJPGを選択して削除

## 補足
・ラインアプリで撮った写真は、撮影日時や撮影場所の記録が限定的なので、リサイズ後の画像はリサイズ処理日の日付になってしまう。
・HEIC形式(iphoneデフォルト）で写真を撮っている人は、抽出の段階でJPEGの代わりに、HEICを指定する。
・動画の縮小は別記事を参照 https://qiita.com/katakaku/items/55c6167ab0ab9afb786b
ショートカットで作成したスクリプトをここで共有する方法が分からない。
Next.jsのSSG

# はじめに
Next.jsをSSGとfetch APIにおけるSSGの動きについて？？？となったので覚書です

# SSGとは
SSG (Static Site Generation)とはビルド時にサーバー側で、APIからのデータ取得とHTMLの構築を終わらせておき、ユーザーからリクエストされた際にこの事前につくっておいたHTMLを渡すアーキテクチャです

# 疑問点
Next.js13においてFetch APIをSSGを用いて使用すると
```tsx
const res = await fetch(`${API_URL}`, { cache: 'no-store' });
```
の形でリクエストを送ります。
しかし、SSGはビルド時に値が確定されているはずなのにサーバー(DBなど)の変化に応じて表示される内容が異なってきます

# 理由
Fetch APIに関するSSGは、ビルド時ではなく初回レンダリング時またはページリロード時にデータの取得が行われるためです

## じゃあSSRはなんなんだよ！
ここでSSRとSSGの違いはなんなのかの疑問が湧くと思います
一言で言うと、**初回レンダリング〜ページリロードするまでの間にDBに変更があった場合にその変更がサイト上に反映されるかどうかです**
### SSRの場合
SSRは初回レンダリング〜ページリロードするまでの間はデータをキャッシュとして保持しているSSGとは異なり毎回毎回データ更新がないか確認しに行っています
そのため例えば誰かがデータを更新した時、その変更をすぐに確認することができるためUXが向上する場合があります(一方で無駄なフェッチも多くなるためパフォーマンスが悪くなることもあります)

```tsx
const res = await fetch(`${API_URL}`, { cache: 'no-cache' });
```




# 参考資料
https://zenn.dev/rinda_1994/articles/e6d8e3150b312d#ssg
Windows PowerShell での AWS CLI 接続先アカウント確認

# はじめに
* 客も Windows 多いんだけど、Windows で AWS CLI 使用時に、アカウント間違えてないか確認
# 手順
## プロファイル指定
```
${profile} = {プロファイルを指定}
```
## 接続先アカウントの確認
```
aws sts get-caller-identity `
    --profile ${profile} `
    --query "Account" `
    --output text
```
テストの技法と評価

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/0289892d-c101-70bf-6483-73dadb794472.png)
　テスト技法には、ブラックボックステスト、ホワイトボックステストがあります。ブラックボックステストは、入力値と出力値の対応関係が正しいかどうかを検証するテスト技法です。ホワイトボックステストは、プログラムの流れを検証し、無駄な処理や矛盾する処理を発見するテスト技法です。命令網羅、判定条件網羅、条件網羅といった技法があります。

１：ブラックボックステスト
　同値分割：入力データを同じ出力結果が得られるグループ（同値クラス）に分割し、各グループから代表値を選んでテストデータとする手法です。正常に処理される入力値のグループを有効同値クラス、エラーとなる入力値のグループを無効同値クラスと言います。

　限界値分析：同値クラスの境界値をテストデータとする手法です。プログラムでは判定条件を
　weight>100
と書くべきなのに
　weight≧１００
と書くという間違いが多く発生します。限界値分析の目的は、このような誤りを発見することです。

２：ホワイトボックステスト
　命令網羅：要件：プログラム中のすべての命令を、少なくとも１回は実行するようにテストデータを作る。

　判定条件網羅（分岐網羅）：要件：プログラムの判定条件で、真と偽を少なくとも１回は実行するようにテストデータを作る。

　条件網羅：要件：判定中の各条件で、真と偽を少なくとも１回は実行するようにテストデータを作る。

　判定条件/条件網羅：要件：判定条件網羅と条件網羅の両方を満たすようにテストデータを作る。

　複数条件網羅：要件：各条件の真偽のすべての組み合わせでテストデータを作る。

３：信頼度成長曲線
　発見されたエラーの累積数が、時間の経過とともにどのように変化するのかを表すグラフです。このグラム（曲線）は、数学の世界では、オジスティック曲線やゴンベルツ曲線と呼ばれています。
　エラーははじめのうちはなかなか見つかりませんが、見つかりはじめるとあれもこれもといったように見つかります。そして、ある程度の時間が経つと、ほぼ出尽くして終わりになります。
　この曲線とともに、実際に発見したエラーの累積数をプロットします。曲線から大きく逸れている場合には、問題があると考え、適切な処理を講じる必要があります。
【Swift】CIFilterで画像の画質を落とす

# はじめに
CIFilter5日目です

# サンプルアプリ
![Simulator Screen Recording - iPhone 15 - 2023-10-16 at 21.36.31.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/98a78dd2-94e8-40f8-3a02-0ce2a8c1f06a.gif)


# 実装
```swift
import SwiftUI

struct ContentView: View {
    private let image = UIImage(named: "sample")!

    @State private var uiImage: UIImage?

    var body: some View {
        ScrollView {
            VStack {
                if let uiImage {
                    Image(uiImage: uiImage)
                        .resizable()
                        .scaledToFit()
                } else {
                    Image(uiImage: image)
                        .resizable()
                        .scaledToFit()
                }

                HStack(spacing: 15) {
                    Button {
                        applyLowResolutionFilter()
                    } label: {
                        Text("適用")
                    }
                    
                    Button {
                        uiImage = nil
                    } label: {
                        Text("リセット")
                    }
                }
            }
            .padding(.horizontal, 20)
        }
    }

    func applyLowResolutionFilter() {
        let context = CIContext()
        let inputImage = CIImage(image: image)!

        guard let overlayFilter = CIFilter(name: "CILanczosScaleTransform", parameters: [
            kCIInputImageKey: inputImage,
            kCIInputScaleKey: 0.1
        ]) else { return }
        guard let outputImage = overlayFilter.outputImage else { return }
        guard let cgImage = context.createCGImage(outputImage, from: outputImage.extent) else { return }
        self.uiImage = UIImage(cgImage: cgImage)
    }
}
```

# おわり
画像のサイズを小さくして元の大きさに引き伸ばすことで画質が悪くなるという仕組みです
自動車エレクトロニクス市場： 電子制御ユニット（ECU）数の増加とアンチブレーキシステムの採用増加に関するリサーチネスターによる分析 2023-2033

リサーチ・ネスターは次のタイトルのレポートを発表した「カーエレクトロニクス市場 世界の需要分析と機会展望2033"この調査レポートは、自動車用エレクトロニクスの世界市場について、製品タイプ別、流通チャネル別、用途別、地域別に分類した詳細な概要を掲載しています。
さらに、詳細な分析のために、市場の成長に関連する現在と将来の市場動向に関する詳細な議論とともに、業界の成長指標、阻害要因、需給リスクを網羅しています。
自動車用エレクトロニクスの世界市場は、予測期間中（2023～2033年）に年平均成長率～8％で成長すると予測されている。市場は用途別に乗用車と商用車に区分される。これらのセグメントのうち、乗用車セグメントは自動車販売の増加により、予測期間中に最大の市場シェアを獲得すると予測される。また、先進的な機能を備えた高級車への需要が民衆の間で高まっていることも、今後数年間の同セグメントの成長を後押しすると予想される。
自動車用エレクトロニクスの世界市場は、世界中で電子システムを搭載した自動車が増加していることを背景に、2033年末までには緩やかな収益を上げると推定されている。自動緊急ブレーキやエアバッグなど、自動車用エレクトロニクスが提供するさまざまな機能も、今後数年間でこれらのツールの売上を押し上げると予測されている。さらに、交通事故の増加や先進運転支援システムの普及拡大も、予測期間中の市場成長を促進すると予測されている。
![Automotive-Electronics-Market-overview.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491677/7a7168fa-a24e-004d-0a35-aef49c9aea3a.jpeg)

詳細レポートへのアクセスはこちら：
https://www.researchnester.jp/reports/automotive-electronics-market/4472

地域的には、世界の自動車用エレクトロニクス市場は、北米、欧州、アジア太平洋地域、中南米、中東・アフリカ地域の5つの主要地域に区分される。このうち、アジア太平洋地域の市場は、自動車販売の増加により、予測期間中に最大の市場シェアを獲得すると推定される。 これとは別に、欧州市場は今後数年間で大きな成長を記録すると予測されている。
この調査はグローバルな性質を持ち、以下の国の市場に関する詳細な分析をカバーしている North America (U.S., Canada), Europe (U.K., Germany, France, Italy, Spain, Hungary, Belgium, Netherlands & Luxembourg, NORDIC [Finland, Sweden, Norway, Denmark], Poland, Turkey, Russia, Rest of Europe), Latin America (Brazil, Mexico, Argentina, Rest of Latin America), Asia-Pacific (China, India, Japan, South Korea, Indonesia, Singapore, Malaysia, Australia, New Zealand, Rest of Asia-Pacific), Middle East and Africa (Israel, GCC [Saudi Arabia, UAE, Bahrain, Kuwait, Qatar, Oman], North Africa, South Africa, Rest of Middle East and Africa). さらに、市場規模、前年比成長率および機会分析、市場プレイヤーの競争調査、投資機会、将来の展望に対する需要などを含む分析も、調査報告書の中で取り上げられ、表示されている。
電子制御ユニット（ECU）使用の増加が市場成長を牽引
データによると、2020年の自動車には、機能を制御するためのECUが100個以上搭載される可能性がある
ECUの採用は、パワーステアリング制御やエンジンのような基本的なものから、パワーウィンドウやシートのような快適性、キーレスエントリーやドアロックのようなセキュリティやアクセスに至るまで、制御する機能の数が急増しているため、今後数年間で市場の成長を加速させると予想される。さらに、技術の進歩や研究開発の増加も、予測期間中の自動車用エレクトロニクスの世界市場の成長を促進すると予想される。
しかし、電子制御ユニットの増加に伴うコスト高騰の可能性や、発展途上国における電子システムの普及率の低さが、予測期間中の自動車用電子機器の世界市場成長の主な阻害要因になると予想される。
本レポートはまた、自動車用エレクトロニクスの世界市場における主要企業の既存の競争シナリオを提供します Robert Bosch GmbH, Continental AG, Denso Corporation, Visteon Corporation, Infineon Technologies AG, Hella GmbH & Co. KGaA, Hitachi, Ltd., Advanced Micro Devices, Inc., Renesas Electronics Corporation, Valeo. The profiling enfolds key information of the companies which encompasses business overview, products and services, key financials and recent news and developments. 全体として、本レポートは世界の自動車用エレクトロニクス市場の詳細な概観を描いており、業界コンサルタント、機器メーカー、拡大機会を探している既存プレイヤー、可能性を探している新規プレイヤー、その他の利害関係者が、現在進行中および今後予想されるトレンドに従って市場中心の戦略を調整するのに役立ちます。
レポートサンプル@を請求する
https://www.researchnester.jp/sample-request-4472

について Research Nester
Research Nesterは戦略的市場調査とコンサルティングのリーディング・サービス・プロバイダーです。業界、コングロマリット、エグゼクティブが将来のマーケティング戦略、事業拡大、投資などのために賢明な決断を下せるよう、偏りのない比類のない市場洞察と業界分析を提供することを目指しています。私たちは、戦略的思考を通じて適切なタイミングで適切なガイダンスを得ることができれば、あらゆるビジネスが新たな地平へと拡大できると信じています。私たちの既成概念にとらわれない思考は、お客様が将来の不確実性を回避するために賢明な決断を下すのに役立ちます。
【お問い合わせ先】
ナオミ コスギ
Eメール: info@researchnester.jp
米国の電話番号: +81 505 050 8480
達人に学ぶDB設計 徹底指南書

今回は、表題となる本書 「達人に学ぶDB設計 徹底指南書」についてまとめる

それぞれの章ごとにまとめる。

[3章 論理設計と正規化 ~なぜテーブルは分割する必要があるのか?~](https://qiita.com/takechanel/items/e1a245ab7716c7c1ac48)

↓ここは後ほど公開↓
[第4章　ER図 ～複数のテーブルの関係を表現する]・・・については省略する！

[5章 論理設計とパフォーマンス ～正規化の欠点と非正規化](https://qiita.com/takechanel/items/e6474c2ce028d7d8d5f1)
[6章 データベースとパフォーマンス](https://qiita.com/takechanel/items/a4b0b678afc2f8e1fe92)
[7章 論理設計のバッドノウハウ]()
[第8章　論理設計のグレーノウハウ]()
[第9章　一歩進んだ論理設計 ～SQLで木構造を扱う]()
OpenAIのGPTシリーズとBedrockのClaudeをコスト比較してみた

# LLMのコスト表示、分かりづらくないですか？

生成AIのモデル利用料金って、1kトークンあたりの単価かつドル表記なのでパッと見分かりづらくないでしょうか？

そこで、エンタープライズな環境で生成AIアプリケーションを開発する際に最も利用されると思われるAzure OpenAI ServiceのGPTシリーズとAmazon BedrockのClaude 2のコストを、イメージしやすい具体的なシナリオに基づいて月額コスト比較してみました。


# 比較するモデル

各社、今のところ利用リージョンによる価格差はないようです。

クラウド | モデル | トークン上限 | 入力コスト | 出力コスト
-|-|-|-|-
Microsoft Azure | GPT-3.5 Turbo | 4k | $0.0015/k | $0.002/k
Microsoft Azure | GPT-3.5 Turbo | 16k | $0.003/k | $0.004/k
Microsoft Azure | GPT-4 | 8k | $0.03/k | $0.06/k
Microsoft Azure | GPT-4 | 32k | $0.06/k | $0.12/k
AWS | Claude 2 | 100k | $0.01102/k | $0.03268/k

※最新の価格設定は各社公式ページをご覧ください。

https://azure.microsoft.com/ja-jp/pricing/details/cognitive-services/openai-service/

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


# 想定シナリオ

AWSブログの以下記事ページを全コピーし「これを要約して」という一文を添えたプロンプトをLLMに投げて要約させる。

https://aws.amazon.com/jp/blogs/news/amazon-bedrock-is-now-generally-available-build-and-scale-generative-ai-applications-with-foundation-models/

- 入力トークン数：8,507
- 出力トークン数：808（実際にGPT-3.5 Turboに上記を要約させた結果）


### 利用量の見積もり

上記の文書要約（入力＋出力）を

- 1人あたり1日に3回行う
- 利用者は10人
- 月の営業日を20日とする

場合の月額コストを試算しました。


# コスト試算結果

最近円安が激しいので、実態に近い `1ドル ＝ 150円` で計算しています。

### 各社、トークン上限最小モデル同士の比較

クラウド | モデル | トークン上限 | 月額コスト
-|-|-|-
Microsoft Azure | GPT-3.5 Turbo | 4k | 1,098円/月
Microsoft Azure | GPT-4 | 8k | 27,000円/月
AWS | Claude 2 | 100k | 10,876円/月

GPT-3.5 Turboのコスパの高さが分かりますね！
これがGPT-4になると一気に価格が跳ね上がります。Claude 2はその1/3近い価格に収まっています。

しかし上記はGPTシリーズにちょっと有利な比較になっています。
今回、文書要約のサンプルに利用したテキストは8,507トークンありましたので、**GPT-3.5/4は上記のモデルだとキャパ越えになりエラー**となってしまいます。

ということで、各社のトークン上限最大モデル同士で改めて比較したものが以下です。


### 各社、トークン上限最大モデル同士の比較

クラウド | モデル | トークン上限 | 月額コスト
-|-|-|-
Microsoft Azure | GPT-3.5 Turbo | 16k | 2,520円/月
Microsoft Azure | GPT-4 | 32k | 54,000円/月
AWS | Claude 2 | 100k | 10,876円/月

※ちなみにAWSのBedrockにはプロビジョンドスループットという機能があり、大規模なワークロード向けに時間単位で性能確保を事前コミットできる契約となっています。こちらは最小ユニットでも1時間あたり9,000円以上かかる破格の設定となっていたため、今回の比較からは除外しています。


# ちなみに実際の性能は…

Rakudaというベンチマークによると、日本語性能の比較では `GPT-3.5 < Claude 2 < GPT-4` というランキングになっているようです。実際のユースケースによっても優劣は変わりますので、参考程度にどうぞ。

https://yuzuai.jp/benchmark

:::note info
価格計算には注意を払っておりますが、もし誤りやお気づきの点があれば遠慮なくコメント等いただけますと幸いです。
:::
SQL tips 3: 連番での重複削除

特定の観察単位における重複を取り除いた結果を取り出すクエリのご紹介です。
例えば、個人ごとに年に一度だけ発生するイベントのデータを作りたいが、データ上にはエラーや特殊なケースで年に二度以上、発生しうる場合を対処したいときです。

■処理イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557030/26869552-2214-3eae-ccf1-3a182615e948.png)

■クエリ
```sql
WITH event_prep AS(
    SELECT 
        ID
        , date
        , X1
        , ROW_NUMBER() OVER(PARTITION BY ID ORDER BY date ASC) AS num
    FROM event)

SELECT ID, date, X1
    FROM event_prep
    WHERE num = 1
```

やっていること
・ROW_NUMBER関数で個人ごとに連番（num）を作成する。
    ・その際、ORDER BY で date が古いものが一番上に来るようにしている（これは場面によって、何をどのように並び変えるかが変わります。）
・WITH句で作ったものから、連番が 1の値を取るデータを取り出す。

POSデータを使って個人ごとに最も大きい購買を集めたデータとかも同様の方法で作れると思います。
【初心者向け】Next.jsでpagesがなくなって絶望しているあなたへ

## 結論: pagesは使えるので安心してください
Next.jsをこれから勉強し始めたいという方への、初歩の初歩の説明です。これはおそらく市販のNext.jsの参考書には載っていません。

あなたは市販のNext.jsの入門書を読んでいるとします。Next.jsをまずインストールすることから始めますね。その際に、以下のコマンドを打ちましょうと書いてあると思います。

```bash
npx create-next-app@latest
```
これを実行すると、なんかわからんけど色々と聞かれますよね。eslintは有効にしますか？とか、TypeScriptは有効にしますか？とか聞かれます。「App Router？まあなんかrecommendedってなってるからYesにしとくか」といって、そのまま進めます。

最初のステップとして、「pagesの中にあるindex.jsxを編集しましょう」と書いてあるとします。するとどうでしょう。あなたはとてつもない壁にぶつかります。

**あれ、pagesディレクトリがおらん**

なんということでしょう。pagesディレクトリがないではないですか。あなたはどうすればわからずググると、このような説明を解説してある記事が見つかります。

**「Next.js 13からはApp Routerになりました」**

あなたはApp Routerが何がなんだかわからず勘違いして、pagesが使えなくなったと勘違いをするかもしれません。その瞬間、あなたは自分のもってる参考書が役に立たなくなったと勘違いして、破り捨てそうになるかもしれません。

でもちょっと待ってください。

## pagesディレクトリを使う方法
安心してください。あなたのその参考書は全然まだ役に立ちます。Next.jsは確かに13からApp Routerが追加されました。Server Componentなるものもあって、記法が今までと少し違います。
しかし、Next.jsは互換性を切っていません。今までのpagesも全然使えます。初心者の方はむしろNext.jsに慣れるためにもpagesディレクトリをぜひ使ったほうがいいです。そしてNext.jsに慣れてきたら、App Routerに挑戦してみてください。

まず、インストールするさいに、`Would you like to use App Router? (recommended)` と聞かれたときに、`No`を選択するとpagesディレクトリが作られます。
もし`Yes`を選択しても大丈夫です。

まず、pagesディレクトリを作ってしまいましょう。もし、srcディレクトリの中にappがあったら、それと同じ階層に作りましょう。
```shell
mkdir src/pages
mkdir src/styles  # cssファイルを置く
```
そして、appに入っている`page.tsx`を`pages`ディレクトリの中に移行させましょう。名前も`index.tsx`に変えましょう。global.cssもstylesの中に移行させましょう

```bash
mv src/app/page.tsx src/pages/index.tsx
mv src/app/global.css src/styles
```
また、pagesディレクトリには、_app.tsxというものがあるので、それもpages直下に作りましょう。

```_app.tsx
import type { AppProps } from "next/app";
import "../styles/globals.css";

export default function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}
```

最後に,appディレクトリを削除しましょう。layout.tsx,favicon.icoなど残っていますが、faviconは使いたければpublicに移動させましょう。layoutはApp Router用なので、pagesには必要ないので大丈夫です。

```bash
rm -rf src/app
```

これで完成です。`npm run dev`で起動させてみましょう。無事に立ち上がると思います。これでpagesが使えて、そのままあなたの参考書は十分に役に立ちます。参考書、入門サイトの通りにNext.jsに入門しましょう。

## 最後に
ファイル操作するのが面倒だったら、一旦プロジェクト作り直して、App Routerを使うか聞かれた時にNoを選択すれば簡単です。
仮説検証の仮説について説明してみた

# はじめに
アジャイルなプロダクト開発において、仮説検証をしながら前進していくという考え方があります。仮説検証をすることで早期にリスクを軽減・回避できたり、新たな学びを得て次の成長につなげられるというメリットがあります。
しかしプロダクト開発において、「仮説ってなんでしょうか」「どのような仮説を立てるといいのでしょうか」と思った経験がありましたので考えを書いていきたいと思います。
※おそらくいろんな解釈や考え方があります


# 思い込みと仮説の違い
思い込みと仮説をよく混同してしまいますが、それぞれ違ってそれぞれ重要です。

## 思い込み
Wikipediaにはこのように書かれていました。
> 思い込みとは、深く信じこむこと。また、固く心に決めること

XXという機能がある製品は売れる。たくさん働けば出世する。こういったものが思い込みになります。つまり**正しいかどうかはわからないけど信じていること**が思い込みと言えます。
この**思い込み**をそのままに開発を進めていくと、いざリリースした後に売れなかったとか使われない機能だったということになりかねません。


## 仮説
Wikipediaにはこのように書かれていました
> 仮説（かせつ、英: hypothesis）とは、真偽はともかくとして、何らかの現象や法則性を説明するのに役立つ命題のこと。仮説はその正否を実験的に検証しうるような、具体的に明確な内容を持つもの

書かれている通り、「検証しうる」ということが特徴です。また、仮説を検証する際は方法と判断指標も大切になってきます。どんな方法で検証をするか、どういう結果を持って正しかったと捉えるかは一概には言えませんが、上手に方法と判断指標を設定することがプロダクトマネージャーのスキルの一つかもしれません。

例を挙げてみます
- XXという機能が欲しいと答える人が多いだろう
    - 家電量販店の入り口で100人にアンケートをとり(方法)、50人以上がXXという機能が欲しいと答える（判断指標）
- 出世した人は残業時間が多かっただろう
    - 先輩や上司にヒヤリングし（方法）、残業が月30時間を常に超えていたと答える人が60%以上いる（判断指標）

## 思い込み→仮説
思い込みが正しいのかどうかを明らかにするために、仮説を検証していくというイメージがわかりやすいかもしれません。
プロダクト開発において、「顧客は存在する」「YYということに課題を感じている」「ZZという機能やソリューションに価値を感じる」といったような思い込みに対して仮説を立てて検証していくことが仮説検証の進め方ではないかと思います。

# 仮説検証の例
仮説検証をしたのかは分かりませんが、綾鷹のCMでやっていた「板前さん100人に聞きました。急須で入れた緑茶にもっとも近いのはどれ？」という調査がとても分かりやすいと感じましたので取り上げてみます。
※あくまでも想像です

- 思い込み（想像）：
    - 綾鷹は急須で入れた緑茶に近い
- 仮説（想像）：
    - 綾鷹を飲んだら多くの人が急須で入れた緑茶と感じる
- 検証方法
    - 板前さん100人に対し数種類の銘柄を隠した緑茶を試飲してもらい、アンケートを実施する
- 判断指標（想像）
    - 60%以上の人が綾鷹を選ぶ

CMでは実際に板前さん100人に対して調査を行い、見事62人の板前さんが綾鷹を選びました。仮説が立証され、「綾鷹は急須で入れた緑茶に近い」という思い込みは正しいと言える状態になったのではないかと思います。
また、検証方法のターゲットとして板前さんを選んだのも、違いがわかる人がそう答えたということで検証の確らしさや説得力があったのではないかと思いました。


# 最後に
この記事を書くにあたっての思い込みと仮説を。
思い込み：この仮説についての記事は誰かの役に立つだろう
仮説：仮説についての記事を書けば、いいねをたくさんもらえる
判断指標：100いいねを超える
※いいねがあまり付かなかった場合でも思い込みが否定されたというわけではなく、記事が微妙だっただけという可能性があります。
Flutter de アプリ開発〜リリース前にすること〜（iOS編）


先日初めてFlutterでアプリをリリースしてみました。
リリースしたアプリはこちら。

https://apps.apple.com/app/id6468472948

夫婦共働きで、夕飯の当番は僕なのですが、いつも献立に悩んでいました。
振り返ると、
「あのときのあれが食べたい」と言われることが多々あり、
過去の献立が再登場することがあるため、日々作成した料理を記録できるアプリを開発してみました。
アイコンは奥さんが描いてくれました。（本当にありがとう！！！！！！）

この記事では備忘録的に、意外と時間のかかるリリース前作業についてまとめたものです。
※2023年10月時点

## リリース前にしたこと
### スクリーン上のDEBUGの表示を消す
- アプリ申請時に必要なスクリーンショットにDEBUGの文字が残っているとリジェクトされるので消しておく。
~~~
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false, //これを追加
      title: 'XXXXXX',
      home: MyHomePage(),
    );
  }
}
~~~
### Bundle Identifierの編集（iOSの場合）
- TARGETS→General→IdentityからBundle Identifierを確認。
- com.exampleから始まっていれば、適切なものへ修正する。

### アプリ名の編集(iOSの場合）
- info.plistのCFBundleNameの<key></key>の中身を編集する
~~~
	<key>CFBundleDisplayName</key>
	<string>物欲の栞</string> //ここ
~~~

### 言語の日本語化
- デフォルトだとEnglishになっているためストアに公開したとき、言語が「EN」になっている。これを「JA」にするために以下の通り修正。
![スクリーンショット 2023-10-14 20.41.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548237/62939721-d434-0bcc-5029-ec3b0e8e4c49.png)

### アプリアイコンの設置
- flutter_launcher_iconsを使用する。１つの画像から複数サイズのアイコンセットを作成してくれる。512×512の画像を用意する。
~~~
dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^2.0.0
  flutter_launcher_icons: ^0.10.0

// androidとiOSで同じアイコンを使用する
flutter_icons:       
  android: true
  ios: true
  image_path: "assets/shiori_base_512_512.png"
  adaptive_icon_foreground: "assets/shiori_base_512_512.png"
  adaptive_icon_background: "#FFFFFF"
  remove_alpha_ios: true
~~~
- ターミナルで以下のコマンドを実行
~~~
flutter pub run flutter_launcher_icons:main
~~~

### App Store Connectへ登録
- ＋ボタンからアプリを登録
![スクリーンショット 2023-10-15 7.05.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548237/e99db2a4-f124-effd-2641-afa09dfe0e08.png)
![スクリーンショット 2023-10-15 7.06.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548237/7db75004-0b7c-adc1-12a1-3e0cf813b4db.png)

### 「一般」タブの情報を埋める
- アプリ情報
- 価格及び配信状況
- アプリのプライバシー
ここで、サポートページとプライバシーポリシーを明記したサイトが必要となるが、今回ははてなブログを掲載し審査通過。

### スクリーンショットを用意する
https://developer.apple.com/jp/help/app-store-connect/reference/screenshot-specifications/
- （必須）iPhone 6.5インチディスプレイ
- （必須）iPhone 5.5インチディスプレイ
- （必須）iPad Pro 12.9インチディスプレイ（第6世代、第2世代）
Simulatorを利用するなら、command + shift + 4→シミュレータ上でスペースキーを押してoptionを押しながら撮影すると影無しでそのままスクショが撮れるので便利。
上部に残るバーはトリミングで削除すればおｋ。
※端末のスクリーンショットが写っていて、要求されている画像サイズを満たせば中身については自由度が高い。
今回はkeynoteで作成。

### TestFlightへアップロード
製品版も、TestFlightを経由しないと製品版ビルドをアップロードできないようになっているみたい。

### テスト後
App Storeタブのビルドに、テストをパスしたビルドをアップロード。
あとは審査を待つのみ。

### 終わりに
業務でiOSやandroidのアプリをリリースしたことがありましたが、昔のことで意外と手間取ってしまいました。
今回はiOSについてまとめましたが、Android版もリリース済みなので近々公開できればと思います。

Flutter最高！
Androidアプリ開発前に知りたかったこと

# 概要
初の記事投稿
androidアプリ開発を始めたので備忘録も兼ねて

# きっかけ
androidアプリ開発を始めて「一回リリースしてみるか」というタイミングで知った仕様
できれば先に知っておきたかった

# 本題
ApplicationIDはデフォルト(`com.example.〇〇`)のままではリリースできない
<font color="red">exampleの部分を変えればリリース可能</font>

リリース直前に気づくと割とめんどくさいので先にしておきたいが、初めてandroidアプリ開発する人はとりあえずデフォルトのまま進める人も多いのでは:thinking:

# おまけ
初めてアプリをリリースしました
https://t.co/TM0EsZKOWi
爆速OpenVPNサーバー設定＆接続

## OpenVPN 2.6 の導入
https://community.openvpn.net/openvpn/wiki/OpenvpnSoftwareRepos
#### CentOS/AlmaLinuxとかその系統

インストラクションにある `yum` ではなく `dnf` を前提としたコマンドは以下の通り（`sudo dnf install yum-plugin-copr` は既に導入されてる可能性が高いです）

```
$ sudo dnf install sudo dnf install yum-plugin-copr
$ sudo dnf copr enable dsommers/openvpn-release-2.6
$ sudo dnf install openvpn
```

次にインストールスクリプトを　`curl` か `wget` か何か好きなコマンドでダウンロード、実行権を付与してからして実行

https://github.com/angristan/openvpn-install

```
$ wget https://raw.githubusercontent.com/angristan/openvpn-install/master/openvpn-install.sh
$ chmod 700 ./openvpn-install.sh
$ ./openvpn-install.sh
```

そのあとはプロンプトに従ってサーバー情報を入力して、ユーザーを追加したら自動的に `openvpn-server@.service` で登録されたサービスが立ち上がります

`openvpn-install.sh` でデフォルトのポートと通信プロトコルを選んだ場合（Enter連打）はUDPの1194番ポートを開放してサーバー側の設定は終了です

次にクライアントは、`openvpn-install.sh` で作成したユーザー名を `user` とした場合、コマンドを実行したディレクトリに設定ファイルが `user.ovpn` として作成されます

これを何とかして手元にあるパソコンにコピーします（FTPでGETでも、catで出力したものをテキストエディタにコピペ保存でも何でも構いません）

このファイルをVPN接続に使うソフトウェア（OpenVPN対応）に読み込ませて接続すれば、何も考えずに接続されます！

この作業、サーバー設定に慣れてる人だと3分かからないと思います（慣れてなくても30分あればたぶんできます）

ちなみに今回の目的は、機械学習用のGPUマシンをVPN接続させて仕事をさせるのが目的で、GPUマシンはLinux、クライアントはVisual Studioを使いたいのでWindowsでした

Windows環境だとvpnuxなんかが手っ取り早く使えます

https://www.vpnux.jp/
Salesforce上のアプリケーション「TeamSpirit」のカスタムオブジェクト（テーブル）へAPIでアクセスし情報を取得するには？

主に勤怠情報の入力・管理に使用しているTeamSpiritの情報を自社のアプリケーションで収集しレポートを生成するため現在、Salesforce API周りの設定を任されていますがこれが一筋縄でいきません。
※当初、アプリケーション担当から相談を持ちかけられたときは、APIへのアクセスに必要ないくつかの設定を行いセキュリティ周りのありがちなキー情報を発行し共有すれば済むくらいの意識でいました...

APIの仕様自体は無論、複雑ではないのですが設定すべき項目とヘルプが大風呂敷かつ説明ベタというか...
とにかく無駄に難解なのです。
せんせー、マイクロ流体デバイスってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/2c47de5a-d81a-78f9-53c1-4d31d8398c36.png)

キーンコーンカーンコーン...
授業が始まります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/be1492ca-910f-2708-d0fa-8fcfcf14af73.png)

せんせー、マイクロ流体デバイスってなに？

# マイクロ流体デバイスとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/da229491-9c49-fb7a-a542-417180e256a7.png)

## どういうこと？

この小さなデバイスは、特別な実験や新しい発見をするために使われるんだ。たとえば、医者が病気の原因を見つけるのを助けたり、新しい薬を作るのに役立ったりすることがあるよ。とっても小さいから、必要な液体の量も少なくてすむんだ。

## どうしてそれがすごいの？

これがすごいのは、とっても小さいから、普通の実験よりも速く、安全に、そして正確に色んなテストができることなんだ。また、少量の薬や液体だけでいろんな実験ができるから、コストを抑えられるのも大きなメリットなんだよ。

## だから、マイクロ流体デバイスってなに？

マイクロ流体デバイスは、液体を小さなチューブを通して正確に動かすことができる、とっても特別なツール。科学者たちが、新しい発見をするためや、病気の治療を助けるために使っているんだよ。

# まとめ

このように、マイクロ流体デバイスは、小さなチューブの中で液体をうまく使って、大切な実験をするためのすごいツールなんだ。これによって、科学者たちは新しい薬を開発したり、病気の調査をしたりして、みんなの生活をより良くするために役立てているんだよ！
せんせー、ダイナミックスペクトラムアクセスってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/2c47de5a-d81a-78f9-53c1-4d31d8398c36.png)

キーンコーンカーンコーン...
授業が始まります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/be1492ca-910f-2708-d0fa-8fcfcf14af73.png)

せんせー、ダイナミックスペクトラムアクセスってなに？

# ダイナミックスペクトラムアクセスとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/da229491-9c49-fb7a-a542-417180e256a7.png)

## ダイナミックスペクトラムアクセスって何？

みんな、ラジオやテレビを見たことがあるよね？これらの機器は、空中を飛んでいる見えない波（電波）をキャッチして、音や映像を出すんだ。この電波の中にはたくさんの「チャンネル」があって、それぞれが違う情報を送っているよ。ダイナミックスペクトラムアクセスは、このチャンネルをとても賢く使う方法なんだ。

## どういうこと？

普通、一つのチャンネルは一つの用途のために予約されているんだ。でも、ダイナミックスペクトラムアクセスは、使っていないチャンネルがあれば、それを他の用途で使えるようにする方法だよ。要するに、電波のチャンネルを無駄にしないように、上手に使う方法なんだ。

## どうしてそれがすごいの？

想像してみて。公園の遊具がいっぱいの場所を考えてみよう。もし一つの遊具が誰も使っていなかったら、他の子が遊ぶことができるよね。ダイナミックスペクトラムアクセスも同じような考え方。使っていない電波のチャンネルを他の人や機器が使えるようにすることで、もっとたくさんの情報を送ったり、受け取ったりできるんだ。

## だから、ダイナミックスペクトラムアクセスってなに？

ダイナミックスペクトラムアクセスは、電波のチャンネルを賢く使う方法。使っていないチャンネルを見つけて、それを他の用途で活用することで、もっと多くの情報を空中を飛ばすことができるんだよ。

# まとめ

このように、ダイナミックスペクトラムアクセスは、電波のチャンネルを上手に使って、もっとたくさんの情報を送受信するための方法だよ。これによって、ラジオやテレビ、インターネットなどの通信がもっとスムーズになるかもしれないね！
せんせー、ストレッチャブルエレクトロニクスってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/2c47de5a-d81a-78f9-53c1-4d31d8398c36.png)

キーンコーンカーンコーン...
授業が始まります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/be1492ca-910f-2708-d0fa-8fcfcf14af73.png)

せんせー、ストレッチャブルエレクトロニクスってなに？

# ストレッチャブルエレクトロニクスとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/da229491-9c49-fb7a-a542-417180e256a7.png)

## ストレッチャブルエレクトロニクスって何？

みんな、ゴムを知ってる？引っ張ると伸びるあのものだよ。さて、電子機器やガジェットって、固いと思う
よね。でも、ゴムのように伸びる電子機器があったら、面白いと思わない？それが「ストレッチャブルエレクトロニクス」なんだよ！

## どういうこと？

電子機器の中には、小さな部品や回路がたくさん入っているんだ。これらを特別な方法で作ると、ゴムのように伸びたり、曲がったりすることができるんだよ。それを「ストレッチャブル（伸びる）エレクトロニクス」と呼ぶんだ。

## どうしてそれがすごいの？

普通の電子機器は固いから、曲げたり伸ばしたりすると壊れてしまうよね。でも、ストレッチャブルエレクトロニクスは、ゴムのように伸びるから、色んな形や場所に使うことができるんだ。例えば、服の中に入れたり、身体に貼ったりして、新しい使い方ができるよ。

## だから、ストレッチャブルエレクトロニクスってなに？

ストレッチャブルエレクトロニクスは、ゴムみたいに伸びる電子機器のこと。固くないから、いろいろな場所や方法で使える特別な電子機器なんだよ。

# まとめ

このように、ストレッチャブルエレクトロニクスは、伸びる電子機器のこと。今後、もっとたくさんの場所や方法で使われるようになるかもしれないね。とっても未来的で楽しい技術だよ！
docker-composeのバージョンを上げたら「mapping key "<<" already defined」エラーでdocker-compose upが失敗する

docker-compose watchを試そうと思って、docker-composeのバージョンを2.22.0にアップデートしたところ、エラーが出てupが失敗するようになってしまいました。


# 現象

- docker-composeをアップデート（2.10系 ⇒ 2.22系）
- `docker-compose up`にて以下のエラーが出た

```shell
mapping key "<<" already defined
```

## ymlファイル（旧）

複数のコンテナで共用したい環境変数を複数の変数に分けて定義し、必要に応じてenvironmentにマージする形で使用していました

```docker-compose.yml
x-env-aws: &aws
  # AWS接続情報
  ・・・

x-env-shared: &shared-values
  # サービス共通で使用したい値
  ・・・

services:
  web:
    ・・・
    environment:
      <<: *aws
      <<: *shared-values
      # 以下、コンテナ固有の環境変数を定義
```


# 原因

どうやらdocker-composeのv2.17.0から`<<`は一つにまとめる記載をしないといけなくなったようです。
参考：https://github.com/docker/compose/issues/10407#issuecomment-1484787932

```docker-compose.yml
x-environment: &env
  environment:
    SOME_VARIABLE: "some_value"

x-deploy-limit: &deploy-limit
  deploy:
    resources:
      limits:
        memory: 24M

services:
  service_a:
    image: alpine
    command: [ "sleep", "infinity"]
    <<: [*env, *deploy-limit]
```

# 修正後のyml

```docker-compose.yml
x-env-aws: &aws
  # AWS接続情報
  ・・・

x-env-shared: &shared-values
  # サービス共通で使用したい値
  ・・・

services:
  web:
    ・・・
    environment:
      # 複数の`<<`を[]で1行にまとめる
      <<: [*aws, *shared-values]
```

# 最後に

一気にバージョンを上げると、破壊的な変更を検知しづらいのでちょいちょいアップデートしていきたいところですね。。。

ちなみに、先日のDockerConで色々と今後のアプデが発表されましたが、かなり便利になりそうなので乗り遅れないようにしたいですね！

https://www.dockercon.com/

https://www.itmedia.co.jp/news/articles/2310/12/news097.html

https://codezine.jp/article/detail/18503
純粋なcppプロジェクトをrosノード化する


純粋な`cpp`プロジェクト(`cmake`+`make`でビルドするプロジェクト)をROS化する方法です．

CMakeLits.txt内で必要なrosパッケージの関連付けとcmakeコマンド実施時に,依存パッケージのcmakeファイルパスを指定することで純粋なc++プロジェクトからROSパッケージを使用することができます．

実施内容はいｋ

- `CMakeLists.txt`内 ros関連の必要なパッケージの関連付け

```cmake:CMakeLits.txt
...

find_package(roscpp)

include_directories(
  ${roscpp_INCLUDE_DIRS}
)

target_link_libraries(${PROJECT_NAME} PUBLIC  ${roscpp_LIBRARIES}) 

...
```

- cmakeの際に依存パッケージのcmakeパスを指定

```bash:cmake
cmake .. -Droscpp_DIR=/opt/ros/noetic/share/roscpp/cmake -Dcpp_common_DIR=/opt/ros/noetic/share/cpp_common/cmake -Dmessage_runtime_DIR=/opt/ros/noetic/share/message_runtime/cmake -Droscpp_serialization_DIR=/opt/ros/noetic/share/roscpp_serialization/cmake -Droscpp_traits_DIR=/opt/ros/noetic/share/roscpp_traits/cmake -Drostime_DIR=/opt/ros/noetic/share/rostime/cmake -Drosconsole_DIR=/opt/ros/noetic/share/rosconsole/cmake -Drosgraph_msgs_DIR=/opt/ros/noetic/share/rosgraph_msgs/cmake -Dstd_msgs_DIR=/opt/ros/noetic/share/std_msgs/cmake -Dxmlrpcpp_DIR=/opt/ros/noetic/share/xmlrpcpp/cmake

```

# 参考

https://answers.ros.org/question/319379/broke-ros-dependencies-not-sure-how-to-fix/

https://github.com/cntools/libsurvive/issues/238
キーボード表示中に画面遷移して戻ってくるとbreaking constraintとコンソールに出力されてしまう

## breaking constraintが表示される前提条件
対象のUITextFieldやUITextViewのinputAccessoryViewにUIToolBar(閉じるボタンとか付けれるやーつ)を代入してる

# 解決策
viewWillDisappear内でview.endEditingする

```SampleViewController.swift
override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        view.endEditing(true)
    }
```

breaking constraintの警告の中にsystemInputAssistantViewやらUIRemoteKeyboardPlaceholderViewやら書いてあったので、キーボードが原因かと思って画面遷移時に引っ込めるようにしたら解決しました！めでたしめでたし！

## おまけ view.endEditing不要パターン
1. チャット画面など、画面下部のカスタムinputAccessoryView内のUITextViewでキーボード使う場合(Delegate使う場合？)は、キーボード表示中に遷移先から戻ってきてもキーボード消えてくれてました！

2. ViewController内に入力系のUIがUIPickerViewを代入してるUITextFieldしかない場合も、キーボード表示中に遷移先から戻ってきてもbreaking constraintは表示されませんでした！
ARC167回答メモ

# 0.はじめに
　先週に続きARC参戦。
　Aをなんとか解けたけど、Bはうまくいかず時間切れ。
　でもまぁ、Aは行けたし、多少はレート揚がってるやろと思いきや
　-5と微減。
　300点問題だし、速度が足りなかったなぁと思いました。


# 1.A - Toasts for Breakfast Party
　直感的に、値が小さい方から詰めて載せていけば
　いいのでは！と実装してテスト。
　テストケース３でいきなり不一致。
　（A+B）**２を最小にするということは
　2ABを最小にすること・・・
　2枚載せる分は、小さい方から選ぶのはそうとして、
　その中で、大きい方と小さい方から一枚ずつ
　組み合わせておけばよいと気づきました。

　【実装】
　　1.NとMとリストAを読み込む
　　2.D2(2枚載せる皿の数)＝N-M
　　3.ans(答え)、D(2枚載せる皿に1枚載せた数)j(2枚目を載せる皿の位置を保持)
　　　を、0で初期化
　　4.D2L(2枚目載せる皿に1枚目のせたトーストの美味しさを保持)を空リストで初期化
　　5.以下をインデックスiでN回繰り返し
　　　5-1.D2>0の時(2枚載せる皿のうち、1枚目が載っていない皿が残っている時)
　　　　5-1-1.D2LにA[i]を追加
　　　　5-1-2.D2から1減算
　　　　5-1-3.jに1加算
　　　5-2.D2<=0かつ、j>0(2枚載せる皿に1枚目がすべて載っていてかつ2枚目が
　　　　　載っていない皿があるとき)
　　　　5-2-1.jから1減算
　　　　5-2-2.ansに(D2L[j]+A[i])**2を加算（2枚載せる皿が完成）
　　　5-3.5-1・2に当てはまらない時(2枚載せる皿は埋まった時)
　　　　5-3-1.ansにA[i]**2を加算(1枚載せる皿が完成)
　　6.ansを出力して終了

　トーストを美味しく無い順に2枚載せる皿に置いていき、2枚載せる皿が埋まったら
　折り返して2枚載せる皿に置いていき、余ったのを1枚載せる皿にのせるイメージです。
　（より分かりにくい気もしますが・・）
　　　　

　https://atcoder.jp/contests/arc167/submissions/46631528

# 2.B - Product of Divisors
　正直、ぱっと見行けそうもなかったのですが
　ググりながら模索していくうちにいけそうな雰囲気になりました。
　結局、WAすら解消できずに時間切れでした。
　解説を読んで、今一な部分はわかりましたので
　折を見てリベンジしていきたいと思います。



以上
javascriptでタブを作る

```javascript:Main
<!DOCTYPE html>
<html>
<head>
    <title>詳細メニュー</title>
</head>
<body>
    <table border="1" style="border-collapse: collapse;">
        <tr>
            <td onmouseover="showDetails('details1')" onmouseout="hideDetails('details1')">MENU</td>
            <td onmouseover="showDetails('details2')" onmouseout="hideDetails('details2')">メール受信</td>
            <td onmouseover="showDetails('details3')" onmouseout="hideDetails('details3')">メール送信</td>
            <td onmouseover="showDetails('details4')" onmouseout="hideDetails('details4')">メール削除</td>
        </tr>
        <tr>
            <td id="details1" onmouseover="showDetails('details1')" onmouseout="hideDetails('details1')" style="visibility: hidden;">
            </td>
            <td id="details2" onmouseover="showDetails('details2')" onmouseout="hideDetails('details2')" style="visibility: hidden;">
                <p onclick="showStr('str1')">・メニューを表示</p>
                <p onclick="hideStr('str1')">・メニューを削除</p>
            </td>
            <td id="details3" onmouseover="showDetails('details3')" onmouseout="hideDetails('details3')" style="visibility: hidden;">
                <p onclick="showStr('str2')">・メニューを表示</p>
                <p onclick="hideStr('str2')">・メニューを削除</p>
            </td>
            <td id="details4" onmouseover="showDetails('details4')" onmouseout="hideDetails('details4')" style="visibility: hidden;">
                <p onclick="showStr('str3')">・メニューを表示</p>
                <p onclick="hideStr('str3')">・メニューを削除</p>
            </td>
        </tr>
        <tr>
            <td style="visibility: hidden;">
            </td>
            <td id="str1" style="visibility: hidden;">
                受信
            </td>
            <td id="str2" style="visibility: hidden;">
                送信
            </td>
            <td id="str3" style="visibility: hidden;">
                削除
            </td>
        </tr>
    </table>

    <script>
        function showDetails(elementId) {
            const details = document.getElementById(elementId);
            details.style.visibility = "visible"; // カーソルが1行目に重なったときに2行目を表示
        }

        function hideDetails(elementId) {
            const details = document.getElementById(elementId);
            details.style.visibility = "hidden"; // カーソルが1行目から外れたときに2行目を非表示
        }

        function showStr(elementId) {
            const con = document.getElementById(elementId);
            con.style.visibility = "visible";
        }

        function hideStr(elementId) {
            const con = document.getElementById(elementId);
            con.style.visibility = "hidden";
        }
    </script>
</body>
</html>

```
datasets.map(), datasets.filter()の仕様について

# TL; DR


# 背景

アルバイトの研修タスクに取り組んでいる途中、Hugging Faceの`datasets.map()`関数の中身の書き方がわからなくなり、[NLP Course 5章](https://huggingface.co/learn/nlp-course/chapter5/1?fw=pt)に取り組みながら解決したので忘備録として残します。

その時使っていたデータセット: [drug review dataset](https://archive.ics.uci.edu/dataset/461/drug+review+dataset+druglib+com)
)

```shell
!wget "https://archive.ics.uci.edu/ml/machine-learning-databases/00462/drugsCom_raw.zip"
!unzip drugsCom_raw.zip
```
```python
from datasets import load_dataset

data_files = {"train": "drugsComTrain_raw.tsv", "test": "drugsComTest_raw.tsv"}
drug_dataset = load_dataset("csv", data_files=data_files, delimiter="\t")
```

# わかったこと

filter()メソッドでデータセットのフィルタリングをしたいとき：
条件をラムダ関数などで記述して渡す
```python
drug_dataset = drug_dataset.filter(lambda x: x["condition"] is not None)
```

既存の列の値に変更を加えたいとき：
処理したい列のみ辞書形式でreturnすれば処理結果がデータセットに反映される
```python
def lowercase_condition(example):
    return {"condition": example["condition"].lower()}

drug_dataset = drug_dataset.map(lowercase_condition)
```

既存の列の値から新しい列を生成したいとき:
新しい列を作りたい際も辞書形式で新しい列名のみ書いてリターンすればデータセットに反映される

```python
def compute_review_length(example):
    return {"review_length": len(example["review"].split())}

drug_dataset = drug_dataset.map(compute_review_length)
```
Wireshark

<!--
2023/10/22
-->
[picoCTF][Forensics][FindAndOpen]

## Writeup
* pcapファイルがあるので、とりあえずWiresharkで開く
いきなりメッセージっぽいものが。
![screenshot 3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/53bbbc24-31e9-ca7b-5063-38c2f920d3e8.png)
<br>

* `Ethernet secret:Is this the flag`だそうです。
Ethernetを見ていくと、またメッセージのようなものが。
* `Could the flag have been splited?`だそうです。
![screenshot 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/9287b5c0-49f8-d970-87e0-592d7280f582.png)
<br>

* メッセージっぽくないけど、末尾に`=`があるので、base64かな。
![screenshot 8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/f616909b-7035-85c4-081e-cbc34ef4de18.png)
![screenshot 6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/dee59ff0-28b4-3c88-486a-3f9d9405a5f6.png)
<br>

* `Maybe try checking the other file`だそうです。
This is the secret:ってあるので、パスワードなのかな。
![screenshot 5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/5cb35a0a-f45f-c11f-85d6-a95785e03c83.png)
![screenshot 9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160736/b6aba6bd-ad00-2663-20e7-78d1ce1c3d4e.png)
* 無事に解凍できました。
<br>

* 以上です。
BGPパスアトリビュートを覚える呪文

こんにちは。E-kan株式会社の藤尾です。

BGPパスアトリビュートが覚えられない～と毎回調べていたのですが、
CCNP取得を目指したことで、暗記しておく必要がでてきました……。

ちなみに過去の備忘録として残したBGPベストパス選択の順番は[こちら](https://www.wantedly.com/companies/e-kan/post_articles/345469)。
今でもたまに確認していて、業務としては調べて確認できれば問題はないのですが、
試験だとそうはいかないのが大変ですね。

現場で「毎回調べてしまって暗記できないんですよね～～～～」とボヤいたところ、
英語の呪文を教えて頂きました。
水平リーベで元素記号を覚えるのと同じようなものですね！

その呪文がこちら
**We** **Lo**ve **Or**anges **As** **Or**anges **Me**an **P**ure **R**efreshment
意味は関係ないから言葉だけ覚えるといいよ、とのこと。

それぞれの単語の最初がBGPパスアトリビュートの優先度順になるというワケです。
**We**ight, **Lo**cal Pref, **Or**iginate, **AS**_PATH, **Or**igin, **ME**D, **P**aths, **R**outerID

| 略|パスアトリビュート|説明|
|:-----------|:-----------|:-----------|
|W	|Weight |Cisco独自。アトリビュートが最も大きいルートを優先|
|L	|LOCAL_PREF |アトリビュートが最も大きいルートを優先|
|O	|Originate |networkコマンドで生成したパス|
|AS	|AS_PATH |アトリビュートが最も短いルートを優先|
|O	|ORIGIN Code |アトリビュートが最も小さいルートを優先（ IGP < EGP < Incomplete ）|
|M	|MED |アトリビュートが最も小さいルートを優先|
|P	|Paths |IBGPで学習したルートよりもEBGPで学習したルートを優先|
|R	|RID |ルータIDが最小のBGPピアから受信したルートを優先|

各パラメータにおける優先度の仕組みやデフォルトはそれぞれ覚える必要がありますが、
順番が分かるだけでも助かります。




# 最後までお読みいただき、ありがとうございます！
イーカンは世界中のエンジニアとともに、ワクワクしたITの未来を作り上げることを楽しみにしています。

新しいテクノロジーとアイデアをブレンドして、もっと便利で効率的なソリューションを世界へ届けることに情熱を注いでいます。

イーカンの目指す未来は、テクノロジーの進化が生活やビジネスに影響を与えて、社会をポジティブな方向に進めていくことです。世界中のエンジニアのビジョンや目標をサポートし、共に成長できることを期待しています！

最新情報やイベントについては、弊社ウェブサイトやSNSアカウントを通じてご案内していきますので、ぜひご覧ください。
エンジニアの皆様との新たな出会いに感謝し、これからも一緒に未来を切り拓いていけることを楽しみにしております。

私たちとともにITの発展を追求していきましょう！

[E-kan株式会社　イーカンカブシキガイシャ]
ウェブサイト：https://e-kan.tokyo/
採用サイト：https://en-gage.net/e-kan/
Twitter：https://twitter.com/EkanTw
Facebook：https://www.facebook.com/ekan0507
Pythonで「ファイルに記述したプログラムを実行する」の動作を確認してみた

# 概要

Pythonで「ファイルに記述したプログラムを実行する」の動作を確認してみました。以下のページを参考にしました。

https://www.javadrive.jp/python/ini/index1.html

# 実装

以下のファイルを作成しました。
```hello2.py
print ("Hello, Python")
```

以下のコマンドを実行しました。
```
$ python3 hello2.py 
Hello, Python
```

# まとめ

何かの役に立てばと。
個人技術投稿の目次です

# 個人技術投稿の目次です

以前の固定投稿もリンクさせています。

これらの投稿で、　
Ctrl と書かれていたら、これはwindows での Ctrl なので、
Mac 系の方は、⌘（command）キーとして捉えてください。＼(_ _)

## 一般系

 1. [アプリボタンの位置の覚え方(パソコン初心者にオススメ）のリンクです。](https://qiita.com/FUKUTAKA7938/items/2a845f964730353304dc)
2. [URLのメールへリンクさせる修正版のリンクです。](https://qiita.com/FUKUTAKA7938/items/8938895fd8af68804ed5)
3. [XへのURLの複数リンクの貼り付け方のリンクです。](https://qiita.com/FUKUTAKA7938/items/7e32f0b17aff40f1db47)
4. [ワークシート関数式をコピペで利用する方法のリンクです。(EXCEL)](https://qiita.com/FUKUTAKA7938/items/0c38b85aadea272e4b33)
5. [各教科の基準点以上と合計点数で、ランク(アルファベット S〜D、不合格)を付ける。(EXCEL)](https://qiita.com/FUKUTAKA7938/items/a1589400ec488a7c9060)
6. [スマートフォンで文字列をアプリへコピー＆ペーストする方法（FUKUTAKA編）](https://qiita.com/FUKUTAKA7938/items/3dd6aea90c267745c631)
7. [X の ブロックした人からXへ報告をする方法(FUKUTAKA編)](https://qiita.com/FUKUTAKA7938/items/761a4a34b4a82aef25bb)

#

## サーバー関係

1. [AlmaLinux9サーバーへのssh接続でchroot設定のやり方](https://qiita.com/FUKUTAKA7938/items/74c6b7adbb0ea5a5f930)
2. [Alma Linux 9/Rocky Linux 9 、apacheサーバーで、sqlite3のDBファイルのネットワークで使うためのコツ(一応、玄人向けです。)(FUKUTAKA編)](https://qiita.com/FUKUTAKA7938/items/5de863729a84e923d421)
3. [apacheサーバー接続のオーナー名の変更についての参考例 - あくまでも実験でやってます。\(_ _)/(一応、これも玄人編)FUKUTAKA編)](https://qiita.com/FUKUTAKA7938/items/118387da6c3f04be9c60)
### 4. [ホストAlmaLinux9.4 httpsサーバ、クライアント MacBook Air M2 macOS Sequoia 15.1 での接続(玄人編)](https://qiita.com/FUKUTAKA7938/items/e1f89efe16ea80e1c145)`(2024/11/12変更)`

#

# 開発環境設定関係
1. [Ubuntu 24.04 LTS のRUSTでのデバイスドライバ開発環境設定(参考サイトがあります、これも玄人の編)](https://qiita.com/FUKUTAKA7938/items/6c72f8a6f46f034bf74c)

# カーネル作成関係
１. [Ubuntu 24.04 LTS での aarch64 カーネルコンパイル(参考サイトがあります、これも玄人編)](https://qiita.com/FUKUTAKA7938/items/0cd6b6f0d3096abb5858)

#
isinで特定の番号の範囲を取得しようとしたらSparkRuntimeExceptionが発生した

## はじめに
PySparkで作成したDataFrameのデータのうち、
idが20番台のデータを取得したいコードを書いたところ、SparkRuntimeExceptionが発生してしまったので備忘メモとして残します。

## やりたいこと
* 作成したDataFrameのレコードの中で、idカラムが20番台(20~29)のレコードを取得したい！
* 20, 21, 22,...という形で指定するのではなく範囲を指定して取得したい！

## 環境
#### 使用した環境
・Google Colaboratory
・Python: 3.10.12
・PySpark: 3.5.0

## 今回使用したコード
https://github.com/yuuka51/google_colab/blob/main/learn_pyspark/pyspark_processing_dataframe_learn.ipynb

以下のようにfilterとisinを使用して20番台のレコードを取得しようとするとSparkRuntimeExceptionが発生してしまいます。

```python
# 20番台の範囲を指定したいのでrangeを使用したがSparkRuntimeExceptionが発生してしまう
sdf.filter(
F.col("id").isin(range(20, 30))
)
```

## エラー内容
```
---------------------------------------------------------------------------
SparkRuntimeException                     Traceback (most recent call last)
<ipython-input-10-3db942e00f8f> in <cell line: 1>()
      1 sdf.filter(
----> 2 F.col("id").isin(range(20, 30))
      3 )

4 frames
/usr/local/lib/python3.10/dist-packages/pyspark/errors/exceptions/captured.py in deco(*a, **kw)
    183                 # Hide where the exception came from that shows a non-Pythonic
    184                 # JVM exception message.
--> 185                 raise converted from None
    186             else:
    187                 raise

SparkRuntimeException: [UNSUPPORTED_FEATURE.LITERAL_TYPE] The feature is not supported: Literal for '[20, 21, 22, 23, 24, 25, 26, 27, 28, 29]' of class java.util.ArrayList.
```

## 原因

公式ドキュメントよりrange型は使用できる型ではないようです。

https://spark.apache.org/docs/3.1.3/api/python/reference/api/pyspark.sql.Column.isin.html

## 解決方法
rangeの外側をlistで囲って型を変換することで実行できるようになりました。

```python
df.filter(
F.col("id").isin(list(range(20, 30)))
).show()
```
出力結果
```
+---+---+---+
| id|  a|  b|
+---+---+---+
| 20|  n|123|
| 21|  o|234|
| 22|  p|234|
| 23|  q|123|
| 24|  r|123|
| 25|  s|123|
| 26|  t|123|
| 27|  u|123|
| 28|  v|123|
| 29|  w|123|
+---+---+---+
```
メタクラスについて

この概念コボラーには結構とっつきにくいんですよね。
↓ご参考です。
説明が分かりやすいです。
https://yu-nix.com/archives/django-meta
ドキュメントはこちら
https://docs.djangoproject.com/ja/4.2/ref/models/options/

試しに作ってみました。
abstractを適用してみました。
![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571777/9fcf5658-b05b-e57c-8ef0-a5721b94624e.jpeg)
Terraformで作ったS3オブジェクトをCloudFront経由でアクセスするとダウンロードになった。。。

# 前提
・S3バケットを作成
・CloudFrontのOAIを作成し、作ったS3バケットをオリジンに指定（S3のバケットポリシーの自動編集にチェックを入れた）

# 事象
AWSマネジメントコンソールでS3バケットへhtmlをアップした場合、CloudFront経由で無事アクセスできたが、
```ruby:index1.html
uploaded by AWS management console.
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/e719dd37-0901-0e46-f8a7-dd8b3e3639e5.png)

このように、Terraformのソースコードで、まずS3バケットをimportして、S3オブジェクトをアップすると、
```ruby:
import {
  to = aws_s3_bucket.bucket
  id = "bucket_name"
}
resource "aws_s3_object" "object" {
  bucket = aws_s3_bucket.bucket.id
  key = "index2.html"
  source = "index2.html"
  etag = filemd5("index2.html")
}
```
```ruby:index2.html
uploaded by Terraform.
```

マネジメントコンソールで見ると、index2.htmlは無事アップロードできるように見えたが、

CloudFront経由でindex2.htmlへアクセスしようとすると、「ダウンロード」になってしまった。。。

# 解決方法

原因は、「content_type」の設定が漏れてしまったから！

```ruby:
import {
  to = aws_s3_bucket.bucket
  id = "bucket_name"
}
resource "aws_s3_object" "object" {
  bucket = aws_s3_bucket.bucket.id
  key = "index2.html"
  source = "index2.html"
  etag = filemd5("index2.html")
  content_type = "text/html"  ###ここを修正！！
}
```

AWSマネジメントコンソールでアップしたindex1.htmlのメタデータを見ると、
**text/html**って自動で設定されるのが分かって、


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/25f13ac9-b3a0-e7cd-ca25-f9df9a309512.png)

しかし、Terraformでオブジェクトをアップする場合、明示的にcontent_type = "text/html"を設定してあげないと、**application/octet-stream**になってしまって。。。

index2.htmlのメタデータを見ると、確かにストリームだね。。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/54c5e7ae-8fe4-6d23-28c4-f62686fff2f7.png)

これだと、アクセスするときはダウンロードになってしまう。。。

# 終わりに
今回はAWSマネジメントコンソールとTerraformでS3オブジェクトをアップする場合の挙動を勉強できた！

# 参考サイト
https://qiita.com/YoshitakeHiroki/items/bb9a5bc86d1ef58d0b7c