OmniAICreator/Qiita-1.07M huggingface dataset:
ページネーション

##ページネーション
長い文章を複数のページに分割して、各ページへのリンクを並べアクセスすることです。
まずはkaminariというGemをインストールします。
追記する場所は、Gemfileの最後の行です。

```
gem 'kaminari'
```
```
$ bundle install
```
##pageメソッド
kaminariを導入すると、モデルクラスにpageメソッドが定義されます。このメソッドは、ページ数を指定します。
kaminariによってリクエストの際paramsの中にpageというキーが追加されています。その値がビューで指定したページ番号となるため、pageの引数はparams[:page]となります。
##perメソッド
kaminariを導入すると、モデルクラスにperメソッドが定義されます。このメソッドは、1ページあたりに表示する件数を指定します。perメソッドに引数として渡した数字が、ページネーションが実装されたビューで1ページあたりに表示するレコードの件数になります。
【例】

```
変数名 = クラスを利用して取得したレコードのインスタンス.page(params[:page]).per(1ページで表示したい件数)
```
今回はモデル名Tweetでindexアクションに定義していきたいと思います。

```
〜省略〜
def index
    @tweets = Tweet.includes(:user).order("created_at DESC").page(params[:page]).per(10)
  end
〜省略〜
```
上記の記述で投稿が10つ以上だったら次のページにいけるようにしました。
だがこれだけではまだエラーがでてしまいます。
##paginateメソッド
kaminariを導入すると、paginateというヘルパーメソッドが使用できます。このメソッドは、ページネーションのリンクを表示したいときに使用します。
paginateメソッドの引数は、コントローラーで定義したレコード情報を持つインスタンス変数を指定します。
投稿を全て表示した後に、ページネーションのリンクを表示したいので最後の行に記述していきます。
【例】

```app/views/tweets/index.html.erb
〜省略〜
<%= simple_format(tweet.text) %>
      <span class="XXXX">
        <a href="/users/<%= tweet.user.id %>">
          <span>投稿者</span><%= tweet.user.nickname %>
        </a>
      </span>
    </div>
  <% end %>
  <%= paginate(@tweets) %>
</div>
```
上記の<%= paginate(@tweets) %>これで、ページネーションを実装することができました。
##マイページ表示にもページネーション
これもさっきのと同じで

```app/controllers/users_controller.rb
class UsersController < ApplicationController
  def show
    user = User.find(params[:id])
    @nickname = user.nickname
    @tweets = user.tweets.page(params[:page]).per(5).order("created_at DESC")
  end
end
```
上記のように記述し

```app/views/users/show.html.erb
<div class="XXXX">
  <p><%= @nickname %>さんの投稿一覧</p>

  <% @tweets.each do |tweet| %>
    <div class="YYYY" style="background-image: url(<%= tweet.image %>);">
      <%= simple_format(tweet.text) %>
    </div>
  <% end %>
  <%= paginate(@tweets) %>
</div>
```
上記の<%= paginate(@tweets) %>を記述すればtweetのindexアクションとuserのshowアクションにページネーションの実装ができました。
getRouteKeyNameメソッドでLaravelのURLをID以外にする方法

##はじめに
LaravelでWebアプリケーションを開発していると、 `/discussion/17` のようにIDからURLが生成されます。

しかし、これではSEOやユーザーフレンドリーの観点から適切ではない場合もあるでしょう。
そこでIDで渡されてくる箇所を、 `/discussion/hello-laravel` のように文字列（ここではタイトル名のスラッグ）にする方法を紹介します。

##スラッグを使用するために
まず、URLにスラッグを使用するためには、 `URLを生成する箇所` と `URLを解釈する箇所` の2つを修正する必要があります。

##URLを生成する箇所
コントローラー内のDBに保存する箇所で新たに `slug` を追加します。このslugがURLのIDの代わりになる部分です。

```DiscussionsController.php
public function store(Request $request)
{
  App\Discussion::create([
    'title'   => $request->title,
    'slug'    => str_slug($request->title),
    'content' => $request->content,
  ]);
}
```

DBに保存するためには、マイグレーションファイルを修正して新たにカラムを追加する必要があります。
URLが重複しないように `unique()` 制約をつけます。

```create_discussions_table.php
public function up()
{
  Schema::create('discussions', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('title');
    $table->string('slug')->unique();
    $table->text('content');
    $table->timestamps();
  });
}
```

##URLを解釈する箇所
まずLaravelではどのようにURLを解釈しているのかというと、Laravelでは[インプリシットバインディング](https://laravel.com/docs/5.8/routing#implicit-binding)という機能があり、タイプヒントされた変数名とルートセグメント名が一致する場合、ルートまたはコントローラーアクションで定義されたEloquentモデルを自動的に解決してくれます。

例えば以下の場合だと、

```web.php
Route::get('discussions/{discussion}', function (App\Discussion $discussion) {
  dd($discussion->toArray());
});
```

`$discussion`はApp\Discussion Eloquentモデルとしてタイプヒントされて、`$discussion`とURIの一部である`{discussion}`が一致するため、リクエストURIの対応する値と一致するIDを持つモデルインスタンスを自動的に挿入してくれます。

そのため、`http://localhost/discussions/1`でアクセスした際に、IDが１のDiscussionインスタンスが自動的に挿入されます。

ここでは、IDが1の箇所をタイトル名のスラッグに変更したいので、Discussionモデル内で`getRouteKeyName()`を使用して、変更したいカラム名でオーバーライドしてあげます。

```Discussion.php
public function getRouteKeyName()
{
  return 'slug';
}
```

これで、以下のレコードが生成されている場合、slugを利用したURLでアクセスすることができるようになります。


|id|title|slug|content|created_at|updated_at|   
|:-:|:--:|:--:|:-----:|:--------:|:--------:|
| 1 |Hello Laravel|hello-laravel|I Love Laravel|2020-01-01 00:00:00|2020-01-01 00:00:00|

`http://localhost/discussions/hello-laravel`
[Unity] macOS CatalinaでのUnityインストールでつまづいた話

# 概要
macOS CatalinaにおいてUnityをインストールしようとした時に問題に直面し、解決に至った事に関するメモです。

またCatalinaでUnity2018.2.x系を使おうとしている方は、ProjectVersionを上げる必要があるかもしれません。
該当する方は下記もお読みください。

>[Unity] Mac CatalinaでUnity2018.2系が正常動作しなかった話
>https://qiita.com/roboqlo/items/ccba760560103da98178


# 環境
| 項目 | 機種・バージョン |
|:--|:--|
| PC | MacBookPro 16インチ |
| OS | macOS Catalina 10.15.3 |
| UnityHub | 2.3.0 |

# 発生した問題
UnityHubからUnityをインストール中、進捗ゲージが8割ほど溜まったところでリストからフッと消失。
なんのエラーも出さずに消えてしまいました。

繰り返し試行していると正常にインストールできる場合とできない場合があり、３回に１回くらい成功していました。

UnityHubを経由せずにインストールしようとすると、インストール先選択画面で権限周りのエラーが表示されており先に進めませんでした。

# 解決策
UnityHubのインストール後にMac自体の環境設定から下記の通り設定しました。

環境設定 > セキュリティとプライバシー > プライバシーから、
『ディスクフルアクセス』の権限をUnityHubに付与。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596598/8e5409dd-2ea5-6673-093b-fffee5f215a5.png)

他には、直接的に解決に関係したかどうかは不明ですが下記は実施しました。

- MacOSを最新にアップデート
- 何かをインストールした際には適宜再起動

上記実施後は、UnityHubから安定してUnityのインストールができています。
UnityHubを経由せずにインストーラからインストールする方は解決できていませんが、UnityHubからインストールできれば特に困らないと思ったので突き詰めていません。
Flutterでアドベンチャーゲームもどきを作ってみる 文字送り編

Flutterで、アドベンチャーゲームっぽい感じの文字送り。

#画面を作る
`Stack`を使うことで、背景画像と人画像を重ねて表示。
メッセージ表示領域はあんまり真面目に作る気がなかったのでボタンで代用。
`Alignment.topLeft`を指定してボタンのテキストを左上に表示させ、メッセージウィンドウ風に。

```dart
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Stack(
              children: <Widget>[
                // 背景画像
                Align(
                  alignment: Alignment.center,
                  child: Image.asset(
                    'images/bg_natural_sougen.jpg',
                  ),
                ),
                // 前面画像
                Align(
                  alignment: Alignment.center,
                  child: Image.asset(
                    'images/keirou_couple2.png',
                  ),
                ),
              ],
            ),
            // メッセージ表示領域(ボタン)
            SizedBox(
                width: MediaQuery.of(context).size.width,
                height: 200,
                child: RaisedButton(
                  child: Align(
                      alignment: Alignment.topLeft,
                      child: new Text("$_showMsg")),
                  color: Colors.blue.withOpacity(0.3),
                  textColor: Colors.white,
                  onPressed: () {
                    updateMsg();
                  },
                ))
          ],
        ),
      ),
    );
  }
```

