OmniAICreator/Qiita-1.07M huggingface dataset:
VMインスタンスのディスクを食い潰したので拡張した

ある日突然インスタンスが起動しなくなりました
GCPからの`パフォーマンス向上`警告を無視し続けたせいか？
スペックケチってDocker使っていたせいか？

#### 環境
OS：Ubuntu 18.04 LTS
ブートディスク：標準永続ディスク
ディスクサイズ：10GB（後に拡張）


以下，すべてrootで実行しています
とりあえず`df -h`コマンド

```
Filesystem      Size  Used Avail Use% Mounted on
udev            821M     0  821M   0% /dev
tmpfs           169M   18M  151M  11% /run
/dev/sda1       9.6G  9.6G     0 100% /
tmpfs           842M     0  842M   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
```

少ない容量を100%使っているのでゾーン永続ディスクのサイズを増やしてみる
以下を参考
https://amemo.hatenablog.jp/entry/2019/01/18/180000
https://cloud.google.com/compute/docs/disks/add-persistent-disk?hl=ja

ディスク容量までは増やせたが、growpartコマンドが実行できない！

```
No space left on device
FAILED: failed to make temp dir
```

`lsblk`コマンドでパーティションサイズの確認


```
sda       8:0    0    10G  0 disk
└─sda1    8:1    0   9.9G  0 part /
```
現パーティションのディスク容量がいっぱいすぎた

`parted`コマンドでパーティション割り当てを変更する

```
GNU Parted 3.2
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) p free
Warning: Not all of the space available to /dev/sda appears to be used, you can fix the GPT to use all of the space (an extra 41943040 blocks) or continue with
the current setting?
Fix/Ignore? Fix
Model: Google PersistentDisk (scsi)
Disk /dev/sda: 32.2GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system  Name  Flags
        17.4kB  1049kB  1031kB  Free Space
14      1049kB  5243kB  4194kB                     bios_grub
15      5243kB  116MB   111MB   fat32              boot, esp
 1      116MB   10.7GB  10.6GB  ext4
        10.7GB  32.2GB  21.5GB  Free Space

(parted) resizepart 1
Warning: Partition /dev/sda1 is being used. Are you sure you want to continue?
Yes/No? Yes
End?  [10.7GB]? 20GB
(parted) p free
Model: Google PersistentDisk (scsi)
Disk /dev/sda: 32.2GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system  Name  Flags
        17.4kB  1049kB  1031kB  Free Space
14      1049kB  5243kB  4194kB                     bios_grub
15      5243kB  116MB   111MB   fat32              boot, esp
 1      116MB   32.2GB  32.1GB  ext4
        32.2GB  32.2GB  12.2MB  Free Space
```

(parted) の箇所で`p free`で状況確認
`resizepart Number`で対象パーティションの設定ができる

おまじないが必要だそうです
https://qiita.com/ahpjop/items/383092ee689a35244ec8

```
resize2fs /dev/sda1
```

最後に`lsblk`や`df -h`コマンドで確認して終わり

元々ディスクサイズが10GBのスナップショットを元に、20GBでインスタンスを作ったとしてもパーティションがいい感じにならず…
解決できたのでめでたしめでたし
Laravel bladeからReactコンポーネント(Material UI)にバリデーションエラーメッセージを渡してみる

地味だけど、割といいなと思ったTips。

## blade側
`errors='@json($errors->toArray())'`がポイント。LaravelのValidationで返ってきた内容をjsonに変換している。
defaultValueは、エラー時に元の入力値を保持するために使用。

```html
@extends('layouts.app')

@section('content')
    <div id="header"></div>
    <form method="POST" action="{{ route('login') }}">
        @csrf

        <div id="login" errors='@json($errors->toArray())' defaultValue='@json(['email'=>old('email')])'></div>

    </form>
    <script src="{{mix('js/app.js')}}" ></script>
@endsection

```

## 受け取るReactコンポーネント

```react
import * as React from 'react';
import { render } from 'react-dom';
import PasswordField from '../atoms/PasswordField';
import EmailInputField from '../atoms/EmailInputField';
import SubmitButton from '../atoms/SubmitButton';
import { Grid } from '@material-ui/core';

type Props = {
    errors?: {
        email :string,
        password : string
    }
    defaultValue?: {
        email: string
    }
}

const Login: React.FC<Props> = ({ errors, defaultValue }) => (
    <div>
      // 中略
      <EmailInputField label="メールアドレス" errors={errors?.email} defaultValue={defaultValue?.email}/>
      <PasswordField label="パスワード" errors={errors?.password}/>
      <SubmitButton label="LOGIN"/>
      // 中略
    </div>
);

const Element = document.getElementById('login');
if(Element){
    const errors = Element.getAttribute('errors');
    const parsedErrors = errors && JSON.parse(errors);
    const defaultValue = Element.getAttribute('defaultValue');
    const parsedDefaultValue = defaultValue && JSON.parse(defaultValue);
    render(<Login errors={parsedErrors} defaultValue={parsedDefaultValue} />, 
            document.getElementById('login'));
}

```

### bladeから受け取ったjsonをparseしているのはこの処理
あとはコンポーネントに渡してあげるだけ。

```react
    const errors = Element.getAttribute('errors');
    const parsedErrors = errors && JSON.parse(errors);
```

## エラー描画をするコンポーネント
helperTextは`undefined`許容なので、判定なしで`errors`を設定可能。

```react
import React from 'react';
import TextField from '@material-ui/core/TextField';
import { InputAdornment } from '@material-ui/core';
import Mail from '@material-ui/icons/Mail';

type Props = {
  label: string;
  errors?: string;
  defaultValue?: string;
}

const EmailInputField: React.FC<Props> = ({ label , errors , defaultValue }) => (
  <div>
    <TextField id="email" name="email" label={label}
    error={(!!errors)?true:false}
    helperText={errors}
    defaultValue={defaultValue}
    />
  </div>
);

export default EmailInputField;
```
Dockerコンテナからインターネットに繋がらないときに確認すること

## 1. DNSの設定は適切ですか？
コンテナに入って

```bash
cat /etc/resolv.conf
```
をしてnameserverを適切に設定しましょう。わからなければ

