OmniAICreator/Qiita-1.07M huggingface dataset:
TextFieldの内部に×ボタンを配置する

##完成系
![スクリーンショット 2020-09-08 18.54.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253564/b21a98cf-6d6a-3012-54ee-6bf8237471e3.png)
##やり方
TextFieldにはrightViewというプロパティがあるのでそこにボタンをセットしてあげます。
ただ、rightViewに直接ボタンを配置すると大きさを指定しても拡大されてしまうので、あいだにUIViewを挟みます。

```Swift
class ViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let view = UIView(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
        //ボタンのY座標は(TextFieldの高さ-ボタンの高さ)/2
        let button = UIButton(frame: CGRect(x: 5, y: 5, width: 20, height: 20))
        button.contentEdgeInsets = .init(top: 0, left: 0, bottom: 3, right: 0)
        button.setTitle("×", for: .normal)
        button.backgroundColor = .lightGray
        button.layer.cornerRadius = button.frame.width / 2
        //ボタンに処理を追加
        button.addTarget(self, action: #selector(tappedButton), for: .touchUpInside)
        view.addSubview(button)
        //デフォルトだと表示されていない
        textField.rightViewMode = .always
        textField.rightView = view
    }

    //タップされたときの処理
    @objc func tappedButton() {
        print("tapped")
    }

}
```
AppServiceで.NetCore Identity認証をするとnoscriptのHttpが返ってくる

#現象
AppServiceに公開しているVue.jsで作成したWebアプリで.NetCoreIdentityによる認証を行っているが、
認証に失敗した場合に、responseとして**noscript**タグが記載してあるHttpが返ってくる。
(ローカルでは正しく判定される)

作りとしては単純で、vue-routerのbeforeEachでバックエンドへ認証の問い合わせを行い、失敗したらログイン画面に遷移させるというコード

```javascript:index.js
    router.beforeEach((to, from, next) => {
        authcontroller.auth()
        .then((x) => {
          next()
        }).catch(() => {
          next({ path: '/login', query: { redirect: from.fullPath } })
        })
    });
```

```html:Startup.cs
    <noscript>
      <strong>We're sorry but test doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
```

#原因
どうも.NetCoreIdentityの認証に失敗した場合、デフォルトではHttpStatusCode[**302(Found)**]が返却されるらしい。
これをAppServiceちゃんが良しなにリダイレクトしておかしくなってるっぽい。
(なぜローカルだと発生しないのかは不明)

#対策
認証失敗時のレスポンスコードを指定してやれば良い

```C#:Startup.cs
        public void ConfigureServices(IServiceCollection services)
        {
            services
               .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
               .AddCookie(options =>{
                    // 認証失敗時のステータスコードを変更
                    options.Events.OnRedirectToLogin = context =>
                    {
                        context.Response.Headers["Location"] = context.RedirectUri;
                        context.Response.StatusCode = 401;
                        return Task.CompletedTask;
                    };
               });
        }
```
中文→日本語オンライン翻訳サービス 読み比べ10種 (後半戦)

# 機械翻訳を試行

[前半戦はこちら](https://qiita.com/stonee/items/216a2415c45b81d66ffb)

前回投稿からのつづきです。
同一の文章を中文→日本語翻訳させた結果を並べてみました。
機械翻訳でよく言われるのが、「AIが理解しやすい文章を入力する」ですが、今回は古典なので、その手は使えません。その状態でどこまで各エンジンが対応できるのか、比較してみました。

元ネタ 「[説唐全伝](http://wagang.econ.hc.keio.ac.jp/index.php?%E9%9B%BB%E5%AD%90%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88/%E3%80%8E%E8%AA%AA%E5%94%90%E5%85%A8%E5%82%B3%E3%80%8F/01)」「[説唐](http://open-lit.com/book.php?bid=141)」


# [DeepL](https://www.deepl.com/ja/translator)
![DeepL_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513949/78ee5454-d666-689c-88ff-e7b808ed0bdf.png)

# [Baidu（百度/バイドゥ）翻訳](https://fanyi.baidu.com/#zh/jp/)
![Baidu_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513949/997666e7-5423-430d-c8a0-d5c7becffb65.png)

# [papago ウェブサイト翻訳](https://papago.naver.com/?sk=zh-TW&tk=ja&hn=0)
![papago_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513949/64d90b41-0afe-cccf-9712-18ea816c938b.png)

# [Weblio翻訳](https://translate.weblio.jp/chinese/)
![Weblio_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513949/6aecf8d5-82d8-64a5-65fc-19b0cfda3ca6.png)

# [So-net 翻訳](https://translate.so-net.ne.jp/)
2021年6月現在、ページにたどりつけません。
![so-net_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513949/47a4ca48-580b-7ac8-7c07-6dd3933091be.png)

# [Bing Microsoft Translator](https://www.bing.com/translator?to=ja&setlang=ja)
![bing_2_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513949/fc1aeef5-81ab-d305-cc49-d4fa9e0de841.png)
![bing_2_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513949/4d949125-4d07-8db0-bbde-cb73e36874f3.png)

# [Rakuten infoseek マルチ翻訳](http://translation.infoseek.ne.jp/)
（2020年12月14日 サービス終了）
![infoseek_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513949/2258839b-7d3b-d5b6-8447-4c62968592e5.png)

# [Google翻訳](https://translate.google.co.jp/?hl=ja#view=home&op=translate&sl=zh-CN&tl=ja)
![google_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513949/b26c899e-2a65-832e-ac2a-abbf6e918a86.png)

# [excite翻訳](https://www.excite.co.jp/world/chinese/)
![excite_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513949/54cd087d-98b0-657d-770e-c7745db2d01e.png)

# [Fresh eye 翻訳](http://mt.fresheye.com/ft_cjform.cgi)
（2020年10月30日 サービス終了）
![Fresheye_2_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513949/1412fecd-9e53-8202-394a-a447c2b59386.png)
![Fresheye_2_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513949/6aeb72ed-1062-4ed4-813a-d749b27d6210.png)
![Fresheye_2_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513949/274ec11f-1e15-121c-5186-62e00540f5cb.png)
sqlloaderメモ

コマンド

```
sqlldr <db名>/<パスワード>@<接続文字列> data=<データファイルパス.> control=<制御ファイルパス> LOG=<ログファイルパス(.log不要)> BAD=<エラーファイルパス.> skip=スキップする行数 load=ロードするレコード数
```

コントロールファイル内容
OPTIONS (ERRORS=50)
LOAD DATA 
APPEND
INTO TABLE "<DB名>"."<テーブル名>"
FIELDS TERMINATED BY'	'
TRAILING NULLCOLS ( 
"USERID" ,
"USERNAME" CHAR (10))

データファイル内容
HEADER 20200101
1	あ	
2	い	
TRAILER	000000000000002
新しいMacでなるべく環境を汚さずに最短でJupyterでPandasが使えるように

# 概要

タイトルにある通り、新しい Mac でなるべく環境を汚さずに Jupter Notebook で Pandas(ついでに numpy) も使えるようにする。細かい流派の違いなどはあるかもしれませんが、これがまあ簡単だし、ちょっと使うには最短かなという手順をまとめました。基本的には以下の流れで必要なものをインストールするだけです。

- homebrew
- anyenv
- pyenv(by anyenv)
- miniconda(by pyenv)
- numpy(by conda)
- pandas(by conda)
- jupyter notebook(by conda)

# 手順

brew のインストールは他にも色々あるので割愛。brew がある前提で以下の手順を。

```shell
brew install anyenv
anyenv init
mkdir -p ~/.anyenv/plugins
git clone https://github.com/znz/anyenv-update.git ~/.anyenv/plugins/anyenv-update
anyenv update
anyenv install pyenv
pyenv install miniconda3-4.7.12
pyenv global miniconda3-4.7.12
conda install numpy
conda install pandas
conda install jupyter
```

何も考えず上から順に愚直にやっていけばOK

# 動作確認

こんな感じの test.csv を作っておく

```csv
date,id,value
2020-08-01,1,123
2020-08-02,2,456
```

jupyter notebook を起動

```
jupter notebook
```

ブラウザから notebook にアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121876/786fe49f-5e35-9760-1e86-f750504ae7c2.png)

test.csv があるところで「新規」から Python3 Console を立ち上げて、以下の画面にあるくらいまで実行してエラーにならなければOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121876/0cc71ae9-aace-9f18-5511-dc58fc529671.png)

# 以上

Enjoy your Python life.
ライブラリとフレームワークの違い

#プログラミング勉強日記
2020年9月8日
Reactについて調べていくうちに、ライブラリとフレームワークがこんがらがってしまったのでまとめる。

#ライブラリとは
　ライブラリは多くのプログラムを保有する場所のこと。汎用性が高い関数やクラス、データなどの複数のプログラムを中に入れているもの。ライブラリは実行ファイルではない場合が多いので、単体では動かない。ライブラリは他のプログラムに機能を与えるための部品のような役割を持つ。

