OmniAICreator/Qiita-1.07M huggingface dataset:
Julia 1.5.2 は パッケージのインストール後ビルド不要？

## 経緯
Jupyter NotebookでJuliaを扱えるようにしたくて、以前参照した [julia v1.1から始めるJupyter Notebook](https://qiita.com/doorei/items/91a52a31f917b9d7bb84) をベースに環境構築しようとしたところ、`add IJulia` の段階でビルドまで終了した。

## 環境
- OS: Windows 10 64bit (1909)
- Julia: 1.5.2 
    - chocolatey 0.10.15 でインストール choco先輩はいいぞ

## 手順
前述の参照元ページの手順ベースで

1. juliaがインストール済みの前提
1. juliaのコンソールを起動(緑字のプロンプト)
1. ]キーを押してパッケージモードへ(青字のプロンプトになる)
1. add IJuliaを実行(Cloning～となり、しばらく時間がかかる) 
 - 以下ログの通り、この時点でビルドまで完了する
1. build IJuliaを実行(Building～となり、しばらく時間がかかる)
 - 不要（コマンド叩いてもビルド済なのですぐ終わる）
1. バックスペースでパッケージモードを抜ける(緑字のプロンプト)
1. using IJuliaを実行(Precompilingされる)
1. notebook(detached=true)を実行
1. 「install Jupyter via Conda, y/n? [y]:」と聞かれるのでyを入力
1. 関連パッケージがダウンロードとインストールされる。(結構時間がかかるので気長に待つ)
1. Jupyterが起動する！「New」のプルダウンにはJulia 1.1.0とpython 3が出てくる

でいけるようになったっぽいです。

### `add julia` のログ
```
(@v1.5) pkg> add IJulia
 Installing known registries into `C:\Users\kanchu\.julia`
      Added registry `General` to `C:\Users\kanchu\.julia\registries\General`
  Resolving package versions...
  Installed Artifacts ─────── v1.3.0
  Installed MbedTLS_jll ───── v2.16.8+1
  Installed ZMQ ───────────── v1.2.1
  Installed Parsers ───────── v1.0.11
  Installed IJulia ────────── v1.22.0
  Installed JLLWrappers ───── v1.1.3
  Installed MbedTLS ───────── v1.0.3
  Installed JSON ──────────── v0.21.1
  Installed VersionParsing ── v1.2.0
  Installed SoftGlobalScope ─ v1.1.0
  Installed Conda ─────────── v1.5.0
  Installed ZeroMQ_jll ────── v4.3.2+5
Updating `C:\Users\kanchu\.julia\environments\v1.5\Project.toml`
  [7073ff75] + IJulia v1.22.0
Updating `C:\Users\kanchu\.julia\environments\v1.5\Manifest.toml`
  [56f22d72] + Artifacts v1.3.0
  [8f4d0f93] + Conda v1.5.0
  [7073ff75] + IJulia v1.22.0
  [692b3bcd] + JLLWrappers v1.1.3
  [682c06a0] + JSON v0.21.1
  [739be429] + MbedTLS v1.0.3
  [c8ffd9c3] + MbedTLS_jll v2.16.8+1
  [69de0a69] + Parsers v1.0.11
  [b85f4697] + SoftGlobalScope v1.1.0
  [81def892] + VersionParsing v1.2.0
  [c2297ded] + ZMQ v1.2.1
  [8f1865be] + ZeroMQ_jll v4.3.2+5
  [2a0f44e3] + Base64
  [ade2ca70] + Dates
  [8ba89e20] + Distributed
  [7b1f6079] + FileWatching
  [b77e0a4c] + InteractiveUtils
  [76f85450] + LibGit2
  [8f399da3] + Libdl
  [56ddb016] + Logging
  [d6f4376e] + Markdown
  [a63ad114] + Mmap
  [44cfe95a] + Pkg
  [de0858da] + Printf
  [3fa0cd96] + REPL
  [9a3f8284] + Random
  [ea8e919c] + SHA
  [9e88b42a] + Serialization
  [6462fe0b] + Sockets
  [8dfed614] + Test
  [cf7118a7] + UUIDs
  [4ec0a83e] + Unicode
   Building Conda ─→ `C:\Users\kanchu\.julia\packages\Conda\x5ml4\deps\build.log`
   Building IJulia → `C:\Users\kanchu\.julia\packages\IJulia\a1SNk\deps\build.log`
```

## 結論
まだドキュメントとか全然見てなしIJuliaしか確認できてないけどどっかで不要になったんですかね。触ろうと思って全然触れてなくてバージョン更新追えてないので改めてちゃんと使っていきたいです。



## 追記
### 2020年11月10日
記事記載後に気づきましたが、 [julia v1.5から始めるJupyter Notebook](https://qiita.com/doorei/items/c0916f0866bfc2859c2f) の記事的には1.5の時点ではビルド必要っぽい。
Ubuntuの自動更新を停止

## 動機

自動更新に伴う再起動で動かしていたプロセスが死んだので…

## 方法

Ubuntu20.04に入っていた`unattended-upgrades`を使用。どうやらこれは18.04あたりからプリインストールらしい。
`--priority`には優先度`{low, medium, high}`を設定。今回は`low`のものだけ自動更新を切る。

```bash
sudo dpkg-reconfigure --priority=low unattended-upgrades
```

「いいえ」を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278919/174c348a-b7a3-806c-2cc1-45b34fcffb5a.png)
猿が管理するElastic BeanStalk

#猿が管理するElastic BeanStalk

ぶっちゃけブラウザ上で一回書いててBackSpace押したら記事が全部消えてやる気が無くなる病が発生中

なんで加筆するけどこんなんをとりあえずはっつけておく

##前提
- ElasticBeanStalk上で複数のApplicationを管理している
- また、その環境内に複数Environmentセットを運用している
- 運用しているEnvironmentは下記の通り
	- DEVELOP : DEV :: x-dev-stage-[XXX] という名称のApplication
	- DEMO : DEMO :: stage-[XXX] という名称のApplication
	- STAGING : STG :: stage-[XXX] という名称のApplication
	- PRODUCTION : PROD :: stage-[XXX] という名称のApplication

### 作文例
```
#!/bin/bash

base_dir="/home/<fuge>/Components"

case "${1}" in
  "prod" | "production" |"PROD" ) 
        STAGE="PROD" ;;
  "demo" | "DEMO" )
        STAGE="DEMO" ;;
  "stg" | "STG" | "staging" )
        STAGE="STG" ;;
  "dev" | "DEV" )
        STAGE="DEV" ;;
  "" ) 
        PS3="What Enviroment do you deploy? >"
        echo ${PS3}
        ans1="production"
        ans2="demo"
        ans3="staging"
        ans4="develop"
       
       select ANS in "$ans1" "$ans2" "$ans3" "$ans4"
       do
         if [ -z "$ANS" ]; then
           continue
         else
           break
         fi
       done
      if [ ${REPLY} == "1" ];then
         STAGE="PROD"
      elif [ ${REPLY} == "2" ];then
         STAGE="DEMO"
      elif [ ${REPLY} == "3" ];then
         STAGE="STG"
      elif [ ${REPLY} == "4" ];then
         STAGE="DEV"
      fi

     echo You selected $REPLY\) $ANS ;;

esac

if [ $STAGE = "DEV" ]; then
　app_ary=( x-dev-stage-1 x-dev-stage-2 x-dev-stage-3 x-dev-stage-4 x-stage-n )
elif [ $STAGE = "STG" -o $STAGE = "DEMO" -o $STAGE = "PROD" ]; then
　app_ary=( stage-1 stage-2 stage-3 stage-4 stage-5 )
fi


declare -a env_ary=()

if [ $STAGE = "DEV" -o $STAGE = "STG" ]; then
all_env=( \
  ENV_1='なんか値_A1' \
  ENV_2='なんか値_A2' \
  ENV_3='なんか値_A3' \
  ENV_4='なんか値_A4' \
  ENV_5='なんか値_A5' \
)

elif [ $STAGE = "DEMO" -o $STAGE = "PROD" ]; then
all_env=( \
  ENV_1='なんか値_B1' \
  ENV_2='なんか値_B2' \
  ENV_3='なんか値_B3' \
  ENV_4='なんか値_B4' \
  ENV_5='なんか値_B5' \
)
fi

for ((i = 0; i < ${#app_ary[@]}; i++)) {
    echo "### Start start ENV VALUE ###"
    cd ${base_dir}/${app_ary[$i]}
    pwd

  if [ $STAGE = "STG" -o $STAGE = "DEMO" -o $STAGE = "PROD" ]; then
     TARGET_NAME=`eb list | grep ${STAGE}-`
     TARGET_NAME=${TARGET_NAME#\*}
     ENV_OPTION="-e ${TARGET_NAME}"
  else
     TARGET_NAME=""
     ENV_OPTION=""
  fi
    echo "eb setenv ${all_env[@]} ${TARGET_NAME}"
    eb setenv ${all_env[@]} ${ENV_OPTION}
    cd -
    echo "#### Finish !! ###"
}

```

