OmniAICreator/Qiita-1.07M huggingface dataset:
jQueryでトグルメニューを作る

#■HTMLの用意

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>jQuery</title>
  <link rel="stylesheet" href="css/style.css">
  <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
</head>
<body>
  <header>
    <h1>Toggle Menu</h1>
  </header>
  <nav>
    <button><i class="fa fa-bars fa-2x"></i></button>
    <ul>
      <li><a href="#">Menu1</a></li>
      <li><a href="#">Menu2</a></li>
      <li><a href="#">Menu3</a></li>
      <li><a href="#">Menu4</a></li>
    </ul>
  </nav>
  <script
  src="https://code.jquery.com/jquery-3.5.1.js"
  integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc="
  crossorigin="anonymous"></script>
  <script src="js/script.js"></script>
</body>
</html>
```

#■CSSの用意

```css:style.css
header {
  background-color: pink;
}

h1 {
  margin: 0;
}

button {
  position: absolute;
  top: 8px;
  right: 8px;
  background-color: yellow;
  border: none;
  cursor: pointer;
  padding: 0;
  height: 48px;
  width: 40px;
  outline: none;
}

ul {
  display: none; /* 初期状態で非表示とする */
  list-style: none;
  padding: 0;
  margin: 0;
}

li {
  background-color: skyblue;
  font-size: 18px;
  line-height: 35px;
}

a {
  text-decoration: none;
  display: inline-block;
  width: 100%;
}
```

#■jQueryの用意

```js:script.js
$(document).ready(() => {
  $("button").click(() => {
    $("ul").slideToggle(400); // クリック時にslideToggle()を実行する
  });
});
```

#■プレビュー
<p class="codepen" data-height="365" data-theme-id="light" data-default-tab="html,result" data-user="dev-nakasho" data-slug-hash="QWGqLvo" style="height: 365px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="QWGqLvo">
  <span>See the Pen <a href="https://codepen.io/dev-nakasho/pen/QWGqLvo">
  QWGqLvo</a> by dev-nakasho (<a href="https://codepen.io/dev-nakasho">@dev-nakasho</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

#※2021/02/21　補足
初期状態でDOM要素を非表示にするために、ul要素に対してdisplay: none;としていますが、
jQueryで$("ul").hide();としても非表示にできます。
その場合も、slideToggle()メソッドで制御できる点は同じです。

以上です。
【Node.js】WindowsでNode.jsの環境構築をする

#プログラミング勉強日記
2021年2月21日
友人にNode.jsの環境構築を教えるために一度調べたので、そのやり方をまとめる。

#Node.jsをインストールする
　[Node.jsの公式サイト](https://nodejs.org/ja/)からNode.jsのインストーラーをダウンロードする。(今回は推奨版をダウンロードした。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/6d5719ab-a923-0b88-dbc5-8af1593facb7.png)

　インストーラーをダウンロードしたら、開いて実行する。その後指示にしたがtt進めていく。基本的にはそのまま`Next`をクリックして進めていく。最後に`Finish`を押して終了する。

#Node.jsのバージョンを確認する
　それぞれコマンドで下記を実行すると、バージョンを確認することができる。バージョンが表示されない場合は、インストールができていない。

```
$ node ^v
$ npm -v
```

```:バージョンが表示されている場合
C:\>node -v
v12.18.4

C:\>npm -v
6.14.6
```
忙しい人のためのDocker入門

とりあえずDockerって何？と思った人のためのまとめ

# Dockerとは
## 一言でまとめると
ざっくりというと「仮想環境構築のためのツール」。

## Dockerのメリット
１、要するに開発環境の構築&破棄が簡単になる。
２、環境による違いをなくせる。
３、クラスタ構成を作るのも楽。

こちらが詳しかった（https://knowledge.sakura.ad.jp/13265/

> コード化されたファイルを共有することで、どこでも誰でも同じ環境が作れる。
作成した環境を配布しやすい。
スクラップ＆ビルドが容易にできる。
例えば、開発環境(Windows上)では動いていたけどLinuxで動かなかった、といったケースも、開発工程からDockerを活用していくことで防ぎやすくなります。そして、開発工程の中で使っていた環境をそのまま本番環境に持っていくことも可能なため、環境差分が少なく、環境による問題を減らすことができます。作成したDockerイメージを他の人にも渡して使ってもらうことで、各自の環境のバージョンずれ防止や、開発環境準備の短縮化にもつながります。開発環境の準備で、説明不足や手順ミスで、丸一日かかったとなってしまうのはもったいないですよね。私自身も、開発環境からDockerを使っていて、新規メンバ参画時のコスト削減や、環境依存問題を減らせて、役立っています。また、クラスタ構成を構築する場合も、Dockerイメージがあれば、それを起動する名前（コンテナ名）などを変えるだけで、
複数の環境（コンテナ）を起動できるので、一から手順に沿って環境を作る作業もなくなり、クラスタ構成を構築するのも容易になります。これは、コンテナを管理するオーケストレーションツールを使うことで、より運用が楽になります。

## Dockerを導入する基準は？　Dockerのデメリットは？
こちらが詳しい。https://qiita.com/taishin/items/e1e7153cecb3ffd44a54
要するにインフラや開発サイクルや運用のことまで考えて導入すべきと思われる。
大規模チームで常にリリースする事業会社なら必須だろうが、少人数で小規模な受託開発するならメリットは無さそう。
（ちなみに前々職では意味なかった

## Dockerで環境を作る流れ
1,Dockerレジストリ(DockerHub）からDockerイメージ（環境に必要なソフトウェアのことPHP,Apache、MySQLなど）を取得。
2,DockerイメージをDockerコンテナ（仮想環境のこと）として動かす。


## DockerでPHPを環境を動かす
こちらが詳しい。https://qiita.com/nemui_/items/f911be7ffa4f29293fd5

## DockerでLaravelの開発環境を作る
Laravelの場合はLaradockを使用するらしい。
https://qiita.com/J_Shell/items/695a30fd38444d065ae5

## Dockerのトラブルシューティング
コンテナ間での通信やイメージに関するトラブルが多い模様。

https://qiita.com/ft0220/items/2522e2d056eb2b289dc1

https://qiita.com/hatai/items/6375c930488f34d15776
弱衝突耐性・強衝突耐性

#違いがよくわからないぞ
色々しらべて、よりイメージしやすく分かりやすい説明を考えました。
wikiに載っている説明をどう解釈するのか

_`以下wiki引用`_
_`弱衝突耐性(第二現像計算困難性)：`_
_`入力m1が与えられたとき、hash(m1)=hash(m2)となるような別の入力m2を求めることが困難でなくてはならない`_
_`強衝突耐性：`_
_`hash(m1)=hash(m2)となる2つの異なるメッセージm1とm2を探し出すことが困難でなくてはならない`_

自分はこの説明で何となくしかわかりませんでしたが、理解が進み、こんな解釈をしました。
・弱衝突耐性
要は1つのハッシュ値が固定で、それと一致するハッシュ値を持つメッセージm2を見つけ出せるか
・強衝突耐性
とりあえず一致するハッシュ値はなんでもよいけど、同じハッシュ値をもつメッセージのペアm1,m2を見つけ出せるか

一致させる必要のあるハッシュ値が特定のハッシュ値なのか
ハッシュ値自体は何でもよいけど、とにかく2つのハッシュ値を一致させる必要があるのか
つまり、__1つの固定ハッシュに注目するか、2つの不定ハッシュに注目するのか、__が違いになると思います。

#理想的なハッシュ関数
理想的なハッシュ関数はこの2つの性質を備えている必要があります。
__「弱衝突耐性」__というのは一致するハッシュ値にあたる(=衝突)事象の起こり難さ(=耐性)として楽な条件(=弱)ということだそうです。(←修正：コメントありがとうございます。) したがって弱衝突耐性の方が__一致するハッシュ値に当たりづらい=破るのはより困難__ということになります。強衝突耐性に関しても同様に考えられます。「弱」という漢字が使われており、誤解しやすいかもしれないですが、何に対して弱いのかきちんと理解しておくことが大切ですね。

特定のハッシュ値に一致するペアを探す(弱衝突耐性)よりも、あるハッシュ値に一致するペアを探す(強衝突耐性)方が簡単であることの具体例として以下を考えました。
ex. 2セット(A,B)のトランプ104枚から赤のダイヤのクイーンに一致するペアを探す(→ペアとしては1枚しか見つからない)よりは、数字絵柄は何でもよいけどよりあえず一致するペアを探してくれと言われた方がすぐ見つかります(→ペアとしては1～Kの13ペア見つかる)。そういうことです。

いままでの説明で弱衝突耐性と強衝突耐性が理解できていれば、弱衝突耐性は強衝突耐性を包含していることに気づくはずです。したがって、__もし弱衝突耐性が破られたとしたら、その時点ですでに強衝突耐性は破られたとみなせる__ことも納得できます。

#誕生日のパラドックス
「何人集まれば、その中に同じ誕生日の人が2人以上いる確率が50%を超えるか？」という問題

答えとしては23人で50%を超えます。
366人集まれば、確実に1人は被るので100%になることはわかりますが、その半数以下でも99.9%以上の割合で同じ誕生日の人が現れます。感覚的に「・・・あれ？」となる人が多いのでイメージとの乖離でパラドックスと呼ばれています。(論理的には全然パラドックスじゃありません。)
実際に考える際は、自分以外のうちの人同士で誕生日が一致する可能性を考慮する必要があり、余事象で求めます。感覚的にはそのグループの中に自分と同じ誕生日の人がいる確率だけ計算すればよい、と考える人が多いのでよく取り上げられる題材です。
[計算式]
P(n) = 1-(364/365)^n
n=253のときにはじめて0.5 <= Pとなります。
SELECT文の結果をDataFrameで受け取る

#困ったこと

psycopg2を使用してPostgreSQLからデータを取得すると、
SQLのデータ型がnumeric,decimal,dateの場合は、object型になってしまうため、
何らかの方法でデータを変換する必要がある。

#データを取得してから変換

pandas.astypeを使用して適切な型にキャストする。

```python
with conn.cursor() as cursor:
    cursor.execute(select_sql)
    column_list = [d.name for d in cursor.description]
    df = pd.DataFrame(cursor.fetchall(), columns=column_list)
    dtype_dict = {}
    for d in cursor.description:
        if d.type_code==1700: dtype_dict[d.name] = 'float64'
        if d.type_code==1082: dtype_dict[d.name] = 'datetime64'
    if len(dtype_dict)> 0: df = df.astype(dtype_dict)
