OmniAICreator/Qiita-1.07M huggingface dataset:
Unixタイムスタンプを日時に変換するGAS

備忘録的に記載

```javascript:unixtsToDatetime.gs
// unix日時情報の変換
function unixtsToDatetime(ts) {
  var dt = new Date(ts*1000);
  var YYYY = dt.getFullYear();
  var MM = dt.getMonth()+1;
  var DD = dt.getDate();
  var hh = dt.getHours();
  var mm = dt.getMinutes();
  var ss = dt.getSeconds();
  return YYYY + '/' + MM + '/' + DD + ' ' + hh + ':' + mm + ':' + ss;
}
```
SQL学習要点(随時更新予定)

☑️SQLではキーワードの大文字と小文字を区別しない
ex) SELECTとselectは同じ

※テーブルに格納された文字列は大文字・小文字が区別される

☑️コメントの記述方法
・１行の場合：- - の後に記述
・複数行の場合：/* と */の間に記述

☑️「ここまでがクエリです」ということをデータベースに伝えるためのセミコロン（；）を加える

☑️SQLは大文字と小文字を区別しないため、小文字で記述しても問題ない。

☑️特定のデータを取得するためには、「どこの」という意味を持つ「WHERE」を用いる。「WHERE」が意味するのは、「どこのレコード（横の列）を取得するか」になる。

☑️SQLでは句の記述する順番が決まっている。勝手に変えるとエラーになる。
ex) WHERE句はFROM句の直後に記述する。

☑️ex) 「WHERE category = “交通費” 
※「交通費」のようなテキストはクォーテーションで囲む必要がある。
※「数値データ」はクォーテーションで囲んではいけないので注意する。
※「日付データ」はダブルクォーテーションまたはシングルクォーテーションで囲む必要があるため、忘れないようにする。

☑️データベースに保存されているデータには、「データ型」と呼ばれるルールがある。「データ型」とは、テキストデータや数値データ、さらには日付データといったように「データの種類」を示すものである。データベースでは、カラムごとにデータ型を決める。
HTMLのリンクのいろいろ

# プログラミングの勉強日記
2020年7月3日　Progate Lv.148
ポートフォリオ作成中
HTMLのリンクについて

#画像にリンクを張る方法と新規タブでリンクを開く方法

##画像リンクの作成
　画像リンクは`<img>`タグを`<a>`タグで囲むことで作成できる。

```html
<a href="リンク先"><img src="画像パス"></a>
```

##リンク先を新規タブに設定する方法
　`<a>`タグに`target="_blank"`属性を付けることでできる。

```html
<a href="ここにURL" target="_blank"></a>
```

#CSSでリンクのデザイン変更

##リンクの下線を消す
　CSSで何も指定しない場合、下の写真のようにリンクのテキストには下線が表示される。これを消したい場合、`text-decoration: none`を指定する。

<img width="949" alt="0703.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/ecf10ab0-b104-6bf2-f723-9cc091d482eb.png">

```css
a {
  text-decoration: none;
}
```

<img width="953" alt="0701.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/4ef93efd-6044-0ac0-d09b-f7419bb78196.png">


##リンクの色変更
　リンクの色を変更する場合は、文字の色を変更するときと同じように、colorプロパティを指定する。

```css
a {
  color: skyblue; /* 水色にする */
}
```

##カーソルを合わせたときのデザイン変更
　　セレクタを`a:hover`と書くことで、マウスカーソルをリンクの上にのせたときのデザインを指定することができる。

```css
/* カーソルをのせたとき */
a:hover {
  color: skyblue;
  font-size: 2em;/*文字サイズ2倍*/
  font-weight: bold;
}
```

##訪問済みのリンクデザインの変更
　カーソルを合わせたときのデザインの変更のように、セレクタを`a:visited`と書く。

```css
/* 訪問済みのリンク */
a:visited {
  color: skyblue;
  font-size: 2em;/*文字サイズ2倍*/
  font-weight: bold;
}
```
Windowsのコマンドラインで、PDFファイルをプリンタ印刷する

手元にあるPDFファイルを、ダイアログを触らずに直接プリンタで印刷する方法のメモ。

# 検索してヒットする方法
AcroRd32.exe /t オプションを使う方法が紹介されているけれど、今のAcrobat Reader DCではうまくいかない・・・

http://pdf-file.nnn2.com/?p=222


# PDFtoPrinter: Command-line PDF printing
そういったソフトを使えば上手くいった。

以下から PDFtoPrinter.exe をダウンロード。

https://github.com/svishnevsky/PDFtoPrinter/tree/master/PDFtoPrinter/build

ローカルプリンターも、LAN接続プリンタでもOK.
```
D:\> PDFtoPrinter.exe filename.pdf "Name of Printer"
```

Priner名は、Acrobat Readerの印刷ダイアログで出てくるプリンタ名をそのまま記入しよう。

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666068/b3b88e28-1f48-f197-fb88-9d65a94128f7.png)


たとえば
```
D:\ "PDFtoPrinter.exe"  C:\home\data\output.pdf  "\\\\Curios\TSC DA200"
```

## Powershellで、プリンタ名一覧を取得するには
こんなコマンドがあるよ。「Name」の値を記入すればOK。

```
PS C:\> get-WmiObject -class Win32_printer

Location      :
Name          : TSC DA200
PrinterState  : 0
PrinterStatus : 3
ShareName     : 
SystemName    : LAYRA


Location      :
Name          : Canon LBP312i
PrinterState  : 0
PrinterStatus : 3
ShareName     :
SystemName    : LAYRA

PS C:\>
```

## PDFtoPrinterコマンドの注意点
### 印刷サイズ
印刷オプションは必ず「実際のサイズで印刷（等倍）」になります。

ページにフィットさせる必要がある場合などは、exeファイルと同じフォルダに「PDF-XChange Viewer Settings.dat」があると、それを設定オプションとして読み込んでからプリントする仕様であるため、設定ファイルをこさえる必要がある。

PDF-XChange Viewerは、ここからダウンロードできる。
* https://forest.watch.impress.co.jp/library/software/pdfxchange/

### 引数ファイルの指定方法
指定するPDFの相対パスは、「**PDFtoPrinter.exeのバイナリを置いたディレクトリ**」が基準になります。別の場所にpdf を置いている場合、絶対パスで指定するのが無難。

たとえばバッチファイルにて、カレントディレクトリにある hoge.pdf を印刷したいなら以下となる。（%~dp0で参照）

```lpr.bat
@echo off
"PDFtoPrinter.exe"  %~dp0hoge.pdf  "Canon LBP312i"
```


# おしまい
Nanopi R2Sで、VisualStudioCode (Code-OSS)を動かす。

### はじめに
「ディスプレイのないNanoPiでも、VisualStudioCodeをがしたい！！」　
というわけで作ってみました。

### 準備
rdp接続できるようにセットアップする。

### インストール
```apt-get install code-oss/stretch```
うまくいかない場合は、次の方法で。
```
cd ~
wget https://packagecloud.io/install/repositories/headmelted/codebuilds/script.deb.sh 
./script.deb.sh
wget --content-disposition https://packagecloud.io/headmelted/codebuilds/packages/debian/stretch/code-oss_1.45.0-1586135971_arm64.deb/download.deb
dpkg -i code-oss_1.45.0-1586135971_arm64.deb
```

### ユーザ作成
root権限のないユーザを作成する


### GUIへログイン
rdp接続し、作成したユーザでログイン

### Visual Studio Codeの起動
ランチャーメニュー⇒Programming⇒Code-OSS

### 日本語化
Extentionで「Japanese Language Pack」を導入

以上
HTTP > HTTPSへのリダイレクト設定後にNGINXがリダイレクトを繰り返す問題への対応