````
nameserver 1.1.1.1
```
と設定しておきましょう。

## 2. iptablesにNAT設定は書き込まれていますか？
```bash
sudo iptables iptables -t nat -L
sudo systemctl restart docker.service
```

## 3. firewalldの設定はされていますか？
dockerの仮想ブリッジはdocker0とします

```bash
firewall-cmd --permanent --zone=trusted --change-interface=docker0
firewall-cmd --reload
systemctl restart docker
```
【bash】sshのパスワード認証のシェル

# sshとは
リモートホストへの接続に使用するプロトコルです。

# 証明書認証
```bash
ssh -i 証明書パス ユーザ名@IPアドレス
```
まず前提として、パスワード認証より証明書認証の方が楽で安全だと思われる。
理由は、パスワード入力を省略できる点と証明書の配布によりアクセス制限が容易にできる点からです。
[証明書認証について分かりやすい記事](https://qiita.com/onokatio/items/397a5899a0ec16c7e60a)

# パスワード認証

```bash
ssh ユーザ名@IPアドレス
```
パスワード認証はパスワードを打つのが面倒であり、打ち間違いの可能性もあるので、シェルでその辺をカバーしたいと考えました。それが以下のものです。

```bash
#!/bin/sh
echo パスワード | clip && ssh ユーザ名@IPアドレス
```
これであとは貼り付けキーで上手くいきます。

# 最後に
個人的には証明書でやるのがいいと思いますが、社内システムの環境だと色々なお約束があるのも事実です。
なので、そういう時はこういうパスワード認証用のシェルでもいいかなと思います。

# 余談
社内システムではよく踏み台サーバを経由するパターンやトンネルを指定するパターンがあります。
その時はsshの-L, -Dオプションあたりがオススメです。
java(多態性)

#多態性（ポリモーフィズム）
「インスタンスをあいまいに捉える」
継承によりis-aの関係が成立しているなら、インスタンスを親クラス型の変数に代入することができる

```java
SuperHero h = new SuperHero();
```
通常のSuperHeroインスタンス

```java
Character c = new SuperHero();
```
SuperHeroクラスの親クラスにCharacterを持っている前提



##あいまいな型の箱へのインスタンスの代入

```java
public class Main {
  public static void main(String[] args) {
    Wizard w = new Wizard();
    Character c = w;             // Character型の箱にいれる
    Matango m = new Matango();
    c.name = "魔法使い";
    c.attack(m);                 //呼び出せる
    c.fireball(m);               //エラーになる
  }
}
```
・箱の中身（Character c）がWizardであることを忘れてしまう
・attack()だけ呼び出せるのは、他のキャラクターはattackを持っているため
　（どのキャラクターもattack()を持っている前提）
・fireball()が呼び出せなったのは、他のキャラクターがfireball()を持っていないから（持っているとは限らない為）エラーになる
・`確実に言えることは、箱に入っているのはキャラクターの一種であることだけわかる`

###強制的にWizardを呼び出す方法（ダウンキャスト）
```java
Character c = new Wizard();
Wizard w = c;                   //エラーになる
```

プログラムを１行ずつ解釈、翻訳する為、２行目のcがWizardとは確定できない為。

```java
Character c = new Wizard();
Wizard w = (Wizard)c;           //強制的な型変換を指示する             
```



##メソッドを呼び出せた場合に動く処理

**Monster（親）クラスをSlime（子）クラスが継承してる**
Monster　  System.out.println("モンスターは逃げ出した。");
Slime　　　 System.out.println("スライムは逃げ出した。");

```java
public class Main {
  public static void main(String[] args) { 
    Slime s = new Slime();
    Monster m = new Slime();
    s.run();
    m.run();
  }
}
```

**実行結果**
スライムは逃げ出した　s.run()の結果
スライムは逃げ出した　m.run()の結果
実際の結果は中身の型(Slime())によって決まる、箱の型(Monster m)は`結果には関係ない`

###ダウンキャスト失敗（ClassCastException）

```java
Character c = new Wizard();
Hero h = (Hero)c;                        
```

コンパイルに成功するが、動作させるとエラー
「嘘の構図」になっている為

###安全にキャストできるか判断する（instanceof演算子）

```java
if(c instanceof Wizard) {  //もしcの中身がWizardと見なして大丈夫なら
Wizard w = (Wizard)c;      //Wizardと見なせ
w.fly();
}                       
```
ゼロから始めるLeetCode Day53 「1365. How Many Numbers Are Smaller Than the Current Number」

# 概要

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

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

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

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

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

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

Python3で解いています。

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

前回
[ゼロから始めるLeetCode Day52 「1351. Count Negative Numbers in a Sorted Matrix」](https://qiita.com/KueharX/items/05685ec9f94d8aa0f26c)

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

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


# 問題

[1365. How Many Numbers Are Smaller Than the Current Number](https://leetcode.com/problems/how-many-numbers-are-smaller-than-the-current-number/)

難易度はEasy。
良い問題だったので書きます。

問題としては、配列`nums`が与えられます。
それらの配列の中の各要素が他の要素より大きい回数を導くようなアルゴリズムを設計してください、という問題です。
日本語的に難しいので例を見てみましょう。

>Input: nums = [8,1,2,2,3]
Output: [4,0,1,1,3]
Explanation: 
For nums[0]=8 there exist four smaller numbers than it (1, 2, 2 and 3). 
For nums[1]=1 does not exist any smaller number than it.
For nums[2]=2 there exist one smaller number than it (1). 
For nums[3]=2 there exist one smaller number than it (1). 
For nums[4]=3 there exist three smaller numbers than it (1, 2 and 2).

>Input: nums = [6,5,4,8]
Output: [2,1,0,3]

>Input: nums = [7,7,7,7]
Output: [0,0,0,0]

# 解法

簡単な考え方としては、インデックスと紐付けて考えるというやり方があります。

`nums`をソートし、それをfor文の中で元々のインデックスで取り出し、配列に追加していってあげる、というものです。

例えば、例の`nums = [6,5,4,8]`であれば、
ソートした結果が`num = [4,5,6,8]`となります。
その要素をインデックスで考えれば自ずと見えてきます。
`num = [4,5,6,8]`はインデックスは`[0,1,2,3]`となります。
これを`nums`の順に置き換えると`[2,1,0,3]`となり、例と一致します。

この流れをPythonで書くとこんな感じになります。

```Python
class Solution:
    def smallerNumbersThanCurrent(self, nums: List[int]) -> List[int]:
        ans = []
        num = sorted(nums)
        for i in range(len(nums)):
            ans.append(num.index(nums[i]))
        return ans
# Runtime: 92 ms, faster than 55.84% of Python3 online submissions for How Many Numbers Are Smaller Than the Current Number.
# Memory Usage: 13.8 MB, less than 79.58% of Python3 online submissions for How Many Numbers Are Smaller Than the Current Number.
```


もっと簡潔に書くと以下のようにも書けます。

```Python
class Solution:
    def smallerNumbersThanCurrent(self, nums: List[int]) -> List[int]:
        sorted_nums = sorted(nums)
        return [sorted_nums.index(num) for num in nums]
# Runtime: 100 ms, faster than 54.35% of Python3 online submissions for How Many Numbers Are Smaller Than the Current Number.
# Memory Usage: 13.9 MB, less than 41.13% of Python3 online submissions for How Many Numbers Are Smaller Than the Current Number.
```

考え方的には数え上げるのもありますが、この考え方の方がスマートだと思いました。
愚直に考えるのではなく、少し頭を捻ればスマートに解ける良い問題ですね。

では今回はここまで。お疲れ様でした。
シェルとターミナルとコンソールについて

#ターミナルについて
「ターミナル」自体は終了という意味から、通信プロセスの末端側を指すように使われる
ソフトウェアでのターミナルはソフトウェアのバージョン

#コンソールについて
画面とキーボードが組み合わせを指し。
事実上それはターミナルである。
技術的にはコンソールはデバイスを指し、ターミナルはコンソール内のソフトウェアプログラムになる
ソフトウェアの世界でターミナルとコンソールはほぼ同義であるらしい

#シェルについて
端末がユーザー入力を送信するプログラムであり、出力を生成し、それを表示するためにターミナルに返す。
シェルの例について

- bash
- fish
- zsh
- ksh
- sh
- tsch
- PowerShell
- pwsh
- cmd
- yori
- 4dos
- command.com

などがある。

個人的解釈
カーネルと呼ばれるOSの中心的プログラムとユーザを橋渡しする、プログラムのこと。
ユーザの入力情報はシェルを介して渡され、処理するのはカーネル

注意なのが、シェルの選択が、ターミナルの選択を指示するものではなく、指示するものでもない

参考記事[https://www.hanselman.com/blog/WhatsTheDifferenceBetweenAConsoleATerminalAndAShell.aspx]

# コマンドプロンプト
Windowsの前身である「MS-DOS」OSからある、OSを操作するためのシェルでコマンドプロンプトからOSに命令を送り、結果をコマンドプロンプトに表示する。(こういった処理を「コマンドラインインタプリタ」と呼ぶ)実際の実行ファイルの名前はcmd.exeである。
現在のWindowsではコマンドプロンプトの役割はエクスプローラーが行っている。
エクスプローラーはGUI(グラフィック・ユーザー・インターフェース)のためマウスによる直感的な操作ができるため、PCが苦手な人でもPCを簡単に操作できるという特徴がある。逆にコマンドプロンプトはCUIとよばれ、コマンドを入力して操作するため、コマンド使用方法を熟知していないといけないため、PC初心者に不向きである
LaravelのLogを思いのままに出す

Laravelではログを簡単に出力する仕組みが準備されている。
とりあえずLogファザードを使えば、ログレベル別のメッセージを簡単に出力できる。
でも、それだけじゃちょっと困るのだ。
例えば、だれがいつアクセスしたか、いわゆるアクセスログにはキーとなる情報が欲しいし、エラーログはなるべくすぐにエラー個所にたどり着けるよう、エラー情報に特化したログのほうがいい。
じゃあ、そんな風に自由にLOGを出せるよう、れっつlaravel！
ごめんねノーサイドゲームの再放送見ちまったかられっつラグビーと絡んじゃってつい書いちゃった。

#１．出力先を分けてみよう
通常のLOGは/storage/logs/laravel.logに出力されるけど、エラー分だけエラーログに、アクセス情報はアクセスログに出したい。
そんな設定は、config/logging.phpの中で設定している。
logging.phpは微妙に長いが、書かれていることは非常にシンプルです。
☆基本どういう出し方をするか？
defaultで設定します。

```php:logging.php
'default' => env('LOG_CHANNEL', 'stack'),
```
デフォルト.envの中のLOG_CHANNELを持ってくるが、省略時はstackだよ、と言っている。
.envの中はこんな感じ。

```:.env
LOG_CHANNEL=stack
```
同じじゃん。単にsingleとかdailyとかにしたいだけなら、.envを変更するだけでログの出力設定を変更できる。

logging.phpの次の設定は、Log Channelだ。
ここには具体的なログの取り方を指定する。
最初に書いてある「stack」はちょっと特殊な扱いで、stackの中にあるchannelsにLog Channelを記述すると、その設定のログを取ってくれる。ここに複数のログを指定することが可能なので、取りたい種類のLog Channelをがつがつ書いていけばいいってことだね。
その下に書かれている「single」以下のchannelが、実際にログを出力する内容の部分だ。どれがどんなログを出しているか知りたい人は適当にググってくれ。結構当たるぞ。
さて、Channelの中にerrorlogあるじゃん。これを出すか？

```php:logging.php
'errorlog' => [
            'driver' => 'errorlog',
            'level' => 'debug',
        ],
