OmniAICreator/Qiita-1.07M huggingface dataset:
【SwiftUI】DatePickerで日付を選択する



## まえがき
この記事はSwift独学者による備忘録です。
万が一誤った記載がある場合は、コメントでご指摘いただけると幸いですm(_ _)m

## 確認環境
XCode Version 15.4
MacOS Sonoma 14.4.1

## 日付を選択する方法
日付の選択方法はいくつかありますが、この記事ではDatePickerを使用して「年月日」を選択する方法をまとめます。

## コード例

```Swift:ContentView.swift
import SwiftUI

struct ContentView: View {
    @State private var selectedDate: Date? = nil
    @State private var isDatePickerPresented = false

    var body: some View {
        NavigationView {
            VStack(spacing: 20) {
                HStack {
                    Text("誕生日:")
                    Spacer()
                    Text(selectedDate != nil ? formattedDate(selectedDate!) : "選択")
                        .foregroundColor(.gray)
                }
                .padding()
                .background(Color(UIColor.secondarySystemBackground))
                .cornerRadius(10)
                .onTapGesture {
                    isDatePickerPresented = true
                }

                Spacer()
            }
            .padding()
            .navigationTitle("誕生日を選択")
            .sheet(isPresented: $isDatePickerPresented) {
                DatePickerView(selectedDate: $selectedDate)
            }
        }
    }

    func formattedDate(_ date: Date) -> String {
        let formatter = DateFormatter()
        formatter.dateStyle = .medium
        formatter.locale = Locale(identifier: "ja_JP") // 選択した日付を日本語表記にする
        return formatter.string(from: date)
    }
}

struct DatePickerView: View {
    @Binding var selectedDate: Date?
    @State private var tempSelectedDate = Date()
    @Environment(\.dismiss) private var dismiss

    var body: some View {
        VStack {
            DatePicker("Select a date", selection: $tempSelectedDate, displayedComponents: .date)
                .datePickerStyle(WheelDatePickerStyle())
                .labelsHidden()
                .padding()
                .environment(\.locale, Locale(identifier: "ja_JP")) // 選択する日付を日本語表記にする
            
            Button("Done") {
                selectedDate = tempSelectedDate
                dismiss()
            }
            .padding()
            .background(Color.blue)
            .foregroundColor(.white)
            .cornerRadius(10)
        }
    }
}

```


| 選択前 | 日付選択画面 | 選択後 |
| ---- | ---- | ---- |
| <img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3805527/f9c441e7-3641-cfc8-ee70-ee04e31fb27e.png"> | <img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3805527/4f7510a3-1b93-107c-059a-8cf9022d13fc.png"> | <img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3805527/8ad16b5a-e559-06ae-f043-943a3a5eefc4.png"> |

## あとがき
簡単にDatePickerで日付を選択する方法をまとめました。
今後も捕捉事項があれば随時更新していきます。
linuxのコマンドラインで使えるオフライン辞書を作った

 前々からlinuxで使えるオフラインの辞書がほしいと思っていた。単純に単語を入力すると意味が帰ってくる機能があればよいので、自作することにした。辞書データは下記のサイトのものを利用させてもらった。 
 
 無料 英和辞書データ ダウンロード
https://kujirahand.com/web-tools/EJDictFreeDL.php

辞書のデータは.txt形式とする。
将来的には他にも辞書データを追加して串刺し検索できるようにした。具体的な作業手順は以下のとおりである。なお、辞書データは./Documents/dictData/に保存してあるとする。

辞書ファイルの保管ディレクトリを作成する。
```
$ sudo mkdir /usr/local/share/dict/
```
辞書ファイルを移動する。
```
$ sudo cp ./Documents/dictData/*.txt /usr/local/share/dict/
```

~/.bashrc に以下の行を追加する。
```
# search from some dictionries
function dict() {
    grep ^$1 /usr/local/share/dict/*.txt -A 0 -wi --color |
    sed 's/\/usr\/local\/share\/dict\///g' |
    grep $1 -A 1 -wi --color
}
```
.bashrcファイルを読み込む
```
$ source ~/.bashrc
```
これでTerminalで
```
$ dict 調べたい単語
```
と入力すると結果が標準出力される。
あなたがよく使うコマンドを.gitconfig aliasに登録しちゃおう！

# TL;DR
`~/.gitconfig`に`alias`を記載すると便利です

```shell
# 例
[user]
	name = ***
    email = ***
[alias]
branch-name = ! git branch --show-current
a = add 
c = commit -m
s = status  
sw = switch
reset-commit = ! git reset --soft HEAD^
p = "!f() { branch=$(git symbolic-ref --short head); if [ \"$branch\" = \"main\" ] || [ \"$branch\" = \"master\" ]; then echo 'error: you cannot push to the '\"$branch\"' branch using this command.'; else git push origin \"$branch\"; fi; }; f" 
```
https://git-scm.com/docs/git-config

https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases

# なぜ便利なのか

## 1. 複雑な操作をする際のコマンドを覚えなくて済む

簡単にaliasを作れない場合もありますが、決まりきった作業をする場合はaliasを作ると便利かと思います。
例えば、下のサイトで紹介されているようなコマンドは非常に便利だと感じており日々利用させてもらっています：
1. [Git で force pull する方法 ( $ git reset --hard origin/branch_name ) #Git - Qiita](https://qiita.com/Yinaura/items/30992f25b87f76af3ba2)
1. [ローカルに潜むリモートで削除済みのブランチを安全に一括で削除したいとき](https://zenn.dev/nekonado/articles/git-housekeeping)
1. [【Git】特定のファイルだけ差分を取り消して元に戻したい場合 #command - Qiita](https://qiita.com/takatoshiinaoka/items/99bd50d2f5c4a8f9dfaf)

## 2. 退屈なタイピング作業から開放される

楽しい開発をするたびに`git commit -m`なんて長ったらしいの打ってられないですよね。

なのでaliasをフル活用しましょう！

なんなら`.zhsrc`などで`git`も`g`なんかにしてしまえば、つまらないタイピングの作業を最小限にできます！！

```shell
alias g=git

# TL;DRを含めて、上記の設定をした結果...
# 今までは 
# git commit -m "Hello World"と打つ必要があったものが、 
# g c "Hello World"
# で完結するように！！
```

ちょっとポジティブの話ばかりをしてしまったため、デメリットも説明をします。

# aliasのデメリット

予期せぬ動作をして、事故につながる可能性があります。

そのため、事故になる可能性が低いもの以外は、上記の設定はしないほうが良いと思います。
（そのため、TL;DRで紹介している内容はmainやmasterにはpushできないようにしていたりします）。
Anacondaの仮想環境でJupyter Labをインストールする

# この記事で実施すること
- Aanacondaで仮想環境をつくる
※この時点でインストールするライブラリはなし
- Jupyter Lab と Jupyter Lab の日本語化ライブラリをインストール
- Jupyter Lab を起動してPythonコードの動作確認
- Jupyter Lab の個人設定

# この記事で実施しないこと
- Anacondaのインストール
※インストールされている前提です。

## Anacondaで可能環境をつくる
Anaconda Prompt を起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1408655/6d1655c4-78d0-c9d2-fb01-4341eb4e3ab6.png)

下記コマンドで仮想環境を作成します。
ここで作成される仮想環境にはなんのライブラリもインストールされません。
```shell
conda create --name 仮想環境名
```
下記のように確認された場合は「y」と入力してEnterを押下します。
```shell
Proceed ([y]/n)?
```
仮想環境が作成できたか確認するには、下記コマンドを実行します。
```shell
conda info -e
```
初期から存在する「base」環境と、ご自身で作成した仮想環境が一覧で表示されます。
これで仮想環境の作成は完了です。

## Jupyter Lab と Jupyter Lab の日本語化ライブラリをインストール
前項で作成した仮想環境にライブラリをインストールしたり開発を行いたい場合、操作する仮想環境を切り替える必要があります。
仮想環境を切り替えるコマンドは下記です。
```shell
conda activate 仮想環境名
```
環境が切り替わったかどうかは、コマンド入力の先頭に記載される環境名を確認してください。
```shell:切り替え前
(base) C:\Users\…
```
```shell:切り替え後
(仮想環境名) C:\Users\…
```

その後、Jupyter Lab と Lupyter Lab の日本語化パックをインストールします。
```shell
conda install jupyterlab
```
```shell
conda install -c conda-forge jupyterlab-language-pack-ja-JP
```
前項と同様、下記のように確認された場合は「y」と入力してEnterを押下します。
```shell
Proceed ([y]/n)?
```
インストールが完了したら、下記コマンドで対象の仮想環境にインストールしたライブラリの一覧を確認できます。
```shell
conda list
```
ここまでで本記事で扱うライブラリのインストールは完了しましたが、必要に応じて追加のライブラリをインストールしてください。
## Jupyter Labを起動してPythonコードの動作確認
では、Jupyter Lab を下記コマンドで起動します。
```shell
jupyter-lab
```
「Settings」の「Language」より、「Japanese」が選択できると思うので、押下してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1408655/16d57293-c8d4-90a6-cde3-40349ebfc7f4.png)

確認のポップアップが出るので、「Change and reload」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1408655/0d4028d0-bc7c-f3c4-1182-304446a7a5f5.png)

「＋」ボタンから作業フォルダを作成します。
ルートフォルダはCドライブのユーザー配下になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1408655/28b016ed-2974-4c6d-0f91-b62ef6654690.png)

Notebookを作成し、試しに実行してみたところ問題なく終了しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1408655/5b1db0e0-6f6f-8ee3-303e-7c99bb4dce91.png)

## Jupyter Lab の個人設定

### テーマの変更
「設定」の「テーマ」からダークモードを選択できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1408655/f1b6f745-d879-919f-4fff-c3873b2b14fd.png)

### 行番号の表示
「設定」の「Setting Editor」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1408655/043403fa-8aa9-1220-f010-c57f27adc9b6.png)

「JSON設定エディタ」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1408655/6877ae62-dfcc-b6ff-f2b8-b0df4f447d40.png)

サイドバーから「Notebbok」の設定項目を選択し、詳細設定エディタにて下記設定を追記します。
```json
"codeCellConfig": {
    "lineNumbers": true
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1408655/95adf670-0766-ee30-0404-0ac27c758fd1.png)

## さいごに
本記事の紹介は以上です。
参考になれば幸いです。
string型をint型に変換する時何が行われているか

例：文字列に含まれる数値（例えば "8402")を整数に変換する場合

1. 文字コードの読み取り
まず、コンピューターは "8402" という文字列が持つ各文字を
**文字コード（例えばASCIIやUTF-8）**として扱います。
文字列 "8402" は、以下のような4つの文字の列です。

    '8' → ASCIIコード 56
    '4' → ASCIIコード 52
    '0' → ASCIIコード 48
    '2' → ASCIIコード 50

　　
2. 文字の数値への変換
    次に、コンピューターは各文字のコードを数値に対応させる変換を行います。これを「文字列から数値へのマッピング」といいます。具体的には、'0' の文字コードが基準となります。
    '8' = 56 → 56 - 48 = 8
    '4' = 52 → 52 - 48 = 4
    '0' = 48 → 48 - 48 = 0
    '2' = 50 → 50 - 48 = 2
    　
3. 桁数の合わせ
文字列 "8402" は4桁なので、次に各数値を桁数に従って数値に直します。
具体的には、各数値を10のべき乗で拡張して足し合わせます。

8 × 10³ = 8000
4 × 10² = 400
0 × 10¹ = 0
2 × 10⁰ = 2

以上です
ご覧いただきありがとうございます。
指摘等はコメントでしていただけるとありがたいです。
Group Policy Settings Reference Spreadsheet のダウンロード先一覧

# 概要

Microsoftで英語とはなりますが、Group Policy Settings Reference Spreadsheet を配布しています。
本ファイルを比較確認すると、各OSのバージョンで含まれるポリシーを確認できます。

個々のバージョンごとでは引用されている情報が散見されますが、一覧としてまとめられた情報が見当たりませんでしたので確認できた範疇で今回まとめます。

# 一覧

**クライアント OS**

|OS|バージョン|リンク|
|:----|:----|:----|
|Windows 11|24H2|https://www.microsoft.com/en-us/download/details.aspx?id=106255|
|Windows 11|23H2|https://www.microsoft.com/en-us/download/details.aspx?id=105668|
|Windows 11|22H2|https://www.microsoft.com/en-us/download/details.aspx?id=104594|
|Windows 11|21H2|https://www.microsoft.com/en-us/download/details.aspx?id=103506|
|Windows 10|22H2|https://www.microsoft.com/en-us/download/details.aspx?id=104678|
|Windows 10|21H2|https://www.microsoft.com/en-us/download/details.aspx?id=103668|
|Windows 10|21H1|https://www.microsoft.com/en-us/download/details.aspx?id=103125|
|Windows 10|20H2|https://www.microsoft.com/en-us/download/details.aspx?id=102158|
|Windows 10|2004|https://www.microsoft.com/en-us/download/details.aspx?id=101451|
|Windows 10|1909|https://www.microsoft.com/en-us/download/details.aspx?id=101604|
|Windows 10|1903|不明|
|Windows 10|1809|https://www.microsoft.com/en-us/download/details.aspx?id=57464|
|Windows 10|1803|https://www.microsoft.com/en-us/download/details.aspx?id=56946|
|Windows 10|1709|不明|
|Windows 10|1703|不明|
|Windows 10|1607|https://www.microsoft.com/en-us/download/details.aspx?id=25250|
|Windows 10|1511|不明|
|Windows 10|1507|不明|

**サーバー OS**

|OS|リンク|
|:----|:----|
|Winodws server 2025|https://www.microsoft.com/en-us/download/details.aspx?id=106296|
|Winodws server 2022|https://www.microsoft.com/en-us/download/details.aspx?id=104005|
|Winodws server 2019|https://www.microsoft.com/en-us/download/details.aspx?id=57464|
|Winodws server 2016|https://www.microsoft.com/en-us/download/details.aspx?id=25250|

関連情報

* [Windows Server 2025で新規に導入されたポリシーの一覧 #WindowsServer - Qiita](https://qiita.com/valpasucucci43/items/d9be0bd9ef87700a4dce)
* [Windows 11 バージョン 24H2で新規に導入されたポリシーの一覧 #Windows11 - Qiita](https://qiita.com/valpasucucci43/private/33fc8c85a9182abc8472)
python if構文（自分用）

1.基本編
-
if構文はif、elif、elseで構成される。（elif、elseは省略可能）

```
#  変数aとbを比較し、結果をprint関数で表示する

a = 20
b = 10

if a==b:
    print("aとbは等しいです")
elif a>b:
    print("aはbより大きいです")
else:
    print("bはaより大きいです")

#  出力　⇒　aはbより大きいです
```

2.ネストも可能
-
あまり深くなりすぎるとコードの可読性が下がるので、おすすめしません。
（エクセル表関数やVBAを使いこなしている方がよくやりがちなパターン）

```
a = 50
b = 10
c = 30

#  aとbを比較し、その後ネストによりaとcを比較する（ネストする場合）
if a > b:
    print("aはbより大きい")
    if a > c:
        print("aは最も大きい")

#  出力　⇒　aはbより大きい
#  出力　⇒　aは最も大きい


#  aとbを比較し、その後ネストによりaとcを比較する（ネストしない場合）
if a > b > c:
    print("aは最も大きい")

#  出力 = ""
```
3.応用編（三項演算子）
-
直感的にわかりにくい感じるため個人的には好きではないものの、基本編と比較すると記述量が少ないため、必要に応じて活用したいところ。
三項演算子の記述イメージは以下のとおり

<strong>変数　= "ifの場合の処理"　ifの条件　else "elseの場合の処理"</strong>　

```
#  三項演算子によるif構文
a = 20
b = 10

result= "aはbより大きい" if a > b else "aはbより小さい"
print(result)

#  出力 = aはbより大きい
```

きっと他にも色んな書き方があるとは思うのが、一旦これぐらいにしておこう。
Python認定基礎試験　setに関するメモ

Pythonエンジニア認定基礎試験の勉強メモです📝
ここでは`set`について。
# setとは
集合を扱うデータ型で、要素を重複しないように保持する。
setに要素を追加するには `add()`メソッドが使用できるが、要素同士は順序を持たないため
要素を取り出す時も、決まった順序で取り出されることはない。
集合同士で、演算も可能。

# set()関数で定義できる
`set()関数`の引数はリストやタプルなどの反復可能体。
```python
# 引数: リスト
set_1 = set(['a', 'b', 'c', 'd'])

# 引数: タプル
set_2 = set((1, 2, 3, 4))
```


# 特定の要素を含むかどうかの判定
```python
sample_set = {'sample', 'keyword'}

print('keyword' in sample_set) # True
print('password' in sample_set) # False
```
この処理の時間計算量は`O(1)`になる。

# set同士の演算

### 和集合
a, bふたつのsetを対象としたとき、a, bいずれかもしくは両方に含まれる要素を求める。
```python
set_3 = {'apple', 'banana', 'peach'}
set_4 = {'orange', 'cherry', 'apple', 'banana'}

# 演算子で和集合を求める場合
union_1 = set_3 | set_4

# メソッドで和集合を求める場合
union_2 = set_3.union(set_4)

print(union_1) # {'apple', 'banana', 'peach', 'orange', 'cherry'}
print(union_2) # {'apple', 'banana', 'peach', 'orange', 'cherry'}
```

### 差集合
a, bふたつのsetを対象とした時、`a-b`なら、aにはあってbにはない要素を求める。
```python
set_5 = {'Tokyo', 'Osaka', 'Fukuoka'}
set_6 = {'Osaka', 'Fukuoka', 'Okinawa'}

# 演算子で差集合を求める場合
diff_1 = set_5 - set_6

# メソッドで差集合を求める場合
diff_2 = set_5.difference(set_6)

print(diff_1) # {'Tokyo'}
print(diff_2) # {'Tokyo'}
```

### 積集合
a, bふたつのsetを対象としたとき、どちらにも共通して含まれる要素を求める。
```python
set_7 = {'dog', 'cat', 'fox', 'deer'}
set_8 = {'fox', 'bird', 'deer', 'cow'}

# 演算子で積集合を求める場合
intersection_1 = set_7 & set_8 # {'fox', 'deer'}

# メソッドで積集合を求める場合
intersection_2 = set_7.intersection(set_8) # {'fox', 'deer'}
```

### 対称差
a, bふたつのsetを対象としたとき、どちらかにしか含まれない要素を求める
```python
set_9 = {'red', 'yellow', 'blue', 'green'}
set_10 = {'yellow', 'green', 'pink', 'blue'}

# 演算子で対称差を求める場合
symmetric_diff_1 = set_9 ^ set_10 # {'red', 'pink'}

# メソッドで対称差を求める場合
symmetric_diff_2 = set_9.symmetric_difference(set_10) # {'red', 'pink'}
Salesforce メールアラートの送信者について

# ワークフロールール、ワークフローアクション｜メールアラートで送信者は誰かをテスト

#### 今回の設定箇所：設定｜プロセスの自動化｜ワークフローアクション｜メールアラート
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894299/c38b75c7-3f1d-2995-175c-9c82b180ba9a.png)

全部３種類設定できる
1.現在のユーザーのメールアドレス
2.デフォルトのワークフローユーザー
3.組織のアドレス

### 差出人メールアドレス：現在のユーザーのメールアドレス
現在のユーザーのメールアドレスとは「最終更新者」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894299/62c052d5-61ec-2e81-4fa5-df6884a703ba.png)

更新者が変わるとメールアラートの送信者も変わります。

### デフォルトのワークフローユーザー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894299/fb334229-8448-59a5-1819-7d78a88b22eb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894299/49f3bcce-0511-e0e9-7e07-69663b9af1c8.png)

デフォルトのワークフローユーザーが送信者になります。

### 組織のアドレス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894299/50c69fce-edab-6adc-e699-34a2075ad974.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894299/f646698d-dce9-6fb6-1215-596c6b1a179e.png)

組織のアドレスが送信者になります。
paizaラーニング問題集「【部分和】部分和問題 4」を解いてみた

https://paiza.jp/works/mondai/dp_primer/dp_primer_partial_sums_boss

▼考え方

ポイントとなると思った考え方を、以下1.～4.に示します。

1.リストaの要素のうち、xを超える要素を排除したリストbを定義します。
a:[9,3,4,11,8]
b:[9,3,4,8]

2.リストbの各要素をxを超えない範囲で定数倍(1,2,...)し、リストcを定義します。
b:[9,3,4,8]
c:[9,3,6,9,4,8,8]

3.リストcを重複排除しリストeを定義します。
c:[9,3,6,9,4,8,8]
e:[9,3,6,4,8]

4.リストeに対し、部分和問題1の考え方と同様に処理を行います。

▼コード
```py
########## 処理0(準備) インプット,リスト定義など ###########

n,x = map(int,input().split())

a = [0]*n
for i in range(n):
    a[i] = int(input())

# 考え方1.
b = [i for i in a if i <= x]

# 考え方2.
c = []
j = 1
for i in range(len(b)):
    while a[i]*j <= x:
        c.append(a[i]*j)
        j += 1
    j = 1

# 考え方3.
d = set(c)
e = list(d)

########## 処理1 漸化式の定義、計算、出力 ##########

# 考え方4.
dp = [0]*(x+1)
dp[0] = 1

for i in range(1,len(e)+1):

    for j in range(x,e[i-1]-1,-1):
        if dp[j-e[i-1]] == 1:
            dp[j] = 1
            
if dp[x] == 1:
    print("yes")
else:
    print("no")
```
Python認定 基礎試験 タプルのメモ

Pythonエンジニア認定基礎試験勉強中のメモです📝
この記事はタプルについて。

# タプルとは
複数の値を扱うデータ型。
一般的に `('apple', 'banana', 'peach')`のようにカンマ区切りの要素を `()`囲む。
（※ 実際にはカンマで要素が区切られていればOKなので、()は省略できる）
一度定義されたタプルは、その後に要素の追加、削除、値の変更などはできない。
```python
tuple_1 = (1, 2, 3)

# 既に定義されたタプルを使って、新たにタプルを定義することは可能
tuple_2 = tuple_1 + (4, 5,)

print(tuple_1) # (1, 2, 3)
print(tuple_2) # (1, 2, 3, 4, 5)
```

## タプルの定義方法
```python
# カンマ区切りの要素を括弧で囲む
tuple_3 = ('dog', 'cat', 'mouse')

# ()を省略した形もある
tuple_4 = 'rice', 'bread', 'noodle'

# 要素が一つのときは末尾にカンマをつける
tuple_5 = 'Hokkaido', 

# tuple()関数を使用する
tuple_6 = tuple(['red', 'blue', 'yellow'])
```
【基本情報・応用情報】 ユーザビリティの評価方法について

# はじめに
ユーザビリティとは、物やサービスを使うときに、簡単で楽しく、ストレスなく使えることです。簡単に言うと、「使いやすさ」のことです。

例を出すと
- **学校の自動販売機**
良いユーザビリティ：ボタンが大きくて押しやすく、お金を入れる場所がわかりやすい。
悪いユーザビリティ：ボタンが小さすぎて押しにくく、どのボタンを押せばいいかわからない。
- **図書館の本の並び方**
良いユーザビリティ：本が題名のアイウエオ順に並んでいて、探しやすい。
悪いユーザビリティ：本がバラバラに置いてあって、欲しい本を見つけるのに時間がかかる。

---
では、そのユーザビリティをどのように評価するかの評価法について今日は紹介したいと思います！！

# ユーザビリティの評価法
- アンケート調査：利用者にアンケートを実施し評価する方法
- 回顧法：利用者にタスクを実行してもらい、専門家が行動を観察し、実行後にインタビューをして評価する方法
- インタビュー法：利用者と直接対話し、詳細な意見や感想を聞く方法
- 思考発話法：利用者が何を考えているかを話してもらいながら操作してもらう方法
- ヒューリスティック法：専門家が過去の経験則に基づいて評価する方法
- 認知的ウォークスルー法：専門家が利用者の立場に立って、タスクの各段階を評価する方法
- ユーザビリティテスト：被験者に実際に製品やサービスを使用してもらい、観察し問題点を洗い出す方法

## 分類分け
### 利用者の立場からの評価方法
- アンケート調査
- 回顧法
- インタビュー法
- 思考発話法
- ユーザビリティテスト

### 専門家の立場からの評価方法
- ヒューリスティック法
- 認知的ウォークスルー法

# おわり
多くの人に利用してもらうために、ユーザビリティを正しく評価し、改善していかなければなりません！
そのためにも評価法があることを覚えておきましょう！！
それではみなさんいいエンジニアライフを〜👋

# 基本情報・応用情報記事

https://qiita.com/bearl27/items/48ea517e5debbff3b2e9

https://qiita.com/bearl27/items/c08be5f2a53fd3fb7b53

https://qiita.com/bearl27/items/e63a6fb14eba0067d940

https://qiita.com/bearl27/items/f8cf339e7f966291683d

https://qiita.com/bearl27/items/849c9400ae93608331e7
R: Circularパッケージ、データの単位変換

Rのcircularパッケージで角度データを用いて、データの単位を変えたい。
例えば、radからdegである。

結論から言うと、conversion.circularを用いる（p.30, https://cran.r-project.org/web/packages/circular/circular.pdf）。

今、
```
data <- read.table("data_in_rad.txt")
datac <- circular(data, units = "rad")
```
とデータを読み込んでいるとする。
これをdegreeに変換したい時は、
```
conversion.circular(datac, units="degrees")
```
とすれば良い。細かなオプションはあるが、これはこの記事の範疇ではないので割愛する。オプションに関しては、上記のリンク先に記載されている。
【ChatGPT Canvas】ここまででわかったTips集


　どうも、カーブミラーです。

　今回は、ここまででわかった、Canvasを使用していて集まったTips集になります。

:::note info
本記事は、ChatGPT（有料版）
で行なっております。画像は
あります。　あしからず。
:::

　ニュースもないので、本題です。

　今回は、
　　ここまででわかった、
　　　Canvasを使用していて
　　　　集まったTips集になります。

　たいした数はありません😅

　まだ、みなさんも
　　試しているところかと
　　　思います。

　登場して、
　　まだ二日ですからね。

　それはともかく、
　　はじめましょうか。
***
　以下のTipsと注意があります。

　Tips集
　・Canvasの新規開始
　・Canvasの一時停止
　・Canvasの内容を書き出す

　注意
　・動作環境
　・数式
***
【Canvasの新規開始】

　WordやEditorのように
　　新規で開きたい場合があります。

　通常セッションで
　　下記Promptを
　　　送信してください。

```Text:Canvasを新規で開始するPrompt
Canvas開始
```

　これで新規ドキュメントとして
　　Canvasが開かれます。
![Screenshot_20241006-101031.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/fd9fb990-6f19-b9f5-5bff-ff89a4e0522e.png)

　これはまた、
　　Promptの最後に追記すれば
　　　結果がCanvasに書き込まれます。
***
【Canvasの一時停止】

　Canvasをやっていると
　　Canvasモードになっていて、
　　　ふつうのやり取りが
　　　　Canvasに反映されて
　　　　　しまいます。

　そこで、一時的に
　　モードを通常セッションに
　　　戻すのが、こちら。

　Canvas使用時に
　　通常セッションで、
　　　下記Promptを送信してください。

```Text:Canvasを一時停止するPrompt
Canvas終了
```
　これでウィンドウが閉じて
　　モードが通常セッションに
　　　なります。

　またCanvasを
　　はじめる際は、
　　　CanvasをタップすればOKです。
***
【Canvasの内容を書き出す】

　Canvasの内容は
　　通常セッションにはありません。
　　　見せているだけです。

　そして、
　　Canvasの内容を変更すれば、
　　　当然ながら、書き換わり、
　　　　あとから見返すには
　　　　　履歴をさかのぼる必要が
　　　　　　ありますよね。

　ですが、
　　その時点での内容を
　　　書き出しておけば、
　　　　あとからでも
　　　　　履歴をさかのぼらずに
　　　　　　確認できます。

　Canvas使用時に
　　通常セッションで、
　　　下記Promptを送信してください。
```Text:Canvas内容をセッションに出力Prompt
Canvasの内容をそのままCanvasを用いないで書き出して
```

[IT naviさんポスト](https://x.com/itnavi2022/status/1842529666747584873?t=y-KlX5zGF8_S9_uOfSceCg&s=19)

　IT naviさんが
　　これを用意したのは、
　　　チャットの共有で
　　　　Canvasの内容が
　　　　　相手に見せられなかった
　　　　　　からだそうです。

　通常セッションに出力すれば
　　共有しても見せられますね。
***
【注意】

　Canvasは
　　アプリでは動きません。
　　　Macのアプリもダメです。

　ブラウザでのみ
　　動きます。

　ただし、
　　スマホでは
　　　機能が限定されているようで、
　　　　ショートカット機能は
　　　　　使えませんでした。
　　　　　　私だけかも😅
***
【注意】

　Canvasは、
　　数式の表示には
　　　対応していません。

　Canvasは
　　Editorとしての機能なので
　　　そうした装飾機能は
　　　　ないのです。

　表示するのならば
　　通常セッションです。

[IT naviさんポスト](https://x.com/itnavi2022/status/1842543589169177069?t=OcVgNDZfSpmaoLSomdSwVA&s=19)
***

　とりあえず、
　　これだけです。

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。
E: Release file for http://archive.ubuntu.com/ubuntu/dists/focal-updates/InRelease is not valid yet (invalid for another 10h 25min 3s). Updates for this repository will not be applied.

## はじめに

phpが入っていなく、パッケージを更新しようとしたらエラーが発生した

　
実行コマンド
```
sudo apt update
```
　
## 本題

タイトルのように
```
E: Release file for http://archive.ubuntu.com/ubuntu/dists/focal-updates/InRelease is not valid yet (invalid for another 10h 25min 3s). Updates for this repository will not be applied.
```

エラーが発生した。
設定されている時間のずれが原因でエラーになる。
　
以下のコマンドで設定された時間を確認できる。
```
date
```
これで表示された時間とPC右下に表示されている時間があっているか確認する。
※自分の場合は10時間ほどずれていたので、すぐ気づいた。

　
### 以下の手順で直る。


#### 1.NTPを有効にして時刻を同期する
```
sudo timedatectl set-ntp true
```
#### 2.NTPが有効になっていることを確認する
```
timedatectl status
```
#### 3.ntpdateを使って即時時刻同期する
```
sudo apt install ntpdate
```
#### 4.NTPサーバーと時刻を同期する
```
sudo ntpdate ntp.ubuntu.com
```
#### 5.再度アップデータを試みる
```
sudo apt update
sudo apt upgrade
```
RAGの精度向上手法：Contextual Retrievalについて

最近の業務でRAGの精度向上に取り組む中、Anthropicの以下の記事に出会いました。この手法を今後試す予定ですので、皆さんにも共有したいと思います。


https://www.anthropic.com/news/contextual-retrieval

# 1. TF-IDF encodings：

この記事の中で、AnthropicはRAGの精度を向上するために2つの方法を紹介しています。その1つは、embeddingと並行してBM25（TF-IDF）を追加することで精度を高める方法です。

:::note info
BM25の特徴：
文書の長さと単語の使用頻度を考慮し、使用頻度が高い単語から結果を支配することを防いで、固有識別子や専門用語を見つける際に非常に効果的な手法
:::

処理の手順は以下の流れに変化します⇩

従来のRAG： chunking → embedding → topkを返す
ここのRAG： chunking → embedding       → rerank → topkを返す
　　　　　　　　　　　→ BM25（TF-IDF） →



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/b694a4e1-97e0-de78-01db-f3df56dd5819.png)


 # 2. Contextual Retrieval：
Contextual Retrievalとは説明コンテキストをchunkに追加することでoutput生成精度を高める手法です。


処理流れは以下となります。

①文書全体とチャンクをプロンプトで渡して、説明コンテキストを生成させる

②コストが課題になるが、Prompt Cachingを活用することでコストを抑えることができる


実際anthropicが使われたContextual Retrievalのprompt⇩：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/16f6ba8f-c883-bb5b-997b-a4f94e265898.png)

この手法の課題は、すべてのチャンクに対して文書全体を用いて説明コンテキストを生成するため、コストが高くなることです。対策として、上記②のPrompt Cachingを活用し、文書全体を保存した上で、新規追加部分のみを処理する方法が考えています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/074d60f3-187c-a8ed-dc15-a8dea032e243.png)

anthropicが定義したprompt caching⇩

https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching



# 3. 評価結果とチュートリアル

評価結果は以下のグラフの通りで、これを見る限り非常に高い効果が得られているようです。（5.7⇒3.7）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/5be6383a-f8db-edc1-084a-157b1c6f9b12.png)


ちなみに、LangChainのgithubで簡単なチュートリアルコードも見つけました。興味ある方試してみてください：

https://github.com/sugarforever/LangChain-Tutorials/blob/main/langchain_anthropic_contextual_retrieval.ipynb
独学でpythonを始めて挫折した話（自分用）

きっかけ
-
初めまして。
私は大企業で働く非エンジニアです。（IT企業ではない）
この記事では下記のついてまとめています
（自分の頭の中の整理をするためのアウトプット）

1.なぜpythonを始めたのか
2.すぐに挫折する
3.転機と学習再開まで
4.挫折した原因を考える
5.アウトプットする習慣を作る
6.今後の活動

1.なぜpythonを始めたのか
-
私は株式投資を行っており、各銘柄の信用倍率、貸借状況の各指標をチェックしていました。
正直、これが面倒だなって思ってた時にyoutubeで<strong>「pythonで自動化」</strong>みたいな動画を見て、「これやってみよう！」と思い立ち、pythonについて調べ始める。

2.すぐに挫折する
-
2021年1月
当時VBAを少しかじったことがある程度の知識しかなかったが、なんとかなるだろうと軽い気持ちでpythonに関する書籍の口コミを調べる。⇒<a href="https://www.amazon.co.jp/Python-1%E5%B9%B4%E7%94%9F-%E4%BD%93%E9%A8%93%E3%81%97%E3%81%A6%E3%82%8F%E3%81%8B%E3%82%8B%EF%BC%81%E4%BC%9A%E8%A9%B1%E3%81%A7%E3%81%BE%E3%81%AA%E3%81%B9%E3%82%8B%EF%BC%81%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AE%E3%81%97%E3%81%8F%E3%81%BF-%E6%A3%AE-%E5%B7%A7%E5%B0%9A/dp/4798153192" >最初に選んだ一冊</a>
軽い気持ちで読み始めたものの、環境構築？インタープリタ言語？pip?・・・なにそれ？

3.転機と学習再開まで
-
2024年8月
会社では新規事業開発に関わる部署に異動する。日々新しい技術に触れる機会が多く、DXによる事業創出も理念に含まれている。
自分で１からシステムを開発することはないだろうが、基礎知識があるに越したことはない。
生成AIによるコーディングも可能である今、改めて学習する絶好の機会ではないだろうか？
（わからなければGPTにとりあえず聞けばいい）

4.挫折した原因を考える
-
改めて当初学習を始めた際に、なぜ挫折したかを考えた。
考えられることはいくつかあるものの、大きくは以下のポイントだと思われる

①いきなり難しいことをやろうとしたこと
②実現したいことを言語化する力が弱いこと（事業開発でも必要な力）
②アウトプットが下手くそであること（致命的）

5.アウトプットする習慣を作る
-
インプットばかりしていても3日も経てば忘れてしまうし、他の人の書いたコードを写経しても全く頭に入ってこない。
プログラミングにしても事業開発にしても作りたいものを言語化し、アウトプットする必要がある。
プログラミングはあくまで手段でしかない。
それを念頭に改めて学び直すことにした。

6.今後の活動
-

基本的な文法や気付きを投稿し、自分用の理解を深めるツールとしてこの場を活用したい。
ローカルでのgit認証切替

## ローカルでのgit認証切替

```dosbatch
·切替
cmdkey /delete:git:https://xx.xx.xx.xx:yy
cmdkey /generic:LegacyGeneric:target=git:https://xx.xx.xx.xx:yy /user:{username} /pass:"{password}"

·確認
cmdkey /list
```
【Git覚書き】マージした時にコミットが作成される場合と作成されない場合の違い

# 初めに
普段は Git を使って開発をしていますが、マージする際に「コミットが作成される場合」と「作成されない場合」があり、その違いをあまり理解できていませんでした。この機会に、マージコミットについて整理し、まとめてみたいと思います。


# マージ時にコミットが作成される場合とされない場合の違い
ブランチをマージした時、以下のようなコミット履歴が作成されている時、ありますよね。
`Merge remote-tracking branch 'origin/testBranch2' into testBranch`
このコミットは、**マージコミット**と呼ばれ、通常のコミットとは少し異なるコミットです。


# マージコミットとは
マージコミットとは、**複数のコミットをまとめるためのコミット**のことです。
詳しく説明していきます。

## 前提：コミットは親コミットのポインターを持っている
各コミットは、**一つ前のコミット（親コミット）のコミットIDを持っています**。

以下の図で言うと、B は A のコミット ID を持っており、C は B のコミット ID を持っています。
```sh
A --- B --- C 
```

gitツリーのようなグラフは各コミットの親コミットIDを元に作成されます。

```sh
A --- B --- C --- D 
       \
        E --- F 
```

※そういう意味では、ブランチとは単なるコミットの連なりをそう呼んでいるだけと言えますね。

このあたりの知識は、以下の記事がとてもわかりやすかったです。
ありがとうございました！

https://qiita.com/jesus_isao/items/2a0495c973a4c911c2cc

## マージコミットには複数の親コミットがある
本題です。
マージコミットとは、**複数の親コミットを持つコミット**のことです。

例えば、以下のようなブランチがあるとします。

```sh
A --- B --- C --- D (main)
     \
       E --- F (feature)
```

このfeatureブランチをmainブランチにマージすると、以下のようなグラフになります。
```sh
A --- B --- C --- D --- M (main)
       \               /
        E --- F (feature)

```

コミットMの親コミットはDとFの二つ。
このように**複数のコミットを持つコミットのことをマージコミット**と呼びます。

# マージコミットが発生する条件
前述の通り、マージ時に必ずマージコミットが発生するというわけではありません。

## マージに大きく分けて二種類の方法がある
マージには大きく分けて二つの方法があります。
**Fast-forward**と**Non-Fast-forward**の二種類です。
どちらのマージ方法が選択されるかは`git merge`コマンド実行時に内部で判断されます。

### Fast-forward（マージコミット発生しない）
マージコミットが作成されないシンプルなマージ方法です。

以下の条件で選択されます。
* マージ先ブランチの先端がマージ元ブランチの先祖コミットに当たる
* マージ元ブランチが切られてから、マージ先ブランチに変更がない


以下のようなイメージ。
```sh: マージ前
A --- B (main)
       \
        E --- F (feature)
```

マージすると以下のようになります。
形は変わっていますが、実際には `main` ブランチの先端が B から F に移動しただけです。
```sh: マージ後
A --- B --- E --- F (main, feature)
```


### Non-Fast-forward（マージコミット発生する）
マージコミットが作成されるマージ方法です。
Fast-forwardの条件に当てはまらない場合に選択されます。

以下のようなイメージ
```sh
A --- B --- C --- D (main)
     \
       E --- F (feature)
```

このfeatureブランチをmainブランチにマージすると、以下のようなグラフになり、マージコミットMが作成されます。
```sh
A --- B --- C --- D --- M (main)
       \               /
        E --- F (feature)
```

:::note info
Fast-forward マージが適用される場合でも、--no-ff オプションを使用することで、意図的にマージコミットを作成することができます。
```sh
git merge --no-ff featureBranch
```
:::


Fast-forwardマージ周りについては以下の記事が分かりやすかったです。
ありがとうございました！

https://qiita.com/bibouroku/items/98bd8eda402bfa1e9472


# 終わりに
マージコミットが発生しないのはシンプルでよいですが、マージ履歴を残すという意味ではマージコミットがあるのはメリットとして大きそうですね。使い分けが大事だと思いました。

# 参考
https://qiita.com/jesus_isao/items/2a0495c973a4c911c2cc
YAMLの型に着目した命名規則

# はじめに
yamlの「独自定義」可能な個所の命名規則を考えました。

## 記載の前提
記述する機会の多い
`Paths Object`と`Components Object`を対象にしています。

命名規則は、
**コンポーネントのtype（型）単位**と
**parameters、requestBody、responsesのコンポーネント単位**
が想定さるが、
ここでは**コンポーネントのtype（型）単位**で考えています。

## TIPS
特殊なのは、`Paths Object`の
`url`（エンドポイント名）と`parameters`の`in`（パラメータの場所）だけで、
他は基本的に、コンポーネントの`type`（型）で考えることが可能です。

# 命名規則

## エンドポイントとパラメータの記載仕様

| 大分類       | 中分類       | 記載仕様       | 設定例               |
|--------------|--------------|----------------|----------------------|
| url          | -            | lowercase      | `/user/name`         |
| parameters   | `in`がheader | kebab-case     | `user-name`          |
|              | `in`がquery  | snake_case     | `user_name`          |
|              | `in`がpath   | snake_case     | `user_name`          |
|              | `in`がcookie | snake_case     | `user_session`       |

## コンポーネントの記載仕様

| 型           | 記載仕様       | 設定例               |
|--------------|----------------|----------------------|
| Object型     | PascalCase     | `AccountNumber`      |
| string型     | camelCase      | `accountNumber`      |
| number型     | camelCase      | `accountNumber`      |
| boolean型    | camelCase      | `isActive`           |
| array型      | camelCase      | `userList`           |

## 記載仕様の説明

- **lowercase**: すべての文字を小文字で記述
  - 例: `user`, `account`
- **snake_case**: 単語をアンダースコア（_）で区切りにして小文字で記述
  - 例: `user_name`, `account_number`
- **kebab-case**: 単語をハイフン（-）で区切りにして小文字で記述
  - 例: `user-name`, `account-number`
- **PascalCase**: 各単語の最初の文字を大文字にして単語を連結
  - 例: `UserName`, `AccountNumber`
- **camelCase**: 先頭の文字を小文字にして以降の単語の先頭を大文字にして連結
  - 例: `userName`, `accountNumber`
自分の市場価値を知りたいバックエンドエンジニアの転職体験談

こちらの記事は、[転職ドラフト体験談投稿キャンペーン](https://job-draft.jp/articles/251)に参加しています。

## 登録したきっかけ
私はバックエンドを得意とするフルスタックエンジニアでした。エンジニアとしての強みを発揮して、キャリアアップや年収アップを図ることが今回の転職理由です。
さらに、これまでの経験を踏まえて、より身近な社会貢献性の高い事業ドメインに挑戦したいという気持ちが強くなり、自社開発のWeb系企業での転職が必須条件となりました。
また、これまで通りフルリモートで働ける環境を希望し、出社の必要がない場合はリモートを選択できる柔軟な働き方を重視していました。

そうした転職の軸から、転職ドラフトに登録することを決意しました。

## どんな指名を受けてどのように受け止めたか

転職ドラフトでは、自分のスキルに応じて指名を受けられるという点が大変魅力的でした。特にWeb系の自社開発企業が多く、私の得意とするバックエンドの経験言語との親和性が高い企業から多くの指名を受けました。多くの企業が即戦力を求めている様子で、自分のこれまでの経験を高く評価してもらえたのは非常に嬉しかったです。

実際に指名を受けた企業の中には、年収アップを提示してくれるところもあり、これまで自分のスキルが市場でどの程度評価されているのかを知る良い機会となりました。また、自分が思っていたよりも高い評価を受けたことで自信がつきました。

## 面談や面接への準備と期待

面談や面接については、以下のポイントに注目して臨むようにしました。

- **キャリア目標の確認**  
  面談や面接は単なる企業との会話ではなく、キャリア目標を達成できる環境かを知る機会と捉えていました


- **企業とのフィット感**  
  働き方や経験をどう活かせるかを質問し、企業とのフィット感を重視しました

面談や面接を通じて、企業側が求めているスキルや役割を深掘りし、転職後の貢献イメージを持つようになりました。

## 参加前の予想と異なったことや印象的だったこと
転職ドラフトに参加する前は、自分が本当に指名をもらえるのか心配でした。しかし、実際に参加してみると、思っていた以上に多くの指名を受け、特に年収面で高い評価を受けたことが印象的でした。これにより、自信を持って次のステップに進むことができました。

また、転職活動を通じて、指名を受けるだけでなく、自分自身のキャリアを再評価する良い機会となりました。自分のスキルセットが業界でどのように評価されているのかを知ることができた点は、非常に大きな収穫です。

## 転職で実現できたこと

結果、以下の目標を達成しました。

- **年収アップ**  
  これまでのキャリアを反映した納得感のある年収水準で内定をもらえました

- **事業ドメイン**  
  社会貢献性の高い事業ドメインで、より興味の持てる業界に移ることができました

- **働き方**  
  一方で、働き方はある程度妥協しました。会社の文化としての出社意義を感じられたため、フルリモートではないですが妥協しました

## これから参加する方へのメッセージ

転職ドラフトで転職成功するためには、以下のポイントが重要だと思います。

- **自分のスキルと経験を適切に言語化する**  

- **面接は自分の現在地を確認するための重要な機会と捉える**  

## まとめ
転職ドラフトは、私のように現年収が自分のスキルに見合っていないと感じている方におすすめです。
自分のスキルと経験を適切に言語化することで、納得感のある年収の指名を受けることができます。
実際に指名を受けるまでにはある程度言語化ができている状態で、それを元に面接で話せば良いので、より効果的に転職活動を行うことができました。
ダッシュボードで指標を切り替える方法

## 背景
ダッシュボード上でグラフを切り替えたいときの簡単な方法の備忘録
完成イメージは以下の画像。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/786947/0d76ba30-24b5-8728-f651-1eb4c881660a.png)

TableauPublicでも公開中
https://public.tableau.com/views/_17281806515340/1?:language=ja-JP&publish=yes&:sid=&:redirect=auth&:display_count=n&:origin=viz_share_link

## 方法
### パラメーター作成
切り替えたい指標の数だけ設定する
表示名は切り替えたい指標の名前をつける。表示名がそのまま、ダッシュボード上でも表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/786947/d5238737-a6ac-743b-877c-0b07cf745bce.png)

計算フィールドでパラメータの表示名に合わせて、計算フィールド名を作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/786947/55b00d76-8a93-89b3-b33e-7f8e18962eb8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/786947/53269721-0ef7-a068-9a41-5cbf27382025.png)

ダッシュボードに移動して、同じコンテナ内に切り替えたいグラフをすべていれる。

グラフをクリックして、「値を使用して表示状態を制御する」にチェックを入れ、グラフに合わせて選択する。ここには計算フィールドで作成したフィールドが表示されている。
これを全てのグラフに行う

パラメーターを表示して切り替えてみる
うまく切り替われば完成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/786947/914b3c67-a789-a020-a469-d23100b4d2e2.png)
動画URL化共有ツール開発と設計思想と利用サービスの詳細

# 動画URL化共有ツール
まずは動くモノが大事ということで、今回開発した動画URL化共有ツールはこちらとなります。

[動画URL化サービス あげる（ベータ）](https://completetools.net/)

ファイルをアップロールするだけで、動画をURL化し、7日間のみ有効な動画リンクを生成します。
利用者は、リンクを共有するだけで簡単に大容量の動画を共有することができるようになります。

# 設計思想
今回のシステム設計と開発では特に以下の点を重視して進めました。

- シンプル
- 低コスト
- ホワイトボックス
- 日本国内運営
それぞれのポイントについて、具体的に説明していきます。

## シンプルな設計
システム設計において最も重視したのは、ユーザにとって使いやすく、直感的に利用できることです。多くの動画共有プラットフォームでは、再生プレイヤーや多機能な動画編集機能が実装されていますが、それがかえって複雑さを増し、使いにくさにつながることもあります。

今回のシステムでは、動画のアップロードから共有までのステップを可能な限りシンプルにし、初心者でも迷うことなく利用できる設計を目指しました。動画を選択し、アップロードボタンを押すだけでURLが生成され、それを共有するだけで完結するプロセスを構築しています。余計な機能や煩雑な操作は排除し、基本的な操作感を追求しました。


## 低コスト
動画共有サービスを運営する際には、どうしてもサーバーやネットワークの運用コストがかかります。今回の開発では、できるだけ運営費用を低コストに抑えることを目指しました。特に、サーバー維持費やストレージコストが高額になるのを防ぐため、柔軟にスケールできるクラウドストレージサービスを採用しました。

具体的には、コスト削減を実現するために、以下のポイントに注力しました。

- VPSとクラウドストレージの併用: 安価なVPNとストレージコストを最低限に抑えるために、Wasabiのようなコスト効率の良いサービスを併用しました。
- CDN活用:CloudflareのCDNを活用して、サーバー負荷を分散し、トラフィックピークにも対応可能にしまいた。

### ホワイトボックス
今回のシステムは、極力フレームワークに依存せず、開発者がその挙動や動作原理をすべて理解できる形で設計しています。ブラックボックス化された部分を極力排除し、透明性の高い設計にこだわりました。

また設計等についても、こういった技術記事で極力発信していく予定です。

## 日本国内運営
動画共有やファイル共有サービスでは、データが海外に送信されることが一般的です。しかし、プライバシーの観点から、日本国内でのデータ処理を行うようにしました。各VPSやクラウドストレージのリージョンは日本を選択しており、ユーザーのデータが国外に送られることなく、日本国内のデータセンターで安全に保管されることで、安心して利用していただける環境を提供します。


# 技術的詳細
## 利用サービス
今回のシステムでは、以下の主要なサービスを利用しています。

- WebARENA: 日本国内のデータセンターを活用し、データの国内処理を実現しています。
- Cloudflare: 高速なCDNとDDoS対策を提供し、安定したサービス運営をサポートしています。
- Wasabi: 高コストパフォーマンスのクラウドストレージサービスで、低コストな運用を可能にしています。

## 設計詳細
上記のサービスを活用して、以下のようなシステム構成を実現しました。

- フロントエンド: ユーザーが簡単に動画をアップロードし、URLを取得できるシンプルなUIを設計。ReactやVue.jsのようなフレームワークは利用せず、Bootstrapと純粋なHTMLとJavaScriptで構築しました。
- バックエンド: 動画のアップロード、ストレージへの保存、URL生成を担当。WebARENAのサーバーを使用し、Flaskを利用して構築しました。
- ストレージ: Wasabiを利用し、大容量の動画ファイルを低コストで安全に保管。


以上が今回のシステム設計の概要です。今後さらに改良を重ねて、使いやすさと持続可能性を両立したシステムを提供していきます。

もう少し詳細な技術的な話は、追って記事化する予定です。

まだサービススタートしたばかりなので、追って様々な開発をしていく予定です。

#  宣伝
ぜひ、使ってください！
[動画URL化サービス あげる（ベータ）](https://completetools.net/)
AtCoder Beginner Contest 374 振り返り

ABC374の振り返りです。

## 結果

A,B,Cの2完でした。

![スクリーンショット 2024-10-06 10.26.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167729/3c75eb6a-b791-3179-89c0-d63857e4d060.png)

![スクリーンショット 2024-10-06 10.29.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167729/b5540244-91a1-fe3e-0d03-792986a6fe4e.png)

## 解説

### A問題

- 問題
  - https://atcoder.jp/contests/abc374/tasks/abc374_a
- 回答
  - https://atcoder.jp/contests/abc374/submissions/58442455

`isSuffixOf`使います

```haskell
main :: IO ()
main = do
  s <- getLine

  putStrLn $ if "san" `isSuffixOf` s then "Yes" else "No"
```

### B問題

- 問題
  - https://atcoder.jp/contests/abc374/tasks/abc374_b
- 回答
  - https://atcoder.jp/contests/abc374/submissions/58455909

再帰で解きます

```haskell
main :: IO ()
main = do
  s <- zip [1 ..] <$> getLine
  t <- zip [1 ..] <$> getLine

  print $ if s == t then 0 else solve s t
  
solve :: Eq a1 => [(a2, a1)] -> [(a2, a1)] -> a2
solve [] ((ti, tc) : _) = ti
solve ((si, sc) : _) [] = si
solve ((si, sc) : st) ((ti, tc) : tt)
  | sc /= tc = si
  | sc == tc = solve st tt
  | otherwise = error "invalid pattarn"
```

### C問題

- 問題
  - https://atcoder.jp/contests/abc374/tasks/abc374_c
- 回答
  - https://atcoder.jp/contests/abc374/submissions/58476117

`2≤N≤20`の制約から、全探索でできると判断できます。
`subsequences`で1つのグループのパターンを全て洗い出し、それぞれのパターンのグループの合計人数を計算します。

合計人数の半分を計算して、それを超える内の最小値を求めれば解けます。

`部署に所属する人数の合計 のうち大きい方の値としてあり得る最小の値を求めてください。`の制約から、半分の値を計算するときに繰り上げないといけないのですが、これを忘れて1ペナになりました

```haskell
main :: IO ()
main = do
  n <- readLn @Int
  ks <- getInts

  let kss' = subsequences ks
      v = (fromIntegral (sum ks) :: Double) `ceilDiv` 2

  print $ minimum [sk | ks' <- kss', let sk = sum ks', sk >= v]
```

### D問題(upsolved)

- 問題
  - https://atcoder.jp/contests/abc374/tasks/abc374_d
- 回答
  - https://atcoder.jp/contests/abc374/submissions/58493647

`1≤N≤6`の制約から、これも全探索でできると判断できます。
Ai-Bi, Ci-Di間は逆方向のパターンも考慮しないといけないですが、現在位置を持たせて、これも全パターン計算すれば解くことができます。
(回答は https://atcoder.jp/contests/abc374/submissions/58484229 を参考にしました。)

```haskell
main :: IO ()
main = do
  [n, s, t] <- getInts
  abcds <- replicateM n do
    [a, b, c, d] <- getInts
    return ((a, b), (c, d))

  let abcds' = permutations abcds

  print $ minimum [solve edges s t | edges <- abcds']

solve :: [((Int, Int), (Int, Int))] -> Int -> Int -> Double
solve edges s t = go edges (0, 0) 0.0
  where
    go :: [((Int, Int), (Int, Int))] -> (Int, Int) -> Double -> Double
    go [] _ len = len
    go (((a, b), (c, d)) : et) (x, y) len =
      let td = sqrt (fromIntegral ((a - c) ^ 2 + (b - d) ^ 2)) / fromIntegral t :: Double
          sd1 = sqrt (fromIntegral ((x - a) ^ 2 + (y - b) ^ 2)) / fromIntegral s :: Double
          res1 = go et (c, d) (len + sd1 + td)

          sd2 = sqrt (fromIntegral ((x - c) ^ 2 + (y - d) ^ 2)) / fromIntegral s :: Double
          res2 = go et (a, b) (len + sd2 + td)
       in min res1 res2
```

## 全体を振り返って

前回に続いて、今回も簡単めだった印象でした。Dは頑張ればとけたかなあ
また次回も頑張ります！
Eclipseの使い方をまとめたみた【基本】

#### main メソッドを挿入

- main　と入力して　Ctrl + スペース

#### main コードの文字の大きさ調整

- Ctrl + or -

- ウインドウ→ 設定→ 一般→ 外観→ 色とフォント→ 基本→ テキスト・フォント→ 編集

#### インデントを揃える

- Ctrl + Shift + F


#### 変数を一度に変換

- 変数を範囲選択→ 右クリック→ リファクタリング→ 名前変更→ 変数名を入力→ Enter


#### System.out.println(); を記述する時

- syso と入力して Ctrl + Space

#### 実行

- ファイルかコードの上で右クリック→　実行
- Ctrl + F11

#### クラスやメソッドが記述されている場所に移動

- Ctrl キー押しながらクラス名やメソッド名をクリック→ 実装を開く

#### try catchを記述する

- コードを行ごと選択→ 右クリック→ 囲む→ try/catch ブロック

#### コンソールの中身をクリア

- コンソール上で右クリック→ クリア

#### コンストラクタや getter/setter, toString()自動生成

- 挿入したい所にカーソルを置く→ 右クリック→ ソースを選択し下記のいずれかを行う

① getter及びsetterの生成
② フィールドを使用してコンストラクタを生成
③ toString()生成




## 参考サイト
[Eclipse（Java）【初心者必見！】まずは覚えておきたい使い方](https://www.youtube.com/watch?v=sdZ2vT5uc44)
[]()
Fedora 40にPowerShell(pwsh)をインストールする

# はじめに

Fedora 40にPowerShell(pwsh)をインストールしました。そのときにメモです。

インストールの流れとしましては、dnfを使用してdotnetをインストールします。

そのあと、dotnetからPowerShellをインストールしました。

# dotnetのインストール

こちらはdnfからインストールしました。ここで少しつまったことがありまして、dotnet runtimeのバージョンが8.0をインストールする必要があったことでした。

```sh
sudo dnf install dotnet dotnet-runtime-8.0 dotnet-sdk-8.0
```

~/.bash_profileを編集します。

```sh
# dotnet
export DOTNET_ROOT=/usr/lib64/dotnet
export PATH=$PATH:$DOTNET_ROOT
export PATH=$PATH:$DOTNET_ROOT/tools
export PATH=$PATH:$DOTNET_ROOT/tools/sdk
```

bashにて、which dotnetと入力したときに、dotnetがインストールされているパスが表示されますと成功となります。

# PowerShell(pwsh)のインストール

dotnetより、PowerShellをインストールします。

```sh
dotnet tool install --global PowerShell
```

which pwshとして、インストールされているパスが表示されますと成功となります。

# PowerShell(pswh)の起動

bashにて以下のコマンドより実行します。

```sh
pwsh
```
AWS Skill Builderの日本語化

# 1. はじめに

AWS資格の学習方法について調べていると、AWS Skill Builder にたどり着く方がいるかと思います。しかし、記事は英語、無料動画も英語で、英語の学習からかと諦めかけていましたが、日本語化する方法を見つけましたので、共有します。

AWSの画面UIが変わった為か、日本語化する最新方法が見つけづらいというのもあります。

ちなみに、この記事は、2024/10/06 に自分で日本語化しました。UI変更があったら、この記事も更新するぞっと、今は思っています。

# 2. AWS Skill Builder日本語化

画面右上の Site Menu を開きます。左上の記事が多く見かけますが、2024/10/06現在は右上です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3195108/708f8dd6-1c1a-abd8-3ca4-99f203ff79fc.png)

My Account をクリックします。

画面左のPreferencesをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3195108/be74af36-50fc-9e78-96ec-50b67efe4e5c.png)

Languagesを日本語に変更して、SAVE CHANGESをクリックします。

CONFIRMをクリックします。

日本語化されました。メニューの場所が右上に変わりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3195108/d8e4567e-b948-a43c-f3ff-67db8e7997f0.png)

いつも、AWS学習し始めようと思った段階で挫折しますが、少しでも助けになればと思い記事にしました。
Webアプリを作成して公開したい #3

続きです。

ローカルで変更した内容をGithubに上げて、変更をデプロイしてみました。

その前に、以下を修正しました。
>Spring Initializrを使用しているので
設置したディレクトリ階層が一段下になっています。
これが必要かどうかわかりませんがデプロイしたいので
Root Directoryにルートを一段下に指定して保存しました。

ダウンロードした圧縮ファイルをそのままworkspaceに展開して利用していたので
階層が変になっていました。
これを作成しなおして不要な階層を削除しました。

プロジェクトを作成しなおす際にJavaを21に設定してしまったのですが
Java21はサポート外だったのか、ローカルでは問題がなかったものの
Railway.appでビルドを行う際に以下のエラーが発生しました。

:::note alert
[エラー] プロジェクト ywm で目標 org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile (default-compile) を実行できませんでした: コンパイル中に致命的なエラーが発生しました: エラー: リリース バージョン 21 はサポートされていません -> [ヘルプ 1]
:::

eclipse上でもぞもぞしてバージョンダウンを試みたものの
うまくいかずに難航しました。
なんとかpom.xmlを修正してeclipseから修正をコミットしました。

eclipseでGithubに接続する方法は以下を参考にしました。

https://qiita.com/programiblis/items/92835473a53794eaa951

途中、プッシュする際に認証が弾かれてしまったのですが
以下に沿ってトークンを発行して解消しました。

https://qiita.com/startPG/items/9566827d0901cd847317

無事コミットされた後は、自動的にデプロイまで完了していました。
（和訳かけているのでメニュー名が変ですがご容赦ください。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/5b829961-40dc-2c3e-a81a-efff7859360b.png)

コミットしたら自動的にデプロイされるのは便利ですね。
ローカルでのテストをしっかりしてからコミットしないと
まずいことになりそうですが。

次は環境変数にDBの接続情報を設定して、
環境毎にDB接続していきたいと思います。

まずローカルでDB接続を行いたいので
MySQLをインストールします。
MySQLにした理由としてはRailway.appデサポートしていたからです。

インストール手順はこちらを参考にしました。

https://qiita.com/taidong5588/items/434495a42ae07f27022c

環境変数を設定した後に起動してみようと思いましたが
以下のようにエラーが出ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/e03d3013-ab85-2264-a379-743b44eb6b1a.png)

なぜ？と思いましたが権限がないことが原因だったみたいです。

https://mofuken.blogspot.com/2014/07/windows-5.html

コマンドプロンプトを「管理者として実行」で実行したところ
MySQLサービスが起動しました。

起動状況はサービスから確認できるそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/9e10259b-c012-9049-cdc7-72885be9031d.png)

「実行中」となっているので起動していますね。

その後はスタートメニューから「MySQL Command Line Client」を探し、クリックして起動。
パスワードを求められたら、インストール時に設定したPasswordを入力して接続。
「mysql > 」と出てこれば接続成功です。

まず、既存のDBを確認します。
```
SHOW databases;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/7e1b1b42-01e4-3e0e-d7bb-d355aafdaedc.png)

DBの作成
```
CREATE DATABASE 作成したいDB名;
```
「SHOW databases;」で再度確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/876f90e8-4de9-e3b8-9b5d-f293af17d97c.png)

あとはテーブル作成...ですがこのままだと使いにくいので（私だけ？）
使い慣れているA5SQLをインストールしてローカルで作成したDBを参照してみます。

インストーラーは以下の公式サイトからダウンロード

https://a5m2.mmatsubara.com/

特別なことはなく手順に沿って進めていきます。
デフォルトのワークスペースの指定を促されますが
特に指定せずそのままにしました。支障ないと思うので。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/8f4ca625-c80b-0dc6-afb5-142deb234397.png)

「ユーザーID」はrootで大丈夫です。
（インストール時にAdd Userしていればそのユーザも使用できるはずですが。）
「パスワード」はインストール時に設定したPassword、
「データベース」には先ほど作成したDBの名前を指定します。

「テスト接続」で接続成功となれば準備OKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3901612/2b08893d-a433-cb97-1ec8-837eb5889f5c.png)

次回はアプリとDBを繋ぎます。
簡単にまずログイン画面を作成できたらなと思います。

では。
JavaScriptの配列メソッドを復習する

### JavaScriptの配列のメソッドを復習する

JavaScriptおよびTypeScriptをそれなりに触って1年以上になりますが、以下のようなコードを見て、一瞬「？？」となったので、備忘録兼ねて解説していきます。

まずは、おなじみの書き方↓
``` JavaScript
const people = [
  { name: 'Taro', age: 20 },
  { name: 'Jiro', age: 25 },
  { name: 'Ichiro', age: 30 },
];
const names = people.map(person => person.name);
console.log(names);
//  ["Taro", "Jiro", "Ichiro"]
```

一瞬理解できなかった書き方↓
``` JavaScript
const people = [
  { name: 'Taro', age: 20 },
  { name: 'Jiro', age: 25 },
  { name: 'Ichiro', age: 30 },
];
const names = people.map(({ name }) => name); // ここです
console.log(names);
//  ["Taro", "Jiro", "Ichiro"]
```


オブジェクトから成る配列より任意のプロパティだけを取り出す時によく使うmapですが、このコールバック関数の引数の部分で分割代入を使用しています。
mapの場合、内部で自動的にコールバック関数に引数が代入されてループするため、代入元が可視化されないため一瞬理解に苦しみました。そこで以下のようなコードを書いて整理します。

↓まずは、単にオブジェクトを引数で受けて、その中のnameプロパティを出力するだけ。

```JavaScript
const printName = obj => {
  console.log(obj.name);
};
const person = { name: 'Taro', age: 20 };
printName(person); // Taro

```

↓次に、printName内で、分割代入をするパターン
```JavaScript
const printName = obj => {
  const { name } = obj; // ここで分割代入をする
  console.log(name);
};
const person = { name: 'Taro', age: 20 };
printName(person); // Taro
```

↓最後に、引数を受ける段階で分割代入によりnameだけを抽出してしまうパターン
```JavaScript
const printName = ({ name }) => { // ←いきなり分割代入してしまう
  console.log(name);
};
const person = { name: 'Taro', age: 20 };
printName(person); // Taro
```

つまり、
**渡す側 → { name: 'Taro', age: 20 }というオブジェクトごと渡す**
**受け取る側 → オブジェクトをもらうが、もらった瞬間にnameだけを抜き取り、後は無視する**
このようになっているわけですね。

で、先程のmapに話を戻すと、

```JavaScript
const people = [
  { name: 'Taro', age: 20 },
  { name: 'Jiro', age: 25 },
  { name: 'Ichiro', age: 30 },
];
const names = people.map(({ name }) => name); // ここです
console.log(names);
//  ["Taro", "Jiro", "Ichiro"]
```
ループで、コールバック関数が、
{ name: 'Taro', age: 20 },
{ name: 'Jiro', age: 25 },
{ name: 'Ichiro', age: 30 },
と、オブジェクトを受け取るわけですが、
```JavaScript
const names = people.map(({ name }) => name);
```
この部分で**オブジェクトすべてをもらわずに、nameだけを抜き取ってもらっていた**わけですね！
ここがmap内部に隠れてしまうので難しく感じた次第でした。
paizaラーニング問題集「部分和問題 3」を解いてみた（処理の流れの解説あり）

https://paiza.jp/works/mondai/dp_primer/dp_primer_partial_sums_step2

▼考え方

ポイントとなると思った考え方を、以下1.～5.に示します。

1.dpは、ある重さを、おもりの重さa_iやa_i以前のおもりを複数組合わせることで実現できるかどうかを示すリストです。例：a_0は7なのでdp[7]=1、a_1は3なのでdp[3]=1、a_0+a_1で10なのでdp[10]=1

2.dp2は、a_iを何個か選んで重さの和がxとなるようにする方法のうち、選ぶおもりの個数の最小値を示すリストです。例：a_0=7とa_1=3があるときdp2[10]=2、次にa_n=10が現れたときdp2[10]=1と更新します。
　
3.ある重さjが、a_iやa_i以前のおもりを複数組合わせることで実現できるのであれば、dp[j]←1と更新します。

4.ある重さjが、a_iのみで実現できるのであれば、dp2[j]←1と更新します。例：重さ7はa_0=7のみで実現できるのでdp2[7]←1と更新します。

5.ある重さjが、a_iをa_i以前のおもりの組合わせで実現できるのであれば、おもりが少ないほうの組合わせの数でdp2[j]を更新します。（考え方2の実現）

▼コード
```py
########## 処理0(準備) インプット,リスト定義など ###########

n,x = map(int,input().split())

a = [0]*n

########## 処理1 漸化式の定義、計算、出力 ##########

dp = [0]*(x+1)
dp2 = [0]*(x+1)
dp[0] = 1

for i in range(n):

    a[i] = int(input())

for i in range(1,n+1):

    for j in range(x,a[i-1]-1,-1):

        # 考え方3.
        if dp[j-a[i-1]] == 1:
            dp[j] = 1

            # 考え方4.
            if j-a[i-1] == 0:
                dp2[j] = 1
                
            # 考え方5.
            else:
                if dp2[j] == 0 or (dp2[j] > dp2[j-a[i-1]]+1):
                    dp2[j] = dp2[j-a[i-1]] + 1

if dp2[x] == 0:
    print(-1)
else:
    print(dp2[x])
```

▼考え方5の補足

おもりが少ないほうの組合わせの数だけdp2[j]に保持するのではなく、すべての組合わせの数を保持させるようなコードも作りました。例：a_0=7とa_1=3があるときdp2[10]=2、次にa_n=10が現れたときdp2[10]=(1,2)

しかし実行するとエラーコードにkilledと表示されました。おそらくdp2のために確保するメモリが上限を超えてしまったものと思います。
Tableauでウォーターフォールチャートの色を項目ごとに設定する方法

## 背景
ウォーターフォールチャートの色を項目ごとに設定する方法
総計も色を設定したい

完成イメージは以下の画像。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/786947/b9720465-ec57-dd5c-69ca-bb45e3f591fb.png)

TableauPublicでも公開中
https://public.tableau.com/views/_17280264974250/1?:language=ja-JP&publish=yes&:sid=&:redirect=auth&:display_count=n&:origin=viz_share_link


## 方法
まずはシンプルにガントチャートを作っていくので説明は省く
以下のような一般的なウォーターフォールチャートを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/786947/741c5a74-02b9-64be-b8ac-9187fdf24526.png)


色分けをするため計算式を作成し、マークカードの色にいれる
``` 
IF ATTR([サブカテゴリ]) = '本棚' THEN '本棚'
ELSEIF SUM([利益]) > 0 AND (ATTR([サブカテゴリ]) = '椅子' OR ATTR([サブカテゴリ]) = 'コピー機' OR ATTR([サブカテゴリ]) = 'アプライアンス' OR ATTR([サブカテゴリ]) = '付属品' OR ATTR([サブカテゴリ]) = '事務機器' OR ATTR([サブカテゴリ]) = '家具' OR ATTR([サブカテゴリ]) = '電話機' OR ATTR([サブカテゴリ]) = '文房具' OR ATTR([サブカテゴリ]) = '紙' OR ATTR([サブカテゴリ]) = '封筒' OR ATTR([サブカテゴリ]) = 'バインダー' OR ATTR([サブカテゴリ]) = '保管箱' OR ATTR([サブカテゴリ]) = 'クリップ' OR ATTR([サブカテゴリ]) = 'ラベル' OR ATTR([サブカテゴリ]) = '画材' OR ATTR([サブカテゴリ]) = 'テーブル') THEN '＋'
ELSEIF SUM([利益]) <= 0 AND (ATTR([サブカテゴリ]) = '椅子' OR ATTR([サブカテゴリ]) = 'コピー機' OR ATTR([サブカテゴリ]) = 'アプライアンス' OR ATTR([サブカテゴリ]) = '付属品' OR ATTR([サブカテゴリ]) = '事務機器' OR ATTR([サブカテゴリ]) = '家具' OR ATTR([サブカテゴリ]) = '電話機' OR ATTR([サブカテゴリ]) = '文房具' OR ATTR([サブカテゴリ]) = '紙' OR ATTR([サブカテゴリ]) = '封筒' OR ATTR([サブカテゴリ]) = 'バインダー' OR ATTR([サブカテゴリ]) = '保管箱' OR ATTR([サブカテゴリ]) = 'クリップ' OR ATTR([サブカテゴリ]) = 'ラベル' OR ATTR([サブカテゴリ]) = '画材' OR ATTR([サブカテゴリ]) = 'テーブル') THEN 'ー'
ELSE '総計'
END
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/786947/039a4a34-0add-ca06-34ae-8a2e6694e04e.png)

各サブカテゴリごとに条件式を用いて色を適用していく

サブカテゴリの本棚を別の色にしたかったので、まず本棚を指定する。
ATTRは非集計値を集計値に変更する上で必要

ELSEIFで＋とーをそれぞれ指定する
OR以降はELSEで総計を指定するために必要であり、本棚以外の全てのサブカテゴリを指定している
イメージとしては「利益が0より大きい」かつ「カテゴリが本棚以外のどれか」
ATTR([サブカテゴリ])で総計を指定できなかったからこのように長い関数を入れている

どの条件にも引っかからなかった項目を総計と指定している