OmniAICreator/Qiita-1.07M huggingface dataset:
【受験記】Python 3 エンジニア認定 データ分析試験

# はじめに

この記事は、先日合格した**Python 3 エンジニア認定 データ分析試験**の簡単な受験記録になります。

この試験に関する一般的な情報は充実してきていると思いますので、ここでは**試験に関する個人的な感想**（難易度を含む）と、準備の過程でお世話になった**（無料）模擬試験**に絞って記したいと思います。

これから受験される方にとって、少しでも参考になれば幸いです。

# 公式情報
- 試験ついてはこちらの[**公式サイト**](https://www.pythonic-exam.com/exam/analyist)でご確認ください。
  - **受験方法**・**試験概要**・**試験範囲と出題の割合**などが載っています。

# 試験の感想
- 難易度としては、後述の模擬試験が十分参考になると思いました。模擬試験で700点（1000点満点）を安定的に超えていれば、合格のチャンスは十分にあると思います。と言うのも、全体的な感想として模擬試験の方が難しいと思いました。

- 主教材の**「Pythonによるあたらしいデータ分析の教科書」**（翔泳社）については、
  - Pythonとプログラミングが両方とも初心者の方は、この教材を使った準備が資格取得の面では最短経路になるのではないかと思いました。
  - ただ、私は既に他の教材で勉強をしていたことから、この教材は購入しませんでした。また、それで特に不都合はありませんでした。なお、過去におこなったG検定の勉強が一部役に立ちました。 

- 合否結果は試験終了後にモニターに表示されます。また、スコアと分野別得点率を印字した紙を別途もらえます。この点に関しては、試験終了後に不正解だった箇所の確認ができないのが残念です。試験直後にせめて5分でもいいので、振り返りができるセッションがあれば、受験者にとってより教育的で有意義な試験になると思いました。


# 無料模擬試験

公式サイトでは、以下の2つの模擬試験が紹介されています。私もこれを利用させていただきましたが、とても役に立ちました。

## DIVE INTO EXAM

こちらが一つ目の[模擬試験のサイト](https://exam.diveintocode.jp/exam)になります。

### ①全体的な特徴

- 試験は複数回受けることができます。（このことは、ぱっと見では分かりませんでした。）つまり、ここの模擬試験を本試験直前の「総仕上げ」として最後までやらずに残しておく必要はありません。むしろ、必要な回数受験しながら、その都度、直しをして、安定して合格点を超えることを目標にするスタイルで利用するといいと思います。

- なお、２回目以降の受験では既出の問題と新出の問題が混ざって出題されます。（この点については、過去に正解した問題は次回以降は全く出題されないか、または低頻度でランダムに出題されるような仕掛けがあると、より効率的に学習できると思いました。無料で利用させていただいておいて、わがままな意見ですね。。）

- 受験後は問題・採点結果・正解をウェブ上で確認できます。（ただし、各問題の選択肢がどうなっていたかは、後から確認することができません。ですから、模擬試験終了後に振り返りと直しを丁寧におこなうつもりであれば、試験中に選択肢をその都度どこかにコピペしておく必要があります。）

- 複数回受験すると、点数の推移が表示されます。

- 実際のスコア（1000点満点）にあわせて採点されます。


### ②出題の特徴
- pandasのデータフレームやmatplotlibのプロットが画像として表示され、それに関するコーディングが問われる問題が多く出題されます。このタイプの出題は視覚的に分かりやすく、試験の枠を超えて実践的な内容だとも思いました。ただし、本試験でこの手の出題はありませんでした。

- それでも、問題が問うている内容それ自体でみれば、全体的な質問の傾向は本試験と概ね同じでした。

- また、難易度は本試験に比べて模擬試験の方が若干難しかったと思います。


## PRIME STUDY

こちらがもう一つの [模擬試験のサイト](https://study.prime-strategy.co.jp/)になります。

### ①全体的な特徴

- 試験は３回分あります。

- なお、各回で問題が全て新しくなるわけではなく、前回の問題の単語を一部入れ替えたような「使い回し」の問題も少なからずあります。（これは学習の計画や見積もりにも影響する話で、ここの模擬試験を３回受験したからと言って、経験値が単純に3倍になる訳ではありません。）

- 受験後は問題・採点結果・自分の解答と正答がメールで送られてきます。（ただし、各問題の選択肢がどうなっていたかは、後から確認することができません。ですから、模擬試験終了後に振り返りと直しを丁寧におこなうつもりであれば、試験中に選択肢をその都度どこかにコピペしておく必要があります。）

- 一度受験した回も、再度受験することができます。（完全に同じ問題を解き直ししたい時や、気になった問題を後から確認したい時に有効です。）

- こちらの模擬試験は100点満点で採点されますが、本試験と問題数が同じことから、換算の際には点数を単に10倍するだけで大丈夫です。

### ②出題の特徴

- 特に文章題において、選択肢に盛り込まれる話題の量と種類が多いと感じました。（これは、限られた問題数の中で模擬試験としての網羅性を高めようとした結果だと思います。ただし、本試験の出題では、選択肢はもう少し狭い範囲内で構成されていました。）

- 上記にも関係しますが、本試験に比べて難易度が高いというか、出題のスタイルが若干（初学者には）マニアックな方向にズレている気がしました。

- それでも、少し余裕のある初学者にとっては、本試験という枠組みを超えて、やっておいて損はない内容だと思います。

# まとめ

模擬試験を利用した感想を踏まえると、**PRIME STUDY**の模擬試験は**学習編**として準備期間の前半に、**DIVE INTO EXAM**の模擬試験は**実践編**として準備期間の後半に利用する、というスタイルも考えられます。

**＊ただ、上記は私個人の意見ですし、今後、本試験も模擬試験も内容が更新されていくことが予想されますので、あくまで本記事執筆時点での一つの考えとして、参考にしていただければ幸いです。**

最後まで読んできただきまして、ありがとうございました。
【Java】同一性と同値性の判定

##Javaの同一性と同値性の判定

についてまとめました。

## 【同一・同値とは】

Javaは「同じ」と言う言葉に２つの意味を持っていて

- 同じインスタンスであることを「**同一」**
- 同じ値であることを「**同値」**

といいます。

## 【同一性・同値性とは】

- **インスタンスは異なるけど、同じ値を持っていることを同値性**
- **複数の変数が同じインスタンスを参照している性質のことを同一性**

といいます。

それぞれの判定方法は以下です。

- **同一性は ==演算子**
- **参照先にあるインスタンスが同じ値を持っているかはequalsメソッド**

## 【サンプルコード】

以下のコードはこのような流れです。

1.  mainメソッドでSampleのインスタンスを１つ生成
2.  Sample型変数をもう一つ用意し、１つ目のインスタンスへの参照を代入
3. さらにSampleのインスタンスを生成し、そのインスタンスへの参照をsample1に代入

コメントアウト内に詳しい処理の流れを書きましたが、最終的にsample1とsample2は異なるインスタンスとなるため、結果は「false」になります。

```java
public class Sample {
    private int num;

    public Sample(int num) {
        this.setNum(num);
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }
}
```

```java
public class Main {

    public static void main(String[] args) {

        // 1. Sampleのインスタンスを１つ生成
        Sample sample1 = new Sample(10);

        // 2. Sample型変数をもう一つ用意し、１つ目のインスタンスへの参照を代入
        Sample sample2 = sample1; // sample1,sample2は「同一」※同じインスタンスであること

        // 3. さらにSampleのインスタンスを生成し、そのインスタンスへの参照をsample1に代入
        sample1 = new Sample(10);// sample1とsample2は異なるインスタンスへの参照を持っているため「同一」ではなくなる

        System.out.println(sample1 == sample2); // 結果false

    }

}
```

```java
false
```

## 【まとめ】

Silver対策として・・

- **インスタンスは異なるけど、同じ値を持っていることを同値性といい、equalsメソッドで判定。**
- **同一性とは、複数の変数が同じインスタンスを参照している性質のことで、==演算子で判定。**

ややこしいですが、同名でも新しくインスタンスを生成すれば異なるインスタンスとなると覚えておく。

## 参考文献・記事

- [徹底攻略Java SE 11 Silver問題集[1Z0-815]対応](https://www.amazon.co.jp/%E5%BE%B9%E5%BA%95%E6%94%BB%E7%95%A5Java-SE-11-Silver%E5%95%8F%E9%A1%8C%E9%9B%86-1Z0-815/dp/4295007625/ref=pd_lpo_14_img_0/356-5238196-1895250?_encoding=UTF8&pd_rd_i=4295007625&pd_rd_r=1c21865b-a9fe-43e8-ac01-46170e44abca&pd_rd_w=9El0Q&pd_rd_wg=hh5Hc&pf_rd_p=4b55d259-ebf0-4306-905a-7762d1b93740&pf_rd_r=72AVH18EM90CKG00CH5W&psc=1&refRID=72AVH18EM90CKG00CH5W)
疎通確認コマンドまとめ

## ssh
他のコンピュータやサーバに遠隔でログインし、操作するためのコマンド。
通信は暗号化される。
デフォルトのポート番号は22を利用する。

```
ssh [オプション] 接続先 [接続先で実行したいコマンド]
```

```
ssh [オプション] [ログイン名@]接続先 [接続先で実行したいコマンド]
```


## telnet
他のコンピュータやサーバに遠隔でログインし、操作するためのコマンド。
sshとは違い、通信が暗号化されていない。
デフォルトのポート番号は23を利用する。


```
telnet [オプション] 接続先 [ポート番号]
```



## ping
宛先までIPパケットが到達するかどうかを確認するために使うコマンド。

```
ping [オプション] 接続先
```


## nslookup
DNSサーバに名前解決を問い合わせるコマンド。

```
nslookup [オプション] [ドメイン名またはIPアドレス] [DNSサーバ]
```

## curl
curlコマンドとはサーバから、もしくはサーバへデータ転送を行うコマンド。

```
curl -O [オプション] URL
```

## traceroute
操作中の端末から目的のサーバまでのネットワーク経路を調べるコマンド。

```
traceroute [オプション] 接続先
```

## 参考
[【基礎】他サーバとの疎通確認方法まとめ](https://ameblo.jp/bakery-diary/entry-12619471168.html#nc)
ArchUnit 実践：実装上、重要なメソッドアノテーションの付与忘れをチェックする

```
// 実行環境
* AdoptOpenJDK 11.0.9.1+1
* Spring Boot 2.4.0
* JUnit 5.7.0
* ArchUnit 0.14.1
```

## アーキテクチャテストのモチベーション

アプリケーション固有の重要な実装ルールを担保したい。

* バックエンドの REST API サービスを Spring Boot で構築している
* API エンドポイントとなるハンドラーメソッドでは HandlerInterceptor と自作アノテーション（`@Auth`）によって、利用者の「認証」と「認可（権限チェック）」を行っている
* 認証・認可のアノテーションを付与し忘れると、エンドポイントがパブリックに公開されてしまうため、**付与忘れがないことを漏れなくチェックしたい**

ハンドラーメソッドの実装イメージ

```java
// ブログの新規投稿エンドポイント
// `EDITOR`権限以上のユーザのみエンドポイントを利用できる
@Auth(Role.EDITOR)
@PostMapping("/api/blogs")
public Map<String, Object> postBlog(@RequestBody final BlogCreateForm form) {
    // ...
}
```



## アーキテクチャテストの実装

```java
package com.example;
　
import com.example.presentation.Auth;
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.domain.JavaMethod;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.core.importer.ImportOption;
import com.tngtech.archunit.lang.ArchCondition;
import com.tngtech.archunit.lang.ConditionEvents;
import com.tngtech.archunit.lang.SimpleConditionEvent;
import org.junit.jupiter.api.Test;
import org.springframework.web.bind.annotation.*;

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.*;

class ArchitectureTest {

    // 検査対象のクラス
    private static final JavaClasses CLASSES =
            new ClassFileImporter()
                    .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
                    .importPackages("com.example");

    @Test
    void APIエンドポイントでは必ず認証と認可を行う() {
        methods()
            .that(new DescribedPredicate<>("are request handler") {
                /**
                 * @param method 検査対象クラスのメソッド
                 * @return ハンドラーメソッドである場合、true
                 */
                @Override
                public boolean apply(JavaMethod method) {
                    return method.isAnnotatedWith(RequestMapping.class)
                        || method.isAnnotatedWith(GetMapping.class)
                        || method.isAnnotatedWith(PostMapping.class)
                        || method.isAnnotatedWith(PutMapping.class)
                        || method.isAnnotatedWith(PatchMapping.class)
                        || method.isAnnotatedWith(DeleteMapping.class);
                }
            })
            .should(new ArchCondition<>("be annotated with @Auth") {
                @Override
                public void check(JavaMethod method, ConditionEvents events) {
                    if (! method.isAnnotatedWith(Auth.class)) {
                        // 実装ルール違反を通知
                        events.add(
                            SimpleConditionEvent.violated(method, String.format(
                                "`%s` is not annotated with @Auth.", method.getFullName()))
                        );
                    }
                }
            })
            .check(CLASSES);
    }
}
```
Proxy下でSSHを使いたい!!!

# 概要
SSHが禁止されているProxy下でSSHを使う方法です。
私が通っている学校でこれのせいで躓いたので記事にしました。

# 注意
Linux向けに記事を書いています。
WindowsやMacの方はいい感じに変えてください。
また、宛先のホストの443ポートがsshで開いている必要があります。(GitHubだとssh.github.comが対応)

# 忙しい人向け
1. `corkscrew`をインストール
2. 以下の形式で`~/.ssh/config`に追記

```config
Host hoge
  User fuga
  Hostname hoge
  Port 443
  IdentityFile ~/path/to/private/key
  ProxyCommand corkscrew <プロキシサーバーのドメインかIP> <プロキシサーバーのポート> <宛先のドメインかIP> <宛先のポート>
```
(ドメインには`http://`などはつけない)

3. `ssh fuga@hoge`を実行
4. 接続できる!!!うれしい!!!

# 解説(何してるか気になる人向け)
## corkscrewって何
> HTTP プロキシによる SSH のトンネリングを行うためのツール
> Archwikiより引用

というわけでcorkscrewはHTTPProxy下でSSH通信を行いたいときに、プロキシサーバーに対して偽装を行うためのツールとなります。

## configの中身
重要な点だけ掻い摘んで紹介します

### Port 443
これは宛先ポートの指定です。
HTTPトンネリングを行うことでプロキシサーバーの監視を掻い潜るのでこれを設定しない場合プロキシサーバーから403(利用禁止)のレスポンスが返ってきます。

### ProxyCommand ...
```
ProxyCommand corkscrew <プロキシサーバーのドメインかIP> <プロキシサーバーのポート> <宛先のドメインかIP> <宛先のポート>
```
ProxyCommandはサーバーへの接続方法の指定となっています。
そしてここでcorkscrewを使い、トンネリングを行うことによってプロキシサーバーを誤魔化しつつSSH接続を行うことができます。

# 使用例(GitHub)
GitHubではssh.github.comの443ポートに対してトンネリングを行うことができます。
ここではSSH鍵を`~/.ssh/key`、プロキシサーバーを`proxy.server.dayo.com`、ポートを`12345`とします。

```~/.ssh/config
Host ssh.github.com
  User git
  Hostname ssh.github.com
  Port 443
  IdentityFile ~/.ssh/key
  ProxyCommand corkscrew proxy.server.dayo.com 12345 ssh.github.com 443
```
このファイルを書いたあと、`ssh -T git@ssh.github.com`を実行すると返答を確認できます。

```
PTY allocation request failed on channel 0
Hi isso0424! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.
zsh: exit 1     ssh git@github.com
```

# さいごに
HTTPトンネリングという物の存在を今日始めて知ったので「世界って便利だなぁ...」ってなりました。
これからもこんな感じで広い方面に知識を付けていけたらと思います。

# 参考資料
[Archwiki-HTTPトンネリング](https://wiki.archlinux.jp/index.php/HTTP_%E3%83%88%E3%83%B3%E3%83%8D%E3%83%AA%E3%83%B3%E3%82%B0)
[GitHub-HTTPS ポートを介して SSH を使用する](https://docs.github.com/ja/free-pro-team@latest/github/authenticating-to-github/using-ssh-over-the-https-port)
TSX内でジェネリクスの型引数を1つにする方法

## やりたいこと

tsxファイル内で、型引数が1つの関数を作る。

```typescript
const fn = <T>() => {
  // 省略
}
````

## 困った事

tsファイルであれば上記のように書くだけですが、tsxファイル内だと下記のエラーが出ます。

> TS17008: JSX element 'T' has no corresponding closing tag.

これは`<T>`がコンポーネントとして認識されてしまっているためです。

## 回避方法

型引数の後にカンマをつける

```typescript
const fn = <T,>() => {
  // 省略
}
````

この方法は、こちらの [issue](https://github.com/Microsoft/TypeScript/issues/15713#issuecomment-499474386)で紹介されていました。

他にも`<T extends {}>`などでも回避出来るという記事がありましたが、
私の環境ではeslintの@typescript-eslint/ban-typesでエラーになったため採用しませんでした。
[ML Ops] Pythonでマルチプロジェクトをやりたい


この記事は [ぷりぷりあぷりけーしょんず Advent Calendar 2020](https://qiita.com/advent-calendar/2020/ppap) の13日目の記事です。

# はじめに

普段は Python を使って MLOps の業務に取り組んでいます。元々は、 Java や Kotlin など、 Maven や Gradle　といったビルドシステムで開発を行っていました。
最近使っている Python は単発のスクリプトや機械学習の文脈では非常に強力なツールだと思います。しかし、実際にプロダクトレベルの運用を始めると、依存関係や共通化の難しさ、ビルド周りの弱さに疲弊してしまう側面もあると思います。
そこで、Java や Kotlin などで使われるマルチプロジェクトの構成を Python で再現したら非常に開発が楽になりました。
今回はそのナレッジを記事にしていきます。

※今回の記事で紹介するアイデアはこちらを参考にさせていただきました → https://medium.com/opendoor-labs/our-python-monorepo-d34028f2b6fa


# なぜマルチプロジェクトが必要だったのか

冒頭に記述した通り、筆者は普段は AI に関係するプロダクトで MLOps を中心とした業務に取り組んでいます。
開発を進めていくうちに以下のような課題が発生しました。

- 学習時と推論時に同じ前処理をしなくてはいけない → コードのコピペが発生
- モノレポにしたいけど、 pip の依存解決のトラブルが多くてできない → 増える新しいモジュールやリポジトリ

これらの課題を整理した結果以下のような用件が出てきました。

- **それぞれのモジュールは独立した依存関係を定義したい**
- **共通化した処理を使いまわしたい**
- **依存先の一覧などが一眼でわかるようにしたい**


これらを解決するには、 private な pip server を立てたり、 Pickle Object を Storage へ置くなどの案があがりましたが、いずれもメンテナンスコストの観点から却下しました。そして、たどり着いたのが、 `Maven や Gradle などを使ったマルチプロジェクトの構成を Python & Poetry で再現することでした`。


# マルチプロジェクトの利点

実際の Maven, Gradle などによるマルチプロジェクトの概要や利点は、まとまった物が世の中にたくさんあるので、解説しません。
今回は ML Ops と Python の都合によるメリットを上げていきます。

- **前処理が共通化できる**
- **モデルごとに依存を個別管理できる**

また、マルチプロジェクトを実現するために、 Poetry を利用しています。すると、追加で以下のようなメリットも享受できます。

- **setup.py　や requirements.txt を用意しなくて良い。**
- **コマンド１つで仮想環境と依存が解決できる。**
- **pipenv よりも洗練された 依存解決のアルゴリズムを利用できる。**


# さあやってみよう

## ディレクトリの構成
ディレクトリ構成は非常にシンプルです。

```
.
├── README.md
├── libs
│   ├── lib-one
│   └── logger
└── projects
    ├── __init__.py
    ├── project-one
    └── project-two
```

それぞれは以下のような役割になっています。

./lib  -> 複数のプロジェクトで使いまわしたい共通モジュール
./projects -> ユースケースを実行するメインモジュール

projects 以下のモジュールは libs 以下のモジュールに依存します。


## モジュールを追加する

モジュールを追加する時は libs でも projects であっても同じです。
poetry の new コマンドで生成していきます。

```shell

# 共通モジュールを追加する場合
cd libs/
poetry new lib-two

# メインモジュールを追加する場合
cd projects/
poetry new project-three
```

以上でOKです。Poetryが勝手に雛形を生成してくれます。
あとは好きなように実装をしていきましょう！


## モジュールに依存関係を追加する

それでは、実際にメインモジュールに共通モジュールの依存関係を追加する方法を見ていきます。と言っても、とても簡単です。

```shell

cd projects/project-one
poetry add ../../libs/lib-one
```

`poetry add {入れたい共通モジュールのパス}` だけでできてしまいます。
pyproject.toml を見てみるときちんと依存が追加されていることが確認できます。

```toml

[tool.poetry]
name = "project-one"
version = "0.1.0"
description = ""
authors = ["ya-mori <ppap.yohei.moriya@gmail.com>"]

[tool.poetry.dependencies]
python = "^3.7"
lib-one = {path = "../../libs/lib-one"}

[tool.poetry.dev-dependencies]
pytest = "^5.2"

[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"
```

この依存関係の追加方法は公式のドキュメントにも記載があります。(https://python-poetry.org/docs/cli/#add)

この方法の素晴らしい点は、共通モジュールの変更がすぐに反映されることです。つまり、いちいちビルドし直す必要はありません。

以上で、 好きなメインモジュールに好きな共有モジュールの依存を追加することができました :smile: 


# さいごに

今回は Python でマルチプロジェクトを実装する方法についてまとめて行きました。
実際の業務ではこれらを Dockerfile に修めなくてはいけないため、もう一苦労あったのですが、それはまた別の機会にご紹介したいと思います。
少しでもあなたの役に立てれば幸いです。
やばい!!報連相の精度をもっと鍛えなきゃ...

## ◆はじめに
当記事は底辺エンジニアである私が自身の研鑽のために
学習した内容の整理、再認識することに重きを置いています。
したがって、本記事の目的は以下の2点です。

* インプットした内容の整理と再認識のためアウトプットする
* (あわよくば)同じような悩みを持つエンジニアの参考にしてもらえれば...

今回自己研鑽のために読書した本は <b>佐々木 圭一さん著『伝え方が9割』</b>です。

## ◆読書前の話
1. <b>読もうと思ったきっかけ</b>
  * 口頭での報連相で詰まることが増えた
  * 自身の成果を十全に伝えられないと思うことが増えた
  * メールやWebフォームの回答の文面に悩むことが増えた
  
2. <b>読書後に期待した効果</b>
  * 効率的な情報伝達の仕方の知見が広がること

## ◆読書後
1. <b>本の感想</b>
  * 「コミュニケーション力」が高いとされる人間の共通点がわかりやすくまとめられていた
  * 「印象に残る言葉」を作る法則性が実例込みでまとめられていた
  
2. <b>業務に活かせそうだと感じたところ、活かすのが難しそうだと感じたところ</b>
  * <b> 活かせそう</b>
        * お客さまへの商品説明やプレゼン、講演会には転用が効きそう
        * 業務上の上司ではなく所属本部の役職者と考課に関する面談などの会話をする際に印象に残る会話を行えそう 
  * <b>活かすのが難しそう</b>
        * ビジネス上の書類作成など、口語的な活用以外では難しそう

3. <b>読書前に感じていた課題の解決に繋がったか</b>

    |課題|結果|
    |:-----|:-----:|
    |口頭での報連相で詰まることが増えた|△|
    |自身の成果を十全に伝えられないと思うことが増えた|△|
    |メールやWebフォームの回答の文面に悩むことが増えた|×|
 
## ◆その他感想
1. 読む前の目的だった課題を解決するには物足りなかった
2. 漠然と認識していたが、法則性として意識してみると仕事だけではなくプライベートでも活用できそう

## ◆おわりに
今回の本は、最近の自身の悩みに対する特効薬とはなりえなかったと感じました。
ただ、長い目で見た際に「なんとなく」ではなく、
「意識して」印象的な言葉になるように考えられるのは無駄ではないと思います。
余談ですが、当記事のタイトルにも今回読んだ本の技術を利用しております。(正しく利用できているだろうか...)
続編もあるそうなので時間あるときに読んでみようと思います。



初めての記事だけど、アウトプットにするのってやっぱり大変ですね...

## ◆リンク
https://www.amazon.co.jp/dp/B00BHCM7HE/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1
（解決方法）Mysql2::Error: Table 'users' already exists

## 発生したエラー
devise導入の流れの中で、マイグレーションファイルを修正し、いざrails db:migrateを実行すると、下記のエラーが発生。

Mysql2::Error: Specified key was too long; max key length is 767 bytes

調べたところ、database.yml の、  encoding: utf8mb4を  encoding: utf8へ修正する必要がある。
（utf８mb4だと、１文字あたり4bytes使い、文字数制限をoverしてしまうそうだ）

そのため、encoding: utf8へ修正し、再度rails db:migrateを実行すると、タイトルのエラー（下記）が発生。
Mysql2::Error: Table 'users' already exists

## 調べた内容と仮説
エラーを和訳すると、usersテーブルが既に存在するということ。
今回、rails db:migrateを実行しようとした結果、表示されたエラーであるため、恐らくすでにmigrateされている
（=ststusがupの状態）ということのはず。

つまり、rollbackし、usersテーブルを一度削除し、再度作成すれば解決する、という仮説が建てられる。

## 仮説に基づいた実行結果
rails db:rollback
rails d devise user
rails g devise user
マイグレーションファイルを修正
rails db:migrate

→再度タイトルのエラー（Mysql2::Error: Table 'users' already exists）

意味がわからない。。

## 結論
結果として、rails db:resetで解決されました。
この理由としては、schema.rbの存在でした。

このファイルは、migrateファイルの生成順序などを管理しています。
そして、このファイルをリセットしなければ、例えテーブルを削除したところで、upの状態になっているそうです。
なので、一度テーブルを削除しても、エラーが維持されるようであれば、resetを頭に入れるべき。

注意点としては、別のテーブルもリセットされてしまうこと。慎重にならなければならない。
Spring 案件ソルーション Rest API　手順書フォルダ

#SpringBoot総復習
##やって見て
結構難しかったです。
ご指摘あればよろしくお願いいたします。
##お役立ちサイト
https://zenn.dev/sugaryo/books/spring-boot-run-up/viewer/spec
##概要
SpringBootの総復習をしようと思います。（Rest API)

##演習問題をAPI化しています。
https://masahiroharada.github.io/spring-boot-primer/practice/practice-application.html
##アウトプット
https://github.com/noikedan/search-rest

##演習問題で作成したソース抜粋

```
package com.example.searchrest.controllers;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.example.searchrest.domains.Task;
import com.example.searchrest.mappers.TaskMapper;

@RestController
public class TaskController {

	private final TaskMapper taskMapper;

	@Autowired
	public TaskController(TaskMapper taskMapper) {
		this.taskMapper = taskMapper;
	}

	@GetMapping("/")
	public List<Task> index(Model model) {
		List<Task> tasks = taskMapper.all();
		model.addAttribute("tasks", tasks);
		return tasks;
	}

	@PostMapping("/add")
	public void create(@RequestBody Task task) {
		taskMapper.add(task);
	}

	@PutMapping("/complete")
	public void put(@RequestBody Task task) {

		Task t = new Task(task.getId());

		taskMapper.complete(t);
	}

}

package com.example.searchrest.domains;

import java.util.Date;
import lombok.Data;

@Data
public class Task {

	public Task() {

	}
	public Task(String title, Date lmt) {
		this.title = title;
		this.lmt = lmt;
	}

	public Task(int id) {
		this.id = id;
	}

	public Task(int id, Boolean status, String title, Date lmt) {
		this.id = 0;
		this.status = status;
		this.title = title;
		this.lmt = lmt;
	}

	private int id;
	private boolean status;
	private String title;
	private Date lmt;
}

package com.example.searchrest.mappers;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.example.searchrest.domains.Task;

@Mapper
public interface TaskMapper {

	List<Task> all();

	void add(Task task);

	void complete(Task task);

}

```

##チェックシート内容
品質向上のためのチェックシート
1.アノテーション「＠RestController」がついている。
2.一覧・登録・完了機能を確認する。
3.一覧表示の時はJSON形式で表示する。
4.application.propertiesを正しく設定しているか確認する。
5.Mapper XMLを正しいフォルダ構成で設定しているか確認する。
6.データベースが起動しているか確認する。
【Jenkins：Mac】ユーザーのジョブ操作制限

# 概要

ユーザーによってジョブの操作を制限したい

Jenkinsバージョン：2.270
Role-based Authorization Strategy：3.1
※Jenkinsとプラグインのバージョンが異なると動作しない可能性があります

# 1. プラグイン追加

まず最初に
Jenkinsの管理 > プラグインの管理 > 「利用可能」タブ
から「Role-based Authorization Strategy」を探してインストールしてください
再起動は不要だと思うので「install without restart」でインストール

# 2. 権限管理設定

Jenkinsの管理 > グローバルセキュリティの設定
から画像のように「Role-Based Strategy」を選択
![jenkins06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216261/00d472b5-30e1-c5b8-d264-a88058d56dfc.png)

# 3. 制限するユーザーの作成

※すでにあれば作成不要

Jenkinsの管理 > ユーザーの管理 > ユーザー作成
からユーザーを作成してください

ユーザー名とパスワードはJenkinsログイン時に使用するものです
![jenkins07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216261/9761f57d-d2fe-171f-8dbc-82c36b72f93e.png)

この時点で上記で設定したユーザーでログインしてみてください
特に制限していないのでジョブは操作し放題だと思います

# 4. 制限設定

どういう制限をかけるかはその時の状況によると思うけど
今回は指定したユーザーは一部のジョブの閲覧とビルドだけできるようにしてみます

#### 管理設定

Jenkinsの管理 > Manage and Assign Roles > Manage Roles

役割名を適当に付けて「Role to add」に入力してAddボタン
リストに追加されるので「Read」だけチェックをつける
画像の例の役割名がsampleでややこしいけどユーザー名とは別物です（画像みたいに一緒でもいいです）
![jenkins08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216261/cc83710b-c747-7eac-d032-0c5742aaf2a5.png)

次に制限するジョブの設定をします
こちらも役割名なので自由に付けてください
Patternには制限したいジョブ名を記載します
ジョブ名がルール付けされてる（プロジェクト名とか）のであれば正規表現（`.*`）でまとめられます
画像の例であれば「sample-」が一致するジョブがすべて当てはまります

Addボタンでリストに追加後、Patternに記載されてる文字をクリックすると当てはまるジョブが表示されます
画像ではビルドとビルドキャンセルと閲覧を可能にするためにチェックを入れてます
※旧バージョン？だと「Item roles」が「Project roles」って名前になってるので注意
![jenkins09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216261/44f075f6-1bca-1759-4562-6663d409af34.png)

一通り設定し終わったら一番下にあるSaveボタンを押すのを忘れずに

#### 割り当て設定

Jenkinsの管理 > Manage and Assign Roles > Assign Roles

今度はユーザー名を「User/group to add」に入力してAddボタン
リストにManage Rolesで追加した役割の列があるので指定のユーザーのチェックを入れる
![jenkins10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216261/84986db8-5422-6b09-2784-7715d2270b4e.png)

こちらも同じく「User/group to add」にユーザー名を入力してAddボタン
さらに同じくリストにManage Rolesで追加した役割の列があるので指定のユーザーのチェックを入れる
![jenkins11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216261/7f8211ea-d228-b810-31fd-1f3edcd6879d.png)

これで設定完了

# 5. 制限されたユーザーでログイン
作成したユーザーでログインしてみます
![jenkins12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216261/11203f37-61ce-d16b-8e22-7b96b86b06a4.png)
指定したジョブしか閲覧できなくなってるかと思います
ビューも閲覧可能なジョブのものしかでてこないです


ちなみにプラグインの公式サイトもあるんですが画像が最新じゃないので逆に混乱した（2020/12/14時点）
参考まで
https://plugins.jenkins.io/role-strategy/
pythonでメールを送信してみました。

#pythonでメールの送信してみました。
この記事は、SLP KBIT Advent Calendar 2020 の14日目の記事です。
今回はPythonでメールの送信をしてみました。ソースコードのサンプルは	Webにあります。（https://docs.python.org/ja/3/library/smtplib.html）
##目次
・開発環境
・メールの自動送信の仕組み
・送信のプログラムを作ってみる。
・終わりに

###開発環境
・python3.9.0
・VS code

###eメールの自動送信のしくみ
eメールはスマホやパソコンから自身のメールサーバーに送られます。次に自身のメールサーバーから受信先のメールサーバーに送られます。そして相手のデバイスにメールが受信されます。
今回はしませんが、メールの自動送信をするには自身のメールサーバーから自身もサーバーに送信するプログラムを作ります。
今回はpythonでgmailを送信します。

####SMTPサーバのアドレスを入力する。
まず、https://docs.python.org/ja/3/library/smtplib.html のサンプルコードをエディタにペーストします。

```
import smtplib

def prompt(prompt):
    return input(prompt).strip()

fromaddr = prompt("From: ")
toaddrs  = prompt("To: ").split()
print("Enter message, end with ^D (Unix) or ^Z (Windows):")

# Add the From: and To: headers at the start!
msg = ("From: %s\r\nTo: %s\r\n\r\n"
       % (fromaddr, ", ".join(toaddrs)))
while True:
    try:
        line = input()
    except EOFError:
        break
    if not line:
        break
    msg = msg + line

print("Message length is", len(msg))

server = smtplib.SMTP('localhost')
server.set_debuglevel(1)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()
```
24行目の'localhost'はサーバーアドレスです。これを'smtp.gmail.com'に変更します。またポートを指定する必要があるので先ほど入力したアドレスの後に「587」と入力します。(今回はTLSを使用しているので587と入力しましたが、SSLを使用する場合は465と入力します。)

```
server = smtplib.SMTP('smtp.gmail.com', 587)
```


####自分と相手のメールアドレスを入力します。
6行目の「From」に自分のメールアドレスを入力します。また7行目の「To」に相手のメールアドレスを入力します。相手が一人の場合、7・12・26行目の「toaddrs」のsを消します。また12行目を以下の画像のように変更します。

```
import smtplib

def prompt(prompt):
    return input(prompt).strip()

fromaddr = 'ここに自分のメールアドレスを入力します。'
toaddr  = 'ここに相手のメールアドレスを入力します。'
print("Enter message, end with ^D (Unix) or ^Z (Windows):")

# Add the From: and To: headers at the start!
msg = ("From: %s\r\nTo: %s\r\n\r\n"
       % (fromaddr, toaddr))
while True:
    try:
        line = input()
    except EOFError:
        break
    if not line:
        break
    msg = msg + line

print("Message length is", len(msg))

server = smtplib.SMTP('smtp.gmail.com', 587)

server.set_debuglevel(1)
server.sendmail(fromaddr, toaddr, msg)
server.quit()
```

####ログインパスワードを設定する。
アプリやプログラム経由でメールを送る場合はアプリパスワードが必要があります。アプリパスワードを設定するには2段階認証が必要なので最初に2段階認証を設定します。
以下の手順で2段階プロセスを有効にします。
1googleアカウントを開く
2ナビゲーションパネル(左に表示されている。)でセキュリティを選択
3[googleへのログイン]で[2段階認証プロセス]の[使ってみる]を選択
4画面の指示に従い手順に従い手順を完了をする。
次にアプリパスワードを設定します。
1googleアカウントを開く
2ナビゲーションパネルでセキュリティを選択
3アプリパスワードをクリック
4画面の手順に従い手順に従って手順を完了する。
次に26行目以降を下のコードに変換します。

```
server.ehlo()
server.starttls()
server.login('自分のGmailのアドレスを入力', 'パスワードを入力')

server.set_debuglevel(1)
server.sendmail(fromaddr, toaddr, msg)
server.quit()
```
####メールの送信
プログラムを実行し、本文を入力することによってメールを送信します


###終わりに
今回はメールを送信するプログラムを作ってみました。
次はメールの自動化をやってみようと思います。
この記事はhttps://www.youtube.com/watch?v=zdPDrtTrqqQ
を参考に作成しました。
# Gitで修正パッチファイルを作成する

※作業メモ

## 概要・背景
Gitで修正パッチファイルを作成・適用する際に行った作業メモ。
自作アプリについて、複数のDB環境で動かす必要があり、その切り替えをスムーズに行う必要があったので、
「MySQL ⇔ Oracle」に簡単に変換できる修正パッチを作成した。

## 作業内容
対象Repositoryまで移動後、
・修正パッチの作成: `git format-patch [コミットid]` (※1)
・修正パッチの適用: `git am [patch file name]`

(※1)現在のcommitから指定commit前までのパッチを作成するため、以下のコミット履歴であれば、
「user ⇒ SpringUserに修正」のコミットidを指定してgit format-patchを実行すれば、
「MySQL⇒Oracleで動くよう修正」までの修正を含めたパッチが作成される。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602075/2a1efa9a-3fc7-226e-d4c9-525f91d17990.png">


## ちなみにMySQL ⇒ Oracleで行った修正内容
* application.properties

```diff
# Oracle DB
+spring.datasource.url=jdbc:oracle:thin:@192.168.10.103:1521:orcl
+spring.datasource.username=**********
+spring.datasource.password=**********
+spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver

# MySQL DB
-spring.datasource.url=jdbc:log4jdbc:mysql://localhost:3306/springdb?serverTimezone=JST
-spring.datasource.username=**********
-spring.datasource.password=**********
-spring.jpa.database=MYSQL
-spring.datasource.driverClassName = net.sf.log4jdbc.DriverSpy
```

* build.gradle

```diff
-runtimeOnly 'mysql:mysql-connector-java'
+compile group: 'com.oracle.database.jdbc', name: 'ojdbc8', version: '19.8.0.0'
```

* 各EntityでSequenceを使うよう修正

```diff
-@GeneratedValue(strategy = GenerationType.IDENTITY)
+@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_CUSTOMER_GENERATOR")
+@SequenceGenerator(name = "SEQ_CUSTOMER_GENERATOR", sequenceName = "SEQ_CUSTOMER", allocationSize = 1)
```
## 参照
https://codechacha.com/ja/git-patch/

## あとがき
最近はOracleの有償サポートが高いということでPostgreSQLやMySQLに移行できないかという問い合わせがありますね。
あとはAWS Auroraへの移行とか。
DB環境を変えた場合の影響調査のリストとか誰かまとめていないかなぁ。
RESTとは何なのか

## 背景
RESTというものが何なのかいまいち実態がつかめずにいたので腰を据えて調べてみたらわかってきたのでまとめたかった。

## RESTはWebのアーキテクチャスタイル
まず前提としてRESTというのは具体的なものではなく**思想**です。ここが曖昧になっており今まで理解ができていませんでした。正確にいうと**アーキテクチャスタイル**と呼びます。直訳で**設計思想**ですが、同じような思想としてフレームワークでの**MVC**などがこれに当たります。

## RESTを構成する要素
そしてRESTというのは複数のアーキテクチャスタイルを組み合わせて作られている**複合アーキテクチャスタイル**です。RESTを構成する要素はいかの通りです。

- クライアント/サーバー
- ステートレスサーバー
- キャッシュ
- 統一インターフェース
- 階層化システム
- コードオンデマンド

これら6つの設計思想を複合してRESTは成り立っています。この制約をしっかり守っているWebサービスやWeb APIなどが***RESTful***と呼ばれています。
１つ１つの要素を見ていきましょう。

## クライアント/サーバー
WebはHTTPというプロトコルでクライアント(ブラウザなど)からリクエストを送り、それに対してサーバーがレスポンスを返します。
この分業によってサーバーはデータストレージ、クライアントはUIに集中できる構造となります。

## ステートレスサーバー
クライアントのアプリケーション状態をサーバーが管理しない状態のことを指します。これにより計算機リソースを確保することができるのと実装を簡略化することができます。
とはいえ、私たちはWebサービスで***ログイン***などができます。これはcookieを使用し、サーバーにてセッションを管理して認証することで実現しています。
つまりログインなどの認証システムは***設計思想から外れている***わけです。
ログイン状態を保持するため、あえてこの思想を***捨てている***のを理解するのがミソです。

## キャッシュ
キャッシュは一度取得したリソース(Webに存在する情報)をクライアント側で使いまわすことを指します。この利点は通信を減らすことでネットワーク帯域の利用や処理時間を減らして効率的に処理ができるようにしています。要は早くブラウザが表示されるということです。

## 統一インターフェース
URI(URLも指す)に対する操作を限定して利用します。GETやPOSTなどの**8個のメソッド**のことを指します。そしてこれ以上にメソッドを拡張しないことを約束することでアーキテクチャが***シンプル***になります。
つまりこの一見厳しいようにも見える制約があるがゆえに現在の様々なクライアント(スマホなども含む)やサーバーの構成に一役買っているわけです。

## 階層化システム
インターフェースの統一をすることで階層化が可能となります。サーバーを複数台設置しロードバランサーで負荷分散をしたり、プロキシサーバーを用意しアクセス制限を行ったりすることが容易に可能となります。これはインターフェースを統一することで別のサーバーやプロキシでも同じインターフェースで接続できることが保証されているためです。

## コードオンデマンド
プログラムコードをサーバーからダウンロードしそれをクライアントで利用できます。**JavaScript**がこれにあたります。

## Roy Fielding
これらの要素を合わせてもともとは***ULCODC\$SS***($Uniform$ $Layered$ $Code$ $on$ $Demand$ $Client$ $Cache$ $Stateless$ $Server$)という名前でした。キャッシュはお金の意味の発音と同じことからダラー\$で表現しています。
2000年当時カリフォルニア大学の大学院生だったRoy FieldingはこのアーキテクチャスタイルをREST($Representational$ $State$ $Transfer$)と名付けて博士論文として発表しました。
のちにAmazonやGoogleがこのRESTを採用したAPIを発表し、この設計思想は定着していきます。

## 所感
１つずつ要素を見てみると使ったことのある機能ばかりで身近にこの設計思想が存在しているのが実感できました。これからはRESTという単語が出てきてもすんなり入ってきそうです。
チャート式 第2回まとめ

\![Mac OS X-10.15.7](<https://img.shields.io/badge/MacOSX-10.15.7-brightgreen>) \![ruby-2.7.1p83](<https://img.shields.io/badge/ruby-2.7.1p83-brightgreen>) 


# 今回の問題

受け取った引数ARGV[0]をnameという変数(variable)に代入してそれを打ち出すcodeを書きなさい．

    > ruby name_variable.rb Rudy
    Rudy


# 簡単な解説

Rubyには型の宣言は必要が無い．シンプルにイコールを使えば良い．

```ruby
name = 'Rudy'
```


# 詳しい解法

    > ruby name_variable.rb Rudy

とした際，

    ruby: No such file or directory -- name_variable.rb (LoadError)

そのようなファイルはないと返ってくる．emacs を起動させて

    > emacs name_variable.rb

以下のようにコードを打ち込み，C-x→C-sで保存．

```ruby
p "Rudy"
```

すると，先ほどのエラーが消えて”Ruby”と表示される．

    > ruby name_variable.rb Rudy
    "Rudy"

　


# 類題

-   nameに代入してRudyと打ち出すようにrefactoringしなさい．
-   ARGV[0]を受け取って，自分の名前を返すようにrefactoringしなさい．

※refactoring：プログラムの外部からみた動作を変えずにソースコードの内部構造を整理すること．


# お題

    > ruby hello_method.rb Rudy
    Hello Rudy.

と返すhello methodを作れ．


# 解説

Rubyではfunctionやprocedureなどのまとまりはmethodを定義(definition)することになる．methodは0個以上の引数を取ることができる．

```ruby
def hello(name)
  p name
end
```


# 解法

emacsでhello\_method.rbを編集する．

    > emacs hello_method.rb

今回はmethodの中身ではなく呼び出す方から考える．

```ruby
hello(name)
```

とすると，以下のようなエラーメッセージが表示される．

    > ruby hello_method.rb Rudy
    hello_method.rb:1:in `<main>': undefined local variable or method `name' for main:Object (NameError)

nameが未定義であるという意味のエラー．そこで，nameにARGV[0]を代入して実行すると．

```ruby
name = ARGV[0]
hello(name)
```

次のようなエラーメッセージが表示される．

    > ruby hello_method.rb Rudy
    hello_method.rb:2:in `<main>': undefined method `hello' for main:Object (NoMethodError)

Helloのmethodがない．つまり，

```ruby
def hello(name)
    p name
end
name = ARGV[0]
hello(name)
```

とすればよい．



------
 - **source** ~/grad_members_20f/members/szksjm/qiita_post/R2.org
Docker + Playframework環境にてログの出力で詰まった話

この記事は ウェブクルー Advent Calendar 2020 15日目の記事です。
昨日は @piwi さんの「 [私的Nuxt.jsでサイト制作したときに悩んだ＆悩んでること(コーダー)](https://qiita.com/piwi/items/980f1306e14c6f27b3f3) 」でした。

## はじめに
普段はサーバー側の実装をしている人間です。多少フロントも触る機会があります。直近ではscala,java,nuxtjsなどやっています。
ちょうどいいネタが思いつかなかったので最近、環境の設定でちょっと困ったこととその対応について書きます。

## ログの出力とローリング設定
環境
CentOS
Docker + Playframework(scala) + Logback


課題：新環境でのツールをリプレイスするにあたって、本番・開発環境設定の一環でログファイルの出力設定をしたい。

前提：stdoutでのログ確認は実装時に既にできている。ログ出力はLogback（デフォルト）

## 最初にやったこと
- logback.xmlでログのファイル出力設定を変更
- docker-compose.ymlに出力先のフォルダのマウント設定追加
↓追加、変更内容（なお、変更前のxmlファイルはplayframeworkで初期化した時に自動で生成されたlogback.xmlほぼそのまま）

```logback.xml
  <property name="LOG_HOME" value="/home/appserver" />

  <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${LOG_HOME}/logs/rolling_application.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- Daily rollover with compression -->
      <fileNamePattern>${LOG_HOME}/logs/application-log-%d{yyyy-MM-dd}.gz</fileNamePattern>
      <!-- keep 90 days worth of history -->
      <maxHistory>90</maxHistory>
    </rollingPolicy>
    <encoder>
      <pattern>%date{yyyy-MM-dd HH:mm:ss ZZZZ} [%level] from %logger in %thread - %message%n%xException</pattern>
    </encoder>
  </appender>

  <appender name="ASYNCFILE" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="ROLLING" />          <!-- 変更 -->
  </appender>

  <root level="WARN">
    <appender-ref ref="ASYNCFILE" />        <!-- 変更 -->
    <appender-ref ref="ASYNCSTDOUT" />
  </root>

```

```docker-compose.yml
version: '3'

services:
  play-runtime:
    image: play-runtime:latest
    container_name: play-runtime
    restart: always
    ports:
      - "9000:9000"
    stdin_open: true
    volumes:                                <!-- 追加 -->
      - ./logs:/home/appserver/logs         <!-- 追加 -->

```

確認のため、自前のPCにてログのローリング設定を分単位にして問題がないか試した。
ローカルで動作確認して問題がなかったので開発環境へアップしたところ、ログが出力されず頭をひねる。
ちなみに、分単位でファイルを切り分けるにはfileNamePattern末尾を`%d{yyyy-MM-dd}`から`%d{yyyy-MM-dd-HH-mm}`みたいにしてやればいい。

### 発生していたと思われる問題
該当のlogフォルダはできていたのに、ファイルは出力されなかった。
以下の記事を参考に、フォルダの所有者権限がネックになっていると予想。
ちなみに、dockerでは一般ユーザー（ユーザー名appserver）を作成してコンテナとアプリケーションを起動している。
https://qiita.com/yohm/items/047b2e68d008ebb0f001

```Dockerfile
RUN groupadd --gid 1001 appserver \
 && useradd --gid 1001 --uid 1001 -m appserver

USER appserver 
```

## 対応
Dockerfil内でフォルダを作成するコマンドを追加。

```Dockerfile
RUN mkdir -p -m 777 /home/appserver/logs \              # 追加
 && chown appserver:appserver /home/appserver/logs
```

無事ログ出力が確認できた。
参照記事のようにアプリケーションの起動スクリプトで作成してもよいと思われる。

## 試してうまくいかなかった対応
参考程度に。

Dockerfile内でユーザー切り替え前にディレクトリ作成→一般ユーザーに所有権限を与える
chmod,chown両方を試してみたが、コンテナを起動した後execにて権限を確認したところ、rootユーザーのみに所有・書き込み権限が与えられておりログ出力はできなかった。

また、なぜローカルの環境で問題なかったかというと、どうやら docker for macだと勝手に権限を良きようにしてくれるらしく、他にも同じようにMacの環境だとうまく行くのにlinuxだとダメ！みたいに記事を書いている人がいた。


明日は@ee4839さんです！よろしくお願いします。
それほどかしこまらなくても書けるPWA

ども
連続何日書いてたっけ。
もう忘れてしまった。
[PWA Advent Calendar 2020](https://qiita.com/advent-calendar/2020/pwa "PWA Advent Calendar 2020")14日目です。
#PWAって難しく考えてませんか？
PWAというのはスマホ上で動くWebアプリのこと言います。
実際には携帯サイズに合わせてCSSやjQueryMobileやReactを使って書いているアプリのことを言います。
スマホアプリで一番とっつきやすいのが実はPWAで自分も昔得意にしていました。
ある会社の教育関係アプリを3ヶ月でWeb上で動くようにプログラミングしたこともあったっけ。
そのあとはめっきり普通のWebアプリ書いてましたが。
一般職に行く前にガリガリとタイムラインを生成するフレームワークを書いてました。
#PWAにはいろんな要素が含まれている
PWAってスマホで表示できるアプリだけだと思ってませんか。
実は裏側は実はC#やPHP・Pythonなどでデータベースに接続されています。
一時期自分もしたんですがHTML5ではもう書けない宣言なんてものをしたことがあります。
それはJavascriptさながら裏側で動くサーバスクリプトが動きが早くブラウザが表示することが遅かったために発生しました。
PHP主体でやっていたFacebookがHTML5に手を出しやけどしたのがちょうど自分がガリガリとある業種のソフト作っていたときでした。
しかも特殊で打倒〇〇〇と叫びながら作るもんですから困らされたのですが実はこのときもう一つの動きとして日報をスマホで書きたいという話も出てきていました。
だけど書くのに疲れた自分は追加のやまと格闘しながらHTML5で各道を選びすっと書き続けました。
その時は盆暮れ正月なしの上土日までフルに使ってました。
その時の上司はどこか逃亡したみたいですけどね。
#昔はガリガリ書ける人にしかできませんでした。
マジでこれ入っておきます。
Reactが来るまでは狂うくらいの仕事量でした。
HTML5を動かすためにはまずCSSをスマホ仕様にHeightやWidthを％表示に変えるところから始まります。
その後動作をつけるためにjQueryMobileでフルスクラッチをしバックエンドに投げるためにAjaxやAsync/Awaitなどを使って書くことになります。
最近はPromiseが多いみたいですけど。
これがまた大変です。
送り出すのにどの手法をp使うかで変わってきます。
昔みたいにPost/Getでやれればよいのですがセキュリティが関わってくるので最近はJSONオブジェクトが多いみたいですね。
JSON配列じゃないですよJSONオブジェクトです。
なぜJSONオブジェクトかというと内部が暗号化され復号化されるまでは何が入っているかわかりにくいからです。
これでPHPとやり取りをしデータベースへとアクセスしていたというわけです。
#タイムラインってなんで難しいの
はっきり言っておきます。
タイムラインをPWAで書くのは至難の業です。
大概の人は見つけ出す前に投げ出してしまう人が大半です。
自分が一回一般職に言って体を治そうと思ったのはこれで精神が狂ってしまったからなんです。
それほど大変です。
今みたいに全部Listでやればいいじゃんじゃないんです。
これやったらおそらく完璧に1年はかかるでしょう。
昔のWeb書いている人なら簡単に思いつくことです。
そうですTableを使うんです。
これじゃないと早くは書けません。
Listだといろんな制限が満載で描くだけでお腹いっぱいになります。
本当ですよ。
気が狂っちゃいます。
削ったり順番入れ替えたり追加したりするとListって案外使いようにならないということがやっていてわかりました。
結局HTML5はTableから逃げられないということだけ言っておきましょう。
業務アプリもほとんどがTableで書かれてますしね。
#地図アプリはPWAがいいよ
そう言えば第2回中京テレビハッカソン優勝作品の[またたび](https://matatavi.net/ "またたび")って知ってますか。
あれは対策です。
ときにはライバルでもあり同士でもある瀬谷さん青島さん川合くんの三人が作ったアプリで実はこれが優勝したときに俺の得意分野でやられてしまったと思ってしまいました。
正直言うとまだ改造中でいろんな機能が盛り込まれています。
一度使ってみることおすすめします。
こういった事ができるんだと言うことを知ることができます。
俺もチームに入りたかったなぁと今も思うくらい最強のチームでした。

今日はここまでにしようと思います。
次は[kan_dai](https://qiita.com/kan_dai "kan_dai")さんです。
PWAって最近下火になりかけてるのでお互い頑張っていきましょう。
#4 Ruby始めました 「たのしいRuby 第６版」第２部基礎を学ぶ 四章　オブジェクトと変数・定数

ここからがスタートラインですｗ
3回までは準備と概要でした。
ここからがプログラムを学ぶ第一歩とあります。


#4−1　オブジェクト P.77

値。

#4−2　クラス P.78

オブジェクト属性


#4−3　変数 P.79

代数：オブジェクト名札


#4−4　定数 P.82

代数２：オブジェクト名札

#4−5 予約語 P.85

クラスや予約語を変数・定数にすることは不可。使用制限があるもの。

#4−6　多重代入 P.84

###変数の入れ替え

```Ruby
Aset,Bset = "キムチ","おしんこ"
tmp=Aset
Aset=Bset
Bset=tmp
p [Aset,Bset]

```
１：１ではなく、１：多で扱える。
DBの基本的なところですね。

あと入れ替えtmpに一時保存も良いですね。
でも多重代入を使えば１行でOK。

```Ruby
Aset,Bset = "キムチ","おしんこ"
Aset,Bset=Bset,Aset
p [Aset,Bset]
```
こりゃ便利だ。

###配列の要素を取り出す

```Ruby
set=["おしんこ、味噌汁","キムチ、味噌汁"]
Aset,Bset=set
p Aset
p Bset
```

変数で決めといて、あとで呼び出し割り振り可能ですね。
こういうことがバリバリちゃんと出来るとなんか良い感じになるんでしょうねｗ


#コメント
一日１項目と思ってましたが、内容が濃いのと、ギターの練習、生活費を稼ぐために仕事もしなければいけないので、２、３日で１項目、難しい内容は１週間にしていきますのでゆっくり、まったり学んでいきますｗ
そうすると単純に「たのしいRuby」は２３章までありますので、最短で半年くらい、1年ぐらいかかる予定ですｗ
そこから資格の問題集をやると遅い気がするので、まあ途中で資格の問題集を取り入れて行くとして、資格習得までの勉強と試験勉強をして、1年後と言う感じですかねｗ

まあ簡単ではないですね。まあ０スタートなんでそんなものでしょうかね。
実際のアプリが作れるようになるのは何年後かなｗ
まあ資格が取れるくらいまで勉強すれば、あとはコピペなんで直ぐだと思いますがｗ
それでも次はJavascriptになると思うので構文、記述の違いがあるので、そこも探りつつ見たいなｗまあ簡単ではない、それなりに難しいですが、まだ全く気にする必要もありませんｗ頑張っていきましょう。基礎さえしっかり学んで押さえておけば、意外となんとかなるもんです。
2020年のエンジニアリングを振り返る

# はじめに
今のところアドベントカレンダーでしかQiita記事投稿できていないsts-sd2改め、[suger4](https://twitter.com/suger4_dev)です。
本投稿は[ラクスアドベントカレンダー](https://qiita.com/advent-calendar/2020/rakus) 15日目の投稿になります。

前回は、@FlatMountainさんの[Androidで歩数計アプリを作ってみた話](https://qiita.com/FlatMountain/items/cec2013bf095261277c9)でした。

さて、本題ですが、今年はエンジニアとして、多方面にいろいろなことを経験しグッと成長できた実感があった1年でした。
あの時期あんなことやったなぁと振り返る意味を込めて、このネタで行きたいと思います。
※自己満足性が高く、淡々と文字が並ぶ記事になっておりますがご了承ください。

# suger4の2020年

## 4月：負荷テストのためにJmeterを試す

オンプレの外部ツールの負荷テストを行うために、Jmeterのscenario作成やデータ作成に勤しんでいました。
このあたりからチーム内のJmeterおじさん化が始まり、Jmeter周りでちょこちょこ対応する機会が増えてきました。

でかいデータの入った環境が欲しいと言われ、素直に**そのまま**準備をした結果サーバのハードディスクを満タンにしてしまったのは今やよい思い出です。
※関係者の皆様、その節はご迷惑おかけしました。m(_ _)m

## 5月：suger4、初めてのリモートワーク

世間的にも自粛のムードが高かったこともあり弊社デモリモートワークになっていましたが、個人的にはあまり長いことこの状況はつらいなぁと思っていました。
**通勤時間が無くなって自分の時間が増える**これは間違いなかったのですが、
環境が変わらないためかプライベートと仕事のON/OFFも無くなり、
集中もし辛く、自宅の椅子は収納スツールのみ。

これは仕事する環境ではないなと。。。

また、画面越しのコミュニケーションは私の所属するチームにはあまり向いていなかったのかも、とも感じました。
もちろん通話することもできましたが、サクッとチャットで話題を振ることの方が多く、
結果的に話の方向がズレていたり、きちんと相手に伝わっていなかったりといったこともあったように思います。

## 6~7月：ドメインモデルの迷宮に足を踏み入れる

次バージョンで開発する機能からドメイン駆動設計（DDD）を取り入れた開発をしていこうということで、DDDの書籍を読んだり、社内の勉強会に参加したり知識をため込んでいる期間でした。  

**駄菓子菓子**、業務ドメインをモデリングしていく過程が難しかったです。
DDD自体チームとしても初の試みであり、そもそもドメインモデルの何たるかもわからずの中、手探りで各々メンバーから「あーじゃないか」「こーじゃないか」「いやいやこれはコア業務だからこっちでしょー」のような会話が飛び交うMTGはみんなでモデルを良くしている感じがして、個人的には楽しかったです。
結果的に出来上がったモデルはまずまずといった出来になったと思います。

これからはモデルのブラッシュアップ力が試されることでしょう。

## 8月：suger4、既存機能の仕様に泣かされる

この時期はガツガツ実装していました。
どこでもあるあるかもですが、既存の仕様に泣かされ、**1からやり直し！**が発動したのもこの時期だったと思います。

ある機能で単発実行していたものを一括実行もできるように機能追加しており、当初は既存の機能をループさせれば行けそうということはわかっており、**見た目上の動き**は行けてました。

**駄菓子菓子**、既存の仕様の一部（多機能に関連する部分）はただループ回すだけでは意味がなく、このままではダメなことが発覚、一時思考停止ののちどうするか検討して対応しました。

もっと仕様を理解せねば、再利用性高く機能は作らねば、そう感じさせられる事件でした。

## 9月：成功しないユニットテストを必死に直す

機能を実装すると、その機能の品質を担保するためにユニットテストを書くわけですが、
私が実装したユニットテストが、ローカルでは成功するのに、定期実行しているサーバ側で実行するとなぜか落ちる事態が発生。
原因調査をコツコツやっていました。

テストデータが悪いのか？テストの実行が起因しているのか？複数の仮説をもとに調査していましたが、原因は「キャッシュに保存したデータを取ってくるロジックが動いていた」でした。

なまじテストコードが起因でなかっただけにすぐにわからず・・・結構時間を使ってしまいました。
こういうこともあるんかと、経験値が溜まりました。

## 10月：suger4、初めてのReact

今後の新機能の画面イメージ（モック）を素早く用意したり、フロントと、バックの分離による開発速度の向上を求めて、Reactのコンポーネントパターンについて情報収集と、どれくらいいい感じなのかとプロトタイプを作成してみました。

コンポーネントパターンはかなりよさげだなという印象を受けたのですが、**コンポーネントがそろっている**前提がないとうまみが得られないと感じました。

コンポーネントさえそろえることができれば、プロジェクト内でUIをそろえることも可能ですし、細かなところで悩む。といったことは減ってくるように思えています。
この取り組みは、継続してコツコツやっていきたいですね。

## 11月：PostgreSQLのパーティショニングで検索性能改善を試みる

ある画面で表示している情報の検索性能（SQLの速度）が悪く、今後の機能改修や利用者増加に耐えられなさそうということで、何とかして性能改善したいと、調査をしていました。
まず考えられたのが、表示するデータ範囲を制限すること（今まではあまり制限なく全件検索っぽくなっていた）、検索キーのインデックスを用意することでした。
これらは明らかに早くなりそうな気がしたので、以前社内で話題になったパーティショニングはどうなんだろうかということで少し手を突っ込んでみました。

が、結論としてはパーティショニングは無しということにしました。
というのも、パーティショニング用のテーブル構築や運用コストが高かったことと、これらのコストに見合う性能改善がみられなかったことが要因です。

調査の結果取り入れることができないという判断になったことは残念ですが、効果とコストを見比べて適切に判断を下す。という経験は今後の業務でもきっと役に立つことでしょう。

# 2020年総括

ここまで私の自己満足にお付き合いいただいている方はきっといないと思いますが、総括をば。

はじめにも書いたように、2020年は新しい技術を使ったフロント・バックの開発、外部システムの技術調査など、密度の濃い1年になりました。
多くのことに手を出したおかげか、自身の発言にも多少自信を持てますし、いろいろな方面から立てた仮説にもブレ（的外れ感）が少なくなってきたように思います。
**エンジニアは学習し続ける生き物**だと思っているので、2021年も貪欲に新しいことにチャレンジしていきたいですね。

では、[ラクスアドベントカレンダー](https://qiita.com/advent-calendar/2020/rakus) 引き続きお楽しみください。
[ServiceNow]簡単にパスワードの強度が設定できるようになった

　まだ2記事目ですが、今回もセキュリティについて記事を書いていきます。
　今回は、パスワードの強度についてです。

#概要
ServiceNowインスタンスのログイン時に必要なパスワードの強度が、提供先の企業などのセキュリティ要件を満たしていない場合に、パスワード強度を簡単に高くすること（逆に低くすることも）が出来る。Orlandoから簡単にできるようになった模様。

#詳細
具体的な設定手順について記載。

#####メジャーバージョン
- Orlando以降から

#####前提
- role：admin

#####デフォルトの強度（公式Docsより）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/76cd749d-b936-856c-ca64-92e6f8abb189.png)

#####手順
1. アプリケーションナビゲータから、「パスワードポリシー>パスワードポリシー」に遷移
2. 一覧に表示されるパスワード強度のプリセットが"デフォルト"レコードのリンクをクリック
3. パスワード強度のプリセットのプルダウンから強度を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/ad807225-e48a-d0cb-237d-4b2430c82f09.png)
強度を変更するとその強度に応じて、下の項目の値が自動で変わる。自由に設定したければ、"カスタム"を選択することも可能。

4. [パスワードをテスト]ボタンをクリックすれば設定内容を検証可能


設定の詳細については公式Docsも参照してください。
[パスワードポリシーを有効にする](https://docs.servicenow.com/bundle/paris-platform-administration/page/integrate/authentication/task/enable-password-policies.html)

#補足
パスワード強度の要件がこれで満たせない場合、スクリプトでカスタマイズすることになると思います。
ASP.NET Core MVC を Heroku でデプロイした

## やったこと
まず、ASP.NET Core MVCのチュートリアルをやった。
https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/first-mvc-app/?view=aspnetcore-5.0
ここで作ったアプリをHerokuでデプロイしたというのが本題。
参考にしたのはこの記事。
https://eiken7.hatenablog.com/entry/2020/08/05/223523
Dockerがまったくわからないので心配だったがそこはなんとかなった。

ちなみに Visual Studio for Mac で開発しています。

## つまづいたところ
手順通りやったらいくつか詰まるところがあった。

### Heroku 上でテーブルがない
ログをコピーするのを忘れていたけど、確か「'Movie'テーブルが存在しない」とか言われたと思う。
これは、contextに、テーブルがなかったら作るようにするという検証を足すことで対応できた。
`context.Database.EnsureCreated()`を`Program.cs`で呼び出すようにすればいい。

```cs:Program.cs
public class Program
{
    public static void Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();
        // ここ！！！
        CreateDbIfNotExists(host);

        using (var scope = host.Services.CreateScope())
        {
            var services = scope.ServiceProvider;
            try
            {
               SeedData.Initialize(services);
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
            logger.LogError(ex, "An error occurred seeding the DB.");
            }
        }
        host.Run();
    }
        
   // ここ！！！
   private static void CreateDbIfNotExists(IHost host)
   {
       using (var scope = host.Services.CreateScope())
       {
           var services = scope.ServiceProvider;

           try
           {
                var context = services.GetRequiredService<MvcMovieContext>();
               DbInitializer.Initialize(context);
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occured creating the DB.");
            }
        }
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
           .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}
```
```cs:Data/DbInitializer.cs
public class DbInitializer
{
    public static void Initialize(MvcMovieContext context)
    {
        // これね
        context.Database.EnsureCreated();
    }
}
```


### PostgreSQL に接続できない
次はこんなエラーが。
```Npgsql.PostgresException (0x80004005): 
28000: no pg_hba.conf entry for host "3.95.56.28", 
user "ctoondcrubydkb", 
database "dfom6cpjugsbme", 
SSL off
```エラーメッセージでググるとこんな記事が。
https://neos21.hatenablog.com/entry/2020/08/05/080000
とにかくSSLで接続しなきゃいけないらしい。
このやり方は色々ググったけどなかなか解決しなかった...。
https://docs.microsoft.com/ja-jp/sql/integration-services/import-export-data/connect-to-a-postgresql-data-source-sql-server-import-and-export-wizard?view=sql-server-ver15
https://software.fujitsu.com/jp/manual/manualfiles/m180007/j2ul2368/01z200/j2368-00-04-03-04.html
最終的に、接続文字列をこんな感じにしたらうまくいった。
`$"Host={uri.Host};Port={uri.Port};Database={db};Username={user};Password={password};Enlist=true;Sslmode=Require;TrustServerCertificate=true";`
これでOK。デプロイできた。

## まとめ
ASP.NET Core + Heroku の記事は少なくて大変だった...。
ASP.NET Coreでこれからいろいろ開発してみたいから、とりあえずデプロイの手順の知見を得られたのは大きいだろうと思って、記事を書き残しておいた。
PowerAutomateを使ってPlannerに期限付きタスクを追加する

# 概要

PowerAutomateを使って、Plannerに期限付き（例：今日から5日後）のタスクを追加してみます。
大したことはやっていませんが、期限を今日から●日後に設定する方法や、Plannerのタスクを追加するだけではなく、そのタスクに説明文を入れる方法について、この記事で触れています。

# フローの全体像

![screencapture-japan-flow-microsoft-manage-environments-Default-f37c99dd-fb85-406b-9726-b683dc62ec8c-flows-new-2020-12-14-20_31_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246556/9284659f-bc5a-29f4-b55a-878ccea604c0.png)

# フローの個別説明

## 期限用の変数を定義

|コネクタ|アクション|
|:--|:--|
|変数|変数を初期化する|

`formatDateTime`関数を利用して、`yyyy-MM-dd`形式の文字列を生成しています。
この関数の第１引数にtimestamp型の値を、第２引数にformatを指定します。
第１引数のtimestamp型に設定する日付は、今回の例では今日（現時点）から＋５日した日付を設定しています。

現在の日時は`utcNow()`関数で取得しています。＋５日するために、`addDays`関数も利用しています。
以下がコードビューの内容です。

```json
{
    "inputs": {
        "variables": [
            {
                "name": "datetimeLimit",
                "type": "string",
                "value": "@{formatDateTime(addDays(utcNow(), 5), 'yyyy-MM-dd')}"
            }
        ]
    }
}
```

## タスクを作成する

|コネクタ|アクション|
|:--|:--|
|Planner|タスクを作成する|

SharePointにすでに構築済みのPlannerを指定し、任意のタイトルをつけています。
開始日時はこのフローが実行された日時を指定し、期限には上記で作成している`yyyy-MM-dd`形式の文字列変数`datetimeLimit`を指定します。

## タスクに説明を追加する

|コネクタ|アクション|
|:--|:--|
|Planner|タスクの詳細の更新|

`タスクを作成する`アクションでは、そのタスクに対する説明を入れることができないようで、
どんなタスクなのか把握するためには、タイトル情報から読み取るしかありません。
もちろん説明を読まなくても内容が把握できるタスクである必要はあるかもしれませんが、説明を入れる方法は知っておいて損はないかなと思います。

説明を入れるために`タスクの詳細の更新`アクションを利用し、全段の`タスクを作成する`アクションの実行結果で生成されるタスクIDを指定して、説明を登録しています。

# 実行結果を確認する

このフローを実際に実行すると、SharePointに作成済みの`サンプルプラン`にタスクが追加されていることを確認できます。

![スクリーンショット 2020-12-14 20.43.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246556/e5219822-054f-fa28-ad9f-c9232b47044c.png)
[JavaScript] すごく初歩のJavaScript (コールバック関数)


###JavaScript (コールバック関数)

JavaScript 自分用の覚え書きです。

JavaScriptでのコールバック関数の使用

```javascript:script.js
// callの定義
const call = (callback) => {
  callback("佐藤", 20);
};

// callを実行し、console.logで表示する
call((name, age) => {
  console.log(`${name}は${age}歳です。`);
});
```
URLフィルタリングを実装する。Nginxで出来ずSquidで実現した。

# 特定のURLにだけアクセスさせたい
- やりたいことは実はこれだけです。
- 所謂、ホワイトリスト運用というものです。
- もう少し詳しく書くと**「全てのインターネットアクセスを遮断した上で、ホワイトリストに記載されたサイトだけアクセス許可したい」**というものです。

# 最初はNginxで・・・断念したけど、出来るかもしれない
- 書いた通りです。一番慣れていたので、Nginxで試みたのですが、上手く出来ませんでした。

# だからSquidでやることにした
- [この方の記事](https://qiita.com/aiai_osaru/items/95feefe4787600b2f478)が非常に役に立ちました。
- この場をお借りして、厚く御礼申し上げます。

# 環境
- AWS EC2 Ubuntu18.04

```
squid -v
Squid Cache: Version 3.5.27
Service Name: squid
Ubuntu linux
```

# インストールと起動確認等
```
apt install squid
sudo systemctl status squid.service

ちなにみ停止・起動・再起動
sudo systemctl stop squid.service
sudo systemctl start squid.service
sudo systemctl restart squid.service
```

# configの変更
- 変更箇所

```
/etc/squid$ diff squid.conf squid.conf.org
1192,1193c1192
< acl whitelist dstdomain "/etc/squid/whitelist"
< http_access allow whitelist
---
>
```
- 場所に注意が必要なので、入れた箇所を
- vimで開いて、「:set nu」しています。
- **許可設定は「1195行目の設定より上に入れる必要がある」**らしいです。

```
-- snip --
1186
1187 # Example rule allowing access from your local networks.
1188 # Adapt localnet in the ACL section to list your (internal) IP networks
1189 # from where browsing should be allowed
1190 #http_access allow localnet
1191 http_access allow localhost
1192 acl whitelist dstdomain "/etc/squid/whitelist"
1193 http_access allow whitelist
1194 # And finally deny all other access to this proxy
1195 http_access deny all
1196
-- snip --
```

# ホワイトリストの定義
- 参考にさせて頂いた記事通りに設定していますが、念のため添付します。

```
ls -l
total 584
-rw-r--r-- 1 root root   1817 Sep  2 15:35 errorpage.css
-rw-r--r-- 1 root root 290935 Dec 14 07:41 squid.conf
-rw-r--r-- 1 root root 290861 Sep  2 15:35 squid.conf.org
-rw-r--r-- 1 root root     24 Dec 14 07:35 whitelist

cat whitelist
.qiita.com
.google.com

pwd
/etc/squid
```

以上です。
MySQLでうっかり違う行を削除してしまったときにバイナリログから復旧する

`DELETE FROM テーブル WHERE id=xx`のxxを間違ってしまった、みたいなときに軽くバイナリログから復旧する方法です。
そもそもWHERE句を入れてなくて100万件消えたとか、ディスクを読み取り専用にしてextundeleteして、みたいなガチな内容ではありません。


# バイナリログってなに？

INSERT/UPDATE/DELETEなどの[変更SQLを保存するログファイル](https://dev.mysql.com/doc/refman/5.6/ja/binary-log.html)です。

MySQLのデータフォルダに`データベース名-bin.000001`みたいなファイルがあればバイナリログです。
レプリケーションにも使うので、レプリケーション環境であれば存在するはずです。

バイナリログがなかったら、以下の手段は使えないのでがんばってどうにかしてください。


# バイナリログをテキストにする

バイナリログは名前のとおりバイナリなので、そのまま見ようとしても全く読めません。
まずはテキスト形式に変換する必要があります。
環境によっては`000001`とか`000002`のように複数のバイナリログファイルがありますが、その場合は更新日時を見てどのあたりが必要なログか確認しましょう。

```bash
mysqlbinlog -v /path/to/mysql/database-bin.000001 > /tmp/log.txt
```

実際はなんだかよくわからないデータも残っていたりするのですが、これで一応人間が読めるテキストファイルになりました。

# DELETE文を抽出

```bash
cat -n /tmp/log.txt | grep "DELETE FROM `DB名`.`テーブル名`"
```

これでDELETE文が入っている行が抽出されます。
たくさん見つかった場合は、その中からどこが該当のDELETE文なのかを探す仕事が始まります。

```bash
head -n 行数+30 /tmp/log.txt | tail -40
```

こんなかんじでDELETE文の前後の行を取り出せます。
そしてポイントですが、バイナリログではDELETE文にも全てのカラムの内容が入っています。
すなわち、うっかりDELETEしてしまった中身を取り出すことができます。

あとは取り出せた値をINSERTしなおせば復旧完了です。
めでたし。

# 未確認

TEXT型は取り出せることを確認していますが、BLOBのようなバイナリ型はこれで取り出せるかはわかりません。

`ON DELETE CASCADE`などで巻き込まれて削除された場合にバイナリログがどうなるかは確認していません。

今回は調べる必要がなかったからね。