OmniAICreator/Qiita-1.07M huggingface dataset:
Blenderチャレンジ：らせんトーラス

3DCGソフトウェアのBlenderを使って、お題のモデルを作成してみましょう。
やり方は一通りではないと思います。あなたは、どんな方法を考えますか？

## 問題

下図のようなモデルを作成してください（色はだいたいでOK）。

![スクリーンショット 2021-12-12 17.13.28.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/9fbd1041-98b7-7591-5304-12fa77e0d24a.jpeg)

[完成物をSketchfabで見る](https://skfb.ly/orXwK)

※ できれば、テクスチャを使わない方法で

…
…
…

OK？

---

## 解答例

作成する手順です。

- `Shift + A`の追加で「カーブ」→「円」で円を追加します。名前を`BezierCircle`とします。
- アドオンの「Add Mesh: Extra Objects」を有効にします。
- `Shift + A`の追加で「メッシュ」→「Single Vert」→「Add Single Vert」で点を追加します（編集モードに入ることに注意）。
- `GX.25`、`[Enter]`（`0.25 = 0.5 / 2`、寸法`Z`の半分）
- `EZ.5236`、`[Enter]`（`0.5236 ≒ π / 6`）
- `A`、「細分化」、さらに「細分化」
- `[Tab]`でオブジェクトモードにします。
- マテリアルを追加し、赤にします。
- 「スクリュー」モディファイアーを追加し、「スクリュー」を`1.0472`に、「反復」を`6`にします（`1.0472 ≒ π / 3`）。
- 「カーブ」モディファイアーを追加し、「カーブオブジェクト」を`BezierCircle`に、「変形軸」を`Z`にします。

![スクリーンショット 2021-12-12 19.13.39.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/399216bb-0c8d-c438-de29-5ab9efd9fa68.jpeg)

- `Shift + D`、`RZ180`、`[Enter]`
- マテリアルをシングルユーザー化し、青にします。

以上
テキストファイルのURLを抽出



```
grep -oE 'http(s?)://[0-9a-zA-Z?=#+_&:/.%\-]+' <file> 
```


```
open -a '/Applications/Google Chrome.app'
```

```
grep -oE 'http(s?)://[0-9a-zA-Z?=#+_&:/.%\-]+' <file>  |  xargs open -a '/Applications/Google Chrome.app'
```

SHIFTからUTF-8に変換する

```
 nkf -w <file>
```


『』　の文字を抽出

```
 nkf -w <file> | grep -oE '『.*』' | tr -d 『』
```

『』の文字を抽出して画面に表示するのみ（テキストの順番通り）

```
nkf -w 621-1.txt | grep -oE '『.*』' | sed 's/』/』\n/ '| grep -oE '『.*』' | sed 's/』/』\n/ '| grep -oE '『.*』' | tr -d 『』
```


『』の文字を抽出して、Chromeで検索する。ソートしている。

```
nkf -w 621-1.txt | grep -oE '『.*』' | sed 's/』/』\n/ '| grep -oE '『.*』' | sed 's/』/』\n/ '| sed 's/'\''// ' | grep -oE '『.*』' | tr -d 『』| sort | uniq | xargs -I {} open -a "Google Chrome" "https://google.co.jp/search?q={}"
```
Visual Studio Code で Python のプログラムを書いてみた(その1)

---
**はじめに**
Visual Studio Code で Python のプログラムを作成し Exe にして実行した。
Raspberry Pi 上のエディタで簡単なプログラムを作ったが Visual Studio Code では、初体験。

簡単にまとめてみた。

が、これだけではダメであった。下記を参考して下さい。
参考：[Visual Studio Code で Python のプログラムを書いてみた(その2)](https://qiita.com/ytetsuo/items/b361f02c824ea12b3e34)

---
2024年12月17日追記
【Visual Studio Code を初期化する方法】
PowerShellを開いて以下のコマンドを実行
~~~
>Remove-Item -Recurse -Force $env:USERPROFILE\.vscode
>Remove-Item -Recurse -Force $env:APPDATA\Code
~~~
日本語化をするには、【EXTENSIONS】(Ctrl+Shift+X)において
Japanese Language Pack for Visual Studio Code
をインストールする

---
１．Visual Studio Code の拡張機能として Python extension for Visual Studio Code をインストールした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2056854/2029fcd8-9d52-ff2f-4d53-b50e34dc6a9b.png)

２．<ファイル>-<新規作成>-<言語の選択> より Python を選ぶ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2056854/d8358176-1d62-3221-10e9-06b25a3abdae.png)

３.簡単なプログラムを書く

~~~
print("Hello Python!")
~~~

４．<実行>-<デバッグなしで実行> を行えば ターミナルに Hello Python! と表示される

５. Exe に変換するために pyinstaller を下記手順で ターミナル上で インストールする

~~~
pip install pyinstaller
~~~

６. 実際にExe を以下の様にして作成する

~~~
pyinstaller hello.py --onefile
~~~

ソースコードを置いたところの dist フォルダーに Exe が置かれる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2056854/874c9499-d282-c10a-cdf2-4b210a227445.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2056854/5b5f3b17-225d-4a34-45f7-dffc4137cbff.png)

---
☆2021年12月12日(日) 午後 5時45分 初版(Ver1.00) 作成
☆2024年12月17日(火) 午前10時50分 VSC初期化方法を追記
---
Jupyter labで複数のPythonバージョンをうまく切り替えることができない件

# はじめに
<!-- 発端や概要を記載 -->
Pythonのバージョン別に仮想環境を作って、jupyterのカーネルに登録したにもかかわらず、Pythonのバージョンが切り替わらない件について、いろいろやったときの備忘録を残しておく。

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# 基本のおさらい
python 3.7とpython 3.8とpython 3.9の仮想環境を作る

```
conda create -n py37 python=3.7 jupyterlab 
conda create -n py38 python=3.8 jupyterlab
conda create -n py39 python=3.9 jupyterlab
```

それぞれの仮想環境(py37とpy38とpy39)をjupyterカーネル(py37とpy38とpy39という名前)で登録する

```
ipython kernel install --user --name=py37 --display-name=py37
ipython kernel install --user --name=py38 --display-name=py38
ipython kernel install --user --name=py39 --display-name=py39
```

<a id="#Chapter2"></a>
# つまづいたポイント  
<b>ipython kernel install</b>を唱えると、唱えた仮想環境のベースのpython環境(バージョン)がjupyterカーネルのpython環境として登録される模様。このとき、仮想環境のライブラリはそのまま参照されるため、pythonとライブラリのバージョンの不一致が起きる(知らないとハマる)。したがって、仮想環境をjupyterカーネルで登録するときに、登録したい仮想環境をアクティベートした上で<b>ipython kernel install</b>を唱えるのがよい。

```
# よい例
(base) C:\\hogehoge>conda activate py37
(py37) C:\\hogehoge>ipython kernel install --user --name=py37 --display-name=py37
(py37) C:\\hogehoge>conda activate py38
(py38) C:\\hogehoge>ipython kernel install --user --name=py38 --display-name=py38
(py38) C:\\hogehoge>conda activate py39
(py39) C:\\hogehoge>ipython kernel install --user --name=py39 --display-name=py39

# 悪い例 (base)のpythonバージョンが引き継がれる
(base) C:\\hogehoge>ipython kernel install --user --name=py37 --display-name=py37
(base) C:\\hogehoge>ipython kernel install --user --name=py38 --display-name=py38
(base) C:\\hogehoge>ipython kernel install --user --name=py39 --display-name=py39
```
省略すなということですな。

<a id="#Chapter3"></a>
# おまけ
python環境とライブラリの環境がアンマッチしていないかはjupyterで以下のスクリプトを実行すると確認できる。

``` hogehoge.ipynb
import sys
print(sys.path) # ライブラリのパス 
print(sys.executable) # pythonのパス(バージョンの確認であればsys.versionでも可)
```
また、カーネルの設定はkernel.jsonに保存されており、argv属性の一番目に使用するpythonのパスが記載されている。強制的に書き換えることも可能。(非推奨) なお、AppDataは隠しフォルダとなっている。
C:\\hogehoge\AppData\Roaming\jupyter\kernels\py38\kernel.json

