OmniAICreator/Qiita-1.07M huggingface dataset:
PowerDNS の API 操作メモ

PowerDNS では API 経由でレコードの確認や追加が可能であるが、いつもやり方を忘れるので各種操作のメモ。
## ZONE の一覧を取得する
```
# curl -sk -H 'X-API-Key: <パスワード>' -X GET http://<PowerDNS の IP or FQDN>:8081/api/v1/servers/localhost/zones | jq .
[
  {
    "account": "",
    "catalog": "",
    "dnssec": false,
    "edited_serial": 2023063001,
    "id": "example.hoge.com.",
    "kind": "Native",
    "last_check": 0,
    "masters": [],
    "name": "example.hoge.com.",
    "notified_serial": 0,
    "serial": 2023063001,
    "url": "/api/v1/servers/localhost/zones/example.hoge.com."
  },
  {
    "account": "",
    "catalog": "",
    "dnssec": false,
    "edited_serial": 2023063005,
    "id": "0.168.192.in-addr.arpa.",
    "kind": "Native",
    "last_check": 0,
    "masters": [],
    "name": "0.168.192.in-addr.arpa.",
    "notified_serial": 0,
    "serial": 2023063005,
    "url": "/api/v1/servers/localhost/zones/0.168.192.in-addr.arpa." <------★
  },

　　　：
```

## ZONE に含まれる各レコードの参照
👆 の API 応答で得られた Zone の名前=`url` を指定して GET する。
```
# curl -sk -H 'X-API-Key: <パスワード>' -X GET http://<PowerDNS の IP or FQDN>:8081/api/v1/servers/localhost/zones/0.168.192.in-addr.arpa. | jq .
　：

    {
      "comments": [],
      "name": "100.0.168.192.in-addr.arpa.",
      "records": [
        {
          "content": "hogehoge.example.hoge.com.",
          "disabled": false
        }
      ],
      "ttl": 3600,
      "type": "PTR"
    },

```

## ZONE へのレコード操作
### 正引きレコードを追加する場合
以下のような A レコードの json ファイルを作成する。
```
{
  "rrsets": [
      {
        "comments": [],
        "name": "fugafuga.example.hoge.com.",
        "changetype": "REPLACE",
        "records": [
          {
            "content": "192.168.0.101",
            "disabled": false
          }
        ],
        "ttl": 3600,
        "type": "A"
    }
  ]
}
```

### 逆引きレコードを追加する場合
以下のような PTR レコードの json ファイルを作成する。
```
{
  "rrsets": [
      {
        "comments": [],
        "name": "101.0.168.192.in-addr.arpa.",
        "changetype": "REPLACE",
        "records": [
          {
            "content": "fugafuga.example.hoge.com.",
            "disabled": false
          }
        ],
        "ttl": 3600,
        "type": "PTR"
      }
  ]
}
```

### レコードの削除を行う場合
上記 json ファイルの `rrsets.changetype` を `DELETE` に変更する。
```
{
  "rrsets": [
      {
        "comments": [],
        "name": "101.0.168.192.in-addr.arpa.",
        "changetype": "DELETE",
 :
```

## Zone の作成
新しい zone 用の json ファイルを作成する。
```
{
    "kind": "Native",
    "masters": [],
    "name": "1.168.192.in-addr.arpa.",
    "nameservers": [
    ]
}
```

## クエリ実行
作成した json ファイルを指定し、各 ZONE に対して PATCH リクエストを発行する。

### レコードの場合
```
# curl -sk -H 'X-API-Key: <パスワード>' -X PATCH -d @xxxxxx.json http://<PowerDNS の IP or FQDN>:8081/api/v1/servers/localhost/zones/<対象 ZONE 名> 
```

### zone の場合
```
# curl -sk -H 'X-API-Key: <パスワード>' -X POST -d @xxxxxx.json http://<PowerDNS の IP or FQDN>:8081/api/v1/servers/localhost/zones
```
エンジニアは「エンジニアは特殊な人種」という思い上がりをやめろ

ポエムです。

# エンジニアの楽しさ

僕も含めエンジニアを職業にしている人は「もの作りの楽しさ」を知っていると思います。

「開発したアプリケーションが上手く動いた」
「セットアップしたルーターでネットワークが繋がった」
「AIモデルを作って画像を分類することができた」
といった成功体験を積み重ねることで、エンジニアという仕事の楽しさを少しづつ覚えていけると思います。