```

SQLのデータ型とpandasのデータ型の対応関係は以下の通り。

|var|sql type|type_code|pd.dtype|astype|
|:---|:---|---:|:---|:---|
|x1 | smallint | 21 | int64||
|x2 | integer | 23 | int64||
|x3 | bigint | 20 | int64||
|x4 | decimal | 1700 | object|float64|
|x5 | numeric | 1700 | object|float64|
|x6 | real | 700 | float64||
|x7 | double precision | 701 | float64||
|x8 | timestamp | 1114 | datetime64[ns]||
|x9 | date | 1082 | object|datetime64|

#データ取得時に変換

PostgreSQLからデータを取得する際に適用する変換関数を登録する方法もある。

```python
from dateutil.parser import parse

def register_typecasters(conn):
    def cast_date(value, cursor):
        return parse(value)

    def cast_numeric(value, cursor):
        return float(value)

    cursor = conn.cursor()
    cursor.execute("SELECT NULL::date")
    date_oid = cursor.description[0][1]
    cursor.execute("SELECT NULL::timestamp")
    timestamp_oid = cursor.description[0][1]
    cursor.execute("SELECT NULL::timestamp with time zone")
    timestamptz_oid = cursor.description[0][1]
    oids = (date_oid, timestamp_oid, timestamptz_oid)
    new_type = psycopg2.extensions.new_type(oids, "DATE", cast_date)
    psycopg2.extensions.register_type(new_type)

    cursor.execute("SELECT NULL::numeric")
    numeric_oid = cursor.description[0][1]
    cursor.execute("SELECT NULL::decimal")
    decimal_oid = cursor.description[0][1]
    oids = (numeric_oid, decimal_oid)
    new_type = psycopg2.extensions.new_type(oids, "NUMERIC", cast_numeric)
    psycopg2.extensions.register_type(new_type)
```

#参考資料

8.1. 数値データ型
https://www.postgresql.jp/document/12/html/datatype-numeric.html
8.5. 日付/時刻データ型
https://www.postgresql.jp/document/12/html/datatype-datetime.html

Python psycopg2.extensions.register_type() Examples
https://www.programcreek.com/python/example/79078/psycopg2.extensions.register_type
Mysql2::Error::ConnectionErrorについて

現在プログラミングスクールにてフリマアプリを作成しております。
モデル単体テストコードを実施した際に遭遇した下記エラー。苦戦したので備忘録として。

「Mysql2::Error::ConnectionError: Lost connection to MySQL server during query」


![63e0767931af109eefa7956d9696b158.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1133522/208d3ac6-4b83-2014-7627-c44076116e6c.png)


上図のように、テストの途中でエラーが発生してるんですね.
でもこれ、コード的には特に問題ないと思うのです。それゆえに悩みました。
また、何度かテストを実施すると、図よりテスト成功ログが増えたりもしまして、これはおかしいと思いました。

エラー内容的には「Mysqlへ繋がらなかったよ。繋ぐまで時間がかかりすぎてタイムアウトしちゃったよ」
という意味合いのようですね。他の方の記事をみてみたところ、「Mysqlの処理量がテスト途中でいっぱいいっぱいになってしまって、時間までに処理できませんでした」ということのようですね

今回行っているモデルの単体テストコードですが、単体ではあるのですが、そのテストには複数モデルが必要だったのです。下記のように、item_orderだけではなく、それに付随するitem_id、user_idも必要なため、それぞれFactoryBotを追加しました。（これを追加するまではテスト通ってたのです）

```ruby:qiita.rb
require 'rails_helper'

describe ItemOrder do
  before do
    user = FactoryBot.create(:user)
    item = FactoryBot.create(:item)
    @item_order = FactoryBot.build(:item_order, item_id: item.id, user_id: user.id)
  end

  describe '商品購入手続き' do
    context '商品購入が成功する時' do
      it '全ての項目が入力されていれば登録できる' do
        expect(@item_order).to be_valid
      end
```
つまり、明らかにこれが原因です。itemとuserから引っ張ってくるデータ量が多すぎたと思われます。
テスト途中にbinding.pryを差し込みまくればテストが通った、という記事も拝見しましたが、私はそれでもテスト成功しませんでした。

そこで登場するのが、sleepメソッドです。
sleepメソッドは、処理速度を指定時間に合わせて行ってくれます。
今回は元々の指定時間に合わせて行ったところ、それに間に合わず、途中で失敗してしまっている、と考えられます。
そこで下図のようにsleepメソッドを挿入してみました。「一つの処理に１秒かける」、という設定ですね。

```ruby:sleep.rb
describe ItemOrder do
  before do
    user = FactoryBot.create(:user)。
    item = FactoryBot.create(:item)
    @item_order = FactoryBot.build(:item_order, item_id: item.id, user_id: user.id)
    sleep(1)
  end
