OmniAICreator/Qiita-1.07M huggingface dataset:
最小実装でモデルのIDをタイプセーフに表現する

実際のアプリを作るとき、多数のモデルが存在することになると思いますが、
APIから取得したデータはIDというプロパティを持つことが多いと思います。
それらはStringやIntなどの型で表現されると思いますが、
メソッドの引数名によっては誤ったモデルのIDを入れてしまうヒューマンエラーが起こる可能性があります。
それをSwiftの型を用いて解決したいと思います。

# ヒューマンエラーの例

`fetchLikes`というメソッドはStringのidを引数に取るため、LikeでもUserでもidがStringで宣言されているので、引数にLikeのIDを入れることができてしまいます。

```swift
final class LikeRepository {
  /// UserのIDをもとにUserのお気に入り一覧を取得する
  func fetchLikes(id: String) -> [Like] {
    ...
  }
}

struct User {
  var id: String
}

struct Like {
  var id: String
}

let user = User(id: "id")
let repository = LikeRepository()
// 正しい使い方
repository.fetchLikes(id: user.id)

let like = Like(id: "id")
// 誤った使い方でもコンパイルできてしまうので、問題に気づけない
repository.fetchLikes(id: like.id)
```

# 解決策

## ユーティリティを実装する
```swift
protocol Identifiable {
  typealias ID = Identifier<Self>
  var id: Identifier<Self> { get }
}

struct Identifier<Object>: Hashable {
  var rawValue: String
}

/// User.IDなどのIdentifierをStringで初期化可能にする
extension Identifier: ExpressibleByStringLiteral {
  init(stringLiteral value: StringLiteralType) {
    self = Identifier(rawValue: value)
  }
}
```

## 使い方
```swift
struct User: Identifiable, Equatable {
  var id: ID
}

struct Like: Identifiable, Equatable {
  var id: ID
}

final class LikeRepository {
  func fetchLikes(id: User.ID) -> [Like] {
    // id.rawValueでStringにアクセスできる
    ...
  }
}

let user = User(id: "id")
let repository = LikeRepository()
 // 正しい使い方
repository.fetchLikes(id: user.id)

let like = Like(id: "id")

// エラーになりコンパイルできないので、ミスに気づける
// Cannot convert value of type 'Like.ID' (aka 'Identifier<Like>') to expected argument type 'User.ID' (aka 'Identifier<User>')
repository.fetchLikes(id: like.id) 
```


# 参考

https://github.com/JohnSundell/Identity
TypeScriptメモ 〜関数編〜

###関数を作ってみる

```typescript
function hello(name:string) {
  // 何らかの処理
}
```

###関数内の変数スコープ

|宣言文|スコープ|
|:-:|:-:|
|var|関数外で宣言した場合はそのソースコード全体で利用できる。関数内で宣言したものは関数内だけで使える|
|let|宣言した{}内で使える|

```typescript
function total(max:number) {
  let num = 0
  for(let i = 1, i < max; i++) {
    num += 1
  }
  console.log(num + i) // エラー！ iが見つかりません！
}
```

###戻り値

戻り値の型を指定できる。何も返さない時はvoid

```typescript
function total(max:number):number {
  //　処理
}
```

###複数の値を返す

```typescript
function calcTax(price:number):[price:number, tax:number] {
  // 処理
}
```

###引数に条件型を使用

```typescript
function foo(foo:number|string){}
```

###オプション引数

省略可能な引数を利用できる。

```typescript
function foo(foo?:string, bar?:string) {}
```

###引数の初期値

```typescript
function foo(foo = 1) {}
```

###可変長引数

いくつ引数が必要かわからない場合に

```typescript
function foo(...data:number[]){}
foo(1,2,3,4)
```

###無名関数

```typescript
const f = function(foo:foo):void {}
```

###アロー関数

```typescript
const f = (foo:foo):void => {}
```

###functionとアロー関数の違い

```typescript
foo() // Error!

const foo = (foo:foo):void => {}
```

```typescript
foo() // ok

function foo(foo:foo):void {}
```

###総称型（ジェネリクス）

「数値を引数で渡したら数値を返し、テキストを渡したらテキストを返す」といった関数を定義する時に使用

```typescript
// Tが指定されたものはすべて同じ型になる
function foo <T> (foo:T):T {}
```

###ジェネレータ

ジェネレータでは「yield」を使って値を返す。returnと違って、値を返したあとも処理を続ける。つまり「待ち状態」になる。
ジェネレータは通常の関数と使い方が違う。関数を呼び出すと戻り値としてジェネレータが返される。そのジェネレータに「next()」を呼び出すことで使える。

```typescript
function* fibo(n:number) {
  let n1 = 0
  let n2 = 1
  for(let i = 0; i <= n; i++) {
    yield n1
    let n3 = n1 + n2
    n1 = n2
    n2 = n3
  }
}

const n = 10
let fb = fibo(n)
for(let i = 0; i <= n; i++) {
  let ob = fb.next()
  console.log(ob.value)
}
```
RealWear上で動かしてるUnityアプリの自動回転が反応しなくなる問題の解決

