OmniAICreator/Qiita-1.07M huggingface dataset:
【AWS】CloudWatchのログをKinesisで抽出してS3に保存する【ログ抽出】

## 初めに
AWSのサービスを使用したログはCloudWatchLogsに集約することができるが、そのログの中で特定のパターンのログを抽出してS3に保存したい場面がある。
今回の記事ではCloudWatchLogsのログをKinesisDataFitehoseで抽出/変換してS3にファイル出力する構成を記事にした。


## 使うAWSサービス
・Amazon CloudWatch
・Amazon Kinesis Data Firehose
・AWS Lambda
・Amazon S3

## 実現方法
### アーキテクチャ
![CW→Kinesis→S3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/dbf34184-63d2-89aa-97f8-161c32cd6151.png)

### ①Lambda関数の作成
<Lambda関数を作成する>
・使用用途に応じたLambda関数を作成する
### ②KinesisDataFirehoseの設定
＜KinesisDataFirehose配信ストリームを作成する＞
##### 「ソースと送信先を選択」
・以下の設定を行う
ソース：DirectPUT
送信先：Amazon S3
![Kinesis設定1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/269083a4-419a-2cc5-4ee6-e995f0452945.png)


##### 「レコードを変換及び転換」
・以下の設定を行う
データ変換をオンにする：チャックボックスを有効化
AWS Lambda関数：①で作成したLambda関数を指定する
![Kinesis設定2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/3b0ef5cf-b7f1-4314-054e-73235c2e53cc.png)

##### 「送信先の設定」
・以下の設定を行う
S3バケット：抽出/変換結果を保存するS3バケットを指定する
S3バケットプレフィックス(オプション)：プレフィックスの指定がある場合や、年月日単位でプレフィックスを分けたいなどの場合は入力する
![Kinesis設定3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/912af366-827f-4aca-3858-acf4f166e9e7.png)
![Kinesis設定4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/75fd987d-00d2-6ced-16ca-4744096280fe.png)


### ③CloudWatchの設定
<サブスクリプションフィルターを作成する>
##### 「ロググループ」
・以下の順に選択してサブスクリプションフィルターを作成する画面を表示する
ロググループ > サブスクリプションフィルター > KinesisFirehoseサブスクリプションフィルターを作成
![CloudWatchLog設定1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/ad2308fe-f9f5-f40c-21ca-57c35e24a22c.png)

##### 「Kinesis Firehose配信ストリームを選択」
・②で設定したKinesis Firehoseストリームを選択する
![CloudWatchLog設定2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/5ffc85a7-3021-2f3f-146d-6f333f748857.png)


## 最後に一言
CloudWatchのログを確認する際にどうしても目的のもの以外のログが多く、なかなか目的のログが発見できないことがある。その対策のためにあらかじめKinesis経由で目的の内容だけ抽出した結果をS3に残しておけば例えば障害発生時の調査などで利用できるのではないかと思う。
DOCTYPE宣言がeslintのチェックにひっかかる場合の対処法

## 概要
DOCTYPE宣言がeslintによるチェックでエラーとして扱われた場合の対処法を記載します。
まぁ実際のシステム開発において、出くわす機会はあまりないかもしれませんが。。

## 事象
htmlファイルの1行目がパースエラーとなります。

```console
$ npm run lint

> (package)@(version) lint
> eslint index.html


(absolute path)\index.html
  1:1  error  Parsing error: Unexpected token <

✖ 1 problem (1 error, 0 warnings)
```

該当のhtmlファイルを確認すると、もちろん１行目はDOCTYPE宣言なわけです。

```html:index.html
<!DOCTYPE html>
<html class="no-js" lang="en">
  <head>
  :
  : (略）
  :
</html>
```

## 解決策

