OmniAICreator/Qiita-1.07M huggingface dataset:
bashで、「ファイルが存在する場合は削除」する。


```bash
rm exist.txt 2> /dev/null
```

もし存在しないならこのコードは標準エラー出力になります。
そして標準エラー出力の2を/dev/nullに捨てます。

__参考__
https://qiita.com/i35_267/items/158cd20ed26f73a3d894
Goの環境変数を扱う(viper)

# はじめに
golangで環境設定ファイルを簡単にするライブラリとしてviperというものがあります。
今回はそのviperの使い方を簡単に紹介します

# viper
シンプルにviperを使ってみる
今回は構造体にマッピングしてそれを引き回して使うように実装を行います

``` :ソースツリー
.
├── config
│   ├── config.yaml
│   └── definition.go
└── main.go
```

```yaml:config.yaml
# 環境変数設定用のyamlファイル
user: 
  name: "kosuke"
```
本来はデータベースのユーザー名等を入れることが多いですが、今回は簡単に上記のような環境変数を設定します。


```go:definition.go
package config

import (
	"fmt"

	"github.com/spf13/viper"
)

// マッピング用の構造体
type Config struct {
	User User   `yaml:user`
}

type User struct {
	Name string `yaml:"name"`
}

func Load() (*Config, error) {
	viper.SetConfigName("config")   // 設定ファイル名を指定
	viper.SetConfigType("yaml")     // 設定ファイルの形式を指定
	viper.AddConfigPath("config/")  // ファイルのpathを指定

	err := viper.ReadInConfig()     // 設定ファイルを探索して読み取る
	if err != nil {            
		return nil, fmt.Errorf("設定ファイル読み込みエラー: %s \n", err)
	}

	var cfg Config

	err = viper.Unmarshal(&cfg)
	if err != nil {
		return nil, fmt.Errorf("unmarshal error: %s \n", err)
	}

	return &cfg, nil
}
```
`Load()`と言う関数の中で、環境変数のファイルを探し`Config`という構造体に環境変数をマッピングしていきます

```go:main.go
package main

import (
	"fmt"
	"viper-test/config"
)

func main() {
	cfg, err := config.Load()
	if err != nil {
		panic(err)
	}

	fmt.Println(cfg.User.Name)
}
```
今回は構造体にデータが入っていることを確かめるために`Config`の中身を表示しているだけですが、
本来であればこの構造体を引数に撮ってDBコネクション等を行っていきます。

```shell
$ go run main.go
kosuke
```

また、本番環境で運用等を行うときは外部から環境変数を受けとりたいということがあると思います。
その際は、、、

```golang:definition.go
package config

import (
	"fmt"

	"github.com/spf13/viper"
)

// マッピング用の構造体
type Config struct {
	User User   `yaml:user`
}

type User struct {
	Name string `yaml:"name"`
}

func Load() (*Config, error) {
	viper.SetConfigName("config")
	viper.SetConfigType("yaml")
	viper.AddConfigPath("config/")

    // ===========↓追記=============
    // 環境変数がすでに指定されてる場合はそちらを優先させる
	viper.AutomaticEnv()            

    // データ構造をキャメルケースに切り替える用の設定
	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
    // ===========↑ここまで=============

	err := viper.ReadInConfig()
	if err != nil {            
		return nil, fmt.Errorf("設定ファイル読み込みエラー: %s \n", err)
	}

	var cfg Config

	err = viper.Unmarshal(&cfg)
	if err != nil {
		return nil, fmt.Errorf("unmarshal error: %s \n", err)
	}

	return &cfg, nil
}
```

上記のような構文を使うことで環境変数が指定された時にはconfigファイルの値ではなく、
環境変数の値を参照することができます

```shell:
# 環境変数を与えて `go run`
$ USER_NAME=tarou go run main.go
tarou
```

# 終わりに
今回はとてもシンプルな使い方でしたが、環境変数を構造体にマッピングして引き回していくのは余計な処理を書かなくて済むのてとても楽かなと思います。
もちろんですが、、、秘匿情報の扱い（AWSのアクセスキーなど）には気をつけて使用していきたいところです。