# 環境
- [RealWear](https://www.realwear.jp/)
    - Androidが搭載されたヘッドマウントディスプレイ
- Unity2018

# 問題
- RealWearは左右の目どちらでも使用できるように端末の上下に合わせて画面を自動回転してくれる機能が備わっている。
  - 自動回転自体は[端末の設定でON/OFF可能](https://support.realwear.com/knowledge/screen-orientation)
- しかし、Unityで作成したアプリを起動しているとき、自動回転をONにしていてもある条件で自動回転が効かなくなる。
  - 自動回転が効かなくなる条件は[ロール軸](https://www.buildinsider.net/small/bookkinectv2/0804)に上下を逆さまにしたとき
  - 逆さまにしたタイミングで一度だけ自動回転が発生するが、その後は上下を逆さまにしても自動回転が効かなくなる。
- 自動回転が効かなくなっているのはアプリレベルの話であるため、他のアプリでは自動回転は動作するし、該当アプリを再起動すれば再び自動回転は効くようになる。

# 解決策
Unityエディタから`Build settings > Player Setiings`を開き、 `settings for Android > Resolution and Presentation`の中の
- `Orientation`を`Auto Rotation`に
- `Allowed Orientations for Auto Rotation`の`Portrait`と`Portrait Upside Down`のチェックを外し、`Landscape Right`と`Landscape Right/Left`だけにチェックをつける
![スクリーンショット 2021-11-24 18.08.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268579/dd80f262-73a4-d592-1de6-4a27659cde66.png)

おそらくRealWearでは横向きが画面しか対応しておらず、ロール軸回転によって一瞬でも縦向きという状態になると、それを正しく処理できず自動回転機能に不具合を起こすのではないかと予想している。
そのため、アプリの設定で縦向きを除外してやることでこの問題の発生を抑えられているのだろう。


# あとがき
- 今回は仕事の関係でRealWearという一般ではあまり利用されていないハードウェアの開発に携わることになり上記の問題に直面した。
- RealWearの情報は公式ドキュメントと日本の販売代理店のもの以外はほぼ存在せず、特にこういった細かい不具合については一切参考になるものがなかったため、今後RealWear × Unityで開発を行う人の助けになればと思い記事を書いた。
- この記事のニーズは日本の中では1人もいないかもしれないが、いつか誰かの役に立つことを願っている。
Swift button action と function の 連結

最初にUIButtonのイニシャライゼーションの指定から。

```
var btn1 = UIButton()
```
これを、viewDidLoad(){} の中に書くと、画面がロードされたときのみ、{}内だけで有効なイニシャライズ＝初期化。下記は、クラス全体で有効なイニシャライズ。

```
class ViewController: UIViewController {
var btn1 = UIButton()

  override func viewDidLoad(){
    btn1.frame = CGRect(x: 左端からの位置, y: 上からの位置, width: 幅, height: 高さ)
    btn1.setTitleColor(.gray, for: .normal)
    btn1.backgroundColor = .black
    btn1.textAlignment = .left
    btn1.addTarget(self, action: #selector(button1(button1;)), for: .touchUpInside)
    self.view.addSubview(btn1)
  }
  @objc button1(button1: UIButton){
    btn1.backgroundColor = .purple
    object()
  }
  func object(){
    // New event start.
  }  
}
```
このようにしてロードした直後のボタンの位置決めと、タップイベントの作成が開始され、ファンクション化されて連結されていく。
一文字一文字に心を込めるプログラム

# はじめに
パソコンで文章を書いていると、手書きに比べてどこか心が込もっていないと感じることはないでしょうか。
そこで本記事では、Pythonを使って「これはペンです」という文章に、心を込めるプログラムを作成してみました。

# 目次
1. [素直な実装](#1-素直な実装)
2. [joinメソッドを用いた実装](#2-joinメソッドを用いた方法)





#1. 素直な実装
文字数分だけループを回します.[^1]

```python
a = "これはペンです"
for i in range(len(a)):
    print(a[i] + "心", end='')
```

出力結果

```txt
こ心れ心は心ペ心ン心で心す心
```


#2. joinメソッドを用いた方法
```python
a = "これはペンです"
print("心".join(a))
```

出力結果

```txt
こ心れ心は心ペ心ン心で心す
```
# おわりに
い心か心が心だ心っ心た心で心し心ょ心う心か心。心P心y心t心h心o心n心を心使心っ心て心た心く心さ心ん心心心の心込心も心っ心た心文心章心を心書心い心て心い心き心ま心し心ょ心う心。

<a id="#reference"></a>
# 参考文献
- [Pythonにおける文字列操作について](https://bigdata-tools.com/python-string/)

[^1]: もう少し簡潔に記述することもできます。
 
 ```python
  a = "これはペンです"
  for i in a:
       print(i + "心", end='')
 ```
pre-commitするときにマルチバイトを含んでいたらrijectする。

あるプロジェクトで多言語化対応する必要があったのですが、日本語がベタ書きされている箇所もちらほらありつつ「これからコーディングする際はマルチバイトを含んでいたらcommit時に弾こう！」となりました。
そのときに行った処理を記載します。

## 使用するライブラリ
- husky

## この記事で説明しないこと
- huskyがなんなのか
- huskyのinstallから設定方法

## 参考にした記事
[Git でコミット前に禁止ワードが入っていないかチェックする](https://qiita.com/nirasan/items/c2474076e1f38c0f408a)


## 実際のコード


```bash
#!/bin/sh
rootPath=$(git rev-parse --show-toplevel)
diffArray=()
show_message () {
  cat <<EOL


[WORD CHECK ERROR]

  Cannot commit multibyte characters


[RESULT]
$1

[HINT]

  If you want to force commit, please append prefix 'NO_WORD_CHECK=1' to command.


EOL
}

for file in $(git diff --cached --name-only)
do
  extention=${file##*.}
  if [ $extention = 'ts' ] || [ $extention = 'js' ] || [ $extention = 'vue' ]; then
    result=$(less "${rootPath}"/"${file}" | grep -A5 -B5 -i [０-９Ａ-ｚ、-◯ぁ-んァ-ヶ亜-腕弌-熙])
    if [ $? -eq 0 ]; then
      diffArray+=("\n$result\n\n")
    fi
  fi
done

if [ ${#diffArray[@]} -gt 0 ] && [ -z $NO_WORD_CHECK ]; then
  joinedStr="$(IFS=; echo "${diffArray[*]}")"
  show_message "$joinedStr"
  exit 1
else
  exit 0
fi
```


## 説明

```bash
git diff --cached --name-only
```
まずは、これでaddしたファイル名を取得しforでブン回します。


```bash
  extention=${file##*.}
  if [ $extention = 'ts' ] || [ $extention = 'js' ] || [ $extention = 'vue' ]; then
```
次に、ts js vueのファイルだけに絞り込みます。


```bash
result=$(less "${rootPath}"/"${file}" | grep -A5 -B5 -i [０-９Ａ-ｚ、-◯ぁ-んァ-ヶ亜-腕弌-熙])
```
lessでファイル開いて、マルチバイトや記号でgrepかけます。


```bash
if [ $? -eq 0 ]; then
```

$?には直前の結果が格納されています。
それをarrayに追加しまして。

```bash
if [ ${#diffArray[@]} -gt 0 ] && [ -z $NO_WORD_CHECK ]; then
  joinedStr="$(IFS=; echo "${diffArray[*]}")"
  show_message "$joinedStr"
  exit 1
else
  exit 0
fi
```

最後に表示させます。

このチェックを回避する場合は、commit時にNO_WORD_CHECK=1のパラメーターを指定するとそのままコミットできます。

```bash
NO_WORD_CHECK=1 git commit
```
M1 Mac の Parallels の Windows 11 で USB シリアルアダプターを使う方法

ARM64 のドライバが提供されてないと動かない。

# CP210x 系

https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers

公式から "CP210x Universal Windows Driver" をダウンロードしてインストールするだけ。

# FTDI 系

ARM64 版はまだ公式には配布されてない。
Surface Pro X も ARM64 で同様の状況らしく、Microsoft のフォーラムに解決策がある。

https://answers.microsoft.com/en-us/surface/forum/all/surface-pro-x-usb-c-to-rs232-issues/3bc380dc-b018-4ad2-958a-e66c438c6b94

以前は FTDI の FTP からダウンロードできたみたいだけど、アク禁されていまは直接手に入れられない。↑のフォーラム内に MediaFire にアップロードされたやつがリンクされてるのでそこからゲットする。

ドライバの署名がテスト用なのでインストール方法が複雑。

1. Bitlocker を off にする。
1. UEFI の設定から Secure Boot を disable にする。
1. `bcdedit /set testsigning on` でテスト署名を有効にする。
1. 再起動する。（右下に "Test mode" って出る
1. USB シリアルアダプタを接続する。
1. デバイスマネージャーに "!" マークのデバイスが出てくるので "Update driver"
1. ダウンロードしてきたファイルの `ARM64\Release` フォルダを指定してドライバをインストール。
1. レジストリエディタを起動。
1. `Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_0403&PID_6001\a410f66c\Device Parameters` みたいなのを開く。`a410f66c` のとこはデバイスごとに異なる。
1. `PortName` っていう string value を新規作成。値を `COM4` とかにする。
1. アダプタを抜いて指し直す。
1. `USBtoSerial device` っていうのが "!" マーク付きで現れるので、再度 "Update driver" する。
1. 完了！

Secure boot も Bitlocker も disable なのでいろいろ注意すること。（戻すと動かなくなる

# CH34x 系

不明…
配列とループ分

# case

* lengthは要素数を評価
* arry2のように途中で"0"= falsyな値があると途中でループが止まる。

```js

const arry = [1, 2, 3, 4, 5];
const arry2 = [1, 2, 3, 0, 5];

for(let i = 0; i < arry.length; i++){
    console.log(i)
}

>>> 1
>>> 2
>>> 3
>>> 4
>>> 5

```

# case2
* [i++]後方インクリメントは初期値を代入してから+1されるので最初のループはvに0が渡されている。
* arry配列5以上場合はundifindが戻り値になるのでfalseになりループが止まる

```js

let v, i = 0 //pythonはたしかこのような変数宣言は推奨されていなかったきがする。

while(v = arry[i++]){
    console.log(v);
}
```
Chartjsで座標を表示させる方法

##chartjsで座標を表示させる方法
まずchartjsのドキュメントからテンプレートを使用する.
https://www.chartjs.org/docs/latest/
この中のチャートタイプに散布図のテンプレコードがある. 
これを使用して以下のchart_init.jsのコードを書く

```javascript
const ctx = document.getElementById('myChart').getContext('2d');
const input_data = [];

const data = {
    datasets: [
      {
        label: 'Dataset 1',
        data: input_data,
        fill: false,
        borderColor: 'rgb(0, 0, 0)',
        backgroundColor: 'rgb(100, 255, 100)',
      }
    ]
  };

const config = {
    type: 'scatter',
    data: data,
    options: {
        elements: {
            line: {
                tension: 10
            },
        },
        responsive: true,
        plugins: {
            title: {
                display: true,
                text: 'POSITION'
            }
        },
        scales: {
            x: {
                min: 0,
                max: 100,
            },
            y: {
                min: 0,
                max: 100,
            }
        }
    },
};

const myChart = new Chart(ctx, config);
```
次にmain.jsのコードを書く

```javascript
function pushPosition(x, y) {
    input_data.push({'x':x, 'y':y});
    myChart.update();
    return true;
}

//sample
for (let i = 0; i < 300; i++) {
    pushPosition(i/10, i/10);
}
```
次にHTMLの設定を行う

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas id="myChart" width="400" height="400"></canvas>
    <script src="https://cdn.jsdelivr.net/npm/chart.js@3.6.0/dist/chart.min.js"></script>

    <script src="./chart_init.js"></script>
    <script src="./main.js"></script>
</body>
</html>
```

これでHTMLのファイルを起動するし, pushPosition(x, y)でｘとｙに表示したい数値をconsoleに入力することによって以下のように表示することができる.

![スクリーンショット 2021-11-17 21.48.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690610/723968c0-0dd4-21cb-f5be-99510fa1c637.png)
Laravelのキューで並列処理をするには

# 使用環境

- Laravel8.x
- PHP 8.0
- Docker(Laravel Sailで構築した環境を使用しました)

# ごあいさつ

この記事は2021年のQiita Advent Calendar PHP の4日目の記事です。
昨日は@yoshikyotoさんのPHP8.0,8.1に関する記事でした。最近PHPも8.1がリリースされてまだまだ進化を遂げていますね。

[@yoshikyotoさんの記事はこちらから](https://www.utakata.work/entry/2021/12/03/230223)

# 記事の目的

この記事ではLaravelで並列処理をするにあたって私が検討した選択肢を紹介することとともに、どのようにそれを実現したかをお示しすることで現在似たような実装を目指している方の助けとなることを目的とします。

# 前提

Laravelのキュー機能では様々な処理をジョブという関数に切り出しておいて、それらをバックグラウンドで非同期に実行することができます。キューについては公式ドキュメントを貼っておきます。
[Laravel 8.x キュー](https://readouble.com/laravel/8.x/ja/queues.html)

Laravelを触り出して半年そこそこの私は、既にキューを使って構築されているメッセージングサービスのプロジェクトでこんな要望を出されました。

社長「メッセージの配信速度って上げられないかなぁ」

問題のプロジェクトではメッセージを送信する際に外部のAPIを使用していました。そしてこのAPI(仮に送信APIと呼びます)を叩く処理をジョブに書いておき、それを必要なタイミングでキューへ発行することでメッセージ配信機能を実現していたのです。

# 送信APIの制約

送信APIは1秒間に5回までしかコールできないという制約がありました。いわゆるレートリミットですね。当然これを超えるとレートリミット超過ということでAPIコールが失敗してしまうので、配信速度を上げるとなれば秒間5コールぎりぎりをついていくほかありませんでした。以下の内容はこのレートリミットを踏まえて進みます。

# メッセージの配信速度を上げるには...?

3つほど紹介します。結論だけ知りたい方は一番下までスキップしてください。

## Golangで並列処理をする

若干Laravelに飽きていた私は新しい技術を使える機会ならばと並列処理を得意とするGolangの使用を考えました。処理機構のイメージとしてはこんな感じです。

![スクリーンショット 2021-11-24 17.12.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/893208/ecc8636a-7e0f-b575-4e4f-1186da499767.png)

詳しい人ならご存知だと思いますがcronやLaravelでそれを実装したタスクスケジューラは最も頻繁に実行しても1分に1回しか実行できません。しかし、問題のプロジェクトでは前述したレートリミットのぎりぎりをつくため1秒に1回実行しなければならなかったのでこの方法は使えませんでした。かなしみ。

## Guzzle HTTPを使う

GuzzleHTTPとはPHPでHTTPコールを並列に行うためのライブラリです。少なくともLaravel8系ではデフォルトで入っています。技術調査にあたってはmercariの方が書かれたスライドが大変参考になったので貼り付けておきます。

[Guzzle Promiseを使った 非同期処理によるAPIコールの高速化](https://speakerdeck.com/suzuki/guzzle-promisewoshi-tuta-fei-tong-qi-chu-li-niyoruapikorufalsegao-su-hua)

要するに外部の送信APIを並列に叩きたいならrequestAsyncなりPoolなりを使ってAPIのエンドポイントにPOSTリクエストを必要なだけ送信すれば良いということになります。しかし、これも結局cronなりタスクスケジューラでレートリミットのぎりぎりをつく制御が必要になってしまう以上Golangの時と同じ理由で使えませんでした。かなしみ。しかし私のようなレートリミットの問題を抱えていない開発者の方には良い選択肢であると思います。PHPで完結するので。

## キューのプロセスを複数起動する

3つの中では最も泥臭い方法ですが、結局これを採用しました。Laravelではジョブを発行する時に発行先のキューを任意に指定することができます。例えばqueue_Aとqueue_Bという2つのキューワーカプロセスを起動しておけば、キューの発行先にこれらのキュー名を指定してやることでジョブの発行先を出し分けることができるのです。

私の場合、従来はキューワーカプロセスを1つだけ起動していたのを2つに増やしたことで送信APIを並列にコールできるようになり、メッセージ配信速度を向上させることができました。

しかしまだレートリミットの問題が解決していません。結論から言えばキューワーカのプロセスを2つにしてベンチマークをとっても秒間5回を超えることはあまりなく、(平均4回でした)あったとしても瞬間的に超える分にはAPIコールは問題なく行えたので一応解決という形になりました。

ただし、本番環境ではキューのプロセスが落ちるリスクへの対策が必要になります。それはSupervisorを使って対応しました。その際に必要なsupervisor.confの書き方などについては記事の目的から外れるため割愛します。私が参考にした神記事を貼っておくのでご覧ください。

[Laravelでキューを使った並列処理](https://qiita.com/Nishi53454367/items/871614343ea77020db17)
ネットワーク学習に役立ちそうなサイト

小生、プログラマーとしてプログラムを扱うことが多いものの、基盤となるインフラ部分（ネットワークとかサーバとか）に関しては触れる機会が少ないです。AWS、AzureといったクラウドサービスやDockerなどの仮想環境を使用して環境構築できるようになってくるにつれて、素のコマンドを叩く機会は益々減ってきました。

また、新人の頃はインフラもアプリもあまり区別する意識もなかったので選り好みせずに手広く学習していたものの、近頃は業務で使う技術以外に触れる機会も少なくなり、だいぶ知識も偏ってきているような気もしてきました。そこでインフラ、まずはネットワークを、学習し直してみようかなと思い立ちまして、といいつつ時間的にも金銭的にもそんなに本格的にやりたいわけではないので、Webで手軽にできる学習サイトはないかなと調べてみました。

こんな基準で調べました。
- お金がかからない
- 基本的なことから学習できる
- ある程度体系的に学習できる

ググっていると昔学習した頃にお世話になった懐かしいサイトや、新しいサイトがみつかりました。
個人的な備忘録ではありますが、ネットワーク初学者の参考にもなればと思い、ちょっと気になるなというものや個人的におススメしたいと思うサイトを本記事にまとめてみることにしました。

## <a href="https://www.infraexpert.com/">ネットワークエンジニアとして</a>
ネットワークの基本的な部分が網羅されており、また説明も図が多用されていて丁寧で分かりやすいです。
サイトのUIは古めかしいため若干学習動線が分かりにくいのですが、内容が充実しているので問題なしです。
CCNAというネットワーク関連の資格試験を受けた際にかなりお世話になっていたサイトで、かなり前からあるサイトだと思いますが、更新もされているようだったのが好印象でした。

## <a href="http://www5e.biglobe.ne.jp/%257eaji/3min/">3 Minutes Networking</a>
ネットワークの学習といえばまず初めに名前があがるのはこのサイトの方も多いのではないでしょうか。
久々にサイトを訪れてみるとなんとSSL対応もされておらず（！）、長い間手が入っていない印象を受けました。ただ、基本を学ぶという意味ではいまだ非常に有意義なサイトかと思います。
当時、対話形式で読み物的にネットワークについて学習できるというのは、非常に画期的だったのではないでしょうか。久々にまた読んでみようかな、という気持ちになりました。

## <a href="https://tech.pjin.jp/blog/infra_engneer_category/ccna/">CCNA | TECH PROjin</a>
「CCNA取得を目指す」という見出しで、資格試験に沿った内容でネットワークを学べるサイト。
ネットワーク以外にもサーバやプログラミングのコンテンツもあるようです。記事末尾に例題があるので理解度チェックができるのが嬉しいところ。
全体のボリュームが分かりにくいので、体系的に学べそうなのかが判断しづらいですが、記事内の説明は丁寧だと思いました。

## <a href="https://www.n-study.com/">ネットワークのおべんきょしませんか？ | Ciscoを中心としたネットワーク技術の解説。Cisco CCNA/CCNP/CCIE対策にも</a>
ネットワークについて丁寧に解説されているサイト。私はヘビーユーザではなかったものの、サイトタイトルは聞いたことがあるので、何度かお世話になっていると思います。「ネットワークエンジニアとして」と同様に網羅的に解説されているように思います。

## <a href="https://beginners-network.com/">ネットワーク入門サイト - 接続・速度・通信の基礎</a>
資格試験対策サイトというよりは、実務寄りの学習ができるサイトという印象をうけました。
実際のコマンドがのっていて分かりやすく、機器別に設定の説明をしているところが面白いと思いました。

## まとめ
色々なサイトを見ていて思ったのですが、老舗のサイトがわかりやすいなと思いました。
ネットワークという半普遍的な技術というのは、プログラミングのような流行り廃りがないまさに"インフラ"技術なのだなと感じました。これらのサイトを読みながら、ネットワークについての学習も細々としていきたいと思います。
【javascript】クロージャー

# クロージャー
レキシカルスコープの変数を関数が使用している状態

## プライベート変数
関数の外部からアクセスさせないようにする

### case

* 数字をカウントアップさせていく関数があったとする。
* 1が3回出力され、カウントアップされない。
* 実行するたびに変数numが初期化されてしまうから。

```js

increment();
increment();
increment();

function increment(){
    let num = 0; //初期化
    num = num + 1;
    console.log(num)
}
>>> 1
>>> 1
>>> 1

```

* increment関数の外側でnumを初期化すればよい。

``` js

let num = 0 //初期化

increment();
increment();
increment();

function increment(){
    num = num + 1;
    console.log(num)
}

>>> 1
>>> 2
>>> 3

```

* しかし、変数の上書きも容易にできるので、予期せぬエラーが発生することがある。

```js

let num = 0 //初期化

increment();
increment();
increment();

function increment(){
    num = num + 1;
    console.log(num)
}

num = 0

increment();

>>> 1
>>> 2
>>> 3
>>> 1

```

#### 結論
クロージャを使用して解決する。

* クロージャーにあたるincrementFactoryを作成しそこで変数を定義
* incrementFactoryの下層にincrement関数を定義してあげることで外部から変数へのアクセスを制御することができる。 

```js
function incrementFactory(){
    let num = 0 //初期化
    function increment(){
        num = num + 1;
        console.log(num)
    }
    return increment;
}


const increment = incrementFactory();

increment();
increment();
increment();

>>> 1
>>> 2
>>> 3
```

## 動的な関数の生成

* addNumberFactoryというクロージャに引数を渡す
* addNumberFactoryを初期化する時に引数をわたし、内部で実行するaddNumberに異なる値を渡すことによって動的な関数を生成することができる。
 
```js
function addNumberFactory(num){
    function addNumber(value){
        return num + value
    }
    return addNumber;
}


const add5 = addNumberFactory(10)
const add2 = addNumberFactory(10)
console.log(add5(5))
console.log(add2(2))
```
[500 server error]Mac再起動後にSQLに接続できず、Laravelのプロジェクトをローカル環境で確認できなくなった時


以前作成したLaravelのプロジェクトの修正を行おうとしていつも通りMAMPを起動してブラウザで表示しようとしたら、、、
![スクリーンショット 2021-11-24 16.23.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2292175/3cc6c7e2-64a6-d982-1dd8-9d8dd8ee0c60.png)
~~もういやだ~~
独学者にはこういうのが一番効きます。

#開発環境

```
$ sw_vers
ProductName:	macOS
ProductVersion:	11.6
BuildVersion:	20G165
$ mysql --version
mysql  Ver 14.14 Distrib 5.7.35, for osx10.16 (x86_64) using  EditLine wrapper
$ php artisan --version
Laravel Framework 6.20.30
```

#解決手順

とりあえず.envのデバッグ設定をオンにして解決手段を模索する。

```plaintext:.env
APP_DEBUG=true
```

するとこんな感じのエラーがブラウザに表示される

```
[2002] No such file or directory (SQL: select * from `users` where `id` = 1 limit 1) (View: /Applications/MAMP/htdocs/[Project_name]/resources/views/welcome.blade.php)
```
意外と単純な理由ってことがわかる。データベースへの接続がうまくいってないみたい。
ひとまずターミナルでMySQLへの接続を試みてみる。

```
$ mysql -u root -p
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock'
```
まあそりゃ接続できないよね。
んでmysql.sockって何だ？と思ったけどどうやら英語で書いてある通りMac内のプログラムとMySQLを通信の処理をしてくれるいいやつらしい。
この仲介役みたいな人がいないからSQLに接続できないらしい。Macをシャットダウンしたときに解雇されたのか。かわいそうに。
だから以下のようにして新しく仲介役を雇用してやる必要があると。

```
$ touch /tmp/mysql.sock
```
>備忘録：
>touch・・・現在のディレクトリにとりあえず空のファイルを作ってあげるコマンド。

ここで権限のエラーが出ることがある

```
touch: /tmp/mysql.sock: Permission denied
```
その場合は

```
$ ls -l /tmp/mysql.sock
```
で権限を確認してやり、

```
$ sudo chown [username]:admin /tmp/mysql.sock
```
で[username]にパーミッションを与えてあげ、改めてtouchしてやる。
>備忘録：
>sudo・・・rootユーザーの権限が必要なコマンドを実行できるようになる。
>chown・・・指定したファイルの所有権を変更するコマンド。

これで仲介役が雇え、MySQLの接続準備が整ったので、MySQLを再起動する。

```
$ mysql.server restart
 ERROR! MySQL server PID file could not be found!
Starting MySQL
. SUCCESS! 
```
ここのエラーはよくわからないが、MySQLが無事再起動できたようなので改めてブラウザでLaravelを起動してみるとうまくいっていることが確認できた。
初めてこういうふうになった時はめちゃくちゃググりまくって時間がかなりかかってしまったのでそういった方々の役に立てれば、、、！！！

#まとめ
Laravelにブラウザで接続できなくなった時はまず.envファイルのdebugをオンにしてどこで接続がうまくいってないか確認する。

mysql.sockでMySQL接続ができないよと言われたら多分mysql.sockが消えてるので、適切な権限のもと新しくmysql.sockを作成してあげる。

mysqlを再起動してうまくいっていることを確認する。

人生がうまくいく。

##参考
>https://qiita.com/jonakp/items/477a18d4a94c01a31583

>https://www.naka-style-blog.com/mysql-log-in-erorr/


コマンドラインの操作だったり、それらに付随するエラーだったりってなかなかとっつきにくくて難しいのでまだまだ勉強が必要だなと思った今日この頃。何か気になる点やご指摘等ございましたら教えていただけるとありがたいです。
MD5によるダイジェスト値を取得する

```Python
$ cat test1.py
#!/usr/bin/env python3

import hashlib
import datetime


class Animal:
  def __init__(self, name='John', height=180):
    dt_now = datetime.datetime.now()
    self._id = hashlib.md5(str(dt_now).encode()).hexdigest()
    self._name = name
    self._height = height

  def __del__(self):
    print(self._id, 'is destruted...')

  @property
  def id(self):
    return self._id

  @property
  def name(self):
    return self._name

  @property
  def height(self):
    return self._height

  @name.setter
  def name(self, name):
    self._name = name

  @height.setter
  def height(self, height):
    self._height = height

  def get(self):
    return self._id, self._name, self._height


if __name__ == '__main__':
  # just for testing

  # dt_now = datetime.datetime.now()
  # print(dt_now)

  # hs = hashlib.md5(str(dt_now).encode()).hexdigest()
  # print(hs)

  a1 = Animal()
  print(a1.id)
  print(a1.name)
  print(a1.height)
  print(a1.get())

  a2 = Animal(name='Paul', height=183)
  print(a2.id)
  print(a2.name)
  print(a2.height)
  print(a2.get())

  a3 = Animal(name='George', height=105)
  print(a3.id)
  print(a3.name)
  print(a3.height)
  print(a3.get())

  del a1, a2, a3
```

```
% ./test1.py
d097b3d674dda8dec898a8e4def18ab1
John
180
26c1a6744fa3d9f7e63640a3a9a8f79a
Paul
183
('26c1a6744fa3d9f7e63640a3a9a8f79a', 'Paul', 183)
3caf70515aa5aa97c9ce6dffb58ce8f8
George
105
('3caf70515aa5aa97c9ce6dffb58ce8f8', 'George', 105)
d097b3d674dda8dec898a8e4def18ab1 is destruted...
26c1a6744fa3d9f7e63640a3a9a8f79a is destruted...
3caf70515aa5aa97c9ce6dffb58ce8f8 is destruted...
PS D:\MyWork\python-test\object-test> python .\test1.py
3580ad44cd6fcdf2b1576354954507df
John
180
('3580ad44cd6fcdf2b1576354954507df', 'John', 180)
c13b973b08263fbff9ddcaf64865277c
Paul
]]
183
('c13b973b08263fbff9ddcaf64865277c', 'Paul', 183)
c13b973b08263fbff9ddcaf64865277c
George
105
('c13b973b08263fbff9ddcaf64865277c', 'George', 105)
3580ad44cd6fcdf2b1576354954507df is destruted...
c13b973b08263fbff9ddcaf64865277c is destruted...
c13b973b08263fbff9ddcaf64865277c is destruted...
```
【javascript】レキシカルスコープ

# レキシカルスコープ
* コードを書く場所によって参照できる変数が変わるスコープ
* 「静的スコープ」ともいう
    * コードを記述した時点で決定するため。


## case

* fn1（）を実行するとfn2（） が実行される。

```js

let a = 2 //グローバルスコープ

function fn1(){
    let b = 1;
    function fn2(){
        let c = 3;
        console.log(b)
    }
    fn2();
}

fn1();

>>> 1
```

* fn1のスコープから外れたfn2（）を実行するとエラーがかえる。
* すなわちfn2から変数bは見えていない。
* つまり、関数を実行する場所によって使用できる変数が変わる。


```js
let a = 2
function fn1(){
    let b = 1;

}

function fn2(){
    let c = 3;
    console.log(b)
}
fn2();

>>> error
```

# まとめ

* スコープは内側から外側へのスコープは取れるが、外側から内側へのスコープは通らない。

イメージはこのような感じ

```js

// windowオブジェクトは最低レイヤーなので全ての関数から参照できる。
let a = 2 

function fn1(){
    let b = 1;
    console.log(a) //参照できる。(内〜外：○)
    console.log(c) //fn2の３章はできない（外〜内:×）
    function fn2(){
        let c = 3;
        console.log(a)//参照できる。(内〜外：○)
        console.log(b)//参照できる。(内〜外：○)
    }
    fn2();

}

fn1();





```
Vue3.2 で追加された expose のメモ


Vue 3.2 より `setup` 関数の第2引数の `context` に `expose` という関数が追加されました。

`expose` を使うことにより、そのコンポーネントが公開するプロパティを明示的に示すことができるようになります。

これについてのメモです。

公式ドキュメントはこちら

- [setup(日本語)](https://v3.ja.vuejs.org/api/options-composition.html#setup)
- [setup(英語)](https://v3.vuejs.org/api/options-composition.html#setup)

## 使い方

### 対象のコンポーネント

`script` 部分のみ抜粋

``` vue:ChildComponent.vue
<script>
export default {
  name: "ChildComponent",

  setup(props, context) {
    const func = () => {
      console.log("child func");
    };

    // funcを公開
    context.expose({
      func
    })

    return {
    }
  },
};
</script>
```

### 利用する側のコンポーネント

``` vue:Parent.vue
<template>
  <div>
    <ChildComponent ref="child" />

    <button @click="handleClick">click me!</button>
  </div>
</template>

<script>
import { ref } from "vue";
import ChildComponent from "./ChildComponent.vue";

export default {
  name: "Parent",
  components: {
    ChildComponent,
  },
  setup() {
    const child = ref(null);

    const handleClick = () => {
      // 公開されている関数を呼び出す
      child.value.func();
    };

    return {
      child,
      handleClick,
    };
  },
};
</script>
```

`expose` で公開された関数は`child.value.func()` のような形で利用することができます。

また `expose` を使ったコンポーネントは
下で挙げるような `return` に含めるものとは異なり `child.value` はまた別の形のインスタンスになっているようです。(`console.log(child.value)` をしてみて差異を比較するとわかります。)

## おわりに

これよりも前のバージョンでは 

``` js 
setup(props, context) {
  const func = () => {
    console.log("child func");
  };

  return {
    func
  }
},
```

このように `setup` 関数の中で`return` に含めて返すことで 同じことができましたが
テンプレートで利用しないものまで 含めるのは違和感がありました。

`expose` 関数を使うことで 「外部に公開するもの」「テンプレートで使うもの」を
明示的に示すことができるので このあたりの問題を解決することができるかなと思います。
terraform backendでs3(さくらのクラウド オブジェクトストレージ)を使う

terraform公式のbackendのs3設定を使用して、tfstateの保存先をさくらのクラウド オブジェクトストレージにします。
しかし、いくつかのエラーが発生するため設定を追加します。

リージョンに関するエラー

```bash
...
Error: Invalid AWS Region: jp-north-1
...
```

名前解決に関するエラー

```bash
...
Error: error using credentials to get account ID: error calling sts:GetCallerIdentity: RequestError: send request failed
caused by: Post https://sts.jp-north-1.amazonaws.com/: dial tcp: lookup sts.jp-north-1.amazonaws.com on **********: no such host
...
```

これらを解決して使用するために、以下の2つの設定を入れます。

```
skip_credentials_validation = true
skip_region_validation      = true
```

設定を入れた場合のHCLは以下の通りです。

例

```terraform 
terraform {
  backend "s3" {
    bucket = "tfstate" # バケット名
    key    = "terraform.tfstate"
    endpoint = "s3.isk01.sakurastorage.jp"
    region = "jp-north-1"
    access_key = "access_key" # アクセスキーID
    secret_key = "secret_key" # シークレットアクセスキー
    skip_credentials_validation = true
    skip_region_validation      = true
  }
}

resource "sakuracloud_server" "server" {
  name        = "server"
  core        = 1
  memory      = 1
  description = "server"

  network_interface {
    upstream         = "shared"
  }

  disk_edit_parameter {
    password        = "P@ssword!"
    disable_pw_auth = false
  }
  count = 1
}
```
php.ini の場所

よく忘れるので備忘録として。

## .ini ファイルの場所を調べる

```shell:shell
php -i |grep php.ini # または --info

# => Configuration File (php.ini) Path => /usr/local/etc/php このディレクトリから php.ini ファイルを探して
#    Loaded Configuration File => /usr/local/etc/php/php.ini このファルが php.ini として読み込まれている
```

## .ini ファイルとして読み込まれているファイルを調べる

```shell:shell
php -r 'echo php_ini_scanned_files();'

# => /usr/local/etc/php/conf.d/docker-php-ext-bcmath.ini,
#    /usr/local/etc/php/conf.d/docker-php-ext-intl.ini,
#    /usr/local/etc/php/conf.d/docker-php-ext-pdo_mysql.ini,
#    /usr/local/etc/php/conf.d/docker-php-ext-sodium.ini,
#    /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini,
#    /usr/local/etc/php/conf.d/docker-php-ext-zip.ini,
#    /usr/local/etc/php/conf.d/xdebug.ini
```

## .ini ファイルのスキャンディレクトリを調べる 

```shell:shell
php -r 'phpinfo();' | grep Scan   

# => Scan this dir for additional .ini files => /usr/local/etc/php/conf.d
#    /usr/local/etc/php/conf.d/*.ini  ファイルが設定ファイルとして読み込まれる
#    xdebugの設定などは、別ファイルに定義した方が良さそう。
```

https://www.php.net/manual/ja/configuration.file.php

## 補足
Dockerイメージ `php: 8.0-fpm-buster` などを使用している時は、
`/usr/local/etc/php` 配下に `php.ini` ファイルがある。
また、同ディレクトリ内に `conf.d` ディレクトリがあり、 その中の `.ini` ファイルがスキャンされている。

### さらに補足
上記のDockerイメージを使用している時に、 `/usr/local/etc` 配下に `php-fpm.conf` ファイルがある。
また、同ディレクトリ内に `php-fpm.d` ディレクトリがあり、その中の `.conf`がスキャンされていそう。(詳しく調べていないので推測)
こちらは、php-fpm の設定ファイル。
概念的には下記がわかりやすい気がします。

https://www.php.net/manual/ja/install.fpm.php

https://wa3.i-3-i.info/word12806.html
JAVAのWebサーバーにTLS1.3を適用する方法


古いWebサーバーはTLS1.0を使っていますが、TLS通信の安全性を上がるため、
TLS1.3にアップデートしようと思います。

## 1.暗号化スイートとは
SSL（Secure Sockets Layer）とTLS（Transport Layer Security）は、いずれもインターネット上でデータを暗号化して送受信する仕組み（プロトコル）です。個人情報やクレジットカード情報などの重要なデータを暗号化して、サーバ～PC間での通信を安全に行なうことができます。

## 2.今のTLSバージョンを確認してみて
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1234182/31622957-e9e8-7bfe-5b57-5897e6595899.png)

えぇぇ！TLS1.3までアップデートしてなっかたのに、
なぜTLS1.3になっているでしょうか？


## 3.TLS1.3に変わる原因は？
ネットから調べたんですが、
TLS 1.0および1.1は、安全とは見なされなくなったTLSプロトコルのバージョンであり、
より安全で最新のバージョン（TLS 1.2および1.3）に取って代わられています。
これらのバージョンは、デフォルトで無効になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1234182/fa31d8e4-d63b-0d6e-01c9-ab5cf95e612e.png)

参照URL：
https://www.oracle.com/java/technologies/javase/11all-relnotes.html#JDK-8202343


## 4.結論
JDK11.0.11以降、TLS 1.0 and 1.1が既に無効になるので、
WebサーバーでSSLの初期化設定(SSLContext)を修正しなくても、
TLS1.3になっています。
ゲームの魅力的品質を助けるレビュー「で、そのゲーム面白いの？」

# はじめに
　ここではゲームQAにおけるレビューについて記載します。
とは言いつつ自身はいくつかの案件で実際にレビューをする仕事をしただけの若輩なので、そこで得た経験から思うことをダラダラと書き綴っていきたいと思います。

# レビューとは？
　名の通り、そのゲームを批評します。
ゲームでの良い所・悪い所を分析して、改善点を導き出すのが大まかな仕事内容になります。

# レビューの役割
　ゲームにとって
「デバッグは**遊べる**ように品質を上げるもの」とすれば、
「レビューは**楽しめる**ように品質を上げるもの」が役割です。
界隈で言われている当たり前品質・魅力的品質のことで、特にこの魅力的品質を高める意味合いが強いものになります。

# レビューで気を付けること
ここからは実際の案件を通して自分が注意するようになったポイントを紹介したいと思います。

1. <font color="red">**一番大事なのはそのゲームが面白いか否か**</font>
　当記事の題目でもあるのですが、作成したレビューを確認してもらおうと上司に見せると「で、このゲーム面白いの？」とよく聞かれたことがあります。
「各要素は評価出来てるけど結局の所、現状でこのゲームが面白いのかつまらないのかが文面から伝わってこない」文章になってしまっていたのです。
各要素を分析するのは勿論それらを総合的に踏まえた時、現状このゲームは面白いのかつまらないのか、評価した全ての要素はそこに集約するように文章を纏めることが肝要です。

1. <font color="red">**空気を読まない**</font>
　大事です、特に**悪い所を評価する時は。**
人は悪い所を指摘されると、どんなにそれが正当な理由であろうともいい気はしないものです。
実際に完成したレビュー資料を上司が先方に報告しに行くと、最初は笑顔だったのに段々と目が笑わなくなっていって居心地が悪かったと聞いたことがあります。
ですが、そんな事を気にしていたらそのゲームが面白くなりません。
**悪い所はハッキリと指摘する。**

1. <font color="red">**空気はちゃんと読む**</font>
　先程は空気を読むなと言いましたが、ここで言う空気は別の話。
それは**相手に伝える時**です。大事、言葉遣い。
良い所はともかく、悪い所を明け透けに伝えると人は大体不機嫌になります。
要点はぼかさない且つ言い回しはマイルドに気を付ける。**語学力が問われます。**
細かい書き方は省きますが、例えば
「〇〇の操作が（理由）のせいで面倒くさい」
→「〇〇が（理由）によって操作しづらく手間に感じてしまう」といった感じ。
シンプルな悪口は避けるのが世渡りのコツではないでしょうか。

1. <font color="red">**何も感じなかった所にこそレビューする要素がある、かも？**</font>
　良い所・悪い所は結構スラスラと出てくるものです。
ここで一度振り返っておきたいのが**自分では何も感じない箇所**がある場合です。
例えば、チュートリアルがあるゲームでその最後に「まずはこれをやってみよう」みたいな導線が無かった場合。
人によっては「とりあえず色々触ってみるか」となってそのままプレイしますが、別の人によっては「この後何をやればいいか分からなくてやめた」となってゲームを遊ばなくなる場合もあります。
自分が前者だった場合、「チュートリアルの最後に導線がない事」は「何も感じない」要素となりますが、後者にとっては「チュートリアルが不親切で遊びづらい」というネガティブな要素になってしまいます。
こういった、自分では感じなかったけど他の人だったら…と考えることもレビューをする上での一つのテクニックかなと思います。

# **〆の挨拶**
　以上、自分が実務を通して学んだレビューで注意していたことについて簡素ではありますが記載してみました。
最後まで読んで下さりありがとうございました。
[JavaScript]イベントリスナー登録

# イベントリスナーとは
webページにおける「ボタンのクリック」や「キーの入力」などのユーザーの操作やページの読み込みなどを「***イベント***」という。***イベントリスナー***とは、そのイベントの発生を監視し、発生したイベントに対応して実行される処理（関数）のこと。
また、イベントが発生することを「***イベントが発火する***」ともいう。

# イベントリスナー登録
対象要素（オブジェクト）にイベントリスナーを```addEventListener()```を使って登録する。```addEventListener()```の書き方は以下のようになる。

```javascript:
<対象要素(オブジェクト)>.addEventListener(<イベントの種類>,<関数>,<イベント伝搬形式>)
```
【各引数について】
■ ***イベントの種類***：
登録するイベント（'click'、'mousedown'など）を指定する。
イベントの種類については、MDNのイベント一覧を参照。（[MDNのイベント一覧](https://developer.mozilla.org/ja/docs/Web/Events#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%AE%E4%B8%80%E8%A6%A7)）
■ ***関数***：
イベントが発生したときに実行される処理を指定する。
■ ***イベントの伝搬形式***：
イベントの伝搬形式を```true```/```false```で指定できる。通常は、```false```で省略することも可能。

また、対象要素（オブジェクト）を取得するためには、```getElementById()```を使用する。これは、引数に指定されたid属性の値に対応した要素のElementオブジェクトを返す。

```javascript
document.getElementById(<id>)
```

# 実装
上記のことを使って、ボタンが押されたときにメッセージを表示するように実装すると以下となる。

```html:HTML
<button id = "message"> メッセージ </button>
```

```javascript:JavaScript
let button = document.getElementById("message");
button.addEventListener('click'()=>{
    alert("ボタンが押されました！");
});
```
PhoneixアプリをreleaseでGigalixirにデプロイするのが良い理由

[mix release](https://hexdocs.pm/mix/1.12/Mix.Tasks.Release.html#module-customization)を使ってPhoenixアプリをgigalixirにデプロイする理由について。

# なぜGigalixirなのか
PhoenixアプリをデプロイするPaasは[ドキュメント](https://hexdocs.pm/phoenix/deployment.html#content)で３つ紹介されています。
1. Gigalxir
2. Fly.io
3. Heroku

他にCommunity Deployment Guidesとして
4. render.com
の[リンク](https://render.com/docs/deploy-phoenix)もあります。

Gigalixirを選んだ理由は[こちらの記事](https://staknine.com/best-cloud-hosting-platforms-elixir-phoenix/)で上記の四つの候補を比較してGigalixirがベストだと言及されていたからです。
選出理由としては、Dockerの設定が不要、Elxiirに特化していることなどが挙げられています。
とはいえ結局は最終的にどの手段ででプリロイするのかは各開発者次第です。

Chris Mccord氏がfly.ioに就職したこと、fly.ioがLiveBookのスポンサーになったことなどから今後はfly.ioでのデプロイも充実していくものと考えられます。

# そもそもAWSやGCPにデプロイすればいいのでは？
Gigalixirは内部的にAWSやGCPを使っており、開発者自身が自分でAWSやGCPにデプロイするよりも手順が簡単になっておりGigalixirを採用するメリットは十分にあるのではないかと思います。しかしGigalixirではできないことをしたい場合は情報が少ないかもしれませんが、自前でAWSやGCPにデプロイする必要が出てくるかもしれません。

# なぜreleaseなのか
[ドキュメント](https://hexdocs.pm/mix/1.12/Mix.Tasks.Release.html#module-customization)ではreleaseを使う理由を以下のように説明しています。以下 Google翻訳

- コードのプリロード
VMには、コードをロードするための2つのメカニズムがあります。インタラクティブと埋め込みです。デフォルトでは、モジュールが初めて使用されるときに動的にモジュールをロードするインタラクティブモードで実行されます。アプリケーションが初めてEnum.map/2を呼び出すと、VMはEnumモジュールを見つけてロードします。欠点があります。本番環境で新しいサーバーを起動すると、他の多くのモジュールをロードする必要があり、最初のリクエストの応答時間が異常に急上昇する可能性があります。 23より前のErlang / OTPで実行している場合、システムは常に組み込みモードで実行されます。 Erlang / OTP 23+を使用する場合、構成中はインタラクティブモードで実行され、その後組み込みモードに切り替わり、システムが起動後にリクエストを処理できるようになります。

- 構成とカスタマイズ
リリースにより、開発者はシステム構成とシステムの起動に使用されるVMフラグをきめ細かく制御できます。

- 自己完結型
リリースでは、ソースコードを本番アーティファクトに含める必要はありません。すべてのコードはプリコンパイルされ、パッケージ化されています。リリースにはErlangVMとそのランタイムがデフォルトで含まれているため、サーバーにErlangやElixirも必要ありません。さらに、ErlangとElixirの両方の標準ライブラリが削除され、実際に使用しているパーツのみが表示されます。

- 複数のリリース
アプリケーションごとに、またはアプリケーション全体でさえ、異なる構成で異なるリリースをアセンブルできます。

- 管理スクリプト
リリースには、起動、再起動、実行中のシステムへのリモート接続、RPC呼び出しの実行、デーモンとしての実行、Windowsサービスとしての実行などのスクリプトが付属しています。

# 色々選択肢があること自体が素晴らしい
今でこそPaasのプロバイダーが増えていて、どれを選ぶのかを迷うことができますが、過去にはHerokuしかなかった時期があったはずですし、Elixir v1.9以前はreleaseもなかったことを考えるとElixir コミュニティーの発展ぶりに感心します。
寄与した多くの開発者に感謝します😌


# チュートリアルのリンク集
https://hexdocs.pm/phoenix/gigalixir.html#content
https://staknine.com/deploy-phoenix-to-gigalixir-using-elixir-releases/
https://dev.to/miguelcoba/deploying-an-elixir-release-to-gigalixir-2d80
Explore - "Blender 3.0 Tutorial - Create Gold Coins"

https://www.youtube.com/watch?v=tf15MaVEfUo

# 新しく知ったこと
+ Bebelの分割数をホイールで調整できること。
+ 画像の透過度の変更方法。
+ Iでの面の挿入時に左下のパネルのindividualでそれぞれの面に対して個別に挿入できること。
+ Opt+LMBで繋がってる辺をまとめて選択できること。

# 調べたこと
None

# 感想
コインの横のギザギザを作るときにスケールの機能を利用したのが賢いなり。

# 成果物
![Coin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2316614/725f3e2d-5fb9-cb02-bb99-2b22a4cc9ece.png)
TypeScriptメモ 〜変数編〜

### 型アノテーション

変数には型がある。変数には決められた型の変数しか代入できない。
**型アノテーション**は明示的に型を示す方法。

```typescript:
let x = 1 // number型が自動的に決まる
let y: number // number型を明示的に指定
y = 1
y = '1' // エラー
```
### any型

以下のスクリプトは問題なく実行できる。xにはany型が指定されるため。

```typescript:
let x 
x = 123
x = 'ok'
```

### 型変換

テキストを数値に変換する時は変数に+をつける

```typescript:
let x = '1'
+x
```
または関数を利用する

```typescript:
let x = '1'
x = Number(x)
```

### 配列

型アノテーション

```typescript
const a: number[] = [1,2,3]
```

配列の中身を変更できなくする

```typescript
const a: readonly number[] = [1,2,3]
```

**タプル型**
配列に複数の型の値を入れられる

```typescript
const a:[string, number]
```

### enum型

多数の中から一つを選ぶ場合

```typescript
enum janken { goo, choki, paa }
let goo = janken.goo
```

**enum型は何も代入していない場合数値が入っているので注意**

```typescript
enum Gender { 
    male = 'male',
    female = 'female',
    other = 'other'
}
console.log(Gender.female) // 'female'

enum Season {
  spring, 
  summer, 
  autumn, 
  winter
}
console.log(Season.autumn) // 2
```

### 型のエイリアス

型名にエイリアスを設けることでわかりやすくなる。

```typescript
type name = string
type age = number
let me:[name, age]
```

### typeで型を定義する

タプル型そのものにエイリアスを作成できる。

```typescript
type name = string
type age = number
type email = string
type person = [name, age, email]

const taro: person = ['taro', 20, 'foo@bar.com']
```

### リテラル型

リテラルを方にできる

```typescript
type ok = 'ok'
let ok:ok
ok = 'ok'
ok = 'foo' // error!
```

### 条件型

```typescript
type msg = 'hello' | 'bye'
type id = number | string
```

### 型チェック

typeofを使用

```typescript
type id = number | string
let x:id = 1
let y:id = 'taro'
console.log(typeof(x)) // 'number'
console.log(typeof(y)) // 'string'
```

### ユーティリティ型

変数に様々な性質を付加する特殊な型。

```typescript
type data = [string, number]
// 値の変更不可なdata型を定義
type ReqData = Readonly<data>

const x:data = ['foo', 20]
const y:ReqData = ['bar', 40]
```

### シンボル

一意な値であることが保証された型。

```typescript
const a:unique symbol = Symbol('ok')
const b:unique symbol = Symbol('ok')
console.log(a === b) // false
console.log(a == b) // false
```

### nullかもしれない値

```typescript
type data = [name:string, age?:number]
```

### 絶対にnullではない値

```typescript
type data = [name!:string, age:number]
```
Webの勉強はじめてみた その2 ～HTML基礎と気になったこと～

2つやろうと思ったんですが、疲れたので1つだけ。

<h2>今日やったこと</h2>

:::note
h/ p/ a/ img/ ul/ ol/ table タグ
:::

<h2>気付いたこと</h2>
:::note
h1～h6：余白の大きさも変わる。
p：前後に適当な余白ができる。
:::
余白の考え方というか、たとえばpを二つ並べたときに真ん中にできる余白はどう考えるのか。和になるのか相殺されるのか。

大きいほうが優先？

https://www.nishishi.com/css/box-paramargin.html


:::note warn
a：target="_blank"の脆弱性とは。
:::

動画では本筋とあまり関係ない話として軽く触れられただけだったので調べてみた。

こちら具体例があって理解しやすかったです。
https://lpeg.info/security/target_blank.html

:::note warn
tableタグは現在あまり推奨されていないらしい。
:::
flexboxというのがあるらしい。
floatもないの？
このあたりは多分少し先の講義でわかるのかな？

<h2>まとめ</h2>
VS CodeのEmmet機能がちょっとした呪文。
`table>(tr>th*2)+(tr>td*2)*6`
[Kotlin][Exposed] Daoでも動的Where句生成がしたい！

# 概要
たとえば検索系のApiなどは、動的にwhere句を生成するロジックを書くケースがしばしばある。指定される検索条件が、状況により変わるためだ。
当記事は、**Kotlin**製ORM **Exposed** で動的にWhere句を書くときのサンプル、特に**Dao**の利用時のそれをまとめたものである。

# DSLではすんなり書けるのに
**DSL**でselect句を使うときは `select` ないし `selectAll` メソッドを使う。

```kotlin
fun selectBy(name: String?, hobby: String?): List<Person> {
    val query = Persons.selectAll()

    name?.let {
        query.andWhere { Persons.name eq it }
    }
    //...後略
}
```
<details><summary>(前提のコード)</summary><div>

```kotlin
object Persons : IntIdTable("persons") {
    val name = varchar("name", 50).nullable()
    val hobby = varchar("hobby", 50).nullable()
}

class PersonEntity(id: EntityID<Int>) : IntEntity(id) {
    companion object : IntEntityClass<PersonEntity>(Persons)

    val name by Persons.name
    val hobby by Persons.hobby

    fun toModel(): Person = Person(name = name, hobby = hobby)
}

data class Person(
    val name: String?,
    val hobby: String?,
)
// SQLは省略
```
</div></details>

各種のselectメソッドは*Query*型を返す。Query型は**andWhere**などのApiが整備されており、動的なwhere句の組み立てロジックも直感的に書ける。[^1]

…ところが**Dao版select句**にあたる`find`メソッドは、返り値を *SizedIterable* 型で返す。これはSQLの実行結果そのもので、抽出条件を差し込む余地はここにない。
これではDSLと同じには書けない。**じゃあどう書くのだ。**


# Daoでもすんなり書きたい

**Dao**を使ってDSLと同じように書こうとすると、こんな感じになる。

```kotlin
fun selectBy(name: String?, hobby: String?): List<Person> {
    val entities = PersonEntity.find {
        mutableListOf<Op<Boolean>>(Op.TRUE).apply {
            name?.let {
                add(Persons.name eq it)
            }
            // ...中略
        }.compoundAnd()
    }
    // ...後略
}
```
`find`メソッドの引数に、もろもろの抽出条件を**ガッチャンコ**するロジックを詰め込むことになる。

**compoundAnd**は、*List*型で渡された`Op`(抽出条件)を、**AND**キーワードによってひとつに結合した結果を返す。
Listの初期化時に *Op.TRUE* を詰めているのは、Listの要素数が0個になるとcompoundAndが例外を吐くためだ(Op.TRUEは無意味な抽出条件)。

# むすび
DSLは公式のサンプルがある一方Daoは無く、公式以外のサンプルも見当たらなかったので、参考までに置いておきます。
サンプルコード全体は[github](https://github.com/satotats/kotlin-training/blob/master/src/main/kotlin/com/satotats/exercise/kotlin/exposed/dynamicwhere/daoSelectSample.kt)をご参照ください。

[^1]: この方法は[公式wikiでも紹介されています。](https://github.com/JetBrains/Exposed/wiki/DSL#conditional-where)
Dynamics365 OAuth接続用のサンプルAppIdとRedirectUri

Office365認証が廃止になり、外部アプリケーションからdataverseへの接続はOAuth認証で接続必要になっています。
OAuth認証用のAppIdは、Azure Active Directory側で作成するため、少し手順と手間が発生します。
 
開発時、迅速的に動作確認したい、または一時環境へ接続したい場合は、以下のMSから提供するAppIdを利用すれば、どのUserでも接続可能です。
https://docs.microsoft.com/ja-jp/powerapps/developer/data-platform/xrm-tooling/use-connection-strings-xrm-tooling-connect
![MicrosoftTeams-image (19).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/9d1a81b0-09f1-7914-bb24-0aec248df839.png)
商用環境は非推奨と記述されていますので、商用環境では正式なAppIdを登録して頂き、アプリケーションユーザーとして利用することをお勧め
また、ApplicationUserの登録は、PowerPlatformの管理センタからよりシンプルで登録できるようになりました。
https://docs.microsoft.com/en-us/power-platform/admin/manage-application-users#view-or-edit-the-details-of-an-application-user
XrmToolbox Tool:Access Checker

XrmToolboxにあるAccess Checkerのツールはさらに機能増強されました。ユーザーがどのロール、どのTeam経由でアクセス権限を獲得したか、レコード共有でアクセス権限を獲得したか、より分かりやすく確認できます。権限関連調査の場合活用できるかと思います。
![MicrosoftTeams-image (18).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2307534/1946d85a-922d-400c-7a90-0304b186ba2d.png)

詳細と使い方は以下のBlogを参考してください。

https://linked365.blog/2021/09/01/access-checker-xrmtoolbox-tool/
expoでソケット通信する記事が日本語で1記事もない件


<h3>記事を書こうと思った理由</h3>
実務で、ネイティブアプリを作ることになりました。前のプロジェクトではVue.jsを使っていたため、スマホアプリでもReactNativeを選択しました。


今回は、httpプロトコルが使えないので、まずは、ソケット通信する必要があります。いつものようにやり方をグーグル先生に聞くと、日本語の記事が一つもない！？


私と同じように何日も沼にはまらないようにこの記事を書こうと思った次第です。


<h3>前提</h3>
ReactNative初学者の人は、まず間違いなくexpoを使って開発すると思います。入門書やUdemyもほぼexpo前提で構成されています。

expoはコマンド一発で、各デバイス用のビルドができるし、ストアへのリリースもとても簡単であることが理由だと思います。

しかしこいつは、ネイティブのモジュールが使えません。便利ゆえの欠点ですね。社内にスマホエンジニアがいないので、ビルド周りでエラーが出たら、なおせる気がしなかった私は、どうしてもexpoを使いたかったわけです。

<h3>解決方法</h3>
react-native-tcp-socketというものを使えば、どうやらソケット通信できます。しかしこいつはネイティブのモジュールであるがゆえにexpoでは使用できません。

https://www.npmjs.com/package/react-native-tcp-socket

そこで使用するのはeas(Expo Application Services)。これを使えば、ネイティブのモジュールをexpoで使えます。環境構築は、公式ドキュメントを参考にしてください。↓

https://blog.expo.dev/introducing-eas-395d4809cc6f


npmのドキュメントに書いてある通りに関数を作り、IPとportを入れて頂ければ、ソケット通信完了です！

sample

```React
const onclick = () => {
    // Create socket
    try {
      const client = TcpSocket.createConnection(
        {
          port: port,
          host: IP
        }
        , () => {
          // Write on the socket
          client.write('Hello server!');
          alert("成功")
          // Close socket
          client.destroy();
        });
    } catch (e) {
      alert("失敗", e)
    }
  }
```
CodeIgniter3でViewファイルをもとにHTMLファイルを出力する

こんなこと誰かがやってそうなもんですけど、全然記事が見つからないので
自分で実装することにしました。~~今更こんな枯れたフレームワーク使ってるとこないか~~
もっと良い方法あったら教えてちょ

```bash
# ファイル出力テスト用のディレクトリを作成して書き込み権限を付与
mkdir /var/www/html/test/
sudo chmod -R 777 /var/www/html/test/
# ファイル出力テスト用のControllerを作成
touch /var/www/html/admin/application/controllers/tools/View.php
# ファイル出力テスト用のViewを作成(レンダリングにはTwigライブラリが必要です)
touch /var/www/html/admin/application/views/user/test/hello.twig.html
```

```php:/var/www/html/admin/application/controllers/tools/View.php

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class View extends CI_Controller
{
    public function __construct()
    {
        parent::__construct();
        $this->load->helper("file");
    }

    public function test_output()
    {
        $data = "Hello World";

        // FCPATH は "/var/www/html/admin/public" を返す( "/var/www/html/admin/public/index.php" で定義)

        if (write_file(FCPATH . '../../test/hello.html', $data) == FALSE){
            echo 'Unable to write the file';
        }
        else {
            echo 'File written!';
        }
    }

    public function test_output2()
    {
        $this->load->library('twig');

        $filePath = "user/test/hello";

        $data = array(
            "test" => "Hello World2"
        );

        $html = $this->twig->render($filePath, $data);

        if (write_file(FCPATH . '../../test/hello2.html', $html) == FALSE){
            echo 'Unable to write the file';
        } else {
            echo 'File written!';
        }
    }
}

```

```html:/var/www/html/admin/application/views/user/test/hello.twig.html
<!DOCTYPE html>
<html>
<head></head>
<body>
<p>{{ test }}</p>
</body>
</html>
```

`http://www.example.com/admin/tools/view/test_output` にアクセスすれば、以下の場所にHTMLファイルが出力されます

```bash
cat /var/www/html/test/hello.html

Hello World
```


`http://www.example.com/admin/tools/view/test_output2` にアクセスすれば、以下の場所にHTMLファイルが出力されます

```html
cat /var/www/html/test/hello2.html

<!DOCTYPE html>
<html>
<head></head>
<body>
<p>Hello World2</p>
</body>
</html>
```
Rubyプログラミング問題にチャレンジ! suzuki_mar 

この記事は、 @jnchitoさんのアドベントカレンダーの[Rubyプログラミング問題にチャレンジ！](https://qiita.com/advent-calendar/2021/ruby-challenge)の12月5日の担当分です。
詳しいレギュレーションは、問題のGitHubの[URL](https://github.com/JunichiIto/tenji-maker-challenge)を参照してください。
[PRのURL](https://github.com/JunichiIto/tenji-maker-challenge/pull/11)

# ロジックの解説
## 用語

| 名前 | 英語 | 説明 |
|:-----------|------------:|:------------:|
|マス|square| 点字の中の一つの点|
|点字|Tenji| マスが一つの組み合わせになったもの 点字の組み合わせで文字に対応している|
|マーク|mark|点字を組み合わせた単語(文字列)|



![スクリーンショット 2021-11-24 14.14.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46364/c7ec90a3-5550-7422-f3fe-0171b5271958.png)

### 点字のルール
> 点字は、縦３点、横２点の６点の組み合わせで作られています。そして、この単位をマスと言います。
下の図をみてください。この図の①②④の点を組み合わせて母音を表し③⑤⑥の点を組み合わせて子音を表します。

引用元 [全視情協](http://www.naiiv.net/braille/?tenji-sikumi)

## クラス説明
### TenjiMaker

今回の問題のmain関数である、```TenjiMaker.to_tenji(text)```を定義しています。
可読性を高くするために抽象度が高く理解容易性が高くなるようにしています。
自分は点字を一文字単位で扱っているため点字が複数ある、```TenjisMaker```としたほうが自然だと思いますが、問題のルール上単数形の```TenjiMaker```になっています

### Tenji
#### クラスの説明
点字を表しているクラスです。
このクラスは表示する文字列 "○" とかと関係性をもっていないので、
例えば出力をコンソール(CLI)ではなくて、ブラウザ(HTML)に変更する仕様追加が発生した場合も柔軟に対応できると思います。

#### や行について
や行は特殊なルールがありますが、そのルールはや行だけなのでロジックを実装するとわかりづらくなったり、バグが発生する可能性があるためハードコーディングをしています。

### MarkBuilder
渡された点字をもとに表示するマークを生成します。
このクラスはマークを生成することに特化しているクラスなので、状態を持たないイミュータブルなクラスにしています。
(Railsでいうサービスクラスです)

### テストのメソッド名について
自分は英語が苦手なのと、このコードを見る人の殆どは日本人だと思います。
そのため、テストのメソッド名については日本語で補足を書いています。

## コードのアピールポイント
- 頑張ったところ
    - マーク(コマンドで表示する文字列)を生成する部分が点字を複数組み合わせて行の文字列を生成するので、直感的な仕様ではないです
    - そのため実装するのが少しだけ大変でした
- 苦労したところ
    - MiniTestをはじめて扱うのでキャッチアップやRspecとの書き方の違いが少しだけわかりづらかったことが苦労しました
- 工夫したところ
    - コードとこのドキュメントがあれば、点字について理解できるように意識しました
- 自慢したいところ
    - 拡張性もあると思うのでもし今後、複雑な点字のルールを実装することになっても実装しやすいのではないかと思います
    - 点字についてわからないエンジニアでもコードを理解しやすいのではないかと思います
        - 点字のルールはTenjiクラスをみればわかると思います
        - 表示する文字列(マーク)についてはMarkBuilderをみればわかると思います

## 伊藤さんにメッセージ
- 点字については全くの知識がなかったのですが、今回の実装した範囲内であれば説明できるようになったので、少しだけ点字が身近に感じました
- 著名な方にレビューをしてもらうのはじめてですので緊張していますw
findコマンドで一部のディレクトリを除外した際に得た理解

findコマンドで一部のディレクトリを除外するためにpruneというオプションを利用した。このときに得た理解をメモしておく。

# 「find ディレクトリ 除外」で検索するとfindコマンドとpruneオプションを利用したテクニックが手に入る

Googleで「_find ディレクトリ 除外_」などで検索すると__prune__オプションを利用したコマンド例が挙がってくる。

```bash
#「test-」から始まるディレクトリを除外し、一覧する
find . -type d -name "test-*" -prune -o -print
```

## 実行例を検証

実行は前提として[このようなディレクトリ構成](#前提)を想定し実行している



そして、findコマンドを実行してみる。

```bash
$ find . -type d -name "test-*" -prune -o -print
.
./file2.txt
./file1.txt
./hoge-dir1
./hoge-dir1/file2.txt
./hoge-dir1/file1.txt
./hoge-dir2
./hoge-dir2/file2.txt
./hoge-dir2/file1.txt
./hoge-dir3
./hoge-dir3/file2.txt
./hoge-dir3/file1.txt
```

確かに、_test-*_から始まるディレクトリが除外された一覧が取得出来る。

## 新しい疑問　「-o -print」って何だ

このとき、「findコマンドでpruneオプションを利用すれば、特定のディレクトリが除外できるんだ！」と理解したのだが、新しい疑問が生まれ混乱した。「-o -printオプション」はなんで必要なんだ。

# prune オプションは除外するオプションではない

結果的にはpruneオプションを利用することで要求を解決出来るのだが、この時に「pruneオプションは、除外するためのオプション」という理解をするのは混乱を招く。

## 前提

以下のような構成のディレクトリを前提に話を進めている。

```bash
$ tree
.
├── file1.txt
├── file2.txt
├── hoge-dir1
│   ├── file1.txt
│   └── file2.txt
├── hoge-dir2
│   ├── file1.txt
│   └── file2.txt
├── hoge-dir3
│   ├── file1.txt
│   └── file2.txt
├── test-dir1
│   ├── file1.txt
│   ├── file2.txt
│   ├── test-dir1
│   │   ├── file1.txt
│   │   ├── file2.txt
│   │   ├── test-file1.txt
│   │   └── test-file2.txt
│   ├── test-file1.txt
│   └── test-file2.txt
├── test-dir2
│   ├── file1.txt
│   ├── file2.txt
│   └── test-dir
│       ├── file1.txt
│       ├── file2.txt
│       ├── test-file1.txt
│       └── test-file2.txt
└── test-dir3
    ├── file1.txt
    ├── file2.txt
    └── test-dir3
        ├── file1.txt
        ├── file2.txt
        ├── test-file1.txt
        └── test-file2.txt
```


## pruneオプションは真を返す

findコマンドでpruneオプションを付加した場合、条件に該当するモノを見つけ結果として真を返す。

それがディレクトリだった場合は、そのディレクトリのより下の階層の検索は行わない。この動作を枝刈り、枝切り、枝探し、切り取りと表現していて、pruneの動詞的な意味なんだと理解出来る。

### 実行例

実際にコマンドを実行してみると、以下のような結果が得られる。

```bash
$ find . -type d -name "test-*" -prune
./test-dir1
./test-dir2
./test-dir3
```

findは結果が真だった場合、その対象を標準出力にパス付きで表示するようになっているらしい。そのため、「_test-_」から始まる3つのディレクトリは結果が真となり出力される。さらにこれらのディレクトリの中には「_test-_」から始まるディレクトリが含まれているが、pruneオプションによって`真となったディレクトリより下のディレクトリは検索しない`という動作になる為それらは出力(検査)されない。


## -o はORの意味
findコマンドを利用する際に複数の条件を論理和として評価したい場合に使う。

はい、でしょうね。知ってました。で、何故それが必要なのか。そして右辺で-printする理由。その結果特定のディレクトリを除外した結果が得られるのか。

## -print は標準出力への結果出力

__findでは結果が真となったファイルやディレクトリをパス付きで標準出力に出力する__と説明は実は言葉足らず。この動作は`−printなどのオプションがfindコマンドに指定されていない場合`の話。
今回のコマンド構成の場合、-oオプションの右辺に-printが指定されているため、左辺の結果に対する出力が行われないことになる。右辺の真に対してのみ出力が行われる。

## -pruneオプションによって結果が除外されるのはなぜ

今回のコマンドの構成を改めて確認して見る。

```bash
#「test-」から始まるディレクトリを除外し、一覧する
find . -type d -name "test-*" -prune -o                    -print
#      ~~~~~~左辺の条件~~~~~~            ~~~~~~右辺の条件~~~~~~ 
```

### 左辺の条件
　__-type d -name "test-*"__この条件を満たしたファイルは真となる。

### 右辺の条件

何もない、要は無条件。

### 短絡評価ってことか

`ORで繋がれた二つの条件がある場合、一つ目の条件が真である場合二つ目の評価をする必要がない。だから二つ目を評価しない`

1. 要するに、左辺の条件を満たファイルはpruneオプションによって真となる。その為、右辺の処理がされないことになる。printオプションは右辺にあるため、右辺を評価しない場合は出力されないことになる。
1. 左辺の条件を満たさなかった場合はどうなるかというと、右辺の条件が評価される。
1. しかし、右辺には条件がない->要するに__無条件__。無条件で__-print__されることになる。