OmniAICreator/Qiita-1.07M huggingface dataset:
JavaScriptでアバターに自動的にユーザーの名前が入るようにしよう！！

Webアプリを作っていると、headerなどに表示されているアバターに画像を表示したいと言ったことが出てくると思います。

しかし、ユーザーの新規登録時などアバターの画像を設定していない段階で、何かしら代わりの画像を設定しておきたいことがあります。

そこで、今回は`JavaScriptのsliceメソッド`を使ってユーザー名を切り出し、イニシャルをアバターとして表示する方法について解説します。

## 完成形の確認

完成形は以下の画像の通りです。

![スクリーンショット 2020-11-29 14.49.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509690/ef9427a5-b23e-2bd1-7286-9d8823d539a0.png)

この画像ではユーザー名を'Guest User'としています。
イニシャルの`G`が表示されています。

例えば、ユーザー名が`Taro Yamada`なら`T`、`John`なら`J`のように最初の1文字が表示されます。

## 実装
今回、ReactとFirebaseを用いて実装しますが、大切な部分は`JavaScriptのsliceを使うところ`だけです。

上記の画像は以下のコードで実装しています。

```HeaderRight.jsx
export default function HeaderRight() {
  const classes = useStyles();
  const { currentUser } = useAuth();
  const [userNameInitial, setUserNameInitial] = useState();

  useEffect(() => {
    const id = currentUser.uid;
    db.collection("users")
      .doc(id)
      .get()
      .then((snapshot) => {
        const data = snapshot.data();
        const username = data.username;
        const initial = username.slice(0, 1);
        setUserNameInitial(initial);
      });
  }, []);

  return (
    <div className={classes.headerRight}>
      <Link to="/postform" className={classes.postFormLink}>
        <Button className={classes.postFormButton}>新規投稿</Button>
      </Link>
      <Link to="/bookmarkList">
        <IconButton className={classes.bookMark}>
          <LibraryBooksIcon />
        </IconButton>
      </Link>
      <Link to="/dashboard" className={classes.avatarLink}>
        <Avatar aria-label="recipe" className={classes.avatar}>
          {userNameInitial}
        </Avatar>
      </Link>
    </div>
  );
}
```

ここで注目して欲しいのは、useEffectの中に書いてある`const initial = username.slice(0, 1);`です。

ここでusernameというのはデータベースから参照してしるユーザー名です。

そしてusernameに対して、`slice(0, 1)`とすることで、最初の一文字を切り抜けます。sliceの0は`切り抜きの開始位置`、1は`何文字切り取るか`を示しています。

例えば、`文字列の先頭から2文字`切り取りたいなら、`slice(0, 2)`とすればOKです。

あとは、切り抜いた文字をアバターとして表示するだけです。
※今回はMaterial uiのAvatarを使っています。

今回は`userNameInitial`という変数に格納していますが、それを表示すれば完了です。

## 参考
[String.prototype.slice()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/slice)

[先頭、末尾の文字を取得する方法](https://lab.syncer.jp/Web/JavaScript/Snippet/6/)
アプリを起動したときに読み込まれるStoryboardを設定する（忘備録）

###1. Storyboardファイルを作成
New File...からStoryboardを選択してCreateする

###2. ViewControllerのClassを作成

```FirstViewController.swift
class FirstViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
  }
```

###3. Storyboardの設定
 - StoryboardのClassを指定
 - StoryBoard IDを入力（Class名と同じでOK）
 - Use StoryBoard IDにチェックを入れる
 
![スクリーンショット 2020-12-02 10.21.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918084/6ea933fc-c0e8-82e2-e5c6-f5cce0faf9aa.png)


###4. SceneDelegateの"willConnectTo"にコードを追記

```SceneDelegate.swift
  func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    
    //初期の画面を設定することができる（ここに記載された方が優先される）
    let window = UIWindow(windowScene:  scene as! UIWindowScene)
    self.window = window
    //レシーバを前面に表示してキーボード等のイベントを受け付けるようにする
    window.makeKeyAndVisible()
    
    //表示させるStoryBoardを指定(First.storyboardの場合)
    let storyboard = UIStoryboard(name: "First", bundle: nil)
    //StoryboardIDを指定
    let viewController = storyboard.instantiateViewController(identifier: "FirstViewController")
    //navigationBarがある場合
    //(ない場合はそのままrootViewControllerにviewControllerを設定する）
    let nav = UINavigationController(rootViewController: viewController)
    //UIWindowのrootViewControllerに設定 
    window.rootViewController = nav
    
    guard let _ = (scene as? UIWindowScene) else { return }
  }
```

###5. Main Interfaceの値“Main”を削除

![スクリーンショット 2020-12-02 10.36.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918084/48a266fa-4566-a9a0-4cff-4a45c4ba1c2c.png)
Mainの値を削除してReturnを押す

###6. info.plistのStoryboard Name (Main)を項目ごと削除

![スクリーンショット 2020-12-02 10.40.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918084/ade0e2b8-2e68-75b6-cca5-01fc361a9a16.png)
選択してdeleteを押すか、マイナス(-)をクリック


###7.使わないファイルを削除
Main.storyboardやViewController.swiftを使わない場合は削除する。




[環境]
Xcode Version 12.2
(超初心者向け)Slackのアクセストークンが記載されている場所について

SlackでBotなどを作ったあとのアクセストークンがどこに記載されているのか迷ってしまっている初心者の方は意外と多いのではないでしょうか？
自分もその一人です。　慣れている人にとっては当たり前のことだと思いますが、英語が読めない自分にとっては迷路でした。

素晴らしい先人達の記事を読んでも、どういう手順でアクセストークンが記述されている場所に行けるのか全然理解できず、初心者の頃は1時間ほどサイトをさまよったので分かりやすい記事があれば助かったのに、と思ったので投稿します。

<h2>アクセストークンが記述されている場所について</h2>
まず<a href ="https://api.slack.com/" >こちら</a>にアクセスして、Your Appsをクリックします。
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918373/cab852d3-982a-9a76-91ac-4312c614d610.png)

次に自分が作成したBotを選択します。赤枠に囲まれた部分です。(複数作成している場合は、任意で選択してください。)
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918373/0f639405-078d-4437-d4fa-72878564f054.png)

次に[OAuth & Permissions]を選択します。赤枠で囲まれた部分です。
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918373/8411dea0-dae2-7474-535b-4f05d18d5fc5.png)

最後にアクセストークンが書かれたページに飛びます。　おそらくXから始まるアルファベットと数字の羅列が記載されていると思います。
![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918373/8cb5d8d4-3179-585f-cf9b-b4acc8fac094.png)

<h2>最後に</h2>
アクセストークンはSlack用のアプリやBotの運用するときに、ほぼ欠かせないものになると思いますが独学で頑張っている方ほどアクセストークンのページにたどり着けず苦戦するような印象があったので、投稿してみました。かくいう自分もその一人です。

ここだけに限らずプログラミングの読み物は英語で書かれているものも多いので、英語が苦手な方は簡単な英単語くらいは勉強すると役立つと思います。
技術的にためになるようなものではありませんが、誰かの助けになれば嬉しいです。
深層学習 Day 4 - WaveNet のまとめ

この記事は個人的なお勉強用のメモです。

# 講義

## WaveNet

### 概要

音声生成モデル（音声認識モデルではない）
音声にもかかわらず、Pixel CNN で処理できる。（RNN ではない）

### Dilated Convolution

層が深くなるにつれて、畳み込みリンクを離す
例
Dilated = 1,2,4,8

### 特徴

パラメータ数に対する受容野が広い。
（1つの出力に利用する複数のパラメータについて、音声の場合は時間が長い）

# 関連記事

黒本で補習。
WaveNetとは。

##### 数式

```math
p(x)=\Pi_{t=1}^T p(x_t|x_1,x_2,...,x_{t-1})
```

$t$ より前のすべての時刻ステップをサンプルにする。

##### 構成

コーザル畳み込み（Causal convolution）とダイレイト畳み込み（dilated convolution）の組み合わせ。

##### コーザル畳み込み（Causal convolution）

- 過去の時刻ステップだけを用いて畳み込む
- モデルが入力データの時間順序を破らない
- 再帰結合を持たないため、RNN に比べて計算が高速
- 画像処理におけるマスク畳み込み（masked convolution）と似通っている
- 受容野は広くできない（この点はダイレイト畳み込みでカバー）

##### ダイレイト畳み込み（dilated convolution）

- 少ないパラメータで広い範囲を畳み込む
- フィルタを適用する入力データの場所を**数ステップずつスキップ**
- フィルタを入力データの場所の長さに比べて**長い**領域に適用

##### 拡大度（dilation）

dilationが1なら通常の畳込み、2なら1つ飛ばし、8なら7つ飛ばし。
dilationは出力層に向かうほど大きくなる。
深層学習 Day 4 - BatchNorm、LayerNorm のまとめ

この記事は個人的なお勉強用のメモです。

# 講義

## Batch Norm

Batch Normalization
バッチ正規化

### 概要

<img src="https://qph.fs.quoracdn.net/main-qimg-fd59ba3f5eb4108e6cc91d8075a081ff">
レイヤー間を流れるデータの分布をミニバッチ単位で
平均 0、分散 1 になるよう正規化

正規化する単位はチャンネル

チャンネルごとの正規化なので、この手法は正攻法。
（Rだけをまとめて正規化、Gだけをまとめて正規化、というのは
　普通の考え方）

### 効果

- 学習時間の短縮
- 初期値への依存低減
- 過学習の抑制

### 問題点

バッチサイズが小さいと、学習が収束しないことがある。効果が薄くなってしまう。