# 参考資料
- viper(https://github.com/spf13/viper )
HUTロックの取得状態を確認

#目的
ホストユーティリティロック（HUTロック）の取得状態を確認する。

#コマンド
| 内容 | コマンド | 実行例 |
|:-:|:-:|:-:|
| cnsterm supervisor screenを起動  | cnsterm 6 |   |
| Show Locksユーティリティの起動  | start showlocks |   |
| 結果確認  | cnsterm 1  |   |
#実行例
###cnsterm supervisor screenを起動
```
TDExpress1620_Sles11:~ # cnsterm 6
Attempting to connect to CNS...Completed.
Hello

Input Supervisor Command:
> 
```
###Show Locksユーティリティの起動
```
> start showlocks
start showlocks

Started 'showlocks' in window 1
 at Sun Sep 27 12:15:29 2020
```

###showlocksの結果を確認(HUTロックがある場合)
```
TDExpress1620_Sles11:~ # cnsterm 1
Attempting to connect to CNS...Completed.
Hello
Host Utility locks which currently exist at both        
the data base level and the table level.                
 
     For each lock which is found, an entry will        
appear on your console which includes the following     
information:                                            
              --Data Base Name                          
              --Table Name (if applicable)              
              --HashId (if applicable)                  
              --User Name of user who placed lock       
              --Lock Mode                               
              --AMP Number                              
              --JobId of DSA Job (if applicable)        
              --PROXY LOCK (if applicable)              
 


SYSDBA.t1
    USER DBC   MODE Read     AMP All Amps

              --ShowLocks Processing Complete--
```

###showlocksの結果を確認(HUTロックがない場合)
「There are currently no host utility locks in the DBC」の表示

```
TDExpress1620_Sles11:~ # cnsterm 1
Attempting to connect to CNS...Completed.
Hello
 
     This program queries all AMPs and reports all      
Host Utility locks which currently exist at both        
the data base level and the table level.                
 
     For each lock which is found, an entry will        
appear on your console which includes the following     
information:                                            
              --Data Base Name                          
              --Table Name (if applicable)              
              --HashId (if applicable)                  
              --User Name of user who placed lock       
              --Lock Mode                               
              --AMP Number                              
              --JobId of DSA Job (if applicable)        
              --PROXY LOCK (if applicable)              
 


There are currently no host utility locks in the DBC

              --ShowLocks Processing Complete--
```

#参考
[Show Locks (showlocks) • Teradata Vantage™ - データベース ユーティリティ • リーダー • Teradataドキュメント](https://docs.teradata.com/reader/gjXRKe910A9hOE8O2C3Ufw/8KJD5vnOisELMvBs4bJVLw)
[]()
[]()
Swift：脱Realmする方法。

データベースを利用するためにRealmを使っていたのですが、よく考えるとRealmを使うほどでもない情報の保存しかしていないことに気づき、脱Realmしようと思い至りました。
そこで、Realmのデータを完全に削除する方法について調べると、[公式リファレンス](https://realm.io/jp/docs/swift/latest/#realm%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF)にて

```swift
let realmURL = Realm.Configuration.defaultConfiguration.fileURL!
  let realmURLs = [
  realmURL,
  realmURL.appendingPathExtension("lock"),
  realmURL.appendingPathExtension("note"),
  realmURL.appendingPathExtension("management")
]
let manager = NSFileManager.defaultManager()
for URL in realmURLs {
  do {
    try FileManager.default.removeItem(at: URL)
  } catch {
    // handle error
  }
}
```

こんな感じで、`Realm.Configuration.defaultConfiguration.fileURL`を用いてデータファイルを削除できるよって書いてありました。

つまり、**脱RealmするにはRealmが必要ってこと？？** ヤダー😭 となったのですが、要はこのURLをなんとか生成できればいいんでしょという方針で対策することにしました。

```swift
func destroyRealm() {
    guard let dir = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first
    else { return }
    let realmURLs: [URL] = [
        dir.appendingPathComponent("default.realm"),
        dir.appendingPathComponent("default.realm.lock"),
        dir.appendingPathComponent("default.realm.note"),
        dir.appendingPathComponent("default.realm.management")
    ]
    for url in realmURLs {
        try? FileManager.default.removeItem(at: url)
    }
}
```

これで、同等のURLを指定してファイルやディレクトリを削除することができるはずです。
Batch実行時などに、DBのコネクションが切れてしまう時の解決策


## Batch実行時に、コネクションが切れてしまうことが増えた

実際のエラー文とは違いますが、大体こんな感じのエラー文

```
ERROR apps.HogeMain - hoge.jdbi.hoge.exceptions.UnableToCreateStatementException: java.sql.SQLException: Connection has already been closed. [statement:"select * from hoges]
```

とはいえ、毎回コネクションが切れるわけではなく、たまーに切れるという程度

## 原因調査

### 結論

- DBコネクションを一定の時間使わないと、自動的にクローズする設定になっていた
- その条件に引っかからないように処理を短くして解決

### 当時の環境(ざっくり)

- `org.apache.tomcat.jdbc.pool` を使って、DBコネクションを貼っていた

### 一度DBに接続したものの切断されたと仮定

- エラーを見る限り、「コネクションが既にクローズされている」と出ていたので、一度接続したものの切断されたと仮定
- Batch実行時とエラー発生時のコネクション接続数の差異を確認
    - コネクションが減っている！
    - （気が向いたら、ここに何かエビデンスを貼る）
- 仮定は合ってそう

### 誰がコネクションをクローズ

- コネクションをクローズするのは、当時使っていた `org.apache.tomcat.jdbc.pool` ?
- `org.apache.tomcat.jdbc.pool` の設定を見直し
    - DBへのアクセスが無いと、自動的にDBコネクションのクローズする設定になっていた
- 具体的には以下の通り
    - `removeAbandoned` はクローズ漏れを防ぐために自動的にクローズするかしないかの設定
    - `removeAbandonedTimeout` はどれぐらいの時間コネクションを使わなかったら、自動的にクローズするかの時間設定

| Attribute | Description |
|---|---|
|removeAbandoned|(boolean) Flag to remove abandoned connections if they exceed the removeAbandonedTimeout. If set to true a connection is considered abandoned and eligible for removal if it has been in use longer than the removeAbandonedTimeout Setting this to true can recover db connections from applications that fail to close a connection. See also logAbandoned The default value is false.|
|removeAbandonedTimeout|(int) Timeout in seconds before an abandoned(in use) connection can be removed. The default value is 60 (60 seconds). The value should be set to the longest running query your applications might have.|

https://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html

## 解決策

- `removeAbandoned` を `false` にする
    - クローズ漏れを防げなくなるので、 `true` で動いていたシステムを `false` に変更するのはリスクがあるかも...変更するときは慎重に
- `removeAbandonedTimeout` の時間を長くする
    - The value should be set to the longest running query your applications might have. と書いてある通り、時間は上手く設定する必要があります。
- 処理時間を短くし、 `removeAbandonedTimeout` に引っかからないようにする

のどれか

## まとめ

- 今回は、 `tomcat.jdbc.pool` の解決策だったが、違う環境下であっても、既にクローズされているというエラー文が出た時は、コネクションの設定を見返すと解決出来るかもしれない
Nimでサウンドプログラミング（超入門レベル）

[Nim言語](https://nim-lang.org/)で、サウンドプログラミングをします。

- 参考書：[やさしい音と音楽のプログラミング　横山真男(著)、森北出版](https://www.morikita.co.jp/books/book/3330)

# 初めに

## 免責

- 筆者はNimプログラミングもサウンドプログラミングもド素人です

## 環境

- nim 1.2.6 (64bit)
- VC++2019
- Windows限定

## この記事のソースコード・dllが含まれるリポジトリ

https://github.com/mk2/nim-sound-study

# 「ド」の音を再生する

参考書によると、`mmsystem.h`というのを読み込んでうまいことコンパイルすれば、Windowsで自由に音が出せるようです。

Nimでは下記のライブラリがmmsystemのラッパーを提供してくれているので利用します（ライブラリ作者の方に感謝 :pray: ）

https://github.com/khchen/winim

`nimble install winim`で事前にインストールしておきます。

```nim
import math
import winim/inc/mmsystem

const SRATE = 44100
const PI = 3.14159286

proc main() =
  var hWave: HWAVEOUT
  var whdr: WAVEHDR
  var wfe: WAVEFORMATEX
  var b_time = 1.0
  let data_len = int32(SRATE * b_time)
  var bWave: cstring = cast[cstring](alloc0(data_len))
  var f0 = 440.0
  var amplitude = 40.0

  for count in 0..data_len:
    bWave[count] = char(amplitude * sin(2 * PI * f0 * float(count) / SRATE))

  wfe.wFormatTag = WAVE_FORMAT_PCM
  wfe.nChannels = 1
  wfe.nSamplesPerSec = SRATE
  wfe.nAvgBytesPerSec = SRATE
  wfe.wBitsPerSample = 8
  wfe.nBlockAlign = uint16(int(wfe.nChannels) * int(wfe.wBitsPerSample) / 8)

  waveOutOpen(hWave.addr, WAVE_MAPPER, wfe.addr, 0, 0, CALLBACK_NULL)

  whdr.lpData = bWave
  whdr.dwBufferLength = data_len
  whdr.dwFlags = WHDR_BEGINLOOP or WHDR_ENDLOOP
  whdr.dwLoops = 1
  
  waveOutPrepareHeader(hWave, whdr.addr, int32(sizeof(WAVEHDR)))
  waveOutWrite(hWave, whdr.addr, int32(sizeof(WAVEHDR)))

  echo("終了するには何かキーを押してください:")
  discard readLine(stdin)


when isMainModule:
  main()
```

これを`nim c -r`で実行すれば、ドの音が流れてきます（音量に注意）。

# MIDIファイルを作成する

参考書は[おーぷんMIDIぷろじぇくと](https://openmidiproject.osdn.jp/)が提供しているライブラリを利用しているので、それを何とかNimでも利用できるようにします。

必要なファイル

- [MIDIData.nim](https://github.com/mk2/nim-sound-study/blob/master/nimMidiDemo/src/MIDIData.nim)
- [MIDIData.dll (64bit)](https://github.com/mk2/nim-sound-study/blob/master/nimMidiDemo/src/MIDIData.dll)

MIDIData.nimはc2nimで作成しました。`MIDIData.h`から不要そうなマクロの定義を削除し、api定義のpragmaをいい感じに修正＆wchar_tをwinimの定義と合わせる感じで修正を行いました。

MIDIData.dllは配布されているdllが32bitのものだったので、VC++2019で64bitにコンパイルしなおして利用しました。

上記のファイルをダウンロードしたら、ダウンロードした場所に下記のソースコードを作成します。

```nim
import winim
import MIDIData

proc main() =
  let midiData: ptr MIDIData = MIDIData_Create(MIDIDATA_FORMAT0, 1, MIDIDATA_TPQNBASE, 120)
  let midiTrack: ptr MIDITrack = MIDIData_GetFirstTrack(midiData)
  MIDITrack_InsertTrackNameW(midiTrack, 0, &T"ドレミ")
  MIDITrack_InsertTempo(midiTrack, 0, clong(60000000 / 120))
  MIDITrack_InsertProgramChange(midiTrack, 0, 0, 1)

  # 音符
  MIDITrack_InsertNote(midiTrack, 0, 0, 60, 100, 120) # ド
  MIDITrack_InsertNote(midiTrack, 120, 0, 62, 100, 120) # レ
  MIDITrack_InsertNote(midiTrack, 240, 0, 64, 100, 120) # ミ

  MIDITrack_InsertEndofTrack(midiTrack, 360)
  MIDIData_SaveAsSMFW(midiData, &T"doremi.midi")
  MIDIData_Delete(midiData)

when isMainModule:
  main()
```

これを`nim c -r`で実行すると、`doremi.midi`ファイルが作成されます。Windows Media Playerで再生すれば、ピアノ音のドレミを聴くことができます。
C言語の学習3 (初心者)

# この記事について
この記事はC言語初学者がアウトプットの為に書いたものなので、大半の方には参考にならないと思います。暇な時でもよろしいので記事に誤りがある場合はご指摘いただけると助かります。

# 三項演算子
「if (条件) {} else {} 」というシンプルな条件分を１行で表現するものです。以下のように書きます。

```sample.c

#include <stdio.h>

/*プロトタイプ宣言*/
float getMax(float a, float b);

int main(void){
    float result;
    result = getMax(2.3, 5.2);
    printf("%f\n", result);

    return 0;
}

/*関数の定義*/
float getMax(float a, float b) {
/*(条件式) ? 条件が真の時の返り値 : 条件が偽の時の返り値*/
    return (a >= b) ? a : b;
/*下の条件文と同一の内容*/
    // if (a >= b) {
    //     return a;
    // } else {
    //     return b;
    // }
}

```

# 変数の有効範囲(スコープ)について
変数を使用する時はスコープに注意する必要があります。スコープとはその変数が使える範囲のことで、ある関数内で定義した変数は、その関数内でしか使用できません。

```sample.c

#include <stdio.h>

/*プロトタイプ宣言*/
void f(void);

int main(void){
    f();
    /*変数aは関数fの中で定義したものなので、ここでは使用できない*/
    printf("a:%d\n", a);
    return 0;
}

/*関数の定義*/
void f(void) {
    int a = 0; /*有効範囲が限定的な変数を"ローカル変数"という*/
    a++;
    printf("a:%d\n", a);
}

```

変数を関数の外で定義すれば問題なく動きます。

```sample.c

#include <stdio.h>

/*プロトタイプ宣言*/
void f(void);

int a = 0; /*グローバル変数という*/

int main(void){
    f();
    /*aは全関数で使用できる共通の変数(グローバル変数)なので、問題なく使用できる*/
    printf("a:%d\n", a);
    return 0;
}

/*関数の定義*/
void f(void) {
    a++;
    printf("a:%d\n", a);
}

```

# 変数の有効期限
ローカル変数は自動変数とも呼ばれており、関数(ブロック)内でしか値を保持しないので関数が呼び出される度にリセットされます。

```sample.c

#include <stdio.h>

/*プロトタイプ宣言*/
void f(void);

int main(void){
    f();
    f();
    f();
    return 0;
}

/*関数の定義*/
void f(void) {
    int a = 0; /*自動変数とも呼ばれる*/
    a++;
    printf("a:%d\n", a);
}

```
```c
/*ターミナルの結果*/
a:1
a:1
a:1
/*呼び出される度にリセットされるので全て1になる*/
```

プログラムが終了するまで値を保持していて欲しい場合、自動変数を静的変数に変えてあげれば問題ありません。

```sample.c

#include <stdio.h>

/*プロトタイプ宣言*/
void f(void);

int main(void){
    f();
    f();
    f();
    return 0;
}

/*関数の定義*/
void f(void) {
    static int a = 0; /*変数の型の前にstaticと付けると静的変数になる*/
    a++;
    printf("a:%d\n", a);
}

```
```c
/*ターミナルの結果*/
a:1
a:2
a:3
/*値が保持されているので関数を呼び出す度に値が高くなる*/
```

静的変数を使用する時に注意する点があります。staticと宣言された変数は、2回目以降は無視されます。以下のように書いてしまうと変数が毎回リセットされます。

```sample.c

void f(void) {
    static int; /*ここだけが２回目以降無視される*/
    a = 0; /*引き続き毎回リセットされる*/
    a++;
    printf("a:%d\n", a);
}

```

# 配列
配列とは同一の型のデータがい1列に並べられたデータの集合体で、配列中の各データは要素と呼ばれ、要素には番号が割り振られています。配列の定義方法は以下のようにやります。

```sample.c

#include <stdio.h>


int main(void){

    int sales[3];

    sales[0] = 200;
    sales[1] = 400;
    sales[2] = 300;
    /*このような書き方も可能 ([]の要素数も省略可能)*/
    int sales2[] = {200, 400, 300}

    /*400と表示される*/
    printf("%d\n", sales[1]);
    return 0;
}

```

# 文字列
C言語では文字列は「文字の配列」という扱いなので、以下のように書きます。

```sample.c

#include <stdio.h>


int main(void){
    /*文字列はchar型の配列 終端には\0と明記する*/
    char s[] = {'a', 'b', 'c', '\0'};
    /*以下のような書き方でもOK*/
    char s1[] = "abc";
    /*終端も含めるので要素数は4*/
    char s2[4] = "abc";

    /*文字列内の1文字を表示*/
    printf("%c\n", s[1]);
    return 0;
}

```

# 感想
これまでのC言語の学習は、ある程他の言語との共通点があるのでスムーズに進んだが、今回からプロトタイプ宣言や静的変数といった新しい概念が出てきたので注意して学習を進めていきたい。
数据通信基本控制规程

ベーシック手順は、ISOが標準化した伝送制御手順です。データリンク制御はコネクション方式になります。文字伝送向けの伝送制御手順で、データリンク確立手順の異なる2つの方法があります。

数据通信基本控制规程，是ISO标准化的传输控制步骤。数据连接控制为竞争方式。在面向文字传送的传送控制步骤里，有不同的数据连接确立步骤的2种方法。

コンテンション方式

各ホストがメッセージの送信権を早い者勝ちで取り合う方法です。

ポーリング／セレクティング方式

主端末である制御局がそれにつながる複数の端末である従属局に対して送信するデータの有無を順番に問い合わせる方法です。
Mac HomebrewでPHPをインストールする

## 〜宣伝〜

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

β版リリース記念キャンペーン中です！

10名様限定、抽選でお好きな技術本1冊プレゼント！
🎉当選者にはメッセージ差し上げます(送付の際に住所はお聞きしません)
詳しくはこちらから↓

https://x.com/dokupro01/status/1796837336145436846
:::
https://dokupro.dev/

# 目的

- MacにHomebrewを使ってPHPを導入する方法をまとめる

# 実施環境

- ハードウェア環境

| 項目 | 情報 |
| --- | --- |
| OS | macOS Catalina(10.15.5) |
| ハードウェア | MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) |
| プロセッサ | 2 GHz クアッドコアIntel Core i5 |
| メモリ | 32 GB 3733 MHz LPDDR4 |
| グラフィックス | Intel Iris Plus Graphics 1536 MB |

- ソフトウェア環境

| 項目 | 情報 | 備考 |
| --- | --- | --- |
| Homebrew バージョン | 7.4.8 | Homwbrewを用いて導入 |

# 前提条件

- Homebrewが導入され`$ brew`コマンドを実行できること。

# 前提情報

- 本記事ではPHP 7.4をインストールするがインストール時のバージョン指定で他のバージョンもインストール可能である。

# 詳細

1. 下記コマンドを実行してHomebrewを最新状態にする。

    ```shell
    brew upgrade
    ```
1. 下記コマンドを実行してPHP 7.4をインストールする。

    ```shell
    brew install php@7.4
    ```
1. 下記コマンドを実行してインストールされたPHPのバージョンを確認する。

    ```shell
    php -v
    ```
ServerlessFramework(AWS)でstage毎にS3などのリソースを別に作る方法

provider > stage: `${opt:stage, self:custom.defaultStage}`
custom > defaultStage: `dev` 
custom > resourcePrefix : `${self:provider.stage}`を使った値
と設定して
BucketNameを `${self:custom.resourcePrefix}-resource`とする

```yml:serverles..yml
service: serverless-sample

frameworkVersion: '2'

provider:
  name: aws
  runtime: python3.8
  stage: ${opt:stage, self:custom.defaultStage} 
  region: ${opt:provider, self:custom.defaultRegion}

custom:
  author: iwato
  defaultStage: dev
  defaultRegion: ap-northeast-1
  resourcePrefix: ${self:custom.author}-${self:service}-${self:provider.stage}
  environment:
    dev: # 開発環境
      key: dev-value
    test: # テスト環境
      key: test-value
    staging: # 検証環境
      key: staging-value
    prod: # 本番環境
      prod: prod-value

resources:
  Resources:
    NewResource:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: ${self:custom.resourcePrefix}-resource
  Outputs:
     NewOutput:
       Description: "Description for the output"
       Value: "Some output value"
ServerlessFrameworkでfunction毎にデプロイするファイルを指定する方法

1. package > individually を`true`に設定し、個別のfunctionのデプロイ対象設定を有効化
1. package > excelude で`./**(全ファイル)`　を設定し、全ファイルをデプロイ対象から除外
1. functions > 個別のfunction > package > include でデプロイしたいファイルを指定
1. zipファイルなどをデプロイしたい場合は functions > 個別のfunction > package > artifact で指定

```yml:serverless.yml
service: serverless-sample

frameworkVersion: '2'

package:
  individually: true # 1
  exclude: # 2
    - ./**

functions:
  hello:
    handler: src/hello/handler.hello
    events:
      - http:
          path: hello
          method: get
    package: # 3
      include:
        - src/hello/**
  hello2: 
    handler: src/hello2/handler.hello2
    events:
      - http:
          path: hello2
          method: get
    package: # 3
      artifact: dist/hello2.zip
```

# 参考
公式　https://www.serverless.com/framework/docs/providers/aws/guide/packaging/
お手頃・高機能スライダーはSwiper使っておけばいい

# 概要
実装をする中で実装可能だけど、そこに時間あんまり費やしたくないなぁって時結構ありますよね。
画像のスライダー機能の実装でそのような状況になりました。
自作実装もできるけど。。アニメーションを場面ごと切り替えたりするのが結構手間＞＜
そこで、よく使われているライブラリを探していたところ`Swiper`を見つけて実装がとても楽だったので共有したいと思います。

### 実装例
スライダーで使うcssをimportする

```tsx:index.tsx
import "swiper/swiper.scss";
import 'swiper/components/pagination/pagination.scss';
```

スライダー用のコンポーネントを実装する

```tsx:SwiperComponent.tsx
import * as React from 'react';
import SwiperCore, { Pagination, Autoplay } from "swiper";
import { Swiper, SwiperSlide } from "swiper/react";

SwiperCore.use([Pagination, Autoplay]);

interface Props {
  imageData: Array<string>;
  // trueで自動でスライダーアニメーションが動く
  isAuto: boolean;
  // trueでpaginationクリックでスライダーアニメーションが動く
  clickable: boolean
}

const SwiperComponent: React.FC<Props> = (props) => {
  return (
    <div>
      <Swiper pagination={{ clickable: props.clickable }} autoplay={props.isAuto}>
        {props.imageData.map((imageSrc, i) => {
          return (
            <SwiperSlide key={`${imageSrc}${i}`}>
              <img key={`${imageSrc}`} src={imageSrc} />
            </SwiperSlide>
          );
        })}
      </Swiper>
    </div>
  );
};
export default SwiperComponent;

```

これだけ！！


あとはスライダー用のコンポーネントをスライダー実装したい箇所に組み込んであげるだけ！

```tsx
<SwiperComponent imageData={["image/image1.jpg", "image/image2.jpg"]} isAuto={true} clickable={false} />
```

これで画像スライダーの完成！
とても簡単。

他にも便利な機能が山ほどあります。
スライドアニメーションもたくさんありますので色々と試してみるといいかもです。

## まとめ
今回は一番シンプルなスライダーを`Swiper`を使って簡単な実装例と共に紹介しました。
ちょっと実装に時間かかりそうなところがめちゃくちゃシンプルに実装できましたね。
Vueにも対応しているみたい

※注意点
ライブラリは便利な反面、何気なく使ってしまうと危険な時があります。
急に開発元が開発をやめたり、特定のバージョンや環境でしか動かなこともザラにあります。
ライブラリを使うときはドキュメントをしっかり読み、ライセンスの確認、使っているユーザーの数(githubスターの数)
さらには開発状況などを確認した上で慎重に使うことをお勧めします。
個人で試す、勉強で使う場合は問題ないと思いますが、
仕事として今後世に出ていくようなサービスで使う場合はその辺りは意識してライブラリは使っていくといいと思います。

## 参照
[Swiper 公式](https://swiperjs.com/get-started/)
[Swiper React](https://swiperjs.com/react/)
[Swiper Vue](https://swiperjs.com/vue/)
[Swiper Demos](https://swiperjs.com/demos/)
WindowsとLinuxのディレクトリの違い

#パスの区切り文字

- Windowsでは **￥** が使われるが、Linuxでは **/** を用いる。

#ディレクトリ構造

- システム全体で2台の物理ディスクがある場合、Windowsでは2つのディレクトリツリーができるが、Linuxでは何台のディスクがあろうが、**`システム全体で1つのディレクトリツリーしか持たない`**のが大きな違いである。このため複数ディスクがある場合、Linuxではルートディレクトリ配下のどこかに、ディスクをディレクトリとしてくっつける手法（この操作を「マウント」と呼ぶ）を取っている。

#####※ ディストリビューションによってディレクトリ構造に若干の違いはある。
Flutterでタブ画面を作る。

# 実装イメージ

<img width="300px" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/738919/29405f24-def8-c58f-c22b-6eaa84b4fec6.gif">


# 実装方法

## タブの小画面を準備する

真ん中に文字があるだけの画面です。
これを2つ（FirstPage、SecondPage）作成します。


```dart:FirstPage.dart
import 'package:flutter/material.dart';

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.orange,
      body: Center(
        child: Text(
          "First Page",
          style: TextStyle(
            fontSize: 20
          ),
        ),
      ),
    );
  }
}
```

## タブ画面を作成します。

```dart:TabPage.dart
import 'package:flutter/material.dart';
import 'package:flutter_app/FirstPage.dart';
import 'package:flutter_app/SecondPage.dart';

class TabPage extends StatelessWidget {

  final _tab = <Tab> [
    Tab( text:'First', icon: Icon(Icons.directions_car)),
    Tab( text:'Second', icon: Icon(Icons.directions_bike)),
  ];

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: _tab.length,
      child: Scaffold(
        appBar: AppBar(
          title: Text("Tab Page"),
          bottom: TabBar(
            tabs: _tab,
          ),
        ),
        body: TabBarView(
          children: <Widget>[
            FirstPage(),
            SecondPage(),
          ],
        ),
      ),
    );
  }
}
```

### ポイント

```dart
final _tab = <Tab> [
  Tab( text:'First', icon: Icon(Icons.directions_car)),
  Tab( text:'Second', icon: Icon(Icons.directions_bike)),
];
```

ここでタブの要素を定義しています。

```dart
@override
Widget build(BuildContext context) {
  return DefaultTabController(
    length: _tab.length,
    child: Scaffold(
      appBar: AppBar(
        title: Text("Tab Page"),
        bottom: TabBar(
          tabs: _tab,
        ),
      ),
      body: TabBarView(
        children: <Widget>[
          FirstPage(),
          SecondPage(),
        ],
      ),
    ),
  );
}
```

`DefaultTabController`を初期化し、`length`にタブ数を、`child`にタブバーの要素と画面を設定しています。

## Main.dartに設定

最後に`Main.dart`に設定して完了です。

```dart:Main.dart
import 'package:flutter/material.dart';
import 'package:flutter_app/TabPage.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: TabPage(),
    );
  }
}
```
## 参考

https://flutter.ctrnost.com/layout/header/tab/
【Laravel】hasOne

#リレーション
##主キーと外部キー
主キーはテーブルに一つ
外部キーはテーブルに複数
主キーと外部キーによりリレーションしている
#hasOne
1体1のリレーション
一つの外部キーしか取得できない

##準備
モデルクラスにテーブルの単数形としてメソッドを用意して以下のように書く

```php
function table(){
  return $this->hasOne('App\Table');
}
```

コントローラからの呼び出しの際には以下のようにする

```php
    function test(){
        $items=Table::all();
        dd(Member::find(10)->table);
    }
```

メソッドだから

```php
//こうじゃなくて
dd(Member::find(10)->table);
//こうじゃないの？
dd(Member::find(10)->table());
```
と悩んだが、**`()`はつけないことに注意**

`Member::find(10)->table`のなかにTableモデルのインスタンスが入る
pythonでdiscordボット raspberry pi zero で[備忘録]

python install

[How to install Python 3 - Install Python 3 | Raspberry Pi Projects](https://projects.raspberrypi.org/en/projects/generic-python-install-python3)

```shell_session
# sudo apt update
# sudo apt install python3 idle3
```

and pip
[Installing Python packages - Raspberry Pi Documentation](https://www.raspberrypi.org/documentation/linux/software/python.md)

```
sudo apt install python3-pip
```

あとは写経
[Pythonで簡単なDiscord Botの作り方 - Qiita](https://qiita.com/PinappleHunter/items/af4ccdbb04727437477f)

---

※気をつけるところ

- BOTページのBuild-A-BotのところのTOKENを使うこと。

General InformationのSecretは違うものだから注意。
英語を習っていない小学１年生でも書ける、l(エル)メソッド

#l(エル)メソッドとは
　時刻や日時を表すときに使うメソッド。指定した現地時間に対応できる。SNSで「何月何日の何時に投稿した」なんてときに使う。テーブルのcreated_atカラムを表示したいときなどに使う。
##現地時間を指定する方法
###ステップ１

```ruby:config/application.rb
class Application < Rails::Application
  config.i18n.default_locale = :ja #日本の場合
  config.time_zone = 'Tokyo' #東京の場合
end
```
Railsの全ての環境設定のファイルに、上記の記述をする。
###ステップ２
ja.ymlファイルを作成する。

```ruby:config/locales/ja.yml
ja:
  time:
    formats:
      default: "%Y/%m/%d %H:%M:%S"
```

###lメソッドの使い方
　上記の２つの設定をしたら、時刻の入ったカラムを表示させるメソッドの前に「l」と入れるだけ。
ex) 拡張子が.html.erbなら

```Ruby
<%= l name.created_at %> #2020/9/27/ 23:32:09　と表示される
```

##ポイント

+ [x]  configディレクトリのapplicationファイルに現地時間の設定をする。
+ [x]  localesディレクトリにja.ymlファイルを作成し、時間の表示方法を指定する。
+ [x]  使う時は、メソッドの前に「l」を記述する。

##最後に
　投稿機能を実装するときには必須のメソッドとなりそう。
暗号と認証

#【暗号と認証】

情報セキュリティの観点からもすごく重要な知識だと思います。
苦手に感じてしまっているので、克服するためにまとめました。

##公開鍵暗号方式

暗号と復号をそれぞれ別々の鍵を使う。

前提条件
・１人につき、ペアである鍵（公開鍵、秘密鍵）を使う。
・公開鍵は、不特定多数の利用者に公開。秘密鍵は、誰にも渡さずに秘密扱いにする。
・公開鍵を使って、平文を暗号化した暗号文は、ペアの秘密鍵でしか復号できない。
→これを暗号化で使う。
・秘密鍵を使って、平文を暗号化した暗号文は、ペアである公開鍵でしか復号できない。
→これをディジタル署名で使う。

暗号化手順
①送信者が受信者の公開鍵で、平文を暗号化。
　暗号文を受信者に送る。
②受信者が受信者の秘密鍵で、暗号文を復号。
　平文を取り出す。

※盗聴なしを確かめられる。

##ハイブリッド暗号

公開鍵暗号方式の短所を、共通鍵暗号方式と組み合わせ補う。
→平文を共通鍵で暗号化し、その共通鍵を公開鍵暗号方式で暗号化する。

暗号化手順
①送信者は、平文を共通鍵を使って暗号化。暗号文を作る。
　共通鍵は、自動的に生成したものを使う。
②送信者は、その共通鍵自体を平文とし、受信者の公開鍵を使って暗号化し、暗号化した共通鍵を作る。
③送信者は、①の暗号文、②の暗号化した共通鍵を、受信者に送る。
④受信者は、受信者の秘密鍵を使って、②の暗号化した鍵を復号し、共通鍵を取り出す。
⑤受信者は、④の共通鍵を使って、①の暗号文を復号し、平文を取り出す。

##ディジタル署名（電子署名）

公開鍵暗号方式の暗号化の逆をする。
なりすまし、改ざんなしを確かめられる。

盗聴なしは確かめられない。

※機密性、真正性、完全性を維持する。

##・重要！！　ディジタル署名と暗号化の違いの覚え方。

防ぐものと秘密鍵に着目するとよいという。

・暗号化が防ぐもの、第三者による復号。
→正規の受信者しか復号できない、受信者の秘密鍵で復号する。
・ディジタル署名が防ぐもの、第三者によるなりすまし。
→正規の送信者しか暗号化できない、送信者の秘密鍵で暗号化する。
複数の一次元配列を連結して１つの一次元配列にする関数

##はじめに

エクセルVBAには、配列を連結し１つの配列にする関数がありません。
ということで、今回、複数の一次元配列を連結し、１つの一次元配列にする関数を作成しました。

##コード

まずは結論から。
コードを記載します。関数名はmerge1DArrayとしました。
引数として、一次元配列の配列を受け取ります。

```VB

Function merge1DArray(arr() As Variant) As Variant
Dim mergedArray() As Variant
Dim i As Long, j As Long, index As Long: index = 0

For i = LBound(arr) To UBound(arr)

  If i = UBound(arr) Then
    ReDim Preserve mergedArray(index + UBound(arr(i)) - LBound(arr(i)))
  Else
    ReDim Preserve mergedArray(index + UBound(arr(i)) - LBound(arr(i)) + 1)
  End If

  For j = LBound(arr(i)) To UBound(arr(i))
    mergedArray(j + index) = arr(i)(j)
  Next j
  
  index = index + UBound(arr(i)) - LBound(arr(i)) + 1

Next i

merge1DArray = mergedArray

End Function

```
<br>
確かめてみます。


```vb

Sub test()

Dim arr1(3) As String
Dim arr2(1) As String
Dim arr3(2) As String
Dim arr(2) As Variant
Dim mergedArray() As Variant
Dim i As Integer

arr1(0) = "あいうえお"
arr1(1) = "かきくけこ"
arr1(2) = "さしすせそ"
arr1(3) = "たちつてと"

arr2(0) = "なにぬねの"
arr2(1) = "はひふへほ"

arr3(0) = "まみむめも"
arr3(1) = "やゆよ"
arr3(2) = "らりるれろ"


arr(0) = arr1
arr(1) = arr2
arr(2) = arr3


mergedArray = merge1DArray(arr)

For i = LBound(mergedArray) To UBound(mergedArray)
  MsgBox mergedArray(i)
Next i

End Sub


```

##解説

まず、動的な配列：mergedArray()を用意します。
この関数は、引数として受け取った配列の配列：arr()の最初のインデックスから最後のインデックスまでループを行い(カウンター変数i)、それぞれの要素(配列)をmergedArray()に格納していきます。

このために、Redim Preserveステートメントを使って、すでにmergedArray()に格納された要素は保持しながらarr(i)の要素数分だけmergedArrray()の要素数を確保します。
これが、If文を使った条件分岐になっているのは、mergedArray()の最初のインデックスが0から始まるため、実は要素数が1つ多い状態でループが進んでいってしまうのですが、ループの最後のiになったときに、
ReDim Preserve mergedArray(index + UBound(arr(i)) - LBound(arr(i)))
と「 + 1 」をなくすことでで、帳尻を合わせています。

実際にmergedArrayに要素を格納していく操作が、カウンター変数jを使ったループです。

indexにarr(i)の要素数を足して次のループに移ります。
PythonでYouTubeのコメントを取得

YouTubeのAPIを使って、動画のコメントを取得します。YouTubeのAPIについては割愛します。

## やり方

```python:getYouTubeComments.py
import requests
import json

URL = 'https://www.googleapis.com/youtube/v3/'
# ここにAPI KEYを入力
API_KEY = 'API KEYを入力'

def print_video_comment(video_id, next_page_token):
  params = {
    'key': API_KEY,
    'part': 'snippet',
    'videoId': video_id,
    'order': 'relevance',
    'textFormat': 'plaintext',
    'maxResults': 100,
  }
  if next_page_token is not None:
    params['pageToken'] = next_page_token
  response = requests.get(URL + 'commentThreads', params=params)
  resource = response.json()

  for comment_info in resource['items']:
    # コメント
    text = comment_info['snippet']['topLevelComment']['snippet']['textDisplay']
    # グッド数
    like_cnt = comment_info['snippet']['topLevelComment']['snippet']['likeCount']
    # 返信数
    reply_cnt = comment_info['snippet']['totalReplyCount']

    print('{}\t{}\t{}'.format(text.replace('\n', ' '), like_cnt, reply_cnt))
  
  if 'nextPageToken' in resource:
    print_video_comment(video_id, resource["nextPageToken"])

# ここにVideo IDを入力
video_id = 'Video IDを入力'
print_video_comment(video_id, None)
```


## 実行結果の例
[日本相撲協会公式チャンネル「高崎親方の料理の鉄人～出羽海部屋ちゃんこ～」](https://www.youtube.com/watch?v=RqOgKHc5blc)の動画コメントを取得すると、下記のようになります。Google Colaboratoryで実行しています。

出力結果は、コメント、グッド数、返信数の順です。

![スクリーンショット 2020-09-27 23.29.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48375/1f6b5b3c-d7b2-0277-6086-6364ddba6d8d.png)


## 参考
下記の記事を参考にしました。ありがとうございました。
- https://qiita.com/Doarakko/items/191209bf14cf5d76fa6f
Vagrant localとファイル共有 synced_folder する際の共有ファイルpermissionを逐一変更できるようにする





# 起こったこと

`Vagrant` でsynced_folder でファイル共有すると
共有のしかたによっては
box 内で共有フォルダ(`synced_folder`) 以下での`permission` を任意で変更できない。

(アプリによっては設定ファイル/データ保管dir などの `permission` を気にするものもあるから
`chmod` とかで逐一変更できるようにしたい)



# 解決法

以下のように type: を指定せず(default は"virtualbox")
nft: true も指定せず
owner: を指定すれば、box内でも変更できるよう

``` :./Vagrantfile
Vagrant.configure("2") do |config|
...

  config.vm.synced_folder "../shared/web", "/var/www/html",
    #type: "rsync",
    id: "web", # unique ID
    #nfs: true
    owner: "vagrant", group: "www-data"
...
end
```

で `vagrant reload` で再起動。

# 参考

https://stackoverflow.com/questions/13169154/cannot-change-permissions-of-folders-within-vagrant-home-folder

https://stackoverflow.com/questions/35807568/vagrant-synced-folder-permissions

https://stackoverflow.com/questions/23161697/changing-permissions-on-vagrant
LPIC202に合格した勉強法

＠Qiita初投稿記事

LPIC202に合格したので、備忘録として勉強法を投稿します。Ping-tに投稿しようと思いましたが、今回Ping-tを一切使用しなかったため、こちらに投稿します。※自身の主観も含まれた記事ではありますが、何卒ご容赦下さい。

<b>取得しようとした目的<b>

サーバー構築などが必要となる場面に必要な知識は、レベル2の取得が必須になると考えたためです。特にLPIC202ではApache,BIND,Nginx,NFS,Sambaなど、Linuxサーバーの幅広い知識が習得できると考え受験しました。

<b>学習時間<b>

約２週間

<b>使用したテキスト<b>

・白本 (似たような問題が出題されます)
・小豆本 （辞書代わりに使いました）

<b>主な学習方法<b>

・小豆本を1周読み、サラッと雰囲気を理解します

・白本を解きます(私の場合、全3回解きました。3回目でようやく全単元(模試含む)90％から80％に近い解答率となりました)

  ※1周目は間違いだらけで苦痛でしょうが、気にせず解いていきましょう

  ※2周目からは解説を全て精読し、重要・理解できない箇所には蛍光ペンでマーキングをしましょう

   (不明点はググり、小豆本を辞書代わりに確認し、理解できない項目に内容を転記していきましょう)

  ※白本内の<b>[参考]</b><b>[合わせてチェック]</b>などに付箋を張り、その箇所を何回か読みこみましょう

  ※白本内の記述問題に出題される設定ファイルは全て押さましょう

  (解説内の細かい設定内容までは覚える必要はありません(覚えるのは時間の無駄))

・LPIC202の出題範囲をスマホのメモ帳に貼り、不明点をググって意味を書き、通勤時間や休み時間などのスキマ時間に読みましょう

・小豆本の暗記項目はスマホのメモ帳に貼り、不明点をググって、メモ帳に転記し、スキマ時間に読みましょう

・LPIC202合格体験記を読み、出題しそうなポイントを押さえておきましょう

・蛍光ペンでマーキングした重要項目、何回も間違えてる箇所を重点的に読み返しましょう

・不明点は小豆本を読み返し、意味を咀嚼してテキストに転記しましょう

<b>ポイント1-理解までに時間がかかる<b>

・最初はサーバーの利用用途から不明なため、出題単元の大枠を理解する上でも、「Sambaは何のために使うのか、NFSは何のために使うのか」などを理解しておきましょう。

・細かい設定内容に関してもググって「何のために使うのか」を重視し、用語の意味を調べた上で、自分で理解できる言葉に置き換えて理解するようにしましょう

・図を書いて全体像を理解しましょう

　-DNSの一連の問い合わせの仕組み
　-netfilterのルーティング仕組み
　-メールの配送方法(MTA/MDA/MUA)

<b>ポイント2-出題範囲からズレた勉強はしない<b>

・出題範囲を何回も読み返し、理解不明な点はググって調べましょう

<b>ポイント3-合格体験記はよく読みましょう<b>

・重箱を突く問題が出る、合格体験記で噂になっているような知識は出ます
　
  -fail2ban
  -グルーレコードなど

<b>最後に<b>

LPIC202はLPIC資格の中でも暗記項目が多く、最難関と言われることが多いですが、
多少なりともこの記事が役に立ち、皆様が合格されることを祈ります。
MySQL Workbench 接続情報ファイル引越し

# 概要
新しいMacを購入したときにMySQL Workbenchの**接続情報を全てそのままコピーした**ときのメモ。すんなり移行できたので一から設定していくのめんどいって人におすすめ。
![screenshot 2020-09-27 23.20.06−2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11087/88786f24-0279-977d-34d2-c5e1ce9b281b.jpeg)


## 自分のPC環境
### pc-A (引越し前)
- Mac Book Pro Retina(2015)
- OS : macOS Mojave
- MySQL Workbench : version 8.0.19

### pc-B (引越し先)
- Mac mini (2018)
- OS : macOS Catalina
- MySQL Workbench : version 8.0.21

# 手順
## 1. 準備
- pc-Aとpc-Bの接続
  - 同ローカルネットワーク上のLANに接続させる
  - pc-Aをサーバーとしてpc-Bから接続
  - memo: 
    - 直接接続しなくても他にいくらでもファイルをコピーする方法はあるので自分の好きな方法でOK.
- pc-BにMySQL Workbenchのインストール
  - [MySQL Community Downloads](https://dev.mysql.com/downloads/workbench/)から最新版を入手
  - 一度起動して終了しておく

## 2. 設定ファイルのコピー
- pc-Aの下記の場所からpc-Bの同じ場所にファイルをコピー。
  - `/Users/username/Library/Application\ Support/MySQL/Workbench`
  - (usernameの部分は適宜読み替え)
  - 全ファイル上書きで問題なし
  - 鍵の場所やユーザー名が変わってる時には`connections.xml`をメモ帳系ソフトでいじってあげれば簡単。

### 注意：
- MySQL Workbenchを起動したままコピーするとソフト終了時に上書きされてしまうので必ず終了した状態でコピーする
- DBのパスワードはこの手順でコピーできない。接続時にキーチェーンに見つからないとポップアップが出るのでそこで再入力すれば問題なし。

### （参考）MySQLWorkbench インストール＆初起動直後の設定ファイル

```
Library
├── Application Support
│ (省略)
│   ├── MySQL
│   │   └── Workbench
│   │       ├── libraries
│   │       ├── log
│   │       │   └── wb.log
│   │       ├── modules
│   │       ├── scripts
│   │       ├── server_instances.xml
│   │       └── snippets
│   │           ├── DB\ Management.txt
│   │           ├── SQL\ DDL\ Statements.txt
│   │           └── SQL\ DML\ Statements.txt
```
Raspberry Pi で SwitchBot 温湿度計の値をとる

# 目的
掲題の通りです。以下の記事を存分に参考にしています。ありがとうございます。コードがほぼ同じなのでご指摘をいただいた場合は即削除します。

> SwitchBot温湿度計の値をRaspberryPiでロギング
> https://qiita.com/c60evaporator/items/7c3156a6bbb7c6c59052

私の環境で一部動かない箇所がありましたので、私的なログとして動作したコードを置いておきます。

# 環境

* Raspberry Pi 4 Model B Rev 1.2
* SwitchBot 温湿度計 (https://www.switchbot.jp/meter)

|![IMG_5275.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82774/c92d8647-24b5-dc6d-befc-51f23989898c.jpeg)|
|---|

# SwitchBot 温湿度計の Mac Address を確認
スマートフォンのアプリケーションから確認できます。

|![IMG_5276.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82774/b84656ce-ae50-e73d-dbec-ee906a3f621e.png)|![IMG_5277.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82774/bec0f0c9-53f6-0a60-3d08-6f4c25ff0ff2.png)|
|---|---|

# センサがデータを飛ばしているか確認
```bash
pi@raspberrypi:~ $ sudo hcitool lescan | grep EB:F6:31:8C:1F:E9
EB:F6:31:8C:1F:E9 (unknown)
EB:F6:31:8C:1F:E9 (unknown)
EB:F6:31:8C:1F:E9 (unknown)
```

このコマンドは何？

```
NAME
       hcitool - configure Bluetooth connections

DESCRIPTION
       hcitool  is  used to configure Bluetooth connections and send some spe-
       cial command to Bluetooth devices. If no command is given,  or  if  the
       option -h is used, hcitool prints some usage information and exits.

```

# Python で値を取得
[bluepy](https://github.com/IanHarvey/bluepy) を利用します。リンク先のURLを参考に。

```
pi@raspberrypi:~ $ sudo install libglib2.0-dev
pi@raspberrypi:~ $ pip3 install bluepy
pi@raspberrypi:~ $ cd .local/lib/python3.7/site-packages/bluepy
pi@raspberrypi:~ $ sudo setcap 'cap_net_raw,cap_net_admin+eip' bluepy-helper
```

# Python スクリプト

```python:switchbot.py
from bluepy import btle
import struct

class SwitchbotScanDelegate(btle.DefaultDelegate):
    def __init__(self, macaddr):
        btle.DefaultDelegate.__init__(self)
        self.sensorValue = None
        self.macaddr = macaddr

    def handleDiscovery(self, dev, isNewDev, isNewData):
        if dev.addr == self.macaddr:
            for (adtype, desc, value) in dev.getScanData():  
                if desc == '16b Service Data':
                    self._decodeSensorData(value)

    def _decodeSensorData(self, valueStr):
        valueBinary = bytes.fromhex(valueStr[4:])
        batt = valueBinary[2] & 0b01111111
        isTemperatureAboveFreezing = valueBinary[4] & 0b10000000
        temp = ( valueBinary[3] & 0b00001111 ) / 10 + ( valueBinary[4] & 0b01111111 )
        if not isTemperatureAboveFreezing:
            temp = -temp
        humid = valueBinary[5] & 0b01111111
        self.sensorValue = {
            'SensorType': 'SwitchBot',
            'Temperature': temp,
            'Humidity': humid,
            'BatteryVoltage': batt
        }
```

```python:main.py
from bluepy import btle
from switchbot import SwitchbotScanDelegate

scanner = btle.Scanner().withDelegate(SwitchbotScanDelegate('eb:f6:31:8c:1f:e9'))
scanner.scan(5.0)
print(scanner.delegate.sensorValue)
```

```bash
pi@raspberrypi:~ $ python3 ./main.py
{'SensorType': 'SwitchBot', 'Temperature': 25.2, 'Humidity': 68, 'BatteryVoltage': 100}
```
［Android］Coil の Video Frames を使ってみる

# はじめに

Coil の Video Frames を使うことで動画ファイルのあるフレーム画像を ImageView に表示できるらしい。今回はどのような感じで取得できるのか試してみたいと思う。

# 準備

Video Frames を使う場合には Core ライブラリに加えて Video Frames ライブラリを依存関係に追加する必要があります。次のように build.gradle に追記して Video Frames ライブラリを依存関係として追加します。

```groovy
dependencies {
      ︙
    implementation "io.coil-kt:coil:1.0.0"
    implementation "io.coil-kt:coil-video:1.0.0"
      ︙
}
```

# 実装

## raw フォルダに動画を格納する

動画ファイルが必要になるので次のように raw フォルダを作成し格納しておきます。
(対応している動画ファイルの拡張子→[サポートされているメディア形式](https://developer.android.com/guide/topics/media/media-formats#video-formats))

[![Image from Gyazo](https://i.gyazo.com/76f7e6451f96c64e42379fd0c02d90c4.png)](https://gyazo.com/76f7e6451f96c64e42379fd0c02d90c4)
[![Image from Gyazo](https://i.gyazo.com/5f8d6a50628a5de598358fc7f5329d4a.gif)](https://gyazo.com/5f8d6a50628a5de598358fc7f5329d4a)

## raw フォルダから動画ファイルを読み込む

まずは raw フォルダに格納したファイルの URL を生成し、load にてその url を読み込んでやります。あとは videoFrameMillis にて動画のどの秒数のフレームを表示するか指定してやれば動作します。

下記のサンプルだと fetcher で VideoFrameUriFetcher を指定してやっています。本来であれば Coil 側で動画ファイルであるか自動的に判定してくれるので指定する必要はないみたいなのですが URL を指定した場合だと上手く動作しないので追加しています。

```kotlin
class MainActivity : AppCompatActivity(R.layout.activity_main) {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // RAWリソースのURLを生成するa
        val url = Uri.parse("android.resource://" + packageName + "/" + R.raw.movie)
        
        // fetcher に VideoFrameUriFetcher を指定してやると動画からフレームを切り出してくれる
        image_view.load(url) {
            videoFrameMillis(1000)
            fetcher(VideoFrameUriFetcher(applicationContext))
        }
    }
}
```

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

また URL だけではなく File での読み込みもできるようになっているみたいです。URLの場合には VideoFrameUriFetcher を指定しましたが File の場合は VideoFrameFileFetcher を指定してやります。

```kotlin
class MainActivity : AppCompatActivity(R.layout.activity_main) {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // ファイル
        val file = File("任意のファイルパス")
        
        // fetcher に VideoFrameFileFetcher を指定してやると動画からフレームを切り出してくれる
        image_view.load(file) {
            videoFrameMillis(1000)
            fetcher(VideoFrameFileFetcher(applicationContext))
        }
    }
}
```

# おわりに

Coil の Video Frames では特定の動画ファイルから特定のフレームを画像として切り出すことができます。これを使えば動画ファイルの読み込み中に表示するサムネイルの取得などができそうです。使う機会が多いとは言えない機能ですが頭の片隅に覚えていれておけばどこかで使えそうだと思いました。

# 参考文献

- [Github - kaleidot725-android/Coil](https://github.com/kaleidot725-android/coil)
- [Coil - Video Frames](https://coil-kt.github.io/coil/videos/)
【Android】Bindingした値をトリガにいい感じにアニメーションする（今回の対象：背景色）

## やりたいこと
「ViewModelクラスに持ってる値に応じて、Viewの背景色を変えたい。変わる時にはアニメーションしてほしい」

## やったリポジトリ
https://github.com/nredjap/android-bindAnimation

## 実装内容の話

プラスマイナスののカウンターがあって、０だと背景グレーで、それ以外だと別の色。
この色変更をアニメーションさせたい。そんな実装をしました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261080/32e22878-7ded-91d7-da1c-6b087e0350d7.png" width=50%><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261080/bac6d813-66b7-a3fb-e46e-8bff3263e8ee.png" width=50%>

### データ側
ViewModel側に色情報も持って、LiveDataに突っ込みました。

```MainViewModel.kt
// ~上略~
    private val _qty = MutableLiveData(0)
    val qty: LiveData<Int> = _qty

    val cardColor: LiveData<Int> = Transformations.map(_qty) {
        when (it) {
            0 -> Color.LTGRAY
            else -> Color.CYAN
        }
    }
// ~下略~
```

### レイアウト側
時間をかけて色を変更するBindingAdapterを定義します。たぶん今回のキモ。

```BindingUtils.kt
@BindingAdapter("backgroundColor_gradually")
fun bindBackgroundColorGradually(view: View, oldColor: Int, newColor: Int) {
    if (oldColor == newColor) return
    val background = view.background
    if (background is ColorDrawable) {
        ValueAnimator.ofArgb(background.color, newColor).apply { // ここでoldColorを使うと色変化中に戻すような時に中間色が使われない
            duration = 500
            addUpdateListener { view.setBackgroundColor(it.animatedValue as Int) }
            start()
        }
    } else {
        view.setBackgroundColor(newColor)
    }
}
```

背景色を変えたいViewに`backgroundColor_gradually`を定義します。

```main_fragment.xml
<!-- ~上略~ -->
        <com.google.android.material.card.MaterialCardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:backgroundColor_gradually="@{vm.cardColor}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">
<!-- ~下略~ -->
```

## おわりに
本質的には「ValueAnimatorつかってみた」だけの内容になってしまった感がありますが、
いい具合に複雑にならずにViewModelからXMLへのBindingで書けたと思います。満足。

BindingAdapter関数の内容のカスタマイズとLiveDataに持つ値の対応で、
Viewの回転とか座標とかサイズとかもアニメーションできると思います。

## 参考
* ValueAnimator
https://developer.android.com/guide/topics/graphics/prop-animation?hl=ja#value-animator
クラス単位で、今回はじめて使いました。

* BindingAdapter
https://developer.android.com/topic/libraries/data-binding/binding-adapters?hl=ja
BindingAdapter自体はヘビーユーザーだったんですが、`oldValue`, `newValue`をはじめて使いました。
インタフェースと抽象クラスの使い分け

#インタフェースと抽象クラスをどう使い分ける？
初心者が、インタフェースと抽象クラスがどんなものかを理解して、次に疑問に思うのは
__それぞれ、どう使い分ければ良いの？__
ということではないかと思います。

#インタフェースは使用者のため、抽象クラスは実装者のため

- インタフェースは__呼び出す人のため__にメソッドのAPIを定義する
- 抽象クラスは__子クラスを実装する人のため__に一部を実装する

端的に言えば、これだけです。

#具体的には
ポリモーフィズムを使用して呼び出してもらいたいクラスは、インタフェースを実装しましょう。

使う側は、抽象クラス型の変数は宣言するべきではないです。
インタフェース型で変数を宣言しましょう。

```java
AbstractFooBar = new FooBar(); // NG
IFooBar = new FooBar(); // OK
```

抽象クラスを仮引数の型とするメソッドも定義するべきではありません。
インタフェース型を指定しましょう。

```java
void fooMethod(AbstractFooBar fooBar); // NG
void fooMethod(IFooBar fooBar); // OK
```

#補足 抽象クラスでポリモーフィズムかけたい場合は？
では、抽象クラスの子クラス群に対してポリモーフィズム使いたい場合はどうするの？
という疑問が生まれそうなので。
その場合は、以下の感じで。

![抽象クラス-インタフェース.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/724841/90c5d284-75d1-82bb-4a46-42eea5a6d419.png)

こうしておけば、使用者は常にIFooBarインタフェース経由で呼び出せば良いですし、
IFooBarインタフェースを実装する人は、
AbstractFooBarを拡張するか、直接IFooBarを実装するかを選べて、
皆が幸せになります。
ロックファイル /var/lib/dpkg/lock-frontend をオープンできません　の対処方法

さてこれがQiita初投稿。大目に見てくださいな。

なんらかのアプリをインストールする際、コマンドで実行しようと

apt install ●●●

だけだと

*****:~$ apt install ●●●
E: ロックファイル /var/lib/dpkg/lock-frontend をオープンできません - open (13: 許可がありません)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), are you root?
*****:~$ 


こういう文言が出てしまう。そのため

sudo apt install ●●● 

のようにaptの前にsudoが必要。なんかのインストールは管理者権限がないと実行できないからね。このコマンドは管理者のコマンドですよぉと認識させるためのものって考えればヨシ

以上、では
【JavaScript】setTimeoutを使って処理のスケジューリング


`JavaScript`で指定時間後に処理を実行するにはsetTimeoutを使用します。
#■書き方
第二引数に与えられた実行タイミング(ミリ秒)で、第一引数に定義された処理内容を1度実行します

```
setTimeout(処理内容,実行タイミング(ミリ秒))

```

#サンプルコード
以下は実行開始から5秒後にアラート表示される処理です。

```javascript:example.js

var alertMessage = function(){
  alert("5秒経過しました！");
}
setTimeout(alertMessage, 5000);
```
#関数に引数を渡す場合

```javascript:example.js

function hello(name) {
  alert('Hello,' + name);
}
  
setTimeout(hello, 5000, 'Taro');
```
#コールバック関数を使用する場合

```javascript:example.js

function hello(name) {
  alert('Hello,' + name);
}

setTimeout(function() {
 hello('Taro');
}, 5000);
```

#参照
[window.setTimeout - Web API インターフェイス | MDN](https://developer.mozilla.org/ja/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout)
メルペイのトップ画面には、「N.A.S.A.」があるらしい。

# はじめに

IT業界にいる方なら、ニュースやQiita、書籍、または企業のIT部門が発信しているブログなどから、技術やトレンドをインプットしていると思います。

こうしたインプットの中から、少しでもアウトプットをしていかなければと思い、その月の気になった記事やニュース、技術などをピックアップして、なにか書いてみようと思いました。

# 今月の気になること

さっそくですが、今月の題材です。
初回は、メルカリとメルペイが発信されている、デザインにまつわるブログの、**[複雑性をシンプルに。メルペイTOP画面に込めたデザインの思想。](https://note.com/mercari_design/n/n43119662dda7)**という記事の紹介です。
メルペイのトップ画面には、「N.A.S.A.」と呼ばれるエリアがあるそうです。
アメリカ航空宇宙局のことではではありません。
そのエリアには、メルペイの体験に対するこだわりが見えました。

# N.A.S.A.ってなんだ！？

メルカリのトップ画面には3つのフェーズがあり、利用しているユーザーがどのフェーズにいるかによって、トップ画面でできることが違っているそうです。
ユーザーごとに利用目的が違うが、トップ画面の使命は、どのフェーズのユーザーに対しても**「お金」に関する体験を共有する**こと。
そんななか、UXリサーチにおいて、「この画面を開いたら、自分は一体何をすれば良いのか？」という迷いの声が多く寄せられた。
それを解決するために生まれたのが、「N.A.S.A.」です。

>
一方お客さま側では「この画面を開いたら、自分は一体何をすれば良いのか？」そんな迷いを抱く声がUXリサーチで多く寄せられました。
私たちが最適なタイミングで提供したい有益な体験と、お客さまの不安と期待がマッチングされる、そんな場所が必要でした。
そこで生まれたのが、通称N.A.S.A.「Next Action Support Area」です。
読んで字の如く、お客さまのその時の状態に沿って「自分が次に何をすればお得・便利になるのか」に気付いてもらい、行動に移せるエリアとなっています。
>

# 気になったポイント

## チュートリアルじゃないんだ...

もし私なら、「この画面を開いたら、自分は一体何をすれば良いのか？」
そんな問いが出たときに、おそらく最初に提案するのはチュートリアルの導入でした。
しかしよく考えてみると、チュートリアルってそんなに読まれているものなのでしょうか。
少なくとも自分はあまり読んでいないことに気づきました...
加えて、チュートリアルというものは、一般的にアプリのインストール直後に1回だけ出すものですよね。
利用しているユーザーがどのフェーズにいるかによって、トップ画面でできることが違っているメルペイアプリでは、「この画面を開いたら、自分は一体何をすれば良いのか？」という問いはチュートリアルでは解決できないことに気づきました...
非常に浅はかな考えで恥ずかしいです。


## N.A.S.A.たくさん置けばいいやん！

N.A.S.A.たくさん置けば、導線も増えていいやん！と浅はかな私は考えるでしょう。

しかし、このN.A.S.A.ですが、トップ画面に一つしか存在させないそうです。
そのこだわりは、N.A.S.A.が、「ユーザーが次にやることを明確にする」という役割を持っているからだそうです。

>
お客さまの次にやることを明確にすることがサポートエリアの役割なので、原則1つだけしか表示させないことが「体験価値」となるからです。
>

確かに、N.A.S.A.が複数あるアプリを想像してみると、やることがたくさんあってどれからやって良いのかわからない、と感じるユーザーがいる、つまり、N.A.S.A.の役割を果たせなくなるのかなと感じました。

一方で、身近なデザイナーの方に伺った話が頭をよぎりました。
「日本人はスタンプラリーのような、ミッションのあるUIを好む（スタンプカードを埋めたい、ミッションをコンプリートしたいという気持ちが強い傾向がある）ので、ユーザーに起こしてほしいアクションを一覧にし、アクションを起こしてくれたら視覚的に見せてあげる（スタンプカードを埋めるイメージ）UIが効果的です」

これも一種の解決策なのかもしれません。

# 私のスマホ(Android)に入っているアプリから、N.A.S.A.のようなものを探してみた

※N.A.S.A.があるから良くて、無いから悪いという話をしているわけではありません。

## IKEA

![ikea.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308235/f35fa7a1-edf3-449a-56c7-7c2ccd2d944c.png)


N.A.S.A.は無いように見えます。
ベーシックなグロナビがあるだけで、何をして良いのかわからないというのはありますね。
話はそれますが、IKEAのアプリ、アップデートしてすごく使いやすくなったと思いませんか？
サクサク動くようになったし、紙のカタログに近い形で見れるようになって、すごくワクワクするようになったと思います。
個人的には、紙のカタログもそうですが、ぼーっと眺めたい気持ちもあるので、気に入っているアプリです。


## ニトリ

![nitori.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308235/fec36b5f-8bab-0149-c1ec-9acae47d51d6.png)

N.A.S.A.っぽいものが...ある？（アプリ会員限定特典のところです）
ですが、固定表示っぽのですこし違う気もします。


## MoneyTree

![mt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308235/cae2881f-2e53-3547-b834-5516ac3da224.png)

N.A.S.A.は一見無いようにみえますね...
気になるところとしては、「ウィークリーレポート」のエリアをタップすると、その週の支出の、各カテゴリーごとの内訳が表示されますが、そのウィークリーレポート画面から、予算設定の画面に飛ばしたりしていたら、立派なN.A.S.A.になるかと思いました。


## ZOZOTOWN

![zozo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308235/2d410587-76c5-a88c-82e1-58b65d49261d.png)

ZOZOTOWNでは、「服をブランド横断して探して、買う」のが目的になるので、「あなただけのタイムセール」がN.A.S.A.になるのでしょうか？
「あなただけのタイムセール」がどれほど「私だけの」タイムセールなのか、ロジックは不明ですが、特別感を出されると買いたくなりますね。


# まとめ
いかがでしたでしょうか。
ほぼ独り言に近いシリーズになるかと思いますが、読んでくれたかたの気になったポイントや、「N.A.S.A.見つけたよ！」報告がコメント欄につくと嬉しいです。
データベース, SQL【超基本】

#【データベース, SQL】

基本情報技術者試験午後のデータベースの学習の際にまとめたものです。
後日、また追記していこうと思います。

##・COUNTの種類

・＊　すべての列を意味する。
・NULL　値が格納されていないことを意味する。
・ALL　同じ値の重複を含めてすべての値を、表示、集計する。省略化。
・DISTINCT　同じ値の重複を除いた値を、表示、集計する。

##・集合関数

集計した値を求めるために使用される。

・SUM　合計値を求める。
・AVG　平均値を求める。
・MAX　最大値値を求める。
・MIN　最小値を求める。
・COUNT　件数や個数を求める。

##・表示する行を絞る。

・HAVING ＜集合関数のある式＞
　用途）集合関数を使って、行を絞る。GRPUP BYの後に条件を絞る。
　表示内容）◎◎である、○○ごとに表示

・WHERE
　用途）集合関数を使わず、行を絞る。
Lalavelでメールの送信機能を実装しようとしたらハマった話。

https://www.hypertextcandy.com/laravel-tutorial-authentication-part-2/
こちらの記事を参考に、Laravel(ver.5.7)でメールの送信機能を実装しようとしたらはまりました。

何度コードの記載をし直しても認証できませんとのエラーが、パスワードの再設定のボタンを押すと出されてしまう。

Swift_TransportException in AbstractSmtpTransport.php line 383: 
Expected response code 250 but got code "530", with message "530 5.7.1 Authentication required" 

結論から言うと、.envを変更した際にキャッシュをクリア（php artisan config:cache）していないのが原因でした。config/mail.phpの設定も一部変更する必要があった模様。
これらの合わせわざではまりました。

```.env
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=ここに Username を記載する
MAIL_PASSWORD=ここに Password を記載する
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=todoapp@email.com
# ここに自分の持っているメールアドレスを記載することで、自分のメールアドレスからパスワードの再発行を申請した人に新しいメールアドレスが送られます。
MAIL_FROM_NAME="ToDo App"
# ここはなんでもOKです。
```

```mailtrap.ioのデータ。
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=ここのデータをコピーする
MAIL_PASSWORD=ここのデータをコピーする。
MAIL_ENCRYPTION=tls
```

カリキュラムだとMAIL_DRIVERの定数の定義が微妙に違いました。

MAIL_DRIVER=smtp
MAIL_MAILER=smtp

とりあえずmailtrapの記載に合わせて「MAIL_MAILER=smtp」と.envに記載しました。

その後、キャッシュをクリアしてみてもエラーがでる。。。

config/mail.phpを確認してみる。
絶対に必要かはわからないが、config/mail.phpをみると確実らしい。

```mail.php
    'driver' => env('MAIL_DRIVER', 'smtp'),
```

これだ！

```mail.php
    'driver' => env('MAIL_MAILER', 'smtp'),
```

記載を変更した時は、忘れ図にキャッシュをクリア！

```
$php artisan config:cache
Configuration cache cleared!
Configuration cached successfully!
``` 

記載しなおしてキャッシュをクリアしたら元に戻りました。
ちゃんとメールも届いてる。