OmniAICreator/Qiita-1.07M huggingface dataset:
Git ブランチの命名規則

# Gitのブランチ命名規則
gitでブランチを切る時,ブランチに命名規則があります。
普通の学習だとmainやmasterからブランチを切ったりしますが実務ではありえないです。
developやfeatureからブランチを切ったりします。


# 命名規則の種類
命名規則の種類です。


|ブランチ名|役割|派生元|マージ先|
|--|--|--|--|
|***master***|　公開するものを置くブランチ||ここのブランチの環境でリリースされます。ブランチの起点みたいなイメージ|
|**develop**|開発中のものを置くブランチ　(このdevelppブランチからfeatureなどブランチを切っていきます)|master|master|
|**release**|次にリリースするものを置くブランチ|develop	|develop, master|
|***feature-****|　新機能開発中に使うブランチ|　develop	|　　develop|
|***hotfix-****|公開中のもののバグ修正用ブランチ|master|　develop,　master|

- ***補足***
1.***feature-〇〇やhotfix-〇〇で、〇〇には適当な名前をつける***
2.***いきなりmasterからブランチを切って作業はないので、developブランチはmasterブランチのクッションのような役割***




これらが命名規則になるので現場にこれから入る方は気をつけましょう。

# 具体的にどんなふうに書くか
具体的には以下のように書いたりします。(現場によって多少変わることはあります)
```
taro% git branch              
* development
  feature/36
```
⚫︎補足
・developではなくdevelopmentと書く場合あり
・36はタスクの番号

## 例外もあり
ブランチ運用で例外もあります。

- いきなり***mainブランチにプッシュする現場(基本的にはdevelopブランチを使う)***
- ***Web系でもGitを使わない現場(大半はGit)***
- ***featureなどを使わずにissue-〇〇***みたいな運用(〇〇はissue番号)

***現場によってブランチ名の付け方も変わってきたりします***。
***現場のルールを確認しておきましょう***。



# 参考資料

https://qiita.com/homhom44/items/9f13c646fa2619ae63d0

https://qiita.com/c6tower/items/fe2aa4ecb78bef69928f
【Quill】editorの内容を書き換える

Quillエディタの中身を更新するとき、HTML構成に沿って書き換えないといけません。
ちゃんと理解してなかったし、詰まったので、メモ。

###QuillのHTML
自分のコードのHTMLはこれだけしか書かれてないんです。

```html
<div id="editor"></div>
```
ですが、開発者ツールで見れば実体はこんな感じ。

```html
<div id="editor" style="width:100%; height:300px;" class="ql-container ql-snow">
　<div class="ql-editor" data-gramm="false" contenteditable="true"></div>
　<div class="ql-clipboard" contenteditable="true" tabindex="-1"></div>
　<div class="ql-tooltip ql-hidden">
　　<a class="ql-preview" target="_blank" href="about:blank"></a>
　　<input type="text" data-formula="e=mc^2" data-link="https://quilljs.com" data-video="Embed URL">
　　<a class="ql-action"></a>
　　<a class="ql-remove"></a></div>
</div>
```

Quillエディタの中身を書き換える時、書き換えるのは#editorの中身ではなく、.ql-editorの中身です。
(これにハマった。)

ですので、こう書き換えます。

```js
$('.ql-editor').html('<p>Hello World!</p>');
```

以上です。
gitのログを見やすくする

# 概要
- `git log`の結果を見やすくする

# git log
## 一行でログを見やすく表示する
### 表示したいもの
- コミットのハッシュ
- 日付
- コミットメッセージ
- ブランチ名(refs)

### コマンド
```
$ git log --date='format-local:%Y/%m/%d %H:%M:%S' --pretty='format:%C(yellow)%H %C(green)%ad %C(reset)%s %C(red)%d'
```
```
7d556dc5d8ad4a49f2b85b06506c9cad4f824292 2021/08/04 22:08:19 feat: Gitのログを1行で表示する  (HEAD -> feat/git_log_oneline)
7e2b7d1d9e169b73eb258d8e9062b0c88bab89b0 2021/08/04 21:43:34 Initial commit  (origin/main, origin/HEAD, main)
```

#### オプション
- `--date='format-local:%Y/%m/%d %H:%M:%S'`
    - 日付のフォーマットを指定する
- `--pretty='format:<フォーマット>'`
    - デフォルトの書式以外の形式で出力する
        - `%C(<color>)`・・・色指定
        - `%H`・・・コミットのハッシュ
        - `%ad`・・・Authorの日付
        - `%s`・・・コミットメッセージ
        - `%d`・・・ブランチ名(refs)

# 参考
- [Git-の基本-コミット履歴の閲覧](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E5%9F%BA%E6%9C%AC-%E3%82%B3%E3%83%9F%E3%83%83%E3%83%88%E5%B1%A5%E6%AD%B4%E3%81%AE%E9%96%B2%E8%A6%A7])
    - [Git - pretty-formats Documentation](https://git-scm.com/docs/pretty-formats#Documentation/pretty-formats.txt)
文字列を分解する

#今回の内容
* 取得してきたDateを"/"を除いて分解し、配列に入れる

# コードと簡単解説

##文字列を分解

* まずはtodayDateに、"/"で区切られたDate( )を取得してきます。（今回は2021/08/04を取得）

* `文字列.components(separatedBy: 除きたい部分)`で除きたい部分を取り除くことが出来ます。(今回は"/")

```Swift:
        let dateformatter = DateFormatter()
        dateformatter.timeStyle = .none  
        dateformatter.dateStyle = .medium
        dateformatter.locale = Locale(identifier: "ja_JP")
        todayDate = dateformatter.string(from: Date())
        
        let disassemblyDateArray = todayDate.components(separatedBy: "/")
        print(disassemblyDateArray)
        print(disassemblyDateArray[0],disassemblyDateArray[2])

```

```:デバッグエリア
        ["2021", "08", "04"]
        2021 04
```
#終わり
ご指摘、ご質問などありましたら、コメントまでお願い致します。
VSCodeの空白・全角空白・タブ文字が見づらいのをなんとかする

# 概要
VSCodeの空白文字が見づらく、tabと空白が混ざったりとか行末空白とかに気づけない、という事が何度かあったので、なんとかなるようにしました

# 解決策概要
拡張機能の `whitespace+` を使いました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282159/439ed3f7-672d-da3a-91ea-413e593388e4.png)

「ホワイトスペースを目立たせるやつ」なんですが、実態は「任意の正規表現にヒットした文字列に、任意の背景色をつける」でした。

# 解決策詳細

拡張機能インストールののち、コマンドパレットで `>Whitespace+ Config` すると、config.jsonが開きます。
それをこうしました。

```json:config.json
{
	"mode": "all",
	"autoStart": true,
	"refreshRate": 100,
	"elements":
	[{
		"name": "タブ文字は目障りにならない程度に色付けする",
		"enabled": true,
		"pattern": "\\t",
		"style": {
			"dark": {
				"backgroundColor": "rgb(48, 48, 48)"
			}
		}
	},{
		"name": "タブ文字と空白が隣り合わせてるやつ絶対許さない",
		"enabled": "true",
		"pattern": "\\t | \\t",
		"style": {
			"dark": {
				"backgroundColor": "pink"
			}
		}
	},{
		"name": "全角空白はめっちゃ目立たせる",
		"enabled": "true",
		"pattern": "　",
		"style": {
			"dark": {
		 		"backgroundColor": "pink"
			}
		}
	},{
		"name": "行末に空白文字があるのはめっちゃ目立たせる",
		"enabled": "true",
		"pattern": "[^\\S\\r\\n]+$",　
		"style": {
			"dark": {
				"backgroundColor": "pink"
			}
		}
	}]
}
```

# 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282159/7620705b-9b76-3de7-cb7e-bdc94c4b84bf.png)

ひとまず満足いく結果になりました。
連続スペースをタブと同様に扱ってもいいかもしれません。

# 設定ファイルの書式等

config.jsonの設定項目は、デフォルトではこんなかんじです。
ちょっと弄ってみるとけっこう柔軟に反応してくれたので、↑の設定は最小限まで絞り込みました。

```json:config.json.default
{
        "name": "space", # 任意なので、項目の説明にしたらいいと思う
        "enabled": true, # カーソル位置によっては色を変えないという設定ができる。詳細は拡張機能のページに記載してる
        "pattern": "\\s", # 正規表現が使える
        "style": {
            "borderWidth": "1px", # 対象文字列の背景の枠線の太さ。いらないと思ったので削った。
            "borderRadius": "2px", # 対象文字列の背景の角の丸め。いらないと（ｒｙ
            "borderStyle": "solid", # 対象文字列の背景の線。いらｎ（ｒｙ
            "light": { # ライトモードのときの色設定。自分はダークモードでしか使ってないので削った。
                "backgroundColor": "rgba(58, 70, 101, 0.3)",
                "borderColor": "rgba(58, 70, 101, 0.4)"
            },
            "dark": { # ダークモードのときの色設定。
                "backgroundColor": "rgba(117, 141, 203, 0.3)", # 背景色。rgb形式でも色名でもOK。
                "borderColor": "rgba(117, 141, 203, 0.4)" # 線の色。いらないと思ったので（ｒｙ
            }
        }
    }
```

空白に限らず任意の正規表現を設定できるので、他の用途も何かあるかもしれません。
こんなかんじ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282159/95a4b0e0-5e4d-16e1-8927-0d82bea5547b.png)
実務で使える！Laravel既存カラムの順番を変更する方法