実際はバッチ正規化を使うことは推奨されない。
バッチのサイズに影響を受けるため（環境によってバッチサイズは異なる）。

## Layer Norm

Layer Normalization

### 概要
<img src="https://qph.fs.quoracdn.net/main-qimg-e15a7b285ad845ee68ed619bba447ebb">
データの分布を正規化するのはバッチ正規化と同じ。
バッチ正規化との相違点

画像データの例
- Batch Norm：ミニバッチ内のチャンネルごとに正規化
- Layer Norm：1枚ずつすべてのチャンネルを正規化

### 効果

ミニバッチの数に影響しないため、
Batch Norm の問題点を解決している。

入力データのスケールに関してロバスト（堅牢）
重み行列のスケールやシフトに対してロバスト

とはいえ、すべてのチャンネルをまとめて正規化するので
正攻法とは少し外れるか。
（RGBをまとめて正規化する意味とは？と考えてしまう）


## Instance Norm

Instance Normalization

### 概要
<img src="https://qph.fs.quoracdn.net/main-qimg-d4d309955656b3fc5a142b01a257db2b">
データの分布を正規化するのは他の正規化と同じ。
Layer Normとの相違点

Layer Norm：1枚ずつすべてのチャンネルを正規化
Instance Norm：1枚の中のチャンネルずつ正規化

Batch Normでバッチサイズが 1 の場合と同じ動き。

### 効果

コントラスト正規化
画像のスタイル転送
テクスチャ合成
などで利用

# 関連記事

正規化のイメージは以下のページが非常にわかりやすかった。

Normalization Layers
https\://hotcocoastudy.hatenablog.jp/entry/2019/10/12/112213

上記のページによると、Group Normalization という正規化があるとのこと。
<img src="https://qph.fs.quoracdn.net/main-qimg-36db2b75a081d918afbde54c648b41f7">
Instance Normalization では 1 枚、1 チャンネルごとに正規化するが、
Group Normalization では複数のチャンネルをまとめてグループにして正規化する。
埼玉県の最近の県政ニュースから新型コロナウイルスに関連した患者等の発生についての別紙PDFから陽性者情報を抽出する

埼玉県の[最近の県政ニュース](https://www.pref.saitama.lg.jp/news/index.html)から新型コロナウイルスに関連した患者等の発生についての別紙PDFから陽性者情報を抽出する

```python
import datetime
import pathlib
import re
from urllib.parse import urljoin

import pandas as pd
import requests
from bs4 import BeautifulSoup

import sys
import pdfplumber

# PDFファイルのリンクを抽出
def get_pdf_link(url):

    r = requests.get(url, headers=headers)
    r.raise_for_status()

    soup = BeautifulSoup(r.content, "html.parser")

    # PDFファイルのリンクを抽出
    tag = soup.select_one("div#tmp_contents > p > a[href$=.pdf]")

    if tag:
        # リンクのテキストが別紙で始まるか確認
        if re.match("別紙", tag.get_text(strip=True)):
            return urljoin(url, tag.get("href"))

    return None


# PDFファイルをダウンロード
def get_pdf_file(url, dir="."):

    r = requests.get(url)
    r.raise_for_status()

    p = pathlib.Path(dir, pathlib.PurePath(url).name)
    p.parent.mkdir(parents=True, exist_ok=True)

    with p.open(mode="wb") as fw:
        fw.write(r.content)
    return p


# 月日をdatetimeに変換
def days2date(s):

    y = dt_now.year

    days = re.findall("[0-9]{1,2}", s)

    if len(days) == 2:
        m, d = map(int, days)

        if dt_now.month < m:

            y -= 1

        return pd.Timestamp(year=y, month=m, day=d)
    else:
        return pd.NaT


url = "https://www.pref.saitama.lg.jp/news/index.html"

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
}

r = requests.get(url, headers=headers)
r.raise_for_status()

soup = BeautifulSoup(r.content, "html.parser")

# 現在の日付
JST = datetime.timezone(datetime.timedelta(hours=+9), "JST")
dt_now = datetime.datetime.now(JST)

dfs = []

for i in soup.select("div.box_news > ul > li > a"):

    # 最近の県政ニュースの新型コロナウイルスに関連した患者等の発生についてを抽出
    if re.match("新型コロナウイルスに関連した患者等の発生について", i.get_text(strip=True)):

        # 別紙のPDFをダウンロード
        link = get_pdf_link(urljoin(url, i.get("href")))

        if link:

            with pdfplumber.open(get_pdf_file(link)) as pdf:

                dfs.extend(
                    [
                        pd.DataFrame(
                            page.extract_table(),
                            index=[
                                "例目",
                                "年代",
                                "性別",
                                "国籍",
                                "職業",
                                "居住地",
                                "発症日",
                                "発症時症状",
                                "陽性判明日",
                                "感染源と疑われる接触",
                                "同居家族",
                                "濃厚接触者",
                            ],
                        ).T.iloc[2:]
                        for page in pdf.pages
                    ]
                )

# ひとつに結合、空白文字を除去、例目をindexに変更
df = pd.concat(dfs).replace("\s", "", regex=True).set_index("例目")

# indexでソート
df.sort_index(inplace=True)

# 月日をdatetimeに変換
df["発症日"] = df["発症日"].apply(days2date)
df["陽性判明日"] = df["陽性判明日"].apply(days2date)

df.to_csv(sys.stdout)
```
深層学習 Day 4 - MobileNet、DenseNet のまとめ

この記事は個人的なお勉強用のメモです。

# 講義

超概要
MobileNet：CNN で軽量化する仕組み
DenseNet：CNN で深い層でも学習する仕組み

## MobileNet

### 概要

- 画像認識モデル
- DNN モデルの軽量化・高速化・高精度化を実現
- Depthwise Convolution と Pointwise Convolution の組み合わせによって軽量化。


### 一般的な畳み込み層の計算量

条件
・入力特徴マップ（チャンネル数）：$H \times W \times C$
・畳み込みカーネルのサイズ：$K\times K\times C$
・出力チャネル数（フィルタ数）：$M$
・ストライド：1
・パディング：1

このとき、出力マップの 1 ピクセルを出力するのに必要な計算量は
$K \times K \times C \times M$

よって、出力マップの全体を出力するのに必要な計算量は
$H \times W \times K \times K \times C \times M$

つまり、一般的な畳み込みの計算は計算量が多い。

### Depthwise Convolution

フィルタ数は 1 固定。（一般的な畳み込みでは、フィルタ数は $M$）
計算量は $H \times W \times C \times K \times K$。（一般的な畳み込みの $1 / M$）
出力マップのチャンネル数は、入力マップのチャンネル数と同じになる。

### Pointwise Convolution

カーネルのサイズは $1\times1$ 固定。（一般的な畳み込みでは、カーネルのサイズは $K\times K$）
出力マップのチャンネル数は $M$。（一般的な畳み込みと同じ）
計算量は $H \times W \times C \times M$（一般的な畳み込みの $1 / (K\times K)$）

### MobileNet（2 種類の Convolution の組み合わせ）

Depthwise Separable Convolution （2種類のConvolutionの組み合わせた名前）

処理の流れ

1. 入力マップに対して、Depthwise Convolution を実行  
出力マップのチャンネル数は入力マップのチャンネル数と同じ
2. 1.の出力マップに対して、Pointwise Convolution を実行  
これが最終的な出力マップになる。

1 の計算量と 2 の計算量の総和が、MobileNet の計算量になる。
メモリ使用量は通常の畳み込みに比べて数十分の 1 になることも。


## DenseNet

### 概要

- 画像認識の NN
- Dense Block が特徴


### Dense Block

Dense Block のレイヤーを通るたびにチャンネルが増える。

Dense Block の処理順序
1. 前の層で計算された結果がチャンネルに付け加えられた状態が入力
2. Batch 正規化
3. ReLU
4. 畳み込み 3x3
5. 出力に処理結果の層を付け加える、これの繰り返し

つまり、Dense Blockを通過するたびに、入力のチャンネル数だけ、出力のチャンネル数が増えていく。
増えたチャンネル数を、その後の Transition Layer (Convlution + Pooling) で元に戻す。
よって、各 block 内での特徴マップのサイズは同じ。


### DenseNet と ResNet の違い

ResNet は直前の 1 層が直後の 1 層のみ入力
DenseNet は前方の各層から後方の層に入力（以前の複数の層を入力にする）

### 成長率（Growth Rate）

成長率 (k) とは、Dense Block の中を何層にするか、というハイパーパラメータ。
成長率が高いほどネットワークが大きくなるため、成長率は小さくするのが望ましい。


# 関連記事

### MobileNet

黒本で MobileNet の補習をしようと思ったら、MobileNet の問題が無かった。
仕方ないので適当にネットで検索した情報。

- 「～wise」というのは「～的に」「～については」という意味合い
- 現状で MobileNet は V3 まで存在する
- いずれも Google の論文
- V2 の特徴は Inverted Residual
- V3 の特徴は BottleneckへのSqueeze-and-Excite　モジュールと h-swish
- V1 から V2 へは効果が大きい。V2 から V3 への効果はそこまで大きくない（V3 は V2 の延長）

### DenseNet

黒本に書いてある DenseNet の情報は講義の内容以下であったため、省略。

- 「Dense」は、「密集」という意味
- Residual Network の略称が ResNet
- 意味の無い層があったとしても、その層の重みが 0 であればよく、ショートカットによって補う
- DenseNet のメリット
 - 勾配消失の削減
 - 特徴伝達の強化
 - 特徴の効率的な利用
 - パラメータ数の削減
 - 正則化効果の期待
深層学習 Day 4 - 量子化、蒸留、プルーニング のまとめ

この記事は個人的なお勉強用のメモです。

# 講義

軽量化の方法
・量子化
・蒸留
・プルーニング

※ 量子化がよく使われる。

## 量子化

Quantization

浮動小数点のデータ型を精度の低いデータ型にする。
例：64 bit 変数を 32 bit 変数に変更 

【効果1】省メモリ化
　64 bit を 32 bit にすると、消費メモリは半分になる。

【効果2】計算の高速化
　bit 数を減らすと、浮動小数点の計算量が少なくて済む。
　＝ 同じ時間で他の計算を多く行えるようになる。

【欠点】数値の精度が下がる。
　ただし、ほとんどの場合、半精度(16bit)で問題ない。

現実的には、16 bit を選択するのが最も良い。

## 蒸留

### 概要

規模の大きなモデルの知識を使って（知識を継承して）、
軽量なモデルを作成する。


### 構成

・教師モデル
　予測精度の高い、複雑なモデルやアンサンブルされたモデル

・生徒モデル
　教師モデルを元に作られた軽量なモデル

### 生徒モデルの作り方

1. 教師モデル（学習済み）と生徒モデル（未学習）を並列に配置する
2. これらのモデルに同じ入力を与える
3. 教師モデルの重みは変更しない
4. 生徒モデルの重みのみを更新する

## プルーニング

### 概要

モデルの精度に寄与が少ないニューロンを削減する。
⇒ モデルの軽量化、高速化

枝刈りするイメージ。

### ニューロンの削減方法

重みがしきい値以下の場合に、ニューロンを削減して、再学習する。

ニューロンを削減しても、意外と性能は落ちないことがわかっている。
パラメータの数を10分の1以下にしても、精度は90%近くを保つ結果あり。

# 関連記事

黒本で補習。

量子化
・活性化を二値化すると、ほとんどの勾配が 0 になってしまう。
・回避策は、ストレート・スルー・エスティメータ(Straight-Through Estimator, STE)
・STE を適用して逆伝播する。

蒸留
・ソフトターゲット損失（$L_{soft}$）を算出する際は、先生の出力（予測結果）を目標分布に用いる。
・ハードターゲット損失（$L_{hard}$）を算出する際は、正解ラベルを目標分布に用いる。
・$L_{soft}$ と $L_{hard}$ の加重平均値を最小値の対象にする。

```math
L=\frac{\lambda_1 T^2 L_{soft} + \lambda_2 L_{hard}}{\lambda_1 + \lambda_2}
```

　※ $L$ は2つのターゲット損失を加重平均した値
　※ $\lambda_1$ と $\lambda_2$ は $L_{soft}$ と $L_{hard}$ の相対的な重みを意味する定数
　※ $T$ を二乗する理由は、スケールを合わせるため

・温度付きソフトマックス関数を使う。

```math
Softmax(z)_i=\frac{\exp(z_i/T)}{\sum_j \exp(z_j/T)}
```
・温度 $T$ を高くすると、不正解に対する確率を大きくできる。

プルーニング
・あるチャンネル剪定では、ラッソに基づく。
・「部分ネットワーク構造」と「初期値」の組み合わせに当たりが存在し、
　その当たりを引き当てると効率的に学習できるという仮説（宝くじ仮説）がある。
・剪定によって、その構造と初期値を見つけられる。
・剪定は学習中または学習後に行われる。
・剪定とは、精度に大きく影響を与えないノードやエッジを刈ること。
python の言語的特徴？

```python:sample.py
b = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
b[2][3] = 3
print(b)

# => [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 3], [0, 0, 0, 0], [0, 0, 0, 0]]

a_num = 4
b_num = 5
c = [[0]*a_num]*b_num
c[2][3] = 3
print(c)

# => [[0, 0, 0, 3], [0, 0, 0, 3], [0, 0, 0, 3], [0, 0, 0, 3], [0, 0, 0, 3]]
```

どちらも同じ配列を作っているのに、配列の置き換えがうまくいかないのはなぜ？
深層学習 Day 4 - データ並列化、モデル並列化 のまとめ

この記事は個人的なお勉強用のメモです。

# 講義

### 高速に学習する方法

・データ並列化
・モデル並列化
・GPU

コンピュータの性能は 1.5 年で 2 倍になると言われているが
モデルの複雑さは毎年 10 倍になっている。
何らかの対策が必要。
　⇒ 分散深層学習という

### 低性能の計算機でモデルを動かす方法

・量子化
・蒸留
・プルーニング

## データ並列化

### 構成

親モデルを複数コピー（コピーされて生成されたものをワーカーという）。
データを分割し、ワーカーごとに学習。

ワーカーの配置は、複数のコンピュータであったり
複数の CPU や GPU であったり、それらの組み合わせであったり。

データが大きい場合はデータ並列化を採用する。

### パラメータの更新方式

同期型と非同期型の 2 種類。

#### 同期型

1. 各ワーカーの学習が終わるのを待つ。
2. 各ワーカーの誤差を集めて誤差の平均を求める。
3. 誤差の平均を使って、親モデルのパラメータを更新する。

ワーカーの学習が終わるのを待つところが、同期型。

#### 非同期型

ワーカーが複数存在するのは同期型と同じ。

1. ワーカーは学習を終えると、学習済みのモデルをキューに push する。
2. 空きのワーカーはキューから pop して学習する。
3. この繰り返し。

#### 比較

- 処理スピードは非同期の方が速い。
- 非同期は学習が不安定になりやすい（最新のモデルを利用しないため）。
- 現在は同期型が主流（精度が良いことが多いため）。
- ワーカーの性能が統一されている場合は同期型、不統一の場合は非同期型。

## モデル並列化

### 構成

1. 親モデルを分割する。
2. 分割したモデルを複数のワーカーに割り当てる。
3. 各ワーカーでモデルを作成する。
4. 学習が終わったら各モデルをマージする。

モデルの分割方法としては、直列のモデルを途中で分割したり、
並列のモデルを分岐ごとに分割したり。
前者の分割は実は難しい。後者の分割がよく用いられる。
複数の GPU で構成することが多い。

モデルが大きい場合はモデル並列化を採用する。

### 効果

モデルのパラメータ数（重みの個数）が多いほど、効果が高い。

## GPU（おまけ）

### 種類

|種類|説明|
|---|---|
|CPU|高性能なコアが少数<br>複雑で連続的な処理が得意|
|GPU|低性能なコアが多数<br>簡単な並列処理が得意|
|GPGPU|General-purpose GPU<br>グラフィック以外で使用されるGPU|

GPU は NN の学習に向いている（NN は行列演算が多いため）。

### GPGPU開発環境

|種類|説明|
|---|---|
|CUDA|NVIDIA社のCPUのみで使用可能<br>DL用に提供されているため、使いやすい|
|OpenCL|NVIDIA社以外のGPUからでも使用可能<br>DLに特化しているわけではない|

現在は CUDA しか使われていない。
TensorFlow や PyTorch の設定をするとすぐに GPGPU が使える。

# 関連記事

黒本で補習。

データ並列の説明
・親モデルをコピー
・異なるバッチを各 GPU ワーカーに供給
・ワーカーからの勾配を送る先を、パラメータサーバという

同期型の特徴
・すべての GPU ワーカーが勾配を計算して平均勾配を求める
・GPU の性能に差があると無駄が生じる
・非同期型よりもスループットは低い

非同期型の特徴
・ある GPU ワーカーが計算する間にパラメータ更新される場合がある
・これを陳腐化した勾配という
・対策としては学習率を小さくする
・更新時間は最遅の GPU ワーカーに依存しない
・同期型よりもスループットは高い

モデル並列の説明
・モデルの各部分を別の GPU 上にロード
・順伝播と逆伝播の両方で通信が必要
・通信コストがボトルネック
・どのようなモデル分割がよいかは、モデルに依存
Progate JavaScript VI VII

コールバック関数という抵抗感を覚えそうな名前が出てきました。
理解するのにめちゃくちゃ時間かかりましたが（いうてもまだ50％くらいの理解。。）、こんなことが出来るならなんでも出来ちゃうんじゃないかって思いましたね！
コールバック関数等を最大限用いて、コードの効率化、処理の拡大化をさせて、様々なモノを作り上げることができるようになるのでしょうか・・
実際の成果物でどのような処理が書かれているのか気になってきますね！
もっともっと理解を深めたくなりましたし、やっぱり楽しいですね(*´꒳`*)
C#上でJavaScriptが動く | プリザンターでローコード開発

本記事は [Pleasanter(プリザンター) Advent Calendar 2020](https://qiita.com/advent-calendar/2020/pleasanter) 1日目の記事です。

# はじめに

ノーコード / ローコード開発が盛り上がってきていますね。プリザンターもごの分野の選択肢の一つとして活用してもらえるよう、色々と機能追加を進めています。

以前からプリザンターはJavaScriptを任意に追加してカスタマイズすることが出来ました。しかし、編集画面で計算を行うようなスクリプトを設置した場合、ユーザが直接編集画面を入力する場合に動作しますが、同じテーブルでインポートや、一覧画面で編集、APIで更新を行った場合などに動作させる事ができない問題がありました。

# サーバサイドでJavaScriptを動かす

こうした問題を解決するために、サーバスクリプト機能を追加しました。この機能は、サーバ上でJavaScriptを動かし、計算処理や画面の表示制御などを簡単に実装できてしまう強力な機能です。以下のバージョンから使用することができます。

|製品|バージョン|
|---|---|
|.NET Framework版|0.50.199.*|
|.NET Core版|1.1.9.0|

※ CentOSなどのLinux環境で動作させるためには下記の追加のセットアップ手順が必要です。
https://pleasanter.net/fs/publishes/2396324

# どうやってやっているの？

プリザンターのサーバサイドは ASP.NET / C# で動いています。そのため、サーバサイドでJavaScriptを動かすといった機能を実装するためには、なんらかの拡張が必要です。プリザンターはで、下記のプラグインを使用してC#上でJavaScriptを動かせるようにしました。

https://www.nuget.org/packages/Microsoft.ClearScript/

# 設定方法

スクリプトを設置したい対象テーブルのテーブルの管理画面を開くと、「サーバスクリプト」タブが表示されます。こちらにスクリプトを追加していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78230/cf8f7361-86d3-17d5-6ace-5fc86ac2b2f5.png)

### スクリプトの例1

```javascript
// レコードの数値Aと数値Bを乗算して数値Cに格納する。
// JavaScriptの関数を使って四則演算以外の演算が可能。
// 「計算式の後」にチェック。
model.NumC = model.NumA * model.NumB;
```

### スクリプトの例2

```javascript
// 状況に合わせて進捗率を変更する。
// 条件分岐との組み合わせでプログラマブルな設定が可能。
// 「計算式の後」にチェック。
switch (model.Status) {
    case 150: // 準備
        model.ProgressRate = 10;
        break;
    case 200: // 実行中
        model.ProgressRate = 50;
        break;
    case 300: // レビュー
        model.ProgressRate = 90;
        break;
    case 900: // 完了
        model.ProgressRate = 100;
        break;
    default:  // その他
        model.ProgressRate = 0;
        break;
}
```

### スクリプトの例3

```javascript
// 分類Aと分類Bに値が入力されると状況を完了にする。
// 条件分岐との組み合わせでプログラマブルな設定が可能。
// 「計算式の後」にチェック。
if (model.ClassA !== '' && model.ClassB !== '') {
    model.Status = 900;
}
```

### スクリプトの例4

```javascript
// ユーザIDによって規定のビューを切り替える。
// 「サイト設定の読み込み時」にチェック。
if (context.UserId === 1) {
    siteSettings.DefaultViewId = 1;
} else if (context.UserId === 2) {
    siteSettings.DefaultViewId = 2;
} else {
    siteSettings.DefaultViewId = 3;
}
```

### スクリプトの例5 

```javascript
// ユーザID: 1 以外の場合には、担当者が自分のものだけを表示するようフィルタする。
// 編集画面でも機能するため動的にレコードのアクセス制御を行うことが可能。
// 「ビュー処理時」にチェック。
if (context.UserId !== 1){
    view.Filters.Owner = '[' + context.UserId + ']'; 
}
```

## 今後の機能拡張

サーバスクリプト機能を利用すると、業務要件に合わせたアプリケーションをこれまで以上簡単に開発できるようになります。今後の機能拡張は下記のようなものを検討しております。

|機能|説明|
|---|---|
|他レコードの操作|CRUDをサーバスクリプトから利用|
|項目のアクセス制御|利用者や状況に応じて項目の非表示や読み取り専用を設定|
|動的な通知|通知メソッドにより任意の条件やタイミングで通知を発行|
|一覧表示のCSS制御|任意の条件で行やセルにCSSを追加|
|ロック|任意の条件でレコードやテーブルをロック|
|メニュー制御|任意の条件でメニューの内容を変更する|
|コマンド制御|任意の条件でコマンドボタンの内容を変更する|

今後も無料で使えるオープンソースのプリザンターの機能強化に取り組んでまいります。ぜひご期待ください！メリークリスマス！🎅

プリザンターのダウンロードはこちら。
https://pleasanter.org
ping できるノードを見つける ＆ サーバを一括監視する

ping が返ってくるノード一覧を表示するバッチファイル。 および、
サーバ等が online かどうかを調べるバッチファイル。
こういうツールは たくさんあるけれど、DOS バッチファイルなのでツールを持ち込めない環境などでも使える。

Raspberry Pi を見つけるための方法を、ぐぐったけど案外 見つからなかったので作ってみた。
環境に合わせて適宜変更を。

文字化けするときは UTF-8 じゃなく Shift-JIS (ANSI) で保存。
(実行環境： Windows10 , Windows7 , ...)

---

#### １行で ping が返ってくるノードを見つける。

コマンドプロンプトにコピペして実行。

```dosbatch
for /l %i in (1,1,254) do @ping -w 1 -n 1 192.168.11.%i | find "TTL" 
```

---

#### ping が返ってくるノードを見つけるバッチファイル。


```dosbatch:SearchIP.bat

@echo off
cls

set network=192.168.11.

echo.
for /l %%i in (1,1,254) do for /F "usebackq tokens=*" %%j in (`ping -w 1 -n 1 %network%%%i`) do echo "%%j" | find "TTL"
echo.
pause
goto :eof
```

実行結果

```
"192.168.11.1 からの応答: バイト数 =32 時間 =1ms TTL=64"
"192.168.11.2 からの応答: バイト数 =32 時間 <1ms TTL=128"
"192.168.11.9 からの応答: バイト数 =32 時間 =30ms TTL=64"
続行するには何かキーを押してください . . .
```

---

#### ping が返ってくるノードを見つけ MAC アドレスも表示するバッチファイル。



```dosbatch:SearchIPandMAC.bat

@echo off
cls

set network=192.168.11.

echo.
setlocal enabledelayedexpansion
for /l %%i in (1,1,254) do (
  set ip=""
  for /F "usebackq tokens=*" %%j in (`ping -w 1 -n 1 %network%%%i`) do (
    echo "%%j" | find "TTL" > NUL: && set ip=yes
  )
  if not "!ip!" == "" (
    arp -a %network%%%i | find "%network%%%i"
  )
)
echo.
pause
goto :eof
```

実行結果

```
  192.168.11.1          xx-xx-xx-xx-xx-xx     動的
  192.168.11.9          xx-xx-xx-xx-xx-xx     動的
続行するには何かキーを押してください . . .
```

---

#### 監視対象のサーバから ping が返ってくるかを確認するバッチファイル。

監視対象のサーバは ping_server.txt に記述する。
１行に１サーバを書き、レコードの先頭は IP アドレス。



```dosbatch:ping_server.bat

@echo off
cls
echo.

set list=%~dpn0.txt

setlocal enabledelayedexpansion
for /f "tokens=1" %%i in (%list%) do for /F "usebackq tokens=*" %%j in (`ping -w 1 -n 1 %network%%%i`) do (
  echo "%%j" | find "TTL"
  echo "%%j" | > NUL: find "タイムアウト" && echo "%%i  is not reachable at !date! !time!"
)
echo.
pause
goto :eof

```

サーバ一覧ファイル 例


```:ping_server.txt
192.168.11.1	server1
192.168.11.2	server2
192.168.11.3	server3
192.168.11.16	server16
192.168.11.17	server17
192.168.11.18	server18
```

実行結果

```
C:\> ping_server.bat

"192.168.11.1 からの応答: バイト数 =32 時間 <1ms TTL=64"
"192.168.11.2  is not reachable at 2020/12/03 20:52:16.78"
"192.168.11.3  is not reachable at 2020/12/03 20:52:17.28"
"192.168.11.16 からの応答: バイト数 =32 時間 =22ms TTL=64"
"192.168.11.17 からの応答: バイト数 =32 時間 =32ms TTL=128"
"192.168.11.18  is not reachable at 2020/12/03 20:52:19.77"
続行するには何かキーを押してください . . .
```


### (無料 アプリ フリーウェア)
alpine 上の postgresql に pg_hint_plan を使う

## 環境
alpine
psql (PostgreSQL) 9.6.19

## やり方

```sh
apk update
apk add gcc make git musl-dev

git clone git://git.osdn.net/gitroot/pghintplan/pg_hint_plan.git

cd pg_hint_plan
git checkout refs/tags/REL96_1_2_7
make
make install

# 任意の database で有効化
psql -d databse1 -c "CREATE EXTENSION pg_hint_plan"
echo "shared_preload_libraries = 'pg_hint_plan'" >> /var/lib/postgresql/data/postgresql.conf"
```

上記実行後、 postgresql インスタンス再起動後に有効になります。
Macbookデータ移行したらエラーが出た！？

macbook　airからmacbook proにデータ移行してコマンドを打つと、、、


主に実行したコマンドは、

```
ruby -v

rails -v
```

などです。


以下のエラーが出ました。


```
dyld: Library not loaded: /usr/local/opt/gmp/lib/libgmp.10.dylib
  Referenced from: /Users/jun/.rbenv/versions/2.6.5/bin/ruby
  Reason: image not found
```



なぜなんなんだと、いろいろ試しているうちに解決策が見つかりました。



homebrewのバージョンがおかしかったのか、


```

brew update && brew upgrade
```



上記のコマンドでHomebrewを最新の状態にします。


そうすると、エラーが解決し使えるようになりました。
GCPのAPIを全部有効化するワンライナー

GCPを使っていると、APIを有効化するように求められることが多いです。
特にTerraformを使ってIaCをしていると、terraform applyのタイミングでAPIが有効化されていないと、applyが途中で失敗してしまいます。

以下のモジュールを使ってTerraformでAPIを有効化することもできますが、APIを有効化するためのリソースを適切に書き、それらの対して適切な `depends_on` を設定するのは面倒な作業です。

https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_project_service

APIの有効化はプロジェクト毎に1回だけやれば良い作業であり、IaCするメリットも薄いのでワンライナーを使って一括で有効化してしまいましょう。

```bash
# プロジェクトの切り替え
gcloud config set project <プロジェクトID>

for s in $(gcloud services list --available | sed 1d | cut -d' ' -f1); do gcloud services enable $s; done
```

これでAPIの有効化という煩わしい操作から解放されます。
【Laravel Dusk】ChromeDriverとChromeのバージョン不一致で生じるエラーの解決方法

#概要
[Laravel Dusk](https://laravel.com/docs/8.x/dusk)の公式に沿って`php artisan dusk`を実行時、下記エラーが発生

```
Facebook\WebDriver\Exception\SessionNotCreatedException: session not created: This version of ChromeDriver only supports Chrome version 87
Current browser version is 86.0.4240.198 with binary path C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
```
内容を簡単にまとめると、ChromeDriverとChromeのバージョンが一致していませんとのこと。

+ ChromeDriver：87.0.4280.20
+ Chrome：86.0.4240.198

#解決方法
解決方法は下記の2通り
**1. ChromeDriveのバージョンをChromeに合わせる** 
**2. ChromeのバージョンをChromeDriverに合わせる** 

##解決方法 ①ChromeDriveのバージョンをChromeに合わせる
Chromeのバージョンに合わせて、ChromeDriveのバージョンをインストール

```
// 〇〇には指定のバージョンを設定
php artisan dusk:chrome-driver 〇〇
```

##解決方法 ②ChromeのバージョンをChromeDriverに合わせる
Chromeのバージョン更新は、下記を参考にすればいけると思います
[Google Chrome を更新する](https://support.google.com/chrome/answer/95414?co=GENIE.Platform%3DDesktop&hl=ja)
実務経験をしている一年目がProgateであやふやな部分を補填する方法

社会人兼プログラミング歴一年目の私は、現在社内システムの修正や改善をしている最中。

言語はJava。

やっていくうちになんとなくわかってきたけど、いまいち理解があやふやな部分があるときのProgateの活用方法について。

#コースをやる必要はない
前提としてレッスンを1から受ける必要はない。これはあくまで何もわからない人向けであって、実務である程度理解しながらプログラミングができているのであればわざわざちまちまやるのは非効率。
![スクリーンショット 2020-11-29 13.56.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/849608/55c56a39-3e0f-d9c6-5f22-b10839eb16bb.png)

#使うのはスライド検索
なら何をするか。コース一覧の横にあるスレイド検索がおすすめ。
たとえば私の場合、for文は書けるけど拡張for文を書ける自信がなくて避けてたからこのスレイドを見てみるとか。
![スクリーンショット 2020-11-29 14.01.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/849608/2af1cd94-18a1-12f4-4942-ee549fab50cb.png)
こうすることで、自分が理解していない部分だけつまみ食いしながら確認することができるのでとても便利。
ちなみに言っておくと、無料会員は無料分、有料会員はすべて見れる。値段も手頃なのでさくっと有料で登録して、つまみ食いしたらさっさと解約してしまえばいい。そして、必要になったときにまた会員登録すればそこまで費用もかからないはず。

#実践は実務で
スライド検索である程度インプットしたらあとはアウトプットをするだけです。プログラミングはアウトプットが命。
そしてそのアウトプットをする場所は実務。アウトプットもでき、会社に貢献もできるのでまさに一石二鳥です。
BoltとServerless Frameworkを使ってSlackチャットボットをAWS Lambdaで実行する

# はじめに

AWS LambdaとBoltフレームワークを使って、Slackのチャットボットを作成しました。
[Bolt入門ガイド](https://slack.dev/bolt-js/ja-jp/tutorial/getting-started)の手順では、`ngrok`を使ってローカルPC上にボットを起動します。
実際の運用ではローカルPC上ではなくサーバ上にアプリを起動すると思いますが、AWS環境へのデプロイ方法の詳細は記載されていないため、備忘録も兼ねて投稿します。

# 各種ツールやライブラリの概要

名称 | 概要
---- | ----
Slack | チャットツール。アプリを作成しカスタマイズできる。
Bolt | Slackアプリ開発のためのフレームワーク。
AWS Lambda | AWSが提供するサーバレス環境。
Serverless Framework | AWS Lambdaを始めとしたサーバレス環境にデプロイするためのフレームワーク。
ngrok | ローカル環境をhttpsで公開できるサービス。開発環境として利用。

**今回実行した環境**

項目 | バージョン
---- | ----
OS | macOS Catalina
nodejs | v10.16.0
@slack/bolt | 2.0.1
Serverless Framework | 1.68.0

## 手順

1. Bolt入門ガイドに沿ってアプリを作成。
1. `seratch/serverless-slack-bolt-aws` をテンプレートとしてアプリを作成。
1. ngrokを使ってURLを生成、テスト。
1. sls deployを使ってLambdaに公開。

### 1. Bolt入門ガイドに沿ってアプリを作成。

[Bolt入門ガイド](https://slack.dev/bolt-js/ja-jp/tutorial/getting-started)の手順に従って、Slackのアプリを新規作成します。
こちらの手順を完了すると、ローカルマシン上でボットを起動し、Slackチャンネルから応答させることができます。
上記手順では`ngrok`の利用方法について記載はないので、以下を参考にインストールしてください。

- ngrokが便利すぎる - https://qiita.com/mininobu/items/b45dbc70faedf30f484e

### 2. `seratch/serverless-slack-bolt-aws` をテンプレートとしてアプリを作成。

AWS Lambdaにコードをデプロイするために、Serverless Frameworkを使います。
npmを使ってServerless Frameworkをインストールします。

```
npm i -g serverless
```

`seratch/serverless-slack-bolt-aws`という便利なテンプレートが公開されていますので、こちらを使ってアプリを作成します。
以下の手順に従って、アプリのインストールとトークンの設定を行います。

- https://github.com/seratch/serverless-slack-bolt-aws/blob/master/README.md

上記手順で生成した`handler.js`の`Application Logic`というコメント箇所を、作成した自分のボットのコードで置き換えます。
`.env`ファイルには、先の手順で使用した`SLACK_SIGNING_SECRET`、`SLACK_BOT_TOKEN`をそれぞれ設定ください。
`AWS_ACCESS_KEY_ID`、`AWS_SECRET_ACCESS_KEY`は、デプロイ先のAWSアカウントで作成したIAMのものを利用します。

### ngrokを使ってURLを生成、テスト。

以下のコマンドでローカルPCでボットを起動し確認できます。

```
$ sls offline
```

起動後、先の手順と同じように`ngrok`を使ってURLを生成しします。

```
$ ngrok http 3000
```

Slackアプリの`Event Subscriptions`メニューにある`Request URL`に生成したURLを入力します。
URLの末尾には`/dev/slack/events`を加えてください。
例えば以下のようなURLになります。

```
https://xxxxxxxx.ngrok.io/dev/slack/events
```

### sls deployを使ってLambdaに公開。

以下コマンドでAWS環境にデプロイできます。

```
$ sls deploy
```

URLが生成されますので、`ngrok`の時と同様、`Request URL`に入力します。
Slackのチャンネルでボットが応答すれば設定完了です。

以上、Boltフレームワークで作成したSlackチャットボットをAWSにデプロイする方法でした。
現在は、個人的な利用目的でしかチャットボットを運用していませんが、AWS CodePipelineなどと組み合わせれば、Slackから運用しているサービスのデプロイなどもできると思います。
ぜひ参考いただければと思います。

### 参照

- Slack Bolt 入門ガイド - https://slack.dev/bolt-js/ja-jp/tutorial/getting-started
- Serverless Framework の Bolt 用テンプレート - https://github.com/seratch/serverless-slack-bolt-aws
Big SurのMultiColorのAccent Colorに対応する。

macOS Big Surから導入されたアプリごとにAccent Colorを設定できるMultiColorに関する記事がなかったので備忘録として


![スクリーンショット 2020-11-29 13.51.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117659/7d7b760c-fd7e-3c18-39ac-72b2612a017c.png)

Accent ColorをAsset Catalogで定義する。（名前はなんでもいい）

![スクリーンショット 2020-11-29 13.52.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117659/9c16dccb-5a9f-ccc5-26f1-2794f86a3455.png)

Build SettingsのAsset Catalog Compiler - Optionsから
Global Accent Color Nameに先ほど作った色の名前を書く

![スクリーンショット 2020-11-29 13.53.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117659/fe3cfe12-1ffd-d56b-973d-d234645be35a.png)

適応された。

![スクリーンショット 2020-11-29 13.56.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117659/3897a16b-c926-f233-f0fe-0d1a07c6e24e.png)
凄く当たり前だけど個人的に出会って感動したif文の使い方

プログラミングを初めて
様々なコードを見たり学んだりしていく中で
if文の可能性に魅力を感じて
「個人的」には感動したif文の使い方を
今回は纏めてみました。
ぜひとも参考にして頂けると幸いです。

```PHP
<?php
$text1 = 'text1';
$text2 = 'text2';

$is_error = false;

if (isset($text)) { // $textは存在しないのでfalseに
	echo '存在する';
} else {
	echo '存在しない ';
	$is_error = true;
}
// 感動if文
if ($is_error) { // $is_errorの格納された値で評価
	echo 'エラーだよ';
} else {
	echo 'エラーはないよ';
}

```

結果

```
存在しない　エラーだよ
```

まず手始めの感動したif文は
変数にboolの値(true/false)を事前に格納しておき
その変数の値にそった評価をさせる方法に感動したのを覚えてます。
if文の条件って

```PHP
if ($text == 'text'){
~
// とか
if ($numbar == 1) {
~
```

と言った内容で評価をするものが大半ですが
感動if文では変数だけで評価をさせているので
初めてみた僕はぶっちゃけちんぷんかんぶんでしたw
でもif文をしっかりと理解すれば

条件の中(if (条件の中))がtrue/falseなら
分岐先の処理へと言った内容なので
極端にかけば

```PHP
if (true) { // trueへ
~
if (false) { // falseへ
~
```
こんな感じで内部で処理されているんだなとなる
言葉での説明が難しいが

```PHP
if (isset($text)) {
~
```

これは条件の中で
isset($text)が処理されて
true/falseになる

```PHP
if (isset($text)) {
↓
// $textが存在する場合
if (true) { //trueの処理へ
// または$textが存在しない場合
if (false) { //falseの処理へ
```

これが理解できると
$is_errorと言ったような変数名を使って
エラーの有無を格納してより可読性が高く
判読性のあるコードが書けるようになるなぁと
当時の僕は感じたのを覚えています。

当たり前に使われている方法だけど
理解してないと使えない、使わないに繋がって
その人にとってもったいないのでぜひとも活用してみてください！
docker-composeを使って最速で社内DNSを構築してみた

この記事は [生産性向上のための環境整備2020 【PR】 Lenovo Advent Calendar 2020](https://qiita.com/advent-calendar/2020/lenovo_env_02) の１日目の記事です。

２日目の記事：[Lenovo社のモバイルディスプレイ 「ThinkVision M14」を買ってよかったこと！ @RyotaMurohoshi](https://mrstar-logs.hatenablog.com/entry/2020/12/02/010916)


社内だけで使えるサービスやシステムを複数運営していると、IPアドレスでのアクセスは大変になってきます。

そこで、社内サービスにもドメインを使ってアクセスできるように社内DNSを整備しました。

合わせてこちらもご覧ください！セットで行うことで、より生産性を向上できます！
[まだhttpで運用してるの👀？（Cloudflare + docker-composeで自動更新可能ワイルドカード証明書を発行してSSL化してみた）](https://qiita.com/nomunomu0504/items/d69d4d94fa5a6f23a25d)

## 前提
- ドメインは取得済み
- ドメインのワイルドカード証明書取得済み  
→ これに関しては取得していなくても大丈夫ですが、SSL化された通信を行いたい場合は取得しておきましょう  
- 取得ドメイン：choipre.com

構築後のネットワーク図は以下のような感じになります
![スクリーンショット 2020-11-29 13.46.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110131/4dd761d5-14b0-c87f-9e01-96d0ec7db003.png)

## 構築
DNSはDockerを使って構築します。CoreDnsというDocker-imageが公開されているので、そちらを利用します。フォルダ構成としては以下の感じです。

```
drwxr-xr-x   - nomunomu  2 11 18:01 dns
.rw-r--r-- 244 nomunomu  4 11 16:00 ├── docker-compose.yml
.rw-r--r-- 115 nomunomu  4 11 16:00 ├── Dockerfile
drwxr-xr-x   - nomunomu  2 11 17:58 └── volumes
drwxr-xr-x   - nomunomu  4 11 16:14    └── config
.rw-r--r-- 181 nomunomu  4 11 16:32       ├── Corefile
.rw-r--r--  53 nomunomu  4 11 16:14       └── hosts
```

### Docker系設定

```:docker-compose.yml
version: '3.1'
services:
  coredns:
    build: .
    container_name: coredns
    restart: on-failure
    expose:
      - '53'
      - '53/udp'
    ports:
      - '53:53'
      - '53:53/udp'
    volumes:
      - './volumes/config:/etc/coredns'
```

```:Dockerfile
FROM coredns/coredns:1.7.0

EXPOSE 53
EXPOSE 53/udp

ENTRYPOINT ["/coredns"]
CMD ["-conf", "/etc/coredns/Corefile"]
```

### CoreDns設定

どのドメインとIPアドレスが紐づくかをhostsファイルに記述します。Corednsの設定はファイルはCorefileというファイルに記述します。

```:Corefile
. {
    whoami
    forward . 192.168.0.100:53   # ここはPublic-DNSでもよい
    errors
    log . "{proto} {remote} is Request: {name} {type} {>id}"
    hosts /etc/coredns/hosts {
        fallthrough
    }
    reload
}
```

```:hosts
192.168.0.110 xxxxxx.choipre.com
192.168.0.111 yyyyyy.choipre.com
192.168.0.112 zzzzzz.choipre.com
```

### 起動
docker-compose.ymlがあるディレクトリで以下のコマンドを流すと、DNSが起動します。

```
docker-compose up
```

docker-composeを走らせたPC（192.168.0.100）へ各クライアントのDNS解決先を向けることでローカルのIPに対してもドメインでアクセスすることができるようになります。

社内のネットワークを整備して、快適なネットワークLifeを！！
超簡単！erbで動的にシンプルなカレンダを作る方法

アドベントカレンダの記念すべき1日目なのでカレンダネタです。

## この記事を読んだらできること

- 任意の範囲でカレンダが作れる
- 特定の日だけデザインを変えたり、文章を変えたりできる

## いきなりですがコード。

```erb
<% # この辺りはViewModelあたりに入れるのがお行儀がいい %>
<% # カレンダにしたい月を含む日付であればなんでもいい %>
<% target_month = Date.new("2020-12-01") %>
<% # カレンダのはじまりの日(例では月初) %>
<% start_day = target_month.beginning_of_month %>
<% # カレンダの終わりの日(例では月末) %>
<% last_day  = target_month.end_of_month %>

<% # カレンダ本体 %>
<table>
  <thead>
    <tr>
      <% %w[日 月 火 水 木 金 土].each do | day | %>
        <%= content_tag :th, day %>
      <% end %>
    </tr>
  </thead>

  <tbody>
    <tr>
      <% # 月初部分の曜日調整 %>
      <% start_day.wday.times do %>
        <%= content_tag :td, '' %>
      <% end %>

      <% (start_day..last_day).each do | date | %>
        <%= content_tag :td, date.day %>
        <% # wday == 6 は土曜日なので、tableの次の行(tr)へと移行する %>
        <%== '</tr><tr>' if date.wday == 6 %>
      <% end %>
    </tr>    
  </tbody>
</table>
```

今回は月初から月末までのオーソドックスなものですが `start_day` `last_day` を変えれば任意の範囲でのカレンダが作れます。
また、 `<%= content_tag :td, day.day %>` を下記のようにすればクリスマスだけ表示を変えたりCSSのclassを付与したりもできます。

```erb
<% if date.month == 12 && date.day == 25 %>
  <%= content_tag :td, 'Xmas', class: 'xmas' %>
<% else %>
  <%= content_tag :td, date.day %>
<% end %>
```

シンプルな分、カスタマイズが自由なカレンダだとおもいます。
Pythonでシーザー暗号プログラム

この記事では、Ｐｙｔｈｏｎのでメッセージをシーザー暗号に暗号化。
また、シーザー暗号を解読するプログラムを紹介します。
とは言っても、皆さんが知っているようなパパっと2、3行！ではなく、内部の仕組みがわかりやすいように書いてみました。

プログラム本文（Win10で動作確認済み）

```Python:シーザー暗号.py
from time import sleep

print("this is a softwear for decoding or coding a code(ascii.ver)")
code_type = input("please select (decoding:d,coding:c)")

counter_C = 0
counter_D = 0
key_counter_C = 0
key_counter_d = 0
#letters = "abcdefghijklmnopqrstuvwxyz"
coded_code = "the code is "
answer = "the messege is "

if code_type == "c":                  
    code_C = input("INPUT STRING(please input a string in big letters):")           
    key_num_C = input("INPUT CODING KEY(please input a coding_key in a big letter):")     
    key_counter_C = ord(key_num_C)-65         
    print(key_counter_C)
    
    while counter_C < len(code_C):            
        coded_code = coded_code + chr(ord(code_C[counter_C])+key_counter_C)
        print(coded_code)
        sleep(0.1)
        counter_C = counter_C + 1
    
    print("CODING COMPLEAT")
    print("CODE:"+coded_code)
    print("this tab will close in 10sec")
    sleep(10)

if code_type == "d":                  
    code_D = input("INPUT CODE:")           
    key_num_D = input("INPUT CODING KEY:")     
    key_counter_D = ord(key_num_D)-65         
    print(key_counter_D)
    
    while counter_D < len(code_D):            
        answer = answer + chr(ord(code_D[counter_D])-key_counter_D)
        print(answer)
        sleep(0.1)
        counter_D = counter_D + 1
    
    print("DECODING COMPLEAT")
    print("MESSEGE:"+answer)
    print("this tab will close in 10sec")
    sleep(10)
```
※プログラムの余分な箇所はコメントアウトしました。
Tick-Tack-Toe（どう書く）

#問題
[http://nabetani.sakura.ne.jp/hena/1/](http://nabetani.sakura.ne.jp/hena/1/)

>三目並べ( tick-tack-toe )の手を入力とし、勝敗を出力する。
>
>*    先攻がo、後攻がx
*    すでに打ってある場所に打った場合、反則負け。
       x が反則をした場合、「Foul : o won.」と出力
*    縦横斜めのいずれかで一列揃ったら、揃えた方の勝ち。       x が揃えた場合、「x won.」と出力
*    9マス埋まっても揃わなかったら引き分け。
        「Draw game.」と出力
*    勝敗が決した後の手は無視する
*    入力文字列は、先攻から順に打った位置を示す。盤上の位置と数の対応は下表を参照。
*       入力文字列が「91593」の場合、「oが9の位置、xが1の位置、oが5の位置、xが9の位置→xの反則負け(最後の3は無視)」となる。
*    以下の様なケースは考慮しなくてよい。
            入力が 1〜9 以外の文字を含んでいる。
        入力が不足していて、ゲームの勝敗が決まらない。

| 1 | 2 | 3 |
|---|---|---|
| 4 | 5 | 6 |
| 7 | 8 | 9 |

#コード
```ruby:Ruby
class TickTackToe
  WinPattern = %W(123 456 789 147 258 369 159 357)
  def initialize(input)
    @input = input.chars.map(&:to_i)
    @field = Array.new(10)
    @turn = 0    #o
    @ptns = WinPattern.map {|pt| pt.chars.map(&:to_i)}
  end
  
  def solve
    @input.each do |i|
      if @field[i]
        return "Foul : #{output_turn(false)} won."
      else
        @field[i] = @turn
        if settle?
          return "#{output_turn} won."
        elsif @field[1..9].all?
          return "Draw game."  
        else
          @turn = 1 - @turn
        end
      end
    end
  end
  
  def settle?
    @ptns.any? do |pt|
      a = pt.map {|i| @field[i]}.join
      a == "000" || a == "111"
    end
  end
  
  def output_turn(t = true)
    %W(o x)[t ? @turn : 1 - @turn]
  end
  
  def self.solve(input)
    new(input).solve
  end
end


if $0 == __FILE__
  data = [79538246, 35497162193, 61978543, 254961323121, 6134278187, 4319581,
   9625663381, 7975662, 2368799597, 18652368566, 965715, 38745796, 371929,
   758698769, 42683953, 618843927, 36535224, 882973, 653675681, 9729934662,
   972651483927, 5439126787, 142583697, 42198637563, 657391482]
  
  data.each do |d|
    puts TickTackToe.solve(d.to_s)
  end
end
```
素因数分解アルゴリズム（Ruby）

#はじめに
入力した数字を素因数分解するアルゴリズムを作成します。
#実行
入力するためのコードは次のようにします。

```ruby
puts 数字を入力してください
x = gets.chomp.to_i
```

素因数分解の為に、別途数字を用意し、その数字で割り切れるかどうかを判別していきます。
割り切れる場合は1をプラスして、次の数字で判別します。

```ruby

a = 2
puts 数字を入力してください
x = gets.chomp.to_i
```

ここでは、判定用の数字をaにします。
割り切れるかどうかの判定は次のようにします。

```ruby
if x % a == 0
end
```
これで、xがaで割り切れるかどうかが判定できます。
今回は、配列を使用して最後に約数を表示させたいので、割り切れた場合は事前に用意していた配列に追加していきます。

```ruby
answer = []
```

```ruby
if x % a == 0
  answer << a
end
```

今のままだと、同じ約数がひたすら追加されるだけなので、
割り切れたら元の数字を割る、割り切れなかったら次の数字で試す、
という操作を入れます。

```ruby
if x % a == 0
  answer << a
  x = x / a
else
  a += 1
end
```

これを元の数字が1になるまで続けます。

```ruby
while x > 1
  if x % a == 0
    answer << a
    x = x / a
  else
    a += 1
  end
end
```

最後にpメソッドを使って表示させます（putsメソッドだと、改行されて結果が見にくくなることがあるので）

```ruby

p answer
```

最終的なjコードは次のようになります。

```ruby

a      = 2
puts 数字を入力してください
x      = gets.chomp.to_i
answer = []

while x > 1
  if x % a == 0
    answer << a
    x = x / a
  else
    a += 1
  end
end

p answer
```

試しに出力して、`775249`と入力すると、[61,71,179]と出力されます。
色々改良可能なコードなので、色々試そうと思います。
Railsでparticles.jsを使ってみた


#はじめに

javascript ライブラリのparticle.jsを使ってみました。
途中、思うようにいかずつまづいていたので、うまくいったやり方を書いておきます。

幾何学模様や、宇宙みたいな粒子をマウスの動きに合わせてアニメーションを設定できる、楽しいやつです。

![ダウンロード.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837382/e7e55146-1a50-0e28-8798-cbfe74a2b03c.gif)
デフォルト

![snow-particles.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837382/6d6a246d-bc41-06da-f1eb-80714124710b.gif)
snowバージョン



##環境
mac OS バージョン10.15.7
Rails 5.1.6
particles.js 2.0.0



##step.1 デモジェネレーターで作りたい見た目を作る

①デモサイトでアニメーションを作る
デモジェネレーターのリンク
>https://vincentgarreau.com/particles.js/

で好きなアニメーションを設定する。
カラーはもちろん、アニメーションのスピードや粒子の方向なども設定できる。

②設定したファイルをダウンロード

>Download current config (json)

　のボタンでダウンロードできます。


③public/assets　内にダウンロードしたJSONファイルを配置
私はこのファイルを app/assetsに配置してずっとうまくいかないな〜ってなってました。
JSONはimgファイルとかと同じ扱いらしいです。

##step.2 パッケージのインストール

Packages install

```Gemfile
gem 'particles-js-rails', '2.0.0'
```

```
bundle install
```

##step.3 コードを書く

bodyタグの閉じタグ直前に以下を記述

```html:application.html.erb
<script src="https://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js"></script>
<script>
particlesJS.load('particles-js', 'assets/particles.json', function() {
      console.log('callback - particles.js config loaded');
    });
</script>
```

assets/particles.jsonの箇所は配置したファイルの名前に合わせる。
ダウンロード直後はparticlesjs-config.jsonのようになっているはず


アニメーションを配置したい箇所に以下を記述

```html:top.html.erb
<div id="particles-js"></div> 
```

CSSファイルに以下を記述

```css:top.scss
#particles-js {
    width:100%;
    height: 100%;
    margin:0 auto;
    background-color: rgb(230, 182, 216)
}
```

これで行けるはず。



もしprecompileのエラーが出てきたら、下記を試してみてください


```config/initializers/assets.rb
Rails.application.config.assets.precompile += %w( particles.js )
```

##参考（本家）
https://github.com/VincentGarreau/particles.js/
スターを付けて使いましょう。
Dockerのバージョン確認方法

#端末（PowerShell）から

```
docker version
```
こんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/552035c8-400b-2471-3f4f-6c8802cfd2d8.png)



#GUIから
クジラさんを右クリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/5ebc3796-21b7-d6de-e135-69cafb8a1161.png)
ここ！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/905cfaae-c93d-4068-9aae-21b8da578e9b.png)
ここ！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/16549306-eb33-1caf-e163-e46b97e060bd.png)


#バージョン
Windows10 Pro バージョン1909 OSビルド19042.630
Docker Desktop:2.5.0.1（49550） Engine:19.03.13
PSVersion 5.1.19041.610
Type 'number[]' is not assignable to type '[number, number]' を解決する

座標のような、値がちょうど二つ欲しいとき、`[number, number]`型を指定します。

```typescript
const map = (center: [number, number]) => {
  ...
}
```

`center` は `[number, number]`型 を明示して宣言します。

```typescript
const center: [number, number] = [10, 20]

map(center)
```

そうでないと、

```typescript
const center = [10, 20]  // number[]

map(center)
// Type 'number[]' is not assignable to type '[number, number]'
```

`center` は配列として推論されるのでコンパイルに失敗します。
AtCoder初参戦した感想など

"AtCoder Regular Contest"に初参戦しました。
[AtCoder Regular Contest 109](https://atcoder.jp/contests/arc109)

今後は月に１回程度のペースで参戦を重ねていきたいと思っています。
この記事は個人的なブログとして参加した感想を書きたいと思います。

# 私について

私の競技プログラミング経験は、就職活動のためpaizaのスキルチェック問題を数回ほど。
[ITエンジニア・プログラマ向けの転職・就活・学習サービス【paiza（パイザ）】](https://paiza.jp/)

余談ですが、paizaではAランクというそこそこ難しい問題を解いて査定年収729万でした。
エンジニアにフルコミットして働き始めたのは2017年5月で、paizaの就職活動は当時2年目でした。
査定結果を確認して浮かれていましたが就職活動がそんなに甘くなかったことは想像に難くないでしょう。
経歴書が薄っぺらいですからね。

フルコミットする前は塾の先生をしていました。担当は数学。
その頃からずっと趣味の延長でWEBアプリ開発（GAE/Java）やiOSアプリの開発をやってます。

現在の仕事はPythonやReactを使ったWEBアプリ開発です。
AWSのアーキ設計やCICD構築にも関わっていて、手を動かすメンバーが5人ほどのチームで幅広くやってます。
型チェックが大好きで、PythonはMypy、ReactにはTypeScriptを使っています。TypeScriptが一番得意です。

# どの言語で解くか

いろいろと迷いましたがPythonで解きました。

昨日はネットワーク環境に通信制限が掛かっていたので、`npm install`や`pip install`など出来ない状況でした。VSCodeでコード補完させながらコードを書きたかったのですが、環境を整えるのが困難だったのでブラウザーでいろんな言語が実行できるpaiza.ioを利用しました。
[ブラウザ上でコードを書いてすぐに実行！！](https://paiza.io/ja)


paizaやっていたころはTypeScriptを使った開発がメインでしたが、TypeScriptは提出言語に選べないのでSwiftで解いていました。[SwiftでPaizaを攻略するための予備知識](https://qiita.com/Lzpeth/items/6c1d8a54fd47677b0a50)

今後のことを考えると速さ重視でC++やRustを使って上位を目指したいです。
その前にアルゴリズム力を鍛える必要がありますけど。

# その他準備したこと

計算用紙に使うためA4の紙を10枚ほど準備しました。

競技プログラミングは数学的な思考力を求められる問題が多く式を書いて計算することはよくあります。また問題把握のためにいろんなケースを書き出すときには紙のほうが便利だと思います。

# 解いた結果

A~Fまで全部で６問出題されます。私が取り組めたのはA,B,Cの３問だけでした。

3問提出しBだけが得点になりました。

Aには考慮不足のケースがあり「WA (Wrong Answer)」という結果が返されていました。「WAってなんだ？」という状態でその場で点数にならないことを確かめずに放置してしまったのでもったいなかった。

Cは正解が計算可能なコードでしたが愚直に問題状況をシミュレーションするようなアルゴリズムだったので「TLE (Time Limit Exceeded)」でした。TLEの意味は知っていましたが時間以内に直すアイディアが浮かばず。。

楽しかったけど、めちゃくちゃ悔しい！

# 次に向けて

たくさん問題を解くのが一番ですよね。AtCoderでは過去開催のコンテストもバーチャル参加が可能です。

問題に向き合って最初にやることは自分で追加のテストケースを作ることが問題を早く解く近道であるように思いました。問題には２〜３つのサンプルケースが最初から与えられていますが、それ以外のケースを自分で作る作業は短時間で問題理解度を確実に高めてくれると思います。

レーティングトップ10に入っている人たちの提出タイムを見ると頭でかなりのケースが把握できる人たちなんだろうと思いますが、私はしっかり紙にケースを書き出して答えを具体的に数え上げてサンプル以外にテスト出来る準備をしておくことが「急がば回れ」になりそうだなと思いました。

問題と向き合っているときのルーティンがある程度決まってくると、もっとミスなく解けるかなと思います。

競プロを鍛えるための道筋を示してくださっている記事もあるので、そういうところから手を付けていこうと思います。

https://qiita.com/drken/items/fd4e5e3630d0f5859067

以上、AtCoder初参戦した感想でした。
AWS ソリューションアーキテクトアソシエイト向け問題 VPC編

## 概要

今回は会社の後輩向けにAWS ソリューションアーキテクトアソシエイト向けの問題を作成したのでそちらの公開を。
元ネタは公式の問題、BlackBeltなどからとっております
今回はVPCをみようと思います。

## VPC関係

* ネットワークACL,セキュリティグループについて説明している文で以下の中から正しいものを1つ選択してください。
    1. ネットワークACLはサーバレベルで効果を発揮する。
    1. ネットワークACLはAllow/DenyをIN・OUTで指定可能。
    1. ネットワークACLはすべてのルールを適用する。
    1. セキュリティグループはステートレスなので戻りのトラフィックも明示的に許可する必要がある。
    1. ネットワークACLはステートフルなので戻りのトラフィックを考慮する必要はない。

<details><summary>回答</summary><div>

* 正解は

    2. ネットワークACLはAllow/DenyをIN・OUTで指定可能。
        * ネットワークACLを使うことで接続を禁止することもできます。
        * セキュリティグループはAllowのみを指定できるので接続先を追加したいときに設定します。

* 以下不正解の理由

    1. ネットワークACLはサブネットレベルで効果を発揮します。サーバによって接続先を制御したいときはセキュリティグループを使います。
    3. ネットワークACLは番号の順序通りに適用します。上位に優先したい条件を指定することで絞り込めます。
    4. セキュリティグループはステートフルです
    5. ネットワークACLはステートレスです


</div></details>

* あるアプリケーションをプライベートサブネットに配置したEC2インスタンス(t3.nano)で実行しそこからS3にアクセスすることを予定しています。しかしS3へアクセスできないようです。IAMロールの設定やバケットポリシーについては問題ないとします。この場合の対処法を以下から選びなさい。(2つ)
    1. EC2インスタンスのインスタンスタイプをt3.micro以上にする。
    1. EC2インスタンスをプライベートサブネットではなくパブリックサブネットに配置する。
    1. AWS Transit Gatewayの設定を行う。
    1. VPC Endopointをプライベートサブネットに対して作成する。
    1. インスタンスに対してEIPのみを設定する。

<details><summary>回答</summary><div>

* 正解は

    2. EC2インスタンスをプライベートサブネットではなくパブリックサブネットに配置する。
    4. VPC Endpointをプライベートサブネットに対して作成する。
        * パブリックサブネットに配置することでインターネットに接続できるためS3へアクセスできるようになります。
        * VPC Endpointを設定することでインターネットに接続しなくてもアクセスが可能です。DynamoDBなどほかのAWSサービスへの接続を行いたいときもVPC Endpointの設定を行います。

* 以下不正解の理由

    1. インスタンスタイプは関係ありません。
    3. AWS Transit Gateway は1000以上のVPCとオンプレミス環境を接続するときに使用します。
    5. EIPのみでなくNAT ゲートウェイまたはNATインスタンスの設定が必要ですこの2つを設定することでS3へアクセスは可能です。


</div></details>
アイカツカードを検索するdiscordのbotを作成する

#はじめに
この記事はアイカツ！ Advent Calendar 2020の1日目の為に書き下ろしました。今年は誰もアドベントカレンダーを作成していなかったので作成しましたが既に1日目にしてSHINING LINE*が切れそうです。助けてください(切実)
前日の記事はありません。記念すべき1日目です。

##自己紹介
N高等学校所属の高校三年生です。MacをMBRで動作させる趣味があります。[^1][^2]
普段はPython3をメインに書いていて片手間でRustをちょこっと学習しています。でもRustの概念があいまいなのでもう少し理解を深める努力をしたいです。Go Langとは分かり合えないです。[^3]

##今回作成したもの
アイカツカードの検索botをpythonで作りました。使用ライブラリはdiscord.pyとbeautifulsoup4、requestsです。実際の~~見にくい~~コードを引用して紹介したいと思います。

##実際のコードから引用したもの
```search.py(スクレイピング部分)
res = requests.get('https://www.aikatsu.com/onparade/cardlist/index.php?search=true')
#アイカツのカード一覧サイトにDDoS攻撃
soup = BeautifulSoup(res.text, 'html.parser')
#lxmlパーサー動かん...

for l in soup.find_all("dd", class_="cardName"):#カード名から要素取得してる
    print(l.text)
    CN.append(l.text)
    
for l in soup.find_all("dd", class_="cardNum"):#これはカード番号取得。
    print(l.text)
    CU.append(l.text)
    
print(CU)
print(CN)

while True:#これはカード名とカード番号を連結している
    a = CU.pop(0)
    b = CN.pop(0)
    CR.append(a+" "+b)
    if CU == [] and CN == []:
        break
    print(CR)
```
クソ汚いコードです。もう少しマトモな書き方は出来ないのでしょうか。
簡潔に纏めるとbot起動時に公式カードリストからカード一覧とカード番号を取得してbotアカウントにログインしています。

##作りたくなったきっかけ
アイカツ公式のサイトが画像を多用しており読み込みが遅かったため[^4]discord上で検索できるようにするべきだと思い作成しました。製作期間は概ね5日です。[^5]

##実際の動作
```!s エンジェリー```と打つとエンジェリーを含むカードを出力します。![キャプチャ10.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328076/0662a61f-4c7f-d4c5-5961-5207a00187d5.png)
複数のキーワードも可能で```!s PR エンジェリー```と検索した場合PRとラブを含むカードを出力します。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328076/63e0cb33-6f3a-1128-0a71-23d8b21f4090.png)
原理としては完全一致検索なので複数のキーワードを含む際、それらのキーワードがすべて含まれるカードを出力します。

##今後の課題
複数キーワード検索で```ラブディスティ二ーコーデ```とかの真ん中のキーワード、ディスティニーで検索してみたいです。実装方法は思いつかないので後日手探りで考えてみたいと思います。
![キャプチャ111.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328076/17ae1e4a-b7c4-4281-e301-487054512fe1.png)

##終わりに
アドベントカレンダー用にこのネタを思いつき必死で製作するのは少し身体に来るものがありました。来年はもう少し余裕を持ちたいと思います。2日目は[]()さんの[]()です。




[^1]: そんな趣味だから女にモテないし婚期を逃すんだ(現18歳)。今すぐやめて婚活をしろ。
[^2]: [Mac OS XをMBRで動かす](https://qiita.com/ricotan_aikatsu/items/14c58f8bf5cd0676af80)に書きました。ニッチなオタクさあ...
[^3]: Go Langすら出来ないのにPythonも出来るわけがない。
[^4]: 自分の所有しているPCがポンコツなのもある。
[^5]: この間に[こんな問題](https://qiita.com/ricotan_aikatsu/items/0bd71436fa9821ad5fd7#%E3%83%8B%E3%83%83%E3%83%81%E3%81%AA%E4%BA%BA%E3%81%8C%E3%83%8F%E3%83%9E%E3%82%8B%E3%82%A8%E3%83%A9%E3%83%BC)も起きたので実質4日程度?
Laravel Duskでエラー「Facebook\WebDriver\Exception\UnknownErrorException: unknown error: net::ERR_CONNECTION_REFUSED」が発生した場合の対処方法

#エラー発生したタイミング
`php artisan dusk`を実行時に、タイトルにあるエラーメッセージが表示

#原因
`.env`ファイルの`APP_URL`パラメータで指定されている値が原因

#解決方法
 [公式](https://laravel.com/docs/8.x/dusk)にも明記されているが、`APP_URL`には、ブラウザでアプリケーションにアクセスするために使用するURLを設定する必要がある。

アプリケーションのURLが下記の場合
`Starting Laravel development server: http://127.0.0.1:8000`

```
APP_URL=http://localhost //（デフォルト）
↓
APP_URL=http://localhost:8000 //（変更後）
```