OmniAICreator/Qiita-1.07M huggingface dataset:
Rails7.1から追加されたgenerates_token_forで期間限定のダウンロードリンクを作る

# はじめに
本記事は錆びかけたRailsの知識を頑張ってアップデートするアドベントカレンダー18日目です。

今回は、Rails7.1で追加されたメソッドである`generates_token_for`を使った実装を試してみました。

### generates_token_forとは？
トークン(簡易的な鍵のようなもの)を簡単に生成できるメソッドです。

これを使うことで、例えばユーザーのパスワード変更などを行うためのトークンを発行することができます。

# generates_token_forを使いダウンロード時にトークンで認証する

## 背景
Railsガイドの例では、このメソッドを使ってパスワード変更を行うための認証トークンを作っていました。

```ruby:generates_token_forの例
class User < ActiveRecord::Base
  has_secure_password

  generates_token_for :password_reset, expires_in: 15.minutes do
    # `password_salt`（`has_secure_password`で定義される）は、
    # そのパスワードのsaltを返す。パスワードが変更されるとsaltも変更されるので、
    # パスワードが変更されるとこのトークンは無効になる。
    password_salt&.last(10)
  end
end

user = User.first
token = user.generate_token_for(:password_reset)

User.find_by_token_for(:password_reset, token) # => user

user.update!(password: "new password")
User.find_by_token_for(:password_reset, token) # => nil
```

しかし、Railsでユーザー認証機能といえばdeviseがあるため、パスワード変更をわざわざこちらで作らずともdeviseの用意した方法を使えば良いのでは？と思ってしまいました。

そこで、期間限定のダウンロードリンクを作れるようにできたら面白いかも？と考え、作ってみました。

## 前提

- deviseでユーザー認証を実装済み
- ユーザーは、自身がすでにアップロードしているファイルを指定して、それを誰でもダウンロードできるリンクを発行できる
- このリンクは期間限定で、リンクを発行する際にその時間を決めることができる

:::note alert
ダウンロードリンクを任意のユーザーが作成できるようにするのはリスクがあります。こちらの機能はアプリケーションの管理者など限られた人が利用する想定です。
:::


## 実装

まず、ユーザーがファイルと有効期限を指定してリンクを生成できるようにし、次にそのリンクを介してファイルがダウンロードされる際に期限をチェックできるようにします。

まず、DownloadLinkモデルを作成し、それに`expires_at`と`file_path`カラムを持たせます。file_pathはダウンロードさせたいファイルのパスを保存します。

### モデル

```ruby:download_link.rb
class DownloadLink < ApplicationRecord
  belongs_to :user
  generates_token_for :access, expires_in: 15.minutes

  def expired?
    Time.current > expires_at
  end
end
```

### コントローラー

```ruby:download_links_controller.rb
class DownloadLinksController < ApplicationController
  before_action :authenticate_user!

  def new
    @download_link = current_user.download_links.new
  end

  def create
    @download_link = current_user.download_links.new(download_link_params)
    if @download_link.save
      token = @download_link.generate_token_for(:access)
      session[:download_token] = token
      redirect_to @download_link, notice: "Download link created successfully."
    else
      render :new
    end
  end

  def show
    @download_link = DownloadLink.find(params[:id])
    @token = session[:download_token]
  end

  def download
    @download_link = DownloadLink.find_by_token_for(:access, params[:token])

    if @download_link.nil? || @download_link.expired?
      redirect_to root_path, alert: "This download link has expired or is invalid."
    else
      send_file @download_link.file_path
    end
  end

  private

  def download_link_params
    params.require(:download_link).permit(:expires_at, :file_path)
  end
end
```

### ルーティング

```ruby:routes.rb
resources :download_links, only: [:new, :create, :show]
get '/download/:token', to: 'download_links#download', as: 'download'
```

### 使い方
ユーザーはdownload_links#newで期間限定のダウンロードリンクについての情報を入力します。ダウンロードリンクや、ダウンロードできる期限を設定できます。

その後はshowにリダイレクトされ、ダウンロード用のリンク(トークン付き)が表示されます。

表示されたトークンを含むURLでリクエストすることでdownload_links#downloadが動き、トークンの検証が成功すればダウンロードが開始されます。
phpenvでphpをインストールする際のコマンドメモ

anyenv経由でphpenvを導入後、phpバージョン8.2.9 `phpenv install 8.2.9` が導入できず苦労したのでここに残します。

# 環境
- Mac M2
- Sonoma 14
- shell: bash

実行してその度に足りないパッケージを追加していったところ以下のコマンドになりました。パッケージはすべてbrew経由で導入しています。

# コマンド
```
PHP_BUILD_CONFIGURE_OPTS="--with-zlib-dir=$(brew --prefix zlib)\
--with-bz2=$(brew --prefix bzip2)\
--with-curl=$(brew --prefix curl)\
--with-iconv=$(brew --prefix libiconv)\
--with-libedit=$(brew --prefix libedit)\
--with--ssl=$(brew --prefix openssl@1.1)\
--with-tidy=$(brew --prefix tidy-html5)"\
phpenv install 8.2.9
```
大規模 Rails で役立つテクニック: コード品質の担保

# はじめに

先日、LTイベント「Qiita Night～Rails～」にて登壇させていただきました。

https://increments.connpass.com/event/297116/

そこで、Railsで大規模Webアプリケーションを 開発するときに知っておきたいテクニックを Qiita の Rails を例にいくつか紹介しました。発表資料はこちらです。

<script async class="speakerdeck-embed" data-id="09d7bd2986104ccbadafb879caae3b61" data-ratio="1.77777777777778" src="//speakerdeck.com/assets/embed.js"></script>

アーカイブ動画もあります。

<iframe width="560" height="315" src="https://www.youtube.com/embed/baynYVfPdhc" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" loading="lazy" allowfullscreen></iframe>

これまで大規模 Rails で役立つテクニックをそれぞれ記事として紹介しました。

https://qiita.com/wataru86/items/523bc9fd8943e75e2def

https://qiita.com/wataru86/items/ff7a2e24fa6d02154310

この記事は、LT で話した残りの部分、「Qiita が Rails のコード品質を担保するためにやっていること」を紹介します。

# Qiita が Rails のコード品質を担保するためにやっていること

それぞれ簡単に紹介していきます！

## RuboCop

Qiita の Rails では RuboCop を導入しています。RuboCop は Ruby のコードを静的解析し、よくない書き方があると指摘してくれます。

https://github.com/rubocop/rubocop

実行のタイミングとして、Git の pre-commit hook により commit する際に実行されます。ここで違反しているコードがあると commit できないようになっています。また、GitHub Actions でも実行しているので、 RuboCop のルールに違反した状態で merge されないようになっています。

## RSpec

Qiita では、テストライブラリとして RSpec を使用しています。

https://rspec.info/

Qiitaではテストをちゃんと書く文化が根付いていて、Model や Controller などを中心にできる限りテストは書くようにしています。LTでも紹介しましたが、SimpleCov でカバレッジを計測したところ 90% となっていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325392/873c2509-e9fe-7735-3909-69d44bbb00cb.png)

また、テストが多いことによるデメリットとして Flaky Test が発生してしまったり、仕様が大きく変化するとテストの修正箇所が多くなってしまうこともありますが、テストがあることで得られる恩恵を考えると、それを直すのも苦ではないと思います。

## Yard

Qiita では、Yard の記法でメソッドの引数と戻り値の型をコメントとして記載しています。

https://yardoc.org/

こんな感じです。

```rb:Yardの例
# @param query [String]
# @param variables [Hash]
# @return [Hash]
def post(query, variables)
  response = client.post({ query: query, variables: variables }.to_json)
  JSON.parse(response.body)
end
```

すべてのメソッドで Yard によりできているわけではないですが、public なメソッドには基本的に書く方針になっています。それにより、メソッドをどのように使えばいいのか、何が返ってくるのかがわかりやすくなっています。

## その他

品質担保に影響していそうなQiitaの文化を少し紹介します。

- コーディング規約
    - RuboCop で捕捉できない Ruvby のルールなどをコーディング規約としてまとめています
    - 障害が起きたときなど、再発しないようにするためルールを追加することがあります
- 設計
    - できるだけ設計になるように心がける文化があります
    - 入社時のオンボーディングとしてオブジェクト指向設計の習得があったりします
- ドキュメント文化
    - Qiita のエンジニアだからこそ、Qiita の記事投稿が推奨されています
    - プライベートな内容は Qiita Team にドキュメントを書くようにしています
    - 上記のコーディング規約やオンボーディングの資料などもQiita Teamに書かれています

# おわりに

ここまで、Qiitaでコード品質を担保するためにやっていることを紹介しました。ですが、まだまだできていないことももちろんあります（ライブラリのアップデートなど）。ですので、これからもコード品質の担保のためにできることがないか探して、また紹介できることが増えたら記事にしていきたいと思います。
【Volta】node.jsバージョン管理ツールをVoltaに乗り換える【設定手順】

## はじめに
いままで`nodist`でnodejsのバージョン管理をしていましたが、どこか使いづらさを感じていました。
`nodist`の最終バージョンはここ２年間の更新がされておらず2019年です。
このまま使い続けるには一抹の不安があるので、この際、`Volta`に乗り換えるために手順をこちらにまとめておこうと思います。

## Nodistのアンインストール
いままで使っていたNodistを削除します。意外としつこく残り続けるのでここでしっかり削除しましょう。
Nodist以外のツールを使用している方もここでしっかり削除します。

### 1. コントロールパネルからアンインストール
コントロールパネルから`Nodist`を探しアンインストールします。
OSの再起動を求められた場合は再起動を行います。

### 2. Nodistフォルダを削除
コントロールパネルから`Nodist`を削除してもNodistのインストール先のフォルダは残ってままになっています。
グローバルインストールしたものなどはここに残ったままなのでフォルダごと削除します。