以下に別法を加えてもう少し詳しく書きました
[HTTP -> HTTPSのリダイレクトはELBで行う方がスマートかもしれない　(Nginxでリダイレクトを行う方法あり) - Qiita](https://qiita.com/naokit-dev/items/c62bdf1d1656c4dba091)


SSL設定の過程で
HTTP > HTTPSへのリダイレクトをNGINXの設定ファイルに記述した後
ブラウザでアクセス時にリダイレクトを繰り返す問題に対する対応をメモ



問題：ブラウザでアクセスすると”リダイレクトが繰り返し行われました。”のエラー

- ブラウザを変えても変化なし

- SSL導入前は正常に動作

- NGINXの.confファイルを編集後に遭遇

  

環境

- AWSにデプロイされたRailsアプリ
- AWSでロードバランサー導入、SSL証明を取得



解決

設定ファイルを`/etc/nginx/conf.d/xxxx.conf`

はじめ以下のうように記載したものを

```
server {
    listen 80;
    return 301 https://$host$request_uri;
```

次のように書き換えた

```
server {
    listen 80;
    if ( $http_x_forwarded_proto != 'https' ) {
      return 301 https://$host$request_uri;
    }
```
【Ubuntu】DockerでRuby on Railsの環境構築中にPermissionErrorが起きる

#背景
https://docs.docker.com/compose/rails/

Ubuntu上から上記に従ってすすめると以下のコマンド実行時にでエラーが出る
```$ docker-compose run web rails new . --force --no-deps --database=postgresql```

【エラー内容】
```PermissionError: [Errno 13] Permission denied: '***/myapp/tmp/db'```

#原因
```rails new```実行時に作成される**myapp/tmp/db**の所有者が***root***になっているためコマンドが正常に動作しない模様  

#解決策
myappディレクトリ直下で以下を実行し/tmp/dbの所有者をログイン中のユーザーへ変更
```sudo chown -R $USER:$USER .```


###参考
https://forums.docker.com/t/permissionerror-errno-13-permission-denied-home-fred-docker-tmp-db/81168/2
Black Hole で Mac の内部音源を録音する

https://github.com/ExistentialAudio/BlackHole

Mac で普通に録音すると、マイクで拾った外部の音しか録音出来ません。Black Hole を使うと Mac が鳴らしている音を録音出来ます。

## インストールと設定

    brew cask install blackhole

* Spotlight から Audio Midi Setup を起動すると Audio Devices 画面が開く。
    * 開かない場合はメニューの Window > Show Audio Devices。
* + を押して Create Multi-Output Device を選択
* チェックボックスを全部解除
* Build-in Output と BlackHole 16ch の順に選択
    * 順序を間違えると音がスピーカから鳴らなくなる。
* Build-in Output と BlackHole 16ch の Drift Correction を選択
* 作った Multi-Output Device を選択して右クリック > "Use This Device For Sound Output"

## 録音

* Spotlight から QuickTime Player を開く
* File > New Audio Recording
* 録音ボタンの右の v でメニューを開く
* Black Hole 16ch を選択

## 元に戻す

* Audio Midi Setup の Audio Devices 画面から
* Build-in Output を右クリック > "Use This Device For Sound Output"

## 参考

* [BlackHoleでMac上で再生される音声を録音する](https://dev.classmethod.jp/articles/record-sounds-on-mac-with-blackhohle/)
* [Multi Output Device](https://github.com/ExistentialAudio/BlackHole/wiki/Multi-Output-Device)
    * 設定のしかた
* [最新のmacOSに対応し、SoundFlowerのように仮想オーディオ入出力を作成できるオープンソースのユーティリティ「BlackHole」がリリース。](https://applech2.com/archives/20191125-blackhole-for-mac-virtual-audio-driver-soundflower-alternative-app.html)
Object Pascalを6行でセグフォらせる

[pythonを三行でセグフォらせる](https://qiita.com/autotaker1984/items/a8ba955acdc81c907b3d)
[pythonを2行でセグフォらせる](https://qiita.com/sh1ma/items/a6dd1bcca0d9725e7e67)
[pythonを1行でセグフォらせる](https://qiita.com/MysteriousMonkey/items/0e389ccdc12988dd4263)
[C言語で16文字でセグフォらせる](https://qiita.com/yasuo-ozu/items/ddc5d3e8e4a97eaa470c)
[Pythonを33文字でセグフォらせる](https://qiita.com/kanimum/items/95a45d8be31ef75d4332)
[Rustを5行でセグフォらせる](https://qiita.com/YoshiTheChinchilla/items/b9f4a6e92266e8ec9d3d)
[C 言語で 5 文字でセグフォらせる](https://qiita.com/zk_phi/items/bd59111e677e6d0e5720)
[6行でJavaをセグフォらせる](https://qiita.com/gazeuse1442/items/3ab17cf72ade90090981)

を見て、たまたまそこにDelphiがあったので適当に書いたが
[Delphi で最少のソースコードを書いてみる](https://qiita.com/ht_deko/items/c81a8bacd7e299c45340)を見て反省して書き直し。


```Project.dpr
program Project1;
uses Classes, Forms; {$R *.res}
var list: TStringList;
begin Application.Initialize; list.Delete(-1); Application.Run;
end.
```

これでいいみたい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/35b1d279-bcbc-5235-8fd2-4f324bb12c76.png)



## 以下初回作
```Unit1.pas
procedure TForm1.FormCreate(Sender: TObject);
var
 data:array[0..0] of string; i:integer;
begin
  for i:=0 to 1 do begin showmessage(data[i]); end;
end;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/bdb7a58c-c140-7db3-fefa-baff05f21926.png)

[Delphi 言語 / Object Pascal について](https://qiita.com/pik/items/c34ca15bffc8f09127e6)
【Java】クラスの継承とは？

#クラスの継承とは
継承とは、親クラス(スーパークラス)を基に子クラス(サブクラス)を作成することで共通処理を引き継ぎながらも、子クラス独自の処理を記述するための機能のことです。継承を使えるようになると、何度も同じようなプログラムを書く必要がなく、作業の効率化、ソースコード全体を見やすくさせることができます。
#Javaクラスの継承方法
継承する場合にはクラス宣言のあとに「extends」を付け継承元とする親クラス名を指定します。ただし、Javaの継承元とするクラスは１つだけです。2つのクラスを同時に継承することはできないようになっています（多重継承の禁止）。

```
class クラス名 extends 元となるクラス名 {
  親クラスとの「差分」メンバ
}
```
継承したクラスのメソッドやコンストラクタを使用する場合には、「super」を使用してアクセス・参照します。

```
class クラス名 extends 元となるクラス名(引数) {
  // 親クラスのコンストラクタの呼び出し
  super(引数);
  // 親インスタンス部分のメソッドを呼び出す
  super.メソッド名(引数);
}
```
#メソッドのオーバーライド
オーバーライドとは親クラスで定義したメソッドの内容を上書きすることです。親クラスで定義されているメソッドの中身を、少し変えて使いたい場合に使用されます。
オーバーライドの条件は、メソッド名、戻り値、引数が同じであることです。

```
  【親クラス】
    public void output() {
      System.out.println("継承");
    }
  【子クラス】
    public void output() {
      System.out.println("オーバーライド");
    }
  
```
親クラス(スーパークラス)を再利用しつつも、変えたいメソッドは自由に変えられるので、便利なオーバーライドですが、使用する上で守らなければならない決まり事がいくつかあります。まず、親クラス(スーパークラス)側のメソッドにfinal修飾子が付与されている場合は、子クラス(サブクラス)でそのメソッドのオーバーライドはできません。また、スーパークラス内のprivate修飾子の付いた変数やメソッドはサブクラスから利用できないことにも気を付ける必要があります。
#オーバーロードとの違い
オーバーライドと似たような用語でオーバーロードがあります。よく間違われるので、簡単に説明しておきます。
オーバーロードとはクラス内に「同じ名称のメソッド」を複数宣言することです。
オーバーロードの条件は、➀メソッド名が同じである事　➁引数の型や数、並び順が異なることです。

```
  public void output() {}
  public void output(String str) {}
  public void output(String str, int i) {}
  public void output(int i, String str) {}
```
#まとめ
クラスの継承を使うことで、子クラスでは親クラスのメンバ変数やメンバメソッドを改めて記述する必要がなくなります。そうすることで、コードも読みやすくなり後々の修正やメンテナンスがしやすくなります。
#PowerApps アプリのインポート方法

2020/07/04 開催されます、[Power Platform Day Summer '20](https://power-platform.connpass.com/event/178495/)  における、当方登壇資料で紹介している「Measure In MR」（MR で測定）の解析・学習用アプリの初心者向けインポート方法です。

# インポート対象の入手
GitHub で公開しています。下記URLよりダウンロードしてください。

https://github.com/Yamad365/PowerApps/tree/master/MeasureInMRSample
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/74cbdfc7-2313-fca3-756f-0cc193fa0421.png)

# アプリ デモ動画
YouTube で公開してみました。下記からご覧いただけます。

[「Measure In MR」（MR で測定）の解析・学習用アプリ](https://youtu.be/lgohr9GPLOg)

# インポート手順
1. [make.powerapps.com](https://make.powerapps.com) 画面を起動し「インポート」をクリックします
    ![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/714e46f7-5eea-2052-d053-40c433526056.png)

2. 「アップロード」ボタンをクリックします
    ![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/58e56378-6a9a-d09b-4793-0843dbd62a25.png)

3. ダウンロードした Zip ファイルを選択します
    ![図3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/4604ea83-bf64-b021-04b3-af9f0af8cd71.png)

4. アップロードが完了すると画面が切り替わるので「インポート」ボタンをクリックします。
    ![図4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/3c12d6eb-1c1b-c530-d5bb-f269ced8b213.png)
すでに同名のアプリが存在する場合、上図の”Check”を『更新』にすれば上書きができます。

5. インポートが完了するまでしばらく待ちます
    ![図5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/657bdd09-1c0a-524e-45ce-03bba367410e.png)

6. インポートが完了すると画面上部の表示が切り替わります。「アプリを開く」をクリックします。
    ![図6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/96124ae8-2b2d-7c6a-3615-9d0f8deb3aaf.png)

7. インポートされたアプリが確認できます
    ![図7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/da358f51-b8f2-509e-51ad-1d2a68cc69ac.png)

8. ※注意※ 念のため、プレビュー機能が ON になっているか？は事前に確認してください
    ![図8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/c0d02bb6-d93e-4d68-02e2-90c31af15c2c.png)

# Power Apps ＋ MR系 参考URL
今回インポートしているのは「MRで測定」機能になります。「3Dで表示」や「MRで表示」など、その他 MR 系機能についても幾つか記事があります。ご参考になれば幸いです。

- [#PowerApps の Mixed Reality（MR）機能を試してみた！](https://qiita.com/yamad365/items/48d021bca0c99418ea80)
- [#PowerApps 3Dで表示(View in 3D) #01](https://qiita.com/yamad365/items/61a327bbd52c133e9233)
- [#PowerApps 3Dで表示(View in 3D) #02 Source指定方法](https://qiita.com/yamad365/items/b4ca0d8a7877de183efe)
- [#PowerApps 3Dで表示(View in 3D) #03 ODfB+Excel](https://qiita.com/yamad365/items/2621b4f122b0bfa286a4)
- [#PowerApps View in MR 外部から変更できない？](https://qiita.com/yamad365/items/a06339b346f72f7e1395)
- [#PowerApps MR のサイズを指定する](https://qiita.com/yamad365/items/f0e4788f6cedc77ee5d5)


MR 機能、GAされる日が楽しみですね！
それでは、皆さま。素晴らしい Power Platform Life を！
Javascriptで電卓アプリを作ってみた

こんにちは、Mottyです。
今回はJavascriptを使ってみました。

##概要
今回はJavascriptの処女作で電卓アプリを作ってみました。
定番ですが、HTML・JavascriptによるWebアプリ作品です。

##ソースコード

```Calculator.html

<!DOCTYPE html>
<html lang = "en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content = "width = device-width, instial-sale = 1.0">
   <meta http-equiv= "X-UA-Compatible" content = "ie=edge">
   <title> Document</title>
   <link rel = "stylesheet" href="Design.css">
    
</head>
<body>
    <script src = "System.js"></script>
    <input id ="result" type = "text" size ="20" style = "width:208px"/>
<br/>
    <input type = "button" value = "7" onClick ="disp(7)"/> 
    <input type = "button" value = "8" onClick ="disp(8)"/> 
    <input type = "button" value = "9" onClick ="disp(9)"/> 
    <input type = "button" value = "/" onClick ="disp('/')"/>
<br/>
    <input type = "button" value = "4" onClick ="disp(4)"/>
    <input type = "button" value = "5" onClick ="disp(5)"/>
    <input type = "button" value = "6" onClick ="disp(6)"/>
    <input type = "button" value = "*" onClick ="disp('*')"/>
<br/>
    <input type = "button" value = "1" onClick ="disp(1)"/>
    <input type = "button" value = "2" onClick ="disp(2)"/>
    <input type = "button" value = "3" onClick ="disp(3)"/>
    <input type = "button" value = "-" onClick ="disp('-')"/>
<br>
    <input type = "button" value = "0" onClick ="disp(0)"/>
    <input type = "button" value = "C" onClick ="clear()"/>
    <input type = "button" value = "=" onClick ="enter()"/>
    <input type = "button" value = "+" onClick ="disp('+')"/>
</body>
</html>

```

```Design.css

input{
    width:50px;
    height:50px;
}
textbox{
    width:200px;
    height:50px;
}
```

```System.js

var EnterFlag = false;

function disp(n){
    var obj = document.getElementById("result");
    obj.value += n;
}

function enter(){
    var obj = document.getElementById("result");
    obj.value = eval(obj.value);
    EnterFlag = true;
}

function clear(){
    var obj = document.getElementById("result");
    obj.value == "0";
}

```

##結果

しっかり表示してくれました。
![ 2020-07-03 22.37.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302420/5dcae6d5-9f32-63fb-eefd-c95765d8856d.png)
パーツとメソッドの繋ぎ方がポイントということを分かっていれば
プログラミング言語が変わっても物自体はちゃんと作れそう。
（しかし配列とかクラスを使えばもっと綺麗なコードをかけたのでは・・・。）
初心者によるプログラミング学習ログ 359日目

#100日チャレンジの359日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
359日目は、

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">昨日の作業・やったこと⇩<br><br>●読書　kindle 20分<br>●ブログ記事1記事作成<br>●プログラミング学習359日目 2h<br>・メンターの課題<a href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E3%81%A4%E3%81%AA%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#駆け出しエンジニアとつながりたい</a><a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</a><a href="https://twitter.com/hashtag/%E6%97%A9%E8%B5%B7%E3%81%8D%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash&amp;ref_src=twsrc%5Etfw">#早起きチャレンジ</a></p>&mdash; ぱぺまぺ@社畜✕投資✕ブロガー (@ppmp65) <a href="https://twitter.com/ppmp65/status/1278785590603866112?ref_src=twsrc%5Etfw">July 2, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
メッセージ送信の非同期化

# フォームが送信されたら、イベントが発火するようにしよう
<img width="536" alt="スクリーンショット 2020-07-03 22.12.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663122/2ebf9493-5bea-a096-28ce-e1eec7a575a4.png">
この記述の解説をします。
$(*****)には、formのクラス名を記述します。
.on(*****,にはイベント名を記述します。
e.preventDefaulでは、非同期通信を行う為にデフォルトのイベントを止めています。
##イベントが発火したときにAjaxを使用して、messages#createが動くようしましょう
<img width="520" alt="スクリーンショット 2020-07-03 22.17.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663122/31442d72-7443-7f06-543c-55a057d5ebb0.png">
この記述の中のthisは、イベントの発火元であるFormの情報が入っています。
 $(this).attr('action');は、Form情報のパスを取得しています。
# messagesコントローラーの#createアクションでメッセージを保存し、respond_toを使用してJSON形式のリクエストに対してのレスポンスを返せるようにしましょう

<img width="498" alt="スクリーンショット 2020-07-03 22.21.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663122/f2c3d5c8-1b01-bc33-6ac9-d3442b79c392.png">
if @message.save
リクエストで送られてきた情報を保存している
respond_to do |format|
        format.json
json方式で返している
## その他アウトプット
<img width="376" alt="スクリーンショット 2020-07-03 22.25.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663122/a7daee69-d21a-e7ec-3b54-8852db29a3cd.png">
クラス名MessageFieldにappend(html)でHTMLを追加している
## $(".submit-btn").prop('disabled', false);
送信ボタンを一度押すとリロードしないと押せなくなるが
prop('disabled', false);を送信ボタンクラスに記述する事によりロードせずに投稿ができる様になる
## 非同期に失敗した場合の処理
<img width="407" alt="スクリーンショット 2020-07-03 22.31.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663122/57ec4196-c18e-6548-07ba-538cf267fb4f.png">
失敗した場合エラーをアラートで知らせてくれます。
Doneの後に使います
sinatraでRakeを使ってデータベース作成

環境
macOS catalina 10.15.5
ruby 2.6.0

sinatraを使っての作業でrailsと違う方法でdbを作ったので備忘録

```ruby:Gemfile

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem 'sinatra'
gem 'sinatra-contrib'

#ここからデータベース作成の為のgem
gem "sinatra-activerecord"
gem "sqlite3"
gem "rake"
```
次にインストール

```app:ターミナル

$ bundle install
#（事前に↓でパスは通しておく）
$ bundle config set path 'vendor/bundle'
```
次にインストールしたActiveRecord を読み込む
指定のデータベースと接続するようにする

```ruby:myapp.rb

require "bundler/setup"
require 'sinatra'
require 'sinatra/reloader'

#ここから
require "sinatra/activerecord"
set :database, {adapter: "sqlite3", database: "sample_app.sqlite3"}
#ここまで

get '/' do
  erb :home
end

get '/hoge' do
  erb :hogedayo
end
```

次に Rakefile というファイルをつくる。

```ruby:Rakefile

require "sinatra/activerecord/rake"

namespace :db do
  task :load_config do
    #ここでset :database した myapp.rb を require して該当のデータベースを特定することができる 
    require "./myapp.rb" 
  end
end
```

ターミナルでマイグレーションファイルを作る

```app:ターミナル

$ bundle exec rake db:create_migration NAME=create_movies
```
下記のように編集

```ruby:マイグレーションファイル
class CreateMovies < ActiveRecord::Migration[6.0]
  def change
    create_table :moveis do |t|
      t.string :name
    end
  end
end
```

ターミナルでdb:migrate

```app:ターミナル
$ bundle exec rake db:migrate
== 20200703150957 CreateMovies: migrating =====================================
-- create_table(:moveis)
   -> 0.0009s
== 20200703150957 CreateMovies: migrated (0.0010s) ============================

```
確認

```
$ sqlite3 sample_app.sqlite3
SQLite version 3.28.0 2019-04-15 14:49:49
Enter ".help" for usage hints.
sqlite> .table
ar_internal_metadata  moveis                schema_migrations
```

完成！
Googleフォームからカレンダー招待（備忘録）

# 背景・目的

- 社内勉強会などでよく参加申し込みフォームを作成するため備忘録的に
- Googleフォームの回答結果が入るSSでカレンダー招待するスクリプトを作成
- 事後のアンケートを送信したりするので、SSにアドレスが残っていると楽なため


# 手順

- フォーム作成
    - 送信者アドレスを取得する設定にしておくこと
- フォームにSSに関連付け
    - フォームの回答をスプレッドシートに出力する設定を行う
- SSのスクリプトエディタでコード編集
    - SSにて「App Script」を起動しコードを貼り付ける
    - ※デフォルトで記載してある「function myFunction(){}」を上書きしましょう
    - 必要箇所を修正する
    - 初回実行時は認証処理必要
- トリガー作成
    - フォーム送信時のトリガーを作成
        - イベントのソース：スプレッドシートから
        - イベントの種類：フォーム送信時

# スクリプト

```javascript:entry.gs

// シート情報:要変更
// https://docs.google.com/spreadsheets/d/AAAAA/ の 「AAAAA」部分がシートID
var SS_ID = "シートID"; // GoogleスプレッドシートのURLから
var SH_NAME = "フォームの回答 1";　// フォーム送信結果が入るシートの名前

// カレンダー情報:登録するカレンダー情報に変更が必要
var EVENT_DATE = '2020/01/01';// 開催日
var EVENT_TITLE = "カレンダー予定名";　// カレンダータイトル

function addGuest() {
  var sh = SpreadsheetApp.openById(SS_ID).getSheetByName(SH_NAME);
  var r = sh.getLastRow(); 
  var c = sh.getLastColumn();
  
  //カレンダー情報
  var date = new Date(EVENT_DATE);
  var options = {
    search: EVENT_TITLE
  }
  var events = CalendarApp.getEventsForDay(date, options);
  var id = events[0].getId();
  var event = CalendarApp.getEventById(id);
  
  // アドレス取得
  var target = sh.getRange(r, 2); // 1列目は送信日時、2列目が送信者アドレス
  var address = target.getValues();
  
  // カレンダー追加
  event.addGuest(address[0][0]);
}

```
SAS/RでSQL エピソードⅠ : Group By処理

# SASやRでもSQL構文を使える!
SASならSQLプロシジャ、RならsqldfというパッケージにてSQLの構文が使えるしdbConnectでデータベースにアクセスしてSQL操作も可能

つまり、データの入出力さえググれば、あとはSQL使ってSASだろうがRだろうがデータのハンドリングや要約統計量を求めることが可能
もちろん、グラフ描くとかpdfできれいに出すとかってなるといろいろ知ってないと難しいが…
pythonもsqlite3とかpandasqlあるから、SQL知ってるといろんな言語でもデータのハンドリングできちゃう
pythonでSQL:https://qiita.com/saspy/items/2b5aeef91e87cac503e2
※微妙にSQLの構文違ったりするけどね...

とりあえず、sashelpのCLASS(sasデータセット)を使って試す
<img width="322" alt="class.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564185/09d6e629-20c2-5c7f-21aa-bb746531ee19.png">

AGEごとにレコード数をカウントする例

# SAS SQLプロシジャ

```sas
proc Sql;
  create table work.CLASS_STAT as
    select AGE , count(*) as N
    from sashelp.CLASS
    group by AGE;
quit;
``` 

<img width="167" alt="stat.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564185/0b8b8baf-61e4-0a48-728f-da0c4eb19b31.png">

# R sqldf

```r
#準備(使うパッケージ群)
library(sqldf)
library(sas7bdat)

#読み込み(SASならlibnameで楽できるのだが...)
Sas_Pass <- "sashelp.classを置いたフォルダパス(ファイル名まで含める)"
SASHELP_CLASS <- read.sas7bdat( file = Sas_Pass )

#sqldf
CLASS_STAT <- fn$sqldf(
 " select AGE , count(*) as N
   from SASHELP_CLASS
   group by AGE
 " )

# SASのSQLプロシジャだとmeanやavgで平均出せるが、基本的にはSQLはavgで平均
```

<img width="167" alt="cccc.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564185/c3b3e3e6-6839-acaf-8b93-e7baee3b2e2e.png">


# R RSQlite

```r
#準備(使うパッケージ群)
library(sqldf)
library(sas7bdat)

#読み込み(SASならlibnameで楽できるのだが...)
Sas_Pass <- "sashelp.classを置いたフォルダパス(ファイル名まで含める)"
SASHELP_CLASS <- read.sas7bdat( file = Sas_Pass )

# データベースに接続
conn = dbConnect( RSQLite::SQLite() , "" , synchronous = "off" )
# ""を"パス/db名"にするとdbを読み込む(dbがない場合は新規に作成)

#データベースに格納
dbWriteTable( conn , "SASHELP_CLASS_SQL" , SASHELP_CLASS , overwrite = TRUE )

query <- " select AGE , count(*) as N
from SASHELP_CLASS_SQL
group by AGE"

CLASS_STAT <- dbGetQuery( conn , query )

#データベースを閉じる
dbDisconnect(conn)
```

#条件分岐
case when ...
でif文のような感じで条件分岐して変数作れる
つまり、SASのif文やRのifelse知らなくてもハンドリングできたりする
もちろん、知ってた方がいいし複雑なロジック組むのにSQLだと書きにくいこともある
dataステップの方が個人的には好き

SASとRでの比較もしていく予定
ScrollReveal.jsでええ感じのパララックス効果を実装する

#スクロールすると画像がふわって出てくる感じのを実装する
簡単にパララックス効果を実装できる便利ライブラリをcdnで以下のようにheadタグに記述
`<script src="https://unpkg.com/scrollreveal"></script>`


次にhtmlを編集。marginはスクロールするスペースを与えるため

```index.html
    <div class="animation" style="margin-top: 1000px;">
        <img src="./images/image1.jpg">
    </div>
```
次にjs

```app.js
$(function () {
    ScrollReveal().reveal('.animation', {
        delay: 500,
        duration: 2000,
    });
});
```

おしまい。
vagrantで立てたVM（CentOS 7）のportを追加で開く

## 紹介する内容
- `semanage`でportを開けるように設定可能です
- 開けるportに対して`nc`でlistenさせてずっと開けます


## 結論
- どこで活用できるか悩ましいです
- vagrantのCentOS 7はsemanageを使えばport開けます
- vagrantの設定でportを開ける設定は見つかりませんでした
   - forwarded_portはできます
   - https://www.vagrantup.com/docs/networking 周りを読みました


## 紹介始めます
### Vagrantfile(port開く側)
```
# -*- mode: ruby -*-
# vi: set ft=ruby :

$script = <<-'SCRIPT'
yum -y update
yum -y install net-tools
yum -y install policycoreutils-python
yum -y install nc
SCRIPT

Vagrant.configure("2") do |config|
  config.vm.box = "centos/7"
  config.vm.synced_folder '.', '/vagrant', disabled: true
  config.vm.provider "virtualbox" do |v|
    v.customize ["modifyvm", :id, "--nictype1", "virtio"]
    v.name = "centos7_a"
    v.memory = "1024"
    v.cpus = 2
  end

  config.vm.network :forwarded_port, host: 2258, guest: 22
  config.vm.network "private_network", ip: "192.168.33.17"

  # Run scripts for all VMs  
  config.vm.provision "shell", inline: $script
end
```

### portスキャンする側とport開く側の説明
- 続くイメージも`上`が`portスキャンする側`、`下`が`port開く側`になります
- port開く側のipが192.168.33.17になります
- 試すportは55556にします
![ips.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247584/99e40f4f-3d88-3cb1-97c4-a6ec42b9b6ee.png)


### semanageでportを開ける設定する前
#### portスキャンする側
- nmapでportをスキャンします。見当たりません。
   - `nmap -p 55556 192.168.33.17`

#### port開く側
- netstatでlisten中のportを確認します。listenリストにもport`55556`は見当たりません
   - `sudo netstat -ntlp`
![noAction.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247584/38463deb-24df-5aee-7faa-ec9f16d52546.png)


### semanageでportを開けれるように設定
#### portスキャンする側
- nmapでportをスキャンします。まだ見当たりません。
   - `nmap -p 55556 192.168.33.17`

#### port開く側
- `sudo semanage port -a -t http_port_t -p tcp 55556`でportを開けれるようになります
   - `sudo semanage port -l | grep http_port_t` で確認できます
- netstatでlisten中のportを確認します。listenリストで、port`55556`まだ見当たりません
   - `sudo netstat -ntlp`
![justOpen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247584/c377b71c-8990-cb63-7ca2-8012bf377527.png)


### ncで開放可能なportに対してlistenさせるとportがスキャンされる
#### portスキャンする側
- nmapでportをスキャンで見えます（`state`が`open`になりました）
   - `nmap -p 55556 192.168.33.17`

#### port開く側
- `sudo nc --listen --source-port 55556 -4`で選んだport`55556`をIPv4でlisten状態にしたから、nmapのportスキャンに見られます
![setListen.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247584/3879ba9c-c927-3e27-92b2-c318e033d545.gif)
ssh（公開鍵認証）の基礎知識

公開鍵とか秘密鍵とか色々ややこしいじゃないですか、
sshログイン使ってるけどちゃんと理解できていなかったので備忘録です。


#sshログインって

公開鍵認証方式を使って
**「鍵を持っている人(パソコン)からのみ、一般ユーザーによるログインを許可する。」**
という方式。

・・・え、どゆこと？
難しく考えなくて大丈夫、簡単です。

公開鍵認証方式でログインするには鍵が2つ必要になるんですね。
それが、
①パソコン側に置く*秘密鍵ファイル*と、
②サーバー側に置く*公開鍵ファイル*です。

秘密鍵ファイルは人に知られてはいけないですよ、秘密なのでね。
公開鍵ファイルは、人に知られても良い(公開できる)ファイルです。

この2つのファイルが揃って初めて公開鍵認証によるログインが可能になるんですね。
公開鍵認証では、sshのログイン時に使ったパスワードの代わりに「パスフレーズ」ってものを使用します。
パスフレーズはサーバーへログインするパスワードと似たようなもので、自分が決めた文字列を設定できます。
これはサーバーへログインするためのものではなく、秘密鍵にアクセスするための秘密の文字列だそうです。


要は鍵を持っていないPCからは簡単にログインできないということ！
これだけ理解できてればとりあえずOK。


#sshの認証方式
SSHの主要な認証方式としてはパスワード認証方式と公開鍵認証方式がある。

**パスワード認証方式**
パスワード認証方式はデフォルトの認証方式で、ユーザー名とパスワードでログインする方式。
ユーザー名とパスワードは接続先OSのユーザーアカウントの情報が使用される。
**公開鍵認証方式**
公開鍵認証方式は公開鍵と秘密鍵の２つの鍵(キーペア)を使用した接続方式。
サーバーに公開鍵、クライアントに秘密鍵を置いて使用する。
公開鍵認証を使うとパスワード入力なしでログインする事が可能になる。
パスワード認証方式はサーバー側で明示的に無効にしていない限り使用できるが、セキュリティ的には脆弱なので無効にしている事も多い。


##つまりは・・・
公開鍵認証を使うことによって
秘密鍵を持っているパソコンからの接続のみ許可し、鍵を持っていないパソコンからはログイン出来ないのでセキュリティが向上するってことですね。セキュリティ対策なんですね。
一方で、
・鍵を作成したり管理する手間がかかる。
・パソコンの故障や紛失などで秘密鍵を紛失したら、再び鍵を作りなおさないといけない。
・どこからでも接続できない。
といったデメリットもある。。。


公開鍵認証はセキュリティを向上させるための仕組みだということでした！



参考文献
[よく分かる公開鍵認証」～初心者でもよくわかる！VPSによるWebサーバー運用講座(2)](https://knowledge.sakura.ad.jp/3543/)
はじめまして🌷

はじめまして
独学でプログラミングやWebマーケティングの勉強を三週間ほど前からはじめた２０代の女です。


最近、架空のカフェのwebページを作りました。


まだまだ完成ではありませんが、これからもっと勉強して、よりいいホームページとなるように頑張っていきたいと思っています。

https://hinatabokko-niki.github.io/hinatabokko.github.io/
↑
これが最近やっと作りあげたホームページです

まだまだ知識と技術が未熟で、書き方などが汚いと思いますが、アドバイスなどがあったら、ぜひ教えてください:relieved:

これから勉強した記録として、学んだことを投稿していこうと思います。
よろしくお願いします☺︎
ゼロから始めるLeetCode Day75 「15. 3Sum」

# 概要

海外ではエンジニアの面接においてコーディングテストというものが行われるらしく、多くの場合、特定の関数やクラスをお題に沿って実装するという物がメインである。

どうやら多くのエンジニアはその対策としてLeetCodeなるサイトで対策を行うようだ。

早い話が本場でも行われているようなコーディングテストに耐えうるようなアルゴリズム力を鍛えるサイトであり、海外のテックカンパニーでのキャリアを積みたい方にとっては避けては通れない道である。

と、仰々しく書いてみましたが、私は今のところそういった面接を受ける予定はありません。

ただ、ITエンジニアとして人並みのアルゴリズム力くらいは持っておいた方がいいだろうということで不定期に問題を解いてその時に考えたやり方をメモ的に書いていこうかと思います。

[Leetcode](https://leetcode.com/)

Python3で解いています。

[ゼロから始めるLeetCode 目次](https://qiita.com/KueharX/items/6ee2502c3b620c795b70)

前回
[ゼロから始めるLeetCode Day74 「12. Integer to Roman」](https://qiita.com/KueharX/items/4be10ce7f2bd98a79849)

今はTop 100 Liked QuestionsのMediumを優先的に解いています。
Easyは全て解いたので気になる方は目次の方へどうぞ。

[Twitter](https://twitter.com/kueharx)やってます。

**[技術ブログ](https://kueharx.blogspot.com/)始めました！！**
技術はLeetCode、Django、Nuxt、あたりについて書くと思います。**こちらの方が更新は早いので**、よければブクマよろしくお願いいたします！

# 問題
[15. 3Sum](https://leetcode.com/problems/3sum/)
難易度はMedium。

問題としては、n個の整数の配列`nums`があるとすると、`nums`に`a + b + c = 0`となる要素`a, b, c`があるかどうかを確認するアルゴリズムを設計し、0の和を与える配列の中のすべてのユニークな三重項を求めよ。

>Example:

>Given array nums = [-1, 0, 1, 2, -1, -4],

>A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

# 解法

3つ選び、0になる組み合わせを選べ、というものです。
組み合わせの鉄則とも言えるかもしれませんが、先に固定するものを決めることが良いと思います。

今回は以下のように僕は書きました。

```python
class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        ans = []
        for i in range(len(nums)-2):
            if i > 0 and nums[i] == nums[i-1]:
                continue
            left = i+1
            right = len(nums)-1
            
            while left < right:
                sums = nums[i]+nums[left]+nums[right]
                if sums < 0:
                    left += 1
                elif sums > 0:
                    right -= 1
                else:
                    ans.append([nums[i],nums[left],nums[right]])
                    while left < right and nums[left]==nums[left+1]:
                        left += 1
                    while left > right and nums[right]==nums[right-1]:
                        right -= 1
                    left += 1
                    right -= 1  
        return ans
# Runtime: 1092 ms, faster than 45.79% of Python3 online submissions for 3Sum.
# Memory Usage: 17.1 MB, less than 76.15% of Python3 online submissions for 3Sum.
```

まず最初にソートすることによって昇順に並べ替えます。
こうすることで前から要素をfor文で回していった時に要素の大小の指定がしやすくなります。

具体的な例を上げるならば、これを
`[-1,0,1,2,-1,-4]`
ソートすると、
`[-4,-1,-1,0,1,2]`
という風になります。

これの要素を最初から舐めていくときに、どういう風に3sumのうちの残りの二つの要素をどうやって選択していくべきかがこの問題の核と言えるでしょう。

コードで書いたように、僕は`i+1`を`left`,`len(nums)-1`を`right`とし、仮にそれらを足した時にそれらの合計値である`sums`が0より小さければleftの要素を+1、0より大きければrightを-1することで解決しました。
これは上でも述べたソートをしているからできることです。

実際には
`-4+(-1)+2=-3<0`
なので、leftの要素を動かして、
`-4+(-1)+2=-3<0`
これでも一緒なのでまたleftの要素を動かして
`-4+0+2=-2<0`
といった風なフローとなっています。

そして仮にそれら以外、すなわちsums==0となった場合は用意していた`ans`に要素を追加する、というものです。

こういった和の組み合わせ系は今回のような形式で解くのが楽な気がするので典型的な問題としてしっかり覚えておきたいですね。

では今回はここまで。お疲れ様でした。
Oculus関する購入方法

今回はOculusの購入方法ですね。
機材だけではなく、Gameの購入方法も紹介します。
# 機材の購入
## ホームページからの購入
まず、勿論ホームページからの購入は一番安全性が高いですね。
[Oculusホームページ](https://www.oculus.com/)

ホームページから購入したい機種を選択しクリックすれば、紹介ページへ飛びます。
右上の購入ボタンを押せば、購入ページへ飛びます。
購入ページでは、
機材本体だけではなく、色んな製品を購入できます、自分の好み（必要）に合わせて購入できます。

ホームページで購入の場合はですが、いくつの注意点があります。
![picturemessage_4r4ftop5.i0m.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541380/3d3346da-e24b-4192-d81a-ebfd7bca7fa3.png)
画像を見ればわかると思いますが、配送の国が選択できます。

購入時名前や住所などの情報なんですが、ローマ字で入力した方が安全と思います。
(現時点では「ローマ字表記」の説明はないですが、1年前はすべてローマ字じゃないといけませんでした。)
ひらがなや漢字で入力すると、トラブルが発生する可能性があるため、ローマ字を推奨します。

あとは、支払い方法を入れて、情報をチェックすれば、普通に購入できます。
## Amazonからの購入
[購入できる場所](https://www.oculus.com/quest/where-to-buy/?locale=ja_JP)
のリストを見ればわかりますが、Amazonからの購入も可能です。

[ホームページから提供リンク](https://www.amazon.co.jp/s?k=Oculus&ref=bl_dp_s_web_4145334051)
ホームページから提供したリンクなので、安全性は保証されていると思います。

（値段はホームページと結構差がありますし、変わったりしますので、
具体的な差は説明しませんが、購入時対比したほうがいいですね。）
## 値段
**以下の値段は全部（2020/07/03）ホームページから参考したものです。**

「Oculus Rift S」¥49800

「Oculus GO」現在販売終了しましたので購入出来ませんが、Amazonでは ¥41000+あたりです。

「Oculus Quest」
64GB　¥49800
128GB　¥62800

# Gameの購入
「Oculus Rift S」対応のゲームなんですが、[Oculus Home](https://www.oculus.com/experiences/rift/)からの購入は可能です。

「Oculus GO」と「Oculus Quest」ゲームの購入何ですが、[Oculus](https://apps.apple.com/jp/app/oculus/id1366478176)のアプリを使う必要があります。
手元の機材と連携して、支配方法なのを設置し、普通に購入すればいいです。

![picturemessage_fs121m0x.wic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541380/9bff8964-02f0-b870-8d21-88b96f9f87aa.png)
（アプリを見る時、選択肢に「Oculus Rift S」がありました、アプリ使って購入可能らしいですね。
一応「Oculus Rift S」使った事ないので、ここでは説明しません。）

では…
ubuntu で sudo  をつけるとデフォルトのpython 呼ばれる。

## 概要

#### 備忘録

`pyenv`などを使ってpythonの仮想環境に入っていたとしても、

`sudo python` 
とするとデフォルトの`/usr/lib`とかの下にある`python`が呼ばれるので注意。

あれ、なんかいつも使ってる仮想環境でできてることが`sudo`つけるとできない、
みたいなことになる。


以上備忘録。

終わり。
MacでOpenMVGを動かす


MacでOpenMVGを動かします。
今回は、標準でインストールされるチュートリアルの実行と結果の表示まで行います。

## 実行環境
macOS Mojave（バージョン10.14.5）
pyenv+python 3.7.5
cmake 3.16.4
Xcode 11.3.1
## 手順
### OpenMVGのインストール

必要なpythonライブラリをインストール

```
$ pip install sphinx
```

Githubからソースコードをクローン

```
$ git clone --recursive https://github.com/openMVG/openMVG.git
```


openMVG/src/CMakeLists.txtを編集
編集前：

```
# ==============================================================================
# IMAGE IO detection
# ==============================================================================
find_package(JPEG QUIET)
find_package(PNG QUIET)
find_package(TIFF QUIET)
```

編集後:
(set〜を追加)

```
# ==============================================================================
# IMAGE IO detection
# ==============================================================================
set(CMAKE_FIND_FRAMEWORK LAST)
find_package(JPEG QUIET)
find_package(PNG QUIET)
find_package(TIFF QUIET)
```

Xcodeを利用してビルドを実施

```
$ mkdir openMVG_Build
$ cd openMVG_Build
$ cmake -DCMAKE_BUILD_TYPE=RELEASE -G "Xcode" . ../openMVG/src/
$ xcodebuild -configuration Release
```
### チュートリアルの実行

チュートリアルを実行

```
$ cd software/SfM
$ python3 tutorial_demo.py 
```
チュートリアルでは、下記のフォルダに格納された10枚の画像から3次元点群を生成します。
openMVG_Build/software/SfM/ImageDataset_SceauxCastle/images
![100_7102.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656719/a084c376-8f35-82ce-666f-c403c9976b4d.jpeg)

カメラの内部パラメータも格納されています

```
$ cat K.txt
2905.88 0 1416 
0 2905.88 1064
0 0 1
```

### MeshLabのインストール

MeshLabのサイトからmac版をダウンロードし、インストール
https://www.meshlab.net/

[File]>[Import Mesh.]から
openMVG_Build/src/software/SfM/tutorial_out/reconstruction_sequential/colorized.ply
を読み込む

下図のように表示されたら成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656719/4b26c315-3cab-1953-facf-d8c8e78e218f.png)
AWS Amplifyにstorybookを自動デプロイする


![ダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60923/b5f1506d-5e29-6162-add6-3a53aacc88a5.png)

Amplifyを使ってGatsyby.jsのホスティングとバックエンドの構築を最近やっていて、
sotrybookを使っていたので簡単にホスティングできる方法を探したところ、色々他サービスあるんですが、BASIC認証が有料だったりともあるのでAWS Amplifyでやってみた。


## 1. amplifyのアプリを作成
メインのアプリとは別にstorybook用のアプリを作成します。
※著者はすでに作ったあとなのでこのように２つのアプリに分けるようにします。

![スクリーンショット 2020-07-03 17.31.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60923/34ee855f-1535-52e5-e798-3603c014be6c.png)


## 2. リポジトリの選択

ポチポチ、リポジトリとブランチを選択します。
![スクリーンショット 2020-07-03 18.02.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60923/65324d3d-5b58-1c87-9b62-f13a34f2cbe6.png)


## 3. ビルドの設定
 
1. backendは不要なのでチェックを外しておきます（デフォルトだとチェックが入っている）
![スクリーンショット 2020-07-03 17.19.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60923/d5925936-29f0-e9e7-38fc-8ad9ad69e737.png)

2. ymlは初期時に自動で入っているので[Edit]します。
![スクリーンショット 2020-07-03 17.21.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60923/821409eb-230f-17f9-a2e7-ab72e4fada12.png)


3. :fire: `yarn run build` → `yarn run storybook:build` と変更して保存します。
※自プロダクトのpackage.jsonのscriptに設定されているscriptを実行するのでコマンド名が違う場合は適宜変更を。

![スクリーンショット 2020-07-03 17.40.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60923/f7d9f748-9c98-b50b-cc49-825ba66bd068.png)

![スクリーンショット 2020-07-03 17.22.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60923/e4eb86ec-8fdc-7910-65be-0411413fb304.png)

## 4. 公開

1. ビルドの書き換えができたら[次へ]を押下し、確認画面で、[保存してデプロイ]を押下してあとはビルドが終わるのを待つだけです。
![スクリーンショット 2020-07-03 17.23.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60923/2d7832d7-1f24-c719-72e5-b884f6b5b66a.png)
![スクリーンショット 2020-07-03 17.23.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60923/38859274-7022-a7cd-4f95-5749360b9476.png)


2. おお、公開された！:beers:
![スクリーンショット 2020-07-03 17.44.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60923/20b45cda-cbf4-3692-5e4b-c480ddce03b1.png)

## 5 BASIC認証

このままだとURLアクセスすると誰にでも見られてしまうので一応BASIC認証をかけておきます。
アプリの中に「アクセスコントロール」があるのでそこの[アクセス管理]から環境ごとにBASIC認証がかけられます。

![スクリーンショット 2020-07-03 17.48.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60923/69fa26af-b80d-e950-6ee1-208e9971a2ed.png)
![スクリーンショット 2020-07-03 17.49.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60923/23a7c3d0-a537-4e95-a9a2-98efb664a01f.png)


## まとめ
他にもいろいろホスティングサービスはあるけど、BASIC認証は有料だったり、描画が遅いとか、デプロイが面倒とかうまくいかなかったりしてとかあるから、AWS使っているならぜひampfliyはおすすめしたい。

静的ホスティングだけでも使えるし、バックエンドも構築できるのでフロントライクな環境が簡単に作れて好きです。
あとは指定したブランチ(master)にコード修正をマージしたらデプロイが自動で走るのでCIツールの設定も不要。

ここでは話していませんが、同じアプリ内で環境切り替えもできるので環境変数はもちろん、簡単に同環境を複製もできるのでサーバー建てる作業も必要ないのもとてもいいですね。
[HLF]のchaincodeインストール方法が"Fabric chaincode lifecycle"に変わった

# chaincodeのインストール方法が、V1.4から変化していたのでメモします。
V2.xから["Fabric chaincode lifecycle"](https://hyperledger-fabric.readthedocs.io/en/release-2.0/chaincode_lifecycle.html)という方法になっていました。
手順が増えているので備忘録として残します。
TLS:Enableだとコマンドラインがゴチャゴチャするので、TLS:Disabledとします。基本は変わらずTLS関連のオプションが増えるだけです。
Organization（Org1） ＋ Peer（Peer0）分だけ書いておきます。

# V1.4はどうだったか？

1. channelをcreateして
2. createしたchannelにjoinして
3. chaincodeをインストールして
4. chaincodeをinstantiate（同時にInitLedgerの呼び出し）します

この4ステップでした。
chaincodeのソースファイルは予め所定の場所へコピーしておきます（ソースがgolangの場合）。

```bash
peer channel create -o orderer-example-com:30050 -c mychannel -f ./channel.tx
peer channel join -b mychannel.block
peer chaincode install -n asset -v 1.0 -p github.com/asset
peer chaincode instantiate -o orderer-example-com:30050 -C mychannel -n asset -v 1.0 -c ...
```
シンプルです。

# "Fabric chaincode lifecycle"でどう変わったか
joinまでは同じですが、そこからかなり手順が増えています。fabric-sampleのシェルを追って書いているので、不要な処理が入っているかもしれません（チェックなど）。

1. channelをcreateして
2. createしたchannelにjoinして
3. channelをupdateして
4. [lifecycle] chaincodeを.tar.gzファイルへpackageして
5. [lifecycle] packageした.tar.gzファイルをinstallして
6. [lifecycle] chaincodeをpackage-idでapproveformyorg(?)して
7. [lifecycle] chaincodeをcommitできるかチェックして（checkcommitreadiness）
8. [lifecycle] chaincodeをcommitして
9. chaincodeをisInitオプションでInitLedgerをinvokeします

手順が倍以上に増えていました。

```bash
peer channel create -o orderer-example-com:30050 -c mychannel -f channel.tx --outputBlock mychannel.block
peer channel join -b mychannel.block
peer channel update -o orderer-example-com:30050 -c mychannel -f Org1MSPanchors.tx
peer lifecycle chaincode package asset.tar.gz --path ${CC_SRC_PATH} --lang ${CC_RUNTIME_LANGUAGE} --label asset_${VERSION}
peer lifecycle chaincode install asset.tar.gz
peer lifecycle chaincode approveformyorg -o orderer-example-com:30050 --channelID mychannel --name asset --version ${VERSION} --init-required --package-id ${PACKAGE_ID} --sequence ${SEQUENCE} --init-required
peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name asset --version ${VERSION} --sequence ${SEQUENCE} --output json --init-required
peer lifecycle chaincode commit -o orderer-example-com:30050 --channelID mychannel --name asset --peerAddresses peer0-org1-example-com:30151 --peerAddresses peer0-org2-example-com:30351 --version ${VERSION} --sequence ${SEQUENCE} --init-required
peer chaincode invoke -o orderer-example-com:30050 -C mychannel -n asset --peerAddresses peer0-org1-example-com:30151 --peerAddresses peer0-org2-example-com:30351 --isInit -c ...
```

ソースファイルは指示した場所に置いてあれば、package化して所定の場所へコピーしてくれます。

# さいごに
解読に疲れた…
【コピペOK】hoverしたら動き出すCSSボタンアニメーション５１選

[<img width="704" alt="スクリーンショット 2020-07-03 20.53.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643410/5a09d4e8-01a9-cc17-cea9-afdf7db7a7ea.png">](https://www.twinzlabo.com)

**コピペだけで作れるボタンアニメーションを５１個**を紹介いたします。

box-shadow, filter, transformなどをふんだんに使っており、transitionで滑らかな動きが表されています

コードには説明もわかりやすく書いてあるのでかなり参考になります

Webデザイン初心者の方はもちろんですが、バックエンドエンジニアの方にもとても助かる内容になっています


## CSSボタンアニメーション５１選

### １. transformを使いこなすボタンアニメーション１６選

transformを使ってボタンを変形し、WebサイトやWebアプリケーションで使えるボタンエフェクトとなっています

transformを全種類使っていてわかりやすく説明もされているのでかなり重宝します

[![css-effect-hover-button-transform-skew.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643410/b7e16364-df9f-95c5-3e85-2c3d28daffe2.png)
]


### ２. transitionを使いこなすボタンアニメーション9選

transitionを使ってボタンにアニメーションを効かせおり、WebサイトやWebアプリケーションで使えるボタンエフェクトとなっています

box-shadowやborder-radiusをエフェクトで使用して見た目のデザインもいい感じです

[![hover-button-animation-color.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643410/66cc0873-a5e5-187d-2c4e-7151c8dfa598.png)
]


### ３. transformを使いこなすマテリアルデザイン5選

transformを使ってボタンにアニメーションを効かせおり、WebサイトやWebアプリケーションでそのまま使えるマテリアルデザインとなっています

マテリアルデザインなのでそのまますぐにでもコピペして使用できます

[<img width="653" alt="css-effects-hover-button-materialdesign-3d.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643410/d6e4f726-d7a8-5029-5059-0e866481f65e.png">
]




### ４. filterが網羅できるCSSボタンアニメーション15選

filterを使ってボタンにエフェクトを効かせおり、特にデザインの見た目をカッコよくしたい場合に非常に使えます

filterエフェクトを全種類使っているので永久保存版としても重宝できそうなまとめ記事になっています

勉強にもフロント開発でも役立つと思います

[![hover-button-animation-filter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643410/c256f0a6-de10-0e95-4443-a8010f39bff6.png)]



### ５. scaleでオシャレなCSSボタンアニメーション3選

transform:scaleを使ってボタンにエフェクトを効かせおり、オシャレでかっこいいボタンになっています

ボタンの背景が滑らかにスライドしたり、フワッと出てきたりするのでみているだけで面白いです

[![css-animation-button-diagonal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643410/9b2d5bd2-f185-f8b6-1daa-4e5fd66fc8b1.png)
]




### ６. ボタンでつくる回転アニメーション9選

transitionを使ってボタンが自然に回転します

ボタンが回転するって純粋に興味ありませんか？

回転扉みたいに動くんです

[![hover-animation-button-explain3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643410/602b2e14-733b-fd07-142f-8be38c6d94f8.png)
]
Logitech G HUBが起動しない問題を解決

#Logitech G HUBが起動しない

Logicool(Logitech)のゲーミングマウスの設定ソフトのG HUBが起動しないでCPU使用率ばかり食っていたので困っていた。

ネットでは
 -再インストールしないといけない
 -Windowsのユーザ名に全角文字を使うとダメ

というのがあったが、どうにもうまくいかず、ようやく解決できたので、備忘として残しておく。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577966/0e732b0e-0cc3-662a-bb07-9b47eb1ba2d9.png)



#原因はファイアウォール
ファイアウォールソフトが lghub_agent.exe の通信を遮断していたためであった。
常時はブロードキャストアドレス(192.168.x.255)にアクセスしているようだったので、
そこは許可設定していたのだが、起動時にループバックアドレス(127.0.0.1)にもアクセス
していて、それがつながらないとハングアップしたような状態になってしまうのであった。
ループバックアドレスも許可すると、起動するようになった。

![無題2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577966/7a878a78-cafd-5bb0-5f1c-a8d973ecc353.png)

なお、なぜかインターネットにもアクセスしているのだが、それは遮断しても特に問題ないようだ。
何のアクセスをしているのか、非常に気になるところだが。

#最後に
ネットで調べると再インストールしないといけないというのと、ユーザ名に全角文字を使うとダメというのがあったが、どちらも当方は該当しなく、大変難儀した。
通信がつながらなければさっさと諦めて、設定ぐらいさせて欲しいものである。

#追記(Arx controlについて: 2021.4.20)
lghub_agentには[Arx Control](https://gaming.logicool.co.jp/ja-jp/partnerdeveloperlab/sdk-resource-list/arx-control-sdk.html)機能があり、特定のアドレスのUDPポート54915へ断続的(1回/秒くらい)にパケットを送信する。
パケットの量がすごいので、当該機能を使わない場合は無効化することをおすすめする。
![arx.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577966/67f6a58b-9274-325e-4565-82711ae0f32b.png)
Reactで<input type="date" />を使う時の無効な日付（2月31日とか）を表示させないやり方

## はじめに

Reactで`<input type="date" />`を使って、日付を選択するフォームを作った時に、`2月31日`とかの無効な日付も選択できてしまうのを防ぎたいと思ったので実装してみました。

inputタグだと味気ないので、material-uiのTextFieldコンポーネントを使ってますが、機能自体は同じです。

## 日付選択を作る

`date`で日付の状態を管理します。
`value`に`date`を受け渡して、`onChange`イベントを受け取って状態を更新する普通の処理です。

```js:App.js
export default function App() {
  const [date, setDate] = useState("");

  return (
    <div className="App">
      <FormControl variant="outlined">
        <TextField
          variant="outlined"
          type="date"
          value={date}
          onChange={e => onChangeDate(e}
        />
      </FormControl>
    </div>
  );
}
```

とりあえず`onChangeDate `はそのまま状態を更新してみる。

``````js:App.js
const onChangeDate = (e) => {
  setDate(e.target.value);
}
```

↑キーとかで選択すると、こんな風に無効な日付が選択できてしまうんですよね・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619552/4c5d59e3-3610-2067-0c98-2856ccfe1d9b.png)

## onChangeDateでいい感じに調整する

問題点としては

* 2月は閏年があるので、28or29日
* 4/6/9/11月は30日まで

なので、一個前の状態`date`を参照して、書き換えていきます。

無効な日付の時の`e.target.value`には値が入ってないので、値が入っている時はそのまま状態を更新します。

それ以外の場合は月ごとに分岐して書いていきます。

``````js:App.js
const onChangeDate = (e) => {

  if (e.target.value) {
    setDate(e.target.value);
  } else {
    const nowYear = date.slice(0, 4);
    const nowMonth = date.substr(5, 2);
    const nowDate = date.slice(-2);

    if (nowDate !== "01") {
      setDate(`${nowYear}-${nowMonth}-01`);
    }
    else{
      switch (nowMonth) {
        case "02":
          if ((nowYear * 1) % 4 === 0) {
            setDate(`${nowYear}-${nowMonth}-29`);
          } else {
            setDate(`${nowYear}-${nowMonth}-28`);
          }
          break;
        case "04":
        case "06":
        case "09":
        case "11":
          setDate(`${nowYear}-${nowMonth}-30`);
          break;
        default:
          break;
      }
    }
  }
}
```

これで無効な日付がとりあえず入らないようになりました！！

ただ、これだと`3/31`から月を2月に変更（↓矢印）すると、`3/1`に一回なってしまいます。

ちょっと気持ち悪いですね。。。

しかし、`e.target.value`に値が入ってこないのですし、年月日のどの値を変更したかもわからないため、
どうしようもなさげです。

世に出回っているカレンダーアプリとかの日付は、普通に2/31日とか選択できるようになっていて、保存できないようにしていたりするのでこれがベストプラクティスなのでしょうかね。


## まとめ

今回は日付選択の無効な日付を表示させないようにしてみました。

まだ気持ち悪いのでベストプラクティスをご存じの方はコメントをお願いします！！
セキュアブラウザ とは何者か？

秋冬のコロナ第二波に備えて用語の整理をしたい今日この頃。

#概要
- セキュアブラウザとか VDI をイメージしやすくなればいいな程度の記事です。

#ターゲット
- そもそもセキュアブラウザってなに？ という人
- なんとなくセキュアブラウザや VDI を使用している人
- 2つの違いはなんなの？ という人

#セキュアブラウザとは？
<img width="655" alt="スクリーンショット 2020-07-03 20.43.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635116/359e74b9-6458-7f8c-fbb7-bf6bec87be75.png">

- 不正アクセス（**フィルタリング機能**）や情報漏洩（**データ保存禁止機能**）の対策を施したブラウザです。
- 一般のブラウザと異なる点はドキュメントやデータをデバイス上の安全な領域で表示するところです。
- データは終了時に自動的に消去されます。

#セキュアブラウザと VDI の違いは？
- どちらも接続先のネットワークが必要なのは一緒です。
- VDI の場合、**社内ネットワークに繋がるデスクトップ環境用のサーバやパソコンが必要**になります。

※接続先のネットワークは主に社内ネットワークなどになります。

##そもそも VDI (デスクトップ仮想化) とは？
<img width="669" alt="スクリーンショット 2020-07-03 20.49.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635116/608ce6b8-beac-5e09-2e21-403234b650f4.png">

- パソコンのデスクトップ環境をサーバ上に集約してサーバ上で稼働させる仕組みのことです。
- サーバからデスクトップ環境の画像だけが送られており、それをパソコン上で表示しているだけです。
- そのため、デスクトップ環境からパソコン上へデータを持ってくることはできません。

※デスクトップ環境内でのデータ移動はできます。

#セキュアブラウザ系のサービス提供元
以下はほんの一例です。

##CACHATTO : e-Janネットワークス（株）
- 閲覧機能、MDM（モバイル端末管理）機能、認証機能がバランスよく整っています。
- 会社支給の PC などにアプリをインストールし、社内ネットワークに接続して使用します。

https://www.cachatto.jp/

##HDE Secure Browser : （株）HENNGE
- office365、G Suiteなどのクラウドに対応したブラウザアプリです。
- HDE Secure Browserがインストールされているデバイスのみ、クラウドへのアクセスを許可する仕組みです。
- 会社支給の PC だけでなく、個人端末にもアプリをインストールすることで、社内ネットワークに接続することもできます。

https://www.hennge.com/jp/service/browser/

##Magic Connect : NTTテクノクロス（株）
- オフィスのデスクトップ画面を手元端末に呼び出して操作できるサービスです。
- VDI っぽいけど、サーバ上のデスクトップ環境ではなく、会社にあるパソコンに繋ぐ点が異なります。
- 社内でパソコンをつけっぱなしにしておくだけなので、VDI を用意するよりも環境構築が簡単です。

https://www.magicconnect.net/

##スマートコネクト : （株）TOKAIコミュニケーションズ
- 社外のモバイル端末からオフィス内の会社支給の PC をインターネット経由で遠隔操作できるリモートアクセスサービスです。
- 既に VDI 環境が用意されていれば、そちらを接続先にすることもできます。
http://www.oneoffice.jp/service/smartconnect/

#まとめ
- **セキュアブラウザとはセキュリティ機能に特化したブラウザ**
- **VDI はデスクトップ環境を提供するサーバ、システム**
- **環境の用意やサービス毎の違いはあれ、社内ネットワークにセキュアに接続するという点では共通**

#最後に
セキュアブラウザにしろ VDI にしろ、セキュリティに特化したためデータの操作にはかなり制限がつきます。
ただ、メールの送信や資料の参照程度で事足りるのであれば、
わざわざ会社に行かなくてもよい、という非常に魅力的なメリットもあります。

今までは出先で社内情報を確認するなどの使い方が多かったかと思います。
今回のコロナによりテレワークが推進されたことで、よく目にする単語になりました。
しかし、100%在宅勤務の方には少し物足りないのでは？という印象です。

他のクラウドサービスなどと連携して、データ操作面をどうにかするのが今後の課題になるかと。
ffmpeg-python環境を構築して動画の分割を行う

### 概要
- python-ffmpegを利用して動画を分割する
- python-ffmpegを動かすまでの手順
- 備忘録

---
### 前提
- 環境
    - python: v.3.7.7
    - [python-ffmpeg](https://pypi.org/project/ffmpeg-python/): v.0.2.0
    - [ffmpeg](https://ffmpeg.org/): v.4.3

---
### ffpmegをインストールする
- ビルド済みのイメージを利用する
    - https://www.johnvansickle.com/ffmpeg/ からビルド済みファイルを利用すれば楽チン
    - ダウンロードしたファイルを解凍後、```/usr/local/bin```配下にコピーすればOK
        - ```ffprobe```をコピーしないと、```ffmpeg.probe```を実行した際に、
        ```[Errno 2] No such file or directory: 'ffprobe': 'ffprobe' ```とエラーが出るので注意

```shell
wget http://johnvansickle.com/ffmpeg/releases/ffmpeg-release-arm64-static.tar.xz
tar xvf ffmpeg-release-arm64-static.tar.xz
sudo cp ./ffmpeg-4.3-arm64-static/ffmpeg /usr/local/bin
sudo cp ./ffmpeg-4.3-arm64-static/ffprobe /usr/local/bin
```

---
### python-ffmpegをインストールする
- pip installするだけ

```
pip install ffmpeg-python
```

---
### 動画の切り出しコードを書く

```python
import ffmpeg
srcfile_path = 'hoge.mp4' # 動画の格納パス
split_num = 5 # 動画の分割数

# ffmpeg.probeを実施して、動画のメタデータを取得
video_info = ffmpeg.probe(srcfile_path)

# 動画の全長(秒)を取得
duration = float(video_info['streams'][0]['duration'])
stride = duration/split_num

# 動画をN個に分割
for i in range(split_num):
    start = int(i * stride)
    stream = ffmpeg.input(srcfile_path, ss=start, t=stride)

    # cオプションは、ffmpegの-vcodecと-acodecをまとめて指定
    # c="copy"指定することで、再変換する手間と時間を抑える
    stream = ffmpeg.output(stream, 'output_{}'.format(i), c="copy")
    ffmpeg.run(stream)

```

---
OpenCV使った方法もあるけど、動画の編集処理だけだったらffmpegは楽チンで便利〜