```

すると・・・・
![b269dbf0d4d12c209d6d4f8f5b5a328a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1133522/0ad171e3-f749-512d-ac5a-3d72e303c61f.png)

成功しました！！！
今回の厄介な所は、コード自体に誤りはなかった、という所ですね。
コードに何か誤りがあるせいでエラーが発生してしまう、と考えていた私にとっては衝撃な点でした。
そもそもテスト中に処理落ちしないテストコードを書ければいい話なのかもしれませんが・・・・それは今後精進していきます！
改善点やダメ出しあれば是非お願いします！
VirtualBoxをコマンド操作する場合に使いそうなコマンド一覧

# はじめに
先日`VirtualBox`のコマンド操作する機会があったので、せっかくなので、使いそうなコマンドをまとめてみました。

# コマンドの場所
`VirtualBox`をコマンドで操作する場合は`VBoxManage`というコマンドで操作を行います。
Windowsの場合、以下にあるため、パスを切りましょう。

|パス|
|:--|
|C:\Program Files\Oracle\VirtualBox|

# 参照系コマンド一覧
|説明|コマンド|
|:--|:--|
|全ての仮想マシン一覧の表示|**VBoxManage list vms**|
|起動中の仮想マシン一覧の表示|**VBoxManage list runningvms**|
|仮想マシンの詳細表示|**VBoxManage showvminfo [UUID or VM名]**|
|仮想マシンのスナップショット一覧表示|**VBoxManage snapshot [UUID or VM名] list**|
|指定したスナップショットの仮想マシン詳細表示|**VBoxManage snapshot [UUID or VM名] showvminfo [スナップショット名]**|

# 操作系コマンド一覧
|説明|コマンド|
|:--|:--|
|仮想マシンの起動（GUIあり）|**VBoxManage startvm [UUID or VM名]**|
|仮想マシンの起動（ボタン表示なし）|**VBoxManage startvm [UUID or VM名] --type sdl**|
|仮想マシンの起動（GUIなし）|**VBoxManage startvm [UUID or VM名] --type headless**|
|仮想マシンの起動（GUIなし変更可）|**VBoxManage startvm [UUID or VM名] --type separate**|
|仮想マシンの電源オフ|**VBoxManage controlvm [UUID or VM名] poweroff**|
|仮想マシンのACPIシャットダウン|**VBoxManage controlvm [UUID or VM名] acpipowerbutton**|
|仮想マシンの再起動|**VBoxManage controlvm [UUID or VM名] reset**|
|仮想マシンのサスペンド|**VBoxManage controlvm [UUID or VM名] savestate**|
|仮想マシンの一時停止|**VBoxManage controlvm [UUID or VM名] pause**|
|仮想マシンの再開|**VBoxManage controlvm [UUID or VM名] resume**|
|スナップショットの作成|**VBoxManage snapshot [UUID or VM名] take [スナップショット名]**|
|指定したスナップショットの削除|**VBoxManage snapshot [UUID or VM名] delete [スナップショット名]**|
|指定したスナップショット名の修正|**VBoxManage snapshot [UUID or VM名] edit [スナップショット名] --name=[新しいスナップショット名]**|
|直前のスナップショットへのリストア|**VBoxManage snapshot [UUID or VM名] restorecurrent**|
|指定したスナップショットへのリストア|**VBoxManage snapshot [UUID or VM名] restore [スナップショット名]**|
|ホストからゲストOSの操作|**VBoxManage guestcontrol [UUID or VM名] run --exe "[コマンドフルパス]" --username [ゲストOSユーザ名] --password [ゲストOSパスワード]**|


※「仮想マシン起動（GUIあり）」は`--type gui`を指定した場合と同じ

## 仮想マシン起動オプションの違い
オプション無し、または`--type gui`の場合、GUIコンソール画面がある通常起動を行います。

`--type headless`の場合、コンソール画面無しの状態で起動するので、GUIコンソール画面での操作を行わない仮想マシンを使う場合に便利です。

`--type separate`は起動後にGUIありかGUIなしかを変更できるタイプで、起動時はGUIコンソール画面がある状態で起動しますが、「仮想マシン」→「GUIをデタッチ」または「×」→「バックグラウンドで動作を継続」を選択することで、`--type headless`と同様の状態となります。

尚、「GUIをデタッチ」または「バックグラウンドで動作を継続」の選択肢はセパレートで起動しないと表示されません。

`--type sdl`はウィンドウに仮想マシンの操作メニューが表示されない起動タイプとなりますが、GUIコンソールが表示されるウィンドウ以外にプロンプトが立ち上がるのと、`Oracle`のマニュアルにも説明が無いことから、開発用なのかと思われます。

以下通常起動した際の「仮想マシンを閉じる」操作一覧。
![capture_21022021_123653.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/cfd25b54-0074-f3fd-1d1a-18498cc27c6d.jpeg)

起動タイプをセパレートで起動した際の「仮想マシンを閉じる」操作一覧。
![capture_21022021_123749.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/93b70a06-952e-c399-16a4-e27e6f410b4c.jpeg)

# ホストからゲストOSの操作について
使う機会は限られると思いますが、`VBoxManage guestcontrol`コマンドを使用することで、ホスト側からゲストOSのコマンドを実行することができます。

但し、コマンドのフルパスを記載する必要があったり、コマンドのオプション指定ができなかったりするようなので、使う場合は注意して下さい。
The password issue. "The password is dead"

The problem with password. I am working on a better password manager. 
https://www.youtube.com/watch?v=xHSnHj-zKF4.
The problem:
"simple passwords – short in length, that use words found in dictionaries, or do not mix in different character types (numbers, punctuation, upper/lower case), or are otherwise easily guessable
passwords others can find – on sticky notes on monitors, in a notepad by the computer, in a document on the computer, whiteboard reminders, smart device storage in clear text, etc.
the same password – using the same password for multiple sites, never changing account passwords, etc.
shared passwords – users telling others passwords, sending unencrypted emails with password information, contractors using same password for all their accounts, etc.
administrative account logins where limited logins would suffice, or
administrators who allow users with the same role to use the same password."
https://en.wikipedia.org/wiki/Password_manager.
"password managers have the disadvantage that any potential hacker or malware just need to know one password to gain access to all of a user's passwords and that such managers have standardized locations and ways of storing passwords which can be exploited by malware."
This is the other problem "Keystroke logging, often referred to as keylogging or keyboard capturing, is the action of recording (logging) the keys struck on a keyboard"
I am experimenting with math and pictures but I am getting stuck. It is to difficult for the average user or the LCD.
Morphism in Math is finding an association from "A" to get to "B". 
https://en.wikipedia.org/wiki/Morphism.
[AtCoder]AtCoder Beginner Contest 192 A~C問題

# A問題
問題文を読み替えると「Xより大きい最小の100の倍数からXを引いた値」を求めればよいことがわかります。
これを更に読み替えると「100から、Xを100で割った余りで引いた値」を求めればよいことがわかります。

```cpp
#include <bits/stdc++.h>
using namespace std;

int main()
{
    int x;
    cin >> x;

    cout << (100 - x % 100) << endl;

    return 0;
}

```
# B問題
文字の先頭から一文字ずつ条件を満たしているか調べていき、一文字でも条件を満たしていなければNo、
すべての文字が条件を満たしている場合のみYesとなります。

```cpp
#include <bits/stdc++.h>
using namespace std;

int main()
{
    string s;
    cin >> s;
    bool difficult = true;

    for(int i = 0; i < s.size(); i++){
        if(i%2==0){
            if(isupper(s[i])){
                difficult = false;
            }
        }else{
            if(islower(s[i])){
                difficult = false;
            }
        }
    }

    if(difficult){
        cout << "Yes" << endl;
    }
    else{
        cout << "No" << endl;
    }

    return 0;
}
```
# C問題
問題文に忠実にg1(),g2(),f()を実装します。
また、g1とg2に共通する「xを十進法で表したときの各桁の数字」という部分をさらに別関数に切り出すとスッキリします。

```cpp
#include <bits/stdc++.h>
using namespace std;

// 整数xの各桁をvectorの各要素に入れて返す
vector<int> to_vector(int x){
    vector<int> ret;

    while(x != 0){
        ret.emplace_back(x%10);
        x /= 10;
    }
    return ret;
}

int g1(int x){
    int ret = 0;
    vector<int> dec_x = to_vector(x);

    sort(dec_x.begin(), dec_x.end(), less<int>());
    for(int i = 0; i < dec_x.size(); i++){
        ret += dec_x[i] * pow(10, i);
    }
    return ret;
}

int g2(int x){
    int ret = 0;
    vector<int> dec_x = to_vector(x);

    sort(dec_x.begin(), dec_x.end(), greater<int>());
    for(int i = 0; i < dec_x.size(); i++){
        ret += dec_x[i] * pow(10, i);
    }
    return ret;
}

int f(int x){
    return g1(x) - g2(x);
}

int main()
{
    ll n,k;
    cin >> n >> k;
    vector<ll> a(k+1);
    a[0] = n;
    
    for(int i = 0; i < k; i++){
        a[i+1] = f(a[i]);
    }  

    cout << a[k] << endl;
    return 0;
}
```
webpack5でTypeScriptで型定義使用してconfigを記述しホットリロードを実現する

2021/03/13 修正
ソースマップを作成するための `devtool` が抜けていたのを追加

# サンプル

まずはサンプルを。

```typescript
import { WebpackOptionsNormalized } from "webpack";

const option: WebpackOptionsNormalized = {
    mode: "development",
    cache: {
        type: "filesystem",
        buildDependencies: {
            config: [__filename]
        }
    },
    devServer: {
        contentBase: "dist",
        open: true
    },
    devtool: 'eval-source-map',
    entry: {
        main: {
            import: ["./src/index.tsx"]
        }
    },
    experiments: {

    },
    externals: {

    },
    externalsPresets: {

    },
    infrastructureLogging: {

    },
    module: {
        defaultRules: [
            "..."
        ],
        generator: {

        },
        parser: {

        },
        rules: [
            {
                test: /\.tsx?$/,
                use: "ts-loader"
            }
        ]
    },
    node: {

    },
    optimization: {

    },
    output: {
        filename: "[name].js",
        path: `${__dirname}/dist`,
    },
    plugins: [],
    resolve: {
        extensions: [".ts", ".tsx", ".js", ".jsx"]
    },
    resolveLoader: {

    },
    snapshot: {

    },
    stats: {

    },
    watchOptions: {

    }
}
};

