OmniAICreator/Qiita-1.07M huggingface dataset:
ハイパースレッディングとは？

## 勉強前イメージ

CPUのなにか・・・・

## 調査

### ハイパースレッディングとは？

Intel社がマイクロプロセッサーに搭載している
1つのプロセッサコアを擬似的に二つに見せかける技術で、
同時マルチスレッディング(SMT)技術の一つである。

### そもそもプロセス・スレッドとは？

- プロセス

実行中のプログラムのこと。
1つのプロセスには1つのメモリ空間が割り当てられている

- スレッド

プロセス内で命令を実行する部分で、CPUコアを利用する単位
同時マルチスレッディング(SMT)ができるまでは1コアに1スレッドが立つのが普通でした。

SMTを利用すれば、
1コアに対して複数のスレッドを割り当てられることが出来ます。

### 様々な確認方法

こちらはlinuxでの確認方法。
多分他にもやり方あると思うけど、、、、

#### ハイパースレッディングが有効か確認したい

確認コマンドは以下。

```
dmidecode -t processor | grep -E '(Core Count|Thread Count)'
```

2コアですが、スレッドが4なのでハイパースレッディングが有効になっています。

```
[root@localhost ~]# dmidecode -t processor | grep -E '(Core Count|Thread Count)'
        Core Count: 2
        Thread Count: 4
```

#### CPUコア数を確認したい

- 物理CPUの数

```
grep physical.id /proc/cpuinfo | sort -u | wc -l
```

結果は以下。
ここでは物理CPUは1つだけ。

```
[root@localhost ~]# grep physical.id /proc/cpuinfo | sort -u | wc -l
1
```

- CPUごとのコア数

```
grep cpu.cores /proc/cpuinfo | sort -u
```

結果は以下。
マルチコアプロセッサーだと物理CPU1つにつき、何コアあるか見ることが出来ます。

```
[root@localhost ~]# grep cpu.cores /proc/cpuinfo | sort -u
cpu cores       : 2
```


- 論理プロセッサーの数

```
grep processor /proc/cpuinfo | wc -l
```

結果は以下。
計算上、1つの物理CPUで・CPU1つにつき2コアなので、2ですが
ハイパースレッディングが有効になっているので2つのコアにつき2つスレッドがつくようになっています。

```
[root@localhost ~]# grep processor /proc/cpuinfo | wc -l
4
```

topを見てもCPUは4つになっている

```
top - 13:10:16 up 3 min,  1 user,  load average: 0.02, 0.04, 0.01
Tasks: 115 total,   1 running,  59 sleeping,   0 stopped,   0 zombie
%Cpu0  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  :  0.0 us,  0.0 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.3 st
%Cpu2  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  :  0.0 us,  0.3 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.3 st
```

## 勉強後イメージ

物理的なところは全く分からなかったけど、なんとなくわかった。。。。
実際に動くのは論理プロセッサーってこと？多分？
こういうの勉強するの、今までの知識が結びついて楽しいね

## 参考