<a id="#reference"></a>
# 参考文献
- [[Python]Anacondaで仮想環境を作る](https://qiita.com/supersaiakujin/items/50def6f33b79f9a61b18)
d3.v7.js で折れ線グラフを作成

こちらのプログラムを参考にしました。
[Simple Line Graph v7](https://blocks.lsecities.net/d3noob/15e4f2a49d0d25468e76ab6717cd95e7)

描画した結果
![d3v7_line_graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/716daecb-b465-7ad2-f3e9-4d58f8156939.png)

```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<title>Line Graph</title>
<style>
.line {
  fill: none;
  stroke: steelblue;
  stroke-width: 2px;
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="line_graph.js"></script>
Dec/12/2021<br />
</body>
</html>
```

```js:line_graph.js
// ------------------------------------------------------------------------
//	line_graph.js
//
// ------------------------------------------------------------------------
// set the dimensions and margins of the graph
var margin = {top: 20, right: 20, bottom: 50, left: 70},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

// parse the date / time
var parseTime = d3.timeParse("%d-%b-%Y");

// set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);

// define the line
var valueline = d3.line()
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.close); });

// append the svg obgect to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");

// ------------------------------------------------------------------------
// Get the data
// d3.csv("data.csv").then(function(data) {
d3.json("data.json").then(function(data) {

  // format the data
  data.forEach(function(dd) {
      dd.date = parseTime(dd.date);
      dd.close = +dd.close;
  });

  // Scale the range of the data
  x.domain(d3.extent(data, function(d) { return d.date; }));
  y.domain([0, d3.max(data, function(d) { return d.close; })]);

  // Add the valueline path.
  svg.append("path")
      .data([data])
      .attr("class", "line")
      .attr("d", valueline);

  // Add the x Axis
  svg.append("g")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x));

  // Add the y Axis
  svg.append("g")
      .call(d3.axisLeft(y));

});

// ------------------------------------------------------------------------
```

```js:data.json
[
{"date": "1-May-2021","close": 58.13},
{"date": "30-Apr-2021","close": 68.13},
{"date": "27-Apr-2021","close": 78.13},
{"date": "26-Apr-2021","close": 55.13},
{"date": "25-Apr-2021","close": 48.13},
{"date": "24-Apr-2021","close": 40.13},
{"date": "23-Apr-2021","close": 30.13},
{"date": "20-Apr-2021","close": 38.13}
]
```
sudo systemctl status railsするとfailになる

##背景
pumaを自動起動設定にするために
https://mebee.info/2021/11/02/post-28224/　
を参考にやったもののstatusがactiveにならない

##結論

```
cd  /etc/systemd/system/var/log
```
でディレクトリ移動し、そこのmessageというファイルをみます(このmessagesファイルにはログが出ています。)

自分の場合、確認してみるとエラーの原因は

```
start request repeated too quickly
```
と書かれており、リクエストを高速で繰り返したために停止されているようです。
解決策としてはrails.serviceファイルの

```
Restart=always
```

を

```
Restart=no
```
にしました。

するとうまく動くようになりました。
ポリモーフィズム（多態性）とは

###ポリモーフィズム（多態性）とは

**・IT用語辞典**
>ポリモーフィズムとは、プログラミング言語の持つ性質の一つで、ある関数やメソッドなどが引数や返り値の数やデータ型などの異なる複数の実装を持ち、呼び出し時に使い分けるようにできること。

**・プログラマが知るべき97のこと** <カーク・ペパーディーン>
>プログラミングにおいてポリモーフィズムとは、同じクラスのオブジェクトやメソッドが、複数の形(form)を取り得るということを意味します。

~~ちょっと何ゆってるかわかんない。。。~~

とにかく納得して、理解できるように簡単にすると
**``「同じ名前のメソッドで、異なる処理を実現すること」``**になります。


では同じ名前のメソッドが異なる処理を実現するとは、どのように実装して、どんな時に使うのか？
ユーザーからのリクエストに対して（GETやPOST）処理を切り分ける、レスポンス処理クラスを使って具体例を見てみます。

・GETリクエスト時 -> ViewResponse
・POSTリクエスト時 -> RedirectResponse

これらのレスポンス処理クラスがそれぞれメソッドを実装していて、処理の内容はそれぞれのクラスによって違います。

そして、実際にユーザーからのリクエストに対して処理をするControllerクラスと
Controllerクラスを呼び出すindex.phpがあります。

####ポリモーフィズムを適用しない場合

```php:RedirectResponse.php
class RedirectResponse
{
    public function redirectResponseHandler()
    {
        // POST時にリダイレクトする処理
    }
}
```

```php:ViewResponse.php
class ViewResponse
{
    public function viewResponseHandler()
    {
        // GET時にHTMLなどをレスポンスボディとして返す処理
    }
}
```

```php:Controller.php
class Controller
{
    public function post()
    {
        return new RedirectResponse;
    }

    public function get()
    {
        return new ViewResponse;
    }
}
```


```php:index.php
$controller = new Controller;
$method = $_SERVER['REQUEST_METHOD'];

// HTTPメソッドがPOSTで来た場合、リダイレクト処理を実行
if ($method === 'POST') {
    $response = $controller->post();
    $response->redirectResponseHandler();
// HTTPメソッドがGETで来た場合、レスポンスボディを返す処理を実行
} else if ($method === 'GET') {
    $response = $controller->get();
    $response->viewResponseHandler();
}
```

この場合、index.phpでHTTPメソッドの種類によって処理を切り分けて、Controllerクラスのメソッドを呼び出し、Controllerクラスではそれぞれレスポンス処理を行うクラスのオブジェクトを返すという処理をしています。
返ってきたオブジェクトを使って$responseはレスポンス処理を行います。

***

####ポリモーフィズムを適用した場合
```php:RedirectResponse.php
class RedirectResponse
{
    public function ResponseHandler()
    {
        // POST時にリダイレクトする処理
    }
}
```

```php:ViewResponse.php
class ViewResponse
{
    public function ResponseHandler()
    {
        // GET時にHTMLなどをレスポンスボディとして返す処理
    }
}
```

```php:Controller.php
class Controller
{
    public function post()
    {
        return new RedirectResponse;
    }

    public function get()
    {
        return new ViewResponse;
    }
}
```


```php:index.php
$controller = new Controller;
// HTTPメソッドの種類によって呼びだすメソッドを決定する
$response = match($_SERVER['REQUEST_METHOD']) {
    'POST' => $controller->post(),
    'GET'  => $controller->get()
};
$response->ResponseHandler();
```
変更した点は、レスポンス処理をするクラスのメソッド名をどちらも``ResponseHandler``にした点と、index.phpでのメソッドの呼び出し方を変更した点です。
Controllerがどちらのクラスオブジェクトを返したとしても、実行するレスポンス処理はResponseHandlerメソッドと決めているので、index.php側で返ってくるオブジェクトの種類を気にする必要が無くなります。

***

###これの何がメリットなのか？

もし、メソッド名にそれぞれのクラス毎に別名をつけていたとすると、index.phpでは全てのレスポンス処理メソッドの呼び出しを行わないといけない上に、もし他のレスポンス処理クラスが追加されたとなれば、また追加されたメソッドを呼び出す記述を追加しないといけません。

処理は異なるメソッドに同じ名前をつけて実装しておくことで、index.phpではレスポンス処理クラスが追加されても、ResponseHandlerとしておけば何も変更を加える必要は無く、index.phpとController以降の処理を完全に切り分けることができるため変更が安全になり、コードの量も減り、可読性も向上するということです。
ScrollView + LazyVGrid / LazyHGrid で固定列 + スクロール列のグリッドを作成する

SwiftUIにて、表示固定部分と横スクロール部分を水平に配置し、
全体としては縦スクロールするグリッドを作成する。
![縦2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/af3ebb0d-59ee-13b4-ed11-3a000a59e20a.png)
![sample3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/1b804c2c-767d-92c9-5c59-4cdb6061bd41.gif)
実装コードはこちら。
全体の ScrollView を [.vertical] として縦スクロールさせつつ、
入れ子にした ScrollView は [.horizontal] として横スクロールさせています。

```swift:ContentView.swift
import SwiftUI

var columnWidth: CGFloat = 60 // 列幅
var rowHeight: CGFloat = 60 // 行高さ
var rowCount: Int = 50 // 表示行数


struct ContentView: View {
    // 大文字アルファベットの配列
    // ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]

    let Alphabets = (65...90).map{ String(Character(UnicodeScalar($0)!)) }
    
    var body: some View {
        ScrollView([.vertical]) { // 全体としては縦スクロールさせる
            HStack {
                // タイトル列
                ScrollView {
                    ForEach(1..<rowCount + 1) { rowNum in
                        TitleColumns(rowNum: "\(rowNum)")
                    }
                }
                .frame(maxWidth: columnWidth) // 列幅
                
                // データ列
                ScrollView([.horizontal]) { // データ列は横スクロールさせる
                    ForEach(1..<rowCount + 1) { rowNum in
                        DataColumns(rowNum: "\(rowNum)", items: Alphabets)
                    }
                }
                .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
            .padding(.horizontal, 20)
            .padding(.vertical, 20)
        }
    }
}

// タイトル列
struct TitleColumns: View {
    var rowNum: String
    
    var body: some View {
        LazyVGrid(
            columns: Array(
                repeating: .init(),
                count: 1 // 列数
            )
        ) {
            ZStack {
                Rectangle()
                    .frame(height: rowHeight) // 行高さ
                    .foregroundColor(.green)
                Text("\(rowNum)")
                    .foregroundColor(.white)
            }
        }
    }
}

// データ列
struct DataColumns: View {
    var rowNum: String
    var items: [String]
    
    var body: some View {
        LazyVGrid(
            columns: Array(
                repeating: .init(.fixed(columnWidth)), // 列幅
                count: items.count
            )
        ) {
            ForEach(items, id: \.self) { item in
                ZStack {
                    Rectangle()
                        .frame(height: rowHeight) // 行高さ
                        .foregroundColor(.gray)
                    Text("\(item)\(rowNum)")
                        .foregroundColor(.white)
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
            .previewInterfaceOrientation(.portrait)
    }
}
```

大文字アルファベットの配列の作成は以下を引用させていただきました。

https://gist.github.com/creaaa/066a94d0ebfecf419210ccc181701a1f
Functorについて調べてみる

## 概要

ScalaとScalaのライブラリ[cats](http://typelevel.org/cats/)で業務を行って1年目、
なんとなくScalaを書くことになれてきたので、Scalaでよく出てくる
`Functor`、`Applicative`、`Monad`についてちゃんと理解したくなったので、調べてみる。

ここでは`Functor`

【参考】
[Functors, Applicatives, And Monads In Pictures](https://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html)

`Functor`とは
Wrapされた値に対して何にも包まれていない値をどのように適用させるかを知っているもの。


数字 + 数字は、何も考えず足すことができる。

```scala
scala> 2 + 5
val res0: Int = 7
```

`Some`にWrapされた`2`に何もWrapされていない`5`を足すことはできない

```scala
@ Some(2) + 5 
cmd2.sc:1: type mismatch;
 found   : Int(5)
 required: String
val res2 = Some(2) + 5
                     ^
Compilation Failed
```
ここで、登場するのがFunctor。
Functor内のメソッド`map`を使用して、`Some`に`Wrap`された値に何も包まれていない`5`を足してみる。

【map】

```scala
def map[A, B](fa: F[A])(f: A => B): F[B]
```

```scala
@ Some(2).map(_ + 5) 
res2: Option[Int] = Some(value = 7)
```

ここでは、まずWrapされた値2を取り出して、何にも包まれていない値5を足して、またWrapしている。

![スクリーンショット 2021-12-12 15.38.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421982/5572dfc6-2c08-b77d-3477-76aac7440459.png)

`fmap`

```scala
@ Map(1 -> "Hello", 2 -> "Every one").fmap(_ + "!") 
res3: Map[Int, String] = Map(1 -> "Hello!", 2 -> "Every one!")
```

`Map`という`context`に入った値に`!`という何にも包まれていない値をつけ加え、また`context`に戻す

## まとめ

もう一度、mapの中身を見ている

```scala
def map[A, B](fa: F[A])(f: A => B): F[B]
```

①. FというcontextにAという値が入っている
②. contextからAを取り出しBという何にも包まれていない値を適用する
③. Fというcontextに包んで返す

mapで上げた例を当てはめると、

```scala
@ Some(2).map(_ + 5) 
res2: Option[Int] = Some(value = 7)
```

`F`→ `Some`(値を包んでいるcontext)
`A`→ `2`(contextに包まれた値)
`B`→　`5`(何にも包まれていない値)
`F[B]` → Some(7)(contextに包まれて返された値)

という感じ。

`Functor`とは
Wrapされた値に対して何にも包まれていない値をどのように適用させるかを知っているもの。


## メモ

Replでの作業を快適にするため[ammonite](http://ammonite.io/#Ammonite-REPL)を使いました。
参考: [Scala で簡単スクリプト Ammonite を試す](https://dev.classmethod.jp/articles/scala-ammonite-repl/)
リレーションを使用したシーダーの作成

今回はリレーションを使用したseederの作成をしていく。

1.Postテーブルにデータを保存
カラム:id,title,content,tag,place

2.Commentsテーブルにデータを保存
カラム:id,post_id,name,article_author,content,post_tag


まずはPostModelにリレーションをはる。
1つの投稿に対して複数のコメントのデータを持つので1対多の関係になるのでhasManyになる。
第二引数には外部キーの設定が必要だが今回の場合、commentsテーブルにはpost_idというカラムがあるため第二引数は必要ない。
*以下ドキュメント参照
>Eloquentは、Commentモデルに対する外部キーを自動的に決めることを心に留めてください。規約によりEloquentは、自分自身のモデル名の「スネークケース」に_idのサフィックスをつけた名前と想定します。ですから今回の例でEloquentは、Commentモデルの外部キーをpost_idであると想定します。

PostModel

```php
    public function comment()
    {
        return $this->hasMany(Comment::class);
    }
```

CommentModel同様にリレーションをはる

```php
    public function post()
    {
        return $this->belongsTo(Post::class);
    }
```

準備が整ったのでリレーションを使ったseederを作成する。

```
php artisan make:seeder hogeSeeder
```

作成したseederに以下のコードを書いていく

```php
public function run()
    {

         //postテーブルにcreateメソッドでデータを作成し$postDataに代入
         //createメソッドで作成することで返り値がModelなのでリレーションが使える。
        $postData = Post::create([
            'name'       => 'hoge',
            'title'      => 'パンケーキ食べに行った',
            'content'.   => '美味しかった',
            'tag'.       => 'グルメ',
            'place'.     => '沖縄県'
        ]);

         //$postDataには作成された記事のデータが入っているのでリレーションを使ってCommentsテーブルのカラムに必要なデータを入れる
         //ちなみにpost_idはリレーションのおかけで書かなくても自動的に作成してくれる
        $postData->comment()->create(
            [
                //'post_id'      => $postData->id,
                'name'           => 'yoshiaki'
                'article_author' => $postData->name //hoge
                'content'        => '美味しそうですね！！'
                'post_tag'       => $postData->tag, //グルメ
            ]
        );
    }
}
```

以上がリレーションを使ったseederの作成になる。
seederの作成というよりデータの作成って感じかな....笑
UIデザインの教科書を読んでみた

# デザインの目的とUI/UX

デザインとは設計のこと。デザインの良し悪しはソフトウェア・顧客満足度の向上に重要。
UIとUXは別物。
UIとはサービスなどのインターフェイスをより使いやすく設計するということ。
UXとはユーザーがサービスによって受ける全ての体験のこと。
UIとUXの違いは客観的か主観的か。UIを良くしてもUXが上がらない仕様だと意味がない。
UIはUXの中核である。

# 物理的な制約

大体これ
1. スマホ
2. タブレット
3. PC
4. TV  

デバイスの違いでUIの影響の仕方が変わる。

- マウスは細かい操作（ホバーなど）が可能
- スマホ・タブレットは細かい操作できない。そのため、リンク先など目視で確認できる必要がある。またスマホなどのタッチで操作するものはある程度の大きさのデザインが必要。
- TVはフォーカス移動・音声入力が特徴。直接画面の対象を操作できないので、フォーカスが今どこにあるのかわかることが重要。要素の連続性も重要。表現の差別化。リモコン操作が簡単になるほど良い。

クリックやタッチは直接操作できる。フォーカスはできない。

デバイスによって画面の近さは変わる。サイズの可変性大事。画面の形固定 -> アスペクト比（大体16:9）
画面サイズ大きいと情報多く載せれる。距離が遠いほど要素を大きくするといい。
画面の大きさのポイントは「可変性」「アスペクト比」「サイズ」

視覚的に距離が遠くなるほど要素を大きくするべし。あと縦横の向きも大事。
Androidは戻るボタンないけどIphoneはある。思想による。シンプルさとか。

# ソフトウェアの影響

Webとアプリの違いとして、ブラウザ（凡庸ツール）かアプリ（専用ツール）の違い。ハードウェアが違う。
WebアプリはURLと不可分に結びついてる。WebはOSの違いに影響を受けないが、スマホアプリは影響を受ける。
アプリはインタラクションが豊富。
サービスの目的によって使い分けるといい。

- Webサイト
    - 実装の容易さ
    - ひとまず使ってもらう手軽さ
    - マルチデバイスの対応力

- アプリ
    - 動きのスピードや操作の軽快さ
    - 単機能/単サービスの専用性
    - インタラクションの対応力

情報は、「テキスト」「画像」「動画」の3つに集約される。

解像度はOSとハードウェアによってきまる。
ハードウェアによって表示できる解像度を「物理解像度」、OSによって表示される解像度を「理論解像度」
最近はハードウェアが向上して物理解像度の方が大きい。

テキストは最強のデータ。テキストで表現できるものであれば画像などは使わずテキストのままでいい。

画像は環境やOSの違いによらず全ての状況で同じデータに見えること。テキストなどはOSによって最適化されてしまう。

速度重要
- HTTP2（複数リクエスト・レスポンス非同期）
- ファイルの先読み
- AMP

# 人間の認知性

色は判別する速度を早めるためにはあったほうがいいかもしれないが、増やし過ぎは良くない。
動きの役割は、「注目のための動き」「理解のための動き」「装飾のための動き」。UIでは「理解のための動き」が基本。
インタラクションコストとは、ユーザーが受ける負担のことで、要するにUXの負担が少なければ使いやすいサービスである。
インタラクションコストを下げるには、「一貫性」「シンプルさ」「共通概念」が必要。

一貫性: ある規則に基づいてサービス内のデザイン要素全てがその基準に従っていること。ユーザーが予測しやすくなること、機能の追加や改善が簡単になる、信頼性が生まれる。一貫性の例外を生みにくいルールを作るといい。
シンプルさ: 「単純にする」ではなく「明快にする」
複雑さ: サービスに精通している方であればワンタップでできたりするボタンが豊富にある方が。

ユニバーサルデザイン大事。日本と世界の違いを理解する。

ユーザーは基本的にページの階層は浅く広くがいい。階層が広ければカテゴリのラベリングがわかりやすい名前をつけやすくなったり、ユーザーのインタラクションコストが少なくて済む。
PCではパンくずリストが有効だが、スマホだと現在地表記が有効。

Webサイトのわからないとは、「場所がわからない」「操作がわからない」の２つ。

# ナビゲーションとインタラクション

画面エリアの制約によってフッターを無くしたり（TV）、縦長の画面など制約を理解すること。

インタラクションとは、ユーザーの入力に対する動きや変化を伴ったフィードバックのこと。「理解のためのインタラクション」と「演出のためのインタラクション」の2種類がある。
使いやすさとは、認知負荷をいかに低減させるかに大きく関わっており、インタラクションはそのための有効な手段。


演出のためのインタラクションとは素敵な体験を通じてサービスの魅力を向上させる動き。
無限スクロールではユーザーが全てのコンテンツを見ることができない。またフッターを使うことができない。また、戻るボタンとの親和性が悪い。
ページングは横向きの操作（タブの切り替え、機能切り替え）と親和性が高い。（ペジネーション）

スクロールの方向としては、テキストの量が多ければ下向き、画面の形が長ければ長い方向、要素の形が縦長であれば横向き、横長であれば縦向き、要素の隙間が大きい方向に。

# デザインを形にする

スキューモーフィズムからミニマリズムへ。要するにリアルに表現するために細かく描くよりもミニマムにフラットなデザインが今は流行り。
ミニマルデザインのポイントは、「どこが押せるか判断できるようにする」「色を絞って余白を活かす」「ミニマルとシンプルの違いを理解する」
語学用のフラッシュカードをGASを使ってスプレッドシートから一括生成する

[Ateam Brides Inc. Advent Calendar 2021](https://qiita.com/advent-calendar/2021/ateam-brides)の13日目は
株式会社エイチームブライズの川村が担当します！

#韓国語の単語を勉強したい
韓国語ペラペラ男子を目指している私は、
毎年春と秋に行われるハングル能力検定を受けるために日々勉強しています

韓国語って日本語と似た言語体系であることから、文法はなんとなく分かるんですが
単語に関しては何回もハングルに触れない限りは覚えることができないんですよね...。

そう、単語だけは単純な暗記勝負なんです。

##単語帳を使っても良いが

私も学生時代は英単語帳をボロボロになるまで使っていましたが、
今どき紙媒体で学習するのもちょっとね...

しかも単語帳には「既に覚えた単語をスキップできない」という弱点があり
単語帳で学習が進めば進むほど非効率になってしまいます。

##スプレッドシートと連携したフラッシュカードを作る

そこで今回はスプレッドシートで未修得の単語を管理しながら
それを基にフラッシュカードを作ることにします

###スプレッドシートに覚えたい単語リストを用意する

まずはスプレッドシートに覚えたい単語リストを用意しました！
こんな感じで↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319121/346c8103-f317-1e2e-a0e7-83ab70fdea2d.png)


そもそも、この単語データベースを用意するのが大変な感じはありますが
幸い韓国語の場合は単語リストを配布しているサイトがあったりします。

### Googleスライドにテンプレートを用意する

こんな感じで1枚テンプレートになるスライドを準備しましょう！
そして、それぞれの変数が代入される箇所に `{furigana}` `{kr}` `{jp}`などと記入しておきます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319121/911fa371-f556-0268-6e41-86124530f80d.png)

のちほどGASを使って
①このスライドを複製して②それぞれの変数の中身を置き換える、という処理をします

###GASを記入する

スプレッドシートからGASで書きます
普段あまりお目にかからないSlidesAPIの`replaceAllText`という関数をリクエストしています

> [Requests | Slides API | Google Developers](https://developers.google.com/slides/api/reference/rest/v1/presentations/request)

処理自体はいたってシンプルです！

```javascript:コード.gs
function myFunction() {

  //スプレッドシートの定義
  var spreadsheet = SpreadsheetApp.openById('SpreadsheetのID');
  var sheet = spreadsheet.getSheetByName("Spreadsheetのシート名");
  var lastRow = sheet.getLastRow()

  //スライドの定義
  var slides = SlidesApp.openById("GoogleSlideのID");
  var firstSlide = slides.getSlides()[0];

//スプシのセルの値を取得->スライドにコピーを繰り返す
  for (var i=2; i<=lastRow; i++){
    var kr = sheet.getRange(i,2).getValue();
    var jp = sheet.getRange(i,4).getValue();
    var furigana = sheet.getRange(i,3).getValue();
    
    var insertedSlide = slides.insertSlide(1,firstSlide);
    insertedSlide.replaceAllText("{kr}",kr);
    insertedSlide.replaceAllText("{jp}",jp);
    insertedSlide.replaceAllText("{furigana}",furigana);
  }

}
```

###GASを実行する

うまく実行完了すれば、大量のフラッシュカードが自動生成されます！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319121/78e44ffe-eb4b-c6c8-56a3-f8acec367e4c.png)

「ふむふむ、韓国語の飲み物は、漢字の<ruby>飲<rt>ウム</rt>料<rt>ニョ</rt>水<rt>ス</rt></ruby>から来てるんだな....」と。

あとは、PDFにするなり、画像形式でエクスポートするなりして
iPadやスマホを使って通勤通学の電車内で勉強するだけですね！（これが一番難しい）

#まとめ

今回は、GASを使って語学学習に役立つフラッシュカードを作ってみました！

弊社ではあまりプレゼン資料を作る機会が少ないので、実業務に役立つか....は未知数ですが
韓国語とウェブマーケター必携のGASスキルが微妙に上がったのは良いことです^^

少なくとも、スプレッドシートにある名簿から自己紹介スライドを大量生成したい人事や
語学向け聞き流し動画を作りたいYouTuberには需要があるかも知れません（ニッチですね）

さて、[Ateam Brides Inc. Advent Calendar 2021](https://qiita.com/advent-calendar/2021/ateam-brides)は、早くも折り返しです！
明日の14日目は、@take_mがお送りします。どんなネタを用意してくるのか楽しみですね！！
プログラミング講座を受講した感想

# はじめに
県のIT人材育成講座に参加しました。
プログラミングの知識なし、Macの操作経験なしの状態でスタートしました。
TECH CAMPを運営されている会社のメンターさんが現地に滞在し、質問に答えてくださいました。
期間は4ヶ月、目標学習時間は600時間でした。

## 受講のきっかけ
県の広報誌で紹介されており、前年度の受講生の声がとても素敵だったため興味を持ちました。

## 学習の進め方
原則、自己学習で質問があれば質問フォームを送ります。
学習の進捗が決まっており、週に１回メンターさんと面談を行いました。
毎日学習した内容をアウトプットし、メンターさんへ報告フォームを送ると１日の学習が終わりです。

## 講座の主なスケジュール
**初日（キックオフ）**
・slacのアカウント開設
・Zoomのダウンロード
・環境構築
・Macの操作方法
**1ヶ月目**
・HTML/CSSの学習
・Rubyの基礎文法を学習
**2ヶ月目**
・Ruby on Railsを学習
・GitとGitHubを使った開発を学習
・テストコードの書き方を学習
**3ヶ月目**
・JavaScriptの文法を学習
・Ajaxを用いた開発を学習
・Herokuへのデプロイとbasic認証を学習
**4ヶ月目**
チーム開発とオリジナルアプリの開発

##受講して良かったこと
・短期間でプログラミングの知識を学ぶことができた
・分からないことをすぐに聞け、解決策だけでなく理論の解説もしてもらえた
・何をすれば良いか迷うことなく、効率的に学習を進められた
・モチベーションを維持することができた

##苦労したこと
・クラスやメソッドなど、用語や概念がたくさんでできて理解に時間を要したこと
・学習の進捗に間に合わせるため、1日に複数の単元を詰め込みで進めたこと
・学習時間の確保

##反省点
・進捗に間に合わせることが目標になってしまい、理解が不十分のままになってしまった
・休息を十分に取らず学習を優先したため負荷が大きくなり、学習意欲の低下につながった

#最後に
最後までお読みいただきありがとうございます。
４ヶ月の概算学習時間は400時間（平日3時間、休日６時間）で目標の600時間には到底及ばず不完全燃焼となってしまいました。
ほぼ毎日プログラミングと向き合うのは思った以上に大変で、何度も心が折れそうになりましたが、その度にメンターさんや同じ講座の受講生に支えていただきました。心より感謝申し上げます。
yarn start がまたできない件

# 再びyarn startができない
 Reactにてアプリケーション作成中に、
 「Error: error:0308010C:digital envelope routines::unsupported」
のようなエラーが出たため、googleで検索すると、解決のためには最低でもnodeのバージョンをv14.18.1まで下げる必要があるとのこと。

## nodebrewを使う
 ターミナル上で、「nodebrew install-binary v14.18.1」を実行するが、「Can not fetch」となりインストールできない...

## nvmでバージョン管理
 nodebrewでインストールできなかったため、nvmをインストールして、「nvm install v14.18.1」を実行。すると、無事にインストール完了しました。

## まとめ
 再びyarn start を実行すると、無事にREACTが起動しました！もし、同じようなエラーがある場合には参考にしていただければと思います。ただ、なぜ問題が起きてなぜ解決したのかその裏側は分からずですね。エラーをきっかけに色々と知れたらと思います。

### 参考URL
https://off.tokyo/blog/next-0308010cdigital-envelope/

https://qiita.com/k3ntar0/items/322e668468716641aa5c#%E5%88%87%E3%82%8A%E6%9B%BF%E3%82%8F%E3%82%89%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88

https://ralacode.com/blog/post/install-nodejs-with-nvm/
DNN学習はPyTorch Lightningしか勝たん理由



[PyTorch Lightning](https://www.pytorchlightning.ai/)は、ML開発者向けの軽量なPyTorchラッパ。
学習とかがめっちゃ簡単で、他のいろんなプラットフォームとの組み合わせが使えて汎用性高いってのを聞いたからとりあえず使ってみた。
いろんな機能があったけど、これだけ理解しといたらいけるやろって感じの機能だけ紹介します。

・[基本的な使い方](#基本的な使い方)
・ログ機能
・CALLBACK

この三つの使い方を今回は書いていきます
PyTorchの使い方知らない人にもわかるように記載しますが、PyTorchも知ってた方が分かりやすいと思う。

##基本的な使い方
簡潔に言うと学習までの手順ですることはこの三つ
・[モデルを作る](#モデルを作る)
・推論時の設定
・学習開始

機械学習においてすることはだいたいこれだけ
しかし、PyTorch Lightningは通常のPyTorchによる学習よりもコードが非常に簡潔！
モデル作成のステップでしっかりと記述できれば非常に便利なので、ぜひ最後まで読んでください。

###モデルを作る

もっとも大事と言えるこのステップ。通常PyTorch等の機械学習では、データの用意や各学習ステップの設計が必要ですが、PyTorch Lightningではこれらの必要な処理をほとんどモデルの内部で行います。
では実際にモデルを定義していきましょう。
分かりやすいようにMNISTのデータを用いて解説していきます。

モデル作成で、継承するPyTorch Lightningのモジュールは、
[pytorch_lightning.LightningModule](https://pytorch-lightning.readthedocs.io/en/latest/common/lightning_module.html)というものです。
これを利用して以下のようにモデルを定義します。

続いて先ほど定義したモデルの中に以下の関数を定義します。
ASTERIA WarpでPlatioとkintoneをつないでみた

モバイルアプリ作成ツール、Platioで作成したモバイルアプリとkintoneで作成したアプリをASTERIA Warpを介してデータ連携処理をやってみました。
※モバイルアプリ作成ツール、Platioに関する詳細はこちら。↓
https://plat.io/ja/

まず、Platioとkintoneの連携対象アプリを確認してみます。

## Platioアプリ - 営業日報

![platio_kintone_0010.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156332/3e310e5e-75c0-da30-c0e4-8b197000918e.png)

営業日報というモバイルアプリがPlatio側での連携対象アプリです。
日々の営業活動を自分のスマホを利用して簡単に報告することができます。

## kintoneアプリ - 案件管理システム

![platio_kintone_0040.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156332/4ce31c7e-019d-5fb5-d245-d4df575f660d.png)

上記の案件管理システムがkintone側での連携対象アプリです。
顧客情報、案件情報、活動履歴で構成されており、顧客先ごとデータを作成し、活動履歴に日々の営業活動の内容を登録することができます。
Platioから連携した営業日報はこの「活動履歴」に登録されます。

それでは、Platioの営業日報アプリのデータをkintoneの案件管理システムへ登録するフローを確認します。

## フローの構成
![platio_kintone_0060.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156332/01c9c707-4f95-2533-7b2a-1fa24db88dbe.png)

2つのフローの構成されており、「Platio→kintone連携」フローから「sub_Platio→kintone連携」フローを呼び出して実行しています。
この処理では、Platioから差分データを抽出するためのロジックが含まれています。
前回処理したPlatioデータのタイムスタンプを保存し、次回の実行ではそれ以降のデータを抽出するための条件式を作成してPlatioからデータを抽出時に検索条件として設定します。

フローの構成の詳細は以下の通りです。

①前回の連携処理で保存しておいた、連携処理情報（タイムスタンプ）を取得します。
②上記①で取得したタイムスタンプ情報を利用して条件式を作成し、PlatioGetコンポーネントへ検索条件として設定します。
![platio_kintone_0070.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156332/7b96923c-2eaf-e588-9f32-a7a62a7a27d7.png)
③Platioアプリから営業日報データを取得します。
④Platioの営業日報データをkintoneの案件管理システムへ登録します。
　この登録処理では、顧客先ごと案件レコードを作成し、営業日報は案件レコードの活動履歴として登録しています。
⑤営業日報データの連携処理情報（タイムスタンプ）を保存します。

## フローの実行結果
![platio_kintone_0090.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156332/cc5df29b-a3fa-fc2c-6979-0ef30ad66e95.png)
ご覧の通り、Platioの営業日報データがkintoneの案件管理システムアプリへ登録されていることが確認できます。
生産者の顔がわかるタイプのCapcha解析サービス

# anti-capcha.com
AntiCapchaという生産者の顔が分かるタイプのCapcha解析サービスを使ってみたので、そのレポートです。

https://anti-captcha.com/

# 使ってみた

## ユーザー登録
まずはこちらの画面からユーザー登録を行います。

https://anti-captcha.com/clients/entrance/register

Capcha解析サービスに登録するためにreCapchaを解く必要があるというところに、一抹の疑問を感じながらも登録を行います。

![スクリーンショット 2021-12-12 16.10.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74551/2f043a17-45f1-a104-3560-1f3de79b00c9.png)

## 入金
ユーザー登録の次に入金を行います。
ログイン後の画面の「Add Funds」で入金画面に移動できます。
多くのクレジットカードや仮想通貨に対応しているようです。
Capcha解析という怪しいサービスにクレカ番号を知られるのはリスクという考えで、今回はEthereumを使って入金することにしました。


![スクリーンショット 2021-12-12 16.17.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74551/20fe4f02-0ae1-6afc-3ed6-bb763e2c3194.png)

Ethereumを選択して、入金額を入力すると、以下のような送金先アドレスが出てきます。
このアドレスに指定の額を送金することで、入金ができます。
今回は1USD分を入金してみました。
ガス代が高いせいで送金手数料として7USDもかかりましたが、安全に対する代金と考えれば安いもんです。

![スクリーンショット_2021-12-12_16_22_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74551/1b938869-0b11-846c-7a64-4372ac32bbdf.png)

## APIを叩く
いよいよAPIを叩いて見ましょう。

今回は一番シンプルなImageToTextTaskというタスクを解いてみます。
以下のような画像に含まれる歪んだ文字を解析するタスクです。

![captcha-img.2fdf3ec.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74551/5c322389-0155-4992-9014-f24b28581870.jpeg)

このタスクのAPI仕様書は以下に公開されています。
画像をbase64エンコードして送れば良いだけなんでとても簡単です。

https://anti-captcha.com/apidoc/task-types/ImageToTextTask

公式のサンプルを少し変えて以下のようにAPIを叩いてみました。
clientKeyには管理画面から確認できる自分のアカウントのAPIキーを設定します。

```sh
curl -i -H "Accept: application/json" \
     -H "Content-Type: application/json" \
     -X POST -d '{
    "clientKey":"XXXXXXXXXX",
    "task":
        {
            "type":"ImageToTextTask",
            "body":"'$(base64 path/to/image.jpg)'"
        }
}' https://api.anti-captcha.com/createTask
```

curlを実行すると、以下のようなレスポンスが返ってくるので、レスポンス中のtaskIdを使って解析結果を取得します。

```json
{"errorId":0,"taskId":1234567890}
```

実行結果の取得にはgetTaskResultを使います。

https://anti-captcha.com/apidoc/methods/getTaskResult

```sh
curl -i -H "Accept: application/json" \
     -H "Content-Type: application/json" \
     -X POST -d '{
    "clientKey":"XXXXXXXXXX",
    "taskId":1234567890
}' https://api.anti-captcha.com/getTaskResult
```

solutionの中のtextが解析結果となっています。
結果は `arch dsjcbka` なので、しっかりと画像を解析して文字に出来ていることが分かります。
また他のフィールドから以下のことも分かります。

- かかった費用は0.00070USD(つまり1万枚で7USD)
- 15秒で解析が完了した(endTime - createTime = 15)

```json
{
  "errorId":0,
  "status":"ready",
  "solution":
    {"text":"arch dsjcbka","url":"http://XXXXXXXX.jpg"},
  "cost":"0.00070",
  "ip":"XXXXXXXXXX",
  "createTime":1639294869,
  "endTime":1639294884,
  "solveCount":0
}
```

# 生産者の顔とは？
さて、タイトルにある「生産者の顔」とは何だったのでしょうか？
実はこのサービスではreCapchaの解析を行っている方々からの感謝の言葉をみることができます。

https://kolostories.com/contents/list
A5SQLの使い方が初心者なのでおすすめサイトを集めて実務でつかう

## おすすめサイト

- [ショートカット](https://shimonss.hatenablog.com/entry/2017/07/08/161043)
- [ダミーデータ作成①](https://a5m2.mmatsubara.com/help/TableEditor/dummy.html)
- [ダミーデータ作成②](https://zenn.dev/waka_morita/articles/3d2d58236a3c7d)
- [ダミーデータ作成③](https://www.tairaengineer-note.com/a5sql-mk-2-table-insert-export/)

## ショートカット

- コメントアウト Ctrl + K
- アンコメント Ctrl + Shift + K
- 全選択 Ctrl + A
- コードの整形 Ctrl + Q
- SQLを1行にする　メニュー「編集(E)」⇒「SQLを1行に整形(E)」を選択する
zoom会議にバーチャルモデルで参加しよう！

# はじめに
<!-- 発端や概要を記載 -->
　こんにちは，本記事に触れていただきありがとうございます．学部４年のDKです．普段はゲームを嗜みながら言語処理の分野を学習しています．

　新型コロナウイルスの影響もあってオンラインによる対話は非常に増えていると思います．特にアプリケーションzoomを用いている方は多いでしょう．すると必ず話題に出るのはビデオをONにするかどうかだと思います．自分の顔を出すのは嫌だなと思っていても，オンライン対話において誰の反応も見てないと話者は心配になることが多いと思います．~~とかそんな堅苦しい前置きなんかいらない．バ美肉したい．可愛い女の子になりたい！！！~~

　そこで本記事では簡潔に自分で作成したバーチャルモデルを用いて参加する方法をご紹介します．ちなみに無料で全部できます．これを知っていれば，顔出しも簡単ですし，友達同士でも面白くおかしくオンライン飲み会も楽しめますね！~~女の子になれる！最高ハッピ～～～~~

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [自分がなりきるバーチャルモデルを作ろう](#Chapter1)
1. [トラッキングをしてみよう](#Chapter2)
1. [zoomで参加しよう](#Chapter3)
1. [最後に](#Chapter4)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# 1. 自分がなりきるバーチャルモデルを作ろう
　まずは自分の分身であるバーチャルモデルを作りましょう．今回紹介するのはVRoidStudio 1.0.1です．下記のリンクからサイトにアクセスして自分の環境に合わせて無料でダウンロードしてみてください．steam版，Windows版，MacOS版があります．

https://vroid.com/studio

ダウンロードしたらさっそく開いてみましょう．新規作成から男性，女性を選択し，顔，髪型，体型などを細かく自分好みに調整します．満足のいくモデルが出来たと思ったら右上から２つ目のアイコンをクリックしてVRMエクスポートをクリックしましょう．エクスポートを行うとvrmファイルで作成したモデルを保存することができます．これでまず第一関門突破です！！！

<a id="#Chapter2"></a>
# 2. トラッキングをしてみよう
　続いて自分の顔の動きを保存したvrmファイルの顔に反映させましょう．今回紹介するのは3teneFREEです．下記のリンクからサイトにアクセスして自分の環境に合わせて無料版をダウンロードしてみてください．こちらもsteam版，Windows版，MacOS版があります．

https://3tene.com/free/

　ダウンロードしたらさっそく開いてみましょう．左の上から４つ目のアイコン（人のシルエットが３人いるアイコン）をクリックするとアバターの選択ができます．＋から先ほど保存したバーチャルモデルのvrmファイルを開きましょう．その後，右上にあるアイコンのトラッキングのオンオフからフェイストラッキングの開始をすると自分のPCにある内蔵カメラ等から自分の顔の動きを読み取ってバーチャルモデルの顔の動きへ反映させることができます．これで第二関門突破です！！！

<a id="#Chapter3"></a>
# 3. zoomで参加しよう
　最後にzoomでミーティングに参加して，左下から２つ目のビデオの開始にあるハットマークから3tene Screen Captureを選択（3teneFREEは起動してトラッキング開始状態のまま）します．すると，なんと自分の顔の動きを反映したバーチャルモデルになりきることできます．最後の関門も突破です！！！

<a id="#Chapter4"></a>
# 4. 最後に
　おめでとうございます！これでみなさんもバーチャル世界で生きていけるようになりましたね．このやり方でうまくいかなかった人はOBSというアプリケーションを介するとうまくいくかもしれません（僕はちょっといまいちやり方が分からなかったのででうまくいったら更新したいと思います）．
　

<a id="#reference"></a>
# 5. 参考文献
- [Qiita記事投稿用テンプレート](https://qiita.com/tkrtmy1031/items/80c292fab5d631c6d4ba)
- [3Dキャラクタ制作ソフトウェアVRoidStudio](https://vroid.com/studio)
- [3tene](https://3tene.com/)
SwitchBot APIを呼び出すフローを作る

[SwitchBotAPI](https://github.com/OpenWonderLabs/SwitchBotAPI#switchbotapi)を呼び出すフローを作り、enebularからHerokuへデプロイします。

# 作成例

![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2303867/291cc521-072a-e52f-0249-ef975a9d0d5f.png)


# 用意するもの

- enebular
    - プロジェクトが作成済みであること
    - Herokuコネクションが作成済みであること
- Heroku
    - アプリが作成済みであること
- [SwitchBot](https://www.switchbot.jp)
    - SwitchBotアカウントが作成済みであること
    - SwitchBotアプリをスマートフォン等にインストール済みであること
    - 任意のSwitchBot製品を少なくとも1つ利用できること
    - SwitchBotクラウドサービスがオンになっていること

# 手順

## enebular

### フローを作る

`http request` ノードがサポートしている認証方式では、SwitchBot APIを呼び出せないので、`function` ノードでヘッダーにトークンを設定します。

NG
> Authorization: \<type> \<credentials> 

OK 
> Authorization: \<credentials> 


1. 編集したいフローを開きます。
1. パレットの`inject`、`function`、`http request` ノードをワークスペースに配置します。
1. `inject` ノードの [Node-RED起動の  秒後、以下を行う] で適当に `5` 秒後に設定します。
1. `function` ノードを[sample-code](#sample-code)のように実装します。クレデンシャルを環境変数で読み取ります。
1. `http request` ノードの [メソッド] をGETにし、 [URL] にSwitchBot APIのURLを入力します。今回は、SwitchBotアカウントに登録済みのデバイス一覧を取得するAPIを呼び出します。

> GET https://api.switch-bot.com/v1.0/devices


#### sample-code

```
msg.headers = {};
msg.headers['Authorization'] = env.get("OPEN_TOKEN");

return msg;
```

## SwitchBot

### SwitchBotアプリからトークンを取得する

1. SwitchBotアプリで、[プロフィール] > [設定] を開きます。
1. [アプリバージョン] をリズミカルに10回タップします。 
1. [開発者向けオプション] をタップして、表示されたトークンを控えておきます。

#### image-1

![image-1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2303867/3b86ce47-0053-1410-c992-ffcd84acebd4.png)


## Heroku

### Herokuアプリに環境変数を設定する

1. Herokuのダッシュボードから、作成済みのHerokuアプリの詳細画面を開きます。
1. [Settings] タブの [Reveal Config Vars] をクリックします。
1. [KEY] に`OPEN_TOKEN`と入力します。
1. [VALUE] に[SwitchBotアプリからトークンを取得する](#switchbotアプリからトークンを取得する)で控えたトークンをを入力して、環境変数を追加します。
1. [フローを作る](#フローを作る)で作ったフローを、Herokuにデプロイします。
1. Herokuアプリのログに、デバイス一覧のJSONが出力されていることを確認します。

![image-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2303867/6e69a44a-9939-1730-82a1-947f10c0453e.png)


SwitchBotアカウントに登録済みのデバイス一覧を取得できました :tada:
Twistedで偽DNSを

# モチベーション
所要で偽DNSサーバ（上位のコンテンツ（権威）サーバ）を作る必要があり、手っ取り早く使えそうなライブラリということでTwistedを使ってみることにしました。
結構いろいろなところにハマったので、そこらへんをまとめておきます。

https://twistedmatrix.com/trac/wiki

# ハマったこと色々
## ハマったこと１　非同期の考え方
Twistedは非同期の実装になっています。
ある処理をして、結果を受け取って、次の処理をする、という同期的な考え方でロジックを組むと、、実装ができなくなります。

非同期実装はしっかりと学んだことがなく、、ココらへんの理解がまずひと手間でした。

### 具体的には？
今回の処理上、DNSリクエストを受け付けてから、本来のDNS権威サーバのレコードを取ってくる、ということをする必要があります。
これを何も考えずサンプルソースに手を入れる形で実装すると、、、つまづきます。

私が今回やりたい処理を同期的な考え方で実装すると、以下のようになります。

1. DNSリクエストを受け付ける
2. DNSリクエストを解釈して、本来の権威サーバにリクエストをかける
3. 権威サーバからのレスポンスを受取る
4. 受け取った中身を解釈して、リクエストしてきたクライアントに加工したレスポンスを返す

一方、Twistedのサンプルソースでは、以下のような実装になっています。
https://github.com/twisted/twisted/blob/trunk/docs/names/howto/listings/names/override_server.py

1. 以下の処理をするクラスを実装して、インスタンスを作成する(DynamicResolver)
    - DNSリクエストを解釈して、中身に応じた加工をして返す。
    - 条件に合わなければ、failを返す。
2. DNSリクエストを受け付けたときの処理に、1をコールバックとして登録する
    - コールバックは複数登録していて、1が失敗したら２つ目のResolver(OSのディフォの/etc/hosts、ローカルキャッシュ、スタブリゾルバに問い合わせる）が実行される。
3. リクエストを受けたら、１の処理が呼び出され、１の処理の戻り値をクライアントに返す。
    - 1の処理がFailしたら、２つ目のResolverが処理して、結果をクライアントに返す。

非同期では、処理はすべて「コールバックとして、別の処理に預けて、別の処理が終わったあとに続けて実施してもらう」というような実装になるため、作りがガラリと変わります。

サンプルソースに対して、同期的な考え方での私の２と３の処理を差し込むには、、、
以下のようなコードを差し込むことを思いつくのですが、そうは動きません。

```
r = client.Resolver()
response = r.query(<権威への問い合わせ>)
```

上記は同期的な発想なのですけれど、非同期に動くResolverのqueryは、「その場で処理して戻り値を返してくれる」ということはしてくれません。
コールバックを預けといてDNSの問い合わせが終わり次第それを実行する、というような実装にしなければなりません。
r.queryは結果ではなく、実施予定（実施中）のコールバックのチェーン（defer）を返してくれるので、そこに実行したい続きの処理（3の権威レスポンスの解釈と、４のクライアントへのレス返し）を預ける、というような実装になります。

。。。という話がとんとピンとこず。

### 非同期＋Twistedのお勉強
腰を据えて以下を読み込むことになりました。
https://krondo.com/an-introduction-to-asynchronous-programming-and-twisted/

腰を据えて読むと非常によくわかり、ちゃんと動くコードがかけるように放ったのですが、、、これ変に詩的な表現多用してくれてるんで読みにくいこと読みにくいこと。。
日本語訳もおかしなことになってる箇所が多々あるし。
結構しんどかったです。

## ハマったこと２　結構古いコード
総じて、Twistedのコードって結構古いんですよね。。
どこらへんが古いかというと、以下。

### Aptで古いバージョンが入ってしまってる
これはTwitedが悪いわけではないのですが。
エラー時のスタックで表示される行の内容がどうもGitで見てるコード合わないないなと調べていて判明。
PIPで最新版を落としてきていたのですが、実はOS(Ubuntu)のパッケージでpython3-twistedというのが入ってしまっていて、そっちが優先されてしまってたんですね。。。
OSのディストリ管理のパッケージの宿命といいますか、めっちゃ古い。
ubuntu20.04だと18.09。21.10だと20.3.0。
現時点の最新版は21.7.0。
dpkg側を削除して、ようやく最新版で動くようになりました。

古いから悪いというか、OSのディストリに取り込まれるくらい古くて実績があるというべきか。
いずれにせよ、注意が必要です。

### マイナー（？）な機能にバグ、、
権威サーバとして使う場合はゾーンファイルを作成しておいてそれを読み込んで使います。
https://github.com/twisted/twisted/blob/trunk/docs/names/howto/names.rst

で、pyzoneという形式で読み込む分にはいいのですが、bindzone形式で読む場合(--bindzone)というのを使うとエラーで止まります。
コードを見てみると、以下の記載があるのですが、python2の場合前者と後者がどちらもtype 'str'として解釈されて結合できるのですが、python3の場合前者がclass 'str'、後者がclass 'bytes'として扱われるので、結合ができずきエラーが出る、と。

```
self.origin = nativeString(fp.basename() + b".")
```

ここだけ直してもまた別の箇所でエラーを履いてしまうので、結構手を入れないといけなさそうです。
テストファイルもなさそうなので、メンテされてないのかもしれませんね。。
Twistedはかなりの数のプロトコルに対応している関係で、マイナーどころの扱いは微妙なのかもしれません。

## ハマった、、ほどではないですが、、　権威サーバとしての振る舞い
今回の特殊動作を実装するにあたり、権威サーバ用のFileAuthorityをベースに手を入れるかなと思って動作をみていたのですが。
権威サーバ、特に上位サーバの場合、自分の直接持っている子ドメインのリクエストではなく、孫ドメインのリクエストが来た際に、子ドメインのNSをAuthority応答として返すということをするのですが、この動作を実装していない感じです。
自分が持ってないレコードが来た場合にSOAを答えるというのはやってくれるのですが。
RFCを読み込んではいないのですが、実際にルートやjpなどの権威サーバに問い合わせるとそう動くので、そういうRFCかディファクトがあるのかなと。

# まとめ
一応意図したものが動くまでは作り込めたのですが、別のライブラリ探すかなぁ、、
とりあえずこんなところで。
Expressでシンプルな掲示版を作る

# はじめに
Expressを使ってシンプルな掲示板を作る手順を説明します。

ソースコード
https://github.com/jeronimo34/SimpleBBS


# 初期設定
以下のコマンドを実行しアプリの雛形を作成します。
テンプレートエンジンに `pug` を選択します。

```
npm install express-generator -g
express --view=pug SimpleBBS
cd SimpleBBS
npm install
```

# 投稿一覧表示実装
## 投稿データの保存先
`app.locals.posts`に投稿データを保存します。`app.locals`に設定した値はアプリケーションの存続期間中、持続します。
アプリケーションを再起動すると投稿データが失われてしまうため、本来はDBにデータを保存すべきですが、今回は簡単のため`app.locals`を使用します。

```javascript:app.js
// データベース
app.locals.posts = [
  {
    name:"test1", text: "hogetext"
  },
  {
    name:"test2", text: "hogetext"
  },
  {
    name:"test3", text: "hogetext"
  },
];
```

## 投稿一覧の表示
`http://localhost:3000` にアクセスしたときの処理を実装します。

```javascript:index.js
router.get('/', function(req, res, next) {
  const posts = req.app.locals.posts;
  // 投稿一覧画面を描画。タイトルと投稿データを伝達。
  res.render('index', { title: 'SimpleBBS' , posts: posts });
});
```

投稿データを全て表示します。

```javascript:index.pug
  div(class="posts")
    each post in posts 
      div(class="post")
        div 名前: #{post.name}
        div 本文: #{post.text}
```

# 新規投稿処理
## おまじない
Formから投稿データを取得するために`body-parser`を有効にします。

```javascript:app.js
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended: true}));
```

## 投稿フォームを追加
投稿データを入力するFormを作成します。

```javascript:index.pug
  form(method="post" action="/post/add")
    div
      label 名前: 
        input(type="textbox" name="name")
    div
      label 本文: 
        input(type="textbox" name="text")
    button(type="submit") 投稿
```


## 新規投稿処理
フォームから受け取った投稿データを、`app.locals.posts`に保存する処理を実装します。
`routes`フォルダ以下に`post.js`を作成します。

```javascript:post.js
var express = require('express');
var router = express.Router();

// 新規投稿
router.post('/add', function(req, res, next) {
    // 投稿データ全取得
    let posts = req.app.locals.posts;

    // 新規投稿データ作成
    posts.unshift({name:req.body.name, text:req.body.text });
    res.redirect('/');
});

module.exports = router;
```

ルーターに`/post`を登録します。これにより、`http://localhost:3000/post`にアクセスしたとき、`post.js`に定義した処理が実行されます。

```javascript:app.js
var postRouter = require('./routes/post');
app.use('/post', postRouter);
```

# 動作確認
```
set DEBUG=SimpleBBS:* & npm start
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2087075/9780fd2f-1759-528b-142a-cd6018e5d044.png)

# おわりに
現状、改善点が多く残っています。
改善方法についても別記事で説明できればいいなと考えています。
・バリデーション処理
・データの永続化
・レイアウトの改善
etc...

# 参考
https://web-camp.io/magazine/archives/5652
https://nodejs.keicode.com/nodejs/express-params-form.php
GalaxyWatch4で開発者モードを有効にする手順

##「システム」の項目が見当たらない 

WearOSに限らずAndroidで実機を使って開発を行う際、「ビルド番号」の項目を連打して開発者モードを有効にする必要があることはご存知だと思います。

https://developer.android.com/training/wearables/apps/debugging?hl=ja#enable-dev-options

GalaxyWatch4でも同様に開発者モードを有効にしようとすると、設定内に「システム」や「ビルド番号」の項目がないことに気がつきます。

<img width="250" alt="galaxywatch4_ss_01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583941/ea907456-7c0c-a260-1624-5560a59099ec.png">
　<font color="DarkGray">↑「システム」の項目が見当たらない</font>


GalaxyWatch4では開発者モードを有効にする手順が違うようです。

## 手順
1. まず、設定アプリを開き、「時計について」→「ソフトウェア」と押していきます。
<img width="250" alt="galaxywatch4_ss_01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583941/ea907456-7c0c-a260-1624-5560a59099ec.png">  <img width="250" alt="galaxywatch4_ss_02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583941/02bf3705-f648-d9ff-dbc7-69fb02c743fe.png">

2. 続いて「ソフトウェアバージョン」の項目を見つけ、これを連打してください。開発者モードがONになります。(OFFにする場合も同じように連打してください)
<img width="250" alt="galaxywatch4_ss_03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583941/de8033f4-ee80-fc4f-3f0b-76348765e494.png">  <img width="250" alt="galaxywatch4_ss_04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583941/50649773-a1eb-8991-50bd-34cb28cdab73.png">

3. ここで設定アプリのトップ画面に「開発者オプション」の項目が追加されています。ここから各設定を行えます。
<img width="250" alt="galaxywatch4_ss_05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583941/51429704-bec8-e77e-6550-80ba64b7a58a.png"> <img width="250" alt="galaxywatch4_ss_06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583941/269fc30d-63d2-dda7-fcc7-562d2eac6b35.png">  <img width="250" alt="galaxywatch4_ss_07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583941/0ba5fe00-2f13-35be-f364-c8d1dd86c636.png">
右にスライドしてONです

おしまい

## 環境
システム: Android 11.0
WearOS バージョン: 3.2
VS CodeでPHPのデバッグ環境を構築する（Xdebug導入）

#導入環境
php : 8.0.13
vscode : 1.63.0
xdebug : 3.1.2
XAMPP : 8.0.13
OS : Windows 10

#VSCodeの拡張機能「PHP Debug」をインストールする
複数あるが、Felix Becker氏の物をインストールする。
PHP DebugはXdebugとVSCodeを橋渡しするための拡張なので、次にXdebugをインストールする必要がある。

#PHPのエクステンション「Xdebug」をインストールする
###環境情報のコピー
新しくファイルを作成し、test.phpとリネームして、以下のコードを貼り付け実行する。

``` test.php
<?php 
phpinfo();
```

以下のように表示されるので、テキストをctrl + Aを押して全コピーする。


![スクリーンショット (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2351428/144ed7c4-7d78-bd26-d236-21f94075134d.png "全選択する情報")

###インストールウィザードで適切なファイルのダウンロードを行う
[Xdebugインストールウィザード](https://xdebug.org/wizard)を開き、全コピーした内容をそのままテキストエリアに貼り付け
Analyse my phpinfo() outputをクリックする。

以下のように表示されるので、ファイル(windowsはdllファイル)をダウンロードする。

![スクリーンショット (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2351428/089dc3ea-b94e-8922-86ad-0aab284e4805.png)

###ファイルのインストール

ダウンロードしたファイルをphp_xdebug.dllとリネームして、 
インストールウィザードで指定された場所(上記の画像ならC:\xampp\php\ext)へ移動させる。
ダウンロードしたXdebugのバージョンによってphp.iniに記述する設定内容が変化するので注意する。

###php.iniファイルへ設定を追加する

インストールウィザードで指定されたパスにあるphp.iniを開き、以下の設定を追加する。
ファイルのリネームを行っていない場合は値をフルパスで記述する。

```php.ini
 zend_extension = xdebug
```

上記の内容だけだとステップ実行が出来ないので、
Xdebugのバージョンごとに以下の内容を追加する。

Xdebug v3.x.xでのphp.iniへの追加内容

```php.ini
xdebug.mode = debug
xdebug.start_with_request = yes
```

Xdebug v2.x.xでのphp.iniへ追加内容

```php.ini
xdebug.remote_enable = 1
xdebug.remote_autostart = 1
xdebug.remote_port = 9000
```
###動作確認
Webサーバを立ち上げているなら再起動を行い、最初に作成したtest.phpを実行する。

``` test.php
<?php 
phpinfo();
```
表示されるテキストにXdebugの項目が新たに追加されていて、
Xdebug v3系だと以下の画像のように設定されていたら導入成功！

**Step Debuggerがenabledになっている**
![スクリーンショット (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2351428/6d981ba7-fe4e-7491-cb10-93e84c36a613.png)
**xdebug.start_with_requestがyesになっている**
![スクリーンショット (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2351428/8b6ba48a-7614-3745-f961-95925f3fee5b.png)
データ量増大により発生したありえない事件TOP3

とあるOLTPのシステムにおいて、大昔のS-in当初と比べて取り扱うデータ量が大きく肥大してきたことにより発生した、ありえない事件簿。
ありえないと思った順にTOP3を紹介する。

第３位：日次バッチが24時間で終わらなくなって、翌日分が開始できなかった！

データ量が増大して徐々に処理時間が伸びるようにあり、やがて24時間を超えたために発生した事件。

そんなことある？？
というか、数時間かかるようになったタイミングで気づいて対処しようよ～。

第２位：ＤＢで一意制約違反発生の原因が、Oracleシーケンスのカンスト

シーケンスが上限まで行ったら1に戻るように設定されていて、
いつの間にかその上限を超えて2周目に入っていた・・・
だけならまだしも、たまたまテーブルがこのシーケンスと別のキーとの複合キーになっていたため、
1に戻っていてもキー重複でエラーになるかどうかは運次第だった。

そして、エラーが発生した時点で、シーケンスは2周目ではなく、3周目の半ばあたりだった。(　ﾟдﾟ)


第１位：性能対策のはずのパージバッチが・・

DB高騰要因となっていたテーブルのデータ量削減のため、
月次バッチで古いデータをパージテーブルに退避する仕組みが作られた。

それで数年は無風だったのだが、そのうち、
毎月決まったタイミングでスローダウンが発生するという報告が上がるようになり調査したところ、
パージバッチが動作している時間帯とぴったり重なることが判明。

月単位でたまるデータ量が徐々に増えていったたため、パージ処理自体が重くなってしまった模様。
暫定的にパージバッチは停止され、その後誰も恒久策を打たないまま、どうなったのかは知らない。
初のOracleで今までmysqlになかったものがいっぱいな気がするので書いてみる

## DUALの使い方

DUALはダミーの表として扱われる
①関数だけを使う

```
select sysdate from dual;
```

②動作確認で使う

## 関数
- NVL関数とは、「抽出した値がNULLの場合、代替値を返す」もの。
Webの勉強はじめてみた その13 ～linuxコマンド ファイル操作編～

N予備校「プログラミング入門 Webアプリ」を進めています。
今回は第2章3節と4節を受講しました。
コンピューターの構造とlinux上のファイル操作コマンド、最後にvagrantとの共有フォルダの作成です。

<h2>学んだこと</h2>
<h3>ハードウェアの一覧を表示</h3>
`sudo lshw -short`


:::note
H/W path : ハードウェアの階層構造
:::
2進数とも違う表記。
マザーボードのどこに繋がってるかってことなんだろうか。

:::note
コンピューターにおけるデータの通り道を バス （bus）と呼ぶ。
:::
基盤につなぐケーブルをイメージしたけど合ってるでしょうか？

<h3>階層</h3>
:::note
. カレントディレクトリ
.. 1つ上の階層のディレクトリ
~ （チルダ) は、ホームディレクトリ。/homeとは違う。
:::

<h3>コマンド</h3>
:::note
<ul>
<li>df : ディスクの使用率</li>
<li>man : MANual マニュアル</li>
<li>pwd: Print Working Directory カレントディレクトリ</li>
<li>cd : Change Directory カレントディレクトリの変更</li>
<li>mkdir : MaKe DIRectory ディレクトリ作成</li>
<li>cp : ファイルやディレクトリのコピー</li>
<li>rm : ファイルやディレクトリの削除</li>
<li>mv : ファイルやディレクトリの移動</li>
<li>ls : LiSt カレントディレクトリ一覧</li>
<li>find : ファイルを検索する</li>
</ul>
:::

メモがてら。
`mv`は気を付けたい。

:::note warn
移動先として指定したディレクトリがまだ存在しない状態で mv コマンドを使うと、移動先として指定したディレクトリ名に名前が変更される。
移動先として指定したディレクトリがすでに存在する状態で mv コマンドを使うと、
移動元のディレクトリ名を保持したまま（名前変更されずに）移動先のディレクトリの下に配置される。
:::

<h4>オプション</h4>
`ls -a`  .(ドット)で始まるファイルも含めすべて表示するオプション
`rm -r` / `rmdir`  ディレクトリ削除
`cp -r` ディレクトリの中身も含めて、再帰的にコピーする
`find . -name b` カレントディレクトリ以下から、名前が b のファイルとディレクトリが検索される。`-name`では正規表現も使える。

<h3>Vagrantfileの編集</h3>
Powershell上で`code`を打つとVSCodeを開ける。
`code .`  ディレクトリを開く

https://maku.blog/p/f5iv9kx/

以下を追加

```
config.vm.synced_folder "./workspace", "/home/vagrant/workspace"
```

VirtualBoxの容量を増やすためにコメントアウトを消す

```
  config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
    vb.memory = "1024"
  end
```

プロビジョニングし再起動
vagrant reload --provision

https://qiita.com/oreo3@github/items/4054a4120ccc249676d9


<h2>まとめ</h2>
プログラミングでのファイル操作はbatファイルで使ったことがあるくらいなのであんまりまだピンと来てない部分があります。はやく実際に使ってみたいところ。