OmniAICreator/Qiita-1.07M huggingface dataset:
"Poetry インストール" でうまくいかない話

# TL;DR
非公式の和訳や技術記事を読む前に公式ドキュメントを読みましょう。
[Introduction | Documentation | Poetry](https://python-poetry.org/docs/#installation) 

## 1. Poetryをインストールする
```bash: Unix: Linux, macOS, WSL(Windows Subsystem for Linux)
curl -sSL https://install.python-poetry.org | python3 -
```

```powershell:Windows (Powershell)
(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
```
※ Microsoft StoreでPythonをインストールした場合は、最後の`py`を`python`に書き換えて下さい。(そもそも非推奨ですが)

## 2. PoetryをPATHに追加する
* Unix: `$HOME/.local/bin`
* Windows: `%APPDATA%\Python\Scripts`
* 自分でインストール先を変更した場合: `$POETRY_HOME/bin`

# どうしてこうなった
`get-poetry.py` や `install-poetry.py` は古いインストーラで、v1.2.0でdeprecatedになりました。
Running homebrew on Debian bullseye

```
export HOMEBREW_NO_AUTO_UPDATE=1
cd /home/linuxbrew/.linuxbrew/Homebrew
git checkout 3.5.9
cd /home/linuxbrew/.linuxbrew/Homebrew/Library/Taps/homebrew/homebrew-core/
git checkout 57779e9761bdddb3adcbab6905e11c1da9093fd6^
```

now can use homebrew without installing glibc.

I'm keen to check further when I have time.
Cyberduckを使ってシン・レンタルサーバーへのファイルアップロード

# はじめに
Cyberduckを使ってシンレンタルサーバーへファイルアップロードするときにつまずいたので記載しておきます。

# 背景
今までレンタルサーバーはロリポップを使っていたのですが、
シン・レンタルサーバーを使ってファイルをアップロードするということでつまずきました。

# 結果
入れたいURLフォルダの下にpublic_htmlというフォルダを作成し、
その中にフォルダやファイルを入れることでアップロードできました。

# 参考URL
ホームページのファイルはどこへアップロードすればいいですか？
https://support.xserver.ne.jp/faq/service_ftp_setting_upload.php
laravel 簡単にページネーションを実装する

## 概要

- ページネーションを実装してみたら想像していたより簡単だったのでまとめる

## 前提

- 今回のページネーションの実装はlaravelで完結するアプリケーション（表示にbladeを使用）で実装してみた。
- APIのページネーションはおそらく本方法では実装できないはず。
- この記事は下記ドキュメントの内容を元に体験した内容になります。
    - [https://readouble.com/laravel/9.x/ja/pagination.html](https://readouble.com/laravel/9.x/ja/pagination.html)
- 今回の説明では公式ドキュメントに習ってユーザーの一覧をページネーションしてみる。ページネーションの実装ができていないだけで、コントローラーで取得したユーザー情報を表示する処理は整っているものとする。

## 今回やること

- 全ユーザーの名前一覧を表示しているページでユーザー20件毎にページネーションさせたい。

## 概要

1. 対象データの取得時の設定
    1. 全ユーザー取得の処理が下記のように記載されていたとする。

        ```php
        use App\Models\User;

        $users = User::all();
        ```

    1. 下記のように記載を変更する。（今回20件毎にページネーションさせたいから`pagenate()`の引数を20としているが、ここを変更することで1ページに表示する数を変更できる。）

        ```php
        use App\Models\User;

        $users = User::pagenate(20);
        ```

    1. `User::all()`の時は複数のUserモデルを含んだCollectionが$usersに入っていた。`User::pagenate()`にすると`Illuminate\Pagination\LengthAwarePaginator`のインスタンスが返されるので注意すること。
1. bladeファイルにページネーションリンクの設置
    1. おそらく`$users`をforeachディレクティブで回してユーザーの情報をあるだけ表示しているはずなので、そのforeachディレクティブのendのすぐ下辺りに下記の内容を追記する。

        ```blade
        {{ $users->links() }}
        ```

    1. ここまで問題なく進められていれば、ユーザーの一覧表示ページにアクセスすると下記のように最初の20件のユーザー情報の表示と下部に「pagination.previous」と「pagination.next」といった内容が表示される。ユーザー情報が20件以上ある場合「pagination.next」がクリッカブルになっており、次の20件を開くリンクになっている。

        ![本棚管理システム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/33211975-e791-65cd-9df0-4228ba855328.png)

    1. これでページネーションのメインの実装は完了した。ただ、ページ遷移のボタンが「pagination.previous」と「pagination.next」となっておりなんだかわかりにくい。これを次で改善する。
        - なぜ何も設定しないとこのように表示されるかは下記に記載した。
            - [laravel ページネーションの「pagination.previous」と「pagination.next」はどこに記載されている？](https://qiita.com/miriwo/items/e0d809179e951cfa3aad)
1. ロケーションの変更と翻訳ファイル設置
    1. `config/app.php`を開く
    1. `locale`の値を`ja`に変更する。当該設定値のみの`config/app.php`の内容を下記に記載する。

        ```config/app.php
        /*
        |--------------------------------------------------------------------------
        | Application Locale Configuration
        |--------------------------------------------------------------------------
        |
        | The application locale determines the default locale that will be used
        | by the translation service provider. You are free to set this value
        | to any of the locales which will be supported by the application.
        |
        */
        
        'locale' => 'ja',
        ```

    1. `resources/lang/ja`直下にpagination.phpを新規作成する。（`resources/lang/ja`のディレクトリが存在しない場合は作成する。）
    1. pagination.phpに下記の内容を記載する。

        ```resources/lang/ja/pagination.php
        <?php
        
        return [
            'previous' => '前へ',
            'next' => '次へ',
        ];
        ```

    1. 下記のように「pagination.previous」と「pagination.next」が「前へ」と「次へ」に変わった。

    ![本棚管理システム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/4fa0c60f-a70f-d826-ba1c-2750ea7ff683.png)

## 参考文献

- [https://readouble.com/laravel/9.x/ja/pagination.html](https://readouble.com/laravel/9.x/ja/pagination.html)
CSVのデータを暗号化してURLに格納

# 初めに
自分でアウトプットして記憶にも記録にも残すために書いておきます。

OpenSSLの利用の仕方に戸惑いましたが、
参考URLの一番上のサイトを見て理解を深めました。

# 送信側
```PHP
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<?php
// 読み取り専用でsample.csvを開きます。
$f = fopen("sample.csv", "r");
// test.csvの行を1行ずつ読み込みます。
while($data = fgetcsv($f)){
    // 1行分の要素すべてを文字列として結合しても空ではない、つまり空行でなければ出力します。
    if(implode($data) != null){

$method = "AES-256-CBC";
$key = "sample";

// $numberを暗号化する
$num = bin2hex( openssl_encrypt( $data[0] , $method, $key, 0, $iv ) );
// $adressを暗号化する
$adr = bin2hex( openssl_encrypt( $data[5] , $method, $key, 0, $iv ) );
?>

<a href="detail.php?name=<?php echo("$num"); ?>&adr=<?php echo("$adr"); ?> ">詳細ページへ</a>

</body>
</html>
```

# 受信側
```PHP
<?php
// URLからnumberデータを取得
if(isset($_GET['name'])) { $name = $_GET['name']; }
// URLからaddressデータを取得
if(isset($_GET['adr'])) { $adr = $_GET['adr']; }
// URLのパラメータを復号化する
$method = "AES-256-CBC";
$key = "sample";

// $numberを復号化する
$dec_num = openssl_decrypt( hex2bin( $name ), $method, $key, 0, $iv );
// $adressを復号化する
$dec_adr = openssl_decrypt( hex2bin( $adr ), $method, $key, 0, $iv );
 ?>
<p><?php echo("$data[2]"); ?></p>
```


# 参考URL
PHPのOpenSSLで暗号化して復号する
https://norando.net/php_openssl/
PHPで文字列を暗号化
https://qiita.com/horikeso/items/b8d143fca301d6cf4511
【PHP】URLにプラス（＋）文字がある場合の対応方法
https://online-world.jp/blog/contents/?id=13
herokuでデプロイしたのに「The page you were looking for dosen't exist.」が出た時にしたこと

railsでアプリケーションを作ってherokuにデプロイし、herokuで開いたところ「The page you were looking for dosen't exist.」と出ました。
![スクリーンショット 2022-10-13 10.44.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2881853/877d9c01-38c5-7c77-ec35-266af4d427b0.png)

「・・・え、なんで？」

これでめちゃめちゃ悩み、調べるのに時間を使ってしまったのですが、実は簡単に解決できました。

あくまでも私の場合で解決できたことなので、解決策の1つとして見てもらえればと思います。

結論から言うと、これは自分のページにアクセス来た時、最初に表示させたいページを設定してないので、このような画面が表示されました。

どういうことかというと、このページのURLは「heroku create」で作ったものです。（https://~~~.herokuapp.com/）

でもrailsでアプリケーションを作ってる最中に「localhost:3000/users
（コントローラ名）/new(アクション)」みたいなのって設定しませんでしたっけ？

![スクリーンショット 2022-10-13 11.45.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2881853/f2840877-c421-118d-e63e-7d09dcfdc34a.png)


この「users/new」を打ち込むことで、usersコントローラのnewアクションが実行され、viewの「new.html.erb」が表示されます。

つまり、そのコントローラ名とアクション名をherokuで作ったURLでも設定する必要があります。

設定の仕方ですが、routes.rbで設定します。

![スクリーンショット 2022-10-13 11.59.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2881853/f7c87137-0775-63b6-dbec-72368c1d61a7.png)

２行目の「root 'users（コントローラ名）#new（アクション名）'」を設定することで、アクセス来た時に一番最初に表示することができます。

この設定が終わったら、再度herokuにデプロイします。

そうしたら、usersコントローラのnewアクションで設定したviewのnew.html.erbを表示させることができました。

![スクリーンショット 2022-10-13 12.04.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2881853/e79dafc1-133a-b1e8-c2cd-10410ce8a718.png)

1つの解決策として書かせてもらいました。
もし間違いや意見などがありましたら、コメント欄で教えてもらえると助かります。
Wikipedia データをスクレイピングする

# 前提
- [Gem](https://github.com/kenpratt/wikipedia-client) の使い方について
    - ruby 2.7.4p191
    - wikipedia-client (1.15.0)

# サマリー
- Gem の機能
    - 指定されたタイトルのページ情報を取得する
        - [Wikipedia データ取得用の API](https://www.mediawiki.org/wiki/API:Main_page) の結果を返す
    - ページ情報の IF がいくつか用意されている
        - タイトル、サマリー、テキスト全体、、
- 特定項目の内容を取得したい場合は、自前で抽出する必要がある
    - 例. テキスト全体から正規表現で抽出
- 標準 IF にない情報は、生データ取得 IF から別途取得すれば良い

# 使い方
```ruby
require 'wikipedia'

# ローカル設定を行う
wikipedia_client = Wikipedia::Client.new(Wikipedia::Configuration.new(domain: 'ja.wikipedia.org'))

title = '植物'
page = wikipedia_client.find(title)

# ページタイトル
page.title
=> "植物"

# ページ URL
page.fullurl
=> "https://ja.wikipedia.org/wiki/%E6%A4%8D%E7%89%A9"

# ページ概要
page.summary
=> "植物（しょくぶつ、英: plant）とは、生物区分のひとつ。\n広辞苑の第5版によると「植物」は、草や木などのように、根があって場所が固定されて生きているような生物のことで、動物と対比させられた生物区分である。\nそれに対し、生物学にも歴史があり、二界説ないし五界説のような分類法が採用されていた時代があった。そこでは菌類（キノコやカビ）、褐藻（ワカメなど）なども植物と見なしていた。対してここ数十年の生物学では、分類群としての名称はあくまで「植物界」である為、現在も定義がひとつに定まっていない。陸上植物を含む単系統群として植物を定義するが、どの単系統を選ぶかにより複数の定義が並立している。狭い定義では陸上植物のみを植物として認めるが、より広い定義では緑色植物全体を植物としたり、紅色植物、灰色植物をも植物に含めたりする。また、「植物」と「植物界」という言葉の違いについても、乱暴に『「植物」は植物界のシノニムだ』と言ってしまう人と、『そうではない』という人など、生物学者たちの中でも意見は分かれている。古い二界説や五界説では植物とみなされていた菌類や褐藻や光合成原生動物（ミドリムシや珪藻など）は、「系統が異なる」として、現在（2012年）では生物分類学上は植物とみなされていない。だが、さらにややこしいことに、生態学的には、こういう分類法では無い。例えば生態学では「光合成を行うワカメや珪藻は、植物（生産者）」とする。"

# ページ内容（マークアップ）
page.content
=> ...

# ページ内容（テキスト）
page.text
=> ...

# 特定項目内容（テキスト）
matches = (/== 関連項目 ==(.+?)===? 外部リンク ===?/m).match(page.text)
matches[1].split(/\R/).compact.delete_if {|s| s.strip.empty? }
=> ["樹木 - 草本", "花 - 葉 - 根 - 茎", "生物の分類", "木、木の一覧", "花卉"]

# 生データ
page.raw_data
=> ...
```
NATゲートウェイを作成する

# NATゲートウェイを作成する
AWSマネジメントコンソールにログインしてください。
VPCダッシュボードを表示してください。
[NATゲートウェイ]をクリックしてください。
![スクリーンショット 2022-10-13 11.27.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14202/a9d2d2cd-5f5a-fe94-e9b1-28f00cf04b70.png)

NATゲートウェイのページが表示されます。
[NATゲートウェイを作成]をクリックしてください。
![スクリーンショット 2022-10-13 11.28.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14202/5cc0a63a-e60d-8163-b6f5-712442a99fa3.png)

NATゲートウェイの作成ページが表示されます。
[名前]にお好きな名前を入力してください。
[サブネット]にパブリックサブネットを選択してください。
[Elastic IPを割り当て]をクリックしてください。
[NATゲートウェイを作成]をクリックしてください。
![スクリーンショット 2022-10-13 11.28.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14202/13045176-4dbd-9ea2-4d14-6a90686caa4c.png)

# プライベートサブネットのルートテーブルにNATゲートウェイを登録する
VPCダッシュボードを表示してください。
[サブネット]をクリックしてください。

サブネットのページが表示されます。
NATゲートウェイへのルートテーブルを登録するプライベートサブネットをクリックしてください。
ルートテーブルタブのリンクをクリックしてください。
![スクリーンショット 2022-10-13 11.36.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14202/b31d034d-856d-a6d0-71d0-774a60b6fa1c.png)

ルートテーブルのページが表示されます。
[ルートを編集]をクリックしてください。
![スクリーンショット 2022-10-13 11.36.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14202/7ada109a-579c-916f-69fa-51dc153ee05a.png)

ルートを編集ページが表示されます。
[送信先]に、「0.0.0.0/0」(すべて)を入力してください。
[ターゲット]に、先ほど作成したNATゲートウェイを選択してください。
[変更を保存]をクリックしてください。
![スクリーンショット 2022-10-13 11.37.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14202/ad0f4877-417e-d28e-d5a9-272bec09b54f.png)

以上で、NATゲートウェイの作成とルートテーブルへの追加は終わりです。
Google CloudのAlloyDB for PostgreSQLを性能検証してみた

# はじめに
Google Cloudから新しくリリースされるDB、AlloyDB for PostgreSQLについてスパイクリクエストを与え性能を検証をしてみた記事になります。
また単体検証だけでなく、他サービスとの比較検証を実施しました。

# AlloyDB for PostgreSQLとは
「AlloyDB for PostgreSQL」（以下、AlloyDB）は、Google Cloudで新たにリリースされたデータベースサービスです。
> AlloyDB は、業界トップのパフォーマンス、可用性、スケーラビリティを備えた、フルマネージド PostgreSQL 互換データベース サービスです。
> （中略）
> AlloyDB は標準の PostgreSQL の 4 倍以上の速度です。高いトランザクション スループット、大きなデータサイズ、複数のリードレプリカなど、最も要求の厳しいエンタープライズ ワークロードに適しています。読み取り接続は、低レイテンシのスケールアウト リードレプリカ プールによって水平スケーリングされます。　[AlloyDB for PostgreSQL](https://cloud.google.com/alloydb?hl=ja)

# 検証実施条件
それぞれの製品の性質上、共通する項目が無い部分は「-」としています。

| 項目 | AlloyDB | 他サービス |
| --- | --- | --- |
| クラスタタイプ | 高可用性（読み取りプールあり）を指定 <br>その他の選択肢：高可用性 | - |
| Database | PostgreSQL 14 互換 | PostgreSQL 14.3 互換 |
| リージョン | asia-northeast-1（東京） | - |
| 読み取りプールインスタンス | ワークロードを分割する必要がないため、追加なし | - |

### テーブル定義
テーブル名：test_1

| カラム名 | 型 | デフォルト値 | 制約 | 主キー |
| --- | --- | --- | --- | --- |
| id | BIGSERIAL | - | - | o |
| hash | UUID | uuid_generate_4() | - |  |
| val | BIGINT | - | NOT NULL |  |
| txt | TEXT | NULL | - |  |
| created_at | TIMESTAMP | current_timestamp | NOT NULL |  |
| updated_at | TIMESTAMP | current_timestamp | NOT NULL |  |

※ update_atには自動更新するトリガーを設定しています

### データ件数
1,000,000レコードを登録する想定です。

# 検証内容

Locustを使った下記クエリの一定時間実行時のパフォーマンスをAlloyDB/他サービスで比較する

1. Databaseに直接接続し、create table文でtest_1テーブルを作成する
2. Locustにてinsert文を10分程度実行してパフォーマンス、登録件数等を計測する。<br>
`INSERT INTO test_1 (val) VALUES ({rnd});`
3. test_1テーブルにレコードを1,000,000件登録し、Locustにてselect文を10分程度実行してパフォーマンスを計測する（INDEXでSELECT）<br>
`SELECT * FROM test_1 WHERE id={rnd};`
5. Locustにてupdate文を7分程度実行してパフォーマンスを計測する（INDEXでUPDATE）<br>
`UPDATE FROM SET txt='update-test' WHERE id={rnd};`

※ {rnd}はunixtimestamp/100や1-10,000など範囲指定の数など対象クエリによって変更する。

# 検証環境
負荷試験ツールは、Locustを使用します。

Master/Worker構成にし、秒間100ユーザずつ追加し最終的に10,000ユーザを生成する設定
リクエスト間のwait_timeは0に設定します。

・Google Cloud環境
GKEクラスターにLocustのサービスを追加
クラスターはAutoPilotモードを指定し、リソースは4vcpu相当をリクエストするよう設定
デプロイメントのレプリカセットを16に指定してWorkerを拡張
![AlloyDB.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2916845/90f6fe50-5146-2dda-b495-74619f5921f4.png)

# 検証結果

### Insertの実行結果

実施時間：10分間

結果：
開始から6分ほどは、両者とも同程度のRPS(=Request per Second)で、エラーを除外すると基本的に他サービスの方が安定していましたが、時間経過とともに高負荷になると他サービスのレスポンスタイムのブレが発生してきました。反対に、AlloyDBは高負荷になればなるほど安定し始め、今回のテストでは平均RPS、リクエスト数、登録レコード数ともに他サービスより上回りました。

### Index Selectの実行結果

実施時間：10分間

結果：
数値や推移の傾向はほとんど同じでしたが、わずかながらRPS、リクエスト数共に他サービスの方が高く平均レスポンスタイムも速いという結果になり、Insertや後述のUpdateとは異なる傾向となりました。DBのCPU使用率はどちらも100%近くに張り付いていました。

### Index Updateの実行結果

実施時間：7分間

結果：
開始3分程度まではどちらも安定して同程度のRPSを出していましたが、3分以降は、AlloyDBはRPSが変わらず安定している一方で、他サービスは極端なブレが出始め、不安定になっていきました。

# まとめ 
他サービスは、負荷が少ない場合のレスポンスタイムは良い傾向があるが、ブレが大きい傾向があるのに比べ、
AlloyDBは、低負荷の場合は他サービスよりもレスポンスが悪い様に見えるが、ブレが少なく安定している傾向があると分かりました。 
AlloyDBに関しては、DBのコネクション数のエラーがあり、そこをもっとあげればエラーなく捌いた可能性もあります。

今回は中程度のインスタンスタイプで行いましたが、さらに負荷を上げるとまた違った結果が出るかもしれないです。
Python 3 エンジニア認定データ分析試験【合格体験記】

# 自己紹介：Back Ground
・職業：データアナリスト
・学歴：大卒／大学院はM2のときに中退（10年前）
・最近はIoT, スマート農業関連に力を入れています
・その他資格：臨床工学技士、甲種危険物取扱者など

# Python3 エンジニア認定データ分析試験とは？
一般社団法人Pythonエンジニア育成推進協会が行っている民間資格になります（[詳細](https://www.pythonic-exam.com/exam/analyist)）



# 試験を受けようと思った理由
・分析でPythonを使っているので力試し。
・基礎がしっかり身についているかを確かめるため。
~~・資格を取ると会社から褒賞金が貰える。~~

# 試験後感のレベル
Pythonで分析関連の仕事をしていれば、基礎中の基礎が問われる問題ばかりで、[Prime Study](https://study.prime-strategy.co.jp/)の模擬試験を研究しまくっていたせいか、本番の試験は拍子抜けするほど簡単でした。
（中には「簡単に解かせないゾ」的な問題はありましたが）
制限時間60分40問のところ、20分で全て解き終わり20分で見直しを終える感じでした。
データ分析を生業としている人なら900～1000点くらいは取れるなぁと感じます。

# 使った参考書とか、Webサイトとか
**公式テキスト：[Pythonによるあたらしいデータ分析の教科書](https://www.amazon.co.jp/dp/4798158348/)**
Pythonの基礎がおろそかになっていたので、そこは参考になった。
データ分析ライブラリは使いまくっているので、結構読み飛ばし気味に。
Pythonでのデータ分析を始めたばっかりの人は、得点源であるPythonライブラリ(pandas, NumPy, Matplotlib, scikit-learn)を集中的に学ぶのがおすすめ。

**[PRIME STUDYの模擬試験](https://study.prime-strategy.co.jp/)**
おそらく、本番試験より難しい問題が出る。
3回分の試験があるが、自分の得点は大体70～80点で、あー本番試験ギリギリでの合格かな～と思っていたら余裕の合格。
**注意点としては、本番試験では計算用紙は無いので数学の問題やpandasの問題を頭の中で解く練習をしておくと良いです。**

# 試験結果
**925/1000点**でした。
![Fc53XROaUAEI8OI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436294/8daaa2f6-a11c-156b-ce5d-659bc7331919.jpeg)
Pythonの基礎がなってないですねすみません。
（matplotlibは何を間違えたんだ・・・）
（Jupyter Notebook関連の問題は出てこなかった・・・こういうこともあるのか）

上の得点からするに3問ミスでの合格。
~~満点取れなくて悔しくなんかないやい！~~

合格できたのでめでたしめでたし。
次は統計検定2級と、DS検定リテラシーレベル取得に向けてｶﾞﾝﾊﾞﾘﾏｽ!!
【Ruby】ネストしたHashをselectメソッドを使って検索する方法

## 今回行いたいこと
```
@drinks{:cola=>{:price=>120, :stock=>5},:redbull=>{:price=>200, :stock=>5},:water=>{:price=>100, :stock=>5}}
@slot_money = gets.to_i
```
- 上記のHashの:priceの値と＠slot_moneyを比較し、購入可能なドリンクのみを入れたリストを作りたい。また、在庫がある商品のみをリストに表示する。

## 実装条件をもとに考えたこと
- リストを作りたいので、リストを返すメソッドを使用する。
- 比較しなければいけないので、Hashの中身を検索できるメソッドを使用する必要がありそう。
=>find, find_all, selectなど…?

## とりあえず、selectが条件に合いそうなので実験してみる。
selectメソッドについて
> select -> Enumerator[permalink][rdoc][edit]
select {|key, value| ... } -> Hash
filter -> Enumerator
filter {|key, value| ... } -> Hash
key, value のペアについてブロックを評価し，真となるペアだけを含むハッシュを生成して返します。
ブロックが与えられなかった場合は、自身と select から生成した Enumerator オブジェクトを返します。
[使用例]
h = { "a" => 100, "b" => 200, "c" => 300 }
h.select {|k,v| k > "a"}  #=> {"b" => 200, "c" => 300}
h.select {|k,v| v < 200}  #=> {"a" => 100}
引用:https://docs.ruby-lang.org/ja/latest/method/Hash/i/filter.html
- 公式リファレンスでは、上記のように記載があるためとりあえず{}内にkeyとvalueを記載する必要がありそう。
```
@drinks.select{|drink, content| ...}
```

<b> ここでつまづきました...
<font color="Red">|drink, content|以降の条件を書く部分になんて書いたらええんや...</font>
 ### しかし、ここで天啓が降りてきました。
　「pメソッド使って中身覗いたろ」と。

- その結果できたコードと結果がこちらです。
```
irb:> @drinks.select{|drink, content| p drink}
:cola
irb> @drinks.select{|drink, content| p content}
{:price=>120, :stock=>5}
注:ここではHashの中身が増えるとわかりつらいため、ひとつだけ入れております。
```

- 結果を見て分かる通り、drinkを指定した際はcolaが、contentを指定した際は、{:price=>120, :stock=>5}が取得できています。

<b> ここで、更なる閃きが起きました。
### 「contentの中身がHashならcontent[:price]とかにしたらpriceの値が取得できるんじゃないか?」

ならば、やってみましょう。

```
irb> @drinks.select{|drink, content| p content[:price]}
120
```

取れちゃいましたね~

- ここまで分かれば、あとは簡単です。selectメソッドの条件部分に検索する条件を記載しましょう。

検索条件は「Hashの:priceの値と＠slot_moneyを比較し、購入可能なドリンクのみを入れたリストを作りたい。また、在庫がある商品のみをリストに表示する。」です。
```
irb> @slot_money = 120 #120円お金を持っています。

irb> @drinks #@drinksにコーラとレッドブルと水を入れています。
=> 
{:cola=>{:price=>120, :stock=>5},
 :redbull=>{:price=>200, :stock=>5},
 :water=>{:price=>100, :stock=>5}}

irb> @drinks.select{|drink, content| content[:price] <= @slot_money 
&& content[:stock] > 0 }
=> {:cola=>{:price=>120, :stock=>5}, :water=>{:price=>100, :stock=>5}} #120円で買える商品のリストを取得できました。
```
### 無事にリストを取得できました!!

- リストをよく見ると120円で買える商品のみのリストを取得できています。
レッドブルは200円で120円では購入できないため、リストに入っていません。

## まとめ
- 今回のケースでは、鍵となるのが、ネストしたHashのkeyとvalueに何が代入されるかという部分でした。
実際に、keyとvalueを確認しながら検証を行うことで値の取り出し方についてHashの基本となる方法のみで取り出すことができました。

<b>今後もこまめに変数の中身を確認しながら作業していきたいと思います。
お家サーバー その3

# 概要
お家サーバーやってみる。
apacheでVirtualHostやってみた。

# VirtualHostの手順

# 000-default.confを変更する。
$ sudo leafpad /etc/apache2/sites-available/000-default.conf

```
<VirtualHost *:80>
	ServerAdmin xxx@***.f5.si
	DocumentRoot /var/www/html
	ServerName ***.f5.si
	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
```
# rebootする。

# DDNS Nowを更新する。

ブラウザで、以下を呼び出す。
```
https://f5.si/update.php?domain=***&password=***&ip=125.199.*.67
```

# テスト
ブラウザで、http://***.f5.siを呼び出す。

以上。
Unityの冒険02 -基礎編-


## 13.カメラを押した時に、非表示にしてみよう
Unityで大切なカメラについてやっていきましょう。カメラは<b>Main Camera</b>というゲームオブジェクト名で最初から入っています。
```try13.cs
public class TryCode:MonoBehaviour
{
    void Start()
    {
        //Main Cameraごと非アクティブにしてみる
        gameOjbect.SetActive(false);
    }
}
```
もちろん、Main Cameraゲームオブジェクトに対して非アクティブにする方法もありますが、今回はコンポーネントの非アクティブにする方法をやってみましょう。

```try13-2.cs
public class TryCode:MonoBehaviour
{
    void Start()
    {
        //Camera型の変数名cameraを作成し、Cameraコンポーネントを取得してみる
        Camera camera = gameObject.GetComponent<Camera>();

        //camera変数に対してチェックボックスを外す
        camera.enabled = false;
    }
}
```
ちょっと難しいかも。
まずはカメラコンポーネントを非アクティブにするためには、２行だけで実装できます。

gameObject.GetComponent<Camera>()
このゲームオブジェクトについている -> Cameraコンポーネント
という感じ。

もし、このゲームオブジェクトにCameraコンポーネントがなかったらエラーが起きます。

## 14.テキストを使ってみよう
ゲームをする際欠かせないのがUI。
その中でもテキストを使って、メッセージを出したり、得点やスコアを表示したりします。
```try14.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro; //追加する

public class TryCode:MonoBehaivour
{
    //TextMeshProUGUI型の変数を宣言する
    private TextMeshProUGUI message; 

    void Start()
    {
        //方法１ ： 変数にTextMeshProUGUIコンポーネントを取得する
        message = gameObject.GetComponent<TextMeshProUGUI>(); 

        //方法２ : thisを使う
        message = this.GetComponent<TextMeshProUGUI>();
 
        //変数に文字列を入れる
        message = "Hello world Unity"; 
    }

    void Update()
    {

    }
}
```
今回はUnityの最新版を意識した書き方をしました。Textコンポーネントを使う方法もあり、参考本でもTextコンポーネントを使用しているのもありますが、Unity側はレガシー版として扱っているみたいです。

書き方として、方法１と方法２を紹介しました。どちらも同じ意味になります。


## 15.Rigidbodyでゲームオブジェクトを落下させてみよう
```try15.cs
public class TryCode:MonoBehaviour
{
    //Rigidbody型の変数を宣言する
    Rigidbody rb;    

    void Start()
    {
        //変数にRigidbodyコンポーネントを取得する
        rb = gameObject.GetComponent<Rigidbody>();

        //関数を使ってX方向へ力を与える
        rb.AddForce(100, 0, 0);
    }
}
```
ゲームオブジェクトにRigidbodyコンポーネントをつければ、Unityの再生ボタンを押したときに落下するのは確認できます。今回はもう一個踏み込んで、Rigidbodyコンポーネントで遊んでみましょう。


## 16.Colliderコンポーネントをつけて衝突判定をしてみよう
ヒエラルキーウィンドウで、新しく球や、キューブを作成してみましょう。作成されるとSphere Collider、キューブなら Box Colliderというコンポーネントがついてきます。
```try16.cs
public class TryCode:MonoBehaviour
{
    void Start()
    {
    }

    void Update()
    {
    }

    //新しく関数を作る(名前も同じように書いてね)
    void OnCollisionEnter()
    {
        Debug.Log("地面にあたったよ");
    }
}
```
今回は、「球が地面に触れたらコンソールウィンドウにメッセージを表示する」というのをやってみました。もちろんん、地面はPlaneというゲームオブジェクトを作成し、Mesh Colliderというコンポーネントがついています。

## 17.他のゲームオブジェクト名を取得してみよう
このまま続きとして行ってみましょう。

```try17.cs
public class TryCode:MonoBehaviour
{
    void Start()
    {
    }

    void Update()
    {
    }

    //引数ありの、新しく関数を作る
    void OnCollisionEnter(Collision collision)
    {
        Debug.Log("君は" + collision.gameObject.name + "だね？");
    }
}
```
引数を指定すれば、どのColliderのゲームオブジェクトに触れたのかを調べることができます。
ここまでできれば、ゲーム要素が増してきて楽しくなると思います。
PHP5.6 + Xdebugのインストール (2022)

MacにPHP5.6 + XDebugをインストールします。

PHPはbrewでインストール

```
brew install php@5.6
```

パスを通します。

```
export PATH="/opt/homebrew/opt/php@5.6/bin/:$PATH" 
```

または（インテルの場合）

```
export PATH="/usr/local/opt/php@5.6/bin:$PATH"
```

次にxdebugのインストールをしますが古すぎてpeclではインストールできません。またソースインストールもphpizeのautoconfのエラーで失敗します。

以下のようにソースインストールに必要なautoconfをソースからインストールします。

```
curl -OL http://ftpmirror.gnu.org/autoconf/autoconf-latest.tar.gz
tar xzf autoconf-latest.tar.gz
cd autoconf-*
./configure --prefix=/usr/local
makea
sudo make install
```

次にPHP5.6に対応したXdebug 2.5.5をソースからインストールします。


```
  curl -OL https://xdebug.org/files/xdebug-2.5.5.tgz
  tar xzf xdebug-2.5.5.tgz 
  cd xdebug-2.5.5
  phpize
  ./configure
  make
  sudo make install
  ```




PHPStorm 2022.1.4でPHP 5.6+Xdebugが動作するのを確認しています。
enebularでREMOTE_ADDR

# 概要
enebularでREMOTE_ADDRやってみた。
phpの_SERVER["REMOTE_ADDR"]は、node-redのreq.headersで、取得できるらしい。

# フロー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/daf461de-722d-d6a0-0f13-9acf9910470d.png)


```
[{"id":"a44f4e88.31af4","type":"http in","z":"c8bc4180.f9321","name":"","url":"/ipinfo","method":"get","upload":false,"swaggerDoc":"","x":150,"y":700,"wires":[["4974a693.d4f5d8","21c925f0.687c8a"]]},{"id":"4974a693.d4f5d8","type":"function","z":"c8bc4180.f9321","name":"ip","func":"//msg.payload = msg.req.ip;\nmsg.payload = msg.req.headers;\nreturn msg;","outputs":1,"noerr":0,"x":340,"y":700,"wires":[["18e86d05.60ff63"]]},{"id":"18e86d05.60ff63","type":"http response","z":"c8bc4180.f9321","name":"","statusCode":"","headers":{},"x":550,"y":700,"wires":[]},{"id":"21c925f0.687c8a","type":"debug","z":"c8bc4180.f9321","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"req","targetType":"msg","x":350,"y":620,"wires":[]}]
```

# サンプルコード

```

function run() {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "https://ohiapp0.herokuapp.com/ipinfo", true);
  xhr.onreadystatechange = function() {
    if (this.readyState === 4 && this.status === 200)
    {
      var data = JSON.parse(this.responseText);
      alert(data["x-forwarded-for"]);
    }
  }
  xhr.send();
}
```

# 成果物

https://embed.plnkr.co/plunk/TXYzmSMmS81a973M


以上。
gitの有用コマンドまとめ

# gitを始めるために覚えるべきコマンド
git add <フォルダ名>
編集したフォルダをgitへ追加します。

git commit -m "コメント"
gitのフォルダを保存します。
これをしないとpushできません。

git push
gitをgit hubへ保存します。
error TS2786: 'RouterView' cannot be used as a JSX component.

vue3のscript setup構文で書いたものをnpm run build するとビルドエラーが出た。

scriptタグからlang属性を外したら動いた。
これでtypescriptが効いているのかもわからないし根本的な解決になっていないかもしれないけどとりあえずビルド通したい場合の参考に。

```
- <script setup lang="ts">
+ <script setup>
```
コラッツ予想の計算をイテレータ、ジェネレータでそれぞれ再現してみた

独習JavaScriptで反復処理を勉強しています。
イテレータ、ジェネレータを覚えて、何かに使えないかということで試してみました。

htmlファイルは同じものを使っております。（h1タグだけ異なりますが）
generatorを用いた記述のほうが簡潔で、１０行ほど短く済みました。

何かアドバイス等ございましたらお気軽にコメントください。

```index.html
<!DOCTYPE html>
<html lang="en">
<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>Collatz</title>
</head>
<body>
    <h1>Collatz Iterator</h1>
    <input id="inputNum" type="number" placeholder="自然数を入力">
    <button id="decide">決定</button>
    <div id="outputNums"></div>
    <script src="main.js"></script>
</body>
</html>
```

# イテレータ
```iterator.js
const decideBut = document.getElementById("decide");
const display = document.getElementById("outputNums");

decideBut.addEventListener('click', ()=>{
    display.innerText = "";
    const inputNum = document.getElementById("inputNum").value;
    const collatz = (num) => {
        return {
            next() {
                if(num===1){
                    return {
                        done: true
                    }
                }else if(num%2===0){
                    return {
                        done: false,
                        value: num/=2 
                    }
                }else{
                    return {
                        done: false,
                        value: num=num*3+1
                    }
                }
            }
        }
    }

    const runCollatz = collatz(inputNum);

    while(1){
        let {done, value} =  runCollatz.next();
        if(done){
            break;
        }else{
            let p = document.createElement("p");
            p.innerText = value;
            display.appendChild(p);
        }
    }
},false)

```
# ジェネレータ
```generator.js
const decideBut = document.getElementById("decide");
const display = document.getElementById("outputNums");

decideBut.addEventListener('click', ()=>{
    display.innerText = ""; // 初期化
    const inputNum = document.getElementById("inputNum").value;
    
    const collatz = function* (num) {
        while(num!==1){
            if(num%2===0){
                yield num/=2;
            }else{
                yield num=num*3+1;
            }
        }
        return {
            done: true
        }
    }

    const runCollatz = collatz(inputNum);

    while(1){
        let {done, value} =  runCollatz.next();
        if(done){
            break;
        }else{
            let p = document.createElement("p");
            p.innerText = value;
            display.appendChild(p);
        }
    }
},false)
```
403 エラー



# HTTP/1.1 403 Forbidden Authorization: Bearer nullX-PrettyPrint: 1 Bad_OAuth_Token

[Implement the OAuth 2.0 Web Server Flow](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000HkKaF)

システム側の問題だったようです。自然と回復したらしい

# 403 Forbidden error - response from endpoint

[403 Forbidden error - response from endpoint](https://trailhead.salesforce.com/en/trailblazer-community/feed/0D54S00000Je9JJ)
設定漏れ？相変わらずのよく分からん内容。

# アマゾンのヘルプによる解説など

[API Gateway から HTTP 403 エラーをトラブルシューティングする方法を教えてください。](https://aws.amazon.com/jp/premiumsupport/knowledge-center/api-gateway-troubleshoot-403-forbidden/)

## エラーの原因を検討する

403 エラーが他のリソースから報告された場合、エラーには別の原因がある可能性があります。例:

+ エラーがウェブブラウザで報告された場合、間違ったプロキシ設定が原因である可能性があります。HTTP アクセスが許可されていない場合、プロキシサーバーは 403 エラーを返します。
+ API の前に別の AWS のサービスがある場合、そのサービスは応答に 403 エラーを含めてリクエストを拒否できます。例:Amazon CloudFront。

## curl を使用してリクエストと応答の詳細を取得する

エラーを再現できる場合は、次のように curl-v コマンドを使用してクライアントと API 間の詳細を取得します。

```
curl -X HTTP_VERB -v https://{api_id}.execute-api.{region}.amazonaws.com/{stage_name}/{resource_name}
```

## HTTP リクエストと応答メッセージを分析する

可能であれば、Web ブラウザでエラーを再現します。次に、ブラウザのネットワークツールを使用して HTTP 要求メッセージと応答メッセージをキャプチャし、それらを分析してエラーが発生した場所を特定します。


## AWS Connect Error

[AWS Connect Error](https://trailhead.salesforce.com/en/trailblazer-community/feed/0D54S000000FyLU)

初めは
Amazon Connect & Salesforce: Lambda not working INVALID_SESSION_ID　のエラーだったけど設定を変えると

```
{
  "success": false,
  "status": 500,
  "statusText": "ERR_OSSL_PEM_NO_START_LINE",
  "errorCode": "ERR_OSSL_PEM_NO_START_LINE",
  "errorMessage": "no start line"
}
```

になったようですが、回避策も原因も私には全く理解できなかったです。よく分からん。
Flutterの実行時に渡す引数で実行環境を切り替える方法

# Flutterの実行時に渡す引数で実行環境を切り替える方法

Flutterで開発をしていると接続先のサーバを本番環境と開発環境を切り替えて使いたいときがあったりします。
そのようなときに毎回コードを書き換えて接続先を変えるのではなく実行時に渡す引数で切り替えれるようにします。

## 変数の設定

変数を設定するために専用のFunctionを定義します。   

```dart
void selectEnv(){
  const env = String.fromEnvironment("BUILD_ENV");
  switch(enc){
    case "DEV":
      developModeInit();
      break;
    case "Pro":
      productionModeInit();
      break;
    default:
      developModeInit();
  }
}
```

このFunctionの中では `String.fromEnvironment` を使って実行時に渡される引数を取得します。  
今回は `BUILD_ENV` という変数名にしています。  

その後それぞれ変数の値によってinit用のFunctionを実行しています。  
また引数が渡されなかった場合は開発環境(developModeInit)を実行するようにしています。  

## Flutterアプリに仕込む  

このFunctionを実際のFlutterアプリへ仕込んでいきます。   

```dart
void main(){
  WidgetsFlutterBinding.ensureInitialized();
  selectEnv();
  runApp(child: MyApp());
}

void selectEnv(){
  const env = String.fromEnvironment("BUILD_ENV");
  switch(enc){
    case "DEV":
      developModeInit();
      break;
    case "Pro":
      productionModeInit();
      break;
    default:
      developModeInit();
  }
}
```

今回はmainの中で呼び出していますが必要によって適宜変更してください。  
runAppの前に呼び出すため `WidgetsFlutterBinding.ensureInitialized()` を使いFlutter engine を用意しています。  


## 実行する  

後はflutter run や flutter build を実行すればアプリの起動ができますがこのタイミングで引数を渡してあげます。  
引数を渡すオプションは `--dart-define` を使用します。  

### 開発環境で起動する

開発環境で起動する場合は何も引数を渡さないか以下のオプションをつけて実行します。  

```bash
flutter run --dart-define=BUILD_ENV=DEV
```

これで変数 `BUILD_ENV` に `DEV` を渡すことができます。  

### 本番環境で起動する  

本番環境の起動は必ず引数で指定する必要があるため先程と同じオプションをつけて`PRO`をしています。  

```bash
flutter run --dart-define=BUILD_ENV=PRO
```

これで本番環境での起動ができるようのなりました。  

## その他  

flutter build を実行する際も同じオプションが使えます。  

```bash
flutter build --dart-define=BUILD_ENV=DEV #開発環境
flutter build --dart-define=BUILD_ENV=PRO #本番環境
```
react-i18nextでの多言語対応時に改行を入れる

# 結論

改行したいテキストに以下のcssを適用
```css:css
style {
  white-space: pre-wrap;
}
```
TailwindCSSを使用している場合、以下のclassを追加
```html:tsx
<div className="whitespace-pre-wrap">
  {some-text}
</div>
```

テキスト元の改行した場所に`\n`を追加
```json:json
{
  "some-text": "これは\nテキストです。"
}
```
AlteryxでPDF出力してみた

# 1.はじめに
Alteryx の「レポーティングツール」を使って見積書を作りPDF出力してみました。

# 2.出力結果
今回作成したPDFです。
![qiita_page-0001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2618987/39f0191d-a779-cb14-1350-679e9d7726d8.jpeg)

# 2.ワークフロー
まずは全体像です。
![全体.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2618987/00981ecf-f432-7922-575a-004218c3ffa9.png)
やっていることは主に文字やデータを「フィールド付加」ツールで結合し、「レイアウト」ツールでレコードを結合してパーツをつなげてます。

フローを4つに分けて説明します。
![全体_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2618987/dd3621f8-bcab-0302-806c-b38a9b5e9b97.png)



## 2.1 御見積書～件名までのフロー
御見積書～件名までのフローです。
![1_3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2618987/d16d7593-ac1d-7261-20df-23dcd6f3f31f.png)

①「テキスト入力」では宛名と件名を入力し、「レポートテキスト」ツールで宛名、下記の通り～の文章と件名を作成
②上側の「画像」ツールは会社のロゴ画像と会社情報を上記と同様に作り、下側の「画像」ツールは印鑑用の画像を挿入し、会社ロゴ＆会社情報パーツと結合
③宛名＆件名パーツと会社ロゴ＆会社情報＆印鑑用パールを「レイアウト」ツールで「水平方向」につなげ、できあがったパーツの下に件名を結合し、パーツの上側に「御見積書」の文字と日付を結合

![1_output.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2618987/6bd490c7-ed4f-4fea-6429-6404fc2f07dc.png)
これで、御見積書～件名までが完成です。

## 2.2 合計金額と商品一覧の表のフロー
合計金額と商品一覧の表のフローです。
![2_3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2618987/98389086-fe50-eea5-22bc-883ca2beb9cd.png)
①「テキスト入力」では商品名、数量、単価を入力し、「フォーミュラ」ツールで「金額」の列を作る
②「集計」ツールの部分では小計、消費税、合計を計算する
③「テーブル」ツールで合計金額と商品一覧の表を作成
![2_output.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2618987/eeef1f79-9164-fcae-4453-020e6da6c332.png)

これで、合計金額と商品一覧の表が完成です。
表の色はデフォルト設定のままですが、好きな色に変更も可能です。

## 2.3 パーツ結合～御見積有効期限まで
パーツ結合～御見積有効期限までのフローです。
![3_2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2618987/bd87f3a5-f5c3-80eb-eeb0-fcd28ae316dd.png)
①御見積書～件名までパーツと合計金額パーツを結合
②合計金額と商品一覧との間にスキマを作りたかったので、線なしのテーブル結合
③商品一覧の表を合計金額の下に配置し、「レポーティング」ツールで御見積書有効期限を挿入
![3_output.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2618987/382261a7-cf29-2ce7-ce4e-85090381afe8.png)


これで、御見積有効期限までが完成です。

## 2.4 特記事項を結合してPDF出力のフロー
特記事項を結合してPDF出力フローです。
![4_3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2618987/9a002e75-6cea-204a-a0c7-0c251fcffcf8.png)

①1x1のテーブルに特記事項を挿入
②御見積書～御見積書有効期限までのパーツと特記事項テーブルを「垂直方向」につなげ、「レンダリング」ツールでPDF出力
![4_output.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2618987/422ab539-c392-9d5a-034e-ff60ed7fa34f.png)
これで、PDF出力完成です。

# 3. おわりに
Alteryxでレポーティングツールを駆使してPDF出力する例を紹介しました。
テキスト入力の部分をマクロ入力に変更して、フローをマクロとすればPDF出力ツールになるので便利ですね！
ご参考になればと思います！
az aks get-credentials で取ってきた client-certificate-data の中身を見てみる

Azure のX509証明書の中身を見てみたくなったのでやり方を残します。
```
# デコードします。
$ echo "<client-certificate-dataに記載された文字列>" | base64 -d > test.pem
# x509証明書の内容を確認します。
$ openssl x509 -text -noout -in test.pem
```
やる気を出す方法について

# はじめに
**モチベーションを高くして、やりたいことがたくさんあると思います。** プログラミング言語を覚えたり、IT技術を身に着けたりするだけでなく、ダイエットや記事の執筆などに取り組みたい人もいるでしょう。しかし、**なかなかモチベーションが上がらず、着手できていないのが現実です。** 僕もダイエットや勉強などを先延ばしにしがちです。モチベーションを上げて、やりたかったけど先延ばしにしていることをする、**何かいい方法はないのでしょうか？**
こんな疑問を抱き、本で方法を探したり、友人にきいたりした方法をまとめたいと思います。
まとめただけじゃ、芸がないので、実際に試して効果があったものに限定します。

# 公式（なぜここに公式が？）
モチベーション＝（価値 × 達成できる見込み）/（期間 × 衝動性）


|用語|公式の説明|
|:-----------|------------|
| 価値       |課題の価値が高かったらモチベーションが上がる|
| 達成できる見込み     |頑張っても無理そうなものはちょっとやる気が下がるよね|
| 期間|1か月先のレポートは先延ばしにしがち。逆に明日テストがあるってなると頑張れる|
| 衝動性|目の前にお菓子とかチョコレートがあったら、ダイエットなんて忘れちゃうよね笑
|


これがすべてのもとになるので、自分に足りていないものが何かを考えるときにはぜひ思い出してみてください！

# モチベーションをアップする具体的なステップ
具体的なステップは以下の通りです。
1. タイプを診断する
1. タイプごとの対策をどれか一つ実践する

## 1. タイプを診断する
自分のモチベーションが上がらない理由を自分なりに診断してみてください。
次の3つのうちどれかにあてはまると思います。
* できる気がしない
* 課題が面白くない・楽しくない
* ほかの誘惑に負けちゃう
診断ができたところで、次のステップに進みましょう。

## 2. タイプごとの対策をどれか一つ実践する
出来る気がしない
→自分と似た人との成功体験を読む。励まし合える仲間を持つ。小さな成功体験を積む。

課題が面白くない・楽しくない
→ゲームとして考える。目的意識を持つ。課題の後にご褒美を設定する。

ほかの誘惑に負けちゃう
→誘惑に負けないように具体的な対策を立てる。細かいゴールを設定する（締め切り効果）。誘惑を取り除く。

# まとめ
今回は、モチベーションを上げる方法について解説しました。内容を振り返ると
* モチベーションの公式について
* モチベーションを上げるためのステップについて
* モチベーションが上がらない問題をタイプ別に分ける
* タイプ別の対策について

僕も今回学んだ内容を活かして、いろいろと勉強したり、個人的に重要なことに取り組んでいきます。
興味が出た人はぜひ、参考文献を検索して読んでみてください。


# 参考文献
* ピアーズ・スティール「ヒトはなぜ先延ばしをしてしまうのか」
SakuraサーバーにNode.jsをインストールする方法

# 目的
* Node.js v16.17.1（2022/10/13時点の最新版）をSakuraサーバーにインストールする

# 前提
* Python3がインストールされていること（Node.jsのコンパイルに必要）

# 参考サイト
* https://blog.pinkumohikan.com/entry/how-to-install-nodejs-to-rental-server-of-sakura

# 手順
## Sakuraサーバーにアクセス
```
$ ssh <User>@<User>.sakura.ne.jp
```
## Open SSLのコンパイル
``` 
$ curl -sSf https://www.openssl.org/source/openssl-1.1.1o.tar.gz -O
$ tar zxf openssl-1.1.1o.tar.gz
$ cd openssl-1.1.1o
$ ./config --prefix=/home/<User>/openssl --openssldir=/home/<User>/local/openssl
$ make
$ make install
```
## Node.jsのコンパイル
```
$ cd ~/
$ curl -sSf https://nodejs.org/dist/v16.17.1/node-v16.17.1.tar.gz -O
$ tar zxf node-v16.17.1.tar.gz
$ cd node-v16.17.1
$ ./configure --shared-openssl --shared-openssl-includes=/home/<User>/openssl/include/ --shared-openssl-libpath=/home/<User>/openssl/lib
$ export LD_LIBRARY_PATH=/home/<User>/openssl/lib
$ nohup make install DESTDIR=/home/<User>/local &
$ echo "export PATH=$PATH:~/local/bin 
> export LD_LIBRARY_PATH=/home/tsuyoshiterakawa/openssl/lib" >> .bashrc
```
## Pathの設定
```
$ cd ~/
$ echo "export PATH=$PATH:~/local/bin 
> export LD_LIBRARY_PATH=/home/tsuyoshiterakawa/openssl/lib" >> .bashrc
$ source ~/.bashrc
```
Mac OS に Azure cli をインストール

Cloud Shellではなくローカルで作業したいなあと思ったのでインストール方法を調べました。

Mac の場合は homebrew で入ります。

```
brew update && brew install azure-cli
```

その他のOSへのinstall方法も公式サイトに載っています。
https://learn.microsoft.com/ja-jp/cli/azure/install-azure-cli
Azure Fundamentals(AZ-900)：Azure の基礎: Azure のアーキテクチャとサービスについて説明する「コンテナ(Container)」

Microsoft Learnを用いたMicrosoft Azure Fundamentals(AZ-900)の試験内容をまとめる投稿です。
この投稿ではMicrosoft Learnで学ぶ内容をできるだけ簡潔にまとめております。
Azureの勉強を一から始める方の参考になれば幸いです。

## 今回の学習内容
**◆「コンテナ(Container)」**
◇対応するMicrosoft Learn ラーニングパス
[Azure の基礎: Azure のアーキテクチャとサービスについて説明する](https://learn.microsoft.com/ja-jp/training/paths/azure-fundamentals-describe-azure-architecture-services/)
◇対応するモジュール
[Azure コンテナーについて説明する](https://learn.microsoft.com/ja-jp/training/modules/describe-azure-compute-networking-services/5-containers)

※前回の投稿は下記から確認できます。
[Azure Fundamentals(AZ-900)：Azure の基礎: Azure のアーキテクチャとサービスについて説明する「Azure Virtual Desktop(AVD)」](https://qiita.com/fsd-jume/items/c680203a6c97b9e464d9)

## コンテナ(Container)
**1つのOS上に仮想化した実行環境を複数配置する技術**
OSはコンテナを配置するサーバのものを使うため、実行環境上にOSが不要( =OSの管理も不要)
・VMに比べて少ないリソースで構築とアプリの実行可能
・VMに比べて動作や再起動が高速

**◆Docker
コンテナ技術を活用する際に必要となる仮想化ソフトウェア**
業界における事実上の標準(デファクトスタンダード)であるオープンソフトウェア(OSS)
・設定ファイル(DockerFile)1つで同様のコンテナ環境が容易に作成可能

**◆Azure Container Instances(ACI)
Azure上でコンテナ実行環境を提供するPaaSサービス**
・単純なアプリやバッチ処理など、単一のコンテナ環境における利用を想定

**◆Azure Kubernetes Service(AKS)
Azure上でKubernetes(k8s)を実行する環境を提供**
◇Kubernetes(k8s)：複数のコンテナを管理できるオーケストレーションツール
・コンテナのスケーリングや復旧が自動で可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851723/edd32af1-b700-22d2-678d-3b632c0f2c5d.png)

## 次の学習内容
**◆Azure Functions / Azure App Service**

https://qiita.com/fsd-jume/items/8675b9945ad6a01ff0be

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/e4ec76959adb547ac5e8
【データ基盤構築/BigQuery】パーティションとクラスタリングを実装してみた

# 本題の前に

### パーティションとクラスタリングで得られるメリット
パーティションやクラスタリングを実装することで、
クエリのパフォーマンスを向上させ、クエリリソースの消費を抑えることができる。

パーティションやクラスタリングが実装されたテーブルに対してクエリを実行すると、
テーブルに対してスキャンする範囲を狭めることができるため、
そのようなメリットを得ることができる。

### パーティションとは
テーブルの特定の列の値を基準にして、内部的に複数パートに分割する機能。
クエリ実行時に全体にアクセスするのではなく、WHERE句などで必要なパートに絞り込むことで、そのパートに限定してアクセスすることができる。

[分割テーブルの概要（BigQuery公式ドキュメント）](https://cloud.google.com/bigquery/docs/partitioned-tables?hl=ja)に記載の通り、`時間単位の列`、`取り込み時間`、`整数範囲の列`に応じて複数パートに、パーティションで分割することができる。





### クラスタリングとは
テーブルの特定の列に基づいて、
テーブルのデータを**内部的にソート＆近い位置に配置**することができる機能。
パーティションと併用することができる。
（パーティション分割した後に、クラスタリングされる。）

クラスタ化列は最大4列まで指定可能で、指定する順番にも意味がある。
テーブルやテーブルパーティション全体ではなく、クラスタ化列に基づいて関連するブロックのみをスキャンするかたちになる。


### BigQueryのパーティションのひとつ「シャーディングテーブル」とは
シャーディングテーブルパーティションのひとつで、
データを日付毎に別のテーブルとして作成する方法。
WHERE句で`_table_suffix`でフィルタリングすることで、テーブルのスキャンの範囲を指定できる。

**シャーディングテーブルのメリットは、日付毎に異なるスキーマを適用することができること。**
データソースでカラムが増減した場合でもそのまま取り込めるので、BigQueryをデータレイク的に使用する時に便利。



# 本題
業務でどのように、パーティションとクラスタリングを実装したのかについて。
### パーティションとクラスタリングの実装方法
下記のクエリで、パーティショニングとクラスタリングがされたデータマートを生成した。
（ETLツールのワークフロー機能で毎日同じ時刻に定期実行する）

```SQL
/* create or replace tableは、全量洗い替え更新を意味している。 */
/* or replaceで、同じ名前のテーブルが存在する場合は置き換えられるようになる。 */

create or replace table
    `生成するデータマートの名前`
partition by -- monthごとにパーティショニングされる。
    month
cluster by -- day, os, workidごとに、この優先順位でクラスタリングされる。
    day
    , os
    , work_id
as

select
    day
    , date_trunc(day, month) as month -- 日別ではなく月別でパーティショニングしたいので、この列を生成。
    , content_id
    , content_name
    , work_id
    , work_title
    , uu
    , pv
    , os
from
    `統合テーブル名`
;
```
### 補足
* データポータルで`day`,`os`,`work_id`でフィルタリングすることが多いので、
`day`と`os`と`work_id`をクラスタ化列に設定した。


* 今回は10年以上のデータを取り扱う必要があるため、
`day`ではなく`month`でパーティショニングを行った。
理由は、**BigQueryでは、1テーブルにつき、4,000パーティションまでしか保持できない**ため。
365日×11年=4,015日の段階ではエラーが発生してしまうため、
`day`でパーティショニングするのは控えた方が良いと考えられた。

### パーティション、クラスタリング実装で得られた結果
クエリリソースの消費を節約することができていた。

パーティション、クラスタリング無しのテーブルに下記のクエリを実行すると「14GB」クエリリソースが消費されるのに対し、
```SQL
select
    day
    , date_trunc(day, month) as month
    , content_id
    , content_name
    , work_id
    , work_title
    , uu
    , pv
    , os
from
    `統合テーブル名`
;
```

パーティションとクラスタリングが実装されたテーブルに下記のクエリを実行して同じカラムを抽出しようとすると、クエリリソースの消費は「12GB」となっていた。
```SQL
select
    day
    , date_trunc(day, month) as month
    , content_id
    , content_name
    , work_id
    , work_title
    , uu
    , pv
    , os
from
    `生成するデータマートの名前`
;
```
localStorageとsessionStorage

# localStorageとsessionStorageについて
html5で提供しているAPIのこと。
両方ともkeyとvalueをもつデータを保存場所として使うが、有効期間があるかどうかが大きな違いと言える。
localStorageとsessionStorageはドメインごとにstorageを保有し、各storageは互いの情報は共有しない。


# localStorageとsessionStorageの違い
localStorageはsafari以外は有効期間は存在しないが、sessionStorageは存在するのが特徴。
なお、chromeやその他のブラウザーもsafariと同様にlocalStorageの有効期限を制限する動きあり。

|   |localStorage|sessionStorage|
|---|---|---|
|有効期間の有無|なし<br>なお、safariは最終アクセスから7日間に制限されるという仕様変更|ブラウザー（またはタブ）が終了するとデータは削除<br>または、一定の時間がすぎるとデータは削除|

# chromeからstorageを見る方法
f12キーを押すと表示される「検証」画面の`Application`タブで見ることができる。
![スクリーンショット 2022-10-13 9.08.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2785890/22af1981-fd3e-fda8-704f-c1822a421c4d.png)

# localStorageとsessionStorageの使い方
### localStorage









##### データの保存
localStorageにデータを保存する方法はリテラル方法とメソッド方法の２つある。
以下はそれぞれの保存方法の使い方の例である。

```javascript:javascript
localStorage.age = '23' //リテラル方法
localStorage.setItem('age', '23') //メソッド方法
```
なお、localStorageのkeyとvalueは必ず文字列でなければならない。
そのため、オブジェクトをvalueにしたい場合、jsonを利用することで保存することができる。
```javascript:javascript
localStorage.user = JSON.stringify({name: "John"})
 
let user = JSON.parse( localStorage.user )
alert( user.name ) // John
```
```javascript:javascript
let arr = [1,2,3,4,5]
localStorage.setItem("data", JSON.stringify(arr))
 
let output = localStorage.getItem("data")
let arr = JSON.parse(output)
console.log(arr) // [1,2,3,4,5]
```







##### データの読み込み
localStorageにデータを保存する方法と同様にリテラル方法とメソッド方法の２つある。
以下はそれぞれの保存方法の使い方の例である。

```javascript:javascript
localStorage.age //リテラル方法
localStorage.getItem('age') //メソッド方法

localStorage.getItem() //引数がない場合、全体の値を返却
localStorage.length //localStorageに保存されている数を返却
localStorage.key(0) //〇番目に該当するkeyとvalueを返却
```









##### データの削除
```javascript:javascript
localStorage.removeItem('age') //localStorageの`age`というkeyをもつデータを削除
localStorage.clear() //localStorageの全てのデータを削除p
```




### sessionStorage
基本的な文法はlocalStorageと変わらない。
```javascript:javascript
sessionStorage.setItem("age", "24") //データの保存
 
sessionStorage.getItem("domain") //データの読み込み
 
sessionStorage.removeItem("domain") //指定したkeyをもつデータの削除
 
sessionStorage.clear() //sessionStorageの全てのデータを削除
```
【Git助っ人】.gitignoreに追加したのに、いつまで経っても出てくるアイツをgitの世から消し去る方法

`git`ってたまに難しい。毎日使っていれば`pull`だの`push`は既に親友同然、`status`あたりは頼れる兄貴感覚。しかしちょっとイレギュラーなことを行おうとした場合、急にやつはつっかかってきたりする。やめて欲しい。

今回はタイトルにもある通り、一度インデックスにあげてしまったファイルを、`.gitignore`に後から追加した場合に、なんか思った通りにいかない時の話。

# 事象

一度インデックスに挙げたり(要は`git add`済)、コミットしたファイル(`git commit`済み)を、あとから`.gitignore`に追加した時に、なかなか追跡対象から外れないことがある。

パスも間違っていないのになぜだーと叫ぶ私。
相も変わらずしれっと追跡対象にファイルを提示し続ける`git`。
仁義なき戦いとは、きっとこういうことを言うのだろう。知らないけれど[^1]。

[^1]: 最近部署内に関西の方が増えてきたので、ちょっと寄せてみている。知らんけどって、いい言葉ですね。知らんけど。

# 原因

`.gitignore`に追記した削除対象のファイルのキャッシュが、インデックスに残り続けているため。これは`.gitignore`がリポジトリーに対し、**これから追加されるファイルを**追跡対象からはずすように伝えるファイルであるため。

https://stackoverflow.com/questions/11249527/what-happens-to-gitignored-untracked-files-when-pulling-them-from-the-remote-re

従って、キャッシュがある=新規追加されたファイルとみなされない=追跡対象であるという判断がされてしまって、いつまで経っても追跡対象から外れてくれないことになる。

# 解決法

`.gitignore`に追記後、キャッシュを消す。

```git
git rm --cached <file-name>
git rm -r --cached . // ファイル内の全キャッシュを削除
```

https://qiita.com/fuwamaki/items/3ed021163e50beab7154

# 解決法2?

ちょっとリサーチしたら、こんなコマンドも出てきた。
まだ試してみていないが、こちらの方が追跡対象にする/しないを、柔軟に対応できそうな感じがする。

```git
git update-index --assume-unchanged  <filename>　//ファイルを追跡対象にする
git update-index --no-assume-unchanged  <filename>　//ファイルを追跡対象に戻す
```

https://stackoverflow.com/questions/9785792/git-track-ignore-delete-untrack/11209188#11209188

# 余談

`.gitignore`の他にも、`.git/info/exclude`下に記述する方法もあるそうで。ここに記述されたルールはコミットされない。よって、完全に自分にしか関係していないファイルはこちらの記述でもよさそう。例えば、他の人と絶対共有しなくていい個人的なメモだとポエムだとかは、こちらに記述して管理もありかもしれない。

```git
# .git/info/exclude　内での書き方（参照ページからそのまま拝借）

# ‘.project’と‘.classpath’は追跡対象外
.project
.classpath
```

ただ、他の人も設定を共有した方がいい場合（共通で使っているエディタ固有のファイルなど）は、`.gitignore`の方がよさそうだ。

http://kar-git.blogspot.com/2012/11/how-to-set-git-to-ignore-few-files-like.html
Java関連の設定

## Java文字コード設定
Windowsのシステム環境変数に以下を追加する。
※確かJenkinsのコンソール文字化け対策で実施しました。

```java
JAVA_TOOL_OPTIONS
-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8
```


## Tomcatのメモリ設定
Tomcatの conf/context.xml に以下を追加する。

```html
<Context>
   <!-- 省略 -->
   <Resources cacheMaxSize="51200" />
</Context>
```

## 新しいEclipseで古いmavenプロジェクトを開いた時のエラー対策

> Exception java.lang.ExceptionInInitializerError [in thread "Worker-42: ビルド"]

不可解なエラーで解決方法が全く見えない。
buildタグのpluginsタグに、maven-war-pluginの設定を追加すると解消されます。

```xml
    <build>
        <finalName>asboxZurichService</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <!--<version>3.6.1</version>-->
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <!-- ↓↓↓新しいEclipseで開く時は必要↓↓↓ -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.1</version>
            </plugin>
            <!-- ↑↑↑新しいEclipseで開く時は必要↑↑↑ -->
        </plugins>
    </build>
```

## IPv4を使うオプション

```
-Djava.net.preferIPv4Stack=true
```

## mavenでSpringBootを起動するコマンド

```
mvn spring-boot:run -Dspring-boot.run.profiles=dev,local
```
pytorchを使った線形回帰

# 初めに
pytorchは、自動微分で求まる傾きを使って誤差を最小化することで、ニューラルネットワークの重み(パラメタ)を最適化しているが、この動作を理解するために単純な例でやってみる。

今回は、以下のようなデータに対して、$y=ax+b$の$a$と$b$を求める。

```python
xi = np.array([10.0,  8.0, 13.0, 9.0 , 11.0, 14.0, 6.0 , 4.0, 12.0, 7.0, 5.0])
yi = np.array([8.04, 6.95, 7.58, 8.81, 8.33, 9.96, 7.24, 4.26, 10.84, 4.82, 5.68])
```

![download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884285/4bd78de8-ba49-99ef-640e-5994baad1c78.png)


# 最小二乗法を使った場合
答え合わせのため、sklearnを使って、傾きと切片を求めておく

```python:線形回帰
from sklearn import linear_model
clf = linear_model.LinearRegression()
clf.fit( xi.reshape(len(xi),1),yi )
print( f'傾き(a):{clf.coef_[0]:.5f} \n切片(b):{clf.intercept_:.5f}') 
```

```:実行結果
傾き(a):0.50009 
切片(b):3.00009
```

これを、pytorchで求められるかやってみる。

# pytorchをつかった線形回帰

まず、今回使う変数を作る
求めるパラメータは(a,b)。初期値は乱数で初期化する
```python
# 説明変数
xi = np.array([10.0,  8.0, 13.0, 9.0 , 11.0, 14.0, 6.0 , 4.0, 12.0, 7.0, 5.0])
# ラベル
yi = np.array([8.04, 6.95, 7.58, 8.81, 8.33, 9.96, 7.24, 4.26, 10.84, 4.82, 5.68])
a = np.random.rand()     # 傾き
b = np.random.rand()     # y切片

# pytorchで扱えるようにテンソルにする。
# 求めるパラメタ(A,B)は、後から微分計算するのでrequires_grad=Trueとする
Xi = torch.tensor( xi )  # 説明変数のテンソル
Yi = torch.tensor( yi )  # 目的変数
A = torch.tensor( a , requires_grad=True )
B = torch.tensor( b , requires_grad=True )
```

パラメタA,Bを使って、予測値:$Y=A*Xi+B$と、正解(教師データ):$Yi$との誤差(平均二乗誤差)を計算する。
```python
# 予測値を計算
Y = A*Xi + B

# 正解ラベルとの誤差を計算(差を二乗したものの平均)
loss = torch.sum((Y-Yi)**2) / len(Y-Yi) 

# pytorchの関数を使って、以下としても同じ
mseloss  = torch.nn.MSELoss()
loss = mseloss( Y, Yi )
```
これ(loss)を最小とするA,Bを求めればよいことになる。

具体的には、lossをA,Bの関数として、A,Bそれぞれで偏微分したうえで、Xiでの傾きを計算する。(これにより、A,Bを微小変化させた際のlossがどう変化するか(増えるのか/減るのか)がわかる。)

pytorchでは、出力値:lossのbackward()を呼ぶと、計算グラフを使った自動微分で傾きが計算され、結果がA,Bのgradプロパティに格納される。
あとは、optimizer.step()を実行すると、この傾きを使ってA/Bが更新される。
```python
optim = torch.optim.RMSprop([A,B], lr=0.001)

for i in range(6000):
    # A,Bの傾きがある場合はクリアしておく
    # (loss.backward()の傾き計算に、前の計算結果が影響してしまうので)
    if A.grad != None:
        A.grad.zero_()
    if B.grad != None:
        B.grad.zero_()

    Y = A*Xi + B

    # 誤差を計算(平均二乗誤差)    
    loss = torch.sum( (Y-Yi)**2 ) / len(Y-Yi)
    
    # 微分計算(A.grad、B.gradに傾きが設定される)
    loss.backward()

    # 計算された傾きを使って、A,Bを更新
    optim.step()

print( f'loss:{loss.detach().tolist():.5f}' )
print( f'A:{A.detach().tolist():.5f} \nB:{B.detach().tolist():.5f}' )
```


以下のコードでも同じ
```python
optim = torch.optim.RMSprop([A,B], lr=0.001)
mseloss  = torch.nn.MSELoss()

for i in range(6000):
    optim.zero_grad()
    Y = A*Xi + B
    loss = mseloss( Y, Yi )
    loss.backward()
    optim.step()

print( f'loss:{loss.detach().tolist():.5f}' )
print( f'A:{A.detach().tolist():.5f} \nB:{B.detach().tolist():.5f}' )
```

```:実行結果
loss:1.25118
A:0.49959 
B:2.99959
```

skleanを使って求めた係数(傾き:0.5、y切片:3)と近い値が求まっていることがわかる。


![download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884285/916ec617-8a2c-2da6-aa31-e22bd0d96f0c.png)
Vuejs3 <script setup> 構文 トップに戻るボタン

### templete

```
<template>
  <transition name="opacity">
    <button 
      v-show="buttonActive"
      @click="pageTop"
      class="fixed right-3 bottom-3 text-white bg-teal-500 w-20 h-20 rounded-full"
    >
      トップに戻る
    </button>
  </transition>
</template>
```
:::note info
ボタンのデザインはtailwind CSS、またtransitionでアニメーションを使用していますが、お好みで変更して下さい。
:::
	
### script
```
<script setup>
import { onMounted, ref } from 'vue'

const buttonActive = ref(false)

let scroll = 0

const pageTop = () => {
  window.scrollTo({
      top: 0,
      behavior: 'smooth'
  })
}

const scrollWindow = () => {
  const top = 100 //topから100pxスクロールしたらボタン登場
  scroll = window.scrollY //垂直方向

  if (top <= scroll) {
    buttonActive.value = true
  } else {
    buttonActive.value = false
  }
}

onMounted(() => {
  window.addEventListener('scroll', scrollWindow)
})
</script>
```

### アニメーション
動きが欲しい人用
```
<style scoped>
.opacity-enter{
  opacity: 0;
}
.opacity-enter-active{
  transition: opacity 1s;
}
.opacity-enter-to{
  opacity: 1;
}
.opacity-leave{
  opacity: 1;
}
.opacity-leave-active{
  transition: opacity 1s;
}
.opacity-leave-to{
  opacity: 0;
}
</style>
```

### 完成イメージ
![](https://storage.googleapis.com/zenn-user-upload/6ef68f5c6449-20221013.gif)

### 参考サイト
https://qiita.com/TK-C/items/42b25ff4ec56528ad870