OmniAICreator/Qiita-1.07M huggingface dataset:
Sparkにおけるデータの爆発 - 特定、結末とソリューション

> **[DatabricksでSparkとDelta Lakeワークロードを最適化するための包括的ガイド](https://qiita.com/taka_yayoi/items/cd199691569fef069a9d)のコンテンツです。**

[Comprehensive Guide to Optimize Data Workloads \| Databricks](https://www.databricks.com/discover/pages/optimize-data-workloads-guide)のセクション[Data Explosion — Identification, Consequences and Solutions](https://www.databricks.com/discover/pages/optimize-data-workloads-guide#data-explosion)の翻訳です。

:::note warn
- 本書は著者が手動で翻訳したものであり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
- 2023年時点の内容です。一部情報が古いものがあります。
:::

特定の変換ステップ後のSparkジョブの実行において、データ爆発と考えられるデータボリュームの不自然な増加を目撃するかもしれません。これによって、クエリーの実行時間は急激にスローダウンします。以下では、データ爆発を引き起こすことにある最もよくある変換処理のいくつかを示します:

# 1. Explode関数

![](https://www.databricks.com/en-website-assets/static/047ac8fbfe6a9e3c3684798759f858aa/22894.png)

JSON、Parquet、Delta、XMLのようなフォーマットを持つ構造化ファイルを操作している際、array、list、mapのようなコレクションでデータを取得することがよくあります。このような場合、Sparkで効率的に処理するためにコレクションの列を行に変換するのに、`explode()`関数は有用です。この[explode](https://sparkbyexamples.com/pyspark/pyspark-explode-array-and-map-columns-to-rows/)オペレーションは、データボリュームを劇的に増加させることがあります。explodeオペレーションは上の画像のようにSpark UIでは*Generate*として表現されます。

# 2. Joinオペレーション

遅いクエリーの一般的な原因は、期待したよりもはるかに多い行を生成するjoinです。これは、多くの場合「行の爆発」と呼ばれるものです。潜在的な行の爆発を特定するには、Spark UIの*SortMergeJoin*や*ShuffleHashJoin*ノードの*rows output*メトリックを参照します。

![](https://www.databricks.com/en-website-assets/static/65645f39d1efe2bbf260897bc3f6e0d3/22895.png)

# インパクト

Parquet、Deltaなどのようなソースから入力データを読み込む際、Sparkはコアあたりのタスクごとに約128MBを読み込み、これはそれぞれのCPUコアで利用できるメモリーに収まるちょうど良いパーティションサイズとなっています。しかし、データ爆発によって、128MBのデータは単一のCPUコアでは爆発したパーティションにフィットするには十分を持たないため問題となるような、非常に大きなボリューム(数GBなど)に変換されることでしょう。この結果、以降のワイドな変換処理では、大量のデータがディスクに溢れ、クエリーパフォーマンスに大きなインパクトを与えることになります。

# ソリューション

- 入力パーティションのサイズを削減します。`explode()`関数の効果を打ち消すために、より小規模なパーティションを作成するために、`spark.sql.files.maxPartitionBytes`(デフォルトは128MB)を減らします。例えば、16MBや32MBのようにはるかに小さいパーティションサイズを選択することができます。

    ```
    set spark.sql.files.maxPartitionBytes = <size in bytes>
    ```

- パーティションの総数を増加させるために、読み込みステートメントのすぐ後で[repartition\(\)](https://spark.apache.org/docs/3.4.1/api/python/reference/pyspark.sql/api/pyspark.sql.DataFrame.repartition.html)関数を明示的に呼び出すことができます。これによって、それぞれのパーティションのサイズを削減することができます。
- joinオペレーションによって爆発が起きている場合には、シンプルなソリューションはパーティションのサイズを128MBよりもはるかに少なくするように、シャッフルパーティションの数を増加させることです。詳細に関しては、[手動でのシャッフルパーティションのチューニング](https://qiita.com/taka_yayoi/items/0fbe02b5f4cd6c0bb9a3#2-%E6%89%8B%E5%8B%95%E3%81%A7%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%B3%E3%83%81%E3%83%A5%E3%83%BC%E3%83%B3)のセクションをご覧ください。

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
オープンソースカンファレンスへの出展ー手続きと準備 ～企業出展編～ ー

先日 (2024/10/26)開催された[**オープンソースカンファレンス2024 Tokyo/Fall**](https://event.ospn.jp/osc2024-fall/ )へ出展してきました。その手続きと準備についてまとめます。 

### オープンソースカンファレンスとは？
"オープンソースカンファレンス（OSC）は、オープンソースの今を伝えるイベントです。
東京だけでなく、北は北海道、南は沖縄まで、年間を通じて全国各地で開催しています。 

オープンソース関連のコミュニティや協賛企業・後援団体による、セミナーやプロダクトの展示などを入場・参加料が無料でご覧いただけるイベントです。" 
([オープンソースカンファレンスの公式ページ](https://www.ospn.jp/) からの引用 )

<br/>

上記のイベントで筆者が所属している企業の場合について書いております。所属企業や開催地域によって異なる場合がありますので、みなさまのご環境に合わせて読み替えてください。 

また、企業出展とコミュニティ出展で手続きと準備のステップが異なりますが、今回は**企業出展の場合**について説明します。 

※本記事は2024年10月現在の情報です。また、出展者として参加した経験からその手続きや準備をまとめたもので、出展の効果や効率的な集客については書いたものではありませんので、あらかじめご了承ください。 


### 1.　出展するイベントを決める 

オープンソースカンファレンスは日本全国で開催されています。 

開催場所と時期は [**オープンソースカンファレンスWebサイトトップ**](https://www.ospn.jp/) の
ぺージ中腹部 **「オープンソースカンファレンス今後の開催予定」** に掲載されているので、
この中から出展するイベントを決めます。 

出展したい地域がない場合は、まだ開催が決まっていない可能性がありますが、
[**過去開催一覧**](https://www.ospn.jp/eventlist) を参照して開催場所と時期を推測できます。
あまり古いものは参考にならないと思うので前年あたりまでを参考にするとよいでしょう。 
また、過去開催を参考にする場合、コロナ前後など、時勢も考慮する必要があります。 

[**OSPN Pressメールマガジン**](https://www.ospn.jp/press/mailmagazine)へ登録しておくと、メールマガジンが月一程度で配信されます。その中で新たに開催の決まったイベントが掲載されます。 

### 2.　展示するものを決める 

来場者へアピールしたい製品や技術を決めましょう。 
オープンソースのイベントなので、オープンソースを使ったものか、関連するものがよいと思います。 

### 3.　社内稟議を通す 

社内でオープンソースカンファレンスへ出展したい旨を伝え、出展許可を取りましょう。 
社内手続きや決済者の賛同を得るため根回しは重要です。 

 
**企業出展の場合、協賛金が要るので注意してください。**


金額はそれほど高くないですが、正確な情報は必要となります。 
過去に出展したことがない場合は、出展するイベントのWebページに「お問合せ」のリンクがあるので、そこから問い合わせましょう。 
過去に出展したことがあれば、イベントの出展募集が始まると、申込書がメールで届きます。そこに詳しい情報が書かれています。

 

### 4.申し込む 

* **申込書に必要事項を書き、事務局へメールで送信** 
申込書は、過去に出展したことがない場合は、出展するイベントのWebページに「お問合せ」のリンクがあるので、そこから問い合わせましょう。 
出展したことがある場合は、イベントへの出展募集が開始されると、メールで申込書が送られてきます。 

&#13;&#10;

* **企業・団体ロゴを事務局へ送る** 
イベントのWebページへ掲載してくれます。 

&#13;&#10;

* 製品のpdfファイルを送ると、イベントのWebページの[**オンラインちらしコーナー**](https://event.ospn.jp/osc2024-fall/article/flyers)へ掲載してくれます。 


### 5.イベント前日までの準備 

前日までに、イベントへ持っていくものを用意しましょう。 
個人的に注意が必要なものを挙げます。 

* **展示物**
オープンソースカンファレンスは当日設営、撤収となります。 
故に、準備が大変な大がかりなデモの展示はお薦めしません。 
私は１時間程度で設置でき、30分程度で撤収できるものを選んでいます。 

&#13;&#10;
 

* **ブース来場者へ配布するリーフレット** 
ビジネス向けの展示会と異なり、複数日開催ではなく、また来場者もほどほどなので、数百部も持っていくのはお薦めしません。個人的には100部程度あればよいと思います。 

&#13;&#10;
 

* **電源タップ** 
デモを展示する場合などで必要となります。 ブースの位置によっては、コンセントの位置が遠い場合があるので、長めのものを用意するか複数個もっていきましょう。 

 

イベントによっては荷物の郵送ができない場合があるので、イベントの申込書を確認して郵送不可なら手持ちできる量に留めておきましょう。  

オープンソースカンファレンスは、土日開催が多いので、社内で休日出勤や代休の手続きをしましょう。社内手続きは重要です。 
イベントWebページからカンファレンス参加登録してください。 

 

 

### 6.　イベント当日の準備 

一般的なビジネス向けの展示会とは異なり、 オープンソースカンファレンスは基本的に当日設営です。 そのためブースの準備は当日の来場者が来られる前の早い時間に行います。 

 

少し早めに会場へ到着して会場の設営（机や椅子を並べる作業）を手伝います。 
（今回は事情があり手伝えませんでした。会場を設営してくださった方々、ありがとうございました。）

 

会場の自ブースの位置に机が設置されるので、
そこにテーブルクロスを敷き展示物を並べます。 


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817840/ded777ae-675b-288e-eed1-f24b48291ca3.png" width="40%">

開場時間になると来場者が来られるので、展示物の説明をしましょう。 


### 7.イベント終了後 

事務局から請求書が送られてきます。
支払いのための社内手続きをすすめましょう。 

 

以上がオープンソースカンファレンスへの企業出展の流れです。 

参加したことのないイベントに出展するのは躊躇される方もいると思います。 
一度、来場者として参加してみて雰囲気を掴んだ上で、検討してみるのもよいと思います。
javascript

udemy課題自力作成し理解度UP
```.js
let input = prompt('こちらに以下を入力せよ(new, list, delete, quit)')
const todos = ['散歩する', '走る', '筋トレする', 'ご飯を食べる'];
// || ではないのがポイント
  while (input !== 'quit' && input !== 'q') {
    if (input === 'list') {
      for (let i=0; i < todos.length; i++) {
        console.log(`${i}:${todos[i]}`);
      }
    } else if (input === 'new') {
      let newTodo = prompt('新しいtodoを入力せよ');
      todos.push(newTodo);
      console.log(`『${newTodo}』を追加しました`)
    } else if (input === 'delete') {
    // parseInt使用しないと数字以外でも削除できてしまう
      let index = parseInt(prompt('削除するイデックスを入力せよ'));
      if (!Number.isNaN(index)) {
        let deleted = todos.splice(index, 1);
        console.log(`『${deleted}』を削除しました`);
      } else {
        console.log('有効なインデックスを入力せよ');
      }
    }
    input = prompt('こちらに以下を入力せよ(new, list, delete, quit)')
  }
  alert('アプリを終了しました');
```
iphoneでUTM SEを使用してArchLinuxを使用してみた(その2)

今回は日本語の対応をしてみようと思います。

# 初期状態の確認
ソフトキーボードを日本語に変更して入力はできるが、全角文字の半分しか文字が表示されません。

![IMG_2032.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3428695/5350f20a-b47d-d1ff-5ea4-646a5973a519.png)

どうもコンソールは標準では2バイトの文字の表示に対応していないみたいです。

# 対策あれこれ
フレームバッファが有効な場合には、fbtermなどの仮想コンソールを使用することで日本語の表示ができるようです。
そのため、下記でフレームバッファが有効か確認します。

~~~
ls /dev/fb*
~~~

ファイルが見つかりません、どうも有効になってないようです。

## フレームバッファの有効化
### カーネルモジュールのロード
カーネルのモジュールを手動でロードしてみます。
~~~
modprobe fbcon
modprobe vesafb
~~~
失敗してしまいました。
こうなると、カーネルのコンパイルからしないといけないようで、この環境ではあまりにもハードルが高そうです。

# 日本語化断念
この環境ではこれ以上のことは無理そうです。
これからも対応策を模索していこうとは思いますが、一旦は終了します。

# UTM SEを使ってみた感想
iphoneでlinuxを実行できるため、色々と遊べそうです。
ただ、処理速度がかなり遅いためiSHでできる範囲なら、UTM SEを使う必要は無さそうです。

UTM SEには色々な設定項目がありますが、まだまだ情報が少なく何をどう設定すれば良いのか手探り状態です。

ArchLinux意外にも色々と試してみようと思います。
Androidスクリーンショットを内部ストレージへ保存する

スクリーンショットを内部ストレージに保存。
保存したタイミングでメインスレッドに戻りたい。
## 準備
内部ストレージ許可
```xml:AndroidManifest
 <uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        tools:ignore="ScopedStorage" />
```

```kotlin:MainActivity
ActivityCompat.requestPermissions(
    this, arrayOf(
        Manifest.permission.WRITE_EXTERNAL_STORAGE,
    ), 1
)
```
## スクリーンショットの取得
スクリーンショットの取得にはPixelCopyを使う。
writeAwait()は後述。
```kotlin:MainActivity
private fun screenShot(){
    //# 保存先の指定（今回はアプリ内へ保存）
    val writefile = File(externalCacheDir, local)
    //# 画面いっぱいにスクショしよう
    val window = this.window
    val view = window.decorView.rootView
    val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
        PixelCopy.request(
            window,
            bitmap,
            { copyResult ->
                if (copyResult == PixelCopy.SUCCESS) {
                    //#ここでファイルに書き出してもいい                  
            },
            Handler(Looper.getMainLooper())
        )
        val st = writeAwait(bitmap,writefile)
        Log.d("OK？",st)
}
```
## 保存後にメインスレッドに戻る
```kotlin:MainActivity
private fun writeAwait(bit:Bitmap, file:File): String {
        Log.d("Coroutine", "executeAwait start")
        var ayncString = ""
        runBlocking {
            FileOutputStream(file).run{
                bit.compress(Bitmap.CompressFormat.JPEG,100,this)
                this.flush()
                this.close()
                ayncString = "OK"
            }
        }
        Log.d("Coroutine", "executeAwait end")
        return ayncString
    }
```
## ログ確認
runBlockingを使うことで
保存後にscreenShot()の最後、メインスレッドに戻れている
```:Logcat
Coroutine  D  executeAwait start
Coroutine  D  executeAwait end
OK?        D  OK
```
Pega Business Architect（PEGACPBA）の資格勉強方法

## はじめに
PEGACPBAを取ったのですが、受験する際に試験問題の雰囲気など情報が少なく困ったので、今後受験する方がいたら少しでもお役に立てたらと思い記事を書くことにしました。

## CPBAを合格した時の私のスペック
合格した時の私のスペックを簡単に紹介させていただきます。
- 24新卒で、8月に研修を終える
- Pegaは社内の部署紹介で、案件を紹介していただいていた時に初めて知る
- 研修後に、Pegaの案件に配属された
- Pega歴は、２ヶ月ちょっと程度で基礎的な研修を受けました

## 勉強方法
ここから私の勉強方法を共有しようと思うのですが、一度試験は不合格になっているので、その経験も踏まえて共有しようと思います。

結論から言うと、以下の勉強方法で私は合格できました。
- Pega Academyを何度も読み込む
- 自分で説明できるようにまとめる（私はパワポを使用しました）
- １回目の試験問題で出た部分を学習する←おまけ

もう少し詳しく解説していきます。
- Pega Academyを何度も読み込む
こちらですが、Pega Academyには練習問題があります。しかし、練習問題から試験問題は出ないと思って良いと思います。なので、練習問題は、各モジュールの理解度チェック程度でやり込む必要はないと思いました。練習問題を繰り返し解くのでなく、各モジュールの内容を繰り返し何度も読み込む方が効果的だと感じました。
- 自分で説明できるようにまとめる（私はパワポを使用しました）
続いてこちらですが、ただ読んでいるだけではなかなか覚えられないので、誰かに説明するつもりでパワポを作りながら勉強をし、作成したパワポで復習などをしていました。以下の画像が、実際に作成した、パワポの一部です。
![Screenshot 2024-11-16 at 23.45.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815234/4eea6fa8-13fb-0549-c037-ed67610ad50d.png)
- １回目の試験問題で出た部分を学習する
最後にこちらですが、私は一度不合格になってしまったのでできたことですが、練習問題では触れられていなかった部分が試験問題に出たりで、練習問題を中心に勉強していた１回目はこれが原因で落ちてしまったと思います。もう少し詳しい内容は後ほど。

ちなみに、Pega Academyにはモジュールとチャレンジがありますがモジュールだけを学習していれば合格できると思います。チャレンジは実際に手を動かすのですが、試験にはないので理解度を深めたい方はやってみても良いかもしれません。

## 試験問題について
試験問題は例えば、以下の画像のような一番右側に書かれている内容に合うワードを一番左から選択して、当てはめるような問題が出ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815234/e4441bb1-4c53-1027-220f-ac78d4957ff0.png)
その他にも、
- ユーザーに複数選択させたい時にはどのコントロールを使用するのが良いか？
- Constellationの正しい内容を２つ選択せよ
- アプリケーションの３つの柱を３つ選択せよ
というような雰囲気の問題が出てきます。

## おわりに
私が受験した時の受験料は3万円ほどだったので、一度落ちた時は金額が高くショックでした。
次はシステムアーキテクトの取得を目指します！
少しでも、試験勉強の参考になっていただけたら嬉しいです。
Cursorで自動フォーマットしないで保存する方法

最近、自分はコーディングする際に <font color="MediumOrchid">**[Cursor](https://www.cursor.com/)**</font> というエディタを使用することが多いです。


そこで、<font color="DodgerBlue">**VSCode**</font> から <font color="MediumOrchid">**Cursor**</font> へ移行した際に...
「『**自動フォーマットしないで保存する**』ためのキーボードショートカットがVSCodeと違くて分からない！」
と周りから質問されることが意外と多かったため、記事に残しておきます。
　
<details><summary><font color="DarkGray">Cursorとは...</font></summary>

:::note warn
<font color="DodgerBlue">VSCode（VisualStudioCode）</font>を元に作られた、AIによるサポート機能を搭載しているエディタ
- 基本的にVSCodeとほぼ同じ使用感で、高度なAIサポートを得られる
- 拡張機能もそのまま使用でき、VSCodeからの導入も一瞬で可能
（詳細は別の方々が色々な記事にまとめていただいておりますので、別途お調べいただけますと幸いです。）
:::
</details>

## 「フォーマットしないで保存」 のキーボードショートカット

| <font color="DodgerBlue">**VSCode**</font>の場合 | <font color="MediumOrchid">**Cursor**</font>の場合 |
| --- | --- |
| **`command + K` の後に `S`** | **`command + R` の後に `S`**|
| <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192049/ec74bbfb-f306-e190-6818-0166d134f6de.png" width=400> | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192049/0d8dea6a-7471-a3bf-6414-09f823652e2e.png" width=400> |

:::note info
### 結論

**Cursorでは、`command + K` の部分が、 `command + R` で設定されています。**
　
<details><summary><font color="DarkGray">初期設定が異なる理由...</font></summary>

Cursorでは、`command + K` に、独自のAIコード編集機能が割り当てられているためです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192049/a55c10e6-2776-4474-77fd-8a554b4c38fb.png" width=400>


</details>
:::
　
## その他（参考）
キーボードショートカットの設定は、以下から開くことができます。（VSCodeと同様）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192049/00af9ad9-0fb2-5b01-187f-28ac043395d3.png" width=400>
CSSで画面上から要素を見えないようにする手段


## 要素を非表示にする方法は主に３種類
簡単に画面上から要素を非表示にする方法を紹介したいと思います。

### 1. display:none
`display:none`は要素を消すことで、画面上から要素を見えなくすることができる。
表示する際には、`display`の値を`none`以外に設定することで、要素を表示することができる。
要素を消すことによって他の要素が詰まり、元のレイアウトと変わる可能性があるため、注意が必要。
要素を完全に消すため、実質HTMLで書いていないのと同じ扱いになる。

### 2. visibility:hidden
`visibility:hidden`は要素を非表示にすることで、画面上から要素を見えなくすることができる。
画面上に表示する際には、`visibility`の値を`visivle`に変えると表示することができる。
`visibility:hidden`は要素を非表示にする一方、`display:none`と違って要素を消しているわけではため、レイアウト自体が崩れることはない。
要素を非表示にするため、要素自体が完全になくなっているわけではないが、クリックはできない。

### 3. opacity:0
`opacity:0`は要素を透明にすることで、画面上から要素を見えなくすることができる。
画面上に表示する際には、`opacity`の値を１にすることで表示できる。
また、`opacity`の値は0～1の値で設定することができ、数字によって透明度を変えることができる。
（0.5を値で指定すると、要素が半透明になる）
透明になっているだけのため、画面上では見えないものの、クリックはできる。

### さいごに
画面上で動きをつける、デバイスによって画面の表示の仕方を変える際ために、要素の非表示を切り替えることは数多くあります。状況によって使い分けながら適切なプロパティを使用できるようにしましょう。
【Rails】最近コンソール機能を使うことが増えたので、、、

こんにちは！
今回は、railsのコンソール機能を使ってやったことをまとめたいと思います。


:::note info
バージョン
ruby 3.2.2
Rails 7.1.3
:::

# コンソールコマンド

### ・コンソール起動
```php

rails console

または

rails c
```

### ・データベースの操作

・データの作成
```php

User.create(name: "テスト太郎", email: "example@example.com")

```

・全てのデータ取得

```php
 User.all
```

・特定のデータ
```php
User.find(1)
// ※主キー（通常はid）を指定してデータを取得
```

・条件に一致する複数のデータを取得
```php
User.where(age: 25)
```

・部分一致
```php
User.where("name LIKE ?", "%テスト%")
```

・範囲指定
```php
User.where(age: 20..40)
```

・データの更新
```php
user.update(name: "山田 テスト")
```

・複数のデータを一括更新
```php
User.where(age: 30).update_all(age: 31)
```

・1件のデータの削除
```php
user.destroy
```

・複数のデータを削除
```php
User.where(age: 31).destroy_all
```

・データ量の確認
```php
User.count
```

・終了時
```php
exit

または

quit
```

# 終わりに
今回の記事は以上になります。
見ていただき、ありがとうございました！
【Java】画像データからハッシュ値を算出する方法

## はじめに
ハッシュ値は、データの整合性を確認する際や、データの一意性を保証するためによく使われます。本記事では、Javaを使って画像データからSHA-256のハッシュ値を算出する方法を紹介します。

## 1. 前提条件
この記事では以下の環境でコードを実行しています：
- OS：macOS 14.2
- Javaのバージョン：23.0.1
- 画像ファイル：ローカル環境に保存されたサンプル画像


## 2. サンプルコード
以下は、画像データからSHA-256ハッシュ値を算出するJavaコードの例です。

```java
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class ImageHash {
    public static String calculateHash(String filePath) throws NoSuchAlgorithmException, IOException {
        // SHA-256アルゴリズムのMessageDigestインスタンスを作成
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        FileInputStream fis = new FileInputStream(filePath);
        
        byte[] byteArray = new byte[1024];
        int bytesCount = 0;

        // ファイルを1024バイトずつ読み込み、ハッシュ値を更新
        while ((bytesCount = fis.read(byteArray)) != -1) {
            digest.update(byteArray, 0, bytesCount);
        }
        
        fis.close();

        // 計算したハッシュ値を16進数文字列に変換
        StringBuilder sb = new StringBuilder();
        for (byte b : digest.digest()) {
            sb.append(String.format("%02x", b));
        }
        
        return sb.toString();
    }
    
    public static void main(String[] args) {
        try {
            // 画像ファイルのパスを指定
            String hash = calculateHash("/Users/xxxx/sample.png");  // 存在するパスを指定すること
            System.out.println("Hash: " + hash);
        } catch (NoSuchAlgorithmException | IOException e) {
            e.printStackTrace();
        }
    }
}
```
:::note warn
・サンプルコード中のファイルパス（例: /Users/xxxx/sample.png）は、この記事用の例です。
・自分の環境に存在する画像ファイルのパスに置き換えてください。
:::
## 3. コードの説明

### 1. `MessageDigest`の利用
- `MessageDigest`クラスは、Java標準ライブラリで提供されるハッシュアルゴリズムを実装するクラスです。
- ここでは、SHA-256アルゴリズムを指定しています。

```java
MessageDigest digest = MessageDigest.getInstance("SHA-256");
```

### 2. ファイルの読み込みとハッシュ化
- 画像データを1024バイトずつ読み込み、`digest.update()`を使ってハッシュを更新しています。
- この方法は、大きなファイルでも効率的に処理できます。

```java
while ((bytesCount = fis.read(byteArray)) != -1) {
    digest.update(byteArray, 0, bytesCount);
}
```
### 3. ハッシュ値を16進数文字列へ変換
- `digest.digest()`メソッドで計算結果を取得し、16進数形式で表示します。

```java
StringBuilder sb = new StringBuilder();
for (byte b : digest.digest()) {
    sb.append(String.format("%02x", b));
}
```

## 4. 実行方法

1. 上記のコードをImageHash.javaという名前で保存する。
2. ターミナルやコマンドプロンプトを開き、ファイルが保存されているディレクトリに移動する。
3. 以下のコマンドを実行して、プログラムをコンパイル・実行する。

```bash
javac ImageHash.java
java ImageHash
```

出力例：
![スクリーンショット 2024-11-16 15.20.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762672/5a0edf36-c305-fffe-c44a-f6680f96d3e7.png)

## 5. おわりに
今回の記事では、Javaを使った画像データのハッシュ値算出方法について紹介しました。
ハッシュ値の利用は、セキュリティやデータ管理において非常に重要ですので、参考になったら嬉しいです。
Rを学びたい Step9 基本操作

## はじめに
Rを学びたいStep9です。基本操作を学んでいきたいと思います！！
色々いじってどんな事ができるかわかってきたので、一旦ここで基本操作を学んでいこうと思います。


## ソースコード

```R:
# 必要なパッケージをロード
library(quantmod)

# フォント設定
par(family = "Hiragino Sans")  # macOS用日本語フォント

# トヨタ自動車（7203.T）のデータを取得
symbol <- "7203.T"
getSymbols(symbol, src = "yahoo", from = "2023-01-01")

# 移動平均線を計算
data <- get(symbol)
```

```R:実行結果
[1] "7203.T"
           7203.T.Open 7203.T.High 7203.T.Low 7203.T.Close 7203.T.Volume
2023-01-04      1798.0      1804.0     1787.5       1799.0      25995600
2023-01-05      1812.0      1819.5     1793.5       1807.5      24700200
2023-01-06      1809.5      1829.0     1806.0       1825.0      22568600
2023-01-10      1837.5      1850.0     1821.5       1827.0      22352300
2023-01-11      1824.0      1840.0     1822.0       1837.5      19798400
2023-01-12      1839.0      1868.0     1838.0       1857.5      21573200
           7203.T.Adjusted
2023-01-04        1700.032
2023-01-05        1708.064
2023-01-06        1724.602
2023-01-10        1726.492
2023-01-11        1736.414
2023-01-12        1755.314
```

### head
上からいくつか抽出して表示する。

```R
head(data) # デフォルトで6つ
head(data, n = 3) # デフォルトで3つ
```

### tail
したからいくつか抽出して表示する。
```R
tail(data) # デフォルトで6つ
tail(data, n = 3) # デフォルトで3つ
```

### str(data) 
dataのデータ構造を表示する。
```R
str(data)
```
自分なりのVite x React環境構築テンプレート

## 概要
- Reactで開発するときに、簡単に環境構築できるように流れも含めてまとめる

## 導入コマンド
```bash
# Reactのインストール
npm create vite@latest

# tsconfigのエラー解消用
npm install -D @types/node
npm install vite-plugin-dts

# tailwindcssを使う場合
npm install -D tailwindcss postcss autoprefixer
npm install tailwind-merge  # クラス名の結合用
npm install class-variance-authority  # バリアントの管理用
npx tailwindcss init -p
```

## tailwindcssの反映
```css:index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
```
こちらを追記する。場合によっては既存のcssはすべて破棄するとよい。

## エイリアスを設定する

エイリアスを設定すると、ファイルを移動してもある種絶対パスで指定することができるので多少変更が楽になる。
さらに細かくプレフィックスを作成しておくと、大きな変更がある場合に楽になるので、`components`配下などで大別する場合などは設定するとよい。
```ts:vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import { resolve } from 'path';
import dts from 'vite-plugin-dts';

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    react(),
    dts({
      insertTypesEntry: true,// 型定義ファイルの生成
    }),
  ],
  resolve: {
    alias: {
      '@': resolve(__dirname, './src'),
    },
  },
});
```

## tsconfig.app.jsonのエラーの解決とviteのエラーの解決

```json:tsconfig.app.json
{
  "compilerOptions": {
    "incremental": true, /* ファイル差分でコンパイルするようになる */
    /* "composite": true,  ものレポの場合はこっちをつける */
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "Bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    /* 自動生成されるものの、エラーが出るので削除する。(拡張機能で対応しているし、、)
       import時にそのライブラリが本当に存在するか探してくれるもの */
    /*"noUncheckedSideEffectImports": true,*/

    /* vite.config.ts のエラー解決 */
    "types": ["node"],
    "baseUrl": "./", /* エイリアスを設定する */
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "include": ["src"]
}
```

## tsconfig.node.json

:::note info
エラー内容はほぼ同じなので省略する。
:::
キャッシュがざっくりわかる

## はじめに

キャッシュについてザックリ理解することを目的に書いています。

## キャッシュの目的
**キャッシュはデータを高速に取得する**ことを目的としており、計算やデータベースの問い合わせなどのコストのかかる処理を減らすことにあります。特に同じデータを複数回取得するとき、キャッシュを利用することでリソースの消費を抑えられます。


:::note warn
**大前提、データベースから情報を持ってきたり、計算したり、Webページを生成したりするのには多かれ少なかれ時間がかかります。**
:::

高速化は**一度取得したデータを一時的に保存し、次回のリクエスト時に再利用することによって実現します。**


## キャッシュの種類
キャッシュには**ブラウザキャッシュ**や**サーバーキャッシュ**など色々と種類があります。

ブラウザキャッシュとは、訪問済みのWebサイトのHTML、CSSなどの情報をクライアント側に保存する機能のことです。

キャッシュのストレージ（保存場所）にもいくつか種類があり、
- メモリキャッシュ（インスタンス変数など）
- 外部キャッシュシステム
- ディスクキャッシュ
- データベースキャッシュ

などがあります。

## キャッシュの弊害
キャッシュはデータ取得を高速にしてくれるメリットがありますが、**更新したはずの情報が反映されていない！** というときは、クライアント側に保存された**古いキャッシュ**が悪さをしている可能性があります。

いくら高速になるからと言っても、ずっと古い情報にアクセスさせ続けてしまうのは、たまったもんじゃないですね。

Web開発者は、キャッシュが長期間保存されないようにHTTPヘッダーやクエリパラメータを設定したり、保存期間を設けるなどして適切にキャッシュを管理する必要があります。

## いったんまとめ
色々種類があるんだなぁという感じですが、一先ず

:::note info
**キャッシュはデータの取得を高速にするための仕組み**です！
:::


## キャッシュの仕組みをイメージする
今回はローカルメモリキャッシュ（アプリケーション単位でのキャッシュ）を使って、キャッシュの仕組みのイメージをつけます。

```ruby
class CacheExample
  def initialize
    @cache = nil
  end

  def calculation
    # ここで重い計算を行う
    print "計算中..."
    42  # 計算結果（今回は単純に 42 を返す）
  end

  def result
    # キャッシュされていない場合に計算を実行し、その結果をキャッシュ
    @cache ||= calculation
  end
end

cache_example = CacheExample.new
puts cache_example.result  # 計算中... 42 が表示され、結果がキャッシュされる
puts cache_example.result  # 計算は行わず、キャッシュされた値 42 が表示される

another =  CacheExample.new # 一応他のインスタンスも作成
puts another.result # 計算中... 42 が表示され、結果がキャッシュされる
puts another.result # 計算は行わず、キャッシュされた値 42 が表示される
```
肝はこの部分ですね。
```ruby
@cache ||= calculation
```
キャッシュがあるならそれを出す、ないなら計算！

## さいごに
### 僕なりの解釈
キャッシュについて調べてるうちにバイト時代を思い出したので、上手いか下手かはさておき、たとえ話をします。（画像は生成AIに作ってもらいました）

バイト時代の話ですが、普通の注文から提供までの流れは

    レジに来る→注文をとる→お会計→作成する→提供する
    
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3924509/c5c34640-efce-2b19-fd11-c4131fb15efc.png)



ですが、毎回同じ注文をするお客さん、つまり常連さんも結構いました。
正直、毎回常連さんに丁寧に注文を聞くのは無駄です。なので常連さんには

    レジに来る→お会計&作成&提供


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3924509/0a60edd2-dae8-a164-8103-891f6703657d.png)

みたいな対応が好ましいですよね。

**圧倒的に時短**になりますし、**お客さんとしても待つ時間が少なくて嬉しい！** って感じです。

ただ一応、新作が出来た時には、とりあえず注文を聞いたりします。常連さんも毎回当たり前のように「いつもの」を出されたら新作試せないですしね。
僕たちの小さな親切のせいで、お客さんが本当に欲しいものを提供できないのは本末転倒です。

こんな感じで、知っているものはすぐに出してあげる仕組みや、古い情報が悪さをする可能性があることがキャッシュに近いなと思いました。

最後までお読みいただきありがとうございました！！

## 参考文献

https://zenn.dev/msy/articles/e81ff7cd52659a

https://qiita.com/sakashin10291029/items/053f1ed144edd9116d3e
Open3D で Voxel する

# Open3D の点群を Voxel にする

Voxel はいわゆるマイクラみたいな感じです！

## まずは普通に読み込み

```py
import open3d as o3d
import numpy as np

pcd = o3d.io.read_point_cloud("vase.xyz")
o3d.visualization.draw_geometries([pcd])
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33095/692804d6-d2f6-bc9f-025c-c86c1bd6533f.png)

## Voxel 化してみる

```py
import open3d as o3d
import numpy as np

pcd = o3d.io.read_point_cloud("vase.xyz")

voxel = o3d.geometry.VoxelGrid.create_from_point_cloud(pcd, 0.15)
o3d.visualization.draw_geometries([voxel])
```

お？黒い？？ボクセル化してるっぽいけど真っ黒でよくわかりません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33095/f3f19e59-c6f1-3094-d071-10f3658439c3.png)

## 色を付ける

```py
# Voxel

import open3d as o3d
import numpy as np

pcd = o3d.io.read_point_cloud("vase.xyz")

xyz = np.asarray(pcd.points)
o = 2
c_min, c_max = np.min(xyz[:,o]), np.max(xyz[:,o])
if abs(c_min) < abs(c_max):
    max = abs(c_max)
else:
    max = abs(c_min)
pcd.colors = o3d.utility.Vector3dVector( [np.ones(3) * (abs(z)/max) for z in xyz[:,o]] )

voxel = o3d.geometry.VoxelGrid.create_from_point_cloud(pcd, 0.15)
o3d.visualization.draw_geometries([voxel])
```

Z軸をもとにグレイスケールで色をつけてみる。
ボクセル化されてる！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33095/bdc5b9a9-655d-1f1f-cad0-5907d3242d2e.png)

## 座標を取り出す

```py
voxel = o3d.geometry.VoxelGrid.create_from_point_cloud(pcd, 0.15)

voxels = voxel.get_voxels()
print(voxels[0].grid_index)
print(voxels[0].color)

voxels_b = voxel.get_voxel_bounding_points([4,0,1])
print(np.asarray(voxels_b))
```

ボクセル化しておわりともいかないので座標を取り出す方法。

`get_voxels()` でボクセルの情報が取り出せます。
`grid_index` で座標がとりだせます。座標と言うかグリッド（方眼紙）の位置というか。
`color` ではそこの色がとりだせます。

```text
# voxels[0].grid_index
[4 0 1]

# voxels[0].color
[0.21738366 0.21738366 0.21738366]
```

`get_voxel_bounding_points()` で実際の座標が取り出せます。
いわゆるキューブ（立方体・サイコロ）なので8点の座標がとりだせます。

`grid_index` と `get_voxel_bounding_points` を組み合わせることでボクセル化した座標が全て取り出せるので活用範囲が広がります！

```text
# voxel.get_voxel_bounding_points([4,0,1])
[[ 0.525 -0.075  0.075]
 [ 0.525 -0.075  0.225]
 [ 0.675 -0.075  0.075]
 [ 0.675 -0.075  0.225]
 [ 0.525  0.075  0.075]
 [ 0.525  0.075  0.225]
 [ 0.675  0.075  0.075]
 [ 0.675  0.075  0.225]]
 ```
cscの作法 その534

# 概要
cscの作法、調べてみた。
練習問題やってみた。

# 練習問題
wpfを1ファイルで書け。

# 方針
- xamlを使わない。


# サンプルコード

```

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;


class Wpf {
	[STAThread]
	public static void Main() {
		Application app = new Application();
		Window wnd = new Window();
		Canvas cnvs = new Canvas();
		Button button1 = new Button();
		TextBlock txt1 = new TextBlock();

		txt1.FontSize = 14;
		txt1.Text = "Hello World!";
		Canvas.SetTop(txt1, 100);
		Canvas.SetLeft(txt1, 10);
		cnvs.Children.Add(txt1);
		wnd.Title = "Wpf";
		wnd.Width = 400;
		wnd.Height = 400;
		button1.Content = "test";
		Canvas.SetLeft(button1, 50);
		Canvas.SetTop(button1, 50);
		button1.Click += (sender, e) => {
			MessageBox.Show("hello, world");
		};
		cnvs.Children.Add(button1);
		wnd.Content = cnvs;
		app.Run(wnd);
	}
}





```

# 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/ba20ab28-b691-2634-9b94-7f7c24ba1a41.png)


以上。
ランダム線形分類機

ランダムフォレストは決定木についてバギングを行っている。
そこで線形モデルをバギングしたらどうなるのかやってみた。
# ライブラリ
```Python3
from sklearn.datasets import make_blobs
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression as LR
from sklearn.ensemble import BaggingClassifier
import numpy as np
import matplotlib.pyplot as plt
```

# データのロード
```Python3
x, y = make_blobs(n_samples=300, centers=4, random_state=0, cluster_std=1.0)
plt.scatter(x[:, 0], x[:, 1], c=y, cmap="brg")
plt.show()
```

# 決定境界描画
```Python3
def visualize_classifier(model, X, y, ax=None, cmap='brg'):
    ax = ax or plt.gca()
    
    # Plot the training points
    ax.scatter(X[:, 0], X[:, 1], c=y, s=30, cmap=cmap,
               clim=(y.min(), y.max()), zorder=3)
    ax.axis('tight')
    ax.axis('off')
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()
    
    # fit the estimator
    model.fit(X, y)
    xx, yy = np.meshgrid(np.linspace(*xlim, num=200),
                         np.linspace(*ylim, num=200))
    Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)

    # Create a color plot with the results
    n_classes = len(np.unique(y))
    contours = ax.contourf(xx, yy, Z, alpha=0.3,
                           levels=np.arange(n_classes + 1) - 0.5,
                           cmap=cmap, clim=(y.min(), y.max()),
                           zorder=1)

    ax.set(xlim=xlim, ylim=ylim)
```
# SVM
```Python3
visualize_classifier(SVC(kernel="linear"), x, y, ax=None, cmap='brg')
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/25add6af-439d-8589-7172-0d7c82004381.png)



# ランダムSVM
```Python3
visualize_classifier(BaggingClassifier(estimator=SVC(kernel="linear"), n_estimators=500), x, y, ax=None, cmap='brg')
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/ec51a17c-2ef2-bad3-6561-ea87854166e3.png)

ランダムSVMの方が直線的ですね。普通のSVMは真ん中のところが少し角になっています。

# Logit
```Python3
visualize_classifier(LR(), x, y, ax=None, cmap='brg')
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/8b1c1c1d-7397-db24-ffc3-d20e8f5fb249.png)

# ランダムLogit
```Python3
visualize_classifier(BaggingClassifier(estimator=LR(), n_estimators=500), x, y, ax=None, cmap='brg')
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/37d34bb3-325e-0495-8348-e3326127d45b.png)
ロジスティック回帰はあんまり変わらないですね。
『ユーザーのための要件定義ガイド第２版』第1章

# 導入

[ユーザーのための要件定義ガイド](https://www.ipa.go.jp/archive/publish/qv6pgp0000000wrt-att/000079352.pdf)

情報技術者試験を主催するIPAが公開している要件定義についての資料。

「ユーザーのための」とあるようにシステム開発を依頼する側に必要な視点だが、ユーザーはそもそもそういう考えに至らない可能性も高いので開発者側も知っておく方が良い。

図など込みで7章に分けて500ぺージ近い資料があるので1章ずつすごく雑に要約していく。


# 本題


## はじめに
ITシステムを作る上で経営層が上流工程に関わることが大事。
###### ざっくり2分野
・基幹業務に関わる
「守りの分野」…レガシー化して面倒

・AIなど新技術
「攻めの分野」…開発中に新しい要求が増えやすいパターンに陥る


###### レガシー化したシステムを再構築
DXを進めるうえで既存のシステムが足かせになりうる


本書は、『システム再構築を成功に導くユーザガイド』と合わせて以下2点に強く関連する内容
「デジタル時代に対応した新たなビジネスモデルの構築」
「DX 実現を困難にしている既存 IT システムの再構築」


## 1章　背景
### システム開発の現状
ITシステムの変遷は下のような流れ
導入 → 置き換え → 効率化 → 競争力強化

###### 今は「競争力強化ステージ」
「デジタル時代に対応した新たなビジネス・モデルの構築と価値の創造」
「DX 実現を困難にしている既存 IT システムの再構築」
をする必要がある

### 既存システムの現状
8割強の企業が老朽化したシステムを抱えていると言われている。
既存システムの中身はブラックボックスになりがち。

運用保守に資金と人材が割かれる

###### 開発の実態
納期遅延・品質満足度が低い
2018年度、500人月以上の大規模システム開発で
43.9% が「予定より遅延した」
23.8% は経営者がシステム品質に不満を持っている

###### 工期遅延の理由
アンケート結果：50%以上が要件定義の問題。

IPA「要件定義は発注者の責任である」
経済産業省「要件定義は準委任契約にすることと述べられて
いる。」

[請負契約と準委任契約の違いとは](https://www.businesslawyers.jp/practices/669)

ユーザーはベンダに丸投げしないでね、ということ

今あるシステム理解して再構築が大変
局所的に入れた連携の取れていないもの(個別サイロ型システム)まで統合しようとすると大変

・構造的な問題
日本は予算が低めで外部のSEに委託
アメリカは予算をしっかり割いて社内にもSEがいる

### DXに見える今後求められるシステム開発
インターネットの発展でサービスの対象者が大幅に増える
データ量も膨大になる(ビッグデータ)

「デジタル時代に対応した新たなビジネスモデルの構築」は特に重要
機能の差別化はすぐ陳腐化するからUI,UXが大事
ビジネス価値の創出のために、どのようなデータをどのように活用するか
単に集めただけだと意味がない("沼")

###### リーンスタートアップ、アジャイル開発
要件定義が変化する可能性もあるので、開発の仕方も大事

☆要件定義は普遍
ここまでをまとめたものは既存の要件定義で重要なものと同一

・お客様が本当に欲しい価値は何なのか
・お客様のエクスペリエンスとは何なのか
・ビジネスにどういう価値を作るのか
・ビジネス・モデルを変えるために、データをどのように活用すれば良いのか
・デジタル技術を用いて、どのように価値創出に貢献できるのか


☆ブラックボックス化した既存システムの刷新が大変
自社の情報資産を正確に把握できていないことが一因。
評価するための項目は以下

・既存システムの調査・分析
・情報資産の仕分（機能分割・刷新、機能追加、機能縮小・廃棄、現状維持（塩漬け）な
ど）
・再構築目的やビジネスリスクの明確化
・再構築手法の選択、再構築リスクの明確化
・現行業務知識不足への対応
・品質保証（業務継続性の担


## 要件定義をめぐる環境の変化
### 要件定義に求められる 3 つのこと
【請負】瑕疵担保責任の改正
【請負】プロジェクトがとん挫した場合でも報酬請求が可能に
【準委任】成果完成型の準委任契約が認められた

「瑕疵」＝プログラムのバグ
「契約の内容に適合しない仕事の目的物」に変わった
やりたい事できてるならいいよね？ということ

バグがあってもいいではなく「目的」の部分をはっきりさせておきましょう


いざ要件定義を終えてみると当初の狙いが達成できていない要件定義になっていることがある。
経営層や業務部門との合意形成や積極的な経営層、業務部門の参画などが要件定義には求められる。

要求仕様の決定や漏れが一番多い。
手戻り負荷は、発覚が遅ければ遅いほど指数的に大きくなると言われている。


### パラダイムシフト
昨今は、クラウドやマイクロサービスなどの普及により、システム構築はサービスを組み
合わせて作るものになってきている。


### 重要度が上がる非機能要求
デザインとかセキュリティとか
機能による差別化が難しくなってきたことが理由

IPA は「非機能要求グレード」を公開している 


### ますます難しくなってきている要件定義
1章の総括
再構築って大変
現状の可視化と理解、変える/変えないの判断を工夫しよう

その機能本当に必要？
分からないことがあるからアジャイル開発とかを前提に見極めるための仕組みを考えよう

アイデア創出
ビジネスモデルの話、UXなどの非機能要求


かなり雑にまとめると
「ベンダーにお任せじゃなくてユーザーも考えましょう」
VSCodeにおけるPythonのLinterとFormatterの設定を整理してみた

# はじめに
VSCodeにおけるPythonのLinterとFormatterの設定を整理しました。
ここでは設定に着目し、導入手順は[【Ruby,Python初学者必見】LinterとFormatterは必ず入れましょう](https://qiita.com/rys0707/items/0b0ed63f9b266bc1358b)などをご参照ください。

# 結論
Linterはflake8、FormatterはBlackとisortを使う。

# Linter
[Black 24.8.0 documentation](https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html#profile)に従う。
flake8は一行の文字数がデフォルトで79字となるが、githubのコードレビュー画面の幅と合わせて119字とする。extend-ignoreを記述することで、以下の警告を避け、Blackとの競合を回避する。
- E203 は、スライス演算子 (:) の前に空白がある場合に警告を出す
例: x[1 : 5]
- E701 は、1行に複数のステートメントがある場合に警告を出す
例: if x == 1: print("OK")

以上より、以下の設定ファイルをプロジェクト直下に配置する。
```.flake8
[flake8]
max-line-length = 119
extend-ignore = E203,E701
```
# Formatter
[Black 24.8.0 documentation](https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html#profile)に従う。
Blackは一行の文字数がデフォルトで88字、isortは79字となるが、githubのコードレビュー画面の幅と合わせて119字とする。isortのセクションにprofile="black"と記述することで、Blackとの競合を回避する。これで回避項目をまとめて設定できるが、カスタムで設定したい場合はドキュメントを参照。
以上より、以下の設定ファイルをプロジェクト直下に配置する。

```pyproject.toml
[tool.black]
line_length = 119

[tool.isort]
profile = "black"
line_length = 119
```
[VSCodeのMarketplace](https://marketplace.visualstudio.com/items?itemName=ms-python.flake8)に従う。
- "pylint.enabled": false
pylintを無効化し競合を回避

- "editor.defaultFormatter": "ms-python.black-formatter"
Blackをデフォルトにする

- "editor.formatOnSave": true
- "editor.codeActionsOnSave": { "source.organizeImports": "explicit" }
自動保存

- "flake8.args": ["--config=.flake8"]
- "black-formatter.args": ["--config", "pyproject.toml"]
設定ファイルの読み込み

- "isort.args": ["--profile", "black"]
Blackとの競合回避

以上より、以下の設定をsettings.jsonに記述する。
```settings.json
 "pylint.enabled": false,
  "[python]": {
    "editor.defaultFormatter": "ms-python.black-formatter",
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
      "source.organizeImports": "explicit"
    }
  },
  "flake8.args": ["--config=.flake8"],
  "black-formatter.args": ["--config", "pyproject.toml"],
  "isort.args": ["--profile", "black"],
```

# おわりに
色々と競合が発生する箇所なので不具合ありましたら適宜更新します。

# 参考文献
- [【Ruby,Python初学者必見】LinterとFormatterは必ず入れましょう](https://qiita.com/rys0707/items/0b0ed63f9b266bc1358b)
- [Pythonのコードフォーマッターについての個人的ベストプラクティス](https://qiita.com/sin9270/items/85e2dab4c0144c79987d)
- [Black 24.8.0 documentation](https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html#profile)
- [Flake8](https://marketplace.visualstudio.com/items?itemName=ms-python.flake8)
- [Black Formatter](https://marketplace.visualstudio.com/items?itemName=ms-python.black-formatter)
- [isort](https://marketplace.visualstudio.com/items?itemName=ms-python.isort)
macOSでrubyのversionが反映されない！？macOSにrubyを入れる時に注意すること

# はじめに
今回は私がrubyの環境構築時に陥った知っていないとハマってしまうmacOSの罠について説明したいと思います。

>   ### 私の環境
> Model Name: MacBook Air
Model Identifier: Mac14,2
      Model Number: Z161003XUJ/A
      Chip: Apple M2

[Homebrew](https://brew.sh/)を用いて環境構築している前提で話していきます。
解決方法だけみたいときは[こちら]()

# 今回陥った罠
```
ruby -v
```
でrubyのversionを確認したところ
```
ruby 2.6.10p210 (2022-04-12 revision 67958) [universal.arm64e-darwin24]
```
となっておりその頃の日付は2024だったため、古いversionだなと思い、いつも通り
```
brew install ruby
```
としてrubyを最新状態にしようと思いました。
しかし、この後
```
ruby -v
```
でrubyのversionを確認したところ
```
ruby 2.6.10p210 (2022-04-12 revision 67958) [universal.arm64e-darwin24]
```
と変更されていなかったのです。

## 原因
これの原因は
```
which ruby
```
をすればわかります。
このコマンドはrubyの環境のPATHを教えてくれるものです。
これで帰ってきた値は` /usr/bin/ruby `
とhomebrewの下ではなかったのです。

::: note info

homebrewでinstallしたものは
`
/opt/homebrew/opt/◯◯
`となる

:::

これはmacOSでは購入時にrubyがinstallされているのですが、それのPATHが`/usr/bin/ruby`にあるからです。

#　解決方法
## 問題
今回の問題がmacOSにプリインストールされているシステムRubyは`/usr/bin/ruby`にある

## 解決
PATHを正しく設定する
```
echo 'export PATH="/opt/homebrew/opt/ruby/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
```

# 最後に
今回はわたしの理解度が低いために起こってしまった失敗談です。しかし、プログラミングを初めて触る方も陥ってしまうのではないかと思い共有しました。.rbenvやdockerなどは学んでみるといいですね
それではみなさん、良いエンジニアライフを〜👋
SQLパズル マイルストーン　25 その4　解法メモ

# 概要

SQLパズル　p110 マイルストーン　25 その4
CASE式とGROUP BY 極値関数の組み合わせで　列→行変換しています。


# 要件

スケジュールの進行状態を1行で表現したい。
※元々は列になっている

2列目：進行中
3列目：完了
4列目：確認


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/fb0f74a5-5f5e-9fdb-ab35-e5b3386c88b6.png)


# SQL

## DDL

```sql
drop table if EXISTS ServicesSchedule;
Create table ServicesSchedule(
    shop_id char(3) not null,
    order_nbr char(10) Not Null,
    sch_seq char(10) not null,
    service_type char(2) not null,
    sch_date Date,
    primary key(shop_id, order_nbr, sch_seq));
INSERT INTO ServicesSchedule VALUES('002',   '4155526710',   1,   '01', '1994-07-16' );
INSERT INTO ServicesSchedule VALUES('002',   '4155526710',   2,   '01', '1994-07-30' ); 
INSERT INTO ServicesSchedule VALUES('002',   '4155526710',   3,   '01', '1994-10-01' );
INSERT INTO ServicesSchedule VALUES('002',   '4155526711',   1,   '01', '1994-07-16' ); 
INSERT INTO ServicesSchedule VALUES('002',   '4155526711',   2,   '01', '1994-07-30' ); 
INSERT INTO ServicesSchedule VALUES('002',   '4155526711',   3,   '01',  NULL ); 
```



## 答えのSQL

```sql
-- 25 マイルストーン　p110
-- CASE式とGROUP BY 極値関数の組み合わせで、列→行　変換
-- MAXを使うことによって部分集合からnullじゃない値を取得できる
SELECT order_nbr,
	MAX(CASE WHEN sch_seq = '1'
		THEN sch_date
		ELSE NULL END) AS processed,
	MAX(CASE WHEN sch_seq ='2'
		THEN sch_date
		ELSE NULL END) AS completd,
	MAX(CASE WHEN sch_seq ='3'
		THEN sch_date
		ELSE NULL END) AS confirmed
FROM ServicesSchedule
WHERE service_type = '01'
AND order_nbr = '4155526710'
GROUP BY order_nbr
;

-- GROUP BY が無い場合
SELECT order_nbr,
	(CASE WHEN sch_seq = '1'
		THEN sch_date
		ELSE NULL END) AS processed,
	(CASE WHEN sch_seq ='2'
		THEN sch_date
		ELSE NULL END) AS completd,
	(CASE WHEN sch_seq ='3'
		THEN sch_date
		ELSE NULL END) AS confirmed
FROM ServicesSchedule
WHERE service_type = '01'
AND order_nbr = '4155526710'
;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/64f69197-cc0b-b50b-5e50-d794ad232344.png)



# 参考

SQLパズル　p110 マイルストーン　25 その4

SQLパズル　サポートページ
https://mickindex.sakura.ne.jp/database/db_support_sqlpuzzle.html#LocalLink-p25

達人に学ぶSQL徹底指南書第２版　p8 異なる条件の集計を1つのSQLで行う　CASE式　行→列に変換

github 差分
https://github.com/RYA234/SQL_Puzzle_Learning/commit/68a02686293fa7f2ded284b2ddc27ee824869daf
【読書メモ】Geminiから最高の回答を得る！プロンプト設計の基本と応用例

### はじめに
GeminiなどのAIを最大限に活用するには、プロンプトの設計がカギです。

本記事では、基本的な設計の4つの要素と、さらに精度を上げるテクニックを具体例とともに紹介します。
プロンプト次第でAIの出力の質が大きく変わるため、ぜひ参考にしてみてください。

---

### プロンプト設計の基本4要素
1. **ペルソナ**: Geminiの視点や立場を設定する  
2. **タスク**: 明確に何をして欲しいか指示する  
3. **コンテキスト**: 背景や状況を詳しく伝える  
4. **フォーマット**: 出力形式や例を提示する  

---

### レベルアップのためのプロンプト改善ポイント
- 言い回しを工夫し、異なる表現で試す  
- Geminiの回答にフィードバックを与え、改善を促す  
- 簡潔なプロンプトを心がける  
- 必要に応じて参考情報を提示する  
- Geminiに「足りない点がないか」質問することで抜け漏れを防ぐ  
- 問題を分割して段階的に回答を得る  

---

### 活用例: プレゼン資料作成
**プロンプト例**:  
あなたは、企業のデジタル化推進担当で、最近話題のデジタルトランスフォーメーションの必要性に関する資料を作成しています。  
「デジタルトランスフォーメーションが企業にもたらす利点」というテーマで10枚のスライド構成を考えてください。  
各スライドのタイトルと箇条書きで3～4つの要素を提案して。  
対象はIT知識が豊富ではない経営者層です。最後に、インパクトのある結論スライドを含めてください。  

**出力例**:  
1. **スライド1: デジタルトランスフォーメーションの概要**  
   - 定義とは何か  
   - 重要性と背景  

2. **スライド2: DXが企業にもたらす主な利点**  
   - 業務効率化  
   - 顧客体験の向上  
   - コスト削減  

(以下省略)

---

### 感想・活用方法
- **感想**: プロンプト設計の重要性と、それを工夫することでAIの能力を最大限に引き出せることが印象的でした。特に「足りない点をAIに確認する」というアプローチが新鮮で、改善のヒントを得られる点が優れていると感じました。  
- **活用方法**: 自分が扱う業務で、特定の状況を想定したペルソナ設定を試しながら、段階的にタスクを分割して成果物を作り上げていきたいです。また、学んだ内容をチームで共有してプロンプト設計力を向上させる取り組みを進めたいです。

#### Qiita向けの追加補足
深津式プロンプトの活用例：  
- 業務改善: 問題分解の手法を用いて、複雑なタスクを段階的にAIで解決  
- 教育: チームメンバーがAIを使いこなすためのトレーニング用プロンプト例を設計  
- 資料作成: Geminiを活用した柔軟なアウトプット生成方法を記事化し、読者にシェア  

---

### タグ候補
- `AI活用`  
- `プロンプトエンジニアリング`  
- `Gemini`  
- `生成AI`
[SEO対策]HTMLタグの使い方一つにも色々あるよって話。

模写コーディングをやっている最中、新しい学びがあったので。
特に一番最初の学習をprogateでやった人は陥りがちなポイントかも知れないのでぜひ読んでいだたければ。

## そもそもSEOとは？
検索エンジン最適化、なんて言葉で言うそうですが、
簡単に言えば｢**いかにGoogle先生に見つけてもらいやすくするか**｣です。
どんなに良いデザインのサービスもサイトも、見つけてもらえないと意味がない。
一人でも多くのユーザーにサイトを訪れてもらうため、こういった工夫がなされているわけです。

## タグ分けしたほうが良いものとその例
適切なHTMLタグを使用することで、検索エンジンがコンテンツを理解しやすくなります。以下はSEOに役立つタグとその例です。

### `<section>`タグ
Webページの内容を論理的に区分するためのタグ。
大まかな章分けをする際に使用する。
```html
<section>
  <h2>サービス概要</h2>
  <p>私たちのサービスは…</p>
</section>
```

### `<dl>,<dt>,<dd>`タグ
定義リストを表すタグ。
用語や説明をわかりやすく整理できるのでFAQや製品仕様などに役立つ。
```html
<dl>
  <dt>Web開発</dt>
  <dd>Webサイトやアプリケーションを作成するプロセス。</dd>
</dl>
```

### `<article>`タグ
独立したコンテンツを示すタグ。
ブログ記事やニュース記事の個別のページに設定するのに適している。
```html
<article>
  <h2>最新のテクノロジー</h2>
  <p>最近の技術進歩について…</p>
</article>
```

## `<div>`タグを使ったほうが良いケース
`<div>`タグは特別な意味を持たないため、単純にコンテンツをまとめるために使います。
単に複数の要素をグループ化してCSSでデザインを調整する際に便利です。

### 使用例
```html
<div class="container">
  <div class="row">
    <div class="column">内容1</div>
    <div class="column">内容2</div>
  </div>
</div>
```

**ポイント**: 他のタグ（`<section>`や`<article>`など）は特定の意味を持ち、検索エンジンが内容を理解しやすくします。一方、`<div>`タグは意味を持たないため、デザインを整えるときや要素を単にグループ化するときに使うのが適しています。

### まとめ
progateで僕は最初HTMLやCSSのインプットをしたわけですが、基本的に全部divタグで書く事が多かったのでその存在すら知りませんでした。
実際すべて`<div>`タグで書いても同じ見た目のものはできるのでしょうが、得られる訪問者などには差が生じるのでしょう。

模写コーディングはもちろん、実務でも当然使う機会が多いと思われるので少しでも役に立てば。
【Java初心者】equalsメソッドでオブジェクトの中身を比較する

## はじめに
SpringBootでアプリ開発をしている中で、更新前後のオブジェクトの内容を比較し、差異がある場合だけUPDATE処理を実行する、ということをしたかったのですが、equalsメソッドをそのまま使ってもうまくいかなかったのでオーバーライドの方法を残しておきます。

## やりたいこと

手軽にオブジェクトの中身の比較をして、差異がある場合だけ処理を実装するような条件分岐をしたい

### 

## エラー内容

エラーはでないが、期待した処理をしない

```java
    // 問題の処理
    if (!modifiedStudent.equals(currentStudent)) {
      studentRepository.updateStudent(modifiedStudent);
    }
    
    
    // 参考：updatteStudentメソッドの内容
      @Update(
      "UPDATE students SET full_name = #{student.fullName}, kana = #{student.kana}, nick_name = #{student.nickName}, email = #{student.email}, city = #{student.city}, age = #{student.age}, gender = #{student.gender}, remark = #{student.remark} "
          + "WHERE id = #{student.id}"
        )
		  void updateStudent(@Param("student") Student student);
```

## 原因

- equalsメソッドがオーバーライドされていない
    - equalsメソッドの実装
        
        ```java
          public boolean equals(Object obj) {
                return (this == obj);
        ```
        
    - equalsメソッドの機能
        - equalsを呼び出したインスタンスと、引数として渡すobjが実体として同じかを確認している
        - 実体として同じであるということ
            - 全く同じインスタンスであるということ
            - フィールドの内容が全く同じであっても、別のオブジェクトとしてインスタンス化されていれば、別のインスタンスとして評価される
                
                ```java
                Student student1 = new Student();
                Student student2 = new Student();
                
                System.out.println(student1.equals(student2)); // false
                System.out.println(student1.equals(student1)); // true
                ```
                
    - デフォルトのオーバーライド機能を使うと、以下のif文は常にfalseを返す
        
        ```java
            if (modifiedStudent.equals(currentStudent)) {
              ...
            }
        
        ```
        

## 解決策

- equalsメソッドをオーバーライドする
    
    ```java
    public class Student {
    
      private String id;
      private String fullName;
      private String kana;
      private String nickName;
      private String email;
      private String city;
      private int age;
      private Gender gender;
      private String remark;
      private Boolean isDeleted;
    
      @Override
      public boolean equals(Object o) {
        if (this == o) {
          return true;
        }
        if (o == null || getClass() != o.getClass()) {
          return false;
        }
        Student student = (Student) o;
        return age == student.age && Objects.equals(id, student.id) && Objects.equals(
            fullName, student.fullName) && Objects.equals(kana, student.kana)
            && Objects.equals(nickName, student.nickName) && Objects.equals(email,
            student.email) && Objects.equals(city, student.city) && gender == student.gender
            && Objects.equals(remark, student.remark) && Objects.equals(isDeleted,
            student.isDeleted);
      }
    ```
    
    - なにをしているのか
        - equalsを呼び出したインスタンスと引数にとったオブジェクトについて以下を返す
            - 実体として同じであればtrue
            - nullまたは違うクラスのインスタンスであればfalse
            - フィールドの値がどこかしら異なればfalse
            - フィールドの値が完全に一致すればtrue

## おわりに
IDEの機能を使えば簡単に実装できました。

## 参考

[**java equalsとは？java equalsを通じてインスタンスが「同じ」かチェックしよう**](https://www.bold.ne.jp/engineer-club/java-equals)
FTPS

1.opensslダウンロード
![图片.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735439/69f06210-e848-516a-a25e-ff860babcaad.png)
2.環境変数設定
3.ダウンロード確認
cmd:openssl version
4..pfxファイル確認
cmd:openssl pkcs12 -info -in test001.pfx -nodes
5..pfxファイル.pemファイルに変換
cmd:openssl pkcs12 -in test001.pfx -out test001.pem -nodes
6..pfxファイル.crtファイルに変換
cmd:openssl pkcs12 -in test001.pfx -clcerts -nokeys -out test001.crt
7.javaに導入
keytool -import -trustcacerts -alias mycert -file test001.crt -keystore cacerts
8.

openssl pkcs12 -in test001.pfx -clcerts -nokeys -out test001.cer
keytool -import -trustcacerts -keystore cacerts -storepass changeit -alias ftps-server -file test001.cer
9.

ftpsClient.execPBSZ(0);
ftpsClient.execPROT("P");
ftpsClient.enterLocalPassiveMode();
[配布] Karabiner-Elements用 Dvorak配列 JSON

Dvorak配列の練習中です

Mac標準のIMEだと英語入力でしか使えなさそう、かつ日本語のみで練習したいので
Karabiner-Elementsを使い日本語入力のときだけDvorak配列になるようにした

JSONは以下のページで公開してます

https://github.com/RepublicOfKorokke/Tools/blob/main/Karabiner-Elements/dvorak.json

- Features
    - input_sources判定有り
    - Modifier optionalにany指定してあるので引き継がれます
    - (追記) optional: left_shiftを追加
        - 文字入力はshiftさえあればいいので
        - command等を押してる時はQWERTYのままなのでshortcut keyが通る


## Progress

https://learn.dvorak.nl

`1 - Home row, 8 keys (start positions) 100 words`
この練習で100ワード打つのに30分かかりました

この文字数の少ない記事もDvorakで書いてますが10分ぐらいかかってます
1週間後にどれくらい慣れたかも書きたい
クラウド型プロセス監視ツール５選

**Amazon CloudWatch**
AWSが提供する監視サービスで、CloudWatchエージェントを使用することで、EC2インスタンス上のプロセス監視が可能です。

‌

![Amazon cloudwatch logo - Social media & Logos Icons](https://tse1.mm.bing.net/th?id=OIP.sBq10Fxq9-lYBvu38QfC4AHaHa&w=200&h=200&c=7)

**Datadog**
クラウドベースの監視サービスで、インフラストラクチャやアプリケーションのパフォーマンスをリアルタイムで監視し、プロセスの稼働状況も追跡できます。

![Datadog Logo PNG vector in SVG, PDF, AI, CDR format](https://tse3.mm.bing.net/th?id=OIP.LWLTsfoMv3Sugt3psLhVnwHaFj&w=200&h=150&c=7)

**Site24x7**
クラウド型の監視ツールで、サーバー上のプロセスやサービスの稼働状況を監視し、異常時にはアラートを送信します。

‌

![Site24x7 Logo PNG vector in SVG, PDF, AI, CDR format](https://tse1.mm.bing.net/th?id=OIP.d_jMpiGP46Div_W1Zscq5AHaFj&w=200&h=150&c=7)

**LogicMonitor**
SaaS型のIT統合運用監視サービスで、オンプレミスやクラウド環境をエージェントレスで一元的に監視し、プロセスの稼働状況もモニタリングします。

‌

![LogicMonitor logo landscape PNG transparente - StickPNG](https://tse3.mm.bing.net/th?id=OIP.i1L-NLWQZGBgjZDkwmL5EwHaBV&w=200&h=112&c=7)

**New Relic**
クラウドベースのアプリケーションパフォーマンス監視ツールで、サーバー上のプロセスやサービスの状態をリアルタイムで監視します。

![New Relic Unveils Groundbreaking APM Solution Tailored for AI-Powered ...](https://tse2.mm.bing.net/th?id=OIP.UGv15bUUb6c4Y6RYpY6z8QHaEJ&w=200&h=112&c=7)

これらのツールは、クラウド環境でのプロセス監視に適しており、各サービスの特性や自社の要件に合わせて選定することが重要です。
ネットショップでの課題解決にARを活用！ノーコードで簡単AR作成に挑戦

皆さん、突然ですが、ネットショップを利用していますか？

私自身、ふと調べてみると、なんとAmazonで年間100個近くのアイテムを購入していました！  
主に電子書籍の漫画が多いですが、パソコン機器やLANケーブルなどの小物もつい買ってしまうことが多いです。  
営業時間内に店舗へ行けないことが多く、送料無料（Amazon Prime加入）で手軽に購入できるという点もあって、「ついついポチっとしてしまう」心情に共感する方も多いのではないでしょうか？

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881447/09939636-b36c-fae8-6950-8b9c23aa8be0.png" width=50%>
---

## ネットショップの課題：実物が見れない問題

さて、前置きが長くなってしまいましたが
今や私たちの生活に欠かせない存在となったネットショップ。  
しかし、パソコンやスマホの画面上では **「実物が見れない」** という課題が依然として存在します。  

私は某社ECショップ担当として働いていますが、日々お客様からこんなお問い合わせをいただきます：  
- **「商品のサイズが教えてください」**  
- **「梱包の箱サイズを教えてほしい」**  

画像や商品説明だけでは、サイズや実際の使用感をイメージしにくいと感じる方が多いようです。  

---

## ARでネットショップの課題を解決！

そこで考えたのが、スマホで簡単に利用できる **「AR（拡張現実）」** です。  
これを活用すれば、商品のサイズ感や梱包サイズを立体的にお客様へ伝えることが可能です。  
本記事では、ノーコードでARを作成できるサービス **「palanAR」** を使って実際に作成した事例をご紹介します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881447/9a4a3d7c-9850-352e-6e27-7fefa9aad142.png" width=50%>
---

## 使用サービス：palanARとは？

[palanAR](https://palanar.com/) は、プログラミング知識がなくてもARを簡単に作成できるノーコードサービスです。  
今回はこのサービスを使い、商品サイズをイメージしやすいARを作成します。

---

### palanARの利用手順

以下の手順でARを作成します。

1. **palanARに会員登録・ログイン**  
2. **新しいARを新規作成** を選択  
3. **ARマーカー** を選択（マーカーを基にARを表示するタイプ）  
4. プロジェクト名を設定  
5. **マーカー画像を選択**（今回は公式が用意している画像を使用）  
6. マーカーの設置方法を選択（今回は **「垂直に配置」** を選択）  
7. テンプレートは **「自由選択」** を選択  

---

### 実際の作成例：商品の箱サイズをARで表示

作成したARでは、商品サイズをイメージしやすいように **「箱」と「比較用の瓶」** を配置しました。  
編集後の画面は以下のようになりました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881447/d49c3efe-88af-3415-81a6-9d0ae3e17fcc.png" width=90%>
---

### 実際にARを表示させてみる


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881447/3226ed05-9c89-ced5-c256-2aa0f8070322.jpeg" width=50%>

公式マーカー画像をパソコンの画面に表示させます。
そして専用アプリで撮影した結果がこちらです：

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881447/c12111a6-025d-9677-017e-9d55c5af1889.png" width=50%>


パソコンのキーボードまではみ出すほどの **立体的な画像** を確認できます！  
さらに、ARの特性を活かして **左右にカメラを動かすと異なる角度から立体的に映し出されます。**

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881447/89ff901f-3c34-f174-470a-7ae3cc461904.png" width=50%><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881447/da033ef1-b323-2844-94fc-10aeccd1a842.png" width=50%>

---

### 効果の確認と次のステップ

今回はお試しで作成したため、細かいスケール調整は行っていませんが、  
これならお客様も **箱サイズのイメージがしやすい** のではないでしょうか？

さらに、「Blender」などの3Dモデリングソフトを使えば、より複雑でリアルなモデルを作成することも可能です！

---

## まとめ

いかがだったでしょうか？  
ARの活用で、ネットショップの課題である **「実物が見れない」問題** を解消できる可能性が広がります。  
しかも、ノーコードサービスを使えば簡単に作成が可能です！

興味を持った方は、ぜひ試してみてください！  
最後まで読んでいただき、ありがとうございました！ 😊

---

**関連リンク**  
- [palanAR公式サイト](https://palanar.com/)  
- [Blender公式サイト](https://www.blender.org/)