export default option;
```

# Configuration ではなく WebpackOptionsNormalized を使う

webpack configをTypeScriptで記述する記事を見ると、 `webpack.Configuration` を使用している場合が多いです。
しかし `webpack.Configuration` にはホットリロードに必要な `devServer` が定義されていません。
手っ取り早いのは `webpack.Configuration` を使用せず型なしのオブジェクトとして記述することですが、それではTypeScriptを使う意味がありません。
そこで `devServer` が定義されている `webpack.WebpackOptionsNormalized` を使用します。

# WebpackOptionsNormalized は定義が多い

`webpack.WebpackOptionsNormalized` は `webpack.Configuration` と比較すると定義する必要がある項目が多いです。
しかしそのほとんどは空で構いません。

# entryの書き方が違う

`entry` には `filename` を記述することが多いかと思います。
しかし　`webpack.WebpackOptionsNormalized` の `entry` には `import` を記述することが必須となります。
そのため `filename` ではなく `import` を記述することになります。
形態素解析を試せるページ (NLP4J)

[NLP4J Index](https://qiita.com/oyahiroki/items/ba79a759c599d3459d29) 

#形態素解析

日本語のテキスト分析において最も重要な技術のひとつが形態素解析です。

しかし「形態素解析を試してみよう」と思ったときにはJavaやPythonの実行環境が必要になる場合が多く、手軽に試せるものではありません。またWebで公開されていてもメンテナンスがされていなかったりHTTPSに対応していないなど作りの古さが見受けられるものもあります。

そこでNLP4Jを使って形態素解析を試せるページを作成しました。

https://nlp4j.azurewebsites.net/nlp.jsp

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110265/a26e0959-a1a0-155d-51ab-8e12d528be32.png)

#使い方

使い方は簡単で、テキストボックスに自然文を入力して「NLP」のボタンを押すと、形態素解析の結果が得られます。

#特徴

Webで手軽に形態素解析を試せます。
スマホでも利用可能です。

##制限

現在の仕様ではリクエストが１日1000回を超えるとエラーが返るようになっています。ご容赦ください。

##裏技

WEB技術に詳しい人だと「このページで呼び出せるURLを使えばCurlでも形態素解析できるのでは」と思われるかと思います。実際に使えますのでそういうのが好きな人はお試しください。


# まとめ
NLP4J を使うと、Javaで簡単に自然言語処理ができます

#プロジェクトURL
https://www.nlp4j.org/
<img width="64" alt="NLP4J_N_128.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110265/4f59b21b-4b43-187d-0aac-7b99c0fd4bac.png">



---
[NLP4J Index](https://qiita.com/oyahiroki/items/ba79a759c599d3459d29)
【ExcelVBA】GoogleChromeを起動する方法

##はじめに

ExcelVBAでChromeを自動起動するためには、単にスクリプトを書くだけではなく、事前準備が複数必要だと分かった。
備忘録メモしておく。

##大まかな流れ
<事前準備>
１：Selenium Basicのインストール
２：Selenium Basic内のchromedriverの最新化
３：.NET Frameworkのインストール
４：ExcelVBE内の参照設定
<スクリプトを記載>
５：「GoogleChromeを起動する」内容をVBE内に書く

##１：Selenium Basicのインストール
VBAでChromeを操作するためにSelenium Basicをインストールする必要あり

①インストールしていく。まずは下記URLにアクセス
http://florentbr.github.io/SeleniumBasic/

②Release pageをクリック

③SeleniumBasic-2.0.9.0.exe（※2021年2月時点のバージョン）を押下し、ダウンロード

④ダウンロードしたファイルを起動し、インストール
インストーラ画面は基本的にデフォルトの設定で問題なし

⑤下記にインストールされていることを確認
C:\Users\ユーザー\AppData\Local\SeleniumBasic

※もしくは以下をエクスプローラへコピペ
%LOCALAPPDATA%\SeleniumBasic

##２：Selenium Basic内のchromedriverの最新化
上述で確認したフォルダに配置されている「chromedriver.exe」は最新ではなく、
最新版に置き換える必要あり

①：置き換えていく。まずは下記URLにアクセス
https://sites.google.com/a/chromium.org/chromedriver/

②：下記のように記載されている太字箇所をクリック
Latest stable release: **ChromeDriver 88.0.4324.96**（※2021年2月時点のバージョン）

③適切なファイルをダウンロード
Windowsなら「chromedriver_win32.zip」をダウンロード

④：ダウンロードしたZIPファイルの中身「chromedriver.exe」を下記フォルダに配置し、古い「chromedriver.exe」と置き換え
C:\Users\ユーザー\AppData\Local\SeleniumBasic

※もしくは以下をエクスプローラへコピペ
%LOCALAPPDATA%\SeleniumBasic


##３：.NET Frameworkのインストール
適切な.NETをインストールしておかないと、VBAは正常に動作しない。

①：下記スクリプトをダブルクリックし、.NET Frameworkインストール
C:\Users\ユーザー\AppData\Local\SeleniumBasic\Scripts
StartChrome.vbs
※5分ほどかかる

##４：ExcelVBE内の参照設定
ExcelVBE内の設定を行わないと、インストールしたSelenium設定が読み込まれないので、参照設定を行う。

①：Excelを起動し、VBE（【開発】タブ→Visual Basic）を開く

②：VBE内の【ツール】タブ→参照設定を押下

③：Selenium Type Libraryにチェックし、OKを押下


##５：「GoogleChromeを起動する」内容をVBE内に書く
Yahooサイトへアクセスするコードを記載する

①：以下をコピペし、実行

```
Sub Yahoo_show()
    Dim Driver As New Selenium.WebDriver
    Driver.Start "chrome" '←.NET Frameworkをインストールしていないとここでエラー
    Driver.Get "https://www.yahoo.co.jp/"
    Stop '←コレを記載していないと、実行時、自動で開いたブラウザが自動で閉じられる
End Sub

```
Google ChatでBotを作成してみる

#ゴール
初心者が家でも環境を整えることを目標にします。
メッセージを送るとオウム返しするBotを作成してみます。

# 手順

##1.Google workspace への加入
Google Chatを利用するには上記プランへ加入する必要があります。

https://workspace.google.co.jp/intl/ja/
右上の「無料試用を開始」より手続きを完了させます。
※本来有料ですが、14日間のトライアル期間があるので登録してしまいましょう

##2.コードを書く準備をする
GoogleDriveからスプレッドシートを新規作成する。
画面左上の「新規」→「空白のスプレッドシート」を選択。
シートが作成されたら、とりあえず名前をつけて保存。

メニューバーより「ツール」→「スクリプトエディタ」を選択
画面が変わらない場合は、数秒経ってからもう一度選択してみてください。

![スクリーンショット 2021-02-21 12.16.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1104729/035e2bff-b3df-fac4-3da0-a9568b3203c1.png)

こんなエディタ画面が開くので名前をつけて保存。
※以後、コードを書くことでシートを操作できます

スクリプトエディタのメニューバーより
「表示」→「マニフェストファイルを表示」を選択すると、appsscript.jsonのというファイルが画面上で開かれます。
"chat": { }　を追記します。※"V8"の後にカンマを忘れないこと

```
{
  "timeZone": "America/Los_Angeles",
  "dependencies": {
  },
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "chat": { }
}
```

一度、コード.gs のタブ戻ります。
既存のコードをすべて消します。
以下の公式サイトより、オウム返しさせるためのコードをコピペして保存。

公式サイト
https://developers.google.com/hangouts/chat/how-tos/bots-apps-script

コードのテンプレート
https://www.google.com/url?sa=D&q=https://script.google.com/create?template=hangoutsChat

次のステップで使うための、Deployment IDを控えておきます。
エディタのメニューバーより「公開」→「マニフェストから配置」を選択
Latest Version横のGet IDをクリック
Deployment ID：xxxxxx... をどこかにメモします。

##3.GCPプロジェクトを作成する
以下のサイトのステップ3のとおりに進めると間違いないです。
https://cloud.google.com/blog/ja/products/g-suite/building-a-google-hangouts-chatbot-using-apps-script

補足：
APIの名前は今だと「Google Chat API」に変わっています。
アバターのURLは、ご自身のGoogle Driveに画像をアップロードした後、画像を右クリックするとリンクを取得できます。
APIが有効になっていると、以下画像のようにチェックが入ります
![スクリーンショット 2021-02-21 12.00.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1104729/709e3166-52f8-0e46-4932-a0337d0260ac.png)


ここまで終わった時点で、メッセージを送信するとオウム返しするBotが完成しているはずです。
コピペしたコードの意味については以下の記事で詳しく解説されています！
「GoogleChat の一番簡単なBotを公式通り作ってみるよ」
https://qiita.com/akky-tys/items/5b22f93b7bb8872836c5

あとはコードを弄って機能を自由に拡張させてみましょう。
弄ったコードは即時反映されるので安心ですね！
機械学習初心者による自然言語処理考察

#はじめに

自然言語処理100本ノック第7章で「スピアマン相関係数」が出てきたので、初心者の私なりに理解できた部分を記載する。

###第7章-66 問題文
>The WordSimilarity-353 Test Collectionの評価データをダウンロードし，単語ベクトルにより計算される類似度のランキングと，人間の類似度判定のランキングの間のスピアマン相関係数を計算せよ．

###第7章-66 解答
以下のコードが正解となっている。（[こちらの記事](https://qiita.com/yamaru/items/822af1f7f77666381e20)より引用）

```
!wget http://www.gabrilovich.com/resources/data/wordsim353/wordsim353.zip
!unzip wordsim353.zip
```
```
!head -10 './combined.csv'
```
```
Word 1,Word 2,Human (mean)
love,sex,6.77
tiger,cat,7.35
tiger,tiger,10.00
book,paper,7.46
computer,keyboard,7.62
computer,internet,7.58
plane,car,5.77
train,car,6.31
telephone,communication,7.50
```
```python:
ws353 = []
with open('./combined.csv', 'r') as f:
  next(f)
  for line in f:  # 1行ずつ読込み、単語ベクトルと類似度を計算
    line = [s.strip() for s in line.split(',')]
    line.append(model.similarity(line[0], line[1]))
    ws353.append(line)

# 確認
for i in range(5):
  print(ws353[i])
```
```:出力
['love', 'sex', '6.77', 0.2639377]
['tiger', 'cat', '7.35', 0.5172962]
['tiger', 'tiger', '10.00', 0.99999994]
['book', 'paper', '7.46', 0.3634626]
['computer', 'keyboard', '7.62', 0.39639163]
```
```python
import numpy as np
from scipy.stats import spearmanr

# スピアマン相関係数の計算
human = np.array(ws353).T[2]
w2v = np.array(ws353).T[3]
correlation, pvalue = spearmanr(human, w2v)