　ライブラリには<font color=orange>静的ライブラリ、動的ライブラリ、共有ライブラリ</font>の3種類ある。
　静的ライブラリ：プログラムを構築するときに組み込まれるもの
　動的ライブラリ：プログラム中に所定の時点で読み込まれるもの
　共有ライブラリ：プログラムが実行された時点でメモリ上で展開されるもの


##特徴
〇プログラムの動作が軽くなる。
→複雑なプログラムを使用するとその分動きが鈍るが、様々な機能が詰まったプログラムの部品であるライブラリを使うことで動作を軽くできる。

〇開発スピードが上がる
→ライブラリを使うことで、毎回プログラムを組まなくていい上にライブラリの部分の動作確認が不要になるので、時間短縮になる。

〇言語によって使い分けが必要
→プログラミング言語によって適切なライブラリは異なる。(すべての言語に対応するライブラリはない)


#フレームワークとは
　システム開発を楽に行えるように用意されたプログラムとかひな形のこと。フレームワークは枠組みを準備することで開発作業を楽にできる。
　枠組みや骨組み、構造などといった意味があって、土台となるフレームワークに必要な機能を追加して、アプリ開発を進めていくのが一般的である。

##特徴
〇意味を理解しないとそのフレームワーク以外でシステムを作れない

#まとめ
フレームワークは枠組みを準備することで開発環境を楽にするもの。
　例) Ruby on Rails, AngularJS
ライブラリは複数のプログラムを再利用できるようにまとめたもの。
　例) Railsのslim, PythonのNumpy

