OmniAICreator/Qiita-1.07M huggingface dataset:
ファイル転送プロトコルに関する学習メモ

# はじめに
ファイル転送プロトコルに関して、違いがよくわかっていなかったためまとめる。あくまでも学習メモなので、間違えていることもあるため参考程度に。

# FTP
FTPとは、「File Transfer Protocol」の略。ファイルを転送する際の約束事。
クライアント・サーバーモデルで動作している。FTPクライアントを用いて、ファイルの転送を行う。

FTPは、利用者の認証情報（ユーザー名、パスワード）やファイルなど、***通信の一切を暗号化しない***。そのため、セキュリティの観点から見て安全ではない。こういった点から、暗号化して通信するプロトコルが推奨されている。

# FTPS
FTPSとは。「File Transfer Protocol over SSL/TLS」の略。FTPで転送する情報を、***SSL/TLSを用いて暗号化するプロトコル***。

## SSL/TLSとは？
SSLは「Secure Sockets Layer」の略で、送受信しているデータを暗号化する通信手順。
WebサイトのURLアドレスが、httpsから始まっている（URLに鍵マークがついている）ものはSSL化されている。

TLSは「Transport Layer Security」の略。SSLの脆弱性が発見され、それに対処するために設計されたのがTLS。そのため現在SSLは実はTLSである場合がほとんどだが、なじみ深いSSLという言葉が使用されている。

SSL/TLSは、***共通鍵暗号方式と公開鍵暗号方式を用いて、通信を暗号化する仕組み***。

### SSL/TLSの流れ
1. クライアント側からサーバー側に、SSL通信のリクエストを送る
2. サーバー側から「公開鍵」付きのSSLサーバ証明書が送付される
3. クライアント側で生成した「共通鍵」を「公開鍵」で暗号化してサーバー側に送付
4. サーバー側は、ペアとなる「秘密鍵」で複合し、「共通鍵」を取得
5. SSL/TLS暗号化通信開始


## 共通鍵暗号方式と公開鍵暗号方式
鍵：暗号化や複合化を行うために使うデータ

### 共通鍵暗号方式
送り手（暗号化する側）と受け手（複合する側）が同じ鍵を用いる暗号化方式のこと。
この鍵は、第三者に知られてしまうと意味がなくなるため注意。

メリット
・暗号化と複合化の計算が速い。

デメリット
・共通鍵を相手に安全に渡す必要がある点。
・やりとりする相手の数だけ鍵が必要になるため、鍵の管理が大変。

### 公開鍵暗号方式
共通鍵暗号方式のデメリットを解決することができるのが、公開鍵暗号方式である。
特徴としては、公開鍵と秘密鍵の２種類のカギが存在する。公開鍵のほうをほかの人に配布して、***送信者側にはこの公開鍵を用いて暗号化してもらう***。***受信者は、自分しかもっていない秘密鍵を用いてその暗号を複合する***。

公開鍵で暗号化されたものは、ペアの秘密鍵でしか複合できない。公開鍵はいくらばらまいても、そのカギでは暗号化しかできないため途中でデータを盗聴される心配などはない。
また、共通鍵暗号方式のように管理する鍵が増えてしまう心配もない。

ただ、共通鍵暗号方式と比べて暗号化や複合化に時間がかかるというデメリットもあるため使い分けが必要。

# SFTP
SFTPは「SSH File Transfer Protocol」の略。FTPで転送する情報を「SSH」で暗号化するプロトコル。

## SSHは？
SSHは「Secure Shell」の略。***ネットワークに接続された機器を遠隔操作し、管理するための手段。その際の通信を暗号化している。***SSLと同様に通信を暗号化するという意味では似ているが、混ざらないよう注意。

SSHとSSLの違いを大雑把に書くと
SSL：インターネットでのやり取りを暗号化。安全にWebサイトを表示するのが目的。
SSL：他コンピュータを遠隔操作する際のやりとりを暗号化。

# SCP
SCPは「Secure Copy」の略。SFTPと同様にSSHを利用しているためセキュリティ面で安全性の高いプロトコル。

## 共通点と相違点
### 共通点
- SSHプロトコルを使用
- パスワード認証だけでなく、秘密鍵を用いての通信が可能
- GUIベースのクライアントソフト、コマンドベースのどちらでも使用可能

### 相違点
SCP

- 転送の再開が出来ない
- SFTPに比べて高速と言われている
- フォルダの送信はできない（クライアントソフトを用いれば可能）

SFTP

- 転送を中断しても、途中から再開できる
- SCPより転送速度が遅い