このような成功体験を積むためには、ある意味で"キャズムを超える"必要があると考えています。
![](https://www.onemarketing.jp/wp-content/uploads/2019/03/196_img01.png)
(出典 https://www.onemarketing.jp/contents/chasm_re/)

IT業界やコンピュータサイエンスの領域の広さと奥深さは計り知れません。個人的には「海より広くてマリアナ海溝よりも深い」とすら思っています。
ただ、色々な知識や経験から点と点が繋がって線になったり、後になって「こういうことか！」と思うようなことが多くあると思います。

そういった意味でエンジニアとして「仕事が楽しい」と思えるようになるには、どうしても最低1～2年程度の期間は必要になる人は多いのではないかと思います。

# エンジニアは専門職である

言わずもがなエンジニアは専門的なスキルを必要とする職種です。

でも、それはエンジニアに限ったことではありません。

マーケティングや営業などの非技術職種においても世の中のトレンドや社会情勢の動向などをキャッチアップして価値を創出し続けるのは難易度が高いことだし、だからこそ専門職種として重宝されることだと思います。

# エンジニアとして生きていくこと

「常に勉強していないとエンジニアとしてやってはいけない」
「勉強するのが大変だと思うならエンジニアに向いていない」
「休日も進んでプログラミングするぐらいじゃないと」

上記のような意見はもちろん完全に間違った話ではないし、時には正論であるのは確かです。

しかし「勉強が続けられないならエンジニアに**向いていない**」「**辞めたほうがいい**」といった物言いは新規参入者の拒絶でしかありません。結果として、長期的にはエンジニア市場の停滞を招く可能性すらあると考えます。

「勉強することが楽しいと思える人」は**僕からしたら単純に羨ましいです**。僕にとって「勉強」はそれ自体が目的にはなりにくい。
勉強するとは新しい技術を知ることや既知の知識をアップデートすることで、それによって例えば「これまでよりも良い設計ができるようになる」とか「品質の高い成果物を作れる」ことを期待しています。もっと言えば、その先の仕事に繋げた金銭的なリターンをモチベーションとしています。

色んな考え方や個性があって良いと思います。~~全員が常に勉強しかしていなくて排他的な界隈って気持ち悪いです~~

# 駆け出しエンジニアの方々へ

筆者がエンジニアになった最初の数年間はどうしても楽しくない期間や"何とも言えない不安感"を覚えたことがありました。
「先輩の話しているあらゆる単語が分からない」「こんな雲の上のような人がいるのか」と思ったことがありました。
ただ、何とかエンジニアになって10年が経ちました。

世の中にはインターネット黎明期から**好きで**コンピュータを扱ってきたり、幼少期から**好奇心で**プログラミングを始める人たちがいます。
あらゆるジャンルの解説書やもちろんQiitaすら存在しない時代に、手探りで作って覚えてITの世界を先導してきた人が存在します。
そういった人たちに追いつけるかは分かりません。
（少なくとも自分には追い付けないと思っている）

それでも僕はエンジニアの仕事は楽しいし好きだし、今ではエンジニアである自分に少しは誇りを持てるようになりました。

駆け出しエンジニアの皆さんにおかれましても、普段から「楽しい！」と思いながら技術を覚えていって頼もしいエンジニアになってくださることを祈っています。
[flutter]textfieldのautofocusプロパティについて調べてみた

こんにちは、今回はflutterのtextfieldのFocusNodeプロパティの使い方など詳細をまとめてみました。

## focusNodeとは

focusNodeとは、ユーザーが入力するタイプのWidget(ex:TextField)でカーソルのフォーカスを制御するためのクラスになります。

なので今回の主題である、textfieldのfocusNodeプロパティもそのfocusNodeクラスを引数にするためのプロパティといえます。

## 手順

focusNodeに引数を設定して、フォーカスを制御する方法は以下です。

1,インスタンスの作成

```dart:インスタンス作成
FocusNode myFocusNode = FocusNode();
```

1,focusNodeに引数として設定

```dart:インスタンス作成
FocusNode myFocusNode = FocusNode();

TextField(
  focusNode: myFocusNode,
  // 他のTextFieldのプロパティやコールバックなどを記述
)
```

上記のように引数にFocusNodeクラスのインスタンスを記載することにより、textfieldをタップした際に、カーソルのフォーカスを当てることができます。

## [発展]フォーカスの状態を監視する

myFocusNode.addListenerを使用することで、フォーカスの当たったタイミング、外れたタイミングを取得することができます。

この状態監視を利用することによってバリデーションなど多くの事ができるようになります。

以下はその一例です。

**1,フォームのバリデーション**
myFocusNodeのフォーカスが失われた時にバリデーションをトリガーして、入力内容の妥当性をチェックすることが可能。


**1,フォーカス時のUI変更**
、フォーカスされたテキストフィールドの背景色を変更するなど、視覚的なフィードバックを提供することが可能

**1,エラーメッセージの表示**
フォームの入力内容にエラーがある場合、フォーカスが移動した時にエラーメッセージを表示することで、ユーザーに問題を指摘することができる。

上記のようにフォーカスのタイミングを制御することでUXの向上を図ることができます。

## ハンドリング方法

```dart
myFocusNode.addListener(() {
  if (myFocusNode.hasFocus) {
    print('フォーカスが得られました！');
  } else {
    print('フォーカスが失われました！');
  }
});
```

上記のコードをinitstateの中などで、記載すると、うまく動作すると思います。
Kaskada〜アーキテクチャー・バックエンド技術選定における設計思想

# はじめに

先日、以下の記事を発表しました。

https://qiita.com/yoshiyuki_kono/items/7dc7bdad5e02ff986f5d

公式ドキュメントの学習過程の記録として、以下の記事をまとめてみました。

本稿情報のソースとして、下記ドキュメントを参照ください。

https://kaskada.io/docs-site/kaskada/main/overview/faq.html

## Kaskada〜アーキテクチャー・バックエンド技術選定における設計思想

### スループットとレイテンシの選択
イベント プロセッサは、スループットとレイテンシの最適化のどちらかを選択する必要がありますが、トレードオフは非対称です。

最新の CPU と GPU は、同じ操作を繰り返し適用する場合の効率が大幅に向上するため、計算するバッチが大きくなるにつれて計算効率が向上します。ただし、リアルタイム システムでは、より大きなバッチを処理すると、バッファリングに多くの時間が費やされることになり、エンドツーエンドの遅延が増加することになります。

### Kaskada の設計目標:バルク/OLAPワークロード

Kaskada の設計目標の 1 つは、ヒストリカルイベントの大規模データセットに対してインタラクティブな結果を提供することです。

### Apache Arrowの採用とバルク処理効率のためのスループット最適化

このようなタイプのバルク/OLAP ワークロードをサポートするために、Kaskada は列指向計算用の[Apache Arrow](https://arrow.apache.org/)ライブラリを使用して構築されています。
*Arrow* をベースに構築することで、Kaskada はレイテンシよりもスループットに対して最適化されています。Kaskadaの設計思想では、数百ミリ秒で測定されるエンドツーエンドのレイテンシは、ほとんどのリアルタイム アプリケーションにとって十分であると考えられています。そして、バルク効率を一桁(Order of Magnitude)向上させるためには、1 桁のレイテンシを犠牲にしても許容できるトレードオフであると捉えられています。



### 単一プロセスのパフォーマンスへの重点〜分散スケーリングと垂直スケーリングとの選択

Kaskada が決定したもう 1 つの重要なトレードオフは、単一プロセスのパフォーマンスに重点を置くことです。
「ビッグ データ」初期の頃、汎用ハードウェアには 1 つのコアと 2Gb の RAM が搭載されていました。テラバイトサイズのデータ​​セットに対する計算を実装する唯一の方法は、それを複数のマシンに分散することでした。最近のコンピューティング エンジンは、分散実行よりも、単一の物理インスタンスでの高パフォーマンスを優先しています。[DuckDB](https://duckdb.org/)の Jordan Tigani による「ビッグデータは死んだ([Big Data is Dead](https://motherduck.com/blog/big-data-is-dead/))」という記事では、その辺りの経緯が説明されています。

### ハイブリッドアプローチ

現在、Kaskada は分散実行に対してハイブリッド アプローチを採用しています。分散ワーカーは、最初にデータをロードするときに使用できます。データの読み込みにはイベントを時系列に並べ替える必要があるため、コストがかかります。Kaskada は現在、単一プロセスで各クエリを実行します。完全分散実行はKaskadaのロードマップにありますが、ほとんどのユースケースには「垂直スケーリング」で十分であることがわかっています。


## 参考情報

### バルク処理効率のためのスループット最適化

https://www.infoworld.com/article/3678300/how-vectorization-improves-database-performance.html
Sorbet で `typed: false` で起きうるエラーを調べる方法


Sorbet を既存のコードに導入する際、気にするのが strictness level (`# typed: XXX` の XXX の部分) の選択だと思います。最初はほとんどのファイルを `typed: false` で始めると思いますが、結局これはどういうエラーを検知するのか (検知してしまうのか) 気になると思います。

公式のリファレンス (https://sorbet.org/docs/static) に解説はありますが、どういうエラーが起きうるのかについて抽象的な説明です。また、実際に Sorbet を実行したとき、「あれ、これ `typed: false` でも怒られるの？」みたいに、結構想像とギャップが出ると思います。

この記事では具体的にどの strictness level でどのようなエラーが起きうるかの調べ方を紹介します。

## 1. ソースコードからエラーを探す

早速ですが、悲しいことにどのエラーがどの strictness level で起きうるかは、ドキュメント化されておらず、ソースコードを読むしかありません。
が、幸いにも、エラーの定義は特定のディレクトリにまとまっていて、定義も読みやすいです。今回はそれを見ます。

[sorbet リポジトリの core/errors ディレクトリ](https://github.com/sorbet/sorbet/tree/0.5.10932.20230725174316-166024b5c/core/errors) に定義があります。
このディレクトリには、Sorbet の実行ステップ[^step]に対応した、複数の `.h` ファイルが置かれていて、それぞれに以下のようなエラー定義が書かれています。

```desugar.h
#ifndef SORBET_CORE_ERRORS_DESUGAR_H
#define SORBET_CORE_ERRORS_DESUGAR_H
#include "core/Error.h"

namespace sorbet::core::errors::Desugar {
constexpr ErrorClass InvalidSingletonDef{3001, StrictLevel::True};
constexpr ErrorClass IntegerOutOfRange{3002, StrictLevel::True};
constexpr ErrorClass UnsupportedNode{3003, StrictLevel::False};
constexpr ErrorClass FloatOutOfRange{3004, StrictLevel::True};
constexpr ErrorClass NoConstantReassignment{3005, StrictLevel::True};
// constexpr ErrorClass SimpleSuperclass{3006, StrictLevel::True};
constexpr ErrorClass UnnamedBlockParameter{3007, StrictLevel::Strict};
constexpr ErrorClass UndefUsage{3008, StrictLevel::Strict};
constexpr ErrorClass UnsupportedRestArgsDestructure{3009, StrictLevel::True};
constexpr ErrorClass CodeInRBI{3010, StrictLevel::False};
constexpr ErrorClass DuplicatedHashKeys{3011, StrictLevel::False};
} // namespace sorbet::core::errors::Desugar

#endif
```

`constexpr ErrorClass` から始まる各行がエラーの定義で、 最初の数字がエラーコード、次の `StrictLevel::` に続く部分が 「どの strictness level 以上からエラーがレポートされるか」を表します。
(※ strictness level の大小関係は、 ignore < false < true < strict < strong です。例えば、 false でレポートされるエラーは、true, strict でもレポートされます。)

例えば、 `DuplicatedHashKeys` は、エラーコードが 3011 で、 `StrictLevel::False` なので、 `typed: false` でもエラーがレポートされます。

エラーコードは、リファレンスの参照に使うほか、 `srb` コマンドの `--suppress-error-code`, `--isolate-error-code` オプションで、特定のエラーを無視したい、あるいはそれだけレポートしてほしいときに使います。

## 2. 公式のエラーリファレンスを参照する

エラーコードと、どの strictness level でレポートされるかがわかったので、次はエラーの説明を見ます。
Sorbet のエラーに関しては、公式のエラーリファレンス (https://sorbet.org/docs/error-reference, https://srb.help/) を参照すると良いです。 エラー表示でこのページに誘導されるので、見たことある人も多いでしょう。

例えば、先程の `DuplicatedHashKeys` (エラーコード: 3011) の解説は、https://sorbet.org/docs/error-reference#3011 から見れて、内容は以下の通りです。

![スクリーンショット 2023-07-28 14.11.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7048/c74267f1-196a-630e-f4e2-69724c3194ab.png)

[^step]: Sorbet の実行ステップについて詳しく知りたければ、開発者向けのドキュメントですが、 https://github.com/sorbet/sorbet/blob/0.5.10932.20230725174316-166024b5c/docs/internals.md を参照すると良いです。
Javaのmainメソッドについて学習してみた

# 概要
Javaのmainメソッドについて学習してみました。以下のページを参考にしました。

mainメソッドと引数

https://www.javadrive.jp/start/main/

引数を指定してmainメソッドを呼び出す

https://www.javadrive.jp/start/main/index1.html

コマンドライン引数の数を確認

https://www.javadrive.jp/start/main/index2.html

# まとめ
何かの役に立てばと。
（仮説）Amplifyのプラットフォーム更新とアクセスコントロールの注意点

Amplifyのプラットフォーム値を`WEB_DYNAMIC`から`WEB_COMPUTE`に更新したらBasic認証が正常に働かない（正しい値を入力しても弾かれる）状態になりました。
いくつか検証して解消したようなので、得た仮説を備忘録としてまとめます。
もし同じような状況で困っている人がいたら、少しでもヒントになれば幸いです。

:::note warn
注意
あくまで**仮説**なのでご了承ください。
正しい情報知ってるよという方、教えてくださるとうれしいです！
:::

## 結論（※仮説です）
Amplifyのプラットフォームの値を更新する際、**アクセスコントロールの設定**によってはBasic認証に影響が出る場合がありそうです。

### 注意したい設定
「グローバルパスワードの適用」が**オン**の状態でプラットフォーム値を更新すると、**Basic認証が正常に働かない**ことがある。

### おそらく大丈夫そうな設定
「グローバルパスワードの適用」は**オフ**（Basic認証をかけるために各ブランチに個別にユーザーネーム/パスワードを設定している状態）でプラットフォーム値を更新すると、特に問題はなさそう。

## 環境
Next.jsのバージョンを12から13に上げるためにはプラットフォームの値をウェブコンピューティング（`WEB_COMPUTE`）にする必要があるとのことです。
もともとの設定がウェブ動的（`WEB_DYNAMIC`）だったので更新しようとしたのがきかっけでした。

その時の設定（プラットフォーム更新する前）は下記の通り。
- フレームワーク
    - Next.js - SSR
    - （この時Next.jsのバージョンは12）
- プラットフォーム
    - ウェブ動的（WEB_DYNAMIC）
- アクセスコントロール
    - グローバルパスワードの適用オン

## 起こったこと
需要はないかもしれないが起こったことを時系列で

- 下記コマンドでAmplifyのプラットフォームを`WEB_DYNAMIC` -> `WEB_COMPUTE`に更新

```
aws amplify update-app --app-id <value> --platform WEB_COMPUTE --region <value>
```

- コンソールにてプラットフォームがウェブコンピューティングに更新されていることを確認
- 各ブランチを再デプロイ
- 再デプロイ完了後、各ブランチでBasic認証に正しいID/Passwordを入れても弾かれる🥲
- アクセスコントロールを見ると「グローバルパスワードの適用」がオフになっていた & 個別に設定されている状態🤔
→もともとは「グローバルパスワードの適用」は**オン**で個別の設定はしていなかった
- 「グローバルパスワードの適用」を再度オンに
- 再度デプロイ
- 再デプロイ完了後、各ブランチの環境でまたしてもBasic認証が弾かれる😭

むむむ

- ここで一度プラットフォームを元のウェブ動的に戻してみる
```
aws amplify update-app --region <value> --app-id <value> --platform  WEB_DYNAMIC
```
- コンソールにてプラットフォームがウェブ動的に更新されていることを確認
- 各ブランチを再デプロイ
- 再デプロイ完了後、各ブランチの環境で依然としてBasic認証が弾かれる😭

むむむ💦

- 「グローバルパスワードの適用」を**オフ**にして各ブランチ個別にユーザーネーム/パスワードを設定
- 各ブランチを再デプロイ
- 再デプロイ完了後、各ブランチのBasic認証が正常に機能していることを確認（ひと安心）

グローバルパスワードの適用があかんのか？
ウェブコンピューティングへの更新は必要なのでもう一度試す。

- Amplifyのプラットフォームを`WEB_DYNAMIC` -> `WEB_COMPUTE`に更新（コマンドは上記と同じ）
- コンソールにてプラットフォームがウェブコンピューティングに更新されていることを確認
- 各ブランチを再デプロイ
- 再デプロイ完了後、Basic認証が正常に機能していることを確認
- ..と思ったら、「ブランチの自動検出」に設定しているブランチでは依然としてBasic認証が弾かれる。mainなど手動で接続したブランチのみBasic認証を突破できる。

なんだこれ🤔

- そしてしばらくすると（数時間？）、先ほどまでBasic認証を突破できていたブランチでもBasic認証が弾かれるように😭
-なんかもう嫌になる

- もう一度プラットフォームを元のウェブ動的に戻してみる（コマンドは上記と同じ）
- コンソールにてプラットフォームがウェブ動的に更新されていることを確認
- 各ブランチを再デプロイ
- 再デプロイ完了後、各ブランチのBasic認証が正常に機能していることを確認（ひと安心）

仕切り直す
**グローバルパスワードの適用をオフにしてユーザーネーム/パスワードは個別に設定した状態**でもう一度ウェブコンピューティングにしてみよう..

- Amplifyのプラットフォームを`WEB_DYNAMIC` -> `WEB_COMPUTE`に更新（コマンドは上記と同じ）
- コンソールにてプラットフォームがウェブコンピューティングに更新されていることを確認
- 再デプロイ完了後、「ブランチの自動検出」に設定しているブランチも含め全てのブランチでBasic認証が正常に機能していることを確認（ガッツポーズ）

---

つらつらと書きましたが、プラットフォームを更新する際はもとのアクセスコントロールの「グローバルパスワードの適用」の設定によりBasic認証の挙動が変わってしまうらしいという推測をしています。

## その他
Basic認証が弾かれる場合はcloudfrontが関わってたりもするような記事も見かけたので、今後またおかしなことになったら試してみようと思います。

### 参考

https://zenn.dev/doutori/scraps/5352ddde3d6620

https://qiita.com/kaino5454/items/fb9e393baecfeea0fc65

https://mgmgblog.com/post-418/

https://dev.classmethod.jp/articles/apply-basic-authentication-password-with-cloudfront-functions/
last

```
[linuxstudy@xxxx ~]$ last
linuxstu pts/0        :0               Fri Jul 28 13:06   still logged in   
linuxstu pts/0        :0               Fri Jul 28 12:57 - 13:06  (00:08)    
linuxstu :0           :0               Fri Jul 28 12:56   still logged in   
reboot   system boot  3.10.0-1160.90.1 Fri Jul 28 12:55 - 13:08  (00:13)    
linuxstu pts/0        :0               Fri Jul 28 12:51 - 12:54  (00:02)    
```
夏休みにやりたいこと

Qiita初めての投稿。
夏休みにやりたいこと（趣味）をまとめておこうと思う。


#### プログラミング
- git_practiceのリポジトリを整理する。
- chaosのリポジトリを整理する
- 拡散モデル
    - 論文
    - 本
- りざばーコンピューティング
- SNNのコーディング
- Diffusion ModelをHuggingfaceの公式リポジトリで解読する(;・∀・)
- Docker, Kubernetes?, AWSについて一通り勉強する。
    - <a href="https://tomomano.github.io/learn-aws-by-coding/">東大AWS講義2021</a>
    - <a href="https://tomomano.gitlab.io/intro-aws/#_%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">東大AWS講義2020</a>
- 勉強/解読した内容をみんなに説明できるよう、Qiitaにまとめておく。
- Latexの書き方
- E資格の勉強

#### 占い
- 書物占いのデザイン、構成について検討する。
- 新しい可愛い日記帳を買う(o^―^o)


#### 読書
- ニーチェ
- エーリッヒフロム
- 夜と霧
- what is life?
- マキアベリの君主論
- 塩野七生さんの「ギリシア」シリーズ
- 
など、ちょっと読んでみたいな...って思っている本。
Facadeパターン（自動給湯器の例）

# 背景
Facadeとは？
weblioより：
"(建物の)正面、(しばしば実体よりりっぱな事物の)見かけ、外見"
例文：
His cunning is hidden behind a facade of honesty.
うわべは正直そうだが, 実は悪賢い男なのだ.

英単語的には、「見かけ」というのが今回のパターンの意味するところで、
複雑なシステムに対するシンプルな窓口の役を果たすのが、「Facade」パターンである。

Facadeパターンについて、具体例と合わせて考えてみた。

# 参考文献
1. [増補改訂版 Java言語で学ぶデザインパターン入門](https://www.amazon.co.jp/増補改訂版-Java言語で学ぶデザインパターン入門-結城-浩-ebook/dp/B00I8ATHGW/ref=sr_1_4?__mk_ja_JP=カタカナ&crid=2LX5EGSDGEHES&keywords=デザインパターン&qid=1670657193&sprefix=デザインぱたーn%2Caps%2C350&sr=8-4)

2. [オブジェクト指向における再利用のためのデザインパターン](https://www.amazon.co.jp/オブジェクト指向における再利用のためのデザインパターン-エリック-ガンマ/dp/4797311126/ref=sr_1_1?keywords=オブジェクト指向における再利用のためのデザインパターン&qid=1670657488&sprefix=オブジェクト指向における再利用のための%2Caps%2C190&sr=8-1)

3. [オブジェクト指向のこころ](https://www.amazon.co.jp/オブジェクト指向のこころ-SOFTWARE-PATTERNS-アラン・シャロウェイ/dp/4621066048/ref=sr_1_1?__mk_ja_JP=カタカナ&crid=36ZXDJPM76WZB&keywords=オブジェクト指向のこころ&qid=1671460633&sprefix=オブジェクト指向のこころ%2Caps%2C310&sr=8-1)

# パターンの目的と適用可能性
GoFによれば、パターンの目的は以下のように記載されている。

```
サブシステム内に存在している複数のインタフェース群に対する、統一したインタフェースを提供する。
Facadeは高レベルのインタフェースを定義することにより、サブシステムを容易に使えるようにするものである。
```

最初この記述を見た時、
「部品を作るときに、ユースケースを考慮して外部から呼び出される公開インタフェースを設計するときに普通考えることじゃないの？」と思った。

しかし、以下のような場合に適用可能性が考えられると理解した。

* 当初の想定が変化して、システムの持つ機能の一部を使いたい場合
* サブシステムが大きく、複雑になってきた場合
* クライアントとサブシステムとの間の依存関係が多い場合

題材としては、自動給湯器がいいかと考えた。

# パターン適用時の嬉しさと注意
ぼくらユーザとしては、「お湯はり」ボタンさえ押せば、お風呂に入れる状態になるのが当たり前だと思う。

ただ、内部のサブシステムとしては、
排水だったり、現在の湯量を計測したり、保温機能が働いたり、いろんなことが行われている（予想）

ユーザはお湯はりをしたいだけなのに、
Facadeクラスがないと、ユーザは以下の手順が必要。

1. 排水
1. 湯量を計測
1. お湯を追加
1. 保温

それをお湯はりボタン一つでできるようにFacadeパターンを使う。
ユーザはお湯はりしたいというニーズにボタン一つで対応できるようになったのでハッピー。

![スクリーンショット 2023-07-28 11.49.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1878269/ec28d583-9f14-6fa5-14a5-3cf9cdbe5ba8.png)

これは、どちらかといえば最初に設計するときに考えると思うが、
例えばお湯はりではなく、
オキシ漬けをしたい、というニーズが出てきたときに、
お湯はりで使っていた一部の部品（クラス）を使ってオキシ漬けができるので、Facadeパターンを使うのかなと思った。
※オキシ漬けは60°Cくらいのお湯でやったほうが効果的らしい。
　いちいちお湯はりの温度を変更して、次お湯はりのときに温度を戻すのもめんどくさい。
　うちのくっせえタオルも匂いが消えるので、たまにやってます。みなさんもぜひお試しあれ。

注意：
Facadeクラスを再帰的に呼び出す例なども記載されていたが、Facadeクラスだらけになって、
ユーザはどのインタフェースを使えば良いか迷ってしまうのではないか。
※レイヤが適切に切られていてレイヤ毎にFacadeが用意されているのであれば問題なさそう。

安易にFacadeパターンを使って新しくインタフェース切るというのも、
結局同じようなインタフェースが生まれてしまい、メンテし切れなくなるか、
リファクタリングする羽目になりそうと思った。

# 関連パターン
[「Mediator」パターン](https://qiita.com/issykatsu/items/8dcb306accf811e924b6)は、相談役を置くことで、特定の依存関係を少なくできるパターンであり、部品は相談役を意識する必要がある。
今回のFacadeパターンは、部品がFacadeクラスを意識する必要はない一方向の呼び出しであり、かつ部品間の依存関係を少なくするという目的ではない。

[「Proxy」パターン](https://qiita.com/issykatsu/items/ada88d665a69f4150f8c)は、代理人を立てるようなパターンであり、対象へのアクセスにコストがかかる場合や、対象へのアクセスに制限があるときに使う。
Facadeパターンはコストがかかるかどうかではなく、見かけをシンプルにする窓口を作る、というイメージなので少し違う。

場面に応じて使いこなすのが難しそう。。
割とFacadeはシンプルで普通にやっていることだと思いますが。
PFRL(v0.4.0)を利用して強化学習プログラムを動かしてみる件

[PFRL(v0.3.0)を利用して強化学習プログラムを動かしてみる件](https://qiita.com/muzzumuzu/items/25a8e6daaf4691c0bbbc) にてPFRL(v0.3.0)を動かしてみましたが、当該記事を書いた直後に、v0.4.0がデプロイされたので、それを試してみました。
以下は私の環境です。
```
Ubuntu 20.04
NVIDIA-SMI 530.30.02 
GeForce RTX 2080 Ti
CUDA 12.1
```
とりあえず、クリーンな仮想環境を利用して、python3.8ベースで環境を作成します。
```
$ virtualenv env -p python3.8
$ source env/bin/activate
(env)$ pip install pfrl
```
そして、pfrlのexampleである、train_dqn_gym.pyを動かしてみます。
```
(env)$ python train_dqn_gym.py
...
ModuleNotFoundError: No module named 'packaging'
```
packagingを入れて、ふたたびチャレンジします。
```
(env)$ pip install packaging
...
gym.error.DeprecatedEnv: Environment version v0 for `Pendulum` is deprecated. Please use `Pendulum-v1` instead.
```
デフォルトでは、Pendulum-v0になっているので、これをPendulum-v1に変更して再度実行(プログラム内の～v0を片っ端から変更)。
```
(env)$ python train_dqn_gym.py
...
 File "*/env/lib/python3.8/site-packages/pfrl/utils/batch_states.py", line 13, in <genexpr>
    return tuple(x.to(device) for x in batched)
AttributeError: 'dict' object has no attribute 'to'
```
xにtoの属性がない（xはdict）。gymとかtorchのバージョンによって、利用される型が違うのではないかと推測（現時点のgymのバージョンは0.26.2）。
とりあえず、[gymのbug report](https://github.com/openai/gym/issues/3097)を見つけ、gymのバージョンを落としてみることに。bug reportでは、0.19.0にダウングレードしていましたが、Pendulum-v1に未対応だったので、0.22.0にダウングレードしました。
```
(env) $ pip install gym==0.22.0
(env) $ python train_dqn_gym.py
...
ModuleNotFoundError: No module named 'pygame'
```
pygameをpipで入れて、再度実行すると
```
(env) $ python train_dqn_gym.py 
Output files are saved in results/20230728T121809.087138
WARNING: Since https://github.com/pfnet/pfrl/pull/112 we have started setting `eval_during_episode=True` in this script, which affects the timings of evaluation phases.
INFO:pfrl.experiments.train_agent:outdir:results/20230728T121809.087138 step:200 episode:0 R:-1.1296703617134025
INFO:pfrl.experiments.train_agent:statistics:[('average_q', nan), ('average_loss', nan), ('cumulative_steps', 200), ('n_updates', 0), ('rlen', 200)]
INFO:pfrl.experiments.train_agent:outdir:results/20230728T121809.087138 step:400 episode:1 R:-1.2355617196091453
INFO:pfrl.experiments.train_agent:statistics:[('average_q', nan), ('average_loss', nan), ('cumulative_steps', 400), ('n_updates', 0), ('rlen', 400)]
...
```
なんとか動きました。
JavaScript Promiseとかについて(resolve, reject)

## resolve, rejectってなに

:::note
JavaScriptや他のプログラミング言語で非同期処理やPromiseを実装する際に使用される用語
:::

## Promiseとは

- 非同期処理をよりシンプルかつ効率的に扱うための機能
例）APIリクエストやファイルの読み込みなど
**非同期処理によって返される結果を、後続の処理で簡単に利用できるようにするためにプロミスが使われる**




## Promiseを使った例

```javascript
function fetchData() {
  return new Promise((resolve, reject) => {
    // 非同期処理を行う（APIリクエスト、ファイルの読み込みなど）
    // 成功した場合は resolve を呼び出し、失敗した場合は reject を呼び出す
  });
}

// Promiseを使用して非同期処理を実行し、成功・失敗時のコールバックを設定する
fetchData()
  .then((data) => {
    // 成功時の処理
  })
  .catch((error) => {
    // 失敗時の処理
  });
```
- **非同期処理の結果を表現**
- **成功時と失敗時の処理を簡潔に記述できる**

:::note
【resolveとrejectはコールバック関数】

- **resolve** : 非同期処理が**成功**した際に呼び出されるコールバック関数
- **reject** : 非同期処理が**失敗**した際に呼び出されるコールバック関数
:::

## resolve
- **プロミスを成功(Fulfilled)した状態にする**ための関数
非同期処理が成功したとき、その結果をresolveに渡すことでプロミスが成功状態となる
→後続の.then()メソッドで結果を処理できるようになる

## reject
- **プロミスを失敗(Rejected)した状態にする**ための関数
非同期処理が失敗した場合に、そのエラー情報をrejectに渡すことでプロミスが失敗状態となる
→後続の.catch()メソッドでエラーを処理できるようになる

***

### deferredとは

- 一般的には**非同期処理を管理するための手法**のこと
特定の状態（成功・失敗・保留）を表現して、その状態に応じコールバックを実行する仕組み

:::note warn
deferredは古いバージョンのjQueryでよく使われていたが、ES6以降ではネイティブなPromiseがサポートされている
よって**Promiseを使用することが推奨**されている
:::

- deferredはjQueryのDeferredオブジェクトのことを指す場合がある

#### jQuery.Deferredとは

:::note
jQueryの非同期処理を管理するための強力なユーティリティ
Promiseと同様に非同期処理の結果を表現し、成功・失敗時のコールバックを設定できる
:::
【Qiita初心者】コードの追記・削除を明示する記述方法


>>コードの種類にdiffを指定して、先頭を + - にしたらコードの追加削除を明示できます。他のシンタックスハイライトと共存させることは残念ながらできませんが

引用： https://qiita.com/Qiita/items/c686397e4a0f4f11683d



見た目はこんな感じになります。
コードのハイライトの色が、追記：緑、削除：赤、、となるので分かりやすいですね。

```diff:コードの種類をdiffにする
 ```diff とする

  def hoge(params)
    a = 100
+   b = "foo"
-   c = "bar"
  }
```


# 参考サイト：

https://qiita.com/Qiita/items/c686397e4a0f4f11683d
結構、間違ってる"浮動小数"の理解。概数、真数というデータ型


# 浮動小数点数と固定小数点数

浮動小数点数（float/double）と固定小数点数について、基本的な情報処理の知識としてみなさま学びますね。
そして、float/doubleは小数使いたくなったらプログラムでも気軽に使いますね。

「小数点の管理の仕方の違い」と習いますが、実際には非常に重要な機能の違いがあります。

# 0.1 + 0.2 => 0.30000000000000004

* 浮動小数点数 => ほとんどの小数は表現できないおおよその数字
* 固定小数点数 => 小数を表現できる実際の数字

浮動小数点数がどのぐらいおおよそかといえば、↓ぐらいデタラメ

```javascript
0.1 + 0.2
=> 0.30000000000000004

0.1 + 0.7
=> 0.7999999999999999
```
↑はJavaScriptで一瞬で再現可能。

`フロントエンドでお金の計算するの怖い`という時に使いましょう

# 2進数で無限小数になる数は表現できない

浮動小数点数が誤差を生じる理由は、2進数で無限小数になる数を正確に表現できないためです。ほとんどの10進数の小数は、2進数に正確に変換できません。
詳細は「浮動小数点 無限小数」とかでググってください。

「小数が浮動」ではなく「おおよその数しか表現できない」というのが浮動小数点数の正体なのです。

# "精度"という言葉の罠

「Javaだと精度の問題があるからBigDecimal使いましょう。」とよく言われます。

`精度`という言葉を単純に受け取ることは危険です。
例えば、「小数点以下10桁程度で誤差が生じるのかな？」というように考えてしまうと、仕様が1桁程度であれば関係ないと勘違いしてしまうかもしれません。というか私は何度かしています。
実際には上述の通りに、浮動小数そのものあが、おおよその数でしかなく、計算の過程でそれが累積してずれていきます。

「浮動小数使って計算したら値はずれてる覚悟がいる。」の方が感覚として大切です。

# 計算コストとかそういう話

じゃあ、みんな固定小数点使えば世界は平和じゃない。と感じますが、ゲーム/API/アプリ。。。とかなり(というかほとんど？)に浮動小数点数が使われます。CPUの性能指標とかまんまですね。
値がずれてしまう。と言っても精度の端の誤差ではあります。コンピューター全体でみると、精度の端の誤差よりも計算速度の方がよほど大切なのです。

コンピュータの世界って実は適当なのですね雑

# 概数、真数

MySQLやRDBMSなどのデーターベース界隈では「概数」「真数」という表現があります。
浮動小数などは↓のように対応します。

* 概数(浮動小数点型)
* 真数(固定小数点型、整数)

`おおむねの数`と、`まことの数`と、超分かりやすくないでしょうか？私は知ったときに目から鱗でした。

データーベース界隈では一般的に使われてる表現であり、別に世界で閉じておく必要もないと感じます。
プログラミング言語の説明にも普通に取り入れてしまって良いのではと思いました。
Security HubとGuardDutyを使った発見的統制 - 通知編

先日、第一子の保育園が内定しました。
保育園が決まったことに一安心しつつ、成長のスピードに少し物悲しくもなっています。

# はじめに
この記事は[前回の記事](https://qiita.com/ksaga9/items/9e3cdc2ee2dede710bee)の続きです。

前回の記事にも書きましたが、発見的統制は、発見したセキュリティリスクを利用者に通知する仕組みが必須です。
通知をしなければ、セキュリティ担当者は気づけないですし、毎日AWSコンソールを開いて異常が発生しているか確認することになります。

Security HubとGuardDutyの運用をスムーズにするための通知の仕組みと、この仕組みに至った背景について紹介します。

# アーキテクチャ
先に、現在のSecurity Hub・GuardDutyの通知のアーキテクチャ図をご紹介します。
![securityhub_qiita_202307271654.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3328969/f25b95df-83cc-fd39-2f37-8179b1c62ac0.png)

## 概要
- GuardDutyの通知は、Security Hubとの統合を使用してSecurity Hub経由で通知する
- リージョン集約を使用し、通知設定を1つのリージョンで完結させる
- 検出結果について
    - Slack通知
    - Backlog起票
    - StepFunctionsを使用して検出結果のステータスを変更する

## Security Hubのリージョン集約
Security Hubは[クロスリージョン集約](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/finding-aggregation.html)という機能があり、これを使用することで複数リージョンの検出結果やセキュリティスコアを1つのリージョンに集約することができます。
上記のアーキテクチャ図では、ap-northeast-1リージョンが集約リージョンにあたります。

この機能のメリットとしては、管理したいすべてのリージョンの集約結果を単一のリージョンで確認できるということと、**単一のリージョンで通知設定を完結できる**ということがあります。

一般的にSecurity Hubなどの検出をイベントドリブンで通知するにはEventBridgeでフィルタルールを作成し、送信したい通知先に送信する、という設定が必要です。
例えばSecurity Hubを複数リージョンで利用している場合、すべてのリージョンにEventBridgeのルールを作成する必要があります。そうしなければすべてのリージョンの結果を検知することができません。
しかし、このクロスリージョン集約機能を使用すれば1つのリージョンで通知設定が完結するため、非常にシンプルになります。

## Security HubとGuardDutyの統合
GuardDutyは、Security Hubと統合することができます。
統合すると、GuardDutyは検出結果をSecurity Hubに送信し、Security Hubの画面上でGuardDutyの検出結果を確認することができるようになります。

通常であればGuardDutyの検出結果をEventBridgeで設定する際はEventBridgeのソースを `aws.guardduty` とする必要がありますが、上記の統合を行っていると `aws.securityhub` をソースとして設定することができます。

この機能の何が嬉しいかというと、**上記のクロスリージョン集約と組み合わせることで、GuardDutyの検出と通知を1つのリージョンにまとめることができます。**

GuardDutyは、普段利用していないリージョン以外でも有効にすることが推奨されています。（[リージョンとエンドポイント）
](https://docs.aws.amazon.com/ja_jp/guardduty/latest/ug/guardduty_regions.html)
> GuardDuty は、サポートされているすべての AWS リージョン で有効にすることをお勧めします。

GuardDutyはSecurity Hubのようにリージョン集約の機能がありませんので、Security Hub経由で集約することでシンプルに実装することができます。

### 参考
[AWS Security Hub との統合](https://docs.aws.amazon.com/ja_jp/guardduty/latest/ug/securityhub-integration.html)
[【小ネタ】GuardDuty 通知は Security Hub 経由で行うとリージョン集約ができて便利](https://dev.classmethod.jp/articles/guardduty-notification-via-securityhub/)

## 検出結果
EventBridgeから、Slack通知と、Backlogへの自動起票を設定しています。
メール通知より普段から使用しているSlack、また当チームはBacklogで課題管理を行っているので自動でBacklogへの課題起票を行うことで取り漏らしと、対応完了までをトラッキングしやすくなりました。

Slackイメージのサンプルです
![スクリーンショット 2023-07-28 11.26.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3328969/47ef76a0-b094-429c-64f7-2db85ed1a436.png)

StepFunctionsはBacklogの自動起票のループを防ぐため、検出結果のワークフローステータスを更新するようにしています。
[AWS Security Hub の検出結果を自動で「通知済み」にする](https://dev.classmethod.jp/articles/set-securityhub-finding-as-notified)を参考に実装しています。詳細は、リンク先の記事をご参照ください。

# おわりに
私が入社した当時は、Security HubやGuarｄDutyが有効なっているだけで通知や運用が整理されていませんでした。
この構成になるまで紆余曲折ありましたが、ひとまず形になって運用も回るようになり、やってよかったと感じています。

しかしまだ改善点が多くあります。他にもAmazon InspectorやAWS Configを活用していきたいと考えています。
またアップデートがあれば記事にしていきたいと思います。
Ruby の文字列の展開の書き方 [式展開, sprintf, `String#%`]

Ruby の文字列の展開の書き方として以下の2点をまとめます。

- 式展開
- フォーマット文字列 sprintf, format, `String#%`

`String#%` のドキュメントを忘れやすいため備忘です。

## 式展開

https://docs.ruby-lang.org/ja/latest/doc/spec=2fliteral.html#exp

リテラルの式展開

```ruby
# ($ruby = "RUBY"の場合)

"my name is #{$ruby}" #=> "my name is RUBY"
'my name is #{$ruby}' #=> "my name is #{$ruby}"
```

> ダブルクォート(")で囲まれた文字列式、コマンド文字列および正規表現の中では#{式}という形式で式の内容(を文字列化したもの)を埋め込むことができます。式が変数記号($,@)で始まる変数の場合には {}を省略して、#変数名という形式でも展開できます。文字#に続く文字が {,$,@でなければ、そのまま文字#として解釈されます。明示的に式展開を止めるには#の前にバックスラッシュを置きます。
> 
> 式展開中の式は、ダブルクォートなども含めて Ruby の式をそのまま書くことができます。コメントも許されます。

## フォーマット文字列 sprintf, format, `%`

https://docs.ruby-lang.org/ja/latest/method/Kernel/m/sprintf.html

> sprintf(format, *arg) -> String
> format(format, *arg) -> String
> format 文字列を C 言語の sprintf と同じように解釈し、引数をフォーマットした文字列を返します。

https://docs.ruby-lang.org/ja/latest/method/String/i/=25.html

String のインスタンスメソッドの `String#%` も sprintf と同じです。

> self % args -> String
> printf と同じ規則に従って args をフォーマットします。
> args が配列であれば Kernel.#sprintf(self, *args) と同じです。それ以外の場合は Kernel.#sprintf(self, args) と同じです。

### sprintf フォーマット

> Ruby の sprintf フォーマットは基本的に C 言語の [sprintf(3)](https://pubs.opengroup.org/onlinepubs/009695399/functions/sprintf.html) のものと同じです。ただし、short や long などの C 特有の型に対する修飾子がないこと、2進数の指示子(%b, %B)が存在すること、sprintf のすべての方言をサポートしていないこと(%': 3桁区切り)などの違いがあります。

```ruby
# %d の整数出力
p sprintf("%d", -1) #=> "-1"
p sprintf("%d", 3.1) #=> "3"

# 幅指定、左詰め右詰め、0詰め
p sprintf("%+5d", 11)  #=> "  +11"
p sprintf("%+-5d", 11) #=> "+11  "
p sprintf("%+05d", 11) #=> "+0011"

# 精度指定
p sprintf("%10.5f", 10)  #=> "  10.00000"
```

### 引数指定

翻訳で引数の順番は変えないがフォーマット文字列の順番は変わるときによく使っています。

> %{name}
> Symbol のインスタンス name をキーとする Hash を引数にした場合、対応する値をフォーマットせずに参照します。幅や精度を指定するために使用することができます。

```ruby
p sprintf('%{foo}f : %{bar}+d', foo: 1, bar: 2) #=> "1f : 2+d"
p '%{foo}f : %{bar}+d' % { foo: 1, bar: 2 } #=> "1f : 2+d"

p '%{turn}ターンの間攻撃力を%{attack}倍' % { turn: 10, attack: 2.5 } #=> "10ターンの間攻撃力を2.5倍"
p '%{attack}x ATK for %{turn} turns' % { turn: 10, attack: 2.5 } #=> "2.5x ATK for 10 turns" # 例なので turns の単数形未考慮
```
Jinjaテンプレートから自作関数を呼び出す

ご閲覧ありがとうございます。オレンジ羽のlibra189です。
FlaskのJinjaテンプレートでFlask側で定義した自作関数を呼び出したいと思ったのですが、少し面倒だったので記録として残しておきます。

# 検証環境

| 環境 | バージョン |
| --- | --- |
| OS | MacOS 12.3 |
| Python | 3.9.6 |
| Flask | 2.0.2 |
| Jinja | 3.1.1 |

# 解決したい問題

例えば、Flaskで動的に画面に値を表示したい時、Jinjaにはそのような関数は用意されていないため、一般的にはテンプレート呼び出し時に結果を引き渡す必要があります

コード例

```python:app.py
from flask import Flask, render_template

app = Flask(__name__)

def get_host_name():
	return "Qiitan"

@app.route("/")
def root():
	return render_template("root.html", host_name = get_host_name())
```

```html:root.html
<html>
	<body>
		<div>ホスト名: {{ host_name }}</div>
		<!-- ホスト名: Qiitan-->
	</body>
</html>
```

上記は渡す値が1つだったのでまだマシですが、これが複数に渡ると管理が困難になります
下記のように多くのパラメータをとる画面をバリデーションに引っかかった等の理由で画面を戻す場合、パラメータをそれぞれ設定し直す必要があるためとても大変です
私はこれが原因で何度もエラーを出してます...

```python:app.py
@app.route("foo")
def many_params():
	return render_template("many_params.html",
                               param1 = "...",
                               param2 = "...",
                               param3 = "...",
                               param4 = "...",
                               param5 = "...",
                               and_more = "..."
                          )
```

# 実装

パラメータ設定が大変なのであればテンプレートで設定すればいいじゃんという発想の元です
Flaskインスタンス生成時にjinja_envというパラメータが設定されるので利用します

実装例

```python:app.py
def get_host_name():
	return "Qiitan"

app = Flask(__name__)

# jinja_env.globalsに名前と関数をセット
app.jinja_env.globals["get_host_name"] = get_host_name

@app.route("/")
def root():
	return render_template("root.html")
```

```html:root.html
<div>ホスト名: {{ get_host_name() }}</div>
```

下記URL先の既存関数と同じ名前で定義すると上書きされるっぽいので注意が必要です
[テンプレート#標準のコンテキスト - Flask](https://msiz07-flask-docs-ja.readthedocs.io/ja/latest/templating.html#standard-context)

# まとめ

2023年現在で新しくFlaskプロジェクトを始める人はいるのか疑問ですが、Flaskを使っている人は使ってみてください
今回の方法を用いれば、多数のViewで使う処理を共有できるようになります
しかし、Viewにビジネスロジックが漏れる可能性があるため使用には注意が必要です
(前職のプロジェクトではViewに漏れ出して管理が大変でした...)
用法要領を守って楽しくコーディングしましょう！

拙文最後までお読みいただきありがとうございます。
気軽にTwitterフォロー、いいね！をお願いします。

# 参考

[FlaskのJinja2テンプレでpython内の変数をどこでも使ってみる](https://qiita.com/you-me/items/c3068b2184c4a4a89176)
AndroidStudio Giraffeキター！

# AndroidStudio Giraffeの更新が乗ってきた
[release-notes](https://developer.android.com/studio/releases)を見るとJetpack Compose関連の改善が多いようです。
<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933408/76e16f13-710a-e657-cfe9-a10f8863796c.png">
## kotlin DSLがデフォルト
その中でも、gradleのビルドスクリプトがgrrovyからkotlin DSLがデフォルトに変わっています。（何故か上のrelease-notesには説明がない）
新規プロジェクトで、
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933408/e637fe22-8bf9-46ea-7570-85f3b9dfbf05.png">
* kotlin DSL
* kotlin DSL + Version catlog
* 従来のgroovy
が選択できます。

[それと同時にkaptからkspへの移行が推奨されています](https://developer.android.com/studio/build/migrate-to-ksp?hl=ja)

* Kapt（Kotlin Annotation Processing Tool）
* KSP（Kotlin Symbol Processing）

ですが、上記の公式ページの通りkaptからkspへの移行してgradle同期すると
```
Unable to load class 'org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData'.

This is an unexpected error. Please file a bug containing the idea.log file.
```
と、エラーなります。既に公式ページのkspのバージョンはバグがあり、古いようです。
```kotlin:build.gradle.kts
plugins {
    id("com.android.application") version "8.1.0" apply false
    id("com.android.library") version "8.1.0" apply false
    id("org.jetbrains.kotlin.android") version "1.8.22" apply false
    id("com.google.devtools.ksp") version "1.8.22-1.0.11" apply false
}
```
1.8.xxだと、1.8.22-1.0.11が最新のようです。(1.9.xxも出てますが)
* org.jetbrains.kotlin.android
* com.google.devtools.ksp

のバージョンは合わせておく必要があります。(ビルド時に「古い」とワーニングが出る)

## 新GUI
AndroidStudioはIntelliJをベースにしていて、約半年遅れくらいのペースでIntelliJの機能を取り込んでいます。既に、IntelliJは新GUIが使用可能になっています。
AndroidStudioも過去のバージョンでも自分で設定を変えることにより新GUIに切り替えは可能でしたが、[正式に設定画面に取り込まれました。](https://developer.android.com/studio/releases#new-ui-preview)
<img width="75%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933408/e92b8abe-5b1c-3006-7a4d-5fe577b654b0.png">
見た感じ・・・VsCodeに非常によく似てるのですが、どうやら開発者が元、VsCodeの開発者だったらしく。

今後はこのGUIが標準になってくと思われます。
[React] ページ移動する時アニメーション

今日はページを移動する時アニメーションを入れる方法について説明します。

# 基本セッティング

まずページを二つ作ります。

main page
```react:app.js
 function App() {
  return (
    <div className="App">
        <h1>main page</h1>
    </div>
  );
}
```

<br>

sub pageは別のファイルに作りました。
```react:SubPage.js
 function SubPage(){
  return(
    <div>
      <h2>sub page</h2>
    </div>
  )
}

export default  SubPage;
```

<br>

ページ移動のため、main pageにリンクを付けます。

```react:app.js
import { Routes, Route, Link, useNavigate } from 'react-router-dom'
import SubPage from './Page/SubPage.js'


function App() {
  let navigate = useNavigate();

  return (
    <div className="App">
      <div>
        <h1>main page</h1>
      </div>

      <Link to={'/subPage'}>sub page</Link>

      <Routes>
        <Route path="/subPage" element={<SubPage />} />
      </Routes>
    </div>
  );
}
```


<br><br>
# アニメーションを入れる手順

1. 変化以前の状態を作る
2. 変化以後の状態を作る

二つの状態を作って、transitionでアニメーションを適用します。
```css：app.css
.before {
  opacity: 0;
}

.after {
  opacity: 1;
  transition: opacity 1s;
}
```

<br>

基本状態をsub pageにつけて
```react:SubPage.js
    <div className="before">
      <h2>sub page</h2>
    </div>
```

<br>

sub pageが読まれたとき、つまりreturnするときにafterを付けるコードを作成します。

classを付けたり消したりするためにstateを使いました。

そしてuseEffectを使うとファイルがマウントする時実行するコードを書きました。

```react:SubPage.js
import { useEffect, useState } from "react";

function SubPage(){
  let [ani, setAni] = useState('')

  useEffect(()=>{
    setAni('after')
    return ()=>{
      setAni('')
    }
  }, [])

  return(
    <div className={"before " + ani}> {/* 分かち書き注意 */}
      <h2>sub page</h2>
    </div>
  )
}
```


以上です
ありがとうござい。
【SAP】Tricentis Toscaをインストールして困ったこと

# はじめに
当記事ではTricentisを使用するうえで困ったこと、その解決方法について記載します。
UIテストツールを導入した背景、その中でもTricentisを選んだ理由は以下の通りです。

## 前提
SAP BTP上に開発したアプリケーションをJenkins経由で自動でテストするため、Tricentisを活用したテスト自動化の仕組みを構築。
![image (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516839/886fc16b-2e2f-e31a-131b-6d0cc49ed11a.png)


## UIテストツールを導入した理由
1. 工数短縮
　開発メンバーがアプリケーションのテストにかける工数を最小限にしたい

1. 品質担保
　手動での単体テストと、Tricentisによる回帰テストの両方を行うことで、
　アプリケーションの品質を担保したい

## Tricentisを選んだ理由
- 2020年にSAP社とTricentis社がパートナーシップを締結。  
SAP BTPをはじめとしたSAP製品との親和性が高いため 
[参考資料](https://blogs.sap.com/2021/01/31/sap%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%BB%E3%83%86%E3%82%B9%E3%83%88%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E6%96%B0%E3%81%97%E3%81%84%E9%81%B8%E6%8A%9E%E8%82%A2%EF%BC%9Atricenti/)

- Jenkinsとの連携に対応していたため



# 環境
Windows10でインストールを行いました。

# スキャン時のエラー
スキャンしようとすると「Could not connect to 'TOSCAAutomationService', Please make sure it is started.」のエラーが発生しました。
![image (27).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516839/9d17f7ea-a505-693c-a9c9-95c3b8e82a9d.png)

:::note alert
Error：Could not connect to 'TOSCAAutomationService', Please make sure it is started.
:::
タスクマネージャーを確認すると、TOSCAAutomationServiceが表示されていません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516839/94bcd861-7b78-9d9c-6bbd-7c4190d2700a.png)
このサービスはTricentis Tosca起動時に自動的に起動されるものですが、インストールやリペアを行った際に起動されないことがあります。


# 解決方法
コマンドを使用してTOSCAAutomationServiceを再インストール、サービスを開始する必要があります。

#### 1. コマンドプロンプトを管理者として実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516839/b973133c-6024-e1d7-11f7-950a3016d49b.png)


#### 2. installutil.exe を含む Microsoft.NET フォルダー に移動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516839/27115a30-6eba-e53c-080f-73cf2cafcdfd.png)
```
cd C:\Windows\Microsoft.NET\Framework\v4.0.30319
```




#### 3. Tricentis.Automation.RelayServiceをインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516839/5e08bb7e-49c9-ef92-028a-e6923aa7fe39.png)
```
installutil.exe"C:\ProgramFiles(x86)\TRICENTIS\ToscaTestsuite\TBox\Tricentis.Automation.RelayService.exe"
```

#### 4. net startコマンドを実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516839/64521fd5-b8ac-b1e4-8b21-cdb1f8c9953d.png)
```
net start ToscaAutomationservice
```
**参考**
・[Tricentis](https://support-hub.tricentis.com/open?sys_kb_id=194a54eedb4f5c181ea7bb13f3961950&id=kb_article_view&number=KB0015302)



# 結果
TOSCAAutomationServiceが実行され、スキャンすることができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516839/eb06b3fb-5b01-6b66-0654-55f3795b6646.png)



# さいごに
当記事の件で上手く動作しない方の参考になれば幸いです。
週末を除いて 2 つのフィールド間の時差を表示する式(DateTime型)


+ [ormula to display time difference between 2 fields while excluding weekends](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007AiI2K)


/*合計日数*/(((Email_First_Reply_Date_Time__c - CreatedDate) - 
/*削除日数を計算します: 週数を数えて 2 を掛けると、合計日数から削除する日数がわかります*/ ((Email_First_Reply_Date_Time__c - CreatedDate) / 7) *2) * 1440)
/*合計日数に 1 日の分数である 1440 を掛けます*/ 

機能しているのかな？

+ [Help with Formula on Cases](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007erA7s)

```
IF( OR( weekday(datevalue(LastModifiedDate))= 1, weekday(datevalue(LastModifiedDate))= 7),

ROUND( 1440 * 

(( 5 * FLOOR( ( DATEVALUE( NOW() ) - DATE( 1900, 1, 8) ) / 7) + MIN(5, MOD( DATEVALUE(NOW() ) - DATE( 1900, 1, 8), 7) + MIN( 1, 24 / 24 * ( MOD( NOW() - DATETIMEVALUE( '1900-01-08 00:00:00' ), 1 )))))

-

( 5 * FLOOR( ( DATEVALUE( LastModifiedDate) - DATE( 1900, 1, 8) ) / 7) + MIN( 5, MOD( DATEVALUE( LastModifiedDate ) - DATE( 1996, 1, 1), 7 ) + MIN( 1, 24 / 24 * ( MOD( LastModifiedDate - DATETIMEVALUE( '1900-01-08 00:00:00' ), 1)))))),0

) + 119,

ROUND( 1440 * 

(( 5 * FLOOR( ( DATEVALUE( NOW() ) - DATE( 1900, 1, 8) ) / 7) + MIN(5, MOD( DATEVALUE(NOW() ) - DATE( 1900, 1, 8), 7) + MIN( 1, 24 / 24 * ( MOD( NOW() - DATETIMEVALUE( '1900-01-08 00:00:00' ), 1 )))))

-

( 5 * FLOOR( ( DATEVALUE( LastModifiedDate) - DATE( 1900, 1, 8) ) / 7) + MIN( 5, MOD( DATEVALUE( LastModifiedDate ) - DATE( 1996, 1, 1), 7 ) + MIN( 1, 24 / 24 * ( MOD( LastModifiedDate - DATETIMEVALUE( '1900-01-08 00:00:00' ), 1)))))),0

))
```
#0007 pythonのparserとは。

## はじめに
- 開発中の日付データをtimestampへ変換するためにparser関数を利用した。
- あまり馴染みがなかったため、調べてみた。

## parseとは
- まず英単語としての`parse`とは「解析する。分割する」という意味。
- 語源は、古フランス語のpart「分け前、部分...」、ラテン語partem（主格はpars）「一部、一片...」など。

[参考](https://www.etymonline.com/jp/word/parse#:~:text=13%E4%B8%96%E7%B4%80%E4%B8%AD%E9%A0%83%E3%80%81%E3%80%8C%E5%88%86%E5%89%B2%E3%80%81,%E3%81%A8%E9%96%A2%E9%80%A3%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82)

## parserを使った日付の変換
- parserについては述べると膨大になりそうなため、今回は仕事で用いた「日付の変換」のみを扱いたいと思います。
- parse関数を利用して文字列の日付（正規表現）をdatetimeに変換しています。
- datetime型なので、月や年での抽出、タイムスタンプへの変換が可能です。

```
>>> from dateutil.parser import parse

>>> str = "2023-12-31 15:30:45"
>>> print(str)
2023-12-31 15:30:45
>>> print(type(str))
<class 'str'>

>>> dt_parse = parse(str)
>>> print(dt_parse)
2023-12-31 15:30:45
>>> print(dt_parse.year)
2023
>>> print(dt_parse.month)
12
>>> print(type(dt_parse))
<class 'datetime.datetime'>

>>> print(dt_parse.timestamp() )
1704004245.0
```

## parserを使うと良いこと
- parseを使う大きな目的は「引数解析」となります。
- chatgptに引数解析の目的を伺ってみました。

>1. プログラムの挙動の制御： 引数の解析により、プログラムの実行時にユーザーがコマンドラインから引数を指定できるようになります。これにより、プログラムの挙動を柔軟に制御できるようになります。例えば、コマンドライン引数で指定したファイルを処理するか、モードを切り替えるか、出力の形式を変更するかなどのオプションを設定することが可能です。
>2. プログラムのパラメータの指定： プログラムには、実行時に必要なパラメータやデータがある場合があります。これらのパラメータを引数として渡すことで、プログラムが適切に動作するようになります。例えば、ファイルパス、データベースの接続情報、処理の設定などが該当します。
>3. ユーザーに対する使いやすさと効率性の向上： 引数の解析により、ユーザーがスクリプトやプログラムを実行する際に、具体的なオプションや引数を指定することが容易になります。ユーザーがコマンドラインヘルプを参照してどのような引数が利用可能かを確認し、それに基づいてスクリプトの実行を行うことができます。これにより、プログラムの使いやすさと効率性が向上します。
>4. 再利用性の向上： 引数の解析を行うことで、プログラムを別のプロジェクトや環境に移植しやすくなります。コマンドライン引数を使用することで、同じプログラムを異なる設定やパラメータで実行することが容易になります。

- 私の解釈では、引数解析の目的は「ユーザーに想定通りの動きへ導くこと」かと思っています。

## argparse関数に関して

- pythonでは標準ライブラリに含まれるargparseモジュールのクラスや関数が引数解析に用いられます。
- argparseを使うことで、コマンドライン引数を簡単に解析でき、ヘルプメッセージを表示できることで、ユーザビリティを高めることが可能となります。

## おわりに
- argparse関数を利用したscriptを作ってみたいと思います。
useRefでDOMノードを扱うときはElementRefが便利！

## useRefのおさらい
Reactではレンダリング間で保持して欲しいが、レンダリングに関わらないような値を扱うときは、`useRef`というReact独自の関数から提供される値を利用します。

```ts
// コンポーネントのトップレベルで`useRef`を呼び出し、第一引数には初期値を渡す
// 型はジェネリクスで指定できる
const ref = useRef<number>(0);
// `ref`はオブジェクトでレンダリング時の値を`ref.current`にもつ
// ref.currentはミュータブルな値
console.log(ref.current);
```

例えば`useRef`の値を用いたカウンターを作成することを考えてみます。`useRef`を用いた値はレンダリングに関わらないので、値自体の更新を行ってもレンダリングは発火せず更新後の値が描画されることはありません。
しかし、この値は異なるレンダリング間で値を保持する性質があるため、別の何かしらの原因で再レンダリングが発火し新たに画面が描画される時には更新後の値が参照されます。
実際に`useRef`を用いたカウンターは以下のように動作します。`useState`から提供される値を更新して再レンダリングを引き起こすとレンダリング前に更新してきた値が画面に描画されることが確認できます。

https://codesandbox.io/embed/youthful-ellis-gkzkhd?fontsize=14&hidenavigation=1&theme=dark


### useRefとDOM操作
このような性質を持つ`useRef`ですが、この値はDOMの操作によく使われます。

```tsx
const SampleComponent: FC = () => {
  const ref = useRef<HTMLInputElement>(null);
  
  return <input ref={ref} />;
};
```

このように記述すると、画面に描画された時に`ref.current`に`input`のDOMノードが設定されます(描画前は`null`が設定されています)。設定したDOMノードを用いてその要素特有の操作や値を取得できます。
```ts
const handleFocus = () => {
  if (!ref.current) {
    return;
  }
  console.log(ref.current.labels);
  ref.current.focus();
}
```
`ref.cuurent`から実行するメソッドや取得する値の種類は`useRef`を呼び出す時に設定する型に依存します。
`HTMLInputElement`を渡した場合は`input`で行える操作を`ref.current`を介して行えます。この場合は`focus`メソッドを実行することや`labels`を取得することができます。これらの呼び出しは`div`にはないものなので`HTMLDivElement`を渡した場合には存在しないプロパティへのアクセスとなりエラーが発生します。
実際に`ref`を渡した要素と異なるインターフェイスを渡したとしてもエラーTypeScriptのエラーにはならず実行時に予期しない動きになる恐れがあるので正しいものを渡せていることに注意してください。
単に`useRef`でDOM要素を扱うことを表したいときは`HTMLElement`を渡すこともできます。

### ElementRef
DOM要素に`ref`渡すときに`useRef`に対する型付けは`HTMLElement`のようなインターフェイスを渡す他にもReact(`@types/react`)が提供する`ElementRef`を用いて解決することができます。
```tsx
const SampleComponent: FC = () => {
  const ref = useRef<ElementRef<'input'>>(null);
  
  return <input ref={ref} />;
};
```
`ElementRef`の型引数として対象の要素を文字列で渡すように型を指定して使います。
この型の引数には要素の文字列以外にも`forwardRef`などを用いて作成した`ref`を渡すコンポーネントの型も渡せます。
これによって`ref`を別のコンポーネントに渡す場合にどの要素を渡せば良いか分からなくても、コンポーネントをもとに型を与えられます。

```tsx
import { ElementRef, forwardRef, useRef } from "react";

const TextField = forwardRef<HTMLInputElement, { name: string }>(
  ({ name }, ref) => {
    return <input type="text" name={name} ref={ref} />;
  }
);

export default function App() {
  const ref = useRef<ElementRef<typeof TextField>>(null);
  return <TextField ref={ref} name="name" />;
}
```
この形式の型指定ができる点で`ElementRef`はとても便利な型となります。
DRF勉強vol5_APIドキュメントの生成

## はじめに

DRF(Django REST framework)の勉強のため、以下書籍を参考にサンプル作成します。  
最終的には書籍にあるVue+DRFの作成を目指します。

1. 現場で使えるDjangoの教科書
2. 現場で使えるDjango REST Frameworkの教科書

Vol.4では別オリジンで動作するフロントエンド(Vue)からアクセスするためのCORS設定を行いました。
Vol.5ではOpenAPI形式のAPIのドキュメント生成をできるようにします。


### 環境

- Intel Mac 13.4.1(c)
- Python 3.11.4
- Django 4.2.3
- DRF 3.14.0


## 手順

### drf-spectacularの導入

`drf-spectacular`パッケージを導入します。

```sh
$ poetry add drf-spectacular
```

<details>
<summary>この時点のpyproject.toml</summary>

[tool.poetry]
name = "backend"
version = "0.1.0"
description = ""
authors = ["Jozuo <jozuo.dev@gmail.com>"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.11"
django = "^4.2.3"
djangorestframework = "^3.14.0"
djangorestframework-simplejwt = "^5.2.2"
dj-rest-auth = "^4.0.1"
django-cors-headers = "^4.2.0"
drf-spectacular = "^0.26.4"


[tool.poetry.group.dev.dependencies]
debugpy = "^1.6.7"
pytest = "^7.4.0"
black = "^23.7.0"
ruff = "^0.0.280"
mypy = "^1.4.1"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
</details>


### 設定変更

設定ファイルに以下を追加します。

```diff:config/settings.py
  INSTALLED_APPS = [
      --- 省略 ---
      # 3rd party package
      "rest_framework",
      "rest_framework.authtoken",
      "dj_rest_auth",
      "corsheaders",
+     "drf_spectacular",
      --- 省略 ---
  ]
  
  --- 省略 ---

  REST_FRAMEWORK = {
      "DEFAULT_AUTHENTICATION_CLASSES": [
          "dj_rest_auth.jwt_auth.JWTCookieAuthentication",
      ],
+     "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
  }
```

### ルート設定

ルート設定に以下を追加します。

```diff:config/urls.py
+ from django.conf import settings
  
  --- 省略 ---
  
+ if settings.DEBUG:
+     urlpatterns += [
+         path("api/schema/", SpectacularAPIView.as_view(), name="schema"),
+         path(
+             "api/schema/swagger-ui/",
+             SpectacularSwaggerView.as_view(url_name="schema"),
+             name="swagger-ui",
+         ),
+         path(
+             "api/schema/redoc/",
+             SpectacularRedocView.as_view(url_name="schema"),
+             name="redoc",
+         ),
+     ]
```

## Swagger-UIでのAPI動作確認

ブラウザで`http://localhost:800/api/scheme/swagger-ui/`にアクセスするとAPIドキュメントが表示されます。  
認証不要なAPIはこの状態で呼び出すことができますが、認証が必要なAPIは認証エラーになるため続けて認証の設定を行います。

### JWTトークンの発行

Swagger-UIから`POST: /api/v1/login/`エンドポイントを利用してJWTトークンを発行します。  
以下のいずれかの組み合わせでAPIを実行します。

- ユーザー名 + パスワード
- メールアドレス + パスワード

ログインに成功すると、以下のようなレスポンスが表示されるため、`access`の値をコピーします。

```json
{
  "access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjkwNTA1OTEwLCJpYXQiOjE2OTA1MDIzMTAsImp0aSI6IjQ3Y2JmYTYwYTU1NzQ5MzJiNDg2MmNiMWY1MzE2MTg5IiwidXNlcl9pZCI6MX0.kYB0PQgBZnWB-O0a1Y5Z5or--BPSEzeykA34pwdHN_8",
  "refresh": "",
  "user": {
    "pk": 1,
    "username": "admin",
    "email": "admin@example.com",
    "first_name": "",
    "last_name": ""
  }
}
```

### JWTトークンの設定

Swagger-UI画面右上にある「Authorize」をクリックすると認証用ダイアログが表示されます。  
このアプリケーションはヘッダー認証を利用しているため`jwtHeaderAuth (apiKey)`側するので、そちらのValueに **"JWT [上で取得したトークン値]"** を入力してAuthorizeを行います。

これで認証が必要なAPIもSwagger-UIから呼び出すことが可能になります。
Go言語で外部APIを呼び出しとJSONの取り扱いについて

# はじめに

今日はGo言語を用いて外部APIを呼び出し、その結果をJSON形式で取り扱う方法について記載します。
これはWebサービスを開発する際によく用いられる技術で、非常に役立つスキルです。

# 必要なパッケージのインストール

まずはじめに、`net/http`と`encoding/json`という2つのパッケージが必要となります。これらはGo言語の標準ライブラリに含まれているので、追加でインストールする必要はありません。

# 外部APIの呼び出し

まず、`net/http`パッケージを使って外部APIを呼び出します。`http.Get`関数を使うと、HTTPのGETリクエストを送ることができます。

以下に簡単な例を示します。

```go
package main

import (
	"fmt"
	"net/http"
)

func main() {
	// http.Getを用いて外部APIを呼び出す
	resp, err := http.Get("https://api.example.com/data")
	// エラーハンドリング
	if err != nil {
		fmt.Printf("The HTTP request failed with error %s\n", err)
	} else {
		fmt.Println("The HTTP request succeeded")
	}
}
```

このコードは "https://api.example.com/data" というURLに対してHTTPのGETリクエストを送り、その結果を表示します。

# JSONの取り扱い

次に、`encoding/json`パッケージを使ってAPIから返されるJSONデータを取り扱います。例えば、APIから以下のようなJSONが返されるとしましょう。

```json
{
	"data": "Hello, World!"
}
```

これを取り扱うためのGoのコードは以下の通りです。

```go
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

// APIから返されるJSONの構造を定義する
type APIResponse struct {
	Data string `json:"data"`
}

func main() {
	// http.Getを用いて外部APIを呼び出す
	resp, err := http.Get("https://api.example.com/data")
	// エラーハンドリング
	if err != nil {
		fmt.Printf("The HTTP request failed with error %s\n", err)
	} else {
		// ioutil.ReadAllでレスポンスボディを全て読み取る
		data, _ := ioutil.ReadAll(resp.Body)

		var responseObject APIResponse
		// json.UnmarshalでJSONデータをGoのオブジェクトに変換する
		json.Unmarshal(data, &responseObject)

		fmt.Println(responseObject.Data)
	}
}
```

このコードでは、APIから返されるJSONデータを`ioutil.ReadAll`関数で全て読み取ります。次に、`json.Unmarshal`関数を使ってJSONデータをGoのオブジェクトに変換します。

注意すべき点は、`APIResponse`という型を作成し、その中にAPIから返されるデータの構造を定義しています。ここでは簡単のため、`Data`という1つのフィールドだけを持つ構造体を作成していますが、実際のAPIのレスポンスに合わせて構造体を定義する必要があります。
iterm2の設定変更をしてみた

# 0. はじめに
## iterm2のインストール
https://iterm2.com/

# 1. 基本設定
## ショートカット
- 以下で設定
https://medium.com/macoclock/5-must-have-key-mappings-on-iterm2-to-be-more-productive-21c4daf56348
https://saphir-jaune.hatenablog.com/entry/2019/08/31/222038

## フォント
- フォントサイズと、テキストの縦・横幅の調整

![Screenshot 2023-07-28 at 11.42.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2674841/d5f80148-3daf-5f22-0e15-d540ec8e1863.png)

# 2. Oh My Zsh のインストール
以下の記事を参考
https://qiita.com/ryamate/items/075c34fcf29d0889c15a