#参考文献
[ライブラリとは？使い方をわかりやすく徹底解説！フレームワーク、コンポーネント、モジュールとは何が違う？](https://agency-star.co.jp/column/library)
[フレームワーク (framework)](https://wa3.i-3-i.info/word12470.html)
[フレームワーク](https://www.otsuka-shokai.co.jp/words/framework.html)
Javaでじゃんけん

* [[Q&A] Java「変数strAは初期化されていない可能性があります」エラーの原因 - Qiita](https://qiita.com/QBmiXMBhsB8l4Er/questions/58eb119c852fa45fec4b)の修正

## openjdk インストール

```sh
apt install -y openjdk-14-jdk
```

## ソース

```java:Janken.java
import java.util.Random;

public class Janken {
	public static void main(String args[]) {

		Random rand = new Random(Integer.valueOf(args[0]));
		int comA = rand.nextInt(3);
		int comB = rand.nextInt(3);
		String strA, strB;
		strA = "";
		strB = "";
		switch(comA){
			case 0 :
				strA = "グー";
				break;

			case 1 :
				strA = "チョキ";
				break;

			case 2 :
				strA = "パー";
				break;

			default:
				strA = "";
				break;
		}
		switch(comB){
			case 0 :
				strB = "グー";
				break;
			case 1 :
				strB = "チョキ";
				break;
			case 2 :
				strB = "パー";
				break;

			default:
				strB = "";
				break;
		}
		if(comA == comB){
			System.out.println(
					"コンピュータA:" + strA
					);
			System.out.println(
					"コンピュータB:" + strB
					);
			System.out.println(
					"あいこ"
					);
		}
		else if(((comA == 0) && (comB == 1)) || ((comA == 1) && (comB == 2)) || ((comA == 2) && (comB == 0))){
			System.out.println(
					"コンピュータA:" + strA
					);
			System.out.println(
					"コンピュータB:" + strB
					);
			System.out.println(
					"コンピュータAの勝ち"
					);
		}
		else{
			System.out.println(
					"コンピュータA:" + strA
					);
			System.out.println(
					"コンピュータB:" + strB
					);
			System.out.println(
					"コンピュータAの負け"
					);
		}
	}
}
```

```sh
# コンパイル
javac Janken.java
```

```go
$ java Janken.java 
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
	at Janken.main(Janken.java:7)

$ java Janken.java 0
コンピュータA:グー
コンピュータB:チョキ
コンピュータAの勝ち

$ java Janken.java 1
コンピュータA:グー
コンピュータB:チョキ
コンピュータAの勝ち

$ java Janken.java 2
コンピュータA:チョキ
コンピュータB:グー
コンピュータAの負け
```
Java Script 基礎文法編　1

# 詳細
今日から本格的にJava Scriptを学習しようと思う。
スクールでも学習したが基礎からコードを一つ一つ確実に理解する為アウトプットをしていく！

## 定数
const price = 150; 
price　に 150を代入する事ができる。
ただ、constを使った場合このpriceに再代入する事ができない 

## 変数
let price = 150;
price　に 150を代入する事ができる。
letは再代入する事ができる。
注　基本はconstを使いどうしてもという時だけlet を使うようにする。
Google Colaboratoryでdarknetコマンドが使えない！

<h2>背景</h2>
./darknet detector train 〜でyoloの重みをGoogle Colaboratoryで学習させたかったが（ローカルで動作検証済み）、./darknet: permission deniedと権限エラーが表示される

<h2>環境</h2>
・mac OS Catalina 10.15.6
・Google Colaboratory
・python 3.6.9
・tensorflow 1.4.2 

<h2>内容</h2>
<h3>権限エラー</h3>
まずは、下記を解決する

```
./darknet: permission denied
```
  　　
darknetの権限を変更する事で解決した

```
chmod 755 darknet
```
　　
しかし、再度エラーが
<h3>バイナリファイルの実行エラー</h3>
次に、下記を解決する

```
./darknet: cannot execute binary file: exec format error
```
これは、コンパイルしたファイルが対応しておらず、実行できないとのこと
gccのバージョンがnvccのバージョンと対応していないようだ
　　
実際、Makefileをmakeした際の出力を確認すると

```
gnu version! gcc versions later than 5 are not supported!
```
とgccのバージョンエラーが記載されていた
　　
コンパイラの変更コマンドで確認してみよう

```
!update-alternatives --config gcc
```
やはりどうやらgcc 7のためのようだ

<h2>解決策</h2>
下記コマンドを流し、gcc 4.8をインストールしてデフォルトに設定する

```
!sudo update-alternatives --remove-all gcc 
!sudo update-alternatives --remove-all g++

!sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
!sudo apt-get update

!sudo apt-get install gcc-4.8 g++-4.8

!sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 50
!sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50

!sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc 50
!sudo update-alternatives --set cc /usr/bin/gcc

!sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++ 50
!sudo update-alternatives --set c++ /usr/bin/g++

!sudo update-alternatives --config gcc
!sudo update-alternatives --config g++
```
　　
コンパイラ変更コマンドで確認した結果、きちんとgcc 4.8をデフォルトとして設定することが出来た

```
$!update-alternatives --config gcc
There is only one alternative in link group gcc (providing /usr/bin/gcc): /usr/bin/gcc-4.8
Nothing to configure.
```
　　
　　
以上
RHEL8.2にPHP7.3をインストールする

RHEL8.2はPHP7.2と7.3がインストールできるが、そのままの状態ではバージョン7.2がインストールされる。

```sh
# PHP 7.2 がインストールされる
yum install php
```

バージョン7.3をインストールするには、バージョン7.3のモジュールをデフォルトにしてからインストールするか、バージョン番号を指定してインストールする。

```sh
# PHP 7.3 モジュールをデフォルトにする
yum module enable php:7.3
# PHP 7.3 がインストールされる
yum install php

# もしくは、
# モジュールのデフォルトストリームは変更せずにインストールする
yum install @php:7.3
```

# 参考

- [4.5. RHEL 8 コンテンツのインストールコマンド Red Hat Enterprise Linux 8 | Red Hat Customer Portal](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/installing_managing_and_removing_user-space_components/commands-for-installing-rhel-8-content_installing-rhel-8-content)
[初心者向け]DKimagePickerControllerのススメ

みなさんImagePickerController使ってますかー？？
ライブラリから写真選択出来るヤツですね！！

でもImagePickerって写真一枚しか選択できないんですよね、、
オリジナルアプリ作りたかった僕は、なんとか複数選択出来るの探しました！

![8efce1b680fc1855f6785e8ba7b34374.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679429/7540910a-b99f-82d2-0b1a-1c4d42c390c7.gif)

はい、これです！！
僕は実際に触らないとわかんないのでこちらを参考に作ってみました。
https://github.com/metasmile/DKImagePickerController
https://teratail.com/questions/189732


![スクリーンショット 2020-09-08 18.15.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679429/8a8b9de6-1558-75ab-f545-d4844bdc6aea.png)
ビルドして改めてコードみてみるとふむふむ、、
アセッツに入れてcollectionViewで表示するのか！

外部のライブラリを使うのは初めてでメンターに聞きまくってわかりました！

fetchFullScreenImage　この中でループ回すのか、、、
DKImagePickerController これをインポートするのか、、
KDAssetsってのがあるのか、、

分かったようでわかりませんでした:joy_cat:
Swift深い！！！

僕が作ったサンプルもどうぞ！
https://github.com/rentamaeda/DKImagePickerTest


#参考にしたサイト等
https://github.com/metasmile/DKImagePickerController
https://teratail.com/questions/189732
Vueでコンポーネントの外側をクリックしたら閉じたい

dependencies

```
vue: 2.x
```

## 目的

コンポーネントの外側、または他の部分をクリックしたら、そのコンポーネントを非表示にしたい。

ModalやDialogのようなコンポーネントはscrim(黒い背景のこと)を持つため、外側をクリックしたら閉じるという動きを作りやすい。実際scrimはコンポーネント内ですし。

そうではなく、Popupなどの軽率にフロートしてなおかつ外側をクリックしたら閉じてほしい、というコンポーネントはそれぞれが`document.onclick`に反応する必要がある。

ググってみたらdirectiveで頑張っている例が多い。

- [vue-click-outside](https://www.npmjs.com/package/vue-click-outside)
- Custom Directive

`vue-click-outside`のコード
https://github.com/vue-bulma/click-outside/blob/master/index.js

ハンドラを通したりSSRを想定する過程で少しhakkyになっているように見える。

ここではdirectiveの代わりにWrapper Componentでよりシンプルに解決したい。

## Wrapper (Popup) Component

``` Popup.vue
<template>
  <div @click.stop>
    <slot />
  </div>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
  methods: {
    onClickOutside(e: Event) {
      this.$emit("click-outside");
    },
  },
  beforeMount() {
    document.addEventListener("click", this.onClickOutside);
  },
  beforeDestroy() {
    document.removeEventListener("click", this.onClickOutside);
  },
});
</script>
```

### 解説

`beforeMount`と`beforeDestroy`はサーバーサイドレンダリングでは呼ばれない。
そのため、directiveで必要なサーバーか否かの判定は必要無くなる。

ref: [API — Vue.js](https://jp.vuejs.org/v2/api/#%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3-%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B5%E3%82%A4%E3%82%AF%E3%83%AB%E3%83%95%E3%83%83%E3%82%AF)

あと自身がクリックされた時にdocumentへ通知されないように、空の`@click.stop`を置いている。

## Usages

``` usage.vue
<template>
  <PopOver v-if="popOver.isVisible" @click-outside="togglePopOver">
    <div>{{ contents }}</div>
  </PopOver>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
  data() {
    return {
      popOver: { isVisible: true }
    }
  },
  methods: {
    togglePopOver() {
      this.$data.popOver.isVisible = !this.$data.popOver.isVisible;
    },
  },
});
</script>
```

### 解説

表示/非表示は`v-if`で判定してもいいし、`PopOver`にpropsを渡して自身が判定する方法にしてもいい。
このサンプルでは`PopOver`は何のスタイルも持たず単なる`div`としてDOM Treeには表示されるので、スタイルは好きに変更すれば良いのでは。
AirflowのBigQueryOperatorで  Invalid schema update. Cannot add fields

# 背景
BigQueryOperatorでクエリ結果からテーブルを作成するジョブが以下のエラーでこけてた

``` bash
Exception: BigQuery job failed. Final error was: {'reason': 'invalid', 'message': 'Invalid schema update. Cannot add fields (field: xxxx)'}.
```

# 対応
BigQueryOperatorでのクエリ結果のテーブル作成は、 `write_disposition` を `WRITE_TRUNCATE` にしていても、カラムが追加されるとエラーになる。カラム追加の場合にエラーをでないでテーブル作成したい場合は `schema_update_options` 引数を追加する必要がある。

```py:dag_sample
   task = BigQueryOperator(
        task_id='sample',
        use_legacy_sql=False,
        write_disposition='WRITE_TRUNCATE',
        allow_large_results=True,
        sql='SELECT * FROM sample_original',
        destination_dataset_table="sample_distination${{next_execution_date.strftime('%Y%m%d')}}",
        time_partitioning={"type": "DAY"},
        schema_update_options=['ALLOW_FIELD_ADDITION'], # <- これ
        dag=dag
    )
```

# 参照

[airflow.contrib.operators.bigquery_operator](
https://airflow.apache.org/docs/stable/_api/airflow/contrib/operators/bigquery_operator/index.html)
【GAS】どこのタブだよ・・・って探すのめんどい人のためのスクリプト

## 解決策
1. タブ名とURLの一覧を作成する
2. タブ名を打ったらURLを生成する独自関数を使う

## 背景
テスト項目書や画面仕様書をSpreadsheetで管理すると、タブがめちゃくちゃ増える。
そして

> あれ、、、テスト#102ってどこだ
> C17画面の仕様は・・・。

とか、Spreadsheetスクロール地獄が待っている。
その地獄を知っている人は、 `一覧` 的なタブを作成して、URLを手で貼っているかもしれない。
それは、それで、地獄である。(経験者です)


## 1. タブ名とURLの一覧を作成する
### 完成形
特定のタブに、シートを開くたびに目次を更新してくれるやつを作ろう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219427/1575a4ee-bb88-a7b3-d671-cfe52ccc8442.png)

### スクリプト
```js
function onOpen(){
  // ブックを取得
  const book = SpreadsheetApp.getActive()
  // スプレッドシートキーを取得
  const ss_key = book.getId()
  // ブックに紐づくすべてのタブを取得
  const sheets = book.getSheets()
  // 吐き出し用のタブを取得
  const sheet_index = book.getSheetByName('index')
  // ここにタブ名, URLをためていきます。
  var values = []
  
  for(var i = 0; i < sheets.length; ++i){
    var name = sheets[i].getSheetName()
    var url = 'https://docs.google.com/spreadsheets/d/' + ss_key + '/edit#gid=' + sheets[i].getSheetId()
    values.push([name, url])
  }

  // 削除にも対応するため、一度clear
  sheet_index.clear()
  // 出力
  sheet_index.getRange(1,1,values.length, values[0].length).setValues(values)
}
```

これで毎回作っておいて、index-matchして特定タブのURLのみ引っ張るという手もある。

## 2. タブ名を打ったらURLを生成する独自関数を使う
### 完成形
![url取得.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219427/66c7073b-9569-81fc-20fc-ce3b3dab8b9c.gif)


### スクリプト
```js
function get_ss_url(sheet_name) {
  // ブックを取得
  const book = SpreadsheetApp.getActive()
  // Spreadsheetキーを取得
  const ss_key = book.getId()
  // 該当シートを取得
  const sheet = book.getSheetByName(sheet_name)
  
  return 'https://docs.google.com/spreadsheets/d/' + ss_key + '/edit#gid=' + sheet.getSheetId()
}
```
javascriptで配列の要素がオブジェクトの場合に、全て値渡しでコピーしたいとき

vue.js等を使っていると、dataに定義している配列を、参照渡しじゃなくて、値のみコピーしたい場合ってよくありますよね。

例. 下記のような配列の要素がオブジェクトの場合。

```javascript
const array = [{a: 1}, {a: 2}]
```

下記のようにmapで各要素ごとをスプレッド構文で展開して、pushしていけばおｋ。

```javascript
let newArray = []
array.map(a => {
  newArray.push({...a})
})
```

また、そのタイミングで、新しいプロパティを追加したい場合は、下記のようにすればおｋ

```javascript
let newArray = []
array.map(a => {
  newArray.push({...a, b: 0})
})
```

もっといいコピーの仕方を知っている方がいれば教えて下さい！
VSCodeでDraw.ioを用いて作成した図(.svg)がGitリポジトリ上で表示できない

# 現象
VSCodeでDraw.ioが使えるということを知ったため、使ってみました。
拡張子`.drawio`でファイルを新規作成し、`.svg`形式で保存しリモートのGitリポジトリにpush。
しかしファイルが壊れているのか、図が表示されない。VSCodeではきちんと表示されるのに何故。
ちなみにそれぞれのバージョンは、VSCode：1.48.2、Draw.io Integration：0.7.2。

# 対応策
ファイルの新規作成時に、`test.drawio.svg`といった感じで初めからファイル形式を`.svg`にすることで無事解決。

`.drawio`でファイルを新規作成し、`.svg`でエクスポートする方法もあるようですが、自分の場合VSCode上でエクスポートの項目が見当たらなかったのと、項目を出す方法を調べて試してみてもなぜか現れなかったため、上記の対応になりました。

# 参考
参考にさせていただいた記事一覧
1.[VSCodeでDraw.ioが使えるようになったらしい！](https://qiita.com/riku-shiru/items/5ab7c5aecdfea323ec4e)
2.[vscode-drawio 最新版(v0.4.0) でExportできない](https://qiita.com/kE-sakai/items/a5331d5e59125260c189)
Rails バリデーションとは

RailsでDBに値を保存する際、無意味なデータや想定外のデータの登録を防ぐ「バリデーション」。備忘録として、書き方や例をまとめます。

バリデーションとは
先にも書きましたが、データを保存する前に、無効なデータでないことを検証する機能のこと。門番みたいなものです。
空のデータが保存されないようにしたり、数字以外は保存できないようにしたり、文字数に制限を設けたり……保存するデータに制限をかける時に使います。

基本的な書き方
Railsではモデルクラスに、validatesメソッドで指定します。

```
validates :カラム名(シンボルで指定),検証ルール（こちらもシンボルで指定）
```

これだけでは理解しづらいので、次から例を用いて書いていきます。
ユーザーモデルにname,age,email,genderのデータを追加していく例になります。

空データを登録できないようにする→presence

```user.rb
class User < ApplicationRecord
  validates :name, presence: true
end
```

文字数の制限を設ける→length

```user.rb
class User < ApplicationRecord
  validates :name, presence: true, length: { maximum: 50 }
end
```

ここでは名前の長さの上限を50文字にしました。下限や範囲の指定もできます。

```
#長さの下限を2文字に設定→minimum
validates :name, length: { minimum: 2 }
#長さの範囲を2-50文字→in .. 
validates :name, length: { in: 2..50 }
#長さを5文字に指定→is
validates :name, length: { is: 5 }
```

数値のみを許可する→numericality、空を許可するallow_blank
ageカラムは数字のみ、空でも構わない例です。

```user.rb
class User < ApplicationRecord
  validates :name, presence: true, length: { maximum: 50 }
  validates :age, numericality: { only_integer: true }, allow_blank: true
end
```

numericalityは、デフォルトでは小数も許容してしまいます。ageカラムでは整数のみ許可したいので、 only_integerを。
また、numericalityは空を許可しないため、空を許可する場合はallow_blank: trueを追加します。（空を許可せず、数値のみを許可する場合はnumericalityのみ、 presence: trueは無くても良い。）

同一データは一つのみ許可する→uniqueness
emailカラムには同じデータを登録できないようにします。

```user.rb
class User < ApplicationRecord
  validates :name, presence: true, length: { maximum: 50 }
  validates :age, numericality: { only_integer: true }, allow_blank: true
  validates :email, presence: true, uniqueness: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i}
end
```

ここではuniqueness: trueを用いました。format:では、文字列が条件に適しているかの検証を行います(ここでは割愛させていただきます)。

特定の値が含まれているか確認する→inclusion
genderカラムに、1~3(1:male, 2:female, 3:other)のいずれかの数字が保存されるとします。


```user.rb
class User < ApplicationRecord
  validates :name, presence: true, length: { maximum: 50 }
  validates :age, numericality: { only_integer: true }, allow_blank: true
  validates :email, presence: true, uniqueness: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i}
  validates :gender, presence: true, inclusion: { in: 1..3 }
end
```

おわりに
ほんの一部ではありますが、validationについてまとめてみました。
まだまだ知らないことだらけですが、日々勉強していきます！

初心者ですので、間違っている点等あればご指摘いただけますと幸いです。
laravelで使わないマイグレーションファイルがあってエラーになった時の対処

# 背景
自分の場合は他の人が作ってくれたlaravelの環境で開発を進めたので自分の知らないマイグレーションファイルがあった。
必要なものなのかと思い残していたが、ある時そのファイルでエラーが起こった。
その内容は現在使っていないマイグレーションファイルがあることでテーブルが作れませんよーみたいな感じ。

# 本編
雑だけど手っ取り早い方法はマイグレーションする時に生成されるlocalというスキーマを削除してから
マイグレーションファイルを削除して新しく作り直して解決した。

手順は以下のようにやった。

1. MySQLに入ってlocalというスキーマを全て削除した
2. database/migration/の中にあるエラーが出ているファイルを削除した
3. ターミナルで`php aritisan migrate`でやり直した

# まとめ
使っていないマイグレーションファイルのせいでエラーが出た時は新しく作り直したらできた。
現在使っていないマイグレーションファイルとかは邪魔になったりそれが原因でエラーになったりあるので消して綺麗にしておきましょう。
systemclt & service 早見表 (CentOS7 & Amazon Linux 2)


CentOS7 や Amazon Linux 2 での systemctl や service の早見表。

root や sudo で実行する必要あり。
基本的に sudo を基本に書いていきます。

systemclt と service は基本的に反対

# 起動

```
$ sudo systemctl start [UNIT]
$ sudo service [UNIT] start 
```

例

```
$ sudo systemctl start nginx
$ sudo service nginx start 
```

# 設定反映 (config 読み込み)

設定の適用なので、サービスの瞬断は無いはず。

```
$ sudo systemctl reload [UNIT]
$ sudo service [UNIT] reload
```

例

```
$ sudo systemctl reload nginx
$ sudo service nginx reload
```


# 再起動

サービスの瞬断あり。

```
$ sudo systemctl restart [UNIT]
$ sudo service [UNIT] restart
```

例

```
$ sudo systemctl reload nginx
$ sudo service nginx reload
```


# 停止

```
$ sudo systemctl stop [UNIT]
$ sudo service [UNIT] stop
```

例

```
$ sudo systemctl stop nginx
$ sudo service nginx stop 
```

# ステータス表示

```
$ sudo systemctl stop [UNIT]
$ sudo service [UNIT] stop
```

例

```
$ sudo systemctl status nginx
$ sudo service nginx status 
```

# サービス自動起動設定

サーバー起動時に、自動的にサービスを立ち上げるかどうかの設定。

## 有効化

```
$ sudo systemctl enable [UNIT]
$ sudo service [UNIT] enable
```

例

```
$ sudo systemctl enable nginx
$ sudo service nginx enable
```

# サービス自動起動設定

## 無効化

```
$ sudo systemctl enable [UNIT]
$ sudo service [UNIT] enable
```

例

```
$ sudo systemctl enable nginx
$ sudo service nginx enable
```

# サービス一覧表示

```
$ sudo systemctl list-unit-files --type=service
```

# 設定ファイルの再読み込み


```
$ sudo systemctl daemon-reload
リスト型、タプル型２

リスト型、タプル型２

アンパック代入
スライスを使った代入に似た機能としてアンパック代入があります。
イコールの左右に複数の要素を記入して、一度に複数の要素に対して代入を行う機能です。
アンパック代入では、イコールの左右で要素数が揃っていないとエラーになるので注意が必要です。
アンパック代入を使うと、次のように一発で変数の入れ替え（Swap）を実行できます。
変数などを使って要素を保存しておく必要がありません。
【アンパック代入を使う】
a = 1
b = 2
b, a = a, b 
print(a, b)
↓
2 1

※Pythonでは、複数の要素をカンマで区切って列挙すると、タプルとして扱われます。
　この記法を使うと、丸括弧を使わずにタプルを作ることができます。
　アンパック代入では、タプルの要素として含まれた変数を対象に、代入を行っていることになります。


スライスのステップ数
スライスに与えるコロン（：）で区切ったパラメータは、実は、3つ与えることができます。
3つ目の数値はステップとして扱われます。
スライスで「n個とばしながら要素を取り出す」という指定ができます。
【リストからスライスで要素を取り出す】
a = [1, 2,3 ,4, 5]
a
↓
[1, 2, 3, 4, 5]

a[1:4]
↓
[2, 3, 4]

a[2:100]
↓
[3, 4, 5]

a[::2]
↓
[1, 3, 5]
※リストから偶数番目の要素を取り出す


スライスを使った要素の代入と削除
スライスと代入を組み合わせると、リストの複数の要素を一括して置き換えることができます。
置き換えを行いたい要素をスライスで指定し、イコールの左に置きます。
置き換えたい要素をイコールの右側に置きます。
右側の要素は、リストやタプルなどのシーケンスである必要があります。
【要素の追加】
a = [1, 2, 3, 4, 5]
a[2:4] = [’Three’, ‘Four’, ‘Five’]
a
↓
[1, 2, ’Three’, ‘Four’, ‘Five’, 5]

イコールの左側では、（0から数えて）2番目と3番目の要素をスライスで指定しています。
右側の要素では、3つの文字列を持ったリストを指定しています。
左右で要素の数が異なる場合でも、自動的に整合性を保つように処理をしてくれます。
del文とスライスを組み合わせると、複数の要素をいっぺんに削除することができます。
【要素の削除】
a = [1, 2, 3, 4, 5]
del a[2:]
a
↓
[1, 2]
※2行目の「del a[2:]」で3番目から最後まで削除する
【Vue.js】ボタンの切り替えテクニック

モダンなサイトだと、ボタンをクリックしたらアイコンが切り替わって、内容が見れたりするようなUIも増えてきていますよね。

そんなボタンの切り替えの構造をVue.js(Nuxt.js)で表現していこうと思います！

#ボタンを押すと、記事内容の表示・非常時を切り替えられる

###ボタンをそして、あるデータの真偽値を変化させる

```vue:
<v-btn @click="show = !show" icon>
</v-btn>
```

```vue:
<script>
expprt default {
  data () {
    return {
      show: false
    }
  }
}
</script>
```

ボタンを押すと、falseの真偽値が切り替わる

###showの真偽値によって変化する者たち

```vue:
<v-btn @click="show = !show" icon>
  <v-icon>{{ show ? 'mdi-chevron-up' : 'mdi-chevron-down' }}</v-icon>
</v-btn>
```

showの真偽値、そして三項演算子によって、アイコンの見た目が変わるようになっている。

```vue:
<v-expand-transition>
  <div v-show="show">
    <v-divider></v-divider>
    <v-card-text>
      <ul>
        <li v-for="item in items" :key="item.id">
          <a href="item.url">{{ item.title }}</a>
        </li>
      </ul>
    </v-card-text>
  </div>
</v-expand-transition>
```

`v-show`の真偽値がtrueの場合は、div以下のコンポーネントが表示されて、falseの時は隠れるようになっている。



#パスワードの入力内容を見たり、隠したりする

###

```vue:
<v-text-field 
  label="パスワード"
  v-model="signupForm.password"
  @click:append="show = !show"
></v-text-field>
```

`append`はボタンの配置を設定している

```vue:
<script>
expprt default {
  data () {
    return {
      show: false
    }
  }
}
</script>
```

例の如く、showの真偽値をボタンによって切り替えている。

###showの真偽値によって、テキスト内容を見たり隠したりする

```vue:
<v-text-field 
  label="パスワード"
  v-model="signupForm.password"
  :type="show ? 'text' : 'password'"
  :append-icon="show ? 'mdi-eye' : 'mdi-eye-off'"
  @click:append="show = !show"
></v-text-field>
```

`type`属性をshowによって紐づけ(bind)て、入力フォームのタイプを切り替えている
`icon`もshowによって紐づけ(bind)て、アイコンの見た目を切り替えている
【後編①】ネットワーク構築（IPsec）

##今回やること
前回引き続き、IPsecについて学習していこうと思います。

机上で学習していても概要ばかりしか分からないので、実際にコマンドを叩いていこうと思います。
習うより慣れろですね。
分からないなりに色々試していこうと思います。（時間はかかりますが・・・）

前回の記事
⇒[【前編】ネットワーク構築（IPsec）](https://qiita.com/nishi-infr/items/9e3bd5bcd67750aab711)

##使用ツール
GNS3
IOS: c2600-adventerprisek9-mz.124-17

##ネットワーク構成図
今回の目的はコマンドを打って、とりあえず感覚をつかむのが目的なので構成自体は簡単なものでいいです。
そしてできた構成図が以下。
![IPSEC.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686507/4aa20332-e497-ea4e-c74d-ed78528613e1.jpeg)

さて構築していきます。

##構築
コンフィグはある程度見ましたが、各コマンドラインの意味を理解しきれていないので
手探り感は出ながらも、コマンドが弾かれたら調べてを繰り返していこうと思います。

では早速**R1**から。
まずは認証方式の設定まで投入していきます。

```
R1#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
R1(config)#cryp
R1(config)#crypto isk
R1(config)#crypto isakm
R1(config)#crypto isakmp poli
R1(config)#crypto isakmp policy 1
R1(config-isakmp)#au
R1(config-isakmp)#authentication pre
R1(config-isakmp)#authentication ?
  pre-share  Pre-Shared Key
  rsa-encr   Rivest-Shamir-Adleman Encryption
  rsa-sig    Rivest-Shamir-Adleman Signature

R1(config-isakmp)#authentication p
R1(config-isakmp)#authentication pre-share
R1(config-isakmp)#exit
R1(config)#
```
これで認証方式まで投入できました。
次にトランスフォーマットセットの設定を投入してみます。

```
R1(config)#
R1(config)#cr
R1(config)#cry
R1(config)#crypto isak
R1(config)#crypto isakmp key 0 kensyo add
R1(config)#crypto isakmp key 0 kensyo address 192.168.12.2
R1(config)#cry
R1(config)#crypto ip
R1(config)#crypto ipsec tran
R1(config)#crypto ipsec transform-set
```
コマンドがわからーーん！笑

調べつつ投入。
IKEのフェーズ１と２を勉強しましたが、今フェーズいくつ！？となりながらも
手探りでいれていきます・・・

恐らくこのコマンド。
**crypto ipsec transform-set [名前] [transform1] [transform2]**
そして投入。

```
R1(config)#crypto ipsec transform-set KENSYO esp
R1(config)#crypto ipsec transform-set KENSYO esp-aes
R1(config)#crypto ipsec transform-set KENSYO esp-aes esp?
esp-md5-hmac  esp-sha-hmac

R1(config)#crypto ipsec transform-set KENSYO esp-aes esp-s
R1(config)#crypto ipsec transform-set KENSYO esp-aes esp-sha-hmac
R1(cfg-crypto-trans)#exit
R1(config)#
```
多分OK。
それにしても暗号化の種類色々あって、どれを入れるのか正直分からない・・・
この辺も勉強していかなくては。

ちょっと今回は予定時間超えそうなので、分割します。
ということで、**write**して中断。

```
R1(cfg-crypto-trans)#exit
R1(config)#exit
R1#
*Mar  1 03:26:23.532: %SYS-5-CONFIG_I: Configured from console by console
R1#write memo
Warning: Attempting to overwrite an NVRAM configuration previously written
by a different version of the system image.
Overwrite the previous NVRAM configuration?[confirm]y
Building configuration...
[OK]
R1#
```

##まとめ
わからないことだらけで、調べながらだと時間が足りないですね。

やはり時間かけないと覚えきれない範囲だということが身に染みてわかったので、
調べつつ構築して、知識を付けていきたいと思います。

次回は構築の続きから行きたいと思います。

以上となります。
IBM Cloud Activity Tracker with LogDNAから直近のアクティビティをCSV形式で出力してみた

#はじめに
IBM Cloud Activity Tracker with LogDNAはIBM Cloud上のアクティビティーを（監査目的などで）モニタリングすることが可能なサービスである。主にUIからダッシュボードなどでアクティビティーを確認できるし、IBM Cloud Object Storage(ICOS)などにそのログをアーカイブして保存しておくことができる。
本稿では、IBM Cloud Activity Tracker with LogDNAへコマンド一発で直近のアクティビティをCSV形式で出力する方法を紹介する。

#1. Activity Tracker with LogDNAを注文する
（省略）

#2. Export機能が有効化されていることを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/2902891e-1256-599a-372a-ab14a6ffb340.png)


#3. Service Keyを作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/b53a9074-c546-4e01-9c86-35184c194f97.png)


#4. APIを使ってアクセス。

https://cloud.ibm.com/docs/Activity-Tracker-with-LogDNA?topic=Activity-Tracker-with-LogDNA-export_api

ポイント

1. IBM Cloud docsにはpublic endpointしか記載されていないが、private endpointでもアクセスできる。<br> https://cloud.ibm.com/docs/Activity-Tracker-with-LogDNA?topic=Activity-Tracker-with-LogDNA-endpoints <br> 例えば、`https://api.jp-tok.logging.cloud.ibm.com`の代わりに、`https://api.private.jp-tok.logging.cloud.ibm.com`のように**private**を含めてアクセスすればよい。もしIBM Cloud上のVSIなどからコマンドを叩けば、Internetに出ることなくログを出力することができる。
2. IBM Cloud docsには`-u USERID`でユーザーIDを指定しているが、パスワード(Service Key)も一緒に指定したければ`-u USERID:SERVICEKEY`と指定すれば良い。
3. データの昇順、降順の好みがあるが、私は最新のログは一番下に出てきてほしいので、`prefer=head`を指定。
4. 抽出するログの指定のために、toは`$(date +%s)000`で現在時刻を指定、fromは`$(($(date +%s)-3600))000`で1時間前を指定。
5. CSV形式で出力したいので`|@csv`を指定。


```
$ USERID=xxxxx
$ SERVICEKEY=yyyyy
$ curl -s "https://api.private.jp-tok.logging.cloud.ibm.com/v1/export?to=$(date +%s)000&from=$(($(date +%s)-3600))000&prefer=head" -u "$USERID:$SERVICEKEY"|jq -r '[.eventTime, ._platform, .message, .action, .outcome, .initiator.name]|@csv'

（略）
"2020-09-08T08:06:04.98+0000","is","Subnet for VPC: read subnet khayama-iks-subnet-01","is.subnet.subnet.read","success","xxx@xxxxxx"
"2020-09-08T08:06:06.72+0000","is","Subnet for VPC: read subnet vpc-kishida-subnet-tok2","is.subnet.subnet.read","success","xxx@xxxxxx"
"2020-09-08T08:06:07.29+0000","is","Subnet for VPC: read subnet asasaki-subnet1","is.subnet.subnet.read","success","xxx@xxxxxx"
"2020-09-08T08:06:54Z","cloudshell",,"cloudshell.server.create","success","yyy@yyyyyy"
"2020-09-08T08:07:59Z","cloudshell",,"cloudshell.server.delete","success","yyy@yyyyyy"
"2020-09-08T08:08:00Z","cloudshell",,"cloudshell.server.create","success","yyy@yyyyyy"
"2020-09-08T08:08:27Z","cloudshell",,"cloudshell.server.configure","success","yyy@yyyyyy"
"2020-09-08T08:09:13.93+0000","is","Subnet for VPC: read subnet sub-10-0-0-0-24","is.subnet.subnet.read","success","xxx@xxxxxx"
"2020-09-08T08:09:14.54+0000","is","Subnet for VPC: read subnet sub-10-1-0-0-24","is.subnet.subnet.read","success","xxx@xxxxxx"
（略）
```

上記結果から、xxxさんはVPCを触っているのねー、yyyさんはCloudShellを触っているねー、などがわかる。
【Nuxt.js】Nuxt文法編：component①

🎈 この記事はWP専用です
https://wp.me/pc9NHC-DX

# 前置き
componentとは
使いまわしができる、
再利用ができるものです🌟

![button.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469755/961e0e25-0e35-7508-bb65-499a416015c7.gif)


シンプルなボタンでも
CSSが長くなったりして
まいかい書くのは面倒ですよね…😔
それを解決してくれるのが
componentです🌟

作り方、表示のさせ方を解説していきます✍️

# 目次
前置き
componentの種類と使用箇所
基本コード
Step1: 使い回すコンポーネントを作る
Step2: コンポーネントをインポートする
自動でインポートする
まとめ

# componentの種類と使用箇所
## 種類

まずは種類を把握しましょう。
おおまかに全部で3つあります💡
今回は1の自作のコンポーネント
について解説していきます🍎
前置きに書いたボタンのような場合は
自作のコンポーネントに該当します🙋‍♀️

1. <好きに命名した名前 />
　=自作のコンポーネント
　importが必要！
2. <nuxt />
　layouts内でのみ使用
3. <nuxt-child />
　ネストされたルート内で使用

nuxtとnuxt-childについては
別記事でご紹介します🌟

## 使用箇所

componentsが使える場所
(インポートできる場所)は
ページを構成する部分です！

・layout
・他のコンポーネント
・pageコンポーネント
自作のコンポーネントの場合は
この中のどれでも使用可能です🤗

# 基本コード
基本コードがこちら。
あとは使いまわしたい物に
作り替えていきましょう👍✨

🎈 続きはWPでご覧ください👀
https://wp.me/pc9NHC-DX
bindValue()の仮引数は何を示しているのか？

# この記事でわかること

- PHPのPDOクラスの関数`bindValue()`の仮引数の中身がわかる

# そもそもbindValue()とは

> ```php
> public PDOStatement::bindValue ( mixed $parameter , mixed $value [, int $data_type = PDO::PARAM_STR ] ) : bool
> ```
>
> プリペアドステートメントで使用する SQL 文の中で、 対応する名前あるいは疑問符のプレースホルダに値をバインドします。
> 　PHP公式リファレンス




ものすごく雑に要約すると、bindValue()とは、
下記SQLクエリ文の"?"部分を別の文字列に置換することができる関数です。
SQLインジェクション対策ですね。


` $sql = "insert into phptodo (name, done, priority) values (?, 0, ?)";`


特に、プリペアドステートメント？PDO？な方は、[こちらの記事](https://qiita.com/tabo_purify/items/d1166236f3b03c7be60d)にまとまっているので参照すると幸せになれます。

SQLインジェクション？という方は、[安全なWebサイトの作り方](https://www.ipa.go.jp/security/vuln/websecurity.html)を参照すると幸せになれます。


なお、bindValue()は第三引数まで取ります。

# bindValue()の各引数について考える

## サンプルコード

```php

     $name = "hoge"
     $priority = "high"

     $sql = "insert into phptodo (name, done, priority) values (?, 0, ?)";  // SQLインジェクション対策のプレースホルダ(=?)
     $stmt = $dbh->prepare($sql);

     $stmt->bindValue(1, $name, PDO::PARAM_STR);

     $stmt->bindValue(2, $priority, PDO::PARAM_STR);
     $stmt->execute();

// $sql = "insert into phptodo (name, done, priority) values ("hoge", 0, "high")"
// となる


```

## bindValue()の第一引数

どのプレースホルダ( `$sql` 内の"?"のこと ) に関数を適用するかを数字で指定します。

例えばサンプルコードでは values(?, 0, ?)となっているので、

values内の第一引数の "?" に変更を加えたい場合 => 1
values内の第三引数の "?" に変更を加えたい場合 => 2

と記述します。
数字は0ではなく1から始まるので注意！


## bindValue()の第二引数

第一引数で指定したプレースホルダに何を代入するかを指定します。
ここでは変数 `$name` や `$priority` を代入しています。


## bindValue()の第三引数

第二引数で指定した内容をどのようなデータ型にするかを指定します。

`PDO::PARAM_INT` `PDO::PARAM_STR`など

これらはInteger型の定数で、例えば`PDO::PARAM_STR`はInteger型の`2`を表しています。
（このため、`PDO::PARAM_STR`ではなく`2`と記述しても同等の内容が実行されます）

```php
print(PDO:PARAM_STR)

// 2
```

他の定数は[ここ](https://www.php.net/manual/ja/pdo.constants.php)


# プレースホルダに"?"を使わない方法

蛇足ですが、プレースホルダを任意の文字列にして可読性を高める方式もあります。

SQL文の"?"を`:hoge`や`:fuga`として、
更に`bindValue()`の第一引数を数字ではなく`":hoge"`や`":fuga"`と指定します。

## サンプルコード

```php
    $sql = "insert into phptodo (name, done, priority) values (:name, 0, :priority)";  
    $stmt = $dbh->prepare($sql);

    $stmt->bindValue(":name", $name, PDO::PARAM_STR);
    $stmt->bindValue(":priority", $priority, PDO::PARAM_STR);
    $stmt->execute();

```


# 参考

- [PDOStatement::bindValue(PHP公式リファレンス)](https://www.php.net/manual/ja/pdostatement.bindvalue.php)
- [定義済み定数(PHP公式リファレンス)](https://www.php.net/manual/ja/pdo.constants.php)
- [PDOで接続、SELECT、プリペアドステートメントとは（PHPでMySQLに接続)](https://qiita.com/tabo_purify/items/d1166236f3b03c7be60d)
- [安全なWebサイトの作り方](https://www.ipa.go.jp/security/vuln/websecurity.html)
JDBCでSQL ServerにWindows認証でログインする。

#Windows認証用DLLを指定のフォルダに置く
[djbcドライバダウンロードサイト](https://docs.microsoft.com/ja-jp/sql/connect/jdbc/download-microsoft-jdbc-driver-for-sql-server?view=sql-server-ver15)

配置場所：C\Windows\System32\\**sqljdbc_auth.dll**

・ダウンロード時はプロセッサアーキテクチャがファイル名含まれるため、リネームすること。
・x86、x64は自身のCPUと一致したdllを使用すること。

後述するが、厳密にはSystem32配下でなくともよい。

#接続文字列にWindows認証を行うことを明記する。
jdbc:sqlserver://サーバ名:ポート番号;DatabaseName=DB名;**IntegratedSecurity=true**

#よく出たエラーメッセージ
・このドライバーは、統合認証を行えるようには構成されていません。
・no sqljdbc_auth in java [dllを探したパスの一覧]

①sqljdbc_auth.dllが正常なパスに存在してない可能性が高い。
dllを探したパスの一覧のどこかに、dllが存在すればよい。
②存在しているのに解決しない場合、プロセッサアーキテクチャの一致していないdllを使用している可能性が高い。
History APIでルーティングしてる時の存在しないページへのフォールバックってどうすんの？

JavaScriptでSPAのルーティングを実装するため[History API](https://developer.mozilla.org/ja/docs/Web/API/History_API)を使っていたところ、操作した後のパスでリロードをした時にこんな画面になりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89911/629a4922-3085-c030-a0e2-df0bfff99965.png)

404です（WARNINGは拡張機能起因のものなのでスルーします）。
ちなみにサーバーはVSCodeの[Live Server Extension](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer)を利用しています。

なぜ？と思う前に冷静にこのアプリのディレクトリ構成を確認します。

```
|-- index.html
|-- style.css
|-- js
    |-- main.js
    |-- router.js
```

よく見れば当たり前の話です。`newPost.html`なんて存在せず、`index.html`しかないので、ルートとなる`http://127.0.0.1:5500/`以外はそもそも存在しません。そりゃ404にもなります。

あれ、でもVueとかNuxt使ってる時に直接このパス見に行ってもページ表示できたよな？あれどうなってんだと思い調べてみることにしました。

## Vue Routerのドキュメントをちゃんと読む

Vueのルーティングを司っているVue Routerのドキュメントを確認すると答えはありました。

[HTML5 History モード](https://router.vuejs.org/ja/guide/essentials/history-mode.html)

どうやらhashとhistoryという2つのモードがあるみたいです。

### hashモード

> vue-router のデフォルトは hash モード です - 完全な URL を hash を使ってシミュレートし、 URL が変更された時にページのリロードが起きません。

hashモードってアレだ！URLが`https://example.com/#/user`みたいに`#`が間に含まれてるやつだ。思い出した。昔Angular.jsで開発してたときもHistory APIがどうのこうのってこのhashモードを使ってました。

hashモードが動く理由は、URLのアンカー`#`の動きを利用して`https://example.com/#/user`の例で言えば実際は`https://example.com`を見に行くという理解を得ました。となるとその中で更にアンカーでのスクロールを実装したいときどうなるんだろう？`https://example.com/#/user#profile`みたいなケース。……これは別の機会に調査します。

### historyモード

> history モードを使用する時は、URL は "普通" に見えます e.g. http://oursite.com/user/id。美しいですね!
>
> しかしながら一点問題があります。シングルページのクライアントサイドアプリケーションなので、適切なサーバーの設定をしないと、ユーザーがブラウザで直接 http://oursite.com/user/id にアクセスした場合に 404 エラーが発生します。

まんまこの問題ですね。

> 心配する必要はありません。この問題を直すためには、単純な catch-all フォールバックのためのルートをサーバー側で追加するだけです。もし URL がどの静的なアセットにもマッチしなかった時はあなたのアプリケーションが動作しているのと同じ index.html ページで受け付けましょう。これも美しいですね!

なるほど！フロント側ではやはりどう足掻いても駄目みたいですね。Vue CLIやらNuxtでの開発は便利ですが、こういうのも隠蔽して裏側でやってくれていたということっぽい。たまにはフレームワーク抜きでJavaScript触るのも学びがあって良いですね。

## History API利用時のフォールバックを設定する

[HTML5 History モード](https://router.vuejs.org/ja/guide/essentials/history-mode.html)

上記のページに以下のケースでのフォールバックは設定例があるのでこのまま使えそうです。

- Apache
- nginx
- Node.js
- Express
- IIS
- Cady
- Firebase

これ以外で今回私が個人的に使ってるLive Server ExtensionとNetlifyでの実装も調べたのでここに残しておきます。

### Liver Server Extension

VS Codeの設定ファイルに以下を追記します。

```json
{
  "liveServer.settings.file": "index.html"
}
```

念の為、個人設定ではなくワークスペース単位での設定をオススメします。

### Netlify

`_redirects`ファイルに以下を追記します。

```
/*   /index.html   200
```

こによりどのパスでアクセスしてもindex.htmlが参照されます。

## サーバーにフォールバックを設定した際の注意点

サーバーに上記のフォールバックを設定した時点で、あらゆるアクセスは`index.html`にリダイレクトされます。つまり、以下のようなディレクトリ構成で：

```
|-- index.html
|-- user.html
|-- item.html
```

`https://example.com/user`にアクセスしようが、`https://example.com/item`にアクセスしようが,
実態は`https://example.com/`にアクセスがリダイレクトされます（ただしURLは`/user/`や`/item`がついた状態）。なので、以下のようなSPAを前提とした実装が必要になります。

- 完全なるルーティングの制御
  - ページロード時（初期表示時）、現在のパスを取得し対応するコンポーネントを表示する
  - 対応するコンポーネントが存在しないパスを表示時、404を表すページを表示する

完全なるルーティングの制御の実装はなかなか骨が折れます。Historyの状態をpush/popする度にコンポーネントの描画を切り替える実装が必要になってきます。VueやReactなどのSPA作れるフレームワークを使う時はセットとなるルーターのライブラリを使いましょう。勉強以外の目的で素のJavaScriptでSPAつくることなんかせず、おとなしくフレームワーク使うことをオススメします。
Windows Server を監視する その3

#[前回](https://qiita.com/kazumatsukazu/items/8022f21c564cc37308c0)までの話

3.アプリケーション監視
MT4アプリが落ちている
→**済**

4.サーバ監視
WindowsServerが落ちている
メモリまたはCPUが１００％になっている
→１００％になってからでは遅いので80%にする(普段は60%)。

5.ネットワーク監視
FX会社との疎通が取れるか
レイテンシが普段と比べて遅くなっていないか

6.セキュリティ監視
ログイン

今回は4.サーバ監視以降をしよう、というお話。

#4.サーバ監視

##WindowsServerが落ちている
[こちら](https://qiita.com/_MasUchida/items/b26a5ac82949693a889b)を参考にした。

StackdriverのUptimeCheckを使う。

TCPでUptimeCheckを使うにはファイアウォールの設定でportを開けておかないといけない。
しかし、不正アクセスをされるのは嫌だったので調べてみると、UptimeCheck元のip一覧が[公式](https://cloud.google.com/monitoring/uptime-checks/using-uptime-checks?hl=ja#monitoring_uptime_check_list_ips-console)からダウンロードできるとのこと。
ただし、変更の可能性あり。~~めんどくさい。~~

UptimeCheck元のリージョン絞って、適当なTCPのportを開放したファイアウォールに、絞ったリージョンのip入れました。
サブネットマスクは「/32」だよね？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485045/1ed73ee1-2741-f39a-305e-7a42d472e76a.png)

###リージョンは3つ選ばないといけないみたい
マジか。。。~~めんど~~
ぽちぽち追加しました。

コンソール上でやったけど、コマンドなら一括でバシッと設定できるのかしら。。。

###うまくいかない！
稼働時間チェックの編集画面でテストを押すと何回やってもずっとエラー。つらみ。

考えたのは2つ。
①指定したポートがだめ。
②設定がまだ足りない。

####①指定したポートがだめ。
ポートは888を指定していました。
事前知識でウェルノウンポートがあるのは知っていたので、そこら辺を避けて888にしたつもりでした。
ですが[調べてみると](https://www.infraexpert.com/study/tea5.htm)、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485045/fb9cd3ed-6d5c-5e9e-8191-8c1e7c4ba961.png)

>①ウェルノウンポート番号はサーバのアプリケーションに割り当てられます。②登録済みポート番号は独自に作成されたアプリケーションに割り当てられます。③のダイナミックポート番号はサーバとのプロセスに応じクライアントのアプリケーションに動的に割り当てられます。②はクライアントに割り当てる時もあります。

**888はダメなんじゃない？**
という結論に至りました。

また、WindowsServer側で`netstat -a`コマンドを打ち、LISTEN状態のポートを調べ、
そのポートに設定を変えました。

####②設定がまだ足りない。
さらに、[こちら](https://symfoware.blog.fc2.com/blog-entry-1925.html)を参考に
WindowsServer側で対象ポートをこじ開けました。

###さて、結果は。。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485045/dce98613-8930-8105-c761-de218ee9dd22.png)
**どんなもんじゃい！**

でもこれだと結局①、②のどちらがよろしくなかったか切り分けできてないんですよね。
しかも再起動とかでLISTENじゃなくなったら、とかの検証もしてない。

##メモリまたはCPUが１００％になっている
[ここら辺](https://qiita.com/mitonattou919/items/a36612cad1840efa1362)見たら行ける！はず！(もう疲れた)

次回で終わり！(にしたい)
ヘッダーぽいものを作る


````html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>SiteName</title>
    <link rel="stylesheet" href="stylesheet.css">
  </head>
  <body>
    <div class="header">
      <div class="header-logo">SiteName</div>
      <ul>
        <li>何を勉強すべきか</li>
        <li>HTML何もわからん人へ</li>
        <li>CSSも何もわからん人へ</li>
      </ul>
    </div>
  </body>
</html>
````

````css
@charset "UTF-8";

.header {
  width: 100%;
  height: 90px;
  background-color: #00FF00;
  color: #fff;
}

.header-logo {
 font-size: 36px;
 float: left;
 padding: 20px 40px;
}

.header li{
 float: left;
 padding: 33px 20px;
 list-style: none;
}
````

###できたもの
![スクリーンショット 2020-09-08 16.32.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197834/5fb6bca6-2158-33eb-4645-e9e1fa6e2416.png)

https://github.com/aki0207/header

こちらを参考にさせていただきました。
<a href=“https://prog-8.com/“>Progate</a>
No module named tkinterを解決する

<h2>背景</h2>
yoloを使用する際に、ラベル付けを行うBBox-Label-Toolを使用した際に（main.pyを実行すると）No module named _tkinterとエラー表示された件の解決を行った

<h2>環境</h2>
・mac OS Catalina 10.15.6
・python 2.7.16
・tcl-tk 8.6.10

<h2>手順</h2>
<h3>試行錯誤</h3>
調べたところpyenvでpythonをインストールし直すらしい
```brew install tcl-tk```は行った
しかし、No module named PIL等うまく行かない
どうやらpythonコマンドを実行するとデフォルトのpythonを使用してしまうらしい

```
#一致しない
$pyenv versions
  system
* 2.7.16 (set by /****/****/.pyenv/version)
  3.7.3

$python --version
python 3.7.3
```

※今回は、pyenvのpythonのバージョンはデフォルトのpythonのバージョンと同じものを使用した

<h2>解決策</h2>
pyenvのパスを優先させる
以下を実行した

```
$ vim /etc/paths
/usr/local/bin
/usr/bin
/bin
/usr/local/sbin
/usr/sbin
/sbin
```
しかし、うまく行かない

<h3>ベストアンサー</h3>
以下を行う

```
pyenv init
source ~/.bash_profile
```
または

```
eval "$(pyenv init -)"
```
　　
　　

以上



追記）
・ターミナルを閉じるとまた、初期状態に戻ってしまうようです。
.~/.bashrcに下記記載すれば起動のたびに読み込まれます。

```
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
```
・BBox-Label-Toolは使用できるようになりますが、対話モードでimport tkinterを行ってもエラーが生じるようです。
Mac + GoogleDriveFileStreamで容量が不足した時はKeynoteの自動セーブファイルも要確認

GoogleDriveFileStream (GDFS)はクラウドに保存しているファイル群をあたかも外付けストレージの様に使える、Gsuite契約者が使用できるアプリである。最大の利点は、ローカルにコピーを保存していないファイルであってもFinder上で確認・編集が出来ることから、ローカルストレージ容量の節約と操作性を両立できる点だと個人的には感じている。

しかしながら、実際に使っているとキャッシュが溜まってローカルの容量を圧迫するので、定期的にチェックする必要があるようだ。その時のチェック内容を以下に記す。

環境
Mac OS 14.6
Keynote version 9.2

#### (1) アカウント接続を解除してGDFSのキャッシュを削除する
GDFSのキャッシュは、
`~/Library/Application Support/Google/DriveFS`
に蓄積されるが、再起動などの操作では解放されない。
私のMacには400 GBほど溜まっていてた。

<b>削除方法：</b>ファイルの変更がアップロード中でないことを確認し、
<b>メニューバーにあるGDFSのアイコン→設定→アカウント接続を解除</b>
で一度キャッシュを削除して、再度接続すればOK
ファイルのアップロード中にこの操作を行ってしまうと更新内容が消える可能性が高いので注意する。

#### (2) Keynoteの自動セーブファイルを削除する
`~/Library/Containers/com.apple.iWork.Keynote/Data/Library/Autosave Information`
の中身をゴミ箱に入れる。私の場合は100GBほど溜まっていた。

#### (3) 雑記
Keynoteの自動セーブファイルが肥大化した原因は不明だが、おそらくGDFSとkeynoteのファイルバージョン管理の相性の問題ではないかと考えている。
これまでGoogle Drive上にあるKeynoteファイルを編集する際、保存に非常に時間がかかり、動作が不安定になる時があると常々感じていた。`⌘+S`をついつい押す度に１０秒以上も待たされることがあったが、Autosaveファイルが毎回裏で作成されていたのであれば辻褄が合う。Dropboxなど他のサービスではこの現象に見舞われたことがないので、MacでGsuiteを使う際のデメリットということになる。

Keynoteファイルに限らず、ファイル編集の際は一度ローカルに落として作業する方が良いかもしれない。使用感が自然過ぎてGDFSの仕様を忘れてしまいがちになので気をつけたい。
JavaScript if文の書き方

初投稿兼投稿の練習になります。プログラミングもまだまだ初心者ですので、内容も恐らく初歩的な内容になります。暖かく見守って頂けると幸いです。

#if文の書き方

```
if(条件式) {
  条件式がtrueの時に実行する処理
} else {
  条件式がfalseの時に実行する時の処理
}
```

上記の書き方をすることで、条件式が成立するか否かで処理を分けることができます。

例えば

```
if(window.confirm('確認できましたか？')) {
  console.log('確認済です');
} else {
  console.log('まだ確認できていません');
}
```

　window.confirmは確認ダイアログボックスを表示します。確認ダイアログボックスにはOKボタンとキャンセルボタンがあり、OKをクリックするとtrue、キャンセルをクリックするとfalseの値が返ってきます。
　なので、OKをクリックすると条件式がtrueとなり、`console.log('確認済です')`が実行され、キャンセルをクリックすると条件式がfalseとなり、`console.log('まだ確認できていません')`が実行されます。

ちなみに

```
if(true) {
  console.log('確認済です');
} else {
  console.log('まだ確認できていません');
}
```

とすると、初めから条件式がtrueとなっているので、処理は分岐せず、true時の処理を実行することになります。条件式をfalseとすると同様に、false時の処理が実行されます。

以上です。ありがとうございました。
[Python] 受け取った関数がユーザーが定義した関数であることを確認する

Pythonでライブラリを作っている時に、「与えられた関数は本当にユーザーが実装した関数か?」をチェックしたい時に使えるTipsです。

# まず関数(callable)かどうか判定

これは言うまでもないですね。

```py
import inspect
inspect.isfunction(func)
```

# ビルトイン関数、frozen関数かどうかを判定

Pythonでは、C言語で記述されたビルトイン関数、またPythonで記述された標準ライブラリのうち、バイトコードの形でPython処理系に組み込まれたfrozen関数が使えます。たとえば`builtins.sorted()`はビルトイン関数、`zipimport.zipimporter()`はfrozen関数です。

## `sys.modules`を用いる方法

これは比較的わかりやすいと思うのですが、`sys.modules`から`func`が定義されたモジュールオブジェクトを探します。これに`__file__`という属性がなければビルトイン関数またはfrozen関数です。(ビルトインモジュール及びfrozenモジュール以外はPythonでは必ずファイルと1対1に対応します)

```py
modname = func.__module__
mod = sys.modules[modname]
fname = getattr(mod, '__file__', None)
return fname != None
```

## `code`オブジェクトを用いる方法

他の方法として以下のような方法があります。こちらの方が簡潔だと思います。

```py
co = getattr(func, '__code__', None)
return co != None
```

# ユーザーが作成した関数かを判定

いくつか方法はあると思いますが、ここでは関数の定義されたファイルのパスを取得し、それが`__main__`モジュールのパス(STDINならワーキングディレクトリ)以下に位置していれば、既存のライブラリではなくユーザーが作成したファイルであると判定します。
なお、この判定はワーキングディレクトリ以下にライブラリのキャッシュを置くパッケージマネージャ(`pyflow`など)では機能しないかもしれません。
また、`os.chdir`等を使ってワーキングディレクトリを変更しつつ`import`を行っている場合も機能しないかもしれません。(そんなプログラムあるのか知りませんが)

```py
filename = path.abspath(co.co_filename)
return filename.startswith(path.join(get_maindir(), ''))

def get_maindir():
    mm = sys.modules['__main__']
    fname = getattr(mm, '__file__', None)
    if fname == None:
        # STDIN
        return os.getcwd()
    else:
        return path.dirname(path.abspath(mm.__file__))
```

# 全ソースコード
```py
import sys
import os
import inspect
from os import path
def is_userfunc_b(func):
    if not inspect.isfunction(func):
        return False
    modname = func.__module__
    mod = sys.modules[modname]
    fname = getattr(mod, '__file__', None)
    if fname == None:
        return false
    fname = path.abspath(fname)
    return fname.startswith(path.join(get_maindir(), ''))
    
def is_userfunc(func):
    if not inspect.isfunction(func):
        return False
    co = getattr(func, '__code__', None)
    if co == None:
        return False
    # Check that the file is placed under main module
    filename = path.abspath(co.co_filename)
    return filename.startswith(path.join(get_maindir(), ''))

def get_maindir():
    mm = sys.modules['__main__']
    fname = getattr(mm, '__file__', None)
    if fname == None:
        # STDIN
        return os.getcwd()
    else:
        return path.dirname(path.abspath(mm.__file__))
```
TypeError:mul():argument 'other' (position 1) must be Tensor,not listエラーの解決法

## 以下のプログラムを実行した際に次のようなエラーが出た。
``` :実行文
seqlen = torch.tensor(10)
mask = [[1] * seqlen]
```
``` :エラー文
TypeError:mul():argument 'other' (position 1) must be Tensor,not list
```

# 原因
Pytorchのバージョン由来のエラー
torch>0.3.1からtorch.tensorとリストの演算が不可能になっているらしい

# 解決法
1. pytorchのバージョンを`torch<=0.3.1`に下げる
2. 次のようにプログラムを修正する

```:変更前
mask = [[1] * seqlen]
```
```:変更後
mask = [[1] * int(seqlen)]
```
LinuxやMacのシェルを切り替える方法


## まずは今のシェルを確認

現時点のシェルを確認するコマンド

```shell
% echo $SHELL

/bin/bash
```
## 続いて、現時点でどのシェルがインストールされているか確認

```shell
% cat /etc/shells
/bin/bash
/bin/csh
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
```

## 早速変更

下記コマンドを入力してください

```shell
chsh
```
※パスワード求められるので入力してください。

切り替えたいシェルを`echo $SHELL`で出したシェルから選んで、
設定ファイルのShell: ***の部分を書き換えます。（例：zshに切り替えたいなら`/bin/zsh`に）

```shell
# Changing user information for ***.
# Use "passwd" to change the password.
##
# Open Directory: /Local/Default
##
Shell: /bin/zsh ← ココです。
Full Name: ***
Office Location:
Office Phone:
Home Phone:
```

シェルを再起動します。

```shell
exec $SHELL
```

現在のシェルを確認し、変更されていることを確認できれば完了です。

```shell
echo $SHELL
```

## 参考記事
https://castleobj.com/shell-change/