```
なんか、他のに比べてシンプルだね。
それもそのはず、errorlogはphpのerror_logのことだって。出力先はphp.iniで設定するんだって。
なんかなー。せっかくだから、laravel内で完結したいなー。
なので、自分でChannel追加しました。

```php:logging.php
'myerror' => [
    'driver' => 'single',
    'path' => storage_path('logs/myerror.log'),
    'level' => 'error',
],
```
とりあえずmonologをStreamingHandlerで出力、レベルはエラーとしたよ。
ついでだから、アクセスログ用のChannelも作っちゃおう。調子乗っちゃって。

```php:logging.php
'myaccess' => [
    'driver' => 'single',
    'path' => storage_path('logs/myaccess.log'),
    'level' => 'info',
],
```
で、これらをstackに設定する。

```php:logging.php
'stack' => [
            'driver' => 'stack',
            'channels' => ['myaccess','myerror'],
            'ignore_exceptions' => false,
        ],
```

本当はinfoレベルだけしか出したくないとか、加工するべきところはいろいろあるのだけれど、まずはお手軽に行きます。
設定はこんなもんで。

#２．出力内容をカスタマイズしよう
アクセスログには、どんなアクセスがあったか、キーになる情報を出したい。例えば、
・日時
・顧客番号
・端末番号
・どんな動作かわかる情報　とりあえずgetとかpostとか
とりあえずサンプルなので、こんなもんでどうでしょう。
これらの項目を自力で出します。
LOGの出力は、LOGファザードを使用します。
書き方はこんな感じ

```php
Log::info('post receipt id:'.$receipt_id.
            ' company id:'.$request->input('company_id').
            ' terminal id:'.$request->input('terminal_id'));