print(f'スピアマン相関係数: {correlation:.3f}')
```
```:出力
スピアマン相関係数: 0.685
```

ここでは、```['love', 'sex'],['tiger', 'cat'],...```のような名詞に対して、人間が評価した類似度は```'6.77','7.35',...```であり、Google Newsデータセット（約1,000億単語）での学習済み単語ベクトルを元にした単語間のコサイン類似度は```'0.2639377','0.5172962',...```であることを示している。
これらの２つの「人間が評価した類似度」と「単語ベクトルを元にしたコサイン類似度」を比較して、スピアマン相関係数を計算した結果が**0.685**という数字で現れている。

##スピアマン相関係数とは？
ここで「スピアマン相関係数」が何をしているのか紐解く。
そもそもスピアマン相関係数とは以下のように定義される。

- 2つの変数の分布の相関を評価する
- ０〜１の間の数値で評価し、１に近ければ近いほど相関有り
- 変数の分布は線形じゃなくてもいい
- 変数を順位に変換し、各ペアにおける2つの変数の順位の差を計算する

例えば、

$a = \[4,7,9,2,3,6,10,1,8,5]$
$b = \[17,51,78,33,29,56,90,12,65,24]$

のような２種類の変数の分布がある時に、それぞれの変数を以下のように順位に変換する。

$a' = \[4,7,9,2,3,6,10,1,8,5]$
$b' = \[2,6,9,5,4,7,10,1,8,3]$

スピアマンの順位相関係数$ρ$は以下のように定義される。

```math
 ρ = 1-\frac{6\sum D^2}{N^3-N}
```
$D$ = 対応する$a$と$b$の値の順位の差
$N$ = 値のペアの数

上記の$a',b'$を愚直に計算すると以下のようになる。

```math
 ρ = 1-\frac{6(2^2+1^2+0^2+3^2+1^2+1^2+0^2+0^2+0^2+2^2)}{10^3-10}\\
 =1-\frac{6\times20}{990}\\
=0.878787...
```

結果、$a,b$の相関係数は約0.88であり、かなり高い相関があるといえる。

前述した「人間が評価した類似度」と「単語ベクトルを元にしたコサイン類似度」のスピアマン相関係数:は0.685だったことから、ある程度の相関はあるものの、人間の感覚と機械学習での評価は一定以上の差があることが分かる。
【やらかし記事】Githubにデータベース情報を公開してしまった…

# 背景
・PHP/MySQLを学習し終え、簡単なアプリ開発をしたので、Herokuにデプロイしました。(これが人生初デプロイでした。)
・ポートフォリオの説明用にQiita記事(※)を投稿し、そこにGithubのURLを張り付けていました。
※書いたQiita記事は[こちら] (https://qiita.com/TkTkTkTkTako/items/d32fd686ce5335101e2a)です。

# きっかけ
投稿した[Qiita記事](https://qiita.com/TkTkTkTkTako/items/d32fd686ce5335101e2a)に以下の内容のコメントをいただきました。
>コメント
「すぐにデータベース情報を消して！Herokuなら環境変数も使えるよ！」

※要点を絞って記載しております。元コメントは抜粋しておりません。

しかし、
>自分
「データベース情報を消す理由は？環境変数とは？？そもそもデータベース情報を記事に記載していないはず…」

と「？」しか浮かびませんでした。

※ここでいうデータベース情報とは以下の``heroku config``の結果で表示される情報です。

```
$ heroku config
 === arcane-ravine-17252 Config Vars
 CLEARDB_DATABASE_URL: mysql://<username>:<password>@<hostname>/<dbname>?reconnect=true

```
[こちらの記事](https://qiita.com/KZ-taran/items/6fd4fc6617953fdbc7db#%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E8%A8%AD%E5%AE%9A)などを参考にして
・Herrokuアカウントの作成
・Herokuアプリケーションの作成
・HerokuCLIのインストール
・ClearDBのインストール
が全て完了したら取得できるものです。

### 当初の認識
元々、データベース情報(ユーザー名／パスワード／ホスト名／データベース名)は個人情報と同じようなもので、**管理に注意が必要であることは知っていた**のでQiita記事を書く際やTwitterでアウトプットする際も気を付けていた**つもり**でした。
ですが、コメントを頂いたのでDB情報が記事内に書かれているのか再度見返しました。

### 重大なミスが発覚…
すると、、、**Qiita記事に貼っていたGithub上のコードにDB情報を公開している**ことに気づきました(汗)

今回のアプリの開発で、普段から何気なくGithubにコード管理のためにプッシュしていたのですが、そのプッシュの内容に本番環境用のデータベース情報がしっかり入っていました(;^ω^)
この時点で、この行為自の危険性を初めて認識しました。

# 対処方法
コメント頂いた通り、すぐに以下を実行しました。
・Herokuで作成した当初アプリを削除
・再度新しいアプリを作成
・本番環境用のDBを作成し**環境変数を使って**デプロイ
⇒デプロイの際に参考にした記事はこちらです
[【PHP】Heroku×PHP×MySQLの環境設定] (https://ryuki999.com/2019/11/10/herokuxphpxmysql-setup/#toc2)

# 原因
大きく分けて2点です。
### 1.Github上のコードは公開されているということの意識の欠乏
Githubはコードを管理すると同時に、「コードは公開されている」ということを忘れていたことが理由の一つです。

### 2. ステージング方法の悪い癖
私は普段Gitでのコミット時、ステージングを
``git add .``
で必ず実行する癖がついていました。

これでは意図しないファイルまでステージング／コミットしてしまうことにつながるので、ステージングは
``git add -p <ファイル名>``
も使用する必要があると学習しました。

# 学んだこと

エンジニアはデータベース上の顧客の個人情報を扱うことになるので、課題解決と同時に**セキュリティ上の問題**にも十分注意して仕事を進めなければいけないのだ、と実感しました。

このような事態が起こったのがエンジニアとして実務をする前の、個人開発のタイミングで本当によかったと感じました。
psycopg2でTypeError: argument 1 must be a string or unicode object: got tuple insteadと言われたとき

# エラーを吐くコード

理由：tupleを引数に与えているから。

```py
import psycopg2


def insert_values(sql):
    conn = psycopg2.connect(host=HOST,
                            user=USER,
                            password=PASSWORD,
                            dbname=DBNAME,
                            port=PORT)
    cur = conn.cursor()
    cur.execute(sql)
    conn.commit()


if __name__ == "__main__":
    sql = ('INSERT INTO test_table VALUES(%s, %s)',
           ('Taro', 5))
    insert_values(sql)
```

# 解決策

unpack

```py
cur.execute(*sql)
```

# 参考記事

psycopg2 documents
https://www.psycopg.org/docs/usage.html#passing-parameters-to-sql-queries
GASでGメールをスプレッドシートに一覧化するプログラムを作ってみた

# 概要

仲間内で共有しているメールアドレスに届くメールチェックのため、GAS を使って特定のアドレスから届いたメールをスプレッドシートに自動で一覧化するプログラムを書いてみました。

# 用いた技術

- GmailApp.search('条件')　：G メールから指定の条件のメールだけ抽出するメソッド
- sheet.insertRowsBefore(行番号, 行数):指定した行番号より上に指定した行数を追加する

# 仕様

- 特定のアドレスからのメールのみを抽出する
- 前日から今日までの間に受信したメールを取り出す

# 意識したこと

指定条件に一致するメール情報をスプレッドシートに随時書き込む仕様だと処理時間が長くなるため、まずはあらかじめ準備したオブジェクトにメール情報を全て保存してから、まとめてスプレッドシートに記載する仕様にしたこと

# 開発したコード

```javascript
ファイル1：common.gs
/**
 * 共通設定
 */
const functionName = 'common()';
const MAX_MAIL_NUM = 100;  // 最大取得メール数
const THREAD_NUM = 0;     // 取得するスレッド(通常は0(冒頭のスレッド)を指定)

// 取得条件
const searchMail = "to:[抽出したいメールアドレス]";  // 取得するメールの条件設定
const startDate = new Date();
startDate.setDate(startDate.getDate() - 1);
const searchPeriod = `after: ${Utilities.formatDate(startDate, 'JST', 'yyyy/M/d')}`;
const query = searchMail + " " + searchPeriod;
console.log(`${functionName} startDate = ${startDate}`);
console.log(`${functionName} query = ${query}`);

// メール情報を記載するスプレッドシート情報
const objSpreadSheet = SpreadsheetApp.openById('[スプレッドシートのID(スプレッドシートのURLの"1"から"/editの手前"まで)]');
const objSheet = objSpreadSheet.getSheetByName('シート名');

// メール情報オブジェクト
const mailRecord = {
  Subject: "",    // 件名
  Body: "",       // 本文
  Time: "",       // 送信日時
  From: "",       // 差出人
};

```

```javascript
ファイル2：InputGmailToSheet.gs
/**
 * @brief 受信したメールをスプレッドシートに記載する
 * @date 開発した日
 * @author 開発者名
 */