#文字送りを実装する
そういうパッケージが既にありそうな気はするけど、自前で実装。
画面に表示したい文字列を分割して、表示用の変数(_showMsg)に1文字ずつ追加する。
追加の度にDelayをかけると、文字送りっぽい感じの見た目になる。

await Delayしている最中に、ボタン連打されてしまうと色々と不都合なので、
bool値(_isAdding)を使って原始的なガードをかける。
ガード内でDelayする時間を0に変更することで、なんだかより"それっぽい"感じの挙動になってくれた。

```dart

  // メッセージリスト
  static const _msgList = [
    "むかしむかし、おじいさんとおばあさんが住んでいました。",
    "おじいさんは山へ芝刈りに、おばあさんは川へ洗濯に出かけました。"
  ];

  // メッセージ表示中であることを示すフラグ
  var _isAdding = false;
  // 現在表示中のメッセージリスト行番号
  var _msgCount = 0;
  // 画面に表示される文字列
  var _showMsg = "";
  // Delay時間
  var _delayMilliSeconds = 0;

  void updateMsg() async {
    if (_isAdding) {
      // メッセージ表示中にボタンタップされた場合、待ち時間を0にする。
      _delayMilliSeconds = 0;
      return;
    }

    _isAdding = true;
    _delayMilliSeconds = 100;

    // 文字追加前に_showMsgを初期化
    setState(() {
      _showMsg = "";
    });

    for (var i = 0; i < _msgList[_msgCount].length; i++) {
      // メッセージリストの内容を1文字ずつ追加する
      setState(() {
        _showMsg += _msgList[_msgCount].substring(i, i + 1);
      });
      // 文字列を追加した後、Delayする
      await new Future.delayed(new Duration(milliseconds: _delayMilliSeconds));
    }
    _msgCount++;
    _isAdding = false;
  }

```

画像変更編に続く？
VPS(nttpc,Indigo)にMATE-desktopを入れて、リモートデスクトップから接続する

ディスプレイレスなVPSに、linux-desktopを入れて、クライアントからは remote-desktop で接続する。
VPS上のサーバ（MATE-desktop)に, remote-desktop-client から接続して、これを踏み台にしてインターネットへアクセスすることを企てた。

```
+-------------+             +-------------+       ::::::::::::::
| RDP client  | ==(rdp)===> | xrdp on VPS | ===>  :: internet ::
+-------------+             +-------------+       ::::::::::::::
```