```
出力されるのが、こんな感じ。

```log
[2020-06-11 22:33:19] local.INFO: post receipt id:7 company id:1 terminal id:1-1-557
```
真剣にフォーマットしたり、JSONで出力してelasticsearchに食わせたりしたらもっと愉快なLOG LIFEになると思うが、それはおいおい。
おいおい、じゃないよ、追々だよ。
それではその日まで、あでぃおす、あみーご！！
Slackbotに@メンションを飛ばしてもらう

# Slackbotとは
![f788648f4675efd23c6a25e865ff5509.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390881/4e9cece9-914a-588c-63d2-8c3b5b414985.png)

- 彼
- ユーザーのメッセージに対応して，カスタムメッセージを返すことができる


# まずはカスタムレスポンスを使ってみる

Slackアプリケーションから**ワークスペースのカスタマイズ**ページに飛ぶ
![e447c113f7c3e555259f753bd6c62a2e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390881/c66f1b74-5439-2196-cd4b-08fd5c34439e.png)

SlackBotのタブを選択する
![fe9d0132fe575c67369213f60fb3c42a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390881/4a55de7b-bca6-2c6c-0202-07f5ee6aa770.png)

赤枠の**新しいレスポンスを追加する**を押下する
![0c77e5570fad345127b392269b3b6c7c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390881/4098a0a5-1cb6-d5b9-531b-4a5999398762.png)

左がトリガーの言葉で，右がSlackBotのセリフ
![dda20f0ddd2f44f703faeb3a43cf471c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390881/4a654ae4-7952-5420-0dc8-d6f39e6a41aa.png)

今回は以下のような設定でテストしてみる
![1a7c48cc7f3decbcee8b7165d7463180.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390881/cd074f7a-6f03-3b0d-deb3-883ff633c6f6.png)

- リンク先はこれ
  - https://youtu.be/o7pdlLoP4yA

ここまでできたら**「レスポンスを保存する」**を押下してテストしてみる
![561dd6a8f57e5d44ceefd9aeae8f9af5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390881/b2123e92-0fcf-42b6-2231-5ac3d340d38f.png)

「おすすめの曲は？」に反応してリンクを送ってきた

# SlackBotにメンション付きのメッセージを送ってもらう
単純に考えればこんな感じでできるはず
![581b4c8da69c6efb7337de2271fe7293.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390881/de57b962-99b7-a3b7-ea57-0b5f98802ee9.png)

でも実際にはできない
![d3a98575a8b66774d53e57bec5c367f7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390881/d6e596bf-6425-6892-3abc-40de3a10a89b.png)

しっかりメンションをつけられればこんな山吹色の表示になるはず
![ac319fa1ff123b6f1c605f17813ab9c0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390881/d58a56b8-4ee0-4b52-5edc-da5f21d7becb.png)

原因は、メンション時に参照しているのが**UserName**だから
ではUserNameはどうやって見るのか？
右側のタブの中から**メンバー管理**を選択する
![2c5752e389a0f2176ebc52453f8716de.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390881/4e7cda94-b273-f496-b947-86e902a933ac.png)

右上にある**メンバーリストをエクスポートする**をクリックしてダウンロードする
![11cfb69e1b24400d004e70cc25d5467e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390881/7e6872ee-9430-40d6-93c2-8b024eb23573.png)

ダウンロードしたCSVファイルを開くと以下のような構成になっている
これの**A列(username)**を使ってメンションすると上手くいく
![56d5b57723e394a33e27776be136496e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390881/c714557f-9c67-b05c-e276-cb48dd033c02.png)

では今度は**username**を使って返信させてみる
![6ceae4a5b4b4e8ddb308a907d55e358a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390881/c0deeeec-3801-a362-28f5-d2a78ddf5e87.png)

上手くいった
![7a76159a2eb70092f68cd64efda7ecd1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390881/e2b8c3d6-bfc6-cb03-3d9b-35cc9620c25a.png)

これで特定の誰かに布教することができる
MediaPipeのハンドトラッキングをiPhoneで

#はじめに
aloha!
新型コロナ（COVID-19）旋風の中、まだ、レインボーブリッジの東京アラートが赤く点灯しています。

さて、4月から研究職から離れて、技術は、自宅で自由に遊ぶことになりました。
コンタクトレスエコノミーになっていく時代、どんなことができるのか、考えていたところ、手の骨格がわかるとジェスチャーコントロールできるなあと思ってみてみたら、Googleが<a href="https://mediapipe.dev/">MediaPipe</a>という素敵なプロジェクトを公開していました。

早速、MacとiPhoneでビルドしてみます。

#環境
・MacBook Air（macOS 10.15.5）
・iPhone XS （iOS13.5.1）
・Xcode 11.5

#さっそくやってみよう
mediapipe.gitをcloneします。

```
% git clone https://github.com/google/mediapipe.git
```

#bazelのインストールする

homebrewを使っていない場合は、インストールします。（使っている場合は、スキップしてください）

```
% /usr/bin/ruby -e "$(curl -fsSL \
https://raw.githubusercontent.com/Homebrew/install/master/install)"
```
<a href="https://bazel.build/">bazel</a>をインストールします。

>※Googleにより開発されているソフトウェアのビルド・テストツールです。Java、C ++、Android、iOS、Goおよびその他のさまざまな言語プラットフォームをビルドしてテストします。BazelはWindows、macOS、Linuxで動作します。

```
% brew tap bazelbuild/tap
% brew install bazelbuild/tap/bazel
```
bazelのバージョン確認します。

```
% bazel --version
```

必要であれば、最新版にアップデート

```
% brew upgrade bazelbuild/tap/bazel
```

#Tulsiをclone

>Tulsiは、bazelのコードからXCodeプロジェクトを生成するジェネレータらしいです。

```
% git clone https://github.com/bazelbuild/tulsi.git
% cd tulsi
% sh build_and_run.sh
```
XCodeのバージョンが違うというエラーが出る場合は、

```shell:tulsi/build_and_run.sh
xcode_version="11.3.1"
```

を

```shell:tulsi/build_and_run.sh
xcode_version="11.5"
```
へ変更してから

```
% sh build_and_run.sh
```

実行してみてください。

Macのアプリケーションの中にTulsi.appがインストールされます。これを起動します。
Open Existing Projectを押下し、自分の指定したディレクトリにある/mediapipe/MediaPipe.tulsiprojを選択します。
Configsタブに「Generate」ボタンを押下し、保存するディレクトリを指定します。

Xcodeプロジェクトが表示されるので、スキーマをHandTrackingGpuAppに切り替えて、DeviceをiPhone（実機）に指定します。
この時、XcodeのGeneral→Identity→Versionに1.0を、Buildに1を追記しました。
また、Signing&Capabilities→Signingで、Automatically Manage Signingをチェックし、Teamに自分のアカウントを指定します。
うまくいかない場合は良きようにゴニョゴニョしてください。

#少しカスタマイズ
##バックカメラへ変更
デフォルトのままだとフロントカメラになるので、バックカメラに変更してみます。
mediapipe/examples/ios/handtrackinggpu/ViewController.mmの109行目付近にある

```c:ViewController.mm
_cameraSource.cameraPosition = AVCaptureDevicePositionFront;
```

を

```c:ViewController.mm
_cameraSource.cameraPosition = AVCaptureDevicePositionBack;
```
に変更します。

##ミラー表示を止める
また、バックカメラへ変更したので、ミラー表示も止めたい場合は、
同じくViewController.mmの100行目付近にある

```c:ViewController.mm
_renderer.mirrored = YES;
```

を

```c:ViewController.mm
_renderer.mirrored = NO;
```
へ変更します。

Buildをするとしばらくして、iPhone側にインストールが行われます。

#実行結果
動画で掲載すればもっとわかりやすいのでしょうけども、かなり高速（30fpsはありそう）に描画されています。
![IMG_3174.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413003/aec0cb1a-b00d-ce6f-afb2-677c245f6f14.png)



#本家のサンプル
もし、どんな感じなのかだけを確認したいのであれば、MediaPipeさんのサイトで、Webブラウザで体験できるデモを提供しています。Gogole ChromeとFacetime HDカメラ（Macに内蔵）があれば試せます。

・<a href="https://viz.mediapipe.dev/demo/face_detection">MediaPipe顔検出</a>
・<a href="https://viz.mediapipe.dev/demo/hand_tracking">MediaPipeハンド</a>
・<a href="https://viz.mediapipe.dev/demo/hand_detection">MediaPipe Hand（手のひら/手の検出のみ）</a>
・<a href="https://viz.mediapipe.dev/demo/hair_segmentation">MediaPipe髪のセグメンテーション</a>

#おわり
 単眼カメラでもかなり高速に手の骨格認識ができるので驚きました。これまでは、Intel Realsenseなどでやってみたことがありましたが、これはかなり良さそうです。

mahalo!
Pi4とPX-Q1UDで起動できなかったメモ

ただのメモでございます。

いま、Pi4にPX-Q1UDをつないで録画サーバーを作っている最中なのですが。。とあるトラブルがおきまして。

　　PX-Q1UDに外部電源をつないだ状態だと起動できない

原因がよくわからず、いろいろ試したのですが、
・起動できない状態から外部電源を外すとすぐに起動を始める
・起動後に外部電源につなぐのは問題なし
・外部電源付きでPi4との接続にハブをかますと起動できる
・Pi4とのUSB接続ケーブルの電源端子を絶縁すると起動できる

というわけで、理由はよくわからんが、外部電源からPi4に向かって電気が回って起動を邪魔しているのでしょうか？とテキトーに言ってみます。

実用的な運用は、
・ハブをかませてPX-Q1UDを接続する
・USB延長ケーブルを細工して電源線を切断する
・pi4とPX-Q1UDのUSB電源線の間に紙かテープか何かを貼り絶縁する


その他おちったトラブルについてはそのうちまた。
■アバター（FaceRig）を使ってオンライン会議に入ってみた件

##**■はじめに**
・オンラインでミーティングをすることもしばしばあるかと思います。そんな時、”顔出しは抵抗ある…　声だけと言うのもちょっと…　アバター使ってみたいけどめんどくさいのやだ…　”と言うことありますよね。そこで、簡単にアバターで入れるやり方をお教えします。と言った感じで忘れないうちに**備忘録**として残しておきます

###**■■ここで出来るようになること**
・FaceRig(ユーザーの顔の表情をWebカメラを取り込み、アバターを使って動作を再現するで表現するソフトウェア)を使ってオンライン会議アプリ（Zoom, Teams, GoogleMeet）にアバターで入ることができる様になります

##**■環境**
**・Windows 10 （FaceRigがWindowsしか対応していないのでそれ以外のOSではできません）**
・FaceRig　Steamから購入。セールの時に買うとお得です
　https://store.steampowered.com/app/274920/FaceRig/?l=japanese
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224568/8d32d45f-4796-7f17-f82a-a6430e9db7e3.png)
・オンライン会議アプリ　今回やってみたもの
　・Microsoft Teams
　・Zoom
　・GoogleMeet

**※上記は現時点（2020/06/11）で動作確認が取れた組み合わせになります。最新の環境の組み合わせについては各自でご確認下さい**

**※後継アプリとなる”Animaze by FaceRig”について書いた記事は[こちら](https://qiita.com/KSxRDevelop/items/2d8ac86c5b26cf911765)**

▲初投稿：2020-06-11
▲更新：2021-04-06

##**■やってみよう！**
###**■■FaceRigの設定**
・FaceRigの購入、インストール手順についてはここでは省きます。起動出来ている事が前提の記載になります

・FaceRigを起動します。起動したら”ブロードキャストに切り替え”をONにします
![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224568/ab73ec48-973d-8fd6-7c63-1dd7d8507753.png)

・右側のメニューからアバターを変える事が出来ます。Live２Dモジュールを購入すると２Dキャラクターを選択することも出来ます
![b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224568/a922b07b-c87e-1e8c-94c5-cba20f88400a.png)

・右側のメニューから背景を変える事が出来ます。zoomではグリーンバックを使うとzoomで背景を切り替えることも出来ます
![c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224568/f8f60ddc-7cd6-7921-9f05-b0b5ebca34df.png)

※以上が最低限の設定になります。他にも多種な機能があるので試して見るとおもしろいと思います

**※注意：FaceRig は落とさずに起動したままオンライン会議アプリを使ってください**

※以降、”FaceRig Virtual Camera”ドライバーが必要になります。選択に出てこない時は以下の場所にドライバがあるので該当のものをインストールしてください
~\steamapps\common\FaceRig\Bin\prerequisites\FaceVirtualCamDriver

###**■■Microsoft Teams にアバターで入る**
・Teamsの設定画面で、カメラを”FaceRig Virtual Camera”に変更します
![d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224568/0012dcda-13d2-660e-a5eb-c22317b1a9f0.png)

###**■■Google Meet にアバターで入る**
・Google Meetの設定画面で、動画＞カメラを”FaceRig Virtual Camera”に変更します
![e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224568/195762ae-3319-6d68-c764-1c38e9c5a96e.png)
![e2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224568/0639bf12-c93f-58e5-ce91-5f4bda536511.png)

###**■■zoom にアバターで入る**
・zoomのカメラ選択で、”FaceRig Virtual Camera”に変更します
![f.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224568/eadb1383-7014-0276-45bd-9341d6db8e88.png)
※FaceRigで背景をグリーンバックにしていると、zoomで背景を設定することも出来ます

**※実際に確認はしていませんが、Discordでも、カメラの選択を”FaceRig Virtual Camera”に切り替えると使える様です**

・とりあえず、これでアバターでオンライン会議に入ることができる様になったら思います。今まではちょっと違った体験を感じてみてください！

##**■参考**
・FaceRig　・・・　[こちら](https://store.steampowered.com/app/274920/FaceRig/?l=japanese)　
・■アバター（Animaze by FaceRig）を使ってオンライン会議に入ってみた件　・・・　[こちら](https://qiita.com/KSxRDevelop/items/2d8ac86c5b26cf911765)　
・ZoomでFaceRig使ってバーチャル参加する方法　・・・　[こちら](https://qiita.com/warapuri/items/7ec5f92fc96563c8b39e)　
・ビデオ通話や配信で顔出ししたくないなら『Facerig』がおすすめ　・・・　[こちら](https://jpstreamer.com/streamingtrend/how-to-use-facerig-with-zoom)　

・Qiita(KSxRDevelop)　・・・　その他の情報は[こちら](https://qiita.com/KSxRDevelop)
positionについて

#positionとは
　ざっくり言うと要素の位置を決めるためのものです。要素の上に別の要素を載せる時などに使われます。

#positionと4つのセレクタ
  static   : 初期値として設定さている。
  relative : 現在の位置を基準に相対的な位置を決める
  absolute : 親要素を基準位絶対的内地を決める 
  fixed    : 位置を固定する

#positionと４つのプロパティ
  top    :上からの距離を
  bottom :下からの距離
  left   :左からの距離
  right  :右からの距離

この４つのセレクタと４つのプロパティを駆使することで要素の位置を決めることができます。

#参考文献
https://saruwakakun.com/html-css/basic/relative-absolute-fixed#section1
GatbyJS の graphQL 上でテーブル間の親子関係を作る方法

## GatbyJS の graphQL 上でテーブル間の親子関係を作る方法

GatsbyJS でテーブルを作成する方法は日本語でも見つかったのですが、そのテーブルに親子関係を設定する方法が見つからず、公式を確認することになったので日本語で書いておきます。

親子関係を作ると「graphQL から子候補を全件取得して条件に一致した子を利用する」みたいなことをしなくて済みます。

以下ソースコードのコメントで解説します。
gatsby-node.js に書いてください。
もしくは gatsby-node.js で require をした関数を export してください。

```gatsby-node.js
async function sourceNodes(
  {
    actions,
    createNodeId,
    createContentDigest,
    getNode,
    getNodesByType,
    reporter,
  },
  pluginOptions
) {
  /* Piyoテーブルのレコードを全件取得する */
  const nodeList = getNodesByType('Piyo');
  const promises = nodeList.map(async (node) => {
    const org = node['fuga'];
    let hoge;
    try {
      /* Piyoテーブルのfugaフィールドを取得してhogeを作ります */
      hoge = createHoge(org);
    } catch (e) {
      /* hogeの作成に失敗した場合 */
      reporter.panic("can't create hoge: ", e);
    }
    const newNode = {
      org,
      hoge,
    };

    /* nodeIdを作成して保持します */
    const nodeId = createNodeId(
      `piyo-fuga-hoge-${node.id}`
    );
    const nodeBase = {
      ...newNode,
      id: nodeId,
      parent: node.id // 子供側に親を設定する,
      children: [],
      internal: {
        type: "PiyoFugaHoge", // 子テーブルの名前を決める
        contentDigest: createContentDigest(newNode),
      },
    };

    /*
     * 子ノードを作成する
     *（Promise<void>を返すので子ノードを取得しなおさなければならない）
     */
    await actions.createNode(nodeBase);
    /* 子ノードを取得する */
    const childNode = getNode(nodeId);
    /* 親側に子を設定する */
    actions.createParentChildLink({ parent: node, child: childNode });
  });

  await Promise.all(promises);
}
exports.sourceNodes = sourceNodes;
```

↑ の例だと Piyo テーブル直下に childPiyoFugaHoge を作るので、参照するのが楽になります。

以上です。ここまで読んで頂きありがとうございます。

この記事は[ブログ記事](https://myblog-by-mako-tos.netlify.app/post/2020-06-11-create-parent-child-on-graphql/)の転載です。
「GitHub Desktopでよくあるトラブル」

今日はバディー見学で学んだGitHubの問題について共有します。
##【トラブル】間違えてmasterブランチでpushをしてしまった場合の対処

**１．masterブランチのHistoryタブに移動**
**２．以下のようにコミットを取り消す**
<img width="1440" alt="スクリーンショット 2020-06-11 21.19.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613200/09594cce-c73c-631f-9290-187f0cf660bc.png">


①Historyタブから取り消したいコミット(おそらく最新のコミット)を選択し
「Revert this Commit」を選択
②するとRevert~という先程のコミットを打ち消すコミットが作成させる
③これを「Push origin」

**3.新しいブランチを作成**
新しいブランチの作り方は皆さんなら理解されていると思うので省略・・・

**4.取り消しコミットの取り消しをコミット**
<img width="668" alt="6DA7DF7A-4FB5-41B4-83DF-8251D7D0DDA7_1_105_c.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613200/96083fb7-82db-48db-480f-4a24a7eff7cb.jpeg">

①HistoryタブからRevert"Merge~というコミットで「Revert this Commit」を選択
②するとRevert"Revert"Merge~というマージを打ち消したコミットを打ち消すコミットが
作成される
③「Publish branch」でリモートに最初のコミット&プッシュをする

**5.Historyタブからchangesタブに移動し「Create Pull Request」を押して終了**

##まとめ
今までコミットやプッシュを間違えたらターミナルでgitログを調べ、git revert
コマンドを打つような流れをイメージしていたが、そもそも使ったこともないし、
改めて考えてみるとよく理解できていませんでした。
①「コミットを取り消す」
②「①で取り消した事自体を更に取り消す」という流れを把握できていなかった。
また、ターミナルを使用しなくてもGithub Desktopからでも操作方法により
git revertの操作が行えるということも勉強になりました。
これならいちいちログを調べてコマンドを打つような難しい作業を行わなくて済みますね。
[PS4] マインクラフトで "Microsoft アカウントへのサインインを試みましたが、問題が発生しました" と出た時に試すべきこと

1.マインクラフトを起動

2.[プロフィール] > [アカウントのサインイン データをクリア] を選択

3.再度メニューに戻ると1.マインクラフトを起動

2.[プロフィール] > [アカウントのサインイン データをクリア] を選択

3.再度メニューに戻るとマイクロソフト アカウントと紐づける一時コードが表示されるので、https://aka.ms/remoteconnect にアクセスして、再度紐づける
TechAcademyが無料公開している「HTML・CSS入門講座」を受講する～HTML第6回～

# アジェンダ
* HTMLのタグ
    * table
    * tr
    * td
    * thead
    * tbody
    * tfoot
* HTMLの属性
    * border
    * colspan
* 実践

# HTMLのタグ
## table
テーブルであることを示すタグ。

## tr
テーブルのうち、ひとつ分の行であることを示すタグ。
table recordのtr。

## td
テーブルのうち、ひとつ分のセルであることを示すタグ。
table dataのtd。

## thead
テーブルのヘッダーであることを示すタグ。

## tbody
テーブルの内容であることを示すタグ。

## tfoot
テーブルのフッターであることを示すタグ。

※thead,tbody,tfootを使用することで、"theadとtfootを固定し、tbodyの箇所だけスクロールする"のようなことができる。

# htmlの属性
## border
枠線の太さを指定するのに用いる属性。
HTML5では1のみ指定できる。

※HTML Living Standardによると、border属性は廃止された。
> 参考 : [HTML Living Standard - とほほのWWW入門](http://www.tohoho-web.com/html/memo/htmlls.htm)

## colspan
同じ行の、複数のセルを結合させるのに用いる属性。
値には結合させるセルの個数を記載する。

# 実践
上記のタグ・属性を用いて、以下のindex.htmlを作成した。

```html:index.html
<!DOCTYPE html>