[eslint-plugin-html](https://github.com/BenoitZugmeyer/eslint-plugin-html/) をインストールしましょう。

`npm install --save-dev eslint-plugin-html`

インストール後、.eslintrc.jsonにオプションを追加します。

```:.eslintrc.json
    "plugins": [
      "html"
    ],
```

追加後に再度、 `npm run lint` を実行すると、DOCTYPE宣言がエラーとして扱われなくなっているはずです。

## そもそも...
ESLintは、JavaScript以外のコードの解析をサポートしていません。
万能に思えてもJavaScript専用のコード解析ツールなわけですね。
【JavaScript】分割代入の際に別名をつける方法


以下のようにすることでオブジェクトを分割代入する際に変数に別名をつけることができます。

```js
const sampleObject = {
  id: 1,
  name: "foo",
}

const { id: itemId, name: itemName } = sampleObject

console.log(itemId) // 1
console.log(itemName) // foo

console.log(id) // エラー
console.log(name) // エラー
```
【React】APIを実行する方法を整理してみた

## 1. Fetch APIを使用する
Fetch APIは、ブラウザ内で簡単にHTTPリクエストを行うための方法です。以下は、Fetch APIを使用してGETリクエストを行う例です。

```js
fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => {
    // データを処理するコードをここに記述
  })
  .catch(error => {
    console.error('リクエストエラー:', error);
  });
```

## 2. Axiosを使用する
AxiosはHTTPクライアントライブラリで、Fetch APIよりも多くの機能を提供します。Axiosを使用するには、まずAxiosをインストールする必要があります。

```bash
npm install axios
```
そして、以下のようにAxiosを使用してAPIリクエストを行うことができます。

```js
import axios from 'axios';

axios.get('https://api.example.com/data')
  .then(response => {
    // レスポンスデータを処理するコードをここに記述
  })
  .catch(error => {
    console.error('リクエストエラー:', error);
  });
```

## 3. async/awaitを使用する
async/awaitを組み合わせて非同期APIリクエストを行うこともできます。以下は、async/awaitを使用したFetch APIの例です。

```js
async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    // データを処理するコードをここに記述
  } catch (error) {
    console.error('リクエストエラー:', error);
  }
}
fetchData();
```

## 3. ライブラリを使用する:
Reactのコミュニティでは、APIリクエストをより簡単に行えるライブラリが提供されています。例えば、react-queryやswrなどがあります。これらのライブラリは、データ取得やキャッシュなどを効率的に扱うのに役立ちます。

以上の方法を使用して、Reactアプリケーション内でAPIリクエストを行うことができます。選択肢は多く、プロジェクトの要件や好みに合わせて最適な方法を選ぶことが重要です。
matplotlibで図に文字出すのめんどくさいときの簡単な方法；instead of ax.text

# 対象読者
* **パッと図を作りたいだけなのに、図に文字を入れるのがめんどくさい！**
* `plt.***` でサッと図を作りたいけど、<strong>位置調整のために `ax.***` スタイルで書くことを強要されるのがイヤだ！</strong>
　

# TL; DR[^TL;DRとは]
`ax.text` の代わりに凡例 `plt.legend`を使うとラク！ 
　
[^TL;DRとは]:TL; DRは Too Long; Didn't Readの略らしい。みんな使ってるので本記事でも使ってみた。しかし...（[参考](https://qiita.com/kei_0121/items/2e2e070702a82a79de8e "TL;DRはフォーマルに向かないだって!?")）
　
　

# テキスト表示のめんどくさいポイント
## 位置調整がめんどくさい
パッと文字列を図に入れたいだけなのに、

* データの範囲がわからないとき
* データの範囲が変動するとき

こういう場合、テキトーに `plt.text` または `ax.text` を使ってしまうと、テキストがあっちゃこっちゃに行ってしまいます。

　
図中のテキストの位置を前もって思い通りに指定するには
1. 図の端を `get_xlim` で取得して、それを用いてテキストの位置を調節する（めんどすぎ）
2. `ax.text` の引数に `transform=ax.transAxes` を入れる（`ax.***` スタイルを強要される）

という方法を採らなければならない（他にもあるかも）。

　
# 解決策
上記のめんどくささを解消した方法が、<font color="red">**凡例を使う**</font>というものです。
　
【メリット】
* 位置調整を勝手にしてくれる
* `plt.***` スタイルでもOK
　

【デメリット】
* 2行以上のテキストには向かない
　

# 例（図に平均値をパッと載せたいとき）
```Python
import matplotlib.pyplot as plt
import numpy as np

# ランダムなデータを生成
data = np.random.randn(1000)  # 1000個のランダムなデータポイント
ave = np.average(data)

# ヒストグラムを作成（ラベルに書きたいテキストを入れておく）
plt.hist(data, bins=20, color='skyblue', edgecolor='black', label=f"Ave.: {ave:.3g}")
plt.title('Histogram')  # グラフのタイトル
plt.xlabel('Value')  # x軸ラベル
plt.ylabel('Frequency')  # y軸ラベル

###凡例を使う########################
plt.legend()
####################################

# グラフを保存
plt.savefig("histogram_with_average.png")
```

![histogram_with_average.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603341/8153c1c9-53d7-0c6c-bf93-ad838f5c4eb0.png)
iOS では中国語（繁体字）を設定しているのに Flutter アプリで中国語（簡体字）で表示されてしまう

# 概要

iOS では中国語（繁体字）を設定しているのに Flutter アプリで中国語（簡体字）で表示されてしまうことがあり解決方法を探した結果をメモしておきます。

# 解決方法

Flutter で supportedLocales の設定があり、こちらに言語コード（中国語 `zh`）と合わせて `Locale` 設定ができました。

ここで、スクリプトコード `scriptCode` の `Hant` や国コード `countryCode` の `TW` を指定することで中国語（繁体字）で表示できました。

# 参考 URL

以下の URL に仕組みが詳しく記載されていました。

https://api.flutter.dev/flutter/widgets/WidgetsApp/supportedLocales.html

# i18n 対応

ARB ファイルを利用して多言語対応している場合は、`@@locale` に `zh_TW` など国コードを一緒に指定すればよさそうです。

https://localizely.com/flutter-arb/

https://github.com/google/app-resource-bundle/wiki/ApplicationResourceBundleSpecification
ノーコードでポートフォリオサイトを作ってみた

![スクリーンショット 2023-10-20 18.11.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705702/a5335ebe-dbcd-335f-f850-95bdddd82e3f.png)

## はじめに
クリエイターやエンジニアの方にとって、作品をまとめたポートフォリオサイトはまさに自分の顔と言っても良いでしょう。
とは言うものの、自分のようにコーディングとかよくわからん！というクリエイターの方もいらっしゃると思います。

今回は、ノーコード・外部サービスを使って自分のポートフォリオサイトを作ってみました！
選定した基準、作り方などを紹介します。

## きっかけ
自分の場合、主にX（旧Twitter）にこれまで作ったものを投稿しており、投稿をまとめられるモーメント機能をポートフォリオ代わりに使っていました。
しかし、例の一件によりモーメント機能が消滅し、新規で追加することが不可能に。
そんなこんなでそろそろ個人のポートフォリオサイトがあっても良いだろう…と思い、今回作ることを決めた次第です。

## どのサービスを使う？
ポートフォリオサイトを作成できるサービスは色々あります。
たとえば、
- [foriio](https://www.foriio.com/)
- [BRIK Portfolio](https://brik.co.jp/portfolio/)
- [RESUME](https://www.resume.id/)
…などがあります。

別にどれを使っても良いとは思うんですが、
自分は[Adobe Portfolio](https://portfolio.adobe.com/)にしました！

なぜかというと…
**Adobe税を払っているから！！！** です。
というのは半分冗談ですが、Adobe CCユーザーの方なら無料で使えるので毎月それなりの金額を払っているのなら使ってみても損はないと思います。
あとはさすがAdobeということでデザインが綺麗そうだったから、というのもあります。

## 中身を作る
作り方はいたってシンプルです。
こんな記事Qiitaに書いていいのかな？と思うぐらいコードは書きません。

こんな感じでテーマがあらかじめ用意されているので…

![スクリーンショット 2023-10-20 17.51.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705702/c3a74124-af0d-b74d-7566-32f6eb20356a.png)

そのうちの一つを選ぶとこんな画面が出てきます。

![スクリーンショット 2023-10-20 17.53.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705702/3fcec086-cf2c-8559-4cbe-3f2de16b646d.png)

直感的な操作で作れるようになっています。

![スクリーンショット 2023-10-20 17.55.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705702/c8130d61-8935-fb4b-3f2b-ba5839441a4e.png)

タイトル・画像・説明文を入れると…

![スクリーンショット 2023-10-20 17.57.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705702/11bf53a7-655e-660c-8d25-8a6be89173c4.png)

トップ画面にも反映されます。

![スクリーンショット 2023-10-20 17.59.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705702/f28a84eb-7e4a-1259-1560-aefd6528a7b5.png)

タイトルを好きな画像に変えることもできます。

![スクリーンショット 2023-10-20 18.07.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705702/cf41a5a0-ab30-644f-ea6d-1deb488f7a39.png)

フッター、背景色、フォントなんかも変えられます。
そんなこんなでサイトが完成！

![スクリーンショット 2023-10-20 18.11.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705702/a5335ebe-dbcd-335f-f850-95bdddd82e3f.png)

## 公開

公開ボタンを押せば公開！…されるのですが、せっかく自分のポートフォリオサイトなんだから独自ドメインがいいよね、ということで他サイト🌸で取得したドメインを使います。

カスタムドメインを入力するとIPアドレスが表示されるので、お使いのドメインのサービスのコントロールパネルでそちらを設定してください。

https://chizutodesign.com/

できました〜！！
一切コードを書かずに独自ドメインの素敵なポートフォリオサイトができました！やったね！

## よかったところと、もうちょっとなところ

:::note info
よかったところ
・コードを一切書かずに作れる
・レスポンシブ対応している
・Adobe税を払っている人は無料で作れる
:::

:::note warn
もうちょっとなところ
・デザインフォーマットはある程度決められているので、自由に作りたい方には向かないかも
・画像のURLがCDNで指定できず、見た目があまり綺麗じゃない
:::

## まとめ
コードを一切書かずに独自ドメインのポートフォリオサイトが作れました！
他のサービスも色々ありますし、一から構築するのも良いと思うのでぜひ作ってみてください🎉

※画像は全てAdobe Portfolioよりキャプチャしました。
SAT成為台灣學子出國留學的關鍵


出國留學一直以來都是台灣學子追求國際化教育的夢想，而在這個過程中，許多考試和申請程序都扮演著關鍵的角色。本文將探討其中最重要的因素之一，即SAT考試，以及它如何成為台灣學子[出國留學](https://www.apexcharity.org/news/3/83)的關鍵，包括簽證和國際學校的申請過程。

SAT：闖入美國大學的通行證
[SAT](https://www.apexcharity.org/news/3/84)，是一項常見的大學入學考試，尤其在美國大學的申請程序中占據著重要地位。對於台灣學子而言，SAT測驗不僅可以評估他們的學術水準，更可以增加他們進入美國大學的機會。

提升[美國簽證](https://www.apexcharity.org/news/3/94)申請的成功率
當台灣學子決定前往美國留學時，簽證是必不可少的一環。然而，美國留學簽證（F-1簽證）的申請程序相對繁瑣，需要提交大量文件和證明材料，以確保學生具有足夠的學術實力並且不會在美國非法滯留。在這方面，SAT的成績可以為學生的簽證申請提供有力的支持。當申請者在SAT中獲得優秀的成績時，這不僅表明他們在學業上表現出色，也增加了他們被授予簽證的可能性，因為這表明他們有著成功完成高等教育的潛力。

打開進入[國際學校](https://www.apexcharity.org/news/3/82)的大門
許多台灣學子的留學夢想包括進入美國的國際學校，這些學校提供國際化的學習環境和世界一流的教育資源。然而，進入這些學校通常需要競爭激烈的申請程序。SAT的成績在這種情況下可以成為學生的競爭優勢。許多國際學校將SAT成績視為錄取決策的一個關鍵因素，因為它提供了一個客觀的標準來評估學生的學術能力。

總之，SAT不僅是台灣學子出國留學的必要考試，而且它在簽證申請和國際學校錄取中扮演著關鍵的角色。通過努力學習和備考SAT，台灣學子可以提高自己出國留學的成功率，實現他們的國際教育夢想，走向更廣闊的世界。
（メモ）Sentinel-2 のダウンロード ～ dataspace.copernicus.eu からダウンロード　（失敗）

# はじめに

## 追記（2025-02-16）
この記事の作成当時はデータをダウンロードできませんでしたが、2025年2月時点では同じ方法でダウンロードできました。関係メモはこちらです。
https://qiita.com/T-ubu/items/4133703595b3b0474160


## 動機
以前、OpenDataHubからのダウンロード方法をメモしたのですが、久しぶりにアクセスしたら以下のメッセージが出ていました。SciHubが2023年10月末に終わるそうです。

新しいところからのダウンロードを試してみたので、現時点の状況をメモしておきます。まだダウンロード出来ていないので、正しいダウンロード方法を知りたい方はもうしばらくお待ちください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/2bde7c5a-b749-1667-9aa0-600a0aeb37fd.png)

## 目標
上記のメッセージにあるdataspace.copernicus.eu からSentinel-2画像データをダウンロードしてみます。私の環境はGoogle Chromeです。



# 手順
## Step 1. 新しいページにアクセス
https://dataspace.copernicus.eu/ にアクセスします。下の図の様な感じです。
右上にある緑のLOGINボタンを押してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/c22be4d7-dd31-e078-5155-6c611e28a3f1.png)

前のアカウントでも入れるかなとやったら、OpenDataHubのユーザー名とパスワードでは入れませんでした。仕方がないので、ログインの右にあるRegisterボタンから登録をします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/46b228f7-d6a8-87cc-e913-bbcedab36c38.png)


## Step 2. ユーザー登録
ユーザー登録をします。名前やメールアドレス等を入力して進みます。以下のフォームを入れるだけ出登録できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/ea35ae92-101d-adc6-386c-3338b6b3f264.png)



## Step 3. データを探す（ブラウザの立ち上げまで）
ログインすると、いくつか画面がありますが、データを選びたいのでExplore dataを選びます（下図）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/874a8fe1-0e9e-0729-18a0-e559cdd30abb.png)

Copernicus BrowserとData collectionsの2つボタンがありますが、ブラウザーの方を選びます（下図）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/c76ac1a3-64ff-c63f-c682-0a5efc11667d.png)

Browserは反応が結構遅いです。しばらく待って以下の図のような画面が出てきました。使い方は前のものに似ていそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/53623e3d-b488-9d5a-e4ff-f3d80711c5a7.png)

## Step 4. データを探す（データの選択）
範囲指定からデータを選びます。
まずはブラウザで地図をズームします。以前は対象エリアを右クリックで選択しましたが、今回は右の作図ツールを使えばいいようです。対象領域（Area of Interest）を作るのに、ファイルのアップロード、矩形作成、ポリゴン作成などいくつか種類があるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/3bae47dd-5263-aaf2-dfe4-931e1352b08d.png)

今回は矩形での選択にして雲の量や日付範囲も設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/566888e0-b197-5c6d-adbe-0f2cc01da762.png)

出てきた結果からダウンロードボタンをクリック。（ログインが求められました。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/0e072a5b-b174-d815-2d9d-6a3ecbe7295a.png)

その結果、ログインしないとダウンロード出来ないというような表示がでました。そもそもログインしていたはずなのですが・・・。もう一度ログインしてもダメで現在ここでスタック中。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/fb1744d3-1e42-302e-fd28-21d0750903c3.png)

# まとめ
2023年10月23日時点で、私はまだ新しいデータブラウザからダウンロード出来ていません。ログインのところが上手くいかないので、ブラウザの設定が悪いのかもしれません。もう少ししたら再度チャレンジ試してみようと思います。

# 参考ページ
https://dataspace.copernicus.eu/
https://qiita.com/T-ubu/items/e40e49b3321dfc720b78
エクセル　VBAで関数セット

## はじめに
最近エクセルVBAを触ったが、忘れそうなので、これを見れば思いだせるようメモっておく。

## 例
ある特定の範囲に関数をセットする。
直接シートに関数をセットすればいいが、今回はあえてvbaでセットする方法を記載する。

sheet2と、sheet1のある個所を掛けるという関数をセットする。

Set sh1 = ThiwWorkbook.Sheets(‘sheet1)

'以下のように関数をセットする
sh1.Range(“G5”).formula =“=G11*Sheet2!G7”
sh1.Range(“G6”).formula =“=G12*Sheet2!G8”
sh1.Range(“G7”).formula =“=G13*Sheet2!G9”
sh1.Range(“G8”).formula =“=G14*Sheet2!G10”
sh1.Range(“G9”).formula =“=G15*Sheet2!G11”
sh1.Range(“H5”).formula =“=H11*Sheet2!H7”
sh1.Range(“H6”).formula =“=H12*Sheet2!H8”
sh1.Range(“H7”).formula =“=H13*Sheet2!H9”
sh1.Range(“H8”).formula =“=H14*Sheet2!H10”
sh1.Range(“H9”).formula =“=H15*Sheet2!H11”


## 関数設定にあたって
・相対参照、絶対参照について
・セルのアドレスより$で分割

### 相対参照、絶対参照
文字で書くとややこしいが、理解要。
Excelでセル参照をする際に使用されるもの。
要はコピーで行とか列にそって変えていくなら相対参照、。
1. 相対参照：数式セルをコピーした時、自動的に参照セルも移動する状態。
2. 絶対参照：数式セルをコピーしても、参照セルが固定された状態。
3. 複合参照：「1」と「2」を組み合わせた状態。

相対参照は、数式セルをコピーした時、自動的に参照セルも移動する状態。一方、絶対参照は、数式セルをコピーしても、参照セルが固定された状態。複合参照は、相対参照と絶対参照を組み合わせたもの。

絶対参照は行の番号と列のアルファベットの前にそれぞれ`$`を入力し指定する。A1のセルを常に参照したい場合は、`$A$1`と入力。相対参照は、数式セルをコピーした時、自動的に参照セルも移動する状態。例えば、B1に`=A1+50`という数式を入力すると、下のセルへとコピーすると参照先がコピー先に応じて変化する。複合参照は、両方組み合わせたもので、`$A1`や`A$1`などがある。


https://www.lifehacker.jp/article/120827excelreference00/

### セルのアドレスより列を取得
colLetter = Split(Cells(1, c).Address, "$")(1)

このコードは、セルのアドレスを「$」で分割して、列名を取得するもの。

Cells(1, c) は、1行目のc列目のセルを表す。
例えば、cが3なら、Cells(1, c)はC1セルになる。
Cells(1, c).Address は、セルのアドレスを文字列で返す。
例えば、C1セルのアドレスは`$C$1`となる。
Split(Cells(1, c).Address, "")は、セルのアドレスを「」で区切って配列する、例えば、`$C$1`を`$`で区切ると、「」「C」「1」という3つの要素からなる配列になる。
`Split(Cells(1, c).Address,"$")(1)` は、配列の2番目の要素を取り出す。例えば、「」「C」「1」という配列の2番目の要素は「C」。
`colLetter = Split(Cells(1, c).Address,"$")(1)` は、colLetterという変数に配列の2番目の要素を代入する。今回は、「C」をcolLetterに代入する。


### 今回の場合
絶対参照は使用せず、相対参照での関数記載となる。
```vb
Sub SetFormulas()
    Dim sh1 As Worksheet
    Dim r As Integer, c As Integer
    Dim startCol As Integer, endCol As Integer
    Dim startRow As Integer, endRow As Integer
    Dim srcRow As Integer, destRow As Integer
    Dim formula As String, colLetter As String, colLetterSheet2 As String
    
    ' Sheet1のワークシートオブジェクトを初期化
    Set sh1 = ThisWorkbook.Sheets("Sheet1")
    
    ' 開始と終了の列番号を定義（G=7、AE=31）
    startCol = 7
    endCol = 31
    
    ' 開始と終了の行番号を定義（5から9）
    startRow = 5
    endRow = 9
    
    ' 行と列を通じてループを回して、関数を設定
    For r = startRow To endRow
        srcRow = r + 6 ' 対応するソース行（11から始まる）
        destRow = r - startRow + 7 ' 対応するSheet2の行（7から始まる）
        
        For c = startCol To endCol
            ' 列番号を文字に変換
            colLetter = Split(Cells(1, c).Address, "$")(1)
            
            ' Sheet2の対応する列文字を変換（G7から始まるので7列先）
            colLetterSheet2 = Split(Cells(1, c - startCol + 7).Address, "$")(1)
            
            ' 関数を設定
            formula = "=" & colLetter & srcRow & "*Sheet2!" & colLetterSheet2 & destRow
            sh1.Cells(r, c).formula = formula
        Next c
    Next r
End Sub

```
例)sh1.Range(“H9”).formula =“=H15Sheet2!H11”

## おわりに
他にも忘れないよう記載しておくべきことは色々あるが、いったん関数セットからメモをとった。
Auto Scaling Group(ASG)にアタッチ

# 結論
ASGにアタッチする場合、希望数が自動で増えるみたいです。

# アタッチ前の構成
次のよう固定数維持のキャパシティにしていて、インスタンスが２台ASGで起動中です。
希望：２、最小：２、最大：２

![アタッチ１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3563936/cedaa0d7-91d7-3330-10ac-364492e99302.png)

# キャパシティ変更
現状のままでは最大キャパシティに該当しアタッチ操作をするとエラーとなりアタッチできません。
なので最大キャパシティを次のよう増やします。
希望：２、最小：２、最大：３
![アタッチ２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3563936/fdf63f93-5931-243f-0eb2-d2762d16f327.png)

# アタッチ操作
起動中インスタンスをASGにアタッチします。
![アタッチ３.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3563936/a92bab17-d09b-f432-e510-9e546967c5e9.png)

当然アタッチに成功するのですが、希望キャパシティも増えます。
![アタッチ５.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3563936/0fc5fc4e-7a79-27b6-5daa-812a923d7b9a.png)

ASGユーザガイドの考慮事項にその旨書かれてます。
![アタッチ６.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3563936/fb0d638c-3d8c-698c-961f-468d2068f801.png)
【Swift】CIFilterで画像の色数を制限する

# はじめに
CIFilterを使って画像の色数を制限してみます

# サンプルアプリ
![Simulator Screen Recording - iPhone 15 - 2023-10-23 at 22.45.10.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/b49deec8-1d44-9bd5-6095-b6a95ad367a2.gif)

# 実装
```swift
import SwiftUI

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

    @State private var uiImage: UIImage?
    
    @State private var colorCount: Int = 0

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

                HStack(spacing: 15) {
                    Button {
                        applyColorPosterizeFilter()
                    } label: {
                        Text("適用")
                    }

                    Button {
                        uiImage = nil
                    } label: {
                        Text("リセット")
                    }
                }
                
                Stepper(value: $colorCount) {
                    Text("色数: \(colorCount)")
                }
            }
            .padding(.horizontal, 20)
        }
    }

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

        guard let colorPosterizeFilter = CIFilter(name: "CIColorPosterize", parameters: [
            kCIInputImageKey: inputImage,
            "inputLevels": colorCount
        ]) else { return }
        guard let outputImage = colorPosterizeFilter.outputImage else { return }
        guard let cgImage = context.createCGImage(outputImage, from: outputImage.extent) else { return }
        self.uiImage = UIImage(cgImage: cgImage)
    }
}
```

# おわり
CIFilterはまだまだたくさんあるので一通り触ってみたいです
Ubuntuでユーザーにsudo権限を付ける

## 環境
Ubuntu 22.04 LTS

## 状況
Ubuntuサーバーは自宅のADにドメイン参加しています。
ドメインユーザーでUbuntuサーバーにログインは出来ますが、sudo権限がついていません。

## Sudo権限を付ける
sudo出来ないユーザーがおらず、rootでログインしている場合
```
gpasswd -a ユーザ名 sudo
```

sudo出来るユーザーがいる場合
```
sudo gpasswd -a ユーザ名 sudo
```

## 設定の確認
「/etc/group」ファイルを確認して、sudoグループに対象ユーザーが追加されていることを確認します。
```
cat /etc/group | grep sudo
```
Tmux入門

最近、GPUアクセラレーションされたターミナルエミュレータ、Kittyを再び使い始めました。

私のMacでは、既存のキーボードショートカットと何らかの衝突があるようで、Kittyの「Layouts」機能が使えないのが悩みの一つです。キーボードショートカットを変更する選択肢もありますが、それよりは別のように解決します。それは、古くて信頼性のある技術、Tmuxに頼っています。

![Screenshot 2023-10-23 at 22.20.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295096/b3f03979-b8a3-d650-8eb5-876f595d8093.png)


ただ、基本的な使い方が少し錆びているので、自分用にこの簡単なガイドをまとめました。他の人にも役立つかもしれないと思い、こちらで共有します。

インストールしていない場合は、`brew install tmux` でインストールできます。

1. **新しいtmuxセッションを開始する**: ターミナルを開いて、`tmux`を実行します。
  
2. **垂直に分割する**: tmuxセッション内で`Ctrl-b`を押した後、`%`を押します。これでウィンドウが垂直に分割されます。
  
3. **水平に分割する**: `Ctrl-b`を押した後、`"`を押します。

### ナビゲーションと管理の基本コマンド:

- **ペイン間を移動する**: `Ctrl-b`を押した後、矢印キーを押します。
  
- **ペインを閉じる**: `Ctrl-b`を押した後、`x`を押します。
  
- **セッションから切り離す**: `Ctrl-b`を押した後、`d`を押します。

### ベストプラクティス:

- **セッションに名前を付ける**: `tmux new -s セッション名`で、後でセッションを識別しやすくします。
  
- **セッションに再接続する**: `tmux attach -t セッション名`は、切り離されたセッションに戻る際に便利です。
AtCoder初心者振り返りメモ ABC216～

# 216 C-問題
https://atcoder.jp/contests/abc216/tasks/abc216_c

**問題文**
空の箱があります。髙橋君は以下の2 種類の魔法を好きな順番で好きな回数使えます。
・魔法 A ：箱の中にボールを 1 つ増やす
・魔法 B ：箱の中のボールの数を 2 倍にする
合計 120 回以内の魔法で、箱の中のボールの数をちょうど N 個にする方法を 1 つ教えてください。

**ポイント**
・ゴールから逆算して解いていく
「2倍する　⇔　2 で割る」「1つ増やす　⇔　1 をひく」

````Python:216C.py
# 入力 
N = int(input())

# 答えを格納する
ans = ""

while N:            # N がゼロになるまで逆算していく
    if N % 2 == 0:  # 2で割れるならBを先頭に入れる、割れない場合はAを先頭に入れる
        ans = 'B' + ans
        N //= 2
    else:
        ans = 'A' + ans
        N -= 1
print(ans)
`````

# 217 C-問題
https://atcoder.jp/contests/abc217/tasks/abc217_c

![217C.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547298/d6d51c3b-682e-79cb-002d-a5bb8e3ed813.png)

**ポイント**
・index を合わせるためにリストの先頭を [0] で埋める
・リストのindex1から出力するときは、print(*Q[1:])　と記述する

````Python:217C.py
# 入力例
3
2 3 1

N = int(input())

# P[0] を埋めるため先頭に　[0] をプラス
P = [0] + list(map(int, input().split()))
# P: [0, 2, 3, 1]

# リスト Q を用意
Q = [0] * (N + 1)

for i in range(1 ,N + 1):
    Q[P[i]] = i

# Q: [0, 3, 1, 2]

# 先頭は、不要なので インデックス1から出力する
print(*Q[1:])

答え
3 1 2

`````
AWS AutoscalingGroup（ASG） 固定数維持を試してみた

# 目的
ASGで２台固定起動するよう設定しているが、３台固定起動するよう試してみます。

# 前提
キャパシティは以下の状態でインスタンス２台がASGにアタッチされている状態です。
希望：２、最小：２，最大：２

![asg1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3563936/b0411c24-79e7-d6b8-e54a-db4b484e8c19.png)

# スケールアウト（追加）
１台スケールアウトさせたいのでキャパシティを次のよう変更します。
希望：３、最小：３，最大：３

![asg2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3563936/594d552c-12c3-0dbc-b68e-4a432e3b8d27.png)

# 動作確認
インスタンス管理画面でASGに１台スケールアウトされてくることを確認できます。
ステータスはまだ「Pending」になっています。
![asg4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3563936/616bdac7-fdc7-92d2-ed8c-3db692f6474b.png)

少し待つとステータスが「InService」になったことを確認できました。
![asg5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3563936/253a8f87-ab1a-48bb-8c3f-0383a00b8caa.png)
NCMBのスクリプトで、blastengineを使ってメールを送信する

[NCMB](https://mbaas.nifcloud.com/)に用意されているスクリプトは、サーバーサイドで実行するコードをクラウド上で実行できる機能です。Node.jsとRubyのコードをクラウド上で実行し、結果を取得できます。

主にガチャのようなクライアントに記述したくないコードを実行したり、APIキーを使ったアクセスなどで活用できます。今回はメール送信サービスの[blastengine](https://blastengine.jp/)を使って、スクリプトでメール送信を実装します。

## 必要なライブラリ

ネットワークアクセスを行う `superagent` をインポートします。 `crypto` はAPIトークン生成用です。

```javascript
const request = require('superagent');
const crypto = require('crypto');
```

## URL、定数の定義

blastengineのAPIへリクエストするための変数を定義します。

- APIユーザーID
- APIキー

```javascript
const BLASTENGINE_USER_ID = 'USER_ID';
const BLASTENGINE_API_KEY = 'API_KEY';
```

その他、固定値を用意します。

```ts
const FROM_NAME = '管理者';
const FROM_EMAIL = 'info@example.com';
const CC_EMAIL = 'test@example.jp';
const SUBJECT = 'お問い合わせありがとうございます';
```

## リクエストに伴う処理

NCMBのスクリプトは、リクエストごとに以下の関数を実行します。

```javascript
module.exports = async (req, res) => {
  // この中に処理を書きます
}
```

### HTTPヘッダーを作成

ユーザーIDとAPIキーを使って、HTTPヘッダーの `Authorization` にセットするトークンを生成します。

```javascript
// トークンの生成
const userId = BLASTENGINE_USER_ID;
const APIKEY = BLASTENGINE_API_KEY;
const str = `${userId}${APIKEY}`;
const hashHex = crypto
	.createHash('sha256')
	.update(str, 'utf8')
	.digest('hex');
const token = Buffer
	.from(hashHex.toLowerCase())
	.toString('base64');
```

### リクエストボディを作成

今回はリクエストされた `email` パラメーター宛にリクエストボディを作成します。

```javascript
// リクエストボディから、blastengineのリクエストを作成
const { body } = req;
const response = await request
	.post('https://app.engn.jp/api/v1/deliveries/transaction')
	.send(
		{
			from: {
				email: FROM_EMAIL,
				name: FROM_NAME,
			},
			to: body.email,
			cc: [CC_EMAIL],
			subject: SUBJECT,
			encode: 'UTF-8',
			insert_code: Object.entries(body).map(([key, value]) => {
				return {
					key: `__${key.toUpperCase()}__`,
					value,
				};
			}),
			text_part: `__ACCOUNTNAME__様
お問い合わせいただきありがとうございます。内容を確認し、追ってご連絡いたします。

会社名：
__COMPANY__
お名前：
__ACCOUNTNAME__
お問い合わせ内容：
__MESSAGE__`,
		}
	)
	.set('Authorization', `Bearer ${token}`)
	.set('Content-Type', 'application/json');
```

### レスポンスを返す

メール送信APIのレスポンスを返却します。

```javascript
res.json(response.body);
```

## スクリプトからの呼び出し

スクリプトでは以下のように呼び出します。下記例は、上記スクリプトを sendmail.js としてアップロードした場合です。

```javascript
const json = await ncmb
	.Script
	.data({
        email: "test@example.com",
        company: "テスト会社",
        accountname: "担当者名",
        type: "お問い合わせ種別",
        message: "お問い合わせ内容",
    })
	.exec('POST', 'sendmail.js');
if (json.delivery_id) {
	// メール送信成功
} else {
	// メール送信失敗
}
```

## まとめ

blastengineはAPIキーを使って簡単にメール送信ができます。アプリからメール送信したり、お問い合わせなどに利用できるでしょう。

アプリにはプッシュ通知もありますが、メールもよく利用されます。メールが必要な際に、blastengineを利用してみてください。

[スクリプト (JavaScript & Monaca) : 基本的な使い方 | ニフクラ mobile backend](https://mbaas.nifcloud.com/doc/current/script/basic_usage_javascript.html#/JavaScript/)
止血剤市場調査：輸血ニーズの増加、外科治療のニーズの増加、がん患者数の増加が促進されるリサーチネスターによる世界分析2023-2033

リサーチ・ネスターは次のタイトルのレポートを発表した<b>「<a href="https://www.researchnester.jp/reports/hemostats-market/4484" target"_blank">止血剤の市場調査：</a>世界の需要分析と機会展望2033年"</b>この調査レポートは、止血材の世界市場を用途別、製品別、エンドユーザー別、地域別に分類し、詳細な概要を掲載しています。
さらに、詳細な分析として、市場の成長に関連する現在および将来の市場動向に関する詳細な考察とともに、業界の成長指標、阻害要因、需給リスクを網羅している。

世界の止血材市場は、予測期間（2023-2033年）に約6％のCAGRで成長すると予測されている。用途別では、外傷、心臓血管外科、整形外科、形成外科、神経外科、一般外科、その他に区分される。すべてのセグメントの中で、整形外科セグメントは2033年末までに最も高い収益を上げるだろう。外科医数の増加と骨折症例の増加により、成長が見込まれている。
止血材の世界市場成長は、手術件数の増加や交通事故による負傷の増加が牽引する。また、がん患者の増加や輸血を必要とする人々の増加が市場成長を促進すると予想される。
地域別では、北米、欧州、アジア太平洋、中南米、中東・アフリカ地域に区分される。なかでも北米市場は、2033年末までに最も高い収益を上げると見られている。慢性疾患の有病率が高く、献血や輸血が増加していることが、北米市場の成長を押し上げる。

![Hemostats-Market-Size.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491677/97b7f155-c824-3592-f446-077fe3892358.jpeg)
<b>このレポートの詳細についてはこちらをご覧ください：</b>
<b><a href="https://www.researchnester.jp/reports/hemostats-market/4484" target"_blank">https://www.researchnester.jp/reports/hemostats-market/4484</a></b>

この調査はグローバルな性質を持ち、以下の国の市場に関する詳細な分析をカバーしている North America (U.S., Canada), Europe (U.K., Germany, France, Italy, Spain, Hungary, Belgium, Netherlands & Luxembourg, NORDIC [Finland, Sweden, Norway, Denmark], Poland, Turkey, Russia, Rest of Europe), Latin America (Brazil, Mexico, Argentina, Rest of Latin America), Asia-Pacific (China, India, Japan, South Korea, Indonesia, Singapore, Malaysia, Australia, New Zealand, Rest of Asia-Pacific), Middle East and Africa (Israel, GCC [Saudi Arabia, UAE, Bahrain, Kuwait, Qatar, Oman], North Africa, South Africa, Rest of Middle East and Africa). さらに、市場規模、前年比成長率および機会分析、市場プレイヤーの競争調査、投資機会、将来の展望に対する需要などを含む分析も、調査報告書の中で取り上げられ、表示されている。

<b>交通事故による負傷者の増加が市場成長を促進する</b>
自動車の衝突事故や歩行者が自動車にはねられる事故は、被害者の重傷や過剰出血につながるため、世界の止血材市場の成長ドライバーとして機能している。WHOによると、毎年約130万人が交通事故により死亡している。
しかし、熟練した訓練士の不足、制御不能な出血の発生、製品の法外な価格などは、予測期間中、世界の止血材市場の成長の主な阻害要因として作用すると予想される。
本レポートはまた、以下の企業プロフィールを含む世界の止血材市場の主要企業の既存の競争シナリオを提供しますPfizer Inc., Integra Life Sciences Corporation, Baxter, Medtronic, Stryker, BD (Becton, Dickinson and Company), Biom’up Innovative Surgery, Johnson & Johnson Services, Inc., CryoLife,Inc.,HemostatisLLCなどがある。プロファイリングでは、事業概要、製品およびサービス、主要財務情報、最近のニュースおよび開発など、企業の主要情報を掲載しています。全体として、当レポートは、業界コンサルタント、機器メーカー、拡大機会を探している既存企業、可能性を探している新規企業、その他の利害関係者が、現在進行中および今後予想される動向に従って市場中心の戦略を調整するのに役立つVの詳細な概要を描いています。

<b>レポートサンプル@を請求する</b>
<b><a href="https://www.researchnester.jp/sample-request-4484" target"_blank">https://www.researchnester.jp/sample-request-4484</a></b>

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

# はじめに
本記事では、Pandasライブラリの関数`read_csv()`で読み込める圧縮ファイルについて記載します。`read_csv()`という名前から拡張子「.csv」しか読み込みできないと思われがちですが、csvが入っている圧縮ファイルも読み込むことができます。

# 読み込める圧縮ファイルについて
拡張子が「.gz」、「.bz2」、「.zip」、「.xz」、「.zst」、「.tar」 、「.tar.gz」、「.tar.xz」、「.tar.bz2」の圧縮ファイルを読み込むことができます。（[Pandas APIリファレンス参照][reference]）

[reference]:
https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html

# read_csv()の記載方法
「.csv」と記載方法は同じで、拡張子の部分を変えるだけになります。
```python:zipファイルの場合
import pandas as pd

#拡張子を変える
df = pd.read_csv("圧縮ファイル名.zip")
```

※圧縮ファイル名.zipの中には、csvファイルが1つ入っています

# 注意点
圧縮ファイル内に入れることのできるファイルは1つになります。複数入れてしまうと「Multiple files found in ZIP file. Only one file per ZIP」といったエラーが発生します。

# 終わりに

今回は`read_csv()`で読み込める圧縮ファイルについて記載しました。仕事で使っているデータが最近、csvからbz形式で配布されるようになったため、今回の手法を扱いました。分析に使うファイルが圧縮して送られてくる場合や、csvのままだと容量を圧迫する場合に使えそうです。
【個人開発】【iOS】ゲーム感覚でIT知識を学べる「ITクエスト」をリリースしました！

こんにちは！趣味で個人開発をしているりょうやです。
エンジニア歴が約3年間になるのですが、ITの知識をしっかりと学び直したいと思い、ゲーム感覚で勉強できるアプリを開発しました。

https://apps.apple.com/us/app/it%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88/id6469339499

# アプリ概要

このアプリ「ITクエスト」は、ITにまつわるクイズを解きモンスターを倒してレベルを上げる、ゲームをしながらITの知識を勉強することができるアプリです。
問題は「初級」「中級」「上級」に分かれており、それぞれ『ITパスポート』『基本情報技術者試験』『応用技術者試験』レベルの問題が出題されます。
他にも『ネットワーク系』『セキュリティ系』『データベース系』の問題も選ぶことができます。
また、クイズには「おとも」というキャラを連れていくことができ、モンスターを倒すサポートをしてくれます。
ガチャでアプリ内のコインを使えば、新しいおともを仲間にすることができます。

# 開発に至った経緯

エンジニアとして働いている中で、IT知識があるかないかはすごく重要になると感じています。
勉強すれば取得できる資格は多いですし、IT業界で仕事をスムーズに進めるためには大切な要素になります。
また、全く知識が無い状態でIT関連の勉強をするのは結構ハードルが高いです。

なので、ゲーム感覚で楽しくIT知識が学べるようなサービスが必要だと感じて開発しました。

# アプリの機能

### クイズ機能

選んだクイズによって出題される問題の難易度が変わります。
正解するとモンスターにダメージを与えて、不正解だと自分がダメージを受けます。
問題の難易度によって、ゲームクリア時の獲得できる経験値とコインが変わります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597913/76db9119-c109-efdb-f515-934412859a50.png)

### おとも機能

クイズを解いてモンスターを倒すときにサポートしてくれる「おとも」というキャラを選ぶことができます。
体力と攻撃力はおともの種類で様々です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597913/362d9a35-aefd-2824-c639-d9252bc3eec3.png)

### ガチャ機能

ガチャを利用しておともをゲットすることができます。
レア度は「ウルトラレア」「スーパーレア」「レア」「ノーマル」と分かれており、レアレリティが高いものほど出現率が低いです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597913/f28713d5-a2be-b5bd-37e9-7558b2182685.png)

### デイリー機能

１日１回だけ挑戦できる問題があって、クリアすると通常よりも豪華な報酬を受けることができます。

### 最後に

ゲーム感覚で学ぶことで、IT知識を習得するハードルが下がるので、初学者の勉強のサポートになればと思います。
[備忘録]Next.js13の動的ルーティングのパラメーター取得

# きっかけ
Next.js12からNext.js13で変わったAppRouterで動的ルーティングも変わっていたので
## どう変化したのか
### Next.js 12(ディレクトリ構造)
```
|--page
   |-- _app.tsx
   |-- [id].tsx
```
### Next.js 13(ディレクトリ構造)
```
|--app
   |-- layout.tsx
   |-- page.tsx
   |-- [id]
        |-- page.tsx
```

### Next.js 12(パラメーター取得)
```
import { useRouter } from 'next/router';

export default function Index() {
    const router = useRouter();
    const { id } = router.query;
}
```
### Next.js 13(パラメーター取得)
```
export default function Index(props) {
    const id = props.params
}
```
## 感想
Next.js 13で動的ルーティングについて調べても情報が少ないと感じました。12と13を比較すると見た目の通り、楽になりました。
LinuxサーバのIPアドレスを固定する方法

# 動機
サーバを再起動するとIPアドレスが変わることがあり、クライアントのWindowsからSSH接続するときに`.ssh\config`に記載したホスト名で接続できない。

# 環境
```
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04.3 LTS"
```

# 方法

まずネットワークの設定ファイルを確認する。
```
$ ls /etc/netplan
00-installer-config.yaml
$ sudo cat /etc/netplan/00-installer-config.yaml
# This is the network config written by 'subiquity'
network:
  ethernets:
    enp3s0:
      dhcp4: true
  version: 2
```
このようにネットワークの設定ファイルは`/etc/netplan`配下に格納されている。
辞書順で`/etc/netplan`配下の`.yaml`ファイルをすべて参照し、最後に参照したものを採用する方式である。
今回は`01-network-manager.yaml`というファイルを作成する。
```
$ sudo cat /etc/netplan/01-network-manager.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    enp3s0:
      dhcp4: no
      addresses: [xxx.xxx.xxx.xxx/xx]
      routes:
        - to: default
          via: xxx.xxx.xxx.xxx
      nameservers:
        addresses: [8.8.8.8,8.8.4.4]
```

## ポイント
- `enp3s0`の行は環境によって異なる。`ip a`コマンドを実行し、マシンが接続しているネットワークデバイス名を採用する。
- `dhcp4: no`とすることでdhcp機能（自動でIPアドレスを割り当てるなど）を無効化できる。
- `addresses`にはその環境で利用できる他マシンと重複しないアドレスを設定する。
例えば、`ip a`コマンドで確認できるinetの値が`192.168.1.xxx/24`であったら、おそらく重複しないであろう`192.168.1.50/24`などを設定する。
- `via`の行はデフォルトゲートウェイを設定する。現在使用しているものを`route -n`で確認できる。
- 最後の`addresses`にはDNSサーバのアドレスを設定する。特に要件がなければGoogleが提供するパブリックDNSサーバである`8.8.8.8`と代替DNSサーバの`8.8.4.4`を設定する。
- `yaml`はインデントが意味を持つので注意して入力する。

ファイルを作成出来たら下記のコマンドで設定を有効化する。
```
sudo netplan try --timeout 10
```
サーバの再起動は不要で、更新後のIPアドレスでSSH接続できれば完了。

# 参考
[Canoninal Netplan(公式)](https://netplan.io/)
【AWS】EC2(t2.micro)環境でnpm run devが通らない時の対応

AWS EC2の無料枠t2.micro上に構築したLaravel環境で、開発サーバを起動するために「npm run dev」を実行した際、ビルド処理が途中でストップしてしまう問題が発生しました。
その原因と対応方法について調べた内容を備忘録として記載しておこうと思います。

## 環境
* Amazon EC2 t2.micro (AMI: Amazon Linux 2023)
* Laravel 10.16.1 (ビルドツール: Laravel Vite)
* Node 18.13.0
* npm 9.2.0

## 【問題】 ビルド処理が終わらない
上記の環境にて、Laravelの開発環境を構築するために「npm run dev」を実行してビルド処理を行った際、ビルド処理が終わらず開発サーバが起動しない問題が発生しました。
ちなみに、ローカル環境では問題なく実行できたので、AWS環境が原因だと考えられます。
```shell
$ npm run dev

> dev
> vite
# この状況でストップする
```

## 【原因】 メモリ容量が不足していた
使用していたインスタンスタイプは無料枠のt2microで、メモリ容量が1GiBと非常に少ないタイプのものでした。
恐らくビルド処理に必要なメモリ容量が不足しているのが原因で、処理が止まってしまったと考えられます。

## 【対応】 スワップ領域を確保する
インスタンスメモリを増やすためにスペックの高いインスタンスタイプに変更するのも手ですが、なるべく料金をかけずに無料枠のままで対処したいという気持ちもあったので、今回はスワップ領域を確保するという方法で対処します。

スワップ領域は、仮想メモリとして使用されるディスク上のメモリのことです。スワップ領域を確保することで、物理的なメモリが不足した際でも実際のメモリよりも大きなメモリがあるように動作させることができます。

以下を実行して、現在のメモリ容量を確認します。
```
$ free -h
               total        used        free      shared  buff/cache   available
Mem:           949Mi       634Mi        67Mi       5.0Mi       247Mi       167Mi
Swap:             0B          0B          0B
```
AWS EC2のデフォルトではスワップ容量は0Bなのでスワップ領域を確保します。

### スワップ領域の計算
一般的に推奨されているスワップ領域は物理メモリの容量に応じてある程度決まっているので、そちらを参考にします。

|  物理メモリ容量(RAM)  |  推奨されるスワップ容量  |
| ---- | ---- |
| RAM <= 2GB  | RAM × 2 |
| 2GB <= RAM <= 8GB  | RAM × 1 |
| 8GB <= RAM <= 64GB | 4GB |

今回は物理メモリが1GBなので、推奨スワップ容量は2倍の2GBとなります。

### スワップファイルを作成
スワップ領域を確保するために、スワップ領域をファイルとして保管する方法を用います。
以下を実行してスワップファイルを作成します。
```
sudo dd if=/dev/zero of=/swapfile bs=1M count=2048
```
ddコマンドを用いて、「/dev/zero」を入力ファイルとして「/swapfile」ファイルに出力します。
「de/zero」は特殊ファイルで全て0で埋まったファイルを読み出します。
bsオプションはブロックサイズを表し、countオプションでブロックサイズの個数を指定します。

つまり、今回の例では、1MB × 2048 = 2048MB(2GB)のサイズの0埋めされたファイルを/swapfileファイルとして出力するというコマンドになります。

### スワップファイルの権限を変更
作成したスワップファイルはroot権限でのみ読み書きできるように変更しておきます。
```
sudo chmod 600 /swapfile
```

### スワップ領域として設定 & 有効化
今のままだとスワップファイルはただの0埋めされたファイルなので、スワップ領域のファイルとして設定し、使用を開始します。
```shell
# スワップ領域のファイルとして設定
sudo mkswap /swapfile

# スワップ領域の有効化（使用開始）
sudo swapon /swapfile

# スワップ領域の確認
sudo swapon /swapfile
```

### 自動割り当て設定
今のままだと、インスタンス再起動時に、作成したスワップファイルがただのファイルに戻ってしまいます。
スワップの自動起動を設定するために「/etc/fstab」に以下の内容を追記しておきます。
```shell:/etc/fstab
/swapfile swap swap defaults 0 0  # 末尾に追記
```

## スワップ領域を設定しても動かない場合
スワップ領域の設定後もビルド処理で止まってしまう場合は、ビルド処理に必要なメモリ容量が不足しているのでインスタンスタイプ変更を検討する必要があります。
ただし、AWSの無料枠から外れてしまい、料金が発生するので注意が必要です。

---
参考サイト
[AWS EC2のLaravel環境でnpm run devが終わらない](https://wingdoor.co.jp/blog/aws-ec2%E3%81%AElaravel%E7%92%B0%E5%A2%83%E3%81%A7npm-run-dev%E3%81%8C%E7%B5%82%E3%82%8F%E3%82%89%E3%81%AA%E3%81%84/)
[AWSのt2micro上でnpm run build ができない【備忘録】](https://qiita.com/sho0403/items/ec3945390c1d9b956930)
[Linuxでのスワップ領域の確保](https://it.becrazy.jp/article/create-swapfile-for-linux)
Dartの三項演算子について

## はじめに
この記事ではDart言語の三項演算子ついて簡単にまとめています。

## 三項演算子
### 基本
条件を判定する際にif/else文を使用することがありますが、これを一文で書いたものを三項演算子といいます。

条件はクエスチョンマーク(?)で、条件が成立した（真値 = true）の場合に実行する式とコロン(:)、そして条件が不成立（偽値 = false）の場合に実行する式が最後に来ます。

三項演算子は、3つのオペランドを取る演算子です。
※オペランドとは、コンピュータの演算における値や変数のことです。
オぺランドは演算の種類や内容を表す演算子（オペレータ）によって演算対象となるもので、例えば「7×3」という計算式があれば、「7」と「3」がオペランドになります。

以下は三項演算子の基本的な書き方になります。
```
    ​(条件) ? trueの場合 : falseの場合
```

以下の例では、myNumberという変数に入っている値を2で割った時に、0になるかどうかを条件としています。
22を2で割ると0になるので 偶数です と出力されます。
```
var myNumber = 20;

myNumber % 2 == 0 ? print("偶数です") : print("奇数です");

// 出力結果 偶数です
```

上記の三項演算子をif/else文で書くと下記のようになります。
```
int myNumber = 20;
  
if (myNumber % 2 == 0) {
  print('偶数です');
} else {
  print('奇数です');
  }
}

// 出力結果　偶数です
```

### 条件チェーン
三項演算子は右結合で、複数の条件を順番にチェックする「連鎖」が可能です。

```
var number = 30;

number < 0 ? print("負の数です") : number == 0 ? print("０です") : print("正の数です");

// 出力結果　正の数です
```

今回の例では3つの条件があります。
1. 変数numberに入っている値が0以下であれば"負の数です"と出力する
2. 0と等しければ"0です"と出力する
3. 上記2つの条件に当てはまらない場合は"正の数です"と出力する

### Nullチェック式
この式はダブルクエスチョンマーク(??)を使用し、nullのチェックに使用します。
代入する変数がnullでないならその値を使い、nullなら右辺値を使います。

```
expr1 ?? expr2
```
expr1がnon-null(nullでない)の場合はその値を返し、nullの場合はexpr2の値を評価して返します。

```
void main() {
  int? nullableValue ;
  int? answer ;

  // nullableValueがnullでない場合
  nullableValue = 100;
  answer = nullableValue ?? 0;
  print(answer); // 100

  // nullableValueがnullの場合
  // 右辺値の0を使います。
  nullableValue = null;
  answer = nullableValue ?? 0;
  print(answer); // 0
}
```

# まとめ
今回は三項演算子についてまとめてみました。
最後までご覧いただきありがとうございました！
【未経験】 見た目が好きなのでAstroNvimを導入してみた

## はじめに
この記事は未経験、初学者がAstroNvimの環境構築をまとめたものです。
間違っている箇所もあるかと思いますがその場合はご指摘のほどよろしくお願いいたします。

## AstroNvimとは
[AstroNvim](https://astronvim.com/)は、[Nvim](https://neovim.io/)を手軽に使い始めることができる設定集です。
必要な拡張機能が揃っているので、インストールするだけでVimの環境が整います。
UIはVSCodeライクなので、見た目の違和感がなく、Vim初心者でも扱いやすいと思います。
Vimを使ってみたいけど拡張機能どれ入れたらいいかわからないという方におすすめします。

### 使い始めた理由
見た目がかっこいいから。
しかし今ではAstroNvimがないと開発できない体になってしまいました。
Vimの世界は奥が深く私が知らないコマンドはたくさんあります。
しかし、それらを全て知っていなくても十分開発効率も上がりなによりコマンドを打つのが楽しく感じると思います。
少しでもかっこいい、使ってみたいと思われた方はこの導入を試してみてぜひ一度AstroNvimを触ってみてください。

## AstroNvimのインストール方法
ターミナルを開き、次のコマンドを実行してAstroNvimをインストールします。
````
git clone https://github.com/AstroNvim/AstroNvim ~/.config/nvim
````
ターミナルで``nvim``と打つとこのような画面が表示されると思います。
※macの既存ターミナルで開くと色がおかしくなる可能性があるため、[iTerm2](https://iterm2.com/)を推奨いたします

![スクリーンショット 2023-10-23 
20.44.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3564501/0220048d-9573-88af-d07a-63d889b86621.png)

### Nerd Fontsをインストールして、アイコン表示を有効にします。
````
# Macの場合
brew install font-hack-nerd-font 

# .zshrcや.bash_profileに追記
export TERM=xterm-256color
````

## 基本設定のカスタマイズ
AstroNvimでは、~/.config/nvim/lua/userディレクトリに設定ファイルを置くことで、個人の設定を反映できます。

### 設定ファイルの追加

PCを変更しても個人の設定が読み込めるようにGitHubにリポジトリを作成し、クローンしていきます。

まずはこちらのGitHubを自分のGitHubにフォークしてください。

https://github.com/AstroNvim/user\\_example

![スクリーンショット 2023-09-27 10.00.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3564501/0c636119-34ec-d4ae-34b0-65fb379e8981.png)

「Fork」または「Use this template」の「Create a new repository」を選択します。

適当な名前をつけリポジトリを作成します。

フォークしてきたリポジトリのREADMEを見ると下の方に

````
git clone https://github.com/<your_user>/<your_repository> ~/.config/nvim/lua/user
````

と書いてあるので実行します。

※your_userとyour_repositoryは個人ごとに異なるため変更してください。
※設定ファイルに変更を加えたときはコミット＆プッシュしてGitHubにデータを写しておきましょう。

初期設定だと行番号が相対的に変化するので変化しないよう変更します。

まず設定ファイルを開きます
````
nvim .config/nvim/lua/user/options.lua
````
5行目のコードをtrueからfalseに変更します。
````
relativenumber = false, -- sets vim.opt.relativenumber
````

## よく使用するコマンド
[こちらの記事](https://qiita.com/hide/items/5bfe5b322872c61a6896)にあるものとAstroNvimで個人的によく使用するコマンドを紹介します。

## Vim操作
| key       | 内容           |
|-----------|----------------|
| h | 左へ1つ移動
| j | 下へ1つ移動
| k | 上へ1つ移動
| l | 右へ1つ移動
| i | 挿入モードへ
| o | 新しい行を追加し挿入モードへ
| yy | １行コピー
| dd | １行削除
| v | ビジュアルモードへ
| y | ビジュアルモードで選択した範囲をコピー
| d | ビジュアルモードで選択した範囲を削除
| p | カーソルの場所にペースト
| ESC, jj, jk | コマンドモードに戻る


## AstroNvim操作
| key       | 内容           |
|-----------|----------------|
| Space | Leader key, コマンドの最初に使用する
| Space + w |  内容を保存
| Space + q | 終了
| Space + o | フォーカスの変更
| [ or ] + b| バッファの移動
| space + c | バッファの削除
| H | ドットファイルの表示/非表示

## tmuxについて
私はtmuxと併用してAstroNvimを使用しています。
tmuxはターミナルを分割したり、ウィンドウを複数持つことができるため何個もターミナルを開くことがなくなります。
Vimを使う上では必須級なので入れておいて損はありません。
tmuxに関しては下記の記事を参考にしてみてください。
[tmuxを必要最低限で入門して使う](https://qiita.com/shin-ch13/items/9d207a70ccc8467f7bab)

## さいごに
この記事では導入と簡単なコマンドしか記載していません。
なので導入してからは実際にご自身で触って慣れてください。
最初は覚えることが多く大変かもしれませんがブラインドタッチすらできなかった私でも1ヶ月もあれば慣れました。
この記事を見てAstroNvimを使う方が増えてくだされば幸いです。
最後まで読んでいただきありがとうございました。
<Next.js> routing error net::ERR_ABORTED 404 _next/static/.../ 

Next.js v13.5

# 背景
訳あって、Next.js(app router) を次のような感じで nginx でリバースプロキシさせている

- Next.js: localhost:3000/xxx
- nginx: localhost/_next/xxx => localhost:3000/_next/xxx

この時に _next/xxx が 404 エラーとなり取得できなくなった。
また、localhost:3000/_next/xxx では取得できる。

```nginx.conf
# ...
location /_next/ {
    proxy_pass http://host.docker.internal:3000/_next/;
    proxy_redirect off;
}
```

# 解決
今回のケースでは i18n 対応していたため _next/xxx に動的パス(`[locale]`)が含まれていた。
ここの`[` `]` のエンコード周りが原因。というのも nginx がよしなにデコードしてしまうので Next.js の server がpathを解釈してくれなくなっていた。

生のpathを突っ込むように修正

```nginx.conf
# ...
location /_next/ {
    set $proxy_uri $request_uri;
    proxy_pass http://host.docker.internal:3000$request_uri;
    proxy_redirect off;
}
```


# 参考

https://zenn.dev/quasar/articles/230255446e9dfe
swift-doccでライブラリのドキュメントをGitHub Pagesにデプロイするまで

今回は、自分が開発したライブラリのドキュメントを、swift-doccを使用してGitHub Pagesにデプロイするまでの過程をご紹介したいと思います。

最近、私は「swiftui-simplex-architecture」という新しいSwiftライブラリをリリースしました。これは、TCAのようなアーキテクチャのライブラリで、SwiftUIを使用したアプリ開発をよりシンプルで効率的に行うことを目指したものとなっています。

https://github.com/Ryu0118/swiftui-simplex-architecture

より詳しいAPIのドキュメントを公開したかったので、Appleが提供しているswift-doccを使用してドキュメントを生成し、GitHub Pagesを通じて公開することにしました。

# 実装
実装はめちゃくちゃ簡単でした。このようなステップで簡単に公開が可能です.

1. GitHub Pagesの設定
2. [swift-docc-plugin](https://github.com/apple/swift-docc-plugin)を使用してローカルでドキュメントを生成
3. GitHubへpush

## GitHub Pagesの設定
まずはリポジトリのSettingsをクリックします。

![スクリーンショット 2023-10-23 20.10.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627061/d19641ca-7514-39cb-eb2f-826ee9324156.png)

次にPagesをクリックします。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627061/bfcd100f-f6de-2048-fbdb-913e6139050f.png" width= "300px" >

設定をこのようにします。

![スクリーンショット 2023-10-23 20.18.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627061/26ea2ce2-b147-a6f1-0a05-7715de55f126.png)

このようにすることで、mainブランチにpushされたら自動でdocsディレクトリにある内容がdeployされます。

## swift-docc-plugin
まずは、ドキュメントを生成したいライブラリのPackage.swiftにswift-docc-pluginを追加します。

```Swift
let package = Package(
    name: "swiftui-simplex-architecture",
    platforms: [
        ...
    ],
    products: [
        ...
    ],
    dependencies: [
        ...
        .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.1.0"),
    ],
    ...
)
```

そして、コマンドを実行します。再度実行しやすいように、Makefileにこのように記述します。
```Makefile
.PHONY: docc
docc:
	swift package --allow-writing-to-directory ./docs \
		generate-documentation --target SimplexArchitecture \
		--disable-indexing \
		--transform-for-static-hosting \
		--hosting-base-path swiftui-simplex-architecture \
		--output-path ./docs
```
`--target`にはドキュメントを生成したいライブラリのターゲットを、
`--hosting-base-path`にはリポジトリ名を、
`--allow-writing-to-directory`と`--output-path`には、docsディレクトリへのパスを指定します。

```shell
$ make docc
```
で実行し、差分をmainにpushします。
すると、
```
https://{ユーザー名}.github.io/{リポジトリ名}/documentation/{ターゲット名}/
```
こちらのURLにドキュメントがデプロイされます！！

今回私はswiftui-simplex-architectureリポジトリのターゲットがSimlexArchitectureをデプロイしたので、

[https://ryu0118.github.io/swiftui-simplex-architecture/documentation/simplexarchitecture/](https://ryu0118.github.io/swiftui-simplex-architecture/documentation/simplexarchitecture/)

こちらのURLにデプロイされました🎉

# DocCのローカルでのプレビュー
ローカルでプレビューすることも可能です。

```Makefile
.PHONY: docc-preview
docc-preview:
	swift package --disable-sandbox preview-documentation --target {ターゲット名}
```
これを実行すると、
![スクリーンショット 2023-10-23 20.27.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627061/8c8a543f-f0cd-c034-ab01-91f45c35e6be.png)
このようにローカルサーバーが起動し、
`http://localhost:8080/documentation/simplexarchitecture`
にアクセスすると、プレビューが見れます。

# さいごに
swift-doccでドキュメントを生成してGithub Pagesにデプロイするのめんどくさいだろうな...と考えていましたが、
めちゃくちゃ簡単にできてよかったです。
まだドキュメントが貧弱なので、TCA並に強化していきたいです！
AssociateAlias APIを使ってCloudFrontの代替ドメインを付け替える

■概要
業務の中で、次のような作業が発生しました。

・CloudFront Aに設定している代替ドメインを、CloudFront Bに付け替えたい。
・ただし、付け替え中に発生するサイトのダウンは避けたい。

この要件を満たすために、AssociateAlias APIを使用して付け替えを実施しました。

AssociateAlias APIは、ダウンタイム無しでCloudFrontの代替ドメインを、他のCloudFrontに付け替えることができるAPIです。

本記事では、その手順を紹介します

以下、公式ドキュメントに沿って作業しています。

https://repost.aws/ja/knowledge-center/resolve-cnamealreadyexists-error

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/CNAMEs.html#alternate-domain-names-move



## 事前作業
### API実行に必要な権限があるか確認
APIを実行するIAMユーザに、以降元と移行先のCloudFrontの操作の権限が付与されているか確認します。

具体的には以下権限
```
cloudfront:GetDistribution
cloudfront:ListConflictingAliases
cloudfront:AssociateAlias
cloudfront:UpdateDistribution
```
### 移行するドメインのSSL証明書を発行する
ドメインのSSL証明書がAWS内に無いと、そもそもCloudFrontに代替ドメインを設定できないため
事前にAWS ACMで証明書を発行しておく必要があります。

### CNAMEの登録
APIを実行するユーザがドメインの変更権限を持っているかを確認するためのレコードを、当該ドメインを管理しているDNSに追加します。

レコード名には「_. + ドメイン名」を
値には付け替え先となるcloudfrontのドメインを設定する

例えばsample.comというドメインだった場合は以下のようなレコードを追加する
```
_.sample.com         900   IN   TXT     d2wrpwcohquu42.cloudfront.net	

# サブドメインの場合は_sub.sample.comになる
_sub.sample.com      900   IN   TXT     d2wrpwcohquu42.cloudfront.net	
```
### AWS CLIのインストール
AssociateAlias APIを使うにはAWS CLIをインストールします。
インストール方法は下記参照

https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html



## 切り替え実行
準備ができたらAPIを実行します。

例えば
・移行先のCloudFrontのIDが「A123BCDEFG」
・移行したいドメイン名が「sample.com」
だった場合は以下コマンドになります。
```
aws cloudfront associate-alias --target-distribution-id A123BCDEFG --alias sample.com
```
APIのドキュメントは以下です。

https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudfront/associate-alias.html
【Django】FlatPageのNo FlatPage matches the given queryを解決する

## FlatPageとは？

更新頻度が低い、プライバシー・ポリシーや規約関連のページに使用します。

URLやタイトル、概要をデータベースに保存するので、管理画面で更新できるようになります。

DjangoのCMS、wagtailなどを導入していたら不要かな？？


## 実装

1. INSTALLED_APPSを追加
1. SITE_IDを追加
1. URLconfを追加
1. migrate
1. htmlの設置

この５ステップだけでOKです。

### 1. INSTALLED_APPS

`sites`と`flatpages`を追加

```python:settings.py
INSTALLED_APPS = [
    ...
    'django.contrib.sites',
    'django.contrib.flatpages',
]
```

### 2. SITE_ID

管理画面のsiteに`example.com`があると思うの`127.0.0.1:8000`に変更しておきます。

`127.0.0.1:8000`を変更せず追加にすると「__No FlatPage matches the given query__」が発生します。

追加したい場合は、SITE_IDを「２」に設定するとエラーは無くなるはずです。

```python:settings.py
SITE_ID = 1
```

### 3. URLconf

以下のようにpathを設定すると、`pages/設定したpath`というアドレスになります。

path、タイトル、概要などは管理画面で設定できます。

```python:urls.py
urlpatterns = [
    ...
    path('pages/', include('django.contrib.flatpages.urls')),
]
```

### 4. migrate

migarteを実行すると、`django_flatpage`と`django_flatpage_sites`のテーブルが作成されます。

### 5. HTMLファイル

初期状態だと、flatpagesは`flatpages/default.html`をレンダリングします。

現在使用している`templates`フォルダ内に`flatpages/default.html`を作成します。

```html:flatpages/default.html
<!DOCTYPE html>
<html>
<head>
  <title>{{ flatpage.title }}</title>
</head>
<body>
  <h1>{{ flatpage.title }}</h1>
  {{ flatpage.content }}
</body>
</html>
```
これで完了！

細かくhtmlファイルを設定したり、独自のフォームを作成することも可能です。

詳しくは公式ページをどうぞ！

https://docs.djangoproject.com/en/4.2/ref/contrib/flatpages
MySQLのDBを別のサーバに定期バックアップする

## 背景
最近監視システムのMySQLのDBバックアップができていないことがわかったので、ちゃんとバックアップして別のサーバで保管したいと考えました。

## 準備
今回は、別のサーバ側にマウントしてマウント先に直接バックアップを行います。

そのため、事前にDBがあるサーバ側にマウントポイント（ディレクトリ）を作成する必要があります。今回は/bkがマウントポイントにあたります。


## コード
```
#!/bin/sh

# DBのバックアップ先のサーバ（XXX.XXX.XXX.XXX）をマウント
mount -t nfs XXX.XXX.XXX.XXX:/mnt/XXXXX /bk

# マウントが失敗したらメールで通知を飛ばす。
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
    /usr/bin/logger -t nfs_mount "ALERT Failed NFS_MOUNT"
    exit $EXITVALUE
fi

# バックアップ処理を走らせる
# XXXXがDBのユーザ名、YYYYYYYYがパスワード、db_nameがDB名
mysqldump -uXXXX -pYYYYYYYY --single-transaction db_name | gzip > /bk/mysqldump_`date +"%Y%m%d"`.sql.gz

# バックアップ失敗したらメールで通知を飛ばす
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
    echo "DBのバックアップに失敗しました。" | mail -s "mysqldumpによるバックアップ失敗" -r aaaaaa@hogehoge.hoge bbbbbbb@hogehoge.hoge
    exit $EXITVALUE
fi

# 3週間前のDBは削除
find /bk/ -mtime +21 -exec rm -f {} \;

# マウント解除
umount /bk

# アンマウント失敗したらメールで通知を飛ばす
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
    /usr/bin/logger -t nfs_unmount "ALERT Failed NFS_UNMOUNT"
    exit $EXITVALUE
fi
```


## 補足	
あとはこれをcronで仕込めば自動で勝手バックアップしてくれます。	
	
なお、バックアップ及びアンマウント失敗時にはメールを飛ばすように設定しています。また、世代管理として、3週間前のDBは自動で削除するコマンドも仕込んでいます。