# VPS
[nttpc, Indigo](https://web.arena.ne.jp/indigo/?argument=vUrp7v4z&dmai=g_191223_0231&gclid=CjwKCAiAzJLzBRAZEiwAmZb0av-wCJnyuEqeA5IkowwFNIrI5HOabpxCizX-_QQm50I1kFIsG8EyqxoCHRsQAvD_BwE)

 nttpc の Indigo がとても安価だったので、これを使います。スペックはこれだけあえば、一人で使うには十分でしょう。VPSへは、sshログインして作業しますが、その方法は割愛します。

- centos-7.5
- 1cpu / 1G
- ssd 20G


## ユーザ追加
rdpするためのユーザ(hoge)を作成します。

```
  $ sudo adduser hoge
  
ssh鍵を配置し、ssh鍵認証でログイン可能にする
  $ sudo mkdir /home/hoge/.ssh 
  $ sudo chown hoge:hoge /home/hoge/.ssh 
  $ sudo cp /home/centos/.ssh/authorized_keys /home/hoge/.ssh/authorized_keys  
  $ sudo chown hoge:hoge /home/hoge/.ssh/authorized_keys 

hogeが sudo 可能にする。
  $ sudo gpasswd -a hoge wheel
```

## MATEのインストール
 これからの作業は、rootにスイッチして行います。軽量デスクトップのMATEをインストールします。
[MATE Desktop]だけインストールで十分な気がしますが、どうにも接続できなかった。無駄ですが[GNOME Desktop]をいったん入れます。

```
yum install epel-release 
yum group-list

yum groupinstall "GNOME Desktop"
yum groupinstall "MATE Desktop"
systemctl get-default
  
yum install xrdp
yum install tigervnc-server
systemctl enable xrdp 
systemctl start  xrdp 

echo "PREFERRED=/usr/bin/mate-session" > /etc/sysconfig/desktop
```

## サーバ自体の起動モードは、CUIでも大丈夫
VPSなので、ディスプレイレス。サーバ本体はCUIでも大丈夫でした、

```
systemctl get-default 
systemctl set-default multi-user 
```

## ポートを空ける
 サーバのfirewallを開けます。
また、VPSのfirewallも同様に開けてください。nttpcのIndigoの場合、ネットワーク管理>>ファイアーウォールのインバウンド、アウトバウンドで必要なポートを開けます。インバウンドはtcp3389、アウトバウンドは全開きにしました。ここで作成したFWを、インスタンスに割当します。

```
firewall-cmd --list-all
ls /usr/lib/firewalld/services/
firewall-cmd --permanent --add-service=qms-wbt  
firewall-cmd --reload
```

## その他設定
　その他に設定、インストールしたもの。これ以外に、rdpで接続したGUIから、言語を日本語に設定。

タイムゾーン

```
timedatectl set-timezone Asia/Tokyo
timedatectl 
```

chromium

```
yum install chromium
```
# 日本語入力を設定する
CUIインストールから、Gnome-desktop, MATE-desktopでは日本語入力が設定されなかったので追加設定します。

## iibus-daemonの自動起動

```
/etc/X11/xinit/xinitrc
  ┗ /etc/X11/xinit/xinitrc-common
      ┗ /etc/X11/xinit/xinitrc.d/* を呼び出ししているので、ここにスクリプトを置く
```

xinitrcから次のスクリプトを呼び出して、ibus-daemonを自動起動にする。

```bash:/etc/X11/xinit/xinitrc.d/mosc.sh
# vi /etc/X11/xinit/xinitrc.d/mosc.sh 
  # 日本語入力
  export GTK_IM_MODULE=ibus
  export XMODIFIERS=@im=ibus
  export QT_IM_MODULE=ibus
  ibus-daemon -drx

# chmod +x /etc/X11/xinit/xinitrc.d/mosc.sh 
```

## MOSCを入力メソッドに追加
  GUIログインして、

### IBUSの設定をメニューに追加

- システム >> コントロールセンタ >> メインメニュー
- メニュー：システム >> 設定 で、「IBUSの設定」を有効化

### IBUSの設定から、入力メソッドを追加

IBUSの設定を起動

- [一般]タブ >> キーボードショートカット >> 次の入力メソッド を、\<Control\>space に設定
- [入力メソッド]タブで、Mozcを追加
【ユークリッドの互除法】2つの値の公約数のうち、n 番目に大きい数値を高速に求める

ふたつの値 A も B も割り切れる値の中から n 番目（K）に大きい数値を求める場合、一般的には以下のように書くことで求められる。

```typescript
const input = "50 100 4"

const main = (input: string) => {
  const [A, B, K] = input.split(" ").map(str => parseInt(str))
  let divisorList = [];

  for (let i = A; i > 0; i--) {
    if(A % i === 0 && B % i === 0) {
      divisorList.push(i)
    }
  }
  console.log(divisorList[K - 1])
}

main(input);
```

ループの中でそれぞれの約数を求め、配列に突っ込んでいる。
今回の条件は`n 番目に大きい数値`を求めるため、配列には大きな数値から並ぶようにしている。

## ユークリッドの互除法
ユークリッドの互除法というものを使えばもっと高速に処理することも可能。
ユークリッド互除法は最大公約数を簡単に高速に求めることが可能な方法。
[Javascriptで最大公約数を求める(ユークリッドの互除法)](https://chiko-ryo-program.blogspot.com/2015/10/javascript_29.html)

これを使って最大公約数を求めてから、その約数を列挙することでNの約数列挙はO(√N)で済むため、プログラムが高速になる。（ループの回数が極端に減る）

```typescript
const input = "50 100 4"

const main = (input: string) => {
  const [A, B, K] = input.split(" ").map(str => parseInt(str))
  let divisorList = [];

  const calcGcd = (a: number, b: number): number => {
    const r = a % b;
    if(r === 0) {
      return b;
    }
    return calcGcd(b, a % b)
  }

  const gcd = calcGcd(A, B)

  for (let i = gcd; i > 0; i--) {
    if(gcd % i === 0) {
      divisorList.push(i)
    }
  }

  console.log(divisorList[K - 1])
}

main(input);
```

さらにこれだと `A === B` であるときはループの回数が変わらないので、約数の列挙を以下の記事を参考に修正してみる。(記事は Python)

[約数を高速で列挙するコード(Python)](https://qiita.com/LorseKudos/items/9eb560494862c8b4eb56)

```typescript
const input = "50 100 4"

const main = (input: string) => {
  const [A, B, K] = input.split(" ").map(str => parseInt(str))
  let divisorList = [];

  const calcGcd = (a: number, b: number): number => {
    const r = a % b;
    if(r === 0) {
      return b;
    }
    return calcGcd(b, a % b)
  }

  const gcd = calcGcd(A, B)
  const squareRoot = Math.ceil(Math.sqrt(gcd))

  for (let i = squareRoot; i > 0; i--) {
    if(gcd % i === 0) {
      divisorList.push(i)
      if(i !== gcd / i) {
        divisorList.push(gcd / i)
      }
    }
  }

  console.log(divisorList[K - 1])
}

main(input);
```

例えば 50 の約数を求めるときは 50 は 2 で割り切れるので、2 だけではなく、同時に `50/2 = 25` も約数であることがわかるので、わざわざ 1-50まで割り切らなくても、1-8まで割ることで全ての約数をカバーすることが可能になる。
そこで、

```typescript
const squareRoot = Math.ceil(Math.sqrt(gcd))
```
ここでまず平方根を求めて整数化して for 文に渡している。

ただしこの方法だと約数の配列順序がバラバラになってしまうので、降順にソートして返す。

```typescript
const input = "50 100 4"

const main = (input: string) => {
  const [A, B, K] = input.split(" ").map(str => parseInt(str))
  let divisorList = [];

  const calcGcd = (a: number, b: number): number => {
    const r = a % b;
    if(r === 0) {
      return b;
    }
    return calcGcd(b, a % b)
  }

  const compareFunc = (a: number, b: number) => {
    return b - a;
  }

  const gcd = calcGcd(A, B)
  const squareRoot = Math.ceil(Math.sqrt(gcd))

  for (let i = squareRoot; i > 0; i--) {
    if(gcd % i === 0) {
      divisorList.push(i)
      if(i !== gcd / i) {
        divisorList.push(gcd / i)
      }
    }
  }

  divisorList.sort(compareFunc)
  console.log(divisorList[K - 1])
}

main(input);
```

これで非常に高速に指定した約数を取得することができる。
Google Spreadsheetでつくるアナログ時計

#きっかけ
子供の宿題を見てて急に複素数の復習をしたくなりました
z=r(cos+isin)久々に思い出しました

#下準備
Google spread sheetを用意する
![下準備.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1817/822451d8-ae6b-12a3-f82c-007b0567f64a.gif)

#時間から秒,分そして時間を抽出する
![時間から秒,分そして時間を抽出する.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1817/adf0bfb6-df58-c066-c445-922669cbb8bf.gif)

時間に関しては24時間表記だとアナログ時計としては都合が悪いので
MODします

#1メモリ進んだときの角度を計算する
![1メモリ進んだときの角度を計算する.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1817/3bc10124-a392-cfcb-563b-d8ebfec788c4.gif)

秒針、分針は 360/60 = 6°
時針は 360/12 = 30°
ですね

#xとy座標をそれぞれ計算する
ここで　高校生のときに勉強した　複素数の極形式を使います
z=r(cos+isin)
rの長さに関しては　秒針は1.2の長さ、分針は1.0の長さ,時針は0.8の長さとしました
こちらを使うと 
秒針:90°から時計回りなので一秒進むごとに6°づつ引いていく
分針:90°から時計回りなので一分進むごとに6°づつ引いていくさらに秒針を考慮して更に秒あたり1/60°づつ調整
時針:90°から時計回りなので一時間進むごとに30°づつ引いていくさらに分針を考慮して更に分あたり1/60 °づつ調整

![xとy座標をそれぞれ計算する.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1817/5c926017-b180-359b-e1e0-267cf5a2c12b.gif)

#グラフを作る
![グラフを作る.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1817/31f51721-6ecf-a941-31cd-202acbc0604d.gif)

#一秒に一回動くようにする
このようなGASスクリプトを用意します
GASのトリガーは一分に一回なのでUtilities.sleepで一秒スリープして
55回/分　更新するようにします
5秒分はバッファです*適当

```JavaScript
function myFunction() {
  var sheet = SpreadsheetApp.getActiveSheet();
  for(var i = 0 ; i < 55 ; i ++){
    var now = new Date();
    sheet.getRange(1,1).setValue(now);
    sheet.setName(now);
    Utilities.sleep(1000);
  }
}
```
## Triggerをセットします
![Triggerをセットします.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1817/c5e3cc58-619b-51c0-6635-cdf117db9839.gif)

#まとめ
極形式をつかうといとも簡単に回転を表現できました。
20数年ぶりに思い出したのであってるか不安です。。
もしツッコミあればコメントいただきますと幸いです。
デモはこちら
https://docs.google.com/spreadsheets/d/10PUmZ9VZY7N9FCOKdaoICyjj8xAPr1Ff-dfPlhPD33s/edit?usp=sharing
Windows10 HomeでDocker Desktop for Windows Edgeを試してみる

# はじめに
2020/03/02にDocker Desktopが**Windows10 Home**版に対応したと発表がありました。
(https://www.docker.com/blog/docker-desktop-for-windows-home-is-here/)

従来Dockerを動かすためには基本的にWindowsPro版が必要だった上、ディストリビューションやDocker自体のバージョンを下げたりなど非常に面倒くさい手順が必要でしたが、これで普通のwindowsPCでも手軽に環境準備ができますね！

# 前提条件
- WSL2の導入  
コマンドプロンプトから以下のコマンドを実行し、ディストリビューション名の横の「VERSION」が「2」であればWSL2になっています。

```shell
C:\Users\myPC>wsl -l -v
  NAME                   STATE           VERSION
* Ubuntu                 Running         2
```



# 導入方法
1. https://docs.docker.com/docker-for-windows/edge-release-notes/
からインストーラーをダウンロード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265544/3fffcd46-9088-8f96-ea29-dd4a71343b9b.png)

1. インストーラーを起動
何もせずに「OK」を選択すると自動的にインストールが始まります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265544/4587664c-ded3-e198-1ae8-80f1b53e11f2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265544/ea383214-ce40-6aea-4a3f-d0a31f156cdb.png)

1. 完了したらPCを再起動し、タスクトレイを右クリック > 「Setting」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265544/c3b2db67-b571-e0aa-9eb6-264af47e19db.png)

1. 以下の設定になっているか確認してみてください

- 「General」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265544/9c8073c8-688a-3465-4524-8cd75405dbcf.png)

- 「Resources > WSL INTEGRATION」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265544/d9bf6974-630a-31d5-ee0a-bca4a99a85ee.png)

これで設定は以上になります。
あとはWSL側でDockerのプロセスが起動しているか確認してみてください。

```shell

root@DESKTOP-801IJ5R:~# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
```

# さいごに
正式版が待ち遠しいです！（WSL2も）
Winodows+DockerToolBoxで証明書の期限が切れてDockerに接続できない

普段から利用しているDockerでSSL関連でDockerコマンドが動作しなくなる問題が発生したため、解消の手順をメモしています。

```
$ docker-compose up -d
ERROR: SSL error: HTTPSConnectionPool(host='192.168.99.100', port=2376): Max retries exceeded with url: /v1.38/networks/scalaakkapractice_default (Caused by SSLError(SSLError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852)'),))
```

```
$ docker ps
error during connect: Get https://192.168.99.100:2376/v1.40/containers/json: x509: certificate has expired or is not yet valid
```

調べてところDockerに接続する部分のSSL証明書の有効期限が切れているようだったので証明書の有効期限を確認する。

```
$ openssl x509 -noout -dates -in ~/.docker/machine/certs/ca.pem 
notBefore=Mar 14 14:09:00 2017 GMT
notAfter=Feb 27 14:09:00 2020 GMT
```

2020/2/27で期限切れとなっていたので証明書を更新する。
（DockerToolBoxのデフォルトのmachine名はdefaultです）

```
$ docker-machine regenerate-certs --client-certs default
Regenerate TLS machine certs?  Warning: this is irreversible. (y/n): y

Regenerating TLS certificates
Regenerating local certificates
CA certificate is outdated and needs to be regenerated
Creating CA: C:\Users\shinohara\.docker\machine\certs\ca.pem
Client certificate is outdated and needs to be regenerated
Creating client certificate: C:\Users\shinohara\.docker\machine\certs\cert.pem
Waiting for SSH to be available...
Detecting the provisioner...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
```

