OmniAICreator/Qiita-1.07M huggingface dataset:
データサイエンス100本ノック~初心者未満の戦いpart3

これはデータサイエンティストの卵がわけもわからないまま100本ノックを行っていく奮闘録である。
完走できるか謎。~~途中で消えてもQiitaにあげてないだけと思ってください。~~


[100本ノックの記事](https://codezine.jp/article/detail/12456)
[100本ノックのガイド](https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess/blob/master/docker/doc/100knocks_guide.pdf)


**ネタバレも含みますのでやろうとされている方は注意**

記事を書く時点で27本目まで終わっていますが、知らなかった書き方も多く、また「自分はこう書いたけど答えはこうだった」というものも多くあったのでメモ代わりに置いておきます。

コレは見づらい！この書き方は危険！等ありましたら教えていただきたいです。~~心にダメージを負いながら~~糧とさせていただきます。

今回は１９～２２まで。
[[前回]](https://qiita.com/sola_wing529/items/3c2d98da08345a879bae)１０～１８
[目次付き初回](https://qiita.com/sola_wing529/items/5fdbd97308dd88da28eb)

**戦いはここから始まる**

#19本目
>P-19: レシート明細データフレーム（df_receipt）に対し、1件あたりの売上金額（amount）が高い順にランクを付与し、先頭10件を抽出せよ。項目は顧客ID（customer_id）、売上金額（amount）、付与したランクを表示させること。なお、売上金額（amount）が等しい場合は同一順位を付与するものとする。

今回の要件は

|id| amo|rank|
|--:|--:|--:|
|    A00|   100|1|
|    B00|   70|2|
|    C00|   80|2|
|    D00|   70|4|
みたいな形の表を作る、ということらしい
SQLでいうなら

```rei.sql
SELECT　id,amo amo,
(SELECT count(amo) FROM df b WHERE a.amo < b.amo)+1 rank
FROM df a ORDER BY rank 
```
といったところか(久々にSQL打った)
一応解説すると`amo`と`a.amo`が今見ている売上で、その見ている売上よりも高い売上`b.amo`の数をカウントして(一番大きいと0になるから)+1する。と、いうrankを作りその列を追加するという内容。
**注意**：とても計算に時間がかかる書き方です。10本ノックのSQLで試しましたが、数分単位でかかりました。


**Dataframeでも同じように**
`df_receipt[['customer_id', 'amount']] `
と`ランク列`を作り、(横に)結合すると表ができる

`ランク列`の作り方は
`df_receipt['amount'].rank(method='min', ascending=False)`
※[[参考]](https://note.nkmk.me/python-pandas-rank/)

- `ascending=False`で降順(多いほうが優先)データ。
- `method='min'`は少ない数(最小値)が順位データとして返る。

**横結合をするには**
`pd.concat([['列A'],['列B']], axis=1)`
`pd.concat`はaxisがデフォルトだと縦結合(表の下に表がくっつく)が、`axis=1`をつけると横結合されるらしい

最後に列名を変え、rank昇順に並び替えると

```mine19.py
df_tmp = pd.concat([df_receipt[['customer_id', 'amount']] ,df_receipt['amount'].rank(method='min', ascending=False)], axis=1)
df_tmp.columns = ['customer_id', 'amount', 'ranking']
df_tmp.sort_values('ranking', ascending=True).head(10)
```

こうなる

**もちろん**分からなくてカンニングである


#20本目
```mine20.py
df=df_receipt
df=pd.concat([df[['customer_id','amount']] ,df['amount'].rank(method='first',ascending=False) ],axis=1)
df.columns=['customer_id','amount','ranking']
df.sort_values('ranking',ascending=True).head(10)
```
19本目と内容が一部被るので割愛
変わる部分は
>なお、売上金額（amount）が等しい場合でも別順位を付与すること。

の部分。つまり、表示として

|id| amo|rank|
|--:|--:|--:|
|    A00|   100|1|
|    B00|   70|2|
|    C00|   80|3|
|    D00|   70|4|
という形をとりたい。

>- `method='min'`は少ない数(最小値)が順位データとして返る。

ここを変更すればよく、降順データにした後に`'min'`を`'first'`とすることで出現順にナンバリングされる。

#21,22本目
```mine21.py
len(df_receipt)
```
```mine22.py
len(df_receipt['customer_id'].unique())
```
~~解説いる？~~
22本目をSQLに直すと
`SELECT COUNT(DISTINCT customer_id) FROM receipt`
でいけます。~~どっちが楽？~~

#今回はここまで
実際ランクをつけるのをSQLとPythonで比較してPythonのほうが早いと感じたので、ようやくpandasを使うことに意義を見出し始めました。~~LIKEとかSQLのが楽やろ~~
問題を解いているだけだとあまり頭に入ってこないので、また問題を解いてから整理をするをしていきたいと思います。
初心者Java　「Staticメソッド」「new演算子」

今回はStaticメソッド」と「new演算子」について。

##「Staticメソッド」について
staticとは「静的」を意味し、Javaのメソッドは必ず何かのクラスに属します。

- インスタンスメソッド：インスタンスが持つメソッド、インスタンスが実行する

- staticメソッド(クラスメソッド)：クラスが持つメソッド、クラスが実行する

###staticメソッドの宣言の仕方
staticメソッドの宣言の仕方は、メソッド宣言での戻り値の前に “static” を付けるだけです。

- staticメソッド

```
アクセス修飾子(publicなど) static 型名 メソッド名(引数){}
```
- static変数

```
アクセス修飾子(publicなど) static 型名 変数名;
```
staticメソッドはその特徴としてnewを使わずに呼び出すことができます。

```java
class StaticMethodSample1 {
 // staticを付ければstaticメソッドになる
 static void staticMethod() {
 }
 
 // staticを付けなければインスタンスメソッドになる
 void instanceMethod() {
 }
}
```

### 「new演算子」について
new演算子は、Javaのクラスをインスタンス化するために利用されます。

JavaScriptに限らずオブジェクト指向のプログラムは、
あらかじめ用意されている「オブジェクト」をそのまま扱うことはありません。

調べていたらわかりやすい例があったので参照

例えば、目的が違う「A」「B」という2つのプログラムがあったとします。
両方のプログラムがまったく同じ「オブジェクト」に対してデータを読み書きしてしまうと
お互いに干渉してしまって正しく動作しません！
「コピーをする」という行為がインスタンス化であり、コピーされた「オブジェクト」をインスタンスと呼ぶわけです。JavaScriptでは、このインスタンスを作成する役割を担っているのが「new演算子」ということです。

クラスをnew（インスタンスを作成）した時点でプログラム上でメモリが確保され、初めて使用できるようになります。

###標準で提供されているJavaScriptの組み込みオブジェクトについて

```
 オブジェクト       内容 
 Array    配列を扱うための機能を提供する 
 String   文字列を扱うための機能を提供する 
 Boolean  真偽値を扱うための機能を提供する 
 Number   数値を扱うための機能を提供する 
 Function 関数を扱うための機能を提供する 
 Date     日付を扱うための機能を提供する 
 RegExp   正規表現を扱うための機能を提供する 
 Object   オブジェクトを扱うための機能を提供する 
```

new演算子の使い方は以下のとおりです。

```
new コンストラクタ;
new クラス名();

```
Ubuntu18.04で環境構築に苦労した件

# はじめに

この記事はOSを飛ばし（主にWindows）Ubuntuを調べながらならインストールできる方を対象とする（デュアルブートとかではない）．また，基本的には言語設定は英語で行うこと．理由は，ディレクトリ名に日本語が入らないからだ（日本語で入れてもあとで変えられるらしいが自分で調べて）．なぜかは，この記事に辿り着いた人にはわかることだから説明はしない．
本題だが，本記事はUbuntu18.04をクリーンインストールしたあとのことを記述していく．また，大学や社内のProxy環境下で開発をしているひとが対象だ．

## Proxyが通るようにする

Ubuntuでは，パッケージ管理システムのaptを用いていろんなものをインストールする．通常はUbunntuをインストールしたあと，普通に使える．しかし，Proxy環境下では思うように使えない．そこで，viかnanoを使って，`/etc/apt/apt.conf`に次のように記述する．そして，再起動する．すると，`apt install <package>`が使えるはずだ．

```sh:/etc/apt/apt.conf
Acquire::http::Proxy "http://<proxy_server>:<port>";
Acquire::https::Proxy "https://<proxy_server>:<port>";
```
しかし，これだけでは通らないコマンドがいくつか発生する．そこで`.bashrc`に以下をVimなど好きなエディタで追記する．追記後は`source ./.bashrc`で反映を忘れずに．

```sh:./.bashrc
proxy=<proxy_server>:<port>
export http_proxy=http://$proxy
export HTTP_PROXY=$http_proxy
export https_proxy=$http_proxy
export HTTPS_PROXY=$http_proxy
```

## CUDA10.2をインストール
CUDA10.2のインストールについては[こちら](https://qiita.com/ShinichiroImoto/items/29fd068de6744b516c0d)に丸投げする．が，[公式サイト](https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#ubuntu-installation)も参考にしたらよい．
ちなみに私は先にNVIDIA　Driverをインストールしてしまったために何度もUbuntuの再インストールを繰り返した．CUDAをインストールするとNVIDIA　Driverも一緒にインストールされる．親切だ．

## Gitが使えるようにする

聡明なあなたは，すでにGitをインストールしていることだろう．しかし，Proxy環境下ではGitもまともに使えない．非常に腹立たしい．
というわけで，次のコマンドを実行しよう．

```sh
$ sudo apt update      # すでにしている人はしなくて良い
$ sudo apt install -y git # すでにしている人はしなくて良い
$ git config --global http.proxy http://<proxy_server>:<port>
$ git config --global https.proxy https://<proxy_server>:<port>
```
これでGitがProxy環境下で使える．Gitコマンドについてはここでは記述しない．

## Python開発環境を構築

私は，Python開発環境はpyenv，pyenv-virtualenvとVSCodeで構築した．VSCodeについては本記事では触れない．

### pyenvをインストール

次のコマンドを実行する．

```
$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv
```

pyenvを使えるようにPathを通す．`.bashrc`に以下を追記する．追記後は`source ./.bashrc`で反映を忘れずに．

```sh:./.bashrc
export PYENV_ROOT=$HOME/.pyenv
export PATH=$PYENV_ROOT/bin:$PATH
if command -v pyenv 1>/dev/null 2>&1; then
    eval "$(pyenv init -)"
fi
```

`pyenv install`はこのままではできないので次のコマンドを実行して必要なツールをインストールする．もともと入っているものもある．

```
$ sudo apt install -y gcc make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
```

### pyenv-virtualenvのインストール

次のコマンドを実行する．

```
$ git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv
```

pyenvのときと同様に`.bashrc`に以下を追記する．

```sh:./.bashrc
eval "$(pyenv virtualenv-init -)"
```
これでpyenvとpyenv-virtualenvが使えるはずだ．pyenvなどの使い方は[こちら](https://bi.biopapyrus.jp/python/pyenv.html)を参考にしてほしい．

## あとがき

本記事は大学院生が研究で使った環境のメモ用なので参考になる人は少ないかもしれない．あと，研究の引き継ぎのメモも兼ねているので不親切な部分が多いが許してほしい．
ちなみに，私はいろんなエディタを使うので好きなエディタはない．`.bashrc`の編集ではVimをいやいや使う（Vimerには申し訳ない）．
plantFEM(旧SiCroF)におけるファイルIO

plantFEM(旧SiCroF)メンテナをしております。

plantFEMは、Fortranベースのアプリケーションで、Fortranを独自拡張したモジュールを多数用意しております。
まずは、File-IOについての機能をご紹介します。

# plantFEMにおけるIO: IOClass

Fortranでは、ファイルIOの際に煩雑な文法を意識する必要がありますが、plantFEMではこの煩雑さを（ある程度）解消しています。

では、まず、ファイルを開く→書き込む→閉じる
までを実装してみましょう。

IOについては、IOClassという部品を用意しております。
これは、stdという部品群に含まれていますので、stdをuse(importやincludeに相当）してきて使います。

まず、新規プロジェクトを作成します。

```zsh
./plantfem new
```
すると、プロジェクト名やスクリプトの種類を聞かれますので、適当にエンターキーを連打します。
すると、home/以下にプレーンスクリプトが作成されますので、そこに書き込んでいきます。


```Fortran
program main
    use std
    implicit none
   
    type(IO_) :: f
   
    call f%open("./","hello",".txt")
    call f%write("Hello, world")
    call f%write(str(100)//"hello")
    call f%write(trim(str(100))//"hello")
    write(f%fh,*) 100.0d0
    call f%close()
   
end program main
```

ファイル入出力用のカーネルを起動し、openコマンドを実行します。実行オプション（カッコの中）に、順に、ファイルパス、ファイル名、拡張子をカンマ区切りで入力すると、その名前のファイルが作成されます。
次いで、writeコマンドを実行すると、実行オプションに入った文字列をファイルに書き込みます。
注意として、文字列にしないと書き込めませんので、数値の場合はstr関数を使って、数値を文字列に変換して出力します。
また、str関数は出力末尾にスペースが含まれる場合がありますので、それを嫌う場合はtrim関数を用いて末尾スペースをカットして出力するとよいでしょう。
また、f%fhとするとファイルハンドルを呼び出せますので、Fortranのwrite文法とも組み合わせて使えます。

スクリプトを保存しましたら、

```
./plantfem home/untitled/main.f90
```
のようにして実行できます。

ファイルの中身はこのようになります。

```
✗ cat hello.txt                    
Hello, world
100                 hello
100hello
   100.00000000000000   
```

今後、html、json、csv形式などに対応予定です。
Visual Studioでのコマンドライン引数の使い方(argc, argv)

#はじめに
######※これは、VC++ Visual Studioを利用する初心者向けの学習用記事です。
今回はVisual Studioでコマンドライン引数(argc, argv)を利用する設定を行う。

#コマンドライン引数(argc, argv)とは、
コマンドライン引数とはmain関数に用いる引数のことです。

自作の関数を作成したことのあるエンジニアであれば、引数を設定したことがあると思うが、それのMain関数版である。
自作関数の場合は、ソースコード内で引数に変数や定値を入れて関数を呼び出すが、
main関数の場合は、実行するときにコマンドラインからコマンドライン引数に値を与えます。

```cpp:自作関数の場合
int foo(int a, int b){
    return a + b;
}

int main(){
    int a = 1;
    int result;
    result = foo(a, 1); //自作関数の引数代入はここで行う。aと1が引数へ代入される。
}
```

```bash:コマンドライン引数の場合
C:/Windows/system32>program.exe 引数1 引数2
```
コマンドライン引数代入は、実行ファイルの後ろに続けて、「半角スペース」を空けながら並べて記述する。


#Visual Studioでのコマンドライン引数の設定方法
コマンドライン引数を設定したいプロジェクトをVisual Studioで開いてください。
Visual Studioの画面が開いたのち、上部のメニューより「プロジェクト」－「プロパティ」を開いてください。
![Visual Studioメニュー画面.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660146/6d61365c-2bcb-f64c-f005-67cc1cc3280a.png)

プロパティの画面が開いたのち、左部のメニューより「構成プロパティ」－「デバック」を選択し、「コマンド引数」の欄をクリックします。
![Visual Studioプロパティページ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660146/c4fba2d3-7960-d20f-6daf-889a9a95874b.png)
「コマンド引数」の欄に、半角スペースで値を並べて入力することで、前述したようにコマンドライン引数ような入力が可能です。

#テストプログラム

```cpp:Argument.cpp
#include<iostream>

using namespace std;

int main(int argc, char* argv[]) {
    for (int i = 0; i < argc; i++)
        cout << "argv[" << i << "] " << argv[i] << endl;
   
    return 0;
}
```
Visual Studioでのコマンド引数は、「test 1」と設定した。

```bash:出力結果
argv[0] C:/Users/User/source/repos/Project/x64/Debug/Project.exe
argv[1] test
argv[2] 1
```
argv[0]は、必ず実行ファイルの名前が入る。
コンソールから実行した場合は、自分が指定した「パス＋実行ファイル名」のみだが、Visual Studioの場合は絶対パスが格納される。
そして、argv[1]以降には、Visual Studioで設定したコマンド引数が順番に出力される。

#注意点
ここで注意しなければならないのは、argv[]はchar型であることだ。
引数に数値を入力したからといって、そのまま利用できるわけではない。
char型なので、整数ならint型、小数点ならfloat,double型などに変換する必要がある。
C++であれば、char型をstring型に変換することも多いと思われる。

```cpp:変換例
int a = atoi(argv[0]); //引数が整数の場合
double b = atof(argv[1]); //引数が小数点の場合
std::string str = argv[3]; //引数をstring型に変換する場合
```

#さいごに
今回はVisual Studioでコマンドライン引数(argc, argv)を利用する設定を行った。
コンパイルに時間のかかるプログラムや閾値などを簡単に設定したい場合などに有用な方法である。
バッチファイルなどを組めば、引数だけを変えて様々処理を自動で処理することも可能であるため、
覚えておいて損のない機能だ。
Github：privateリポジトリーの指定ブランチをコマンドラインにて圧縮ファイルで取得

# 1. GithubにてAPIトークンを作成

 公式のヘルプの通り。

 [▶　Github.com ：コマンドライン用の個人アクセストークンを作成する](https://help.github.com/ja/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line)

- スコープは、「repo」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15972/95dfa137-d79f-6097-6dc5-df9423dee5e0.png)

# 2. curlで取得

- ${}は該当する値。
- ${api_token}は、項番1で作成したトークン。
- ${archive_type}は、「zipball」の場合zip形式。「tarball」の場合tar形式。

```sh
curl -H "Authorization: token ${api_token}" -L https://api.github.com/repos/${owner_name}/${repository_name}/${archive_type}/${branch_name} > ${file_path}

```

# 備考

レンタルサーバなどGitコマンドが使えない環境でのデプロイに利用できるかもしれません。
yumとrpm

パッケージを管理するyumとrpm。
その違いとコマンドについてちょろっと。


yum
・パッケージ管理ツール
→OSへのソフトウェアの導入と削除、依存関係の整理などを行うツール
・rpmより高機能
→統合的に管理運用するシステムが備わっている

＜代表的なコマンド＞
--info(-i):パッケージグループの詳細表示
--list(-l):パッケージグループ一覧表示
--provides(-p):ファイルなどを指定して、該当ファイルを提供するパッケージ検索
--quiet(-q):実行時にメッセージを表示しない
--verbose(-v):詳しいメッセージ出力


rpm
・パッケージ管理ツール
→OSへのソフトウェアの導入と削除、依存関係の整理などを行うツール

＜代表的なコマンド＞
--install(-i):パッケージをインストール
--erase(-e):パッケージアンインストール
--query(-q):パッケージ情報の表示と検索
--verify(-V):パッケージ検査

目次とかってどうやって作るんだろ、、終わり
【随時更新】データ分析によく使うPythonメモ【N分割等】

#リストのデータをN分割する

```python
from matplotlib import pyplot as plt
import numpy as np
import random

#任意の数の分割する(分割数, データリスト)
def division_datas(division_length, datas):
    sort_data = sorted(datas)
    datas = [sort_data[i:i+division_length] for i in range(0, len(datas), division_length)]
    return datas

#0~100のランダムな数値を100個生成する
my_data = [random.randint(0, 100) for i in range(100)]

#データを15分割してみる
division_data_ls = division_datas(15, my_data)
print(division_data_ls)
```
マイグレーション データ型は何が適しての？？

#マイグレーションで実現できること

テーブル作成
テーブル削除
カラム追加
カラム名変更
カラムのデータ型変更
カラム削除

#マイグレーションファイル作成

マイグレーションファイルは モデルを作成した時 に一緒に作成される。
さらに マイグレーションファイル単体 で作成することも可能。

```ruby:ターミナル
rails g model　[モデル名] [属性名:データ型 属性名:データ型・・・] [オプション]

#単体で生成する場合
rails g migration　マイグレーション名
```

上記のコマンドを実行することで、db/migrateフォルダの中にマイグレーションファイルが作成される。




#データ型は何が適してるの？？

|オフィシャル情報| 日本語でざっくり概要|
|:-:|:-:|
| primary_key  | プライマリキー  |
|string   |  文字列(1〜255文字) |
| text  |長い文字列(1〜4294967296文字)   |
| integer  |整数(4バイト)   |
| bigint  |整数(8バイト)   |
| float  |  浮動小数 |
| decimal| 精度の高い少数|
|numeric|数値|
|datetime|日時|
|time |時間|
|date|日付|
|binary|バイナリーデーター|
|boolean|Boolean型 |	

##似ているけど違うものはどうするのか

**文字を扱う場合、stringとtextどちらが適しているか**

stringは、255文字までしか扱うことが出来ないため、状態や時期によっては、256文字以上になる可能性のあるデータを扱う場合はtextを使うことをおすすめします。
名前やメールアドレス、社名などの文字情報は、stringで取り扱い、本文や備考などの文章情報はtextを使うのが一般的です。

**enumを扱う場合、stringとintegerどちらが適しているか**
hashのintegerをマッピングできるのがenumなので、enumで扱う予定のカラムをstringにしたらそもそもenumを取り入れる意味がないし、機能しないですね。ということを冷静に考えて、enumで扱う予定のカラムのデータ型はintegerが適しています。

**idを扱う場合、 integerとbigintどちらが適しているか**
idは、将来的にユーザーが増えると膨大な桁数になる可能性があります。Rails5.1からidカラムがデフォルトでbigintになっていることも踏まえて、基本的にはbigintが適していると考えて良いでしょう。

いずれも、現状と一致させるという考え方よりは、将来的に「入らない！」という状況になる可能性が少しでもあれば大きめの箱を用意する、という考え方で選定すると安心です。










#### 補足
######Rails modelの命名規約

Railsでは、modelに対応するデータベースのテーブル名はmembersのように複数形になります。

しかし、modelのクラス名は、Memberのように頭が大文字の単数形になる。

また、modelを作成する時は、「rails g model member」のようにmemberを小文字始めても大丈夫です。

また、例えばmember_imageと指定してもMemberImageとしても、MemberImageモデル(テーブル名はmember_images)が作成されます。

ただし、membersのように複数形にすることは厳禁です。Membersモデルが作成されてしまいます。modelは必ず単数形で作成しましょう。
Pythonで信号処理(1)：フーリエ変換

#はじめに
Pythonで行う信号処理の勉強資料。

#使用するライブラリー
numpy, matplotlib
scipyのfftpack

#実行内容
1. 特定周波数の正弦波を生成する。(numpy)
2. FFTを実行する。(scipy)
3. 実行結果をプロットする。(matplotlib)

#プログラムコード

##1.正弦波の生成部分

```python
N = 2**20 # data number
dt = 0.0001 # data step [s]
f1 = 5 # frequency[Hz]
A1 = 1 # Amplitude
p1 = 90*pi/180  # phase [rad]

#波形形成
t = np.arange(0, N*dt, dt) # time
freq = np.linspace(0, 1.0/dt, N) # frequency step
y = A1*np.sin(2*np.pi*f1*t + p1) 

```

##2.フーリエ変換部分

```python
# 離散フーリエ変換&規格化
yf = fft(y)/(N/2) 

# y : numpy 配列
# N : サンプリング数
```

全体コード

```python:fft.py
import numpy as np
from scipy.fftpack import fft
import matplotlib.pyplot as plt

#円周率π
pi = np.pi

# parameters

N = 2**20 # data number
dt = 0.0001 # data step [s]
f1 = 5 # frequency[Hz]
A1 = 1 # Amplitude
p1 = 90*pi/180 # phase

#波形形成
t = np.arange(0, N*dt, dt) # time
freq = np.linspace(0, 1.0/dt, N) # frequency step

y = A1*np.sin(2*np.pi*f1*t + p1)

#フーリエ変換
yf = fft(y)/(N/2) # 離散フーリエ変換&規格化

#プロット
plt.figure(2)

plt.subplot(211)
plt.plot(t, y)
plt.xlim(0, 1)
plt.xlabel("time")
plt.ylabel("amplitude")

plt.subplot(212)
plt.plot(freq, np.abs(yf))
plt.xlim(0, 10)
plt.xlabel("frequency")
plt.ylabel("amplitude")

plt.tight_layout()
plt.savefig("01")

plt.show()
```
#3.実行結果
上：時間領域のグラフ：位相が90度ずれていることを確認。
下：周波数領域のグラフ：5Hzの周波数が確認。
![Figure_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/01e87576-b4db-d1be-91b1-031c0656f641.png)


#まとめ
1.PythonでFFTを実行した。

##感想
これまで信号処理には、matlabを使ってきたが、pythonのscipyのほうも簡単。

#参考資料
ApolloClient(React Hooks)でMutation後にQueryをRefetchする。

ApolloClientにて、`useMutation`でデータを更新した後に`useQuery`のデータを再取得する方法に関して
ざっと調べた結果です。

# useQueryのrefetch関数を利用する。

`useQuery`関数の戻り値に含まれる`refetch`関数を実行することで、データの再取得ができます。
`useMutation`関数が同一コンポーネント内、もしくはすぐ配下のコンポーネントならば、
こちらの関数を利用すれば事足ります。

```js
const { data, loading, error, refetch } = useQuery(ANY_GET_QUERY);

const [update, { loading, error }] = useMutation(ANY_SET_QUERY, {
  onCompleted() {
    refetch();
  },
});
```

[FETCHING DATA > Queries > Refetching - APOLLO DOCS](https://www.apollographql.com/docs/react/data/queries/#refetching)
[API > @apollo/react-hooks > useQuery > Result](https://www.apollographql.com/docs/react/api/react-hooks/#result)

# useMutationのrefetchQueriesオプションを利用する。

いくつかのWidgetを組み合わせた構成の画面などで、兄弟関係のコンポーネントのQueryをRefetchさせたい場合は、
`useMutation`関数のオプション引数`refetchQueries`が便利です。

更新したいクエリ名を配列で渡すと、Mutation完了後に該当Queryを実行してくれます。
更新対象の可能性があるクエリ名を最大数記載しても、該当コンポーネントが無ければ
余分なクエリが実行されることはありません。

```js
/**
 * Widget A : リストの表示
 */
const QUERY_A = gql`
  query QueryA {
    list(id: $id) {
      id
      name
    }
  } 
`;

const { data, loading, error } = useQuery(QUERY_A);

/**
 * Widget B : リストの表示
 */
const QUERY_B = gql`
  query QueryB($id: ID!) {
    list(id: $id) {
      id
      date
    }
  } 
`;

const { data, loading, error } = useQuery(QUERY_B);

/**
 * Widget C : リストの更新
 */
const [update, { loading, error }] = useMutation(QUERY_B, {
  refetchQueries: [
    'QueryA',
    'QueryB'
  ],
});

```

単にクエリ名を渡すのみの場合、クエリの引数は前回のものがそのまま活用されます。
名前文字列の代わりに`variables`を指定したオブジェクトを渡すことも可能です。
配列の代わりに`useMutation`の結果を受け取る関数を渡すこともできます。

```js
const [update, { loading, error }] = useMutation(QUERY_B, {
  refetchQueries: ( mutationResult ) => {
    return [
      'QueryA',
      {
        query: 'QueryB',
        variables: { id: mutationResult.id }
      }
    ]
  },
});
```

[Updating after a mutation - APOLLO DOCS](https://www.apollographql.com/docs/react/caching/cache-interaction/#updating-after-a-mutation)
[useMutation API > Options - APOLLO DOCS](https://www.apollographql.com/docs/react/data/mutations/#options)
[react-hoc API > options.refetchQueries - APOLLO DOCS](https://www.apollographql.com/docs/react/api/react-hoc/#optionsrefetchqueries)

## onComplete関数が呼ばれない

`refetch`されたいくつかのクエリのうち、`onComplete`関数が呼ばれるものと呼ばれないものがありました。
今のところ原因は不明です。。。
`useQuery`の戻り値の`data`はちゃんと新しくなっていたので、取り急ぎ`onComplete`を利用せず、
代わりにReactの`useMemo`を活用することで対処しました。
（情報求ム）

# 参考情報

https://github.com/apollographql/apollo-client/issues/1831
[Git] ファイルがどのbranchに含まているか検索する　

謎のmigrationがあるためgit log全体を検索
対象のファイルが含まれるコミットを発見

```bash
$ git log --all -- 'db/migrate/2020323*'

commit d178513009038b0d6473de95a685c9402da14123
Author: Cozy <dummy-mail@gmail.com>
Date:   Fri Mar 27 18:20:29 2020 +0900

    〇〇のcolumn名変更

```

あった。glob対応してるのが嬉しいね

`git branch`でコミットが含まれるbranchを検索して発見

```
$ git branch -a --contains d178513009038b0d6473de95a685c9402da14123
  remotes/origin/feature/dummy-feature-branch
```

これにて一件落着 🙏
新型コロナウイルスに関するツイートへの感情分析

元記事：https://www.octoparse.jp/blog/twitter-sentiment-analysis-on-novel-coronavirus/

欧米で新型コロナウイルスの感染拡大の中、ウイルス関連の陰謀論も盛り上がっています。SNSでも根拠が不明なまま人々の不安をあおる発言がじわじわ広がっているため、FacebookやTwitterは、投稿の精査 ・確認に積極的に取り組んできました。信頼できる情報源が増えるにつれ、実際の人々の声を聞いて、コロナウイルスに関する真の感情を発見する方が面白いと思いました。

 

#Twitterをスクレイピングする

「スクレイピング」という単語に怯えないでください。Webページを閲覧できれば、初心者でもプロ並みのWebスクレイピングができます。

人々の声を聞く最も簡単な方法は、新型コロナのキーワードを含むツイートをすべて収集することです。アメリカと英語という検索条件を設定することで、研究の範囲をさらに狭めています。これにより、サンプルデータが検索トピックと一貫性を保ち、予測の精度が向上します。

研究範囲が決まったら、スクレイピングを開始できます。Pythonなどのプログラミング言語に詳しくないので、いつものWebスクレイピングツール「[Octoparse](https://www.octoparse.jp/)」を使います。自動認識機能を備えているため、データの手動選択する時間を大幅に節約できます。

Twitterは動的なサイトで、ページを下にスクロールし続けると、ツイートが表示されます。つまり、できるだけ多くのツイートを取得するために、ループリストを作成して、情報を取得しながらスクロール動作を維持します。これにより、スクレイピングワークフローが中断することなく一貫性を保ちます。

そのようなサイトからデータを抽出するのは難しいので、Octoparseが提供しているTwitter[スクレイピングテンプレート](https://www.octoparse.jp/blog/a-revolutionary-web-scraping-software-to-boost-your-business-easier/)を利用します。Octoparseには数十種類のあらかじめ作成されたテンプレートがあり、瞬時にデータを取得できて、スクレイピングタスクを設定する必要はありません。今回はTwitterの「Advanced Search」というテンプレートを利用します。
![template.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262932/1e608701-d362-ca3d-a1c0-7d245233baf9.png)


それから、検索条件を絞り込んだURLとスクロールダウン回数を入力し、「保存して実行」をクリックすると、データが抽出されます。以下は取得したデータです：
![sample data.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262932/82e744e4-32af-ed0f-f5e5-32d3477d9c98.png)


 

 

#NLPで感情分析を行う

NLPは自然言語処理の略称で、テキストの感情分析に広く使用されています。アイデアは、単語を計算する分類子モデルを構築し、単語の意味を理解することです。たとえば、ツイートを入力すると、内容が積極的か消極的かがわかるはずです。明らかに、よりきめの細かい感情分類はより困難な作業です。

すでに十分に訓練されたモデルを持っているので、この場合は、FastTextを使用してツイートを予測します。得た結果はこのようなものです：
![sentiment analysis.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262932/af570042-18e7-bfde-2109-31f2b6351269.png)


ご覧のように、ツイートは「積極的」と「消極的」2つのグループに分類されていて、確率スコアもあります。得点が高いほど、予測は正確になります。約0.5のスコアについては、積極的でも消極的でもない中立的な感情を示しています。

スコアが0.7未満のツイートを除外してグラフを作成しました。
![visualize using Tableau.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262932/ae01d9e5-df77-fc6b-467b-019bd26989af.png)
グラフが示すように、ツイートの42.2％は新型コロナウイルスに対して積極的ですが、ツイートの57.8％は消極的です。最も多くのコメントを得たツイートは、より積極的になる傾向があります。一方、最もいいねされたツイートはより消極的であるように見えました。この結果は、一般市民の態度が単一性ではなく二分法のレベルを示しているため、皮肉な状況を示しています。これが、なぜ経済の再開に抗議する側がいるのか、反対に医療タスクフォースの撤廃を懸念している人々がいる理由を説明しています。私たちはパラドキシーまたは不確実性の状況にあります。 

 

 

#まとめ

ニュースメディアは常に大衆に知らせるために最も大きな声を持っています。しかし、これらの主流メディアは、私たちの意思決定に大きな影響を与える政治的視点を持っています。特に、陰謀論がかき立てられて、事態を混乱させる場合、これは危機の際の典型的な現象です。

頭脳を明晰に保つにはどうすればよいですか？ストーリーの片側だけを読むのではなく、より多くの声に耳を傾けてください。ニュースを読むときは、正しい判断力を高め、様々な情報の中から、必要な情報のみを取り入れるのは必要です。
Swift文字列←→CGFloatやり方によっては誤差が含まれたまま文字列に変換されてしまう 

## Swift文字列←→CGFloatやり方によっては誤差が含まれたまま文字列に変換されてしまう

#### 目的:"1.1"をCGFloatに変換して、変換したCGFloatの値をもとの文字列"1.1"に戻したい

1. 文字列からCGFloatに変換
2. CGFloatから文字列に変換

誤差が含まれて文字列になってしまうやり方があることがわかった
"1.1"をfloatへ(1.100000023841858)これをCGFloatに変換してから文字列へ"1.100000023841858"
32bitアプリか64bitアプリかで違うということらしいので、64bitのCGFloatはdoubleのtypedef

```swift:
// CGFloatより
/// The native type used to store the CGFloat, which is Float on
/// 32-bit architectures and Double on 64-bit architectures.
```

ここで注意して欲しいのは、CGFloat(Float("1.1"))としないこと、これは32bitアプリの場合
現在は64bitアプリなのでCGFloat(Double("1.1"))が正解

##### CGFloatへの変換はNumberFormatterクラスを使う
* NumberFormatterクラスを使う<br>これを使うといい<br>

```swift:
let strNum = "1.1"
let numberFormatter = NumberFormatter().number(from: strNum) ?? 0.0
let cgFloat = CGFloat(truncating: numberFormatter)
let str = "\(cgFloat)"
```
Paloalto URLフィルタリングの備忘録

## はじめに

PaloaltoシリーズのURLフィルタリングについて備忘録的にまとめます。

## URLフィルタリングとは
Paloalto社が保持するURLフィルタリング データベースを利用して、危険なカテゴリに属するサイトへのアクセス制御をきめ細かく制御できる機能になります。
なお、こちらの機能を利用するにはPANDB URL Filtering subscriptionのオプションライセンスの追加購入が必要になります。
※以前はBrightCloud Filtering subscriptionという名前でBlightCloud社のデータベースを参照してましたが、こちらの販売は終了し現在はPANDBのほうで移行しています。BrightCloudとPANDBとの違いは以下コミュニティ資料が役立ちます。

https://live.paloaltonetworks.com/t5/general-topics/url-filtering-pandb-vs-brightcloud/td-p/32283

https://live.paloaltonetworks.com/t5/%E3%83%8A%E3%83%AC%E3%83%83%E3%82%B8%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88/pa%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-url%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0-pan-db/ta-p/95652

## プロファイルの作成
URLフィルタリングを適用するためには、まずURLフィルタリングプロファイルの作成が必要になります。
プロファイルの作成では、主にPANDBが用意しているカテゴリに対して許可・拒否の設定を行います。
（例：アダルト系、ギャンブル系、マルウェア、フィッシング系は拒否など）
ただ、このPANDBによるカテゴライズは定期的に変更される可能性がある（Wildfireの判定結果等）ため、昨日まで閲覧できていたサイトが今日になったらマルウェアサイト扱いになっていてアクセスできなくなったなんてことはよくあります。
その回避策としては以下の２つがあります。

・オーバーライド
・サイトのカテゴリ変更依頼申請

オーバーライドに特定のURLを記述すると、PANDBのカテゴライズよりも優先して処理されます。
オーバーライドには許可リスト、ブロックリストの2種類が登録できるため
例えば上記のように急にアクセスできなくなったサイトも許可リストに登録すればすぐにアクセスできるようになります。
オーバーライドの記述方法については、以下サイトが参考になります。
https://docs.paloaltonetworks.com/pan-os/8-1/pan-os-admin/url-filtering/url-filtering-concepts/block-and-allow-lists

【PaloaltoのURLフィルタリング処理優先度】

1.オーバーライド（ブロックリスト）
2.オーバーライド（許可リスト）
3.カテゴリ(カスタムURLカテゴリ)
4.DP URLキャッシュ
5.MP URLキャッシュ
6.カテゴリ(PANDBカテゴリ)

3のカスタムURLカテゴリは、PANDBのカテゴリではなく自分でURLカテゴリを作成できるものになります。
個別に許可サイト・ブロックサイトを登録できるため、こちらオーバーライドではなくこちらを利用するケースもあります。

Test A SiteというサイトからPaloalto社にサイトのカテゴリ変更依頼を申請することもできます。
申請してから実際に変更処理が行われるまで時間がかかる場合もあリます。
そのため、急にアクセスできなくなったサイトへの対応についてはまずオーバーライドして運用上回避したあとに申請を行うケースが多いと思います。

## セキュリティポリシールール

該当のポリシールールに、プロファイル設定で作成したURLフィルタリングプロファイルを割り当てます。
尚、PaloaltoのURLフィルタリングはポート、プロトコルに依存せず動作するので、HTTP、HTTPS以外のポリシーに適用しても動作します。

## SSL復号化とURLフィルタリング
一般的にSSLインスペクションなどと呼ばれていますが、PaloaltoでHTTPSなどの暗号化された通信でURLフィルタリングを動作させるためには復号化ポリシーも合わせて設定する必要があります。
宛先URLアドレスも暗号化されておりURLの中身を見ることができなければPaloaltoもフィルタリング判別ができないからです。

この復号化ポリシーのルール条件にはURLカテゴリやカスタムURLカテゴリを利用することができます。
復号化専用のカスタムURLカテゴリを作成しておくことを推奨します。
scrapboxのtexで角括弧が使いたい

# 概要

scrapboxで数式を書くときにtex記法で記述する事ができるが、各括弧([])を書くときのエスケープ方法が毎回分からなくなるので、備忘のため掲載

# やり方

[]はそれぞれ`\lbrack`と`\rbrack`を使えばよい


例えば、以下のような数式を書きたい場合、

```math
V[X] =E[X^2]-E[X]^2
```

texでは以下のように記述するが、

> V[X] =E[X^2]-E[X]^2

scrapboxなら以下のように記述すればよい

`[$ V\lbrack X \rbrack = E\lbrack X^2 \rbrack - E\lbrack X \rbrack ^2`
react-scripts によってクリアされるログを確認する

# react-scripts によってクリアされるログを確認する

`create-react-app` により作成されたプロジェクトの `yarn start` のログが消えてしまい困っていたところ
以下の Issue にて対応案が記載されていました。

[Disable console clearing in `npm start` #7640](https://github.com/facebook/create-react-app/issues/7640)

> 
**Describe alternatives you've considered**
The only workaround that I've found to work is to invoke the dev server with:
> 
```sh
COLOR=1 npm start | cat
```

`cat` で受けることによりクリアされるはずの内容も確認することができました。
色は白一色になりますが・・・
AWS☆☆☆☆ デプロイまでの道のり４-最終章（短いバージョン、全４回）

###  <font color='lightblue'>１）背景</font>
第４回目の最終章です。
自身のポートフォリオをデプロイしました。最後の作業としてドメインの紐つけをします。
AWS関連手順記事はすごく多いので、ここでは備忘録も含めて、非常に端的に手順を記載します。


###  <font color='lightblue'>２）環境</font>

| 項目              |               内容 | 
|:-----------------|:------------------:|
| OS.Amazon Linux AMI      |            release 2018.03 |            
| Ruby             |            v2.5.1 |  
| Ruby On Rails    |           v5.2.4.3 |  
| MySQL    |           v5.6 |  
| Unicorn    |           v5.4.1 |  


###  <font color='lightblue'>３）内容</font>
<font color='blue'>**以下設定で65分程度かなと思います。（段取りが分かっていれば、30分）**</font>
※【ローカルマシン】指定以外は、全てAWSでの作業になります。

####  （1）お名前ドットコムからドメインを取得(20分)
同サイトからドメインを契約します。ここについては割愛いたします。

####  （２）Nginxの導入と設定(20分)
- yumパッケージを活用してNginx（webサーバ）を導入する
- Nginxのconfigファイルを設定する
- Nginxのパッケージ権限の付与（/var/lib/nginx）
- Unicorn設定ファイルの変更(Nginxを経由して処理を行うために設定)

####  （３）AWS-Route53の設定(10分)
- ホストゾーンの新規作成
- 新規レコードセットに同ElaspicIPを登録する

####  （４）お名前ドットコムの設定(15分)
- AWSで新規に割り当てられたNSレコードをネームサーバ名として登録する
- DNS設定（ElaspicIPと、ドメインの紐付けを行う）

####  （２）Nginx設定2(10分)
- 登録したドメイン名を同設定ファイルに設定する。

これで完了です。
指定のドメインにアクセスすると、NGINXを介してUnicornが起動しているrailsアプリを参照することが出来ます。
正直簡単です。出来るだけ難しく書かないように端的に記載しました。
以上です。
データサイエンス100本ノック~初心者未満の戦いpart2

これはデータサイエンティストの卵がわけもわからないまま100本ノックを行っていく奮闘録である。
完走できるか謎。~~途中で消えてもQiitaにあげてないだけと思ってください。~~

[100本ノックの記事](https://codezine.jp/article/detail/12456)
[100本ノックのガイド](https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess/blob/master/docker/doc/100knocks_guide.pdf)


**ネタバレも含みますのでやろうとされている方は注意**

今回は１０～１８まで
[目次付き初回](https://qiita.com/sola_wing529/items/5fdbd97308dd88da28eb)

今回から、自分で書いたモノが成功してるとは限らず、答えを見ながら書いていたり、失敗例も書いてあります。

#10本目
```mine10.py
df=df_store
df[df['store_cd'].str.contains('S14')].head()

'''模範解答'''
df_store.query("store_cd.str.startswith('S14')", engine='python').head(10)

'''失敗例'''
import re
df=df_store
df[None != re.match(r'S14.*',str(df['store_cd']))]
#>(中略)KeyError: False
```
**一目見て「SQLでLIKE使えば一発じゃねぇか！？」と思いました。**
とりあえず、~~心の友~~reマッチングに突っ込んで解決しようとする。が、文字列型じゃないことに気づいたり、この書き方だと頭1文字マッチングしてもNoneで帰らなかったり~~そもそもKeyErrorを起こし続けたので~~別の手段を模索。

すると、`df.str.contains`というものを見つけて感動。
内部も正規表現で書けるので無敵感を覚えながら使用したが、模範解答は~~更にﾜｹﾉﾜｶﾗﾅｲ~~メソッドを使用。
`engine='python'`はおまじないのようなものらしい[[参考]](https://note.nkmk.me/python-pandas-query/)

#11本目
```mine11.py
df=df_customer
df[df['customer_id'].str.contains('1$')].head()

'''模範解答'''
df_customer.query("customer_id.str.endswith('1')", engine='python').head(10)
```
引き続きSQLのありがたさを教えてくれる問題。
記事をある程度書いて復習が終わったらリファレンスを読み直して`df.str`以下のメソッドも調べてみます。

#12～15本目
```mine12.py
df= df_store
df=df[df['address'].str.contains('横浜市')]
df

'''模範解答'''
df_store.query("address.str.contains('横浜市')", engine='python')
```
```mine13.py
df=df_customer
df=df[df['status_cd'].str.contains('^[A-F]')]
df.head(10)

'''模範解答'''
df_customer.query("status_cd.str.contains('^[A-F]', regex=True)", engine='python').head(10)
```
```mine14.py
df=df_customer
df=df[df['status_cd'].str.contains('[0-9]$')]
df.head(10)

'''模範解答'''
df_customer.query("status_cd.str.contains('[1-9]$', regex=True)", engine='python').head(10)
```
```mine15.py
df=df_customer
df=df[df['status_cd'].str.contains('^[A-F].*[0-9]$')]
df.head(10)

'''模範解答'''
df_customer.query("status_cd.str.contains('^[A-F].*[1-9]$', regex=True)", engine='python').head(10)
```
```mine16.py
df=df_store
df=df[df['tel_no'].str.contains('[0-9]{3}-[0-9]{3}-[0-9]{4}')]
df.head(10)

'''模範解答'''
df_store.query("tel_no.str.contains('[0-9]{3}-[0-9]{3}-[0-9]{4}', regex=True)", engine='python')
```
感想が無くてすいません。query使わなくてすいません。~~お前書きながらエラー吐かないから怖いんだよ~~

尚、`regex=True`は「正規表現を利用する」ということらいしい[[参考]](https://note.nkmk.me/python-pandas-str-contains-match/)


#17本目
```mine17.py
df_customer.sort_values('birth_day', ascending=True).head(10)
```

**唐突に来る別パターン**
これに関しては~~忘れていたので~~調べながら記述しました。
`ascending`はSQLの`ORDER BY ASC`と同じ意味かな？

#18本目
```mine17.py
df_customer.sort_values('birth_day', ascending=False).head(10)
```
SQLと違うのは`DESC`を使うのではなく`ascending=False`とする部分。


#今回はここまで
**ここまではよかったんだ。ここまでは。**

1,2は消化試合感もある復習でしたが、ここからは知識を組み合わせられるかが試される問題が増えてきます。
~~知識が足りてない~~自分には難しい問題が多かったので、少しゆっくりとしたペースで進みたいです。飛ばす部分もありますが(21,22とか)。
ダークモード対応時にObjective-Cのコードがあったとき

# はじめに
歴史のあるiOSアプリのプロジェクトになると、Swift移行が完全でなくObjective-C（以降、objc）のコードが残存していたりするかと思います。

自分の関わるプロジェクトでは、ダークモード対応するぞ！ってなったときに、objcのコードが残っていたので一部objcで対応しました。

# コードから直接カラーセットを利用する
Storyboard上のパーツにカラー指定すれば基本的には対応できますが、中にはコード上でカスタムカラーを指定している場合もあります。 

Swiftで記述する場合は`enum`でカラーセットを定義してそれを利用するとか、`UIColor`のextensionでカスタムカラーを定義する方法があるかと思います。

自分の関わったプロジェクトでは前者の方法で対応していたため、objcでenumを使えませんでした。
objc用で列挙型を定義するのもありかもしれませんが、いずれobjcを撲滅することを考えるとわざわざ定義するのに工数もかけたくありません。
直接呼び出せればいいやって感じです。

その時は以下のようにします。

```objc
// ラベルの文字色を決めるとき
textLabel.textColor = [UIColor colorNamed: @"hogehoge"];
// 画像の枠の色を決めるとき
imageView.layer.borderColor = [[UIColor colorNamed: @"hugahuga"] CGColor];
```

一応、Swiftだとこんな感じになります。

```swift
// ラベルの文字色を決めるとき
textLabel.textColor = UIColor(named: "hogehoge") ?? UIColor.black
// 画像の枠の色を決めるとき
imageView.layer.borderColor = UIColor(named: "hugahuga").cgColor ?? UIColor.black.cgColor
```

意外と簡単にカラーセット呼び出せるんですね。
早くobjc撲滅してSwiftで綺麗にしたい。

# ライトモードとダークモードの切り替え時の対応
`traitCollectionDidChange`を利用して、モードが切り替わったことを検知して、そのときにカスタムカラーの更新をかけます。

```objective_c

- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
    [super traitCollectionDidChange:previousTraitCollection];
     
    if (@available(iOS 12.0, *)) {
         UIUserInterfaceStyle currentStyle = self.traitCollection.userInterfaceStyle;
         UIUserInterfaceStyle previousStyle = previousTraitCollection.userInterfaceStyle;

        if (currentStyle != previousStyle) {
            //カスタムカラーの更新処理を記述する
        }
    }
}
```

Swiftでも基本的に同様の書き方です。

```swift
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    
    if #available(iOS 12.0, *) {
        let previousStyle = previousTraitCollection?.userInterfaceStyle
        let currentStyle = traitCollection.userInterfaceStyle

        if previousStyle != currentStyle {
            // カスタムカラーの更新処理を記述する
        }
    }
}
```

# 参照
1. [colorNamed: - UIColor | Apple Developer Documentation](https://developer.apple.com/documentation/uikit/uicolor/2877380-colornamed?language=objc)
2. [iOS13 ダークモード対応](https://re-engines.com/2019/10/23/ios13%E3%83%80%E3%83%BC%E3%82%AF%E3%83%A2%E3%83%BC%E3%83%89%E5%AF%BE%E5%BF%9C/)
3. [爆速でiOSアプリのカラー設定をするための\`extension\`と\`enum\`](https://fromatom.hatenablog.com/entry/2016/02/22/160004)
4. [Objective-Cのアプリをダークモード対応した](https://note.com/kaigian/n/nc8ff24a2f368)
【MySQL】MySQL 8 でユーザー作成しGRANTで権限追加する際にエラーが発生

```ruby:ターミナル
## MySQLに root で接続
$ mysql -uroot -p

## ユーザー作成
> CREATE USER 'homestead'@'localhost' IDENTIFIED BY 'XXX';

## ユーザーに全権限追加
> GRANT ALL ON *.* TO 'homestead'@'localhost' IDENTIFIED BY 'XXX';
>> エラー発生

## 権限の変更をデータベースに反映
FLUSH PRIVILEGES;
```

``GRANT ``でエラー発生
原因：MySQL8.0ではGRANT構文でユーザを作成できない
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
解決策

```ruby:ターミナル
## MySQLに root で接続
$ mysql -uroot -p

## ユーザー作成
> CREATE USER 'homestead'@'localhost' IDENTIFIED BY 'XXX';

## ユーザーに全権限追加
> GRANT all ON *.* TO 'homestead'@'localhost';

## 権限の変更をデータベースに反映
> FLUSH PRIVILEGES;
```
```ruby:log
## MySQLに root で接続
$ mysql -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 19
Server version: 8.0.19 Homebrew

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

## ユーザー作成
mysql>
mysql> CREATE USER 'homestead'@'localhost' IDENTIFIED BY 'XXX';
Query OK, 0 rows affected (0.00 sec)

## ユーザーに権限追加
mysql> GRANT ALL ON *.* TO 'homestead'@'localhost' IDENTIFIED BY 'XXX';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IDENTIFIED BY 'XXX'' at line 1
>> エラー発生
```



参考記事：https://www7390uo.sakura.ne.jp/wordpress/archives/456
【CircleCI】秘密鍵を旧式に変更した際にやったこと

CircleCIに鍵を設定して、その形式だと追加できないとエラーが起きました。秘密鍵の中身を確認するとヘッダー形式が BEGIN OPENSSH PRIVATE KEY と変わっていたので、そちらを旧式に直すことを目的にしています。

```
$ ssh-keygen -m PEM -f 旧式にしたい秘密鍵の名称
```

こちらで旧式に設定できます。詳細は以下の参考サイトで確認してください！

参考サイト
https://blog.adachin.me/archives/11554

## 秘密鍵を旧式に変更した際にやったこと

①更新した秘密鍵でcircleCIに登録し、fingerprintsをコピーする。

②config.ymlを更新、プルリク、mastarにマージ。

③しかし、現状これだと本番環境のサーバーにssｈログインする際、Permission deniedエラーが発生してしまいます。これを解消していきます。

④GitHubで改めて公開鍵を設定します。ローカルで.sshに入り、catで該当の公開鍵（id_rsa.pub等）の情報を閲覧・コピペしていきます。

⑤しかしまだsshログインできず…そこで、新たにEC2内で該当のsshユーザーにログインし、更新した秘密鍵に対応した公開鍵を登録しなおさなければいいけないことに気づきました。

まずはec2-userでsshログインし、下記のコマンドを実行。

```
sudo su - 該当のユーザー名
```
公開鍵の設定

```
[ユーザー@ip-10-0-10-10 ~]$ cd .ssh
[ユーザー@ip-10-0-10-10 .ssh]$ vim authorized_keys # GitHubに登録した公開鍵を追記
[ユーザー@ip-10-0-10-10 .ssh]$ chmod 600 authorized_keys
```

これで無事該当ユーザーでsshログインできるようになりました！
Ubuntu 20.04 LTSでVNC

#これは何？
Ubuntu 20.04 LTSでVNCを設定したときのメモ。
注意：暗号化をOFFでセキュリティについてのケアをしない接続方法です。

# 手順
1. 設定 > 画面共有 から接続を許可する（パスワードにする場合は8桁まで）
2. VNCサーバ(vino)のEncryptionをOffにする
3. Portを開放しufwを有効化する
4. VNCクライアントから接続する

### 1. 設定 > 画面共有 から接続を許可する（パスワードにする場合は8桁まで）
以下が参考になります。
- [画面共有の設定 - MacからUbuntu18.04へのリモート接続設定備忘録(UFW設定方法付き)](https://qiita.com/y-vectorfield/items/c5fd815a9cabe5c2d6d8#%E7%94%BB%E9%9D%A2%E5%85%B1%E6%9C%89%E3%81%AE%E8%A8%AD%E5%AE%9A)

また、ネットワークに対しての許可を与えることをコマンドで実行する場合は以下が参考になります。
- [開発メモ その162 Ubuntu 18.04でVINOをコマンドラインから有効化する – A certain engineer "COMPLEX"](https://taktak.jp/2019/01/02/3938)



### 2. VNCサーバ(vino)のEncryptionをOffにする
```bash
$ gsettings set org.gnome.Vino require-encryption false
```

以下を参考にしました。
- [sharing - VNC Viewer unable to connect: Encryption Issue - Ask Ubuntu](https://askubuntu.com/questions/1126714/vnc-viewer-unable-to-connect-encryption-issue)


###  3. Portを開放しufwを有効化する
※ 以下のコマンドではPortは5900に指定しています。

```bash
$ sudo ufw allow from any to any port 5900 proto tcp
$ sudo ufw enable && sudo systemctl start ufw
```

以下のコマンドで動作の確認をする。

```bash
$ sudo systemctl is-active ufw
$ sudo ufw status
```

ついでにIPアドレスも調べる。

```bash
$ ip addr
```

### 4. VNCクライアントから接続する

VNCクライアントを起動して、以下を指定する。

```
vnc://[3で調べたIPアドレス]:[3.で指定したPort]

(例) vinoが動作するUbuntuのネットワーク機器のIPアドレスが192.168.0.250、Portを5900と指定した場合。
 vnc://192.168.0.250:5900
```


# コメント
どうしてもLinuxから操作の必要はあるときにUSBメモリからのBootするのはいいが、作業の進捗確認の度に物理的にディスプレイケーブルを接続し直したりするのが面倒なときに使います。SSHが切断されて、途中で作業中断したりすることの不安を解消する効果があると思っています。
渗透经验分享之文件操作漏洞拓展

上文分享了注入相关的东西，注入也可以对文件进行操作，本文是对文件操作漏洞的拓展。

# 文件操作漏洞
1. 文件上传
2. 文件读取
3. 文件写入
4. 文件删除
5. 文件包含

一般java的站点存在文件系列的洞比较多(除了文件包含)。

# 文件上传
在哪最容易发现上传点？注册登陆用户头像、发布文章发布产品、js中的文件上传接口、一些编辑器，甚至还有扫目录扫出来的`/uploader`路径，访问出现这种405的uploader一般就是上传。比如：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/84b74880-49ec-26bf-2eaf-e5b565db1e4f.png)

这个时候本地构造POST表单就行了，file参数靠猜，有的时候任意参数就行，有的时候post提交过去会报错缺失什么参数，随机应变。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/cef3ccd8-caca-871a-80d8-8e3b54ba9cb0.png)

一般上java的站点扫出来这种uploader比较多，都是上传写的servlet接口。

上传其实upload-labs里的绕过姿势已经非常全面了。拿到一个上传点，首先应该判断能不能正常上传、白名单还是黑名单、怎么校验的在哪校验的，这些没什么好讲的。聊一些比较恶心的文件上传。

1. 上传不返回路径
2. 上传不在web目录

上传不返回路径多出现在`市长邮箱`、`投诉举报`这类功能中，其实这种功能本来就没打算给你返回路径。我的思路一般是找注入点，只要没返回路径的文件上传并且返回给你一个ID给你当作凭据的(此处只是举例，类推)，肯定保存路径在数据库中。找到注入就等于找到了文件路径。

如果没有注入呢？找找日志。比如tp的日志是有规律的，你可以传一个非法文件名`1.;`，在tp的日志中报错，说不定就有路径。这个我自己是真实碰到的，一个laravel的框架，在laravel.log中报错返回了错误文件名的文件路径，猜出来了shell的路径。

如果没有日志呢？猜。形如`/Files/`、`/uploads/`目录，猜要有根据的猜，观察网站的图片和文件地址，以此拼接你的shell文件名，多数以时间戳命名，bp爆破下就行了。

再来说不在web目录的，上传的时候关注下请求包的几个参数，有没有`path`、`filepath`、`filename`、`file_prefix`，甚至测一下`../../1.jpg`文件名。如果上传不能跨目录其实你就应该转移关注点了。找文件包含、文件读取。

上传不在web目录的站，有这种功能的很多都有文件读取的洞，因为传上去的文件总归是要下回来的，找找形如`download?path=1.jpg`这种。拓展思路，举一反三。

另外就是文件包含了，没啥可说的。

# 文件读取
限制条件有两个

1. 限制前缀
2. 限制后缀

不限制前缀的时候可以通过`file`协议读文件，php可以通过伪协议读文件，当限制前缀的时候Linux其实还好，可以通过`../`跳目录，但是windows没办法通过`../`跳盘符。

限制后缀就比较恶心了，php好像可以用`#`、`?`符号去绕过。具体看 [chybeta师傅的文章](https://chybeta.github.io/2017/10/08/php%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB%E6%BC%8F%E6%B4%9E/#%E6%8C%87%E5%AE%9A%E5%90%8E%E7%BC%80) 吧。

确定是文件读取之后，如何进一步拿权限？个人习惯先读`/etc/passwd`，权限够大直接读`/etc/shadow`，然后根据`/etc/passwd`读每个用户的`.bash_history`，读中间件的配置文件，以此判断web的绝对路径。然后逐个读源码，java的话可以读一下war包，搞到代码之后就变得`so easy`了。

举个例子：文件读取读到了旁站的war包，旁站是一个监控，就一个登陆框，而war包中配置文件里写死了密码，刚好登陆进去直接可以执行命令rce。

weblogic的话可以直接读console账号密码，登陆console部署war包getshell。

反正就是文件读取=60%中间件特性+10%猜+30%运气。

# 文件写入
文件写入拿shell很简单，直接指定web目录和内容就行了。但是这个一般上会有限制，比如内容检测(不能写php标签之类)，文件名检测(不能写`.php`)。

1. 写计划任务**或许**为一个好的选择
2. 覆盖原有配置文件(比如覆盖安装锁)
3. 写ssh

文件写入好像没什么好说的，先就这样，想到什么补充什么。

# 文件删除
实战没怎么遇到过这个洞

1. 删除配置文件
2. 删除安装锁(造成重装)
3. 删除waf文件`include waf.php`

# 文件包含
文件包含多为php站点，所以伪协议读文件这些都是基本操作。不过有一说一，除了ctf中碰到过文件包含，实战中没遇到过。

具体看 [chybeta师傅的文章-php文件包含漏洞](https://chybeta.github.io/2017/10/08/php%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB%E6%BC%8F%E6%B4%9E/) 

需要提一嘴的是phar可以伪装为图片，你可以传一个1.jpg，绕过内容检测，然后用`phar://`协议包含。还有就是smb包含，php缓存文件包含。


--- 
或许渗透变化万千的思路才是我真正喜欢他的原因。
AWS Lambda Nodejsのバージョンが8から12に強制アップデートされたら Error: Cannot find module 'jmespath' と出る問題

# 要約
AWS Lambdaで利用するnodejsのバージョンが nodejs8 -> nodejs10以降のアップデートすると aws-sdkが組みこまれるようになるため
node_modulesにaws-sdkを含んでいるとエラーになるので、取り除く必要がある

# 本文

nodejs8で書かれたAWS Lambdaスクリプトは非推奨となりました。
AWS Lambdaのnodejs10やnodejs12環境で同じスクリプトを実行すると、以下のようなエラーメッセージが表示される。

```
{"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'jmespath'","stack":["Runtime.ImportModuleError: Error: Cannot find module 'jmespath'","    at _loadUserApp (/var/runtime/UserFunction.js:100:13)","    at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)","    at Object.<anonymous> (/var/runtime/index.js:36:30)","    at Module._compile (internal/modules/cjs/loader.js:701:30)","    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)","    at Module.load (internal/modules/cjs/loader.js:600:32)","    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)","    at Function.Module._load (internal/modules/cjs/loader.js:531:3)","    at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)","    at startup (internal/bootstrap/node.js:283:19)"]}
```

モジュール'jmespath'自体はpackage.jsonをみても見つからない、普通のモジュールの場合は、 requireの書き方を修正しすればよいが、
**aws-sdkの場合は対応が異なる**

```
# この様になっているものを
var aaa = require('foobar')

# このように相対パスを指定してあげれば良い
var aaa = require('./foobar')

```
node_moduleを使って`aws-sdk`下記のように呼び出している場合は aws-sdk を node_modulesから削除する必要がある

```
var aws = require('aws-sdk');
```


aws-sdkを取り除くyarnの場合

```
yarn remove aws-sdk
```

aws-sdkを取り除くnpmの場合

```
npm uninstall aws-sdk
```

nodejs10 から lambda に aws-sdk が追加されました。 see: https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html
【Java】特定の曜日の日を取得する

忘備録として

LocalDateを使うとかんたん。

```java

// 今日
LocalDate now = LocalDate.now();    // 2020-06-23：火曜日

// 今週の金曜日
LocalDate thisFriday = now.with(DayOfWeek.FRIDAY);    // 2020-06-26

// 先週の水曜日
LocalDate lastWednesDay = now.minusWeeks(1).with(DayOfWeek.WEDNESDAY);    // 2020-06-17

// 来週の木曜日
LocalDate nextThursDay = now.plusWeeks(1).with(DayOfWeek.THURSDAY);    // 2020-07-02

// おまけ　LocalDateTimeへ変換
LocalDateTime from = lastWednesDay.atTime(00, 00, 00);    // 2020-06-17 00:00:00

```

### 参考

[日本人のための Date and Time API Tips (ja)](https://www.coppermine.jp/docs/notepad/2013/12/jsr310-tips.html)
[【Java】過去週の月曜日と日曜日の日付を順番に取得する @kazokclily](https://qiita.com/kazokclily/items/3364e25b612487ddac05)
Docker内のJooby(Kotlin × Gradle)をホットリロードさせながらIntelliJでRemoteDebugする

#1-やること
タイトルの通り、DockerやIntellijの実行構成を含んだ全部入りリポジトリはこちら
[Githubリポジトリ](https://github.com/TakuyaShirosaka/RemoteDebugJooby)

#2-完璧でないところ
・後述のjoobyRunを行った後、RemoteDebugを走らせないとホットリロードが動きません。
　→裏でport5005に対する接続待ちが起きてる？？

・ブレークポイントで止まっている間はホットリロードが効きませんでした。

#3-ポイント
・Docker内のJDKとIntelliJのJDKは合わせよう！
　→この記事ではamazoncorretto:11でそろえてます。

・docker-compose.yml:　environmentに環境変数GRADLE_OPTSを指定

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

services:
  app:
    shm_size: 4096m
    build: "./build/app"
    ports:
      - '8015:8080'
      - '5005:5005'
    
    volumes:
      - "./app:/app"
    
    environment:
      TZ: 'Asia/Tokyo'
      GRADLE_OPTS: '-Dorg.gradle.jvmargs=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005'
      
    working_dir: /app
    
    cap_add:
      - SYS_ADMIN
    security_opt:
      - seccomp:unconfined
    tty: true
```
・IntelliJにdocker-compose用の実行構成を作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309466/966c188a-f41d-1bfa-b451-5323a4f5a45b.png)

・RemoteDebug用の実行構成を作成
　Command line arguments for remote JVMの内容が先述の「GRADLE_OPTS」とイコールになるはず
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309466/88354890-de1b-8351-bc21-93c1f34376d4.png)

・docker-composeの起動構成を実行→コンテナ内部でjoobyRun実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309466/379cff96-e9c5-60c7-3012-e63784ad665a.png)

```
コマンド実行
./gradlew joobyRun
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309466/25991d71-9353-ff28-9bb9-dbb3ba11a328.png)

・RemoteDebugの起動構成を実行→適当に置いたブレークポイントを通るパスにアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309466/5dcc628b-41dd-9f42-0b55-c3ad3206b66c.png)

```
以下にアクセス
http://localhost:8015/
```
ブレークポイントで止まる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309466/9f8acd80-c391-cdd2-75a1-fc5743d84f61.png)

ソース修正するとホットリロードが行われる
※ブレークポイントで処理停止させている場合は勿論効かないです。(重要なので二度目)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309466/e9bcb787-4bc1-0e76-93ef-57312b089470.png)

#4-おわり
・dockerでローカルを汚さないかつ、IntelliJの強力なアシスト+joobyRunでのホットリロード+RemoteDebug
　LL言語並みに高速でリコンパイルされるわけでないですが、これで開発がとても楽になります。


>・後述のjoobyRunを行った後、RemoteDebugを走らせないとホットリロードが動きません。
　→裏でport5005に対する接続待ちが起きてる？？

回避策としてはRemoteDebugが不要な時はdocker-compose.ymlのGRADLE_OPTSをコメントアウトすれば良いです。
Swift5.3の変更点

取り急ぎ、Swift Language Guideに掲載されている箇所をまとめておきました。

## 末尾クロージャ（追加）
複数のトレーリング・クロージャに関する情報をトレーリング・クロージャのセクションに追加しました。
https://docs.swift.org/swift-book/LanguageGuide/Closures.html#ID102

## プロトコル（追加）
合成された実装を使用したプロトコルの採用のセクションに、列挙のための Comparable の合成された実装に関する情報が追加されました。
https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID627

## 状況に応じたWhere句（追加）
より多くの場所で一般的な where 節を書くことができるようになり、コンテキストに応じた where 節のセクションが追加されました。
https://docs.swift.org/swift-book/LanguageGuide/Generics.html#ID628

## 所有されないオプショナル参照（追加）
オプション値での未所有の参照の使用についての情報を持つ、未所有のオプション参照セクションを追加しました。
https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html#ID625

## @main属性（追加）
main セクションに @main 属性に関する情報を追加しました。
https://docs.swift.org/swift-book/ReferenceManual/Attributes.html#ID626

## リテラル式（追加）
リテラル式のセクションに #filePath を追加し、#file の説明を更新しました。
https://docs.swift.org/swift-book/ReferenceManual/Expressions.html#ID390

## クロージャのエスケープ（更新）
Escaping Closuresセクションを更新し、より多くのシナリオでクロージャが暗黙的に自己を参照できるようになりました。
https://docs.swift.org/swift-book/LanguageGuide/Closures.html#ID546

## エラー対処（更新）
Do-CatchとDoステートメントを使用したエラーの処理セクションを更新し、キャッチ句が複数のエラーにマッチするようになりました。
https://docs.swift.org/swift-book/LanguageGuide/ErrorHandling.html#ID541

## プロパティ・オブザーバ（更新）
遅延プロパティがオブザーバを持つことができるようになりました。
https://docs.swift.org/swift-book/LanguageGuide/Properties.html#ID262

## プロトコル宣言（更新）
プロトコル宣言セクションを更新し、列挙のメンバがプロトコルの要件を満たすことができるようになりました。
https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID369

## プロパティ・オブザーバ（更新）
ストアド変数オブザーバとプロパティオブザーバのセクションを更新し、ゲッターがオブザーバの前に呼び出される場合について説明しました。
https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID359
Docker初心者に立ちはだかるエラー

下記サイトからDockerを学んでいるときに出会ったエラー
https://tech-lab.sios.jp/archives/19191

Dockerイメージを作ろうと
docker buildをした際に起こりました。
```Sending build context to Docker daemon```
がひたすら続くというエラー。。
下のようなエラーも出たりで、、

    ERRO[0529] Can't add file /Users/shingo/Library/Application Support/Code/1.45.1-main.sock to tar: archive/tar: sockets not supported 
    ERRO[0529] Can't add file /Users/shingo/Library/Application Support/Code/1.45.1-shared.sock to tar: archive/tar: sockets not supported

一向にイメージを作れる気配もなく、中断しました。

色々と調べた結果
https://ytooyama.hatenadiary.jp/entry/2018/04/06/003019
この記事を発見！

Dockerファイルをホームディレクトリに作成し、docker buildを実行していたので
DockerクライアントからDocker daemonに対して、ホームディレクトリ配下のファイルを全て転送していたようです。
~/working/dockerディレクトリを作成し、そこにDockerfile「だけ」を作成しました。
その後
buildが成功しました。

なんとも簡単な、、

PC
余計な仕事させてごめんよ！！
TypeScript+Vue.jsの環境でnullableなpropsを指定する

TypeScript+Vue.jsの環境でVue.jsのコンポーネントでpropsを使っているときに、nullableなtype指定をどうやってやるかを説明します。

# 結論
Typescriptの方の型指定だけnullableであることを明示します。

```vue:title.vue

<template>
<h1>{{ title }}</h1>
</template>

<script lang="ts">
import { createComponent, SetupContext } from '@vue/composition-api'

export default createComponent({
    props: {
        title: {
            type: String as () => string | null,
            default: null
        }
    }
})
</script>

```

そもそもなのですが、Vue.jsのpropsはすべてnullableなので、nullableにするときに`[String, null]`というようにnullをpropsのtypeに書く必要はありません。

よって、TypeScript側にだけnullableだということを教えればよいです。
WWDC 2020 keynote：動画配信の視点で気になった点



AppleのWWDC 2020 (https://www.apple.com/apple-events/june-2020/ )の基調講演を見て、動画配信の目線で気になった点を簡単にまとめておきます。

# Picture in Picture機能がiOSにも追加

元々、既にiPadOSでは搭載されていた機能ですが、iOS 14からiPhoneでもPicture in Pictureが使えるようになります。
ネイティブのプレイヤーを利用していれば、問題なく使えると思いますが、サービスのコンセプトやコンテンツフォルダーとの許諾の関係上、そもそも許可したくない場合なども考えられますので、注意が必要です。

# iOS/iPadがApple SiliconのmacOSで動く

※SoCやらCPUの知識が乏しいため、不確かなことを書いていたらご指摘ください。

元々、昨年のmacOS Catalinaから、Mac CatalystでiPadアプリケーションをmacOSに提供することはできましたが、あくまでiPadアプリをmacOS向けに変換するものでした。

Apple SiliconはiPhone/iPadと同系のSoCになりますので、おそらくアプリの変換なく利用できるようになるはずです。

ストアの設定でmacOS向けに公開するかどうかの選択くらいはできると思いますが、macOSに対して展開した場合に

- 権利の許諾関係に問題はないか
- DRMが正しく動作するか
- アプリの画面サイズはどういう扱いになるか（自由になると厄介ですね）

など、色々と検証が必要そうです。

# macOSはしばらくの間、Intel系とApple Silicon系が並行して存在する

Apple Silicon搭載のMacは2020年末に発売予定で、2年間の移行期間があるようです。
移行期間の意味をどうとらえるか悩みどころですが、メジャーアップデートが2年という意味で、Intel Macのシェアがすぐ縮小するとは思えません。

同じmacOSと言えど、Intel MacとApple Siliconの挙動が完全に一致はしないのは間違いないでしょう。特にSafariでの動画再生は両方の検証をしておく必要がでてくると思われます。

参考）アップル、MacのCPUを「Apple Silicon」に。年内に最初の製品、2年で切替
https://www.watch.impress.co.jp/docs/news/1260710.html