OmniAICreator/Qiita-1.07M huggingface dataset:
【祝M1対応】Hasura×Docker×M1 超入門

# HasuraをM1Macで動かす

HasuraはGraphQLを手軽行うためのGraphQLエンジンです。
Hausraを使えば簡単にGraphQLを体験することができます。

最近までHasuraの公式DockerイメージはM1非対応でしたが、
`2021/12/10`の時点で**ベータ版ではありますが、M1対応の公式イメージが発表されました。**

詳しくは[こちら](https://github.com/hasura/graphql-engine/releases/tag/v2.1.0-beta.3)にあります。

# Hasuraには２種類ある（知っている人は飛ばしてね）

Hasuraを試したいと思ったらその方法は２つあります。

1. **Hasura Cloud を使う**
2. **Docker Hasura を使う**

## Hasura Cloud とは
Hasura Cloud とは名前の通りクラウド上でHasuraを扱うためのもので、
Firebase的なものをイメージしてもらえれば良いかと思います。

[こちら](https://hasura.io/cloud/)のURLからアカウントを新規作成し
プロジェクトをポチポチしながら作っていくと簡単に作成できます。

お手軽ですが、リクエスト行える回数に上限があり課金しないと無制限には使えません。
ただ、セキュリティのための追加機能とDBも併せて用意してくれると言う特典があります。
**お金に余裕があるか、勉強のために使ってみたいだけの人におすすめです。**

## Hasura Docker とは

前述したHasura Cloud は手軽さの反面、課金が必要になりますが
こちらの「Hasura Docker」であれば無料で使うことができます。

こちらはDBも自分で用意する必要がありますが、
**無料ですし導入方法も簡単なので個人的にはこっちの方がおすすめです。**

# Hasura Docker の始め方

先に書いた通り、HasuraはDockerでも始められるように公式イメージを配布してくれています。
以下のように`docker-compose.yml`を用意してみましょう。


``` docker-compose.yml
version: '3.6'
services:
  postgres:
    image: postgres:12
    restart: always
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: postgrespassword
  graphql-engine:
    image: hasura/graphql-engine:v2.1.0-beta.3.cli-migrations-v2.arm64
    ports:
      - '8080:8080'
    depends_on:
      - 'postgres'
    restart: always
    environment:
      ## postgres database to store Hasura metadata
      HASURA_GRAPHQL_METADATA_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/postgres
      ## this env var can be used to add the above postgres database to Hasura as a data source. this can be removed/updated based on your needs
      HASURA_GRAPHQL_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/postgres
      ## enable the console served by server
      HASURA_GRAPHQL_ENABLE_CONSOLE: 'true' # set to "false" to disable console
      ## enable debugging mode. It is recommended to disable this in production
      HASURA_GRAPHQL_DEV_MODE: 'true'
      HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log
      ## uncomment next line to set an admin secret
      # HASURA_GRAPHQL_ADMIN_SECRET: myadminsecretkey
volumes:
  db_data:

```
こちらの`docker-compose.yml`は[Hasura公式](https://hasura.io/docs/latest/graphql/core/getting-started/docker-simple.html)で公開されている`docker-compose.yml`をM1用に少しいじったものになります。

こちらを作成し`docker-compose up`をすれば正しく起動するはずです。
[localhost:8080](http://localhost:8080)にアクセスしてみればHasuraのコンソールが見えると思います。
Laravelでの画像取得処理いろいろ

# 背景
Laravelでの画像取得処理を実装したときの個人的メモです。

## 画像の保存方法
1. 画面などからアップした画像を保存する
2. インターネット上に保存されている画像を保存する

## 画像の保存先
以下２つが考えられるが、2.の方がメジャーなようなのでそちらで実装する。

1. 画像ファイルをDBにそのままバイナリデータとして保存する
2. 画像ファイルはサーバ上に保存しておきDBにはファイル格納パスだけを保存する
 
[データベースに画像を保存するのはありでしょうか？](https://teratail.com/questions/81233)

## 1. 画面からアップした画像を保存する(アバター画像をアップロードする)
```html:upload.blade.php

<form method="post" action="{{route('profile.update', $user)}}" enctype="multipart/form-data">
    @csrf
    @method('put')

    <div class="form-group">
        <label for="avatar">アバター</label>
        <!-- ↓登録済みファイルの表示。 -->
        <img src="{{asset('storage/avatar/'.($user->avatar))}}"
        class="d-block rounded-circle mb-3" style="height:100px;width:100px;">
        <div>
            <!-- ↓ファイルアップロード用UI。バックエンドではこれをオブジェクトとして利用可能 -->
            <input id="avatar" type="file" name="avatar">
        </div>
    </div>
```

```php:profilecontoroller.php
    public function update(User $user, Request $request){

    // ...中略

    // リクエストオブジェクトのfileメソッドでname="avatar"を取得し、アップロード時に指定したオリジナルの名称を取得
    $name=request()->file('avatar')->getClientOriginalName();
    // リクエストオブジェクトのfileメソッドでname="avatar"を取得し、storeAsメソッドで名前を付けて画像ファイルをサーバに登録。引数はパス、ファイル名。
    request()->file( 'avatar')->storeAs('public/avatar', $name);
    $inputs['avatar'] = $name;
    // 保存したファイルパスをDBに更新
    $user->update($inputs);

```

## 2. インターネット上に保存されている画像を保存する
画像ファイルの保存先URLがDBに格納されており、それを使って画像ファイルを取得・保存し、DBにパスを更新する。という場合。

```php:profilecontoroller.php
use Illuminate\Support\Facades\Storage;

    // 中略...

    //////////////// 
    // 画像データ取得
    //////////////// 
    // $image = Storage::get($image_url); //これはエラーになる。Laravelが管理する範囲内しか取得できない。Laravel独自の関数は無いようなのでphpのfile_get_contentsを使う。
    $image = file_get_contents($image_url);
    //////////////// 
    // 画像データ保存
    //////////////// 
    // 画像ファイルパスを作成。$image_idは一意の名前が格納されている。
    $image_path = 'Images/' . $image_id . '.jpeg';
    // Storage Facadeを使い、ドライバを指定してファイルを保存。ドライバの指定なしだとデフォルトのLOCALドライバが使われる。ストレージドライバはconfig/filesystems.phpの設定による。
    Storage::disk('public')->put($image_path , $image);

    // DBカラムに画像ファイルパスを更新。$userはuserモデル。
    $user->image_file_path = $image_path;
    $user->save();

```

Laravelには大抵の処理にはヘルパ関数があるので
phpオリジナル関数の`file_get_contents`をつかわないとできないところが
個人的に引っかかりました。
何かベストプラクティスあれば教えて頂けると幸いです。

## 参考
[Laravel 8.x ファイルストレージ](https://readouble.com/laravel/8.x/ja/filesystem.html)
【手順】MacにPythonインストール(pyenv経由)

1.Homebrewからpyenvをインストール
-
Homebrewは下記記事の前半に手順が書かれていますの参考にどうぞ。
[【手順】Macの開発環境構築](https://qiita.com/yuthi01020104/items/321c339b3d6f9c0f6538)
ターミナルにて下記コマンドを実行し、「pyenv」をインストールします。

```terminal:ターミナル
brew install pyenv
```

インストールが完了したら下記コマンドを入力して```pyenv X.X.X```と表示されればインストール完了。

```terminal:ターミナル
brew install pyenv
```

2.pyenvのパス設定
-
Macには元々Pythonがインストールされているので参照するパスを変更する必要があります。
>近々、Macへの標準インストールは無くなるとか...

下記コマンドにて使用しているシェルによってコマンドが<font color="Red">分岐</font>します。シェルについては**[こちら](https://wa3.i-3-i.info/word11219.html)**から

```terminal:ターミナル
echo $SHELL
```
**実行結果が ```~/bin/bash```の場合のコマンド**
上から順にコマンドをコピぺして実行してください

```terminal:ターミナル
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
```

```terminal:ターミナル
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
```

```terminal:ターミナル
echo 'eval "$(pyenv init --path)"' >> ~/.bash_profile
```

```terminal:ターミナル
source ~/.bash_profile
```
**実行結果が ```~/bin/zsh```の場合のコマンド**
上から順にコマンドをコピぺして実行してください

```terminal:ターミナル
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
```

```terminal:ターミナル
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
```

```terminal:ターミナル
echo 'eval "$(pyenv init --path)"' >> ~/.zshrc
```

```terminal:ターミナル
source ~/.zshrc
```

3.Pythonのインストール
-
`list`コマンドでインストールできるPythonのバージョンを確認。
上に遡って`X.X.X`のバージョンだけ記載されたところがPythonのバージョンです(多分)

```terminal:ターミナル
pyenv install --list
```

`install`コマンドで任意のバージョンをインストールします

```terminal:ターミナル
pyenv install X.X.X
```

`versions`コマンドでバージョンを確認し、インストールされていることを確認。

```terminal:ターミナル
pyenv versions
```

4.使用するPythonのバージョンを指定
-

```terminal:ターミナル
pyenv global X.X.X
```

下記コマンドでPythonのバージョンを確認してインストールしたバージョンと一致しているか突合して、問題なければPythonのインストール完了です。

```terminal:ターミナル
Python -V
```
はじめに

![lamprima_pairs.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2519177/727dcfa3-f32c-b0b9-ae47-76b533db3882.jpeg)

はじめまして。maruquiです。
現在沖縄県の宮古島市にて、HTMLコーダーとして勤務をしております。
HTMLコーダーとしての実務経験は1年程度で、まだまだ修行が多い日々です。

この記事では、なぜQiitaに投稿しようと思ったのかや、Qiitaでどのようなことを投稿していく予定なのかをまとめています。
今回は特に有益な情報を発信するようなことはないので、その点ご了承ください。

## Qiita に投稿しようと思った経緯

宮古島に移住することに決まったときに、専用のブログを用意していました。
宮古島の観光スポットやグルメなどをまとめつつ、コーダーとしての毎日を記録していくものでした。

一週間かかさずに投稿していたのですが、7月ごろから更新が途絶えてしまいました。会社での業務が単調になってしまったことが主な原因です。

その頃の私が行なっていた業務は、以下の通りです。

* コラムの作成
* テキストの更新
* ちょっとしたコードの編集
* ときたまコーディング業務

そんな中、ふと思ったことがあります。

「いつも同じすぎておもんないなw」

勤務して3ヶ月、早くも行なっている業務のネタ切れを感じました。

「こんな実装を行いました！」とか「このサイトみたいなイカしたことをできるようになりました！」とかをイメージしていたのですが、そのようなことを行える兆しがありませんでした。

ちなみに、今も行なっていることの変化はあまり起きていません。

唯一増えたことは、BEM表記で書いたものをコーディングを保存するシステムに追加していくくらいです。根本的に新しいシステムを開発するだとか、今風のおサレな実装をどんどんやっていくみたいなのはありません。

また、宮古島の観光スポットについても紹介はできますが、正直生活に慣れてしまったので観光する意欲も少なくなってしまいました。

余談ですが宮古島の海は、天候の条件さえよければ加工なしでもこのような写真が撮れます。

![IMG_4450.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2519177/8bf3d324-684f-0a0b-b906-c36e8cc3e9b8.jpeg)

海は本当に綺麗だし自然も豊かなのは間違いありませんが、見慣れてしまうとわざわざ紹介しようとも思わなくなってしまいました。

大阪でいうところのユニバ、関東でいうところのディズニーランド、京都でいうところの伏見稲荷大社、栃木でいうところの日光東照宮、鳥取でいうところの鳥取砂丘みたいなものです。

こうした背景から、宮古島＋コーダーのブログを続ける理由がなくなってしまいました。

とは言うものの、日頃どういう学習をしているのかなどを発信したい気持ちは残っています。自分の成長記録にもなるし、興味をもってくださる方が出てくるかもしれないと思っているからです。

単に承認欲求を満たすためだけに記事を書いていくつもりはありませんが、この業界をよりよくしていくためには情報共有が大事だと考えています。

なので、自分が行なっていることなどは引き続き発信していこうと思いました。

## Qiitaにどのようなことを発信していくか

明確には定めておりませんが、以下の内容を発信していこうとは考えております。

* 学習の記録
* 転職に関すること
* 自分がつまづいた箇所
* Udemyで学習した後の感想
* 技術系の書籍を読んだ後の感想

この他にも、Qiitaに投稿できそうな内容があれば、随時投稿していこうと思います。

あくまでも学習や技術に関することを発信していくものなので、宮古島に関することや自分の趣味など、コンセプトから大きく外れてしまうようなことは発信しないよう気をつけます。

※ 趣味や宮古島についての質問は大歓迎なので、もしあれば仰ってください。

## Qiitaの更新頻度や文字数

こちらも明確には定めません。今までの私の傾向から、週に○記事みたいに定めると、苦しくなって続かなくなったからです。

1ヶ月に1記事投稿できればいいな〜とは思っていますが、それも絶対行うものとは決めないようにします。気まぐれにすすめていきます。

また、文字数についても特に定めません。今はライターではないので、そこを決めてしまったらますます更新しなくなるからです。

読みやすいような配慮はしていきますが、文字数についても特に定めるつもりはありません。

## 今自分が興味ある言語について

この記事を投稿した2022年1月30日現在、自分が興味ある言語を記録として残しておきます。いつか見返したときにおもしろそうだからです。

現在興味がある、もしくはより学習してみたいことは下記の通りです。

* HTMLのタグの種類をもっと知りたい
* CSSのプロパティをもっと知りたい
* Sass（SCSS）のより良い記述方法をもっと知りたい
* Sassの関数や＠系をもっとうまく操れるようにしたい
* JavaScriptの理解をもっと深めたい
* jQueryの理解をもっと深めたい
* Vueの学習を進めたい
* Reactの学習を進めたい
* PHPの理解をもっと深めたい
* Laravelの学習を進めたい
* CakePHPの学習を進めたい
* CodeIgniterの学習を進めたい

めちゃくちゃ多いし、書いてみて「大丈夫かな自分。無理してへんかな。」と思いましたが、興味があることはこんな感じです。

職場では、VueやReactを触ったことは一度もありませんが、CakePHPやCodeIgniterは一度か二度、ソースコードをみたことはありました。

次の1年後ではどのように感じているのか、どこまで成長できているのかが楽しみです。とりあえず内地に戻れたら書籍を漁りに行くことにします。宮古島にもいくつか書店はありますが、技術系の本は1冊も置いてないので（笑）

# まとめ

今回はなぜQiitaに投稿しようと思ったのかや、Qiitaでどのようなことを発信していくのかなどをまとめました。

今後の私が、どのようなキャリアを積んでいくのかは分かりませんが、見返した時に笑っている自分の姿をイメージできるので、未来の自分への贈り物として記事をまとめました。

また、誰かの目に止まる可能性もあるかもしれません。そのような時に、自分の人となりが少しでも伝わればいいなと思っています。

というわけで、最後までご覧いただきありがとうございました。

また気まぐれに更新していきます。
Phoenixの学習時にはデータベースにSQLite3を使おう

# 経緯
学習中に先人たちのブログやQiitaの記事のサンプルコードを試してみたり、
ライブラリを試してみたりする度に、新たにPhoenixのプロジェクトを作り、
その都度PostgreSQLのDBも作ってたら、結構な数のDBができてしまって。。

それに試したコードの大半がSQLを直接書く必要もなかったんで、
ポスグレである必要ないなと。。

~~使いまわせばいいんだけなんですけどね~~

# ということで
候補に上がったのが、SQLite3。あんまりゴリゴリ使ったことないけど。定番なのは知ってる。

## 前提
Elixirだけ入ってればいいです。

```
$ elixir -v
Erlang/OTP 24 [erts-12.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit] [dtrace]

Elixir 1.13.1 (compiled with Erlang/OTP 24)
```

## 設定方法は？

`mix phx.new`時にオプション指定するだけ。

```
$ mix phx.new my_app --database sqlite3
```

昔からサポートされてはいたけど、
古いバージョンだと自分でライブリ追加したり、しなきゃならなかったみたいですが、
嬉しいことにPhoenix1.6.xではオプションで指定するだけで使える。
それならば使わない手はないですね。

これだけで終わってしまっては記事としては寂しいので
一応画面立ち上げまでつづけてやっていきます。

↓途中で聞かれるこれは"Y"で。

```
Fetch and install dependencies? [Yn] Y
```

終了したら、案内に従って以下を実行

```
$ cd my_app
$ mix ecto.create
```
ectoが終了したら、`my_app_dev.db`というファイルが出来上がってる。
![スクリーンショット 2022-01-28 22.48.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2245296/67755ac6-0d8a-516f-a916-e51560b49f3e.png)

シンプルな画面作って動作を確認してみましょう。

```
mix phx.gen.html People User users name:string age:integer
```

`lib/my_app_web/router.ex`に一行追加

```elixir
  scope "/", MyAppWeb do
    pipe_through :browser

    get "/", PageController, :index
    resources "/users", UserController # この行を追加
    
  end
```
migrate実行

```
$ mix ecto.migrate
```

終了したら、ブラウザでアクセス

http://127.0.0.1:4000/users

画面が表示されていますが、データがありません。
![スクリーンショット 2022-01-28 23.28.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2245296/caac6fe1-96e8-2e7b-3b7a-689231cbeddc.png)

適当に追加してみます。
![スクリーンショット 2022-01-28 23.31.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2245296/85dbde76-3989-49ce-4acf-758b8e0b4e4a.png)

一覧を再表示。追加したデータが表示されてます。
![スクリーンショット 2022-01-28 23.31.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2245296/3527785c-6891-23b3-dca8-0ea2556638fd.png)

## 再度フォルダを見てみると
この時点で、`my_app_dev.db`、`my_app_dev.db-shm`、`my_app_dev.db-wal`の
三つのファイルが出来上がっている。サイズも軽量。
![スクリーンショット 2022-01-28 23.49.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2245296/f48e889d-f340-d5bb-58a2-b368a042838e.png)

- db-shmファイル： トランザクション開始から終了までの更新内容が書き込まれる
- db-walファイル： コミットした時に更新内容が書き込まれる
とのこと。
herokuのProcfile

# はじめに
 herokuをwindowsからProcfileをpushするときのトラブルシュート
# 現象
 間違えてProcfileではなく、procfileとして投入してしまったのでなかなか認識してもらえなかった。
# 理由
 windows上ではProcfileもprocfileも同じなので、gitに通知できなかったようである。
# 解決法
 procfileaとかの別名にして、いったんコミットし、その後にProcfileをcommitすると正式にgitに通知可能となり、無事にherokuが認識してくれた。
# ちなみに
 - Procfileはgitの直下に作成します。
 - 最初はweb以外は起動していないので、 heroku ps:scale worker=1 -a アプリ　とかを実施して起動します。
 - logを確認するのは heroku logs -d worker -a アプリ になります。
 - heroku 無償で遊べるのでいいですねえ・・
[Solved] openethereum (parity) install failed

Since Parity has been replaced by OpeneThereum, I tried to install OpeneThereum, but got an error, so I wrote down a workaround.

I referred to the following page.
[Latest Rust version compiles main branch went error #547](https://github.com/openethereum/openethereum/issues/547)

And I'm using WSL2 and Ubuntu18.04.

```bash:command
curl https://sh.rustup.rs -sSf | sh -s -- -y
sudo apt install clang cmake
source ~/.cargo/env  # you may add to .bashrc
rustup override set 1.51.0 # IMPORTANT!!
git clone https://github.com/openethereum/openethereum
cd openethereum
cargo clean
cargo build --release --features final
```
Pythonのプログラム名をhttp.pyにしてはいけない

```python:http.py
import urllib.request
req = urllib.request.Request("https://hoge")
```
このプログラムを実行するとエラーになります。

```linux:
$ python3 http.py
Traceback (most recent call last):
  File "/home/norioy01/http.py", line 1, in <module>
    import urllib.request
  File "/usr/lib/python3.9/urllib/request.py", line 88, in <module>
    import http.client
  File "/home/norioy01/http.py", line 3, in <module>
    req = urllib.request.Request("https://hoge")
AttributeError: module 'urllib' has no attribute 'request'
$ 
```
エラーの原因はimportがループする為です。
1. http.pyの**import urllib.request**でurllib/request.pyが実行。
2. urllib/request.pyの**import http.client**でhttp.pyが実行。


```python:urllib/request.py
#・・・省略・・・
import http.client
#・・・省略・・・
```

プログラム名を変更すれば正常に動きます。



```linux:
$ mv http.py hoge.py
$ 
$ python3 hoge.py
$ 
```
Julia: PDF を読む

こちらのサンプルをプログラムとして実行してみました。
[sambitdash/PDFIO.jl](https://github.com/sambitdash/PDFIO.jl)

```jl:pdf_to_text.jl
#! /usr/bin/julia
#
#	pdf_to_text.jl
#
#						Jan/30/2022
# --------------------------------------------------------------------
using PDFIO
# --------------------------------------------------------------------
function getPDFText(src, out)
	doc = pdDocOpen(src)
	docinfo = pdDocGetInfo(doc) 
#
	open(out, "w") do io
		npage = pdDocGetPageCount(doc)
#
		for it=1:npage
			page = pdDocGetPage(doc, it)
			pdPageExtractText(io, page)
		end
	end
#
	pdDocClose(doc)
	return docinfo
end

# --------------------------------------------------------------------
println(stderr,"*** 開始 ***")
#
src = ARGS[1]
out = ARGS[2]
println(src) 
println(out) 
#
getPDFText(src, out)
#
println(stderr,"*** 終了 ***")
# --------------------------------------------------------------------
```

実行結果

```text
$ ./pdf_to_text.jl cities.pdf out01.txt
*** 開始 ***
cities.pdf
out01.txt
*** 終了 ***
```

入力データ
![cities_jan30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/78d7d606-5eda-27eb-9470-eb532140f085.png)

出力結果

```text
$ head out01.txt 
     t2381              名古屋             72534             2002-5-14

     t2382              豊橋               63473             2002-8-12

     t2383              岡崎               57982             2002-9-01

     t2384              一宮               46329             2002-10-29

     t2385              蒲郡               31765             2002-7-14
```

パッケージのインストール方法

```text
julia> using Pkg
julia> Pkg.add("PDFIO")
```
Databricksクラスター

[Clusters \| Databricks on AWS](https://docs.databricks.com/clusters/index.html) [2022/1/21時点]の翻訳です。

> [Databricksクイックスタートガイド](https://qiita.com/taka_yayoi/items/125231c126a602693610)のコンテンツです。

:::note warn
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

Databricksクラスターは、プロダクションのETLパイプライン、ストリーミング分析、アドホック分析、機械学習のようなデータエンジニアリング、データサイエンス、データ分析ワークロードを実行するための計算リソース、設定のセットです。

ノートブックの一連のコマンドや自動化されたジョブとしてこれらのワークロードを実行します。Databricksは*all-purposeクラスター*と*jobクラスター*を区別します。インタラクティブなノートブックを用いて、コラボレーションをつうて自データ分析を行う際にはall-purposeクラスターを使用します。高速かつ堅牢な自動化ジョブを実行するためにjobクラスターを使用します。

- UI、CLI、REST APIを用いて*all-purpose*クラスターを作成することができます。手動でall-purposeクラスターを停止、再起動することができます。複数のユーザーが、コラボレーティブかつインタラクティブな分析を行うためにこれらのクラスターを使用することができます。
- *新規jobクラスター*でジョブを実行する際、Databricksのジョブスケジューラーが*jobクラスター*を作成し、ジョブが完了するとクラスターを停止します。*jobクラスターを再起動することはできません。*

このセクションでは、UIを用いてクラスターをどのように操作するのかを説明します。他の方法については、[Clusters CLI](https://docs.databricks.com/dev-tools/cli/clusters-cli.html)、[Clusters API 2\.0](https://docs.databricks.com/dev-tools/api/latest/clusters.html)を参照ください。

このセクションでは、jobクラスターよりもall-purposeクラスターにフォーカスしますが、説明する設定、管理ツールの多くは両方のクラスタータイプに適用されます。jobクラスターの作成方法の詳細については、[ジョブ](https://qiita.com/taka_yayoi/items/b3275a1983c51a8bbe1a)を参照ください。

> **重要！**
Databricksは、過去30日以内に停止された最大70台のall-purposeクラスターの設定情報を維持し、ジョブスケジューラーによって停止された最大30台のjobクラスターの情報を保持します。[停止](https://qiita.com/taka_yayoi/items/991aae376c089df58504#%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%83%BC%E3%81%AE%E5%81%9C%E6%AD%A2)後30日を経過してもall-purposeクラスターの設定を維持したい場合には、管理者はクラスターリストにクラスターを[ピン留め](https://qiita.com/taka_yayoi/items/991aae376c089df58504#%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%83%BC%E3%81%AE%E3%83%94%E3%83%B3%E7%95%99%E3%82%81)することができます。

- [Cluster basics](https://docs.databricks.com/clusters/basics.html)
- [Databricksにおけるクラスター作成](https://qiita.com/taka_yayoi/items/d36a469a1e0c0cebaf1b)
- [Databricksにおけるクラスター管理](https://qiita.com/taka_yayoi/items/991aae376c089df58504)
- [Databricksクラスターの設定](https://qiita.com/taka_yayoi/items/8d951b660cd87c6c5f18)
- [Databricksクラスター設定のベストプラクティス](https://qiita.com/taka_yayoi/items/ef3dc37143e7b77b50ad)
- [Task preemption](https://docs.databricks.com/clusters/preemption.html)
- [Customize containers with Databricks Container Services](https://docs.databricks.com/clusters/custom-containers.html)
- [Cluster node initialization scripts](https://docs.databricks.com/clusters/init-scripts.html)
- [GPU\-enabled clusters](https://docs.databricks.com/clusters/gpu.html)
- [Databricksのシングルノードクラスター](https://qiita.com/taka_yayoi/items/6e7c6cc14a5017ef6d15)
- [DatabricksのPools](https://qiita.com/taka_yayoi/items/919acd7ef9decf0f61e6)
- [Web terminal](https://docs.databricks.com/clusters/web-terminal.html)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
RDP Wrapper Library でログイン画面が表示されないとき

Windows10 ProしかできないリモートデスクトップをHomeでもできるようにするアプリの１つに[RDP Wrapper Library](https://github.com/stascorp/rdpwrap)がある。

# 問題
[ここ](https://m-suta.com/bibouroku-etc-rdpwrap/#toc4) を参考にインストールしたが、[このissue](https://github.com/stascorp/rdpwrap/issues/1654)のようにログイン画面が表示されなかった。

# 解決方法
issueにも記載されているように、[ここ](https://support.microsoft.com/ja-jp/windows/windows-%E3%81%A7%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%81%AE%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC-%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%81%BE%E3%81%9F%E3%81%AF%E7%AE%A1%E7%90%86%E8%80%85%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B-20de74e0-ac7f-3502-a866-32915af2a34d#WindowsVersion=Windows_10)を参考にMicrosoftアカウントをローカルアカウントに変更すればいい。
（ただし、Microsoftアカウントから変更することで、他のPCとの連携が切れたりする可能性があるので注意）

## 補足
ちなみに、動作チェックとしてRDPCheck.exeを実行して、ログインを行っても「アクセスが拒否されました。」と表示されるが、他のPCからログインしてみると正常に利用できる。
【PostgresSQL】条件分岐を高パフォーマンスで行う

# 目的
SQLで条件分岐を行うには、WHEREやUNIONを使った方法の他にCASEを使った方法もある。
UNIONなども理解しやすく、使いたくなるが、CASEを使った方が基本的にパフォーマンスが高いようなので、実際に本当に違うのか試してみることにした。

# 環境
PostgreSQL 14.1 (Ubuntu 14.1-1.pgdg18.04+1) on x86_64-pc-linux-gnu

# UNIONを条件分岐で行わない
絶対にダメというわけではないが、基本的に下記のようにUNIONで条件分岐は行うべきではないようだ。
なぜならテーブルスキャンが二回行われてしまうため。

```bash
select is_adult = false
where age < 20
union all
select is_adult = true
where age => 20
```

- UNIONはわかりやすくて使いたくなるが、条件分岐用に作られたものではなく、パフォーマンス的によくない
- 長い文になって、ミスも増えるし、読みづらい
- 内部的に複数のSELECTを実行することになるため、I/Oが増える

# WHERE内で条件分岐を行わない
WHEREではなく、SELECT内で条件分岐をしたほうが速度は確実に早い

# WHERE+UNIONを使って条件分岐をする

```bash
explain 
select *, '50以上' as test
from basketball_team where profile_id >= 50
union
select *, '50以下' as test
from basketball_team where profile_id < 50 ;

                                                    QUERY PLAN
------------------------------------------------------------------------------------------------------------------
# レコードをグルーピングしている
 HashAggregate  (cost=2.30..2.36 rows=6 width=84)
   Group Key: basketball_team.member_id, basketball_team."position", basketball_team.profile_id, ('50以上'::text)
   ->  Append  (cost=0.00..2.24 rows=6 width=84)
         # 一度目のbasketball_teamテーブルのフルスキャン
         ->  Seq Scan on basketball_team  (cost=0.00..1.07 rows=3 width=51)
               Filter: (profile_id >= 50)
         # 二度目のbasketball_teamテーブルのフルスキャン
         ->  Seq Scan on basketball_team basketball_team_1  (cost=0.00..1.07 rows=3 width=51)
               Filter: (profile_id < 50)
(7 rows)

 member_id |  position  | profile_id |  test
-----------+------------+------------+--------
         4 | center     |          4 | 50以下
         3 | guard      |          3 | 50以下
         2 | foward     |          2 | 50以下
         1 | center     |          1 | 50以下
         5 | foward     |       1000 | 50以上
         6 | center     |        100 | 50以上
```

### HashAggregateとは
> レコードをグルーピングするのに一時的なハッシュテーブルを使います。 HashAggregate処理では、データセットは事前にソートされている必要はありませんが、 中間結果(パイプライン化されていないもの)をマテリアライズするために非常に多くのメモリを必要とします。出力は、 一定のルールに沿って並べられているわけではないものになります。
参考: [こちら](https://use-the-index-luke.com/ja/sql/explain-plan/postgresql/operations)

# SELECTでCASEを使って条件分岐をする
```bash
explain 
select *,
case when profile_id >= 50
     then '50以上'
     when profile_id < 50
     then '50以下'
     else null
end as test
from basketball_team;

                           QUERY PLAN
----------------------------------------------------------------
 Seq Scan on basketball_team  (cost=0.00..1.09 rows=6 width=51)
(1 row)

 member_id |  position  | profile_id |  test
-----------+------------+------------+--------
         1 | center     |          1 | 50以下
         2 | foward     |          2 | 50以下
         3 | guard      |          3 | 50以下
         4 | center     |          4 | 50以下
         5 | foward     |       1000 | 50以上
         6 | center     |        100 | 50以上
```

# 結果
```bash
# WHERE + UNION
Execution Time: 0.199 ms
# SELECT + CASE
Execution Time: 0.032 ms
```

８倍以上実行速度に差が出た。
gitブランチとチェックアウトをまとめて行う方法

## はじめに
こちら自分用のメモであるためとても雑な記事です。

## メモ
```.zsh
$ git checkout -b 〇〇(ブランチ名)
```
ブランチの作成とチェックアウトをまとめて行うことができる。

## 最後に
時間ができた頃にブランチ周りについてまとめてみようと思います。
とても短い記事でした。ありがとうございました。
2022/1/30主にITとかセキュリティの記事

Linuxに深刻な脆弱性　ユーザーのセキュリティは12年も守られていなかった(1/27)
https://jp.sputniknews.com/20220127/linux12-10044673.html

セキュリティーソフト相次ぐトラブル　「McAfee」「ウイルスバスター」に脆弱性(1/27)
https://news.infoseek.co.jp/topics/jcasttrend_20222429813/

「Microsoft Excel」のXLLアドインを用いるフィッシング攻撃が急増(1/28)
https://japan.zdnet.com/article/35182738/

ランサムウェアやクラウドのセキュリティは2022年もCISOの課題上位--マイクロソフト(1/28)
https://japan.zdnet.com/article/35182754/

Androidマルウェアに注意、不正送金後に工場出荷時の状態へリセット(1/26)
https://news.mynavi.jp/techplus/article/20220126-2257482/

QNAP、NASを狙う新しいランサムウェア「DeadBolt」に注意喚起(1/27)
https://pc.watch.impress.co.jp/docs/news/1383754.html

Microsoft、「Windows 11」次期アップデートでAndroidアプリ利用可能に - ITmedia NEWS(1/27)
https://newstopics.jp/url/19205610

有田市がホームページに個人情報(1/27)
https://www.tv-wakayama.co.jp/news/detail.php?id=67700

「QUIC」とは? - いまさら聞けないスマートフォン用語(1/28)
https://news.infoseek.co.jp/article/mynavi_2360199/?tpgnr=it

Androidマルウェア「BRATA」が凶暴化、不正送金後にファクトリーリセットして証拠隠滅(1/28)
https://japan.cnet.com/article/35182772/

「MacはもともとWindowsだし」にならなかった理由(1/27)
https://www.itmedia.co.jp/news/spv/2201/27/news189.html

ブロックチェーンを活用することでサプライチェーンの問題を解決する(1/28)
https://www.dhbr.net/articles/-/8335

Wear OSの「タイル」の開発がより簡易に(1/28)
https://k-tai.watch.impress.co.jp/docs/news/1384292.html

欧米には3～5年遅れ、国内金融機関のデジタルバンキングを阻む壁の乗り越え方(1/28)
https://www.sbbit.jp/article/fj/79353?ref=rss

日本狙う中露のサイバー攻撃集団　急速な技術進展、増す脅威(1/28)
https://www.sankei.com/article/20220128-4YOUWT2VS5IHXHWDBRMSBCGU2E/

ビットコインが抱えるプライバシー問題：タップルートは何を変える？(1/28)
https://m.finance.yahoo.co.jp/news/detail/20220128-00157556-coindesk-bus_all

ブレイクアウト時間が短縮し、痕跡も残さぬ攻撃から守れ
https://special.nikkeibp.co.jp/atclh/ONB/22/crowdstrike0128/

個人データへの意識向上訴え ネット活動家(1/28)
https://www.swissinfo.ch/jpn/multimedia/%E5%80%8B%E4%BA%BA%E3%83%87%E3%83%BC%E3%82%BF%E3%81%B8%E3%81%AE%E6%84%8F%E8%AD%98%E5%90%91%E4%B8%8A%E8%A8%B4%E3%81%88-%E3%83%8D%E3%83%83%E3%83%88%E6%B4%BB%E5%8B%95%E5%AE%B6/47286902?utm_campaign=swi-rss&utm_source=multiple&utm_medium=rss&utm_content=o

京大のスパコンでファイル約77TB分が消失、実行中のスクリプト更新で誤動作 | 日経クロステック（xTECH）(1/28)
https://xtech.nikkei.com/atcl/nxt/column/18/01157/012700053/

Googleが密かに「PCゲーム市場」を狙っている証拠が発見される(1/27)
https://www.appbank.net/2022/01/27/technology/2186101.php

大手通信事業者かたる架空請求ショートメール　北九州市若松区内で複数確認(1/27)
https://www.nishinippon.co.jp/sp/item/n/868172/

自治体証明書のシステム障害 ハードウェア故障が原因 総務相(1/28)
https://www3.nhk.or.jp/news/html/20220128/k10013454181000.html

メタバースの発展に欠かせない、ビジネスリスクを軽減する法整備(1/28)
https://xtech.nikkei.com/atcl/nxt/column/18/00065/00540/
【Kotlin】value classを引数に設定した際にコンパイル結果がbox/unboxされた形となる規則

# TL;DR
- `value class`を引数に設定した場合、コンパイル結果（= `Java`上の表現）が`unbox`された形になる場合とならない場合が有る
- 引数が`nullable`で、`value class`のプロパティがプリミティブ型もしくは`nullable`だった場合`box`された形になる
- それ以外の場合`unbox`された形となる

# 検証
以下のコードをデコンパイルして確認します。
なお、検証は`Kotlin 1.6.10`で行っています。

```kotlin:元コード
@JvmInline
value class NonNullPrimitive(val value: Int)

@JvmInline
value class NullablePrimitive(val value: Int?)

@JvmInline
value class NonNullObject(val value: String)

@JvmInline
value class NullableObject(val value: String?)

fun temp(
    v0: NonNullPrimitive, v1: NonNullPrimitive?,
    v2: NullablePrimitive, v3: NullablePrimitive?,
    v4: NonNullObject, v5: NonNullObject?,
    v6: NullableObject, v7: NullableObject?
) {}
```

デコンパイル結果は以下のようになります。
引数が`nullable`で、プロパティがプリミティブ型もしくは`nullable`の場合のみ`box`された形となっていることが分かります。

```java:デコンパイル結果（抜粋・整形済み）
public static final void temp-wcdxcvQ(
  int v0, @Nullable NonNullPrimitive v1,
  @NotNull Integer v2, @Nullable NullablePrimitive v3,
  @NotNull String v4, @Nullable String v5,
  @NotNull String v6, @Nullable NullableObject v7
) {
  Intrinsics.checkNotNullParameter(v4, "v4");
}
```
Vim備忘録

# 概要
Vimを使用するたびに調べているため備忘録を作成しておく。

# コマンド
コマンド一覧を以下にまとめる。

## モード切替
以下のコマンドでモード切替を行う.

|  | 内容 |
|:---:|:---|
| i | 挿入モード |
| ESC | ノーマルモード |
| v | ビジュアルモード |
| Ctrl + v | 矩形選択のビジュアルモード |

## カーソル移動

|  | 内容 |
|:---:|:---|
| w | 次の単語 |
| b | 前の単語 |
| % | 対応する括弧に移動 |


## 編集

|  | 内容 |
|:---:|:---|
| D | カーソル位置から行末まで削除 |
| x | カーソル位置の１文字を削除 |
| yy | カーソル行をコピー |
| dd | カーソル行を切り取り |
| p | ペースト |
| u | Undo |
| Ctrl + r | Redo |

## 選択/コピー

|  | 内容 |
|:---:|:---|
| y | コピー |
| d | 切り取り |

## 検索

|  | 内容 |
|:---:|:---|
| / | 検索文字の入力開始 |
| * | カーソル位置の単語検索 |
| n | 下方向へ検索 |
| N | 上方向へ検索 |

## 保存/終了

|  | 内容 |
|:---:|:---|
| :wq | 保存して終了 |
| :q! | 保存せずに終了 |

## おまけ

|  | 内容 |
|:---:|:---|
| :set number | 行番号表示 |
| :set hlsearch | 検索結果のハイライト |
ZeroSSLでSSL証明書を無料かつ爆速で取得する方法

# 概要

`ZeroSSL` で無料のSSL証明書を発行する方法をまとめていきます

https://zerossl.com/


# この記事で伝えたいこと　

`ZeroSSL`でSSL証明書を発行してドメインをHTTPS化するまでのプロセス     

## ZeroSSLについて

今回`ZeroSSL`を導入するにあたって以下の記事を参考にしました

https://zenn.dev/mattn/articles/b2c4c92c9116b1

> Let's Encryptは、証明書を無料で大規模に提供することで、素晴らしい活動をしている素晴らしい組織です。しかし、問題は、長い間、そのような組織は彼らだけだったということです。
他の選択肢を持つことは常に良いアイデアです。

https://scotthelme.co.uk/introducing-another-free-ca-as-an-alternative-to-lets-encrypt/


### ドメイン取得

今回はGCPで構築した環境にSSL証明書を適用します

### 更新するドメインを`Create Free SSL Certificate`に入力

![スクリーンショット 2022-01-30 1.42.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555632/c6a0340f-9aa5-f0d3-4f52-c4bd2e86bf15.png)

https://zerossl.com/


### アカウントを作成する

![スクリーンショット 2022-01-30 1.44.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555632/673d4a17-6bad-948d-a867-f82be23d78c7.png)


### `Create SSL Certificate`でSSL証明書を発行する

![スクリーンショット 2022-01-30 1.45.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555632/a6973756-c45d-1d47-7ec2-33f72800034d.png)

### ドメイン名を入力 > 90日間の証明書を選択 > Next Step 

![スクリーンショット 2022-01-30 1.47.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555632/24c8f827-4f67-48e4-c52c-07069e6908b4.png)


### `Free`プランを選択 > Next Step

![スクリーンショット 2022-01-30 1.49.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555632/dffe34e9-9fa9-e762-1bc0-e30ed8a1d7bf.png)

### `DNS（CNAME）`で認証（他の認証方法でも可） > Next Step

![スクリーンショット 2022-01-30 3.19.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555632/bf8c442d-d2bf-6786-ae00-e1cd4753f56d.png)


### Download Certificateで証明書ファイルをダウンロードする

![スクリーンショット 2022-01-30 2.16.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555632/05545160-bd9b-71aa-d566-7d8dab2996e7.png)

### `Cloud Load Balancing`に証明書を設定する

![スクリーンショット 2022-01-30 3.25.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555632/f3cf3e20-f814-c91d-3d06-ebe6aab09289.png)

### `Cloud Load Balancing`のIPを`Cloud DNS`に設定する

![スクリーンショット 2022-01-30 3.35.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555632/a2372703-d522-3137-5c16-9c4a8809e237.png)

### SSL証明書設定完了

![スクリーンショット 2022-01-30 3.40.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555632/a6c5ca67-66ad-df24-f840-cdfaadeb9dfe.png)


# 留意点、デメリット

無料の証明書は90日間で期限が切れてしまいますので注意が必要です
JavaScript学習①　受け取った数字を降順にして返す（正の数のみ）

#前書き
この投稿は筆者がJavaScriptの勉強としてこなした課題を、どのように解いたかを解説する自分用のメモです。

ついでに同じような問題にぶつかっている人の助けになったら幸いと思いアップしています。

初心者のため間違う可能性や表現が悪い場合があります。ご注意ください。
また、間違った表現などがあった際は指摘してくださると幸いです。
よろしくお願いいたします。

※ちなみに課題はcodewarsを利用しています。
練習に最適なので、ぜひ挑戦してみてください↓
https://www.codewars.com

それでは早速本日の課題を解いていきましょう！

#課題
あなたの仕事は、負でない整数を引数として受け取り、その桁を降順にして返すことができる関数を作ることです。基本的には、可能な限り大きな数字を作るために桁を並べ替えることである。

例
入力 42145 出力。54421

入力 145263 出力 654321

入力 123456789 出力 987654321

引用元URL（codewars）：https://www.codewars.com/kata/5467e4d82edf8bbf40000155/train/javascript
※課題はDeepLにて翻訳して載せているだけなため、解釈などが異なる場合があります。英語本文は上記URLを参照にしてください。

#回答

```javascript
function descendingOrder(n){
  return parseInt(String(n).split('').sort().reverse().join(''))
}

console.log(descendingOrder('123456789'));
//>> 987654321
```

#解説
回答で使用されている関数の説明や、注意する箇所などを解説します。

##parseInt()
StringオブジェクトをIntオブジェクトに変換してくれる関数。
第一引数には、Stringオブジェクトを指定する。
第二引数には、基数を指定する。指定しない場合は、文字列より自動的に基数が判定される。

```javascript
let str = "123"
let num = parseInt(str);
console.log(num); //>> 123
```

##String()
引数をStringオブジェクトに変換してくれる関数。

```javascript
let num = new String(365);
console.log(num); //>> String {"365"}
```

##split()
Stringオブジェクトを分割して配列化するメソッド。
第一引数には区切り文字を指定する。
また、第二引数を指定することで取得する要素を制限できる。
今回のsplit('')は、Stringオブジェクトの数字を1文字ずつ配列にしている。

```javascript
let lists = 'リンゴ,バナナ,メロン,イチゴ,スイカ';
let num = '12345'

let result = lists.split(',', 3);
let result2 = num.split('')

console.log( result ); //>> ['リンゴ', 'バナナ', 'メロン']
console.log( result2 ); //>> ['1', '2', '3', '4', '5']
```

##sort()
並び替えを実現するメソッド。
sort()はかなりさまざまな使い方があるが、今回は回答で使われている考え方のみここでは解説する。
sort()は単純に考えると、文字コードを数値に変換した値を小さい順に並び替えるメソッドのこと。
※その他、詳しいsort()の使い方でとてもわかりやすく解説されていたサイトを紹介します↓
とてもわかりやすくまとめられており、感謝しかありません。
https://dezanari.com/js-sort/

```javascript
const num = ['1', '0', '2', '1']
let result = num.sort()
console.log(num) //>> ['0', '1', '1', '2']
```

##reverse()
配列の要素を反転させるメソッド。

```javascript
const num = ['0', '1', '1', '2']
let result = num.reverse()
console.log(num) //>> ['2', '1', '1', '0']
```

##join()
配列の全要素を順に連結した文字列を新たに作成するメソッド。
今回のjoin('')は、要素の値をそのまま連結したものになります。例では2番目。

```javascript
const elements = ['Fire', 'Air', 'Water'];

console.log(elements.join());
// expected output: "Fire,Air,Water"

console.log(elements.join(''));
// expected output: "FireAirWater"

console.log(elements.join('-'));
// expected output: "Fire-Air-Water"
```
引用：[MDN Web Docs](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/join)

#まとめ
今回は入力として渡された数値を降順で並び替える課題を解きました。

最初はif分岐などを活用して必死に頑張っていましたが、便利なメソッドを活用することで最終的に1行でかけることがわかり、プログラミングのすごさとできる方のコードの美しさに感動しました。

今回の中で、sort()はかなり様々な場面で活用されており、今後時間がある時に自分自身の言葉でまとめたいと思います。乞うご期待ください。

[Twitter](https://twitter.com/EngineerShige)やっていますので、友達になりたい方入ればフォローしてくださると喜びます！一緒にプログラミング頑張る友達ができると嬉しいです。
最近Twitterはあまり活動できていませんが。。。
DMなどくだされば反応はしますのでご安心を！
Wordleソルバーができた気がする話

[Wordle](https://www.powerlanguage.co.uk/wordle/)、やってますか？
英語圏だけの流行りかと思ったら、日本語圏でも流行り始めてる気がしますね。
Wordleソルバーを作ってみたらうまく行った気がするのでメモ書き程度ですが共有しておきます。
Wordleって何？という方はググるか実際に遊んでください。
#Absurdle
最初は[Absurdle](https://qntm.org/files/wordle/index.html)のソルバーを作っていました。
Absurdleとは、ざっくり言うと「ゲーム開始時点では答えは確定していない」「ユーザの入れた単語に応じて、可能な限り答えのパターンが多くなるような盤面を構成してくる」バージョンのWordleです。
人間がやるとまあムカつく仕様ですが、面倒なのでPythonにやらせました。
答えのパターンが常に最大になるようなら、その最大値を最小にするような入力を与えてやればよいのです。
というわけでAbsurdleは常識的な手数で解けたのですが、これをWordleでも応用できないかと考えました。
#Wordle
Absurdleで同じアルゴリズムで入力を考えていたのですが、妙に手数がかかる気がします。
そこで、最大値はWordleの評価値としては正しくないと考えました。
しかし、相加平均をちょっといじったものでうまくいった気がしました。

以下では、1回の入力に応じて表示される5色の四角を「色パネル」と呼びます。複数ターンは考慮しません。

具体的には、色パネルとしてありえるパターン全てについて「その色パネルが表示される正解」の数を求め、この総和を求め、正解の候補に$i$が含まれていたら1を引き、さらに「表示される色パネルの種類数」で割る。この値を評価値とするため、この計算を入力としてありうる単語$i$全てで行います。「正解」の数を1以上2以下の数で適当に累乗してもいいかもしれません。

#未完

真面目に探索したほうが良くなるかもしれません。
vim でエロ漫画を読む

#注意
ふざけた内容です。
試す際には自己責任でお願いします。

# 対象者
windows terminal上のvimでネットサーフィンからプログラミングまでやってるような奇特な方

# ……どういうことなの？
そのまんまの意味です。 
みなさん、vimでエロ漫画を読みたくなることってありませんか？
ありますよね？
そう、あるんですよ！

というわけで、外部ツールとちょっとしたコードでvimに画像表示機能を付けようというのがこの記事の趣旨です（それも、ANSIエスケープシーケンスのみで）。

# 作業内容
## 外部ツールの導入
画像をANSIエスケープシーケンスで表示するためのプログラムを導入します。
何でも構いませんが、今回はimgcatを使用します。
https://github.com/danielgatis/imgcat
を参考にインストールします。

## vimrc の編集
vimrcに以下を追記します。

```vim
augroup ImgOpener
    autocmd!
    if executable('imgcat')
        func! ImgDriver(filename, buftype)
            let l:img_to_open = ''
            if a:buftype==''
                setlocal nobuflisted
                if exists('b:netrw_tmpfile')
                    let l:img_to_open = fnamemodify(b:netrw_tmpfile, ":r").'.'.fnamemodify(a:filename, ":e")
                else
                    let l:img_to_open = a:filename
                endif
                exe "terminal ++curwin imgcat ".shellescape(l:img_to_open)
                setlocal buftype=nowrite
                setlocal buflisted
                setlocal hidden
            endif
        endfunc
        autocmd BufEnter *.jpg,*.png,*.gif,*.tiff,*.jfif,*.bmp :call ImgDriver(@%, &buftype)
    endif
augroup END
```
再起動したvimで適当な画像ファイルを開くと、画面上に画像がちゃんと表示されるはずです。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2519101/d9fdc2b0-eae4-46af-d353-dddf3caa55df.png)

いかがでしたか？
多少不便なのは否めませんが、vimからエロ漫画（画像）が閲覧可能であることがお分かりいただけたことと思います。
ではまた。

# 参考
https://qiita.com/u1and0/items/526d95d6991bc19003d2

# 余談
sixelが恋しい。
[JS](基礎的)JavaScriptのコードが実行される仕組み

アウトプットとして
#JavaScriptのコードが実行される仕組み
JavaScriptは「何かが起きたらコードを実行する」という`動的`な概念に基づいて設計されています。
この「何かが起きたら」は`イベント`と呼ばれ、HTMLに対して行われた要求のことをいいます。
また、イベントを認識してJavaScriptのコード（特に関数）が動き出すことを`イベント発火`と言います。

イベントの例

- ブラウザ上のボタンをクリックした
- テキストフィールドでキー入力をした
- 要素の上にマウスカーソルを乗せた etc...

##addEventListener()メソッド
イベント発火の際に実行する関数を定義するためのメソッド

```javascript
要素.addEventListener('イベント名', 関数function(){
  //イベントが起きた際の処理
})
```
イベントの例

|イベント名|説明|
|-------|---|
|loadイベント|ページ全体が全て読み込まれた後に、イベント発火する|
|clickイベント|指定された要素がクリックされた時に、イベントが発火する|
|mouseoverイベント|マウスカーソルが指定された要素上に乗った時に、イベントが発火する|
|mouseoutイベント|マウスカーソルが指定された要素上から外れた時に、イベントが発火する|

関数については→[JavaScriptの関数](https://qiita.com/Shi-raCanth/items/a6c2fabcc152b05f09bc)
要素の取り出し方に関しては→[HTMLの要素を取得する方法](https://qiita.com/Shi-raCanth/items/7ae6c1efac28668571b3)


以上。
※補足等ありましたらコメントいただけると幸いです。
Puppeteerでユーザーエージェントを偽装する

# これはなに？

以前 `await puppeteer.launch()` のオプションでUserAgentを指定できたような気がしたが出来なかったので改めて調査してみた。

手元に昔書いたこんな風のコードあったけど初めから期待した挙動してなかったんかな……

```js
  const browser = await puppeteer.launch({
    headless:true,
    executablePath: "/usr/bin/google-chrome",
    ua: "foobar",
  });
```

# どうするの？

## ブラウザの起動オプションに与える

```js
  const browser = await puppeteer.launch({
    headless:true,
    slowMo: 10,
    executablePath: "/usr/bin/google-chrome",
    args: [
      "--user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36",
    ],
  });
```

argsがブラウザ起動時のコマンドラインオプションになるはずなのでこれで指定する

## 素直にsetUserAgent()を使う

```js
  const page = await browser.newPage();
  page.setUserAgent("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36");
```

Puppeteer使うならこれが正攻法なんでしょうね。

# 結果

```js:checkua.js
const puppeteer = require("puppeteer");

(async() => {
  const browser = await puppeteer.launch({
    headless:true,
    slowMo: 10,
    executablePath: "/usr/bin/google-chrome",
    args: [
      // "--user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36",
    ],
  });
  const page = await browser.newPage();
  // page.setUserAgent("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36");

  try {
    const value = await page.evaluate(() => {
      return navigator.userAgent;
    });
    console.log(value);
  } catch(e) {
    console.log(e);
  }
  browser.close();
})();
```

```
$ node checkua.js
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/97.0.4692.99 Safari/537.36
```

argsの方のコメントアウト部分を有効にすると

```
$ node checkua.js
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36
```

デフォルトでHeadlessChromeとなっていた箇所がChromeとなり、上書きされていることが確認できる。

setUserAgentの方のコメントアウト部分を有効にすると

```
$ node checkua.js
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36
```

こちらも書き換えられている。

昔書いたスクリプト直さなきゃだ！

---

それでは良いWebスクレイピングライフを。
ECCUBEをXserverにアップして表示するまで(コマンドで)

コマンドで行った時の忘備録です。

##コマンドでECCUBEをサーバにアップ

    $ wget eccube-4.1.1.zip

##サーバにSSH接続

    $ ssh -i 秘密鍵の名前 -p 10022 サーバID@XXXX.xserver.jp -l MySQLユーザーネーム

###ECCUBEがあるか確認

    $ ls

###unzipする

    $ unzip eccube-X.X.X

###public_htmlのデータを退避

    $ mv ./サーバID.xsrv.jp/public_html ./サーバID.xsrv.jp/p

###unzipしたECCUBEの中身を移動

    $ mv ./ec-cube /サーバID.xsrv.jp/public_html

##サイトにアクセス

ECCUBEの設定画面が表示されたらOKです
goでbuffer writeする処理のメモ

bufferにwriteする際、io.Writerのインターフェースを使う場合は以下のように書けます。

```
buffer.Write([]byte("bytes.Buffer example1"))
```

ただ、毎回バイト列にキャストしないといけないのは面倒です。なのでWriteStringというメソッドがbufferに用意されています。

```
buffer.WriteString("bytes.Buffer example2")
```

ただ、WriteStringはbuffer専用のメソッドのため、他の構造体では使えません。すべてのio.Writerインターフェースを満たす構造体に対してstringを書き込むような処理はio.WriteStringで実装できます。

```
io.WriteString(&buffer, "bytes.Buffer example")
io.WriteString(os.Stdout, "bytes.Buffer example")
```

まとめると以下のような感じです。

```main.go
package main

import (
	"bytes"
	"fmt"
	"io"
)

func main() {
	var buffer bytes.Buffer

    // 以下の3行は同じbufferにwriteする処理を行う。
	// buffer.Write([]byte("bytes.Buffer example1"))
	// buffer.WriteString("bytes.Buffer example2")
	io.WriteString(&buffer, "bytes.Buffer example3")
	
	fmt.Println(buffer.String())
}

```

## 参考

[goならわかるシステムプログラミング](https://www.amazon.co.jp/Go%E3%81%AA%E3%82%89%E3%82%8F%E3%81%8B%E3%82%8B%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E6%B8%8B%E5%B7%9D-%E3%82%88%E3%81%97%E3%81%8D/dp/4908686033)
簡単なPySimpleGUI①～二次方程式の解の公式～

PysimpleGUIの使い方メモとして、二次方程式の解を「解の公式」で求めるGUIを作成しました。
# この記事で扱う要素
**入力**
・数値入力ボックス（sg.InputText）
・ボタン (sg.Button, sg.B)


**出力**
・画面出力 (window['hoge'].update('hogehoge'))

# コード
```Python:Code
import PySimpleGUI as sg

def main():
     layout =  [[sg.Text("解の公式GUI", size=(15, 1), justification='center', font=("Helvetica", 20), relief=sg.RELIEF_RIDGE)],
                [sg.T("ax^2+bx+c=0", size=(15, 1), justification='center')],
                [sg.Text('a :'), sg.InputText("1", key='a', size=(25, 1))],
                [sg.Text('b :'), sg.InputText("-4", key='b', size=(25, 1))],
                [sg.Text('c :'), sg.InputText("4", key='c', size=(25, 1))],
                [sg.Text('出力 :'), sg.Text("ここに答えが表示されます", key='ans')],
                [sg.Button('解の公式'), sg.B('Cancel')]]

    window = sg.Window('GUI window', layout)

    while True:
        event, values = window.read()
        a = float(values['a'])
        b = float(values['b'])
        c = float(values['c'])
        if event == None or event == 'Cancel':  # if user closes window or clicks cancel
            break

        elif event == '解の公式':
            ans = kai_no_kousiki(a, b, c)

        window['ans'].update(ans)

    window.close()

def kai_no_kousiki(a, b, c):
    D = (b**2 - 4*a*c) ** (1/2)
    x_1 = (-b + D) / (2 * a)
    x_2 = (-b - D) / (2 * a)

    return [x_1, x_2]

if __name__ == '__main__':
    main()
```

# 得られるGUI
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601935/12fd96e9-4db9-3e4a-bba4-77b124cd64c1.png)
Dockerのコマンド

######勉強したことの備忘録
Dockerの基礎的なコマンド

|コマンド|意味|
|---|---|---|
|docker login|Docker hubにログイン|
|docker pull (image)|imageをDocker hubからpullする|
docker images|ホストにあるDockerのimageを見ることができる
docker run (image)|imageを元にコンテナを作る
docker run -d (image) | コンテナ起動時にdetachをする(抜けてもupの状態のまま)
docker run --rm (iamge) | Exit後に削除をする
docker run --name(name)(image)|名前をつけてコンテナを立ち上げる
docker ps -a|全てのコンテナを見る
docker run -it ubuntu bash|ubuntuのimageを元にコンテナを作ってbashを起動　 ubuntuなければpullしてくれる
exit|コンテナから抜ける
docer restart|コンテナを再起動する
docker commit containerのID new image|コンテナからイメージを作成
docker rm|コンテナを削除
docker stop (container)|コンテナを止める
docker system prune|コンテナを全削除
docker build -t (name)(directory)|Dockerfileを元にimageを作成
-v (host):(container)|ホストのファイルシステムをコンテナにマウントする　実際コンテナにファイルシステムがあるわけではない
docker-compose build| Docker composeを使う場合のdocker build
docker-compose up| Docker composeを使う場合のdocker run (image)
docker-compose ps | Docker composeを使う場合のdocker ps
docker run -it -u $(id -u):$(id -g)|ユーザーIDを指定してコンテナを起動　権限を持たせる
docker run -it -p 8888:8888|ホストのポートとコンテナのポートを繋げる　ポートは部屋番号のようなもの　コンテナに立ててるwebサービスにアクセスするため
継承先で追加動作を書きたいとき

最近色々と実装を行っていた際に、継承でもともとの実装を変えずに追加実装を書こうと思った際にどうしたらよいか少し迷ったので忘れないように自分の覚え書きを書いておきます。

```cs
class BaseClass
{
    protected virtual void Initialize()
    {
        // 色々実装が入っている
    }
}

class DerivedClass : BaseClass
{
    protected override void Initialize()
    {
        base.Initialize();
        // 追加実装を書く
        hoge();
    }

    void hoge()
    {
        // 処理内容を書く
    }
}
```

色々理由があり元の実装は変更したくない、しかし追加実装を書きたいということがありこのようになりました。
追加がしたいため継承で新たにクラスを作成しました。
そのため、追加実装を書きたい関数をvirtualに変更しoverrideを行えるように変更し、関数自体をoverrideします。
~~そして、その中に追加実装を書きoverrideした関数の方でbaseで元の実装を呼びだすことで対応します。~~

@shiracamus さんから指摘をいただき、追加実装は後ろにずらしました。
追加実装の修正により、baseの実装が上書きされてしまうのを防ぐためです。

これでシンプルに追加実装を書くことができます。

### 最後に

この方法がわからずに少し時間を無駄にしてしまいました。
やはり、オブジェクト指向回りの理解がまだ不十分だと改めて思いました。
また思いつきで記事を書いていきたいと思います。
Go言語における.envファイルの使い方（viper使用）

# はじめに

Go言語でサーバーアプリケーションを作成しています。

このアプリでは、暗号化に使うシークレットキーやら、データベースのユーザー、パスワードといった設定値を簡単に扱えるライブラリとして、viperを使っています。

viperを使ってconfig.yamlといった外部ファイルを読み込む方法については、下記の参考資料等々よく見ますが、config.yamlの他に.envファイルも扱いたいと思いました。

viperにおける、.envの扱いについては、調べてもあまり出てこなかったので備忘録としてまとめました。

# 前提

## Versionについて

Goのバージョン、viperのバージョンは以下のとおりです。

- Go 1.17.6
- [github.com/spf13/viper](http://github.com/spf13/viper) v1.10.1

## フォルダ構成

今回説明するフォルダ構成は以下の通りです。

```:フォルダ構成
.
├── config
│   ├── config.yaml
│   └── config.go
├── .env
└── main.go
```

viperを用いて、config.yamlを読み取る方法については、

[Goの環境変数を扱う(viper)](https://qiita.com/takehanKosuke/items/1b17ade882b50cf2d737)

に詳しく記載されていますので参照していただければと思います。

# 環境変数の定義

.envファイルに環境変数を定義する。

例：

```:.env
VERSION=1.0.0
DBUSER=postgres
DBPASSWORD=postgres
```

# Goのviperの設定

デフォルトでは、viperでconfig.yamlを読み取っているが、

```go:config.go
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath("config/")
//↑がconfig.yamlの設定

//↓が環境変数の設定 ※これを書いただけでは、.envは読み取られない
viper.AutomaticEnv()                                   //環境変数の読み込み
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) //プリフィックスの設定
```

とすることで、環境変数で設定値を上書きできる。
環境変数はすべて大文字で問題ない。viperがよしなにやってくれる。

ただし、注意点として、go runやgo buildしたあとの実行ファイルを実行するときに、自動で.envファイルを読み取ってくれるわけではないので、後述するやり方で.envファイルの値をgoの中に反映させる。

## (環境変数の反映)

go runをする際に、

```makefile
VERSION=1.0.0 DBUSER=postgres DBPASSWORD=postres go run main.go
```

といった形にすれば環境変数が反映される。

# .envファイルの環境変数の反映

go buildで実行ファイル(./bin/main)を作成したあと、

```makefile
#!/bin/ash
export $(cat .env | grep -v ^# | xargs); ./bin/main
```

とすることで、.envのファイルを表示させて実行してくれる。

`#!/bin/ash`はalpine用なので、適宜変えること。

[コマンドでの環境変数の受け渡し](https://qiita.com/reflet/items/2caf9dbf0e3f775276ec)

を参考にさせていただきました。

# 補足

dockerを使っているのであれば、dockerfileの中で.envの設定をしてもいいとは思うが、開発環境がローカル(dockerを使わない)ので、.envはこの形で反映させるようにしている。

# 参考資料

- **[Goの環境変数を扱う(viper)](https://qiita.com/takehanKosuke/items/1b17ade882b50cf2d737)**
- **[コマンドでの環境変数の受け渡し](https://qiita.com/reflet/items/2caf9dbf0e3f775276ec)**

# おわりに

間違い、あるいはご意見等あればコメントいただければ幸いです。
C++14で使える簡易版Optional型を自作した

# 概要

C++17で無効値を表すことができる`std::optional`クラスが導入されたが，これに近い機能をC++14で利用するために簡易版`mylib::optional`クラスを自作した．

# ソースコード

```cpp
#pragma once

#include <stdexcept>

namespace mylib {

class bad_optional_access : public std::exception {
  public:
    const char* what() const noexcept override {
      return "bad_optional_access";
    }
};

template <typename T>
class optional {
 public:
  /**
   * @brief コンストラクタ．無効値を生成する．
   */
  constexpr optional() noexcept : value_(), has_value_(false) {}

  /**
   * @brief コンストラクタ．有効値を生成する．
   */
  constexpr explicit optional(const T& v) : value_(v), has_value_(true) {}

  /**
   * @brief コピーコンストラクタ
   */
  constexpr optional(const optional& rhs)
      : value_(rhs.value_), has_value_(rhs.has_value_) {}

  /**
   * @brief ムーブコンストラクタ
   */
  constexpr optional(optional&& rhs) noexcept
      : value_(std::move(rhs.value_)), has_value_(rhs.has_value_) {}

  /**
   * @brief デストラクタ
   */
  ~optional() = default;

  /**
   * @brief コピー代入演算子
   */
  optional& operator=(const optional& rhs) {
    if (this != &rhs) {
      value_ = rhs.value_;
      has_value_ = rhs.has_value_;
    }
    return *this;
  }

  /**
   * @brief ムーブ代入演算子
   */
  optional& operator=(optional&& rhs) noexcept {
    if (this != &rhs) {
      value_ = std::move(rhs.value_);
      has_value_ = rhs.has_value_;
    }
    return *this;
  }

  /**
   * @brief 有効値かどうかを返す．
   */
  constexpr explicit operator bool() const noexcept { return has_value_; }

  /**
   * @brief 有効値かどうかを返す．
   */
  constexpr bool has_value() const noexcept { return has_value_; }

  /**
   * @brief メンバアクセス演算子
   */
  constexpr T* operator->() noexcept { return &value_; }

  /**
   * @brief メンバアクセス演算子
   */
  constexpr const T* operator->() const noexcept { return &value_; }

  /**
   * @brief 間接参照演算子（左辺値参照）
   */
  constexpr T& operator*() & noexcept { return value_; }

  /**
   * @brief 間接参照演算子（右辺値参照）
   */
  constexpr T&& operator*() && noexcept { return std::move(value_); };

  /**
   * @brief 間接参照演算子（const左辺値参照）
   */
  constexpr const T& operator*() const& noexcept { return value_; }

  /**
   * @brief 間接参照演算子（const右辺値参照）
   */
  constexpr const T&& operator*() const&& noexcept { return std::move(value_); }

  /**
   * @brief 保持値への左辺値参照を取得する．
   */
  constexpr T& value() & {
    if (!has_value_) {
      throw bad_optional_access();
    }
    return value_;
  }

  /**
   * @brief 保持値への右辺値参照を取得する．
   */
  constexpr T&& value() && {
    if (!has_value_) {
      throw bad_optional_access();
    }
    return std::move(value_);
  }

  /**
   * @brief 保持値へのconst左辺値参照を取得する．
   */
  constexpr const T& value() const& {
    if (!has_value_) {
      throw bad_optional_access();
    }
    return value_;
  }

  /**
   * @brief 保持値へのconst右辺値参照を取得する．
   */
  constexpr const T&& value() const&& {
    if (!has_value_) {
      throw bad_optional_access();
    }
    return std::move(value_);
  }

 private:
  T value_;
  bool has_value_;
};

} // namespace mylib
```
Ruby と Python で解く AtCoder ARC 134 A

# はじめに
*[AtCoder Problems](https://kenkoooo.com/atcoder/#/)* の Recommendation を利用して、過去の問題を解いています。
AtCoder さん、AtCoder Problems さん、ありがとうございます。

# 今回のお題
https://atcoder.jp/contests/arc134/tasks/arc134_a

<font color="gray">Difficulty: 247</font>

いやー、この問題ちょっと鬼畜眼鏡ではないのかな。
# Ruby
```ruby:AC.rb
n, l, w = gets.split.map(&:to_i)
a = gets.split.map(&:to_i)
a << l
ans = (a[0] / w.to_r).ceil
n.times do |i|
  if a[i + 1] - a[i] - w > 0
    ans += ((a[i + 1] - a[i] - w) / w.to_r).ceil
  end
end
puts ans
```
```ruby:WA.rb
n, l, w = gets.split.map(&:to_i)
a = gets.split.map(&:to_i)
a << l
ans = (a[0] / w.to_f).ceil
n.times do |i|
  if a[i + 1] - a[i] - w > 0
    ans += ((a[i + 1] - a[i] - w) / w.to_f).ceil
  end
end
puts ans
```
`AC.rb`と`WA.rb`の違い、分かりますでしょうか。
# Python
```python:AC.py
from math import ceil
from fractions import Fraction

n, l, w = map(int, input().split())
a = list(map(int, input().split()))
a.append(l)
ans = ceil(Fraction(a[0], w))
for i in range(n):
    if a[i + 1] - a[i] - w > 0:
        ans += ceil(Fraction(a[i + 1] - a[i] - w, w))
print(ans)
```
```python:WA.py
from math import ceil

n, l, w = map(int, input().split())
a = list(map(int, input().split()))
a.append(l)
ans = ceil(a[0] / w)
for i in range(n):
    if a[i + 1] - a[i] - w > 0:
        ans += ceil((a[i + 1] - a[i] - w) / w)
print(ans)
```
`Python`だと書式が違いますので気付かれると思いますが、浮動小数の誤差による、`AC`と`WA`の違いでした。

# まとめ
+ ARC 134 A を解いた