OmniAICreator/Qiita-1.07M huggingface dataset:
S3アップロードをトリガーにDataSpider Servistaのスクリプトを実行する

# はじめに
弊社製品のDataSpider Servista（以下DataSpider）にはファイルトリガーというファイル配置をトリガーに処理を実行する機能があります。

https://www.hulft.com/software/dataspider

担当システムのクラウド移行に伴って、ファイル配置場所をS3に変更する案がありました。
大量のファイルトリガーで動く処理をいかに工数少なく移行するか、検証まで行いましたが、S3案はボツとなりお蔵入りになってしまいました。
せっかくなのでこの場でご紹介いたします。

# 構成
まず移行前の構成はこのようになります。

![before.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3941080/e49714e5-4788-178e-69f3-f37b385acdde.png)

1. 監視フォルダーでファイルを配置する
1. DataSpiderのファイルトリガーが発火して処理が実行される


AWS移行後はこのような構成を検討しました。

![after.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3941080/5791bcf7-e441-de20-6987-35d97bd6bd7c.png)

1. S3にファイルを配置する
1. putイベントでLambdaを発火
1. LambdaでDataSpiderに対してHTTPリクエストを行う
1. DataSpiderのHTTPトリガーがじっこうS3からのファイルダウンロード処理が実行される
1. ファイルダウンロードによるファイル配置により、DataSpiderのファイルトリガーが発火して処理が実行される

# Lambda
Lambdaのコードはこのようになります。
```
import json
from urllib import request

def lambda_handler(event, context):
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = event['Records'][0]['s3']['object']['key']
    url = 'http://【DataSPiderのパス】/dataspider/trigger/s3put_test?bucket='+bucket+'&key='+key
    res = req(url)
    
    return {
        'url': url,
        'res': res,
    }
    
def req(url):
    get_req = request.Request(url)
    with request.urlopen(get_req) as res:
        body = res.read()
        return body
```

1. イベント情報から「バケット名」と「キー」を取得する
1. DataSpiderに対してHTTPリクエストを投げる
その際リクエストパラメータに「バケット名」と「キー」を設定する

特定のバケットからのputイベントでこちらのLambdaが発火するよう設定をしておきます。

# DaraSpiderのスクリプト
DataSpiderの「S3ダウンロード」スクリプトはこのようになります。

![DSS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3941080/19292509-e5ba-bd40-2775-eeac848b7981.png)

1. HTTPリクエストのパラメータの「バケット名」「キー」を元にS3から監視フォルダへファイルをダウンロードする
1. ダウンロードが成功したらS3のファイルを削除する

# まとめ
共通処理のLambdaとDataSpiderの処理を作成することで、ファイルトリガーで実行するDataSpiderの各処理の修正を不要とすることが出来ました。
今回利用機会はありませんでしたが、今後AWSを活用していく中で活用できればと考えています。
3Dプリンターを活用したオンラインビジネスの始め方

**3Dプリンターを活用したオンラインビジネスの始め方**  

テクノロジーの進化に伴い、3Dプリンティング技術は研究室から一般家庭へと広がりつつあります。起業家にとって、3Dプリンターは単なる便利なツールではなく、収益を生み出す強力なビジネスツールでもあります。3Dプリンターを活用してオンラインビジネスを始めることで、比較的低コストで柔軟かつ革新的な事業を展開することが可能です。以下に、3Dプリンターを活用して利益を上げるための重要なポイントをご紹介します。  

### 1. ターゲット市場を明確にする  
まずは、ターゲットとする顧客層を明確にしましょう。3Dプリンティングは多岐にわたる分野で応用が可能です。例えば、オーダーメイドのアクセサリー、インテリアデザイン、教育用ツール、機械部品などが挙げられます。DIY愛好家向けにパーツを提供したり、結婚式市場に特化したデコレーションアイテムを製作するのも一案です。明確な市場の特定は、デザインや製作の方向性を定め、より多くの顧客を惹きつける助けとなります。  
![71329797e7a43f56c98fbe03172eafa2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/5238b8ea-2ce8-74f5-3e67-54929fcc5457.png)

### 2. カスタマイズをビジネスの軸に  
3Dプリンティングの最大の強みはカスタマイズが可能な点です。従来の大量生産とは異なり、3Dプリンターを使えば、顧客ごとにオリジナル商品を製作することができます。例えば、特定のサイズのフォトフレームや、名前を刻印したアクセサリーなどを提供することで、顧客に特別な価値を届けることができ、競争力のある商品を展開できます。  
![db1abb37e483e496f0d0aed59041402b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/c88ec108-fc1b-225e-8bc2-0ff5a8128675.png)

### 3. デザインプロセスの効率化  
3Dモデリングは初心者にとって難しく感じられるかもしれませんが、3Dスキャナーを使えば既存のアイテムを簡単にスキャンしてプリント可能なデータを作成することができます。また、Fusion 360やBlenderといったモデリングソフトを活用すれば、さらに複雑なデザインも実現可能です。  
![59a4f4f3dcf23fd3c30fd42d0d7937d6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/23645497-181f-de5d-f814-d20b943abd84.png)

https://www.revopoint3d.jp/
### 4. オンラインショップを構築  
製品が完成したら、それを展示・販売するプラットフォームが必要です。EtsyやShopifyなどのプラットフォームは、初心者にとって最適な選択肢です。これらは広範なユーザー層を持ち、支払いと物流の基本機能を提供しているため、デザインや製作に専念できます。また、SNSを活用してマーケティングを行うことで、さらに多くの顧客にリーチすることが可能です。  

### 5. プリント品質と材料選びを重視  
顧客は高品質の製品に対してお金を払います。したがって、高品質な材料と設備を選ぶことが重要です。PLAやABSは初心者向けの一般的な素材で、多くの用途に適しています。ビジネスが成長するにつれて、金属や樹脂を用いたより高級な製品にも挑戦できます。安定したプリント品質を維持することは、良い評判を築く鍵となります。  
![968b45b05e82f8d3acc37c9b35aea3aa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/01dca171-db7b-b89f-4a56-9f02c412e0a2.png)

### 6. 生産効率の最適化  
3Dプリンティングは通常、小ロット生産に向いていますが、需要が増える場合は、プリント時間を最適化したり、プリントレイアウトを調整することで効率を向上させることが可能です。例えば、複数の小型パーツを同時にプリントしたり、高速プリンターを導入することで、生産コストを抑えることができます。  

### 7. サービス内容を拡充  
製品の提供だけでなく、関連するサービスも検討してみてください。例えば、モデリングサービス、3Dプリントの講座やワークショップを提供することで、顧客の興味を引き出し、付加価値の高い収入源を確保することができます。  

  3Dプリンターを活用したオンラインビジネスは、テクノロジーを活用した新しい起業スタイルとして注目されています。市場の特定から商品設計、プラットフォームでの販売に至るまで、各ステップを着実に進めることで、事業は次第に形になっていきます。3Dスキャナーなどのツールを組み合わせることで、より多様なサービスを提供することも可能です。さあ、3Dプリンターを手に取り、創造の一歩を踏み出しましょう！
  
  https://www.revopoint3d.com/
vscode extension を Deno で開発する

VSCode のエクステンションは通常は Node で開発しますが、バンドラーのアウトプットを工夫することで、Deno でも開発できます。

VSCode 向けに Deno スクリプトをバンドルする際に気を付けることは以下の点です。
- VSCode がエクステンションとして読み込めるのは CommonJS 形式のみ
- "vscode" パッケージは vscode 本体への依存なのでバンドルしてはいけない

これを実現するための esbuild の設定は以下のようになります。

```ts:build.ts
import * as esbuild from "npm:esbuild@0.24";
import { denoPlugins } from "jsr:@luca/esbuild-deno-loader@0.11";
import { resolve } from "jsr:@std/path@1";

const result = await esbuild.build({
  plugins: [...denoPlugins({
    configPath: resolve("path/to/deno.json")
  })],
  entryPoints: ["src/extension.ts"],
  outfile: "out/extension.js",
  bundle: true,
  external: ["vscode"],
  format: "cjs",
});
esbuild.stop();
```

上のビルドスクリプトを実行すると、`src/extension.ts` がビルドされて、ビルド結果が `out/extension.js` に出力されます。ビルドの際に、`import * as vscode from "vscode"` 以外の import 文が全てビルド結果に含まれるため、この状態で、vscode から見て実行可能なスクリプトになります。