これで複数のapplication環境　またその環境内に含まれる複数のEnvironmentに対して一気に環境変数をセットできる
環境変数部分（なんか値_XX）とかは増減させるなり外部ファイル化しておけば幸せ
Flutterでipaファイルを作成する

##はじめに
DeployGate用にIPAファイルをさっと作りたかったのですが、これが一番わかりやすかったので、メモ。

##環境
- Mac
- Android Studio 4.1

##参考

[How to create .ipa file for testing using Runner.app?
](https://stackoverflow.com/a/56666092)

##手順
1. ビルドする 
コマンドの実行（```flutter build ios --release/debug```）
もしくは、メニューから _Build > Flutter > Build iOS_


2. __Payload__フォルダーを作成する
3. ビルドされたAppファイルを__Payload__フォルダーに移動する
4. __Payload__フォルダーを圧縮する（ZIP）
5. 作成された__Payload.zip__を__Payload.ipa__に変更する
[Ruby]includes?メソッドを使って配列内の要素を調べる

__配列の中に特定の文字列が含まれていたら、切り出して別の処理をしたい。__

## includes?メソッド
include?メソッドは指定した要素が、配列中に含まれているかを判定するメソッド

```
array = ["foo", "bar"]
puts array.include?("bar")
#=> true
puts array.include?("hoge")
#=> false

```

## 問題例
配列内に特定の文字が入っていたら「true」、それ以外の文字であれば「false」と返すメソッドを作る。
<br>
ここでは特定の文字は`1,2,3`の数字とする。
コードを書いていく。

```
def array123(nums)
  if nums.include?(1) && nums.include?(2) && nums.include?(3)
    puts "True"
  else
    puts "False"
  end
end
```

今回呼び出すのは`array123`のメソッドとし、`nums`を仮引数にしておき、実引数を受け取る準備はOK。

```
def array123(nums)
```
<br>
if条件分岐を用いて1,2,3のそれぞれが含まれていたら以下の処理をしてねとしてあげる。
論理演算子`&&`（〜との意味）や`||`（もしくはの意味）などを用いる。

```
if nums.include?(1) && nums.include?(2) && nums.include?(3)
```

trueのときにさせたい処理があれば`if~else`の間に記述、
falseのときにさせたい処理があれば`else~end`の間に記述する。
<br>
■参考リファレンス
* https://docs.ruby-lang.org/ja/latest/method/Array/i/include=3f.html
【Dr.Sum Datalizer】明細の項目並び順とソートさせたい項目順が一致しない場合

★2021/07/30追記
[朗報！朗報！Datalizer5.5からはソート順を指定できます！](https://qiita.com/ratsbane666/items/334f1a69e96a0b25c979#%E8%A7%A3%E6%B1%BA%E6%B3%95)

##明細項目
・領収書番号
・お客様番号

##この明細で実現したいこと
お客様番号ごとに並べたときに、複数の領収書がある場合がある。
その場合、最新の領収書を上に出したい。

| 領収書番号 | お客様番号 | 
|:-:|:-:|
|0005  | 1  |  
|0001  | 1  | 
|0003  | 2  |  
|0002  | 2  | 

##項目を並べたい順
左から、
(1)領収書番号
(2)お客様番号

| 領収書番号 | お客様番号 | 
|:-:|:-:|


##やりたいソート順
(1)お客様番号（昇順）
(2)領収書番号（降順）

しかし、お客様番号より前に（明細表示したときに左に）領収書番号があるため、
領収書番号にソート（降順）設定すると、最初に効くソートが「領収書番号」になって
「領収書番号」（降順）で並んじゃう。

**現実**

| 領収書番号 | お客様番号 | 
|:-:|:-:|
|0005  | 1  |  
|0003  | 2  | 
|0002  | 2  |  
|0001  | 1  | 

**理想**

| 領収書番号 | お客様番号 | 
|:-:|:-:|
|0005  | 1  |  
|0001  | 1  | 
|0003  | 2  |  
|0002  | 2  | 


##解決法
★2021/07/30追記
<font color="Red">朗報！朗報！Datalizer5.5からはソート順を指定できます！</font>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278265/22278ccd-9e8e-73d0-7afc-7777c7108bc1.png)

以下、Ver.5.5より古いバージョンの話です。
**ソートしたい項目を明細の左側（表示したときに左側）に持っていく以外、ない。**
明細表でのソート仕様は以下

(a)レイアウトの配置順
(b)非表示項目はソート無効

例えば前述の例でいうと、
お客様番号を新たに明細表の先頭に加えソートを設定しても、非表示では無効になる。


#ウイングアークのユーザコミュニティ「nest」
私も参加しています。多くの有益な情報があり、交流があります。
世の中が変わり、社外活動の重要性がより増していると考えております。
社外で自分の価値を計れるものさしを持とう。

https://www.wingarc.com/wug-nest/

以上
roman numerals



# お題

アラビア数字(arabic numerals)を受け取って，ローマ数字(roman numerals)を返すmethodを書きなさい[^pine]．


# ローマ数字で使われる文字

| arabic numerals | roman numerals |
|----------------:|:---------------|
| 1               | I              |
| 5               | V              |
| 10              | X              |
| 50              | L              |
| 100             | C              |
| 500             | D              |
| 1000            | M              |


# 例

| arabic numerals | roman numerals  |
|----------------:|:----------------|
| 1               | I               |
| 2               | II              |
| 4               | IV              |
| 5               | V               |
| 6               | VI              |
| 9               | IX              |
| 10              | X               |
| 11              | XI              |
| 14              | XIV             |
| 15              | XV              |
| 16              | XVI = X + V + I |
| 19              | XIX             |
| 38              | XXXVIII         |
| 42              | XLII            |
| 49              | XLIX            |
| 51              | LI              |
| 97              | XCVII           |
| 99              | XCIX            |
| 439             | CDXXXIX         |
| 483             | CDLXXXIII       |
| 499             | CDXCIX          |
| 732             | DCCXXXII        |
| 961             | CMLXI           |
| 999             | CMXCIX          |
| 1999            |                 |


# 発展

整数はInteger classです．[hello class](https://qiita.com/daddygongon/items/969ad5112878f6dab844)を参照して，Integer classを拡張して，

    999.to_roman #=> CMXCIX

と返すようにしなさい．


# 参照文献

[^pine]: "初めてのプログラミング", Chris Pine (著), 西山 伸 (翻訳),オライリー・ジャパン (2006/7/24).



------
 - **source** ~/git_hub/ruby_docs/chart_style_ruby/ex_roman_numerals.org
エクセル列の数値→アルファベット変換

# エクセルの列番号を数値からもとめます。
自分用のメモです。
用途は色々あると思います。
セルのxとyを数値でやると直感的にわかりにくいので嫌だなという時とかに使います。
.Netで利用できるExcelCreator とか VBReportとかで使っています。

``` vb:vb.net
Dim n2a = Function(num As Integer)
              Dim en As String() = {"", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
              Dim a As String = en(Math.Floor(num / 26))
              Dim b As String = en(num Mod 26)
              Return a & b
          End Function
Dim hoge = n2a(1) 'A
```
忙しい人のためのAWS「IAM」

##はじめに

自分のアウトプットがてら、さくさくとAWSの各種サービスについてまとめていくシリーズです。
今回はIAMについて取り上げます。

##IAMとは

Identity and Access Managementの略称。結論、**ユーザー管理**をしてくれる、もしくは自分でするためのサービスです。

いちばん初めにAWSにサインアップしたときのアカウントを**ルートユーザー**と呼びます。
このユーザーは本当に何でもできる神のような存在なので、普段使いはしないようにすることが推奨されています。

そこで、**IAMユーザー**というものを神によって創造し、普段の操作はそのアカウントを使うことで、変なことをしないようにできます。つまり、安全にAWS操作を実施するための認証や認可の仕組みを作れます。

##主要トピック

**ユーザー**、**グループ**、**ポリシー**、**ロール**の4つがあります。

ポリシーとは、このIAMユーザーは○○と△△のサービスにアクセスできます、などのルールのことです。ルートユーザーはポリシーもクソもないのでまったく別で考えます。何といっても神なので。

つまり、IAMユーザー、IAMグループとは、IAMポリシーに基づいてAWSを利用できるユーザーだということになります。

念のため、ユーザーとグループの違いについても書きます。

まずAさん、Bさんがいたとします。この2人は別々のIAMユーザーですが、会社で同じ部署に所属しています。ルートユーザーからしてみれば、役割が同じAさんとBさんそれぞれに同じIAMポリシーを適用するのは非常に面倒です。

そこで、グループという考え方を採用します。たとえば、「人事部」というグループを作成し、ポリシーを適用します。

その中にAさんとBさんを入れてあげることで、それぞれにまとめてポリシーを適用できるということです。

最後にロールですが、これは先ほどまでのユーザーではなく「AWSの各種サービスにポリシーを適用する」というイメージです。EC2からS3にアクセスできるようにするとか。

##まとめ
IAMとは、ユーザー管理の仕組みを作れるサービスである。

ルートユーザーは**神**であり、扱いに注意しなければならない。

ポリシーが適用されたユーザーをIAMユーザーと呼び、普段はIAMユーザーで操作する。

ロールと呼ばれる、AWSのサービス自体にポリシーを適用する仕組みも存在する。
ipynbファイルをダブルクリックで開く（Mac、Anaconda仮想環境）


.ipynbファイルをMacでダブルクリックで開けるようにした際のメモ。
下記リンク先の通り、Automatorでjupyterlabを起動するアプリを作成してipynb拡張子を開くデフォルトアプリケーションに登録すればよいのだが、
[HOW TO OPEN JUPYTER NOTEBOOKS WITH A DOUBLE CLICK (MAC OS)](https://samedwardes.com/post/2020-01-31-open-ipynb-with-double-click/)
anacondaの仮想環境で開きたい場合はそのままでは使えない(base環境でjupyterlabが開いてしまう)ので微細な変更を加えた。上記リンク先の説明が丁寧なので、こちらでは変更点のみ簡潔に記載する。

1. Automator.appを開く
1. 新規作成→アプリケーション
1. 「シェルスクリプトを実行」アクションを追加
1. 入力の引き渡し方法を"引数として"に変更（ダブルクリックしたファイルのパスを取ってくるため）
2. 実行するスクリプトを以下のように設定する

```{shell}
variable="'$1'"
the_script='tell application "terminal" to do script "source activate my_env && jupyter lab '
osascript -e "${the_script}${variable}\""
```

リンク元との変更点は、スクリプト内に`source activate my_env &&`を追記している。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549192/b7b9cdd9-2fd8-7112-158a-7d7a486848d8.png)

6. 作成したアプリケーションを保存する。
7. ipynbファイルを右クリック→"情報を見る"→"このアプリケーションで開く"で作成したアプリケーションを割り当てる。

参考
[Linuxコマンドを連続して使うには](https://qiita.com/egawa_kun/items/714394609eef6be8e0bf)

関連記事　Windowsの場合
[ipynbファイルをダブルクリックで開く(Windows)](https://qiita.com/k_maki/items/c97c3c5202a913273c57)
SQLのUPDATEでカラムの内容を移動させる

# 1つのカラムに複数の情報が混在していた

articlesテーブルのmediaカラムに、画像のパスやyoutubeのリンク情報が混在していたので、youtubeカラムを追加して、youtubeのリンク情報だけ移せないか試してみました。

```
// 変更前

|id | media                 | youtube |
|:-:|:---------------------:|:-------:|
| 1 |{"img":"//s3-ap-J***"} |NULL     |
| 2 |{"youtube":"NnH*****"} |NULL     |
| 3 |{"img":"//s3-ap-I***"} |NULL     |


// 変更後

|id |media                  |youtube                |
|:-:|:---------------------:|:---------------------:|
| 1 |{"img":"//s3-ap-J***"} |NULL                   |
| 2 |NULL                   |{"youtube":"NnH*****"} |
| 3 |{"img":"//s3-ap-I***"} |NULL                   |

```

## 要件

1. mediaカラムの内、"youtube"の文字列があるセルをyoutubeカラムにコピー
2. mediaカラムの内、"youtube"の文字列があるセルをNULLに書き換える

## 成功したSQL文

```sql
UPDATE articles A SET A.youtube = A.media, A.media = null WHERE A.media LIKE '%youtube%'
```


## おわり
SET句で同一カラムの変更（情報のコピーとNULLへの書き換え）を同時に書いてますが、順番通りに実行されたようで一安心です。
ただ、今回は件数が少なかっただけで、何万件ものレコードの書き換えがあった場合にどうなるかはわからないです( ˘ω˘ )。
TypeScriptで、dynamoで複数更新処理にてrollback

## dynamoにおけるrollbackについて
dynamoでのrollbackはあんまり自由にはできない。ロールバックは更新内容が ConditionCheck を満たさない場合にのみできるようで、DynamoDB と無関係の処理結果に応じてトランザクション内の処理をロールバックする、といったことはできない。みたいな決まりがある。

が、直接dynamoに関係する処理結果に応じてトランザクションできるので、その方法

## 方法
いろいろググったらtransactWriteItemsを使った方法が出てきたが、typescriptを使った例が出てこなかったのと、インタフェースを用いて更新するデータを配列によって自由に設定できるようにしました。
また、今使ってるaws-sdkのバージョンの影響なのか、transactWriteItemsは使えずtransactWriteなら使えたのでそちらを使う。

```typescript:anime-suko.ts

const hogeList = ["hoge-123","fuga-456"]//ここは本来何かの処理結果に応じたデータ

  interface TransactItemsInterface {
    Update: {
      TableName: string
      Key: {
        hogeID: string
      }
      UpdateExpression: string
    }
  }
  const transactItemsList: TransactItemsInterface[] = []

  await Promise.all(
    hogeList.map(async (value) => {
      const transactItems = {
        Update: {
          TableName: 'hogeTable',
          Key: {
            hogeID: value,
          },
          UpdateExpression: 'Remove hogeDate',
        },
      }
      transactItemsList.push(transactItems)
    })
  )
  try {
    await documentClient
      .transactWrite({
        TransactItems: transactItemsList,
      })
      .promise()
  } catch (err) {
     console.log(err)
  }
}
```


## 感想
マジ、dynamoのメリットってなんなん。。。(困惑)
MySQL先輩、おっすおっす
javascriptで「今から○時間限定タイムセール」のカウントダウンタイマーを作る

特定のページにアクセスしたときに、アクセスからn時間以内に次のアクションを起こしてもらうためのカウントダウンタイマーをjavascriptで作ってみました。

試しに72時間限定キャンペーンと言う感じで、残り72時間からスタートするカウントダウンタイマーを作りました。

##HTML

```HTML
<div id="js-timer"></div>
```
HTMLはこれだけ。innerHTMLで中身を入れていきます。

##javascriipt

72時間を秒に換算しておく。本当はここも計算でやるといいのかもしれませんが。
`settime`の値を変えることで残り時間を変更することができます。

```javascript
var settime = 259200; //72時間
var timer = document.getElementById('js-timer');
var h = 0;
var m = 0;
var s = 0;

//カウント開始
setInterval('countdown()',1000);

var countdown = function(){  
    settime--;
    h = Math.floor(settime / 3600);
    m = Math.floor(settime / 60) % 60;
    s = (settime % 60) % 60;
    timer.innerHTML = '残り' + h + '時間' + m + '分' + s + '秒';
 };

```

* `settime`の数値を1減らし、
* `settime`の数値をそれぞれ`h`（時間）、`m`（分）、`s`（秒）に変換し
* `timer`に代入する
* 上記の処理を1秒おきに繰り返す

という単純な作りです。

##実装結果

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="js,result" data-user="nagomi-753" data-slug-hash="LYZgWmx" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="カウントダウンタイマー">
  <span>See the Pen <a href="https://codepen.io/nagomi-753/pen/LYZgWmx">
  カウントダウンタイマー</a> by nagomi-753 (<a href="https://codepen.io/nagomi-753">@nagomi-753</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

cookieの制御などと合わせると良い感じになるのではないでしょうか〜
ただこういうカウントダウンタイマーって、キャンペーンとかセールとかでユーザーのCVを上げるための装飾であることが多いので、あんまり厳密に作らないことのほうが多い。

今回はフォームへの申込み完了後のサンクスページにて、更に申し込みを増やすための施策として実装しました。
クイズとかに利用するのもありですね。
auth0でログイン後WebAuth.checkSession()から常に'login required'を要求される

ライブラリは**auth0-js**を利用しています。

## エラーが起こる箇所
```js
      webAuth.checkSession({}, (err, authResult) => {
        if (err) {
          reject(err);
        } else {
          this.localLogin(authResult);
          resolve(authResult);
        }
      });   
```


## コンソールに返ってくる内容
```
{
code: login_required,
description: Login required,
error: login_required,
error_description: Login required,
original: {
error: login_required,
error_description: Login required
}
```

## 解決方法
**サードパーティのcookiesの利用を可能に**する。
（私の場合テスト環境はBraveでした。ライオンをクリックしてアドブロックをオフにしましょう！）


## 参考記事
- https://community.auth0.com/t/checksession-always-returns-login-required-after-login/33972
[Ruby] sliceメソッドを使って文字列を切り出す 

__文字列から特定の箇所だけ切り出したい。そんな時に__

## sliceメソッド
 sliceメソッドを用いることで、配列や文字列から指定した要素を取り出すことができる。

```
# 配列を作成します
array = [0,1,2,3,4,5,6]

# 配列から引数で指定した要素をsliceします
ele1 = array.slice(1)
puts ele1
#=> 1

# 配列番号1から4つ分の要素をsliceします
ele2 = array.slice(1,4)
puts ele2
#=> 1 2 3 4

# 配列はもとのままです
puts array 
#=> [0,1,2,3,4,5,6]  
```
### 問題例
任意の文字列から最後の２文字を出力するメソッドを作る。
```出力例：
extra_end('Hello') → 'lo'
extra_end('abcde') → 'de'
```

ここでは呼び出すメソッドは`extra_end`にします。
<br>
それではコードを書いていきます。

```
def extra_end(str)
  char_num = str.length
  right2 = str.slice(char_num - 2, 2)
  puts right2
end
```

まずextra_endの仮引数を`str`とし、実引数を受け取る準備をしてあげます。
`char_num`は`str`の文字数を取得するため、lengthメソッドを用いて定義します。
<br>
今回の問題は”最後の２文字を取得する”なので、sliceメソッドを用いて、`char_num`の-2、つまり後ろから数えて二文字分遡った後に、2とする事で、そこから二文字分を取得します。
<br>
たとえば、extra_end('Hello')でメソッドを呼び出した場合、char_num = 5となり、right2 = str.slice(3,2)になります。
slice(3,2)は配列番号（インデックス）3つ目から数えて2つ分の要素を切り取ります。今回の場合、切り取られた結果loが残り、right2 = loとなります。
<br>

■ 参考リファレンス
* https://docs.ruby-lang.org/ja/latest/method/String/i/slice=21.html
Azure SQLの行レベルセキュリティをロールで実装する

## はじめに

2020/11時点の情報です。

 [参考](https://docs.microsoft.com/ja-jp/sql/relational-databases/security/row-level-security?view=sql-server-ver15)

上記のサンプルコードがユーザ単位での実装で使い勝手が悪そうなので、ちょっと改変したコードを放流します。
さっくり使ったのでもっと美しい実装があるかも？

## 手順概要

2つのADユーザ(全てのデータ閲覧可能、)を利用して、検証します。

- 管理者（adminuser）・・・Azure SQLの管理者・Azure SQL上のデータは全て閲覧可能
- 利用者（readuser）・・・Azure SQL上のデータは自分のロール(sales1)のデータのみ閲覧可能

手順は以下の流れ
1. Azure SQLの準備
2. セキュリティポリシー設定


### 1. Azure SQLの準備

適当なDBを作成します。
[クイック スタート:Azure SQL Database の単一データベースを作成する](https://docs.microsoft.com/ja-jp/azure/azure-sql/database/single-database-create-quickstart?tabs=azure-portal)

AD管理者を設定します。  
[Azure AD 管理者をプロビジョニングする (SQL Database)](https://docs.microsoft.com/ja-jp/azure/azure-sql/database/authentication-aad-configure?tabs=azure-powershell#provision-azure-ad-admin-sql-database)


### 2. セキュリティポリシー設定

AD管理者でログインして、以下を実施(masterではなく、DBに対して実行)

```sql

--利用者をDBにアクセスできるようにする
CREATE USER [readuser@xxx.onmicrosoft.com] FROM EXTERNAL PROVIDER
GO
--ロールに作成、利用者を追加
CREATE ROLE Sales1 AUTHORIZATION [dbo]
GO
EXEC sp_addrolemember 'Sales1' ,'readuser@xxx.onmicrosoft.com';  

--テスト用テーブル作成

CREATE TABLE Sales  
    (  
    OrderID int,  
    SalesRep sysname,  
    Product varchar(10),  
    Qty int  
    );  

INSERT INTO Sales VALUES (1, 'Sales1', 'Valve', 5);
INSERT INTO Sales VALUES (2, 'Sales1', 'Wheel', 2);
INSERT INTO Sales VALUES (3, 'Sales1', 'Valve', 4);
INSERT INTO Sales VALUES (4, 'Sales2', 'Bracket', 2);
INSERT INTO Sales VALUES (5, 'Sales2', 'Wheel', 5);
INSERT INTO Sales VALUES (6, 'Sales2', 'Seat', 5);
-- 6件が表示
SELECT * FROM Sales;

-- ロールに権限付与
GRANT SELECT ON Sales TO Sales1


-- セキュリティポリシーの作成
CREATE SCHEMA Security;  
GO  
 
-- サンプルクエリを改変して、ロールをチェックするように
CREATE FUNCTION Security.fn_securitypredicate(@SalesRep AS sysname)  
    RETURNS TABLE  
WITH SCHEMABINDING  
AS  
    RETURN 
	SELECT 
		1
	AS fn_securitypredicate_result
	where 1=IIF(ORIGINAL_LOGIN( ) = 'adminuser@xxx.onmicrosoft.com',1,ISNULL(IS_ROLEMEMBER(@SalesRep , ORIGINAL_LOGIN()),0))
 ; 

-- テーブルに適用
CREATE SECURITY POLICY SalesFilter  
ADD FILTER PREDICATE Security.fn_securitypredicate(SalesRep)
ON dbo.Sales  
WITH (STATE = ON);  

-- セキュリティポリシーへアクセス権を付与
GRANT SELECT ON security.fn_securitypredicate TO [Sales1];  


```

readuserでログインして結果確認
pythonでのグラフ描画に困っている人へ

python でグラフを書いてみようと matplotlib をインストールしてみたものの、 

「ImportError: DLL load failed while importing ft2font: 指定されたモジュールが見つかりません。」

と注意を受けて、グラフが出力されなかった。

ワイの実行環境：
windows10
Python 3.8.6
（以下pip freezeで出力）
certifi==2020.6.20
cycler==0.10.0
kiwisolver==1.2.0
matplotlib==3.3.2
numpy==1.19.1
pandas==1.1.4
Pillow==7.2.0
pyparsing==2.4.7
python-dateutil==2.8.1
pytz==2020.4
six==1.15.0


僕の場合、matplotlib のバージョンを１つ下のやつにダウングレードすることで解決できた。具体的なコマンドは、Anaconda Prompt(anaconda3)上で

```
pip uninstall matplotlib 
pip install matplotlib== 3.2.2
```

とした。
エラーメッセージの中に出てきた「ft2font」については、謎のままである。
iOSでパラメータ付きのPUSH通知を受け取る

この記事の前提として、既にPUSH通知は届く状態とします。

> PUSH通知の実装に関する参考資料：
> [iOS で Firebase Cloud Messaging クライアント アプリを設定する](https://firebase.google.com/docs/cloud-messaging/ios/client)

初期設定では、アプリが起動している場合はPUSH通知のバナーは表示されません。
次の didReceiveRemoteNotification に値が届きます。

```swift

class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        // 省略...

        Messaging.messaging().delegate = self

        // 省略...
}

extension AppDelegate: MessagingDelegate {

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        print(userInfo)
    }

}
```

ただ UNUserNotificationCenter を繋いだ場合は上記の didReceiveRemoteNotification は呼ばれなくなり、下記のfuncが呼ばれるようになりました。
また completionHandler に返す値により、アプリが全面にあってもPUSH通知のバナーが表示されるようになります。

アプリ起動時も起動していないときも、didReceiveはタップした場合に呼ばれました。
PUSH通知をタップする処理があるケースでは didReceiveRemoteNotification は利用しないかもしれないですね。

```swift
extension AppDelegate : UNUserNotificationCenterDelegate {
    
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        let userInfo = notification.request.content.userInfo

        print(userInfo)
        
        if #available(iOS 14.0, *) {
            completionHandler([[.banner, .list, .sound]])
        } else {
            completionHandler([[.alert, .sound]])
        }
        
        // NOTE: push通知を表示したくない場合はこちら
        // completionHandler([])
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo

        // 起動してない時に楽にuserInfoを確認するためにアラートで表示
        if let rootViewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController {
            let alertController = UIAlertController(title: "userInfo", message: userInfo.description, preferredStyle: .alert)
            let okAction = UIAlertAction(title: "ＯＫ", style: .default, handler: nil)
            alertController.addAction(okAction)
            rootViewController.present(alertController, animated: true, completion: nil)
        }
                
        completionHandler()
    }
    
}
```

## 参考文献

- [Open app in specific view when push notification is tapped (iOS 13+)
](https://fluffy.es/open-app-in-specific-view-when-push-notification-is-tapped-ios-13/)
- [iOS 14からUNNotificationPresentationOptionsの「.alert」が「.banner」と「.list」に分かれた
](https://qiita.com/uhooi/items/7e7f0293a83b57eaf72f)
Route 53を使用し、お名前.comで取得した独自ドメインでWebページを表示させる

前提として
お名前.comで独自ドメインを取得済み、
IPアドレスでWebページが表示されていることとします。
やり方はこちらをご覧ください

[**お名前.comを使い、独自ドメイン取得**](https://qiita.com/tksh8/items/ab3748bcb01316461abe)


[**AWSでのデプロイ手順**](https://qiita.com/tksh8/items/9a8e88a777a3a4ee7a09)



# Route 53を使用し、お名前.comで取得した独自ドメインでWebページを表示させる

## Route 53の設定
### ホストゾーンの作成

Top画面→Route 53を検索
![スクリーンショット 2020-11-10 10.18.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355517/6e298daa-ba95-f0bd-c727-fd67bd5d9e0f.png)


[ホストゾーンの作成]を押下する

![スクリーンショット 2020-11-10 10.19.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355517/165f7c39-736c-c773-73a5-25156a37c4e4.png)

ドメイン名に取得したドメインを入れ[作成]を押下します。
![スクリーンショット 2020-11-10 10.29.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355517/00d922fd-49a0-72d3-72fa-0bad8ba0d45a.png)


ホストゾーンを作成するとNSレコードとSOAレコードが生成されます

お名前.comの設定で使うので、NSレコードの値4つをメモしておきましょう！

![スクリーンショット 2020-11-10 10.32.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355517/93073131-eeda-d391-f363-9b31c883e2a3.png)



### Elastic IPと紐付ける
まずはElastic IPをメモしておきます

[**こちらで設定されたIPアドレスです**](https://qiita.com/tksh8/items/3d2f2eeaf0e8de291b6d#%E7%A2%BA%E8%AA%8D)

[レコードセットの作成]を押下し、
名前:何も入力せず
タイプ:A
エイリアス:いいえ
値:先ほどメモしたIPアドレス

で[作成]を押下します。


![スクリーンショット 2020-11-10 10.38.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355517/0082ceb0-7f0a-56a0-63c4-14255bc59122.png)


### www.〜でもアクセス対応できるようにする



[レコードセットの作成]を押下し、
名前:*.
タイプ:A
エイリアス:はい
エイリアス先:取得した独自ドメインを選択する


で[作成]を押下します。

![スクリーンショット 2020-11-10 10.43.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355517/c624d8e0-1cc7-5811-9661-9db45a6ab9b0.png)



## お名前.comの設定


![スクリーンショット 2020-11-10 10.45.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355517/f2742806-5af5-08e4-506d-14f3531c8a9f.png)

ここで[次へ]を押下する

[ネームサーバーの変更]を押下する
![スクリーンショット 2020-11-10 10.46.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355517/cfc9ae68-af48-2fa6-27ef-bd867dae1d46.png)



[その他]を押下し、先ほどメモした
NSレコードの値を貼り付け、確認を押下します
![スクリーンショット 2020-11-10 10.47.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355517/40a6a0a8-2441-0611-d5e1-e5a66d4e25c7.png)


これで、ネームサーバーが変更されると、
メール通知がきます。気長に待ちましょう。。。


## ターミナルで確認する
実際にどうなったの確認方法です。
digコマンドというDNSなどが確認できるやり方でやります。

ターミナルを開き、取得したドメイン（ここではtest.com）を入れ実行してみましょう！


```
dig test.com



;; ANSWER SECTION:
test.com. 300	IN	A	xx.xx.xx.xxx
```
のように、IPアドレスが表示されていれば、成功です。


数日待ちましょう。。。


## ドメインで確認する
実際に取得したドメインをうってみましょう。
うまくいけば、表示されるのですが、
私の場合は、
test.com
![スクリーンショット 2020-11-10 10.57.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355517/88cce773-e5e9-acd3-865e-e19024924778.png)

のようになってしまいました。

そんな時は

 sudo vim /etc/nginx/conf.d/test.conf

```/etc/nginx/conf.d/{アプリ名}.conf
server {
    listen 80;
    client_max_body_size 4G;
    server_name www.test.com or xx.xx.xx.xxx; #独自ドメインを追加
```


server_nameに独自ドメインを追加してあげましょう！！

nginxをリスタートさせることを忘れずに！
`sudo service nginx restart`

これで、
Route 53を使用し、お名前.comで取得した独自ドメインでWebページを表示させることができました！！！！！！
RailsのアプリをEC2へデプロイしてみる-後編(サーバー構築編)-

#この記事について
今回はEC2でサーバー構築をしていきます。
前編の内容が前提となりますのでまだの方はご確認ください。
尚今回はEC2内にnode.jsやRubyといった必須のソフトウェアは既にインストールしたものとして記述していきます。
https://qiita.com/kotobuki562/items/57ffbaadad8ec8d16a4f

#データベースの用意
今回はMariaDBを使用します。インスタンスをAmazonLinux2で起動しているためです。
MYSQLの派生版と考えていただければ相違ありません。

下記コマンドを入力してデータベースをインストールしましょう。
MariaDBはyumコマンドでインストールできます。

```terminal
[ec2-user@ip-111-11-11-111 ~]$ sudo yum -y install mysql56-server mysql56-devel mysql56 mariadb-server mysql-devel
```
systemctlコマンドでMariaDBを起動しましょう。

```terminal
[ec2-user@ip-111-11-11-111 ~]$ sudo systemctl start mariadb
```
statusコマンドで起動しているか確認しましょう。

```terminal
[ec2-user@ip-111-11-11-111 ~]$ sudo systemctl status mariadb
```
緑の文字で「active (running)」と表示されていれば成功です。
#データベースのパスワード設定
デフォルトでユーザー名は「root」となっていますが、パスワードはご自身で設定します。
下記コマンドを実行すると色々yes/no聞かれるのでyesと回答して下さい。
「New password:」と表示されたら、ご自身で決めたパスワードを入力してください。
忘れない様にメモしておきましょう。

```terminal
[ec2-user@ip-111-11-11-111 ~]$ sudo /usr/bin/mysql_secure_installation
```

完了したらデータベースに接続してみましょう。
接続が確認できたら「exit」で抜け出しましょう。

```terminal
[ec2-user@ip-111-11-11-111 ~]$ mysql -u root -p
```

これでEC2のデータベース設計は完了です。
次回は実際にGitHubでSSHキーの登録をしてデプロイするところまで記述できればと思います。
Codepipelineの通知をchatbot経由slackに。CDKを使って。

以下の記事は古く、最新バージョンをご利用の際は[こちら](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-codestarnotifications-readme.html#examples)を参考にしてください。

-------

以下のようなファイルを用意して。

```chatbot-stack.ts
import * as cdk from "@aws-cdk/core";
import * as chatbot from "@aws-cdk/aws-chatbot";
import * as codestarnotifications from "@aws-cdk/aws-codestarnotifications";

export interface ChatBotStackProps extends cdk.StackProps {
  name: string;        // 適当な他とかぶらない文字列

  workspaceId: string; // 繋ぎ込みすると management consoleから確認できます。
  channelId: string;   // チャンネルID。copy linkして最後のセクションの文字列。

  pipelineArn: string; // 対象pipelineのarn
}

export class ChatBotStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props: ChatBotStackProps) {
    super(scope, id, props);

    const slackChannel = new chatbot.SlackChannelConfiguration(
      this,
      "NotificationSlackChannel",
      {
        slackChannelConfigurationName: props.name,
        slackWorkspaceId: props.workspaceId,
        slackChannelId: props.channelId,
      }
    );

    const rule = new codestarnotifications.CfnNotificationRule(
      this,
      "NotificationRule",
      {
        name: name,
        detailType: "FULL",
        eventTypeIds: [
          "codepipeline-pipeline-action-execution-succeeded",
          "codepipeline-pipeline-action-execution-failed",
        ],
        resource: props.pipelineArn,
        targets: [
          {
            targetType: "AWSChatbotSlack",
            targetAddress: slackChannel.slackChannelConfigurationArn,
          },
        ],
      }
    );
  }
}
```

こんな感じでpipelineのarnとその他情報を与えてやる感じです。

```cdk.ts

...

const chatbot = new ChatBotStack(app, "ChatBotStack", {
  applicationName: "sampleapp",
  workspaceId: "XXXXXXX",
  channelId: 'deploy-notifications',
  pipelineArn: "arn:xxxxxxxxxxxxxxxxxx",
  env: {
    account: "ZZZZZZZZZ",
    region: "ap-northeast-1",
  },
});

...

```


slackとのつなぎ込みは、management consoleからやってしまいました。
[AWS Chatbot のセットアップ](https://aws.amazon.com/jp/builders-flash/202006/slack-chatbot/) を参考にしてください。
Android Studio でのアプリ開発の学習記録1

#背景
大学院進学を控えた学部4年生です。最近とある事情があり、Androidアプリの開発を始めました。学習内容の備忘録的な意味も込めて記録を残しておきたいと思います。プログラミングスキルとしては、研究で多少pythonは触るものの、その他は完全に未経験です。

#環境
Mac OS Catalina ver 10.15.6
Android Studio 4.1
API 30
使用言語　Kotlin

#学習内容
Android アプリ開発について、わかりやすくまとめられているページ( https://akira-watson.com/ )を参照しました。

・Android Studio による基本的な開発(上記ページの1~10)
・Activityについて
　Activityの具体的な役割の理解が少し進みました。
　特にIntentの役割、MainActivityからSubActivityへの遷移について理解できました。
　現在ではActivityの遷移ではなく、Fragmentによって画面遷移を管理するのが主流のようです。


プログラミング初心者には独学は結構厳しいですね〜
何かおすすめの学習法などありましたら教えてください!
3分アジャイル ペアプログラミング

## オリジナル

- 同じマシンを使って2人でプログラミング
- キーボードとマウスも共用
- プログラミング（分析、設計、テスト）を同時に行う

---

## ポイント（XP）

- 意見を出し合う
- アイディアを明確にする
- ドライバーとナビゲーターを定期的に交代する
- 詰まったところがあれば交代する

---

## 背景

- エクストリーム・プログラミングで紹介されたプラクティス（実践方法）
- 2000年ごろに流行（XPの代名詞）

---

## メリット

- 規範意識の増大
- よりよいコード
- 作業効率の向上
- 多数の開発者による設計
- 勤労意欲の向上
- 集団的なコード所有権
- 教育的側面
- チームワーク
- 割り込みの削減
- ワークステーション数の削減（過去）

---
##デイリー

- 開発チームがスプリントゴールを達成するために、私が昨日やったことは何か？
- 開発チームがスプリントゴールを達成するために、私が今日やることは何か？
- 私や開発チームがスプリントゴールを達成する上で、障害となる物を目撃したか？

---

参考
https://ja.wikipedia.org/wiki/%E3%83%9A%E3%82%A2%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0

ペアプログラミング（PairProgramming）
ＫｅｎｔＢｅｃｋ,ＣｙｎｔｈｉａＡｎｄｒｅｓ. エクストリームプログラミング (Japanese Edition) (Kindle Location 1049). Kindle Edition.
Githubからクローンする時のプロトコルの違い

## はじめに
GitクライアントツールからGithubのリポジトリをクローンする時に、httpsやSSHの通信プロトコルの話とリポジトリへの権限について、理解できていない部分があった。
友人に手伝ってもらいながら試してみて分かった事があるので、メモとして残しておく。


## 実行環境
【ローカルPC-OS】
　　Windows 10 Pro　

【インストールツール】
　　Git for windows 2.29.1
　　SourceTree 3.3.9

　※事前にGithub上にアカウントは作っておく。



## 本記事の流れ

１．Gitクライアントツールのインストール
２．通信プロトコルの説明（httpsとSSH）
３．アクセス権限の話


### １．Gitクライアントツールのインストール
**まずはWindows用のGitを以下よりダウンロードして実行する。**
　　・git for windows（[インストーラー場所](https://gitforwindows.org/)　　[インストール手順の参考サイト](https://laboradian.com/git-installation-on-wndows/#1_Git_for_Windows-2)）


**GITクライアントツールは何でも良いが、今回はSourceTreeをインストールする。**
　　・SourceTree（[インストーラー場所](https://sourcetreeapp.com/)　　 [インストール手順の参考サイト](https://sukkiri.jp/technologies/devtools/git/sourcetree_win.html)）

　※上記の『git for windows』をインストールしていなくても、SourceTreeのインストール時に一緒にインストールする事が可能っぽい。しかし、他のGitクライアントツールも併用したい場合に何か面倒な事が起こりそうなので、上記の流れを推奨。


SourceTreeのインストールでは、インストールの中でSSH鍵の設定も求められるが、一旦はスキップしてしまって問題ない。


### ２．通信プロトコルの説明（httpsとSSH）

Github上にあるリポジトリを単純に使いたかったり、共同開発をしたかったりする場合、基本的にはローカルにクローンを持ってくることが多いと思う。

しかし、`clone`するにもその後に`push`するにも誰でもできる訳ではない。
ローカルのGitクライアントからクローンをする場合、クローンしようとしている人のGithub上のアカウントを把握して、そのアカウントが対象のリポジトリにどんなアクセス権限を持っているかを確認する必要がある。

その際の認証をどのように行うかというのが、**httpsプロトコル** と **SSHプロトコル** で異なるという理解。
　

**httpsプロトコルの場合**
初めてGithubのリポジトリをクローンしようとした場合、Basic認証が動き、Githubの [アカウント名] と [パスワード] の入力が求められる。（ブラウザ経由でサインインを求められる事もある様だが、やっている事は同じ。）

※クライアントツールによっては、1度目の認証通過時に資格情報が記録されているため、同じホスト(今回であればgithub.com)に2回目以降接続する際は入力情報が省略される。


　

**SSHプロトコルの場合**　
自分のGithubアカウントはどれなのかをSSH鍵を使って判断しているイメージ。
そのため、そもそもGithub上で自分のプロフィールに対してSSH公開鍵を設定していない場合、SSHプロトコルによる接続ができない。

SSH鍵の設定後は、クライアントツールの起動のタイミングやリポジトリへの接続のタイミングで、パスフレーズ（SSH鍵を作成した時に設定したもの）を求められるので、それを入力すればリポジトリに接続できる。

※Github上のアカウントで対象のリポジトリに権限を持っていなければ、もちろん`clone`や`push`はできない。

　　　
**接続のイメージはこんな感じ**
あなたのリポジトリクローンしたいです！
　**⇒** あんたは誰や？

　**⇒** httpsプロトコルで接続している場合：Basic認証情報からGithub上のアカウントを判断。
　　 SSHプロトコルで接続している場合：鍵情報からGithub上のアカウントを判断

　**⇒** 君はOK or 権限ないからダメよー　


### ３．アクセス権限の話

権限の設定は基本的にリポジトリ単位でできる。
Github上で自分がオーナーのリポジトリを開くと `Settings` タブがあるはずなので、そこに入り『Manage access』から対象のアカウントに invitation を送る。

※『invite a collaborator』のボタンしかなく、ここでの権限は *[collaborator]* しかなさそうなので、Github上のどのアカウントに対して *[collaborator]* としてinvitationを出すのかという話。

アカウントに対する基本的な権限は　*[collaborator]* と *[non-collaborator]* しかないという前提で、PublicリポジトリとPrivateリポジトリの権限について整理する。


**Publicリポジトリの場合**

■non-collaborator
　読み込み権限（`clone`） ⇒ OK
　書き込み権限（`push`）　⇒ NG

■collaborator
　読み込み権限（`clone`） ⇒ OK
　書き込み権限（`push`）　⇒ OK


**Privateリポジトリの場合**

■non-collaborator
　読み込み権限（`clone`）　⇒ NG
　書き込み権限（`push`）　⇒ NG

■collaborator
　読み込み権限（`clone`） ⇒ OK
　書き込み権限（`push`）　⇒ OK


※Privateリポジトリについても　*[collaborator]* としてinvitationを出すしかできなそうなので、以下の権限も作れるかと予想していたがここの権限設定からでは無理っぽい。

　読み込み権限（`clone`） ⇒ OK
　書き込み権限（`push`）　⇒ NG
　<font color="red">↑この権限設定はできない。</font>


しかし、デフォルトが上記というたけで *[collaborator]* に対する権限は、もう少し細かく設定ができるのかもしれない。


### 補足
ブランチレベルでの権限設定もできそうだが、それは『Setting』タブにあるbranch protection rule を使えば、メンバー対して細かい権限設定もできそうだが本記事ではここまで。
（例えば、Masterブランチにはpushできる人を特定のメンバーのみにするなどは、ここで設定できるそう）

関連してそうな記事を一応貼っておく。
https://qiita.com/da-sugi/items/ba3cd83e64c689795c50
踏み台サーバー経由でPostgreSQLにSQLを流し込むシェル

# はじめに
ローカルPCから踏み台サーバー経由でPostgreSQLにSQLを流し込む際のシェルスクリプトです。


- スクリプト

    ```sh:throw_sql.sh
    #!/bin/sh

    # 踏み台サーバーへのSSH接続情報
    SSH_HOST={SSH_HOST}
    BASTION_SSHUSER={BASTION_SSHUSER}
    BASTION_SSHKEY={BASTION_SSHKEY}

    # DBの接続情報
    BASTION_SSHKEY={DB_HOST}
    BASTION_SSHKEY={DB_NAME}
    BASTION_SSHKEY={DB_USER}
    DB_PASSWORD={DB_PASSWORD}

    # SQL
    SQL='SELECT * FROM TABLE;'

    DBRESULT=`ssh -T -l ${BASTION_SSHUSER} -i ${BASTION_SSHKEY} ${SSH_HOST} <<EOC
    export PGPASSWORD=${DB_PASSWORD}
    psql -U ${DB_USER} -d ${DB_NAME} -h ${DB_HOST} << EOF
    ${SQL}
    EOF
    exit $?
    EOC
    `
    echo ${DBRESULT}
    ```
GmailでPythonを使って送信する

#結論

```python

import smtplib
from email.utils import formatdate
from os.path import basename
from email.mime.text import MIMEText
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart


EMAIL_SENDER_ADDRESS = ''
EMAIL_SENDER_PASSWORD = ''

def sendEmail(message, subject):
    #送り主
    from_email = EMAIL_SENDER_ADDRESS
    from_password = EMAIL_SENDER_PASSWORD

    # 送り先
    to_email = [Env.EMAIL_RECIEVE_ADDRESS]

    # メールの内容
    msg = MIMEMultipart()
    body = MIMEText(message, "html")
    msg.attach(body)
    msg["Subject"] = subject
    msg["To"] = ",".join(to_email)
    msg["From"] = from_email

    gmail = smtplib.SMTP("smtp.gmail.com", 587)
    gmail.starttls()
    gmail.login(from_email, from_password)
    gmail.send_message(msg)
```
cakephp 2.xでcsvを作成しダウンロード

仕事でcsv出力をする機会があって、その時にパッとやり方が思いつかなかったので備忘録。
もっと良いやり方があれば、教えていただけると幸いです。

#コード
以下の配列がコントローラからビューに渡されている想定です。

``` php
<?php
/*
 * Controller
 */

$data = array(
  0 => array(
    'name'=>'一郎',
    'age'=>10,
  ),
  1 => array(
    'name'=>'次郎',
    'age'=>20,
  ),
  2 => array(
    'name'=>'太郎',
    'age'=>30,
  )
);
?>
```

``` php
<?php
/*
 * View
 */

//出力情報の設定
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=list.csv");
header("Content-Transfer-Encoding: base64");

//変数の初期化
$csv = null;

//1行目のラベル
$csv .= '"名前","年齢"' . "\n";

//出力データ
foreach($d as $data) {
  $csv .= '"' . $d['name'] . '","' . $d['age'] . '"' . "\n";	
}

//BOMを追加
$csv = "\xEF\xBB\xBF" .$csv;

//CSVファイル出力
echo $csv;
?>
```
#気になること
小規模のデータベースから比較的少ない量のレコード(100件程度)をcsvにまとめる形だったので、このように単純にできるが、大規模だとmax_execetion_timeに引っかかるみたいな話も聞いた。
fputcsv使うのが良いのかなと思いますが...
【JS】関数の引数で値が代入されている！？デフォルト引数について

関数の引数の中でイコールで値が渡されている以下のような記述がある。この中身についてのメモ。

```js:こういうの
const 関数名 = (a=3, b=5) => 処理
```

`(a=3, b=5)`のように最初から引数の値を指定して渡す方法を**デフォルト引数**と呼ぶ。
参考： https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Default_parameters

引数がない場合はこのデフォルトで設定された値が使われる。別の値が引数として渡された場合は渡された値が上書きされて使われる。


##実例

```js:全てのデフォルト値を指定
const multi = (a=3,b=5) => a*b

console.log(multi()) //15 =3*5
console.log(multi(10)) //50 =10*5
console.log(multi(1,2)) //2 = 1*2
```

<br>

```js:片方だけ指定
const multi = (a,b=5) => a*b

console.log(multi()) //NaN = NaN*5
console.log(multi(10)) //50 = 10*5
console.log(multi(1,2)) //2 = 1*2
```


＞[MDN公式 デフォルト引数](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Default_parameters)
cscの作法 その44 dllimport

#概要

cscの作法、調べてみた。
dllimportやってみた。
vs2010で、コンパイルしたdll、使ってみた。

#サンプルコード


```
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;

class form1: Form {
	[DllImport("inp.dll")]
	static extern StringBuilder InputBox(StringBuilder msg);
	form1() {
		Text = "hello";
		ClientSize = new Size(200, 200);
		Button btn1 = new Button();
		btn1.Location = new Point(50, 50);
		btn1.Text = "test";
		btn1.Click += btn1_Click;
		Controls.AddRange(new Control[] {
			btn1
		});
	}
	void btn1_Click(object sender, System.EventArgs e) {
		StringBuilder msg = new StringBuilder(256);
		msg.Append("test");
		MessageBox.Show((InputBox(msg)).ToString(), "こんちは");
	}
	[STAThread]
	public static void Main() {
		Application.Run(new form1());
	}
}




```

以上。
vistaでvs2010 その4

#概要

vistaで、visual studio 2010やってみた。
コマンドプロンプトで、C++をコンパイルしてみた。


#コマンドプロンプトで、dllをコンパイル。リソース有り


```
rc inp.rc
cl inp.cpp inp.res kernel32.lib user32.lib gdi32.lib /LD

```

#サンプルコード

inp.rc

```
#include <windows.h>
#include "inp.h"

IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 131, 63
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "文字列入力"
FONT 9, "ＭＳ Ｐゴシック"
BEGIN
	DEFPUSHBUTTON "OK", IDOK, 7, 42, 50, 14
	PUSHBUTTON "ｷｬﾝｾﾙ", IDCANCEL, 73, 42, 50, 14
	EDITTEXT IDC_EDIT1, 7, 7, 118, 25, ES_AUTOHSCROLL
	LTEXT "", IDC_STATIC1, 4, 40, 114, 8
END




```

inp.h


```
extern "C" __declspec(dllexport) char * CALLBACK InputBox(char * msg);

#define IDD_DIALOG1		101
#define IDC_STATIC1		102
#define IDC_EDIT1		103


```

inp.cpp


```
#include <windows.h>
#include <windowsx.h>
#include "inp.h"

typedef struct inputbox_global {
	HINSTANCE hinst;
	char input_buffer[256];
	char prompt[256];
} * inputbox_globalptr;

inputbox_global g;

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		g.hinst = (HINSTANCE) hModule;
		strcpy(g.input_buffer, "");
	break;
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
	break;
	}
	return TRUE;
}
LRESULT CALLBACK InputBoxProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) {
	switch (msg)
	{
	case WM_INITDIALOG:
		SetWindowText(hDlg, "InputBox");
		SetWindowText(GetDlgItem(hDlg, IDC_STATIC1), g.prompt);
		return TRUE;
	case WM_COMMAND:
		switch (LOWORD(wp))
		{
		case IDOK:
			Edit_GetText(GetDlgItem(hDlg, IDC_EDIT1), g.input_buffer, sizeof(g.input_buffer));
			EndDialog(hDlg, IDOK);
			return TRUE;
		case IDCANCEL:
			EndDialog(hDlg, IDCANCEL);
			return TRUE;
		}
	break;
	}
	return FALSE;
}
char * CALLBACK InputBox(char * msg) {
	strcpy(g.prompt, msg);
	if (DialogBox(g.hinst, MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC) InputBoxProc) == -1)
	{
		MessageBox(NULL, "DialogBox error!", "InputBox Error", MB_OK);
		strcpy(g.input_buffer, "");
	}
	return (g.input_buffer);
}





```

以上。
JavaScriptを触ってみた記録　〜パッケージ管理と配列処理〜


# この記事

JavaScriptを学習し始めた人が、その記録を残します。

前回は基本文法とクラスで、今回はファイル間連携やパッケージについて軽く触れました。


## デフォルトエクスポート
変数や関数、クラスはexportとimportで連携可能

デフォルトの場合は１ファイル１つの値まで可能
importの際に、名前を変えてもOK

```
ファイルA
export default Penguin;
↓
ファイルB
import Pen from "script.js";
```

## 名前付きエクスポート
名前は同じものを指定
複数指定が可能

```
ファイルA
export { Bear, Cat };
↓
ファイルB
import { Bear, Cat } from "test.js"
```

## パッケージを使ってみる

readline-syncというパッケージを用いて
入力した内容を変数に代入する

```
import readlineSync from "readline-sync";
const scan = readlineSync.question("What's your name? ");
console.log(`Hello! ${scan}!`);
```

## パッケージ管理

パッケージマネージャはnpm, yarnがあるが今回はnpmを扱う

パッケージ情報は、**package.json**というファイルで管理する
プロジェクトの情報はここに記載する
ファイルを作成後、**npm init**を使って内容を記載できる（直接も可）

```
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help init` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (test_npm)
version: (1.0.0) 
description: 
entry point: (index.js) 
test command: 
git repository: 
keywords: 
author: 
license: (ISC)
~
Is this OK? (yes) 
```

**npm install chalk**
のように、ライブラリを追加すると

```
  "dependencies": {
    "chalk": "^4.1.0"
  }
```
といったようにpackage.jsonに追記される

逆に、パッケージ情報を記載しておくことで
他の環境でも依存パッケージを **npm installで用意**することができる

インストールしたパッケージは**node_modules**ディレクトリ内に入っている

```
$ ls node_modules/chalk/
index.d.ts	license		package.json	readme.md	source
```

yarnも同じように使用できるが、
**パッケージインストールが並列**で行われたり
**整合性チェック**があったり等のメリットがある


# 配列操作メソッド

## 配列順次処理
forEachメソッド

引数penguinに対して、順番に処理がされる。
出力処理の例

```
const penguins = ["エンペラーペンギン", "コウテイペンギン", "アデリーペンギン", "ジェンツーペンギン"];

penguins.forEach( (penguin) => {console.log(penguin);} );

```
↓

```
エンペラーペンギン
コウテイペンギン
アデリーペンギン
ジェンツーペンギン
```

## 配列要素の探索
findメソッド
要素ごとに、処理が実行される
見つかればそこで終了する
オブジェクトのプロパティに対しても使用できる

条件に当てはまる全てを出力したい場合はfilterメソッドを使用

```
const Entries = [
  {ent: 1, name: "エンペラーペンギン"},
  {ent: 2, name: "コウテイペンギン"},
  {ent: 3, name: "アデリーペンギン"},
  {ent: 4, name: "ジェンツーペンギン"}
];

const foundPygoscelis = Entries.find( (pen) => {
  return pen.name === "アデリーペンギン";
});

console.log(foundPygoscelis);
```
↓

```
{ent: 3, name: 'アデリーペンギン'}
```


## 処理して新配列を作成
mapメソッド
全ての要素に処理をした後、戻り値から配列を作成する

```
const array = [1, 3, 5]
const newArray = array.map( (value) => {
  return value * value;
});

console.log(array)
console.log(newArray)
```
↓

```
[ 1, 3, 5 ]
[ 1, 9, 25 ]
```


## 感想

他の言語で学習した内容と似てる部分があり、まだ取り組みやすかった印象

最近AWSでLambdaを少し触ることがあり、たまたま事前にJavaScriptをほんの少し触れただけでも
Node.jsに対して**あまり抵抗なく取り組めた**のが嬉しかったです。

以前はさっぱりでしたが、こうやってきっかけを作っていくといい流れになるのかなと感じました。

## 使用したツール、ドキュメント

・Progate
https://prog-8.com/

・MDN web docs - JavaScriptリファレンス
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference
[メモ] WSL2 のカーネルビルドと使用


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75594/5d7c7f71-4c02-20f2-2e31-bafe0044f171.png)


# 概要
WSL2のUbuntu 20.04上で、kernel.orgから持ってきたたカーネルソースをビルドして、WSL2のカーネルとして使用する。

# 環境
- Windows 10 (2004)
- Ubuntu 20.04 on WSL2 
- `stable: 5.9.6 2020-11-05`を使用してみる

# 手順

1. ビルドツール導入

    ```bash
    sudo apt update && \
    sudo apt install -y build-essential flex bison libssl-dev libelf-dev pkg-config libncurses-dev
    ```

2. カーネルソースのダウンロード
    - https://www.kernel.org/ <br>> stable: 5.9.6 2020-11-05 [tarball]

    ```bash
    cd ~
    wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.9.6.tar.xz
    tar xvf linux-5.9.6.tar.xz
    cd linux-5.9.6
    ```
3. `.config`の取得
    - https://github.com/microsoft/WSL2-Linux-Kernel/blob/master/Microsoft/config-wsl

    ```bash
    rm -rfv .config
    wget https://raw.githubusercontent.com/microsoft/WSL2-Linux-Kernel/master/Microsoft/config-wsl -O .config
    ```

4. `make menuconfig`
    `<Exit>` => `<Yes>`で抜ける

5. ビルド

    ```bash
    make -j 5 && sudo make modules_install`
    ```
6. カーネルイメージのコピー (例: `C:\wslkernel\kernel-5.9.6`)

    ```bash
    mkdir -p /mnt/c/wslkernel
    cp -v arch/x86/boot/bzImage /mnt/c/wslkernel/kernel-5.9.6
    ```



7. `C:\Users\<username>\.wslconfig`

    ```ini:例：.wslconfig
    [wsl2]
    #memory=2GB
    #processors=2
    kernel=C:\\wslkernel\kernel-5.9.6
    localhostForwarding=true
    swap=0
    ```
    パスの指定で、バックスラッシュを２つ(`\\`)になるのを注意

8. PowerShellを管理者で開いて、カーネルシャットダウン。

    ```powershell
    wsl --shutdown
    ```
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75594/a56ebdc0-32cb-016e-b436-7c63b253961f.png)

9. Ubuntu再起動
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75594/5d7c7f71-4c02-20f2-2e31-bafe0044f171.png)






# その他
「コンピュータの回路」②　論理回路と基本回路

##論理回路
コンピュータの論理演算は、実際には電子回路で行われています。
論理演算や記憶の処理を行うために作られた電子回路のことを**論理回路**と呼びます。

論理回路のうち、論理積回路（AND回路）、論理和回路（OR回路）、否定回路（NOT回路）の3つが基本的な回路であり、**基本回路**と呼ばれています。
これらの回路を組み合わせることでコンピュータは複雑な制御を実現しています。

##論理積回路（AND回路）
論理積回路（AND回路）では、**入力がどちらも「$1$」である時に限り「$1$」を出力する**という特徴があります。
回路図を以下の図に示します。
![スクリーンショット 2020-11-10 9.14.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657974/64e33922-844e-9449-0b75-dda35114e0f6.png)
論理演算は、**論理式**という式によって表すことが出来ます。
論理積（AND）を表す記号は「・」なので、入力Aと入力B、出力Yを用いて論理式にすると以下のようになります。

```math
A•B=Y
```
入力AとBはそれぞれ「$1$」と「$0$」を出力することができるので、入力AとBの組み合わせは4パターンになります。
このパターンに対応する出力Yを表にまとめたものを「**真理値表**」と呼びます。
この表によって、「どこで何が入力された時に、何が出力されるか」を把握することが出来ます。

以下に論理積回路（AND回路）の真理値表を示します。

| 入力A | 入力B | 出力Y |
|:-:|:-:|:-:|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
真理値表から、入力AとBがどちらも「$1$」の時にのみ出力Yが「$1$」であることがわかります。
上に示した回路図は入力Aが「$1$」で入力Bが「$1$」なので出力Yで「$1$」となっています。
この状態は真理値表の4行目で表現されています。

##論理和回路（OR回路）
論理和回路（OR回路）では、**どちらかの入力が「$1$」である時に「$1$」を出力する**という特徴があります。
回路図を以下の図に示します。
![スクリーンショット 2020-11-10 9.28.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657974/82eac8fe-cca9-382e-c9fc-798541d77084.png)
論理和（OR）を表す記号は「＋」なので、入力Aと入力B、出力Yを用いて論理式にすると以下のようになります。

```math
A+B=Y
```
入力AとBはそれぞれ「$1$」と「$0$」を出力することができるので、入力AとBの組み合わせは4パターンになります。

以下に論理積回路（AND回路）の真理値表を示します。

| 入力A | 入力B | 出力Y |
|:-:|:-:|:-:|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
真理値表から、入力AとBのいずれか一方が「$1$」の時に出力Yが「$1$」であることがわかります。
また、入力AとBのどちらも「$1$」の時についても出力Yが「$1$」であることがわかります。
上に示した回路図は入力Aが「$1$」で入力Bが「$0$」なので出力Yで「$1$」となっています。
この状態は真理値表の3行目で表現されています。

##否定回路（NOT回路）
否定回路（NOT回路）では、**入力された値を反転させて出力する**という特徴があります。
つまり、入力が「$1$」ならば「$0$」を出力し、入力が「$0$」ならば「$1$」を出力します。
回路図を以下の図に示します。
![スクリーンショット 2020-11-10 9.51.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657974/d005552f-ac65-eab7-8887-83e91b6f25fc.png)


否定（NOT）を表す記号は「‾」なので、入力Aと出力Yを用いて論理式にすると以下のようになります。

```math
‾A=Y
```
※実際には否定の記号「‾」がAの上にあります。

入力Aはそれぞれ「$1$」と「$0$」を出力することができるので、2パターンになります。

以下に論理積回路（AND回路）の真理値表を示します。

| 入力A | 出力Y |
|:-:|:-:|
| 0 | 1 |
| 1 | 0 |

真理値表から、入力Aが出力Yで反転されていることがわかります。
上に示した回路図は入力Aが「$1$」なので、出力Yで「$0$」となっています。
この状態は真理値表の2行目で表現されています。

##参考にさせて頂いた書籍
きたみりゅうじ 『キタミ式イラストIT塾 基本情報技術者平成31/01年』 技術評論社 2019年

##学習してみて
今回は基本回路について学習しました。
真理値表は各入力部分と出力部分の状態をセットで表現できるのでとても便利ですね。
ベン図と真理値表、うまく使いこなしていこうと思います。