証明書を更新すると、Dockerコマンドが動くようになった。

```
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
```
【Vim】lightline.vimでLanguageClient-nvimのエラー表示を改良する

lightlineで動的にエラー表示を行うには、[lightlineに用意されたイベントの仕組み](https://itchyny.hatenablog.com/entry/20130918/1379461406)を使う必要があります。
この仕組みをプラグインとして公開しているものはいくつかありますが、既存の[LanguageClient-nvim](https://github.com/autozimu/LanguageClient-neovim)用の設定が適用できない環境があったため、新しくプラグインを書きました。

## 作ったもの
https://github.com/takiyu/lightline-languageclient.vim
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257847/4aaa32d4-ef65-25d1-8748-c284fcab0383.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257847/6055d138-4dda-5396-564d-ca87f55f6a8d.png)

## これまでの何が問題か
既存のプラグイン・情報
* [Palpatineli/lightline-lsc-nvim](https://github.com/Palpatineli/lightline-lsc-nvim)
* [【Neovim】LanguageClinet-neovim + lightline.vimで簡易エラー表示](https://qiita.com/88IO/items/32ddc02fa35db13fd9ca)
* [solderneer/lightline-languageclient](https://github.com/solderneer/lightline-languageclient)

LanguageClient-nvim用のプラグインや記事では組み込み関数`getqflist()`を使用しているため、**QuickFixにエラー情報を載せる設定にしていなければならない**、という制約がありました。

すなわち、LanguageClient-nvimの標準の設定で

```viml
let g:LanguageClient_diagnosticsList = "Quickfix"
```
としているなら問題ありません。

しかしそれ以外の出力先にしている場合には、当然ですが正常に動作しません。

```viml
let g:LanguageClient_diagnosticsList = "Disabled"  " or Locacion-list or fzf
```
この項目はvimgrepやジャンプリスト(`g:LanguageClient_selectionUI`)の兼ね合いを考えた場合に設定することがあります。

## やったこと
そこでLanguageClient-nvimが出力する生のエラー情報を用いてlightlineに伝わるようにしました。
`LanguageClient#getState(callback)`を用いるとcallback関数にstateが渡されるAPIが存在します。
このstateを解析すればよいのですが、中身にvimのdictionary型ではなくてjsonの文字列が含まれているため、[よしなにパース](https://github.com/takiyu/lightline-languageclient.vim/blob/master/autoload/lightline/languageclient.vim)しました。
また残念ながらcallbackなAPIなため、合わせて`lightline#update()`の呼び出し場所も変えています。

## 使い方
### 1.通常通りにプラグインをインストールします。

```toml
[[plugins]]
repo = 'takiyu/lightline-languageclient.vim'
```
など。

### 2.lightline側に表示用の設定をします。

```viml
let g:lightline = {}

let g:lightline.component_expand = {
    \   'linter_errors': 'lightline#languageclient#errors',
    \   'linter_ok': 'lightline#languageclient#ok',
    \ }

let g:lightline.component_type = {
    \   'linter_errors': 'error',
    \   'linter_ok': 'left',
    \ }

let g:lightline.active = {
    \   'right': [[ 'linter_errors', 'linter_ok' ]],
    \ }
```

### 3.お好みで文字を変えてください。

```viml
let g:lightline#languageclient#indicator_ok = 'OK'
let g:lightline#languageclient#indicator_ns = 'N/S'
let g:lightline#languageclient#indicator_e = 'E:%d'
let g:lightline#languageclient#indicator_w = 'W:%d'
let g:lightline#languageclient#indicator_i = 'I:%d'
```

## 結論
`LanguageClient#getState()`で頑張ると、QuickFixに依存しないLanguageClient-nvimのエラー表示が出来ます。

## その他
PRお待ちしております。
Railsで定期的に実行したい処理を、rakeタスクを使って実装する。（おまけ:Wheneverとの連携）

「Railsで定期的に実行したい処理を、lib/tasks以下のディレクトリに、rakeタスクを作成して処理を記述することが多い。」という話を聞いてrakeタスク？？となったので、調べました。
以下にまとめて記載します。

#そもそもrakeとは
rake：Rubyで書かれたコードをタスクとして作成しておき、必要に応じて呼び出し実行する事が出来る機能です。

#rakeタスク
アプリケーションを起動せず、行いたい処理をCUI（コマンドプロンプトやターミナル）から実行でき、サーバーを起動せず任意の処理を実行できます。
つまり、冒頭のコメントにある”Railsで定期的に実行したい処理”をrakeタスクを作成して処理するというのは、例えば、以下のようなときに使えます。

- 何かしらのデータの連携
- データベースのバックアップ
- 定期的にデータを更新、削除する

#rakeタスクの使い方
##1.Rakeタスクファイルを生成
まず、処理を記載するためのrakeファイルを作成します。

```:ターミナル
$ rails g task ファイル名
```
上記コマンドを実行するとlib/tasks以下のディレクトリにファイルが生成されます。
それでは、早速処理の内容を記述していきましょう。

##2.処理内容の記述
今回は例として以下の記述を入れます。
処理内容：ユーザーが入店したかどうかを管理する"enterd_flag"というカラムをfalseにする

処理内容の記述箇所
namespace：生成したファイル名を記述します。＊今回、以下では[user]とします。
desc：実行する処理の説明を記述します。
task:タスクの名前を記述します。

```:lib/tasks/ファイル名
#モデルにアクセスする場合は :environmentの指定が必要です。
namespace :user do
  desc "ユーザーの入店情報をリセットする"
  task reset_entered_flag: :environment do
    User.update_all(entered_flag: false)
  end
end
```

##3.処理の実行
この処理を実行するには、以下のようにターミナルでコマンド入力することで実行できます。

```:ターミナル
#rake [namespeceの名前]:[taskの名前]
$ rake user:reset_entered_flag
```
#追加機能（定期的な処理を行うとき）/gem:wheneverの使用
今回のような処理を定期的に実行するときにはgem:wheneverを使うと実装できます。
wheneverはcrontab管理ライブラリです。
Crontab：UNIX系のOS（Linux,Macなど）で使えるcronを動かすためのコマンド。
Cron:UNIX系のOS（Linux、Macなど）でタイミングを指定しておき、そのタイミングになったら、このプログラムを動かしてくれるもの
詳細は、以下確認ください。
https://wa3.i-3-i.info/word11748.html

##1.wheneverのインストール

```:gemfile
gem 'whenever', require: false
 =>bundle install
```
*アプリケーションから使わないgemは require: false を付けます。
例えばcapistrano、rubocop、unicorn 等、今回もアプリケーションから使用しないため、require: false をつけます。
メリット
- 読み込まないようにして起動を少しでも早くする
- 想定外の挙動を減らす

##2.whenever設定ファイルschedule.rbを作成
まず、wheneverの設定するファイルを作成します。

```:ターミナル
$ bundle exec wheneverize
> [add] writing `./config/schedule.rb'
> [done] wheneverized! 
```

作成できたら、以下のように記述をしていきましょう。
実行するものは以下のいずれかを使用することで実行できます。
- command: bashコマンド実行
- rake: rakeタスク実行
- runner: Rails内のメソッド実行
- script: scriptの実行
- 
```:schedule.rb(例）
# 出力先のログファイルの指定
set :output, 'log/crontab.log'
# ジョブの実行環境の指定
set :environment, :production

# 3時間毎に実行するスケジューリング
every 3.hours do
  rake 'my:rake:task'
end
```

##3.Crontabへの設定
上記で設定した内容をCromtabに設定しましょう。

```:ターミナル
$ bundle exec whenever --update-crontab
```

以上で設定完了です。
Capistranoで本番環境にも簡単に設定できるようですので、気になる方は以下の参照ご確認の上、ご対応ください！


#参照
【Ruby on Rails】Rakeタスクを使えば様々な処理が自動化出来る？（初心者向け）
https://opiyotan.hatenablog.com/entry/rails-rake-task

javan/whenever
https://github.com/javan/whenever

Wheneverは導入が超簡単なcrontab管理ライブラリGemです！[Rails 4.2 x Ruby 2.3]
https://morizyun.github.io/blog/whenever-gem-rails-ruby-capistrano/index.html#Corntab%E3%81%B8%E3%81%AE%E8%A8%AD%E5%AE%9A

gemのwheneverを導入してみた
http://shiro-16.hatenablog.com/entry/2015/02/17/000715

Railsで定期的にバッチ回す「Whenever」
https://qiita.com/yumiyon/items/388fbb84450f49a6ab0d


以上となります。最後までご覧いただき、ありがとうございました！
今後も学習した事項に関してQiitaに投稿していきますので、よろしくお願いします！
記述に何か誤りなどございましたら、お手数ですが、ご連絡いただけますと幸いです。
orderメソッド

##orderメソッド
orderメソッドは、並び順を変更するメソッドです。
【例】モデルをTweetとします。

```
インスタンス = モデル名.all.order("並び替えの基準となるカラム名 並び順")
```
上記で設定できます。
並び替えの基準にはASC(昇順)とDESC(降順)の2種類があり、ASCは値が古いものから新しいのものになり、DESCはその逆で新しいものから古いものになります。
今回はcreated_at(作成日時)をDESCしてみます。

```app/controllers/tweets_controller.rb
〜省略〜
  def index
    @tweets = Tweet.includes(:user).order("created_at DESC")
  end
〜省略〜
```
上記でTweet.includes(:user)はN+1問題の解消、order("created_at DESC")でcreated_at(作成日時)が投稿したときに新しいものから古い順になります。
最近、思うテストのこと


最近、思うテストのことを書きます。
私のようにテストについて、腹落ちしていない人の手助けになればと。

本内容は、私の経験に基づく、個人的な主観になります。

# そもそも、何故、テストをするのか？
システムを使って、意図した通りのことができるか？を確認するため。

## 意図した通りとは？
業務フロー、操作フロー通りってこと。

# そしたら、業務フロー、操作フロー通りにテスト仕様書を書いて、テストすればよい？
フローが全てを網羅していれば、それで良い。
が、現実的には、問題がある。

## テスト仕様書を作るに当たっての問題点
フローは、全てを網羅しているわけではない（概略レベル）。枝葉は、書いていない。
要件定義書、設計書に分かれている。
　　業務フロー
　　　A
　　　↓
　　　B　★ Bの中の細かな話は、要件定義書、設計書に書かれている
　　　↓
　　　C
→業務フローだけなぞっても、ケースが足りない。
## テスト実施に当たっての問題点
テスト実施時に、フロー通りだと、手間。

A → B → C → D 

Cのテストをするのに、A → Bをやらないといけない。

# あれ？じゃあどうするの？
## テスト仕様書を作るに当たっての問題点に対してのアプローチ
→ 業務フロー以外に、要件定義書、設計書を見て、単純に増やせばよい。

## テスト実施に当たっての問題点に対するアプローチ
→ Cだけ切り出してテストをすればよい

# テストっていつする？
最後にまとめてやる？それとも、パーツ単位でやる？

## 最後にまとめてやると。。
### メリット
単体テスト、内部結合テスト、外部結合テスト とかフェーズを分けることなく、テスト仕様書が一本化され、重複するケースが減る。
### デメリット
規模が大きいと、テスト仕様書が膨大になり、テスト実施が遅くなり、バグが出たときに死ぬことになる。

## 細かくやる？
### メリット
テスト実施の開始時期が早くなり、バグの検出が早くなる。

### デメリット
単体テスト仕様書、内部結合テスト仕様書、外部結合テスト仕様書等、テスト仕様書が沢山増え、ケースの重複が増える。

# 回帰テストってどうする？
自動？手動？

## 自動でやると
### メリット
改修が怖くなくなる！

### デメリット
回帰テスト用のコードを書くため、テスト開始まで時間がかかる。

## 手動でやると
### メリット
テスト開始が早くなり、バグの検出時期が早くなる。

### デメリット
改修が怖くなるｗ

# まとめ
走り書きのように内に秘めてた内容を整理してみました。
結論としては、回帰テストの自動化は、メリットが大きいと思う。
フェーズ分け（単体、結合、総合）は、単体は必須で、残りは状況次第かな～って思う。
[Unity] macOS CatalinaでUnity2018.2系が正常動作しなかった話

# 概要
MacOS CatalinaにおいてUnity2018.2系で致命的な動作異常があり、仕方なく2018.3系に上げたという話です。

先に行き着いた結論を書いておくと、
**MacOS Catalinaでは、Unity2018.2系が正常動作しない可能性が高い** です。
具体的な問題としては、Audio系ファイルが一切Import不可。

**MacBookPro16インチはOSが初期状態からCatalinaになっており、ダウングレード不可**のため、購入を検討されている方は特に注意してください。

LTS版や2018.2以前では試していませんが、2018.2以前のバージョンでも同様の事象の発生が海外のフォーラムでいくつか上がっていました。

2018.3.14、および2019.3.0では問題は発生しませんでした。

# 環境
| 項目 | 機種・バージョン |
|----|----|
| PC | MacBookPro 16インチ |
| OS | macOS Catalina 10.15.3 |
|Unity|2018.2.0 及び 2018.2.21(2018.2.x系の最終バージョン)|

# 発生事象
Audio系ファイル(mp3,wave)がUnity一切Importできない状態になりました。

今回はCatalinaOSにUnity初期インストールした後のProject初期Import時に問題に直面しました。
何度やってもAudioファイルImportのところでImport中ゲージが進まなくなる。
Unityのログファイルをみてみると、下記のようなエラーを確認。

```
[NSConcreteTask terminationStatus]: task not launched
```

AudioファイルをProjectから全削除してみるとImportできましたが、その後改めてAudioファイルをインポートしようとするとやはり止まる。

# 解決方法
根本的な解決方法は見つからず、仕方なく2018.3系の最終バージョンである2018.3.14にバージョンアップしました。
（2018.2系と2018.3系は差が大きいのでできれば避けたかったですが。。）

下記フォーラムで同様の問題が挙がっていました。
https://forum.unity.com/threads/installing-unity-on-macos-catalina.689089/
https://issuetracker.unity3d.com/issues/macos-catalina-crash-on-dropping-audio-file-into-editor


# (余談) Unityのインストールでもつまづいた話
別の話として、Unity自体のインストールもCatalinaOSでは少しハマりました。
>[Unity] macOS CatalinaでのUnityインストールでつまづいた話
>https://qiita.com/roboqlo/items/71872ecb09e789e9c8ce

Unity以外もCatalinaは未だに互換性の問題が多くあり、特別理由がない限りはCatalinaへのアップデートは見送るのが良いかもしれませんね。
'Showing Recent Issues SWIFT_VERSION '3.0' is unsupported, supported versions are: 4.0, 4.2, 5.0.'について



久しぶり以前作成したSwiftのソースコードを開いたら、下記のエラーが発生しましたので、
対処方法を明記いたします。
※情報の判断はご自身の責任でお願い致します。

`Showing Recent Issues SWIFT_VERSION '3.0' is unsupported, supported versions are: 4.0, 4.2, 5.0.` 

環境:
Xcode11.3

原因:
原因といたしましては、Swiftのバージョンの違いによるものです。

対応方法:
使用しているSwiftのコードを最新にする必要があります。

project File → Build Phases → Swift Language Version
内のversionを任意のものにする必要があります。
![capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96378/f352f5e5-dc89-fb03-801f-574865106d25.png)

**※注意点としましては、Target,Project内のものを全てのバージョンを変更する必要があります。** 

以上となります。🦔
Zabbix単体でログからアバウトなレスポンスタイム計測 

# 背景
色々な仕組みが混在したシステムでボトルネックとなっている機能を特定するのに手間がかかりすぎる問題に対して、ログの中身を見てボトルネックを特定することが多々あった。大概問題が起きている機能はレスポンスタイムが遅くなっていたり、実行回数が異常であったりする。それを確認するためにいちいちログファイルを見て集計するのが面倒であったため、何か簡単にできる方法はないかと考えたもの。

# 概要
Zabbix単体でログからレスポンスタイムを計測する。具体的に取得するデータは単位時間(1監視間隔)当たりの以下。ログの時間をログ監視で取得し、計算アイテムで集計する。

- 平均応答時間  
- 最大応答時間
- アクセス回数

ただし、以下の欠点がある。

- 単位時間内にアクセスが無い(つまりログが無い)場合、その後のデータが正しく取得できない。Zabbixの平均値や最大値取得の関数がデータが0であると首都負荷状態になるため。「取得不可アイテムの監視間隔」後に正常に取得し出すが抜けた分は取得されない。
- 単位時間はログに記載された時間ではなく、もととなるデータをZabbixがログ監視で取得したタイミング。
- ログ監視と計算のタイミングが被ると集計がおかしくなる。

導入してみた結果、上記欠点が分かったためfluentdとZabbixで同様のデータを取得をしたいと考えた。しかしながら、精密なパフォーマンス取得ではなくボトルネック特定程度の用途であれば耐えれそう且つ、導入が容易であるため記事にしました。

![chart3.php.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443775/a0d66b91-fb00-98bd-04f0-c93f33a71b41.png)

# 構築方法
## 0. Apacheでレスポンスタイムを表示
Apacheを例にレスポンスタイムを測定する。デフォルトではレスポンスタイムが出力されないため、以下の設定をする。

- 設定内容

```

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common

## 上記の付近に以下を追加
LogFormat "time:%{%Y/%m/%d_%H:%M:%S %z}t\tx_forwarded_for:%{X-Forwarded-For}i\tremote_host:%h\trequest:%r\tlast_status:%s\tsize:%b\treferer:%{Referer}i\tuser_agent:%{User-Agent}i\tv_host:%{Host}i\tresponse_time:%D" apache_ltsv
```


```
## 以下をコメントアウト
#CustomLog "logs/access_log" combined

## 上記の付近に以下を追加
CustomLog "logs/access_log" apache_ltsv
```

- 出力例

```
time:2020/03/08_12:35:59 +0900  x_forwarded_for:-       remote_host:xxx.xxx.xxx.xxx        request:POST /zabbix/jsrpc.php?output=json-rpc HTTP/1.1    last_status:200 size:63 referer:http://xxxxxx/zabbix/zabbix.php?action=dashboard.view  user_agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36     v_host:xxxxxx       response_time:35108
```

## 1. Zabbixでログ監視アイテム設定
監視間隔は短めにする。パフォーマンスデータを1分間隔で取得したいのであれば次項の計算アイテムを1分間隔に設定するのであるが、それより短いほうがいい。このアイテムと次項のアイテムの取得間隔を同じにした場合、取得タイミングが秒単位でかぶると計算アイテムが正しい値を取得しなかった。
また、いくつかのZabbixのバージョンで試したが、データ型がおかしいエラーが出たときは数値(浮動小数点)で実施するととれることがある。  

```
・名前: (任意)
・タイプ: Zabbixエージェント(アクティブ)
・キー: log[/var/log/httpd/access_log,"items\.php.*response_time:([0-9]+)$",,,,\1]
・データ型: 数値(整数)
・監視間隔: 15s (短め、負荷を考えないのであれば1sでいい)  
```

## 2. 計算アイテムの設定
### アクセス回数
上記で作ったアイテムに"などが含まれるときは式内でエスケープが必要になるので気を付ける。

```
- 名前: Log_ApacheResponseTime_COUNT (任意)
- タイプ: 計算
- キー: ApacheResponseTime.COUNT (任意)
- 式: count("log[/var/log/httpd/access_log,\"items\.php.*response_time:([0-9]+)$\",,,,\1]",30)
- データ型: 数値(整数)
- 回
- 監視間隔: 30s
```

### 平均値
1000000で割っているのはApacheでログに出力しているレスポンスタイムがマイクロ秒であるため。

```
- 名前: Log_ApacheResponseTime_AVG (任意)
- タイプ: 計算
- キー: ApacheResponseTime.AVG (任意)
- 式: avg("log[/var/log/httpd/access_log,\"items\.php.*response_time:([0-9]+)$\",,,,\1]",30)/1000000
- データ型: 数値(浮動小数点)
- 単位:秒
- 監視間隔: 30s
```

## 最大値

```
- 名前: Log_ApacheResponseTime_MAX (任意)
- タイプ: 計算
- キー: ApacheResponseTime.MAX (任意)
- 式: max("log[/var/log/httpd/access_log,\"items\.php.*response_time:([0-9]+)$\",,,,\1]",30)/1000000
- データ型: 数値(浮動小数点)
- 単位:秒
- 監視間隔: 30s
```
【初心者】バッチについて

<h1>■バッチ処理とは</h1>

<br>一定期間に一定量のデータをまとめて一括処理すること

------------------------------------------------------------------
<h1>■書こうと思ったきっかけ</h1>
★とある日の会話★
機械：バッチがアベンド(異常終了)しました
Aさん：バッチがアベンドしたぞ！こんな夜遅い時間に最悪だ.... なんのバッチだ?
Bさん：売上のバッチでこけたみたいです....
私：?？？
Aさん：重要なバッチでアベンドしたな。
Bさん：原因を調査します！
Aさん：お客様に影響があったら大変だ！
Bさん：承知しました。私さん一緒にどのデータがうまく処理されなかったか原因調査してくれ！
私：!?!?

--------------------------------------------------------------
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164302/1f8f27c6-9217-35bd-7fbf-6c06f4284f05.png)
バッチについて無頓着であった私は何も力になれず...
これを機に簡単にバッチについて調べようと思い、
また、知識定着のためにもこの場をお借りしてスライドを作ろう思いました

-----------------------------------------------------------------------------
<h2>■あのとき何が起きていたのか？</h2>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164302/2391894f-50bd-71ef-47f1-75721f1257d8.png)
<言語化>
お店から売上依頼の命令がされて、バッチが起動したがデータ3がうまく処理されずにアベンドしてしまいエラーを検知した

---------------------------------------
<h2>■バッチについて深堀</h2>
・バッチ処理とは・・・一定期間に一定量のデータをまとめて一括処理する処理のこと

・バッチの処理時間・・・基本的に長め

・バッチの起動時間・・・毎時・日時・夜間等々

・バッチの種類・・・オフラインバッチ・オンラインバッチ

・オフラインバッチ・・・システムから切り離されたバッチ

・オンラインバッチ・・・システムと繋がっており、特定の時間にデータの処理をにしている

---------------------------------------------------------------------------
<h1>■バッチのメリット</h1>
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164302/022df528-0769-e76e-338e-038fde98731a.png)
・オペレーター不要

・好きな時間に処理が可能

・大量データの処理が可能(限界あり)

・入力ミスのような人的ミスがない

・複雑な処理を任せられる            

-------------------------------------------------------------------
<h1>■バッチのデメリット</h1>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164302/3c0ce1db-ec3c-f1b1-4e89-66fe8a8c7b8b.png)
・リアルタイムに確認できない

・大量データによる処理の遅延

・中身の仕組みが理解しにくいブラックボックス化

・アベンドしたときの対応・原因調査の難しさ

・現代はリアルタイムが当たり前の考え方が浸透している

-------------------------------------
<h1>■あのときの深堀</h1>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164302/f446d42e-2538-f11a-81f8-44ee6dac0e45.png)
<言語化>
お店から売上依頼の命令がされて、機械が自動的に21時にオンラインバッチを起動させた。
しかし、データ3がうまく処理されずにアベンドしてしまいエラーを検知、原因調査を行うもバッチの仕組みが理解しずらく影響調査に時間が掛かってしまったが原因は異常データによるものと判明し、データ3を除きバッチを再実行し成功した。
これによるお客様の影響はないと判明し対応は終了した。再発防止策や今後の対応について検討した。

-------------------------------------------------------------------------------------
<h1>■まとめ</h1>
現代はリアルタイムが当たり前の時代となり、私も当たり前の感覚を持ってしまった。
そのため、バッチのような処理は無頓着となってしまっていた。

今回起きたバッチの異常終了の原因は異常なデータによるものだった。

影響調査の中で難しいと感じたのは、データ1と2は正常にうまく処理されているのか?
それともデータ3だけ処理されなかったのか?データ4があった場合は処理がされるのか?等
バッチの仕組みを理解するのが難しい感じた。

また、もしこれが数百万単位のデータであったら処理ができるのかなどバッチ処理は調べれば調べるほど奥が深いと感じた。
Firebaseのsnapshotのchildrenの扱い方の研究

Firebaseで以下のような構造を持つデータがあった場合、`ref.child("users").observe(.value, ...)`とした場合に変更を検知して帰ってくるsnapshotがどんな値か分からなかった。やりたいことはユーザーの子の子である注文情報が追加されたら、それが誰であってもタイムラインに表示をさせたい。

<img width="948" alt="スクリーンショット 2020-03-08 16.31.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242610/a69ea246-c066-2661-97cb-ebedcc4f1567.png">

[公式リファレンス](https://firebase.google.com/docs/database/ios/lists-of-data?hl=ja#listen_for_value_events)では`.value`を使うときは`snapshot.children`をforで回して個別の子にアクセスできるよと書いているが、何のこっちゃよく分からない。なので毎回childをprintすることで、どんな値なのか調べてみた。


```swift

    func startObservingDatabase () {
        databaseHandle = ref.child("users").observe(.value, with: { [weak self] (snapshot) in
            guard let strongSelf = self else { return }
            strongSelf.orders.removeAll()
            print("snapshot: \(snapshot)")
            for child in snapshot.children {
                print("snapshot.child: \(child)")
                guard let userSnapshot = child as? DataSnapshot else { return }
                for child in userSnapshot.children {
                    print("userSnapshot.child:\(child)")
                    guard let ordersSnapshot = child as? DataSnapshot else { return }
                    for child in ordersSnapshot.children {
                        print("ordersSnapshot.child:\(child)")
                        guard let orderSnapshot = child as? DataSnapshot else { return }
                        strongSelf.orders.append(orderSnapshot)
                    }
                }
            }
            strongSelf.orders.reverse()
            strongSelf.tableView.reloadData()
        })
    }
```

これでRunして、一番下の子ノードであるorderデータを追加すると以下のようにusersノードのデータ全部のsnapshotが返ってくる。

```
snapshot: Snap (users) {
snapshot.child: Snap (zxzGLeLBJvguP7TDMMtc7zDfqdO2) {
userSnapshot.child:Snap (orders) {
ordersSnapshot.child:Snap (17065026d06aa5b3) {
ordersSnapshot.child:Snap (17067ac197c29929) {
ordersSnapshot.child:Snap (1706a288c50dd2d4) {
ordersSnapshot.child:Snap (17089ff731c2f382) {
ordersSnapshot.child:Snap (1709e0d81897c5bb) {
```

なので子供の子供の・・・と紐解いてやって出てきた注文データをappendすると、新規で追加されたデータ以外も全てordersに追加されてデータが重複するため、一旦は変更を検知したらプロパティのordersをremoveAll()し、そして新たに全注文データをセットしてreloadData()すると言うエンジニアが発狂しそうなやり方をとった（笑）。

これtableViewのリロード何回走るんやろう…。Firebase詳しいSwiftエンジニアさん誰か助けて。
あたまのなかの整理メモ(Java - 制御構文編)

## My Java環境

* java11

## for文

```java

for (初期化文, 条件文, 更新文) {
    // 繰り返し処理
}
```

* 初期化文は複数記載可能(カンマ`,`区切りで記載)だが、型が同じであること
* 条件文は複数記載可能(論理演算子`&&など`で記載)
* 更新文は複数記載可能(カンマ`,`区切りで記載)、メソッド呼び出しでもOK
* それぞれは省略可能

## do-while文

* `while(制御文);`は、最後セミコロン(`;`)で終わること。

```java

do {
    ... // 繰り返し処理
} while(制御文);
```

## 中括弧(`{}`)の省略

`while`文の場合は1つの文だけが、繰り返し対象になる。
(`if`文も同じ感じ。)
(IDE使って下記処理を書くと、インデントずらしてくれるから間違えなそう。)
(1行ではない、1文。`;`まで。)

```java

int param = 0;
while (param < 3)
    System.out.println("param:" + param);
    param++;
```

は、実行結果

```
param:0
param:0
param:0
・・・
```

無限ループになる。

↓は、コンパイルエラー。

```java

do
    System.out.println("param:" + param);
    param++;
while(param < 3);
```
amplify cliはnode.js version 10以上が必要

# 現象

amplify cliをインストール(`npm install -g @aws-amplify/cli
`)して、いざ`amplify`を使おうとしたら


```bash
amplify configure
/home/****/.nvm/versions/node/v8.16.2/lib/node_modules/@aws-amplify/cli/lib/plugin-manager.js:47
    catch {
          ^

SyntaxError: Unexpected token {
    at Generator.next (<anonymous>)
    at Object.Module._extensions..js (module.js:664:10)

```

とエラーメッセージが出て利用できなかった。
`amplify init`など他のすべてのコマンドで失敗した。

## 解決策

単純な話で、[AWS amplify cliのgithub](https://github.com/aws-amplify/amplify-cli)に書いてあるようにnode.jsのバージョンが10以上でないと`amplify cli`は使えない。エラーメッセージを見ると利用しているバージョンは`v8.16.2`だとわかる。`10`以上にアップデートしたら使えた。

## 教訓

対応バージョンやインストール時のエラーメッセージはしっかり読まないといけない。
[Python3 / mplfinance] mpl-financeからmplfinanceへの移行（新機能は一切使わないver）

# 概要

タイトルを見て「え？何言ってんの？」と思った方も多いと思います。
「たいぽ？」って言われてもおかしくないようなタイトルです。

ですが、[matplotlib/mpl-finance](https://github.com/matplotlib/mpl-finance)は **DEPRECATED** とされ、[matplotlib/mplfinance](https://github.com/matplotlib/mplfinance)へと移行されました。
ハイフンが消えましたｗ（わかりにくい>д<）

というわけで、とりあえず昔のmpl-financeをやめて新しいmplfinanceに切り替えて、なおかつ昔の処理をそのまま生かす方法を書いてみます。

ちなみに、Githubには**New mplfinance package (to replace mpl-finance by mid 2020).** と書かれていたので、そのうちmpl-financeはなくなるんだと思います>_<;

# 実施内容

## 1. pip install

Githubにも書いてある通り。

```bash
$ pip install --upgrade mplfinance
```

## 2. import文の書き換え

```python
# もともとのimport文
import mpl_finance as mpf

# 新しいimport文
import mplfinance.original_flavor as mpf

# as 以降が異なる方は合わせてください
# 旧 mpl_finance と mplfinance.original_flavor は同一の存在だと思って大丈夫です
```

# 3. requirements.txt の書き換え

```
# 元々
mpl_finance

# 書き換え後
mplfinance
```

とりあえずこれで動く

# x. mpl-finance 削除

新しいmplfinanceで動作確認ができたら、要らないものはお掃除

**他のアプリとかで使ってたら消しちゃダメですけどね** ><;

```bash
$ pip uninstall mpl_finance
```

# 補足

このimport文にくっついてる`original_flavor`というのは、昔の機能を呼び出すために付けなければならないものになります。

それとは別に、新mplfinanceでは、[いろいろなこと](https://github.com/matplotlib/mplfinance#newapi)が新しくできるようになっているっぽいので、その辺のことも書いていこうかな...

新機能はまだ試していないので、今回はここまで(`・ω・´)
HelloWorldを書こう

この記事を見てくれてるってことはどこかで見つけてきたか前の記事を見てくれたんだよね？
じゃ、本題行きますか。
今回はMinecraftの中で「/hello」って打つと「HelloWorld!」って出てくるようになるコードを書いていこう。
じゃまずIntelliJ IDEAを立ち上げよう。

##プロジェクトを立ち上げる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545700/cf4a986b-acc0-d139-dfc9-553d040729a6.png)
まずSpigotにチェックをつけよう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545700/c1332075-c1ce-7f1d-b218-dc26c3df47e5.png)
ここではよくわからない人はこんな感じに設定していいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545700/e6cab1c5-4695-9626-2fb8-9183b258cdc2.png)
ここでプロジェクト名を決めましょう。
よくわからない人はこんな感じで書いてください。
```HelloWorld-spigot```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545700/e7389c3b-992c-ae6b-f149-b541544bd34a.png)
ビルドされるまで待ちましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545700/9cf12865-67ea-8322-1574-99eb2eed3881.png)

##コードを書こう
ビルドされたら、、、
まず左にあるファイルを開くところからplugin.ymlを開いてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545700/b8c9cf73-17b1-4100-81cc-bfee93c41324.png)
このように書いてください。
慣れるまではコピペでいいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545700/85e3f58e-579b-11a3-b45a-dc3cdc4a6bcc.png)
そしたら次にHelloWorld.javaを開きましょう。
そしてこのように書いてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545700/d1908968-781d-8760-2819-1c18f394487e.png)
書けたらここを押してください。「構成の追加」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545700/f75018c7-f5e6-eb40-56b2-310caf68c536.png)
Mavenを開いて「HelloWorld-spigot build」というのを選んでください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545700/7fd3477e-04ce-98c5-a1bd-b5a9c8cf517e.png)
そして選択したらOK
このようになったと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545700/4dcbf057-f893-eb23-c069-0f0a35148fcc.png)
そしたら１つ右にある再生ボタンを押してRunさせてください。
こうなって
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545700/9548f72d-33c3-e7a7-c40a-864beaabf21c.png)
このように「BUILD SUCCESS」ってなったら完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545700/e4861b21-5b5a-f60a-001f-2598c71d96e0.png)
じゃtargetを開いてHelloWorld-1.0-SNAPSHOT.jarをサーバーのpluginsのファイルに入れてサーバー内で「/hello」って打ってみましょう。
HelloWorld!って表示されたら完成です！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545700/96fd1009-01c2-c556-f63c-1e083bdb646f.png)
今回はここまで！
ぜひいいねとフォローよろしくお願いします。
じゃまた会いましょう！
BYE~
cargo publish する前に埋めておきたい Cargo.toml の項目に関するメモ

正直試行錯誤しないと <https://crates.io> 挙動が良くわからんかったのでメモを書いておく。

`name`, `version`, `authors`, `edition` の4つは `cargo new` の際にでデフォルトで書かれる。

```toml
[package]
name = "hoge"
version = "0.1.0"
authors = ["Hideyuki Tanaka <tanaka.hideyuki@gmail.com>"]
edition = "2018"
```

`license` か `license-file` の項目は必須。所定のコードを入れるか、`license-file` にライセンスファイルのファイル名を入れる。

ライセンスのコードは <https://spdx.org/licenses/> の `Identifier` の項目を入れれば多分良いはず。

```toml
license = "MIT"
# または
license-file = "LICENSE"
```

`description` と (`repository` または `homepage`) も（多分）必須。
`repository` と `homepage` はあれば <http://crates.io> のパッケージのページにリンクが張られる。
最初は `repository` だけで、万が一パッケージが成長して公式ページができたら `homepage` に書けば良いのでは。

```toml
description = "Hoge library"
repository = "https://github.com/tanakh/hogehoge"
homepage = "..."
```

`documentation` のURLもパッケージのページからリンクが張られるが、この項目がない場合、自動生成された <https://docs.rs> のドキュメントへのリンクが自動的にパッケージのリンクに貼られるので、よほどこだわりがないかドキュメントの自動ビルドに失敗するような場合以外は空にしておいた方が良いのでは。

```toml
documentation = "..."
```

`readme` にパッケージ内へのファイル名を指定しておけば、それをパッケージのページの "About This Package" みたいなところにレンダリングしてくれる(とりあえずMarkdownはしてくれた)。正直これがあるとないとでは見栄えが全然違うのでこれは指定しておいた方が良いと思う。

```toml
readme = "README.md"
```

ところで、`README.md` を書くのは面倒、というか、crateのドキュメントと同じ事を書きたいことが多いはず。そして、同じテキストを複数のファイルに書くのはドキュメントの同期を取るのが面倒すぎる。

こういう意識は世の中にも当然あるみたいで、[cargo-readme](https://github.com/livioribeiro/cargo-readme)というcrateのドキュメントからREADME.mdを生成するツールがある。なので、`README.md` はこれを使って生成するのが良いだろう。

このツールは`Cargo.toml`の`[badges]`セクションを見て、`README.md`の先頭にバッジを置いてくれるので、ここも埋めておくのが良いだろう。詳しい書き方は<https://doc.rust-lang.org/cargo/reference/manifest.html#the-badges-section>この辺にある。

```toml
[badges]
github = { repository = "tanakh/hogehoge", workflow = "Rust" }
```

`categories` と `keywords` は埋めておくとページにそれぞれカテゴリーとキーワードへのリンクを付けてくれる。
パッケージを見つけてもらいやすくなるんだと思う。

`categories` の方は <https://crates.io/category_slugs> の中から選択で、`keywords` は好きな単語を書けば良いんじゃないかと思う(<https://crates.io/keywords> の人気の高いのを書くと見つけられやすくなるのかも知れない)。


```toml
categories = ["algorithms"]
keywords = ["graph"]
```

# まとめ

`cargo publish` するときに設定しておいた方が良い項目のまとめ：

```toml
[package]
# `cargo new` が自動生成するやつ
name = "..."
version = "..."
authors = ["..."]
edition = "2018"

# `cargo publish` するときに最初から埋めて置いた方が良い項目
description = "..."
repository = "<url-to-repository>"
license = "MIT" # <https://spdx.org/licenses/> から選択
readme = "README.md" # `cargo-readme` で生成するのが便利

# お好みで
categories = ["..."] # <https://crates.io/category_slugs> から選択
keywords = ["..."] # 好きに書けるけど <https://crates.io/keywords> から選ぶとよさそう

# あれば
homepage = "<url-to-homepage>"

# デフォルトで docs.rs へのリンクが作られるからあまり要らないのでは
documentation = "<url-to-documentation>"

# バッジを埋めておくと `cargo-readme` がバッジを埋めてくれる
[badges]
github = { repository = "tanakh/hogehoge", workflow = "Rust" }
```
MySQLのルートパスを忘れてしまったときの対処法


#目的
MySQLのルートパスを忘れてしまい、認証できなくなったときの対処方法をまとめておく。(よく忘れるので)

#概要
①起動しているMySQLを止める
②セーフモードでMySQLを起動
③パスワードを再設定する
④セーフモードのMySQLを止める
⑤通常のMySQLを起動する

#手順１ 起動しているMySQLを止める

(すでに停止している場合は不要です。)

```terminal
sudo service mysqld stop
```

#手順２　セーフモードでMySQLを起動

```terminal
#セーフモードで起動
mysqld_safe --skip-grant-tables &　
#セーフモードのMySQLにrootユーザーでログイン
sudo mysql -u root
```

#手順3 パスワードを再設定する

```terminal
#パスワード更新のクエリを実行
use mysql;
update user set password=PASSWORD("新しいパスワード") where User='root';
flush privileges;
#ログアウトする
quit
```

#手順4 セーフモードのMySQLを止める

```terminal
sudo service mysqld stop
```

#手順5 通常のMySQLを起動する

```terminal
sudo service mysqld start
```


以上でパスワードの再設定は完了です！
最後まで読んでいただきありがとうございました！
EmacsユーザーがSublimeTextでpythonのコードを書く時に知っておいた方が良いこと

# emacsユーザーがSublimeTextを使う時に知っておくとよいこと

emacsを日頃使ってるけど、pythonはSublimeTextで書く、というくらいのユーザーの場合、知らないと損していることあるので、簡単にまとめておきます。(macユーザーなのでwindowsは検証できてませんが、同機能はあるはずです。)

## (1) 選択した任意の場所に文字列を追加する方法

コマンド + 左クリック、で任意の場所を選択できて、そこに文字の追加や編集が可能です。
これは emacs でどうやるのか知らない。とっても便利！

例えば、文字列を書いた後に、全部に改行を追加したかって、て思った時も、⌘+左クリックで、入れたい場所を選択して、文字を入力できる。

<img width="267" alt="sublime_command.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179652/118c3de6-bef7-ca19-48e9-003068623bc4.png">

## (2) SublimeTextでも長方形選択できます！

長方形(短形)選択できるのは、emacs だけの特典ではないのです。
「Opt を押しながら、左クリックしドラッグ」
とすると、長方形の領域で選択できます。Optを**押しながらドラッグ**、というのがポイントです。もちろん、これの後に del をすると削除できますし、文字列を入れると置換できます。

- 参考ページ : https://qiita.com/seafield1979/items/56d4833dae818dcf85ae

## (3) SublimeTextを使ってるとインデントで怒られるのはなぜ？？

これは、sublimeTextに限らない問題であるが、「ソフトタブとハードタブの混在」が原因である。なぜsublimeTextだと問題になるかというと、デフォルトではスペース4つでタブであるため、見た目はインデントが揃っているように見えてしまう。
例えばよくありがちなパターン。emacsで見ると明らかにずれているのがわかるが、sublimeTextだと一見揃ってる様に見える(こうなるかは設定に依存します)。

![indent.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179652/c7ac9abb-b9f8-7fa2-acd6-4573922b6e04.png)

解決方法は簡単で、**「全選択をしてドット(....)とダッシュ(----)の混在を確認」** で一発でわかります。

- 参考 : https://www.sejuku.net/blog/86942

## (4) 置換方法のショートカット

emacsユーザーにはなかなか覚えられないかもしれないが、、「Cmd + Opt + F」で置換できます。設定をemacs風に変える方法はあります。

- 参考 : https://qiita.com/fujimohige/items/feb915c55a034029e513

## (5) タブとスペースが混在するエラーを防止するための設定

最近は、ChatGPTなど生成系はタブではなく、スペース４個を用いてるので、sublimetext の設定もタブを使った時にスペースが４つに設定しておくと便利です。

### タブを強制的にスペース４つ分にする。

基本設定から、

``` python:
    // The number of spaces a tab is considered equal to
    "tab_size": 4,

    // Set to true to insert spaces when tab is pressed
    "translate_tabs_to_spaces": true,
```

と設定すると、tab が 4つのスペースで、タブを強制的にスペース４つ分にしてくれます。

![スクリーンショット 2024-06-22 19.06.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179652/abf840b5-74eb-2378-7f97-ef90635e7ff4.png)


### 点々を常に表示する

`draw_white_space` を `all` に変更すると常に点々が表示されて、タブと点々が混在していたとしてもすぐに気がつけて便利です。

``` python:
    // Set to "none" to turn off drawing white space, "selection" to draw only the
    // white space within the selection, and "all" to draw all white space
//    "draw_white_space": "selection",
    "draw_white_space": "all",
```

![スクリーンショット 2024-06-22 19.10.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179652/32d742df-b966-cf59-ba47-91336db9a44f.png)

この設定をしておくと、

![スクリーンショット 2024-06-22 19.06.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179652/ebd68194-8347-1254-fb3c-ac13cc2e641b.png)

のように、点々が常に見えてるようになります。