<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>外部ファイル</title>
  </head>
  <body>
    <h1>外部ファイルに関するタグと属性のまとめ</h1>
    <hr>
    <p>今後HTMLを書いていく際、どのタグにどの属性を書くのかわからなくなる予感がしたため、表でまとめた。
      <table border="1">
        <thead>
        <!-- 一行目. -->
        <tr>
          <td></td>
          <td>img</td>
          <td>link</td>
          <td>script</td>
          <td>iframe</td>
        </tr>
        </thead>
        <tbody>
          <!-- 二行目. -->
          <tr>
            <td>type</td>
            <td></td>
            <td>〇</td>
            <td>〇</td>
            <td></td>
          </tr>
          <!-- 三行目. -->
          <tr>
            <td>title</td>
            <td>〇</td>
            <td></td>
            <td></td>
            <td></td>
          </tr>
          <!-- 四行目. -->
          <tr>
            <td>rel</td>
            <td></td>
            <td>〇</td>
            <td></td>
            <td></td>
          </tr>
          <!-- 五行目. -->
          <tr>
            <td>href</td>
            <td></td>
            <td>〇</td>
            <td></td>
            <td></td>
          </tr>
          <!-- 六行目. -->
          <tr>
            <td>src</td>
            <td>〇</td>
            <td></td>
            <td>△</td>
            <td>〇</td>
          </tr>
          <!-- 七行目. -->
          <tr>
            <td>alt</td>
            <td>〇</td>
            <td></td>
            <td></td>
            <td></td>
          </tr>
        </tbody>
        <tfoot>
          <!-- 八行目. -->
          <tr>
            <td colspan="5">以上。</td>
          </tr>
        </tfoot>
      </table>
    </p>
  </body>