### 3. npm-cacheフォルダの削除
npmのキャッシュフォルダを削除します。
npm-cacheフォルダは以下に格納されているので探して削除してください。

```
C:\Users\<ユーザー名>\AppData\Roaming\npm-cache
```

`AppData`フォルダは隠しフォルダになっているので注意してください。

### 4. 環境変数の削除
環境変数が設定されているとおもいますので削除します。
`Windowsキー + R`を押下して`ファイル名を指定して実行`を開きます。
`sysdm.cpl`と入力して、システムのプロパティ画面を開き、設定タブから環境変数を押下します。
環境変数画面からNodist関連の環境変数を削除します。
これでNodistの削除は完了です。

## Voltaをインストール
### MacOS

```
curl https://get.volta.sh | bash
```

### Windows
[公式サイト](https://docs.volta.sh/guide/getting-started)からインストーラをダウンロードしてください。
詳細については公式サイトを確認するのが一番信用できるので説明は省きます。

## Voltaの使い方
こちらのコマンドでnodejsがインストールされます。
バージョンは長期サポート（LTS）版。

```
volta install node
```

このnodeバージョンにあったnpmも一緒にインストールされるのでわざわざ別途インストールする必要はありません。
あえてインストールする場合はこちら。

```
volta install npm
```

バージョンを指定してインストールする場合はこちらのコマンドを実行します。

```
volta install node@20

# 最新バージョンをインストールする場合
volta install node@latest
```

インストールしたnodejsやnpmなどのバージョンを確認する時はこちらのコマンド。
実行できないときは開発者モードで行ってみてください。

```
volta install all
```

nodejsのバージョンをプロジェクト固定にするにはこちらのコマンドを実行します。
package.jsonにバージョン情報が記載され管理されます。

```
volta pin node@20
```

```package.json
"volta": {
  "node": "20.10.0"
}
```

voltaはpackage.jsonのnode情報からnpmのバージョンもあったものをインストールしてくれるので、nodeだけ実行します。
npmのバージョンも明示的に記載しておきたい場合はコマンドを実行してください。

## まとめ
これでvoltaを使いこなせるはずです！
Happy node life!
[Python][Julia]project euler 12 (プロジェクトオイラー１２)  

### Projevt Euler Ploblem 12 (プロジェクトオイラー１２)
#### Highly Divisible Triangular Number

Project Euler 12を解いたので、備忘のために残しておく。 
Python と Julia のコードを両方かいた(下段)
処理速度はJuliaの方がずっと速い。

自分のPCだと 
Pythonが 約2.5秒
Julia が 約1.5秒
だった。

### 問題
問題文（適当な和訳なので、完全に正しいかはわからない...）
三角数の数列は自然数の足していくことによってできる。
７番目の三角数は1 + 2 + 3 + 4 + 5 + 7 = 28 となる。
初めの１０項は1,3,6,10,15,21,28,36,45,55....となる。
7項目までの三角数の約数を並べると以下のようになる。
1:1
3:1,3
6:1,2,3,6
10:1,2,5,10
15:1,3,5,15
21:1,3,7,21
28:1,2,4,7,14,28
28は約数の数が5個を超える最初の三角数だとわかる。
約数の数が500個を超える最初の三角数の値は？
#### 答え：76576500

問題文（原文）
The sequence of triangle numbers is generated by adding the natural numbers. 
So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 7 = 28 
The first ten terms would be:1,3,6,10,15,21,28,36,45,55....

Let us list the factors of the first seven triangle numbers:
1:1
3:1,3
6:1,2,3,6
10:1,2,5,10
15:1,3,5,15
21:1,3,7,21
28:1,2,4,7,14,28

We can see that 28 is the first triangle number to have over five divisors.
What is the value of the first triangle number to have over five hundred divisors?


### 求め方の方針
約数を求める関数(divisors) を作り
三角数の値を約数を求める関数の引数として、約数の個数が500を超えるまで三角数の１番目から計算(seek_answer)。
三角数の和は 
```math
\sum_{k=1}^{n} k = 1 + 2 + 3 + \cdots + n = \frac{n(n+1)}{2} \
```
から
### Python のコード
```Python:Ploblem12(Python)
import time #処理時間計測用
start = time.time() 
 
def divisors(num: int) -> int:
    count: int = 0
    for i in range(1, int(num**0.5) + 1):
        if num % i == 0:
            count += 1
            if num // i != i:
                count += 1
    return count

def seek_answer(d: int) -> int:
    ans: int = 1
    k: int = 1
    while divisors(ans) < d:
        ans = k*(k + 1)//2
        k += 1    
    return ans

d = 500
print(seek_answer(d))

end = time.time()
 
print(f"処理時時間：{end - start}")

```

### Juliaのコード
```Julia:Ploblem12(Julia)
using Dates #処理時間計測用

start = Dates.now()

function divisors(num::Int64)::Int64
    count::Int64 = 0
    for i in 1:ceil(sqrt(num))
        if num % i == 0
            count += 1
            if num ÷ i != i
                count += 1
            end
        end
    end
    return count
end



function seek_answer(d::Int64)::Int64
    ans::Int64 = 1
    k::Int64 = 1
    while divisors(ans) < d
        ans = k*(k+1)/2
        k += 1
    end
    return ans
end

d::Int64 = 500
println(seek_answer(d))
endtime = now()
println("処理時間：", endtime - start)

```

2023/12/24 コードを修正しました(ありがとうございます！）
ジェネリック医薬品と運用保守と私

初めまして。私は、某SIerにて運用保守業務に10年以上携わっております。
今回は縁あってアドベンドカレンダーに記事を投稿しますので、少々お付き合いいただければ幸いです。

タイトルだけ見ると何かその年代の人のような感じに思えますが、単純にこの言い回しを使いたかっただけです（笑）
もし何を言っているのかわからなかったらお父さんお母さんに聞いてみてください。

そもそも何でタイトルにジェネリック医薬品なの？って話なのですが、本日12/22は、「ジェネリック医薬品の日」らしいです。**ジェネリック医薬品**って運用保守の中で言うところの**実績のある手順書**に似ている気がする（ちょっとこじつけすぎ？）ので、少し関連付けて日々思っていることを書いていこうと思います。

# ジェネリック医薬品とは
>ジェネリック医薬品は、特許の期限が切れた新薬（オリジナルのブランド医薬品）と同じ有効成分、効果・効能、用法・用量を有する医薬品を指します。これは**医薬品の生産コストを大幅に削減**し、結果的に医療費の抑制や患者さんの負担軽減に繋がります。
>さらに、ジェネリック医薬品は、それぞれの国の厚生労働省や食品医薬品局などの規制当局によって厳密に評価され、その**安全性と効果が保証**されています。これにより患者さんは、価格が低いからといって品質が落ちることはないと確信できます。

:::note info
運用現場に置き換えると**商用作業等のために作成した実績のある手順書**は、同様の作業において**再利用可能**なため、**追加コストをかけずに確実な運用作業を行うためにとても重要なドキュメント**と言えると思います。
:::

# ジェネリック医薬品の使用に関する注意点
ただし、**ジェネリック医薬品も万能ではなく、その使用には注意が必要**です。具体的にはどのような注意が必要なのでしょうか。その注意点は**実績のある手順書にも通じるものがある**と思いますので、一緒に確認していきましょう。


<dl>
  <dt>適応についての理解</dt>
  <dd>ジェネリック医薬品は新薬と同じ効果を持つと認められていますが、それは同じ症状や疾患に対してのことです。ジェネリック医薬品が新薬と全く同じすべての適応を持っているとは限らないので、使用する前には医師や薬剤師と相談することが重要です。</dd>

:::note info
実績がある手順書に関しても同じだと思っています。
本当に過去と同じケースなのでしょうか。よく「過去実績がありますので問題ありません。」と聞くことがあります。手順書の話よりも作業の前提に違いがないかもセットで確認することが必要です。
:::
  
  <dt>製造元の違い</dt>
  <dd>ジェネリック医薬品は異なる製造元から提供されるため、見た目や色、形状が新薬や他のジェネリック医薬品と異なることがあります。しかし、有効成分は同じであり、品質も保証されているため、見た目の違いが効果に影響を与えることはありません。</dd>

:::note info
手順書は見た目が違うと効果も違うので、ちゃんと過去の実績があった手順書なのかという構成管理の観点が必要だと考えます。

プログラムや設計書は構成管理しているけど、ちょっとした商用作業などの手順書が構成管理はされていないケースもあると思いますので、「過去実績がある手順書です。」と言いつつ、違う手順書だったということも起こる可能性がありますので要注意です。。。
:::
  
  <dt>副作用のリスク</dt>
  <dd>新薬と同じく、ジェネリック医薬品にも副作用のリスクがあります。他の薬との相互作用も考慮に入れるべきです。</dd>

:::note info
他作業と同時実施する場合、それは既に過去実績のケースとは異なっているということに気づく必要があります。作業は同じかもしれませんが、一緒にやる他作業との関係性まで見極められていますでしょうか？
::: 
</dl>

# まとめ
ジェネリック医薬品と同様に実績のある手順書は日々の運用作業を確実こなしていくためにとても重要なドキュメントになります。ただし、実績があるからと言って確認せずに使ってしまうと痛い目を見ることにもなり得るので、「実績があります。」とか、「過去の作業を踏襲しています。」という言葉を聞いたときには、「それって本当ですか？」とそこだけはコストをかけて確認していくことをオススメします。

# あとがき
本当は、最近流行りの「生成AIと運用保守」みたいな感じで、人材不足を生成AIでどう補うかみたいな記事でも書こうと思っていたのですが、それはまたの機会にしたいと思います。

最後まで読んでいただきありがとうございました。またどこかでお会いしましょう。
画面幅が変わった時の処理をmatchMediaでやってみた

## 目次
- resizeで実装した場合
- matchMediaで実装した場合


## resizeで実装した場合

画面幅が変わった時の処理は`resize`というイベントを用いて行うことが一般的です。

```javascript
// イベントリスナー
const listener = () => {
  // 600px以上のときの処理
  if (window.innerWidth >= 600) {
    console.log('600px以上だよ！');
  } else {
    // 600px未満のときの処理
    console.log('600px未満だよ！');
  }
};

// リスナー登録
window.addEventListener('resize', listener);

// 初期化
listener();
```

しかしこれだと画面幅がresizeされるたびにイベントリスナーを呼び出すことになります。そこでmatchMediaという手法を使っていきましょう。

## matchMediaで実装した場合

mdn：https://developer.mozilla.org/ja/docs/Web/API/MediaQueryList

`MediaQueryList`オブジェクトはメディアクエリの情報を格納します。

MediaQueryListオブジェクトを生成するには`window.matchMedia()`とします。さらに`window.matchMedia("(max-width: 600px)")`のようにすると、600px未満のメディアクエリーリストが生成されます。

画面幅がメディアクエリーリストと一致するか否かを判別するには、`matches`プロパティを使います。このプロパティはboolean型で、メディアクエリーリストと一致する場合はtrue、一致しない場合はfalseを返します。こうして画面幅によって処理を条件分岐できます。

メディアクエリーが変化するイベントを`resize`ではなく`change`として、イベントリスナーを呼び出します。

```javascript
const mql = window.matchMedia("(max-width: 600px)");

function screenTest(e) {
  if (e.matches) {
    console.log('一致したよ!600px未満だよ！');
  } else {
    console.log('不一致だったよ！600px以上だよ！');
  }
}

mql.addEventListener("change", screenTest);
```

## まとめ

メディアクエリーリストを作って、それと一致したらAの処理、一致しなかったらBの処理という風に書けた。

なので`window.addEventListener('resize', イベントリスナー)`のようにwindowがリサイズするたびにイベントリスナーを呼び出す必要がなく、

`window.matchMedia(幅).addEventListener('change', イベントリスナー)`のようにメディアクエリが変わった時だけイベントリスナーを呼び出せるようになった。
プログラミングに必要なのは日本語（母国語）力ではないのか

プログラミングに必要な力は、数学？、英語？なの。

いやいや実は母国語を駆使する力、国語力ではないのか？
ほとんどのプログラミング言語は、英語によせて記述されているので、英語を母語とする人々はある意味有利です。マニュアルもほぼ英語で読めますから。

しかしそれを読んだり、書いたりしてプログラムを作るには、国語力が必要です。これまで出会ったきた優秀なプログラマは実は国語力が豊かな人たちでした。英語が得意でも数学が得意でもなくても。しかし国語力のない人はよいプログラムが書けません。そう思います。

いい加減、文系、理系分類は制度としてやめたほうがよいと思います。ナポレオンのころより、お国のためになるには数学、物理、化学的才能のある（戦争に役立つ）理系有利な時代が200年続いています。

中途半端なプログラミング教育などしないで、国語教育に力をいれればプログラミングに強い国ができるのではないでしょうか。
AWSで100万円溶かした話

# はじめに
まずこちらをご覧ください。タイトルの通りですが、初歩的なミスによりAWSで100万円溶かしました。生き恥を晒しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/466700/51bf4852-5c36-3c9e-2b02-25481a495543.png)

この記事では、私がどのようにこの大金を失ったのか、そしてその教訓について共有します。そして、「世の中にはこんな間抜けな人間がいるんだなぁ」というエンタメとして楽しんで貰えればと思います。

# 勉強が高くついた
私がAWSを触った目的は、RDSやEC2を使ってアプリ開発の勉強をし、GlueやAthenaなどのサービスにも少し手を出してみることでした。しかし、6月から11月の間に気づかぬうちに100万円が消えていました。

# 原因

### 原因1: サービスの停止忘れ
開発したEC2インスタンスなどのサービスは停止するのが基本です。しかし私は一部のサービスを停止することを忘れていたため、不要なコストが発生していました。さらに、私はEC2インスタンスだけでなく、スナップショットの保持にも費用がかかることを知らず、追加のコストが発生していることに気づきませんでした。


### 原因2: 無料枠の過信
AWSの無料枠があると高を括り、実際の使用量を見落としていました。無料枠といってもサービスごとに利用上限があります。例えば、EC2なら月750時間まで無料だが、私の場合は試行錯誤のために複数個のEC2インスタンスを建てており、上限を超えてしまっていました。
[AWS 無料利用枠](https://docs.aws.amazon.com/ja_jp/whitepapers/latest/how-aws-pricing-works/get-started-with-the-aws-free-tier.html)

### 原因3: クレジットカードの未確認
私は数ヶ月間、クレジットカードの支払いを確認していませんでした。口座残高はチェックしていたものの、直近で大きな買い物や定期投資もしていたため、「まぁこんなもんかなぁ」と思い込んでいました。気が付いた時には手遅れでした。

# 結果と対応
AWSに事情を説明したところ、最近の支払い30万円余りは返金してもらえました。
AWSのサポートは非常に親切でしたが、残りの70万円については返金が難しいとのことでした。
(詳細な理由の個別回答は難しいということでしたが、もしかしたら直近2～3ヶ月の支払いだけが対象となるのかもしれません)
少なくとも気が付くのが早ければ早い方が良いということですね。

# 対策方法
### 1. 支払い上限の設定
対策の中で、最も重要です。AWSの支払い上限を設定し、予期せぬ高額請求を防ぎます。面倒くさいかもしれないですが、実務では必須になると思うので覚えましょう。手順通りに実施するだけです。
[請求アラームの作成方法](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/monitor_estimated_charges_with_cloudwatch.html)

### 2. サービスの適切な管理
EC2などのサービスは使用しない時は必ず停止するようにします。これは意識して停止出来れば世話がないですが、停止忘れのためにも1.のアラート設定は優先的に行いましょう。

### 3. 定期的な支払い確認
クレジットカードの支払いは定期的に確認し、予期せぬ出費を避けます。クレジットカードの不正利用対策にもなるので、AWSに限らずクレジットカードの支払いは定期的に見ておきましょう。

# まとめ
私のような失敗を避けるためにも、定期的な支払い確認とサービスの適切な管理が重要です。詰まるところ、当たり前のことを当たり前に実施しましょうという話です。
そして、100万円を失い恥を晒しても、人間は意外と前向きに生きていけることを学びました。むしろ人生が変わったなくらいの感覚で、多少のミスに動じなくなりました。
最後に、私の失敗談を聞いて「自分のミスなんて大したことないな...」と少しでも前向きになる方がいれば嬉しいです。
コーディング時に意識できると良いと思ったことまとめ

コードレビュー時にコードの品質以外の点で指摘されたことはないでしょうか？
設計以外で指摘を受けることはコードレビューする側の負担となってしまいます…

:::note info
この記事では、最低限原則として知っておいた方がいいことや不用意な指摘を減らすためのプラグインを伝えられたらと思います！
:::

## 「code-spell-checker」を入れる

vscodeを利用している場合であれば「code-spell-checker」を入れておきましょう！

https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker

:::note warn
たまに動いていない時があるので、動いているか時々確認してあげてください…
:::

## 命名ルールに特例を作らない
例えばTailwindCSSを利用している環境だったとします。
TailwindCSSを拡張し、新しくclassを追加しようとした時に**TailwindCSSのルールに沿わないclassは作らない**ということです。

```typescript
// NG:キャメルケース
const extendColors = {
  onSurface: '#ff49db';
}

// OK：ケバブケース
const extendColors = {
  'on-surface': '#ff49db';
}

```

細かいですが、1つでも異なった形式で定義すると統一感が失われ、たった1例だけ許したはずがその後例外を生み続ける火種になる可能性があるので注意が必要です。

:::note info
Reactではイベントハンドラ関数に「handle」をつけて命名する慣習があるので覚えておきましょう！
:::

## 基本ルールを知っておく

それぞれの言語には暗黙のルールのようなものが存在します。
一般的な通例に沿わないコーディングはノイズになり、後の開発者を混乱させてしまうので世の中の一般的な書き方を知っておけると良いと考えます。

https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines

ただ、ルールをそのまま採用するかはチームで認識をすり合わせる必要があります。

インデントのルールは4つのスペースを利用すると記載がありますが、スペースは2つを利用することもあると思います。

:::note info
インデント4つだと深い感じるので2つが良いと考えています
:::

全てのルールを採用するわけではなく、命名ルールや書き方は世間一般に公開されているルールを採用することで新規Joinするメンバーにとっても優しい環境になるのではないかと考えています。

## ちょっとした違和感を大切にする
たとえば下記のような例です。

```typescript
type Props = {
  children: string
}

const COmponent = ({ children }) => {
  return <p>{children}</p>
}
```

`children`は`string`だけにしたいと考えて`children`を`stging型`で定義しました。
ミスではないのですが、`children`はHTMLも要素の中に含まれることがあります。

というより`children`が利用される場面はむしろHTMLも含めたいケースがほとんどではないかと思っています。

:::note warn
`children`の型はReactNodeを選択するのが一般的なのでstringの型を指定するのは違和感がある
:::

間違いではありませんが、コンポーネントで型定義を強めすぎると柔軟性がなくなり扱いは難しくなります。

:::note info
コンポーネントを別ドメインでシェアできるように想定して作成するのであれば、あえて緩く作ってコンポーネントを利用するアプリケーション層で型を厳格にするなどを検討できると良いでしょう。
:::

## まとめ
私も全てができているわけではありませんが、意識できることでレビューワーとのコミュニケーションコストは下がると考えています！

世の中の標準ってなんだろう？は事前にキャッチできなければ、レビューワーとレビューの方針は何かすり合わせておけると良いと考えます！
VueRouter を使う際のサーバー設定

# 結論
VueRouterを使用して、サブディレクトリへのアクセスをもとにルーティングを行いたいときはトップディレクトリを参照するようにサーバー側の設定が必要。

例
下記のように、www.website.com/app にアクセスした際にはAppHomeを、www.website.com/app/aboutにアクセスした際にはAboutコンポーネントを表示させたいとする。
AppHomeの表示に関しては、特に気にすることなく、サーバー側の公開ディレクトリにビルド後のファイルを配置すれば正常に表示される。
一方で、Aboutの表示は、そのままでは404NotFoundなどの結果が返ってくる。

``` main.ts
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: AppHome,
    },
    {
      // サブディレクトリへのアクセスを制御したい
      path: '/about',
      name: 'about',
      component: About
    },
    {
      path: '/:catchAll(.*)',
      component: ERR404
    }
    ...
```
# 理由・解決法
- サブディレクトリ www.website.com/app/about に対するリクエストを受けたWEBサーバーは/app/about/index.htmlを探しに行くが、そのようなディレクトリ・ファイルは存在せず、404エラーを返すため。
- VueRouterに処理をさせるには、リクエストをVueRouterまで届けないといけない
- 具体的には、Vueの場合は、/app/about へのアクセスを、/app に対してリダイレクトさせる必要がある

# 解決法具体例 Nginxの場合
wwww.website.com/app/* に対してアクセスがあった際に該当ファイルがなければ、/appへリダイレクトされ、/app配下のvueアプリケーションまでリクエストが届けられ、VueRouterで処理がなされる。
``` nginx.conf
	#For Vue-Router
	location /app {
		files $uri $uri/ /app;
	}
```

# 余談と経緯
- VueRouterを使用して上記のようなことをした際に、ローカルの開発環境では問題ないが、ビルドしてサーバーに上げるとサブディレクトリへのアクセス404になるという現象に遭遇し時間をとられた。
- VueRouterというくらいだから、サーバーへのアクセスよしなにやってくれるんだ楽ちんくらいの気持ちでおり、WEBサーバーとVueとのやり取りの仕組みをよく理解せず使っていたため、解決に時間がかかった。
- nginx の confファイルが複数あり、書いても書いても反映されずにそこでも時間をくった
structとclassの違いを理解しよう！~deep copyとshallow copyの理解~

# struct (値型)
各インスタンスはデータの**コピーを保持する！**
変数や定数に代入するときや関数に渡すときに、新しいインスタンス (コピー) を作成する
# class (参照型)
各インスタンスはデータの**コピーを共有する！**
一度初期化された型は、変数または定数に割り当てられるか、関数に渡されると、同じ既存のインスタンスへの参照を返す！

# deep copy(深いコピー)でstructを理解！
ディープコピー(深いコピー)とは**完全な複製**を作成するコピーです。
生成時点のデータをコピーした実体を作成する。
完全な複製を作成するので、コピー元とコピー先は別々の実体を参照することとなる。
サンプルコードをPlaygroundで動かしてみて、理解を深めましょう！
```swift:
 struct Info {
    var count = 0
}

class VC1 {
    var info: Info
    init(info: Info) {
        self.info = info
    }
}
class VC2 {
    var info: Info
    init(info: Info) {
        self.info = info
    }
}

let info = Info()
let vc1 = VC1(info: info)
let vc2 = VC2(info: info)
vc1.info.count = 10
vc1.info.count// ①これはいくつ？
vc2.info.count// ②これはいくつ？
info.count // ③これはいくつ？
```
**問題①〜③はいくつになるでしょうか？**


![e82d70f92dc577d951a761c8530a3b84.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090887/7445bbf2-0e81-ce4d-1321-c7f64480c26a.png)

上記の図のようにコピー元のinfoのディープコピーを行い、vc1、vc2のコピーが作成される。
その際、その時点の実体もコピーされるので、info、vc1、vc2は別々の実体を指す。
` vc1.info.count `を10にしても、別々の実体なので` vc2.info.count `と` info.count `に変更は反映されず、0になります！
**答え**
```swift
vc1.info.count// ① 10
vc2.info.count// ② 0
info.count // ③ 0
```



# shallow copy (浅いコピー)でclassを理解！

シャローコピー(浅いコピー)とは**実体（データ）のコピーを行わない**コピーです。
そのため、コピーを共有することができる！
コピーを共有するので、コピー元とコピー先は同じ実体を参照することとなる。
サンプルコードをPlaygroundで動かしてみて、理解を深めましょう！
```swift:
class Info {
    var count = 0
}

class VC1 {
    var info: Info
    init(info: Info) {
        self.info = info
    }
}
class VC2 {
    var info: Info
    init(info: Info) {
        self.info = info
    }
}

let info = Info()
let vc1 = VC1(info: info)
let vc2 = VC2(info: info)
vc1.info.count = 10
vc1.info.count// ①これはいくつ？
vc2.info.count// ②これはいくつ？
info.count // ③これはいくつ？
```

![ea43565b45a7ee573cab1541a662dbcf.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090887/b72996c6-3b50-c68b-361a-96a1f19f5cc1.png)


上記の図のようにコピー元のinfoのシャローコピーを行い、vc1、vc2のコピーが作成される。
その際、info、vc1、vc2は同じ実体を参照しているので、値を共有することができる！
` vc1.info.count `を10にすると、同じ実体を参照するので、` vc2.info.count `と` info.count `にも変更が反映され、10になります！
**答え**
```swift
vc1.info.count// ① 10
vc2.info.count// ② 10
info.count // ③ 10
```

# 参考文献
https://medium.com/@thaoth58/shallow-copy-and-deep-copy-in-swift-f1ce6908376e

https://medium-company.com/%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%82%B3%E3%83%94%E3%83%BC%E3%81%A8%E3%82%B7%E3%83%A3%E3%83%AD%E3%83%BC%E3%82%B3%E3%83%94%E3%83%BC%E3%81%AE%E9%81%95%E3%81%84/
django+nginx±uwsgi+centos8の環境構築

環境構築の本を執筆しました。
よかったらご覧ください。
https://zenn.dev/nori1234/books/ce09094f5f4371?fbclid=IwAR2QQLFVU6YKWk-u_Hi4j8mnyI1VL_yTxdg4tpu8tbPd31C4K_5dW2BIGYw_aem_AaiI_5F70BWIF_WuXRgxTsytQDrB_wDthiURpPLxqjBjWK81YzPxH58QmvSN2jveeRQ
[21日目] どのAIがプログラミングに強いのか

こんにちは、なりかくんと申します。
この記事はなりかくん Advent Calender 2023の21日目の記事です。

今回は、どのAIがプログラミングに強いのかを簡単に調べてみます。

# 調査対象のAI
今回調査に使うAIは以下のサービスです。

- ChatGPT GPT-3.5
- Google Bard
- Bing AI (厳密)

# 使う問題
今回は、AtCoder内の問題を利用させていただこうと思います。

https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_l

# 言語について
今回、言語は C言語 と Python の二種類を3回ずつ生成して試してみます。

# 渡す文章について
今回このように用意しました。
```
競技プログラミングの問題です。この問題のコードを教えてください。
なお、プログラミング言語は C言語 でお願いします。

・問題
N 台のプリンターがあり、1 から N までの番号が付けられています。プリンターi は Ai 秒ごとにチラシを 1 枚印刷します。すなわち、スイッチを入れてから Ai 秒後、
2Ai 秒後、 3Ai 秒後･･･ に印刷します。すべてのプリンターのスイッチを同時に入れたとき、K 枚目のチラシが印刷されるのは何秒後でしょうか。

・制約
- 1≤N≤100000
- 1≤K≤10^9
- 1≤Ai≤10^9
- 答えは 10^9 を超えない
- 入力はすべて整数

・入力
入力は以下の形式で標準入力から与えられます。

N　K
A1 A2 ⋯ AN
​
・出力
何秒後に K 枚目のチラシが印刷されるかを一行で出力してください。

・入力例 1
4 10
1 2 3 4

・出力例 1
6
```

# 略称について
AC 正解
WA 不正解
CE コンパイルエラー
RE 実行時エラー

# ChatGPT
C 1回目 WA
https://atcoder.jp/contests/tessoku-book/submissions/48696598
C 2回目 AC
https://atcoder.jp/contests/tessoku-book/submissions/48696646
C 3回目 WA
https://atcoder.jp/contests/tessoku-book/submissions/48696673

Python 1回目 AC
https://atcoder.jp/contests/tessoku-book/submissions/48697085
Python 2回目 AC
https://atcoder.jp/contests/tessoku-book/submissions/48697121
Python 3回目 AC
https://atcoder.jp/contests/tessoku-book/submissions/48697155

# Google Bard
C 1回目 RE
https://atcoder.jp/contests/tessoku-book/submissions/48696891
C 2回目 CE
https://atcoder.jp/contests/tessoku-book/submissions/48696954
C 3回目 CE
https://atcoder.jp/contests/tessoku-book/submissions/48697004

Python 1回目 RE
https://atcoder.jp/contests/tessoku-book/submissions/48697186
Python 2回目 WA
https://atcoder.jp/contests/tessoku-book/submissions/48697230
Python 3回目 RE
https://atcoder.jp/contests/tessoku-book/submissions/48697265

# Bing AI
C 1回目 AC
https://atcoder.jp/contests/tessoku-book/submissions/48696939
C 2回目 WA
https://atcoder.jp/contests/tessoku-book/submissions/48697046
C 3回目 AC
https://atcoder.jp/contests/tessoku-book/submissions/48697070

Python 1回目 AC
https://atcoder.jp/contests/tessoku-book/submissions/48697224
Python 2回目 AC
https://atcoder.jp/contests/tessoku-book/submissions/48697253
Python 3回目 AC
https://atcoder.jp/contests/tessoku-book/submissions/48697304

# 結果まとめ
結果をまとめるとこのようになりました。
Google Bardはボロボロですね。ChatGPT GPT-3.5とBing AIがかなり良い正答率です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/f2791fd6-70bd-df62-8b99-0875720482db.png)

結果を見るとBing AIが今回の実験では一番優勢でした。
最近Google Bardでは、Google Workspaceなどと連携できるなどあったみたいなので、使いどころを考えながらサービスを使うと良さそうです。

ChatGPT GPT-4は、契約してないので使うことが出来なかったのですが、どうなんでしょうか。

# 最後に
皆さんもいろいろ試してみてください。最後までお読みいただきありがとうございました。
CEDEC2023講演 まとめ ～ イヤホンの頭内定位を解消する独自技術 AudiiSion EP  とは

[<B>MATLAB/Simulink Advent Calendar 2023</B>](https://qiita.com/advent-calendar/2023/matlab)に参加しました。

カレンダー2の12/20分として追加しました。

・使用ツール
<dt>　MATLAB</dt>
<br>

<H4><a href="https://note.com/leftbank/n/n963bb83a7f7a"</a> [<B>note</B>]にUpしました。</H4>
CMSとはなんなのか

# CMSとはなんなのか
CMSとはContents Management Systemでコンテンツ管理システムと訳されます。

## CMSとは
サイトの開発・運用を一元的に管理するシステムです。テンプレートなどを用いることで、ノーコードで管理することが可能です。
画像や動画、デザインなども一元的に管理することができます。
また、共同編集が可能かつ権限管理が容易で、共同作業でも活躍します。

## CMSのメリット
### 1.ノーコードで開発できる
CMSのテンプレートなどを用いることでノーコードで開発が可能です。エンジニアの専門知識がない人でも、直感的で簡単に変種することが可能で作業分担などが可能になります。

## 2.マルチデバイス対応が容易にできる
スマートフォン/タブレット/PCによって画面サイズなどの環境が違うことから必要である、マルチデバイス対応が容易に実現でき、ユーザエクスペリエンスの向上にも役立ちます。

## 3.拡張機能を利用することでカスタマイズが可能
セキュリティに関する拡張機能も用意されており、簡単にカスタマイズが可能です。

## 有名なCMS
* WordPress
* Shopify
* Wix
* Adobe Systems
* Jimdo

## Word Pressのセキュリティ
Word Pressは利用者が多いこともあり、脆弱性が多く発見されます。また、ログインページ(wp-admin)を守る対策も必要です。プラグインの導入などの対策が行いやすいです。
TerraformでGuardDutyのAWS Fargate のRuntime脅威検知を有効化する

AWS re:Invent 2023で発表されたこちらの機能をTerraformで有効可する方法です。


https://aws.amazon.com/jp/blogs/news/introducing-amazon-guardduty-ecs-runtime-monitoring-including-aws-fargate/


TerraformのGitHubの数日に一回くらいIssue検索しながら緩く待っていたのですが、Issueに上がってこないということはドキュメントに無いだけで設定できるのではということでやってみました。

APIに渡すFeature Nameはこちらの公式から `RUNTIME_MONITORING.additionalConfiguration.ECS_FARGATE_AGENT_MANAGEMENT` だということがわかりました。


https://docs.aws.amazon.com/guardduty/latest/ug/guardduty-feature-object-api-changes-march2023.html

ということで、そのままTerraformに埋め込んでみました。ECS Fargateだけ対象としたい場合は以下の通りです。

```terraform
resource "aws_guardduty_detector" "this" {
  enable = true
}

resource "aws_guardduty_detector_feature" "ecs_fargate_agent_runtime" {
  detector_id = aws_guardduty_detector.this.id
  name        = "RUNTIME_MONITORING"
  status      = "ENABLED"
  additional_configuration {
    name   = "EKS_ADDON_MANAGEMENT"
    status = "DISABLED"
  }
  additional_configuration {
    name   = "ECS_FARGATE_AGENT_MANAGEMENT"
    status = "ENABLED"
  }
}
```


これでGuardDuty側は有効化できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/f148dcb8-f1bc-4a1b-f476-61e787944f16.png)

上記に追加で対応したのは以下の3点です。

1. GuardDutyのVPC Endpoint(`com.amazonaws.ap-northeast-1.guardduty-data`)作成
2. SubnetやSecurity Groupの確認
3. IAM権限の確認( `AmazonECSTaskExecutionRolePolicy` 使っていれば問題無し）

特に1は恐らく画面から操作すれば自動で作成されるらしいですが、Terraformから作成した場合は自分で作成する必要がありそうでした。また、ここまでやっても以下のエラーが出ていてUnhealtyの状態でした。

> Unidentified issue, for tasks in TaskDefinition - 'TASK_DEFINITION'


権限もVPCEndPointへの疎通確認しても問題無さそうだしということで諦めて一晩寝て起きて見てみたらHealtyになっていました。時間かかるのかもしれません。
サロゲートペアについて調べてみる

## はじめに
サロゲートペアという言葉を聞いてよくわからなかったので、調べたことを備忘録としてまとめておこうと思います。

## サロゲートペアについて調べてみる
まずサロゲートペアについて話す前に、Unicode の話をしようと思います。

### Unicode とは
Unicode とは、世界中の文字を一意に表現するための文字コードのことです。日本語に使われるかなや、英語に使われるアルファベット、それ以外の言語で使われる文字が含まれます。

Unicode は様々なエンコーディング方式（例えば UTF-8、UTF-16、UTF-32）を使用し、これらは 1 文字を表現するのに可変長のバイトを使用します。UTF-8は 1 ~ 4 バイト、UTF-16 は 2 バイトまたは 4 バイトを使用できます。

### サロゲートペアとは
サロゲートペアとは、2 つの 2 バイトのコードユニットの組み合わせです。これには、上位サロゲートと下位サロゲートがあります。これらの範囲は、それぞれ 2^10 (= 1,024) 個のコードポイントを持ちます。上位サロゲートと下位サロゲートは、それぞれ単体では意味をなしません。それぞれが組み合わさることで初めて特定の文字を表します。これにより、追加の 1,048,576 個のコードポイントが利用可能になりました。

### サロゲートペアの問題点
サロゲートペアを使う文字は、特に文字列の長さのカウントや文字の切り出しで注意が必要です。2 つのコードユニットが 1 つの文字を表すため、一般的な文字数カウント方法では正確な結果が得られません。

知人が、ChatGPT などの AI が苦手なことの一つに、文字数カウントがあると言っていて、その理由がサロゲートペアを使った文字をカウントしている時があるからと言っていました。

## 参考資料
以下の記事を参考に作成しました。

https://codezine.jp/article/detail/1592

https://www.magata.net/memo/index.php?%A5%B5%A5%ED%A5%B2%A1%BC%A5%C8%A5%DA%A5%A2

https://developer.mozilla.org/ja/docs/Glossary/Unicode

https://systemengineers.hateblo.jp/entry/2021/07/10/071513
Juliaでデータ処理

# はじめに
JuliaでCSVデータの処理を行ったため、いくつかまとめる。

# 処理内容
まずはCSVファイルをデータフレームとして読み込む。
```julia
using CSV, DataFrames, StringEncodings

df = open("your_file_path", "r") do file
    decoded = read(file, enc"CP932")
    CSV.read(decoded, DataFrame)
end
```
CSVファイルを読み込んで→エンコーディングして→データフレームとして読み込むという処理したい手順でコードを書くことができてとても便利！

では、いらない列を削除してみよう。
```julia
select!(df, Not([1,2,3,size(df,2)]))
```
select関数を用いることで、抽出したい列を指定できるが、引数にNot演算子で削除したい列を指定することで削除することができる。
このとき、Not演算子には数字で渡せば1番目、2番目となるが、`:列名`で渡せば、任意の列を削除することができる。
また、今回の例では`size(df,2)`を指定しているが、これは**一番最後の列**を意味している。一応覚えておこう。

次に、1行目をヘッダーに指定してみる。
```julia
header = [Symbol(df[1,col]) for col in names(df)]
rename!(df, header, makeunique=true)
deleteat!(df, 1)
```
`names(df)`で全列名を取得し、それらをfor文でシンボル型に変換する。その後、rename関数を用いて列名を更新する。1行目は列名に指定したため不要だからdeleteat関数で1行目を削除する。
`rename関数`は以下のような書き方でも列名を変更することができる。
```julia
rename!(df, :old_column => :new_column, :aaa => :bbb)
```
こちらもセットで覚えておこう。

最後にグルーピングして、それらの最大値を取得してみよう。
```julia
group = groupby(df, :column_name)
max_values = combine(group, names(df) .=> maximum)
```
`groupby関数`でグルーピングしたい列名を指定してグルーピングする。
その後、`combine関数`を用いて、全列名に対して最大値を取得する。
このとき`.=>`と`=>`の前に`.`を入力したが、これはドット演算子といって、リストの全ての要素に対して同じ処理を行いたい場合に用いることがある。
これもよく使用するので覚えておこう。

# まとめ
データ処理を行う際によくやってる処理をJuliaで行ってみた。
演算子や関数について、まだ理解が浅いため深めていこうと思う。
Arch Linuxのブートローダーを変更した話

この記事はウェブクルー Advent Calendar 2023 22日目の記事です。
昨日は @kalzit さんの「[Effectの紹介](https://qiita.com/kalzit/items/fb3c12310436610790a3)」でした。

## はじめに

去年、自宅ThinkPadにArch Linuxを導入してから1年以上経ちました。最近、不用意にブートローダーをいじったせいでArch Linuxが起動できなくなったことがあったので、備忘録として残します。

## Arch Linuxとは

公式サイトから引用させていただきました。
Linuxのディストリビューションの1種で**シンプル**という点に重きが置かれています。

> Arch Linux は、x86_64 向けに独自に開発された、あらゆる用途に対応できる万能 GNU/Linux ディストリビューションです。Arch はローリングリリースモデルをベースとしており、常に最先端であるように努め、ほとんどのソフトウェアは最新の安定バージョンが提供されます。Arch は最小限の基本システムの状態でインストールされ、ユーザー自身が、ユーザーの理想とする環境のために必要なものだけをインストールして構築することができます。 

https://wiki.archlinux.jp/index.php/Arch_Linux

## ブートローダーとは

最近、ChatGPTに課金したので聞いてみました。

> ブートローダーは、コンピューターの起動時にオペレーティングシステム（OS）をメモリにロードするための小さなソフトウェアプログラムです。コンピューターの電源が入ると、ブートローダーが動作を開始し、ストレージデバイス（ハードドライブやSSDなど）に保存されているOSを見つけてメモリに読み込みます。これにより、OSが起動し、コンピューターを使用することができるようになります。ブートローダーはコンピューターの起動プロセスの最初のステップであり、システムが正常に動作するために非常に重要です。

とのことです。

## 話の流れ

1. ログイン時に表示されるエラーを直したい
2. ブートローダーの再インストール
3. USBに最新のISOをインストール
4. USBを使ってThinkPadでArch Linuxを起動する
5. ThinkPadのSSDにマウントしてブートローダーの設定変更
6. 直った！！

## 1. ログイン時に表示されるエラーを直したい

Arch Linuxのログイン画面で数秒間ログインせずに放置していると以下エラーがでます。

```
Invalid ELF header magic: != △ELF
```

このエラーは放置しても特に問題なくログインできるので普段は放置していましたが、ふとこれ邪魔だなと思い直そうとしたのがこの話の始まりです。

## 2. ブートローダーの再インストール

このエラーを修正しようとして調べていて、利用していた**GRUB**というブートローダーのせいではという情報がでてきたので再インストールをしました。
これのせいで既存のブートローダーの設定が上書き？されてしまい、ThinkPadの電源を落とした後に起動させようと電源ボタンを押してもOSが起動せずにThinkPadのBIOSに飛ぶようになってしまいました。。

## 3. USBに最新のISOをインストール

ThinkPadのBIOSでOS起動ができないか色々といじって頑張りましたが、無理でした。
こういうときはインストールメディアを用意する必要があるので、バッテリーが死んでいてほぼ使っていないMacBookを押入れから出してUSBにArch LinuxのISOをインストールしました。
やり方は以下記事を参考にすればできます。

https://wiki.archlinux.jp/index.php/USB_%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%83%A1%E3%83%87%E3%82%A3%E3%82%A2#macOS_.E3.81.A7

## 4. USBを使ってThinkPadでArch Linuxを起動する

3.で用意したUSBをThinkPadにぶっ刺してBIOSで起動するArch Linuxを選択します。
そうすると、でかいビープ音とともにOSが起動します。
このときにThinkPadのセキュアブーストを無効化しました。これをし忘れると永遠に起動してくれません。

## 5. ThinkPadのSSDにマウントしてブートローダーの設定変更

OSが起動できたらあとはインストールガイドに沿って作業を進めました。
パーティションはすでにあるやつを使いたかったのでスキップして、すでにあるパーティションにマウントをしてThinkPadのSSDに入り込みました。
ここまで作業をしてようやくブートローダーの設定変更ができるようになります。
ブートローダーにはGRUBを使っていましたが、今回はsystemd-bootに変更しました。
GRUBのせいでログイン画面のエラーになっているかもしれないということがあったのとsystemd-bootの方がシンプルでsystemdと一緒に最初に入ってくるらしいのでこちらを選択しました。
あとはsystemd-bootの設定を公式サイトに沿ってやりました。


https://wiki.archlinux.jp/index.php/%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%82%AC%E3%82%A4%E3%83%89#.E3.83.95.E3.82.A1.E3.82.A4.E3.83.AB.E3.82.B7.E3.82.B9.E3.83.86.E3.83.A0.E3.81.AE.E3.83.9E.E3.82.A6.E3.83.B3.E3.83.88

https://wiki.archlinux.jp/index.php/Systemd-boot


## 6. 直った！！

ブートローダーの設定が終わったら、ThinkPadのSSDをアンマウントしてThinkPadを再起動させました。
起動時にブートローダーが正常に動作したおかげで、USBがなくてもOSが起動できるようになりました！！
ただ、ログイン画面で発生していたエラーはそのままでした。。ブートローダーが悪さをしていたわけではなさそう、、どなたか詳しい方いれば教えていただきたいです。。

## おわりに

話の流れをまとめて書いたら各作業をさくさく進められたみたいに思えますが、かなり色々とはまりました。。
自分が低レイヤに対する知識が薄いのと久しぶりにBIOSとかの操作をしたのでまったく覚えてなくて結構時間が溶けました。。
普段はWEBアプリに関連した仕事をしていますが、OSとかにも強くなりたい。。

明日は、@ee4839 さんの投稿です。よろしくお願いします。
【Git】cherry-pickで特定のコミットだけマージする

このようなコミットがあるとして、`develop`ブランチ
に`master`の`F`のコミットだけ`merge`したいとする


![スクリーンショット 2023-12-21 21.57.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517817/2d564895-8cb6-7b5e-dc15-501d4ea31f06.png)

現状`E`と`F`のコミットの内容は`index.html`にそれぞれ`E`と`F`の文字列が存在している。

つまり、今回は`F`の文字列だけ`develop`にmergeしたい。
```
user1@user1noMacBook-Pro cherry % git show 64aaf1a
commit 64aaf1a9b018f9ec26103188fb08a21b237dc551 (HEAD -> master)
Author: 
Date:   Thu Dec 21 21:56:48 2023 +0900

    F

diff --git a/index.html b/index.html
index 54f9e44..254e13c 100644
--- a/index.html
+++ b/index.html
@@ -1,2 +1,2 @@
 A
-E
\ No newline at end of file
+F
\ No newline at end of file
user1@user1noMacBook-Pro cherry % git show 53a6b25
commit 53a6b2557d17eada8c0c70d3aed8a4538d9bd45d
Author: 
Date:   Thu Dec 21 21:56:35 2023 +0900

    E

diff --git a/index.html b/index.html
index 8c7e5a6..54f9e44 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,2 @@
-A
\ No newline at end of file
+A
+E
\ No newline at end of file
```

`git cherry-pick ブランチ or ハッシュ or HEAD`で指定できる。


```terminal
git cherry-pick master
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
error: could not apply 5fee5ce... E
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
```

該当の`コミット`をマージする事で、その`コミット`を取り込んだ新しい`コミット`(今回は`G`)を作って、特定の`コミット`のみを`マージ`する事ができる。

![スクリーンショット 2023-12-21 22.05.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517817/3c7059de-3582-ee43-27d1-e70ee186041b.png)

![スクリーンショット 2023-12-21 22.05.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517817/d314d188-c8ff-9a1c-b33f-9dfc91c50b3a.png)
非情報系の大学生　基本・応用の受験記録

# はじめに
R4秋に基本情報・R5秋に応用情報に合格することができたので、体験記という形で勉強の進め方などを書くことができたらと思っております。

普段からQiitaにはお世話になっており、自分も何とか記事として何かを還元できないかを考えた時に、こちらの記事を書くに至りました。

ITよわよわ人間なりに、どのように対策したかを書こうと思ってます。
今後、基本情報や応用情報を受ける予定の方々への参考になったら幸いです。
# 目次
<!-- タイトルとアンカー名を編集 -->
1. [基本情報の勉強について](#Chapter1)
1. [応用情報の勉強について](#Chapter2)
1. [おわりに](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# 基本情報の勉強について
まず、基本情報を受けたときの私の前提知識は

・情報系の知識はほとんどわからない(未習なので)
・過去問道場を初めて通しで解いた時は正答率4割ほど

であり、**簡単な計算の問題や当たり前の知識問題**くらいしか取ることができないという状態でかなりボロボロの状態でした。。。

その状態から何とか試験本番での成績は、**午前:68.75点　午後:75点**に持ち上げることができました

私が基本情報を受ける際に行った勉強は以下の通りです。
### (A)午前対策:　「栢木先生の基本情報技術者教室」×１周　→　過去問道場
まず、何をすれば良いのかわからないほど基本知識がボロボロの状態だったので、上記の本を１ヶ月くらいかけて１周しました。
本については、最新版のものを買うと良いと思います。
その後、過去問道場を回しまくって(総3300問・五段)、過去問だけでも8割くらい取れるようにしました。
過去問道場では、最初は間違えまくって辛いと思いますが、慣れてくると高速で回せるようになるので頑張りましょう！！
### 〜午前対策の反省(基本情報)〜
とりあえずで申し込んで上記のような勉強をしたので、全然効率的じゃないと思ってます...
改善するとしたら、

・　最初に全体像を把握するための参考書はわからなくても良いので**１週間くらい**で終わらせる
・　過去問道場を回すだけでなく、間違えた問題に対して**用語などを覚えるフェーズ**を作る

以上の２点を気をつけるともう少し勉強が点数に結びつくと思いました！

### (B)午後対策:　「基本情報技術者 午後試験対策書(iTec)」×１周　→　過去問道場
午後については、基本情報の午前問題で正答率が6割ほどになった時に「基本情報技術者 午後試験対策書(iTec)」を始めました。
また、対策する分野はある程度絞って
・情報セキュリティ
・ソフトウェア設計
・マネジメントやストラテジ系
・アルゴリズム
・プログラミング(表計算ソフト)
あたりを対策していました。(今は、基本情報が新しくなったのであまり参考にはならないかもしれませんが...)
その後、過去問道場で８回分の模擬演習を行いました。

### 〜午後対策の反省(基本情報)〜
問題との相性や設問ごとの難易度差があったりで、**勉強しても点数になかなか繋がりづらくて**しんどかったです。**時間を測って本番を想定した演習を積む**と割と短期で良い結果に繋がる可能性があると思われます。
ということで「**午後対策本を一周やって終わり**」という方も多いかもしれませんが、個人的には**通しで何回か演習しておく**と安定すると良いんじゃないかと思います。


<a id="#Chapter2"></a>
# 応用情報の勉強について
次に応用情報についてです。この時点での私の前提知識は以下の通りでした。

・基本情報を取ったものの、１年経っているのでほとんど忘れる()
・院試で論理回路の勉強をしたので、論理回路周りの知識は固まっている

また、諸々の都合で対策期間を**1ヶ月**にせざるを得ない状況でした。

初めて応用情報の過去問道場を解いた時にはおよそ4.5割くらいで、基本情報との難易度差に絶望しかけました。

そのような状態から何とか**午前:76.25点　午後:62点**で滑り込みました(午後危なすぎ！！！)
大まかな勉強の流れは基本情報の時と大差ないですが、一応紹介させていただきます。

### (A)午前対策:　過去問道場のみ
とにかく過去問道場を回しまくり(総3000問・四段)、過去問だけでも8割越え安定するようにしました。
また今回は、基本情報の時の反省を活かして、過去問道場で**間違えた用語と意味をノート・暗記帳にまとめてひたすら覚えました**。
**覚える**というフェーズがなかなか大事で、午後で用語を書かせる問題が出たりするので、勉強する上で**遠回りなようで時短につながった**と思います。

### 〜午前対策の反省(応用情報)〜
今回は対策にかけられる時間が1ヶ月もなかったので、中途半端な対策になってしまったのですが、もう少し過去問道場を回せるようになると安定すると思われます！あとはISOだとか無線の規格など**細かい知識**も抑えられるようになるとなお良いと思います。

### (B)午後対策:　「応用情報技術者　午後問題の重点対策(iTec)」×１周
午後については、本当に対策不足感が否めないです。。。上記の本を一周して、答案の書き方を学びました。
また、対策する分野は絞って、
・情報セキュリティ
・経営戦略
・システムアーキテクチャ
・組み込みシステム
・プロマネ
・サビマネ
の６科目を勉強しました。

受験前の戦略として、**セキュリティと組み込み**は安定するようにしました。
あとは損益表あたりの計算は絶対できるように対策しました。

### 〜午後対策の反省(応用情報)〜
対策にかける時間をもう２週間くらい増やせれば安定してくるんじゃないかと思ってます。
本当はプログラミングも触れたかったです...自己採点をする時に文系寄りの科目が増えると採点の精度がぼやけてしまうので、理系寄りの答えがはっきり出る問題を得意科目にすると合格発表までの期間も安心できると思います。
あとは、**通しでの演習は一回もできませんでした**(ヤバすぎる)ので、なかなかな賭けに出てしまったと反省しております。
### 通しでの演習を何回かやっておいた方が絶対に良いです！！！

<a id="#reference"></a>
# 終わりに
以上が基本情報・応用情報の受験した時の勉強方法と反省です。
この記事を見た方にとって少しでも有益な情報が書けていたら幸いです。(筆者は来年データベーススペシャリストを受けようかなと思っています)
#### 基本情報・応用情報の勉強は長くて、大変だと思いますが頑張ってください！！
システム開発上中流工程でユビキタス言語化された日本語プログラミング言語と日本語識別子を使った数学的形式言語の対比

# はじめに

日本語プログラミング言語をモデリング言語としてシステム開発上中流工程に導入した場合、そのメリット・デメリットについて考察する記事の9回目です。

本記事の内容はいくつかに分割されて記載されます。本記事中の「本記事」とは分割された内容の総体を指す場合があります。

https://qiita.com/advent-calendar/2023/remind

この記事は日本語構造化仕様記述言語 Re:Mind（リマインド）アドベントカレンダー2023の21日向けの記事です。

## 対象読者
とりあえずこの記事の想定読者はシステムエンジニアさんです。とくに日本語で要求仕様や内部設計資料を書いている方向けのお話です。

# 想定しているシステム開発フロー
オーソドックスなリレーショナルデータベースを使用している業務システムであることを[1回目](https://qiita.com/mylifewithviolin/items/b7cc85911507cf1a2a55)[2回目](https://qiita.com/mylifewithviolin/items/4ce62e0d5473626347e1)の記事で説明しております。

## 想定しているレイヤードアーキテクチャ・業務
一般的なWebアプリケーションシステムであり、簡単な受発注業務をインターネットで支援するシステムであることを[3回目](https://qiita.com/mylifewithviolin/items/d10d59e98c4d2d7dca3d)[4回目](https://qiita.com/mylifewithviolin/items/68dbf00cebb1bc8f6209)の記事で説明しております。

## 想定しているユビキタス言語
[5回目](https://qiita.com/mylifewithviolin/items/e1a7915efbf369117c97)の記事ではドメイン駆動設計（DDD）の文脈で用いられる意味でのユビキタス言語を例示しました。

## ユビキタス言語化された日本語プログラミング言語
[6回目](https://qiita.com/mylifewithviolin/items/f49c48241d8f72d6839a)[7回目](https://qiita.com/mylifewithviolin/items/8823d08c79bf70464bc0)の記事ではドメインエキスパートからプログラマレベルまで共有可能な言語のことをユビキタス言語化された日本語プログラミング言語とし、その各工程のソースコードの差異を例示・解説しました。

また、[前回](https://qiita.com/mylifewithviolin/items/4db1d402ed273ec784dc)の記事では日本語プログラミング言語をモデリング言語としてシステム開発の上中流工程に導入した場合のメリット・デメリットについて、いったんまとめてみました。

# 数学的形式言語で日本語識別子を使えばよいのでは問題
21世紀の第1四半期のおわりである今日、システム開発の上中流工程において実績のある言語処理系はやはり数学的形式言語でしょう。
中でも構造化プログラミング言語の構文を持ち、オブジェクト指向言語によるモデリングも可能な処理系としてVDM++は最有力の存在です。

コンピュータシステムと一言でいっても多種多様な系が存在し、IoT時代ではハードウェア制御が関係するシステムも多数存在しており、ミッションクリティカルなシステムでは数学的形式言語での要件適合性の検証がマスト要件になっているものもあるようです。

結論から申し上げますと、数学的形式言語で日本語識別子を使えばシステム開発の上中流工程のあいまいさを排し、より合理的な整合性のある仕様や設計が可能であることに疑いはないとわたしは考えております。

1回目の記事で図示しました、ユビキタス言語化された日本語プログラミング言語のシステム開発工程上の位置づけを数学的形式言語で置き換えてみますと、ざっくり以下のようになると思われます。

```mermaid
flowchart 
    subgraph sgA["上流工程"]
    A["ユビキタス言語</br>（日本語業務用語ディクショナリ）"] --> B["日本語を使った数学的形式言語（陰定義）"]
    A --> F["概念ER図"]
    style sgA width:500px
    end
    subgraph sgB["中流工程"]
    B --> C["日本語を使った数学的形式言語（陽定義）"]
    C --> D["数学的形式言語の実装言語ソース生成"]
    F --> G["論理ER図"]
    G --> H["物理ER図"]
    style sgB width:500px
    end
    subgraph sgC["実現工程"]
    D --> E["実装言語（Java C++など）"]
    H --> I["実データベース"]
    style sgC width:500px
    end
```
数学的形式言語の処理系であるVDM++を使用した設計手法の解説情報では、当たり前のように日本語識別子が使われています。これはやはりDDD的な意味でのユビキタス言語が自然言語の母語で書かれていることから、その流れでも日本語でモデリングするのが自然であるという認識が設計現場では一般的であると推察されます。

## ユビキタス言語化された日本語プログラミング言語と日本語識別子を使った数学的形式言語ではなにが違うのか

日本語識別子を使った数学的形式言語といった場合、半角英字トークンをベースに設計された処理系で日本語識別子を使うという意味のほか、まだ登場はしていませんが、日本語プログラミング言語のように日本語がネイティブのシステムトークンとなっている数学的形式言語というものが、将来登場するとしたらそれも含めて何が違うのかという話になっていきます。

ちなみに本記事の主題は、システム開発上中流工程で同じようにユビキタス言語化された、日本語識別子を使った数学的形式言語を新たに検討しようとするものではなく、構造化プログラミング言語で静的型付け、オブジェクト指向パラダイムの特徴をもつ設計言語について検討しております。

なにがどう違うのかについては次回、詳しく説明します。

# この回のまとめ
上中流工程においては、競合でありパートナーでもある日本語識別子を使った数学的形式言語の存在について触れてみました。

# 次回
数学的形式言語との関係について引き続き検討します。
MongoDBシャードキーの選び方

## はじめに
MongoDBでの効率的なコレクション設計には、シャーディングを考慮したアプローチが不可欠です。本記事では、最適なシャードキーの選び方に焦点を当て、それらのキーがMongoDBのパフォーマンスにどのように影響するかを探ります。

## シャードキーとは
シャーディングはデータベースの水平分散を指し、データを異なるサーバーに分散させて負荷を軽減します。シャードキーはこのシャーディングプロセスにおいて、どのデータがどのシャードに割り当てられるかを決定する重要な要素です。

MongoDBでは、シャードキーによってデータは重複なく分割されます。分割されたデータ範囲を**チャンク**と呼び、MongoDBはこれらのチャンクを各シャードに均等に分配します。この均等なデータ分配プロセスを**オートバランシング**と称します。


## シャードキーの選び方アンチパターン
まずは、やってはいけない選び方を説明します。シャードキーの選び方はいろいろありますが、やらない方を先に分かっておくと選択肢が狭まり、選びやすくなります。

では、シャードキーのアンチパターンを３つ紹介します。

### アンチパターン１：検索に使用しないフィールド
検索に使用しないフィールドをシャードキーに設定してしまうと、サーバーに無駄な負荷をかけてしまいます。
シャーディングされたサーバーへデータを取得するときの流れを説明します。
1. mongosからconfigサーバーへ、データが格納されている場所を問い合わせます。
1. configサーバーは設定されたシャードキーから、データが格納されたシャードを見つけます
1. configサーバーからmongosへ格納場所（シャード）を渡します
1. mongosは指定されたシャードからデータを取得します

ここで、シャードキーのフィールドが検索クエリに指定されていないと、configサーバーがmongosへ格納場所を教えることができず、シャードを全検索します。

![スクリーンショット 2023-12-21 21.01.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1650886/26def120-f0f1-8e35-d8a8-2583a56925b7.png)

そのため、せっかくシャードを分散しているのに、負荷分散できなければシャーディングの意味がないため、検索に使わないフィールドはシャードキーに指定しないようにしましょう。

### アンチパターン2：単調増加するフィールド
単調増加するフィールド（例えば、タイムスタンプやID）は、新しいデータが特定のシャードに偏ることを引き起こすため、シャードキーとしては適していません。
例えばUserコレクションで、UserIDをシャードキーにしたとき、UserIDは001,002,003と単調増加していきます。多くのユーザーがいる場合、UserIDの値も大きくなり、片方のシャードに問い合わせが偏ります。

![スクリーンショット 2023-12-21 21.14.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1650886/5915c28c-3c4d-d225-c94d-390867aea19f.png)

これはMongoDBが各チャンクにminKey,maxKeyをいう値をもっており、単調増加した場合、maxKeyのみが増えていくためです。

単調増加するフィールドとしては、_idや、インクリメントだけする数値データ、日付データなどがあります。これらは、シャードキーに設定しないようにしましょう。

## シャードキーの選び方
アンチパターンがわかったところで、シャードキーの選び方を考えます。
適切なシャードキーを選ぶことは、システムのスケーラビリティとパフォーマンスに直接影響します。
以下に選び方の一種を載せます。

### 検索条件に使われるフィールド
「アンチパターン１：検索に使用しないフィールド」の逆で、検索によく使われるフィールドはシャードキーに適しています。


### カーディナリティの高いフィールド
シャードキーのカーディナリティによって、作成できるチャンクの最大数が決まります。
そのため、カーディナリティが高い、つまり多様な値を持つフィールドをシャードキーに選ぶことで、データの分散が均等になり、負荷分散に寄与します。

例として、投稿コレクションを例に、どのフィールドがシャードキーに適切か考えてみましょう。
投稿IDはシステムにより自動採番される値とします。

【投稿コレクション】
- _id
- 投稿ID
- ユーザーID
- 投稿日時
- 投稿内容
- いいね数

検索条件に使用されない、「_id」「いいね数」はシャードキーに適切ではありません。
単調増加する、「投稿ID」「投稿日時」はシャードキーに適切ではありません。

残ったのは「ユーザーID」「投稿内容」ですが、カーディナリティが高い「ユーザーID」が適切です。

## 終わりに
適切なシャードキーの選定は、MongoDBのパフォーマンスとスケーラビリティを最大化する上で重要です。これらのガイドラインを参考に、効果的なシャーディング戦略を立てましょう。

### 参考文献
- MongoDB公式ドキュメント: [シャードキーの選び方](https://www.mongodb.com/docs/manual/core/sharding-choose-a-shard-key/#std-label-sharding-shard-key-selection)
DjangoのカンタンLogout機能で2日間さまよった話

# 何が起こったか？
お勉強がてら作ったWebアプリにログインログアウト機能を作ろうと思って、とりま、paizaラーニング様の言う通り、settings.pyやらurls.pyやら修正したり、追加したりしていました。
login.htmlとlogged_out.htmlも作成し、テスト！

rogin.htmlはさっくり表示され、いいねぇ＾＾と喜んでいました。
そして、ログアウト！
・・・・・
「このページは機能していません　405エラー」

なんかあっさりした日本語のエラーが表示されました。
エラーが出るときって、なんか色々小難しい英語でまくしたてられるのに。

# ログインはうまくいくのにログアウトできないって
- ルーティングがうまくいってない？
- settings.pyがダメなん？
- ひょっとしてlogged_out.htmlに記述ミスが？
- ページのログアウトのリンクがNG？
- まさかのdjango.contrib.auth.urlsやviewsあたりにバグが！？（ぉぃｗ）

気になりだしたら先に進めなくなってしまい、1つづつ○○.pyやらXX.htmlやらを確認していきました。
時間はかかるし、一旦あきらめようと思いつつ、やっぱり気になり、また見直すという繰り返し。
そして・・・

# ターミナルを見た💦
Method Not Allowed (GET): /accounts/logout/
Method Not Allowed: /accounts/logout/
[21/Dec/2023 21:11:19] "GET /accounts/logout/ HTTP/1.1" 405 0
っていっぱい出てた。

これって、え、まさかのGETダメなやつ！？
そして、ググった。
LogoutViewはGETメソッド廃止されてるんだって。
えーーーーー・・・。

Logoutのリンクの部分をこんな風にしたら、あっさり解決しました。

```html
<form action="{% url 'logout' %}" method="post" name="f_logout">
    {% csrf_token %}
    <input type="hidden" value="logout">
    <a href="javascript:f_logout.submit()" class="logout nav-link">Logout</a>
</form>
                    
```

マジ、解決してよかった＞＜
何も手がつかなくなるところだった。
そして、色々反省した。
【Slack 新ワークフロービルダー】フォームの回答形式が増えたので触ってみた

## はじめに

こんにちは！

この記事は、[ミロゴス Advent Calendar 2023](https://qiita.com/advent-calendar/2023/milogos) 23日目の記事です。

Slackのワークフローが新しくなり、できることが色々増えましたが、
個人的にフォームの回答形式のアップデートがアツかったので、触ってみました。

## できるようになったこと
旧ワークフローはレガシーワークフローと呼ばれています。
レガシーワークフローでは、フォームの回答形式は5種類しかありませんでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981564/9725c9ed-4f76-a3ed-8cb1-080db12256de.png)

- 1行テキスト：1行のテキストで回答できる。
- 段落：改行を使用して回答できる。マークダウン形式の入力は不可。
- ドロップダウン：最大20個のリストから選択できる。単一選択のみ。
- メンバーを選択：ワークスペースにいるメンバーを選択することができる。1人のメンバーのみ選択可能。



5種類の回答形式しかなかったレガシーワークフローと比べて、新ワークフローのフォーム回答形式は14種類あります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981564/e0cbfdd6-fd31-ace6-54da-3431351597a1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981564/4efe81ba-a5d0-06c0-8733-cb6232cd324d.png)

- 1行テキスト：1行のテキストで回答できる。
- 段落：改行を使用して回答できる。マークダウン形式の入力は不可。
- **リッチメッセージ作成領域**：マークダウン形式の入力が可能。
- メンバーを選択：ワークスペースにいるメンバーを選択することができる。1人のメンバーのみ選択可能。
- **複数の人を選択する**：ワークスペースにいるメンバーを選択することができる。複数のメンバーを選択可能。
- チャンネルを選択：ワークスペースにあるチャンネルを1つ選択可能。
- **複数のチャンネルを選択する**：ワークスペースにある複数のチャンネルを選択可能。
- ドロップダウン：**50個以上**のリストから選択できる。単一選択のみ。
- **複数選択**：50個以上のリストから選択できる。複数選択可能。選択できるアイテム数の上限も設定可能。
- **チェックボックス**：10個のチェックボックスを設定可能。
- **日付**：カレンダーから日付を選択可能。
- **日時**：日付と時間を選択可能。
- **数値**：数値を入力可能。
- **ファイルのアップロード**：アップロードする必要があるファイルの数を「シングル」か「複数」で設定可能。アップロードできるファイルタイプを画像のみに指定することも可能。



## 新ワークフローの罠
複数選択や日時選択ができるようになり、フォームの使い方の幅が広がりましたが、注意したい罠があります。
**罠1**
- 複数選択にすると、メンションやリンクが無効になる※12/22時点
    - 複数の人にメンションを送りたい場合は、フォームで単一選択の設定をしておく必要があるようです。
    - Slackのサポートに問い合わせたところ、不具合だという回答がありましたので、改善されると良いですね。

**罠2**
- 日時の選択は、タイムゾーンがUTCである
    - 日本時間で記載したい場合には、フォームの回答時に**9時間後**の日時を選択する必要があるようです。

新ワークフローで作成したフォーム提出後の見え方
![画像4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981564/1f2aaddc-c353-61d7-6a3d-1b5139768d10.png)

## おわりに
フォームの回答から日付を選択できるようになったり、ファイルをアップロードできるようになったりしたことで、活用の幅がぐんと広がりました。
最後に記載した罠について解消方法をご存じの方や、よりよいフォームの活用方法がありましたら、ぜひコメント欄でシェアいただけますと幸いです。

以上、ここまで読んでいただきありがとうございました！
【SwiftUI】SectionのHeaderとContentのspacingを調整する

# はじめに
こんにちは。[ymurao2](https://twitter.com/ymurao2)です！
Viewのグループ化をSectionを利用して行う際、HeaderとContentのスペースの調整方法が分からなかったので、記事に残しておきます

#### 想定する画面
想定する画面は以下のようなものです。
Contentの上にHeaderを表示しています。

![CleanShot 2023-12-21 at 21.38.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529173/62ac14a4-5d89-f2a1-b70f-14d66e88dd89.png)

# 実装
```diff_swift
var body: some View {
+   VStack(spacing: 0) {
        Section {
            Text("Content")
                .font(.title)
                .frame(maxWidth: .infinity)
                .frame(height: 300)
                .background(Color.gray.opacity(0.2))
        } header: {
            Text("Header")
                .font(.caption)
                .frame(maxWidth: .infinity, alignment: .leading)
                .background(Color.gray.opacity(0.4))
        }
+  }
}
```
`Section`を`VStack`で囲んで、`spacing`を付与することでContentとHeaderのスペースを調整できることがわかりました。
0を指定することで、ContentとHeaderがピッタリくっついています。

```swift
var body: some View {
    VStack(spacing: 8) {
        Section {
            // 省略
        } header: {
            // 省略
    }
}
```
spacingに8を指定したときは以下のとおりです


![CleanShot 2023-12-21 at 21.40.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529173/b2668381-0423-4edc-2556-24f93dbc376b.png)

# おわりに
当然と言えば当然かもしれませんが、簡単に実装できました
（もっと早く知りたかった...）