OmniAICreator/Qiita-1.07M huggingface dataset:
モジュール名と同名のファイルを作るとModuleNotFoundError

pdf2txtを試すためにpdfminerを使ってみたのだが、ModuleNotFoundErrorに詰まった。

```pdfminer.py
import os
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfpage import PDFPage
from io import StringIO

def pdf_to_text(pdf_path):
    with open(pdf_path, 'rb') as f:
        outf = StringIO()
        rm = PDFResourceManager()
        lap = LAParams()
        dev = TextConverter(rm, outf, laparams=lap)
        iprtr = PDFPageInterpreter(rm, dev)

        for page in PDFPage.get_pages(f):
            iprtr.process_page(page)

        contents = outf.getvalue()

        dev.close()
        outf.close()

        return contents

def save_text_to_file(text, output_path):
    with open(output_path, 'w', encoding='utf-8') as file:
        file.write(text)

def convert_pdfs(input_folder, output_folder):
    os.makedirs(output_folder, exist_ok=True)

    for filename in os.listdir(input_folder):
        print(filename)
        if filename.endswith(".pdf"):
            pdf_path = os.path.join(input_folder, filename)
            text = pdf_to_text(pdf_path)

            # 各PDFに対応するtxtファイルを作成し、output_folderに保存
            output_path = os.path.join(output_folder, os.path.splitext(filename)[0] + ".txt")
            save_text_to_file(text, output_path)

if __name__ == "__main__":
    # PDFファイルがあるフォルダと出力先フォルダを指定
    pdf_folder = ""
    output_folder = ""

    convert_pdfs(pdf_folder, output_folder)


```
パスが通っていないのかと思い確認する
```bash
pip show pdfminer.six

Location: /Users/ユーザー名/.pyenv/versions/3.12.0/lib/python3.12/site-packages
```
sysのパスも確認
```path.py
import sys
print(sys.path)
```
```bash
'/Users/ユーザー名/.pyenv/versions/3.12.0/lib/python3.12/site-packages'
```
パスに問題はない。ならばなぜ動かないのかと逡巡していたところ、リネームをすると動くことに気がつく。
どうやら実行ファイルの名前をpdfminer.pyとしていたことが原因のようだった。

つまりモジュール名と同名の実行ファイルを作成してしまうと、pythonが実行ファイルをモジュールとして解釈してしまい、標準モジュールよりも優先して読み込んでしまうということが起きるらしい。

なので実行ファイル名をリネームして解決した。
郵便番号検索するためのデータベースを作成する-１

## PowerAppsで郵便番号検索を行いたい


今回はPowerAppsで下記動画のような郵便番号検索アプリを作成するために、
PowerAutomateで郵便番号検索データベースを作成します。

:::note info
PowerAppsで下記動画のように住所検索ができるようにできますが、事業所郵便番号で住所検索まではできません。
あしからず。
:::

今回のゴールはこちらです
![postelCodeDB.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111714/4fd43bdb-9040-34ab-da24-f653c917063b.gif)


## なぜこれをしたいのか
ユーザーの時短になるからです！

PowerAppsでの郵便検索はAPIで検索する方法は紹介されていると思います。

ただし…

追加コストがかかる！！！

そういった部分を説得していくのは、中小企業の方にとっては本当～に難しいことなので
だったら手作りすればいいじゃない！ということで
PowerAutomateで郵便番号のデータベースを作成することにしました。
今回は1か月に一度自動更新を行うようなフローを想定しています。

## 郵便番号データをダウンロードする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111714/198157d2-c517-8842-1149-5245347c8dbf.png)

https://www.post.japanpost.jp/zipcode/download.html


※文字コードUTF-8の郵便番号コードリストはありませんでしたが
なんと2023年6月から対応してくださったのです！
そちらをダウンロードして使用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111714/d28f1b17-f9f5-3181-0160-5cbf3cb7e492.png)

最新データのダウンロードリンクを右クリックからリンクを取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111714/575f7051-f755-35a5-597f-3fb9c385de99.png)


## PowerAutomateからデータをダウンロードするアクションを追加する
![Automate_logo (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111714/fb377145-8d9b-ea8c-b96a-5c39a1590613.jpeg)
1.PowerAutomateにはOneDriveのアクションの中に
【URLからのファイルのアップロード】というアクションがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111714/ac36c4ce-2b66-0b3e-6fd5-942a08151c7c.png)

【ソースURL】にダウンロードするURL先を入力しましょう。
【対象のファイルのパス】はデータベースを保存したいファイル先名を入力します。
必ず、【上書き保存】にはいを選択してください。


2.フォルダーにアーカイブを展開しますというアクションがファイル解凍のコマンドとなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111714/a3d58481-787d-f191-7382-a28ef0d88f9b.png)

【ソース　アーカイブ　ファイルのパス】に保存する先のファイルに、
【宛先フォルダーパス】に解凍先データ(csvファイル)を保管する場所、
【上書きする】にはいを選択してください



下記のようになれば、データのダウンロードから解凍まで可能となってきます。
。
![2023-12-16-17-22-31.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111714/4746ae11-29f9-612f-5213-b0d50ef4a6b5.gif)







丁度区切りがいいので、その２に続きます！
Hello Androidに半年かかった話

# 結論から
ウイルス対策ソフトのせいでした．