暇なときに予定を探せるアプリ[yoteiPicker](https://yoteipicker.com/)をリリースしました。

Laravelのマイグレーションで既存カラムの順番を変更する方法を解説します。

laravelのバージョンは6系
mysqlは5.7系。
phpは7.4系です。

[＞＞フリーランスも対象！エンジニア転職におすすめなサイト5選](https://www.kamome-susume.com/enginner-job-change-site/
)

マイグレーションをすでに作成して、テーブルもできたのにカラムの順番を変更したい時ってあると思います。

booksテーブル
book_id
book_name
category_id

これを、以下のようにしたい。

booksテーブル
book_id
category_id
book_name

真っ先に考えられるのはchangeマイグレーションを作成して、afterで対応すればいいのでは？と思うかもしれませんが、うまくいかないんですよね。

そんな時は、以下の方法を試してみましょう。

まずは、カラムの順番を変更するマイグレーションファイルの作成

```
php artisan make:migration change_book_name_to_books_table --table=books
```

以下のようにマイグレーションファイルを編集。

```php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class ChangeBookNameToBooksTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('books', function (Blueprint $table) {
            DB::statement("ALTER TABLE books MODIFY COLUMN book_name varchar(255) NOT NULL AFTER category_id");
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('books', function (Blueprint $table) {
            DB::statement("ALTER TABLE books MODIFY COLUMN book_name varchar(255) NOT NULL AFTER book_id");
        });
    }
}
```

マイグレーションを実行。

```
php artisan migrate
```

このように既存テーブルにあるカラムの順番を変更できました。
![スクリーンショット 2021-08-04 22.18.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1693248/a35edd8e-17bf-5383-12db-ec98fbee67c4.png)

```
DB::statement("ALTER TABLE books MODIFY COLUMN book_name varchar(255) NOT NULL AFTER category_id");
```

ポイントは上記ですが、book_nameの後の`varchar(255) NOT NULL`を忘れずに記載してください。

今回はbook_nameの型は文字列(string)でnullを許容しないカラムだったので、このように書きました。
※マイグレーションファイルではstringだが、mySQLではvarcharであることに注意。

数値型の場合は、intとかになります。

他にも記事書いているので、ぜひプロフィールからご参照ください。
・マイグレーション
・クエリビルダなど
書いています。

暇なときに予定を探せるアプリ[yoteiPicker](https://yoteipicker.com/)をリリースしました。

[＞＞Laravelのマイグレーションが怖くない【作成・カラムの追加・削除】](https://qiita.com/kamome_susume/items/22fe17935bbd1760b7f7
)
[＞＞【Laravelクエリビルダ】複数のカラムをgroupByでグループ化させる
](https://qiita.com/kamome_susume/items/29a29c65356de9a0a272
)

[＞＞フリーランスも対象！エンジニア転職におすすめなサイト5選](https://www.kamome-susume.com/enginner-job-change-site/
)
[02] subprocessの代替パッケージ「sh」を使ってみる


|本シリーズのトップページ|
|:--|
|https://qiita.com/robozushi10/items/fabde36bb9a312347bc7|

# はじめに

一般的に Python で Linux コマンドを使う場合は `subprocess` を使うこと多い.
が、標準パッケージでは無いものの subprocess の代替である「`sh`」(`amoffat/sh`) も便利である.[^1]

個人的な考えではあるが、「sh[^2]」は標準パッケージでは無いので、職場などで使い込むと
他者の迷惑になり兼ねない。しかし、適度に使う分には `subprocess` よりも速く実装できて
好都合なので書き残しておく.


本項では「**<font color="blue">手抜きをして『sh』を使う場合</font>**」を記す.

この実装方法であれば <font color="blue">シェルスクリプトに近い感覚で実装できる</font>ので、
[前項](https://qiita.com/robozushi10/items/815748c274a3a54af4b2) とは異なり subprocess よりも速く実装できるのではないかと思う.


# セットアップ

pip 等で `sh` をインストールする.
詳細は本項末尾の「[参考情報](#参考情報)」に記した.


# 使用例

下記シェルスクリプト「001.sh」相当を、パッケージ「sh」を使って Python で実装する


## 001.sh

### 処理概要

<details><summary>前項と同じ内容である. (詳細はクリックすること)</summary><div>

001.sh の処理内容は、次の 1〜5 の処理である.
しかし、個人的には Python の subprocess でこの処理を実装しようとすると相当辛い.

\```
1. ディレクトリ /tmp/<一意な文字列>/ を作成する
2. ディレクトリ /tmp/<一意な文字列>/ に移動する
3. ファイル /tmp/<一意な文字列>/log を作成する
4. pwd と date の実行結果を /tmp/<一意な文字列>/log に追加書き込みする
5. ファイル /tmp/<一意な文字列>/log を表示する
\```
</div></details>


### コード

前項と同じ内容である.

```bash
#!/bin/bash
# 一意な値を生成して UUID に格納する
UUID=`uuidgen`
mkdir -p /tmp/$UUID
cd /tmp/$UUID
touch log
pwd  >> log
date +"%Y/%m/%d %H:%M:%S.%6N" >> log
echo "/tmp/$UUID/log に書き込みました"
cat -n /tmp/$UUID/log
```

### 実行結果

```
/tmp/a0db1349-a758-44c9-b017-2b90f184ba84/log に書き込みました
     1	/tmp/a0db1349-a758-44c9-b017-2b90f184ba84
     2	2021/08/04 20:44:44.374856
```

　

## 002.py

上述のシェルスクリプトを、Python パッケージ「sh」を使って <font color="blue">**手抜き実装した版**</font> である.

「`bash -c <コマンド>`」を使用しているので楽な記述になっており、
subprocess から置き換えるメリットがあるかと思われる.

なお、`cd` については `sh.cd(パス)` を使用しないと移動できないので注意すること.
これは bash -c だと別プロセスとして実行されているためだと推測している.


### コード

```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sh

if __name__ == '__main__':

  buf = sh.bash('-c', 'uuidgen').rstrip()
  UUID = sh.bash('-c', f'echo {buf} | sed "s/-//g"').rstrip()
  TMPDIR = f'/tmp/{UUID}'
  sh.bash('-c', f'mkdir -p {TMPDIR}')
  sh.cd(f'/tmp/{UUID}')
  sh.bash('-c', f'touch /tmp/{UUID}/log')
  sh.bash('-c', f'pwd >> /tmp/{UUID}/log')
  sh.bash('-c', f'date +"+%Y/%m/%d %H:%M:%S.%6N" >> /tmp/{UUID}/log')
  print(sh.bash('-c', f'echo "/tmp/{UUID}/log に書き込みました"').rstrip())
  for l in sh.bash('-c', f'cat -n /tmp/{UUID}/log'):
    print(l.rstrip())


```

### 実行結果

```bash
/tmp/19d2b497d10243a6bd19bf8194b78764/log に書き込みました
     1	/tmp/19d2b497d10243a6bd19bf8194b78764
     2	+2021/08/04 22:13:39.062400
```


# 参考情報

|項目|URL|一言|
|:--|:--|:--|
|Pypi sh|https://pypi.org/project/sh/||
|公式ドキュメント - トップページ|https://amoffat.github.io/sh/||
|公式ドキュメント - API逆引き|https://amoffat.github.io/sh/reference.html||
|チュートリアル|https://amoffat.github.io/sh/tutorials|ここで実現したい機能を検索しながら使うことが多い|
|もた日記|https://wonderwall.hatenablog.com/entry/2017/07/30/083000||


# 検討環境

```bash
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.4 LTS"
```

　

以上

[^1]: 私は職場で別の方が使用していて知った
[^2]: パッケージ名が「sh」だと検索し辛い..
[2021Aug] HTTP と HTTPS のサイト転送を AWS CloudFront Functions で

# はじめに

AWS CloudFront では HTTP Request / Response の加工などが可能で、Origin にアクセスせず Response を返すことも可能です。
この加工は別途用意した関数で処理されますが、関数の実行機構として新しく CloudFront Functions がデビューしたとのこと。
「S3 を使った転送と同等のことが CloudFront 単体で実現できる」ということだと解釈し、試してみました。


# 大まかな仕組み

- Viewer request に関連付けた CloudFront Functions 関数で転送する（Status Code 301 を返す Response を生成する）
- CloudFront の Alternate Domain Names 機能で名前付け、および、暗号化する
- DNS の CNAME or ANAME で（間接的に） IP Address 付けする

[S3 を利用する場合](https://qiita.com/teruo-oshida/items/0ad13fe5b4b32ff075e8)と比べると、転送機能を担っているのが S3 から CloudFront に代わりますが、その他の名前付けなどは同じです。


# 手順概略

1. ACM 証明書作成
1. CloudFront Functions 関数作成
1. CloudFront ディストリビューション作成
1. DNS 設定


# 手順詳細

### ACM 証明書作成

us-east-1 にて、転送元ドメインの証明書を作成。


### CloudFront Functions 関数作成

サブメニューの Distributions の下あたりに新設された Functions リンクから関数作成を始めます。

転送用の関数の内容は、例えば下記。

```JavaScript
function handler(event) {
  var DEST_LOC_BASE = 'https://specify.destination.fqdn.here';

  var response = {
    statusCode: 301,
    statusDescription: 'Moved Permanently',
    headers: {
      'location': { value: DEST_LOC_BASE + event.request.uri }
    }
  };

  return response;
}
```

執筆時点で const は使えませんでした。
uri は "/" で始まるパス文字列です。


### CloudFront ディストリビューション作成

Origin Domain Name は、転送先ドメインの FQDN を記入しておきました。ちょっとパラドックス感もありますが、必須項目につき空にできないので。
Function associations の Viewer request にて、作成した CloudFront Functions 関数を関連付け。
Alternate Domain Names に転送元ドメインの FQDN を記入。
SSL Certificate は Custom SSL Certificate を選択し、ACM で作っておいた証明書を選択。


### DNS 設定

Route53 だったら CNAME じゃなくて A の Alias を使うのが正解でしょう。Zone Apex に対しても使えます。


# おわりに

初見でもスムースに構築できました。test や publish など CloudFront Functions の UI はシンプルかつ強力です。
S3 を使うより断然良いと思います。

なお、前述の関数の Compute Utilization は 25 でした。上限が 100 とのことですが、転送目的なら十分に足りそうです。
AtCoderログ：0054 - 「AtCoder Beginners Selection」の記事のまとめ

# 問題セットの情報
- 名称：[AtCoder Beginners Selection](https://atcoder.jp/contests/abs)
- 問題数：11問
- 備考：[AtCoder に登録したら次にやること](https://qiita.com/drken/items/fd4e5e3630d0f5859067)で紹介されているメイン問題を集めたもの
 
# 記事一覧 (随時更新)
|問題番号|問題|対応する記事|
|:-----:|----|------------|
|第00問|[PracticeA - Welcome to AtCoder](https://atcoder.jp/contests/abs/tasks)|---|
|第01問|[ABC 086 A - Product](https://atcoder.jp/contests/abc086/tasks/abc086_a)|[AtCoderログ：0002](https://qiita.com/RoadLynton/items/b50fcf597e2a12083fa0)|
|第02問|[ABC 081 A - Placing Marbles](https://atcoder.jp/contests/abc081/tasks/abc081_a)|[AtCoderログ：0010](https://qiita.com/RoadLynton/items/dafadf919a845989d44d)|
|第03問|[ABC 081 B - Shift Only](https://atcoder.jp/contests/abc081/tasks/abc081_b)|[AtCoderログ：0019](https://qiita.com/RoadLynton/items/bbcae9be35cbd142d087)|
|第04問|[ABC 087 B - Coins](https://atcoder.jp/contests/abc087/tasks/abc087_b)|[AtCoderログ：0035](https://qiita.com/RoadLynton/items/338e306e579fb345969d)|
|第05問|[ABC 083 B - Some Sums](https://atcoder.jp/contests/abc083/tasks/abc083_b)|AtCoderログ：****|
|第06問|[ABC 088 B - Card Game for Two](https://atcoder.jp/contests/abc088/tasks/abc088_b)|AtCoderログ：****|
|第07問|[ABC 085 B - Kagami Mochi](https://atcoder.jp/contests/abc085/tasks/abc085_b)|AtCoderログ：****|
|第08問|[ABC 085 C - Otoshidama](https://atcoder.jp/contests/abc085/tasks/abc085_c)|AtCoderログ：****|
|第09問|[ABC 049 C - 白昼夢](https://atcoder.jp/contests/abc049/tasks/arc065_a)|AtCoderログ：****|
|第10問|[ABC 086 C - Traveling](https://atcoder.jp/contests/abc086/tasks/arc089_a)|AtCoderログ：****|
単体テスト実施前までの流れ

# はじめに
本記事では、単体テストを開始するまでの流れを記述します。
今日の学習で、テストコードをあまり理解できていないことがわかったため、
アウトプットいたします。
以下、過去にテストの際に登場するメソッドなどを投稿しておりますので、
ご参照ください。

https://qiita.com/mkato1013/items/48870bc17580448fc256

#テストコード実施までの流れ
## Gemの追加
RSpecを使用するのには、まず`Gemをインストール`する必要があります。
RSpecのGemです。
*私は、10分ほどspecのディレクトリを探しておりました。ここでGemということを再認識。

①Gemfileに記述
記述するものは「`gem 'rspec-rails', '~> 4.0.0'`」です。

```ruby
group :development, :test do

省略

  gem 'rspec-rails', '~> 4.0.0'
end
```

②bundle install
省略

```
% cd (ディレクトリ)
% bundle install
```

## RSpecの設定
Gemが追加できたため、
次は、アプリケーション（テストしたいディレクトリ）内でRSpecを使用します。

①アプリケーション内にRSpecをインストール

```	
% rails g rspec:install
```

インストールが完了すると、
以下のようなディレクトリ・ファイルが生成されます。

```
[ターミナル内]
create  .rspec
create  spec
create  spec/spec_helper.rb
create  spec/rails_helper.rb
```

②.rspecに設定を追加する
生成された「.rspec」に以下のように記述します。
テストコードの`結果`をターミナル内で`確認`できるようにするための記述です。

```
--require spec_helper
--format documentation　　　　←これです
```

## テストコードを記述するファイルを用意
以下のようなコマンドを実行することで、
`テストコードのテンプレート(後述)`が前もって`記載されている`ファイルを生成できます。

今回は、「バリデーションができているか」という目的で、
モデルのファイルを生成したいと思います。

```
% rails g rspec:model user
```
↓

```
create  spec/models/user_spec.rb
```

ファイルの生成ができました。
`テストコードのテンプレート`は以下のようになっています。

```ruby
require 'rails_helper'

RSpec.describe User, type: :model do
  pending "add some examples to (or delete) #{__FILE__}"
end
```


この後からは、以下のようにテストを進めていきます。
明日以降本格的に、テストを行うことになるため、
その際に、テストの流れについて投稿いたします。

```ruby
require 'rails_helper'

RSpec.describe User, type: :model do
  describe 'ユーザー新規登録' do
    it 'nameが空では登録できない' do
      # nameが空では登録できないテストコードを記述
    end
    it 'emailが空では登録できない' do
      # emailが空では登録できないテストコードを記述
    end
  end
end
```

たびたび失礼しますが、メソッドなどの言葉については、
過去の投稿をご参照ください。

https://qiita.com/mkato1013/items/48870bc17580448fc256

# 終わりに
アプリケーションの実装訓練を毎日積んでおりますが、
今までテストコードを書いたことやテストを実施したことがなかったため、
『テストは特に行うものではないのか』と思っておりましたが、
`全くの勘違い`でした。

アプリケーションを実装するのは作り手側が責任を持って作成する必要があります。

そのためには、テストを行うことは当然であることを改めて認識しました。

明日は本格的にテストを学習する予定です。
引き続き頑張ります！！
AtCoderログ：0053 - ABC 088 B

# 問題

https://atcoder.jp/contests/abc088/tasks/abc088_b

## 問題文
> $N$ 枚のカードがあります. $i$ 枚目のカードには, $a_i$ という数が書かれています.
> Alice と Bob は, これらのカードを使ってゲームを行います. ゲームでは, Alice と Bob が交互に 1 枚ずつカードを取っていきます. Alice が先にカードを取ります.
> 2 人がすべてのカードを取ったときゲームは終了し, 取ったカードの数の合計がその人の得点になります. 2 人とも自分の得点を最大化するように最適な戦略を取った時, Alice は Bob より何点多く取るか求めてください.

## 制約
> ・$N$ は $1$ 以上 $100$ 以下の整数
> ・$a_i~(1 \le i \le N)$ は $1$ 以上 $100$ 以下の整数

## 収録されている問題セット
- [AtCoder に登録したら次にやること](https://qiita.com/drken/items/fd4e5e3630d0f5859067) [[第06問]](https://qiita.com/drken/items/fd4e5e3630d0f5859067#%E7%AC%AC-6-%E5%95%8F--abc-088-b---card-game-for-two-200-%E7%82%B9)

- [AtCoder Beginners Selection](https://atcoder.jp/contests/abs)

- [[BfB-E]\(AtCoder Problems Boot camp for beginners Easy 100\)](https://kenkoooo.com/atcoder/#/training/Boot%20camp%20for%20Beginners/1) #010 


# 回答
## 回答1 (AC)
このゲームでは、自分が取ったカードの数の合計が自分の得点になるので、「最適な戦略」のもとでは、Alice も Bob もその時の場にある最大の値が書かれたカードを取ります。カードの値を配列 a() で受け取った後、これを大きい順 (降順) にソートすると、0 番目のカードは Alice、1 番目のカードは Bob、2番目のカードは Alice、3番目のカードは Bob ...が取ることになるので、それぞれの得点の合計を計算し、最後にその差を出力すれば良いでしょう。コードは以下のようになりました。

```C++:abc088b-1.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  int n;
  cin >> n;

  vector<int> a(n);
  for ( int i=0; i<n; i++ ) {
    cin >> a.at(i);
  }

  sort( a.rbegin(), a.rend() );

  int ascore = 0, bscore = 0;
  for ( int i=0; i<n; i++ ) {
    if ( i%2==0 ) {
      ascore += a.at(i);
    } else {
      bscore += a.at(i);
    }
  }
  cout << ascore-bscore << endl;
}
```

# 調べたこと
## [AtCoder の解説](https://atcoder.jp/contests/abc088/tasks/abc088_b/editorial) → [ユーザ解説](https://blog.hamayanhamayan.com/entry/2018/02/18/224451)
回答と同じ方針でした。

## [AtCoder の解説](https://atcoder.jp/contests/abc088/tasks/abc088_b/editorial) → [コンテスト全体の解説](https://img.atcoder.jp/abc088/editorial.pdf)
こちらも回答と同じ方針でした。

# リンク
## 前後の記事
- 前の記事 → [AtCoderログ：0052 - ABC 212 B](https://qiita.com/RoadLynton/items/6bfd748018f6872da0d6)
なぜ今データサイエンスが必要なのか　非データエンジニアが考察してみた

# 概要

データエンジニアは、クライアント(自社の場合でも便宜上クライアントと呼称することにします)のデータ資源を付加価値のある(＝分析可能な)データにアウトプットするためのデータ基盤の構築・運用を行う
これらのデータはデータサイエンティストやクライアントの経営陣が利活用することになる
では、なぜ今データサイエンスが必要になっているのかを理解することでデータエンジニアが必要とされる理由を知ることができる


# なぜ？

https://www.hitachi.co.jp/Prod/comp/soft1/spcon/itbnavi_1105/

電子商取引、電子マネーやICカードの普及、RFIDによる物流管理、センサー技術の発展等による社会インフラの変化から取り扱うデータの量が飛躍的に増大してきている。
ソーシャルネットワークサービスや証券・金融の分野、スマートグリッド等においても大量のアクセスログやセンサーデータを解析して活用する取り組みが行われている。

このように、増え続けるデータを効率的に活用し、新たなビジネスにつなげていくことは今後の企業発展における一つのカギとなる

データは増え続けており、それを利用して企業発展を行いたい企業のニーズは高まっていくと予想されることからデータサイエンスの需要は高まっていくことが考えられる

データサイエンスの需要が高まるということは、
**データサイエンスを行う基盤を構築するためのデータエンジニアの需要も高まっていくことが予想される**


# データ分析・活用のアプローチについて

参考：https://www.itmedia.co.jp/im/articles/0111/20/news001.html

CRISP-DM(Cross-Indstry Standard Process for Data Mining)というデータ分析・活用のためのモデルが存在する

これは
フェーズ１：ビジネス状況の理解
フェーズ２：データの理解
フェーズ３：データの準備
フェーズ４：モデル作成
フェーズ５：評価
フェーズ６：展開/共有
というフェーズに分けて行う循環型プロセスである

この中でデータエンジニアが担当する領域は

## データの理解(データが使用できる状況かの調査)

データの項目・量・品質を調査し、データに欠損がないか、データ項目に欠落がないかを調査
調査結果をフェーズ１にフィードバックする(ビジネス目標を達成するのに必要十分なデータがあるかを判断)
システムインフラの課題でデータを処理するマシンスペックがデータ量に適合しているかも検討する

## データの準備(使用可能なデータを分析に適したデータに整形していく→データクレンジング)

・欠損値処理
データに欠損がある場合にデフォルト値(定数)または削除する等を行う
　
・データの型整備・および正規化
データ項目のデータを後続処理に適した形に変換処理する(生年月日を年齢に変換等)

・サンプリング
大規模データを処理する際に、必要であれば標本を採ってサンプリングを行う(統計的手法)

である(もしくはBIツールなどを使用したダッシュボードの作成まで行うならモデル作成迄といえるか)
★分析に使用するデータによって結果が大きく左右されるので、結果的に全行程の大部分をこのフェーズ１・２に費やすことになる

# まとめ

後半はあまり関係なかったけど、要するに
・企業が保有するデータを資源として利活用するのにデータサイエンスが必要(需要がある)
・データサイエンスのために分析するデータ資源並びにデータ資源を提供する基盤が必要
・絶え間なく、迅速に、正確に提供することでデータ分析、企業の意思決定をサポート
・データ分析基盤を構築し、運用するデータエンジニアのニーズも高まっていくよね
・データドリブンな意思決定を行うためのデータ基盤を支えるデータエンジニア(=縁の下の力持ち)って地味なようで凄い(小並感)

というお話でした。(データエンジニアではありませんが）
データエンジニアになるべくGCP資格試験勉強や[これ](https://www.qwiklabs.com/quests/25?event=Your&linkId=72780327&locale=ja)をやってみて実践してみてます

**データエンジニアなるぞー！！**


# ＋α

・ドメイン知識の獲得方法
データサイエンティストはデータ分析をするうえで、対象の事業領域のドメイン知識が不可欠となる
→それを素早く獲得することも仕事のうち

https://data.wingarc.com/what-is-domain-knowledge-4410


・データマイニングについて
企業が蓄積しているデータを利用して有用なパターンやルールを発見し、マーケティング活動を支援する統計的手法、またはツールの集合体のこと

https://www.albert2005.co.jp/knowledge/data_mining/data_mining_basics/about_data_mining
2の補数を使って引き算ができる仕組みを１０進数を使って解説

# なんやねん「補数」って
「２の補数を使えばマイナス数を表現でき、それを加算することによって引き算が実現できる」
ということは事実としてご存知だと思います。

しかしどういう原理でそれが可能なのか、不思議な方も多いと思います。
今回はそんな方を対象に、補数での引き算の原理を１０進数を使って解説します。

# 補数の種類
まず、今後混乱しないためにも、補数には二種類ある事をお伝えしておきます。N進数には「Nの補数」と「N-1の補数」があります。
なので２進数では「２の補数」と「１の補数」、１０進数では「１０の補数」と「９の補数」がある、という事になります。
この記事では「Nの補数」についてだけ説明します。

# Nの補数とは
一言で説明すると

```
　「ある数」の桁が１つ増える為に必要な最小の数
```
という事です。

例えば、１０進数の６で考えます

```　
６は１桁
これを２桁にするためには、４を足して
６＋４＝１０
で２桁となる

もちろん、５を足しても１１という２桁になるが、ここでのポイントは
「桁が１つ増える為に必要な最小の数」という点

なので、１桁である６を２桁にする為の最小の数は４
これの求め方は　１０－６＝４　でOK

つまり、６を１桁から２桁にする為の最小の数は４なので、
「６に対する１０の補数」は４となる
```
という感じです。

この「４」というのが、補数的な表現としての「－６」になります。

# 補数を使って引き算をしてみる
よく分からないと思うので、実際に１０進数で、補数を用いた引き算をやってみます。

８－６の場合

```　
先ほどやったように、６に対する１０の補数は４
なので、「－６」という数は補数で表現すると「４」になる

「８－６」を計算する場合、「８＋(－６)」と考えられるので、

「(－６)」を「４」に置き換えて

８＋４　を計算する

その答えは「１２」となるが、このうち、１０の位（最上位）は無視

すると「２」だけが残り、これが　８－６　の答え
```

はい、できました。

# ゑ？
いや、なぜ１０を無視できるんだ？それで「２」という答えが得られたのはたまたまじゃね？
のように、何か騙されたような気持ちかもしれません。

解説します。

# 解説
先ほどの計算を次のように見ていきます

```　
８＋４＝
８＋（１０－６）＝
８＋１０－６＝
１０＋８－６＝　<--　注目
１０＋２＝１２
```

お分かり頂けますでしょうか？
「注目」の部分を見れば分かるように、「８－６」が出てきているのです。

これによって「２」が得られ、代わりに「１０」が余分になります。
よって、１０は「無視する」という事です。

機械的な手順としては、Nの補数を加算した後、最上位の「１」を無視すれば引き算の結果が得られるという事です。

凄いでしょ？！

# しかし・・・
いや、でも、騙されてはいけません。先ほどの例では、８＋４としましたが、
じゃあこの「４」はどこから出てきましたか？

そうですよね。
結局「１０－６」と、引き算して求めたんです。
「じゃあ最初から素直に８－６やれよ」
って思いますよね？

# ところが・・・
先程の１０進数の例では、補数を求める為に結局引き算を使っていました。
だから「最初から引き算やれ」と突っ込まれるのですが、
しかし２進数では・・・**本当に、どこにも引き算が必要無いんです！！**

# ２進数における補数の求め方
これはITパスポートとか基本情報レベルなので、良く知られている事実かと思いますが、
２進数の補数の求め方は

1. 全ビットを反転させる（１と０を反転させる）
2. １を加算する

という、たったこれだけの操作で、「機械的に」求められるのです！
３進数以上ではこうはいきませんよね。

で、これで求められた２の補数を加算し、そして、最上位の「１」を無視します。
すると、それ以降に並んでいる数が「引き算の結果」という事です。
実際に２進数での引き算の様子を見てみましょう。

```
　54 - 13 の場合

　54：00110110(8桁)
　13：00001101(8桁)
　※桁数は何でも良い

　54 - 13 　は
　54 + ( -13 ) 　なので、

　-13 = 13の補数 = 11110010(13の反転) + 1 = 11110011

　よって

　00110110(54) + 11110011(13の補数) = 100101001(9桁)

　100101001 のうち、最上位の「１」は無視　→　1(00101001)
　
　括弧の部分は「41」
　よって答えは 41
```

こういう仕組みです。

でもやっぱり騙されたような感覚になると思うので、
深く納得したい方は、実際に手を動かして計算してみて下さい。

最後に、９００－１２３をやってみます

```　
　１２３に対する１０の補数・・・１０００－１２３＝８７７
　９００＋８７７＝１７７７
　最上位の「１」は無視
　答え　７７７（GOGO CHANCE!）
```

数学って面白いなああああ。
シェルスクリプトの[ -lt, -le, -gt, -ge, -eq, -ne ]が嫌いな人に送るvalハック

## はじめに

シェルスクリプトでは数値を比較する時の演算子に `-lt`, -`le`, `-gt`, `-ge`, `-eq`, `-ne` を使います。これは他の言語で一般的な `<`、`<=`、`>`、`>=`、`==`、`!=` ではないため、分かりづらいという人がいるようです。`-lt` や `-gt` は CSS の実体参照 `&lt;`、`&gt;` と同じだし、英語の less than、greater than の略だし `-le` や `-ge` は equal との組み合わせなので（英語が得意なのではなく LT はリトルの L が左側、GT はグレートの G が左側にあるという変な覚え方をしてるだけですがなにか？）、個人的には言語による文法の違い程度にしか思わずさほど気にならないのですが、記号よりは分かりづらいと言えば分かりづらいでしょう。

さてそんな人のために、この記事では `[ ]` とこれらの演算子をなくす `val` ハックというものを紹介します。ちなみに名前自体は私がつけたのでググっても見つかりません。

## val ハック

少し複雑な計算式が含まれる条件式を例にします。

`( (x + y)/(a * b) ) < (foo * bar)`

まずこれをシェルスクリプトの一般的な書き方で書くと以下のようになります。

```sh
while [ $(( (x + y)/(a * b) )) -lt $((foo * bar)) ]
do
    # some calculations
done
```

シェルスクリプト特有の `[ ]` と `-lt` が登場し元の条件式とは違って見えますね？

もしくは、次のように書くこともできます。元の条件式に少し近くなりましたが、`[ ]` は依然登場していますし、`-lt` が消えた代わりに意味的にも分かりづらい `-ne 0` が必要になりました。

```sh
while [ $(( ( (x + y)/(a * b) ) < (foo * bar) )) -ne 0 ]
do
    # some calculations
done
```

これを `val` ハックを使って書くと以下のようになります。

```sh
while val $(( ( (x + y)/(a * b) ) < (foo * bar) ))
do
    # some calculations
done
```

`[ ]` も `-lt` も消えてしまい、だいぶ元の条件式に近い形になりました。他の言語と同じように `==` や `!=` で比較することもできます。`val` というのは実際には以下の簡単な関数です。この関数にも `[ ]` や `-ne` などの演算子が登場していません。実はシェルスクリプト特有の数値の比較演算子は一切不要なのです。これが `val` ハックです。

```sh
val() {
    return $((!$1))
}
```

変なことやってんなーって思いました？はい、私もです。名前は関数名を元に私がつけましたが、実はこのコードは [POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html#tag_23_02_06_04) に載っているものなのです。元のコードには必要のない `$` が使用されていたためそこだけ取り除いています。

もっとも POSIX ではこの書き方を推奨しているわけではなく、算術式評価（`(( ))`） ではなく算術式展開（`$(( ))`）を採用した理由として「（`[ ]` でも十分対応できるし）複雑な条件式であってもこのような関数で読みやすく書くことができる」という文脈で使われています。

ちなみに算術式評価を使うとこのようになります（もちろん POSIX 準拠ではありません）。

```sh
while (( ( (x + y)/(a * b) ) < (foo * bar) ))
do
    # some calculations
done
```

確かに読みやすいけれども `val $` が消えただけとも言えます。


## さいごに

この方法を使うかどうかは皆さんにおまかせします。**私はたぶん使いません。**
データエンジニアとは



# データエンジニアとは

現場における課題を考え、適切な課題解決方法をデータを使用して導き出すエンジニアのこと。
データを分析可能な状態にするエンジニアのこと。
現代の膨大なデータ(不揃い、不規則)をあらゆるスキルやツールを用いて、集計・加工・集計・可視化することを主業務とする。

★名前の由来
海外ではデータラングラーと呼ばれていたりする。
ラングラーとは家畜を飼いならす人のことで、牛のように暴れまわるデータを自在に操り分析可能にするためこのようなネーミングが付いた。


# 具体的な内容

データはあるが、それが分析可能な状態に整理されていたリ、フォーマットされているわけでもない。
そういったデータをまとめ上げ(加工等)、ストレスなく横断して活用できるようにする。


# データサイエンティストとの違い

データサイエンティストの主業務の
8割：データの準備、前処理
2割：準備されたデータに対して高度な統計数理を適用したり、機械学習モデルを作ったりといった専門性を発揮すべき分野

データエンジニアはこの8割の作業に当たる必要なデータを準備する役割になる。
実際にデータサイエンティストが分析を行うための必要なデータというものを作成することが作業内容になる。
生データに対してデータサイエンティストが分析するのに必要な状態にする(＝付加価値をつける)ことに意味がある。


# 必要なスキル

## 1. RDB、SQLのスキル

データウェアハウスやデータマートなどでクエリを使用するためSQLの知識が必要
また、データウェアハウスのテーブル設計にはRDBとは違うディメンショナルモデリングというデータモデリング手法が必要となる

## 2. オンプレ、クラウドの知識

サーバやストレージの構築を行うことも多い
状況に応じて自社内で設備を構築するオンプレ
ネットワークを経由して接続できるクラウドの適したほうで設計するスキルが必要

## 3. 分散処理スキル

大規模データを使用する際にサーバー負荷権限、データの処理速度を上げるための分散処理スキル
分散処理を行うフレームワーク

必要な具体的スキル
・Hadoopに関する知識
・Sparkに関する知識


## 4. ネットワーク設計スキル

サーバ構築なども行うことがあるので、インフラエンジニア並みのインフラ設計、運用についてのスキルが必要



# 主な作業内容

「大規模データ基盤の構築・運用」

大規模データ基盤とは
→データの取得・保管・加工・分析・提供を担う一連のシステム群のこと


# 職種の魅力

データ基盤という大規模装置を複数人で共同で作り動かしていくところにある
異なるスキルを持ったメンバーが共同してすべてが正しく動き、クライアントのデータというあるだけでは無価値な膨大な資産から
付加価値のついた(＝分析可能な)アウトプットを生む仕組みを作ることができる



# 参考

https://www.dsk-cloud.com/blog/data-engineer-is-good-understanding-data#toc-0

https://www.acrovision.jp/career/?p=1948

https://data-soldier.hatenablog.com/entry/2017/12/08/114731
DWH 複数スタースキーマ まとめ

# 概要

スタースキーマを学習した後で

**モデルとしてスタースキーマが存在するが、実際の業務システムを単一スタースキーマで表現することは難しい**

とのことだったので複数スタースキーマを勉強した。それのまとめ

以下参考

https://zenn.dev/pei0804/articles/multiple-star-schema


# 複数スタースキーマについて

複数のプロセスを横断的に分析できるのが真に価値ある分析となる

# ファクトの発生イベントが異なるものは分ける

記事では
・製品別注文数量
・製品別出荷量
というファクトに対して
・時間
・顧客
というディメンションがある場合の単一スキーマにした時の失敗が記載されている。

要約すると

**ファクトテーブルのカラムに複数イベントを格納するとたいてい後で苦しくなる**

## 理由

・対象イベント外のファクトデータに無意味なデータが格納される
　ファクトテーブルはそれぞれのイベント発生時のデータを格納するが、それ以外のイベントが発生しなければ格納する値がない
　→デフォルトキー(Nullか0等。Nullはあまり使いたくないので0を格納する)を設定する
　→時間軸などで分析した時に、デフォルトキーで格納されているデータも引っ張られるので、意味のないレコードが分析データ内に残る
　
・クエリで解決しようとしても複雑性が増す
　上記の内容をクエリでフィルタリングして解決することにする
　→サブクエリや集計処理などでフィルタリングのことを考慮する必要があり、この制約が効いてくる(悪いほうに)


## 解決策

素直にファクトテーブルをイベント(プロセスと呼んでいる)毎に分けること
→それぞれでディメンションテーブルとリレーションをはってモデリングする


# 複数のファクトテーブルの横断的な分析がしたい 

上記のようなモチベーションがあるとする(業務間の比較(e.g. 生産と受注の比較など))

## 落とし穴

この時、素直にJOINしてしまうと**ファントラップ**という現象が起きる可能性が高い

## どうするか

１．それぞれのファクトテーブルをいったん分析軸となるディメンションテーブルと結合する
　　→WITH句などで切り出すのが効率的
　　→Group By句でディメンションの外部キーを指定してグループ化する

２．１で結合したファクトテーブル同士をFULL JOINする
　　→ディメンションのキーは一意のものとなっているので、重複する値がなくなりファントラップは起こらない

上記の方法を**ドリルアクロス**と呼ぶらしい

詳しくは記事のソースを確認したら理解しやすい


# まとめ

・単一スタースキーマでは業務プロセスを分析するのは難しい(できてたら状態がないことになる)
・イベント(＝プロセス)毎にファクトを分ける
・複数のファクトを横断的に分析するときはドリルアクロスでファントラップしないようにする

理論としては理解したので実践してみたい。
結局単一スタースキーマで表現されるのは、業務プロセス内の単一イベント。
業務プロセスごとのファクトは異なるので、まずは業務プロセスを理解し、それぞれのプロセスのファクトとディメンションを分けることを考えれるようにする。
DWH データモデリング まとめ

# 概要

データウェアハウスモデリング入門（ダイジェスト版）（事前公開版）というSlideShareを読んだ
DWHについては概要を何となく理解したけど、DWHのデータモデリングが気になったので検索してたら上記のソースを発見したので
読みながら調べた結果をまとめてみる

↓参考

https://www.slideshare.net/snaga/ss-135048443

# スライドの主目的

・データ分析に必要なデータモデリングについて理解する
・主業務で利用しているデータをデータ分析向けのデータモデルに変換できるようになる
　→ここが気になっていたので重要


# データモデルとは

>データモデルの主な目的は、データの定義とフォーマットを提供することによって、情報システムの開発を支援すること

データモデルには目的や意図があり、業務システムのDBのデータモデル(正規化されている)とDWH等のデータモデルでは用途が異なる

## データモデルの分類

当スライドでは以下のように分類

・オンライン系データモデル
　OLTPに特化したモデル
　ACID(Atomicity,Consistency,Isolation,Durability)を保つための機構がある
　正規化を行う過程で参照関係が複雑になりやすい(エンドユーザーが理解するのは不可能)

・大福帳データモデル
　システムで発生するデータを要約せずにそのまま蓄積するデータモデル
　BIツールなどを使うときに好まれやすいモデル
　カラムの数が膨大になりやすい(正規化も何もないため)

・ディメンショナルデータモデル
　データ分析のためのデータモデル(参照のみで更新されることを想定しない)
　時系列の数値を持つファクトと呼ばれるテーブルと、分析軸(支社別、品目別等)となるディメンションと呼ばれるテーブルから構成される
　→スタースキーマと呼ばれる
　→ファクトとディメンションを掛け合わせて分析を行うことができる多次元データベースの様なもの


# データウェアハウスモデリングが必要な理由

・オンライン系データベースはユーザーが分析するにあたって敷居が高い(前述のとおり複雑だから)
　→というか、オンライン系データベースにクエリ投げるのはそもそもご法度(本番系のリソースを食いつぶす恐れがある)
・ユーザーの意図に対して都度最適化されたオペレーション(データマートの作成、BIレポート作成)をしていくと幸せになれない
　→データマートはユーザーの局所的なニーズにこたえすぎるとメンテがつらい
　　→上記のケースではそもそもユーザーがマートを見てない(ニーズをとらえきれていないEtc)が考えられる
・以上の理由からスケールが難しい状況に陥る

## 解消するには

・ユーザーレベルで理解できるデータモデル
・汎用性、拡張性に優れるデータモデル


# ディメンショナルデータモデル

先述した内容の補足
・スタースキーマを主軸とするシンプルでわかりやすい、拡張性と柔軟性を備えたデータモデル

## スタースキーマ

ファクトテーブルとディメンションテーブルから構成される
・ファクトテーブルとリレーションを張ったディメンションテーブル
(よくある真ん中にファクトテーブルがあってディメンションテーブルが外側にあり、キーで結合している様子がスタースキーマの所以？)

## 用語

・ファクトテーブル
　集計対象となる金額や数値の入った、索引と数値カラムで構成されるテーブル
　→分析のために集計処理をするため、ディメンションテーブルに分割したキーと数値データのみで構成されるのが望ましい　
　参考：https://www.necto.jp/keywords/fact_table.html
　
・分析軸として利用するデータを含んだテーブル
　ディメンションは一つの次元のみを持つ構成にする(次元を含んだテーブルのため)


# ディメンショナルデータモデルの利活用

・BIツールは、ファクトに対してディメンションを掛け合わせて分析し、可視化する
　→ディメンショナルデータモデルで切り出した集計対象と分析対象をBIの目的に合わせて掛け合わせるだけで利用できる
　→さらにフィルターやグループ化といった処理をして集計、分析処理をする

ディメンショナルモデルで集計対象と分析対象を切り出せていないと、
ユーザーが掛け合わせる対象が分からない＆扱いづらいということで利用されない、不満が出る


# スタースキーマ設計の基本的なプロセス

・どのビジネスプロセスをモデル化するか決める
　
・ファクトテーブルの粒度を決める
　「いつ、だれが、どこで、何を、どのように**購入したか**」等の、ファクトテーブルが持つディメンションの数
　この集約によって、潜在的には有用だった情報を失うかもしれないので、実は重要なプロセス
　→できる限り粒度が細かいほうが後がラク(必要な粒度での計測が難しくなり、再構築する必要があるかもしれない)

・分析軸/ディメンションを決める
　→上記の粒度を決めたら決まったようなものだと思う

・ファクトテーブルの項目を決める
　→集計対象となる数値データ等


# まとめ

・DWHではディメンショナルデータモデルをテーブル設計に取り入れる
・スタースキーマ設計に沿ってテーブル設計を行う
・DWHのデータモデリングがデータ利用者から見た使いやすさ等に起因するのでしっかり勉強する
DWH スタースキーマ まとめ

# 概要

ディメンショナルデータモデルについて学習したら、スタースキーマ設計について詳細に理解したいと思った。
そこで、以下記事を読んで理解した内容をまとめる

↓参考

https://zenn.dev/pei0804/articles/star-schema-design


# ディメンションモデリング

・データウェアハウスにデータを格納するために、最適化されたデータ構造


# スタースキーマ

・ディメンションモデリングをRDBで実装したもの
・DWHで利用されるスキーマ
・ファクトとディメンションからなる
・オンライン系モデルのデータからBIツール側でデータ利用したい場合に使える
　→ファクトとディメンションを掛け合わせることで分析ができる＝理解しやすい


# ディメンションテーブル設計Tips

## サロゲートキーとナチュラルキー

・サロゲートキー
　ナチュラルキーとは異なる、ETLプロセスの一部で作成される本質的な意味を持たない値

・ナチュラルキー
　業務システムのエンティティを一意に識別可能なキー

## 何がうれしいか
　
・業務システムのエンティティに変更があった場合に履歴を保てるようにするため
　→ファクトテーブルのキーの外部キーとしてサロゲートキーを指定し、業務システムのエンティティをナチュラルキーとすることで
　　業務システム側のキーの変更を吸収しながら履歴を保つことができる

## ディメンションは細かく切り出す

・ファクトの文脈としてディメンションがある
・この文脈の豊富さがファクトの解釈を多様なものにする


# ファクトテーブル設計Tips

## 測定値はすべて列に含める(計算列を使用しない)

冗長性があっても測定値は列として保持する
クエリやツールから一貫性のある測定ができる
→計算列を計算するようにすると、計算式が変更されたときの過去の計算列の意味が変わってしまう
→計算列を計算するようにしてしまうと、計算式が変わることで過去の値まで変わるため、計算列を含むことで時点の結果を不変なもの(一貫性)にする？
★ここについてあまり腑に落ちていないので誰か説明してください。。


## 粒度を細かくする

「月の売り上げが50万円」と「月の売り上げが100万円」と単に聞くと後者と判断する
→実は。。。実働１時間で50万と実働１００時間で100万かもしれない(ファクトを理解する文脈が少ないので評価指標が月という次元のみになる)

上記は極端な例だが、粒度の説明にはなっていると思う
全てのファクトを同じ粒度で格納されていることを保証するためには

→ディメンションを多く持つ(＝粒度を細かくしておく)ことでファクトテーブルの行が表す意味について混乱が生じにくくなる


# まとめ

スタースキーマの設計方法について具体的に書かれていたのでよかった。
サロゲートキーとナチュラルキーをディメンションテーブルにしようして、サロゲートキーを外部キーとすることでエンティティの変更に追従して
履歴を残す方法などは他のサイトで見ることはなかったので(ググり力がないだけ？)非常に参考になった。
DWHまとめ

参考：https://www.dal.co.jp/column/b-dwh/

# データウェアハウスとは

Inmon氏いわく
> 意志決定のため、目的別に編成、統合された時系列で、削除や更新しないデータの集合体

通常のDBは業務に特化したデータを保管する
DWHは企業の意思決定を行うために必要なデータを保管する(横断的なデータ)


# DBとの違い

## 大量データを高速で検索・分析

DWHの様なデータ分析を目的としているDBは、従来型DBより検索・分析機能にたけている
並列処理アーキテクチャを採用しているため、一つのクエリに対して複数のアクセスポイント(ワーカー)から独立したデータ処理を行える
これを実装しているDWH製品が(Hadoop/Spark/Google BigQuery(Dremel))等


## 統合的なデータ分析に特化している

各個別DBから集約するデータは、単に集約するわけではない
従来型のDBでは、データを目的別に分けていた
→DWHでは「商品」「店舗」「従業員」「取引」というようにサブジェクト（主題）ごとに分解・整理して格納する


## 時系列でのデータ分析が可能

基幹系DBなどでは、売上等のログは日次、週次、月次などの単位の管理を基本とする
このため、ストレージ容量確保のために過去データは集計処理等をすると削除する
→DWHでは業務上発生した取引記録などのデータをすべて格納しておく
　これで過去の売り上げ推移や顧客の趣向変遷等を時系列で分析できる
　→ストレージ容量については過去データなどについてはGoogle BigQueryはディスカウントされる(90日間更新がないデータに対して等)
　→また、蓄積されるデータについては不変性を持っている
PrePoMax による練習１：書籍『例題で極める非線形有限要素法』より

# はじめに
前回までの投稿、[Elmerによる練習１：書籍『例題で極める非線形有限要素法』より--補足--](https://qiita.com/superrino130/items/48246becbdcf1ff9e1d7) では、`Elmer` でしたが、`PrePoMax` でやってみました。
# Salome
`Salome`でメッシュを切ります。

```
６面体要素の場合
   3D Hexahedron(I.J,K)
   2D Quadrangle:Mapping
   1D Wire Discreation
        Local Length
        lengthで値を設定しました　1, 0.5, 0.34, 0.25, 0.2
```
`PrePoMax`ではメッシュデータを読み込むときの、単位の設定が容易ですので、`mm`単位でメッシュデータを作成します。
# PrePoMax
![20210804_020.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538241/4252b426-62eb-4341-42a1-c3a840e96302.png)
![20210804_025.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538241/df609214-c4bb-01a1-7386-92b314f1455c.png)
![20210804_034.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538241/52746be5-44a6-5a1f-fa1c-5baf8139c319.png)
![20210804_050.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538241/75b098e2-80a0-7e6f-4dd8-1af9ce19b0b6.png)
![20210804_100.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538241/fafa1796-efb8-0e81-f633-3d4ad93678d2.png)
はい、いい感じですね。
# まとめ
+ PrePoMax さんありがとう
+ Salome さんありがとう
+ 例題で極める非線形有限要素法 さんありがとう
+ S さんありがとう
systemd でDoT (DNS over TLS) と DNSSEC に対応したDNSキャッシュサーバーを作る

[DoT](https://www.nic.ad.jp/ja/mailmagazine/backnumber/2020/vol1752.html) (DNS over TLS) と [DNSSEC](https://www.nic.ad.jp/ja/newsletter/No43/0800.html) に対応した[DNSキャッシュサーバー](https://www.nic.ad.jp/ja/newsletter/No51/0800.html) を `systemd-resolved` で作る話です。 [systemd-networkdをDHCPサーバーにする](https://qiita.com/kakinaguru_zo/items/f3dbf5c44bf28fc27f9c) を組み合わせると dnsmasq の代わりに systemd を使えるようになります。以下の設定は[systemd 247かそれ以降](https://qiita.com/konosuke/items/88a49c63cb5876f4b8d8#dnsstublistenerextra%E3%81%A7153%E3%82%92listen%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88) で使えます。

```config:/etc/systemd/resolved.conf.d/my.conf
[Resolve]

DNS=2001:4860:4860::8888#dns.google 2001:4860:4860::8844#dns.google
DNSSEC=allow-downgrade
DNSOverTLS=yes
MulticastDNS=yes
LLMNR=yes
Cache=no-negative
DNSStubListener=no
DNSStubListenerExtra=192.168.1.2
DNSStubListenerExtra=127.0.0.1
```

ポイント

* DNSSEC, DNSOverTLS と一緒に使うとき[Cloudflare DNSととても相性が悪い](https://bbs.archlinux.org/viewtopic.php?pid=1980169#p1980169) のでクラウドフレアを用いない
* `DNSStubListenerExtra` にDNSの問い合わせを受け付けるIPアドレスを書く
* `/etc/resolv.conf` を以下のように`nameserver` の部分に上記の`DNSStubListenerExtra` に指定したIPアドレスを設定する

```config:/etc/resolv.conf
options inet6 edns0 trust-ad use-vc
nameserver 127.0.0.1
```
magentoユーザー発行

# ユーザー
magentoの管理画面を操作するための、ユーザーを発行します。

```
/var/www/html/magento
```

にプロジェクトを作成したという前提です。

```
/var/www/html/magento$ bin/magento admin:user:create
Admin user: name
Admin password: pass
Admin email: xxx@xxx.co.jp
Admin first name: admin
Admin last name: admin
```
Grove IoT スターターキット for SORACOM でボタンを使う

ボタンを押すとLED が点灯するプログラムです。
ボタンの Grove を D38 に接続します。

```text:grove-button/grove-button.ino
// ---------------------------------------------------------------
/*
	grove_button.ino

					Aug/04/2021
*/
// ---------------------------------------------------------------
#include <WioLTEforArduino.h>

#define BUTTON_PIN	(WIOLTE_D38)
#define INTERVAL	  (100)

WioLTE Wio;

int icount = 0;
// ---------------------------------------------------------------
void setup()
{
	Wio.Init();	
	pinMode(BUTTON_PIN, INPUT);
}

// ---------------------------------------------------------------
void loop()
{
	int buttonState = digitalRead(BUTTON_PIN);
	SerialUSB.print(buttonState ? '*' : '.');

	if ((icount % 40) == 0)
		{
		SerialUSB.println("");
		}

	if (buttonState)
		{
		Wio.LedSetRGB(0, 0, 1);
		}
	else
		{
		Wio.LedSetRGB(0, 0, 0);
		}
		

	delay(INTERVAL);

	icount++;
}

// ---------------------------------------------------------------
```

実行時のシリアルモニターの様子
![serial_monitor_aa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/5a5c6342-6207-4980-a5c0-522dfb053f39.png)
【ExcelVBA】娘(1歳半)との尊い会話シミュレーター

##概要
娘(1歳半)との会話が尊いので、いつでも再現できるようにVBAでシミュレーターを作成した。

##イメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464218/15f8ee07-aafb-3aea-b906-c603317ba4e6.png)

A列を「単語リスト」として、知っている単語を列記しておく。

##動作
「会話シミュレート」を押すとバーチャル娘が問いかけてくるので、適当な単語を入力。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464218/e55461af-a8b2-e760-5e59-1c9a434c0af2.png)

知っている単語であれば、返答してくれる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464218/9b6c10a8-c2a2-8744-2015-774d0918cecb.png)

知らない単語を入力すると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464218/fa593df6-b368-9509-c14c-6bff26799a34.png)

不思議そうな顔をしてくる。ここで「はい」を押すと、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464218/690c6381-67a2-f2ac-6e49-083f2d225c74.png)

単語リストに追加され、次回から返答してくれるようになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464218/af014b1e-521c-5a8a-a43b-7fe68d1eb19d.png)

このやりとりを1～6回のランダムな回数繰り返す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464218/945d16ee-5c56-e165-949e-1b6a8d97f16b.png)


##コード

```vb
Sub talk()
Dim i As Integer
Dim nani As String
Dim yesno As String
Randomize
i = Int(6 * Rnd + 1) '1-6でランダム
For i = i To 6 '質問を最大6回繰り返す
    nani = InputBox(Prompt:="なーにーなーにー？") '質問
    If nani <> "" Then '空白でない場合、処理を続ける
        If WorksheetFunction.CountIf(Range("a:a"), nani) = 0 Then '単語リストに存在しない場合
            yesno = MsgBox("？", vbYesNo)
            If yesno = vbYes Then '「はい」を押すと単語リストに追加
                Cells(Cells(Rows.Count, 1).End(xlUp).Row + 1, 1) = nani
                MsgBox (nani & "！") '単語リストA列の末尾に追加後、応答
            End If
        Else: MsgBox (nani & "！") '単語リストに存在する場合、応答
        End If
    End If '空白の場合、再度質問
Next
End Sub
```

##まとめ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464218/3af2fdd7-e733-253b-03b9-9e18fc0dcfeb.png)
Z3Py　例題　数独

# 問題
3×3のブロックに区切られた 9×9の正方形の枠内に1〜9までの数字を入れる。 ([Wikipedia:数独](https://ja.wikipedia.org/wiki/%E6%95%B0%E7%8B%AC))

# 回答
```example_sudoku.py
from z3 import *

problem = [
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 4, 3, 0, 0, 0, 6, 7, 0],
    [5, 0, 0, 4, 0, 2, 0, 0, 8],
    [8, 0, 0, 0, 6, 0, 0, 0, 1],
    [2, 0, 0, 0, 0, 0, 0, 0, 5],
    [0, 5, 0, 0, 0, 0, 0, 4, 0],
    [0, 0, 6, 0, 0, 0, 7, 0, 0],
    [0, 0, 0, 5, 0, 1, 0, 0, 0],
    [0, 0, 0, 0, 8, 0, 0, 0, 0]
]
X = [[Int("x_%s_%s" % (i, j))for j in range(9)] for i in range(9)]

s = Solver()
s.add([And(1 <= X[i][j], X[i][j] <= 9) for i in range(9) for j in range(9)])
for i in range(9):
    for j in range(9):
        if problem[i][j] != 0:
            s.add(X[i][j] == problem[i][j])
s.add([Distinct([X[i][j] for i in range(9)]) for j in range(9)])
s.add([Distinct([X[i][j] for j in range(9)]) for i in range(9)])
s.add([Distinct([X[i+3*a][j+3*b] for i in range(3)
      for j in range(3)]) for a in range(3) for b in range(3)])

print(s.check())

m = s.model()
for i in range(9):
    tmp = []
    for j in range(9):
        tmp.append(m[X[i][j]])
    print(tmp)

```
出力

```terminal
sat
[7, 2, 8, 9, 3, 6, 5, 1, 4]
[9, 4, 3, 1, 5, 8, 6, 7, 2]
[5, 6, 1, 4, 7, 2, 9, 3, 8]
[8, 3, 4, 7, 6, 5, 2, 9, 1]
[2, 1, 7, 8, 4, 9, 3, 6, 5]
[6, 5, 9, 2, 1, 3, 8, 4, 7]
[1, 8, 6, 3, 2, 4, 7, 5, 9]
[3, 7, 2, 5, 9, 1, 4, 8, 6]
[4, 9, 5, 6, 8, 7, 1, 2, 3]
```

## 解説
縦横３×３の範囲の数字がすべて異なるので、`Distinct`を使用する。


# 他の例題
[Z3Py個人的ポータル](https://qiita.com/Ganesha/items/7a606ffc8a7c2504c143) へ
Stderr: VBoxManage: error: Incompatible configuration requested. 

# vagrant up時エラーが発生しました。

```
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Checking if box 'generic/ubuntu2004' version '3.1.0' is up to date...
==> default: Clearing any previously set forwarded ports...
==> default: Fixed port collision for 22 => 2222. Now on port 2200.
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
    default: Adapter 2: hostonly
==> default: Forwarding ports...
    default: 22 (guest) => 2200 (host) (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
There was an error while executing `VBoxManage`, a CLI used by Vagrant
for controlling VirtualBox. The command and stderr is shown below.
```

いやな音

```
Command: ["startvm", "3ed7cfeb-028a-46c9-be74-a180599963ad", "--type", "headless"]
Stderr: VBoxManage: error: Incompatible configuration requested. (VERR_INCOMPATIBLE_CONFIG)
VBoxManage: error: Details: code NS_ERROR_FAILURE (0x80004005), component ConsoleWrap, interface IConsole
```

わああああああなんか出た(´д｀)
↓
再起動しました。upできるようになりました。
（心当たりはソフトウェアのアップデートしたあたり・・・）


# 参考さま
https://www.oresamalabo.net/entry/2016/11/27/170745
【Docker】 Dockerインストール

> 私は日本就職を目指して、勉強している韓国人大学生です。
> もし、内容の中で間違った表現や言葉などがあれば、書き込みをしてください。


#Dockerというのは？
- Linuxコンテナを簡単に生成したり、管理できるようにサポートする__コンテナ型仮想化プログラム__
- アプリケーションの開発・構築・テスト・配布等を迅速に可能
- 私が感じた長所
    1. Back-Endサーバーの開発・構築するとき、__複数のバージョンを使ったテスト可能__
    2. Docker Composeで__複数のコンテナを1つのセットで簡単に管理__
    3. イメージを活用して、__バージョン管理、ロールバック等を簡単に可能__
    4. Reverse Proxyで__WEBとAPIサーバーを単一サーバーで運営__

```
実務でCI／CDパイプライン構築を通して、持続的な配布環境をよく構築
```

#Dockerインストール

###Dockerリポジトリを設定

```bash
$ sudo apt-get update

# 패키지 다운로드
$ sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common

# Docker GPG 키 추가
$ sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# Docker GPG 키 등록 확인
$ sudo apt-key fingerprint 0EBFCD88

# Docker 저장소 등록
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
```

###Dockerエンジンインストール
```bash
$ sudo apt-get update

# Docker最新バージョンインストール
$ sudo apt-get install docker-ce docker-ce-cli containerd.io 

# インストール結果確認
$ docker -v
```

###Dockerコンポーズインストール
```bash
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.25.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
```
Powershellの引数ではまった話

# Powershellの引数ではまった話

以下の関数をご覧ください

```powershell
function test_func([int]$x,[int]$y){
    Write-Host($x)
}
```

この関数に以下の通り数値を2つ引き渡すと、エラーが出力されます
```
test_func(3,4)
```

```
test_func : パラメーター 'x' の引数変換を処理できません。"System.Object[]" の値を "System.Object[]" 型から "System.Int3
2" 型に変換できません。
発生場所 行:1 文字:10
+ test_func(3,4)
+          ~~~~~
    + CategoryInfo          : InvalidData: (:) [test_func]、ParameterBindingArgumentTransformationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,test_func
```

int変換に失敗しているということで以下の通り修正して実行してみると

```powershell
function test_func($x,$y){
    Write-Host($x)
}
```

なんと(3,4)という一つの配列扱いされてしまっているのです
```
test_func(3,4) # 3,4
```

以下のように変数に収めようと無駄です
```
$a = 4
$b = 9
test_func($a,$b) # 4,9
```

stringに使用が配列扱いです。

結局以下の通り宣言するのが正しいようでした
```
 test_func $a $b # 4
```

ただ関数のように指定もできるときもあるため
この現象の原因は結局わからずじまいでした。

そもそもPowershellはShellに近い書き方なので
()内に指定する方があまり意図しない指定の仕方なのかもしれないです

以上、Powershellの引数指定にはまった話でした。
Apache2.4 でHTTPS (SSL/TLS) の設定をしたら起動しなくなった話

##結論
server.key が短すぎるとエラーになるため、2048byteで作成しなおしたら起動するようになった。

##はじめに
オンラインアプリ開発経験はあるのですが、サーバ構築経験のほぼない初心者のため、四苦八苦しています。
初心者のただのメモですが、もし同じことで詰まる人のために記事にします。

##環境
サーバ：RHEL8.2 AWS AMIから作成
Apache 2.4.37
社内プロキシ経由でネットに接続できる環境のため、下記を設定してyumインストールしています

* セキュリティグループのアウトバウンド設定に社内プロキシのポートを設定
* /etc/yum.conf にProxy設定を追加

[社内Proxyに阻まれていろいろ捗らない人のためのTips](https://qiita.com/sachioksg/items/289e40d69382b1d09811) 様を参考に設定しています
※オフラインインストールでイライラした経験があるので、yumコマンド一発でインストールできるのは気持ちいいですね・・・！

## 実施した内容
① Apache をyumでインストール
[Apache httpd 2.4 を CentOS 7 に yum でインストールする手順](https://weblabo.oscasierra.net/apache-installing-apache24-yum-centos7-1/) 様を参考にインストール
無事httpで接続できることを確認
(セキュリティグループでインバウンドルールも合わせて修正)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1846218/91c1fa8f-b472-18db-ec7c-634fc0c84b4c.png)

② HTTPSでも接続するため、OpenSSLをyumでインストール
　→ 秘密鍵・証明書(server.key,server.csr,server.crt) を作成
　※無料でやりたかったのでオレオレ証明で作成しました。
　　開発環境用なので、HTTPS接続時に警告が出てもまぁいいかな～と。。
　　
[OpenSSL で SSL 自己証明書を発行する手順](https://weblabo.oscasierra.net/openssl-gencert-1/) 様を参考にインストール
他記事で見たのですが、
「Common Name (eg, your name or your server's hostname) 」はServerName と合わせる必要があるとのこと

③ mod_ssl をyumインストールし、②で作成した秘密鍵・証明書を配置
[Apache httpd 2.2 に HTTPS (SSL/TLS) の設定をする (CentOS 6)](https://weblabo.oscasierra.net/apache-httpd22-ssl-centos6/) 様を参考に実施

④ Apacheを再起動・・・しようとしたら、起動に失敗する・・・！

## 調査
* systemctl status httpd や  journalctl -xe を見ても、大した情報が書いていない・・・

※ServerNameを設定しろって警告がありましたが、こちらは起動とは関係無し

```
 httpd.service: Main process exited, code=exited, status=1/FAILURE
 httpd.service: Failed with result 'exit-code'.
 Failed to start The Apache HTTP Server.
```

* /var/log/httpd/error_log を確認したら下記情報が出ていたのでググったが、関係なさそう・・・

```
SELinux policy enabled; httpd running as context system_u:system_r:httpd_t:s0
AH01232: suEXEC mechanism enabled (wrapper: /usr/sbin/suexec)
```

* /var/log/httpd/ssl_error_log を確認したところ、下記ログが！

```
SSL Library Error: error:140AB18F:SSL routines:SSL_CTX_use_certificate:ee key too small
```

server.key を、参考にしたページどおり2024byteで作成していたのですが、こちらを2048byteで作成したところ、問題なくApacheが起動するようになりました！
HTTPSで接続しても、警告は出ますがちゃんとApacheの画面が表示されました！




## 感想
mod_SSL を入れたら、ssl_error_log なんてのが出るようになるんですね。。
journalctl のエラーログから解決策を探していたので、こちらのログを見つけるまでに時間がかかってしまいました・・・。

トラブルシューティング時はログを見るのが基本だと思いますが、どのようなログがどこに出るのかちゃんと把握していないとキツイですね。。引き続き構築頑張ります。。
Ubuntuシェルスクリプトのループ処理で Syntax error:"(" unexpectedが出たときの備忘録

#環境
VirtualBox:6.1.22
Ubuntu:20.04.2 LTS
bash: 5.0.17

#やっていたこと
Linux(Ubuntu)の環境でループ処理を行うシェルスクリプトを作成していた。
しかし配列の代入部分に「Syntax error：”(”unexpected」が出てしまった。

```
#ファイル名（loop.sh）

#!/bin/sh
info=(book website article)
for media in "${info[@]}"
do
echo $media
done

==結果==
./loop.sh: 3: Syntax error: "(" unexpected
```

#原因
シェルスクリプトの最初の行にて「#!/bin/sh」と書いていたのがまずかったらしい。

ちなみにこのソースコードは「bash <ファイル名>」で実行できるとのこと。

```
bash loop.sh
```

つまり上記のコードの場合は「bash loop.sh」でエラーは出ずに実行できた。

[参考サイト：シェルスクリプトで『Syntax error: "(" unexpected』とかなった場合のメモ](https://cortyuming.hateblo.jp/entry/20130701/p3)

#解決方法
「bashコマンド＋ファイル名」で実行できたものの何かもやもやする。ということで、試行錯誤で一番上の宣言の部分を「#!/bin/bash」に直したところエラーは出ずにコードは稼働した。

```
#ファイル名=loop.sh
#!/bin/bash
info=(book website article)

for media in "${info[@]}"
do
echo $media
done

#==結果==
book
website
article
```

なるほど、一番上の宣言はコメントとしてだけでなくコンパイラへの指示（疑似命令？）として扱われるのかと推測。

#推測
自分がどのシェルを利用しているのか調べてみた。

```
echo $SHELL
/bin/bash
```

どうやら現在のシェルはbashを利用しているみたい。

だからシェルスクリプトファイルの一番上の疑似命令には"#!/bin/bash"と記載しないと動かないのか？

ファイルの先頭の疑似命令に”/bin/sh”としている場合は"sh"環境で動くと前提されているファイルだから、あえてファイルの実行時には「bash ファイル名」というようにBash宣言をしなければいけないのかと思った。

#仮説をもとに、疑似命令を「#!/bin/sh」にして環境変数SHELLを「sh」にして実行してみた。
```
echo $SHELL   #現在のシェルを確認
/bin/bash 

export SHELL=/bin/sh   #シェルをshに変更

cat loop.sh　   #ファイルの中身を確認
#!/bin/sh

info=(book website article)
for media in "${info[@]}"
do
echo $media
done

./loop.sh #shシェルにてファイルの実行
./loop.sh: 3: Syntax error: "(" unexpected
```

あれ。。
エラーが出た。。
環境変数SHELLを「sh」にしてファイルの宣言に「#!/bin/sh」にしたのにエラーが出てしまった。

なぜだかわかる方、コメントの方でご教授願います（ ;  ; ）