function InputGmailToSheet() {
  const function_name = "InputGmailToSheet()";
  console.log(`${function_name} start`);

  const myThreads = GmailApp.search(query, THREAD_NUM, MAX_MAIL_NUM);
  const myMsgs = GmailApp.getMessagesForThreads(myThreads);
  console.log(`${function_name} myMsgs = ${myMsgs}`);

  // 指定クエリと一致するスレッドを全てループ
  const mailDataList = [];
  for ( let threadIndex in myThreads ) {

    // メールから 件名(Subject)、本文(Body)、送信日時（Time）、差出人（From）を抜き出す
    mailRecord.Subject = myMsgs[threadIndex][0].getSubject();
    mailRecord.Body    = myMsgs[threadIndex][0].getBody();
    mailRecord.Time    = myMsgs[threadIndex][0].getDate();
    mailRecord.From    = myMsgs[threadIndex][0].getFrom();
    console.log(`${function_name} Subject = ${mailRecord.Subject}`);
    console.log(`${function_name} Time = ${mailRecord.Time}`);
    console.log(`${function_name} From = ${mailRecord.From}`);

    // 取得したメール情報をmailDataListに追加
    mailDataList.push([mailRecord.Time, mailRecord.Subject, mailRecord.From]);
    console.log(`${function_name} mailDataList = ${mailDataList}`);
  }

  // 指定されたシートの1行目は見出し行とし、最新のデータを常に２行目以降に追加
  objSheet.insertRowsBefore(2, mailDataList.length);

  // 抽出した情報をセルに入力する
  objSheet.getRange(2,2,mailDataList.length, 3).setValues(mailDataList);

  console.log(`${function_name} end`);
  return;
}
```

### 参考情報

https://walking-elephant.blogspot.com/2021/01/gas.timezone.html
【Rails6】AWS EC2デプロイ時に背景画像を表示

#前提
・AWS EC2は導入済み

・背景画像は『app/assets/images』フォルダに格納している


#バージョン
rubyのバージョン　ruby-2.6.5
Railsのバージョン Rails:6.0.0

#はじめに
background-imageプロパティを使って、Herokuやローカル上では背景画像が表示されているのに
AWS EC2でデプロイしたら、背景画像が表示されないので、それを解決したい方向けの記事となっています。

#概要
以下2点を変更して、再度デプロイすると背景画像が表示されます。

①CSSファイルをSCSSファイルに変更する。

②背景画像を指定するCSSの記述をbackground-image: image-url("画像名");に変更する。

#詳細
##①CSSファイルをSCSSファイルに変更する。
以下のどちらかのパターンで行えます。

・ファイル名の拡張子を、 .CSS → .SCSSに変更する。
・背景画像を表示させているviewの拡張子.SCSSファイルに、②の内容を記述する。

※私は後者を選びました。というのも、SCSSに拡張子を変更してしまうと、それまで記述したCSSの記述に影響が出るためです。

##②背景画像を指定するCSSの記述をbackground-image: image-url("画像名");に変更する。
SCSSファイルの内容を以下のように変更します。

（変更前）

```app/assets/stylesheets/~.scss
background-image: url(画像名);
```
↓

（変更後）

```app/assets/stylesheets/~.scss
background-image: image-url("画像名");
```

※""（ダブルクォーテーション）を忘れないようにしてください

#③デプロイして確認
確認し問題なければ終了です。
なお、ローカル内でも、同様の表示ができます。

#背景画像が表示されない理由
表示されない理由としては、Asset Pipelinの仕組みが関係しています。

仕組みの１つとして、※1)キャッシュされていた既存のアセットを無効化を行います。というのも、キャッシュの効果を使った悪用を防ぎ、デプロイさせる役割をしているためです。

変更前のbackground-image: url(画像名);記述では、「url」がファイル名は以前と変化していないと認識され、既存のキャッシュとしてみなされます。

したがって、既存の古いキャッシュでは読み込めない状態となるので、、画像を読み込んでもらえません。


（変更前）

```app/assets/stylesheets/~.scss
background-image: url(画像名);
```

そこで、
「url」を指定するのではなく、Railsが指定している「image-url」メソッドを使うことで、デプロイ時にapp/assetsから読み込めるようにします。

（変更後）

```app/assets/stylesheets/~.scss
background-image: image-url("画像名");
```

※1) キャッシュとは、データを一時的に保存することで、データの処理速度を速める考え方、仕組みのこと。


#補足
AWS EC2をデプロイする方法を以下に載せていますので、よろしければご参考ください。
https://qiita.com/narimiya/items/2e642b60baa4002c4bee

assetsディレクトリに関しても以下に載せていますので、よろしければご参考ください。
https://qiita.com/narimiya/items/73ca907c74b4c615f39d

以上です。
psycopg2でpsycopg2.ProgrammingError: no results to fetchと言われたとき

# statusmessage
fetchall()やfetchone()ではなくstatusmessageを使う。
select文だとfetchall()で結果を表示できるが、insert文だとエラーを吐く。


```py
import psycopg2


def insert_values(name, age):
    conn = psycopg2.connect(host=HOST,
                            user=USER,
                            password=PASSWORD,
                            dbname=DBNAME,
                            port=PORT)
    cur = conn.cursor()
    cur.execute('INSERT INTO sample_table VALUES(%s, %s)', (name, age))
    cur.execute(sql)
    conn.commit()
    print(cur.statusmessage)


if __name__ == "__main__":
    insert_values('Taro', 5)
```

# 参考記事

stackoverflow
https://stackoverflow.com/questions/55400707/python3-psycopg2-no-results-to-fetch-using-returning

github issues
https://github.com/psycopg/psycopg2/issues/346
量子コンピュータの基本 - 基底エンコーディングと振幅エンコーディング

## :level_slider: この記事の目的

私達が普段から行っている数値の計算(以降、古典計算と呼びます)を量子コンピュータ上で都合よく計算するのはどうすれば良いでしょうか。ここでは、古典計算において計算で使用したい値を量子コンピュータ上で表現する方法の一つである、**振幅エンコーディング**について説明します。

## :level_slider: 量子ビットと確率振幅

私達が普段から使っているコンピュータ(以降、古典コンピュータと呼びます)は、0と1を計算のもとの値(基底)として使用しています。これを**ビット**と言います。
このビットは、原理的には電圧の高い・低いで区別され、0または1の値は入れ替わったり変化したりはしません。もし変化することがあるとすれば、それは計算結果も変動することになり計算機としての信頼性が無いことになります。

ところが量子コンピュータでは、全く事情が異なります。量子コンピュータは量子力学の原理に基づいて動作するコンピュータです。古典コンピュータと同様に計算のもとの値はビットを使用しますが、このビットの値が0を指したり1を指したりします。これは確率的に変動します。

量子コンピュータでは、1ビットのことを**1量子ビット**と呼びます。
1量子ビットは以下のような書き方をします。

```math
1量子ビット\:=\:|0〉\:または\:|1〉
```

先に、0と1の値は確率的に変動すると書きました。
変動したときに「どのような確率を取るか」を決めておく必要がありますので、以下のように定義します。
ここで、$\alpha$または$\beta$は実数または複素数とします。

```math
1量子ビット\:=\:\alpha|0〉+\:\beta|1〉\quad...(式.1)
```

$\alpha$及び$\beta$は確率的に決まりますので、以下の確率原則が成立します。

```math
|\alpha|^2+|\beta|^2=1
```

$\alpha$及び$\beta$を**確率振幅**と呼びます。

## :level_slider: 基底エンコーディング

1量子ビットは(式.1)のように表現しました。
それでは、2量子ビットはどう表現したら良いでしょうか。2量子ビットも同様に確率振幅を使用して表記します。

```math
2量子ビット=\alpha|00〉+\beta|01〉+\gamma|10〉+\delta|11〉\quad...(式.2)
```

もちろん、確率原則が働くことにも注意が必要です。

```math
|\alpha|^2+|\beta|^2+|\gamma|^2+|\delta|^2=1
```

量子ビットの数をどんどん大きくすると、例えば|001〉、|0101〉、|10010〉…と増えていきます。これでは0や1を書くことが大変になります。

そこで、以下のように10進数を利用し、量子ビットを表現します。

```math
|0〉=|0〉\\
|1〉=|1〉\\
|2〉=|10〉\\
|3〉=|11〉\\
|4〉=|100〉\\
\vdots\\
|n〉=|...〉
```

さらに上記に確率振幅を付与し、量子ビットは以下のように表現します。
確率振幅を$a$とすると

```math
\begin{align}
量子ビット&=a_0|0〉+a_1|1〉+a_2|2〉+ ...+a_{n-1}|n-1〉\\
&=\sum_{i=0}^{n-1}a_i|i〉
\end{align}
```

確率原則から$a$は以下のようになります。

```math
\sum_{i=0}^{n-1}|a_i|^2=1
```

このように、古典のnビット1,2,3,...を量子ビットに書き換えることを**基底エンコーディング**と言います。

## :level_slider: 振幅エンコーディング

古典コンピュータで使用するデータを確率振幅にエンコード(割り当て)する方法を**振幅エンコーディング**と言います。

例えば、古典データ$x_0$,$x_1$,$x_2$...$x_{n-1}$のn次元のベクトルがあるとき、これを振幅エンコードすると以下のようになります。

```math
\mathbf{x}=\begin{pmatrix} x_0 \\ x_1 \\ \vdots \\ x_{n-1} \end{pmatrix}\quad\rightarrow振幅エンコード\rightarrow\quad\sum_{i=0}^{n-1}x_i|i〉

```

ここで、確率原則から$\mathbf{x}$は以下を満たします。(規格化と言います)

```math
\sum_{i=0}^{n-1}|x_i|^2=1

```

またベクトルだけではなく、要素を$a_{ij}$とし、m行 x n列の行列Aを用いて振幅エンコーディングすることもできます。

```math
A=\begin{pmatrix} a_{00} & a_{01} & ... & a_{0n} \\ a_{10} & a_{11} & ... & a_{1n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m0} & a_{m1} & ... & a_{mn} \end{pmatrix}
\quad\rightarrow振幅エンコード\rightarrow\quad
\sum_{i=0}^{m-1}\sum_{j=0}^{n-1}a_{ij}|i〉|j〉

```

ただし、規格化条件は以下となります。

```math
\sum_{i=0}^{m-1}\sum_{j=0}^{n-1}|a_{ij}|^2=1

```

## :level_slider: 振幅エンコーディングの応用

振幅エンコーディングを応用することで、古典計算を行うのと同じように、計算に使用したい値を特定して(固定して)量子ビットに割り当て、計算を行うことができます。

どのように行うのかと言うと、上記の特定の値を確率振幅に取り込むという方法を取ります。
ただし、確率原則を守る必要があるため、その他の確率振幅には確率原則が有効な値を設定することになります。


## :level_slider: 関連情報

:paperclip: 量子コンピュータの基本 - ブロッホ球の数式をしっかり解説
https://qiita.com/ttabata/items/0e839d03963d656551e0


## :level_slider: ご意見など

ご意見、間違い訂正などございましたらお寄せ下さい。
swift辞書「振らた事を検知する」

#お断り
この記事は自分専用メモなのですごい初歩的な事しか書いていませんがご了承下さい。
確認環境
Interface:Storyboard
Life Cycle:UIKit App Delegate
Language:Swift
◉Use Core Data
__○Host in CloudKit
◉Include Tests

#この記事で出来る様になる事
振られた時の処理が書けるよういになる

#実装
###UIの実装
無し！！
###コードの実装
```swift
import UIKit
import CoreMotion
import AVFoundation

class ViewController: UIViewController {
    
    let MotionSensor = CMMotionManager()
    var sound:AVAudioPlayer!