# 詳しく
[結論から](#結論から)で書き終えているので詳しく話すこともないですが…
## 経緯
今年(2023年)の4月，Androidのアプリ開発に関する本を衝動買いしアプリ開発をはじめました．

しかし，本の通りにコードを書いて実行しても「androidResources (アクセスが拒否されました。)」のエラーばかり出て全く動きません．
ネットで情報を漁ってもめぼしいものはなく，「これで解決した」と書かれている手順をまねしても全くうまくいきませんでした．

ところがつい先日，思い立って一時的にウイルス対策ソフトを止めてみると何の問題もなく実行されました．
その時の感動のツイートが以下．

https://x.com/tt41357393/status/1735278925813788963?s=20

ちなみに止めた機能は「ウイルス自動検知」です
TypeScriptでPickを利用する

## はじめに
TypeScriptで基本型に対し、一部の型を取得するPickを紹介します。

## ソースコード

```ts:pick.ts
type Person = {
    name: string;
    age: number;
    address: string;
  };

//   type PersonBasicInfo = Pick<Person, 'name' | 'age'>;
  type PersonBasicInfo = Pick<Person, 'name'>;

  const person: PersonBasicInfo = {
    name: 'Alice',
  };
  
  console.log(person); // { name: 'Alice' }
```

## 実行結果
```shell:実行結果
~/develop/react/typescript_node$ ts-node pick.ts
{ name: 'Alice' }
```
私のエンジニア市場価値・社内価値を高める修行記録

# 目次
- [本稿の目的](#本稿の目的)
- [モチベーション](#モチベーション)
- [修行方法](#修行方法)
- [修行内容](#修行内容)
    - [資格取得](#資格取得)
    - [コードを書く、読む](#コードを書く、読む)
    - [本を読む](#本を読む)
- [お約束](#お約束)
- [最後に](#最後に)

# 本稿の目的
私の修行記録・モチベーション維持のために本稿を書いています。修行モチベーションが低下した際にこの投稿を見て、再度奮起できればいいなと思います。
また、本記事を読んだ人の何かのきっかけになれば幸いです。

# モチベーション
"社内価値だけでなく市場価値を高めたい"
社会人3年目(27歳)の2023年8月頃にふと将来について考え、今後も今までのような生活でいいのだろうか？と考え始めました。
当時の私には「スキル」「経験」「知識」が不足しているという自覚はありましたが、仕事をやっていくうちに身につく、時間が解決してくれるだろうと考えていました。しかし、そんな受け身な姿勢でいつ身につくのか？そもそも身につくまで会社が待ってくれるのか？といった不安から、何か行動しなければと思ったのがきっかけです。
そこで、今の自分に何ができるか、何が必要かを考えました。

# 修行方法
- 資格取得
- コードを書く、読む
- 本を読む

# 修行内容
## 資格取得
私の以下の基準で選定しました。
- 業務内容と遠すぎない
資格を取ることが目的となるのを防ぐためです。
- 試験期間が空きすぎない
モチベーション維持につながります。

| 資格 | 理由 | 取得状況 |
| :---: | :--- | :---: |
| [QC検定](https://webdesk.jsa.or.jp/common/W10K0500/index/qc/) | ・モノづくりに必要な品質の考え方が学べるため<br>・会社推奨資格| 3級 2023/9 |
| [LPIC](https://www.lpi.org/ja/) | ・開発業務でLinuxを使用しているため<br>・試験日程を自分で決められるため<br>・国際資格に惹かれ[LinuC](https://linuc.org/)ではなくLPICを選択| LPIC-101 2023/10/28<br>LPIC-102 2023/12/15 |
| [AP](https://www.ipa.go.jp/shiken/kubun/ap.html) | ・幅広く知識を付けられるため<br>・会社推奨資格 | ×2024/10 午前:57.50点 |
| [NW](https://www.ipa.go.jp/shiken/kubun/ap.html) | 視野/思考を広げるために取りたい | |
| [DB](https://www.ipa.go.jp/shiken/kubun/db.html) | 視野/思考を広げるために取りたい |
| [ES](https://www.ipa.go.jp/shiken/kubun/es.html) | 視野/思考を広げるために取りたい | |
| [ETEC](https://www.jasa.or.jp/etec/) | ・組込み知識を体系的に学べるため<br>・CBT方式で試験期間に制限がないため |
| [UMTP](https://umtp-japan.org/) | ・UMLを業務で使用するため<br> ・ソフトウェア設計をきれいに行いたいため | l1 2024/1/31  |  
| [G検定](https://www.jdla.org/certificate/general/) | ・AIに関して勉強するきっかけづくり<br> 社内でもAI技術やデータアナリスト教育に力を入れているため | 2024/7/6 |  

## コードを書く、読む
技術力を上げたいならコードをたくさん書いて、お手本となる他者のコードを読むのがいいのではと思いました。そこで選択したのが「アルゴリズムとデータ構造」です。参考書籍はもちろん、競技プログラミングに参加すれば、他人の書いたコードが無料で読めるからです。
あと大事なのが私自身「アルゴリズムとデータ構造」について学びたいと思ったからです。

## 本を読む
できる人ほど本を読むと何かに書いてあるのを見た気がします！笑
ジャンルは自分が興味あれば何でもいいと思っています。

# お約束
- 修行記録を残す
  - [Studyplus](https://app.studyplus.jp/)を使って時間や内容を記録
  - [Qiita](https://qiita.com/yankee2023)を使って備忘録やメモ
  - [Github](https://github.com/yankee2023)を活用しソースコードを記録
- 修行の習慣をつける
  - 理想は短時間でもいいので毎日修行
  - 朝早く会社に行き修行時間を確保する
  - 残業はなるべくせずに修行時間を確保する
  - 移動などの隙間時間をうまく活用する
- 無理をしない
  - 体調が悪いときは無理をしない(健全な修行は健全な心身から)
  - 会社の人や友人との予定を優先する(息抜き大事)

# 最後に
やり続ける・やり抜くためには「無理をしない」「自分に厳しすぎない」ということを頭において修行を続けてください。
TypeScriptでOmitを利用する。

## はじめに
TypeScriptで基本型に対し、一部の型を除外するOmitを紹介します。

## ソースコード

```ts:omit.ts
type Person = {
    name: string;
    age: number;
    address: string;
  };

  type PersonWithoutAddress = Omit<Person, 'address'>;

  const person: PersonWithoutAddress = {
    name: 'Alice',
    age: 30,
    // 'address' プロパティは省略されているので指定不可
    // address: '123 Main St',
  };

console.log(person); // { name: 'Alice', age: 30 }
```

:::note info
Omitとは日本語で「省く」という意味です。任意の型から一部のプロパティを省いて新規の型を作成します。
:::


### 実行結果
```shell:実行結果
~/develop/react/typescript_node$ ts-node omit.ts 
{ name: 'Alice', age: 30 }
```
Firebase * Swiftでレシピ保存アプリを作りました！

## 技育キャンプ マンスリーハッカソン vol.12
### タイトル
Recipe Clipper

### 発表スライド(デモ、スクリーンショット)
https://www.canva.com/design/DAF15mDsjN0/fQrkpAErKrCyhswyKmfpMA/edit

### 開発期間
一週間

### 開発人数
個人開発

### 役割
企画　開発　デザイン

### 使用した技術・ツール
Swift,　Firebase

### プロジェクトの目的・動機
YouTubeにある料理動画は見ながら、料理をするのが大変と感じたので、料理動画を読み込んで要約し、レシピを保存するというアプリを作りました。

### 課題と学び
firebaseとの接続がうまくいかなかった。
Storyboardを使ったデザインが初めてで、スプラッシュ画面の実装がうまくいかなかった。
firebaseを使った影響か、Storyboardを使ったからか、シュミレーションがうまくできなかった。
Initial View Controllerにチェックを入れる、
InitialViewControllerに設定しているClassが存在しているか,
シミュレータで cmd + shift + h を押してホーム画面へ
起動しないアプリを削除し、もう一度Runする,
TARGETSのGeneral（Main Interface）の確認、
https://qiita.com/vaza__ta/items/9a563079bb33d086a66d


いろいろ試したが結局解決方法が分からなかった。


### コードサンプルまたはGitHubリンク
https://github.com/haruki-mochida/RecipeClipper

### 反省点・今後の改善計画

まだリリースまでイケてないので、シミュレーターの問題を解決したらリリースを目指す
作成したレシピの音声をながせるようにしたい
「レシピの材料を買い物リストに追加する」機能
作成したレシピをカロリー順だったり、おすすめ順みたいに並べ替える機能
【React(TypeScript)】React Routerで画面遷移前にログインチェックなどの共通処理を入れる

# 概要
画面遷移前にログインチェックを入れたいという要件はまあまああると思います。調べてみると色々やり方はあるようですが、比較的簡単にやる方法が分かりましたのでマイベストプラクティスとして共有させていただきたいと思います。

# やり方
ログインチェックし画面遷移先を制御するコンポーネントを作成して、React Routerでログインチェックを入れたい画面をこれで囲みます。

# Router.tsx
ログイン済みであるかを判定し、結果に応じて画面遷移先を制御するコンポーネント（PrivateRoutes）を作成します。ログイン済みチェックを入れたい画面（例：```<Route path="home" element={<Home />} />```）をこれで囲みます。
PrivateRoutesの```<Outlet />```はRouteを表しています。つまり、Outletをreturnするということは、通常どおり画面遷移を行うということなります。一方、NavigateをreturnすればRouteの画面遷移ではなく、Navigateで指定された画面遷移を行うということになります。

```jsx
const PrivateRoutes = () => {
  // 未ログインチェック
  // （isLoginを判定する処理は省略してます）
  if (isLogin === false) {
    return (
      <Navigate to='/signin' />
    )
  }
  return <Outlet />
}

const Router = () => (
  <BrowserRouter>
    <Routes>
      <Route path="signin" element={<SignIn />} />
      {/* PrivaeRoutes内に設定された画面はサインインが必須になる */}
      <Route element={<PrivateRoutes />}>
        <Route path="home" element={<Home />} />
      </Route>
      <Route path="*" element={<Error404 />} />
    </Routes>
  </BrowserRouter>
)

export default Router
```
Azure Blob Storage を扱う Python アプリの開発環境を Docker で作る

タイトルの通り、Azure Blob Storage を扱う Python アプリの開発環境を Docker で作りたかったのでメモ。

## Azurite
開発環境から本物の Blob Storage を触るのはダルいので、ローカルでそれっぽく動くやつないかググったら Microsoft 公式から Azurite というツールが公開されていた。さすが。

→ [Azure/Azurite: A lightweight server clone of Azure Storage that simulates most of the commands supported by it with minimal dependencies](https://github.com/Azure/Azurite)

## Docker イメージを動かす
公式 Docker イメージもあったので Docker Compose で動かしてみる。

``` compose.yml
services:

  my_python_app:
    (略)

  azurite:
    image: mcr.microsoft.com/azure-storage/azurite
    volumes:
      - azurite:/data

volumes:
  azurite:
```

今回は `my_python_app` サービスから触れればよく「特にポート公開とかはしなくていいや」となったのでボリュームを `/data` にマウントするだけで済んだ。

中ではポート 10000 で Blob Service が listen しているらしい。

## Blob Service に接続する
Azurite を動かすと「ローカルに Azure ストレージアカウントがひとつ作られている」みたいな感じになるっぽい。

ストレージアカウントの接続情報は公式ドキュメントに書いてあった。

→ [ローカルでの Azure Storage の開発に Azurite エミュレーターを使用する | Microsoft Learn](https://learn.microsoft.com/ja-jp/azure/storage/common/storage-use-azurite?tabs=visual-studio%2Cblob-storage)

今回は Python から Blob Service を利用するので、こんな感じになった。 (`azure-storage-blob` パッケージのインストールが必要)

``` python
from azure.storage.blob import BlobServiceClient

def get_blob_service_client() -> BlobServiceClient:
    # TODO: 本番環境の場合は本番環境用の BlobServiceClient を返すようにする
    azurite_conn_str = "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://azurite:10000/devstoreaccount1;"
    return BlobServiceClient.from_connection_string(azurite_conn_str)


blob_service_client = get_blob_service_client()
```

`azurite_conn_str` は公式ドキュメントからコピペしてきて `127.0.0.1` の部分を `azurite` に変えただけ。

## Blob Storage を操作する
公式ドキュメントを見ながら操作していく。
Amazon S3 とノリは同じだったのでだいぶわかりやすかった。

[Azure Storage SDK for Python | Microsoft Learn](https://learn.microsoft.com/ja-jp/python/api/overview/azure/storage)

``` python
blob_service.list_containers()  #=> []
```

まだなんも作ってないので空。それはそう。

``` python
blob_container = blob_service.create_container("foo")
```

Blob コンテナを作ってみた。

``` python
blob_container = blob_service.get_container_client("foo")
```

作成済みの Blob コンテナのクライアントを取得するときはこう。

``` python
blob_container.list_blobs()  #=> []
```

コンテナから Blob 一覧を取得するときはこう。

データを Blob にアップロードしてみる。

``` python
data = b"FOOOOOO!!!"
blob_container.upload_blob("foo.txt", data)
```

`data` には bytes や str だけでなく Iterable や IO も指定できるらしいので、普通に何でもアップロードできそう。

ファイル一覧を取得してみる。

``` python
for blob in blob_container.list_blobs():
    print(blob["name"])
#=> "foo.txt"
```

ファイルをダウンロードしてローカルに書き出してみる。

``` python
stream = blob.download_blob()
with open("foo.txt", "wb") as f:
    f.write(stream.readall())
```

「せやな」という感じで普通に操作ができた。

詳しいことは公式ドキュメントを参照： [Azure Storage SDK for Python | Microsoft Learn](https://learn.microsoft.com/ja-jp/python/api/overview/azure/storage)
Laravel sailで、PHP内部からlocalhostへのアクセスができない

# Laravel sailで、PHP内部からlocalhostへのアクセスができなかった。

## 問題

いい設計かは別として、Laravel sailのdocker内で、下記のような事をやろうとしても、レスポンスがtimeoutしてできなかった。

```php
file_get_contents('http://localhost/');
```

## 理由

Laravel sailのウェブサーバーは、artisan serveコマンドを使っていて、これが同時に1プロセスしか処理できない。つまり、file_get_contentsを呼び出している側のプロセスで既に1プロセス使ってるので、受け側のHTTPリクエストを処理することができない。

## 解決

artisan serveのプロセス数を増やせばOK。

```.env
PHP_CLI_SERVER_WORKERS=16
```
Reactでページ内遷移を実装する。(AnchorLinkを実装する）

## はじめに
表題通り、Reactでページ内遷移を実装します。
よくWebページで#値を元にページ内遷移ができるUIをどのように実装しているのだろうという興味のもと、今回実装してみました。

## 成果物
![card_scroll.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/f8dc51bd-9636-87e0-25e4-b778f163567b.gif)

## ソースコード

https://github.com/kouji0705/react_anchor_link

```shell:ディレクトリ構成
├── src
│   ├── App.tsx
│   ├── components
│   │   ├── ListCard.tsx
│   │   ├── ListContainer.tsx
│   │   ├── hooks.tsx
│   │   └── type.ts
│   ├── index.tsx
```

## ソースコード
```tsx:App.tsx
import React from 'react';
import { ListContainer } from './components/ListContainer'

function App() {
  return (
    <ListContainer />
  );
}

export default App;
```

```tsx:src/components/hooks.tsx
import { useEffect, useState } from "react"
import { ListItem } from "./type"

export const useCardScroll = () => {
    const [list, setList] = useState<ListItem[]>([]);

    useEffect(() => {
      const items = Array.from({ length: 100 }, (_, index) => ({
        id: `card${index + 1}`,
        title: `タイトル${index + 1}`,
        content: `コンテンツ${index + 1}`
      }));
      setList(items);
  
      const scrollToCard = () => {
        const hash = window.location.hash;
        if (hash) {
          const id = hash.replace('#', '');
          const element = document.getElementById(id);
          if (element) {
            element.scrollIntoView();
          }
        }
      };
  
      scrollToCard(); // コンポーネントのマウント時にスクロール
      window.addEventListener('hashchange', scrollToCard); // ハッシュ変更時にスクロール
  
      return () => {
        window.removeEventListener('hashchange', scrollToCard);
      };
    }, []);

    return { list }
}
```

```tsx:src/components/ListCard.tsx
import { Card, CardContent, Typography } from '@material-ui/core'
import React from 'react';

export interface ListItem {
    id: string;
    title: string;
    content: string;
  }

export  const ListCard: React.FC<{ item: ListItem }> = ({ item }) => {
    const handleClick = () => {
      window.location.hash = item.id;
    };
    return (
      <Card id={item.id} style={{ margin: '10px', width: '200px' }} onClick={handleClick}>
        <CardContent>
          <Typography variant="h6">{item.title}</Typography>
          <Typography variant="body2">{item.content}</Typography>
        </CardContent>
      </Card>
    );
  };
```

```tsx:src/components/ListContainer.tsx
import React from 'react';
import { ListItem } from './type'
import { ListCard } from './ListCard'
import { useCardScroll } from './hooks'

export const ListContainer: React.FC = () => {
    const { list } = useCardScroll();

  return (
    <div>
      {list.map((item: ListItem) => (
        <ListCard key={item.id} item={item} />
      ))}
    </div>
  );
};

```

```ts:src/components/type.ts
export type ListItem = {
    id: string;
    title: string;
    content: string;
}
```
Windows環境でアプリ・フォルダの起動をショートカットキーで行う小技


アドベントカレンダーで未投稿になっている部分を勝手に埋める担当のNMRです。
よろしくお願いします。

日頃Windowsで作業中
「このアプリ（フォルダ）一発で起動（移動）したい～」
という需要が非常にあったため、やり方を調べ記事にしました。

### この記事でできるようになること
- アプリケーション起動にショートカットキーを割り当てられるようになる
- 好きなフォルダへショートカットキーで移動できるようになる

### ショートカットキーの設定方法

#### アプリケーションの場合

アプリケーション起動アイコンを右クリックしてプロパティを選択。
![スクリーンショット 2023-12-16 112446.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2636207/49a34199-6e64-a73d-01c5-b86fd101f5c9.png)

ショートカットキー欄に使いたいショートカットキーを入力して、適用を押す。
![スクリーンショット 2023-12-16 112714.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2636207/a616c51b-29d8-b5b8-a59d-3926f952ca15.png)

管理者権限を求められますが、続行を押します。

以上です。

環境によっては再起動が必要かもしれません。
設定したショートカットキーが動作しない場合は再起動してください。

#### フォルダの場合

パスはどこでもいいので右クリックし「新規作成」→「ショートカット」でショートカットを作成します。

開きたいフォルダを選択し、OKを押します。

![スクリーンショット 2023-12-16 163800.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2636207/50ec8126-091d-bae5-ded2-0a3a5c624823.png)

出来上がったショートカットを右クリック→プロパティを選択します。」

アプリケーションの時と同じようにショートカットキーを設定してOKを押します。

![スクリーンショット 2023-12-16 164845.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2636207/c504e337-cc10-564f-2829-1e9980d12487.png)

これでショートカットキーを押すことでショートカットに設定したフォルダを開けるようになりました。

以上

アプリやフォルダにショートカットキーを設定する方法でした。

ダウンロードフォルダなど、いちいちマウスでカチカチ操作して移動することが多いフォルダへ設定しておくのがおすすめです。
[Typescript] オブジェクトのクローン

## 初めに
NextJS + typescriptでwebアプリケーションを作成していた際、使用しているオブジェクトの内容が意図せず変更されてしまい、とても困惑してしまいました。その原因と解決策をここに残したいと思います。

## 意図していない変更の概要
下記のようにオブジェクトAを変数Bに代入して、その代入された変数Bに変更を加えた後に元々のオブジェクトAを確認すると、変数Bにした変更がオブジェクトAにも反映されてしまっていました。
```
const object_A = {
    id: 1,
    name: 'tanaka'
}

const B = object_A
B.name = 'takahashi'

console.log(object_A)
// {id: 1, name: 'takahashi'}

```

## 原因
これの原因としては、Typescript(Javascript)はオブジェクトを変数に代入すると参照渡しになるためでした。
変数BにはオブジェクトAの参照が渡されるため、オブジェクトAと変数Bが同じオブジェクトを参照する事になります。そのため、変数Bにした変更がオブジェクトAにも反映されてしまいます。

オブジェクトAに変更を反映してほしくない場合は、変数Bに代入するときに意図的に値渡しにする必要があります。

## 解決策
Typescirptでオブジェクトを値渡しにする方法は`structureClose()`メソッドを使用する事です。
引数にオブジェクトを入れると値渡しでオブジェクトを複製できます。
```
const B = structureClose(object_A);
```
こうする事によって、変数BはオブジェクトAとは切り離されるので、変数Bに変更を加えてもオブジェクトAにはなんの影響も与えられません。

## 最後に
オブジェクトに意図せず変更が加えられていた場合は参照渡しされている事が原因な可能性がありますので、頭の片隅にでも置いといてもらえればと思います。
以上、閲覧して頂きありがとうございました:bow_tone1:
弊チームでデプロイ作業の自動化、デプロイ構成情報を管理

# TL;DR

- 弊チームではGitHub ActionsとTerraform Cloudを用いてデプロイ作業の自動化、デプロイ構成情報を管理しています
- GitHub ActionsからTerraform Cloudの設定を変更することによって、構成情報の一元管理を実現しています。
- Terraform Cloudの設定を変更できるGitHub Actionsがあれば嬉しい

# 弊チームのデプロイ方針

 弊チームでは、[タクシー事業者のDXを推進 　LINEを活用した「配車サービス」の8月本格提供に向けて 一部タクシー事業者へのテスト導入を開始](https://www.persol-pt.co.jp/news/2023/07/06/8082/)に記載されているLINEを活用した「配車サービス」をタクシー事業者に提供しております。このサービスのデプロイ作業の可視化（コード化）に[Terraform](https://www.terraform.io)を、自動デプロイを実現するために[GitHub Actions](https://docs.github.com/ja/actions)を用いました。またデプロイ構成情報(tfstate)の保管先に[Terraform Cloud](https://app.terraform.io/public/signup/account)を用いて、デプロイ作業のチーム内における「べき等性」を確保しました。

このおかげで、同様な構成をもつサービスを横展開する際にデプロイ作業の簡略化も実現しています。

上記のフローは以下の通りです。

```mermaid
sequenceDiagram
    actor Dev
    participant GH as GitHub
    participant TF as Terraform Cloud
    participant CS as Cloud Service
    Dev ->> GH: デプロイの依頼をする
    Note over GH: コンテナーイメージの作成
    GH ->> TF: terraform apply の実行
    TF ->> CS: デプロイを行う
    CS ->> TF: デプロイ構成情報を渡す
```

# 課題

このフローを実現するためには、課題がありました。[Amazon Elastic Container Serviceへのデプロイ - GitHub Actions](https://docs.github.com/ja/actions/deployment/deploying-to-your-cloud-provider/deploying-to-amazon-elastic-container-service)や[Azure App Service に Docker をデプロイする - GitHub Actions](https://docs.github.com/ja/actions/deployment/deploying-to-your-cloud-provider/deploying-to-azure/deploying-docker-to-azure-app-service)にあるように、GitHub Actiosのドキュメントで継続的デプロイ(CD)を実現するために、[AWS for GitHub Actions](https://github.com/aws-actions)や[GitHub Actions for Azure](https://azure.github.io/actions/)を用いています。

この方法では、デプロイ構成情報が[Terraform Cloud](https://app.terraform.io/public/signup/account)に保存されません。Terraform Cloud上で想定している使用コンテナーイメージと実際に動作しているコンテナーイメージの不一致が発生しました。

# 解決方法

この課題を解決する上でTerraform Cloud上で作成したWorkspace特有のVariableをGitHub Actionsから直接変更する方針を採用しました。
幸いにも、Terraform CloudにはWebAPIが提供されています。

本作業に必要なWebAPIは以下の3つです。

- [Workspaces -> List workspaces](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspaces#list-workspaces)
- [Workspace-Specific Variables -> List Variables](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspace-variables#list-variables)
- [Workspace-Specific Variables -> List Variables](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspace-variables#update-variables)

このWebAPIを利用して、**Workspace特有のVaribleと指定しているデプロイに使うコンテナーイメージの値を更新** しています

```mermaid
sequenceDiagram
    actor Dev
    participant GH as GitHub
    participant TF as Terraform Cloud
    participant CS as Cloud Service
    Dev ->> GH: デプロイの依頼をする
    Note over GH: コンテナーイメージの作成
    GH ->> TF: Workspace特有のVaribleと指定しているデプロイに使うコンテナーイメージの値を更新する
    GH ->> TF: terraform apply の実行
    TF ->> CS: デプロイを行う
    CS ->> TF: デプロイ構成情報を渡す
```

# 今後の課題

Terraform CloudのWebAPIをたたくことができるGitHub Actionsがあればいいですね。
業務ではありませんが個人的に[レポジトリ](https://github.com/abekatsu/tfc-api-action)を作成しました(README.mdしか作成していませんが)。時間を見つけて埋めていきます。
Laravel & sail環境でChromiumを導入して、HTMLで作った帳票をPDFファイルを出力するまで。

# Laravel&sail環境で、綺麗なPDFファイルを作る。

PDFファイルを作る方法は色々ある。
ChromiumブラウザからPDFファイルを出力する方法だと、複雑なHTMLでもPDF化できるので便利。
m1/m2/m3のmacとかでも対応できる手順。

## DockerでのChromiumをインストール

リリース版のChromiumは、aptじゃないsnapというパッケージマネージャーをインストールする必要があるらしく、Dockerで入れるには色々面倒っぽい。betaバージョンのChromiumを入れることにした。

Dockerの設定ファイルを書き出す。

```shell
./artisan sail:publish
```

Dockerの設定変更

```/docker/8.2/Docker
    && apt-get install -y mysql-client \
    && apt-get install -y postgresql-client-$POSTGRES_VERSION \
+   && apt-get install -y software-properties-common \
+   && add-apt-repository -y ppa:saiarcot895/chromium-beta \
+   && apt-get update \
+   && apt-get install -y chromium-browser \
```


```/docker-compose.yaml
-       image: sail-8.2/app
+       image: sail-8.2/app-with-chromium
```

イメージを作り直して起動する。
```shell
./vendor/bin/sail up
```

## PHPから簡単に呼び出せるパッケージをインストール

```shell
composer require chrome-php/chrome
```

## 使ってみる

```php
use HeadlessChromium\BrowserFactory;


// chromium-browserのパスを指定して、ブラウザファクトリを作成
$browserFactory = new BrowserFactory('/usr/bin/chromium-browser');

// ブラウザを起動
$browser = $browserFactory->createBrowser();

try {
    // 新しいタブを作成
    $page = $browser->createPage();

    // ページに移動
    $page->navigate('https://www.yahoo.co.jp/')->waitForNavigation();

    // スクリーンショットを撮影
    $tmp_path = tempnam(sys_get_temp_dir(), 'pdf');
    $page->pdf(['printBackground' => false])->saveToFile($tmp_path);

    // ブラウザを閉じる
    $browser->close();

    // PDFファイルを返す
    return response()->file($tmp_path)->deleteFileAfterSend(true);

} catch(Exception $e) {

    // ブラウザを閉じる
    $browser->close();

    // 例外をまた飛ばす
    throw $e;
}
```
分散システムについて改めて学習してみる。まずはHadoop1系から勉強しなきゃダメ HDFS MapReduce編

# 1.そもそも分散システムとは？

働いている会社で、ビックデータを扱う機会が増えている人もいるのではないでしょうか？

数百GB、TBレベルの大量のデータを１つのコンピューターで処理することはかなりの時間を要してしまいます。

そこで、複数のコンピューティングを使って分散してデータを処理するシステムのことを分散システムと総称していいます。

![スクリーンショット 2023-12-16 14.33.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2526914/65ec32b2-e6fe-c96a-7c77-f1bc74ea9222.png)
上記資料参考サイト：

https://oss.nttdata.com/hadoop/hadoop.html

分散システムの中にApache Sparkというものを聞いたこともある方はいるかと思います。
HadoopとSparkは対の関係ではなく、
Hadoopの一部にSparkがあるのです。

なので、Sparkの構成を知りたい方はまずHadoopとはなんなのかを学習するところから始まります。


# 2.Hadoopとさまざまな分散システム

分散システムを学習したい方はまず初めにHadoopというシステムを学習する、ないしは聞いたことがある人が多いかと思います

Hadoopは
2006年には単体のプロジェクトとして独立し、Apache　Hadoopとしてリリースされました

Hadoopは１つのソフトウェアではなく、複数のソフトウェアを組み合わせたものになります。


## なぜ今1系の勉強をするのか？

2023年12月現在、Hadoopは3系まで存在しています。

まずは1系のシステム構成から学習した方が基礎が分かるので
吸収が速いかと思い、まずは１系から説明いたします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2526914/56389020-b7c2-9a26-b7bf-c6bc1365bc09.png)

以下の画像はとりあえず今のところは
『こんな構成してるんだー』くらいの認識でOkです。

個別に見ていきましょう。

## HDFS
Hadoop Distributed File System
分散ファイルシステムといいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2526914/3a6ea908-3b9d-d6c5-d8fa-978014574521.png)

１つのデータをブロック単位でまずは分割します。
時系列のデータあれば

13:00~15:00の50万行のデータを分割
15:00~17:00の50万行のデータを分割

みたいに一定サイズで分割していきます。

コンテナという複数の入れ物みたいなものに分割したデータを格納します。

### HDFSの細かな構成

コンテナ単位で分割されるのはわかりました。
イメージですが、どのデータがどのコンテナに格納されているか管理しないといけません。

それにNameNodeというものがあり、まだ、コンテナの集団をDataNodeといいます。
DataNodeにはデータの実態が存在します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2526914/ca871461-9b87-594a-87b9-9406a4f8ba14.png)

ここで、DataNodeが故障したらどうなるでしょうか？
これがデータを分割させた理由になります。
Bのみを保存していた部分が壊れていても、他にBが格納されているので、問題なく稼働することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2526914/8af70cb3-2d96-2cdc-7fab-88f3311b64ab.png)


### Name Nodeが壊れた場合は？
図で分かる通り、Name Nodeが壊れた場合は、単一障害点としてHadoopシステムが動かなくなってしまいます。

NameNodeのサービスを維持する仕組みとして、Apache ZooKeeperの分散ロック機構を利用した、Active-Standby構成のNameNode-HAが開発されました。 このNameNode-HAにより、Active側のNameNodeが故障した場合に、ダウンタイムなしでStandby側のNameNodeにサービスを引き継げることが可能になりました。

## Mapreduceのシステム構成

Mapreduceは実際にデータを処理するソフトウェアになります。

Hadoop MapReduceは、マスターノードであるJobTrackerとスレーブノードであるTaskTrackerで構成されています。 JobTrackerは、MapReduceジョブの管理やTaskTrackerへのタスクの割り当て、TaskTrackerのリソース管理を役割としています。 TaskTrackerは、タスクの実行を役割としています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2526914/25ba8e2c-b091-2e7d-a55d-1d9f3286b222.png)
上のTask Trackerの１つをクラスタと呼びます。

もし仮にどこかのTaskTrackerが故障した場合は、クラスタを引き離し、別のTask Trackerで再試行されるような設計になっています。


## Hadoop2系の登場

Hadoop2系では、分散処理フレームワークHadoop MapReduceの仕組みが変更となり、分散リソース制御機構 Hadoop YARNとMapReduce ApplicationMasterの2つに分離されました。 YARNの登場により、MapReduceに適していない処理については、各自が仕組み(ApplicationMasterとアプリケーション制御)を実装することでMapReduceと同様にYARNの仕組みによって分散処理が可能となりました。 YARN上でのMapReduce以外のアプリケーションでは、Apache Tez、Apache Sparkなど活発に開発されています。

ここからようやくSparkが出てくるわけですね。

次の記事はHadoop2系の説明とSparkのシステムをしたいと思います。
Power AutomateのCopilotが環境ごとに挙動が違った話

※本記事は「[Microsoft Power Automate Advent Calendar 2023 シリーズ2 16日目](https://qiita.com/advent-calendar/2023/powerautomate)」の記事です。

こんにちわ、 [のりじ](https://twitter.com/nori790822) です。
Power Automateで利用できるCopilotを使ってみて、環境によっては「おや？」っとなったところがあったので現時点の状況メモ的な記事です。

## 1. デフォルトの日本環境の表示

![copilot01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103396/5a03b70c-f5aa-e947-8fd0-ca2c54826f18.jpeg)

日本環境でもモダンデザイナー表示がデフォルトになりました。  
ですが、上図のように左側にはコネクタの設定が表示されますが、Copilotは表示されず右側が空白の状態です。（2023年12月16日現在）

このように、日本環境ではCopilotの表示がされていませんが、Power Platform管理センターで「地域間のデータ移動を有効化する」ことで表示するようにできます。

## 2. 日本環境＆日本語でCopilotを使う準備

[Power Platform管理センター](https://admin.powerplatform.microsoft.com/)を表示します。

![copilot02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103396/29e80003-d183-65ca-55d0-a43bd95f4910.jpeg)

[環境]から該当の環境を選択し、下方に表示されている「生成AI機能」の「リージョン間でデータを移動する」をクリックします。

![copilot03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103396/6137b94d-956d-d476-01b2-7c5fa4a2cd75.jpeg)

上図のような画面が表示され、少し待つと環境の設定が完了します。

![copilot04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103396/e98c84aa-bfa0-7f01-0f53-df01ab6240e2.jpeg)


作成済みのワークフローを開くと、右側にCopilotが表示されるようになりました。

- [コパイロットと生成 AI 機能の有効化](https://learn.microsoft.com/ja-jp/power-platform/admin/geographical-availability-copilot?WT.mc_id=ppac_inproduct_settings)

## 3. 米国環境と日本環境の挙動の違い

これで日本環境＆日本語でCopilotを使えるようになった！と思ったのですが…どうも挙動がおかしい気がする。
ということで、以下の環境＆言語で「Outlookでメールを送信する」という簡単なプロンプトを「記述して作成する」で実行して確認してみました。

1. 米国環境＆日本語
2. 日本環境＆日本語
3. 日本環境＆英語

### 3-1. 米国環境＆日本語の結果

![copilot05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103396/f2a0f0c8-a27e-0644-8417-05d69f703428.jpeg)

上図のように、フローが提案されます。

![copilot05-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103396/eefba4a9-0d2c-647a-cbba-4639ab20df6a.jpeg)

トリガーとアクションで実行されるコネクタが表示されるので、問題なければ「フローを作成」をクリック。

![copilot05-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103396/845f4eea-aa44-85ab-5aa5-cae532b4bbd7.jpeg)

「記述して作成する」で入力した内容がフロー名になったワークフローが作成できました。

### 3-2. 日本環境＆日本語の結果

![copilot06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103396/f70fb89e-c38e-76c6-4aaa-b779fceed938.jpeg)

「2. 日本環境＆日本語でCopilotを使う準備」を行った環境です。
上図のように「フローの提案なし」と表示され、ワークフローが作成できませんでした。
ちなみに、日本環境は「Power Automate Premium」ライセンスを付与したアカウントでも同様の結果となりました。

### 3-3. 日本環境＆英語の結果

![copilot07.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103396/c37ff465-e639-f32e-785c-1d457a79793f.jpeg)

では、プロンプトを英語にしてみたらどうだろう？と試してみたところ「3-1. 米国環境＆日本語の結果」のようにワークフローが作成できました。

## 最後に

現時点では「地域間のデータ移動を有効化する」を行っても、日本環境＆日本語の組み合わせではまだCopilotを利用できないようです…。
環境ごとに出力結果が違う、というところは実際に使うときにハマるポイントになりそうなのでお気をつけください！
箱庭のUnityアセットをﾁｮｯﾄﾀﾞｹ変更してみる 

箱庭のアセットがいくつか公開されていて、ちょっとだけ修正したいんだけど、Unity力ほぼゼロの私がやったことを書いてきます。

# どんな人向けか
- [箱庭のプロトタイプ](https://toppers.github.io/hakoniwa/prototypes/)は動かしてみたことある（動かす環境はインストール済み）
- Unityｾﾞﾝｾﾞﾝﾜｶﾝﾅｲ（Unityの言われた操作はできるけど、ググってもわからないこと多し）

(自分のUnityレベルです)

# お題
Unityの制御モデル側はさわらず、環境（背景とか）をちょっとだけ変更して仮想シミュレーションを動かしたい
`ライントレースのコースがあるんだけど、ラインの間隔をちょっと広げてほしいんだよなー`
![スクリーンショット 2023-12-16 144628.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26274/daf8b461-663d-eca9-826d-3190802da5a3.png)

## 方針
- ラインはUnityのオブジェクトになっている
- ラインは格子状になっているので、この位置を移動させれば何とかなるんじゃないか
- ロボットの位置の変え方はわからないので、左の縦線と手前の横線の位置は変えない（ロボットのスタート位置は変更しない）

# Unityの編集

## 真上からのビューに切り替える
最初起動するとこんな感じになっているので、真上からのビューに切り替えたい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26274/9107cdbf-1884-d3d4-9771-29613dbf058e.png)

自分はいつもシーンビューの操作がうまくできない。3Dゲームが下手なのも同じなんだろう。
シーンビューは右上にある、「シーンギズモ」の円錐のところをクリックすると座標軸の視点に切り替えてくれるらしい。
[【Unity基礎】 シーンビュー(3D)の視点操作(移動)方法まとめ](https://nekopro99.com/scene-view-navigation/)

円錐のところポチポチっと押して、キーボードの矢印キーなどで位置をあわせるとこんな感じに。（ロボットが右上になってしまったが、気にしないことにします）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26274/ddef33f9-3980-9341-a6ba-2b4e1f349ddf.png)

## 縦線のラインの位置を変更する
ラインのオブジェクトはHierarchyビューの`Hakoniwa/Hakoniwa/ENV/Line-` にあります。（これは箱庭アセットでそれぞれ異なります）
選択すると、該当するオブジェクトが赤く選択され、Inspectorビューが表示されます。
これで各オブジェクトがどの位置にあるのか確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26274/ecc4d6ad-5dca-d233-bdd5-03c6cca0824d.png)

今回はLine-1,2,3が縦線で右から番号が振られていました
InspectorビューにあるTransformのPositionを見ると数値が次のようになっていましたので、この数値を変更して間を1.3倍にしてみます。

| LINE | Position | Position変更後 |
|:-:|:-:|:-:|
| Line-1 | 0  | 0  |
| Line-2 | -1  | -1.3  |
| Line-3 | -2  | -2.6  |

そうすると、縦線の間隔が広がりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26274/f96e9354-7adb-25e7-9b01-5429b93c72ce.png)

## 横線のライン位置を変更する
同様に横線になっているオブジェクトの位置情報を確認します。
それぞれの位置を見るとZ軸の数値が変わってたので、それを変更すればいいんでしょう（たぶん）

| LINE | Position | Position変更後 |
|:-:|:-:|:-:|
| Line-4 |  1.5  |  1.5  |
| Line-5 |  0.5  |  0.2  |
| Line-6 | -0.5  | -1.1  |
| Line-7 | -1.5  | -2.4  |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26274/0bbd8c66-8345-0818-32a5-2d52b0ae56e0.png)

## 縦線のラインを伸ばす
間隔は広がったんですが、手前の横線まで縦線が伸びないとコースとして成立しなくなるのでこの長さを変更する必要があります。
このアセットでは線のオブジェクトは`Cube` で作成しています。
オブジェクトを選択するとTransformの位置が表示されます。Z座標の変更でよさそうです。

| LINE | 変更前 | 変更後 |
|:-:|:-:|:-:|
| Position | 0.276 | -0.5  |
| Scale    | 4     | 5.5 |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26274/dd1a2d9c-20fd-2b8f-a35f-4f0c0cd07106.png)

# 箱庭で動かしてみる
修正が終わったので、箱庭のシミュレーション環境で実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26274/3fe105d8-84cf-01b6-0951-db3da354c1e3.png)

一番上の画像よりも、ロボットと線の間隔が広がったことがわかります。
シミュレーションの環境をちょっと変えるだけなら、制御アプリに関係なく可視化と環境情報を取得するUnity側を変えるだけになります。

# 可視化アセット大募集＆箱庭イベントやってます
箱庭ではUnityやUnreal Engineなど箱庭の可視化アセットを一緒に作ってくれる方を大募集中です。毎月connpassでチュートリアル会などやっていますので、お気軽にのぞいてください。
https://hakoniwa.connpass.com/
Quasar Framework と android の実機開発について


## Quasar Framework でできること
quasar は開発ツールなのでデバックに関する手際のよい手法を編み出しています。
"WebView を使うリモートデバッグ" でして、実機からWifi経由で開発環境につなげる操作を次のコマンドで呼び出せます。

```
  quasar dev -m cordova -T android
```
あくまで開発用なので注意してください。
開発端末の電源を落としたり、Wifiの接続を切れば画面そのものの表示が途切れます。

実機で動かせるパッケージは別の方法で用意します。

## 実機で動かせるパッケージを用意する
ほぼ quasar 公式の解説通りです。

* android studio をＤＬする。
* jdk 8 をＤＬする。
* android 開発ツールのパスを環境変数に追加してコマンドから呼べるようにする。
 (android tools と android platform-tools)
* 次にデバイスを用意する。
* android studio から android APIをDLする。
（デバイスのandroid version に合わせた APIを選ぶ）
* emuratorを追加する。
（サンプルプロジェクト hello word を作って一度再生してみると簡単。wizerd から download できる)
* device 接続の確認
（上記の wizerd と同じ場所でできる）
* quasar のプロジェクトを開発で実機起動する
```
  quasar dev -m cordova - T android
```
* quasar のプロジェクトをリリースアプリにして実機で起動する
※ リリースアプリの実機確認はエラーになりましたので、おそらく電子著名が必要です

```
  quasar build -m cordova - T android
```
* 実機でデバックアプリを起動する

```
  cordova run android --device
```

箇条書きですが以上です。
Dockerのメモ

Dockerに苦手意識があったのですが、わかりやすい解説を見て次の点がイケてるなって感じました。ポイントは<b>モダンな開発みたいにインフラ構築もコマンドでサクサク</b>です。

## Docker の利点

**Docker hub がある**

docker環境をパッケージ化したimageファイルはdockerhubで検索できます。
だいたい思いつく一般的な構成のimageはもうサイトにあるのでmysqlとかubuntuとか検索して持ってこれます。

ソフトやサーバを一つずつインストールする手間が不要になるだけでずいぶん楽ですね。
（いわゆる現場猫作業が不要です。ヨシ！なに見てヨシって言ったんですか？インフラ的に言えば手順書がほぼ不要です）

**手順を細かく設定できる**

ソフトをダウンロードして各種設定するとか一度設定ファイルを作ると使いまわせます。
またimageコンテナはgitのようにコマンドでローカルにダウンロードできます。

他にもコマンドがありましてDockerfile 1枚で以下のような管理ができます。

* 基礎に使うimageファイルを指定する
* ローカルのファイルをコンテナにコピーする
* Pythonのモジュールのインストールを指定のファイルから行う
* 環境変数設定
* 作業ディレクトリ設定
* ネットからファイルを追加
* コマンドの実行

**起動状態をGUIツールでチェックできる**

imageの起動状態も**docker for windows**ってGUIツールで現状を確認できるのでぼーっとしてても大丈夫です。

**環境が共有できる**

一度imageファイルを作っておけば人の入れ替わりがあっても環境を共通化できます。
なので人が入れ替わった初回は楽できますね。

**Docker以前 / Docker以後**

:::note warn
平成頃だと仮想OS環境の構築はソフトで実現してたんですけどこれがめんどくさい。
（パーティション切ったり、一度切ったら細かくすると隙間ができてめんどくさいとか、インストールにちょー時間かかるとか...etc）
今はDockerのコンテナで仮想環境をパーティション空間を気にせずポコポコ使いまわせます。って話でコンテナってなんだ？？ってなりがちですけどコンテナには大した意味ないので安心です。
:::

## プログラム環境の構築
例えばMySQLの環境を構築したらDBにコネクションしてデータ確認したいですよね。
そのためにローカルにPythonとか入れてコネクション張るパッケージを追加したりコネクションを張るコードを書いて実行したりとあります。
pythonの場合はpipもいいですけどpyenvも似たことできるのでそっちもいいなとかでした。

で開発環境はanacondaかvanillaかあるんですけど、データサイエンス専門ならanancondaでpythonで諸々開発したいならvaniraで環境組めるとスッキリしていいよねって話がありました。


## まとめ

過去の苦手意識から食わず嫌いしてましたが今はずいぶん使いやすくなったよって懺悔の記事でした。

わかりやすい解説動画はこちら

https://www.youtube.com/watch?v=B5tSZr_QqXw
VuetifyでFont awesomeを使用してみた

[Material Design Icons](URL "https://pictogrammers.com/library/mdi/"), [Material Icons](URL "https://fonts.google.com/icons"),  [Font Awesome 4](URL "https://fontawesome.com/versions"), [Font Awesome 5](URL "https://fontawesome.com/")

公式ドキュメントによると、上記4つがVuetifyでサポートされているとのことなので、Font Awesome5を導入して使用してみた。

__環境__
・MacBookPro M1 2020(OS Sonoma14.1.1)
・Vuetify3.4.7
・Node.js 17.9.1
・Vue 3.2.0
・yarn 1.22.19
・TypeScript,Vue-Router導入

## 1. Font awesomeインストール
```
yarn add @fortawesome/fontawesome-free -D

// CDNの場合は以下をファイルに挿入
// <link href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" rel="stylesheet">
```

## 2. src/plugins/vuetify.tsに以下追加
（TypeScriptを使用しない場合はsrc/plugins/vuetify.js）

```
import "@mdi/font/css/materialdesignicons.css";
import "vuetify/styles";
import { createVuetify } from "vuetify";
// 追加
import "font-awesome/css/font-awesome.min.css";
import { aliases, fa } from "vuetify/iconsets/fa4";

export default createVuetify({
  theme: {
    themes: {
      light: {
        colors: {
          primary: "#1867C0",
          secondary: "#5CBBF6",
        },
      },
    },
  },
  // 追加
  icons: {
    defaultSet: "fa",
    aliases,
    sets: {
      fa,
    },
  },
});
```

## 3. Font awesomeからデザインを選択、コードコピー
![スクリーンショット 0005-12-16 14.34.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588992/3fb9d542-b57f-1586-8161-1363a9692024.png)

![スクリーンショット 0005-12-16 14.35.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588992/6150ed92-fbfc-0e40-aafc-7a4f5b874ac3.png)

## 4. ヘッダーにハンバーガーアイコンを追加
```
  <v-app-bar flat>
    <v-app-bar-title>
      <v-icon icon="fas fa-bars" style="color: #d24bc0" />
      //こちらの書き方でもOK
      //<v-icon style="color: #d24bc0">fas fa-bars</v-icon>
    </v-app-bar-title>
  </v-app-bar>
```
## 5. yarn devで起動、無事挿入を確認
![スクリーンショット 0005-12-16 14.39.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588992/54f1bd04-bc18-a2dd-7c25-e15957ace117.png)

以前VueでFont awesomeを導入したことがあったが、Vuetifyではなかったので勉強になった。
ハンバーガーをCSSで1から作成すると結構大変だけど、挿入のみで簡単に実装できるのは楽〜！
【ゼロから学ぶNuxt3×Typescript】③component作成-2

Nuxt３×TypeScript 学習
下記の参考サイトを見ながら、Nuxt３とTypescriptを学ぶ第３回。

▼　神回|vue3.js nuxt3 typescriptどうやる？【ゼロから解説】

https://field.asia/%E7%A5%9E%E5%9B%9Evue3-js-nuxt3-typescript%E3%81%A9%E3%81%86%E3%82%84%E3%82%8B%EF%BC%9F%E3%80%90%E3%82%BC%E3%83%AD%E3%81%8B%E3%82%89%E8%A7%A3%E8%AA%AC%E3%80%91/


前回はこちら👇

https://qiita.com/sakuc47/items/e9c6724930293208d225

第1回はこちら👇

https://qiita.com/sakuc47/items/2770d40720070b682ee9


では始めます！！🧙

### 1.`/jobs/[id].vue`を編集
<INS>・/jobs/[id].vue</INS>

```vue
<template>
  <p>あなたの名前は{{ name }}</p>
  <input type="text" name="name" v-model="name">
</template>

<script>
// nuxt3から導入されたref関数をvueのモジュールからimportしている
// [ref関数]_リアクティブ(状態管理)の値を定義するための関数
// https://field.asia/%E7%A5%9E%E5%9B%9Evue3-js-nuxt3-typescript%E3%81%A9%E3%81%86%E3%82%84%E3%82%8B%EF%BC%9F%E3%80%90%E3%82%BC%E3%83%AD%E3%81%8B%E3%82%89%E8%A7%A3%E8%AA%AC%E3%80%91/

import {ref} from 'vue'

export default {
  setup() {
    const name = ref("");

    return {
      name
    }
  }
}
</script>

<style>
</style>
```

http://localhost:3000/jobs/hoge

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524465/793da2c4-9367-d239-2a85-060aaf32dbc5.png)


#### ▼ref関数とは

- Nuxt3から導入された関数
` import {ref} from 'vue' `　でvueモジュールからimportしている。

- リアクティブ（状態管理）の値を定義するための関数
- setupの中で`const name = ref(’’)`のように定義できるようになる
- オブジェクト以外の状態管理
    - オブジェクトは`reactive`を使う

:::note info
**リアクティブなデータとは**
データの変更に対して自動的に反応する性質
:::

v-modelでnameを指定することによって、
`value=”XXX”`の`XXX`がリアルタイムでnameに渡され、
{{name}}としてリアルタイムに表示されます。

#### <INS>※vue2からvue3への変更点</INS>
vue2.Xでは`<template>`内を`<div>`で囲む必要があったのですが、3.Xでは複数のルートノードを持てるようになりました。
（必ずしもdivで囲む必要はない）

```vue
<!-- Layout.vue -->
<template>
  <header>...</header>
  <main v-bind="$attrs">...</main>
  <footer>...</footer>
</template>
```
▼Vue.jsの公式ドキュメント
https://vueframework.com/docs/v3/ja/guide/migration/fragments.html#_2-x-%E6%A7%8B%E6%96%87

勉強で使用したコードも修正しておきます。

### 今回はここまで



### 参考サイト

https://nonakayasuo.com/ref/

https://zenn.dev/simsim/articles/1abff49327109f
EV3モータをEV3以外のマイコンで動かす

レゴMINDSTORMのパーツはロボットのハードをつくるには非常に有用ですが、肝心のEV3本体のサイズ大きく、小型のロボットを作成するときにネックになります。そこでEV3モータを直接Arduinoやその他マイコンに繋いで動かす方法を紹介します。

# EV3モータについて
https://depfields.com/dcmotor-pwmcontrol/#i-2
上記のサイトを参考にするとEV3のコードの白と黒の線がモータを動かすのに必要であることがわかります。実際にこの2線に電池を繋ぐとモータが動くことが確認できると思います。今回はトランジスタを使ってモータの回転を制御します。

# 使用したもの
・EV3モータおよび接続ケーブル
・Arduino Nano Every
・npnトランジスタ(2sc1815)
・抵抗(1.5kΩ)
・電池(単４×１)
・ブレッドボードやジャンパーワイヤ、ピンソケットなど


# モータを動かす
写真のようにEV3用のコードを切断して、代わりにそれぞれの線にピンソケットをはんだ付けしました。このうち赤緑青黄は今回は使いません。

![ケーブル](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654830/2e373ba1-f153-e2ef-0051-9a41b207d09c.jpeg)


このコードを使って以下のような回路を組みます。モータの部分はコードの黒と白の線にそれぞれ繋ぎます。（Arduinoの電源はPCから）

![回路](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654830/3f17b7de-41e8-48d0-e09d-96bd3525f6dc.png)

ブレッドボードに作った回路は以下の通り。

![ブレッドボード](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654830/9251201b-c485-14e8-260a-b3ea87b145b0.jpeg)

プログラムはArduinoIDEで以下のものを作成しました。１秒ごとにモータが回転と停止を繰り返します。モータの回転中はLEDが光るようにしています。

~~~motor_test.ino
#define MOTOR 2
#define LED 13

void setup()
{
  pinMode(MOTOR, OUTPUT);
  pinMode(LED, OUTPUT);

  digitalWrite(MOTOR, LOW);
  digitalWrite(LED, LOW);
}

void loop()
{
  digitalWrite(MOTOR, HIGH);
  digitalWrite(LED, HIGH);
  delay(1000);

  digitalWrite(MOTOR, LOW);
  digitalWrite(LED, LOW);
  delay(1000);
}
~~~


プログラムを書き込んで実際に動かした様子です。ArduinoでEV3モータを制御できました！
![movie](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654830/1015266b-e99b-ea7f-97ea-49eef468b13a.gif)


# 終わりに
ハードはレゴベースでつくりたいけど、EV3は使いたくないという方の参考になればと思います。
ブロック変数とは？

ブロック変数は、Rubyのプログラミングにおいて、ブロック内で使われる変数のことです。


ブロックは、do ... end または { ... } で囲まれたコードの塊で、イテレータメソッド（例えば each, map, select など）と共に使用されます。


ブロック変数は、これらのイテレータメソッドによって供給される値を受け取るために使用されます。

## ブロック変数の特徴と動作
**定義と範囲**

ブロック変数は、ブロックの開始部分で | |（パイプライン）の間に定義されます。
この変数はブロック内部でのみ有効で、ブロックの外部からはアクセスできません。


**値の受け取り**

ブロック変数は、イテレータメソッドから値を受け取ります。例えば、each メソッドが配列の各要素を順にブロック変数に渡します。


## 使用例

例えば、[1, 2, 3].each do |number| の場合、number はブロック変数です。each メソッドは配列 [1, 2, 3] の各要素を順に number に渡し、その都度ブロック内のコードが実行されます。

``` ruby
# 配列の各要素を表示
[1, 2, 3].each do |number|
  puts number
end
```
**出力**

```
1
2
3
```

**複数のブロック変数**
いくつかの場合（特にハッシュを処理する場合など）では、複数のブロック変数を使用することがあります。例えば、hash.each do |key, value| では、2つのブロック変数 key と value を使用しています。




``` ruby
# ハッシュの各キーと値を表示
{a: 1, b: 2}.each do |key, value|
  puts "#{key}: #{value}"
end
```
**出力**

```
a: 1
b: 2
```
ブロック変数はRubyのブロックを使ったプログラミングにおいて非常に重要で、コードの柔軟性と表現力を高めるためのキー要素です。
kaggle winners callの流れ

# はじめに
<!-- 発端や概要を記載 -->
初めまして[luddite^](https://www.kaggle.com/ludditep)です。KaiRAアドベントカレンダーの15日目の記事として、先日kaggleの音声認識コンペ「[Bengali.AI Speech Recognition](https://www.kaggle.com/competitions/bengaliai-speech)」で賞金を獲得し、その際winners callを受けたため、その流れを書きたいと思います。


# 目次
<!-- タイトルとアンカー名を編集 -->
1. [winners callとは](#Chapter1)
1. [winners call当日までの流れ](#Chapter2)
1. [winners call当日の流れ](#Chapter3)
1. [終わりに](#Chapter4)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# winners callとは
kaggleはデータ分析・機械学習の世界的なコンペティションプラットフォームであり、世界中のデータサイエンティストがコンペに参加して予測精度を競います。いくつかのコンペでは上位入賞で賞金を獲得することができ、賞金獲得チームは後日winners callを受けることになります。名前的に電話で賞金獲得を祝ってくれるみたいな楽しげなイベントを想定しますが、そんなわけもなく、コンペのホストに対してwebミーティングで自身の解法のプレゼンテーションを行うという非常に~~面倒な~~光栄なイベントです。
kaggleで賞金を獲得したことがある人は少なく、ネット上にもwinners callに関する情報があまりないため、後世のために私の体験を残しておこうと思います。


<a id="#Chapter2"></a>
# winners call当日までの流れ
2023年10月17日:
コンペ終了。

2023年10月20日:
順位確定。
コンペホストからメールが来て、2週間以内に以下のことが求められる。
解法とリーダーボードのスコアを再現できるコードの共有。
⇒discussionで解法を書く。学習のワークフローとコードをgithubで1つのリポジトリにまとめて公開する。
kaggleのteamタブからモデルの提出。
⇒提出ファイルの容量上限的にモデルの重みを提出できないため、上記のリポジトリをzipファイルにしてそれを提出する。
competition close formというgoogle formの提出。
⇒名前や住所、payoneerのアカウント、賞金の分割法、winners callに応じられない日程を記入する。payoneerは海外送金を受けるためのサービスで、アカウントの作成時に免許証かパスポート(マイナンバーカードは不可)の写しが求められることがある。コンペ終了1週間前位にどちらも持っていない場合は、急いでパスポートを発行しに行く。

2023年11月23日:
コンペホストからwinners callに関するメールが来る。
⇒20分程度の発表スライドを作成する。winners callの日程候補が2つ与えられたため、どちらがよいか選択する(交渉の余地あり)。前日までに作成したスライドをホストに送る。


<a id="#Chapter3"></a>
# winners call当日の流れ
2023年12月5日午前9時に開催されたwinners callには、コンペホスト2名、Kaggle職員1名、私たちのチーム3名、及び2位のチームから1名の合計7名が参加しました。イベントはコンペホストの自己紹介で始まり、2位チームのプレゼンテーション、続いて私たちのプレゼンテーションと質疑応答が行われました。交流は全て英語で行われるため、質疑応答に不安がある場合は事前にメールで質問を送ることをお勧めします。運が良ければ事前に回答が得られますが、運が悪いと返信がないか、当日まったく異なる質問が投げられることがあります。

参考までに、私たちが受けた質問は以下の通りです。「デノイズ処理に特殊なワークフローを用いた理由は何か」、「デノイズの効果の程度はどうか」、「解法で最も計算コストが高い部分はどこか」、「より高性能な計算機を使用できる場合の改善策は何か」、「リアルタイム推論は可能か」、「さらなるデータ収集が必要な場合、どのようなデータがどれだけ必要か」などです。

最後には、質疑応答とは別に広報用のQ&Aセッションがあり、これに回答してイベントは終了しました。


<a id="#last"></a>
# 終わりに
kaggleで賞金獲得した際の流れについて説明しました。英語でプレゼンテーションと聞くとすごいハードルが高いように思いますが、実際にやってみると大したことないことに気づきます。「賞金をとった」というとkaggleを知らない人にも実力を示しやすく、対外的にもウケがいいので、ぜひメダルだけでなく賞金も狙ってみてください。

皆様、よきkaggleライフを～
ﾋﾟﾋﾟｰｯ！同一生成元ポリシー違反です！

# 背景
ローカルで開発中にjavascriptで同じディレクトリの画像を読み込もうとしたらエラーが出た。
原因を調べるとどうやら同一生成元ポリシーが理由とのことだったのでこれを機に調べてみた。

# 同一生成元ポリシーとは？

> 同一オリジンポリシーは重要なセキュリティの仕組みであり、あるオリジンによって読み込まれた文書やスクリプトが、他のオリジンにあるリソースにアクセスできる方法を制限するものです。 
引用元：[同一オリジンポリシー](https://developer.mozilla.org/ja/docs/Web/Security/Same-origin_policy)

つまりあるプログラムから参照できるリソース（画像など）を制限しているという事だと思う。
それでは制限の基準にしているらしい「オリジン」とは何か。

## オリジンとは？
以下の要素の組み合わせのこと
- スキーム（プロトコル）
- ホスト（ドメイン名）
- ポート番号

例えば次のURLではそれぞれ以下の箇所を意味する
```
http://www.example.com:80/folder/image.png
```
- スキーム：`http://`
- ホスト：`www.example.com`
- ポート番号：`80`

つまりこの例では `http://www.example.com:80` の部分がオリジンになる。

### ポート番号がurlに含まれていない場合はなんなの？
プロトコルによって規定のポート番号が決まっており省略されている。
|プロトコル|既定のポート番号|
|---|---|
|http|80|
|https|443|


### オリジンの一致と不一致
オリジンが一致しているかどうかについて分かりやすい例があったので以下で一部引用する。

**`http://store.company.com/dir/page.html` とオリジンが一致するものとしないもの**

|URL|結果|理由|
|---|---|---|
|http://store.company.com/dir2/other.html|同一オリジン|パスだけが異なる|
|http://store.company.com/dir/inner/another.html|同一オリジン|パスだけが異なる|
|https://store.company.com/page.html|不一致|プロトコルが異なる|
|http://store.company.com:81/dir/page.html|不一致|ポート番号が異なる (http:// は既定で 80 番ポート)|
|http://news.company.com/dir/page.html|不一致|ホストが異なる|

表引用元：[同一オリジンポリシー](https://developer.mozilla.org/ja/docs/Web/Security/Same-origin_policy)


## それでは改めて、同一生成元ポリシーとは？
「あるプログラムが異なるオリジンのリソースを参照できないように制限するセキュリティの仕組み」

これで納得です


# 疑問：なぜローカル開発中にこのエラーが出たのか
冒頭でお伝えした通り、私はローカルで開発中にこのエラーに遭遇した。
内容としてはwebGLでオブジェクトにテクスチャを張り付けるというシンプルなものだった。
index.htmlもimage.pngもアクセスする際はfileスキームを使用しているのに生成元が異なるというのがピンとこなかった。


```plaintext:ファイル構成
root
∟index.html
∟script.js
∟image.png
```

```javascript:script.js
var image = new Image();
image.src = 'image.png';
```

## エラーが出た理由
[ここ](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy) より

> Modern browsers usually treat the origin of files loaded using the file:/// schema as opaque origins. What this means is that if a file includes other files from the same folder (say), they are not assumed to come from the same origin, and may trigger CORS errors.

翻訳するとこんなかんじ
> 現代のブラウザは通常、`file:///` スキーマを使用してロードされたファイルの起源を不透明な起源として扱う。これは、例えばあるファイルが同じフォルダから他のファイルを含む場合、それらが同じ起源から来たとは仮定されず、CORSエラーを引き起こす可能性があることを意味する。

つまりfileスキームでアクセスしたリソースは生成元不明扱いになるということ。
少なくとも私が試したchromeではこのように扱われるためエラーが出ていたことがわかった。

## 対策
①chromeの起動オプションで同一生成元ポリシーを無視して実行する
セキュリティリスクではあるので開発でのみ使用するべき
※何か問題が生じても当方では責任を負いかねます

②webサーバを立てる
こっちの方が無難だと思う
クリスマスに自分へのプレゼント！自分だけのTシャツをProtoPedia APIで作ってみた！

# 1. 自分へのクリスマスプレゼント

みんな、クリスマスが近づいてきましたね！今回は、クリスマスプレゼントにぴったりな、自分だけのオリジナルTシャツを作る方法を紹介します。ProtoPediaのAPIを使って、自分の人気作品をTシャツにできるサービスを作ってみました。

https://blue-islands.github.io/protopedia-t-shirt/

# 2. 人気のある作品をTシャツに並べる

ProtoPediaで自分の作品の中から、アクセス数が多いトップ8をAPIで選び出しました。これらの作品をTシャツにすることで、自分のクリエイティブな成果をさらに多くの人に共有できるんです。

# 3. Tシャツの作り方:

## APIからデータ取得

まずは、ProtoPediaのAPIを通して、自分の人気作品のデータを取得します。

![データ取得イメージ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20464/82913dae-b653-7188-138c-eca871bccc80.png)

以下の項目を入力する必要があります。
- **タイトル**: Tシャツに表示したいタイトルを入力します。
- **ユーザーID**: ProtoPediaのプロフィールのページの@以降に表示されているIDを入力します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20464/b65ab5c1-3228-5355-d1f1-199bedc277ca.png" width="400">

## デザインの決定

人気作品をベースに、ランダムに作品とQRコードの生成がされます。お気に入りの作品ができるまで、何回でも試してみましょう。

![デザイン例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20464/b6e0bb66-5893-bd63-4edd-4c5ca05c77ab.png)

## QRコードでアクセス簡単

各Tシャツには、作品ページへのリンクを含むQRコードをプリント。これで、誰でもスマホでQRコードを読み取って、作品の詳細をすぐにチェックできます。

## 生成された画像を使ってオリジナルグッズを作る

生成された画像をダウンロードして[**SUZURI**](https://suzuri.jp/)などのオリジナルグッズを作成できるサービスを利用してTシャツを作成します。マグカップやステッカーなどを作成してもいいと思います。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20464/bc089ce7-582b-5627-9827-5bc8c90d1eb5.jpeg" width="400">

# 4. 実際の制作体験

- **試行錯誤の楽しみ**: 人気作品を選び出してTシャツにデザインする過程は、自分の創造性を再発見する素晴らしい機会でした。
- **完成したTシャツ**: 出来上がったTシャツを実際に着てみると、自分の作品が新しい形で生まれ変わった感じがして、とても嬉しいです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20464/c897c999-45be-1134-6473-6ac1b39ac277.jpeg" width="400">

# 5. まとめ

- **個性的なクリスマスプレゼント**: 自分の人気作品をTシャツにすることで、他にはない特別なアイテムが完成します。
- **クリエイティブな共有**: これらのTシャツは、自分の創造性をより多くの人に広める新しい方法として活用できます。

クリスマスには、自分だけのオリジナルTシャツをプレゼントしてみませんか？ProtoPedia APIを使って、あなたのクリエイティビティが輝く瞬間を楽しんでみてください！

https://blue-islands.github.io/protopedia-t-shirt/