なお、[`@kt3k/pack`](https://jsr.io/@kt3k/pack) を使うと以下のように少し簡潔にビルドコマンドを書くことも出来ます (内部的に上と全く同じビルドが実行されます)

```sh
deno -A jsr:@kt3k/pack@0.1.14 src/extension.ts -o out/extension.js --external vscode --format cjs
```


`package.json` の `main` に `./out/extension.js` を設定することで、このバンドルを VSCode Extension として実行できます。

また、`import * as vscode from "vscode";` を Deno で型チェック出来るようにするためには、以下のように記述します。

```ts:extension.ts
// @ts-types="npm:@types/vscode";
import * as vscode from "vscode";
```

これで、`vscode` 名前空間に適切な型があたります。また、"vscode" というモジュール指定子はDeno から見た場合は実体がないため、import map でこれを空のファイル (空の empty.ts ファイルを作ってください)に向けておきます。

```json:deno.json
{
  "imports": {
    "vscode": "empty.ts"
  }
}
```

以上の設定で、vscode extension 開発を Deno だけを使って行うことができます。

以下のレポジトリは、ここまで説明した設定を使って、ピクセルエディタの VSCode Extension を筆者が開発しているサンプルです。

https://github.com/kt3k/vscode-pixeledit
下書き

サンプル

```
import re

def extract_content(file_path, keyword):
    with open(file_path, 'r', encoding='utf-8') as file:
        content = file.read()
    
    # 正規表現で "keyword" の後ろの {} 中の文字を抽出
    pattern = rf"{keyword}\s*{{(.*?)}}"
    match = re.search(pattern, content, re.DOTALL)
    
    if match:
        return match.group(1).strip().splitlines()  # 行ごとに分割してリストとして返す
    else:
        return None

# 使用例
file_path = "example.txt"  # 抽出元のファイルパス
keyword = "hoge"           # 検索キーワード

result = extract_content(file_path, keyword)

if result:
    print("抽出結果:", result)
else:
    print(f"{keyword} に対応する内容が見つかりませんでした。")
```
【Java】なぜ List<Dog> は List<Animal> のサブクラスではないのか？【ジェネリクス】

```java
// Animalリストを受け取って出力するメソッド
private void printList(List<Animal> list)

// 上記メソッドにDogリストを渡す
List dogs = getDogList();
printList(dogs);
```

*Dog* は *Animal* のサブクラスだから動作しそう。
でも、これは動作しない。

*Dog* が *Animal* のサブクラスだとしても、
*List\<Dog>* は *List\<Animal>* のサブクラスとは見なされない！

どうして...


## なぜ List だとサブクラスと見なされない？

```java
list.add( new Cat() );
```

*Cat* は *Animal* のサブクラスなのでこれは問題ない。

ところが、listの中身が *List\<Dog>* だった場合、
*List\<Dog>* に *Cat* を格納することになっる！

そういうわけで以下は動作しない。

**・List\<Animal> ← List\<Dog>**



## これを解決する、ジェネリクスのワイルドカード

そこで登場するのがジェネリクスのワイルドカード！

```java
// Animalリストを受け取って出力するメソッド
private void printList(List<? extends Animal> list)
```

こうやって書けば、期待通りに動きます。
つまり *List\<Animal>、List\<Dog>、List\<Cat>* たちが
渡せるようになります。
連想配列とLaravelの内部動作

<p>以前の記事（以下のリンク先の記事）でLaravelの内部動作について少し書きました。その記事では、連想配列が格納された変数自体（つまり、連想配列の形で渡された変数ではない）がそのままコントローラからビューへ渡されたケースについて触れました。今回は、配列の中に連想配列が格納された変数におけるLaravelの内部動作について紹介します。</p>

https://qiita.com/Shuta_Learner/items/71ff522ebf48c022479a

# 連想配列の形で渡された変数
　前提として、基本的には連想配列の形でコントローラからビューへ変数が渡されます。例えば以下のような記述です。

<strong>コントローラ側の記述は以下</strong>
class TestController extends Controller
{
&emsp;public function index(Request $request)
&emsp;{
&emsp;&emsp;`$`data = [
&emsp;&emsp;[
&emsp;&emsp;&emsp;'name' => 'taro',
&emsp;&emsp;&emsp;'city' => 'tokyo',
&emsp;&emsp;&emsp;'sport' => 'soccer',
&emsp;&emsp;&emsp;'age' => 12
&emsp;&emsp;],
&emsp;&emsp;[
&emsp;&emsp;&emsp;'name' => 'jiro',
&emsp;&emsp;&emsp;'city' => 'osaka',
&emsp;&emsp;&emsp;'sport' => 'baseball',
&emsp;&emsp;&emsp;'age' => 14
&emsp;&emsp;],
&emsp;&emsp;[
&emsp;&emsp;&emsp;'name' => 'hanako',
&emsp;&emsp;&emsp;'city' => 'kyoto',
&emsp;&emsp;&emsp;'sport' => 'basketball',
&emsp;&emsp;&emsp;'age' => 13
&emsp;&emsp;]
&emsp;&emsp;];
&emsp;&emsp;return view('test.index', ['data' => $data]);
&emsp;}
}
</p><br>

<strong>ビュー側の記述は以下</strong><br>
`@`foreach(`$`data as `$`item)
    <p>名前：{{ `$`item['name'] }}
    出身：{{ `$`item['city'] }}
    得意なスポーツ：{{ `$`item['sport'] }}
    年齢：{{ `$`item['age'] }}<p/>
`@`endforeach


<p>上記の記述の場合、なぜビュー側で'name'や'city'といったコントローラ側で定義された連想配列のキーが使用できるのでしょうか？</p>

# データバインディング
<p>実は、Laravelのデータバインディングという仕組みが鍵を握っています。<br>データバインディングとは、コントローラで準備したデータがビュー内でそのまま変数として利用できる仕組みのことです。そして、
<strong>もしそのデータが連想配列であれば、そのキーを使ってビュー内で中身（値）にアクセスすることができるようになります。</strong>
<br><br>もう一度先ほどの記述を見ていきます。</p>

<strong>コントローラ側の記述は以下</strong>
class TestController extends Controller
{
&emsp;public function index(Request $request)
&emsp;{
&emsp;&emsp;`$`data = [
&emsp;&emsp;[
&emsp;&emsp;&emsp;'name' => 'taro',
&emsp;&emsp;&emsp;'city' => 'tokyo',
&emsp;&emsp;&emsp;'sport' => 'soccer',
&emsp;&emsp;&emsp;'age' => 12
&emsp;&emsp;],
&emsp;&emsp;[
&emsp;&emsp;&emsp;'name' => 'jiro',
&emsp;&emsp;&emsp;'city' => 'osaka',
&emsp;&emsp;&emsp;'sport' => 'baseball',
&emsp;&emsp;&emsp;'age' => 14
&emsp;&emsp;],
&emsp;&emsp;[
&emsp;&emsp;&emsp;'name' => 'hanako',
&emsp;&emsp;&emsp;'city' => 'kyoto',
&emsp;&emsp;&emsp;'sport' => 'basketball',
&emsp;&emsp;&emsp;'age' => 13
&emsp;&emsp;]
&emsp;&emsp;];
&emsp;&emsp;return view('test.index', ['data' => $data]);
&emsp;}
}


<br>コントローラ内で複数の連想配列が格納された配列が`$`dataという変数として定義されています。そして、return viewの第二引数の部分で、その変数が連想配列の形でビューへと渡されています。ここで、データバインディングの登場です！

<br><strong>ビュー側の記述は以下</strong><br>
`@`foreach(`$`data as `$`item)
    <p>名前：{{ `$`item['name'] }}
    出身：{{ `$`item['city'] }}
    得意なスポーツ：{{ `$`item['sport'] }}
    年齢：{{ `$`item['age'] }}<p/>
`@`endforeach

<br>ビュー内のforeachの中で`$`dataとありますが、これはデータバインディングにより、コントローラ内で準備した変数が使えるからであり、正しいと記述となります。
次に`$`itemとありますが、こちらにコントローラ側で準備された連想配列が代入されています。そしてこれもデータバインディングの仕組みにより、例えば、{{ `$`item['name'] }}というように、キーである'name'を使って値（'taro'、'jiro'、'hanako'）にアクセスすることができるのです。
【UI/UX】生成AI時代に改めて考える、差別化って一体なんだろうか？

:::note warn
本記事は私の経験と考察をまとめたものです。誤りや改善点がありましたら、ぜひコメントをいただけると嬉しいです。:bow_tone1:
:::
:::note
本記事の主な目的は「差別化」という概念の理解を深めることです。
その為、「差別化」という概念に関してよく知らない、説明するのが難しいと感じる方が主なターゲット読者になります。
:::

私は新卒2年目で、肩書上はデザイナーとエンジニアの両方を担当させていただいております。

皆さんは「**差別化**」という言葉をよく耳にしませんか？でも、いざ説明しようとすると難しくありませんか？

私は経済学部経営学科卒なので、学生時代から「差別化」という言葉には馴染みがありました。ただ、正直なところ**差別化=違いを作る**という漠然とした理解で済ませていた部分があります。

また、昨今は生成AIが普及しており、活用すれば他と違うものを量産できるようになりました。その中で差別化の重要性を改めて考える必要があると思います。

「差別化について知りたい方」、「説明が難しい方」など、私と同じように感じている方の参考になれば幸いです:raised_hand:

## 差別化の定義
まず、「差別化」という用語の定義を見ていきましょう。

**広辞苑による定義**
>- 同類の他のものと違いを際立たせること
>- 「他社とは提供するサービスで差別化をはかる」といった用例がある

**Cambridge Dictionary による定義**
>- 明確に他と異なるものにすること
>- 何かを異なるものにする、または異なるものになるプロセス

**マイケル・ポーターによる定義**
>- 競合他社の商品と比較して機能やサービス面において差異を設けることで、競争上の優位性を得ようとすること
>- 同種カテゴリーにある製品やサービスにおいて、基本機能は同じでも、デザインやブランドイメージ、広告などによって価値活動の一部を差異化すること

上記では日英3つの定義を掲載しました。意味としては、「他と異質化すること」や「異質化するプロセス」という私たちがよくイメージするものや「競争上の優位性確保」などのビジネス的なものが挙げられました。

ここからわかるのは少なくとも「差別化」という概念は複数の意味を持っているということです。冒頭の私のように差別化=違いを作るという認識も誤りではないということがわかります。

しかし、私たちが生きている資本主義においては、ビジネス上の定義が特に価値を持つのだと思います。すなわち「**競争優位性を確立するため**」の重要な戦略として行うことですね。恐らく多くの人は「他との違いを作ること」というイメージを持つのではないかと思いますが、ビジネスにおいては単なる違い以上の意味を持つのだと考えます。

また、現代のUIデザインの分野では、ユーザーにとって「意味のある価値」を生み出すことこそが真の差別化だと考えています。単なる見た目の違いではなく、ユーザーの課題解決や体験の向上につながる本質的な価値提供が重要なのではないでしょうか

## 差別化を取り巻く課題
### 手段の目的化
現場で直面する大きな課題の一つが「**手段の目的化**」です。差別化は本来、ユーザーや顧客に価値を提供し、結果として利益を生み出すための戦略的プロセスです。しかし時と場合によっては「とにかく他と違えばいい」という考えに陥りがちです。私自身もそういう時があります。

業務でもまず差別化、差別化はどうするかという用語が飛び交う時もあります。
しかし、本来は以下のように最終目的を達成するための手段であるべきだと思います。

![img_differentiated.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624902/0e30acde-712e-a329-618d-812c0e5bfc8d.png)


### 差別化の意味に関する認識の不一致
もう一つの課題は、差別化の意味に関する認識の違いです。多くの人が私と同じように**差別化=違いを作る**と捉えているかもしれません。でも実際は、ユーザーにとって本当に価値のある違いを作ることが重要です。

![img_differentiated2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624902/17b3c7c3-6b7a-e6c0-f5ef-40aa04e662f1.png)

もしかしたら、「差別化=違い」と考えていて、なぜそこまで固執するのかと疑問に思う方もいるかもしれないので、ここに関しては、メンバー間で認識を合わせる必要があるかもしれません。

## UI/UXにおける実践的な差別化アプローチ
UI/UXにおいて差別化を実現するためには以下3つのアプローチがあると思います。
- マーケティング
- UXリサーチ
- ウェブアクセシビリティ

UI/UXの分野で効果的な差別化を実現するには、まず客観的な市場理解のためのマーケティング調査が欠かせません。その上で、体系的なUXリサーチとデザインプロセスを進めていきます。

具体的には、ユーザーの生の声を聞くアンケート調査から始まり、具体的なターゲット像を描くペルソナ設定、ユーザー体験を可視化するカスタマージャーニーマップ、そして提供価値を明確にするバリュープロポジションキャンパスの作成などを行います。

さらに、より多くの人が使いやすいサービスを目指して、ウェブアクセシビリティの向上にも取り組むことが重要です。これらの取り組みを通じて、本質的な価値を持つ差別化が実現できると考えています。

## まとめ
今回は、「差別化」について取り上げました。
- ビジネスにおいて差別化は競争の優位性を確保するための戦略・プロセスそのものである。すなわち、差別化はあくまで目的ではなく、最終目的を達成するためのプロセスである。
- UIデザインにおいて、差別化は単なる「違い」ではなく、「意味のある価値」を生み出すことである

※もちろん地域や考える人の立場によって差別化の捉え方は様々あると思います。

良い差別化には時間とコストがかかります。でも、改めてより良いUI/UXを実現するための重要な指針として、私自身も大切にしていきたいと思いました

本記事を最後までお読みいただき、ありがとうございました！:bow_tone1:
Advent Calendarのリマインドをする

<!-- Advent Calendarのリマインドをする -->

※この記事は[Udon Advent Calendar 2024 - Adventar](https://adventar.org/calendars/10764)の10日目の記事です。

## はじめに

こんにちは。Udonです。このAdvent Calendarも10日目となりました。

さて、Adventarなんですが、マイページからGoogle Calendarなどに投稿の予定を読み込むことができるiCalのURLを取得することができます。

このURLを使って、Advent Calendarのリマインドをする方法を紹介します。

## iCalのURLの取得

まず、Adventarにログインして、マイページに移動します。

マイページの下の方を見ると、iCalのURLが表示されています。形式は以下のようになっています。

```
https://adventar.org/calendars/[UserID].ics
```

これを使っていきます。

## 作ったもの

自分のサークルのサーバで動かすことにしたので、以下のようにサークルのGitLabにリポジトリを作りました。

[pgm_udon / Adventar-Notice · GitLab](https://gitlab.mma.club.uec.ac.jp/pgm_udon/adventar-notice)

Dockerを用いて動作するもので、Pythonベースで記述しました。

## 使い方

1. リポジトリをクローンする
2. .env-sample をコピーして .env を作成
3. .env に必要な情報を記入
4. docker-compose up -d でコンテナを起動

## 動作の様子

1. 午前0時まで待つ
2. スケジュールをiCalから取得
3. 本日の日付を取得
4. 本日が12/26なら終了
5. 本日の日付とスケジュールの日付が一致するものを取得
6. メールを送信

## iCalendar

本当はBeautifulSoupを使って、Adventarのページから情報を取得する方法を考えていたのですが、seleniumを使う必要があり、環境構築が少し大変そうだと思ったので今回はiCalとiCalendarを使ってみました。

```python
def add_schedule():
    url=f'{MYPAGE_URL}.ics'
    with urllib.request.urlopen(url) as f:
        calendar = Calendar.from_ical(f.read())
        schedule={}
        for component in calendar.walk():
            if component.name == "VEVENT":
                dtstart = component.get('DTSTART').dt
                summary = component.get('SUMMARY')
                key=f'{dtstart}'
                element=f'{summary}'
                if key in schedule:
                    schedule[key].append(element)
                else:
                    schedule[key]=[element]
    return schedule
```

この部分でiCalからスケジュールを取得しています。urlは.envに記述した``MYPAHE_URL``を用いることで生成しています。

``urllib.request.urlopen(url)``でiCalを取得し、``Calendar.from_ical(f.read())``でiCalを読み込んでいます。読み込んだデータから、``VEVENT``の部分を取得しています。ここには日付やイベント名などの情報が格納されているので、日付の``DTSTART``とイベント名の``SUMMARY``を取得しています。そして、日付をキー、イベント名を要素として辞書に格納しています。イベントは複数存在する場合があるので、リストとして格納することで複数持てるようにしています。

## メール送信の仕組み

メール送信にはsmtplibを使っています。

```python
def send_mail(subject, body):
    msg = MIMEText(body, "plain", "utf-8")
    msg['Subject'] = subject
    msg['From'] = MAIL_SENDUSER
    msg['To'] = MAIL_RECIEVEUSER
    try:
        server = smtplib.SMTP_SSL(MAILSERVER_HOST, MAILSERVER_PORT)
        server.sendmail(MAIL_SENDUSER, MAIL_RECIEVEUSER, msg.as_string())
        server.quit()
    except Exception as e:
        print(e)
    return
```

``server``部分は各々の環境に合わせる感じですが、自分はサークルのサーバが使えるのでその中で自分自身に送るという流れで実装しています。おそらく、Gmailなどを使う場合は、認証が必要になると思います。

``subject``と``body``はそれぞれ別の関数で、日付とイベント名をもとに精製したものを渡すことになっています。

```python
def make_subject(today_str):
    return f'{today_str}の更新予定'

def make_body(summary):
    res="今日は以下のAdvent Calendarの更新日です。\n\n"
    for s in summary:
        res+=f'{s}\n'
    res+="\n早めに更新してください。"
    return res
```

## おわりに

これで毎日午前0時にAdvent Calendarのリマインドが届くようになりました。更新を忘れることも避けることができそうです。

ではまた、次の記事でお会いしましょう。

## 参考文献

[iCalendarデータの仕様とPythonにおける利用方法 #icalendar - Qiita](https://qiita.com/shi_ma/items/7133cea99fbf1dc5bdc7)
Macで"¥"ではなく"\"を表示させる方法(Hint&Tips)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/2e9195d1-ba51-b632-0c2e-d25d6e5f2e4e.png)
を押すだけだと、円マーク(`¥`)が入力されてしまう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/63940b27-9dd3-5bee-1ed2-9b7fb71b630b.png)
Optionボタンと組み合わせると、`\`が入力できる。
座標圧縮の別解(ABC 213 C問題)

## 本記事の内容
座標圧縮を題材としたABC213 C問題を解説とは違うアプローチで解いたので共有します。

### 本記事で解説する問題
https://atcoder.jp/contests/abc213/tasks/abc213_c

### 問題文
![スクリーンショット 2024-12-10 14.48.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3767231/a2e2941e-2f91-526c-cdca-750f043bdcc6.png)

![スクリーンショット 2024-12-10 14.48.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3767231/e493dfb9-1541-0ef1-990f-0205766ec910.png)


この問題では、サンプルの出力例にある*の行と列を削除して新たな行列を取得する問題です。こちらは**座標圧縮**という処理と言うみたいです。


### 筆者の解法
```Python
from bisect import bisect_left

h, w, n = map(int, input().split())
ab_n = [list(map(int, input().split())) for _ in range(n)]

rows = [ab_n[i][0] for i in range(n)]
cols = [ab_n[i][1] for i in range(n)]

# その数自身に重複があっても問題ないが、それ以前に重複があるとズレる。 setを用いて重複を削除
r_sort = sorted(set(rows))
c_sort = sorted(set(cols))

for i in range(n):
    r_pos = bisect_left(r_sort, ab_n[i][0]) + 1  # 左側のインデックスを返す
    c_pos = bisect_left(c_sort, ab_n[i][1]) + 1
    print(r_pos, c_pos)
```

行と列の配列をそれぞれもち、それらを二分探索でインデックスを取得する方法で解きました。この際に`set`を使用しないと、前の要素の重複により、ズレてしまうため集合に変換することが重要になります(これを忘れてWAしました。)
pythonのindexは0オリジンなので1を加えれば圧縮した座標を取得することが出来ます。

計算量としては、ソート時に`O(NlogN)`、座標取得時に`O(NlogN)`かかっています。全体の計算量は`O(NlogN)`なので十分早く値を取得することが出来ます。


### さいごに
コードの量が増えそうな問題でもシンプルに書けてしまうのがAtCoderあるあるですよね。
解いているときも冷静になってシンプルに書けるようになりたいです。
同期処理と非同期処理

同期処理
　ある処理（タスクA）を実行中に、別の処理（タスクB）を実行しようとすると、タスクAが完了するまでタスクBは待機しないといけない
 →実装は簡単だが、ユーザビリティに問題

 非同期処理
 　タスクA実行中に別のタスクBが介入しても、タスクAを待たずにBを実行できる
  →ユーザビリティは保証されるが、実装が複雑
二人の女性エンジニアの物語

日本のIT派遣業界（SIer）では、結合テストはプロジェクト開発の重要な工程です。私たちのチームには、AさんとBさんという2人の女性派遣エンジニアがいます。彼女たちの役割は、複数のシステムモジュールが順調に統合され、期待通りの機能を果たすことを確認することです。仕事内容は似ていますが、仕事に対する態度は全く異なります。

### Aさん：細心かつ積極的、品質を追求
Aさんは責任感の強いエンジニアです。業界経験はまだ浅いものですか、結合テストの重要性を深く理解しています。テストの実施中、Aさんはテストケースに基づいて厳格に作業を進めるだけでなく、見落とされたシナリオも積極的に補足します。例えば、テスト計画にシステム間の異常処理が含まれていないことに気づき、プロジェクトマネージャーに改善提案を行いました。
細かいログの分析やバグの再現作業など、面倒なタスクに直面しても、Aさんは決して不満を言わず、問題の根本原因を丁寧に探りました。その細やかさがチームを重大なリリース後のトラブルから守り、顧客様からも高い評価を得ました。

### Bさん：受動的で形式的、タスク完了が目的
一方で、Bさんの仕事に対する姿勢は全く異なります。Bさんは指示されていない事項に直面すると、その場で作業を止めて指示を待つことが多いです。例えば、あるテスト中にモジュール間のデータ転送が異常であることに気づきましたが、彼女はそれをテストレポートに簡単に記録するだけで、問題の原因を特定したり、開発チームに相談したりはしませんでした。
この問題がその後のシステムテストで再発し、プロジェクトチームは計画を再調整せざるを得ず、多くの時間とコストを無駄にしました。チーム内では次第にBさんへの期待が薄れ、彼女の評価にも影響を及ぼしました。

### 態度が全てを決める
日本のSIer業界では、派遣エンジニアはしばしばプレッシャーの高い環境で重要なタスクを任されます。AさんとBさんの物語から明らかなように、仕事に対する態度がキャリアの成長に直接影響します。積極的かつ細部に注意を払う人は、同僚や顧客からの信頼を得るだけでなく、学習と経験を積み重ねて自身の専門能力を高めることができます。一方で、受動的で指示待ちの姿勢を取る人は、成長のチャンスを逃し、キャリアに悪影響を及ぼす可能性があります。
SIer業界で努力しているすべての新人エンジニアに対して、私はこう言いたいです。「テストでも、開発でも、あなたの態度がチームでの役割を決めます。情熱とプロフェッショナルな精神であらゆる課題に向き合えば、あなたの努力は必ず評価されます。」
2025年に挑戦したいシステム開発のアイデア

# まず、今年の振り返り
今年は、主に4つのシステム開発と1つの資格の取得に取り組みました。

#### ・オンライン上でオープンキャンパスを実現するシステム
https://qiita.com/kk3desu/items/76d3880c25a137201a4f

#### ・【非公開✖️公開】勉強記録アプリ

https://qiita.com/kk3desu/items/3205e81ce33985596359

#### ・単体ファイルアップロードのみのサイトを擬似的に複数ファイルアップロード可能にするChrome拡張機能

https://qiita.com/kk3desu/items/df8f3ac79bce4d3d3430

#### ・Oracle Java Silver

https://qiita.com/kk3desu/items/e775efa5ab8c44ecd90a

# 来年、開発してみたいシステムのアイデア
## 原付専用のナビアプリ
### 技術スタック
**フロントエンド**
- Flutter

**バックエンド**
- サーバーレスクラウドサービス FireBase,AWS,Azure
- Python

**必要なスキル**
ルート計算アルゴリズムへの理解
- Dijkstra法
- A*アルゴリズム
- GraphHopper


https://ja.wikipedia.org/wiki/%E6%9C%80%E7%9F%AD%E7%B5%8C%E8%B7%AF%E5%95%8F%E9%A1%8C

### システム概要
2段階右折など原付特有の交通ルールに従った、ルートを計算してくれるアプリです。また、2段階右折などを次の交差点ですると早く目的地に着くのか、少し遠回りになるが、2段階右折を避けて目的に向かう方が良いのかを考慮してルート計算します。

### 競合サービス
#### ツーリングサポーター 原付バイク〜大型バイクまで使えるナビ

https://apps.apple.com/jp/app/%E3%83%84%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0%E3%82%B5%E3%83%9D%E3%83%BC%E3%82%BF%E3%83%BC-%E5%8E%9F%E4%BB%98%E3%83%90%E3%82%A4%E3%82%AF-%E5%A4%A7%E5%9E%8B%E3%83%90%E3%82%A4%E3%82%AF%E3%81%BE%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B%E3%83%8A%E3%83%93/id958072896

#### 比較
レビューを見ていると、「原付で高速道路に案内されました。」など原付に完全に対応しているわけではなさそうです。

## 単体ファイルアップロード制限のあるサイトを複数ファイルアップロード可能にするChrome拡張機能　汎用版
### 技術スタック
TypeScript
React
### システム概要
1つ1つしかファイルをアップロードすることのできないサイトを擬似的に複数ファイルアップロード可能にする拡張機能です。また、大学の印刷サイトの拡張機能をしましたが、**どんなサイトでも使える**ような拡張機能を開発したいと考えています。


https://qiita.com/kk3desu/items/df8f3ac79bce4d3d3430

# 最後に
来年もシステム開発を継続していきたいと考えています。今年はFlutter、Firebase、NoSQLなど、さまざまな新しい技術に触れることができ、大きな成長を実感できた一年となりました。来年挑戦してみたい技術としてはGo言語を学習してみたいです。これまで、勉強記録アプリのバックエンドでPythonを用いてサーバー処理を記述することがありましたが、主にクライアントサイドの処理を行うことが多かったため、来年はサーバーサイドのスキルをさらに深めていきたいと考えています。
PSONについて

PSONはpuppetという自動化ソフトウェアで使われるシリアライゼーションフォーマットで、JSONの亜種だそうです。
JSONは文字コードとしてUTF-8を採用していますが、PSONは8bit-ACSIIを採用しているため任意のバイト列を表すことができます。

# JSONとの違い
以下の型の表についてJSONとPSONの違いはありません。

- オブジェクト
- 配列
- 数値
- ブール値
- null


文字列のみがJSONとPSONで異なります。
PSON文字列は8bit ASCIIでエンコードされたバイト列で、JSONとは異なりUTF-8的にinvalidate(対応する文字がない)バイト表現であったとしてもPSONではOKです。
一部の特殊文字はJSONとの互換性のためか特殊なエンコード方法で表現する必要があるようです。

| Byte | ASCII Character | Encoded Sequence | Encoded ASCII Sequence |
| ---- | --------------- | ---------------- | ---------------------- |
| 0x22 | "               | 0x5C, 0x22       | \"                     |
| 0x5c | \               | 0x5C, 0x5C       | \\                     |
| 0x08 | Backspace       | 0x5C, 0x62       | \b                     |
| 0x09 | Horizontal Tab  | 0x5C, 0x74       | \t                     |
| 0x0A | Line Feed       | 0x5C, 0x6E       | \n                     |
| 0x0C | Form Feed       | 0x5C, 0x66       | \f                     |
| 0x0D | Carriage Return | 0x5C, 0x72       | \r                     |

さらに、0x00から0x1Fまでの文字は \u に続いて4バイトのバイトを並べる必要があります。例えばASCIIコードでのレコード区切り文字0x1Eは\u001Eと表現されます。

# PSONのデコード方法
多くの言語にはすでにJSONパーサーがあり、これらのパーサーに対してをLatin-1エンコードと解釈するように指示すればPSONをパースできます。

例えば以下のようなデータを持つdata.psonというファイルを想定します。

```
0x7b 0x22 0x64 0x61 0x74 0x61 0x22 0x3a 0x22 0x5c 0x75 0x30 0x30 0x30 0x37 0x5c 0x62 0xc3 0xc3 0x22 0x7d
```

このファイルをパースするために、Pythonでは以下のようにします。

```
>>> import json
>>> json.load(open("data.pson"), "latin_1")
{u'data': u'\x07\x08\xc3\xc3'}
```

出展:

https://www.puppet.com/docs/puppet/7/http_api/pson
API開発の基礎：Rails APIモードとLaravelのリソースコントローラー

### はじめに
Rails APIモードとLaravelは、それぞれRubyとPHPのフレームワークで、API開発に強力なツールを提供します。本記事では、両フレームワークの基本的なコントローラー設計を比較しながら、コード例を交えて解説します。

### 1. Rails APIモードとは
RailsのAPIモードは、WebアプリケーションのAPIバックエンドを構築するために軽量化された設定です。Railsの全機能を利用する通常のモードと異なり、API開発に不要なビューやアセット関連の機能を省きます。

プロジェクトの作成
RailsでAPIモードのプロジェクトを作成するには、以下のコマンドを実行します：

```bash
rails new my_api_project --api
```

コントローラーの生成
Railsでは、コントローラーを次のように生成します：

```bash
rails generate controller Articles
```

### 2. Laravelのリソースコントローラーとは
Laravelでは、リソースコントローラーを使うとCRUD操作（Create, Read, Update, Delete）に対応したAPIエンドポイントを簡単に構築できます。

プロジェクトの作成
Laravelプロジェクトの作成は以下のコマンドで行います：

```bash
composer create-project laravel/laravel my_api_project
```

コントローラーの生成
リソースコントローラーは次のコマンドで生成します：

```bash
php artisan make:controller ArticleController --resource
```

### 3. 比較：Rails APIモードとLaravelリソースコントローラー
#### 3.1 Railsの例
以下は、RailsのArticlesControllerのサンプルコードです。

```ruby
class ArticlesController < ApplicationController
  def index
    @articles = Article.all
    render json: @articles
  end

  def show
    @article = Article.find(params[:id])
    render json: @article
  end

  def create
    @article = Article.new(article_params)
    if @article.save
      render json: @article, status: :created
    else
      render json: @article.errors, status: :unprocessable_entity
    end
  end

  private

  def article_params
    params.require(:article).permit(:title, :content)
  end
end
```

#### 3.2 Laravelの例
以下は、LaravelのArticleControllerのサンプルコードです。

```php
namespace App\Http\Controllers;

use App\Models\Article;
use Illuminate\Http\Request;

class ArticleController extends Controller
{
    public function index()
    {
        return response()->json(Article::all());
    }

    public function show($id)
    {
        $article = Article::findOrFail($id);
        return response()->json($article);
    }

    public function store(Request $request)
    {
        $article = Article::create($request->all());
        return response()->json($article, 201);
    }
}
```

### 4. 公式ドキュメントで学ぶべきポイント
Rails
[Action Controllerの概要](https://railsguides.jp/action_controller_overview.html)
[Rails による API 専用アプリケーション](https://railsguides.jp/api_app.html)

Laravel
[Controllers - Laravel](https://laravel.com/docs/11.x/controllers)
[Eloquent ORM - Laravel](https://laravel.com/docs/11.x/eloquent)

### 5. まとめ
Rails APIモードとLaravelリソースコントローラーは、それぞれのフレームワークにおけるAPI開発の基本機能を網羅しています。どちらも公式ドキュメントを活用することで効率的に学習を進めることができます。両者の違いや共通点を理解することで、API開発のスキルを一段と高めることができるでしょう。

学習の際には、再現性のあるコードを実際に書いてみることをおすすめします。どちらも強力なフレームワークであるため、自分のプロジェクトに合った選択をする助けとなるでしょう。
サクラエディタで改行コードを検索する

サクラエディタで改行コードを検索するには次のように入力します。

![サクラエディタで改行コード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3949518/b4e09952-0e18-26a1-27d1-77099a36df40.png)
UnityHub でプロジェクトを作成する際、パスの文字数制限に引っかかって作成できなかった時の対処方法

たぶんUnity Hub の仕様なんだろうけどちょっと不便に感じる    
最新の Unity Hub 3.9.1 も同様の現象は残ってる     

# 構成   
- Unity Hub : 3.8.0
- Editor Version : 2022.3.33f1


# 再現時の状態      
Unity Hub で新しくプロジェクトを作成する時、以下の画像のようにパスの文字数制限に引っかかりプロジェクトが作成できなかった  
原因は今のところ不明 ( 前日までは結構な長さのプロジェクト名でも正常にプロジェクトが作成できた )     
![20240919122305.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212999/a80171b3-bf99-2c4e-f66d-7736e45210ab.png)


この時の配置場所は以下のようなパスになっている
```C:/Users/username/Desktop/UnityProjects/プロジェクト名```

# 対処法 ( 対症療法的な手段 )   
新プロジェクト作成時のチェックで引っかかるんだったら既に作ってるプロジェクトはセーフなんじゃね？ってノリでやってみたらうまくいった   

1. プロジェクトパスの文字数制限に引っかからないフォルダにて ( 例えば Cドライブ直下とか ) プロジェクトを作成   
2. Projects のリストからいったん削除
3. Unity プロジェクトを本来配置したい場所に移動
4. Unity Hub の [Add] からプロジェクトを追加   
![20240919125325.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212999/0a14fb24-4995-738c-c604-b9feeb4a0369.png)


以上の手順を踏んだら問題なくプロジェクトが起動で来たので多分大丈夫そう
Macでサクッと導入：Slack MCPサーバーでClaudeを相棒化する方法

Slackで情報を取り扱うとき、「もっとスムーズに検索・編集ができたらいいのにな…」と思ったことはありませんか？

そこでおすすめなのが、Slack MCPサーバーを導入して、Claudeと連携する方法です。  
この設定をするだけで、Slackチャンネル一覧の取得やメッセージの自動送信、スレッドへの返信などがスムーズになります。

Mac環境をベースにしていますが、Windowsユーザー向けの補足も用意しているので、多くの方が実践可能です。  
ほんの5分程度で、あなたのSlack体験が一気にレベルアップするはず。 

興味のある方は、ぜひ以下のリンクから詳細な記事をご覧ください！

https://zenn.dev/utoc11/articles/fe35ae2ef848f6
ページ遷移直後のスクロールのちらつきを無くしたい

この記事は[ソニックガーデン 若手プログラマ Advent Calendar 2024](https://qiita.com/advent-calendar/2024/sonicgarden-junior) 10日目の記事です。

# はじめに

webアプリケーションにおいて、チャット画面等でページ遷移直後に最下部へJavaScriptでスクロールさせるという事はよくあると思います。
その際に、ページ遷移直後からスクロール完了までのごく僅かな瞬間にスクロール前の要素がちらつくことがあります。
そのちらつきを無くす方法をご紹介します。

# 結論
CSSのスタイルがvisibility: hiddenの状態で画面を表示するようにし、スクロール後にそのスタイルを取り除くことでちらつきを防ぐことができます。

# visibilityとは
要素を表示したり非表示にしたりするためのプロパティです。
`display`とは異なり、画面のレイアウトを保持したまま表示を制御することができます。


### display: noneの場合
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="ZYzOKbj" data-pen-title="Untitled" data-user="yatsuhashi168" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yatsuhashi168/pen/ZYzOKbj">
  Untitled</a> by yatsuhashi (<a href="https://codepen.io/yatsuhashi168">@yatsuhashi168</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

### visibility: hiddenの場合
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="MYgemaX" data-pen-title="Untitled" data-user="yatsuhashi168" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yatsuhashi168/pen/MYgemaX">
  Untitled</a> by yatsuhashi (<a href="https://codepen.io/yatsuhashi168">@yatsuhashi168</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# コード例
html
```html
<div id="scroll-target" class="visibility-hidden">
 <div class="item">item</div>
 <div class="item">item</div>
 <div class="item">item</div>
 <div class="item">item</div>
 <div class="item">item</div>
 <!-- 〜以下itemが続く〜 -->
</div>
```

css
```css
#scroll-target {
  height: 300px;
  overflow-y: scroll;
}

.item {
  height: 100px;
}

.visibility-hidden {
  visibility: hidden;
}
```

JavaScript
```javascript
// 最下部までスクロール
const target = document.getElementById('scroll-target');
target.scrollIntoView(false);

// 非表示状態を解除
target.classList.remove('visibility-hidden');

```

画面遷移後の初期状態では`visibility: hidden`で要素の領域を保持したまま非表示の状態にしておき、スクロール終了後にJavaScriptで`visibility: hidden`を解除して要素を表示することでちらつきを防げます。


# おわりに
以上、ページ遷移直後のちらつきを無くす方法でした。
最後まで目を通していただきありがとうございました！

[ソニックガーデン 若手プログラマ Advent Calendar 2024](https://qiita.com/advent-calendar/2024/sonicgarden-junior)、11日目は@MrTTです。お楽しみに！
Angular × TypeScript 初心者ガイド：基本から実践まで

## **はじめに**
Angularは、Googleが開発した強力なフロントエンドフレームワークで、TypeScriptと組み合わせることで、堅牢で保守性の高いアプリケーションを開発するのに適しています。この記事では、初心者向けにAngularとTypeScriptの基本を解説し、簡単なアプリケーション作成までの流れを紹介します。

---

## **目次**
1. Angularとは？
2. TypeScriptの基礎
3. Angularのプロジェクト構造
4. コンポーネントの作成
5. データバインディングの使い方
6. サービスと依存性注入（DI）
7. 実践：簡単なToDoアプリを作ろう
8. おすすめの学習リソース

---

## **1. Angularとは？**
- **特徴**  
  - コンポーネントベースのアーキテクチャ  
  - 双方向データバインディング  
  - 強力なルーティング機能  
  - モジュール化された開発
- **使われる場面**  
  - 企業向けWebアプリケーション  
  - SPA（シングルページアプリケーション）

---

## **2. TypeScriptの基礎**
- **TypeScriptの概要**  
  - JavaScriptのスーパーセットで、型チェックや最新のECMAScript機能が利用可能。  
- **基本構文**
  ```typescript
  let message: string = "Hello, Angular!";
  function greet(name: string): string {
      return `Hello, ${name}`;
  }
  console.log(greet("TypeScript"));
  ```
- AngularでTypeScriptを使うメリット:
  - 型安全性
  - IDEサポート（補完機能・エラー検出）

---

## **3. Angularのプロジェクト構造**
Angular CLIで生成されるプロジェクトには、以下のディレクトリがあります。
- `src/app`：アプリケーションのメインコード
- `src/assets`：画像やスタイルシート
- `src/environments`：環境ごとの設定

### **Angular CLIを使ったプロジェクト作成**
```bash
npm install -g @angular/cli
ng new my-angular-app
cd my-angular-app
ng serve
```

---

## **4. コンポーネントの作成**
Angularでは、アプリケーションを小さなコンポーネントに分割して管理します。

### **コンポーネントの作成方法**
```bash
ng generate component my-component
```

### **コンポーネントコード例**
```typescript
import { Component } from '@angular/core';

@Component({
  selector: 'app-my-component',
  template: `<h1>{{ title }}</h1>`,
  styles: [`h1 { color: blue; }`]
})
export class MyComponent {
  title: string = 'Hello Angular!';
}
```

---

## **5. データバインディングの使い方**
- **双方向データバインディング**
  ```html
  <input [(ngModel)]="name">
  <p>Hello, {{ name }}!</p>
  ```
- **イベントバインディング**
  ```html
  <button (click)="onClick()">Click me</button>
  ```

---

## **6. サービスと依存性注入（DI）**
### **サービスの作成**
```bash
ng generate service my-service
```

### **サービスの使用例**
```typescript
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class MyService {
  getMessage(): string {
    return 'Hello from MyService!';
  }
}
```

---

## **7. 実践：簡単なToDoアプリを作ろう**
### **機能**
- 新しいタスクを追加
- タスクをリストに表示

**コード例**  
- **コンポーネント**
  ```typescript
  tasks: string[] = [];
  newTask: string = '';

  addTask() {
    if (this.newTask.trim()) {
      this.tasks.push(this.newTask);
      this.newTask = '';
    }
  }
  ```
- **テンプレート**
  ```html
  <input [(ngModel)]="newTask" placeholder="新しいタスク">
  <button (click)="addTask()">追加</button>
  <ul>
    <li *ngFor="let task of tasks">{{ task }}</li>
  </ul>
  ```

---

## **8. おすすめの学習リソース**
- [Angular公式ドキュメント](https://angular.io/docs)
- [TypeScript公式ドキュメント](https://www.typescriptlang.org/docs/)
- UdemyやYouTubeでのチュートリアル

---

## **おわりに**
AngularとTypeScriptを組み合わせることで、堅牢なアプリケーションを効率よく構築できます。この記事を参考に、ぜひ実際にコードを書きながら学んでみてください！

---
【Unity】Installing CocoaPods... が失敗する時！！！

# はじめに
Macを新しくした。
ウキウキでUnityの環境セットアップをする。
EDM4Uを使用しているプロジェクトなので、ターゲットPlatformをiOSに切り替えると自動でInstalling Cocoapods…が出てくるが、Failed to install CocoaPods for the current userと出て失敗。
![スクリーンショット 2024-11-26 17.56.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679129/14d82761-cc9a-2944-452b-06e622e923c7.png)

あーよくあるやつね。そうそう、よくあるやつ。。。
と、ネットの海に潜るというのを何度か繰り返したのでしっかりメモっておく。


# 環境
OS：macOS Sequoia 15.1.1
チップ：M4
Unity：2022.3.52f1

# Rubyバージョンを新しくする
先ほどのエラーウィンドウに出てきた最後の部分に注目すると、現在システムで使用されているrubyバージョンが古い可能性が伺える。
```
drb requires Ruby version >= 2.7.0. The current ruby version is 2.6.10.210
訳：drbはRubyバージョン>= 2.7.0を必要としますが、現在のRubyバージョンは2.6.10.210です。
```
ので、まずはrubyのバージョンを更新する。

いろいろやり方はあると思うが、rbenvを使用する方法が管理しやすいと思うので、以下の記事を参考にさせていただき、更新する。
https://qiita.com/kiharito/items/240911cc43bb9a1f4356

Homebrewがインストールされていなければ先にインストールしておく。
また、rubyバージョンは自分の場合は3.3.6をインストールしたが、その時の最新安定版にしておくことをお勧めする。
rubyインストールが完了したら、システムがグローバルに使用するrubyをそのバージョンに切り替えることもお忘れなく。

# ターミナルからcocoapodsをインストールする
システムのrubyを上記でインストールしたバージョンに切り替えできたら、以下のQ & Aの回答を参考にさせていただき、その通りに進めればOK。
[unityにcocoapodsがインストールできない件](https://qiita.com/syuki0516/questions/f4dd64d90aa6de307edc)

ターミナルで実行するコマンドを上記より抜粋。
```
sudo gem install -n /usr/local/bin cocoapods
```
```
pod setup
```

# おわりに
以上でInstalling Cocoapods…が成功する。
クラッシュ回復とは

>ホストとルーターがクラッシュしやすかったり、コネクションが（大きなソフトやメディアのダウンロードなど）長期的であったりする場合、クラッシュからの回復が課題になる

# クラッシュからの回復が難しい
>ホストのクラッシュ回復が厄介な問題である。サーバーがクラッシュし、すぐにリブートした時、クライアントが仕事を続行できることが望ましいが、これが実現するのは難しい。単純な逐次確認プロトコルを使って、あるクライアントが長いファイルをファイル・サーバーに送るとしよう。サーバーのトランスポート層は入力セグメントを単純に一つずつトランスポート・ユーザーに渡すだけである。伝送の途中でサーバーがクラッシュし、その後再起動した時、`テーブルは再び初期化されるので、もはやどこまで転送したのかがわからない`。

# N層でクラッシュが起きてもN+1層で情報を保持する
>プロトコルをより精巧に作ってもムダである。たとえサーバーが書き込みを試みる前に、クライアントがサーバーといくつかのセグメントを交換することにより、`正確なサーバーの状況を把握しようとしても、クラッシュが書き込みの直前か直後どちらに起こるかを知る術はない`。`同時に起こるイベントはない（別々に区別された処理が全く同じ時刻に発生することはない）`という基本規則においては、`ホストのクラッシュと回復を上位層に透過することはできない`と言うのが結論である。
　より一般的な用語を使えば、`層Nのクラッシュは、層N+1が十分な状態情報を保持していれば、問題が発生する前に問題がある場所を再構築することで回復可能`であるということである。これは前述のケースと一致していて、`コネクションのエンドが常に自分の状態を見失わないようにしていれば、トランスポート層はネットワーク層の障害から回復できる`。
 
https://bookplus.nikkei.com/atcl/catalog/23/03/16/00728/
初めて翻訳をしてみた話

# 説明なんていいからはよ見せろ
[ここ](https://github.com/JF6DEU/2FASolver)へどうぞ。

# 何を翻訳した？
[こちら](https://github.com/iamyuthan/2FA-Solver)です。

# ここから本題
初めて翻訳をしてみた話です。
 - 心配なところ
     - コピーと見なされないか
        やはりここですよね。コピーと見なされたらそれで終わりです。
        私は「フォーク」することによってこの問題を解決(?)しました。
     - ミスがあったらどうするか
        私はGitHubの質問やバグを投稿する機能、その名も「issues」に身を委ねました。
     - 日本語用のサーバーを用意したのはなぜか
        恥ずかしながら、GitHub Pagesの使い方が単にわからなかっただけです。
 - 自慢したいところ
     - 翻訳機を使わなかったところ
        電子辞書は使いましたが、翻訳機は使いませんでした。
        これにより日本語に怪しさがない翻訳ができ、安心感を与えることができると思います。
     - 元の機能を全く改変しなかったところ
        これが一番大きいのではないでしょうか。
        これにより、「日本語と英語で機能が違う!」といったことを回避することができます。

オープンソースの開発者へ、第一歩を踏み入れてみたわけです。
LINE WORKS Developer Console でアプリを登録する

# LINE WORKS Developer Console でアプリを登録する手順

LINE WORKS Developer Console でアプリを登録する方法を解説します。この手順に従って、簡単にアプリを登録できます。

## 手順概要
1. アプリ リストにアクセスする  
2. アプリを新規作成する  
3. 必要な情報を入力し、設定を行う  

## 1. アプリ リストにアクセスする
まずは、LINE WORKS Developer Console のアプリ リストにアクセスします。以下のリンクから直接アクセスできます。  
[LINE WORKS Developer Console - アプリ リスト](https://dev.worksmobile.com/jp/console/openapi/v2/app/list/view)

## 2. アプリを新規作成する
### (1) 「アプリの新規追加」をクリック
画面左上にある「**アプリの新規追加**」のタイルをクリックします。
![temp_1733804214029.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/4dda4eb1-45f9-3bda-44da-9de09c66b6cb.png)

### (2) アプリ名称を入力
アプリの名称を入力します。分かりやすい名前を設定してください。  
その後、「**同意して利用する**」ボタンをクリックします。
![temp_1733804283374.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/6cdd2476-68b6-36e9-02fa-95f81e44fec3.png)

## 3. 必要な情報を入力し、設定を行う
### (1) アプリの説明を入力
アプリの説明に、アプリの用途や機能を簡潔に記載します。この内容は任意ですが、後でわかりやすいようにしておくと便利です。
![temp_1733804660312.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/c9121e59-5e50-b4ce-27c8-3e5b933bd4cc.png)

### (2) OAuth Scopes を設定
1. 「**OAuth Scopes**」セクションの [管理] ボタンをクリックします。
![temp_1733804702626.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/ed65711e-3da6-a751-c4bd-88eafa85484f.png)
  
2. 「**OAuth Scopes の選択**」画面で、アプリに必要な Scope を選択します。  
   - 例: Bot 機能を利用する場合は **[bot]** を選択。
![temp_1733804768790.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/5843828e-1f05-d69b-fbfe-cdcf3897d85d.png)

3. 必要な Scope を選択したら、画面下部の **[保存]** ボタンをクリックします。
![temp_1733804822909.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/7ec6d4e6-4a9c-8fda-50b1-78990fc23226.png)

### (3) Service Account の発行
1. 「**Service Account**」セクションに移動します。  
2. **[発行]** ボタンをクリックして、Service Account を作成します。  
   - 発行された情報は、後ほど API の利用時に必要になりますので、大切に保管してください。
![temp_1733804863093.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/0c6cca0b-4ebf-1eb1-5a87-c773b2065766.png)

## 補足
アプリの登録が完了したら、必要に応じて **Bot** や **Webhook 設定** を追加設定してください。これらはアプリの機能によって必要になります。

この手順を参考に、LINE WORKS Developer Console でアプリを登録してみてください！質問や不明点があればコメントでお知らせください。
[VSCode]エディタ上でマウスカーソルが消える

GitHubにてIssue投稿済み。

https://github.com/microsoft/vscode/issues/235695

2024/12/10未明ごろから、VSCodeのテキストエディタ上でカーソルが消える現象に遭遇。
VSCodeのIssueをみると、数件同様の報告アリ。

2024年2月頃に同様のIssueが報告されており、それによればハードウェアアクセラレーションを無効化することで解消できる模様。
私も以下の方法で解決。

https://github.com/microsoft/vscode/issues/204181

ハードウェアアクセラレーション周りって度々トラブるっすね……。
Azure App Service で自動スケーリングを設定する順序について

# はじめに

こんにちはあるいはこんばんは。クラウドを扱うみなさんの多くは、Microsoft Azure 認定資格の取得に勤しまれているかと思います。
今回は、Microsoft Azure 認定資格 AZ-204 Microsoft Certified: Azure Developer Associate のとある設問についての話題です。

# Azure App Service

Azure App Serviceの話題になります。簡単に説明いたします。

Azure App Service　は、Web アプリケーション、REST API、およびモバイル バックエンドをホストするための HTTP ベースのサービスです。以下が特徴です。

* 多くの言語をサポート
* マネージドな運用環境。OSパッチ適用など不要。
* DevOpsに対応
* スケーリング

https://learn.microsoft.com/en-us/azure/app-service/overview

今回は、スケーリングについての設問が対象です。
ちなみに、 Azure App Service で自動スケーリングするためには、App Service プランを standard 以上にする必要があります。これもよくテストに出るポイントです。

https://learn.microsoft.com/en-us/azure/app-service/overview-hosting-plans#how-does-my-app-run-and-scale

# 設問の何が問題なのか

Azure App Service で自動スケーリングを設定する順序の設問は、以下が正解です。

1. 自動スケーリングを有効にする
2. ルールを追加する
3. 条件(condition)を追加する

一方、2と3の順序が逆、という意見の方がおります。どうしてでしょうか。
なお、以降は考察ですので、純粋に試験対策だけされたい方は、以上の正解の順番を覚えていただければよいです。

# 情報のソースを見てみよう

実は、Microsoft さんのwebサイトで、両方の順序が登場します。
まずは正しい順序の方から。Microsoft Learn > App Service のドキュメント > スケーリングをパフォーマンス > ルールを使用してスケールアウトする

https://learn.microsoft.com/en-us/azure/azure-monitor/autoscale/autoscale-get-started

一方、混乱の元となっている方。Microsoft Learn > トレーニング > 参照 > Azureでの移行、ビジネス継続性、ディザースターリカバリーの設計 > Webアプリの変化するパフォーマンス要件を自動スケーリングルールで動的に満たす

![2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630062/860dab8d-3c31-f3e9-e09e-4d214e886125.jpeg)

出典: https://learn.microsoft.com/en-us/training/modules/app-service-autoscale-rules/6-autoscale-a-web-app

2と3順序が逆になっています...
画像を見ていただくと、後者がなぜこう書いてしまったのかがわかります。画像上 Condition が上に、その下に rule があるからです。事実は以下です。

・Conditionは、最初からデフォルトのものがある(**最初から追加する必要がない**)

・Conditionの中に、"+Add a rule"が含まれる

・一番下に"+Add a scale condition"がある。

よって、やはり後者URLの説明順序が正しくないようです。

# まとめ

以上、AZ-204の細かいネタをご紹介しました。みなさんの認定資格取得がうまくいくよう願っております。

- Azure は、マイクロソフト 企業グループの商標です。
- その他、本資料に記述してある会社名、製品名は、各社の登録商品または商標です。
性能負荷テストの進め方　～準備編～

# 概要
以前書いた、性能テストの進め方に対する記事の続きです。今回は準備について書いていきます。
[性能負荷テストの進め方　～計画編～](https://qiita.com/ramendaisuki/items/47a771e4b3565014c5f0)

時間がたつのは早いもので、続きを書こうと思って気づいたら4年もたっていました。怖いですね。

もともとは今回で実施についても書こうと思っていましたが、実施と評価はまとめて書きたいので、それは次回にしようと思います。

# 環境の準備
計画で検討した環境の要件に従い、環境の準備を行います。
以下については考慮が漏れやすいので気を付けましょう。
* サーバリソースを収集するためのパッケージやツールのインストール
* 負荷ツールを実行する端末/サーバの準備
この端末/サーバのスペック不足のせいで思った通りの流量がでない、ということがあります。

また、性能テストで使う環境はほかのシステムテストでも使うことが多く、環境の奪い合いが起きやすいです。
性能テストは環境に負荷をかけるため、占有するスケジュールにしないとほかのテストに影響が出るので、注意が必要です。
この事前調整も早い段階で行っておくことをお勧めします。

# テストケースの作成
オンライン機能とバッチ機能それぞれで考慮すべき点を挙げてみます。
* オンライン機能
対象機能までの導線があるのか、それとも直接該当機能を実行するのかによって考慮するて点が変わってきます。
    * 実際の画面フローに従った遷移フローとする
      * ログイン認証等必要な場合はログインのリクエストを実行後に対象APIを実行する
      * 複数の入力値パターンがテスト対象である場合はテストケースに記載する
      * 前処理と測定処理に分割し、測定対象のみループさせることが可能か検討する
      * ２段階認証等の手作業が必要となる機能が途中にある場合は自動化できる手段があるか検討し、なければどのように手動実行を挟むか検討する
    * 対象となるAPIを直接実行する
      * ログイン認証等必要な場合はそのAPIを実行した後に対象APIを実行する
      * トークンが必要な場合はトークン生成などもシナリオに含んでおく
    * 実際の業務を想定した負荷をかける
      * 測定用のシナリオとは別で負荷用のシナリオを実行するようにする
      * 実運用上並行してバッチも実行されるのであれば、そのバッチも一緒に実行する 

* バッチ機能
こちらもオンラインと同様に、業務に沿った処理フローでの実行が必要です。
  * 単独で実行するバッチは単独で実行する
  （負荷として並行で流すバッチがある場合は別）
  * 直列実行するバッチは直列で実行する
  * 並行実行するバッチは同時に実行する
  * 実際の業務を想定した負荷をかける
      * 実運用上並行してオンラインアクセスがあるであれば、
      オンライン機能を実行する負荷用シナリオも並行して実行する


# データの準備
テストデータの準備というと、ほかのテストと同じように考えてしまいがちですが、性能テストのデータでは考慮することが非常に多いです。ここでデータを作りこんでおかないと、性能テストでは問題なかったのに本番で性能が出ない、という悲劇を生んでしまいます。
例えば以下のようなことを考慮する必要があります。
* データの分布
データの分布は検索速度に大きく影響します。
以下のような点に注意しながら、運用後のデータ分布を再現する必要があります。
  * 業務的な意味を考慮せずにツールで機械的にデータを作成していないか
  * 業務上取りうる値のみになっているか
  * 業務上特殊な分布が存在しないか
  （例えばキャンペーンを打ち出すサービスの場合、その期間に登録されるユーザが多くなります）
* データ量
データ量も検索速度に大きく影響します。
運用後に想定されるデータ量を投入する必要がありますが、大量のデータとなるため、手作業での作成は非現実です。そのため。ツールの作成から検討する必要があります。
* 外部サービスのデータ
外部APIなどを使用する場合、その対抗先でもテスト用のデータが必要になります。こちらも事前に調整する必要があります。

# 負荷ツールの準備
負荷ツールの選定、および選定した負荷ツールを使えるようにするための準備が必要です。
データの作成もそうですが、この作業も時間がかかるため、計画的に進める必要があります。

負荷ツールのシナリオ作成では以下のような点を考慮する必要があります。
* ユーザの導線を考慮する
例えばTOPページに行ってから各機能に遷移するなど、実際にユーザがたどる動きを再現する必要があります
* 負荷用のシナリオでは機能ごとのアクセス割合を意識する
運用時にアクセスが多くなる機能を中心にアクセスするような負荷でないと、
本番と負荷のかかり方が違ってしまいます。
* 複数ユーザによるアクセスの必要性
ほとんどのシステムでは様々なユーザからアクセスが来るため、
テストシナリオでも複数のユーザを使うようにしておかないと、
本番と負荷のかかり方が違ってしまいます。
* サーバ側によるリクエスト冪等性の保証
サーバ側でリクエスト冪等性を保証している場合は、実行日時やシーケンス番号のインクリメント、CSVでの実行回数等を実施してリクエストのIDとなる埋め込むことによって、サーバ側に同一リクエストと認識させない工夫を実施する
* Cookieやトークンの保持
Cookieやトークンを利用するオンライン機能では、これらを保持したままシナリオ実行するよう設定が必要です。

# 事前の疎通確認
性能テストの実施方法は特殊なので、ほかのテストとは異なる手順になることがほとんどです。
そのため、いきなり本番を迎えると想定外の障害に遭遇することが多いです（経験談）。

事前に疎通確認をし、スムーズにテスト実施できるようにしておくと安全です。
以下のような点は事前に確認しておくことをお勧めします。
* データが想定通り投入できること
* まずは秒間１リクエストぐらいで実施できること
* 実際に使うシナリオが動くこと
* シナリオ実行中のサーバリソースが取得できること
* テストケースの手順通りにテストできること

# 続きの記事
次は実施・評価について書こうと思います。今度は４年もたたずに書けると思います（フラグ）。
性能テストの進め方については次回で最後になる予定です。
SQLAlchemy スキーマを動的に変更する方法

# 概要
PostgreSQLだとDBとテーブルの間にスキーマが存在しますが、別スキーマの同名テーブルに動的に接続を切り替えたい場合、以下のように関数で囲むことで上手くいきました。

# コード例
ORMのモデルクラスを作成し、関数で囲むようにします。
```python:tables/Users.py
from sqlalchemy import Column, VARCHAR, DateTime
from sqlalchemy.orm import declarative_base
from datetime import datetime

Base = declarative_base()


def get_users_orm(schema_name="public"):
    class Users(Base):
        __tablename__ = "users"
        __table_args__ = {"schema": schema_name, "extend_existing": True}

        user_id = Column(VARCHAR(100), primary_key=True, nullable=False)
        name = Column(VARCHAR(100), nullable=False)
        email = Column(VARCHAR(100), nullable=False)
        password = Column(VARCHAR(200), nullable=False)
        created_at = Column(DateTime, default=datetime.now, nullable=False)
        updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now, nullable=False)

    return Users

```
上記は以下のように使用します。
```python
from tables.Users import get_users_orm

# ※sessionの取得は省略

# privateスキーマのusersテーブルのnameカラムが"スキーマ太郎"のレコードを取得
users_orm = get_users_orm("private")
session.query(users_orm).filter(users_orm.name == "スキーマ太郎").first()
```

# 詳細
`schema_name`に切り替え対象のスキーマを設定します。
また、上記関数を呼び出すごとに、テーブルが再定義されるようなので、`__table_args__`に
```python
"extend_existing": True
```
を設定し、再定義を許可しています。

# 補足
最初はインスタンス化時にclassの引数へ設定してみたのですが、スキーマは切り替わりませんでした。
調べたらSQLAlchemyでは、ALTER TABLE文をサポートしていないようです。

※pytestで上記関数を使う場合、再定義されてしまっていますよ、というwarningが出たので、pytest.iniなどでエラーメッセージを非表示にする必要があります。
競馬予想AI作成 #2 データ準備

## まえがき
##### 前回記事👇
[競馬予想AI作成 #1 コンセプト](https://qiita.com/altom837/items/4f25ec2a335f831ca3f6)

今回は、AIにつっこむためのデータを準備する。
データはnetkeibaさんより、スクレイピングで収集。
(利用規約を見たところ、スクレイピングに関する記載は無かった。24/12/10)

## 取得データ詳細
今回予測したいのは馬毎の走破タイムなので、「結果・払戻」ページの結果表とその時の
レース条件(距離や競馬場等)を取得。

### 説明変数
#### レース条件
・競馬場 (カテゴリ)
・レース名 (カテゴリ)
・距離 (数値)
・馬場状態 (カテゴリ)
・芝/ダート/障害 (カテゴリ)
・コース (カテゴリ)

#### 各馬のデータ
・枠 (数値)
・馬番 (数値)
・馬名 (カテゴリ)
・性齢 (数値)
・体重 (数値)
・体重増減 (数値)
・斤量 (数値)
・騎手による減量 (数値)
・騎手名 (カテゴリ)
・人気 (数値)
・トレセン (カテゴリ)
・調教師 (カテゴリ)
### 目的変数
・走破タイム
#
一見関係無さそうなレース名や馬名は入れるか迷ったが、予測したい馬が過去に何回か
走っている場合、精度向上に繋がる可能性が捨てきれなかったので一旦入れておいた。

また、本来なら入れないといけない説明変数(血統や調教データ)がもっとあるはずだが
取得に結構な時間がかかるので今回は上記でのデータで試してみる。

データ取得期間は2019/1～2024/10とした。
(現役競走馬の最高齢を8歳として、その馬が過去に走っている可能性のある期間)

取得したデータのcsvはこんな感じ👇(今回使わない項目も入ってます)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3955641/9da39d98-0901-c65b-23be-1c65bf6577a9.png)

今回はここまで。

次回はモデルの選定と予測までやっていきます。
Error の localizedDescription はなぜ上書きされるのか

## はじめに
Swift で独自の `Error` を作成する際は `localizedDescription` を使わずに `LocalizedError` の `errorDescription` を使いなさいというのはよく聞く話です。この記事はなぜ `localizedDescription` はダメなのかという話です。

参考

https://qiita.com/takehilo/items/cf384e5a3ab2c22163d7

## 前提
独自のエラーとして下記のように `Hoge` を実装してみます。

```swift
enum Hoge: Error {

    case hoge

    var localizedDescription: String {
        return "hoge"
    }
}

// hogeじゃない
(Hoge.hoge as Error).localizedDescription
```

`(Hoge.hoge as Error).localizedDescription` は下記のような値になります。

```
The operation couldn’t be completed. (Hoge error 0.)
```

下記のようにしてやると `localizedDescription` はちゃんと hoge になります。

```swift
enum Hoge: Error {

    case hoge
}

extension Hoge: LocalizedError {

    var errorDescription: String? {
        return "hoge"
    }
}

// hoge
(Hoge.hoge as Error).localizedDescription
```

`Hoge.localizedDescription` を変更してもダメなのは `Error` のデフォルト実装があるからそれで上書きされるというのをどこかで見かけてそうなんだと思っていました。
ですが下記のような実装をしても別に上書きされないじゃないかという疑問を持ちました。

```swift
protocol Fuga {
    var fuga: String { get }
}

extension Fuga {
    var fuga: String {
        return "fuga"
    }
}

enum Piyo: Fuga {
    case piyo

    var fuga: String {
        return "piyo"
    }
}

// piyo
(Piyo.piyo as Fuga).fuga
```

## なぜ上書きされるのか
ではなぜ `localizedDescription` は上書きされるのかということなのですがおそらく私の認識が間違っていたのです:flushed:

`Error` の `localizedDescription` はプロトコルで定義されているわけではなくおそらく `extension` なんですね。

Xcode で cmd + control + J で `localizedDescription` の定義にとぶと下記のようになっていました。

```swift
@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)
extension Error {

    /// Retrieve the localized description for this error.
    public var localizedDescription: String { get }
}
```

つまり `Fuga` の例でいうとこんな感じです。

```swift
protocol Fuga {}

extension Fuga {
    var fuga: String {
        return "fuga"
    }
}

enum Piyo: Fuga {
    case piyo

    var fuga: String {
        return "piyo"
    }
}

// fuga
(Piyo.piyo as Fuga).fuga
```

`errorDescription` の定義にとぶと下記のようにプロトコルで定義されていました。おそらく`localizedDescription` 内で `errorDescription` を呼ぶような実装になっているものと思われます。

```swift
@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)
public protocol LocalizedError : Error {

    /// A localized message describing what error occurred.
    var errorDescription: String? { get }
```

## おわりに
今まではそういうものだと思って独自エラーを作る際は `errorDescription` を使っていましたがこれでスッキリ使えるようになりました:relieved: