OmniAICreator/Qiita-1.07M huggingface dataset:
OCI CLIで子テナンシーの一覧を確認する

# はじめに
OCIの子テナンシーの一覧をCLIで確認する方法です

以降は親テナンシーで実施します。

# organization OCIDの確認

```
oci organizations organization list --compartment-id ocid1.tenancy.oc1..aaaaaaaacueyrcxxxxxxxxxxxxxxxxxx
{
  "data": {
    "items": [
      {
        ・・・
        "id": "ocid1.organizationsentity.oc1.ap-tokyo-1.amaaaaaaad4rljyabqrzc33axxxxxxxxxxxxxxxxx",
        ・・・
      }
    ]
  }
```

# 子テナンシーの一覧表示
確認したorganization OCIDを環境変数に設定してから表示します。

```
export ID=ocid1.organizationsentity.oc1.ap-tokyo-1.amaaaaaaad4rljyabqrzcxxxxxxxxxxxxxxxx
```

```
oci organizations organization list-organization-tenancies --all --organization-id $ID --query data.items[].name
[
  "aaaaaaa",
  "bbbbbbbbb",
]
```

テーブル形式

```
oci organizations organization list-organization-tenancies --output table --all --organization-id $ID --query data.items[].name
+---------------------------+
| Column1                   |
+---------------------------+
| aaaaaaaaaaaaaaaaaaa       |
| bbbbbbbbbbbbbbbbbbbbb     |
+---------------------------+
```

テナンシー名とOCIDを表示する


```
$ oci organizations organization list-organization-tenancies --all --organization-id $ID --query "data.items[].{NAME:\"name\", OCID:\"tenancy-id\"}" --output table
+---------------------------+---------------------------------------------------------------------------------+
| NAME                      | OCID                                                                            |
+---------------------------+---------------------------------------------------------------------------------+
| xxxxxxxxxxxxxxxxxx        | ocid1.tenancy.oc1..aaaaaaaaxxxxxxx |
| xxxxxxxxxxxxxxxxxxxxx     | ocid1.tenancy.oc1..aaaaaaaaxxxxxxx |
```

テナンシー名、OCID、Statusを表示する

```
$ oci organizations organization list-organization-tenancies --all --organization-id $ID --query "data.items[].{NAME:\"name\", STATUS:\"lifecycle-state\", OCID:\"tenancy-id\"}"
[
  {
    "NAME": "aaaaaaa",
    "OCID": "ocid1.tenancy.oc1..aaaaaaaarhr6f2epwsy6lkw2uwaaaaaaaaaaaaaaaaaa",
    "STATUS": "DELETING"
  },
  {
    "NAME": "bbbbbbb",
    "OCID": "ocid1.tenancy.oc1..aaaaaaaa2mas56ekw3jhkxtkkebbbbbbbbbbbbbbbb",
    "STATUS": "ACTIVE"
  }
]
```

StatusがActiveのテナンシーだけ表示

```
oci organizations organization list-organization-tenancies --all --organization-id $ID --query "data.items[?\"lifecycle-state\"=='ACTIVE'].{NAME:\"name\", STATUS:\"lifecycle-state\", OCID:\"tenancy-id\"}"
```
Emacsで、mozc-modeでもdelete-selection-modeを機能させる

## 状況

普段、選択範囲（リージョン）を作った状態で打鍵をしたら、打鍵した文字で選択範囲を上書きしてほしいので、init.elで以下を設定している。

```elisp:init.el
(delete-selection-mode t)
```
しかし、`mozc-mode`（日本語を直接入力するモード）だと、ぼくの環境では、この設定がうまく行かなかった。`mozc-mode`で選択範囲を作った状態で、なにか文字列を入力すると、選択範囲を外して（選択範囲の文字が残って）、文字が入力された。

## 解決

以下、elispをinit.elに入れた。
これで、`mozc-mode`で選択範囲がある状態で、文字入力すると、選択範囲の文字を入力した文字で上書きしてくれるようになった。

```elisp:init.el
;;; ------------------------------------------------------------
;; mozc-modeでもdelete-selection-modeを機能させる
(defun my-mozc-handle-event (orig-fun &rest args)
  "Make `delete-selection-mode` work in mozc-mode.  ORIG-FUN, ARGS."
  (let* ((event (nth 0 args))
         (event-type (and event (event-basic-type event))))
    (if (and (use-region-p)
             event
             (not (or (member event-type '(left right up down henkan muhenkan wheel-up wheel-down escape))
                      (member 'shift (event-modifiers event))
                      (member 'super (event-modifiers event))
                      (member 'meta (event-modifiers event))
                      (member 'control (event-modifiers event))
                      (mouse-event-p event))))
        (delete-region (region-beginning) (region-end)))
    (apply orig-fun args)))

(advice-add 'mozc-handle-event :around #'my-mozc-handle-event)

(defun my-delete-selection-before-yank (&rest _args)
  "Deactivate the selection before yank."
  (if (use-region-p)
      (delete-region (region-beginning) (region-end))))

(advice-add 'yank :before #'my-delete-selection-before-yank)
```

## ポイント

- 選択範囲がある状態で、打鍵があるたびに選択範囲の文字列を削除してしまうと、キーボードでコピーやカットができなくなるので、対策をしている
JavaScriptの変数管理 (宣言、初期化、代入の違い)

## アジェンダ
JavaScriptの変数管理においての、**宣言**、**初期化**、**代入**の概念について簡単にまとめます。

## 1. 宣言（Declaration）
変数の宣言は、その変数をJavaScriptのメモリ空間に確保することです。`var`、`let`を使って変数を宣言します。

- **`var`**
```javascript
var x;
```

- **`let`**
```javascript
let y;
```
宣言された変数は、それが属するスコープ内で使用可能になります。

- **❌`const`(宣言ができない)**
constキーワードを使って変数を宣言する際に値を指定しないと、SyntaxErrorが発生します。

```javascript
// エラーが発生する
const z;
```
エラー内容
```
SyntaxError: Missing initializer in const declaration
```
constは「定数」という名前が示すように、その値が変更されないことを保証しているため、constで宣言された変数には、宣言と同時に値を割り当てる必要があります。
値を指定しない宣言は意味を成さず、エラーとして扱われます。

## 2. 初期化（Initialization）
初期化は、変数に初めて値を設定することです。宣言時に同時に初期化することも可能です。

- **`var`の宣言と初期化**
```javascript
var x = 10;
```

- **`let`の宣言と初期化**
```javascript
let y = 20;
```

- **`const`の宣言と初期化**
```javascript
const z = 30;
```

`const`の場合、宣言時に必ず初期化が必要です。`var`や`let`は宣言時に初期化しなくても構いませんが、初期化されるまでは`undefined`の値を持ちます。

## 3. 代入（Assignment）
代入は、既に宣言されている変数に値を設定することです。これは初期化後でも行うことができます。

- **`var`の代入**
```javascript
var x;
x = 10;
```

- **`let`の代入**
```javascript
let y;
y = 20;
```

- **❌`const`の代入（再代入不可）**
`const`は再代入ができないため、一度初期化した後に値を変更することはできません。

```javascript
const z = 30;
// z = 40; // エラーが発生します
```

## 具体例を通じて理解する

```javascript
// 宣言
let a;
var b;
// const c; // エラーが発生します

// 初期化
a = 10;
b = 20;
const c = 5; // 宣言と初期化を同時に行う

// 代入
a = 15; // aは再代入可能
b = 25; // bも再代入可能
// c = 30; // エラーが発生します
```

## まとめ

- **宣言**は変数をメモリに確保することです。
- **初期化**は変数に初めて値を設定することです。
- **代入**は既存の変数に新たな値を設定することです。

## 参考
[JavaScript | 変数への値の代入と変数の初期化](https://www.javadrive.jp/javascript/var/index4.html)
てすと

```
function extractZipEmailsAndStoreInDrive() {
  // zipファイル付きのメールを検索
  var searchQuery = 'has:attachment filename:zip';
  var zipThreads = GmailApp.search(searchQuery);
  var messagesWithZip = [];

  for (var i = 0; i < zipThreads.length; i++) {
    var messages = zipThreads[i].getMessages();
    for (var j = 0; j < messages.length; j++) {
      var message = messages[j];
      var attachments = message.getAttachments();
      var hasZip = attachments.some(function(attachment) {
        return attachment.getContentType() === 'application/zip';
      });
      if (hasZip) {
        messagesWithZip.push(message);
      }
    }
  }

  var relatedEmails = [];
  var emailIds = messagesWithZip.map(function(message) { return message.getId(); });

  var timeBufferMinutes = 15;
  var relatedSearchQueryParts = messagesWithZip.map(function(message) {
    var timeFrameStart = new Date(message.getDate().getTime() - timeBufferMinutes * 60 * 1000);
    var timeFrameEnd = new Date(message.getDate().getTime() + timeBufferMinutes * 60 * 1000);
    var sender = message.getFrom();
    return '(' + 'after:' + formatDate(timeFrameStart) + ' before:' + formatDate(timeFrameEnd) + ' from:' + sender + ')';
  });

  var relatedSearchQuery = relatedSearchQueryParts.join(' OR ');
  var relatedThreads = GmailApp.search(relatedSearchQuery);

  for (var k = 0; k < relatedThreads.length; k++) {
    var relatedMessages = relatedThreads[k].getMessages();
    for (var l = 0; l < relatedMessages.length; l++) {
      var relatedMessage = relatedMessages[l];
      if (!emailIds.includes(relatedMessage.getId())) {
        relatedEmails.push(relatedMessage);
      }
    }
  }

  var passwordPattern = /[A-Za-z0-9!@#$%^&*()_+]{6,}/;
  var password = null;

  relatedEmails.forEach(function(message) {
    var body = message.getBody();
    var match = body.match(passwordPattern);
    if (match) {
      password = match[0];
      return false;
    }
  });

  if (password) {
    messagesWithZip.forEach(function(message) {
      var attachments = message.getAttachments();
      attachments.forEach(function(attachment) {
        if (attachment.getContentType() === 'application/zip') {
          var blob = attachment.copyBlob();
          var unzippedFiles = Utilities.unzip(blob, password);
          var folder = DriveApp.getFolderById('<YOUR_DRIVE_FOLDER_ID>');
          unzippedFiles.forEach(function(file) {
            folder.createFile(file);
          });
        }
      });
    });
  } else {
    Logger.log('No password found');
  }
}

function formatDate(date) {
  var year = date.getFullYear();
  var month = ('0' + (date.getMonth() + 1)).slice(-2);
  var day = ('0' + date.getDate()).slice(-2);
  var hour = ('0' + date.getHours()).slice(-2);
  var minute = ('0' + date.getMinutes()).slice(-2);
  return year + '/' + month + '/' + day + ' ' + hour + ':' + minute;
}
```
初心者向け：JSONサーバー入門

### JSONサーバーとは？

JSONサーバーは、シンプルなJSONファイルを使ってモック（擬似）REST APIを作成できるツールです。
これを使うと、実際のバックエンドが完成していなくても、手軽にAPIをシミュレーションできます。


### 前提
- Node.jsをマシンにインストールしておくこと

### 手順
1. 新しいNode.jsプロジェクトを初期化します（すでにプロジェクトがある場合はスキップ）：
    ```bash
    npm init -y
    ```


2. JSONサーバーをインストール：
    ```bash
    npm install json-server
    ```


3. `db.json`というファイルを作成し、以下のように初期データを記述：
    ```json
    {
      "posts": [
        { "id": 1, "title": "Hello World", "author": "John Doe" }
      ],
      "comments": [
        { "id": 1, "body": "Nice post!", "postId": 1 }
      ],
      "profile": { "name": "John Doe" }
    }
    ```

4. JSONサーバーをポート5000で起動：
    ```bash
    npx json-server --watch db.json --port 5000
    ```
watchオプションを使用することで、db.jsonファイルに加えた変更をリアルタイムでサーバーに反映できます。


### JSONサーバーへのアクセス
- ブラウザを開き、[http://localhost:5000](http://localhost:5000) にアクセスしてみましょう。
- リソースには以下のエンドポイントからアクセスできます：
  - [http://localhost:5000/posts](http://localhost:5000/posts)
  - [http://localhost:5000/comments](http://localhost:5000/comments) 


### エンドポイントの例
#### `GET /posts`
すべての投稿が取得できます。
```json
[
  {
    "id": 1,
    "title": "Hello World",
    "author": "John Doe"
  }
]
```

#### `POST /posts`
リクエストボディに新しい投稿のデータを含めましょう。
```json
{
  "title": "New Post",
  "author": "Jane Doe"
}
```
成功すると、新しい投稿が追加されます。
```json
{
  "id": 2,
  "title": "New Post",
  "author": "Jane Doe"
}
```

#### `PUT /posts/1`
IDが1の投稿を更新します。リクエストボディに更新内容を含めましょう。
```json
{
  "title": "Updated Post",
  "author": "John Doe"
}
```
成功すると、更新された投稿が返されます。
```json
{
  "id": 1,
  "title": "Updated Post",
  "author": "John Doe"
}
```

#### `DELETE /posts/1`
IDが1の投稿を削除します。成功すると、削除された投稿のデータが返されます。
```json
{
  "id": 1,
  "title": "Hello World",
  "author": "John Doe"
}
```

より詳細な情報が必要な方は、JSONサーバーの[GitHubリポジトリ](https://github.com/typicode/json-server)をご覧ください。
paiza Aランク問題「お菓子の詰め合わせ」を Elixir で解いてみた

## はじめに

paiza A ランク問題を Elixir で解いてみます

## お菓子の詰め合わせ

お菓子をできるだけ種類豊富に、お釣りが少なくなるように購入します

https://paiza.jp/works/mondai/a_rank_skillcheck_archive/school_hiking

```elixir
defmodule Comb.Naive do
  def combinations(_, 0), do: [[]]
  def combinations([], _), do: []

  def combinations([h|t], k) do
    ((for l <- combinations(t, k - 1), do: [h|l]) ++ combinations(t, k))
    |> Enum.uniq
  end

  def combinations(enum, k), do: combinations(Enum.to_list(enum), k)
end

defmodule Paiza do
  def main do
    [_n, x] =
      :stdio
      |> IO.read(:line)
      |> String.trim()
      |> String.split(" ")
      |> Enum.map(&String.to_integer(&1))

    prices =
      :stdio
      |> IO.read(:all)
      |> String.trim()
      |> String.split("\n")
      |> Enum.map(&String.to_integer(&1))
      |> Enum.filter(fn price -> price <= x end)  # 単体で予算オーバーになるお菓子は除外
      |> Enum.sort()  # 安い順に並べ替え

    # 購入するお菓子の個数を決める（安い順に足していって予算以上になる個数）
    {_sum, length} =
      prices
      |> Enum.with_index()
      |> Enum.reduce_while({0, 0}, fn {price, index}, {sum, _} ->
        cond do
          sum + price == x ->
            {:halt, {x, index + 1}}
          sum + price > x ->
            {:halt, {sum, index}}
          true ->
            {:cont, {sum + price, index + 1}}
        end
      end)

    # 指定した個数を選ぶとき、合計金額が予算以下で最大の組み合わせを選択する
    prices
    |> Comb.Naive.combinations(length)
    |> Enum.map(fn combination ->
      Enum.sum(combination)
    end)
    |> Enum.filter(fn alt -> alt <= x end)
    |> Enum.max()
    |> then(fn y -> x - y end)  # お釣りを計算
    |> IO.puts()
  end
end

Paiza.main()
```

## 解説

### 組み合わせの生成

「全ての組み合わせを作る処理」については先人の知恵を拝借しました

https://github.com/tallakt/comb

`Comb.Naive` モジュールについては以下のリンクの箇所を拝借しています

https://github.com/tallakt/comb/blob/e6660924891d88d798494ab0c5adeefb29fae8b8/lib/comb/naive.ex#L1-L19

`Comb.Naive.combinations` 関数は指定配列から指定個数を選択する全ての組み合わせを作成します

例えば `Comb.Naive.combinations([1, 2, 3], 2)` は `[[1, 2], [2, 3], [1, 3]]` を返します

### 個数の算出

上記関数の２番目の引数に渡すための、「何個のお菓子を購入するか」を求めます

最も多くの種類を買いたいので、安いものから順に選択することになります

安い順に並べ替え、 `Enum.reduce_while` で足していって、合計金額が予算以上になる個数 = 最大個数です

### 最大金額の算出

お釣りを最小にする = 予算内で合計金額が最大になる組み合わせということです

上記の組み合わせ取得関数で全組み合わせを作り、合計金額が予算以下のものの中から最大値を取得します

最終的に求めるのはお釣りの額なので、予算から合計金額を引いて出力します

## まとめ

個数が少ないので、全組み合わせを計算するような実装でもタイムオーバーにはなりませんでした

全組み合わせの取得については自前実装ではないので、少しズルい回答ですが
Databricksノートブックでコマンドパレットが利用できるようになりました！

こちらのアップデートです。

[ノートブックからコマンドパレットが利用可能に](https://docs.databricks.com/en/release-notes/product/2024/july.html#command-palette-available-in-notebooks)

> コマンドパレットを用いてノートブックでのアクションをクイックに実行できるようになりました。頻繁に使用するアクションにアクセスするには、ノートブックを開いている際に、MacOSなら**Cmd + Shift + P**、Windowsなら**Ctrl + Shift + P**を押します。[コマンドパレット](https://docs.databricks.com/ja/notebooks/notebooks-code.html#command-palette)をご覧ください。

![](https://docs.databricks.com/ja/_images/command-palette.gif)

早速確認してみます。ノートブックを開いて**Cmd + Shift + P**。開きました！
![Screenshot 2024-08-08 at 8.52.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/d57913a5-2b90-c055-93e5-f454c292b485.png)

ノートブック右下のアイコンからもアクセスできます。
![Screenshot 2024-08-08 at 8.53.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/4cb94cfc-27a6-a741-823b-310e4e2ac306.png)

過去の履歴へのアクセスや検索(ただ、現時点では英語のみのサポートのようで日本語で検索できませんでした)も可能です。
![Screenshot 2024-08-08 at 8.54.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/6a812cda-289e-816c-5710-eabac1da72c0.png)

作業効率が上がることは間違いなしですので、是非ご活用ください！

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
Java gold 例題 Function

```java
public class ToDoubleFunctionTest {
	public static void main(String[] args) {

		1️⃣ ToDoubleFunction f = n -> n * 0.1;
		2️⃣ double ans = f.applyAsDouble(20);
    	   System.out.println(ans);
	}
}
```
出力結果はどれでしょうか
1. 20.0
1. 20
1. 1️⃣でコンパイルエラー
1. 2️⃣でコンパイルエラー
1. 実行時エラー

↓

↓

↓

↓

↓

↓

↓

↓

↓

↓

↓

↓

↓

↓

↓

↓

#### 3:  1️⃣でコンパイルエラー
`ToDoubleFunction<T>`は引数の型をジェネリクスで指定する必要があります。
戻り値の型は`Double`型になります。
問題では、`ToDoubleFunction f = ・・・`とあり、引数の型を指定するジェネリクスがないためコンパイルエラーとなります。
以下のように修正するとコンパイルエラーは解消されます。
```java
ToDoubleFunction<Integer> f = n -> n * 0.1;
```
もしくは引数の型もあらかじめ決まっている`IntToDoubleFunction`が利用できます。
```java
IntToDoubleFunction f = n -> n * 0.1;
```


https://qiita.com/T-ngtj/private/df254aacd05be698199a
【読書記録】プリンシプル オブ プログラミング 5章~7章

# 読んだ本
「プリンシプル オブ プログラミング3年目までに身につけたい一生役立つ101の原理原則」

https://www.amazon.co.jp/dp/4798046140

この記事では、5章〜７章の中で特に覚えておきたいことを記載します。


## ボーイスカウトの規則
```
Boy Scout Rule
```
ボーイスカウトの「自分のいた場所は、そこを出て行く時、きたときよりも綺麗にしなければならない」という規則。
最初にそのコードを書いたのが誰であるかに関係なく、少しずつでもコードを改善する努力を続ける。

## エゴレスプログラミング
```
Egoless programming
```

「うぬぼれ」や「プライド」を捨て、自分の書いたコードを積極的に仲間に見せ、改善点を指摘してもらう。
#### エゴレスプログラミングの十戒
- 自分自身も間違いを犯すということを理解し、受け入れます
- 書いたコードは、自分自身ではありません
- どれほど極めたと思っていても、上には上がいます
- 相談なしに、コードを書き直しません
- 自分よりもスキルが劣る人にも、尊敬と敬意と忍耐を持って接します
- 世界でういいつ変わらないことは、変わるということだけです
- 本当の権威は、地位ではなく、知識から生じます
- 信じる者のために戦います。ただし、負けは潔く受け入れます
- 部屋に篭りきりはいけません
- 「人に優しく、コードに厳しく」して、人ではなくコードを批評します

## 1歩ずつ少しずつ
```
One by one
```

小さな作業を1つ行い、それをしっかり確認し次の作業に移る、というサイクルを繰り返す。
1歩ずつ進めると、最後の一歩を後戻りすることが楽になる。また、各1歩の確認が楽になる。

例）
リファクタリングであれば、モジュール間で関数を移動する時、
関数名の不備に気づいたとしても移動と名前お変更を同時に行ってはいけない。
関数を移動したあと、一旦その状態で動作確認をしてから関数名の変更に取り組みます.
## 割れた窓の法則
```
Broken Windows Theory
```

悪いコード（割れた窓）を放置すると、建物全体に対する深刻な破損が起こる

ソフトウェアに「割れた窓」が少しでもあると、修正するプログラマに「きっと残りの全てのコードもガラクタなんだから、自分も適当に作業してしまえ」という考え方が忍び込む

コードのよく無い部分をそのままにせず、発見と同時に修復する。
もしくは、このコードがよく無いという旨をわかりやすいところに明示する。
【読書記録】プリンシプル オブ プログラミング（アーキテクチャ根底技法）


# 読んだ本
「プリンシプル オブ プログラミング3年目までに身につけたい一生役立つ101の原理原則」

https://www.amazon.co.jp/dp/4798046140

この記事では、3章の *アーキテクチャ根底技法* について記載します。

# アーキテクチャ根底技法
```
Enabling Techniques for Architecture
```
### どういうこと？
良いソフトウェア・アーキテクチャ構築のための基礎原理。
以下の技法がある。
- 抽象
- カプセル化
- 情報隠蔽
- パッケージ化
- 関心の分離
- 充足性、完全性、プリミティブ性
- ポリシーと実装の分離
- インタフェースと実装の分離
- 参照の一点性
- 分割統治

## 技法1: 抽象
```
Abstraction
```
###  どういうこと?

抽象とは、概念的に明確な「線引き」を行うこと。
抽象は、2つの観点がある。
- 抽象
- 一般化

例）楽器（ピアノ・バイオリン・チェロ）の場合、
- 抽象化：複雑な対象のいくつかの性質を捨て去り、特定の性質に目を向けること
- 一般化：具体的な対象から共通の性質を抽出し、より汎用的な概念に定式化すること
```
//抽象化
楽器（具体的な個体の集合・製造番号） → 楽器の種類（商品番号）

//一般化
ピアノ・バイオリン・チェロ → 楽器
```

参考: 5分30秒〜
https://www.youtube.com/watch?v=X9HbfKswJHc

## 技法2: カプセル化
```
Encapsulation
```
関連のあるデータとロジックをグルーピングして、1つのモジュールにまとめる。
カプセル化には以下のメリットがある。
- 関連のない要素が混じらないため、コードが見やすくなる
- 変更時の影響が、モジュールないに閉じることになる
- 影響度が明確になるので、コードの変更が容易になる
- それぞれが独立した部品になるので、再利用性が高まる
- 小さい単位に分割されるので、複雑な問題に対処できる

## 技法3: 情報隠蔽
```
Infomation Hiding
```
モジュールにどのようなデータがあり、関数がどのようなロジックで機能を実現するかを外部から隠蔽する。
モジュールの持つデータは、外部から直接アクセスできないようにする。

クライアントから見ても余計な情報が見えないため、モジュールの使い方がシンプルになり、使い勝手が良くなる

### カプセル化と情報隠蔽の違い
#### カプセル化
関係のある要素を集めてモジュール化すること。
関連の深いデータと関数を一箇所にまとめる。

#### 情報隠蔽
モジュールの内部状態や内部関数を隠蔽すること。
内部に対する外部からの直接アクセスを遮断する。

## 技法4: パッケージ化
```
Packaging
```
モジュールを意味のある単位にまとめ、それをグループ化する。
これはソフトウェア全体を意味のある単位に分割すること。これをパッケージと呼ぶ。
#### 利点
- ソフトウェア全体が、パッケージという小さい単位に分割されるので、複雑度が下がる
- パッケージ内は関係のないモジュールが混じらないので、モジュールの管理がしやすくなる
- 修正に対して、影響度がパッケージ内に止まる可能性が高いので、コードが変更しやすくなる
- 依存関係が整理されることになり、パッケージを単位とした再利用をしやすくなる

パッケージの設計は、モジュールがある程度できてから、ボトムアップで設計する。　

## 技法5: 関心の分離
```
Separation of Concerns
```
関心とは、ソフトウェアの機能や目的のこと。
関心ごとに。モジュールを作成し、互いに異なる責務や、無関係な責務は分離しておく。
最も代表的な設計技法のパターンはMVC（「ビジネスロジック・ユーザへの表示・入力処理」に分離している）
#### メリット
コードが関心ごとに分離されていれば、以下のメリットがある
- 関心ごとに独立して修正できるので、読む範囲が限られ、変更が容易になる
- 影響範囲が関心内に留まることになるので、変更時の品質が安定する
- コードを書くときは、関心を単位として開発するため、分業して並行して開発を進めることができる

## 技法6: 充足性、完全性、プリミティブ性
```
Sufficiency, Completeness, Primitiveness
```

モジュールの担っている抽象の表現は、「充足」し「完全」で「プリミティブ」であるべき。
#### 充足性
モジュールが表現しようとしている抽象が、それを伝えるために十分であるか、ということ

例）モジュールがコレクションを表現しいているとき、`remove`が提供されていても`add`が提供されていなければ、コレクションであることを伝えるのは不十分


#### 完全性
モジュールが表現しようとしている抽象が、全ての特徴を備えているか、ということ

例）モジュールがコレクションを表現しているとき、その要素数を取得する`size`が提供されていなければ、完全とは言えない

#### プリミティブ性
モジュールが表現しようとしている抽象が、全て純粋であるかどうか、ということ

例）モジュールがコレクションを表現しているとき、アイテムを1つ追加する`add`が提供されていれば、アイテムを10個追加する`add10`は必要ない


## 技法7: ポリシーと実装の分離
```
Separation of Policy and Implementaion
```

モジュールは、「ポリシー」あるいは「実装」を扱うが、1つのモジュールでその両方を扱ってはいけない。
「ポリシー」と「実装」が混ざっていると、ポリシーの変更に実装が引きづられ、再利用できなくなってしまう。
#### ポリシーモジュール
ソフトウェアの前提に依存する、ビジネスロジックや、その他のモジュールに対する引数の選択を行う部分

#### 実装モジュール
そのソフトウェアの前提に依存しない、独立したロジック部分。
そのソフトウェアの前提条件については、モジュールに対する引数として与えられる。


## 技法8: インタフェースと実装の分離
```
Separation of Interface and Implementaion
```

モジュールは「インターフェース」パートと「実装」パートの2つの分離した部分から構成する。
使用者はインタフェースだけ知れば良い。
インタフェースを用いて設計する

## 技法9: 参照の一点性
```
Single Point of Reference
```
モジュールの要素で、宣言され定義されるのは1回切りにする。
そのために、単一代入を行う。
単一代入: 変数に対して、値の再代入を行わないこと

## 技法10: 分割統治
```
Divide and Conquer
```

そのままでは解決することが難しい大きな問題は、いくつかの小さな問題に分割して、個別に解決する
HTMLの書き方さえ分からなかったあの頃の自分へ

## コンピューターといえばスーファミのことだと思っていたあの頃

こんにちは。私はとあるITの企業で働いている崖っぷちサラリーマンです。

今日は私が未経験時代だった時代、世の中に対するフィルター的な部分、価値観的な部分をご共有したいと記事を書きました。

## 家のLANに接続するだけで1年間もかかった

私のPCとの出会いは2003年ごろになります。家にWindowsのマシンがきて私が使っていいということになりました。ありし日のNECのLavieのデスクトップパソコンです。

モニタはもちろんCRT。今も絶賛ほこりを被っております。

## ネットに接続するだけでひと苦労

今はWiFiを探してパスワードを入力するだけでしたが、当時はCDとかを使わねばならずインターネットに接続するだけでも大変でした。

## はじめて使ったアプリはMSPaint、マインスイーパーがお気に入り

WindowsはXPまでゲームが入ってました。その中のマインスイーパーにハマってました。

## 音楽の再生、動画の再生ができるだけで驚いた

音楽の再生はラジカセやウォークマンがすること、動画にいたってはテレビかビデオしかなく、DVDは高級品だったので、音楽や動画が再生できるだけですごかったんです

## HTMLだけのウェブサイトが作れるだけで神

はじめてホームページをみたときこれを自分で作れるとは正直思わなかったです。

しかしそんな私に運命的な出会いが訪れます。

## HTMLとの出会い

何もインストールしなくてもメモ帳だけで作れるHTML作って1人で感動していました。

## 今のウェブ環境は当時想像できなかった

コンピューターといえばファミコンだったのでスマホが当たり前、デュアルSIM当たり前の今の時代は私にとっていつまでも浦島太郎状態です。

## さいごに

今後どれだけ技術が発展してもあの頃の感覚をいつまでも忘れないでいたいので書きました。

いつになるかわかりませんが、2040年代とかになれば脳に埋め込むデバイスができて、それを使わないと職場で取り残される未来が来るんじゃないかと思ってます。

そんな時代になったら私は生きていないでしょうがこの記事はいつまでも残ると信じて備忘録として残しました。

今の新卒は今の技術が当たり前にある時代で育っているのでうらやましくはないです。

若くないっていうのもいいんだぞって言いたいですね。
LivePortraitを試す - トークヘッド 非商用ならこれでOK（企業でないなら)

Huggingfaceで話題のLivePortraitを試しました。
https://github.com/KwaiVGI/LivePortrait

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54688/d9441d4d-2a52-e581-06b9-39f070df7d0d.png)

公式のSpaceは大人気すぎてエラーになりやすいですが
HuggingfaceのProアカウントをお持ちの方は、クローンしてpriveで使うと、エラーなく使えるでしょう。
(ZeroGPUの使い道の一つですね)

## オープンソースなのに、非商用とは?
requires.txtに記載されてるのは、大抵ライセンスはMIT/BSD/Apacheですが、そのライブラリーが使っている関連する技術を遡ると、ほぼすべてのトークヘッドはNvidiaにたどり付きます。

LivePortraitは、Nvidiaのface-vid2vidの改良版といっていい
https://nvlabs.github.io/face-vid2vid/

セグメンテーションで使ってる
https://github.com/NVlabs/SPADE

## 企業向きでないのは？
トレーニングデータがまだ非公開です。まずいのが入ってたときのリスクが不明
個人は、非商用で使うのに、トレーニングデーター気にする必要はないのでは？

## ローカルで動かす
Gradioの環境、Python3.10なら、動作を確認しました。驚いたたことに、わずか8GB VRAMでも動きました。

pickleのエラーは
```
magic_number = pickle_module.load(f, **pickle_load_args)
_pickle.UnpicklingError: invalid load key, 'v'.
```
git lfs が原因でした。(Gradioで、pickle関係のエラーは、すべてLFSが原因かも)
https://scrapbox.io/nishio/_pickle.UnpicklingError:_invalid_load_key,_'v'
NumPy Python 基礎トレーニングコース

## Pythonでかっこいいことがしたいあなたへ

Pythonは、そのシンプルさと強力なライブラリの豊富さから、データ分析や機械学習の分野で広く利用されています。

その中でも、NumPyは数値計算を効率的に行うための基本的なライブラリとして知られています。本記事では、NumPyの基礎を学ぶためのトレーニングコースと、実際のユースケースを用いたサンプルコードを紹介します。

### NumPyとは？

NumPy（Numerical Python）は、Pythonでの数値計算をサポートするライブラリで、多次元配列オブジェクトや数学関数を提供します。NumPyを使用することで、数値データの操作を高速かつ効率的に行うことが可能です。

### NumPyの基礎

NumPyの基本的な機能を理解するために、以下のトピックをカバーします：

1. **NumPy配列の作成**
2. **配列の操作**
3. **配列の計算**
4. **ユースケースの紹介**

#### 1. NumPy配列の作成

NumPy配列は、`numpy.array()`関数を使用して作成します。以下のコードは、基本的な1次元および2次元配列の作成例です。

```python
import numpy as np

# 1次元配列の作成
array_1d = np.array([1, 2, 3, 4, 5])
print("1次元配列:", array_1d)

# 2次元配列の作成
array_2d = np.array([[1, 2, 3], [4, 5, 6]])
print("2次元配列:\n", array_2d)
```

#### 2. 配列の操作

NumPyでは、配列の形状を変更したり、要素を抽出したりすることができます。

```python
# 配列の形状を変更
reshaped_array = array_1d.reshape(5, 1)
print("形状を変更した配列:\n", reshaped_array)

# 要素の抽出
element = array_2d[1, 2]
print("抽出した要素:", element)
```

#### 3. 配列の計算

NumPyは、配列同士の計算を効率的に行うための関数を提供しています。

```python
# 配列の加算
array_sum = array_1d + np.array([10, 20, 30, 40, 50])
print("配列の加算結果:", array_sum)

# 行列の積
matrix_product = np.dot(array_2d, array_2d.T)
print("行列の積:\n", matrix_product)
```

### ユースケースの紹介

NumPyは、データ分析や科学計算の分野でさまざまなユースケースに利用されています。ここでは、簡単なデータ分析の例を紹介します。

#### データ分析の例：平均と標準偏差の計算

以下のコードは、NumPyを使用してデータセットの平均と標準偏差を計算する例です。

```python
# データセット
data = np.array([23, 45, 12, 67, 34, 89, 56])

# 平均の計算
mean_value = np.mean(data)
print("データセットの平均:", mean_value)

# 標準偏差の計算
std_deviation = np.std(data)
print("データセットの標準偏差:", std_deviation)
```

このトレーニングコースを通じて、NumPyの基本的な機能を理解し、実際のデータ分析に応用するスキルを身につけることができます。

NumPyをマスターすることで、Pythonでの数値計算がより効率的かつ効果的になるでしょう。
【たぶん真似るだけ】AWS EC2上に、Laravel Sailで動作環境を構築する

ふとしたきっかけで、Laravel Sailを用いて作ったプロジェクトを、せっかく作ったのでWEBに公開できるよう準備しようと思い立ちましたので、AWS上に環境を構築しました。

ちなみに作成したプロジェクトは公開されております。

https://github.com/WdknWdkn/oneonone

しかしsailが便利すぎて「あんなたくさんのコンテナに該当する環境、いちいち作っとられるかい！」と率直に思い、「もうええわEC2上に同じようにsailで環境作ったらそれでいったんよし」という死ぬほど雑な思考で「とりあえず動くもの」ということで環境構築しました。

まじで恥ずかしい。

# 概要

パブリックサブネット内に立ってるEC2上での作業内容になります。

# 実作業記録
## プロジェクトのクローン
### Gitのインストール

```shell
# システムのパッケージを更新
sudo yum update -y
# Gitをインストール
sudo yum install git -y
```

### SSHキーの作成

```shell
# RSA 4096ビットのSSHキーを作成
ssh-keygen -t rsa -b 4096 -C "sample@hogehoge.jp"
```

### SSHの公開鍵を取得

```shell
# ホームディレクトリに移動
cd
# .sshディレクトリに移動
cd .ssh
# ディレクトリの内容を表示
ls
# id_rsa.pubファイルを表示
less id_rsa.pub
# → 取得した公開鍵はGitLabに設定
```

### プロジェクトのクローン

```shell
# /homeディレクトリに移動
cd /home
# ssm-userディレクトリに移動
cd ssm-user
# プロジェクトをクローン
git clone <プロジェクト指定>
```

## Dockerのインストール

```shell
# システムのパッケージを更新
sudo yum update -y
# Dockerをインストール
sudo dnf install -y docker
# Dockerサービスを開始
sudo systemctl start docker
# Dockerサービスを自動起動に設定
sudo systemctl enable docker
# Dockerグループに現在のユーザーを追加
sudo usermod -aG docker $USER
# Dockerグループにssm-userを追加
sudo usermod -aG docker ssm-user
# シェルを再起動してグループ変更を反映
exec $SHELL -l
# Docker Composeをインストール
sudo curl -L "https://github.com/docker/compose/releases/download/v2.5.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# Docker Composeの実行権限を設定
sudo chmod +x /usr/local/bin/docker-compose
```

## Node.jsのインストール

```shell
# Node.js 20.xのセットアップスクリプトを実行
curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash -
```

## プロジェクトディレクトリに移動

```shell
# プロジェクトディレクトリに移動
cd （プロジェクトディレクトリパス）
# ディレクトリの内容を表示
ls
```

## PHPとComposerのインストール

```shell
# PHPと関連パッケージのインストール
sudo dnf install -y php-cli php-json php-zip wget unzip
# Composerのインストールスクリプトをダウンロード
curl -sS https://getcomposer.org/installer | php
# Composerをグローバルにインストール
sudo mv composer.phar /usr/local/bin/composer
# Composerの実行権限を設定
sudo chmod +x /usr/local/bin/composer
```

## Composerでパッケージをインストール

```shell
# PHPのXMLとDOMパッケージをインストール
sudo dnf install -y php-xml php-dom
# Laravel Sailをプロジェクトに追加
composer require laravel/sail --dev
# sailコマンドのエイリアスを設定
alias sail='[ -f sail ] && bash sail || bash vendor/bin/sail'
```

## .envファイルの作成

```shell
# .env.exampleをコピーして.envを作成
cp .env.example .env
# .envファイルを編集
sudo vi .env
```

## コンテナ立ち上げ

```shell
# コンテナ立ち上げ（なぜかssmで入り直したらできた）
exec $SHELL -l
sudo systemctl status docker
sudo systemctl restart docker
cd （プロジェクトディレクトリパス）
./vendor/bin/sail up -d
```

## artisanで準備

```shell
./vendor/bin/sail php artisan key:generate
./vendor/bin/sail php artisan migrate
```

## vite.config.jsを編集

以下追加

```javascript
  server: {
    host: '0.0.0.0',  // 外部からのアクセスを許可するため
    port: 5173,  // Viteサーバーのポート番号
    hmr: {
      host: '18.182.107.191',  // EC2のパブリックIPアドレス
      port: 5173,
    },
  },
```

### viteの再起動

```shell
./vendor/bin/sail npm run dev
```

## AWSのセキュリティグループ設定

* vite用にセキュリティグループで5173を解放
* phpmyadmin用にセキュリティグループで8080を解放

# 終わり

さすがにできないことないだろと思いつつ、やってみてできるとやっぱりなるほどとなる場面が多数。でもさすがに恥ずかしすぎる環境構成なので、やってみた後から「ちゃんと作るか。。。」となったのは開発者のサガだと信じています。

マテ次回。
未経験者向け！基礎から学ぶJavaプログラミング講座

## 未経験でもJavaさえできれば働ける！それがIT業界！

こんにちは！プログラミングの世界へようこそ。この記事では、Javaの基礎を学ぶためのガイドを提供します。Javaは、オブジェクト指向プログラミング言語であり、Webアプリケーションからモバイルアプリまで幅広い用途で使用されています。ここでは、Javaの基本概念を理解し、実際にコードを書いてみることで、プログラミングの楽しさを体験していただければと思います。

## 第1章: Javaとは？

Javaは、1995年にサン・マイクロシステムズ（現在はオラクル）によって開発されたプログラミング言語です。プラットフォームに依存しない「Write Once, Run Anywhere（WORA）」の特性を持ち、どの環境でも動作することが可能です。Javaは、セキュリティ、パフォーマンス、移植性に優れており、多くの企業で採用されています。

## 第2章: Javaの開発環境を整える

Javaプログラミングを始めるためには、開発環境を整える必要があります。以下の手順でセットアップを行いましょう。

### 2.1 JDKのインストール

Java Development Kit（JDK）は、Javaアプリケーションを開発するためのツールキットです。オラクルの公式サイトから最新のJDKをダウンロードし、インストールしてください。

### 2.2 IDEの選択

効率的にコーディングを行うためには、統合開発環境（IDE）が便利です。初心者には、EclipseやIntelliJ IDEAが人気です。これらのIDEをインストールし、プロジェクトを作成してみましょう。

## 第3章: Javaの基本構文

Javaの基本構文を理解することは、プログラミングを始める第一歩です。ここでは、Javaの基本的なプログラムを作成し、実行してみましょう。

### 3.1 Hello, World!

最初に書くプログラムとして、Hello, World!を表示するプログラムを作成します。

```java
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}
```

このプログラムは、`Hello, World!`という文字列をコンソールに出力します。`main`メソッドは、Javaアプリケーションのエントリーポイントです。

### 3.2 変数とデータ型

Javaでは、データを格納するために変数を使用します。変数にはデータ型があり、整数、浮動小数点数、文字列などがあります。

```java
int number = 10; // 整数型
double pi = 3.14; // 浮動小数点数型
String greeting = "こんにちは"; // 文字列型
```

### 3.3 演算子

Javaには、さまざまな演算子があります。ここでは、基本的な算術演算子を紹介します。

```java
int a = 5;
int b = 3;
int sum = a + b; // 加算
int difference = a - b; // 減算
int product = a * b; // 乗算
int quotient = a / b; // 除算
int remainder = a % b; // 剰余
```

## 第4章: 制御構造

プログラムの流れを制御するための構造を学びます。

### 4.1 条件分岐

条件分岐は、プログラムの実行を条件によって分岐させるための構造です。

```java
int score = 85;
if (score >= 90) {
    System.out.println("優秀です！");
} else if (score >= 70) {
    System.out.println("良いです！");
} else {
    System.out.println("もっと頑張りましょう！");
}
```

### 4.2 ループ

ループは、同じ処理を繰り返し実行するための構造です。

```java
for (int i = 0; i < 5; i++) {
    System.out.println("カウント: " + i);
}
```

## 第5章: オブジェクト指向プログラミング

Javaはオブジェクト指向プログラミング（OOP）をサポートしています。ここでは、クラスとオブジェクトの基本を学びます。

### 5.1 クラスとオブジェクト

クラスはオブジェクトの設計図であり、オブジェクトはクラスのインスタンスです。

```java
class Dog {
    String name;
    int age;

    void bark() {
        System.out.println(name + "がワンワンと吠えています！");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog();
        myDog.name = "ポチ";
        myDog.age = 3;
        myDog.bark();
    }
}
```

## 第6章: まとめと次のステップ

Javaの基礎を学ぶことで、プログラミングの基本的な概念を理解することができました。これからは、より複雑なプログラムを作成し、実践的なスキルを磨いていきましょう。次のステップとして、Javaのライブラリやフレームワークを学び、実際のプロジェクトに取り組んでみてください。

Javaの学習は継続的なプロセスです。楽しみながら、少しずつスキルを向上させていきましょう！
8x8の回転を考える(270度回転)

参考

https://qiita.com/caa45040/items/94e0f1099714fdcdb885

x 過去ログを見よ
x ArduinoUnoの予定は、未定


結果

![o_coq297.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/02cca0d7-2582-6669-f35a-9fe7fe05143f.jpeg)



プログラム

オンラインコンパイラ

```c++





#define bit8_put(aa) for(int ii=8;ii!=0;ii--) \
{if(aa & 0x80){printf("1");}else{printf("0");}aa=aa<<1;}


// ビットマップデータ
unsigned char databytes[8] = 

{

0b01100110,
0b10101111,
0b10111111,
0b11011111,

0b01111110,
0b01111110,
0b00111100,
0b00011000

};

// ビットマップデータ
unsigned char databytes_90[8]={0,0,0,0, 0,0,0,0};


#include <iostream>
using namespace std;
int main(void){
    // Your code here!
    printf("START\n\n");
    int a; //一時ワーク

    printf("INPUT\n");
    for(int ii=0;ii<8;ii++){
        a = databytes[ii];
        bit8_put(a);
        printf("\n");
    }//for ii
    printf("\n");

    //int a; //一時ワーク
    int a_mask;
    for(int ii=0;ii<8;ii++){
        //処理
        
        //         12345678
        a_mask = 0b10000000;
        a = databytes[ii];// << ii;
        
        databytes_90[7] = databytes_90[7]|((a_mask & a)>>ii); a = a << 1;  
        databytes_90[6] = databytes_90[6]|((a_mask & a)>>ii); a = a << 1;
        databytes_90[5] = databytes_90[5]|((a_mask & a)>>ii); a = a << 1;
        databytes_90[4] = databytes_90[4]|((a_mask & a)>>ii); a = a << 1;

        databytes_90[3] = databytes_90[3]|((a_mask & a)>>ii); a = a << 1;
        databytes_90[2] = databytes_90[2]|((a_mask & a)>>ii); a = a << 1;
        databytes_90[1] = databytes_90[1]|((a_mask & a)>>ii); a = a << 1;
        databytes_90[0] = databytes_90[0]|((a_mask & a)>>ii);
    
    }//for ii

    printf("OUTPUT\n");
    for(int ii=0;ii<8;ii++){
        a = databytes_90[ii];
        bit8_put(a);
        printf("\n");
    }//for ii
    printf("\n");

}//main


```



```

START

INPUT
01100110
10101111
10111111
11011111
01111110
01111110
00111100
00011000

OUTPUT
01110000
11111100
11111110
01111111
00111111
11101110
10011100
01110000


```
足し算 (paizaランク D 相当) Python解答例

## 問題：２つの正の整数 a, b が半角スペース区切りで入力されるので a と b を足した数を出力してください。

※「掛け算」の問題では入力が改行区切りで与えられましたが、今回は半角スペース区切りで与えられます。

入力は以下のフォーマットで与えられます。
a b


### まず、Python3でinputとsplitを使用し、複数の値を受け取ります。
inputで複数の値を取得する際に、複数の値を取得する方法をまとめます。
指定された数の文字列を格納します。
```diff_python

# 入力された文字列を分割してaとbを取得します
a, b = input().split()

```

### 次に、Python3のmap()を用いて、全ての要素に関数を適用します。int関数を使った記述方法は以下の通りです。

```diff_python

# map()を使って入力された文字列をintを使って、数値として分割してaとbを取得します
a, b = map(int, input().split())

```

#### 数値として分割できているか心配な場合は、printを用いて出力して確認します。

```diff_python
# map()を使って入力された文字列をintを使って、数値として分割してaとbを取得します
a, b = map(int, input().split())
# 数値として分割できているか心配の場合は、printを用いて出力して確認します。
print(a)
print(b)

```

### あとは、足し算をするだけです。

```diff_python

# map()を使って入力された文字列をintを使って、数値として分割してaとbを取得します
a, b = map(int, input.split())

# aとbを足した結果を出力します。
print(a + b)

```
Javaで「文字クラスを使って色々な文字にマッチするパターンを記述する」の動作を確認してみた

# 概要

Javaで「文字クラスを使って色々な文字にマッチするパターンを記述する」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/start/regex/index8.html

# 実装

以下のファイルを作成しました。
```JSample8_1.java
import java.util.regex.*;

class JSample8_1{
  public static void main(String[] args){
    String regex = "Sun";
    Pattern p = Pattern.compile(regex);

    Matcher m1 = p.matcher("Today is Sunday");
    System.out.println(m1.find());  // true

    Matcher m2 = p.matcher("Sunrise");
    System.out.println(m2.find());  // true

    Matcher m3 = p.matcher("Ham Sandwich");
    System.out.println(m3.find());  // false
  }
}
```

以下のコマンドを実行しました。
```
$ javac JSample8_1.java 
$ java JSample8_1 
true
true
false
```

# まとめ

何かの役に立てばと。
Excelで未来を予測：What-If分析とシナリオマネージャーの活用法

# Excelで未来を予測しよう

ビジネスの世界では、将来の不確実性に備えることが重要です。そこで役立つのが、ExcelのWhat-If分析とシナリオマネージャーです。これらの機能を使いこなすことで、様々な状況下での財務予測や意思決定をサポートすることができます。

## What-If分析とは？

What-If分析は、「もし〜だったら」という仮定のシナリオを分析するツールです。例えば、「もし売上が10%増加したら利益はどうなるか」といった質問に答えることができます。

主な機能には以下があります：

1. シナリオマネージャー
2. ゴールシーク
3. データテーブル

今回は、特にシナリオマネージャーに焦点を当てて解説します。

## What-If分析を実行するために必要な情報

What-If分析を効果的に実行するためには、以下の情報を準備する必要があります：

1. 基本モデル：現在の状況を反映した財務モデルやスプレッドシート
2. 変動要素：分析したい変数（例：価格、販売数量、コストなど）
3. 計算式：変数の変更が結果にどのように影響するかを示す数式
4. 目標値：分析の結果として見たい指標（例：利益、売上高など）
5. シナリオ：検討したい異なる状況や条件のセット

## シナリオマネージャーの使い方

シナリオマネージャーを使うと、複数の仮定シナリオを作成し、比較することができます。

### 手順：

1. 「データ」タブから「What-If分析」を選択し、「シナリオマネージャー」をクリックします。
2. 「追加」ボタンをクリックし、新しいシナリオを作成します。
3. シナリオ名を入力し、変更したいセルを指定します。
4. 各シナリオの値を入力します。
5. 「概要」ボタンをクリックして、全シナリオの比較表を作成します。

## 活用例：販売戦略の検討

例えば、ある商品の価格と販売数量を変えた場合の利益を比較したいとします。以下のテーブルは、基本シナリオと2つのシナリオの比較を示しています。

| シナリオ名   | 商品価格 (円) | 販売数量 | 売上 (円)       | コスト (円) | 利益 (円)       |
|--------------|----------------|----------|------------------|--------------|------------------|
| 基本シナリオ | 1,000          | 100      | 100,000          | 70,000       | 30,000           |
| シナリオA    | 1,100          | 90       | 99,000           | 70,000       | 29,000           |
| シナリオB    | 1,000          | 120      | 120,000          | 84,000       | 36,000           |

### シナリオの説明：

- **基本シナリオ**: 現在の価格と販売数量での利益を示します。
- **シナリオA**: 商品価格を10%上げた場合の利益を示しますが、販売数量が減少しています。
- **シナリオB**: 商品価格をそのままにして販売数量を20%増やした場合の利益を示します。

このテーブルを使用することで、どの戦略が最も利益を生み出すかを視覚的に確認できます。

## What-If分析の実行手順

1. 基本モデルを作成：上記のテーブルをExcelで作成します。
2. 変動要素を特定：この例では、商品価格と販売数量が変動要素です。
3. 計算式を設定：売上 = 商品価格 × 販売数量、利益 = 売上 - コスト
4. 目標値を決定：この例では、利益が目標値です。
5. シナリオを作成：基本シナリオ、シナリオA、シナリオBを設定します。
6. シナリオマネージャーを使用：各シナリオの値を入力し、結果を比較します。

## まとめ

What-If分析とシナリオマネージャーは、ビジネスの意思決定を支援する強力なツールです。不確実な未来に対して、様々な可能性を検討し、最適な戦略を立てるのに役立ちます。
JLCPCBでのPCBAの注文の仕方

# 初めに
今回は秋月電子で販売されているLattice社のFPGAをDIP化する基板を設計し、JLCPCBに発注してみたいと思います。

使用するFPGAは以下の物を使用します。
https://akizukidenshi.com/catalog/g/g111003/

基板の発注には以下のJLCPCBを利用していきます。
[JLCPCB](https://jlcpcb.jp/ "JLCPCB")
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632959/873e55b9-22b0-f4e2-115d-d22ec1a10469.png" width="45%">

## 設計
データシートを参考にAutodesk社のEAGLEを用いて設計していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632959/8199d588-244a-d3d8-51bf-d02d51e6abcb.png)

回路を引いたらエクスポートするために、以下の水色で囲んだ工場マークの部分をクリックします。
![スクリーンショット 2024-08-07 040743.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632959/84c96454-5fc1-6377-9c55-515dc96c913a.png)

以下の画像の水色ので囲んだExport as ZIPの項目にチェックをつけ、水色で囲んだProcess Jobをクリックする事でエクスポートする事ができます。エクスポート先を指定する画面が出てくると思うので任意のフォルダーを選択してください。
![スクリーンショット 2024-08-07 040923.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632959/683c5af3-2998-90e1-3d82-21ae23186297.png)

## JLCPCBに注文
[JLCPCB](https://jlcpcb.jp/ "JLCPCB")
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632959/873e55b9-22b0-f4e2-115d-d22ec1a10469.png" width="45%">
上記のJLCPCBのリンクにアクセスしてください。トップページに行き、以下の画像の水色で囲まれた部分に先ほどエクスポートしたファイルをアップロードしてください。あとは配送方法等を選択する事で簡単に注文する事ができます。
![スクリーンショット 2024-08-07 041420.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632959/4aadde58-a08c-4545-9c91-eaf66cee7a15.png)


## 届いた！
実際に届いた基板が以下のような通りです。2週間ほどで届きました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632959/1f67de63-6027-d007-fecc-44ca23438ff1.jpeg" width="45%">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632959/06d7b2f6-5652-98e2-744f-b082c500355f.jpeg" width="45%">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632959/c68552c3-8732-3be6-d5b6-33e0a8112b23.jpeg" width="45%">


[JLCPCB](https://jlcpcb.jp/ "JLCPCB")
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632959/873e55b9-22b0-f4e2-115d-d22ec1a10469.png" width="45%">
第２級アマチュア無線技士　合格体験記

# はじめに
合格体験記として残します。ついに私としては念願の二アマ取得です。やったね！

# Who am i ?
しがないエンジニアです。過去にアマチュア無線の資格はいくつか取得しています。

https://qiita.com/forest_moririri/items/e53fe4fc8e0635969a6b

https://qiita.com/forest_moririri/items/c67f34da7c40c015e355

# この記事の想定読者
特にないです。

# 本題
JARDさんのEラーニングで二アマを取得しました！正直、二アマともなると四アマ三アマと比較して難しいです。特に無線工学に関しては本質的なことを問われる設問が多かったように感じます。高校や大学の教養範囲で習う電磁気とはまた異なる面白さがありました。また参考情報ですが、JARDさんのEラーニング経由で二アマを取得するとHAMtteの二アマ修了生コミュニティへのアクセス権が付与され、そこで情報交換ができたりします。またHAMtteはアマチュア無線を楽しむ中で色んな割引が受けられるため便利です。

勉強方法ですが、「たくてれ。」さんという方が公開されている動画が大変わかりやすいので、もし興味ある方はご参考にされてください。

https://www.youtube.com/watch?v=FFdTmCndsNc&t=290s

# 振り返り
試験には合格しましたが、いまいち血肉になった感じがしません。本質的なことを勉強しようとするとトランジスタや電気回路の専門書を読まないといけないんですかね。トランジスタ周りはググったレベルでしか知らないので何ともという感じです。試験のための勉強を何とかこなしただけなので、トランジスタ周りはもっと勉強しようかなと思います。ただ一旦は念願叶ったりなので満足です。

# 今後
私の場合は移動局前提なので空中線電力最大50W程度の予定です。何だかんだでFPVドローン用途でしかアマチュア無線の開局をしなかったので、無線機買いたいです!!二アマでしか出ることができない周波数バンドもワッチしたいですね。一アマは夢ですが試験の動向だけウォッチしようかと思ってます!


# 最後に
よいハムライフを！！
MikanOS 2章

## 2.1
EDK2: UEFI BIOS自体の開発にも、UEFI BIOS上で動くアプリケーションの開発にも使うことができる開発キット


## 2.2
1章では直接UEFIアプリケーションを書いてたけど、EDKを使うことで、楽に書けるようになる。

workflow
```
edit mikanOS
cd $HOME/edk2
(ln -s $HOME/workspace/mikanos/MikanLoaderPkg ./)
(source edksetup.sh)
build
$HOME/osbook/devenv/run_qemu.sh Build/MikanLoaderX64/DEBUG_CLANG38/X64/Loader.efi
```

## 2.3 メモリマップ
メインメモリのどの部分がどんな用途で使われているかを示した地図

| PhysicalStart | Type | NumberOfPages | 
| ---- | ---- | ---- |
| 0x0000000 | EFIBootServiceCode | 0x9F |
| 0x0000100 | EFIConventinalMemory | 0x700 |
| ... | ... | ... |

PhysicalStart : そのメモリ領域がどこから始まるか
Type: そのメモリ領域が何に使われているか
NumberOfPages: メモリ領域の大きさをページ単位で表したもの。(1ページ: 4KiB)

## 2.5 メモリマップの取得
メモリマップ
→メモリディスクリプタの配列

メモリディスクリプタの構造
| Field name | Type | explanation | 
| ---- | ---- | ---- |
| Type | UINT32 | メモリ領域の種別 |
| Physical Start  | EFI_PHYSICAL_ADDRESS | メモリ領域先頭の物理アドレス |
| Virtual Start | ... | ... |
| ... | ... | ... |
（私事）chatGPTの影響でQiitaの更新頻度が下がった

# （私事）chatGPTの影響でQiita更新頻度が下がった
自分のQiitaの記事は新規性とか難解な物をやさしくとかそういう物は一切無くてメモ書きみたいな記事が多いのですが、それでもある程度は誰かは必要とするかも？程度の期待は込めて記事を更新しています（本当にただのメモの時もある）
最近はchatGPTに尋ねると簡単な疑問に対してはだいたい正解が返ってくるのでなにか思いついたりつまづいた事を解決しても「これは書かなくていいな」となります、chatGPTの写経しても意味ないと思うので。
AIが良いとか悪いとか言いたいわけではなくAIの影響で記事書くモチベを下げた人間がここに居て多分それは自分だけではないのではと思いました。
lsオプションを使って、Ｅｘｃｅｌ貼り付けを楽にしたい

## :point_up:調べようと思ったきっかけ
ファイル情報の取得と証跡や検証として出力するのは1日に何回も行っているのですが、現状とても効率が悪いと思って調べてみました。

**現状**
findで取得したディレクトリ配下のファイルをlsコマンド形式でテキストとして出力する▼
```
find /BENKYO -type f | xargs -r ls -l --time-style=+'%Y%m%d %H:%S' > BENKYO.txt
```
出力されたテキストをExcelにコピペする
★セル1つに横並びの1行が入ってしまうので区切り文字を使って都度データの整理を行う

今回省略したい手順は★の行

### 方法その１(?)
出力されたテキストをExcelに貼り付ける前にメモ帳に貼って、スペースをタブに置換する
➡別ツールを起動しなくてはならない手間がある
➡タブキーは多くの機能を持っているため、タブスペースを置換後として認識させるには、別で用意したタブスペースをコピペする必要がある
➡不採用

### :point_up:point_up方法その２
以下オプションのついたコマンドを実行する
```
tr -s ' ' '￥t'
```
説明：ls形式で出力されるリストのスペースをタブで表示させる
実用例▼
```
find /BENKYO -type f | xargs -r ls -l --time-style=+'%Y%m%d %H:%S'| tr -s ' ' '￥t' > BENKYO.txt
```
レコード間がタブスペースとして出力されてあるため、そのままExcelにコピペすると自動的にそれぞれのセルにそれぞれのデータが分けられる。
➡コマンドに即反映させられるので手間がかなり省ける
➡採用

#### :point_up:その他
findコマンドに -mathdepth 1 を足すと、指定したディレクトリ直下のファイルのみを参照してくれる▼

```
find /BENKYO -maxdepth 1 -type f | xargs -r ls -l --time-style=+'%Y%m%d %H:%S'| tr -s ' ' '￥t' > BENKYO.txt
```


## 参考
[【Linux】ls -lコマンドの実行結果をタブ区切りで取得する](https://syutaku.blog/linux-cmd-ls-tab-delims/)
Android Studio で Markdown のプレビューが表示されなくなった問題

# 現象

Android Studio で .md形式のファイルを編集する際、プレビューを表示するには、画面下部にある「Markdown Split Editor」タブを押します。

![markdown-split-editor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43328/333917e2-f975-46ef-5cda-5849c70784b0.png)

しかしどういうわけか、このタブが表示されないという問題が生じました。

**環境**
* macOS Sonoma 14.5
* Android Studio: Koala 2024.1.1 Patch 1
* Markdown（プラグイン）: bundled 241.18034.62.2411.12071903


# 解決策

以下の手順で、IDEの使用する Java Runtime を変更します。（開発するアプリのJavaバージョンとは関係ありません。）

こちらの回答を大いに参考にしました。
[Where is Android Studio Markdown support plugin preview preference? - StackOverflow](https://stackoverflow.com/a/71063742)

## 1. Boot Java Runtime の選択画面を開く

1. Shift キーを素早く2回押します。
2. すると Find Action ポップアップが表示されます。
3. 「choose」とタイプすると `Choose Boot Java Runtime for the IDE` が表示されるので選択します（画像）。

![find-action-choose.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43328/42e4deba-f9ac-9d4a-9442-f229093edac4.png)

## 2. "with JCEF" と書かれたバージョンを選択する

1. `New`のコンボボックスをクリックすると、選択可能な Runtime が一覧されます。
2. `Current` のバージョンに近く、`with JCEF` と書かれたバージョンを選択します。
3. `OK` を押して閉じます。

![choose-runtime.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43328/fb267059-fac0-fc51-8575-9d261c9788a2.png)

末尾の数字が大きいほど新しいです。ひとまず執筆時点で最新のバージョンを選択しました。

## 3. Android Studio を再起動

1. 初回は Runtime をダウンロードするので少し時間がかかります。
2. 準備ができたらIDEを再起動（Restart）するかと聞かれるので、再起動する方を選びます。
3. 再起動したら画面を確認してください。最初に示したタブが表示されるはずです。
4. 右上のアイコンから、markdown・両方・プレビューのみ表示を切り替えられます。


# まとめと補足

IDE の Java Runtime を変更することにより、markdown プレビューを表示するよう設定しました。


### 補足1 - JCEF
変更先の JCEF についてや、なぜ変更する必要があるかは、こちらの記事がわかりやすかったです。
[IntelliJ IDEA 2020.2でJavaFXのランタイムが同梱されなくなりました - AOEの日記](https://aoe-tk.hatenablog.com/entry/2020/07/29/200740)

### 補足2 - デフォルトへの戻し方
元の Runtime に戻す場合は `Choose Boot Runtime for the IDE` のダイアログ左下の `Use Default Runtime` を押します。
Basic認証の導入ガイド

### 概要
Basic認証とは、HTTP通信の規格に備え付けられているユーザー認証の仕組みです。サーバーと通信できるユーザー名とパスワードをあらかじめ設定し、それに一致するユーザーのみがWebアプリケーションを利用できるようにします。この記事では、RailsアプリケーションにBasic認証を導入する方法を簡単に説明します。

### 1. Basic認証の設定方法

#### 1.1 コントローラーでの設定
`authenticate_or_request_with_http_basic`メソッドを使用して、開発中のRailsアプリケーションにBasic認証を導入します。以下の例では、ユーザー名`admin`とパスワード`password`で認証を行います。

```ruby
class ApplicationController < ActionController::Base
  before_action :basic_auth

  private

  def basic_auth
    authenticate_or_request_with_http_basic do |username, password|
      username == 'admin' && password == 'password'
    end
  end
end
```

#### 1.2 すべてのページでBasic認証を適用
上記のコードを`ApplicationController`に追加することで、アプリケーションのすべてのページでBasic認証が適用されます。

### 2. セキュリティの向上: 環境変数の利用
コードにユーザー名とパスワードを直接記述すると、公開リポジトリでソースコードを管理している場合、不正にBasic認証を突破されるリスクがあります。この対策として、環境変数を利用します。

#### 2.1 開発環境での環境変数の設定
まず、開発環境の環境変数にユーザー名とパスワードを設定します。

1. ターミナルを開き、`.zshrc`ファイルを編集します。
   ```sh
   vim ~/.zshrc
   ```

2. 以下の行を追加して、ファイルを保存します。
   ```sh
   export BASIC_AUTH_USER='admin'
   export BASIC_AUTH_PASSWORD='password'
   ```

3. ファイルの変更を反映するために`source`コマンドを実行します。
   ```sh
   source ~/.zshrc
   ```

#### 2.2 Railsアプリケーションでの環境変数の使用
環境変数を読み込むように、`basic_auth`メソッドを修正します。

```ruby
class ApplicationController < ActionController::Base
  before_action :basic_auth

  private

  def basic_auth
    authenticate_or_request_with_http_basic do |username, password|
      username == ENV["BASIC_AUTH_USER"] && password == ENV["BASIC_AUTH_PASSWORD"]
    end
  end
end
```

### 3. 動作確認
環境変数が正しく設定されているか確認するために、サーバーを再起動し、任意のページにアクセスしてBasic認証の動作を確認します。間違った情報ではログインできないこと、正しい情報でログインできることを確認しましょう。

### 4. 本番環境での設定
本番環境でも同様に環境変数を設定します。例えば、HerokuやRenderなどのホスティングサービスを利用している場合、それぞれのサービスのダッシュボードから環境変数を設定します。

#### 4.1 Renderなどのサーバーでの環境変数設定
1. Renderのダッシュボードにアクセスし、該当するアプリケーションを選択します。
2. メニューの「Environment」を選択し、以下の環境変数を追加します。
   - `BASIC_AUTH_USER`: `admin`
   - `BASIC_AUTH_PASSWORD`: `password`

### 5. Basic認証の制限と注意点
Basic認証は手軽に導入できる認証方式ですが、以下のような制限があります。
- 認証情報はBase64でエンコードされて送信されるため、暗号化されていません。SSL/TLSを使用して通信を暗号化することが推奨されます。
- ログアウトの概念がないため、セッション管理が難しい場合があります。

このガイドを参考にして、開発中のWebアプリケーションやポートフォリオにBasic認証を導入してみました。

※セキュリティ関連のため今回は実際のコードをお見せすることができません💦
ぶるぶる


@keyframes wiggle {
    0% { transform: rotate(0deg); }
    80% { transform: rotate(0deg); }
    85% { transform: rotate(5deg); }
    95% { transform: rotate(-5deg); }
    100% { transform: rotate(0deg); }
  }
  
  .wiggle:focus {
    display: inline-block;
    animation: wiggle 0.5s;
  }
ApexでIPv4アドレスを整形

```apex
  // IPv4アドレスを整形 (111.11.01.001 → 111.11.1.1)
  public static String formatIPv4Address(String ipAddress) {
    String[] octets = ipAddress.split('\\.');
    if (octets.size() != 4) {
      return null;
    }
    String formattedIpAddress = '';
    for (Integer i = 0; i < 4; i++) {
      if (i != 0) {
        formattedIpAddress += '.';
      }
      formattedIpAddress += Integer.valueOf(octets[i]).toString();
    }
    return formattedIpAddress;
  }
```
Excelの翻訳関数がすごい[TRANSLATE関数/DETECTLANGUAGE関数]

## すごい関数がきていたよ～～
Copilotに夢中になっていて、Excelの新機能を追っていなかったことを反省。
なんとExcel上で100言語以上に翻訳が可能なTRANSLATE関数と、何語か判別するDETECTLANGUAGE関数がきておりました。（ちなGoogleはずっと前から翻訳関数あるため普通に遅れています…ｗ）

関数のジャンルとしては文字列操作のグループに入っていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/e5c15541-6f80-e464-90a9-ff20147d0692.png)

これはすごい！！Excelで申請書やマニュアルを作成していて、多言語展開が必要な場合にいちいちGoogle翻訳やAI翻訳しなくてもいけちゃいますね！
マニュアル等が修正になっても元の言語だけ直せばいいだけなのが熱い。
お役所とか、ホテルとか、飲食店とか助かるんじゃない。

## TRANSLATE関数について
### 仕組み
裏側でMicrosoft Translation Servicesを使っています。
なんと対応言語は100言語以上。
インターネットにつながっていないと翻訳できないため、オフライン環境では利用することができません。
関数の引数に翻訳する元の文書、翻訳元言語、翻訳後言語を指定します。

```text:引数
=TRANSLATE(text, [source language], [target language])
```

https://support.microsoft.com/ja-jp/office/translate-function-d34f71c7-2ffe-409a-9a63-5eb5e91aa3dd

### 対応言語
Microsoft Translation Servicesの仕様に基づくようですが、ちょっとちがうかも。
英語で試してみましたが処理限界は1セルで3000文字くらいまででした。（Microsoft Translation Servicesのドキュメントには5万字とある。）

https://learn.microsoft.com/ja-jp/azure/ai-services/translator/language-support

## DETECTLANGUAGE関数について
### 仕組み
TRANSLATE関数とセットでリリースされたのが、DETECTLANGUAGE関数。
文字列が何の言語か判別してくれます。
こちらも仕組みとしてはMicrosoft Translation Servicesを使っています。

```text:引数
=DETECTLANGUAGE(text)
```

https://support.microsoft.com/ja-jp/office/detectlanguage-function-0748e285-1912-4d24-b735-57d18142fa3b

## ためしてみた
### 言語の特定

Copilotで適当につくった文章で、ひとまずDETECTLANGUAGE関数で言語を特定しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/c862227f-5e73-b1fa-1b54-68844bacdaa5.png)

うおお、いい感じです。

### 和訳してみた

次に全部和訳してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/52adbbc6-1036-26e2-ede3-129362fb9cf9.png)

うんうん、いいかんじ。ちなみに翻訳後の言語については引数なしにするとデフォルトの設定言語になるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/15928d11-5f25-aa23-95dc-d5a0604dafb3.png)

### 動的な変更

言語メニューみたいなのを作っておいてプルダウンやボタンの押下で切り替えとかもいいかも。

![無題の動画.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/49c1fa46-680d-69d2-0af1-12582cd13ed8.gif)


というわけで今日もExcelが本当にきもくて大好き（ほめている）
【Ruby】whileの戻り値を正しく把握していなかった


素のRubyを用いてちょっとした業務カイゼンアプリを作ってたのだが、そのときにほんの少しだけ当たった問題

※ 鬼基本的な内容です

# `while`は`nil`を返します

※単一ファイルで書かれたスクリプトを想定しています

「渡ってきた日付（`date`オブジェクト）が土日祝のいずれかに当てはまるかを判定し、当てはまる場合は平日になるまで1日ずつ日付を加算する」という処理を作っていた

- 日付を加算するには`date`オブジェクトに`+ 1`をしていけばよい
- 土日の判定はDateクラスにある`saturday?`や`sunday?`が、日付が土日の場合に`true`を返す
- 日本の祝日判定は`HolidayJp`というGemのメソッドを使えば同じように祝日に当てはまるとき`true`を返す
    - [holiday-jp/holiday_jp-ruby: Japanese holiday.](https://github.com/holiday-jp/holiday_jp-ruby)
- 上記が`true`のときに日付を1日加算したい

→ **条件が`true`のときに処理をループさせることができる`while`使えばいいのでは？** と思い以下のような処理を書いた

```ruby
while day.saturday? ||
      day.sunday? ||
      HolidayJp.holiday?(day)
    day += 1
end
```

実際に試してみる
```ruby
# 日曜日
day = Date.new(2024, 8, 11)
=> #<Date: 2024-08-11 ((2460534j,0s,0n),+0s,2299161j)>

while day.saturday? ||
      day.sunday? ||
      HolidayJp.holiday?(day)
    day += 1
end

p day
=> #<Date: 2024-08-12 ((2460535j,0s,0n),+0s,2299161j)>

# ちゃんと平日である８月12日㈪が返ってきた！
```

期待した値が返ってきたのでOK

ただこの処理はスクリプト内のいたるところで使用していたので、メソッドにしたいと思いメソッド化した

```ruby
# 日曜日
day = Date.new(2024, 8, 11)

def check_weekend_return_weekday(day)
  while day.saturday? ||
        day.sunday? ||
        HolidayJp.holiday?(day)
    day += 1
  end
end

weekday = check_weekend_return_weekday(day)
p weekday
```

「ま、ふつうになんも問題ないやろ」と思ってたら。。。。。。。。。

```
nil
```

ohhhhhhhhhhhhhhhhhhhhhhhhh

なぜだ、、、と思ってリファレンス見てみたら普通に答え書いてあった

> while は nil を返します

公式: [制御構造 (Ruby 3.3 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/doc/spec=2fcontrol.html#while)

Rubyはメソッドの最後に評価された式が戻り値になるので`while`自体が`nil`を返すなら`nil`が返ってくるのは当たり前だ。。。。

# メソッド内でwhileで処理した値を返したい場合は`break`か戻り値を明示させよう

なので修正
公式には以下のように書いてある

> また、引数を伴った break により while 式の戻り値をその値にすることもできます。

公式: [制御構造 (Ruby 3.3 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/doc/spec=2fcontrol.html#while)

というわけで返したい値に`break`を明示させておこう
```ruby
# 日曜日
day = Date.new(2024, 8, 11)

def check_weekend_return_weekday(day)
  while day.saturday? ||
        day.sunday? ||
        HolidayJp.holiday?(day)
    break day += 1 # breakを明示
  end
end

weekday = check_weekend_return_weekday(day)
p weekday

=> #<Date: 2024-08-12 ((2460535j,0s,0n),+0s,2299161j)>
```
ちゃんと返ってきた！

当然だが`break`使わないでメソッドの最後に戻り値を明示させるだけでもOK

```ruby
# 日曜日
day = Date.new(2024, 8, 11)

def check_weekend_return_weekday(day)
    while day.saturday? ||
          day.sunday? ||
          HolidayJp.holiday?(day)
      day += 1
    end
  day # メソッドの最後に戻り値を明示
end

weekday = check_weekend_return_weekday(day)
p weekday

=> #<Date: 2024-08-12 ((2460535j,0s,0n),+0s,2299161j)>
```


基本的なことだが忘れないようにしよう