</html>
```

これをWebブラウザに表示させるとこんな感じ。
![index.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648214/505f82a6-338d-3b50-5a53-b2ef84831651.png)

前回作った表を再現することができた。
しかし、thead,tbody,tfootの効果は確認できなかった。

# おわりに
今回は表に関する内容だった。
うまくコメントをつけないと、表が大きくなった際にコードの可読性が低くなってしまいそうだ。

次回 >> ☆まだ☆

## 参考
[6-1 行とセル（HTMLのテーブル）](https://www.youtube.com/watch?v=T22kEynH40g&list=PLjw-30bsJNVU87F5iCPAW9kB4QDUGQxUG&index=18)
[6-2 テーブルのヘッダーとフッター（HTMLのテーブル）](https://www.youtube.com/watch?v=1uj-meQQHLw&list=PLjw-30bsJNVU87F5iCPAW9kB4QDUGQxUG&index=19)
React.memoについて

- React.memo


カレンダーでタスクの追加と削除機能を作っていたときに、レンダリングがかなり重複していたのに気がつきました。
そんな時に活かせるのが、上記にあるReactにある機能たちになります。
主にパフォーマンス向上のための機能になります。

・React.memoはコンポーネントの再レンダリングをスキップする

簡単な説明ではありますがこう言った機能になっています。


Reactにとって、再レンダリングや再計算の最適化が最も基本的なパフォーマンス向上の基本になります。



```tsx
const Greeting = React.memo((props: { name: string }) => {
  const { name } = props
  return <h1>Greeting{name}</h1>;
});
```
GoogleformからGoogleカレンダーにスケジュール登録できるようにした話

##はじめに
今回作成したformは組織内の別の人がZOOMのミーティングを作成するのをメール連絡が、面倒と言う話が出たので作成。
まだ、未完成のformなので、データを入力し送信しても、googlecalenderにスケジュール登録はされるが、ZOOMのミーティングIDは後から管理者が手動で作成し、メールするという部分は残ってます。

googlecalenderにスケジュールが登録されたらSlackに通知を飛ばさせて、それを確認したら、該当のスケジュールを開いてミーティングIDを作成し、利用者にメール送信が必要です。

##GoogleFormの作成
1．適当なGoogleアカウントでGoogleDriveにアクセス
2．新規➝その他➝Googleフォーム
3．必要な項目を作成　↓完成イメージ
![2-1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641254/c0d2e542-94c8-3936-452e-34fd529eb784.jpeg)
4．GoogleAppsScriptでスクリプトを追加
　右上「送信」横の詳細ボタンからスクリプトエディタを開く
5．下記コードを参考にコードを書く
<code>
function myFunction(e){
  //初期設定
  var itemResponses = e.response.getItemResponses();
  var message = '';
  //入力項目の解析
  for (var i = 0; i < itemResponses.length; i++) {
    var itemResponse = itemResponses[i];
    var question = itemResponse.getItem().getTitle();
    var answer = itemResponse.getResponse();
    if(question=="MTG名"){
      var cTitle=answer;
    }else if(question=="申請者名・メールアドレス"){
      message=answer;
    }else if(question=="利用日"){
      var cDate=answer.replace(/-/g,'/');
      var cEDate=cDate;
    }else if(question=="利用開始時間"){
      var cDate=cDate + " " + answer;
    }else if(question=="利用終了時間"){
      var cEDate=cEDate + " " + answer;
    }
  }
  //Googleカレンダーへの投稿
  var objCalendar = CalendarApp.getCalendarById('入力したいカレンダーのID');
  var objEvent = objCalendar.createEvent(cTitle,new Date(cDate),new Date(cEDate),{description:message}).setGuestsCanSeeGuests(false); 
}
</code>
##カレンダーIDの取得方法
1.GoogleCalendarのサイドバーにあるマイカレンダーから該当するカレンダーにマウスオーバーし、オーバーフローメニューをクリック
2．設定と共有をクリック
![2-2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641254/3df7ec2a-f990-b73e-2642-a0b8f3ee93ca.jpeg)

3．カレンダーの統合の中にある、カレンダーID欄をすべてコピー
![2-3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641254/66fdffda-0de8-5f81-719a-6aca11143135.jpeg)
Laravel 7.x で Auth を利用する

Laravel 7系で Auth を使おうとしたら、5系のコマンドが通らなかったので個人の備忘として。

# 結論

5系まで使用していた以下のコマンドは、6系以降は変更になってます。

```
$ php artisan make:auth

  Command "make:auth" is not defined.
  // 【以下省略】
```

代わりに以下を使って下さい。
https://readouble.com/laravel/7.x/ja/authentication.html

```New.
$ composer require laravel/ui
$ php artisan ui vue --auth
```

# 実際の流れ

## インストール

- laravel/ui の composerインストール

```
$ composer require laravel/ui
Using version ^2.0 for laravel/ui
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Nothing to install or update
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fideloper/proxy
Discovered Package: fruitcake/laravel-cors
Discovered Package: laravel/tinker
Discovered Package: laravel/ui
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.
30 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
```

- Auth の認証スカフォールドを生成

```
$ php artisan ui vue --auth
Vue scaffolding installed successfully.
Please run "npm install && npm run dev" to compile your fresh scaffolding.
Authentication scaffolding generated successfully.
```

- Vueまわりのパッケージをインストールする  
ログイン画面やユーザ登録画面のCSS準備などにも必要で、**この時点でログインページを表示すると崩れます**…

```
$ npm install && npm run dev
```

## DBをマイグレーション

ここまでの手順で、以下の通り必要なマイグレーションファイルは自動で生成されます。

```
$ ls -l database/migrations/
total 12
-rw-rw-r-- 1 appdev appdev 798 May 19 06:50 2014_10_12_000000_create_users_table.php
-rw-rw-r-- 1 appdev appdev 683 Jun 11 20:56 2014_10_12_100000_create_password_resets_table.php
-rw-rw-r-- 1 appdev appdev 774 May 19 06:50 2019_08_19_000000_create_failed_jobs_table.php
```

特にカスタマイズするテーブルがなければ、 `.env` または `config/database.php` が適切に設定されていることを確認し、マイグレーションを実行します。

```
$ php artisan migrate
```

この後はユーザー登録　→　ログイン確認をすれば良いでしょう。

Fin❤︎
OpenCV/C++/プロパティシート


#プロパティシート
プロジェクトの設定をまとめたものです。拡張子　.props

VSでプロパティマネージャを表示して新規作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555658/785f9a08-8b23-87d9-1fe8-c9d058019696.png)

ダブルクリックするとダイアログ表示されます。項目はみなれた物なので必要なものを設定します。

```
<?xml version="1.0" encoding="utf-8"?> 
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ImportGroup Label="PropertySheets" />
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup />
  <ItemDefinitionGroup />
  <ItemGroup />
</Project>

```

プロジェクト側で設定をいじると、プロパティシート設定が反映されない事があります。
その場合、%(AdditionalIncludeDirectories)を入れるとよいみたいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555658/796a628a-bfe7-1698-1f0b-2f60e90d87bb.png)

インクルード　AdditionalIncludeDirectories
ライブラリ　AdditionalLibraryDirectories

FBXSDKでつかったもの

```

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ImportGroup Label="PropertySheets" />
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup />
  <ItemDefinitionGroup>
    <ClCompile>
      <AdditionalIncludeDirectories>C:\SDK\fbxsdk\20190\include;C:\SDK\fbxsdk\20190\include\fbxsdk\core;C:\SDK\fbxsdk\20190\include\fbxsdk\scene\constraint;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
    </ClCompile>
    <Link>
      <AdditionalLibraryDirectories>C:\SDK\fbxsdk\20190\lib\vs2015\x64\debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
      <AdditionalDependencies>libfbxsdk-md.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup />
</Project>

```
WindowsでGoの開発環境構築

## Chocolateyのインストール

PowerShellを管理者権限で起動し、下記のコマンドを実行します。

```
Get-ExecutionPolicy
```

このコマンドでもし`Restricted`が返ってきたら、`Set-ExecutionPolicy AllSigned`または`Set-ExecutionPolicy Bypass -Scope Process`を実行するらしいのですが、私の環境では、`Bypass`が返されたので、未検証です。


続いて、下記を実行します。

```
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
```

```
Installation of Chocolatey to default folder requires Administrative permissions. Please run from elevated prompt. Plea
se see https://chocolatey.org/install for details and alternatives if needing to install as a non-administrator.
```
と言われたらPowerShellを管理者権限で起動してください。

*Chocolatey (choco.exe) is now ready.*
が表示されればインストールは成功です。

## Goのインストール

```
choco install golang
```

*The install of golang was successful.*
が表示されればインストールは成功です。

## PATHの編集
環境変数PATHに`%GOPATH%\bin`を追加します。

[コントロールパネル] -> [システムとセキュリティ] -> [システム] -> [システムの詳細設定] -> [環境変数] で`Path`に`%GOPATH%\bin`を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230436/7ebc361b-ba13-f176-4360-f84774deb7c2.png)

## インストールの確認
PowerShellを起動し、`go version`でバージョン情報が表示されればインストール成功です！
posts/show.html.erb

<div class="main posts-show">
  <div class="container">
    <div class="posts-show-item">
      <div class="post-user-name">
        <img src="<%= "/user_images/#{@user.image_name}" %>">
        <%= link_to(@user.name, "/users/#{@user.id}") %>
      </div>
      <p>
        <%= @post.content %>
      </p>
      <div class="post-time">
        <%= @post.created_at %>
      </div>
      <!-- if文を用いて、表示内容を切り替えてください -->
      <% if Like.find_by(user_id:@current_user.id,post_id:@post.id) %>
      いいね！済み
      <% else %>
      いいね!していません
      <% end %>
      
      
      <% if @post.user_id == @current_user.id %>
        <div class="post-menus">
          <%= link_to("編集", "/posts/#{@post.id}/edit") %>
          <%= link_to("削除", "/posts/#{@post.id}/destroy", {method: "post"}) %>
        </div>
      <% end %>
    </div>
  </div>
</div>
投稿詳細ページで、その投稿にいいねしたかどうかを表示できるようにしましょう。
個人的用メモ　Progate Ruby Ⅰ(1) 

##●Rubyとは？

まつもとゆきひろ氏により開発されたオブジェクト指向スクリプト言語。WEBアプリの「システム」を構築するためのプログラミング言語。

類似言語：PHP, Python


##1.Rubyの実行
```
>_コンソール

Hello あざらし　
```
・コンソール…入出力装置

##2.Rubyの基本と文字列

```
puts "Hello あざらし"
```
・命令「putsの後の値を出力せよ」

＊文字列は必ずシングルかダブルクォーテーション
※ ＃=その行がコメント(灰色で表示)

##3.数値と足し算・引き算
###[注意] 
・数値はクォーテーションで囲まない
・文字列と数値は別

```
 5 + 2 =7     ← (数値)
"5 + 2"       ← (文字列)
```

##4.様々な計算

● Addition(+)
● subtraction(-)
● multiplication(/)
● division(%)

  
##5.文字列と数値の連結

```
puts "あざらし" + "だよ" 
```
```
>_コンソール

あざらしだよ　
```
⇒文字列同士に+記号を用いると、
文字列同士を連結できる。

※数値の場合も同様

```
puts  3 + 5  → 8  (数値)
puts "3"+"5" →35 (文字列)      
```
Qiitaに予約投稿する仕組みを作る【下書き取得編】 ~1日10行コーディング 〜~

## 8日目

前回に引き続きQiitaの取得部分を作成します。

### 【技術テーマ】
Qiitaの下書きスクレイピング

### 言語
* Ruby

### 目標成果物
Qiitaの自分の下書き一覧を取得する

### コードと資料

#### 下書き取得の実装

前回同様ログイン系の処理なのでmechanizeを使います。

crawler.rb

```crawler.rb
page = agent.get("https://qiita.com/drafts")
doc = Nokogiri::HTML.parse(page.body, nil, 'utf-8')
json = JSON.parse(doc.css('.js-react-on-rails-component')[1].inner_html)
json['creating_draft_items'].each do |item|
  if item['raw_body'].match(/予約投稿/)
    id = item['item_uuid']
    title = item['title']
    raw_body = item['raw_body']
    tags = item['tag_notation'].split(' ')
    agent.get("https://qiita.com/drafts/#{id}")
    tag_data = []
    tags.each do |tag|
      tag_data.push({name:tag,versions: []})
    end
  end
end
```

前回から追加&修正で上記の文を追加します。
上のコードでは下書き情報の一覧を取得し、その中に予約投稿という文言があったらその情報を取得するということをしています。
前回下書きの取得部分でURLをIDかなにか指定していたのですが/draftsでリダイレクトされるのでこれでいけます。


【次回】
いよいよ投稿部分を作ろうと思うのですが、思ったより苦戦しそうで....
もしかしたらseleniumとかに頼るかもしれない....
[UE4] パッケージアプリの起動直後からデバッガをアタッチする

検証Ver:4.25.0

#ケース
　極々稀ですが「起動直後のパッケージアプリにアタッチしたい」ことがあります。主に以下の問題に遭遇した場合です。

・Visual Studioから起動した時には問題が発生しないのにパッケージだけ問題が発生する
・アプリケーションが起動直後に問題が発生するのでログも何も出力されずヒントが無い
・パッケージにプロセスアタッチしたいけどクラッシュするタイミングの方が早いので間に合わない

もう少し具体的には以下のようなケースが該当します。

・アプリケーション起動直後に理由不明の強制終了が発生する
　→ プラグインの読み込み失敗、アセットの破損など

・アプリケーション起動直後のデバッグ
　→ パッチのマウント、初回ロードなど

#起動時引数で解決
　`-WaitForDebugger`のコンソールコマンドをアプリケーション起動時引数に渡すことで、デバッガがアタッチ(Visual Studioからプロセスアタッチ)するまでアプリケーションがSleepで待機させておくことができます。ソース上ではEngineLoopのPreInit()で以下のようにプロセスアタッチが発生するまで待機します。これを使えばアプリ内にディレイを仕込む必要が無くなるので良いですね。

```:
#if !UE_BUILD_SHIPPING
    if (FParse::Param(FCommandLine::Get(), TEXT("WaitForDebugger")))
    {
        while(!FPlatformMisc::IsDebuggerPresent())
        {
            FPlatformMisc::LowLevelOutputDebugString(TEXT("Waiting for debugger...\n"));
            FPlatformProcess::Sleep(1.f);
        }
        FPlatformMisc::LowLevelOutputDebugString(TEXT("Debugger attached.\n"));
    }