- [物理 CPU、CPU コア、および論理 CPU の数を確認する](https://access.redhat.com/ja/solutions/2159401)
- [Hyperthreading が有効かどうか確認する方法](https://qiita.com/intrajp/items/67a71eae7507d19915dc)
- [【図解】ハイパースレッディング(SMT)の仕組み～メリットとデメリット、悪影響や脆弱性などの問題について～](https://milestone-of-se.nesuke.com/sv-basic/architecture/hyper-threading-smt/)
osmium-tool の tags-filter 処理（シェルスクリプト）

こんにちは。
OpenStreetMap データ（osm.pbf ファイルの ```way``` データ）に対して、osmium-tool の [tags-filter](https://osmcode.org/osmium-tool/manual.html#filtering-by-tags) コマンドの処理を行うシェルスクリプトを作りました。 ```and``` 条件も指定可能です（```&``` で区切った条件を与えます）。GeoJSON データを標準出力します（GDAL (ogr2ogr） を使っています）。

動作例（下記）は、

1. 最初に、tags-filter: ```w/highway=motorway,motorway_link``` を処理し[^1]、
2. 次にこれに対して、tags-filter: ```w/moped=yes w/bicycle=yes``` を処理する例です：

[^1]: 複数条件を指定すると ```or``` 扱いです（osmium-tool の tags-filter の仕様です）。

```console
$ ./tags_filter.sh "w/highway=motorway,motorway_link & w/moped=yes w/bicycle=yes" japan-latest.osm.pbf > result.geojson
```

```tags_filter.sh
#!/bin/sh

WAYS="$1"
inputfile="$2"

## function ##
realpath_() {
  case "$1" in /*) ;; *) printf '%s/' "$PWD";; esac; echo "$1"
}

## main ##
resultfile=ways.osm.pbf
inputfile=$(realpath_ "$inputfile")
tmpdir=$(mktemp -d)
cd "$tmpdir" || exit

echo "$WAYS" | tr '&' '\n' | { while read -r ways; do
  cp -f "$inputfile" input.osm.pbf
  osmium tags-filter input.osm.pbf $ways -O -o "$resultfile"
  inputfile="$resultfile"
done }

ogr2ogr -f "GeoJSON" result.json "$resultfile" lines >/dev/null
cat result.json
rm -rf "$tmpdir"
exit
```
Windowsサービスの削除

# Windowsサービスを削除したい。
アップルユーザーが、独学でWindows serverを構築した後に、zabbixをインストールしました。
しかし、設定に失敗。
zabbixのインストーラーを再インストールしたときに、Windowsサービスによりエラーになりました。
時間がかかってしまいましたので、投稿しようと思います。

# そもそもWindowsサービスとは？
WindowsサービスとはOS内で、バックグラウンドとして稼働するプログラムです。
バックグラウンドはフォアグラウンドとは異なり、GUIで実行していなくても画面の裏側で処理を実行することができます。
バックグラウンドは、ユーザーが実行していなくても、実行をすることが特徴です。

特定のサービスをGUIで設定ができますが、削除に関する機能の設定はコマンドプロプトを用いて削除を行います。


# コマンドで削除
まずコマンドでサービスを削除するためには、サービス名を調べる必要がります。
＊コマンドには管理者として入り、削除の実行をしてください。

サービス管理ツールを使用し、削除したいサービスを指定します。
コントロールパネル→サービス管理ツールから見つけ出します。
削除するサービスのプロパティを開き、そのプロパティの名前がサービス名になります。

```
# sc delete サービス名
```

## 初心者が陥るポイント
多くのサイトには削除する時は、プロパティに記載されているサービス名をそのまま記載しています。
そして以下の例外については触れていません。

その為こちらで記載します。
その例外ついては、サービス名は一単語の場合、""は必要ありません。

しかし、サービス名が[Zabbix Server]と文字に空間がある場合、""(ダブルクォーテーション)で囲む必要があります。

コマンドでスペースを開けるとそれぞれコマンドとして認識してしまう可能性があります。
それを防ぎ一つの値として認識してもらうために、""で囲むことでコマンドを実行することができます。
スペースやスペルを完全に一致さして、""を使用する必要があります。

```
sc delete "Zabbix Server"
```

# まとめ
・Windowsサービスはバックグランドで動くプログラム。
・Windowsサービスはコマンドを使用して削除する必要がある。
・コマンドは管理者として実行する。
・コマンドで用いるサービス名は、管理ツールのプロパティで確認する。
・サービス名にスペースがある場合は、""で囲む。

わからないことに挑戦して、苦戦しますが理解すると楽しいですね。
何かアドバイスがあればよろしくお願いします。
【Swift】一意のIDを作成したい時 NSUUID

# 使用用途
何かを一意に識別する時などに使う。
DBに保存するオブジェクトのプライマリーキーなど、値がユニークである必要がある時など。

# 使用方法

下記のような形で使うと定数idに16進数で32桁のIDが作成されます。

~~~ swift
let id = NSUUID().uuidString
~~~

ただ必ずユニークな値が保証されているわけではないようです。
しかし、確率としては340,282,366,920,938,463,463,374,607,431,768,211,456分の 1とかみたいなので、よっぽど大丈夫。(笑)


趣味開発でRealmを使用した際、こんなふうに使ってidを作成してました。

~~~ swift
class Plan: Object {
    @objc dynamic var id: String = NSUUID().uuidString
    @objc dynamic var title: String = ""
    @objc dynamic var content: String = ""
    @objc dynamic var date: Date = Date()
    @objc dynamic var createdAt: Date = Date()
    
    override static func primaryKey() -> String? {
        return "id"
    }
}
~~~

# 終わりに
素人なので参考までに。。。
他にいい方法がありましたら教えていただきたいです。


*参考資料*

https://developer.apple.com/documentation/foundation/nsuuid

https://www.sirochro.com/note/swift-generate-uuid/
[基礎]Gitコマンドについてまとめてみた①

#はじめに
実は共同開発は愚か、GithubDesktopを使用していたため、あまりコマンド操作になれてなかったり、リベース周りに慣れていなかったりするのでこちらにアウトプットしていきます。
入社までに完璧にするぜ！

見づらさはご了承ください

#基本的なコマンド

##ローカルリポジトリの新規作成

.gitディレクトリが作成される。

- 圧縮ファイル
- ツリーファイル
- コミットファイル
- インデックスファイル
- 設定ファイル

```:terminal
git init
```

##リモートリポジトリのコピーを作成

```:terminal
git clone リポジトリ名
```

##変更をステージに上げてからコミット

```:terminal
git add ファイル名
git add ディレクトリ名

git commit -m(-v) "コミットメッセージ" 
```

##差分を調べる

```:terminal
#git addする前の変更分

git diff
git diff ファイル名

#git add した後の変更分
git diff --staged
```

##変更履歴の確認

```:terminal
git log

git log --oneline #1行で表示する

git log -p index.html #ファイルの変更差分を表示する

git log -n コミット数　#表示数の制限
```

##ファイルの削除

```:terminal
#リモートもローカルでも消す場合
git rm ファイル名
git rm -r ディレクトリ名

#リモート側のみでローカルには残したい時
git rm --cached
```

##ファイルの移動を記録する

```:terminal
git mv 旧ファイル　新ファイル

#上記コマンドは以下をまとめたもの
mv 旧ファイル　新ファイル
git rm 旧ファイル
git add 新ファイル　
```

##リモートリポジトリを新規追加する

慣例的にoriginにすることが多いが、当然それ以外でもOK

```:terminal
git remote add origin https://github.com/~~~~
```

##プッシュする

```:terminal
git push リモート名　ブランチ

git push origin master 
```

##コマンドにエイリアスをつける

```:terminal

git config --global alias.ci commit
git config --global alias.st status
git config --global alias.br branch
```

#変更を元に戻すコマンド

##ワークツリーでファイルへの変更を取り消す

ブランチを切り替えるコマンドとよく似ているので混同しないように注意

```:terminal
git checkout --　ファイル名
git checkout -- ディレクトリ名

#全変更を取り消す魔法の言葉
git checkout -- . 
```

##ステージした変更を取り消す

git addした後にやっぱなし！をしたい時
ワークツリーには影響なし

```:terminal
git reset HEAD ファイル名
git reset HEAD ディレクトリ名

#ステージの全変更を消す
git reset HEAD 
```

##直前のコミットをやりなおす方法

ただし、リモートリポジトリにPushしたコミットはやり直し厳禁
```:terminal
git commit --amend
```

#Githubとあれこれするタイプのコマンド

##リモート表示

```:terminal
git remote

#対応するURLを表示
git remote -v
```

##リモートリポジトリを新規追加

```:terminal
git remote add リモート名　リモートURL

git remote add tutiral htpps://~~~~~
```

##リモートから情報を取得（フェッチ）

git fetch はリモートリポジトリからローカルリポジトリへ下ろすだけ
ワークツリー

```:terminal
git fetch リモート名
git fetch origin 
```

##リモートから情報を取得してマージする (プル)

```:terminal
git pull リモート名　ブランチ名

#上記コマンドは下記と同じ
git fetch origin master
git merge origin/master
```

##リモートの詳細

```:terminal
git remote show リモート名
git remote show origin
```

##リモートの変更

```:terminal
git remote rename 旧リモート名　新リモート名
```

##リモートの削除

```:terminal
git remote rm リモート名
```

#続き

まだまだリベースとかもやっていきま〜す！！↓
https://qiita.com/tochisuke221/items/ef3fc32ba904d23ed258
FFmpegインストール・使い方

#紹介
コマンドラインで利用できる動画編集ツール[FFmpeg](https://trac.ffmpeg.org/wiki/CompilationGuide)の紹介です。
今回は指定動画からサムネイル用に1フレームを書き出し方を見て見たいと思います。

**公式サイト**
https://ffmpeg.org/

#インストール
**macOS**
macOSの場合はHomeBrewで一発です。

```:ターミナル
$ brew install ffmpeg
```

**Windows**
下記ページを参考にインストールできます。
https://fukatsu.tech/windows-ffmpeg

まず、ダウンロード
https://github.com/BtbN/FFmpeg-Builds/releases
![スクリーンショット 2021-06-07 21.58.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/710589/4ab10f1c-8d81-c166-2d86-1baf26c33eb9.png)

解凍してbinフォルダのPATHをシステムの環境変数に追加します。


```:エラー画面
C:¥>ffmpeg -version
'ffmpeg' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。
```
↑
エラーが出たらシステムの環境変数PATHがまだ追加されていない可能性が高い。

#使い方
無事にインストールできたら使うだけ。

**・最初の1フレームを画像保存**

```:ターミナル
$ ffmpeg -i 動画のパス.mp4 -ss 1 -vframes 1 -f image2 生成画像パスとファイル名.jpg
```

**・最後の1フレームを画像保存**

```:ターミナル
$ ffmpeg -sseof -3 -i 動画のパス.mp4 -update 1 -q:v 1 生成画像パスとファイル名.jpg
```

#参考サイト
いろんな使い方があるにで紹介します。
https://qiita.com/cha84rakanal/items/e84fe4eb6fbe2ae13fd8
https://blog.katsubemakito.net/macos/ffmpeg
Nuxt.jsでGoogleBooksAPIを使用して検索結果を表示してみた

[1.はじめに](#1-はじめに)
[2.内容](#2-内容い)
[3.おわりに](#5-おわりに)

#1. はじめに
GoogleBooksAPIとaxiosを使用して書籍検索システムを作りました。
画像とタイトルを表示させたいと思います。
#2. 内容
###axiosでGoogleBooksAPIからデータを取得
GoogleBooksAPIから情報を取得するたにaxiosでリクエストを送ります。

```javascript
data () {
    return {
      books: [],
      keyword: '',
      url: 'https://www.googleapis.com/books/v1/volumes?q='
    }
  }
```
URLとユーザーが検索できるkeywordはdataで取り扱います。空のbook配列には取得した書籍データを格納します。

```template
 <v-text-field
    v-model="keyword"
  />
```
keywordはtemplateのテキストと結び助けておくことで検索機能として動くようにしました。

```javascript
 methods: {
    get () {
      this.$axios.$get(this.url + this.keyword + '&maxResults=15')
        .then(this.setBooks)
    },
 setBooks (res) { this.books = res.data.items }
```
keywordを入力した後に検索ボタンを押すとgetメソッドが発火して書籍情報を取得→bookに格納というように動いてくれます。

```vuejs
           <v-card
              v-for="book in books"
              :key="book.id"
              class="ma-0"
            >
              <v-row>
                <v-cols class="my-4 ml-7">
                  <img :src="volumeInfo.imageLinks.thumbnail">
                </v-cols>
                <v-cols>
                  <v-card-title>{{ book.volumeInfo.title }}</v-card-title>
                  <v-card-text>{{ book.volumeInfo.authors) }}</v-card-text>
                </v-cols>
              </v-row>
            </v-card>
```
items以降のデータを取り出してfor文で表示させたら完成です

#問題が見つかる
問題が見つかりました。タイトルや著者情報がない時や、サムネイル画像がないとundefinedでエラーになってしまいます。特に画像のない本が結構あったので対策は必須です。

###解決策①
**v-ifを使って条件分岐で情報を切り替える**
これは真っ先に思いついたのですが、だいぶ冗長になってしまうのと、そもそも公式で非推奨のやり方になってるのでやめました。

###解決策②
**methodsで条件分岐してくれるオブジェクトを作成**
スマートだしかっこいい気がする！ということでこちらを採用！

```javascript
title (valu) { return valu.volumeInfo.title ? valu.volumeInfo.title : 'No title' },
authors (valu) { return valu.volumeInfo.authors ? valu.volumeInfo.authors : 'No authors' },
image (valu) { return valu.volumeInfo.imageLinks ? valu.volumeInfo.imageLinks.thumbnail : noImage }
```
```vue
  <v-cols class="my-4 ml-7">
      <img :src="image(book)">
         </v-cols>
            <v-cols>
               <v-card-title>{{ title(book) }}</v-card-title>
                <v-card-text>{{ authors(book) }}</v-card-text>
            </v-cols>
```
引数をとって処理を分けることでかっこよくなりました。
こういうのってなんか気持ちいですよね〜
#5. おわりに
これでなんとか検索結果を表示させることはできました。初めての実装でしたが　オブジェクトを用意して条件分岐をするというのは非常に勉強になりました。

#####課題〜誰か助けて〜
今度はオブジェクトとfor文を使って表示させた画像、タイトル、著者をクリックするとすぐ下に表示されるという機能を追加したいです。やり方を考えているのですが、なかなか見つけられないのと、思いつかなくて困っています。誰か教えてください泣

①検索リスト表示　←今回のとこ
②ユーザークリック
③クリックした情報がすぐ下に表示される　　← ここがわからない
④表示されたものを保存する

という流れを想定しています。

とりあえず根気強く調べてみようと思います。ではまた！
【Rails】刃物のノコギリじゃないよ、gemのNokogiriだよ

# Nokogiriとは
Nokogiriを利用すると、RubyからXML/HTMLを簡単に生成することが出来ます。
これは、ドキュメントの読み取り、書き込み、変更、およびクエリを行うための、賢明で理解しやすい API を提供します。

# インストール方法
Gemfileに以下を記載し、`bundle install`する。

```
gem 'nokogiri'
```

## 使い方

```app/lib/html_builder.rb
module HtmlBuilder
  def markup(tag_name = nil, options = {})
    root = Nokogiri::HTML::DocumentFragment.parse("")
    Nokogiri::HTML::Builder.with(root) do |doc|
      if tag_name
        doc.method_missing(tag_name, options) do
          yield(doc)
        end
      else
        yield(doc)
      end
    end
    root.to_html.html_safe
  end
end
```

```ruby
def notes
  markup(:div, class: "notes") do |m|
    m.span "*", class: "mark"
    m.text "印の付いた項目は入力必須です。"
  end
end
```
【algorithm】再帰関数の基礎的な例

#はじめに
今回は、再帰関数を使った例をいくつか見ていきたいと思います。

#例

##aからbの合計値を求める
```C++
int sum_range(int a, int b) {
    if (a == b) {
        return a;
    }
    return sum_range(a, b-1) + b;
}
```
##配列の要素の合計値を求める

```C++
int array_sum_from_i(vector<int> &data, int i) {
    if (i == data.size()) {
        return 0;
    }
    int s = array_sum_from_i(data, i+1);
    return data.at(i) + s;
}

int array_sum(vector<int> &data) {
    return array_sum_from_i(data, 0);
}
```

##素数かどうかを判定する

```C++
bool has_divisor(int N, int i) {
    if (i == N) {
        return false;
    }
    if (N % i == 0) {
        return true;
    }
    return has_divisor(N, i+1);
}

bool is_prime(int N) {
    if (N == 1) {
        return false;
    }
    else if (N == 2) {
        return true;
    }
    else {
        return !has_divisor(N, 2);
    }
}
```

##相互再帰

```C++
bool is_even(int);
bool is_odd(int);
bool is_even(int n) {
    if (n == 0) {
        return true;
    }
    return is_odd(n-1);
}

bool is_odd(int n) {
    if (n == 0) {
        return false;
    }
    return is_even(n-1);
}
```

#おわりに
おわりです。
Eloquentって何ってなったからまとめてみた


##Eloquentとは
Eloquent ORMとはLaravelで実装されているデーターベース操作のための機能。
すべてのEloquentモデルは　```Illumination\Database\Eloquent\Model```を継承する。

##そもそもORMとは
ORM・・・Object-relational mapping

>オブジェクト関係マッピング（英: Object-relational mapping、O/RM、ORM）とは、データベースとオブジェクト指向プログラミング言語の間の非互換なデータを変換するプログラミング技法である。 オブジェクト関連マッピングとも呼ぶ。

Wikipediaより

- オブジェクト指向プログラミングとRDBとの考え方の違いを変換してつないでくれるもの。

     - 考え方の違いを「インピーダンス・ミスマッチ」 　という

- 本来RDBからの値はオブジェクト指向プログラミングとは互換性がないがそれを変換して使いやすくしてくれることになる。

とりあえず自分がわかる範囲でまとめました…。

###Laravelにおけるデータベース操作
①Eloquent ORM
②クエリビルダ

Eloquentを使用するにはuseするモデル名を宣言する必要がある。
クエリビルダを使用する場合には加えてDBファザードをuse宣言する必要がある。


##本題
###使用するサンプル
```Flight.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    //
}
```
###テーブルの定義
```Flight.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * モデルと関連しているテーブル
     *
     * @var string
     */
    protected $table = 'my_flights';
}
```
###主キー

- 主キーは```id```カラムであると想定している。

これをオーバーライドするにはprotectedの```primaryKey```プロパティを定義する。

###タイムスタンプ

 - データベース上にあるcreated_atカラムとupdated_atカラムを自動的に更新する。
  - 自動的に更新してほしくない場合は```$timestamps```を```false```にする。
  
 - タイムスタンプのフォーマットをカスタマイズするなら```$dataFormat```プロパティを設定する。
 - タイムスタンプを保存するカラム名をカスタマイズする必要があるなら、モデルに```CREATED_AT```と```UPDATED_AT```定数を設定する。 

##データベース接続
デフォルトでは.envに定義されているデータベースに接続されるが、それと異なる接続をしたいときは```$connection```プロパティを使用する。

##デフォルト属性値
あるモデルの属性にデフォルト値を指定したい場合は、```$attributes```プロバティを定義する。

##モデルの取得
各Eloquentモデルは対応するデータベースへ接続できたときクエリビルダとして使用できる。

###コレクション
複数の結果を取得する```all```や```get```は```Illuminate\Database\Eloquent\Collection```インスタンスを返す。

https://blog.capilano-fw.com/?p=727#all

多次元配列で返されるため、アロー演算子ではプロパティの取得ができない。
###単レコードの取得

- 単一レコードで取得した場合は```Model```オブジェクトで値を返す。

- アロー演算子で中身のプロパティの取得ができる。 

主キーで指定したモデル取得:```find```

```
$flight = App\Flight::find(1);
```
クエリ条件にマッチした最初のモデル取得:```first```

```
$flight = App\Flight::where('active', 1)->first();
```

クエリ条件にマッチした最初のモデル取得の短縮記法:```firstWhere```

```
$flight = App\Flight::firstWhere('active', 1);
```

##```fillable```と```guarded```の違い
両方とも入力値を反映したくないときに使う。
```fillble``` →　 指定したカラムのみ値が入力される。
```guarded``` →　指定したカラムには値が入力されない。

##おわりに
だいぶ駆け足でまとめたのでだいぶ中身が薄っぺらくなってしまいましたが、いままで何となく使っていたものが
ここまで奥深いとは思いませんでした。（正直何も疑問に思わずに手を動かしていた）
これをきっかけにまた詳しく学んでいきたいと感じました！

##参考
https://qiita.com/yoshitaro218/items/e5f92b6c01c902fb91ef

https://readouble.com/laravel/6.x/ja/eloquent.html

https://qiita.com/shosho/items/5ca6bdb880b130260586

https://qiita.com/gone0021/items/4b1b4555b9b8f2eca458
【Rails】簡単にRDSを使いたい

### 環境

ホスト：MacOS
ゲスト：CentOS6
Vagrant
MySQL

## Problem

https://qiita.com/Alice_ecilA/items/54b4624f0126c7eec5e5
↑こちらの続きです。
vagrantをコピーしたので、アプリケーション側とRDS側にしていきます。

## Solve

#### アプリケーションサーバ
```config/database.yml
development:
  <<: *default
  database: my_database
  username: apps
  password: this_is_password
  host: 192.168.33.11
```
アプリケーション側はdatabase.ymlにRDSの接続情報を追加してあげればOK。

#### RDS用

```sh
mysql -u root [-p] #パスワードがある場合-p
```

```sql
-- アプリケーションサーバからの接続を許可する
mysql> GRANT all ON *.* TO apps@'192.168.33.22' IDENTIFIED BY 'this_is_password';
mysql> FLUSH PRIVILEGES;

-- 先程のIPが登録されていれば接続できる状態
mysql> SELECT user,host FROM mysql.user;
+------------------+---------------+
| user             | host          |
+------------------+---------------+
| apps             | 192.168.33.22 |
| apps             | localhost     |
| root             | localhost     |
+------------------+---------------+
```

RDS側はmysqlに入り、アプリケーションサーバのIPアドレスを登録して接続を許可すればOK。

## まとめ

これでアプリケーションとRDSの通信ができるようになりました。
外部のDBを使いたい場合はこれが応用できると思います。
もしうまく行かないのであれば、RDS側のOSで外部との通信を許可しているか？(Firewall)
MySQLサーバの設定ファイル(mysqld.cnf)でIPアドレスの制限を解除しているか？確認してみましょう。
Tailwindcssに寄せたメモ

https://qiita.com/Takazudo/items/78ee15564bfefdea844c

を拝読し、自分だったらこのCSSフレームワークをどう扱うかについてのメモです。

# 結論

- クラス名でのスタイル指定はしない
- Tailwindcss の [apply ディレクティブ](https://tailwindcss.com/docs/functions-and-directives#apply) を用いる

# Tailwind の特徴

- CSS が適切に高級化されており、記述の手間が軽減
- bootstrap や material-ui と比べると、テーマ層がずっと薄いため、汎用的なレイアウトに使える


# Tailwindcss の選定

### CSS in JS

- Util な関数を作りたくなるが、自由度が高すぎて（特にデザイナーにとっては）保守性が下がりやすい
- 動的なスタイルを作る場合、devtool 等によるデバッグがしづらくなる

### クラス名にまつわるあれこれ

#### クラス名にスタイルを書く方法

- HTMLの可読性が下がる（役割が分かりづらい、検索しづらい）
- render 結果にクラス名フックがないと e2e テストとかデバッグはやりづらそう
- `@apply` ディレクティブを使うのが良さそう

#### scoped・CSS 単体ファイル

- BEM は命名のコストが高いので、CSS Modules などの scoped なクラス名を導入
- Next.js・Vue ではそんなにトラブル無く scoped が導入できた記憶
- そこそこ複雑なスタイルだと CSS は別ファイルのほうが楽（デザイナーも触る場合は特に）

### DSL

- Tailwind には便利な DSL があるが、規模が大きいといろんな記法が混在しそう
- ある程度チーム合意をとって使う機能を吟味・限定したほうが良さそう

# その他メモ

### `@apply` は意味のまとまりごとに改行したほうが良さそう

```scss
@apply text-base font-medium rounded-lg p-3 bg-rose-500 text-white;
```

よりは

```scss
@apply text-base font-medium;
@apply bg-rose-500 text-white;
@apply rounded-lg p-3;
```

ぐらいのまとまりで書いておいたほうが、見やすく後々編集も楽なのではないか


### 職種間の寄り添い

インターフェースとなりうる箇所

- [テーマ](https://tailwindcss.com/docs/theme)
- [スペーシング](https://tailwindcss.com/docs/customizing-spacing)
- [カラー](https://tailwindcss.com/docs/customizing-colors)

を双方理解し、これを用いてデザインし、カンプに反映しやり取り出来ると連携しやすさ抜群


### 誤解

- 最初に書いたように、テーマ層が他の UI フレームワークに比べてずっと薄いので、Tailwindcss トップページをみて、良いテイストだなと思って採用すると、あれを実現するまでには結構遠い道のりになる
- Material-ui = Bootstrap >> Bruma >>> Tailwindcss ぐらいのテーマ性の無さ、CSS の高級 DSL の側面が強そうなので、UI フレームワークという認識じゃないほうがいいんじゃないか感

# 参考

https://qiita.com/Takazudo/items/78ee15564bfefdea844c

https://zenn.dev/tsugu_maru_san/articles/f4d2a6dc114407
僕がエンジニアになるまでの話

Qiita初投稿です。
時々Twitterで質問されることがあるので記事にしてみました。
大学中退してほぼほぼずっとラーメン屋で働いてきた人が31才で独学でエンジニアになったお話です。
2019年の秋にラーメン屋を退職して、ニートしたり、アルバイトしたりしながら勉強してました。
2021年の1月からリモートでアルバイトとして
2月から正社員として働いています。
業務では主にDjangoやVue.jsを使っています。

1. エンジニアになるまでにやったこと(学習)
2. エンジニアになるまでにやったこと(就活)

こんな流れで書いていきます。
特別なことは特にしてないと思いますが、僕のこのスペックでもエンジニアになれたってことを記しておこうと思います。
どなたかのお役に立つかわかりませんが読んでいただけたら嬉しいです。

## エンジニアになるまでにやったこと(学習)

### 使った教材

主に

1. Progate
2. ドットインストール
3. PyQ
4. Udemy

を使って学習しました。
PythonやJSを勉強してPython好きだなって思って
主にDjangoの勉強を勉強しました。

他にはググって見つけたチュートリアルをやったりしました。

### 意識してやったこと

効率的でなくていいのでなるべくたくさんコードを書くようにしてました。

## エンジニアになるまでにやったこと(就活)

1. 求人に応募しまくる
2. Twitterで会社さんを募集

結果この2つ以外で仕事が決まりました。

独学初めて3ヶ月ほどで
知り合ったエンジニアの人がいて
色々お話させていただいただけでなく、めっちゃ学習のアドバイスをしてもらえて
この人と働ければいいなと思ったのが今でも印象的です。

この間に色々成果物を作ってました。

色々あって共同開発してもらえることになりそこからめちゃくちゃ成長出来ました。

一緒に働かせて欲しいといったらなんと

起業するつもりなんですけど一緒に働きませんかみたいな話になって
起業を10ヶ月くらい待ってエンジニアになりました。
長かった。。。

最近なんで自分を選んでくれたのかを質問聞いたら
成長速度を評価してもらえたようです。
成長速度と伸びしろっていうのはポイントなのかもしれないですね。

## 最後に

いろんな人の力をお借りしてエンジニアになることが出来ました。
求人に応募するだけが就活ではないんだということが大きな発見でした。

まだスタート地点にたったばかりなのでもっと勉強して精進していきます！
AzureのTimerTrigger Functionを手動実行した際の「Object reference not set to an instance of an object.」エラー原因と対応

# 事象
Azureで、TImerTriggerのFunctionを手動実行(Azureポータルの「コードとテスト」から実行)をすると下記のエラーが出力されます。

```
Object reference not set to an instance of an object.
```

# 原因
TimerTriggerFunctionは、デフォルトとしてタイマーオブジェクトを必須引数として指定しています。
しかし、このタイマーオブジェクトは、トリガーとなるタイマーから起動された場合のみしかFunctionに受け渡されず、手動実行した場合タイマーオブジェクトはFunctionに受け渡されません。
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-timer?tabs=csharp#manually-invoke-a-timer-trigger

上記仕様により、Functionが手動実行された場合、必須引数であるタイマーオブジェクトを参照できずエラーが発生してしまいます。

# 対策
## タイマーオブジェクトを任意引数とする。

修正前

```cs
        public async Task RunAsync(
            ~~
            TimerInfo timer,
        {
```

修正後

```cs
        public async Task RunAsync(
            ~~
            TimerInfo timer?,
        {
```


同じ事象で悩んでいる方の一助になれば幸いです。
他にも対策方法があれば教えていただきたいです！
Azureで、Functionsが失敗した時にポイズンキューが作成されない原因と対策

# 事象
Azureでは、キュートリガーのFunctionsが失敗した際、その失敗したキューを保持しておくためのポイズンキューが自動作成される仕様があります。
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-storage-queue-trigger?tabs=csharp#poison-messages

しかし、キュートリガーのFunctionが失敗ししても、ポイズンキューが作成されませんでした。

# 原因
キュー名の最大値オーバーが原因。

Azureのキュー名には下記の制約があります。
>キュー名は、文字または数字で始まり、文字、数字、またはダッシュ (-) 文字だけを使用できます。
キュー名の最初と最後の文字は、英数字にする必要があります。 ダッシュ (-) 文字は最初の文字にすることも最後の文字にすることもできません。 キュー名で、ダッシュ文字を連続して使用することはできません。
キュー名のすべての文字は、小文字にする必要があります。
キュー名の長さは 3 ～ 63 文字にする必要があります。
https://docs.microsoft.com/ja-jp/rest/api/storageservices/naming-queues-and-metadata

上記の63文字制限に引っかかったため、ポイズンキューの作成が失敗していました。


# 対策
キュー名を短くする。

同じ事象で悩んでいる方の一助になれば幸いです。
他にも対策があれば教えていただきたいです！
Gitで違うリポジトリのブランチを取り込みたい

# 結論

```
git -b ブランチ名 clone リポジトリのURL
```

```
cd プロジェクト名
```

```
rm -rf .git //前のリポジトリの.gitディレクトリを消去
```

```
git init
```

```
git branch -M main
```

```
git add .
```

```
git commit -m "最初のコミット"
```

```
git push -u origin main
```

これで違うリポジトリの好きなブランチをローカルに取り込んで、新しいプロジェクトとして管理できる。
ストアドプロシージャ作り方（SQL Server）

# ストアドプロシージャとは

DBを使用する際にDB側に設置できる関数のようなもの
**呼出し側のツール**でバリデーションやその他ビジネスルールを守るための処理などを書く必要がなくなり
複数のツールで利用する場合でも、言語関係なく同じ機能を呼出すことが可能になる
処理漏れやデータの不整合を防いだり、各プログラムで何度も同じ処理を書かなくて済む

## ストアドプロシージャの作成例
下記のような商品マスタと、店舗が扱っている商品を登録している店舗商品マスタがあった場合
商品をマスタから削除する際に、店舗で登録されている商品かをチェックし削除するストアドプロシージャを作成

**■ 商品マスタ**

|商品コード|商品名|単価|
|:-------:|:---:|:-:|
|001|りんご|150|
|002|バナナ|100|
|003|みかん|250|

**■ 店舗商品マスタ**

|店舗コード|商品コード|
|:-------:|:---:|
|A01|001|
|A01|002|
|A02|001|

**ストアドプロシージャの作成**

```sql
CREATE PROCEDURE ProductDelete
    @商品コード varchar(20),
    @ErrorMessage   NVARCHAR(100) OUT
AS
BEGIN
	-- 商品コードが店舗商品マスタにあった場合　エラーメッセージを返す
    IF EXISTS
        (SELECT *
           FROM 店舗商品マスタ
         　WHERE 商品コード = @商品コード)
		BEGIN
			SET @ErrorMessage = N'商品を使用している店舗があるので削除できません';
			Return;
		END
	ELSE
	-- 該当しなかった場合は削除を実行
		BEGIN
			DELETE
			  FROM 商品マスタ
			 WHERE 商品コード = @商品コード;
			   SET @Message = N'削除完了';
			   Return;
		END
END;
```


## VBAから呼び出し方（例）
　商品コード「001」を引数に渡し、削除するVBAコードを実行

```vb
' DBコネクションを作成
Dim CN As ADODB.Connection
Dim constr As String

Dim MYPROVIDERE = "Provider=SQLOLEDB;"
Dim MYSERVER = "Data Source=localhost;"   ' サーバー
Dim MYDATABASE = "Initial Catalog=Test;"  ' 接続するデータベース名
Dim USER = "User ID=sa;"                  ' SQL Server認証の場合のみ指定
Dim PSWD = "Password=12345;"              ' SQL Server認証の場合のみ指定

' DB接続
Set CN = New ADODB.Connection
CN.CursorLocation = 3 ' クライアントサイドカーソルに変更        
' SQL Server認証
constr = MYPROVIDERE & MYSERVER & MYDATABASE & USER & PSWD
CN.ConnectionString = constr
CN.Open
    
' コマンドの設定
Private CM As ADODB.Command
Set CM = New ADODB.Command
Set CM.ActiveConnection = CN

CM.CommandType = adCmdStoredProc ' ストアドプロシージャ用コマンド
CM.CommandText = "ProductDelete" ' プロシージャ名

' 引数がある場合は引数・戻り値がある場合は戻り値を受けるパラメータ
Dim objParam As ADODB.Parameter

' ひとつ目のパラメータ
Set objParam = CM.CreateParameter()
objParam.Name = "商品コード"       ' 引数の名前
objParam.Type = adChar            ' データ型（文字列）
objParam.Direction = adParamInput ' 引数を指定
objParam.Value = "001"         　 ' 引数の値

CM.Parameters.Append objParam ' パラメータ追加

' 戻り値のパラメータ
Set objParam = CM.CreateParameter()
objParam.Name = "Message"          ' 戻り値の名前（任意）
objParam.Type = adChar             ' データ型（文字列）
objParam.Direction = adParamOutput ' 戻り値を指定

CM.Parameters.Append objParam ' パラメータ追加
CM.Execute                    ' コマンド実行

Dim returnValue As String
returnValue = CM.Parameters("Message").Value　' 戻り値の文字列を代入
Debug.Print returnValue　　　　　　　　　　　   ' デバッグプリント

' DB接続解除
Set objParam = Nothing
Set CM = Nothing
Set CN = Nothing

```

**結果：**エラーメッセージを取得「商品を使用している店舗があるので削除できません」

上記プロシージャを使用することで、呼出し側で（今回はVBAだが言語関係なく）
店舗で商品が使用されているかを検索するプログラムを書かなくても、削除するプログラムのみ書くだけで済む
Microsoftから独立した元女子高生AI rinnaとcolabで対話する方法

# 概要

今回はMicrosoftが開発し、Microsoftから独立して会社になってしまった元女子高生AIチャットボット「りんな」の事前学習モデルがhuggingfaceに公開されていたので、さっそく試す。



# 対象読者

* 人工知能・機械学習・深層学習の概要は知っているという方
* 理論より実装を重視する方
* Pythonを触ったことがある方
#目次
[1.36本目-ライブラリのセットアップ](#1-36本目-ライブラリのセットアップ)
[2.37本目-事前学習モデルのロード](#2-37本目-事前学習モデルのロード)
[3.38本目-トークナイズ](#3-38本目-トークナイズ)
[4.39本目-推論](#4-39本目-推論)
[5.40本目-対話](#5-40本目-対話)
[6.参考文献](#6-参考文献)
[7.著者](#7-著者)
[8.参考動画](#8-参考動画)
[9.他のノックはこちら](#9-他のノックはこちら)

#1. 36本目 ライブラリのセットアップ

* 質問： Colabでrinna(rinna/japanese-gpt2-medium)と会話するために必要なモジュールをインストールせよ。

* 回答： huggingfaceのtransformersとsentencepieceが必要。ver.は結構大事なのでつけておくことを推奨する。

```Python
!pip install transformers==4.6.1
!pip install sentencepiece
```

#2. 37本目 事前学習モデルのロード 

* 質問： rinnaの事前学習モデル"rinna/japanese-gpt2-medium"をtokenizer, modelにロードせよ。

* 回答： AutoModelForCasualLMの方はAutoでもいいのだが、T5Tokenizerの方をAutoTokenizerにするとエラーがでる。
この微妙な差が大事。
 
```Python
from transformers import T5Tokenizer, AutoModelForCausalLM

tokenizer = T5Tokenizer.from_pretrained("rinna/japanese-gpt2-medium")
model = AutoModelWithLMHead.from_pretrained("rinna/japanese-gpt2-medium")
```

#3. 38本目 トークナイズ

* 質問： '新型コロナ収束。'を37本目のtokenizerでトークナイズせよ。

* 回答： tokenizer()に引数で渡すだけ。input_ids, attention_maskが返却される。

```Python
inputs = tokenizer('新型コロナ収束。')
inputs
```

結果
---
```Shell
{'input_ids': [9, 7127, 5049, 145, 14365, 8, 2], 'attention_mask': [1, 1, 1, 1, 1, 1, 1]}
```

#4. 39本目 推論

* 質問： 38本目でトークナイズしたテキストを入力に、37本目でロードしたrinna事前学習モデルで推論を行え。

* 回答： modelにはinput_idsのみをtorch.tensorでキャストして渡す。

```Python

import torch
outputs = model(torch.tensor(inputs['input_ids']))
print(outputs.keys())
print(type(outputs.logits))
print(type(outputs.past_key_values))
print(outputs.logits.shape)
print(outputs.past_key_values[0][0].shape)
```
結果
---
```Shell

odict_keys(['logits', 'past_key_values'])
<class 'torch.Tensor'>
<class 'tuple'>
torch.Size([7, 32000])
torch.Size([1, 16, 7, 64])
```
outputsはlogitsとpast_key_valuesをキーとして持っていることがわかる。
logitsには生成されたテキストのID（語彙32000個のうちのどれかを示すもの）の列が格納されている（7トークン）。
past_key_valuesはもう一度同じ計算をする際に、隠れ層のキャッシュを再利用し高速化を図る目的で保持されている。

https://huggingface.co/transformers/model_doc/gpt2.html



#5. 40本目 対話

* 質問： 39本目の推論結果を解釈し、りんなが発した言葉をテキスト化せよ。

* 回答： logits.argmax(0)で0軸の最大となる索引を返却できる。logits.argmax(-1)としているのは、軸が増えた場合には軸1を、一次元の場合は軸0のargmaxを取得するという意味である。

```Python

print(''.join([tokenizer.decode(logit.argmax(0).item()) for logit in outputs.logits]))

```

結果
---
```Shell
、インフルエンザナの装置pic
```

天才りんなに聞いてみると、新型コロナ収束の鍵は、インフルエンザナの装置picにありそうだ…
インフルエンザと新型コロナは両方かかってしまうこともあるそうだが、両方に効く一挙両得な治療法が見つかることを切に願う。

たくさん話しかけてみると、拙い日本語だが関連するテキストが返却されるのでぜひお試しください。


<a id="#reference"></a>
#11. 参考文献

- [Huggingface model hub](https://huggingface.co/models)

- [Huggingface GPT2](https://huggingface.co/transformers/model_doc/gpt2.html)


#12. 著者

ツイッターでPython/numpy/pandas/pytorch関連の有益なツイートを配信してます。

@keiji_dl

#13. 参考動画

- [直感！Pytorchで始める深層学習実装入門（実践編）](https://www.udemy.com/course/python_pytorch/)

- [7ステップで作るPython x Flask x Pytorch 人工知能Webアプリ開発入門](https://www.udemy.com/course/7step_python_vit/)
SOCといっても色々

# 概要
SOCといっても色々あるなと思い、メモ

# Security Operation Center
ネットワークやデバイスを監視し、サイバー攻撃の検出や分析、対応策のアドバイスを行う組織
余談だが、SOCはインシデントの検知に重点が置かれているが、他にもインシデントが発生した後の対応に重点をおいたCSIRT（Computer Security Incident Response Team）というものもあるらしい

# Service Organization Controls
サービス組織の統制をとること
標準化された基準に基づいた内部統制の状況を第三者からの評価を受け認定されるもの
https://dev.classmethod.jp/articles/soc2_overview/

# System-on-a-chip（SOC、SoC）
集積回路の1個のチップ上に、プロセッサコアをはじめ一般的なマイクロコントローラが持つような機能の他、応用目的の機能なども集積し、連携してシステムとして機能するよう設計されている、集積回路製品
https://ja.wikipedia.org/wiki/System-on-a-chip
※だから何だという話ではあるが、個人的にはこれが一番なじみがある
当たり前だけどエラーに向き合う心構え

※備忘録的に記述します。

RailsでもPythonでもそうですが、エラーが発生したときにやりがちなことが
「エラーの文言をそのままGoogle検索」
だと思うんですが、はっきり言ってこれは間違っている。

まず最初にやることはエラーの内容を理解して、どこが問題なのかを理解すること。

JavaScriptが読み込まない
Nomethodと出る
どんなエラーでも同じですが、
①どのようなエラーが発生しているのか
②何が原因なのか
ということをきちんと把握することが大事。

プログラミング初心者だと、ついエラーから逃げがちだけども、一番大事なことはここなのかと。

いろんな言語を経験しているわけではないので、全てではないですが、どの言語においても共通していることだと思います。

まずは真剣にエラーと向き合う。
どこでエラーが発生しているのか、原因となっている箇所は何なのか、どのようなエラー内容なのか、ということを正確に把握することが大事。

ということをすごく学びました。
【GAS】（シンプル）スプレッドシートから値取得⇒gasでHTMLメール送信（table形式）

###◆やること

1. スプレッドシートから値取得
1. gasでテーブル形式のhtmlにする
1. htmlメール送信

以下コード

---
###◆コード

```javascript:コード.js
function myFunction() {
  
  //値取得、二次元配列格納
  let vals = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getDataRange().getValues();
  
 
　//ここでforを使ってval⇒htmlのtable形式に

  //オプションでHTMLメール本文を設定する
  let mailText = "htmlを入れた変数";
  let options = {"htmlBody":mailText,};

  //GmailApp.sendEmail(メールアドレス,メール表題,本文（htmlメール送信できないとき表示）,htmlメールを設定（{htmlBody：html本文})
  GmailApp.sendEmail("メールアドレス","メール表題", mailText , options);

}
```

上記のforの中身を書くとしたら、下記の感じです。

```javascript:コード.js
let tbl = "<table border='1' style='border-collapse: collapse;'><tr><th>ヘッダー1</th><th>ヘッダー2</th><th>ヘッダー3</th><th>ヘッダー4</th><th>ヘッダー25</th><th>ヘッダー6</th></tr>";
//ここでは最後</table>でしめません。forでtrを追加して、一番最後に<table>を追加します。

  let newtd ="";

  vals.forEach(x=>{    //二次元配列valsから一つずつ配列取り出し
    for(let elnum in x){    //取り出した一次元配列から一つずつ要素取り出し
      newtd += "<td>"+x[elnum]+"</td>";
    } 
    let tr = "<tr>"+newtd+"</tr>"
    tbl += tr; tr
    newtd="";
  })

  let mailText = tbl+"</table>"//ここでtableを閉じます。
```
自分は、あとは送信先アドレス一覧を別シートで用意して、
アドレス一覧取得、`GmailApp.sendEmail("メールアドレス","件名", "本文" ,);`
のアドレスに入れました。

あと、引っ張ってくる一覧をクエリ関数で作成、GASで日付書き換えて関数で内容変更⇒トリガーで定時に集計メールが届くようにしました。

###◆完成品（ほぼモザイクですいません）
|![スライド1.GIF](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1563301/6b71f79a-b3a6-d7fa-b88a-31053c0f0af1.gif)|
|:-:|


###◆その他

#####スプシにメアド書いて、それに送る

下記が参考になります。
[【GAS】スプレッドシートからメールを送信する方法](https://notes.sharesl.net/articles/1919/)



<br>



#####ほかのhtmlファイルからテンプレート持ってくる

下記が参考になります。
[Google Apps ScriptでGmailからHTMLメールを送信する方法](https://tonari-it.com/gas-gmail-html-email/)

####感想
これぞ自動化という感じです。
デプロイをする時（２回目以降）の注意点

デプロイをする時（２回目以降）の注意点
 
やることは以下の２つだけ。
 
（１）git push heroku master
（２）heroku run rails db:migrate
 
（１）の後に以下の文章がシークレットウィンドウ上に表示されることがある。
 
We're sorry, but something went wrong.
 
エラー原因として考えられるのは（２）をやり忘れている場合。
 
その場合はターミナルで
heroku run rails db:migrate
を行えばエラーは解消される。
DockerでReact+Typescriptの開発環境を構築する

# はじめに
よく見る内容ではありますが、メンバーに配布できるようになってなくて困ったことがあってので改めて自分でやってみました。

# 環境
```
~ % docker --version
Docker version 20.10.2, build 2291f61
~ % docker-compose --version
docker-compose version 1.27.4, build 40524192
```

# 手順
1. node.jsのイメージをもとにコンテナ作成
1. Reactのプロジェクト作成
1. より使いやすく

## 1.node.jsのイメージをもとにコンテナ作成
[node.jsのイメージ](https://hub.docker.com/_/node)をもとにコンテナを作成する

[ docker-compose.yml ]

```
version: '3'
services:
  app:
    image: node:16.3.0-alpine3.11
    volumes:
      - .:/app
    tty: true
```

#### 動作確認
```
~ % docker-compose exec app sh
/ # node
Welcome to Node.js v16.3.0.
Type ".help" for more information.
> 
```
nodeコマンドが使用できることが確認できます

```
/ # ls
app    bin    dev    etc    home   lib    media  mnt    opt    proc   root   run    sbin   srv    sys    tmp    usr    var
/ # cd app
/app # ls
docker-compose.yml
```
ファイルがコンテナ内にマウントされていることも確認できました。

## 2.Reactのプロジェクト作成
先ほど作成したコンテナ内でReactのプロジェクトを作成します。

```
~ % docker-compose exec app sh
/ # cd app
/app # npx create-react-app sample_app --template typescript
```

パッケージのインストールが走ってsample_appディレクトリが作られます。

```
.
├── docker-compose.yml
└── sample_app
```

Reactの初期ページを参照するにはポートの設定が必要です。

[ docker-compose.yml ]

```
version: '3'
services:
  app:
    image: node:16.3.0-alpine3.11
    volumes:
      - .:/app
    ports: # 追加
      - "8080:3000" 
    tty: true
```
yarn startで立ち上がるサーバーのポートは3000がデフォルトなので、それをもとに設定。http://localhost:8080/ でReactの初期ページが参照できます。

## 3. より使いやすく

[ docker-compose.yml ]

```
version: '3'
services:
  app:
    image: node:16.3.0-alpine3.11
    volumes: # ①変更
      - ./sample_app:/app
    ports:
      - "8080:3000"
    working_dir: /app # ②追加
    command: sh -c "yarn install && yarn start" # ③追加
```

#### ① マウントするディレクトリの変更
sample_app内以外のファイルをコンテナ内でいじる必要がないからね。

#### ② working_dirの変更
コンテナ入った時に一発でsample_app配下のファイルに行ける方が楽だよね。

#### ③ コマンドの追加
docker立ち上げのタイミングで

```
yarn install && yarn start
```
のコマンドが走るようになる。`docker-compose up`するだけでサーバーが立ち上がるからコンテナ入って `yarn start`叩く必要がないので楽。`yarn install`はメンバーと環境が合わせられるように。

# おわりに
ここまでご拝読いただきありがとうございました。少しでも役に立ちますように。
YARN+TypeScript+ts-mochaにnycを加えてカバレッジ情報追加する方法

# 背景
ts-nodeをなんかする方法ばっかりだったので、単純にnyc追加だけでイケた事を書き残す為に記載してます。
今回の方法だと、package.jsonや追加設定ファイルにごちゃごちゃ書く必要がありません。
testに必要になってくるものって大体同じなので、設定ファイルを別途用意するほどコテコテにする意味がわからないので、シンプルにしました。

# やったこと
- nycの追加
- package.json書き換え

## nycの追加
```shell
$ yarn add nyc --dev
```

## package.json書き換え
```diff
     "scripts": {
-        "test": "ts-mocha --paths -p ./tsconfig.json test/**/*.test.ts --timeout 10000"
+        "test": "nyc --reporter=lcov --reporter=text --extension .ts ts-mocha --paths -p ./tsconfig.json test/**/*.test.ts --timeout 10000"
     },
```
オプションなどは環境の構築の仕方で変わってくるので、読み替えてください。
公式Readmeに従い、lcovを指定する事でoutputにhtmlを追加することができました。

# output
コマンド実行時標準出力
全体 - パッケージ単位 - ファイル単位という感じに字下げして表現されてます。
複数階層のパッケージはスラッシュ区切りで同じ段落になりました。

```
------------------------------------------|---------|----------|---------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------
File                                      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s                                                                                                                                        
------------------------------------------|---------|----------|---------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------
All files                                 |    20.1 |     7.95 |   17.89 |    19.9 |                                                                                                                                                          
 hogefuga                                 |   68.68 |    62.59 |   68.26 |   67.91 |                                                                                                                                                          
  hello.ts                                |   94.62 |    59.42 |     100 |   94.51 | 170-171,187,244-245 
 hogefuga/errors                          |      20 |        0 |       0 |      20 |                                                                                                                                                          
  HelloError.ts                           |      20 |        0 |       0 |      20 | 3-13 
...
...
...
Done in 92.52s.
```

**HTML**
summaryをクリック → ファイル一覧 → ファイル単位詳細でコード単位で閲覧可能です。
![bbb.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139745/a94eaec9-1886-a9b6-2f8f-0b9560516810.gif)


# おまけ
CircleCIを使っているので、package.jsonのscriptに設定したコマンドをtestコマンドとして実行していますが、今回の対応ではこれまでの出力にプラスしてカバレッジ情報も付随されるようになりました。
jestにしようとtryしてみましたが、実行速度が非常に遅くなったり、timeout設定が面倒だったりしたので、一旦諦めてます。
コーディングについて～実装編①～

前回の命名編に引き続き、実装面に関しても勉強した内容を備忘録としてまとめます。

# はじめに
本記事はJavaScriptをベースに作成しています。

# 変数の定義
基本的にconstを使いましょう。
過去に書いたコードを振り返ってみると、letではなくconstでよかった変数がいくつもあります。

constでは処理できない場合にletを使いましょう。
簡単にはイテレータ変数やフラグなどです。

varはどうしても必要な場合のみ使いましょう。
ちなみにですが、今のところどうしても必要になったことはありません。

```Javascript
// OK
const test = "test";
// 状況に応じてOK
let test = "test";
// 基本的にNG
var test = "test";
```

# 変数の使い回し
これはNGです、新たに変数を定義しましょう。
使い回してはいけない理由として

* 変数の生存期間が長くなる
* 影響範囲が広くなる
* デバッグが難しくなる

など様々です。
constで定義することで防止することができます。

# foreachは極力使わない
私のプロジェクトではコーディング規約がないながらもfor文よりもforeachを使うという暗黙のルールがあります。
それ故に例えば以下のようなコードが量産されていました。

```Javascript
const tests = [];
testList.foreach(test => {
  if (test === "test") {
    tests.push(test);
  }
});
```

この場合はfilterを使いましょう。

```Javascript
const tests = testList.filter(test => test === "test");
```

他にも以下の辺りを積極的に使いましょう。
案外foreachを使わずに実装できるのでそうすべきです。

* find
* map
* reduce

# ネスト
浅いほど良いです。
深ければ深いほど読みにくく、よいことがないです。
深くなるようであれば一部を関数として切り出すなどの対応が必要です。

# 条件式は整理する
長いor複雑な条件式は関数として切り出しましょう。

```Javascript
// NG
if (fileName !== null && filePath !== null && fileType !== null && fileSize !== null) {
  // 処理
}

// OK
function existFile() {
  return fileName !== null && filePath !== null && fileType !== null && fileSize !== null;
}

if (existFile()) {
  // 処理
}
```

# 行数が少ない=正義ではない
少ない行数で書けたとしても、それがきれいで読みやすいかは別問題です。
書き方や程度によりますが、三項演算子はif文に変換、メソッドチェーンは程よいところで変数に代入した方がよいと思います。
読みにくいだけではなくデバッグもやりにくくなります。

# 即return
returnは早ければ早いほど良いです。
無駄な処理が動くことがない上に追いやすくなります。

```JavaScript
// NG
function test(String string) {
  // 処理
  if (string === null) {
    return;
  }
}

// OK
function test(String string) {
  if (string === null) {
    return;
  }
  // 処理 
}
```

# コメントはとても大切
積極的に残すようにしましょう。
ただし、読めばわかるコードに残すのはNGです。

```Javascript
// NG：読めばわかるので不要
// testListの中で30未満のデータを抽出
const tests = testList.filter(test => test < 30);
```

以下例のように、読めばわかる実装ではありますが処理に意図がある場合は残す必要があります。
本当は変数名などで表すのがベストです。

```Javascript
// OK
// 赤点の人を抽出
const tests = testList.filter(test => test < 30);
```

# 最後に
どなたかの参考になりましたら幸いです。

# 参考
[リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック](https://www.amazon.co.jp/%E3%83%AA%E3%83%BC%E3%83%80%E3%83%96%E3%83%AB%E3%82%B3%E3%83%BC%E3%83%89-%E2%80%95%E3%82%88%E3%82%8A%E8%89%AF%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%9B%B8%E3%81%8F%E3%81%9F%E3%82%81%E3%81%AE%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%81%A7%E5%AE%9F%E8%B7%B5%E7%9A%84%E3%81%AA%E3%83%86%E3%82%AF%E3%83%8B%E3%83%83%E3%82%AF-Theory-practice-Boswell/dp/4873115655)
[JavaScript で forEach を使うのは最終手段](https://qiita.com/diescake/items/70d9b0cbd4e3d5cc6fce)
[変数の使い回しはなぜよくないのか](https://funcallfunc.com/programming/2016/02/29/why-mutable-is-bad.html)
突然「このサイトにアクセスできません」と表示された際の対応

お名前.comにてドメイン取得していたサイトが突然表示されなくなったので、その際の対処法です。

結論としては、メール認証が上手くできていないことが原因でした。

![スクリーンショット 2021-06-07 20.20.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1340120/ed321990-d3cc-8347-fab3-ba58466a3489.png)

突然のことだったので何が原因か分からなかったのですが、IPアドレスではサイト表示ができたのでドメイン関係であると推測できました。

まずはお名前.comでのDNS状態を確認します。
トップページから、ログイン→利用ドメイン一覧→情報ダウンロードにて確認します。
![スクリーンショット 2021-06-07 20.25.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1340120/3467fc47-b537-c9ec-1a02-92263bef53f2.png)

すると現在、利用制限されていることがわかりました。
![スクリーンショット 2021-06-07 20.27.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1340120/9bee5ee1-205a-33ba-dd2b-7379c728f502.png)


この場合、メール認証する必要があるので、登録しているメールアドレスに届いているメールを探してください。
以下のタイトルのメールが届いているかと思うので、URLをクリックして認証させる必要があります。
![スクリーンショット 2021-06-07 20.22.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1340120/49fdba3b-e506-e341-0bd4-44720e32296e.png)

これをクリックした後に完了のメールが届いているはずなので、確認しておいてください。
![スクリーンショット 2021-06-07 20.29.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1340120/ff84031e-a096-785f-7362-63dc5fa0ab11.png)

再度お名前.comから利用制限の状態を確認してみてください。
![スクリーンショット 2021-06-07 20.31.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1340120/e513c844-ce7a-a4a8-c4ea-259b7666d7aa.png)

完了通知にも記載がありますが、インターネット全体に反映されるまで最大72時間程度かかる可能性があるみたいなので、その点は注意が必要です。
Discord用の今から遊びたい人を募集するBOTを作った

「今から遊べる人いませんかー？」
「これまだ募集してます？？」
「ああ、もう人数集まっちゃったんですよ・・・」

Discordでよく見かけるやり取りですよね。
こんなやり取りをせずにスムーズに今から遊ぶ人を募集するBOTを作りました。

## その名もロボちょすBOT！

こんな感じで募集状態を管理してくれます。

![overview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458229/2eac946e-0de5-d238-0fe7-5dbf22883985.png)

## 導入方法

1. 以下のリンクより自分のDiscordサーバーにロボちょすを招待します。
    
    https://discord.com/api/oauth2/authorize?client_id=815139175837335582&permissions=8&scope=bot
1. 募集機能を使いたいテキストチャンネルで以下のコマンドを入力して下さい。

    ```
    .rt enable
    ```
    
    ![rt_enable.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458229/011dd078-848d-53b6-13b7-03ad3165b1f0.png)

**これで導入は完了です！**

## 使い方

### 募集

募集を開始するときは「募集内容@募集人数」と書いて下さい。

![open.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458229/767ff119-a71f-b9ae-7e7a-5fdb0d8f6130.png)

時間を含めると、時間指定で募集を開始できます。

![open_with_time.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458229/cc97bb6f-1303-0b26-2985-0053942a61bb.png)

### 参加

募集に参加したいときは、募集の左側に表示されている番号に続けて「参加」と書いて下さい。

![join.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458229/f314d1c5-6e28-4659-5d5b-1b05e93fe8b8.png)

### 参加キャンセル

参加した募集から抜けたいときは、募集の左側に表示されている番号に続けて「キャンセル」と書いて下さい。

![cancel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458229/e32e1087-8cb6-f88e-8408-5b37daab98cd.png)

### 募集の終了

募集は人数が集まると、参加者に通知を行い自動で終了します。

![close_full.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458229/a40bb1b3-a5f2-a07c-e1cd-85d9d654f721.png)

ただし、時間指定募集のときは、集まっても募集は終了しません。

![reserve_full.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458229/ec1acec8-fa42-8031-0ea1-7b27b322e6e0.png)

指定時間になったときに人数が集まっていると、参加者に通知を行い自動で終了します。

![close_reserved.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458229/91103925-dbc0-ad64-f2d4-4d19129760c2.png)

手動で募集を終了するときは、募集の左側に表示されている番号に続けて「しめ」と書いて下さい。

![close.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458229/e2189b28-e57c-4093-84e9-6fec1aba19ad.png)

### 募集の再開

間違えて終了してしまった募集を再開するときは「復活」と書いて下さい。

![resume.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458229/2d0fff15-3d0b-90b4-b071-7c3f522f677c.png)

募集期限が過ぎてない最後の募集が再開されます。

任意の募集を再開することはできません。

## Q&A

### 不具合もしくは要望があります。

ロボちょすサポート用Discordサーバーでご報告お願いします。

https://discord.gg/G86a3WkrVn

### 複数のテキストチャンネルで募集機能を使えますか？

はい、利用できます。

チェンネル毎に募集状態を管理していますので、各テキストチャンネルでロボちょすを有効にすることで1つのサーバーで複数の募集状態を管理できます。

### Twitter連携機能はありますか？

あります。が、負荷が高いのと設定が大変なので一般開放していません。

### ロボちょすBOTを自分で実行したい！コードを見てみたい！

こちらにあります。ご自由にどうぞ！
https://github.com/utyosu/robotyosu-go
mixhostにVSCodeでSSH接続できなくなった

##前提
SSH接続の設定は完了しており、今までは問題なく接続できました。


##現象
レンタルサーバのmixhostに、VSCodeでSSH接続ができなくなりました。
ターミナルからも接続できなくなり、ターミナルには以下のエラーが表示されました。


```terminal
-bash: fork: retry: リソースが一時的に利用できません
-bash: fork: retry: 子プロセスがありません
```
上記を繰り返し。

##原因
不具合が起きているプロセスがあったため、アクセスできなかった様子。

##対応
ターミナルからは、時間を置いたらアクセスできるようになったので、サーバにSSH接続した状態で、下記のコマンドを実行。

```terminal
$ ps -ef
```
不具合が起きているプロセスを

```terminal
$ kill 12345
```
※12345は削除したいPIDの値を入力

上記の操作後、VSCodeからmixhostにSSH接続できるようになりました。
また、サーバ上に「core.12345」のようなファイルができていたので、削除しました。


##参照
[VSCodeでmixhostのstyle.cssを更新する【WordPress】](https://rabirgo.net/vscode-insiders-remote/)
[【ps・kill】実行中のプロセス表示と強制終了](https://qiita.com/shuntaro_tamura/items/4016868bda604baeac3c)
[[7-6.]coreファイルから情報が漏れる]
(https://www.ipa.go.jp/security/awareness/vendor/programmingv1/b07_06.html)
Pythonのアップデート時、ターミナルを再起動するとPythonのバージョンが戻ってしまう

MacでPythonのバージョンを2系(2.7.10)から3系(3.9.5)にアップデートしていたのですが、ターミナルを終了して再度開くとバージョンが戻る現象が発生しました。
解消してみると、くだらないオチだったのですが、経験があまりない方々は割と詰まってしまいそうな気がしましたので、メモとして記載(共有)しようと思います。


## 想定読者
MacでPythonのアップデートを行われている方を想定致します。
バージョンが変わらないという方だけでなく、アップデートを行われている方の参考にもなるかと思います。
ちなみに私はアップデートを行う際、以下の記事を参考にさせて頂きました。

1. [MacのPythonを2系から3系にアップデートする](https://qiita.com/Ajyarimochi/items/ff40e57d082dd171e761)
2.  [MacのPython2系からPython3系に3分で切り替える方法](https://nontitle.xyz/archives/135) 

補足: シェルの環境設定(.bash_profileへの書き込み)は2の記事を参考にしました。

## 再現するまで
参考にした記事の通り、

1. Homebrewでpyenvをインストール
2. pyenvの設定のため、.bash_profileを修正
3. pyenvを使用して最新(対応時は3.9.5)のPythonをインストール
4. `pyenv global 3.9.5` コマンドをターミナルで実行してPythonのバージョン切り替え

以上を行いました。
`pyenv versions` を実行すると、

```
$ pyenv versions
  system
* 3.9.5 (set by $HOME/.pyenv/version)
```
pyenvのPythonのバージョンの切り替えは問題なし。
`python --version` でPythonのバージョンも確認すると、

```
$ python --version
Python 3.9.5
```
こちらもOK。
しかし、ターミナルを終了して再度起動し、 `python --version` すると、

```
$ python --version
Python 2.7.10
```
元のバージョンに戻りました。(pyenv versionsの方は更新が正常に反映されていました)


## 原因
私のPCのシェルがbashではなくzshを使っていたことが原因でした。(`echo $SHELL` を実行すると「/bin/zsh」と表示されました。)
どうやら、シェルの環境設定(「再現するまで」の2の手順)の修正対象ファイルを誤っていたようです。


## 対策
参考にした記事で.bash_profileに追記されていた下記の設定を.zshrcに追記しました。

```
export PATH="$HOME/.pyenv/shims:$PATH"
```

これで、ターミナルを再起動してもpythonのバージョンは元に戻らなくなりました。
シェルの環境設定の際は、まず、 `echo $SHELL` をターミナルで実行して、自分のPCのシェルが何を使っているか確認しないといけませんね...

## 最後に
「何かをする時は、まず己自身を知りなさい。」

そんな声が聞こえた気がしました。

良い教訓でした、反省。。。
GitHub Actions ことはじめ

# はじめに
GitHub でCI/CD を実現できる GitHub Actions があるので試してみる。


# ワークフローの作成
とりあえず適当なレポジトリを作成し、まずはデフォルトの設定を利用し、実行結果に「Hello World」を出してみる。

メニューにある Actions というメニューがあるので、これをクリックし、「set up a workflow yourself」をクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304109/aa6e8704-3c92-ec49-293e-19be54eadb5a.png)

自動で以下の設定ができる。(yml 形式)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304109/6f137c46-a088-7979-7fbd-905d061a35b9.png)

左の「Start Commit」をクリックし commit する。
手っ取り早く動作させるために、 master に commit しておく

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304109/3fc25f31-9c71-56d6-5204-05665c4dc1ab.png)

そうすると (レポジトリ名)/.github/workflow/(github Actions のワークフロー.yml) というファイルができる。 


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304109/65b1f52e-9588-9ace-298c-9e0ae6184001.png)

# 実行

サンプルでは master ブランチに commit されると自動でワークフローが実行されるようになっているので、勝手に動作している。

ここでは、ワークフローを選択して実行させる方法です。

メニューの「Actions」を選択してワークフローの一覧を表示。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304109/608d6439-c070-71e8-d3c0-e6fffb42ec72.png)

 yml 形式の [name] で設定した名前 (Hello World) で左メニュー一覧に表示されているので、それをクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304109/a29a313d-4aec-0381-4156-8e848d7373a9.png)

[Run workflow] を選択し [Run warkflow] をクリックすると実行される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304109/8b308625-30ef-4514-d2f2-3f06846c161c.png)

# 結果

実行すると、以下のように結果が表示される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304109/925a6030-bb6f-160a-8a81-660de427214e.png)

実行したワークフローをクリックすると、以下のような詳細画面が表示されて、「Run a one-line script」と表示されているところに実行した結果が表示されている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304109/091fedf0-fc58-9525-fdc2-c3c0e19d56b0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304109/72a7d58d-e4f1-f228-2dff-f55ea1c42d42.png)
【jQuery】モーダルの作成方法

#完成形
* SCSSを使用
* jQueryを使用

<p class="codepen" data-height="444" data-theme-id="dark" data-default-tab="html,result" data-user="c-koch0514" data-slug-hash="MWpXJmm" style="height: 444px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="MWpXJmm">
  <span>See the Pen <a href="https://codepen.io/c-koch0514/pen/MWpXJmm">
  MWpXJmm</a> by c-koch0514 (<a href="https://codepen.io/c-koch0514">@c-koch0514</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

#HTML
```html:html
<!-------------------  modal ------------------------->
<button id="modal-btn">modelを開く</button>
<div class="modal">
  <div class="modal-bg modal-close"></div>
  <div class="modal-content">
    <h1>モーダルタイトル</h1>
    <p>モーダルテキストモーダルテキストモーダルテキストモーダルテキストモーダルテキストモーダルテキストモーダルテキストモーダルテキストモーダルテキストモーダルテキストモーダルテキスト</p>

    <button class="modal-close">閉じる</button>
  </div>
</div>
<!-------------------  end of modal ------------------>
```

#SCSS
```scss:scss
/***********************************************************************/
/**********                modalの設定                       *************/
/***********************************************************************/
#modal-btn {
  background-color: #000000;
  border-radius: 10px;
  font-size:15px;
  color: #fff;
  width: 130px;
  height: 50px;
}
.modal {
  display: none;
  height: 100%;
  position: fixed;
  top: 0;
  width: 100%;
  top: 0;
  left: 0;
  z-index: 1;

  .modal-bg {
    background: rgba(0, 0, 0, 0.6);
    height: 100vh;
    width: 100%;
  }
  .modal-content{
    width: 300px;
    height: 200px;
    background: #fff;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    border-radius: 5px;
    padding: 10px 30px;
    
    .modal-close{
      position: absolute;
      top: 0;
      right: 0;
    }
  }
}
/*********************  ena of modal    **********************************/
/***********************************************************************/

```
#jQuery
```js:jQuery
$(function(){  

  /***************** modal モーダル **********************/
  // ウィンドウを開く
  $('#modal-btn').on('click', function() {
       $('.modal').fadeIn( 300 );
       return false;
  });

  // ウィンドウを閉じる
  $( '.modal-close' ).on( 'click', function() {
  $( '.modal' ).fadeOut( 300 );
  return false;
  });
  /*********************************************************/

});
```