    override func viewDidLoad() {
        super.viewDidLoad()
        getAccelerometer()
        sound = try? AVAudioPlayer(contentsOf: URL(fileURLWithPath: Bundle.main.path(forResource: "test", ofType: "wav")!))
        // Do any additional setup after loading the view.
    }
    func get() {
            sound.stop()
            sound.currentTime = 0
            sound.play()
    }
    func getAccelerometer() {
        MotionSensor.accelerometerUpdateInterval = 0.2
        MotionSensor.startAccelerometerUpdates(to: OperationQueue.current!, withHandler: {
            accelerometerData,error in
            let x = accelerometerData!.acceleration.x
            let y = accelerometerData!.acceleration.y
            let z = accelerometerData!.acceleration.z
            let synthetic = (x * x) + (y * y) + (z * z)
            
            if synthetic >= 6 {
                self.get()
            }
        })
    }

}
```
**let MotionSensor = CMMotionManager()**ではCMMotionManagerのインスタンスMotionSensorを作る
**func getAccelerometer()**この関数内に振られたか調べるプログラムを書いて行く
**MotionSensor.accelerometerUpdateInterval = 0.2**加速度を確認する間隔を0.2秒ごとに確認する
**let x = accelerometerData!.acceleration.x**ではxの加速度を取得する
**let synthetic = (x * x) + (y * y) + (z * z)**ではx、y、zの加速度を掛け合わせて変数syntheticに代入する
後はif文で一定値を越えたら音を鳴らす関数を呼び出す

#細かいところ
めんどくさいので細かい所はappleのリファレンスを見て
https://developer.apple.com/documentation/coremotion
(Laravel)外部キーを設定するにはデータ型を揃える。

#環境
Windows10
Laravel 8.27.0
XAMPP 8.0.1

#問題
Laravelでテーブルを作成し、外部キーを設定しようとしているのにエラーが発生する。

```jsx
("SQLSTATE[HY000]: General error: 1005 Can't create table `todo`.`folders` (errno: 150 "Foreign key constraint is 
incorrectly formed")
```

#原因
データ型が適切でないことだった。
外部キーを設定する側 \$table->integer('user_id')->unsigned(); //INT(符号なし)
外部キーの対象側 \$table->id(); //BIGINT(符号なし)

#解決策
外部キーを設定する側 \$table->bigInteger('user_id')->unsigned(); //BIGINT(符号なし)
外部キーの対象側 \$table->id(); //BIGINT(符号なし)

参照先`$table->id()`のとき、参照先カラムのデータ型が符号なしのBIGINTだったため、外部キーを設定するカラムも符号なしのBIGINT(符号なし)型`$table-bigIngeger('user_id')->unsigned()`で指定する必要がある。

データ型を適切に指定し、`php artisan migrate:refresh`でテーブルをすべて作り直し解決。
みんなのiOS講座 ゼロからSwiftで学ぶiPhoneアプリ開発の基礎：作業メモ③

本日も[みんなのiOS講座 ゼロからSwiftで学ぶiPhoneアプリ開発の基礎](https://www.udemy.com/course/ios-apps/)の学んだことメモ。
Swiftの基礎nの続き。



#分岐

ifを使った条件分岐。
ここはSwift Playgroundsでやっていたこともあったので、そんなに難しくなかった。



#配列


- 配列を用いることで、1つの変数の中に複数の要素を格納することができる。

```
let a = [1, 2, 3, 4, 5]
```
上記の場合、変数が全て整数なので、int型の変数だと認識される。


- また、下記のように[]を使って数字を指定すると、配列の中の各要素を取り出すことができる。

```
let b = a[0]
```

この場合、aの配列の先頭は1という数字なので、1という数字が出力される。


- letの場合、配列の中を変更することができないが、varの場合は配列の中を変更することができる。

```
var e = [1, 2, 3, 4, 5]

e.append(6)
e.remove(at: 3)
```

この場合、appendで6という要素が新たに追加されたことになり、removeで先頭から3番目の要素が削除された状態となる。


- 加えて、下記のように配列の要素を指定して、変更することもできる。

```
e[2] = 9
```

この場合、先頭から2番目の数字が9に変更されている。


#ディクショナリ

- キーと値をセットで格納し、キーを使って値を取り出すことができる。
- 多くのデータを効率的に管理するのにとても便利。

```
let a = ["Taro": 1985, "Hanako": 1986]

let b = a["Taro"]
let c = a["Hanako"]
```

この場合、Taroの値1985とHanakoの値1986が出力される。


- varの場合は、ディクショナリを追加・変更することもできる。

```
var d: [String: Int] = ["Taro": 1985, "Hanako": 1986]
d["Jiro"] = 1988
```

この時はTaro、Hanakoに加えてJiroを追加した。既にキーが存在している場合は変更されることになる。


#ループ

- 同じような処理を何度も実行することができる。

```
for i in 0..<10 {
    print(i)
}
//10未満

for i in 0...10{
    print(i)
}
//10以下
```


- forループと配列の組み合わせ

```
var a: [Int] = []
for i in 0..<10 {
    a.append(i)
}
```

varで空の配列を作り、for分を使って要素を入れることができる。
また、下記のように書くこともできる。

```
for i in a {
    print(i)
}
```

（実際に活用するときの具体的なイメージがわいていないので、違いがあまりわからない...）


#ループと分岐の組み合わせ

```
var a: [Int] = []
for i in 0..<10 {
    if i%2 == 0 {
        a.append(i)
    }
}
```

この場合は2で割り切れる数字がiの配列のとして出力される（[0, 2, 4, 6, 8]）。

```
var b :[Int] = []
for i in 0..<10 {
    if i%3 == 0 {
        b.append(i*3)
    }else{
        b.append(i)
    }
}
```

この場合は、3で割り切れる数字だけ3倍されていて、他の数字は普通に出力される（[0, 1, 2, 9, 4, 5, 18, 7, 8, 27]）。


#関数とスコープ

- 関数を書いておくことで、処理をまとめておくことができるのでそれを何度も再利用することができる。
- 関数名()をかけば、使用することができる


```
func a() {
    print("Hello!")
}
a()
```

- スコープ

下記の例のように、関数の外で定義された変数の値に関数の中でアクセスできる。
関数の外で定義された変数に関しては、関数の中で使用できる。このような変数の有効範囲のことをスコープという。
また、関数の中で定義した変数は、関数の外からアクセスすることができない。

```
let b = 123
func c() {
    if b == 123 {
        print("Hi!")
    }
}
print(e)
//↑エラーが起こる
```


#引数と返り値

- 関数の外部から渡される値を引数という。

```
let a = 4
let b = 6

func add1(c: Int, d: Int) {
    let e = c + d
    print(e)
}
add1(c: a, d: b)
```

- 返り値とは関数を実行した結果、得られる値
- 返り値の方は->の後に記述する。
- 返り値は関数の外に出ていく値となる。

```
func add2(c: Int, d: Int) -> Int {
    let e = c + d
    return e
}
let f = add2(c: a, d: b)
print(f)
```


#メモ
なんとなく、何をやっているのかは理解しているが、アプリを作るときにどう使用するのか全くイメージがわいていない。
引き続き授業を続けて、解像度上げていきたい。
Apple SiliconなのにArmで動作してなかったら自身を起動しなおすPythonスクリプト

# 気づいてしまった

PyAutoGUIを使ってスクリーンショットを撮るテストをしていた。

```Python
#!/usr/bin/env python3

import sys
import pyautogui

def main(argv):
    ss = pyautogui.screenshot()
    ss.save('test.png')

if __name__ == '__main__':
    main(sys.argv)
```

ターミナルがArmで起動してると正常に動作したが、x64だとダメだった。
たとえば、インサイダーではないVisual Studio Codeの内蔵ターミナルとか。

```
NameError: name 'Image' is not defined
```

現時点(2021-02-21)では「ImageをArmでインストールしていた場合はx64では動作しない」と考えるべきなのだろう。

# 対策する

Apple SiliconなのにプロセッサーがArmではない場合、`arch`コマンドを使って自身を起動しなおせば良い。

```Python
#!/usr/bin/env python3

import platform
import subprocess
import sys
import pyautogui

def main(argv):
    ss = pyautogui.screenshot()
    ss.save('test.png')

def apple_silicon_x64():
    if platform.system() != 'Darwin' or platform.processor() == 'arm':
        return False
    cp = subprocess.run(
        ['sysctl', 'machdep.cpu.brand_string'],
        capture_output=True,
        encoding='utf-8')
    return cp.returncode == 0 and cp.stdout.find('Apple') > 0

if __name__ == '__main__':
    if apple_silicon_x64(sys.argv):
        subprocess.run(['arch', '-arm64e'] + sys.argv)
    else:
        main(sys.argv)
```
コンソールで遊んでみよう！




##自己紹介
![rat.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13048/88a95ca8-6725-8c96-d4ac-3c9083034757.png)
なまえ：rattcv（しばたかずお）
職業：会社員＆フリーランスプログラマ
・UnixライクなOSが好き
・自称CLIヲタク
・青森県弘前市というところに住んでます
・twitter: [@rattcv](https://twitter.com/rattcv)

----

##今回の趣旨
- Linux デスクトップ環境では、X Window System（略して X）というディスプレイ上でウィンドウシステムを提供するネットワーク透過な表示プロトコルが使われています。
（他にWaylandがある）

- 今日はこの X を起動せずに、コンソールのままでグラフィカルなアプリケーションを使用する方法を紹介します。

----



##仮想コンソールについて
仮想コンソールとは、非グラフィカル環境でのテキストコンソールのことです。
X Window System を備えたた Linux 環境で、画面がフリーズした場合などのトラブルシューティングに有効です。

仮想コンソールは tty(TeleTypewriter) と呼ばれています。通常は、6つ(tty1 ~ tty6)が存在します。それぞれのコンソールは同時にアクセスし、異なる作業を行うことができます。

 ■ グラフィカルデスクトップとの切り替え方法(Ubuntu20.04の場合）

|動作|入力キー|
|:-----------------|:---------------------|
|仮想コンソール( tty[1-6] )切り替え|Ctrl + Alt + F[1-6]|
|デスクトップに戻る|Ctrl + Alt + F7|

現在ログインしている仮想コンソールの番号は、次のコマンドから確認できます。

```
$ tty
/dev/tty3
```

`sudo systemctl set-default  multi-user.target` とやってリブートしてもテキストログイン出来る。

`sudo systemctl set-default graphical.target` でグラフィカルモードに戻る。




----

##mltermを使ってみる

Linux Kernel 2.2からframebufferで高解像度のコンソールが使えるが、２バイト文字には非対応。
そこで、ターミナルエミュレータ `mlterm` のコンソール版である `mlterm-fb` を使ってみましょう。

https://github.com/arakiken/mlterm

----
##libsixelを使ってみる

https://github.com/saitoha/libsixel

----

##w3m-sixelを使ってみる

https://github.com/tats/w3m

----

##sayakaちゃんを使ってみる

https://github.com/isaki68k/sayaka

----

##FFmpeg-SIXELを使ってみる

https://github.com/saitoha/ffmpeg-sixel/tree/sixel

----

##matplotlib-sixelを使ってみる

https://github.com/koppa/matplotlib-sixel

----
#おしまい
ROSの勉強　第11弾：センシング-LaserScan

# #プログラミング ROS< センシング-LaserScan >

##はじめに
1つの参考書に沿って，ROS(Robot Operating System)を難なく扱えるようになることが目的である．その第11弾として，センシング-LaserScanを扱う．


##環境
#####仮想環境
|||
|:-:|:--|
|ソフト|VMware Workstation 15|
|実装RAM|2 GB|
|OS|Ubuntu 64 ビット|
|isoファイル|ubuntu-mate-20.04.1-desktop-amd64.iso|

#####コンピュータ
|||
|:-:|:--|
|デバイス|MSI|
|プロセッサ|Intel(R) Core(TM) i5-7300HQ CPU @ 2.50GHz 2.50GHz|
|実装RAM|8.00 GB (7.89 GB 使用可能)|
|OS|Windows (Windows 10 Home, バージョン：1909)|

#####ROS
|||
|:-:|:--|
|Distribution|noetic|
|プログラミング言語|Python 3.8.5|
|シミュレーション|gazebo|


##センシング
センサのデータを読み取る．ここでは，例としてgazeboでのturtlebotに搭載されている深度カメラを用いてレーザスキャンのような擬似のセンサデータを扱う．（これは，コスト削減のため本物のレーザスキャナは搭載していないようだ）

前回( https://qiita.com/Yuya-Shimizu/items/f6afb00fd37019540ca5 )同様，turtlebotをgazebo上で起動させてから``rostopic list``を用いて，turtlebotの仕様を確認する．そのときの様子を次に示す．
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/d0ec40be-1677-360a-e443-ae506dd2097d.png)

赤で印づけているように，``/scan``のトピックがある．さらに``rostopic echo /scan``を実行することで，扱いたいデータがどのように配信されているのか確認できる．そのときの様子を次に示す．
![キャプチャ1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/649b7447-b4d0-21ce-d9f0-39fcc967a070.png)

幾つかのパラメータがあることが分かる．ここで配信されているものを購読すればセンサデータを扱えるということになる．

##センサデータの扱い
ここで簡単にセンサデータの扱いを記録しておく．
レーザスキャンのようなデータということで，距離だけでなく方向も求められる．その式を示す．
#####方向
``bearing = msg.angle_min + i * msg.angle_max / len(msg.ranges)``
#####ロボットの真正面にある一番近い障害物までの距離: ranges配列の中央要素
``range_ahead = msg.ranges[len(msg.ranges)//2]``
#####スキャナで検出した一番近い障害物までの距離: ranges配列の最小値
``closest_range = min(msg.ranges)``


##実装
ここでは，センサデータを読み取ることが目的であるから，単純に読み取ったデータを``print``で数値を可視化するという例を実装する．以下にソースコードとそのときの出力を示す．

#####ソースコード
```python:range_ahead.py
#! /usr/bin/env python3

import rospy
from sensor_msgs.msg import LaserScan	#レーザスキャンを扱うメッセージ

def scan_callback(msg):
	range_ahead = msg.ranges[len(msg.ranges)//2]	#ロボットの真正面にある障害物までの距離　ranges配列の中央要素

	print(f"range ahead: {range_ahead:.1f}")	#正面にある障害物までの距離を表示


rospy.init_node('range_ahead')	#'range_ahead'というノードを生成・初期化

scan_sub = rospy.Subscriber('scan', LaserScan, scan_callback)	#'scan'トピックをLaserScan型で購読し，scan_callback関数を呼び出す

rospy.spin()	#ループ
```

#####出力
![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/226440e8-45a6-2eac-bd5a-a827de055d6c.png)

なお，出力で示されている数値は，gazebo上で直接turtlebotを適当に動かしたときの値であり，センサは図にaheadと示す方向が正面のようだ．

##感想
今回，センサの扱いを学んだ．ロボットを扱うときに非常に重要になってくるところである．次回は前回学んだ移動と今回もセンサを組み合わせたより実践的なものを学ぶということで非常に楽しみである．

##参考文献
プログラミングROS Pythonによるロボットアプリケーション開発
　　　　　　　　Morgan Quigley, Brian Gerkey, William D.Smart 著
　　　　　　　　　　　　　　　　　　　　　　　河田　卓志　監訳
　　　　　　　　　　  　松田　晃一，福地　正樹，由谷　哲夫　訳
　　　　　　　　　　　　　　　　　　オイラリー・ジャパン　発行
Flutter:画面遷移の方向を変える

#実現したいこと
Flutterでページ遷移する際に、遷移方向を変えたい。
Navigator.pushの場合は右方向に遷移してしまうが、左方向に遷移したい場合に使う。


#解決方法
```Dart
  onPressed: () => _onSignOut(context),

  void _onSignOut(BuildContext context) async {
    await FirebaseAuth.instance.signOut();
    Navigator.of(context).pushReplacement(
      SlideRightRoute(page: SecondScreen())
      //SecondScreenが遷移したいページ
    );
  }

class SlideRightRoute extends PageRouteBuilder {
  final Widget page;
  SlideRightRoute({this.page})
      : super(
    pageBuilder: (
        BuildContext context,
        Animation<double> animation,
        Animation<double> secondaryAnimation,
        ) =>
    page,
    transitionsBuilder: (
        BuildContext context,
        Animation<double> animation,
        Animation<double> secondaryAnimation,
        Widget child,
        ) =>
        SlideTransition(
          position: Tween<Offset>(
            begin: const Offset(-1, 0),
            end: Offset.zero,
          ).animate(animation),
          child: child,
        ),
  );
}