#endif
```

　あとはVisual Studioから[Debug]->[Attach To Process]を選択して、
![2020-06-11_14h00_40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101019/c10f6d17-d857-e6f3-9c00-18bfea68c2ea.png)

　実行中のアプリケーションを選択してAttachすることで、アプリケーションのウィンドウを開いて進行します。
![2020-06-11_14h00_58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101019/6c4b578c-077e-9a42-2643-b197a350e090.png)

　プロセスアタッチするまではアプリケーションウィンドウが開かれていない状態のため、アタッチし忘れるとずっとバックグラウンドで動いたままとなります。アプリのアタッチし忘れにはご注意ください。

#おまけ
　起動引数には様々なものが存在していて、公式ドキュメントの[「コマンドライン引数」](https://docs.unrealengine.com/ja/Programming/Basics/CommandLineArguments/index.html)でも確認することができます。
他にも色々ありますが、ドキュメントに無い項目としては以下のようなものもありますのでデバッグ時などに役立てて下さい。

**-CleanLogs**
　ログ用フォルダがある場合削除します。ログファイルが貯まり続けるのを抑制するのに役立ちます。

**-CleanScreenshots**
　スクリーンショット用フォルダがある場合削除します。上記同様にスクリーンショットが蓄積するのを抑制できます。

**-ExecCmds** (-execcmds="stat unit, stat memory")
　起動直後から対象のコンソールコマンドを実行することができます（複数のコマンドを指定することも可能です）。
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111)

mysql -u rootと打つとERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111)
となっておそらくログインできない状態？になってるのでログインできる状態にしたい

mysql -u rootと打つとERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111)
となっておそらくログインできない状態？になってるのでログインできる状態にしたい

現在udemyのhttps://www.udemy.com/course/web-application-development/learn/lecture/9175504#content　
コースの受講をしていて
環境はASWcloudでmySQL5.7.28です
上記の通りログインできない状態になっています

# 試したこと 

再インストールしようとして

sudo yum -y remove mysql-config mysql55-server mysql57-libs mysql57

sudo yum -y install mysql57-server mysql57

はうまくいったのですが

sudo service mysqld start　と打つと

Socket file /var/lib/mysql/mysql.sock exists.
The file /var/lib/mysql/mysql.sock is not a socket file, which is suspicious.
Please, remove /var/lib/mysql/mysql.sock manually to start the service.
と表示されます
【Rails】reCAPTCHAの導入方法

# 目標

![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/2f27b858-bdf8-3d35-8dd9-e61ffbc9228e.gif)

# 開発環境
・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina

# 前提

下記実装済み。

・[Slim導入](https://qiita.com/matsubishi5/items/b639ffddecc626856039)
・[ログイン機能実装](https://qiita.com/matsubishi5/items/5bd8fdd45af955cf137d)

# reCAPTCHAを登録

### 1.下記リンクにアクセス

[reCAPTCHA](https://www.google.com/recaptcha/intro/v3.html)

### 2.`Admin console`をクリック
![スクリーンショット 2020-06-11 19.59.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/07d9f666-d722-e1ce-ba0e-991120f24416.png)

### 3.下記画像の様に設定し、`送信`をクリック
![スクリーンショット 2020-06-11 20.02.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/69ef34d0-8e9b-801d-b119-f2e99729739e.png)

![スクリーンショット 2020-06-11 20.02.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/6e0dc127-cd4c-b272-62d7-293d0572f168.png)

### 4.`サイトキー`と`シークレットキー`をコピーして控えておく
![スクリーンショット 2020-06-11 20.07.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/1a48816c-0ec4-8ba1-1019-88fbb9d37462.png)

### 5.

# 実装

### 1.`サイトキー`と`シークレットキー`を環境変数化

**①「gem 'dotenv-rails'」を導入**

```ruby:Gemfile
gem 'dotenv-rails'
```

```terminal:ターミナル
& bundle
```

**②アプリケーション直下に「.env」ファイルを作成**
※アプリケーションのディレクトリに移動してから下記コマンドを実行

```terminal:ターミナル
$ touch .env 
```
![スクリーンショット 2020-06-02 11.32.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/6136dec1-89a9-94cb-0410-8aec11f79a8b.png)

**③`.env`ファイルを編集**

```:.env
# 追記
RECAPTCHA_SITE_KEY = 'サイトキー'
RECAPTCHA_SECRET_KEY = 'シークレットキー'
```

**④`.gitignore`ファイルを編集**

```:.gitignore
/.env # 追記
```

### 2.reCAPTCHAの設定ファイルを作成・編集

```terminal:ターミナル
$ touch config/initializers/recaptcha.rb
```

```ruby:recaptcha.rb
# 追記
Recaptcha.configure do |config|
  config.site_key = ENV["RECAPTCHA_SITE_KEY"]
  config.secret_key = ENV["RECAPTCHA_SECRET_KEY"]
end
```

### 3.`resistration_controller.rb`を編集

```ruby:resistration_controller.rb
# 追記
prepend_before_action :check_captcha, only: [:create]

private

  # reCAPTCA認証を行わないとサインアップ出来なくし、バリデーションメッセージを表示する
  def check_captcha
    self.resource = resource_class.new sign_up_params
    resource.validate
    unless verify_recaptcha(model: resource)
      respond_with_navigational(resource) { render :new }
    end
  end
```

### 4.ビューを編集

```slim:resistrations/new.html.slim
/ 追記
= recaptcha_tags
```

# 5.バリデーションメッセージを日本語化

**①Gemを導入**

```ruby:Gemfile
gem 'rails-i18n'
gem 'devise-i18n'
```

```terminal:ターミナル
$ bundle
```

**②`application.rb`を編集**

```ruby:application.rb
module Bookers2Debug
  class Application < Rails::Application
    config.load_defaults 5.2
    config.i18n.default_locale = :ja # 追記
  end
end
```

**③`devise.ja.yml`ファイルを作成・編集**

```yml:devise.ja.yml
ja:
  recaptcha:
    errors:
      verification_failed: 'reCAPTCHA認証に失敗しました。'
```
like.rb

class Like < ApplicationRecord
  validates :user_id,{presence: true}
  validates :post_id,{presence: true}
end
//バリデーションを追加する
いいねのデータは、user_idとpost_idの両方が常に存在していないと不完全なデータとなってしまいますので、最初にバリデーションを追加しておきましょう。user_idとpost_idのそれぞれに、値が存在していることをチェックする「presence: true」のバリデーションを追加します。
両方存在しないと不完全なデータになってしまう
repository指定したgemをbundle install しても最新に更新されない

### TL;DR

gemfileが更新されていない場合gemfile.lockにある`revision`のcommit hashを見に行ってしまうので

```bash:console
bundle update gem-name
```
しましょう

### 問題
社内で使っているライブラリに`fork -> PR -> merge`まで行っていざ確認してみようとすると追加したはずのmethodが未定義と言われてしまっていた。

### 解決までしたこと
まず何なら使えるのかを確認

```ruby:rails_console
# respond_to?はメソッドが存在するかどうかを確認するやつです
GemName respond_to? :configure #-> true
GemName respond_to? :new_added_method #-> false

# PRで入れたはずのメソッドがないことに気づいてgem自体は問題なく入っているかどうかを確認
GemName.added_a_lomng_time_ago_method #-> 通った
```
ここでPRの内容がまるっと入っていないことに気づいてHEADがずれてるんじゃないかみたいなことを検討した

```bash:console
git clone git@github.com:my-org/gem-name # forkではなく大元のリポジトリをclone
git rev-parse HEAD #-> 00ff0012345
git rev-parse master #-> 00ff0012345(HEADと同じなのを確認)
```
ずれてないねってことで試しにcommit hashでgemを指定

```text:gemfile
gem 'gem-name', git: 'git@github.com:my-org/gem-name', ref: '00ff0012345'

# bundle install する
```
```ruby:rails_console
GemName.new_added_method #-> 通った！
```
ので、`gemfile.lock`を確認した所、`revision`が変わってた。ここが原因やったんやな…………

この後

```text:gemfile
gem 'gem-name', git: 'git@github.com:my-org/gem-name', branch: 'master'
```
にしても問題なかったです。まあcommit hash指定時に`revision`がHEADになったから想定内。

### 本来すべきこと

まあそもそもinstallは`gemfile.lock`を元に行われることなので当たり前といえば当たり前なのですが、`bundle update`を使う必要がありました。リポジトリを直接指定していることにばかり気を取られて完全に忘れてました。
もしbundle installと同時にupdateを行いたい場合はまとめて行う実行ファイルを作成する必要があります。

参考：https://stackoverflow.com/questions/8324334/bundler-always-use-latest-revision-of-git-branch-in-gemfile