# 参考
- [FTP、FTPS、SFTP、SCPの違いってなんなんだ？](https://liginc.co.jp/398039)
- [【図解】SSL/TLSとは何か？その違いや仕組み・導入方法についてわかりやすく解説します](https://www.kagoya.jp/howto/rentalserver/ssl/)
- [SSL/TLS暗号化通信の仕組み](https://jp.globalsign.com/ssl-pki-info/ssl_practices/ssl_encryption.html)
- キタミ式　基本情報技術者
- [【セキュリティ】共通鍵暗号・公開鍵暗号の仕組みについて解説します](https://keita-blog.com/programming/security-common-open)
- [「SSL」と「SSH」の違い](https://wa3.i-3-i.info/diff384security.html)
- [SCPとSFTPの違い](https://www.skyarch.net/blog/?p=379)

# まとめ
今回は、ファイル転送プロトコルとその周辺知識についてまとめた。
まずは今回のように広く浅く、知識を増やしていきたい。
IntelliJ IDEA でよく使うショートカット集

IntelliJ IDEA でよく使うショートカットをまとめました。
mac 環境を対象としています。
なお、 Preferences | Keymap でショートカットキーを変更できます。

## Navigation
### 参照箇所を検索 (Find Usages / Show Usages)
* Find Usages: ⌥ option + F7 (touch bar: ⌘ command + ⌥ option -> Find Usages)
* Show Usages: ⌘ command + ⌥ option + F7 (touch bar: ⌘ command -> Show Usages)

class, method, 変数など、指定した対象の参照箇所を検索できます。


### 宣言 / 参照箇所に移動 (Go to Declaration or Usages)
* ⌘ command + B
* ⌘ command + click
* Force click

宣言に対して実行すると参照箇所の一覧が表示されます。
参照に対して実行すると宣言に移動します。


### 継承 tree を表示 (Type Hierarchy)
* ⌃ control + H


### Class を検索 (Go to Class...)
* ⌘ command + O

もう一度 ⌘ command + O で検索範囲を Project から全体 (library など) に広げることができます。

途中の文字だけでも絞り込みができます。
例: QiiitaMainActivity -> `qma` のように入力するだけで上位候補に表示されます。


### File を検索 (Go to File...)
* ⌘ command + ⇧ shift + O

一つもファイルを開いていないときに表示される hint の1つですね。
![スクリーンショット 2021-04-10 18.03.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95517/14cc98e5-0e07-271c-f511-1a79269416ba.png)

もう一度 ⌘ command + ⇧ shift + O で検索範囲を Project から全体 (library など) に広げることができます。


### File 内検索 (Find...)
* ⌘ command + F


### File 内置換 (Replace...)
* ⌘ command + R


### Scope 検索 (Find in Path...)
* ⌘ command + ⇧ shift + F

Project, Module, Directory など、 scope を指定して検索できます。


### Scope 置換 (Replace in Path...)
* ⌘ command + ⇧ shift + R


## 編集関連
### コード補完 (Code Completion | Basic)
* ⌃ control + space

何もない空行で実行するとその scope で有効な様々なサジェストが出てきます。
method 名などを途中まで入力すると勝手に出てくるものと同じです。

※ mac の標準機能に割り当てらていた気がするので、標準機能かコード補完どちらかのキーを変更する必要があります。


### Comment in / out (Comment with Line Comment)
* ⌘ command + /

選択した行の comment 状態を変更できます。


### Rename (Rename...)
* ⇧ shift + F6 (touch bar: ⇧ shift -> Rename)

File, class, method, 変数名など、指定した対象の名前を変更できます。


### Move (Move...)
* F6 (touch bar: ⇧ shift -> Move File)

File などの場所移動ができます。


### 行削除 (Delete Line)
* ⌘ command + delete

指定した範囲の行を削除します。
範囲を指定しない場合は1行を削除します。


### 複製 (Duplicate Line or Selection)
* ⌘ command + D

指定した範囲を複製します。
範囲を指定しない場合は改行含む1行を複製します。
clip board を消費しないので何か copy している状態に便利です。


### 移動 (Move Statement Up / Down)
* ⌘ command + ⇧ shift + ↑ / ↓

class, method, 変数, 処理等の順序を入れ替えできます。


### Format (Reformat Code)
* ⌘ comamnd + ⌥ option + L

事前に指定した format rule で source code を format できます。


## Build & Run
### 実行 (Run)
* ⌃ control + R
Java11の開発環境構築 まとめ

# 背景
Javaの開発環境を整えようとして少し苦戦したので、その手順を自己理解のためにまとめてみました。
必要のなさそうな箇所や間違いがあればご教授頂けると幸いです。

# 環境
- macOS Big Sur ver11.2.2

# 手順
- ① homebrewのインストール
  - `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`
- ② homebrew-caskのインストール
  - `brew install alfred`
  - 参考資料: https://github.com/Homebrew/homebrew-cask
- ③ homebrew-cask-versionsのインストール
  - `brew tap homebrew/cask-versions`
  - 参考資料: https://qiita.com/morioheisei/items/ef8eb5d75c07b4d280f4#homebrew-cask-versions%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB
- ④ Javaのインストール
  - https://www.java.com/ja/
- ⑤ OpenJDKのインストール
  - `brew install java11`
  - `echo 'export PATH="/usr/local/opt/openjdk@11/bin:$PATH"' >> ~/.zshrc`
  - `export CPPFLAGS="-I/usr/local/opt/openjdk@11/include"`
  - `source ~/.zshrc`
  - 参考資料: https://qiita.com/ponsuke0531/items/9be8dee67a91c6c78d4f

# 補足
- `brew install alfred`が上手く行かない場合は、homebrewを[アンインストール](https://github.com/homebrew/install#uninstall-homebrew)してインストールし直す。

# おまけ
- [OpenJDKを手動でダウンロードする方法](https://www.javadrive.jp/start/install/index1.html)
- [[Mac]Big Surでhomebrew-caskを使うときの注意](https://qiita.com/luton-mr/items/83386f43c395ecec7736)
- [いつの間にかbrew caskが使用できなくなっていた話](https://www.mathkuro.com/mac/brew-cask-command-error/)

# 謝辞
ここで参考にさせて頂いた記事を作成した皆様に深く感謝致します。
【Vue.js】Google Fontsの使い方



#まずは公式ページでフォントを選ぶ

公式サイト：[Google Fonts](https://fonts.google.com/)

#フォントが決まったら[+ select this style]を押下

「**Use on the web**」という箇所があるので、そこで**import**を選択。

**import**が選択できたら下記コードをコピー

```vuejs
<style>
@import url('https://fonts.googleapis.com/css2?family=(選択されたフォント)&display=swap');
</style>
```

```
font-family: (選択されたフォント)；
```

#styleタグ内にペースト

これをコピーしてstyleタグ内に貼り付けます。

```vuejs:scss
<style scoped lang="scss">
@import url("https://fonts.googleapis.com/css2?family=(選択されたフォント)&display=swap");

.ttl {
    font-family: (選択されたフォント)；
</style>
```

たったこれだけでGoogle Fontsが使えるようになりました。
Jupyter notebook 起動時に [FileNotFoundError] が出るときの対処法

先日Jupyter-notebookが起動しない問題が起こり調べてもそれらしきサイトが存在せず苦労したため記事に残しておく．

# 環境
- OS: Windows10

#Jupyter-notebook を起動すると [FileNotFoundError] が出る．
jupyter-notebookを起動すると一瞬コマンドプロンプトが開きすぐに閉じる．
コマンドプロンプトやAnaconda Navigaterから起動すると下記のようなエラーが発生する．

```
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\work\\tls.keys'
```

#解決策
システム環境変数`SSLKEYLOGFILE`を削除する.
![bb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1294332/41261d7c-673d-7fb3-eadd-596fce5694d5.png)

以前Wiresharkを使った時に追加したこの環境変数が悪さをしていたらしい．
当時参考にしたであろうサイト: 
[【解析/Wireshark】https(SSL/TLS)を復号化する方法(SSLKEYLOGFILE),ブラウザで見る方法](https://milestone-of-se.nesuke.com/nw-basic/tls/decrypt-tls-at-executing-packetcapture/)

削除後にJupyter-notebookを実行すると問題なく動いた．
環境変数を書き換えた後はどこかにメモを残しておくのがいいだろう．
cookieを使って、見せるページを分岐させる。

自分のための忘備録です。
***


そのページに初回の人と2回目以降の人を分けて見せたいとかの時にクッキーでできるみたいです。
クッキーは簡単に設置できるみたいです。


##有効期限が一時間のクッキー設置
session_start()はいらないかもです。。

```php:htmlにphpで記入
<?php session_start(); ?>
<?php
  $value = 1;
  if(!isset($_COOKIE['visited'])) {
    setcookie("visited", $value, time()+3600);
?>

//ここに初回の人に見せる内容

<?php
exit;
}
?>

//ここに2回目以降の人に見せる内容
```



##問題点

ブラウザでクッキー無効にしていたら効かないみたいです。
クッキーの代わりにセッションというのがあるみたいです。



##クッキーとセッションの違い

**クッキー**・・・ブラウザに情報を残す
**セッション**・・・サーバーに情報を残す


##セッションの有効期限を変更するには
php.iniの「session.cookie_lifetime」を変更する必要があるみたいですが、
レンタルサーバー等では変更できるかどうかは確認しないとわからないです。
他にもphpの関数で設定できるみたいですが、これもレンタルサーバーでは効かないこともあるみたいです。


```php:セッションで有効期限１時間で設置
<?php
// セッションの有効期限を設定
session_set_cookie_params(3600);
 
// セッション管理開始
session_start();
 
if (!isset($_SESSION['visited'])) {
    $_SESSION['visited'] = 1;
?>
    //ここに初回の人に見せる内容
<?php
exit;
}
?>

//ここに2回目以降の人に見せる内容
```


##セッションの削除
テストとかするとき必要でした。

```php:php
unset($_SESSION['visited']);
```

***
参考しました。
https://www.sejuku.net/blog/25276
iOS libtorch をソースからビルドするメモ

## 背景

libtorch 1.8 になり, FFT モジュールとかついたので音声処理とか libtorch で完結できてよいので iOS で動かしたい.

オフィシャルでは Cocoapods での例を提示していますが...

https://pytorch.org/mobile/ios/


* XCode の設定, Cmake でやっている(Cocoapods だと xcodeproj ファイルとが無いと `pod install` できない)
* Cocoapod でインストールとかめんどい...
  * M1 macOS だと fft 周りで arm 対応しておらずコケる https://stackoverflow.com/questions/64901180/running-cocoapods-on-apple-silicon-m1
  * 最新 libtorch が得られない
  * いずれにせよ Cocoapod 使いたくない(Specs ファイルが git repo 管理されており 2 GB! もある) 

のでソースからビルドします.

## 手順

iOS ビルド用のスクリプトが用意されていますので, それを叩くだけです.

```
$ git clone https://github.com/pytorch/pytorch
$ cd pytorch
# (お好みで branch/tag をチェックアウト)
$ git submodule update --init --recursive
$ ./scripts/build_ios.sh
```

でいけます! 

M1 macmini では 12 分ほどでビルドが終わりました.

あとはビルドできたファイルをよろしく自前プロジェクトにコピーするなどして利用しましょう.



## TODO

* [ ] CI ビルドサーバか Cocoapods のダウンロード URL を探して iOS prebuilt パッケージを wget なりでぺろっと落とす方法を見つける
BERTでサクっと文章要約する

#はじめに
BERTを用いたテキスト要約のライブラリ```bert-extractive-summarizer```を見つけたので試してみた。あたかも自分がサクッと作ったような書き方になってしまったが、実際はこのツールがサクっとやってくれたという話。

#bert-extractive-summarizer とは
講義要約用のライブラリである。仕組みとしては、まず文章をエンベディングし、クラスタリングした後、重心に近い文章(クラスタを代表するもの）をピックアップしているようである。

講義用とは言え、他の文章にも色々使えそうである。
ちなみに本ライブラリは英語用であるが、自分は英語を要約したいのでこれで十分である。


#インストール
```
pip install bert-extractive-summarizer
```
実際には、pytorch等いくつか依存するライブラリがあるので、試行錯誤しながら入れてみよう。

#プログラム
コマンドラインで動かすプログラムを書いてみた。入力とするテキストファイル、出力ファイル、抽出文章の数を指定できる。

``` text_summarizer.py

import argparse
from summarizer import Summarizer


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("-input", type=str, required=True)
    parser.add_argument("-num_sentences", type=int, default=5)
    parser.add_argument("-output", type=str, required=True)
    args = parser.parse_args()

    model = Summarizer()
    with open(args.input, "r", encoding="utf-8") as f:
        body = "".join(f.readlines())

    #print(body)
    result = model(body, num_sentences=args.num_sentences)
    full = ''.join(result)
    with open(args.output, "w", encoding='utf-8') as fw:
        fw.write(full)

if __name__ == "__main__":
    main()

```

#動かしてみた
とりあえず、CNNの以下のニュースをやってみた。
https://edition.cnn.com/2021/04/10/sport/san-diego-padres-no-hitter-joe-musgrove/index.html

上の文章を```input.txt```に保存して以下を実行。今回は3つの文章を抽出する。

```sh
$ python.exe text_summarizer.py -input input.txt -num_sentences 3 -output output.txt
```

結果は以下の通り

```output.txt
Pitcher Joe Musgrove tossed the first no-hitter in Padres franchise history on 
Friday night, as San Diego defeated the Texas Rangers 3-0 at Globe Life Field in
Arlington, Texas. Musgrove struck out 10 and only allowed one base runner when 
he hit Joey Gallo, which prevented a perfect game. I looked up at the scoreboard 
to see what (the) pitch count was, and I was at, like, 67, and I was like, we've
 got some room to work with." Musgrove added, "It feels really good to be in a
 Padres uniform when I did it.
```

一応ノーヒットノーランを達成した様子が伝わってくる。


#参考
- [bert-extractive-summarizer](https://github.com/dmmiller612/bert-extractive-summarizer)
初心者による、Linuxコマンド一覧！

#Linuxコマンドまとめ
ディレクトリの移動

```sh:
cd `移動先のディレクトリ名`
```
ディレクトリの内容をリスト形式で表示

```sh:
$ ls
```

ディレクトリを作成する

```sh:
$ mkdir `ディレクトリ名`
```
ファイルやディレクトリをコピー

```sh:
$ cp ` (移動元ファイル名/ディレクトリ名)` `(移動先ファイル名/ディレクトリ名)`
```
現在いる位置を表示する

```sh:
$ pwd
```
ファイルやフォルダのアクセス権限を変更する

```sh:
$ chmod `モード` `権限ファイル名`
````

ファイルやフォルダのオーナーやグループを変更する

```sh:
$ chown `変更したいユーザー名 変更したいファイル名`
```

ファイルの内容を表示する

```sh:
$ cat `ファイル名`
```
viエディタの起動

```sh:
$ vi `ファイル名`
```
ファイルとファイルの内容の違いを表示する

```sh:
$ diff `旧ファイル名` `新ファイル名`
```
突然condaが起動できなくなった時の対処法

anaconda環境があるとき突然起動しなくなった…ということがあったので対処の記録です。

起動しようとしたらコマンドプロンプトが一瞬起動してすぐ消える、という状態に突然なってしまいました。

このような「起動しない」系の問題の時はまず環境変数を確認せよ、とよく言われますのでシステム詳細設定を開いてユーザー環境変数を確認すると、確かに以前追加したはずのpython関係のパスが確かに見つからない。

python関連が入っているパスを追加しなおしたものの、まだ状態は変わらず起動しない。

**原因はやっぱり環境変数でした**
ほかの原因を探そうと、起動に使っているバッチファイルがきちんと動くか確認してみたところ、activate.batというバッチファイルを実行すると、コマンドプロンプトが開き
「'cmd'は、内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチ ファイルとして認識されていません。」
というエラーメッセージが表示されました。

結局原因はこれで、「C:\WINDOWS\system32」にパスが通っていない(消えていた?)ことだったようです。

先ほどのユーザー環境変数にC:\WINDOWS\system32を追加すると、元通り起動しました。

ある時にユーザー環境変数が何やらガラッと変わってしまったことによるものだったのかもしれません。
いずれにしても、やはり**起動しない問題についてはまずパスが通っているか疑ってみる**という対処で良かったみたいです。
shellscriptのfor,while

shellscriptのfor,while,untilなどを勉強したのでまとめます。
#for文
###書式
変数に値を格納してその値の個数分ループする。

```for_ex.sh
for 変数名 in 値;
do
    処理
done
```
###例
```for.sh
for var in 1 2 3 4 5;
do
   echo $var
done

for var2 in `seq 1 5`;  #seq 1 2 10 だと 1 3 5 7 9が格納される
do
    echo $var2
done
```
どちらも実行すると1行ずつ数値が表示される。
(seqを使って指定すると、短く書ける。インクリメントする数も指定できる。)
###break・continue
```file.sh
#break
for var in `seq 1 10`;
do
    echo $var 
    if [ $var -eq 5 ];
    then
        break
    fi
done

#continue
for var2 in `seq 1 10`;
do
    if [ $var -eq 3 ];
    then
        continue
    done
    echo $var2
done
```
数値が5のとき終了する文と、数値が3のとき表示しない文。

##for文でコマンドを実行
```command.sh
for com in pwd ls;
do
    echo $com  #コマンドは実行されない
    $com       #コマンドが実行される
done
```
変数に文字列を格納して、$変数名とかけば実行ができる。

#while文
条件が満たされている間はdo~doneの処理を実行する。
###書式
```while_ex.sh
while [ 文字列 ] or (( 数値 ));
do
  処理
done
```
数値演算は```$(( ))```だけど、while文では```(( ))```となる。
###例
*var変数がある前提で

```while.sh
#文字列
read -p 'var変数の中身' var

while [ $var != 'end' ];
do
    echo 'yes!'
    read -p 'var変数の中身' var
done

#数値

varn=0
 
while (( $varn < 10 ));
do
    echo $varn
    varn=$(( $varn + 1 )) #これがないと無限ループになる
done
```
上はendという文字列を入力したら処理が終了する。
下は変数$varnが10より小さい場合に数値を表示し、最後の行で変数をインクリメントしている。
###break
breakが実行されると、ループ自体が終了する。

```break.sh
var=0
while (( $var < 10 );
do
    if [ $var -eq 7 ];
    then
        break
    fi
    var=$(( $var + 1 ))
done
```
この例では$varが7になったらループを強制終了させる。
 
###continue
continue以降の処理を中止し、ループを繰り返す。

```continue.sh
var=0
while (( $var < 10 ));
do
    echo $var
    if [ $var -eq 7 ];
    then
        continue
    fi
    var=$(($var+1))
done 
```
これを実行すると$varが7になったら、最後のインクリメントが行われずに無限ループになる。
出力は下記のようになる。(Ctrl+Cで終了)

```
1
2
~~
6
7
7
.
.
```
##whileでファイルを読み込む
読み込ませるファイル

```sample.txt
1
2
3
sample
hello
```
####やり方
```file.sh
while read var
do
    echo $var
done < 'sample.txt'
----------- or -----------
cat 'sample.txt' | while var
do
    echo $var
done
```
catで変数を読み込もうとしたらエラーが正しく処理されなかった。
変数を使うときは上の方がいい。
####出力
```
1
2
3
sample
hello
```
whileの条件に```read 変数名```を書くことで外部ファイルを変数に格納する。(1行ごと)
その変数をechoで表示している。

#until文
条件にマッチするまで処理を続ける。
書式はwhileと同じ。
###例
```until.sh
var=0
until (( $var > 10 );
do 
    var=$(( $var + 1 ))
done
```
$varが10より大きくなるまでインクリメントを続ける。

**間違いがありましたらご指摘ください。**
【TypeScript】オブジェクトのプロパティを読み込み専用にする6通りの方法

## readonly

```ts
type User = {
  readonly name: string
  age: number
}

const user1: User = {
  name: 'Taro',
  age: 18
}

user1.name = 'Hanako' // Error
user1.age = 30 // OK
```

## Readonly型

```ts
type User = {
  name: string
  age: number
}

const user1: Readonly<User> = {
  name: 'Taro',
  age: 18
}

user1.name = 'Hanako' // Error
user1.age = 30 // Error
```

## constアサーション

```ts
const user1 = {
  name: 'Taro',
  age: 18
} as const

user1.name = 'Hanako' // Error
user1.age = 30 // Error
```


## 型アサーション

```ts
const user1 = {
  name: 'Taro' as 'Taro',
  age: 18
}

user1.name = 'Hanako' // Error
user1.age = 30 // OK
```

## リテラル型

```ts
type User = {
  name: 'Taro'
  age: 18
}

const user1: User = {
  name: 'Taro',
  age: 18
};

user1.name = 'Hanako' // error
user1.age = 30 // error
```

## Object.freeze()

```ts
const user1 = {
  name: 'Taro',
  age: 18
}

const frozenUser = Object.freeze(user1)

frozenUser.name = 'Hanako' // Error
frozenUser.age = 30 // Error
```
WEBRTC 良記事


youtube

https://www.youtube.com/watch?v=DvlyzDZDEq4


基本

https://ticktakclock.hatenablog.com/entry/2019/09/11/144122

応用

https://qiita.com/Turtle-child-No2/items/7205d5c1399375a8c10b

https://qiita.com/yusuke84/items/43a20e3b6c78ae9a8f6c
rails Basic 認証

##初めに 
初学者です。学習のためにアウトプットしています。間違いなどありましたらご指摘お願いします。

## Basic認証
Basic認証とはHTTP通信の規格に備え付けられている、ユーザー認証の仕組みのことです。
サーバーとの通信が可能なユーザーとパスワードをあらかじめ設定しておき、それに一致したユーザーのみが利用できる認証システムです。
ページに遷移した時にこんな感じで出てきます。

![]
(https://gyazo.com/13f36b70ca09578f405352b42da60fe4.png)

## railsアプリにBasic認証を導入する。
まずはauthenticate_or_request_with_http_basicメソッドを使用します。
こちらのメソッドはBasic認証を使うために利用するメソッドになります。全てのコントローラーに使用するためapplication_controller.rbに記述します。

```ruby
class ApplicationController < ActionController::Base
  before_action :basic_auth

  private
  def basic_auth
    authenticate_or_request_with_http_basic do |username, password|
      username == 'hoge' && password == '1234'
    end
  end
end
```
これで設定完了です。ちなみにユーザーnameは`hoge`パスワードは`1234`です。

しかしこのままでは問題があります。コード上にBasicコードが記述されていることです。GitHub上に公開した場合、Basicコードのパスワードが誰にでも読める状態になっているからです。
その対策として環境変数を利用する必要があります。環境変数はzsh,またはbashの設定ファイルに記載します。
では軽く用語の説明をしていきます。

####zsh
zshとはログインシェルと呼ばれるものです。簡単に言えば隠しファイルみたいなものです。そしてプログラムの一番最初に対応します。
####bash
bashもログインシェルの１つです。違いはMacのosによってzshかbashを使うかの違いです。
####vim
vimとはサーバー上で使用できるテキストエディタのこと。vim
コマンドを使うことで指定したファイルの編集をターミナルから行うことが可能になります。

##環境変数の設定
私のMacではzshのためzshを使用していきます。
まずはターミナルに以下のコマンドを使用します。

```
% vim ~/.zshrc
```
~
~
~
~
のように〜が縦並びでたくさん出てきます。
そのあとiキーを押してインサートモードに移行します。ターミナル左下にINSERTと出てきます。
そのあとにzah内に以下の記述をしていきます。

```
export BASIC_AUTH_USER='hoge'
export BASIC_AUTH_PASSWORD='1234'
```
記述が終わったらescキーを使用して:wqと入力し、Enterキーを押します。
最後にsourceコマンドを実行します。

```
source ~/.zshrc
```
このsouceコマンドとはシェルに記述された内容を実行する役割があります。
そしてapplication_controller.rbに環境変数を読み込む記述をすれば完成です。

```ruby
def basic_auth
    authenticate_or_request_with_http_basic do |username, password|
      username == ENV["BASIC_AUTH_USER"] && password == ENV["BASIC_AUTH_PASSWORD"]  # ここを変更
    end
  end
```

最後にheroku上に環境変数を設定します。以下の記述を順番に記述します。

```
% heroku config:set BASIC_AUTH_USER="hoge"
% heroku config:set BASIC_AUTH_PASSWORD="1234"
```

最後にherokuにpushして完成になります。
Excel ショートカット

便利に使っているExcelのショートカットキーの一覧です。
参考：[Microsoft Excel のショートカット キー](https://support.microsoft.com/ja-jp/topic/excel-%E3%81%AE%E3%82%B7%E3%83%A7%E3%83%BC%E3%83%88%E3%82%AB%E3%83%83%E3%83%88-%E3%82%AD%E3%83%BC-1798d9d5-842a-42b8-9c99-9b7213f0040f)

|目的|キー|
|:--|:--|
|[セルの書式設定] ダイアログを開く|Ctrl + 1|
|現在の日付を入力する|Ctrl + ;|
|現在の時刻を入力する|Ctrl + :|
|複数範囲選択モード|Shift + F8|
|シートを移動する|Crtl + Page Up, Ctrl + Page Down|

こちらもご参考に！
[50 time-saving Excel shortcuts](https://templates.office.com/en-us/50-time-saving-excel-shortcuts-tm67670278)
【AWS】IAM(Identity and Access Management)とは何か

#プログラミング勉強日記
2021年4月10日

#IAMとは
　IAMはIdentity and Access Managementの頭文字をとったもので、読み方は「アイアム」。AWSのサービスにアクセスして操作し、認証や認可を設定・管理する機構のこと。

　IAMはユーザやグループごとに権限を分けることができる。AWSアカウントで契約したサービスにアクセスして操作できる権限を付与した人をIAMユーザという。IMAユーザごとに細かくアクセスと操作の権限を設定することができて、IAMユーザをグループにまとめると権限をまとめて管理することができる。
　IAMの役割はユーザの認証と認可。アクセスしようとしているのがどのIAMユーザかを特定するのが認証で、IAMユーザのアクセスと操作の権限のみを許可するのを認可という。

#IAMの3つの機能

##IAMユーザとIAMグループ
　登録・権限設定したIAMユーザで通常の操作を行う。複数のIAMユーザをIAMグループとしてまとめることもでき、グループでまとめて権限の設定を行うことができる。

##IAMロール
　IAMユーザは、AWSサービスへのアクセスや操作の権限を付与するもの。IAMロールは、AWSで開発しているアプリのコンテンツやサービスに操作権限(IAMポリシー)を付与する仕組みのこと。
　IAMロールを使用すると、コードに認証パスワードなどの情報を記述する必要がなくなり、セキュリティを高めることができる。


##IAMポリシー
　IAMユーザやIAMロールに付与する操作権限をIAMポリシーにJSON形式で記述する。


#参考文献
[AWSのIAMとは？3つの機能でできることをやさしく解説](https://www.sejuku.net/blog/127175)
Wordpressで投稿画像のファイル名を英語にリネームする。

自分のための忘備録です。
***



(・ω・)＜ kubiee君、以前作ったwordpressの画像のファイル名が日本語になってるよ

・・・（やばい・何か問題があるのかな・・？）　＞(´∇｀)


##問題点
今後wordpressを引っ越すときにエラーが出るみたいです。
こちらのサイトを参考に過去の投稿画像をリネームしました。

https://7step-pc.com/?p=4467



##今後の投稿画像も自動で英語にリネームする

https://zumarketing.work/wordpress-file-name-change/


functions.phpに以下を追加

```php:functions.php
function rename_file_md5($fileName) {
$i = strrpos($fileName, '.');
if ($i) $Exts = '.'.substr($fileName, $i + 1);
else $Exts = '';
$fileName = md5(time().$fileName).$Exts;
return strtolower($fileName);
}
add_filter('sanitize_file_name', 'rename_file_md5', 10);
```
ArgoCDのv2.0でkustomizeのyamlを読み込めなくなった

# 起きた事象

- ArgoCDをv2.0にアップグレードした
- yamlのmanifestが読み込めなくなった
- エラーメッセージをみると、`kustomize build`でpanicした様子
- ![スクリーンショット 2021-04-10 16.20.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84477/c2b731a9-dd29-1540-9be4-18597bb20b4b.png)
- ![スクリーンショット 2021-04-10 16.20.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84477/954862a4-3616-39ef-7986-b490f48aa6b9.png)


# 発生条件
- ArgoCD v2.0
- kustomizeを使っている
- 全角文字列がyamlファイルに含まれている

# 対策
以下のどちらが対応できる
- ArgoCD v2.0の場合、yamlファイルから全角文字を全て削除する
- ArgoCDのバージョンをv1系に戻す

# 原因
- ArgoCDがkustomizeのバージョンをv3.8.1 -> v3.9.4にアップグレードした
    - https://github.com/argoproj/argo-cd/commit/8569105d812ddc6fbac5b5478c053d331aa0ee34#diff-f7e84247fc1a8aacb66bf62b7d104d8e934f8805830e484b9a316431c80bb990
- kustomizeはv3.9.1から全角文字でエラーするようになっている
    - https://qiita.com/nekoshita_yuki/items/edb312da58c8a4e30141
Flake8 Pythonコードに対して使ってみた


# インストール

```
$ pip install flake8
```

インストール方法

https://flake8.pycqa.org/en/latest/index.html

# バージョン確認

```
flake8 --version
3.8.4 (mccabe: 0.6.1, pycodestyle: 2.6.0, pyflakes: 2.2.0) CPython 3.8.2 on Windows
```

# 実行例

```
$ flake8 flake8_sample.py
flake8_sample.py:1:1: F401 'sys' imported but unused
flake8_sample.py:3:15: W292 no newline at end of file
```

エラーコード

| コード | メッセージの例                    |
| ------ | --------------------------------- |
| F401   | `module` インポートされたが未使用 |

Fに関するエラーコード

https://flake8.pycqa.org/en/latest/user/error-codes.html

| **W2** | *空白の警告*                       |
| ------ | ---------------------------------- |
| W291   | 末尾の空白                         |
| W292   | ファイルの終わりに改行がありません |
| W293   | 空白行に空白が含まれています       |

E, Wに関するエラーコード

https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes



## エラーコード

|コード|内容|
|---|---|
|E|pycodestyleによるエラー|
|F|pyflakesによるエラー|
|W|pycodestyleによる警告|

詳細はこちら

https://flake8.pycqa.org/en/latest/user/violations.html

## オプション例

**--filename**
対象にするファイルを指定

```
flake8 --filename *.py
.\flake8_sample.py:1:1: F401 'sys' imported but unused
.\test_sample.py:4:1: E302 expected 2 blank lines, found 1
```

**--count**
エラーの数を表示する

```
flake8 flake8_sample.py --count
flake8_sample.py:1:1: F401 'sys' imported but unused
flake8_sample.py:3:15: W292 no newline at end of file
2
```

**--show-source**
該当ソースを表示する

```
flake8 flake8_sample.py --show-source
flake8_sample.py:1:1: F401 'sys' imported but unused
import sys
^
flake8_sample.py:3:15: W292 no newline at end of file
print('hello')
```

**--select**
指定したエラーコードのみ表示する

```
flake8 flake8_sample.py --select=W292
flake8_sample.py:3:15: W292 no newline at end of file
```

エラーコードの種類だけを選択することも可能

```
flake8 flake8_sample.py --select=F
flake8_sample.py:1:1: F401 'sys' imported but unused
```

F4で始まるエラーコードのみ選択することも可能

```
flake8 flake8_sample.py --select=F4
flake8_sample.py:1:1: F401 'sys' imported but unused
```

**--statics**
エラーごとにカウント数、エラーコードを表示

```
flake8 flake8_sample.py --statistics
flake8_sample.py:1:1: F401 'sys' imported but unused
flake8_sample.py:2:1: F401 'os' imported but unused
flake8_sample.py:4:15: W292 no newline at end of file
2     F401 'sys' imported but unused
1     W292 no newline at end of file
```

**--max-line-length=n(デフォルトは79)**
文字数超過を表示

```
flake8 flake8_sample.py --max-line-length=90
flake8_sample.py:1:91: E501 line too long (99 > 90 characters)
```

**--tee**
標準出力とファイルに出力

**--output-file**
結果をファイルに出力

```
flake8 flake8_sample.py --tee --output-file outpu.txt
flake8_sample.py:1:1: F401 'sys' imported but unused
```

**--help**

```
flake8 --help
```

**--exit-zero**
エラーがあってもステータスコード "0 "で終了
私の人生のように。

# 参考記事

https://flake8.pycqa.org/en/latest/index.html

https://flake8.pycqa.org/en/latest/user/error-codes.html

https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes

https://flake8.pycqa.org/en/latest/user/violations.html
[JavaScript] 配列の要素を昇順に並べ替えたい

# はじめに

実際のフロントエンドの現場で「配列の要素を"昇順"に並べ替えてください」と言われることは結構多くあると思ったんで（たとえば、価格の安い順にデータを表示させたい、といった場面）配列の要素を昇順に並べ替える方法をES6の書き方で簡単にまとめました。

# オブジェクトを要素に持たない配列の場合

### 問題

```js
// この配列を
const array1 = [1, 30, 4, 21, 100000];

// 昇順に並べ替えたい
[1, 4, 21, 30, 10000]

// どうやって実装する？
```

### 実装方法

```js
// sort関数は破壊的なメソッドなのでまずは配列をコピーする
const cloneArray = [...sampleArray];
const sortedArray = cloneArray.sort((a,b) => a - b );
console.log(sortedArray);

// expected output
[1, 4, 21, 30, 100000]
```

# オブジェクトを要素に持つ配列の場合

### 問題

```js
// この配列を
const items = [
  { name: 'tanaka', value: 24 },
  { name: 'kimura', value: 35 },
  { name: 'suzuki', value: 23 },
];

// 値順にソートしたい
[
  { name: 'tanaka', value: 23 },
  { name: 'kimura', value: 24 },
  { name: 'suzuki', value: 35 },
];

// どうやって実装する？
```

### 実装方法

sort関数のコールバック関数で、valueプロパテを指定して並べ替えればOKです

```js
// sort関数は破壊的なメソッドなのでまずは配列をコピーする
const cloneItems = [...items];
cloneItems.sort((a,b) => a.value - b.value);
console.log(cloneItems);

// expected output
[
  { name: 'tanaka', value: 23 },
  { name: 'kimura', value: 24 },
  { name: 'suzuki', value: 35 },
];
```

# 参考文献

[Array.prototype.sort() | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
スパム対策：google reCAPTCHAの設置

自分のための忘備録です。

## reCAPTCHAとは
google reCAPTCHAとはフォーム送信の際に画像認証などを用い、botを防ぐ仕組み。
**V2**と**V3**がある。


## v2とv3の違い
**V2**・・・画像認証が出てチェックさせる。フォーム送信に手間がかかる。
**V3**・・・フォームでの挙動から自動でbotか判断する。フォーム送信に手間がかからないが、効いてるのかいまいち分からない。


# 設置方法

①まずgoogleアカウントを作り、ダッシュボードでプロジェクトを作っておく
上の「Google Cloud Platform」の横にあるところから「新しいプロジェクト」

https://console.cloud.google.com/home/dashboard


②reCAPTCHAを設置したいドメインを登録して、v2かv3を選んでキーをもらう
サイトキーとシークレットキーがある。

https://www.google.com/recaptcha/admin



##v2の設置コード

htmlだけで済ませたいならこちら

https://qiita.com/dokkoisho/items/efe72652ae58ece26de1

htmlとphpで処理を分けるならこちら

https://qiita.com/neguse/items/e6f4876c2eaa5bdf28f1



##v3の設置コード

https://qiita.com/ma7ma7pipipi/items/3d7c59fbefba45e29d82


##v3設置してて問題点が出てきた
どうやらreCAPTCHAはトークンを取得して５分経つとタイムアウトエラー出るみたいです。

https://qiita.com/dozo/items/77abc7b211c6214d9dc3

##タイムアウトエラー対策
タイムアウトエラーだけ無視できるようにちょっと変更します。
ついでに条件を「スコアが0.9以上なら成功」に変更



```php:フォームのphp
if (!empty($_POST['recaptchaResponse'])) {
    $secret = 'シークレットキーを入れる';
    $verifyResponse = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='.$secret.'&response='.$_POST['recaptchaResponse']);
    $reCAPTCHA = json_decode($verifyResponse);
    $reCAPTCHA_error = [];
    if($reCAPTCHA->{'error-codes'}) {
    	$reCAPTCHA_error = $reCAPTCHA->{'error-codes'};
    };

    if ($reCAPTCHA->score >= 0.9 || (count($reCAPTCHA_error) === 1 && $reCAPTCHA_error[0] === 'timeout-or-duplicate')) {
        // たぶん人間なので送信とかの処理

    } else {
        // ボットかも

    }
}

```

ただこれだとタイムアウトエラーが出ていたらscore関係なくtrueになってしまいます。
recaptureはタイムアウトエラーになるとscoreが消えてしまうので仕方ないみたいです。


##効いてるか確認

https://g.co/recaptcha/admin



* * *
参考させていただきました
https://norando.net/recaptcha-v3_timeout-or-duplicate/
https://blog.4breaker.com/2020/02/29/post-358/
別のWindowを表示する

#はじめに
PrismでMVVMパターンを使用していると、基本的にWindowは一つで、RegionにModuleを表示させるのが基本的な流れです。
Webアプリや最近のアプリでは、Single Windowが基本のように思いますが、業務アプリを作成していると、複数のWindowを使用する必要がでる場合があります。
昔は、MDIアプリケーションが一般的だったように思うのですが、最近はあまり見かけなくなりました。

複数のWindowを使用するアプリを作るために、メインWindowとは別のWindowを表示させる方法の一つを紹介します。
方法は旧来からあるものです。
ただ、以前アプリを開発していた時に、どうすればいいのか悩んだことがあるので、プログラミングを始めたばかりの人には悩みどころの一つではないかと思います。

#別Winodowの表示
基本的には、Win Formsでも同じですが、ボタンをクリックしたら、別Windowを表示させるためのコードです。
ボタンをクリックするたびに、Windowが表示されるのは防ぐようにしています。

```C#
    // ボタンをクリックで呼び出すコード
    private void ShowWindow()
    {
        // SampleWindow : WPF のView
        Type winType = typeof(SampleWindow);

        // Windowのインスタンスを取得
        Window win = GetWindowInstance(winType);

        // Windowを表示させます
        win.Show();
        win.Title = "サンプル";
        win.Activate();
        win.WindowState = WindowState.Normal;
    }

    // Windowのインスタンス取得処理
    private Window GetWindowInstance(Type winType)
    {
        // Windowsを取得
        Window win;
        win =System.Windows.Application.Current.Windows
                .OfType<Window>()
                .SingleOrDefault(w => w.GetType() == winType);

        // まだ表示されていない場合はインスタンスを生成する
        if (win == null)
        {
            win = (Window)Activator.CreateInstance(winType, _regionManager);
        }
        return win;
    }

```

CreateInstanceの引数に_regionManagerがありますが、Prismを利用していて、Viewの引数にregionManagerがあるためです。
ShowWindowのところで、引数にView(Window)を指定するようにすれば汎用的に使用することもできます。
【Python】S&P500から低PERの銘柄をスクリーニングする


米国株からスクリーニングするとき，ナスダック銘柄は1万銘柄とかあるので，そこからスクリーニングするのは時間がかかって仕方がありません．

そこで思いつくのが，500銘柄程度しかないインデックスであるS&P500からスクリーニングするということです．

#S&P500の銘柄データ（チェッカーシンボル）を持ってくる

S&P500銘柄が一覧になっているデータを探すしかありません．

Wikipediaに記載されている銘柄をまとめたと考えられているCSVデータが，以下のURLにあります．

https://raw.githubusercontent.com/datasets/s-and-p-500-companies/master/data/constituents.csv

参考：配当再投資でのんびり投資（https://nonbiri-reinvest.net/post-692/）

ただし，公式かどうかは怪しいので，正確ではないかもしれません．また，S&P500の組入れ銘柄は定期的に入れ替わるので，最新の銘柄を取得し続ける必要があります．公式で一覧になっているものが見つかれば，再掲したいです．

これを以下のようにPython(pandas)で呼んでやれば，S&P500だけのデータを取得できます．


```python
import pandas as pd
url = "https://raw.githubusercontent.com/datasets/s-and-p-500-companies/master/data/constituents.csv"
df = pd.read_csv(url, encoding="SHIFT_JIS")
```

```python
print(df)
```

```
    Symbol                 Name                  Sector
0      MMM           3M Company             Industrials
1      AOS      A.O. Smith Corp             Industrials
2      ABT  Abbott Laboratories             Health Care
3     ABBV          AbbVie Inc.             Health Care
4     ABMD              Abiomed             Health Care
..     ...                  ...                     ...
500    YUM      Yum! Brands Inc  Consumer Discretionary
501   ZBRA   Zebra Technologies  Information Technology
502    ZBH        Zimmer Biomet             Health Care
503   ZION        Zions Bancorp              Financials
504    ZTS               Zoetis             Health Care
```

これで，S&P500の銘柄を取得できました（たぶん）．

#低PERの銘柄をスクリーニングする

以下のコードでできます．

```python
import pandas as pd
import pandas_datareader.data as web

pers = pd.DataFrame({'PER':['']}, index=['銘柄'])
error_symbols = []
for c in codelist['Symbol']:
    try:
        per = web.get_quote_yahoo(c)['trailingPE']
        if per[c] < 10:
            pers.loc[c] = per[c]
    except:
        error_symbols.append(c)

print(pers)
```

構造としては，pandas_datareaderのget_quote_yahooで各銘柄のPER（正確にはtrailingPE）を見ていき，PERが10以下ならpersというDataFrameにシンボルとPERを格納します．

深くは考えていませんが，エラーが起きた時にはerror_symbolsというリストに入るようにしています．

これ（もしくは本記事の最後のまとめコード）を実行すると，以下が得られます．

```
          PER
銘柄
AFL   7.81709
ALL    6.7747
BIO   4.51307
CE    8.71157
EBAY   7.3074
KIM   8.76055
MHK    3.7743
PGR   9.66667
PHM   9.60201
COO   8.52827
UNM   7.40874
```

3分ほどでスクリーニングできました．S&P500でも結構かかりますね．

#まとめコード

S&P500から低PERの銘柄をスクリーニングするコードです．

```python
import pandas as pd
import pandas_datareader.data as web

url = "https://raw.githubusercontent.com/datasets/s-and-p-500-companies/master/data/constituents.csv"
codelist = pd.read_csv(url, encoding="SHIFT_JIS")

pers = pd.DataFrame({'PER':['']}, index=['銘柄'])
error_symbols = []
for c in codelist['Symbol']:
    try:
        per = web.get_quote_yahoo(c)['trailingPE']
        if per[c] < 10:
            pers.loc[c] = per[c]
    except:
        error_symbols.append(c)

print(pers)
```


#ちなみに：ナスダック銘柄からスクリーニングする

ナスダック銘柄からスクリーニングする場合は，

```python
from pandas_datareader.nasdaq_trader import get_nasdaq_symbols
codelist = get_nasdaq_symbols() #ナスダック銘柄を取得
```

という感じでナスダック銘柄を取得できます．

今回の内容も含めて，詳しくは以下の記事に書いてあります．

https://optrip.xyz/?p=2109
SlackLogViewer を Windows10 にインストール


「SlackからExportされたjson形式ログファイルのビューワを作った。 - 賢朽脳瘏」
https://kenkyu-note.hatenablog.com/entry/2020/09/28/045232

 Windows デスクトップ用アプリですが、インストールをしてみました。

# 環境

- Windows 10 Professional

# ダウンロード、解凍

https://github.com/thayakawa-gh/SlackLogViewer/releases/tag/v1.1.Beta-1
こちらから

SlackLogViewer.v1.1.Beta-1.zip
をダウンロードして解凍、インストールしようとするとエラーが出ました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/6f79b6a2-0b74-cd85-7d86-db47e1c640be.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/cde0abb0-f07d-a8a0-b14a-9bb5e25896cc.png)

以下の 3 つが無いと出ます。

- MSVCP140_ATOMIC_WAIT.dll
- VCRUNTIME140_1.dll
- MSVCP140_1.dll

# 再頒布可能パッケージ

ここかな?（ハズレ)
「Download Microsoft Visual C++ 2015 再頒布可能パッケージ Update 3 from Official Microsoft Download Center」
https://www.microsoft.com/ja-jp/download/details.aspx?id=53840

これをダウンロードし、インストールしましたが、改善しませんでした。

こちらが正解らしいです。

「>Visual Studio 2019 for Windows および Mac のダウンロード」
より「その他のツールとフレームワーク」の「Visual Studio 2019 の Microsoft Visual C++ 再頒布可能パッケージ」からインストール


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/74391d0d-60f0-25b8-7833-bbb4dd901b1f.png)

# 起動確認

動きました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/c82bebce-cf0a-c3a4-7b11-d2e8ac35ba9c.png)


# Slackのログを取得する

我が家で使っているSlackで試してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/34ea65ea-ca27-2472-8e70-2b4fc38d529c.png)

以下のように取得してみます


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/c2b07766-058d-2303-72a5-17632daba6fb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/da759ea0-5907-4abe-b9b8-54a9cc3a482c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/dae681a8-46a7-7b1e-4f52-520530f91331.png)

ダウンロードに数日かかるということでしたが、一瞬で取得できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/a8651bd2-2f25-4d3b-ca85-cb768e3f95cf.png)
ダウンロードしたものを解凍します。日本語が化けてますが・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/4de5bd1a-ac4b-d3b3-1bb4-2a6cb503078b.png)

うーむ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/b1213528-bfdb-5b4a-1804-5682fc5f1b48.png)

フォルダ名を変更したら

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/b8f27220-72e9-4dca-650c-9285592eedbf.png)

読めました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/8f8bbf9d-2876-13ec-ee74-1e8a06a798b3.png)
[OpenShift]Alertmanagerの設定

#はじめに
PrometheusのAlertmanagerを設定して、OpenShiftのアラートの設定方法を確認します。

https://prometheus.io/docs/alerting/0.20/configuration/

バージョンはOCP4.5.4です。

```
$ oc version
Client Version: 4.5.4
Server Version: 4.5.4
Kubernetes Version: v1.18.3+012b3ec
```

#Secretの設定
今回はアラートをメールで送信します。

##Secretの確認とファイルへの書き出し
既存でできている alertmanager-main Secret を確認して、ファイルに書き出します。

```
$ oc describe secrets -n openshift-monitoring alertmanager-main
Name:         alertmanager-main
Namespace:    openshift-monitoring
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
alertmanager.yaml:  278 bytes

$ oc extract secret/alertmanager-main --to /tmp/ -n openshift-monitoring --confirm
/tmp/alertmanager.yaml
```

##設定ファイルの編集
書き出した設定ファイルを以下のように編集します。

```/tmp/alertmanager.yaml 
"global":
  "resolve_timeout": "5m"
  smtp_smarthost: 192.168.1.254:24 #追記。 SMTPホスト
  smtp_from: alerts@example.com #追記。送信者のメールアドレス
  smtp_require_tls: false #追記。SMTPにTLSが必要かどうか
"receivers":
- "name": default #変更
- name: email-notification #追記。任意の名前
  email_configs: #追記。メールでアラートを送信する
  - to: hoge@example.com #追記。送信先メールアドレス
"route":
  "group_by":
  - "namespace"
  "group_interval": "5m"
  "group_wait": "30s"
  "receiver": default #変更
  "repeat_interval": 1m #変更。アラートを再送するまでの待機時間（すぐに再送されるように短くした）
  "routes":
  - "match":
      "alertname": "Watchdog"
    "receiver": default
  - match: #追記
      severity: warning #追記。Warningでアラートを送信する。（ここではすぐに送信されるようにWarningにした）
    receiver: email-notification #追記。使用するレシーバー

```

#Secretの更新

編集したファイルでSecretを更新します。

```
$ oc set data secret/alertmanager-main -n openshift-monitoring --from-file /tmp/alertmanager.yaml
secret/alertmanager-main data updated
```

更新後、以下のログが出力されることを確認します。

```
$ oc logs -f -c alertmanager alertmanager-main-0 -n openshift-monitoring
・・・
level=info ts=2021-04-10T06:42:03.588Z caller=coordinator.go:131 component=configuration msg="Completed loading of configuration file" file=/etc/alertmanager/config/alertmanager.yaml
```

#確認
アラートメールが送信されているか、クライアントで確認します。

```
$ mailx
Heirloom Mail version 12.5 7/5/10.  Type ? for help.
"/var/spool/mail/lab": 2 messages 1 new
    1 alerts@example.  Fri Apr  9 09:48 188/10319 "[FIRING:1]  (AlertmanagerReceiversNotConfigured openshif"
>N  2 alerts@example.  Sat Apr 10 02:41 219/12401 "[FIRING:2]  (openshift-monitoring/k8s warning)"
```
VSCode向けの拡張機能の対応状況を整理した

#概要
[これまでの記事](https://qiita.com/HiroInTFLab/items/ac8ffc86b5b822aa68b1)で[Xtext Visual Studio Code Example](https://github.com/itemis/xtext-languageserver-example)を例に、DSL向けのプログラミング環境を提供する、VSCode向けの拡張機能について書いてきました。昨今のプログラミング環境は、概ね決まった機能を提供する雛形に基づいて作られています。ここでいったん、vscode、xtext、Xtext Visual Studio Code Exampleなど関係について整理し、独自DSLのプログラミング環境を拡張機能で提供する上で、必要なことがらについてまとめていきたいと思います。

#開発環境など
- Windows10 Pro 1909
- VSCode 1.47
- JDK 1.8
- Xtext 2.24

#整理
まずは星取表で整理してみました。
編集途中の項目が多いので、少しずつ足していきます。

| 機能 | vscode1.47（>LSP3.15） | xtext2.24 | Xtext Visual Studio Code Example | 一連の記事で実現したこと。なお、コードは[こちら](https://github.com/tfLabs/xtext-languageserver-example) | 独自DSL化に必要なこと |
|:-:|:-:|:-:|:-:|:-:|:-:|
| コメント | クライアントとして対応済を✔ | LSP対応済を✔ | 筆者による対応確認済を✔  | ✔は、断りない限りXtext Visual Studio Code Exampleにならう  | |
| Syntax Coloring | ✔ |  ✔| ✔ | ✔  |（xtextによる文法定義とは非同期のため、mydsl.tmLanguage.jsonの手動更新が必要）|
| Semantic Coloring | ✔ |   |   |   | |
| Error Checking（通常の文法エラーに報知） | ✔（エラー箇所に赤い下線。1000個目以上のエラーには赤下線が引かれず） | ✔ | ✔ | ✔ | |
| Validation | |  ✔ | ✔  | ✔ | |
| Auto-Completion | ✔ |  ✔ | ✔  | ✔  | |
| Formatting | ✔ |  ✔ | ✔  | ✔  | |
| Hover Information | ✔ |  ✔ | ✔  | ✔  | |
| Mark Occurrences | ✔ |  ✔ | ✔  |  ✔ | |
| Go To Declaration | ✔ |  ✔ | ✔  |  ✔ | |
| Rename Refactoring |✔  |  ✔ | ✔  | ✔  | |
| Debugging | ✔ |   |   |   | |
| Toggle Comments | ✔ |  ✔ | ✔  | ✔  | |
| Outline / Structure View | ✔ |  ✔ | ✔  | ✔  | |
| Find Reference | ✔ |  ✔ | ✔  | ✔  | |
| Call Hierarchy | ✔ |   |   |   | |
| Type Hierarchy |  |   |   |   | |
| Folding | ✔ |   |   | ✔（[こちら](https://qiita.com/HiroInTFLab/items/1a712466e263bc302243)で対応） | |
| 保存時にファイル生成 | （vscodeの機能ではない）|  | （未対応。キー押下時にvalidationとファイル生成が連続実行される）  | ✔（[こちら](https://qiita.com/HiroInTFLab/items/e6fb11fac742bd347fd4)でキー押下時にvalidationのみ、保存時に生成を実施するよう変更）  | |
| 進捗表示 | ✔ |   |   | ✔（[こちら](https://qiita.com/HiroInTFLab/items/ef5ecb39b70c8cf4b4b0)で準備、[こちら](https://qiita.com/HiroInTFLab/items/c9000eb789ea1e203ede)で対応）  | |
| コマンド実行 | ✔ | ✔  | ✔（MyDsl A、MyDsl Bが定義済）  | ✔  | |
ruby even?メソッド

## 初めに
初学者です。学習した内容が定着させるためにアウトプットしていきます。
### even?メソッド
`even?`メソッドとはRubyがもともと用意している、対象の数値が偶数かどうか判別するためのメソッドになります。
対象の数値が偶数の場合は真を返し、そうでない場合は偽を返します。

```ruby
2.even?
#=> true

3.even?
#=> false
```
配列の中身の偶数の数をカウントしてみましょう。

```ruby
array = [1,2,3]
count = 0
array.each do |num|
  if num.even?
   count += 1
  end
puts count
end
```
変数countを定義してカウントした数を保持する変数を作ります。
そしてif文を使用して偶数の時だけカウントするように記述します。
最後にcountを出力すれば完成です。
今回は配列arrayには偶数が１つしかないので１と答えがですはずです。
Ruby　変数について

Ruby変数に関しての記事を書きたいと思う。

### 変数
■変数
変数とは、値を入れる箱のようなもの。この箱には名前をつけることができ、どんな値が入っているのかを簡単に識別できるようになる。この名前を変数名と言う。
変数を利用することで、値を再利用したい場合に、変数の名前を使うだけで呼び出すことができる。

■変数の宣言と定義
変数を作ることを変数の宣言と言う。このとき、作成する変数には名前をつける。
そして宣言した変数にどのような値を入れるのか記述することを変数の定義言う。

```ruby
fruits    #宣言（変数名をつけて変数を作る）

fruits = "apple" #定義(変数にどのような値を入れるか記述する)

#基本的には、宣言と定義は同時に行う。

```
■代入
変数のあとの=(イコール)は数学の方程式のように等しいという意味ではなく、
「変数の箱の中に値を入れる」という意味。これを代入と言う。
この=は代入演算子と呼ばれる。

[![Image from Gyazo](https://i.gyazo.com/305d2d0c07c199a71551fb96a2ae1cd9.png)](https://gyazo.com/305d2d0c07c199a71551fb96a2ae1cd9)
fruitsが左辺、appleが右辺「=」を使って、右辺を左辺に代入している。

■再代入
1度値を代入したあとの変数に、別の値を再び代入することもできる。
プログラム中に何度でも変更可能。
[![Image from Gyazo](https://i.gyazo.com/dc6cccaab36c8476cfdb89333e10a160.png)](https://gyazo.com/dc6cccaab36c8476cfdb89333e10a160)
変数の値が後から代入したものに書き換わっている。
Rubyでは、変数にはどんな値でも代入できる。
変数に対してメソッドを使うこともできる。

[![Image from Gyazo](https://i.gyazo.com/6a11c7ad44cfc823c1222344d93fd06b.png)](https://gyazo.com/6a11c7ad44cfc823c1222344d93fd06b)

上記のように、1を入れた変数の中に1を足して2を入れた変数にすることも可能。
この方法を自己代入変算子と言う。

|自己代入演算子|例|処理|
|------------|--|---|
|+=|number += 1	|numberに1足した値をnumber自身に代入|
|-=|number -= 1	|numberから1引いた値をnumber自身に代入|
|*=|number *= 2	|numberに2かけた値をnumber自身に代入|
|/=|number /= 2	|numberを2で割った値をnumber自身に代入|

変数の命名規則

|命名規則|説明|
|-------|---|
|変数の中身が何かわかる|どんな名前もつけられるが、zzzのような意味のない名前は避ける。|
|小文字で始める|大文字からも開始できるが、とくに理由がない場合は避ける。|
|_(アンダーバー)で始めない|_からも開始できるが、とくに理由がない場合は避ける。2文字目以降には使える。|
|数字で始めない|1文字目に使うとエラーが生じる。2文字目以降には使える。|
|日本語を使わない|文字列以外では日本語は使えないため、変数名も日本語は使えない。|
|スペースを含めない|名前にスペースが入るとエラーが生じる。|
|予約語を使用しない	|Rubyには文法などで使うことがあらかじめ決まっている単語があり、それを予約語と呼ぶ。使うとエラーが生じる。|

ソースコードの見やすさ(可読性)や分かりやすさは、プログラミングにおいて非常に重要なため、わかりやすい
名前をつける。
【Git】ステージングから取り消したい。

## git addしたけど、取り消したいときに
git addをして、ステージングに登録したけどやっぱり取り消したいとき。

```
$ git reset HEAD index.html
```
これで、git addでステージングに登録したものを取り消すことができる。
ただ、変更自体が取り消されるわけではない。
もし、変更後と取り消したい場合は以下のコマンドを実行する。

```
$ git reset HEAD .
```
これで、ファイルそのものの変更も取り消される。
再帰呼び出し Method Class

####あるメソッド内で、再度同じメソッドを呼び出す事を再帰呼び出しを呼ぶ。
for&while文を使わずに繰り返し処理を行える
if内でtestメソッドコピーをとって、num<10がfalseになるまで処理を繰り返し行える
コピーをとって動かしている

```Method_Class_4_10.java

public class Method_Class_4_10 {
    public static void main(String[] args) {
       var sample = new Method_Class_4_10();
        sample.test(1);
   }
public void test(int num){
   System.out.println("test");
   if(num < 10){
       test(num +1);
   }
}
}

```
「Salesforceノンコーディング開発」親オブジェクトレコード項目に子オブジェクトレコードの最新の値を表示させる方法

今回はSalesforceの「フロー」機能を使用し親オブジェクトから最新の子オブジェクトのレコード情報を更新させるフローを紹介します。

想定される状況として今回は
「取引先から最新の完了予定日の商談名を表示させたい」
という状況です。
（取引先にはOpportunitykakunou__cというカスタムテキスト項目を作成し、そこに商談名を更新させる想定です）

では、まずはフロー全体像です
![フロー04101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/cd9b334b-7f81-20fd-b642-7000c0776f7a.png)

一個ずつ確認しましょう

ステップ１
商談オブジェクトでレコードが作成または更新された場合にフローが起動するように設定

ステップ２
商談オブジェクトのレコードを取得します。
![フロー04012.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/49d8bf64-25fb-2642-5045-3e07fcfd10fe.png)
ポイントとしては「並び替え」でCloseDate(完了予定日)を昇順に設定することです。これにより完了予定日が最も最新の商談レコードが取得可能です

ステップ３
取引先レコードを更新します。
![フロー04103.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/b76ea03f-bb2d-227b-256d-1fd2c9791a41.png)

これにより、取得した商談レコードの内容が取引先レコードに更新されます。


商談レコードの削除がある場合

削除がある場合は下記フローの作成が必要です
![フローd04101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/acea66d5-d1d1-90f5-cf94-3d8715458189.png)

ますは削除を起点にフローを動かします

![フローd04102.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/4ea6e9fc-b09b-36cd-8804-6f49cf2799cb.png)


次は商談レコード取得です。ポイントとしては今回削除する商談レコードは抜くことでしょう


そして取引先の更新
![フローd04103.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/27799507-1849-9835-e26b-48b34ab224b2.png)


いかがでいたでしょうか。
簡単なフローですが使い道は結構あるかと思いますので、ぜひ皆様試してみてください！
仲介ドライブとデータ圧縮を使ってデータ移行する方法[dd]

# はじめに
ddコマンドは間違って使った場合はデータの損失のリスクがあります。ディスクコピーの状況によってこの記事のコマンドが適用できない場合も考えられますので、リファレンスを確認したうえで実行は自己責任でお願いします。

## TL;DR
- 3つのドライブを用いてデータのコピーをする。
    - ドライブ1: 「コピー元」のドライブ
    - ドライブ2: 「仲介役」
    - ドライブ3: 「コピー先」のドライブ
- `if`と`of`の指定を間違えた場合のリスクを軽減することができる。
    - 操作1では「コピー元」のディスクイメージを「仲介役」内に作成
    - 操作3では「仲介役」のディスクイメージを「コピー先」に展開
    - 操作を分ける、同時に接続しないことで「コピー先」から「コピー元」に書き込ませない
- 複数コアを利用する圧縮コマンドを用いることでコピーの高速化を行う。

## 参考にした記事
> ディスクイメージの作り方(圧縮あり)
 https://www.cyberciti.biz/faq/unix-linux-dd-create-make-disk-image-commands/
> pigz, unpigzの使い方
https://www.baeldung.com/linux/gzip-and-gunzip

# 内容
`pigz, unpigz`は`gzip, gunzip`の複数コアに対応したバージョンである。
pigz=`parallel implementation of gzip`

## 1. ディスクイメージの作成

「コピー元」(`/dev/sdX`)と「仲介役」のドライブをつける。
「コピー元」(`/dev/sdX`)の内容をマウントした「仲介役」内の`compressed.gz`に圧縮する。`status=progress`で進捗を確認することができる。

``` bash
dd if=/dev/sdX conv=noerror,sync status=progress bs=512K | pigz -c >/path_to_compressed.gz
```

### 2. ドライブの入れ替え
「コピー元」(`/dev/sdX`)のディスクを外して「コピー先」(`/dev/sdY`)をつける。

### 3. ディスクイメージの展開
「仲介役」内の`compressed.gz`の内容を「コピー先」(`/dev/sdY`)に展開する。`status=progress`で進捗を確認することができる。

``` bash
unpigz -c /path_to_compressed.gz | dd of=/dev/sdY conv=noerror,sync status=progress bs=16M
```
【初学者向け】ターミナルで頻繁に使うコマンド

ターミナル上でめちゃくちゃよく使うコマンドをまとめておく。
プログラミングを学習し始めた方は何度も自分でターミナルで実行してみて無意識に打てるようにすることをおすすめする。

### cdコマンド
ディレクトリを移動することができるコマンド。

### lsコマンド
ディレクトリの中身を確認することができるコマンド。今いるディレクトリの中身にはどんなファイルが存在しているのか確認することができる。

### mkdirコマンド
make directoryの略っぽい。翻訳の通り、ディレクトリを作成するコマンド。

### rmコマンド
ファイルを削除するコマンド。オプションなどたくさんあるので、その都度調べるといい。

### cpコマンド
コピーをするコマンド。ファイルのコピーができる。

### catコマンド
ファイルの中身に何が書かれているのかを確認することができるコマンド。


本当に最低限のコマンドのため、知らなかったら恥ずかしい。がんばりましょう。
GitHub Pages(Github io)で出会ったエラー

# はじめに
ある日youtubeで以下の動画を見かけました。

<iframe width="560" height="315" src="https://www.youtube.com/embed/B1iabPM69vM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

「Javascriptでチャリ走みたいなものを作ることができるのか！？」みたいな驚きを受け自分も作ってみました。
あ、ちなみにチャリ走とは

>チャリ走シリーズ（チャリそうシリーズ、BIKE RIDER series）は、クリエイターの護美童子によって生み出され、その後スパイシーソフトによって開発・販売されているアクションゲームであり、プレイヤーは自転車に乗った棒人間になり、自動スクロールする地面の上を走り、障害物や崖はジャンプで飛び越えていくゲーム。→#ゲームシステム
2007年にiアプリとしてゲーム投稿サイトのアプリゲットで公開されて以降、2015年7月現在までにシリーズ累計2000万ダウンロードを記録。
フィーチャーフォンからスマートフォンやニンテンドー3DSでも作品を配信。初のニンテンドー3DS作品であるチャリ走DXは週刊ファミ通による2013年ダウンロードゲームソフト1位に選出、ニンテンドー3DSダウンロードソフト歴代売上ランキングでも5位に入るなどシリーズ累計ダウンロード数は2000万を超える。日本国内のみならず、海外マーケットでも高い評価を受けているゲームである。

出典：Wikipedia

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654472/2391696a-89fe-a5a4-7793-ecd1a59b3f3b.png)

↑こんなやつですね。

とまあJavascriptの練習がてら作ってみて、`Github pages`を使って無料でWebに公開できるからしてみるか
としてたときに遭遇した404のエラーの対処法をまとめています。

# 対処法
このGithub pageのエラーの対処法はぐぐってみると分かるのですがたくさんの方がいろいろな対処法を共有してくれています。
例えば以下の記事の方は作り方から対処法までまとめてくれていました。自分も作る際にはお世話になりました。

>* [GitHub Pagesの作り方（404が出てしまい挫折した人向け)](https://qiita.com/KOJI-YAMAMOTO/items/38578a3f4c822a15ef49#%E8%A3%9C%E8%B6%B3)

また以下の記事もとても参考になりました。（ちなみにこの記事の内容はファイル名に由来するエラーのことについて書かれています）

>* [【GitHub Pages】404 Not Foundになってしまう場合](https://qiita.com/tanaShoe/items/d3b4e0d17e79a9b42187)

実はもう一つ注意するべきことがありまして、リポジトリにフォルダを作ってはいけないということです。
自分もなんで404が出続けるのだろうかと悩んでいて、フォルダをなくしたら解決しました。（以下のサイトがその時参考にしたサイトです）

>* [Github Pages でサイトを公開したいが、404エラーに悩んでいます。](https://teratail.com/questions/139933)

上記の3つのサイトで基本的には設定はちゃんとできると思います。
設定したあとに気長に10分程度待ってしっかりとWebページが表示されれば晴れてGithub pagesの構築は完了です。
お疲れさまでした。

# 最後に
今回はGithub pagesの404エラーの対処法について紹介させていただきました。意外に紹介されていないフォルダに関するエラーについてエラーに悩んだ人の助けになればいいなと感じています。
PEP 647 (User-Defined Type Guards) を読んだよメモ

今朝、[PEP 647 (User-Defined Type Guards)](https://www.python.org/dev/peps/pep-0647/) が [Accepted になったというPR](https://github.com/python/peps/pull/1917)を見かけました。
そこで、今回は PEP 647 を読んでみようと思います。

## 概要

* 型チェッカーツールでは type narrowing と呼ばれる手法を使って、プログラム内で型情報をより正確に決定しています。

  以下の例では if文と `is None` を利用して、自動的に if 文の中の型が絞り込まれます。

  ```
  def func(val: Optional[str]):
    # "is None" type guard
    if val is not None:
        # Type of val is narrowed to str
        ...
    else:
        # Type of val is narrowed to None
        ...
  ```

  他にも `isinstance()` など、いくつかの判定で type narrowing が行われています。

* しかし、以下のようにユーザー関数を利用して判定している場合には、type narrowing は意図通りには働きません。

  ```
  def is_str_list(val: List[object]) -> bool:
    """Determines whether all objects in the list are strings"""
    return all(isinstance(x, str) for x in val)

  def func1(val: List[object]):
    if is_str_list(val):
        print(" ".join(val)) # Error: invalid type
  ```

* そこで、新しい型情報 `typing.TypeGuard` を通じて **ユーザー定義 型ガード** (user-defined type guard) を定義できるようにします
* ユーザー定義 型ガードを用いることで、type narrowing のサポートを受けやすくなります
* ユーザー定義 型ガードは pyright にはすでに実装済みで、 `typing.TypeGuard` による定義は 3.10 から利用可能です

## アプローチ

`is_str_list()` のような bool を返す関数の返り値の型として `typing.TypeGuard` を指定します。

```
from typing import TypeGuard

def is_str_list(val: List[object]) -> TypeGuard[List[str]]:
    """Determines whether all objects in the list are strings"""
    return all(isinstance(x, str) for x in val)
```

型チェッカーは、この関数が True を返した場合に、先頭の引数を `TypeGuard` に指定した型に合致するとみなします。上記の例では、 `is_str_list()` をパスしたデータは `List[str]` として扱われます。

なお、この関数が False を返した場合は type narrowing は行われません。
以下の例では、 `if is_two_element_tuple(...)` のブロックでは type narrowing が行われた結果、型が `Tuple[str, str]` に絞り込まれるのに対して、else ブロックでは型は変化しません。

```
def is_two_element_tuple(val: Tuple[str, ...]) -> TypeGuard[Tuple[str, str]]:
    return len(val) == 2

OneOrTwoStrs = Union[Tuple[str], Tuple[str, str]]
def func(val: OneOrTwoStrs):
    if is_two_element_tuple(val):
        reveal_type(val)  # Tuple[str, str]
        ...
    else:
        reveal_type(val)   # OneOrTwoStrs
```

Union を使っているので、 `Tuple[str]` に絞り込まれるような印象を持ちますが、ユーザー定義 型ガードではそのようには動かないので注意が必要です。

## 感想

* 条件文で型が絞り込まれていることは知っていたけど、type narrowing と呼ばれているのは知らなかった
* 致し方なく `type: ignore` している箇所が減らせるのは気持ちよさそう
* 細かすぎる機能な気がするものの、かゆいところに手が届く感じがある